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