daisy seed tentative

This commit is contained in:
Stefano D'Angelo 2024-01-31 15:50:07 +01:00
parent 58075f0b3a
commit 6e98d0a324
11 changed files with 299 additions and 1 deletions

1
TODO
View File

@ -24,3 +24,4 @@
* vst3 tail, web process return true/false
* error checking etc. web, especially processor.js
* LV2: round latency output value
* daisy-seed: DAC

View File

@ -0,0 +1,11 @@
include vars.mk
TARGET = ${BUNDLE_NAME}
CPP_SOURCES = src/main.cpp ${CPP_SOURCES_EXTRA}
SYSTEM_FILES_DIR=${LIBDAISY_DIR}/core
include ${SYSTEM_FILES_DIR}/Makefile
#TODO: CFLAGS, LDFLAGS

View File

@ -0,0 +1,4 @@
module.exports = function (data, api) {
api.copyFile(`Makefile`, `Makefile`);
api.generateFileFromTemplateFile(`vars.mk`, `vars.mk`, data);
};

View File

@ -0,0 +1,4 @@
BUNDLE_NAME := {{=it.product.bundleName}}
CFLAGS_EXTRA := {{=it.make && it.make.cflags ? it.make.cflags : ""}} {{=it.daisy_seed_make.cflags ? it.daisy_seed_make.cflags : ""}}
LDFLAGS_EXTRA := {{=it.make && it.make.ldflags ? it.make.ldflags : ""}} {{=it.daisy_seed_make.ldflags ? it.daisy_seed_make.ldflags : ""}}
LIBDAISY_DIR := {{=it.daisy_seed_make.libdaisyDir}}

View File

@ -0,0 +1,43 @@
#define AUDIO_BUS_IN {{=it.product.buses.findIndex(x => x.type == "audio" && x.direction == "input" && !x.cv && !x.sidechain)}}
#define AUDIO_BUS_OUT {{=it.product.buses.findIndex(x => x.type == "audio" && x.direction == "output" && !x.cv && !x.sidechain)}}
#define NUM_CHANNELS_IN {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input" && !x.cv && !x.sidechain) ? (it.product.buses.filter(x => x.type == "audio" && x.direction == "input" && !x.cv && !x.sidechain)[0].channels == "mono" ? 1 : 2) : 0}}
#define NUM_CHANNELS_OUT {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output" && !x.cv && !x.sidechain) ? (it.product.buses.filter(x => x.type == "audio" && x.direction == "output" && !x.cv && !x.sidechain)[0].channels == "mono" ? 1 : 2) : 0}}
#define MIDI_BUS_IN {{=it.product.buses.findIndex(x => x.type == "midi" && x.direction == "input")}}
#define NUM_PARAMETERS {{=it.product.parameters.length}}
#define NUM_ADC {{=it.product.parameters.filter((x, i) => x.direction == "input" && it.daisy_seed.parameterPins[i] >= 0).length}}
#define NUM_DAC {{=it.product.parameters.filter((x, i) => x.direction == "output" && it.daisy_seed.parameterPins[i] >= 0).length}}
#if NUM_PARAMETERS > 0
# define PARAM_BYPASS 1
# define PARAM_TOGGLED (1<<1)
# define PARAM_INTEGER (1<<2)
# define PARAM_MAP_LOG (1<<3)
static struct {
char out;
int8_t pin;
float min;
float max;
float def;
uint32_t flags;
float mapK;
} param_data[NUM_PARAMETERS] = {
{{~it.product.parameters :p:i}}
{
/* .out = */ {{=p.direction == "output" ? 1 : 0}},
/* .pin = */ {{=it.daisy_seed.parameterPins[i]}},
/* .min = */ {{=p.minimum.toExponential()}}f,
/* .max = */ {{=p.maximum.toExponential()}}f,
/* .def = */ {{=p.defaultValue.toExponential()}}f,
/* .flags = */ {{?p.isBypass}}PARAM_BYPASS{{??}}0{{?p.toggled}} | PARAM_TOGGLED{{?}}{{?p.integer}} | PARAM_INTEGER{{?}}{{?p.map == "logarithmic"}}| PARAM_MAP_LOG{{?}}{{?}},
/* .mapK = */ {{?p.map == "logarithmic"}}{{=Number(2.0 * Math.log(Math.sqrt(p.maximum * p.minimum) / Math.abs(p.minimum))).toExponential()}}{{??}}0.0{{?}}f
},
{{~}}
};
#endif

