clap

CLAP Audio Plugin API
Log | Files | Refs | README | LICENSE

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:
Mexamples/thyns/defs.h | 3+++
Mexamples/thyns/osc.h | 154++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Aexamples/thyns/params.h | 35+++++++++++++++++++++++++++++++++++
Mexamples/thyns/plugin.c | 23++++++++++++++++++++++-
Mexamples/thyns/thyns.h | 13+++++++++++--
Mexamples/thyns/voice.h | 21+++++++++++++++++++++
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(&params->osc1); + thyns_osc_params_init(&params->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(&params->osc1, index, value); + return; + } + + index -= THYNS_OSC_PARAM_COUNT; + if (index < THYNS_OSC_PARAM_COUNT) { + thyns_osc_param_set(&params->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 = &params->osc1.waveform; + voice->osc1.pwm = &params->osc1.pwm; + voice->osc1.phase = &params->osc1.phase; + voice->osc1.tune = &params->osc1.tune; + + // osc2 + voice->osc2.waveform = &params->osc2.waveform; + voice->osc2.pwm = &params->osc2.pwm; + voice->osc2.phase = &params->osc2.phase; + voice->osc2.tune = &params->osc2.tune; +} + +static inline void thyns_voice_start_note(struct thyns_voice *voice, uint32_t key, float freq)