diff --git a/hosts/daisy/examples/bluemchen/calibrator/Makefile b/hosts/daisy/examples/bluemchen/calibrator/Makefile index 9f1f4b9..ba71828 100644 --- a/hosts/daisy/examples/bluemchen/calibrator/Makefile +++ b/hosts/daisy/examples/bluemchen/calibrator/Makefile @@ -1,7 +1,7 @@ # Project Name TARGET ?= signaletic-bluemchen-calibrator -DEBUG = 0 +DEBUG = 1 OPT = -O0 # Sources diff --git a/hosts/daisy/examples/dpt/lfos/include/signaletic-dpt-lfos-signals.h b/hosts/daisy/examples/dpt/lfos/include/signaletic-dpt-lfos-signals.h new file mode 100644 index 0000000..ef59736 --- /dev/null +++ b/hosts/daisy/examples/dpt/lfos/include/signaletic-dpt-lfos-signals.h @@ -0,0 +1,110 @@ +#include +#include "../../../../include/signaletic-daisy-host.h" + +struct sig_daisy_ClockedLFO_Inputs { + float_array_ptr clockFreq; +}; + +struct sig_daisy_ClockedLFO_Parameters { + int freqScaleCVInputControl; + int lfoGainCVInputControl; + int cvOutputControl; +}; + +// TODO: This isn't quite the correct name. +struct sig_daisy_ClockedLFO { + struct sig_dsp_Signal signal; + struct sig_daisy_ClockedLFO_Inputs inputs; + struct sig_daisy_ClockedLFO_Parameters parameters; + struct sig_dsp_Signal_SingleMonoOutput outputs; + struct sig_daisy_FilteredCVIn* freqScaleIn; + struct sig_dsp_BinaryOp* clockFreqMultiplier; + struct sig_daisy_FilteredCVIn* lfoGainIn; + struct sig_dsp_Oscillator* lfo; + struct sig_daisy_CVOut* cvOut; +}; + + +struct sig_daisy_ClockedLFO* sig_daisy_ClockedLFO_new( + struct sig_Allocator* allocator, struct sig_SignalContext* context, + struct sig_daisy_Host* host); +void sig_daisy_ClockedLFO_init(struct sig_daisy_ClockedLFO* self, + struct sig_SignalContext* context); +void sig_daisy_ClockedLFO_generate(void* signal); +void sig_daisy_ClockedLFO_destroy(struct sig_Allocator* allocator, + struct sig_daisy_ClockedLFO* self); + + +struct sig_daisy_ClockedLFO* sig_daisy_ClockedLFO_new( + struct sig_Allocator* allocator, struct sig_SignalContext* context, + struct sig_daisy_Host* host) { + struct sig_daisy_ClockedLFO* self = sig_MALLOC(allocator, + struct sig_daisy_ClockedLFO); + + self->freqScaleIn = sig_daisy_FilteredCVIn_new(allocator, context, host); + self->clockFreqMultiplier = sig_dsp_Mul_new(allocator, context); + self->lfoGainIn = sig_daisy_FilteredCVIn_new(allocator, context, host); + self->lfo = sig_dsp_LFTriangle_new(allocator, context); + self->cvOut = sig_daisy_CVOut_new(allocator, context, host); + + sig_daisy_ClockedLFO_init(self, context); + + return self; +} + +void sig_daisy_ClockedLFO_init(struct sig_daisy_ClockedLFO* self, + struct sig_SignalContext* context) { + sig_dsp_Signal_init(self, context, *sig_daisy_ClockedLFO_generate); + self->parameters.freqScaleCVInputControl = 1; + self->parameters.lfoGainCVInputControl = 2; + self->parameters.cvOutputControl = 1; + + self->freqScaleIn->parameters.scale = 9.99f; + self->freqScaleIn->parameters.offset = 0.01f; + + // TODO: Implement proper calibration for CV output + // My DPT seems to output -4.67V to 7.96V, + // this was tuned by hand with the (uncalibrated) VCV Rack oscilloscope. + // cvOut->parameters.scale = 0.68; + // cvOut->parameters.offset = -0.32; + + self->clockFreqMultiplier->inputs.right = self->freqScaleIn->outputs.main; + self->lfo->inputs.freq = self->clockFreqMultiplier->outputs.main; + self->lfo->inputs.mul = self->lfoGainIn->outputs.main; + self->outputs.main = self->lfo->outputs.main; + self->cvOut->inputs.source = self->lfo->outputs.main; + sig_CONNECT_TO_SILENCE(self, clockFreq, context); +} + +void sig_daisy_ClockedLFO_generate(void* signal) { + struct sig_daisy_ClockedLFO* self = + (struct sig_daisy_ClockedLFO*) signal; + self->freqScaleIn->parameters.control = + self->parameters.freqScaleCVInputControl; + self->lfoGainIn->parameters.control = + self->parameters.lfoGainCVInputControl; + self->cvOut->parameters.control = self->parameters.cvOutputControl; + + self->clockFreqMultiplier->inputs.left = self->inputs.clockFreq; + + self->freqScaleIn->signal.generate(self->freqScaleIn); + self->clockFreqMultiplier->signal.generate(self->clockFreqMultiplier); + self->lfoGainIn->signal.generate(self->lfoGainIn); + self->lfo->signal.generate(self->lfo); + self->cvOut->signal.generate(self->cvOut); +} + +void sig_daisy_ClockedLFO_destroy(struct sig_Allocator* allocator, + struct sig_daisy_ClockedLFO* self) { + sig_daisy_FilteredCVIn_destroy(allocator, self->freqScaleIn); + sig_dsp_Mul_destroy(allocator, self->clockFreqMultiplier); + sig_daisy_FilteredCVIn_destroy(allocator, self->lfoGainIn); + sig_dsp_LFTriangle_destroy(allocator, self->lfo); + sig_daisy_CVOut_destroy(allocator, self->cvOut); + + // We don't call sig_dsp_Signal_destroy + // because our output is borrowed from self->lfo, + // which was already freed in LFTriangle's destructor. + allocator->impl->free(allocator, self); +} + diff --git a/hosts/daisy/examples/dpt/lfos/src/signaletic-dpt-lfos.cpp b/hosts/daisy/examples/dpt/lfos/src/signaletic-dpt-lfos.cpp index 49aa67b..218b45d 100644 --- a/hosts/daisy/examples/dpt/lfos/src/signaletic-dpt-lfos.cpp +++ b/hosts/daisy/examples/dpt/lfos/src/signaletic-dpt-lfos.cpp @@ -1,5 +1,5 @@ #include "daisy.h" -#include +#include "../include/signaletic-dpt-lfos-signals.h" #include "../../../../include/daisy-dpt-host.h" #define HEAP_SIZE 1024 * 256 // 256KB @@ -29,12 +29,14 @@ struct sig_List signals = { struct sig_dsp_SignalListEvaluator* evaluator; struct sig_daisy_GateIn* clockInput; struct sig_dsp_ClockDetector* clockFreq; -struct sig_daisy_CVIn* lfoAmpValue; -struct sig_dsp_BinaryOp* lfoGain; -struct sig_daisy_CVIn* lfoClockScaleValue; -struct sig_dsp_BinaryOp* lfoClockScale; -struct sig_dsp_Oscillator* lfo; -struct sig_daisy_CVOut* cv1Out; +struct sig_daisy_ClockedLFO* lfo1; +struct sig_daisy_ClockedLFO* lfo2; +struct sig_daisy_ClockedLFO* lfo3; +struct sig_daisy_ClockedLFO* lfo4; +struct sig_dsp_BinaryOp* lfo1PlusLFO3; +struct sig_dsp_BinaryOp* lfo2PlusLFO4; +struct sig_daisy_CVOut* lfo1And3Out; +struct sig_daisy_CVOut* lfo2And4Out; struct sig_daisy_GateOut* gate1Out; void InitCVInputs(struct sig_SignalContext* context, @@ -42,16 +44,6 @@ void InitCVInputs(struct sig_SignalContext* context, clockInput = sig_daisy_GateIn_new(&alloc, context, dptHost); clockInput->parameters.control = sig_daisy_DPT_GATE_IN_1; sig_List_append(&signals, clockInput, status); - - lfoClockScaleValue = sig_daisy_CVIn_new(&alloc, context, dptHost); - lfoClockScaleValue->parameters.control = sig_daisy_DPT_CV_IN_1; - lfoClockScaleValue->parameters.scale = 9.9f; - lfoClockScaleValue->parameters.offset = 0.1f; - sig_List_append(&signals, lfoClockScaleValue, status); - - lfoAmpValue = sig_daisy_CVIn_new(&alloc, context, dptHost); - lfoAmpValue->parameters.control = sig_daisy_DPT_CV_IN_2; - sig_List_append(&signals, lfoAmpValue, status); } void InitClock(struct sig_SignalContext* context, struct sig_Status* status) { @@ -61,35 +53,59 @@ void InitClock(struct sig_SignalContext* context, struct sig_Status* status) { } void InitLFO(struct sig_SignalContext* context, struct sig_Status* status) { - lfoClockScale = sig_dsp_Mul_new(&alloc, context); - lfoClockScale->inputs.left = clockFreq->outputs.main; - lfoClockScale->inputs.right = lfoClockScaleValue->outputs.main; - sig_List_append(&signals, lfoClockScale, status); - - lfo = sig_dsp_LFTriangle_new(&alloc, context); - lfo->inputs.freq = lfoClockScale->outputs.main; - lfo->inputs.mul = sig_AudioBlock_newWithValue(&alloc, - context->audioSettings, 1.0f); - sig_List_append(&signals, lfo, status); - - lfoGain = sig_dsp_Mul_new(&alloc, context); - lfoGain->inputs.left = lfo->outputs.main; - lfoGain->inputs.right = lfoAmpValue->outputs.main; - sig_List_append(&signals, lfoGain, status); + lfo1 = sig_daisy_ClockedLFO_new(&alloc, context, dptHost); + sig_List_append(&signals, lfo1, status); + lfo1->parameters.freqScaleCVInputControl = sig_daisy_DPT_CV_IN_1; + lfo1->parameters.lfoGainCVInputControl = sig_daisy_DPT_CV_IN_2; + lfo1->parameters.cvOutputControl = sig_daisy_DPT_CV_OUT_1; + lfo1->inputs.clockFreq = clockFreq->outputs.main; + + lfo2 = sig_daisy_ClockedLFO_new(&alloc, context, dptHost); + sig_List_append(&signals, lfo2, status); + lfo2->parameters.freqScaleCVInputControl = sig_daisy_DPT_CV_IN_3; + lfo2->parameters.lfoGainCVInputControl = sig_daisy_DPT_CV_IN_4; + lfo2->parameters.cvOutputControl = sig_daisy_DPT_CV_OUT_2; + lfo2->inputs.clockFreq = clockFreq->outputs.main; + + lfo3 = sig_daisy_ClockedLFO_new(&alloc, context, dptHost); + sig_List_append(&signals, lfo3, status); + lfo3->inputs.clockFreq = clockFreq->outputs.main; + lfo3->parameters.freqScaleCVInputControl = sig_daisy_DPT_CV_IN_5; + lfo3->parameters.lfoGainCVInputControl = sig_daisy_DPT_CV_IN_6; + lfo3->parameters.cvOutputControl = sig_daisy_DPT_CV_OUT_3; + + lfo4 = sig_daisy_ClockedLFO_new(&alloc, context, dptHost); + sig_List_append(&signals, lfo4, status); + lfo4->inputs.clockFreq = clockFreq->outputs.main; + lfo4->parameters.freqScaleCVInputControl = sig_daisy_DPT_CV_IN_7; + lfo4->parameters.lfoGainCVInputControl = sig_daisy_DPT_CV_IN_8; + lfo4->parameters.cvOutputControl = sig_daisy_DPT_CV_OUT_4; + + lfo1PlusLFO3 = sig_dsp_Add_new(&alloc, context); + sig_List_append(&signals, lfo1PlusLFO3, status); + lfo1PlusLFO3->inputs.left = lfo1->outputs.main; + lfo1PlusLFO3->inputs.right = lfo3->outputs.main; + + lfo2PlusLFO4 = sig_dsp_Add_new(&alloc, context); + sig_List_append(&signals, lfo2PlusLFO4, status); + lfo2PlusLFO4->inputs.left = lfo2->outputs.main; + lfo2PlusLFO4->inputs.right = lfo4->outputs.main; + + lfo1And3Out = sig_daisy_CVOut_new(&alloc, context, dptHost); + sig_List_append(&signals, lfo1And3Out, status); + lfo1And3Out->inputs.source = lfo1PlusLFO3->outputs.main; + lfo1And3Out->parameters.control = sig_daisy_DPT_CV_OUT_5; + lfo1And3Out->parameters.scale = 0.5f; // TODO: Replace with a wavefolder. + + lfo2And4Out = sig_daisy_CVOut_new(&alloc, context, dptHost); + sig_List_append(&signals, lfo2And4Out, status); + lfo2And4Out->inputs.source = lfo2PlusLFO4->outputs.main; + lfo2And4Out->parameters.control = sig_daisy_DPT_CV_OUT_6; + lfo2And4Out->parameters.scale = 0.5f; } void InitCVOutputs(struct sig_SignalContext* context, struct sig_Status* status) { - cv1Out = sig_daisy_CVOut_new(&alloc, context, dptHost); - cv1Out->parameters.control = sig_daisy_DPT_CV_OUT_1; - cv1Out->inputs.source = lfoGain->outputs.main; - sig_List_append(&signals, cv1Out, status); - - // TODO: My DPT seems to output -4.67V to 7.96V, - // this was tuned by hand with the VCV Rack oscilloscope. - cv1Out->parameters.scale = 0.68; - cv1Out->parameters.offset = -0.32; - gate1Out = sig_daisy_GateOut_new(&alloc, context, dptHost); gate1Out->parameters.control = sig_daisy_DPT_GATE_OUT_1; gate1Out->inputs.source = clockInput->outputs.main; @@ -108,7 +124,7 @@ int main(void) { struct sig_AudioSettings audioSettings = { .sampleRate = 48000, .numChannels = 2, - .blockSize = 1 + .blockSize = 48 }; struct sig_Status status; diff --git a/hosts/daisy/include/daisy-bluemchen-host.h b/hosts/daisy/include/daisy-bluemchen-host.h index 53778c6..056d74c 100644 --- a/hosts/daisy/include/daisy-bluemchen-host.h +++ b/hosts/daisy/include/daisy-bluemchen-host.h @@ -1,3 +1,6 @@ +#ifndef SIGNALETIC_DAISY_BLUEMCHENHOST_H +#define SIGNALETIC_DAISY_BLUEMCHENHOST_H + #include "./signaletic-daisy-host.h" #include "../vendor/kxmx_bluemchen/src/kxmx_bluemchen.h" @@ -105,3 +108,5 @@ struct sig_daisy_Host* sig_daisy_NehcmeulbHost_new( 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-dpt-host.h b/hosts/daisy/include/daisy-dpt-host.h index 637690a..1a3557e 100644 --- a/hosts/daisy/include/daisy-dpt-host.h +++ b/hosts/daisy/include/daisy-dpt-host.h @@ -1,3 +1,6 @@ +#ifndef SIGNALETIC_DAISY_DPT_H +#define SIGNALETIC_DAISY_DPT_H + #include "./signaletic-daisy-host.h" #include "../vendor/dpt/lib/daisy_dpt.h" @@ -86,3 +89,5 @@ void sig_daisy_DPTHost_init(struct sig_daisy_DPTHost* self, void sig_daisy_DPTHost_destroy( struct sig_Allocator* allocator, struct sig_daisy_DPTHost* self); + +#endif // SIGNALETIC_DAISY_DPT_H diff --git a/hosts/daisy/include/daisy-patch-sm-host.h b/hosts/daisy/include/daisy-patch-sm-host.h index e48452c..6a36c07 100644 --- a/hosts/daisy/include/daisy-patch-sm-host.h +++ b/hosts/daisy/include/daisy-patch-sm-host.h @@ -1,3 +1,6 @@ +#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" @@ -137,3 +140,5 @@ void sig_daisy_PatchSMHost_Board_init(struct sig_daisy_Host_Board* self, 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/daisy-versio-host.h b/hosts/daisy/include/daisy-versio-host.h index b9e901b..e0b1148 100644 --- a/hosts/daisy/include/daisy-versio-host.h +++ b/hosts/daisy/include/daisy-versio-host.h @@ -1,3 +1,6 @@ +#ifndef SIGNALETIC_DAISY_VERSIO_H +#define SIGNALETIC_DAISY_VERSIO_H + #include "./signaletic-daisy-host.h" #include "../vendor/libDaisy/src/daisy_versio.h" @@ -58,3 +61,5 @@ void sig_daisy_VersioHost_init(struct sig_daisy_Host* self, struct sig_AudioSettings* audioSettings, daisy::DaisyVersio* versio, struct sig_dsp_SignalEvaluator* evaluator); + +#endif // SIGNALETIC_DAISY_VERSIO_H diff --git a/hosts/daisy/include/looper-view.h b/hosts/daisy/include/looper-view.h index 18e0d40..bed5b15 100644 --- a/hosts/daisy/include/looper-view.h +++ b/hosts/daisy/include/looper-view.h @@ -1,3 +1,6 @@ +#ifndef SIGNALETIC_LOOPER_VIEW_H +#define SIGNALETIC_LOOPER_VIEW_H + // Note: This is a C++ file because I haven't gotten around to // considering how to wrap Daisy objects in C, // and doing so doesn't seem hugely important since we're certain @@ -172,3 +175,5 @@ void sig_ui_daisy_LooperView_render(struct sig_ui_daisy_LooperView* self, sig_ui_daisy_LoopRenderer_drawPositionLine(self->loopRenderer, playbackPos, self->positionLineThickness, foregroundOn); } + +#endif // SIGNALETIC_LOOPER_VIEW_H diff --git a/hosts/daisy/include/signaletic-daisy-host.h b/hosts/daisy/include/signaletic-daisy-host.h index 0910c9c..ae2d238 100644 --- a/hosts/daisy/include/signaletic-daisy-host.h +++ b/hosts/daisy/include/signaletic-daisy-host.h @@ -1,3 +1,6 @@ +#ifndef SIGNALETIC_DAISY_HOST_H +#define SIGNALETIC_DAISY_HOST_H + #include #include "daisy.h" @@ -473,3 +476,5 @@ void sig_daisy_AudioIn_destroy(struct sig_Allocator* allocator, struct sig_daisy_Encoder { }; + +#endif /* SIGNALETIC_DAISY_HOST_H */ diff --git a/libsignaletic/include/libsignaletic.h b/libsignaletic/include/libsignaletic.h index 36aed39..7c7beaa 100644 --- a/libsignaletic/include/libsignaletic.h +++ b/libsignaletic/include/libsignaletic.h @@ -1641,6 +1641,7 @@ void sig_dsp_ClockDetector_destroy(struct sig_Allocator* allocator, struct sig_dsp_ClockDetector* self); + struct sig_dsp_LinearToFreq_Inputs { float_array_ptr source; }; diff --git a/libsignaletic/src/libsignaletic.c b/libsignaletic/src/libsignaletic.c index e50bee4..e68dc53 100644 --- a/libsignaletic/src/libsignaletic.c +++ b/libsignaletic/src/libsignaletic.c @@ -1999,21 +1999,10 @@ struct sig_dsp_DustGate* sig_dsp_DustGate_new(struct sig_Allocator* allocator, struct sig_dsp_DustGate); self->reciprocalDensity = sig_dsp_Div_new(allocator, context); - self->reciprocalDensity->inputs.left = context->unity->outputs.main; - self->densityDurationMultiplier = sig_dsp_Mul_new(allocator, context); - self->densityDurationMultiplier->inputs.left = - self->reciprocalDensity->outputs.main; - self->dust = sig_dsp_Dust_new(allocator, context); - self->gate = sig_dsp_TimedGate_new(allocator, context); - self->gate->inputs.trigger = self->dust->outputs.main; - self->gate->inputs.duration = - self->densityDurationMultiplier->outputs.main; - sig_dsp_DustGate_init(self, context); - self->outputs.main = self->gate->outputs.main; return self; } @@ -2022,9 +2011,17 @@ struct sig_dsp_DustGate* sig_dsp_DustGate_new(struct sig_Allocator* allocator, void sig_dsp_DustGate_init(struct sig_dsp_DustGate* self, struct sig_SignalContext* context) { sig_dsp_Signal_init(self, context, *sig_dsp_DustGate_generate); + self->reciprocalDensity->inputs.left = context->unity->outputs.main; + self->densityDurationMultiplier->inputs.left = + self->reciprocalDensity->outputs.main; + self->gate->inputs.trigger = self->dust->outputs.main; + self->gate->inputs.duration = + self->densityDurationMultiplier->outputs.main; + self->outputs.main = self->gate->outputs.main; + sig_CONNECT_TO_SILENCE(self, density, context); sig_CONNECT_TO_SILENCE(self, durationPercentage, context); -}; +} void sig_dsp_DustGate_generate(void* signal) { struct sig_dsp_DustGate* self = (struct sig_dsp_DustGate*) signal; @@ -2182,6 +2179,8 @@ void sig_dsp_ClockDetector_destroy(struct sig_Allocator* allocator, sig_dsp_Signal_destroy(allocator, self); } + + struct sig_dsp_LinearToFreq* sig_dsp_LinearToFreq_new( struct sig_Allocator* allocator, struct sig_SignalContext* context) { struct sig_dsp_LinearToFreq* self = sig_MALLOC(allocator,