diff options
Diffstat (limited to 'src/jalv_internal.h')
-rw-r--r-- | src/jalv_internal.h | 612 |
1 files changed, 138 insertions, 474 deletions
diff --git a/src/jalv_internal.h b/src/jalv_internal.h index 3bfc102..01d4c86 100644 --- a/src/jalv_internal.h +++ b/src/jalv_internal.h @@ -1,378 +1,130 @@ -/* - 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. -*/ +// Copyright 2007-2022 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC #ifndef JALV_INTERNAL_H #define JALV_INTERNAL_H -#define _POSIX_C_SOURCE 200809L - -#include "lv2_evbuf.h" +#include "attributes.h" +#include "control.h" +#include "jalv_config.h" +#include "log.h" +#include "nodes.h" +#include "options.h" #include "symap.h" +#include "types.h" +#include "urids.h" +#include "worker.h" #include "zix/ring.h" #include "zix/sem.h" -#include "zix/thread.h" #include "lilv/lilv.h" #include "serd/serd.h" #include "sratom/sratom.h" -#ifdef HAVE_SUIL -#include "suil/suil.h" +#if USE_SUIL +# include "suil/suil.h" #endif -#include "lv2/atom/atom.h" #include "lv2/atom/forge.h" +#include "lv2/core/lv2.h" #include "lv2/data-access/data-access.h" #include "lv2/log/log.h" -#include "lv2/midi/midi.h" #include "lv2/options/options.h" -#include "lv2/resize-port/resize-port.h" #include "lv2/state/state.h" #include "lv2/ui/ui.h" #include "lv2/urid/urid.h" #include "lv2/worker/worker.h" +#include <stdbool.h> +#include <stdint.h> #include <stdio.h> -#include <stdlib.h> -#include <string.h> -#ifdef HAVE_ISATTY -# include <unistd.h> -#endif - -#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 - char* ui_uri; ///< URI of UI to load -} 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; +JALV_BEGIN_DECLS 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_extensionData; - 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* ui_showInterface; - 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; - LV2UI_Request_Value request_value; - LV2_Feature request_value_feature; - LV2_Extension_Data_Feature ext_data; + 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[7]; + LV2_Feature options_feature; + LV2_Feature safe_restore_feature; + LV2UI_Request_Value request_value; + LV2_Feature request_value_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) +struct JalvImpl { + JalvOptions opts; ///< Command-line options + JalvURIDs urids; ///< URIDs + JalvNodes nodes; ///< Nodes + JalvLog log; ///< Log for error/warning/debug messages + LV2_Atom_Forge forge; ///< Atom forge + 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_to_plugin; ///< Port events from UI + ZixRing* plugin_to_ui; ///< 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) +#if USE_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 - float 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; + 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 + float ui_scale_factor; ///< UI scale factor + float 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 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); @@ -389,50 +141,31 @@ ControlID* jalv_control_by_symbol(Jalv* jalv, const char* sym); void -jalv_set_control(const ControlID* control, +jalv_set_control(Jalv* jalv, + 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); - -float -jalv_ui_refresh_rate(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); +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); +jalv_send_to_plugin(void* jalv_handle, + 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, @@ -440,127 +173,58 @@ jalv_ui_port_event(Jalv* jalv, 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); - -int -jalv_update(Jalv* jalv); - -typedef int (*PresetSink)(Jalv* jalv, - const LilvNode* node, - const LilvNode* title, - void* data); +/** + Write a port event using the atom:eventTransfer protocol. -int -jalv_load_presets(Jalv* jalv, PresetSink sink, void* data); + This is used to transfer atoms between the plugin and UI via sequence ports. + @param jalv Jalv instance. + @param target Communication ring (jalv->plugin_to_ui or jalv->ui_to_plugin). + @param port_index Index of the port this change is for. + @param size Size of body in bytes. + @param type Atom type URID. + @param body Atom body. + @return 0 on success, non-zero on failure (overflow). +*/ int -jalv_unload_presets(Jalv* jalv); +jalv_write_event(Jalv* jalv, + ZixRing* target, + uint32_t port_index, + uint32_t size, + LV2_URID type, + const void* body); -int -jalv_apply_preset(Jalv* jalv, const LilvNode* preset); +/** + Write a control port change using the default (0) protocol. -int -jalv_delete_current_preset(Jalv* jalv); + This is used to transfer control port value changes between the plugin and + UI. + @param jalv Jalv instance. + @param target Communication ring (jalv->plugin_to_ui or jalv->ui_to_plugin). + @param port_index Index of the port this change is for. + @param value New control port value. + @return 0 on success, non-zero on failure (overflow). +*/ int -jalv_save_preset(Jalv* jalv, - const char* dir, - const char* uri, - const char* label, - const char* filename); +jalv_write_control(Jalv* jalv, + ZixRing* target, + uint32_t port_index, + float value); void -jalv_save(Jalv* jalv, const char* dir); +jalv_dump_atom(Jalv* jalv, + FILE* stream, + const char* label, + const LV2_Atom* atom, + int color); -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, ...); +bool +jalv_run(Jalv* jalv, uint32_t nframes); 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) -{ -#if defined(HAVE_ISATTY) && defined(HAVE_FILENO) - 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 -} +jalv_update(Jalv* jalv); -#ifdef __cplusplus -} // extern "C" -#endif +JALV_END_DECLS -#endif // JALV_INTERNAL_H +#endif // JALV_INTERNAL_H |