[Scummvm-cvs-logs] scummvm master -> 66df9c95e0eea427527491e964b40adc2a9def05
lordhoto
lordhoto at gmail.com
Thu Jul 23 22:41:08 CEST 2015
This automated email contains information about 6 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
979a885ef9 AGOS: Add initial version of Simon1 DOS AdLib output.
33c57c632c Revert "AGOS: Add updated patch for #647 - Simon 1 DOS Adlib instrument bank"
cf42dc0a35 AGOS: Slight cleanup in Simon1 AdLib output initialization code.
757077fecc AGOS: Add simple volume control when Simon1 AdLib output is used.
01eda204d6 NEWS: Mention Simon1 AdLib output addition.
66df9c95e0 NEWS: Slight style fix (MT32 to MT-32).
Commit: 979a885ef9785afbed650dfffc8c5af6af8ea8e5
https://github.com/scummvm/scummvm/commit/979a885ef9785afbed650dfffc8c5af6af8ea8e5
Author: Johannes Schickel (lordhoto at scummvm.org)
Date: 2015-07-23T22:33:56+02:00
Commit Message:
AGOS: Add initial version of Simon1 DOS AdLib output.
Testing so far has not really happened. Only the first part of the intro has
been tested.
Changed paths:
A engines/agos/drivers/simon1/adlib.cpp
A engines/agos/drivers/simon1/adlib.h
engines/agos/midi.cpp
engines/agos/midi.h
engines/agos/module.mk
diff --git a/engines/agos/drivers/simon1/adlib.cpp b/engines/agos/drivers/simon1/adlib.cpp
new file mode 100644
index 0000000..d331b86
--- /dev/null
+++ b/engines/agos/drivers/simon1/adlib.cpp
@@ -0,0 +1,494 @@
+/* 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.
+ *
+ */
+
+#include "agos/drivers/simon1/adlib.h"
+
+#include "common/textconsole.h"
+#include "common/util.h"
+
+namespace AGOS {
+
+enum {
+ kChannelUnused = 0xFF,
+ kChannelOrphanedFlag = 0x80,
+
+ kOPLVoicesCount = 9
+};
+
+MidiDriver_Simon1_AdLib::Voice::Voice()
+ : channel(kChannelUnused), note(0), instrTotalLevel(0), instrScalingLevel(0), frequency(0) {
+}
+
+MidiDriver_Simon1_AdLib::MidiDriver_Simon1_AdLib(const byte *instrumentData)
+ : _isOpen(false), _opl(nullptr), _timerProc(nullptr), _timerParam(nullptr),
+ _melodyVoices(0), _amvdrBits(0), _rhythmEnabled(false), _voices(), _midiPrograms(),
+ _instruments(instrumentData) {
+}
+
+MidiDriver_Simon1_AdLib::~MidiDriver_Simon1_AdLib() {
+ close();
+ delete[] _instruments;
+}
+
+int MidiDriver_Simon1_AdLib::open() {
+ if (_isOpen) {
+ return MERR_ALREADY_OPEN;
+ }
+
+ _opl = OPL::Config::create();
+ if (!_opl) {
+ return MERR_DEVICE_NOT_AVAILABLE;
+ }
+
+ if (!_opl->init()) {
+ delete _opl;
+ _opl = nullptr;
+
+ return MERR_CANNOT_CONNECT;
+ }
+
+ _opl->start(new Common::Functor0Mem<void, MidiDriver_Simon1_AdLib>(this, &MidiDriver_Simon1_AdLib::onTimer));
+
+ _opl->writeReg(0x01, 0x20);
+ _opl->writeReg(0x08, 0x40);
+ _opl->writeReg(0xBD, 0xC0);
+ reset();
+
+ _isOpen = true;
+ return 0;
+}
+
+bool MidiDriver_Simon1_AdLib::isOpen() const {
+ return _isOpen;
+}
+
+void MidiDriver_Simon1_AdLib::close() {
+ setTimerCallback(nullptr, nullptr);
+
+ if (_isOpen) {
+ _opl->stop();
+ delete _opl;
+ _opl = nullptr;
+
+ _isOpen = false;
+ }
+}
+
+void MidiDriver_Simon1_AdLib::send(uint32 b) {
+ int channel = b & 0x0F;
+ int command = b & 0xF0;
+ int param1 = (b >> 8) & 0xFF;
+ int param2 = (b >> 16) & 0xFF;
+
+ // The percussion channel is handled specially. The AdLib output uses
+ // channels 11 to 15 for percussions. For this, the original converted
+ // note on on the percussion channel to note on channels 11 to 15 before
+ // giving it to the AdLib output. We do this in here for simplicity.
+ if (command == 0x90 && channel == 9) {
+ param1 -= 36;
+ if (param1 < 0 || param1 >= ARRAYSIZE(_rhythmMap)) {
+ return;
+ }
+
+ channel = _rhythmMap[param1].channel;
+ MidiDriver::send(0xC0 | channel, _rhythmMap[param1].program, 0);
+
+ param1 = _rhythmMap[param1].note;
+ MidiDriver::send(0x80 | channel, param1, param2);
+
+ param2 >>= 1;
+ }
+
+ switch (command) {
+ case 0x80: // note OFF
+ noteOff(channel, param1);
+ break;
+
+ case 0x90: // note ON
+ if (param2 == 0) {
+ noteOff(channel, param1);
+ } else {
+ noteOn(channel, param1, param2);
+ }
+ break;
+
+ case 0xB0: // control change
+ controlChange(channel, param1, param2);
+ break;
+
+ case 0xC0: // program change
+ programChange(channel, param1);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void MidiDriver_Simon1_AdLib::setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) {
+ _timerParam = timer_param;
+ _timerProc = timer_proc;
+}
+
+uint32 MidiDriver_Simon1_AdLib::getBaseTempo() {
+ return 1000000 / OPL::OPL::kDefaultCallbackFrequency;
+}
+
+void MidiDriver_Simon1_AdLib::onTimer() {
+ if (_timerProc) {
+ (*_timerProc)(_timerParam);
+ }
+}
+
+void MidiDriver_Simon1_AdLib::reset() {
+ resetOPLVoices();
+ resetRhythm();
+ for (int i = 0; i < kNumberOfVoices; ++i) {
+ _voices[i].channel = kChannelUnused;
+ }
+ resetVoices();
+}
+
+void MidiDriver_Simon1_AdLib::resetOPLVoices() {
+ _amvdrBits &= 0xE0;
+ _opl->writeReg(0xBD, _amvdrBits);
+ for (int i = 8; i >= 0; --i) {
+ _opl->writeReg(0xB0 + i, 0);
+ }
+}
+
+void MidiDriver_Simon1_AdLib::resetRhythm() {
+ _melodyVoices = 9;
+ _amvdrBits = 0xC0;
+ _opl->writeReg(0xBD, _amvdrBits);
+}
+
+void MidiDriver_Simon1_AdLib::resetVoices() {
+ memset(_midiPrograms, 0, sizeof(_midiPrograms));
+ for (int i = 0; i < kNumberOfVoices; ++i) {
+ _voices[i].channel = kChannelUnused;
+ }
+
+ for (int i = 0; i < kOPLVoicesCount; ++i) {
+ resetRhythm();
+ _opl->writeReg(0x08, 0x00);
+
+ int oplRegister = _operatorMap[i];
+ for (int j = 0; j < 4; ++j) {
+ oplRegister += 0x20;
+
+ _opl->writeReg(oplRegister + 0, _operatorDefaults[2 * j + 0]);
+ _opl->writeReg(oplRegister + 3, _operatorDefaults[2 * j + 1]);
+ }
+
+ _opl->writeReg(oplRegister + 0x60, 0x00);
+ _opl->writeReg(oplRegister + 0x63, 0x00);
+
+ // This seems to be serious bug but the original does it the same way.
+ _opl->writeReg(_operatorMap[i] + i, 0x08);
+ }
+}
+
+int MidiDriver_Simon1_AdLib::allocateVoice(uint channel) {
+ for (int i = 0; i < _melodyVoices; ++i) {
+ if (_voices[i].channel == (channel | kChannelOrphanedFlag)) {
+ return i;
+ }
+ }
+
+ for (int i = 0; i < _melodyVoices; ++i) {
+ if (_voices[i].channel == kChannelUnused) {
+ return i;
+ }
+ }
+
+ for (int i = 0; i < _melodyVoices; ++i) {
+ if (_voices[i].channel > 0x7F) {
+ return i;
+ }
+ }
+
+ // The original had some logic for a priority based reuse of channels.
+ // However, the priority value is always 0, which causes the first channel
+ // to be picked all the time.
+ const int voice = 0;
+ _opl->writeReg(0xA0 + voice, (_voices[voice].frequency ) & 0xFF);
+ _opl->writeReg(0xB0 + voice, (_voices[voice].frequency >> 8) & 0xFF);
+ return voice;
+}
+
+void MidiDriver_Simon1_AdLib::noteOff(uint channel, uint note) {
+ if (_melodyVoices <= 6 && channel >= 11) {
+ _amvdrBits &= ~(_rhythmInstrumentMask[channel - 11]);
+ _opl->writeReg(0xBD, _amvdrBits);
+ } else {
+ for (int i = 0; i < _melodyVoices; ++i) {
+ if (_voices[i].note == note && _voices[i].channel == channel) {
+ _voices[i].channel |= kChannelOrphanedFlag;
+ _opl->writeReg(0xA0 + i, (_voices[i].frequency ) & 0xFF);
+ _opl->writeReg(0xB0 + i, (_voices[i].frequency >> 8) & 0xFF);
+ return;
+ }
+ }
+ }
+}
+
+void MidiDriver_Simon1_AdLib::noteOn(uint channel, uint note, uint velocity) {
+ if (_rhythmEnabled && channel >= 11) {
+ noteOnRhythm(channel, note, velocity);
+ return;
+ }
+
+ const int voiceNum = allocateVoice(channel);
+ Voice &voice = _voices[voiceNum];
+
+ if ((voice.channel & 0x7F) != channel) {
+ setupInstrument(voiceNum, _midiPrograms[channel]);
+ }
+ voice.channel = channel;
+
+ _opl->writeReg(0x43 + _operatorMap[voiceNum], (0x3F - (((velocity | 0x80) * voice.instrTotalLevel) >> 8)) | voice.instrScalingLevel);
+
+ voice.note = note;
+ if (note >= 0x80) {
+ note = 0;
+ }
+
+ const int frequencyAndOctave = _frequencyIndexAndOctaveTable[note];
+ const uint frequency = _frequencyTable[frequencyAndOctave & 0x0F];
+
+ uint highByte = ((frequency & 0xFF00) >> 8) | ((frequencyAndOctave & 0x70) >> 2);
+ uint lowByte = frequency & 0x00FF;
+ voice.frequency = (highByte << 8) | lowByte;
+
+ _opl->writeReg(0xA0 + voiceNum, lowByte);
+ _opl->writeReg(0xB0 + voiceNum, highByte | 0x20);
+}
+
+void MidiDriver_Simon1_AdLib::noteOnRhythm(uint channel, uint note, uint velocity) {
+ const uint voiceNum = channel - 5;
+ Voice &voice = _voices[voiceNum];
+
+ _amvdrBits |= _rhythmInstrumentMask[voiceNum - 6];
+
+ const uint level = (0x3F - (((velocity | 0x80) * voice.instrTotalLevel) >> 8)) | voice.instrScalingLevel;
+ if (voiceNum == 6) {
+ _opl->writeReg(0x43 + _rhythmOperatorMap[voiceNum - 6], level);
+ } else {
+ _opl->writeReg(0x40 + _rhythmOperatorMap[voiceNum - 6], level);
+ }
+
+ voice.note = note;
+ if (note >= 0x80) {
+ note = 0;
+ }
+
+ const int frequencyAndOctave = _frequencyIndexAndOctaveTable[note];
+ const uint frequency = _frequencyTable[frequencyAndOctave & 0x0F];
+
+ uint highByte = ((frequency & 0xFF00) >> 8) | ((frequencyAndOctave & 0x70) >> 2);
+ uint lowByte = frequency & 0x00FF;
+ voice.frequency = (highByte << 8) | lowByte;
+
+ const uint oplOperator = _rhythmVoiceMap[voiceNum - 6];
+ _opl->writeReg(0xA0 + oplOperator, lowByte);
+ _opl->writeReg(0xB0 + oplOperator, highByte);
+
+ _opl->writeReg(0xBD, _amvdrBits);
+}
+
+void MidiDriver_Simon1_AdLib::controlChange(uint channel, uint controller, uint value) {
+ // Enable/Disable Rhythm Section
+ if (controller == 0x67) {
+ resetVoices();
+ _rhythmEnabled = (value != 0);
+
+ if (_rhythmEnabled) {
+ _melodyVoices = 6;
+ _amvdrBits = 0xE0;
+ } else {
+ _melodyVoices = 9;
+ _amvdrBits = 0xC0;
+ }
+
+ _voices[6].channel = kChannelUnused;
+ _voices[7].channel = kChannelUnused;
+ _voices[8].channel = kChannelUnused;
+
+ _opl->writeReg(0xBD, _amvdrBits);
+ }
+}
+
+void MidiDriver_Simon1_AdLib::programChange(uint channel, uint program) {
+ _midiPrograms[channel] = program;
+
+ if (_rhythmEnabled && channel >= 11) {
+ setupInstrument(channel - 5, program);
+ } else {
+ // Fully unallocate all previously allocated but now unused voices for
+ // this MIDI channel.
+ for (uint i = 0; i < kOPLVoicesCount; ++i) {
+ if (_voices[i].channel == (channel | kChannelOrphanedFlag)) {
+ _voices[i].channel = kChannelUnused;
+ }
+ }
+
+ // Set the program for all voices allocted for this MIDI channel.
+ for (uint i = 0; i < kOPLVoicesCount; ++i) {
+ if (_voices[i].channel == channel) {
+ setupInstrument(i, program);
+ }
+ }
+ }
+}
+
+void MidiDriver_Simon1_AdLib::setupInstrument(uint voice, uint instrument) {
+ const byte *instrumentData = _instruments + instrument * 16;
+
+ int scaling = instrumentData[3];
+ if (_rhythmEnabled && voice >= 7) {
+ scaling = instrumentData[2];
+ }
+
+ const int scalingLevel = scaling & 0xC0;
+ const int totalLevel = scaling & 0x3F;
+
+ _voices[voice].instrScalingLevel = scalingLevel;
+ _voices[voice].instrTotalLevel = (-(totalLevel - 0x3F)) & 0xFF;
+
+ if (!_rhythmEnabled || voice <= 6) {
+ int oplRegister = _operatorMap[voice];
+ for (int j = 0; j < 4; ++j) {
+ oplRegister += 0x20;
+ _opl->writeReg(oplRegister + 0, *instrumentData++);
+ _opl->writeReg(oplRegister + 3, *instrumentData++);
+ }
+ oplRegister += 0x60;
+ _opl->writeReg(oplRegister + 0, *instrumentData++);
+ _opl->writeReg(oplRegister + 3, *instrumentData++);
+
+ _opl->writeReg(0xC0 + voice, *instrumentData++);
+ } else {
+ voice -= 7;
+
+ int oplRegister = _rhythmOperatorMap[voice + 1];
+ for (int j = 0; j < 4; ++j) {
+ oplRegister += 0x20;
+ _opl->writeReg(oplRegister + 0, *instrumentData++);
+ ++instrumentData;
+ }
+ oplRegister += 0x60;
+ _opl->writeReg(oplRegister + 0, *instrumentData++);
+ ++instrumentData;
+
+ _opl->writeReg(0xC0 + _rhythmVoiceMap[voice + 1], *instrumentData++);
+ }
+}
+
+const int MidiDriver_Simon1_AdLib::_operatorMap[9] = {
+ 0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11,
+ 0x12
+};
+
+const int MidiDriver_Simon1_AdLib::_operatorDefaults[8] = {
+ 0x01, 0x11, 0x4F, 0x00, 0xF1, 0xF2, 0x53, 0x74
+};
+
+const int MidiDriver_Simon1_AdLib::_rhythmOperatorMap[5] = {
+ 0x10, 0x14, 0x12, 0x15, 0x11
+};
+
+const uint MidiDriver_Simon1_AdLib::_rhythmInstrumentMask[5] = {
+ 0x10, 0x08, 0x04, 0x02, 0x01
+};
+
+const int MidiDriver_Simon1_AdLib::_rhythmVoiceMap[5] = {
+ 6, 7, 8, 8, 7
+};
+
+const int MidiDriver_Simon1_AdLib::_frequencyIndexAndOctaveTable[128] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x20, 0x21, 0x22, 0x23,
+ 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3A, 0x3B, 0x40, 0x41, 0x42, 0x43,
+ 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5A, 0x5B, 0x60, 0x61, 0x62, 0x63,
+ 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x7B, 0x70, 0x71, 0x72, 0x73,
+ 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B,
+ 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B
+};
+
+const int MidiDriver_Simon1_AdLib::_frequencyTable[16] = {
+ 0x0157, 0x016B, 0x0181, 0x0198, 0x01B0, 0x01CA, 0x01E5, 0x0202,
+ 0x0220, 0x0241, 0x0263, 0x0287, 0x2100, 0xD121, 0xA307, 0x46A4
+};
+
+const MidiDriver_Simon1_AdLib::RhythmMap MidiDriver_Simon1_AdLib::_rhythmMap[39] = {
+ { 11, 123, 40 },
+ { 12, 127, 50 },
+ { 12, 124, 1 },
+ { 12, 124, 90 },
+ { 13, 125, 50 },
+ { 13, 125, 25 },
+ { 15, 127, 80 },
+ { 13, 125, 25 },
+ { 15, 127, 40 },
+ { 13, 125, 35 },
+ { 15, 127, 90 },
+ { 13, 125, 35 },
+ { 13, 125, 45 },
+ { 14, 126, 90 },
+ { 13, 125, 45 },
+ { 15, 127, 90 },
+ { 0, 0, 0 },
+ { 15, 127, 60 },
+ { 0, 0, 0 },
+ { 13, 125, 60 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 13, 125, 45 },
+ { 13, 125, 40 },
+ { 13, 125, 35 },
+ { 13, 125, 30 },
+ { 13, 125, 25 },
+ { 13, 125, 80 },
+ { 13, 125, 40 },
+ { 13, 125, 80 },
+ { 13, 125, 40 },
+ { 14, 126, 40 },
+ { 15, 127, 60 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 14, 126, 80 },
+ { 0, 0, 0 },
+ { 13, 125, 100 }
+};
+
+} // End of namespace AGOS
diff --git a/engines/agos/drivers/simon1/adlib.h b/engines/agos/drivers/simon1/adlib.h
new file mode 100644
index 0000000..b92c1dd
--- /dev/null
+++ b/engines/agos/drivers/simon1/adlib.h
@@ -0,0 +1,116 @@
+/* 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.
+ *
+ */
+
+#ifndef AGOS_SIMON1_ADLIB_H
+#define AGOS_SIMON1_ADLIB_H
+
+#include "audio/mididrv.h"
+#include "audio/fmopl.h"
+
+namespace AGOS {
+
+class MidiDriver_Simon1_AdLib : public MidiDriver {
+public:
+ MidiDriver_Simon1_AdLib(const byte *instrumentData);
+ virtual ~MidiDriver_Simon1_AdLib();
+
+ // MidiDriver API
+ virtual int open();
+ virtual bool isOpen() const;
+ virtual void close();
+
+ virtual void send(uint32 b);
+
+ virtual void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc);
+ virtual uint32 getBaseTempo();
+
+ virtual MidiChannel *allocateChannel() { return 0; }
+ virtual MidiChannel *getPercussionChannel() { return 0; }
+private:
+ bool _isOpen;
+
+ OPL::OPL *_opl;
+
+ Common::TimerManager::TimerProc _timerProc;
+ void *_timerParam;
+ void onTimer();
+
+ void reset();
+ void resetOPLVoices();
+
+ void resetRhythm();
+ int _melodyVoices;
+ uint8 _amvdrBits;
+ bool _rhythmEnabled;
+
+ enum {
+ kNumberOfVoices = 11,
+ kNumberOfMidiChannels = 16
+ };
+
+ struct Voice {
+ Voice();
+
+ uint channel;
+ uint note;
+ uint instrTotalLevel;
+ uint instrScalingLevel;
+ uint frequency;
+ };
+
+ void resetVoices();
+ int allocateVoice(uint channel);
+
+ Voice _voices[kNumberOfVoices];
+ uint _midiPrograms[kNumberOfMidiChannels];
+
+ void noteOff(uint channel, uint note);
+ void noteOn(uint channel, uint note, uint velocity);
+ void noteOnRhythm(uint channel, uint note, uint velocity);
+ void controlChange(uint channel, uint controller, uint value);
+ void programChange(uint channel, uint program);
+
+ void setupInstrument(uint voice, uint instrument);
+ const byte *_instruments;
+
+ static const int _operatorMap[9];
+ static const int _operatorDefaults[8];
+
+ static const int _rhythmOperatorMap[5];
+ static const uint _rhythmInstrumentMask[5];
+ static const int _rhythmVoiceMap[5];
+
+ static const int _frequencyIndexAndOctaveTable[128];
+ static const int _frequencyTable[16];
+
+ struct RhythmMap {
+ int channel;
+ int program;
+ int note;
+ };
+
+ static const RhythmMap _rhythmMap[39];
+};
+
+} // End of namespace AGOS
+
+#endif
diff --git a/engines/agos/midi.cpp b/engines/agos/midi.cpp
index 85f2dd5..67765fa 100644
--- a/engines/agos/midi.cpp
+++ b/engines/agos/midi.cpp
@@ -29,6 +29,7 @@
#include "agos/midi.h"
#include "agos/drivers/accolade/mididriver.h"
+#include "agos/drivers/simon1/adlib.h"
// Miles Audio for Simon 2
#include "audio/miles.h"
@@ -109,6 +110,8 @@ int MidiPlayer::open(int gameType, bool isDemo) {
if (isDemo) {
_musicMode = kMusicModeAccolade;
accoladeDriverFilename = "MUSIC.DRV";
+ } else if (Common::File::exists("MT_FM.IBK")) {
+ _musicMode = kMusicModeSimon1;
}
break;
case GType_SIMON2:
@@ -231,6 +234,35 @@ int MidiPlayer::open(int gameType, bool isDemo) {
return 0;
}
+ case kMusicModeSimon1: {
+ // This only handles the original AdLib driver of Simon1.
+ if (musicType == MT_ADLIB) {
+ _adLibMusic = true;
+ _map_mt32_to_gm = false;
+ _nativeMT32 = false;
+
+ // Load instrument data.
+ Common::File ibk;
+
+ if (ibk.open("MT_FM.IBK")) {
+ if (ibk.readUint32BE() == 0x49424b1a) {
+ byte *instrumentData = new byte[128 * 16];
+ if (ibk.read(instrumentData, 128 * 16) == 128 * 16) {
+ _driver = new MidiDriver_Simon1_AdLib(instrumentData);
+ ret = _driver->open();
+ if (ret == 0) {
+ _driver->setTimerCallback(this, &onTimer);
+ _driver->send(0xB0, 0x67, 0x01);
+ return 0;
+ }
+ }
+ }
+ }
+ }
+
+ _musicMode = kMusicModeDisabled;
+ }
+
default:
break;
}
diff --git a/engines/agos/midi.h b/engines/agos/midi.h
index edb3402..e8a6bca 100644
--- a/engines/agos/midi.h
+++ b/engines/agos/midi.h
@@ -36,7 +36,8 @@ namespace AGOS {
enum kMusicMode {
kMusicModeDisabled = 0,
kMusicModeAccolade = 1,
- kMusicModeMilesAudio
+ kMusicModeMilesAudio = 2,
+ kMusicModeSimon1 = 3
};
struct MusicInfo {
diff --git a/engines/agos/module.mk b/engines/agos/module.mk
index 6d4e72e..e7b773d 100644
--- a/engines/agos/module.mk
+++ b/engines/agos/module.mk
@@ -4,6 +4,7 @@ MODULE_OBJS := \
drivers/accolade/adlib.o \
drivers/accolade/driverfile.o \
drivers/accolade/mt32.o \
+ drivers/simon1/adlib.o \
agos.o \
charset.o \
charset-fontdata.o \
Commit: 33c57c632cc630d1d64266d9ee2bf340d0052049
https://github.com/scummvm/scummvm/commit/33c57c632cc630d1d64266d9ee2bf340d0052049
Author: Johannes Schickel (lordhoto at scummvm.org)
Date: 2015-07-23T22:33:56+02:00
Commit Message:
Revert "AGOS: Add updated patch for #647 - Simon 1 DOS Adlib instrument bank"
This reverts commit 06addfc4041b3e20fd89dee46227e04f1c66fe52.
We implement the actual Simon1 DOS AdLib driver now, thus this code is
obsolete.
Changed paths:
engines/agos/midi.cpp
engines/agos/midi.h
diff --git a/engines/agos/midi.cpp b/engines/agos/midi.cpp
index 67765fa..61bab7d 100644
--- a/engines/agos/midi.cpp
+++ b/engines/agos/midi.cpp
@@ -53,8 +53,6 @@ MidiPlayer::MidiPlayer() {
_driver = 0;
_map_mt32_to_gm = false;
- _adlibPatches = NULL;
-
_adLibMusic = false;
_enable_sfx = true;
_current = 0;
@@ -84,7 +82,6 @@ MidiPlayer::~MidiPlayer() {
}
_driver = NULL;
clearConstructs();
- unloadAdlibPatches();
}
int MidiPlayer::open(int gameType, bool isDemo) {
@@ -278,12 +275,6 @@ int MidiPlayer::open(int gameType, bool isDemo) {
if (_nativeMT32)
_driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
- /* Disabled due to not sounding right, and low volume level
- if (gameType == GType_SIMON1 && MidiDriver::getMusicType(dev) == MT_ADLIB) {
- loadAdlibPatches();
- }
- */
-
_map_mt32_to_gm = (gameType != GType_SIMON2 && !_nativeMT32);
ret = _driver->open();
@@ -319,10 +310,8 @@ void MidiPlayer::send(uint32 b) {
else if (_current == &_music)
volume = volume * _musicVolume / 255;
b = (b & 0xFF00FFFF) | (volume << 16);
- } else if ((b & 0xF0) == 0xC0) {
- if (_map_mt32_to_gm && !_adlibPatches) {
- b = (b & 0xFFFF00FF) | (MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8);
- }
+ } else if ((b & 0xF0) == 0xC0 && _map_mt32_to_gm) {
+ b = (b & 0xFFFF00FF) | (MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8);
} else if ((b & 0xFFF0) == 0x007BB0) {
// Only respond to an All Notes Off if this channel
// has already been allocated.
@@ -353,16 +342,7 @@ void MidiPlayer::send(uint32 b) {
else if (_current == &_music)
_current->channel[9]->volume(_current->volume[9] * _musicVolume / 255);
}
-
- if ((b & 0xF0) == 0xC0 && _adlibPatches) {
- // NOTE: In the percussion channel, this function is a
- // no-op. Any percussion instruments you hear may
- // be the stock ones from adlib.cpp.
- _driver->sysEx_customInstrument(_current->channel[channel]->getNumber(), 'ADL ', _adlibPatches + 30 * ((b >> 8) & 0xFF));
- } else {
- _current->channel[channel]->send(b);
- }
-
+ _current->channel[channel]->send(b);
if ((b & 0xFFF0) == 0x79B0) {
// We have received a "Reset All Controllers" message
// and passed it on to the MIDI driver. This may or may
@@ -573,47 +553,6 @@ void MidiPlayer::resetVolumeTable() {
}
}
-void MidiPlayer::loadAdlibPatches() {
- Common::File ibk;
-
- if (!ibk.open("mt_fm.ibk"))
- return;
-
- if (ibk.readUint32BE() == 0x49424b1a) {
- _adlibPatches = new byte[128 * 30];
- byte *ptr = _adlibPatches;
-
- memset(_adlibPatches, 0, 128 * 30);
-
- for (int i = 0; i < 128; i++) {
- byte instr[16];
-
- ibk.read(instr, 16);
-
- ptr[0] = instr[0]; // Modulator Sound Characteristics
- ptr[1] = instr[2]; // Modulator Scaling/Output Level
- ptr[2] = ~instr[4]; // Modulator Attack/Decay
- ptr[3] = ~instr[6]; // Modulator Sustain/Release
- ptr[4] = instr[8]; // Modulator Wave Select
- ptr[5] = instr[1]; // Carrier Sound Characteristics
- ptr[6] = instr[3]; // Carrier Scaling/Output Level
- ptr[7] = ~instr[5]; // Carrier Attack/Delay
- ptr[8] = ~instr[7]; // Carrier Sustain/Release
- ptr[9] = instr[9]; // Carrier Wave Select
- ptr[10] = instr[10]; // Feedback/Connection
-
- // The remaining six bytes are reserved for future use
-
- ptr += 30;
- }
- }
-}
-
-void MidiPlayer::unloadAdlibPatches() {
- delete[] _adlibPatches;
- _adlibPatches = NULL;
-}
-
static const int simon1_gmf_size[] = {
8900, 12166, 2848, 3442, 4034, 4508, 7064, 9730, 6014, 4742, 3138,
6570, 5384, 8909, 6457, 16321, 2742, 8968, 4804, 8442, 7717,
diff --git a/engines/agos/midi.h b/engines/agos/midi.h
index e8a6bca..fb987fd 100644
--- a/engines/agos/midi.h
+++ b/engines/agos/midi.h
@@ -82,15 +82,11 @@ protected:
byte _queuedTrack;
bool _loopQueuedTrack;
- byte *_adlibPatches;
-
protected:
static void onTimer(void *data);
void clearConstructs();
void clearConstructs(MusicInfo &info);
void resetVolumeTable();
- void loadAdlibPatches();
- void unloadAdlibPatches();
public:
bool _adLibMusic;
Commit: cf42dc0a358da489ff93d32c18a5103de4dc4385
https://github.com/scummvm/scummvm/commit/cf42dc0a358da489ff93d32c18a5103de4dc4385
Author: Johannes Schickel (lordhoto at scummvm.org)
Date: 2015-07-23T22:33:56+02:00
Commit Message:
AGOS: Slight cleanup in Simon1 AdLib output initialization code.
Changed paths:
engines/agos/drivers/simon1/adlib.cpp
engines/agos/drivers/simon1/adlib.h
engines/agos/midi.cpp
diff --git a/engines/agos/drivers/simon1/adlib.cpp b/engines/agos/drivers/simon1/adlib.cpp
index d331b86..7f1370e 100644
--- a/engines/agos/drivers/simon1/adlib.cpp
+++ b/engines/agos/drivers/simon1/adlib.cpp
@@ -24,6 +24,7 @@
#include "common/textconsole.h"
#include "common/util.h"
+#include "common/file.h"
namespace AGOS {
@@ -491,4 +492,25 @@ const MidiDriver_Simon1_AdLib::RhythmMap MidiDriver_Simon1_AdLib::_rhythmMap[39]
{ 13, 125, 100 }
};
+MidiDriver *createMidiDriverSimon1AdLib(const char *instrumentFilename) {
+ // Load instrument data.
+ Common::File ibk;
+
+ if (!ibk.open(instrumentFilename)) {
+ return nullptr;
+ }
+
+ if (ibk.readUint32BE() != 0x49424b1a) {
+ return nullptr;
+ }
+
+ byte *instrumentData = new byte[128 * 16];
+ if (ibk.read(instrumentData, 128 * 16) != 128 * 16) {
+ delete[] instrumentData;
+ return nullptr;
+ }
+
+ return new MidiDriver_Simon1_AdLib(instrumentData);
+}
+
} // End of namespace AGOS
diff --git a/engines/agos/drivers/simon1/adlib.h b/engines/agos/drivers/simon1/adlib.h
index b92c1dd..6057bf1 100644
--- a/engines/agos/drivers/simon1/adlib.h
+++ b/engines/agos/drivers/simon1/adlib.h
@@ -111,6 +111,8 @@ private:
static const RhythmMap _rhythmMap[39];
};
+MidiDriver *createMidiDriverSimon1AdLib(const char *instrumentFilename);
+
} // End of namespace AGOS
#endif
diff --git a/engines/agos/midi.cpp b/engines/agos/midi.cpp
index 61bab7d..c5bace0 100644
--- a/engines/agos/midi.cpp
+++ b/engines/agos/midi.cpp
@@ -238,23 +238,16 @@ int MidiPlayer::open(int gameType, bool isDemo) {
_map_mt32_to_gm = false;
_nativeMT32 = false;
- // Load instrument data.
- Common::File ibk;
-
- if (ibk.open("MT_FM.IBK")) {
- if (ibk.readUint32BE() == 0x49424b1a) {
- byte *instrumentData = new byte[128 * 16];
- if (ibk.read(instrumentData, 128 * 16) == 128 * 16) {
- _driver = new MidiDriver_Simon1_AdLib(instrumentData);
- ret = _driver->open();
- if (ret == 0) {
- _driver->setTimerCallback(this, &onTimer);
- _driver->send(0xB0, 0x67, 0x01);
- return 0;
- }
- }
- }
+ _driver = createMidiDriverSimon1AdLib("MT_FM.IBK");
+ if (_driver && _driver->open() == 0) {
+ _driver->setTimerCallback(this, &onTimer);
+ // Like the original, we enable the rhythm support by default.
+ _driver->send(0xB0, 0x67, 0x01);
+ return 0;
}
+
+ delete _driver;
+ _driver = nullptr;
}
_musicMode = kMusicModeDisabled;
Commit: 757077fecc2a939e767ccd29822547828a9c5e2f
https://github.com/scummvm/scummvm/commit/757077fecc2a939e767ccd29822547828a9c5e2f
Author: Johannes Schickel (lordhoto at scummvm.org)
Date: 2015-07-23T22:33:57+02:00
Commit Message:
AGOS: Add simple volume control when Simon1 AdLib output is used.
Changed paths:
engines/agos/midi.cpp
diff --git a/engines/agos/midi.cpp b/engines/agos/midi.cpp
index c5bace0..f636c13 100644
--- a/engines/agos/midi.cpp
+++ b/engines/agos/midi.cpp
@@ -288,7 +288,28 @@ void MidiPlayer::send(uint32 b) {
return;
if (_musicMode != kMusicModeDisabled) {
- // Send directly to Accolade/Miles Audio driver
+ // Handle volume control for Simon1 output.
+ if (_musicMode == kMusicModeSimon1) {
+ // The driver does not support any volume control, thus we simply
+ // scale the velocities on note on for now.
+ // TODO: We should probably handle this at output level at some
+ // point. Then we can allow volume changes to affect already
+ // playing notes too. For now this simple change allows us to
+ // have some simple volume control though.
+ if ((b & 0xF0) == 0x90) {
+ byte volume = (b >> 16) & 0x7F;
+
+ if (_current == &_sfx) {
+ volume = volume * _sfxVolume / 255;
+ } else if (_current == &_music) {
+ volume = volume * _musicVolume / 255;
+ }
+
+ b = (b & 0xFF00FFFF) | (volume << 16);
+ }
+ }
+
+ // Send directly to Accolade/Miles/Simon1 Audio driver
_driver->send(b);
return;
}
Commit: 01eda204d63ab78dbdb5623359c21b526c38661c
https://github.com/scummvm/scummvm/commit/01eda204d63ab78dbdb5623359c21b526c38661c
Author: Johannes Schickel (lordhoto at scummvm.org)
Date: 2015-07-23T22:33:57+02:00
Commit Message:
NEWS: Mention Simon1 AdLib output addition.
Changed paths:
NEWS
diff --git a/NEWS b/NEWS
index 3e411f0..685ea7b 100644
--- a/NEWS
+++ b/NEWS
@@ -25,6 +25,8 @@ For a more comprehensive changelog of the latest experimental code, see:
- Fixed verb area been removed in Amiga versions of Simon the Sorcerer 1.
- Added Accolade AdLib & MT32 music drivers for the games:
Elvira 1, Elvira 2, Waxworks and Simon the Sorcerer 1 demo.
+ - Added Simon the Sorcerer 1 AdLib output. This vastly improves the AdLib
+ output and makes it closer to the original.
Broken Sword 1:
- Fix speech endianness detection on big endian systems for the Macintosh
Commit: 66df9c95e0eea427527491e964b40adc2a9def05
https://github.com/scummvm/scummvm/commit/66df9c95e0eea427527491e964b40adc2a9def05
Author: Johannes Schickel (lordhoto at scummvm.org)
Date: 2015-07-23T22:33:57+02:00
Commit Message:
NEWS: Slight style fix (MT32 to MT-32).
Changed paths:
NEWS
diff --git a/NEWS b/NEWS
index 685ea7b..f9aac42 100644
--- a/NEWS
+++ b/NEWS
@@ -23,7 +23,7 @@ For a more comprehensive changelog of the latest experimental code, see:
- Fixed arpeggio effect used in music of Amiga version of Elvira 1.
- Fixed loading and saving progress in the PC version of Waxworks.
- Fixed verb area been removed in Amiga versions of Simon the Sorcerer 1.
- - Added Accolade AdLib & MT32 music drivers for the games:
+ - Added Accolade AdLib & MT-32 music drivers for the games:
Elvira 1, Elvira 2, Waxworks and Simon the Sorcerer 1 demo.
- Added Simon the Sorcerer 1 AdLib output. This vastly improves the AdLib
output and makes it closer to the original.
More information about the Scummvm-git-logs
mailing list