~ubuntu-branches/debian/sid/x42-plugins/sid

« back to all changes in this revision

Viewing changes to robtk/jackwrap.c

  • Committer: Package Import Robot
  • Author(s): Jaromír Mikeš
  • Date: 2014-01-18 17:04:40 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20140118170440-g38hz8mttoobqdla
Tags: 20140115-1
* Imported Upstream version 20140115.
* Added libjack-dev as build dep.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* x42 jack wrapper
 
2
 *
 
3
 * Copyright (C) 2012, 2013 Robin Gareus
 
4
 *
 
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.
 
9
 *
 
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.
 
14
 *
 
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/>.
 
17
 */
 
18
 
 
19
 
 
20
#ifndef UPDATE_FREQ_RATIO
 
21
#define UPDATE_FREQ_RATIO 10 // MAX # of audio-cycles per GUI-refresh
 
22
#endif
 
23
 
 
24
#ifndef UI_UPDATE_FPS
 
25
#define UI_UPDATE_FPS 15
 
26
#endif
 
27
 
 
28
///////////////////////////////////////////////////////////////////////////////
 
29
 
 
30
#ifndef _GNU_SOURCE
 
31
#define _GNU_SOURCE
 
32
#endif
 
33
 
 
34
#ifdef WIN32
 
35
#include <windows.h>
 
36
#include <pthread.h>
 
37
#define pthread_t //< override jack.h def
 
38
#endif
 
39
 
 
40
#include <stdio.h>
 
41
#include <errno.h>
 
42
#include <unistd.h>
 
43
#include <stdlib.h>
 
44
#include <string.h>
 
45
#include <math.h>
 
46
#include <time.h>
 
47
#include <getopt.h>
 
48
#include <jack/jack.h>
 
49
#include <jack/ringbuffer.h>
 
50
#include <jack/midiport.h>
 
51
#include <sys/mman.h>
 
52
#include <assert.h>
 
53
 
 
54
#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
 
55
#include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
 
56
#include "lv2/lv2plug.in/ns/ext/uri-map/uri-map.h"
 
57
#include "lv2/lv2plug.in/ns/ext/urid/urid.h"
 
58
#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
 
59
#include "lv2/lv2plug.in/ns/ext/atom/forge.h"
 
60
#include "lv2/lv2plug.in/ns/ext/midi/midi.h"
 
61
#include "lv2/lv2plug.in/ns/ext/time/time.h"
 
62
 
 
63
#include "./gl/xternalui.h"
 
64
 
 
65
#ifndef WIN32
 
66
#include <signal.h>
 
67
#include <pthread.h>
 
68
#endif
 
69
 
 
70
#define LV2_EXTERNAL_UI_RUN(ptr) (ptr)->run(ptr)
 
71
#define LV2_EXTERNAL_UI_SHOW(ptr) (ptr)->show(ptr)
 
72
#define LV2_EXTERNAL_UI_HIDE(ptr) (ptr)->hide(ptr)
 
73
 
 
74
#define nan NAN
 
75
 
 
76
const LV2_Descriptor* plugin_dsp;
 
77
const LV2UI_Descriptor *plugin_gui;
 
78
 
 
79
LV2_Handle plugin_instance = NULL;
 
80
LV2UI_Handle gui_instance = NULL;
 
81
 
 
82
float  *plugin_ports_pre  = NULL;
 
83
float  *plugin_ports_post = NULL;
 
84
 
 
85
LV2_Atom_Sequence *atom_in = NULL;
 
86
LV2_Atom_Sequence *atom_out = NULL;
 
87
 
 
88
static jack_port_t **input_port = NULL;
 
89
static jack_port_t **output_port = NULL;
 
90
 
 
91
static jack_port_t *midi_in = NULL;
 
92
static jack_port_t *midi_out = NULL;
 
93
 
 
94
static jack_client_t *j_client = NULL;
 
95
static uint32_t j_samplerate = 48000;
 
96
 
 
97
struct transport_position {
 
98
        jack_nframes_t position;
 
99
        float          bpm;
 
100
        bool           rolling;
 
101
} j_transport = {0, 0, false};
 
102
 
 
103
static jack_ringbuffer_t *rb_ctrl_to_ui = NULL;
 
104
static jack_ringbuffer_t *rb_ctrl_from_ui = NULL;
 
105
static jack_ringbuffer_t *rb_atom_to_ui = NULL;
 
106
static jack_ringbuffer_t *rb_atom_from_ui = NULL;
 
107
 
 
108
static pthread_mutex_t gui_thread_lock = PTHREAD_MUTEX_INITIALIZER;
 
109
static pthread_cond_t  data_ready = PTHREAD_COND_INITIALIZER;
 
110
 
 
111
extern const LV2_Descriptor* lv2_descriptor(uint32_t index);
 
112
extern const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index);
 
113
 
 
114
uint32_t uri_midi_MidiEvent = 0;
 
