1 /*
2 * Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see http://www.gnu.org/licenses.
16 */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <ctype.h>
22 #include <math.h>
23
24 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
25 # include <pthread_np.h>
26 typedef cpuset_t cpu_set_t;
27 #endif
28
29 #include <asoundlib.h>
30 #include <pcmi.h>
31
32 #include <synthpod_bin.h>
33
34 #define MIDI_SEQ_SIZE 2048
35 #define NANO_SECONDS 1000000000
36
37 typedef enum _chan_type_t chan_type_t;
38 typedef struct _prog_t prog_t;
39 typedef struct _chan_t chan_t;
40
41 enum _chan_type_t {
42 CHAN_TYPE_PCMI,
43 CHAN_TYPE_MIDI
44 };
45
46 struct _chan_t {
47 chan_type_t type;
48
49 union {
50 struct {
51 //TODO
52 } audio;
53 struct {
54 int port;
55 snd_midi_event_t *trans;
56
57 LV2_Atom_Forge forge;
58 LV2_Atom_Forge_Frame frame;
59 LV2_Atom_Forge_Ref ref;
60 LV2_Atom_Sequence *seq_in;
61 int64_t last;
62 } midi;
63 };
64 };
65
66 struct _prog_t {
67 bin_t bin;
68
69 LV2_Atom_Forge forge;
70
71 LV2_URID midi_MidiEvent;
72
73 pcmi_t *pcmi;
74 snd_seq_t *seq;
75 int queue;
76 uint8_t m [MIDI_SEQ_SIZE];
77
78 save_state_t save_state;
79 atomic_int kill;
80 pthread_t thread;
81
82 uint32_t srate;
83 uint32_t frsize;
84 uint32_t nfrags;
85 bool twochan;
86 bool debug;
87 bool do_play;
88 bool do_capt;
89 uint32_t seq_size;
90
91 const char *io_name;
92 const char *play_name;
93 const char *capt_name;
94
95 LV2_OSC_Schedule osc_sched;
96 struct timespec cur_ntp;
97 struct timespec nxt_ntp;
98 struct {
99 uint64_t cur_frames;
100 uint64_t ref_frames;
101 double dT;
102 double dTm1;
103 } cycle;
104 };
105
106 static inline void
_ntp_now(cross_clock_t * clk,struct timespec * ntp)107 _ntp_now(cross_clock_t *clk, struct timespec *ntp)
108 {
109 cross_clock_gettime(clk, ntp);
110 ntp->tv_sec += JAN_1970; // convert NTP to OSC time
111 }
112
113 static inline void
_ntp_clone(struct timespec * dst,struct timespec * src)114 _ntp_clone(struct timespec *dst, struct timespec *src)
115 {
116 dst->tv_sec = src->tv_sec;
117 dst->tv_nsec = src->tv_nsec;
118 }
119
120 static inline void
_ntp_add_nanos(struct timespec * ntp,uint64_t nanos)121 _ntp_add_nanos(struct timespec *ntp, uint64_t nanos)
122 {
123 ntp->tv_nsec += nanos;
124 while(ntp->tv_nsec >= NANO_SECONDS) // has overflowed
125 {
126 ntp->tv_sec += 1;
127 ntp->tv_nsec -= NANO_SECONDS;
128 }
129 }
130
131 static inline double
_ntp_diff(struct timespec * from,struct timespec * to)132 _ntp_diff(struct timespec *from, struct timespec *to)
133 {
134 double diff = to->tv_sec;
135 diff -= from->tv_sec;
136 diff += 1e-9 * to->tv_nsec;
137 diff -= 1e-9 * from->tv_nsec;
138
139 return diff;
140 }
141
142 __realtime static inline void
_process(prog_t * handle)143 _process(prog_t *handle)
144 {
145 pcmi_t *pcmi = handle->pcmi;
146 bin_t *bin = &handle->bin;
147 sp_app_t *app = bin->app;
148
149 const uint32_t nsamples = handle->frsize;
150 int nplay = pcmi_nplay(pcmi);
151 int ncapt = pcmi_ncapt(pcmi);
152 int play_num;
153 int capt_num;
154
155 const uint64_t nanos_per_period = (uint64_t)nsamples * NANO_SECONDS / handle->srate;
156 handle->cycle.cur_frames = 0; // initialize frame counter
157 _ntp_now(&bin->clk_real, &handle->nxt_ntp);
158
159 snd_seq_queue_status_t *stat = NULL;
160 const snd_seq_real_time_t *real_time = NULL;
161 snd_seq_real_time_t ref_time;
162 snd_seq_queue_status_malloc(&stat);
163
164 pcmi_pcm_start(handle->pcmi);
165 while(!atomic_load_explicit(&handle->kill, memory_order_relaxed))
166 {
167 uint32_t na = pcmi_pcm_wait(pcmi);
168
169 // current time is next time from last cycle
170 _ntp_clone(&handle->cur_ntp, &handle->nxt_ntp);
171
172 // extrapolate new nxt_ntp
173 struct timespec nxt_ntp;
174 _ntp_now(&bin->clk_real, &nxt_ntp);
175 _ntp_clone(&handle->nxt_ntp, &nxt_ntp);
176
177 // reset ref_frames
178 handle->cycle.ref_frames = handle->cycle.cur_frames;
179
180 // calculate apparent period
181 _ntp_add_nanos(&nxt_ntp, nanos_per_period);
182 double diff = _ntp_diff(&handle->cur_ntp, &nxt_ntp);
183
184 // calculate apparent samples per period
185 handle->cycle.dT = nsamples / diff;
186 handle->cycle.dTm1 = 1.0 / handle->cycle.dT;
187
188 // get ALSA sequencer reference timestamp
189 snd_seq_get_queue_status(handle->seq, handle->queue, stat);
190 real_time = snd_seq_queue_status_get_real_time(stat);
191 ref_time.tv_sec = real_time->tv_sec;
192 ref_time.tv_nsec = real_time->tv_nsec;
193
194 uint32_t pos = 0;
195 for( ; na >= nsamples;
196 na -= nsamples,
197 handle->cycle.ref_frames += nsamples,
198 pos += nsamples,
199 _ntp_add_nanos(&handle->nxt_ntp, nanos_per_period) )
200 {
201 const sp_app_system_source_t *sources = sp_app_get_system_sources(app);
202
203 if(sp_app_bypassed(app))
204 {
205 //const sp_app_system_sink_t *sinks = sp_app_get_system_sinks(app);
206
207 //fprintf(stderr, "app is bypassed\n");
208
209 pcmi_pcm_idle(pcmi, nsamples);
210
211 bin_process_pre(bin, nsamples, true);
212 bin_process_post(bin);
213
214 continue;
215 }
216
217 // fill input buffers
218 if(ncapt)
219 pcmi_capt_init(pcmi, nsamples);
220 capt_num = 0;
221 for(const sp_app_system_source_t *source=sources;
222 source->type != SYSTEM_PORT_NONE;
223 source++)
224 {
225 chan_t *chan = source->sys_port;
226
227 switch(source->type)
228 {
229 case SYSTEM_PORT_NONE:
230 case SYSTEM_PORT_CONTROL:
231 case SYSTEM_PORT_CV:
232 case SYSTEM_PORT_OSC:
233 break;
234
235 case SYSTEM_PORT_AUDIO:
236 {
237
238 if(capt_num < ncapt)
239 pcmi_capt_chan(pcmi, capt_num++, source->buf, nsamples);
240
241 break;
242 }
243
244 case SYSTEM_PORT_MIDI:
245 {
246 void *seq_in = source->buf;
247
248 // initialize LV2 event port
249 LV2_Atom_Forge *forge = &chan->midi.forge;
250 chan->midi.seq_in = seq_in; // needed for lv2_atom_sequence_clear
251 lv2_atom_forge_set_buffer(forge, seq_in, SEQ_SIZE);
252 chan->midi.ref = lv2_atom_forge_sequence_head(forge, &chan->midi.frame, 0);
253 chan->midi.last = 0;
254
255 break;
256 }
257
258 case SYSTEM_PORT_COM:
259 {
260 void *seq_in = source->buf;
261
262 LV2_Atom_Forge *forge = &handle->forge;
263 LV2_Atom_Forge_Frame frame;
264 lv2_atom_forge_set_buffer(forge, seq_in, SEQ_SIZE);
265 LV2_Atom_Forge_Ref ref = lv2_atom_forge_sequence_head(forge, &frame, 0);
266
267 const LV2_Atom_Object *obj;
268 size_t size;
269 while((obj = varchunk_read_request(bin->app_from_com, &size)))
270 {
271 if(ref)
272 ref = lv2_atom_forge_frame_time(forge, 0);
273 if(ref)
274 ref = lv2_atom_forge_write(forge, obj, size);
275
276 varchunk_read_advance(bin->app_from_com);
277 }
278 if(ref)
279 lv2_atom_forge_pop(forge, &frame);
280 else
281 lv2_atom_sequence_clear(seq_in);
282
283 break;
284 }
285 }
286 }
287
288 // read incoming MIDI and dispatch to corresponding MIDI port
289 {
290 snd_seq_event_t *sev;
291 while(snd_seq_event_input_pending(handle->seq, 1) > 0)
292 {
293 chan_t *chan = NULL;
294
295 // get event
296 snd_seq_event_input(handle->seq, &sev);
297
298 // search for matching port
299 for(const sp_app_system_source_t *source=sources;
300 source->type != SYSTEM_PORT_NONE;
301 source++)
302 {
303 if(source->type == SYSTEM_PORT_MIDI)
304 {
305 chan_t *_chan = source->sys_port;
306
307 if(_chan->midi.port == sev->dest.port)
308 {
309 chan = _chan;
310 break; // right port found, break out of loop
311 }
312 }
313 }
314
315 if(chan)
316 {
317 long len;
318 if((len = snd_midi_event_decode(chan->midi.trans, handle->m,
319 MIDI_SEQ_SIZE, sev)) > 0)
320 {
321 LV2_Atom_Forge *forge = &chan->midi.forge;
322
323 const bool is_real = snd_seq_ev_is_real(sev);
324 const bool is_abs = snd_seq_ev_is_abstime(sev);
325 assert(is_real);
326
327 volatile double dd = sev->time.time.tv_sec;
328 if(is_abs) // calculate relative time difference
329 dd -= ref_time.tv_sec;
330 dd += sev->time.time.tv_nsec * 1e-9;
331 if(is_abs) // calculate relative time difference
332 dd -= ref_time.tv_nsec * 1e-9;
333
334 int64_t frames = dd * handle->srate - pos;
335 if(frames < 0)
336 frames = 0;
337 else if(frames >= nsamples)
338 frames = nsamples - 1; //TODO report this
339
340 if(frames < chan->midi.last)
341 frames = chan->midi.last; // frame time must be increasing
342 else
343 chan->midi.last = frames;
344
345 // fix up noteOn(vel=0) -> noteOff(vel=0)
346 if( (len == 3) && ( (handle->m[0] & 0xf0) == 0x90)
347 && (handle->m[2] == 0x0) )
348 {
349 handle->m[0] = 0x80 | (handle->m[0] & 0x0f);
350 handle->m[2] = 0x0;
351 }
352
353 if(chan->midi.ref)
354 chan->midi.ref = lv2_atom_forge_frame_time(forge, frames);
355 if(chan->midi.ref)
356 chan->midi.ref = lv2_atom_forge_atom(forge, len, handle->midi_MidiEvent);
357 if(chan->midi.ref)
358 chan->midi.ref = lv2_atom_forge_write(forge, handle->m, len);
359 }
360 else
361 {
362 bin_log_trace(bin, "%s: MIDI event decode failed\n", __func__);
363 }
364 }
365 else
366 {
367 bin_log_trace(bin, "%s: no matching port for MIDI event\n", __func__);
368 }
369
370 if(snd_seq_free_event(sev))
371 {
372 bin_log_trace(bin, "%s: MIDI event free failed\n", __func__);
373 }
374 }
375 }
376
377 for(const sp_app_system_source_t *source=sources;
378 source->type != SYSTEM_PORT_NONE;
379 source++)
380 {
381 chan_t *chan = source->sys_port;
382
383 if(source->type == SYSTEM_PORT_MIDI)
384 {
385 LV2_Atom_Forge *forge = &chan->midi.forge;
386
387 // finalize LV2 event port
388 if(chan->midi.ref)
389 lv2_atom_forge_pop(forge, &chan->midi.frame);
390 else
391 lv2_atom_sequence_clear(chan->midi.seq_in);
392 }
393 }
394 if(ncapt)
395 pcmi_capt_done(pcmi, nsamples);
396
397 bin_process_pre(bin, nsamples, false);
398
399 const sp_app_system_sink_t *sinks = sp_app_get_system_sinks(app);
400
401 // fill output buffers
402 if(nplay)
403 pcmi_play_init(pcmi, nsamples);
404 play_num = 0;
405 for(const sp_app_system_sink_t *sink=sinks;
406 sink->type != SYSTEM_PORT_NONE;
407 sink++)
408 {
409 chan_t *chan = sink->sys_port;
410
411 switch(sink->type)
412 {
413 case SYSTEM_PORT_NONE:
414 case SYSTEM_PORT_CONTROL:
415 case SYSTEM_PORT_CV:
416 case SYSTEM_PORT_OSC:
417 break;
418
419 case SYSTEM_PORT_AUDIO:
420 {
421
422 if(play_num < nplay)
423 pcmi_play_chan(pcmi, play_num++, sink->buf, nsamples);
424
425 break;
426 }
427
428 case SYSTEM_PORT_MIDI:
429 {
430 const LV2_Atom_Sequence *seq_out = sink->buf;
431
432 LV2_ATOM_SEQUENCE_FOREACH(seq_out, ev)
433 {
434 const LV2_Atom *atom = &ev->body;
435
436 if(atom->type != handle->midi_MidiEvent)
437 continue; // ignore non-MIDI events
438
439 snd_seq_event_t sev;
440 snd_seq_ev_clear(&sev);
441 long consumed;
442 const uint8_t *buf = LV2_ATOM_BODY_CONST(atom);
443 if( (consumed = snd_midi_event_encode(chan->midi.trans, buf, atom->size, &sev)) != atom->size)
444 {
445 bin_log_trace(bin, "%s: MIDI encode event failed: %li\n", __func__, consumed);
446 continue;
447 }
448
449 // absolute timestamp
450 volatile double dd = (double)(ev->time.frames + pos) / handle->srate;
451 double sec;
452 double nsec = modf(dd, &sec);
453 struct snd_seq_real_time rtime = {
454 .tv_sec = ref_time.tv_sec + sec,
455 .tv_nsec = ref_time.tv_nsec + nsec
456 };
457 while(rtime.tv_nsec >= NANO_SECONDS) // handle overflow
458 {
459 rtime.tv_sec += 1;
460 rtime.tv_nsec -= NANO_SECONDS;
461 }
462
463 // schedule midi
464 snd_seq_ev_set_source(&sev, chan->midi.port);
465 snd_seq_ev_set_subs(&sev); // set broadcasting to subscribers
466 snd_seq_ev_schedule_real(&sev, handle->queue, 0, &rtime); // absolute scheduling
467 snd_seq_event_output(handle->seq, &sev);
468 //snd_seq_drain_output(handle->seq);
469 }
470
471 break;
472 }
473
474 case SYSTEM_PORT_COM:
475 {
476 const LV2_Atom_Sequence *seq_out = sink->buf;
477
478 LV2_ATOM_SEQUENCE_FOREACH(seq_out, ev)
479 {
480 const LV2_Atom *atom = &ev->body;
481
482 // try do process events directly
483 bin->advance_ui = sp_app_from_ui(bin->app, atom);
484 if(!bin->advance_ui) // queue event in ringbuffer instead
485 {
486 //fprintf(stderr, "plugin ui direct is blocked\n");
487
488 void *ptr;
489 size_t size = lv2_atom_total_size(atom);
490 if((ptr = varchunk_write_request(bin->app_from_app, size)))
491 {
492 memcpy(ptr, atom, size);
493 varchunk_write_advance(bin->app_from_app, size);
494 }
495 else
496 {
497 bin_log_trace(bin, "%s: app_from_app ringbuffer full\n", __func__);
498 //FIXME
499 }
500 }
501 }
502 break;
503 }
504 }
505 }
506 snd_seq_drain_output(handle->seq); //TODO is this rt-safe?
507
508 // clear unused output channels
509 while(play_num<nplay)
510 {
511 pcmi_clear_chan(pcmi, play_num++, nsamples);
512 }
513
514 if(nplay)
515 pcmi_play_done(pcmi, nsamples);
516
517 bin_process_post(bin);
518 }
519
520 // increase cur_frames
521 handle->cycle.cur_frames = handle->cycle.ref_frames;
522 //sched_yield();
523 }
524 pcmi_pcm_stop(handle->pcmi);
525
526 snd_seq_queue_status_free(stat);
527 }
528
529 __non_realtime static void *
_rt_thread(void * data)530 _rt_thread(void *data)
531 {
532 prog_t *handle = data;
533 bin_t *bin = &handle->bin;
534
535 bin->dsp_thread = pthread_self();
536
537 if(handle->bin.audio_prio)
538 {
539 struct sched_param schedp;
540 memset(&schedp, 0, sizeof(struct sched_param));
541 schedp.sched_priority = handle->bin.audio_prio;
542
543 if(schedp.sched_priority)
544 {
545 if(pthread_setschedparam(bin->dsp_thread, SCHED_FIFO, &schedp))
546 bin_log_error(bin, "%s: pthread_setschedparam failed\n", __func__);
547 }
548 }
549
550 if(handle->bin.cpu_affinity)
551 {
552 cpu_set_t cpuset;
553 CPU_ZERO(&cpuset);
554 CPU_SET(0, &cpuset);
555 if(pthread_setaffinity_np(bin->dsp_thread, sizeof(cpu_set_t), &cpuset))
556 bin_log_error(bin, "%s: pthread_setaffinity_np failed\n", __func__);
557 }
558
559 _process(handle);
560
561 return NULL;
562 }
563
564 __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)565 _system_port_add(void *data, system_port_t type, const char *short_name,
566 const char *pretty_name, const char *designation, bool input, uint32_t order)
567 {
568 bin_t *bin = data;
569 prog_t *handle = (void *)bin - offsetof(prog_t, bin);
570
571 chan_t *chan = NULL;
572
573 switch(type)
574 {
575 case SYSTEM_PORT_NONE:
576 {
577 // skip
578 break;
579 }
580
581 case SYSTEM_PORT_CONTROL:
582 {
583 // unsupported, skip
584 break;
585 }
586
587 case SYSTEM_PORT_AUDIO:
588 {
589 chan = calloc(1, sizeof(chan_t));
590 if(chan)
591 {
592 chan->type = CHAN_TYPE_PCMI;
593 //TODO
594 }
595
596 break;
597 }
598 case SYSTEM_PORT_CV:
599 {
600 // unsupported, skip
601 break;
602 }
603
604 case SYSTEM_PORT_MIDI:
605 {
606 chan = calloc(1, sizeof(chan_t));
607 if(chan)
608 {
609 chan->type = CHAN_TYPE_MIDI;
610 memcpy(&chan->midi.forge, &handle->forge, sizeof(LV2_Atom_Forge)); // initialize forge
611
612 snd_seq_port_info_t *pinfo;
613 snd_seq_port_info_malloc(&pinfo);
614
615 snd_seq_port_info_set_name(pinfo, short_name);
616 snd_seq_port_info_set_capability(pinfo, input
617 ? SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE
618 : SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ);
619 snd_seq_port_info_set_type(pinfo, SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION);
620 snd_seq_port_info_set_midi_channels(pinfo, 16);
621 snd_seq_port_info_set_midi_voices(pinfo, 64);
622 snd_seq_port_info_set_synth_voices(pinfo, 0);
623 snd_seq_port_info_set_timestamping(pinfo, 1);
624 snd_seq_port_info_set_timestamp_real(pinfo, 1);
625 snd_seq_port_info_set_timestamp_queue(pinfo, handle->queue);
626
627 snd_seq_create_port(handle->seq, pinfo);
628 chan->midi.port = snd_seq_port_info_get_port(pinfo);
629 if(chan->midi.port < 0)
630 bin_log_error(bin, "%s: could not create MIDI port\n", __func__);
631
632 snd_seq_port_info_free(pinfo);
633
634 if(snd_midi_event_new(MIDI_SEQ_SIZE, &chan->midi.trans))
635 bin_log_error(bin, "%s: could not create MIDI event translator\n", __func__);
636 snd_midi_event_init(chan->midi.trans);
637 if(input)
638 snd_midi_event_reset_encode(chan->midi.trans);
639 else
640 snd_midi_event_reset_decode(chan->midi.trans);
641 snd_midi_event_no_status(chan->midi.trans, 1);
642 }
643
644 break;
645 }
646 case SYSTEM_PORT_OSC:
647 {
648 // unsupported, skip
649 break;
650 }
651 case SYSTEM_PORT_COM:
652 {
653 // unsupported, skip
654 break;
655 }
656 }
657
658 return chan;
659 }
660
661 __non_realtime static void
_system_port_del(void * data,void * sys_port)662 _system_port_del(void *data, void *sys_port)
663 {
664 bin_t *bin = data;
665 prog_t *handle = (void *)bin - offsetof(prog_t, bin);
666
667 chan_t *chan = sys_port;
668
669 if(!chan)
670 return;
671
672 switch(chan->type)
673 {
674 case CHAN_TYPE_PCMI:
675 {
676 //TODO
677
678 break;
679 }
680 case CHAN_TYPE_MIDI:
681 {
682 snd_midi_event_free(chan->midi.trans);
683 if(handle->seq)
684 snd_seq_delete_simple_port(handle->seq, chan->midi.port);
685
686 break;
687 }
688 }
689
690 free(chan);
691 }
692
693 __non_realtime static void
_saved(bin_t * bin,int status)694 _saved(bin_t *bin, int status)
695 {
696 prog_t *handle = (void *)bin - offsetof(prog_t, bin);
697
698 if(handle->save_state == SAVE_STATE_NSM)
699 {
700 nsmc_saved(bin->nsm, status);
701 }
702 handle->save_state = SAVE_STATE_INTERNAL;
703
704 if(atomic_load_explicit(&handle->kill, memory_order_relaxed))
705 {
706 bin_quit(bin);
707 }
708 }
709
710 static int
_alsa_init(prog_t * handle,const char * id)711 _alsa_init(prog_t *handle, const char *id)
712 {
713 bin_t *bin = &handle->bin;
714
715 // init alsa sequencer
716 if(snd_seq_open(&handle->seq, "hw", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK))
717 bin_log_error(bin, "%s: could not open sequencer\n", __func__);
718 if(snd_seq_set_client_name(handle->seq, id))
719 bin_log_error(bin, "%s: could not set name\n", __func__);
720 handle->queue = snd_seq_alloc_queue(handle->seq);
721 if(handle->queue < 0)
722 bin_log_error(bin, "%s: could not allocate queue\n", __func__);
723 snd_seq_start_queue(handle->seq, handle->queue, NULL);
724
725 // init alsa pcm
726 handle->pcmi = pcmi_new(handle->play_name, handle->capt_name,
727 handle->srate, handle->frsize, handle->nfrags, handle->twochan, handle->debug);
728 if(!handle->pcmi)
729 return -1;
730 pcmi_printinfo(handle->pcmi);
731
732 return 0;
733 }
734
735 static void
_alsa_deinit(prog_t * handle)736 _alsa_deinit(prog_t *handle)
737 {
738 bin_t *bin = &handle->bin;
739
740 if(handle->thread)
741 {
742 atomic_store_explicit(&handle->kill, 1, memory_order_relaxed);
743 pthread_join(handle->thread, NULL);
744 }
745
746 if(handle->pcmi)
747 {
748 pcmi_free(handle->pcmi);
749
750 handle->pcmi = NULL;
751 }
752
753 if(handle->seq)
754 {
755 if(snd_seq_drain_output(handle->seq))
756 bin_log_error(bin, "%s: draining output failed\n", __func__);
757 snd_seq_stop_queue(handle->seq, handle->queue, NULL);
758 if(snd_seq_free_queue(handle->seq, handle->queue))
759 bin_log_error(bin, "%s: freeing queue failed\n", __func__);
760 if(snd_seq_close(handle->seq))
761 bin_log_error(bin, "%s: close sequencer failed\n", __func__);
762
763 handle->seq = NULL;
764 handle->queue = 0;
765 }
766 }
767
768 __non_realtime static int
_open(const char * path,const char * name,const char * id,void * data)769 _open(const char *path, const char *name, const char *id, void *data)
770 {
771 bin_t *bin = data;
772 prog_t *handle = (void *)bin - offsetof(prog_t, bin);
773 (void)name;
774
775 if(bin->path)
776 free(bin->path);
777 bin->path = strdup(path);
778
779 // alsa init
780 if(_alsa_init(handle, id))
781 {
782 nsmc_opened(bin->nsm, -1);
783 return -1;
784 }
785
786 // synthpod init
787 bin->app_driver.sample_rate = handle->srate;
788 bin->app_driver.update_rate = handle->bin.update_rate;
789 bin->app_driver.max_block_size = handle->frsize;
790 bin->app_driver.min_block_size = 1;
791 bin->app_driver.seq_size = handle->seq_size;
792 bin->app_driver.num_periods = handle->nfrags;
793
794 // app init
795 bin->app = sp_app_new(NULL, &bin->app_driver, bin);
796
797 // alsa activate
798 atomic_init(&handle->kill, 0);
799 if(pthread_create(&handle->thread, NULL, _rt_thread, handle))
800 bin_log_error(bin, "%s: creation of realtime thread failed\n", __func__);
801
802 bin_bundle_load(bin, bin->path);
803 nsmc_opened(bin->nsm, 0);
804
805 return 0; // success
806 }
807
808 __non_realtime static int
_save(void * data)809 _save(void *data)
810 {
811 bin_t *bin = data;
812 prog_t *handle = (void *)bin - offsetof(prog_t, bin);
813
814 handle->save_state = SAVE_STATE_NSM;
815 bin_bundle_save(bin, bin->path);
816 _saved(bin, 0);
817
818 return 0; // success
819 }
820
821 __non_realtime static int
_show(void * data)822 _show(void *data)
823 {
824 bin_t *bin = data;
825
826 return bin_show(bin);
827 }
828
829 __non_realtime static int
_hide(void * data)830 _hide(void *data)
831 {
832 bin_t *bin = data;
833
834 return bin_hide(bin);
835 }
836
837 static const nsmc_driver_t nsm_driver = {
838 .open = _open,
839 .save = _save,
840 .show = _show,
841 .hide = _hide
842 };
843
844 // rt
845 __realtime static double
_osc_schedule_osc2frames(LV2_OSC_Schedule_Handle instance,uint64_t timestamp)846 _osc_schedule_osc2frames(LV2_OSC_Schedule_Handle instance, uint64_t timestamp)
847 {
848 prog_t *handle = instance;
849
850 if(timestamp == 1ULL)
851 return 0; // inject at start of period
852
853 const uint64_t time_sec = timestamp >> 32;
854 const uint64_t time_frac = timestamp & 0xffffffff;
855
856 const double diff = (time_sec - handle->cur_ntp.tv_sec)
857 + time_frac * 0x1p-32
858 - handle->cur_ntp.tv_nsec * 1e-9;
859
860 const double frames = diff * handle->cycle.dT
861 - handle->cycle.ref_frames
862 + handle->cycle.cur_frames;
863
864 return frames;
865 }
866
867 // rt
868 __realtime static uint64_t
_osc_schedule_frames2osc(LV2_OSC_Schedule_Handle instance,double frames)869 _osc_schedule_frames2osc(LV2_OSC_Schedule_Handle instance, double frames)
870 {
871 prog_t *handle = instance;
872
873 double diff = (frames - handle->cycle.cur_frames + handle->cycle.ref_frames)
874 * handle->cycle.dTm1;
875 diff += handle->cur_ntp.tv_nsec * 1e-9;
876 diff += handle->cur_ntp.tv_sec;
877
878 double time_sec_d;
879 double time_frac_d = modf(diff, &time_sec_d);
880
881 uint64_t time_sec = time_sec_d;
882 uint64_t time_frac = time_frac_d * 0x1p32;
883 if(time_frac >= 0x100000000ULL) // illegal overflow
884 time_frac = 0xffffffffULL;
885
886 uint64_t timestamp = (time_sec << 32) | time_frac;
887
888 return timestamp;
889 }
890
891 int
main(int argc,char ** argv)892 main(int argc, char **argv)
893 {
894 mlockall(MCL_CURRENT | MCL_FUTURE);
895
896 static prog_t handle;
897 bin_t *bin = &handle.bin;
898
899 handle.srate = 48000;
900 handle.frsize = 1024;
901 handle.nfrags = 3;
902 handle.twochan = false;
903 handle.debug = false;
904 handle.do_play = true;
905 handle.do_capt = true;
906 handle.seq_size = SEQ_SIZE;
907
908 const char *def = "hw:0";
909 handle.io_name = def;
910 handle.play_name = NULL;
911 handle.capt_name = NULL;
912
913 bin->audio_prio = 70;
914 bin->worker_prio = 60;
915 bin->num_slaves = sysconf(_SC_NPROCESSORS_ONLN) - 1;
916 bin->bad_plugins = false;
917 bin->has_gui = false;
918 bin->kill_gui = false;
919 snprintf(bin->socket_path, sizeof(bin->socket_path), "shm:///synthpod-%i", getpid());
920 bin->update_rate = 25;
921 bin->cpu_affinity = false;
922
923 fprintf(stderr,
924 "Synthpod "SYNTHPOD_VERSION"\n"
925 "Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch)\n"
926 "Released under GNU General Public License 3 by Open Music Kontrollers\n");
927
928 // read local configuration if present
929 /*FIXME
930 Efreet_Ini *ini = _read_config(&handle);
931 */
932
933 int c;
934 while((c = getopt(argc, argv, "vhgGbkKBaAIOtTxXy:Yw:Wl:d:i:o:r:p:n:s:c:f:")) != -1)
935 {
936 switch(c)
937 {
938 case 'v':
939 fprintf(stderr,
940 "--------------------------------------------------------------------\n"
941 "This program is free software; you can redistribute it and/or modify\n"
942 "it under the terms of the GNU General Public License as published by\n"
943 "the Free Software Foundation; either version 3 of the License, or\n"
944 "(at your option) any later version.\n"
945 "\n"
946 "This program is distributed in the hope that it will be useful,\n"
947 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
948 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
949 "GNU General Public License for more details.\n"
950 "\n"
951 "You should have received a copy of the GNU General Public License\n"
952 "along with this program. If not, see http://www.gnu.org/licenses.\n\n");
953 return 0;
954 case 'h':
955 fprintf(stderr,
956 "--------------------------------------------------------------------\n"
957 "USAGE\n"
958 " %s [OPTIONS] [BUNDLE_PATH]\n"
959 "\n"
960 "OPTIONS\n"
961 " [-v] print version and full license information\n"
962 " [-h] print usage information\n"
963 " [-g] load GUI\n"
964 " [-G] do NOT load GUI (default)\n"
965 " [-k] kill DSP with GUI\n"
966 " [-K] do NOT kill DSP with GUI (default)\n"
967 " [-b] enable bad plugins\n"
968 " [-B] disable bad plugins (default)\n"
969 " [-a] enable CPU affinity\n"
970 " [-A] disable CPU affinity (default)\n"
971 " [-I] disable capture\n"
972 " [-O] disable playback\n"
973 " [-t] force 2 channel mode\n"
974 " [-T] do NOT force 2 channel mode (default)\n"
975 " [-x] notify about XRuns\n"
976 " [-X] do NOT notify about XRuns (default)\n"
977 " [-y] audio-priority audio thread realtime priority (70)\n"
978 " [-Y] do NOT use audio thread realtime priority\n"
979 " [-w] worker-priority worker thread realtime priority (60)\n"
980 " [-W] do NOT use worker thread realtime priority\n"
981 " [-l] link-path socket link path (shm:///synthpod)\n"
982 " [-d] device capture/playback device (\"hw:0\")\n"
983 " [-i] capture-device capture device (\"hw:0\")\n"
984 " [-o] playback-device playback device (\"hw:0\")\n"
985 " [-r] sample-rate sample rate (48000)\n"
986 " [-p] sample-period frames per period (1024)\n"
987 " [-n] period-number number of periods of playback latency (3)\n"
988 " [-s] sequence-size minimum sequence size (8192)\n"
989 " [-c] slave-cores number of slave cores (auto)\n"
990 " [-f] update-rate GUI update rate (25)\n\n"
991 , argv[0]);
992 return 0;
993 case 'g':
994 bin->has_gui = true;
995 break;
996 case 'G':
997 bin->has_gui = false;
998 break;
999 case 'k':
1000 bin->kill_gui = true;
1001 break;
1002 case 'K':
1003 bin->kill_gui = false;
1004 break;
1005 case 'b':
1006 bin->bad_plugins = true;
1007 break;
1008 case 'B':
1009 bin->bad_plugins = false;
1010 break;
1011 case 'a':
1012 bin->cpu_affinity = true;
1013 break;
1014 case 'A':
1015 bin->cpu_affinity = false;
1016 break;
1017 case 'I':
1018 handle.do_capt = false;
1019 break;
1020 case 'O':
1021 handle.do_play = false;
1022 break;
1023 case 't':
1024 handle.twochan = true;
1025 break;
1026 case 'T':
1027 handle.twochan = false;
1028 break;
1029 case 'x':
1030 handle.debug = true;
1031 break;
1032 case 'X':
1033 handle.debug = false;
1034 break;
1035 case 'y':
1036 bin->audio_prio = atoi(optarg);
1037 break;
1038 case 'Y':
1039 bin->audio_prio = 0;
1040 break;
1041 case 'w':
1042 bin->worker_prio = atoi(optarg);
1043 break;
1044 case 'W':
1045 bin->worker_prio = 0;
1046 break;
1047 case 'l':
1048 snprintf(bin->socket_path, sizeof(bin->socket_path), "%s", optarg);
1049 break;
1050 case 'd':
1051 handle.do_capt = optarg != NULL;
1052 handle.do_play = optarg != NULL;
1053 handle.io_name = optarg;
1054 break;
1055 case 'i':
1056 handle.do_capt = optarg != NULL;
1057 handle.capt_name = optarg;
1058 break;
1059 case 'o':
1060 handle.do_play = optarg != NULL;
1061 handle.play_name = optarg;
1062 break;
1063 case 'r':
1064 handle.srate = atoi(optarg);
1065 break;
1066 case 'p':
1067 handle.frsize = atoi(optarg);
1068 break;
1069 case 'n':
1070 handle.nfrags = atoi(optarg);
1071 break;
1072 case 's':
1073 handle.seq_size = MAX(SEQ_SIZE, atoi(optarg));
1074 break;
1075 case 'c':
1076 if(atoi(optarg) < bin->num_slaves)
1077 bin->num_slaves = atoi(optarg);
1078 break;
1079 case 'f':
1080 bin->update_rate = atoi(optarg);
1081 break;
1082 case '?':
1083 if( (optopt == 'd') || (optopt == 'i') || (optopt == 'o') || (optopt == 'r')
1084 || (optopt == 'p') || (optopt == 'n') || (optopt == 's') || (optopt == 'c')
1085 || (optopt == 'l') || (optopt == 'f') )
1086 fprintf(stderr, "Option `-%c' requires an argument.\n", optopt);
1087 else if(isprint(optopt))
1088 fprintf(stderr, "Unknown option `-%c'.\n", optopt);
1089 else
1090 fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
1091 return -1;
1092 default:
1093 return -1;
1094 }
1095 }
1096
1097 if(!handle.capt_name && handle.do_capt)
1098 handle.capt_name = handle.io_name;
1099 if(!handle.play_name && handle.do_play)
1100 handle.play_name = handle.io_name;
1101
1102 bin_init(bin, handle.srate);
1103
1104 LV2_URID_Map *map = bin->map;
1105
1106 lv2_atom_forge_init(&handle.forge, map);
1107
1108 handle.midi_MidiEvent = map->map(map->handle, LV2_MIDI__MidiEvent);
1109
1110 bin->app_driver.system_port_add = _system_port_add;
1111 bin->app_driver.system_port_del = _system_port_del;
1112
1113 handle.osc_sched.osc2frames = _osc_schedule_osc2frames;
1114 handle.osc_sched.frames2osc = _osc_schedule_frames2osc;
1115 handle.osc_sched.handle = &handle;
1116 bin->app_driver.osc_sched = &handle.osc_sched;
1117 bin->app_driver.features = SP_APP_FEATURE_FIXED_BLOCK_LENGTH; // always true for ALSA
1118 if(handle.frsize && !(handle.frsize & (handle.frsize - 1))) // check for powerOf2
1119 bin->app_driver.features |= SP_APP_FEATURE_POWER_OF_2_BLOCK_LENGTH;
1120
1121 // run
1122 bin_run(bin, argv, &nsm_driver, NULL, NULL);
1123
1124 // stop
1125 bin_stop(bin);
1126
1127 // deinit alsa
1128 _alsa_deinit(&handle);
1129
1130 // deinit
1131 bin_deinit(bin);
1132
1133 /*FIXME
1134 if(ini)
1135 efreet_ini_free(ini);
1136 */
1137
1138 munlockall();
1139
1140 return 0;
1141 }
1142