1 /*
2 * Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
3 *
4 * This is free software: you can redistribute it and/or modify
5 * it under the terms of the Artistic License 2.0 as published by
6 * The Perl Foundation.
7 *
8 * This source is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * Artistic License 2.0 for more details.
12 *
13 * You should have received a copy of the Artistic License 2.0
14 * along the source as a COPYING file. If not, obtain it from
15 * http://www.perlfoundation.org/artistic_license_2_0.
16 */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <assert.h>
22 #include <limits.h>
23 #include <math.h>
24
25 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
26 # include <pthread_np.h>
27 typedef cpuset_t cpu_set_t;
28 #endif
29
30 #include <synthpod_bin.h>
31
32 #include <jack/jack.h>
33 #include <jack/midiport.h>
34 #include <jack/transport.h>
35 #include <jack/session.h>
36 #if defined(JACK_HAS_METADATA_API)
37 # include <jack/metadata.h>
38 # include <jack/uuid.h>
39 # include <jackey.h>
40 #endif
41
42 #include <osc.lv2/forge.h>
43 #include <osc.lv2/writer.h>
44
45 #define OSC_SIZE 0x800
46
47 typedef struct _prog_t prog_t;
48
49 struct _prog_t {
50 bin_t bin;
51
52 LV2_Atom_Forge forge;
53
54 uint8_t osc_buf [OSC_SIZE]; //TODO how big?
55
56 LV2_OSC_URID osc_urid;
57
58 LV2_URID midi_MidiEvent;
59
60 LV2_URID time_position;
61 LV2_URID time_barBeat;
62 LV2_URID time_bar;
63 LV2_URID time_beatUnit;
64 LV2_URID time_beatsPerBar;
65 LV2_URID time_beatsPerMinute;
66 LV2_URID time_frame;
67 LV2_URID time_framesPerSecond;
68 LV2_URID time_speed;
69
70 atomic_int kill;
71 save_state_t save_state;
72 atomic_uintptr_t async;
73
74 char *server_name;
75 char *session_id;
76 jack_client_t *client;
77 jack_session_event_t *session_event;
78 uint32_t seq_size;
79
80 struct {
81 jack_transport_state_t rolling;
82 jack_nframes_t frame;
83 float beats_per_bar;
84 float beat_type;
85 double ticks_per_beat;
86 double beats_per_minute;
87 } trans;
88
89 LV2_OSC_Schedule osc_sched;
90 struct timespec cur_ntp;
91 struct {
92 jack_nframes_t cur_frames;
93 jack_nframes_t ref_frames;
94 jack_time_t cur_usecs;
95 jack_time_t nxt_usecs;
96 double dT;
97 double dTm1;
98 } cycle;
99 };
100
101 static LV2_Atom_Forge_Ref
_trans_event(prog_t * prog,LV2_Atom_Forge * forge,int rolling,jack_position_t * pos)102 _trans_event(prog_t *prog, LV2_Atom_Forge *forge, int rolling, jack_position_t *pos)
103 {
104 LV2_Atom_Forge_Frame frame;
105
106 LV2_Atom_Forge_Ref ref = lv2_atom_forge_frame_time(forge, 0);
107 if(ref)
108 ref = lv2_atom_forge_object(forge, &frame, 0, prog->time_position);
109 {
110 if(ref)
111 ref = lv2_atom_forge_key(forge, prog->time_frame);
112 if(ref)
113 ref = lv2_atom_forge_long(forge, pos->frame);
114
115 if(ref)
116 ref = lv2_atom_forge_key(forge, prog->time_speed);
117 if(ref)
118 ref = lv2_atom_forge_float(forge, rolling ? 1.0 : 0.0);
119
120 if(pos->valid & JackPositionBBT)
121 {
122 float bar_beat = pos->beat - 1 + (pos->tick / pos->ticks_per_beat);
123 float bar = pos->bar - 1;
124
125 if(ref)
126 ref = lv2_atom_forge_key(forge, prog->time_barBeat);
127 if(ref)
128 ref = lv2_atom_forge_float(forge, bar_beat);
129
130 if(ref)
131 ref = lv2_atom_forge_key(forge, prog->time_bar);
132 if(ref)
133 ref = lv2_atom_forge_long(forge, bar);
134
135 if(ref)
136 ref = lv2_atom_forge_key(forge, prog->time_beatUnit);
137 if(ref)
138 ref = lv2_atom_forge_int(forge, pos->beat_type);
139
140 if(ref)
141 ref = lv2_atom_forge_key(forge, prog->time_beatsPerBar);
142 if(ref)
143 ref = lv2_atom_forge_float(forge, pos->beats_per_bar);
144
145 if(ref)
146 ref = lv2_atom_forge_key(forge, prog->time_beatsPerMinute);
147 if(ref)
148 ref = lv2_atom_forge_float(forge, pos->beats_per_minute);
149 }
150 }
151 if(ref)
152 lv2_atom_forge_pop(forge, &frame);
153
154 return ref;
155 }
156
157 __non_realtime static void
_saved(bin_t * bin,int status)158 _saved(bin_t *bin, int status)
159 {
160 prog_t *handle = (void *)bin - offsetof(prog_t, bin);
161
162 if(handle->save_state == SAVE_STATE_NSM)
163 {
164 nsmc_saved(bin->nsm, status);
165 }
166 else if(handle->save_state == SAVE_STATE_JACK)
167 {
168 jack_session_event_t *ev = handle->session_event;
169 if(ev)
170 {
171 if(status != 0)
172 ev->flags |= JackSessionSaveError;
173 jack_session_reply(handle->client, ev);
174 jack_session_event_free(ev);
175 handle->session_event = NULL;
176 }
177 }
178 handle->save_state = SAVE_STATE_INTERNAL;
179
180 if(atomic_load_explicit(&handle->kill, memory_order_relaxed))
181 {
182 bin_quit(bin);
183 }
184 }
185
186 // rt
187 __realtime static int
_process(jack_nframes_t nsamples,void * data)188 _process(jack_nframes_t nsamples, void *data)
189 {
190 prog_t *handle = data;
191 bin_t *bin = &handle->bin;
192 sp_app_t *app = bin->app;
193
194 if(bin->first)
195 {
196 bin->dsp_thread = pthread_self();
197
198 if(handle->bin.cpu_affinity)
199 {
200 cpu_set_t cpuset;
201 CPU_ZERO(&cpuset);
202 CPU_SET(0, &cpuset);
203 if(pthread_setaffinity_np(bin->dsp_thread, sizeof(cpu_set_t), &cpuset))
204 bin_log_trace(bin, "%s: pthread_setaffinity_np error\n", __func__);
205 }
206
207 bin->first = false;
208 }
209
210 cross_clock_gettime(&bin->clk_real, &handle->cur_ntp);
211 handle->cur_ntp.tv_sec += JAN_1970; // convert NTP to OSC time
212 //jack_nframes_t offset = jack_frames_since_cycle_start(handle->client);
213
214 float T;
215 jack_get_cycle_times(handle->client, &handle->cycle.cur_frames,
216 &handle->cycle.cur_usecs, &handle->cycle.nxt_usecs, &T);
217 (void)T;
218
219 handle->cycle.ref_frames = handle->cycle.cur_frames;
220
221 // calculate apparent period
222 double diff = 1e-6 * (handle->cycle.nxt_usecs - handle->cycle.cur_usecs);
223
224 // calculate apparent samples per period
225 handle->cycle.dT = nsamples / diff;
226 handle->cycle.dTm1 = 1.0 / handle->cycle.dT;
227
228 // get transport position
229 jack_position_t pos;
230 jack_transport_state_t rolling = jack_transport_query(handle->client, &pos) == JackTransportRolling;
231 int trans_changed = (rolling != handle->trans.rolling)
232 || (pos.frame != handle->trans.frame)
233 || (pos.beats_per_bar != handle->trans.beats_per_bar)
234 || (pos.beat_type != handle->trans.beat_type)
235 || (pos.ticks_per_beat != handle->trans.ticks_per_beat)
236 || (pos.beats_per_minute != handle->trans.beats_per_minute);
237
238 const size_t sample_buf_size = sizeof(float) * nsamples;
239 const sp_app_system_source_t *sources = sp_app_get_system_sources(app);
240
241 if(sp_app_bypassed(app)) // aka loading state
242 {
243 const sp_app_system_sink_t *sinks = sp_app_get_system_sinks(app);
244
245 //fprintf(stderr, "app is bypassed\n");
246
247 // clear output buffers
248 for(const sp_app_system_sink_t *sink=sinks;
249 sink->type != SYSTEM_PORT_NONE;
250 sink++)
251 {
252 switch(sink->type)
253 {
254 case SYSTEM_PORT_NONE:
255 case SYSTEM_PORT_CONTROL:
256 case SYSTEM_PORT_COM:
257 break;
258
259 case SYSTEM_PORT_AUDIO:
260 case SYSTEM_PORT_CV:
261 {
262 void *out_buf = jack_port_get_buffer(sink->sys_port, nsamples);
263 memset(out_buf, 0x0, sample_buf_size);
264 break;
265 }
266 case SYSTEM_PORT_MIDI:
267 case SYSTEM_PORT_OSC:
268 {
269 void *out_buf = jack_port_get_buffer(sink->sys_port, nsamples);
270 jack_midi_clear_buffer(out_buf);
271 break;
272 }
273 }
274 }
275
276 bin_process_pre(bin, nsamples, true);
277 bin_process_post(bin);
278
279 return 0;
280 }
281
282 //TODO use __builtin_assume_aligned
283
284 // fill input buffers
285 for(const sp_app_system_source_t *source=sources;
286 source->type != SYSTEM_PORT_NONE;
287 source++)
288 {
289 switch(source->type)
290 {
291 case SYSTEM_PORT_NONE:
292 case SYSTEM_PORT_CONTROL:
293 break;
294
295 case SYSTEM_PORT_AUDIO:
296 case SYSTEM_PORT_CV:
297 {
298 const void *in_buf = jack_port_get_buffer(source->sys_port, nsamples);
299 memcpy(source->buf, in_buf, sample_buf_size);
300 break;
301 }
302 case SYSTEM_PORT_MIDI:
303 {
304 void *in_buf = jack_port_get_buffer(source->sys_port, nsamples);
305 void *seq_in = source->buf;
306
307 LV2_Atom_Forge *forge = &handle->forge;
308 LV2_Atom_Forge_Frame frame;
309 lv2_atom_forge_set_buffer(forge, seq_in, SEQ_SIZE);
310 LV2_Atom_Forge_Ref ref = lv2_atom_forge_sequence_head(forge, &frame, 0);
311
312 if(ref && trans_changed)
313 ref = _trans_event(handle, forge, rolling, &pos);
314
315 const int n = jack_midi_get_event_count(in_buf);
316 for(int i=0; i<n; i++)
317 {
318 jack_midi_event_t mev;
319 jack_midi_event_get(&mev, in_buf, i);
320
321 if( (mev.buffer[0] & 0x80) != 0x80)
322 continue; // no MIDI message
323
324 //add jack midi event to in_buf
325 if(ref)
326 ref = lv2_atom_forge_frame_time(forge, mev.time);
327 if(ref)
328 ref = lv2_atom_forge_atom(forge, mev.size, handle->midi_MidiEvent);
329 // fix up noteOn(vel=0) -> noteOff(vel=0)
330 if( (mev.size == 3) && ( (mev.buffer[0] & 0xf0) == 0x90)
331 && (mev.buffer[2] == 0x00) )
332 {
333 const uint8_t note_off [3] = {
334 0x80 | (mev.buffer[0] & 0xf),
335 mev.buffer[1],
336 0x0
337 };
338 if(ref)
339 ref = lv2_atom_forge_write(forge, note_off, sizeof(note_off));
340 }
341 else
342 {
343 if(ref)
344 ref = lv2_atom_forge_write(forge, mev.buffer, mev.size);
345 }
346 }
347 if(ref)
348 lv2_atom_forge_pop(forge, &frame);
349 else
350 lv2_atom_sequence_clear(seq_in);
351
352 break;
353 }
354
355 case SYSTEM_PORT_OSC:
356 {
357 void *in_buf = jack_port_get_buffer(source->sys_port, nsamples);
358 void *seq_in = source->buf;
359
360 LV2_Atom_Forge *forge = &handle->forge;
361 LV2_Atom_Forge_Frame frame;
362 lv2_atom_forge_set_buffer(forge, seq_in, SEQ_SIZE);
363 LV2_Atom_Forge_Ref ref = lv2_atom_forge_sequence_head(forge, &frame, 0);
364
365 if(ref && trans_changed)
366 ref = _trans_event(handle, forge, rolling, &pos);
367
368 const int n = jack_midi_get_event_count(in_buf);
369 for(int i=0; i<n; i++)
370 {
371 jack_midi_event_t mev;
372 jack_midi_event_get(&mev, in_buf, i);
373
374 if( (mev.buffer[0] != '/') && (mev.buffer[0] != '#') )
375 continue; // no OSC message
376
377 if(ref)
378 ref = lv2_atom_forge_frame_time(forge, mev.time);
379 if(ref)
380 ref = lv2_osc_forge_packet(forge, &handle->osc_urid, handle->bin.map,
381 mev.buffer, mev.size); // Note: an invalid packet will return 0
382 }
383 if(ref)
384 lv2_atom_forge_pop(forge, &frame);
385 else
386 lv2_atom_sequence_clear(seq_in);
387
388 break;
389 }
390
391 case SYSTEM_PORT_COM:
392 {
393 void *seq_in = source->buf;
394
395 LV2_Atom_Forge *forge = &handle->forge;
396 LV2_Atom_Forge_Frame frame;
397 lv2_atom_forge_set_buffer(forge, seq_in, SEQ_SIZE);
398 LV2_Atom_Forge_Ref ref = lv2_atom_forge_sequence_head(forge, &frame, 0);
399
400 const LV2_Atom_Object *obj;
401 size_t size;
402 while((obj = varchunk_read_request(bin->app_from_com, &size)))
403 {
404 if(ref)
405 ref = lv2_atom_forge_frame_time(forge, 0);
406 if(ref)
407 ref = lv2_atom_forge_write(forge, obj, size);
408
409 varchunk_read_advance(bin->app_from_com);
410 }
411 if(ref)
412 lv2_atom_forge_pop(forge, &frame);
413 else
414 lv2_atom_sequence_clear(seq_in);
415
416 break;
417 }
418 }
419 }
420
421 // update transport state
422 handle->trans.rolling = rolling;
423 handle->trans.frame = rolling
424 ? handle->trans.frame + nsamples
425 : pos.frame;
426 handle->trans.beats_per_bar = pos.beats_per_bar;
427 handle->trans.beat_type = pos.beat_type;
428 handle->trans.ticks_per_beat = pos.ticks_per_beat;
429 handle->trans.beats_per_minute = pos.beats_per_minute;
430
431 bin_process_pre(bin, nsamples, false);
432
433 const sp_app_system_sink_t *sinks = sp_app_get_system_sinks(app);
434
435 // fill output buffers
436 for(const sp_app_system_sink_t *sink=sinks;
437 sink->type != SYSTEM_PORT_NONE;
438 sink++)
439 {
440 switch(sink->type)
441 {
442 case SYSTEM_PORT_NONE:
443 case SYSTEM_PORT_CONTROL:
444 break;
445
446 case SYSTEM_PORT_AUDIO:
447 case SYSTEM_PORT_CV:
448 {
449 void *out_buf = jack_port_get_buffer(sink->sys_port, nsamples);
450 memcpy(out_buf, sink->buf, sample_buf_size);
451 break;
452 }
453 case SYSTEM_PORT_MIDI:
454 {
455 void *out_buf = jack_port_get_buffer(sink->sys_port, nsamples);
456 const LV2_Atom_Sequence *seq_out = sink->buf;
457
458 // fill midi output buffer
459 jack_midi_clear_buffer(out_buf);
460 if(seq_out)
461 {
462 LV2_ATOM_SEQUENCE_FOREACH(seq_out, ev)
463 {
464 const LV2_Atom *atom = &ev->body;
465
466 if(atom->type != handle->midi_MidiEvent)
467 continue; // ignore non-MIDI events
468
469 jack_midi_event_write(out_buf, ev->time.frames,
470 LV2_ATOM_BODY_CONST(atom), atom->size);
471 }
472 }
473
474 break;
475 }
476
477 case SYSTEM_PORT_OSC:
478 {
479 void *out_buf = jack_port_get_buffer(sink->sys_port, nsamples);
480 const LV2_Atom_Sequence *seq_out = sink->buf;
481
482 // fill midi output buffer
483 jack_midi_clear_buffer(out_buf);
484 if(seq_out)
485 {
486 LV2_ATOM_SEQUENCE_FOREACH(seq_out, ev)
487 {
488 const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body;
489
490 if(!lv2_atom_forge_is_object_type(&handle->forge, obj->atom.type))
491 continue;
492
493 if(!lv2_osc_is_message_or_bundle_type(&handle->osc_urid, obj->body.otype))
494 continue;
495
496 LV2_OSC_Writer writer;
497 lv2_osc_writer_initialize(&writer, handle->osc_buf, OSC_SIZE);
498 lv2_osc_writer_packet(&writer, &handle->osc_urid, handle->bin.unmap,
499 obj->atom.size, &obj->body);
500 size_t size;
501 uint8_t *osc_buf = lv2_osc_writer_finalize(&writer, &size);
502
503 if(size)
504 {
505 jack_midi_event_write(out_buf, ev->time.frames,
506 osc_buf, size);
507 }
508 }
509 }
510
511 break;
512 }
513
514 case SYSTEM_PORT_COM:
515 {
516 const LV2_Atom_Sequence *seq_out = sink->buf;
517
518 LV2_ATOM_SEQUENCE_FOREACH(seq_out, ev)
519 {
520 const LV2_Atom *atom = (const LV2_Atom *)&ev->body;
521
522 // try do process events directly
523 bin->advance_ui = sp_app_from_ui(bin->app, atom);
524 if(!bin->advance_ui) // queue event in ringbuffer instead
525 {
526 //fprintf(stderr, "plugin ui direct is blocked\n");
527
528 void *ptr;
529 size_t size = lv2_atom_total_size(atom);
530 if((ptr = varchunk_write_request(bin->app_from_app, size)))
531 {
532 memcpy(ptr, atom, size);
533 varchunk_write_advance(bin->app_from_app, size);
534 }
535 else
536 {
537 bin_log_trace(bin, "%s: app_from_app ringbuffer full\n", __func__);
538 //FIXME
539 }
540 }
541 }
542 break;
543 }
544 }
545 }
546
547 bin_process_post(bin);
548
549 return 0;
550 }
551
552 __non_realtime static void
_session(jack_session_event_t * ev,void * data)553 _session(jack_session_event_t *ev, void *data)
554 {
555 prog_t *handle = data;
556
557 //printf("_session: %s %s %s\n",
558 // ev->session_dir, ev->client_uuid, ev->command_line);
559
560 jack_session_event_t *async = (void *)atomic_exchange(&handle->async, (uintptr_t)ev);
561 if(async)
562 jack_session_event_free(async);
563 }
564
565 // rt, but can do non-rt stuff, as process won't be called
566 __non_realtime static int
_buffer_size(jack_nframes_t block_size,void * data)567 _buffer_size(jack_nframes_t block_size, void *data)
568 {
569 prog_t *handle = data;
570 bin_t *bin = &handle->bin;
571
572 //printf("JACK: new buffer size: %p %u %u\n",
573 // handle->app, handle->app_driver.max_block_size, block_size);
574
575 if(bin->app)
576 return sp_app_nominal_block_length(bin->app, block_size);
577
578 return 0;
579 }
580
581 __non_realtime static int
_sample_rate(jack_nframes_t sample_rate,void * data)582 _sample_rate(jack_nframes_t sample_rate, void *data)
583 {
584 prog_t *handle = data;
585 bin_t *bin = &handle->bin;
586
587 if(bin->app && (sample_rate != bin->app_driver.sample_rate) )
588 bin_log_error(bin, "%s: synthpod does not support dynamic sample rate changes\n", __func__);
589
590 return 0;
591 }
592
593 void
_replace(char * str,const char * a,const char * b)594 _replace(char* str, const char* a, const char* b)
595 {
596 const size_t len = strlen(str);
597 const size_t lena = strlen(a);
598 const size_t lenb = strlen(b);
599
600 for(char *p = str; (p = strstr(p, a)); ++p)
601 {
602 if(lena != lenb) // shift end as needed
603 {
604 memmove(p+lenb, p+lena, len - (p - str) + lenb);
605 }
606 memcpy(p, b, lenb);
607 }
608 }
609
610 __non_realtime static void *
_system_port_add(void * data,system_port_t type,const char * short_name,const char * pretty_name,const char * designation,bool input,uint32_t order)611 _system_port_add(void *data, system_port_t type, const char *short_name,
612 const char *pretty_name, const char *designation, bool input, uint32_t order)
613 {
614 bin_t *bin = data;
615 prog_t *handle = (void *)bin - offsetof(prog_t, bin);
616
617 //printf("_system_port_add: %s\n", short_name);
618
619 const size_t len = jack_port_name_size();
620 char *name = alloca(len);
621 strncpy(name, short_name, len);
622
623 if(strstr(name, "sink"))
624 _replace(name, "sink", "source");
625 else if(strstr(name, "source"))
626 _replace(name, "source", "sink");
627
628 jack_port_t *jack_port = NULL;
629
630 unsigned long flags = input ? JackPortIsInput : JackPortIsOutput;
631
632 switch(type)
633 {
634 case SYSTEM_PORT_NONE:
635 {
636 // skip
637 break;
638 }
639
640 case SYSTEM_PORT_CONTROL:
641 {
642 // unsupported, skip
643 break;
644 }
645
646 case SYSTEM_PORT_AUDIO:
647 {
648 jack_port = jack_port_register(handle->client, name,
649 JACK_DEFAULT_AUDIO_TYPE, flags, 0);
650 break;
651 }
652 case SYSTEM_PORT_CV:
653 {
654 jack_port = jack_port_register(handle->client, name,
655 JACK_DEFAULT_AUDIO_TYPE, flags, 0);
656
657 #if defined(JACK_HAS_METADATA_API)
658 if(jack_port)
659 {
660 jack_uuid_t uuid = jack_port_uuid(jack_port);
661 if(!jack_uuid_empty(uuid))
662 {
663 jack_set_property(handle->client, uuid,
664 JACKEY_SIGNAL_TYPE, "CV", "text/plain");
665 }
666 }
667 #endif
668 break;
669 }
670
671 case SYSTEM_PORT_MIDI:
672 {
673 jack_port = jack_port_register(handle->client, name,
674 JACK_DEFAULT_MIDI_TYPE, flags, 0);
675
676 #if defined(JACK_HAS_METADATA_API)
677 if(jack_port)
678 {
679 jack_uuid_t uuid = jack_port_uuid(jack_port);
680 if(!jack_uuid_empty(uuid))
681 {
682 jack_set_property(handle->client, uuid,
683 JACKEY_EVENT_TYPES, "MIDI", "text/plain");
684 }
685 }
686 #endif
687 break;
688 }
689 case SYSTEM_PORT_OSC:
690 {
691 jack_port = jack_port_register(handle->client, name,
692 JACK_DEFAULT_MIDI_TYPE, flags, 0);
693
694 #if defined(JACK_HAS_METADATA_API)
695 if(jack_port)
696 {
697 jack_uuid_t uuid = jack_port_uuid(jack_port);
698 if(!jack_uuid_empty(uuid))
699 {
700 jack_set_property(handle->client, uuid,
701 JACKEY_EVENT_TYPES, "OSC", "text/plain");
702 }
703 }
704 #endif
705 break;
706 }
707
708 case SYSTEM_PORT_COM:
709 {
710 // unsupported, skip
711 break;
712 }
713 }
714
715 #if defined(JACK_HAS_METADATA_API)
716 if(jack_port)
717 {
718 jack_uuid_t uuid = jack_port_uuid(jack_port);
719 if(!jack_uuid_empty(uuid))
720 {
721 if(pretty_name)
722 {
723 jack_set_property(handle->client, uuid,
724 JACK_METADATA_PRETTY_NAME, pretty_name, "text/plain");
725 }
726
727 if(designation)
728 {
729 jack_set_property(handle->client, uuid,
730 JACKEY_DESIGNATION, designation, "text/plain");
731 }
732
733 char order_str [32];
734 sprintf(order_str, "%"PRIu32, order);
735 jack_set_property(handle->client, uuid,
736 JACKEY_ORDER, order_str, "http://www.w3.org/2001/XMLSchema#integer");
737 }
738 }
739 #endif
740
741 return jack_port;
742 }
743
744 __non_realtime static void
_system_port_del(void * data,void * sys_port)745 _system_port_del(void *data, void *sys_port)
746 {
747 bin_t *bin = data;
748 prog_t *handle = (void *)bin - offsetof(prog_t, bin);
749
750 jack_port_t *jack_port = sys_port;
751
752 if(!jack_port || !handle->client)
753 return;
754
755 #if defined(JACK_HAS_METADATA_API)
756 jack_uuid_t uuid = jack_port_uuid(jack_port);
757 if(!jack_uuid_empty(uuid))
758 jack_remove_properties(handle->client, uuid);
759 #endif
760
761 jack_port_unregister(handle->client, jack_port);
762 }
763
764 __non_realtime static void
_shutdown(void * data)765 _shutdown(void *data)
766 {
767 prog_t *handle = data;
768
769 //TODO do this asynchronously?
770 handle->client = NULL; // client has died, didn't it?
771 bin_quit(&handle->bin);
772 }
773
774 __non_realtime static int
_xrun(void * data)775 _xrun(void *data)
776 {
777 prog_t *handle = data;
778 bin_t *bin = &handle->bin;
779
780 //TODO do this asynchronously?
781 bin_log_warning(bin, "JACK XRun\n");
782
783 return 0;
784 }
785
786 static int
_jack_init(prog_t * handle,const char * id)787 _jack_init(prog_t *handle, const char *id)
788 {
789 jack_options_t opts = JackNullOption | JackNoStartServer;
790 if(handle->server_name)
791 opts |= JackServerName;
792 if(handle->session_id)
793 opts |= JackSessionID;
794
795 jack_status_t status;
796 if(!(handle->client = jack_client_open(id, opts, &status,
797 handle->server_name ? handle->server_name : handle->session_id,
798 handle->server_name ? handle->session_id : NULL)))
799 {
800 return -1;
801 }
802
803 //TODO check status
804
805 // set client pretty name
806 #if defined(JACK_HAS_METADATA_API)
807 jack_uuid_t uuid;
808 const char *client_name = jack_get_client_name(handle->client);
809 const char *uuid_str = jack_get_uuid_for_client_name(handle->client, client_name);
810 if(uuid_str)
811 jack_uuid_parse(uuid_str, &uuid);
812 else
813 jack_uuid_clear(&uuid);
814
815 if(!jack_uuid_empty(uuid))
816 {
817 jack_set_property(handle->client, uuid,
818 JACK_METADATA_PRETTY_NAME, "Synthpod", "text/plain");
819 }
820 #endif
821
822 // set client process callback
823 if(jack_set_process_callback(handle->client, _process, handle))
824 return -1;
825 if(jack_set_session_callback(handle->client, _session, handle))
826 return -1;
827 if(jack_set_sample_rate_callback(handle->client, _sample_rate, handle))
828 return -1;
829 if(jack_set_buffer_size_callback(handle->client, _buffer_size, handle))
830 return -1;
831 jack_on_shutdown(handle->client, _shutdown, handle);
832 jack_set_xrun_callback(handle->client, _xrun, handle);
833
834 return 0;
835 }
836
837 static void
_jack_deinit(prog_t * handle)838 _jack_deinit(prog_t *handle)
839 {
840 if(handle->client)
841 {
842 // remove client properties
843 #if defined(JACK_HAS_METADATA_API)
844 jack_uuid_t uuid;
845 const char *client_name = jack_get_client_name(handle->client);
846 const char *uuid_str = jack_get_uuid_for_client_name(handle->client, client_name);
847 if(uuid_str)
848 jack_uuid_parse(uuid_str, &uuid);
849 else
850 jack_uuid_clear(&uuid);
851
852 if(!jack_uuid_empty(uuid))
853 jack_remove_properties(handle->client, uuid);
854 #endif
855
856 jack_deactivate(handle->client);
857 jack_client_close(handle->client);
858 handle->client = NULL;
859 }
860 }
861
862 __non_realtime static int
_open(const char * path,const char * name,const char * id,void * data)863 _open(const char *path, const char *name, const char *id, void *data)
864 {
865 bin_t *bin = data;
866 prog_t *handle = (void *)bin - offsetof(prog_t, bin);
867 (void)name;
868
869 if(bin->path)
870 free(bin->path);
871 bin->path = strdup(path);
872
873 // jack init
874 if(_jack_init(handle, id))
875 {
876 nsmc_opened(bin->nsm, -1);
877 return -1;
878 }
879
880 // synthpod init
881 bin->app_driver.sample_rate = jack_get_sample_rate(handle->client);
882 bin->app_driver.update_rate = handle->bin.update_rate;
883 bin->app_driver.max_block_size = jack_get_buffer_size(handle->client);
884 bin->app_driver.min_block_size = 1;
885 bin->app_driver.seq_size = MAX(handle->seq_size,
886 jack_port_type_get_buffer_size(handle->client, JACK_DEFAULT_MIDI_TYPE));
887 bin->app_driver.num_periods = 1; //FIXME
888
889 // app init
890 bin->app = sp_app_new(NULL, &bin->app_driver, bin);
891
892 // jack activate
893 atomic_init(&handle->kill, 0);
894 jack_activate(handle->client); //TODO check
895
896 bin_bundle_load(bin, bin->path);
897 nsmc_opened(bin->nsm, 0);
898
899 return 0; // success
900 }
901
902 __non_realtime static int
_save(void * data)903 _save(void *data)
904 {
905 bin_t *bin = data;
906 prog_t *handle = (void *)bin - offsetof(prog_t, bin);
907
908 handle->save_state = SAVE_STATE_NSM;
909 bin_bundle_save(bin, bin->path);
910 _saved(bin, 0);
911
912 return 0; // success
913 }
914
915 __non_realtime static int
_show(void * data)916 _show(void *data)
917 {
918 bin_t *bin = data;
919
920 return bin_show(bin);
921 }
922
923 __non_realtime static int
_hide(void * data)924 _hide(void *data)
925 {
926 bin_t *bin = data;
927
928 return bin_hide(bin);
929 }
930
931 static const nsmc_driver_t nsm_driver = {
932 .open = _open,
933 .save = _save,
934 .show = _show,
935 .hide = _hide
936 };
937
938 // rt
939 __realtime static double
_osc_schedule_osc2frames(LV2_OSC_Schedule_Handle instance,uint64_t timestamp)940 _osc_schedule_osc2frames(LV2_OSC_Schedule_Handle instance, uint64_t timestamp)
941 {
942 prog_t *handle = instance;
943
944 if(timestamp == 1ULL)
945 return 0; // inject at start of period
946
947 const uint64_t time_sec = timestamp >> 32;
948 const uint64_t time_frac = timestamp & 0xffffffff;
949
950 const double diff = (time_sec - handle->cur_ntp.tv_sec)
951 + time_frac * 0x1p-32
952 - handle->cur_ntp.tv_nsec * 1e-9;
953
954 const double frames = diff * handle->cycle.dT
955 - handle->cycle.ref_frames
956 + handle->cycle.cur_frames;
957
958 return frames;
959 }
960
961 // rt
962 __realtime static uint64_t
_osc_schedule_frames2osc(LV2_OSC_Schedule_Handle instance,double frames)963 _osc_schedule_frames2osc(LV2_OSC_Schedule_Handle instance, double frames)
964 {
965 prog_t *handle = instance;
966
967 double diff = (frames - handle->cycle.cur_frames + handle->cycle.ref_frames)
968 * handle->cycle.dTm1;
969 diff += handle->cur_ntp.tv_nsec * 1e-9;
970 diff += handle->cur_ntp.tv_sec;
971
972 double time_sec_d;
973 double time_frac_d = modf(diff, &time_sec_d);
974
975 uint64_t time_sec = time_sec_d;
976 uint64_t time_frac = time_frac_d * 0x1p32;
977 if(time_frac >= 0x100000000ULL) // illegal overflow
978 time_frac = 0xffffffffULL;
979
980 uint64_t timestamp = (time_sec << 32) | time_frac;
981
982 return timestamp;
983 }
984
985 static void
_idle(void * data)986 _idle(void *data)
987 {
988 prog_t *handle = data;
989 bin_t *bin = &handle->bin;
990
991 jack_session_event_t *async = (void *)atomic_exchange(&handle->async, 0);
992 if(!async)
993 return;
994
995 //printf("_session_async: %s %s %s\n",
996 // async->session_dir, async->client_uuid, async->command_line);
997
998 char path [PATH_MAX];
999 const char *resolvedpath = realpath(async->session_dir, path);
1000 if(!resolvedpath)
1001 resolvedpath = async->session_dir; // fall-back
1002
1003 // create command line
1004 char *buf = NULL;
1005 size_t sz = 0;
1006 bool ignore = false;
1007
1008 for(int i=0; i<bin->optind; i++)
1009 {
1010 const char *arg = (i == 0)
1011 ? "synthpod_jack"
1012 : bin->argv[i];
1013
1014 if(ignore)
1015 {
1016 ignore = false;
1017 continue;
1018 }
1019
1020 if(!strcmp(arg, "-u"))
1021 {
1022 ignore = true;
1023 continue;
1024 }
1025
1026 const size_t len = strlen(arg);
1027 buf = realloc(buf, sz + len);
1028
1029 sprintf(&buf[sz], "%s ", arg);
1030 sz += len + 1;
1031 }
1032
1033 {
1034 const size_t len = 32;
1035 buf = realloc(buf, sz + len);
1036
1037 sprintf(&buf[sz], "-u %s ${SESSION_DIR}", async->client_uuid);
1038 }
1039
1040 async->command_line = buf;
1041 handle->session_event = async;
1042
1043 switch(async->type)
1044 {
1045 case JackSessionSaveAndQuit:
1046 atomic_store_explicit(&handle->kill, 1, memory_order_relaxed); // quit after saving
1047 // fall-through
1048 case JackSessionSave:
1049 handle->save_state = SAVE_STATE_JACK;
1050 bin_bundle_save(bin, resolvedpath);
1051 _saved(bin, 0);
1052 break;
1053 case JackSessionSaveTemplate:
1054 handle->save_state = SAVE_STATE_JACK;
1055 bin_bundle_new(bin);
1056 bin_bundle_save(bin, resolvedpath);
1057 _saved(bin, 0);
1058 break;
1059 }
1060 }
1061
1062 int
main(int argc,char ** argv)1063 main(int argc, char **argv)
1064 {
1065 mlockall(MCL_CURRENT | MCL_FUTURE);
1066
1067 static prog_t handle;
1068 bin_t *bin = &handle.bin;
1069
1070 handle.server_name = NULL;
1071 handle.session_id = NULL;
1072 handle.seq_size = SEQ_SIZE;
1073
1074 bin->audio_prio = 70; // not used
1075 bin->worker_prio = 60;
1076 bin->num_slaves = sysconf(_SC_NPROCESSORS_ONLN) - 1;
1077 bin->bad_plugins = false;
1078 bin->has_gui = false;
1079 bin->kill_gui = false;
1080 snprintf(bin->socket_path, sizeof(bin->socket_path), "shm:///synthpod-%i", getpid());
1081 bin->update_rate = 25;
1082 bin->cpu_affinity = false;
1083
1084 fprintf(stderr,
1085 "Synthpod "SYNTHPOD_VERSION"\n"
1086 "Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch)\n"
1087 "Released under Artistic License 2.0 by Open Music Kontrollers\n");
1088
1089 int c;
1090 while((c = getopt(argc, argv, "vhgGkKbBaAw:Wl:n:u:s:c:f:")) != -1)
1091 {
1092 switch(c)
1093 {
1094 case 'v':
1095 fprintf(stderr,
1096 "--------------------------------------------------------------------\n"
1097 "This is free software: you can redistribute it and/or modify\n"
1098 "it under the terms of the Artistic License 2.0 as published by\n"
1099 "The Perl Foundation.\n"
1100 "\n"
1101 "This source is distributed in the hope that it will be useful,\n"
1102 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1103 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1104 "Artistic License 2.0 for more details.\n"
1105 "\n"
1106 "You should have received a copy of the Artistic License 2.0\n"
1107 "along the source as a COPYING file. If not, obtain it from\n"
1108 "http://www.perlfoundation.org/artistic_license_2_0.\n\n");
1109 return 0;
1110 case 'h':
1111 fprintf(stderr,
1112 "--------------------------------------------------------------------\n"
1113 "USAGE\n"
1114 " %s [OPTIONS] [BUNDLE_PATH]\n"
1115 "\n"
1116 "OPTIONS\n"
1117 " [-v] print version and full license information\n"
1118 " [-h] print usage information\n"
1119 " [-g] load GUI\n"
1120 " [-G] do NOT load GUI (default)\n"
1121 " [-k] kill DSP with GUI\n"
1122 " [-K] do NOT kill DSP with GUI (default)\n"
1123 " [-b] enable bad plugins\n"
1124 " [-B] disable bad plugins (default)\n"
1125 " [-a] enable CPU affinity\n"
1126 " [-A] disable CPU affinity (default)\n"
1127 " [-w] worker-priority worker thread realtime priority (60)\n"
1128 " [-W] do NOT use worker thread realtime priority\n"
1129 " [-l] link-path socket link path (shm:///synthpod)\n"
1130 " [-n] server-name connect to named JACK daemon\n"
1131 " [-u] client-uuid client UUID for JACK session management\n"
1132 " [-s] sequence-size minimum sequence size (8192)\n"
1133 " [-c] slave-cores number of slave cores (auto)\n"
1134 " [-f] update-rate GUI update rate (25)\n\n"
1135 , argv[0]);
1136 return 0;
1137 case 'g':
1138 bin->has_gui = true;
1139 break;
1140 case 'G':
1141 bin->has_gui = false;
1142 break;
1143 case 'k':
1144 bin->kill_gui = true;
1145 break;
1146 case 'K':
1147 bin->kill_gui = false;
1148 break;
1149 case 'b':
1150 bin->bad_plugins = true;
1151 break;
1152 case 'B':
1153 bin->bad_plugins = false;
1154 break;
1155 case 'a':
1156 bin->cpu_affinity = true;
1157 break;
1158 case 'A':
1159 bin->cpu_affinity = false;
1160 break;
1161 case 'w':
1162 bin->worker_prio = atoi(optarg);
1163 break;
1164 case 'W':
1165 bin->worker_prio = 0;
1166 break;
1167 case 'l':
1168 snprintf(bin->socket_path, sizeof(bin->socket_path), "%s", optarg);
1169 break;
1170 case 'n':
1171 handle.server_name = optarg;
1172 break;
1173 case 'u':
1174 handle.session_id = optarg;
1175 break;
1176 case 's':
1177 handle.seq_size = MAX(SEQ_SIZE, atoi(optarg));
1178 break;
1179 case 'c':
1180 if(atoi(optarg) < bin->num_slaves)
1181 bin->num_slaves = atoi(optarg);
1182 break;
1183 case 'f':
1184 bin->update_rate = atoi(optarg);
1185 break;
1186 case '?':
1187 if( (optopt == 'n') || (optopt == 'u') || (optopt == 's') || (optopt == 'c')
1188 || (optopt == 'l') || (optopt == 'f') )
1189 fprintf(stderr, "Option `-%c' requires an argument.\n", optopt);
1190 else if(isprint(optopt))
1191 fprintf(stderr, "Unknown option `-%c'.\n", optopt);
1192 else
1193 fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
1194 return -1;
1195 default:
1196 return -1;
1197 }
1198 }
1199
1200 atomic_init(&handle.async, 0);
1201
1202 bin_init(bin, 48000); //FIXME
1203
1204 LV2_URID_Map *map = bin->map;
1205
1206 lv2_atom_forge_init(&handle.forge, map);
1207 lv2_osc_urid_init(&handle.osc_urid, map);
1208
1209 handle.midi_MidiEvent = map->map(map->handle, LV2_MIDI__MidiEvent);
1210
1211 handle.time_position = map->map(map->handle, LV2_TIME__Position);
1212 handle.time_barBeat = map->map(map->handle, LV2_TIME__barBeat);
1213 handle.time_bar = map->map(map->handle, LV2_TIME__bar);
1214 handle.time_beatUnit = map->map(map->handle, LV2_TIME__beatUnit);
1215 handle.time_beatsPerBar = map->map(map->handle, LV2_TIME__beatsPerBar);
1216 handle.time_beatsPerMinute = map->map(map->handle, LV2_TIME__beatsPerMinute);
1217 handle.time_frame = map->map(map->handle, LV2_TIME__frame);
1218 handle.time_framesPerSecond = map->map(map->handle, LV2_TIME__framesPerSecond);
1219 handle.time_speed = map->map(map->handle, LV2_TIME__speed);
1220
1221 bin->app_driver.system_port_add = _system_port_add;
1222 bin->app_driver.system_port_del = _system_port_del;
1223
1224 handle.osc_sched.osc2frames = _osc_schedule_osc2frames;
1225 handle.osc_sched.frames2osc = _osc_schedule_frames2osc;
1226 handle.osc_sched.handle = &handle;
1227 bin->app_driver.osc_sched = &handle.osc_sched;
1228
1229 bin->app_driver.features = SP_APP_FEATURE_POWER_OF_2_BLOCK_LENGTH; // always true for JACK
1230
1231 // run
1232 bin_run(bin, argv, &nsm_driver, _idle, &handle);
1233
1234 // stop
1235 bin_stop(bin);
1236
1237 jack_session_event_t *async = (void *)atomic_load(&handle.async);
1238 if(async)
1239 jack_session_event_free(async);
1240
1241 // deinit JACK
1242 _jack_deinit(&handle);
1243
1244 // deinit
1245 bin_deinit(bin);
1246
1247 munlockall();
1248
1249 return 0;
1250 }
1251