return snd_seq_remove_events(seq, &rmp);
}
+/**
+ * \brief drain output queue
+ * \param seq sequencer handle
+ * \return 0 on success or negative error code
+ */
+int snd_seq_sync_output_queue(snd_seq_t *seq)
+{
+ int err;
+ snd_seq_client_pool_t info;
+ int saved_room;
+ struct pollfd pfd;
+
+ assert(seq);
+ /* reprogram the room size to full */
+ if ((err = snd_seq_get_client_pool(seq, &info)) < 0)
+ return err;
+ saved_room = info.output_room;
+ info.output_room = info.output_pool; /* wait until all gone */
+ if ((err = snd_seq_set_client_pool(seq, &info)) < 0)
+ return err;
+ /* wait until all events are purged */
+ pfd.fd = seq->poll_fd;
+ pfd.events = POLLOUT;
+ err = poll(&pfd, 1, -1);
+ /* restore the room size */
+ info.output_room = saved_room;
+ snd_seq_set_client_pool(seq, &info);
+ return err;
+}
+
/**
* \brief parse the given string and get the sequencer address
* \param seq sequencer handle
* \param addr the address pointer to be returned
* \param arg the string to be parsed
* \return 0 on success or negative error code
+ *
+ * This function parses the sequencer client and port numbers from the given string.
+ * The client and port tokes are separated by either colon or period, e.g. 128:1.
+ * When \a seq is not NULL, the function accepts also a client name not only
+ * digit numbers.
*/
int snd_seq_parse_address(snd_seq_t *seq, snd_seq_addr_t *addr, const char *arg)
{
int client, port;
int len;
- assert(seq && addr && arg);
+ assert(addr && arg);
if ((p = strpbrk(arg, ":.")) != NULL) {
if ((port = atoi(p + 1)) < 0)
/* convert from the name */
snd_seq_client_info_t cinfo;
+ if (! seq)
+ return -EINVAL;
*p = 0;
if (len <= 0)
return -EINVAL;
}
/* print out text */
-static void mytext(int type, int leng, char *msg)
+static void mytext(int type ATTRIBUTE_UNUSED, int leng, char *msg)
{
char *p;
char *ep = msg + leng;
/* synchronize to the end of event */
static void alsa_sync(void)
{
- int left;
- snd_seq_event_t *input_event;
- snd_seq_event_t ev;
-
/* send echo event to self client. */
if (verbose >= VERB_MUCH)
- printf("alsa_sync syncing... send ECHO(%d) event to myself. time=%f\n",
- SND_SEQ_EVENT_ECHO, (double) Mf_currtime+1);
- snd_seq_ev_clear(&ev);
- /* redirect to itself */
- snd_seq_ev_set_dest(&ev, snd_seq_client_id(seq_handle), my_port);
- snd_seq_ev_set_source(&ev, my_port);
- set_event_time(&ev, Mf_currtime+1);
- ev.type = SND_SEQ_EVENT_ECHO;
- write_ev(&ev);
-
+ printf("alsa_sync syncing...\n");
/* dump buffer */
- left = snd_seq_drain_output(seq_handle);
-
- /* wait for the timer start event */
- for (;;) {
- input_event = wait_for_event();
- if (input_event) {
- if (verbose >= VERB_MUCH)
- printf("alsa_sync got event. type=%d, flags=%d\n",
- input_event->type, input_event->flags);
- if (input_event->type == SND_SEQ_EVENT_ECHO &&
- input_event->source.client == snd_seq_client_id(seq_handle)) {
- snd_seq_free_event(input_event);
- break;
- }
- snd_seq_free_event(input_event);
- }
- }
+ snd_seq_drain_output(seq_handle);
+ snd_seq_sync_output_queue(seq_handle);
if (verbose >= VERB_MUCH)
printf("alsa_sync synced\n");
+ sleep(1); /* give a time for note releasing.. */
}
fprintf(stderr, " -b : play on non-blocking mode\n");
}
-/* parse destination address (-a option) */
-void parse_address(char *arg, int *clientp, int *portp)
-{
- char *next;
-
- *clientp = atoi(arg);
- if ((next = strchr(arg, ':')) != NULL)
- *portp = atoi(next + 1);
-}
-
int main(int argc, char *argv[])
{
int tmp;
int c;
+ snd_seq_addr_t dest_addr;
+ const char *addr = NULL;
- while ((c = getopt(argc, argv, "s:a:q:vrb")) != -1) {
+ while ((c = getopt(argc, argv, "s:a:p:q:vrb")) != -1) {
switch (c) {
case 'v':
verbose++;
break;
case 'a':
- parse_address(optarg, &dest_client, &dest_port);
+ case 'p':
+ addr = optarg;
break;
case 'q':
dest_queue = atoi(optarg);
}
/* open sequencer device */
- /* Here we open the device read/write mode. */
- /* Because we write SND_SEQ_EVENT_ECHO to myself to sync. */
- tmp = snd_seq_open(&seq_handle, "hw", SND_SEQ_OPEN_DUPLEX, 0);
+ /* Here we open the device read/write for slave mode. */
+ tmp = snd_seq_open(&seq_handle, "hw", slave ? SND_SEQ_OPEN_DUPLEX : SND_SEQ_OPEN_OUTPUT, 0);
if (tmp < 0) {
perror("open /dev/snd/seq");
exit(1);
/* set name */
/* set event filter to recieve only echo event */
/* if running in slave mode also listen for START event */
- snd_seq_set_client_event_filter(seq_handle, SND_SEQ_EVENT_ECHO);
if (slave)
snd_seq_set_client_event_filter(seq_handle, SND_SEQ_EVENT_START);
snd_seq_set_client_name(seq_handle, "MIDI file player");
exit(1);
}
+ if (snd_seq_parse_address(seq_handle, &dest_addr, addr) < 0) {
+ perror("invalid destination address");
+ exit(1);
+ }
+ dest_client = dest_addr.client;
+ dest_port = dest_addr.port;
+
/* setup queue */
if (dest_queue >= 0) {
if (snd_seq_set_queue_usage(seq_handle, dest_queue, 1) < 0) {