doxygen: blender/blenkernel tagged.
[blender.git] / source / blender / blenkernel / intern / sound.c
index 74c6afdc018bee4a8dc206ea4a7bea57f6beabbd..cfc98b4a67d2755c9f49555092836ee349efc295 100644 (file)
@@ -1,3 +1,6 @@
+/** \file blender/blenkernel/intern/sound.c
+ *  \ingroup bke
+ */
 /**
  * sound.c (mar-2001 nzc)
  *
 
 #include "BLI_blenlib.h"
 
+#include "DNA_anim_types.h"
 #include "DNA_scene_types.h"
-#include "DNA_sound_types.h"
+#include "DNA_sequence_types.h"
 #include "DNA_packedFile_types.h"
 #include "DNA_screen_types.h"
-#include "DNA_userdef_types.h"
+#include "DNA_sound_types.h"
 
 #include "AUD_C-API.h"
 
 #include "BKE_context.h"
 #include "BKE_library.h"
 #include "BKE_packedFile.h"
+#include "BKE_fcurve.h"
+#include "BKE_animsys.h"
+
+
+static int force_device = -1;
+
+#ifdef WITH_JACK
+static void sound_sync_callback(void* data, int mode, float time)
+{
+       struct Main* bmain = (struct Main*)data;
+       struct Scene* scene;
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
+       scene = bmain->scene.first;
+       while(scene)
+       {
+               if(scene->audio.flag & AUDIO_SYNC)
+               {
+                       if(mode)
+                               sound_play_scene(scene);
+                       else
+                               sound_stop_scene(scene);
+                       AUD_seek(scene->sound_scene_handle, time);
+               }
+               scene = scene->id.next;
+       }
+}
 #endif
 
-static int sound_disabled = 0;
+int sound_define_from_str(const char *str)
+{
+       if (BLI_strcaseeq(str, "NULL"))
+               return AUD_NULL_DEVICE;
+       if (BLI_strcaseeq(str, "SDL"))
+               return AUD_SDL_DEVICE;
+       if (BLI_strcaseeq(str, "OPENAL"))
+               return AUD_OPENAL_DEVICE;
+       if (BLI_strcaseeq(str, "JACK"))
+               return AUD_JACK_DEVICE;
+
+       return -1;
+}
+
+void sound_force_device(int device)
+{
+       force_device = device;
+}
 
-void sound_disable()
+void sound_init_once(void)
 {
-       sound_disabled = 1;
+       AUD_initOnce();
 }
 
-void sound_init()
+void sound_init(struct Main *bmain)
 {
-       AUD_Specs specs;
+       AUD_DeviceSpecs specs;
        int device, buffersize;
 
        device = U.audiodevice;
@@ -49,8 +93,8 @@ void sound_init()
        specs.format = U.audioformat;
        specs.rate = U.audiorate;
 
-       if (sound_disabled)
-               device = 0;
+       if(force_device >= 0)
+               device = force_device;
 
        if(buffersize < 128)
                buffersize = AUD_DEFAULT_BUFFER_SIZE;
@@ -66,36 +110,47 @@ void sound_init()
 
        if(!AUD_init(device, specs, buffersize))
                AUD_init(AUD_NULL_DEVICE, specs, buffersize);
+               
+#ifdef WITH_JACK
+       AUD_setSyncCallback(sound_sync_callback, bmain);
+#else
+       (void)bmain; /* unused */
+#endif
 }
 
-void sound_exit()
+void sound_exit(void)
 {
        AUD_exit();
 }
 
