/* ============================================================================== PluginProcessor.cpp Created: 4 Nov 2025 6:20:37pm Author: mickl ============================================================================== */ #include "PluginProcessor.h" //============================================================================== WebViewPluginAudioProcessor::WebViewPluginAudioProcessor(AudioProcessorValueTreeState::ParameterLayout layout) : AudioProcessor(BusesProperties() .withInput("Input", juce::AudioChannelSet::stereo(), true) .withOutput("Output", juce::AudioChannelSet::stereo(), true) ), parameters(layout), state(*this, nullptr, "STATE", std::move(layout)) { shifter.Init(48000.0f, 48); shifter.SetFormantPreserve(state.getParameterAsValue("formantPreserve").getValue()); shifter.SetAutoTuneSpeed(state.getParameterAsValue("autoTuneSpeed").getValue()); shifter.SetAutoTuneDepth(state.getParameterAsValue("autoTuneDepth").getValue()); shifter.SetPortamentoTime(state.getParameterAsValue("portTime").getValue()); } //============================================================================== void WebViewPluginAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock) { const auto channels = std::max(getTotalNumInputChannels(), getTotalNumOutputChannels()); shifter.Init((float)sampleRate, samplesPerBlock); if (channels == 0) return; filter.prepare({ sampleRate, (uint32_t)samplesPerBlock, (uint32_t)channels }); filter.reset(); } bool WebViewPluginAudioProcessor::isBusesLayoutSupported(const BusesLayout& layouts) const { if (layouts.getMainOutputChannelSet() != juce::AudioChannelSet::mono() && layouts.getMainOutputChannelSet() != juce::AudioChannelSet::stereo()) return false; if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet()) return false; return true; } void WebViewPluginAudioProcessor::processBlock(juce::AudioBuffer& buffer, juce::MidiBuffer& midi) { juce::ScopedNoDenormals noDenormals; const auto totalNumInputChannels = getTotalNumInputChannels(); const auto totalNumOutputChannels = getTotalNumOutputChannels(); for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i) buffer.clear(i, 0, buffer.getNumSamples()); shifter.SetFormantPreserve(state.getParameterAsValue("formantPreserve").getValue()); shifter.SetAutoTuneSpeed(state.getParameterAsValue("autoTuneSpeed").getValue()); shifter.SetAutoTuneDepth(state.getParameterAsValue("autoTuneDepth").getValue()); shifter.SetPortamentoTime(state.getParameterAsValue("portTime").getValue()); shifter.SetHarmonyMix(state.getParameterAsValue("harmonyMix").getValue()); shifter.SetAutoTuneEnable(state.getParameterAsValue("autoTuneEnabled").getValue()); shifter.SetFreeze(state.getParameterAsValue("freezeEnabled").getValue()); shifter.SetFreezePitchAdjust(state.getParameterAsValue("freezePitch").getValue()); shifter.SetFreezeVolume(state.getParameterAsValue("freezeVolume").getValue()); shifter.SetPanWidth(state.getParameterAsValue("panWidth").getValue()); juce::AudioBuffer const_buff; const_buff.makeCopyOf(buffer); shifter.Process(const_buff.getArrayOfReadPointers(), (float**)buffer.getArrayOfWritePointers(), buffer.getNumSamples()); for (const auto metadata : midi) { const auto msg = metadata.getMessage(); if (msg.isNoteOn()) { shifter.AddMidiNote(msg.getNoteNumber()); new_midi = true; } else if (msg.isNoteOff()) { shifter.RemoveMidiNote(msg.getNoteNumber()); new_midi = true; } } } //============================================================================== void WebViewPluginAudioProcessor::getStateInformation(juce::MemoryBlock& destData) { auto out_state = state.copyState(); std::unique_ptr xml(out_state.createXml()); copyXmlToBinary(*xml, destData); } void WebViewPluginAudioProcessor::setStateInformation(const void* data, int sizeInBytes) { std::unique_ptr xmlState(getXmlFromBinary(data, sizeInBytes)); if (xmlState.get() != nullptr && xmlState->hasTagName(state.state.getType())) state.replaceState(juce::ValueTree::fromXml(*xmlState)); }