AME
ame_Reverb.hpp
Go to the documentation of this file.
1
10#pragma once
11
12#include "ame_AudioBuffer.hpp"
13#include "ame_Util.hpp"
14
15#include <array>
16#include <cassert>
17#include <concepts>
18#include <cstdint>
19#include <type_traits>
20
21namespace ame::dsp
22{
27template <std::floating_point FloatType, size_t MaximumChannels, size_t MaximumSampleRate>
29{
30 static_assert (! std::is_const<FloatType>::value, "FloatType is must NOT be const.");
31
32public:
33 explicit Freeverb (FloatType sampleRate)
34 {
35 setSampleRate (sampleRate);
36 setRoomSize (0.5f, 0.5f);
37 }
38 ~Freeverb() = default;
39
44 void setRoomSize (FloatType roomSize, FloatType damp) noexcept
45 {
46 static constexpr FloatType roomScaleFactor = 0.28f;
47 static constexpr FloatType roomOffset = 0.7f;
48 static constexpr FloatType dampScaleFactor = 0.4f;
49 damping = damp * dampScaleFactor;
50 feedback = roomSize * roomScaleFactor + roomOffset;
51 }
52
56 void setSampleRate (FloatType sampleRate)
57 {
58 assert (0 < sampleRate);
59 assert (sampleRate <= MaximumSampleRate);
60
61 static constexpr int_fast16_t combTunings[] = { 1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617 };
62 static constexpr int_fast16_t allPassTunings[] = { 556, 441, 341, 225 };
63 static const FloatType sampleRateRatio = sampleRate / 44100.0f;
64
65 for (int i = 0; i < numCombs; ++i)
66 {
67 comb[0][i].setSize (std::round (combTunings[i] * sampleRateRatio));
68 comb[1][i].setSize (std::round ((combTunings[i] + stereoSpread) * sampleRateRatio));
69 }
70
71 for (int i = 0; i < numAllPasses; ++i)
72 {
73 allPass[0][i].setSize (std::round (allPassTunings[i] * sampleRateRatio));
74 allPass[1][i].setSize (std::round ((allPassTunings[i] + stereoSpread) * sampleRateRatio));
75 }
76
77 const int_fast16_t smoothSteps = static_cast<int_fast16_t> (sampleRate * 0.01f); //10ms
78 dryWet.setRampLength (smoothSteps);
79 }
80
84 void setDryWet (FloatType mix)
85 {
86 dryWet.setTargetValue (mix);
87 }
88
90 void reset()
91 {
92 for (int ch = 0; ch < MaximumChannels; ++ch)
93 {
94 for (int i = 0; i < numCombs; ++i)
95 {
96 comb[ch][i].clear();
97 }
98
99 for (int i = 0; i < numAllPasses; ++i)
100 {
101 allPass[ch][i].clear();
102 }
103 }
104 }
105
106 //==============================================================================
108 template <size_t N>
110 {
111 const uint_fast32_t numChannels = block.getNumChannels();
112 const uint_fast32_t bufferSize = block.getNumSamplesPerChannel();
113 assert (numChannels <= MaximumChannels);
114
115 block.applyGain (inputGain);
116
117 uint_fast32_t i = 0;
118 for (uint_fast32_t samp = 0; samp < bufferSize; ++samp)
119 {
120 const FloatType mix = dryWet.getNextValue();
121 for (uint_fast32_t ch = 0; ch < numChannels; ++ch)
122 {
123 const FloatType input = block.view[i];
124 FloatType output = 0.0f;
125
126 for (int cmb = 0; cmb < numCombs; ++cmb) //accumulate the comb filters in parallel
127 {
128 output += comb[ch][cmb].process (input, damping, feedback);
129 }
130
131 for (int ap = 0; ap < numAllPasses; ++ap) // run the all-pass filters in series
132 {
133 output = allPass[ch][ap].process (output);
134 }
135 block.view[i] = std::lerp (input, output, mix);
136 ++i;
137 }
138 }
139 }
140
141private:
142 static constexpr int stereoSpread = 23;
143 static constexpr FloatType inputGain = 0.06f;
144 static constexpr int numCombs = 8;
145 static constexpr int numAllPasses = 4;
146
147 class CombFilter
148 {
149 public:
150 CombFilter() noexcept {}
151
152 void setSize (const int size)
153 {
154 assert (size <= buffer.size());
155 bufferIndex.changeLength (size);
156 bufferIndex.set (0);
157 clear();
158 }
159
160 void clear() noexcept
161 {
162 last = 0;
163 buffer.fill (0.0f);
164 }
165
166 FloatType process (FloatType input, FloatType damp, FloatType feedbackLevel) noexcept
167 {
168 const auto ind = bufferIndex.get();
169 const FloatType output = buffer[ind];
170 last = (output * (1.0f - damp)) + (last * damp);
171 buffer[ind] = input + (last * feedbackLevel);
172 bufferIndex++;
173 return output;
174 }
175
176 private:
177 static constexpr int bufferAllocatedSize = (1617 + stereoSpread) * (MaximumSampleRate / 44100.0f);
178 std::array<FloatType, bufferAllocatedSize> buffer {};
179 ame::Wrap<int> bufferIndex { bufferAllocatedSize };
180 FloatType last {};
181 };
182
183 //==============================================================================
184 class AllPassFilter
185 {
186 public:
187 AllPassFilter() noexcept {}
188
189 void setSize (const int size)
190 {
191 bufferIndex.changeLength (size);
192 bufferIndex.set (0);
193 clear();
194 }
195
196 void clear() noexcept
197 {
198 buffer.fill (0.0f);
199 }
200
201 FloatType process (FloatType input) noexcept
202 {
203 const auto ind = bufferIndex.get();
204 const FloatType bufferedValue = buffer[ind];
205 buffer[ind] = input + (bufferedValue * 0.5f);
206 bufferIndex++;
207 return bufferedValue - input;
208 }
209
210 private:
211 static constexpr int bufferAllocatedSize = (556 + stereoSpread) * (MaximumSampleRate / 44100.0f);
212 std::array<FloatType, bufferAllocatedSize> buffer;
213 ame::Wrap<int> bufferIndex { bufferAllocatedSize };
214 };
215
216 CombFilter comb[MaximumChannels][numCombs] {};
217 AllPassFilter allPass[MaximumChannels][numAllPasses] {};
218 LinearSmoothedValue<FloatType> dryWet { 0.5f, 100 };
219 FloatType damping {};
220 FloatType feedback {};
221};
222} // namespace ame::dsp
Audio buffer.
Some utilities functions.
A lightweight data structure that stores a pointer to an audio buffer.
Definition: ame_AudioBuffer.hpp:32
uint_fast32_t getNumChannels() const noexcept
Returns the number of channels.
Definition: ame_AudioBuffer.hpp:49
void applyGain(const float gain)
Applies a gain multiple to all the audio data.
Definition: ame_AudioBuffer.hpp:91
uint_fast32_t getNumSamplesPerChannel() const noexcept
Returns the number of samples per channel.
Definition: ame_AudioBuffer.hpp:55
A number to wrap between 0~length.
Definition: ame_Util.hpp:254
void changeLength(T newLength) noexcept
The number to automatically wrap in the range [0, length-1].
Definition: ame_Util.hpp:308
Reverb.
Definition: ame_Reverb.hpp:29
void setSampleRate(FloatType sampleRate)
Sets the sample rate that will be used for the reverb.
Definition: ame_Reverb.hpp:56
void process(AudioBlockView< FloatType, N > block)
Applies the reverb to two stereo channels of audio data.
Definition: ame_Reverb.hpp:109
void setDryWet(FloatType mix)
Dry/Wet balance.
Definition: ame_Reverb.hpp:84
void setRoomSize(FloatType roomSize, FloatType damp) noexcept
Room size and damping.
Definition: ame_Reverb.hpp:44
void reset()
Clears the reverb's buffers.
Definition: ame_Reverb.hpp:90