-struct bSound* sound_new_file(struct Main *main, char* filename)
+struct bSound* sound_new_file(struct Main *bmain, const char *filename)
 {
        bSound* sound = NULL;
 
        char str[FILE_MAX];
+       char *path;
+
        int len;
 
        strcpy(str, filename);
-       BLI_convertstringcode(str, main->name);
+
+       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 = alloc_libblock(&main->sound, ID_SO, filename+len);
-       strcpy(sound->name, filename);
+       sound = alloc_libblock(&bmain->sound, ID_SO, filename+len);
+       BLI_strncpy(sound->name, filename, FILE_MAX);
 // XXX unused currently        sound->type = SOUND_TYPE_FILE;
 
-       sound_load(main, sound);
+       sound_load(bmain, sound);
 
-       if(!sound->handle)
+       if(!sound->playback_handle)
        {
-               free_libblock(&main->sound, sound);
+               free_libblock(&bmain->sound, sound);
                sound = NULL;
        }
 
@@ -119,7 +174,7 @@ struct bSound* sound_new_buffer(struct bContext *C, struct bSound *source)
 
        sound_load(CTX_data_main(C), sound);
 
-       if(!sound->handle)
+       if(!sound->playback_handle)
        {
                free_libblock(&CTX_data_main(C)->sound, sound);
                sound = NULL;
@@ -145,7 +200,7 @@ struct bSound* sound_new_limiter(struct bContext *C, struct bSound *source, floa
 
        sound_load(CTX_data_main(C), sound);
 
-       if(!sound->handle)
+       if(!sound->playback_handle)
        {
                free_libblock(&CTX_data_main(C)->sound, sound);
                sound = NULL;
@@ -161,8 +216,6 @@ void sound_delete(struct bContext *C, struct bSound* sound)
        {
                sound_free(sound);
 
-               sound_unlink(C, sound);
-
                free_libblock(&CTX_data_main(C)->sound, sound);
        }
 }
@@ -173,7 +226,7 @@ void sound_cache(struct bSound* sound, int ignore)
                AUD_unload(sound->cache);
 
        sound->cache = AUD_bufferSound(sound->handle);
-       sound->changed++;
+       sound->playback_handle = sound->cache;
 }
 
 void sound_delete_cache(struct bSound* sound)
@@ -182,10 +235,11 @@ void sound_delete_cache(struct bSound* sound)
        {
                AUD_unload(sound->cache);
                sound->cache = NULL;
+               sound->playback_handle = sound->handle;
        }
 }
 
-void sound_load(struct Main *main, struct bSound* sound)
+void sound_load(struct Main *bmain, struct bSound* sound)
 {
        if(sound)
        {
@@ -193,6 +247,7 @@ void sound_load(struct Main *main, struct bSound* sound)
                {
                        AUD_unload(sound->handle);
                        sound->handle = NULL;
+                       sound->playback_handle = NULL;
                }
 
 // XXX unused currently
@@ -212,11 +267,11 @@ void sound_load(struct Main *main, struct bSound* sound)
                        BLI_strncpy(fullpath, sound->name, sizeof(fullpath));
 
                        if(sound->id.lib)
-                               path = sound->id.lib->filename;
+                               path = sound->id.lib->filepath;
                        else
-                               path = main ? main->name : G.sce;
+                               path = bmain->name;
 
-                       BLI_convertstringcode(fullpath, path);
+                       BLI_path_abs(fullpath, path);
 
                        /* but we need a packed file then */
                        if (pf)
@@ -224,7 +279,7 @@ void sound_load(struct Main *main, struct bSound* sound)
                        /* or else load it from disk */
                        else
                                sound->handle = AUD_load(fullpath);
-               } // XXX
+               }
 // XXX unused currently
 #if 0
                        break;
@@ -239,7 +294,10 @@ void sound_load(struct Main *main, struct bSound* sound)
                        break;
                }
 #endif
-               sound->changed++;
+               if(sound->cache)
+                       sound->playback_handle = sound->cache;
+               else
+                       sound->playback_handle = sound->handle;
        }
 }
 
@@ -255,243 +313,186 @@ void sound_free(struct bSound* sound)
        {
                AUD_unload(sound->handle);
                sound->handle = NULL;
+               sound->playback_handle = NULL;
        }
 }
 
-void sound_unlink(struct bContext *C, struct bSound* sound)
+static float sound_get_volume(Scene* scene, Sequence* sequence, float time)
 {
-       Scene *scene;
-       SoundHandle *handle;
+       AnimData *adt= BKE_animdata_from_id(&scene->id);
+       FCurve *fcu = NULL;
+       char buf[64];
+       
+       /* NOTE: this manually constructed path needs to be used here to avoid problems with RNA crashes */
+       sprintf(buf, "sequence_editor.sequences_all[\"%s\"].volume", sequence->name+2);
+       if (adt && adt->action && adt->action->curves.first)
+               fcu= list_find_fcurve(&adt->action->curves, buf, 0);
+       
+       if(fcu)
+               return evaluate_fcurve(fcu, time * FPS);
+       else
+               return sequence->volume;
+}
 
