diff --git a/CMakeLists.txt b/CMakeLists.txt index 03bb5f5..08c3829 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ set(PLUGIN_CODE "Spli") # # set(PROJECT_NAME "MyPlugin_v${MAJOR_VERSION}") # Doing so enables major versions to show up in IDEs and DAWs as separate plugins # allowing you to change parameters and behavior without breaking existing user projects -set(PRODUCT_NAME "ZL Split") +set(PRODUCT_NAME "ZL Splitter") # Change me! Used for the MacOS bundle name and Installers set(COMPANY_NAME "ZL") @@ -125,11 +125,11 @@ target_compile_definitions(SharedCode CMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" VERSION="${CURRENT_VERSION}" - JUCE_DISPLAY_SPLASH_SCREEN=0 + # JUCE_DISPLAY_SPLASH_SCREEN=0 # JucePlugin_Name is for some reason doesn't use the nicer PRODUCT_NAME PRODUCT_NAME_WITHOUT_VERSION="${PRODUCT_NAME}" - # JUCE_COREGRAPHICS_RENDER_WITH_MULTIPLE_PAINT_CALLS=1 + # JUCE_COREGRAPHICS_RENDER_WITH_MULTIPLE_PAINT_CALLS=1 JUCE_SILENCE_XCODE_15_LINKER_WARNING=1 ) diff --git a/source/PluginEditor.cpp b/source/PluginEditor.cpp index 4a09138..f566b65 100644 --- a/source/PluginEditor.cpp +++ b/source/PluginEditor.cpp @@ -1,3 +1,12 @@ +// Copyright (C) 2024 - zsliu98 +// This file is part of ZLSplit +// +// ZLSplit is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// +// ZLSplit is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with ZLSplit. If not, see . + #include "PluginEditor.h" PluginEditor::PluginEditor(PluginProcessor &p) diff --git a/source/PluginEditor.h b/source/PluginEditor.h index ef9689f..a382f90 100644 --- a/source/PluginEditor.h +++ b/source/PluginEditor.h @@ -1,3 +1,12 @@ +// Copyright (C) 2024 - zsliu98 +// This file is part of ZLSplit +// +// ZLSplit is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// +// ZLSplit is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with ZLSplit. If not, see . + #pragma once #include "PluginProcessor.h" diff --git a/source/PluginProcessor.cpp b/source/PluginProcessor.cpp index 0d2e27b..957d754 100644 --- a/source/PluginProcessor.cpp +++ b/source/PluginProcessor.cpp @@ -1,16 +1,25 @@ +// Copyright (C) 2024 - zsliu98 +// This file is part of ZLSplit +// +// ZLSplit is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// +// ZLSplit is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with ZLSplit. If not, see . + #include "PluginProcessor.h" #include "PluginEditor.h" //============================================================================== PluginProcessor::PluginProcessor() - : AudioProcessor(BusesProperties() -#if !JucePlugin_IsMidiEffect -#if !JucePlugin_IsSynth - .withInput("Input", juce::AudioChannelSet::stereo(), true) -#endif - .withOutput("Output", juce::AudioChannelSet::stereo(), true) -#endif -) { + : AudioProcessor(BusesProperties() + .withInput("Input", juce::AudioChannelSet::stereo(), true) + + .withOutput("Output 1", juce::AudioChannelSet::stereo(), true) + .withOutput("Output 2", juce::AudioChannelSet::stereo(), true)), + parameters(*this, nullptr, + juce::Identifier("ZLSplitParameters"), + zlDSP::getParameterLayout()) { } PluginProcessor::~PluginProcessor() { @@ -50,7 +59,7 @@ double PluginProcessor::getTailLengthSeconds() const { } int PluginProcessor::getNumPrograms() { - return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs, + return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs, // so this should be at least 1, even if you're not really implementing programs. } @@ -75,7 +84,13 @@ void PluginProcessor::changeProgramName(int index, const juce::String &newName) void PluginProcessor::prepareToPlay(double sampleRate, int samplesPerBlock) { // Use this method as the place to do any pre-playback // initialisation that you need.. - juce::ignoreUnused(sampleRate, samplesPerBlock); + const juce::dsp::ProcessSpec spec{ + sampleRate, + static_cast(samplesPerBlock), + 4 + }; + doubleBuffer.setSize(4, samplesPerBlock); + controller.prepare(spec); } void PluginProcessor::releaseResources() { @@ -84,24 +99,16 @@ void PluginProcessor::releaseResources() { } bool PluginProcessor::isBusesLayoutSupported(const BusesLayout &layouts) const { -#if JucePlugin_IsMidiEffect - juce::ignoreUnused (layouts); - return true; -#else - // This is the place where you check if the layout is supported. - // In this template code we only support mono or stereo. - if (layouts.getMainOutputChannelSet() != juce::AudioChannelSet::mono() - && layouts.getMainOutputChannelSet() != juce::AudioChannelSet::stereo()) + if (layouts.getMainOutputChannelSet() != juce::AudioChannelSet::stereo()) { return false; - - // This checks if the input layout matches the output layout -#if !JucePlugin_IsSynth - if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet()) + } + if (layouts.getChannelSet(true, 0) != layouts.getChannelSet(true, 1)) { return false; -#endif - + } + if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet()) { + return false; + } return true; -#endif } void PluginProcessor::processBlock(juce::AudioBuffer &buffer, @@ -109,29 +116,23 @@ void PluginProcessor::processBlock(juce::AudioBuffer &buffer, juce::ignoreUnused(midiMessages); juce::ScopedNoDenormals noDenormals; - auto totalNumInputChannels = getTotalNumInputChannels(); - auto totalNumOutputChannels = getTotalNumOutputChannels(); - - // In case we have more outputs than inputs, this code clears any output - // channels that didn't contain input data, (because these aren't - // guaranteed to be empty - they may contain garbage). - // This is here to avoid people getting screaming feedback - // when they first compile a plugin, but obviously you don't need to keep - // this code if your algorithm always overwrites all the output channels. - for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i) - buffer.clear(i, 0, buffer.getNumSamples()); - - // This is the place where you'd normally do the guts of your plugin's - // audio processing... - // Make sure to reset the state if your inner loop is processing - // the samples and the outer loop is handling the channels. - // Alternatively, you can process the samples with the channels - // interleaved by keeping the same state. - for (int channel = 0; channel < totalNumInputChannels; ++channel) { - auto *channelData = buffer.getWritePointer(channel); - juce::ignoreUnused(channelData); - // ..do something to the data... + for (int chan = 0; chan < 2; ++chan) { + auto *dest = doubleBuffer.getWritePointer(chan); + auto *src = buffer.getReadPointer(chan / 2); + for (int i = 0; i < doubleBuffer.getNumSamples(); ++i) { + dest[i] = src[i]; + } } + controller.process(doubleBuffer); + buffer.makeCopyOf(doubleBuffer, true); +} + +void PluginProcessor::processBlock(juce::AudioBuffer &buffer, + juce::MidiBuffer &midiMessages) { + juce::ignoreUnused(midiMessages); + + juce::ScopedNoDenormals noDenormals; + controller.process(buffer); } //============================================================================== @@ -140,7 +141,8 @@ bool PluginProcessor::hasEditor() const { } juce::AudioProcessorEditor *PluginProcessor::createEditor() { - return new PluginEditor(*this); + // return new PluginEditor(*this); + return new juce::GenericAudioProcessorEditor(*this); } //============================================================================== @@ -159,8 +161,6 @@ void PluginProcessor::setStateInformation(const void *data, int sizeInBytes) { //============================================================================== // This creates new instances of the plugin.. -juce::AudioProcessor *JUCE_CALLTYPE - -createPluginFilter() { +juce::AudioProcessor *JUCE_CALLTYPE createPluginFilter() { return new PluginProcessor(); } diff --git a/source/PluginProcessor.h b/source/PluginProcessor.h index 02c22f5..bd6910f 100644 --- a/source/PluginProcessor.h +++ b/source/PluginProcessor.h @@ -1,3 +1,12 @@ +// Copyright (C) 2024 - zsliu98 +// This file is part of ZLSplit +// +// ZLSplit is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// +// ZLSplit is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with ZLSplit. If not, see . + #pragma once #include @@ -6,8 +15,12 @@ #include "ipps.h" #endif +#include "dsp/dsp.hpp" + class PluginProcessor : public juce::AudioProcessor { public: + juce::AudioProcessorValueTreeState parameters; + PluginProcessor(); ~PluginProcessor() override; @@ -20,6 +33,8 @@ class PluginProcessor : public juce::AudioProcessor { void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override; + void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override; + juce::AudioProcessorEditor *createEditor() override; bool hasEditor() const override; @@ -48,6 +63,11 @@ class PluginProcessor : public juce::AudioProcessor { void setStateInformation(const void *data, int sizeInBytes) override; + bool supportsDoublePrecisionProcessing() const override { return true; } + private: + zlDSP::Controller controller; + + juce::AudioBuffer doubleBuffer; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginProcessor) }; diff --git a/source/dsp/controller.cpp b/source/dsp/controller.cpp new file mode 100644 index 0000000..bb2b647 --- /dev/null +++ b/source/dsp/controller.cpp @@ -0,0 +1,66 @@ +// Copyright (C) 2024 - zsliu98 +// This file is part of ZLSplit +// +// ZLSplit is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// +// ZLSplit is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with ZLSplit. If not, see . + +#include "controller.hpp" + +namespace zlDSP { + Controller::Controller() { + + } + + void Controller::reset() { + lrSplitter.reset(); + msSplitter.reset(); + } + + void Controller::prepare(const juce::dsp::ProcessSpec &spec) { + lrSplitter.prepare(spec); + msSplitter.prepare(spec); + } + + void Controller::process(juce::AudioBuffer &buffer) { + switch (splitType.load()) { + case splitType::lright: { + processLR(buffer); + break; + } + case splitType::mside: { + processMS(buffer); + break; + } + case splitType::lhigh: { + break; + } + case splitType::ttone: { + break; + } + } + } + + void Controller::processLR(juce::AudioBuffer &buffer) { + lrSplitter.split(buffer); + const auto currentMix = mix.load(); + const auto lBlock = juce::dsp::AudioBlock(lrSplitter.getLBuffer()); + const auto rBlock = juce::dsp::AudioBlock(lrSplitter.getRBuffer()); + const auto block = juce::dsp::AudioBlock(buffer); + std::array, 4> blocks; + for (size_t i = 0; i < 4; ++i) { + blocks[i] = block.getSingleChannelBlock(i); + } + blocks[0].replaceWithProductOf(lBlock, 1.0 - currentMix); + blocks[1].replaceWithProductOf(rBlock, currentMix); + blocks[2].replaceWithProductOf(lBlock, currentMix); + blocks[3].replaceWithProductOf(rBlock, 1.0 - currentMix); + } + + void Controller::processMS(juce::AudioBuffer &buffer) { + + } + +} // zlDSP \ No newline at end of file diff --git a/source/dsp/controller.hpp b/source/dsp/controller.hpp new file mode 100644 index 0000000..3292f2d --- /dev/null +++ b/source/dsp/controller.hpp @@ -0,0 +1,57 @@ +// Copyright (C) 2024 - zsliu98 +// This file is part of ZLSplit +// +// ZLSplit is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// +// ZLSplit is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with ZLSplit. If not, see . + +#ifndef CONTROLLER_HPP +#define CONTROLLER_HPP + +#include "splitter/splitter.hpp" +#include "dsp_definitions.hpp" + +namespace zlDSP { + +class Controller { +public: + Controller(); + + void reset(); + + void prepare(const juce::dsp::ProcessSpec &spec); + + void process(juce::AudioBuffer &buffer); + + void setType(splitType::stype x) { + splitType.store(x); + } + + void setMix(double x) { + mix.store(x); + } + + zlSplitter::LRSplitter& getLRSplitter() { + return lrSplitter; + } + + zlSplitter::MSSplitter& getMSSplitter() { + return msSplitter; + } + +private: + std::atomic splitType; + zlSplitter::LRSplitter lrSplitter; + zlSplitter::MSSplitter msSplitter; + std::atomic mix{0.0}; + + void processLR(juce::AudioBuffer &buffer); + + void processMS(juce::AudioBuffer &buffer); +}; + +} // zlDSP + +#endif //CONTROLLER_HPP diff --git a/source/dsp/dsp.hpp b/source/dsp/dsp.hpp new file mode 100644 index 0000000..1bcd8f2 --- /dev/null +++ b/source/dsp/dsp.hpp @@ -0,0 +1,16 @@ +// Copyright (C) 2024 - zsliu98 +// This file is part of ZLSplit +// +// ZLSplit is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// +// ZLSplit is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with ZLSplit. If not, see . + +#ifndef DSP_HPP +#define DSP_HPP + +#include "controller.hpp" +#include "dsp_definitions.hpp" + +#endif //DSP_HPP diff --git a/source/dsp/dsp_definitions.hpp b/source/dsp/dsp_definitions.hpp new file mode 100644 index 0000000..4ab6c00 --- /dev/null +++ b/source/dsp/dsp_definitions.hpp @@ -0,0 +1,108 @@ +// Copyright (C) 2024 - zsliu98 +// This file is part of ZLSplit +// +// ZLSplit is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// +// ZLSplit is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with ZLSplit. If not, see . + +#ifndef ZLSPLIT_DSP_DEFINITIONS_HPP +#define ZLSPLIT_DSP_DEFINITIONS_HPP + +#include + +namespace zlDSP { + inline auto static constexpr versionHint = 1; + + // float + template + class FloatParameters { + public: + static std::unique_ptr get(const std::string &suffix = "", bool automate = true) { + auto attributes = juce::AudioParameterFloatAttributes().withAutomatable(automate).withLabel(T::name); + return std::make_unique(juce::ParameterID(T::ID + suffix, versionHint), + T::name + suffix, T::range, T::defaultV, attributes); + } + + inline static float convertTo01(const float x) { + return T::range.convertTo0to1(x); + } + }; + + // bool + template + class BoolParameters { + public: + static std::unique_ptr get(const std::string &suffix = "", bool automate = true) { + auto attributes = juce::AudioParameterBoolAttributes().withAutomatable(automate).withLabel(T::name); + return std::make_unique(juce::ParameterID(T::ID + suffix, versionHint), + T::name + suffix, T::defaultV, attributes); + } + + static std::unique_ptr get(bool meta, const std::string &suffix = "", + bool automate = true) { + auto attributes = juce::AudioParameterBoolAttributes().withAutomatable(automate).withLabel(T::name). + withMeta(meta); + return std::make_unique(juce::ParameterID(T::ID + suffix, versionHint), + T::name + suffix, T::defaultV, attributes); + } + + inline static float convertTo01(const bool x) { + return x ? 1.f : 0.f; + } + }; + + // choice + template + class ChoiceParameters { + public: + static std::unique_ptr get(const std::string &suffix = "", bool automate = true) { + auto attributes = juce::AudioParameterChoiceAttributes().withAutomatable(automate).withLabel(T::name); + return std::make_unique(juce::ParameterID(T::ID + suffix, versionHint), + T::name + suffix, T::choices, T::defaultI, attributes); + } + + inline static float convertTo01(const int x) { + return static_cast(x) / static_cast(T::choices.size()); + } + }; + + class splitType : public ChoiceParameters { + public: + auto static constexpr ID = "split_type"; + auto static constexpr name = ""; + inline auto static const choices = juce::StringArray{ + "Left Right", "Mid Side", "Low High", "Transient Tone" + }; + int static constexpr defaultI = 0; + + enum stype { + lright, mside, lhigh, ttone + }; + }; + + class lrightMix : public FloatParameters { + public: + auto static constexpr ID = "lright_mix"; + auto static constexpr name = "Mix"; + inline auto static const range = juce::NormalisableRange(0, 100, .1f); + auto static constexpr defaultV = 0.f; + }; + + class msideMix : public FloatParameters { + public: + auto static constexpr ID = "mside_mix"; + auto static constexpr name = "Mix"; + inline auto static const range = juce::NormalisableRange(0, 100, .1f); + auto static constexpr defaultV = 0.f; + }; + + inline juce::AudioProcessorValueTreeState::ParameterLayout getParameterLayout() { + juce::AudioProcessorValueTreeState::ParameterLayout layout; + layout.add(splitType::get(), lrightMix::get(), msideMix::get()); + return layout; + } +} + +#endif //ZLSPLIT_DSP_DEFINITIONS_HPP diff --git a/source/dsp/splitter/lright/lr_splitter.cpp b/source/dsp/splitter/lright/lr_splitter.cpp new file mode 100644 index 0000000..20284bc --- /dev/null +++ b/source/dsp/splitter/lright/lr_splitter.cpp @@ -0,0 +1,44 @@ +// Copyright (C) 2024 - zsliu98 +// This file is part of ZLSplit +// +// ZLSplit is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// +// ZLSplit is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with ZLSplit. If not, see . + +#include "lr_splitter.hpp" + +namespace zlSplitter { + template + void LRSplitter::reset() { + lBuffer.clear(); + rBuffer.clear(); + } + + template + void LRSplitter::prepare(const juce::dsp::ProcessSpec &spec) { + lBuffer.setSize(1, static_cast(spec.maximumBlockSize)); + rBuffer.setSize(1, static_cast(spec.maximumBlockSize)); + } + + template + void LRSplitter::split(juce::AudioBuffer &buffer) { + lBuffer.copyFrom(0, 0, buffer, 0, 0, buffer.getNumSamples()); + rBuffer.copyFrom(0, 0, buffer, 1, 0, buffer.getNumSamples()); + lBuffer.setSize(1, buffer.getNumSamples(), true, false, true); + rBuffer.setSize(1, buffer.getNumSamples(), true, false, true); + } + + template + void LRSplitter::combine(juce::AudioBuffer &buffer) { + buffer.copyFrom(0, 0, lBuffer, 0, 0, buffer.getNumSamples()); + buffer.copyFrom(1, 0, rBuffer, 0, 0, buffer.getNumSamples()); + } + + template + class LRSplitter; + + template + class LRSplitter; +} \ No newline at end of file diff --git a/source/dsp/splitter/lright/lr_splitter.hpp b/source/dsp/splitter/lright/lr_splitter.hpp new file mode 100644 index 0000000..67f70e1 --- /dev/null +++ b/source/dsp/splitter/lright/lr_splitter.hpp @@ -0,0 +1,51 @@ +// Copyright (C) 2024 - zsliu98 +// This file is part of ZLSplit +// +// ZLSplit is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// +// ZLSplit is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with ZLSplit. If not, see . + +#ifndef LR_SPLITER_HPP +#define LR_SPLITER_HPP + +#include +#include + +namespace zlSplitter { + /** + * a splitter that splits the stereo audio signal input left signal and right signal + * @tparam FloatType + */ + template + class LRSplitter { + public: + LRSplitter() = default; + + void reset(); + + void prepare(const juce::dsp::ProcessSpec &spec); + + /** + * split the audio buffer into internal left buffer and right buffer + * @param buffer + */ + void split(juce::AudioBuffer &buffer); + + /** + * combine the internal left buffer and right buffer into the audio buffer + * @param buffer + */ + void combine(juce::AudioBuffer &buffer); + + inline juce::AudioBuffer &getLBuffer() { return lBuffer; } + + inline juce::AudioBuffer &getRBuffer() { return rBuffer; } + + private: + juce::AudioBuffer lBuffer, rBuffer; + }; +} + +#endif //LR_SPLITER_HPP diff --git a/source/dsp/splitter/mside/ms_splitter.cpp b/source/dsp/splitter/mside/ms_splitter.cpp new file mode 100644 index 0000000..fe4d545 --- /dev/null +++ b/source/dsp/splitter/mside/ms_splitter.cpp @@ -0,0 +1,55 @@ +// Copyright (C) 2024 - zsliu98 +// This file is part of ZLSplit +// +// ZLSplit is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// +// ZLSplit is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with ZLSplit. If not, see . + +#include "ms_splitter.hpp" +namespace zlSplitter { + template + void MSSplitter::reset() { + mBuffer.clear(); + sBuffer.clear(); + } + + template + void MSSplitter::prepare(const juce::dsp::ProcessSpec &spec) { + mBuffer.setSize(1, static_cast(spec.maximumBlockSize)); + sBuffer.setSize(1, static_cast(spec.maximumBlockSize)); + } + + template + void MSSplitter::split(juce::AudioBuffer &buffer) { + auto lBuffer = buffer.getReadPointer(0); + auto rBuffer = buffer.getReadPointer(1); + auto _mBuffer = mBuffer.getWritePointer(0); + auto _sBuffer = sBuffer.getWritePointer(0); + for (size_t i = 0; i < static_cast(buffer.getNumSamples()); ++i) { + _mBuffer[i] = FloatType(0.5) * (lBuffer[i] + rBuffer[i]); + _sBuffer[i] = FloatType(0.5) * (lBuffer[i] - rBuffer[i]); + } + mBuffer.setSize(1, buffer.getNumSamples(), true, false, true); + sBuffer.setSize(1, buffer.getNumSamples(), true, false, true); + } + + template + void MSSplitter::combine(juce::AudioBuffer &buffer) { + auto lBuffer = buffer.getWritePointer(0); + auto rBuffer = buffer.getWritePointer(1); + auto _mBuffer = mBuffer.getReadPointer(0); + auto _sBuffer = sBuffer.getReadPointer(0); + for (size_t i = 0; i < static_cast(buffer.getNumSamples()); ++i) { + lBuffer[i] = _mBuffer[i] + _sBuffer[i]; + rBuffer[i] = _mBuffer[i] - _sBuffer[i]; + } + } + + template + class MSSplitter; + + template + class MSSplitter; +} \ No newline at end of file diff --git a/source/dsp/splitter/mside/ms_splitter.hpp b/source/dsp/splitter/mside/ms_splitter.hpp new file mode 100644 index 0000000..f2de756 --- /dev/null +++ b/source/dsp/splitter/mside/ms_splitter.hpp @@ -0,0 +1,51 @@ +// Copyright (C) 2024 - zsliu98 +// This file is part of ZLSplit +// +// ZLSplit is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// +// ZLSplit is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with ZLSplit. If not, see . + +#ifndef MS_SPLITTER_HPP +#define MS_SPLITTER_HPP + +#include +#include + +namespace zlSplitter { + /** + * a splitter that splits the stereo audio signal input mid signal and side signal + * @tparam FloatType + */ + template + class MSSplitter { + public: + MSSplitter() = default; + + void reset(); + + void prepare(const juce::dsp::ProcessSpec &spec); + + /** + * split the audio buffer into internal mid buffer and side buffer + * @param buffer + */ + void split(juce::AudioBuffer &buffer); + + /** + * combine the internal mid buffer and side buffer into the audio buffer + * @param buffer + */ + void combine(juce::AudioBuffer &buffer); + + inline juce::AudioBuffer &getMBuffer() { return mBuffer; } + + inline juce::AudioBuffer &getSBuffer() { return sBuffer; } + + private: + juce::AudioBuffer mBuffer, sBuffer; + }; +} + +#endif //MS_SPLITTER_HPP diff --git a/source/dsp/splitter/splitter.hpp b/source/dsp/splitter/splitter.hpp new file mode 100644 index 0000000..9db1784 --- /dev/null +++ b/source/dsp/splitter/splitter.hpp @@ -0,0 +1,16 @@ +// Copyright (C) 2024 - zsliu98 +// This file is part of ZLSplit +// +// ZLSplit is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// +// ZLSplit is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with ZLSplit. If not, see . + +#ifndef SPLITTER_HPP +#define SPLITTER_HPP + +#include "lright/lr_splitter.hpp" +#include "mside/ms_splitter.hpp" + +#endif //SPLITTER_HPP