Home | History | Annotate | Download | only in seq
      1 /*
      2  *  Sequencer Interface - middle-level routines
      3  *
      4  *  Copyright (c) 1999 by Takashi Iwai <tiwai (at) suse.de>
      5  *
      6  *
      7  *   This library is free software; you can redistribute it and/or modify
      8  *   it under the terms of the GNU Lesser General Public License as
      9  *   published by the Free Software Foundation; either version 2.1 of
     10  *   the License, or (at your option) any later version.
     11  *
     12  *   This program is distributed in the hope that it will be useful,
     13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15  *   GNU Lesser General Public License for more details.
     16  *
     17  *   You should have received a copy of the GNU Lesser General Public
     18  *   License along with this library; if not, write to the Free Software
     19  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
     20  *
     21  */
     22 
     23 #include <stdio.h>
     24 #include <stdlib.h>
     25 #include <unistd.h>
     26 #include <string.h>
     27 #include <fcntl.h>
     28 #include <ctype.h>
     29 #include <sys/ioctl.h>
     30 #include "seq_local.h"
     31 
     32 /**
     33  * \brief queue controls - start/stop/continue
     34  * \param seq sequencer handle
     35  * \param q queue id to control
     36  * \param type event type
     37  * \param value event value
     38  * \param ev event instance
     39  *
     40  * This function sets up general queue control event and sends it.
     41  * To send at scheduled time, set the schedule in \a ev.
     42  * If \a ev is NULL, the event is composed locally and sent immediately
     43  * to the specified queue.  In any cases, you need to call #snd_seq_drain_output()
     44  * appropriately to feed the event.
     45  *
     46  * \sa snd_seq_alloc_queue()
     47  */
     48 int snd_seq_control_queue(snd_seq_t *seq, int q, int type, int value, snd_seq_event_t *ev)
     49 {
     50 	snd_seq_event_t tmpev;
     51 	if (ev == NULL) {
     52 		snd_seq_ev_clear(&tmpev);
     53 		ev = &tmpev;
     54 		snd_seq_ev_set_direct(ev);
     55 	}
     56 	snd_seq_ev_set_queue_control(ev, type, q, value);
     57 	return snd_seq_event_output(seq, ev);
     58 }
     59 
     60 
     61 /**
     62  * \brief create a port - simple version
     63  * \param seq sequencer handle
     64  * \param name the name of the port
     65  * \param caps capability bits
     66  * \param type type bits
     67  * \return the created port number or negative error code
     68  *
     69  * Creates a port with the given capability and type bits.
     70  *
     71  * \sa snd_seq_create_port(), snd_seq_delete_simple_port()
     72  */
     73 int snd_seq_create_simple_port(snd_seq_t *seq, const char *name,
     74 			       unsigned int caps, unsigned int type)
     75 {
     76 	snd_seq_port_info_t pinfo;
     77 	int result;
     78 
     79 	memset(&pinfo, 0, sizeof(pinfo));
     80 	if (name)
     81 		strncpy(pinfo.name, name, sizeof(pinfo.name) - 1);
     82 	pinfo.capability = caps;
     83 	pinfo.type = type;
     84 	pinfo.midi_channels = 16;
     85 	pinfo.midi_voices = 64; /* XXX */
     86 	pinfo.synth_voices = 0; /* XXX */
     87 
     88 	result = snd_seq_create_port(seq, &pinfo);
     89 	if (result < 0)
     90 		return result;
     91 	else
     92 		return pinfo.addr.port;
     93 }
     94 
     95 /**
     96  * \brief delete the port
     97  * \param seq sequencer handle
     98  * \param port port id
     99  * \return 0 on success or negative error code
    100  *
    101  * \sa snd_seq_delete_port(), snd_seq_create_simple_port()
    102  */
    103 int snd_seq_delete_simple_port(snd_seq_t *seq, int port)
    104 {
    105 	return snd_seq_delete_port(seq, port);
    106 }
    107 
    108 /**
    109  * \brief simple subscription (w/o exclusive & time conversion)
    110  * \param seq sequencer handle
    111  * \param myport the port id as receiver
    112  * \param src_client sender client id
    113  * \param src_port sender port id
    114  * \return 0 on success or negative error code
    115  *
    116  * Connect from the given sender client:port to the given destination port in the
    117  * current client.
    118  *
    119  * \sa snd_seq_subscribe_port(), snd_seq_disconnect_from()
    120  */
    121 int snd_seq_connect_from(snd_seq_t *seq, int myport, int src_client, int src_port)
    122 {
    123 	snd_seq_port_subscribe_t subs;
    124 
    125 	memset(&subs, 0, sizeof(subs));
    126 	subs.sender.client = src_client;
    127 	subs.sender.port = src_port;
    128 	/*subs.dest.client = seq->client;*/
    129 	subs.dest.client = snd_seq_client_id(seq);
    130 	subs.dest.port = myport;
    131 
    132 	return snd_seq_subscribe_port(seq, &subs);
    133 }
    134 
    135 /**
    136  * \brief simple subscription (w/o exclusive & time conversion)
    137  * \param seq sequencer handle
    138  * \param myport the port id as sender
    139  * \param dest_client destination client id
    140  * \param dest_port destination port id
    141  * \return 0 on success or negative error code
    142  *
    143  * Connect from the given receiver port in the current client
    144  * to the given destination client:port.
    145  *
    146  * \sa snd_seq_subscribe_port(), snd_seq_disconnect_to()
    147  */
    148 int snd_seq_connect_to(snd_seq_t *seq, int myport, int dest_client, int dest_port)
    149 {
    150 	snd_seq_port_subscribe_t subs;
    151 
    152 	memset(&subs, 0, sizeof(subs));
    153 	/*subs.sender.client = seq->client;*/
    154 	subs.sender.client = snd_seq_client_id(seq);
    155 	subs.sender.port = myport;
    156 	subs.dest.client = dest_client;
    157 	subs.dest.port = dest_port;
    158 
    159 	return snd_seq_subscribe_port(seq, &subs);
    160 }
    161 
    162 /**
    163  * \brief simple disconnection
    164  * \param seq sequencer handle
    165  * \param myport the port id as receiver
    166  * \param src_client sender client id
    167  * \param src_port sender port id
    168  * \return 0 on success or negative error code
    169  *
    170  * Remove connection from the given sender client:port
    171  * to the given destination port in the current client.
    172  *
    173  * \sa snd_seq_unsubscribe_port(), snd_seq_connect_from()
    174  */
    175 int snd_seq_disconnect_from(snd_seq_t *seq, int myport, int src_client, int src_port)
    176 {
    177 	snd_seq_port_subscribe_t subs;
    178 
    179 	memset(&subs, 0, sizeof(subs));
    180 	subs.sender.client = src_client;
    181 	subs.sender.port = src_port;
    182 	/*subs.dest.client = seq->client;*/
    183 	subs.dest.client = snd_seq_client_id(seq);
    184 	subs.dest.port = myport;
    185 
    186 	return snd_seq_unsubscribe_port(seq, &subs);
    187 }
    188 
    189 /**
    190  * \brief simple disconnection
    191  * \param seq sequencer handle
    192  * \param myport the port id as sender
    193  * \param dest_client destination client id
    194  * \param dest_port destination port id
    195  * \return 0 on success or negative error code
    196  *
    197  * Remove connection from the given sender client:port
    198  * to the given destination port in the current client.
    199  *
    200  * \sa snd_seq_unsubscribe_port(), snd_seq_connect_to()
    201  */
    202 int snd_seq_disconnect_to(snd_seq_t *seq, int myport, int dest_client, int dest_port)
    203 {
    204 	snd_seq_port_subscribe_t subs;
    205 
    206 	memset(&subs, 0, sizeof(subs));
    207 	/*subs.sender.client = seq->client;*/
    208 	subs.sender.client = snd_seq_client_id(seq);
    209 	subs.sender.port = myport;
    210 	subs.dest.client = dest_client;
    211 	subs.dest.port = dest_port;
    212 
    213 	return snd_seq_unsubscribe_port(seq, &subs);
    214 }
    215 
    216 /*
    217  * set client information
    218  */
    219 
    220 /**
    221  * \brief set client name
    222  * \param seq sequencer handle
    223  * \param name name string
    224  * \return 0 on success or negative error code
    225  *
    226  * \sa snd_seq_set_client_info()
    227  */
    228 int snd_seq_set_client_name(snd_seq_t *seq, const char *name)
    229 {
    230 	snd_seq_client_info_t info;
    231 	int err;
    232 
    233 	if ((err = snd_seq_get_client_info(seq, &info)) < 0)
    234 		return err;
    235 	strncpy(info.name, name, sizeof(info.name) - 1);
    236 	return snd_seq_set_client_info(seq, &info);
    237 }
    238 
    239 /**
    240  * \brief add client event filter
    241  * \param seq sequencer handle
    242  * \param event_type event type to be added
    243  * \return 0 on success or negative error code
    244  *
    245  * \sa snd_seq_set_client_info()
    246  */
    247 int snd_seq_set_client_event_filter(snd_seq_t *seq, int event_type)
    248 {
    249 	snd_seq_client_info_t info;
    250 	int err;
    251 
    252 	if ((err = snd_seq_get_client_info(seq, &info)) < 0)
    253 		return err;
    254 	snd_seq_client_info_event_filter_add(&info, event_type);
    255 	return snd_seq_set_client_info(seq, &info);
    256 }
    257 
    258 /**
    259  * \brief change the output pool size of the given client
    260  * \param seq sequencer handle
    261  * \param size output pool size
    262  * \return 0 on success or negative error code
    263  *
    264  * \sa snd_seq_set_client_pool()
    265  */
    266 int snd_seq_set_client_pool_output(snd_seq_t *seq, size_t size)
    267 {
    268 	snd_seq_client_pool_t info;
    269 	int err;
    270 
    271 	if ((err = snd_seq_get_client_pool(seq, &info)) < 0)
    272 		return err;
    273 	info.output_pool = size;
    274 	return snd_seq_set_client_pool(seq, &info);
    275 }
    276 
    277 /**
    278  * \brief change the output room size of the given client
    279  * \param seq sequencer handle
    280  * \param size output room size
    281  * \return 0 on success or negative error code
    282  *
    283  * \sa snd_seq_set_client_pool()
    284  */
    285 int snd_seq_set_client_pool_output_room(snd_seq_t *seq, size_t size)
    286 {
    287 	snd_seq_client_pool_t info;
    288 	int err;
    289 
    290 	if ((err = snd_seq_get_client_pool(seq, &info)) < 0)
    291 		return err;
    292 	info.output_room = size;
    293 	return snd_seq_set_client_pool(seq, &info);
    294 }
    295 
    296 /**
    297  * \brief change the input pool size of the given client
    298  * \param seq sequencer handle
    299  * \param size input pool size
    300  * \return 0 on success or negative error code
    301  *
    302  * \sa snd_seq_set_client_pool()
    303  */
    304 int snd_seq_set_client_pool_input(snd_seq_t *seq, size_t size)
    305 {
    306 	snd_seq_client_pool_t info;
    307 	int err;
    308 
    309 	if ((err = snd_seq_get_client_pool(seq, &info)) < 0)
    310 		return err;
    311 	info.input_pool = size;
    312 	return snd_seq_set_client_pool(seq, &info);
    313 }
    314 
    315 /**
    316  * \brief reset client output pool
    317  * \param seq sequencer handle
    318  * \return 0 on success or negative error code
    319  *
    320  * So far, this works ideically like #snd_seq_drop_output().
    321  */
    322 int snd_seq_reset_pool_output(snd_seq_t *seq)
    323 {
    324 	return snd_seq_drop_output(seq);
    325 }
    326 
    327 /**
    328  * \brief reset client input pool
    329  * \param seq sequencer handle
    330  * \return 0 on success or negative error code
    331  *
    332  * So far, this works ideically like #snd_seq_drop_input().
    333  */
    334 int snd_seq_reset_pool_input(snd_seq_t *seq)
    335 {
    336 	return snd_seq_drop_input(seq);
    337 }
    338 
    339 /**
    340  * \brief wait until all events are processed
    341  * \param seq sequencer handle
    342  * \return 0 on success or negative error code
    343  *
    344  * This function waits until all events of this client are processed.
    345  *
    346  * \sa snd_seq_drain_output()
    347  */
    348 int snd_seq_sync_output_queue(snd_seq_t *seq)
    349 {
    350 	int err;
    351 	snd_seq_client_pool_t info;
    352 	int saved_room;
    353 	struct pollfd pfd;
    354 
    355 	assert(seq);
    356 	/* reprogram the room size to full */
    357 	if ((err = snd_seq_get_client_pool(seq, &info)) < 0)
    358 		return err;
    359 	saved_room = info.output_room;
    360 	info.output_room = info.output_pool; /* wait until all gone */
    361 	if ((err = snd_seq_set_client_pool(seq, &info)) < 0)
    362 		return err;
    363 	/* wait until all events are purged */
    364 	pfd.fd = seq->poll_fd;
    365 	pfd.events = POLLOUT;
    366 	err = poll(&pfd, 1, -1);
    367 	/* restore the room size */
    368 	info.output_room = saved_room;
    369 	snd_seq_set_client_pool(seq, &info);
    370 	return err;
    371 }
    372 
    373 /**
    374  * \brief parse the given string and get the sequencer address
    375  * \param seq sequencer handle
    376  * \param addr the address pointer to be returned
    377  * \param arg the string to be parsed
    378  * \return 0 on success or negative error code
    379  *
    380  * This function parses the sequencer client and port numbers from the given string.
    381  * The client and port tokes are separated by either colon or period, e.g. 128:1.
    382  * When \a seq is not NULL, the function accepts also a client name not only
    383  * digit numbers.
    384  */
    385 int snd_seq_parse_address(snd_seq_t *seq, snd_seq_addr_t *addr, const char *arg)
    386 {
    387 	char *p;
    388 	int client, port;
    389 	int len;
    390 
    391 	assert(addr && arg);
    392 
    393 	if ((p = strpbrk(arg, ":.")) != NULL) {
    394 		if ((port = atoi(p + 1)) < 0)
    395 			return -EINVAL;
    396 		len = (int)(p - arg); /* length of client name */
    397 	} else {
    398 		port = 0;
    399 		len = strlen(arg);
    400 	}
    401 	addr->port = port;
    402 	if (isdigit(*arg)) {
    403 		client = atoi(arg);
    404 		if (client < 0)
    405 			return -EINVAL;
    406 		addr->client = client;
    407 	} else {
    408 		/* convert from the name */
    409 		snd_seq_client_info_t cinfo;
    410 
    411 		if (! seq)
    412 			return -EINVAL;
    413 		if (len <= 0)
    414 			return -EINVAL;
    415 		cinfo.client = -1;
    416 		while (snd_seq_query_next_client(seq, &cinfo) >= 0) {
    417 			if (! strncmp(arg, cinfo.name, len)) {
    418 				addr->client = cinfo.client;
    419 				return 0;
    420 			}
    421 		}
    422 		return -ENOENT; /* not found */
    423 	}
    424 	return 0;
    425 }
    426 
    427