#pragma once #include #include "dsp/SynthVoice.h" #include "dsp/StepSequencer.h" class MonostepAudioProcessor final : public juce::AudioProcessor { public: MonostepAudioProcessor(); ~MonostepAudioProcessor() override = default; void prepareToPlay (double sampleRate, int samplesPerBlock) override; void releaseResources() override; void processBlock (juce::AudioBuffer&, juce::MidiBuffer&) override; juce::AudioProcessorEditor* createEditor() override; bool hasEditor() const override { return true; } const juce::String getName() const override { return "Monostep"; } bool acceptsMidi() const override { return true; } bool producesMidi() 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&) override; void setStateInformation (const void*, int) override; juce::AudioProcessorValueTreeState& getAPVTS() { return apvts; } monostep::StepSequencer& getSequencer() { return sequencer; } const monostep::StepSequencer& getSequencer() const { return sequencer; } int getNumSteps() const { return monostep::numSteps; } int getPatternLength() const { return juce::roundToInt (seqLenParam->load()); } int getCurrentStep() const { return playStep.load(); } void setStepGate (int idx, bool gate); void setStepNote (int idx, int semitone); void setStepCents (int idx, float cents); void setStepSlide (int idx, bool slide); void setStepAccent (int idx, bool accent); void shiftPattern (int dir); int getNumPresets() const; const char* getPresetName (int index) const; void applyPreset (int index); void randomizePattern(); void randomizeParams(); void randomizeOsc(); void randomizeFilter(); void randomizeEnv(); void randomizeSeqSettings(); void randomizeFx(); juce::String getStepNoteName (int idx) const; std::function onPatternChanged; private: static juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout(); void updateVoiceParams(); void applyParamValue (const juce::String& id, float value); float midiToFreq (float note) const; void storeSequence (juce::ValueTree& seq) const; void loadSequence (const juce::ValueTree& seq); void setDefaultPattern(); juce::AudioProcessorValueTreeState apvts; std::atomic* osc1WaveParam = nullptr; std::atomic* osc2WaveParam = nullptr; std::atomic* osc1CoarseParam = nullptr; std::atomic* osc2CoarseParam = nullptr; std::atomic* detuneParam = nullptr; std::atomic* mixParam = nullptr; std::atomic* osc1PhaseParam = nullptr; std::atomic* cutoffParam = nullptr; std::atomic* resParam = nullptr; std::atomic* attackParam = nullptr; std::atomic* decayParam = nullptr; std::atomic* sustainParam = nullptr; std::atomic* releaseParam = nullptr; std::atomic* glideParam = nullptr; std::atomic* masterParam = nullptr; std::atomic* seqLenParam = nullptr; std::atomic* seqRateParam = nullptr; std::atomic* seqRootParam = nullptr; std::atomic* seqOctaveParam = nullptr; std::atomic* seqSwingParam = nullptr; std::atomic* seqGateLenParam = nullptr; std::atomic* driveParam = nullptr; std::atomic* ringModParam = nullptr; std::atomic* accentParam = nullptr; monostep::StepSequencer sequencer; monostep::SynthVoice voice; juce::AudioBuffer scratch; juce::Random random; double sampleRate = 44100.0; int lastStep = -1; std::atomic playStep { -1 }; bool lastGateApplied = false; float lastFreqApplied = -1.0f; bool midiHeld = false; int lastMidiNote = -1; bool wasPlaying = false; double lastHostPpq = -1.0; double freePpq = 0.0; };