
8 changed files with 410 additions and 0 deletions
@ -0,0 +1,55 @@ |
|||
#include "instr_kick.hh" |
|||
#include "daisysp.h" |
|||
|
|||
using namespace daisysp; |
|||
|
|||
|
|||
namespace Heck { |
|||
namespace Instrument { |
|||
|
|||
void Kick::init(float samplerate) |
|||
{ |
|||
osc.Init(samplerate); |
|||
|
|||
osc.SetWaveform(Oscillator::WAVE_TRI); |
|||
osc.SetAmp(1); |
|||
|
|||
pitchEnv.Init(samplerate); |
|||
pitchEnv.SetTime(ADENV_SEG_ATTACK, .001); |
|||
pitchEnv.SetTime(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.SetMax(1); |
|||
volEnv.SetMin(0); |
|||
} |
|||
|
|||
|
|||
void Kick::trigger() |
|||
{ |
|||
volEnv.Trigger(); |
|||
pitchEnv.Trigger(); |
|||
return; |
|||
} |
|||
|
|||
void Kick::ctl(unsigned int ctl_nr, float val) noexcept {} |
|||
void Kick::switch_mode(unsigned int pos) noexcept {} |
|||
void Kick::swtich_variation(unsigned int pos) noexcept {} |
|||
void Kick::switch_filter(unsigned int pos) noexcept {} |
|||
|
|||
float Kick::nextsample() noexcept |
|||
{ |
|||
float kck_env_out = volEnv.Process(); |
|||
|
|||
osc.SetFreq(pitchEnv.Process()); |
|||
osc.SetAmp(kck_env_out); |
|||
float osc_out = osc.Process(); |
|||
|
|||
return osc_out; |
|||
} |
|||
|
|||
} // namespace Instrument
|
|||
} // namespace Heck
|
@ -0,0 +1,34 @@ |
|||
#ifndef HECK_DAISY_INSTR_KICK_HH |
|||
#define HECK_DAISY_INSTR_KICK_HH |
|||
|
|||
#include "perkons_instrument_interface.hh" |
|||
#include "daisy_seed.h" |
|||
#include "daisysp.h" |
|||
|
|||
namespace ld = daisy; |
|||
namespace dsp = daisysp; |
|||
|
|||
namespace Heck { |
|||
namespace Instrument { |
|||
|
|||
class Kick : public PerkonsInstrumentInterface { |
|||
public: |
|||
void init(float samplerate); |
|||
|
|||
void trigger() noexcept override; |
|||
void ctl(unsigned int ctl_nr, float val) noexcept override; |
|||
void switch_mode(unsigned int pos) noexcept override; |
|||
void swtich_variation(unsigned int pos) noexcept override; |
|||
void switch_filter(unsigned int pos) noexcept override; |
|||
|
|||
float nextsample() noexcept override; |
|||
|
|||
private: |
|||
dsp::Oscillator osc; |
|||
dsp::AdEnv volEnv; |
|||
dsp::AdEnv pitchEnv; |
|||
}; |
|||
|
|||
} // namespace Instrument
|
|||
} // namespace Heck
|
|||
#endif |
@ -0,0 +1,40 @@ |
|||
#include "instr_noise.hh" |
|||
#include "daisysp.h" |
|||
|
|||
using namespace daisysp; |
|||
|
|||
namespace Heck { |
|||
namespace Instrument { |
|||
|
|||
void Noise::init(float samplerate) |
|||
{ |
|||
noise.Init(); |
|||
|
|||
env.Init(samplerate); |
|||
env.SetTime(ADENV_SEG_ATTACK, .0001); |
|||
env.SetTime(ADENV_SEG_DECAY, .01); |
|||
env.SetMax(1); |
|||
env.SetMin(0); |
|||
} |
|||
|
|||
void Noise::trigger() |
|||
{ |
|||
env.Trigger(); |
|||
} |
|||
|
|||
void Noise::ctl(unsigned int ctl_nr, float val) noexcept {} |
|||
void Noise::switch_mode(unsigned int pos) noexcept {} |
|||
void Noise::swtich_variation(unsigned int pos) noexcept {} |
|||
void Noise::switch_filter(unsigned int pos) noexcept {} |
|||
|
|||
float Noise::nextsample() noexcept |
|||
{ |
|||
float snr_env_out = env.Process(); |
|||
float sig = noise.Process(); |
|||
sig *= snr_env_out; |
|||
|
|||
return sig; |
|||
} |
|||
|
|||
} // namespace Instrument
|
|||
} // namespace Heck
|
@ -0,0 +1,33 @@ |
|||
#ifndef HECK_DAISY_INSTR_NOISE_HH |
|||
#define HECK_DAISY_INSTR_NOISE_HH |
|||
|
|||
#include "perkons_instrument_interface.hh" |
|||
#include "daisy_seed.h" |
|||
#include "daisysp.h" |
|||
|
|||
namespace ld = daisy; |
|||
namespace dsp = daisysp; |
|||
|
|||
namespace Heck { |
|||
namespace Instrument { |
|||
|
|||
class Noise : public PerkonsInstrumentInterface { |
|||
public: |
|||
void init(float samplerate); |
|||
|
|||
void trigger() noexcept override; |
|||
void ctl(unsigned int ctl_nr, float val) noexcept override; |
|||
void switch_mode(unsigned int pos) noexcept override; |
|||
void swtich_variation(unsigned int pos) noexcept override; |
|||
void switch_filter(unsigned int pos) noexcept override; |
|||
|
|||
float nextsample() noexcept override; |
|||
|
|||
private: |
|||
dsp::WhiteNoise noise; |
|||
dsp::AdEnv env; |
|||
}; |
|||
|
|||
} // namespace Instrument
|
|||
} // namespace Heck
|
|||
#endif |
@ -0,0 +1,138 @@ |
|||
// Hecks perkons extension
|
|||
#include "daisy_seed.h" |
|||
#include "daisysp.h" |
|||
|
|||
#include "types.hh" |
|||
#include "utils.hh" |
|||
#include "perkons_instrument_interface.hh" |
|||
#include "instr_kick.hh" |
|||
#include "instr_noise.hh" |
|||
|
|||
using namespace daisy; |
|||
using namespace daisysp; |
|||
|
|||
static DaisySeed hw{}; |
|||
static MidiUartHandler midi{}; |
|||
static FIFO<MidiEvent, 128> event_log{}; |
|||
static float samplerate{}; |
|||
|
|||
static Heck::Instrument::Kick instr_kick{}; |
|||
static Heck::Instrument::Noise instr_noise{}; |
|||
|
|||
void AudioCallback( |
|||
AudioHandle::InterleavingInputBuffer in, |
|||
AudioHandle::InterleavingOutputBuffer out, |
|||
size_t size) |
|||
{ |
|||
float sig{}; |
|||
|
|||
for (size_t i = 0; i < size; i += 2) { |
|||
float kick_sig = instr_kick.nextsample(); |
|||
float noise_sig = instr_noise.nextsample(); |
|||
sig = .5 * noise_sig + .5 * kick_sig; |
|||
sig *= 0.4; |
|||
|
|||
out[i] = sig; |
|||
out[i + 1] = sig; |
|||
} |
|||
} |
|||
|
|||
int init_dsp_chain() |
|||
{ |
|||
instr_kick.init(samplerate); |
|||
instr_noise.init(samplerate); |
|||
return 0; |
|||
} |
|||
|
|||
int main(void) |
|||
{ |
|||
hw.Configure(); |
|||
hw.Init(); |
|||
hw.StartLog(); |
|||
|
|||
uint32_t now = System::GetNow(); |
|||
uint32_t log_time{}; |
|||
bool heartbeat_led_state{ false }; |
|||
uint32_t heartbeat_time{}; |
|||
|
|||
init_dsp_chain(); |
|||
|
|||
// Start Audio
|
|||
hw.SetAudioBlockSize(4); |
|||
samplerate = hw.AudioSampleRate(); |
|||
hw.StartAudio(AudioCallback); |
|||
|
|||
// MIDI RX
|
|||
MidiUartHandler::Config midi_config; |
|||
midi.Init(midi_config); |
|||
uint32_t systick_last_rt_msg{}; |
|||
midi.realtime_callback = [&systick_last_rt_msg](MidiEvent& msg) { |
|||
uint32_t systick_now = System::GetNow(); |
|||
uint32_t systick_since_last = systick_now - systick_last_rt_msg; |
|||
systick_last_rt_msg = systick_now; |
|||
|
|||
char outstr[128]; |
|||
char rttype_str[32]; |
|||
GetMidiRTTypeAsString(msg, rttype_str); |
|||
|
|||
// sprintf(
|
|||
// outstr,
|
|||
// "RT: systick: %i\ttimedelta: %i\ttype: %s\n",
|
|||
// (unsigned int)systick_now,
|
|||
// (unsigned int)systick_since_last,
|
|||
// rttype_str);
|
|||
// hw.PrintLine("%s", outstr);
|
|||
}; |
|||
|
|||
midi.StartReceive(); |
|||
midi.Listen(); |
|||
|
|||
while (1) { |
|||
now = System::GetNow(); |
|||
while (midi.HasEvents()) { |
|||
MidiEvent msg = midi.PopEvent(); |
|||
event_log.PushBack(msg); |
|||
if (msg.type == MidiMessageType::NoteOn) { |
|||
if (msg.channel == 0) { |
|||
instr_kick.trigger(); |
|||
} |
|||
if (msg.channel == 1) { |
|||
instr_noise.trigger(); |
|||
} |
|||
|
|||
std::array<uint8_t, 3> bytes = { 0x90, 0x00, 0x00 }; |
|||
bytes[1] = msg.data[0]; |
|||
bytes[2] = msg.data[1]; |
|||
midi.SendMessage(bytes.data(), 3); |
|||
} else if (msg.type == MidiMessageType::ControlChange) { |
|||
} else { |
|||
} |
|||
} |
|||
|
|||
if (now - log_time > 5) { |
|||
log_time = now; |
|||
if (!event_log.IsEmpty()) { |
|||
auto msg = event_log.PopFront(); |
|||
char outstr[128]; |
|||
char type_str[32]; |
|||
GetMidiTypeAsString(msg, type_str); |
|||
sprintf( |
|||
outstr, |
|||
"time-last:\t%ld\ttype: %s\tChannel: %d\tData MSB: " |
|||
"%d\tData LSB: %d\n", |
|||
now, |
|||
type_str, |
|||
msg.channel, |
|||
msg.data[0], |
|||
msg.data[1]); |
|||
hw.PrintLine(outstr); |
|||
} |
|||
} |
|||
|
|||
if (now - heartbeat_time > 500) { |
|||
heartbeat_time = now; |
|||
hw.SetLed(heartbeat_led_state); |
|||
heartbeat_led_state = !heartbeat_led_state; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,21 @@ |
|||
#ifndef HECK_DAISY_PERKONS_INSTRUMENT_INTERFACE |
|||
#define HECK_DAISY_PERKONS_INSTRUMENT_INTERFACE |
|||
|
|||
class PerkonsInstrumentInterface { |
|||
public: |
|||
virtual void trigger() noexcept = 0; |
|||
|
|||
// ctl-nr must be 0-5
|
|||
// val must be 0-1
|
|||
virtual void ctl(unsigned int ctl_nr, float val) noexcept = 0; |
|||
|
|||
// pos must be either 0,1,2
|
|||
virtual void switch_mode(unsigned int pos) noexcept = 0; |
|||
virtual void swtich_variation(unsigned int pos) noexcept = 0; |
|||
virtual void switch_filter(unsigned int pos) noexcept = 0; |
|||
virtual float nextsample() noexcept = 0; |
|||
|
|||
private: |
|||
}; |
|||
|
|||
#endif // HECK_DAISY_PERKONS_INSTRUMENT_INTERFACE
|
@ -0,0 +1,78 @@ |
|||
#include "utils.hh" |
|||
|
|||
using namespace daisy; |
|||
|
|||
void GetMidiTypeAsString(MidiEvent& msg, char* str) |
|||
{ |
|||
switch (msg.type) { |
|||
case NoteOff: |
|||
strcpy(str, "NoteOff"); |
|||
break; |
|||
case NoteOn: |
|||
strcpy(str, "NoteOn"); |
|||
break; |
|||
case PolyphonicKeyPressure: |
|||
strcpy(str, "PolyKeyPres."); |
|||
break; |
|||
case ControlChange: |
|||
strcpy(str, "CC"); |
|||
break; |
|||
case ProgramChange: |
|||
strcpy(str, "Prog. Change"); |
|||
break; |
|||
case ChannelPressure: |
|||
strcpy(str, "Chn. Pressure"); |
|||
break; |
|||
case PitchBend: |
|||
strcpy(str, "PitchBend"); |
|||
break; |
|||
case SystemCommon: |
|||
strcpy(str, "Sys. Common"); |
|||
break; |
|||
case SystemRealTime: |
|||
strcpy(str, "Sys. Realtime"); |
|||
break; |
|||
case ChannelMode: |
|||
strcpy(str, "Chn. Mode"); |
|||
break; |
|||
default: |
|||
strcpy(str, "Unknown"); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
void GetMidiRTTypeAsString(MidiEvent& msg, char* str) |
|||
{ |
|||
switch (msg.srt_type) { |
|||
case TimingClock: |
|||
strcpy(str, "TimingClock"); |
|||
break; |
|||
case SRTUndefined0: |
|||
strcpy(str, "SRTUndefined0"); |
|||
break; |
|||
case Start: |
|||
strcpy(str, "Start"); |
|||
break; |
|||
case Continue: |
|||
strcpy(str, "Continue"); |
|||
break; |
|||
case Stop: |
|||
strcpy(str, "Stop"); |
|||
break; |
|||
case SRTUndefined1: |
|||
strcpy(str, "SRTUndefined1"); |
|||
break; |
|||
case ActiveSensing: |
|||
strcpy(str, "ActiveSensing"); |
|||
break; |
|||
case Reset: |
|||
strcpy(str, "Reset"); |
|||
break; |
|||
case SystemRealTimeLast: |
|||
strcpy(str, "SystemRealTimeLast"); |
|||
break; |
|||
default: |
|||
strcpy(str, "Unknown"); |
|||
break; |
|||
} |
|||
} |
@ -0,0 +1,11 @@ |
|||
#ifndef HECK_DAISY_UTILS_HH |
|||
#define HECK_DAISY_UTILS_HH |
|||
|
|||
#include "daisy_seed.h" |
|||
#include "types.hh" |
|||
|
|||
void GetMidiTypeAsString(daisy::MidiEvent& msg, char* str); |
|||
void GetMidiRTTypeAsString(daisy::MidiEvent& msg, char* str); |
|||
|
|||
|
|||
#endif // HECK_DAISY_UTILS_HH
|
Loading…
Reference in new issue