diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp index dbe896e..98077f5 100644 --- a/Source/PluginEditor.cpp +++ b/Source/PluginEditor.cpp @@ -20,9 +20,6 @@ ConekoAudioProcessorEditor::ConekoAudioProcessorEditor(ConekoAudioProcessor &p) // set AudioFormatManager for reading IR file formatManager.registerBasicFormats(); - const auto sliderStyle = juce::Slider::RotaryHorizontalVerticalDrag; - const auto sliderLabelJustification = juce::Justification::centred; - addAndMakeVisible(openIRFileButton); openIRFileButton.setButtonText("Open IR File..."); openIRFileButton.onClick = [this] { openButtonClicked(); }; @@ -30,17 +27,6 @@ ConekoAudioProcessorEditor::ConekoAudioProcessorEditor(ConekoAudioProcessor &p) irFileLabel.setText("", juce::dontSendNotification); irFileLabel.setJustificationType(juce::Justification::centredLeft); - addAndMakeVisible(reverseButton); - reverseButton.setButtonText("Reverse IR"); - reverseButton.setEnabled(enableIRParameters); - reverseButton.onClick = [this] { - audioProcessor.updateIRParameters(); - shouldPaintWaveform = true; - repaint(); - }; - reverseButtonAttachment = std::make_unique( - audioProcessor.apvts, "Reversed", reverseButton); - addAndMakeVisible(bypassButton); bypassButton.setButtonText("Bypass"); bypassButtonAttachment = std::make_unique( @@ -61,32 +47,6 @@ ConekoAudioProcessorEditor::ConekoAudioProcessorEditor(ConekoAudioProcessor &p) dryWetMixSliderAttachment = std::make_unique( audioProcessor.apvts, "DryWetMix", dryWetMixSlider); - createSlider(decayTimeSlider, " s"); - decayTimeSlider.setEnabled(enableIRParameters); - decayTimeSlider.onDragEnd = [this] { - audioProcessor.updateIRParameters(); - shouldPaintWaveform = true; - repaint(); - }; - createLabel(decayTimeLabel, "Decay", &decayTimeSlider); - decayTimeSliderAttachment = std::make_unique( - audioProcessor.apvts, "DecayTime", decayTimeSlider); - - createSlider(preDelayTimeSlider, " ms"); - // preDelayTimeSlider.onDragEnd = [this] { - // audioProcessor.updateIRParameters(); - // shouldPaintWaveform = true; - // repaint(); - //}; - createLabel(preDelayTimeLabel, "Pre-delay", &preDelayTimeSlider); - preDelayTimeSliderAttachment = std::make_unique( - audioProcessor.apvts, "PreDelayTime", preDelayTimeSlider); - - createSlider(stereoWidthSlider, " %"); - createLabel(stereoWidthLabel, "Width", &stereoWidthSlider); - stereoWidthSliderAttachment = std::make_unique( - audioProcessor.apvts, "StereoWidth", stereoWidthSlider); - createSlider(lowShelfFreqSlider, " Hz"); createLabel(lowShelfFreqLabel, "LowFreq", &lowShelfFreqSlider); lowShelfFreqSliderAttachment = std::make_unique( @@ -173,8 +133,6 @@ void ConekoAudioProcessorEditor::resized() { 40); irFileLabel.setBounds(leftRightMargin, topBottomMargin + 45, dialWidth * 3, 20); - reverseButton.setBounds(leftRightMargin + dialWidth * 2, topBottomMargin + 40, - dialWidth, 30); bypassButton.setBounds(getWidth() - leftRightMargin - dialWidth * 3, topBottomMargin, dialWidth, 20); inputGainSlider.setBounds(leftRightMargin, @@ -186,15 +144,6 @@ void ConekoAudioProcessorEditor::resized() { dryWetMixSlider.setBounds(leftRightMargin + dialWidth * 2, getHeight() - topBottomMargin - dialHeight, dialWidth, dialHeight); - decayTimeSlider.setBounds(leftRightMargin + dialWidth * 3, - getHeight() - topBottomMargin - dialHeight * 3 + 30, - dialWidth * 3, dialHeight * 3 - 30); - preDelayTimeSlider.setBounds(getWidth() - leftRightMargin - dialWidth * 3, - topBottomMargin + dialHeight / 3 * 2, dialWidth, - dialHeight); - stereoWidthSlider.setBounds(getWidth() - leftRightMargin - dialWidth * 3, - getHeight() - topBottomMargin - dialHeight, - dialWidth, dialHeight); lowShelfFreqSlider.setBounds(getWidth() - leftRightMargin - dialWidth * 2, topBottomMargin + dialHeight / 3 * 2, dialWidth, dialHeight); @@ -211,8 +160,8 @@ void ConekoAudioProcessorEditor::resized() { void ConekoAudioProcessorEditor::openButtonClicked() { fileChooser = std::make_unique( - "Choose a support IR File (WAV, AIFF, OGG)...", juce::File(), - "*.wav;*.aif;*.aiff;*.ogg", true, false); + "Choose a support IR File (WAV, AIFF, OGG, FLAC)...", juce::File(), + "*.wav;*.aif;*.aiff;*.ogg;*.flac", true, false); auto chooserFlags = juce::FileBrowserComponent::openMode | juce::FileBrowserComponent::canSelectFiles; fileChooser->launchAsync(chooserFlags, [this](const juce::FileChooser &fc) { @@ -233,8 +182,8 @@ void ConekoAudioProcessorEditor::openButtonClicked() { shouldPaintWaveform = true; enableIRParameters = true; - reverseButton.setEnabled(enableIRParameters); - decayTimeSlider.setEnabled(enableIRParameters); + // reverseButton.setEnabled(enableIRParameters); + // decayTimeSlider.setEnabled(enableIRParameters); repaint(); } } diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h index f3529f5..39a193c 100644 --- a/Source/PluginEditor.h +++ b/Source/PluginEditor.h @@ -42,8 +42,6 @@ class ConekoAudioProcessorEditor : public juce::AudioProcessorEditor { juce::TextButton openIRFileButton; juce::Label irFileLabel; - juce::ToggleButton reverseButton; - std::unique_ptr reverseButtonAttachment; juce::ToggleButton bypassButton; std::unique_ptr bypassButtonAttachment; juce::Slider inputGainSlider; @@ -55,15 +53,6 @@ class ConekoAudioProcessorEditor : public juce::AudioProcessorEditor { juce::Slider dryWetMixSlider; juce::Label dryWetMixLabel; std::unique_ptr dryWetMixSliderAttachment; - juce::Slider decayTimeSlider; - juce::Label decayTimeLabel; - std::unique_ptr decayTimeSliderAttachment; - juce::Slider preDelayTimeSlider; - juce::Label preDelayTimeLabel; - std::unique_ptr preDelayTimeSliderAttachment; - juce::Slider stereoWidthSlider; - juce::Label stereoWidthLabel; - std::unique_ptr stereoWidthSliderAttachment; juce::Slider lowShelfFreqSlider; juce::Label lowShelfFreqLabel; std::unique_ptr lowShelfFreqSliderAttachment; diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 86ca491..27cdaa2 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -71,14 +71,14 @@ int ConekoAudioProcessor::getNumPrograms() { int ConekoAudioProcessor::getCurrentProgram() { return 0; } -void ConekoAudioProcessor::setCurrentProgram(int index) {} +void ConekoAudioProcessor::setCurrentProgram(int /*index*/) {} -const juce::String ConekoAudioProcessor::getProgramName(int index) { +const juce::String ConekoAudioProcessor::getProgramName(int /*oindex*/) { return {}; } -void ConekoAudioProcessor::changeProgramName(int index, - const juce::String &newName) {} +void ConekoAudioProcessor::changeProgramName(int /*index*/, + const juce::String &/*newName*/) { } //============================================================================== void ConekoAudioProcessor::prepareToPlay(double sampleRate, @@ -89,18 +89,12 @@ void ConekoAudioProcessor::prepareToPlay(double sampleRate, spec.numChannels = getTotalNumOutputChannels(); spec.maximumBlockSize = samplesPerBlock; - soundtouch.setSampleRate(sampleRate); - soundtouch.setChannels(1); - inputGainer.prepare(spec); inputGainer.reset(); outputGainer.prepare(spec); outputGainer.reset(); dryWetMixer.prepare(spec); dryWetMixer.reset(); - delay.prepare(spec); - delay.setMaximumDelayInSamples(sampleRate); - delay.reset(); convolver.prepare(spec); convolver.reset(); @@ -142,7 +136,7 @@ bool ConekoAudioProcessor::isBusesLayoutSupported( #endif void ConekoAudioProcessor::processBlock(juce::AudioBuffer &buffer, - juce::MidiBuffer &midiMessages) { + juce::MidiBuffer &/*midiMessages*/) { juce::ScopedNoDenormals noDenormals; auto totalNumInputChannels = getTotalNumInputChannels(); auto totalNumOutputChannels = getTotalNumOutputChannels(); @@ -165,35 +159,19 @@ void ConekoAudioProcessor::processBlock(juce::AudioBuffer &buffer, auto isBypassed = apvts.getRawParameterValue("Bypassed"); updateFilterParameters(); - if (isBypassed->load() == true) { + if (isBypassed->load() != 0.0) { return; } inputGainer.setGainDecibels(inputGainValue->load()); outputGainer.setGainDecibels(outputGainValue->load()); dryWetMixer.setWetMixProportion(dryWetMixValue->load() / 100.0f); - delay.setDelay(preDelayTimeValue->load() / 1000.0 * this->getSampleRate()); auto block = juce::dsp::AudioBlock(buffer); auto context = juce::dsp::ProcessContextReplacing(block); inputGainer.process(context); dryWetMixer.pushDrySamples(block); convolver.process(context); - delay.process(context); - - // set stereo width using mid/side technique - if (context.getInputBlock().getNumChannels() == 2) { - const float width = stereoWidthValue->load() / 100.0; - for (int sample = 0; sample < context.getInputBlock().getNumSamples(); - ++sample) { - float left = context.getInputBlock().getSample(0, sample); - float right = context.getInputBlock().getSample(1, sample); - context.getOutputBlock().setSample( - 0, sample, left * (1 + width) / 2 + right * (1 - width) / 2); - context.getOutputBlock().setSample( - 1, sample, left * (1 - width) / 2 + right * (1 + width) / 2); - } - } lowShelfFilter.process(context); highShelfFilter.process(context); @@ -212,14 +190,14 @@ juce::AudioProcessorEditor *ConekoAudioProcessor::createEditor() { } //============================================================================== -void ConekoAudioProcessor::getStateInformation(juce::MemoryBlock &destData) { +void ConekoAudioProcessor::getStateInformation(juce::MemoryBlock &/*destData*/) { // You should use this method to store your parameters in the memory block. // You could do that either as raw data, or use the XML or ValueTree classes // as intermediaries to make it easy to save and load complex data. } -void ConekoAudioProcessor::setStateInformation(const void *data, - int sizeInBytes) { +void ConekoAudioProcessor::setStateInformation(const void */*data*/, + int /*sizeInBytes*/) { // You should use this method to restore your parameters from this memory // block, whose contents will have been created by the getStateInformation() // call. @@ -246,123 +224,31 @@ void ConekoAudioProcessor::loadImpulseResponse() { // normalized IR signal float globalMaxMagnitude = originalIRBuffer.getMagnitude(0, originalIRBuffer.getNumSamples()); - originalIRBuffer.applyGain(1.0f / (globalMaxMagnitude + 0.01)); - - // trim IR signal - int numSamples = originalIRBuffer.getNumSamples(); - int blockSize = static_cast(std::floor(this->getSampleRate()) / 100); - int startBlockNum = 0; - int endBlockNum = numSamples / blockSize; - float localMaxMagnitude = 0.0f; - while ((startBlockNum + 1) * blockSize < numSamples) { - localMaxMagnitude = - originalIRBuffer.getMagnitude(startBlockNum * blockSize, blockSize); - // find the start position of IR - if (localMaxMagnitude > 0.001) { - break; - } - ++startBlockNum; - } - localMaxMagnitude = 0.0f; - while ((endBlockNum - 1) * blockSize > 0) { - --endBlockNum; - localMaxMagnitude = - originalIRBuffer.getMagnitude(endBlockNum * blockSize, blockSize); - // find the time to decay by 60 dB (T60) - if (localMaxMagnitude > 0.001) { - break; - } - } - - int trimmedNumSamples; - if (endBlockNum * blockSize < numSamples) { - trimmedNumSamples = (endBlockNum - startBlockNum) * blockSize - 1; - } else { - trimmedNumSamples = numSamples - startBlockNum * blockSize; - } - modifiedIRBuffer.setSize(originalIRBuffer.getNumChannels(), trimmedNumSamples, - false, true, false); - for (int channel = 0; channel < originalIRBuffer.getNumChannels(); - ++channel) { - for (int sample = 0; sample < trimmedNumSamples; ++sample) { - modifiedIRBuffer.setSample( - channel, sample, - originalIRBuffer.getSample(channel, - sample + startBlockNum * blockSize)); - } - } + originalIRBuffer.applyGain(1.0f / (globalMaxMagnitude + 0.01f)); - originalIRBuffer.makeCopyOf(modifiedIRBuffer); - - auto decayTimeParam = apvts.getParameter("DecayTime"); - double decayTime = - static_cast(trimmedNumSamples) / this->getSampleRate(); - decayTimeParam->beginChangeGesture(); - decayTimeParam->setValueNotifyingHost( - decayTimeParam->convertTo0to1(decayTime)); - decayTimeParam->endChangeGesture(); - - updateImpulseResponse(modifiedIRBuffer); + updateImpulseResponse(originalIRBuffer); } void ConekoAudioProcessor::updateImpulseResponse( juce::AudioBuffer irBuffer) { convolver.loadImpulseResponse(std::move(irBuffer), this->getSampleRate(), juce::dsp::Convolution::Stereo::yes, - juce::dsp::Convolution::Trim::no, + juce::dsp::Convolution::Trim::yes, juce::dsp::Convolution::Normalise::yes); } +// TODO: remove this since there aren't any more IR parameters? void ConekoAudioProcessor::updateIRParameters() { if (originalIRBuffer.getNumSamples() < 1) { return; } - // stretch IR according to decay time - auto decayTimeValue = apvts.getRawParameterValue("DecayTime"); - int decaySample = static_cast( - std::round(decayTimeValue->load() * this->getSampleRate())); - double stretchRatio = - originalIRBuffer.getNumSamples() / static_cast(decaySample); - - int numChannels = originalIRBuffer.getNumChannels(); - soundtouch.setTempo(stretchRatio); - modifiedIRBuffer.setSize(numChannels, decaySample, false, true, false); - for (int channel = 0; channel < numChannels; ++channel) { - soundtouch.putSamples(originalIRBuffer.getReadPointer(channel), - originalIRBuffer.getNumSamples()); - soundtouch.receiveSamples(modifiedIRBuffer.getWritePointer(channel), - decaySample); - soundtouch.clear(); - } - - // delay IR according to pre-delay time - // auto preDelayTimeValue = apvts.getRawParameterValue("PreDelayTime"); - // int preDelaySample = static_cast(std::round(preDelayTimeValue->load()) - // / - // 1000 * this->getSampleRate()); - // juce::AudioBuffer tempBuffer(modifiedIRBuffer); - // modifiedIRBuffer.setSize(numChannels, - // preDelaySample + tempBuffer.getNumSamples(), false, - // false, false); - // modifiedIRBuffer.clear(); - // for (int channel = 0; channel < numChannels; ++channel) { - // modifiedIRBuffer.copyFrom(channel, preDelaySample, - // tempBuffer.getReadPointer(channel), - // tempBuffer.getNumSamples()); - //} - - // reverse of the IR - auto isReversed = apvts.getRawParameterValue("Reversed"); - if (isReversed->load() == true) { - modifiedIRBuffer.reverse(0, modifiedIRBuffer.getNumSamples()); - } - - updateImpulseResponse(modifiedIRBuffer); + updateImpulseResponse(originalIRBuffer); } + void ConekoAudioProcessor::updateFilterParameters() { - const float sampleRate = this->getSampleRate(); + const float sampleRate = static_cast(this->getSampleRate()); auto lowShelfFreqValue = apvts.getRawParameterValue("LowShelfFreq"); auto lowShelfGainValue = apvts.getRawParameterValue("LowShelfGain"); diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index 96766a4..b25575d 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -8,7 +8,6 @@ #pragma once -#include "../soundtouch/SoundTouch.h" #include //============================================================================== @@ -73,14 +72,14 @@ class ConekoAudioProcessor : public juce::AudioProcessor { juce::AudioBuffer originalIRBuffer; juce::AudioBuffer modifiedIRBuffer; - soundtouch::SoundTouch soundtouch; + // soundtouch::SoundTouch soundtouch; APVTS::ParameterLayout createParameters(); juce::dsp::Gain inputGainer; juce::dsp::Gain outputGainer; juce::dsp::DryWetMixer dryWetMixer; - juce::dsp::DelayLine delay; + // juce::dsp::DelayLine delay; juce::dsp::Convolution convolver; juce::dsp::ProcessorDuplicator, juce::dsp::IIR::Coefficients> diff --git a/coneko.jucer b/coneko.jucer index 0cdbba1..4d7b920 100644 --- a/coneko.jucer +++ b/coneko.jucer @@ -73,10 +73,10 @@ - + - - + + @@ -84,6 +84,7 @@ + @@ -93,7 +94,7 @@ - + @@ -102,6 +103,8 @@ +