Workspace: Move engines to workspace and Properties Editor cleanup
[blender.git] / source / blender / blenkernel / intern / sound.c
index 88d14333fb231125b07f52babaef08ac550abe4b..6cf310461c1331fea2dd3cbd737910a893c82c46 100644 (file)
 #include "DNA_speaker_types.h"
 
 #ifdef WITH_AUDASPACE
-#  include AUD_SOUND_H
-#  include AUD_SEQUENCE_H
-#  include AUD_HANDLE_H
-#  include AUD_SPECIAL_H
-#  ifdef WITH_SYSTEM_AUDASPACE
-#    include "../../../intern/audaspace/intern/AUD_Set.h"
-#  endif
+#  include <AUD_Sound.h>
+#  include <AUD_Sequence.h>
+#  include <AUD_Handle.h>
+#  include <AUD_Special.h>
+#  include "../../../intern/audaspace/intern/AUD_Set.h"
 #endif
 
 #include "BKE_global.h"
 #ifdef WITH_AUDASPACE
 /* evil globals ;-) */
 static int sound_cfra;
-static char** audio_device_names = NULL;
+static char **audio_device_names = NULL;
 #endif
 
-bSound *BKE_sound_new_file(struct Main *bmain, const char *filename)
+bSound *BKE_sound_new_file(struct Main *bmain, const char *filepath)
 {
        bSound *sound;
-
-       char str[FILE_MAX];
        const char *path;
+       char str[FILE_MAX];
 
-       size_t len;
-
-       BLI_strncpy(str, filename, sizeof(str));
+       BLI_strncpy(str, filepath, sizeof(str));
 
        path = /*bmain ? bmain->name :*/ G.main->name;
 
        BLI_path_abs(str, path);
 
-       len = strlen(filename);
-       while (len > 0 && filename[len - 1] != '/' && filename[len - 1] != '\\')
-               len--;
-
-       sound = BKE_libblock_alloc(bmain, ID_SO, filename + len);
-       BLI_strncpy(sound->name, filename, FILE_MAX);
+       sound = BKE_libblock_alloc(bmain, ID_SO, BLI_path_basename(filepath), 0);
+       BLI_strncpy(sound->name, filepath, FILE_MAX);
        /* sound->type = SOUND_TYPE_FILE; */ /* XXX unused currently */
 
        BKE_sound_load(bmain, sound);
@@ -99,8 +90,42 @@ bSound *BKE_sound_new_file(struct Main *bmain, const char *filename)
        return sound;
 }
 
+bSound *BKE_sound_new_file_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists)
+{
+       bSound *sound;
+       char str[FILE_MAX], strtest[FILE_MAX];
+
+       BLI_strncpy(str, filepath, sizeof(str));
+       BLI_path_abs(str, bmain->name);
+
+       /* first search an identical filepath */
+       for (sound = bmain->sound.first; sound; sound = sound->id.next) {
+               BLI_strncpy(strtest, sound->name, sizeof(sound->name));
+               BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &sound->id));
+
+               if (BLI_path_cmp(strtest, str) == 0) {
+                       id_us_plus(&sound->id);  /* officially should not, it doesn't link here! */
+                       if (r_exists)
+                               *r_exists = true;
+                       return sound;
+               }
+       }
+
+       if (r_exists)
+               *r_exists = false;
+       return BKE_sound_new_file(bmain, filepath);
+}
+
+bSound *BKE_sound_new_file_exists(struct Main *bmain, const char *filepath)
+{
+       return BKE_sound_new_file_exists_ex(bmain, filepath, NULL);
+}
+
+/** Free (or release) any data used by this sound (does not free the sound itself). */
 void BKE_sound_free(bSound *sound)
 {
+       /* No animdata here. */
+
        if (sound->packedfile) {
                freePackedFile(sound->packedfile);
                sound->packedfile = NULL;
@@ -120,22 +145,58 @@ void BKE_sound_free(bSound *sound)
 
        BKE_sound_free_waveform(sound);
        
+#endif  /* WITH_AUDASPACE */
        if (sound->spinlock) {
                BLI_spin_end(sound->spinlock);
                MEM_freeN(sound->spinlock);
                sound->spinlock = NULL;
        }
-       
-#endif  /* WITH_AUDASPACE */
+}
+
+/**
+ * Only copy internal data of Sound ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag  Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_sound_copy_data(Main *bmain, bSound *sound_dst, const bSound *UNUSED(sound_src), const int UNUSED(flag))
+{
+       sound_dst->handle = NULL;
+       sound_dst->cache = NULL;
+       sound_dst->waveform = NULL;
+       sound_dst->playback_handle = NULL;
+       sound_dst->spinlock = NULL;  /* Think this is OK? Otherwise, easy to create new spinlock here... */
+
+       /* Just to be sure, should not have any value actually after reading time. */
+       sound_dst->ipo = NULL;
+       sound_dst->newpackedfile = NULL;
+
+       if (sound_dst->packedfile) {
+               sound_dst->packedfile = dupPackedFile(sound_dst->packedfile);
+       }
+
+       /* Initialize whole runtime (audaspace) stuff. */
+       BKE_sound_load(bmain, sound_dst);
+}
+
+void BKE_sound_make_local(Main *bmain, bSound *sound, const bool lib_local)
+{
+       BKE_id_make_local_generic(bmain, &sound->id, true, lib_local);
 }
 
 #ifdef WITH_AUDASPACE
 
