aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/eg-scope.lv2
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2020-12-26 19:21:17 +0100
committerDavid Robillard <d@drobilla.net>2020-12-26 19:21:17 +0100
commit882b9446cbf7316345de391188e68c2a7333da5b (patch)
tree5baf31e0a28313b380cc7e8694b09a2a517d14f3 /plugins/eg-scope.lv2
parent8d2251749da9e0ae4254502edfc8917236a9b8c0 (diff)
downloadlv2-882b9446cbf7316345de391188e68c2a7333da5b.tar.xz
Format all code with clang-format
Diffstat (limited to 'plugins/eg-scope.lv2')
-rw-r--r--plugins/eg-scope.lv2/examploscope.c573
-rw-r--r--plugins/eg-scope.lv2/examploscope_ui.c954
-rw-r--r--plugins/eg-scope.lv2/uris.h70
3 files changed, 791 insertions, 806 deletions
diff --git a/plugins/eg-scope.lv2/examploscope.c b/plugins/eg-scope.lv2/examploscope.c
index b767508..ec013a1 100644
--- a/plugins/eg-scope.lv2/examploscope.c
+++ b/plugins/eg-scope.lv2/examploscope.c
@@ -42,40 +42,40 @@
UI using atom messages via a sequence port, similarly to MIDI I/O.
*/
typedef struct {
- // Port buffers
- float* input[2];
- float* output[2];
- const LV2_Atom_Sequence* control;
- LV2_Atom_Sequence* notify;
-
- // Atom forge and URI mapping
- LV2_URID_Map* map;
- ScoLV2URIs uris;
- LV2_Atom_Forge forge;
- LV2_Atom_Forge_Frame frame;
-
- // Log feature and convenience API
- LV2_Log_Logger logger;
-
- // Instantiation settings
- uint32_t n_channels;
- double rate;
-
- // UI state
- bool ui_active;
- bool send_settings_to_ui;
- float ui_amp;
- uint32_t ui_spp;
+ // Port buffers
+ float* input[2];
+ float* output[2];
+ const LV2_Atom_Sequence* control;
+ LV2_Atom_Sequence* notify;
+
+ // Atom forge and URI mapping
+ LV2_URID_Map* map;
+ ScoLV2URIs uris;
+ LV2_Atom_Forge forge;
+ LV2_Atom_Forge_Frame frame;
+
+ // Log feature and convenience API
+ LV2_Log_Logger logger;
+
+ // Instantiation settings
+ uint32_t n_channels;
+ double rate;
+
+ // UI state
+ bool ui_active;
+ bool send_settings_to_ui;
+ float ui_amp;
+ uint32_t ui_spp;
} EgScope;
/** ==== Port Indices ==== */
typedef enum {
- SCO_CONTROL = 0, // Event input
- SCO_NOTIFY = 1, // Event output
- SCO_INPUT0 = 2, // Audio input 0
- SCO_OUTPUT0 = 3, // Audio output 0
- SCO_INPUT1 = 4, // Audio input 1 (stereo variant)
- SCO_OUTPUT1 = 5, // Audio input 2 (stereo variant)
+ SCO_CONTROL = 0, // Event input
+ SCO_NOTIFY = 1, // Event output
+ SCO_INPUT0 = 2, // Audio input 0
+ SCO_OUTPUT0 = 3, // Audio output 0
+ SCO_INPUT1 = 4, // Audio input 1 (stereo variant)
+ SCO_OUTPUT1 = 5, // Audio input 2 (stereo variant)
} PortIndex;
/** ==== Instantiate Method ==== */
@@ -85,85 +85,83 @@ instantiate(const LV2_Descriptor* descriptor,
const char* bundle_path,
const LV2_Feature* const* features)
{
- (void)descriptor; // Unused variable
- (void)bundle_path; // Unused variable
-
- // Allocate and initialise instance structure.
- EgScope* self = (EgScope*)calloc(1, sizeof(EgScope));
- if (!self) {
- return NULL;
- }
-
- // Get host features
- // clang-format off
- const char* missing = lv2_features_query(
- features,
- LV2_LOG__log, &self->logger.log, false,
- LV2_URID__map, &self->map, true,
- NULL);
- // clang-format on
-
- lv2_log_logger_set_map(&self->logger, self->map);
- if (missing) {
- lv2_log_error(&self->logger, "Missing feature <%s>\n", missing);
- free(self);
- return NULL;
- }
-
- // Decide which variant to use depending on the plugin URI
- if (!strcmp(descriptor->URI, SCO_URI "#Stereo")) {
- self->n_channels = 2;
- } else if (!strcmp(descriptor->URI, SCO_URI "#Mono")) {
- self->n_channels = 1;
- } else {
- free(self);
- return NULL;
- }
-
- // Initialise local variables
- self->ui_active = false;
- self->send_settings_to_ui = false;
- self->rate = rate;
-
- // Set default UI settings
- self->ui_spp = 50;
- self->ui_amp = 1.0f;
-
- // Map URIs and initialise forge/logger
- map_sco_uris(self->map, &self->uris);
- lv2_atom_forge_init(&self->forge, self->map);
-
- return (LV2_Handle)self;
+ (void)descriptor; // Unused variable
+ (void)bundle_path; // Unused variable
+
+ // Allocate and initialise instance structure.
+ EgScope* self = (EgScope*)calloc(1, sizeof(EgScope));
+ if (!self) {
+ return NULL;
+ }
+
+ // Get host features
+ // clang-format off
+ const char* missing = lv2_features_query(
+ features,
+ LV2_LOG__log, &self->logger.log, false,
+ LV2_URID__map, &self->map, true,
+ NULL);
+ // clang-format on
+
+ lv2_log_logger_set_map(&self->logger, self->map);
+ if (missing) {
+ lv2_log_error(&self->logger, "Missing feature <%s>\n", missing);
+ free(self);
+ return NULL;
+ }
+
+ // Decide which variant to use depending on the plugin URI
+ if (!strcmp(descriptor->URI, SCO_URI "#Stereo")) {
+ self->n_channels = 2;
+ } else if (!strcmp(descriptor->URI, SCO_URI "#Mono")) {
+ self->n_channels = 1;
+ } else {
+ free(self);
+ return NULL;
+ }
+
+ // Initialise local variables
+ self->ui_active = false;
+ self->send_settings_to_ui = false;
+ self->rate = rate;
+
+ // Set default UI settings
+ self->ui_spp = 50;
+ self->ui_amp = 1.0f;
+
+ // Map URIs and initialise forge/logger
+ map_sco_uris(self->map, &self->uris);
+ lv2_atom_forge_init(&self->forge, self->map);
+
+ return (LV2_Handle)self;
}
/** ==== Connect Port Method ==== */
static void
-connect_port(LV2_Handle handle,
- uint32_t port,
- void* data)
+connect_port(LV2_Handle handle, uint32_t port, void* data)
{
- EgScope* self = (EgScope*)handle;
-
- switch ((PortIndex)port) {
- case SCO_CONTROL:
- self->control = (const LV2_Atom_Sequence*)data;
- break;
- case SCO_NOTIFY:
- self->notify = (LV2_Atom_Sequence*)data;
- break;
- case SCO_INPUT0:
- self->input[0] = (float*)data;
- break;
- case SCO_OUTPUT0:
- self->output[0] = (float*)data;
- break;
- case SCO_INPUT1:
- self->input[1] = (float*)data;
- break;
- case SCO_OUTPUT1:
- self->output[1] = (float*)data;
- break;
- }
+ EgScope* self = (EgScope*)handle;
+
+ switch ((PortIndex)port) {
+ case SCO_CONTROL:
+ self->control = (const LV2_Atom_Sequence*)data;
+ break;
+ case SCO_NOTIFY:
+ self->notify = (LV2_Atom_Sequence*)data;
+ break;
+ case SCO_INPUT0:
+ self->input[0] = (float*)data;
+ break;
+ case SCO_OUTPUT0:
+ self->output[0] = (float*)data;
+ break;
+ case SCO_INPUT1:
+ self->input[1] = (float*)data;
+ break;
+ case SCO_OUTPUT1:
+ self->output[1] = (float*)data;
+ break;
+ }
}
/**
@@ -174,9 +172,9 @@ connect_port(LV2_Handle handle,
[source,turtle]
--------
[]
- a sco:RawAudio ;
- sco:channelID 0 ;
- sco:audioData [ 0.0, 0.0, ... ] .
+ a sco:RawAudio ;
+ sco:channelID 0 ;
+ sco:audioData [ 0.0, 0.0, ... ] .
--------
where the value of the `sco:audioData` property, `[ 0.0, 0.0, ... ]`, is a
@@ -190,134 +188,131 @@ tx_rawaudio(LV2_Atom_Forge* forge,
const size_t n_samples,
const float* data)
{
- LV2_Atom_Forge_Frame frame;
+ LV2_Atom_Forge_Frame frame;
- // Forge container object of type 'RawAudio'
- lv2_atom_forge_frame_time(forge, 0);
- lv2_atom_forge_object(forge, &frame, 0, uris->RawAudio);
+ // Forge container object of type 'RawAudio'
+ lv2_atom_forge_frame_time(forge, 0);
+ lv2_atom_forge_object(forge, &frame, 0, uris->RawAudio);
- // Add integer 'channelID' property
- lv2_atom_forge_key(forge, uris->channelID);
- lv2_atom_forge_int(forge, channel);
+ // Add integer 'channelID' property
+ lv2_atom_forge_key(forge, uris->channelID);
+ lv2_atom_forge_int(forge, channel);
- // Add vector of floats 'audioData' property
- lv2_atom_forge_key(forge, uris->audioData);
- lv2_atom_forge_vector(
- forge, sizeof(float), uris->atom_Float, n_samples, data);
+ // Add vector of floats 'audioData' property
+ lv2_atom_forge_key(forge, uris->audioData);
+ lv2_atom_forge_vector(
+ forge, sizeof(float), uris->atom_Float, n_samples, data);
- // Close off object
- lv2_atom_forge_pop(forge, &frame);
+ // Close off object
+ lv2_atom_forge_pop(forge, &frame);
}
/** ==== Run Method ==== */
static void
run(LV2_Handle handle, uint32_t n_samples)
{
- EgScope* self = (EgScope*)handle;
-
- /* Ensure notify port buffer is large enough to hold all audio-samples and
- configuration settings. A minimum size was requested in the .ttl file,
- but check here just to be sure.
-
- TODO: Explain these magic numbers.
- */
- const size_t size = (sizeof(float) * n_samples + 64) * self->n_channels;
- const uint32_t space = self->notify->atom.size;
- if (space < size + 128) {
- /* Insufficient space, report error and do nothing. Note that a
- real-time production plugin mustn't call log functions in run(), but
- this can be useful for debugging and example purposes.
- */
- lv2_log_error(&self->logger, "Buffer size is insufficient\n");
- return;
- }
-
- // Prepare forge buffer and initialize atom-sequence
- lv2_atom_forge_set_buffer(&self->forge, (uint8_t*)self->notify, space);
- lv2_atom_forge_sequence_head(&self->forge, &self->frame, 0);
-
- /* Send settings to UI
-
- The plugin can continue to run while the UI is closed and re-opened.
- The state and settings of the UI are kept here and transmitted to the UI
- every time it asks for them or if the user initializes a 'load preset'.
- */
- if (self->send_settings_to_ui && self->ui_active) {
- self->send_settings_to_ui = false;
- // Forge container object of type 'ui_state'
- LV2_Atom_Forge_Frame frame;
- lv2_atom_forge_frame_time(&self->forge, 0);
- lv2_atom_forge_object(&self->forge, &frame, 0, self->uris.ui_State);
-
- // Add UI state as properties
- lv2_atom_forge_key(&self->forge, self->uris.ui_spp);
- lv2_atom_forge_int(&self->forge, self->ui_spp);
- lv2_atom_forge_key(&self->forge, self->uris.ui_amp);
- lv2_atom_forge_float(&self->forge, self->ui_amp);
- lv2_atom_forge_key(&self->forge, self->uris.param_sampleRate);
- lv2_atom_forge_float(&self->forge, (float)self->rate);
- lv2_atom_forge_pop(&self->forge, &frame);
- }
-
- // Process incoming events from GUI
- if (self->control) {
- const LV2_Atom_Event* ev = lv2_atom_sequence_begin(
- &(self->control)->body);
- // For each incoming message...
- while (!lv2_atom_sequence_is_end(
- &self->control->body, self->control->atom.size, ev)) {
- // If the event is an atom:Blank object
- 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.ui_On) {
- // If the object is a ui-on, the UI was activated
- self->ui_active = true;
- self->send_settings_to_ui = true;
- } else if (obj->body.otype == self->uris.ui_Off) {
- // If the object is a ui-off, the UI was closed
- self->ui_active = false;
- } else if (obj->body.otype == self->uris.ui_State) {
- // If the object is a ui-state, it's the current UI settings
- const LV2_Atom* spp = NULL;
- const LV2_Atom* amp = NULL;
- lv2_atom_object_get(obj, self->uris.ui_spp, &spp,
- self->uris.ui_amp, &amp,
- 0);
- if (spp) {
- self->ui_spp = ((const LV2_Atom_Int*)spp)->body;
- }
- if (amp) {
- self->ui_amp = ((const LV2_Atom_Float*)amp)->body;
- }
- }
- }
- ev = lv2_atom_sequence_next(ev);
- }
- }
-
- // Process audio data
- for (uint32_t c = 0; c < self->n_channels; ++c) {
- if (self->ui_active) {
- // If UI is active, send raw audio data to UI
- tx_rawaudio(&self->forge, &self->uris, c, n_samples, self->input[c]);
- }
- // If not processing audio in-place, forward audio
- if (self->input[c] != self->output[c]) {
- memcpy(self->output[c], self->input[c], sizeof(float) * n_samples);
- }
- }
-
- // Close off sequence
- lv2_atom_forge_pop(&self->forge, &self->frame);
+ EgScope* self = (EgScope*)handle;
+
+ /* Ensure notify port buffer is large enough to hold all audio-samples and
+ configuration settings. A minimum size was requested in the .ttl file,
+ but check here just to be sure.
+
+ TODO: Explain these magic numbers.
+ */
+ const size_t size = (sizeof(float) * n_samples + 64) * self->n_channels;
+ const uint32_t space = self->notify->atom.size;
+ if (space < size + 128) {
+ /* Insufficient space, report error and do nothing. Note that a
+ real-time production plugin mustn't call log functions in run(), but
+ this can be useful for debugging and example purposes.
+ */
+ lv2_log_error(&self->logger, "Buffer size is insufficient\n");
+ return;
+ }
+
+ // Prepare forge buffer and initialize atom-sequence
+ lv2_atom_forge_set_buffer(&self->forge, (uint8_t*)self->notify, space);
+ lv2_atom_forge_sequence_head(&self->forge, &self->frame, 0);
+
+ /* Send settings to UI
+
+ The plugin can continue to run while the UI is closed and re-opened.
+ The state and settings of the UI are kept here and transmitted to the UI
+ every time it asks for them or if the user initializes a 'load preset'.
+ */
+ if (self->send_settings_to_ui && self->ui_active) {
+ self->send_settings_to_ui = false;
+ // Forge container object of type 'ui_state'
+ LV2_Atom_Forge_Frame frame;
+ lv2_atom_forge_frame_time(&self->forge, 0);
+ lv2_atom_forge_object(&self->forge, &frame, 0, self->uris.ui_State);
+
+ // Add UI state as properties
+ lv2_atom_forge_key(&self->forge, self->uris.ui_spp);
+ lv2_atom_forge_int(&self->forge, self->ui_spp);
+ lv2_atom_forge_key(&self->forge, self->uris.ui_amp);
+ lv2_atom_forge_float(&self->forge, self->ui_amp);
+ lv2_atom_forge_key(&self->forge, self->uris.param_sampleRate);
+ lv2_atom_forge_float(&self->forge, (float)self->rate);
+ lv2_atom_forge_pop(&self->forge, &frame);
+ }
+
+ // Process incoming events from GUI
+ if (self->control) {
+ const LV2_Atom_Event* ev = lv2_atom_sequence_begin(&(self->control)->body);
+ // For each incoming message...
+ while (!lv2_atom_sequence_is_end(
+ &self->control->body, self->control->atom.size, ev)) {
+ // If the event is an atom:Blank object
+ 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.ui_On) {
+ // If the object is a ui-on, the UI was activated
+ self->ui_active = true;
+ self->send_settings_to_ui = true;
+ } else if (obj->body.otype == self->uris.ui_Off) {
+ // If the object is a ui-off, the UI was closed
+ self->ui_active = false;
+ } else if (obj->body.otype == self->uris.ui_State) {
+ // If the object is a ui-state, it's the current UI settings
+ const LV2_Atom* spp = NULL;
+ const LV2_Atom* amp = NULL;
+ lv2_atom_object_get(
+ obj, self->uris.ui_spp, &spp, self->uris.ui_amp, &amp, 0);
+ if (spp) {
+ self->ui_spp = ((const LV2_Atom_Int*)spp)->body;
+ }
+ if (amp) {
+ self->ui_amp = ((const LV2_Atom_Float*)amp)->body;
+ }
+ }
+ }
+ ev = lv2_atom_sequence_next(ev);
+ }
+ }
+
+ // Process audio data
+ for (uint32_t c = 0; c < self->n_channels; ++c) {
+ if (self->ui_active) {
+ // If UI is active, send raw audio data to UI
+ tx_rawaudio(&self->forge, &self->uris, c, n_samples, self->input[c]);
+ }
+ // If not processing audio in-place, forward audio
+ if (self->input[c] != self->output[c]) {
+ memcpy(self->output[c], self->input[c], sizeof(float) * n_samples);
+ }
+ }
+
+ // Close off sequence
+ lv2_atom_forge_pop(&self->forge, &self->frame);
}
static void
cleanup(LV2_Handle handle)
{
- free(handle);
+ free(handle);
}
-
/**
==== State Methods ====
@@ -334,22 +329,26 @@ state_save(LV2_Handle instance,
uint32_t flags,
const LV2_Feature* const* features)
{
- EgScope* self = (EgScope*)instance;
- if (!self) {
- return LV2_STATE_SUCCESS;
- }
-
- store(handle, self->uris.ui_spp,
- (void*)&self->ui_spp, sizeof(uint32_t),
- self->uris.atom_Int,
- LV2_STATE_IS_POD);
-
- store(handle, self->uris.ui_amp,
- (void*)&self->ui_amp, sizeof(float),
- self->uris.atom_Float,
- LV2_STATE_IS_POD);
-
- return LV2_STATE_SUCCESS;
+ EgScope* self = (EgScope*)instance;
+ if (!self) {
+ return LV2_STATE_SUCCESS;
+ }
+
+ store(handle,
+ self->uris.ui_spp,
+ (void*)&self->ui_spp,
+ sizeof(uint32_t),
+ self->uris.atom_Int,
+ LV2_STATE_IS_POD);
+
+ store(handle,
+ self->uris.ui_amp,
+ (void*)&self->ui_amp,
+ sizeof(float),
+ self->uris.atom_Float,
+ LV2_STATE_IS_POD);
+
+ return LV2_STATE_SUCCESS;
}
static LV2_State_Status
@@ -359,72 +358,68 @@ state_restore(LV2_Handle instance,
uint32_t flags,
const LV2_Feature* const* features)
{
- EgScope* self = (EgScope*)instance;
-
- size_t size = 0;
- uint32_t type = 0;
- uint32_t valflags = 0;
-
- const void* spp = retrieve(
- handle, self->uris.ui_spp, &size, &type, &valflags);
- if (spp && size == sizeof(uint32_t) && type == self->uris.atom_Int) {
- self->ui_spp = *((const uint32_t*)spp);
- self->send_settings_to_ui = true;
- }
-
- const void* amp = retrieve(
- handle, self->uris.ui_amp, &size, &type, &valflags);
- if (amp && size == sizeof(float) && type == self->uris.atom_Float) {
- self->ui_amp = *((const float*)amp);
- self->send_settings_to_ui = true;
- }
-
- return LV2_STATE_SUCCESS;
+ EgScope* self = (EgScope*)instance;
+
+ size_t size = 0;
+ uint32_t type = 0;
+ uint32_t valflags = 0;
+
+ const void* spp =
+ retrieve(handle, self->uris.ui_spp, &size, &type, &valflags);
+ if (spp && size == sizeof(uint32_t) && type == self->uris.atom_Int) {
+ self->ui_spp = *((const uint32_t*)spp);
+ self->send_settings_to_ui = true;
+ }
+
+ const void* amp =
+ retrieve(handle, self->uris.ui_amp, &size, &type, &valflags);
+ if (amp && size == sizeof(float) && type == self->uris.atom_Float) {
+ self->ui_amp = *((const float*)amp);
+ self->send_settings_to_ui = true;
+ }
+
+ return LV2_STATE_SUCCESS;
}
static const void*
extension_data(const char* uri)
{
- static const LV2_State_Interface state = { state_save, state_restore };
- if (!strcmp(uri, LV2_STATE__interface)) {
- return &state;
- }
- return NULL;
+ static const LV2_State_Interface state = {state_save, state_restore};
+ if (!strcmp(uri, LV2_STATE__interface)) {
+ return &state;
+ }
+ return NULL;
}
/** ==== Plugin Descriptors ==== */
-static const LV2_Descriptor descriptor_mono = {
- SCO_URI "#Mono",
- instantiate,
- connect_port,
- NULL,
- run,
- NULL,
- cleanup,
- extension_data
-};
-
-static const LV2_Descriptor descriptor_stereo = {
- SCO_URI "#Stereo",
- instantiate,
- connect_port,
- NULL,
- run,
- NULL,
- cleanup,
- extension_data
-};
+static const LV2_Descriptor descriptor_mono = {SCO_URI "#Mono",
+ instantiate,
+ connect_port,
+ NULL,
+ run,
+ NULL,
+ cleanup,
+ extension_data};
+
+static const LV2_Descriptor descriptor_stereo = {SCO_URI "#Stereo",
+ instantiate,
+ connect_port,
+ NULL,
+ run,
+ NULL,
+ cleanup,
+ extension_data};
LV2_SYMBOL_EXPORT
const LV2_Descriptor*
lv2_descriptor(uint32_t index)
{
- switch (index) {
- case 0:
- return &descriptor_mono;
- case 1:
- return &descriptor_stereo;
- default:
- return NULL;
- }
+ switch (index) {
+ case 0:
+ return &descriptor_mono;
+ case 1:
+ return &descriptor_stereo;
+ default:
+ return NULL;
+ }
}
diff --git a/plugins/eg-scope.lv2/examploscope_ui.c b/plugins/eg-scope.lv2/examploscope_ui.c
index e9e0c6f..e601843 100644
--- a/plugins/eg-scope.lv2/examploscope_ui.c
+++ b/plugins/eg-scope.lv2/examploscope_ui.c
@@ -38,7 +38,7 @@
#include <string.h>
// Drawing area size
-#define DAWIDTH (640)
+#define DAWIDTH (640)
#define DAHEIGHT (200)
/**
@@ -53,101 +53,100 @@
given 'index' position.
*/
typedef struct {
- float data_min[DAWIDTH];
- float data_max[DAWIDTH];
+ float data_min[DAWIDTH];
+ float data_max[DAWIDTH];
- uint32_t idx;
- uint32_t sub;
+ uint32_t idx;
+ uint32_t sub;
} ScoChan;
typedef struct {
- LV2_Atom_Forge forge;
- LV2_URID_Map* map;
- ScoLV2URIs uris;
-
- LV2UI_Write_Function write;
- LV2UI_Controller controller;
-
- GtkWidget* hbox;
- GtkWidget* vbox;
- GtkWidget* sep[2];
- GtkWidget* darea;
- GtkWidget* btn_pause;
- GtkWidget* lbl_speed;
- GtkWidget* lbl_amp;
- GtkWidget* spb_speed;
- GtkWidget* spb_amp;
- GtkAdjustment* spb_speed_adj;
- GtkAdjustment* spb_amp_adj;
-
- ScoChan chn[2];
- uint32_t stride;
- uint32_t n_channels;
- bool paused;
- float rate;
- bool updating;
+ LV2_Atom_Forge forge;
+ LV2_URID_Map* map;
+ ScoLV2URIs uris;
+
+ LV2UI_Write_Function write;
+ LV2UI_Controller controller;
+
+ GtkWidget* hbox;
+ GtkWidget* vbox;
+ GtkWidget* sep[2];
+ GtkWidget* darea;
+ GtkWidget* btn_pause;
+ GtkWidget* lbl_speed;
+ GtkWidget* lbl_amp;
+ GtkWidget* spb_speed;
+ GtkWidget* spb_amp;
+ GtkAdjustment* spb_speed_adj;
+ GtkAdjustment* spb_amp_adj;
+
+ ScoChan chn[2];
+ uint32_t stride;
+ uint32_t n_channels;
+ bool paused;
+ float rate;
+ bool updating;
} EgScopeUI;
-
/** Send current UI settings to backend. */
static void
send_ui_state(LV2UI_Handle handle)
{
- EgScopeUI* ui = (EgScopeUI*)handle;
- const float gain = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ui->spb_amp));
+ EgScopeUI* ui = (EgScopeUI*)handle;
+ const float gain = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ui->spb_amp));
- // Use local buffer on the stack to build atom
- uint8_t obj_buf[1024];
- lv2_atom_forge_set_buffer(&ui->forge, obj_buf, sizeof(obj_buf));
+ // Use local buffer on the stack to build atom
+ uint8_t obj_buf[1024];
+ lv2_atom_forge_set_buffer(&ui->forge, obj_buf, sizeof(obj_buf));
- // Start a ui:State object
- LV2_Atom_Forge_Frame frame;
- LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object(
- &ui->forge, &frame, 0, ui->uris.ui_State);
+ // Start a ui:State object
+ LV2_Atom_Forge_Frame frame;
+ LV2_Atom* msg =
+ (LV2_Atom*)lv2_atom_forge_object(&ui->forge, &frame, 0, ui->uris.ui_State);
- assert(msg);
+ assert(msg);
- // msg[samples-per-pixel] = integer
- lv2_atom_forge_key(&ui->forge, ui->uris.ui_spp);
- lv2_atom_forge_int(&ui->forge, ui->stride);
+ // msg[samples-per-pixel] = integer
+ lv2_atom_forge_key(&ui->forge, ui->uris.ui_spp);
+ lv2_atom_forge_int(&ui->forge, ui->stride);
- // msg[amplitude] = float
- lv2_atom_forge_key(&ui->forge, ui->uris.ui_amp);
- lv2_atom_forge_float(&ui->forge, gain);
+ // msg[amplitude] = float
+ lv2_atom_forge_key(&ui->forge, ui->uris.ui_amp);
+ lv2_atom_forge_float(&ui->forge, gain);
- // Finish ui:State object
- lv2_atom_forge_pop(&ui->forge, &frame);
+ // Finish ui:State object
+ lv2_atom_forge_pop(&ui->forge, &frame);
- // Send message to plugin port '0'
- ui->write(ui->controller,
- 0,
- lv2_atom_total_size(msg),
- ui->uris.atom_eventTransfer,
- msg);
+ // Send message to plugin port '0'
+ ui->write(ui->controller,
+ 0,
+ lv2_atom_total_size(msg),
+ ui->uris.atom_eventTransfer,
+ msg);
}
/** Notify backend that UI is closed. */
static void
send_ui_disable(LV2UI_Handle handle)
{
- EgScopeUI* ui = (EgScopeUI*)handle;
- send_ui_state(handle);
+ EgScopeUI* ui = (EgScopeUI*)handle;
+ send_ui_state(handle);
- uint8_t obj_buf[64];
- lv2_atom_forge_set_buffer(&ui->forge, obj_buf, sizeof(obj_buf));
+ uint8_t obj_buf[64];
+ lv2_atom_forge_set_buffer(&ui->forge, obj_buf, sizeof(obj_buf));
- LV2_Atom_Forge_Frame frame;
- LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object(
- &ui->forge, &frame, 0, ui->uris.ui_Off);
+ LV2_Atom_Forge_Frame frame;
+ LV2_Atom* msg =
+ (LV2_Atom*)lv2_atom_forge_object(&ui->forge, &frame, 0, ui->uris.ui_Off);
- assert(msg);
+ assert(msg);
- lv2_atom_forge_pop(&ui->forge, &frame);
- ui->write(ui->controller,
- 0,
- lv2_atom_total_size(msg),
- ui->uris.atom_eventTransfer,
- msg);
+ lv2_atom_forge_pop(&ui->forge, &frame);
+ ui->write(ui->controller,
+ 0,
+ lv2_atom_total_size(msg),
+ ui->uris.atom_eventTransfer,
+ msg);
}
/**
@@ -158,35 +157,35 @@ send_ui_disable(LV2UI_Handle handle)
static void
send_ui_enable(LV2UI_Handle handle)
{
- EgScopeUI* ui = (EgScopeUI*)handle;
+ EgScopeUI* ui = (EgScopeUI*)handle;
- uint8_t obj_buf[64];
- lv2_atom_forge_set_buffer(&ui->forge, obj_buf, sizeof(obj_buf));
+ uint8_t obj_buf[64];
+ lv2_atom_forge_set_buffer(&ui->forge, obj_buf, sizeof(obj_buf));
- LV2_Atom_Forge_Frame frame;
- LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object(
- &ui->forge, &frame, 0, ui->uris.ui_On);
+ LV2_Atom_Forge_Frame frame;
+ LV2_Atom* msg =
+ (LV2_Atom*)lv2_atom_forge_object(&ui->forge, &frame, 0, ui->uris.ui_On);
- assert(msg);
+ assert(msg);
- lv2_atom_forge_pop(&ui->forge, &frame);
- ui->write(ui->controller,
- 0,
- lv2_atom_total_size(msg),
- ui->uris.atom_eventTransfer,
- msg);
+ lv2_atom_forge_pop(&ui->forge, &frame);
+ ui->write(ui->controller,
+ 0,
+ lv2_atom_total_size(msg),
+ ui->uris.atom_eventTransfer,
+ msg);
}
/** Gtk widget callback. */
static gboolean
on_cfg_changed(GtkWidget* widget, gpointer data)
{
- EgScopeUI* ui = (EgScopeUI*)data;
- if (!ui->updating) {
- // Only send UI state if the change is from user interaction
- send_ui_state(data);
- }
- return TRUE;
+ EgScopeUI* ui = (EgScopeUI*)data;
+ if (!ui->updating) {
+ // Only send UI state if the change is from user interaction
+ send_ui_state(data);
+ }
+ return TRUE;
}
/**
@@ -197,127 +196,127 @@ on_cfg_changed(GtkWidget* widget, gpointer data)
static gboolean
on_expose_event(GtkWidget* widget, GdkEventExpose* ev, gpointer data)
{
- EgScopeUI* ui = (EgScopeUI*)data;
- const float gain = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ui->spb_amp));
-
- // Get cairo type for the gtk window
- cairo_t* cr = gdk_cairo_create(ui->darea->window);
-
- // Limit cairo-drawing to exposed area
- cairo_rectangle(cr, ev->area.x, ev->area.y, ev->area.width, ev->area.height);
- cairo_clip(cr);
-
- // Clear background
- cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
- cairo_rectangle(cr, 0, 0, DAWIDTH, DAHEIGHT * ui->n_channels);
- cairo_fill(cr);
-
- cairo_set_line_width(cr, 1.0);
-
- const uint32_t start = ev->area.x;
- const uint32_t end = ev->area.x + ev->area.width;
-
- assert(start < DAWIDTH);
- assert(end <= DAWIDTH);
- assert(start < end);
-
- for (uint32_t c = 0; c < ui->n_channels; ++c) {
- ScoChan* chn = &ui->chn[c];
-
- /* Drawing area Y-position of given sample-value.
- * Note: cairo-pixel at 0 spans -0.5 .. +0.5, hence (DAHEIGHT / 2.0 -0.5)
- * also the cairo Y-axis points upwards (hence 'minus value')
- *
- * == ( DAHEIGHT * (CHN) // channel offset
- * + (DAHEIGHT / 2) - 0.5 // vertical center -- '0'
- * - (DAHEIGHT / 2) * (VAL) * (GAIN)
- * )
- */
- const float chn_y_offset = DAHEIGHT * c + DAHEIGHT * 0.5f - 0.5f;
- const float chn_y_scale = DAHEIGHT * 0.5f * gain;
-
-#define CYPOS(VAL) (chn_y_offset - (VAL) * chn_y_scale)
-
- cairo_save(cr);
-
- /* Restrict drawing to current channel area, don't bleed drawing into
- neighboring channels. */
- cairo_rectangle(cr, 0, DAHEIGHT * c, DAWIDTH, DAHEIGHT);
- cairo_clip(cr);
-
- // Set color of wave-form
- cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 1.0);
-
- /* This is a somewhat 'smart' mechanism to plot audio data using
- alternating up/down line-directions. It works well for both cases:
- 1 pixel <= 1 sample and 1 pixel represents more than 1 sample, but
- is not ideal for either. */
- if (start == chn->idx) {
- cairo_move_to(cr, start - 0.5, CYPOS(0));
- } else {
- cairo_move_to(cr, start - 0.5, CYPOS(chn->data_max[start]));
- }
-
- uint32_t pathlength = 0;
- for (uint32_t i = start; i < end; ++i) {
- if (i == chn->idx) {
- continue;
- } else if (i % 2) {
- cairo_line_to(cr, i - .5, CYPOS(chn->data_min[i]));
- cairo_line_to(cr, i - .5, CYPOS(chn->data_max[i]));
- ++pathlength;
- } else {
- cairo_line_to(cr, i - .5, CYPOS(chn->data_max[i]));
- cairo_line_to(cr, i - .5, CYPOS(chn->data_min[i]));
- ++pathlength;
- }
-
- /** Limit the max cairo path length. This is an optimization trade
- off: too short path: high load CPU/GPU load. too-long path:
- bad anti-aliasing, or possibly lost points */
- if (pathlength > MAX_CAIRO_PATH) {
- pathlength = 0;
- cairo_stroke(cr);
- if (i % 2) {
- cairo_move_to(cr, i - .5, CYPOS(chn->data_max[i]));
- } else {
- cairo_move_to(cr, i - .5, CYPOS(chn->data_min[i]));
- }
- }
- }
-
- if (pathlength > 0) {
- cairo_stroke(cr);
- }
-
- // Draw current position vertical line if display is slow
- if (ui->stride >= ui->rate / 4800.0f || ui->paused) {
- cairo_set_source_rgba(cr, .9, .2, .2, .6);
- cairo_move_to(cr, chn->idx - .5, DAHEIGHT * c);
- cairo_line_to(cr, chn->idx - .5, DAHEIGHT * (c + 1));
- cairo_stroke(cr);
- }
-
- // Undo the 'clipping' restriction
- cairo_restore(cr);
-
- // Channel separator
- if (c > 0) {
- cairo_set_source_rgba(cr, .5, .5, .5, 1.0);
- cairo_move_to(cr, 0, DAHEIGHT * c - .5);
- cairo_line_to(cr, DAWIDTH, DAHEIGHT * c - .5);
- cairo_stroke(cr);
- }
-
- // Zero scale line
- cairo_set_source_rgba(cr, .3, .3, .7, .5);
- cairo_move_to(cr, 0, DAHEIGHT * (c + .5) - .5);
- cairo_line_to(cr, DAWIDTH, DAHEIGHT * (c + .5) - .5);
- cairo_stroke(cr);
- }
-
- cairo_destroy(cr);
- return TRUE;
+ EgScopeUI* ui = (EgScopeUI*)data;
+ const float gain = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ui->spb_amp));
+
+ // Get cairo type for the gtk window
+ cairo_t* cr = gdk_cairo_create(ui->darea->window);
+
+ // Limit cairo-drawing to exposed area
+ cairo_rectangle(cr, ev->area.x, ev->area.y, ev->area.width, ev->area.height);
+ cairo_clip(cr);
+
+ // Clear background
+ cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
+ cairo_rectangle(cr, 0, 0, DAWIDTH, DAHEIGHT * ui->n_channels);
+ cairo_fill(cr);
+
+ cairo_set_line_width(cr, 1.0);
+
+ const uint32_t start = ev->area.x;
+ const uint32_t end = ev->area.x + ev->area.width;
+
+ assert(start < DAWIDTH);
+ assert(end <= DAWIDTH);
+ assert(start < end);
+
+ for (uint32_t c = 0; c < ui->n_channels; ++c) {
+ ScoChan* chn = &ui->chn[c];
+
+ /* Drawing area Y-position of given sample-value.
+ * Note: cairo-pixel at 0 spans -0.5 .. +0.5, hence (DAHEIGHT / 2.0 -0.5)
+ * also the cairo Y-axis points upwards (hence 'minus value')
+ *
+ * == ( DAHEIGHT * (CHN) // channel offset
+ * + (DAHEIGHT / 2) - 0.5 // vertical center -- '0'
+ * - (DAHEIGHT / 2) * (VAL) * (GAIN)
+ * )
+ */
+ const float chn_y_offset = DAHEIGHT * c + DAHEIGHT * 0.5f - 0.5f;
+ const float chn_y_scale = DAHEIGHT * 0.5f * gain;
+
+#define CYPOS(VAL) (chn_y_offset - (VAL)*chn_y_scale)
+
+ cairo_save(cr);
+
+ /* Restrict drawing to current channel area, don't bleed drawing into
+ neighboring channels. */
+ cairo_rectangle(cr, 0, DAHEIGHT * c, DAWIDTH, DAHEIGHT);
+ cairo_clip(cr);
+
+ // Set color of wave-form
+ cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 1.0);
+
+ /* This is a somewhat 'smart' mechanism to plot audio data using
+ alternating up/down line-directions. It works well for both cases:
+ 1 pixel <= 1 sample and 1 pixel represents more than 1 sample, but
+ is not ideal for either. */
+ if (start == chn->idx) {
+ cairo_move_to(cr, start - 0.5, CYPOS(0));
+ } else {
+ cairo_move_to(cr, start - 0.5, CYPOS(chn->data_max[start]));
+ }
+
+ uint32_t pathlength = 0;
+ for (uint32_t i = start; i < end; ++i) {
+ if (i == chn->idx) {
+ continue;
+ } else if (i % 2) {
+ cairo_line_to(cr, i - .5, CYPOS(chn->data_min[i]));
+ cairo_line_to(cr, i - .5, CYPOS(chn->data_max[i]));
+ ++pathlength;
+ } else {
+ cairo_line_to(cr, i - .5, CYPOS(chn->data_max[i]));
+ cairo_line_to(cr, i - .5, CYPOS(chn->data_min[i]));
+ ++pathlength;
+ }
+
+ /** Limit the max cairo path length. This is an optimization trade
+ off: too short path: high load CPU/GPU load. too-long path:
+ bad anti-aliasing, or possibly lost points */
+ if (pathlength > MAX_CAIRO_PATH) {
+ pathlength = 0;
+ cairo_stroke(cr);
+ if (i % 2) {
+ cairo_move_to(cr, i - .5, CYPOS(chn->data_max[i]));
+ } else {
+ cairo_move_to(cr, i - .5, CYPOS(chn->data_min[i]));
+ }
+ }
+ }
+
+ if (pathlength > 0) {
+ cairo_stroke(cr);
+ }
+
+ // Draw current position vertical line if display is slow
+ if (ui->stride >= ui->rate / 4800.0f || ui->paused) {
+ cairo_set_source_rgba(cr, .9, .2, .2, .6);
+ cairo_move_to(cr, chn->idx - .5, DAHEIGHT * c);
+ cairo_line_to(cr, chn->idx - .5, DAHEIGHT * (c + 1));
+ cairo_stroke(cr);
+ }
+
+ // Undo the 'clipping' restriction
+ cairo_restore(cr);
+
+ // Channel separator
+ if (c > 0) {
+ cairo_set_source_rgba(cr, .5, .5, .5, 1.0);
+ cairo_move_to(cr, 0, DAHEIGHT * c - .5);
+ cairo_line_to(cr, DAWIDTH, DAHEIGHT * c - .5);
+ cairo_stroke(cr);
+ }
+
+ // Zero scale line
+ cairo_set_source_rgba(cr, .3, .3, .7, .5);
+ cairo_move_to(cr, 0, DAHEIGHT * (c + .5) - .5);
+ cairo_line_to(cr, DAWIDTH, DAHEIGHT * (c + .5) - .5);
+ cairo_stroke(cr);
+ }
+
+ cairo_destroy(cr);
+ return TRUE;
}
/**
@@ -346,27 +345,27 @@ process_channel(EgScopeUI* ui,
uint32_t* idx_start,
uint32_t* idx_end)
{
- int overflow = 0;
- *idx_start = chn->idx;
- for (size_t i = 0; i < n_elem; ++i) {
- if (data[i] < chn->data_min[chn->idx]) {
- chn->data_min[chn->idx] = data[i];
- }
- if (data[i] > chn->data_max[chn->idx]) {
- chn->data_max[chn->idx] = data[i];
- }
- if (++chn->sub >= ui->stride) {
- chn->sub = 0;
- chn->idx = (chn->idx + 1) % DAWIDTH;
- if (chn->idx == 0) {
- ++overflow;
- }
- chn->data_min[chn->idx] = 1.0f;
- chn->data_max[chn->idx] = -1.0f;
- }
- }
- *idx_end = chn->idx;
- return overflow;
+ int overflow = 0;
+ *idx_start = chn->idx;
+ for (size_t i = 0; i < n_elem; ++i) {
+ if (data[i] < chn->data_min[chn->idx]) {
+ chn->data_min[chn->idx] = data[i];
+ }
+ if (data[i] > chn->data_max[chn->idx]) {
+ chn->data_max[chn->idx] = data[i];
+ }
+ if (++chn->sub >= ui->stride) {
+ chn->sub = 0;
+ chn->idx = (chn->idx + 1) % DAWIDTH;
+ if (chn->idx == 0) {
+ ++overflow;
+ }
+ chn->data_min[chn->idx] = 1.0f;
+ chn->data_max[chn->idx] = -1.0f;
+ }
+ }
+ *idx_end = chn->idx;
+ return overflow;
}
/**
@@ -379,56 +378,57 @@ update_scope(EgScopeUI* ui,
const size_t n_elem,
float const* data)
{
- // Never trust input data which could lead to application failure.
- if (channel < 0 || (uint32_t)channel > ui->n_channels) {
- return;
- }
-
- // Update state in sync with 1st channel
- if (channel == 0) {
- ui->stride = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ui->spb_speed));
- const bool paused = gtk_toggle_button_get_active(
- GTK_TOGGLE_BUTTON(ui->btn_pause));
-
- if (paused != ui->paused) {
- ui->paused = paused;
- gtk_widget_queue_draw(ui->darea);
- }
- }
- if (ui->paused) {
- return;
- }
-
- uint32_t idx_start = 0; // Display pixel start
- uint32_t idx_end = 0; // Display pixel end
- int overflow = 0; // Received more audio-data than display-pixel
-
- // Process this channel's audio-data for display
- ScoChan* chn = &ui->chn[channel];
- overflow = process_channel(ui, chn, n_elem, data, &idx_start, &idx_end);
-
- // Signal gtk's main thread to redraw the widget after the last channel
- if ((uint32_t)channel + 1 == ui->n_channels) {
- if (overflow > 1) {
- // Redraw complete widget
- gtk_widget_queue_draw(ui->darea);
- } else if (idx_end > idx_start) {
- // Redraw area between start -> end pixel
- gtk_widget_queue_draw_area(ui->darea, idx_start - 2, 0, 3
- + idx_end - idx_start,
- DAHEIGHT * ui->n_channels);
- } else if (idx_end < idx_start) {
- // Wrap-around: redraw area between 0->start AND end->right-end
- gtk_widget_queue_draw_area(
- ui->darea,
- idx_start - 2, 0,
- 3 + DAWIDTH - idx_start, DAHEIGHT * ui->n_channels);
- gtk_widget_queue_draw_area(
- ui->darea,
- 0, 0,
- idx_end + 1, DAHEIGHT * ui->n_channels);
- }
- }
+ // Never trust input data which could lead to application failure.
+ if (channel < 0 || (uint32_t)channel > ui->n_channels) {
+ return;
+ }
+
+ // Update state in sync with 1st channel
+ if (channel == 0) {
+ ui->stride = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ui->spb_speed));
+ const bool paused =
+ gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ui->btn_pause));
+
+ if (paused != ui->paused) {
+ ui->paused = paused;
+ gtk_widget_queue_draw(ui->darea);
+ }
+ }
+ if (ui->paused) {
+ return;
+ }
+
+ uint32_t idx_start = 0; // Display pixel start
+ uint32_t idx_end = 0; // Display pixel end
+ int overflow = 0; // Received more audio-data than display-pixel
+
+ // Process this channel's audio-data for display
+ ScoChan* chn = &ui->chn[channel];
+ overflow = process_channel(ui, chn, n_elem, data, &idx_start, &idx_end);
+
+ // Signal gtk's main thread to redraw the widget after the last channel
+ if ((uint32_t)channel + 1 == ui->n_channels) {
+ if (overflow > 1) {
+ // Redraw complete widget
+ gtk_widget_queue_draw(ui->darea);
+ } else if (idx_end > idx_start) {
+ // Redraw area between start -> end pixel
+ gtk_widget_queue_draw_area(ui->darea,
+ idx_start - 2,
+ 0,
+ 3 + idx_end - idx_start,
+ DAHEIGHT * ui->n_channels);
+ } else if (idx_end < idx_start) {
+ // Wrap-around: redraw area between 0->start AND end->right-end
+ gtk_widget_queue_draw_area(ui->darea,
+ idx_start - 2,
+ 0,
+ 3 + DAWIDTH - idx_start,
+ DAHEIGHT * ui->n_channels);
+ gtk_widget_queue_draw_area(
+ ui->darea, 0, 0, idx_end + 1, DAHEIGHT * ui->n_channels);
+ }
+ }
}
static LV2UI_Handle
@@ -440,199 +440,191 @@ instantiate(const LV2UI_Descriptor* descriptor,
LV2UI_Widget* widget,
const LV2_Feature* const* features)
{
- EgScopeUI* ui = (EgScopeUI*)calloc(1, sizeof(EgScopeUI));
-
- if (!ui) {
- fprintf(stderr, "EgScope.lv2 UI: out of memory\n");
- return NULL;
- }
-
- ui->map = NULL;
- *widget = NULL;
-
- if (!strcmp(plugin_uri, SCO_URI "#Mono")) {
- ui->n_channels = 1;
- } else if (!strcmp(plugin_uri, SCO_URI "#Stereo")) {
- ui->n_channels = 2;
- } else {
- free(ui);
- return NULL;
- }
-
- for (int i = 0; features[i]; ++i) {
- if (!strcmp(features[i]->URI, LV2_URID_URI "#map")) {
- ui->map = (LV2_URID_Map*)features[i]->data;
- }
- }
-
- if (!ui->map) {
- fprintf(stderr, "EgScope.lv2 UI: Host does not support urid:map\n");
- free(ui);
- return NULL;
- }
-
- // Initialize private data structure
- ui->write = write_function;
- ui->controller = controller;
-
- ui->vbox = NULL;
- ui->hbox = NULL;
- ui->darea = NULL;
- ui->stride = 25;
- ui->paused = false;
- ui->rate = 48000;
-
- ui->chn[0].idx = 0;
- ui->chn[0].sub = 0;
- ui->chn[1].idx = 0;
- ui->chn[1].sub = 0;
- memset(ui->chn[0].data_min, 0, sizeof(float) * DAWIDTH);
- memset(ui->chn[0].data_max, 0, sizeof(float) * DAWIDTH);
- memset(ui->chn[1].data_min, 0, sizeof(float) * DAWIDTH);
- memset(ui->chn[1].data_max, 0, sizeof(float) * DAWIDTH);
-
- map_sco_uris(ui->map, &ui->uris);
- lv2_atom_forge_init(&ui->forge, ui->map);
-
- // Setup UI
- ui->hbox = gtk_hbox_new(FALSE, 0);
- ui->vbox = gtk_vbox_new(FALSE, 0);
-
- ui->darea = gtk_drawing_area_new();
- gtk_widget_set_size_request(ui->darea, DAWIDTH, DAHEIGHT * ui->n_channels);
-
- ui->lbl_speed = gtk_label_new("Samples/Pixel");
- ui->lbl_amp = gtk_label_new("Amplitude");
-
- ui->sep[0] = gtk_hseparator_new();
- ui->sep[1] = gtk_label_new("");
- ui->btn_pause = gtk_toggle_button_new_with_label("Pause");
-
- ui->spb_speed_adj = (GtkAdjustment*)gtk_adjustment_new(
- 25.0, 1.0, 1000.0, 1.0, 5.0, 0.0);
- ui->spb_speed = gtk_spin_button_new(ui->spb_speed_adj, 1.0, 0);
-
- ui->spb_amp_adj = (GtkAdjustment*)gtk_adjustment_new(
- 1.0, 0.1, 6.0, 0.1, 1.0, 0.0);
- ui->spb_amp = gtk_spin_button_new(ui->spb_amp_adj, 0.1, 1);
-
- gtk_box_pack_start(GTK_BOX(ui->hbox), ui->darea, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(ui->hbox), ui->vbox, FALSE, FALSE, 4);
-
- gtk_box_pack_start(GTK_BOX(ui->vbox), ui->lbl_speed, FALSE, FALSE, 2);
- gtk_box_pack_start(GTK_BOX(ui->vbox), ui->spb_speed, FALSE, FALSE, 2);
- gtk_box_pack_start(GTK_BOX(ui->vbox), ui->sep[0], FALSE, FALSE, 8);
- gtk_box_pack_start(GTK_BOX(ui->vbox), ui->lbl_amp, FALSE, FALSE, 2);
- gtk_box_pack_start(GTK_BOX(ui->vbox), ui->spb_amp, FALSE, FALSE, 2);
- gtk_box_pack_start(GTK_BOX(ui->vbox), ui->sep[1], TRUE, FALSE, 8);
- gtk_box_pack_start(GTK_BOX(ui->vbox), ui->btn_pause, FALSE, FALSE, 2);
-
- g_signal_connect(G_OBJECT(ui->darea), "expose_event",
- G_CALLBACK(on_expose_event), ui);
- g_signal_connect(G_OBJECT(ui->spb_amp), "value-changed",
- G_CALLBACK(on_cfg_changed), ui);
- g_signal_connect(G_OBJECT(ui->spb_speed), "value-changed",
- G_CALLBACK(on_cfg_changed), ui);
-
- *widget = ui->hbox;
-
- /* Send UIOn message to plugin, which will request state and enable message
- transmission. */
- send_ui_enable(ui);
-
- return ui;
+ EgScopeUI* ui = (EgScopeUI*)calloc(1, sizeof(EgScopeUI));
+
+ if (!ui) {
+ fprintf(stderr, "EgScope.lv2 UI: out of memory\n");
+ return NULL;
+ }
+
+ ui->map = NULL;
+ *widget = NULL;
+
+ if (!strcmp(plugin_uri, SCO_URI "#Mono")) {
+ ui->n_channels = 1;
+ } else if (!strcmp(plugin_uri, SCO_URI "#Stereo")) {
+ ui->n_channels = 2;
+ } else {
+ free(ui);
+ return NULL;
+ }
+
+ for (int i = 0; features[i]; ++i) {
+ if (!strcmp(features[i]->URI, LV2_URID_URI "#map")) {
+ ui->map = (LV2_URID_Map*)features[i]->data;
+ }
+ }
+
+ if (!ui->map) {
+ fprintf(stderr, "EgScope.lv2 UI: Host does not support urid:map\n");
+ free(ui);
+ return NULL;
+ }
+
+ // Initialize private data structure
+ ui->write = write_function;
+ ui->controller = controller;
+
+ ui->vbox = NULL;
+ ui->hbox = NULL;
+ ui->darea = NULL;
+ ui->stride = 25;
+ ui->paused = false;
+ ui->rate = 48000;
+
+ ui->chn[0].idx = 0;
+ ui->chn[0].sub = 0;
+ ui->chn[1].idx = 0;
+ ui->chn[1].sub = 0;
+ memset(ui->chn[0].data_min, 0, sizeof(float) * DAWIDTH);
+ memset(ui->chn[0].data_max, 0, sizeof(float) * DAWIDTH);
+ memset(ui->chn[1].data_min, 0, sizeof(float) * DAWIDTH);
+ memset(ui->chn[1].data_max, 0, sizeof(float) * DAWIDTH);
+
+ map_sco_uris(ui->map, &ui->uris);
+ lv2_atom_forge_init(&ui->forge, ui->map);
+
+ // Setup UI
+ ui->hbox = gtk_hbox_new(FALSE, 0);
+ ui->vbox = gtk_vbox_new(FALSE, 0);
+
+ ui->darea = gtk_drawing_area_new();
+ gtk_widget_set_size_request(ui->darea, DAWIDTH, DAHEIGHT * ui->n_channels);
+
+ ui->lbl_speed = gtk_label_new("Samples/Pixel");
+ ui->lbl_amp = gtk_label_new("Amplitude");
+
+ ui->sep[0] = gtk_hseparator_new();
+ ui->sep[1] = gtk_label_new("");
+ ui->btn_pause = gtk_toggle_button_new_with_label("Pause");
+
+ ui->spb_speed_adj =
+ (GtkAdjustment*)gtk_adjustment_new(25.0, 1.0, 1000.0, 1.0, 5.0, 0.0);
+ ui->spb_speed = gtk_spin_button_new(ui->spb_speed_adj, 1.0, 0);
+
+ ui->spb_amp_adj =
+ (GtkAdjustment*)gtk_adjustment_new(1.0, 0.1, 6.0, 0.1, 1.0, 0.0);
+ ui->spb_amp = gtk_spin_button_new(ui->spb_amp_adj, 0.1, 1);
+
+ gtk_box_pack_start(GTK_BOX(ui->hbox), ui->darea, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(ui->hbox), ui->vbox, FALSE, FALSE, 4);
+
+ gtk_box_pack_start(GTK_BOX(ui->vbox), ui->lbl_speed, FALSE, FALSE, 2);
+ gtk_box_pack_start(GTK_BOX(ui->vbox), ui->spb_speed, FALSE, FALSE, 2);
+ gtk_box_pack_start(GTK_BOX(ui->vbox), ui->sep[0], FALSE, FALSE, 8);
+ gtk_box_pack_start(GTK_BOX(ui->vbox), ui->lbl_amp, FALSE, FALSE, 2);
+ gtk_box_pack_start(GTK_BOX(ui->vbox), ui->spb_amp, FALSE, FALSE, 2);
+ gtk_box_pack_start(GTK_BOX(ui->vbox), ui->sep[1], TRUE, FALSE, 8);
+ gtk_box_pack_start(GTK_BOX(ui->vbox), ui->btn_pause, FALSE, FALSE, 2);
+
+ g_signal_connect(
+ G_OBJECT(ui->darea), "expose_event", G_CALLBACK(on_expose_event), ui);
+ g_signal_connect(
+ G_OBJECT(ui->spb_amp), "value-changed", G_CALLBACK(on_cfg_changed), ui);
+ g_signal_connect(
+ G_OBJECT(ui->spb_speed), "value-changed", G_CALLBACK(on_cfg_changed), ui);
+
+ *widget = ui->hbox;
+
+ /* Send UIOn message to plugin, which will request state and enable message
+ transmission. */
+ send_ui_enable(ui);
+
+ return ui;
}
static void
cleanup(LV2UI_Handle handle)
{
- EgScopeUI* ui = (EgScopeUI*)handle;
- /* Send UIOff message to plugin, which will save state and disable message
- * transmission. */
- send_ui_disable(ui);
- gtk_widget_destroy(ui->darea);
- free(ui);
+ EgScopeUI* ui = (EgScopeUI*)handle;
+ /* Send UIOff message to plugin, which will save state and disable message
+ * transmission. */
+ send_ui_disable(ui);
+ gtk_widget_destroy(ui->darea);
+ free(ui);
}
static int
recv_raw_audio(EgScopeUI* ui, const LV2_Atom_Object* obj)
{
- const LV2_Atom* chan_val = NULL;
- const LV2_Atom* data_val = NULL;
-
- // clang-format off
- const int n_props = lv2_atom_object_get(
- obj,
- ui->uris.channelID, &chan_val,
- ui->uris.audioData, &data_val,
- NULL);
- // clang-format on
-
- if (n_props != 2 ||
- chan_val->type != ui->uris.atom_Int ||
- data_val->type != ui->uris.atom_Vector) {
- // Object does not have the required properties with correct types
- fprintf(stderr, "eg-scope.lv2 UI error: Corrupt audio message\n");
- return 1;
- }
-
- // Get the values we need from the body of the property value atoms
- const int32_t chn = ((const LV2_Atom_Int*)chan_val)->body;
- const LV2_Atom_Vector* vec = (const LV2_Atom_Vector*)data_val;
- if (vec->body.child_type != ui->uris.atom_Float) {
- return 1; // Vector has incorrect element type
- }
-
- // Number of elements = (total size - header size) / element size
- const size_t n_elem = ((data_val->size - sizeof(LV2_Atom_Vector_Body))
- / sizeof(float));
-
- // Float elements immediately follow the vector body header
- const float* data = (const float*)(&vec->body + 1);
-
- // Update display
- update_scope(ui, chn, n_elem, data);
- return 0;
+ const LV2_Atom* chan_val = NULL;
+ const LV2_Atom* data_val = NULL;
+ const int n_props = lv2_atom_object_get(
+ obj, ui->uris.channelID, &chan_val, ui->uris.audioData, &data_val, NULL);
+
+ if (n_props != 2 || chan_val->type != ui->uris.atom_Int ||
+ data_val->type != ui->uris.atom_Vector) {
+ // Object does not have the required properties with correct types
+ fprintf(stderr, "eg-scope.lv2 UI error: Corrupt audio message\n");
+ return 1;
+ }
+
+ // Get the values we need from the body of the property value atoms
+ const int32_t chn = ((const LV2_Atom_Int*)chan_val)->body;
+ const LV2_Atom_Vector* vec = (const LV2_Atom_Vector*)data_val;
+ if (vec->body.child_type != ui->uris.atom_Float) {
+ return 1; // Vector has incorrect element type
+ }
+
+ // Number of elements = (total size - header size) / element size
+ const size_t n_elem =
+ ((data_val->size - sizeof(LV2_Atom_Vector_Body)) / sizeof(float));
+
+ // Float elements immediately follow the vector body header
+ const float* data = (const float*)(&vec->body + 1);
+
+ // Update display
+ update_scope(ui, chn, n_elem, data);
+ return 0;
}
static int
recv_ui_state(EgScopeUI* ui, const LV2_Atom_Object* obj)
{
- const LV2_Atom* spp_val = NULL;
- const LV2_Atom* amp_val = NULL;
- const LV2_Atom* rate_val = NULL;
-
- // clang-format off
- const int n_props = lv2_atom_object_get(
- obj,
- ui->uris.ui_spp, &spp_val,
- ui->uris.ui_amp, &amp_val,
- ui->uris.param_sampleRate, &rate_val,
- NULL);
- // clang-format on
-
- if (n_props != 3 ||
- spp_val->type != ui->uris.atom_Int ||
- amp_val->type != ui->uris.atom_Float ||
- rate_val->type != ui->uris.atom_Float) {
- // Object does not have the required properties with correct types
- fprintf(stderr, "eg-scope.lv2 UI error: Corrupt state message\n");
- return 1;
- }
-
- // Get the values we need from the body of the property value atoms
- const int32_t spp = ((const LV2_Atom_Int*)spp_val)->body;
- const float amp = ((const LV2_Atom_Float*)amp_val)->body;
- const float rate = ((const LV2_Atom_Float*)rate_val)->body;
-
- // Disable transmission and update UI
- ui->updating = true;
- gtk_spin_button_set_value(GTK_SPIN_BUTTON(ui->spb_speed), spp);
- gtk_spin_button_set_value(GTK_SPIN_BUTTON(ui->spb_amp), amp);
- ui->updating = false;
- ui->rate = rate;
-
- return 0;
+ const LV2_Atom* spp_val = NULL;
+ const LV2_Atom* amp_val = NULL;
+ const LV2_Atom* rate_val = NULL;
+
+ const int n_props = lv2_atom_object_get(obj,
+ ui->uris.ui_spp,
+ &spp_val,
+ ui->uris.ui_amp,
+ &amp_val,
+ ui->uris.param_sampleRate,
+ &rate_val,
+ NULL);
+
+ if (n_props != 3 || spp_val->type != ui->uris.atom_Int ||
+ amp_val->type != ui->uris.atom_Float ||
+ rate_val->type != ui->uris.atom_Float) {
+ // Object does not have the required properties with correct types
+ fprintf(stderr, "eg-scope.lv2 UI error: Corrupt state message\n");
+ return 1;
+ }
+
+ // Get the values we need from the body of the property value atoms
+ const int32_t spp = ((const LV2_Atom_Int*)spp_val)->body;
+ const float amp = ((const LV2_Atom_Float*)amp_val)->body;
+ const float rate = ((const LV2_Atom_Float*)rate_val)->body;
+
+ // Disable transmission and update UI
+ ui->updating = true;
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(ui->spb_speed), spp);
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(ui->spb_amp), amp);
+ ui->updating = false;
+ ui->rate = rate;
+
+ return 0;
}
/**
@@ -650,35 +642,33 @@ port_event(LV2UI_Handle handle,
uint32_t format,
const void* buffer)
{
- EgScopeUI* ui = (EgScopeUI*)handle;
- const LV2_Atom* atom = (const LV2_Atom*)buffer;
-
- /* Check type of data received
- * - format == 0: Control port event (float)
- * - format > 0: Message (atom)
- */
- if (format == ui->uris.atom_eventTransfer &&
- lv2_atom_forge_is_object_type(&ui->forge, atom->type)) {
- const LV2_Atom_Object* obj = (const LV2_Atom_Object*)atom;
- if (obj->body.otype == ui->uris.RawAudio) {
- recv_raw_audio(ui, obj);
- } else if (obj->body.otype == ui->uris.ui_State) {
- recv_ui_state(ui, obj);
- }
- }
+ EgScopeUI* ui = (EgScopeUI*)handle;
+ const LV2_Atom* atom = (const LV2_Atom*)buffer;
+
+ /* Check type of data received
+ * - format == 0: Control port event (float)
+ * - format > 0: Message (atom)
+ */
+ if (format == ui->uris.atom_eventTransfer &&
+ lv2_atom_forge_is_object_type(&ui->forge, atom->type)) {
+ const LV2_Atom_Object* obj = (const LV2_Atom_Object*)atom;
+ if (obj->body.otype == ui->uris.RawAudio) {
+ recv_raw_audio(ui, obj);
+ } else if (obj->body.otype == ui->uris.ui_State) {
+ recv_ui_state(ui, obj);
+ }
+ }
}
-static const LV2UI_Descriptor descriptor = {
- SCO_URI "#ui",
- instantiate,
- cleanup,
- port_event,
- NULL
-};
+static const LV2UI_Descriptor descriptor = {SCO_URI "#ui",
+ instantiate,
+ cleanup,
+ port_event,
+ NULL};
LV2_SYMBOL_EXPORT
const LV2UI_Descriptor*
lv2ui_descriptor(uint32_t index)
{
- return index == 0 ? &descriptor : NULL;
+ return index == 0 ? &descriptor : NULL;
}
diff --git a/plugins/eg-scope.lv2/uris.h b/plugins/eg-scope.lv2/uris.h
index cba978f..8873786 100644
--- a/plugins/eg-scope.lv2/uris.h
+++ b/plugins/eg-scope.lv2/uris.h
@@ -24,47 +24,47 @@
#define SCO_URI "http://lv2plug.in/plugins/eg-scope"
typedef struct {
- // URIs defined in LV2 specifications
- LV2_URID atom_Vector;
- LV2_URID atom_Float;
- LV2_URID atom_Int;
- LV2_URID atom_eventTransfer;
- LV2_URID param_sampleRate;
+ // URIs defined in LV2 specifications
+ LV2_URID atom_Vector;
+ LV2_URID atom_Float;
+ LV2_URID atom_Int;
+ LV2_URID atom_eventTransfer;
+ LV2_URID param_sampleRate;
- /* URIs defined for this plugin. It is best to re-use existing URIs as
- much as possible, but plugins may need more vocabulary specific to their
- needs. These are used as types and properties for plugin:UI
- communication, as well as for saving state. */
- LV2_URID RawAudio;
- LV2_URID channelID;
- LV2_URID audioData;
- LV2_URID ui_On;
- LV2_URID ui_Off;
- LV2_URID ui_State;
- LV2_URID ui_spp;
- LV2_URID ui_amp;
+ /* URIs defined for this plugin. It is best to re-use existing URIs as
+ much as possible, but plugins may need more vocabulary specific to their
+ needs. These are used as types and properties for plugin:UI
+ communication, as well as for saving state. */
+ LV2_URID RawAudio;
+ LV2_URID channelID;
+ LV2_URID audioData;
+ LV2_URID ui_On;
+ LV2_URID ui_Off;
+ LV2_URID ui_State;
+ LV2_URID ui_spp;
+ LV2_URID ui_amp;
} ScoLV2URIs;
static inline void
map_sco_uris(LV2_URID_Map* map, ScoLV2URIs* uris)
{
- uris->atom_Vector = map->map(map->handle, LV2_ATOM__Vector);
- uris->atom_Float = map->map(map->handle, LV2_ATOM__Float);
- uris->atom_Int = map->map(map->handle, LV2_ATOM__Int);
- uris->atom_eventTransfer = map->map(map->handle, LV2_ATOM__eventTransfer);
- uris->param_sampleRate = map->map(map->handle, LV2_PARAMETERS__sampleRate);
+ uris->atom_Vector = map->map(map->handle, LV2_ATOM__Vector);
+ uris->atom_Float = map->map(map->handle, LV2_ATOM__Float);
+ uris->atom_Int = map->map(map->handle, LV2_ATOM__Int);
+ uris->atom_eventTransfer = map->map(map->handle, LV2_ATOM__eventTransfer);
+ uris->param_sampleRate = map->map(map->handle, LV2_PARAMETERS__sampleRate);
- /* Note the convention that URIs for types are capitalized, and URIs for
- everything else (mainly properties) are not, just as in LV2
- specifications. */
- uris->RawAudio = map->map(map->handle, SCO_URI "#RawAudio");
- uris->audioData = map->map(map->handle, SCO_URI "#audioData");
- uris->channelID = map->map(map->handle, SCO_URI "#channelID");
- uris->ui_On = map->map(map->handle, SCO_URI "#UIOn");
- uris->ui_Off = map->map(map->handle, SCO_URI "#UIOff");
- uris->ui_State = map->map(map->handle, SCO_URI "#UIState");
- uris->ui_spp = map->map(map->handle, SCO_URI "#ui-spp");
- uris->ui_amp = map->map(map->handle, SCO_URI "#ui-amp");
+ /* Note the convention that URIs for types are capitalized, and URIs for
+ everything else (mainly properties) are not, just as in LV2
+ specifications. */
+ uris->RawAudio = map->map(map->handle, SCO_URI "#RawAudio");
+ uris->audioData = map->map(map->handle, SCO_URI "#audioData");
+ uris->channelID = map->map(map->handle, SCO_URI "#channelID");
+ uris->ui_On = map->map(map->handle, SCO_URI "#UIOn");
+ uris->ui_Off = map->map(map->handle, SCO_URI "#UIOff");
+ uris->ui_State = map->map(map->handle, SCO_URI "#UIState");
+ uris->ui_spp = map->map(map->handle, SCO_URI "#ui-spp");
+ uris->ui_amp = map->map(map->handle, SCO_URI "#ui-amp");
}
-#endif /* SCO_URIS_H */
+#endif /* SCO_URIS_H */