View File

@ -0,0 +1,214 @@
#include <stdlib.h>
#include <stdint.h>
#include "data.h"
#include "plugin.h"
#include <math.h>
#include "daisy_seed.h"
#define BLOCK_SIZE 32
using namespace daisy;
DaisySeed hardware;
#if MIDI_BUS_IN >= 0
MidiUartHandler midi_uart;
MidiUsbHandler midi_usb;
#else
CpuLoadMeter loadMeter;
#endif
plugin instance;
float buf[2][BLOCK_SIZE];
float *bufs[2] = { buf[0], buf[1] };
#if NUM_ADC >= 0
static float clampf(float x, float m, float M) {
return x < m ? m : (x > M ? M : x);
}
static float parameterMap(int i, float v) {
return param_data[i].flags & PARAM_MAP_LOG ? param_data[i].min * expf(param_data[i].mapK * v) : param_data[i].min + (param_data[i].max - param_data[i].min) * v;
}
/*
static float parameterUnmap(int i, float v) {
return param_data[i].flags & PARAM_MAP_LOG ? logf(v / param_data[i].min) / param_data[i].mapK : (v - param_data[i].min) / (param_data[i].max - param_data[i].min);
}
*/
static float parameterAdjust(int i, float v) {
v = param_data[i].flags & (PARAM_BYPASS | PARAM_TOGGLED) ? (v >= 0.5f ? 1.f : 0.f)
: (param_data[i].flags & PARAM_INTEGER ? (int32_t)(v + 0.5f) : v);
return clampf(v, param_data[i].min, param_data[i].max);
}
static void readADCs() {
for (int i = 0, j = 0; i < NUM_PARAMETERS; i++) {
if (param_data[i].out || param_data[i].pin < 0)
continue;
float v = hardware.adc.GetFloat(j);
v = parameterAdjust(i, parameterMap(i, v));
plugin_set_parameter(&instance, i, v);
j++;
}
}
#endif
static void AudioCallback(
AudioHandle::InterleavingInputBuffer in,
AudioHandle::InterleavingOutputBuffer out,
size_t size) {
#if MIDI_BUS_IN < 0
loadMeter.OnBlockStart();
#endif
readADCs();
const size_t n = size >> 1;
#if NUM_CHANNELS_IN > 0
for (size_t i = 0; i < n; i++) {
const size_t j = i << 1;
buf[0][i] = in[j];
# if NUM_CHANNELS_IN > 1
buf[1][i] = in[j + 1];
# endif
}
#endif
plugin_process(&instance, (const float **)bufs, bufs, n);
for (size_t i = 0; i < n; i++) {
const size_t j = i << 1;
#if NUM_CHANNELS_OUT > 0
out[j] = buf[0][i];
#else
out[j] = 0.f;
#endif
#if NUM_CHANNELS_OUT > 1
out[j + 1] = buf[1][i];
#else
out[j + 1] = 0.f;
#endif
}
#if MIDI_BUS_IN < 0
loadMeter.OnBlockEnd();
#endif
}
int main() {
hardware.Configure();
hardware.Init();
#if NUM_ADC >= 0
AdcChannelConfig adcConfig[NUM_ADC];
for (int i = 0, j = 0; i < NUM_PARAMETERS; i++) {
if (param_data[i].out || param_data[i].pin < 0)
continue;
adcConfig[j].InitSingle(hardware.GetPin(param_data[i].pin));
j++;
}
hardware.adc.Init(adcConfig, NUM_ADC);
hardware.adc.Start();
#endif
hardware.SetAudioBlockSize(BLOCK_SIZE);
float sample_rate = hardware.AudioSampleRate();
plugin_init(&instance);
plugin_set_sample_rate(&instance, sample_rate);
if (plugin_mem_req(&instance) != 0)
plugin_mem_set(&instance, (void *)0xc0000000);
#if NUM_PARAMETERS > 0
for (int i = 0, j = 0; i < NUM_PARAMETERS; i++) {
if (param_data[i].out)
continue;
float v = param_data[i].def;
v = parameterAdjust(i, parameterMap(i, v));
plugin_set_parameter(&instance, i, v);
j++;
}
#endif
#if MIDI_BUS_IN < 0
hardware.StartLog();
loadMeter.Init(sample_rate, BLOCK_SIZE);
#endif
#if NUM_ADC >= 0
readADCs();
#endif
plugin_reset(&instance);
hardware.StartAudio(AudioCallback);
while (1) {
#if MIDI_BUS_IN >= 0
midi_usb.Listen();
midi_uart.Listen();
while (midi_usb.HasEvents() || midi_uart.HasEvents()) {
MidiEvent ev = midi_usb.HasEvents() ? midi_usb.PopEvent() : midi_uart.PopEvent();
uint8_t data[3];
switch (ev.type) {
case NoteOff:
data[0] = 0x80;
break;
case NoteOn:
data[0] = 0x90;
break;
case PolyphonicKeyPressure:
data[0] = 0xa0;
break;
case ControlChange:
case ChannelMode:
data[0] = 0xb0;
break;
case ProgramChange:
data[0] = 0xc0;
break;
case ChannelPressure:
data[0] = 0xd0;
break;
case PitchBend:
data[0] = 0xe0;
break;
default:
continue;
break;
}
data[0] |= ev.channel;
data[1] = ev.data[1];
data[2] = ev.data[2];
plugin_midi_msg_in(&instance, MIDI_BUS_IN, data);
}
#else
const float avgLoad = loadMeter.GetAvgCpuLoad();
const float maxLoad = loadMeter.GetMaxCpuLoad();
const float minLoad = loadMeter.GetMinCpuLoad();
hardware.PrintLine("---");
# if NUM_PARAMETERS > 0
for (int i = 0; i < NUM_PARAMETERS; i++)
if (param_data[i].out)
hardware.PrintLine("parameter #%i: %g", i, plugin_get_parameter(&instance, i));
# endif
hardware.PrintLine("---");
hardware.PrintLine("Processing Load %:");
hardware.PrintLine("Max: " FLT_FMT3, FLT_VAR3(maxLoad * 100.0f));
hardware.PrintLine("Avg: " FLT_FMT3, FLT_VAR3(avgLoad * 100.0f));
hardware.PrintLine("Min: " FLT_FMT3, FLT_VAR3(minLoad * 100.0f));
System::Delay(500);
#endif
}
(void)plugin_fini;
#if MIDI_BUS_IN >= 0 && NUM_PARAMETERS > 0
(void)plugin_get_parameter;
#endif
}