115
uint32_t uri_atom_Sequence = 0;
 
116
uint32_t uri_atom_EventTransfer = 0;
 
117
 
 
118
uint32_t uri_time_Position = 0;
 
119
uint32_t uri_time_frame    = 0;
 
120
uint32_t uri_time_speed    = 0;
 
121
uint32_t uri_time_bar     = 0;
 
122
uint32_t uri_time_barBeat = 0;
 
123
uint32_t uri_time_beatUnit = 0;
 
124
uint32_t uri_time_beatsPerBar = 0;
 
125
uint32_t uri_time_beatsPerMinute = 0;
 
126
 
 
127
char **urimap = NULL;
 
128
uint32_t urimap_len = 0;
 
129
 
 
130
enum PortType {
 
131
        CONTROL_IN = 0,
 
132
        CONTROL_OUT,
 
133
        AUDIO_IN,
 
134
        AUDIO_OUT,
 
135
        MIDI_IN,
 
136
        MIDI_OUT,
 
137
        ATOM_IN,
 
138
        ATOM_OUT
 
139
};
 
140
 
 
141
struct LV2Port {
 
142
        const char *name;
 
143
        enum PortType porttype;
 
144
        float val_default;
 
145
};
 
146
 
 
147
/* a simple state machine for this client */
 
148
static volatile enum {
 
149
  Init,
 
150
  Run,
 
151
  Exit
 
152
} client_state = Init;
 
153
 
 
154
struct lv2_external_ui_host extui_host;
 
155
struct lv2_external_ui *extui = NULL;
 
156
 
 
157
LV2UI_Controller controller = NULL;
 
158
 
 
159
LV2_Atom_Forge lv2_forge;
 
160
uint32_t *portmap_a_in;
 
161
uint32_t *portmap_a_out;
 
162
uint32_t *portmap_rctl;
 
163
int      *portmap_ctrl;
 
164
uint32_t  portmap_atom_to_ui = -1;
 
165
uint32_t  portmap_atom_from_ui = -1;
 
166
 
 
167
static uint32_t uri_to_id(LV2_URI_Map_Callback_Data callback_data, const char* uri);
 
168
 
 
169
///////////////////////////
 
170
// GET INFO FROM LV2 TTL //
 
171
//     see lv2ttl2c      //
 
172
///////////////////////////
 
173
#include JACK_DESCRIPT ////
 
174
///////////////////////////
 
175
 
 
176
/******************************************************************************
 
177
 * JACK
 
178
 */
 
