1d5ac70f0Sopenharmony_ci/* 2d5ac70f0Sopenharmony_ci * RawMIDI - Virtual (sequencer mode) 3d5ac70f0Sopenharmony_ci * Copyright (c) 2003 by Takashi Iwai <tiwai@suse.de> 4d5ac70f0Sopenharmony_ci * 5d5ac70f0Sopenharmony_ci * 6d5ac70f0Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 7d5ac70f0Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as 8d5ac70f0Sopenharmony_ci * published by the Free Software Foundation; either version 2.1 of 9d5ac70f0Sopenharmony_ci * the License, or (at your option) any later version. 10d5ac70f0Sopenharmony_ci * 11d5ac70f0Sopenharmony_ci * This program is distributed in the hope that it will be useful, 12d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 13d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14d5ac70f0Sopenharmony_ci * GNU Lesser General Public License for more details. 15d5ac70f0Sopenharmony_ci * 16d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public 17d5ac70f0Sopenharmony_ci * License along with this library; if not, write to the Free Software 18d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19d5ac70f0Sopenharmony_ci * 20d5ac70f0Sopenharmony_ci */ 21d5ac70f0Sopenharmony_ci 22d5ac70f0Sopenharmony_ci#include "rawmidi_local.h" 23d5ac70f0Sopenharmony_ci#include <unistd.h> 24d5ac70f0Sopenharmony_ci#include <string.h> 25d5ac70f0Sopenharmony_ci#include <fcntl.h> 26d5ac70f0Sopenharmony_ci#include <sys/ioctl.h> 27d5ac70f0Sopenharmony_ci#include "seq.h" 28d5ac70f0Sopenharmony_ci#include "seq_midi_event.h" 29d5ac70f0Sopenharmony_ci 30d5ac70f0Sopenharmony_ci#ifndef PIC 31d5ac70f0Sopenharmony_ci/* entry for static linking */ 32d5ac70f0Sopenharmony_ciconst char *_snd_module_rawmidi_virt = ""; 33d5ac70f0Sopenharmony_ci#endif 34d5ac70f0Sopenharmony_ci 35d5ac70f0Sopenharmony_ci 36d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 37d5ac70f0Sopenharmony_citypedef struct { 38d5ac70f0Sopenharmony_ci int open; 39d5ac70f0Sopenharmony_ci 40d5ac70f0Sopenharmony_ci snd_seq_t *handle; 41d5ac70f0Sopenharmony_ci int port; 42d5ac70f0Sopenharmony_ci 43d5ac70f0Sopenharmony_ci snd_midi_event_t *midi_event; 44d5ac70f0Sopenharmony_ci 45d5ac70f0Sopenharmony_ci snd_seq_event_t *in_event; 46d5ac70f0Sopenharmony_ci int in_buf_size; 47d5ac70f0Sopenharmony_ci int in_buf_ofs; 48d5ac70f0Sopenharmony_ci char *in_buf_ptr; 49d5ac70f0Sopenharmony_ci char in_tmp_buf[16]; 50d5ac70f0Sopenharmony_ci 51d5ac70f0Sopenharmony_ci snd_seq_event_t out_event; 52d5ac70f0Sopenharmony_ci int pending; 53d5ac70f0Sopenharmony_ci} snd_rawmidi_virtual_t; 54d5ac70f0Sopenharmony_ci 55d5ac70f0Sopenharmony_ciint _snd_seq_open_lconf(snd_seq_t **seqp, const char *name, 56d5ac70f0Sopenharmony_ci int streams, int mode, snd_config_t *lconf, 57d5ac70f0Sopenharmony_ci snd_config_t *parent_conf); 58d5ac70f0Sopenharmony_ci#endif 59d5ac70f0Sopenharmony_ci 60d5ac70f0Sopenharmony_cistatic int snd_rawmidi_virtual_close(snd_rawmidi_t *rmidi) 61d5ac70f0Sopenharmony_ci{ 62d5ac70f0Sopenharmony_ci snd_rawmidi_virtual_t *virt = rmidi->private_data; 63d5ac70f0Sopenharmony_ci virt->open--; 64d5ac70f0Sopenharmony_ci if (virt->open) 65d5ac70f0Sopenharmony_ci return 0; 66d5ac70f0Sopenharmony_ci snd_seq_close(virt->handle); 67d5ac70f0Sopenharmony_ci if (virt->midi_event) 68d5ac70f0Sopenharmony_ci snd_midi_event_free(virt->midi_event); 69d5ac70f0Sopenharmony_ci free(virt); 70d5ac70f0Sopenharmony_ci return 0; 71d5ac70f0Sopenharmony_ci} 72d5ac70f0Sopenharmony_ci 73d5ac70f0Sopenharmony_cistatic int snd_rawmidi_virtual_nonblock(snd_rawmidi_t *rmidi, int nonblock) 74d5ac70f0Sopenharmony_ci{ 75d5ac70f0Sopenharmony_ci snd_rawmidi_virtual_t *virt = rmidi->private_data; 76d5ac70f0Sopenharmony_ci 77d5ac70f0Sopenharmony_ci return snd_seq_nonblock(virt->handle, nonblock); 78d5ac70f0Sopenharmony_ci} 79d5ac70f0Sopenharmony_ci 80d5ac70f0Sopenharmony_cistatic int snd_rawmidi_virtual_info(snd_rawmidi_t *rmidi, snd_rawmidi_info_t * info) 81d5ac70f0Sopenharmony_ci{ 82d5ac70f0Sopenharmony_ci // snd_rawmidi_virtual_t *virt = rmidi->private_data; 83d5ac70f0Sopenharmony_ci 84d5ac70f0Sopenharmony_ci info->stream = rmidi->stream; 85d5ac70f0Sopenharmony_ci /* FIXME: what values should be there? */ 86d5ac70f0Sopenharmony_ci info->card = 0; 87d5ac70f0Sopenharmony_ci info->device = 0; 88d5ac70f0Sopenharmony_ci info->subdevice = 0; 89d5ac70f0Sopenharmony_ci info->flags = 0; 90d5ac70f0Sopenharmony_ci strcpy((char *)info->id, "Virtual"); 91d5ac70f0Sopenharmony_ci strcpy((char *)info->name, "Virtual RawMIDI"); 92d5ac70f0Sopenharmony_ci strcpy((char *)info->subname, "Virtual RawMIDI"); 93d5ac70f0Sopenharmony_ci info->subdevices_count = 1; 94d5ac70f0Sopenharmony_ci info->subdevices_avail = 0; 95d5ac70f0Sopenharmony_ci return 0; 96d5ac70f0Sopenharmony_ci} 97d5ac70f0Sopenharmony_ci 98d5ac70f0Sopenharmony_cistatic int snd_rawmidi_virtual_input_params(snd_rawmidi_virtual_t *virt, snd_rawmidi_params_t *params) 99d5ac70f0Sopenharmony_ci{ 100d5ac70f0Sopenharmony_ci int err; 101d5ac70f0Sopenharmony_ci 102d5ac70f0Sopenharmony_ci // snd_rawmidi_drain_input(substream); 103d5ac70f0Sopenharmony_ci if (params->buffer_size < sizeof(snd_seq_event_t) || 104d5ac70f0Sopenharmony_ci params->buffer_size > 1024L * 1024L) { 105d5ac70f0Sopenharmony_ci return -EINVAL; 106d5ac70f0Sopenharmony_ci } 107d5ac70f0Sopenharmony_ci if (params->buffer_size != snd_seq_get_input_buffer_size(virt->handle)) { 108d5ac70f0Sopenharmony_ci err = snd_seq_set_input_buffer_size(virt->handle, params->buffer_size); 109d5ac70f0Sopenharmony_ci if (err < 0) 110d5ac70f0Sopenharmony_ci return err; 111d5ac70f0Sopenharmony_ci params->buffer_size = snd_seq_get_input_buffer_size(virt->handle); 112d5ac70f0Sopenharmony_ci /* FIXME: input pool size? */ 113d5ac70f0Sopenharmony_ci } 114d5ac70f0Sopenharmony_ci return 0; 115d5ac70f0Sopenharmony_ci} 116d5ac70f0Sopenharmony_ci 117d5ac70f0Sopenharmony_ci 118d5ac70f0Sopenharmony_cistatic int snd_rawmidi_virtual_output_params(snd_rawmidi_virtual_t *virt, snd_rawmidi_params_t *params) 119d5ac70f0Sopenharmony_ci{ 120d5ac70f0Sopenharmony_ci int err; 121d5ac70f0Sopenharmony_ci 122d5ac70f0Sopenharmony_ci // snd_rawmidi_drain_output(substream); 123d5ac70f0Sopenharmony_ci if (params->buffer_size < sizeof(snd_seq_event_t) || 124d5ac70f0Sopenharmony_ci params->buffer_size > 1024L * 1024L) { 125d5ac70f0Sopenharmony_ci return -EINVAL; 126d5ac70f0Sopenharmony_ci } 127d5ac70f0Sopenharmony_ci if (params->buffer_size != snd_seq_get_output_buffer_size(virt->handle)) { 128d5ac70f0Sopenharmony_ci err = snd_seq_set_output_buffer_size(virt->handle, params->buffer_size); 129d5ac70f0Sopenharmony_ci if (err < 0) 130d5ac70f0Sopenharmony_ci return err; 131d5ac70f0Sopenharmony_ci params->buffer_size = snd_seq_get_output_buffer_size(virt->handle); 132d5ac70f0Sopenharmony_ci } 133d5ac70f0Sopenharmony_ci return 0; 134d5ac70f0Sopenharmony_ci} 135d5ac70f0Sopenharmony_ci 136d5ac70f0Sopenharmony_ci 137d5ac70f0Sopenharmony_cistatic int snd_rawmidi_virtual_params(snd_rawmidi_t *rmidi, snd_rawmidi_params_t * params) 138d5ac70f0Sopenharmony_ci{ 139d5ac70f0Sopenharmony_ci snd_rawmidi_virtual_t *virt = rmidi->private_data; 140d5ac70f0Sopenharmony_ci params->stream = rmidi->stream; 141d5ac70f0Sopenharmony_ci 142d5ac70f0Sopenharmony_ci if (rmidi->stream == SND_RAWMIDI_STREAM_INPUT) 143d5ac70f0Sopenharmony_ci return snd_rawmidi_virtual_input_params(virt, params); 144d5ac70f0Sopenharmony_ci else 145d5ac70f0Sopenharmony_ci return snd_rawmidi_virtual_output_params(virt, params); 146d5ac70f0Sopenharmony_ci} 147d5ac70f0Sopenharmony_ci 148d5ac70f0Sopenharmony_cistatic int snd_rawmidi_virtual_status(snd_rawmidi_t *rmidi, snd_rawmidi_status_t * status) 149d5ac70f0Sopenharmony_ci{ 150d5ac70f0Sopenharmony_ci // snd_rawmidi_virtual_t *virt = rmidi->private_data; 151d5ac70f0Sopenharmony_ci memset(status, 0, sizeof(*status)); 152d5ac70f0Sopenharmony_ci status->stream = rmidi->stream; 153d5ac70f0Sopenharmony_ci return 0; 154d5ac70f0Sopenharmony_ci} 155d5ac70f0Sopenharmony_ci 156d5ac70f0Sopenharmony_cistatic int snd_rawmidi_virtual_drop(snd_rawmidi_t *rmidi) 157d5ac70f0Sopenharmony_ci{ 158d5ac70f0Sopenharmony_ci snd_rawmidi_virtual_t *virt = rmidi->private_data; 159d5ac70f0Sopenharmony_ci if (rmidi->stream == SND_RAWMIDI_STREAM_OUTPUT) { 160d5ac70f0Sopenharmony_ci snd_seq_drop_output(virt->handle); 161d5ac70f0Sopenharmony_ci snd_midi_event_reset_encode(virt->midi_event); 162d5ac70f0Sopenharmony_ci virt->pending = 0; 163d5ac70f0Sopenharmony_ci } else { 164d5ac70f0Sopenharmony_ci snd_seq_drop_input(virt->handle); 165d5ac70f0Sopenharmony_ci snd_midi_event_reset_decode(virt->midi_event); 166d5ac70f0Sopenharmony_ci virt->in_buf_ofs = 0; 167d5ac70f0Sopenharmony_ci } 168d5ac70f0Sopenharmony_ci return 0; 169d5ac70f0Sopenharmony_ci} 170d5ac70f0Sopenharmony_ci 171d5ac70f0Sopenharmony_cistatic int snd_rawmidi_virtual_drain(snd_rawmidi_t *rmidi) 172d5ac70f0Sopenharmony_ci{ 173d5ac70f0Sopenharmony_ci snd_rawmidi_virtual_t *virt = rmidi->private_data; 174d5ac70f0Sopenharmony_ci int err; 175d5ac70f0Sopenharmony_ci 176d5ac70f0Sopenharmony_ci if (rmidi->stream == SND_RAWMIDI_STREAM_OUTPUT) { 177d5ac70f0Sopenharmony_ci if (virt->pending) { 178d5ac70f0Sopenharmony_ci err = snd_seq_event_output(virt->handle, &virt->out_event); 179d5ac70f0Sopenharmony_ci if (err < 0) 180d5ac70f0Sopenharmony_ci return err; 181d5ac70f0Sopenharmony_ci virt->pending = 0; 182d5ac70f0Sopenharmony_ci } 183d5ac70f0Sopenharmony_ci snd_seq_drain_output(virt->handle); 184d5ac70f0Sopenharmony_ci snd_seq_sync_output_queue(virt->handle); 185d5ac70f0Sopenharmony_ci } 186d5ac70f0Sopenharmony_ci return snd_rawmidi_virtual_drop(rmidi); 187d5ac70f0Sopenharmony_ci} 188d5ac70f0Sopenharmony_ci 189d5ac70f0Sopenharmony_cistatic ssize_t snd_rawmidi_virtual_write(snd_rawmidi_t *rmidi, const void *buffer, size_t size) 190d5ac70f0Sopenharmony_ci{ 191d5ac70f0Sopenharmony_ci snd_rawmidi_virtual_t *virt = rmidi->private_data; 192d5ac70f0Sopenharmony_ci ssize_t result = 0; 193d5ac70f0Sopenharmony_ci ssize_t size1; 194d5ac70f0Sopenharmony_ci int err; 195d5ac70f0Sopenharmony_ci 196d5ac70f0Sopenharmony_ci if (virt->pending) { 197d5ac70f0Sopenharmony_ci err = snd_seq_event_output(virt->handle, &virt->out_event); 198d5ac70f0Sopenharmony_ci if (err < 0) { 199d5ac70f0Sopenharmony_ci if (err != -EAGAIN) 200d5ac70f0Sopenharmony_ci /* we got some fatal error. removing this event 201d5ac70f0Sopenharmony_ci * at the next time 202d5ac70f0Sopenharmony_ci */ 203d5ac70f0Sopenharmony_ci virt->pending = 0; 204d5ac70f0Sopenharmony_ci return err; 205d5ac70f0Sopenharmony_ci } 206d5ac70f0Sopenharmony_ci virt->pending = 0; 207d5ac70f0Sopenharmony_ci } 208d5ac70f0Sopenharmony_ci 209d5ac70f0Sopenharmony_ci while (size > 0) { 210d5ac70f0Sopenharmony_ci size1 = snd_midi_event_encode(virt->midi_event, buffer, size, &virt->out_event); 211d5ac70f0Sopenharmony_ci if (size1 <= 0) 212d5ac70f0Sopenharmony_ci break; 213d5ac70f0Sopenharmony_ci size -= size1; 214d5ac70f0Sopenharmony_ci result += size1; 215d5ac70f0Sopenharmony_ci buffer += size1; 216d5ac70f0Sopenharmony_ci if (virt->out_event.type == SND_SEQ_EVENT_NONE) 217d5ac70f0Sopenharmony_ci continue; 218d5ac70f0Sopenharmony_ci snd_seq_ev_set_subs(&virt->out_event); 219d5ac70f0Sopenharmony_ci snd_seq_ev_set_source(&virt->out_event, virt->port); 220d5ac70f0Sopenharmony_ci snd_seq_ev_set_direct(&virt->out_event); 221d5ac70f0Sopenharmony_ci err = snd_seq_event_output(virt->handle, &virt->out_event); 222d5ac70f0Sopenharmony_ci if (err < 0) { 223d5ac70f0Sopenharmony_ci virt->pending = 1; 224d5ac70f0Sopenharmony_ci return result > 0 ? result : err; 225d5ac70f0Sopenharmony_ci } 226d5ac70f0Sopenharmony_ci } 227d5ac70f0Sopenharmony_ci 228d5ac70f0Sopenharmony_ci if (result > 0) 229d5ac70f0Sopenharmony_ci snd_seq_drain_output(virt->handle); 230d5ac70f0Sopenharmony_ci 231d5ac70f0Sopenharmony_ci return result; 232d5ac70f0Sopenharmony_ci} 233d5ac70f0Sopenharmony_ci 234d5ac70f0Sopenharmony_cistatic ssize_t snd_rawmidi_virtual_read(snd_rawmidi_t *rmidi, void *buffer, size_t size) 235d5ac70f0Sopenharmony_ci{ 236d5ac70f0Sopenharmony_ci snd_rawmidi_virtual_t *virt = rmidi->private_data; 237d5ac70f0Sopenharmony_ci ssize_t result = 0; 238d5ac70f0Sopenharmony_ci int size1, err; 239d5ac70f0Sopenharmony_ci 240d5ac70f0Sopenharmony_ci while (size > 0) { 241d5ac70f0Sopenharmony_ci if (! virt->in_buf_ofs) { 242d5ac70f0Sopenharmony_ci err = snd_seq_event_input_pending(virt->handle, 1); 243d5ac70f0Sopenharmony_ci if (err <= 0 && result > 0) 244d5ac70f0Sopenharmony_ci return result; 245d5ac70f0Sopenharmony_ci err = snd_seq_event_input(virt->handle, &virt->in_event); 246d5ac70f0Sopenharmony_ci if (err < 0) 247d5ac70f0Sopenharmony_ci return result > 0 ? result : err; 248d5ac70f0Sopenharmony_ci 249d5ac70f0Sopenharmony_ci if (virt->in_event->type == SND_SEQ_EVENT_SYSEX) { 250d5ac70f0Sopenharmony_ci virt->in_buf_ptr = virt->in_event->data.ext.ptr; 251d5ac70f0Sopenharmony_ci virt->in_buf_size = virt->in_event->data.ext.len; 252d5ac70f0Sopenharmony_ci } else { 253d5ac70f0Sopenharmony_ci virt->in_buf_ptr = virt->in_tmp_buf; 254d5ac70f0Sopenharmony_ci virt->in_buf_size = snd_midi_event_decode(virt->midi_event, 255d5ac70f0Sopenharmony_ci (unsigned char *)virt->in_tmp_buf, 256d5ac70f0Sopenharmony_ci sizeof(virt->in_tmp_buf), 257d5ac70f0Sopenharmony_ci virt->in_event); 258d5ac70f0Sopenharmony_ci } 259d5ac70f0Sopenharmony_ci if (virt->in_buf_size <= 0) 260d5ac70f0Sopenharmony_ci continue; 261d5ac70f0Sopenharmony_ci } 262d5ac70f0Sopenharmony_ci size1 = virt->in_buf_size - virt->in_buf_ofs; 263d5ac70f0Sopenharmony_ci if ((size_t)size1 > size) { 264d5ac70f0Sopenharmony_ci memcpy(buffer, virt->in_buf_ptr + virt->in_buf_ofs, size); 265d5ac70f0Sopenharmony_ci virt->in_buf_ofs += size; 266d5ac70f0Sopenharmony_ci result += size; 267d5ac70f0Sopenharmony_ci break; 268d5ac70f0Sopenharmony_ci } 269d5ac70f0Sopenharmony_ci memcpy(buffer, virt->in_buf_ptr + virt->in_buf_ofs, size1); 270d5ac70f0Sopenharmony_ci size -= size1; 271d5ac70f0Sopenharmony_ci result += size1; 272d5ac70f0Sopenharmony_ci buffer += size1; 273d5ac70f0Sopenharmony_ci virt->in_buf_ofs = 0; 274d5ac70f0Sopenharmony_ci } 275d5ac70f0Sopenharmony_ci 276d5ac70f0Sopenharmony_ci return result; 277d5ac70f0Sopenharmony_ci} 278d5ac70f0Sopenharmony_ci 279d5ac70f0Sopenharmony_cistatic const snd_rawmidi_ops_t snd_rawmidi_virtual_ops = { 280d5ac70f0Sopenharmony_ci .close = snd_rawmidi_virtual_close, 281d5ac70f0Sopenharmony_ci .nonblock = snd_rawmidi_virtual_nonblock, 282d5ac70f0Sopenharmony_ci .info = snd_rawmidi_virtual_info, 283d5ac70f0Sopenharmony_ci .params = snd_rawmidi_virtual_params, 284d5ac70f0Sopenharmony_ci .status = snd_rawmidi_virtual_status, 285d5ac70f0Sopenharmony_ci .drop = snd_rawmidi_virtual_drop, 286d5ac70f0Sopenharmony_ci .drain = snd_rawmidi_virtual_drain, 287d5ac70f0Sopenharmony_ci .write = snd_rawmidi_virtual_write, 288d5ac70f0Sopenharmony_ci .read = snd_rawmidi_virtual_read, 289d5ac70f0Sopenharmony_ci}; 290d5ac70f0Sopenharmony_ci 291d5ac70f0Sopenharmony_ci 292d5ac70f0Sopenharmony_ci/*! \page rawmidi RawMidi interface 293d5ac70f0Sopenharmony_ci 294d5ac70f0Sopenharmony_ci\section rawmidi_virt Virtual RawMidi interface 295d5ac70f0Sopenharmony_ci 296d5ac70f0Sopenharmony_ciThe "virtual" plugin creates a virtual RawMidi instance on the ALSA 297d5ac70f0Sopenharmony_cisequencer, which can be accessed through the connection of the sequencer 298d5ac70f0Sopenharmony_ciports. 299d5ac70f0Sopenharmony_ciThere is no connection established as default. 300d5ac70f0Sopenharmony_ci 301d5ac70f0Sopenharmony_ciFor creating a virtual RawMidi instance, pass "virtual" as its name at 302d5ac70f0Sopenharmony_cicreation. 303d5ac70f0Sopenharmony_ci 304d5ac70f0Sopenharmony_ciExample: 305d5ac70f0Sopenharmony_ci\code 306d5ac70f0Sopenharmony_cisnd_rawmidi_open(&read_handle, &write_handle, "virtual", 0); 307d5ac70f0Sopenharmony_ci\endcode 308d5ac70f0Sopenharmony_ci 309d5ac70f0Sopenharmony_ci*/ 310d5ac70f0Sopenharmony_ci 311d5ac70f0Sopenharmony_ciint snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, 312d5ac70f0Sopenharmony_ci const char *name, snd_seq_t *seq_handle, int port, 313d5ac70f0Sopenharmony_ci int merge, int mode) 314d5ac70f0Sopenharmony_ci{ 315d5ac70f0Sopenharmony_ci int err; 316d5ac70f0Sopenharmony_ci snd_rawmidi_t *rmidi = NULL; 317d5ac70f0Sopenharmony_ci snd_rawmidi_virtual_t *virt = NULL; 318d5ac70f0Sopenharmony_ci struct pollfd pfd; 319d5ac70f0Sopenharmony_ci 320d5ac70f0Sopenharmony_ci if (inputp) 321d5ac70f0Sopenharmony_ci *inputp = 0; 322d5ac70f0Sopenharmony_ci if (outputp) 323d5ac70f0Sopenharmony_ci *outputp = 0; 324d5ac70f0Sopenharmony_ci 325d5ac70f0Sopenharmony_ci virt = calloc(1, sizeof(*virt)); 326d5ac70f0Sopenharmony_ci if (virt == NULL) { 327d5ac70f0Sopenharmony_ci err = -ENOMEM; 328d5ac70f0Sopenharmony_ci goto _err; 329d5ac70f0Sopenharmony_ci } 330d5ac70f0Sopenharmony_ci virt->handle = seq_handle; 331d5ac70f0Sopenharmony_ci virt->port = port; 332d5ac70f0Sopenharmony_ci err = snd_midi_event_new(256, &virt->midi_event); 333d5ac70f0Sopenharmony_ci if (err < 0) 334d5ac70f0Sopenharmony_ci goto _err; 335d5ac70f0Sopenharmony_ci snd_midi_event_init(virt->midi_event); 336d5ac70f0Sopenharmony_ci snd_midi_event_no_status(virt->midi_event, !merge); 337d5ac70f0Sopenharmony_ci 338d5ac70f0Sopenharmony_ci if (inputp) { 339d5ac70f0Sopenharmony_ci rmidi = calloc(1, sizeof(*rmidi)); 340d5ac70f0Sopenharmony_ci if (rmidi == NULL) { 341d5ac70f0Sopenharmony_ci err = -ENOMEM; 342d5ac70f0Sopenharmony_ci goto _err; 343d5ac70f0Sopenharmony_ci } 344d5ac70f0Sopenharmony_ci if (name) 345d5ac70f0Sopenharmony_ci rmidi->name = strdup(name); 346d5ac70f0Sopenharmony_ci rmidi->type = SND_RAWMIDI_TYPE_VIRTUAL; 347d5ac70f0Sopenharmony_ci rmidi->stream = SND_RAWMIDI_STREAM_INPUT; 348d5ac70f0Sopenharmony_ci rmidi->mode = mode; 349d5ac70f0Sopenharmony_ci err = snd_seq_poll_descriptors(seq_handle, &pfd, 1, POLLIN); 350d5ac70f0Sopenharmony_ci if (err < 0) 351d5ac70f0Sopenharmony_ci goto _err; 352d5ac70f0Sopenharmony_ci rmidi->poll_fd = pfd.fd; 353d5ac70f0Sopenharmony_ci rmidi->ops = &snd_rawmidi_virtual_ops; 354d5ac70f0Sopenharmony_ci rmidi->private_data = virt; 355d5ac70f0Sopenharmony_ci virt->open++; 356d5ac70f0Sopenharmony_ci *inputp = rmidi; 357d5ac70f0Sopenharmony_ci } 358d5ac70f0Sopenharmony_ci if (outputp) { 359d5ac70f0Sopenharmony_ci rmidi = calloc(1, sizeof(*rmidi)); 360d5ac70f0Sopenharmony_ci if (rmidi == NULL) { 361d5ac70f0Sopenharmony_ci err = -ENOMEM; 362d5ac70f0Sopenharmony_ci goto _err; 363d5ac70f0Sopenharmony_ci } 364d5ac70f0Sopenharmony_ci if (name) 365d5ac70f0Sopenharmony_ci rmidi->name = strdup(name); 366d5ac70f0Sopenharmony_ci rmidi->type = SND_RAWMIDI_TYPE_VIRTUAL; 367d5ac70f0Sopenharmony_ci rmidi->stream = SND_RAWMIDI_STREAM_OUTPUT; 368d5ac70f0Sopenharmony_ci rmidi->mode = mode; 369d5ac70f0Sopenharmony_ci err = snd_seq_poll_descriptors(seq_handle, &pfd, 1, POLLOUT); 370d5ac70f0Sopenharmony_ci if (err < 0) 371d5ac70f0Sopenharmony_ci goto _err; 372d5ac70f0Sopenharmony_ci rmidi->poll_fd = pfd.fd; 373d5ac70f0Sopenharmony_ci rmidi->ops = &snd_rawmidi_virtual_ops; 374d5ac70f0Sopenharmony_ci rmidi->private_data = virt; 375d5ac70f0Sopenharmony_ci virt->open++; 376d5ac70f0Sopenharmony_ci *outputp = rmidi; 377d5ac70f0Sopenharmony_ci } 378d5ac70f0Sopenharmony_ci 379d5ac70f0Sopenharmony_ci return 0; 380d5ac70f0Sopenharmony_ci 381d5ac70f0Sopenharmony_ci _err: 382d5ac70f0Sopenharmony_ci if (seq_handle) 383d5ac70f0Sopenharmony_ci snd_seq_close(seq_handle); 384d5ac70f0Sopenharmony_ci if (virt) { 385d5ac70f0Sopenharmony_ci if (virt->midi_event) 386d5ac70f0Sopenharmony_ci snd_midi_event_free(virt->midi_event); 387d5ac70f0Sopenharmony_ci free(virt); 388d5ac70f0Sopenharmony_ci } 389d5ac70f0Sopenharmony_ci if (inputp) 390d5ac70f0Sopenharmony_ci free(*inputp); 391d5ac70f0Sopenharmony_ci if (outputp) 392d5ac70f0Sopenharmony_ci free(*outputp); 393d5ac70f0Sopenharmony_ci free(rmidi); 394d5ac70f0Sopenharmony_ci return err; 395d5ac70f0Sopenharmony_ci} 396d5ac70f0Sopenharmony_ci 397d5ac70f0Sopenharmony_ciint _snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, 398d5ac70f0Sopenharmony_ci char *name, snd_config_t *root ATTRIBUTE_UNUSED, 399d5ac70f0Sopenharmony_ci snd_config_t *conf, int mode) 400d5ac70f0Sopenharmony_ci{ 401d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 402d5ac70f0Sopenharmony_ci const char *slave_str = NULL; 403d5ac70f0Sopenharmony_ci int err; 404d5ac70f0Sopenharmony_ci int streams, seq_mode; 405d5ac70f0Sopenharmony_ci int merge = 1; 406d5ac70f0Sopenharmony_ci int port; 407d5ac70f0Sopenharmony_ci unsigned int caps; 408d5ac70f0Sopenharmony_ci snd_seq_t *seq_handle; 409d5ac70f0Sopenharmony_ci 410d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, conf) { 411d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 412d5ac70f0Sopenharmony_ci const char *id; 413d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 414d5ac70f0Sopenharmony_ci continue; 415d5ac70f0Sopenharmony_ci if (snd_rawmidi_conf_generic_id(id)) 416d5ac70f0Sopenharmony_ci continue; 417d5ac70f0Sopenharmony_ci if (strcmp(id, "slave") == 0) { 418d5ac70f0Sopenharmony_ci err = snd_config_get_string(n, &slave_str); 419d5ac70f0Sopenharmony_ci if (err < 0) 420d5ac70f0Sopenharmony_ci return err; 421d5ac70f0Sopenharmony_ci continue; 422d5ac70f0Sopenharmony_ci } 423d5ac70f0Sopenharmony_ci if (strcmp(id, "merge") == 0) { 424d5ac70f0Sopenharmony_ci merge = snd_config_get_bool(n); 425d5ac70f0Sopenharmony_ci continue; 426d5ac70f0Sopenharmony_ci } 427d5ac70f0Sopenharmony_ci return -EINVAL; 428d5ac70f0Sopenharmony_ci } 429d5ac70f0Sopenharmony_ci 430d5ac70f0Sopenharmony_ci streams = 0; 431d5ac70f0Sopenharmony_ci if (inputp) 432d5ac70f0Sopenharmony_ci streams |= SND_SEQ_OPEN_INPUT; 433d5ac70f0Sopenharmony_ci if (outputp) 434d5ac70f0Sopenharmony_ci streams |= SND_SEQ_OPEN_OUTPUT; 435d5ac70f0Sopenharmony_ci if (! streams) 436d5ac70f0Sopenharmony_ci return -EINVAL; 437d5ac70f0Sopenharmony_ci 438d5ac70f0Sopenharmony_ci seq_mode = 0; 439d5ac70f0Sopenharmony_ci if (mode & SND_RAWMIDI_NONBLOCK) 440d5ac70f0Sopenharmony_ci seq_mode |= SND_SEQ_NONBLOCK; 441d5ac70f0Sopenharmony_ci 442d5ac70f0Sopenharmony_ci if (! slave_str) 443d5ac70f0Sopenharmony_ci slave_str = "default"; 444d5ac70f0Sopenharmony_ci err = _snd_seq_open_lconf(&seq_handle, slave_str, streams, seq_mode, 445d5ac70f0Sopenharmony_ci root, conf); 446d5ac70f0Sopenharmony_ci if (err < 0) 447d5ac70f0Sopenharmony_ci return err; 448d5ac70f0Sopenharmony_ci 449d5ac70f0Sopenharmony_ci caps = 0; 450d5ac70f0Sopenharmony_ci if (inputp) 451d5ac70f0Sopenharmony_ci caps |= SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SYNC_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE; 452d5ac70f0Sopenharmony_ci if (outputp) 453d5ac70f0Sopenharmony_ci caps |= SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SYNC_READ | SND_SEQ_PORT_CAP_SUBS_READ; 454d5ac70f0Sopenharmony_ci if (inputp && outputp) 455d5ac70f0Sopenharmony_ci caps |= SNDRV_SEQ_PORT_CAP_DUPLEX; 456d5ac70f0Sopenharmony_ci 457d5ac70f0Sopenharmony_ci port = snd_seq_create_simple_port(seq_handle, "Virtual RawMIDI", 458d5ac70f0Sopenharmony_ci caps, SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC); 459d5ac70f0Sopenharmony_ci if (port < 0) { 460d5ac70f0Sopenharmony_ci snd_seq_close(seq_handle); 461d5ac70f0Sopenharmony_ci return port; 462d5ac70f0Sopenharmony_ci } 463d5ac70f0Sopenharmony_ci 464d5ac70f0Sopenharmony_ci return snd_rawmidi_virtual_open(inputp, outputp, name, seq_handle, port, 465d5ac70f0Sopenharmony_ci merge, mode); 466d5ac70f0Sopenharmony_ci} 467d5ac70f0Sopenharmony_ci 468d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 469d5ac70f0Sopenharmony_ciSND_DLSYM_BUILD_VERSION(_snd_rawmidi_virtual_open, SND_RAWMIDI_DLSYM_VERSION); 470d5ac70f0Sopenharmony_ci#endif 471