copy of docs from 2.4x for python modules that have been kept
[blender.git] / source / blender / blenkernel / intern / sound.c
1 /**
2  * sound.c (mar-2001 nzc)
3  *
4  * $Id$
5  */
6
7 #include <string.h>
8 #include <stdlib.h>
9
10 #include "MEM_guardedalloc.h"
11
12 #include "BLI_blenlib.h"
13
14 #include "DNA_scene_types.h"
15 #include "DNA_sound_types.h"
16 #include "DNA_packedFile_types.h"
17 #include "DNA_screen_types.h"
18 #include "DNA_userdef_types.h"
19
20 #include "AUD_C-API.h"
21
22 #include "BKE_utildefines.h"
23 #include "BKE_global.h"
24 #include "BKE_main.h"
25 #include "BKE_sound.h"
26 #include "BKE_context.h"
27 #include "BKE_library.h"
28 #include "BKE_packedFile.h"
29
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33
34 static int sound_disabled = 0;
35
36 void sound_disable()
37 {
38         sound_disabled = 1;
39 }
40
41 void sound_init()
42 {
43         AUD_DeviceSpecs specs;
44         int device, buffersize;
45
46         device = U.audiodevice;
47         buffersize = U.mixbufsize;
48         specs.channels = U.audiochannels;
49         specs.format = U.audioformat;
50         specs.rate = U.audiorate;
51
52         if (sound_disabled)
53                 device = 0;
54
55         if(buffersize < 128)
56                 buffersize = AUD_DEFAULT_BUFFER_SIZE;
57
58         if(specs.rate < AUD_RATE_8000)
59                 specs.rate = AUD_RATE_44100;
60
61         if(specs.format <= AUD_FORMAT_INVALID)
62                 specs.format = AUD_FORMAT_S16;
63
64         if(specs.channels <= AUD_CHANNELS_INVALID)
65                 specs.channels = AUD_CHANNELS_STEREO;
66
67         if(!AUD_init(device, specs, buffersize))
68                 AUD_init(AUD_NULL_DEVICE, specs, buffersize);
69 }
70
71 void sound_exit()
72 {
73         AUD_exit();
74 }
75
76 struct bSound* sound_new_file(struct Main *main, char* filename)
77 {
78         bSound* sound = NULL;
79
80         char str[FILE_MAX];
81         int len;
82
83         strcpy(str, filename);
84         BLI_convertstringcode(str, main->name);
85
86         len = strlen(filename);
87         while(len > 0 && filename[len-1] != '/' && filename[len-1] != '\\')
88                 len--;
89
90         sound = alloc_libblock(&main->sound, ID_SO, filename+len);
91         strcpy(sound->name, filename);
92 // XXX unused currently sound->type = SOUND_TYPE_FILE;
93
94         sound_load(main, sound);
95
96         if(!sound->handle)
97         {
98                 free_libblock(&main->sound, sound);
99                 sound = NULL;
100         }
101
102         return sound;
103 }
104
105 // XXX unused currently
106 #if 0
107 struct bSound* sound_new_buffer(struct bContext *C, struct bSound *source)
108 {
109         bSound* sound = NULL;
110
111         char name[25];
112         strcpy(name, "buf_");
113         strcpy(name + 4, source->id.name);
114
115         sound = alloc_libblock(&CTX_data_main(C)->sound, ID_SO, name);
116
117         sound->child_sound = source;
118         sound->type = SOUND_TYPE_BUFFER;
119
120         sound_load(CTX_data_main(C), sound);
121
122         if(!sound->handle)
123         {
124                 free_libblock(&CTX_data_main(C)->sound, sound);
125                 sound = NULL;
126         }
127
128         return sound;
129 }
130
131 struct bSound* sound_new_limiter(struct bContext *C, struct bSound *source, float start, float end)
132 {
133         bSound* sound = NULL;
134
135         char name[25];
136         strcpy(name, "lim_");
137         strcpy(name + 4, source->id.name);
138
139         sound = alloc_libblock(&CTX_data_main(C)->sound, ID_SO, name);
140
141         sound->child_sound = source;
142         sound->start = start;
143         sound->end = end;
144         sound->type = SOUND_TYPE_LIMITER;
145
146         sound_load(CTX_data_main(C), sound);
147
148         if(!sound->handle)
149         {
150                 free_libblock(&CTX_data_main(C)->sound, sound);
151                 sound = NULL;
152         }
153
154         return sound;
155 }
156 #endif
157
158 void sound_delete(struct bContext *C, struct bSound* sound)
159 {
160         if(sound)
161         {
162                 sound_free(sound);
163
164                 sound_unlink(C, sound);
165
166                 free_libblock(&CTX_data_main(C)->sound, sound);
167         }
168 }
169
170 void sound_cache(struct bSound* sound, int ignore)
171 {
172         if(sound->cache && !ignore)
173                 AUD_unload(sound->cache);
174
175         sound->cache = AUD_bufferSound(sound->handle);
176         sound->changed++;
177 }
178
179 void sound_delete_cache(struct bSound* sound)
180 {
181         if(sound->cache)
182         {
183                 AUD_unload(sound->cache);
184                 sound->cache = NULL;
185         }
186 }
187
188 void sound_load(struct Main *main, struct bSound* sound)
189 {
190         if(sound)
191         {
192                 if(sound->handle)
193                 {
194                         AUD_unload(sound->handle);
195                         sound->handle = NULL;
196                 }
197
198 // XXX unused currently
199 #if 0
200                 switch(sound->type)
201                 {
202                 case SOUND_TYPE_FILE:
203 #endif
204                 {
205                         char fullpath[FILE_MAX];
206                         char *path;
207
208                         /* load sound */
209                         PackedFile* pf = sound->packedfile;
210
211                         /* dont modify soundact->sound->name, only change a copy */
212                         BLI_strncpy(fullpath, sound->name, sizeof(fullpath));
213
214                         if(sound->id.lib)
215                                 path = sound->id.lib->filename;
216                         else
217                                 path = main ? main->name : G.sce;
218
219                         BLI_convertstringcode(fullpath, path);
220
221                         /* but we need a packed file then */
222                         if (pf)
223                                 sound->handle = AUD_loadBuffer((unsigned char*) pf->data, pf->size);
224                         /* or else load it from disk */
225                         else
226                                 sound->handle = AUD_load(fullpath);
227                 } // XXX
228 // XXX unused currently
229 #if 0
230                         break;
231                 }
232                 case SOUND_TYPE_BUFFER:
233                         if(sound->child_sound && sound->child_sound->handle)
234                                 sound->handle = AUD_bufferSound(sound->child_sound->handle);
235                         break;
236                 case SOUND_TYPE_LIMITER:
237                         if(sound->child_sound && sound->child_sound->handle)
238                                 sound->handle = AUD_limitSound(sound->child_sound, sound->start, sound->end);
239                         break;
240                 }
241 #endif
242                 sound->changed++;
243         }
244 }
245
246 void sound_free(struct bSound* sound)
247 {
248         if (sound->packedfile)
249         {
250                 freePackedFile(sound->packedfile);
251                 sound->packedfile = NULL;
252         }
253
254         if(sound->handle)
255         {
256                 AUD_unload(sound->handle);
257                 sound->handle = NULL;
258         }
259 }
260
261 void sound_unlink(struct bContext *C, struct bSound* sound)
262 {
263         Scene *scene;
264         SoundHandle *handle;
265
266 // XXX unused currently
267 #if 0
268         bSound *snd;
269         for(snd = CTX_data_main(C)->sound.first; snd; snd = snd->id.next)
270         {
271                 if(snd->child_sound == sound)
272                 {
273                         snd->child_sound = NULL;
274                         if(snd->handle)
275                         {
276                                 AUD_unload(sound->handle);
277                                 snd->handle = NULL;
278                         }
279
280                         sound_unlink(C, snd);
281                 }
282         }
283 #endif
284
285         for(scene = CTX_data_main(C)->scene.first; scene; scene = scene->id.next)
286         {
287                 for(handle = scene->sound_handles.first; handle; handle = handle->next)
288                 {
289                         if(handle->source == sound)
290                         {
291                                 handle->source = NULL;
292                                 if(handle->handle)
293                                         AUD_stop(handle->handle);
294                         }
295                 }
296         }
297 }
298
299 struct SoundHandle* sound_new_handle(struct Scene *scene, struct bSound* sound, int startframe, int endframe, int frameskip)
300 {
301         ListBase* handles = &scene->sound_handles;
302
303         SoundHandle* handle = MEM_callocN(sizeof(SoundHandle), "sound_handle");
304         handle->source = sound;
305         handle->startframe = startframe;
306         handle->endframe = endframe;
307         handle->frameskip = frameskip;
308         handle->state = AUD_STATUS_INVALID;
309         handle->volume = 1.0f;
310
311         BLI_addtail(handles, handle);
312
313         return handle;
314 }
315
316 void sound_delete_handle(struct Scene *scene, struct SoundHandle *handle)
317 {
318         if(handle == NULL)
319                 return;
320
321         if(handle->handle)
322                 AUD_stop(handle->handle);
323
324         BLI_freelinkN(&scene->sound_handles, handle);
325 }
326
327 void sound_stop_all(struct bContext *C)
328 {
329         SoundHandle *handle;
330
331         for(handle = CTX_data_scene(C)->sound_handles.first; handle; handle = handle->next)
332         {
333                 if(handle->state == AUD_STATUS_PLAYING)
334                 {
335                         AUD_pause(handle->handle);
336                         handle->state = AUD_STATUS_PAUSED;
337                 }
338         }
339 }
340
341 void sound_update_playing(struct bContext *C)
342 {
343         SoundHandle *handle;
344         Scene* scene = CTX_data_scene(C);
345         int cfra = CFRA;
346         float fps = FPS;
347         int action;
348
349         AUD_lock();
350
351         for(handle = scene->sound_handles.first; handle; handle = handle->next)
352         {
353                 if(cfra < handle->startframe || cfra >= handle->endframe || handle->mute || (scene->audio.flag & AUDIO_MUTE))
354                 {
355                         if(handle->state == AUD_STATUS_PLAYING)
356                         {
357                                 AUD_pause(handle->handle);
358                                 handle->state = AUD_STATUS_PAUSED;
359                         }
360                 }
361                 else
362                 {
363                         action = 0;
364
365                         if(handle->changed != handle->source->changed)
366                         {
367                                 handle->changed = handle->source->changed;
368                                 action = 3;
369                                 if(handle->state != AUD_STATUS_INVALID)
370                                 {
371                                         AUD_stop(handle->handle);
372                                         handle->state = AUD_STATUS_INVALID;
373                                 }
374                         }
375                         else
376                         {
377                                 if(handle->state != AUD_STATUS_PLAYING)
378                                         action = 3;
379                                 else
380                                 {
381                                         handle->state = AUD_getStatus(handle->handle);
382                                         if(handle->state != AUD_STATUS_PLAYING)
383                                                 action = 3;
384                                         else
385                                         {
386                                                 float diff = AUD_getPosition(handle->handle) * fps - cfra + handle->startframe;
387                                                 if(diff < 0.0)
388                                                         diff = -diff;
389                                                 if(diff > FPS/2.0)
390                                                 {
391                                                         action = 2;
392                                                 }
393                                         }
394                                 }
395                         }
396
397                         AUD_setSoundVolume(handle->handle, handle->volume);
398                         
399                         if(action & 1)
400                         {
401                                 if(handle->state == AUD_STATUS_INVALID)
402                                 {
403                                         if(handle->source && handle->source->handle)
404                                         {
405                                                 AUD_Sound* limiter = AUD_limitSound(handle->source->cache ? handle->source->cache : handle->source->handle, handle->frameskip / fps, (handle->frameskip + handle->endframe - handle->startframe)/fps);
406                                                 handle->handle = AUD_play(limiter, 1);
407                                                 AUD_unload(limiter);
408                                                 if(handle->handle)
409                                                         handle->state = AUD_STATUS_PLAYING;
410                                                 if(cfra == handle->startframe)
411                                                         action &= ~2;
412                                         }
413                                 }
414                                 else
415                                         if(AUD_resume(handle->handle))
416                                                 handle->state = AUD_STATUS_PLAYING;
417                                         else
418                                                 handle->state = AUD_STATUS_INVALID;
419                         }
420
421                         if(action & 2)
422                                 AUD_seek(handle->handle, (cfra - handle->startframe) / fps);
423                 }
424         }
425
426         AUD_unlock();
427 }
428
429 void sound_scrub(struct bContext *C)
430 {
431         SoundHandle *handle;
432         Scene* scene = CTX_data_scene(C);
433         int cfra = CFRA;
434         float fps = FPS;
435
436         if(scene->audio.flag & AUDIO_SCRUB && !CTX_wm_screen(C)->animtimer)
437         {
438                 AUD_lock();
439
440                 for(handle = scene->sound_handles.first; handle; handle = handle->next)
441                 {
442                         if(cfra >= handle->startframe && cfra < handle->endframe && !handle->mute)
443                         {
444                                 if(handle->source && handle->source->handle)
445                                 {
446                                         int frameskip = handle->frameskip + cfra - handle->startframe;
447                                         AUD_Sound* limiter = AUD_limitSound(handle->source->cache ? handle->source->cache : handle->source->handle, frameskip / fps, (frameskip + 1)/fps);
448                                         AUD_play(limiter, 0);
449                                         AUD_unload(limiter);
450                                 }
451                         }
452                 }
453
454                 AUD_unlock();
455         }
456 }
457
458 AUD_Device* sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, int end, float volume)
459 {
460         AUD_Device* mixdown = AUD_openReadDevice(specs);
461         SoundHandle *handle;
462         float fps = FPS;
463         AUD_Sound *limiter, *delayer;
464         int frameskip, s, e;
465
466         end++;
467
468         AUD_setDeviceVolume(mixdown, volume);
469
470         for(handle = scene->sound_handles.first; handle; handle = handle->next)
471         {
472                 if(start < handle->endframe && end > handle->startframe && !handle->mute && handle->source && handle->source->handle)
473                 {
474                         frameskip = handle->frameskip;
475                         s = handle->startframe - start;
476                         e = handle->frameskip + AUD_MIN(handle->endframe, end) - handle->startframe;
477
478                         if(s < 0)
479                         {
480                                 frameskip -= s;
481                                 s = 0;
482                         }
483                         
484                         AUD_setSoundVolume(handle->handle, handle->volume);
485                         
486                         limiter = AUD_limitSound(handle->source->handle, frameskip / fps, e / fps);
487                         delayer = AUD_delaySound(limiter, s / fps);
488
489                         AUD_playDevice(mixdown, delayer);
490
491                         AUD_unload(delayer);
492                         AUD_unload(limiter);
493                 }
494         }
495
496         return mixdown;
497 }