179
 
 
180
int process (jack_nframes_t nframes, void *arg) {
 
181
        while (jack_ringbuffer_read_space(rb_ctrl_from_ui) >= sizeof(uint32_t) + sizeof(float)) {
 
182
                uint32_t idx;
 
183
                jack_ringbuffer_read(rb_ctrl_from_ui, (char*) &idx, sizeof(uint32_t));
 
184
                jack_ringbuffer_read(rb_ctrl_from_ui, (char*) &(plugin_ports_pre[idx]), sizeof(float));
 
185
        }
 
186
 
 
187
        /* Get Jack transport position */
 
188
        jack_position_t pos;
 
189
        const bool rolling = (jack_transport_query(j_client, &pos) == JackTransportRolling);
 
190
        const bool transport_changed = (rolling != j_transport.rolling
 
191
                        || pos.frame != j_transport.position
 
192
                        || ((pos.valid & JackPositionBBT) && (pos.beats_per_minute != j_transport.bpm)));
 
193
 
 
194
        /* atom buffers */
 
195
        if (nports_atom_in > 0 || nports_midi_in > 0) {
 
196
                /* start Atom sequence */
 
197
                atom_in->atom.type = uri_atom_Sequence;
 
198
                atom_in->atom.size = 8;
 
199
                LV2_Atom_Sequence_Body *body = &atom_in->body;
 
200
                body->unit = 0; // URID of unit of event time stamp LV2_ATOM__timeUnit ??
 
201
                body->pad  = 0; // unused
 
202
                uint8_t * seq = (uint8_t*) (body + 1);
 
203
 
 
204
                if (transport_changed && send_time_info) {
 
205
                        uint8_t   pos_buf[256];
 
206
                        LV2_Atom* lv2_pos = (LV2_Atom*)pos_buf;
 
207
 
 
208
                        lv2_atom_forge_set_buffer(&lv2_forge, pos_buf, sizeof(pos_buf));
 
209
                        LV2_Atom_Forge* forge = &lv2_forge;
 
210
                        LV2_Atom_Forge_Frame frame;
 
211
                        lv2_atom_forge_blank(&lv2_forge, &frame, 1, uri_time_Position);
 
212
                        lv2_atom_forge_property_head(forge, uri_time_frame, 0);
 
213
                        lv2_atom_forge_long(forge, pos.frame);
 
214
                        lv2_atom_forge_property_head(forge, uri_time_speed, 0);
 
215
                        lv2_atom_forge_float(forge, rolling ? 1.0 : 0.0);
 
216
                        if (pos.valid & JackPositionBBT) {
 
217
                                lv2_atom_forge_property_head(forge, uri_time_barBeat, 0);
 
218
                                lv2_atom_forge_float(
 
219
                                                forge, pos.beat - 1 + (pos.tick / pos.ticks_per_beat));
 
220
                                lv2_atom_forge_property_head(forge, uri_time_bar, 0);
 
221
                                lv2_atom_forge_long(forge, pos.bar - 1);
 
222
                                lv2_atom_forge_property_head(forge, uri_time_beatUnit, 0);
 
223
                                lv2_atom_forge_int(forge, pos.beat_type);
 
224
                                lv2_atom_forge_property_head(forge, uri_time_beatsPerBar, 0);
 
225
                                lv2_atom_forge_float(forge, pos.beats_per_bar);
 
226
                                lv2_atom_forge_property_head(forge, uri_time_beatsPerMinute, 0);
 
227
                                lv2_atom_forge_float(forge, pos.beats_per_minute);
 
228
                        }
 
229
 
 
230
                        uint32_t size = lv2_pos->size;
 
231
                        uint32_t padded_size = ((sizeof(LV2_Atom_Event) + size) +  7) & (~7);
 
232
 
 
233
                        if (min_atom_bufsiz > padded_size) {
 
234
                                printf("send time..\n");
 
235
                                LV2_Atom_Event *aev = (LV2_Atom_Event *)seq;
 
236
                                aev->time.frames = 0;
 
237
                                aev->body.size   = size;
 
238
                                aev->body.type   = lv2_pos->type;
 
239
                                memcpy(LV2_ATOM_BODY(&aev->body), LV2_ATOM_BODY(lv2_pos), size);
 
240
                                atom_in->atom.size += padded_size;
 
241
                                seq +=  padded_size;
 
242
                        }
 
243
                }
 
244
                // TODO only if UI..?
 
245
                while (jack_ringbuffer_read_space(rb_atom_from_ui) > sizeof(LV2_Atom)) {
 
246
                        LV2_Atom a;
 
247
                        jack_ringbuffer_read(rb_atom_from_ui, (char *) &a, sizeof(LV2_Atom));
 
248
                        uint32_t padded_size = atom_in->atom.size + a.size + sizeof(int64_t);
 
249
                        if (min_atom_bufsiz > padded_size) {
 
250
                                memset(seq, 0, sizeof(int64_t)); // LV2_Atom_Event->time
 
251
                                seq += sizeof(int64_t);
 
252
                                jack_ringbuffer_read(rb_atom_from_ui, (char *) seq, a.size);
 
253
                                seq += a.size;
 
254
                                atom_in->atom.size += a.size + sizeof(int64_t);
 
255
                        }
 
256
                }
 
257
                if (nports_midi_in > 0) {
 
258
                        /* inject midi events */
 
259
                        void* buf = jack_port_get_buffer(midi_in, nframes);
 
260
                        for (uint32_t i = 0; i < jack_midi_get_event_count(buf); ++i) {
 
261
                                jack_midi_event_t ev;
 
262
                                jack_midi_event_get(&ev, buf, i);
 
263
 
 
264
                                uint32_t size = ev.size;
 
265
                                uint32_t padded_size = ((sizeof(LV2_Atom_Event) + size) +  7) & (~7);
 
266
 
 
267
                                if (min_atom_bufsiz > padded_size) {
 
268
                                        LV2_Atom_Event *aev = (LV2_Atom_Event *)seq;
 
269
                                        aev->time.frames = ev.time;
 
270
                                        aev->body.size  = size;
 
271
                                        aev->body.type  = uri_midi_MidiEvent;
 
272
                                        memcpy(LV2_ATOM_BODY(&aev->body), ev.buffer, size);
 
273
                                        atom_in->atom.size += padded_size;
 
274
                                        seq += padded_size;
 
275
                                }
 
276
                        }
 
277
                }
 
278
        }
 
279
 
 
280
        if (nports_atom_out > 0 || nports_midi_out > 0) {
 
281
                atom_out->atom.type = 0;
 
282
                atom_out->atom.size = min_atom_bufsiz;
 
283
        }
 
284
 
 
285
        /* [re] connect jack audio buffers */
 
286
  for (uint32_t i=0; i < nports_audio_in; i++) {
 
287
                plugin_dsp->connect_port(plugin_instance, portmap_a_in[i], jack_port_get_buffer (input_port[i], nframes));
 
288
  }
 
289
  for (uint32_t i=0 ; i < nports_audio_out; i++) {
 
290
                plugin_dsp->connect_port(plugin_instance, portmap_a_out[i], jack_port_get_buffer (output_port[i], nframes));
 
291
  }
 
292
 
 
293
        /* make a backup copy, to see what was changed */
 
294
        memcpy(plugin_ports_post, plugin_ports_pre, nports_ctrl * sizeof(float));
 
295
 
 
296
        /* expected transport state in next cycle */
 
297
        j_transport.position = rolling ? pos.frame + nframes : pos.frame;
 
298
        j_transport.bpm      = pos.beats_per_minute;
 
299
        j_transport.rolling  = rolling;
 
300
 
 
301
        /* run the plugin */
 
302
        plugin_dsp->run(plugin_instance, nframes);
 
303
 
 
304
        /* create port-events for change values */
 
305
        // TODO only if UI..?
 
306
        for (uint32_t p = 0; p < nports_ctrl; p++) {
 
307
                if (ports[portmap_rctl[p]].porttype != CONTROL_OUT) continue;
 
308
 
 
309
                if (plugin_ports_pre[p] != plugin_ports_post[p]) {
 
310
                        if (jack_ringbuffer_write_space(rb_ctrl_to_ui) >= sizeof(uint32_t) + sizeof(float)) {
 
311
                                jack_ringbuffer_write(rb_ctrl_to_ui, (char *) &portmap_rctl[p], sizeof(uint32_t));
 
312
                                jack_ringbuffer_write(rb_ctrl_to_ui, (char *) &plugin_ports_pre[p], sizeof(float));
 
313
                        }
 
314
                }
 
315
        }
 
316
 
 
317
        if (nports_midi_out > 0) {
 
318
                void* buf = jack_port_get_buffer(midi_out, nframes);
 
319
                jack_midi_clear_buffer(buf);
 
320
        }
 
321
 
 
322
        /* Atom sequence port-events */
 
323
        if (nports_atom_out + nports_midi_out > 0 && atom_out->atom.size > sizeof(LV2_Atom)) {
 
324
                // TODO only if UI..?
 
325
                if (jack_ringbuffer_write_space(rb_atom_to_ui) >= atom_out->atom.size + 2 * sizeof(LV2_Atom)) {
 
326
                        LV2_Atom a = {atom_out->atom.size + (uint32_t) sizeof(LV2_Atom), 0};
 
327
                        jack_ringbuffer_write(rb_atom_to_ui, (char *) &a, sizeof(LV2_Atom));
 
328
                        jack_ringbuffer_write(rb_atom_to_ui, (char *) atom_out, a.size);
 
329
                }
 
330
 
 
331
                if (nports_midi_out) {
 
332
                        void* buf = jack_port_get_buffer(midi_out, nframes);
 
333
                        LV2_Atom_Event const* ev = (LV2_Atom_Event const*)((&(atom_out)->body) + 1); // lv2_atom_sequence_begin
 
334
                        while((const uint8_t*)ev < ((const uint8_t*) &(atom_out)->body + (atom_out)->atom.size)) {
 
335
                                if (ev->body.type == uri_midi_MidiEvent) {
 
336
                                        jack_midi_event_write(buf, ev->time.frames, (const uint8_t*)(ev+1), ev->body.size);
 
337
                                }
 
338
                                ev = (LV2_Atom_Event const*) /* lv2_atom_sequence_next() */
 
339
                                        ((const uint8_t*)ev + sizeof(LV2_Atom_Event) + ((ev->body.size + 7) & ~7));
 
340
                        }
 
341
                }
 
342
        }
 
343
 
 
344
        /* wake up UI */
 
345
        if (jack_ringbuffer_read_space(rb_ctrl_to_ui) > sizeof(uint32_t) + sizeof(float)
 
346
                        || jack_ringbuffer_read_space(rb_atom_to_ui) > sizeof(LV2_Atom)
 
347
                        ) {
 
348
                if (pthread_mutex_trylock (&gui_thread_lock) == 0) {
 
349
                        pthread_cond_signal (&data_ready);
 
350
                        pthread_mutex_unlock (&gui_thread_lock);
 
351
                }
 
352
        }
 
353
  return 0;
 
354
}
 
