trommelkiste/Source/PluginProcessor.h

147 lines
4.4 KiB
C
Raw Normal View History

2026-07-19 11:40:36 +02:00
#pragma once
#include <juce_audio_processors/juce_audio_processors.h>
#include <juce_audio_formats/juce_audio_formats.h>
2026-07-19 18:53:17 +02:00
#include <juce_dsp/juce_dsp.h>
#include <atomic>
2026-07-19 18:53:17 +02:00
#include <random>
2026-07-19 11:40:36 +02:00
static constexpr int NUM_TRACKS = 10;
static constexpr int MAX_VOICES = 32;
static constexpr int BASE_NOTE = 60;
class TrommelkisteProcessor : public juce::AudioProcessor
{
public:
TrommelkisteProcessor();
~TrommelkisteProcessor() 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 "Trommelkiste"; }
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;
std::optional<juce::String> getNameForMidiNoteNumber(int note, int) override;
void loadSample(int trackIndex, const juce::File& file);
void clearSample(int trackIndex);
struct Track
{
juce::AudioBuffer<float> buffer;
int fileSampleRate = 44100;
juce::SpinLock lock;
juce::String filePath;
};
Track tracks[NUM_TRACKS];
std::atomic<bool> trackActive[NUM_TRACKS] = {};
2026-07-20 13:26:16 +02:00
std::atomic<float> outputLevel { 0.0f };
2026-07-19 11:40:36 +02:00
juce::AudioProcessorValueTreeState apvts;
// Sample library
struct SampleRef
{
juce::String name;
juce::File file;
const char* data = nullptr;
int dataSize = 0;
};
juce::Array<SampleRef> trackSamples[NUM_TRACKS];
int currentSampleIndex[NUM_TRACKS] = {};
void scanSamples();
void loadSampleByIndex(int trackIndex, int sampleIndex);
void nextSample(int trackIndex);
void prevSample(int trackIndex);
// Kit / Preset system
struct Kit
{
juce::String name;
const char* samples[NUM_TRACKS];
};
int currentPresetIndex = 0;
2026-07-19 11:40:36 +02:00
void loadKit(int index);
int getNumKits() const;
static const Kit* getKitList();
// User presets (saved to disk, shown in the preset menu)
struct UserPreset
{
juce::String name;
juce::File file;
};
juce::Array<UserPreset> userPresets;
void saveUserPreset(const juce::String& name);
void loadUserPreset(int index);
void refreshUserPresets();
int getNumPresets() const { return getNumKits() + userPresets.size(); }
juce::String getPresetName(int index) const;
void loadPreset(int index);
void nextPreset();
void prevPreset();
2026-07-19 11:40:36 +02:00
private:
struct Voice
{
bool active = false;
int trackIndex = -1;
float position = 0.0f;
int samplesPlayed = 0;
float filterStateL = 0.0f;
float filterStateR = 0.0f;
float noteVelocity = 1.0f;
2026-07-19 18:53:17 +02:00
float ringModPhase = 0.0f;
2026-07-19 11:40:36 +02:00
};
Voice voices[MAX_VOICES];
juce::AudioFormatManager formatManager;
double currentSampleRate = 44100.0;
2026-07-19 18:53:17 +02:00
std::mt19937 rng{std::random_device{}()};
// Effects
static constexpr int DELAY_BUFFER_SECONDS = 4;
juce::AudioBuffer<float> delayBuffer;
int delayWritePos = 0;
juce::dsp::Reverb reverb;
juce::dsp::Reverb::Parameters reverbParams;
2026-07-19 11:40:36 +02:00
int findFreeVoice(int trackIndex);
void handleNoteOn(int trackIndex, float velocity);
void handleNoteOff(int trackIndex);
juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
2026-07-20 16:09:31 +02:00
struct PendingShuffleEvent
{
int trackIndex = -1;
float velocity = 0.0f;
int delaySamples = 0;
};
static constexpr int MAX_PENDING_SHUFFLE = 32;
PendingShuffleEvent pendingShuffle[MAX_PENDING_SHUFFLE];
int numPendingShuffle = 0;
int lastTriggeredTrack = -1;
2026-07-20 16:09:31 +02:00
2026-07-19 11:40:36 +02:00
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TrommelkisteProcessor)
};