// // Programmer: Craig Stuart Sapp // Creation Date: Thu May 11 21:10:02 PDT 2000 // Last Modified: Sat Oct 13 14:51:43 PDT 2001 (updated for ALSA 0.9 interface) // Last Modified: Tue May 26 12:38:18 EDT 2009 (updated for ALSA 1.0 interface) // Filename: ...sig/maint/code/control/Sequencer_alsa.cpp // Web Address: http://sig.sapp.org/src/sig/Sequencer_alsa.cpp // Syntax: C++ // // Description: MIDI input/output capability for the // Linux ALSA raw midi devices. This class // is inherited by the classes MidiInPort_alsa and // MidiOutPort_alsa. // #if defined(LINUX) && defined(ALSA) #include "SigCollection.h" #include "Sequencer_alsa.h" #include #include #include #include #include #include /* for reading filename for MIDI info */ // use the following include for older then ALSA 0.9: //#include // use the following include for ALSA 0.9 and later: #include #ifndef OLDCPP #include using namespace std; #else #include #endif typedef unsigned char uchar; // define static variables: int Sequencer_alsa::class_count = 0; int Sequencer_alsa::initialized = 0; // static variables for MIDI I/O information database int Sequencer_alsa::indevcount = 0; int Sequencer_alsa::outdevcount = 0; SigCollection Sequencer_alsa::rawmidi_in; SigCollection Sequencer_alsa::rawmidi_out; SigCollection Sequencer_alsa::rawmidi_info; SigCollection Sequencer_alsa::midiin_index; SigCollection Sequencer_alsa::midiout_index; /////////////////////////////// // // Sequencer_alsa::Sequencer_alsa -- // default value: autoOpen = 1; // Sequencer_alsa::Sequencer_alsa(int autoOpen) { if (class_count < 0) { cerr << "Unusual class instantiation count: " << class_count << endl; exit(1); } else if (class_count == 0) { buildInfoDatabase(); } // will not autoOpen class_count++; } ////////////////////////////// // // Sequencer_alsa::~Sequencer_alsa -- // Sequencer_alsa::~Sequencer_alsa() { if (class_count == 1) { close(); removeInfoDatabase(); } else if (class_count <= 0) { cerr << "Unusual class instantiation count: " << class_count << endl; exit(1); } class_count--; } ////////////////////////////// // // Sequencer_alsa::close -- close the sequencer device. The device // automatically closes once the program ends. // void Sequencer_alsa::close(void) { int i; for (i=0; i= rawmidi_in.getSize()) { return; } if (rawmidi_in[index] != NULL) { snd_rawmidi_close(rawmidi_in[index]); rawmidi_in[index] = NULL; } } void Sequencer_alsa::closeOutput(int index) { if (index < 0 || index >= rawmidi_out.getSize()) { return; } if (rawmidi_out[index] != NULL) { snd_rawmidi_close(rawmidi_out[index]); rawmidi_out[index] = NULL; } } ////////////////////////////// // // Sequencer_alsa::displayInputs -- display a list of the // available MIDI input devices. // default values: out = cout, initial = "\t" // void Sequencer_alsa::displayInputs(ostream& out, char* initial) { for (int i=0; i= 0) { sprintf(devname, "hw:%d,%d,%d", card, device, subdevice); } else { sprintf(devname, "hw:%d,%d", card, device); } int mode = 0; status = snd_rawmidi_open(&rawmidi_in[index], NULL, devname, mode); if (status == 0) { return 1; } else { return 0; } } int Sequencer_alsa::openOutput(int index) { if (rawmidi_out[index] != NULL) { return 1; } int status; char devname[128] = {0}; int card = rawmidi_info[midiout_index[index]].card; int device = rawmidi_info[midiout_index[index]].device; int subdevice = rawmidi_info[midiout_index[index]].subdevice; if (subdevice >= 0) { sprintf(devname, "hw:%d,%d,%d", card, device, subdevice); } else { sprintf(devname, "hw:%d,%d", card, device); } int mode = SND_RAWMIDI_SYNC; status = snd_rawmidi_open(NULL, &rawmidi_out[index], devname, mode); if (status == 0) { return 1; } else { return 0; } } ////////////////////////////// // // Sequencer_alsa::read -- reads MIDI bytes and also stores the // device from which the byte was read from. Timing is not // saved from the device. If needed, then it would have to // be saved in this function, or just return the raw packet // data (use rawread function). // void Sequencer_alsa::read(int dev, uchar* buf, int count) { if (is_open_in(dev)) { snd_rawmidi_read(rawmidi_in[dev], buf, count); } else { cout << "Warning: MIDI input port " << dev << " is not open for reading" << endl; } } ////////////////////////////// // // Sequencer_alsa::rebuildInfoDatabase -- rebuild the internal // database that keeps track of the MIDI input and output devices. // void Sequencer_alsa::rebuildInfoDatabase(void) { removeInfoDatabase(); buildInfoDatabase(); } /////////////////////////////// // // Sequencer_alsa::write -- Send a byte out the specified MIDI // port which can be either an internal or an external synthesizer. // int Sequencer_alsa::write(int aDevice, int aByte) { uchar byte[1]; byte[0] = (uchar)aByte; return write(aDevice, byte, 1); } int Sequencer_alsa::write(int aDevice, uchar* bytes, int count) { if (is_open_out(aDevice)) { int status = snd_rawmidi_write(rawmidi_out[aDevice], bytes, count); return status == count ? 1 : 0; } else { cerr << "Warning: MIDI output port " << aDevice << " is not open for writing" << endl; return 0; } return 0; } int Sequencer_alsa::write(int aDevice, char* bytes, int count) { return write(aDevice, (uchar*)bytes, count); } int Sequencer_alsa::write(int aDevice, int* bytes, int count) { uchar *newBytes; newBytes = new uchar[count]; for (int i=0; i= 0) { searchForMidiDevicesOnCard(card, info); status = snd_card_next(&card); if (status < 0) { break; } } info.allowGrowth(0); } //////////////////////// // // searchForMidiDevicesOnCard -- for a particular "card" look at all // of the "devices/subdevices" on it and store the information about // triplets of numbers which can handle MIDI input and/or output. // void Sequencer_alsa::searchForMidiDevicesOnCard(int card, SigCollection& info) { snd_ctl_t *ctl; char name[64] = {0}; int device = -1; int status; sprintf(name, "hw:%d", card); if ((status = snd_ctl_open(&ctl, name, 0)) < 0) { cerr << "Cannot open control for card " << card << ": " << snd_strerror(status) << endl; return; } do { status = snd_ctl_rawmidi_next_device(ctl, &device); if (status < 0) { cerr << "Cannot determine device number: " << snd_strerror(status) << endl; break; } if (device >= 0) { searchForMidiSubdevicesOnDevice(ctl, card, device, info); } } while (device >= 0); snd_ctl_close(ctl); } ////////////////////////////// // // Sequencer_alsa::searchForMidiSubdevicesOnDevice -- // void Sequencer_alsa::searchForMidiSubdevicesOnDevice(snd_ctl_t* ctl, int card, int device, SigCollection& rawmidi_info) { snd_rawmidi_info_t *info; const char *name; const char *sub_name; int subs, subs_in, subs_out; int sub, in, out; int status; snd_rawmidi_info_alloca(&info); snd_rawmidi_info_set_device(info, device); snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT); snd_ctl_rawmidi_info(ctl, info); subs_in = snd_rawmidi_info_get_subdevices_count(info); snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_OUTPUT); snd_ctl_rawmidi_info(ctl, info); subs_out = snd_rawmidi_info_get_subdevices_count(info); subs = subs_in > subs_out ? subs_in : subs_out; sub = 0; in = out = 0; if ((status = is_output(ctl, card, device, sub)) < 0) { cerr << "Cannot get rawmidi information " << card << ":" << device << ": " << snd_strerror(status) << endl; return; } else if (status) out = 1; if (status == 0) { if ((status = is_input(ctl, card, device, sub)) < 0) { cerr << "Cannot get rawmidi information " << card << ":" << device <<": " << snd_strerror(status) << endl; return; } } else if (status) in = 1; if (status == 0) return; int index; name = snd_rawmidi_info_get_name(info); sub_name = snd_rawmidi_info_get_subdevice_name(info); if (sub_name[0] == '\0') { if (subs == 1) { rawmidi_info.setSize(rawmidi_info.getSize()+1); index = rawmidi_info.getSize()-1; rawmidi_info[index].card = card; rawmidi_info[index].device = device; rawmidi_info[index].subdevice = -1; strcpy(rawmidi_info[index].name, name); rawmidi_info[index].input = in; rawmidi_info[index].output = out; } else rawmidi_info.setSize(rawmidi_info.getSize()+1); index = rawmidi_info.getSize()-1; rawmidi_info[index].card = card; rawmidi_info[index].device = device; rawmidi_info[index].subdevice = -1; strcpy(rawmidi_info[index].name, name); rawmidi_info[index].input = in; rawmidi_info[index].output = out; } else { sub = 0; for (;;) { rawmidi_info.setSize(rawmidi_info.getSize()+1); index = rawmidi_info.getSize()-1; rawmidi_info[index].card = card; rawmidi_info[index].device = device; rawmidi_info[index].subdevice = sub; strcpy(rawmidi_info[index].name, sub_name); rawmidi_info[index].input = in; rawmidi_info[index].output = out; if (++sub >= subs) break; in = is_input(ctl, card, device, sub); out = is_output(ctl, card, device, sub); snd_rawmidi_info_set_subdevice(info, sub); if (out) { snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_OUTPUT); if ((status = snd_ctl_rawmidi_info(ctl, info)) < 0) { cerr << "Cannot get rawmidi information " << card << ":" << device << ":" << sub << ": " << snd_strerror(status) << endl; break; } } else { snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT); if ((status = snd_ctl_rawmidi_info(ctl, info)) < 0) { cerr << "Cannot get rawmidi information " << card << ":" << device << ":" << sub << ": " << snd_strerror(status) << endl; break; } } sub_name = snd_rawmidi_info_get_subdevice_name(info); } } } ////////////////////////////// // // Sequencer_alsa::is_input -- returns true if specified card/device/sub // can read MIDI data. // int Sequencer_alsa::is_input(snd_ctl_t *ctl, int card, int device, int sub) { snd_rawmidi_info_t *info; int status; snd_rawmidi_info_alloca(&info); snd_rawmidi_info_set_device(info, device); snd_rawmidi_info_set_subdevice(info, sub); snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT); if ((status = snd_ctl_rawmidi_info(ctl, info)) < 0 && status != -ENXIO) { return status; } else if (status == 0) { return 1; } return 0; } ////////////////////////////// // // Sequencer_alsa::is_output -- returns true if specified card/device/sub // can write MIDI data. // int Sequencer_alsa::is_output(snd_ctl_t *ctl, int card, int device, int sub) { snd_rawmidi_info_t *info; int status; snd_rawmidi_info_alloca(&info); snd_rawmidi_info_set_device(info, device); snd_rawmidi_info_set_subdevice(info, sub); snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_OUTPUT); if ((status = snd_ctl_rawmidi_info(ctl, info)) < 0 && status != -ENXIO) { return status; } else if (status == 0) { return 1; } return 0; } #endif /* LINUX and ALSA */ // md5sum: 22b8e7ca6c14c4f0a708d8eaacc0e910 Sequencer_alsa.cpp [20050403]