Krotos Modules 3
Loading...
Searching...
No Matches
ConvolutionComputationThread.cpp
Go to the documentation of this file.
1namespace krotos
2{
3 class FloatBufferSource : public AudioSource
4 {
5 public:
6 explicit FloatBufferSource(const FloatBuffer::Ptr& sourceBuffer)
7 : juce::AudioSource(), m_sourceBuffer(sourceBuffer), m_pos(0)
8 {
9 }
10
11 virtual void prepareToPlay(int /*samplesPerBlockExpected*/, double /*sampleRate*/) { m_pos = 0; }
12
13 virtual void releaseResources() { m_pos = 0; }
14
15 virtual void getNextAudioBlock(const AudioSourceChannelInfo& bufferToFill)
16 {
17 AudioSampleBuffer* destBuffer = bufferToFill.buffer;
18 const int len = std::min(bufferToFill.numSamples, static_cast<int>(m_sourceBuffer->getSize() - m_pos));
19 if (destBuffer)
20 {
21 for (int channel = 0; channel < destBuffer->getNumChannels(); ++channel)
22 {
23 if (channel == 0 && m_sourceBuffer)
24 {
25 destBuffer->copyFrom(channel, bufferToFill.startSample, m_sourceBuffer->data() + m_pos, len);
26 if (len < bufferToFill.numSamples)
27 {
28 const int startClear = bufferToFill.startSample + len;
29 const int lenClear = bufferToFill.numSamples - len;
30 destBuffer->clear(startClear, lenClear);
31 }
32 }
33 else
34 {
35 destBuffer->clear(channel, bufferToFill.startSample, bufferToFill.numSamples);
36 }
37 }
38 }
39 m_pos += static_cast<size_t>(len);
40 }
41
42 private:
44 size_t m_pos;
45
48 };
49
50 // ===================================================================
51
53 : juce::Thread("ConvolutionComputationThread"), m_processor(processor)
54 {
55 startThread();
56 }
57
59
61 {
62 if (threadShouldExit() || m_processor.getImpulseResponseFilePath() == "")
63 {
64 return;
65 }
66
68 if (!irFile.existsAsFile())
69 return;
70
71 const auto& convolvers = m_processor.getConvolvers();
72 int numConvolvers = convolvers.size();
73
74 std::vector<FloatBuffer::Ptr> buffers;
75
76 juce::AudioFormatManager formatManager;
77 formatManager.registerBasicFormats();
78 std::unique_ptr<AudioFormatReader> reader(formatManager.createReaderFor(irFile));
79 double fileSampleRate = reader->sampleRate;
80
81 // add an audio buffer for each convolver
82 int fileChannels = static_cast<int>(reader->numChannels);
83 if (fileChannels < 1 || fileChannels > 2) // only mono & stereo IR's are supported currently
84 return;
85
86 bool isMono = fileChannels == 1;
87 for (int i = 0; i < numConvolvers; ++i)
88 if (!threadShouldExit())
89 buffers.push_back(importChannelFromAudioFile(reader.get(), isMono ? 0 : i % 2));
90
91 // resample the buffers to the current sample rate
92 const double convolverSampleRate = m_processor.getSampleRate();
93 if (convolverSampleRate < 1.0)
94 return;
95
96 for (int i = 0; i < numConvolvers; ++i)
97 if (!threadShouldExit())
98 buffers[static_cast<size_t>(i)] =
99 changeSampleRate(buffers[static_cast<size_t>(i)], fileSampleRate, convolverSampleRate);
100
101 // Unify buffer size
102 unifyBufferSize(buffers);
103 if (threadShouldExit())
104 {
105 return;
106 }
107
108 // Normalise the IR levels
110 if (threadShouldExit())
111 {
112 return;
113 }
114
115 // Update convolvers
116 const float headBlockSize = static_cast<float>(m_processor.getConvolverHeadBlockSize());
117 const float tailBlockSize = static_cast<float>(m_processor.getConvolverTailBlockSize());
118 if (headBlockSize > 0 && tailBlockSize > 0)
119 for (int i = 0; i < convolvers.size(); i++)
120 convolvers[i]->resetConvolver(buffers[static_cast<size_t>(i)], headBlockSize, tailBlockSize);
121 }
122
124 int fileChannel) const
125 {
126 if (!reader || reader->sampleRate < 0.0001)
127 return {};
128
129 const int fileChannels = static_cast<int>(reader->numChannels);
130 const int fileLen = static_cast<int>(reader->lengthInSamples);
131
132 if (static_cast<int>(fileChannel) >= fileChannels)
133 return {};
134
135 FloatBuffer::Ptr buffer(new FloatBuffer(static_cast<size_t>(fileLen)));
136 AudioFormatReaderSource audioFormatReaderSource(reader, false);
137 juce::AudioSampleBuffer importBuffer(fileChannels, 8192);
138 auto bufferPtr = buffer->data();
139 auto importBufferPtr = importBuffer.getReadPointer(fileChannel);
140 int pos = 0;
141 while (pos < fileLen)
142 {
143 if (threadShouldExit())
144 {
145 return {};
146 }
147
148 const int loading = std::min(importBuffer.getNumSamples(), static_cast<int>(fileLen - pos));
149 AudioSourceChannelInfo info;
150 info.buffer = &importBuffer;
151 info.startSample = 0;
152 info.numSamples = loading;
153 audioFormatReaderSource.getNextAudioBlock(info);
154 ::memcpy(bufferPtr + pos, importBufferPtr,
155 static_cast<size_t>(static_cast<unsigned int>(loading) * sizeof(float)));
156 pos += static_cast<int>(loading);
157 }
158
159 return buffer;
160 }
161
163 double inputSampleRate,
164 double outputSampleRate) const
165 {
166 if (!inputBuffer)
167 {
168 return {};
169 }
170
171 if (std::fabs(outputSampleRate - inputSampleRate) < 0.0000001)
172 {
173 return inputBuffer;
174 }
175
176 jassert(inputSampleRate >= 1.0);
177 jassert(outputSampleRate >= 1.0);
178
179 const double samplesInPerOutputSample = inputSampleRate / outputSampleRate;
180 const int inputSampleCount = static_cast<int>(inputBuffer->getSize());
181 const int outputSampleCount =
182 static_cast<int>(::ceil(static_cast<double>(inputSampleCount) / samplesInPerOutputSample));
183 const int blockSize = 8192;
184
185 FloatBufferSource inputSource(inputBuffer);
186 ResamplingAudioSource resamplingSource(&inputSource, false, 1);
187 resamplingSource.setResamplingRatio(samplesInPerOutputSample);
188 resamplingSource.prepareToPlay(blockSize, outputSampleRate);
189
190 FloatBuffer::Ptr outputBuffer(new FloatBuffer(static_cast<size_t>(outputSampleCount)));
191 AudioSampleBuffer blockBuffer(1, blockSize);
192 int processed = 0;
193 while (processed < outputSampleCount)
194 {
195 if (threadShouldExit())
196 {
197 return {};
198 }
199
200 const int remaining = outputSampleCount - processed;
201 const int processing = std::min(blockSize, remaining);
202
203 juce::AudioSourceChannelInfo info;
204 info.buffer = &blockBuffer;
205 info.startSample = 0;
206 info.numSamples = processing;
207 resamplingSource.getNextAudioBlock(info);
208 ::memcpy(outputBuffer->data() + processed, blockBuffer.getReadPointer(0),
209 static_cast<size_t>(static_cast<unsigned long>(processing) * sizeof(float)));
210 processed += processing;
211 }
212
213 resamplingSource.releaseResources();
214
215 return outputBuffer;
216 }
217
218 void ConvolutionComputationThread::unifyBufferSize(std::vector<FloatBuffer::Ptr>& buffers) const
219 {
220 size_t bufferSize = 0;
221 for (size_t i = 0; i < buffers.size(); ++i)
222 {
223 if (buffers[i] != nullptr)
224 {
225 bufferSize = std::max(bufferSize, buffers[i]->getSize());
226 }
227 }
228 for (size_t i = 0; i < buffers.size(); ++i)
229 {
230 if (threadShouldExit())
231 {
232 return;
233 }
234 if (buffers[i] && buffers[i]->getSize() < bufferSize)
235 {
236 FloatBuffer::Ptr buffer(new FloatBuffer(bufferSize));
237 const size_t copySize = buffers[i]->getSize();
238 const size_t padSize = bufferSize - copySize;
239 ::memcpy(buffer->data(), buffers[i]->data(), copySize * sizeof(float));
240 ::memset(buffer->data() + copySize, 0, padSize * sizeof(float));
241 buffers[i] = buffer;
242 }
243 }
244 }
245
246 void ConvolutionComputationThread::normaliseImpulseResponses(const std::vector<FloatBuffer::Ptr>& buffers) const
247 {
248 // Normalize IRs based on RMS (method used by old convolution reverb)
249 if (threadShouldExit())
250 return;
251
252 auto buffer = buffers[0]->data();
253 auto len = buffers[0]->getSize();
254
255 float rms = 0.0f;
256 for (size_t i = 0; i < len; ++i)
257 rms += buffer[i] * buffer[i];
258 rms = std::sqrt(rms / static_cast<float>(len));
259
260 const float idealRms = 1e-3f;
261 float gain = idealRms / rms;
262 for (auto& buff : buffers)
263 if (buff != nullptr)
264 for (int i = 0; i < static_cast<int>(buff->getSize()); i++)
265 buff->data()[i] *= gain;
266 }
267} // namespace krotos
void run() override
Adds audio buffer to the convolvers, resamples it to the current sample rate, unifies buffer size and...
Definition ConvolutionComputationThread.cpp:60
void normaliseImpulseResponses(const std::vector< FloatBuffer::Ptr > &buffers) const
Definition ConvolutionComputationThread.cpp:246
FloatBuffer::Ptr importChannelFromAudioFile(AudioFormatReader *reader, int fileChannel) const
Definition ConvolutionComputationThread.cpp:123
ConvolutionComputationThread(ConvolutionReverb &processor)
Definition ConvolutionComputationThread.cpp:52
~ConvolutionComputationThread() override
Definition ConvolutionComputationThread.cpp:58
ConvolutionReverb & m_processor
Definition ConvolutionComputationThread.h:24
FloatBuffer::Ptr changeSampleRate(const FloatBuffer::Ptr &inputBuffer, double inputSampleRate, double outputSampleRate) const
Definition ConvolutionComputationThread.cpp:162
void unifyBufferSize(std::vector< FloatBuffer::Ptr > &buffers) const
Definition ConvolutionComputationThread.cpp:218
Audio processing class that uses multi-threading to convolve an input signal with an impulse response...
Definition ConvolutionReverb.h:9
size_t getConvolverTailBlockSize() const
Definition ConvolutionReverb.cpp:171
String getImpulseResponseFilePath() const
Definition ConvolutionReverb.cpp:177
size_t getConvolverHeadBlockSize() const
Definition ConvolutionReverb.cpp:165
const OwnedArray< IRConvolver > & getConvolvers() const
Definition ConvolutionReverb.cpp:142
double getSampleRate() const
Definition ConvolutionReverb.cpp:84
Definition IRConvolver.h:4
ReferenceCountedObjectPtr< FloatBuffer > Ptr
Definition IRConvolver.h:6
Definition ConvolutionComputationThread.cpp:4
FloatBufferSource & operator=(const FloatBufferSource &)
virtual void releaseResources()
Definition ConvolutionComputationThread.cpp:13
const FloatBuffer::Ptr & m_sourceBuffer
Definition ConvolutionComputationThread.cpp:43
size_t m_pos
Definition ConvolutionComputationThread.cpp:44
virtual void getNextAudioBlock(const AudioSourceChannelInfo &bufferToFill)
Definition ConvolutionComputationThread.cpp:15
FloatBufferSource(const FloatBuffer::Ptr &sourceBuffer)
Definition ConvolutionComputationThread.cpp:6
FloatBufferSource(const FloatBufferSource &)
virtual void prepareToPlay(int, double)
Definition ConvolutionComputationThread.cpp:11
Definition AirAbsorptionFilter.cpp:2