// SPDX-License-Identifier: GPL-2.0-or-later /* * Virtual Raw MIDI client on Sequencer * * Copyright (c) 2000 by Takashi Iwai <tiwai@suse.de>, * Jaroslav Kysela <perex@perex.cz>
*/
/* * Virtual Raw MIDI client * * The virtual rawmidi client is a sequencer client which associate * a rawmidi device file. The created rawmidi device file can be * accessed as a normal raw midi, but its MIDI source and destination * are arbitrary. For example, a user-client software synth connected * to this port can be used as a normal midi device as well. * * The virtual rawmidi device accepts also multiple opens. Each file * has its own input buffer, so that no conflict would occur. The drain * of input/output buffer acts only to the local buffer. *
*/
if (atomic)
read_lock(&rdev->filelist_lock); else
down_read(&rdev->filelist_sem);
list_for_each_entry(vmidi, &rdev->filelist, list) { if (!READ_ONCE(vmidi->trigger)) continue; if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) continue;
snd_seq_dump_var_event(ev, dump_to_rawmidi, vmidi->substream);
snd_midi_event_reset_decode(vmidi->parser);
} else {
len = snd_midi_event_decode(vmidi->parser, msg, sizeof(msg), ev); if (len > 0)
snd_rawmidi_receive(vmidi->substream, msg, len);
}
} if (atomic)
read_unlock(&rdev->filelist_lock); else
up_read(&rdev->filelist_sem);
return 0;
}
/* * event handler of virmidi port
*/ staticint snd_virmidi_event_input(struct snd_seq_event *ev, int direct, void *private_data, int atomic, int hop)
{ struct snd_virmidi_dev *rdev;
/* * trigger rawmidi stream for input
*/ staticvoid snd_virmidi_input_trigger(struct snd_rawmidi_substream *substream, int up)
{ struct snd_virmidi *vmidi = substream->runtime->private_data;
WRITE_ONCE(vmidi->trigger, !!up);
}
/* process rawmidi bytes and send events; * we need no lock here for vmidi->event since it's handled only in this work
*/ staticvoid snd_vmidi_output_work(struct work_struct *work)
{ struct snd_virmidi *vmidi; struct snd_rawmidi_substream *substream; unsignedchar input; int ret;
/* discard the outputs in dispatch mode unless subscribed */ if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH &&
!(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) {
snd_rawmidi_proceed(substream); return;
}
while (READ_ONCE(vmidi->trigger)) { if (snd_rawmidi_transmit(substream, &input, 1) != 1) break; if (!snd_midi_event_encode_byte(vmidi->parser, input,
&vmidi->event)) continue; if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) {
ret = snd_seq_kernel_client_dispatch(vmidi->client,
&vmidi->event, false, 0);
vmidi->event.type = SNDRV_SEQ_EVENT_NONE; if (ret < 0) break;
} /* rawmidi input might be huge, allow to have a break */
cond_resched();
}
}
/* * trigger rawmidi stream for output
*/ staticvoid snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, int up)
{ struct snd_virmidi *vmidi = substream->runtime->private_data;
WRITE_ONCE(vmidi->trigger, !!up); if (up)
queue_work(system_highpri_wq, &vmidi->output_work);
}
/* * create a sequencer client and a port
*/ staticint snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev)
{ int client; struct snd_seq_port_callback pcallbacks; struct snd_seq_port_info *pinfo __free(kfree) = NULL; int err;
if (rdev->client >= 0) return 0;
pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL); if (!pinfo) return -ENOMEM;
/* * register the device
*/ staticint snd_virmidi_dev_register(struct snd_rawmidi *rmidi)
{ struct snd_virmidi_dev *rdev = rmidi->private_data; int err;
switch (rdev->seq_mode) { case SNDRV_VIRMIDI_SEQ_DISPATCH:
err = snd_virmidi_dev_attach_seq(rdev); if (err < 0) return err; break; case SNDRV_VIRMIDI_SEQ_ATTACH: if (rdev->client == 0) return -EINVAL; /* should check presence of port more strictly.. */ break; default:
pr_err("ALSA: seq_virmidi: seq_mode is not set: %d\n", rdev->seq_mode); return -EINVAL;
} return 0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.