aboutsummaryrefslogtreecommitdiffstats
path: root/src/jalv.c
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2017-02-23 19:01:03 +0100
committerDavid Robillard <d@drobilla.net>2017-02-23 19:01:03 +0100
commitc505e04d5b21a317f99c0a8459b090428e845d2e (patch)
treeabd178d9f36e6cecd418a231908a3d040a80f247 /src/jalv.c
parent0b587a635b966bee3569fbd5569b091827e33ceb (diff)
downloadjalv-c505e04d5b21a317f99c0a8459b090428e845d2e.tar.gz
jalv-c505e04d5b21a317f99c0a8459b090428e845d2e.tar.bz2
jalv-c505e04d5b21a317f99c0a8459b090428e845d2e.zip
Preliminary native OSX workosx
Diffstat (limited to 'src/jalv.c')
-rw-r--r--src/jalv.c428
1 files changed, 224 insertions, 204 deletions
diff --git a/src/jalv.c b/src/jalv.c
index 78901ca..6bf8c6b 100644
--- a/src/jalv.c
+++ b/src/jalv.c
@@ -688,6 +688,10 @@ jalv_run(Jalv* jalv, uint32_t nframes)
bool
jalv_update(Jalv* jalv)
{
+ if (!jalv->plugin) {
+ return true;
+ }
+
/* Check quit flag and close if set. */
if (zix_sem_try_wait(&exit_sem)) {
jalv_close_ui(jalv);
@@ -759,6 +763,217 @@ jalv_apply_control_arg(Jalv* jalv, const char* s)
return true;
}
+int
+jalv_load_plugin(Jalv* jalv, const LilvNode* plugin_uri, LilvState* state)
+{
+ LilvWorld* world = jalv->world;
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+
+ /* Find plugin */
+ printf("Plugin: %s\n", lilv_node_as_string(plugin_uri));
+ jalv->plugin = lilv_plugins_get_by_uri(plugins, plugin_uri);
+ /* lilv_node_free(plugin_uri); */
+ if (!jalv->plugin) {
+ fprintf(stderr, "Failed to find plugin\n");
+ lilv_world_free(world);
+ return EXIT_FAILURE;
+ }
+
+ /* Load preset, if specified */
+ if (jalv->opts.preset) {
+ LilvNode* preset = lilv_new_uri(jalv->world, jalv->opts.preset);
+
+ jalv_load_presets(jalv, NULL, NULL);
+ state = lilv_state_new_from_world(jalv->world, &jalv->map, preset);
+ jalv->preset = state;
+ lilv_node_free(preset);
+ if (!state) {
+ fprintf(stderr, "Failed to find preset <%s>\n", jalv->opts.preset);
+ lilv_world_free(world);
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* Check that any required features are supported */
+ LilvNodes* req_feats = lilv_plugin_get_required_features(jalv->plugin);
+ LILV_FOREACH(nodes, f, req_feats) {
+ const char* uri = lilv_node_as_uri(lilv_nodes_get(req_feats, f));
+ if (!feature_is_supported(uri)) {
+ fprintf(stderr, "Feature %s is not supported\n", uri);
+ lilv_world_free(world);
+ return EXIT_FAILURE;
+ }
+ }
+ lilv_nodes_free(req_feats);
+
+ /* Check for thread-safe state restore() method. */
+ LilvNode* state_threadSafeRestore = lilv_new_uri(
+ jalv->world, LV2_STATE__threadSafeRestore);
+ if (lilv_plugin_has_feature(jalv->plugin, state_threadSafeRestore)) {
+ jalv->safe_restore = true;
+ }
+ lilv_node_free(state_threadSafeRestore);
+
+ if (!state) {
+ /* Not restoring state, load the plugin as a preset to get default */
+ state = lilv_state_new_from_world(
+ jalv->world, &jalv->map, lilv_plugin_get_uri(jalv->plugin));
+ }
+
+ /* Get a plugin UI */
+ const char* native_ui_type_uri = jalv_native_ui_type(jalv);
+ jalv->uis = lilv_plugin_get_uis(jalv->plugin);
+ if (!jalv->opts.generic_ui && native_ui_type_uri) {
+ const LilvNode* native_ui_type = lilv_new_uri(jalv->world, native_ui_type_uri);
+ LILV_FOREACH(uis, u, jalv->uis) {
+ const LilvUI* this_ui = lilv_uis_get(jalv->uis, u);
+ if (lilv_ui_is_supported(this_ui,
+ suil_ui_supported,
+ native_ui_type,
+ &jalv->ui_type)) {
+ /* TODO: Multiple UI support */
+ jalv->ui = this_ui;
+ break;
+ }
+ }
+ } else if (!jalv->opts.generic_ui && jalv->opts.show_ui) {
+ jalv->ui = lilv_uis_get(jalv->uis, lilv_uis_begin(jalv->uis));
+ }
+
+ /* Create ringbuffers for UI if necessary */
+ if (jalv->ui) {
+ fprintf(stderr, "UI: %s\n",
+ lilv_node_as_uri(lilv_ui_get_uri(jalv->ui)));
+ } else {
+ fprintf(stderr, "UI: None\n");
+ }
+
+ /* Create port and control structures */
+ jalv_create_ports(jalv);
+ jalv_create_controls(jalv, true);
+ jalv_create_controls(jalv, false);
+
+ if (!(jalv->backend = jalv_backend_init(jalv))) {
+ die("Failed to connect to audio system");
+ }
+
+ printf("Sample rate: %u Hz\n", jalv->sample_rate);
+ printf("Block length: %u frames\n", jalv->block_length);
+ printf("MIDI buffers: %zu bytes\n", jalv->midi_buf_size);
+
+ if (jalv->opts.buffer_size == 0) {
+ /* The UI ring is fed by plugin output ports (usually one), and the UI
+ updates roughly once per cycle. The ring size is a few times the
+ size of the MIDI output to give the UI a chance to keep up. The UI
+ should be able to keep up with 4 cycles, and tests show this works
+ for me, but this value might need increasing to avoid overflows.
+ */
+ jalv->opts.buffer_size = jalv->midi_buf_size * N_BUFFER_CYCLES;
+ }
+
+ if (jalv->opts.update_rate == 0.0) {
+ /* Calculate a reasonable UI update frequency. */
+ jalv->ui_update_hz = (float)jalv->sample_rate / jalv->midi_buf_size * 2.0f;
+ jalv->ui_update_hz = MAX(25.0f, jalv->ui_update_hz);
+ } else {
+ /* Use user-specified UI update rate. */
+ jalv->ui_update_hz = jalv->opts.update_rate;
+ jalv->ui_update_hz = MAX(1.0f, jalv->ui_update_hz);
+ }
+
+ /* The UI can only go so fast, clamp to reasonable limits */
+ jalv->ui_update_hz = MIN(60, jalv->ui_update_hz);
+ jalv->opts.buffer_size = MAX(4096, jalv->opts.buffer_size);
+ fprintf(stderr, "Comm buffers: %d bytes\n", jalv->opts.buffer_size);
+ fprintf(stderr, "Update rate: %.01f Hz\n", jalv->ui_update_hz);
+
+ /* Build options array to pass to plugin */
+ const LV2_Options_Option options[] = {
+ { LV2_OPTIONS_INSTANCE, 0, jalv->urids.param_sampleRate,
+ sizeof(float), jalv->urids.atom_Float, &jalv->sample_rate },
+ { LV2_OPTIONS_INSTANCE, 0, jalv->urids.bufsz_minBlockLength,
+ sizeof(int32_t), jalv->urids.atom_Int, &jalv->block_length },
+ { LV2_OPTIONS_INSTANCE, 0, jalv->urids.bufsz_maxBlockLength,
+ sizeof(int32_t), jalv->urids.atom_Int, &jalv->block_length },
+ { LV2_OPTIONS_INSTANCE, 0, jalv->urids.bufsz_sequenceSize,
+ sizeof(int32_t), jalv->urids.atom_Int, &jalv->midi_buf_size },
+ { LV2_OPTIONS_INSTANCE, 0, jalv->urids.ui_updateRate,
+ sizeof(float), jalv->urids.atom_Float, &jalv->ui_update_hz },
+ { LV2_OPTIONS_INSTANCE, 0, 0, 0, 0, NULL }
+ };
+
+ options_feature.data = (void*)&options;
+
+ /* Create Plugin <=> UI communication buffers */
+ jalv->ui_events = zix_ring_new(jalv->opts.buffer_size);
+ jalv->plugin_events = zix_ring_new(jalv->opts.buffer_size);
+ zix_ring_mlock(jalv->ui_events);
+ zix_ring_mlock(jalv->plugin_events);
+
+ /* Instantiate the plugin */
+ jalv->instance = lilv_plugin_instantiate(
+ jalv->plugin, jalv->sample_rate, features);
+ if (!jalv->instance) {
+ die("Failed to instantiate plugin.\n");
+ }
+
+ ext_data.data_access = lilv_instance_get_descriptor(jalv->instance)->extension_data;
+
+ fprintf(stderr, "\n");
+ if (!jalv->buf_size_set) {
+ jalv_allocate_port_buffers(jalv);
+ }
+
+ /* Create workers if necessary */
+ if (lilv_plugin_has_feature(jalv->plugin, jalv->nodes.work_schedule)
+ && lilv_plugin_has_extension_data(jalv->plugin, jalv->nodes.work_interface)) {
+ const LV2_Worker_Interface* iface = (const LV2_Worker_Interface*)
+ lilv_instance_get_extension_data(jalv->instance, LV2_WORKER__interface);
+
+ jalv_worker_init(jalv, &jalv->worker, iface, true);
+ if (jalv->safe_restore) {
+ jalv_worker_init(jalv, &jalv->state_worker, iface, false);
+ }
+ }
+
+ /* Apply loaded state to plugin instance if necessary */
+ if (state) {
+ jalv_apply_state(jalv, state);
+ }
+
+ if (jalv->opts.controls) {
+ for (char** c = jalv->opts.controls; *c; ++c) {
+ jalv_apply_control_arg(jalv, *c);
+ }
+ }
+
+ /* Set Jack callbacks */
+ jalv_backend_init(jalv);
+
+ /* Create Jack ports and connect plugin ports to buffers */
+ for (uint32_t i = 0; i < jalv->num_ports; ++i) {
+ jalv_backend_activate_port(jalv, i);
+ }
+
+ /* Print initial control values */
+ for (size_t i = 0; i < jalv->controls.n_controls; ++i) {
+ ControlID* control = jalv->controls.controls[i];
+ if (control->type == PORT) {// && control->value_type == jalv->forge.Float) {
+ struct Port* port = &jalv->ports[control->index];
+ print_control_value(jalv, port, port->control);
+ }
+ }
+
+ /* Activate plugin */
+ lilv_instance_activate(jalv->instance);
+
+ /* Activate audio backend */
+ jalv_backend_activate(jalv);
+ jalv->play_state = JALV_RUNNING;
+
+ return 0;
+}
+
static void
signal_handler(int ignored)
{
@@ -884,7 +1099,6 @@ main(int argc, char** argv)
LilvWorld* world = lilv_world_new();
lilv_world_load_all(world);
jalv.world = world;
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
/* Cache URIs for concepts we'll use */
jalv.nodes.atom_AtomPort = lilv_new_uri(world, LV2_ATOM__AtomPort);
@@ -948,216 +1162,22 @@ main(int argc, char** argv)
plugin_uri = lilv_new_uri(world, argv[argc - 1]);
}
- if (!plugin_uri) {
- fprintf(stderr, "Missing plugin URI, try lv2ls to list plugins\n");
- return EXIT_FAILURE;
- }
-
- /* Find plugin */
- printf("Plugin: %s\n", lilv_node_as_string(plugin_uri));
- jalv.plugin = lilv_plugins_get_by_uri(plugins, plugin_uri);
- lilv_node_free(plugin_uri);
- if (!jalv.plugin) {
- fprintf(stderr, "Failed to find plugin\n");
- lilv_world_free(world);
- return EXIT_FAILURE;
- }
-
- /* Load preset, if specified */
- if (jalv.opts.preset) {
- LilvNode* preset = lilv_new_uri(jalv.world, jalv.opts.preset);
-
- jalv_load_presets(&jalv, NULL, NULL);
- state = lilv_state_new_from_world(jalv.world, &jalv.map, preset);
- jalv.preset = state;
- lilv_node_free(preset);
- if (!state) {
- fprintf(stderr, "Failed to find preset <%s>\n", jalv.opts.preset);
- lilv_world_free(world);
- return EXIT_FAILURE;
- }
- }
-
- /* Check that any required features are supported */
- LilvNodes* req_feats = lilv_plugin_get_required_features(jalv.plugin);
- LILV_FOREACH(nodes, f, req_feats) {
- const char* uri = lilv_node_as_uri(lilv_nodes_get(req_feats, f));
- if (!feature_is_supported(uri)) {
- fprintf(stderr, "Feature %s is not supported\n", uri);
- lilv_world_free(world);
- return EXIT_FAILURE;
- }
- }
- lilv_nodes_free(req_feats);
-
- /* Check for thread-safe state restore() method. */
- LilvNode* state_threadSafeRestore = lilv_new_uri(
- jalv.world, LV2_STATE__threadSafeRestore);
- if (lilv_plugin_has_feature(jalv.plugin, state_threadSafeRestore)) {
- jalv.safe_restore = true;
- }
- lilv_node_free(state_threadSafeRestore);
-
- if (!state) {
- /* Not restoring state, load the plugin as a preset to get default */
- state = lilv_state_new_from_world(
- jalv.world, &jalv.map, lilv_plugin_get_uri(jalv.plugin));
- }
+ /* if (!plugin_uri) { */
+ /* fprintf(stderr, "Missing plugin URI, try lv2ls to list plugins\n"); */
+ /* return EXIT_FAILURE; */
+ /* } */
- /* Get a plugin UI */
- const char* native_ui_type_uri = jalv_native_ui_type(&jalv);
- jalv.uis = lilv_plugin_get_uis(jalv.plugin);
- if (!jalv.opts.generic_ui && native_ui_type_uri) {
- const LilvNode* native_ui_type = lilv_new_uri(jalv.world, native_ui_type_uri);
- LILV_FOREACH(uis, u, jalv.uis) {
- const LilvUI* this_ui = lilv_uis_get(jalv.uis, u);
- if (lilv_ui_is_supported(this_ui,
- suil_ui_supported,
- native_ui_type,
- &jalv.ui_type)) {
- /* TODO: Multiple UI support */
- jalv.ui = this_ui;
- break;
- }
+ if (plugin_uri) {
+ /* Load plugin */
+ const int st = jalv_load_plugin(&jalv, plugin_uri, state);
+ if (st) {
+ return st;
}
- } else if (!jalv.opts.generic_ui && jalv.opts.show_ui) {
- jalv.ui = lilv_uis_get(jalv.uis, lilv_uis_begin(jalv.uis));
}
- /* Create ringbuffers for UI if necessary */
- if (jalv.ui) {
- fprintf(stderr, "UI: %s\n",
- lilv_node_as_uri(lilv_ui_get_uri(jalv.ui)));
- } else {
- fprintf(stderr, "UI: None\n");
- }
-
- /* Create port and control structures */
- jalv_create_ports(&jalv);
- jalv_create_controls(&jalv, true);
- jalv_create_controls(&jalv, false);
-
- if (!(jalv.backend = jalv_backend_init(&jalv))) {
- die("Failed to connect to audio system");
- }
-
- printf("Sample rate: %u Hz\n", jalv.sample_rate);
- printf("Block length: %u frames\n", jalv.block_length);
- printf("MIDI buffers: %zu bytes\n", jalv.midi_buf_size);
-
- if (jalv.opts.buffer_size == 0) {
- /* The UI ring is fed by plugin output ports (usually one), and the UI
- updates roughly once per cycle. The ring size is a few times the
- size of the MIDI output to give the UI a chance to keep up. The UI
- should be able to keep up with 4 cycles, and tests show this works
- for me, but this value might need increasing to avoid overflows.
- */
- jalv.opts.buffer_size = jalv.midi_buf_size * N_BUFFER_CYCLES;
- }
-
- if (jalv.opts.update_rate == 0.0) {
- /* Calculate a reasonable UI update frequency. */
- jalv.ui_update_hz = (float)jalv.sample_rate / jalv.midi_buf_size * 2.0f;
- jalv.ui_update_hz = MAX(25.0f, jalv.ui_update_hz);
- } else {
- /* Use user-specified UI update rate. */
- jalv.ui_update_hz = jalv.opts.update_rate;
- jalv.ui_update_hz = MAX(1.0f, jalv.ui_update_hz);
- }
-
- /* The UI can only go so fast, clamp to reasonable limits */
- jalv.ui_update_hz = MIN(60, jalv.ui_update_hz);
- jalv.opts.buffer_size = MAX(4096, jalv.opts.buffer_size);
- fprintf(stderr, "Comm buffers: %d bytes\n", jalv.opts.buffer_size);
- fprintf(stderr, "Update rate: %.01f Hz\n", jalv.ui_update_hz);
-
- /* Build options array to pass to plugin */
- const LV2_Options_Option options[] = {
- { LV2_OPTIONS_INSTANCE, 0, jalv.urids.param_sampleRate,
- sizeof(float), jalv.urids.atom_Float, &jalv.sample_rate },
- { LV2_OPTIONS_INSTANCE, 0, jalv.urids.bufsz_minBlockLength,
- sizeof(int32_t), jalv.urids.atom_Int, &jalv.block_length },
- { LV2_OPTIONS_INSTANCE, 0, jalv.urids.bufsz_maxBlockLength,
- sizeof(int32_t), jalv.urids.atom_Int, &jalv.block_length },
- { LV2_OPTIONS_INSTANCE, 0, jalv.urids.bufsz_sequenceSize,
- sizeof(int32_t), jalv.urids.atom_Int, &jalv.midi_buf_size },
- { LV2_OPTIONS_INSTANCE, 0, jalv.urids.ui_updateRate,
- sizeof(float), jalv.urids.atom_Float, &jalv.ui_update_hz },
- { LV2_OPTIONS_INSTANCE, 0, 0, 0, 0, NULL }
- };
-
- options_feature.data = (void*)&options;
-
- /* Create Plugin <=> UI communication buffers */
- jalv.ui_events = zix_ring_new(jalv.opts.buffer_size);
- jalv.plugin_events = zix_ring_new(jalv.opts.buffer_size);
- zix_ring_mlock(jalv.ui_events);
- zix_ring_mlock(jalv.plugin_events);
-
- /* Instantiate the plugin */
- jalv.instance = lilv_plugin_instantiate(
- jalv.plugin, jalv.sample_rate, features);
- if (!jalv.instance) {
- die("Failed to instantiate plugin.\n");
- }
-
- ext_data.data_access = lilv_instance_get_descriptor(jalv.instance)->extension_data;
-
- fprintf(stderr, "\n");
- if (!jalv.buf_size_set) {
- jalv_allocate_port_buffers(&jalv);
- }
-
- /* Create workers if necessary */
- if (lilv_plugin_has_feature(jalv.plugin, jalv.nodes.work_schedule)
- && lilv_plugin_has_extension_data(jalv.plugin, jalv.nodes.work_interface)) {
- const LV2_Worker_Interface* iface = (const LV2_Worker_Interface*)
- lilv_instance_get_extension_data(jalv.instance, LV2_WORKER__interface);
-
- jalv_worker_init(&jalv, &jalv.worker, iface, true);
- if (jalv.safe_restore) {
- jalv_worker_init(&jalv, &jalv.state_worker, iface, false);
- }
- }
-
- /* Apply loaded state to plugin instance if necessary */
- if (state) {
- jalv_apply_state(&jalv, state);
- }
-
- if (jalv.opts.controls) {
- for (char** c = jalv.opts.controls; *c; ++c) {
- jalv_apply_control_arg(&jalv, *c);
- }
- }
-
- /* Set Jack callbacks */
- jalv_backend_init(&jalv);
-
- /* Create Jack ports and connect plugin ports to buffers */
- for (uint32_t i = 0; i < jalv.num_ports; ++i) {
- jalv_backend_activate_port(&jalv, i);
- }
-
- /* Print initial control values */
- for (size_t i = 0; i < jalv.controls.n_controls; ++i) {
- ControlID* control = jalv.controls.controls[i];
- if (control->type == PORT) {// && control->value_type == jalv->forge.Float) {
- struct Port* port = &jalv.ports[control->index];
- print_control_value(&jalv, port, port->control);
- }
- }
-
- /* Activate plugin */
- lilv_instance_activate(jalv.instance);
-
/* Discover UI */
jalv.has_ui = jalv_discover_ui(&jalv);
- /* Activate Jack */
- jalv_backend_activate(&jalv);
- jalv.play_state = JALV_RUNNING;
-
/* Run UI (or prompt at console) */
jalv_open_ui(&jalv);