#pragma once #include #include #include #include #include #include class SliceManager { public: struct Slice { int startSample; int endSample; int midiNote; // full MIDI note (60 = C4, 61 = C#4, ..., 83 = B5) }; SliceManager(); void setSampleBuffer(juce::AudioBuffer* buffer, double sampleRate); void setSensitivity(float s); void setBassGain(float g); void setTrebleGain(float g); void autoSlice(); void clearSlices(); void addSliceManual(int samplePos); void removeSliceAt(int samplePos, int tolerance = 5); void moveSlice(int fromSample, int toSample); void trimStart(int sample); void trimEnd(int sample); std::vector getSlices() const; int getNumSlices() const; Slice getSlice(int index) const; void setSlices(const std::vector& newSlices); void setBeforeChangeCallback(std::function cb) { beforeChangeCallback = std::move(cb); } int findSliceIndexForSample(int samplePos) const; juce::AudioBuffer* getMutableBuffer() { return sampleBuffer; } private: void sortSlices(); void assignMidiNotes(); mutable juce::CriticalSection mutex; std::vector slices; juce::AudioBuffer* sampleBuffer = nullptr; double currentSampleRate = 44100.0; float sensitivity = 0.5f; float bassGain = 1.0f; float trebleGain = 1.0f; std::function beforeChangeCallback; std::vector computeEnvelope(const float* channelData, int numSamples); std::vector lowpassFilter(const std::vector& input, float cutoffHz); std::vector highpassFilter(const std::vector& input, float cutoffHz); std::vector detectOnsets(const std::vector& envelope, float threshold); };