From 90019676b076abdfc076ed6f38005d6cce89923b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Sat, 23 Jul 2022 23:41:51 +0200 Subject: Code quality: Fix header guards consistency Adds `header_guards.sh` bash script, used in CI to validate future changes. Can be run locally to fix invalid header guards. --- servers/audio/audio_driver_dummy.h | 2 +- servers/audio/audio_effect.h | 6 +- servers/audio/effects/audio_effect_amplify.h | 6 +- servers/audio/effects/audio_effect_chorus.h | 6 +- servers/audio/effects/audio_effect_compressor.h | 6 +- servers/audio/effects/audio_effect_delay.h | 6 +- servers/audio/effects/audio_effect_distortion.h | 6 +- servers/audio/effects/audio_effect_eq.cpp | 1 + servers/audio/effects/audio_effect_eq.h | 8 +- servers/audio/effects/audio_effect_filter.h | 6 +- servers/audio/effects/audio_effect_panner.h | 6 +- servers/audio/effects/audio_effect_record.h | 6 +- servers/audio/effects/audio_effect_reverb.h | 8 +- servers/audio/effects/audio_stream_generator.h | 1 + servers/audio/effects/eq.cpp | 203 -------------- servers/audio/effects/eq.h | 102 ------- servers/audio/effects/eq_filter.cpp | 203 ++++++++++++++ servers/audio/effects/eq_filter.h | 102 +++++++ servers/audio/effects/reverb.cpp | 341 ------------------------ servers/audio/effects/reverb.h | 122 --------- servers/audio/effects/reverb_filter.cpp | 341 ++++++++++++++++++++++++ servers/audio/effects/reverb_filter.h | 122 +++++++++ 22 files changed, 806 insertions(+), 804 deletions(-) delete mode 100644 servers/audio/effects/eq.cpp delete mode 100644 servers/audio/effects/eq.h create mode 100644 servers/audio/effects/eq_filter.cpp create mode 100644 servers/audio/effects/eq_filter.h delete mode 100644 servers/audio/effects/reverb.cpp delete mode 100644 servers/audio/effects/reverb.h create mode 100644 servers/audio/effects/reverb_filter.cpp create mode 100644 servers/audio/effects/reverb_filter.h (limited to 'servers/audio') diff --git a/servers/audio/audio_driver_dummy.h b/servers/audio/audio_driver_dummy.h index 232a8d5e1f..8f47e64d8b 100644 --- a/servers/audio/audio_driver_dummy.h +++ b/servers/audio/audio_driver_dummy.h @@ -85,4 +85,4 @@ public: ~AudioDriverDummy() {} }; -#endif +#endif // AUDIO_DRIVER_DUMMY_H diff --git a/servers/audio/audio_effect.h b/servers/audio/audio_effect.h index 3a0578679d..653d04595e 100644 --- a/servers/audio/audio_effect.h +++ b/servers/audio/audio_effect.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef AUDIOEFFECT_H -#define AUDIOEFFECT_H +#ifndef AUDIO_EFFECT_H +#define AUDIO_EFFECT_H #include "core/io/resource.h" #include "core/math/audio_frame.h" @@ -62,4 +62,4 @@ public: AudioEffect(); }; -#endif // AUDIOEFFECT_H +#endif // AUDIO_EFFECT_H diff --git a/servers/audio/effects/audio_effect_amplify.h b/servers/audio/effects/audio_effect_amplify.h index bd0fcaa94d..fd424cbe9a 100644 --- a/servers/audio/effects/audio_effect_amplify.h +++ b/servers/audio/effects/audio_effect_amplify.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef AUDIOEFFECTAMPLIFY_H -#define AUDIOEFFECTAMPLIFY_H +#ifndef AUDIO_EFFECT_AMPLIFY_H +#define AUDIO_EFFECT_AMPLIFY_H #include "servers/audio/audio_effect.h" @@ -63,4 +63,4 @@ public: AudioEffectAmplify(); }; -#endif // AUDIOEFFECTAMPLIFY_H +#endif // AUDIO_EFFECT_AMPLIFY_H diff --git a/servers/audio/effects/audio_effect_chorus.h b/servers/audio/effects/audio_effect_chorus.h index 19035222c5..72b495f7f9 100644 --- a/servers/audio/effects/audio_effect_chorus.h +++ b/servers/audio/effects/audio_effect_chorus.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef AUDIOEFFECTCHORUS_H -#define AUDIOEFFECTCHORUS_H +#ifndef AUDIO_EFFECT_CHORUS_H +#define AUDIO_EFFECT_CHORUS_H #include "servers/audio/audio_effect.h" @@ -133,4 +133,4 @@ public: AudioEffectChorus(); }; -#endif // AUDIOEFFECTCHORUS_H +#endif // AUDIO_EFFECT_CHORUS_H diff --git a/servers/audio/effects/audio_effect_compressor.h b/servers/audio/effects/audio_effect_compressor.h index 53c448e5db..998bd3c978 100644 --- a/servers/audio/effects/audio_effect_compressor.h +++ b/servers/audio/effects/audio_effect_compressor.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef AUDIOEFFECTCOMPRESSOR_H -#define AUDIOEFFECTCOMPRESSOR_H +#ifndef AUDIO_EFFECT_COMPRESSOR_H +#define AUDIO_EFFECT_COMPRESSOR_H #include "servers/audio/audio_effect.h" @@ -91,4 +91,4 @@ public: AudioEffectCompressor(); }; -#endif // AUDIOEFFECTCOMPRESSOR_H +#endif // AUDIO_EFFECT_COMPRESSOR_H diff --git a/servers/audio/effects/audio_effect_delay.h b/servers/audio/effects/audio_effect_delay.h index 5cc6d72c99..137a4e7dbe 100644 --- a/servers/audio/effects/audio_effect_delay.h +++ b/servers/audio/effects/audio_effect_delay.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef AUDIOEFFECTDELAY_H -#define AUDIOEFFECTDELAY_H +#ifndef AUDIO_EFFECT_DELAY_H +#define AUDIO_EFFECT_DELAY_H #include "servers/audio/audio_effect.h" @@ -131,4 +131,4 @@ public: AudioEffectDelay(); }; -#endif // AUDIOEFFECTDELAY_H +#endif // AUDIO_EFFECT_DELAY_H diff --git a/servers/audio/effects/audio_effect_distortion.h b/servers/audio/effects/audio_effect_distortion.h index 487babbdda..c845a0e53c 100644 --- a/servers/audio/effects/audio_effect_distortion.h +++ b/servers/audio/effects/audio_effect_distortion.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef AUDIOEFFECTDISTORTION_H -#define AUDIOEFFECTDISTORTION_H +#ifndef AUDIO_EFFECT_DISTORTION_H +#define AUDIO_EFFECT_DISTORTION_H #include "servers/audio/audio_effect.h" @@ -90,4 +90,4 @@ public: VARIANT_ENUM_CAST(AudioEffectDistortion::Mode) -#endif // AUDIOEFFECTDISTORTION_H +#endif // AUDIO_EFFECT_DISTORTION_H diff --git a/servers/audio/effects/audio_effect_eq.cpp b/servers/audio/effects/audio_effect_eq.cpp index b7c373479a..500abd3a6f 100644 --- a/servers/audio/effects/audio_effect_eq.cpp +++ b/servers/audio/effects/audio_effect_eq.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "audio_effect_eq.h" + #include "servers/audio_server.h" void AudioEffectEQInstance::process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) { diff --git a/servers/audio/effects/audio_effect_eq.h b/servers/audio/effects/audio_effect_eq.h index 9b0560223f..b80fb7c73c 100644 --- a/servers/audio/effects/audio_effect_eq.h +++ b/servers/audio/effects/audio_effect_eq.h @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef AUDIOEFFECTEQ_H -#define AUDIOEFFECTEQ_H +#ifndef AUDIO_EFFECT_EQ_H +#define AUDIO_EFFECT_EQ_H #include "servers/audio/audio_effect.h" -#include "servers/audio/effects/eq.h" +#include "servers/audio/effects/eq_filter.h" class AudioEffectEQ; @@ -98,4 +98,4 @@ public: AudioEffectEQ(EQ::PRESET_21_BANDS) {} }; -#endif // AUDIOEFFECTEQ_H +#endif // AUDIO_EFFECT_EQ_H diff --git a/servers/audio/effects/audio_effect_filter.h b/servers/audio/effects/audio_effect_filter.h index d5d58ddaa3..a40af2f13c 100644 --- a/servers/audio/effects/audio_effect_filter.h +++ b/servers/audio/effects/audio_effect_filter.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef AUDIOEFFECTFILTER_H -#define AUDIOEFFECTFILTER_H +#ifndef AUDIO_EFFECT_FILTER_H +#define AUDIO_EFFECT_FILTER_H #include "servers/audio/audio_effect.h" #include "servers/audio/audio_filter_sw.h" @@ -167,4 +167,4 @@ public: AudioEffectFilter(AudioFilterSW::HIGHSHELF) {} }; -#endif // AUDIOEFFECTFILTER_H +#endif // AUDIO_EFFECT_FILTER_H diff --git a/servers/audio/effects/audio_effect_panner.h b/servers/audio/effects/audio_effect_panner.h index d05c9902af..3eca71a926 100644 --- a/servers/audio/effects/audio_effect_panner.h +++ b/servers/audio/effects/audio_effect_panner.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef AUDIOEFFECTPANNER_H -#define AUDIOEFFECTPANNER_H +#ifndef AUDIO_EFFECT_PANNER_H +#define AUDIO_EFFECT_PANNER_H #include "servers/audio/audio_effect.h" @@ -61,4 +61,4 @@ public: AudioEffectPanner(); }; -#endif // AUDIOEFFECTPANNER_H +#endif // AUDIO_EFFECT_PANNER_H diff --git a/servers/audio/effects/audio_effect_record.h b/servers/audio/effects/audio_effect_record.h index 8a6247e27a..b23b63dbd8 100644 --- a/servers/audio/effects/audio_effect_record.h +++ b/servers/audio/effects/audio_effect_record.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef AUDIOEFFECTRECORD_H -#define AUDIOEFFECTRECORD_H +#ifndef AUDIO_EFFECT_RECORD_H +#define AUDIO_EFFECT_RECORD_H #include "core/io/file_access.h" #include "core/io/marshalls.h" @@ -103,4 +103,4 @@ public: AudioEffectRecord(); }; -#endif // AUDIOEFFECTRECORD_H +#endif // AUDIO_EFFECT_RECORD_H diff --git a/servers/audio/effects/audio_effect_reverb.h b/servers/audio/effects/audio_effect_reverb.h index 90694c5492..a2c1fc5ea5 100644 --- a/servers/audio/effects/audio_effect_reverb.h +++ b/servers/audio/effects/audio_effect_reverb.h @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef AUDIOEFFECTREVERB_H -#define AUDIOEFFECTREVERB_H +#ifndef AUDIO_EFFECT_REVERB_H +#define AUDIO_EFFECT_REVERB_H #include "servers/audio/audio_effect.h" -#include "servers/audio/effects/reverb.h" +#include "servers/audio/effects/reverb_filter.h" class AudioEffectReverb; @@ -94,4 +94,4 @@ public: AudioEffectReverb(); }; -#endif // AUDIOEFFECTREVERB_H +#endif // AUDIO_EFFECT_REVERB_H diff --git a/servers/audio/effects/audio_stream_generator.h b/servers/audio/effects/audio_stream_generator.h index 0394c3c6a9..a0bed0fda5 100644 --- a/servers/audio/effects/audio_stream_generator.h +++ b/servers/audio/effects/audio_stream_generator.h @@ -95,4 +95,5 @@ public: AudioStreamGeneratorPlayback(); }; + #endif // AUDIO_STREAM_GENERATOR_H diff --git a/servers/audio/effects/eq.cpp b/servers/audio/effects/eq.cpp deleted file mode 100644 index 2123284b3b..0000000000 --- a/servers/audio/effects/eq.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/*************************************************************************/ -/* eq.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -// Author: reduzio@gmail.com (C) 2006 - -#include "eq.h" -#include "core/error/error_macros.h" -#include "core/math/math_funcs.h" -#include - -#define POW2(v) ((v) * (v)) - -/* Helper */ -static int solve_quadratic(double a, double b, double c, double *r1, double *r2) { - //solves quadractic and returns number of roots - - double base = 2 * a; - if (base == 0.0f) { - return 0; - } - - double squared = b * b - 4 * a * c; - if (squared < 0.0) { - return 0; - } - - squared = sqrt(squared); - - *r1 = (-b + squared) / base; - *r2 = (-b - squared) / base; - - if (*r1 == *r2) { - return 1; - } else { - return 2; - } -} - -EQ::BandProcess::BandProcess() { - c1 = c2 = c3 = history.a1 = history.a2 = history.a3 = 0; - history.b1 = history.b2 = history.b3 = 0; -} - -void EQ::recalculate_band_coefficients() { -#define BAND_LOG(m_f) (log((m_f)) / log(2.)) - - for (int i = 0; i < band.size(); i++) { - double octave_size; - - double frq = band[i].freq; - - if (i == 0) { - octave_size = BAND_LOG(band[1].freq) - BAND_LOG(frq); - } else if (i == (band.size() - 1)) { - octave_size = BAND_LOG(frq) - BAND_LOG(band[i - 1].freq); - } else { - double next = BAND_LOG(band[i + 1].freq) - BAND_LOG(frq); - double prev = BAND_LOG(frq) - BAND_LOG(band[i - 1].freq); - octave_size = (next + prev) / 2.0; - } - - double frq_l = round(frq / pow(2.0, octave_size / 2.0)); - - double side_gain2 = POW2(Math_SQRT12); - double th = Math_TAU * frq / mix_rate; - double th_l = Math_TAU * frq_l / mix_rate; - - double c2a = side_gain2 * POW2(cos(th)) - 2.0 * side_gain2 * cos(th_l) * cos(th) + side_gain2 - POW2(sin(th_l)); - - double c2b = 2.0 * side_gain2 * POW2(cos(th_l)) + side_gain2 * POW2(cos(th)) - 2.0 * side_gain2 * cos(th_l) * cos(th) - side_gain2 + POW2(sin(th_l)); - - double c2c = 0.25 * side_gain2 * POW2(cos(th)) - 0.5 * side_gain2 * cos(th_l) * cos(th) + 0.25 * side_gain2 - 0.25 * POW2(sin(th_l)); - - //printf("band %i, precoefs = %f,%f,%f\n",i,c2a,c2b,c2c); - - // Default initializing to silence compiler warning about potential uninitialized use. - // Both variables are properly set in _solve_quadratic before use, or we continue if roots == 0. - double r1 = 0, r2 = 0; //roots - int roots = solve_quadratic(c2a, c2b, c2c, &r1, &r2); - - ERR_CONTINUE(roots == 0); - - band.write[i].c1 = 2.0 * ((0.5 - r1) / 2.0); - band.write[i].c2 = 2.0 * r1; - band.write[i].c3 = 2.0 * (0.5 + r1) * cos(th); - //printf("band %i, coefs = %f,%f,%f\n",i,(float)bands[i].c1,(float)bands[i].c2,(float)bands[i].c3); - } -} - -void EQ::set_preset_band_mode(Preset p_preset) { - band.clear(); - -#define PUSH_BANDS(m_bands) \ - for (int i = 0; i < m_bands; i++) { \ - Band b; \ - b.freq = bands[i]; \ - b.c1 = b.c2 = b.c3 = 0; \ - band.push_back(b); \ - } - - switch (p_preset) { - case PRESET_6_BANDS: { - static const double bands[] = { 32, 100, 320, 1e3, 3200, 10e3 }; - PUSH_BANDS(6); - - } break; - - case PRESET_8_BANDS: { - static const double bands[] = { 32, 72, 192, 512, 1200, 3000, 7500, 16e3 }; - - PUSH_BANDS(8); - } break; - - case PRESET_10_BANDS: { - static const double bands[] = { 31.25, 62.5, 125, 250, 500, 1e3, 2e3, 4e3, 8e3, 16e3 }; - - PUSH_BANDS(10); - - } break; - - case PRESET_21_BANDS: { - static const double bands[] = { 22, 32, 44, 63, 90, 125, 175, 250, 350, 500, 700, 1e3, 1400, 2e3, 2800, 4e3, 5600, 8e3, 11e3, 16e3, 22e3 }; - PUSH_BANDS(21); - - } break; - - case PRESET_31_BANDS: { - static const double bands[] = { 20, 25, 31.5, 40, 50, 63, 80, 100, 125, 160, 200, 250, 315, 400, 500, 630, 800, 1e3, 1250, 1600, 2e3, 2500, 3150, 4e3, 5e3, 6300, 8e3, 10e3, 12500, 16e3, 20e3 }; - PUSH_BANDS(31); - } break; - }; - - recalculate_band_coefficients(); -} - -int EQ::get_band_count() const { - return band.size(); -} - -float EQ::get_band_frequency(int p_band) { - ERR_FAIL_INDEX_V(p_band, band.size(), 0); - return band[p_band].freq; -} - -void EQ::set_bands(const Vector &p_bands) { - band.resize(p_bands.size()); - for (int i = 0; i < p_bands.size(); i++) { - band.write[i].freq = p_bands[i]; - } - - recalculate_band_coefficients(); -} - -void EQ::set_mix_rate(float p_mix_rate) { - mix_rate = p_mix_rate; - recalculate_band_coefficients(); -} - -EQ::BandProcess EQ::get_band_processor(int p_band) const { - EQ::BandProcess band_proc; - - ERR_FAIL_INDEX_V(p_band, band.size(), band_proc); - - band_proc.c1 = band[p_band].c1; - band_proc.c2 = band[p_band].c2; - band_proc.c3 = band[p_band].c3; - - return band_proc; -} - -EQ::EQ() { - mix_rate = 44100; -} - -EQ::~EQ() { -} diff --git a/servers/audio/effects/eq.h b/servers/audio/effects/eq.h deleted file mode 100644 index d6293bf875..0000000000 --- a/servers/audio/effects/eq.h +++ /dev/null @@ -1,102 +0,0 @@ -/*************************************************************************/ -/* eq.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef EQ_FILTER_H -#define EQ_FILTER_H - -#include "core/templates/vector.h" -#include "core/typedefs.h" - -class EQ { -public: - enum Preset { - PRESET_6_BANDS, - PRESET_8_BANDS, - PRESET_10_BANDS, - PRESET_21_BANDS, - PRESET_31_BANDS - }; - - class BandProcess { - friend class EQ; - float c1, c2, c3; - struct History { - float a1, a2, a3; - float b1, b2, b3; - - } history; - - public: - inline void process_one(float &p_data); - - BandProcess(); - }; - -private: - struct Band { - float freq; - float c1, c2, c3; - }; - - Vector band; - - float mix_rate; - - void recalculate_band_coefficients(); - -public: - void set_mix_rate(float p_mix_rate); - - int get_band_count() const; - void set_preset_band_mode(Preset p_preset); - void set_bands(const Vector &p_bands); - BandProcess get_band_processor(int p_band) const; - float get_band_frequency(int p_band); - - EQ(); - ~EQ(); -}; - -/* Inline Function */ - -inline void EQ::BandProcess::process_one(float &p_data) { - history.a1 = p_data; - - history.b1 = c1 * (history.a1 - history.a3) + c3 * history.b2 - c2 * history.b3; - - p_data = history.b1; - - history.a3 = history.a2; - history.a2 = history.a1; - history.b3 = history.b2; - history.b2 = history.b1; -} - -#endif // EQ_FILTER_H diff --git a/servers/audio/effects/eq_filter.cpp b/servers/audio/effects/eq_filter.cpp new file mode 100644 index 0000000000..6807e81cc4 --- /dev/null +++ b/servers/audio/effects/eq_filter.cpp @@ -0,0 +1,203 @@ +/*************************************************************************/ +/* eq_filter.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "eq_filter.h" + +#include "core/error/error_macros.h" +#include "core/math/math_funcs.h" + +#include + +#define POW2(v) ((v) * (v)) + +/* Helper */ +static int solve_quadratic(double a, double b, double c, double *r1, double *r2) { + //solves quadractic and returns number of roots + + double base = 2 * a; + if (base == 0.0f) { + return 0; + } + + double squared = b * b - 4 * a * c; + if (squared < 0.0) { + return 0; + } + + squared = sqrt(squared); + + *r1 = (-b + squared) / base; + *r2 = (-b - squared) / base; + + if (*r1 == *r2) { + return 1; + } else { + return 2; + } +} + +EQ::BandProcess::BandProcess() { + c1 = c2 = c3 = history.a1 = history.a2 = history.a3 = 0; + history.b1 = history.b2 = history.b3 = 0; +} + +void EQ::recalculate_band_coefficients() { +#define BAND_LOG(m_f) (log((m_f)) / log(2.)) + + for (int i = 0; i < band.size(); i++) { + double octave_size; + + double frq = band[i].freq; + + if (i == 0) { + octave_size = BAND_LOG(band[1].freq) - BAND_LOG(frq); + } else if (i == (band.size() - 1)) { + octave_size = BAND_LOG(frq) - BAND_LOG(band[i - 1].freq); + } else { + double next = BAND_LOG(band[i + 1].freq) - BAND_LOG(frq); + double prev = BAND_LOG(frq) - BAND_LOG(band[i - 1].freq); + octave_size = (next + prev) / 2.0; + } + + double frq_l = round(frq / pow(2.0, octave_size / 2.0)); + + double side_gain2 = POW2(Math_SQRT12); + double th = Math_TAU * frq / mix_rate; + double th_l = Math_TAU * frq_l / mix_rate; + + double c2a = side_gain2 * POW2(cos(th)) - 2.0 * side_gain2 * cos(th_l) * cos(th) + side_gain2 - POW2(sin(th_l)); + + double c2b = 2.0 * side_gain2 * POW2(cos(th_l)) + side_gain2 * POW2(cos(th)) - 2.0 * side_gain2 * cos(th_l) * cos(th) - side_gain2 + POW2(sin(th_l)); + + double c2c = 0.25 * side_gain2 * POW2(cos(th)) - 0.5 * side_gain2 * cos(th_l) * cos(th) + 0.25 * side_gain2 - 0.25 * POW2(sin(th_l)); + + //printf("band %i, precoefs = %f,%f,%f\n",i,c2a,c2b,c2c); + + // Default initializing to silence compiler warning about potential uninitialized use. + // Both variables are properly set in _solve_quadratic before use, or we continue if roots == 0. + double r1 = 0, r2 = 0; //roots + int roots = solve_quadratic(c2a, c2b, c2c, &r1, &r2); + + ERR_CONTINUE(roots == 0); + + band.write[i].c1 = 2.0 * ((0.5 - r1) / 2.0); + band.write[i].c2 = 2.0 * r1; + band.write[i].c3 = 2.0 * (0.5 + r1) * cos(th); + //printf("band %i, coefs = %f,%f,%f\n",i,(float)bands[i].c1,(float)bands[i].c2,(float)bands[i].c3); + } +} + +void EQ::set_preset_band_mode(Preset p_preset) { + band.clear(); + +#define PUSH_BANDS(m_bands) \ + for (int i = 0; i < m_bands; i++) { \ + Band b; \ + b.freq = bands[i]; \ + b.c1 = b.c2 = b.c3 = 0; \ + band.push_back(b); \ + } + + switch (p_preset) { + case PRESET_6_BANDS: { + static const double bands[] = { 32, 100, 320, 1e3, 3200, 10e3 }; + PUSH_BANDS(6); + + } break; + + case PRESET_8_BANDS: { + static const double bands[] = { 32, 72, 192, 512, 1200, 3000, 7500, 16e3 }; + + PUSH_BANDS(8); + } break; + + case PRESET_10_BANDS: { + static const double bands[] = { 31.25, 62.5, 125, 250, 500, 1e3, 2e3, 4e3, 8e3, 16e3 }; + + PUSH_BANDS(10); + + } break; + + case PRESET_21_BANDS: { + static const double bands[] = { 22, 32, 44, 63, 90, 125, 175, 250, 350, 500, 700, 1e3, 1400, 2e3, 2800, 4e3, 5600, 8e3, 11e3, 16e3, 22e3 }; + PUSH_BANDS(21); + + } break; + + case PRESET_31_BANDS: { + static const double bands[] = { 20, 25, 31.5, 40, 50, 63, 80, 100, 125, 160, 200, 250, 315, 400, 500, 630, 800, 1e3, 1250, 1600, 2e3, 2500, 3150, 4e3, 5e3, 6300, 8e3, 10e3, 12500, 16e3, 20e3 }; + PUSH_BANDS(31); + } break; + }; + + recalculate_band_coefficients(); +} + +int EQ::get_band_count() const { + return band.size(); +} + +float EQ::get_band_frequency(int p_band) { + ERR_FAIL_INDEX_V(p_band, band.size(), 0); + return band[p_band].freq; +} + +void EQ::set_bands(const Vector &p_bands) { + band.resize(p_bands.size()); + for (int i = 0; i < p_bands.size(); i++) { + band.write[i].freq = p_bands[i]; + } + + recalculate_band_coefficients(); +} + +void EQ::set_mix_rate(float p_mix_rate) { + mix_rate = p_mix_rate; + recalculate_band_coefficients(); +} + +EQ::BandProcess EQ::get_band_processor(int p_band) const { + EQ::BandProcess band_proc; + + ERR_FAIL_INDEX_V(p_band, band.size(), band_proc); + + band_proc.c1 = band[p_band].c1; + band_proc.c2 = band[p_band].c2; + band_proc.c3 = band[p_band].c3; + + return band_proc; +} + +EQ::EQ() { + mix_rate = 44100; +} + +EQ::~EQ() { +} diff --git a/servers/audio/effects/eq_filter.h b/servers/audio/effects/eq_filter.h new file mode 100644 index 0000000000..9dcad4dcea --- /dev/null +++ b/servers/audio/effects/eq_filter.h @@ -0,0 +1,102 @@ +/*************************************************************************/ +/* eq_filter.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef EQ_FILTER_H +#define EQ_FILTER_H + +#include "core/templates/vector.h" +#include "core/typedefs.h" + +class EQ { +public: + enum Preset { + PRESET_6_BANDS, + PRESET_8_BANDS, + PRESET_10_BANDS, + PRESET_21_BANDS, + PRESET_31_BANDS + }; + + class BandProcess { + friend class EQ; + float c1, c2, c3; + struct History { + float a1, a2, a3; + float b1, b2, b3; + + } history; + + public: + inline void process_one(float &p_data); + + BandProcess(); + }; + +private: + struct Band { + float freq; + float c1, c2, c3; + }; + + Vector band; + + float mix_rate; + + void recalculate_band_coefficients(); + +public: + void set_mix_rate(float p_mix_rate); + + int get_band_count() const; + void set_preset_band_mode(Preset p_preset); + void set_bands(const Vector &p_bands); + BandProcess get_band_processor(int p_band) const; + float get_band_frequency(int p_band); + + EQ(); + ~EQ(); +}; + +/* Inline Function */ + +inline void EQ::BandProcess::process_one(float &p_data) { + history.a1 = p_data; + + history.b1 = c1 * (history.a1 - history.a3) + c3 * history.b2 - c2 * history.b3; + + p_data = history.b1; + + history.a3 = history.a2; + history.a2 = history.a1; + history.b3 = history.b2; + history.b2 = history.b1; +} + +#endif // EQ_FILTER_H diff --git a/servers/audio/effects/reverb.cpp b/servers/audio/effects/reverb.cpp deleted file mode 100644 index adfd648514..0000000000 --- a/servers/audio/effects/reverb.cpp +++ /dev/null @@ -1,341 +0,0 @@ -/*************************************************************************/ -/* reverb.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "reverb.h" - -#include "core/math/math_funcs.h" - -#include - -const float Reverb::comb_tunings[MAX_COMBS] = { - //freeverb comb tunings - 0.025306122448979593f, - 0.026938775510204082f, - 0.028956916099773241f, - 0.03074829931972789f, - 0.032244897959183672f, - 0.03380952380952381f, - 0.035306122448979592f, - 0.036666666666666667f -}; - -const float Reverb::allpass_tunings[MAX_ALLPASS] = { - //freeverb allpass tunings - 0.0051020408163265302f, - 0.007732426303854875f, - 0.01f, - 0.012607709750566893f -}; - -void Reverb::process(float *p_src, float *p_dst, int p_frames) { - if (p_frames > INPUT_BUFFER_MAX_SIZE) { - p_frames = INPUT_BUFFER_MAX_SIZE; - } - - int predelay_frames = lrint((params.predelay / 1000.0) * params.mix_rate); - if (predelay_frames < 10) { - predelay_frames = 10; - } - if (predelay_frames >= echo_buffer_size) { - predelay_frames = echo_buffer_size - 1; - } - - for (int i = 0; i < p_frames; i++) { - if (echo_buffer_pos >= echo_buffer_size) { - echo_buffer_pos = 0; - } - - int read_pos = echo_buffer_pos - predelay_frames; - while (read_pos < 0) { - read_pos += echo_buffer_size; - } - - float in = undenormalise(echo_buffer[read_pos] * params.predelay_fb + p_src[i]); - - echo_buffer[echo_buffer_pos] = in; - - input_buffer[i] = in; - - p_dst[i] = 0; //take the chance and clear this - - echo_buffer_pos++; - } - - if (params.hpf > 0) { - float hpaux = expf(-Math_TAU * params.hpf * 6000 / params.mix_rate); - float hp_a1 = (1.0 + hpaux) / 2.0; - float hp_a2 = -(1.0 + hpaux) / 2.0; - float hp_b1 = hpaux; - - for (int i = 0; i < p_frames; i++) { - float in = input_buffer[i]; - input_buffer[i] = in * hp_a1 + hpf_h1 * hp_a2 + hpf_h2 * hp_b1; - hpf_h2 = input_buffer[i]; - hpf_h1 = in; - } - } - - for (int i = 0; i < MAX_COMBS; i++) { - Comb &c = comb[i]; - - int size_limit = c.size - lrintf((float)c.extra_spread_frames * (1.0 - params.extra_spread)); - for (int j = 0; j < p_frames; j++) { - if (c.pos >= size_limit) { //reset this now just in case - c.pos = 0; - } - - float out = undenormalise(c.buffer[c.pos] * c.feedback); - out = out * (1.0 - c.damp) + c.damp_h * c.damp; //lowpass - c.damp_h = out; - c.buffer[c.pos] = input_buffer[j] + out; - p_dst[j] += out; - c.pos++; - } - } - - static const float allpass_feedback = 0.7; - /* this one works, but the other version is just nicer.... - int ap_size_limit[MAX_ALLPASS]; - - for (int i=0;ipos>=ap_size_limit[m_ap]) \ - ap->pos=0; \ - aux=undenormalise(ap->buffer[ap->pos]); \ - in=sample; \ - sample=-in+aux; \ - ap->pos++; - - - PROCESS_ALLPASS(0); - PROCESS_ALLPASS(1); - PROCESS_ALLPASS(2); - PROCESS_ALLPASS(3); - - p_dst[i]=sample; - } - */ - - for (int i = 0; i < MAX_ALLPASS; i++) { - AllPass &a = allpass[i]; - int size_limit = a.size - lrintf((float)a.extra_spread_frames * (1.0 - params.extra_spread)); - - for (int j = 0; j < p_frames; j++) { - if (a.pos >= size_limit) { - a.pos = 0; - } - - float aux = a.buffer[a.pos]; - a.buffer[a.pos] = undenormalise(allpass_feedback * aux + p_dst[j]); - p_dst[j] = aux - allpass_feedback * a.buffer[a.pos]; - a.pos++; - } - } - - static const float wet_scale = 0.6; - - for (int i = 0; i < p_frames; i++) { - p_dst[i] = p_dst[i] * params.wet * wet_scale + p_src[i] * params.dry; - } -} - -void Reverb::set_room_size(float p_size) { - params.room_size = p_size; - update_parameters(); -} - -void Reverb::set_damp(float p_damp) { - params.damp = p_damp; - update_parameters(); -} - -void Reverb::set_wet(float p_wet) { - params.wet = p_wet; -} - -void Reverb::set_dry(float p_dry) { - params.dry = p_dry; -} - -void Reverb::set_predelay(float p_predelay) { - params.predelay = p_predelay; -} - -void Reverb::set_predelay_feedback(float p_predelay_fb) { - params.predelay_fb = p_predelay_fb; -} - -void Reverb::set_highpass(float p_frq) { - if (p_frq > 1) { - p_frq = 1; - } - if (p_frq < 0) { - p_frq = 0; - } - params.hpf = p_frq; -} - -void Reverb::set_extra_spread(float p_spread) { - params.extra_spread = p_spread; -} - -void Reverb::set_mix_rate(float p_mix_rate) { - params.mix_rate = p_mix_rate; - configure_buffers(); -} - -void Reverb::set_extra_spread_base(float p_sec) { - params.extra_spread_base = p_sec; - configure_buffers(); -} - -void Reverb::configure_buffers() { - clear_buffers(); //clear if necessary - - for (int i = 0; i < MAX_COMBS; i++) { - Comb &c = comb[i]; - - c.extra_spread_frames = lrint(params.extra_spread_base * params.mix_rate); - - int len = lrint(comb_tunings[i] * params.mix_rate) + c.extra_spread_frames; - if (len < 5) { - len = 5; //may this happen? - } - - c.buffer = memnew_arr(float, len); - c.pos = 0; - for (int j = 0; j < len; j++) { - c.buffer[j] = 0; - } - c.size = len; - } - - for (int i = 0; i < MAX_ALLPASS; i++) { - AllPass &a = allpass[i]; - - a.extra_spread_frames = lrint(params.extra_spread_base * params.mix_rate); - - int len = lrint(allpass_tunings[i] * params.mix_rate) + a.extra_spread_frames; - if (len < 5) { - len = 5; //may this happen? - } - - a.buffer = memnew_arr(float, len); - a.pos = 0; - for (int j = 0; j < len; j++) { - a.buffer[j] = 0; - } - a.size = len; - } - - echo_buffer_size = (int)(((float)MAX_ECHO_MS / 1000.0) * params.mix_rate + 1.0); - echo_buffer = memnew_arr(float, echo_buffer_size); - for (int i = 0; i < echo_buffer_size; i++) { - echo_buffer[i] = 0; - } - - echo_buffer_pos = 0; -} - -void Reverb::update_parameters() { - //more freeverb derived constants - static const float room_scale = 0.28f; - static const float room_offset = 0.7f; - - for (int i = 0; i < MAX_COMBS; i++) { - Comb &c = comb[i]; - c.feedback = room_offset + params.room_size * room_scale; - if (c.feedback < room_offset) { - c.feedback = room_offset; - } else if (c.feedback > (room_offset + room_scale)) { - c.feedback = (room_offset + room_scale); - } - - float auxdmp = params.damp / 2.0 + 0.5; //only half the range (0.5 .. 1.0 is enough) - auxdmp *= auxdmp; - - c.damp = expf(-Math_TAU * auxdmp * 10000 / params.mix_rate); // 0 .. 10khz - } -} - -void Reverb::clear_buffers() { - if (echo_buffer) { - memdelete_arr(echo_buffer); - } - - for (int i = 0; i < MAX_COMBS; i++) { - if (comb[i].buffer) { - memdelete_arr(comb[i].buffer); - } - - comb[i].buffer = nullptr; - } - - for (int i = 0; i < MAX_ALLPASS; i++) { - if (allpass[i].buffer) { - memdelete_arr(allpass[i].buffer); - } - - allpass[i].buffer = nullptr; - } -} - -Reverb::Reverb() { - params.room_size = 0.8; - params.damp = 0.5; - params.dry = 1.0; - params.wet = 0.0; - params.mix_rate = 44100; - params.extra_spread_base = 0; - params.extra_spread = 1.0; - params.predelay = 150; - params.predelay_fb = 0.4; - params.hpf = 0; - - input_buffer = memnew_arr(float, INPUT_BUFFER_MAX_SIZE); - - configure_buffers(); - update_parameters(); -} - -Reverb::~Reverb() { - memdelete_arr(input_buffer); - clear_buffers(); -} diff --git a/servers/audio/effects/reverb.h b/servers/audio/effects/reverb.h deleted file mode 100644 index c9602c5b5a..0000000000 --- a/servers/audio/effects/reverb.h +++ /dev/null @@ -1,122 +0,0 @@ -/*************************************************************************/ -/* reverb.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef REVERB_H -#define REVERB_H - -#include "core/math/audio_frame.h" -#include "core/os/memory.h" -#include "core/typedefs.h" - -class Reverb { -public: - enum { - INPUT_BUFFER_MAX_SIZE = 1024, - - }; - -private: - enum { - MAX_COMBS = 8, - MAX_ALLPASS = 4, - MAX_ECHO_MS = 500 - - }; - - static const float comb_tunings[MAX_COMBS]; - static const float allpass_tunings[MAX_ALLPASS]; - - struct Comb { - int size = 0; - float *buffer = nullptr; - float feedback = 0; - float damp = 0; //lowpass - float damp_h = 0; //history - int pos = 0; - int extra_spread_frames = 0; - - Comb() {} - }; - - struct AllPass { - int size = 0; - float *buffer = nullptr; - int pos = 0; - int extra_spread_frames = 0; - AllPass() {} - }; - - Comb comb[MAX_COMBS]; - AllPass allpass[MAX_ALLPASS]; - float *input_buffer = nullptr; - float *echo_buffer = nullptr; - int echo_buffer_size = 0; - int echo_buffer_pos = 0; - - float hpf_h1 = 0.0f; - float hpf_h2 = 0.0f; - - struct Parameters { - float room_size; - float damp; - float wet; - float dry; - float mix_rate; - float extra_spread_base; - float extra_spread; - float predelay; - float predelay_fb; - float hpf; - } params; - - void configure_buffers(); - void update_parameters(); - void clear_buffers(); - -public: - void set_room_size(float p_size); - void set_damp(float p_damp); - void set_wet(float p_wet); - void set_dry(float p_dry); - void set_predelay(float p_predelay); // in ms - void set_predelay_feedback(float p_predelay_fb); // in ms - void set_highpass(float p_frq); - void set_mix_rate(float p_mix_rate); - void set_extra_spread(float p_spread); - void set_extra_spread_base(float p_sec); - - void process(float *p_src, float *p_dst, int p_frames); - - Reverb(); - - ~Reverb(); -}; - -#endif // REVERB_H diff --git a/servers/audio/effects/reverb_filter.cpp b/servers/audio/effects/reverb_filter.cpp new file mode 100644 index 0000000000..0363706714 --- /dev/null +++ b/servers/audio/effects/reverb_filter.cpp @@ -0,0 +1,341 @@ +/*************************************************************************/ +/* reverb_filter.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "reverb_filter.h" + +#include "core/math/math_funcs.h" + +#include + +const float Reverb::comb_tunings[MAX_COMBS] = { + //freeverb comb tunings + 0.025306122448979593f, + 0.026938775510204082f, + 0.028956916099773241f, + 0.03074829931972789f, + 0.032244897959183672f, + 0.03380952380952381f, + 0.035306122448979592f, + 0.036666666666666667f +}; + +const float Reverb::allpass_tunings[MAX_ALLPASS] = { + //freeverb allpass tunings + 0.0051020408163265302f, + 0.007732426303854875f, + 0.01f, + 0.012607709750566893f +}; + +void Reverb::process(float *p_src, float *p_dst, int p_frames) { + if (p_frames > INPUT_BUFFER_MAX_SIZE) { + p_frames = INPUT_BUFFER_MAX_SIZE; + } + + int predelay_frames = lrint((params.predelay / 1000.0) * params.mix_rate); + if (predelay_frames < 10) { + predelay_frames = 10; + } + if (predelay_frames >= echo_buffer_size) { + predelay_frames = echo_buffer_size - 1; + } + + for (int i = 0; i < p_frames; i++) { + if (echo_buffer_pos >= echo_buffer_size) { + echo_buffer_pos = 0; + } + + int read_pos = echo_buffer_pos - predelay_frames; + while (read_pos < 0) { + read_pos += echo_buffer_size; + } + + float in = undenormalise(echo_buffer[read_pos] * params.predelay_fb + p_src[i]); + + echo_buffer[echo_buffer_pos] = in; + + input_buffer[i] = in; + + p_dst[i] = 0; //take the chance and clear this + + echo_buffer_pos++; + } + + if (params.hpf > 0) { + float hpaux = expf(-Math_TAU * params.hpf * 6000 / params.mix_rate); + float hp_a1 = (1.0 + hpaux) / 2.0; + float hp_a2 = -(1.0 + hpaux) / 2.0; + float hp_b1 = hpaux; + + for (int i = 0; i < p_frames; i++) { + float in = input_buffer[i]; + input_buffer[i] = in * hp_a1 + hpf_h1 * hp_a2 + hpf_h2 * hp_b1; + hpf_h2 = input_buffer[i]; + hpf_h1 = in; + } + } + + for (int i = 0; i < MAX_COMBS; i++) { + Comb &c = comb[i]; + + int size_limit = c.size - lrintf((float)c.extra_spread_frames * (1.0 - params.extra_spread)); + for (int j = 0; j < p_frames; j++) { + if (c.pos >= size_limit) { //reset this now just in case + c.pos = 0; + } + + float out = undenormalise(c.buffer[c.pos] * c.feedback); + out = out * (1.0 - c.damp) + c.damp_h * c.damp; //lowpass + c.damp_h = out; + c.buffer[c.pos] = input_buffer[j] + out; + p_dst[j] += out; + c.pos++; + } + } + + static const float allpass_feedback = 0.7; + /* this one works, but the other version is just nicer.... + int ap_size_limit[MAX_ALLPASS]; + + for (int i=0;ipos>=ap_size_limit[m_ap]) \ + ap->pos=0; \ + aux=undenormalise(ap->buffer[ap->pos]); \ + in=sample; \ + sample=-in+aux; \ + ap->pos++; + + + PROCESS_ALLPASS(0); + PROCESS_ALLPASS(1); + PROCESS_ALLPASS(2); + PROCESS_ALLPASS(3); + + p_dst[i]=sample; + } + */ + + for (int i = 0; i < MAX_ALLPASS; i++) { + AllPass &a = allpass[i]; + int size_limit = a.size - lrintf((float)a.extra_spread_frames * (1.0 - params.extra_spread)); + + for (int j = 0; j < p_frames; j++) { + if (a.pos >= size_limit) { + a.pos = 0; + } + + float aux = a.buffer[a.pos]; + a.buffer[a.pos] = undenormalise(allpass_feedback * aux + p_dst[j]); + p_dst[j] = aux - allpass_feedback * a.buffer[a.pos]; + a.pos++; + } + } + + static const float wet_scale = 0.6; + + for (int i = 0; i < p_frames; i++) { + p_dst[i] = p_dst[i] * params.wet * wet_scale + p_src[i] * params.dry; + } +} + +void Reverb::set_room_size(float p_size) { + params.room_size = p_size; + update_parameters(); +} + +void Reverb::set_damp(float p_damp) { + params.damp = p_damp; + update_parameters(); +} + +void Reverb::set_wet(float p_wet) { + params.wet = p_wet; +} + +void Reverb::set_dry(float p_dry) { + params.dry = p_dry; +} + +void Reverb::set_predelay(float p_predelay) { + params.predelay = p_predelay; +} + +void Reverb::set_predelay_feedback(float p_predelay_fb) { + params.predelay_fb = p_predelay_fb; +} + +void Reverb::set_highpass(float p_frq) { + if (p_frq > 1) { + p_frq = 1; + } + if (p_frq < 0) { + p_frq = 0; + } + params.hpf = p_frq; +} + +void Reverb::set_extra_spread(float p_spread) { + params.extra_spread = p_spread; +} + +void Reverb::set_mix_rate(float p_mix_rate) { + params.mix_rate = p_mix_rate; + configure_buffers(); +} + +void Reverb::set_extra_spread_base(float p_sec) { + params.extra_spread_base = p_sec; + configure_buffers(); +} + +void Reverb::configure_buffers() { + clear_buffers(); //clear if necessary + + for (int i = 0; i < MAX_COMBS; i++) { + Comb &c = comb[i]; + + c.extra_spread_frames = lrint(params.extra_spread_base * params.mix_rate); + + int len = lrint(comb_tunings[i] * params.mix_rate) + c.extra_spread_frames; + if (len < 5) { + len = 5; //may this happen? + } + + c.buffer = memnew_arr(float, len); + c.pos = 0; + for (int j = 0; j < len; j++) { + c.buffer[j] = 0; + } + c.size = len; + } + + for (int i = 0; i < MAX_ALLPASS; i++) { + AllPass &a = allpass[i]; + + a.extra_spread_frames = lrint(params.extra_spread_base * params.mix_rate); + + int len = lrint(allpass_tunings[i] * params.mix_rate) + a.extra_spread_frames; + if (len < 5) { + len = 5; //may this happen? + } + + a.buffer = memnew_arr(float, len); + a.pos = 0; + for (int j = 0; j < len; j++) { + a.buffer[j] = 0; + } + a.size = len; + } + + echo_buffer_size = (int)(((float)MAX_ECHO_MS / 1000.0) * params.mix_rate + 1.0); + echo_buffer = memnew_arr(float, echo_buffer_size); + for (int i = 0; i < echo_buffer_size; i++) { + echo_buffer[i] = 0; + } + + echo_buffer_pos = 0; +} + +void Reverb::update_parameters() { + //more freeverb derived constants + static const float room_scale = 0.28f; + static const float room_offset = 0.7f; + + for (int i = 0; i < MAX_COMBS; i++) { + Comb &c = comb[i]; + c.feedback = room_offset + params.room_size * room_scale; + if (c.feedback < room_offset) { + c.feedback = room_offset; + } else if (c.feedback > (room_offset + room_scale)) { + c.feedback = (room_offset + room_scale); + } + + float auxdmp = params.damp / 2.0 + 0.5; //only half the range (0.5 .. 1.0 is enough) + auxdmp *= auxdmp; + + c.damp = expf(-Math_TAU * auxdmp * 10000 / params.mix_rate); // 0 .. 10khz + } +} + +void Reverb::clear_buffers() { + if (echo_buffer) { + memdelete_arr(echo_buffer); + } + + for (int i = 0; i < MAX_COMBS; i++) { + if (comb[i].buffer) { + memdelete_arr(comb[i].buffer); + } + + comb[i].buffer = nullptr; + } + + for (int i = 0; i < MAX_ALLPASS; i++) { + if (allpass[i].buffer) { + memdelete_arr(allpass[i].buffer); + } + + allpass[i].buffer = nullptr; + } +} + +Reverb::Reverb() { + params.room_size = 0.8; + params.damp = 0.5; + params.dry = 1.0; + params.wet = 0.0; + params.mix_rate = 44100; + params.extra_spread_base = 0; + params.extra_spread = 1.0; + params.predelay = 150; + params.predelay_fb = 0.4; + params.hpf = 0; + + input_buffer = memnew_arr(float, INPUT_BUFFER_MAX_SIZE); + + configure_buffers(); + update_parameters(); +} + +Reverb::~Reverb() { + memdelete_arr(input_buffer); + clear_buffers(); +} diff --git a/servers/audio/effects/reverb_filter.h b/servers/audio/effects/reverb_filter.h new file mode 100644 index 0000000000..fe846fe2e7 --- /dev/null +++ b/servers/audio/effects/reverb_filter.h @@ -0,0 +1,122 @@ +/*************************************************************************/ +/* reverb_filter.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef REVERB_FILTER_H +#define REVERB_FILTER_H + +#include "core/math/audio_frame.h" +#include "core/os/memory.h" +#include "core/typedefs.h" + +class Reverb { +public: + enum { + INPUT_BUFFER_MAX_SIZE = 1024, + + }; + +private: + enum { + MAX_COMBS = 8, + MAX_ALLPASS = 4, + MAX_ECHO_MS = 500 + + }; + + static const float comb_tunings[MAX_COMBS]; + static const float allpass_tunings[MAX_ALLPASS]; + + struct Comb { + int size = 0; + float *buffer = nullptr; + float feedback = 0; + float damp = 0; //lowpass + float damp_h = 0; //history + int pos = 0; + int extra_spread_frames = 0; + + Comb() {} + }; + + struct AllPass { + int size = 0; + float *buffer = nullptr; + int pos = 0; + int extra_spread_frames = 0; + AllPass() {} + }; + + Comb comb[MAX_COMBS]; + AllPass allpass[MAX_ALLPASS]; + float *input_buffer = nullptr; + float *echo_buffer = nullptr; + int echo_buffer_size = 0; + int echo_buffer_pos = 0; + + float hpf_h1 = 0.0f; + float hpf_h2 = 0.0f; + + struct Parameters { + float room_size; + float damp; + float wet; + float dry; + float mix_rate; + float extra_spread_base; + float extra_spread; + float predelay; + float predelay_fb; + float hpf; + } params; + + void configure_buffers(); + void update_parameters(); + void clear_buffers(); + +public: + void set_room_size(float p_size); + void set_damp(float p_damp); + void set_wet(float p_wet); + void set_dry(float p_dry); + void set_predelay(float p_predelay); // in ms + void set_predelay_feedback(float p_predelay_fb); // in ms + void set_highpass(float p_frq); + void set_mix_rate(float p_mix_rate); + void set_extra_spread(float p_spread); + void set_extra_spread_base(float p_sec); + + void process(float *p_src, float *p_dst, int p_frames); + + Reverb(); + + ~Reverb(); +}; + +#endif // REVERB_FILTER_H -- cgit v1.2.3