From 037eec31446b64ec56b24e31d5be392390a694ba Mon Sep 17 00:00:00 2001 From: athrxx Date: Mon, 10 Dec 2018 00:39:10 +0100 Subject: [PATCH] SCI: implement SCI0 midi driver track initialization I put this in an separate commit to make it easier to review/revert. I've tried to make this as minimum invasive as possible. That's why I put this in place of the former call to onNewSound(). SCI_0_LATE sound drivers (probably also SCI_0_EARLY, but I don't know that) do some midi track initialization, mostly resetting certain values and assigning voices (hardware channels) to midi parts. The information for this comes from the track header. The SCI0 version of the PC-98 sound driver relies on this code. The driver checks the channel flags with two different masks and assigns different sound channel types accordingly. This can't be done with the 0x4B event. Using the 0x4B event is sort of counter intuitive anyway, since only some of the SCI0 drivers even support that event. It seems that the only driver making use of onNewSound() was MT-32. I've adapted the driver to my changes, although I am quite sure that the sound will be unaffected. The only thing that the MT-32 driver does with the header information is checking whether a midi part should play or not and assign exactly one timbre (with exactly the same number) to that part if required. --- engines/sci/resource.h | 1 + engines/sci/resource_audio.cpp | 2 ++ engines/sci/sound/drivers/midi.cpp | 47 +++++++++++++++++++++----- engines/sci/sound/drivers/mididriver.h | 9 +++-- engines/sci/sound/midiparser_sci.cpp | 14 +++----- 5 files changed, 53 insertions(+), 20 deletions(-) diff --git a/engines/sci/resource.h b/engines/sci/resource.h index 9fc9708e743..119d8600b0e 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -654,6 +654,7 @@ public: struct Track { byte type; byte channelCount; + SciSpan header; Channel *channels; int16 digitalChannelNr; uint16 digitalSampleRate; diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp index dfc3d2fcfbc..58437a653fc 100644 --- a/engines/sci/resource_audio.cpp +++ b/engines/sci/resource_audio.cpp @@ -766,6 +766,8 @@ SoundResource::SoundResource(uint32 resourceNr, ResourceManager *resMan, SciVers // Digital sample data included? -> Add an additional channel if (resource->getUint8At(0) == 2) _tracks->channelCount++; + // header information that can be passed to the SCI0 sound driver + _tracks->header = resource->subspan(0, _soundVersion == SCI_VERSION_0_EARLY ? 0x11 : 0x21); _tracks->channels = new Channel[_tracks->channelCount]; channel = &_tracks->channels[0]; channel->flags |= 2; // don't remap (SCI0 doesn't have remapping) diff --git a/engines/sci/sound/drivers/midi.cpp b/engines/sci/sound/drivers/midi.cpp index 889a8758041..4f3f0da4b05 100644 --- a/engines/sci/sound/drivers/midi.cpp +++ b/engines/sci/sound/drivers/midi.cpp @@ -158,10 +158,10 @@ public: int getFirstChannel() const override; int getLastChannel() const override; void setVolume(byte volume) override; - virtual void onNewSound() override; int getVolume() override; void setReverb(int8 reverb) override; void playSwitch(bool play) override; + virtual void initTrack(SciSpan &) override; private: bool isMt32GmPatch(const SciSpan &data); @@ -479,14 +479,6 @@ int MidiPlayer_Midi::getVolume() { return _masterVolume; } -void MidiPlayer_Midi::onNewSound() { - if (_defaultReverb >= 0) - // SCI0 in combination with MT-32 requires a reset of the reverb to - // the default value that is present in either the MT-32 patch data - // or MT32.DRV itself. - setReverb(_defaultReverb); -} - void MidiPlayer_Midi::setReverb(int8 reverb) { assert(reverb < kReverbConfigNr); @@ -507,6 +499,43 @@ void MidiPlayer_Midi::playSwitch(bool play) { } } +void MidiPlayer_Midi::initTrack(SciSpan &header) { + if (_version > SCI_VERSION_0_LATE) + return; + + if (_defaultReverb >= 0) + // SCI0 in combination with MT-32 requires a reset of the reverb to + // the default value that is present in either the MT-32 patch data + // or MT32.DRV itself. + setReverb(_defaultReverb); + + /* TODO: I have no idea what SCI_VERSION_0_EARLY games do here. + Therefore the extra code is restricted to SCI_VERSION_0_LATE for now.*/ + if (_version == SCI_VERSION_0_EARLY) + return; + + uint8 caps = header.getInt8At(0); + if (caps != 0 && caps != 2) + return; + + uint8 readPos = 3; + byte msg[9]; + uint8 flags = 0; + + for (int i = 1; i < 9; ++i) { + readPos++; + flags = header.getInt8At(readPos++); + msg[i - 1] = (flags & 1) ? i : 0x10; + } + + flags = header.getInt8At(readPos); + msg[8] = (flags & 0x80) ? 9 : 0x10; + + // assign channels + Sci::SciSpan s(msg, 9); + sendMt32SysEx(0x10000D, s, false); +} + bool MidiPlayer_Midi::isMt32GmPatch(const SciSpan &data) { uint32 size = data.size(); diff --git a/engines/sci/sound/drivers/mididriver.h b/engines/sci/sound/drivers/mididriver.h index f51851bde6a..73c2fd5737a 100644 --- a/engines/sci/sound/drivers/mididriver.h +++ b/engines/sci/sound/drivers/mididriver.h @@ -24,6 +24,7 @@ #define SCI_SFX_SOFTSEQ_MIDIDRIVER_H #include "sci/sci.h" +#include "sci/util.h" #include "audio/mididrv.h" #include "common/error.h" @@ -106,8 +107,6 @@ public: return _driver ? _driver->property(MIDI_PROP_MASTER_VOLUME, 0xffff) : 0; } - virtual void onNewSound() {} - // Returns the current reverb, or -1 when no reverb is active int8 getReverb() const { return _reverb; } // Sets the current reverb, used mainly in MT-32 @@ -121,6 +120,12 @@ public: } } + // Prepares the driver for the playback of SCI0 midi tracks. + // The main purpose is the assignment of voices ("hardware" sound channels) to the 16 midi parts. + // This is basically the predecessor of the 0x4B midi event. + // Some drivers also do other things in here. + virtual void initTrack(SciSpan &) {} + protected: SciVersion _version; }; diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp index ad4b0da397e..22a5c6de9cf 100644 --- a/engines/sci/sound/midiparser_sci.cpp +++ b/engines/sci/sound/midiparser_sci.cpp @@ -392,15 +392,11 @@ void MidiParser_SCI::sendInitCommands() { // Set initial voice count if (_pSnd) { if (_soundVersion <= SCI_VERSION_0_LATE) { - static_cast(_driver)->onNewSound(); - - for (int i = 0; i < 15; ++i) { - byte voiceCount = 0; - if (_channelUsed[i]) { - voiceCount = _pSnd->soundRes->getInitialVoiceCount(i); - sendToDriver(0xB0 | i, 0x4B, voiceCount); - } - } + // Send header data to SCI0 sound drivers. The driver function which parses the header (opcode 3) + // seems to be implemented at least in all SCI0_LATE drivers. The things that the individual drivers + // do in that init function varies. + if (_track->header.byteSize()) + static_cast(_driver)->initTrack(_track->header); } else { for (int i = 0; i < _track->channelCount; ++i) { byte voiceCount = _track->channels[i].poly;