1
/* x42 jack wrapper / minimal LV2 host
3
* Copyright (C) 2012-2014 Robin Gareus
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program. If not, see <http://www.gnu.org/licenses/>.
20
#ifndef UPDATE_FREQ_RATIO
21
#define UPDATE_FREQ_RATIO 60 // MAX # of audio-cycles per GUI-refresh
24
#ifndef JACK_AUTOCONNECT
25
#define JACK_AUTOCONNECT 0
29
#define UI_UPDATE_FPS 25
33
#define MAXDELAY 192001 // delayline max possible delay
37
#define MAXPERIOD 8192 // delayline - max period size (jack-period)
40
///////////////////////////////////////////////////////////////////////////////
49
#define pthread_t //< override jack.h def
53
#include <CoreFoundation/CoreFoundation.h>
54
extern void rtk_osx_api_init(void);
55
extern void rtk_osx_api_terminate(void);
56
extern void rtk_osx_api_run(void);
57
extern void rtk_osx_api_err(const char *msg);
69
#if (defined _WIN32 && defined RTK_STATIC_INIT)
70
#include <glib-object.h>
76
#include <sys/timeb.h>
80
#include "weakjack/weak_libjack.h"
82
#include <jack/jack.h>
83
#include <jack/ringbuffer.h>
84
#include <jack/midiport.h>
88
#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
89
#include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
90
#include "lv2/lv2plug.in/ns/ext/uri-map/uri-map.h"
91
#include "lv2/lv2plug.in/ns/ext/urid/urid.h"
92
#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
93
#include "lv2/lv2plug.in/ns/ext/atom/forge.h"
94
#include "lv2/lv2plug.in/ns/ext/midi/midi.h"
95
#include "lv2/lv2plug.in/ns/ext/time/time.h"
96
#include "lv2/lv2plug.in/ns/ext/worker/worker.h"
98
#include "./gl/xternalui.h"
105
#define LV2_EXTERNAL_UI_RUN(ptr) (ptr)->run(ptr)
106
#define LV2_EXTERNAL_UI_SHOW(ptr) (ptr)->show(ptr)
107
#define LV2_EXTERNAL_UI_HIDE(ptr) (ptr)->hide(ptr)
111
static const LV2_Descriptor* plugin_dsp;
112
static const LV2UI_Descriptor *plugin_gui;
114
static LV2_Handle plugin_instance = NULL;
115
static LV2UI_Handle gui_instance = NULL;
117
static float *plugin_ports_pre = NULL;
118
static float *plugin_ports_post = NULL;
120
static LV2_Atom_Sequence *atom_in = NULL;
121
static LV2_Atom_Sequence *atom_out = NULL;
123
static jack_port_t **input_port = NULL;
124
static jack_port_t **output_port = NULL;
126
static jack_port_t *midi_in = NULL;
127
static jack_port_t *midi_out = NULL;
129
static jack_client_t *j_client = NULL;
130
static uint32_t j_samplerate = 48000;
132
static int _freewheeling = 0;
134
struct transport_position {
135
jack_nframes_t position;
138
} j_transport = {0, 0, false};
140
static jack_ringbuffer_t *rb_ctrl_to_ui = NULL;
141
static jack_ringbuffer_t *rb_ctrl_from_ui = NULL;
142
static jack_ringbuffer_t *rb_atom_to_ui = NULL;
143
static jack_ringbuffer_t *rb_atom_from_ui = NULL;
145
static pthread_mutex_t gui_thread_lock = PTHREAD_MUTEX_INITIALIZER;
146
static pthread_cond_t data_ready = PTHREAD_COND_INITIALIZER;
148
static uint32_t uri_midi_MidiEvent = 0;
149
static uint32_t uri_atom_Sequence = 0;
150
static uint32_t uri_atom_EventTransfer = 0;
152
static uint32_t uri_time_Position = 0;
153
static uint32_t uri_time_frame = 0;
154
static uint32_t uri_time_speed = 0;
155
static uint32_t uri_time_bar = 0;
156
static uint32_t uri_time_barBeat = 0;
157
static uint32_t uri_time_beatUnit = 0;
158
static uint32_t uri_time_beatsPerBar = 0;
159
static uint32_t uri_time_beatsPerMinute = 0;
161
static char **urimap = NULL;
162
static uint32_t urimap_len = 0;
176
jack_latency_range_t port_latency;
178
int c_dly; // current delay
181
float out_buffer[MAXPERIOD]; // TODO dynamically allocate, use jack-period
182
float delay_buffer[MAXDELAY];
187
enum PortType porttype;
191
typedef struct _RtkLv2Description {
192
const LV2_Descriptor* (*lv2_descriptor)(uint32_t index);
193
const LV2UI_Descriptor* (*lv2ui_descriptor)(uint32_t index);
195
const uint32_t dsp_descriptor_id;
196
const uint32_t gui_descriptor_id;
197
const char *plugin_human_id;
199
const struct LV2Port *ports;
201
const uint32_t nports_total;
202
const uint32_t nports_audio_in;
203
const uint32_t nports_audio_out;
204
const uint32_t nports_midi_in;
205
const uint32_t nports_midi_out;
206
const uint32_t nports_atom_in;
207
const uint32_t nports_atom_out;
208
const uint32_t nports_ctrl;
209
const uint32_t nports_ctrl_in;
210
const uint32_t nports_ctrl_out;
211
const uint32_t min_atom_bufsiz;
212
const bool send_time_info;
215
static RtkLv2Description const *inst;
217
/* a simple state machine for this client */
218
static volatile enum {
221
} client_state = Run;
223
static struct lv2_external_ui_host extui_host;
224
static struct lv2_external_ui *extui = NULL;
226
static LV2UI_Controller controller = NULL;
228
static LV2_Atom_Forge lv2_forge;
229
static uint32_t *portmap_a_in;
230
static uint32_t *portmap_a_out;
231
static uint32_t *portmap_rctl;
232
static int *portmap_ctrl;
233
static uint32_t portmap_atom_to_ui = -1;
234
static uint32_t portmap_atom_from_ui = -1;
236
static uint32_t uri_to_id(LV2_URI_Map_Callback_Data callback_data, const char* uri);
239
static jack_ringbuffer_t* worker_requests = NULL;
240
static jack_ringbuffer_t* worker_responses = NULL;
241
static pthread_t worker_thread;
242
static pthread_mutex_t worker_lock = PTHREAD_MUTEX_INITIALIZER;
243
static pthread_cond_t worker_ready = PTHREAD_COND_INITIALIZER;
244
static LV2_Worker_Interface* worker_iface = NULL;
246
static struct DelayBuffer **delayline = NULL;
247
static uint32_t worst_capture_latency = 0;
248
static uint32_t plugin_latency = 0;
250
/******************************************************************************
251
* Delayline for latency compensation
253
#define FADE_LEN (16)
255
#define INCREMENT_PTRS \
256
dly->r_ptr = (dly->r_ptr + 1) % MAXDELAY; \
257
dly->w_ptr = (dly->w_ptr + 1) % MAXDELAY;
260
delay_port (struct DelayBuffer *dly, uint32_t n_samples, float *in)
263
const int delay = dly->wanted_delay;
264
const float * const input = in;
265
float* const output = dly->out_buffer;
267
if (dly->c_dly == delay && delay == 0) {
268
// only copy data into buffer in case delay time changes
269
for (; pos < n_samples; pos++) {
270
dly->delay_buffer[ dly->w_ptr ] = input[pos];
276
// fade if delaytime changes
277
if (dly->c_dly != delay) {
278
const uint32_t fade_len = (n_samples >= FADE_LEN) ? FADE_LEN : n_samples / 2;
281
for (; pos < fade_len; pos++) {
282
const float gain = (float)(fade_len - pos) / (float)fade_len;
283
dly->delay_buffer[ dly->w_ptr ] = input[pos];
284
output[pos] = dly->delay_buffer[ dly->r_ptr ] * gain;
288
// update read pointer
289
dly->r_ptr += dly->c_dly - delay;
290
if (dly->r_ptr < 0) {
291
dly->r_ptr -= MAXDELAY * floor(dly->r_ptr / (float)MAXDELAY);
294
//printf("Delay changed %d -> %d\n", dly->c_dly, delay); // DEBUG
295
dly->r_ptr = dly->r_ptr % MAXDELAY;
299
for (; pos < 2 * fade_len; pos++) {
300
const float gain = (float)(pos - fade_len) / (float)fade_len;
301
dly->delay_buffer[ dly->w_ptr ] = input[pos];
302
output[pos] = dly->delay_buffer[ dly->r_ptr ] * gain;
307
for (; pos < n_samples; pos++) {
308
dly->delay_buffer[ dly->w_ptr ] = input[pos];
309
output[pos] = dly->delay_buffer[ dly->r_ptr ];
313
return dly->out_buffer;
317
///////////////////////////
318
// GET INFO FROM LV2 TTL //
321
///////////////////////////
322
#include JACK_DESCRIPT ////
323
///////////////////////////
326
/******************************************************************************
330
static int process (jack_nframes_t nframes, void *arg) {
331
while (jack_ringbuffer_read_space(rb_ctrl_from_ui) >= sizeof(uint32_t) + sizeof(float)) {
333
jack_ringbuffer_read(rb_ctrl_from_ui, (char*) &idx, sizeof(uint32_t));
334
jack_ringbuffer_read(rb_ctrl_from_ui, (char*) &(plugin_ports_pre[idx]), sizeof(float));
337
/* Get Jack transport position */
339
const bool rolling = (jack_transport_query(j_client, &pos) == JackTransportRolling);
340
const bool transport_changed = (rolling != j_transport.rolling
341
|| pos.frame != j_transport.position
342
|| ((pos.valid & JackPositionBBT) && (pos.beats_per_minute != j_transport.bpm)));
345
if (inst->nports_atom_in > 0 || inst->nports_midi_in > 0) {
346
/* start Atom sequence */
347
atom_in->atom.type = uri_atom_Sequence;
348
atom_in->atom.size = 8;
349
LV2_Atom_Sequence_Body *body = &atom_in->body;
350
body->unit = 0; // URID of unit of event time stamp LV2_ATOM__timeUnit ??
351
body->pad = 0; // unused
352
uint8_t * seq = (uint8_t*) (body + 1);
354
if (transport_changed && inst->send_time_info) {
355
uint8_t pos_buf[256];
356
LV2_Atom* lv2_pos = (LV2_Atom*)pos_buf;
358
lv2_atom_forge_set_buffer(&lv2_forge, pos_buf, sizeof(pos_buf));
359
LV2_Atom_Forge* forge = &lv2_forge;
360
LV2_Atom_Forge_Frame frame;
362
lv2_atom_forge_object(&lv2_forge, &frame, 1, uri_time_Position);
364
lv2_atom_forge_blank(&lv2_forge, &frame, 1, uri_time_Position);
366
lv2_atom_forge_property_head(forge, uri_time_frame, 0);
367
lv2_atom_forge_long(forge, pos.frame);
368
lv2_atom_forge_property_head(forge, uri_time_speed, 0);
369
lv2_atom_forge_float(forge, rolling ? 1.0 : 0.0);
370
if (pos.valid & JackPositionBBT) {
371
lv2_atom_forge_property_head(forge, uri_time_barBeat, 0);
372
lv2_atom_forge_float(
373
forge, pos.beat - 1 + (pos.tick / pos.ticks_per_beat));
374
lv2_atom_forge_property_head(forge, uri_time_bar, 0);
375
lv2_atom_forge_long(forge, pos.bar - 1);
376
lv2_atom_forge_property_head(forge, uri_time_beatUnit, 0);
377
lv2_atom_forge_int(forge, pos.beat_type);
378
lv2_atom_forge_property_head(forge, uri_time_beatsPerBar, 0);
379
lv2_atom_forge_float(forge, pos.beats_per_bar);
380
lv2_atom_forge_property_head(forge, uri_time_beatsPerMinute, 0);
381
lv2_atom_forge_float(forge, pos.beats_per_minute);
384
uint32_t size = lv2_pos->size;
385
uint32_t padded_size = ((sizeof(LV2_Atom_Event) + size) + 7) & (~7);
387
if (inst->min_atom_bufsiz > padded_size) {
388
printf("send time..\n");
389
LV2_Atom_Event *aev = (LV2_Atom_Event *)seq;
390
aev->time.frames = 0;
391
aev->body.size = size;
392
aev->body.type = lv2_pos->type;
393
memcpy(LV2_ATOM_BODY(&aev->body), LV2_ATOM_BODY(lv2_pos), size);
394
atom_in->atom.size += padded_size;
398
// TODO only if UI..?
399
while (jack_ringbuffer_read_space(rb_atom_from_ui) > sizeof(LV2_Atom)) {
401
jack_ringbuffer_read(rb_atom_from_ui, (char *) &a, sizeof(LV2_Atom));
402
uint32_t padded_size = atom_in->atom.size + a.size + sizeof(int64_t);
403
if (inst->min_atom_bufsiz > padded_size) {
404
memset(seq, 0, sizeof(int64_t)); // LV2_Atom_Event->time
405
seq += sizeof(int64_t);
406
jack_ringbuffer_read(rb_atom_from_ui, (char *) seq, a.size);
408
atom_in->atom.size += a.size + sizeof(int64_t);
411
if (inst->nports_midi_in > 0) {
412
/* inject midi events */
413
void* buf = jack_port_get_buffer(midi_in, nframes);
414
for (uint32_t i = 0; i < jack_midi_get_event_count(buf); ++i) {
415
jack_midi_event_t ev;
416
jack_midi_event_get(&ev, buf, i);
418
uint32_t size = ev.size;
419
uint32_t padded_size = ((sizeof(LV2_Atom_Event) + size) + 7) & (~7);
421
if (inst->min_atom_bufsiz > padded_size) {
422
LV2_Atom_Event *aev = (LV2_Atom_Event *)seq;
423
aev->time.frames = ev.time;
424
aev->body.size = size;
425
aev->body.type = uri_midi_MidiEvent;
426
memcpy(LV2_ATOM_BODY(&aev->body), ev.buffer, size);
427
atom_in->atom.size += padded_size;
434
if (inst->nports_atom_out > 0 || inst->nports_midi_out > 0) {
435
atom_out->atom.type = 0;
436
atom_out->atom.size = inst->min_atom_bufsiz;
439
/* make a backup copy, to see what was changed */
440
memcpy(plugin_ports_post, plugin_ports_pre, inst->nports_ctrl * sizeof(float));
442
/* expected transport state in next cycle */
443
j_transport.position = rolling ? pos.frame + nframes : pos.frame;
444
j_transport.bpm = pos.beats_per_minute;
445
j_transport.rolling = rolling;
447
/* [re] connect jack audio buffers */
448
for (uint32_t i=0 ; i < inst->nports_audio_out; i++) {
449
plugin_dsp->connect_port(plugin_instance, portmap_a_out[i], jack_port_get_buffer (output_port[i], nframes));
452
for (uint32_t i=0; i < inst->nports_audio_in; i++) {
453
delayline[i]->wanted_delay = worst_capture_latency - delayline[i]->port_latency.max;
454
plugin_dsp->connect_port(
455
plugin_instance, portmap_a_in[i],
456
delay_port(delayline[i], nframes, (float*) jack_port_get_buffer (input_port[i], nframes))
461
plugin_dsp->run(plugin_instance, nframes);
463
/* handle worker emit response - may amend Atom seq... */
464
if (worker_responses) {
465
uint32_t read_space = jack_ringbuffer_read_space(worker_responses);
468
char worker_response[4096];
469
jack_ringbuffer_read(worker_responses, (char*)&size, sizeof(size));
470
jack_ringbuffer_read(worker_responses, worker_response, size);
471
worker_iface->work_response(plugin_instance, size, worker_response);
472
read_space -= sizeof(size) + size;
476
/* create port-events for change values */
477
// TODO only if UI..?
478
for (uint32_t p = 0; p < inst->nports_ctrl; p++) {
479
if (inst->ports[portmap_rctl[p]].porttype != CONTROL_OUT) continue;
481
if (plugin_ports_pre[p] != plugin_ports_post[p]) {
483
if (TODO this port reportsLatency) {
484
plugin_latency = rintf(plugin_ports_pre[p]);
485
jack_recompute_total_latencies(j_client);
488
if (jack_ringbuffer_write_space(rb_ctrl_to_ui) >= sizeof(uint32_t) + sizeof(float)) {
489
jack_ringbuffer_write(rb_ctrl_to_ui, (char *) &portmap_rctl[p], sizeof(uint32_t));
490
jack_ringbuffer_write(rb_ctrl_to_ui, (char *) &plugin_ports_pre[p], sizeof(float));
495
if (inst->nports_midi_out > 0) {
496
void* buf = jack_port_get_buffer(midi_out, nframes);
497
jack_midi_clear_buffer(buf);
500
/* Atom sequence port-events */
501
if (inst->nports_atom_out + inst->nports_midi_out > 0 && atom_out->atom.size > sizeof(LV2_Atom)) {
502
// TODO only if UI..?
503
if (jack_ringbuffer_write_space(rb_atom_to_ui) >= atom_out->atom.size + 2 * sizeof(LV2_Atom)) {
504
LV2_Atom a = {atom_out->atom.size + (uint32_t) sizeof(LV2_Atom), 0};
505
jack_ringbuffer_write(rb_atom_to_ui, (char *) &a, sizeof(LV2_Atom));
506
jack_ringbuffer_write(rb_atom_to_ui, (char *) atom_out, a.size);
509
if (inst->nports_midi_out) {
510
void* buf = jack_port_get_buffer(midi_out, nframes);
511
LV2_Atom_Event const* ev = (LV2_Atom_Event const*)((&(atom_out)->body) + 1); // lv2_atom_sequence_begin
512
while((const uint8_t*)ev < ((const uint8_t*) &(atom_out)->body + (atom_out)->atom.size)) {
513
if (ev->body.type == uri_midi_MidiEvent) {
514
jack_midi_event_write(buf, ev->time.frames, (const uint8_t*)(ev+1), ev->body.size);
516
ev = (LV2_Atom_Event const*) /* lv2_atom_sequence_next() */
517
((const uint8_t*)ev + sizeof(LV2_Atom_Event) + ((ev->body.size + 7) & ~7));
522
/* signal worker end of process run */
523
if (worker_iface && worker_iface->end_run) {
524
worker_iface->end_run(plugin_instance);
528
if (jack_ringbuffer_read_space(rb_ctrl_to_ui) > sizeof(uint32_t) + sizeof(float)
529
|| jack_ringbuffer_read_space(rb_atom_to_ui) > sizeof(LV2_Atom)
531
if (pthread_mutex_trylock (&gui_thread_lock) == 0) {
532
pthread_cond_signal (&data_ready);
533
pthread_mutex_unlock (&gui_thread_lock);
540
static void jack_shutdown (void *arg) {
541
fprintf(stderr,"recv. shutdown request from jackd.\n");
543
pthread_cond_signal (&data_ready);
546
static int jack_graph_order_cb (void *arg) {
547
worst_capture_latency = 0;
548
for (uint32_t i = 0; i < inst->nports_audio_in; i++) {
549
jack_port_get_latency_range(input_port[i], JackCaptureLatency, &(delayline[i]->port_latency));
550
if (delayline[i]->port_latency.max > worst_capture_latency) {
551
worst_capture_latency = delayline[i]->port_latency.max;
557
static void jack_latency_cb (jack_latency_callback_mode_t mode, void *arg) {
559
// TODO add systemic latency of plugin (currently no robtk plugins add latency)
560
jack_graph_order_cb(NULL); // update worst-case latency, delayline alignment
561
if (mode == JackCaptureLatency) {
562
for (uint32_t i = 0; i < inst->nports_audio_out; i++) {
563
jack_latency_range_t r;
564
if (i < inst->nports_audio_in) {
565
const uint32_t port_delay = worst_capture_latency - delayline[i]->port_latency.max;
566
jack_port_get_latency_range(input_port[i], JackCaptureLatency, &r);
572
r.min += plugin_latency;
573
r.max += plugin_latency;
574
jack_port_set_latency_range(output_port[i], JackCaptureLatency, &r);
576
} else { // JackPlaybackLatency
577
for (uint32_t i = 0; i < inst->nports_audio_in; i++) {
578
const uint32_t port_delay = worst_capture_latency - delayline[i]->port_latency.max;
579
jack_latency_range_t r;
580
if (i < inst->nports_audio_out) {
581
jack_port_get_latency_range(output_port[i], JackPlaybackLatency, &r);
585
r.min += port_delay + plugin_latency;
586
r.max += port_delay + plugin_latency;
587
jack_port_set_latency_range(input_port[i], JackPlaybackLatency, &r);
592
static void jack_freewheel_cb (int onoff, void *arg) {
593
_freewheeling = onoff;
596
static int init_jack(const char *client_name) {
597
jack_status_t status;
598
j_client = jack_client_open (client_name, JackNoStartServer, &status);
599
if (j_client == NULL) {
600
fprintf (stderr, "jack_client_open() failed, status = 0x%2.0x\n", status);
601
if (status & JackServerFailed) {
602
fprintf (stderr, "Unable to connect to JACK server\n");
606
if (status & JackServerStarted) {
607
fprintf (stderr, "JACK server started\n");
609
if (status & JackNameNotUnique) {
610
client_name = jack_get_client_name(j_client);
611
fprintf (stderr, "jack-client name: `%s'\n", client_name);
614
jack_set_process_callback (j_client, process, 0);
615
jack_set_graph_order_callback (j_client, jack_graph_order_cb, 0);
616
jack_set_latency_callback(j_client, jack_latency_cb, 0);
617
jack_set_freewheel_callback(j_client, jack_freewheel_cb, 0);
620
jack_on_shutdown (j_client, jack_shutdown, NULL);
622
j_samplerate=jack_get_sample_rate (j_client);
626
static int jack_portsetup(void) {
627
/* Allocate data structures that depend on the number of ports. */
628
input_port = (jack_port_t **) malloc (sizeof (jack_port_t *) * inst->nports_audio_in);
629
delayline = (struct DelayBuffer **) calloc (inst->nports_audio_in, sizeof (struct DelayBuffer *));
631
for (uint32_t i = 0; i < inst->nports_audio_in; i++) {
632
if ((input_port[i] = jack_port_register (j_client,
633
inst->ports[portmap_a_in[i]].name,
634
JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0)) == 0) {
635
fprintf (stderr, "cannot register input port \"%s\"!\n", inst->ports[portmap_a_in[i]].name);
638
delayline[i] = (struct DelayBuffer *) calloc (1, sizeof (struct DelayBuffer));
641
output_port = (jack_port_t **) malloc (sizeof (jack_port_t *) * inst->nports_audio_out);
643
for (uint32_t i = 0; i < inst->nports_audio_out; i++) {
644
if ((output_port[i] = jack_port_register (j_client,
645
inst->ports[portmap_a_out[i]].name,
646
JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) == 0) {
647
fprintf (stderr, "cannot register output port \"%s\"!\n", inst->ports[portmap_a_out[i]].name);
652
if (inst->nports_midi_in){
653
if ((midi_in = jack_port_register (j_client,
654
inst->ports[portmap_atom_from_ui].name,
655
JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0)) == 0) {
656
fprintf (stderr, "cannot register midi input port \"%s\"!\n", inst->ports[portmap_atom_from_ui].name);
661
if (inst->nports_midi_out){
662
if ((midi_out = jack_port_register (j_client,
663
inst->ports[portmap_atom_to_ui].name,
664
JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0)) == 0) {
665
fprintf (stderr, "cannot register midi ouput port \"%s\"!\n", inst->ports[portmap_atom_to_ui].name);
669
jack_graph_order_cb (NULL); // query port latencies
670
jack_recompute_total_latencies(j_client);
674
static void jack_portconnect(int which) {
676
if (which & 1) { // connect audio input(s)
677
const char **ports = jack_get_ports(j_client, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput|JackPortIsPhysical);
678
for (uint32_t i = 0; i < inst->nports_audio_in && ports && ports[i]; i++) {
679
if (jack_connect (j_client, jack_port_name (input_port[i]), ports[i]))
682
if (ports) { jack_free(ports); }
685
if (which & 2) { // connect audio outputs(s)
686
const char **ports = jack_get_ports(j_client, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput|JackPortIsPhysical);
687
for (uint32_t i = 0; i < inst->nports_audio_out && ports && ports[i]; i++) {
688
if (jack_connect (j_client, jack_port_name (output_port[i]), ports[i]))
691
if (ports) { jack_free(ports); }
694
if ((which & 4) && midi_in) { // midi in
695
const char **ports = jack_get_ports(j_client, NULL, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput|JackPortIsPhysical);
696
if (ports && ports[0]) {
697
jack_connect (j_client, jack_port_name (midi_in), ports[0]);
699
if (ports) { jack_free(ports); }
702
if ((which & 8) && midi_out) { // midi out
703
const char **ports = jack_get_ports(j_client, NULL, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput|JackPortIsPhysical);
704
if (ports && ports[0]) {
705
jack_connect (j_client, jack_port_name (midi_out), ports[0]);
707
if (ports) { jack_free(ports); }
712
/******************************************************************************
716
static uint32_t uri_to_id(LV2_URI_Map_Callback_Data callback_data, const char* uri) {
717
for (uint32_t i=0; i < urimap_len; ++i) {
718
if (!strcmp(urimap[i], uri)) {
719
//printf("Found mapped URI '%s' -> %d\n", uri, i);
723
//printf("map URI '%s' -> %d\n", uri, urimap_len);
724
urimap = (char**) realloc(urimap, (urimap_len + 1) * sizeof(char*));
725
urimap[urimap_len] = strdup(uri);
729
static void free_uri_map() {
730
for (uint32_t i=0; i < urimap_len; ++i) {
736
static void write_function(
737
LV2UI_Controller controller,
739
uint32_t buffer_size,
740
uint32_t port_protocol,
741
const void* buffer) {
743
if (buffer_size == 0) return;
745
if (port_protocol != 0) {
746
if (jack_ringbuffer_write_space(rb_atom_from_ui) >= buffer_size + sizeof(LV2_Atom)) {
747
LV2_Atom a = {buffer_size, 0};
748
jack_ringbuffer_write(rb_atom_from_ui, (char *) &a, sizeof(LV2_Atom));
749
jack_ringbuffer_write(rb_atom_from_ui, (char *) buffer, buffer_size);
753
if (buffer_size != sizeof(float)) {
754
fprintf(stderr, "LV2Host: write_function() unsupported buffer\n");
757
if (port_index < inst->nports_total && portmap_ctrl[port_index] < 0) {
758
fprintf(stderr, "LV2Host: write_function() unmapped port\n");
761
if (jack_ringbuffer_write_space(rb_ctrl_from_ui) >= sizeof(uint32_t) + sizeof(float)) {
762
jack_ringbuffer_write(rb_ctrl_from_ui, (char *) &portmap_ctrl[port_index], sizeof(uint32_t));
763
jack_ringbuffer_write(rb_ctrl_from_ui, (char *) buffer, sizeof(float));
769
static LV2_Worker_Status
770
lv2_worker_respond(LV2_Worker_Respond_Handle unused,
774
jack_ringbuffer_write(worker_responses, (const char*)&size, sizeof(size));
775
jack_ringbuffer_write(worker_responses, (const char*)data, size);
776
return LV2_WORKER_SUCCESS;
780
static void* worker_func(void* data) {
781
pthread_mutex_lock (&worker_lock);
786
if (jack_ringbuffer_read_space(worker_requests) <= sizeof(size)) {
787
pthread_cond_wait(&worker_ready, &worker_lock);
790
if (client_state == Exit) break;
792
jack_ringbuffer_read(worker_requests, (char*)&size, sizeof(size));
795
fprintf(stderr, "Worker information is too large. Abort.\n");
799
jack_ringbuffer_read(worker_requests, buf, size);
800
worker_iface->work(plugin_instance, lv2_worker_respond, NULL, size, buf);
802
pthread_mutex_unlock (&worker_lock);
806
static void worker_init() {
807
worker_requests = jack_ringbuffer_create(4096);
808
worker_responses = jack_ringbuffer_create(4096);
809
jack_ringbuffer_mlock(worker_requests);
810
jack_ringbuffer_mlock(worker_responses);
811
pthread_create(&worker_thread, NULL, worker_func, NULL);
814
static LV2_Worker_Status
815
lv2_worker_schedule(LV2_Worker_Schedule_Handle unused,
820
worker_iface->work(plugin_instance, lv2_worker_respond, NULL, size, data);
821
return LV2_WORKER_SUCCESS;
823
assert(worker_requests);
824
jack_ringbuffer_write(worker_requests, (const char*)&size, sizeof(size));
825
jack_ringbuffer_write(worker_requests, (const char*)data, size);
826
if (pthread_mutex_trylock (&worker_lock) == 0) {
827
pthread_cond_signal (&worker_ready);
828
pthread_mutex_unlock (&worker_lock);
830
return LV2_WORKER_SUCCESS;
833
/******************************************************************************
837
static void cleanup(int sig) {
839
jack_client_close (j_client);
843
if (worker_requests) {
844
pthread_mutex_lock (&worker_lock);
845
pthread_cond_signal (&worker_ready);
846
pthread_mutex_unlock (&worker_lock);
848
pthread_join(worker_thread, NULL);
850
jack_ringbuffer_free(worker_requests);
851
jack_ringbuffer_free(worker_responses);
854
if (plugin_dsp && plugin_instance && plugin_dsp->deactivate) {
855
plugin_dsp->deactivate(plugin_instance);
857
if (plugin_gui && gui_instance && plugin_gui->cleanup) {
858
plugin_gui->cleanup(gui_instance);
860
if (plugin_dsp && plugin_instance && plugin_dsp->cleanup) {
861
plugin_dsp->cleanup(plugin_instance);
864
jack_ringbuffer_free(rb_ctrl_to_ui);
865
jack_ringbuffer_free(rb_ctrl_from_ui);
867
jack_ringbuffer_free(rb_atom_to_ui);
868
jack_ringbuffer_free(rb_atom_from_ui);
874
for (uint32_t i = 0; i < inst->nports_audio_in; i++) {
880
free(plugin_ports_pre);
881
free(plugin_ports_post);
887
fprintf(stderr, "bye.\n");
890
static void run_one(LV2_Atom_Sequence *data) {
892
while (jack_ringbuffer_read_space(rb_ctrl_to_ui) >= sizeof(uint32_t) + sizeof(float)) {
895
jack_ringbuffer_read(rb_ctrl_to_ui, (char*) &idx, sizeof(uint32_t));
896
jack_ringbuffer_read(rb_ctrl_to_ui, (char*) &val, sizeof(float));
897
plugin_gui->port_event(gui_instance, idx, sizeof(float), 0, &val);
900
while (jack_ringbuffer_read_space(rb_atom_to_ui) > sizeof(LV2_Atom)) {
902
jack_ringbuffer_read(rb_atom_to_ui, (char *) &a, sizeof(LV2_Atom));
903
assert(a.size < inst->min_atom_bufsiz);
904
jack_ringbuffer_read(rb_atom_to_ui, (char *) data, a.size);
905
LV2_Atom_Event const* ev = (LV2_Atom_Event const*)((&(data)->body) + 1); // lv2_atom_sequence_begin
906
while((const uint8_t*)ev < ((const uint8_t*) &(data)->body + (data)->atom.size)) {
907
plugin_gui->port_event(gui_instance, portmap_atom_to_ui,
908
ev->body.size, uri_atom_EventTransfer, &ev->body);
909
ev = (LV2_Atom_Event const*) /* lv2_atom_sequence_next() */
910
((const uint8_t*)ev + sizeof(LV2_Atom_Event) + ((ev->body.size + 7) & ~7));
914
LV2_EXTERNAL_UI_RUN(extui);
919
static void osx_loop (CFRunLoopTimerRef timer, void *info) {
920
if (client_state == Run) {
921
run_one((LV2_Atom_Sequence*)info);
923
if (client_state == Exit) {
924
rtk_osx_api_terminate();
931
static void main_loop(void) {
932
struct timespec timeout;
933
LV2_Atom_Sequence *data = (LV2_Atom_Sequence*) malloc(inst->min_atom_bufsiz * sizeof(uint8_t));
935
pthread_mutex_lock (&gui_thread_lock);
936
while (client_state != Exit) {
939
if (client_state == Exit) break;
942
//Sleep(1000/UI_UPDATE_FPS);
943
#if (defined(__MINGW64__) || defined(__MINGW32__)) && __MSVCRT_VERSION__ >= 0x0601
944
struct __timeb64 timebuffer;
945
_ftime64(&timebuffer);
947
struct __timeb32 timebuffer;
950
timeout.tv_nsec = timebuffer.millitm * 1000000;
951
timeout.tv_sec = timebuffer.time;
953
clock_gettime(CLOCK_REALTIME, &timeout);
955
timeout.tv_nsec += 1000000000 / (UI_UPDATE_FPS);
956
if (timeout.tv_nsec >= 1000000000) {timeout.tv_nsec -= 1000000000; timeout.tv_sec+=1;}
957
pthread_cond_timedwait (&data_ready, &gui_thread_lock, &timeout);
959
} /* while running */
961
pthread_mutex_unlock (&gui_thread_lock);
963
#endif // APPLE RUNLOOP
965
static void catchsig (int sig) {
966
fprintf(stderr,"caught signal - shutting down.\n");
968
pthread_cond_signal (&data_ready);
971
static void on_external_ui_closed(void* controller) {
975
#ifdef X42_MULTIPLUGIN
976
static void list_plugins (void) {
978
for (i = 0; i < sizeof(_plugins) / sizeof(RtkLv2Description); ++i) {
979
const LV2_Descriptor* d = _plugins[i].lv2_descriptor(_plugins[i].dsp_descriptor_id);
980
printf(" %2d \"%s\" %s\n", i, _plugins[i].plugin_human_id, d->URI);
985
static void print_usage (void) {
986
#ifdef X42_MULTIPLUGIN
987
printf ("x42-%s - JACK %s\n\n", APPNAME, X42_MULTIPLUGIN_NAME);
988
printf ("Usage: x42-%s [ Plugin-ID or URI ]\n\n", APPNAME);
989
printf ("This is a standalone JACK application of a collection of LV2 plugins.\n"
990
"Use ID -1, -l or --list for a dedicated list of included plugins.\n"
991
"By default the first listed plugin (ID 0) is used.\n\n");
992
printf ("List if available plugins: (ID \"Name\" URI)\n");
994
printf ("\nSee also: <%s>\n", X42_MULTIPLUGIN_URI);
997
#if defined X42_PLUGIN_STRUCT
998
inst = & X42_PLUGIN_STRUCT;
1002
const LV2_Descriptor* d = inst->lv2_descriptor(inst->dsp_descriptor_id);
1004
printf ("x42-%s - JACK %s\n\n", APPNAME, inst->plugin_human_id);
1005
printf ("Usage: x42-%s\n\n", APPNAME);
1006
printf ("This is a standalone JACK application of the LV2 plugin:\n"
1007
"\"%s\".\n", inst->plugin_human_id);
1009
printf ("\nSee also: <%s>\n", d->URI);
1011
printf ("Website: <http://x42-plugins.com/>\n");
1014
static void print_version (void) {
1015
printf ("x42-%s version %s\n\n", APPNAME, VERSION);
1017
"Copyright (C) GPL 2013-2015 Robin Gareus <robin@gareus.org>\n"
1018
"This is free software; see the source for copying conditions. There is NO\n"
1019
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
1022
int main (int argc, char **argv) {
1025
uint32_t c_aout = 0;
1026
uint32_t c_ctrl = 0;
1032
if (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
1036
if (argc > 1 && (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version"))) {
1041
// TODO autoconnect option.
1043
#ifdef X42_MULTIPLUGIN
1044
if (argc > 1 && (atoi(argv[1]) < 0 || !strcmp(argv[1], "-l") || !strcmp(argv[1], "--list"))) {
1050
if (argc > 1 && strlen(argv[1]) > 2 && atoi(argv[1]) == 0) {
1052
for (i = 0; i < sizeof(_plugins) / sizeof(RtkLv2Description); ++i) {
1053
const LV2_Descriptor* d = _plugins[i].lv2_descriptor(_plugins[i].dsp_descriptor_id);
1054
if (strstr(d->URI, argv[1]) || strstr(_plugins[i].plugin_human_id, argv[1])) {
1055
inst = &_plugins[i];
1060
if (argc > 1 && !inst && atoi(argv[1]) >= 0) {
1061
unsigned int plugid = atoi(argv[1]);
1062
if (plugid < (sizeof(_plugins) / sizeof(RtkLv2Description))) {
1063
inst = &_plugins[plugid];
1067
inst = &_plugins[0];
1069
#elif defined X42_PLUGIN_STRUCT
1070
inst = & X42_PLUGIN_STRUCT;
1079
#ifdef USE_WEAK_JACK
1080
if (have_libjack()) {
1081
fprintf(stderr, "JACK is not available. http://jackaudio.org/\n");
1083
MessageBox(NULL, TEXT(
1084
"JACK is not available.\n"
1085
"You must have the JACK Audio Connection Kit installed to use the tools. "
1086
"Please see http://jackaudio.org/ and http://jackaudio.org/faq/jack_on_windows.html"
1087
), TEXT("Error"), MB_ICONERROR | MB_OK);
1090
"JACK is not available.\n"
1091
"You must have the JACK Audio Connection Kit installed to use the tools. "
1092
"Please see http://jackaudio.org/ and http://jackosx.com/"
1100
pthread_win32_process_attach_np();
1102
#if (defined _WIN32 && defined RTK_STATIC_INIT)
1104
gobject_init_ctor();
1108
LV2_URID_Map uri_map = { NULL, &uri_to_id };
1109
const LV2_Feature map_feature = { LV2_URID__map, &uri_map};
1110
const LV2_Feature unmap_feature = { LV2_URID__unmap, NULL };
1112
LV2_Worker_Schedule schedule = { NULL, lv2_worker_schedule };
1113
LV2_Feature schedule_feature = { LV2_WORKER__schedule, &schedule };
1115
const LV2_Feature* features[] = {
1116
&map_feature, &unmap_feature, &schedule_feature, NULL
1119
const LV2_Feature external_lv_feature = { LV2_EXTERNAL_UI_URI, &extui_host};
1120
const LV2_Feature external_kx_feature = { LV2_EXTERNAL_UI_URI__KX__Host, &extui_host};
1121
LV2_Feature instance_feature = { "http://lv2plug.in/ns/ext/instance-access", NULL };
1123
const LV2_Feature* ui_features[] = {
1124
&map_feature, &unmap_feature,
1126
&external_lv_feature,
1127
&external_kx_feature,
1131
/* check sourced settings */
1132
assert ((inst->nports_midi_in + inst->nports_atom_in) <= 1);
1133
assert ((inst->nports_midi_out + inst->nports_atom_out) <= 1);
1134
assert (inst->plugin_human_id);
1135
assert (inst->nports_total > 0);
1137
extui_host.plugin_human_id = inst->plugin_human_id;
1139
// TODO check if allocs succeeded - OOM -> exit
1140
/* allocate data structure */
1141
portmap_a_in = (uint32_t*) malloc(inst->nports_audio_in * sizeof(uint32_t));
1142
portmap_a_out = (uint32_t*) malloc(inst->nports_audio_out * sizeof(uint32_t));
1143
portmap_rctl = (uint32_t*) malloc(inst->nports_ctrl * sizeof(uint32_t));
1144
portmap_ctrl = (int*) malloc(inst->nports_total * sizeof(int));
1146
plugin_ports_pre = (float*) calloc(inst->nports_ctrl, sizeof(float));
1147
plugin_ports_post = (float*) calloc(inst->nports_ctrl, sizeof(float));
1149
atom_in = (LV2_Atom_Sequence*) malloc(inst->min_atom_bufsiz + sizeof(uint8_t));
1150
atom_out = (LV2_Atom_Sequence*) malloc(inst->min_atom_bufsiz + sizeof(uint8_t));
1152
rb_ctrl_to_ui = jack_ringbuffer_create((UPDATE_FREQ_RATIO) * inst->nports_ctrl * 2 * sizeof(float));
1153
rb_ctrl_from_ui = jack_ringbuffer_create((UPDATE_FREQ_RATIO) * inst->nports_ctrl * 2 * sizeof(float));
1155
rb_atom_to_ui = jack_ringbuffer_create((UPDATE_FREQ_RATIO) * inst->min_atom_bufsiz);
1156
rb_atom_from_ui = jack_ringbuffer_create((UPDATE_FREQ_RATIO) * inst->min_atom_bufsiz);
1158
/* reolve descriptors */
1159
plugin_dsp = inst->lv2_descriptor(inst->dsp_descriptor_id);
1160
plugin_gui = inst->lv2ui_descriptor(inst->gui_descriptor_id);
1163
fprintf(stderr, "cannot resolve LV2 descriptor\n");
1167
/* jack-open -> samlerate */
1168
if (init_jack(extui_host.plugin_human_id)) {
1169
fprintf(stderr, "cannot connect to JACK.\n");
1171
MessageBox (NULL, TEXT(
1172
"Cannot connect to JACK.\n"
1173
"Please start the JACK Server first."
1174
), TEXT("Error"), MB_ICONERROR | MB_OK);
1177
"Cannot connect to JACK.\n"
1178
"Please start the JACK Server first."
1186
plugin_instance = plugin_dsp->instantiate(plugin_dsp, j_samplerate, NULL, features);
1187
if (!plugin_instance) {
1188
fprintf(stderr, "instantiation failed\n");
1194
for (uint32_t p=0; p < inst->nports_total; ++p) {
1195
portmap_ctrl[p] = -1;
1196
switch (inst->ports[p].porttype) {
1198
plugin_ports_pre[c_ctrl] = inst->ports[p].val_default;
1200
portmap_ctrl[p] = c_ctrl;
1201
portmap_rctl[c_ctrl] = p;
1202
plugin_dsp->connect_port(plugin_instance, p , &plugin_ports_pre[c_ctrl++]);
1205
portmap_a_in[c_ain++] = p;
1208
portmap_a_out[c_aout++] = p;
1212
portmap_atom_from_ui = p;
1213
plugin_dsp->connect_port(plugin_instance, p , atom_in);
1217
portmap_atom_to_ui = p;
1218
plugin_dsp->connect_port(plugin_instance, p , atom_out);
1221
fprintf(stderr, "yet unsupported port..\n");
1226
assert(c_ain == inst->nports_audio_in);
1227
assert(c_aout == inst->nports_audio_out);
1228
assert(c_ctrl == inst->nports_ctrl);
1230
if (inst->nports_atom_out > 0 || inst->nports_atom_in > 0 || inst->nports_midi_in > 0 || inst->nports_midi_out > 0) {
1231
uri_atom_Sequence = uri_to_id(NULL, LV2_ATOM__Sequence);
1232
uri_atom_EventTransfer = uri_to_id(NULL, LV2_ATOM__eventTransfer);
1233
uri_midi_MidiEvent = uri_to_id(NULL, LV2_MIDI__MidiEvent);
1234
uri_time_Position = uri_to_id(NULL, LV2_TIME__Position);
1235
uri_time_frame = uri_to_id(NULL, LV2_TIME__frame);
1236
uri_time_speed = uri_to_id(NULL, LV2_TIME__speed);
1237
uri_time_bar = uri_to_id(NULL, LV2_TIME__bar);
1238
uri_time_barBeat = uri_to_id(NULL, LV2_TIME__barBeat);
1239
uri_time_beatUnit = uri_to_id(NULL, LV2_TIME__beatUnit);
1240
uri_time_beatsPerBar = uri_to_id(NULL, LV2_TIME__beatsPerBar);
1241
uri_time_beatsPerMinute = uri_to_id(NULL, LV2_TIME__beatsPerMinute);
1242
lv2_atom_forge_init(&lv2_forge, &uri_map);
1245
if (jack_portsetup()) {
1251
/* init plugin GUI */
1252
extui_host.ui_closed = on_external_ui_closed;
1253
instance_feature.data = plugin_instance;
1254
gui_instance = plugin_gui->instantiate(plugin_gui,
1255
plugin_dsp->URI, NULL,
1256
&write_function, controller,
1257
(void **)&extui, ui_features);
1261
if (!gui_instance || !extui) {
1263
fprintf(stderr, "Error: GUI initialization failed.\n");
1267
fprintf(stderr, "Warning: GUI initialization failed.\n");
1272
if (mlockall (MCL_CURRENT | MCL_FUTURE)) {
1273
fprintf(stderr, "Warning: Can not lock memory.\n");
1278
for (uint32_t p = 0; p < inst->nports_ctrl; p++) {
1279
if (jack_ringbuffer_write_space(rb_ctrl_to_ui) >= sizeof(uint32_t) + sizeof(float)) {
1280
jack_ringbuffer_write(rb_ctrl_to_ui, (char *) &portmap_rctl[p], sizeof(uint32_t));
1281
jack_ringbuffer_write(rb_ctrl_to_ui, (char *) &plugin_ports_pre[p], sizeof(float));
1286
if (plugin_dsp->extension_data) {
1287
worker_iface = (LV2_Worker_Interface*) plugin_dsp->extension_data (LV2_WORKER__interface);
1293
if (plugin_dsp->activate) {
1294
plugin_dsp->activate(plugin_instance);
1297
if (jack_activate (j_client)) {
1298
fprintf (stderr, "cannot activate client.\n");
1303
jack_portconnect(JACK_AUTOCONNECT);
1306
signal (SIGHUP, catchsig);
1307
signal (SIGINT, catchsig);
1310
if (!gui_instance || !extui) {
1312
while (client_state != Exit) {
1317
LV2_EXTERNAL_UI_SHOW(extui);
1320
LV2_Atom_Sequence *data = (LV2_Atom_Sequence*) malloc(inst->min_atom_bufsiz * sizeof(uint8_t));
1321
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
1322
CFRunLoopTimerContext context = {0, data, NULL, NULL, NULL};
1323
CFRunLoopTimerRef timer = CFRunLoopTimerCreate(kCFAllocatorDefault, 0, 1.0/UI_UPDATE_FPS, 0, 0, &osx_loop, &context);
1324
CFRunLoopAddTimer(runLoop, timer, kCFRunLoopCommonModes);
1332
LV2_EXTERNAL_UI_HIDE(extui);
1338
pthread_win32_process_detach_np();
1340
#if (defined _WIN32 && defined RTK_STATIC_INIT)
1341
glib_cleanup_static();
1345
/* vi:set ts=2 sts=2 sw=2: */