10#include <condition_variable>
30#define DNA_DEPRECATED_ALLOW
44# include <AUD_Handle.h>
45# include <AUD_Sequence.h>
46# include <AUD_Sound.h>
47# include <AUD_Special.h>
73 std::optional<Library *> ,
81 sound_dst->
handle =
nullptr;
82 sound_dst->
cache =
nullptr;
89 sound_dst->
ipo =
nullptr;
140 function_callback(
id, &key, &sound->
waveform, 0, user_data);
188 sound->
cache =
nullptr;
238static char **audio_device_names =
nullptr;
270 STRNCPY(filepath_abs, filepath);
298 STRNCPY(filepath_abs, filepath);
332 AUD_Sound_free(sound->
handle);
338 AUD_Sound_free(sound->
cache);
339 sound->
cache =
nullptr;
352 const char *force_device =
nullptr;
355 const char *device_name =
nullptr;
356 AUD_DeviceSpecs initialized_specs;
359 AUD_Device *sound_device =
nullptr;
361 std::mutex sound_device_mutex;
363 bool need_exit =
false;
364 bool use_delayed_close =
true;
365 std::thread delayed_close_thread;
366 std::condition_variable delayed_close_cv;
368 int num_device_users = 0;
369 std::chrono::time_point<std::chrono::steady_clock> last_user_disconnect_time_point;
375static void sound_device_close_no_lock()
379 AUD_exit(
g_state.sound_device);
380 g_state.sound_device =
nullptr;
384static void sound_device_open_no_lock(AUD_DeviceSpecs requested_specs)
390 g_state.sound_device = AUD_init(
391 g_state.device_name, requested_specs,
g_state.buffer_size,
"Blender");
393 g_state.sound_device = AUD_init(
"None", requested_specs,
g_state.buffer_size,
"Blender");
396 g_state.initialized_specs.channels = AUD_Device_getChannels(
g_state.sound_device);
397 g_state.initialized_specs.rate = AUD_Device_getRate(
g_state.sound_device);
398 g_state.initialized_specs.format = AUD_Device_getFormat(
g_state.sound_device);
401static void sound_device_use_begin()
409 sound_device_open_no_lock(
g_state.initialized_specs);
412static void sound_device_use_end_after(
const std::chrono::milliseconds after_ms)
415 if (
g_state.num_device_users == 0) {
420 if (
g_state.num_device_users == 0) {
421 g_state.last_user_disconnect_time_point = std::chrono::steady_clock::now() + after_ms;
422 g_state.delayed_close_cv.notify_one();
426static void sound_device_use_end()
428 sound_device_use_end_after(std::chrono::milliseconds(0));
434static bool sound_use_close_thread()
439 if (__builtin_available(macOS 15.2, *)) {
448static void delayed_close_thread_run()
450 constexpr std::chrono::milliseconds device_close_delay{30000};
455 if (!
g_state.use_delayed_close) {
463 if (
g_state.num_device_users == 0) {
464 if (
g_state.sound_device ==
nullptr) {
469 g_state.delayed_close_cv.wait_until(
470 lock,
g_state.last_user_disconnect_time_point + device_close_delay);
486 if (!
g_state.use_delayed_close) {
493 CLOG_INFO(&
LOG, 3,
"Device is not open, nothing to do");
497 CLOG_INFO(&
LOG, 3,
"Checking last device usage and timestamp");
499 if (
g_state.num_device_users) {
504 const std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
505 if ((now -
g_state.last_user_disconnect_time_point) >= device_close_delay) {
506 sound_device_close_no_lock();
510 CLOG_INFO(&
LOG, 3,
"Delayed device close thread finished");
515static void sound_sync_callback(
void *
data,
int mode,
float time)
532 if (sound_use_close_thread()) {
533 CLOG_INFO(&
LOG, 2,
"Using delayed device close thread");
534 g_state.delayed_close_thread = std::thread(delayed_close_thread_run);
541 sound_device_close_no_lock();
551 if (
g_state.delayed_close_thread.joinable()) {
552 g_state.delayed_close_cv.notify_one();
553 g_state.delayed_close_thread.join();
557 sound_device_close_no_lock();
560 if (audio_device_names !=
nullptr) {
562 for (
i = 0; audio_device_names[
i];
i++) {
563 free(audio_device_names[
i]);
565 free(audio_device_names);
566 audio_device_names =
nullptr;
574 sound_device_close_no_lock();
576 AUD_DeviceSpecs requested_specs;
577 requested_specs.channels = AUD_Channels(
U.audiochannels);
578 requested_specs.format = AUD_SampleFormat(
U.audioformat);
579 requested_specs.rate =
U.audiorate;
581 if (
g_state.force_device ==
nullptr) {
583 g_state.device_name = names[0];
586 for (
int i = 0; names[
i];
i++) {
587 if (
i ==
U.audiodevice) {
596 g_state.buffer_size =
U.mixbufsize < 128 ? 1024 :
U.mixbufsize;
598 if (requested_specs.rate < AUD_RATE_8000) {
599 requested_specs.rate = AUD_RATE_48000;
602 if (requested_specs.format <= AUD_FORMAT_INVALID) {
603 requested_specs.format = AUD_FORMAT_S16;
606 if (requested_specs.channels <= AUD_CHANNELS_INVALID) {
607 requested_specs.channels = AUD_CHANNELS_STEREO;
611 sound_device_open_no_lock(requested_specs);
625 g_state.use_delayed_close =
false;
626 AUD_setSynchronizerCallback(sound_sync_callback, bmain);
629 g_state.use_delayed_close =
true;
630 sound_device_close_no_lock();
638 AUD_setSynchronizerCallback(sound_sync_callback, bmain);
653 sound->child_sound = source;
654 sound->type = SOUND_TYPE_BUFFER;
656 sound_load(bmain, sound);
661bSound *BKE_sound_new_limiter(
Main *bmain,
bSound *source,
float start,
float end)
670 sound->child_sound = source;
671 sound->start = start;
673 sound->type = SOUND_TYPE_LIMITER;
675 sound_load(bmain, sound);
686 AUD_Sound_free(sound->
cache);
701 AUD_Sound_free(sound->
cache);
702 sound->
cache =
nullptr;
707static void sound_load_audio(
Main *bmain,
bSound *sound,
bool free_waveform)
711 AUD_Sound_free(sound->
cache);
712 sound->
cache =
nullptr;
716 AUD_Sound_free(sound->
handle);
727 switch (sound->type) {
728 case SOUND_TYPE_FILE:
746 sound->
handle = AUD_Sound_file(fullpath);
753 case SOUND_TYPE_BUFFER:
754 if (sound->child_sound && sound->child_sound->
handle) {
755 sound->
handle = AUD_bufferSound(sound->child_sound->
handle);
758 case SOUND_TYPE_LIMITER:
759 if (sound->child_sound && sound->child_sound->
handle) {
760 sound->
handle = AUD_limitSound(sound->child_sound, sound->start, sound->end);
766 void *handle = AUD_Sound_rechannel(sound->
handle, AUD_CHANNELS_MONO);
767 AUD_Sound_free(sound->
handle);
786 sound_load_audio(bmain, sound,
true);
789AUD_Device *BKE_sound_mixdown(
const Scene *scene, AUD_DeviceSpecs specs,
int start,
float volume)
792 return AUD_openMixdownDevice(
793 specs, scene->
sound_scene, volume, AUD_RESAMPLE_QUALITY_MEDIUM, start /
FPS);
839 g_state.sound_device_mutex.lock();
840 if (
g_state.sound_device ==
nullptr) {
843 AUD_Device_lock(
g_state.sound_device);
848 g_state.sound_device_mutex.unlock();
849 if (
g_state.sound_device ==
nullptr) {
852 AUD_Device_unlock(
g_state.sound_device);
894 Scene *scene,
Strip *sequence,
int startframe,
int endframe,
int frameskip)
897 if (sequence->
scene && scene != sequence->
scene) {
898 const double fps =
FPS;
919 Scene *scene,
Strip *sequence,
int startframe,
int endframe,
int frameskip)
923 if (sequence->
sound ==
nullptr) {
927 const double fps =
FPS;
930 if (offset_time >= 0.0f) {
933 startframe / fps + offset_time,
960 AUD_SequenceEntry_setMuted(handle, mute);
971 const double fps =
FPS;
972 const double offset_time = audio_offset - frameskip / fps;
973 if (offset_time >= 0.0f) {
974 AUD_SequenceEntry_move(handle, startframe / fps + offset_time, endframe / fps, 0.0f);
977 AUD_SequenceEntry_move(handle, startframe / fps, endframe / fps, -offset_time);
985 double offset_time = 0.0f;
986 if (sequence->
sound !=
nullptr) {
1007#ifdef WITH_AUDASPACE
1008 AUD_SequenceEntry_setSound(handle, sound_handle);
1014#ifdef WITH_AUDASPACE
1032 const char animated)
1034 AUD_SequenceEntry_setAnimationData(handle, AUD_AP_VOLUME, frame, &volume, animated);
1040 const char animated)
1042 AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PITCH, frame, &pitch, animated);
1050 frame_start =
max_ii(0, frame_start);
1051 frame_end =
max_ii(0, frame_end);
1052 AUD_SequenceEntry_setConstantRangeAnimationData(
1053 handle, AUD_AP_PITCH, frame_start, frame_end, &pitch);
1059 const char animated)
1061 AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PANNING, frame, &pan, animated);
1066 BLI_assert_msg(0,
"is not supposed to be used, is weird function.");
1070 for (scene =
static_cast<Scene *
>(
main->scenes.first); scene;
1078static void sound_start_play_scene(
Scene *scene)
1097 sound_device_use_begin();
1103 AUD_Device_lock(
g_state.sound_device);
1120 if (status == AUD_STATUS_INVALID) {
1121 sound_start_play_scene(scene);
1124 AUD_Device_unlock(
g_state.sound_device);
1129 if (status != AUD_STATUS_PLAYING) {
1132 AUD_seekSynchronizer(cur_time);
1138 AUD_playSynchronizer();
1141 AUD_Device_unlock(
g_state.sound_device);
1152 AUD_stopSynchronizer();
1155 sound_device_use_end();
1161 bool animation_playing =
false;
1163 screen =
static_cast<bScreen *
>(screen->id.next))
1165 if (screen->animtimer) {
1166 animation_playing =
true;
1173 if (do_audio_scrub) {
1175 sound_device_use_begin();
1177 else if (
g_state.sound_device ==
nullptr) {
1183 AUD_Device_lock(
g_state.sound_device);
1187 if (status == AUD_STATUS_INVALID) {
1188 sound_start_play_scene(scene);
1191 AUD_Device_unlock(
g_state.sound_device);
1192 if (do_audio_scrub) {
1193 sound_device_use_end();
1201 const double one_frame = 1.0 /
FPS +
1202 (
U.audiorate > 0 ?
U.mixbufsize / double(
U.audiorate) : 0.0);
1205 if (do_audio_scrub) {
1220 sound_device_use_end_after(std::chrono::milliseconds(
int(one_frame * 1000)));
1222 else if (status == AUD_STATUS_PLAYING) {
1227 AUD_seekSynchronizer(cur_time);
1231 AUD_Device_unlock(
g_state.sound_device);
1239 if (
G.is_rendering) {
1245 return AUD_getSynchronizerPosition();
1258 if (waveform->
data) {
1272 bool need_close_audio_handles =
false;
1275 sound_load_audio(bmain, sound,
true);
1276 need_close_audio_handles =
true;
1282 if (info.length > 0) {
1287 short stop_i16 = *
stop;
1288 waveform->
length = AUD_readSound(
1290 *
stop = stop_i16 != 0;
1297 waveform->
data =
nullptr;
1302 if (waveform->
data) {
1319 if (need_close_audio_handles) {
1324static void sound_update_base(
Scene *scene,
Object *
object,
void *new_set)
1344 if (speaker->
sound) {
1345 AUD_SequenceEntry_move(strip->speaker_handle,
double(strip->start) /
FPS,
FLT_MAX, 0);
1348 AUD_Sequence_remove(scene->
sound_scene, strip->speaker_handle);
1349 strip->speaker_handle =
nullptr;
1353 if (speaker->
sound) {
1354 strip->speaker_handle = AUD_Sequence_add(scene->
sound_scene,
1356 double(strip->start) /
FPS,
1359 AUD_SequenceEntry_setRelative(strip->speaker_handle, 0);
1363 if (strip->speaker_handle) {
1366 AUD_SequenceEntry_setVolumeMaximum(strip->speaker_handle, speaker->
volume_max);
1367 AUD_SequenceEntry_setVolumeMinimum(strip->speaker_handle, speaker->
volume_min);
1368 AUD_SequenceEntry_setDistanceMaximum(strip->speaker_handle, speaker->
distance_max);
1369 AUD_SequenceEntry_setDistanceReference(strip->speaker_handle, speaker->
distance_reference);
1370 AUD_SequenceEntry_setAttenuation(strip->speaker_handle, speaker->
attenuation);
1371 AUD_SequenceEntry_setConeAngleOuter(strip->speaker_handle, speaker->
cone_angle_outer);
1372 AUD_SequenceEntry_setConeAngleInner(strip->speaker_handle, speaker->
cone_angle_inner);
1373 AUD_SequenceEntry_setConeVolumeOuter(strip->speaker_handle, speaker->
cone_volume_outer);
1377 AUD_SequenceEntry_setAnimationData(
1378 strip->speaker_handle, AUD_AP_LOCATION, scene->
r.
cfra, location, 1);
1379 AUD_SequenceEntry_setAnimationData(
1380 strip->speaker_handle, AUD_AP_ORIENTATION, scene->
r.
cfra, quat, 1);
1381 AUD_SequenceEntry_setAnimationData(
1382 strip->speaker_handle, AUD_AP_VOLUME, scene->
r.
cfra, &speaker->
volume, 1);
1383 AUD_SequenceEntry_setAnimationData(
1384 strip->speaker_handle, AUD_AP_PITCH, scene->
r.
cfra, &speaker->
pitch, 1);
1386 AUD_SequenceEntry_setMuted(strip->speaker_handle, mute);
1408 sound_update_base(scene,
object, new_set);
1420 AUD_Sequence_setAnimationData(scene->
sound_scene, AUD_AP_LOCATION, scene->
r.
cfra, location, 1);
1421 AUD_Sequence_setAnimationData(scene->
sound_scene, AUD_AP_ORIENTATION, scene->
r.
cfra, quat, 1);
1430 return ((
bSound *)sound)->playback_handle;
1448 if (audio_device_names ==
nullptr) {
1449 audio_device_names = AUD_getDeviceNames();
1452 return audio_device_names;
1455static bool sound_info_from_playback_handle(
void *playback_handle,
SoundInfo *sound_info)
1457 if (playback_handle ==
nullptr) {
1460 AUD_SoundInfo info = AUD_getInfo(playback_handle);
1470 return sound_info_from_playback_handle(sound->
playback_handle, sound_info);
1475 sound_load_audio(
main, sound,
false);
1482 const char *filepath,
1489 AUD_StreamInfo *stream_infos;
1492 STRNCPY(filepath_abs, filepath);
1495 sound = AUD_Sound_file(filepath_abs);
1500 stream_count = AUD_Sound_getFileStreams(sound, &stream_infos);
1502 AUD_Sound_free(sound);
1504 if (!stream_infos) {
1508 if ((stream < 0) || (stream >= stream_count)) {
1513 sound_info->
start = stream_infos[stream].start;
1514 sound_info->
duration = stream_infos[stream].duration;
1625 static char *names[1] = {
nullptr};
1664 sound->
cache =
nullptr;
1670 if (sound->
cache !=
nullptr) {
1678#if defined(WITH_AUDASPACE)
1690 if (
G.is_rendering) {
1693#ifdef WITH_AUDASPACE
1694 AUD_Device_lock(
g_state.sound_device);
1705 AUD_Device_unlock(
g_state.sound_device);
void * AUD_getSet(void *set)
void AUD_addSet(void *set, void *entry)
void AUD_destroySet(void *set)
char AUD_removeSet(void *set, void *entry)
bool BKE_bpath_foreach_path_fixed_process(BPathForeachPathData *bpath_data, char *path, size_t path_maxncpy)
@ BKE_BPATH_FOREACH_PATH_SKIP_PACKED
void(*)(ID *id, const IDCacheKey *cache_key, void **cache_p, uint flags, void *user_data) IDTypeForeachCacheFunctionCallback
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
@ IDTYPE_FLAGS_NO_ANIMDATA
void * BKE_libblock_alloc(Main *bmain, short type, const char *name, int flag) ATTR_WARN_UNUSED_RESULT
void BKE_id_blend_write(BlendWriter *writer, ID *id)
LibraryForeachIDFlag BKE_lib_query_foreachid_process_flags_get(const LibraryForeachIDData *data)
@ IDWALK_DO_DEPRECATED_POINTERS
#define BKE_LIB_FOREACHID_PROCESS_ID_NOCHECK(data_, id_, cb_flag_)
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
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
void(* SoundJackSyncCallback)(struct Main *bmain, int mode, double time)
#define BLI_assert_msg(a, msg)
void BLI_kdtree_nd_ free(KDTree *tree)
#define LISTBASE_FOREACH(type, var, list)
MINLINE int max_ii(int a, int b)
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
char * STRNCPY(char(&dst)[N], const char *src)
#define BLI_string_join(...)
pthread_spinlock_t SpinLock
void BLI_spin_init(SpinLock *spin)
void BLI_spin_unlock(SpinLock *spin)
void BLI_spin_lock(SpinLock *spin)
void BLI_spin_end(SpinLock *spin)
#define UNUSED_VARS_NDEBUG(...)
bool BLO_read_data_is_undo(BlendDataReader *reader)
#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_INFO(clg_ref, level,...)
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_FINAL_RESULT
Object is a sort of wrapper for general info.
@ SOUND_TAGS_WAVEFORM_LOADING
@ SOUND_TAGS_WAVEFORM_NO_RELOAD
Read Guarded memory(de)allocation.
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)
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_load(Main *, bSound *)
void BKE_sound_update_sequencer(Main *, bSound *)
static void sound_free_data(ID *id)
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_play_scene(Scene *)
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 *)
static void sound_foreach_id(ID *id, LibraryForeachIDData *data)
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_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 pf(_x, _i)
Prefetch 64.
float length(VecOp< float, D >) RET
static GPUSelectNextState g_state
#define ID_BLEND_PATH(_bmain, _id)
#define ID_IS_OVERRIDE_LIBRARY(_id)
void * MEM_mallocN(size_t len, const char *str)
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
void MEM_freeN(void *vmemh)
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
unsigned int id_session_uid
void * sound_scrub_handle
struct SoundInfo::@231102123130065173371367072324216376355364061242 specs
struct PackedFile * packedfile
struct PackedFile * newpackedfile
static void sound_jack_sync_callback(Main *bmain, int mode, double time)