40 struct ProcessingInformation
50 SourceType sourceType = SourceType::sourceNone;
52 const void* sourceData;
54 File fileImpulseResponse;
56 double originalSampleRate;
58 int originalNumChannels = 1;
62 bool wantsStereo =
true;
63 bool wantsTrimming =
true;
64 bool wantsNormalisation =
true;
68 double sampleRate = 0;
69 size_t maximumBufferSize = 0;
76 bufferOverlap.clear();
77 bufferTempOutput.clear();
79 for (
auto i = 0; i < buffersInputSegments.size(); ++i)
80 buffersInputSegments.getReference (i).clear();
89 blockSize = (size_t) nextPowerOfTwo ((
int) info.maximumBufferSize);
91 FFTSize = blockSize > 128 ? 2 * blockSize
94 numSegments = ((size_t) info.finalSize) / (FFTSize - blockSize) + 1u;
96 numInputSegments = (blockSize > 128 ? numSegments : 3 * numSegments);
98 FFTobject.reset (
new FFT (roundToInt (std::log2 (FFTSize))));
100 bufferInput.setSize (1, static_cast<int> (FFTSize));
101 bufferOutput.setSize (1, static_cast<int> (FFTSize * 2));
102 bufferTempOutput.setSize (1, static_cast<int> (FFTSize * 2));
103 bufferOverlap.setSize (1, static_cast<int> (FFTSize));
105 buffersInputSegments.clear();
106 buffersImpulseSegments.clear();
107 bufferOutput.clear();
109 for (
size_t i = 0; i < numInputSegments; ++i)
112 newInputSegment.
setSize (1, static_cast<int> (FFTSize * 2));
113 buffersInputSegments.add (newInputSegment);
116 for (
auto i = 0u; i < numSegments; ++i)
119 newImpulseSegment.
setSize (1, static_cast<int> (FFTSize * 2));
120 buffersImpulseSegments.add (newImpulseSegment);
123 std::unique_ptr<FFT> FFTTempObject (
new FFT (roundToInt (std::log2 (FFTSize))));
125 auto* channelData = info.buffer->getWritePointer (channel);
127 for (
size_t n = 0; n < numSegments; ++n)
129 buffersImpulseSegments.getReference (static_cast<int> (n)).clear();
131 auto* impulseResponse = buffersImpulseSegments.getReference (static_cast<int> (n)).getWritePointer (0);
134 impulseResponse[0] = 1.0f;
136 for (
size_t i = 0; i < FFTSize - blockSize; ++i)
137 if (i + n * (FFTSize - blockSize) < (
size_t) info.finalSize)
138 impulseResponse[i] = channelData[i + n * (FFTSize - blockSize)];
140 FFTTempObject->performRealOnlyForwardTransform (impulseResponse);
152 if (FFTSize != other.FFTSize)
154 FFTobject.reset (
new FFT (roundToInt (std::log2 (other.FFTSize))));
155 FFTSize = other.FFTSize;
158 currentSegment = other.currentSegment;
159 numInputSegments = other.numInputSegments;
160 numSegments = other.numSegments;
161 blockSize = other.blockSize;
162 inputDataPos = other.inputDataPos;
164 bufferInput = other.bufferInput;
165 bufferTempOutput = other.bufferTempOutput;
166 bufferOutput = other.bufferOutput;
168 buffersInputSegments = other.buffersInputSegments;
169 buffersImpulseSegments = other.buffersImpulseSegments;
170 bufferOverlap = other.bufferOverlap;
182 size_t numSamplesProcessed = 0;
184 auto indexStep = numInputSegments / numSegments;
186 auto* inputData = bufferInput.getWritePointer (0);
187 auto* outputTempData = bufferTempOutput.getWritePointer (0);
188 auto* outputData = bufferOutput.getWritePointer (0);
189 auto* overlapData = bufferOverlap.getWritePointer (0);
191 while (numSamplesProcessed < numSamples)
193 const bool inputDataWasEmpty = (inputDataPos == 0);
194 auto numSamplesToProcess = jmin (numSamples - numSamplesProcessed, blockSize - inputDataPos);
199 auto* inputSegmentData = buffersInputSegments.getReference (static_cast<int> (currentSegment)).getWritePointer (0);
203 FFTobject->performRealOnlyForwardTransform (inputSegmentData);
207 if (inputDataWasEmpty)
211 auto index = currentSegment;
213 for (
size_t i = 1; i < numSegments; ++i)
217 if (index >= numInputSegments)
218 index -= numInputSegments;
221 buffersImpulseSegments.getReference (static_cast<int> (i)).getWritePointer (0),
229 buffersImpulseSegments.getReference (0).getWritePointer (0),
234 FFTobject->performRealOnlyInverseTransform (outputData);
237 for (
size_t i = 0; i < numSamplesToProcess; ++i)
238 output[i + numSamplesProcessed] = outputData[inputDataPos + i] + overlapData[inputDataPos + i];
241 inputDataPos += numSamplesToProcess;
243 if (inputDataPos == blockSize)
257 currentSegment = (currentSegment > 0) ? (currentSegment - 1) : (numInputSegments - 1);
260 numSamplesProcessed += numSamplesToProcess;
267 auto FFTSizeDiv2 = FFTSize / 2;
269 for (
size_t i = 0; i < FFTSizeDiv2; i++)
270 samples[i] = samples[2 * i];
272 samples[FFTSizeDiv2] = 0;
274 for (
size_t i = 1; i < FFTSizeDiv2; i++)
275 samples[i + FFTSizeDiv2] = -samples[2 * (FFTSize - i) + 1];
281 auto FFTSizeDiv2 = FFTSize / 2;
289 output[FFTSize] += input[FFTSize] * impulse[FFTSize];
298 auto FFTSizeDiv2 = FFTSize / 2;
300 for (
size_t i = 1; i < FFTSizeDiv2; i++)
302 samples[2 * (FFTSize - i)] = samples[i];
303 samples[2 * (FFTSize - i) + 1] = -samples[FFTSizeDiv2 + i];
308 for (
size_t i = 1; i < FFTSizeDiv2; i++)
310 samples[2 * i] = samples[2 * (FFTSize - i)];
311 samples[2 * i + 1] = -samples[2 * (FFTSize - i) + 1];
316 std::unique_ptr<FFT> FFTobject;
319 size_t currentSegment = 0, numInputSegments = 0, numSegments = 0, blockSize = 0, inputDataPos = 0;
324 bool isReady =
false;
339 enum class ChangeRequest
343 changeMaximumBufferSize,
345 changeImpulseResponseSize,
350 numChangeRequestTypes
353 using SourceType = ConvolutionEngine::ProcessingInformation::SourceType;
356 Pimpl() :
Thread (
"Convolution"), abstractFifo (fifoSize)
358 abstractFifo.reset();
359 fifoRequestsType.resize (fifoSize);
360 fifoRequestsParameter.resize (fifoSize);
362 requestsType.resize (fifoSize);
363 requestsParameter.resize (fifoSize);
365 for (
auto i = 0; i < 4; ++i)
368 currentInfo.maximumBufferSize = 0;
369 currentInfo.buffer = &impulseResponse;
371 temporaryBuffer.setSize (2, static_cast<int> (maximumTimeInSamples),
false,
false,
true);
372 impulseResponseOriginal.setSize (2, static_cast<int> (maximumTimeInSamples),
false,
false,
true);
373 impulseResponse.setSize (2, static_cast<int> (maximumTimeInSamples),
false,
false,
true);
387 interpolationBuffer.setSize (1, maximumBufferSize,
false,
false,
true);
388 mustInterpolate =
false;
395 int start1, size1, start2, size2;
396 abstractFifo.prepareToWrite (1, start1, size1, start2, size2);
400 jassert (size1 + size2 > 0);
404 fifoRequestsType.setUnchecked (start1, type);
405 fifoRequestsParameter.setUnchecked (start1, parameter);
410 fifoRequestsType.setUnchecked (start2, type);
411 fifoRequestsParameter.setUnchecked (start2, parameter);
414 abstractFifo.finishedWrite (size1 + size2);
420 int start1, size1, start2, size2;
421 abstractFifo.prepareToWrite (numEntries, start1, size1, start2, size2);
425 jassert (numEntries > 0 && size1 + size2 > 0);
429 for (
auto i = 0; i < size1; ++i)
431 fifoRequestsType.setUnchecked (start1 + i, types[i]);
432 fifoRequestsParameter.setUnchecked (start1 + i, parameters[i]);
438 for (
auto i = 0; i < size2; ++i)
440 fifoRequestsType.setUnchecked (start2 + i, types[i + size1]);
441 fifoRequestsParameter.setUnchecked (start2 + i, parameters[i + size1]);
445 abstractFifo.finishedWrite (size1 + size2);
451 int start1, size1, start2, size2;
452 abstractFifo.prepareToRead (1, start1, size1, start2, size2);
456 type = fifoRequestsType[start1];
457 parameter = fifoRequestsParameter[start1];
462 type = fifoRequestsType[start2];
463 parameter = fifoRequestsParameter[start2];
466 abstractFifo.finishedRead (size1 + size2);
472 return abstractFifo.getNumReady();
484 if (getNumRemainingEntries() == 0 || isThreadRunning() || mustInterpolate)
487 auto numRequests = 0;
490 while (getNumRemainingEntries() > 0 && numRequests < fifoSize)
492 ChangeRequest type = ChangeRequest::changeEngine;
495 readFromFifo (type, parameter);
497 requestsType.setUnchecked (numRequests, type);
498 requestsParameter.setUnchecked (numRequests, parameter);
504 for (
auto i = 0; i < (int) ChangeRequest::numChangeRequestTypes; ++i)
508 for (
auto n = numRequests; --n >= 0;)
510 if (requestsType[n] == (ChangeRequest) i)
515 requestsType.setUnchecked (n, ChangeRequest::changeIgnore);
522 for (
auto n = 0; n < numRequests; ++n)
524 switch (requestsType[n])
526 case ChangeRequest::changeEngine:
530 case ChangeRequest::changeSampleRate:
532 double newSampleRate = requestsParameter[n];
534 if (currentInfo.sampleRate != newSampleRate)
537 currentInfo.sampleRate = newSampleRate;
541 case ChangeRequest::changeMaximumBufferSize:
543 int newMaximumBufferSize = requestsParameter[n];
545 if (currentInfo.maximumBufferSize != (
size_t) newMaximumBufferSize)
548 currentInfo.maximumBufferSize = (size_t) newMaximumBufferSize;
552 case ChangeRequest::changeSource:
554 auto* arrayParameters = requestsParameter[n].getArray();
555 auto newSourceType =
static_cast<SourceType
> (
static_cast<int> (arrayParameters->getUnchecked (0)));
557 if (currentInfo.sourceType != newSourceType)
558 changeLevel = jmax (2, changeLevel);
560 if (newSourceType == SourceType::sourceBinaryData)
562 auto& prm = arrayParameters->getRawDataPointer()[1];
563 auto* newMemoryBlock = prm.getBinaryData();
565 auto* newPtr = newMemoryBlock->getData();
566 auto newSize = (int) newMemoryBlock->getSize();
568 if (currentInfo.sourceData != newPtr || currentInfo.sourceDataSize != newSize)
569 changeLevel = jmax (2, changeLevel);
571 currentInfo.sourceType = SourceType::sourceBinaryData;
572 currentInfo.sourceData = newPtr;
573 currentInfo.sourceDataSize = newSize;
574 currentInfo.fileImpulseResponse =
File();
576 else if (newSourceType == SourceType::sourceAudioFile)
578 File newFile (arrayParameters->getUnchecked (1).toString());
580 if (currentInfo.fileImpulseResponse != newFile)
581 changeLevel = jmax (2, changeLevel);
583 currentInfo.sourceType = SourceType::sourceAudioFile;
584 currentInfo.fileImpulseResponse = newFile;
585 currentInfo.sourceData =
nullptr;
586 currentInfo.sourceDataSize = 0;
588 else if (newSourceType == SourceType::sourceAudioBuffer)
590 double originalSampleRate (arrayParameters->getUnchecked (1));
591 changeLevel = jmax (2, changeLevel);
593 currentInfo.sourceType = SourceType::sourceAudioBuffer;
594 currentInfo.originalSampleRate = originalSampleRate;
595 currentInfo.fileImpulseResponse =
File();
596 currentInfo.sourceData =
nullptr;
597 currentInfo.sourceDataSize = 0;
602 case ChangeRequest::changeImpulseResponseSize:
604 int64 newSize = requestsParameter[n];
606 if (currentInfo.wantedSize != newSize)
607 changeLevel = jmax (1, changeLevel);
609 currentInfo.wantedSize = newSize;
613 case ChangeRequest::changeStereo:
615 bool newWantsStereo = requestsParameter[n];
617 if (currentInfo.wantsStereo != newWantsStereo)
618 changeLevel = jmax (0, changeLevel);
620 currentInfo.wantsStereo = newWantsStereo;
624 case ChangeRequest::changeTrimming:
626 bool newWantsTrimming = requestsParameter[n];
628 if (currentInfo.wantsTrimming != newWantsTrimming)
629 changeLevel = jmax (1, changeLevel);
631 currentInfo.wantsTrimming = newWantsTrimming;
635 case ChangeRequest::changeNormalisation:
637 bool newWantsNormalisation = requestsParameter[n];
639 if (currentInfo.wantsNormalisation != newWantsNormalisation)
640 changeLevel = jmax (1, changeLevel);
642 currentInfo.wantsNormalisation = newWantsNormalisation;
646 case ChangeRequest::changeIgnore:
655 if (currentInfo.sourceType == SourceType::sourceNone)
657 currentInfo.sourceType = SourceType::sourceAudioBuffer;
659 if (currentInfo.sampleRate == 0)
660 currentInfo.sampleRate = 44100;
662 if (currentInfo.maximumBufferSize == 0)
663 currentInfo.maximumBufferSize = 128;
665 currentInfo.originalSampleRate = currentInfo.sampleRate;
666 currentInfo.wantedSize = 1;
667 currentInfo.fileImpulseResponse =
File();
668 currentInfo.sourceData =
nullptr;
669 currentInfo.sourceDataSize = 0;
675 copyBufferToTemporaryLocation (newBuffer);
679 if (changeLevel == 3)
681 loadImpulseResponse();
682 processImpulseResponse();
683 initializeConvolutionEngines();
685 else if (changeLevel > 0)
699 currentInfo.originalNumChannels = (block.
getNumChannels() > 1 ? 2 : 1);
700 currentInfo.originalSize = (int) jmin ((
size_t) maximumTimeInSamples, block.
getNumSamples());
702 for (
auto channel = 0; channel < currentInfo.originalNumChannels; ++channel)
703 temporaryBuffer.copyFrom (channel, 0, block.
getChannelPointer ((
size_t) channel), (int) currentInfo.originalSize);
710 for (
auto* e : engines)
713 mustInterpolate =
false;
725 size_t numChannels = jmin (input.
getNumChannels(), (size_t) (currentInfo.wantsStereo ? 2 : 1));
728 if (mustInterpolate ==
false)
730 for (
size_t channel = 0; channel < numChannels; ++channel)
737 for (
size_t channel = 0; channel < numChannels; ++channel)
744 changeVolumes[channel].applyGain (buffer.getChannelPointer (0), (int) numSamples);
746 auto* interPtr = interpolationBuffer.getWritePointer (0);
747 engines[(int) channel + 2]->
processSamples (interPtr, interPtr, numSamples);
748 changeVolumes[channel + 2].applyGain (interPtr, (
int) numSamples);
750 buffer += interpolated;
753 if (input.
getNumChannels() > 1 && currentInfo.wantsStereo ==
false)
757 changeVolumes[1].applyGain (buffer.getChannelPointer (0), (int) numSamples);
758 changeVolumes[3].applyGain (buffer.getChannelPointer (0), (int) numSamples);
761 if (changeVolumes[0].isSmoothing() ==
false)
763 mustInterpolate =
false;
765 for (
auto channel = 0; channel < 2; ++channel)
770 if (input.
getNumChannels() > 1 && currentInfo.wantsStereo ==
false)
775 const int64 maximumTimeInSamples = 10 * 96000;
784 if (changeLevel == 2)
786 loadImpulseResponse();
788 if (isThreadRunning() && threadShouldExit())
792 processImpulseResponse();
794 if (isThreadRunning() && threadShouldExit())
797 initializeConvolutionEngines();
801 void loadImpulseResponse()
803 if (currentInfo.sourceType == SourceType::sourceBinaryData)
805 if (! (copyAudioStreamInAudioBuffer (
new MemoryInputStream (currentInfo.sourceData, (
size_t) currentInfo.sourceDataSize,
false))))
808 else if (currentInfo.sourceType == SourceType::sourceAudioFile)
810 if (! (copyAudioStreamInAudioBuffer (
new FileInputStream (currentInfo.fileImpulseResponse))))
813 else if (currentInfo.sourceType == SourceType::sourceAudioBuffer)
815 copyBufferFromTemporaryLocation();
822 void processImpulseResponse()
824 trimAndResampleImpulseResponse (currentInfo.originalNumChannels, currentInfo.originalSampleRate, currentInfo.wantsTrimming);
826 if (isThreadRunning() && threadShouldExit())
829 if (currentInfo.wantsNormalisation)
831 if (currentInfo.originalNumChannels > 1)
833 normaliseImpulseResponse (currentInfo.buffer->getWritePointer (0), (int) currentInfo.finalSize, 1.0);
834 normaliseImpulseResponse (currentInfo.buffer->getWritePointer (1), (int) currentInfo.finalSize, 1.0);
838 normaliseImpulseResponse (currentInfo.buffer->getWritePointer (0), (int) currentInfo.finalSize, 1.0);
842 if (currentInfo.originalNumChannels == 1)
843 currentInfo.buffer->copyFrom (1, 0, *currentInfo.buffer, 0, 0, (
int) currentInfo.finalSize);
849 bool copyAudioStreamInAudioBuffer (
InputStream* stream)
853 std::unique_ptr<AudioFormatReader> formatReader (manager.
createReaderFor (stream));
855 if (formatReader !=
nullptr)
857 currentInfo.originalNumChannels = formatReader->numChannels > 1 ? 2 : 1;
858 currentInfo.originalSampleRate = formatReader->sampleRate;
859 currentInfo.originalSize =
static_cast<int> (jmin (maximumTimeInSamples, formatReader->lengthInSamples));
861 impulseResponseOriginal.clear();
862 formatReader->read (&(impulseResponseOriginal), 0, (
int) currentInfo.originalSize, 0,
true, currentInfo.originalNumChannels > 1);
873 void copyBufferFromTemporaryLocation()
877 for (
auto channel = 0; channel < currentInfo.originalNumChannels; ++channel)
878 impulseResponseOriginal.copyFrom (channel, 0, temporaryBuffer, channel, 0, (
int) currentInfo.originalSize);
882 void trimAndResampleImpulseResponse (
int numChannels,
double srcSampleRate,
bool mustTrim)
886 auto indexEnd = currentInfo.originalSize - 1;
890 indexStart = currentInfo.originalSize - 1;
893 for (
auto channel = 0; channel < numChannels; ++channel)
895 auto localIndexStart = 0;
896 auto localIndexEnd = currentInfo.originalSize - 1;
898 auto* channelData = impulseResponseOriginal.getReadPointer (channel);
900 while (localIndexStart < currentInfo.originalSize - 1
901 && channelData[localIndexStart] <= thresholdTrim
902 && channelData[localIndexStart] >= -thresholdTrim)
905 while (localIndexEnd >= 0
906 && channelData[localIndexEnd] <= thresholdTrim
907 && channelData[localIndexEnd] >= -thresholdTrim)
910 indexStart = jmin (indexStart, localIndexStart);
911 indexEnd = jmax (indexEnd, localIndexEnd);
916 for (
auto channel = 0; channel < numChannels; ++channel)
918 auto* channelData = impulseResponseOriginal.getWritePointer (channel);
920 for (
auto i = 0; i < indexEnd - indexStart + 1; ++i)
921 channelData[i] = channelData[i + indexStart];
923 for (
auto i = indexEnd - indexStart + 1; i < currentInfo.originalSize - 1; ++i)
924 channelData[i] = 0.0f;
929 if (currentInfo.sampleRate == srcSampleRate)
932 currentInfo.finalSize = jmin (static_cast<int> (currentInfo.wantedSize), indexEnd - indexStart + 1);
934 impulseResponse.clear();
936 for (
auto channel = 0; channel < numChannels; ++channel)
937 impulseResponse.copyFrom (channel, 0, impulseResponseOriginal, channel, 0, (
int) currentInfo.finalSize);
942 auto factorReading = srcSampleRate / currentInfo.sampleRate;
943 currentInfo.finalSize = jmin (static_cast<int> (currentInfo.wantedSize), roundToInt ((indexEnd - indexStart + 1) / factorReading));
945 impulseResponse.clear();
951 resamplingSource.
prepareToPlay ((
int) currentInfo.finalSize, currentInfo.sampleRate);
955 info.
numSamples = (int) currentInfo.finalSize;
956 info.
buffer = &impulseResponse;
962 if (numChannels == 1)
963 impulseResponse.copyFrom (1, 0, impulseResponse, 0, 0, (
int) currentInfo.finalSize);
967 void normaliseImpulseResponse (
float* samples,
int numSamples,
double factorResampling)
const 969 auto magnitude = 0.0f;
971 for (
auto i = 0; i < numSamples; ++i)
972 magnitude += samples[i] * samples[i];
974 auto magnitudeInv = 1.0f / (4.0f * std::sqrt (magnitude)) * 0.5f * static_cast <float> (factorResampling);
976 for (
auto i = 0; i < numSamples; ++i)
977 samples[i] *= magnitudeInv;
984 void initializeConvolutionEngines()
986 if (currentInfo.maximumBufferSize == 0)
989 if (changeLevel == 3)
991 for (
auto i = 0; i < 2; ++i)
994 mustInterpolate =
false;
998 for (
auto i = 0; i < 2; ++i)
1000 engines[i + 2]->initializeConvolutionEngine (currentInfo, i);
1001 engines[i + 2]->reset();
1003 if (isThreadRunning() && threadShouldExit())
1007 for (
auto i = 0; i < 2; ++i)
1009 changeVolumes[i].setTargetValue (1.0f);
1010 changeVolumes[i].reset (currentInfo.sampleRate, 0.05);
1011 changeVolumes[i].setTargetValue (0.0f);
1013 changeVolumes[i + 2].setTargetValue (0.0f);
1014 changeVolumes[i + 2].reset (currentInfo.sampleRate, 0.05);
1015 changeVolumes[i + 2].setTargetValue (1.0f);
1019 mustInterpolate =
true;
1025 static constexpr
int fifoSize = 1024;
1034 int changeLevel = 0;
1037 ConvolutionEngine::ProcessingInformation currentInfo;
1051 bool mustInterpolate =
false;
1054 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (
Pimpl)
1061 pimpl.reset (
new Pimpl());
1062 pimpl->addToFifo (Convolution::Pimpl::ChangeRequest::changeEngine,
juce::var (0));
1070 bool wantsStereo,
bool wantsTrimming,
size_t size,
1071 bool wantsNormalisation)
1073 if (sourceData ==
nullptr)
1076 auto maximumSamples = (size_t) pimpl->maximumTimeInSamples;
1077 auto wantedSize = (size == 0 ? maximumSamples : jmin (size, maximumSamples));
1079 Pimpl::ChangeRequest types[] = { Pimpl::ChangeRequest::changeSource,
1080 Pimpl::ChangeRequest::changeImpulseResponseSize,
1081 Pimpl::ChangeRequest::changeStereo,
1082 Pimpl::ChangeRequest::changeTrimming,
1083 Pimpl::ChangeRequest::changeNormalisation };
1087 sourceParameter.
add (
juce::var ((
int) ConvolutionEngine::ProcessingInformation::SourceType::sourceBinaryData));
1088 sourceParameter.
add (
juce::var (sourceData, sourceDataSize));
1091 juce::var (static_cast<int64> (wantedSize)),
1096 pimpl->addToFifo (types, parameters, 5);
1100 bool wantsTrimming,
size_t size,
bool wantsNormalisation)
1105 auto maximumSamples = (size_t) pimpl->maximumTimeInSamples;
1106 auto wantedSize = (size == 0 ? maximumSamples : jmin (size, maximumSamples));
1108 Pimpl::ChangeRequest types[] = { Pimpl::ChangeRequest::changeSource,
1109 Pimpl::ChangeRequest::changeImpulseResponseSize,
1110 Pimpl::ChangeRequest::changeStereo,
1111 Pimpl::ChangeRequest::changeTrimming,
1112 Pimpl::ChangeRequest::changeNormalisation };
1116 sourceParameter.
add (
juce::var ((
int) ConvolutionEngine::ProcessingInformation::SourceType::sourceAudioFile));
1120 juce::var (static_cast<int64> (wantedSize)),
1125 pimpl->addToFifo (types, parameters, 5);
1129 double bufferSampleRate,
bool wantsStereo,
bool wantsTrimming,
bool wantsNormalisation,
size_t size)
1131 copyAndLoadImpulseResponseFromBlock (
AudioBlock<float> (buffer), bufferSampleRate,
1132 wantsStereo, wantsTrimming, wantsNormalisation, size);
1136 bool wantsStereo,
bool wantsTrimming,
bool wantsNormalisation,
size_t size)
1138 jassert (bufferSampleRate > 0);
1143 auto maximumSamples = (size_t) pimpl->maximumTimeInSamples;
1144 auto wantedSize = (size == 0 ? maximumSamples : jmin (size, maximumSamples));
1146 pimpl->copyBufferToTemporaryLocation (block);
1148 Pimpl::ChangeRequest types[] = { Pimpl::ChangeRequest::changeSource,
1149 Pimpl::ChangeRequest::changeImpulseResponseSize,
1150 Pimpl::ChangeRequest::changeStereo,
1151 Pimpl::ChangeRequest::changeTrimming,
1152 Pimpl::ChangeRequest::changeNormalisation };
1155 sourceParameter.
add (
juce::var ((
int) ConvolutionEngine::ProcessingInformation::SourceType::sourceAudioBuffer));
1159 juce::var (static_cast<int64> (wantedSize)),
1164 pimpl->addToFifo (types, parameters, 5);
1169 jassert (isPositiveAndBelow (spec.
numChannels, static_cast<uint32> (3)));
1171 Pimpl::ChangeRequest types[] = { Pimpl::ChangeRequest::changeSampleRate,
1172 Pimpl::ChangeRequest::changeMaximumBufferSize };
1177 pimpl->addToFifo (types, parameters, 2);
1180 for (
size_t channel = 0; channel < spec.
numChannels; ++channel)
1182 volumeDry[channel].reset (spec.
sampleRate, 0.05);
1183 volumeWet[channel].reset (spec.
sampleRate, 0.05);
1206 jassert (isPositiveAndBelow (input.
getNumChannels(),
static_cast<size_t> (3)));
1211 auto dry = dryBuffer.getSubsetChannelBlock (0, numChannels);
1213 if (volumeDry[0].isSmoothing())
1215 dry.copyFrom (input);
1217 for (
size_t channel = 0; channel < numChannels; ++channel)
1218 volumeDry[channel].applyGain (dry.getChannelPointer (channel), (int) numSamples);
1220 pimpl->processSamples (input, output);
1222 for (
size_t channel = 0; channel < numChannels; ++channel)
1223 volumeWet[channel].applyGain (output.
getChannelPointer (channel), (int) numSamples);
1229 if (! currentIsBypassed)
1230 pimpl->processSamples (input, output);
1232 if (isBypassed != currentIsBypassed)
1234 currentIsBypassed = isBypassed;
1236 for (
size_t channel = 0; channel < numChannels; ++channel)
1238 volumeDry[channel].setTargetValue (isBypassed ? 0.0f : 1.0f);
1239 volumeDry[channel].reset (sampleRate, 0.05);
1240 volumeDry[channel].setTargetValue (isBypassed ? 1.0f : 0.0f);
1242 volumeWet[channel].setTargetValue (isBypassed ? 1.0f : 0.0f);
1243 volumeWet[channel].reset (sampleRate, 0.05);
1244 volumeWet[channel].setTargetValue (isBypassed ? 0.0f : 1.0f);
AudioBlock & copyFrom(const AudioBlock< OtherSampleType > &src) noexcept
void initializeConvolutionEngine(ProcessingInformation &info, int channel)
void prepareToPlay(int samplesPerBlockExpected, double sampleRate) override
void getNextAudioBlock(const AudioSourceChannelInfo &) override
static Type decibelsToGain(Type decibels, Type minusInfinityDb=Type(defaultMinusInfinitydB))
static void JUCE_CALLTYPE add(float *dest, float amountToAdd, int numValues) noexcept
static void JUCE_CALLTYPE copy(float *dest, const float *src, int numValues) noexcept
void add(const ElementType &newElement)
void setSize(int newNumChannels, int newNumSamples, bool keepExistingContent=false, bool clearExtraSpace=false, bool avoidReallocating=false)
AudioBlock getSingleChannelBlock(size_t channel) const noexcept
static void JUCE_CALLTYPE fill(float *dest, float valueToFill, int numValues) noexcept
void initProcessing(int maximumBufferSize)
void loadImpulseResponse(const void *sourceData, size_t sourceDataSize, bool wantsStereo, bool wantsTrimming, size_t size, bool wantsNormalisation=true)
void convolutionProcessingAndAccumulate(const float *input, const float *impulse, float *output)
void copyStateFromOtherEngine(const ConvolutionEngine &other)
constexpr size_t getNumSamples() const noexcept
int getNumRemainingEntries() const noexcept
void processSamples(const float *input, float *output, size_t numSamples)
void processSamples(const AudioBlock< const float > &input, AudioBlock< float > &output)
static void JUCE_CALLTYPE subtractWithMultiply(float *dest, const float *src, float multiplier, int numValues) noexcept
void updateSymmetricFrequencyDomainData(float *samples) noexcept
bool existsAsFile() const
void readFromFifo(ChangeRequest &type, juce::var ¶meter)
void copyAndLoadImpulseResponseFromBuffer(AudioBuffer< float > &buffer, double bufferSampleRate, bool wantsStereo, bool wantsTrimming, bool wantsNormalisation, size_t size)
void addToFifo(ChangeRequest type, juce::var parameter)
AudioBuffer< float > * buffer
void setResamplingRatio(double samplesInPerOutputSample)
static void JUCE_CALLTYPE addWithMultiply(float *dest, const float *src, float multiplier, int numValues) noexcept
void addToFifo(ChangeRequest *types, juce::var *parameters, int numEntries)
void setSample(int destChannel, int destSample, Type newValue) noexcept
SampleType * getChannelPointer(size_t channel) const noexcept
void prepareForConvolution(float *samples) noexcept
constexpr size_t getNumChannels() const noexcept
void copyBufferToTemporaryLocation(dsp::AudioBlock< float > block)
const String & getFullPathName() const noexcept
void prepare(const ProcessSpec &)
void copyAndLoadImpulseResponseFromBlock(AudioBlock< float > block, double bufferSampleRate, bool wantsStereo, bool wantsTrimming, bool wantsNormalisation, size_t size)