aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/eg-scope.lv2/examploscope.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/eg-scope.lv2/examploscope.c')
-rw-r--r--plugins/eg-scope.lv2/examploscope.c573
1 files changed, 284 insertions, 289 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;
+ }
}