From a94ba4cb9f65c16faec6fb5824e94481033fc06a Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 8 Jul 2012 06:38:00 +0000 Subject: Sync to transport position events provided by the host. Consistently initialise pad state. git-svn-id: http://svn.drobilla.net/lad/trunk/plugins/matriseq@4516 a436a847-0d15-0410-975c-d299462d15a1 --- matriseq.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++------------ matriseq.ttl | 8 +++--- 2 files changed, 74 insertions(+), 21 deletions(-) diff --git a/matriseq.c b/matriseq.c index 1831599..1027535 100644 --- a/matriseq.c +++ b/matriseq.c @@ -28,6 +28,7 @@ #include "lv2/lv2plug.in/ns/ext/atom/forge.h" #include "lv2/lv2plug.in/ns/ext/log/log.h" #include "lv2/lv2plug.in/ns/ext/midi/midi.h" +#include "lv2/lv2plug.in/ns/ext/time/time.h" #include "lv2/lv2plug.in/ns/ext/urid/urid.h" #include "lv2/lv2plug.in/ns/lv2core/lv2.h" @@ -47,8 +48,14 @@ typedef enum { // URIDs used by this plugin typedef struct { + LV2_URID atom_Blank; + LV2_URID atom_Float; LV2_URID log_Error; LV2_URID midi_MidiEvent; + LV2_URID time_Position; + LV2_URID time_barBeat; + LV2_URID time_beatsPerMinute; + LV2_URID time_speed; } MatriseqURIs; typedef struct { @@ -73,6 +80,7 @@ typedef struct { // State double rate; float bpm; + float speed; uint32_t beats_per_bar; uint32_t time_frames; uint32_t step; @@ -123,8 +131,14 @@ instantiate(const LV2_Descriptor* descriptor, // Initialise LV2 stuff LV2_URID_Map* map = self->map; - self->uris.log_Error = map->map(map->handle, LV2_LOG__Error); - self->uris.midi_MidiEvent = map->map(map->handle, LV2_MIDI__MidiEvent); + self->uris.atom_Blank = map->map(map->handle, LV2_ATOM__Blank); + self->uris.atom_Float = map->map(map->handle, LV2_ATOM__Float); + self->uris.log_Error = map->map(map->handle, LV2_LOG__Error); + self->uris.midi_MidiEvent = map->map(map->handle, LV2_MIDI__MidiEvent); + self->uris.time_Position = map->map(map->handle, LV2_TIME__Position); + self->uris.time_barBeat = map->map(map->handle, LV2_TIME__barBeat); + self->uris.time_beatsPerMinute = map->map(map->handle, LV2_TIME__beatsPerMinute); + self->uris.time_speed = map->map(map->handle, LV2_TIME__speed); lv2_atom_forge_init(&self->forge, self->map); // Initialise USB stuff @@ -134,6 +148,7 @@ instantiate(const LV2_Descriptor* descriptor, // Initialise state self->rate = rate; self->bpm = 140.0f; + self->speed = 0.0f; self->beats_per_bar = 4; self->page_y = 1; // Start at note 36 (kick) @@ -179,6 +194,15 @@ set_button(Matriseq* self, NaubControlID control, bool active) naub_set_control(self->naub, control, value); } +static void +set_column(Matriseq* self, uint32_t step, bool active) +{ + for (int y = 0; y < 8; ++y) { + const NaubControlID control = { 0, 0, step % GRID_W, y }; + set_button(self, control, active); + } +} + static void set_page_indicators(Matriseq* self) { @@ -254,6 +278,8 @@ pad_thread(void* instance) // Initialise pad set_page_indicators(self); + set_column(self, step, true); + naub_flush(self->naub); while (!naub_handle_events_timeout(self->naub, 10) && !self->exit) { uint32_t new_step; @@ -265,18 +291,12 @@ pad_thread(void* instance) // De-highlight old active row if (step >= begin && step < end) { - for (int y = 0; y < 8; ++y) { - const NaubControlID control = { 0, 0, step % GRID_W, y }; - set_button(self, control, false); - } + set_column(self, step, false); } // Highlight new active row if (new_step >= begin && new_step < end) { - for (int y = 0; y < 8; ++y) { - const NaubControlID control = { 0, 0, new_step % GRID_W, y }; - set_button(self, control, true); - } + set_column(self, new_step, true); } // Send bulk update to device @@ -309,7 +329,8 @@ activate(LV2_Handle instance) static void run(LV2_Handle instance, uint32_t n_frames) { - Matriseq* self = (Matriseq*)instance; + Matriseq* self = (Matriseq*)instance; + const MatriseqURIs* uris = &self->uris; const float s_per_beat = 60.0f / self->bpm; const float s_per_step = s_per_beat * self->beats_per_bar / STEP_TYPE; @@ -322,16 +343,46 @@ run(LV2_Handle instance, uint32_t n_frames) LV2_Atom_Forge_Frame out_frame; lv2_atom_forge_sequence_head(&self->forge, &out_frame, 0); - for (uint32_t i = 0; i < n_frames; ++i) { + // Work forwards in time frame by frame, handling events as we go + const LV2_Atom_Sequence* in = self->in; + LV2_Atom_Event* ev = lv2_atom_sequence_begin(&in->body); + for (uint32_t t = 0; t < n_frames; ++t) { + while (!lv2_atom_sequence_is_end(&in->body, in->atom.size, ev) && + ev->time.frames == t) { + if (ev->body.type == uris->atom_Blank) { + const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body; + if (obj->body.otype == uris->time_Position) { + // Update transport position and speed + LV2_Atom *beat = NULL, *bpm = NULL, *speed = NULL; + lv2_atom_object_get(obj, + uris->time_barBeat, &beat, + uris->time_beatsPerMinute, &bpm, + uris->time_speed, &speed, + NULL); + if (bpm && bpm->type == uris->atom_Float) { + self->bpm = ((LV2_Atom_Float*)bpm)->body; + } + if (beat && beat->type == uris->atom_Float) { + self->time_frames = (((LV2_Atom_Float*)beat)->body + * s_per_beat + * self->rate); + } + if (speed && speed->type == uris->atom_Float) { + self->speed = ((LV2_Atom_Float*)speed)->body; + } + } + } + + ev = lv2_atom_sequence_next(ev); + } + const double time_s = self->time_frames / self->rate; const uint32_t step = (uint32_t)(time_s / s_per_step) % STEP_TYPE; if (step != self->step) { - // Update step and frame time + // Update step self->step = step; if (step == 0) { self->time_frames = 0; - } else { - ++self->time_frames; } // Notify USB thread of new step @@ -341,12 +392,14 @@ run(LV2_Handle instance, uint32_t n_frames) for (uint32_t y = 0; y < SEQ_H; ++y) { if (self->seq[y][step]) { const uint8_t ev[] = { 0x90, NOTE_MIN + y, 0x40 }; - lv2_atom_forge_frame_time(&self->forge, i); + lv2_atom_forge_frame_time(&self->forge, t); lv2_atom_forge_atom(&self->forge, 3, self->uris.midi_MidiEvent); lv2_atom_forge_write(&self->forge, ev, 3); } } - } else { + } + + if (self->speed) { ++self->time_frames; } } diff --git a/matriseq.ttl b/matriseq.ttl index 2abf153..be253ef 100644 --- a/matriseq.ttl +++ b/matriseq.ttl @@ -2,8 +2,10 @@ @prefix doap: . @prefix foaf: . @prefix lv2: . +@prefix midi: . @prefix rdf: . @prefix rdfs: . +@prefix time: . a foaf:Person ; @@ -22,8 +24,7 @@ a lv2:InputPort , atom:AtomPort ; atom:bufferType atom:Sequence ; - atom:supports , - ; + atom:supports time:Position ; lv2:index 0 ; lv2:symbol "in" ; lv2:name "In" @@ -31,8 +32,7 @@ a lv2:OutputPort , atom:AtomPort ; atom:bufferType atom:Sequence ; - atom:supports , - ; + atom:supports midi:MidiEvent ; lv2:index 1 ; lv2:symbol "out" ; lv2:name "Out" -- cgit v1.2.1