void Processor::clearConvolvers() { { juce::ScopedLock convolverLock(_convolverMutex); _reverse = false; _predelayMs = 0.0; _stretch = 1.0; _irBegin = 0.0; _irEnd = 1.0; _attackLength = 0.0; _attackShape = 0.0; _decayShape = 0.0; } setParameterNotifyingHost(Parameters::EqLowCutFreq, Parameters::EqLowCutFreq.getDefaultValue()); setParameterNotifyingHost(Parameters::EqLowShelfFreq, Parameters::EqLowShelfFreq.getDefaultValue()); setParameterNotifyingHost(Parameters::EqLowShelfDecibels, Parameters::EqLowShelfDecibels.getDefaultValue()); setParameterNotifyingHost(Parameters::EqHighCutFreq, Parameters::EqHighCutFreq.getDefaultValue()); setParameterNotifyingHost(Parameters::EqHighShelfFreq, Parameters::EqHighShelfFreq.getDefaultValue()); setParameterNotifyingHost(Parameters::EqHighShelfDecibels, Parameters::EqHighShelfDecibels.getDefaultValue()); setParameterNotifyingHost(Parameters::StereoWidth, Parameters::StereoWidth.getDefaultValue()); for (size_t i=0; i<_agents.size(); ++i) { _agents[i]->clear(); } notifyAboutChange(); updateConvolvers(); }
//============================================================================== void Processor::prepareToPlay(double /*sampleRate*/, int samplesPerBlock) { // Play safe to be clean releaseResources(); // Prepare convolvers { juce::ScopedLock convolverLock(_convolverMutex); _convolverHeadBlockSize = 1; while (_convolverHeadBlockSize < static_cast<size_t>(samplesPerBlock)) { _convolverHeadBlockSize *= 2; } _convolverTailBlockSize = std::max(size_t(8192), 2 * _convolverHeadBlockSize); } // Prepare convolution buffers _wetBuffer.setSize(2, samplesPerBlock); _convolutionBuffer.resize(samplesPerBlock); // Initialize parameters _stereoWidth.initializeWidth(getParameter(Parameters::StereoWidth)); // Initialize IR agents for (size_t i=0; i<_agents.size(); ++i) { _agents[i]->initialize(); } notifyAboutChange(); updateConvolvers(); }
void Processor::setIREnd(double irEnd) { bool changed = false; bool irChanged = false; { juce::ScopedLock convolverLock(_convolverMutex); double irEndClamped = std::min(1.0, std::max(_irBegin, irEnd)); if (::fabs(irEndClamped-irEnd) > 0.0001) { changed = true; } if (::fabs(_irEnd-irEndClamped) > 0.0001) { _irEnd = irEndClamped; changed = true; irChanged = true; } } if (changed) { notifyAboutChange(); } if (irChanged) { updateConvolvers(); } }
void IRAgent::setConvolver(Convolver* convolver) { ScopedPointer<Convolver> conv(convolver); { // Make sure that the convolver mutex is locked as short as // possible and that all destruction and deallocation happens // outside of the lock because this might block the audio thread ScopedLock convolverLock(_convolverMutex); if (_convolver != conv) { _convolver.swapWith(conv); } } conv = nullptr; }
double Processor::getMaxFileDuration() const { juce::ScopedLock convolverLock(_convolverMutex); double maxDuration = 0.0; for (auto it=_agents.begin(); it!=_agents.end(); ++it) { const size_t sampleCount = (*it)->getFileSampleCount(); const double sampleRate = (*it)->getFileSampleRate(); const double duration = static_cast<double>(sampleCount) / sampleRate; if (duration > maxDuration) { maxDuration = duration; } } return maxDuration; }
void Processor::setPredelayMs(double predelayMs) { bool changed = false; { juce::ScopedLock convolverLock(_convolverMutex); if (_predelayMs != predelayMs) { _predelayMs = predelayMs; changed = true; } } if (changed) { notifyAboutChange(); updateConvolvers(); } }
void Processor::setReverse(bool reverse) { bool changed = false; { juce::ScopedLock convolverLock(_convolverMutex); if (_reverse != reverse) { _reverse = reverse; changed = true; } } if (changed) { notifyAboutChange(); updateConvolvers(); } }
void Processor::setDecayShape(double shape) { bool changed = false; { juce::ScopedLock convolverLock(_convolverMutex); if (_decayShape != shape) { _decayShape = shape; changed = true; } } if (changed) { notifyAboutChange(); updateConvolvers(); } }
void Processor::setStretch(double stretch) { bool changed = false; { juce::ScopedLock convolverLock(_convolverMutex); if (::fabs(_stretch-stretch) > 0.000001) { _stretch = stretch; changed = true; } } if (changed) { notifyAboutChange(); updateConvolvers(); } }
void Processor::setAttackLength(double length) { bool changed = false; length = std::max(0.0, std::min(1.0, length)); { juce::ScopedLock convolverLock(_convolverMutex); if (_attackLength != length) { _attackLength = length; changed = true; } } if (changed) { notifyAboutChange(); updateConvolvers(); } }
void IRAgent::resetIR(const FloatBuffer::Ptr& irBuffer, Convolver* convolver) { { ScopedLock lock(_mutex); _irBuffer = irBuffer; } { ScopedPointer<Convolver> conv(convolver); { // Make sure that the convolver mutex is locked as short as // possible and that all destruction and deallocation happens // outside of the lock because this might block the audio thread ScopedLock convolverLock(_convolverMutex); if (_convolver != conv) { _convolver.swapWith(conv); } } } propagateChange(); }
size_t Processor::getConvolverTailBlockSize() const { juce::ScopedLock convolverLock(_convolverMutex); return _convolverTailBlockSize; }
double Processor::getPredelayMs() const { juce::ScopedLock convolverLock(_convolverMutex); return _predelayMs; }
void IRAgent::process(const float* input, float* output, size_t len) { const float Epsilon = 0.0001f; // This is the hopefully one and only rare exception where we need to // lock a mutex in the realtime audio thread :-/ (however, the according // convolver mutex is locked somewhere else only once for a very short and // rare swapping operation, so this shouldn't be a problem, and most operating // systems internally try spinning before performing an expensive context switch, // so we will never give up the context here probably). juce::ScopedLock convolverLock(_convolverMutex); if (_convolver && (_fadeFactor > Epsilon || ::fabs(_fadeIncrement) > Epsilon)) { _convolver->process(input, output, len); if (::fabs(_fadeIncrement) > Epsilon || _fadeFactor < (1.0-Epsilon)) { for (size_t i=0; i<len; ++i) { _fadeFactor = std::max(0.0f, std::min(1.0f, _fadeFactor+_fadeIncrement)); output[i] *= _fadeFactor; } if (_fadeFactor < Epsilon || _fadeFactor > (1.0-Epsilon)) { _fadeIncrement = 0.0; } } } else { ::memset(output, 0, len * sizeof(float)); _fadeFactor = 0.0; _fadeIncrement = 0.0; } // EQ low const int eqLowType = _processor.getParameter(Parameters::EqLowType); if (eqLowType == Parameters::Cut) { const float eqLowCutFreq = _processor.getParameter(Parameters::EqLowCutFreq); if (::fabs(eqLowCutFreq-Parameters::EqLowCutFreq.getMinValue()) > 0.0001f) { _eqLo.setType(CookbookEq::HiPass2); _eqLo.setFreq(eqLowCutFreq); _eqLo.filterOut(output, len); } } else if (eqLowType == Parameters::Shelf) { const float eqLowShelfDecibels = _processor.getParameter(Parameters::EqLowShelfDecibels); if (::fabs(eqLowShelfDecibels-0.0f) > 0.0001f) { _eqLo.setType(CookbookEq::LoShelf); _eqLo.setFreq(_processor.getParameter(Parameters::EqLowShelfFreq)); _eqLo.setGain(eqLowShelfDecibels); _eqLo.filterOut(output, len); } } // EQ high const int eqHighType = _processor.getParameter(Parameters::EqHighType); if (eqHighType == Parameters::Cut) { const float eqHighCutFreq = _processor.getParameter(Parameters::EqHighCutFreq); if (::fabs(eqHighCutFreq-Parameters::EqHighCutFreq.getMaxValue()) > 0.0001f) { _eqHi.setType(CookbookEq::LoPass2); _eqHi.setFreq(eqHighCutFreq); _eqHi.filterOut(output, len); } } else if (eqHighType == Parameters::Shelf) { const float eqHighShelfDecibels = _processor.getParameter(Parameters::EqHighShelfDecibels); if (::fabs(eqHighShelfDecibels-0.0f) > 0.0001f) { _eqHi.setType(CookbookEq::HiShelf); _eqHi.setFreq(_processor.getParameter(Parameters::EqHighShelfFreq)); _eqHi.setGain(eqHighShelfDecibels); _eqHi.filterOut(output, len); } } }
double Processor::getIREnd() const { juce::ScopedLock convolverLock(_convolverMutex); return _irEnd; }
double Processor::getIRBegin() const { juce::ScopedLock convolverLock(_convolverMutex); return _irBegin; }
double Processor::getDecayShape() const { juce::ScopedLock convolverLock(_convolverMutex); return _decayShape; }
double Processor::getStretch() const { juce::ScopedLock convolverLock(_convolverMutex); return _stretch; }
double Processor::getAttackShape() const { juce::ScopedLock convolverLock(_convolverMutex); return _attackShape; }
bool Processor::getReverse() const { juce::ScopedLock convolverLock(_convolverMutex); return _reverse; }