1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
|
#ifndef JALV_INTERNAL_H
#define JALV_INTERNAL_H
#include <stdlib.h>
#include <string.h>
#include <jack/jack.h>
#include <jack/ringbuffer.h>
#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
} 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
|