Browse Source

DSP: Made trimming of the convolution impulse response optional

tags/2021-05-28
hogliux 8 years ago
parent
commit
7a34790388
6 changed files with 91 additions and 55 deletions
  1. +2
    -2
      examples/DSP module plugin demo/Source/PluginProcessor.cpp
  2. +3
    -3
      examples/DSPDemo/JuceLibraryCode/BinaryData.cpp
  3. +1
    -1
      examples/DSPDemo/JuceLibraryCode/BinaryData.h
  4. +2
    -2
      examples/DSPDemo/Source/Demos/ConvolutionDemo.cpp
  5. +77
    -44
      modules/juce_dsp/frequency/juce_Convolution.cpp
  6. +6
    -3
      modules/juce_dsp/frequency/juce_Convolution.h

+ 2
- 2
examples/DSP module plugin demo/Source/PluginProcessor.cpp View File

@@ -240,9 +240,9 @@ void DspModulePluginDemoAudioProcessor::updateParameters()
auto maxSize = static_cast<size_t> (roundDoubleToInt (8192 * getSampleRate() / 44100));
if (type == 0)
convolution.loadImpulseResponse (BinaryData::Impulse1_wav, BinaryData::Impulse1_wavSize, false, maxSize);
convolution.loadImpulseResponse (BinaryData::Impulse1_wav, BinaryData::Impulse1_wavSize, false, true, maxSize);
else
convolution.loadImpulseResponse (BinaryData::Impulse2_wav, BinaryData::Impulse2_wavSize, false, maxSize);
convolution.loadImpulseResponse (BinaryData::Impulse2_wav, BinaryData::Impulse2_wavSize, false, true, maxSize);
}
cabinetIsBypassed = ! cabinetSimParam->get();


+ 3
- 3
examples/DSPDemo/JuceLibraryCode/BinaryData.cpp View File

@@ -1565,11 +1565,11 @@ static const unsigned char temp_binary_data_3[] =
" if (cabinetTypeParameter->getCurrentSelectedID() == 2)\r\n"
" convolution.loadImpulseResponse (BinaryData::guitar_amp_wav,\r\n"
" BinaryData::guitar_amp_wavSize,\r\n"
" false, maxSize);\r\n"
" false, true, maxSize);\r\n"
" else\r\n"
" convolution.loadImpulseResponse (BinaryData::cassette_recorder_wav,\r\n"
" BinaryData::cassette_recorder_wavSize,\r\n"
" false, maxSize);\r\n"
" false, true, maxSize);\r\n"
" }\r\n"
" }\r\n"
" }\r\n"
@@ -2325,7 +2325,7 @@ const char* getNamedResource (const char* resourceNameUTF8, int& numBytes) throw
case 0x409ff6ec: numBytes = 37902; return cassette_recorder_wav;
case 0x69523d16: numBytes = 628; return EditorColourScheme_xml;
case 0x700ccf3c: numBytes = 90246; return guitar_amp_wav;
case 0x5922ccdf: numBytes = 2999; return ConvolutionDemo_cpp;
case 0x5922ccdf: numBytes = 3011; return ConvolutionDemo_cpp;
case 0x14aa0aae: numBytes = 2674; return FIRFilterDemo_cpp;
case 0xab621a06: numBytes = 1809; return GainDemo_cpp;
case 0x06a7a4b1: numBytes = 2819; return IIRFilterDemo_cpp;


+ 1
- 1
examples/DSPDemo/JuceLibraryCode/BinaryData.h View File

@@ -18,7 +18,7 @@ namespace BinaryData
const int guitar_amp_wavSize = 90246;
extern const char* ConvolutionDemo_cpp;
const int ConvolutionDemo_cppSize = 2999;
const int ConvolutionDemo_cppSize = 3011;
extern const char* FIRFilterDemo_cpp;
const int FIRFilterDemo_cppSize = 2674;


+ 2
- 2
examples/DSPDemo/Source/Demos/ConvolutionDemo.cpp View File

@@ -65,11 +65,11 @@ struct ConvolutionDemo
if (cabinetTypeParameter->getCurrentSelectedID() == 2)
convolution.loadImpulseResponse (BinaryData::guitar_amp_wav,
BinaryData::guitar_amp_wavSize,
false, maxSize);
false, true, maxSize);
else
convolution.loadImpulseResponse (BinaryData::cassette_recorder_wav,
BinaryData::cassette_recorder_wavSize,
false, maxSize);
false, true, maxSize);
}
}
}


