From 4c13a9d897285c735c827c00166609312cbc4dfb Mon Sep 17 00:00:00 2001 From: Sjoerd van der Berg Date: Sun, 6 Apr 2003 06:31:54 +0000 Subject: [PATCH] ALSA Midi Support Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@870 --- src/gui/Makefile.am | 2 +- src/gui/midi.cpp | 6 ++ src/gui/midi_alsa.h | 178 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 src/gui/midi_alsa.h diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 83664b6d..fafd8e72 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -2,5 +2,5 @@ AM_CPPFLAGS = -I$(top_srcdir)/include noinst_LIBRARIES = libgui.a libgui_a_SOURCES = sdlmain.cpp render.cpp render_normal.h render_scale2x.h \ - midi.cpp midi_win32.h midi_oss.h midi_coreaudio.h + midi.cpp midi_win32.h midi_oss.h midi_coreaudio.h midi_alsa.h diff --git a/src/gui/midi.cpp b/src/gui/midi.cpp index 589a2416..6f6ca663 100644 --- a/src/gui/midi.cpp +++ b/src/gui/midi.cpp @@ -86,6 +86,12 @@ MidiHandler Midi_none; #endif +#if defined (HAVE_ALSA) + +#include "midi_alsa.h" + +#endif + static struct { Bitu status; Bitu cmd_len; diff --git a/src/gui/midi_alsa.h b/src/gui/midi_alsa.h new file mode 100644 index 00000000..0f2ae276 --- /dev/null +++ b/src/gui/midi_alsa.h @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2002-2003 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include + +#define ADDR_DELIM ".:" + +#if SND_LIB_MINOR >= 6 +#define snd_seq_flush_output(x) snd_seq_drain_output(x) +#define snd_seq_set_client_group(x,name) /*nop */ +#define my_snd_seq_open(seqp) snd_seq_open(seqp, "hw", SND_SEQ_OPEN_OUTPUT, 0) +#else +/* SND_SEQ_OPEN_OUT causes oops on early version of ALSA */ +#define my_snd_seq_open(seqp) snd_seq_open(seqp, SND_SEQ_OPEN) +#endif + +class MidiHandler_alsa : public MidiHandler { +private: + snd_seq_event_t ev; + snd_seq_t *seq_handle; + int seq_client, seq_port; + int my_client, my_port; + void send_event(int do_flush) { + snd_seq_ev_set_direct(&ev); + snd_seq_ev_set_source(&ev, my_port); + snd_seq_ev_set_dest(&ev, seq_client, seq_port); + + snd_seq_event_output(seq_handle, &ev); + if (do_flush) + snd_seq_flush_output(seq_handle); + } + + int parse_addr(char *arg, int *client, int *port) { + char *p; + + if (isdigit(*arg)) { + if ((p = strpbrk(arg, ADDR_DELIM)) == NULL) + return -1; + *client = atoi(arg); + *port = atoi(p + 1); + } else { + if (*arg == 's' || *arg == 'S') { + *client = SND_SEQ_ADDRESS_SUBSCRIBERS; + *port = 0; + } else + return -1; + } + return 0; + } +public: + MidiHandler_alsa() : MidiHandler() {}; + char* GetName(void) { return "alsa"; } + void PlaySysex(Bit8u * sysex,Bitu len) { + snd_seq_ev_set_sysex(&ev, len, sysex); + } + + void PlayMsg(Bit32u msg) { + unsigned int midiCmd[4]; + ev.type = SND_SEQ_EVENT_OSS; + + if (msg == 247) // to accomadate lure of the temptress + return; + + midiCmd[3] = (msg & 0xFF000000) >> 24; + midiCmd[2] = (msg & 0x00FF0000) >> 16; + midiCmd[1] = (msg & 0x0000FF00) >> 8; + midiCmd[0] = (msg & 0x000000FF); + ev.data.raw32.d[0] = midiCmd[0]; + ev.data.raw32.d[1] = midiCmd[1]; + ev.data.raw32.d[2] = midiCmd[2]; + + unsigned char chanID = midiCmd[0] & 0x0F; + switch (midiCmd[0] & 0xF0) { + case 0x80: + snd_seq_ev_set_noteoff(&ev, chanID, midiCmd[1], midiCmd[2]); + send_event(1); + break; + case 0x90: + snd_seq_ev_set_noteon(&ev, chanID, midiCmd[1], midiCmd[2]); + send_event(1); + break; + case 0xB0: + snd_seq_ev_set_controller(&ev, chanID, midiCmd[1], midiCmd[2]); + send_event(1); + break; + case 0xC0: + snd_seq_ev_set_pgmchange(&ev, chanID, midiCmd[1]); + send_event(0); + break; + case 0xE0:{ + long theBend = ((long)midiCmd[1] + (long)(midiCmd[2] << 7)) - 0x2000; + snd_seq_ev_set_pitchbend(&ev, chanID, theBend); + send_event(1); + } + break; + default: + LOG(LOG_MISC,"ALSA:Unknown Command: %08x", (int)msg); + send_event(1); + break; + } + } + + void Close(void) { + if (seq_handle) + snd_seq_close(seq_handle); + } + + bool Open(const char * conf) { + char var[10]; + unsigned int caps; + + // try to use port specified in config file + if (conf && conf[0]) { + strncpy(var, conf, 10); + if (parse_addr(var, &seq_client, &seq_port) < 0) { + LOG_MSG("ALSA:Invalid alsa port %s", var); + return false; + } + } + // default port if none specified + else if (parse_addr("65:0", &seq_client, &seq_port) < 0) { + LOG_MSG("ALSA:Invalid alsa port 65:0"); + return false; + } + + if (my_snd_seq_open(&seq_handle)) { + LOG_MSG("ALSA:Can't open sequencer"); + return false; + } + + my_client = snd_seq_client_id(seq_handle); + snd_seq_set_client_name(seq_handle, "DOSBOX"); + snd_seq_set_client_group(seq_handle, "input"); + + caps = SND_SEQ_PORT_CAP_READ; + if (seq_client == SND_SEQ_ADDRESS_SUBSCRIBERS) + caps = ~SND_SEQ_PORT_CAP_SUBS_READ; + my_port = + snd_seq_create_simple_port(seq_handle, "DOSBOX", caps, + SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION); + if (my_port < 0) { + snd_seq_close(seq_handle); + LOG_MSG("ALSA:Can't create ALSA port"); + return false; + } + + if (seq_client != SND_SEQ_ADDRESS_SUBSCRIBERS) { + /* subscribe to MIDI port */ + if (snd_seq_connect_to(seq_handle, my_port, seq_client, seq_port) < 0) { + snd_seq_close(seq_handle); + LOG_MSG("ALSA:Can't subscribe to MIDI port (%d:%d)", seq_client, seq_port); + return false; + } + } + + LOG_MSG("ALSA:Client initialised [%d:%d]", seq_client, seq_port); + return true; + } + +}; + +MidiHandler_alsa Midi_alsa;