diff --git a/.vscode/launch.json b/.vscode/launch.json index 3bcb9af..b9747de 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -434,6 +434,66 @@ "svdFile": "${workspaceRoot}/.vscode/STM32H750x.svd", "type": "cortex-debug" }, + { + "name": "Remote Lichen Sines", + "configFiles": [ + "interface/stlink.cfg", + "target/stm32h7x.cfg" + ], + "cwd": "${workspaceFolder}/hosts/daisy/examples/lichen-medium/sines", + "debuggerArgs": [ + "-d", + "${workspaceRoot}/hosts/daisy/examples/lichen-medium/sines" + ], + "executable": "${workspaceRoot}/hosts/daisy/examples/lichen-medium/sines/build/lichen-medium-sines.elf", + "interface": "swd", + "openOCDLaunchCommands": [ + "init", + "reset init" + ], + "preLaunchTask": "Debug Build Lichen Medium Examples", + "preRestartCommands": [ + "load", + "enable breakpoint", + "monitor reset" + ], + "request": "launch", + "runToEntryPoint": "main", + "servertype": "openocd", + "showDevDebugOutput": "parsed", + "svdFile": "${workspaceRoot}/.vscode/STM32H750x.svd", + "type": "cortex-debug" + }, + { + "name": "Remote Lichen Freddie Bare Board Test", + "configFiles": [ + "interface/stlink.cfg", + "target/stm32h7x.cfg" + ], + "cwd": "${workspaceFolder}/hosts/daisy/examples/lichen-freddie/bare-board-test", + "debuggerArgs": [ + "-d", + "${workspaceRoot}/hosts/daisy/examples/lichen-freddie/bare-board-test" + ], + "executable": "${workspaceRoot}/hosts/daisy/examples/lichen-freddie/bare-board-test/build/lichen-freddie-bare-board-test.elf", + "interface": "swd", + "openOCDLaunchCommands": [ + "init", + "reset init" + ], + "preLaunchTask": "Debug Build Lichen Freddie Examples", + "preRestartCommands": [ + "load", + "enable breakpoint", + "monitor reset" + ], + "request": "launch", + "runToEntryPoint": "main", + "servertype": "openocd", + "showDevDebugOutput": "parsed", + "svdFile": "${workspaceRoot}/.vscode/STM32H750x.svd", + "type": "cortex-debug" + }, { "name": "Remote Versio Filter", "configFiles": [ diff --git a/.vscode/settings.json b/.vscode/settings.json index e3ce90e..ee71e1b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -28,6 +28,38 @@ "array": "cpp", "initializer_list": "cpp", "map": "cpp", - "unordered_map": "cpp" + "unordered_map": "cpp", + "signaletic-host.h": "c", + "__config": "cpp", + "__debug": "cpp", + "__errc": "cpp", + "__mutex_base": "cpp", + "__threading_support": "cpp", + "__verbose_abort": "cpp", + "cctype": "cpp", + "charconv": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "complex": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "exception": "cpp", + "iosfwd": "cpp", + "mutex": "cpp", + "new": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "typeinfo": "cpp", + "variant": "cpp", + "algorithm": "cpp" } } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index f5056b7..ac7b5b5 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -206,6 +206,20 @@ ], "type": "shell" }, + { + "label": "Debug Build Lichen Freddie Examples", + "dependsOn": [ + "Build libdaisy" + ], + "command": "make clean;DEBUG=1 OPT=-Og make", + "options": { + "cwd": "${workspaceFolder}/hosts/daisy/examples/lichen-freddie" + }, + "problemMatcher": [ + "$gcc" + ], + "type": "shell" + }, { "label": "Build Bluemchen Examples", "dependsOn": [ diff --git a/hosts/daisy/examples/bluemchen/bare-board-test/src/bluemchen-bare-board-test.cpp b/hosts/daisy/examples/bluemchen/bare-board-test/src/bluemchen-bare-board-test.cpp index 0b27c67..4e86882 100644 --- a/hosts/daisy/examples/bluemchen/bare-board-test/src/bluemchen-bare-board-test.cpp +++ b/hosts/daisy/examples/bluemchen/bare-board-test/src/bluemchen-bare-board-test.cpp @@ -23,11 +23,18 @@ struct sig_dsp_Signal* listStorage[MAX_NUM_SIGNALS]; struct sig_List signals; struct sig_dsp_SignalListEvaluator* evaluator; -sig::libdaisy::Seed board; +sig::libdaisy::seed::SeedBoard board; daisy::OledDisplay display; FixedCapStr<20> displayStr; struct sig_daisy_Host* host; sig::libdaisy::AnalogInput knob1; +float knob1RawValue = 0.0f; +sig::libdaisy::AnalogInput knob2; +float knob2RawValue = 0.0f; +sig::libdaisy::InvertedAnalogInput cv1; +float cv1RawValue = 0.0f; +sig::libdaisy::InvertedAnalogInput cv2; +float cv2RawValue = 0.0f; struct sig_dsp_Value* freq; sig::libdaisy::GateInput gateIn; struct sig_dsp_Value* gain; @@ -38,6 +45,7 @@ struct sig_dsp_BinaryOp* harmonizerFreqScale; struct sig_dsp_Oscillator* harmonizer; sig::libdaisy::Toggle button; struct sig_dsp_Value* buttonValue; +float buttonRawValue = 0.0f; struct sig_dsp_BinaryOp* mixer; struct sig_dsp_BinaryOp* attenuator; @@ -102,8 +110,13 @@ void buildSignalGraph(struct sig_Allocator* allocator, void AudioCallback(daisy::AudioHandle::InputBuffer in, daisy::AudioHandle::OutputBuffer out, size_t size) { - freq->parameters.value = 1760.0f * knob1.Value(); - buttonValue->parameters.value = button.Value(); + knob1RawValue = knob1.Value(); + knob2RawValue = knob2.Value(); + cv1RawValue = cv1.Value(); + cv2RawValue = cv2.Value(); + buttonRawValue = button.Value(); + freq->parameters.value = 1760.0f * knob1RawValue; + buttonValue->parameters.value = buttonRawValue; evaluator->evaluate((struct sig_dsp_SignalEvaluator*) evaluator); @@ -119,10 +132,24 @@ void updateOLED() { displayStr.Clear(); displayStr.Append("Button "); - displayStr.AppendFloat(button.Value(), 1); + displayStr.AppendFloat(buttonRawValue, 1); display.SetCursor(0, 0); display.WriteString(displayStr.Cstr(), Font_6x8, true); + displayStr.Clear(); + displayStr.AppendFloat(knob1RawValue, 2); + displayStr.Append(" "); + displayStr.AppendFloat(knob2RawValue, 2); + display.SetCursor(0, 8); + display.WriteString(displayStr.Cstr(), Font_6x8, true); + + displayStr.Clear(); + displayStr.AppendFloat(cv1RawValue, 2); + displayStr.Append(" "); + displayStr.AppendFloat(cv2RawValue, 2); + display.SetCursor(0, 16); + display.WriteString(displayStr.Cstr(), Font_6x8, true); + display.Update(); } @@ -144,10 +171,10 @@ int main(void) { // TODO: Move ADC initialization out of the Init function dsy_gpio_pin adcPins[] = { - sig::libdaisy::SEED_PIN_D16, - sig::libdaisy::SEED_PIN_D15, - sig::libdaisy::SEED_PIN_D21, - sig::libdaisy::SEED_PIN_D18 + sig::libdaisy::seed::PIN_D16, + sig::libdaisy::seed::PIN_D15, + sig::libdaisy::seed::PIN_D21, + sig::libdaisy::seed::PIN_D18 }; board.InitADC(adcPins, 4); @@ -157,9 +184,11 @@ int main(void) { &audioSettings); buildSignalGraph(&allocator, context, &signals, &audioSettings, &status); - knob1.Init(&board.adc, 1); - // gateIn.Init(sig::libdaisy::PATCH_SM_PIN_B10); - button.Init(sig::libdaisy::SEED_PIN_D28); // Encoder button. + knob1.Init(&board.adc, 0); + knob2.Init(&board.adc, 1); + cv1.Init(&board.adc, 2); + cv2.Init(&board.adc, 3); + button.Init(sig::libdaisy::seed::PIN_D28); // Encoder button. board.audio.Start(AudioCallback); diff --git a/hosts/daisy/examples/bluemchen/oscillator/Makefile b/hosts/daisy/examples/bluemchen/oscillator/Makefile index f232928..b4611b9 100644 --- a/hosts/daisy/examples/bluemchen/oscillator/Makefile +++ b/hosts/daisy/examples/bluemchen/oscillator/Makefile @@ -5,10 +5,10 @@ DEBUG = 0 OPT = -O3 # Sources -C_SOURCES += ../../../../../libsignaletic/vendor/tlsf/tlsf.c ../../../../../libsignaletic/src/libsignaletic.c +C_SOURCES += ../../../../../libsignaletic/vendor/tlsf/tlsf.c ../../../../../libsignaletic/src/libsignaletic.c ../../../src/signaletic-host.c C_INCLUDES += -I../../../../../libsignaletic/vendor/tlsf -I../../../../../libsignaletic/include -CPP_SOURCES = ../../../vendor/kxmx_bluemchen/src/kxmx_bluemchen.cpp ../../../src/signaletic-daisy-host.cpp ../../../src/daisy-bluemchen-host.cpp src/${TARGET}.cpp +CPP_SOURCES = ../../../src/signaletic-daisy-host.cpp ../../../src/sig-daisy-seed.cpp src/${TARGET}.cpp USE_FATFS = 0 diff --git a/hosts/daisy/examples/bluemchen/oscillator/src/signaletic-bluemchen-oscillator.cpp b/hosts/daisy/examples/bluemchen/oscillator/src/signaletic-bluemchen-oscillator.cpp index 22c05bb..01c3405 100644 --- a/hosts/daisy/examples/bluemchen/oscillator/src/signaletic-bluemchen-oscillator.cpp +++ b/hosts/daisy/examples/bluemchen/oscillator/src/signaletic-bluemchen-oscillator.cpp @@ -1,10 +1,12 @@ #include #include #include -#include "../../../../include/daisy-bluemchen-host.h" +#include "../../../../include/signaletic-daisy-host.h" +#include "../../../../include/kxmx-bluemchen-device.hpp" -using namespace kxmx; +using namespace kxmx::bluemchen; using namespace daisy; +using namespace sig::libdaisy; FixedCapStr<20> displayStr; @@ -26,41 +28,40 @@ struct sig_dsp_Signal* listStorage[MAX_NUM_SIGNALS]; struct sig_List signals; struct sig_dsp_SignalListEvaluator* evaluator; -Bluemchen bluemchen; -struct sig_daisy_Host* host; +DaisyHost host; -struct sig_daisy_FilteredCVIn* coarseFreqKnob; -struct sig_daisy_FilteredCVIn* fineFreqKnob; -struct sig_daisy_CVIn* vOctCVIn; +struct sig_host_FilteredCVIn* coarseFreqKnob; +struct sig_host_FilteredCVIn* fineFreqKnob; +struct sig_host_CVIn* vOctCVIn; struct sig_dsp_BinaryOp* coarsePlusVOct; struct sig_dsp_BinaryOp* coarseVOctPlusFine; struct sig_dsp_LinearToFreq* frequency; struct sig_dsp_Oscillator* osc; struct sig_dsp_ConstantValue* gainLevel; struct sig_dsp_BinaryOp* gain; -struct sig_daisy_AudioOut* leftOut; -struct sig_daisy_AudioOut* rightOut; +struct sig_host_AudioOut* leftOut; +struct sig_host_AudioOut* rightOut; void UpdateOled() { - bluemchen.display.Fill(false); + host.device.display.Fill(false); displayStr.Clear(); displayStr.Append("Starscill"); - bluemchen.display.SetCursor(0, 0); - bluemchen.display.WriteString(displayStr.Cstr(), Font_6x8, true); + host.device.display.SetCursor(0, 0); + host.device.display.WriteString(displayStr.Cstr(), Font_6x8, true); displayStr.Clear(); displayStr.AppendFloat(frequency->outputs.main[0], 1); - bluemchen.display.SetCursor(0, 8); - bluemchen.display.WriteString(displayStr.Cstr(), Font_6x8, true); + host.device.display.SetCursor(0, 8); + host.device.display.WriteString(displayStr.Cstr(), Font_6x8, true); displayStr.Clear(); displayStr.Append(" Hz"); - bluemchen.display.SetCursor(46, 8); - bluemchen.display.WriteString(displayStr.Cstr(), Font_6x8, true); + host.device.display.SetCursor(46, 8); + host.device.display.WriteString(displayStr.Cstr(), Font_6x8, true); - bluemchen.display.Update(); + host.device.display.Update(); } void buildSignalGraph(struct sig_SignalContext* context, @@ -68,22 +69,26 @@ void buildSignalGraph(struct sig_SignalContext* context, /** Frequency controls **/ // Bluemchen AnalogControls are all unipolar, // so they need to be scaled to bipolar values. - coarseFreqKnob = sig_daisy_FilteredCVIn_new(&allocator, context, host); + // FIXME: this is no longer true. + coarseFreqKnob = sig_host_FilteredCVIn_new(&allocator, context); + coarseFreqKnob->hardware = &host.device.hardware; sig_List_append(&signals, coarseFreqKnob, status); - coarseFreqKnob->parameters.control = bluemchen.CTRL_1; + coarseFreqKnob->parameters.control = sig_host_KNOB_1; coarseFreqKnob->parameters.scale = 10.0f; coarseFreqKnob->parameters.offset = -5.0f; coarseFreqKnob->parameters.time = 0.01f; - fineFreqKnob = sig_daisy_FilteredCVIn_new(&allocator, context, host); + fineFreqKnob = sig_host_FilteredCVIn_new(&allocator, context); + fineFreqKnob->hardware = &host.device.hardware; sig_List_append(&signals, fineFreqKnob, status); - fineFreqKnob->parameters.control = bluemchen.CTRL_2; + fineFreqKnob->parameters.control = sig_host_KNOB_1; fineFreqKnob->parameters.offset = -0.5f; fineFreqKnob->parameters.time = 0.01f; - vOctCVIn = sig_daisy_CVIn_new(&allocator, context, host); + vOctCVIn = sig_host_CVIn_new(&allocator, context); + vOctCVIn->hardware = &host.device.hardware; sig_List_append(&signals, vOctCVIn, status); - vOctCVIn->parameters.control = bluemchen.CTRL_4; + vOctCVIn->parameters.control = sig_host_CV_IN_1; vOctCVIn->parameters.scale = 10.0f; vOctCVIn->parameters.offset = -5.0f; @@ -120,13 +125,15 @@ void buildSignalGraph(struct sig_SignalContext* context, gain->inputs.right = gainLevel->outputs.main; sig_List_append(&signals, gain, status); - leftOut = sig_daisy_AudioOut_new(&allocator, context, host); - leftOut->parameters.channel = 0; + leftOut = sig_host_AudioOut_new(&allocator, context); + leftOut->hardware = &host.device.hardware; + leftOut->parameters.channel = sig_host_AUDIO_OUT_1; leftOut->inputs.source = gain->outputs.main; sig_List_append(&signals, leftOut, status); - rightOut = sig_daisy_AudioOut_new(&allocator, context, host); - rightOut->parameters.channel = 1; + rightOut = sig_host_AudioOut_new(&allocator, context); + rightOut->hardware = &host.device.hardware; + rightOut->parameters.channel = sig_host_AUDIO_OUT_2; rightOut->inputs.source = gain->outputs.main; sig_List_append(&signals, rightOut, status); } @@ -145,16 +152,12 @@ int main(void) { sig_List_init(&signals, (void**) &listStorage, MAX_NUM_SIGNALS); evaluator = sig_dsp_SignalListEvaluator_new(&allocator, &signals); - host = sig_daisy_BluemchenHost_new(&allocator, - &audioSettings, - &bluemchen, - (struct sig_dsp_SignalEvaluator*) evaluator); - sig_daisy_Host_registerGlobalHost(host); + host.Init(&audioSettings, (struct sig_dsp_SignalEvaluator*) evaluator); struct sig_SignalContext* context = sig_SignalContext_new(&allocator, &audioSettings); buildSignalGraph(context, &status); - host->impl->start(host); + host.Start(); while (1) { UpdateOled(); diff --git a/hosts/daisy/examples/lichen-freddie/Makefile b/hosts/daisy/examples/lichen-freddie/Makefile new file mode 100644 index 0000000..3804ac9 --- /dev/null +++ b/hosts/daisy/examples/lichen-freddie/Makefile @@ -0,0 +1,5 @@ +all: + $(MAKE) -C bare-board-test + +clean: + $(MAKE) -C bare-board-test clean diff --git a/hosts/daisy/examples/lichen-freddie/lichen-freddie-bare-board-test/Makefile b/hosts/daisy/examples/lichen-freddie/bare-board-test/Makefile similarity index 96% rename from hosts/daisy/examples/lichen-freddie/lichen-freddie-bare-board-test/Makefile rename to hosts/daisy/examples/lichen-freddie/bare-board-test/Makefile index 5bba337..2eb4aa2 100644 --- a/hosts/daisy/examples/lichen-freddie/lichen-freddie-bare-board-test/Makefile +++ b/hosts/daisy/examples/lichen-freddie/bare-board-test/Makefile @@ -8,7 +8,7 @@ OPT = -O0 C_SOURCES += ../../../../../libsignaletic/vendor/tlsf/tlsf.c ../../../../../libsignaletic/src/libsignaletic.c C_INCLUDES += -I../../../../../libsignaletic/vendor/tlsf -I../../../../../libsignaletic/include -CPP_INCLUDES += -I../vendor/lib -I../../../vendor/lib/dev -I../../../include +CPP_INCLUDES += -I../vendor/lib -I../../../vendor/lib/dev -I../../../include -I/include CPP_SOURCES = src/${TARGET}.cpp ../../../src/sig-daisy-seed.cpp USE_FATFS = 0 diff --git a/hosts/daisy/examples/lichen-freddie/bare-board-test/include/ring-buffer.hpp b/hosts/daisy/examples/lichen-freddie/bare-board-test/include/ring-buffer.hpp new file mode 100644 index 0000000..eb91dbd --- /dev/null +++ b/hosts/daisy/examples/lichen-freddie/bare-board-test/include/ring-buffer.hpp @@ -0,0 +1,63 @@ +#pragma once +#include // For size_t + +namespace sig { + template class RingBuffer { + public: + size_t capacity = size; + T buffer[size]; + volatile size_t readIdx; + volatile size_t writeIdx; + + void Init() { + readIdx = 0; + writeIdx = 0; + } + + /** + * @brief Returns the number of unread elements in the buffer. + * + * @return size_t the number of unread elements + */ + inline size_t readable() { + return (size + writeIdx - readIdx) % size; + } + + /** + * @brief Returns the number of elements that can be written + * without overwriting unread data. + * + * @return size_t the number of writeable items remaining + */ + inline size_t writeable() { + // FIXME: This returns 0 whenever all elements have been read + // (i.e. when it's empty), including in its initial state. + // This article has a good overview of the issue: + // https://www.snellman.net/blog/archive/2016-12-13-ring-buffers/ + return (size + readIdx - writeIdx) % size; + } + + /** + * @brief Directly + * + * @return T + */ + inline T read() { + size_t i = readIdx; + T result = buffer[i]; + readIdx = (i + 1) % size; + + return result; + } + + inline void write(T value) { + size_t i = writeIdx; + buffer[i] = value; + writeIdx = (i + 1) % size; + } + + inline void Flush() { + writeIdx = readIdx; + } + }; +}; diff --git a/hosts/daisy/examples/lichen-freddie/bare-board-test/src/lichen-freddie-bare-board-test.cpp b/hosts/daisy/examples/lichen-freddie/bare-board-test/src/lichen-freddie-bare-board-test.cpp new file mode 100644 index 0000000..e1d4ac3 --- /dev/null +++ b/hosts/daisy/examples/lichen-freddie/bare-board-test/src/lichen-freddie-bare-board-test.cpp @@ -0,0 +1,174 @@ +#include "daisy.h" +#include +#include +#include "../../../../include/signaletic-daisy-host.h" +#include "../../../../include/lichen-freddie-device.hpp" +#include "../include/ring-buffer.hpp" + +#define SAMPLERATE 48000 +#define HEAP_SIZE 1024 * 384 // 384 KB +#define MAX_NUM_SIGNALS 32 +#define NUM_CONTROLS 8 +#define MIDI_QUEUE_SIZE 128 +#define MIDI_MESSAGE_SIZE 3 +#define SMOOTH_COEFFICIENT 0.0001f + +const uint8_t sliderToCC[NUM_CONTROLS] = {0, 1, 2, 3, 4, 5, 6, 7}; +const uint8_t buttonToCC[NUM_CONTROLS] = {48, 49, 50, 51, 52, 53, 54, 55}; + +uint8_t memory[HEAP_SIZE]; +struct sig_AllocatorHeap heap = { + .length = HEAP_SIZE, + .memory = (void*) memory +}; + +struct sig_Allocator allocator = { + .impl = &sig_TLSFAllocatorImpl, + .heap = &heap +}; + +struct sig_dsp_Signal* listStorage[MAX_NUM_SIGNALS]; +struct sig_List signals; +struct sig_dsp_SignalListEvaluator* evaluator; + +lichen::freddie::FreddieDevice device; +MidiUsbHandler usbMIDI; +MidiUartHandler trsMIDI; + +sig::libdaisy::Toggle buttons[NUM_CONTROLS]; +sig::libdaisy::GPIOOutput leds[NUM_CONTROLS]; +float previousButtonValues[NUM_CONTROLS] = {0.0f}; +uint8_t previousSliderMIDIValues[NUM_CONTROLS] = {0}; +bool buttonState[NUM_CONTROLS] = {false}; +sig::RingBuffer, MIDI_QUEUE_SIZE> + midiEvents; +struct sig_filter_Smooth sliderFilters[NUM_CONTROLS]; + +void enqueueMIDIMessage(std::array msg) { + midiEvents.write(msg); +} + +void sendMIDIMessage(std::array msg) { + usbMIDI.SendMessage(msg.data(), MIDI_MESSAGE_SIZE); + trsMIDI.SendMessage(msg.data(), MIDI_MESSAGE_SIZE); +} + +void midiCCEvent(uint8_t ccNum, uint8_t value, uint8_t channel = 0) { + std::array msg = {0}; + msg[0] = (channel & 0x0F) + 0xB0; + msg[1] = ccNum & 0x7F; + msg[2] = value & 0x7F; + enqueueMIDIMessage(msg); +} + +void midiNoteEvent(bool isNoteOn, uint8_t note, uint8_t velocity, + uint8_t channel = 0) { + std::array msg = {0}; + msg[0] = (channel & 0x0F) + (isNoteOn ? 0x90 : 0x80); + msg[1] = note & 0x7F; + msg[2] = velocity & 0x7F; + enqueueMIDIMessage(msg); +} + +inline void processSliders(size_t control) { + float sliderValue = device.hardware.adcChannels[control]; + float previousSliderMIDIValue = previousSliderMIDIValues[control]; + float smoothedSliderValue = sig_filter_Smooth_generate( + &sliderFilters[control], sliderValue); + uint8_t sliderMIDIValue = static_cast( + roundf(smoothedSliderValue * 127)); + + if (sliderMIDIValue != previousSliderMIDIValue) { + midiCCEvent(sliderToCC[control], sliderMIDIValue); + } + previousSliderMIDIValues[control] = sliderMIDIValue; +} + +inline void processLEDs(size_t control) { + device.hardware.gpioOutputs[control] = static_cast( + buttonState[control]); +} + +inline void processButtons(size_t control) { + // Read button presses. + float buttonValue = device.hardware.toggles[control]; + float previousButtonValue = previousButtonValues[control]; + if (buttonValue != previousButtonValue) { + // The button's state has changed (either pressed or released). + if (buttonValue > 0.0f && previousButtonValue <= 0.0f) { + // The button has been pressed. Toggle the LED. + buttonState[control] = !buttonState[control]; + } + + midiCCEvent(buttonToCC[control], buttonValue <= 0 ? 0 : 127); + } + previousButtonValues[control] = buttonValue; +} + +void AudioCallback(daisy::AudioHandle::InputBuffer in, + daisy::AudioHandle::OutputBuffer out, size_t size) { + + evaluator->evaluate((struct sig_dsp_SignalEvaluator*) evaluator); + + device.Read(); + + for (size_t i = 0; i < NUM_CONTROLS; i++) { + processButtons(i); + processLEDs(i); + processSliders(i); + } + + device.Write(); +} + +void processMIDIEvents() { + size_t eventsToRead = midiEvents.readable(); + for (size_t i = 0; i < eventsToRead; i++) { + sendMIDIMessage(midiEvents.read()); + } +} + +void initMIDI() { + MidiUsbHandler::Config usbConfig; + usbConfig.transport_config.periph = MidiUsbTransport::Config::INTERNAL; + usbMIDI.Init(usbConfig); + + MidiUartHandler::Config trsConfig; + trsConfig.transport_config.tx = sig::libdaisy::seed::PIN_D13; + trsConfig.transport_config.rx = sig::libdaisy::seed::PIN_NONE; + trsConfig.transport_config.periph = + UartHandler::Config::Peripheral::USART_1; + trsMIDI.Init(trsConfig); + + midiEvents.Init(); +} + +void initSliderFilters() { + for (size_t i = 0; i < NUM_CONTROLS; i++) { + sig_filter_Smooth_init(&sliderFilters[i], SMOOTH_COEFFICIENT); + } +} + +int main(void) { + allocator.impl->init(&allocator); + + struct sig_AudioSettings audioSettings = { + .sampleRate = SAMPLERATE, + .numChannels = 2, + .blockSize = 48 + }; + + struct sig_Status status; + sig_Status_init(&status); + sig_List_init(&signals, (void**) &listStorage, MAX_NUM_SIGNALS); + evaluator = sig_dsp_SignalListEvaluator_new(&allocator, &signals); + device.Init(&audioSettings); + initMIDI(); + initSliderFilters(); + device.Start(); + device.board.audio.Start(AudioCallback); + + while (1) { + processMIDIEvents(); + } +} diff --git a/hosts/daisy/examples/lichen-freddie/lichen-freddie-bare-board-test/src/lichen-freddie-bare-board-test.cpp b/hosts/daisy/examples/lichen-freddie/lichen-freddie-bare-board-test/src/lichen-freddie-bare-board-test.cpp deleted file mode 100644 index 824a864..0000000 --- a/hosts/daisy/examples/lichen-freddie/lichen-freddie-bare-board-test/src/lichen-freddie-bare-board-test.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include "daisy.h" -#include -#include "../../../../include/signaletic-daisy-host.h" -#include "../../../../include/sig-daisy-seed.hpp" -#include "dev/oled_ssd130x.h" - -#define SAMPLERATE 48000 -#define HEAP_SIZE 1024 * 384 // 384 KB -#define MAX_NUM_SIGNALS 32 -#define NUM_CONTROLS 8 - -uint8_t memory[HEAP_SIZE]; -struct sig_AllocatorHeap heap = { - .length = HEAP_SIZE, - .memory = (void*) memory -}; - -struct sig_Allocator allocator = { - .impl = &sig_TLSFAllocatorImpl, - .heap = &heap -}; - -struct sig_dsp_Signal* listStorage[MAX_NUM_SIGNALS]; -struct sig_List signals; -struct sig_dsp_SignalListEvaluator* evaluator; - -sig::libdaisy::Seed board; -MidiUsbHandler usbMIDI; -MidiUartHandler trsMIDI; -struct sig_daisy_Host* host; - -sig::libdaisy::AnalogInput sliders[NUM_CONTROLS]; -sig::libdaisy::Toggle buttons[NUM_CONTROLS]; -sig::libdaisy::GPIOOutput leds[NUM_CONTROLS]; -uint8_t midiNotes[NUM_CONTROLS] = {0}; -bool midiState[NUM_CONTROLS] = {false}; -bool previousMidiState[NUM_CONTROLS] = {false}; - -void AudioCallback(daisy::AudioHandle::InputBuffer in, - daisy::AudioHandle::OutputBuffer out, size_t size) { - - evaluator->evaluate((struct sig_dsp_SignalEvaluator*) evaluator); - - for (size_t i = 0; i < NUM_CONTROLS; i++) { - float buttonValue = buttons[i].Value(); - previousMidiState[i] = midiState[i]; - midiState[i] = (bool) buttonValue; - leds[i].Write(buttonValue); - // TODO: Need smoothing to avoid stuck notes. - midiNotes[i] = sliders[i].Value() * 127; - } - - for (size_t i = 0; i < size; i++) { - out[0][i] = 0; - out[1][i] = 0; - } -} - -void fireMidiNoteEvent(bool isNoteOn, uint8_t note, uint8_t velocity) { - uint8_t channel = 0; - uint8_t data[3] = {0}; - data[0] = (channel & 0x0F) + (isNoteOn ? 0x90 : 0x80); - data[1] = note & 0x7F; - data[2] = velocity & 0x7F; - usbMIDI.SendMessage(data, 3); - trsMIDI.SendMessage(data, 3); -} - -void initMIDI() { - MidiUsbHandler::Config usbConfig; - usbConfig.transport_config.periph = MidiUsbTransport::Config::INTERNAL; - usbMIDI.Init(usbConfig); - - MidiUartHandler::Config trsConfig; - trsConfig.transport_config.tx = sig::libdaisy::SEED_PIN_D13; - trsConfig.transport_config.rx = sig::libdaisy::SEED_PIN_NONE; - trsConfig.transport_config.periph = - UartHandler::Config::Peripheral::USART_1; - trsMIDI.Init(trsConfig); -} - -int main(void) { - allocator.impl->init(&allocator); - - struct sig_AudioSettings audioSettings = { - .sampleRate = SAMPLERATE, - .numChannels = 2, - .blockSize = 48 - }; - - struct sig_Status status; - sig_Status_init(&status); - sig_List_init(&signals, (void**) &listStorage, MAX_NUM_SIGNALS); - - evaluator = sig_dsp_SignalListEvaluator_new(&allocator, &signals); - board.Init(audioSettings.blockSize, audioSettings.sampleRate); - - dsy_gpio_pin adcPins[] = { - sig::libdaisy::SEED_PIN_ADC_0, - sig::libdaisy::SEED_PIN_ADC_1, - sig::libdaisy::SEED_PIN_ADC_2, - sig::libdaisy::SEED_PIN_ADC_3, - sig::libdaisy::SEED_PIN_ADC_4, - sig::libdaisy::SEED_PIN_ADC_5, - sig::libdaisy::SEED_PIN_ADC_6, - sig::libdaisy::SEED_PIN_ADC_7, - sig::libdaisy::SEED_PIN_ADC_8 - }; - - board.InitADC(adcPins, NUM_CONTROLS); - board.adc.Start(); - - dsy_gpio_pin buttonPins[] = { - sig::libdaisy::SEED_PIN_D0, - sig::libdaisy::SEED_PIN_D1, - sig::libdaisy::SEED_PIN_D2, - sig::libdaisy::SEED_PIN_D3, - sig::libdaisy::SEED_PIN_D4, - sig::libdaisy::SEED_PIN_D5, - sig::libdaisy::SEED_PIN_D6, - sig::libdaisy::SEED_PIN_D7 - }; - - dsy_gpio_pin ledPins[] = { - sig::libdaisy::SEED_PIN_D8, - sig::libdaisy::SEED_PIN_D9, - sig::libdaisy::SEED_PIN_D10, - sig::libdaisy::SEED_PIN_D11, - sig::libdaisy::SEED_PIN_D12, - sig::libdaisy::SEED_PIN_D25, - sig::libdaisy::SEED_PIN_D26, - sig::libdaisy::SEED_PIN_D27 - }; - - for (size_t i = 0; i < NUM_CONTROLS; i++) { - leds[i].Init(ledPins[i], DSY_GPIO_MODE_OUTPUT_PP, DSY_GPIO_NOPULL); - sliders[i].Init(&board.adc, i); - buttons[i].Init(buttonPins[i]); - } - - initMIDI(); - - board.audio.Start(AudioCallback); - - uint32_t lastMidiTick = System::GetUs(); - - while (1) { - uint32_t now = System::GetUs(); - if (now - lastMidiTick >= 1000) { - for (size_t i = 0; i < NUM_CONTROLS; i++) { - bool noteState = midiState[i]; - if (noteState != previousMidiState[i]) { - fireMidiNoteEvent(noteState, midiNotes[i], 127); - } - } - lastMidiTick = now; - } - } -} diff --git a/hosts/daisy/examples/lichen-medium/bare-board-test/src/lichen-medium-bare-board-test.cpp b/hosts/daisy/examples/lichen-medium/bare-board-test/src/lichen-medium-bare-board-test.cpp index a2b3cb6..f488ffb 100644 --- a/hosts/daisy/examples/lichen-medium/bare-board-test/src/lichen-medium-bare-board-test.cpp +++ b/hosts/daisy/examples/lichen-medium/bare-board-test/src/lichen-medium-bare-board-test.cpp @@ -23,19 +23,14 @@ struct sig_dsp_Signal* listStorage[MAX_NUM_SIGNALS]; struct sig_List signals; struct sig_dsp_SignalListEvaluator* evaluator; -sig::libdaisy::Module medium; -struct sig_daisy_Host* host; -sig::libdaisy::AnalogInput* knob1; +lichen::medium::MediumDevice medium; struct sig_dsp_Value* freq; -sig::libdaisy::GateInput gateIn; struct sig_dsp_Value* gain; struct sig_dsp_Oscillator* sine; struct sig_dsp_Value* switchValue; struct sig_dsp_ScaleOffset* switchValueScale; struct sig_dsp_BinaryOp* harmonizerFreqScale; struct sig_dsp_Oscillator* harmonizer; -sig::libdaisy::TriSwitch threeway; -sig::libdaisy::Toggle button; struct sig_dsp_Value* buttonValue; struct sig_dsp_BinaryOp* mixer; struct sig_dsp_BinaryOp* attenuator; @@ -95,9 +90,12 @@ void buildSignalGraph(struct sig_Allocator* allocator, void AudioCallback(daisy::AudioHandle::InputBuffer in, daisy::AudioHandle::OutputBuffer out, size_t size) { - freq->parameters.value = 1760.0f * knob1->Value(); - buttonValue->parameters.value = button.Value(); - switchValue->parameters.value = threeway.Value(); + medium.Read(); + + freq->parameters.value = 1760.0f * + medium.adcController.channelBank.values[0]; + buttonValue->parameters.value = medium.buttonBank.values[0]; + switchValue->parameters.value = medium.switchBank.values[0]; evaluator->evaluate((struct sig_dsp_SignalEvaluator*) evaluator); @@ -106,8 +104,8 @@ void AudioCallback(daisy::AudioHandle::InputBuffer in, out[0][i] = sig; out[1][i] = sig; - medium.board.dacBuffer[0][i] = sig_bipolarToUint12( - gateIn.Value() - 0.75f); + medium.dacChannelBank.values[0] = medium.gateBank.values[0] - 0.75f; + medium.Write(); } } @@ -125,18 +123,12 @@ int main(void) { sig_List_init(&signals, (void**) &listStorage, MAX_NUM_SIGNALS); evaluator = sig_dsp_SignalListEvaluator_new(&allocator, &signals); - medium.Init(lichen::medium::MediumDefinition, audioSettings); + medium.Init(&audioSettings); struct sig_SignalContext* context = sig_SignalContext_new(&allocator, &audioSettings); buildSignalGraph(&allocator, context, &signals, &audioSettings, &status); - - knob1 = &medium.adcController.inputs[0]; - gateIn.Init(sig::libdaisy::PatchSM::PIN_B10); - threeway.Init(sig::libdaisy::PatchSM::PIN_B7, - sig::libdaisy::PatchSM::PIN_B8); - button.Init(sig::libdaisy::PatchSM::PIN_D1); - + medium.Start(); medium.board.audio.Start(AudioCallback); while (1) { diff --git a/hosts/daisy/examples/lichen-medium/chorus/src/lichen-medium-chorus.cpp b/hosts/daisy/examples/lichen-medium/chorus/src/lichen-medium-chorus.cpp index 069e0ee..7c555f9 100644 --- a/hosts/daisy/examples/lichen-medium/chorus/src/lichen-medium-chorus.cpp +++ b/hosts/daisy/examples/lichen-medium/chorus/src/lichen-medium-chorus.cpp @@ -1,7 +1,6 @@ #include "daisy.h" #include -#include "../../../../include/daisy-patch-sm-host.h" -#include "../../../../include/lichen-medium-host.h" +#include "../../../../include/lichen-medium-module.h" #define SAMPLERATE 96000 #define DELAY_LINE_LENGTH SAMPLERATE diff --git a/hosts/daisy/examples/lichen-medium/sines/Makefile b/hosts/daisy/examples/lichen-medium/sines/Makefile index 212dac2..d038531 100644 --- a/hosts/daisy/examples/lichen-medium/sines/Makefile +++ b/hosts/daisy/examples/lichen-medium/sines/Makefile @@ -1,15 +1,15 @@ # Project Name TARGET ?= lichen-medium-sines -DEBUG = 0 -OPT = -O3 +DEBUG = 1 +OPT = -Og # Sources -C_SOURCES += ../../../../../libsignaletic/vendor/tlsf/tlsf.c ../../../../../libsignaletic/src/libsignaletic.c +C_SOURCES += ../../../../../libsignaletic/vendor/tlsf/tlsf.c ../../../../../libsignaletic/src/libsignaletic.c ../../../src/signaletic-host.c C_INCLUDES += -I../../../../../libsignaletic/vendor/tlsf -I../../../../../libsignaletic/include CPP_INCLUDES += -I../vendor/lib -I../../../vendor/lib/dev -I../../../include -CPP_SOURCES = src/${TARGET}.cpp ../../../src/signaletic-daisy-host.cpp ../../../src/daisy-patch-sm-host.cpp +CPP_SOURCES = ../../../src/signaletic-daisy-host.cpp ../../../src/sig-daisy-patch-sm.cpp src/${TARGET}.cpp USE_FATFS = 0 diff --git a/hosts/daisy/examples/lichen-medium/sines/src/lichen-medium-sines.cpp b/hosts/daisy/examples/lichen-medium/sines/src/lichen-medium-sines.cpp index dcc3597..0952e86 100644 --- a/hosts/daisy/examples/lichen-medium/sines/src/lichen-medium-sines.cpp +++ b/hosts/daisy/examples/lichen-medium/sines/src/lichen-medium-sines.cpp @@ -1,7 +1,6 @@ #include "daisy.h" #include -#include "../../../../include/daisy-patch-sm-host.h" -#include "../../../../include/lichen-medium-host.h" +#include "../../../../include/lichen-medium-module.h" #define HEAP_SIZE 1024 * 256 // 256KB #define MAX_NUM_SIGNALS 32 @@ -17,28 +16,27 @@ struct sig_Allocator allocator = { .heap = &heap }; -daisy::patch_sm::DaisyPatchSM lichenMedium; +DaisyHost host; struct sig_dsp_Signal* listStorage[MAX_NUM_SIGNALS]; struct sig_List signals; struct sig_dsp_SignalListEvaluator* evaluator; -struct sig_daisy_Host* host; struct sig_dsp_ConstantValue* ampScale; -struct sig_daisy_CVIn* knobIn; -struct sig_daisy_CVIn* cvIn; +struct sig_host_CVIn* knobIn; +struct sig_host_CVIn* cvIn; struct sig_dsp_LinearToFreq* vOct; struct sig_dsp_Oscillator* sine; -struct sig_daisy_AudioOut* leftOut; -struct sig_daisy_AudioOut* rightOut; - +struct sig_host_AudioOut* leftOut; +struct sig_host_AudioOut* rightOut; void buildGraph(struct sig_SignalContext* context, struct sig_Status* status) { ampScale = sig_dsp_ConstantValue_new(&allocator, context, 0.75f); - knobIn = sig_daisy_CVIn_new(&allocator, context, host); + knobIn = sig_host_CVIn_new(&allocator, context); + knobIn->hardware = &host.device.hardware; sig_List_append(&signals, knobIn, status); - knobIn->parameters.control = sig_lichen_Medium_KNOB_6; + knobIn->parameters.control = sig_host_KNOB_6; knobIn->parameters.scale = 5.0f; vOct = sig_dsp_LinearToFreq_new(&allocator, context); @@ -50,14 +48,16 @@ void buildGraph(struct sig_SignalContext* context, struct sig_Status* status) { sine->inputs.freq = vOct->outputs.main; sine->inputs.mul = ampScale->outputs.main; - leftOut = sig_daisy_AudioOut_new(&allocator, context, host); + leftOut = sig_host_AudioOut_new(&allocator, context); + leftOut->hardware = &host.device.hardware; sig_List_append(&signals, leftOut, status); - leftOut->parameters.channel = sig_daisy_AUDIO_OUT_1; + leftOut->parameters.channel = sig_host_AUDIO_OUT_1; leftOut->inputs.source = sine->outputs.main; - rightOut = sig_daisy_AudioOut_new(&allocator, context, host); + rightOut = sig_host_AudioOut_new(&allocator, context); + rightOut->hardware = &host.device.hardware; sig_List_append(&signals, rightOut, status); - rightOut->parameters.channel = sig_daisy_AUDIO_OUT_2; + rightOut->parameters.channel = sig_host_AUDIO_OUT_2; rightOut->inputs.source = sine->outputs.main; } @@ -77,13 +77,9 @@ int main(void) { struct sig_SignalContext* context = sig_SignalContext_new(&allocator, &audioSettings); evaluator = sig_dsp_SignalListEvaluator_new(&allocator, &signals); - host = sig_daisy_PatchSMHost_new(&allocator, - &audioSettings, &lichenMedium, - (struct sig_dsp_SignalEvaluator*) evaluator); - sig_daisy_Host_registerGlobalHost(host); + host.Init(&audioSettings, (struct sig_dsp_SignalEvaluator*) evaluator); buildGraph(context, &status); - - host->impl->start(host); + host.Start(); while (1) {} } diff --git a/hosts/daisy/include/daisy-bluemchen-host.h b/hosts/daisy/include/daisy-bluemchen-host.h deleted file mode 100644 index 056d74c..0000000 --- a/hosts/daisy/include/daisy-bluemchen-host.h +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef SIGNALETIC_DAISY_BLUEMCHENHOST_H -#define SIGNALETIC_DAISY_BLUEMCHENHOST_H - -#include "./signaletic-daisy-host.h" -#include "../vendor/kxmx_bluemchen/src/kxmx_bluemchen.h" - -enum { - sig_daisy_Bluemchen_CV_IN_KNOB_1 = kxmx::Bluemchen::Ctrl::CTRL_1, - sig_daisy_Bluemchen_CV_IN_KNOB_2 = kxmx::Bluemchen::Ctrl::CTRL_2, - sig_daisy_Bluemchen_CV_IN_CV1 = kxmx::Bluemchen::Ctrl::CTRL_3, - sig_daisy_Bluemchen_CV_IN_CV2 = kxmx::Bluemchen::Ctrl::CTRL_4, - sig_daisy_Bluemchen_CV_IN_LAST = kxmx::Bluemchen::Ctrl::CTRL_LAST -}; - -const int sig_daisy_Bluemchen_NUM_ANALOG_INPUTS = kxmx::Bluemchen::Ctrl::CTRL_LAST; -const int sig_daisy_Bluemchen_NUM_ANALOG_OUTPUTS = 0; -const int sig_daisy_Bluemchen_NUM_GATE_INPUTS = 0; -const int sig_daisy_Bluemchen_NUM_GATE_OUTPUTS = 0; -const int sig_daisy_Bluemchen_NUM_SWITCHES = 0; -const int sig_daisy_Bluemchen_NUM_TRI_SWITCHES = 0; -const int sig_daisy_Bluemchen_NUM_ENCODERS = 1; - -enum { - sig_daisy_Nehcmeulb_CV_IN_KNOB1 = kxmx::Bluemchen::Ctrl::CTRL_1, - sig_daisy_Nehcmeulb_CV_IN_KNOB2 = kxmx::Bluemchen::Ctrl::CTRL_2, - sig_daisy_Nehcmeulb_CV_IN_CV1 = kxmx::Bluemchen::Ctrl::CTRL_3, - sig_daisy_Nehcmeulb_CV_IN_CV2 = kxmx::Bluemchen::Ctrl::CTRL_4, - sig_daisy_Nehcmeulb_CV_IN_LAST -}; - -enum { - sig_daisy_Nehcmeulb_CV_OUT_1 = 0, - sig_daisy_Nehcmeulb_CV_OUT_2, - sig_daisy_Nehcmeulb_CV_OUT_BOTH, - sig_daisy_Nehcmeulb_CV_OUT_LAST -}; - -const int sig_daisy_Nehcmeulb_NUM_ANALOG_INPUTS = sig_daisy_Nehcmeulb_CV_IN_LAST; -const int sig_daisy_Nehcmeulb_NUM_ANALOG_OUTPUTS = 2; -const int sig_daisy_Nehcmeulb_NUM_GATE_INPUTS = 0; -const int sig_daisy_Nehcmeulb_NUM_GATE_OUTPUTS = 0; -const int sig_daisy_Nehcmeulb_NUM_SWITCHES = 0; -const int sig_daisy_Nehcmeulb_NUM_TRI_SWITCHES = 0; -const int sig_daisy_Nehcmeulb_NUM_ENCODERS = 1; - -extern struct sig_daisy_Host_Impl sig_daisy_BluemchenHostImpl; - -void sig_daisy_BluemchenHostImpl_setControlValue(struct sig_daisy_Host* host, - int control, float value); - -void sig_daisy_BluemchenHostImpl_start(struct sig_daisy_Host* host); - -void sig_daisy_BluemchenHostImpl_stop(struct sig_daisy_Host* host); - -/** - * @brief Creates a new BluemchenHost instance. - * - * @param allocator the allocator to use - * @param bluemchen the Bluemchen board support object - * @param evaluator a signal evaluator to use in the audio callback - * @return struct sig_daisy_Host* - */ -struct sig_daisy_Host* sig_daisy_BluemchenHost_new( - struct sig_Allocator* allocator, - struct sig_AudioSettings* audioSettings, - kxmx::Bluemchen* bluemchen, - struct sig_dsp_SignalEvaluator* evaluator); - -/** - * @brief Initializes a Bluemchen board object with the specified configuration - * - * @param self the BluemchenHost_Board instance to initialize - * @param bluemchen the Blumchen board support object - * @param boardConfig the board configuration object to use (e.g. for the Bluemchen or Nehcmeulb) - */ -void sig_daisy_BluemchenHost_Board_init(struct sig_daisy_Host_Board* self, - kxmx::Bluemchen* bluemchen, - struct sig_daisy_Host_BoardConfiguration* boardConfig); - -/** - * @brief Initializes the state of a BluemchenHost instance. - * - * @param self the BluemchenHost to initialize - * @param bluemchen the Bluemchen board support object - * @param evaluator a signal evaluator to use in the audio callback - */ -void sig_daisy_BluemchenHost_init(struct sig_daisy_Host* self, - struct sig_AudioSettings* audioSettings, - struct sig_daisy_Host_BoardConfiguration* boardConfig, - kxmx::Bluemchen* bluemchen, - struct sig_dsp_SignalEvaluator* evaluator); - -/** - * @brief Destroys a BluemchenHost instance. - * - * @param allocator the allocator to use - * @param self the BluemchenHost to destroy - */ -void sig_daisy_BluemchenHost_destroy(struct sig_Allocator* allocator, - struct sig_daisy_Host* self); - - -struct sig_daisy_Host* sig_daisy_NehcmeulbHost_new( - struct sig_Allocator* allocator, - struct sig_AudioSettings* audioSettings, - kxmx::Bluemchen* bluemchen, - struct sig_dsp_SignalEvaluator* evaluator); - -void sig_daisy_NehcmeulbHost_destroy(struct sig_Allocator* allocator, - struct sig_daisy_Host* self); - -#endif // SIGNALETIC_DAISY_BLUEMCHENHOST_H diff --git a/hosts/daisy/include/daisy-patch-sm-host.h b/hosts/daisy/include/daisy-patch-sm-host.h deleted file mode 100644 index 4dd36a4..0000000 --- a/hosts/daisy/include/daisy-patch-sm-host.h +++ /dev/null @@ -1,144 +0,0 @@ -#ifndef SIGNALETIC_DAISY_PATCH_SM_H -#define SIGNALETIC_DAISY_PATCH_SM_H - -#include "./signaletic-daisy-host.h" -#include "../vendor/libDaisy/src/daisy_patch_sm.h" - -enum { - sig_daisy_PatchSM_CV_IN_1 = daisy::patch_sm::CV_1, - sig_daisy_PatchSM_CV_IN_2 = daisy::patch_sm::CV_2, - sig_daisy_PatchSM_CV_IN_3 = daisy::patch_sm::CV_3, - sig_daisy_PatchSM_CV_IN_4 = daisy::patch_sm::CV_4, - sig_daisy_PatchSM_CV_IN_5 = daisy::patch_sm::CV_5, - sig_daisy_PatchSM_CV_IN_6 = daisy::patch_sm::CV_6, - sig_daisy_PatchSM_CV_IN_7 = daisy::patch_sm::CV_7, - sig_daisy_PatchSM_CV_IN_8 = daisy::patch_sm::CV_8, - sig_daisy_PatchSM_ADC_IN_9 = daisy::patch_sm::ADC_9, - sig_daisy_PatchSM_ADC_IN_10 = daisy::patch_sm::ADC_10, - sig_daisy_PatchSM_ADC_IN_11 = daisy::patch_sm::ADC_11, - sig_daisy_PatchSM_ADC_IN_12 = daisy::patch_sm::ADC_12, - sig_daisy_PatchSM_CV_IN_LAST -}; - -const int sig_daisy_PatchSM_NUM_ANALOG_INPUTS = daisy::patch_sm::ADC_LAST; - -enum { - sig_daisy_PatchSM_CV_OUT_1 = daisy::patch_sm::CV_OUT_1, - sig_daisy_PatchSM_CV_OUT_2 = daisy::patch_sm::CV_OUT_2, - sig_daisy_PatchSM_CV_OUT_LAST -}; - -const int sig_daisy_PatchSM_NUM_ANALOG_OUTPUTS = 2; - -enum { - sig_daisy_PatchSM_GATE_IN_1 = sig_daisy_GATE_IN_1, - sig_daisy_PatchSM_GATE_IN_2 = sig_daisy_GATE_IN_2, - sig_daisy_PatchSM_GATE_IN_LAST = sig_daisy_GATE_IN_LAST -}; - -const int sig_daisy_PatchSM_NUM_GATE_INPUTS = sig_daisy_GATE_IN_LAST; - -enum { - sig_daisy_PatchSM_GATE_OUT_1 = sig_daisy_GATE_OUT_1, - sig_daisy_PatchSM_GATE_OUT_2 = sig_daisy_GATE_OUT_2, - sig_daisy_PatchSM_GATE_OUT_LAST = sig_daisy_GATE_OUT_LAST -}; - -const int sig_daisy_PatchSM_NUM_GATE_OUTPUTS = sig_daisy_GATE_OUT_LAST; - - -enum { - sig_daisy_PatchSM_SWITCH_1, - sig_daisy_PatchSM_SWITCH_2, - sig_daisy_PatchSM_SWITCH_LAST -}; -const int sig_daisy_PatchSM_NUM_SWITCHES = sig_daisy_PatchSM_SWITCH_LAST; -const int sig_daisy_PatchSM_NUM_TRI_SWITCHES = 0; -const int sig_daisy_PatchSM_NUM_ENCODERS = 0; - -// TODO: What are the additional 4x ADC pins on the Patch SM, -// and where are they mapped (if at all) on the Patch init? -enum { - sig_daisy_PatchInit_KNOB_1 = daisy::patch_sm::CV_1, - sig_daisy_PatchInit_KNOB_2 = daisy::patch_sm::CV_2, - sig_daisy_PatchInit_KNOB_3 = daisy::patch_sm::CV_3, - sig_daisy_PatchInit_KNOB_4 = daisy::patch_sm::CV_4, - sig_daisy_PatchInit_CV_IN_1 = daisy::patch_sm::CV_5, - sig_daisy_PatchInit_CV_IN_2 = daisy::patch_sm::CV_6, - sig_daisy_PatchInit_CV_IN_3 = daisy::patch_sm::CV_7, - sig_daisy_PatchInit_CV_IN_4 = daisy::patch_sm::CV_8, - sig_daisy_PatchInit_CV_IN_LAST -}; - -const int sig_daisy_PatchInit_NUM_ANALOG_INPUTS = sig_daisy_PatchInit_CV_IN_LAST; - -enum { - sig_daisy_PatchInit_CV_OUT = daisy::patch_sm::CV_OUT_1, - sig_daisy_PatchInit_LED = daisy::patch_sm::CV_OUT_2, - sig_daisy_PatchInit_CV_OUT_LAST -}; - -const int sig_daisy_PatchInit_NUM_ANALOG_OUTPUTS = 2; - -enum { - sig_daisy_PatchInit_GATE_IN_1 = sig_daisy_GATE_IN_1, - sig_daisy_PatchInit_GATE_IN_2 = sig_daisy_GATE_IN_2, - sig_daisy_PatchInit_GATE_IN_LAST = sig_daisy_GATE_IN_LAST -}; - -const int sig_daisy_PatchInit_NUM_GATE_INPUTS = sig_daisy_PatchInit_GATE_IN_LAST; - -enum { - sig_daisy_PatchInit_GATE_OUT_1 = sig_daisy_GATE_OUT_1, - sig_daisy_PatchInit_GATE_OUT_2 = sig_daisy_GATE_OUT_2, - sig_daisy_PatchInit_GATE_OUT_LAST = sig_daisy_GATE_OUT_LAST -}; - -const int sig_daisy_PatchInit_NUM_GATE_OUTPUTS = sig_daisy_PatchInit_GATE_OUT_LAST; - -enum { - sig_daisy_PatchInit_BUTTON = sig_daisy_PatchSM_SWITCH_1, - sig_daisy_PatchInit_TOGGLE = sig_daisy_PatchSM_SWITCH_2, - sig_daisy_PatchInit_SWITCH_LAST -}; - -const int sig_daisy_PatchInit_NUM_SWITCHES = sig_daisy_PatchInit_SWITCH_LAST; -const int sig_daisy_PatchInit_NUM_TRI_SWITCHES = 0; -const int sig_daisy_PatchInit_NUM_ENCODERS = 0; - -extern struct sig_daisy_Host_Impl sig_daisy_PatchSMHostImpl; - -void sig_daisy_PatchSMHostImpl_start( - struct sig_daisy_Host* host); - -void sig_daisy_PatchSMHostImpl_stop( - struct sig_daisy_Host* host); - -void sig_daisy_PatchSMHostImpl_setControlValue( - struct sig_daisy_Host* host, int control, float value); - -float sig_daisy_PatchSMHostImpl_getGateValue( - struct sig_daisy_Host* host, int control); - -void sig_daisy_PatchSMHostImpl_setGateValue( - struct sig_daisy_Host* host, int control, float value); - -struct sig_daisy_Host* sig_daisy_PatchSMHost_new( - struct sig_Allocator* allocator, - sig_AudioSettings* audioSettings, - daisy::patch_sm::DaisyPatchSM* board, - struct sig_dsp_SignalEvaluator* evaluator); - -void sig_daisy_PatchSMHost_init(struct sig_daisy_Host* self, - sig_AudioSettings* audioSettings, - daisy::patch_sm::DaisyPatchSM* patchSM, - struct sig_dsp_SignalEvaluator* evaluator); - -void sig_daisy_PatchSMHost_Board_init(struct sig_daisy_Host_Board* self, - daisy::patch_sm::DaisyPatchSM* patchSM); - -void sig_daisy_PatchSMHost_destroy( - struct sig_Allocator* allocator, - struct sig_daisy_Host* self); - -#endif // SIGNALETIC_DAISY_PATCH_SM_H diff --git a/hosts/daisy/include/kxmx-bluemchen-device.hpp b/hosts/daisy/include/kxmx-bluemchen-device.hpp new file mode 100644 index 0000000..09413c4 --- /dev/null +++ b/hosts/daisy/include/kxmx-bluemchen-device.hpp @@ -0,0 +1,104 @@ +#pragma once + +#include "signaletic-host.h" +#include "signaletic-daisy-host.h" +#include "sig-daisy-seed.hpp" +#include "dev/oled_ssd130x.h" + +using namespace sig::libdaisy; + +enum { + sig_host_KNOB_1 = 0, + sig_host_KNOB_2 +}; + +enum { + sig_host_CV_IN_1 = 0, + sig_host_CV_IN_2 +}; + +enum { + sig_host_AUDIO_IN_1 = 0, + sig_host_AUDIO_IN_2 +}; + +enum { + sig_host_AUDIO_OUT_1 = 0, + sig_host_AUDIO_OUT_2 +}; + +namespace kxmx { +namespace bluemchen { + static const size_t NUM_ADC_CHANNELS = 4; + + static dsy_gpio_pin ADC_PINS[NUM_ADC_CHANNELS] = { + seed::PIN_D16, + seed::PIN_D15, + seed::PIN_D21, + seed::PIN_D18 + }; + + class BluemchenDevice { + public: + seed::SeedBoard board; + ADCController adcController; + daisy::OledDisplay + display; + daisy::MidiUartHandler midi; + struct sig_host_HardwareInterface hardware; + + void Init(struct sig_AudioSettings* audioSettings) { + board.Init(audioSettings->blockSize, audioSettings->sampleRate); + InitADCController(); + + hardware = { + .numAudioInputChannels = 2, + .audioInputChannels = NULL, // Supplied by audio callback + .numAudioOutputChannels = 2, + .audioOutputChannels = NULL, // Supplied by audio callback + .numADCChannels = NUM_ADC_CHANNELS, + .adcChannels = adcController.channelBank.values, + .numDACChannels = 0, + .dacChannels = NULL, + .numGateInputs = 0, + .gateInputs = NULL, + .numGPIOOutputs = 0, + .gpioOutputs = NULL, + .numToggles = 0, + .toggles = NULL, + .numTriSwitches = 0, + .triSwitches = NULL + }; + } + + void InitADCController() { + adcController.Init(&board.adc, ADC_PINS); + } + + void InitDisplay() { + daisy::OledDisplay::Config config; + config.driver_config.transport_config.Defaults(); + display.Init(config); + } + + void InitMidi() { + daisy::MidiUartHandler::Config config; + midi.Init(config); + } + + void Start() { + adcController.Start(); + } + + void Stop () { + adcController.Stop(); + } + + inline void Read() { + adcController.Read(); + } + + inline void Write() {} + }; +}; +}; diff --git a/hosts/daisy/include/lichen-freddie-device.hpp b/hosts/daisy/include/lichen-freddie-device.hpp new file mode 100644 index 0000000..88e737d --- /dev/null +++ b/hosts/daisy/include/lichen-freddie-device.hpp @@ -0,0 +1,132 @@ +#pragma once + +#include "signaletic-host.h" +#include "signaletic-daisy-host.h" +#include "sig-daisy-seed.hpp" + +using namespace sig::libdaisy; + +enum { + sig_host_KNOB_1 = 0, + sig_host_KNOB_2, + sig_host_KNOB_3, + sig_host_KNOB_4, + sig_host_KNOB_5, + sig_host_KNOB_6, + sig_host_KNOB_7, + sig_host_KNOB_8 +}; + +namespace lichen { +namespace freddie { + static const size_t NUM_CONTROLS = 8; + + static dsy_gpio_pin ADC_PINS[NUM_CONTROLS] = { + seed::PIN_ADC_0, + seed::PIN_ADC_1, + seed::PIN_ADC_2, + seed::PIN_ADC_3, + seed::PIN_ADC_4, + seed::PIN_ADC_5, + seed::PIN_ADC_6, + seed::PIN_ADC_7 + }; + + static dsy_gpio_pin BUTTON_PINS[NUM_CONTROLS] = { + seed::PIN_D0, + seed::PIN_D1, + seed::PIN_D2, + seed::PIN_D3, + seed::PIN_D4, + seed::PIN_D5, + seed::PIN_D6, + seed::PIN_D7 + }; + + static dsy_gpio_pin LED_PINS[] = { + seed::PIN_D8, + seed::PIN_D9, + seed::PIN_D10, + seed::PIN_D11, + seed::PIN_D12, + seed::PIN_D25, + seed::PIN_D26, + seed::PIN_D27 + }; + + class FreddieDevice { + public: + seed::SeedBoard board; + ADCController adcController; + Toggle buttons[NUM_CONTROLS]; + InputBank buttonBank; + GPIOOutput leds[NUM_CONTROLS]; + OutputBank ledBank; + struct sig_host_HardwareInterface hardware; + + void Init(struct sig_AudioSettings* audioSettings) { + board.Init(audioSettings->blockSize, audioSettings->sampleRate); + InitADCController(); + InitButtons(); + InitLEDs(); + + hardware = { + .numAudioInputChannels = 0, + .audioInputChannels = NULL, + .numAudioOutputChannels = 0, + .audioOutputChannels = NULL, + .numADCChannels = NUM_CONTROLS, + .adcChannels = adcController.channelBank.values, + .numDACChannels = 0, + .dacChannels = NULL, + .numGateInputs = 0, + .gateInputs = NULL, + .numGPIOOutputs = NUM_CONTROLS, + .gpioOutputs = ledBank.values, + .numToggles = NUM_CONTROLS, + .toggles = buttonBank.values, + .numTriSwitches = 0, + .triSwitches = NULL + }; + } + + void InitADCController() { + adcController.Init(&board.adc, ADC_PINS); + } + + void InitButtons() { + for (size_t i = 0; i < NUM_CONTROLS; i++) { + buttons[i].Init(BUTTON_PINS[i]); + } + + buttonBank.inputs = buttons; + } + + void InitLEDs() { + for (size_t i = 0; i < NUM_CONTROLS; i++) { + leds[i].Init(LED_PINS[i], DSY_GPIO_MODE_OUTPUT_PP, + DSY_GPIO_NOPULL); + } + + ledBank.outputs = leds; + } + + void Start() { + adcController.Start(); + } + + void Stop () { + adcController.Stop(); + } + + inline void Read() { + adcController.Read(); + buttonBank.Read(); + } + + inline void Write() { + ledBank.Write(); + } + }; +}; +}; diff --git a/hosts/daisy/include/lichen-medium-host.h b/hosts/daisy/include/lichen-medium-host.h deleted file mode 100644 index de84f7e..0000000 --- a/hosts/daisy/include/lichen-medium-host.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef SIGNALETIC_LICHEN_MEDIUM_HOST_H -#define SIGNALETIC_LICHEN_MEDIUM_HOST_H - -#include "./signaletic-daisy-host.h" -#include "../vendor/libDaisy/src/daisy_patch_sm.h" - -enum { - sig_lichen_Medium_CV_IN_1 = daisy::patch_sm::CV_1, - sig_lichen_Medium_CV_IN_2 = daisy::patch_sm::CV_2, - sig_lichen_Medium_CV_IN_3 = daisy::patch_sm::CV_3, - sig_lichen_Medium_CV_IN_4 = daisy::patch_sm::CV_4, - sig_lichen_Medium_CV_IN_5 = daisy::patch_sm::CV_5, - sig_lichen_Medium_CV_IN_6 = daisy::patch_sm::CV_6, - sig_lichen_Medium_KNOB_1 = daisy::patch_sm::CV_7, - sig_lichen_Medium_KNOB_2 = daisy::patch_sm::CV_8, - sig_lichen_Medium_KNOB_3 = daisy::patch_sm::ADC_9, - sig_lichen_Medium_KNOB_4 = daisy::patch_sm::ADC_12, - sig_lichen_Medium_KNOB_5 = daisy::patch_sm::ADC_10, - sig_lichen_Medium_KNOB_6 = daisy::patch_sm::ADC_11, - sig_lichen_Medium_CV_IN_LAST -}; - -enum { - sig_lichen_Medium_CV_OUT_LED = daisy::patch_sm::CV_OUT_1, - sig_lichen_Medium_CV_OUT_LAST -}; - -#endif // SIGNALETIC_LICHEN_MEDIUM_HOST_H diff --git a/hosts/daisy/include/lichen-medium-module.h b/hosts/daisy/include/lichen-medium-module.h index 4cfb97f..d951f58 100644 --- a/hosts/daisy/include/lichen-medium-module.h +++ b/hosts/daisy/include/lichen-medium-module.h @@ -1,57 +1,180 @@ #pragma once +#include "signaletic-host.h" #include "signaletic-daisy-host.h" #include "sig-daisy-patch-sm.hpp" +using namespace sig::libdaisy; + enum { - sig_HOST_CV_IN_1 = 0, - sig_HOST_CV_IN_2, - sig_HOST_CV_IN_3, - sig_HOST_CV_IN_4, - sig_HOST_CV_IN_5, - sig_HOST_CV_IN_6 + sig_host_KNOB_1 = 6, + sig_host_KNOB_2, + sig_host_KNOB_3, + sig_host_KNOB_4, + sig_host_KNOB_5, + sig_host_KNOB_6 }; enum { - sig_HOST_KNOB_1 = 6, - sig_HOST_KNOB_2, - sig_HOST_KNOB_3, - sig_HOST_KNOB_4, - sig_HOST_KNOB_5, - sig_HOST_KNOB_6 + sig_host_CV_IN_1 = 0, + sig_host_CV_IN_2, + sig_host_CV_IN_3, + sig_host_CV_IN_4, + sig_host_CV_IN_5, + sig_host_CV_IN_6 }; -namespace lichen { -class MediumModule { - public: - sig::libdaisy::ADCController<12> adcController; - sig::libdaisy::GateInput gates[1]; - sig::libdaisy::InputBank gateBank; +enum { + sig_host_AUDIO_IN_1 = 0, + sig_host_AUDIO_IN_2 +}; +enum { + sig_host_AUDIO_OUT_1 = 0, + sig_host_AUDIO_OUT_2 }; + +namespace lichen { namespace medium { - static const size_t NUM_ADC_PINS = 12; + static const size_t NUM_ADC_CHANNELS = 12; // These pins are ordered based on the panel: // knobs first in labelled order, then CV jacks in labelled order. - static dsy_gpio_pin ADC_PINS[NUM_ADC_PINS] = { - sig::libdaisy::PatchSM::PIN_CV_5, // Knob one/POT_CV_1/Pin C8 - sig::libdaisy::PatchSM::PIN_CV_6, // Knob two/POT_CV_2/Pin C9 - sig::libdaisy::PatchSM::PIN_ADC_9, // Knob three/POT_CV_3/Pin A2 - sig::libdaisy::PatchSM::PIN_ADC_11, // Knob four/POT_CV_4/Pin A3 - sig::libdaisy::PatchSM::PIN_ADC_10, // Knob five/POT_CV_5/Pin D9 - sig::libdaisy::PatchSM::PIN_ADC_12, // Knob six/POT_CV_6/Pin D8 - - sig::libdaisy::PatchSM::PIN_CV_1, // CV1 ("seven")/CV_IN_1/Pin C5 - sig::libdaisy::PatchSM::PIN_CV_2, // CV2 ("eight")/CV_IN_2Pin C4 - sig::libdaisy::PatchSM::PIN_CV_3, // CV3 ("nine")/CV_IN_3/Pin C3 - sig::libdaisy::PatchSM::PIN_CV_7, // CV6 ("ten")/CV_IN_6/Pin C7 - sig::libdaisy::PatchSM::PIN_CV_8, // CV5 ("eleven")/CV_IN_5/Pin C6 - sig::libdaisy::PatchSM::PIN_CV_4 // CV4 ("twelve")/CV_IN_4/Pin C2 + static dsy_gpio_pin ADC_PINS[NUM_ADC_CHANNELS] = { + patchsm::PIN_CV_5, // Knob one/POT_CV_1/Pin C8 + patchsm::PIN_CV_6, // Knob two/POT_CV_2/Pin C9 + patchsm::PIN_ADC_9, // Knob three/POT_CV_3/Pin A2 + patchsm::PIN_ADC_11, // Knob four/POT_CV_4/Pin A3 + patchsm::PIN_ADC_10, // Knob five/POT_CV_5/Pin D9 + patchsm::PIN_ADC_12, // Knob six/POT_CV_6/Pin D8 + + patchsm::PIN_CV_1, // CV1 ("seven")/CV_IN_1/Pin C5 + patchsm::PIN_CV_2, // CV2 ("eight")/CV_IN_2Pin C4 + patchsm::PIN_CV_3, // CV3 ("nine")/CV_IN_3/Pin C3 + patchsm::PIN_CV_7, // CV6 ("ten")/CV_IN_6/Pin C7 + patchsm::PIN_CV_8, // CV5 ("eleven")/CV_IN_5/Pin C6 + patchsm::PIN_CV_4 // CV4 ("twelve")/CV_IN_4/Pin C2 + }; + + static const size_t NUM_GATES = 1; + + static dsy_gpio_pin GATE_PINS[NUM_GATES] = { + patchsm::PIN_B10 + }; + + static const size_t NUM_TRISWITCHES = 1; + static dsy_gpio_pin TRISWITCH_PINS[NUM_GATES][2] = { + { + patchsm::PIN_B7, + patchsm::PIN_B8 + } + }; + + static const size_t NUM_BUTTONS = 1; + static dsy_gpio_pin BUTTON_PINS[NUM_BUTTONS] = { + patchsm::PIN_D1 }; - static const sig::libdaisy::ModuleDefinition MediumDefinition = { - .adcPins = ADC_PINS + static const size_t NUM_DAC_CHANNELS = 1; + + void onEvaluateSignals(size_t size, + struct sig_host_HardwareInterface* hardware); + + void afterEvaluateSignals(size_t size, + struct sig_host_HardwareInterface* hardware); + + class MediumDevice { + public: + patchsm::PatchSMBoard board; + ADCController adcController; + GateInput gates[NUM_GATES]; + InputBank gateBank; + TriSwitch triSwitches[NUM_TRISWITCHES]; + InputBank switchBank; + Toggle buttons[NUM_BUTTONS]; + InputBank buttonBank; + AnalogOutput dacChannels[NUM_DAC_CHANNELS]; + OutputBank dacChannelBank; + struct sig_host_HardwareInterface hardware; + + void Init(struct sig_AudioSettings* audioSettings) { + board.Init(audioSettings->blockSize, audioSettings->sampleRate); + InitADCController(); + InitControls(); + + hardware = { + .evaluator = NULL, + .onEvaluateSignals = onEvaluateSignals, + .afterEvaluateSignals = afterEvaluateSignals, + .userData = this, + .numAudioInputChannels = 2, + .audioInputChannels = NULL, // Supplied by audio callback + .numAudioOutputChannels = 2, + .audioOutputChannels = NULL, // Supplied by audio callback + .numADCChannels = NUM_ADC_CHANNELS, + .adcChannels = adcController.channelBank.values, + .numDACChannels = NUM_DAC_CHANNELS, + .dacChannels = dacChannelBank.values, + .numGateInputs = NUM_GATES, + .gateInputs = gateBank.values, + .numGPIOOutputs = 0, + .gpioOutputs = NULL, + .numToggles = NUM_BUTTONS, + .toggles = buttonBank.values, + .numTriSwitches = NUM_TRISWITCHES, + .triSwitches = switchBank.values + }; + } + + void InitADCController() { + adcController.Init(&board.adc, ADC_PINS); + } + + void InitDAC() { + dacChannels[0].Init( + &patchsm::sig_daisy_patch_sm_dac_output[0]); + } + + void InitControls() { + gates[0].Init(GATE_PINS[0]); + gateBank.inputs = gates; + triSwitches[0].Init(TRISWITCH_PINS[0][1], TRISWITCH_PINS[0][2]); + switchBank.inputs = triSwitches; + buttons[0].Init(BUTTON_PINS[0]); + buttonBank.inputs = buttons; + } + + void Start() { + adcController.Start(); + } + + void Stop () { + adcController.Stop(); + } + + inline void Read() { + adcController.Read(); + gateBank.Read(); + switchBank.Read(); + buttonBank.Read(); + } + + inline void Write() { + dacChannelBank.Write(); + } }; + + + void onEvaluateSignals(size_t size, + struct sig_host_HardwareInterface* hardware) { + MediumDevice* self = static_cast (hardware->userData); + self->Read(); + } + + void afterEvaluateSignals(size_t size, + struct sig_host_HardwareInterface* hardware) { + MediumDevice* self = static_cast (hardware->userData); + self->Read(); + } }; }; diff --git a/hosts/daisy/include/sig-daisy-patch-sm.hpp b/hosts/daisy/include/sig-daisy-patch-sm.hpp index e210c92..7f1b33d 100644 --- a/hosts/daisy/include/sig-daisy-patch-sm.hpp +++ b/hosts/daisy/include/sig-daisy-patch-sm.hpp @@ -3,70 +3,72 @@ namespace sig { namespace libdaisy { - class PatchSM : public Board { - public: - static constexpr dsy_gpio_pin PIN_NONE = {DSY_GPIOX, 0}; - static constexpr dsy_gpio_pin PIN_A1 = {DSY_GPIOX, 0}; - static constexpr dsy_gpio_pin PIN_A2 = {DSY_GPIOA, 1}; - static constexpr dsy_gpio_pin PIN_A3 = {DSY_GPIOA, 0}; - static constexpr dsy_gpio_pin PIN_A4 = {DSY_GPIOX, 0}; - static constexpr dsy_gpio_pin PIN_A5 = {DSY_GPIOX, 0}; - static constexpr dsy_gpio_pin PIN_A6 = {DSY_GPIOX, 0}; - static constexpr dsy_gpio_pin PIN_A7 = {DSY_GPIOX, 0}; - static constexpr dsy_gpio_pin PIN_A8 = {DSY_GPIOA, 14}; - static constexpr dsy_gpio_pin PIN_A9 = {DSY_GPIOA, 15}; - static constexpr dsy_gpio_pin PIN_A10 = {DSY_GPIOX, 0}; +namespace patchsm { + static constexpr dsy_gpio_pin PIN_NONE = {DSY_GPIOX, 0}; + static constexpr dsy_gpio_pin PIN_A1 = {DSY_GPIOX, 0}; + static constexpr dsy_gpio_pin PIN_A2 = {DSY_GPIOA, 1}; + static constexpr dsy_gpio_pin PIN_A3 = {DSY_GPIOA, 0}; + static constexpr dsy_gpio_pin PIN_A4 = {DSY_GPIOX, 0}; + static constexpr dsy_gpio_pin PIN_A5 = {DSY_GPIOX, 0}; + static constexpr dsy_gpio_pin PIN_A6 = {DSY_GPIOX, 0}; + static constexpr dsy_gpio_pin PIN_A7 = {DSY_GPIOX, 0}; + static constexpr dsy_gpio_pin PIN_A8 = {DSY_GPIOA, 14}; + static constexpr dsy_gpio_pin PIN_A9 = {DSY_GPIOA, 15}; + static constexpr dsy_gpio_pin PIN_A10 = {DSY_GPIOX, 0}; - static constexpr dsy_gpio_pin PIN_B1 = {DSY_GPIOX, 0}; - static constexpr dsy_gpio_pin PIN_B2 = {DSY_GPIOX, 0}; - static constexpr dsy_gpio_pin PIN_B3 = {DSY_GPIOX, 0}; - static constexpr dsy_gpio_pin PIN_B4 = {DSY_GPIOX, 0}; - static constexpr dsy_gpio_pin PIN_B5 = {DSY_GPIOC, 13}; - static constexpr dsy_gpio_pin PIN_B6 = {DSY_GPIOC, 14}; - static constexpr dsy_gpio_pin PIN_B7 = {DSY_GPIOB, 8}; - static constexpr dsy_gpio_pin PIN_B8 = {DSY_GPIOB, 9}; - static constexpr dsy_gpio_pin PIN_B9 = {DSY_GPIOG, 14}; - static constexpr dsy_gpio_pin PIN_B10 = {DSY_GPIOG, 13}; + static constexpr dsy_gpio_pin PIN_B1 = {DSY_GPIOX, 0}; + static constexpr dsy_gpio_pin PIN_B2 = {DSY_GPIOX, 0}; + static constexpr dsy_gpio_pin PIN_B3 = {DSY_GPIOX, 0}; + static constexpr dsy_gpio_pin PIN_B4 = {DSY_GPIOX, 0}; + static constexpr dsy_gpio_pin PIN_B5 = {DSY_GPIOC, 13}; + static constexpr dsy_gpio_pin PIN_B6 = {DSY_GPIOC, 14}; + static constexpr dsy_gpio_pin PIN_B7 = {DSY_GPIOB, 8}; + static constexpr dsy_gpio_pin PIN_B8 = {DSY_GPIOB, 9}; + static constexpr dsy_gpio_pin PIN_B9 = {DSY_GPIOG, 14}; + static constexpr dsy_gpio_pin PIN_B10 = {DSY_GPIOG, 13}; - static constexpr dsy_gpio_pin PIN_C1 = {DSY_GPIOA, 5}; - static constexpr dsy_gpio_pin PIN_C2 = {DSY_GPIOA, 7}; - static constexpr dsy_gpio_pin PIN_C3 = {DSY_GPIOA, 2}; - static constexpr dsy_gpio_pin PIN_C4 = {DSY_GPIOA, 6}; - static constexpr dsy_gpio_pin PIN_C5 = {DSY_GPIOA, 3}; - static constexpr dsy_gpio_pin PIN_C6 = {DSY_GPIOB, 1}; - static constexpr dsy_gpio_pin PIN_C7 = {DSY_GPIOC, 4}; - static constexpr dsy_gpio_pin PIN_C8 = {DSY_GPIOC, 0}; - static constexpr dsy_gpio_pin PIN_C9 = {DSY_GPIOC, 1}; - static constexpr dsy_gpio_pin PIN_C10 = {DSY_GPIOA, 4}; + static constexpr dsy_gpio_pin PIN_C1 = {DSY_GPIOA, 5}; + static constexpr dsy_gpio_pin PIN_C2 = {DSY_GPIOA, 7}; + static constexpr dsy_gpio_pin PIN_C3 = {DSY_GPIOA, 2}; + static constexpr dsy_gpio_pin PIN_C4 = {DSY_GPIOA, 6}; + static constexpr dsy_gpio_pin PIN_C5 = {DSY_GPIOA, 3}; + static constexpr dsy_gpio_pin PIN_C6 = {DSY_GPIOB, 1}; + static constexpr dsy_gpio_pin PIN_C7 = {DSY_GPIOC, 4}; + static constexpr dsy_gpio_pin PIN_C8 = {DSY_GPIOC, 0}; + static constexpr dsy_gpio_pin PIN_C9 = {DSY_GPIOC, 1}; + static constexpr dsy_gpio_pin PIN_C10 = {DSY_GPIOA, 4}; - static constexpr dsy_gpio_pin PIN_D1 = {DSY_GPIOB, 4}; - static constexpr dsy_gpio_pin PIN_D2 = {DSY_GPIOC, 11}; - static constexpr dsy_gpio_pin PIN_D3 = {DSY_GPIOC, 10}; - static constexpr dsy_gpio_pin PIN_D4 = {DSY_GPIOC, 9}; - static constexpr dsy_gpio_pin PIN_D5 = {DSY_GPIOC, 8}; - static constexpr dsy_gpio_pin PIN_D6 = {DSY_GPIOC, 12}; - static constexpr dsy_gpio_pin PIN_D7 = {DSY_GPIOD, 2}; - static constexpr dsy_gpio_pin PIN_D8 = {DSY_GPIOC, 2}; - static constexpr dsy_gpio_pin PIN_D9 = {DSY_GPIOC, 3}; - static constexpr dsy_gpio_pin PIN_D10 = {DSY_GPIOD, 3}; + static constexpr dsy_gpio_pin PIN_D1 = {DSY_GPIOB, 4}; + static constexpr dsy_gpio_pin PIN_D2 = {DSY_GPIOC, 11}; + static constexpr dsy_gpio_pin PIN_D3 = {DSY_GPIOC, 10}; + static constexpr dsy_gpio_pin PIN_D4 = {DSY_GPIOC, 9}; + static constexpr dsy_gpio_pin PIN_D5 = {DSY_GPIOC, 8}; + static constexpr dsy_gpio_pin PIN_D6 = {DSY_GPIOC, 12}; + static constexpr dsy_gpio_pin PIN_D7 = {DSY_GPIOD, 2}; + static constexpr dsy_gpio_pin PIN_D8 = {DSY_GPIOC, 2}; + static constexpr dsy_gpio_pin PIN_D9 = {DSY_GPIOC, 3}; + static constexpr dsy_gpio_pin PIN_D10 = {DSY_GPIOD, 3}; - static constexpr dsy_gpio_pin PIN_CV_1 = PIN_C5; - static constexpr dsy_gpio_pin PIN_CV_2 = PIN_C4; - static constexpr dsy_gpio_pin PIN_CV_3 = PIN_C3; - static constexpr dsy_gpio_pin PIN_CV_4 = PIN_C2; - static constexpr dsy_gpio_pin PIN_CV_5 = PIN_C6; - static constexpr dsy_gpio_pin PIN_CV_6 = PIN_C7; - static constexpr dsy_gpio_pin PIN_CV_7 = PIN_C8; - static constexpr dsy_gpio_pin PIN_CV_8 = PIN_C9; - static constexpr dsy_gpio_pin PIN_ADC_9 = PIN_A2; - static constexpr dsy_gpio_pin PIN_ADC_10 = PIN_A3; - static constexpr dsy_gpio_pin PIN_ADC_11 = PIN_D9; - static constexpr dsy_gpio_pin PIN_ADC_12 = PIN_D8; - static constexpr dsy_gpio_pin PIN_USER_LED = {DSY_GPIOC, 7}; + static constexpr dsy_gpio_pin PIN_CV_1 = PIN_C5; + static constexpr dsy_gpio_pin PIN_CV_2 = PIN_C4; + static constexpr dsy_gpio_pin PIN_CV_3 = PIN_C3; + static constexpr dsy_gpio_pin PIN_CV_4 = PIN_C2; + static constexpr dsy_gpio_pin PIN_CV_5 = PIN_C6; + static constexpr dsy_gpio_pin PIN_CV_6 = PIN_C7; + static constexpr dsy_gpio_pin PIN_CV_7 = PIN_C8; + static constexpr dsy_gpio_pin PIN_CV_8 = PIN_C9; + static constexpr dsy_gpio_pin PIN_ADC_9 = PIN_A2; + static constexpr dsy_gpio_pin PIN_ADC_10 = PIN_A3; + static constexpr dsy_gpio_pin PIN_ADC_11 = PIN_D9; + static constexpr dsy_gpio_pin PIN_ADC_12 = PIN_D8; + static constexpr dsy_gpio_pin PIN_USER_LED = {DSY_GPIOC, 7}; + class PatchSMBoard : public Board { + public: daisy::Pcm3060 codec; size_t dac_buffer_size_; uint16_t* dacBuffer[2]; + uint16_t dacOutput[2]; bool dac_running_; void Init(size_t blockSize, float sampleRate); @@ -76,3 +78,4 @@ namespace libdaisy { }; }; }; +}; diff --git a/hosts/daisy/include/sig-daisy-seed.hpp b/hosts/daisy/include/sig-daisy-seed.hpp index 6b76247..8be6992 100644 --- a/hosts/daisy/include/sig-daisy-seed.hpp +++ b/hosts/daisy/include/sig-daisy-seed.hpp @@ -4,79 +4,80 @@ namespace sig { namespace libdaisy { - static constexpr dsy_gpio_pin SEED_PIN_NONE = {DSY_GPIOX, 0}; - static constexpr dsy_gpio_pin SEED_PIN_D0 = {DSY_GPIOB, 12}; - static constexpr dsy_gpio_pin SEED_PIN_D1 = {DSY_GPIOC, 11}; - static constexpr dsy_gpio_pin SEED_PIN_D2 = {DSY_GPIOC, 10}; - static constexpr dsy_gpio_pin SEED_PIN_D3 = {DSY_GPIOC, 9}; - static constexpr dsy_gpio_pin SEED_PIN_D4 = {DSY_GPIOC, 8}; - static constexpr dsy_gpio_pin SEED_PIN_D5 = {DSY_GPIOD, 2}; - static constexpr dsy_gpio_pin SEED_PIN_D6 = {DSY_GPIOC, 12}; - static constexpr dsy_gpio_pin SEED_PIN_D7 = {DSY_GPIOG, 10}; - static constexpr dsy_gpio_pin SEED_PIN_D8 = {DSY_GPIOG, 11}; - static constexpr dsy_gpio_pin SEED_PIN_D9 = {DSY_GPIOB, 4}; - static constexpr dsy_gpio_pin SEED_PIN_D10 = {DSY_GPIOB, 5}; - static constexpr dsy_gpio_pin SEED_PIN_D11 = {DSY_GPIOB, 8}; - static constexpr dsy_gpio_pin SEED_PIN_D12 = {DSY_GPIOB, 9}; - static constexpr dsy_gpio_pin SEED_PIN_D13 = {DSY_GPIOB, 6}; - static constexpr dsy_gpio_pin SEED_PIN_D14 = {DSY_GPIOB, 7}; - static constexpr dsy_gpio_pin SEED_PIN_D15 = {DSY_GPIOC, 0}; - static constexpr dsy_gpio_pin SEED_PIN_D16 = {DSY_GPIOA, 3}; - static constexpr dsy_gpio_pin SEED_PIN_D17 = {DSY_GPIOB, 1}; - static constexpr dsy_gpio_pin SEED_PIN_D18 = {DSY_GPIOA, 7}; - static constexpr dsy_gpio_pin SEED_PIN_D19 = {DSY_GPIOA, 6}; - static constexpr dsy_gpio_pin SEED_PIN_D20 = {DSY_GPIOC, 1}; - static constexpr dsy_gpio_pin SEED_PIN_D21 = {DSY_GPIOC, 4}; - static constexpr dsy_gpio_pin SEED_PIN_D22 = {DSY_GPIOA, 5}; - static constexpr dsy_gpio_pin SEED_PIN_D23 = {DSY_GPIOA, 4}; - static constexpr dsy_gpio_pin SEED_PIN_D24 = {DSY_GPIOA, 1}; - static constexpr dsy_gpio_pin SEED_PIN_D25 = {DSY_GPIOA, 0}; - static constexpr dsy_gpio_pin SEED_PIN_D26 = {DSY_GPIOD, 11}; - static constexpr dsy_gpio_pin SEED_PIN_D27 = {DSY_GPIOG, 9}; - static constexpr dsy_gpio_pin SEED_PIN_D28 = {DSY_GPIOA, 2}; - static constexpr dsy_gpio_pin SEED_PIN_D29 = {DSY_GPIOB, 14}; - static constexpr dsy_gpio_pin SEED_PIN_D30 = {DSY_GPIOB, 15}; - static constexpr dsy_gpio_pin SEED_PIN_USER_LED = {DSY_GPIOC, 7}; +namespace seed { + static constexpr dsy_gpio_pin PIN_NONE = {DSY_GPIOX, 0}; + static constexpr dsy_gpio_pin PIN_D0 = {DSY_GPIOB, 12}; + static constexpr dsy_gpio_pin PIN_D1 = {DSY_GPIOC, 11}; + static constexpr dsy_gpio_pin PIN_D2 = {DSY_GPIOC, 10}; + static constexpr dsy_gpio_pin PIN_D3 = {DSY_GPIOC, 9}; + static constexpr dsy_gpio_pin PIN_D4 = {DSY_GPIOC, 8}; + static constexpr dsy_gpio_pin PIN_D5 = {DSY_GPIOD, 2}; + static constexpr dsy_gpio_pin PIN_D6 = {DSY_GPIOC, 12}; + static constexpr dsy_gpio_pin PIN_D7 = {DSY_GPIOG, 10}; + static constexpr dsy_gpio_pin PIN_D8 = {DSY_GPIOG, 11}; + static constexpr dsy_gpio_pin PIN_D9 = {DSY_GPIOB, 4}; + static constexpr dsy_gpio_pin PIN_D10 = {DSY_GPIOB, 5}; + static constexpr dsy_gpio_pin PIN_D11 = {DSY_GPIOB, 8}; + static constexpr dsy_gpio_pin PIN_D12 = {DSY_GPIOB, 9}; + static constexpr dsy_gpio_pin PIN_D13 = {DSY_GPIOB, 6}; + static constexpr dsy_gpio_pin PIN_D14 = {DSY_GPIOB, 7}; + static constexpr dsy_gpio_pin PIN_D15 = {DSY_GPIOC, 0}; + static constexpr dsy_gpio_pin PIN_D16 = {DSY_GPIOA, 3}; + static constexpr dsy_gpio_pin PIN_D17 = {DSY_GPIOB, 1}; + static constexpr dsy_gpio_pin PIN_D18 = {DSY_GPIOA, 7}; + static constexpr dsy_gpio_pin PIN_D19 = {DSY_GPIOA, 6}; + static constexpr dsy_gpio_pin PIN_D20 = {DSY_GPIOC, 1}; + static constexpr dsy_gpio_pin PIN_D21 = {DSY_GPIOC, 4}; + static constexpr dsy_gpio_pin PIN_D22 = {DSY_GPIOA, 5}; + static constexpr dsy_gpio_pin PIN_D23 = {DSY_GPIOA, 4}; + static constexpr dsy_gpio_pin PIN_D24 = {DSY_GPIOA, 1}; + static constexpr dsy_gpio_pin PIN_D25 = {DSY_GPIOA, 0}; + static constexpr dsy_gpio_pin PIN_D26 = {DSY_GPIOD, 11}; + static constexpr dsy_gpio_pin PIN_D27 = {DSY_GPIOG, 9}; + static constexpr dsy_gpio_pin PIN_D28 = {DSY_GPIOA, 2}; + static constexpr dsy_gpio_pin PIN_D29 = {DSY_GPIOB, 14}; + static constexpr dsy_gpio_pin PIN_D30 = {DSY_GPIOB, 15}; + static constexpr dsy_gpio_pin PIN_USER_LED = {DSY_GPIOC, 7}; /** Analog pins share same pins as digital pins */ - static constexpr dsy_gpio_pin SEED_PIN_A0 = SEED_PIN_D15; - static constexpr dsy_gpio_pin SEED_PIN_A1 = SEED_PIN_D16; - static constexpr dsy_gpio_pin SEED_PIN_A2 = SEED_PIN_D17; - static constexpr dsy_gpio_pin SEED_PIN_A3 = SEED_PIN_D18; - static constexpr dsy_gpio_pin SEED_PIN_A4 = SEED_PIN_D19; - static constexpr dsy_gpio_pin SEED_PIN_A5 = SEED_PIN_D20; - static constexpr dsy_gpio_pin SEED_PIN_A6 = SEED_PIN_D21; - static constexpr dsy_gpio_pin SEED_PIN_A7 = SEED_PIN_D22; - static constexpr dsy_gpio_pin SEED_PIN_A8 = SEED_PIN_D23; - static constexpr dsy_gpio_pin SEED_PIN_A9 = SEED_PIN_D24; - static constexpr dsy_gpio_pin SEED_PIN_A10 = SEED_PIN_D25; - static constexpr dsy_gpio_pin SEED_PIN_A11 = SEED_PIN_D28; + static constexpr dsy_gpio_pin PIN_A0 = PIN_D15; + static constexpr dsy_gpio_pin PIN_A1 = PIN_D16; + static constexpr dsy_gpio_pin PIN_A2 = PIN_D17; + static constexpr dsy_gpio_pin PIN_A3 = PIN_D18; + static constexpr dsy_gpio_pin PIN_A4 = PIN_D19; + static constexpr dsy_gpio_pin PIN_A5 = PIN_D20; + static constexpr dsy_gpio_pin PIN_A6 = PIN_D21; + static constexpr dsy_gpio_pin PIN_A7 = PIN_D22; + static constexpr dsy_gpio_pin PIN_A8 = PIN_D23; + static constexpr dsy_gpio_pin PIN_A9 = PIN_D24; + static constexpr dsy_gpio_pin PIN_A10 = PIN_D25; + static constexpr dsy_gpio_pin PIN_A11 = PIN_D28; - static constexpr dsy_gpio_pin SEED_PIN_ADC_0 = SEED_PIN_A0; - static constexpr dsy_gpio_pin SEED_PIN_ADC_1 = SEED_PIN_A1; - static constexpr dsy_gpio_pin SEED_PIN_ADC_2 = SEED_PIN_A2; - static constexpr dsy_gpio_pin SEED_PIN_ADC_3 = SEED_PIN_A3; - static constexpr dsy_gpio_pin SEED_PIN_ADC_4 = SEED_PIN_A4; - static constexpr dsy_gpio_pin SEED_PIN_ADC_5 = SEED_PIN_A5; - static constexpr dsy_gpio_pin SEED_PIN_ADC_6 = SEED_PIN_A6; - static constexpr dsy_gpio_pin SEED_PIN_ADC_7 = SEED_PIN_A7; - static constexpr dsy_gpio_pin SEED_PIN_ADC_8 = SEED_PIN_A8; - static constexpr dsy_gpio_pin SEED_PIN_ADC_9 = SEED_PIN_A9; - static constexpr dsy_gpio_pin SEED_PIN_ADC_10 = SEED_PIN_A10; - static constexpr dsy_gpio_pin SEED_PIN_ADC_11 = SEED_PIN_A11; + static constexpr dsy_gpio_pin PIN_ADC_0 = PIN_A0; + static constexpr dsy_gpio_pin PIN_ADC_1 = PIN_A1; + static constexpr dsy_gpio_pin PIN_ADC_2 = PIN_A2; + static constexpr dsy_gpio_pin PIN_ADC_3 = PIN_A3; + static constexpr dsy_gpio_pin PIN_ADC_4 = PIN_A4; + static constexpr dsy_gpio_pin PIN_ADC_5 = PIN_A5; + static constexpr dsy_gpio_pin PIN_ADC_6 = PIN_A6; + static constexpr dsy_gpio_pin PIN_ADC_7 = PIN_A7; + static constexpr dsy_gpio_pin PIN_ADC_8 = PIN_A8; + static constexpr dsy_gpio_pin PIN_ADC_9 = PIN_A9; + static constexpr dsy_gpio_pin PIN_ADC_10 = PIN_A10; + static constexpr dsy_gpio_pin PIN_ADC_11 = PIN_A11; - static constexpr dsy_gpio_pin SEED_PIN_DAC_OUT_1 = SEED_PIN_ADC_8; - static constexpr dsy_gpio_pin SEED_PIN_DAC_OUT_2= SEED_PIN_ADC_7; + static constexpr dsy_gpio_pin PIN_DAC_OUT_1 = PIN_ADC_8; + static constexpr dsy_gpio_pin PIN_DAC_OUT_2= PIN_ADC_7; /** Pins unique to Daisy Seed 2 DFM */ - static constexpr dsy_gpio_pin SEED_PIN_D31 = {DSY_GPIOC, 2}; - static constexpr dsy_gpio_pin SEED_PIN_D32 = {DSY_GPIOC, 3}; + static constexpr dsy_gpio_pin PIN_D31 = {DSY_GPIOC, 2}; + static constexpr dsy_gpio_pin PIN_D32 = {DSY_GPIOC, 3}; /** Analog Pin alias */ - static constexpr dsy_gpio_pin SEED_PIN_A12 = SEED_PIN_D31; - static constexpr dsy_gpio_pin SEED_PIN_A13 = SEED_PIN_D32; + static constexpr dsy_gpio_pin PIN_A12 = PIN_D31; + static constexpr dsy_gpio_pin PIN_A13 = PIN_D32; - class Seed : public Board { + class SeedBoard : public Board { public: enum class BoardVersion { DAISY_SEED, @@ -100,3 +101,4 @@ namespace libdaisy { }; }; }; +}; diff --git a/hosts/daisy/include/signaletic-daisy-host.h b/hosts/daisy/include/signaletic-daisy-host.h index ea75e00..a816fe7 100644 --- a/hosts/daisy/include/signaletic-daisy-host.h +++ b/hosts/daisy/include/signaletic-daisy-host.h @@ -1,16 +1,17 @@ -#ifndef SIGNALETIC_DAISY_HOST_H -#define SIGNALETIC_DAISY_HOST_H +#pragma once #include #include "daisy.h" +#include "signaletic-host.h" namespace sig { namespace libdaisy { template class InputBank { public: - T inputs[size]; - float values[size]; + T* inputs; + float values[size] = {0.0}; + inline void Read() { for (size_t i = 0; i < size; i++) { values[i] = inputs[i].Value(); @@ -20,7 +21,7 @@ template class InputBank { template class OutputBank { public: - T outputs[size]; + T* outputs; float values[size]; inline void Write() { for (size_t i = 0; i < size; i++) { @@ -29,32 +30,62 @@ template class OutputBank { } }; -class AnalogInput { +class BaseAnalogInput { public: uint16_t* adcPtr; void Init(daisy::AdcHandle* adc, int adcChannel) { - adcPtr = adc->GetPtr(adcChannel); + adcPtr = adc->GetPtr(adcChannel); } +}; +class AnalogInput : public BaseAnalogInput { + public: /** * @brief Returns the value of the ADC channel as a float - * scaled to a range of 0.0 to 1.0f. + * scaled to a range of -1.0 to 1.0f. + * + * @return float the ADC channel's current value + */ + inline float Value() { + float converted = sig_uint16ToBipolar(*adcPtr); + return converted; + } +}; + +class UnipolarAnalogInput : public BaseAnalogInput { + public: + /** + * @brief Returns the inverted value of the ADC channel as + * a float scaled to the range of 0.0 to 1.0f. * * @return float the ADC channel's current value */ inline float Value() { - float normalized = (float) (*adcPtr / 65536.0f); - float inverted = 1.0f - normalized; - float scaled = inverted * 2.0f - 1.0f; - return scaled; + return sig_uint16ToUnipolar(*adcPtr); } }; -template class ADCController { +// FIXME: At least on the Bluemchen, this (and the other AnalogInputs?) +// is returning values in the range -0.9..+1.0 +class InvertedAnalogInput : public AnalogInput { + public: + /** + * @brief Returns the inverted value of the ADC channel as + * a float scaled to the range of -1.0 to 1.0f. + * + * @return float the ADC channel's current value + */ + inline float Value() { + return sig_invUint16ToBipolar(*adcPtr); + } +}; + +template class ADCController { public: daisy::AdcHandle* adcHandle; - AnalogInput inputs[numChannels]; + T inputs[numChannels]; + InputBank channelBank; void Init(daisy::AdcHandle* inAdcHandle, dsy_gpio_pin* pins) { adcHandle = inAdcHandle; @@ -69,6 +100,8 @@ template class ADCController { for (size_t i = 0; i < numChannels; i++) { inputs[i].Init(adcHandle, i); } + + channelBank.inputs = inputs; } void Start() { @@ -78,6 +111,24 @@ template class ADCController { void Stop() { adcHandle->Stop(); } + + inline void Read() { + channelBank.Read(); + } +}; + +class AnalogOutput { + public: + uint16_t* dacBuffer; + size_t channel; + + void Init(uint16_t* inDACBuffer) { + dacBuffer = inDACBuffer; + } + + inline void Write(float value) { + *dacBuffer = sig_bipolarToUint12(value); + } }; class GPIO { @@ -156,507 +207,34 @@ class TriSwitch { } inline float Value () { - return (float) switchA.Value() + -switchB.Value(); - } -}; - -struct ModuleDefinition { - dsy_gpio_pin* adcPins; - dsy_gpio_pin* gatePins; -}; - -template -class Module { - public: - T board; - sig::libdaisy::ADCController adcController; - ModuleDefinition definition; - - void Init(ModuleDefinition inDefinition, - struct sig_AudioSettings audioSettings) { - definition = inDefinition; - board.Init(audioSettings.blockSize, audioSettings.sampleRate); - InitADCController(); - } - - void InitADCController() { - adcController.Init(&board.adc, definition.adcPins); - adcController.Start(); + return switchA.Value() + -switchB.Value(); } }; -#define MAX_NUM_CONTROLS 16 - -enum { - sig_daisy_AUDIO_IN_1 = 0, - sig_daisy_AUDIO_IN_2, - sig_daisy_AUDIO_IN_LAST -}; - -enum { - sig_daisy_AUDIO_OUT_1 = 0, - sig_daisy_AUDIO_OUT_2, - sig_daisy_AUDIO_OUT_LAST -}; - -enum { - sig_daisy_GATE_IN_1 = 0, - sig_daisy_GATE_IN_2, - sig_daisy_GATE_IN_LAST -}; - -enum { - sig_daisy_GATE_OUT_1 = 0, - sig_daisy_GATE_OUT_2, - sig_daisy_GATE_OUT_LAST -}; - -struct sig_daisy_Host_BoardConfiguration { - int numAudioInputChannels; - int numAudioOutputChannels; - int numAnalogInputs; - int numAnalogOutputs; - int numGateInputs; - int numGateOutputs; - int numSwitches; - int numTriSwitches; - int numEncoders; -}; - -struct sig_daisy_Host_Board { - struct sig_daisy_Host_BoardConfiguration* config; - daisy::AudioHandle::InputBuffer audioInputs; - daisy::AudioHandle::OutputBuffer audioOutputs; - daisy::AnalogControl* analogControls; - daisy::DacHandle* dac; - daisy::GateIn* gateInputs[MAX_NUM_CONTROLS]; - // TODO: It's unwieldy and unscalable to accumulate all possible - // hardware UI controls into one Board object. We need - // a more dynamic data structure for referencing - // hardware capabilities. - dsy_gpio* gateOutputs[MAX_NUM_CONTROLS]; - daisy::Switch switches[MAX_NUM_CONTROLS]; - daisy::Switch3 triSwitches[MAX_NUM_CONTROLS]; - daisy::Encoder* encoders[MAX_NUM_CONTROLS]; - void* boardInstance; -}; - -typedef void (*sig_daisy_Host_onEvaluateSignals)( - daisy::AudioHandle::InputBuffer in, - daisy::AudioHandle::OutputBuffer out, - size_t size, - struct sig_daisy_Host* host, - void* userData); - -typedef void (*sig_daisy_Host_afterEvaluateSignals)( - daisy::AudioHandle::InputBuffer in, - daisy::AudioHandle::OutputBuffer out, - size_t size, - struct sig_daisy_Host* host, - void* userData); - -struct sig_daisy_Host { - struct sig_daisy_Host_Impl* impl; - struct sig_daisy_Host_Board board; - struct sig_AudioSettings* audioSettings; - struct sig_dsp_SignalEvaluator* evaluator; - sig_daisy_Host_onEvaluateSignals onEvaluateSignals; - sig_daisy_Host_afterEvaluateSignals afterEvaluateSignals; - void* userData; -}; - -daisy::SaiHandle::Config::SampleRate sig_daisy_Host_convertSampleRate( - float sampleRate); - -void sig_daisy_Host_addOnEvaluateSignalsListener( - struct sig_daisy_Host* self, - sig_daisy_Host_onEvaluateSignals listener, - void* userData); - -void sig_daisy_Host_addAfterEvaluateSignalsListener( - struct sig_daisy_Host* self, - sig_daisy_Host_onEvaluateSignals listener, - void* userData); void sig_daisy_Host_audioCallback(daisy::AudioHandle::InputBuffer in, daisy::AudioHandle::OutputBuffer out, size_t size); -void sig_daisy_Host_init(struct sig_daisy_Host* self); - -void sig_daisy_Host_registerGlobalHost(struct sig_daisy_Host* host); - -void sig_daisy_Host_noOpAudioCallback(daisy::AudioHandle::InputBuffer in, - daisy::AudioHandle::OutputBuffer out, size_t size, - struct sig_daisy_Host* host, void* userData); - -typedef float (*sig_daisy_Host_getControlValue)( - struct sig_daisy_Host* host, int control); - -typedef void (*sig_daisy_Host_setControlValue)( - struct sig_daisy_Host* host, int control, float value); - -typedef float (*sig_daisy_Host_getGateValue)( - struct sig_daisy_Host* host, int control); - -typedef void (*sig_daisy_Host_setGateValue)( - struct sig_daisy_Host* host, int control, float value); - -typedef float (*sig_daisy_Host_getSwitchValue)( - struct sig_daisy_Host* host, int control); - -typedef float (*sig_daisy_Host_getTriSwitchValue)( - struct sig_daisy_Host* host, int control); - -typedef float (*sig_daisy_Host_getEncoderIncrement)( - struct sig_daisy_Host* host, int control); - -typedef float (*sig_daisy_Host_getEncoderButtonValue)( - struct sig_daisy_Host* host, int control); - -typedef void (*sig_daisy_Host_start)(struct sig_daisy_Host* host); -typedef void (*sig_daisy_Host_stop)(struct sig_daisy_Host* host); - -struct sig_daisy_Host_Impl { - sig_daisy_Host_getControlValue getControlValue; - sig_daisy_Host_setControlValue setControlValue; - sig_daisy_Host_getGateValue getGateValue; - sig_daisy_Host_setGateValue setGateValue; - sig_daisy_Host_getSwitchValue getSwitchValue; - sig_daisy_Host_getTriSwitchValue getTriSwitchValue; - sig_daisy_Host_getEncoderIncrement getEncoderIncrement; - sig_daisy_Host_getEncoderButtonValue getEncoderButtonValue; - sig_daisy_Host_start start; - sig_daisy_Host_stop stop; -}; - -/** - * @brief Writes a bipolar float in the range of -1.0 to 1.0 to the - * on-board Daisy DAC that has been configured for polling (i.e. not DMA) mode. - * - * @param dac a handle to the DAC - * @param control the control to write to - * @param value the value to write - */ -void sig_daisy_Host_writeValueToDACPolling(daisy::DacHandle* dac, - int control, float value); - -float sig_daisy_HostImpl_noOpGetControl(struct sig_daisy_Host* host, - int control); - -void sig_daisy_HostImpl_noOpSetControl(struct sig_daisy_Host* host, - int control, float value); - -/** - * @brief Processes and returns the value for the specified Analog Control. - * This implementation should work with most Daisy boards, assuming they - * provide public access to an array of daisy::AnalogControls (which most do). - * - * @param host the host instance - * @param control the control number to process - * @return float the value of the control - */ -float sig_daisy_HostImpl_processControlValue(struct sig_daisy_Host* host, - int control); - -void sig_daisy_HostImpl_setControlValue( - struct sig_daisy_Host* host, int control, float value); - -float sig_daisy_HostImpl_getGateValue(struct sig_daisy_Host* host, - int control); - -void sig_daisy_HostImpl_setGateValue(struct sig_daisy_Host* host, - int control, float value); - -float sig_daisy_HostImpl_getSwitchValue(struct sig_daisy_Host* host, - int control); - -float sig_daisy_HostImpl_getTriSwitchValue(struct sig_daisy_Host* host, - int control); - -float sig_daisy_HostImpl_getEncoderIncrement(struct sig_daisy_Host* host, - int control); - -float sig_daisy_HostImpl_processEncoderButtonValue(struct sig_daisy_Host* host, - int control); - -struct sig_daisy_CV_Parameters { - float scale; - float offset; - int control; -}; - -struct sig_daisy_GateIn { - struct sig_dsp_Signal signal; - struct sig_daisy_CV_Parameters parameters; - struct sig_dsp_Signal_SingleMonoOutput outputs; - struct sig_daisy_Host* host; -}; - -struct sig_daisy_GateIn* sig_daisy_GateIn_new( - struct sig_Allocator* allocator, - struct sig_SignalContext* context, - struct sig_daisy_Host* host); -void sig_daisy_GateIn_init(struct sig_daisy_GateIn* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host); -void sig_daisy_GateIn_generate(void* signal); -void sig_daisy_GateIn_destroy(struct sig_Allocator* allocator, - struct sig_daisy_GateIn* self); - - -struct sig_daisy_GateOut_Inputs { - float_array_ptr source; -}; - -struct sig_daisy_GateOut { - struct sig_dsp_Signal signal; - struct sig_daisy_CV_Parameters parameters; - struct sig_daisy_GateOut_Inputs inputs; - struct sig_dsp_Signal_SingleMonoOutput outputs; - struct sig_daisy_Host* host; -}; - -struct sig_daisy_GateOut* sig_daisy_GateOut_new( - struct sig_Allocator* allocator, - struct sig_SignalContext* context, - struct sig_daisy_Host* host); -void sig_daisy_GateOut_init(struct sig_daisy_GateOut* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host); -void sig_daisy_GateOut_generate(void* signal); -void sig_daisy_GateOut_destroy(struct sig_Allocator* allocator, - struct sig_daisy_GateOut* self); - - -struct sig_daisy_CVIn { - struct sig_dsp_Signal signal; - struct sig_daisy_CV_Parameters parameters; - struct sig_dsp_Signal_SingleMonoOutput outputs; - struct sig_daisy_Host* host; -}; - -struct sig_daisy_CVIn* sig_daisy_CVIn_new(struct sig_Allocator* allocator, - struct sig_SignalContext* context, struct sig_daisy_Host* host); -void sig_daisy_CVIn_init(struct sig_daisy_CVIn* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host); -void sig_daisy_CVIn_generate(void* signal); -void sig_daisy_CVIn_destroy(struct sig_Allocator* allocator, - struct sig_daisy_CVIn* self); - -struct sig_daisy_FilteredCVIn_Parameters { - float scale; - float offset; - int control; - float time; -}; - -struct sig_daisy_FilteredCVIn { - struct sig_dsp_Signal signal; - struct sig_daisy_FilteredCVIn_Parameters parameters; - struct sig_dsp_Signal_SingleMonoOutput outputs; - struct sig_daisy_Host* host; - struct sig_daisy_CVIn* cvIn; - struct sig_dsp_Smooth* filter; -}; - -struct sig_daisy_FilteredCVIn* sig_daisy_FilteredCVIn_new( - struct sig_Allocator* allocator, struct sig_SignalContext* context, - struct sig_daisy_Host* host); -void sig_daisy_FilteredCVIn_init(struct sig_daisy_FilteredCVIn* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host); -void sig_daisy_FilteredCVIn_generate(void* signal); -void sig_daisy_FilteredCVIn_destroy(struct sig_Allocator* allocator, - struct sig_daisy_FilteredCVIn* self); - - -struct sig_daisy_VOctCVIn_Parameters { - float scale; - float offset; - int control; - float middleFreq; -}; - -struct sig_daisy_VOctCVIn { - struct sig_dsp_Signal signal; - struct sig_daisy_VOctCVIn_Parameters parameters; - struct sig_dsp_Signal_SingleMonoOutput outputs; - struct sig_daisy_Host* host; - struct sig_daisy_CVIn* cvIn; - struct sig_dsp_LinearToFreq* cvConverter; -}; - -struct sig_daisy_VOctCVIn* sig_daisy_VOctCVIn_new( - struct sig_Allocator* allocator, struct sig_SignalContext* context, - struct sig_daisy_Host* host); -void sig_daisy_VOctCVIn_init(struct sig_daisy_VOctCVIn* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host); -void sig_daisy_VOctCVIn_generate(void* signal); -void sig_daisy_VOctCVIn_destroy(struct sig_Allocator* allocator, - struct sig_daisy_VOctCVIn* self); - -// TODO: Replace SwitchIn and TriSwitchIn with a more generic -// implementation that operates on a configurable list of GPIO pins -// (since a three way switch just consists of two separate pins). - -struct sig_daisy_SwitchIn { - struct sig_dsp_Signal signal; - struct sig_daisy_CV_Parameters parameters; - struct sig_dsp_Signal_SingleMonoOutput outputs; - struct sig_daisy_Host* host; - daisy::Switch switchInstance; -}; - -struct sig_daisy_SwitchIn* sig_daisy_SwitchIn_new( - struct sig_Allocator* allocator, struct sig_SignalContext* context, - struct sig_daisy_Host* host); -void sig_daisy_SwitchIn_init(struct sig_daisy_SwitchIn* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host); -void sig_daisy_SwitchIn_generate(void* signal); -void sig_daisy_SwitchIn_destroy(struct sig_Allocator* allocator, - struct sig_daisy_SwitchIn* self); - -struct sig_daisy_TriSwitchIn { - struct sig_dsp_Signal signal; - struct sig_daisy_CV_Parameters parameters; - struct sig_dsp_Signal_SingleMonoOutput outputs; - struct sig_daisy_Host* host; - daisy::Switch switchInstance; -}; - -struct sig_daisy_TriSwitchIn* sig_daisy_TriSwitchIn_new( - struct sig_Allocator* allocator, struct sig_SignalContext* context, - struct sig_daisy_Host* host); -void sig_daisy_TriSwitchIn_init(struct sig_daisy_TriSwitchIn* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host); -void sig_daisy_TriSwitchIn_generate(void* signal); -void sig_daisy_TriSwitchIn_destroy(struct sig_Allocator* allocator, - struct sig_daisy_TriSwitchIn* self); - - -struct sig_daisy_EncoderIn_Outputs { - /** - * @brief The encoder's accumulated value. - * This output tracks the sum of all increment values over time. - */ - float_array_ptr main; - - /** - * @brief The encoder's increment value. - * This output represents the state of change of the encoder: - * -1.0 if the encoder was turned counterclockwise, - * +1.0 if turned clockwise, - * 0.0 if the encoder was not turned - */ - float_array_ptr increment; // The encoder's increment value - - /** - * @brief A gate signal for the encoder's button. - * This output will be > 1.0 if the button is currently pressed, - * and 0.0 it is not. - */ - float_array_ptr button; -}; - -void sig_daisy_EncoderIn_Outputs_newAudioBlocks(struct sig_Allocator* allocator, - struct sig_AudioSettings* audioSettings, - struct sig_daisy_EncoderIn_Outputs* outputs); - -void sig_daisy_EncoderIn_Outputs_destroyAudioBlocks( - struct sig_Allocator* allocator, - struct sig_daisy_EncoderIn_Outputs* outputs); - -struct sig_daisy_EncoderIn { - struct sig_dsp_Signal signal; - struct sig_daisy_CV_Parameters parameters; - struct sig_daisy_EncoderIn_Outputs outputs; - struct sig_daisy_Host* host; - daisy::Encoder encoder; - - float accumulatedValue; -}; - -struct sig_daisy_EncoderIn* sig_daisy_EncoderIn_new( - struct sig_Allocator* allocator, struct sig_SignalContext* context, - struct sig_daisy_Host* host); -void sig_daisy_EncoderIn_init(struct sig_daisy_EncoderIn* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host); -void sig_daisy_EncoderIn_generate(void* signal); -void sig_daisy_EncoderIn_destroy(struct sig_Allocator* allocator, - struct sig_daisy_EncoderIn* self); - - -struct sig_daisy_CVOut_Inputs { - float_array_ptr source; -}; - -// TODO: Should we have a "no output" outputs type, -// or continue with the idea of passing through the input -// for chaining? -struct sig_daisy_CVOut { - struct sig_dsp_Signal signal; - struct sig_daisy_CV_Parameters parameters; - struct sig_daisy_CVOut_Inputs inputs; - struct sig_dsp_Signal_SingleMonoOutput outputs; - struct sig_daisy_Host* host; -}; - -struct sig_daisy_CVOut* sig_daisy_CVOut_new( - struct sig_Allocator* allocator, - struct sig_SignalContext* context, - struct sig_daisy_Host* host); -void sig_daisy_CVOut_init(struct sig_daisy_CVOut* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host); -void sig_daisy_CVOut_generate(void* signal); -void sig_daisy_CVOut_destroy(struct sig_Allocator* allocator, - struct sig_daisy_CVOut* self); - -struct sig_daisy_AudioParameters { - int channel; - float scale; -}; - -struct sig_daisy_AudioOut_Inputs { - float_array_ptr source; -}; - -struct sig_daisy_AudioOut { - struct sig_dsp_Signal signal; - struct sig_daisy_AudioParameters parameters; - struct sig_daisy_AudioOut_Inputs inputs; - struct sig_dsp_Signal_SingleMonoOutput outputs; - struct sig_daisy_Host* host; -}; - -struct sig_daisy_AudioOut* sig_daisy_AudioOut_new( - struct sig_Allocator* allocator, - struct sig_SignalContext* context, - struct sig_daisy_Host* host); -void sig_daisy_AudioOut_init(struct sig_daisy_AudioOut* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host); -void sig_daisy_AudioOut_generate(void* signal); -void sig_daisy_AudioOut_destroy(struct sig_Allocator* allocator, - struct sig_daisy_AudioOut* self); - - -struct sig_daisy_AudioIn { - struct sig_dsp_Signal signal; - struct sig_daisy_AudioParameters parameters; - struct sig_dsp_Signal_SingleMonoOutput outputs; - struct sig_daisy_Host* host; -}; - -struct sig_daisy_AudioIn* sig_daisy_AudioIn_new( - struct sig_Allocator* allocator, - struct sig_SignalContext* context, - struct sig_daisy_Host* host); -void sig_daisy_AudioIn_init(struct sig_daisy_AudioIn* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host); -void sig_daisy_AudioIn_generate(void* signal); -void sig_daisy_AudioIn_destroy(struct sig_Allocator* allocator, - struct sig_daisy_AudioIn* self); +template class DaisyHost { + public: + T device; + struct sig_AudioSettings* audioSettings; + void Init(struct sig_AudioSettings* inAudioSettings, + struct sig_dsp_SignalEvaluator* evaluator) { + audioSettings = inAudioSettings; + device.Init(audioSettings); + } -struct sig_daisy_Encoder { + void Start() { + device.Start(); + device.board.audio.Start(sig_daisy_Host_audioCallback); + } + void Stop() { + device.Stop(); + device.board.audio.Stop(); + } }; }; }; -#endif /* SIGNALETIC_DAISY_HOST_H */ diff --git a/hosts/daisy/include/signaletic-host.h b/hosts/daisy/include/signaletic-host.h new file mode 100644 index 0000000..04af257 --- /dev/null +++ b/hosts/daisy/include/signaletic-host.h @@ -0,0 +1,283 @@ +#ifndef SIGNALETIC_HOST_H +#define SIGNALETIC_HOST_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include // For size_t + +struct sig_host_HardwareInterface; + +typedef void (*sig_host_onEvaluateSignals)( + size_t size, + struct sig_host_HardwareInterface* hardware); + +typedef void (*sig_host_afterEvaluateSignals)( + size_t size, + struct sig_host_HardwareInterface* hardware); + +void sig_host_noOpAudioEventCallback(size_t size, + struct sig_host_HardwareInterface* hardware); + + +struct sig_host_HardwareInterface { + struct sig_dsp_SignalEvaluator* evaluator; + + sig_host_onEvaluateSignals onEvaluateSignals; + sig_host_afterEvaluateSignals afterEvaluateSignals; + + void* userData; + + size_t numAudioInputChannels; + float** audioInputChannels; + + size_t numAudioOutputChannels; + float** audioOutputChannels; + + size_t numADCChannels; + float* adcChannels; + + size_t numDACChannels; + float* dacChannels; + + size_t numGateInputs; + float* gateInputs; + + size_t numGPIOOutputs; + float* gpioOutputs; + + size_t numToggles; + float* toggles; + + size_t numTriSwitches; + float* triSwitches; +}; + +// FIXME: Compiler thinks this variable is unused. +// Maybe because this source file is compiled as C +// and it is used in C++-compiled code? +static struct sig_host_HardwareInterface* sig_host_globalHardwareInstance; + +struct sig_host_CV_Parameters { + float scale; + float offset; + int control; +}; + + +struct sig_host_GateIn { + struct sig_dsp_Signal signal; + struct sig_host_CV_Parameters parameters; + struct sig_dsp_Signal_SingleMonoOutput outputs; + struct sig_host_HardwareInterface* hardware; +}; + +struct sig_host_GateIn* sig_host_GateIn_new( + struct sig_Allocator* allocator, + struct sig_SignalContext* context); +void sig_host_GateIn_init(struct sig_host_GateIn* self, + struct sig_SignalContext* context); +void sig_host_GateIn_generate(void* signal); +void sig_host_GateIn_destroy(struct sig_Allocator* allocator, + struct sig_host_GateIn* self); + +struct sig_host_GateOut_Inputs { + float_array_ptr source; +}; + + +struct sig_host_GateOut { + struct sig_dsp_Signal signal; + struct sig_host_CV_Parameters parameters; + struct sig_host_GateOut_Inputs inputs; + struct sig_dsp_Signal_SingleMonoOutput outputs; + struct sig_host_HardwareInterface* hardware; +}; + +struct sig_host_GateOut* sig_host_GateOut_new( + struct sig_Allocator* allocator, + struct sig_SignalContext* context); +void sig_host_GateOut_init(struct sig_host_GateOut* self, + struct sig_SignalContext* context); +void sig_host_GateOut_generate(void* signal); +void sig_host_GateOut_destroy(struct sig_Allocator* allocator, + struct sig_host_GateOut* self); + + +struct sig_host_CVIn { + struct sig_dsp_Signal signal; + struct sig_host_CV_Parameters parameters; + struct sig_dsp_Signal_SingleMonoOutput outputs; + struct sig_host_HardwareInterface* hardware; +}; + +struct sig_host_CVIn* sig_host_CVIn_new(struct sig_Allocator* allocator, + struct sig_SignalContext* context); +void sig_host_CVIn_init(struct sig_host_CVIn* self, + struct sig_SignalContext* context); +void sig_host_CVIn_generate(void* signal); +void sig_host_CVIn_destroy(struct sig_Allocator* allocator, + struct sig_host_CVIn* self); + + +struct sig_host_FilteredCVIn_Parameters { + float scale; + float offset; + int control; + float time; +}; + +struct sig_host_FilteredCVIn { + struct sig_dsp_Signal signal; + struct sig_host_FilteredCVIn_Parameters parameters; + struct sig_dsp_Signal_SingleMonoOutput outputs; + struct sig_host_HardwareInterface* hardware; + struct sig_host_CVIn* cvIn; + struct sig_dsp_Smooth* filter; +}; + +struct sig_host_FilteredCVIn* sig_host_FilteredCVIn_new( + struct sig_Allocator* allocator, struct sig_SignalContext* context); +void sig_host_FilteredCVIn_init(struct sig_host_FilteredCVIn* self, + struct sig_SignalContext* context); +void sig_host_FilteredCVIn_generate(void* signal); +void sig_host_FilteredCVIn_destroy(struct sig_Allocator* allocator, + struct sig_host_FilteredCVIn* self); + + +struct sig_host_VOctCVIn_Parameters { + float scale; + float offset; + int control; + float middleFreq; +}; + +struct sig_host_VOctCVIn { + struct sig_dsp_Signal signal; + struct sig_host_VOctCVIn_Parameters parameters; + struct sig_dsp_Signal_SingleMonoOutput outputs; + struct sig_host_HardwareInterface* hardware; + struct sig_host_CVIn* cvIn; + struct sig_dsp_LinearToFreq* cvConverter; +}; + +struct sig_host_VOctCVIn* sig_host_VOctCVIn_new( + struct sig_Allocator* allocator, struct sig_SignalContext* context); +void sig_host_VOctCVIn_init(struct sig_host_VOctCVIn* self, + struct sig_SignalContext* context); +void sig_host_VOctCVIn_generate(void* signal); +void sig_host_VOctCVIn_destroy(struct sig_Allocator* allocator, + struct sig_host_VOctCVIn* self); + + +struct sig_host_CVOut_Inputs { + float_array_ptr source; +}; + +// TODO: Should we have a "no output" outputs type, +// or continue with the idea of passing through the input +// for chaining? +struct sig_host_CVOut { + struct sig_dsp_Signal signal; + struct sig_host_CV_Parameters parameters; + struct sig_host_CVOut_Inputs inputs; + struct sig_dsp_Signal_SingleMonoOutput outputs; + struct sig_host_HardwareInterface* hardware; +}; + +struct sig_host_CVOut* sig_host_CVOut_new( + struct sig_Allocator* allocator, + struct sig_SignalContext* context); +void sig_host_CVOut_init(struct sig_host_CVOut* self, + struct sig_SignalContext* context); +void sig_host_CVOut_generate(void* signal); +void sig_host_CVOut_destroy(struct sig_Allocator* allocator, + struct sig_host_CVOut* self); + + +struct sig_host_AudioParameters { + int channel; + float scale; +}; + +struct sig_host_AudioOut_Inputs { + float_array_ptr source; +}; + +struct sig_host_AudioOut { + struct sig_dsp_Signal signal; + struct sig_host_AudioParameters parameters; + struct sig_host_AudioOut_Inputs inputs; + struct sig_dsp_Signal_SingleMonoOutput outputs; + struct sig_host_HardwareInterface* hardware; +}; + +struct sig_host_AudioOut* sig_host_AudioOut_new( + struct sig_Allocator* allocator, + struct sig_SignalContext* context); +void sig_host_AudioOut_init(struct sig_host_AudioOut* self, + struct sig_SignalContext* context); +void sig_host_AudioOut_generate(void* signal); +void sig_host_AudioOut_destroy(struct sig_Allocator* allocator, + struct sig_host_AudioOut* self); + + +struct sig_host_AudioIn { + struct sig_dsp_Signal signal; + struct sig_host_AudioParameters parameters; + struct sig_dsp_Signal_SingleMonoOutput outputs; + struct sig_host_HardwareInterface* hardware; +}; + +struct sig_host_AudioIn* sig_host_AudioIn_new( + struct sig_Allocator* allocator, + struct sig_SignalContext* context); +void sig_host_AudioIn_init(struct sig_host_AudioIn* self, + struct sig_SignalContext* context); +void sig_host_AudioIn_generate(void* signal); +void sig_host_AudioIn_destroy(struct sig_Allocator* allocator, + struct sig_host_AudioIn* self); + + + +// TODO: Replace SwitchIn and TriSwitchIn with a more generic +// implementation that operates on a configurable list of GPIO pins +// (since a three way switch just consists of two separate pins). + +struct sig_host_SwitchIn { + struct sig_dsp_Signal signal; + struct sig_host_CV_Parameters parameters; + struct sig_dsp_Signal_SingleMonoOutput outputs; + struct sig_host_HardwareInterface* hardware; +}; + +struct sig_host_SwitchIn* sig_host_SwitchIn_new( + struct sig_Allocator* allocator, struct sig_SignalContext* context); +void sig_host_SwitchIn_init(struct sig_host_SwitchIn* self, + struct sig_SignalContext* context); +void sig_host_SwitchIn_generate(void* signal); +void sig_host_SwitchIn_destroy(struct sig_Allocator* allocator, + struct sig_host_SwitchIn* self); + +struct sig_host_TriSwitchIn { + struct sig_dsp_Signal signal; + struct sig_host_CV_Parameters parameters; + struct sig_dsp_Signal_SingleMonoOutput outputs; + struct sig_host_HardwareInterface* hardware; +}; + +struct sig_host_TriSwitchIn* sig_host_TriSwitchIn_new( + struct sig_Allocator* allocator, struct sig_SignalContext* context); +void sig_host_TriSwitchIn_init(struct sig_host_TriSwitchIn* self, + struct sig_SignalContext* context); +void sig_host_TriSwitchIn_generate(void* signal); +void sig_host_TriSwitchIn_destroy(struct sig_Allocator* allocator, + struct sig_host_TriSwitchIn* self); + +#ifdef __cplusplus +} +#endif + +#endif /* SIGNALETIC_HOST_H */ diff --git a/hosts/daisy/src/daisy-bluemchen-host.cpp b/hosts/daisy/src/daisy-bluemchen-host.cpp deleted file mode 100644 index 548ee9b..0000000 --- a/hosts/daisy/src/daisy-bluemchen-host.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include "../include/daisy-bluemchen-host.h" - -struct sig_daisy_Host_BoardConfiguration sig_daisy_BluemchenConfig = { - .numAudioInputChannels = 2, - .numAudioOutputChannels = 2, - .numAnalogInputs = sig_daisy_Bluemchen_NUM_ANALOG_INPUTS, - .numAnalogOutputs = sig_daisy_Bluemchen_NUM_ANALOG_OUTPUTS, - .numGateInputs = sig_daisy_Bluemchen_NUM_GATE_INPUTS, - .numGateOutputs = sig_daisy_Bluemchen_NUM_GATE_OUTPUTS, - .numSwitches = sig_daisy_Bluemchen_NUM_SWITCHES, - .numTriSwitches = sig_daisy_Bluemchen_NUM_TRI_SWITCHES, - .numEncoders = sig_daisy_Bluemchen_NUM_ENCODERS -}; - -struct sig_daisy_Host_BoardConfiguration sig_daisy_NehcmeulbConfig = { - .numAudioInputChannels = 2, - .numAudioOutputChannels = 2, - .numAnalogInputs = sig_daisy_Nehcmeulb_NUM_ANALOG_INPUTS, - .numAnalogOutputs = sig_daisy_Nehcmeulb_NUM_ANALOG_OUTPUTS, - .numGateInputs = sig_daisy_Nehcmeulb_NUM_GATE_INPUTS, - .numGateOutputs = sig_daisy_Nehcmeulb_NUM_GATE_OUTPUTS, - .numSwitches = sig_daisy_Nehcmeulb_NUM_SWITCHES, - .numTriSwitches = sig_daisy_Nehcmeulb_NUM_TRI_SWITCHES, - .numEncoders = sig_daisy_Nehcmeulb_NUM_ENCODERS -}; - -struct sig_daisy_Host_Impl sig_daisy_BluemchenHostImpl = { - .getControlValue = sig_daisy_HostImpl_processControlValue, - .setControlValue = sig_daisy_BluemchenHostImpl_setControlValue, - .getGateValue = sig_daisy_HostImpl_noOpGetControl, - .setGateValue = sig_daisy_HostImpl_noOpSetControl, - .getSwitchValue = sig_daisy_HostImpl_noOpGetControl, - .getTriSwitchValue = sig_daisy_HostImpl_noOpGetControl, - .getEncoderIncrement = sig_daisy_HostImpl_getEncoderIncrement, - .getEncoderButtonValue = sig_daisy_HostImpl_processEncoderButtonValue, - .start = sig_daisy_BluemchenHostImpl_start, - .stop = sig_daisy_BluemchenHostImpl_stop -}; - -void sig_daisy_BluemchenHostImpl_setControlValue(struct sig_daisy_Host* host, - int control, float value) { - if (control > -1 && control < host->board.config->numAnalogOutputs) { - daisy::DacHandle::Channel channel = - static_cast(control); - host->board.dac->WriteValue(channel, sig_unipolarToUint12(value)); - } -} - -void sig_daisy_BluemchenHostImpl_start(struct sig_daisy_Host* host) { - kxmx::Bluemchen* bluemchen = static_cast( - host->board.boardInstance); - bluemchen->StartAdc(); - bluemchen->StartAudio(sig_daisy_Host_audioCallback); -} - -void sig_daisy_BluemchenHostImpl_stop(struct sig_daisy_Host* host) { - kxmx::Bluemchen* bluemchen = static_cast( - host->board.boardInstance); - bluemchen->StopAudio(); -} - -struct sig_daisy_Host* sig_daisy_BluemchenHost_new( - struct sig_Allocator* allocator, - struct sig_AudioSettings* audioSettings, - kxmx::Bluemchen* bluemchen, - struct sig_dsp_SignalEvaluator* evaluator) { - struct sig_daisy_Host* self = sig_MALLOC(allocator, struct sig_daisy_Host); - sig_daisy_BluemchenHost_init(self, - audioSettings, - &sig_daisy_BluemchenConfig, - bluemchen, - evaluator); - - return self; -} - -struct sig_daisy_Host* sig_daisy_NehcmeulbHost_new( - struct sig_Allocator* allocator, - struct sig_AudioSettings* audioSettings, - kxmx::Bluemchen* bluemchen, - struct sig_dsp_SignalEvaluator* evaluator) { - struct sig_daisy_Host* self = sig_MALLOC(allocator, struct sig_daisy_Host); - sig_daisy_BluemchenHost_init(self, - audioSettings, - &sig_daisy_NehcmeulbConfig, - bluemchen, - evaluator); - - return self; -} - -void sig_daisy_BluemchenHost_Board_init( - struct sig_daisy_Host_Board* self, - kxmx::Bluemchen* bluemchen, - struct sig_daisy_Host_BoardConfiguration* boardConfig) { - self->boardInstance = (void*) bluemchen; - self->config = boardConfig; - self->analogControls = &bluemchen->controls[0]; - self->dac = &bluemchen->seed.dac; - // Bluemchen has no gates. - self->gateInputs[0] = NULL; - self->gateInputs[1] = NULL; - self->gateOutputs[0] = NULL; - self->gateOutputs[1] = NULL; - self->encoders[0] = &bluemchen->encoder; -} - - -void sig_daisy_BluemchenHost_init( - struct sig_daisy_Host* self, - struct sig_AudioSettings* audioSettings, - struct sig_daisy_Host_BoardConfiguration* boardConfig, - kxmx::Bluemchen* bluemchen, - struct sig_dsp_SignalEvaluator* evaluator) { - self->impl = &sig_daisy_BluemchenHostImpl; - self->audioSettings = audioSettings; - self->evaluator = evaluator; - - bluemchen->Init(); - daisy::SaiHandle::Config::SampleRate sampleRate = - sig_daisy_Host_convertSampleRate(audioSettings->sampleRate); - bluemchen->SetAudioSampleRate(sampleRate); - bluemchen->SetAudioBlockSize(audioSettings->blockSize); - sig_daisy_BluemchenHost_Board_init(&self->board, bluemchen, boardConfig); - sig_daisy_Host_init(self); -} - -void sig_daisy_BluemchenHost_destroy(struct sig_Allocator* allocator, - struct sig_daisy_Host* self) { - allocator->impl->free(allocator, self); -} - -void sig_daisy_NehcmeulbHost_destroy(struct sig_Allocator* allocator, - struct sig_daisy_Host* self) { - sig_daisy_BluemchenHost_destroy(allocator, self); -} diff --git a/hosts/daisy/src/daisy-patch-sm-host.cpp b/hosts/daisy/src/daisy-patch-sm-host.cpp deleted file mode 100644 index 1ceb12d..0000000 --- a/hosts/daisy/src/daisy-patch-sm-host.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include "../include/daisy-patch-sm-host.h" - -struct sig_daisy_Host_BoardConfiguration sig_daisy_PatchSMConfig = { - .numAudioInputChannels = 2, - .numAudioOutputChannels = 2, - .numAnalogInputs = sig_daisy_PatchSM_NUM_ANALOG_INPUTS, - .numAnalogOutputs = sig_daisy_PatchSM_NUM_ANALOG_OUTPUTS, - .numGateInputs = sig_daisy_PatchSM_NUM_GATE_INPUTS, - .numGateOutputs = sig_daisy_PatchSM_NUM_GATE_OUTPUTS, - .numSwitches = sig_daisy_PatchSM_NUM_SWITCHES, - .numTriSwitches = sig_daisy_PatchSM_NUM_TRI_SWITCHES, - .numEncoders = sig_daisy_PatchSM_NUM_ENCODERS -}; - -struct sig_daisy_Host_BoardConfiguration sig_daisy_PatchInitConfig = { - .numAudioInputChannels = 2, - .numAudioOutputChannels = 2, - .numAnalogInputs = sig_daisy_PatchInit_NUM_ANALOG_INPUTS, - .numAnalogOutputs = sig_daisy_PatchInit_NUM_ANALOG_OUTPUTS, - .numGateInputs = sig_daisy_PatchInit_NUM_GATE_INPUTS, - .numGateOutputs = sig_daisy_PatchInit_NUM_GATE_OUTPUTS, - .numSwitches = sig_daisy_PatchInit_NUM_SWITCHES, - .numTriSwitches = sig_daisy_PatchInit_NUM_TRI_SWITCHES, - .numEncoders = sig_daisy_PatchInit_NUM_ENCODERS -}; - -struct sig_daisy_Host_Impl sig_daisy_PatchSMHostImpl = { - .getControlValue = sig_daisy_HostImpl_processControlValue, - .setControlValue = sig_daisy_PatchSMHostImpl_setControlValue, - .getGateValue = sig_daisy_HostImpl_getGateValue, - .setGateValue = sig_daisy_HostImpl_setGateValue, - .getSwitchValue = sig_daisy_HostImpl_getSwitchValue, - .getTriSwitchValue = sig_daisy_HostImpl_noOpGetControl, - .getEncoderIncrement = sig_daisy_HostImpl_noOpGetControl, - .getEncoderButtonValue = sig_daisy_HostImpl_noOpGetControl, - .start = sig_daisy_PatchSMHostImpl_start, - .stop = sig_daisy_PatchSMHostImpl_stop -}; - -void sig_daisy_PatchSMHostImpl_start(struct sig_daisy_Host* host) { - daisy::patch_sm::DaisyPatchSM* patchSM = - static_cast(host->board.boardInstance); - patchSM->StartAdc(); - patchSM->StartAudio(sig_daisy_Host_audioCallback); -} - -void sig_daisy_PatchSMHostImpl_stop(struct sig_daisy_Host* host) { - daisy::patch_sm::DaisyPatchSM* patchSM = - static_cast(host->board.boardInstance); - patchSM->StopAudio(); -} - -// TODO: Implement a generic version of this that can work -// with any Daisy board that has DMA enabled. -void sig_daisy_PatchSMHostImpl_setControlValue(struct sig_daisy_Host* host, - int control, float value) { - daisy::patch_sm::DaisyPatchSM* patchSM = - static_cast(host->board.boardInstance); - - float rectified = fabsf(value); - float scaled = rectified * 5.0f; - - // Controls are off by one because 0 signifies both in the Daisy API. - // We don't expose this to Signaletic users, because it is awkward. - patchSM->WriteCvOut(control, scaled); -} - -struct sig_daisy_Host* sig_daisy_PatchSMHost_new( - struct sig_Allocator* allocator, - struct sig_AudioSettings* audioSettings, - daisy::patch_sm::DaisyPatchSM* patchSM, - struct sig_dsp_SignalEvaluator* evaluator) { - struct sig_daisy_Host* self = sig_MALLOC(allocator, - struct sig_daisy_Host); - sig_daisy_PatchSMHost_init(self, audioSettings, patchSM, evaluator); - - return self; -} - -void sig_daisy_PatchSMHost_Board_init(struct sig_daisy_Host_Board* self, - daisy::patch_sm::DaisyPatchSM* patchSM) { - self->config = &sig_daisy_PatchSMConfig; - self->analogControls = &patchSM->controls[0]; - self->dac = &patchSM->dac; - self->gateInputs[0] = &patchSM->gate_in_1; - self->gateInputs[1] = &patchSM->gate_in_2; - self->gateOutputs[0] = &patchSM->gate_out_1; - self->gateOutputs[1] = &patchSM->gate_out_2; - self->switches[0].Init(patchSM->B7, patchSM->AudioCallbackRate()); - self->switches[1].Init(patchSM->B8, patchSM->AudioCallbackRate()); - self->boardInstance = (void*) patchSM; -} - -void sig_daisy_PatchSMHost_init(struct sig_daisy_Host* self, - struct sig_AudioSettings* audioSettings, - daisy::patch_sm::DaisyPatchSM* patchSM, - struct sig_dsp_SignalEvaluator* evaluator) { - self->impl = &sig_daisy_PatchSMHostImpl; - self->audioSettings = audioSettings; - self->evaluator = evaluator; - - patchSM->Init(); - patchSM->SetAudioBlockSize(audioSettings->blockSize); - patchSM->SetAudioSampleRate(audioSettings->sampleRate); - sig_daisy_PatchSMHost_Board_init(&self->board, patchSM); - sig_daisy_Host_init(self); -} - -void sig_daisy_PatchSMHost_destroy(struct sig_Allocator* allocator, - struct sig_daisy_Host* self) { - allocator->impl->free(allocator, self); -} diff --git a/hosts/daisy/src/lichen-medium-host.cpp b/hosts/daisy/src/lichen-medium-host.cpp deleted file mode 100644 index 7cedbed..0000000 --- a/hosts/daisy/src/lichen-medium-host.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "../include/daisy-patch-sm-host.h" -#include "../include/lichen-medium-host.h" diff --git a/hosts/daisy/src/sig-daisy-patch-sm.cpp b/hosts/daisy/src/sig-daisy-patch-sm.cpp index b691adf..59f4706 100644 --- a/hosts/daisy/src/sig-daisy-patch-sm.cpp +++ b/hosts/daisy/src/sig-daisy-patch-sm.cpp @@ -6,68 +6,7 @@ using namespace daisy; uint16_t DMA_BUFFER_MEM_SECTION sig_daisy_patch_sm_dac_buffer[2][48]; uint16_t sig_daisy_patch_sm_dac_output[2]; -// TODO: If the Daisy toolchain ever upgrades to C++17, -// these definitions shouldn't be needed. -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_NONE; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_A1; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_A2; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_A3; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_A4; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_A5; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_A6; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_A7; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_A8; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_A9; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_A10; - -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_B1; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_B2; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_B3; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_B4; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_B5; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_B6; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_B7; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_B8; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_B9; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_B10; - -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_C1; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_C2; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_C3; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_C4; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_C5; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_C6; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_C7; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_C8; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_C9; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_C10; - -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_D1; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_D2; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_D3; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_D4; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_D5; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_D6; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_D7; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_D8; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_D9; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_D10; - -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_CV_1; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_CV_2; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_CV_3; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_CV_4; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_CV_5; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_CV_6; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_CV_7; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_CV_8; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_ADC_9; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_ADC_10; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_ADC_11; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_ADC_12; -constexpr dsy_gpio_pin sig::libdaisy::PatchSM::PIN_USER_LED; - -void sig::libdaisy::PatchSM::Init(size_t blockSize, float sampleRate) { +void sig::libdaisy::patchsm::PatchSMBoard::Init(size_t blockSize, float sampleRate) { dac_running_ = false; dac_buffer_size_ = 48; sig_daisy_patch_sm_dac_output[0] = 0; @@ -149,7 +88,7 @@ void sig::libdaisy::PatchSM::Init(size_t blockSize, float sampleRate) { } -void sig::libdaisy::PatchSM::InitDac() { +void sig::libdaisy::patchsm::PatchSMBoard::InitDac() { DacHandle::Config dac_config; dac_config.mode = DacHandle::Mode::DMA; dac_config.bitdepth = DacHandle::BitDepth:: @@ -160,19 +99,20 @@ void sig::libdaisy::PatchSM::InitDac() { dac.Init(dac_config); } -void sig::libdaisy::PatchSM::StartDac(DacHandle::DacCallback callback) { +void sig::libdaisy::patchsm::PatchSMBoard::StartDac(DacHandle::DacCallback callback) { if (dac_running_) { dac.Stop(); } - dac.Start(dacBuffer[0], + dac.Start( + dacBuffer[0], dacBuffer[1], dac_buffer_size_, callback == nullptr ? DefaultDacCallback : callback); dac_running_ = true; } -void sig::libdaisy::PatchSM::DefaultDacCallback(uint16_t **output, +void sig::libdaisy::patchsm::PatchSMBoard::DefaultDacCallback(uint16_t **output, size_t size) { for (size_t i = 0; i < size; i++) { output[0][i] = sig_daisy_patch_sm_dac_output[0]; diff --git a/hosts/daisy/src/sig-daisy-seed.cpp b/hosts/daisy/src/sig-daisy-seed.cpp index 1fdd8a5..a496451 100644 --- a/hosts/daisy/src/sig-daisy-seed.cpp +++ b/hosts/daisy/src/sig-daisy-seed.cpp @@ -6,7 +6,7 @@ extern "C" { using namespace daisy; -void sig::libdaisy::Seed::Init(size_t blockSize, float sampleRate) { +void sig::libdaisy::seed::SeedBoard::Init(size_t blockSize, float sampleRate) { System::Config syscfg; syscfg.Boost(); @@ -22,7 +22,7 @@ void sig::libdaisy::Seed::Init(size_t blockSize, float sampleRate) { qspi_config.pin_config.ncs = dsy_pin(DSY_GPIOG, 6); // Configure the built-in GPIOs. - userLED.pin = SEED_PIN_USER_LED; + userLED.pin = PIN_USER_LED; userLED.mode = DSY_GPIO_MODE_OUTPUT_PP; auto memory = System::GetProgramMemoryRegion(); @@ -45,7 +45,8 @@ void sig::libdaisy::Seed::Init(size_t blockSize, float sampleRate) { InitAudio(blockSize, sampleRate); } -void sig::libdaisy::Seed::InitAudio(size_t blockSize, float sampleRate) { +void sig::libdaisy::seed::SeedBoard::InitAudio(size_t blockSize, + float sampleRate) { // SAI1 -- Peripheral // Configure SaiHandle::Config sai_config; @@ -109,7 +110,8 @@ void sig::libdaisy::Seed::InitAudio(size_t blockSize, float sampleRate) { callbackRate = audio.GetSampleRate() / audio.GetConfig().blocksize; } -void sig::libdaisy::Seed::InitDAC(daisy::DacHandle::Channel channel) { +void sig::libdaisy::seed::SeedBoard::InitDAC( + daisy::DacHandle::Channel channel) { // TODO: This is sourced from the kxmx_Bluemchen. // Is DMA-based DAC access an option instead of polling? daisy::DacHandle::Config cfg; @@ -121,7 +123,8 @@ void sig::libdaisy::Seed::InitDAC(daisy::DacHandle::Channel channel) { dac.WriteValue(daisy::DacHandle::Channel::BOTH, 0); } -sig::libdaisy::Seed::BoardVersion sig::libdaisy::Seed::CheckBoardVersion() { +sig::libdaisy::seed::SeedBoard::BoardVersion + sig::libdaisy::seed::SeedBoard::CheckBoardVersion() { /** Version Checks: * * Fall through is Daisy Seed v1 (aka Daisy Seed rev4) * * PD3 tied to gnd is Daisy Seed v1.1 (aka Daisy Seed rev5) diff --git a/hosts/daisy/src/signaletic-daisy-host.cpp b/hosts/daisy/src/signaletic-daisy-host.cpp index 140d784..13e6687 100644 --- a/hosts/daisy/src/signaletic-daisy-host.cpp +++ b/hosts/daisy/src/signaletic-daisy-host.cpp @@ -1,762 +1,19 @@ #include "../include/signaletic-daisy-host.h" -struct sig_daisy_Host* sig_daisy_Host_globalHost = NULL; - -daisy::SaiHandle::Config::SampleRate sig_daisy_Host_convertSampleRate( - float sampleRate) { - // Copy-pasted from libdaisy - // because the Seed has a completely different API - // for setting sample rates than the PatchSM. - // Srsly, Electrosmith?! - // https://github.com/electro-smith/libDaisy/blob/v5.3.0/src/daisy_patch_sm.cpp#L383-L409 - daisy::SaiHandle::Config::SampleRate sai_sr; - - switch(int(sampleRate)) { - case 8000: - sai_sr = daisy::SaiHandle::Config::SampleRate::SAI_8KHZ; - break; - case 16000: - sai_sr = daisy::SaiHandle::Config::SampleRate::SAI_16KHZ; - break; - case 32000: - sai_sr = daisy::SaiHandle::Config::SampleRate::SAI_32KHZ; - break; - case 48000: - sai_sr = daisy::SaiHandle::Config::SampleRate::SAI_48KHZ; - break; - case 96000: - sai_sr = daisy::SaiHandle::Config::SampleRate::SAI_96KHZ; - break; - default: - sai_sr = daisy::SaiHandle::Config::SampleRate::SAI_48KHZ; - break; - } - - return sai_sr; -} - -// TODO: userData is shared, but the API makes it seem as if -// different pointers could be provided for each of these callbacks. -// We either need to support two pointers to user data, or provide -// a different API for registering a single shared userData -// pointer for all callbacks. -void sig_daisy_Host_addOnEvaluateSignalsListener( - struct sig_daisy_Host* self, - sig_daisy_Host_onEvaluateSignals listener, - void* userData) { - self->onEvaluateSignals = listener; - self->userData = userData; -} - -void sig_daisy_Host_addAfterEvaluateSignalsListener( - struct sig_daisy_Host* self, - sig_daisy_Host_onEvaluateSignals listener, - void* userData) { - self->afterEvaluateSignals = listener; - self->userData = userData; -} - -void sig_daisy_Host_registerGlobalHost(struct sig_daisy_Host* host) { - if (sig_daisy_Host_globalHost != NULL && - sig_daisy_Host_globalHost != host) { - // TODO: Clean up memory leak here, - // or throw an error and do nothing if this is called more than once. - } - - sig_daisy_Host_globalHost = host; -} - -void sig_daisy_Host_noOpAudioCallback(daisy::AudioHandle::InputBuffer in, - daisy::AudioHandle::OutputBuffer out, size_t size, - struct sig_daisy_Host* host, void* userData) {} - -void sig_daisy_Host_init(struct sig_daisy_Host* self) { - self->onEvaluateSignals = sig_daisy_Host_noOpAudioCallback; - self->afterEvaluateSignals = sig_daisy_Host_noOpAudioCallback; -}; - void sig_daisy_Host_audioCallback(daisy::AudioHandle::InputBuffer in, daisy::AudioHandle::OutputBuffer out, size_t size) { - struct sig_daisy_Host* self = sig_daisy_Host_globalHost; - self->board.audioInputs = in; - self->board.audioOutputs = out; + struct sig_host_HardwareInterface* hardware = + sig_host_globalHardwareInstance; + hardware->audioInputChannels = (float**) in; + hardware->audioOutputChannels = (float**) out; // Invoke callback before evaluating the signal graph. - sig_daisy_Host_globalHost->onEvaluateSignals(in, out, size, - self, self->userData); + hardware->onEvaluateSignals(size, hardware); // Evaluate the signal graph. - struct sig_dsp_SignalEvaluator* evaluator = - sig_daisy_Host_globalHost->evaluator; + struct sig_dsp_SignalEvaluator* evaluator = hardware->evaluator; evaluator->evaluate(evaluator); // Invoke the after callback. - sig_daisy_Host_globalHost->afterEvaluateSignals(in, out, size, self, - self->userData); -} - - -float sig_daisy_HostImpl_noOpGetControl(struct sig_daisy_Host* host, - int control) { - return 0.0f; -} - -void sig_daisy_HostImpl_noOpSetControl(struct sig_daisy_Host* host, - int control, float value) {} - -float sig_daisy_HostImpl_processControlValue(struct sig_daisy_Host* host, - int control) { - return control > -1 && control < host->board.config->numAnalogInputs ? - host->board.analogControls[control].Process() : 0.0f; -} - -void sig_daisy_HostImpl_setControlValue(struct sig_daisy_Host* host, - int control, float value) { - if (control > -1 && control < host->board.config->numAnalogOutputs) { - sig_daisy_Host_writeValueToDACPolling(host->board.dac, control, value); - } -} - -void sig_daisy_Host_writeValueToDACPolling(daisy::DacHandle* dac, - int control, float value) { - daisy::DacHandle::Channel channel = static_cast( - control); - dac->WriteValue(channel, sig_bipolarToInvUint12(value)); -} - -float sig_daisy_HostImpl_getGateValue(struct sig_daisy_Host* host, - int control) { - if (control < 0 || control > host->board.config->numGateInputs) { - return 0.0f; - } - - daisy::GateIn* gate = host->board.gateInputs[control]; - // The gate is inverted (i.e. true when voltage is 0V). - // See https://electro-smith.github.io/libDaisy/classdaisy_1_1_gate_in.html#a08f75c6621307249de3107df96cfab2d - float sample = gate->State() ? 0.0f : 1.0f; - - return sample; -} - -void sig_daisy_HostImpl_setGateValue(struct sig_daisy_Host* host, - int control, float value) { - if (control < 0 || control >= host->board.config->numGateOutputs) { - return; - } - - dsy_gpio* gate = host->board.gateOutputs[control]; - dsy_gpio_write(gate, value > 0.0f ? 0 : 1); -} - -float sig_daisy_HostImpl_getSwitchValue(struct sig_daisy_Host* host, - int control) { - float sample = 0.0f; - if (control > -1 && control < host->board.config->numSwitches) { - daisy::Switch* sw = &(host->board.switches[control]); - sw->Debounce(); - sample = (float) sw->Pressed(); - } - - return sample; -} - -float sig_daisy_HostImpl_getTriSwitchValue(struct sig_daisy_Host* host, - int control) { - float sample = 0.0f; - if (control > -1 && control < host->board.config->numTriSwitches) { - daisy::Switch3* sw = &(host->board.triSwitches[control]); - int rawValue = sw->Read(); - // Left/up is mapped to +1, centre is 0, down/right is -1. - sample = rawValue == sw->POS_UP ? 1.0f : rawValue == sw->POS_DOWN ? - -1.0f : 0.0f; - } - - return sample; -} - - -float sig_daisy_HostImpl_getEncoderIncrement(struct sig_daisy_Host* host, - int control) { - float increment = 0.0f; - - if (control > -1 && control < host->board.config->numEncoders) { - daisy::Encoder* enc = host->board.encoders[control]; - increment = (float) enc->Increment(); - } - - return increment; -} - -// TODO: Encoders have an underlying daisy::Switch object, so we could -// remove this in favour of the getSwitchValue impl if we had some way of -// indexing an encoder within the switch array. -float sig_daisy_HostImpl_processEncoderButtonValue(struct sig_daisy_Host* host, - int control) { - bool isPressed = false; - - if (control > -1 && control < host->board.config->numEncoders) { - daisy::Encoder* enc = host->board.encoders[control]; - // TODO: We need to separate the evaluation of controls - // from value retrieval so that multiple instances that are - // bound to a signal control won't cause time to "tick" too fast. - enc->Debounce(); - isPressed = enc->Pressed(); - } - - return isPressed ? 1.0f : 0.0f; -} - -struct sig_daisy_GateIn* sig_daisy_GateIn_new( - struct sig_Allocator* allocator, - struct sig_SignalContext* context, - struct sig_daisy_Host* host) { - struct sig_daisy_GateIn* self = sig_MALLOC(allocator, - struct sig_daisy_GateIn); - sig_daisy_GateIn_init(self, context, host); - sig_dsp_Signal_SingleMonoOutput_newAudioBlocks(allocator, - context->audioSettings, &self->outputs); - - return self; -} - -void sig_daisy_GateIn_init(struct sig_daisy_GateIn* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host) { - sig_dsp_Signal_init(self, context, *sig_daisy_GateIn_generate); - self->host = host; - self->parameters = { - .scale = 1.0f, - .offset = 0.0f, - .control = 0 - }; -} - -void sig_daisy_GateIn_generate(void* signal) { - struct sig_daisy_GateIn* self = (struct sig_daisy_GateIn*) signal; - struct sig_daisy_Host* host = self->host; - float scale = self->parameters.scale; - float offset = self->parameters.offset; - int control = self->parameters.control; - - for (size_t i = 0; i < self->signal.audioSettings->blockSize; i++) { - // TODO: Should this only be called at the block rate? - float sample = host->impl->getGateValue(host, control); - FLOAT_ARRAY(self->outputs.main)[i] = sample * scale + offset; - } -} - -void sig_daisy_GateIn_destroy(struct sig_Allocator* allocator, - struct sig_daisy_GateIn* self) { - sig_dsp_Signal_SingleMonoOutput_destroyAudioBlocks(allocator, - &self->outputs); - sig_dsp_Signal_destroy(allocator, (void*) self); -} - - -struct sig_daisy_GateOut* sig_daisy_GateOut_new( - struct sig_Allocator* allocator, - struct sig_SignalContext* context, - struct sig_daisy_Host* host) { - struct sig_daisy_GateOut* self = sig_MALLOC(allocator, - struct sig_daisy_GateOut); - sig_daisy_GateOut_init(self, context, host); - sig_dsp_Signal_SingleMonoOutput_newAudioBlocks(allocator, - context->audioSettings, &self->outputs); - - return self; -} - -void sig_daisy_GateOut_init(struct sig_daisy_GateOut* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host) { - sig_dsp_Signal_init(self, context, *sig_daisy_GateOut_generate); - self->host = host; - self->parameters = { - .scale = 1.0f, - .offset = 0.0f, - .control = 0 - }; - - sig_CONNECT_TO_SILENCE(self, source, context); -} - -void sig_daisy_GateOut_generate(void* signal) { - struct sig_daisy_GateOut* self = (struct sig_daisy_GateOut*) signal; - struct sig_daisy_Host* host = self->host; - float scale = self->parameters.scale; - float offset = self->parameters.offset; - int control = self->parameters.control; - - for (size_t i = 0; i < self->signal.audioSettings->blockSize; i++) { - float value = FLOAT_ARRAY(self->inputs.source)[i] * scale + offset; - FLOAT_ARRAY(self->outputs.main)[i] = value; - // TODO: Should this only be called at the block rate? - host->impl->setGateValue(host, control, value); - } -} - -void sig_daisy_GateOut_destroy(struct sig_Allocator* allocator, - struct sig_daisy_GateOut* self) { - sig_dsp_Signal_SingleMonoOutput_destroyAudioBlocks(allocator, - &self->outputs); - sig_dsp_Signal_destroy(allocator, (void*) self); -} - - -struct sig_daisy_CVIn* sig_daisy_CVIn_new(struct sig_Allocator* allocator, - struct sig_SignalContext* context, struct sig_daisy_Host* host) { - struct sig_daisy_CVIn* self = sig_MALLOC(allocator, - struct sig_daisy_CVIn); - sig_daisy_CVIn_init(self, context, host); - sig_dsp_Signal_SingleMonoOutput_newAudioBlocks(allocator, - context->audioSettings, &self->outputs); - - return self; -} - -void sig_daisy_CVIn_init(struct sig_daisy_CVIn* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host) { - sig_dsp_Signal_init(self, context, *sig_daisy_CVIn_generate); - self->host = host; - self->parameters = { - .scale = 1.0f, - .offset = 0.0f, - .control = 0 - }; -} - -void sig_daisy_CVIn_generate(void* signal) { - struct sig_daisy_CVIn* self = (struct sig_daisy_CVIn*) signal; - struct sig_daisy_Host* host = self->host; - float scale = self->parameters.scale; - float offset = self->parameters.offset; - int control = self->parameters.control; - - float rawCV = host->impl->getControlValue(host, control); - for (size_t i = 0; i < self->signal.audioSettings->blockSize; i++) { - float sample = rawCV * scale + offset; - FLOAT_ARRAY(self->outputs.main)[i] = sample; - } -} - -void sig_daisy_CVIn_destroy(struct sig_Allocator* allocator, - struct sig_daisy_CVIn* self) { - sig_dsp_Signal_SingleMonoOutput_destroyAudioBlocks(allocator, - &self->outputs); - sig_dsp_Signal_destroy(allocator, (void*) self); -} - -struct sig_daisy_FilteredCVIn* sig_daisy_FilteredCVIn_new( - struct sig_Allocator* allocator, struct sig_SignalContext* context, - struct sig_daisy_Host* host) { - struct sig_daisy_FilteredCVIn* self = sig_MALLOC(allocator, - struct sig_daisy_FilteredCVIn); - self->cvIn = sig_daisy_CVIn_new(allocator, context, host); - self->filter = sig_dsp_Smooth_new(allocator, context); - sig_daisy_FilteredCVIn_init(self, context, host); - - return self; -} - -void sig_daisy_FilteredCVIn_init(struct sig_daisy_FilteredCVIn* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host) { - sig_dsp_Signal_init(self, context, *sig_daisy_FilteredCVIn_generate); - self->host = host; - self->parameters = { - .scale = 1.0f, - .offset = 0.0f, - .control = 0, - .time = 0.01f - }; - self->filter->inputs.source = self->cvIn->outputs.main; - self->outputs = self->filter->outputs; -} - -void sig_daisy_FilteredCVIn_generate(void* signal) { - struct sig_daisy_FilteredCVIn* self = - (struct sig_daisy_FilteredCVIn*) signal; - // TODO: We have to update these parameters - // at block rate because there's no way to know if there - // was actually a parameter change made and parameters are - // stored by value, not by pointer. - self->filter->parameters.time = self->parameters.time; - self->cvIn->parameters.control = self->parameters.control; - self->cvIn->parameters.scale = self->parameters.scale; - self->cvIn->parameters.offset = self->parameters.offset; - - self->cvIn->signal.generate(self->cvIn); - self->filter->signal.generate(self->filter); -} - -void sig_daisy_FilteredCVIn_destroy(struct sig_Allocator* allocator, - struct sig_daisy_FilteredCVIn* self) { - sig_daisy_CVIn_destroy(allocator, self->cvIn); - sig_dsp_Smooth_destroy(allocator, self->filter); - sig_dsp_Signal_destroy(allocator, (void*) self); -} - - -struct sig_daisy_VOctCVIn* sig_daisy_VOctCVIn_new( - struct sig_Allocator* allocator, struct sig_SignalContext* context, - struct sig_daisy_Host* host) { - struct sig_daisy_VOctCVIn* self = sig_MALLOC(allocator, - struct sig_daisy_VOctCVIn); - self->cvIn = sig_daisy_CVIn_new(allocator, context, host); - self->cvConverter = sig_dsp_LinearToFreq_new(allocator, context); - sig_daisy_VOctCVIn_init(self, context, host); - - return self; -} - -void sig_daisy_VOctCVIn_init(struct sig_daisy_VOctCVIn* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host) { - sig_dsp_Signal_init(self, context, *sig_daisy_VOctCVIn_generate); - self->host = host; - self->parameters = { - .scale = 1.0f, - .offset = 0.0f, - .control = 0, - .middleFreq = self->cvConverter->parameters.middleFreq - }; - self->outputs = self->cvConverter->outputs; - self->cvConverter->inputs.source = self->cvIn->outputs.main; -} - -void sig_daisy_VOctCVIn_generate(void* signal) { - struct sig_daisy_VOctCVIn* self = (struct sig_daisy_VOctCVIn*) signal; - // TODO: We always have to update these parameters - // at block rate because there's no way to know if there - // was actually a parameter change made and parameters are not pointers. - self->cvConverter->parameters.middleFreq = self->parameters.middleFreq; - self->cvIn->parameters.control = self->parameters.control; - self->cvIn->parameters.scale = self->parameters.scale; - self->cvIn->parameters.offset = self->parameters.offset; - - self->cvIn->signal.generate(self->cvIn); - self->cvConverter->signal.generate(self->cvConverter); -} - -void sig_daisy_VOctCVIn_destroy(struct sig_Allocator* allocator, - struct sig_daisy_VOctCVIn* self) { - sig_daisy_CVIn_destroy(allocator, self->cvIn); - sig_dsp_LinearToFreq_destroy(allocator, self->cvConverter); - sig_dsp_Signal_destroy(allocator, (void*) self); -} - - -struct sig_daisy_SwitchIn* sig_daisy_SwitchIn_new( - struct sig_Allocator* allocator, struct sig_SignalContext* context, - struct sig_daisy_Host* host) { - struct sig_daisy_SwitchIn* self = sig_MALLOC(allocator, - struct sig_daisy_SwitchIn); - sig_daisy_SwitchIn_init(self, context, host); - sig_dsp_Signal_SingleMonoOutput_newAudioBlocks(allocator, - context->audioSettings, &self->outputs); - - return self; -} - -void sig_daisy_SwitchIn_init(struct sig_daisy_SwitchIn* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host) { - sig_dsp_Signal_init(self, context, *sig_daisy_SwitchIn_generate); - self->host = host; - self->parameters = { - .scale = 1.0f, - .offset = 0.0f, - .control = 0 - }; -} - -void sig_daisy_SwitchIn_generate(void* signal) { - struct sig_daisy_SwitchIn* self = (struct sig_daisy_SwitchIn*) signal; - struct sig_daisy_Host* host = self->host; - float scale = self->parameters.scale; - float offset = self->parameters.offset; - int control = self->parameters.control; - - float sample = host->impl->getSwitchValue(host, control); - float scaledSample = sample * scale + offset; - - for (size_t i = 0; i < self->signal.audioSettings->blockSize; i++) { - FLOAT_ARRAY(self->outputs.main)[i] = scaledSample; - } -} - -void sig_daisy_SwitchIn_destroy(struct sig_Allocator* allocator, - struct sig_daisy_SwitchIn* self) { - sig_dsp_Signal_SingleMonoOutput_destroyAudioBlocks(allocator, - &self->outputs); - sig_dsp_Signal_destroy(allocator, (void*) self); -} - - - -struct sig_daisy_TriSwitchIn* sig_daisy_TriSwitchIn_new( - struct sig_Allocator* allocator, struct sig_SignalContext* context, - struct sig_daisy_Host* host) { - struct sig_daisy_TriSwitchIn* self = sig_MALLOC(allocator, - struct sig_daisy_TriSwitchIn); - sig_daisy_TriSwitchIn_init(self, context, host); - sig_dsp_Signal_SingleMonoOutput_newAudioBlocks(allocator, - context->audioSettings, &self->outputs); - - return self; -} - -void sig_daisy_TriSwitchIn_init(struct sig_daisy_TriSwitchIn* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host) { - sig_dsp_Signal_init(self, context, *sig_daisy_TriSwitchIn_generate); - self->host = host; - self->parameters = { - .scale = 1.0f, - .offset = 0.0f, - .control = 0 - }; -} - -void sig_daisy_TriSwitchIn_generate(void* signal) { - struct sig_daisy_TriSwitchIn* self = (struct sig_daisy_TriSwitchIn*) signal; - struct sig_daisy_Host* host = self->host; - float scale = self->parameters.scale; - float offset = self->parameters.offset; - int control = self->parameters.control; - - float sample = host->impl->getTriSwitchValue(host, control); - float scaledSample = sample * scale + offset; - - for (size_t i = 0; i < self->signal.audioSettings->blockSize; i++) { - FLOAT_ARRAY(self->outputs.main)[i] = scaledSample; - } -} - -void sig_daisy_TriSwitchIn_destroy(struct sig_Allocator* allocator, - struct sig_daisy_SwitchIn* self) { - sig_dsp_Signal_SingleMonoOutput_destroyAudioBlocks(allocator, - &self->outputs); - sig_dsp_Signal_destroy(allocator, (void*) self); -} - - - -void sig_daisy_EncoderIn_Outputs_newAudioBlocks(struct sig_Allocator* allocator, - struct sig_AudioSettings* audioSettings, - struct sig_daisy_EncoderIn_Outputs* outputs) { - outputs->main = sig_AudioBlock_newSilent(allocator, audioSettings); - outputs->button = sig_AudioBlock_newSilent(allocator, audioSettings); -} - -void sig_daisy_EncoderIn_Outputs_destroyAudioBlocks( - struct sig_Allocator* allocator, - struct sig_daisy_EncoderIn_Outputs* outputs) { - sig_AudioBlock_destroy(allocator, outputs->main); - sig_AudioBlock_destroy(allocator, outputs->button); -} - -struct sig_daisy_EncoderIn* sig_daisy_EncoderIn_new( - struct sig_Allocator* allocator, struct sig_SignalContext* context, - struct sig_daisy_Host* host) { - struct sig_daisy_EncoderIn* self = sig_MALLOC(allocator, - struct sig_daisy_EncoderIn); - sig_daisy_EncoderIn_init(self, context, host); - sig_daisy_EncoderIn_Outputs_newAudioBlocks(allocator, - context->audioSettings, &self->outputs); - - return self; -} - -void sig_daisy_EncoderIn_init(struct sig_daisy_EncoderIn* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host) { - sig_dsp_Signal_init(self, context, *sig_daisy_EncoderIn_generate); - self->host = host; - self->parameters = { - .scale = 1.0f, - .offset = 0.0f, - .control = 0 - }; - - self->accumulatedValue = 0.0f; -} - -void sig_daisy_EncoderIn_generate(void* signal) { - struct sig_daisy_EncoderIn* self = (struct sig_daisy_EncoderIn*) signal; - struct sig_daisy_Host* host = self->host; - float scale = self->parameters.scale; - float offset = self->parameters.offset; - int control = self->parameters.control; - - float incrementValue = host->impl->getEncoderIncrement(host, control); - float buttonValue = host->impl->getEncoderButtonValue(host, control); - float accumulatedValue = self->accumulatedValue + incrementValue; - float scaledAccumulatedValue = accumulatedValue * scale + offset; - - for (size_t i = 0; i < self->signal.audioSettings->blockSize; i++) { - FLOAT_ARRAY(self->outputs.main)[i] = scaledAccumulatedValue; - FLOAT_ARRAY(self->outputs.increment)[i] = incrementValue; - FLOAT_ARRAY(self->outputs.button)[i] = buttonValue; - } - - self->accumulatedValue = accumulatedValue; -} - -void sig_daisy_EncoderIn_destroy(struct sig_Allocator* allocator, - struct sig_daisy_EncoderIn* self) { - sig_daisy_EncoderIn_Outputs_destroyAudioBlocks(allocator, - &self->outputs); - sig_dsp_Signal_destroy(allocator, (void*) self); -} - - -struct sig_daisy_CVOut* sig_daisy_CVOut_new(struct sig_Allocator* allocator, - struct sig_SignalContext* context, struct sig_daisy_Host* host) { - struct sig_daisy_CVOut* self = sig_MALLOC(allocator, - struct sig_daisy_CVOut); - sig_daisy_CVOut_init(self, context, host); - sig_dsp_Signal_SingleMonoOutput_newAudioBlocks(allocator, - context->audioSettings, &self->outputs); - - return self; -} - -void sig_daisy_CVOut_init(struct sig_daisy_CVOut* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host) { - sig_dsp_Signal_init(self, context, *sig_daisy_CVOut_generate); - self->host = host; - self->parameters = { - .scale = 1.0f, - .offset = 0.0f, - .control = 0 - }; - - sig_CONNECT_TO_SILENCE(self, source, context); -} - -void sig_daisy_CVOut_generate(void* signal) { - struct sig_daisy_CVOut* self = (struct sig_daisy_CVOut*) signal; - struct sig_daisy_Host* host = self->host; - float scale = self->parameters.scale; - float offset = self->parameters.offset; - int control = self->parameters.control; - - // Pass through the value to the output buffer, - // so even sink signals can be chained. - for (size_t i = 0; i < self->signal.audioSettings->blockSize; i++) { - float source = FLOAT_ARRAY(self->inputs.source)[i]; - float sample = source * scale + offset; - FLOAT_ARRAY(self->outputs.main)[i] = sample; - // TODO: Should this only be called at the block rate? - host->impl->setControlValue(host, control, sample); - } -} - -void sig_daisy_CVIn_destroy(struct sig_Allocator* allocator, - struct sig_daisy_CVOut* self) { - sig_dsp_Signal_SingleMonoOutput_destroyAudioBlocks(allocator, - &self->outputs); - sig_dsp_Signal_destroy(allocator, (void*) self); -} - -struct sig_daisy_AudioOut* sig_daisy_AudioOut_new( - struct sig_Allocator* allocator, - struct sig_SignalContext* context, - struct sig_daisy_Host* host) { - struct sig_daisy_AudioOut* self = sig_MALLOC(allocator, - struct sig_daisy_AudioOut); - sig_daisy_AudioOut_init(self, context, host); - sig_dsp_Signal_SingleMonoOutput_newAudioBlocks(allocator, - context->audioSettings, &self->outputs); - - return self; -} - -void sig_daisy_AudioOut_init(struct sig_daisy_AudioOut* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host) { - sig_dsp_Signal_init(self, context, *sig_daisy_AudioOut_generate); - self->host = host; - self->parameters = { - .channel = 0, - .scale = 1.0f - }; - - sig_CONNECT_TO_SILENCE(self, source, context); -} - -void sig_daisy_AudioOut_generate(void* signal) { - struct sig_daisy_AudioOut* self = (struct sig_daisy_AudioOut*) signal; - struct sig_daisy_Host* host = self->host; - daisy::AudioHandle::OutputBuffer out = host->board.audioOutputs; - float_array_ptr source = self->inputs.source; - int channel = self->parameters.channel; - float scale = self->parameters.scale; - - // TODO: We need a validation stage for Signals so that we can - // avoid these conditionals happening at block rate. - if (channel < 0 || - channel >= host->board.config->numAudioOutputChannels) { - // There's a channel mismatch, just do nothing. - return; - } - - // TODO: Is it safe to assume here that the Signal's block size is - // the same as the Host's? - for (size_t i = 0; i < self->signal.audioSettings->blockSize; i++) { - out[channel][i] = FLOAT_ARRAY(source)[i] * scale; - } -} - -void sig_daisy_AudioOut_destroy(struct sig_Allocator* allocator, - struct sig_daisy_AudioOut* self) { - sig_dsp_Signal_SingleMonoOutput_destroyAudioBlocks(allocator, - &self->outputs); - sig_dsp_Signal_destroy(allocator, (void*) self); -} - - -struct sig_daisy_AudioIn* sig_daisy_AudioIn_new( - struct sig_Allocator* allocator, - struct sig_SignalContext* context, - struct sig_daisy_Host* host) { - struct sig_daisy_AudioIn* self = sig_MALLOC(allocator, - struct sig_daisy_AudioIn); - sig_daisy_AudioIn_init(self, context, host); - sig_dsp_Signal_SingleMonoOutput_newAudioBlocks(allocator, - context->audioSettings, &self->outputs); - - return self; -} - -void sig_daisy_AudioIn_init(struct sig_daisy_AudioIn* self, - struct sig_SignalContext* context, struct sig_daisy_Host* host) { - sig_dsp_Signal_init(self, context, *sig_daisy_AudioIn_generate); - self->host = host; - self->parameters = { - .channel = 0, - .scale = 1.0f - }; -} - -void sig_daisy_AudioIn_generate(void* signal) { - struct sig_daisy_AudioIn* self = (struct sig_daisy_AudioIn*) signal; - struct sig_daisy_Host* host = self->host; - daisy::AudioHandle::InputBuffer in = host->board.audioInputs; - int channel = self->parameters.channel; - float scale = self->parameters.scale; - - // TODO: We need a validation stage for Signals so that we can - // avoid these conditionals happening at block rate. - if (channel < 0 || - channel >= host->board.config->numAudioInputChannels) { - // There's a channel mismatch, just do nothing. - return; - } - - // TODO: Is it safe to assume here that the Signal's block size is - // the same as the Host's? - for (size_t i = 0; i < self->signal.audioSettings->blockSize; i++) { - FLOAT_ARRAY(self->outputs.main)[i] = in[channel][i] * scale; - } -} - -void sig_daisy_AudioIn_destroy(struct sig_Allocator* allocator, - struct sig_daisy_AudioIn* self) { - sig_dsp_Signal_SingleMonoOutput_destroyAudioBlocks(allocator, - &self->outputs); - sig_dsp_Signal_destroy(allocator, (void*) self); + hardware->afterEvaluateSignals(size, hardware); } diff --git a/hosts/daisy/src/signaletic-host.c b/hosts/daisy/src/signaletic-host.c new file mode 100644 index 0000000..60a34b8 --- /dev/null +++ b/hosts/daisy/src/signaletic-host.c @@ -0,0 +1,448 @@ +#include "../include/signaletic-host.h" + +void sig_host_noOpAudioEventCallback(size_t size, + struct sig_host_HardwareInterface* hardware) {}; + +struct sig_host_GateIn* sig_host_GateIn_new( + struct sig_Allocator* allocator, + struct sig_SignalContext* context) { + struct sig_host_GateIn* self = sig_MALLOC(allocator, + struct sig_host_GateIn); + sig_host_GateIn_init(self, context); + sig_dsp_Signal_SingleMonoOutput_newAudioBlocks(allocator, + context->audioSettings, &self->outputs); + + return self; +} + + +void sig_host_GateIn_init(struct sig_host_GateIn* self, + struct sig_SignalContext* context) { + sig_dsp_Signal_init(self, context, *sig_host_GateIn_generate); + self->parameters.scale = 1.0f; + self->parameters.offset = 0.0f; + self->parameters.control = 0; +} + +void sig_host_GateIn_generate(void* signal) { + struct sig_host_GateIn* self = (struct sig_host_GateIn*) signal; + struct sig_host_HardwareInterface* hardware = self->hardware; + float scale = self->parameters.scale; + float offset = self->parameters.offset; + int control = self->parameters.control; + + for (size_t i = 0; i < self->signal.audioSettings->blockSize; i++) { + float sample = hardware->gateInputs[control]; + FLOAT_ARRAY(self->outputs.main)[i] = sample * scale + offset; + } +} + +void sig_host_GateIn_destroy(struct sig_Allocator* allocator, + struct sig_host_GateIn* self) { + sig_dsp_Signal_SingleMonoOutput_destroyAudioBlocks(allocator, + &self->outputs); + sig_dsp_Signal_destroy(allocator, (void*) self); +} + +struct sig_host_GateOut* sig_host_GateOut_new( + struct sig_Allocator* allocator, + struct sig_SignalContext* context) { + struct sig_host_GateOut* self = sig_MALLOC(allocator, + struct sig_host_GateOut); + sig_host_GateOut_init(self, context); + sig_dsp_Signal_SingleMonoOutput_newAudioBlocks(allocator, + context->audioSettings, &self->outputs); + + return self; +} + +void sig_host_GateOut_init(struct sig_host_GateOut* self, + struct sig_SignalContext* context) { + sig_dsp_Signal_init(self, context, *sig_host_GateOut_generate); + self->parameters.scale = 1.0f; + self->parameters.offset = 0.0f; + self->parameters.control = 0; + + sig_CONNECT_TO_SILENCE(self, source, context); +} + +void sig_host_GateOut_generate(void* signal) { + struct sig_host_GateOut* self = (struct sig_host_GateOut*) signal; + struct sig_host_HardwareInterface* hardware = self->hardware; + float scale = self->parameters.scale; + float offset = self->parameters.offset; + int control = self->parameters.control; + + for (size_t i = 0; i < self->signal.audioSettings->blockSize; i++) { + float value = FLOAT_ARRAY(self->inputs.source)[i] * scale + offset; + FLOAT_ARRAY(self->outputs.main)[i] = value; + // TODO: Should this only be called at the block rate? + hardware->gpioOutputs[control] = value; + } +} + +void sig_host_GateOut_destroy(struct sig_Allocator* allocator, + struct sig_host_GateOut* self) { + sig_dsp_Signal_SingleMonoOutput_destroyAudioBlocks(allocator, + &self->outputs); + sig_dsp_Signal_destroy(allocator, (void*) self); +} + + +struct sig_host_CVIn* sig_host_CVIn_new(struct sig_Allocator* allocator, + struct sig_SignalContext* context) { + struct sig_host_CVIn* self = sig_MALLOC(allocator, + struct sig_host_CVIn); + sig_host_CVIn_init(self, context); + sig_dsp_Signal_SingleMonoOutput_newAudioBlocks(allocator, + context->audioSettings, &self->outputs); + + return self; +} + +void sig_host_CVIn_init(struct sig_host_CVIn* self, + struct sig_SignalContext* context) { + sig_dsp_Signal_init(self, context, *sig_host_CVIn_generate); + self->parameters.scale = 1.0f; + self->parameters.offset = 0.0f; + self->parameters.control = 0; +} + +void sig_host_CVIn_generate(void* signal) { + struct sig_host_CVIn* self = (struct sig_host_CVIn*) signal; + struct sig_host_HardwareInterface* hardware = self->hardware; + float scale = self->parameters.scale; + float offset = self->parameters.offset; + int control = self->parameters.control; + + float rawCV = hardware->adcChannels[control]; + for (size_t i = 0; i < self->signal.audioSettings->blockSize; i++) { + float sample = rawCV * scale + offset; + FLOAT_ARRAY(self->outputs.main)[i] = sample; + } +} + +void sig_host_CVIn_destroy(struct sig_Allocator* allocator, + struct sig_host_CVIn* self) { + sig_dsp_Signal_SingleMonoOutput_destroyAudioBlocks(allocator, + &self->outputs); + sig_dsp_Signal_destroy(allocator, (void*) self); +} + + +struct sig_host_FilteredCVIn* sig_host_FilteredCVIn_new( + struct sig_Allocator* allocator, struct sig_SignalContext* context) { + struct sig_host_FilteredCVIn* self = sig_MALLOC(allocator, + struct sig_host_FilteredCVIn); + self->cvIn = sig_host_CVIn_new(allocator, context); + self->filter = sig_dsp_Smooth_new(allocator, context); + sig_host_FilteredCVIn_init(self, context); + + return self; +} + +void sig_host_FilteredCVIn_init(struct sig_host_FilteredCVIn* self, + struct sig_SignalContext* context) { + sig_dsp_Signal_init(self, context, *sig_host_FilteredCVIn_generate); + self->parameters.scale = 1.0f; + self->parameters.offset = 0.0f; + self->parameters.control = 0; + self->parameters.time = 0.01f; + self->filter->inputs.source = self->cvIn->outputs.main; + self->outputs = self->filter->outputs; +} + +void sig_host_FilteredCVIn_generate(void* signal) { + struct sig_host_FilteredCVIn* self = + (struct sig_host_FilteredCVIn*) signal; + // TODO: We have to update these parameters + // at block rate because there's no way to know if there + // was actually a parameter change made and parameters are + // stored by value, not by pointer. + self->cvIn->hardware = self->hardware; + self->filter->parameters.time = self->parameters.time; + self->cvIn->parameters.control = self->parameters.control; + self->cvIn->parameters.scale = self->parameters.scale; + self->cvIn->parameters.offset = self->parameters.offset; + + self->cvIn->signal.generate(self->cvIn); + self->filter->signal.generate(self->filter); +} + +void sig_host_FilteredCVIn_destroy(struct sig_Allocator* allocator, + struct sig_host_FilteredCVIn* self) { + sig_host_CVIn_destroy(allocator, self->cvIn); + sig_dsp_Smooth_destroy(allocator, self->filter); + sig_dsp_Signal_destroy(allocator, (void*) self); +} + + +struct sig_host_VOctCVIn* sig_host_VOctCVIn_new( + struct sig_Allocator* allocator, struct sig_SignalContext* context) { + struct sig_host_VOctCVIn* self = sig_MALLOC(allocator, + struct sig_host_VOctCVIn); + self->cvIn = sig_host_CVIn_new(allocator, context); + self->cvConverter = sig_dsp_LinearToFreq_new(allocator, context); + sig_host_VOctCVIn_init(self, context); + + return self; +} + +void sig_host_VOctCVIn_init(struct sig_host_VOctCVIn* self, + struct sig_SignalContext* context) { + sig_dsp_Signal_init(self, context, *sig_host_VOctCVIn_generate); + self->parameters.scale = 1.0f; + self->parameters.offset = 0.0f; + self->parameters.control = 0; + self->parameters.middleFreq = self->cvConverter->parameters.middleFreq; + + self->outputs = self->cvConverter->outputs; + self->cvConverter->inputs.source = self->cvIn->outputs.main; +} + +void sig_host_VOctCVIn_generate(void* signal) { + struct sig_host_VOctCVIn* self = (struct sig_host_VOctCVIn*) signal; + // TODO: We always have to update these parameters + // at block rate because there's no way to know if there + // was actually a parameter change made and parameters are not pointers. + self->cvIn->hardware = self->hardware; + self->cvConverter->parameters.middleFreq = self->parameters.middleFreq; + self->cvIn->parameters.control = self->parameters.control; + self->cvIn->parameters.scale = self->parameters.scale; + self->cvIn->parameters.offset = self->parameters.offset; + + self->cvIn->signal.generate(self->cvIn); + self->cvConverter->signal.generate(self->cvConverter); +} + +void sig_host_VOctCVIn_destroy(struct sig_Allocator* allocator, + struct sig_host_VOctCVIn* self) { + sig_host_CVIn_destroy(allocator, self->cvIn); + sig_dsp_LinearToFreq_destroy(allocator, self->cvConverter); + sig_dsp_Signal_destroy(allocator, (void*) self); +} + + +struct sig_host_CVOut* sig_host_CVOut_new(struct sig_Allocator* allocator, + struct sig_SignalContext* context) { + struct sig_host_CVOut* self = sig_MALLOC(allocator, + struct sig_host_CVOut); + sig_host_CVOut_init(self, context); + sig_dsp_Signal_SingleMonoOutput_newAudioBlocks(allocator, + context->audioSettings, &self->outputs); + + return self; +} + +void sig_host_CVOut_init(struct sig_host_CVOut* self, + struct sig_SignalContext* context) { + sig_dsp_Signal_init(self, context, *sig_host_CVOut_generate); + self->parameters.scale = 1.0f; + self->parameters.offset = 0.0f; + self->parameters.control = 0; + + sig_CONNECT_TO_SILENCE(self, source, context); +} + +void sig_host_CVOut_generate(void* signal) { + struct sig_host_CVOut* self = (struct sig_host_CVOut*) signal; + struct sig_host_HardwareInterface* hardware = self->hardware; + float scale = self->parameters.scale; + float offset = self->parameters.offset; + int control = self->parameters.control; + + // Pass through the value to the output buffer, + // so even sink signals can be chained. + for (size_t i = 0; i < self->signal.audioSettings->blockSize; i++) { + float source = FLOAT_ARRAY(self->inputs.source)[i]; + float sample = source * scale + offset; + FLOAT_ARRAY(self->outputs.main)[i] = sample; + // TODO: Should this only be called at the block rate? + hardware->dacChannels[control] = sample; + } +} + + +struct sig_host_AudioOut* sig_host_AudioOut_new( + struct sig_Allocator* allocator, + struct sig_SignalContext* context) { + struct sig_host_AudioOut* self = sig_MALLOC(allocator, + struct sig_host_AudioOut); + sig_host_AudioOut_init(self, context); + sig_dsp_Signal_SingleMonoOutput_newAudioBlocks(allocator, + context->audioSettings, &self->outputs); + + return self; +} + +void sig_host_AudioOut_init(struct sig_host_AudioOut* self, + struct sig_SignalContext* context) { + sig_dsp_Signal_init(self, context, *sig_host_AudioOut_generate); + self->parameters.channel = 0; + self->parameters.scale = 1.0f; + + sig_CONNECT_TO_SILENCE(self, source, context); +} + +void sig_host_AudioOut_generate(void* signal) { + struct sig_host_AudioOut* self = (struct sig_host_AudioOut*) signal; + struct sig_host_HardwareInterface* hardware = self->hardware; + float** out = hardware->audioOutputChannels; + float_array_ptr source = self->inputs.source; + int channel = self->parameters.channel; + float scale = self->parameters.scale; + + // TODO: We need a validation stage for Signals so that we can + // avoid these conditionals happening at block rate. + if (channel < 0 || + channel >= hardware->numAudioOutputChannels) { + // There's a channel mismatch, just do nothing. + return; + } + + // TODO: Is it safe to assume here that the Signal's block size is + // the same as the Host's? + for (size_t i = 0; i < self->signal.audioSettings->blockSize; i++) { + out[channel][i] = FLOAT_ARRAY(source)[i] * scale; + } +} + +void sig_host_AudioOut_destroy(struct sig_Allocator* allocator, + struct sig_host_AudioOut* self) { + sig_dsp_Signal_SingleMonoOutput_destroyAudioBlocks(allocator, + &self->outputs); + sig_dsp_Signal_destroy(allocator, (void*) self); +} + + +struct sig_host_AudioIn* sig_host_AudioIn_new( + struct sig_Allocator* allocator, + struct sig_SignalContext* context) { + struct sig_host_AudioIn* self = sig_MALLOC(allocator, + struct sig_host_AudioIn); + sig_host_AudioIn_init(self, context); + sig_dsp_Signal_SingleMonoOutput_newAudioBlocks(allocator, + context->audioSettings, &self->outputs); + + return self; +} + +void sig_host_AudioIn_init(struct sig_host_AudioIn* self, + struct sig_SignalContext* context) { + sig_dsp_Signal_init(self, context, *sig_host_AudioIn_generate); + self->parameters.channel = 0; + self->parameters.scale = 1.0f; +} + +void sig_host_AudioIn_generate(void* signal) { + struct sig_host_AudioIn* self = (struct sig_host_AudioIn*) signal; + struct sig_host_HardwareInterface* hardware = self->hardware; + float** in = hardware->audioInputChannels; + int channel = self->parameters.channel; + float scale = self->parameters.scale; + + // TODO: We need a validation stage for Signals so that we can + // avoid these conditionals happening at block rate. + if (channel < 0 || + channel >= hardware->numAudioInputChannels) { + // There's a channel mismatch, just do nothing. + return; + } + + // TODO: Is it safe to assume here that the Signal's block size is + // the same as the Host's? + for (size_t i = 0; i < self->signal.audioSettings->blockSize; i++) { + FLOAT_ARRAY(self->outputs.main)[i] = in[channel][i] * scale; + } +} + +void sig_host_AudioIn_destroy(struct sig_Allocator* allocator, + struct sig_host_AudioIn* self) { + sig_dsp_Signal_SingleMonoOutput_destroyAudioBlocks(allocator, + &self->outputs); + sig_dsp_Signal_destroy(allocator, (void*) self); +} + + +struct sig_host_SwitchIn* sig_host_SwitchIn_new( + struct sig_Allocator* allocator, struct sig_SignalContext* context) { + struct sig_host_SwitchIn* self = sig_MALLOC(allocator, + struct sig_host_SwitchIn); + sig_host_SwitchIn_init(self, context); + sig_dsp_Signal_SingleMonoOutput_newAudioBlocks(allocator, + context->audioSettings, &self->outputs); + + return self; +} + +void sig_host_SwitchIn_init(struct sig_host_SwitchIn* self, + struct sig_SignalContext* context) { + sig_dsp_Signal_init(self, context, *sig_host_SwitchIn_generate); + self->parameters.scale = 1.0f; + self->parameters.offset = 0.0f; + self->parameters.control = 0; +} + +void sig_host_SwitchIn_generate(void* signal) { + struct sig_host_SwitchIn* self = (struct sig_host_SwitchIn*) signal; + struct sig_host_HardwareInterface* hardware = self->hardware; + float scale = self->parameters.scale; + float offset = self->parameters.offset; + int control = self->parameters.control; + + float sample = hardware->toggles[control]; + float scaledSample = sample * scale + offset; + + for (size_t i = 0; i < self->signal.audioSettings->blockSize; i++) { + FLOAT_ARRAY(self->outputs.main)[i] = scaledSample; + } +} + +void sig_host_SwitchIn_destroy(struct sig_Allocator* allocator, + struct sig_host_SwitchIn* self) { + sig_dsp_Signal_SingleMonoOutput_destroyAudioBlocks(allocator, + &self->outputs); + sig_dsp_Signal_destroy(allocator, (void*) self); +} + + +struct sig_host_TriSwitchIn* sig_host_TriSwitchIn_new( + struct sig_Allocator* allocator, struct sig_SignalContext* context) { + struct sig_host_TriSwitchIn* self = sig_MALLOC(allocator, + struct sig_host_TriSwitchIn); + sig_host_TriSwitchIn_init(self, context); + sig_dsp_Signal_SingleMonoOutput_newAudioBlocks(allocator, + context->audioSettings, &self->outputs); + + return self; +} + +void sig_host_TriSwitchIn_init(struct sig_host_TriSwitchIn* self, + struct sig_SignalContext* context) { + sig_dsp_Signal_init(self, context, *sig_host_TriSwitchIn_generate); + self->parameters.scale = 1.0f; + self->parameters.offset = 0.0f; + self->parameters.control = 0; +} + +void sig_host_TriSwitchIn_generate(void* signal) { + struct sig_host_TriSwitchIn* self = (struct sig_host_TriSwitchIn*) signal; + struct sig_host_HardwareInterface* hardware = self->hardware; + float scale = self->parameters.scale; + float offset = self->parameters.offset; + int control = self->parameters.control; + + float sample = hardware->triSwitches[control]; + float scaledSample = sample * scale + offset; + + for (size_t i = 0; i < self->signal.audioSettings->blockSize; i++) { + FLOAT_ARRAY(self->outputs.main)[i] = scaledSample; + } +} + +void sig_host_TriSwitchIn_destroy(struct sig_Allocator* allocator, + struct sig_host_TriSwitchIn* self) { + sig_dsp_Signal_SingleMonoOutput_destroyAudioBlocks(allocator, + &self->outputs); + sig_dsp_Signal_destroy(allocator, (void*) self); +} diff --git a/libsignaletic/include/libsignaletic.h b/libsignaletic/include/libsignaletic.h index b98d561..fa97b84 100644 --- a/libsignaletic/include/libsignaletic.h +++ b/libsignaletic/include/libsignaletic.h @@ -171,6 +171,39 @@ uint16_t sig_bipolarToUint12(float sample); */ uint16_t sig_bipolarToInvUint12(float sample); +/** + * Converts an unsigned 16-bit integer in the range 0-65536 to a + * bipolar floating point sample in the range -1.0 to 1.0. + * + * This function does not clamp the sample. + * + * @param sample the unsigned 16-bit sample to convert + * @return the sample converted to normalized floating point + */ +float sig_uint16ToBipolar(uint16_t sample); + +/** + * Converts an unsigned 16-bit integer in the range 0-65536 to a + * unipolar floating point sample in the range 0.0 to 1.0. + * + * This function does not clamp the sample. + * + * @param sample the unsigned 16-bit sample to convert + * @return the sample converted to normalized unipolar floating point + */ +float sig_uint16ToUnipolar(uint16_t sample); + +/** + * Converts an unsigned 16-bit integer in the range 65536-0 to a + * bipolar floating point sample in the range -1.0 to 1.0. + * + * This function does not clamp the sample. + * + * @param sample the inverted unsigned 16-bit sample to convert + * @return the sample converted to normalized floating point + */ +float sig_invUint16ToBipolar(uint16_t sample); + /** * Converts MIDI note numbers into frequencies in hertz. * This algorithm assumes A4 = 440 Hz = MIDI note #69. @@ -407,6 +440,16 @@ float sig_filter_smooth(float current, float previous, float coeff); float sig_filter_smooth_calculateCoefficient(float timeSecs, float sampleRate); +// TODO: Documentation! +struct sig_filter_Smooth { + float coeff; + float previous; +}; + +void sig_filter_Smooth_init(struct sig_filter_Smooth* self, float coeff); + +float sig_filter_Smooth_generate(struct sig_filter_Smooth* self, float value); + /** * Type definition for a waveform generator function. * diff --git a/libsignaletic/src/libsignaletic.c b/libsignaletic/src/libsignaletic.c index 50a5b81..929f914 100644 --- a/libsignaletic/src/libsignaletic.c +++ b/libsignaletic/src/libsignaletic.c @@ -83,19 +83,36 @@ inline float sig_linearMap(float value, return (value - fromMin) * (toMax - toMin) / (fromMax - fromMin) + toMin; } -uint16_t sig_unipolarToUint12(float sample) { +inline uint16_t sig_unipolarToUint12(float sample) { return (uint16_t) (sample * 4095.0f); } -uint16_t sig_bipolarToUint12(float sample) { +inline uint16_t sig_bipolarToUint12(float sample) { float normalized = sample * 0.5 + 0.5; return (uint16_t) (normalized * 4095.0f); } -uint16_t sig_bipolarToInvUint12(float sample) { +inline uint16_t sig_bipolarToInvUint12(float sample) { return sig_bipolarToUint12(-sample); } +inline float sig_uint16ToBipolar(uint16_t sample) { + float normalized = (float) (sample / 65536.0f); + float scaled = normalized * 2.0f - 1.0f; + + return scaled; +} + +inline float sig_uint16ToUnipolar(uint16_t sample) { + float normalized = (float) (sample / 65536.0f); + + return normalized; +} + +inline float sig_invUint16ToBipolar(uint16_t sample) { + return -sig_uint16ToBipolar(sample); +} + float sig_midiToFreq(float midiNum) { return powf(2, (midiNum - 69.0f) / 12.0f) * 440.0f; } @@ -276,6 +293,20 @@ inline float sig_filter_smooth_calculateCoefficient(float time, return expf(sig_LOG0_001 / (time * sampleRate)); } + +void sig_filter_Smooth_init(struct sig_filter_Smooth* self, float coeff) { + self->coeff = coeff; + self->previous = 0; +} + +inline float sig_filter_Smooth_generate(struct sig_filter_Smooth* self, + float value) { + float smoothed = sig_filter_smooth(value, self->previous, self->coeff); + self->previous = smoothed; + + return smoothed; +} + // TODO: Unit tests. float sig_waveform_sine(float phase) { return sinf(phase);