This allows for connecting up any MIDI device (hardware or software)
through programs such as aconnect or qjackctl that allow one to
connect MIDI outputs to inputs. This is quite convenient for
connecting a virtual keyboard (such as vkeybd or vmpk) to scherzo.
It can also be used to connect a real, hardware MIDI keyboard to
scherzo, but we keep around the code that does a direct connection to
/dev/midi1 since that simplifies things by reducing one step in the
usage, (the user needn't run aconnect nor qjackctl to make the
connection).
* keyboard". Any "piano keyboard" key knows its own octave and
* accidental already. */
int keyboard_octave;
* keyboard". Any "piano keyboard" key knows its own octave and
* accidental already. */
int keyboard_octave;
snd_midi_event_t *snd_midi_event;
mnemon_t mnemon;
snd_midi_event_t *snd_midi_event;
mnemon_t mnemon;
+typedef struct
+{
+ scherzo_t *scherzo;
+ int fd;
+} scherzo_midi_closure_t;
+
static int
on_midi_input (unused (GIOChannel *channel),
unused (GIOCondition condition),
void *user_data)
{
static int
on_midi_input (unused (GIOChannel *channel),
unused (GIOCondition condition),
void *user_data)
{
+ scherzo_midi_closure_t *closure = user_data;
unsigned char buf[MIDI_BUF_SIZE], *next;
unsigned char buf[MIDI_BUF_SIZE], *next;
- scherzo_t *scherzo = user_data;
+ scherzo_t *scherzo = closure->scherzo;
+ int fd = closure->fd;
ssize_t remaining;
snd_seq_event_t event;
ssize_t remaining;
snd_seq_event_t event;
- remaining = read (scherzo->midi_fd, buf, MIDI_BUF_SIZE);
+ remaining = read (fd, buf, MIDI_BUF_SIZE);
next = buf;
while (remaining) {
next = buf;
while (remaining) {
+static void *
+listen_to_alsa_midi (void *data)
+{
+ scherzo_midi_closure_t *closure = data;
+ int out_fd = closure->fd;
+ snd_rawmidi_t *midi_in;
+ unsigned char buf[MIDI_BUF_SIZE];
+ ssize_t bytes;
+ int err;
+
+ err = snd_rawmidi_open (&midi_in, NULL, "virtual", 0);
+ if (err) {
+ fprintf (stderr, "Failed to open virtual MIDI handle.");
+ return NULL;
+ }
+
+ while (1) {
+ bytes = snd_rawmidi_read (midi_in, buf, MIDI_BUF_SIZE);
+ write (out_fd, buf, bytes);
+ }
+
+ return NULL;
+}
+
int
main (int argc, char *argv[])
{
GtkWidget *drawing_area;
int
main (int argc, char *argv[])
{
GtkWidget *drawing_area;
+ int alsa_midi_fd[2];
+ scherzo_midi_closure_t midi_out, alsa_midi_in, alsa_midi_out;
int err;
srand (time (NULL));
int err;
srand (time (NULL));
}
#define MIDI_DEVICE "/dev/midi1"
}
#define MIDI_DEVICE "/dev/midi1"
- scherzo.midi_fd = open (MIDI_DEVICE, O_RDONLY);
- if (scherzo.midi_fd < 0) {
- printf ("failed to open " MIDI_DEVICE ". Midi input will not be available.\n");
- } else {
- GIOChannel *channel;
- channel = g_io_channel_unix_new (scherzo.midi_fd);
+ midi_out.scherzo = &scherzo;
+ midi_out.fd = open (MIDI_DEVICE, O_RDONLY);
+ if (midi_out.fd < 0) {
+ printf ("Failed to open " MIDI_DEVICE ". You will need to connect a MIDI device.\n");
+ } else {
+ channel = g_io_channel_unix_new (midi_out.fd);
g_io_channel_set_encoding (channel, NULL, NULL);
g_io_channel_set_encoding (channel, NULL, NULL);
- g_io_add_watch (channel, G_IO_IN, on_midi_input, &scherzo);
+ g_io_add_watch (channel, G_IO_IN, on_midi_input, &midi_out);
+ pipe (alsa_midi_fd);
+
+ alsa_midi_in.scherzo = &scherzo;
+ alsa_midi_in.fd = alsa_midi_fd[1];
+ g_thread_new ("scherzo-vmidi", listen_to_alsa_midi, &alsa_midi_in);
+
+ alsa_midi_out.scherzo = &scherzo;
+ alsa_midi_out.fd = alsa_midi_fd[0];
+ channel = g_io_channel_unix_new (alsa_midi_out.fd);
+ g_io_channel_set_encoding (channel, NULL, NULL);
+ g_io_add_watch (channel, G_IO_IN, on_midi_input, &alsa_midi_out);
+
scherzo.window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (scherzo.window), 1000, 600);
scherzo.window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (scherzo.window), 1000, 600);