aboutsummaryrefslogtreecommitdiffstats
path: root/src/jalv_internal.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/jalv_internal.h')
-rw-r--r--src/jalv_internal.h559
1 files changed, 559 insertions, 0 deletions
diff --git a/src/jalv_internal.h b/src/jalv_internal.h
new file mode 100644
index 0000000..9ee880c
--- /dev/null
+++ b/src/jalv_internal.h
@@ -0,0 +1,559 @@
+/*
+ Copyright 2007-2016 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef JALV_INTERNAL_H
+#define JALV_INTERNAL_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_ISATTY
+# include <unistd.h>
+#endif
+
+#include "lilv/lilv.h"
+#include "serd/serd.h"
+#ifdef HAVE_SUIL
+#include "suil/suil.h"
+#endif
+
+#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
+#include "lv2/lv2plug.in/ns/ext/atom/forge.h"
+#include "lv2/lv2plug.in/ns/ext/data-access/data-access.h"
+#include "lv2/lv2plug.in/ns/ext/log/log.h"
+#include "lv2/lv2plug.in/ns/ext/midi/midi.h"
+#include "lv2/lv2plug.in/ns/ext/resize-port/resize-port.h"
+#include "lv2/lv2plug.in/ns/ext/state/state.h"
+#include "lv2/lv2plug.in/ns/ext/urid/urid.h"
+#include "lv2/lv2plug.in/ns/ext/worker/worker.h"
+#include "lv2/lv2plug.in/ns/ext/options/options.h"
+
+#include "zix/ring.h"
+#include "zix/sem.h"
+#include "zix/thread.h"
+
+#include "sratom/sratom.h"
+
+#include "lv2_evbuf.h"
+#include "symap.h"
+
+#ifdef __clang__
+# define REALTIME __attribute__((annotate("realtime")))
+#else
+# define REALTIME
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct JalvBackend JalvBackend;
+
+typedef struct Jalv Jalv;
+
+enum PortFlow {
+ FLOW_UNKNOWN,
+ FLOW_INPUT,
+ FLOW_OUTPUT
+};
+
+enum PortType {
+ TYPE_UNKNOWN,
+ TYPE_CONTROL,
+ TYPE_AUDIO,
+ TYPE_EVENT,
+ TYPE_CV
+};
+
+struct Port {
+ const LilvPort* lilv_port; ///< LV2 port
+ enum PortType type; ///< Data type
+ enum PortFlow flow; ///< Data flow direction
+ void* sys_port; ///< For audio/MIDI ports, otherwise NULL
+ LV2_Evbuf* evbuf; ///< For MIDI ports, otherwise NULL
+ void* widget; ///< Control widget, if applicable
+ size_t buf_size; ///< Custom buffer size, or 0
+ uint32_t index; ///< Port index
+ float control; ///< For control ports, otherwise 0.0f
+};
+
+/* Controls */
+
+/** Type of plugin control. */
+typedef enum {
+ PORT, ///< Control port
+ PROPERTY ///< Property (set via atom message)
+} ControlType;
+
+typedef struct {
+ float value;
+ char* label;
+} ScalePoint;
+
+/** Order scale points by value. */
+int scale_point_cmp(const ScalePoint* a, const ScalePoint* b);
+
+/** Plugin control. */
+typedef struct {
+ Jalv* jalv;
+ ControlType type;
+ LilvNode* node;
+ LilvNode* symbol; ///< Symbol
+ LilvNode* label; ///< Human readable label
+ LV2_URID property; ///< Iff type == PROPERTY
+ uint32_t index; ///< Iff type == PORT
+ LilvNode* group; ///< Port/control group, or NULL
+ void* widget; ///< Control Widget
+ size_t n_points; ///< Number of scale points
+ ScalePoint* points; ///< Scale points
+ LV2_URID value_type; ///< Type of control value
+ LilvNode* min; ///< Minimum value
+ LilvNode* max; ///< Maximum value
+ LilvNode* def; ///< Default value
+ bool is_toggle; ///< Boolean (0 and 1 only)
+ bool is_integer; ///< Integer values only
+ bool is_enumeration; ///< Point values only
+ bool is_logarithmic; ///< Logarithmic scale
+ bool is_writable; ///< Writable (input)
+ bool is_readable; ///< Readable (output)
+} ControlID;
+
+ControlID*
+new_port_control(Jalv* jalv, uint32_t index);
+
+ControlID*
+new_property_control(Jalv* jalv, const LilvNode* property);
+
+typedef struct {
+ size_t n_controls;
+ ControlID** controls;
+} Controls;
+
+void
+add_control(Controls* controls, ControlID* control);
+
+ControlID*
+get_property_control(const Controls* controls, LV2_URID property);
+
+/**
+ Control change event, sent through ring buffers for UI updates.
+*/
+typedef struct {
+ uint32_t index;
+ uint32_t protocol;
+ uint32_t size;
+ uint8_t body[];
+} ControlChange;
+
+typedef struct {
+ char* name; ///< Client name
+ int name_exact; ///< Exit if name is taken
+ char* uuid; ///< Session UUID
+ char* load; ///< Path for state to load
+ char* preset; ///< URI of preset to load
+ char** controls; ///< Control values
+ uint32_t buffer_size; ///< Plugin <= >UI communication buffer size
+ double update_rate; ///< UI update rate in Hz
+ int dump; ///< Dump communication iff true
+ int trace; ///< Print trace log iff true
+ int generic_ui; ///< Use generic UI iff true
+ int show_hidden; ///< Show controls for notOnGUI ports
+ int no_menu; ///< Hide menu iff true
+ int show_ui; ///< Show non-embedded UI
+ int print_controls; ///< Print control changes to stdout
+ int non_interactive; ///< Do not listen for commands on stdin
+} JalvOptions;
+
+typedef struct {
+ LV2_URID atom_Float;
+ LV2_URID atom_Int;
+ LV2_URID atom_Object;
+ LV2_URID atom_Path;
+ LV2_URID atom_String;
+ LV2_URID atom_eventTransfer;
+ LV2_URID bufsz_maxBlockLength;
+ LV2_URID bufsz_minBlockLength;
+ LV2_URID bufsz_sequenceSize;
+ LV2_URID log_Error;
+ LV2_URID log_Trace;
+ LV2_URID log_Warning;
+ LV2_URID midi_MidiEvent;
+ LV2_URID param_sampleRate;
+ LV2_URID patch_Get;
+ LV2_URID patch_Put;
+ LV2_URID patch_Set;
+ LV2_URID patch_body;
+ LV2_URID patch_property;
+ LV2_URID patch_value;
+ LV2_URID time_Position;
+ LV2_URID time_bar;
+ LV2_URID time_barBeat;
+ LV2_URID time_beatUnit;
+ LV2_URID time_beatsPerBar;
+ LV2_URID time_beatsPerMinute;
+ LV2_URID time_frame;
+ LV2_URID time_speed;
+ LV2_URID ui_updateRate;
+} JalvURIDs;
+
+typedef struct {
+ LilvNode* atom_AtomPort;
+ LilvNode* atom_Chunk;
+ LilvNode* atom_Float;
+ LilvNode* atom_Path;
+ LilvNode* atom_Sequence;
+ LilvNode* lv2_AudioPort;
+ LilvNode* lv2_CVPort;
+ LilvNode* lv2_ControlPort;
+ LilvNode* lv2_InputPort;
+ LilvNode* lv2_OutputPort;
+ LilvNode* lv2_connectionOptional;
+ LilvNode* lv2_control;
+ LilvNode* lv2_default;
+ LilvNode* lv2_enumeration;
+ LilvNode* lv2_integer;
+ LilvNode* lv2_maximum;
+ LilvNode* lv2_minimum;
+ LilvNode* lv2_name;
+ LilvNode* lv2_reportsLatency;
+ LilvNode* lv2_sampleRate;
+ LilvNode* lv2_symbol;
+ LilvNode* lv2_toggled;
+ LilvNode* midi_MidiEvent;
+ LilvNode* pg_group;
+ LilvNode* pprops_logarithmic;
+ LilvNode* pprops_notOnGUI;
+ LilvNode* pprops_rangeSteps;
+ LilvNode* pset_Preset;
+ LilvNode* pset_bank;
+ LilvNode* rdfs_comment;
+ LilvNode* rdfs_label;
+ LilvNode* rdfs_range;
+ LilvNode* rsz_minimumSize;
+ LilvNode* work_interface;
+ LilvNode* work_schedule;
+ LilvNode* end; ///< NULL terminator for easy freeing of entire structure
+} JalvNodes;
+
+typedef enum {
+ JALV_RUNNING,
+ JALV_PAUSE_REQUESTED,
+ JALV_PAUSED
+} JalvPlayState;
+
+typedef struct {
+ Jalv* jalv; ///< Pointer back to Jalv
+ ZixRing* requests; ///< Requests to the worker
+ ZixRing* responses; ///< Responses from the worker
+ void* response; ///< Worker response buffer
+ ZixSem sem; ///< Worker semaphore
+ ZixThread thread; ///< Worker thread
+ const LV2_Worker_Interface* iface; ///< Plugin worker interface
+ bool threaded; ///< Run work in another thread
+} JalvWorker;
+
+typedef struct {
+ LV2_Feature map_feature;
+ LV2_Feature unmap_feature;
+ LV2_State_Make_Path make_path;
+ LV2_Feature make_path_feature;
+ LV2_Worker_Schedule sched;
+ LV2_Feature sched_feature;
+ LV2_Worker_Schedule ssched;
+ LV2_Feature state_sched_feature;
+ LV2_Log_Log llog;
+ LV2_Feature log_feature;
+ LV2_Options_Option options[6];
+ LV2_Feature options_feature;
+ LV2_Feature safe_restore_feature;
+ LV2_Extension_Data_Feature ext_data;
+} JalvFeatures;
+
+struct Jalv {
+ JalvOptions opts; ///< Command-line options
+ JalvURIDs urids; ///< URIDs
+ JalvNodes nodes; ///< Nodes
+ LV2_Atom_Forge forge; ///< Atom forge
+ const char* prog_name; ///< Program name (argv[0])
+ LilvWorld* world; ///< Lilv World
+ LV2_URID_Map map; ///< URI => Int map
+ LV2_URID_Unmap unmap; ///< Int => URI map
+ SerdEnv* env; ///< Environment for RDF printing
+ Sratom* sratom; ///< Atom serialiser
+ Sratom* ui_sratom; ///< Atom serialiser for UI thread
+ Symap* symap; ///< URI map
+ ZixSem symap_lock; ///< Lock for URI map
+ JalvBackend* backend; ///< Audio system backend
+ ZixRing* ui_events; ///< Port events from UI
+ ZixRing* plugin_events; ///< Port events from plugin
+ void* ui_event_buf; ///< Buffer for reading UI port events
+ JalvWorker worker; ///< Worker thread implementation
+ JalvWorker state_worker; ///< Synchronous worker for state restore
+ ZixSem work_lock; ///< Lock for plugin work() method
+ ZixSem done; ///< Exit semaphore
+ ZixSem paused; ///< Paused signal from process thread
+ JalvPlayState play_state; ///< Current play state
+ char* temp_dir; ///< Temporary plugin state directory
+ char* save_dir; ///< Plugin save directory
+ const LilvPlugin* plugin; ///< Plugin class (RDF data)
+ LilvState* preset; ///< Current preset
+ LilvUIs* uis; ///< All plugin UIs (RDF data)
+ const LilvUI* ui; ///< Plugin UI (RDF data)
+ const LilvNode* ui_type; ///< Plugin UI type (unwrapped)
+ LilvInstance* instance; ///< Plugin instance (shared library)
+#ifdef HAVE_SUIL
+ SuilHost* ui_host; ///< Plugin UI host support
+ SuilInstance* ui_instance; ///< Plugin UI instance (shared library)
+#endif
+ void* window; ///< Window (if applicable)
+ struct Port* ports; ///< Port array of size num_ports
+ Controls controls; ///< Available plugin controls
+ uint32_t block_length; ///< Audio buffer size (block length)
+ size_t midi_buf_size; ///< Size of MIDI port buffers
+ uint32_t control_in; ///< Index of control input port
+ uint32_t num_ports; ///< Size of the two following arrays:
+ uint32_t plugin_latency; ///< Latency reported by plugin (if any)
+ float ui_update_hz; ///< Frequency of UI updates
+ uint32_t sample_rate; ///< Sample rate
+ uint32_t event_delta_t; ///< Frames since last update sent to UI
+ uint32_t position; ///< Transport position in frames
+ float bpm; ///< Transport tempo in beats per minute
+ bool rolling; ///< Transport speed (0=stop, 1=play)
+ bool buf_size_set; ///< True iff buffer size callback fired
+ bool exit; ///< True iff execution is finished
+ bool has_ui; ///< True iff a control UI is present
+ bool request_update; ///< True iff a plugin update is needed
+ bool safe_restore; ///< Plugin restore() is thread-safe
+ JalvFeatures features;
+ const LV2_Feature** feature_list;
+};
+
+int
+jalv_open(Jalv* jalv, int argc, char** argv);
+
+int
+jalv_init(int* argc, char*** argv, JalvOptions* opts);
+
+int
+jalv_close(Jalv* jalv);
+
+JalvBackend*
+jalv_backend_init(Jalv* jalv);
+
+void
+jalv_backend_activate(Jalv* jalv);
+
+void
+jalv_backend_deactivate(Jalv* jalv);
+
+void
+jalv_backend_close(Jalv* jalv);
+
+/** Expose a port to the system (if applicable) and connect it to its buffer. */
+void
+jalv_backend_activate_port(Jalv* jalv, uint32_t port_index);
+
+void
+jalv_create_ports(Jalv* jalv);
+
+void
+jalv_allocate_port_buffers(Jalv* jalv);
+
+struct Port*
+jalv_port_by_symbol(Jalv* jalv, const char* sym);
+
+void
+jalv_create_controls(Jalv* jalv, bool writable);
+
+ControlID*
+jalv_control_by_symbol(Jalv* jalv, const char* sym);
+
+void
+jalv_set_control(const ControlID* control,
+ uint32_t size,
+ LV2_URID type,
+ const void* body);
+
+const char*
+jalv_native_ui_type(void);
+
+bool
+jalv_discover_ui(Jalv* jalv);
+
+int
+jalv_open_ui(Jalv* jalv);
+
+void
+jalv_init_ui(Jalv* jalv);
+
+int
+jalv_close_ui(Jalv* jalv);
+
+void
+jalv_ui_instantiate(Jalv* jalv,
+ const char* native_ui_type,
+ void* parent);
+
+bool
+jalv_ui_is_resizable(Jalv* jalv);
+
+void
+jalv_ui_write(void* const controller,
+ uint32_t port_index,
+ uint32_t buffer_size,
+ uint32_t protocol,
+ const void* buffer);
+
+void
+jalv_apply_ui_events(Jalv* jalv, uint32_t nframes);
+
+uint32_t
+jalv_ui_port_index(void* const controller, const char* symbol);
+
+void
+jalv_ui_port_event(Jalv* jalv,
+ uint32_t port_index,
+ uint32_t buffer_size,
+ uint32_t protocol,
+ const void* buffer);
+
+bool
+jalv_send_to_ui(Jalv* jalv,
+ uint32_t port_index,
+ uint32_t type,
+ uint32_t size,
+ const void* body);
+bool
+jalv_run(Jalv* jalv, uint32_t nframes);
+
+bool
+jalv_update(Jalv* jalv);
+
+int
+jalv_ui_resize(Jalv* jalv, int width, int height);
+
+typedef int (*PresetSink)(Jalv* jalv,
+ const LilvNode* node,
+ const LilvNode* title,
+ void* data);
+
+int
+jalv_load_presets(Jalv* jalv, PresetSink sink, void* data);
+
+int
+jalv_unload_presets(Jalv* jalv);
+
+int
+jalv_apply_preset(Jalv* jalv, const LilvNode* preset);
+
+int
+jalv_delete_current_preset(Jalv* jalv);
+
+int
+jalv_save_preset(Jalv* jalv,
+ const char* dir,
+ const char* uri,
+ const char* label,
+ const char* filename);
+
+void
+jalv_save(Jalv* jalv, const char* dir);
+
+void
+jalv_save_port_values(Jalv* jalv,
+ SerdWriter* writer,
+ const SerdNode* subject);
+char*
+jalv_make_path(LV2_State_Make_Path_Handle handle,
+ const char* path);
+
+void
+jalv_apply_state(Jalv* jalv, LilvState* state);
+
+char*
+atom_to_turtle(LV2_URID_Unmap* unmap,
+ const SerdNode* subject,
+ const SerdNode* predicate,
+ const LV2_Atom* atom);
+
+static inline void
+jalv_print_control(Jalv* jalv, const struct Port* port, float value)
+{
+ const LilvNode* sym = lilv_port_get_symbol(jalv->plugin, port->lilv_port);
+ printf("%s = %f\n", lilv_node_as_string(sym), value);
+}
+
+static inline char*
+jalv_strdup(const char* str)
+{
+ const size_t len = strlen(str);
+ char* copy = (char*)malloc(len + 1);
+ memcpy(copy, str, len + 1);
+ return copy;
+}
+
+static inline char*
+jalv_strjoin(const char* a, const char* b)
+{
+ const size_t a_len = strlen(a);
+ const size_t b_len = strlen(b);
+ char* const out = (char*)malloc(a_len + b_len + 1);
+
+ memcpy(out, a, a_len);
+ memcpy(out + a_len, b, b_len);
+ out[a_len + b_len] = '\0';
+
+ return out;
+}
+
+int
+jalv_printf(LV2_Log_Handle handle,
+ LV2_URID type,
+ const char* fmt, ...);
+
+int
+jalv_vprintf(LV2_Log_Handle handle,
+ LV2_URID type,
+ const char* fmt,
+ va_list ap);
+
+static inline bool
+jalv_ansi_start(FILE* stream, int color)
+{
+#ifdef HAVE_ISATTY
+ if (isatty(fileno(stream))) {
+ return fprintf(stream, "\033[0;%dm", color);
+ }
+#endif
+ return 0;
+}
+
+static inline void
+jalv_ansi_reset(FILE* stream)
+{
+#ifdef HAVE_ISATTY
+ if (isatty(fileno(stream))) {
+ fprintf(stream, "\033[0m");
+ fflush(stream);
+ }
+#endif
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // JALV_INTERNAL_H