355
 
 
356
 
 
357
void jack_shutdown (void *arg) {
 
358
  fprintf(stderr,"recv. shutdown request from jackd.\n");
 
359
  client_state=Exit;
 
360
  pthread_cond_signal (&data_ready);
 
361
}
 
362
 
 
363
static int init_jack(const char *client_name) {
 
364
  jack_status_t status;
 
365
  j_client = jack_client_open (client_name, JackNullOption, &status);
 
366
  if (j_client == NULL) {
 
367
    fprintf (stderr, "jack_client_open() failed, status = 0x%2.0x\n", status);
 
368
    if (status & JackServerFailed) {
 
369
      fprintf (stderr, "Unable to connect to JACK server\n");
 
370
    }
 
371
    return (-1);
 
372
  }
 
373
  if (status & JackServerStarted) {
 
374
    fprintf (stderr, "JACK server started\n");
 
375
  }
 
376
  if (status & JackNameNotUnique) {
 
377
    client_name = jack_get_client_name(j_client);
 
378
    fprintf (stderr, "jack-client name: `%s'\n", client_name);
 
379
  }
 
380
 
 
381
  jack_set_process_callback (j_client, process, 0);
 
382
 
 
383
#ifndef WIN32
 
384
  jack_on_shutdown (j_client, jack_shutdown, NULL);
 
385
#endif
 
386
  j_samplerate=jack_get_sample_rate (j_client);
 
387
  return (0);
 
388
}
 
