1/**************************************************************************/
2/* audio_effect_filter.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_effect_filter.h"
32#include "servers/audio_server.h"
33
34template <int S>
35void AudioEffectFilterInstance::_process_filter(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) {
36 for (int i = 0; i < p_frame_count; i++) {
37 float f = p_src_frames[i].l;
38 filter_process[0][0].process_one(f);
39 if constexpr (S > 1) {
40 filter_process[0][1].process_one(f);
41 }
42 if constexpr (S > 2) {
43 filter_process[0][2].process_one(f);
44 }
45 if constexpr (S > 3) {
46 filter_process[0][3].process_one(f);
47 }
48
49 p_dst_frames[i].l = f;
50 }
51
52 for (int i = 0; i < p_frame_count; i++) {
53 float f = p_src_frames[i].r;
54 filter_process[1][0].process_one(f);
55 if constexpr (S > 1) {
56 filter_process[1][1].process_one(f);
57 }
58 if constexpr (S > 2) {
59 filter_process[1][2].process_one(f);
60 }
61 if constexpr (S > 3) {
62 filter_process[1][3].process_one(f);
63 }
64
65 p_dst_frames[i].r = f;
66 }
67}
68
69void AudioEffectFilterInstance::process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) {
70 filter.set_cutoff(base->cutoff);
71 filter.set_gain(base->gain);
72 filter.set_resonance(base->resonance);
73 filter.set_mode(base->mode);
74 int stages = int(base->db) + 1;
75 filter.set_stages(stages);
76 filter.set_sampling_rate(AudioServer::get_singleton()->get_mix_rate());
77
78 for (int i = 0; i < 2; i++) {
79 for (int j = 0; j < 4; j++) {
80 filter_process[i][j].update_coeffs();
81 }
82 }
83
84 if (stages == 1) {
85 _process_filter<1>(p_src_frames, p_dst_frames, p_frame_count);
86 } else if (stages == 2) {
87 _process_filter<2>(p_src_frames, p_dst_frames, p_frame_count);
88 } else if (stages == 3) {
89 _process_filter<3>(p_src_frames, p_dst_frames, p_frame_count);
90 } else if (stages == 4) {
91 _process_filter<4>(p_src_frames, p_dst_frames, p_frame_count);
92 }
93}
94
95AudioEffectFilterInstance::AudioEffectFilterInstance() {
96 for (int i = 0; i < 2; i++) {
97 for (int j = 0; j < 4; j++) {
98 filter_process[i][j].set_filter(&filter);
99 }
100 }
101}
102
103Ref<AudioEffectInstance> AudioEffectFilter::instantiate() {
104 Ref<AudioEffectFilterInstance> ins;
105 ins.instantiate();
106 ins->base = Ref<AudioEffectFilter>(this);
107
108 return ins;
109}
110
111void AudioEffectFilter::set_cutoff(float p_freq) {
112 cutoff = p_freq;
113}
114
115float AudioEffectFilter::get_cutoff() const {
116 return cutoff;
117}
118
119void AudioEffectFilter::set_resonance(float p_amount) {
120 resonance = p_amount;
121}
122
123float AudioEffectFilter::get_resonance() const {
124 return resonance;
125}
126
127void AudioEffectFilter::set_gain(float p_amount) {
128 gain = p_amount;
129}
130
131float AudioEffectFilter::get_gain() const {
132 return gain;
133}
134
135void AudioEffectFilter::set_db(FilterDB p_db) {
136 db = p_db;
137}
138
139AudioEffectFilter::FilterDB AudioEffectFilter::get_db() const {
140 return db;
141}
142
143void AudioEffectFilter::_bind_methods() {
144 ClassDB::bind_method(D_METHOD("set_cutoff", "freq"), &AudioEffectFilter::set_cutoff);
145 ClassDB::bind_method(D_METHOD("get_cutoff"), &AudioEffectFilter::get_cutoff);
146
147 ClassDB::bind_method(D_METHOD("set_resonance", "amount"), &AudioEffectFilter::set_resonance);
148 ClassDB::bind_method(D_METHOD("get_resonance"), &AudioEffectFilter::get_resonance);
149
150 ClassDB::bind_method(D_METHOD("set_gain", "amount"), &AudioEffectFilter::set_gain);
151 ClassDB::bind_method(D_METHOD("get_gain"), &AudioEffectFilter::get_gain);
152
153 ClassDB::bind_method(D_METHOD("set_db", "amount"), &AudioEffectFilter::set_db);
154 ClassDB::bind_method(D_METHOD("get_db"), &AudioEffectFilter::get_db);
155
156 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cutoff_hz", PROPERTY_HINT_RANGE, "1,20500,1,suffix:Hz"), "set_cutoff", "get_cutoff");
157 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "resonance", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_resonance", "get_resonance");
158 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gain", PROPERTY_HINT_RANGE, "0,4,0.01"), "set_gain", "get_gain");
159 ADD_PROPERTY(PropertyInfo(Variant::INT, "db", PROPERTY_HINT_ENUM, "6 dB,12 dB,18 dB,24 dB"), "set_db", "get_db");
160
161 BIND_ENUM_CONSTANT(FILTER_6DB);
162 BIND_ENUM_CONSTANT(FILTER_12DB);
163 BIND_ENUM_CONSTANT(FILTER_18DB);
164 BIND_ENUM_CONSTANT(FILTER_24DB);
165}
166
167AudioEffectFilter::AudioEffectFilter(AudioFilterSW::Mode p_mode) {
168 mode = p_mode;
169 cutoff = 2000;
170 resonance = 0.5;
171 gain = 1.0;
172 db = FILTER_6DB;
173}
174