#ifndef JALV_INTERNAL_H #define JALV_INTERNAL_H #include #include #include #include #include "lilv/lilv.h" #include "serd/serd.h" #include "lv2/lv2plug.in/ns/ext/atom/atom.h" #include "lv2/lv2plug.in/ns/ext/atom/forge.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 "zix/sem.h" #include "zix/thread.h" #include "sratom/sratom.h" #include "lv2_evbuf.h" #include "symap.h" #ifdef __cplusplus extern "C" { #endif enum PortFlow { FLOW_UNKNOWN, FLOW_INPUT, FLOW_OUTPUT }; enum PortType { TYPE_UNKNOWN, TYPE_CONTROL, TYPE_AUDIO, TYPE_EVENT }; struct Port { const LilvPort* lilv_port; enum PortType type; enum PortFlow flow; jack_port_t* jack_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 bool old_api; ///< True for event, false for atom }; /** 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* uuid; ///< Session UUID char* load; ///< Path for state 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 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 nchannels; /// int sample_rate; /// char* outfile; /// } JalvOptions; typedef struct { LV2_URID atom_Float; LV2_URID atom_Int; LV2_URID atom_eventTransfer; LV2_URID bufsz_maxBlockLength; LV2_URID bufsz_minBlockLength; LV2_URID bufsz_sequenceSize; LV2_URID log_Trace; LV2_URID midi_MidiEvent; LV2_URID param_sampleRate; LV2_URID patch_Set; 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_Sequence; LilvNode* ev_EventPort; LilvNode* lv2_AudioPort; LilvNode* lv2_ControlPort; LilvNode* lv2_InputPort; LilvNode* lv2_OutputPort; LilvNode* lv2_connectionOptional; LilvNode* lv2_control; LilvNode* lv2_name; LilvNode* midi_MidiEvent; LilvNode* pg_group; LilvNode* pset_Preset; LilvNode* rdfs_label; 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 { jack_ringbuffer_t* requests; ///< Requests to the worker jack_ringbuffer_t* 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 } JalvWorker; typedef struct { 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 Sratom* sratom; ///< Atom serialiser Sratom* ui_sratom; ///< Atom serialiser for UI thread Symap* symap; ///< URI map ZixSem symap_lock; ///< Lock for URI map jack_client_t* jack_client; ///< Jack client jack_ringbuffer_t* ui_events; ///< Port events from UI jack_ringbuffer_t* plugin_events; ///< Port events from plugin void* ui_event_buf; ///< Buffer for reading UI port events JalvWorker worker; ///< Worker thread implementation 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) 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) void* window; ///< Window (if applicable) struct Port* ports; ///< Port array of size num_ports uint32_t block_length; ///< Jack 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 longest_sym; ///< Longest port symbol float ui_update_hz; ///< Frequency of UI updates jack_nframes_t sample_rate; ///< Sample rate jack_nframes_t event_delta_t; ///< Frames since last update sent to UI uint32_t midi_event_id; ///< MIDI event class ID in event context jack_nframes_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 } Jalv; int jalv_init(int* argc, char*** argv, JalvOptions* opts); void jalv_create_ports(Jalv* jalv); struct Port* jalv_port_by_symbol(Jalv* jalv, const char* sym); 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_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 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); #ifdef __cplusplus } // extern "C" #endif #endif // JALV_INTERNAL_H