-// XXX unused currently
-#if 0
-       bSound *snd;
-       for(snd = CTX_data_main(C)->sound.first; snd; snd = snd->id.next)
-       {
-               if(snd->child_sound == sound)
-               {
-                       snd->child_sound = NULL;
-                       if(snd->handle)
-                       {
-                               AUD_unload(sound->handle);
-                               snd->handle = NULL;
-                       }
-
-                       sound_unlink(C, snd);
-               }
-       }
-#endif
+AUD_Device* sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume)
+{
+       AUD_Device* mixdown = AUD_openReadDevice(specs);
 
-       for(scene = CTX_data_main(C)->scene.first; scene; scene = scene->id.next)
-       {
-               for(handle = scene->sound_handles.first; handle; handle = handle->next)
-               {
-                       if(handle->source == sound)
-                       {
-                               handle->source = NULL;
-                               if(handle->handle)
-                                       AUD_stop(handle->handle);
-                       }
-               }
-       }
+       AUD_setDeviceVolume(mixdown, volume);
+
+       AUD_playDevice(mixdown, scene->sound_scene, start / FPS);
+
+       return mixdown;
 }
 
-struct SoundHandle* sound_new_handle(struct Scene *scene, struct bSound* sound, int startframe, int endframe, int frameskip)
+void sound_create_scene(struct Scene *scene)
 {
-       ListBase* handles = &scene->sound_handles;
+       scene->sound_scene = AUD_createSequencer(scene, (AUD_volumeFunction)&sound_get_volume);
+}
 
-       SoundHandle* handle = MEM_callocN(sizeof(SoundHandle), "sound_handle");
-       handle->source = sound;
-       handle->startframe = startframe;
-       handle->endframe = endframe;
-       handle->frameskip = frameskip;
-       handle->state = AUD_STATUS_INVALID;
-       handle->volume = 1.0f;
+void sound_destroy_scene(struct Scene *scene)
+{
+       if(scene->sound_scene_handle)
+               AUD_stop(scene->sound_scene_handle);
+       if(scene->sound_scene)
+               AUD_destroySequencer(scene->sound_scene);
+}
 
-       BLI_addtail(handles, handle);
+void* sound_scene_add_scene_sound(struct Scene *scene, struct Sequence* sequence, int startframe, int endframe, int frameskip)
+{
+       if(scene != sequence->scene)
+               return AUD_addSequencer(scene->sound_scene, &(sequence->scene->sound_scene), startframe / FPS, endframe / FPS, frameskip / FPS, sequence);
+       return NULL;
+}
 
-       return handle;
+void* sound_add_scene_sound(struct Scene *scene, struct Sequence* sequence, int startframe, int endframe, int frameskip)
+{
+       return AUD_addSequencer(scene->sound_scene, &(sequence->sound->playback_handle), startframe / FPS, endframe / FPS, frameskip / FPS, sequence);
 }
 
-void sound_delete_handle(struct Scene *scene, struct SoundHandle *handle)
+void sound_remove_scene_sound(struct Scene *scene, void* handle)
 {
-       if(handle == NULL)
-               return;
+       AUD_removeSequencer(scene->sound_scene, handle);
+}
+
+void sound_mute_scene_sound(struct Scene *scene, void* handle, char mute)
+{
+       AUD_muteSequencer(scene->sound_scene, handle, mute);
+}
 
-       if(handle->handle)
-               AUD_stop(handle->handle);
+void sound_move_scene_sound(struct Scene *scene, void* handle, int startframe, int endframe, int frameskip)
+{
+       AUD_moveSequencer(scene->sound_scene, handle, startframe / FPS, endframe / FPS, frameskip / FPS);
+}
 
-       BLI_freelinkN(&scene->sound_handles, handle);
+static void sound_start_play_scene(struct Scene *scene)
+{
+       scene->sound_scene_handle = AUD_play(scene->sound_scene, 1);
+       AUD_setLoop(scene->sound_scene_handle, -1);
 }
 
