/* 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