mirror of
https://github.com/libretro/scummvm.git
synced 2025-03-03 00:35:54 +00:00
Unified how we deal with (and how we generate) MIDI sysex messages -- in particular, we now always do so w/o framing the message (documented this with a Doxygen comment in the MidiDriver class)
svn-id: r25630
This commit is contained in:
parent
96162c14ea
commit
4db72c8762
@ -196,15 +196,16 @@ void MidiDriver_ALSA::send(uint32 b) {
|
||||
}
|
||||
|
||||
void MidiDriver_ALSA::sysEx(const byte *msg, uint16 length) {
|
||||
unsigned char buf[1024];
|
||||
unsigned char buf[256];
|
||||
|
||||
if (length > 254) {
|
||||
warning("Cannot send SysEx block - data too large");
|
||||
return;
|
||||
}
|
||||
assert(length + 2 <= 256);
|
||||
|
||||
// Add SysEx frame
|
||||
buf[0] = 0xF0;
|
||||
memcpy(buf + 1, msg, length);
|
||||
buf[length + 1] = 0xF7;
|
||||
|
||||
// Send it
|
||||
snd_seq_ev_set_sysex(&ev, length + 2, &buf);
|
||||
send_event(1);
|
||||
}
|
||||
|
@ -178,22 +178,18 @@ void MidiDriver_CORE::send(uint32 b) {
|
||||
}
|
||||
|
||||
void MidiDriver_CORE::sysEx(const byte *msg, uint16 length) {
|
||||
unsigned char buf[256];
|
||||
|
||||
assert(length + 2 <= 256);
|
||||
assert(_auGraph != NULL);
|
||||
|
||||
// Add SysEx frame if missing
|
||||
byte *buf = 0;
|
||||
if (*msg != 0xF0) {
|
||||
buf = (byte *)malloc(length + 2);
|
||||
buf[0] = 0xF0;
|
||||
memcpy(buf+1, msg, length);
|
||||
buf[length+1] = 0xF7;
|
||||
msg = buf;
|
||||
length += 2;
|
||||
}
|
||||
// Add SysEx frame
|
||||
buf[0] = 0xF0;
|
||||
memcpy(buf + 1, msg, length);
|
||||
buf[length + 1] = 0xF7;
|
||||
|
||||
MusicDeviceSysEx(_synth, msg, length);
|
||||
|
||||
free(buf);
|
||||
// Send it
|
||||
MusicDeviceSysEx(_synth, buf, length+2);
|
||||
}
|
||||
|
||||
MidiDriver *MidiDriver_CORE_create() {
|
||||
|
@ -163,17 +163,13 @@ void MidiDriver_CoreMIDI::sysEx(const byte *msg, uint16 length) {
|
||||
|
||||
packet->timeStamp = 0;
|
||||
|
||||
// Add SysEx frame if missing
|
||||
if (*msg != 0xF0) {
|
||||
packet->length = length + 2;
|
||||
packet->data[0] = 0xF0;
|
||||
memcpy(packet->data + 1, msg, length);
|
||||
packet->data[length + 1] = 0xF7;
|
||||
} else {
|
||||
packet->length = length;
|
||||
memcpy(packet->data, msg, length);
|
||||
}
|
||||
// Add SysEx frame
|
||||
packet->length = length + 2;
|
||||
packet->data[0] = 0xF0;
|
||||
memcpy(packet->data + 1, msg, length);
|
||||
packet->data[length + 1] = 0xF7;
|
||||
|
||||
// Send it
|
||||
MIDISend(mOutPort, mDest, packetList);
|
||||
}
|
||||
|
||||
|
@ -141,15 +141,12 @@ void MidiDriver_SEQ::send(uint32 b) {
|
||||
}
|
||||
|
||||
void MidiDriver_SEQ::sysEx (const byte *msg, uint16 length) {
|
||||
if (length > 254) {
|
||||
warning ("Cannot send SysEx block - data too large");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned char buf [1024];
|
||||
int position = 0;
|
||||
const byte *chr = msg;
|
||||
|
||||
assert(length + 2 <= 256);
|
||||
|
||||
buf[position++] = SEQ_MIDIPUTC;
|
||||
buf[position++] = 0xF0;
|
||||
buf[position++] = _device_num;
|
||||
|
@ -34,7 +34,7 @@
|
||||
class MidiDriver_WIN : public MidiDriver_MPU401 {
|
||||
private:
|
||||
MIDIHDR _streamHeader;
|
||||
byte _streamBuffer [258]; // SysEx blocks should be no larger than 256 bytes
|
||||
byte _streamBuffer[256]; // SysEx blocks should be no larger than 256 bytes
|
||||
HANDLE _streamEvent;
|
||||
HMIDIOUT _mo;
|
||||
bool _isOpen;
|
||||
@ -42,19 +42,19 @@ private:
|
||||
void check_error(MMRESULT result);
|
||||
|
||||
public:
|
||||
MidiDriver_WIN() : _isOpen (false) { }
|
||||
MidiDriver_WIN() : _isOpen(false) { }
|
||||
int open();
|
||||
void close();
|
||||
void send(uint32 b);
|
||||
void sysEx (const byte *msg, uint16 length);
|
||||
void sysEx(const byte *msg, uint16 length);
|
||||
};
|
||||
|
||||
int MidiDriver_WIN::open() {
|
||||
if (_isOpen)
|
||||
return MERR_ALREADY_OPEN;
|
||||
|
||||
_streamEvent = CreateEvent (NULL, true, true, NULL);
|
||||
MMRESULT res = midiOutOpen((HMIDIOUT *)&_mo, MIDI_MAPPER, (unsigned long) _streamEvent, 0, CALLBACK_EVENT);
|
||||
_streamEvent = CreateEvent(NULL, true, true, NULL);
|
||||
MMRESULT res = midiOutOpen((HMIDIOUT *)&_mo, MIDI_MAPPER, (unsigned long)_streamEvent, 0, CALLBACK_EVENT);
|
||||
if (res != MMSYSERR_NOERROR) {
|
||||
check_error(res);
|
||||
CloseHandle(_streamEvent);
|
||||
@ -70,9 +70,9 @@ void MidiDriver_WIN::close() {
|
||||
return;
|
||||
_isOpen = false;
|
||||
MidiDriver_MPU401::close();
|
||||
midiOutUnprepareHeader (_mo, &_streamHeader, sizeof (_streamHeader));
|
||||
midiOutUnprepareHeader(_mo, &_streamHeader, sizeof(_streamHeader));
|
||||
check_error(midiOutClose(_mo));
|
||||
CloseHandle (_streamEvent);
|
||||
CloseHandle(_streamEvent);
|
||||
}
|
||||
|
||||
void MidiDriver_WIN::send(uint32 b) {
|
||||
@ -98,25 +98,29 @@ void MidiDriver_WIN::sysEx(const byte *msg, uint16 length) {
|
||||
return;
|
||||
}
|
||||
|
||||
midiOutUnprepareHeader (_mo, &_streamHeader, sizeof (_streamHeader));
|
||||
_streamBuffer [0] = 0xF0;
|
||||
memcpy(&_streamBuffer[1], msg, length);
|
||||
_streamBuffer [length+1] = 0xF7;
|
||||
assert(length+2 <= 256);
|
||||
|
||||
_streamHeader.lpData = (char *) _streamBuffer;
|
||||
midiOutUnprepareHeader(_mo, &_streamHeader, sizeof(_streamHeader));
|
||||
|
||||
// Add SysEx frame
|
||||
_streamBuffer[0] = 0xF0;
|
||||
memcpy(&_streamBuffer[1], msg, length);
|
||||
_streamBuffer[length+1] = 0xF7;
|
||||
|
||||
_streamHeader.lpData = (char *)_streamBuffer;
|
||||
_streamHeader.dwBufferLength = length + 2;
|
||||
_streamHeader.dwBytesRecorded = length + 2;
|
||||
_streamHeader.dwUser = 0;
|
||||
_streamHeader.dwFlags = 0;
|
||||
|
||||
MMRESULT result = midiOutPrepareHeader (_mo, &_streamHeader, sizeof (_streamHeader));
|
||||
MMRESULT result = midiOutPrepareHeader(_mo, &_streamHeader, sizeof(_streamHeader));
|
||||
if (result != MMSYSERR_NOERROR) {
|
||||
check_error (result);
|
||||
return;
|
||||
}
|
||||
|
||||
ResetEvent(_streamEvent);
|
||||
result = midiOutLongMsg (_mo, &_streamHeader, sizeof (_streamHeader));
|
||||
result = midiOutLongMsg(_mo, &_streamHeader, sizeof(_streamHeader));
|
||||
if (result != MMSYSERR_NOERROR) {
|
||||
check_error(result);
|
||||
SetEvent(_streamEvent);
|
||||
|
@ -110,6 +110,11 @@ void MidiDriver_Zodiac::send(uint32 b) {
|
||||
}
|
||||
|
||||
void MidiDriver_Zodiac::sysEx(const byte *msg, uint16 length) {
|
||||
FIXME: We may have to add the 0xF0 / 0xF7 frame here.
|
||||
Or not -- maybe TwMidiSysEx doesn't expect it either.
|
||||
But since I couldn't find any documentation on this API,
|
||||
I'll leave it to the porter to decide that. -- Fingolfin
|
||||
|
||||
TwMidiSysEx(_midiHandle, 0, (byte *)msg, length);
|
||||
}
|
||||
|
||||
|
@ -1484,7 +1484,7 @@ void IMuseInternal::initGM(MidiDriver *midi) {
|
||||
|
||||
// General MIDI System On message
|
||||
// Resets all GM devices to default settings
|
||||
memcpy(&buffer[0], "\xF0\x7E\x7F\x09\x01\xF7", 6);
|
||||
memcpy(&buffer[0], "\x7E\x7F\x09\x01", 4);
|
||||
midi->sysEx(buffer, 6);
|
||||
debug(2, "GM SysEx: GM System On");
|
||||
_system->delayMillis(200);
|
||||
@ -1499,11 +1499,11 @@ void IMuseInternal::initGM(MidiDriver *midi) {
|
||||
// require individual SysEx commands with unique IDs.
|
||||
|
||||
// Roland GS SysEx ID
|
||||
memcpy(&buffer[0], "\xF0\x41\x10\x42\x12", 5);
|
||||
memcpy(&buffer[0], "\x41\x10\x42\x12", 4);
|
||||
|
||||
// GS Reset
|
||||
memcpy(&buffer[5], "\x40\x00\x7F\x00\x41\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[4], "\x40\x00\x7F\x00\x41", 5);
|
||||
midi->sysEx(buffer, 9);
|
||||
debug(2, "GS SysEx: GS Reset");
|
||||
_system->delayMillis(200);
|
||||
|
||||
@ -1532,8 +1532,8 @@ void IMuseInternal::initGM(MidiDriver *midi) {
|
||||
}
|
||||
|
||||
// Set Master Chorus to 0. The MT-32 has no chorus capability.
|
||||
memcpy(&buffer[5], "\x40\x01\x3A\x00\x05\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[4], "\x40\x01\x3A\x00\x05", 5);
|
||||
midi->sysEx(buffer, 9);
|
||||
debug(2, "GS SysEx: Master Chorus Level is 0");
|
||||
|
||||
// Set Channels 1-16 Reverb to 64, which is the
|
||||
@ -1545,48 +1545,17 @@ void IMuseInternal::initGM(MidiDriver *midi) {
|
||||
// Set Channels 1-16 Pitch Bend Sensitivity to
|
||||
// 12 semitones; then lock the RPN by setting null.
|
||||
for (i = 0; i < 16; ++i) {
|
||||
midi->send(( 0 << 16) | (100 << 8) | (0xB0 | i));
|
||||
midi->send(( 0 << 16) | (101 << 8) | (0xB0 | i));
|
||||
midi->send(( 12 << 16) | (6 << 8) | (0xB0 | i));
|
||||
midi->send(( 0 << 16) | (38 << 8) | (0xB0 | i));
|
||||
midi->send(( 127 << 16) | (100 << 8) | (0xB0 | i));
|
||||
midi->send(( 127 << 16) | (101 << 8) | (0xB0 | i));
|
||||
midi->setPitchBendRange(i, 12);
|
||||
}
|
||||
debug(2, "GM Controller 6 Change: Channels 1-16 Pitch Bend Sensitivity is 12 semitones");
|
||||
|
||||
// Set channels 1-16 Mod. LFO1 Pitch Depth to 4
|
||||
memcpy(&buffer[5], "\x40\x20\x04\x04\x18\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[5], "\x40\x21\x04\x04\x17\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[5], "\x40\x22\x04\x04\x16\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[5], "\x40\x23\x04\x04\x15\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[5], "\x40\x24\x04\x04\x14\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[5], "\x40\x25\x04\x04\x13\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[5], "\x40\x26\x04\x04\x12\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[5], "\x40\x27\x04\x04\x11\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[5], "\x40\x28\x04\x04\x10\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[5], "\x40\x29\x04\x04\x0F\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[5], "\x40\x2A\x04\x04\x0E\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[5], "\x40\x2B\x04\x04\x0D\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[5], "\x40\x2C\x04\x04\x0C\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[5], "\x40\x2D\x04\x04\x0B\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[5], "\x40\x2E\x04\x04\x0A\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[5], "\x40\x2F\x04\x04\x09\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[4], "\x40\x20\x04\x04\x18", 5);
|
||||
for (i = 0; i < 16; ++i) {
|
||||
buffer[5] = 0x20 + i;
|
||||
buffer[8] = 0x18 - i;
|
||||
midi->sysEx(buffer, 9);
|
||||
}
|
||||
debug(2, "GS SysEx: Channels 1-16 Mod. LFO1 Pitch Depth Level is 4");
|
||||
|
||||
// Set Percussion Channel Expression to 80
|
||||
@ -1596,26 +1565,26 @@ void IMuseInternal::initGM(MidiDriver *midi) {
|
||||
// Turn off Percussion Channel Rx. Expression so that
|
||||
// Expression cannot be modified. I don't know why, but
|
||||
// Roland does it this way.
|
||||
memcpy(&buffer[5], "\x40\x10\x0E\x00\x22\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[4], "\x40\x10\x0E\x00\x22", 5);
|
||||
midi->sysEx(buffer, 9);
|
||||
debug(2, "GS SysEx: Percussion Channel Rx. Expression is OFF");
|
||||
|
||||
// Change Reverb Character to 0. I don't think this
|
||||
// sounds most like MT-32, but apparently Roland does.
|
||||
memcpy(&buffer[5], "\x40\x01\x31\x00\x0E\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[4], "\x40\x01\x31\x00\x0E", 5);
|
||||
midi->sysEx(buffer, 9);
|
||||
debug(2, "GS SysEx: Reverb Character is 0");
|
||||
|
||||
// Change Reverb Pre-LF to 4, which is similar to
|
||||
// what MT-32 reverb does.
|
||||
memcpy(&buffer[5], "\x40\x01\x32\x04\x09\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[4], "\x40\x01\x32\x04\x09", 5);
|
||||
midi->sysEx(buffer, 9);
|
||||
debug(2, "GS SysEx: Reverb Pre-LF is 4");
|
||||
|
||||
// Change Reverb Time to 106; the decay on Hall 2
|
||||
// Reverb is too fast compared to the MT-32's
|
||||
memcpy(&buffer[5], "\x40\x01\x34\x6A\x21\xF7", 6);
|
||||
midi->sysEx(buffer, 11);
|
||||
memcpy(&buffer[4], "\x40\x01\x34\x6A\x21", 5);
|
||||
midi->sysEx(buffer, 9);
|
||||
debug(2, "GS SysEx: Reverb Time is 106");
|
||||
}
|
||||
}
|
||||
|
@ -397,7 +397,8 @@ void Player::sysEx(const byte *p, uint16 len) {
|
||||
debugC(DEBUG_IMUSE, "[%02d] SysEx:%s", _id, buf);
|
||||
}
|
||||
|
||||
if (_se->_sysex) (*_se->_sysex) (this, p, len);
|
||||
if (_se->_sysex)
|
||||
(*_se->_sysex)(this, p, len);
|
||||
}
|
||||
|
||||
void Player::decode_sysex_bytes(const byte *src, byte *dst, int len) {
|
||||
|
@ -92,9 +92,9 @@ void GmMusic::setupChannels(uint8 *channelData) {
|
||||
}
|
||||
|
||||
void GmMusic::startDriver(void) {
|
||||
// Send GM System On to reset channel parameters on external and capa$
|
||||
uint8 sysEx[] = "\xf0\x7e\x7f\x09\x01\xf7";
|
||||
_midiDrv->sysEx(sysEx, 6);
|
||||
// Send GM System On to reset channel parameters etc.
|
||||
uint8 sysEx[] = {0x7e, 0x7f, 0x09, 0x01};
|
||||
_midiDrv->sysEx(sysEx, sizeof(sysEx));
|
||||
//_midiDrv->send(0xFF); //ALSA can't handle this.
|
||||
// skip all sysEx as it can't be handled anyways.
|
||||
}
|
||||
|
@ -165,8 +165,24 @@ public:
|
||||
/** Close the midi driver. */
|
||||
virtual void close() = 0;
|
||||
|
||||
/** Output a packed midi command to the midi stream. */
|
||||
/**
|
||||
* Output a packed midi command to the midi stream.
|
||||
* The 'lowest' byte (i.e. b & 0xFF) is the status
|
||||
* code, then come (if used) the first and second
|
||||
* opcode.
|
||||
*/
|
||||
virtual void send(uint32 b) = 0;
|
||||
|
||||
/**
|
||||
* Output a midi command to the midi stream. Convenience wrapper
|
||||
* around the usual 'packed' send method.
|
||||
*
|
||||
* Do NOT use this for sysEx transmission; instead, use the sysEx()
|
||||
* method below.
|
||||
*/
|
||||
void send(byte status, byte firstOp, byte secondOp) {
|
||||
send(status | ((uint32)firstOp << 8) | ((uint32)secondOp << 16));
|
||||
}
|
||||
|
||||
/** Get or set a property. */
|
||||
virtual uint32 property(int prop, uint32 param) { return 0; }
|
||||
@ -175,18 +191,29 @@ public:
|
||||
static const char *getErrorName(int error_code);
|
||||
|
||||
// HIGH-LEVEL SEMANTIC METHODS
|
||||
virtual void setPitchBendRange(byte channel, uint range)
|
||||
{
|
||||
send(( 0 << 16) | (101 << 8) | (0xB0 | channel));
|
||||
send(( 0 << 16) | (100 << 8) | (0xB0 | channel));
|
||||
send((range << 16) | ( 6 << 8) | (0xB0 | channel));
|
||||
send(( 0 << 16) | ( 38 << 8) | (0xB0 | channel));
|
||||
send(( 127 << 16) | (101 << 8) | (0xB0 | channel));
|
||||
send(( 127 << 16) | (100 << 8) | (0xB0 | channel));
|
||||
virtual void setPitchBendRange(byte channel, uint range) {
|
||||
send(0xB0 | channel, 101, 0);
|
||||
send(0xB0 | channel, 100, 0);
|
||||
send(0xB0 | channel, 6, range);
|
||||
send(0xB0 | channel, 38, 0);
|
||||
send(0xB0 | channel, 101, 127);
|
||||
send(0xB0 | channel, 100, 127);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmit a sysEx to the midi device.
|
||||
*
|
||||
* The given msg MUST NOT contain the usual SysEx frame, i.e.
|
||||
* do NOT include the leading 0xF0 and the trailing 0xF7.
|
||||
*
|
||||
* Furthermore, the maximal supported length of a SysEx
|
||||
* is 254 bytes. Passing longer buffers can lead to
|
||||
* undefined behavior (most likely, a crash).
|
||||
*/
|
||||
virtual void sysEx(const byte *msg, uint16 length) { }
|
||||
|
||||
virtual void sysEx_customInstrument(byte channel, uint32 type, const byte *instr) { }
|
||||
|
||||
virtual void metaEvent(byte type, byte *data, uint16 length) { }
|
||||
|
||||
// Timing functions - MidiDriver now operates timers
|
||||
|
@ -121,7 +121,7 @@ void MidiParser::hangingNote(byte channel, byte note, uint32 time_left, bool rec
|
||||
best = ptr;
|
||||
if (ptr->time_left) {
|
||||
if (recycle)
|
||||
_driver->send(0x80 | channel | note << 8);
|
||||
_driver->send(0x80 | channel, note, 0);
|
||||
--_hanging_notes_count;
|
||||
}
|
||||
break;
|
||||
@ -166,7 +166,7 @@ void MidiParser::onTimer() {
|
||||
for (i = ARRAYSIZE(_hanging_notes); i; --i, ++ptr) {
|
||||
if (ptr->time_left) {
|
||||
if (ptr->time_left <= _timer_rate) {
|
||||
_driver->send(0x80 | ptr->channel | ptr->note << 8);
|
||||
_driver->send(0x80 | ptr->channel, ptr->note, 0);
|
||||
ptr->time_left = 0;
|
||||
--_hanging_notes_count;
|
||||
} else {
|
||||
@ -193,7 +193,11 @@ void MidiParser::onTimer() {
|
||||
|
||||
if (info.event == 0xF0) {
|
||||
// SysEx event
|
||||
_driver->sysEx (info.ext.data, (uint16)info.length);
|
||||
// Check for trailing 0xF7 -- if present, remove it.
|
||||
if (info.ext.data[info.length-1] == 0xF7)
|
||||
_driver->sysEx(info.ext.data, (uint16)info.length-1);
|
||||
else
|
||||
_driver->sysEx(info.ext.data, (uint16)info.length);
|
||||
} else if (info.event == 0xFF) {
|
||||
// META event
|
||||
if (info.ext.type == 0x2F) {
|
||||
@ -223,7 +227,7 @@ void MidiParser::onTimer() {
|
||||
else
|
||||
activeNote(info.channel(), info.basic.param1, true);
|
||||
}
|
||||
_driver->send(info.event | info.basic.param1 << 8 | info.basic.param2 << 16);
|
||||
_driver->send(info.event, info.basic.param1, info.basic.param2);
|
||||
}
|
||||
|
||||
|
||||
@ -249,7 +253,7 @@ void MidiParser::allNotesOff() {
|
||||
for (i = 0; i < 128; ++i) {
|
||||
for (j = 0; j < 16; ++j) {
|
||||
if (_active_notes[i] & (1 << j)) {
|
||||
_driver->send(0x80 | j | i << 8);
|
||||
_driver->send(0x80 | j, i, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -257,7 +261,7 @@ void MidiParser::allNotesOff() {
|
||||
// Turn off all hanging notes
|
||||
for (i = 0; i < ARRAYSIZE(_hanging_notes); i++) {
|
||||
if (_hanging_notes[i].time_left) {
|
||||
_driver->send(0x80 | _hanging_notes[i].channel | _hanging_notes[i].note << 8);
|
||||
_driver->send(0x80 | _hanging_notes[i].channel, _hanging_notes[i].note, 0);
|
||||
_hanging_notes[i].time_left = 0;
|
||||
}
|
||||
}
|
||||
@ -267,7 +271,7 @@ void MidiParser::allNotesOff() {
|
||||
// support this...).
|
||||
|
||||
for (i = 0; i < 16; ++i) {
|
||||
_driver->send(0x007BB0 | i); // All notes off
|
||||
_driver->send(0xB0 | i, 0x7b, 0); // All notes off
|
||||
}
|
||||
|
||||
memset(_active_notes, 0, sizeof(_active_notes));
|
||||
@ -323,7 +327,7 @@ void MidiParser::hangAllActiveNotes() {
|
||||
for (j = 0; j < 16; ++j) {
|
||||
if (temp_active[i] & (1 << j)) {
|
||||
activeNote(j, i, false);
|
||||
_driver->send(0x80 | j | i << 8);
|
||||
_driver->send(0x80 | j, i, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -368,10 +372,13 @@ bool MidiParser::jumpToTick(uint32 tick, bool fireEvents) {
|
||||
_driver->metaEvent(info.ext.type, info.ext.data, (uint16) info.length);
|
||||
}
|
||||
} else if (fireEvents) {
|
||||
if (info.event == 0xF0)
|
||||
_driver->sysEx(info.ext.data, (uint16) info.length);
|
||||
else
|
||||
_driver->send(info.event | info.basic.param1 << 8 | info.basic.param2 << 16);
|
||||
if (info.event == 0xF0) {
|
||||
if (info.ext.data[info.length-1] == 0xF7)
|
||||
_driver->sysEx(info.ext.data, (uint16)info.length-1);
|
||||
else
|
||||
_driver->sysEx(info.ext.data, (uint16)info.length);
|
||||
} else
|
||||
_driver->send(info.event, info.basic.param1, info.basic.param2);
|
||||
}
|
||||
|
||||
parseNextEvent(_next_event);
|
||||
@ -411,7 +418,7 @@ void MidiParser::unloadMusic() {
|
||||
|
||||
if (_driver) {
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
_driver->send(0x4000E0 | i);
|
||||
_driver->send(0xE0 | i, 0, 0x40);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,6 +124,9 @@ void MidiParser_SMF::parseNextEvent(EventInfo &info) {
|
||||
info.ext.data = _position._play_pos;
|
||||
_position._play_pos += info.length;
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("MidiParser_XMIDI::parseNextEvent: Unsupported event code %x", info.event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -120,6 +120,9 @@ void MidiParser_XMIDI::parseNextEvent(EventInfo &info) {
|
||||
info.ext.data[2] = 0x20;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("MidiParser_XMIDI::parseNextEvent: Unsupported event code %x", info.event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -565,7 +565,7 @@ public:
|
||||
int getRate() const { return _mixer->getOutputRate(); }
|
||||
|
||||
private:
|
||||
bool _game_SmallHeader;
|
||||
bool _scummSmallHeader; // FIXME: This flag controls a special mode for SCUMM V3 games
|
||||
|
||||
FM_OPL *_opl;
|
||||
byte *_adlib_reg_cache;
|
||||
@ -805,7 +805,7 @@ MidiDriver_ADLIB::MidiDriver_ADLIB(Audio::Mixer *mixer)
|
||||
: MidiDriver_Emulated(mixer) {
|
||||
uint i;
|
||||
|
||||
_game_SmallHeader = false;
|
||||
_scummSmallHeader = false;
|
||||
|
||||
_adlib_reg_cache = 0;
|
||||
|
||||
@ -922,8 +922,8 @@ void MidiDriver_ADLIB::send(byte chan, uint32 b) {
|
||||
uint32 MidiDriver_ADLIB::property(int prop, uint32 param) {
|
||||
switch (prop) {
|
||||
case PROP_OLD_ADLIB: // Older games used a different operator volume algorithm
|
||||
_game_SmallHeader = (param > 0);
|
||||
if (_game_SmallHeader) {
|
||||
_scummSmallHeader = (param > 0);
|
||||
if (_scummSmallHeader) {
|
||||
_timer_p = 473;
|
||||
_timer_q = 1000;
|
||||
} else {
|
||||
@ -1041,7 +1041,7 @@ void MidiDriver_ADLIB::mc_inc_stuff(AdlibVoice *voice, Struct10 *s10, Struct11 *
|
||||
switch (s11->param) {
|
||||
case 0:
|
||||
voice->_vol_2 = s10->start_value + s11->modify_val;
|
||||
if (!_game_SmallHeader) {
|
||||
if (!_scummSmallHeader) {
|
||||
adlib_set_param(voice->_channel, 0,
|
||||
volume_table[lookup_table[voice->_vol_2]
|
||||
[part->_vol_eff >> 2]]);
|
||||
@ -1051,7 +1051,7 @@ void MidiDriver_ADLIB::mc_inc_stuff(AdlibVoice *voice, Struct10 *s10, Struct11 *
|
||||
break;
|
||||
case 13:
|
||||
voice->_vol_1 = s10->start_value + s11->modify_val;
|
||||
if (voice->_twochan && !_game_SmallHeader) {
|
||||
if (voice->_twochan && !_scummSmallHeader) {
|
||||
adlib_set_param(voice->_channel, 13,
|
||||
volume_table[lookup_table[voice->_vol_1]
|
||||
[part->_vol_eff >> 2]]);
|
||||
@ -1253,10 +1253,6 @@ void MidiDriver_ADLIB::adlib_playnote(int channel, int note) {
|
||||
adlib_write(channel + 0xB0, oct | 0x20);
|
||||
}
|
||||
|
||||
// TODO: Replace this with RandomSource? But if so, please note that this
|
||||
// function will be called with negative parameters - getRandomNumber(-1) will
|
||||
// crash ScummVM, random_nr(-1) won't.
|
||||
|
||||
int MidiDriver_ADLIB::random_nr(int a) {
|
||||
static byte _rand_seed = 1;
|
||||
if (_rand_seed & 1) {
|
||||
@ -1310,8 +1306,8 @@ AdlibVoice *MidiDriver_ADLIB::allocate_voice(byte pri) {
|
||||
}
|
||||
}
|
||||
|
||||
/* V3 games don't have note priorities, first comes wins. */
|
||||
if (_game_SmallHeader)
|
||||
/* SCUMM V3 games don't have note priorities, first comes wins. */
|
||||
if (_scummSmallHeader)
|
||||
return NULL;
|
||||
|
||||
if (best)
|
||||
@ -1341,7 +1337,7 @@ void MidiDriver_ADLIB::mc_key_on(AdlibVoice *voice, AdlibInstrument *instr, byte
|
||||
if (voice->_duration != 0)
|
||||
voice->_duration *= 63;
|
||||
|
||||
if (!_game_SmallHeader)
|
||||
if (!_scummSmallHeader)
|
||||
vol_1 = (instr->mod_scalingOutputLevel & 0x3F) + lookup_table[velocity >> 1][instr->mod_waveformSelect >> 2];
|
||||
else
|
||||
vol_1 = 0x3f - (instr->mod_scalingOutputLevel & 0x3F);
|
||||
@ -1349,7 +1345,7 @@ void MidiDriver_ADLIB::mc_key_on(AdlibVoice *voice, AdlibInstrument *instr, byte
|
||||
vol_1 = 0x3F;
|
||||
voice->_vol_1 = vol_1;
|
||||
|
||||
if (!_game_SmallHeader)
|
||||
if (!_scummSmallHeader)
|
||||
vol_2 = (instr->car_scalingOutputLevel & 0x3F) + lookup_table[velocity >> 1][instr->car_waveformSelect >> 2];
|
||||
else
|
||||
vol_2 = 0x3f - (instr->car_scalingOutputLevel & 0x3F);
|
||||
@ -1359,7 +1355,7 @@ void MidiDriver_ADLIB::mc_key_on(AdlibVoice *voice, AdlibInstrument *instr, byte
|
||||
|
||||
c = part->_vol_eff >> 2;
|
||||
|
||||
if (!_game_SmallHeader) {
|
||||
if (!_scummSmallHeader) {
|
||||
vol_2 = volume_table[lookup_table[vol_2][c]];
|
||||
if (voice->_twochan)
|
||||
vol_1 = volume_table[lookup_table[vol_1][c]];
|
||||
@ -1453,7 +1449,7 @@ void MidiDriver_ADLIB::mc_init_stuff(AdlibVoice *voice, Struct10 * s10,
|
||||
|
||||
void MidiDriver_ADLIB::struct10_init(Struct10 *s10, InstrumentExtra *ie) {
|
||||
s10->active = 1;
|
||||
if (!_game_SmallHeader) {
|
||||
if (!_scummSmallHeader) {
|
||||
s10->cur_val = 0;
|
||||
} else {
|
||||
s10->cur_val = s10->start_value;
|
||||
|
Loading…
x
Reference in New Issue
Block a user