00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "pent_include.h"
00027 #include "ALSAMidiDriver.h"
00028
00029 #ifdef USE_ALSA_MIDI
00030
00031 const MidiDriver::MidiDriverDesc ALSAMidiDriver::desc =
00032 MidiDriver::MidiDriverDesc ("alsa", createInstance);
00033
00034
00035
00036
00037 #if SND_LIB_MAJOR >= 1 || SND_LIB_MINOR >= 6
00038 #define snd_seq_flush_output(x) snd_seq_drain_output(x)
00039 #define snd_seq_set_client_group(x,name)
00040 #define my_snd_seq_open(seqp) snd_seq_open(seqp, "hw", SND_SEQ_OPEN_OUTPUT, 0)
00041 #else
00042
00043 #define my_snd_seq_open(seqp) snd_seq_open(seqp, SND_SEQ_OPEN)
00044 #endif
00045
00046 #define ALSA_PORT "65:0"
00047 #define ADDR_DELIM ".:"
00048
00049
00050 ALSAMidiDriver::ALSAMidiDriver()
00051 : isOpen(false), seq_handle(0), seq_client(0), seq_port(0),
00052 my_client(0), my_port(0)
00053 {
00054 memset(&ev, 0, sizeof(ev));
00055 }
00056
00057 int ALSAMidiDriver::open() {
00058 std::string arg;
00059 unsigned int caps;
00060
00061 if (isOpen)
00062 return -1;
00063
00064 arg = getConfigSetting("alsa_port", ALSA_PORT);
00065
00066 if (parse_addr(arg, &seq_client, &seq_port) < 0) {
00067 perr << "ALSAMidiDriver: Invalid port: " << arg << std::endl;
00068 return -1;
00069 }
00070
00071 if (my_snd_seq_open(&seq_handle)) {
00072 perr << "ALSAMidiDriver: Can't open sequencer" << std::endl;
00073 return -1;
00074 }
00075
00076 isOpen = true;
00077
00078 my_client = snd_seq_client_id(seq_handle);
00079 snd_seq_set_client_name(seq_handle, "PENTAGRAM");
00080 snd_seq_set_client_group(seq_handle, "input");
00081
00082 caps = SND_SEQ_PORT_CAP_READ;
00083 if (seq_client == SND_SEQ_ADDRESS_SUBSCRIBERS)
00084 caps = ~SND_SEQ_PORT_CAP_SUBS_READ;
00085 my_port =
00086 snd_seq_create_simple_port(seq_handle, "PENTAGRAM", caps,
00087 SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION);
00088 if (my_port < 0) {
00089 snd_seq_close(seq_handle);
00090 isOpen = false;
00091 perr << "ALSAMidiDriver: Can't create port" << std::endl;
00092 return -1;
00093 }
00094
00095 if (seq_client != SND_SEQ_ADDRESS_SUBSCRIBERS) {
00096
00097 if (snd_seq_connect_to(seq_handle, my_port, seq_client, seq_port) < 0) {
00098 snd_seq_close(seq_handle);
00099 isOpen = false;
00100 perr << "ALSAMidiDriver: "
00101 << "Can't subscribe to MIDI port (" << seq_client
00102 << ":" << seq_port << ")" << std::endl;
00103 return -1;
00104 }
00105 }
00106
00107 pout << "ALSA client initialised [" << seq_client << ":"
00108 << seq_port << "]" << std::endl;
00109
00110 return 0;
00111 }
00112
00113 void ALSAMidiDriver::close() {
00114 isOpen = false;
00115 if (seq_handle)
00116 snd_seq_close(seq_handle);
00117 }
00118
00119 void ALSAMidiDriver::send(uint32 b) {
00120 unsigned int midiCmd[4];
00121 ev.type = SND_SEQ_EVENT_OSS;
00122
00123 midiCmd[3] = (b & 0xFF000000) >> 24;
00124 midiCmd[2] = (b & 0x00FF0000) >> 16;
00125 midiCmd[1] = (b & 0x0000FF00) >> 8;
00126 midiCmd[0] = (b & 0x000000FF);
00127 ev.data.raw32.d[0] = midiCmd[0];
00128 ev.data.raw32.d[1] = midiCmd[1];
00129 ev.data.raw32.d[2] = midiCmd[2];
00130
00131 unsigned char chanID = midiCmd[0] & 0x0F;
00132 switch (midiCmd[0] & 0xF0) {
00133 case 0x80:
00134 snd_seq_ev_set_noteoff(&ev, chanID, midiCmd[1], midiCmd[2]);
00135 send_event(1);
00136 break;
00137 case 0x90:
00138 snd_seq_ev_set_noteon(&ev, chanID, midiCmd[1], midiCmd[2]);
00139 send_event(1);
00140 break;
00141 case 0xB0:
00142
00143 snd_seq_ev_set_controller(&ev, chanID, midiCmd[1], midiCmd[2]);
00144 send_event(1);
00145 break;
00146 case 0xC0:
00147 snd_seq_ev_set_pgmchange(&ev, chanID, midiCmd[1]);
00148 send_event(0);
00149 break;
00150 case 0xD0:
00151 snd_seq_ev_set_chanpress(&ev, chanID, midiCmd[1]);
00152 send_event(0);
00153 break;
00154 case 0xE0:{
00155
00156
00157 long theBend = ((long)midiCmd[1] + (long)(midiCmd[2] << 7)) - 0x2000;
00158 snd_seq_ev_set_pitchbend(&ev, chanID, theBend);
00159 send_event(1);
00160 }
00161 break;
00162
00163 default:
00164 perr << "ALSAMidiDriver: Unknown Command: "
00165 << std::hex << (int)b << std::dec << std::endl;
00166
00167 send_event(1);
00168 break;
00169 }
00170 }
00171
00172 void ALSAMidiDriver::send_sysex(uint8 status,const uint8 *msg,uint16 length) {
00173 unsigned char buf[1024];
00174
00175 if (length > 511) {
00176 perr << "ALSAMidiDriver: "
00177 << "Cannot send SysEx block - data too large" << std::endl;
00178 return;
00179 }
00180 buf[0] = status;
00181 memcpy(buf + 1, msg, length);
00182 snd_seq_ev_set_sysex(&ev, length + 1, &buf);
00183 send_event(1);
00184 }
00185
00186
00187 int ALSAMidiDriver::parse_addr(std::string _arg, int *client, int *port) {
00188 const char* arg = _arg.c_str();
00189 char *p;
00190
00191 if (isdigit(*arg)) {
00192 if ((p = strpbrk(arg, ADDR_DELIM)) == NULL)
00193 return -1;
00194 *client = atoi(arg);
00195 *port = atoi(p + 1);
00196 } else {
00197 if (*arg == 's' || *arg == 'S') {
00198 *client = SND_SEQ_ADDRESS_SUBSCRIBERS;
00199 *port = 0;
00200 } else
00201 return -1;
00202 }
00203 return 0;
00204 }
00205
00206 void ALSAMidiDriver::send_event(int do_flush) {
00207 snd_seq_ev_set_direct(&ev);
00208 snd_seq_ev_set_source(&ev, my_port);
00209 snd_seq_ev_set_dest(&ev, seq_client, seq_port);
00210
00211 snd_seq_event_output(seq_handle, &ev);
00212 if (do_flush)
00213 snd_seq_flush_output(seq_handle);
00214 }
00215
00216 #endif