chromaflock/Source/PluginProcessor.h

124 lines
4.1 KiB
C
Raw Normal View History

2026-07-13 20:57:38 +02:00
#pragma once
#include <juce_audio_processors/juce_audio_processors.h>
#include <juce_audio_basics/juce_audio_basics.h>
#include "DSP/Voice.h"
#include "DSP/Arpeggiator.h"
2026-07-13 20:57:38 +02:00
#include "DSP/Distortion.h"
#include "DSP/Compressor.h"
#include "DSP/Limiter.h"
2026-07-13 20:57:38 +02:00
#include "DSP/Delay.h"
#include "DSP/Reverb.h"
#include "PresetManager.h"
#include <array>
#include <atomic>
const juce::StringArray& getSemitoneChoices();
2026-07-13 20:57:38 +02:00
class ChromaFlockProcessor : public juce::AudioProcessor {
public:
ChromaFlockProcessor();
~ChromaFlockProcessor() override;
void prepareToPlay(double sampleRate, int samplesPerBlock) override;
void releaseResources() override;
void processBlock(juce::AudioBuffer<float>&, juce::MidiBuffer&) override;
juce::AudioProcessorEditor* createEditor() override;
bool hasEditor() const override { return true; }
const juce::String getName() const override { return "ChromaFlock"; }
bool acceptsMidi() const override { return true; }
bool producesMidi() const override { return false; }
bool isMidiEffect() const override { return false; }
double getTailLengthSeconds() const override { return 0.0; }
int getNumPrograms() override { return 1; }
int getCurrentProgram() override { return 0; }
void setCurrentProgram(int) override {}
const juce::String getProgramName(int) override { return {}; }
void changeProgramName(int, const juce::String&) override {}
void getStateInformation(juce::MemoryBlock& destData) override;
void setStateInformation(const void* data, int sizeInBytes) override;
juce::AudioProcessorValueTreeState apvts;
PresetManager presetManager;
static constexpr int scopeBufferSize = 1024;
std::array<float, scopeBufferSize> scopeBuffer{};
std::atomic<int> scopeWritePos{0};
static constexpr int fftOrder = 11;
static constexpr int fftSize = 1 << fftOrder;
std::array<float, fftSize> fftInput{};
std::atomic<int> fftWritePos{0};
Arpeggiator arp;
2026-07-13 20:57:38 +02:00
float getRmsLevel() const { return rmsLevel.load(); }
bool isArpEnabled() const {
auto* p = apvts.getRawParameterValue("arpEnabled");
return p != nullptr && p->load() > 0.5f;
}
2026-07-13 20:57:38 +02:00
void noteOn(int midiNote, float velocity) {
if (midiNote >= 0 && midiNote < 128)
activeNotes[midiNote].store(true, std::memory_order_relaxed);
if (isArpEnabled())
arp.noteOn(midiNote, velocity);
else
synth.noteOn(1, juce::jlimit(0, 127, midiNote + getTransposeSemitones()), velocity);
2026-07-13 20:57:38 +02:00
}
void noteOff(int midiNote) {
if (midiNote >= 0 && midiNote < 128)
activeNotes[midiNote].store(false, std::memory_order_relaxed);
if (isArpEnabled())
arp.noteOff(midiNote);
else
synth.noteOff(1, juce::jlimit(0, 127, midiNote + getTransposeSemitones()), 0.0f, true);
2026-07-13 20:57:38 +02:00
}
bool isNoteActive(int midiNote) const {
return midiNote >= 0 && midiNote < 128
&& activeNotes[midiNote].load(std::memory_order_relaxed);
}
bool isAnyNoteActive() const {
for (auto& n : activeNotes)
if (n.load(std::memory_order_relaxed)) return true;
return false;
}
2026-07-13 20:57:38 +02:00
int getTransposeSemitones() const;
// Fade out all currently sounding voices over `seconds` so a long release
// tail from the previous preset is silenced on preset change.
void fadeOutActiveVoices(float seconds);
2026-07-13 20:57:38 +02:00
std::atomic<float> pitchBendValue{0.0f};
float getPitchBend() const { return pitchBendValue.load(std::memory_order_relaxed); }
private:
juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
void updateVoiceParameters();
juce::Synthesiser synth;
static constexpr int maxVoices = 16;
Distortion distortion;
Compression compression;
Limiter limiter;
2026-07-13 20:57:38 +02:00
Delay delay;
ReverbFX reverbFX;
float autoPanPhase = 0.0f;
float autoPanPhaseOffset = 0.0f;
2026-07-13 20:57:38 +02:00
double currentSampleRate = 44100.0;
double currentBpm = 120.0;
double arpSampleCount = 0.0;
2026-07-13 20:57:38 +02:00
std::atomic<float> rmsLevel{0.0f};
std::array<std::atomic<bool>, 128> activeNotes{};
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ChromaFlockProcessor)
};