clap

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

commit 78394dd926f80c146c3723510c104af978b1cfaa
parent efb5a262f0aeca23923e607bb80513e6003d3f4b
Author: Alexandre Bique <bique.alexandre@gmail.com>
Date:   Thu, 23 Oct 2014 19:05:07 +0200

thyns: note on, note off

Diffstat:
Aexamples/thyns/dlist.h | 28++++++++++++++++++++++++++++
Mexamples/thyns/env.h | 2+-
Mexamples/thyns/filt.h | 19++++++++++++-------
Mexamples/thyns/osc.h | 20++++++++++++++------
Mexamples/thyns/thyns.h | 62+++++++++++++++++++++++++++++++++++++++++++++++---------------
Mexamples/thyns/voice.h | 35+++++++++++++++++++++++++++--------
6 files changed, 129 insertions(+), 37 deletions(-)

diff --git a/examples/thyns/dlist.h b/examples/thyns/dlist.h @@ -0,0 +1,28 @@ +#ifndef DLIST_H +# define DLIST_H + +# define thyns_dlist_push_back(Head, Item) \ + do { \ + if (!(Head)) { \ + (Head) = (Item); \ + (Item)->next = (Item); \ + (Item)->prev = (Item); \ + } else { \ + (Item)->next = (Head); \ + (Item)->prev = (Head)->prev; \ + (Item)->prev->next = (Item); \ + (Item)->next->prev = (Item); \ + } \ + } while (0) + +# define thyns_dlist_remove(Head, Item) \ + do { \ + (Item)->next->prev = (Item)->prev; \ + (Item)->prev->next = (Item)->next; \ + (Item)->next = NULL; \ + (Item)->prev = NULL; \ + if ((Head) == (Item)) \ + (Head) = NULL; \ + } while (0) + +#endif /* !DLIST_H */ diff --git a/examples/thyns/env.h b/examples/thyns/env.h @@ -31,12 +31,12 @@ struct thyns_env static inline void thyns_env_init(struct thyns_env * restrict env) { env->state = THYNS_ENV_IDLE; + env->v = 0; } static inline void thyns_env_restart(struct thyns_env * restrict env) { env->state = THYNS_ENV_ATTACK; - env->v = 0; } static inline double thyns_env_step(struct thyns_env * restrict env) diff --git a/examples/thyns/filt.h b/examples/thyns/filt.h @@ -10,6 +10,9 @@ struct thyns_filt { + uint32_t sr; // sample rate + double pi_sr; // M_PI / sample_rate + double cutoff; // in hz double resonance; @@ -24,21 +27,23 @@ struct thyns_filt float y4; // delayed feedback }; -static inline void thyns_filt_init(struct thyns_filt *filt) +static inline void +thyns_filt_init(struct thyns_filt *filt, uint32_t sr) { memset(filt, 0, sizeof (*filt)); + filt->sr = sr; + filt->pi_sr = M_PI / sr; } -static inline void thyns_filt_set_cutoff(struct thyns_filt *filt, - double cutoff, - double pi_sr) +static inline void +thyns_filt_set_cutoff(struct thyns_filt *filt, double cutoff) { - filt->g = tan(pi_sr * cutoff); + filt->g = tan(filt->pi_sr * cutoff); filt->g_div = 1.0 / (1.0 + filt->g); } -static inline double thyns_filt_step(struct thyns_filt *filt, - double in) +static inline double +thyns_filt_step(struct thyns_filt *filt, double in) { double x0 = in - filt->resonance * filt->y4; double y1 = (filt->g * tanh(x0) + filt->iceq1) * filt->g_div; diff --git a/examples/thyns/osc.h b/examples/thyns/osc.h @@ -14,17 +14,24 @@ enum thyns_osc_type struct thyns_osc { + uint32_t sr; // sample rate + double pi_sr; // M_PI / sample_rate + enum thyns_osc_type type; double pwm; // 0..1 + double tune; double freq; double angle_ramp; double angle; double phase; }; -static inline void thyns_osc_init(struct thyns_osc *osc) +static inline void + thyns_osc_init(struct thyns_osc *osc, uint32_t sr) { + osc->sr = sr; + osc->pi_sr = M_PI / sr; osc->type = THYNS_OSC_NONE; osc->pwm = 0.5; osc->freq = 0; @@ -32,14 +39,15 @@ static inline void thyns_osc_init(struct thyns_osc *osc) osc->phase = 0; } -static inline void thyns_osc_set_freq(struct thyns_osc *osc, - double freq, - double pi_sr) +static inline void +thyns_osc_set_freq(struct thyns_osc *osc, double freq) { - osc->angle_ramp = 2 * pi_sr * freq; + osc->freq = freq; + osc->angle_ramp = 2 * osc->pi_sr * freq * pow(2, osc->tune); } -static inline double thyns_osc_step(struct thyns_osc *osc) +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); diff --git a/examples/thyns/thyns.h b/examples/thyns/thyns.h @@ -4,34 +4,35 @@ # include <clap/clap.h> # include "voice.h" +# include "dlist.h" # define THYNS_VOICE_COUNT 32 struct thyns { - uint32_t sr; // sample rate + uint32_t sr; // sample rate double pi_sr; // M_PI / sample_rate uint64_t steady_time; - struct thyns_voice *running; + struct thyns_voice *singing; struct thyns_voice *idle; + struct thyns_voice *keys[0x80]; struct thyns_voice buffer[THYNS_VOICE_COUNT]; }; static inline void thyns_init(struct thyns *thyns, uint32_t sr) { + memset(thyns, 0, sizeof (*thyns)); + thyns->sr = sr; thyns->pi_sr = M_PI / sr; - thyns->running = NULL; - thyns->idle = thyns->buffer; for (uint32_t i = 0; i < THYNS_VOICE_COUNT; ++i) { thyns_voice_init(thyns->buffer + i, sr); - thyns->buffer[i].next = thyns->buffer + i + 1; + thyns_dlist_push_back(thyns->idle, thyns->buffer + i); } - thyns->buffer[THYNS_VOICE_COUNT - 1].next = NULL; } static double thyns_step(struct thyns *thyns, @@ -39,7 +40,7 @@ static double thyns_step(struct thyns *thyns, { double out = 0; struct thyns_voice *prev = NULL; - struct thyns_voice *v = thyns->running; + struct thyns_voice *v = thyns->singing; while (v) { out += thyns_voice_step(v); @@ -54,7 +55,7 @@ static double thyns_step(struct thyns *thyns, } else { v->next = thyns->idle; thyns->idle = v; - v = thyns->running; + v = thyns->singing; } } else { prev = v; @@ -65,18 +66,49 @@ static double thyns_step(struct thyns *thyns, return out; } -static inline struct thyns_voice * -thyns_find_voice(struct thyns *thyns, uint8_t note) +static inline void +thyns_note_on(struct thyns *thyns, + uint8_t key, + float pitch) +{ + struct thyns_voice *voice = NULL; + + assert(key < 0x80); + if (thyns->keys[key]) { + voice = thyns->keys[key]; + } else { + if (thyns->idle) { + voice = thyns->idle; + thyns_dlist_remove(thyns->idle, voice); + } else { + voice = thyns->singing; + thyns_dlist_remove(thyns->singing, voice); + thyns->keys[voice->key] = NULL; + } + thyns_dlist_push_back(thyns->singing, voice); + thyns->keys[key] = voice; + } + + thyns_voice_start_note(thyns->keys[key], key, pitch); +} + +static inline void +thyns_note_off(struct thyns *thyns, + uint8_t key) { - // XXX - return NULL; } -static inline void thyns_handle_event(struct thyns *thyns, - struct clap_event *ev) +static inline void +thyns_handle_event(struct thyns *thyns, + struct clap_event *ev) { switch (ev->type) { case CLAP_EVENT_NOTE_ON: + thyns_note_on(thyns, ev->note.key, ev->note.pitch); + break; + + case CLAP_EVENT_NOTE_OFF: + thyns_note_off(thyns, ev->note.key); break; default: @@ -105,7 +137,7 @@ static inline void thyns_process(struct thyns *thyns, process->output[0][i] = thyns_step(thyns, process); } - process->need_processing = thyns->running; + process->need_processing = thyns->singing; } #endif /* !THYNS_H */ diff --git a/examples/thyns/voice.h b/examples/thyns/voice.h @@ -7,12 +7,14 @@ struct thyns_voice { + struct thyns_voice *prev; struct thyns_voice *next; uint32_t sr; // sample rate double pi_sr; // M_PI / sample_rate - float freq; + uint32_t key; + float freq; // osc part struct thyns_osc osc1; @@ -29,19 +31,23 @@ struct thyns_voice double amp; }; -static void thyns_voice_init(struct thyns_voice *voice, uint32_t sr) +static inline void +thyns_voice_init(struct thyns_voice *voice, uint32_t sr) { + voice->prev = NULL; + voice->next = NULL; + voice->sr = sr; voice->pi_sr = M_PI / sr; // osc - thyns_osc_init(&voice->osc1); - thyns_osc_init(&voice->osc2); + thyns_osc_init(&voice->osc1, sr); + thyns_osc_init(&voice->osc2, sr); voice->osc_mix = 0; // filter - thyns_filt_init(&voice->filt); - thyns_filt_set_cutoff(&voice->filt, 1000, voice->pi_sr); + thyns_filt_init(&voice->filt, sr); + thyns_filt_set_cutoff(&voice->filt, 1000); thyns_env_init(&voice->filt_env); voice->filt_env_depth = 0; @@ -50,7 +56,20 @@ static void thyns_voice_init(struct thyns_voice *voice, uint32_t sr) voice->amp = 0.7; } -double thyns_voice_step(struct thyns_voice *voice) +static inline void +thyns_voice_start_note(struct thyns_voice *voice, + uint32_t key, + float freq) +{ + thyns_osc_set_freq(&voice->osc1, freq); + thyns_osc_set_freq(&voice->osc2, freq); + + thyns_env_restart(&voice->filt_env); + thyns_env_restart(&voice->amp_env); +} + +static inline double +thyns_voice_step(struct thyns_voice *voice) { double osc1 = thyns_osc_step(&voice->osc1); double osc2 = thyns_osc_step(&voice->osc2); @@ -58,7 +77,7 @@ double thyns_voice_step(struct thyns_voice *voice) double fenv = thyns_env_step(&voice->filt_env); double cutoff = exp(log(voice->filt.cutoff) + fenv); - thyns_filt_set_cutoff(&voice->filt, cutoff, voice->pi_sr); + thyns_filt_set_cutoff(&voice->filt, cutoff); double filtered = thyns_filt_step(&voice->filt, oscm); return filtered * voice->amp * thyns_env_step(&voice->amp_env);