Skip to content

Commit

Permalink
feat: add lr splitter
Browse files Browse the repository at this point in the history
  • Loading branch information
zsliu98 committed May 14, 2024
1 parent 8e8e449 commit 34954a9
Show file tree
Hide file tree
Showing 14 changed files with 556 additions and 54 deletions.
6 changes: 3 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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
)

Expand Down
9 changes: 9 additions & 0 deletions source/PluginEditor.cpp
Original file line number Diff line number Diff line change
@@ -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 <https://www.gnu.org/licenses/>.

#include "PluginEditor.h"

PluginEditor::PluginEditor(PluginProcessor &p)
Expand Down
9 changes: 9 additions & 0 deletions source/PluginEditor.h
Original file line number Diff line number Diff line change
@@ -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 <https://www.gnu.org/licenses/>.

#pragma once

#include "PluginProcessor.h"
Expand Down
102 changes: 51 additions & 51 deletions source/PluginProcessor.cpp
Original file line number Diff line number Diff line change
@@ -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 <https://www.gnu.org/licenses/>.

#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() {
Expand Down Expand Up @@ -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.
}

Expand All @@ -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<juce::uint32>(samplesPerBlock),
4
};
doubleBuffer.setSize(4, samplesPerBlock);
controller.prepare(spec);
}

void PluginProcessor::releaseResources() {
Expand All @@ -84,54 +99,40 @@ 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<float> &buffer,
juce::MidiBuffer &midiMessages) {
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<double> &buffer,
juce::MidiBuffer &midiMessages) {
juce::ignoreUnused(midiMessages);

juce::ScopedNoDenormals noDenormals;
controller.process(buffer);
}

//==============================================================================
Expand All @@ -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);
}

//==============================================================================
Expand All @@ -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();
}
20 changes: 20 additions & 0 deletions source/PluginProcessor.h
Original file line number Diff line number Diff line change
@@ -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 <https://www.gnu.org/licenses/>.

#pragma once

#include <juce_audio_processors/juce_audio_processors.h>
Expand All @@ -6,8 +15,12 @@
#include "ipps.h"
#endif

#include "dsp/dsp.hpp"

class PluginProcessor : public juce::AudioProcessor {
public:
juce::AudioProcessorValueTreeState parameters;

PluginProcessor();

~PluginProcessor() override;
Expand All @@ -20,6 +33,8 @@ class PluginProcessor : public juce::AudioProcessor {

void processBlock(juce::AudioBuffer<float> &, juce::MidiBuffer &) override;

void processBlock(juce::AudioBuffer<double> &, juce::MidiBuffer &) override;

juce::AudioProcessorEditor *createEditor() override;

bool hasEditor() const override;
Expand Down Expand Up @@ -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<double> doubleBuffer;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginProcessor)
};
66 changes: 66 additions & 0 deletions source/dsp/controller.cpp
Original file line number Diff line number Diff line change
@@ -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 <https://www.gnu.org/licenses/>.

#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<double> &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<double> &buffer) {
lrSplitter.split(buffer);
const auto currentMix = mix.load();
const auto lBlock = juce::dsp::AudioBlock<double>(lrSplitter.getLBuffer());
const auto rBlock = juce::dsp::AudioBlock<double>(lrSplitter.getRBuffer());
const auto block = juce::dsp::AudioBlock<double>(buffer);
std::array<juce::dsp::AudioBlock<double>, 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<double> &buffer) {

}

} // zlDSP
57 changes: 57 additions & 0 deletions source/dsp/controller.hpp
Original file line number Diff line number Diff line change
@@ -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 <https://www.gnu.org/licenses/>.

#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<double> &buffer);

void setType(splitType::stype x) {
splitType.store(x);
}

void setMix(double x) {
mix.store(x);
}

zlSplitter::LRSplitter<double>& getLRSplitter() {
return lrSplitter;
}

zlSplitter::MSSplitter<double>& getMSSplitter() {
return msSplitter;
}

private:
std::atomic<splitType::stype> splitType;
zlSplitter::LRSplitter<double> lrSplitter;
zlSplitter::MSSplitter<double> msSplitter;
std::atomic<double> mix{0.0};

void processLR(juce::AudioBuffer<double> &buffer);

void processMS(juce::AudioBuffer<double> &buffer);
};

} // zlDSP

#endif //CONTROLLER_HPP
16 changes: 16 additions & 0 deletions source/dsp/dsp.hpp
Original file line number Diff line number Diff line change
@@ -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 <https://www.gnu.org/licenses/>.

#ifndef DSP_HPP
#define DSP_HPP

#include "controller.hpp"
#include "dsp_definitions.hpp"

#endif //DSP_HPP
Loading

0 comments on commit 34954a9

Please sign in to comment.