Skip to content

Commit

Permalink
lichen-community-systemsgh-66: Updates the DPT LFOs example to use al…
Browse files Browse the repository at this point in the history
…l outputs.
  • Loading branch information
colinbdclark committed Nov 20, 2023
1 parent 43b6e03 commit b00e4a0
Show file tree
Hide file tree
Showing 11 changed files with 212 additions and 56 deletions.
2 changes: 1 addition & 1 deletion hosts/daisy/examples/bluemchen/calibrator/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Project Name
TARGET ?= signaletic-bluemchen-calibrator

DEBUG = 0
DEBUG = 1
OPT = -O0

# Sources
Expand Down
110 changes: 110 additions & 0 deletions hosts/daisy/examples/dpt/lfos/include/signaletic-dpt-lfos-signals.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#include <libsignaletic.h>
#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);
}

102 changes: 59 additions & 43 deletions hosts/daisy/examples/dpt/lfos/src/signaletic-dpt-lfos.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "daisy.h"
#include <libsignaletic.h>
#include "../include/signaletic-dpt-lfos-signals.h"
#include "../../../../include/daisy-dpt-host.h"

#define HEAP_SIZE 1024 * 256 // 256KB
Expand Down Expand Up @@ -29,29 +29,21 @@ 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,
struct sig_Status* status) {
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) {
Expand All @@ -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;
Expand All @@ -108,7 +124,7 @@ int main(void) {
struct sig_AudioSettings audioSettings = {
.sampleRate = 48000,
.numChannels = 2,
.blockSize = 1
.blockSize = 48
};

struct sig_Status status;
Expand Down
5 changes: 5 additions & 0 deletions hosts/daisy/include/daisy-bluemchen-host.h
Original file line number Diff line number Diff line change
@@ -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"

Expand Down Expand Up @@ -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
5 changes: 5 additions & 0 deletions hosts/daisy/include/daisy-dpt-host.h
Original file line number Diff line number Diff line change
@@ -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"

Expand Down Expand Up @@ -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
5 changes: 5 additions & 0 deletions hosts/daisy/include/daisy-patch-sm-host.h
Original file line number Diff line number Diff line change
@@ -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"

Expand Down Expand Up @@ -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
5 changes: 5 additions & 0 deletions hosts/daisy/include/daisy-versio-host.h
Original file line number Diff line number Diff line change
@@ -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"

Expand Down Expand Up @@ -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
5 changes: 5 additions & 0 deletions hosts/daisy/include/looper-view.h
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
5 changes: 5 additions & 0 deletions hosts/daisy/include/signaletic-daisy-host.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#ifndef SIGNALETIC_DAISY_HOST_H
#define SIGNALETIC_DAISY_HOST_H

#include <libsignaletic.h>
#include "daisy.h"

Expand Down Expand Up @@ -473,3 +476,5 @@ void sig_daisy_AudioIn_destroy(struct sig_Allocator* allocator,
struct sig_daisy_Encoder {

};

#endif /* SIGNALETIC_DAISY_HOST_H */
1 change: 1 addition & 0 deletions libsignaletic/include/libsignaletic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down
23 changes: 11 additions & 12 deletions libsignaletic/src/libsignaletic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit b00e4a0

Please sign in to comment.