The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1218 lines
45KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 6 technical preview.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For this technical preview, this file is not subject to commercial licensing.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. namespace juce
  14. {
  15. namespace dsp
  16. {
  17. struct ConvolutionEngine
  18. {
  19. ConvolutionEngine (const float* samples,
  20. size_t numSamples,
  21. size_t maxBlockSize)
  22. : blockSize ((size_t) nextPowerOfTwo ((int) maxBlockSize)),
  23. fftSize (blockSize > 128 ? 2 * blockSize : 4 * blockSize),
  24. fftObject (std::make_unique<FFT> (roundToInt (std::log2 (fftSize)))),
  25. numSegments (numSamples / (fftSize - blockSize) + 1u),
  26. numInputSegments ((blockSize > 128 ? numSegments : 3 * numSegments)),
  27. bufferInput (1, static_cast<int> (fftSize)),
  28. bufferOutput (1, static_cast<int> (fftSize * 2)),
  29. bufferTempOutput (1, static_cast<int> (fftSize * 2)),
  30. bufferOverlap (1, static_cast<int> (fftSize))
  31. {
  32. bufferOutput.clear();
  33. auto updateSegmentsIfNecessary = [this] (size_t numSegmentsToUpdate,
  34. std::vector<AudioBuffer<float>>& segments)
  35. {
  36. if (numSegmentsToUpdate == 0
  37. || numSegmentsToUpdate != (size_t) segments.size()
  38. || (size_t) segments[0].getNumSamples() != fftSize * 2)
  39. {
  40. segments.clear();
  41. for (size_t i = 0; i < numSegmentsToUpdate; ++i)
  42. segments.push_back ({ 1, static_cast<int> (fftSize * 2) });
  43. }
  44. };
  45. updateSegmentsIfNecessary (numInputSegments, buffersInputSegments);
  46. updateSegmentsIfNecessary (numSegments, buffersImpulseSegments);
  47. auto FFTTempObject = std::make_unique<FFT> (roundToInt (std::log2 (fftSize)));
  48. size_t currentPtr = 0;
  49. for (auto& buf : buffersImpulseSegments)
  50. {
  51. buf.clear();
  52. auto* impulseResponse = buf.getWritePointer (0);
  53. if (&buf == &buffersImpulseSegments.front())
  54. impulseResponse[0] = 1.0f;
  55. FloatVectorOperations::copy (impulseResponse,
  56. samples + currentPtr,
  57. static_cast<int> (jmin (fftSize - blockSize, numSamples - currentPtr)));
  58. FFTTempObject->performRealOnlyForwardTransform (impulseResponse);
  59. prepareForConvolution (impulseResponse);
  60. currentPtr += (fftSize - blockSize);
  61. }
  62. reset();
  63. }
  64. void reset()
  65. {
  66. bufferInput.clear();
  67. bufferOverlap.clear();
  68. bufferTempOutput.clear();
  69. bufferOutput.clear();
  70. for (auto& buf : buffersInputSegments)
  71. buf.clear();
  72. currentSegment = 0;
  73. inputDataPos = 0;
  74. }
  75. void processSamples (const float* input, float* output, size_t numSamples)
  76. {
  77. // Overlap-add, zero latency convolution algorithm with uniform partitioning
  78. size_t numSamplesProcessed = 0;
  79. auto indexStep = numInputSegments / numSegments;
  80. auto* inputData = bufferInput.getWritePointer (0);
  81. auto* outputTempData = bufferTempOutput.getWritePointer (0);
  82. auto* outputData = bufferOutput.getWritePointer (0);
  83. auto* overlapData = bufferOverlap.getWritePointer (0);
  84. while (numSamplesProcessed < numSamples)
  85. {
  86. const bool inputDataWasEmpty = (inputDataPos == 0);
  87. auto numSamplesToProcess = jmin (numSamples - numSamplesProcessed, blockSize - inputDataPos);
  88. FloatVectorOperations::copy (inputData + inputDataPos, input + numSamplesProcessed, static_cast<int> (numSamplesToProcess));
  89. auto* inputSegmentData = buffersInputSegments[currentSegment].getWritePointer (0);
  90. FloatVectorOperations::copy (inputSegmentData, inputData, static_cast<int> (fftSize));
  91. fftObject->performRealOnlyForwardTransform (inputSegmentData);
  92. prepareForConvolution (inputSegmentData);
  93. // Complex multiplication
  94. if (inputDataWasEmpty)
  95. {
  96. FloatVectorOperations::fill (outputTempData, 0, static_cast<int> (fftSize + 1));
  97. auto index = currentSegment;
  98. for (size_t i = 1; i < numSegments; ++i)
  99. {
  100. index += indexStep;
  101. if (index >= numInputSegments)
  102. index -= numInputSegments;
  103. convolutionProcessingAndAccumulate (buffersInputSegments[index].getWritePointer (0),
  104. buffersImpulseSegments[i].getWritePointer (0),
  105. outputTempData);
  106. }
  107. }
  108. FloatVectorOperations::copy (outputData, outputTempData, static_cast<int> (fftSize + 1));
  109. convolutionProcessingAndAccumulate (inputSegmentData,
  110. buffersImpulseSegments.front().getWritePointer (0),
  111. outputData);
  112. updateSymmetricFrequencyDomainData (outputData);
  113. fftObject->performRealOnlyInverseTransform (outputData);
  114. // Add overlap
  115. FloatVectorOperations::add (&output[numSamplesProcessed], &outputData[inputDataPos], &overlapData[inputDataPos], (int) numSamplesToProcess);
  116. // Input buffer full => Next block
  117. inputDataPos += numSamplesToProcess;
  118. if (inputDataPos == blockSize)
  119. {
  120. // Input buffer is empty again now
  121. FloatVectorOperations::fill (inputData, 0.0f, static_cast<int> (fftSize));
  122. inputDataPos = 0;
  123. // Extra step for segSize > blockSize
  124. FloatVectorOperations::add (&(outputData[blockSize]), &(overlapData[blockSize]), static_cast<int> (fftSize - 2 * blockSize));
  125. // Save the overlap
  126. FloatVectorOperations::copy (overlapData, &(outputData[blockSize]), static_cast<int> (fftSize - blockSize));
  127. currentSegment = (currentSegment > 0) ? (currentSegment - 1) : (numInputSegments - 1);
  128. }
  129. numSamplesProcessed += numSamplesToProcess;
  130. }
  131. }
  132. void processSamplesWithAddedLatency (const float* input, float* output, size_t numSamples)
  133. {
  134. // Overlap-add, zero latency convolution algorithm with uniform partitioning
  135. size_t numSamplesProcessed = 0;
  136. auto indexStep = numInputSegments / numSegments;
  137. auto* inputData = bufferInput.getWritePointer (0);
  138. auto* outputTempData = bufferTempOutput.getWritePointer (0);
  139. auto* outputData = bufferOutput.getWritePointer (0);
  140. auto* overlapData = bufferOverlap.getWritePointer (0);
  141. while (numSamplesProcessed < numSamples)
  142. {
  143. auto numSamplesToProcess = jmin (numSamples - numSamplesProcessed, blockSize - inputDataPos);
  144. FloatVectorOperations::copy (inputData + inputDataPos, input + numSamplesProcessed, static_cast<int> (numSamplesToProcess));
  145. FloatVectorOperations::copy (output + numSamplesProcessed, outputData + inputDataPos, static_cast<int> (numSamplesToProcess));
  146. numSamplesProcessed += numSamplesToProcess;
  147. inputDataPos += numSamplesToProcess;
  148. // processing itself when needed (with latency)
  149. if (inputDataPos == blockSize)
  150. {
  151. // Copy input data in input segment
  152. auto* inputSegmentData = buffersInputSegments[currentSegment].getWritePointer (0);
  153. FloatVectorOperations::copy (inputSegmentData, inputData, static_cast<int> (fftSize));
  154. fftObject->performRealOnlyForwardTransform (inputSegmentData);
  155. prepareForConvolution (inputSegmentData);
  156. // Complex multiplication
  157. FloatVectorOperations::fill (outputTempData, 0, static_cast<int> (fftSize + 1));
  158. auto index = currentSegment;
  159. for (size_t i = 1; i < numSegments; ++i)
  160. {
  161. index += indexStep;
  162. if (index >= numInputSegments)
  163. index -= numInputSegments;
  164. convolutionProcessingAndAccumulate (buffersInputSegments[index].getWritePointer (0),
  165. buffersImpulseSegments[i].getWritePointer (0),
  166. outputTempData);
  167. }
  168. FloatVectorOperations::copy (outputData, outputTempData, static_cast<int> (fftSize + 1));
  169. convolutionProcessingAndAccumulate (inputSegmentData,
  170. buffersImpulseSegments.front().getWritePointer (0),
  171. outputData);
  172. updateSymmetricFrequencyDomainData (outputData);
  173. fftObject->performRealOnlyInverseTransform (outputData);
  174. // Add overlap
  175. FloatVectorOperations::add (outputData, overlapData, static_cast<int> (blockSize));
  176. // Input buffer is empty again now
  177. FloatVectorOperations::fill (inputData, 0.0f, static_cast<int> (fftSize));
  178. // Extra step for segSize > blockSize
  179. FloatVectorOperations::add (&(outputData[blockSize]), &(overlapData[blockSize]), static_cast<int> (fftSize - 2 * blockSize));
  180. // Save the overlap
  181. FloatVectorOperations::copy (overlapData, &(outputData[blockSize]), static_cast<int> (fftSize - blockSize));
  182. currentSegment = (currentSegment > 0) ? (currentSegment - 1) : (numInputSegments - 1);
  183. inputDataPos = 0;
  184. }
  185. }
  186. }
  187. // After each FFT, this function is called to allow convolution to be performed with only 4 SIMD functions calls.
  188. void prepareForConvolution (float *samples) noexcept
  189. {
  190. auto FFTSizeDiv2 = fftSize / 2;
  191. for (size_t i = 0; i < FFTSizeDiv2; i++)
  192. samples[i] = samples[i << 1];
  193. samples[FFTSizeDiv2] = 0;
  194. for (size_t i = 1; i < FFTSizeDiv2; i++)
  195. samples[i + FFTSizeDiv2] = -samples[((fftSize - i) << 1) + 1];
  196. }
  197. // Does the convolution operation itself only on half of the frequency domain samples.
  198. void convolutionProcessingAndAccumulate (const float *input, const float *impulse, float *output)
  199. {
  200. auto FFTSizeDiv2 = fftSize / 2;
  201. FloatVectorOperations::addWithMultiply (output, input, impulse, static_cast<int> (FFTSizeDiv2));
  202. FloatVectorOperations::subtractWithMultiply (output, &(input[FFTSizeDiv2]), &(impulse[FFTSizeDiv2]), static_cast<int> (FFTSizeDiv2));
  203. FloatVectorOperations::addWithMultiply (&(output[FFTSizeDiv2]), input, &(impulse[FFTSizeDiv2]), static_cast<int> (FFTSizeDiv2));
  204. FloatVectorOperations::addWithMultiply (&(output[FFTSizeDiv2]), &(input[FFTSizeDiv2]), impulse, static_cast<int> (FFTSizeDiv2));
  205. output[fftSize] += input[fftSize] * impulse[fftSize];
  206. }
  207. // Undoes the re-organization of samples from the function prepareForConvolution.
  208. // Then takes the conjugate of the frequency domain first half of samples to fill the
  209. // second half, so that the inverse transform will return real samples in the time domain.
  210. void updateSymmetricFrequencyDomainData (float* samples) noexcept
  211. {
  212. auto FFTSizeDiv2 = fftSize / 2;
  213. for (size_t i = 1; i < FFTSizeDiv2; i++)
  214. {
  215. samples[(fftSize - i) << 1] = samples[i];
  216. samples[((fftSize - i) << 1) + 1] = -samples[FFTSizeDiv2 + i];
  217. }
  218. samples[1] = 0.f;
  219. for (size_t i = 1; i < FFTSizeDiv2; i++)
  220. {
  221. samples[i << 1] = samples[(fftSize - i) << 1];
  222. samples[(i << 1) + 1] = -samples[((fftSize - i) << 1) + 1];
  223. }
  224. }
  225. //==============================================================================
  226. const size_t blockSize;
  227. const size_t fftSize;
  228. const std::unique_ptr<FFT> fftObject;
  229. const size_t numSegments;
  230. const size_t numInputSegments;
  231. size_t currentSegment = 0, inputDataPos = 0;
  232. AudioBuffer<float> bufferInput, bufferOutput, bufferTempOutput, bufferOverlap;
  233. std::vector<AudioBuffer<float>> buffersInputSegments, buffersImpulseSegments;
  234. };
  235. //==============================================================================
  236. template <typename Element>
  237. class Queue
  238. {
  239. public:
  240. explicit Queue (int size)
  241. : fifo (size), storage (static_cast<size_t> (size)) {}
  242. bool push (Element& element) noexcept
  243. {
  244. if (fifo.getFreeSpace() == 0)
  245. return false;
  246. const auto writer = fifo.write (1);
  247. if (writer.blockSize1 != 0)
  248. storage[static_cast<size_t> (writer.startIndex1)] = std::move (element);
  249. else if (writer.blockSize2 != 0)
  250. storage[static_cast<size_t> (writer.startIndex2)] = std::move (element);
  251. return true;
  252. }
  253. template <typename Fn>
  254. void pop (Fn&& fn) { popN (1, std::forward<Fn> (fn)); }
  255. template <typename Fn>
  256. void popAll (Fn&& fn) { popN (fifo.getNumReady(), std::forward<Fn> (fn)); }
  257. bool hasPendingMessages() const noexcept { return fifo.getNumReady() > 0; }
  258. private:
  259. template <typename Fn>
  260. void popN (int n, Fn&& fn)
  261. {
  262. fifo.read (n).forEach ([&] (int index)
  263. {
  264. fn (storage[static_cast<size_t> (index)]);
  265. });
  266. }
  267. AbstractFifo fifo;
  268. std::vector<Element> storage;
  269. };
  270. //==============================================================================
  271. class MultichannelEngine
  272. {
  273. public:
  274. MultichannelEngine (const AudioBuffer<float>& buf,
  275. int maxBlockSize,
  276. int maxBufferSize,
  277. Convolution::NonUniform headSizeIn,
  278. bool isZeroDelayIn)
  279. : tailBuffer (1, maxBlockSize),
  280. latency (isZeroDelayIn ? 0 : maxBufferSize),
  281. irSize (buf.getNumSamples()),
  282. blockSize (maxBlockSize),
  283. isZeroDelay (isZeroDelayIn)
  284. {
  285. constexpr auto numChannels = 2;
  286. const auto makeEngine = [&] (int channel, int offset, int length, uint32 thisBlockSize)
  287. {
  288. return std::make_unique<ConvolutionEngine> (buf.getReadPointer (jmin (buf.getNumChannels() - 1, channel), offset),
  289. length,
  290. static_cast<size_t> (thisBlockSize));
  291. };
  292. if (headSizeIn.headSizeInSamples == 0)
  293. {
  294. for (int i = 0; i < numChannels; ++i)
  295. head.emplace_back (makeEngine (i, 0, buf.getNumSamples(), static_cast<uint32> (maxBufferSize)));
  296. }
  297. else
  298. {
  299. const auto size = jmin (buf.getNumSamples(), headSizeIn.headSizeInSamples);
  300. for (int i = 0; i < numChannels; ++i)
  301. head.emplace_back (makeEngine (i, 0, size, static_cast<uint32> (maxBufferSize)));
  302. const auto tailBufferSize = static_cast<uint32> (headSizeIn.headSizeInSamples + (isZeroDelay ? 0 : maxBufferSize));
  303. if (size != buf.getNumSamples())
  304. for (int i = 0; i < numChannels; ++i)
  305. tail.emplace_back (makeEngine (i, size, buf.getNumSamples() - size, tailBufferSize));
  306. }
  307. }
  308. void reset()
  309. {
  310. for (const auto& e : head)
  311. e->reset();
  312. for (const auto& e : tail)
  313. e->reset();
  314. }
  315. void processSamples (const AudioBlock<const float>& input, AudioBlock<float>& output)
  316. {
  317. const auto numChannels = juce::jmin (head.size(), input.getNumChannels(), output.getNumChannels());
  318. const auto numSamples = jmin (input.getNumSamples(), output.getNumSamples());
  319. const AudioBlock<float> fullTailBlock (tailBuffer);
  320. const auto tailBlock = fullTailBlock.getSubBlock (0, (size_t) numSamples);
  321. const auto isUniform = tail.empty();
  322. for (size_t channel = 0; channel < numChannels; ++channel)
  323. {
  324. if (! isUniform)
  325. tail[channel]->processSamplesWithAddedLatency (input.getChannelPointer (channel),
  326. tailBlock.getChannelPointer (0),
  327. numSamples);
  328. if (isZeroDelay)
  329. head[channel]->processSamples (input.getChannelPointer (channel),
  330. output.getChannelPointer (channel),
  331. numSamples);
  332. else
  333. head[channel]->processSamplesWithAddedLatency (input.getChannelPointer (channel),
  334. output.getChannelPointer (channel),
  335. numSamples);
  336. if (! isUniform)
  337. output.getSingleChannelBlock (channel) += tailBlock;
  338. }
  339. const auto numOutputChannels = output.getNumChannels();
  340. for (auto i = numChannels; i < numOutputChannels; ++i)
  341. output.getSingleChannelBlock (i).copyFrom (output.getSingleChannelBlock (0));
  342. }
  343. int getIRSize() const noexcept { return irSize; }
  344. int getLatency() const noexcept { return latency; }
  345. int getBlockSize() const noexcept { return blockSize; }
  346. private:
  347. std::vector<std::unique_ptr<ConvolutionEngine>> head, tail;
  348. AudioBuffer<float> tailBuffer;
  349. const int latency;
  350. const int irSize;
  351. const int blockSize;
  352. const bool isZeroDelay;
  353. };
  354. static AudioBuffer<float> fixNumChannels (const AudioBuffer<float>& buf, Convolution::Stereo stereo)
  355. {
  356. const auto numChannels = jmin (buf.getNumChannels(), stereo == Convolution::Stereo::yes ? 2 : 1);
  357. const auto numSamples = buf.getNumSamples();
  358. AudioBuffer<float> result (numChannels, buf.getNumSamples());
  359. for (auto channel = 0; channel != numChannels; ++channel)
  360. result.copyFrom (channel, 0, buf.getReadPointer (channel), numSamples);
  361. if (result.getNumSamples() == 0 || result.getNumChannels() == 0)
  362. {
  363. result.setSize (1, 1);
  364. result.setSample (0, 0, 1.0f);
  365. }
  366. return result;
  367. }
  368. static AudioBuffer<float> trimImpulseResponse (const AudioBuffer<float>& buf)
  369. {
  370. const auto thresholdTrim = Decibels::decibelsToGain (-80.0f);
  371. const auto numChannels = buf.getNumChannels();
  372. const auto numSamples = buf.getNumSamples();
  373. std::ptrdiff_t offsetBegin = numSamples;
  374. std::ptrdiff_t offsetEnd = numSamples;
  375. for (auto channel = 0; channel < numChannels; ++channel)
  376. {
  377. const auto indexAboveThreshold = [&] (auto begin, auto end)
  378. {
  379. return std::distance (begin, std::find_if (begin, end, [&] (float sample)
  380. {
  381. return std::abs (sample) >= thresholdTrim;
  382. }));
  383. };
  384. const auto channelBegin = buf.getReadPointer (channel);
  385. const auto channelEnd = channelBegin + numSamples;
  386. const auto itStart = indexAboveThreshold (channelBegin, channelEnd);
  387. const auto itEnd = indexAboveThreshold (std::make_reverse_iterator (channelEnd),
  388. std::make_reverse_iterator (channelBegin));
  389. offsetBegin = jmin (offsetBegin, itStart);
  390. offsetEnd = jmin (offsetEnd, itEnd);
  391. }
  392. if (offsetBegin == numSamples)
  393. {
  394. auto result = AudioBuffer<float> (numChannels, 1);
  395. result.clear();
  396. return result;
  397. }
  398. const auto newLength = juce::jmax (1, numSamples - static_cast<int> (offsetBegin + offsetEnd));
  399. AudioBuffer<float> result (numChannels, newLength);
  400. for (auto channel = 0; channel < numChannels; ++channel)
  401. {
  402. result.copyFrom (channel,
  403. 0,
  404. buf.getReadPointer (channel, static_cast<int> (offsetBegin)),
  405. result.getNumSamples());
  406. }
  407. return result;
  408. }
  409. static float calculateNormalisationFactor (float sumSquaredMagnitude)
  410. {
  411. if (sumSquaredMagnitude < 1e-8f)
  412. return 1.0f;
  413. return 0.125f / std::sqrt (sumSquaredMagnitude);
  414. }
  415. static void normaliseImpulseResponse (AudioBuffer<float>& buf)
  416. {
  417. const auto numChannels = buf.getNumChannels();
  418. const auto numSamples = buf.getNumSamples();
  419. const auto channelPtrs = buf.getArrayOfWritePointers();
  420. const auto maxSumSquaredMag = std::accumulate (channelPtrs, channelPtrs + numChannels, 0.0f, [&] (auto max, auto* channel)
  421. {
  422. return juce::jmax (max, std::accumulate (channel, channel + numSamples, 0.0f, [] (auto sum, auto samp)
  423. {
  424. return sum + (samp * samp);
  425. }));
  426. });
  427. const auto normalisationFactor = calculateNormalisationFactor (maxSumSquaredMag);
  428. std::for_each (channelPtrs, channelPtrs + numChannels, [&] (auto* channel)
  429. {
  430. FloatVectorOperations::multiply (channel, normalisationFactor, numSamples);
  431. });
  432. }
  433. static AudioBuffer<float> resampleImpulseResponse (const AudioBuffer<float>& buf,
  434. const double srcSampleRate,
  435. const double destSampleRate)
  436. {
  437. if (srcSampleRate == destSampleRate)
  438. return buf;
  439. const auto factorReading = srcSampleRate / destSampleRate;
  440. AudioBuffer<float> original = buf;
  441. MemoryAudioSource memorySource (original, false);
  442. ResamplingAudioSource resamplingSource (&memorySource, false, buf.getNumChannels());
  443. const auto finalSize = roundToInt (juce::jmax (1.0, buf.getNumSamples() / factorReading));
  444. resamplingSource.setResamplingRatio (factorReading);
  445. resamplingSource.prepareToPlay (finalSize, srcSampleRate);
  446. AudioBuffer<float> result (buf.getNumChannels(), finalSize);
  447. resamplingSource.getNextAudioBlock ({ &result, 0, result.getNumSamples() });
  448. return result;
  449. }
  450. //==============================================================================
  451. class BackgroundMessageQueue : private Thread
  452. {
  453. public:
  454. BackgroundMessageQueue()
  455. : Thread ("Convolution background loader"), queue (1000)
  456. {
  457. startThread();
  458. }
  459. ~BackgroundMessageQueue() override
  460. {
  461. stopThread (-1);
  462. }
  463. using IncomingCommand = FixedSizeFunction<400, void()>;
  464. // Push functions here, and they'll be called later on a background thread.
  465. // This function is wait-free.
  466. // This function is only safe to call from a single thread at a time.
  467. bool push (IncomingCommand& command) { return queue.push (command); }
  468. private:
  469. void run() override
  470. {
  471. while (! threadShouldExit())
  472. {
  473. if (queue.hasPendingMessages())
  474. queue.pop ([] (IncomingCommand& command) { command(); command = nullptr;});
  475. else
  476. sleep (10);
  477. }
  478. }
  479. Queue<IncomingCommand> queue;
  480. };
  481. template <typename Element>
  482. class TryLockedPtr
  483. {
  484. public:
  485. void set (std::unique_ptr<Element> p)
  486. {
  487. const SpinLock::ScopedLockType lock (mutex);
  488. ptr = std::move (p);
  489. }
  490. std::unique_ptr<MultichannelEngine> get()
  491. {
  492. const SpinLock::ScopedTryLockType lock (mutex);
  493. return lock.isLocked() ? std::move (ptr) : nullptr;
  494. }
  495. private:
  496. std::unique_ptr<Element> ptr;
  497. SpinLock mutex;
  498. };
  499. struct BufferWithSampleRate
  500. {
  501. BufferWithSampleRate() = default;
  502. BufferWithSampleRate (AudioBuffer<float>&& bufferIn, double sampleRateIn)
  503. : buffer (std::move (bufferIn)), sampleRate (sampleRateIn) {}
  504. AudioBuffer<float> buffer;
  505. double sampleRate = 0.0;
  506. };
  507. static BufferWithSampleRate loadStreamToBuffer (std::unique_ptr<InputStream> stream, size_t maxLength)
  508. {
  509. AudioFormatManager manager;
  510. manager.registerBasicFormats();
  511. std::unique_ptr<AudioFormatReader> formatReader (manager.createReaderFor (std::move (stream)));
  512. if (formatReader == nullptr)
  513. return {};
  514. const auto fileLength = static_cast<size_t> (formatReader->lengthInSamples);
  515. const auto lengthToLoad = maxLength == 0 ? fileLength : jmin (maxLength, fileLength);
  516. BufferWithSampleRate result { { jlimit (1, 2, static_cast<int> (formatReader->numChannels)),
  517. static_cast<int> (lengthToLoad) },
  518. formatReader->sampleRate };
  519. formatReader->read (result.buffer.getArrayOfWritePointers(),
  520. result.buffer.getNumChannels(),
  521. 0,
  522. result.buffer.getNumSamples());
  523. return result;
  524. }
  525. // This class caches the data required to build a new convolution engine
  526. // (in particular, impulse response data and a ProcessSpec).
  527. // Calls to `setProcessSpec` and `setImpulseResponse` construct a
  528. // new engine, which can be retrieved by calling `getEngine`.
  529. class ConvolutionEngineFactory
  530. {
  531. public:
  532. ConvolutionEngineFactory (Convolution::Latency requiredLatency,
  533. Convolution::NonUniform requiredHeadSize)
  534. : latency { (requiredLatency.latencyInSamples <= 0) ? 0 : jmax (64, nextPowerOfTwo (requiredLatency.latencyInSamples)) },
  535. headSize { (requiredHeadSize.headSizeInSamples <= 0) ? 0 : jmax (64, nextPowerOfTwo (requiredHeadSize.headSizeInSamples)) },
  536. shouldBeZeroLatency (requiredLatency.latencyInSamples == 0)
  537. {}
  538. // It is safe to call this method simultaneously with other public
  539. // member functions.
  540. void setProcessSpec (const ProcessSpec& spec)
  541. {
  542. const std::lock_guard<std::mutex> lock (mutex);
  543. processSpec = spec;
  544. engine.set (makeEngine());
  545. }
  546. // It is safe to call this method simultaneously with other public
  547. // member functions.
  548. void setImpulseResponse (BufferWithSampleRate&& buf,
  549. Convolution::Stereo stereo,
  550. Convolution::Trim trim,
  551. Convolution::Normalise normalise)
  552. {
  553. const std::lock_guard<std::mutex> lock (mutex);
  554. wantsNormalise = normalise;
  555. originalSampleRate = buf.sampleRate;
  556. impulseResponse = [&]
  557. {
  558. auto corrected = fixNumChannels (buf.buffer, stereo);
  559. return trim == Convolution::Trim::yes ? trimImpulseResponse (corrected) : corrected;
  560. }();
  561. engine.set (makeEngine());
  562. }
  563. // Returns the most recently-created engine, or nullptr
  564. // if there is no pending engine, or if the engine is currently
  565. // being updated by one of the setter methods.
  566. // It is safe to call this simultaneously with other public
  567. // member functions.
  568. std::unique_ptr<MultichannelEngine> getEngine() { return engine.get(); }
  569. private:
  570. std::unique_ptr<MultichannelEngine> makeEngine()
  571. {
  572. auto resampled = resampleImpulseResponse (impulseResponse, originalSampleRate, processSpec.sampleRate);
  573. if (wantsNormalise == Convolution::Normalise::yes)
  574. normaliseImpulseResponse (resampled);
  575. const auto currentLatency = jmax (processSpec.maximumBlockSize, (uint32) latency.latencyInSamples);
  576. const auto maxBufferSize = shouldBeZeroLatency ? static_cast<int> (processSpec.maximumBlockSize)
  577. : nextPowerOfTwo (static_cast<int> (currentLatency));
  578. return std::make_unique<MultichannelEngine> (resampled,
  579. processSpec.maximumBlockSize,
  580. maxBufferSize,
  581. headSize,
  582. shouldBeZeroLatency);
  583. }
  584. static AudioBuffer<float> makeImpulseBuffer()
  585. {
  586. AudioBuffer<float> result (1, 1);
  587. result.setSample (0, 0, 1.0f);
  588. return result;
  589. }
  590. ProcessSpec processSpec { 44100.0, 128, 2 };
  591. AudioBuffer<float> impulseResponse = makeImpulseBuffer();
  592. double originalSampleRate = processSpec.sampleRate;
  593. Convolution::Normalise wantsNormalise = Convolution::Normalise::no;
  594. const Convolution::Latency latency;
  595. const Convolution::NonUniform headSize;
  596. const bool shouldBeZeroLatency;
  597. TryLockedPtr<MultichannelEngine> engine;
  598. mutable std::mutex mutex;
  599. };
  600. static void setImpulseResponse (ConvolutionEngineFactory& factory,
  601. const void* sourceData,
  602. size_t sourceDataSize,
  603. Convolution::Stereo stereo,
  604. Convolution::Trim trim,
  605. size_t size,
  606. Convolution::Normalise normalise)
  607. {
  608. factory.setImpulseResponse (loadStreamToBuffer (std::make_unique<MemoryInputStream> (sourceData, sourceDataSize, false), size),
  609. stereo, trim, normalise);
  610. }
  611. static void setImpulseResponse (ConvolutionEngineFactory& factory,
  612. const File& fileImpulseResponse,
  613. Convolution::Stereo stereo,
  614. Convolution::Trim trim,
  615. size_t size,
  616. Convolution::Normalise normalise)
  617. {
  618. factory.setImpulseResponse (loadStreamToBuffer (std::make_unique<FileInputStream> (fileImpulseResponse), size),
  619. stereo, trim, normalise);
  620. }
  621. // This class acts as a destination for convolution engines which are loaded on
  622. // a background thread.
  623. // Deriving from `enable_shared_from_this` allows us to capture a reference to
  624. // this object when adding commands to the background message queue.
  625. // That way, we can avoid dangling references in the background thread in the case
  626. // that a Convolution instance is deleted before the background message queue.
  627. class ConvolutionEngineQueue : public std::enable_shared_from_this<ConvolutionEngineQueue>
  628. {
  629. public:
  630. ConvolutionEngineQueue (BackgroundMessageQueue& queue,
  631. Convolution::Latency latencyIn,
  632. Convolution::NonUniform headSizeIn)
  633. : messageQueue (queue), factory (latencyIn, headSizeIn) {}
  634. void loadImpulseResponse (AudioBuffer<float>&& buffer,
  635. double sr,
  636. Convolution::Stereo stereo,
  637. Convolution::Trim trim,
  638. Convolution::Normalise normalise)
  639. {
  640. callLater ([b = std::move (buffer), sr, stereo, trim, normalise] (ConvolutionEngineFactory& f) mutable
  641. {
  642. f.setImpulseResponse ({ std::move (b), sr }, stereo, trim, normalise);
  643. });
  644. }
  645. void loadImpulseResponse (const void* sourceData,
  646. size_t sourceDataSize,
  647. Convolution::Stereo stereo,
  648. Convolution::Trim trim,
  649. size_t size,
  650. Convolution::Normalise normalise)
  651. {
  652. callLater ([sourceData, sourceDataSize, stereo, trim, size, normalise] (ConvolutionEngineFactory& f) mutable
  653. {
  654. setImpulseResponse (f, sourceData, sourceDataSize, stereo, trim, size, normalise);
  655. });
  656. }
  657. void loadImpulseResponse (const File& fileImpulseResponse,
  658. Convolution::Stereo stereo,
  659. Convolution::Trim trim,
  660. size_t size,
  661. Convolution::Normalise normalise)
  662. {
  663. callLater ([fileImpulseResponse, stereo, trim, size, normalise] (ConvolutionEngineFactory& f) mutable
  664. {
  665. setImpulseResponse (f, fileImpulseResponse, stereo, trim, size, normalise);
  666. });
  667. }
  668. void prepare (const ProcessSpec& spec)
  669. {
  670. factory.setProcessSpec (spec);
  671. }
  672. // Call this regularly to try to resend any pending message.
  673. // This allows us to always apply the most recently requested
  674. // state (eventually), even if the message queue fills up.
  675. void postPendingCommand()
  676. {
  677. if (pendingCommand == nullptr)
  678. return;
  679. if (messageQueue.push (pendingCommand))
  680. pendingCommand = nullptr;
  681. }
  682. std::unique_ptr<MultichannelEngine> getEngine() { return factory.getEngine(); }
  683. private:
  684. template <typename Fn>
  685. void callLater (Fn&& fn)
  686. {
  687. // If there was already a pending command (because the queue was full) we'll end up deleting it here.
  688. // Not much we can do about that!
  689. pendingCommand = [weak = weakFromThis(), callback = std::forward<Fn> (fn)]() mutable
  690. {
  691. if (auto t = weak.lock())
  692. callback (t->factory);
  693. };
  694. postPendingCommand();
  695. }
  696. std::weak_ptr<ConvolutionEngineQueue> weakFromThis() { return shared_from_this(); }
  697. BackgroundMessageQueue& messageQueue;
  698. ConvolutionEngineFactory factory;
  699. BackgroundMessageQueue::IncomingCommand pendingCommand;
  700. };
  701. class CrossoverMixer
  702. {
  703. public:
  704. void reset()
  705. {
  706. smoother.setCurrentAndTargetValue (1.0f);
  707. }
  708. void prepare (const ProcessSpec& spec)
  709. {
  710. smoother.reset (spec.sampleRate, 0.05);
  711. smootherBuffer.setSize (1, static_cast<int> (spec.maximumBlockSize));
  712. mixBuffer.setSize (static_cast<int> (spec.numChannels), static_cast<int> (spec.maximumBlockSize));
  713. reset();
  714. }
  715. template <typename ProcessCurrent, typename ProcessPrevious, typename NotifyDone>
  716. void processSamples (const AudioBlock<const float>& input,
  717. AudioBlock<float>& output,
  718. ProcessCurrent&& current,
  719. ProcessPrevious&& previous,
  720. NotifyDone&& notifyDone)
  721. {
  722. if (smoother.isSmoothing())
  723. {
  724. const auto numSamples = static_cast<int> (input.getNumSamples());
  725. for (auto sample = 0; sample != numSamples; ++sample)
  726. smootherBuffer.setSample (0, sample, smoother.getNextValue());
  727. AudioBlock<float> mixBlock (mixBuffer);
  728. mixBlock.clear();
  729. previous (input, mixBlock);
  730. for (size_t channel = 0; channel != output.getNumChannels(); ++channel)
  731. {
  732. FloatVectorOperations::multiply (mixBlock.getChannelPointer (channel),
  733. smootherBuffer.getReadPointer (0),
  734. numSamples);
  735. }
  736. FloatVectorOperations::multiply (smootherBuffer.getWritePointer (0), -1.0f, numSamples);
  737. FloatVectorOperations::add (smootherBuffer.getWritePointer (0), 1.0f, numSamples);
  738. current (input, output);
  739. for (size_t channel = 0; channel != output.getNumChannels(); ++channel)
  740. {
  741. FloatVectorOperations::multiply (output.getChannelPointer (channel),
  742. smootherBuffer.getReadPointer (0),
  743. numSamples);
  744. FloatVectorOperations::add (output.getChannelPointer (channel),
  745. mixBlock.getChannelPointer (channel),
  746. numSamples);
  747. }
  748. if (! smoother.isSmoothing())
  749. notifyDone();
  750. }
  751. else
  752. {
  753. current (input, output);
  754. }
  755. }
  756. void beginTransition()
  757. {
  758. smoother.setCurrentAndTargetValue (1.0f);
  759. smoother.setTargetValue (0.0f);
  760. }
  761. private:
  762. LinearSmoothedValue<float> smoother;
  763. AudioBuffer<float> smootherBuffer;
  764. AudioBuffer<float> mixBuffer;
  765. };
  766. class Convolution::Impl
  767. {
  768. public:
  769. Impl (Latency requiredLatency, NonUniform requiredHeadSize)
  770. : engineQueue (std::make_shared<ConvolutionEngineQueue> (messageQueue, requiredLatency, requiredHeadSize))
  771. {}
  772. void reset()
  773. {
  774. mixer.reset();
  775. if (currentEngine != nullptr)
  776. currentEngine->reset();
  777. destroyPreviousEngine();
  778. }
  779. void prepare (const ProcessSpec& spec)
  780. {
  781. mixer.prepare (spec);
  782. engineQueue->prepare (spec);
  783. installPendingEngine();
  784. jassert (currentEngine != nullptr);
  785. }
  786. void processSamples (const AudioBlock<const float>& input, AudioBlock<float>& output)
  787. {
  788. engineQueue->postPendingCommand();
  789. if (previousEngine == nullptr)
  790. installPendingEngine();
  791. mixer.processSamples (input,
  792. output,
  793. [this] (const AudioBlock<const float>& in, AudioBlock<float>& out)
  794. {
  795. currentEngine->processSamples (in, out);
  796. },
  797. [this] (const AudioBlock<const float>& in, AudioBlock<float>& out)
  798. {
  799. if (previousEngine != nullptr)
  800. previousEngine->processSamples (in, out);
  801. else
  802. out.copyFrom (in);
  803. },
  804. [this] { destroyPreviousEngine(); });
  805. }
  806. int getCurrentIRSize() const { return currentEngine != nullptr ? currentEngine->getIRSize() : 0; }
  807. int getLatency() const { return currentEngine != nullptr ? currentEngine->getLatency() : 0; }
  808. void loadImpulseResponse (AudioBuffer<float>&& buffer,
  809. double originalSampleRate,
  810. Stereo stereo,
  811. Trim trim,
  812. Normalise normalise)
  813. {
  814. engineQueue->loadImpulseResponse (std::move (buffer), originalSampleRate, stereo, trim, normalise);
  815. }
  816. void loadImpulseResponse (const void* sourceData,
  817. size_t sourceDataSize,
  818. Stereo stereo,
  819. Trim trim,
  820. size_t size,
  821. Normalise normalise)
  822. {
  823. engineQueue->loadImpulseResponse (sourceData, sourceDataSize, stereo, trim, size, normalise);
  824. }
  825. void loadImpulseResponse (const File& fileImpulseResponse,
  826. Stereo stereo,
  827. Trim trim,
  828. size_t size,
  829. Normalise normalise)
  830. {
  831. engineQueue->loadImpulseResponse (fileImpulseResponse, stereo, trim, size, normalise);
  832. }
  833. private:
  834. void destroyPreviousEngine()
  835. {
  836. // If the queue is full, we'll destroy this straight away
  837. BackgroundMessageQueue::IncomingCommand command = [p = std::move (previousEngine)]() mutable { p = nullptr; };
  838. messageQueue.push (command);
  839. }
  840. void installNewEngine (std::unique_ptr<MultichannelEngine> newEngine)
  841. {
  842. destroyPreviousEngine();
  843. previousEngine = std::move (currentEngine);
  844. currentEngine = std::move (newEngine);
  845. mixer.beginTransition();
  846. }
  847. void installPendingEngine()
  848. {
  849. if (auto newEngine = engineQueue->getEngine())
  850. installNewEngine (std::move (newEngine));
  851. }
  852. BackgroundMessageQueue messageQueue;
  853. std::shared_ptr<ConvolutionEngineQueue> engineQueue;
  854. std::unique_ptr<MultichannelEngine> previousEngine, currentEngine;
  855. CrossoverMixer mixer;
  856. };
  857. //==============================================================================
  858. void Convolution::Mixer::prepare (const ProcessSpec& spec)
  859. {
  860. for (auto& dry : volumeDry)
  861. dry.reset (spec.sampleRate, 0.05);
  862. for (auto& wet : volumeWet)
  863. wet.reset (spec.sampleRate, 0.05);
  864. sampleRate = spec.sampleRate;
  865. dryBlock = AudioBlock<float> (dryBlockStorage,
  866. jmin (spec.numChannels, 2u),
  867. spec.maximumBlockSize);
  868. }
  869. template <typename ProcessWet>
  870. void Convolution::Mixer::processSamples (const AudioBlock<const float>& input,
  871. AudioBlock<float>& output,
  872. bool isBypassed,
  873. ProcessWet&& processWet) noexcept
  874. {
  875. const auto numChannels = jmin (input.getNumChannels(), volumeDry.size());
  876. const auto numSamples = jmin (input.getNumSamples(), output.getNumSamples());
  877. auto dry = dryBlock.getSubsetChannelBlock (0, numChannels);
  878. if (volumeDry[0].isSmoothing())
  879. {
  880. dry.copyFrom (input);
  881. for (size_t channel = 0; channel < numChannels; ++channel)
  882. volumeDry[channel].applyGain (dry.getChannelPointer (channel), (int) numSamples);
  883. processWet (input, output);
  884. for (size_t channel = 0; channel < numChannels; ++channel)
  885. volumeWet[channel].applyGain (output.getChannelPointer (channel), (int) numSamples);
  886. output += dry;
  887. }
  888. else
  889. {
  890. if (! currentIsBypassed)
  891. processWet (input, output);
  892. if (isBypassed != currentIsBypassed)
  893. {
  894. currentIsBypassed = isBypassed;
  895. for (size_t channel = 0; channel < numChannels; ++channel)
  896. {
  897. volumeDry[channel].setTargetValue (isBypassed ? 0.0f : 1.0f);
  898. volumeDry[channel].reset (sampleRate, 0.05);
  899. volumeDry[channel].setTargetValue (isBypassed ? 1.0f : 0.0f);
  900. volumeWet[channel].setTargetValue (isBypassed ? 1.0f : 0.0f);
  901. volumeWet[channel].reset (sampleRate, 0.05);
  902. volumeWet[channel].setTargetValue (isBypassed ? 0.0f : 1.0f);
  903. }
  904. }
  905. }
  906. }
  907. void Convolution::Mixer::reset() { dryBlock.clear(); }
  908. //==============================================================================
  909. Convolution::Convolution()
  910. : Convolution (Latency { 0 }) {}
  911. Convolution::Convolution (const Latency& requiredLatency)
  912. : pimpl (std::make_unique<Impl> (requiredLatency, NonUniform{}))
  913. {}
  914. Convolution::Convolution (const NonUniform& nonUniform)
  915. : pimpl (std::make_unique<Impl> (Latency{}, nonUniform))
  916. {}
  917. Convolution::~Convolution() noexcept = default;
  918. void Convolution::loadImpulseResponse (const void* sourceData,
  919. size_t sourceDataSize,
  920. Stereo stereo,
  921. Trim trim,
  922. size_t size,
  923. Normalise normalise)
  924. {
  925. pimpl->loadImpulseResponse (sourceData, sourceDataSize, stereo, trim, size, normalise);
  926. }
  927. void Convolution::loadImpulseResponse (const File& fileImpulseResponse,
  928. Stereo stereo,
  929. Trim trim,
  930. size_t size,
  931. Normalise normalise)
  932. {
  933. pimpl->loadImpulseResponse (fileImpulseResponse, stereo, trim, size, normalise);
  934. }
  935. void Convolution::loadImpulseResponse (AudioBuffer<float>&& buffer,
  936. double originalSampleRate,
  937. Stereo stereo,
  938. Trim trim,
  939. Normalise normalise)
  940. {
  941. pimpl->loadImpulseResponse (std::move (buffer), originalSampleRate, stereo, trim, normalise);
  942. }
  943. void Convolution::prepare (const ProcessSpec& spec)
  944. {
  945. mixer.prepare (spec);
  946. pimpl->prepare (spec);
  947. isActive = true;
  948. }
  949. void Convolution::reset() noexcept
  950. {
  951. mixer.reset();
  952. pimpl->reset();
  953. }
  954. void Convolution::processSamples (const AudioBlock<const float>& input,
  955. AudioBlock<float>& output,
  956. bool isBypassed) noexcept
  957. {
  958. if (! isActive)
  959. return;
  960. jassert (input.getNumChannels() == output.getNumChannels());
  961. jassert (isPositiveAndBelow (input.getNumChannels(), static_cast<size_t> (3))); // only mono and stereo is supported
  962. mixer.processSamples (input, output, isBypassed, [this] (const auto& in, auto& out)
  963. {
  964. pimpl->processSamples (in, out);
  965. });
  966. }
  967. int Convolution::getCurrentIRSize() const { return pimpl->getCurrentIRSize(); }
  968. int Convolution::getLatency() const { return pimpl->getLatency(); }
  969. } // namespace dsp
  970. } // namespace juce