+ 77
- 44
modules/juce_dsp/frequency/juce_Convolution.cpp View File

@@ -54,6 +54,7 @@ struct ConvolutionEngine
double sampleRate = 0;
bool wantsStereo;
bool wantsTrimming;
size_t impulseResponseSize;
size_t maximumBufferSize = 0;
};
@@ -335,6 +336,7 @@ public:
changeSource,
changeImpulseResponseSize,
changeStereo,
changeTrimming,
numChangeRequestTypes
};
@@ -588,6 +590,17 @@ public:
}
break;
case ChangeRequest::changeTrimming:
{
bool newWantsTrimming = requestParameters[n];
if (currentInfo.wantsTrimming != newWantsTrimming)
changeLevel = jmax(1, changeLevel);
currentInfo.wantsTrimming = newWantsTrimming;
}
break;
default:
jassertfalse;
break;
@@ -732,6 +745,7 @@ private:
void processImpulseResponse()
{
if (currentInfo.sourceType == SourceType::sourceBinaryData)
{
copyAudioStreamInAudioBuffer (new MemoryInputStream (currentInfo.sourceData, currentInfo.sourceDataSize, false));
@@ -743,7 +757,7 @@ private:
else if (currentInfo.sourceType == SourceType::sourceAudioBuffer)
{
copyBufferFromTemporaryLocation();
trimAndResampleImpulseResponse (temporaryBuffer.getNumChannels(), currentInfo.bufferSampleRate);
trimAndResampleImpulseResponse (temporaryBuffer.getNumChannels(), currentInfo.bufferSampleRate, currentInfo.wantsTrimming);
}
if (isThreadRunning() && threadShouldExit())
@@ -751,19 +765,19 @@ private:
if (currentInfo.wantsStereo)
{
normalizeImpulseResponse (currentInfo.buffer->getWritePointer(0), currentInfo.buffer->getNumSamples());
normalizeImpulseResponse (currentInfo.buffer->getWritePointer(1), currentInfo.buffer->getNumSamples());
normalizeImpulseResponse (currentInfo.buffer->getWritePointer(0), currentInfo.buffer->getNumSamples(), 1.0);
normalizeImpulseResponse (currentInfo.buffer->getWritePointer(1), currentInfo.buffer->getNumSamples(), 1.0);
}
else
{
normalizeImpulseResponse (currentInfo.buffer->getWritePointer (0), currentInfo.buffer->getNumSamples());
normalizeImpulseResponse (currentInfo.buffer->getWritePointer (0), currentInfo.buffer->getNumSamples(), 1.0);
}
}
/** Converts the data from an audio file into a stereo audio buffer of floats, and
performs resampling if necessary.
*/
void copyAudioStreamInAudioBuffer (InputStream* stream)
double copyAudioStreamInAudioBuffer (InputStream* stream)
{
AudioFormatManager manager;
manager.registerBasicFormats();
@@ -778,54 +792,65 @@ private:
impulseResponseOriginal.clear();
formatReader->read (&(impulseResponseOriginal), 0, impulseResponseOriginal.getNumSamples(), 0, true, numChannels > 1);
trimAndResampleImpulseResponse (numChannels, formatReader->sampleRate);
return trimAndResampleImpulseResponse (numChannels, formatReader->sampleRate, currentInfo.wantsTrimming);
}
else
return 0.0;
}
void trimAndResampleImpulseResponse (int numChannels, double bufferSampleRate)
double trimAndResampleImpulseResponse (int numChannels, double bufferSampleRate, bool mustTrim)
{
auto thresholdTrim = Decibels::decibelsToGain (-80.0f);
auto indexStart = impulseResponseOriginal.getNumSamples() - 1;
auto indexEnd = 0;
auto indexStart = 0;
auto indexEnd = impulseResponseOriginal.getNumSamples() - 1;
for (auto channel = 0; channel < numChannels; ++channel)
if (mustTrim)
{
auto localIndexStart = 0;
auto localIndexEnd = impulseResponseOriginal.getNumSamples() - 1;
indexStart = impulseResponseOriginal.getNumSamples() - 1;
indexEnd = 0;
for (auto channel = 0; channel < numChannels; ++channel)
{
auto localIndexStart = 0;
auto localIndexEnd = impulseResponseOriginal.getNumSamples() - 1;
auto* channelData = impulseResponseOriginal.getReadPointer (channel);
auto* channelData = impulseResponseOriginal.getReadPointer (channel);
while (localIndexStart < impulseResponseOriginal.getNumSamples() - 1
&& channelData[localIndexStart] <= thresholdTrim
&& channelData[localIndexStart] >= -thresholdTrim)
++localIndexStart;
while (localIndexStart < impulseResponseOriginal.getNumSamples() - 1
&& channelData[localIndexStart] <= thresholdTrim
&& channelData[localIndexStart] >= -thresholdTrim)
++localIndexStart;
while (localIndexEnd >= 0
&& channelData[localIndexEnd] <= thresholdTrim
&& channelData[localIndexEnd] >= -thresholdTrim)
--localIndexEnd;
while (localIndexEnd >= 0
&& channelData[localIndexEnd] <= thresholdTrim
&& channelData[localIndexEnd] >= -thresholdTrim)
--localIndexEnd;
indexStart = jmin (indexStart, localIndexStart);
indexEnd = jmax (indexEnd, localIndexEnd);
}
indexStart = jmin (indexStart, localIndexStart);
indexEnd = jmax (indexEnd, localIndexEnd);
}
if (indexStart > 0)
{
for (auto channel = 0; channel < numChannels; ++channel)
if (indexStart > 0)
{
auto* channelData = impulseResponseOriginal.getWritePointer (channel);
for (auto channel = 0; channel < numChannels; ++channel)
{
auto* channelData = impulseResponseOriginal.getWritePointer (channel);
for (auto i = 0; i < indexEnd - indexStart + 1; ++i)
channelData[i] = channelData[i + indexStart];
for (auto i = 0; i < indexEnd - indexStart + 1; ++i)
channelData[i] = channelData[i + indexStart];
for (auto i = indexEnd - indexStart + 1; i < impulseResponseOriginal.getNumSamples() - 1; ++i)
channelData[i] = 0.0f;
for (auto i = indexEnd - indexStart + 1; i < impulseResponseOriginal.getNumSamples() - 1; ++i)
channelData[i] = 0.0f;
}
}
}
double factorReading;
if (currentInfo.sampleRate == bufferSampleRate)
{
// No resampling
factorReading = 1.0;
auto impulseSize = jmin (static_cast<int> (currentInfo.impulseResponseSize), indexEnd - indexStart + 1);
impulseResponse.setSize (2, impulseSize);
@@ -837,7 +862,7 @@ private:
else
{
// Resampling
auto factorReading = bufferSampleRate / currentInfo.sampleRate;
factorReading = bufferSampleRate / currentInfo.sampleRate;
auto impulseSize = jmin (static_cast<int> (currentInfo.impulseResponseSize), roundDoubleToInt ((indexEnd - indexStart + 1) / factorReading));
impulseResponse.setSize (2, impulseSize);
@@ -860,16 +885,18 @@ private:
// Filling the second channel with the first if necessary
if (numChannels == 1)
impulseResponse.copyFrom (1, 0, impulseResponse, 0, 0, impulseResponse.getNumSamples());
return factorReading;
}
void normalizeImpulseResponse (float* samples, int numSamples) const
void normalizeImpulseResponse (float* samples, int numSamples, double factorResampling) const
{
auto magnitude = 0.0f;
for (int i = 0; i < numSamples; ++i)
magnitude += samples[i] * samples[i];
auto magnitudeInv = 1.0f / (4.0f * std::sqrt (magnitude));
auto magnitudeInv = 1.0f / (4.0f * std::sqrt (magnitude)) * 0.5f * static_cast <float> (factorResampling);
for (int i = 0; i < numSamples; ++i)
samples[i] *= magnitudeInv;
@@ -965,14 +992,15 @@ Convolution::~Convolution()
{
}
void Convolution::loadImpulseResponse (const void* sourceData, size_t sourceDataSize, bool wantsStereo, size_t size)
void Convolution::loadImpulseResponse (const void* sourceData, size_t sourceDataSize, bool wantsStereo, bool wantsTrimming, size_t size)
{
if (sourceData == nullptr)
return;
Pimpl::ChangeRequest types[] = { Pimpl::ChangeRequest::changeSource,
Pimpl::ChangeRequest::changeImpulseResponseSize,
Pimpl::ChangeRequest::changeStereo };
Pimpl::ChangeRequest::changeStereo,
Pimpl::ChangeRequest::changeTrimming };
Array<juce::var> sourceParameter;
@@ -981,19 +1009,21 @@ void Convolution::loadImpulseResponse (const void* sourceData, size_t sourceData
juce::var parameters[] = { juce::var (sourceParameter),
juce::var (static_cast<int64> (size)),
juce::var (wantsStereo) };
juce::var (wantsStereo),
juce::var (wantsTrimming) };
pimpl->addToFifo (types, parameters, 3);
}
void Convolution::loadImpulseResponse (const File& fileImpulseResponse, bool wantsStereo, size_t size)
void Convolution::loadImpulseResponse (const File& fileImpulseResponse, bool wantsStereo, bool wantsTrimming, size_t size)
{
if (! fileImpulseResponse.existsAsFile())
return;
Pimpl::ChangeRequest types[] = { Pimpl::ChangeRequest::changeSource,
Pimpl::ChangeRequest::changeImpulseResponseSize,
Pimpl::ChangeRequest::changeStereo };
Pimpl::ChangeRequest::changeStereo,
Pimpl::ChangeRequest::changeTrimming };
Array<juce::var> sourceParameter;
@@ -1002,13 +1032,14 @@ void Convolution::loadImpulseResponse (const File& fileImpulseResponse, bool wan
juce::var parameters[] = { juce::var (sourceParameter),
juce::var (static_cast<int64> (size)),
juce::var (wantsStereo) };
juce::var (wantsStereo),
juce::var (wantsTrimming) };
pimpl->addToFifo (types, parameters, 3);
}
void Convolution::copyAndLoadImpulseResponseFromBuffer (const AudioBuffer<float>& buffer,
double bufferSampleRate, bool wantsStereo, size_t size)
double bufferSampleRate, bool wantsStereo, bool wantsTrimming, size_t size)
{
jassert (bufferSampleRate > 0);
@@ -1019,7 +1050,8 @@ void Convolution::copyAndLoadImpulseResponseFromBuffer (const AudioBuffer<float>
Pimpl::ChangeRequest types[] = { Pimpl::ChangeRequest::changeSource,
Pimpl::ChangeRequest::changeImpulseResponseSize,
Pimpl::ChangeRequest::changeStereo };
Pimpl::ChangeRequest::changeStereo,
Pimpl::ChangeRequest::changeTrimming };
Array<juce::var> sourceParameter;
sourceParameter.add (juce::var ((int) ConvolutionEngine::ProcessingInformation::SourceType::sourceAudioBuffer));
@@ -1027,7 +1059,8 @@ void Convolution::copyAndLoadImpulseResponseFromBuffer (const AudioBuffer<float>
juce::var parameters[] = { juce::var (sourceParameter),
juce::var (static_cast<int64> (size)),
juce::var (wantsStereo) };
juce::var (wantsStereo),
juce::var (wantsTrimming) };
pimpl->addToFifo (types, parameters, 3);
}


