mirror of
https://codeberg.org/armin/trommelkiste.git
synced 2026-09-01 04:10:46 +02:00
118 lines
3.6 KiB
C++
118 lines
3.6 KiB
C++
#pragma once
|
|
#include <juce_audio_processors/juce_audio_processors.h>
|
|
#include <juce_audio_formats/juce_audio_formats.h>
|
|
#include <juce_dsp/juce_dsp.h>
|
|
#include <random>
|
|
|
|
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];
|
|
bool trackActive[NUM_TRACKS] = {};
|
|
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 currentKitIndex = 0;
|
|
void loadKit(int index);
|
|
void nextKit();
|
|
void prevKit();
|
|
int getNumKits() const;
|
|
juce::String getCurrentKitName() const;
|
|
static const Kit* getKitList();
|
|
|
|
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;
|
|
float ringModPhase = 0.0f;
|
|
};
|
|
|
|
Voice voices[MAX_VOICES];
|
|
juce::AudioFormatManager formatManager;
|
|
double currentSampleRate = 44100.0;
|
|
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;
|
|
|
|
int findFreeVoice(int trackIndex);
|
|
void handleNoteOn(int trackIndex, float velocity);
|
|
void handleNoteOff(int trackIndex);
|
|
juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TrommelkisteProcessor)
|
|
};
|