Compare commits
9 Commits
ee59c116eb
...
2e00ffbeba
Author | SHA1 | Date |
---|---|---|
|
2e00ffbeba | 7 months ago |
|
c67e6723cd | 7 months ago |
|
13aa24b17a | 7 months ago |
|
d2df1c612c | 7 months ago |
|
de621e8b93 | 7 months ago |
|
87481815f6 | 7 months ago |
|
3f22f34014 | 7 months ago |
|
b2d7e5eb7d | 7 months ago |
|
dc20dc60dd | 7 months ago |
14 changed files with 596 additions and 21 deletions
@ -1,13 +1,21 @@ |
|||
.PHONY: all flash clean |
|||
.PHONY: all lib example flash clean clean-lib clean-examples |
|||
|
|||
all: compile flash |
|||
all: flash |
|||
|
|||
compile: |
|||
lib: |
|||
$(MAKE) -C src |
|||
|
|||
flash: |
|||
$(MAKE) -C src program |
|||
example: lib |
|||
$(MAKE) -C examples |
|||
|
|||
clean: |
|||
flash: example |
|||
$(MAKE) -C examples program |
|||
|
|||
clean: clean-lib clean-examples |
|||
|
|||
clean-lib: |
|||
$(MAKE) -C src clean |
|||
|
|||
clean-examples: |
|||
$(MAKE) -C examples clean |
|||
|
|||
|
@ -0,0 +1,12 @@ |
|||
HERE:=$(dir $(lastword $(MAKEFILE_LIST))) |
|||
-include $(HERE)build.conf |
|||
|
|||
TARGET_LIB ?= libdizzy |
|||
DEBUG ?= 0 |
|||
|
|||
LIBDAISY_DIR ?= ../../heck_libDaisy |
|||
DAISYSP_DIR ?= ../../heck_DaisySP |
|||
|
|||
CXX_STANDARD ?= -std=c++17 |
|||
CXXFLAGS += -Wall -Wno-unused -Wno-reorder-ctor -Wno-switch |
|||
CXXFLAGS += -fdiagnostics-color=always |
@ -0,0 +1,18 @@ |
|||
HERE:=$(dir $(lastword $(MAKEFILE_LIST))) |
|||
-include $(HERE)../Makefile.conf |
|||
|
|||
TARGET ?= main_blink |
|||
DEBUG ?= 0 |
|||
|
|||
LIBDIZZY_DIR ?= ../src/ |
|||
CXXFLAGS += -I$(LIBDIZZY_DIR) |
|||
LDFLAGS += -L$(LIBDIZZY_DIR)build/ |
|||
LDFLAGS += -ldizzy |
|||
|
|||
ALL_SRC = $(wildcard *.cc) |
|||
TARGET_SRC = $(TARGET).cc |
|||
MODULES_SRC = $(filter-out main_%,$(ALL_SRC)) |
|||
CXX_SRC = $(MODULES_SRC) $(TARGET_SRC) |
|||
|
|||
CXX_SOURCES = $(CXX_SRC) |
|||
include $(LIBDAISY_DIR)/core/Makefile |
@ -0,0 +1,46 @@ |
|||
#include "main_adc.hh" |
|||
#include "utils.hh" |
|||
#include <functional> |
|||
|
|||
namespace Heck { |
|||
namespace { // anonymous namespace for internal linkage
|
|||
ld::DaisySeed seed{}; |
|||
Observer<int> pot1{}; |
|||
SWTimer scan_pots{}; |
|||
|
|||
void init() |
|||
{ |
|||
seed.Init(Constants::CPU_BOOST480MHZ); |
|||
seed.StartLog(Constants::Developer::LOG_BLOCKS_BOOT); |
|||
|
|||
ld::AdcChannelConfig adc_cfg[3]; |
|||
adc_cfg[0].InitSingle(ld::DaisySeed::GetPin(Constants::Hardware::PIN_POT_1)); |
|||
|
|||
seed.adc.Init(adc_cfg, 1); |
|||
seed.adc.Start(); |
|||
|
|||
scan_pots.set_period(10); |
|||
scan_pots.set_callback([]() { |
|||
pot1.on_change_fuzzy(seed.adc.Get(0), 10, [](int val) { |
|||
seed.PrintLine("POT_1: %d", val); |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
void mainloop() |
|||
{ |
|||
u32&& time_boot_ms{}; |
|||
while (true) { |
|||
time_boot_ms = ld::System::GetNow(); |
|||
scan_pots.is_it_already_time_again(time_boot_ms); |
|||
} |
|||
} |
|||
} // namespace
|
|||
} // namespace Heck
|
|||
|
|||
|
|||
int main() |
|||
{ |
|||
Heck::init(); |
|||
Heck::mainloop(); |
|||
} |
@ -0,0 +1,28 @@ |
|||
#ifndef HECK_MAIN_ADC_HH |
|||
#define HECK_MAIN_ADC_HH |
|||
|
|||
#include <functional> |
|||
#include "types.hh" |
|||
|
|||
namespace Heck { |
|||
namespace Constants { |
|||
namespace Hardware { |
|||
constexpr int PIN_BUTTON_1 = 28; |
|||
constexpr int PIN_POT_1 = 15; |
|||
constexpr int PIN_POT_2 = 16; |
|||
constexpr int PIN_POT_3 = 15; |
|||
} |
|||
|
|||
constexpr bool CPU_BOOST480MHZ = false; |
|||
|
|||
namespace Developer { |
|||
constexpr bool LOG_BLOCKS_BOOT = false; |
|||
} |
|||
} // namespace Constants
|
|||
|
|||
//Hardware
|
|||
extern ld::DaisySeed seed; |
|||
// extern ld::Switch but_rec;
|
|||
} // namespace Heck
|
|||
|
|||
#endif |
@ -0,0 +1,124 @@ |
|||
// Hecks perkons extension
|
|||
|
|||
#include <functional> |
|||
#include "main_template_full.hh" |
|||
#include "utils.hh" |
|||
|
|||
namespace Heck { |
|||
namespace { // anonymous namespace for internal linkage
|
|||
// =============================================================================================
|
|||
// INIT
|
|||
// =============================================================================================
|
|||
ld::DaisySeed seed{}; |
|||
|
|||
static ld::MidiUartHandler midi{}; |
|||
|
|||
// function prototypes
|
|||
void audio_callback( |
|||
ld::AudioHandle::InputBuffer in, |
|||
ld::AudioHandle::OutputBuffer out, |
|||
size_t size) |
|||
; |
|||
void midi_realtime_handler(const ld::MidiEvent& msg); |
|||
|
|||
void init() |
|||
{ |
|||
seed.Configure(); |
|||
seed.Init(Constants::CPU_BOOST480MHZ); |
|||
seed.StartLog(Constants::Developer::LOG_BLOCKS_BOOT); |
|||
|
|||
seed.PrintLine("Setting Blocksize: %i", Constants::AUDIO_BUFFERSIZE); |
|||
seed.SetAudioBlockSize(Constants::AUDIO_BUFFERSIZE); |
|||
|
|||
seed.PrintLine("Setting Samplerate: %i", Constants::AUDIO_SAMPLERATE); |
|||
seed.SetAudioSampleRate(Constants::AUDIO_SAMPLERATE); |
|||
|
|||
seed.PrintLine("Initializing MIDI"); |
|||
ld::MidiUartHandler::Config midi_config{}; |
|||
midi.Init(midi_config); |
|||
|
|||
seed.PrintLine("Starting MIDI Receive"); |
|||
midi.StartReceiveRt(&midi_realtime_handler); |
|||
midi.Listen(); |
|||
|
|||
seed.PrintLine("Starting Audio"); |
|||
seed.StartAudio(audio_callback); |
|||
} |
|||
|
|||
|
|||
// =============================================================================================
|
|||
// RUN
|
|||
// =============================================================================================
|
|||
|
|||
void audio_callback(ld::AudioHandle::InputBuffer in, ld::AudioHandle::OutputBuffer out, size_t size) |
|||
{ |
|||
// Channel 1
|
|||
for (size_t i = 0; i < size; i++) { |
|||
out[0][i] = in[0][i]; |
|||
} |
|||
|
|||
// Channel 2
|
|||
for (size_t i = 0; i < size; i++) { |
|||
out[1][i] = in[1][i]; |
|||
} |
|||
} |
|||
|
|||
|
|||
void midi_realtime_handler(const ld::MidiEvent& msg) |
|||
{ |
|||
switch (msg.srt_type) { |
|||
case ld::TimingClock: { |
|||
} break; |
|||
case ld::Start: { |
|||
} break; |
|||
case ld::Stop: { |
|||
} break; |
|||
case ld::Reset: { |
|||
} break; |
|||
case ld::Continue: { |
|||
} break; |
|||
} |
|||
} |
|||
|
|||
void midi_async_handler(const ld::MidiEvent& msg) |
|||
{ |
|||
char strbuf[128]; |
|||
GetMidiTypeAsString(msg, &strbuf[0]); |
|||
seed.PrintLine("%s", strbuf); |
|||
return; |
|||
} |
|||
|
|||
void mainloop() |
|||
{ |
|||
seed.PrintLine("Entering MainLoop"); |
|||
u32 systick_now{}; |
|||
|
|||
bool heartbeat_led_state{ false }; |
|||
|
|||
SWTimer heartbeat{}; |
|||
heartbeat.set_period(100); |
|||
heartbeat.set_callback([&heartbeat_led_state]() { |
|||
heartbeat_led_state = !heartbeat_led_state; |
|||
seed.SetLed(heartbeat_led_state); |
|||
return; |
|||
}); |
|||
|
|||
while (true) { |
|||
systick_now = ld::System::GetNow(); |
|||
|
|||
while (midi.HasEvents()) { |
|||
midi_async_handler(midi.PopEvent()); |
|||
} |
|||
|
|||
heartbeat.is_it_already_time_again(systick_now); |
|||
} |
|||
} |
|||
} // namespace
|
|||
} // namespace Heck
|
|||
|
|||
|
|||
int main() |
|||
{ |
|||
Heck::init(); |
|||
Heck::mainloop(); |
|||
} |
@ -0,0 +1,30 @@ |
|||
#ifndef HECK_DAISY_GLOBALS_HH |
|||
#define HECK_DAISY_GLOBALS_HH |
|||
|
|||
#include <cstdint> |
|||
#include "daisy_seed.h" |
|||
#include "daisysp.h" |
|||
#include "types.hh" |
|||
|
|||
namespace Heck { |
|||
namespace Constants { |
|||
namespace Hardware { |
|||
// constexpr int PIN_BUTTON_RECORD = 28;
|
|||
} |
|||
|
|||
constexpr bool CPU_BOOST480MHZ = false; |
|||
constexpr int AUDIO_BUFFERSIZE = 4; |
|||
constexpr Samplerate AUDIO_SAMPLERATE = Samplerate::SAI_48KHZ; |
|||
|
|||
namespace Developer { |
|||
constexpr bool LOG_BLOCKS_BOOT = false; |
|||
} |
|||
} // namespace Constants
|
|||
|
|||
//Hardware
|
|||
extern ld::DaisySeed seed; |
|||
// extern ld::Switch but_rec;
|
|||
} // namespace Heck
|
|||
|
|||
|
|||
#endif |
@ -1,20 +1,7 @@ |
|||
HERE:=$(dir $(lastword $(MAKEFILE_LIST))) |
|||
-include $(HERE)../build.conf |
|||
|
|||
TARGET ?= main_blink |
|||
DEBUG ?= 0 |
|||
LIBDAISY_DIR ?= ../../heck_libDaisy |
|||
DAISYSP_DIR ?= ../../heck_DaisySP |
|||
|
|||
CXX_STANDARD ?= -std=c++17 |
|||
CXXFLAGS += -Wall -Wno-unused -Wno-reorder-ctor -Wno-switch |
|||
CXXFLAGS += -fdiagnostics-color=always |
|||
-include $(HERE)../Makefile.conf |
|||
|
|||
ALL_SRC = $(wildcard *.cc) |
|||
TARGET_SRC = $(TARGET).cc |
|||
MODULES_SRC = $(filter-out main_%,$(ALL_SRC)) |
|||
CXX_SRC = $(MODULES_SRC) $(TARGET_SRC) |
|||
|
|||
CXX_SOURCES = $(CXX_SRC) |
|||
CXX_SOURCES = $(ALL_SRC) |
|||
|
|||
include $(LIBDAISY_DIR)/core/Makefile |
|||
|
@ -0,0 +1,110 @@ |
|||
#include "density.hh" |
|||
namespace Heck { |
|||
|
|||
void Density::process(const f32 *inSourceP, f32 *inDestP, u32 size) |
|||
{ |
|||
UInt32 nSampleFrames = size; |
|||
const Float32 *sourceP = inSourceP; |
|||
Float32 *destP = inDestP; |
|||
Float64 inputSample; |
|||
Float64 drySample; |
|||
Float64 overallscale = 1.0; |
|||
overallscale /= 44100.0; |
|||
overallscale *= Constants::AUDIO_SAMPLERATE; |
|||
Float64 density = params[0]; |
|||
Float64 iirAmount = pow(params[1], 3) / overallscale; |
|||
Float64 output = params[2]; |
|||
Float64 wet = params[3]; |
|||
Float64 dry = 1.0 - wet; |
|||
Float64 bridgerectifier; |
|||
Float64 out = fabs(density); |
|||
density = density * fabs(density); |
|||
Float64 count; |
|||
|
|||
while (nSampleFrames-- > 0) { |
|||
inputSample = *sourceP; |
|||
|
|||
if (fabs(inputSample) < 1.18e-23) { |
|||
inputSample = fpd * 1.18e-17; |
|||
} |
|||
|
|||
drySample = inputSample; |
|||
|
|||
if (fpFlip) { |
|||
iirSampleA = (iirSampleA * (1 - iirAmount)) + (inputSample * iirAmount); |
|||
inputSample -= iirSampleA; |
|||
} else { |
|||
iirSampleB = (iirSampleB * (1 - iirAmount)) + (inputSample * iirAmount); |
|||
inputSample -= iirSampleB; |
|||
} |
|||
|
|||
//highpass section
|
|||
count = density; |
|||
while (count > 1.0) { |
|||
bridgerectifier = fabs(inputSample) * 1.57079633; |
|||
if (bridgerectifier > 1.57079633) { |
|||
bridgerectifier = 1.57079633; |
|||
} |
|||
//max value for sine function
|
|||
bridgerectifier = sin(bridgerectifier); |
|||
if (inputSample > 0.0) { |
|||
inputSample = bridgerectifier; |
|||
} else { |
|||
inputSample = -bridgerectifier; |
|||
} |
|||
count = count - 1.0; |
|||
} |
|||
|
|||
//we have now accounted for any really high density settings.
|
|||
while (out > 1.0) { |
|||
out = out - 1.0; |
|||
} |
|||
bridgerectifier = fabs(inputSample) * 1.57079633; |
|||
if (bridgerectifier > 1.57079633) { |
|||
bridgerectifier = 1.57079633; |
|||
} |
|||
//max value for sine function
|
|||
if (density > 0) { |
|||
bridgerectifier = sin(bridgerectifier); |
|||
} else { |
|||
bridgerectifier = 1 - cos(bridgerectifier); |
|||
} |
|||
//produce either boosted or starved version
|
|||
if (inputSample > 0) { |
|||
inputSample = (inputSample * (1 - out)) + (bridgerectifier * out); |
|||
} else { |
|||
inputSample = (inputSample * (1 - out)) - (bridgerectifier * out); |
|||
} |
|||
//blend according to density control
|
|||
|
|||
if (output < 1.0) { |
|||
inputSample *= output; |
|||
} |
|||
|
|||
if (wet < 1.0) { |
|||
inputSample = (drySample * dry) + (inputSample * wet); |
|||
} |
|||
|
|||
//nice little output stage template: if we have another scale of floating point
|
|||
//number, we really don't want to meaninglessly multiply that by 1.0.
|
|||
fpFlip = !fpFlip; |
|||
|
|||
//begin 32 bit floating point dither
|
|||
|
|||
if constexpr (DO_DITHER) { |
|||
int expon; |
|||
frexpf((float)inputSample, &expon); |
|||
fpd ^= fpd << 13; |
|||
fpd ^= fpd >> 17; |
|||
fpd ^= fpd << 5; |
|||
inputSample += ((double(fpd) - uint32_t(0x7fffffff)) * 5.5e-36l * pow(2, expon + 62)); |
|||
//end 32 bit floating point dither
|
|||
} |
|||
*destP = inputSample; |
|||
|
|||
//that simple.
|
|||
sourceP++; |
|||
destP++; |
|||
} |
|||
} |
|||
} // namespace Heck
|
@ -0,0 +1,33 @@ |
|||
#ifndef HECK_OSP_DENSITY |
|||
#define HECK_OSP_DENSITY |
|||
|
|||
#include "types.hh" |
|||
#include <array> |
|||
|
|||
namespace Heck::Constants { |
|||
constexpr Samplerate AUDIO_SAMPLERATE = Samplerate::SAI_48KHZ; |
|||
} |
|||
|
|||
namespace Heck { |
|||
|
|||
struct Density { |
|||
using Float32 = f32; |
|||
using Float64 = f64; |
|||
using UInt32 = u32; |
|||
|
|||
static constexpr bool DO_DITHER{ false }; |
|||
|
|||
std::array<f64, 4> params{ 0., 0., 1., 1. }; |
|||
|
|||
void process(const f32 * const inSourceP, f32 *inDestP, u32 size); |
|||
|
|||
private: |
|||
Float64 iirSampleA; |
|||
Float64 iirSampleB; |
|||
uint32_t fpd; |
|||
bool fpFlip; |
|||
}; |
|||
|
|||
|
|||
} // namespace Heck
|
|||
#endif |
@ -0,0 +1,119 @@ |
|||
#include "utils.hh" |
|||
|
|||
namespace Heck { |
|||
|
|||
void GetMidiTypeAsString(const ld::MidiEvent& msg, char* str) |
|||
{ |
|||
switch (msg.type) { |
|||
case ld::NoteOff: |
|||
strcpy(str, "NoteOff"); |
|||
break; |
|||
case ld::NoteOn: |
|||
strcpy(str, "NoteOn"); |
|||
break; |
|||
case ld::PolyphonicKeyPressure: |
|||
strcpy(str, "PolyKeyPres."); |
|||
break; |
|||
case ld::ControlChange: |
|||
strcpy(str, "CC"); |
|||
break; |
|||
case ld::ProgramChange: |
|||
strcpy(str, "Prog. Change"); |
|||
break; |
|||
case ld::ChannelPressure: |
|||
strcpy(str, "Chn. Pressure"); |
|||
break; |
|||
case ld::PitchBend: |
|||
strcpy(str, "PitchBend"); |
|||
break; |
|||
case ld::SystemCommon: |
|||
strcpy(str, "Sys. Common"); |
|||
break; |
|||
case ld::SystemRealTime: |
|||
strcpy(str, "Sys. Realtime"); |
|||
break; |
|||
case ld::ChannelMode: |
|||
strcpy(str, "Chn. Mode"); |
|||
break; |
|||
default: |
|||
strcpy(str, "Unknown"); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
void GetMidiRTTypeAsString(const ld::MidiEvent& msg, char* str) |
|||
{ |
|||
switch (msg.srt_type) { |
|||
case ld::TimingClock: |
|||
strcpy(str, "TimingClock"); |
|||
break; |
|||
case ld::SRTUndefined0: |
|||
strcpy(str, "SRTUndefined0"); |
|||
break; |
|||
case ld::Start: |
|||
strcpy(str, "Start"); |
|||
break; |
|||
case ld::Continue: |
|||
strcpy(str, "Continue"); |
|||
break; |
|||
case ld::Stop: |
|||
strcpy(str, "Stop"); |
|||
break; |
|||
case ld::SRTUndefined1: |
|||
strcpy(str, "SRTUndefined1"); |
|||
break; |
|||
case ld::ActiveSensing: |
|||
strcpy(str, "ActiveSensing"); |
|||
break; |
|||
case ld::Reset: |
|||
strcpy(str, "Reset"); |
|||
break; |
|||
case ld::SystemRealTimeLast: |
|||
strcpy(str, "SystemRealTimeLast"); |
|||
break; |
|||
default: |
|||
strcpy(str, "Unknown"); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
|
|||
float scalen_min_max(float val, float min, float max) |
|||
{ |
|||
float range = max - min; |
|||
float ret = min + (val * range); |
|||
return ret; |
|||
} |
|||
|
|||
float scalen_center_range(float val, float center, float range) |
|||
{ |
|||
float min = center - (range / 2); |
|||
float ret = min + (val * range); |
|||
return ret; |
|||
} |
|||
} // namespace Heck
|
|||
|
|||
namespace Heck { |
|||
void SWTimer::set_period(u32 time_units) |
|||
{ |
|||
time_period_ = time_units; |
|||
} |
|||
|
|||
void SWTimer::set_callback(const Callback& cb) |
|||
{ |
|||
callback_ = cb; |
|||
} |
|||
|
|||
bool SWTimer::is_it_already_time_again(u32 time_now) |
|||
{ |
|||
if (time_now - time_last_exec_ >= time_period_) { |
|||
time_last_exec_ = time_now; |
|||
if (callback_) { |
|||
//todo: constexpr if metrics
|
|||
callback_(); |
|||
} |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
} // namespace Heck
|
@ -0,0 +1,60 @@ |
|||
#ifndef HECK_DAISY_UTILS_HH |
|||
#define HECK_DAISY_UTILS_HH |
|||
|
|||
#include "daisy_seed.h" |
|||
#include "types.hh" |
|||
|
|||
namespace Heck { |
|||
void GetMidiTypeAsString(const ld::MidiEvent& msg, char* str); |
|||
void GetMidiRTTypeAsString(const ld::MidiEvent& msg, char* str); |
|||
|
|||
float scalen_min_max(float val, float min, float max); |
|||
float scalen_center_range(float val, float center, float range); |
|||
} // namespace Heck
|
|||
|
|||
|
|||
namespace Heck { |
|||
class SWTimer { |
|||
public: |
|||
using Callback = std::function<void(void)>; |
|||
|
|||
void set_period(u32 time_units); |
|||
void set_callback(const Callback& cb); |
|||
bool is_it_already_time_again(u32 time_now); |
|||
|
|||
private: |
|||
Callback callback_{}; |
|||
u32 time_last_exec_{}; |
|||
u32 time_period_{}; |
|||
}; |
|||
} // namespace Heck
|
|||
|
|||
namespace Heck { |
|||
template<typename T> class Observer { |
|||
|
|||
public: |
|||
bool on_change(T val_new, std::function<void(T val_current)> fn) |
|||
{ |
|||
if (val_new != val_current_) { |
|||
val_current_ = val_new; |
|||
fn(val_current_); |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
bool on_change_fuzzy(T val_new, T min_deviation, std::function<void(T val_current)> fn) |
|||
{ |
|||
if (std::abs(val_new - val_current_) >= min_deviation) { |
|||
val_current_ = val_new; |
|||
fn(val_current_); |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
private: |
|||
static inline T val_current_{}; |
|||
}; |
|||
} // namespace Heck
|
|||
#endif // HECK_DAISY_UTILS_HH
|
Loading…
Reference in new issue