View File

@ -0,0 +1,7 @@
var path = require("path");
var sep = path.sep;
module.exports = function (data, api) {
api.generateFileFromTemplateFile(`src${sep}data.h`, `src${sep}data.h`, data);
api.copyFile(`src${sep}main.cpp`, `src${sep}main.cpp`);
};

View File

@ -35,7 +35,7 @@ static double parameterUnmap(Steinberg_Vst_ParamID id, double v) {
}
static double parameterAdjust(Steinberg_Vst_ParamID id, double v) {
v = parameterData[id].flags & (DATA_PARAM_BYPASS | DATA_PARAM_TOGGLED) ? v >= 0.5 ? 1.0 : 0.0
v = parameterData[id].flags & (DATA_PARAM_BYPASS | DATA_PARAM_TOGGLED) ? (v >= 0.5 ? 1.0 : 0.0)
: (parameterData[id].flags & DATA_PARAM_INTEGER ? (int32_t)(v + 0.5) : v);
return clamp(v, parameterData[id].min, parameterData[id].max);
}

View File

@ -0,0 +1,5 @@
{
"daisy_seed_make": {
"libdaisyDir": "../../../libDaisy"
}
}

5
test/daisy-seed.json Normal file
View File

@ -0,0 +1,5 @@
{
"daisy_seed": {
"parameterPins": [ 15, 16, 17, 18, 22 ]
}
}

View File

@ -22,3 +22,7 @@ cp $dir/plugin.h $dir/../out/android/src
$dir/../tibia $dir/product.json,$dir/company.json,$dir/cmd.json $dir/../templates/cmd $dir/../out/cmd
$dir/../tibia $dir/product.json,$dir/company.json,$dir/cmd.json,$dir/cmd-make.json $dir/../templates/cmd-make $dir/../out/cmd
cp $dir/plugin.h $dir/../out/cmd/src
$dir/../tibia $dir/product.json,$dir/company.json,$dir/daisy-seed.json $dir/../templates/daisy-seed $dir/../out/daisy-seed
$dir/../tibia $dir/product.json,$dir/company.json,$dir/daisy-seed.json,$dir/daisy-seed-make.json $dir/../templates/daisy-seed-make $dir/../out/daisy-seed
cp $dir/plugin.h $dir/../out/daisy-seed/src