diff --git a/src/globals.hh b/src/globals.hh new file mode 100644 index 0000000..3e8420a --- /dev/null +++ b/src/globals.hh @@ -0,0 +1,34 @@ +#ifndef HECK_DAISY_GLOBALS_HH +#define HECK_DAISY_GLOBALS_HH + +#include +namespace Constants { + constexpr int BUFFERSIZE = 4; + constexpr int SAMPLERATE = 48000; + constexpr int TRACK_COUNT = 4; + + namespace MIDI_Mapping { + constexpr int TRACK_PITCH = 70; + constexpr int TRACK_DECAY = 71; + constexpr int TRACK_PARAM1 = 72; + constexpr int TRACK_PARAM2 = 73; + constexpr int TRACK_FILTER = 74; + constexpr int TRACK_DRIVE = 75; + constexpr int TRACK_VOLUME = 76; + } // namespace MIDI_Mapping +} // namespace Constants + +// Types +using u8 = uint8_t; +using u16 = uint16_t; +using u32 = uint32_t; +using u64 = uint64_t; + +using i8 = int8_t; +using i16 = int16_t; +using i32 = int32_t; +using i64 = int64_t; + +using f32 = float; +using f64 = double; +#endif \ No newline at end of file diff --git a/src/instr_abstract.hh b/src/instr_abstract.hh new file mode 100644 index 0000000..d161051 --- /dev/null +++ b/src/instr_abstract.hh @@ -0,0 +1,28 @@ +#ifndef HECK_DAISY_PERKONS_INSTR_ABSTRACT +#define HECK_DAISY_PERKONS_INSTR_ABSTRACT + +#include "globals.hh" + +namespace Heck { + namespace Instrument { + int samplerate = Constants::SAMPLERATE; + + class AbstractInstrument { + public: + virtual void trigger() = 0; + + // ctl-nr must be 0-3 + // val must be 0-1 + virtual void ctl(unsigned int ctl_nr, float val) = 0; + + // pos must be either 0,1,2 + virtual void switch_mode(unsigned int pos) = 0; + virtual void switch_variation(unsigned int pos) = 0; + virtual float nextsample() = 0; + private: + }; + } // namespace Instruments +} // namespace Heck + + +#endif // HECK_DAISY_PERKONS_INSTR_ABSTRACT diff --git a/src/instr_fm.cc b/src/instr_fm.cc index ddd43de..2d6e7fe 100644 --- a/src/instr_fm.cc +++ b/src/instr_fm.cc @@ -1,13 +1,10 @@ #include "instr_fm.hh" #include "daisysp.h" -using namespace daisysp; - - namespace Heck { namespace Instrument { - void FM::init(float samplerate) + void FM::init() { osc.Init(samplerate); osc.SetFrequency(100); @@ -15,17 +12,15 @@ namespace Heck { osc.SetIndex(0.); volEnv.Init(samplerate); - volEnv.SetTime(ADENV_SEG_ATTACK, .0001); - volEnv.SetTime(ADENV_SEG_DECAY, 1.); + volEnv.SetTime(dsp::ADENV_SEG_ATTACK, .0001); + volEnv.SetTime(dsp::ADENV_SEG_DECAY, 1.); volEnv.SetMax(1); volEnv.SetMin(0); - } void FM::trigger() { volEnv.Trigger(); - return; } void FM::ctl(unsigned int ctl_nr, float val) @@ -35,7 +30,7 @@ namespace Heck { osc.SetFrequency(val * 200.); break; case 1: - volEnv.SetTime(ADENV_SEG_DECAY, val * 2.); + volEnv.SetTime(dsp::ADENV_SEG_DECAY, val * 2.); break; case 2: osc.SetRatio(val * 1.); @@ -52,7 +47,6 @@ namespace Heck { void FM::switch_mode(unsigned int pos) {} void FM::switch_variation(unsigned int pos) {} - void FM::switch_filter(unsigned int pos) {} float FM::nextsample() { diff --git a/src/instr_fm.hh b/src/instr_fm.hh index 10c1610..e202ac8 100644 --- a/src/instr_fm.hh +++ b/src/instr_fm.hh @@ -1,7 +1,7 @@ #ifndef HECK_DAISY_INSTR_FM_HH #define HECK_DAISY_INSTR_FM_HH -#include "perkons_instrument_interface.hh" +#include "instr_abstract.hh" #include "daisy_seed.h" #include "daisysp.h" @@ -11,15 +11,14 @@ namespace dsp = daisysp; namespace Heck { namespace Instrument { - class FM : public PerkonsInstrumentInterface { + class FM : public AbstractInstrument { public: - void init(float samplerate); + void init(); void trigger() override; void ctl(unsigned int ctl_nr, float val) override; void switch_mode(unsigned int pos) override; void switch_variation(unsigned int pos) override; - void switch_filter(unsigned int pos) override; float nextsample() override; diff --git a/src/instr_kick.cc b/src/instr_kick.cc index 7624622..6aa6837 100644 --- a/src/instr_kick.cc +++ b/src/instr_kick.cc @@ -1,44 +1,38 @@ #include "instr_kick.hh" #include "daisysp.h" -using namespace daisysp; - - namespace Heck { namespace Instrument { - void Kick::init(float samplerate) + void Kick::init() { osc.Init(samplerate); - osc.SetWaveform(Oscillator::WAVE_TRI); + osc.SetWaveform(dsp::Oscillator::WAVE_TRI); osc.SetAmp(1); pitchEnv.Init(samplerate); - pitchEnv.SetTime(ADENV_SEG_ATTACK, .001); - pitchEnv.SetTime(ADENV_SEG_DECAY, .01); + pitchEnv.SetTime(dsp::ADENV_SEG_ATTACK, .001); + pitchEnv.SetTime(dsp::ADENV_SEG_DECAY, .01); pitchEnv.SetMax(250); pitchEnv.SetMin(20); volEnv.Init(samplerate); - volEnv.SetTime(ADENV_SEG_ATTACK, .0001); - volEnv.SetTime(ADENV_SEG_DECAY, 0.1); + volEnv.SetTime(dsp::ADENV_SEG_ATTACK, .0001); + volEnv.SetTime(dsp::ADENV_SEG_DECAY, 0.1); volEnv.SetMax(1); volEnv.SetMin(0); } - void Kick::trigger() { volEnv.Trigger(); pitchEnv.Trigger(); - return; } void Kick::ctl(unsigned int ctl_nr, float val) {} void Kick::switch_mode(unsigned int pos) {} void Kick::switch_variation(unsigned int pos) {} - void Kick::switch_filter(unsigned int pos) {} float Kick::nextsample() { diff --git a/src/instr_kick.hh b/src/instr_kick.hh index edc4e56..64f27e4 100644 --- a/src/instr_kick.hh +++ b/src/instr_kick.hh @@ -1,7 +1,7 @@ #ifndef HECK_DAISY_INSTR_KICK_HH #define HECK_DAISY_INSTR_KICK_HH -#include "perkons_instrument_interface.hh" +#include "instr_abstract.hh" #include "daisy_seed.h" #include "daisysp.h" @@ -11,18 +11,16 @@ namespace dsp = daisysp; namespace Heck { namespace Instrument { - class Kick : public PerkonsInstrumentInterface { + class Kick : public AbstractInstrument { public: - void init(float samplerate); + void init(); void trigger() override; void ctl(unsigned int ctl_nr, float val) override; void switch_mode(unsigned int pos) override; void switch_variation(unsigned int pos) override; - void switch_filter(unsigned int pos) override; float nextsample() override; - private: dsp::Oscillator osc; dsp::AdEnv volEnv; diff --git a/src/instr_noise.cc b/src/instr_noise.cc index 25937ac..ae420ac 100644 --- a/src/instr_noise.cc +++ b/src/instr_noise.cc @@ -1,18 +1,16 @@ #include "instr_noise.hh" #include "daisysp.h" -using namespace daisysp; - namespace Heck { namespace Instrument { - void Noise::init(float samplerate) + void Noise::init() { noise.Init(); env.Init(samplerate); - env.SetTime(ADENV_SEG_ATTACK, .0001); - env.SetTime(ADENV_SEG_DECAY, .01); + env.SetTime(dsp::ADENV_SEG_ATTACK, .0001); + env.SetTime(dsp::ADENV_SEG_DECAY, .01); env.SetMax(1); env.SetMin(0); } @@ -25,7 +23,6 @@ namespace Heck { void Noise::ctl(unsigned int ctl_nr, float val) {} void Noise::switch_mode(unsigned int pos) {} void Noise::switch_variation(unsigned int pos) {} - void Noise::switch_filter(unsigned int pos) {} float Noise::nextsample() { diff --git a/src/instr_noise.hh b/src/instr_noise.hh index 6beaeb2..2e24581 100644 --- a/src/instr_noise.hh +++ b/src/instr_noise.hh @@ -1,7 +1,7 @@ #ifndef HECK_DAISY_INSTR_NOISE_HH #define HECK_DAISY_INSTR_NOISE_HH -#include "perkons_instrument_interface.hh" +#include "instr_abstract.hh" #include "daisy_seed.h" #include "daisysp.h" @@ -11,18 +11,16 @@ namespace dsp = daisysp; namespace Heck { namespace Instrument { - class Noise : public PerkonsInstrumentInterface { + class Noise : public AbstractInstrument { public: - void init(float samplerate); + void init(); void trigger() override; void ctl(unsigned int ctl_nr, float val) override; void switch_mode(unsigned int pos) override; void switch_variation(unsigned int pos) override; - void switch_filter(unsigned int pos) override; float nextsample() override; - private: dsp::WhiteNoise noise; dsp::AdEnv env; diff --git a/src/main_perkons.cc b/src/main_perkons.cc index ed16b87..e01f1b9 100644 --- a/src/main_perkons.cc +++ b/src/main_perkons.cc @@ -1,42 +1,86 @@ // Hecks perkons extension -#include #include #include #include "daisy_seed.h" #include "daisysp.h" -#include "types.hh" +#include "globals.hh" #include "utils.hh" -#include "perkons_instrument_interface.hh" +#include "instr_abstract.hh" #include "instr_kick.hh" #include "instr_noise.hh" #include "instr_fm.hh" -#define TRACK_COUNT 4 +namespace ld = daisy; +namespace dsp = daisysp; namespace Heck { + // ============================================================================================= // INIT // ============================================================================================= - using namespace daisy; - using namespace daisysp; - static DaisySeed hw{}; - static MidiUartHandler midi{}; - static FIFO event_log{}; + static ld::DaisySeed hw{}; + static ld::MidiUartHandler midi{}; + static ld::FIFO event_log{}; Instrument::Noise instrument0{}; Instrument::FM instrument1{}; Instrument::FM instrument2{}; Instrument::Kick instrument3{}; - std::array, TRACK_COUNT> tracks{}; + struct Track { + public: + void init(Instrument::AbstractInstrument& instrument) + { + instrument_.reset(&instrument); + ctl_volume_ = 1.; + // filter_.Init(); + } + + float nextsample() + { + float sig = instrument_->nextsample(); + sig = vca_(sig, ctl_volume_); + // sig = filter_.Low(); + return sig; + } + + void trigger() + { + instrument_->trigger(); + } + + void volume(float vol) + { + ctl_volume_ = vol; + } + + void filter(float freq) + { + filter_.SetFreq(freq); + } + + void drive(float amt) + { + filter_.SetDrive(amt); + } + + private: + std::shared_ptr instrument_{}; + dsp::LinearVCA vca_{}; + dsp::Svf filter_{}; + + float ctl_volume_{}; + }; + + std::array tracks; // function prototypes - int create_tracks(float samplerate); + int create_tracks(); void AudioCallback( - AudioHandle::InterleavingInputBuffer in, - AudioHandle::InterleavingOutputBuffer out, + ld::AudioHandle::InterleavingInputBuffer in, + ld::AudioHandle::InterleavingOutputBuffer out, size_t size); @@ -50,11 +94,35 @@ namespace Heck { hw.StartLog(true); // Start Audio - hw.SetAudioBlockSize(4); - float samplerate = hw.AudioSampleRate(); + hw.PrintLine("Setting Blocksize: %i", Constants::BUFFERSIZE); + hw.SetAudioBlockSize(Constants::BUFFERSIZE); + + hw.PrintLine("Setting Samplerate: %i", Constants::SAMPLERATE); + switch (Constants::SAMPLERATE) { + case 8000: + hw.SetAudioSampleRate(daisy::SaiHandle::Config::SampleRate::SAI_8KHZ); + break; + case 16000: + hw.SetAudioSampleRate(daisy::SaiHandle::Config::SampleRate::SAI_16KHZ); + break; + case 32000: + hw.SetAudioSampleRate(daisy::SaiHandle::Config::SampleRate::SAI_32KHZ); + break; + case 48000: + hw.SetAudioSampleRate(daisy::SaiHandle::Config::SampleRate::SAI_48KHZ); + break; + case 96000: + hw.SetAudioSampleRate(daisy::SaiHandle::Config::SampleRate::SAI_48KHZ); + break; + default: + hw.PrintLine("Samplerate not supported, fallback to 48000"); + hw.SetAudioSampleRate(daisy::SaiHandle::Config::SampleRate::SAI_48KHZ); + break; + } + hw.PrintLine("Creating Tracks"); - create_tracks(samplerate); + create_tracks(); hw.PrintLine("Starting Audio"); hw.StartAudio(AudioCallback); @@ -62,11 +130,11 @@ namespace Heck { // MIDI RX hw.PrintLine("Setting up MIDI"); - MidiUartHandler::Config midi_config; + ld::MidiUartHandler::Config midi_config; midi.Init(midi_config); u32 systick_last_rt_msg{}; - midi.realtime_callback = [&systick_last_rt_msg](MidiEvent& msg) { - u32 systick_now = System::GetNow(); + midi.realtime_callback = [&systick_last_rt_msg](ld::MidiEvent& msg) { + u32 systick_now = ld::System::GetNow(); u32 systick_since_last = systick_now - systick_last_rt_msg; systick_last_rt_msg = systick_now; @@ -90,17 +158,16 @@ namespace Heck { hw.PrintLine("Entering MainLoop"); } - int create_tracks(float samplerate) + int create_tracks() { - instrument0.init(samplerate); - tracks[0] = std::shared_ptr(&instrument0); - instrument1.init(samplerate); - tracks[1] = std::shared_ptr(&instrument1); - instrument2.init(samplerate); - tracks[2] = std::shared_ptr(&instrument2); - instrument3.init(samplerate); - tracks[3] = std::shared_ptr(&instrument3); - + instrument0.init(); + tracks[0].init(instrument0); + instrument1.init(); + tracks[1].init(instrument1); + instrument2.init(); + tracks[2].init(instrument2); + instrument3.init(); + tracks[3].init(instrument3); return 0; } @@ -111,14 +178,14 @@ namespace Heck { void AudioCallback( - AudioHandle::InterleavingInputBuffer in, - AudioHandle::InterleavingOutputBuffer out, + ld::AudioHandle::InterleavingInputBuffer in, + ld::AudioHandle::InterleavingOutputBuffer out, size_t size) { float sig_out{}; for (size_t i = 0; i < size; i += 2) { - for (int i = 0; i < TRACK_COUNT; i++) { - sig_out += tracks[i]->nextsample(); + for (int i = 0; i < Constants::TRACK_COUNT; i++) { + sig_out += tracks[i].nextsample(); } sig_out *= 0.1; @@ -129,22 +196,30 @@ namespace Heck { void mainloop() { - u32 now = System::GetNow(); + u32 now = ld::System::GetNow(); u32 log_time{}; bool heartbeat_led_state{ false }; u32 heartbeat_time{}; while (1) { - now = System::GetNow(); + now = ld::System::GetNow(); while (midi.HasEvents()) { - MidiEvent msg = midi.PopEvent(); + ld::MidiEvent msg = midi.PopEvent(); event_log.PushBack(msg); - if (msg.type == MidiMessageType::NoteOn) { - if (msg.channel >= 0 && msg.channel < TRACK_COUNT) { - tracks[msg.channel]->trigger(); + if (msg.type == ld::MidiMessageType::NoteOn) { + if (msg.channel >= 0 && msg.channel < Constants::TRACK_COUNT) { + tracks[msg.channel].trigger(); + } + } else if (msg.type == ld::MidiMessageType::ControlChange) { + ld::ControlChangeEvent cc = msg.AsControlChange(); + switch (cc.control_number) { + case Constants::MIDI_Mapping::TRACK_VOLUME: + tracks[cc.channel].volume(cc.value); + break; + case Constants::MIDI_Mapping::TRACK_FILTER: + tracks[cc.channel].volume(cc.value); + break; } - } else if (msg.type == MidiMessageType::ControlChange) { - // ControlChangeEvent cc = msg.AsControlChange(); event_log.PushBack(msg); } else { } diff --git a/src/perkons_instrument_interface.hh b/src/perkons_instrument_interface.hh deleted file mode 100644 index 67d20e6..0000000 --- a/src/perkons_instrument_interface.hh +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef HECK_DAISY_PERKONS_INSTRUMENT_INTERFACE -#define HECK_DAISY_PERKONS_INSTRUMENT_INTERFACE - -class PerkonsInstrumentInterface { -public: - virtual void trigger() = 0; - - // ctl-nr must be 0-5 - // val must be 0-1 - virtual void ctl(unsigned int ctl_nr, float val) = 0; - - // pos must be either 0,1,2 - virtual void switch_mode(unsigned int pos) = 0; - virtual void switch_variation(unsigned int pos) = 0; - virtual void switch_filter(unsigned int pos) = 0; - virtual float nextsample() = 0; - -private: -}; - -#endif // HECK_DAISY_PERKONS_INSTRUMENT_INTERFACE diff --git a/src/types.hh b/src/types.hh deleted file mode 100644 index c4669d5..0000000 --- a/src/types.hh +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef HECK_DAISY_TYPES_HH -#define HECK_DAISY_TYPES_HH - -#include - -using u8 = uint8_t; -using u16 = uint16_t; -using u32 = uint32_t; -using u64 = uint64_t; - -using i8 = int8_t; -using i16 = int16_t; -using i32 = int32_t; -using i64 = int64_t; - -using f32 = float; -using f64 = double; - -#endif \ No newline at end of file diff --git a/src/utils.hh b/src/utils.hh index 121a671..79a00b0 100644 --- a/src/utils.hh +++ b/src/utils.hh @@ -2,7 +2,7 @@ #define HECK_DAISY_UTILS_HH #include "daisy_seed.h" -#include "types.hh" +#include "globals.hh" void GetMidiTypeAsString(daisy::MidiEvent& msg, char* str); void GetMidiRTTypeAsString(daisy::MidiEvent& msg, char* str);