|
|
@ -1,42 +1,86 @@ |
|
|
|
// Hecks perkons extension
|
|
|
|
#include <map> |
|
|
|
#include <array> |
|
|
|
#include <memory> |
|
|
|
#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<MidiEvent, 128> event_log{}; |
|
|
|
static ld::DaisySeed hw{}; |
|
|
|
static ld::MidiUartHandler midi{}; |
|
|
|
static ld::FIFO<ld::MidiEvent, 128> event_log{}; |
|
|
|
|
|
|
|
Instrument::Noise instrument0{}; |
|
|
|
Instrument::FM instrument1{}; |
|
|
|
Instrument::FM instrument2{}; |
|
|
|
Instrument::Kick instrument3{}; |
|
|
|
|
|
|
|
std::array<std::shared_ptr<PerkonsInstrumentInterface>, 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::AbstractInstrument> instrument_{}; |
|
|
|
dsp::LinearVCA vca_{}; |
|
|
|
dsp::Svf filter_{}; |
|
|
|
|
|
|
|
float ctl_volume_{}; |
|
|
|
}; |
|
|
|
|
|
|
|
std::array<Track, Constants::TRACK_COUNT> 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<PerkonsInstrumentInterface>(&instrument0); |
|
|
|
instrument1.init(samplerate); |
|
|
|
tracks[1] = std::shared_ptr<PerkonsInstrumentInterface>(&instrument1); |
|
|
|
instrument2.init(samplerate); |
|
|
|
tracks[2] = std::shared_ptr<PerkonsInstrumentInterface>(&instrument2); |
|
|
|
instrument3.init(samplerate); |
|
|
|
tracks[3] = std::shared_ptr<PerkonsInstrumentInterface>(&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 { |
|
|
|
} |
|
|
|