rename MonoSlicer to Monoslicer (lower-case s)

This commit is contained in:
Armin 2026-07-22 00:33:03 +02:00
commit 9b7c973622
8 changed files with 78 additions and 58 deletions

View file

@ -1,17 +1,17 @@
cmake_minimum_required(VERSION 3.22)
project(MonoSlicer VERSION 1.0.0 LANGUAGES C CXX)
project(Monoslicer VERSION 1.0.0 LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_subdirectory(lib/JUCE)
juce_add_plugin(MonoSlicer
COMPANY_NAME "MonoSlicer"
juce_add_plugin(Monoslicer
COMPANY_NAME "Monoslicer"
PLUGIN_MANUFACTURER_CODE RcSp
PLUGIN_CODE MsP1
FORMATS AU VST3 Standalone
PRODUCT_NAME "MonoSlicer"
PRODUCT_NAME "Monoslicer"
IS_SYNTH TRUE
NEEDS_MIDI_INPUT TRUE
NEEDS_MIDI_OUTPUT FALSE
@ -21,7 +21,7 @@ juce_add_plugin(MonoSlicer
VST3_CATEGORIES Instrument Sampler
)
target_sources(MonoSlicer PRIVATE
target_sources(Monoslicer PRIVATE
Source/PluginProcessor.cpp
Source/PluginEditor.cpp
Source/SliceManager.cpp
@ -29,13 +29,13 @@ target_sources(MonoSlicer PRIVATE
Source/PianoRollDisplay.cpp
)
target_compile_definitions(MonoSlicer PUBLIC
target_compile_definitions(Monoslicer PUBLIC
JUCE_WEB_BROWSER=0
JUCE_USE_CURL=0
JUCE_VST3_CAN_REPLACE_VST2=0
)
target_link_libraries(MonoSlicer
target_link_libraries(Monoslicer
PRIVATE
juce::juce_audio_utils
juce::juce_audio_processors

View file

@ -20,18 +20,18 @@ configure: fetch
cmake -B $(BUILD_DIR) -S . $(CMAKE_ARGS)
build: configure
@echo ">>> Building MonoSlicer..."
@echo ">>> Building Monoslicer..."
cmake --build $(BUILD_DIR) -j$$(sysctl -n hw.ncpu)
install: build
@echo ">>> Installing plugins..."
mkdir -p ~/Library/Audio/Plug-Ins/Components
mkdir -p ~/Library/Audio/Plug-Ins/VST3
cp -R $(BUILD_DIR)/MonoSlicer_artefacts/Release/AU/MonoSlicer.component ~/Library/Audio/Plug-Ins/Components/
cp -R $(BUILD_DIR)/MonoSlicer_artefacts/Release/VST3/MonoSlicer.vst3 ~/Library/Audio/Plug-Ins/VST3/
cp -R $(BUILD_DIR)/Monoslicer_artefacts/Release/AU/Monoslicer.component ~/Library/Audio/Plug-Ins/Components/
cp -R $(BUILD_DIR)/Monoslicer_artefacts/Release/VST3/Monoslicer.vst3 ~/Library/Audio/Plug-Ins/VST3/
@echo ">>> Rescanning Audio Units..."
killall -9 AudioComponentRegistrar 2>/dev/null; true
@echo ">>> Done. MonoSlicer installed as AU and VST3."
@echo ">>> Done. Monoslicer installed as AU and VST3."
clean:
rm -rf $(BUILD_DIR)

View file

@ -1,4 +1,4 @@
# MonoSlicer
# Monoslicer
A monophonic sample slicer and sampler instrument built with [JUCE](https://juce.com/) and CMake.
@ -6,7 +6,7 @@ Load an audio file, slice it into regions (automatically via onset detection or
## Screenshot
![MonoSlicer](monoslicershot.png)
![Monoslicer](monoslicershot.png)
## Features
@ -31,7 +31,7 @@ Requires CMake 3.22+ and a C++17 compiler.
make # Fetch JUCE, configure, build, and install (AU + VST3)
```
Running `make` with no arguments will fetch JUCE, build MonoSlicer in Release mode, copy the AU and VST3 plugins to your system directories, and trigger an Audio Unit rescan.
Running `make` with no arguments will fetch JUCE, build Monoslicer in Release mode, copy the AU and VST3 plugins to your system directories, and trigger an Audio Unit rescan.
Individual targets are also available:

View file

@ -1,6 +1,6 @@
#include "PluginEditor.h"
MonoSlicerEditor::MonoSlicerEditor(MonoSlicerProcessor& p)
MonoslicerEditor::MonoslicerEditor(MonoslicerProcessor& p)
: AudioProcessorEditor(p),
processorRef(p),
waveformDisplay(p.getSliceManager())
@ -16,6 +16,7 @@ MonoSlicerEditor::MonoSlicerEditor(MonoSlicerProcessor& p)
};
setupTitleBtn(loadSampleButton, "Load audio file");
setupTitleBtn(clearSampleButton, "Clear loaded sample");
setupTitleBtn(prevSampleButton, "Previous sample in folder");
setupTitleBtn(nextSampleButton, "Next sample in folder");
setupTitleBtn(undoButton, "Undo");
@ -182,12 +183,13 @@ MonoSlicerEditor::MonoSlicerEditor(MonoSlicerProcessor& p)
startTimerHz(30);
}
MonoSlicerEditor::~MonoSlicerEditor()
MonoslicerEditor::~MonoslicerEditor()
{
autoSliceButton.removeListener(this);
clearSlicesButton.removeListener(this);
scaleComboBox.removeListener(this);
loadSampleButton.removeListener(this);
clearSampleButton.removeListener(this);
prevSampleButton.removeListener(this);
nextSampleButton.removeListener(this);
undoButton.removeListener(this);
@ -198,7 +200,7 @@ MonoSlicerEditor::~MonoSlicerEditor()
stretchButton.removeListener(this);
}
void MonoSlicerEditor::setupSlider(juce::Slider& slider, juce::Label& label, const juce::String& name)
void MonoslicerEditor::setupSlider(juce::Slider& slider, juce::Label& label, const juce::String& name)
{
addAndMakeVisible(slider);
addAndMakeVisible(label);
@ -208,14 +210,14 @@ void MonoSlicerEditor::setupSlider(juce::Slider& slider, juce::Label& label, con
label.setFont(juce::Font(juce::FontOptions(13.0f)));
}
void MonoSlicerEditor::attachSlider(juce::Slider& slider, juce::Label& label, const juce::String& name,
void MonoslicerEditor::attachSlider(juce::Slider& slider, juce::Label& label, const juce::String& name,
const juce::String& paramId, std::unique_ptr<SliderAttachment>& attachment)
{
setupSlider(slider, label, name);
attachment = std::make_unique<SliderAttachment>(processorRef.getAPVTS(), paramId, slider);
}
void MonoSlicerEditor::paint(juce::Graphics& g)
void MonoslicerEditor::paint(juce::Graphics& g)
{
g.fillAll(juce::Colour(0xff0f0f1a));
@ -232,7 +234,7 @@ void MonoSlicerEditor::paint(juce::Graphics& g)
g.drawHorizontalLine(40, 0.0f, static_cast<float>(getWidth()));
}
void MonoSlicerEditor::resized()
void MonoslicerEditor::resized()
{
float scaleX = static_cast<float>(getWidth()) / static_cast<float>(baseWidth);
float scaleY = static_cast<float>(getHeight()) / static_cast<float>(baseHeight);
@ -249,6 +251,7 @@ void MonoSlicerEditor::resized()
};
placeBtn(loadSampleButton, 44);
placeBtn(clearSampleButton, 44);
placeBtn(prevSampleButton, 24);
placeBtn(nextSampleButton, 24);
@ -339,7 +342,7 @@ void MonoSlicerEditor::resized()
waveformDisplay.setBounds(mainArea);
}
void MonoSlicerEditor::timerCallback()
void MonoslicerEditor::timerCallback()
{
if (processorRef.stateRestored.exchange(false))
{
@ -362,7 +365,7 @@ void MonoSlicerEditor::timerCallback()
}
}
void MonoSlicerEditor::buttonClicked(juce::Button* button)
void MonoslicerEditor::buttonClicked(juce::Button* button)
{
if (button == &loadSampleButton)
{
@ -378,6 +381,11 @@ void MonoSlicerEditor::buttonClicked(juce::Button* button)
}
});
}
else if (button == &clearSampleButton)
{
processorRef.clearSample();
waveformDisplay.setSampleBuffer(&processorRef.getSampleBuffer(), processorRef.getSampleRateLoaded());
}
else if (button == &prevSampleButton)
{
processorRef.loadPreviousSample();
@ -440,7 +448,7 @@ void MonoSlicerEditor::buttonClicked(juce::Button* button)
}
}
void MonoSlicerEditor::comboBoxChanged(juce::ComboBox* comboBoxThatHasChanged)
void MonoslicerEditor::comboBoxChanged(juce::ComboBox* comboBoxThatHasChanged)
{
if (comboBoxThatHasChanged == &scaleComboBox)
{
@ -454,7 +462,7 @@ void MonoSlicerEditor::comboBoxChanged(juce::ComboBox* comboBoxThatHasChanged)
}
}
bool MonoSlicerEditor::isInterestedInFileDrag(const juce::StringArray& files)
bool MonoslicerEditor::isInterestedInFileDrag(const juce::StringArray& files)
{
for (const auto& f : files)
if (f.endsWithIgnoreCase(".wav") || f.endsWithIgnoreCase(".aiff") ||
@ -463,7 +471,7 @@ bool MonoSlicerEditor::isInterestedInFileDrag(const juce::StringArray& files)
return false;
}
void MonoSlicerEditor::filesDropped(const juce::StringArray& files, int, int)
void MonoslicerEditor::filesDropped(const juce::StringArray& files, int, int)
{
for (const auto& f : files)
{

View file

@ -3,15 +3,15 @@
#include "PluginProcessor.h"
#include "WaveformDisplay.h"
class MonoSlicerEditor : public juce::AudioProcessorEditor,
class MonoslicerEditor : public juce::AudioProcessorEditor,
private juce::FileDragAndDropTarget,
private juce::Button::Listener,
private juce::ComboBox::Listener,
private juce::Timer
{
public:
MonoSlicerEditor(MonoSlicerProcessor&);
~MonoSlicerEditor() override;
MonoslicerEditor(MonoslicerProcessor&);
~MonoslicerEditor() override;
void paint(juce::Graphics&) override;
void resized() override;
@ -23,7 +23,7 @@ public:
void timerCallback() override;
private:
MonoSlicerProcessor& processorRef;
MonoslicerProcessor& processorRef;
WaveformDisplay waveformDisplay;
@ -33,6 +33,7 @@ private:
// Title bar buttons
juce::TextButton loadSampleButton { "Load" };
juce::TextButton clearSampleButton { "Clear" };
juce::TextButton prevSampleButton { "<" };
juce::TextButton nextSampleButton { ">" };
juce::TextButton undoButton { "Undo" };
@ -94,5 +95,5 @@ private:
int keyClickNote = -1;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MonoSlicerEditor)
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MonoslicerEditor)
};

View file

@ -1,7 +1,7 @@
#include "PluginProcessor.h"
#include "PluginEditor.h"
MonoSlicerProcessor::MonoSlicerProcessor()
MonoslicerProcessor::MonoslicerProcessor()
: AudioProcessor(BusesProperties()
.withInput("Input", juce::AudioChannelSet::stereo(), true)
.withOutput("Output", juce::AudioChannelSet::stereo(), true)),
@ -10,9 +10,9 @@ MonoSlicerProcessor::MonoSlicerProcessor()
formatManager.registerBasicFormats();
}
MonoSlicerProcessor::~MonoSlicerProcessor() {}
MonoslicerProcessor::~MonoslicerProcessor() {}
juce::AudioProcessorValueTreeState::ParameterLayout MonoSlicerProcessor::createParameterLayout()
juce::AudioProcessorValueTreeState::ParameterLayout MonoslicerProcessor::createParameterLayout()
{
juce::AudioProcessorValueTreeState::ParameterLayout layout;
@ -88,15 +88,15 @@ juce::AudioProcessorValueTreeState::ParameterLayout MonoSlicerProcessor::createP
return layout;
}
void MonoSlicerProcessor::prepareToPlay(double sampleRate, int samplesPerBlock)
void MonoslicerProcessor::prepareToPlay(double sampleRate, int samplesPerBlock)
{
currentSampleRate = sampleRate;
juce::ignoreUnused(samplesPerBlock);
}
void MonoSlicerProcessor::releaseResources() {}
void MonoslicerProcessor::releaseResources() {}
void MonoSlicerProcessor::computeBiquadCoeffs(FilterType type, float cutoff, float resonance,
void MonoslicerProcessor::computeBiquadCoeffs(FilterType type, float cutoff, float resonance,
float sampleRate, float& b0, float& b1, float& b2,
float& a1, float& a2)
{
@ -163,7 +163,7 @@ void MonoSlicerProcessor::computeBiquadCoeffs(FilterType type, float cutoff, flo
}
}
void MonoSlicerProcessor::advanceAmpEnvelope(Voice& voice, int samples)
void MonoslicerProcessor::advanceAmpEnvelope(Voice& voice, int samples)
{
float attack = apvts.getRawParameterValue("ampAttack")->load();
float decay = apvts.getRawParameterValue("ampDecay")->load();
@ -221,7 +221,7 @@ void MonoSlicerProcessor::advanceAmpEnvelope(Voice& voice, int samples)
}
}
void MonoSlicerProcessor::advanceFilterEnvelope(Voice& voice, int samples)
void MonoslicerProcessor::advanceFilterEnvelope(Voice& voice, int samples)
{
float attack = apvts.getRawParameterValue("filterAttack")->load();
float decay = apvts.getRawParameterValue("filterDecay")->load();
@ -273,7 +273,7 @@ void MonoSlicerProcessor::advanceFilterEnvelope(Voice& voice, int samples)
}
}
void MonoSlicerProcessor::processBlock(juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)
void MonoslicerProcessor::processBlock(juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)
{
juce::ScopedNoDenormals noDenormals;
buffer.clear();
@ -446,7 +446,7 @@ void MonoSlicerProcessor::processBlock(juce::AudioBuffer<float>& buffer, juce::M
currentPlaybackSample.store(-1);
}
void MonoSlicerProcessor::handleNoteOn(int noteNumber, float velocity)
void MonoslicerProcessor::handleNoteOn(int noteNumber, float velocity)
{
int offset = static_cast<int>(apvts.getRawParameterValue("octaveOffset")->load()) * 12;
int sliceIdx = noteNumber - 60 + offset;
@ -479,7 +479,7 @@ void MonoSlicerProcessor::handleNoteOn(int noteNumber, float velocity)
}
}
void MonoSlicerProcessor::handleNoteOff()
void MonoslicerProcessor::handleNoteOff()
{
for (auto& voice : voices)
{
@ -491,7 +491,7 @@ void MonoSlicerProcessor::handleNoteOff()
}
}
void MonoSlicerProcessor::loadAudioFile(const juce::File& file)
void MonoslicerProcessor::loadAudioFile(const juce::File& file)
{
std::unique_ptr<juce::AudioFormatReader> reader(formatManager.createReaderFor(file));
if (reader)
@ -507,7 +507,17 @@ void MonoSlicerProcessor::loadAudioFile(const juce::File& file)
}
}
void MonoSlicerProcessor::refreshFolderList()
void MonoslicerProcessor::clearSample()
{
sampleBuffer.setSize(0, 0);
currentFile = juce::File{};
folderFiles.clear();
currentFileIndex = -1;
sliceManager.setSampleBuffer(&sampleBuffer, loadedSampleRate);
selectedSlice.store(-1);
}
void MonoslicerProcessor::refreshFolderList()
{
folderFiles.clear();
currentFileIndex = -1;
@ -527,37 +537,37 @@ void MonoSlicerProcessor::refreshFolderList()
}
}
void MonoSlicerProcessor::loadNextSample()
void MonoslicerProcessor::loadNextSample()
{
if (folderFiles.isEmpty()) return;
int nextIdx = (currentFileIndex + 1) % folderFiles.size();
loadAudioFile(folderFiles[nextIdx]);
}
void MonoSlicerProcessor::loadPreviousSample()
void MonoslicerProcessor::loadPreviousSample()
{
if (folderFiles.isEmpty()) return;
int prevIdx = (currentFileIndex - 1 + folderFiles.size()) % folderFiles.size();
loadAudioFile(folderFiles[prevIdx]);
}
void MonoSlicerProcessor::triggerSlice(int sliceIndex, float velocity)
void MonoslicerProcessor::triggerSlice(int sliceIndex, float velocity)
{
int noteNumber = sliceIndex + 60;
handleNoteOn(noteNumber, velocity);
}
void MonoSlicerProcessor::releaseSlice()
void MonoslicerProcessor::releaseSlice()
{
handleNoteOff();
}
juce::AudioProcessorEditor* MonoSlicerProcessor::createEditor()
juce::AudioProcessorEditor* MonoslicerProcessor::createEditor()
{
return new MonoSlicerEditor(*this);
return new MonoslicerEditor(*this);
}
void MonoSlicerProcessor::getStateInformation(juce::MemoryBlock& destData)
void MonoslicerProcessor::getStateInformation(juce::MemoryBlock& destData)
{
auto state = apvts.copyState();
@ -592,7 +602,7 @@ void MonoSlicerProcessor::getStateInformation(juce::MemoryBlock& destData)
}
}
void MonoSlicerProcessor::setStateInformation(const void* data, int sizeInBytes)
void MonoslicerProcessor::setStateInformation(const void* data, int sizeInBytes)
{
auto stream = juce::MemoryInputStream(data, static_cast<size_t>(sizeInBytes), false);
auto state = juce::ValueTree::readFromStream(stream);
@ -661,10 +671,10 @@ void MonoSlicerProcessor::setStateInformation(const void* data, int sizeInBytes)
juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter()
{
return new MonoSlicerProcessor();
return new MonoslicerProcessor();
}
void MonoSlicerProcessor::stretchToBeats(int numBeats, float bpm)
void MonoslicerProcessor::stretchToBeats(int numBeats, float bpm)
{
if (sampleBuffer.getNumSamples() == 0 || bpm <= 0.0f || numBeats <= 0) return;

View file

@ -4,11 +4,11 @@
#include <juce_dsp/juce_dsp.h>
#include "SliceManager.h"
class MonoSlicerProcessor : public juce::AudioProcessor
class MonoslicerProcessor : public juce::AudioProcessor
{
public:
MonoSlicerProcessor();
~MonoSlicerProcessor() override;
MonoslicerProcessor();
~MonoslicerProcessor() override;
void prepareToPlay(double sampleRate, int samplesPerBlock) override;
void releaseResources() override;
@ -34,6 +34,7 @@ public:
void setStateInformation(const void* data, int sizeInBytes) override;
void loadAudioFile(const juce::File& file);
void clearSample();
void loadNextSample();
void loadPreviousSample();
void triggerSlice(int sliceIndex, float velocity = 0.8f);
@ -123,5 +124,5 @@ private:
void computeBiquadCoeffs(FilterType type, float cutoff, float resonance, float sampleRate,
float& b0, float& b1, float& b2, float& a1, float& a2);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MonoSlicerProcessor)
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MonoslicerProcessor)
};

View file

@ -208,7 +208,7 @@ void WaveformDisplay::paint(juce::Graphics& g)
auto textArea = bounds.withTrimmedBottom(scrollbarHeight);
g.setColour(juce::Colours::grey);
g.setFont(14.0f);
g.drawText("Drop or load an audio file", textArea, juce::Justification::centred);
g.drawText("No audio file loaded.", textArea, juce::Justification::centred);
hScrollBar.setBounds(bounds.removeFromBottom(scrollbarHeight).toNearestInt());
return;
}