~hp/orbit.lv2

9c1822bcbd23470f97f7cea1af3d6ab6c78808cc — Hanspeter Portner 3 months ago 8ab331a
Add time:position atomization function to orbit:midi_sync
4 files changed, 154 insertions(+), 21 deletions(-)

M meson_options.txt
M src/orbit_midi_clock.c
M src/orbit_midi_sync.c
M ttl/orbit.ttl
M meson_options.txt => meson_options.txt +1 -1
@@ 9,4 9,4 @@ option('lv2libdir',
	type : 'string',
	value : 'lib/lv2')

option('version', type : 'string', value : '0.1.707')
option('version', type : 'string', value : '0.1.713')

M src/orbit_midi_clock.c => src/orbit_midi_clock.c +1 -1
@@ 90,7 90,7 @@ _cb(timely_t *timely, int64_t frames, LV2_URID type, void *data)
		if(handle->rolling)
		{
			const uint64_t beats = TIMELY_BAR(timely) * TIMELY_BEATS_PER_BAR(timely)
				+ TIMELY_BAR_BEAT(timely);
				+ TIMELY_BAR_BEAT_RAW(timely);
			const uint16_t midi_beats = beats / 6; // 1 MIDI Beat spans 6 MIDI Clocks

			const uint8_t song_sel [] = {

M src/orbit_midi_sync.c => src/orbit_midi_sync.c +149 -16
@@ 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,

M ttl/orbit.ttl => ttl/orbit.ttl +3 -3
@@ 817,9 817,9 @@ orbit:sync_position
	a lv2:Parameter ;
	rdfs:label "Position" ;
	rdfs:comment "Position" ;
	rdfs:range atom:Int ;
	lv2:minimum 0 ;
	lv2:maximum 16383 .
	rdfs:range atom:Float ;
	lv2:minimum 0.0 ;
	lv2:maximum 16383.0 .

orbit:midiSync
	a lv2:Plugin ,