1 --- audacity-Audacity-2.3.2/lib-src/portmidi/porttime/ptlinux.c
2 +++ audacity-Audacity-2.3.2/lib-src/portmidi/porttime/ptlinux.c
3 @@ -31,14 +31,13 @@ CHANGE LOG
6 #include "sys/resource.h"
7 -#include "sys/timeb.h"
13 static int time_started_flag = FALSE;
14 -static struct timeb time_offset = {0, 0, 0, 0};
15 +static struct timespec time_offset = {0, 0};
16 static pthread_t pt_thread_pid;
17 static int pt_thread_created = FALSE;
19 @@ -79,7 +78,7 @@ static void *Pt_CallbackProc(void *p)
20 PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
22 if (time_started_flag) return ptNoError;
23 - ftime(&time_offset); /* need this set before process runs */
24 + clock_gettime(CLOCK_MONOTONIC, &time_offset); /* need this set before process runs */
27 pt_callback_parameters *parms = (pt_callback_parameters *)
28 @@ -120,12 +119,12 @@ int Pt_Started()
32 - long seconds, milliseconds;
35 - seconds = now.time - time_offset.time;
36 - milliseconds = now.millitm - time_offset.millitm;
37 - return seconds * 1000 + milliseconds;
38 + long seconds, nanoseconds;
39 + struct timespec now;
40 + clock_gettime(CLOCK_MONOTONIC, &now);
41 + seconds = now.tv_sec - time_offset.tv_sec;
42 + nanoseconds = now.tv_nsec - time_offset.tv_nsec;
43 + return seconds * 1000 + nanoseconds / 1000000;
47 --- audacity-Audacity-2.3.2/lib-src/portmidi/Makefile.am.~1~ 2019-05-04 13:38:57.000000000 +0000
48 +++ audacity-Audacity-2.3.2/lib-src/portmidi/Makefile.am 2019-08-13 14:04:41.370862823 +0000
50 libportmidi_s_a_SOURCES = pm_common/portmidi.c \
53 - pm_linux/pmlinuxalsa.c \
54 - pm_linux/pmlinux.c \
55 - pm_linux/finddefault.c
56 + pm_linux/pmlinuxalsa.c
58 # and the header files for the library. At the moment these go into the include
59 # directory directly, it would be much better to have them in a subdirectory
60 --- audacity-Audacity-2.3.2/lib-src/portmidi/pm_linux/pmlinuxalsa.c.~1~ 2019-05-04 13:38:57.000000000 +0000
61 +++ audacity-Audacity-2.3.2/lib-src/portmidi/pm_linux/pmlinuxalsa.c 2019-08-13 14:18:53.991304730 +0000
66 -#include <alsa/asoundlib.h>
68 -/* I used many print statements to debug this code. I left them in the
69 - * source, and you can turn them on by changing false to true below:
72 -#define VERBOSE if (VERBOSE_ON)
74 -#define MIDI_SYSEX 0xf0
75 -#define MIDI_EOX 0xf7
77 -#if SND_LIB_MAJOR == 0 && SND_LIB_MINOR < 9
78 -#error needs ALSA 0.9.0 or later
81 -/* to store client/port in the device descriptor */
82 -#define MAKE_DESCRIPTOR(client, port) ((void*)(((client) << 8) | (port)))
83 -#define GET_DESCRIPTOR_CLIENT(info) ((((int)(info)) >> 8) & 0xff)
84 -#define GET_DESCRIPTOR_PORT(info) (((int)(info)) & 0xff)
86 -#define BYTE unsigned char
87 +PmDeviceID pm_default_input_device_id = -1;
88 +PmDeviceID pm_default_output_device_id = -1;
90 extern pm_fns_node pm_linuxalsa_in_dictionary;
91 extern pm_fns_node pm_linuxalsa_out_dictionary;
93 -static snd_seq_t *seq = NULL; // all input comes here,
94 - // output queue allocated on seq
95 -static int queue, queue_used; /* one for all ports, reference counted */
97 -typedef struct alsa_descriptor_struct {
102 - snd_midi_event_t *parser;
103 - int error; /* host error code */
104 -} alsa_descriptor_node, *alsa_descriptor_type;
107 -/* get_alsa_error_text -- copy error text to potentially short string */
109 -static void get_alsa_error_text(char *msg, int len, int err)
111 - int errlen = strlen(snd_strerror(err));
112 - if (errlen < len) {
113 - strcpy(msg, snd_strerror(err));
114 - } else if (len > 20) {
115 - sprintf(msg, "Alsa error %d", err);
116 - } else if (len > 4) {
117 - strcpy(msg, "Alsa");
124 -/* queue is shared by both input and output, reference counted */
125 -static PmError alsa_use_queue(void)
127 - if (queue_used == 0) {
128 - snd_seq_queue_tempo_t *tempo;
130 - queue = snd_seq_alloc_queue(seq);
132 - pm_hosterror = queue;
133 - return pmHostError;
135 - snd_seq_queue_tempo_alloca(&tempo);
136 - snd_seq_queue_tempo_set_tempo(tempo, 480000);
137 - snd_seq_queue_tempo_set_ppq(tempo, 480);
138 - pm_hosterror = snd_seq_set_queue_tempo(seq, queue, tempo);
139 - if (pm_hosterror < 0)
140 - return pmHostError;
142 - snd_seq_start_queue(seq, queue, NULL);
143 - snd_seq_drain_output(seq);
150 -static void alsa_unuse_queue(void)
153 - if (--queue_used == 0) {
154 - snd_seq_stop_queue(seq, queue, NULL);
155 - snd_seq_drain_output(seq);
156 - snd_seq_free_queue(seq, queue);
157 - VERBOSE printf("queue freed\n");
162 -/* midi_message_length -- how many bytes in a message? */
163 -static int midi_message_length(PmMessage message)
167 - if (message < 0x80) {
169 - } else if (message < 0xf0) {
170 - static const int length[] = {3, 3, 3, 3, 2, 2, 3};
171 - return length[(message - 0x80) >> 4];
173 - static const int length[] = {
174 - -1, 2, 3, 2, 0, 0, 1, -1, 1, 0, 1, 1, 1, 0, 1, 1};
175 - return length[message - 0xf0];
180 -static PmError alsa_out_open(PmInternal *midi, void *driverInfo)
182 - void *client_port = descriptors[midi->device_id].descriptor;
183 - alsa_descriptor_type desc = (alsa_descriptor_type)
184 - pm_alloc(sizeof(alsa_descriptor_node));
185 - snd_seq_port_info_t *info;
188 - if (!desc) return pmInsufficientMemory;
190 - snd_seq_port_info_alloca(&info);
191 - snd_seq_port_info_set_port(info, midi->device_id);
192 - snd_seq_port_info_set_capability(info, SND_SEQ_PORT_CAP_WRITE |
193 - SND_SEQ_PORT_CAP_READ);
194 - snd_seq_port_info_set_type(info, SND_SEQ_PORT_TYPE_MIDI_GENERIC |
195 - SND_SEQ_PORT_TYPE_APPLICATION);
196 - snd_seq_port_info_set_port_specified(info, 1);
197 - err = snd_seq_create_port(seq, info);
198 - if (err < 0) goto free_desc;
200 - /* fill in fields of desc, which is passed to pm_write routines */
201 - midi->descriptor = desc;
202 - desc->client = GET_DESCRIPTOR_CLIENT(client_port);
203 - desc->port = GET_DESCRIPTOR_PORT(client_port);
204 - desc->this_port = midi->device_id;
205 - desc->in_sysex = 0;
209 - err = snd_midi_event_new(PM_DEFAULT_SYSEX_BUFFER_SIZE, &desc->parser);
210 - if (err < 0) goto free_this_port;
212 - if (midi->latency > 0) { /* must delay output using a queue */
213 - err = alsa_use_queue();
214 - if (err < 0) goto free_parser;
216 - err = snd_seq_connect_to(seq, desc->this_port, desc->client, desc->port);
217 - if (err < 0) goto unuse_queue; /* clean up and return on error */
219 - err = snd_seq_connect_to(seq, desc->this_port, desc->client, desc->port);
220 - if (err < 0) goto free_parser; /* clean up and return on error */
225 - alsa_unuse_queue();
227 - snd_midi_event_free(desc->parser);
229 - snd_seq_delete_port(seq, desc->this_port);
232 - pm_hosterror = err;
234 - get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, err);
236 - return pmHostError;
237 +PmDeviceID Pm_GetDefaultInputDeviceID() {
239 + return pm_default_input_device_id;
243 -static PmError alsa_write_byte(PmInternal *midi, unsigned char byte,
244 - PmTimestamp timestamp)
246 - alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor;
247 - snd_seq_event_t ev;
250 - snd_seq_ev_clear(&ev);
251 - if (snd_midi_event_encode_byte(desc->parser, byte, &ev) == 1) {
252 - snd_seq_ev_set_dest(&ev, desc->client, desc->port);
253 - snd_seq_ev_set_source(&ev, desc->this_port);
254 - if (midi->latency > 0) {
255 - /* compute relative time of event = timestamp - now + latency */
256 - PmTimestamp now = (midi->time_proc ?
257 - midi->time_proc(midi->time_info) :
259 - int when = timestamp;
260 - /* if timestamp is zero, send immediately */
261 - /* otherwise compute time delay and use delay if positive */
262 - if (when == 0) when = now;
263 - when = (when - now) + midi->latency;
264 - if (when < 0) when = 0;
265 - VERBOSE printf("timestamp %d now %d latency %d, ",
266 - (int) timestamp, (int) now, midi->latency);
267 - VERBOSE printf("scheduling event after %d\n", when);
268 - /* message is sent in relative ticks, where 1 tick = 1 ms */
269 - snd_seq_ev_schedule_tick(&ev, queue, 1, when);
270 - /* NOTE: for cases where the user does not supply a time function,
271 - we could optimize the code by not starting Pt_Time and using
272 - the alsa tick time instead. I didn't do this because it would
273 - entail changing the queue management to start the queue tick
274 - count when PortMidi is initialized and keep it running until
275 - PortMidi is terminated. (This should be simple, but it's not
276 - how the code works now.) -RBD */
277 - } else { /* send event out without queueing */
278 - VERBOSE printf("direct\n");
279 - /* ev.queue = SND_SEQ_QUEUE_DIRECT;
280 - ev.dest.client = SND_SEQ_ADDRESS_SUBSCRIBERS; */
281 - snd_seq_ev_set_direct(&ev);
283 - VERBOSE printf("sending event\n");
284 - err = snd_seq_event_output(seq, &ev);
287 - return pmHostError;
291 +PmDeviceID Pm_GetDefaultOutputDeviceID() {
293 + return pm_default_output_device_id;
297 -static PmError alsa_out_close(PmInternal *midi)
299 - alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor;
300 - if (!desc) return pmBadPtr;
302 - if ((pm_hosterror = snd_seq_disconnect_to(seq, desc->this_port,
303 - desc->client, desc->port))) {
304 - // if there's an error, try to delete the port anyway, but don't
305 - // change the pm_hosterror value so we retain the first error
306 - snd_seq_delete_port(seq, desc->this_port);
307 - } else { // if there's no error, delete the port and retain any error
308 - pm_hosterror = snd_seq_delete_port(seq, desc->this_port);
310 - if (midi->latency > 0) alsa_unuse_queue();
311 - snd_midi_event_free(desc->parser);
312 - midi->descriptor = NULL; /* destroy the pointer to signify "closed" */
314 - if (pm_hosterror) {
315 - get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN,
317 - return pmHostError;
319 +static PmError none_out_open(PmInternal *midi, void *driverInfo) {
324 -static PmError alsa_in_open(PmInternal *midi, void *driverInfo)
325 +static PmError none_abort(PmInternal *midi)
327 - void *client_port = descriptors[midi->device_id].descriptor;
328 - alsa_descriptor_type desc = (alsa_descriptor_type)
329 - pm_alloc(sizeof(alsa_descriptor_node));
330 - snd_seq_port_info_t *info;
331 - snd_seq_port_subscribe_t *sub;
332 - snd_seq_addr_t addr;
335 - if (!desc) return pmInsufficientMemory;
337 - err = alsa_use_queue();
338 - if (err < 0) goto free_desc;
340 - snd_seq_port_info_alloca(&info);
341 - snd_seq_port_info_set_port(info, midi->device_id);
342 - snd_seq_port_info_set_capability(info, SND_SEQ_PORT_CAP_WRITE |
343 - SND_SEQ_PORT_CAP_READ);
344 - snd_seq_port_info_set_type(info, SND_SEQ_PORT_TYPE_MIDI_GENERIC |
345 - SND_SEQ_PORT_TYPE_APPLICATION);
346 - snd_seq_port_info_set_port_specified(info, 1);
347 - err = snd_seq_create_port(seq, info);
348 - if (err < 0) goto free_queue;
350 - /* fill in fields of desc, which is passed to pm_write routines */
351 - midi->descriptor = desc;
352 - desc->client = GET_DESCRIPTOR_CLIENT(client_port);
353 - desc->port = GET_DESCRIPTOR_PORT(client_port);
354 - desc->this_port = midi->device_id;
355 - desc->in_sysex = 0;
359 - VERBOSE printf("snd_seq_connect_from: %d %d %d\n",
360 - desc->this_port, desc->client, desc->port);
361 - snd_seq_port_subscribe_alloca(&sub);
362 - addr.client = snd_seq_client_id(seq);
363 - addr.port = desc->this_port;
364 - snd_seq_port_subscribe_set_dest(sub, &addr);
365 - addr.client = desc->client;
366 - addr.port = desc->port;
367 - snd_seq_port_subscribe_set_sender(sub, &addr);
368 - snd_seq_port_subscribe_set_time_update(sub, 1);
369 - /* this doesn't seem to work: messages come in with real timestamps */
370 - snd_seq_port_subscribe_set_time_real(sub, 0);
371 - err = snd_seq_subscribe_port(seq, sub);
373 - snd_seq_connect_from(seq, desc->this_port, desc->client, desc->port); */
374 - if (err < 0) goto free_this_port; /* clean up and return on error */
378 - snd_seq_delete_port(seq, desc->this_port);
380 - alsa_unuse_queue();
383 - pm_hosterror = err;
385 - get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, err);
387 - return pmHostError;
390 -static PmError alsa_in_close(PmInternal *midi)
391 +static PmError none_out_close(PmInternal *midi)
393 - alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor;
394 - if (!desc) return pmBadPtr;
395 - if ((pm_hosterror = snd_seq_disconnect_from(seq, desc->this_port,
396 - desc->client, desc->port))) {
397 - snd_seq_delete_port(seq, desc->this_port); /* try to close port */
399 - pm_hosterror = snd_seq_delete_port(seq, desc->this_port);
401 - alsa_unuse_queue();
402 - midi->descriptor = NULL;
404 - if (pm_hosterror) {
405 - get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN,
407 - return pmHostError;
413 -static PmError alsa_abort(PmInternal *midi)
414 +static unsigned int none_has_host_error(PmInternal *midi)
416 - /* NOTE: ALSA documentation is vague. This is supposed to
417 - * remove any pending output messages. If you can test and
418 - * confirm this code is correct, please update this comment. -RBD
420 - /* Unfortunately, I can't even compile it -- my ALSA version
421 - * does not implement snd_seq_remove_events_t, so this does
422 - * not compile. I'll try again, but it looks like I'll need to
423 - * upgrade my entire Linux OS -RBD
426 - alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor;
427 - snd_seq_remove_events_t info;
428 - snd_seq_addr_t addr;
429 - addr.client = desc->client;
430 - addr.port = desc->port;
431 - snd_seq_remove_events_set_dest(&info, &addr);
432 - snd_seq_remove_events_set_condition(&info, SND_SEQ_REMOVE_DEST);
433 - pm_hosterror = snd_seq_remove_events(seq, &info);
434 - if (pm_hosterror) {
435 - get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN,
437 - return pmHostError;
440 - printf("WARNING: alsa_abort not implemented\n");
447 -This is old code here temporarily for reference
448 -static PmError alsa_write(PmInternal *midi, PmEvent *buffer, int32_t length)
449 +static void none_get_host_error(PmInternal *midi, char *msg, unsigned int len)
451 - alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor;
453 - unsigned char byte;
457 - for (; length > 0; length--, buffer++) {
458 - VERBOSE printf("message 0x%x\n", buffer->message);
459 - if (Pm_MessageStatus(buffer->message) == MIDI_SYSEX)
460 - desc->in_sysex = TRUE;
461 - if (desc->in_sysex) {
462 - msg = buffer->message;
463 - for (i = 0; i < 4; i++) {
464 - byte = msg; /* extract next byte to send */
465 - alsa_write_byte(midi, byte, buffer->timestamp);
466 - if (byte == MIDI_EOX) {
467 - desc->in_sysex = FALSE;
470 - if (desc->error < 0) break;
471 - msg >>= 8; /* shift next byte into position */
474 - bytes = midi_message_length(buffer->message);
475 - msg = buffer->message;
476 - for (i = 0; i < bytes; i++) {
477 - byte = msg; /* extract next byte to send */
478 - VERBOSE printf("sending 0x%x\n", byte);
479 - alsa_write_byte(midi, byte, buffer->timestamp);
480 - if (desc->error < 0) break;
481 - msg >>= 8; /* shift next byte into position */
485 - if (desc->error < 0) return pmHostError;
487 - VERBOSE printf("snd_seq_drain_output: 0x%x\n", (unsigned int) seq);
488 - desc->error = snd_seq_drain_output(seq);
489 - if (desc->error < 0) return pmHostError;
491 - desc->error = pmNoError;
497 -static PmError alsa_write_flush(PmInternal *midi, PmTimestamp timestamp)
499 - alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor;
500 - if (!desc) return pmBadPtr;
501 - VERBOSE printf("snd_seq_drain_output: 0x%x\n", (unsigned int) seq);
502 - desc->error = snd_seq_drain_output(seq);
503 - if (desc->error < 0) return pmHostError;
505 - desc->error = pmNoError;
508 +void *pm_alloc(size_t s) { return malloc(s); }
510 +void pm_free(void *ptr) { free(ptr); }
512 -static PmError alsa_write_short(PmInternal *midi, PmEvent *event)
514 - int bytes = midi_message_length(event->message);
515 - PmMessage msg = event->message;
517 - alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor;
518 - if (!desc) return pmBadPtr;
519 - for (i = 0; i < bytes; i++) {
520 - unsigned char byte = msg;
521 - VERBOSE printf("sending 0x%x\n", byte);
522 - alsa_write_byte(midi, byte, event->timestamp);
523 - if (desc->error < 0) break;
524 - msg >>= 8; /* shift next byte into position */
526 - if (desc->error < 0) return pmHostError;
527 - desc->error = pmNoError;
532 -/* alsa_sysex -- implements begin_sysex and end_sysex */
533 -PmError alsa_sysex(PmInternal *midi, PmTimestamp timestamp) {
538 -static PmTimestamp alsa_synchronize(PmInternal *midi)
540 - return 0; /* linux implementation does not use this synchronize function */
541 - /* Apparently, Alsa data is relative to the time you send it, and there
542 - is no reference. If this is true, this is a serious shortcoming of
543 - Alsa. If not true, then PortMidi has a serious shortcoming -- it
544 - should be scheduling relative to Alsa's time reference. */
548 -static void handle_event(snd_seq_event_t *ev)
550 - int device_id = ev->dest.port;
551 - PmInternal *midi = descriptors[device_id].internalDescriptor;
552 - // There is a race condition when closing a device and
553 - // continuing to poll other open devices. The closed device may
554 - // have outstanding events from before the close operation.
559 - PmTimeProcPtr time_proc = midi->time_proc;
560 - PmTimestamp timestamp;
562 - /* time stamp should be in ticks, using our queue where 1 tick = 1ms */
563 - assert((ev->flags & SND_SEQ_TIME_STAMP_MASK) == SND_SEQ_TIME_STAMP_TICK);
565 - /* if no time_proc, just return "native" ticks (ms) */
566 - if (time_proc == NULL) {
567 - timestamp = ev->time.tick;
568 - } else { /* translate time to time_proc basis */
569 - snd_seq_queue_status_t *queue_status;
570 - snd_seq_queue_status_alloca(&queue_status);
571 - snd_seq_get_queue_status(seq, queue, queue_status);
572 - /* return (now - alsa_now) + alsa_timestamp */
573 - timestamp = (*time_proc)(midi->time_info) + ev->time.tick -
574 - snd_seq_queue_status_get_tick_time(queue_status);
576 - pm_ev.timestamp = timestamp;
577 - switch (ev->type) {
578 - case SND_SEQ_EVENT_NOTEON:
579 - pm_ev.message = Pm_Message(0x90 | ev->data.note.channel,
580 - ev->data.note.note & 0x7f,
581 - ev->data.note.velocity & 0x7f);
582 - pm_read_short(midi, &pm_ev);
584 - case SND_SEQ_EVENT_NOTEOFF:
585 - pm_ev.message = Pm_Message(0x80 | ev->data.note.channel,
586 - ev->data.note.note & 0x7f,
587 - ev->data.note.velocity & 0x7f);
588 - pm_read_short(midi, &pm_ev);
590 - case SND_SEQ_EVENT_KEYPRESS:
591 - pm_ev.message = Pm_Message(0xa0 | ev->data.note.channel,
592 - ev->data.note.note & 0x7f,
593 - ev->data.note.velocity & 0x7f);
594 - pm_read_short(midi, &pm_ev);
596 - case SND_SEQ_EVENT_CONTROLLER:
597 - pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel,
598 - ev->data.control.param & 0x7f,
599 - ev->data.control.value & 0x7f);
600 - pm_read_short(midi, &pm_ev);
602 - case SND_SEQ_EVENT_PGMCHANGE:
603 - pm_ev.message = Pm_Message(0xc0 | ev->data.note.channel,
604 - ev->data.control.value & 0x7f, 0);
605 - pm_read_short(midi, &pm_ev);
607 - case SND_SEQ_EVENT_CHANPRESS:
608 - pm_ev.message = Pm_Message(0xd0 | ev->data.note.channel,
609 - ev->data.control.value & 0x7f, 0);
610 - pm_read_short(midi, &pm_ev);
612 - case SND_SEQ_EVENT_PITCHBEND:
613 - pm_ev.message = Pm_Message(0xe0 | ev->data.note.channel,
614 - (ev->data.control.value + 0x2000) & 0x7f,
615 - ((ev->data.control.value + 0x2000) >> 7) & 0x7f);
616 - pm_read_short(midi, &pm_ev);
618 - case SND_SEQ_EVENT_CONTROL14:
619 - if (ev->data.control.param < 0x20) {
620 - pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel,
621 - ev->data.control.param,
622 - (ev->data.control.value >> 7) & 0x7f);
623 - pm_read_short(midi, &pm_ev);
624 - pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel,
625 - ev->data.control.param + 0x20,
626 - ev->data.control.value & 0x7f);
627 - pm_read_short(midi, &pm_ev);
629 - pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel,
630 - ev->data.control.param & 0x7f,
631 - ev->data.control.value & 0x7f);
633 - pm_read_short(midi, &pm_ev);
636 - case SND_SEQ_EVENT_SONGPOS:
637 - pm_ev.message = Pm_Message(0xf2,
638 - ev->data.control.value & 0x7f,
639 - (ev->data.control.value >> 7) & 0x7f);
640 - pm_read_short(midi, &pm_ev);
642 - case SND_SEQ_EVENT_SONGSEL:
643 - pm_ev.message = Pm_Message(0xf3,
644 - ev->data.control.value & 0x7f, 0);
645 - pm_read_short(midi, &pm_ev);
647 - case SND_SEQ_EVENT_QFRAME:
648 - pm_ev.message = Pm_Message(0xf1,
649 - ev->data.control.value & 0x7f, 0);
650 - pm_read_short(midi, &pm_ev);
652 - case SND_SEQ_EVENT_START:
653 - pm_ev.message = Pm_Message(0xfa, 0, 0);
654 - pm_read_short(midi, &pm_ev);
656 - case SND_SEQ_EVENT_CONTINUE:
657 - pm_ev.message = Pm_Message(0xfb, 0, 0);
658 - pm_read_short(midi, &pm_ev);
660 - case SND_SEQ_EVENT_STOP:
661 - pm_ev.message = Pm_Message(0xfc, 0, 0);
662 - pm_read_short(midi, &pm_ev);
664 - case SND_SEQ_EVENT_CLOCK:
665 - pm_ev.message = Pm_Message(0xf8, 0, 0);
666 - pm_read_short(midi, &pm_ev);
668 - case SND_SEQ_EVENT_TUNE_REQUEST:
669 - pm_ev.message = Pm_Message(0xf6, 0, 0);
670 - pm_read_short(midi, &pm_ev);
672 - case SND_SEQ_EVENT_RESET:
673 - pm_ev.message = Pm_Message(0xff, 0, 0);
674 - pm_read_short(midi, &pm_ev);
676 - case SND_SEQ_EVENT_SENSING:
677 - pm_ev.message = Pm_Message(0xfe, 0, 0);
678 - pm_read_short(midi, &pm_ev);
680 - case SND_SEQ_EVENT_SYSEX: {
681 - const BYTE *ptr = (const BYTE *) ev->data.ext.ptr;
682 - /* assume there is one sysex byte to process */
683 - pm_read_bytes(midi, ptr, ev->data.ext.len, timestamp);
690 -static PmError alsa_poll(PmInternal *midi)
692 - snd_seq_event_t *ev;
693 - /* expensive check for input data, gets data from device: */
694 - while (snd_seq_event_input_pending(seq, TRUE) > 0) {
695 - /* cheap check on local input buffer */
696 - while (snd_seq_event_input_pending(seq, FALSE) > 0) {
697 - /* check for and ignore errors, e.g. input overflow */
698 - /* note: if there's overflow, this should be reported
699 - * all the way through to client. Since input from all
700 - * devices is merged, we need to find all input devices
701 - * and set all to the overflow state.
702 - * NOTE: this assumes every input is ALSA based.
704 - int rslt = snd_seq_event_input(seq, &ev);
707 - } else if (rslt == -ENOSPC) {
709 - for (i = 0; i < pm_descriptor_index; i++) {
710 - if (descriptors[i].pub.input) {
711 - PmInternal *midi = (PmInternal *)
712 - descriptors[i].internalDescriptor;
713 - /* careful, device may not be open! */
714 - if (midi) Pm_SetOverflow(midi->queue);
724 -static unsigned int alsa_has_host_error(PmInternal *midi)
726 - alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor;
727 - if (!desc) return 0;
728 - return desc->error;
732 -static void alsa_get_host_error(PmInternal *midi, char *msg, unsigned int len)
734 - alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor;
736 - int err = (pm_hosterror || desc->error);
737 - get_alsa_error_text(msg, len, err);
741 -pm_fns_node pm_linuxalsa_in_dictionary = {
742 +pm_fns_node pm_linuxalsa_out_dictionary = {
748 + none_write_short, /* short realtime message */
755 - alsa_has_host_error,
756 - alsa_get_host_error
759 -pm_fns_node pm_linuxalsa_out_dictionary = {
764 - alsa_write_short, /* short realtime message */
775 - alsa_has_host_error,
776 - alsa_get_host_error
777 + none_has_host_error,
778 + none_get_host_error
788 -PmError pm_linuxalsa_init( void )
791 - snd_seq_client_info_t *cinfo;
792 - snd_seq_port_info_t *pinfo;
795 - /* Previously, the last parameter was SND_SEQ_NONBLOCK, but this
796 - * would cause messages to be dropped if the ALSA buffer fills up.
797 - * The correct behavior is for writes to block until there is
798 - * room to send all the data. The client should normally allocate
799 - * a large enough buffer to avoid blocking on output.
800 - * Now that blocking is enabled, the seq_event_input() will block
801 - * if there is no input data. This is not what we want, so must
802 - * call seq_event_input_pending() to avoid blocking.
804 - err = snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, 0);
805 - if (err < 0) return err;
807 - snd_seq_client_info_alloca(&cinfo);
808 - snd_seq_port_info_alloca(&pinfo);
810 - snd_seq_client_info_set_client(cinfo, -1);
811 - while (snd_seq_query_next_client(seq, cinfo) == 0) {
812 - snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo));
813 - snd_seq_port_info_set_port(pinfo, -1);
814 - while (snd_seq_query_next_port(seq, pinfo) == 0) {
815 - if (snd_seq_port_info_get_client(pinfo) == SND_SEQ_CLIENT_SYSTEM)
816 - continue; /* ignore Timer and Announce ports on client 0 */
817 - caps = snd_seq_port_info_get_capability(pinfo);
818 - if (!(caps & (SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_SUBS_WRITE)))
819 - continue; /* ignore if you cannot read or write port */
820 - if (caps & SND_SEQ_PORT_CAP_SUBS_WRITE) {
821 - if (pm_default_output_device_id == -1)
822 - pm_default_output_device_id = pm_descriptor_index;
823 - pm_add_device("ALSA",
824 - pm_strdup(snd_seq_port_info_get_name(pinfo)),
826 - MAKE_DESCRIPTOR(snd_seq_port_info_get_client(pinfo),
827 - snd_seq_port_info_get_port(pinfo)),
828 - &pm_linuxalsa_out_dictionary);
830 - if (caps & SND_SEQ_PORT_CAP_SUBS_READ) {
831 - if (pm_default_input_device_id == -1)
832 - pm_default_input_device_id = pm_descriptor_index;
833 - pm_add_device("ALSA",
834 - pm_strdup(snd_seq_port_info_get_name(pinfo)),
836 - MAKE_DESCRIPTOR(snd_seq_port_info_get_client(pinfo),
837 - snd_seq_port_info_get_port(pinfo)),
838 - &pm_linuxalsa_in_dictionary);
846 -void pm_linuxalsa_term(void)
849 - snd_seq_close(seq);
850 - pm_free(descriptors);
851 - descriptors = NULL;
852 - pm_descriptor_index = 0;
853 - pm_descriptor_max = 0;