/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * 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 3 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ /* * Raw output support by Michael Pearce * Alsa support by Nicolas Noble copied from * both the QuickTime support and (vkeybd https://web.archive.org/web/20070629122111/http://www.alsa-project.org/~iwai/alsa.html) */ // Disable symbol overrides so that we can use system headers. #define FORBIDDEN_SYMBOL_ALLOW_ALL #include "common/scummsys.h" #if defined(USE_SEQ_MIDI) #include "common/error.h" #include "common/textconsole.h" #include "common/util.h" #include "audio/musicplugin.h" #include "audio/mpu401.h" #include #include #include //////////////////////////////////////// // // Unix dev/sequencer driver // //////////////////////////////////////// #define SEQ_MIDIPUTC 5 class MidiDriver_SEQ : public MidiDriver_MPU401 { public: MidiDriver_SEQ(); int open() override; bool isOpen() const override { return _isOpen; } void close() override; void send(uint32 b) override; void sysEx(const byte *msg, uint16 length) override; private: bool _isOpen; int device, _device_num; }; MidiDriver_SEQ::MidiDriver_SEQ() { _isOpen = false; device = 0; _device_num = 0; } int MidiDriver_SEQ::open() { char *device_name; char dev_seq[] = "/dev/sequencer"; if (_isOpen) return MERR_ALREADY_OPEN; _isOpen = true; device = 0; device_name = getenv("SCUMMVM_MIDI"); if (device_name == NULL) { warning("SCUMMVM_MIDI environment variable not set, using /dev/sequencer"); device_name = dev_seq; } device = ::open((device_name), O_RDWR, 0); if (device < 0) { warning("Cannot open rawmidi device %s - using /dev/null (no music will be heard)", device_name); device = (::open(("/dev/null"), O_RDWR, 0)); if (device < 0) error("Cannot open /dev/null to dump midi output"); } if (getenv("SCUMMVM_MIDIPORT")) _device_num = atoi(getenv("SCUMMVM_MIDIPORT")); return 0; } void MidiDriver_SEQ::close() { MidiDriver_MPU401::close(); ::close(device); _isOpen = false; } void MidiDriver_SEQ::send(uint32 b) { midiDriverCommonSend(b); unsigned char buf[256]; int position = 0; switch (b & 0xF0) { case 0x80: case 0x90: case 0xA0: case 0xB0: case 0xE0: buf[position++] = SEQ_MIDIPUTC; buf[position++] = (unsigned char)b; buf[position++] = _device_num; buf[position++] = 0; buf[position++] = SEQ_MIDIPUTC; buf[position++] = (unsigned char)((b >> 8) & 0x7F); buf[position++] = _device_num; buf[position++] = 0; buf[position++] = SEQ_MIDIPUTC; buf[position++] = (unsigned char)((b >> 16) & 0x7F); buf[position++] = _device_num; buf[position++] = 0; break; case 0xC0: case 0xD0: buf[position++] = SEQ_MIDIPUTC; buf[position++] = (unsigned char)b; buf[position++] = _device_num; buf[position++] = 0; buf[position++] = SEQ_MIDIPUTC; buf[position++] = (unsigned char)((b >> 8) & 0x7F); buf[position++] = _device_num; buf[position++] = 0; break; default: warning("MidiDriver_SEQ::send: unknown: %08x", (int)b); break; } if (write(device, buf, position) == -1) warning("MidiDriver_SEQ::send: write failed (%s)", strerror(errno)); } void MidiDriver_SEQ::sysEx(const byte *msg, uint16 length) { unsigned char buf [266*4]; int position = 0; const byte *chr = msg; assert(length + 2 <= 266); midiDriverCommonSysEx(msg, length); buf[position++] = SEQ_MIDIPUTC; buf[position++] = 0xF0; buf[position++] = _device_num; buf[position++] = 0; for (; length; --length, ++chr) { buf[position++] = SEQ_MIDIPUTC; buf[position++] = (unsigned char) *chr & 0x7F; buf[position++] = _device_num; buf[position++] = 0; } buf[position++] = SEQ_MIDIPUTC; buf[position++] = 0xF7; buf[position++] = _device_num; buf[position++] = 0; if (write(device, buf, position) == -1) warning("MidiDriver_SEQ::send: write failed (%s)", strerror(errno)); } // Plugin interface class SeqMusicPlugin : public MusicPluginObject { public: const char *getName() const { return "SEQ"; } const char *getId() const { return "seq"; } MusicDevices getDevices() const; Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const; }; MusicDevices SeqMusicPlugin::getDevices() const { MusicDevices devices; // TODO: Return a different music type depending on the configuration // TODO: List the available devices devices.push_back(MusicDevice(this, "", MT_GM)); return devices; } Common::Error SeqMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const { *mididriver = new MidiDriver_SEQ(); return Common::kNoError; } //#if PLUGIN_ENABLED_DYNAMIC(SEQ) //REGISTER_PLUGIN_DYNAMIC(SEQ, PLUGIN_TYPE_MUSIC, SeqMusicPlugin); //#else REGISTER_PLUGIN_STATIC(SEQ, PLUGIN_TYPE_MUSIC, SeqMusicPlugin); //#endif #endif