From c3f8750e51e619a71c8f934b72f7ae76a6c9972e Mon Sep 17 00:00:00 2001 From: BuzzLord Date: Wed, 29 May 2024 16:49:12 -0600 Subject: [PATCH] Fix capture and record audioeffect bugs for surround systems. --- doc/classes/AudioEffectCapture.xml | 3 ++ doc/classes/AudioEffectRecord.xml | 3 ++ servers/audio/audio_effect.h | 1 + .../audio/effects/audio_effect_capture.cpp | 15 +++++++ servers/audio/effects/audio_effect_capture.h | 6 +++ .../audio/effects/audio_effect_compressor.h | 2 +- servers/audio/effects/audio_effect_record.cpp | 45 ++++++++++++++++--- servers/audio/effects/audio_effect_record.h | 8 ++++ servers/audio_server.cpp | 4 +- 9 files changed, 78 insertions(+), 9 deletions(-) diff --git a/doc/classes/AudioEffectCapture.xml b/doc/classes/AudioEffectCapture.xml index ce516be5fc40..127193045026 100644 --- a/doc/classes/AudioEffectCapture.xml +++ b/doc/classes/AudioEffectCapture.xml @@ -61,6 +61,9 @@ + + The audio bus channel that is captured by the effect. + Length of the internal ring buffer, in seconds. Setting the buffer length will have no effect if already initialized. diff --git a/doc/classes/AudioEffectRecord.xml b/doc/classes/AudioEffectRecord.xml index ed0a0c5b08a1..ee471da9f897 100644 --- a/doc/classes/AudioEffectRecord.xml +++ b/doc/classes/AudioEffectRecord.xml @@ -35,6 +35,9 @@ + + The audio bus channel that is used for recording by the effect. Note that changing to a different channel will remove the previously recorded sample. + Specifies the format in which the sample will be recorded. See [enum AudioStreamWAV.Format] for available formats. diff --git a/servers/audio/audio_effect.h b/servers/audio/audio_effect.h index 9952246c20af..793bc98e8e8d 100644 --- a/servers/audio/audio_effect.h +++ b/servers/audio/audio_effect.h @@ -47,6 +47,7 @@ class AudioEffectInstance : public RefCounted { public: virtual void process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count); virtual bool process_silence() const; + virtual void set_current_channel(int p_channel) {} }; class AudioEffect : public Resource { diff --git a/servers/audio/effects/audio_effect_capture.cpp b/servers/audio/effects/audio_effect_capture.cpp index a5740c7e275d..b444717b7d35 100644 --- a/servers/audio/effects/audio_effect_capture.cpp +++ b/servers/audio/effects/audio_effect_capture.cpp @@ -69,7 +69,10 @@ void AudioEffectCapture::_bind_methods() { ClassDB::bind_method(D_METHOD("get_discarded_frames"), &AudioEffectCapture::get_discarded_frames); ClassDB::bind_method(D_METHOD("get_buffer_length_frames"), &AudioEffectCapture::get_buffer_length_frames); ClassDB::bind_method(D_METHOD("get_pushed_frames"), &AudioEffectCapture::get_pushed_frames); + ClassDB::bind_method(D_METHOD("set_active_channel", "channel"), &AudioEffectCapture::set_active_channel); + ClassDB::bind_method(D_METHOD("get_active_channel"), &AudioEffectCapture::get_active_channel); + ADD_PROPERTY(PropertyInfo(Variant::INT, "active_channel", PROPERTY_HINT_ENUM, "Stereo,3.1,5.1,7.1"), "set_active_channel", "get_active_channel"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "buffer_length", PROPERTY_HINT_RANGE, "0.01,10,0.01,suffix:s"), "set_buffer_length", "get_buffer_length"); } @@ -116,6 +119,14 @@ int64_t AudioEffectCapture::get_pushed_frames() const { return pushed_frames.get(); } +void AudioEffectCapture::set_active_channel(int p_channel) { + active_channel = p_channel; +} + +int AudioEffectCapture::get_active_channel() const { + return active_channel; +} + void AudioEffectCaptureInstance::process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) { RingBuffer &buffer = base->buffer; @@ -123,6 +134,10 @@ void AudioEffectCaptureInstance::process(const AudioFrame *p_src_frames, AudioFr p_dst_frames[i] = p_src_frames[i]; } + if (base->get_active_channel() != current_channel) { + return; + } + if (buffer.space_left() >= p_frame_count) { // Add incoming audio frames to the IO ring buffer int32_t ret = buffer.write(p_src_frames, p_frame_count); diff --git a/servers/audio/effects/audio_effect_capture.h b/servers/audio/effects/audio_effect_capture.h index 38213984e71d..2554e11190d5 100644 --- a/servers/audio/effects/audio_effect_capture.h +++ b/servers/audio/effects/audio_effect_capture.h @@ -45,10 +45,12 @@ class AudioEffectCaptureInstance : public AudioEffectInstance { GDCLASS(AudioEffectCaptureInstance, AudioEffectInstance); friend class AudioEffectCapture; Ref base; + int current_channel; public: virtual void process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) override; virtual bool process_silence() const override; + virtual void set_current_channel(int p_channel) override { current_channel = p_channel; } }; class AudioEffectCapture : public AudioEffect { @@ -60,6 +62,7 @@ class AudioEffectCapture : public AudioEffect { SafeNumeric pushed_frames; float buffer_length_seconds = 0.1f; bool buffer_initialized = false; + int active_channel = 0; protected: static void _bind_methods(); @@ -78,6 +81,9 @@ class AudioEffectCapture : public AudioEffect { int64_t get_discarded_frames() const; int get_buffer_length_frames() const; int64_t get_pushed_frames() const; + + void set_active_channel(int p_channel); + int get_active_channel() const; }; #endif // AUDIO_EFFECT_CAPTURE_H diff --git a/servers/audio/effects/audio_effect_compressor.h b/servers/audio/effects/audio_effect_compressor.h index e1b9a6853519..5489dc972ea8 100644 --- a/servers/audio/effects/audio_effect_compressor.h +++ b/servers/audio/effects/audio_effect_compressor.h @@ -44,7 +44,7 @@ class AudioEffectCompressorInstance : public AudioEffectInstance { int current_channel; public: - void set_current_channel(int p_channel) { current_channel = p_channel; } + virtual void set_current_channel(int p_channel) override { current_channel = p_channel; } virtual void process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) override; }; diff --git a/servers/audio/effects/audio_effect_record.cpp b/servers/audio/effects/audio_effect_record.cpp index e30a8fa99e31..2e6d740bedf6 100644 --- a/servers/audio/effects/audio_effect_record.cpp +++ b/servers/audio/effects/audio_effect_record.cpp @@ -70,6 +70,10 @@ bool AudioEffectRecordInstance::process_silence() const { return true; } +void AudioEffectRecordInstance::set_current_channel(int p_channel) { + base->register_channel_instance(p_channel, Ref(this)); +} + void AudioEffectRecordInstance::_io_thread_process() { while (is_recording) { _update_buffer(); @@ -123,6 +127,7 @@ void AudioEffectRecordInstance::finish() { Ref AudioEffectRecord::instantiate() { Ref ins; ins.instantiate(); + ins->base = Ref(this); ins->is_recording = false; //Re-using the buffer size calculations from audio_effect_delay.cpp @@ -147,17 +152,26 @@ Ref AudioEffectRecord::instantiate() { ins->ring_buffer_read_pos = 0; - ensure_thread_stopped(); + return ins; +} + +void AudioEffectRecord::set_current_instance(Ref p_instance) { bool is_currently_recording = false; if (current_instance != nullptr) { is_currently_recording = current_instance->is_recording; } - if (is_currently_recording) { - ins->init(); + ensure_thread_stopped(); + if (is_currently_recording && p_instance != nullptr) { + p_instance->init(); } - current_instance = ins; + current_instance = p_instance; +} - return ins; +void AudioEffectRecord::register_channel_instance(int p_channel, Ref p_instance) { + if (active_channel == p_channel) { + set_current_instance(p_instance); + } + channel_instances.insert(p_channel, p_instance); } void AudioEffectRecord::ensure_thread_stopped() { @@ -197,6 +211,24 @@ AudioStreamWAV::Format AudioEffectRecord::get_format() const { return format; } +void AudioEffectRecord::set_active_channel(int p_channel) { + if (active_channel == p_channel) { + return; + } + active_channel = p_channel; + HashMap>::Iterator it = channel_instances.find(p_channel); + if (it) { + set_current_instance(it->value); + } else { + WARN_PRINT("Active channel set to uninitialized channel idx " + itos(p_channel) + "."); + set_current_instance(Ref()); + } +} + +int AudioEffectRecord::get_active_channel() const { + return active_channel; +} + Ref AudioEffectRecord::get_recording() const { AudioStreamWAV::Format dst_format = format; bool stereo = true; //forcing mono is not implemented @@ -282,7 +314,10 @@ void AudioEffectRecord::_bind_methods() { ClassDB::bind_method(D_METHOD("set_format", "format"), &AudioEffectRecord::set_format); ClassDB::bind_method(D_METHOD("get_format"), &AudioEffectRecord::get_format); ClassDB::bind_method(D_METHOD("get_recording"), &AudioEffectRecord::get_recording); + ClassDB::bind_method(D_METHOD("set_active_channel", "channel"), &AudioEffectRecord::set_active_channel); + ClassDB::bind_method(D_METHOD("get_active_channel"), &AudioEffectRecord::get_active_channel); + ADD_PROPERTY(PropertyInfo(Variant::INT, "active_channel", PROPERTY_HINT_ENUM, "Stereo,3.1,5.1,7.1"), "set_active_channel", "get_active_channel"); ADD_PROPERTY(PropertyInfo(Variant::INT, "format", PROPERTY_HINT_ENUM, "8-Bit,16-Bit,IMA-ADPCM"), "set_format", "get_format"); } diff --git a/servers/audio/effects/audio_effect_record.h b/servers/audio/effects/audio_effect_record.h index 6f518c07e20d..0cb930174add 100644 --- a/servers/audio/effects/audio_effect_record.h +++ b/servers/audio/effects/audio_effect_record.h @@ -44,6 +44,7 @@ class AudioEffectRecord; class AudioEffectRecordInstance : public AudioEffectInstance { GDCLASS(AudioEffectRecordInstance, AudioEffectInstance); friend class AudioEffectRecord; + Ref base; bool is_recording; Thread io_thread; @@ -67,6 +68,7 @@ class AudioEffectRecordInstance : public AudioEffectInstance { void finish(); virtual void process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) override; virtual bool process_silence() const override; + virtual void set_current_channel(int p_channel) override; }; class AudioEffectRecord : public AudioEffect { @@ -78,10 +80,14 @@ class AudioEffectRecord : public AudioEffect { IO_BUFFER_SIZE_MS = 1500 }; + HashMap> channel_instances; Ref current_instance; + int active_channel = 0; AudioStreamWAV::Format format; + void set_current_instance(Ref p_instance); + void register_channel_instance(int p_channel, Ref p_instance); void ensure_thread_stopped(); protected: @@ -93,6 +99,8 @@ class AudioEffectRecord : public AudioEffect { bool is_recording_active() const; void set_format(AudioStreamWAV::Format p_format); AudioStreamWAV::Format get_format() const; + void set_active_channel(int p_channel); + int get_active_channel() const; Ref get_recording() const; AudioEffectRecord(); ~AudioEffectRecord(); diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index d37836ed9609..e6fa3ed27838 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -1006,9 +1006,7 @@ void AudioServer::_update_bus_effects(int p_bus) { buses.write[p_bus]->channels.write[i].effect_instances.resize(buses[p_bus]->effects.size()); for (int j = 0; j < buses[p_bus]->effects.size(); j++) { Ref fx = buses.write[p_bus]->effects.write[j].effect->instantiate(); - if (Object::cast_to(*fx)) { - Object::cast_to(*fx)->set_current_channel(i); - } + fx->set_current_channel(i); buses.write[p_bus]->channels.write[i].effect_instances.write[j] = fx; } }