1/**************************************************************************/
2/* audio_stream.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "audio_stream.h"
32
33#include "core/config/project_settings.h"
34#include "core/os/os.h"
35
36void AudioStreamPlayback::start(double p_from_pos) {
37 if (GDVIRTUAL_CALL(_start, p_from_pos)) {
38 return;
39 }
40 ERR_FAIL_MSG("AudioStreamPlayback::start unimplemented!");
41}
42void AudioStreamPlayback::stop() {
43 if (GDVIRTUAL_CALL(_stop)) {
44 return;
45 }
46 ERR_FAIL_MSG("AudioStreamPlayback::stop unimplemented!");
47}
48bool AudioStreamPlayback::is_playing() const {
49 bool ret;
50 if (GDVIRTUAL_CALL(_is_playing, ret)) {
51 return ret;
52 }
53 ERR_FAIL_V_MSG(false, "AudioStreamPlayback::is_playing unimplemented!");
54}
55
56int AudioStreamPlayback::get_loop_count() const {
57 int ret = 0;
58 GDVIRTUAL_CALL(_get_loop_count, ret);
59 return ret;
60}
61
62double AudioStreamPlayback::get_playback_position() const {
63 double ret;
64 if (GDVIRTUAL_CALL(_get_playback_position, ret)) {
65 return ret;
66 }
67 ERR_FAIL_V_MSG(0, "AudioStreamPlayback::get_playback_position unimplemented!");
68}
69void AudioStreamPlayback::seek(double p_time) {
70 GDVIRTUAL_CALL(_seek, p_time);
71}
72
73int AudioStreamPlayback::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
74 int ret = 0;
75 GDVIRTUAL_REQUIRED_CALL(_mix, p_buffer, p_rate_scale, p_frames, ret);
76 return ret;
77}
78
79void AudioStreamPlayback::tag_used_streams() {
80 GDVIRTUAL_CALL(_tag_used_streams);
81}
82
83void AudioStreamPlayback::_bind_methods() {
84 GDVIRTUAL_BIND(_start, "from_pos")
85 GDVIRTUAL_BIND(_stop)
86 GDVIRTUAL_BIND(_is_playing)
87 GDVIRTUAL_BIND(_get_loop_count)
88 GDVIRTUAL_BIND(_get_playback_position)
89 GDVIRTUAL_BIND(_seek, "position")
90 GDVIRTUAL_BIND(_mix, "buffer", "rate_scale", "frames");
91 GDVIRTUAL_BIND(_tag_used_streams);
92}
93//////////////////////////////
94
95void AudioStreamPlaybackResampled::begin_resample() {
96 //clear cubic interpolation history
97 internal_buffer[0] = AudioFrame(0.0, 0.0);
98 internal_buffer[1] = AudioFrame(0.0, 0.0);
99 internal_buffer[2] = AudioFrame(0.0, 0.0);
100 internal_buffer[3] = AudioFrame(0.0, 0.0);
101 //mix buffer
102 _mix_internal(internal_buffer + 4, INTERNAL_BUFFER_LEN);
103 mix_offset = 0;
104}
105
106int AudioStreamPlaybackResampled::_mix_internal(AudioFrame *p_buffer, int p_frames) {
107 int ret = 0;
108 GDVIRTUAL_REQUIRED_CALL(_mix_resampled, p_buffer, p_frames, ret);
109 return ret;
110}
111float AudioStreamPlaybackResampled::get_stream_sampling_rate() {
112 float ret = 0;
113 GDVIRTUAL_REQUIRED_CALL(_get_stream_sampling_rate, ret);
114 return ret;
115}
116
117void AudioStreamPlaybackResampled::_bind_methods() {
118 ClassDB::bind_method(D_METHOD("begin_resample"), &AudioStreamPlaybackResampled::begin_resample);
119
120 GDVIRTUAL_BIND(_mix_resampled, "dst_buffer", "frame_count");
121 GDVIRTUAL_BIND(_get_stream_sampling_rate);
122}
123
124int AudioStreamPlaybackResampled::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
125 float target_rate = AudioServer::get_singleton()->get_mix_rate();
126 float playback_speed_scale = AudioServer::get_singleton()->get_playback_speed_scale();
127
128 uint64_t mix_increment = uint64_t(((get_stream_sampling_rate() * p_rate_scale * playback_speed_scale) / double(target_rate)) * double(FP_LEN));
129
130 int mixed_frames_total = -1;
131
132 int i;
133 for (i = 0; i < p_frames; i++) {
134 uint32_t idx = CUBIC_INTERP_HISTORY + uint32_t(mix_offset >> FP_BITS);
135 //standard cubic interpolation (great quality/performance ratio)
136 //this used to be moved to a LUT for greater performance, but nowadays CPU speed is generally faster than memory.
137 float mu = (mix_offset & FP_MASK) / float(FP_LEN);
138 AudioFrame y0 = internal_buffer[idx - 3];
139 AudioFrame y1 = internal_buffer[idx - 2];
140 AudioFrame y2 = internal_buffer[idx - 1];
141 AudioFrame y3 = internal_buffer[idx - 0];
142
143 if (idx >= internal_buffer_end && mixed_frames_total == -1) {
144 // The internal buffer ends somewhere in this range, and we haven't yet recorded the number of good frames we have.
145 mixed_frames_total = i;
146 }
147
148 float mu2 = mu * mu;
149 AudioFrame a0 = 3 * y1 - 3 * y2 + y3 - y0;
150 AudioFrame a1 = 2 * y0 - 5 * y1 + 4 * y2 - y3;
151 AudioFrame a2 = y2 - y0;
152 AudioFrame a3 = 2 * y1;
153
154 p_buffer[i] = (a0 * mu * mu2 + a1 * mu2 + a2 * mu + a3) / 2;
155
156 mix_offset += mix_increment;
157
158 while ((mix_offset >> FP_BITS) >= INTERNAL_BUFFER_LEN) {
159 internal_buffer[0] = internal_buffer[INTERNAL_BUFFER_LEN + 0];
160 internal_buffer[1] = internal_buffer[INTERNAL_BUFFER_LEN + 1];
161 internal_buffer[2] = internal_buffer[INTERNAL_BUFFER_LEN + 2];
162 internal_buffer[3] = internal_buffer[INTERNAL_BUFFER_LEN + 3];
163 int mixed_frames = _mix_internal(internal_buffer + 4, INTERNAL_BUFFER_LEN);
164 if (mixed_frames != INTERNAL_BUFFER_LEN) {
165 // internal_buffer[mixed_frames] is the first frame of silence.
166 internal_buffer_end = mixed_frames;
167 } else {
168 // The internal buffer does not contain the first frame of silence.
169 internal_buffer_end = -1;
170 }
171 mix_offset -= (INTERNAL_BUFFER_LEN << FP_BITS);
172 }
173 }
174 if (mixed_frames_total == -1 && i == p_frames) {
175 mixed_frames_total = p_frames;
176 }
177 return mixed_frames_total;
178}
179
180////////////////////////////////
181
182Ref<AudioStreamPlayback> AudioStream::instantiate_playback() {
183 Ref<AudioStreamPlayback> ret;
184 if (GDVIRTUAL_CALL(_instantiate_playback, ret)) {
185 return ret;
186 }
187 ERR_FAIL_V_MSG(Ref<AudioStreamPlayback>(), "Method must be implemented!");
188}
189String AudioStream::get_stream_name() const {
190 String ret;
191 GDVIRTUAL_CALL(_get_stream_name, ret);
192 return ret;
193}
194
195double AudioStream::get_length() const {
196 double ret = 0;
197 GDVIRTUAL_CALL(_get_length, ret);
198 return ret;
199}
200
201bool AudioStream::is_monophonic() const {
202 bool ret = true;
203 GDVIRTUAL_CALL(_is_monophonic, ret);
204 return ret;
205}
206
207double AudioStream::get_bpm() const {
208 double ret = 0;
209 GDVIRTUAL_CALL(_get_bpm, ret);
210 return ret;
211}
212
213bool AudioStream::has_loop() const {
214 bool ret = 0;
215 GDVIRTUAL_CALL(_has_loop, ret);
216 return ret;
217}
218
219int AudioStream::get_bar_beats() const {
220 int ret = 0;
221 GDVIRTUAL_CALL(_get_bar_beats, ret);
222 return ret;
223}
224
225int AudioStream::get_beat_count() const {
226 int ret = 0;
227 GDVIRTUAL_CALL(_get_beat_count, ret);
228 return ret;
229}
230
231void AudioStream::tag_used(float p_offset) {
232 if (tagged_frame != AudioServer::get_singleton()->get_mixed_frames()) {
233 offset_count = 0;
234 tagged_frame = AudioServer::get_singleton()->get_mixed_frames();
235 }
236 if (offset_count < MAX_TAGGED_OFFSETS) {
237 tagged_offsets[offset_count++] = p_offset;
238 }
239}
240
241uint64_t AudioStream::get_tagged_frame() const {
242 return tagged_frame;
243}
244uint32_t AudioStream::get_tagged_frame_count() const {
245 return offset_count;
246}
247float AudioStream::get_tagged_frame_offset(int p_index) const {
248 ERR_FAIL_INDEX_V(p_index, MAX_TAGGED_OFFSETS, 0);
249 return tagged_offsets[p_index];
250}
251
252void AudioStream::_bind_methods() {
253 ClassDB::bind_method(D_METHOD("get_length"), &AudioStream::get_length);
254 ClassDB::bind_method(D_METHOD("is_monophonic"), &AudioStream::is_monophonic);
255 ClassDB::bind_method(D_METHOD("instantiate_playback"), &AudioStream::instantiate_playback);
256 GDVIRTUAL_BIND(_instantiate_playback);
257 GDVIRTUAL_BIND(_get_stream_name);
258 GDVIRTUAL_BIND(_get_length);
259 GDVIRTUAL_BIND(_is_monophonic);
260 GDVIRTUAL_BIND(_get_bpm)
261 GDVIRTUAL_BIND(_get_beat_count)
262}
263
264////////////////////////////////
265
266Ref<AudioStreamPlayback> AudioStreamMicrophone::instantiate_playback() {
267 Ref<AudioStreamPlaybackMicrophone> playback;
268 playback.instantiate();
269
270 playbacks.insert(playback.ptr());
271
272 playback->microphone = Ref<AudioStreamMicrophone>((AudioStreamMicrophone *)this);
273 playback->active = false;
274
275 return playback;
276}
277
278String AudioStreamMicrophone::get_stream_name() const {
279 //if (audio_stream.is_valid()) {
280 //return "Random: " + audio_stream->get_name();
281 //}
282 return "Microphone";
283}
284
285double AudioStreamMicrophone::get_length() const {
286 return 0;
287}
288
289bool AudioStreamMicrophone::is_monophonic() const {
290 return true;
291}
292
293void AudioStreamMicrophone::_bind_methods() {
294}
295
296AudioStreamMicrophone::AudioStreamMicrophone() {
297}
298
299int AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_frames) {
300 AudioDriver::get_singleton()->lock();
301
302 Vector<int32_t> buf = AudioDriver::get_singleton()->get_input_buffer();
303 unsigned int input_size = AudioDriver::get_singleton()->get_input_size();
304 int mix_rate = AudioDriver::get_singleton()->get_mix_rate();
305 unsigned int playback_delay = MIN(((50 * mix_rate) / 1000) * 2, buf.size() >> 1);
306#ifdef DEBUG_ENABLED
307 unsigned int input_position = AudioDriver::get_singleton()->get_input_position();
308#endif
309
310 int mixed_frames = p_frames;
311
312 if (playback_delay > input_size) {
313 for (int i = 0; i < p_frames; i++) {
314 p_buffer[i] = AudioFrame(0.0f, 0.0f);
315 }
316 input_ofs = 0;
317 } else {
318 for (int i = 0; i < p_frames; i++) {
319 if (input_size > input_ofs && (int)input_ofs < buf.size()) {
320 float l = (buf[input_ofs++] >> 16) / 32768.f;
321 if ((int)input_ofs >= buf.size()) {
322 input_ofs = 0;
323 }
324 float r = (buf[input_ofs++] >> 16) / 32768.f;
325 if ((int)input_ofs >= buf.size()) {
326 input_ofs = 0;
327 }
328
329 p_buffer[i] = AudioFrame(l, r);
330 } else {
331 if (mixed_frames == p_frames) {
332 mixed_frames = i;
333 }
334 p_buffer[i] = AudioFrame(0.0f, 0.0f);
335 }
336 }
337 }
338
339#ifdef DEBUG_ENABLED
340 if (input_ofs > input_position && (int)(input_ofs - input_position) < (p_frames * 2)) {
341 print_verbose(String(get_class_name()) + " buffer underrun: input_position=" + itos(input_position) + " input_ofs=" + itos(input_ofs) + " input_size=" + itos(input_size));
342 }
343#endif
344
345 AudioDriver::get_singleton()->unlock();
346
347 return mixed_frames;
348}
349
350int AudioStreamPlaybackMicrophone::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
351 return AudioStreamPlaybackResampled::mix(p_buffer, p_rate_scale, p_frames);
352}
353
354float AudioStreamPlaybackMicrophone::get_stream_sampling_rate() {
355 return AudioDriver::get_singleton()->get_mix_rate();
356}
357
358void AudioStreamPlaybackMicrophone::start(double p_from_pos) {
359 if (active) {
360 return;
361 }
362
363 if (!GLOBAL_GET("audio/driver/enable_input")) {
364 WARN_PRINT("You must enable the project setting \"audio/driver/enable_input\" to use audio capture.");
365 return;
366 }
367
368 input_ofs = 0;
369
370 if (AudioDriver::get_singleton()->input_start() == OK) {
371 active = true;
372 begin_resample();
373 }
374}
375
376void AudioStreamPlaybackMicrophone::stop() {
377 if (active) {
378 AudioDriver::get_singleton()->input_stop();
379 active = false;
380 }
381}
382
383bool AudioStreamPlaybackMicrophone::is_playing() const {
384 return active;
385}
386
387int AudioStreamPlaybackMicrophone::get_loop_count() const {
388 return 0;
389}
390
391double AudioStreamPlaybackMicrophone::get_playback_position() const {
392 return 0;
393}
394
395void AudioStreamPlaybackMicrophone::seek(double p_time) {
396 // Can't seek a microphone input
397}
398
399void AudioStreamPlaybackMicrophone::tag_used_streams() {
400 microphone->tag_used(0);
401}
402
403AudioStreamPlaybackMicrophone::~AudioStreamPlaybackMicrophone() {
404 microphone->playbacks.erase(this);
405 stop();
406}
407
408AudioStreamPlaybackMicrophone::AudioStreamPlaybackMicrophone() {
409}
410
411////////////////////////////////
412
413void AudioStreamRandomizer::add_stream(int p_index, Ref<AudioStream> p_stream, float p_weight) {
414 if (p_index < 0) {
415 p_index = audio_stream_pool.size();
416 }
417 ERR_FAIL_COND(p_index > audio_stream_pool.size());
418 PoolEntry entry{ p_stream, p_weight };
419 audio_stream_pool.insert(p_index, entry);
420 emit_signal(SNAME("changed"));
421 notify_property_list_changed();
422}
423
424// p_index_to is relative to the array prior to the removal of from.
425// Example: [0, 1, 2, 3], move(1, 3) => [0, 2, 1, 3]
426void AudioStreamRandomizer::move_stream(int p_index_from, int p_index_to) {
427 ERR_FAIL_INDEX(p_index_from, audio_stream_pool.size());
428 // p_index_to == audio_stream_pool.size() is valid (move to end).
429 ERR_FAIL_COND(p_index_to < 0);
430 ERR_FAIL_COND(p_index_to > audio_stream_pool.size());
431 audio_stream_pool.insert(p_index_to, audio_stream_pool[p_index_from]);
432 // If 'from' is strictly after 'to' we need to increment the index by one because of the insertion.
433 if (p_index_from > p_index_to) {
434 p_index_from++;
435 }
436 audio_stream_pool.remove_at(p_index_from);
437 emit_signal(SNAME("changed"));
438 notify_property_list_changed();
439}
440
441void AudioStreamRandomizer::remove_stream(int p_index) {
442 ERR_FAIL_INDEX(p_index, audio_stream_pool.size());
443 audio_stream_pool.remove_at(p_index);
444 emit_signal(SNAME("changed"));
445 notify_property_list_changed();
446}
447
448void AudioStreamRandomizer::set_stream(int p_index, Ref<AudioStream> p_stream) {
449 ERR_FAIL_INDEX(p_index, audio_stream_pool.size());
450 audio_stream_pool.write[p_index].stream = p_stream;
451 emit_signal(SNAME("changed"));
452}
453
454Ref<AudioStream> AudioStreamRandomizer::get_stream(int p_index) const {
455 ERR_FAIL_INDEX_V(p_index, audio_stream_pool.size(), nullptr);
456 return audio_stream_pool[p_index].stream;
457}
458
459void AudioStreamRandomizer::set_stream_probability_weight(int p_index, float p_weight) {
460 ERR_FAIL_INDEX(p_index, audio_stream_pool.size());
461 audio_stream_pool.write[p_index].weight = p_weight;
462 emit_signal(SNAME("changed"));
463}
464
465float AudioStreamRandomizer::get_stream_probability_weight(int p_index) const {
466 ERR_FAIL_INDEX_V(p_index, audio_stream_pool.size(), 0);
467 return audio_stream_pool[p_index].weight;
468}
469
470void AudioStreamRandomizer::set_streams_count(int p_count) {
471 audio_stream_pool.resize(p_count);
472}
473
474int AudioStreamRandomizer::get_streams_count() const {
475 return audio_stream_pool.size();
476}
477
478void AudioStreamRandomizer::set_random_pitch(float p_pitch) {
479 if (p_pitch < 1) {
480 p_pitch = 1;
481 }
482 random_pitch_scale = p_pitch;
483}
484
485float AudioStreamRandomizer::get_random_pitch() const {
486 return random_pitch_scale;
487}
488
489void AudioStreamRandomizer::set_random_volume_offset_db(float p_volume_offset_db) {
490 if (p_volume_offset_db < 0) {
491 p_volume_offset_db = 0;
492 }
493 random_volume_offset_db = p_volume_offset_db;
494}
495
496float AudioStreamRandomizer::get_random_volume_offset_db() const {
497 return random_volume_offset_db;
498}
499
500void AudioStreamRandomizer::set_playback_mode(PlaybackMode p_playback_mode) {
501 playback_mode = p_playback_mode;
502}
503
504AudioStreamRandomizer::PlaybackMode AudioStreamRandomizer::get_playback_mode() const {
505 return playback_mode;
506}
507
508Ref<AudioStreamPlayback> AudioStreamRandomizer::instance_playback_random() {
509 Ref<AudioStreamPlaybackRandomizer> playback;
510 playback.instantiate();
511 playbacks.insert(playback.ptr());
512 playback->randomizer = Ref<AudioStreamRandomizer>((AudioStreamRandomizer *)this);
513
514 double total_weight = 0;
515 Vector<PoolEntry> local_pool;
516 for (const PoolEntry &entry : audio_stream_pool) {
517 if (entry.stream.is_valid() && entry.weight > 0) {
518 local_pool.push_back(entry);
519 total_weight += entry.weight;
520 }
521 }
522 if (local_pool.is_empty()) {
523 return playback;
524 }
525 double chosen_cumulative_weight = Math::random(0.0, total_weight);
526 double cumulative_weight = 0;
527 for (PoolEntry &entry : local_pool) {
528 cumulative_weight += entry.weight;
529 if (cumulative_weight > chosen_cumulative_weight) {
530 playback->playback = entry.stream->instantiate_playback();
531 last_playback = entry.stream;
532 break;
533 }
534 }
535 if (playback->playback.is_null()) {
536 // This indicates a floating point error. Take the last element.
537 last_playback = local_pool[local_pool.size() - 1].stream;
538 playback->playback = local_pool.write[local_pool.size() - 1].stream->instantiate_playback();
539 }
540 return playback;
541}
542
543Ref<AudioStreamPlayback> AudioStreamRandomizer::instance_playback_no_repeats() {
544 Ref<AudioStreamPlaybackRandomizer> playback;
545
546 double total_weight = 0;
547 Vector<PoolEntry> local_pool;
548 for (const PoolEntry &entry : audio_stream_pool) {
549 if (entry.stream == last_playback) {
550 continue;
551 }
552 if (entry.stream.is_valid() && entry.weight > 0) {
553 local_pool.push_back(entry);
554 total_weight += entry.weight;
555 }
556 }
557 if (local_pool.is_empty()) {
558 // There is only one sound to choose from.
559 // Always play a random sound while allowing repeats (which always plays the same sound).
560 playback = instance_playback_random();
561 return playback;
562 }
563
564 playback.instantiate();
565 playbacks.insert(playback.ptr());
566 playback->randomizer = Ref<AudioStreamRandomizer>((AudioStreamRandomizer *)this);
567 double chosen_cumulative_weight = Math::random(0.0, total_weight);
568 double cumulative_weight = 0;
569 for (PoolEntry &entry : local_pool) {
570 cumulative_weight += entry.weight;
571 if (cumulative_weight > chosen_cumulative_weight) {
572 last_playback = entry.stream;
573 playback->playback = entry.stream->instantiate_playback();
574 break;
575 }
576 }
577 if (playback->playback.is_null()) {
578 // This indicates a floating point error. Take the last element.
579 last_playback = local_pool[local_pool.size() - 1].stream;
580 playback->playback = local_pool.write[local_pool.size() - 1].stream->instantiate_playback();
581 }
582 return playback;
583}
584
585Ref<AudioStreamPlayback> AudioStreamRandomizer::instance_playback_sequential() {
586 Ref<AudioStreamPlaybackRandomizer> playback;
587 playback.instantiate();
588 playbacks.insert(playback.ptr());
589 playback->randomizer = Ref<AudioStreamRandomizer>((AudioStreamRandomizer *)this);
590
591 Vector<Ref<AudioStream>> local_pool;
592 for (const PoolEntry &entry : audio_stream_pool) {
593 if (entry.stream.is_null()) {
594 continue;
595 }
596 if (local_pool.find(entry.stream) != -1) {
597 WARN_PRINT("Duplicate stream in sequential playback pool");
598 continue;
599 }
600 local_pool.push_back(entry.stream);
601 }
602 if (local_pool.is_empty()) {
603 return playback;
604 }
605 bool found_last_stream = false;
606 for (Ref<AudioStream> &entry : local_pool) {
607 if (found_last_stream) {
608 last_playback = entry;
609 playback->playback = entry->instantiate_playback();
610 break;
611 }
612 if (entry == last_playback) {
613 found_last_stream = true;
614 }
615 }
616 if (playback->playback.is_null()) {
617 // Wrap around
618 last_playback = local_pool[0];
619 playback->playback = local_pool.write[0]->instantiate_playback();
620 }
621 return playback;
622}
623
624Ref<AudioStreamPlayback> AudioStreamRandomizer::instantiate_playback() {
625 switch (playback_mode) {
626 case PLAYBACK_RANDOM:
627 return instance_playback_random();
628 case PLAYBACK_RANDOM_NO_REPEATS:
629 return instance_playback_no_repeats();
630 case PLAYBACK_SEQUENTIAL:
631 return instance_playback_sequential();
632 default:
633 ERR_FAIL_V_MSG(nullptr, "Unhandled playback mode.");
634 }
635}
636
637String AudioStreamRandomizer::get_stream_name() const {
638 return "Randomizer";
639}
640
641double AudioStreamRandomizer::get_length() const {
642 return 0;
643}
644
645bool AudioStreamRandomizer::is_monophonic() const {
646 for (const PoolEntry &entry : audio_stream_pool) {
647 if (entry.stream.is_valid() && entry.stream->is_monophonic()) {
648 return true;
649 }
650 }
651 return false;
652}
653
654bool AudioStreamRandomizer::_get(const StringName &p_name, Variant &r_ret) const {
655 if (AudioStream::_get(p_name, r_ret)) {
656 return true;
657 }
658 Vector<String> components = String(p_name).split("/", true, 2);
659 if (components.size() == 2 && components[0].begins_with("stream_") && components[0].trim_prefix("stream_").is_valid_int()) {
660 int index = components[0].trim_prefix("stream_").to_int();
661 if (index < 0 || index >= (int)audio_stream_pool.size()) {
662 return false;
663 }
664
665 if (components[1] == "stream") {
666 r_ret = get_stream(index);
667 return true;
668 } else if (components[1] == "weight") {
669 r_ret = get_stream_probability_weight(index);
670 return true;
671 } else {
672 return false;
673 }
674 }
675 return false;
676}
677
678bool AudioStreamRandomizer::_set(const StringName &p_name, const Variant &p_value) {
679 if (AudioStream::_set(p_name, p_value)) {
680 return true;
681 }
682 Vector<String> components = String(p_name).split("/", true, 2);
683 if (components.size() == 2 && components[0].begins_with("stream_") && components[0].trim_prefix("stream_").is_valid_int()) {
684 int index = components[0].trim_prefix("stream_").to_int();
685 if (index < 0 || index >= (int)audio_stream_pool.size()) {
686 return false;
687 }
688
689 if (components[1] == "stream") {
690 set_stream(index, p_value);
691 return true;
692 } else if (components[1] == "weight") {
693 set_stream_probability_weight(index, p_value);
694 return true;
695 } else {
696 return false;
697 }
698 }
699 return false;
700}
701
702void AudioStreamRandomizer::_get_property_list(List<PropertyInfo> *p_list) const {
703 AudioStream::_get_property_list(p_list); // Define the trivial scalar properties.
704 p_list->push_back(PropertyInfo(Variant::NIL, "Streams", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
705 for (int i = 0; i < audio_stream_pool.size(); i++) {
706 p_list->push_back(PropertyInfo(Variant::OBJECT, vformat("stream_%d/stream", i), PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"));
707 p_list->push_back(PropertyInfo(Variant::FLOAT, vformat("stream_%d/weight", i), PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"));
708 }
709}
710
711void AudioStreamRandomizer::_bind_methods() {
712 ClassDB::bind_method(D_METHOD("add_stream", "index", "stream", "weight"), &AudioStreamRandomizer::add_stream, DEFVAL(1.0));
713 ClassDB::bind_method(D_METHOD("move_stream", "index_from", "index_to"), &AudioStreamRandomizer::move_stream);
714 ClassDB::bind_method(D_METHOD("remove_stream", "index"), &AudioStreamRandomizer::remove_stream);
715
716 ClassDB::bind_method(D_METHOD("set_stream", "index", "stream"), &AudioStreamRandomizer::set_stream);
717 ClassDB::bind_method(D_METHOD("get_stream", "index"), &AudioStreamRandomizer::get_stream);
718 ClassDB::bind_method(D_METHOD("set_stream_probability_weight", "index", "weight"), &AudioStreamRandomizer::set_stream_probability_weight);
719 ClassDB::bind_method(D_METHOD("get_stream_probability_weight", "index"), &AudioStreamRandomizer::get_stream_probability_weight);
720
721 ClassDB::bind_method(D_METHOD("set_streams_count", "count"), &AudioStreamRandomizer::set_streams_count);
722 ClassDB::bind_method(D_METHOD("get_streams_count"), &AudioStreamRandomizer::get_streams_count);
723
724 ClassDB::bind_method(D_METHOD("set_random_pitch", "scale"), &AudioStreamRandomizer::set_random_pitch);
725 ClassDB::bind_method(D_METHOD("get_random_pitch"), &AudioStreamRandomizer::get_random_pitch);
726
727 ClassDB::bind_method(D_METHOD("set_random_volume_offset_db", "db_offset"), &AudioStreamRandomizer::set_random_volume_offset_db);
728 ClassDB::bind_method(D_METHOD("get_random_volume_offset_db"), &AudioStreamRandomizer::get_random_volume_offset_db);
729
730 ClassDB::bind_method(D_METHOD("set_playback_mode", "mode"), &AudioStreamRandomizer::set_playback_mode);
731 ClassDB::bind_method(D_METHOD("get_playback_mode"), &AudioStreamRandomizer::get_playback_mode);
732
733 ADD_ARRAY("streams", "stream_");
734 ADD_PROPERTY(PropertyInfo(Variant::INT, "streams_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_streams_count", "get_streams_count");
735 ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_mode", PROPERTY_HINT_ENUM, "Random (Avoid Repeats),Random,Sequential"), "set_playback_mode", "get_playback_mode");
736 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "random_pitch", PROPERTY_HINT_RANGE, "1,16,0.01"), "set_random_pitch", "get_random_pitch");
737 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "random_volume_offset_db", PROPERTY_HINT_RANGE, "0,40,0.01,suffix:dB"), "set_random_volume_offset_db", "get_random_volume_offset_db");
738
739 BIND_ENUM_CONSTANT(PLAYBACK_RANDOM_NO_REPEATS);
740 BIND_ENUM_CONSTANT(PLAYBACK_RANDOM);
741 BIND_ENUM_CONSTANT(PLAYBACK_SEQUENTIAL);
742}
743
744AudioStreamRandomizer::AudioStreamRandomizer() {}
745
746void AudioStreamPlaybackRandomizer::start(double p_from_pos) {
747 playing = playback;
748 {
749 float range_from = 1.0 / randomizer->random_pitch_scale;
750 float range_to = randomizer->random_pitch_scale;
751
752 pitch_scale = range_from + Math::randf() * (range_to - range_from);
753 }
754 {
755 float range_from = -randomizer->random_volume_offset_db;
756 float range_to = randomizer->random_volume_offset_db;
757
758 float volume_offset_db = range_from + Math::randf() * (range_to - range_from);
759 volume_scale = Math::db_to_linear(volume_offset_db);
760 }
761
762 if (playing.is_valid()) {
763 playing->start(p_from_pos);
764 }
765}
766
767void AudioStreamPlaybackRandomizer::stop() {
768 if (playing.is_valid()) {
769 playing->stop();
770 }
771}
772
773bool AudioStreamPlaybackRandomizer::is_playing() const {
774 if (playing.is_valid()) {
775 return playing->is_playing();
776 }
777
778 return false;
779}
780
781int AudioStreamPlaybackRandomizer::get_loop_count() const {
782 if (playing.is_valid()) {
783 return playing->get_loop_count();
784 }
785
786 return 0;
787}
788
789double AudioStreamPlaybackRandomizer::get_playback_position() const {
790 if (playing.is_valid()) {
791 return playing->get_playback_position();
792 }
793
794 return 0;
795}
796
797void AudioStreamPlaybackRandomizer::seek(double p_time) {
798 if (playing.is_valid()) {
799 playing->seek(p_time);
800 }
801}
802
803void AudioStreamPlaybackRandomizer::tag_used_streams() {
804 Ref<AudioStreamPlayback> p = playing; // Thread safety
805 if (p.is_valid()) {
806 p->tag_used_streams();
807 }
808 randomizer->tag_used(0);
809}
810
811int AudioStreamPlaybackRandomizer::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
812 if (playing.is_valid()) {
813 return playing->mix(p_buffer, p_rate_scale * pitch_scale, p_frames);
814 } else {
815 for (int i = 0; i < p_frames; i++) {
816 p_buffer[i] = AudioFrame(0, 0);
817 }
818 return p_frames;
819 }
820}
821
822AudioStreamPlaybackRandomizer::~AudioStreamPlaybackRandomizer() {
823 randomizer->playbacks.erase(this);
824}
825/////////////////////////////////////////////
826