#pragma once #include #include #include #include "SliceManager.h" class MonoSlicerProcessor : public juce::AudioProcessor { public: MonoSlicerProcessor(); ~MonoSlicerProcessor() override; 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 JucePlugin_Name; } bool acceptsMidi() const override { return true; } bool producesMidi() const override { return true; } 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; void loadAudioFile(const juce::File& file); void loadNextSample(); void loadPreviousSample(); void triggerSlice(int sliceIndex, float velocity = 0.8f); void releaseSlice(); void stretchToBeats(int numBeats, float bpm); void psolaStretch(int targetLength); float getHostBpm() const; juce::AudioProcessorValueTreeState& getAPVTS() { return apvts; } SliceManager& getSliceManager() { return sliceManager; } const juce::AudioBuffer& getSampleBuffer() const { return sampleBuffer; } double getSampleRateLoaded() const { return loadedSampleRate; } const juce::File& getCurrentFile() const { return currentFile; } int getCurrentFileIndex() const { return currentFileIndex; } int getNumFilesInFolder() const { return static_cast(folderFiles.size()); } std::atomic stateRestored { false }; std::atomic currentPlaybackSample { -1 }; std::atomic currentActiveSlice { -1 }; std::atomic selectedSlice { -1 }; private: juce::AudioProcessorValueTreeState apvts; juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout(); SliceManager sliceManager; juce::AudioFormatManager formatManager; juce::AudioBuffer sampleBuffer; double loadedSampleRate = 44100.0; double currentSampleRate = 44100.0; juce::File currentFile; juce::Array folderFiles; int currentFileIndex = -1; void refreshFolderList(); enum class AmpStage { Idle, Attack, Decay, Sustain, Release }; enum class FilterType { LP12, LP24, HP, BP, Notch }; struct BiquadState { float x1 = 0.0f, x2 = 0.0f, y1 = 0.0f, y2 = 0.0f; float b0 = 0.0f, b1 = 0.0f, b2 = 0.0f; float a1 = 0.0f, a2 = 0.0f; void reset() { x1 = x2 = y1 = y2 = 0.0f; } float process(float input) { float output = b0 * input + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2; x2 = x1; x1 = input; y2 = y1; y1 = output; return output; } }; struct Voice { bool active = false; int sliceIndex = -1; float position = 0.0f; float velocity = 0.0f; bool midiNoteSent = false; AmpStage ampStage = AmpStage::Idle; float ampEnv = 0.0f; int ampSamplesToNext = 0; AmpStage filterStage = AmpStage::Idle; float filterEnv = 0.0f; int filterSamplesToNext = 0; BiquadState filterL, filterR; }; static constexpr int maxVoices = 16; std::array voices; void handleNoteOn(int noteNumber, float velocity); void handleNoteOff(); void advanceAmpEnvelope(Voice& voice, int samples); void advanceFilterEnvelope(Voice& voice, int samples); 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) };