summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--matriseq.c87
-rw-r--r--matriseq.ttl8
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)
@@ -180,6 +195,15 @@ set_button(Matriseq* self, NaubControlID control, bool active)
}
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)
{
const NaubControlID page_x_but = { 0, 1, self->page_x, 0 };
@@ -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: <http://usefulinc.com/ns/doap#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
+@prefix midi: <http://lv2plug.in/ns/ext/midi#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix time: <http://lv2plug.in/ns/ext/time#> .
<http://drobilla.net/drobilla#me>
a foaf:Person ;
@@ -22,8 +24,7 @@
a lv2:InputPort ,
atom:AtomPort ;
atom:bufferType atom:Sequence ;
- atom:supports <http://lv2plug.in/ns/ext/midi#MidiEvent> ,
- <http://lv2plug.in/ns/ext/patch#Message> ;
+ 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 <http://lv2plug.in/ns/ext/midi#MidiEvent> ,
- <http://lv2plug.in/ns/ext/patch#Message> ;
+ atom:supports midi:MidiEvent ;
lv2:index 1 ;
lv2:symbol "out" ;
lv2:name "Out"