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