+ 6
- 3
modules/juce_dsp/frequency/juce_Convolution.h View File

@@ -87,10 +87,11 @@ public:
@param sourceData the block of data to use as the stream's source
@param sourceDataSize the number of bytes in the source data block
@param wantsStereo requests to load both stereo channels or only one mono channel
@param wantsTrimming requests to trim the start and the end of the impulse response
@param size the expected size for the impulse response after loading
*/
void loadImpulseResponse (const void* sourceData, size_t sourceDataSize,
bool wantsStereo, size_t size);
bool wantsStereo, bool wantsTrimming, size_t size);
/** This function loads an impulse response from an audio file on any drive. It
can load any of the audio formats registered in JUCE, and performs some
@@ -98,10 +99,11 @@ public:
@param fileImpulseResponse the location of the audio file
@param wantsStereo requests to load both stereo channels or only one mono channel
@param wantsTrimming requests to trim the start and the end of the impulse response
@param size the expected size for the impulse response after loading
*/
void loadImpulseResponse (const File& fileImpulseResponse,
bool wantsStereo, size_t size);
bool wantsStereo, bool wantsTrimming, size_t size);
/** This function loads an impulse response from an audio buffer, which is
copied before doing anything else. Performs some resampling and
@@ -110,10 +112,11 @@ public:
@param buffer the AudioBuffer to use
@param bufferSampleRate the sampleRate of the data in the AudioBuffer
@param wantsStereo requests to load both stereo channels or only one mono channel
@param wantsTrimming requests to trim the start and the end of the impulse response
@param size the expected size for the impulse response after loading
*/
void copyAndLoadImpulseResponseFromBuffer (const AudioBuffer<float>& buffer, double bufferSampleRate,
bool wantsStereo, size_t size);
bool wantsStereo, bool wantsTrimming, size_t size);
private:
//==============================================================================


Loading…
Cancel
Save