-void sound_stop_all(struct bContext *C)
+void sound_play_scene(struct Scene *scene)
 {
-       SoundHandle *handle;
+       AUD_Status status;
+       AUD_lock();
+
+       status = AUD_getStatus(scene->sound_scene_handle);
 
-       for(handle = CTX_data_scene(C)->sound_handles.first; handle; handle = handle->next)
+       if(status == AUD_STATUS_INVALID)
+               sound_start_play_scene(scene);
+
+       if(status != AUD_STATUS_PLAYING)
        {
-               if(handle->state == AUD_STATUS_PLAYING)
-               {
-                       AUD_pause(handle->handle);
-                       handle->state = AUD_STATUS_PAUSED;
-               }
+               AUD_seek(scene->sound_scene_handle, CFRA / FPS);
+               AUD_resume(scene->sound_scene_handle);
        }
+
+       if(scene->audio.flag & AUDIO_SYNC)
+               AUD_startPlayback();
+
+       AUD_unlock();
+}
+
+void sound_stop_scene(struct Scene *scene)
+{
+       AUD_pause(scene->sound_scene_handle);
+
+       if(scene->audio.flag & AUDIO_SYNC)
+               AUD_stopPlayback();
 }
 
-void sound_update_playing(struct bContext *C)
+void sound_seek_scene(struct bContext *C)
 {
-       SoundHandle *handle;
-       Scene* scene = CTX_data_scene(C);
-       int cfra = CFRA;
-       float fps = FPS;
-       int action;
+       struct Scene *scene = CTX_data_scene(C);
+       AUD_Status status;
 
        AUD_lock();
 
-       for(handle = scene->sound_handles.first; handle; handle = handle->next)
+       status = AUD_getStatus(scene->sound_scene_handle);
+
+       if(status == AUD_STATUS_INVALID)
+       {
+               sound_start_play_scene(scene);
+               AUD_pause(scene->sound_scene_handle);
+       }
+
+       if(scene->audio.flag & AUDIO_SCRUB && !CTX_wm_screen(C)->animtimer)
        {
-               if(cfra < handle->startframe || cfra >= handle->endframe || handle->mute || (scene->audio.flag & AUDIO_MUTE))
+               if(scene->audio.flag & AUDIO_SYNC)
                {
-                       if(handle->state == AUD_STATUS_PLAYING)
-                       {
-                               AUD_pause(handle->handle);
-                               handle->state = AUD_STATUS_PAUSED;
-                       }
+                       AUD_seek(scene->sound_scene_handle, CFRA / FPS);
+                       AUD_seekSequencer(scene->sound_scene_handle, CFRA / FPS);
                }
+               else
+                       AUD_seek(scene->sound_scene_handle, CFRA / FPS);
+               AUD_resume(scene->sound_scene_handle);
+               if(AUD_getStatus(scene->sound_scrub_handle) != AUD_STATUS_INVALID)
+                       AUD_seek(scene->sound_scrub_handle, 0);
+               else
+                       scene->sound_scrub_handle = AUD_pauseAfter(scene->sound_scene_handle, 1 / FPS);
+       }
+       else
+       {
+               if(scene->audio.flag & AUDIO_SYNC)
+                       AUD_seekSequencer(scene->sound_scene_handle, CFRA / FPS);
                else
                {
-                       action = 0;
-
-                       if(handle->changed != handle->source->changed)
-                       {
-                               handle->changed = handle->source->changed;
-                               action = 3;
-                               if(handle->state != AUD_STATUS_INVALID)
-                               {
-                                       AUD_stop(handle->handle);
-                                       handle->state = AUD_STATUS_INVALID;
-                               }
-                       }
-                       else
-                       {
-                               if(handle->state != AUD_STATUS_PLAYING)
-                                       action = 3;
-                               else
-                               {
-                                       handle->state = AUD_getStatus(handle->handle);
-                                       if(handle->state != AUD_STATUS_PLAYING)
-                                               action = 3;
-                                       else
-                                       {
-                                               float diff = AUD_getPosition(handle->handle) * fps - cfra + handle->startframe;
-                                               if(diff < 0.0)
-                                                       diff = -diff;
-                                               if(diff > FPS/2.0)
-                                               {
-                                                       action = 2;
-                                               }
-                                       }
-                               }
-                       }
-
-                       AUD_setSoundVolume(handle->handle, handle->volume);
-                       
-                       if(action & 1)
-                       {
-                               if(handle->state == AUD_STATUS_INVALID)
-                               {
-                                       if(handle->source && handle->source->handle)
-                                       {
-                                               AUD_Sound* limiter = AUD_limitSound(handle->source->cache ? handle->source->cache : handle->source->handle, handle->frameskip / fps, (handle->frameskip + handle->endframe - handle->startframe)/fps);
-                                               handle->handle = AUD_play(limiter, 1);
-                                               AUD_unload(limiter);
-                                               if(handle->handle)
-                                                       handle->state = AUD_STATUS_PLAYING;
-                                               if(cfra == handle->startframe)
-                                                       action &= ~2;
-                                       }
-                               }
-                               else
-                                       if(AUD_resume(handle->handle))
-                                               handle->state = AUD_STATUS_PLAYING;
-                                       else
-                                               handle->state = AUD_STATUS_INVALID;
-                       }
-
-                       if(action & 2)
-                               AUD_seek(handle->handle, (cfra - handle->startframe) / fps);
+                       if(status == AUD_STATUS_PLAYING)
+                               AUD_seek(scene->sound_scene_handle, CFRA / FPS);
                }
        }
 
        AUD_unlock();
 }
 
