mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 13:50:13 +00:00
added support for Adlib tracks
svn-id: r29509
This commit is contained in:
parent
b95a102011
commit
de750efced
@ -252,6 +252,10 @@
|
||||
RelativePath="..\..\engines\queen\logic.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\queen\midiadlib.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\queen\music.cpp"
|
||||
>
|
||||
|
628
engines/queen/midiadlib.cpp
Normal file
628
engines/queen/midiadlib.cpp
Normal file
@ -0,0 +1,628 @@
|
||||
/* 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 2
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/endian.h"
|
||||
|
||||
#include "sound/fmopl.h"
|
||||
#include "sound/softsynth/emumidi.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
class AdlibMidiChannel;
|
||||
|
||||
class AdlibMidiDriver : public MidiDriver_Emulated {
|
||||
public:
|
||||
|
||||
AdlibMidiDriver(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer) {}
|
||||
~AdlibMidiDriver() {}
|
||||
|
||||
// MidiDriver
|
||||
int open();
|
||||
void close();
|
||||
void send(uint32 b);
|
||||
void metaEvent(byte type, byte *data, uint16 length);
|
||||
MidiChannel *allocateChannel() { return 0; }
|
||||
MidiChannel *getPercussionChannel() { return 0; }
|
||||
|
||||
// AudioStream
|
||||
bool isStereo() const { return false; }
|
||||
int getRate() const { return _mixer->getOutputRate(); }
|
||||
|
||||
// MidiDriver_Emulated
|
||||
void generateSamples(int16 *buf, int len);
|
||||
|
||||
private:
|
||||
|
||||
void handleMidiEvent0x90_NoteOn(int channel, int param1, int param2);
|
||||
void handleSequencerSpecificMetaEvent1(int channel, const uint8 *data);
|
||||
void handleSequencerSpecificMetaEvent2(uint8 value);
|
||||
void handleSequencerSpecificMetaEvent3(uint8 value);
|
||||
|
||||
void Adlib_Write(uint8 port, uint8 value);
|
||||
void Adlib_SetupCard();
|
||||
void Adlib_SetupChannels(int fl);
|
||||
void Adlib_ResetAmpVibratoRhythm(int am, int vib, int kso);
|
||||
void Adlib_ResetChannels();
|
||||
void Adlib_SetAmpVibratoRhythm();
|
||||
void Adlib_SetCSMKeyboardSplit();
|
||||
void Adlib_SetNoteMul(int mul);
|
||||
void Adlib_SetWaveformSelect(int fl);
|
||||
void Adlib_SetPitchBend(int channel, int range);
|
||||
void Adlib_PlayNote(int channel);
|
||||
uint8 Adlib_PlayNoteHelper(int channel, int note1, int note2, int oct);
|
||||
void Adlib_TurnNoteOff(int channel);
|
||||
void Adlib_TurnNoteOn(int channel, int note);
|
||||
void Adlib_SetupChannelFromSequence(int channel, const uint8 *src, int fl);
|
||||
void Adlib_SetupChannel(int channel, const uint16 *src, int fl);
|
||||
void Adlib_SetNoteVolume(int channel, int volume);
|
||||
void Adlib_SetupChannelHelper(int channel);
|
||||
void Adlib_SetChannel0x40(int channel);
|
||||
void Adlib_SetChannel0xC0(int channel);
|
||||
void Adlib_SetChannel0x60(int channel);
|
||||
void Adlib_SetChannel0x80(int channel);
|
||||
void Adlib_SetChannel0x20(int channel);
|
||||
void Adlib_SetChannel0xE0(int channel);
|
||||
|
||||
FM_OPL *_opl;
|
||||
int _midiNumberOfChannels;
|
||||
int _adlibNoteMul;
|
||||
int _adlibWaveformSelect;
|
||||
int _adlibAMDepthEq48;
|
||||
int _adlibVibratoDepthEq14;
|
||||
int _adlibRhythmEnabled;
|
||||
int _adlibKeyboardSplitOn;
|
||||
int _adlibVibratoRhythm;
|
||||
uint8 _midiChannelsFreqTable[9];
|
||||
uint8 _adlibChannelsLevelKeyScalingTable[11];
|
||||
uint8 _adlibSetupChannelSequence1[14 * 18];
|
||||
uint16 _adlibSetupChannelSequence2[14];
|
||||
int16 _midiChannelsNote2Table[9];
|
||||
uint8 _midiChannelsNote1Table[9];
|
||||
uint8 _midiChannelsOctTable[9];
|
||||
uint16 _adlibChannelsVolume[11];
|
||||
uint16 _adlibMetaSequenceData[28];
|
||||
|
||||
static const uint8 _adlibChannelsMappingTable1[];
|
||||
static const uint8 _adlibChannelsNoFeedback[];
|
||||
static const uint8 _adlibChannelsMappingTable2[];
|
||||
static const uint8 _adlibChannelsMappingTable3[];
|
||||
static const uint8 _adlibChannelsKeyScalingTable1[];
|
||||
static const uint8 _adlibChannelsKeyScalingTable2[];
|
||||
static const uint8 _adlibChannelsVolumeTable[];
|
||||
static const uint8 _adlibInitSequenceData1[];
|
||||
static const uint8 _adlibInitSequenceData2[];
|
||||
static const uint8 _adlibInitSequenceData3[];
|
||||
static const uint8 _adlibInitSequenceData4[];
|
||||
static const uint8 _adlibInitSequenceData5[];
|
||||
static const uint8 _adlibInitSequenceData6[];
|
||||
static const uint8 _adlibInitSequenceData7[];
|
||||
static const uint8 _adlibInitSequenceData8[];
|
||||
static const int16 _midiChannelsNoteTable[];
|
||||
static const int16 _midiNoteFreqTable[];
|
||||
};
|
||||
|
||||
int AdlibMidiDriver::open() {
|
||||
MidiDriver_Emulated::open();
|
||||
_opl = makeAdlibOPL(getRate());
|
||||
Adlib_SetupCard();
|
||||
for (int i = 0; i < 11; ++i) {
|
||||
_adlibChannelsVolume[i] = 0;
|
||||
Adlib_SetNoteVolume(i, 0);
|
||||
Adlib_TurnNoteOff(i);
|
||||
}
|
||||
_mixer->playInputStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, false, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::close() {
|
||||
_mixer->stopHandle(_mixerSoundHandle);
|
||||
OPLDestroy(_opl);
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::send(uint32 b) {
|
||||
int channel = b & 15;
|
||||
int cmd = (b >> 4) & 7;
|
||||
int param1 = (b >> 8) & 255;
|
||||
int param2 = (b >> 16) & 255;
|
||||
switch (cmd) {
|
||||
case 0:
|
||||
Adlib_TurnNoteOff(channel);
|
||||
break;
|
||||
case 1:
|
||||
handleMidiEvent0x90_NoteOn(channel, param1, param2);
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
case 5:
|
||||
Adlib_SetNoteVolume(channel, param1);
|
||||
_adlibChannelsVolume[channel] = param1;
|
||||
break;
|
||||
case 6:
|
||||
Adlib_SetPitchBend(channel, param1 | (param2 << 7));
|
||||
break;
|
||||
default:
|
||||
// warning("Unhandled cmd %d channel %d (0x%X)\n", cmd, channel, b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::metaEvent(byte type, byte *data, uint16 length) {
|
||||
int event = 0;
|
||||
if (length > 4 && READ_BE_UINT32(data) == 0x3F00) {
|
||||
event = data[4];
|
||||
switch (event) {
|
||||
case 1:
|
||||
if (length == 34) {
|
||||
handleSequencerSpecificMetaEvent1(data[5], data + 6);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (length == 6) {
|
||||
handleSequencerSpecificMetaEvent2(data[5]);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (length == 6) {
|
||||
handleSequencerSpecificMetaEvent3(data[5]);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
warning("Unhandled meta event %d len %d", event, length);
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::generateSamples(int16 *data, int len) {
|
||||
memset(data, 0, sizeof(int16) * len);
|
||||
YM3812UpdateOne(_opl, data, len);
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::handleSequencerSpecificMetaEvent1(int channel, const uint8 *data) {
|
||||
for (int i = 0; i < 28; ++i) {
|
||||
_adlibMetaSequenceData[i] = data[i];
|
||||
}
|
||||
if (_midiNumberOfChannels > channel) {
|
||||
const uint8 *p;
|
||||
if (_adlibRhythmEnabled) {
|
||||
p = &_adlibChannelsKeyScalingTable2[channel * 2];
|
||||
} else {
|
||||
p = &_adlibChannelsKeyScalingTable1[channel * 2];
|
||||
}
|
||||
Adlib_SetupChannel(p[0], _adlibMetaSequenceData, _adlibMetaSequenceData[26]);
|
||||
if (p[1] != 255) {
|
||||
Adlib_SetupChannel(p[1], _adlibMetaSequenceData + 13, _adlibMetaSequenceData[27]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::handleSequencerSpecificMetaEvent2(uint8 value) {
|
||||
_adlibRhythmEnabled = value;
|
||||
_midiNumberOfChannels = _adlibRhythmEnabled ? 11 : 9;
|
||||
Adlib_SetAmpVibratoRhythm();
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::handleSequencerSpecificMetaEvent3(uint8 value) {
|
||||
Adlib_SetNoteMul(value);
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::handleMidiEvent0x90_NoteOn(int channel, int param1, int param2) { // note, volume
|
||||
if (param2 == 0) {
|
||||
Adlib_TurnNoteOff(channel);
|
||||
_adlibChannelsVolume[channel] = param2;
|
||||
} else {
|
||||
Adlib_SetNoteVolume(channel, param2);
|
||||
_adlibChannelsVolume[channel] = param2;
|
||||
Adlib_TurnNoteOff(channel);
|
||||
Adlib_TurnNoteOn(channel, param1);
|
||||
}
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_Write(uint8 port, uint8 value) {
|
||||
OPLWriteReg(_opl, port, value);
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_SetupCard() {
|
||||
for (int i = 1; i <= 0xF5; ++i) {
|
||||
Adlib_Write(i, 0);
|
||||
}
|
||||
Adlib_Write(4, 6);
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
_midiChannelsNote2Table[i] = 8192;
|
||||
_midiChannelsOctTable[i] = 0;
|
||||
_midiChannelsNote1Table[i] = 0;
|
||||
_midiChannelsFreqTable[i] = 0;
|
||||
}
|
||||
memset(_adlibChannelsLevelKeyScalingTable, 127, 11);
|
||||
Adlib_SetupChannels(0);
|
||||
Adlib_ResetAmpVibratoRhythm(0, 0, 0);
|
||||
Adlib_SetNoteMul(1);
|
||||
Adlib_SetWaveformSelect(1);
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_SetupChannels(int fl) {
|
||||
if (fl != 0) {
|
||||
_midiChannelsNote1Table[8] = 24;
|
||||
_midiChannelsNote2Table[8] = 8192;
|
||||
Adlib_PlayNote(8);
|
||||
_midiChannelsNote1Table[7] = 31;
|
||||
_midiChannelsNote2Table[7] = 8192;
|
||||
Adlib_PlayNote(7);
|
||||
}
|
||||
_adlibRhythmEnabled = fl;
|
||||
_midiNumberOfChannels = fl ? 11 : 9;
|
||||
_adlibVibratoRhythm = 0;
|
||||
_adlibAMDepthEq48 = 0;
|
||||
_adlibVibratoDepthEq14 = 0;
|
||||
_adlibKeyboardSplitOn = 0;
|
||||
Adlib_ResetChannels();
|
||||
Adlib_SetAmpVibratoRhythm();
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_ResetAmpVibratoRhythm(int am, int vib, int kso) {
|
||||
_adlibAMDepthEq48 = am;
|
||||
_adlibVibratoDepthEq14 = vib;
|
||||
_adlibKeyboardSplitOn = kso;
|
||||
Adlib_SetAmpVibratoRhythm();
|
||||
Adlib_SetCSMKeyboardSplit();
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_ResetChannels() {
|
||||
for (int i = 0; i < 18; ++i) {
|
||||
Adlib_SetupChannelFromSequence(i, _adlibChannelsNoFeedback[i] ? _adlibInitSequenceData2 : _adlibInitSequenceData1, 0);
|
||||
}
|
||||
if (_adlibRhythmEnabled) {
|
||||
Adlib_SetupChannelFromSequence(12, _adlibInitSequenceData3, 0);
|
||||
Adlib_SetupChannelFromSequence(15, _adlibInitSequenceData4, 0);
|
||||
Adlib_SetupChannelFromSequence(16, _adlibInitSequenceData5, 0);
|
||||
Adlib_SetupChannelFromSequence(14, _adlibInitSequenceData6, 0);
|
||||
Adlib_SetupChannelFromSequence(17, _adlibInitSequenceData7, 0);
|
||||
Adlib_SetupChannelFromSequence(13, _adlibInitSequenceData8, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_SetAmpVibratoRhythm() {
|
||||
uint8 value = 0;
|
||||
if (_adlibAMDepthEq48) {
|
||||
value |= 0x80;
|
||||
}
|
||||
if (_adlibVibratoDepthEq14) {
|
||||
value |= 0x40;
|
||||
}
|
||||
if (_adlibRhythmEnabled) {
|
||||
value |= 0x20;
|
||||
}
|
||||
Adlib_Write(0xBD, value | _adlibVibratoRhythm);
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_SetCSMKeyboardSplit() {
|
||||
uint8 value = _adlibKeyboardSplitOn ? 0x40 : 0;
|
||||
Adlib_Write(8, value);
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_SetNoteMul(int mul) {
|
||||
if (mul > 12) {
|
||||
mul = 12;
|
||||
} else if (mul < 1) {
|
||||
mul = 1;
|
||||
}
|
||||
_adlibNoteMul = mul;
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_SetWaveformSelect(int fl) {
|
||||
_adlibWaveformSelect = fl ? 0x20 : 0;
|
||||
for (int i = 0; i < 18; ++i) {
|
||||
Adlib_Write(0xE0 + _adlibChannelsMappingTable1[i], 0);
|
||||
}
|
||||
Adlib_Write(1, _adlibWaveformSelect);
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_SetPitchBend(int channel, int range) {
|
||||
if ((_adlibRhythmEnabled && channel <= 6) || channel < 9) {
|
||||
if (range > 16383) {
|
||||
range = 16383;
|
||||
}
|
||||
_midiChannelsNote2Table[channel] = range;
|
||||
Adlib_PlayNote(channel);
|
||||
}
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_PlayNote(int channel) {
|
||||
_midiChannelsFreqTable[channel] = Adlib_PlayNoteHelper(channel, _midiChannelsNote1Table[channel], _midiChannelsNote2Table[channel], _midiChannelsOctTable[channel]);
|
||||
}
|
||||
|
||||
uint8 AdlibMidiDriver::Adlib_PlayNoteHelper(int channel, int note1, int note2, int oct) {
|
||||
int n = ((note2 * _midiChannelsNoteTable[channel]) >> 8) - 8192;
|
||||
if (n != 0) {
|
||||
n >>= 5;
|
||||
n *= _adlibNoteMul;
|
||||
}
|
||||
n += (note1 << 8) + 8;
|
||||
n >>= 4;
|
||||
if (n < 0) {
|
||||
n = 0;
|
||||
} else if (n > 1535) {
|
||||
n = 1535;
|
||||
}
|
||||
int index = (((n >> 4) % 12) << 4) | (n & 0xF);
|
||||
int f = _midiNoteFreqTable[index];
|
||||
int o = (n >> 4) / 12 - 1;
|
||||
if (f < 0) {
|
||||
++o;
|
||||
}
|
||||
if (o < 0) {
|
||||
++o;
|
||||
f >>= 1;
|
||||
}
|
||||
Adlib_Write(0xA0 + channel, f & 0xFF);
|
||||
int value = ((f >> 8) & 3) | (o << 2) | oct;
|
||||
Adlib_Write(0xB0 + channel, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_TurnNoteOff(int channel) {
|
||||
if ((_adlibRhythmEnabled && channel <= 6) || channel < 9) {
|
||||
_midiChannelsOctTable[channel] = 0;
|
||||
_midiChannelsFreqTable[channel] &= ~0x20;
|
||||
Adlib_Write(0xB0 + channel, _midiChannelsFreqTable[channel]);
|
||||
} else if (_adlibRhythmEnabled && channel <= 10) {
|
||||
_adlibVibratoRhythm &= ~(1 << (4 - (channel - 6)));
|
||||
Adlib_SetAmpVibratoRhythm();
|
||||
}
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_TurnNoteOn(int channel, int note) {
|
||||
note -= 12;
|
||||
if (note < 0) {
|
||||
note = 0;
|
||||
}
|
||||
if ((_adlibRhythmEnabled && channel <= 6) || channel < 9) {
|
||||
_midiChannelsNote1Table[channel] = note;
|
||||
_midiChannelsOctTable[channel] = 0x20;
|
||||
Adlib_PlayNote(channel);
|
||||
} else if (_adlibRhythmEnabled && channel <= 10) {
|
||||
if (channel == 6) {
|
||||
_midiChannelsNote1Table[6] = note;
|
||||
Adlib_PlayNote(channel);
|
||||
} else if (channel == 8 && _midiChannelsNote1Table[8] == note) {
|
||||
_midiChannelsNote1Table[8] = note;
|
||||
_midiChannelsNote1Table[7] = note + 7;
|
||||
Adlib_PlayNote(8);
|
||||
Adlib_PlayNote(7);
|
||||
}
|
||||
_adlibVibratoRhythm = 1 << (4 - (channel - 6));
|
||||
Adlib_SetAmpVibratoRhythm();
|
||||
}
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_SetupChannelFromSequence(int channel, const uint8 *src, int fl) {
|
||||
for (int i = 0; i < 13; ++i) {
|
||||
_adlibSetupChannelSequence2[i] = src[i];
|
||||
}
|
||||
Adlib_SetupChannel(channel, _adlibSetupChannelSequence2, fl);
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_SetupChannel(int channel, const uint16 *src, int fl) {
|
||||
for (int i = 0; i < 13; ++i) {
|
||||
_adlibSetupChannelSequence1[14 * channel + i] = src[i];
|
||||
}
|
||||
_adlibSetupChannelSequence1[14 * channel + 13] = fl & 3;
|
||||
Adlib_SetupChannelHelper(channel);
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_SetNoteVolume(int channel, int volume) {
|
||||
if (_midiNumberOfChannels > channel) {
|
||||
if (volume > 127) {
|
||||
volume = 127;
|
||||
}
|
||||
_adlibChannelsLevelKeyScalingTable[channel] = volume;
|
||||
const uint8 *p;
|
||||
if (_adlibRhythmEnabled) {
|
||||
p = &_adlibChannelsKeyScalingTable2[channel * 2];
|
||||
} else {
|
||||
p = &_adlibChannelsKeyScalingTable1[channel * 2];
|
||||
}
|
||||
Adlib_SetChannel0x40(p[0]);
|
||||
if (p[1] != 255) {
|
||||
Adlib_SetChannel0x40(p[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_SetupChannelHelper(int channel) {
|
||||
Adlib_SetAmpVibratoRhythm();
|
||||
Adlib_SetCSMKeyboardSplit();
|
||||
Adlib_SetChannel0x40(channel);
|
||||
Adlib_SetChannel0xC0(channel);
|
||||
Adlib_SetChannel0x60(channel);
|
||||
Adlib_SetChannel0x80(channel);
|
||||
Adlib_SetChannel0x20(channel);
|
||||
Adlib_SetChannel0xE0(channel);
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_SetChannel0x40(int channel) {
|
||||
int index, value, fl;
|
||||
|
||||
if (_adlibRhythmEnabled) {
|
||||
index = _adlibChannelsMappingTable3[channel];
|
||||
} else {
|
||||
index = _adlibChannelsMappingTable2[channel];
|
||||
}
|
||||
value = 63 - (_adlibSetupChannelSequence1[channel * 14 + 8] & 63);
|
||||
fl = 0;
|
||||
if (_adlibRhythmEnabled && index > 6) {
|
||||
fl = -1;
|
||||
}
|
||||
if (_adlibChannelsNoFeedback[channel] || _adlibSetupChannelSequence1[channel * 14 + 12] == 0 || fl != 0) {
|
||||
value = ((_adlibChannelsLevelKeyScalingTable[index] * value) + 64) >> 7;
|
||||
}
|
||||
value = (_adlibChannelsVolumeTable[index] * value * 2) >> 8;
|
||||
if (value > 63) {
|
||||
value = 63;
|
||||
}
|
||||
value = 63 - value;
|
||||
value |= _adlibSetupChannelSequence1[channel * 14] << 6;
|
||||
Adlib_Write(0x40 + _adlibChannelsMappingTable1[channel], value);
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_SetChannel0xC0(int channel) {
|
||||
if (_adlibChannelsNoFeedback[channel] == 0) {
|
||||
const uint8 *p = &_adlibSetupChannelSequence1[channel * 14];
|
||||
uint8 value = p[2] << 1;
|
||||
if (p[12] == 0) {
|
||||
value |= 1;
|
||||
}
|
||||
Adlib_Write(0xC0 + _adlibChannelsMappingTable2[channel], value);
|
||||
}
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_SetChannel0x60(int channel) {
|
||||
const uint8 *p = &_adlibSetupChannelSequence1[channel * 14];
|
||||
uint8 value = (p[3] << 4) | (p[6] & 15);
|
||||
Adlib_Write(0x60 + _adlibChannelsMappingTable1[channel], value);
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_SetChannel0x80(int channel) {
|
||||
const uint8 *p = &_adlibSetupChannelSequence1[channel * 14];
|
||||
uint8 value = (p[4] << 4) | (p[7] & 15);
|
||||
Adlib_Write(0x80 + _adlibChannelsMappingTable1[channel], value);
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_SetChannel0x20(int channel) {
|
||||
const uint8 *p = &_adlibSetupChannelSequence1[channel * 14];
|
||||
uint8 value = p[1] & 15;
|
||||
if (p[9]) {
|
||||
value |= 0x80;
|
||||
}
|
||||
if (p[10]) {
|
||||
value |= 0x40;
|
||||
}
|
||||
if (p[5]) {
|
||||
value |= 0x20;
|
||||
}
|
||||
if (p[11]) {
|
||||
value |= 0x10;
|
||||
}
|
||||
Adlib_Write(0x20 + _adlibChannelsMappingTable1[channel], value);
|
||||
}
|
||||
|
||||
void AdlibMidiDriver::Adlib_SetChannel0xE0(int channel) {
|
||||
uint8 value = 0;
|
||||
if (_adlibWaveformSelect) {
|
||||
const uint8 *p = &_adlibSetupChannelSequence1[channel * 14];
|
||||
value = p[13] & 3;
|
||||
}
|
||||
Adlib_Write(0xE0 + _adlibChannelsMappingTable1[channel], value);
|
||||
}
|
||||
|
||||
const uint8 AdlibMidiDriver::_adlibChannelsMappingTable1[] = {
|
||||
0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21
|
||||
};
|
||||
|
||||
const uint8 AdlibMidiDriver::_adlibChannelsNoFeedback[] = {
|
||||
0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1
|
||||
};
|
||||
|
||||
const uint8 AdlibMidiDriver::_adlibChannelsMappingTable2[] = {
|
||||
0, 1, 2, 0, 1, 2, 3, 4, 5, 3, 4, 5, 6, 7, 8, 6, 7, 8
|
||||
};
|
||||
|
||||
const uint8 AdlibMidiDriver::_adlibChannelsMappingTable3[] = {
|
||||
0, 1, 2, 0, 1, 2, 3, 4, 5, 3, 4, 5, 6, 10, 8, 6, 7, 9
|
||||
};
|
||||
|
||||
const uint8 AdlibMidiDriver::_adlibChannelsKeyScalingTable1[] = {
|
||||
0, 3, 1, 4, 2, 5, 6, 9, 7, 10, 8, 11, 12, 15, 13, 16, 14, 17
|
||||
};
|
||||
|
||||
const uint8 AdlibMidiDriver::_adlibChannelsKeyScalingTable2[] = {
|
||||
0, 3, 1, 4, 2, 5, 6, 9, 7, 10, 8, 11, 12, 15, 16, 255, 14, 255, 17, 255, 13, 255
|
||||
};
|
||||
|
||||
const uint8 AdlibMidiDriver::_adlibChannelsVolumeTable[] = {
|
||||
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128
|
||||
};
|
||||
|
||||
const uint8 AdlibMidiDriver::_adlibInitSequenceData1[] = {
|
||||
1, 1, 3, 15, 5, 0, 1, 3, 15, 0, 0, 0, 1, 0
|
||||
};
|
||||
|
||||
const uint8 AdlibMidiDriver::_adlibInitSequenceData2[] = {
|
||||
0, 1, 1, 15, 7, 0, 2, 4, 0, 0, 0, 1, 0, 0
|
||||
};
|
||||
|
||||
const uint8 AdlibMidiDriver::_adlibInitSequenceData3[] = {
|
||||
0, 0, 0, 10, 4, 0, 8, 12, 11, 0, 0, 0, 1, 0
|
||||
};
|
||||
|
||||
const uint8 AdlibMidiDriver::_adlibInitSequenceData4[] = {
|
||||
0, 0, 0, 13, 4, 0, 6, 15, 0, 0, 0, 0, 1, 0
|
||||
};
|
||||
|
||||
const uint8 AdlibMidiDriver::_adlibInitSequenceData5[] = {
|
||||
0, 12, 0, 15, 11, 0, 8, 5, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
const uint8 AdlibMidiDriver::_adlibInitSequenceData6[] = {
|
||||
0, 4, 0, 15, 11, 0, 7, 5, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
const uint8 AdlibMidiDriver::_adlibInitSequenceData7[] = {
|
||||
0, 1, 0, 15, 11, 0, 5, 5, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
const uint8 AdlibMidiDriver::_adlibInitSequenceData8[] = {
|
||||
0, 1, 0, 15, 11, 0, 7, 5, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
const int16 AdlibMidiDriver::_midiChannelsNoteTable[] = {
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256
|
||||
};
|
||||
|
||||
const int16 AdlibMidiDriver::_midiNoteFreqTable[] = {
|
||||
690, 692, 695, 697, 700, 702, 705, 707, 710, 713, 715, 718,
|
||||
720, 723, 726, 728, 731, 733, 736, 739, 741, 744, 747, 749,
|
||||
752, 755, 758, 760, 763, 766, 769, 771, 774, 777, 780, 783,
|
||||
785, 788, 791, 794, 797, 800, 803, 806, 809, 811, 814, 817,
|
||||
820, 823, 826, 829, 832, 835, 838, 841, 844, 847, 850, 854,
|
||||
857, 860, 863, 866, 869, 872, 875, 879, 882, 885, 888, 891,
|
||||
895, 898, 901, 904, 908, 911, 914, 917, 921, 924, 927, 931,
|
||||
934, 937, 941, 944, 948, 951, 955, 958, 961, 965, 968, 972,
|
||||
975, 979, 983, 986, 990, 993, 997, 1000, 1004, 1008, 1011, 1015,
|
||||
1019, 1022, -511, -509, -507, -505, -504, -502, -500, -498, -496, -494,
|
||||
-492, -490, -488, -486, -484, -482, -480, -479, -477, -475, -473, -471,
|
||||
-469, -467, -465, -463, -460, -458, -456, -454, -452, -450, -448, -446,
|
||||
-444, -442, -440, -438, -436, -433, -431, -429, -427, -425, -423, -420,
|
||||
-418, -416, -414, -412, -409, -407, -405, -403, -401, -398, -396, -394,
|
||||
-391, -389, -387, -385, -382, -380, -378, -375, -373, -371, -368, -366,
|
||||
-363, -361, -359, -356, -354, -351, -349, -347, -344, -342, -339, -337
|
||||
};
|
||||
|
||||
MidiDriver *C_Player_CreateAdlibMidiDriver(Audio::Mixer *mixer) {
|
||||
return new AdlibMidiDriver(mixer);
|
||||
}
|
||||
|
||||
} // End of namespace Queen
|
@ -12,6 +12,7 @@ MODULE_OBJS := \
|
||||
input.o \
|
||||
journal.o \
|
||||
logic.o \
|
||||
midiadlib.o \
|
||||
music.o \
|
||||
musicdata.o \
|
||||
queen.o \
|
||||
@ -27,5 +28,5 @@ ifdef BUILD_PLUGINS
|
||||
PLUGIN := 1
|
||||
endif
|
||||
|
||||
# Include common rules
|
||||
# Include common rules
|
||||
include $(srcdir)/rules.mk
|
||||
|
@ -23,6 +23,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/events.h"
|
||||
|
||||
#include "queen/music.h"
|
||||
@ -34,28 +35,64 @@
|
||||
|
||||
namespace Queen {
|
||||
|
||||
MidiMusic::MidiMusic(MidiDriver *driver, QueenEngine *vm)
|
||||
: _driver(driver), _isPlaying(false), _looping(false), _randomLoop(false), _masterVolume(192), _queuePos(0), _passThrough(false), _buf(0) {
|
||||
extern MidiDriver *C_Player_CreateAdlibMidiDriver(Audio::Mixer *);
|
||||
|
||||
MidiMusic::MidiMusic(QueenEngine *vm)
|
||||
: _isPlaying(false), _looping(false), _randomLoop(false), _masterVolume(192), _buf(0) {
|
||||
|
||||
memset(_channel, 0, sizeof(_channel));
|
||||
_queuePos = _lastSong = _currentSong = 0;
|
||||
queueClear();
|
||||
_lastSong = _currentSong = 0;
|
||||
|
||||
int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI);
|
||||
_adlib = (midiDriver == MD_ADLIB);
|
||||
_nativeMT32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32"));
|
||||
|
||||
const char *musicDataFile;
|
||||
if (vm->resource()->isDemo()) {
|
||||
_tune = Sound::_tuneDemo;
|
||||
musicDataFile = "AQ8.RL";
|
||||
} else {
|
||||
_tune = Sound::_tune;
|
||||
musicDataFile = "AQ.RL";
|
||||
}
|
||||
if (_adlib) {
|
||||
musicDataFile = "AQBANK.MUS";
|
||||
}
|
||||
_musicData = vm->resource()->loadFile(musicDataFile, 0, &_musicDataSize);
|
||||
_numSongs = READ_LE_UINT16(_musicData);
|
||||
|
||||
_tune = vm->resource()->isDemo() ? Sound::_tuneDemo : Sound::_tune;
|
||||
|
||||
if (_adlib) {
|
||||
// int infoOffset = _numSongs * 4 + 2;
|
||||
// if (READ_LE_UINT16(_musicData + 2) != infoOffset) {
|
||||
// defaultAdlibVolume = _musicData[infoOffset];
|
||||
// }
|
||||
_driver = C_Player_CreateAdlibMidiDriver(vm->_mixer);
|
||||
} else {
|
||||
_driver = MidiDriver::createMidi(midiDriver);
|
||||
if (_nativeMT32) {
|
||||
_driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
|
||||
}
|
||||
}
|
||||
|
||||
_driver->open();
|
||||
_driver->setTimerCallback(this, &onTimer);
|
||||
|
||||
_parser = MidiParser::createParser_SMF();
|
||||
_parser->setMidiDriver(this);
|
||||
_parser->setTimerRate(_driver->getBaseTempo());
|
||||
|
||||
const char *filename = vm->resource()->isDemo() ? "AQ8.RL" : "AQ.RL";
|
||||
_musicData = vm->resource()->loadFile(filename, 0, &_musicDataSize);
|
||||
_numSongs = READ_LE_UINT16(_musicData);
|
||||
this->open();
|
||||
|
||||
_tune = vm->resource()->isDemo() ? Sound::_tuneDemo : Sound::_tune;
|
||||
vm->_system->getEventManager()->registerRandomSource(_rnd, "queenMusic");
|
||||
}
|
||||
|
||||
MidiMusic::~MidiMusic() {
|
||||
_driver->setTimerCallback(0, 0);
|
||||
_driver->close();
|
||||
delete _driver;
|
||||
_parser->unloadMusic();
|
||||
delete _parser;
|
||||
this->close();
|
||||
delete[] _buf;
|
||||
delete[] _musicData;
|
||||
}
|
||||
@ -100,7 +137,7 @@ bool MidiMusic::queueSong(uint16 songNum) {
|
||||
|
||||
// Work around bug in Roland music, note that these numbers are 'one-off'
|
||||
// from the original code
|
||||
if (/*isRoland && */ songNum == 88 || songNum == 89)
|
||||
if (!_adlib && (songNum == 88 || songNum == 89))
|
||||
songNum = 62;
|
||||
|
||||
_songQueue[MUSIC_QUEUE_SIZE - emptySlots] = songNum;
|
||||
@ -114,27 +151,8 @@ void MidiMusic::queueClear() {
|
||||
memset(_songQueue, 0, sizeof(_songQueue));
|
||||
}
|
||||
|
||||
int MidiMusic::open() {
|
||||
// Don't ever call open without first setting the output driver!
|
||||
if (!_driver)
|
||||
return 255;
|
||||
|
||||
int ret = _driver->open();
|
||||
if (ret)
|
||||
return ret;
|
||||
_driver->setTimerCallback(this, &onTimer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MidiMusic::close() {
|
||||
_driver->setTimerCallback(NULL, NULL);
|
||||
if (_driver)
|
||||
_driver->close();
|
||||
_driver = 0;
|
||||
}
|
||||
|
||||
void MidiMusic::send(uint32 b) {
|
||||
if (_passThrough) {
|
||||
if (_adlib) {
|
||||
_driver->send(b);
|
||||
return;
|
||||
}
|
||||
@ -146,13 +164,12 @@ void MidiMusic::send(uint32 b) {
|
||||
_channelVolume[channel] = volume;
|
||||
volume = volume * _masterVolume / 255;
|
||||
b = (b & 0xFF00FFFF) | (volume << 16);
|
||||
} else if ((b & 0xF0) == 0xC0 && !_nativeMT32) {
|
||||
} else if ((b & 0xF0) == 0xC0 && !_adlib && !_nativeMT32) {
|
||||
b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
|
||||
}
|
||||
else if ((b & 0xFFF0) == 0x007BB0) {
|
||||
} else if ((b & 0xFFF0) == 0x007BB0) {
|
||||
//Only respond to All Notes Off if this channel
|
||||
//has currently been allocated
|
||||
if (_channel[b & 0x0F])
|
||||
if (_channel[channel])
|
||||
return;
|
||||
}
|
||||
|
||||
@ -172,14 +189,23 @@ void MidiMusic::send(uint32 b) {
|
||||
}
|
||||
|
||||
void MidiMusic::metaEvent(byte type, byte *data, uint16 length) {
|
||||
//Only thing we care about is End of Track.
|
||||
if (type != 0x2F)
|
||||
return;
|
||||
|
||||
if (_looping || _songQueue[1])
|
||||
playMusic();
|
||||
else
|
||||
stopMusic();
|
||||
switch (type) {
|
||||
case 0x2F: // End of Track
|
||||
if (_looping || _songQueue[1]) {
|
||||
playMusic();
|
||||
} else {
|
||||
stopMusic();
|
||||
}
|
||||
break;
|
||||
case 0x7F: // Specific
|
||||
if (_adlib) {
|
||||
_driver->metaEvent(type, data, length);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// warning("Unhandled meta event: %02x", type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MidiMusic::onTimer(void *refCon) {
|
||||
@ -248,7 +274,7 @@ void MidiMusic::playMusic() {
|
||||
}
|
||||
|
||||
byte *prevSong = _musicData + songOffset(_currentSong);
|
||||
if (*prevSong == 0x43 || *prevSong == 0x63) {
|
||||
if (*prevSong == 'C' || *prevSong == 'c') {
|
||||
if (_buf) {
|
||||
delete[] _buf;
|
||||
_buf = 0;
|
||||
@ -263,7 +289,7 @@ void MidiMusic::playMusic() {
|
||||
|
||||
byte *musicPtr = _musicData + songOffset(songNum);
|
||||
uint32 size = songLength(songNum);
|
||||
if (*musicPtr == 0x43 || *musicPtr == 0x63) {
|
||||
if (*musicPtr == 'C' || *musicPtr == 'c') {
|
||||
uint32 packedSize = songLength(songNum) - 0x200;
|
||||
_buf = new uint16[packedSize];
|
||||
|
||||
@ -277,7 +303,7 @@ void MidiMusic::playMusic() {
|
||||
_buf[i] = data[*(idx + i)];
|
||||
#endif
|
||||
|
||||
musicPtr = ((byte *)_buf) + ((*musicPtr == 0x63) ? 1 : 0);
|
||||
musicPtr = ((byte *)_buf) + ((*musicPtr == 'c') ? 1 : 0);
|
||||
size = packedSize * 2;
|
||||
}
|
||||
|
||||
|
@ -33,18 +33,17 @@ class MidiParser;
|
||||
|
||||
namespace Queen {
|
||||
|
||||
struct tuneData;
|
||||
struct TuneData;
|
||||
|
||||
class QueenEngine;
|
||||
|
||||
class MidiMusic : public MidiDriver {
|
||||
public:
|
||||
MidiMusic(MidiDriver *driver, QueenEngine *vm);
|
||||
MidiMusic(QueenEngine *vm);
|
||||
~MidiMusic();
|
||||
void setVolume(int volume);
|
||||
int getVolume() { return _masterVolume; }
|
||||
int getVolume() const { return _masterVolume; }
|
||||
|
||||
void hasNativeMT32(bool b) { _nativeMT32 = b; }
|
||||
void playSong(uint16 songNum);
|
||||
void stopSong() { stopMusic(); }
|
||||
void playMusic();
|
||||
@ -53,12 +52,11 @@ public:
|
||||
void queueTuneList(int16 tuneList);
|
||||
bool queueSong(uint16 songNum);
|
||||
void queueClear();
|
||||
void setPassThrough(bool b) { _passThrough = b; }
|
||||
void toggleVChange();
|
||||
|
||||
//MidiDriver interface implementation
|
||||
int open();
|
||||
void close();
|
||||
int open() { return 0; }
|
||||
void close() {}
|
||||
void send(uint32 b);
|
||||
|
||||
void metaEvent(byte type, byte *data, uint16 length);
|
||||
@ -86,8 +84,8 @@ protected:
|
||||
MidiParser *_parser;
|
||||
MidiChannel *_channel[16];
|
||||
byte _channelVolume[16];
|
||||
bool _adlib;
|
||||
bool _nativeMT32;
|
||||
bool _passThrough;
|
||||
|
||||
Common::RandomSource _rnd;
|
||||
|
||||
@ -105,7 +103,7 @@ protected:
|
||||
uint32 _musicDataSize;
|
||||
bool _vToggle;
|
||||
byte *_musicData;
|
||||
const tuneData *_tune;
|
||||
const TuneData *_tune;
|
||||
};
|
||||
|
||||
} // End of namespace Queen
|
||||
|
@ -28,7 +28,7 @@
|
||||
|
||||
namespace Queen {
|
||||
|
||||
const songData Sound::_songDemo[] = {
|
||||
const SongData Sound::_songDemo[] = {
|
||||
/* 1 - Hotel Gangsters */
|
||||
{ { 1, 0 }, 128, 128, 128, 1, 0 },
|
||||
|
||||
@ -123,7 +123,7 @@ const songData Sound::_songDemo[] = {
|
||||
{ { 34, 0 }, 128, 128, 128, 1, 1 },
|
||||
};
|
||||
|
||||
const songData Sound::_song[] = {
|
||||
const SongData Sound::_song[] = {
|
||||
/* 1 - Hotel Gangsters */
|
||||
{ { 1, 0 }, 128, 180, 0, 1, 0 },
|
||||
|
||||
@ -752,7 +752,7 @@ const songData Sound::_song[] = {
|
||||
{ { 212, 0 }, 128, 128, 128, 1, 0 }
|
||||
};
|
||||
|
||||
const tuneData Sound::_tuneDemo[] = {
|
||||
const TuneData Sound::_tuneDemo[] = {
|
||||
/* 1 - Hotel Gangsters */
|
||||
{ { 32, 0 }, { 0, 0 }, 1, 0 },
|
||||
|
||||
@ -859,7 +859,7 @@ const tuneData Sound::_tuneDemo[] = {
|
||||
{ { 46, 0 }, { 0, 0 }, 1, 0 },
|
||||
};
|
||||
|
||||
const tuneData Sound::_tune[] = {
|
||||
const TuneData Sound::_tune[] = {
|
||||
/* 1 - Hotel Gangsters */
|
||||
{ { 32, 0 }, { 0, 0 }, 1, 0 },
|
||||
|
||||
|
@ -157,15 +157,7 @@ void Sound::loadState(uint32 ver, byte *&ptr) {
|
||||
PCSound::PCSound(Audio::Mixer *mixer, QueenEngine *vm)
|
||||
: Sound(mixer, vm) {
|
||||
|
||||
int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI);
|
||||
bool native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32"));
|
||||
|
||||
MidiDriver *driver = MidiDriver::createMidi(midiDriver);
|
||||
if (native_mt32)
|
||||
driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
|
||||
|
||||
_music = new MidiMusic(driver, vm);
|
||||
_music->hasNativeMT32(native_mt32);
|
||||
_music = new MidiMusic(vm);
|
||||
}
|
||||
|
||||
PCSound::~PCSound() {
|
||||
|
@ -37,7 +37,7 @@ namespace Common {
|
||||
|
||||
namespace Queen {
|
||||
|
||||
struct songData {
|
||||
struct SongData {
|
||||
int16 tuneList[5];
|
||||
int16 volume;
|
||||
int16 tempo;
|
||||
@ -46,7 +46,7 @@ struct songData {
|
||||
int16 ignore;
|
||||
};
|
||||
|
||||
struct tuneData {
|
||||
struct TuneData {
|
||||
int16 tuneNum[9];
|
||||
int16 sfx[2];
|
||||
int16 mode;
|
||||
@ -103,10 +103,10 @@ public:
|
||||
void saveState(byte *&ptr);
|
||||
void loadState(uint32 ver, byte *&ptr);
|
||||
|
||||
static const songData _songDemo[];
|
||||
static const songData _song[];
|
||||
static const tuneData _tuneDemo[];
|
||||
static const tuneData _tune[];
|
||||
static const SongData _songDemo[];
|
||||
static const SongData _song[];
|
||||
static const TuneData _tuneDemo[];
|
||||
static const TuneData _tune[];
|
||||
static const char *_sfxName[];
|
||||
static const int16 _jungleList[];
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user