12namespace tracktion {
inline namespace engine
19 auto um = getUndoManager();
25 highPassCutoffValue.
referTo (state, IDs::highPassFrequency, um, frequencyRange.start);
26 lowPassCutoffValue.
referTo (state, IDs::lowPassFrequency, um, frequencyRange.
end);
27 gainValue.
referTo (state, IDs::gain, um, 0.0f);
28 mixValue.
referTo (state, IDs::mix, um, 1.0f);
38 gainParam = addParam (IDs::gain.toString(),
TRANS (
"Gain"), volumeRange,
40 [] (
const juce::String& s) {
return s.getFloatValue(); });
41 gainParam->attachToCurrentValue (gainValue);
44 [] (
float value) {
return juce::String (midiNoteToFrequency (value), 1) +
" Hz"; },
45 [] (
const juce::String& s) {
return frequencyToMidiNote (s.getFloatValue()); });
49 [] (
float value) {
return juce::String (midiNoteToFrequency (value), 1) +
" Hz"; },
50 [] (
const juce::String& s) {
return frequencyToMidiNote (s.getFloatValue()); });
53 mixParam = addParam (IDs::mix.toString(),
TRANS(
"Mix"), { 0.0f, 1.0f, 0.0f },
56 mixParam->attachToCurrentValue (mixValue);
58 filterQParam = addParam (IDs::filterQ.toString(),
TRANS(
"Filter Q"), { 0.1f, 14.0f, 0.0f },
60 [] (
const juce::String& s) {
return s.getFloatValue(); });
63 loadImpulseResponseFromState();
68 notifyListenersOfDeletion();
76const char* ImpulseResponsePlugin::getPluginName() {
return NEEDS_TRANS (
"Impulse Response"); }
87 reader->read (&buffer, 0, buffer.
getNumSamples(), 0,
true,
true);
89 return loadImpulseResponse (std::move (buffer), reader->sampleRate, (
int) reader->bitsPerSample);
106 double sampleRateToStore,
114 (
unsigned int) bufferImpulseResponse.getNumChannels(),
119 if (writer->writeFromAudioSampleBuffer (bufferImpulseResponse, 0, bufferImpulseResponse.getNumSamples()))
122 state.
setProperty (IDs::irFileData,
juce::var (std::move (fileDataMemoryBlock)), getUndoManager());
133juce::String ImpulseResponsePlugin::getShortName (
int) {
return "IR"; }
134juce::String ImpulseResponsePlugin::getPluginType() {
return xmlTypeName; }
135bool ImpulseResponsePlugin::needsConstantBufferSize() {
return false; }
138double ImpulseResponsePlugin::getLatencySeconds()
140 return processorChain.
get<convolutionIndex>().getLatency() / sampleRate;
149 processorChain.
prepare (processSpec);
157 const auto wetDry = getWetDryLevels (
mixParam->getCurrentValue());
161 const double smoothTime = 0.01;
162 lowFreqSmoother.
reset (info.sampleRate, smoothTime);
163 highFreqSmoother.
reset (info.sampleRate, smoothTime);
164 gainSmoother.
reset (info.sampleRate, smoothTime);
165 qSmoother.
reset (info.sampleRate, smoothTime);
166 wetGainSmoother.
reset (info.sampleRate, smoothTime);
167 dryGainSmoother.
reset (info.sampleRate, smoothTime);
175 processorChain.
reset();
186 const auto wetDryGain = getWetDryLevels (
mixParam->getCurrentValue());
191 auto hpf = processorChain.
get<HPFIndex>().state;
192 auto& lpf = processorChain.
get<LPFIndex>().state;
193 auto& gain = processorChain.
get<gainIndex>();
199 const int blockSize = 32;
201 int numSamplesDone = 0;
205 const int numThisTime =
std::min (blockSize, numSamplesLeft);
210 juce::dsp::ProcessContextReplacing <float> context (inOutBlock);
211 processorChain.
process (context);
214 const auto qFactor = qSmoother.
skip (numThisTime);
219 numSamplesDone += numThisTime;
220 numSamplesLeft -= blockSize;
235 juce::dsp::ProcessContextReplacing <float> context (inOutBlock);
236 processorChain.
process (context);
242 dryGainSmoother.
applyGain (dryBuffer.buffer, dryBuffer.buffer.getNumSamples());
254void ImpulseResponsePlugin::restorePluginStateFromValueTree (
const juce::ValueTree& v)
256 copyPropertiesToCachedValues (v, gainValue, highPassCutoffValue, lowPassCutoffValue, mixValue, qValue);
258 state.
setProperty (IDs::name, v[IDs::name], getUndoManager());
260 if (
auto irFileData = v.getProperty (IDs::irFileData).getBinaryData())
263 for (
auto p : getAutomatableParameters())
264 p->updateFromAttachedValue();
268void ImpulseResponsePlugin::loadImpulseResponseFromState()
275 .createReaderFor (is.release(),
true)))
278 reader->read (&loadIRBuffer, 0, (
int) reader->lengthInSamples, 0,
true,
true);
280 jassert (reader->numChannels > 0);
283 reader->numChannels > 1 ? juce::dsp::Convolution::Stereo::yes
284 : juce::dsp::Convolution::Stereo::no,
286 : juce::dsp::Convolution::Trim::no,
287 normalise.
get() ? juce::dsp::Convolution::Normalise::yes
288 : juce::dsp::Convolution::Normalise::no);
297 if (
id == IDs::irFileData ||
id == IDs::normalise ||
id == IDs::trimSilence)
298 loadImpulseResponseFromState();
302 Plugin::valueTreePropertyChanged (v,
id);
int getNumChannels() const noexcept
int getNumSamples() const noexcept
void addFrom(int destChannel, int destStartSample, const AudioBuffer &source, int sourceChannel, int sourceStartSample, int numSamples, Type gainToApplyToSource=Type(1)) noexcept
void referTo(ValueTree &tree, const Identifier &property, UndoManager *um)
Type get() const noexcept
static Type decibelsToGain(Type decibels, Type minusInfinityDb=Type(defaultMinusInfinitydB))
static String toString(Type decibels, int decimalPlaces=2, Type minusInfinityDb=Type(defaultMinusInfinitydB), bool shouldIncludeSuffix=true, StringRef customMinusInfinityString={})
bool loadFileAsData(MemoryBlock &result) const
void * getData() noexcept
size_t getSize() const noexcept
void setSkewForCentre(ValueType centrePointValue) noexcept
bool isSmoothing() const noexcept
void applyGain(FloatType *samples, int numSamples) noexcept
FloatType getCurrentValue() const noexcept
FloatType skip(int numSamples) noexcept
void reset(double sampleRate, double rampLengthInSeconds) noexcept
void setTargetValue(FloatType newValue) noexcept
float getFloatValue() const noexcept
ValueTree & setProperty(const Identifier &name, const var &newValue, UndoManager *undoManager)
const var & getProperty(const Identifier &name) const noexcept
Iterator end() const noexcept
AudioBlock getSubBlock(size_t newOffset, size_t newLength) const noexcept
void prepare(const ProcessSpec &spec)
void process(const ProcessContext &context) noexcept
MemoryBlock * getBinaryData() const noexcept
An audio scratch buffer that has pooled storage.
AudioFileFormatManager & getAudioFileFormatManager() const
Returns the AudioFileFormatManager that maintains a list of available audio file formats.
bool loadImpulseResponse(const void *sourceData, size_t sourceDataSize)
Loads an impulse from binary audio file data i.e.
AutomatableParameter::Ptr gainParam
Parameter for the gain to apply.
AutomatableParameter::Ptr mixParam
Parameter for the mix control, 0.0 = dry, 1.0 = wet.
juce::CachedValue< juce::String > name
A name property.
~ImpulseResponsePlugin() override
Destructor.
juce::String getSelectableDescription() override
Subclasses must return a description of what they are.
juce::String getName() const override
The name of the type, e.g.
void applyToBuffer(const PluginRenderContext &) override
Process the next block of data.
ImpulseResponsePlugin(PluginCreationInfo)
Creates an ImpulseResponsePlugin.
void deinitialise() override
Called after play stops to release resources.
AutomatableParameter::Ptr lowPassCutoffParam
Cutoff frequency for the low pass filter to applied after the IR.
AutomatableParameter::Ptr filterQParam
Parameter for the Q factor of the high pass and low pass filters.
juce::CachedValue< bool > normalise
Normalise the IR file when loading from the state.
AutomatableParameter::Ptr highPassCutoffParam
Cutoff frequency for the high pass filter to applied after the IR.
juce::CachedValue< bool > trimSilence
Trim silence from the IR file when loading from the state.
void reset() override
Should reset synth voices, tails, clear delay buffers, etc.
#define TRANS(stringLiteral)
#define NEEDS_TRANS(stringLiteral)
int roundToInt(const FloatType value) noexcept
Passed into Plugins when they are being initialised, to give them useful contextual information that ...
static std::array< NumericType, 6 > makeHighPass(double sampleRate, NumericType frequency)
static std::array< NumericType, 6 > makeLowPass(double sampleRate, NumericType frequency)
The context passed to plugin render methods to provide it with buffers to fill.
int bufferNumSamples
The number of samples to write into the audio buffer.
juce::AudioBuffer< float > * destBuffer
The target audio buffer which needs to be filled.
int bufferStartSample
The index of the start point in the audio buffer from which data must be written.