389
 
 
390
static int jack_portsetup(void) {
 
391
  /* Allocate data structures that depend on the number of ports. */
 
392
  input_port = (jack_port_t **) malloc (sizeof (jack_port_t *) * nports_audio_in);
 
393
 
 
394
  for (uint32_t i = 0; i < nports_audio_in; i++) {
 
395
    if ((input_port[i] = jack_port_register (j_client,
 
396
                                                ports[portmap_a_in[i]].name,
 
397
                                                JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0)) == 0) {
 
398
      fprintf (stderr, "cannot register input port \"%s\"!\n", ports[portmap_a_in[i]].name);
 
399
      return (-1);
 
400
    }
 
401
  }
 
402
 
 
403
  output_port = (jack_port_t **) malloc (sizeof (jack_port_t *) * nports_audio_out);
 
404
 
 
405
  for (uint32_t i = 0; i < nports_audio_out; i++) {
 
406
    if ((output_port[i] = jack_port_register (j_client,
 
407
                                                ports[portmap_a_out[i]].name,
 
408
                                                JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) == 0) {
 
409
      fprintf (stderr, "cannot register output port \"%s\"!\n", ports[portmap_a_out[i]].name);
 
410
      return (-1);
 
411
    }
 
412
  }
 
413
 
 
414
        if (nports_midi_in){
 
415
                if ((midi_in = jack_port_register (j_client,
 
416
                                                ports[portmap_atom_from_ui].name,
 
417
                                                JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0)) == 0) {
 
418
                        fprintf (stderr, "cannot register midi input port \"%s\"!\n", ports[portmap_atom_from_ui].name);
 
419
                        return (-1);
 
420
                }
 
421
        }
 
422
 
 
423
        if (nports_midi_out){
 
424
                if ((midi_out = jack_port_register (j_client,
 
425
                                                ports[portmap_atom_to_ui].name,
 
426
                                                JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0)) == 0) {
 
427
                        fprintf (stderr, "cannot register midi ouput port \"%s\"!\n", ports[portmap_atom_to_ui].name);
 
428
                        return (-1);
 
429
                }
 
430
        }
 
431
        return (0);
 
432
}
 
433
 
 
434
/******************************************************************************
 
435
 * LV2
 
436
 */
 
437
 
 
438
static uint32_t uri_to_id(LV2_URI_Map_Callback_Data callback_data, const char* uri) {
 
439
        for (uint32_t i=0; i < urimap_len; ++i) {
 
440
                if (!strcmp(urimap[i], uri)) {
 
441
                        //printf("Found mapped URI '%s' -> %d\n", uri, i);
 
442
                        return i;
 
443
                }
 
444
        }
 
445
        //printf("map URI '%s' -> %d\n", uri, urimap_len);
 
446
        urimap = (char**) realloc(urimap, (urimap_len + 1) * sizeof(char*));
 
447
        urimap[urimap_len] = strdup(uri);
 
448
        return urimap_len++;
 
449
}
 
450
 
 
451
static void free_uri_map() {
 
452
        for (uint32_t i=0; i < urimap_len; ++i) {
 
453
                free(urimap[i]);
 
454
        }
 
455
        free(urimap);
 
456
}
 
457
 
 
458
void write_function(
 
459
                LV2UI_Controller controller,
 
460
                uint32_t         port_index,
 
461
                uint32_t         buffer_size,
 
462
                uint32_t         port_protocol,
 
463
                const void*      buffer) {
 
464
 
 
465
        if (buffer_size == 0) return;
 
466
 
 
467
        if (port_protocol != 0) {
 
468
                if (jack_ringbuffer_write_space(rb_atom_from_ui) >= buffer_size + sizeof(LV2_Atom)) {
 
469
                        LV2_Atom a = {buffer_size, 0};
 
470
                        jack_ringbuffer_write(rb_atom_from_ui, (char *) &a, sizeof(LV2_Atom));
 
471
                        jack_ringbuffer_write(rb_atom_from_ui, (char *) buffer, buffer_size);
 
472
                }
 
473
                return;
 
474
        }
 
475
        if (buffer_size != sizeof(float)) {
 
476
                fprintf(stderr, "LV2Host: write_function() unsupported buffer\n");
 
477
                return;
 
478
        }
 
479
        if (port_index >=0 && port_index < nports_total && portmap_ctrl[port_index] < 0) {
 
480
                fprintf(stderr, "LV2Host: write_function() unmapped port\n");
 
481
                return;
 
482
        }
 
483
        if (jack_ringbuffer_write_space(rb_ctrl_from_ui) >= sizeof(uint32_t) + sizeof(float)) {
 
484
                jack_ringbuffer_write(rb_ctrl_from_ui, (char *) &portmap_ctrl[port_index], sizeof(uint32_t));
 
485
                jack_ringbuffer_write(rb_ctrl_from_ui, (char *) buffer, sizeof(float));
 
486
        }
 
487
}
 
488
 
 
489
 
 
490
/******************************************************************************
 
491
 * MAIN
 
492
 */
 
493
 
 
494
static void cleanup(int sig) {
 
495
  if (j_client) {
 
496
    jack_client_close (j_client);
 
497
    j_client=NULL;
 
498
  }
 
499
 
 
500
        if (plugin_dsp && plugin_instance && plugin_dsp->deactivate) {
 
501
                plugin_dsp->deactivate(plugin_instance);
 
502
        }
 
503
        if (plugin_gui && gui_instance && plugin_gui->cleanup) {
 
504
                plugin_gui->cleanup(gui_instance);
 
505
        }
 
506
        if (plugin_dsp && plugin_instance && plugin_dsp->cleanup) {
 
507
                plugin_dsp->cleanup(plugin_instance);
 
508
        }
 
509
 
 
510
        jack_ringbuffer_free(rb_ctrl_to_ui);
 
511
        jack_ringbuffer_free(rb_ctrl_from_ui);
 
512
 
 
513
        jack_ringbuffer_free(rb_atom_to_ui);
 
514
        jack_ringbuffer_free(rb_atom_from_ui);
 
515
 
 
516
  free(input_port);
 
517
  free(output_port);
 
518
 
 
519
        free(plugin_ports_pre);
 
520
        free(plugin_ports_post);
 
521
        free(portmap_a_in);
 
522
        free(portmap_a_out);
 
523
        free(portmap_ctrl);
 
524
        free(portmap_rctl);
 
525
        free_uri_map();
 
526
  fprintf(stderr, "bye.\n");
 
527
}
 
528
 
 
529
static void main_loop(void) {
 
530
        struct timespec timeout;
 
531
        LV2_Atom_Sequence *data = (LV2_Atom_Sequence*) malloc(min_atom_bufsiz * sizeof(uint8_t));
 
532
 
 
533
  pthread_mutex_lock (&gui_thread_lock);
 
534
  while (client_state != Exit) {
 
535
 
 
536
                while (jack_ringbuffer_read_space(rb_ctrl_to_ui) >= sizeof(uint32_t) + sizeof(float)) {
 
537
                        uint32_t idx;
 
538
                        float val;
 
539
                        jack_ringbuffer_read(rb_ctrl_to_ui, (char*) &idx, sizeof(uint32_t));
 
540
                        jack_ringbuffer_read(rb_ctrl_to_ui, (char*) &val, sizeof(float));
 
541
                        plugin_gui->port_event(gui_instance, idx, sizeof(float), 0, &val);
 
542
                }
 
543
 
 
544
                while (jack_ringbuffer_read_space(rb_atom_to_ui) > sizeof(LV2_Atom)) {
 
545
                        LV2_Atom a;
 
546
                        jack_ringbuffer_read(rb_atom_to_ui, (char *) &a, sizeof(LV2_Atom));
 
547
                        assert(a.size < min_atom_bufsiz);
 
548
                        jack_ringbuffer_read(rb_atom_to_ui, (char *) data, a.size);
 
549
                        LV2_Atom_Event const* ev = (LV2_Atom_Event const*)((&(data)->body) + 1); // lv2_atom_sequence_begin
 
550
                        while((const uint8_t*)ev < ((const uint8_t*) &(data)->body + (data)->atom.size)) {
 
551
                                plugin_gui->port_event(gui_instance, portmap_atom_to_ui,
 
552
                                                ev->body.size, uri_atom_EventTransfer, &ev->body);
 
553
                                ev = (LV2_Atom_Event const*) /* lv2_atom_sequence_next() */
 
554
                                        ((const uint8_t*)ev + sizeof(LV2_Atom_Event) + ((ev->body.size + 7) & ~7));
 
555
                        }
 
556
                }
 
557
 
 
558
                LV2_EXTERNAL_UI_RUN(extui);
 
559
 
 
560
    if (client_state == Exit) break;
 
561
 
 
562
                clock_gettime(CLOCK_REALTIME, &timeout);
 
563
                timeout.tv_nsec += 1000000000 / (UI_UPDATE_FPS);
 
564
                if (timeout.tv_nsec >= 1000000000) {timeout.tv_nsec -= 1000000000; timeout.tv_sec+=1;}
 
565
    pthread_cond_timedwait (&data_ready, &gui_thread_lock, &timeout);
 
566
 
 
567
  } /* while running */
 
568
        free(data);
 
569
  pthread_mutex_unlock (&gui_thread_lock);
 
570
}
 
571
 
 
572
static void catchsig (int sig) {
 
573
  fprintf(stderr,"caught signal - shutting down.\n");
 
574
  client_state=Exit;
 
575
  pthread_cond_signal (&data_ready);
 
576
}
 
577
 
 
578
static void on_external_ui_closed(void* controller) {
 
579
        catchsig(0);
 
580
}
 
581
 
 
582
int main (int argc, char **argv) {
 
583
        uint32_t c_ain  = 0;
 
584
        uint32_t c_aout = 0;
 
585
        uint32_t c_ctrl = 0;
 
586
 
 
587
        LV2_URID_Map uri_map            = { NULL, &uri_to_id };
 
588
        const LV2_Feature map_feature   = { LV2_URID__map, &uri_map};
 
589
        const LV2_Feature unmap_feature = { LV2_URID__unmap, NULL };
 
590
 
 
591
        const LV2_Feature* features[] = {
 
592
                &map_feature, &unmap_feature, NULL
 
593
        };
 
594
 
 
595
        const LV2_Feature external_lv_feature = { LV2_EXTERNAL_UI_URI, &extui_host};
 
596
        const LV2_Feature external_kx_feature = { LV2_EXTERNAL_UI_URI__KX__Host, &extui_host};
 
597
        LV2_Feature instance_feature          = { "http://lv2plug.in/ns/ext/instance-access", NULL };
 
598
 
 
599
        const LV2_Feature* ui_features[] = {
 
600
                &map_feature, &unmap_feature,
 
601
                &instance_feature,
 
602
                &external_lv_feature,
 
603
                &external_kx_feature,
 
604
                NULL
 
605
        };
 
606
 
 
607
        /* check sourced settings */
 
608
        assert ((nports_midi_in + nports_atom_in) <= 1);
 
609
        assert ((nports_midi_out + nports_atom_out) <= 1);
 
610
        assert (plugin_human_id);
 
611
        assert (nports_total > 0);
 
612
 
 
613
        extui_host.plugin_human_id = plugin_human_id;
 
614
 
 
615
        // TODO check if allocs succeeded - OOM -> exit
 
616
        /* allocate data structure */
 
617
        portmap_a_in  = (uint32_t*) malloc(nports_audio_in * sizeof(uint32_t));
 
618
        portmap_a_out = (uint32_t*) malloc(nports_audio_out * sizeof(uint32_t));
 
619
        portmap_rctl  = (uint32_t*) malloc(nports_ctrl  * sizeof(uint32_t));
 
620
        portmap_ctrl  = (int*)      malloc(nports_total * sizeof(int));
 
621
 
 
622
        plugin_ports_pre  = (float*) calloc(nports_ctrl, sizeof(float));
 
623
        plugin_ports_post = (float*) calloc(nports_ctrl, sizeof(float));
 
624
 
 
625
        atom_in = (LV2_Atom_Sequence*) malloc(min_atom_bufsiz + sizeof(uint8_t));
 
626
        atom_out = (LV2_Atom_Sequence*) malloc(min_atom_bufsiz + sizeof(uint8_t));
 
627
 
 
628
        rb_ctrl_to_ui = jack_ringbuffer_create((UPDATE_FREQ_RATIO) * nports_ctrl * 2 * sizeof(float));
 
629
        rb_ctrl_from_ui = jack_ringbuffer_create((UPDATE_FREQ_RATIO) * nports_ctrl * 2 * sizeof(float));
 
630
 
 
631
        rb_atom_to_ui = jack_ringbuffer_create((UPDATE_FREQ_RATIO) * min_atom_bufsiz);
 
632
        rb_atom_from_ui = jack_ringbuffer_create((UPDATE_FREQ_RATIO) * min_atom_bufsiz);
 
633
 
 
634
 
 
635
        /* reolve descriptors */
 
636
        plugin_dsp = lv2_descriptor(dsp_descriptor_id);
 
637
        plugin_gui = lv2ui_descriptor(gui_descriptor_id);
 
638
 
 
639
        if (!plugin_dsp) {
 
640
                fprintf(stderr, "cannot resolve LV2 descriptor\n");
 
641
                goto out;
 
642
        }
 
643
        /* jack-open -> samlerate */
 
644
  if (init_jack(extui_host.plugin_human_id)) goto out;
 
645
 
 
646
        /* init plugin */
 
647
        plugin_instance = plugin_dsp->instantiate(plugin_dsp, j_samplerate, NULL, features);
 
648
        if (!plugin_instance) {
 
649
                fprintf(stderr, "instantiation failed\n");
 
650
                goto out;
 
651
        }
 
652
 
 
653
        /* connect ports */
 
654
        for (uint32_t p=0; p < nports_total; ++p) {
 
655
                portmap_ctrl[p] = -1;
 
656
                switch (ports[p].porttype) {
 
657
                        case CONTROL_IN:
 
658
                                plugin_ports_pre[c_ctrl] = ports[p].val_default;
 
659
                        case CONTROL_OUT:
 
660
                                portmap_ctrl[p] = c_ctrl;
 
661
                                portmap_rctl[c_ctrl] = p;
 
662
                                plugin_dsp->connect_port(plugin_instance, p , &plugin_ports_pre[c_ctrl++]);
 
663
                                break;
 
664
                        case AUDIO_IN:
 
665
                                portmap_a_in[c_ain++] = p;
 
666
                                break;
 
667
                        case AUDIO_OUT:
 
668
                                portmap_a_out[c_aout++] = p;
 
669
                                break;
 
670
                        case MIDI_IN:
 
671
                        case ATOM_IN:
 
672
                                portmap_atom_from_ui = p;
 
673
                                plugin_dsp->connect_port(plugin_instance, p , atom_in);
 
674
                                break;
 
675
                        case MIDI_OUT:
 
676
                        case ATOM_OUT:
 
677
                                portmap_atom_to_ui = p;
 
678
                                plugin_dsp->connect_port(plugin_instance, p , atom_out);
 
679
                                break;
 
680
                        default:
 
681
                                fprintf(stderr, "yet unsupported port..\n");
 
682
                                break;
 
683
                }
 
684
        }
 
685
 
 
686
        assert(c_ain == nports_audio_in);
 
687
        assert(c_aout == nports_audio_out);
 
688
        assert(c_ctrl == nports_ctrl);
 
689
 
 
690
        if (nports_atom_out > 0 || nports_atom_in > 0 || nports_midi_in > 0 || nports_midi_out > 0) {
 
691
                uri_atom_Sequence       = uri_to_id(NULL, LV2_ATOM__Sequence);
 
692
                uri_atom_EventTransfer  = uri_to_id(NULL, LV2_ATOM__eventTransfer);
 
693
                uri_midi_MidiEvent      = uri_to_id(NULL, LV2_MIDI__MidiEvent);
 
694
                uri_time_Position       = uri_to_id(NULL, LV2_TIME__Position);
 
695
                uri_time_frame          = uri_to_id(NULL, LV2_TIME__frame);
 
696
                uri_time_speed          = uri_to_id(NULL, LV2_TIME__speed);
 
697
                uri_time_bar            = uri_to_id(NULL, LV2_TIME__bar);
 
698
                uri_time_barBeat        = uri_to_id(NULL, LV2_TIME__barBeat);
 
699
                uri_time_beatUnit       = uri_to_id(NULL, LV2_TIME__beatUnit);
 
700
                uri_time_beatsPerBar    = uri_to_id(NULL, LV2_TIME__beatsPerBar);
 
701
                uri_time_beatsPerMinute = uri_to_id(NULL, LV2_TIME__beatsPerMinute);
 
702
                lv2_atom_forge_init(&lv2_forge, &uri_map);
 
703
        }
 
704
 
 
705
  if (jack_portsetup()) goto out;
 
706
 
 
707
        if (plugin_gui) {
 
708
        /* init plugin GUI */
 
709
        extui_host.ui_closed = on_external_ui_closed;
 
710
        instance_feature.data = plugin_instance;
 
711
        gui_instance = plugin_gui->instantiate(plugin_gui,
 
712
                        plugin_dsp->URI, NULL,
 
713
                        &write_function, controller,
 
714
                        (void **)&extui, ui_features);
 
715
 
 
716
        }
 
717
 
 
718
#ifdef REQUIRE_UI
 
719
        if (!gui_instance || !extui) {
 
720
    fprintf(stderr, "Error: GUI was not initialized.\n");
 
721
                goto out;
 
722
        }
 
723
#endif
 
724
 
 
725
  if (mlockall (MCL_CURRENT | MCL_FUTURE)) {
 
726
    fprintf(stderr, "Warning: Can not lock memory.\n");
 
727
  }
 
728
 
 
729
        if (plugin_dsp->activate) {
 
730
                plugin_dsp->activate(plugin_instance);
 
731
        }
 
732
 
 
733
  if (jack_activate (j_client)) {
 
734
    fprintf (stderr, "cannot activate client.\n");
 
735
    goto out;
 
736
  }
 
737
 
 
738
#ifndef _WIN32
 
739
  signal (SIGHUP, catchsig);
 
740
  signal (SIGINT, catchsig);
 
741
#endif
 
742
 
 
743
        if (!gui_instance || !extui) {
 
744
                /* no GUI */
 
745
                while (client_state != Exit) {
 
746
                        sleep (1);
 
747
                }
 
748
        } else {
 
749
 
 
750
                LV2_EXTERNAL_UI_SHOW(extui);
 
751
 
 
752
                main_loop();
 
753
 
 
754
                LV2_EXTERNAL_UI_HIDE(extui);
 
755
        }
 
756
 
 
757
out:
 
758
  cleanup(0);
 
759
  return(0);
 
760
}
 
761
/* vi:set ts=2 sts=2 sw=2: */