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 = "";
44
snd_midi_event_t *midi_event;
46
snd_seq_event_t *in_event;
52
snd_seq_event_t out_event;
54
} snd_rawmidi_virtual_t;
56
static int snd_rawmidi_virtual_close(snd_rawmidi_t *rmidi)
58
snd_rawmidi_virtual_t *virt = rmidi->private_data;
62
snd_seq_close(virt->handle);
64
snd_midi_event_free(virt->midi_event);
69
static int snd_rawmidi_virtual_nonblock(snd_rawmidi_t *rmidi, int nonblock)
71
snd_rawmidi_virtual_t *virt = rmidi->private_data;
73
return snd_seq_nonblock(virt->handle, nonblock);
76
static int snd_rawmidi_virtual_info(snd_rawmidi_t *rmidi, snd_rawmidi_info_t * info)
78
// snd_rawmidi_virtual_t *virt = rmidi->private_data;
80
info->stream = rmidi->stream;
81
/* FIXME: what values should be there? */
86
strcpy(info->id, "Virtual");
87
strcpy(info->name, "Virtual RawMIDI");
88
strcpy(info->subname, "Virtual RawMIDI");
89
info->subdevices_count = 1;
90
info->subdevices_avail = 0;
94
static int snd_rawmidi_virtual_input_params(snd_rawmidi_virtual_t *virt, snd_rawmidi_params_t *params)
98
// snd_rawmidi_drain_input(substream);
99
if (params->buffer_size < sizeof(snd_seq_event_t) ||
100
params->buffer_size > 1024L * 1024L) {
103
if (params->buffer_size != snd_seq_get_input_buffer_size(virt->handle)) {
104
err = snd_seq_set_input_buffer_size(virt->handle, params->buffer_size);
107
params->buffer_size = snd_seq_get_input_buffer_size(virt->handle);
108
/* FIXME: input pool size? */
114
static int snd_rawmidi_virtual_output_params(snd_rawmidi_virtual_t *virt, snd_rawmidi_params_t *params)
118
// snd_rawmidi_drain_output(substream);
119
if (params->buffer_size < sizeof(snd_seq_event_t) ||
120
params->buffer_size > 1024L * 1024L) {
123
if (params->buffer_size != snd_seq_get_output_buffer_size(virt->handle)) {
124
err = snd_seq_set_output_buffer_size(virt->handle, params->buffer_size);
127
params->buffer_size = snd_seq_get_output_buffer_size(virt->handle);
133
static int snd_rawmidi_virtual_params(snd_rawmidi_t *rmidi, snd_rawmidi_params_t * params)
135
snd_rawmidi_virtual_t *virt = rmidi->private_data;
136
params->stream = rmidi->stream;
138
if (rmidi->stream == SND_RAWMIDI_STREAM_INPUT)
139
return snd_rawmidi_virtual_input_params(virt, params);
141
return snd_rawmidi_virtual_output_params(virt, params);
144
static int snd_rawmidi_virtual_status(snd_rawmidi_t *rmidi, snd_rawmidi_status_t * status)
146
// snd_rawmidi_virtual_t *virt = rmidi->private_data;
147
memset(status, 0, sizeof(*status));
148
status->stream = rmidi->stream;
152
static int snd_rawmidi_virtual_drop(snd_rawmidi_t *rmidi)
154
snd_rawmidi_virtual_t *virt = rmidi->private_data;
155
if (rmidi->stream == SND_RAWMIDI_STREAM_OUTPUT) {
156
snd_seq_drop_output(virt->handle);
157
snd_midi_event_reset_encode(virt->midi_event);
160
snd_seq_drop_input(virt->handle);
161
snd_midi_event_reset_decode(virt->midi_event);
162
virt->in_buf_ofs = 0;
167
static int snd_rawmidi_virtual_drain(snd_rawmidi_t *rmidi)
169
snd_rawmidi_virtual_t *virt = rmidi->private_data;
172
if (rmidi->stream == SND_RAWMIDI_STREAM_OUTPUT) {
174
err = snd_seq_event_output(virt->handle, &virt->out_event);
179
snd_seq_drain_output(virt->handle);
180
snd_seq_sync_output_queue(virt->handle);
182
return snd_rawmidi_virtual_drop(rmidi);
185
static ssize_t snd_rawmidi_virtual_write(snd_rawmidi_t *rmidi, const void *buffer, size_t size)
187
snd_rawmidi_virtual_t *virt = rmidi->private_data;
193
err = snd_seq_event_output(virt->handle, &virt->out_event);
196
/* we got some fatal error. removing this event
206
size1 = snd_midi_event_encode(virt->midi_event, buffer, size, &virt->out_event);
209
if (virt->out_event.type == SND_SEQ_EVENT_NONE)
214
snd_seq_ev_set_subs(&virt->out_event);
215
snd_seq_ev_set_source(&virt->out_event, virt->port);
216
snd_seq_ev_set_direct(&virt->out_event);
217
err = snd_seq_event_output(virt->handle, &virt->out_event);
220
return result > 0 ? result : err;
225
snd_seq_drain_output(virt->handle);
230
static ssize_t snd_rawmidi_virtual_read(snd_rawmidi_t *rmidi, void *buffer, size_t size)
232
snd_rawmidi_virtual_t *virt = rmidi->private_data;
237
if (! virt->in_buf_ofs) {
238
err = snd_seq_event_input_pending(virt->handle, 1);
239
if (err <= 0 && result > 0)
241
err = snd_seq_event_input(virt->handle, &virt->in_event);
243
return result > 0 ? result : err;
245
if (virt->in_event->type == SND_SEQ_EVENT_SYSEX) {
246
virt->in_buf_ptr = virt->in_event->data.ext.ptr;
247
virt->in_buf_size = virt->in_event->data.ext.len;
249
virt->in_buf_ptr = virt->in_tmp_buf;
250
virt->in_buf_size = snd_midi_event_decode(virt->midi_event,
252
sizeof(virt->in_tmp_buf),
255
if (virt->in_buf_size <= 0)
258
size1 = virt->in_buf_size - virt->in_buf_ofs;
259
if ((size_t)size1 > size) {
260
virt->in_buf_ofs += size1 - size;
261
memcpy(buffer, virt->in_buf_ptr, size);
265
memcpy(buffer, virt->in_buf_ptr + virt->in_buf_ofs, size1);
269
virt->in_buf_ofs = 0;
275
snd_rawmidi_ops_t snd_rawmidi_virtual_ops = {
276
.close = snd_rawmidi_virtual_close,
277
.nonblock = snd_rawmidi_virtual_nonblock,
278
.info = snd_rawmidi_virtual_info,
279
.params = snd_rawmidi_virtual_params,
280
.status = snd_rawmidi_virtual_status,
281
.drop = snd_rawmidi_virtual_drop,
282
.drain = snd_rawmidi_virtual_drain,
283
.write = snd_rawmidi_virtual_write,
284
.read = snd_rawmidi_virtual_read,
288
/*! \page rawmidi RawMidi interface
290
\section rawmidi_virt Virtual RawMidi interface
292
The "virtual" plugin creates a virtual RawMidi instance on the ALSA
293
sequencer, which can be accessed through the connection of the sequencer
295
There is no connection established as default.
297
For creating a virtual RawMidi instance, pass "virtual" as its name at
302
snd_rawmidi_open(&read_handle, &write_handle, "virtual", 0);
307
int snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
308
const char *name, snd_seq_t *seq_handle, int port,
312
snd_rawmidi_t *rmidi;
313
snd_rawmidi_virtual_t *virt = NULL;
321
virt = calloc(1, sizeof(*virt));
326
virt->handle = seq_handle;
328
err = snd_midi_event_new(256, &virt->midi_event);
331
snd_midi_event_init(virt->midi_event);
332
snd_midi_event_no_status(virt->midi_event, !merge);
335
rmidi = calloc(1, sizeof(*rmidi));
341
rmidi->name = strdup(name);
342
rmidi->type = SND_RAWMIDI_TYPE_VIRTUAL;
343
rmidi->stream = SND_RAWMIDI_STREAM_INPUT;
345
err = snd_seq_poll_descriptors(seq_handle, &pfd, 1, POLLIN);
348
rmidi->poll_fd = pfd.fd;
349
rmidi->ops = &snd_rawmidi_virtual_ops;
350
rmidi->private_data = virt;
355
rmidi = calloc(1, sizeof(*rmidi));
361
rmidi->name = strdup(name);
362
rmidi->type = SND_RAWMIDI_TYPE_VIRTUAL;
363
rmidi->stream = SND_RAWMIDI_STREAM_OUTPUT;
365
err = snd_seq_poll_descriptors(seq_handle, &pfd, 1, POLLOUT);
368
rmidi->poll_fd = pfd.fd;
369
rmidi->ops = &snd_rawmidi_virtual_ops;
370
rmidi->private_data = virt;
379
snd_seq_close(seq_handle);
380
if (virt->midi_event)
381
snd_midi_event_free(virt->midi_event);
384
if (inputp && *inputp)
386
if (outputp && *outputp)
391
int _snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
392
char *name, snd_config_t *root ATTRIBUTE_UNUSED,
393
snd_config_t *conf, int mode)
395
snd_config_iterator_t i, next;
396
const char *slave_str = NULL;
398
int streams, seq_mode;
402
snd_seq_t *seq_handle;
404
snd_config_for_each(i, next, conf) {
405
snd_config_t *n = snd_config_iterator_entry(i);
407
if (snd_config_get_id(n, &id) < 0)
409
if (strcmp(id, "comment") == 0)
411
if (strcmp(id, "type") == 0)
413
if (strcmp(id, "slave") == 0) {
414
err = snd_config_get_string(n, &slave_str);
419
if (strcmp(id, "merge") == 0) {
420
merge = snd_config_get_bool(n);
428
streams |= SND_SEQ_OPEN_INPUT;
430
streams |= SND_SEQ_OPEN_OUTPUT;
435
if (mode & SND_RAWMIDI_NONBLOCK)
436
seq_mode |= O_NONBLOCK;
439
slave_str = "default";
440
err = snd_seq_open_lconf(&seq_handle, slave_str, streams, seq_mode, root);
446
caps |= SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SYNC_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE;
448
caps |= SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SYNC_READ | SND_SEQ_PORT_CAP_SUBS_READ;
449
if (inputp && outputp)
450
caps |= SNDRV_SEQ_PORT_CAP_DUPLEX;
452
port = snd_seq_create_simple_port(seq_handle, "Virtual RawMIDI",
453
caps, SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC);
455
snd_seq_close(seq_handle);
459
return snd_rawmidi_virtual_open(inputp, outputp, name, seq_handle, port,
464
SND_DLSYM_BUILD_VERSION(_snd_rawmidi_virtual_open, SND_RAWMIDI_DLSYM_VERSION);