-void sound_scrub(struct bContext *C)
+float sound_sync_scene(struct Scene *scene)
 {
-       SoundHandle *handle;
-       Scene* scene = CTX_data_scene(C);
-       int cfra = CFRA;
-       float fps = FPS;
-
-       if(scene->audio.flag & AUDIO_SCRUB && !CTX_wm_screen(C)->animtimer)
-       {
-               AUD_lock();
-
-               for(handle = scene->sound_handles.first; handle; handle = handle->next)
-               {
-                       if(cfra >= handle->startframe && cfra < handle->endframe && !handle->mute)
-                       {
-                               if(handle->source && handle->source->handle)
-                               {
-                                       int frameskip = handle->frameskip + cfra - handle->startframe;
-                                       AUD_Sound* limiter = AUD_limitSound(handle->source->cache ? handle->source->cache : handle->source->handle, frameskip / fps, (frameskip + 1)/fps);
-                                       AUD_play(limiter, 0);
-                                       AUD_unload(limiter);
-                               }
-                       }
-               }
-
-               AUD_unlock();
-       }
+       if(scene->audio.flag & AUDIO_SYNC)
+               return AUD_getSequencerPosition(scene->sound_scene_handle);
+       else
+               return AUD_getPosition(scene->sound_scene_handle);
 }
 
-AUD_Device* sound_mixdown(struct Scene *scene, AUD_Specs specs, int start, int end, float volume)
+int sound_scene_playing(struct Scene *scene)
 {
-       AUD_Device* mixdown = AUD_openReadDevice(specs);
-       SoundHandle *handle;
-       float fps = FPS;
-       AUD_Sound *limiter, *delayer;
-       int frameskip, s, e;
+       if(scene->audio.flag & AUDIO_SYNC)
+               return AUD_doesPlayback();
+       else
+               return -1;
+}
 
-       end++;
+int sound_read_sound_buffer(struct bSound* sound, float* buffer, int length, float start, float end)
+{
+       AUD_Sound* limiter = AUD_limitSound(sound->cache, start, end);
+       return AUD_readSound(limiter, buffer, length);
+       AUD_unload(limiter);
+}
 
-       AUD_setDeviceVolume(mixdown, volume);
+int sound_get_channels(struct bSound* sound)
+{
+       AUD_SoundInfo info;
 
-       for(handle = scene->sound_handles.first; handle; handle = handle->next)
-       {
-               if(start < handle->endframe && end > handle->startframe && !handle->mute && handle->source && handle->source->handle)
-               {
-                       frameskip = handle->frameskip;
-                       s = handle->startframe - start;
-                       e = handle->frameskip + AUD_MIN(handle->endframe, end) - handle->startframe;
-
-                       if(s < 0)
-                       {
-                               frameskip -= s;
-                               s = 0;
-                       }
-                       
-                       AUD_setSoundVolume(handle->handle, handle->volume);
-                       
-                       limiter = AUD_limitSound(handle->source->handle, frameskip / fps, e / fps);
-                       delayer = AUD_delaySound(limiter, s / fps);
-
-                       AUD_playDevice(mixdown, delayer);
-
-                       AUD_unload(delayer);
-                       AUD_unload(limiter);
-               }
-       }
+       info = AUD_getInfo(sound->playback_handle);
 
-       return mixdown;
+       return info.specs.channels;
 }