2 * RawMIDI - Virtual (sequencer mode)
3 * Copyright (c) 2003 by Takashi Iwai <tiwai@suse.de>
6 * This library is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <sys/ioctl.h>
28 #include "rawmidi_local.h"
30 #include "seq_midi_event.h"
33 /* entry for static linking */
34 const char *_snd_module_rawmidi_virt = "";
45 snd_midi_event_t *midi_event;
47 snd_seq_event_t *in_event;
53 snd_seq_event_t out_event;
55 } snd_rawmidi_virtual_t;
57 int _snd_seq_open_lconf(snd_seq_t **seqp, const char *name,
58 int streams, int mode, snd_config_t *lconf,
59 snd_config_t *parent_conf);
62 static int snd_rawmidi_virtual_close(snd_rawmidi_t *rmidi)
64 snd_rawmidi_virtual_t *virt = rmidi->private_data;
68 snd_seq_close(virt->handle);
70 snd_midi_event_free(virt->midi_event);
75 static int snd_rawmidi_virtual_nonblock(snd_rawmidi_t *rmidi, int nonblock)
77 snd_rawmidi_virtual_t *virt = rmidi->private_data;
79 return snd_seq_nonblock(virt->handle, nonblock);
82 static int snd_rawmidi_virtual_info(snd_rawmidi_t *rmidi, snd_rawmidi_info_t * info)
84 // snd_rawmidi_virtual_t *virt = rmidi->private_data;
86 info->stream = rmidi->stream;
87 /* FIXME: what values should be there? */
92 strcpy((char *)info->id, "Virtual");
93 strcpy((char *)info->name, "Virtual RawMIDI");
94 strcpy((char *)info->subname, "Virtual RawMIDI");
95 info->subdevices_count = 1;
96 info->subdevices_avail = 0;
100 static int snd_rawmidi_virtual_input_params(snd_rawmidi_virtual_t *virt, snd_rawmidi_params_t *params)
104 // snd_rawmidi_drain_input(substream);
105 if (params->buffer_size < sizeof(snd_seq_event_t) ||
106 params->buffer_size > 1024L * 1024L) {
109 if (params->buffer_size != snd_seq_get_input_buffer_size(virt->handle)) {
110 err = snd_seq_set_input_buffer_size(virt->handle, params->buffer_size);
113 params->buffer_size = snd_seq_get_input_buffer_size(virt->handle);
114 /* FIXME: input pool size? */
120 static int snd_rawmidi_virtual_output_params(snd_rawmidi_virtual_t *virt, snd_rawmidi_params_t *params)
124 // snd_rawmidi_drain_output(substream);
125 if (params->buffer_size < sizeof(snd_seq_event_t) ||
126 params->buffer_size > 1024L * 1024L) {
129 if (params->buffer_size != snd_seq_get_output_buffer_size(virt->handle)) {
130 err = snd_seq_set_output_buffer_size(virt->handle, params->buffer_size);
133 params->buffer_size = snd_seq_get_output_buffer_size(virt->handle);
139 static int snd_rawmidi_virtual_params(snd_rawmidi_t *rmidi, snd_rawmidi_params_t * params)
141 snd_rawmidi_virtual_t *virt = rmidi->private_data;
142 params->stream = rmidi->stream;
144 if (rmidi->stream == SND_RAWMIDI_STREAM_INPUT)
145 return snd_rawmidi_virtual_input_params(virt, params);
147 return snd_rawmidi_virtual_output_params(virt, params);
150 static int snd_rawmidi_virtual_status(snd_rawmidi_t *rmidi, snd_rawmidi_status_t * status)
152 // snd_rawmidi_virtual_t *virt = rmidi->private_data;
153 memset(status, 0, sizeof(*status));
154 status->stream = rmidi->stream;
158 static int snd_rawmidi_virtual_drop(snd_rawmidi_t *rmidi)
160 snd_rawmidi_virtual_t *virt = rmidi->private_data;
161 if (rmidi->stream == SND_RAWMIDI_STREAM_OUTPUT) {
162 snd_seq_drop_output(virt->handle);
163 snd_midi_event_reset_encode(virt->midi_event);
166 snd_seq_drop_input(virt->handle);
167 snd_midi_event_reset_decode(virt->midi_event);
168 virt->in_buf_ofs = 0;
173 static int snd_rawmidi_virtual_drain(snd_rawmidi_t *rmidi)
175 snd_rawmidi_virtual_t *virt = rmidi->private_data;
178 if (rmidi->stream == SND_RAWMIDI_STREAM_OUTPUT) {
180 err = snd_seq_event_output(virt->handle, &virt->out_event);
185 snd_seq_drain_output(virt->handle);
186 snd_seq_sync_output_queue(virt->handle);
188 return snd_rawmidi_virtual_drop(rmidi);
191 static ssize_t snd_rawmidi_virtual_write(snd_rawmidi_t *rmidi, const void *buffer, size_t size)
193 snd_rawmidi_virtual_t *virt = rmidi->private_data;
199 err = snd_seq_event_output(virt->handle, &virt->out_event);
202 /* we got some fatal error. removing this event
212 size1 = snd_midi_event_encode(virt->midi_event, buffer, size, &virt->out_event);
218 if (virt->out_event.type == SND_SEQ_EVENT_NONE)
220 snd_seq_ev_set_subs(&virt->out_event);
221 snd_seq_ev_set_source(&virt->out_event, virt->port);
222 snd_seq_ev_set_direct(&virt->out_event);
223 err = snd_seq_event_output(virt->handle, &virt->out_event);
226 return result > 0 ? result : err;
231 snd_seq_drain_output(virt->handle);
236 static ssize_t snd_rawmidi_virtual_read(snd_rawmidi_t *rmidi, void *buffer, size_t size)
238 snd_rawmidi_virtual_t *virt = rmidi->private_data;
243 if (! virt->in_buf_ofs) {
244 err = snd_seq_event_input_pending(virt->handle, 1);
245 if (err <= 0 && result > 0)
247 err = snd_seq_event_input(virt->handle, &virt->in_event);
249 return result > 0 ? result : err;
251 if (virt->in_event->type == SND_SEQ_EVENT_SYSEX) {
252 virt->in_buf_ptr = virt->in_event->data.ext.ptr;
253 virt->in_buf_size = virt->in_event->data.ext.len;
255 virt->in_buf_ptr = virt->in_tmp_buf;
256 virt->in_buf_size = snd_midi_event_decode(virt->midi_event,
257 (unsigned char *)virt->in_tmp_buf,
258 sizeof(virt->in_tmp_buf),
261 if (virt->in_buf_size <= 0)
264 size1 = virt->in_buf_size - virt->in_buf_ofs;
265 if ((size_t)size1 > size) {
266 virt->in_buf_ofs += size1 - size;
267 memcpy(buffer, virt->in_buf_ptr, size);
271 memcpy(buffer, virt->in_buf_ptr + virt->in_buf_ofs, size1);
275 virt->in_buf_ofs = 0;
281 static const snd_rawmidi_ops_t snd_rawmidi_virtual_ops = {
282 .close = snd_rawmidi_virtual_close,
283 .nonblock = snd_rawmidi_virtual_nonblock,
284 .info = snd_rawmidi_virtual_info,
285 .params = snd_rawmidi_virtual_params,
286 .status = snd_rawmidi_virtual_status,
287 .drop = snd_rawmidi_virtual_drop,
288 .drain = snd_rawmidi_virtual_drain,
289 .write = snd_rawmidi_virtual_write,
290 .read = snd_rawmidi_virtual_read,
294 /*! \page rawmidi RawMidi interface
296 \section rawmidi_virt Virtual RawMidi interface
298 The "virtual" plugin creates a virtual RawMidi instance on the ALSA
299 sequencer, which can be accessed through the connection of the sequencer
301 There is no connection established as default.
303 For creating a virtual RawMidi instance, pass "virtual" as its name at
308 snd_rawmidi_open(&read_handle, &write_handle, "virtual", 0);
313 int snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
314 const char *name, snd_seq_t *seq_handle, int port,
318 snd_rawmidi_t *rmidi;
319 snd_rawmidi_virtual_t *virt = NULL;
327 virt = calloc(1, sizeof(*virt));
332 virt->handle = seq_handle;
334 err = snd_midi_event_new(256, &virt->midi_event);
337 snd_midi_event_init(virt->midi_event);
338 snd_midi_event_no_status(virt->midi_event, !merge);
341 rmidi = calloc(1, sizeof(*rmidi));
347 rmidi->name = strdup(name);
348 rmidi->type = SND_RAWMIDI_TYPE_VIRTUAL;
349 rmidi->stream = SND_RAWMIDI_STREAM_INPUT;
351 err = snd_seq_poll_descriptors(seq_handle, &pfd, 1, POLLIN);
354 rmidi->poll_fd = pfd.fd;
355 rmidi->ops = &snd_rawmidi_virtual_ops;
356 rmidi->private_data = virt;
361 rmidi = calloc(1, sizeof(*rmidi));
367 rmidi->name = strdup(name);
368 rmidi->type = SND_RAWMIDI_TYPE_VIRTUAL;
369 rmidi->stream = SND_RAWMIDI_STREAM_OUTPUT;
371 err = snd_seq_poll_descriptors(seq_handle, &pfd, 1, POLLOUT);
374 rmidi->poll_fd = pfd.fd;
375 rmidi->ops = &snd_rawmidi_virtual_ops;
376 rmidi->private_data = virt;
385 snd_seq_close(seq_handle);
387 if (virt->midi_event)
388 snd_midi_event_free(virt->midi_event);
398 int _snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
399 char *name, snd_config_t *root ATTRIBUTE_UNUSED,
400 snd_config_t *conf, int mode)
402 snd_config_iterator_t i, next;
403 const char *slave_str = NULL;
405 int streams, seq_mode;
409 snd_seq_t *seq_handle;
411 snd_config_for_each(i, next, conf) {
412 snd_config_t *n = snd_config_iterator_entry(i);
414 if (snd_config_get_id(n, &id) < 0)
416 if (snd_rawmidi_conf_generic_id(id))
418 if (strcmp(id, "slave") == 0) {
419 err = snd_config_get_string(n, &slave_str);
424 if (strcmp(id, "merge") == 0) {
425 merge = snd_config_get_bool(n);
433 streams |= SND_SEQ_OPEN_INPUT;
435 streams |= SND_SEQ_OPEN_OUTPUT;
440 if (mode & SND_RAWMIDI_NONBLOCK)
441 seq_mode |= SND_SEQ_NONBLOCK;
444 slave_str = "default";
445 err = _snd_seq_open_lconf(&seq_handle, slave_str, streams, seq_mode,
452 caps |= SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SYNC_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE;
454 caps |= SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SYNC_READ | SND_SEQ_PORT_CAP_SUBS_READ;
455 if (inputp && outputp)
456 caps |= SNDRV_SEQ_PORT_CAP_DUPLEX;
458 port = snd_seq_create_simple_port(seq_handle, "Virtual RawMIDI",
459 caps, SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC);
461 snd_seq_close(seq_handle);
465 return snd_rawmidi_virtual_open(inputp, outputp, name, seq_handle, port,
470 SND_DLSYM_BUILD_VERSION(_snd_rawmidi_virtual_open, SND_RAWMIDI_DLSYM_VERSION);