Blender V5.0
blenkernel/intern/sound.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <chrono>
10#include <condition_variable>
11#include <cstdlib>
12#include <cstring>
13#include <mutex>
14#include <optional>
15#include <thread>
16
17#include "MEM_guardedalloc.h"
18
19#include "BLI_build_config.h"
20#include "BLI_listbase.h"
21#include "BLI_math_base.h"
22#include "BLI_math_rotation.h"
23#include "BLI_path_utils.hh"
24#include "BLI_string.h"
25#include "BLI_threads.h"
26
27#include "BLT_translation.hh"
28
29/* Allow using deprecated functionality for .blend file I/O. */
30#define DNA_DEPRECATED_ALLOW
31
32#include "DNA_anim_types.h"
33#include "DNA_object_types.h"
35#include "DNA_scene_types.h"
36#include "DNA_screen_types.h"
37#include "DNA_sequence_types.h"
38#include "DNA_sound_types.h"
39#include "DNA_speaker_types.h"
40#include "DNA_userdef_types.h"
41
42#ifdef WITH_AUDASPACE
44# include <AUD_Handle.h>
45# include <AUD_Sequence.h>
46# include <AUD_Sound.h>
47# include <AUD_Special.h>
48# include <AUD_Types.h>
49#endif
50
51#include "BKE_bpath.hh"
52#include "BKE_global.hh"
53#include "BKE_idtype.hh"
54#include "BKE_lib_id.hh"
55#include "BKE_lib_query.hh"
56#include "BKE_library.hh"
57#include "BKE_main.hh"
58#include "BKE_packedFile.hh"
59#include "BKE_sound.h"
60
61#include "DEG_depsgraph.hh"
63
64#include "BLO_read_write.hh"
65
66#include "SEQ_sound.hh"
67#include "SEQ_time.hh"
68
69#include "CLG_log.h"
70
71static void sound_free_audio(bSound *sound);
72
73static void sound_copy_data(Main * /*bmain*/,
74 std::optional<Library *> /*owner_library*/,
75 ID *id_dst,
76 const ID *id_src,
77 const int /*flag*/)
78{
79 bSound *sound_dst = (bSound *)id_dst;
80 const bSound *sound_src = (const bSound *)id_src;
81
82 sound_dst->handle = nullptr;
83 sound_dst->cache = nullptr;
84 sound_dst->waveform = nullptr;
85 sound_dst->playback_handle = nullptr;
86 sound_dst->spinlock = (void *)MEM_mallocN<SpinLock>("sound_spinlock");
87 BLI_spin_init(static_cast<SpinLock *>(sound_dst->spinlock));
88
89 /* Just to be sure, should not have any value actually after reading time. */
90 sound_dst->newpackedfile = nullptr;
91
92 if (sound_src->packedfile != nullptr) {
93 sound_dst->packedfile = BKE_packedfile_duplicate(sound_src->packedfile);
94 }
95
96 BKE_sound_reset_runtime(sound_dst);
97}
98
99static void sound_free_data(ID *id)
100{
101 bSound *sound = (bSound *)id;
102
103 /* No animation-data here. */
104
105 if (sound->packedfile) {
107 sound->packedfile = nullptr;
108 }
109
110 sound_free_audio(sound);
112
113 if (sound->spinlock) {
114 BLI_spin_end(static_cast<SpinLock *>(sound->spinlock));
115 /* The void cast is needed when building without TBB. */
116 MEM_freeN((void *)static_cast<SpinLock *>(sound->spinlock));
117 sound->spinlock = nullptr;
118 }
119}
120
121static void sound_foreach_cache(ID *id,
122 IDTypeForeachCacheFunctionCallback function_callback,
123 void *user_data)
124{
125 bSound *sound = (bSound *)id;
126 IDCacheKey key{};
127 key.id_session_uid = id->session_uid;
128 key.identifier = offsetof(bSound, waveform);
129
130 function_callback(id, &key, &sound->waveform, 0, user_data);
131}
132
133static void sound_foreach_path(ID *id, BPathForeachPathData *bpath_data)
134{
135 bSound *sound = (bSound *)id;
136 if (sound->packedfile != nullptr && (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0)
137 {
138 return;
139 }
140
141 /* FIXME: This does not check for empty path... */
142 BKE_bpath_foreach_path_fixed_process(bpath_data, sound->filepath, sizeof(sound->filepath));
143}
144
145static void sound_blend_write(BlendWriter *writer, ID *id, const void *id_address)
146{
147 bSound *sound = (bSound *)id;
148 const bool is_undo = BLO_write_is_undo(writer);
149
150 /* Clean up, important in undo case to reduce false detection of changed datablocks. */
151 sound->tags = 0;
152 sound->handle = nullptr;
153 sound->playback_handle = nullptr;
154 sound->spinlock = nullptr;
155
156 /* Do not store packed files in case this is a library override ID. */
157 if (ID_IS_OVERRIDE_LIBRARY(sound) && !is_undo) {
158 sound->packedfile = nullptr;
159 }
160
161 /* write LibData */
162 BLO_write_id_struct(writer, bSound, id_address, &sound->id);
163 BKE_id_blend_write(writer, &sound->id);
164
166}
167
168static void sound_blend_read_data(BlendDataReader *reader, ID *id)
169{
170 bSound *sound = (bSound *)id;
171 sound->tags = 0;
172 sound->handle = nullptr;
173 sound->playback_handle = nullptr;
174
175 /* versioning stuff, if there was a cache, then we enable caching: */
176 if (sound->cache) {
177 sound->flags |= SOUND_FLAGS_CACHING;
178 sound->cache = nullptr;
179 }
180
181 if (BLO_read_data_is_undo(reader)) {
183 }
184
185 sound->spinlock = (void *)MEM_mallocN<SpinLock>("sound_spinlock");
186 BLI_spin_init(static_cast<SpinLock *>(sound->spinlock));
187
188 /* clear waveform loading flag */
190
191 BKE_packedfile_blend_read(reader, &sound->packedfile, sound->filepath);
192 BKE_packedfile_blend_read(reader, &sound->newpackedfile, sound->filepath);
193}
194
196 /*id_code*/ bSound::id_type,
197 /*id_filter*/ FILTER_ID_SO,
198 /*dependencies_id_types*/ 0,
199 /*main_listbase_index*/ INDEX_ID_SO,
200 /*struct_size*/ sizeof(bSound),
201 /*name*/ "Sound",
202 /*name_plural*/ N_("sounds"),
203 /*translation_context*/ BLT_I18NCONTEXT_ID_SOUND,
205 /*asset_type_info*/ nullptr,
206
207 /* A fuzzy case, think NULLified content is OK here... */
208 /*init_data*/ nullptr,
209 /*copy_data*/ sound_copy_data,
210 /*free_data*/ sound_free_data,
211 /*make_local*/ nullptr,
212 /*foreach_id*/ nullptr,
213 /*foreach_cache*/ sound_foreach_cache,
214 /*foreach_path*/ sound_foreach_path,
215 /*foreach_working_space_color*/ nullptr,
216 /*owner_pointer_get*/ nullptr,
217
218 /*blend_write*/ sound_blend_write,
219 /*blend_read_data*/ sound_blend_read_data,
220 /*blend_read_after_liblink*/ nullptr,
221
222 /*blend_read_undo_preserve*/ nullptr,
223
224 /*lib_override_apply_post*/ nullptr,
225};
226
227#ifdef WITH_AUDASPACE
228/* evil globals ;-) */
229static char **audio_device_names = nullptr;
230#endif
231
233{
235 /* This is a bit tricky and not quite reliable, but good enough check.
236 *
237 * We don't want audio system handles to be allocated on an original data-blocks, and only want
238 * them to be allocated on a data-blocks which are result of dependency graph evaluation.
239 *
240 * Data-blocks which are covered by a copy-on-evaluation system of dependency graph will have
241 * ID_TAG_COPIED_ON_EVAL tag set on them. But if some of data-blocks during its evaluation
242 * decides to re-allocate its nested one (for example, object evaluation could re-allocate mesh
243 * when evaluating modifier stack). Such data-blocks will have
244 * ID_TAG_COPIED_ON_EVAL_FINAL_RESULT tag set on them.
245 *
246 * Additionally, we also allow data-blocks outside of main database. Those can not be "original"
247 * and could be used as a temporary evaluated result during operations like baking.
248 *
249 * NOTE: We consider ID evaluated if ANY of those flags is set. We do NOT require ALL of them.
250 */
251 BLI_assert(id->tag &
253}
254
255bSound *BKE_sound_new_file(Main *bmain, const char *filepath)
256{
257 bSound *sound;
258 const char *blendfile_path = BKE_main_blendfile_path(bmain);
259 char filepath_abs[FILE_MAX];
260
261 STRNCPY(filepath_abs, filepath);
262 BLI_path_abs(filepath_abs, blendfile_path);
263
264 sound = static_cast<bSound *>(BKE_libblock_alloc(bmain, ID_SO, BLI_path_basename(filepath), 0));
265 STRNCPY(sound->filepath, filepath);
266 // sound->type = SOUND_TYPE_FILE; /* UNUSED. */
267
268 /* Extract sound specs for bSound */
269 SoundInfo info;
270 bool success = BKE_sound_info_get(bmain, sound, &info);
271 if (success) {
272 sound->samplerate = info.specs.samplerate;
273 sound->audio_channels = info.specs.channels;
274 }
275
276 sound->spinlock = (void *)MEM_mallocN<SpinLock>("sound_spinlock");
277 BLI_spin_init(static_cast<SpinLock *>(sound->spinlock));
278
280
281 return sound;
282}
283
284bSound *BKE_sound_new_file_exists_ex(Main *bmain, const char *filepath, bool *r_exists)
285{
286 bSound *sound;
287 char filepath_abs[FILE_MAX], filepath_test[FILE_MAX];
288
289 STRNCPY(filepath_abs, filepath);
290 BLI_path_abs(filepath_abs, BKE_main_blendfile_path(bmain));
291
292 /* first search an identical filepath */
293 for (sound = static_cast<bSound *>(bmain->sounds.first); sound;
294 sound = static_cast<bSound *>(sound->id.next))
295 {
296 STRNCPY(filepath_test, sound->filepath);
297 BLI_path_abs(filepath_test, ID_BLEND_PATH(bmain, &sound->id));
298
299 if (BLI_path_cmp(filepath_test, filepath_abs) == 0) {
300 id_us_plus(&sound->id); /* officially should not, it doesn't link here! */
301 if (r_exists) {
302 *r_exists = true;
303 }
304 return sound;
305 }
306 }
307
308 if (r_exists) {
309 *r_exists = false;
310 }
311 return BKE_sound_new_file(bmain, filepath);
312}
313
314bSound *BKE_sound_new_file_exists(Main *bmain, const char *filepath)
315{
316 return BKE_sound_new_file_exists_ex(bmain, filepath, nullptr);
317}
318
319static void sound_free_audio(bSound *sound)
320{
321#ifdef WITH_AUDASPACE
322 if (sound->handle) {
323 AUD_Sound_free(sound->handle);
324 sound->handle = nullptr;
325 sound->playback_handle = nullptr;
326 }
327
328 if (sound->cache) {
329 AUD_Sound_free(sound->cache);
330 sound->cache = nullptr;
331 }
332#else
333 UNUSED_VARS(sound);
334#endif /* WITH_AUDASPACE */
335}
336
337#ifdef WITH_AUDASPACE
338static CLG_LogRef LOG = {"sound"};
339
340namespace {
341
342struct GlobalState {
343 const char *force_device = nullptr;
344
345 /* Parameters of the opened device */
346 const char *device_name = nullptr;
347 AUD_DeviceSpecs initialized_specs;
348
349 /* Device handle and its synchronization mutex. */
350 AUD_Device *sound_device = nullptr;
351 int buffer_size = 0;
352 std::mutex sound_device_mutex;
353
354 bool need_exit = false;
355 bool use_delayed_close = true;
356 std::thread delayed_close_thread;
357 std::condition_variable delayed_close_cv;
358
359 int num_device_users = 0;
360 std::chrono::time_point<std::chrono::steady_clock> last_user_disconnect_time_point;
361
362 ~GlobalState()
363 {
364 /* Ensure that we don't end up in a deadlock if the global state is being cleaned up
365 * before BKE_sound_exit_once has been called. (For example if someone called exit()
366 * to quickly close the program without cleaning up)
367 *
368 * If we don't do this, we could end up in a state where this destructor is waiting for
369 * other threads to let go of delayed_close_cv forever. See #146640.
370 */
371 exit_threads();
372 }
373
374 void exit_threads()
375 {
376 {
377 std::unique_lock lock(sound_device_mutex);
378 need_exit = true;
379 }
380
381 if (delayed_close_thread.joinable()) {
382 delayed_close_cv.notify_all();
383 delayed_close_thread.join();
384 }
385 }
386};
387
388GlobalState g_state;
389} // namespace
390
391static void sound_device_close_no_lock()
392{
393 if (g_state.sound_device) {
394 CLOG_DEBUG(&LOG, "Closing audio device");
395 AUD_exit(g_state.sound_device);
396 g_state.sound_device = nullptr;
397 }
398}
399
400static void sound_device_open_no_lock(AUD_DeviceSpecs requested_specs)
401{
402 BLI_assert(!g_state.sound_device);
403
404 CLOG_DEBUG(&LOG, "Opening audio device name:%s", g_state.device_name);
405
406 g_state.sound_device = AUD_init(
407 g_state.device_name, requested_specs, g_state.buffer_size, "Blender");
408 if (!g_state.sound_device) {
409 g_state.sound_device = AUD_init("None", requested_specs, g_state.buffer_size, "Blender");
410 }
411
412 g_state.initialized_specs.channels = AUD_Device_getChannels(g_state.sound_device);
413 g_state.initialized_specs.rate = AUD_Device_getRate(g_state.sound_device);
414 g_state.initialized_specs.format = AUD_Device_getFormat(g_state.sound_device);
415}
416
417static void sound_device_use_begin()
418{
419 ++g_state.num_device_users;
420
421 if (g_state.sound_device) {
422 return;
423 }
424
425 sound_device_open_no_lock(g_state.initialized_specs);
426}
427
428static void sound_device_use_end_after(const std::chrono::milliseconds after_ms)
429{
430 BLI_assert(g_state.num_device_users > 0);
431 if (g_state.num_device_users == 0) {
432 return;
433 }
434
435 --g_state.num_device_users;
436 if (g_state.num_device_users == 0) {
437 g_state.last_user_disconnect_time_point = std::chrono::steady_clock::now() + after_ms;
438 g_state.delayed_close_cv.notify_one();
439 }
440}
441
442static void sound_device_use_end()
443{
444 sound_device_use_end_after(std::chrono::milliseconds(0));
445}
446
447/* Return true if we need a thread which checks for device usage and closes it when it is inactive.
448 * Only runtime-invariant checks are done here, such as possible platform-specific requirements.
449 */
450static bool sound_use_close_thread()
451{
452 /* No point starting a thread if sound is disabled and we're running headless. */
453 if (g_state.force_device && STREQ(g_state.force_device, "None")) {
454# if defined(WITH_PYTHON_MODULE) || defined(WITH_HEADLESS)
455 return false;
456# endif
457 if (G.background) {
458 return false;
459 }
460 }
461
462# if OS_MAC
463 /* Closing audio device on macOS prior to 15.2 could lead to interference with other software.
464 * See #121911 for details. */
465 if (__builtin_available(macOS 15.2, *)) {
466 return true;
467 }
468 return false;
469# else
470 return true;
471# endif
472}
473
474static void delayed_close_thread_run()
475{
476 constexpr std::chrono::milliseconds device_close_delay{30000};
477
478 std::unique_lock lock(g_state.sound_device_mutex);
479
480 while (!g_state.need_exit) {
481 if (!g_state.use_delayed_close) {
482 CLOG_DEBUG(&LOG, "Delayed device close is disabled");
483 /* Don't do anything here as delayed close is disabled.
484 * Wait so that we don't spin around in the while loop. */
485 g_state.delayed_close_cv.wait(lock);
486 continue;
487 }
488
489 if (g_state.num_device_users == 0) {
490 if (g_state.sound_device == nullptr) {
491 /* There are no device users, wait until there is device to be waited for to close. */
492 g_state.delayed_close_cv.wait(lock);
493 }
494 else {
495 g_state.delayed_close_cv.wait_until(
496 lock, g_state.last_user_disconnect_time_point + device_close_delay);
497 }
498 }
499 else {
500 /* If there are active device users wait indefinitely, until the system is requested to be
501 * closed or the user stops using device.
502 * It is not really guaranteed that the CV is notified for every user that stops using
503 * device, only the last one is guaranteed to notify the CV. */
504 g_state.delayed_close_cv.wait(lock);
505 }
506
507 if (g_state.need_exit) {
508 CLOG_DEBUG(&LOG, "System exit requested");
509 break;
510 }
511
512 if (!g_state.use_delayed_close) {
513 /* Take into account corner case where you switch from a delayed close device while Blender
514 * is running and a delayed close has already been queued up. */
515 continue;
516 }
517
518 if (!g_state.sound_device) {
519 CLOG_DEBUG(&LOG, "Device is not open, nothing to do");
520 continue;
521 }
522
523 CLOG_DEBUG(&LOG, "Checking last device usage and timestamp");
524
525 if (g_state.num_device_users) {
526 CLOG_DEBUG(&LOG, "Device is used by %d user(s)", g_state.num_device_users);
527 continue;
528 }
529
530 const std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
531 if ((now - g_state.last_user_disconnect_time_point) >= device_close_delay) {
532 sound_device_close_no_lock();
533 }
534 }
535
536 CLOG_DEBUG(&LOG, "Delayed device close thread finished");
537}
538
540
541static void sound_sync_callback(void *data, int mode, float time)
542{
543 if (sound_jack_sync_callback == nullptr) {
544 return;
545 }
546 Main *bmain = (Main *)data;
547 sound_jack_sync_callback(bmain, mode, time);
548}
549
550void BKE_sound_force_device(const char *device)
551{
552 g_state.force_device = device;
553}
554
556{
557 AUD_initOnce();
558 if (sound_use_close_thread()) {
559 CLOG_DEBUG(&LOG, "Using delayed device close thread");
560 g_state.delayed_close_thread = std::thread(delayed_close_thread_run);
561 }
562}
563
564void BKE_sound_exit()
565{
566 std::lock_guard lock(g_state.sound_device_mutex);
567 sound_device_close_no_lock();
568}
569
571{
572 g_state.exit_threads();
573
574 std::lock_guard lock(g_state.sound_device_mutex);
575 sound_device_close_no_lock();
576 AUD_exitOnce();
577
578 if (audio_device_names != nullptr) {
579 int i;
580 for (i = 0; audio_device_names[i]; i++) {
581 free(audio_device_names[i]);
582 }
583 free(audio_device_names);
584 audio_device_names = nullptr;
585 }
586}
587
588void BKE_sound_init(Main *bmain)
589{
590 std::lock_guard lock(g_state.sound_device_mutex);
591 /* Make sure no instance of the sound system is running, otherwise we get leaks. */
592 sound_device_close_no_lock();
593
594 AUD_DeviceSpecs requested_specs;
595 requested_specs.channels = AUD_Channels(U.audiochannels);
596 requested_specs.format = AUD_SampleFormat(U.audioformat);
597 requested_specs.rate = U.audiorate;
598
599 if (g_state.force_device == nullptr) {
600 char **names = BKE_sound_get_device_names();
601 g_state.device_name = names[0];
602
603 /* make sure device is within the bounds of the array */
604 for (int i = 0; names[i]; i++) {
605 if (i == U.audiodevice) {
606 g_state.device_name = names[i];
607 }
608 }
609 }
610 else {
611 g_state.device_name = g_state.force_device;
612 }
613
614 g_state.buffer_size = U.mixbufsize < 128 ? 1024 : U.mixbufsize;
615
616 if (requested_specs.rate < AUD_RATE_8000) {
617 requested_specs.rate = AUD_RATE_48000;
618 }
619
620 if (requested_specs.format <= AUD_FORMAT_INVALID) {
621 requested_specs.format = AUD_FORMAT_S16;
622 }
623
624 if (requested_specs.channels <= AUD_CHANNELS_INVALID) {
625 requested_specs.channels = AUD_CHANNELS_STEREO;
626 }
627
628 /* Make sure that we have our initalized_specs */
629 sound_device_open_no_lock(requested_specs);
630 if (STR_ELEM(g_state.device_name, "JACK", "PulseAudio", "PipeWire")) {
631 /* JACK:
632 * Do not close the device when using JACK. If we close it, we will not be able to
633 * respond to JACK audio bus commands.
634 *
635 * PulseAudio, PipeWire:
636 * These APIs are built around the idea that the program using them keeps the device open.
637 * Instead it uses audio streams to determine if something is playing back audio or not.
638 * These streams are only active when Audaspace is playing back, so we don't need to
639 * do anything manually.
640 * If we close these devices, it will become very hard and tedious for end users to
641 * control the volume or route audio from Blender.
642 */
643 g_state.use_delayed_close = false;
644 AUD_setSynchronizerCallback(sound_sync_callback, bmain);
645 }
646 else {
647 g_state.use_delayed_close = true;
648 sound_device_close_no_lock();
649 }
650}
651
653{
654 std::lock_guard lock(g_state.sound_device_mutex);
655 if (g_state.sound_device) {
656 AUD_setSynchronizerCallback(sound_sync_callback, bmain);
657 }
658}
659
660/* XXX unused currently */
661# if 0
662bSound *BKE_sound_new_buffer(Main *bmain, bSound *source)
663{
664 bSound *sound = nullptr;
665
666 char name[MAX_ID_NAME + 5];
667 BLI_string_join(name, sizeof(name), "buf_", source->id.name);
668
669 sound = BKE_libblock_alloc(bmain, ID_SO, name);
670
671 sound->child_sound = source;
672 sound->type = SOUND_TYPE_BUFFER;
673
674 sound_load(bmain, sound);
675
676 return sound;
677}
678
679bSound *BKE_sound_new_limiter(Main *bmain, bSound *source, float start, float end)
680{
681 bSound *sound = nullptr;
682
683 char name[MAX_ID_NAME + 5];
684 BLI_string_join(name, sizeof(name), "lim_", source->id.name);
685
686 sound = BKE_libblock_alloc(bmain, ID_SO, name);
687
688 sound->child_sound = source;
689 sound->start = start;
690 sound->end = end;
691 sound->type = SOUND_TYPE_LIMITER;
692
693 sound_load(bmain, sound);
694
695 return sound;
696}
697# endif
698
699void BKE_sound_cache(bSound *sound)
700{
702
703 if (sound->cache) {
704 AUD_Sound_free(sound->cache);
705 }
706
707 sound->cache = AUD_Sound_cache(sound->handle);
708 if (sound->cache) {
709 sound->playback_handle = sound->cache;
710 }
711 else {
712 sound->playback_handle = sound->handle;
713 }
714}
715
717{
718 if (sound->cache) {
719 AUD_Sound_free(sound->cache);
720 sound->cache = nullptr;
721 sound->playback_handle = sound->handle;
722 }
723}
724
725static void sound_load_audio(Main *bmain, bSound *sound, bool free_waveform)
726{
727
728 if (sound->cache) {
729 AUD_Sound_free(sound->cache);
730 sound->cache = nullptr;
731 }
732
733 if (sound->handle) {
734 AUD_Sound_free(sound->handle);
735 sound->handle = nullptr;
736 sound->playback_handle = nullptr;
737 }
738
739 if (free_waveform) {
741 }
742
743/* XXX unused currently */
744# if 0
745 switch (sound->type) {
746 case SOUND_TYPE_FILE:
747# endif
748 {
749 char fullpath[FILE_MAX];
750
751 /* load sound */
752 PackedFile *pf = sound->packedfile;
753
754 /* Don't modify `sound->filepath`, only change a copy. */
755 STRNCPY(fullpath, sound->filepath);
756 BLI_path_abs(fullpath, ID_BLEND_PATH(bmain, &sound->id));
757
758 /* but we need a packed file then */
759 if (pf) {
760 sound->handle = AUD_Sound_bufferFile((uchar *)pf->data, pf->size);
761 }
762 else {
763 /* or else load it from disk */
764 sound->handle = AUD_Sound_file(fullpath);
765 }
766 }
767/* XXX unused currently */
768# if 0
769 break;
770 }
771 case SOUND_TYPE_BUFFER:
772 if (sound->child_sound && sound->child_sound->handle) {
773 sound->handle = AUD_bufferSound(sound->child_sound->handle);
774 }
775 break;
776 case SOUND_TYPE_LIMITER:
777 if (sound->child_sound && sound->child_sound->handle) {
778 sound->handle = AUD_limitSound(sound->child_sound, sound->start, sound->end);
779 }
780 break;
781}
782# endif
783 if (sound->flags & SOUND_FLAGS_MONO) {
784 void *handle = AUD_Sound_rechannel(sound->handle, AUD_CHANNELS_MONO);
785 AUD_Sound_free(sound->handle);
786 sound->handle = handle;
787 }
788
789 if (sound->flags & SOUND_FLAGS_CACHING) {
790 sound->cache = AUD_Sound_cache(sound->handle);
791 }
792
793 if (sound->cache) {
794 sound->playback_handle = sound->cache;
795 }
796 else {
797 sound->playback_handle = sound->handle;
798 }
799}
800
801void BKE_sound_load(Main *bmain, bSound *sound)
802{
804 sound_load_audio(bmain, sound, true);
805}
806
807AUD_Device *BKE_sound_mixdown(const Scene *scene, AUD_DeviceSpecs specs, int start, float volume)
808{
810 return AUD_openMixdownDevice(specs,
811 scene->sound_scene,
812 volume,
813 AUD_RESAMPLE_QUALITY_MEDIUM,
814 start / scene->frames_per_second());
815}
816
817void BKE_sound_create_scene(Scene *scene)
818{
820
821 /* should be done in version patch, but this gets called before */
822 if (scene->r.frs_sec_base == 0) {
823 scene->r.frs_sec_base = 1;
824 }
825
826 scene->sound_scene = AUD_Sequence_create(scene->frames_per_second(),
827 scene->audio.flag & AUDIO_MUTE);
828 AUD_Sequence_setSpeedOfSound(scene->sound_scene, scene->audio.speed_of_sound);
829 AUD_Sequence_setDopplerFactor(scene->sound_scene, scene->audio.doppler_factor);
830 AUD_Sequence_setDistanceModel(scene->sound_scene,
831 AUD_DistanceModel(scene->audio.distance_model));
832 scene->playback_handle = nullptr;
833 scene->sound_scrub_handle = nullptr;
834 scene->speaker_handles = nullptr;
835}
836
838{
839 if (scene->playback_handle) {
840 AUD_Handle_stop(scene->playback_handle);
841 }
842 if (scene->sound_scrub_handle) {
843 AUD_Handle_stop(scene->sound_scrub_handle);
844 }
845 if (scene->speaker_handles) {
846 void *handle;
847
848 while ((handle = AUD_getSet(scene->speaker_handles))) {
849 AUD_Sequence_remove(scene->sound_scene, handle);
850 }
851
853 }
854 if (scene->sound_scene) {
855 AUD_Sequence_free(scene->sound_scene);
856 }
857}
858
859void BKE_sound_lock()
860{
861 g_state.sound_device_mutex.lock();
862 if (g_state.sound_device == nullptr) {
863 return;
864 }
865 AUD_Device_lock(g_state.sound_device);
866}
867
868void BKE_sound_unlock()
869{
870 g_state.sound_device_mutex.unlock();
871 if (g_state.sound_device == nullptr) {
872 return;
873 }
874 AUD_Device_unlock(g_state.sound_device);
875}
876
878{
880
881 if (scene->sound_scene) {
882 AUD_Sequence_setSpecs(scene->sound_scene, g_state.initialized_specs.specs);
883 }
884}
885
886void BKE_sound_mute_scene(Scene *scene, int muted)
887{
889 if (scene->sound_scene) {
890 AUD_Sequence_setMuted(scene->sound_scene, muted);
891 }
892}
893
894void BKE_sound_update_fps(Main *bmain, Scene *scene)
895{
897
898 if (scene->sound_scene) {
899 AUD_Sequence_setFPS(scene->sound_scene, scene->frames_per_second());
900 }
901
903}
904
906{
908
909 AUD_Sequence_setSpeedOfSound(scene->sound_scene, scene->audio.speed_of_sound);
910 AUD_Sequence_setDopplerFactor(scene->sound_scene, scene->audio.doppler_factor);
911 AUD_Sequence_setDistanceModel(scene->sound_scene,
912 AUD_DistanceModel(scene->audio.distance_model));
913}
914
916 Scene *scene, Strip *sequence, int startframe, int endframe, int frameskip)
917{
919 if (sequence->scene && scene != sequence->scene) {
920 const double fps = scene->frames_per_second();
921 return AUD_Sequence_add(scene->sound_scene,
922 sequence->scene->sound_scene,
923 startframe / fps,
924 endframe / fps,
925 frameskip / fps);
926 }
927 return nullptr;
928}
929
931{
933 scene,
934 sequence,
937 sequence->startofs + sequence->anim_startofs);
938}
939
941 Scene *scene, Strip *sequence, int startframe, int endframe, int frameskip)
942{
944 /* Happens when sequence's sound data-block was removed. */
945 if (sequence->sound == nullptr) {
946 return nullptr;
947 }
949 const double fps = scene->frames_per_second();
950 const double offset_time = sequence->sound->offset_time + sequence->sound_offset -
951 frameskip / fps;
952 if (offset_time >= 0.0f) {
953 return AUD_Sequence_add(scene->sound_scene,
954 sequence->sound->playback_handle,
955 startframe / fps + offset_time,
956 endframe / fps,
957 0.0f);
958 }
959 return AUD_Sequence_add(scene->sound_scene,
960 sequence->sound->playback_handle,
961 startframe / fps,
962 endframe / fps,
963 -offset_time);
964}
965
966void *BKE_sound_add_scene_sound_defaults(Scene *scene, Strip *sequence)
967{
968 return BKE_sound_add_scene_sound(scene,
969 sequence,
972 sequence->startofs + sequence->anim_startofs);
973}
974
975void BKE_sound_remove_scene_sound(Scene *scene, void *handle)
976{
977 AUD_Sequence_remove(scene->sound_scene, handle);
978}
979
980void BKE_sound_mute_scene_sound(void *handle, bool mute)
981{
982 AUD_SequenceEntry_setMuted(handle, mute);
983}
984
985void BKE_sound_move_scene_sound(const Scene *scene,
986 void *handle,
987 int startframe,
988 int endframe,
989 int frameskip,
990 double audio_offset)
991{
993 const double fps = scene->frames_per_second();
994 const double offset_time = audio_offset - frameskip / fps;
995 if (offset_time >= 0.0f) {
996 AUD_SequenceEntry_move(handle, startframe / fps + offset_time, endframe / fps, 0.0f);
997 }
998 else {
999 AUD_SequenceEntry_move(handle, startframe / fps, endframe / fps, -offset_time);
1000 }
1001}
1002
1003void BKE_sound_move_scene_sound_defaults(Scene *scene, Strip *sequence)
1004{
1006 if (sequence->scene_sound) {
1007 double offset_time = 0.0f;
1008 if (sequence->sound != nullptr) {
1009 offset_time = sequence->sound->offset_time + sequence->sound_offset;
1010 }
1012 sequence->scene_sound,
1015 sequence->startofs + sequence->anim_startofs,
1016 offset_time);
1017 }
1018}
1019
1020void BKE_sound_update_scene_sound(void *handle, bSound *sound)
1021{
1022 AUD_SequenceEntry_setSound(handle, sound->playback_handle);
1023}
1024
1025#endif /* WITH_AUDASPACE */
1026
1027void BKE_sound_update_sequence_handle(void *handle, void *sound_handle)
1028{
1029#ifdef WITH_AUDASPACE
1030 AUD_SequenceEntry_setSound(handle, sound_handle);
1031#else
1032 UNUSED_VARS(handle, sound_handle);
1033#endif
1034}
1035
1036#ifdef WITH_AUDASPACE
1037
1038void BKE_sound_set_scene_volume(Scene *scene, float volume)
1039{
1041 if (scene->sound_scene == nullptr) {
1042 return;
1043 }
1044 AUD_Sequence_setAnimationData(scene->sound_scene,
1045 AUD_AP_VOLUME,
1046 scene->r.cfra,
1047 &volume,
1048 (scene->audio.flag & AUDIO_VOLUME_ANIMATED) != 0);
1049}
1050
1052 const int frame,
1053 float volume,
1054 const char animated)
1055{
1056 AUD_SequenceEntry_setAnimationData(handle, AUD_AP_VOLUME, frame, &volume, animated);
1057}
1058
1060 const int frame,
1061 float pitch,
1062 const char animated)
1063{
1064 AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PITCH, frame, &pitch, animated);
1065}
1066
1068 int frame_start,
1069 int frame_end,
1070 float pitch)
1071{
1072 frame_start = max_ii(0, frame_start);
1073 frame_end = max_ii(0, frame_end);
1074 AUD_SequenceEntry_setConstantRangeAnimationData(
1075 handle, AUD_AP_PITCH, frame_start, frame_end, &pitch);
1076}
1077
1079 const int frame,
1080 float pan,
1081 const char animated)
1082{
1083 AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PANNING, frame, &pan, animated);
1084}
1085
1087{
1088 BLI_assert_msg(0, "is not supposed to be used, is weird function.");
1089
1090 Scene *scene;
1091
1092 for (scene = static_cast<Scene *>(main->scenes.first); scene;
1093 scene = static_cast<Scene *>(scene->id.next))
1094 {
1095 blender::seq::sound_update(scene, sound);
1096 }
1097}
1098
1099/* This function assumes that you have already held the g_state.sound_device mutex. */
1100static void sound_start_play_scene(Scene *scene)
1101{
1103
1104 if (scene->playback_handle) {
1105 AUD_Handle_stop(scene->playback_handle);
1106 }
1107
1109
1110 scene->playback_handle = AUD_Device_play(g_state.sound_device, scene->sound_scene, 1);
1111 if (scene->playback_handle) {
1112 AUD_Handle_setLoopCount(scene->playback_handle, -1);
1113 }
1114}
1115
1116void BKE_sound_play_scene(Scene *scene)
1117{
1118 std::lock_guard lock(g_state.sound_device_mutex);
1119 sound_device_use_begin();
1121
1122 AUD_Status status;
1123 const double cur_time = FRA2TIME(scene->r.cfra + scene->r.subframe);
1124
1125 AUD_Device_lock(g_state.sound_device);
1126
1127 if (scene->sound_scrub_handle &&
1128 AUD_Handle_getStatus(scene->sound_scrub_handle) != AUD_STATUS_INVALID)
1129 {
1130 /* If the audio scrub handle is playing back, stop to make sure it is not active.
1131 * Otherwise, it will trigger a callback that will stop audio playback. */
1132 AUD_Handle_stop(scene->sound_scrub_handle);
1133 scene->sound_scrub_handle = nullptr;
1134 /* The scrub_handle started playback with playback_handle, stop it so we can
1135 * properly restart it. */
1136 AUD_Handle_pause(scene->playback_handle);
1137 }
1138
1139 status = scene->playback_handle ? AUD_Handle_getStatus(scene->playback_handle) :
1140 AUD_STATUS_INVALID;
1141
1142 if (status == AUD_STATUS_INVALID) {
1143 sound_start_play_scene(scene);
1144
1145 if (!scene->playback_handle) {
1146 AUD_Device_unlock(g_state.sound_device);
1147 return;
1148 }
1149 }
1150
1151 if (status != AUD_STATUS_PLAYING) {
1152 /* Seeking the synchronizer will also seek the playback handle.
1153 * Even if we don't have A/V sync on, keep the synchronizer and handle seek time in sync. */
1154 AUD_seekSynchronizer(cur_time);
1155 AUD_Handle_setPosition(scene->playback_handle, cur_time);
1156 AUD_Handle_resume(scene->playback_handle);
1157 }
1158
1159 if (scene->audio.flag & AUDIO_SYNC) {
1160 AUD_playSynchronizer();
1161 }
1162
1163 AUD_Device_unlock(g_state.sound_device);
1164}
1165
1166void BKE_sound_stop_scene(Scene *scene)
1167{
1168 std::lock_guard lock(g_state.sound_device_mutex);
1169 BLI_assert(g_state.sound_device);
1170 if (scene->playback_handle) {
1171 AUD_Handle_pause(scene->playback_handle);
1172
1173 if (scene->audio.flag & AUDIO_SYNC) {
1174 AUD_stopSynchronizer();
1175 }
1176 }
1177 sound_device_use_end();
1178}
1179
1180void BKE_sound_seek_scene(Main *bmain, Scene *scene)
1181{
1182 std::lock_guard lock(g_state.sound_device_mutex);
1183 bool animation_playing = false;
1184 for (bScreen *screen = static_cast<bScreen *>(bmain->screens.first); screen;
1185 screen = static_cast<bScreen *>(screen->id.next))
1186 {
1187 if (screen->animtimer) {
1188 animation_playing = true;
1189 break;
1190 }
1191 }
1192
1193 bool do_audio_scrub = scene->audio.flag & AUDIO_SCRUB && !animation_playing;
1194
1195 if (do_audio_scrub) {
1196 /* Make sure the sound device is open for scrubbing. */
1197 sound_device_use_begin();
1198 }
1199 else if (g_state.sound_device == nullptr) {
1200 /* Nothing to do if there is no sound device and we are not doing audio scrubbing. */
1201 return;
1202 }
1204
1205 AUD_Device_lock(g_state.sound_device);
1206
1207 AUD_Status status = scene->playback_handle ? AUD_Handle_getStatus(scene->playback_handle) :
1208 AUD_STATUS_INVALID;
1209 if (status == AUD_STATUS_INVALID) {
1210 sound_start_play_scene(scene);
1211
1212 if (!scene->playback_handle) {
1213 AUD_Device_unlock(g_state.sound_device);
1214 if (do_audio_scrub) {
1215 sound_device_use_end();
1216 }
1217 return;
1218 }
1219
1220 AUD_Handle_pause(scene->playback_handle);
1221 }
1222
1223 const double one_frame = 1.0 / scene->frames_per_second() +
1224 (U.audiorate > 0 ? U.mixbufsize / double(U.audiorate) : 0.0);
1225 const double cur_time = FRA2TIME(scene->r.cfra);
1226
1227 if (do_audio_scrub) {
1228 /* Playback one frame of audio without advancing the timeline. */
1229 AUD_Handle_setPosition(scene->playback_handle, cur_time);
1230 AUD_Handle_resume(scene->playback_handle);
1231 if (scene->sound_scrub_handle &&
1232 AUD_Handle_getStatus(scene->sound_scrub_handle) != AUD_STATUS_INVALID)
1233 {
1234 AUD_Handle_setPosition(scene->sound_scrub_handle, 0);
1235 }
1236 else {
1237 if (scene->sound_scrub_handle) {
1238 AUD_Handle_stop(scene->sound_scrub_handle);
1239 }
1240 scene->sound_scrub_handle = AUD_pauseAfter(scene->playback_handle, one_frame);
1241 }
1242 sound_device_use_end_after(std::chrono::milliseconds(int(one_frame * 1000)));
1243 }
1244 else if (status == AUD_STATUS_PLAYING) {
1245 /* Seeking the synchronizer will also seek the playback handle.
1246 * Even if we don't have A/V sync on, keep the synchronizer and handle
1247 * seek time in sync.
1248 */
1249 AUD_seekSynchronizer(cur_time);
1250 AUD_Handle_setPosition(scene->playback_handle, cur_time);
1251 }
1252
1253 AUD_Device_unlock(g_state.sound_device);
1254}
1255
1256double BKE_sound_sync_scene(Scene *scene)
1257{
1259
1260 /* Ugly: Blender doesn't like it when the animation is played back during rendering */
1261 if (G.is_rendering) {
1262 return NAN_FLT;
1263 }
1264
1265 if (scene->playback_handle) {
1266 if (scene->audio.flag & AUDIO_SYNC) {
1267 return AUD_getSynchronizerPosition();
1268 }
1269
1270 return AUD_Handle_getPosition(scene->playback_handle);
1271 }
1272 return NAN_FLT;
1273}
1274
1276{
1277 if ((sound->tags & SOUND_TAGS_WAVEFORM_NO_RELOAD) == 0) {
1278 SoundWaveform *waveform = static_cast<SoundWaveform *>(sound->waveform);
1279 if (waveform) {
1280 if (waveform->data) {
1281 MEM_freeN(waveform->data);
1282 }
1283 MEM_freeN(waveform);
1284 }
1285
1286 sound->waveform = nullptr;
1287 }
1288 /* This tag is only valid once. */
1290}
1291
1292void BKE_sound_read_waveform(Main *bmain, bSound *sound, bool *stop)
1293{
1294 bool need_close_audio_handles = false;
1295 if (sound->playback_handle == nullptr) {
1296 /* TODO(sergey): Make it fully independent audio handle. */
1297 sound_load_audio(bmain, sound, true);
1298 need_close_audio_handles = true;
1299 }
1300
1301 AUD_SoundInfo info = AUD_getInfo(sound->playback_handle);
1302 SoundWaveform *waveform = MEM_mallocN<SoundWaveform>("SoundWaveform");
1303
1304 if (info.length > 0) {
1305 int length = info.length * SOUND_WAVE_SAMPLES_PER_SECOND;
1306
1307 waveform->data = MEM_malloc_arrayN<float>(3 * size_t(length), "SoundWaveform.samples");
1308 waveform->length = AUD_readSound(
1309 sound->playback_handle, waveform->data, length, SOUND_WAVE_SAMPLES_PER_SECOND, stop);
1310 }
1311 else {
1312 /* Create an empty waveform here if the sound couldn't be
1313 * read. This indicates that reading the waveform is "done",
1314 * whereas just setting sound->waveform to nullptr causes other
1315 * code to think the waveform still needs to be created. */
1316 waveform->data = nullptr;
1317 waveform->length = 0;
1318 }
1319
1320 if (*stop) {
1321 if (waveform->data) {
1322 MEM_freeN(waveform->data);
1323 }
1324 MEM_freeN(waveform);
1325 BLI_spin_lock(static_cast<SpinLock *>(sound->spinlock));
1327 BLI_spin_unlock(static_cast<SpinLock *>(sound->spinlock));
1328 return;
1329 }
1330
1332
1333 BLI_spin_lock(static_cast<SpinLock *>(sound->spinlock));
1334 sound->waveform = waveform;
1336 BLI_spin_unlock(static_cast<SpinLock *>(sound->spinlock));
1337
1338 if (need_close_audio_handles) {
1339 sound_free_audio(sound);
1340 }
1341}
1342
1343static void sound_update_base(Scene *scene, Object *object, void *new_set)
1344{
1345 Speaker *speaker;
1346 float quat[4];
1347
1349 sound_verify_evaluated_id(&object->id);
1350
1351 if ((object->type != OB_SPEAKER) || !object->adt) {
1352 return;
1353 }
1354
1355 LISTBASE_FOREACH (NlaTrack *, track, &object->adt->nla_tracks) {
1356 LISTBASE_FOREACH (NlaStrip *, strip, &track->strips) {
1357 if (strip->type != NLASTRIP_TYPE_SOUND) {
1358 continue;
1359 }
1360 speaker = (Speaker *)object->data;
1361
1362 if (AUD_removeSet(scene->speaker_handles, strip->speaker_handle)) {
1363 if (speaker->sound) {
1364 AUD_SequenceEntry_move(strip->speaker_handle,
1365 double(strip->start) / scene->frames_per_second(),
1366 FLT_MAX,
1367 0);
1368 }
1369 else {
1370 AUD_Sequence_remove(scene->sound_scene, strip->speaker_handle);
1371 strip->speaker_handle = nullptr;
1372 }
1373 }
1374 else {
1375 if (speaker->sound) {
1376 strip->speaker_handle = AUD_Sequence_add(scene->sound_scene,
1377 speaker->sound->playback_handle,
1378 double(strip->start) /
1379 scene->frames_per_second(),
1380 FLT_MAX,
1381 0);
1382 AUD_SequenceEntry_setRelative(strip->speaker_handle, 0);
1383 }
1384 }
1385
1386 if (strip->speaker_handle) {
1387 const bool mute = ((strip->flag & NLASTRIP_FLAG_MUTED) || (speaker->flag & SPK_MUTED));
1388 AUD_addSet(new_set, strip->speaker_handle);
1389 AUD_SequenceEntry_setVolumeMaximum(strip->speaker_handle, speaker->volume_max);
1390 AUD_SequenceEntry_setVolumeMinimum(strip->speaker_handle, speaker->volume_min);
1391 AUD_SequenceEntry_setDistanceMaximum(strip->speaker_handle, speaker->distance_max);
1392 AUD_SequenceEntry_setDistanceReference(strip->speaker_handle, speaker->distance_reference);
1393 AUD_SequenceEntry_setAttenuation(strip->speaker_handle, speaker->attenuation);
1394 AUD_SequenceEntry_setConeAngleOuter(strip->speaker_handle, speaker->cone_angle_outer);
1395 AUD_SequenceEntry_setConeAngleInner(strip->speaker_handle, speaker->cone_angle_inner);
1396 AUD_SequenceEntry_setConeVolumeOuter(strip->speaker_handle, speaker->cone_volume_outer);
1397
1398 mat4_to_quat(quat, object->object_to_world().ptr());
1399 blender::float3 location = object->object_to_world().location();
1400 AUD_SequenceEntry_setAnimationData(
1401 strip->speaker_handle, AUD_AP_LOCATION, scene->r.cfra, location, 1);
1402 AUD_SequenceEntry_setAnimationData(
1403 strip->speaker_handle, AUD_AP_ORIENTATION, scene->r.cfra, quat, 1);
1404 AUD_SequenceEntry_setAnimationData(
1405 strip->speaker_handle, AUD_AP_VOLUME, scene->r.cfra, &speaker->volume, 1);
1406 AUD_SequenceEntry_setAnimationData(
1407 strip->speaker_handle, AUD_AP_PITCH, scene->r.cfra, &speaker->pitch, 1);
1408 AUD_SequenceEntry_setSound(strip->speaker_handle, speaker->sound->playback_handle);
1409 AUD_SequenceEntry_setMuted(strip->speaker_handle, mute);
1410 }
1411 }
1412 }
1413}
1414
1415void BKE_sound_update_scene(Depsgraph *depsgraph, Scene *scene)
1416{
1418
1419 void *new_set = AUD_createSet();
1420 void *handle;
1421 float quat[4];
1422
1423 /* cheap test to skip looping over all objects (no speakers is a common case) */
1425 DEGObjectIterSettings deg_iter_settings = {nullptr};
1426 deg_iter_settings.depsgraph = depsgraph;
1427 deg_iter_settings.flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
1430 DEG_OBJECT_ITER_BEGIN (&deg_iter_settings, object) {
1431 sound_update_base(scene, object, new_set);
1432 }
1434 }
1435
1436 while ((handle = AUD_getSet(scene->speaker_handles))) {
1437 AUD_Sequence_remove(scene->sound_scene, handle);
1438 }
1439
1440 if (scene->camera) {
1441 mat4_to_quat(quat, scene->camera->object_to_world().ptr());
1442 blender::float3 location = scene->camera->object_to_world().location();
1443 AUD_Sequence_setAnimationData(scene->sound_scene, AUD_AP_LOCATION, scene->r.cfra, location, 1);
1444 AUD_Sequence_setAnimationData(scene->sound_scene, AUD_AP_ORIENTATION, scene->r.cfra, quat, 1);
1445 }
1446
1448 scene->speaker_handles = new_set;
1449}
1450
1451void *BKE_sound_get_factory(void *sound)
1452{
1453 return ((bSound *)sound)->playback_handle;
1454}
1455
1456float BKE_sound_get_length(Main *bmain, bSound *sound)
1457{
1458 if (sound->playback_handle != nullptr) {
1459 AUD_SoundInfo info = AUD_getInfo(sound->playback_handle);
1460 return info.length;
1461 }
1462 SoundInfo info;
1463 if (!BKE_sound_info_get(bmain, sound, &info)) {
1464 return 0.0f;
1465 }
1466 return info.length;
1467}
1468
1470{
1471 if (audio_device_names == nullptr) {
1472 audio_device_names = AUD_getDeviceNames();
1473 }
1474
1475 return audio_device_names;
1476}
1477
1478static bool sound_info_from_playback_handle(void *playback_handle, SoundInfo *sound_info)
1479{
1480 if (playback_handle == nullptr) {
1481 return false;
1482 }
1483 AUD_SoundInfo info = AUD_getInfo(playback_handle);
1484 sound_info->specs.channels = (eSoundChannels)info.specs.channels;
1485 sound_info->length = info.length;
1486 sound_info->specs.samplerate = info.specs.rate;
1487 return true;
1488}
1489
1490bool BKE_sound_info_get(Main *main, bSound *sound, SoundInfo *sound_info)
1491{
1492 if (sound->playback_handle != nullptr) {
1493 return sound_info_from_playback_handle(sound->playback_handle, sound_info);
1494 }
1495 /* TODO(sergey): Make it fully independent audio handle. */
1496 /* Don't free waveforms during non-destructive queries.
1497 * This causes unnecessary recalculation - see #69921 */
1498 sound_load_audio(main, sound, false);
1499 const bool result = sound_info_from_playback_handle(sound->playback_handle, sound_info);
1500 sound_free_audio(sound);
1501 return result;
1502}
1503
1505 const char *filepath,
1506 int stream,
1507 SoundStreamInfo *sound_info)
1508{
1509 const char *blendfile_path = BKE_main_blendfile_path(main);
1510 char filepath_abs[FILE_MAX];
1511 AUD_Sound *sound;
1512 AUD_StreamInfo *stream_infos;
1513 int stream_count;
1514
1515 STRNCPY(filepath_abs, filepath);
1516 BLI_path_abs(filepath_abs, blendfile_path);
1517
1518 sound = AUD_Sound_file(filepath_abs);
1519 if (!sound) {
1520 return false;
1521 }
1522
1523 stream_count = AUD_Sound_getFileStreams(sound, &stream_infos);
1524
1525 AUD_Sound_free(sound);
1526
1527 if (!stream_infos) {
1528 return false;
1529 }
1530
1531 if ((stream < 0) || (stream >= stream_count)) {
1532 free(stream_infos);
1533 return false;
1534 }
1535
1536 sound_info->start = stream_infos[stream].start;
1537 sound_info->duration = stream_infos[stream].duration;
1538
1539 free(stream_infos);
1540
1541 return true;
1542}
1543
1544# ifdef WITH_RUBBERBAND
1545void *BKE_sound_ensure_time_stretch_effect(void *sound_handle, void *sequence_handle, float fps)
1546{
1547 /* If sequence handle is already the time stretch effect with the same framerate, use that. */
1548 AUD_Sound *cur_seq_sound = sequence_handle ? AUD_SequenceEntry_getSound(sequence_handle) :
1549 nullptr;
1550 if (AUD_Sound_isAnimateableTimeStretchPitchScale(cur_seq_sound) &&
1551 AUD_Sound_animateableTimeStretchPitchScale_getFPS(cur_seq_sound) == fps)
1552 {
1553 return cur_seq_sound;
1554 }
1555
1556 /* Otherwise create the time stretch effect. */
1557 return AUD_Sound_animateableTimeStretchPitchScale(
1558 sound_handle, fps, 1.0, 1.0, AUD_STRETCHER_QUALITY_HIGH, false);
1559}
1561 int frame,
1562 float time_stretch,
1563 char animated)
1564{
1565 AUD_Sound_animateableTimeStretchPitchScale_setAnimationData(
1566 handle, AUD_AP_TIME_STRETCH, frame, &time_stretch, animated);
1567}
1569 int frame_start,
1570 int frame_end,
1571 float time_stretch)
1572{
1573 frame_start = max_ii(0, frame_start);
1574 frame_end = max_ii(0, frame_end);
1575 AUD_Sound_animateableTimeStretchPitchScale_setConstantRangeAnimationData(
1576 handle, AUD_AP_TIME_STRETCH, frame_start, frame_end, &time_stretch);
1577}
1578# endif /* WITH_RUBBERBAND */
1579
1580#else /* WITH_AUDASPACE */
1581
1582# include "BLI_utildefines.h"
1583
1584void BKE_sound_force_device(const char * /*device*/) {}
1586void BKE_sound_init(Main * /*bmain*/) {}
1589void BKE_sound_cache(bSound * /*sound*/) {}
1590void BKE_sound_delete_cache(bSound * /*sound*/) {}
1591void BKE_sound_load(Main * /*bmain*/, bSound * /*sound*/) {}
1592void BKE_sound_create_scene(Scene * /*scene*/) {}
1593void BKE_sound_destroy_scene(Scene * /*scene*/) {}
1598void BKE_sound_mute_scene(Scene * /*scene*/, int /*muted*/) {}
1600 Strip * /*sequence*/,
1601 int /*startframe*/,
1602 int /*endframe*/,
1603 int /*frameskip*/)
1604{
1605 return nullptr;
1606}
1607void *BKE_sound_scene_add_scene_sound_defaults(Scene * /*scene*/, Strip * /*sequence*/)
1608{
1609 return nullptr;
1610}
1612 Strip * /*sequence*/,
1613 int /*startframe*/,
1614 int /*endframe*/,
1615 int /*frameskip*/)
1616{
1617 return nullptr;
1618}
1619void *BKE_sound_add_scene_sound_defaults(Scene * /*scene*/, Strip * /*sequence*/)
1620{
1621 return nullptr;
1622}
1623void BKE_sound_remove_scene_sound(Scene * /*scene*/, void * /*handle*/) {}
1624void BKE_sound_mute_scene_sound(void * /*handle*/, bool /*mute*/) {}
1625void BKE_sound_move_scene_sound(const Scene * /*scene*/,
1626 void * /*handle*/,
1627 int /*startframe*/,
1628 int /*endframe*/,
1629 int /*frameskip*/,
1630 double /*audio_offset*/)
1631{
1632}
1633void BKE_sound_move_scene_sound_defaults(Scene * /*scene*/, Strip * /*sequence*/) {}
1634void BKE_sound_play_scene(Scene * /*scene*/) {}
1635void BKE_sound_stop_scene(Scene * /*scene*/) {}
1636void BKE_sound_seek_scene(Main * /*bmain*/, Scene * /*scene*/) {}
1637double BKE_sound_sync_scene(Scene * /*scene*/)
1638{
1639 return NAN_FLT;
1640}
1642 bSound *sound,
1643 /* NOLINTNEXTLINE: readability-non-const-parameter. */
1644 bool *stop)
1645{
1646 UNUSED_VARS(sound, stop, bmain);
1647}
1648
1649void BKE_sound_update_sequencer(Main * /*main*/, bSound * /*sound*/) {}
1650void BKE_sound_update_scene(Depsgraph * /*depsgraph*/, Scene * /*scene*/) {}
1651void BKE_sound_update_scene_sound(void * /*handle*/, bSound * /*sound*/) {}
1653void BKE_sound_update_fps(Main * /*bmain*/, Scene * /*scene*/) {}
1655 int /*frame*/,
1656 float /*volume*/,
1657 char /*animated*/)
1658{
1659}
1661 int /*frame*/,
1662 float /*pan*/,
1663 char /*animated*/)
1664{
1665}
1666void BKE_sound_set_scene_volume(Scene * /*scene*/, float /*volume*/) {}
1668 int /*frame*/,
1669 float /*pitch*/,
1670 char /*animated*/)
1671{
1672}
1674 int /*frame_start*/,
1675 int /*frame_end*/,
1676 float /*pitch*/)
1677{
1678}
1679float BKE_sound_get_length(Main * /*bmain*/, bSound * /*sound*/)
1680{
1681 return 0;
1682}
1684{
1685 static char *names[1] = {nullptr};
1686 return names;
1687}
1688
1690
1691bool BKE_sound_info_get(Main * /*main*/, bSound * /*sound*/, SoundInfo * /*sound_info*/)
1692{
1693 return false;
1694}
1695
1697 const char * /*filepath*/,
1698 int /*stream*/,
1699 SoundStreamInfo * /*sound_info*/)
1700{
1701 return false;
1702}
1703
1704#endif /* WITH_AUDASPACE */
1705
1706#if !defined(WITH_AUDASPACE) || !defined(WITH_RUBBERBAND)
1707void *BKE_sound_ensure_time_stretch_effect(void * /*sound_handle*/,
1708 void * /*sequence_handle*/,
1709 float /*fps*/)
1710{
1711 return nullptr;
1712}
1713
1715 int /*frame*/,
1716 float /*time_stretch*/,
1717 char /*animated*/)
1718{
1719}
1721 int /*frame_start*/,
1722 int /*frame_end*/,
1723 float /*time_stretch*/)
1724{
1725}
1726#endif
1727
1729{
1730 scene->sound_scene = nullptr;
1731 scene->playback_handle = nullptr;
1732 scene->sound_scrub_handle = nullptr;
1733 scene->speaker_handles = nullptr;
1734}
1735
1737{
1738 if (scene->sound_scene != nullptr) {
1739 return;
1740 }
1742}
1743
1745{
1746 sound->cache = nullptr;
1747 sound->playback_handle = nullptr;
1748}
1749
1751{
1752 if (sound->cache != nullptr) {
1753 return;
1754 }
1755 BKE_sound_load(bmain, sound);
1756}
1757
1759{
1760#if defined(WITH_AUDASPACE)
1761 sound_jack_sync_callback = callback;
1762#else
1763 UNUSED_VARS(callback);
1764#endif
1765}
1766
1767void BKE_sound_jack_scene_update(Scene *scene, int mode, double time)
1768{
1770
1771 /* Ugly: Blender doesn't like it when the animation is played back during rendering. */
1772 if (G.is_rendering) {
1773 return;
1774 }
1775#ifdef WITH_AUDASPACE
1776 AUD_Device_lock(g_state.sound_device);
1777
1778 if (mode) {
1779 BKE_sound_play_scene(scene);
1780 }
1781 else {
1782 BKE_sound_stop_scene(scene);
1783 }
1784 if (scene->playback_handle != nullptr) {
1785 AUD_Handle_setPosition(scene->playback_handle, time);
1786 }
1787 AUD_Device_unlock(g_state.sound_device);
1788#else
1789 UNUSED_VARS(mode, time);
1790#endif
1791}
1792
1793void BKE_sound_evaluate(Depsgraph *depsgraph, Main *bmain, bSound *sound)
1794{
1795 DEG_debug_print_eval(depsgraph, __func__, sound->id.name, sound);
1796 if (sound->id.recalc & ID_RECALC_SOURCE) {
1797 /* Sequencer checks this flag to see if the strip sound is to be updated from the Audaspace
1798 * side. */
1799 sound->id.recalc |= ID_RECALC_AUDIO;
1800 }
1801
1802 if (sound->id.recalc & ID_RECALC_AUDIO) {
1803 BKE_sound_load(bmain, sound);
1804 return;
1805 }
1806 BKE_sound_ensure_loaded(bmain, sound);
1807}
void * AUD_createSet()
Definition AUD_Set.cpp:13
void * AUD_getSet(void *set)
Definition AUD_Set.cpp:38
void AUD_addSet(void *set, void *entry)
Definition AUD_Set.cpp:31
void AUD_destroySet(void *set)
Definition AUD_Set.cpp:18
char AUD_removeSet(void *set, void *entry)
Definition AUD_Set.cpp:23
bool BKE_bpath_foreach_path_fixed_process(BPathForeachPathData *bpath_data, char *path, size_t path_maxncpy)
Definition bpath.cc:125
@ BKE_BPATH_FOREACH_PATH_SKIP_PACKED
Definition BKE_bpath.hh:42
void(*)(ID *id, const IDCacheKey *cache_key, void **cache_p, uint flags, void *user_data) IDTypeForeachCacheFunctionCallback
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
Definition BKE_idtype.hh:47
@ IDTYPE_FLAGS_NO_ANIMDATA
Definition BKE_idtype.hh:49
IDTypeInfo IDType_ID_SO
void * BKE_libblock_alloc(Main *bmain, short type, const char *name, int flag) ATTR_WARN_UNUSED_RESULT
Definition lib_id.cc:1447
void id_us_plus(ID *id)
Definition lib_id.cc:358
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2631
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:887
PackedFile * BKE_packedfile_duplicate(const PackedFile *pf_src)
void BKE_packedfile_free(PackedFile *pf)
void BKE_packedfile_blend_write(BlendWriter *writer, const PackedFile *pf)
void BKE_packedfile_blend_read(BlendDataReader *reader, PackedFile **pf_p, blender::StringRefNull filepath)
void * BKE_sound_get_factory(void *sound)
#define SOUND_WAVE_SAMPLES_PER_SECOND
Definition BKE_sound.h:10
void(* SoundJackSyncCallback)(struct Main *bmain, int mode, double time)
Definition BKE_sound.h:207
eSoundChannels
Definition BKE_sound.h:62
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define BLI_INLINE
void BLI_kdtree_nd_ free(KDTree *tree)
#define LISTBASE_FOREACH(type, var, list)
MINLINE int max_ii(int a, int b)
#define NAN_FLT
void mat4_to_quat(float q[4], const float mat[4][4])
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
void void void const char * BLI_path_basename(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define FILE_MAX
#define BLI_path_cmp
#define STR_ELEM(...)
Definition BLI_string.h:661
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
#define BLI_string_join(...)
unsigned char uchar
pthread_spinlock_t SpinLock
void BLI_spin_init(SpinLock *spin)
Definition threads.cc:391
void BLI_spin_unlock(SpinLock *spin)
Definition threads.cc:430
void BLI_spin_lock(SpinLock *spin)
Definition threads.cc:405
void BLI_spin_end(SpinLock *spin)
Definition threads.cc:445
#define UNUSED_VARS(...)
#define UNUSED_VARS_NDEBUG(...)
#define STREQ(a, b)
bool BLO_read_data_is_undo(BlendDataReader *reader)
Definition readfile.cc:5963
#define BLO_write_id_struct(writer, struct_name, id_address, id)
bool BLO_write_is_undo(BlendWriter *writer)
#define BLT_I18NCONTEXT_ID_SOUND
#define CLOG_DEBUG(clg_ref,...)
Definition CLG_log.h:191
void DEG_debug_print_eval(Depsgraph *depsgraph, const char *function_name, const char *object_name, const void *object_address)
#define DEG_OBJECT_ITER_BEGIN(settings_, instance_)
#define DEG_OBJECT_ITER_END
bool DEG_id_type_any_exists(const Depsgraph *depsgraph, short id_type)
@ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY
@ DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY
@ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET
@ ID_TAG_COPIED_ON_EVAL
Definition DNA_ID.h:997
@ ID_TAG_COPIED_ON_EVAL_FINAL_RESULT
Definition DNA_ID.h:1007
@ ID_TAG_NO_MAIN
Definition DNA_ID.h:978
@ ID_RECALC_AUDIO
Definition DNA_ID.h:1132
@ ID_RECALC_SOURCE
Definition DNA_ID.h:1143
#define FILTER_ID_SO
Definition DNA_ID.h:1219
#define MAX_ID_NAME
Definition DNA_ID.h:373
#define ID_BLEND_PATH(_bmain, _id)
Definition DNA_ID.h:685
@ INDEX_ID_SO
Definition DNA_ID.h:1302
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:730
@ ID_SO
@ ID_SPK
@ NLASTRIP_FLAG_MUTED
@ NLASTRIP_TYPE_SOUND
Object is a sort of wrapper for general info.
@ OB_SPEAKER
@ AUDIO_MUTE
@ AUDIO_VOLUME_ANIMATED
@ AUDIO_SCRUB
@ AUDIO_SYNC
#define FRA2TIME(a)
@ SOUND_FLAGS_MONO
@ SOUND_FLAGS_CACHING
@ SOUND_TAGS_WAVEFORM_LOADING
@ SOUND_TAGS_WAVEFORM_NO_RELOAD
@ SPK_MUTED
Read Guarded memory(de)allocation.
volatile int lock
#define U
void BKE_sound_jack_sync_callback_set(SoundJackSyncCallback callback)
void BKE_sound_refresh_callback_bmain(Main *)
void BKE_sound_ensure_scene(Scene *scene)
BLI_INLINE void sound_verify_evaluated_id(const ID *id)
void BKE_sound_exit()
double BKE_sound_sync_scene(Scene *)
void * BKE_sound_add_scene_sound_defaults(Scene *, Strip *)
void BKE_sound_destroy_scene(Scene *)
char ** BKE_sound_get_device_names()
void BKE_sound_init(Main *)
static void sound_free_audio(bSound *sound)
void BKE_sound_lock()
void BKE_sound_load(Main *, bSound *)
void BKE_sound_update_sequencer(Main *, bSound *)
static void sound_free_data(ID *id)
void BKE_sound_set_scene_sound_time_stretch_at_frame(void *, int, float, char)
static void sound_blend_read_data(BlendDataReader *reader, ID *id)
void BKE_sound_mute_scene_sound(void *, bool)
void BKE_sound_seek_scene(Main *, Scene *)
void BKE_sound_set_scene_sound_time_stretch_constant_range(void *, int, int, float)
void BKE_sound_play_scene(Scene *)
void * BKE_sound_ensure_time_stretch_effect(void *, void *, float)
void BKE_sound_force_device(const char *)
void BKE_sound_jack_scene_update(Scene *scene, int mode, double time)
void BKE_sound_update_scene(Depsgraph *, Scene *)
bSound * BKE_sound_new_file_exists_ex(Main *bmain, const char *filepath, bool *r_exists)
static void sound_blend_write(BlendWriter *writer, ID *id, const void *id_address)
void BKE_sound_mute_scene(Scene *, int)
void BKE_sound_exit_once()
bSound * BKE_sound_new_file(Main *bmain, const char *filepath)
void BKE_sound_update_fps(Main *, Scene *)
void BKE_sound_delete_cache(bSound *)
static void sound_foreach_path(ID *id, BPathForeachPathData *bpath_data)
void BKE_sound_move_scene_sound_defaults(Scene *, Strip *)
void * BKE_sound_scene_add_scene_sound_defaults(Scene *, Strip *)
void BKE_sound_remove_scene_sound(Scene *, void *)
void BKE_sound_reset_runtime(bSound *sound)
bool BKE_sound_stream_info_get(Main *, const char *, int, SoundStreamInfo *)
float BKE_sound_get_length(Main *, bSound *)
void * BKE_sound_scene_add_scene_sound(Scene *, Strip *, int, int, int)
bool BKE_sound_info_get(Main *, bSound *, SoundInfo *)
void BKE_sound_set_scene_sound_pan_at_frame(void *, int, float, char)
static void sound_copy_data(Main *, std::optional< Library * >, ID *id_dst, const ID *id_src, const int)
void BKE_sound_init_once()
void * BKE_sound_add_scene_sound(Scene *, Strip *, int, int, int)
void BKE_sound_set_scene_sound_pitch_at_frame(void *, int, float, char)
void BKE_sound_create_scene(Scene *)
void BKE_sound_update_scene_sound(void *, bSound *)
void BKE_sound_free_waveform(bSound *)
void BKE_sound_set_scene_sound_pitch_constant_range(void *, int, int, float)
static void sound_foreach_cache(ID *id, IDTypeForeachCacheFunctionCallback function_callback, void *user_data)
void BKE_sound_set_scene_volume(Scene *, float)
bSound * BKE_sound_new_file_exists(Main *bmain, const char *filepath)
void BKE_sound_reset_scene_runtime(Scene *scene)
void BKE_sound_update_sequence_handle(void *handle, void *sound_handle)
void BKE_sound_stop_scene(Scene *)
void BKE_sound_reset_scene_specs(Scene *)
void BKE_sound_evaluate(Depsgraph *depsgraph, Main *bmain, bSound *sound)
void BKE_sound_move_scene_sound(const Scene *, void *, int, int, int, double)
void BKE_sound_read_waveform(Main *bmain, bSound *sound, bool *stop)
void BKE_sound_unlock()
void BKE_sound_cache(bSound *)
void BKE_sound_update_scene_listener(Scene *)
void BKE_sound_ensure_loaded(Main *bmain, bSound *sound)
void BKE_sound_set_scene_sound_volume_at_frame(void *, int, float, char)
BMesh const char void * data
BPy_StructRNA * depsgraph
#define offsetof(t, d)
#define pf(_x, _i)
Prefetch 64.
Definition gim_memory.h:48
static GPUSelectNextState g_state
#define main()
float length(VecOp< float, D >) RET
#define LOG(level)
Definition log.h:97
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define G(x, y, z)
int time_right_handle_frame_get(const Scene *scene, const Strip *strip)
void sound_update_length(Main *bmain, Scene *scene)
int time_left_handle_frame_get(const Scene *, const Strip *strip)
void sound_update(Scene *scene, bSound *sound)
VecBase< float, 3 > float3
const char * name
const int status
#define FLT_MAX
Definition stdcycles.h:14
ListBase nla_tracks
float doppler_factor
float speed_of_sound
eBPathForeachFlag flag
Definition BKE_bpath.hh:102
unsigned int id_session_uid
Definition BKE_idtype.hh:77
size_t identifier
Definition BKE_idtype.hh:82
Definition DNA_ID.h:414
unsigned int recalc
Definition DNA_ID.h:445
int tag
Definition DNA_ID.h:442
char name[258]
Definition DNA_ID.h:432
void * next
Definition DNA_ID.h:417
void * first
ListBase sounds
Definition BKE_main.hh:297
ListBase screens
Definition BKE_main.hh:292
ListBase strips
struct AnimData * adt
void * sound_scrub_handle
void * sound_scene
struct RenderData r
void * speaker_handles
struct Object * camera
struct AudioData audio
void * playback_handle
int samplerate
Definition BKE_sound.h:77
eSoundChannels channels
Definition BKE_sound.h:76
float length
Definition BKE_sound.h:79
struct SoundInfo::@351331251115247062377132230300211145252373324171 specs
double duration
Definition BKE_sound.h:83
float * data
Definition BKE_sound.h:24
float cone_angle_outer
float distance_reference
float cone_volume_outer
float distance_max
float attenuation
struct bSound * sound
float cone_angle_inner
void * scene_sound
struct Scene * scene
struct bSound * sound
float sound_offset
void * playback_handle
struct PackedFile * packedfile
struct PackedFile * newpackedfile
char filepath[1024]
void * handle
void * cache
void * spinlock
void * waveform
int audio_channels
short flags
double offset_time
i
Definition text_draw.cc:230
#define N_(msgid)
static void sound_jack_sync_callback(Main *bmain, int mode, double time)