-static const charforce_device = NULL;
+static const char *force_device = NULL;
 
 #ifdef WITH_JACK
 static void sound_sync_callback(void *data, int mode, float time)
 {
+       // Ugly: Blender doesn't like it when the animation is played back during rendering
+       if (G.is_rendering)
+               return;
+
        struct Main *bmain = (struct Main *)data;
        struct Scene *scene;
 
@@ -165,18 +226,21 @@ void BKE_sound_init_once(void)
        atexit(BKE_sound_exit_once);
 }
 
-static AUD_Device* sound_device;
+static AUD_Device *sound_device = NULL;
 
-voidBKE_sound_get_device(void)
+void *BKE_sound_get_device(void)
 {
        return sound_device;
 }
 
 void BKE_sound_init(struct Main *bmain)
 {
+       /* Make sure no instance of the sound system is running, otherwise we get leaks. */
+       BKE_sound_exit();
+
        AUD_DeviceSpecs specs;
        int device, buffersize;
-       const chardevice_name;
+       const char *device_name;
 
        device = U.audiodevice;
        buffersize = U.mixbufsize;
@@ -184,16 +248,17 @@ void BKE_sound_init(struct Main *bmain)
        specs.format = U.audioformat;
        specs.rate = U.audiorate;
 
-       if (force_device == NULL)
-       {
+       if (force_device == NULL) {
                int i;
-               char** names = BKE_sound_get_device_names();
+               char **names = BKE_sound_get_device_names();
                device_name = names[0];
 
-               // make sure device is within the bounds of the array
-               for(i = 0; names[i]; i++)
-                       if(i == device)
+               /* make sure device is within the bounds of the array */
+               for (i = 0; names[i]; i++) {
+                       if (i == device) {
                                device_name = names[i];
+                       }
+               }
        }
        else
                device_name = force_device;
@@ -202,7 +267,7 @@ void BKE_sound_init(struct Main *bmain)
                buffersize = 1024;
 
        if (specs.rate < AUD_RATE_8000)
-               specs.rate = AUD_RATE_44100;
+               specs.rate = AUD_RATE_48000;
 
        if (specs.format <= AUD_FORMAT_INVALID)
                specs.format = AUD_FORMAT_S16;
@@ -219,7 +284,8 @@ void BKE_sound_init(struct Main *bmain)
 void BKE_sound_init_main(struct Main *bmain)
 {
 #ifdef WITH_JACK
-       AUD_setSynchronizerCallback(sound_sync_callback, bmain);
+       if (sound_device)
+               AUD_setSynchronizerCallback(sound_sync_callback, bmain);
 #else
        (void)bmain; /* unused */
 #endif
@@ -237,16 +303,14 @@ void BKE_sound_exit_once(void)
        sound_device = NULL;
        AUD_exitOnce();
 
-#ifdef WITH_SYSTEM_AUDASPACE
-       if(audio_device_names != NULL)
-       {
+       if (audio_device_names != NULL) {
                int i;
-               for(i = 0; audio_device_names[i]; i++)
+               for (i = 0; audio_device_names[i]; i++) {
                        free(audio_device_names[i]);
+               }
                free(audio_device_names);
                audio_device_names = NULL;
        }
-#endif
 }
 
 /* XXX unused currently */
@@ -290,15 +354,6 @@ bSound *BKE_sound_new_limiter(struct Main *bmain, bSound *source, float start, f
 }
 #endif
 
-void BKE_sound_delete(struct Main *bmain, bSound *sound)
-{
-       if (sound) {
-               BKE_sound_free(sound);
-
-               BKE_libblock_free(bmain, sound);
-       }
-}
-
 void BKE_sound_cache(bSound *sound)
 {
        sound->flags |= SOUND_FLAGS_CACHING;
@@ -426,6 +481,16 @@ void BKE_sound_destroy_scene(struct Scene *scene)
                AUD_destroySet(scene->speaker_handles);
 }
 
+void BKE_sound_reset_scene_specs(struct Scene *scene)
+{
+       AUD_Specs specs;
+
+       specs.channels = AUD_Device_getChannels(sound_device);
+       specs.rate = AUD_Device_getRate(sound_device);
+
+       AUD_Sequence_setSpecs(scene->sound_scene, specs);
+}
+
 void BKE_sound_mute_scene(struct Scene *scene, int muted)
 {
        if (scene->sound_scene)
@@ -537,6 +602,7 @@ void BKE_sound_set_scene_sound_pitch(void *handle, float pitch, char animated)
 
 void BKE_sound_set_scene_sound_pan(void *handle, float pan, char animated)
 {
+       printf("%s\n", __func__);
        AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PANNING, sound_cfra, &pan, animated);
 }
 
@@ -551,15 +617,10 @@ void BKE_sound_update_sequencer(struct Main *main, bSound *sound)
 
 static void sound_start_play_scene(struct Scene *scene)
 {
-       AUD_Specs specs;
-
        if (scene->playback_handle)
                AUD_Handle_stop(scene->playback_handle);
 
-       specs.channels = AUD_Device_getChannels(sound_device);
-       specs.rate = AUD_Device_getRate(sound_device);
-
-       AUD_Sequence_setSpecs(scene->sound_scene, specs);
+       BKE_sound_reset_scene_specs(scene);
 
        if ((scene->playback_handle = AUD_Device_play(sound_device, scene->sound_scene, 1)))
                AUD_Handle_setLoopCount(scene->playback_handle, -1);
@@ -668,6 +729,10 @@ void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene)
 
 float BKE_sound_sync_scene(struct Scene *scene)
 {
+       // Ugly: Blender doesn't like it when the animation is played back during rendering
+       if (G.is_rendering)
+               return NAN_FLT;
+
        if (scene->playback_handle) {
                if (scene->audio.flag & AUDIO_SYNC)
                        return AUD_getSynchronizerPosition(scene->playback_handle);
@@ -679,6 +744,10 @@ float BKE_sound_sync_scene(struct Scene *scene)
 
 int BKE_sound_scene_playing(struct Scene *scene)
 {
+       // Ugly: Blender doesn't like it when the animation is played back during rendering
+       if (G.is_rendering)
+               return -1;
+
        if (scene->audio.flag & AUDIO_SYNC)
                return AUD_isSynchronizerPlaying();
        else
@@ -737,13 +806,76 @@ void BKE_sound_read_waveform(bSound *sound, short *stop)
        BLI_spin_unlock(sound->spinlock);
 }
 
-void BKE_sound_update_scene(Main *bmain, struct Scene *scene)
+static void sound_update_base(Scene *scene, Base *base, void *new_set)
 {
-       Object *ob;
-       Base *base;
+       Object *ob = base->object;
        NlaTrack *track;
        NlaStrip *strip;
        Speaker *speaker;
+       float quat[4];
+
+       if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
+               return;
+       }
+
+       ob->id.tag &= ~LIB_TAG_DOIT;
+
+       if ((ob->type != OB_SPEAKER) || !ob->adt) {
+               return;
+       }
+
+       for (track = ob->adt->nla_tracks.first; track; track = track->next) {
+               for (strip = track->strips.first; strip; strip = strip->next) {
+                       if (strip->type != NLASTRIP_TYPE_SOUND) {
+                               continue;
+                       }
+                       speaker = (Speaker *)ob->data;
+
+                       if (AUD_removeSet(scene->speaker_handles, strip->speaker_handle)) {
+                               if (speaker->sound) {
+                                       AUD_SequenceEntry_move(strip->speaker_handle, (double)strip->start / FPS, FLT_MAX, 0);
+                               }
+                               else {
+                                       AUD_Sequence_remove(scene->sound_scene, strip->speaker_handle);
+                                       strip->speaker_handle = NULL;
+                               }
+                       }
+                       else {
+                               if (speaker->sound) {
+                                       strip->speaker_handle = AUD_Sequence_add(scene->sound_scene,
+                                                                               speaker->sound->playback_handle,
+                                                                               (double)strip->start / FPS, FLT_MAX, 0);
+                                       AUD_SequenceEntry_setRelative(strip->speaker_handle, 0);
+                               }
+                       }
+
+                       if (strip->speaker_handle) {
+                               const bool mute = ((strip->flag & NLASTRIP_FLAG_MUTED) || (speaker->flag & SPK_MUTED));
+                               AUD_addSet(new_set, strip->speaker_handle);
+                               AUD_SequenceEntry_setVolumeMaximum(strip->speaker_handle, speaker->volume_max);
+                               AUD_SequenceEntry_setVolumeMinimum(strip->speaker_handle, speaker->volume_min);
+                               AUD_SequenceEntry_setDistanceMaximum(strip->speaker_handle, speaker->distance_max);
+                               AUD_SequenceEntry_setDistanceReference(strip->speaker_handle, speaker->distance_reference);
+                               AUD_SequenceEntry_setAttenuation(strip->speaker_handle, speaker->attenuation);
+                               AUD_SequenceEntry_setConeAngleOuter(strip->speaker_handle, speaker->cone_angle_outer);
+                               AUD_SequenceEntry_setConeAngleInner(strip->speaker_handle, speaker->cone_angle_inner);
+                               AUD_SequenceEntry_setConeVolumeOuter(strip->speaker_handle, speaker->cone_volume_outer);
+
+                               mat4_to_quat(quat, ob->obmat);
+                               AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_LOCATION, CFRA, ob->obmat[3], 1);
+                               AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_ORIENTATION, CFRA, quat, 1);
+                               AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_VOLUME, CFRA, &speaker->volume, 1);
+                               AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_PITCH, CFRA, &speaker->pitch, 1);
+                               AUD_SequenceEntry_setSound(strip->speaker_handle, speaker->sound->playback_handle);
+                               AUD_SequenceEntry_setMuted(strip->speaker_handle, mute);
+                       }
+               }
+       }
+}
+
+void BKE_sound_update_scene(Main *bmain, Scene *scene)
+{
+       Base *base;
        Scene *sce_it;
 
        void *new_set = AUD_createSet();
@@ -752,59 +884,18 @@ void BKE_sound_update_scene(Main *bmain, struct Scene *scene)
 
        /* cheap test to skip looping over all objects (no speakers is a common case) */
        if (!BLI_listbase_is_empty(&bmain->speaker)) {
-               for (SETLOOPER(scene, sce_it, base)) {
-                       ob = base->object;
-                       if ((ob->type != OB_SPEAKER) || !ob->adt) {
-                               continue;
-                       }
-                       for (track = ob->adt->nla_tracks.first; track; track = track->next) {
-                               for (strip = track->strips.first; strip; strip = strip->next) {
-                                       if (strip->type != NLASTRIP_TYPE_SOUND) {
-                                               continue;
-                                       }
-                                       speaker = (Speaker *)ob->data;
-
-                                       if (AUD_removeSet(scene->speaker_handles, strip->speaker_handle)) {
-                                               if (speaker->sound) {
-                                                       AUD_SequenceEntry_move(strip->speaker_handle, (double)strip->start / FPS, FLT_MAX, 0);
-                                               }
-                                               else {
-                                                       AUD_Sequence_remove(scene->sound_scene, strip->speaker_handle);
-                                                       strip->speaker_handle = NULL;
-                                               }
-                                       }
-                                       else {
-                                               if (speaker->sound) {
-                                                       strip->speaker_handle = AUD_Sequence_add(scene->sound_scene,
-                                                                                               speaker->sound->playback_handle,
-                                                                                               (double)strip->start / FPS, FLT_MAX, 0);
-                                                       AUD_SequenceEntry_setRelative(strip->speaker_handle, 0);
-                                               }
-                                       }
-
-                                       if (strip->speaker_handle) {
-                                               const bool mute = ((strip->flag & NLASTRIP_FLAG_MUTED) || (speaker->flag & SPK_MUTED));
-                                               AUD_addSet(new_set, strip->speaker_handle);
-                                               AUD_SequenceEntry_setVolumeMaximum(strip->speaker_handle, speaker->volume_max);
-                                               AUD_SequenceEntry_setVolumeMinimum(strip->speaker_handle, speaker->volume_min);
-                                               AUD_SequenceEntry_setDistanceMaximum(strip->speaker_handle, speaker->distance_max);
-                                               AUD_SequenceEntry_setDistanceReference(strip->speaker_handle, speaker->distance_reference);
-                                               AUD_SequenceEntry_setAttenuation(strip->speaker_handle, speaker->attenuation);
-                                               AUD_SequenceEntry_setConeAngleOuter(strip->speaker_handle, speaker->cone_angle_outer);
-                                               AUD_SequenceEntry_setConeAngleInner(strip->speaker_handle, speaker->cone_angle_inner);
-                                               AUD_SequenceEntry_setConeVolumeOuter(strip->speaker_handle, speaker->cone_volume_outer);
-
-                                               mat4_to_quat(quat, ob->obmat);
-                                               AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_LOCATION, CFRA, ob->obmat[3], 1);
-                                               AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_ORIENTATION, CFRA, quat, 1);
-                                               AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_VOLUME, CFRA, &speaker->volume, 1);
-                                               AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_PITCH, CFRA, &speaker->pitch, 1);
-                                               AUD_SequenceEntry_setSound(strip->speaker_handle, speaker->sound->playback_handle);
-                                               AUD_SequenceEntry_setMuted(strip->speaker_handle, mute);
-                                       }
-                               }
+               BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true);
+
+               for (SceneLayer *scene_layer = scene->render_layers.first; scene_layer; scene_layer = scene_layer->next) {
+                       for (base = scene_layer->object_bases.first; base; base = base->next) {
+                               sound_update_base(scene, base, new_set);
                        }
                }
