@@ 19,7 19,7 @@ typedef struct _plughandle_t plughandle_t;
struct _plugstate_t {
// ro
int32_t song;
- int32_t pos;
+ float pos;
int32_t rolling;
int32_t beats_per_minute;
// rw
@@ 45,6 45,8 @@ struct _plughandle_t {
const LV2_Atom_Sequence *event_in;
LV2_Atom_Sequence *event_out;
+ timely_t timely;
+
plugstate_t state;
plugstate_t stash;
@@ 91,6 93,121 @@ static const props_def_t defs [MAX_NPROPS] = {
};
static void
+_position_atomize(plughandle_t *handle, LV2_Atom_Forge *forge, int64_t frames)
+{
+ timely_t *timely = &handle->timely;
+
+ double beats = handle->state.pos / 4; //FIXME handle->state.beat_unit
+ //
+ const int64_t this_clock = handle->nsamples + frames;
+ const int64_t nsamples = this_clock - handle->last_clock;
+ if(handle->last_clock > 0 && nsamples > 0)
+ {
+ //FIXME test this
+ const double offset = nsamples / handle->rate / 60.0 * handle->state.beats_per_minute * handle->state.beat_unit;
+ beats += offset;
+ }
+
+ const double bar_beat = fmod(beats, handle->state.beats_per_bar);
+ const double bar = (beats - bar_beat) / handle->state.beats_per_bar;
+ timely->pos.bar = (int64_t)bar;
+ timely->pos.bar_beat = bar_beat;
+
+ timely->pos.beat_unit = handle->state.beat_unit;
+ timely->pos.beats_per_bar = handle->state.beats_per_bar;
+ timely->pos.beats_per_minute = handle->state.beats_per_minute;
+
+ timely->pos.frame = handle->nsamples + frames;
+ timely->pos.frames_per_second = handle->rate;
+
+ timely->pos.speed = handle->state.rolling ? 1.f : 0.f;
+
+ LV2_Atom_Forge_Frame frame;
+ LV2_Atom_Forge_Ref ref = lv2_atom_forge_frame_time(forge, frames);
+ if(ref)
+ {
+ ref = lv2_atom_forge_object(forge, &frame, 0, timely->urid.time_position);
+ }
+
+ if(ref)
+ {
+ ref = lv2_atom_forge_key(forge, TIMELY_URI_BAR_BEAT(timely));
+ }
+ if(ref)
+ {
+ ref = lv2_atom_forge_float(forge, TIMELY_BAR_BEAT_RAW(timely));
+ }
+
+ if(ref)
+ {
+ ref = lv2_atom_forge_key(forge, TIMELY_URI_BAR(timely));
+ }
+ if(ref)
+ {
+ ref = lv2_atom_forge_long(forge, TIMELY_BAR(timely));
+ }
+
+ if(ref)
+ {
+ ref = lv2_atom_forge_key(forge, TIMELY_URI_BEAT_UNIT(timely));
+ }
+ if(ref)
+ {
+ ref = lv2_atom_forge_int(forge, TIMELY_BEAT_UNIT(timely));
+ }
+
+ if(ref)
+ {
+ ref = lv2_atom_forge_key(forge, TIMELY_URI_BEATS_PER_BAR(timely));
+ }
+ if(ref)
+ {
+ ref = lv2_atom_forge_float(forge, TIMELY_BEATS_PER_BAR(timely));
+ }
+
+ if(ref)
+ {
+ ref = lv2_atom_forge_key(forge, TIMELY_URI_BEATS_PER_MINUTE(timely));
+ }
+ if(ref)
+ {
+ ref = lv2_atom_forge_float(forge, TIMELY_BEATS_PER_MINUTE(timely));
+ }
+
+ if(ref)
+ {
+ ref = lv2_atom_forge_key(forge, TIMELY_URI_FRAME(timely));
+ }
+ if(ref)
+ {
+ ref = lv2_atom_forge_long(forge, TIMELY_FRAME(timely));
+ }
+
+ if(ref)
+ {
+ ref = lv2_atom_forge_key(forge, TIMELY_URI_FRAMES_PER_SECOND(timely));
+ }
+ if(ref)
+ {
+ ref = lv2_atom_forge_float(forge, TIMELY_FRAMES_PER_SECOND(timely));
+ }
+
+ if(ref)
+ {
+ ref = lv2_atom_forge_key(forge, TIMELY_URI_SPEED(timely));
+ }
+ if(ref)
+ {
+ ref = lv2_atom_forge_float(forge, TIMELY_SPEED(timely));
+ }
+
+ if(ref)
+ {
+ lv2_atom_forge_pop(forge, &frame);
+ }
+}
+
+static void
_set_bpm(plughandle_t *handle, LV2_Atom_Forge *forge,
int64_t frames, int32_t bpm)
{
@@ 102,6 219,7 @@ _set_bpm(plughandle_t *handle, LV2_Atom_Forge *forge,
handle->state.beats_per_minute = bpm;
props_set(&handle->props, forge, frames, handle->urid.beats_per_minute, &handle->ref);
+ _position_atomize(handle, forge, frames);
}
static void
@@ 116,11 234,12 @@ _set_song(plughandle_t *handle, LV2_Atom_Forge *forge,
handle->state.song = song;
props_set(&handle->props, forge, frames, handle->urid.song, &handle->ref);
+ _position_atomize(handle, forge, frames);
}
static void
_set_pos_raw(plughandle_t *handle, LV2_Atom_Forge *forge,
- int64_t frames, int32_t pos)
+ int64_t frames, float pos)
{
if(pos == handle->state.pos)
{
@@ 130,16 249,17 @@ _set_pos_raw(plughandle_t *handle, LV2_Atom_Forge *forge,
handle->state.pos = pos;
props_set(&handle->props, forge, frames, handle->urid.pos, &handle->ref);
+ _position_atomize(handle, forge, frames);
}
static void
_set_pos(plughandle_t *handle, LV2_Atom_Forge *forge,
- int64_t frames, int32_t pos)
+ int64_t frames, float pos)
{
_set_pos_raw(handle, forge, frames, pos);
// update clocks based on song position
- handle->clocks = handle->state.pos * 6;
+ handle->clocks = handle->state.pos * 6.f;
}
static void
@@ 154,6 274,7 @@ _set_rolling(plughandle_t *handle, LV2_Atom_Forge *forge,
handle->state.rolling = rolling;
props_set(&handle->props, forge, frames, handle->urid.rolling, &handle->ref);
+ _position_atomize(handle, forge, frames);
}
static void
@@ 171,7 292,7 @@ _handle_midi_song_pos(plughandle_t *handle, LV2_Atom_Forge *forge,
{
const int32_t lsb = m[1];
const int32_t msb = m[2];
- const int32_t pos = (msb << 7) | lsb;
+ const float pos = (msb << 7) | lsb;
_set_pos(handle, forge, frames, pos);
}
@@ 180,7 301,7 @@ static void
_handle_midi_start(plughandle_t *handle, LV2_Atom_Forge *forge,
int64_t frames)
{
- _set_pos(handle, forge, frames, 0);
+ _set_pos(handle, forge, frames, 0.f);
_set_rolling(handle, forge, frames, 1);
}
@@ 203,28 324,31 @@ static void
_handle_midi_clock(plughandle_t *handle, LV2_Atom_Forge *forge,
int64_t frames)
{
+ const int64_t this_clock = handle->nsamples + frames;
+ const int64_t nsamples = this_clock - handle->last_clock;
+ handle->last_clock = this_clock;
+
// advance clock
handle->clocks += 1;
- const int32_t pos = handle->clocks / 6;
+ const float pos = handle->clocks / 6.f;
_set_pos_raw(handle, forge, frames, pos);
- const int64_t this_clock = handle->nsamples + frames;
- const int64_t nsamples = this_clock - handle->last_clock;
- handle->last_clock = this_clock;
-
- const double minutes = nsamples / handle->rate / 60.0;
- const int32_t bpm = 1.0 / 24.0 / minutes; // FIXME use beat_unit
- // FIXME filter this value
+ if(handle->clocks > 1)
+ {
+ const double minutes = nsamples / handle->rate / 60.0;
+ const int32_t bpm = 1.0 / 6 / handle->state.beat_unit / minutes;
+ // FIXME filter this value
- _set_bpm(handle, forge, frames, bpm);
+ _set_bpm(handle, forge, frames, bpm);
+ }
}
static void
_handle_midi(plughandle_t *handle, LV2_Atom_Forge *forge,
int64_t frames, const uint8_t *m)
{
- const uint8_t comm = m[0] & 0xf0;
+ const uint8_t comm = m[0];
switch(comm)
{
@@ 255,6 379,13 @@ _handle_midi(plughandle_t *handle, LV2_Atom_Forge *forge,
}
}
+static void
+_cb(timely_t *timely UNUSED, int64_t frames UNUSED, LV2_URID type UNUSED,
+ UNUSED void *data UNUSED)
+{
+ // do nothing
+}
+
static LV2_Handle
instantiate(const LV2_Descriptor* descriptor, double rate UNUSED,
const char *bundle_path UNUSED, const LV2_Feature *const *features)
@@ 295,6 426,8 @@ instantiate(const LV2_Descriptor* descriptor, double rate UNUSED,
handle->urid.midi_event = handle->map->map(handle->map->handle, LV2_MIDI__MidiEvent);
+ const timely_mask_t mask = 0;
+ timely_init(&handle->timely, handle->map, rate, mask, _cb, handle);
lv2_atom_forge_init(&handle->forge, handle->map);
if(!props_init(&handle->props, descriptor->URI,