Browse Source

Add some initial structures towards the envisioned perkons enhancement

main
heck 7 months ago
parent
commit
82d9ba7f4c
  1. 55
      src/instr_kick.cc
  2. 34
      src/instr_kick.hh
  3. 40
      src/instr_noise.cc
  4. 33
      src/instr_noise.hh
  5. 138
      src/main_perkons.cc
  6. 21
      src/perkons_instrument_interface.hh
  7. 78
      src/utils.cc
  8. 11
      src/utils.hh

55
src/instr_kick.cc

@ -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

34
src/instr_kick.hh

@ -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

40
src/instr_noise.cc

@ -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

33
src/instr_noise.hh

@ -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

138
src/main_perkons.cc

@ -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;
}
}
}

21
src/perkons_instrument_interface.hh

@ -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

78
src/utils.cc

@ -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;
}
}

11
src/utils.hh

@ -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…
Cancel
Save