2 ==============================================================================
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
7 JUCE is an open source library subject to commercial or open-source
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
23 ==============================================================================
32 Used by the Convolution to dispatch engine-update messages on a background
35 May be shared between multiple Convolution instances.
39 class JUCE_API ConvolutionMessageQueue
42 /** Initialises the queue to a default size.
44 If your Convolution is updated very frequently, or you are sharing
45 this queue between multiple Convolutions, consider using the alternative
46 constructor taking an explicit size argument.
48 ConvolutionMessageQueue();
49 ~ConvolutionMessageQueue() noexcept
;
51 /** Initialises the queue with the specified number of entries.
53 In general, the number of required entries scales with the number
54 of Convolutions sharing the same Queue, and the frequency of updates
55 to those Convolutions.
57 explicit ConvolutionMessageQueue (int numEntries
);
59 ConvolutionMessageQueue (ConvolutionMessageQueue
&&) noexcept
;
60 ConvolutionMessageQueue
& operator= (ConvolutionMessageQueue
&&) noexcept
;
62 ConvolutionMessageQueue (const ConvolutionMessageQueue
&) = delete;
63 ConvolutionMessageQueue
& operator= (const ConvolutionMessageQueue
&) = delete;
67 std::unique_ptr
<Impl
> pimpl
;
69 friend class Convolution
;
73 Performs stereo partitioned convolution of an input signal with an
74 impulse response in the frequency domain, using the JUCE FFT class.
76 This class provides some thread-safe functions to load impulse responses
77 from audio files or memory on-the-fly without noticeable artefacts,
78 performing resampling and trimming if necessary.
80 The processing performed by this class is equivalent to the time domain
81 convolution done in the FIRFilter class, with a FIRFilter::Coefficients
82 object having the samples of the impulse response as its coefficients.
83 However, in general it is more efficient to do frequency domain
84 convolution when the size of the impulse response is 64 samples or
87 Note: The default operation of this class uses zero latency and a uniform
88 partitioned algorithm. If the impulse response size is large, or if the
89 algorithm is too CPU intensive, it is possible to use either a fixed
90 latency version of the algorithm, or a simple non-uniform partitioned
91 convolution algorithm.
93 Threading: It is not safe to interleave calls to the methods of this
94 class. If you need to load new impulse responses during processing the
95 load() calls must be synchronised with process() calls, which in practice
96 means making the load() call from the audio thread. The
97 loadImpulseResponse() functions *are* wait-free and are therefore
98 suitable for use in a realtime context.
100 @see FIRFilter, FIRFilter::Coefficients, FFT
104 class JUCE_API Convolution
107 //==============================================================================
108 /** Initialises an object for performing convolution in the frequency domain. */
111 /** Initialises a convolution engine using a shared background message queue.
113 IMPORTANT: the queue *must* remain alive throughout the lifetime of the
116 explicit Convolution (ConvolutionMessageQueue
& queue
);
118 /** Contains configuration information for a convolution with a fixed latency. */
119 struct Latency
{ int latencyInSamples
; };
121 /** Initialises an object for performing convolution with a fixed latency.
123 If the requested latency is zero, the actual latency will also be zero.
124 For requested latencies greater than zero, the actual latency will
125 always at least as large as the requested latency. Using a fixed
126 non-zero latency can reduce the CPU consumption of the convolution
129 @param requiredLatency the minimum latency
131 explicit Convolution (const Latency
& requiredLatency
);
133 /** Contains configuration information for a non-uniform convolution. */
134 struct NonUniform
{ int headSizeInSamples
; };
136 /** Initialises an object for performing convolution in the frequency domain
137 using a non-uniform partitioned algorithm.
139 A requiredHeadSize of 256 samples or greater will improve the
140 efficiency of the processing for IR sizes of 4096 samples or greater
141 (recommended for reverberation IRs).
143 @param requiredHeadSize the head IR size for two stage non-uniform
144 partitioned convolution
146 explicit Convolution (const NonUniform
& requiredHeadSize
);
148 /** Behaves the same as the constructor taking a single Latency argument,
149 but with a shared background message queue.
151 IMPORTANT: the queue *must* remain alive throughout the lifetime of the
154 Convolution (const Latency
&, ConvolutionMessageQueue
&);
156 /** Behaves the same as the constructor taking a single NonUniform argument,
157 but with a shared background message queue.
159 IMPORTANT: the queue *must* remain alive throughout the lifetime of the
162 Convolution (const NonUniform
&, ConvolutionMessageQueue
&);
164 ~Convolution() noexcept
;
166 //==============================================================================
167 /** Must be called before first calling process.
169 In general, calls to loadImpulseResponse() load the impulse response (IR)
170 asynchronously. The IR will become active once it has been completely loaded
171 and processed, which may take some time.
173 Calling prepare() will ensure that the IR supplied to the most recent call to
174 loadImpulseResponse() is fully initialised. This IR will then be active during
175 the next call to process(). It is recommended to call loadImpulseResponse() *before*
176 prepare() if a specific IR must be active during the first process() call.
178 void prepare (const ProcessSpec
&);
180 /** Resets the processing pipeline ready to start a new stream of data. */
181 void reset() noexcept
;
183 /** Performs the filter operation on the given set of samples with optional
186 template <typename ProcessContext
,
187 std::enable_if_t
<std::is_same
<typename
ProcessContext::SampleType
, float>::value
, int> = 0>
188 void process (const ProcessContext
& context
) noexcept
190 processSamples (context
.getInputBlock(), context
.getOutputBlock(), context
.isBypassed
);
193 //==============================================================================
194 enum class Stereo
{ no
, yes
};
195 enum class Trim
{ no
, yes
};
196 enum class Normalise
{ no
, yes
};
198 //==============================================================================
199 /** This function loads an impulse response audio file from memory, added in a
200 JUCE project with the Projucer as binary data. It can load any of the audio
201 formats registered in JUCE, and performs some resampling and pre-processing
204 Note: Don't try to use this function on float samples, since the data is
205 expected to be an audio file in its binary format. Be sure that the original
206 data remains constant throughout the lifetime of the Convolution object, as
207 the loading process will happen on a background thread once this function has
210 @param sourceData the block of data to use as the stream's source
211 @param sourceDataSize the number of bytes in the source data block
212 @param isStereo selects either stereo or mono
213 @param requiresTrimming optionally trim the start and the end of the impulse response
214 @param size the expected size for the impulse response after loading, can be
215 set to 0 to requesting the original impulse response size
216 @param requiresNormalisation optionally normalise the impulse response amplitude
218 void loadImpulseResponse (const void* sourceData
, size_t sourceDataSize
,
219 Stereo isStereo
, Trim requiresTrimming
, size_t size
,
220 Normalise requiresNormalisation
= Normalise::yes
);
222 /** This function loads an impulse response from an audio file. It can load any
223 of the audio formats registered in JUCE, and performs some resampling and
224 pre-processing as well if needed.
226 @param fileImpulseResponse the location of the audio file
227 @param isStereo selects either stereo or mono
228 @param requiresTrimming optionally trim the start and the end of the impulse response
229 @param size the expected size for the impulse response after loading, can be
230 set to 0 to requesting the original impulse response size
231 @param requiresNormalisation optionally normalise the impulse response amplitude
233 void loadImpulseResponse (const File
& fileImpulseResponse
,
234 Stereo isStereo
, Trim requiresTrimming
, size_t size
,
235 Normalise requiresNormalisation
= Normalise::yes
);
237 /** This function loads an impulse response from an audio buffer.
238 To avoid memory allocation on the audio thread, this function takes
239 ownership of the buffer passed in.
241 If calling this function during processing, make sure that the buffer is
242 not allocated on the audio thread (be careful of accidental copies!).
243 If you need to pass arbitrary/generated buffers it's recommended to
244 create these buffers on a separate thread and to use some wait-free
245 construct (a lock-free queue or a SpinLock/GenericScopedTryLock combination)
246 to transfer ownership to the audio thread without allocating.
248 @param buffer the AudioBuffer to use
249 @param bufferSampleRate the sampleRate of the data in the AudioBuffer
250 @param isStereo selects either stereo or mono
251 @param requiresTrimming optionally trim the start and the end of the impulse response
252 @param requiresNormalisation optionally normalise the impulse response amplitude
254 void loadImpulseResponse (AudioBuffer
<float>&& buffer
, double bufferSampleRate
,
255 Stereo isStereo
, Trim requiresTrimming
, Normalise requiresNormalisation
);
257 /** This function returns the size of the current IR in samples. */
258 int getCurrentIRSize() const;
260 /** This function returns the current latency of the process in samples.
262 Note: This is the latency of the convolution engine, not the latency
263 associated with the current impulse response choice that has to be
264 considered separately (linear phase filters, for example).
266 int getLatency() const;
269 //==============================================================================
270 Convolution (const Latency
&,
272 OptionalScopedPointer
<ConvolutionMessageQueue
>&&);
274 void processSamples (const AudioBlock
<const float>&, AudioBlock
<float>&, bool isBypassed
) noexcept
;
279 void prepare (const ProcessSpec
&);
281 template <typename ProcessWet
>
282 void processSamples (const AudioBlock
<const float>&,
285 ProcessWet
&&) noexcept
;
290 std::array
<SmoothedValue
<float>, 2> volumeDry
, volumeWet
;
291 AudioBlock
<float> dryBlock
;
292 HeapBlock
<char> dryBlockStorage
;
293 double sampleRate
= 0;
294 bool currentIsBypassed
= false;
297 //==============================================================================
299 std::unique_ptr
<Impl
> pimpl
;
301 //==============================================================================
303 bool isActive
= false;
305 //==============================================================================
306 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Convolution
)