commit 5a2806b26c16710aeda17359b572804f9f934daf
parent 60d4e1206803b32a229d5fc99ea3d1e2fba89a58
Author: Alexandre Bique <bique.alexandre@gmail.com>
Date: Fri, 21 Nov 2014 01:33:06 +0100
Synthesizer + jack host works!!!
Diffstat:
9 files changed, 223 insertions(+), 44 deletions(-)
diff --git a/examples/thyns/dlist.h b/examples/thyns/dlist.h
@@ -3,6 +3,8 @@
# define thyns_dlist_push_back(Head, Item) \
do { \
+ assert((Item)->prev == NULL); \
+ assert((Item)->next == NULL); \
if (!(Head)) { \
(Head) = (Item); \
(Item)->next = (Item); \
@@ -17,12 +19,18 @@
# define thyns_dlist_remove(Head, Item) \
do { \
- (Item)->next->prev = (Item)->prev; \
- (Item)->prev->next = (Item)->next; \
+ assert((Head)); \
+ assert((Item)->prev); \
+ assert((Item)->next); \
+ if ((Item)->next == (Item)) \
+ (Head) = NULL; \
+ else { \
+ (Head) = (Item)->next; \
+ (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
@@ -14,16 +14,11 @@ enum thyns_env_state
struct thyns_env
{
- // params
- uint32_t a; // duration in ms
- uint32_t d; // duration in ms
- double s; // sustain level
- uint32_t r; // duration in ms
-
// state
enum thyns_env_state state;
double ar; // attack ramp
double dr; // decay ramp
+ double s; // sustain level
double rr; // release ramp
double v;
};
@@ -32,6 +27,10 @@ static inline void thyns_env_init(struct thyns_env * restrict env)
{
env->state = THYNS_ENV_IDLE;
env->v = 0;
+ env->ar = 0.0001;
+ env->dr = 0.0001;
+ env->s = 0.7;
+ env->rr = 0.00001;
}
static inline void thyns_env_restart(struct thyns_env * restrict env)
@@ -39,6 +38,11 @@ static inline void thyns_env_restart(struct thyns_env * restrict env)
env->state = THYNS_ENV_ATTACK;
}
+static inline void thyns_env_release(struct thyns_env * restrict env)
+{
+ env->state = THYNS_ENV_RELEASE;
+}
+
static inline double thyns_env_step(struct thyns_env * restrict env)
{
switch (env->state) {
@@ -51,7 +55,7 @@ static inline double thyns_env_step(struct thyns_env * restrict env)
break;
case THYNS_ENV_DECAY:
- env->v += env->dr;
+ env->v -= env->dr;
if (env->v <= env->s) {
env->v = env->s;
env->state = THYNS_ENV_SUSTAIN;
@@ -62,7 +66,7 @@ static inline double thyns_env_step(struct thyns_env * restrict env)
break;
case THYNS_ENV_RELEASE:
- env->v += env->rr;
+ env->v -= env->rr;
if (env->v <= 0) {
env->v = 0;
env->state = THYNS_ENV_IDLE;
diff --git a/examples/thyns/osc.h b/examples/thyns/osc.h
@@ -9,7 +9,7 @@ enum thyns_osc_type
THYNS_OSC_SQUARE = 1,
THYNS_OSC_SAW = 2,
THYNS_OSC_TRI = 3,
- THYNS_OSC_SIN = 4,
+ THYNS_OSC_SINE = 4,
};
struct thyns_osc
@@ -31,12 +31,13 @@ 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->pi_sr = M_PI / ((float)sr);
+ osc->type = THYNS_OSC_SQUARE;
osc->pwm = 0.5;
osc->freq = 0;
osc->angle = 0;
osc->phase = 0;
+ osc->tune = 0;
}
static inline void
@@ -49,7 +50,7 @@ thyns_osc_set_freq(struct thyns_osc *osc, double freq)
static inline double
thyns_osc_step(struct thyns_osc *osc)
{
- osc->angle += fmod(osc->angle + osc->angle_ramp, 2 * M_PI);
+ osc->angle = fmod(osc->angle + osc->angle_ramp, 2 * M_PI);
double angle = fmod(osc->angle + osc->phase, 2 * M_PI);
switch (osc->type) {
@@ -67,7 +68,7 @@ thyns_osc_step(struct thyns_osc *osc)
return angle * 2.0 / M_PI - 1;
return (2 * M_PI - angle) * 2.0 / M_PI - 1;
- case THYNS_OSC_SIN:
+ case THYNS_OSC_SINE:
return sin(angle);
default:
diff --git a/examples/thyns/thyns.h b/examples/thyns/thyns.h
@@ -38,30 +38,30 @@ static inline void thyns_init(struct thyns *thyns, uint32_t sr)
static double thyns_step(struct thyns *thyns,
struct clap_process *process)
{
+ if (!thyns->singing)
+ return 0;
+
double out = 0;
struct thyns_voice *prev = NULL;
struct thyns_voice *v = thyns->singing;
+ struct thyns_voice *end = v->prev;
- while (v) {
+ do {
out += thyns_voice_step(v);
// can we release the voice?
if (v->amp_env.state == THYNS_ENV_IDLE) {
- if (prev) {
- prev->next = v->next;
- v->next = thyns->idle;
- thyns->idle = v;
- v = prev->next;
- } else {
- v->next = thyns->idle;
- thyns->idle = v;
- v = thyns->singing;
- }
+ printf("releasing %d\n", v->key);
+ assert(v->key != 0);
+ thyns->keys[v->key] = NULL;
+ thyns_dlist_remove(thyns->singing, v);
+ thyns_dlist_push_back(thyns->idle, v);
+ v = prev ? prev->next : thyns->singing;
} else {
prev = v;
v = v->next;
}
- }
+ } while (v && prev != end && v != prev);
return out;
}
@@ -73,6 +73,7 @@ thyns_note_on(struct thyns *thyns,
{
struct thyns_voice *voice = NULL;
+ printf("note_on(%d, %f)\n", key, pitch);
assert(key < 0x80);
if (thyns->keys[key]) {
voice = thyns->keys[key];
@@ -87,6 +88,7 @@ thyns_note_on(struct thyns *thyns,
}
thyns_dlist_push_back(thyns->singing, voice);
thyns->keys[key] = voice;
+ voice->key = key;
}
thyns_voice_start_note(thyns->keys[key], key, pitch);
@@ -96,6 +98,10 @@ static inline void
thyns_note_off(struct thyns *thyns,
uint8_t key)
{
+ printf("note_off(%d)\n", key);
+ assert(key < 0x80);
+ if (thyns->keys[key])
+ thyns_voice_stop_note(thyns->keys[key], key);
}
static inline void
@@ -138,6 +144,9 @@ thyns_process(struct thyns *thyns, struct clap_process *process)
process->output[1][i] = process->output[0][i];
}
+ // ensure no more events are left
+ assert(!ev);
+
if (thyns->singing)
return CLAP_PROCESS_CONTINUE;
return CLAP_PROCESS_STOP;
diff --git a/examples/thyns/voice.h b/examples/thyns/voice.h
@@ -13,7 +13,7 @@ struct thyns_voice
uint32_t sr; // sample rate
double pi_sr; // M_PI / sample_rate
- uint32_t key;
+ uint8_t key;
float freq;
// osc part
@@ -47,13 +47,14 @@ thyns_voice_init(struct thyns_voice *voice, uint32_t sr)
// filter
thyns_filt_init(&voice->filt, sr);
- thyns_filt_set_cutoff(&voice->filt, 1000);
+ voice->filt.cutoff = 4000;
+ voice->filt.resonance = 1.5;
thyns_env_init(&voice->filt_env);
- voice->filt_env_depth = 0;
+ voice->filt_env_depth = 0.2;
// amp
thyns_env_init(&voice->amp_env);
- voice->amp = 0.7;
+ voice->amp = 0.2;
}
static inline void
@@ -68,19 +69,27 @@ thyns_voice_start_note(struct thyns_voice *voice,
thyns_env_restart(&voice->amp_env);
}
+static inline void
+thyns_voice_stop_note(struct thyns_voice *voice,
+ uint32_t key)
+{
+ thyns_env_release(&voice->filt_env);
+ thyns_env_release(&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);
double oscm = osc1 * (1 - voice->osc_mix) + osc2 * voice->osc_mix;
-
- double fenv = thyns_env_step(&voice->filt_env);
+ double fenv = thyns_env_step(&voice->filt_env) * voice->filt_env_depth;
double cutoff = exp(log(voice->filt.cutoff) + fenv);
thyns_filt_set_cutoff(&voice->filt, cutoff);
double filtered = thyns_filt_step(&voice->filt, oscm);
+ double amp = voice->amp * thyns_env_step(&voice->amp_env);
- return filtered * voice->amp * thyns_env_step(&voice->amp_env);
+ return filtered * amp;
}
#endif /* !VOICE_H */
diff --git a/include/clap/clap-midi-parser.c b/include/clap/clap-midi-parser.c
@@ -1,4 +1,146 @@
#include <assert.h>
+#include <math.h>
+
+static inline float
+clap_midi_pitch(uint8_t key)
+{
+ return 440.0f * powf(2, (key - 57.f) / 12.f);
+}
+
+// for i in $(seq 0 127);
+// do
+// calc "440.0 * 2.0 ^ ((${i}.0 - 57.0) / 12.0)"
+// done | sed -r 's/\t(.*)$/ \1,/g'
+static const float clap_midi_pitches[128] = {
+ 16.3515978312874146696,
+ 17.323914436054506016,
+ 18.354047994837972516,
+ 19.4454364826300569232,
+ 20.6017223070543706096,
+ 21.8267644645627427796,
+ 23.1246514194771499336,
+ 24.499714748859330882,
+ 25.9565435987465711576,
+ 27.5,
+ 29.1352350948806197776,
+ 30.8677063285077569896,
+ 32.7031956625748293348,
+ 34.647828872109012032,
+ 36.708095989675945032,
+ 38.890872965260113842,
+ 41.2034446141087412192,
+ 43.6535289291254855548,
+ 46.2493028389542998672,
+ 48.9994294977186617596,
+ 51.9130871974931423152,
+ 55,
+ 58.2704701897612395508,
+ 61.7354126570155139792,
+ 65.4063913251496586696,
+ 69.295657744218024064,
+ 73.416191979351890064,
+ 77.781745930520227684,
+ 82.406889228217482434,
+ 87.3070578582509711096,
+ 92.4986056779085997344,
+ 97.9988589954373235236,
+ 103.8261743949862846304,
+ 110,
+ 116.5409403795224791016,
+ 123.4708253140310279584,
+ 130.8127826502993173392,
+ 138.5913154884360481236,
+ 146.8323839587037801324,
+ 155.563491861040455368,
+ 164.813778456434964868,
+ 174.6141157165019422236,
+ 184.9972113558171994688,
+ 195.9977179908746470428,
+ 207.6523487899725692608,
+ 220,
+ 233.0818807590449582032,
+ 246.9416506280620559168,
+ 261.6255653005986346784,
+ 277.1826309768720962472,
+ 293.6647679174075602648,
+ 311.126983722080910736,
+ 329.627556912869929736,
+ 349.2282314330038844472,
+ 369.9944227116343989332,
+ 391.9954359817492940856,
+ 415.3046975799451385216,
+ 440,
+ 466.1637615180899164064,
+ 493.8833012561241118292,
+ 523.2511306011972693568,
+ 554.3652619537441924988,
+ 587.3295358348151205252,
+ 622.253967444161821472,
+ 659.255113825739859472,
+ 698.45646286600776889,
+ 739.9888454232687978664,
+ 783.9908719634985881712,
+ 830.6093951598902770432,
+ 880,
+ 932.3275230361798328128,
+ 987.7666025122482236628,
+ 1046.5022612023945387092,
+ 1108.7305239074883849932,
+ 1174.6590716696302410504,
+ 1244.507934888323642944,
+ 1318.510227651479718944,
+ 1396.91292573201553778,
+ 1479.9776908465375957328,
+ 1567.9817439269971763424,
+ 1661.2187903197805540908,
+ 1760,
+ 1864.65504607235966563,
+ 1975.5332050244964473212,
+ 2093.0045224047890774228,
+ 2217.4610478149767699908,
+ 2349.3181433392604821008,
+ 2489.0158697766472858924,
+ 2637.020455302959437888,
+ 2793.8258514640310755644,
+ 2959.95538169307519147,
+ 3135.9634878539943526848,
+ 3322.4375806395611081816,
+ 3520,
+ 3729.3100921447193312556,
+ 3951.0664100489928946468,
+ 4186.0090448095781548456,
+ 4434.9220956299535399816,
+ 4698.636286678520964206,
+ 4978.0317395532945717804,
+ 5274.0409106059188757716,
+ 5587.6517029280621511244,
+ 5919.91076338615038294,
+ 6271.9269757079887053696,
+ 6644.8751612791222163588,
+ 7040,
+ 7458.6201842894386625156,
+ 7902.1328200979857892936,
+ 8372.0180896191563096912,
+ 8869.8441912599070799632,
+ 9397.2725733570419284076,
+ 9956.0634791065891435652,
+ 10548.0818212118377515476,
+ 11175.3034058561243022532,
+ 11839.82152677230076588,
+ 12543.8539514159774107436,
+ 13289.7503225582444327176,
+ 14080,
+ 14917.2403685788773250312,
+ 15804.2656401959715785828,
+ 16744.0361792383126193824,
+ 17739.688382519814159922,
+ 18794.5451467140838568196,
+ 19912.126958213178287126,
+ 21096.1636424236755030952,
+ 22350.606811712248604502,
+ 23679.6430535446015317556,
+ 25087.7079028319548214828,
+};
static inline uint16_t
clap_midi_parse_be16(const uint8_t *in)
@@ -66,8 +208,8 @@ clap_midi_parse_channel_event(struct clap_midi_parser *parser)
if (parser->size < 3)
return CLAP_MIDI_PARSER_EOB;
- parser->channel.event_type = parser->in[0] & 0xf;
- parser->channel.channel = parser->in[0] >> 4;
+ parser->channel.event_type = parser->in[0] >> 4;
+ parser->channel.channel = parser->in[0] & 0xf;
parser->channel.param1 = parser->in[1];
parser->channel.param2 = parser->in[2];
@@ -104,7 +246,7 @@ clap_midi_parse_meta_event(struct clap_midi_parser *parser)
static inline enum clap_midi_parser_status
clap_midi_parse_event(struct clap_midi_parser *parser)
{
- if ((parser->in[0] & 0xf) <= 0xe)
+ if ((parser->in[0] >> 4) <= 0xe)
return clap_midi_parse_channel_event(parser);
if (parser->in[0] == 0xff)
return clap_midi_parse_meta_event(parser);
@@ -114,7 +256,7 @@ clap_midi_parse_event(struct clap_midi_parser *parser)
static inline enum clap_midi_parser_status
clap_midi_parse(struct clap_midi_parser *parser)
{
- if (!parser->in || parser->size < 4)
+ if (!parser->in || parser->size < 1)
return CLAP_MIDI_PARSER_EOB;
switch (parser->state) {
@@ -157,20 +299,23 @@ clap_midi_convert(const uint8_t *in,
event->note.key = parser.channel.param1;
event->note.velocity = ((float)parser.channel.param2) / 127.0f;
event->note.events = NULL;
- break;
+ event->note.pitch = clap_midi_pitches[event->note.key];
+ return;
case CLAP_MIDI_CHANNEL_NOTE_ON:
event->type = CLAP_EVENT_NOTE_ON;
event->note.key = parser.channel.param1;
event->note.velocity = ((float)parser.channel.param2) / 127.0f;
event->note.events = NULL;
- break;
+ event->note.pitch = clap_midi_pitches[event->note.key];
+ return;
}
default:
+ printf("midi\n");
event->type = CLAP_EVENT_MIDI;
event->midi.buffer = in;
event->midi.size = size;
- break;
+ return;
}
}
diff --git a/include/clap/clap.h b/include/clap/clap.h
@@ -137,6 +137,8 @@ struct clap_event_note
struct clap_event_param
{
+ bool is_global; // is this event global?
+ uint8_t key; // if !is_global, target key
uint32_t index;
union clap_param_value value;
float increment; // for param ramp
diff --git a/tools/clap-jack-host/CMakeLists.txt b/tools/clap-jack-host/CMakeLists.txt
@@ -1,2 +1,2 @@
add_executable(clap-jack-host clap-jack-host.c)
-target_link_libraries(clap-jack-host jack dl)
+target_link_libraries(clap-jack-host jack dl m)
diff --git a/tools/clap-jack-host/clap-jack-host.c b/tools/clap-jack-host/clap-jack-host.c
@@ -87,6 +87,7 @@ int process(jack_nframes_t nframes, void *arg)
p.output = out;
p.samples_count = nframes;
p.is_offline = false;
+ p.steady_time = app->steady_time;
// XXX add time info
/* convert midi events */