commit 32d46742354cbfc365f9d25976de2af365472445
parent fb4a32caf74330809a0ec8ddb64b9876ab48e1e1
Author: Alexandre Bique <bique.alexandre@gmail.com>
Date: Wed, 3 Dec 2014 23:04:10 +0100
Initial tentative for parameters automations
Diffstat:
6 files changed, 234 insertions(+), 15 deletions(-)
diff --git a/examples/thyns/defs.h b/examples/thyns/defs.h
@@ -5,6 +5,9 @@
# include <math.h>
# include <assert.h>
+# include <clap/clap.h>
+# include <clap/ext/params.h>
+
# ifndef M_PI
# define M_PI 3.14159265358979323846
# endif
diff --git a/examples/thyns/osc.h b/examples/thyns/osc.h
@@ -12,48 +12,178 @@ enum thyns_osc_waveform
THYNS_OSC_SINE = 4,
};
+static const char * const thyns_osc_waveform_name[] = {
+ "none",
+ "square",
+ "saw",
+ "tri",
+ "sine",
+};
+
+enum thyns_osc_param_index
+{
+ THYNS_OSC_PARAM_WAVEFORM = 0,
+ THYNS_OSC_PARAM_PHASE,
+ THYNS_OSC_PARAM_PWM,
+ THYNS_OSC_PARAM_TUNE,
+ THYNS_OSC_PARAM_COUNT
+};
+
+struct thyns_osc_params
+{
+ enum thyns_osc_waveform waveform;
+ double pwm; // 0..1
+ double phase;
+ double tune;
+};
+
struct thyns_osc
{
+ /* processing constants */
uint32_t sr; // sample rate
double pi_sr; // M_PI / sample_rate
- enum thyns_osc_waveform waveform;
- double pwm; // 0..1
-
- double tune;
+ /* oscillator state */
double freq;
double angle_ramp;
double angle;
- double phase;
+
+ /* parameters */
+ enum thyns_osc_waveform *waveform;
+ double *pwm; // 0..1
+ double *phase;
+ double *tune;
};
+void
+thyns_osc_param_set(struct thyns_osc_params *params,
+ uint32_t index,
+ union clap_param_value value)
+{
+ switch (index) {
+ case THYNS_OSC_PARAM_WAVEFORM:
+ params->waveform = value.i;
+ break;
+
+ case THYNS_OSC_PARAM_PHASE:
+ params->phase = value.f;
+ break;
+
+ case THYNS_OSC_PARAM_PWM:
+ params->pwm = value.f;
+ break;
+
+ case THYNS_OSC_PARAM_TUNE:
+ params->tune = value.f;
+ break;
+ }
+}
+
+void
+thyns_osc_param_info(struct thyns_osc_params *params,
+ uint32_t index,
+ struct clap_param *param,
+ const char *prefix)
+{
+#define P(Dst, Args...) snprintf(Dst, sizeof (Dst), Args);
+
+ switch (index) {
+ case THYNS_OSC_PARAM_WAVEFORM:
+ P(param->id, "%s%s", prefix, "waveform");
+ P(param->name, "%s", "waveform");
+ P(param->desc, "%s", "Oscillator's waveform");
+ P(param->display, "%s", thyns_osc_waveform_name[params->waveform]);
+ param->type = CLAP_PARAM_ENUM;
+ param->is_per_note = true;
+ param->is_used = true;
+ param->is_periodic = false;
+ param->value.i = params->waveform;
+ param->min.i = 0;
+ param->max.i = THYNS_OSC_SINE;
+ param->scale = CLAP_PARAM_LINEAR;
+ break;
+
+ case THYNS_OSC_PARAM_PHASE:
+ P(param->id, "%s%s", prefix, "phase");
+ P(param->name, "%s", "phase");
+ P(param->desc, "%s", "Oscillator's phase");
+ P(param->display, "%f", params->phase);
+ param->type = CLAP_PARAM_FLOAT;
+ param->is_per_note = true;
+ param->is_used = true;
+ param->is_periodic = true;
+ param->value.f = params->phase;
+ param->min.f = 0;
+ param->max.f = 2 * M_PI;
+ param->scale = CLAP_PARAM_LINEAR;
+ break;
+
+ case THYNS_OSC_PARAM_PWM:
+ P(param->id, "%s%s", prefix, "pwm");
+ P(param->name, "%s", "pwm");
+ P(param->desc, "%s", "Oscillator's pulse width modulation");
+ P(param->display, "%f", params->pwm);
+ param->type = CLAP_PARAM_FLOAT;
+ param->is_per_note = true;
+ param->is_used = true;
+ param->is_periodic = false;
+ param->value.f = params->pwm;
+ param->min.f = 0;
+ param->max.f = 1;
+ param->scale = CLAP_PARAM_LINEAR;
+ break;
+
+ case THYNS_OSC_PARAM_TUNE:
+ P(param->id, "%s%s", prefix, "tune");
+ P(param->name, "%s", "tune");
+ P(param->desc, "%s", "Oscillator's tunning in semitones");
+ P(param->display, "%f", params->pwm);
+ param->type = CLAP_PARAM_FLOAT;
+ param->is_per_note = true;
+ param->is_used = true;
+ param->is_periodic = false;
+ param->value.f = params->tune;
+ param->min.f = -48;
+ param->max.f = +48;
+ param->scale = CLAP_PARAM_LINEAR;
+ break;
+ }
+
+#undef P
+}
+
+static inline void
+thyns_osc_params_init(struct thyns_osc_params *params)
+{
+ params->waveform = THYNS_OSC_SQUARE;
+ params->pwm = 0.5;
+ params->phase = 0;
+ params->tune = 0;
+}
+
static inline void
thyns_osc_init(struct thyns_osc *osc, uint32_t sr)
{
osc->sr = sr;
osc->pi_sr = M_PI / ((float)sr);
- osc->waveform = THYNS_OSC_SQUARE;
- osc->pwm = 0.5;
osc->freq = 0;
osc->angle = 0;
- osc->phase = 0;
- osc->tune = 0;
}
static inline void
thyns_osc_set_freq(struct thyns_osc *osc, double freq)
{
osc->freq = freq;
- osc->angle_ramp = 2 * osc->pi_sr * freq * pow(2, osc->tune);
+ osc->angle_ramp = 2 * osc->pi_sr * freq * pow(2, *osc->tune / 12.f);
}
static inline double
thyns_osc_step(struct thyns_osc *osc)
{
osc->angle = fmod(osc->angle + osc->angle_ramp, 2 * M_PI);
- double angle = fmod(osc->angle + osc->phase, 2 * M_PI);
+ double angle = fmod(osc->angle + *osc->phase, 2 * M_PI);
- switch (osc->waveform) {
+ switch (*osc->waveform) {
case THYNS_OSC_NONE:
return 0;
diff --git a/examples/thyns/params.h b/examples/thyns/params.h
@@ -0,0 +1,35 @@
+#ifndef PARAMS_H
+# define PARAMS_H
+
+struct thyns_params
+{
+ struct thyns_osc_params osc1;
+ struct thyns_osc_params osc2;
+};
+
+static void
+thyns_params_init(struct thyns_params *params)
+{
+ thyns_osc_params_init(¶ms->osc1);
+ thyns_osc_params_init(¶ms->osc2);
+}
+
+static void
+thyns_params_set(struct thyns_params *params,
+ uint32_t index,
+ union clap_param_value value)
+{
+ if (index < THYNS_OSC_PARAM_COUNT) {
+ thyns_osc_param_set(¶ms->osc1, index, value);
+ return;
+ }
+
+ index -= THYNS_OSC_PARAM_COUNT;
+ if (index < THYNS_OSC_PARAM_COUNT) {
+ thyns_osc_param_set(¶ms->osc2, index, value);
+ return;
+ }
+}
+
+
+#endif /* !PARAMS_H */
diff --git a/examples/thyns/plugin.c b/examples/thyns/plugin.c
@@ -1,7 +1,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <clap/clap.h>
-#include <clap/ext/ports.h>
+#include <clap/ext/params.h>
#include "thyns.h"
@@ -10,6 +10,7 @@ struct thyns_plugin
struct thyns thyns;
struct clap_plugin plugin;
struct clap_host *host;
+ struct clap_plugin_params params;
};
void
@@ -65,6 +66,10 @@ thyns_plugin_process(struct clap_plugin *plugin,
void *
thyns_plugin_extension(struct clap_plugin *plugin, const char *extension)
{
+ struct thyns_plugin *p = plugin->plugin_data;
+
+ if (!strcmp(extension, CLAP_EXT_PARAMS))
+ return &p->params;
return NULL;
}
@@ -79,6 +84,20 @@ thyns_plugin_deactivate(struct clap_plugin *plugin)
{
}
+uint32_t
+thyns_params_count(struct clap_plugin *plugin)
+{
+ return 2 * THYNS_OSC_PARAM_COUNT;
+}
+
+bool
+thyns_params_get(struct clap_plugin *plugin,
+ uint32_t index,
+ struct clap_param *param)
+{
+ return false;
+}
+
struct thyns_plugin *
thyns_plugin_create(struct clap_host *host,
uint32_t sample_rate)
@@ -102,6 +121,8 @@ thyns_plugin_create(struct clap_host *host,
p->plugin.extension = thyns_plugin_extension;
p->plugin.activate = thyns_plugin_activate;
p->plugin.deactivate = thyns_plugin_deactivate;
+ p->params.count = thyns_params_count;
+ p->params.get = thyns_params_get;
return p;
}
diff --git a/examples/thyns/thyns.h b/examples/thyns/thyns.h
@@ -1,10 +1,9 @@
#ifndef THYNS_H
# define THYNS_H
-# include <clap/clap.h>
-
# include "voice.h"
# include "dlist.h"
+# include "params.h"
# define THYNS_VOICE_COUNT 32
@@ -19,6 +18,7 @@ struct thyns
struct thyns_voice *idle;
struct thyns_voice *keys[0x80];
+ struct thyns_params params;
struct thyns_voice buffer[THYNS_VOICE_COUNT];
};
@@ -29,6 +29,8 @@ static inline void thyns_init(struct thyns *thyns, uint32_t sr)
thyns->sr = sr;
thyns->pi_sr = M_PI / sr;
+ thyns_params_init(&thyns->params);
+
for (uint32_t i = 0; i < THYNS_VOICE_COUNT; ++i) {
thyns_voice_init(thyns->buffer + i, sr);
thyns_dlist_push_back(thyns->idle, thyns->buffer + i);
@@ -46,6 +48,7 @@ static double thyns_step(struct thyns *thyns,
struct thyns_voice *v = thyns->singing;
struct thyns_voice *end = v->prev;
+ /* compute voices */
do {
out += thyns_voice_step(v);
@@ -89,6 +92,7 @@ thyns_note_on(struct thyns *thyns,
thyns_dlist_push_back(thyns->singing, voice);
thyns->keys[key] = voice;
voice->key = key;
+ thyns_voice_params_init(voice, &thyns->params);
}
thyns_voice_start_note(thyns->keys[key], key, pitch);
@@ -117,6 +121,11 @@ thyns_handle_event(struct thyns *thyns,
thyns_note_off(thyns, ev->note.key);
break;
+ case CLAP_EVENT_PARAM_SET:
+ if (ev->param.is_global)
+ thyns_params_set(&thyns->params, ev->param.index, ev->param.value);
+ break;
+
default:
break;
}
diff --git a/examples/thyns/voice.h b/examples/thyns/voice.h
@@ -4,6 +4,7 @@
# include "env.h"
# include "filt.h"
# include "osc.h"
+# include "params.h"
struct thyns_voice
{
@@ -29,6 +30,9 @@ struct thyns_voice
// amp
struct thyns_env amp_env;
double amp;
+
+ // voice parameters
+ struct thyns_params params;
};
static inline void
@@ -58,6 +62,23 @@ thyns_voice_init(struct thyns_voice *voice, uint32_t sr)
}
static inline void
+thyns_voice_params_init(struct thyns_voice *voice,
+ struct thyns_params *params)
+{
+ // osc1
+ voice->osc1.waveform = ¶ms->osc1.waveform;
+ voice->osc1.pwm = ¶ms->osc1.pwm;
+ voice->osc1.phase = ¶ms->osc1.phase;
+ voice->osc1.tune = ¶ms->osc1.tune;
+
+ // osc2
+ voice->osc2.waveform = ¶ms->osc2.waveform;
+ voice->osc2.pwm = ¶ms->osc2.pwm;
+ voice->osc2.phase = ¶ms->osc2.phase;
+ voice->osc2.tune = ¶ms->osc2.tune;
+}
+
+static inline void
thyns_voice_start_note(struct thyns_voice *voice,
uint32_t key,
float freq)