Browse Source

let plugin know when UI is on or off

master
Alexandros Theodotou 3 years ago
parent
commit
0626dbb832
Signed by: alex
GPG Key ID: 022EAE42313D70F3
  1. 234
      src/zlfo.c
  2. 60
      src/zlfo_common.h
  3. 10
      src/zlfo_ttl_gen.c
  4. 48
      src/zlfo_ui.c

234
src/zlfo.c

@ -62,9 +62,43 @@ typedef struct ZLFO @@ -62,9 +62,43 @@ typedef struct ZLFO
float * rnd_out;
float * custom_out;
/** Transport speed (0.0 is stopped, 1.0 is
* normal playback, -1.0 is reverse playback,
* etc.). */
float speed;
float bpm;
/** Frames per beat. */
float frames_per_beat;
int beat_unit;
/** This is how far we are inside a beat, from 0.0
* to 1.0. */
float beat_offset;
/**
* Effective frequency.
*
* This is either the free-running frequency,
* or the frequency corresponding to the current
* sync rate.
*/
float effective_freq;
/** Frequency during the last run. */
float last_freq;
/**
* Whether the plugin was freerunning in the
* last cycle.
*
* This is used to detect changes in freerunning/
* sync.
*/
int was_freerunning;
/** Plugin samplerate. */
double samplerate;
@ -78,6 +112,9 @@ typedef struct ZLFO @@ -78,6 +112,9 @@ typedef struct ZLFO
*/
long current_sample;
/** Global current sample in the host. */
long host_current_sample;
/** Atom forge. */
LV2_Atom_Forge forge;
LV2_Atom_Forge_Frame notify_frame;
@ -143,8 +180,7 @@ instantiate ( @@ -143,8 +180,7 @@ instantiate (
/* map uris */
map_uris (self->map, &self->uris);
lv2_atom_forge_init (
&self->forge, self->map);
lv2_atom_forge_init (&self->forge, self->map);
return (LV2_Handle) self;
}
@ -284,10 +320,49 @@ send_messages_to_ui ( @@ -284,10 +320,49 @@ send_messages_to_ui (
lv2_atom_forge_pop (&self->forge, &frame);
}
/**
* Gets the current frequency.
*/
static float
get_freq (
ZLFO * self)
{
if (*self->freerun > 0.f)
{
return *self->freq;
}
else
{
/* if host does not send position info,
* send frequency back instead */
if (self->beat_unit == 0)
{
log_error (
self->log, &self->uris,
"Have not received time info from host "
"yet. Beat unit is unknown.");
return * self->freq;
}
/* bpm / (60 * BU * sync note) */
float sync_note =
sync_rate_to_float (
(SyncRate) *self->sync_rate,
(SyncRateType) *self->sync_rate_type);
return
self->bpm /
(60.f * self->beat_unit * sync_note);
}
}
static void
recalc_multipliers (
ZLFO * self)
{
self->effective_freq = get_freq (self);
fprintf (stderr, "effective freq is %f\n", (double) self->effective_freq);
/*
* F = frequency
* X = samples processed
@ -309,7 +384,8 @@ recalc_multipliers ( @@ -309,7 +384,8 @@ recalc_multipliers (
* ? radians = X samples * sine_multiplier
*/
self->sine_multiplier =
(*self->freq / (float) self->samplerate) *
(self->effective_freq /
(float) self->samplerate) *
2.f * PI;
/*
@ -332,12 +408,43 @@ recalc_multipliers ( @@ -332,12 +408,43 @@ recalc_multipliers (
* ? value = ((X samples * saw_multiplier) % 1) * 2 - 1
*/
self->saw_up_multiplier =
(*self->freq / (float) self->samplerate);
(self->effective_freq /
(float) self->samplerate);
self->period_size =
(uint32_t)
((float) self->samplerate / * self->freq);
self->current_sample = 0;
if (*self->freerun > 0.0001f) /* freerunning */
{
self->period_size =
(uint32_t)
((float) self->samplerate /
self->effective_freq);
self->current_sample = 0;
}
else /* synced */
{
if (self->beat_unit == 0)
{
/* set reasonable values if host does not
* send time info */
self->period_size =
(uint32_t)
((float) self->samplerate /
self->effective_freq);
self->current_sample = 0;
}
else
{
self->period_size =
(uint32_t)
(self->frames_per_beat *
self->beat_unit *
sync_rate_to_float (
*self->sync_rate,
*self->sync_rate_type));
self->current_sample =
(uint32_t)
(self->beat_offset * self->period_size);
}
}
}
static void
@ -349,6 +456,49 @@ activate ( @@ -349,6 +456,49 @@ activate (
recalc_multipliers (self);
}
static void
update_position (
ZLFO * self,
const LV2_Atom_Object * obj)
{
ZLfoUris * uris = &self->uris;
/* Received new transport position/speed */
LV2_Atom *beat = NULL,
*bpm = NULL,
*beat_unit = NULL,
*speed = NULL;
lv2_atom_object_get (
obj, uris->time_barBeat, &beat,
uris->time_beatUnit, &beat_unit,
uris->time_beatsPerMinute, &bpm,
uris->time_speed, &speed, NULL);
if (bpm && bpm->type == uris->atom_Float)
{
/* Tempo changed, update BPM */
self->bpm = ((LV2_Atom_Float*)bpm)->body;
}
if (speed && speed->type == uris->atom_Float)
{
/* Speed changed, e.g. 0 (stop) to 1 (play) */
self->speed =
((LV2_Atom_Float *) speed)->body;
}
if (beat_unit && beat_unit->type == uris->atom_Int)
{
self->beat_unit =
((LV2_Atom_Int *) beat_unit)->body;
}
if (beat && beat->type == uris->atom_Float)
{
self->frames_per_beat =
60.0f / self->bpm * (float) self->samplerate;
const float bar_beats =
((LV2_Atom_Float *) beat)->body;
self->beat_offset = fmodf (bar_beats, 1.f);
}
}
static void
run (
LV2_Handle instance,
@ -356,10 +506,58 @@ run ( @@ -356,10 +506,58 @@ run (
{
ZLFO * self = (ZLFO *) instance;
/* if freq changed, set the multipliers */
if (fabsf (self->last_freq - *self->freq) >
0.0001f)
int xport_changed = 0;
/* read incoming events from host and UI */
LV2_ATOM_SEQUENCE_FOREACH (
self->control, ev)
{
self->host_current_sample = ev->time.frames;
if (lv2_atom_forge_is_object_type (
&self->forge, ev->body.type))
{
const LV2_Atom_Object * obj =
(const LV2_Atom_Object*)&ev->body;
if (obj->body.otype ==
self->uris.time_Position)
{
update_position (self, obj);
xport_changed = 1;
}
else if (obj->body.otype ==
self->uris.ui_on)
{
self->ui_active = 1;
fprintf (stderr, "UI IS ACTIVE\n\n");
}
else if (obj->body.otype ==
self->uris.ui_off)
{
self->ui_active = 0;
fprintf (stderr, "UI IS OFF\n\n");
}
}
}
int freq_changed =
fabsf (
self->last_freq - *self->freq) >
0.0001f;
int is_freerunning = *self->freerun > 0.0001f;
int sync_or_freerun_changed =
self->was_freerunning &&
!is_freerunning;
/* if freq or transport changed, reset the
* multipliers */
if (xport_changed || freq_changed ||
sync_or_freerun_changed)
{
fprintf (
stderr,
"xport %d freq %d sync %d\n",
xport_changed, freq_changed,
sync_or_freerun_changed);
recalc_multipliers (self);
}
@ -483,16 +681,26 @@ run ( @@ -483,16 +681,26 @@ run (
#undef ADJUST_RANGE
self->current_sample++;
if (is_freerunning ||
(!is_freerunning && self->speed >
0.00001f))
{
self->current_sample++;
}
if (self->current_sample ==
self->period_size)
self->current_sample = 0;
}
fprintf (stderr, "current sample %ld\n", self->current_sample);
/* remember frequency */
self->last_freq = *self->freq;
self->was_freerunning = is_freerunning;
send_messages_to_ui (self);
if (self->ui_active)
{
send_messages_to_ui (self);
}
}
static void

60
src/zlfo_common.h

@ -34,6 +34,7 @@ @@ -34,6 +34,7 @@
#include "lv2/atom/atom.h"
#include "lv2/log/log.h"
#include "lv2/urid/urid.h"
#include "lv2/time/time.h"
/** Min, max and default frequency. */
#define MIN_FREQ 0.1f
@ -54,13 +55,23 @@ typedef struct ZLfoUris @@ -54,13 +55,23 @@ typedef struct ZLfoUris
LV2_URID log_Note;
LV2_URID log_Trace;
LV2_URID log_Warning;
LV2_URID time_Position;
LV2_URID time_bar;
LV2_URID time_barBeat;
LV2_URID time_beatsPerMinute;
LV2_URID time_beatUnit;
LV2_URID time_frame;
LV2_URID time_speed;
/* custom URIs */
/* object */
LV2_URID ui_state;
LV2_URID ui_on;
LV2_URID ui_off;
LV2_URID ui_state_current_sample;
LV2_URID ui_state_samplerate;
/** Messages for UI on/off. */
LV2_URID ui_on;
LV2_URID ui_off;
} ZLfoUris;
typedef enum PortIndex
@ -171,6 +182,40 @@ typedef enum CurveAlgorithm @@ -171,6 +182,40 @@ typedef enum CurveAlgorithm
CURVE_ALGORITHM_SUPERELLIPSE,
} CurveAlgorithm;
static inline float
sync_rate_to_float (
SyncRate rate,
SyncRateType type)
{
switch (rate)
{
case SYNC_1_128:
return 1.f / 128.f;
case SYNC_1_64:
return 1.f / 64.f;
case SYNC_1_32:
return 1.f / 32.f;
case SYNC_1_16:
return 1.f / 16.f;
case SYNC_1_8:
return 1.f / 8.f;
case SYNC_1_4:
return 1.f / 4.f;
case SYNC_1_2:
return 1.f / 2.f;
case SYNC_1_1:
return 1.f;
case SYNC_2_1:
return 2.f;
case SYNC_4_1:
return 4.f;
default:
break;
}
return 0.f;
}
static inline void
map_uris (
LV2_URID_Map* map,
@ -179,6 +224,7 @@ map_uris ( @@ -179,6 +224,7 @@ map_uris (
#define MAP(x,uri) \
uris->x = map->map (map->handle, uri)
/* official URIs */
MAP (atom_Blank, LV2_ATOM__Blank);
MAP (atom_Object, LV2_ATOM__Object);
MAP (atom_Float, LV2_ATOM__Float);
@ -191,6 +237,16 @@ map_uris ( @@ -191,6 +237,16 @@ map_uris (
MAP (log_Note, LV2_LOG__Note);
MAP (log_Trace, LV2_LOG__Trace);
MAP (log_Warning, LV2_LOG__Warning);
MAP (time_Position, LV2_TIME__Position);
MAP (time_bar, LV2_TIME__bar);
MAP (time_barBeat, LV2_TIME__barBeat);
MAP (
time_beatsPerMinute, LV2_TIME__beatsPerMinute);
MAP (time_beatUnit, LV2_TIME__beatUnit);
MAP (time_frame, LV2_TIME__frame);
MAP (time_speed, LV2_TIME__speed);
/* custom URIs */
MAP (ui_on, LFO_URI "#ui_on");
MAP (ui_off, LFO_URI "#ui_off");
MAP (ui_state, LFO_URI "#ui_state");

10
src/zlfo_ttl_gen.c

@ -59,10 +59,11 @@ int main ( @@ -59,10 +59,11 @@ int main (
fprintf (f,
"@prefix atom: <http://lv2plug.in/ns/ext/atom#> .\n\
@prefix doap: <http://usefulinc.com/ns/doap#> .\n\
@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n\
@prefix midi: <http://lv2plug.in/ns/ext/midi#> .\n\
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n\
@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\
@prefix time: <http://lv2plug.in/ns/ext/time#> .\n\
@prefix urid: <http://lv2plug.in/ns/ext/urid#> .\n\
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .\n\
@prefix log: <http://lv2plug.in/ns/ext/log#> .\n\n");
@ -85,11 +86,12 @@ int main ( @@ -85,11 +86,12 @@ int main (
a lv2:InputPort ,\n\
atom:AtomPort ;\n\
atom:bufferType atom:Sequence ;\n\
atom:supports time:Position ;\n\
lv2:index 0 ;\n\
lv2:designation lv2:control ;\n\
lv2:symbol \"control\" ;\n\
lv2:name \"Control\" ;\n\
rdfs:comment \"GUI to plugin communication\" ;\n\
rdfs:comment \"GUI/host to plugin communication\" ;\n\
] , [\n\
a lv2:OutputPort ,\n\
atom:AtomPort ;\n\
@ -363,9 +365,9 @@ int main ( @@ -363,9 +365,9 @@ int main (
fprintf (f,
"<" LFO_UI_URI ">\n\
a ui:X11UI ;\n\
lv2:requiredFeature urid:map ;\n\
lv2:requiredFeature urid:map ,\n\
ui:idleInterface ;\n\
lv2:optionalFeature log:log ,\n\
ui:idleInterface,\n\
ui:noUserResize ;\n\
lv2:extensionData ui:idleInterface ,\n\
ui:showInterface ;\n\

48
src/zlfo_ui.c

@ -1110,27 +1110,27 @@ mid_region_bg_draw_cb ( @@ -1110,27 +1110,27 @@ mid_region_bg_draw_cb (
widget->rect.y + 105);
cairo_stroke (cr);
#if 0
/*#if 0*/
/* draw current position */
long period_size =
(long)
((float) self->samplerate / self->freq);
double total_space = 8 * space;
double total_space = GRID_WIDTH;
double current_offset =
(double) self->current_sample /
(double) period_size;
cairo_move_to (
cr,
widget->rect.x + hpadding +
widget->rect.x + GRID_HPADDING +
current_offset * total_space,
widget->rect.y + 46);
cairo_line_to (
cr,
widget->rect.x + hpadding +
widget->rect.x + GRID_HPADDING +
current_offset * total_space,
widget->rect.y + 164);
cairo_stroke (cr);
#endif
/*#endif*/
if (self->wave_mode == WAVE_CUSTOM)
{
@ -1969,6 +1969,23 @@ instantiate ( @@ -1969,6 +1969,23 @@ instantiate (
(LV2UI_Widget)
puglGetNativeWindow (self->app->view);
/* let the plugin know that the UI is active */
uint8_t obj_buf[64];
lv2_atom_forge_set_buffer (
&self->forge, obj_buf, 64);
LV2_Atom_Forge_Frame frame;
lv2_atom_forge_frame_time (&self->forge, 0);
LV2_Atom* msg =
(LV2_Atom *)
lv2_atom_forge_object (
&self->forge, &frame, 1,
self->uris.ui_on);
lv2_atom_forge_pop (&self->forge, &frame);
self->write (
self->controller, 0,
lv2_atom_total_size (msg),
self->uris.atom_eventTransfer, msg);
return self;
}
@ -1977,6 +1994,23 @@ cleanup (LV2UI_Handle handle) @@ -1977,6 +1994,23 @@ cleanup (LV2UI_Handle handle)
{
ZLfoUi * self = (ZLfoUi *) handle;
/* let the plugin know that the UI is off */
uint8_t obj_buf[64];
lv2_atom_forge_set_buffer (
&self->forge, obj_buf, 64);
LV2_Atom_Forge_Frame frame;
lv2_atom_forge_frame_time (&self->forge, 0);
LV2_Atom* msg =
(LV2_Atom *)
lv2_atom_forge_object (
&self->forge, &frame, 1,
self->uris.ui_off);
lv2_atom_forge_pop (&self->forge, &frame);
self->write (
self->controller, 0,
lv2_atom_total_size (msg),
self->uris.atom_eventTransfer, msg);
ztk_app_free (self->app);
free (self);
@ -2121,7 +2155,7 @@ port_event ( @@ -2121,7 +2155,7 @@ port_event (
"failed to get current sample");
}
}
#if 0
/*#if 0*/
PuglRect rect;
rect.x = self->mid_region->rect.x;
rect.y = self->mid_region->rect.y;
@ -2130,7 +2164,7 @@ port_event ( @@ -2130,7 +2164,7 @@ port_event (
self->mid_region->rect.height;
puglPostRedisplayRect (
self->app->view, rect);
#endif
/*#endif*/
}
else
{

Loading…
Cancel
Save