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 |
$(MAKE) -C src |
||||
|
|
||||
flash: |
example: lib |
||||
$(MAKE) -C src program |
$(MAKE) -C examples |
||||
|
|
||||
clean: |
flash: example |
||||
|
$(MAKE) -C examples program |
||||
|
|
||||
|
clean: clean-lib clean-examples |
||||
|
|
||||
|
clean-lib: |
||||
$(MAKE) -C src clean |
$(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))) |
HERE:=$(dir $(lastword $(MAKEFILE_LIST))) |
||||
-include $(HERE)../build.conf |
-include $(HERE)../Makefile.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 |
|
||||
|
|
||||
ALL_SRC = $(wildcard *.cc) |
ALL_SRC = $(wildcard *.cc) |
||||
TARGET_SRC = $(TARGET).cc |
CXX_SOURCES = $(ALL_SRC) |
||||
MODULES_SRC = $(filter-out main_%,$(ALL_SRC)) |
|
||||
CXX_SRC = $(MODULES_SRC) $(TARGET_SRC) |
|
||||
|
|
||||
CXX_SOURCES = $(CXX_SRC) |
|
||||
|
|
||||
include $(LIBDAISY_DIR)/core/Makefile |
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