+
+               for (SETLOOPER_SET_ONLY(scene, sce_it, base)) {
+                       sound_update_base(scene, base, new_set);
+               }
+
        }
 
        while ((handle = AUD_getSet(scene->speaker_handles))) {
@@ -834,32 +925,15 @@ float BKE_sound_get_length(bSound *sound)
        return info.length;
 }
 
-char** BKE_sound_get_device_names(void)
+char **BKE_sound_get_device_names(void)
 {
-       if(audio_device_names == NULL)
-       {
-#ifdef WITH_SYSTEM_AUDASPACE
+       if (audio_device_names == NULL) {
                audio_device_names = AUD_getDeviceNames();
-#else
-               static const char* names[] = {
-                       "Null", "SDL", "OpenAL", "Jack"
-               };
-               audio_device_names = (char**)names;
-#endif
        }
 
        return audio_device_names;
 }
 
-bool BKE_sound_is_jack_supported(void)
-{
-#ifdef WITH_SYSTEM_AUDASPACE
-       return 1;
-#else
-       return (bool)AUD_isJackSupported();
-#endif
-}
-
 #else  /* WITH_AUDASPACE */
 
 #include "BLI_utildefines.h"
@@ -874,6 +948,7 @@ void BKE_sound_delete_cache(struct bSound *UNUSED(sound)) {}
 void BKE_sound_load(struct Main *UNUSED(bmain), struct bSound *UNUSED(sound)) {}
 void BKE_sound_create_scene(struct Scene *UNUSED(scene)) {}
 void BKE_sound_destroy_scene(struct Scene *UNUSED(scene)) {}
+void BKE_sound_reset_scene_specs(struct Scene *UNUSED(scene)) {}
 void BKE_sound_mute_scene(struct Scene *UNUSED(scene), int UNUSED(muted)) {}
 void *BKE_sound_scene_add_scene_sound(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence),
                                       int UNUSED(startframe), int UNUSED(endframe), int UNUSED(frameskip)) { return NULL; }
@@ -905,5 +980,6 @@ void BKE_sound_set_scene_sound_pan(void *UNUSED(handle), float UNUSED(pan), char
 void BKE_sound_set_scene_volume(struct Scene *UNUSED(scene), float UNUSED(volume)) {}
 void BKE_sound_set_scene_sound_pitch(void *UNUSED(handle), float UNUSED(pitch), char UNUSED(animated)) {}
 float BKE_sound_get_length(struct bSound *UNUSED(sound)) { return 0; }
-bool BKE_sound_is_jack_supported(void) { return false; }
+char **BKE_sound_get_device_names(void) { static char *names[1] = {NULL}; return names; }
+
 #endif  /* WITH_AUDASPACE */