2009-12-27 02:46:00 +00:00
|
|
|
/* 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 "sci/engine/kernel.h"
|
|
|
|
#include "sci/engine/state.h"
|
2010-01-05 01:22:16 +00:00
|
|
|
#include "sci/sound/midiparser_sci.h"
|
2010-01-21 16:27:29 +00:00
|
|
|
#include "sci/sound/drivers/mididriver.h"
|
2009-12-27 02:46:00 +00:00
|
|
|
|
|
|
|
namespace Sci {
|
|
|
|
|
|
|
|
static const int nMidiParams[] = { 2, 2, 2, 2, 1, 1, 2, 0 };
|
|
|
|
|
2010-01-03 14:39:38 +00:00
|
|
|
enum SciMidiCommands {
|
2010-01-02 17:03:58 +00:00
|
|
|
kSetSignalLoop = 0x7F,
|
|
|
|
kEndOfTrack = 0xFC,
|
|
|
|
kSetReverb = 0x50,
|
|
|
|
kMidiHold = 0x52,
|
2010-01-22 12:26:12 +00:00
|
|
|
kUpdateCue = 0x60,
|
|
|
|
kResetOnPause = 0x4C
|
2010-01-02 17:03:58 +00:00
|
|
|
};
|
2009-12-28 21:00:59 +00:00
|
|
|
|
2009-12-27 02:46:00 +00:00
|
|
|
// MidiParser_SCI
|
|
|
|
//
|
2010-06-16 21:02:58 +00:00
|
|
|
MidiParser_SCI::MidiParser_SCI(SciVersion soundVersion, SciMusic *music) :
|
2009-12-27 02:46:00 +00:00
|
|
|
MidiParser() {
|
2010-01-04 15:17:46 +00:00
|
|
|
_soundVersion = soundVersion;
|
2010-06-16 21:02:58 +00:00
|
|
|
_music = music;
|
2009-12-27 02:46:00 +00:00
|
|
|
_mixedData = NULL;
|
|
|
|
// mididata contains delta in 1/60th second
|
|
|
|
// values of ppqn and tempo are found experimentally and may be wrong
|
|
|
|
_ppqn = 1;
|
|
|
|
setTempo(16667);
|
|
|
|
|
2010-09-01 19:20:17 +00:00
|
|
|
_masterVolume = 15;
|
2010-06-28 09:22:57 +00:00
|
|
|
_volume = 127;
|
2010-01-04 19:50:58 +00:00
|
|
|
|
2009-12-27 02:46:00 +00:00
|
|
|
_signalSet = false;
|
|
|
|
_signalToSet = 0;
|
2010-01-21 22:33:35 +00:00
|
|
|
_dataincAdd = false;
|
|
|
|
_dataincToAdd = 0;
|
2010-01-22 12:26:12 +00:00
|
|
|
_resetOnPause = false;
|
2010-06-17 03:57:38 +00:00
|
|
|
_pSnd = 0;
|
2009-12-27 02:46:00 +00:00
|
|
|
}
|
2009-12-28 21:00:59 +00:00
|
|
|
|
2009-12-27 02:46:00 +00:00
|
|
|
MidiParser_SCI::~MidiParser_SCI() {
|
|
|
|
unloadMusic();
|
2010-06-26 11:16:25 +00:00
|
|
|
// we do this, so that MidiParser won't be able to call his own ::allNotesOff()
|
|
|
|
// this one would affect all channels and we can't let that happen
|
|
|
|
_driver = 0;
|
2009-12-27 02:46:00 +00:00
|
|
|
}
|
2009-12-28 21:00:59 +00:00
|
|
|
|
2010-06-21 22:07:03 +00:00
|
|
|
void MidiParser_SCI::mainThreadBegin() {
|
|
|
|
_mainThreadCalled = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MidiParser_SCI::mainThreadEnd() {
|
|
|
|
_mainThreadCalled = false;
|
|
|
|
}
|
|
|
|
|
2009-12-27 02:46:00 +00:00
|
|
|
bool MidiParser_SCI::loadMusic(SoundResource::Track *track, MusicEntry *psnd, int channelFilterMask, SciVersion soundVersion) {
|
|
|
|
unloadMusic();
|
|
|
|
_track = track;
|
|
|
|
_pSnd = psnd;
|
|
|
|
_soundVersion = soundVersion;
|
|
|
|
|
2010-06-19 20:37:53 +00:00
|
|
|
for (int i = 0; i < 16; i++) {
|
2010-06-16 21:02:58 +00:00
|
|
|
_channelUsed[i] = false;
|
|
|
|
_channelRemap[i] = -1;
|
2010-06-17 11:54:54 +00:00
|
|
|
_channelMuted[i] = false;
|
2010-06-28 09:22:57 +00:00
|
|
|
_channelVolume[i] = 127;
|
2010-06-16 21:02:58 +00:00
|
|
|
}
|
|
|
|
_channelRemap[9] = 9; // never map channel 9, because that's used for percussion
|
|
|
|
_channelRemap[15] = 15; // never map channel 15, because thats used by sierra internally
|
|
|
|
|
2009-12-27 02:46:00 +00:00
|
|
|
if (channelFilterMask) {
|
|
|
|
// SCI0 only has 1 data stream, but we need to filter out channels depending on music hardware selection
|
|
|
|
midiFilterChannels(channelFilterMask);
|
|
|
|
} else {
|
|
|
|
midiMixChannels();
|
|
|
|
}
|
|
|
|
|
|
|
|
_num_tracks = 1;
|
|
|
|
_tracks[0] = _mixedData;
|
2010-06-11 14:47:13 +00:00
|
|
|
if (_pSnd)
|
|
|
|
setTrack(0);
|
2009-12-27 02:46:00 +00:00
|
|
|
_loopTick = 0;
|
2010-01-15 07:40:07 +00:00
|
|
|
|
2010-06-19 20:23:55 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-06-28 10:00:12 +00:00
|
|
|
byte MidiParser_SCI::midiGetNextChannel(long ticker) {
|
|
|
|
byte curr = 0xFF;
|
|
|
|
long closest = ticker + 1000000, next = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < _track->channelCount; i++) {
|
|
|
|
if (_track->channels[i].time == -1) // channel ended
|
|
|
|
continue;
|
|
|
|
SoundResource::Channel *curChannel = &_track->channels[i];
|
|
|
|
if (curChannel->curPos >= curChannel->size)
|
|
|
|
continue;
|
|
|
|
next = curChannel->data[curChannel->curPos]; // when the next event should occur
|
|
|
|
if (next == 0xF8) // 0xF8 means 240 ticks delay
|
|
|
|
next = 240;
|
|
|
|
next += _track->channels[i].time;
|
|
|
|
if (next < closest) {
|
|
|
|
curr = i;
|
|
|
|
closest = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return curr;
|
|
|
|
}
|
|
|
|
|
|
|
|
byte *MidiParser_SCI::midiMixChannels() {
|
|
|
|
int totalSize = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < _track->channelCount; i++) {
|
|
|
|
_track->channels[i].time = 0;
|
|
|
|
_track->channels[i].prev = 0;
|
|
|
|
_track->channels[i].curPos = 0;
|
|
|
|
totalSize += _track->channels[i].size;
|
|
|
|
}
|
|
|
|
|
|
|
|
byte *outData = new byte[totalSize * 2]; // FIXME: creates overhead and still may be not enough to hold all data
|
|
|
|
_mixedData = outData;
|
|
|
|
long ticker = 0;
|
|
|
|
byte channelNr, curDelta;
|
|
|
|
byte midiCommand = 0, midiParam, global_prev = 0;
|
|
|
|
long newDelta;
|
|
|
|
SoundResource::Channel *channel;
|
|
|
|
|
|
|
|
while ((channelNr = midiGetNextChannel(ticker)) != 0xFF) { // there is still an active channel
|
|
|
|
channel = &_track->channels[channelNr];
|
|
|
|
curDelta = channel->data[channel->curPos++];
|
|
|
|
channel->time += (curDelta == 0xF8 ? 240 : curDelta); // when the command is supposed to occur
|
|
|
|
if (curDelta == 0xF8)
|
|
|
|
continue;
|
|
|
|
newDelta = channel->time - ticker;
|
|
|
|
ticker += newDelta;
|
|
|
|
|
|
|
|
midiCommand = channel->data[channel->curPos++];
|
|
|
|
if (midiCommand != kEndOfTrack) {
|
|
|
|
// Write delta
|
|
|
|
while (newDelta > 240) {
|
|
|
|
*outData++ = 0xF8;
|
|
|
|
newDelta -= 240;
|
|
|
|
}
|
|
|
|
*outData++ = (byte)newDelta;
|
|
|
|
}
|
|
|
|
// Write command
|
|
|
|
switch (midiCommand) {
|
|
|
|
case 0xF0: // sysEx
|
|
|
|
*outData++ = midiCommand;
|
|
|
|
do {
|
|
|
|
midiParam = channel->data[channel->curPos++];
|
|
|
|
*outData++ = midiParam;
|
|
|
|
} while (midiParam != 0xF7);
|
|
|
|
break;
|
|
|
|
case kEndOfTrack: // end of channel
|
|
|
|
channel->time = -1;
|
|
|
|
break;
|
|
|
|
default: // MIDI command
|
|
|
|
if (midiCommand & 0x80) {
|
|
|
|
midiParam = channel->data[channel->curPos++];
|
|
|
|
} else {// running status
|
|
|
|
midiParam = midiCommand;
|
|
|
|
midiCommand = channel->prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
// remember which channel got used for channel remapping
|
|
|
|
byte midiChannel = midiCommand & 0xF;
|
|
|
|
_channelUsed[midiChannel] = true;
|
|
|
|
|
|
|
|
if (midiCommand != global_prev)
|
|
|
|
*outData++ = midiCommand;
|
|
|
|
*outData++ = midiParam;
|
|
|
|
if (nMidiParams[(midiCommand >> 4) - 8] == 2)
|
|
|
|
*outData++ = channel->data[channel->curPos++];
|
|
|
|
channel->prev = midiCommand;
|
|
|
|
global_prev = midiCommand;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert stop event
|
|
|
|
*outData++ = 0; // Delta
|
|
|
|
*outData++ = 0xFF; // Meta event
|
|
|
|
*outData++ = 0x2F; // End of track (EOT)
|
|
|
|
*outData++ = 0x00;
|
|
|
|
*outData++ = 0x00;
|
|
|
|
return _mixedData;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is used for SCI0 sound-data. SCI0 only has one stream that may
|
|
|
|
// contain several channels and according to output device we remove
|
|
|
|
// certain channels from that data.
|
|
|
|
byte *MidiParser_SCI::midiFilterChannels(int channelMask) {
|
|
|
|
SoundResource::Channel *channel = &_track->channels[0];
|
|
|
|
byte *channelData = channel->data;
|
|
|
|
byte *channelDataEnd = channel->data + channel->size;
|
|
|
|
byte *outData = new byte[channel->size + 5];
|
|
|
|
byte curChannel = 15, curByte, curDelta;
|
|
|
|
byte command = 0, lastCommand = 0;
|
|
|
|
int delta = 0;
|
|
|
|
int midiParamCount = 0;
|
2011-05-12 04:34:20 +03:00
|
|
|
bool containsMidiData = false;
|
2010-06-28 10:00:12 +00:00
|
|
|
|
|
|
|
_mixedData = outData;
|
|
|
|
|
|
|
|
while (channelData < channelDataEnd) {
|
|
|
|
curDelta = *channelData++;
|
|
|
|
if (curDelta == 0xF8) {
|
|
|
|
delta += 240;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
delta += curDelta;
|
|
|
|
curByte = *channelData++;
|
|
|
|
|
|
|
|
switch (curByte) {
|
|
|
|
case 0xF0: // sysEx
|
|
|
|
case kEndOfTrack: // end of channel
|
|
|
|
command = curByte;
|
|
|
|
curChannel = 15;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (curByte & 0x80) {
|
|
|
|
command = curByte;
|
|
|
|
curChannel = command & 0x0F;
|
|
|
|
midiParamCount = nMidiParams[(command >> 4) - 8];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((1 << curChannel) & channelMask) {
|
2011-05-12 04:34:20 +03:00
|
|
|
if (curChannel != 0xF)
|
|
|
|
containsMidiData = true;
|
|
|
|
|
2010-06-28 10:00:12 +00:00
|
|
|
if (command != kEndOfTrack) {
|
|
|
|
// Write delta
|
|
|
|
while (delta > 240) {
|
|
|
|
*outData++ = 0xF8;
|
|
|
|
delta -= 240;
|
|
|
|
}
|
|
|
|
*outData++ = (byte)delta;
|
|
|
|
delta = 0;
|
|
|
|
}
|
|
|
|
// Write command
|
|
|
|
switch (command) {
|
|
|
|
case 0xF0: // sysEx
|
|
|
|
*outData++ = command;
|
|
|
|
do {
|
|
|
|
curByte = *channelData++;
|
|
|
|
*outData++ = curByte; // out
|
|
|
|
} while (curByte != 0xF7);
|
|
|
|
lastCommand = command;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case kEndOfTrack: // end of channel
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: // MIDI command
|
|
|
|
// remember which channel got used for channel remapping
|
|
|
|
byte midiChannel = command & 0xF;
|
|
|
|
_channelUsed[midiChannel] = true;
|
|
|
|
|
|
|
|
if (lastCommand != command) {
|
|
|
|
*outData++ = command;
|
|
|
|
lastCommand = command;
|
|
|
|
}
|
|
|
|
if (midiParamCount > 0) {
|
|
|
|
if (curByte & 0x80)
|
|
|
|
*outData++ = *channelData++;
|
|
|
|
else
|
|
|
|
*outData++ = curByte;
|
|
|
|
}
|
|
|
|
if (midiParamCount > 1) {
|
|
|
|
*outData++ = *channelData++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (curByte & 0x80)
|
|
|
|
channelData += midiParamCount;
|
|
|
|
else
|
|
|
|
channelData += midiParamCount - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert stop event
|
|
|
|
*outData++ = 0; // Delta
|
|
|
|
*outData++ = 0xFF; // Meta event
|
|
|
|
*outData++ = 0x2F; // End of track (EOT)
|
|
|
|
*outData++ = 0x00;
|
|
|
|
*outData++ = 0x00;
|
|
|
|
|
2011-05-12 04:34:20 +03:00
|
|
|
// This occurs in the music tracks of LB1 Amiga, when using the MT-32
|
|
|
|
// driver (bug #3297881)
|
|
|
|
if (!containsMidiData)
|
|
|
|
warning("MIDI parser: the requested SCI0 sound has no MIDI note data for the currently selected sound driver");
|
|
|
|
|
2010-06-28 10:00:12 +00:00
|
|
|
return _mixedData;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This will get called right before actual playing and will try to own the used channels
|
|
|
|
void MidiParser_SCI::tryToOwnChannels() {
|
|
|
|
// We don't have SciMusic in case debug command show_instruments is used
|
|
|
|
if (!_music)
|
|
|
|
return;
|
|
|
|
for (int curChannel = 0; curChannel < 15; curChannel++) {
|
|
|
|
if (_channelUsed[curChannel]) {
|
|
|
|
if (_channelRemap[curChannel] == -1) {
|
|
|
|
_channelRemap[curChannel] = _music->tryToOwnChannel(_pSnd, curChannel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MidiParser_SCI::lostChannels() {
|
|
|
|
for (int curChannel = 0; curChannel < 15; curChannel++)
|
|
|
|
if ((_channelUsed[curChannel]) && (curChannel != 9))
|
|
|
|
_channelRemap[curChannel] = -1;
|
|
|
|
}
|
|
|
|
|
2010-06-19 20:23:55 +00:00
|
|
|
void MidiParser_SCI::sendInitCommands() {
|
2010-06-28 09:22:57 +00:00
|
|
|
// reset our "global" volume and channel volumes
|
|
|
|
_volume = 127;
|
|
|
|
for (int i = 0; i < 16; i++)
|
|
|
|
_channelVolume[i] = 127;
|
|
|
|
|
|
|
|
// Set initial voice count
|
2010-06-11 14:47:13 +00:00
|
|
|
if (_pSnd) {
|
|
|
|
if (_soundVersion <= SCI_VERSION_0_LATE) {
|
2010-06-19 20:23:55 +00:00
|
|
|
for (int i = 0; i < 15; ++i) {
|
2010-06-11 14:47:13 +00:00
|
|
|
byte voiceCount = 0;
|
2010-06-19 20:23:55 +00:00
|
|
|
if (_channelUsed[i]) {
|
|
|
|
voiceCount = _pSnd->soundRes->getInitialVoiceCount(i);
|
2010-06-21 22:07:03 +00:00
|
|
|
sendToDriver(0xB0 | i, 0x4B, voiceCount);
|
2010-06-19 20:23:55 +00:00
|
|
|
}
|
2010-06-11 14:47:13 +00:00
|
|
|
}
|
2010-01-26 19:25:33 +00:00
|
|
|
}
|
2010-01-15 22:15:58 +00:00
|
|
|
}
|
|
|
|
|
2011-11-20 20:56:43 +02:00
|
|
|
// Reset all the parameters of the channels used by this song
|
2010-06-28 08:25:45 +00:00
|
|
|
for (int i = 0; i < 16; ++i) {
|
|
|
|
if (_channelUsed[i]) {
|
2011-11-20 20:56:43 +02:00
|
|
|
sendToDriver(0xB0 | i, 0x07, 127); // Reset volume to maximum
|
|
|
|
sendToDriver(0xB0 | i, 0x0A, 64); // Reset panning to center
|
|
|
|
sendToDriver(0xB0 | i, 0x40, 0); // Reset hold pedal to none
|
|
|
|
sendToDriver(0xB0 | i, 0x4E, 0); // Reset velocity to none
|
|
|
|
sendToDriver(0xE0 | i, 0, 64); // Reset pitch wheel to center
|
2010-06-28 08:25:45 +00:00
|
|
|
}
|
|
|
|
}
|
2009-12-27 02:46:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MidiParser_SCI::unloadMusic() {
|
2010-06-11 14:47:13 +00:00
|
|
|
if (_pSnd) {
|
|
|
|
resetTracking();
|
|
|
|
allNotesOff();
|
|
|
|
}
|
2009-12-27 02:46:00 +00:00
|
|
|
_num_tracks = 0;
|
2010-01-13 14:46:45 +00:00
|
|
|
_active_track = 255;
|
2010-01-22 12:32:54 +00:00
|
|
|
_resetOnPause = false;
|
2010-01-13 14:46:45 +00:00
|
|
|
|
2009-12-27 02:46:00 +00:00
|
|
|
if (_mixedData) {
|
|
|
|
delete[] _mixedData;
|
|
|
|
_mixedData = NULL;
|
|
|
|
}
|
2010-06-16 21:02:58 +00:00
|
|
|
}
|
2010-06-03 21:57:49 +00:00
|
|
|
|
2010-06-21 22:07:03 +00:00
|
|
|
// this is used for scripts sending midi commands to us. we verify in that case that the channel is actually
|
|
|
|
// used, so that channel remapping will work as well and then send them on
|
|
|
|
void MidiParser_SCI::sendFromScriptToDriver(uint32 midi) {
|
|
|
|
byte midiChannel = midi & 0xf;
|
2010-06-19 20:00:32 +00:00
|
|
|
|
|
|
|
if (!_channelUsed[midiChannel]) {
|
2010-06-20 10:25:46 +00:00
|
|
|
// trying to send to an unused channel
|
|
|
|
// this happens for cmdSendMidi at least in sq1vga right at the start, it's a script issue
|
2010-06-19 20:00:32 +00:00
|
|
|
return;
|
|
|
|
}
|
2010-06-28 08:16:20 +00:00
|
|
|
if (_channelRemap[midiChannel] == -1) {
|
|
|
|
// trying to send to an unmapped channel
|
|
|
|
// this happens for cmdSendMidi at least in sq1vga right at the start, scripts are pausing the sound
|
|
|
|
// and then sending manually. it's a script issue
|
|
|
|
return;
|
|
|
|
}
|
2010-06-21 22:07:03 +00:00
|
|
|
sendToDriver(midi);
|
2010-06-20 10:25:46 +00:00
|
|
|
}
|
|
|
|
|
2010-06-21 22:07:03 +00:00
|
|
|
void MidiParser_SCI::sendToDriver(uint32 midi) {
|
|
|
|
byte midiChannel = midi & 0xf;
|
2010-06-20 10:25:46 +00:00
|
|
|
|
2010-06-21 22:07:03 +00:00
|
|
|
if ((midi & 0xFFF0) == 0x4EB0) {
|
2010-06-17 11:54:54 +00:00
|
|
|
// this is channel mute only for sci1
|
|
|
|
// it's velocity control for sci0
|
|
|
|
if (_soundVersion >= SCI_VERSION_1_EARLY) {
|
2010-06-21 22:07:03 +00:00
|
|
|
_channelMuted[midiChannel] = midi & 0xFF0000 ? true : false;
|
2010-06-17 11:54:54 +00:00
|
|
|
return; // don't send this to driver at all
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Is channel muted? if so, don't send command
|
|
|
|
if (_channelMuted[midiChannel])
|
|
|
|
return;
|
2010-06-28 09:22:57 +00:00
|
|
|
|
|
|
|
if ((midi & 0xFFF0) == 0x07B0) {
|
|
|
|
// someone trying to set channel volume?
|
|
|
|
int channelVolume = (midi >> 16) & 0xFF;
|
|
|
|
// Remember, if we need to set it ourselves
|
|
|
|
_channelVolume[midiChannel] = channelVolume;
|
2010-09-01 19:20:17 +00:00
|
|
|
// Adjust volume accordingly to current local volume
|
2010-06-28 09:22:57 +00:00
|
|
|
channelVolume = channelVolume * _volume / 127;
|
|
|
|
midi = (midi & 0xFFF0) | ((channelVolume & 0xFF) << 16);
|
|
|
|
}
|
|
|
|
|
2010-06-16 21:02:58 +00:00
|
|
|
// Channel remapping
|
2010-06-17 11:54:54 +00:00
|
|
|
int16 realChannel = _channelRemap[midiChannel];
|
2010-08-03 21:38:26 +00:00
|
|
|
if (realChannel == -1)
|
|
|
|
return;
|
2010-06-18 02:16:00 +00:00
|
|
|
|
2010-06-21 22:07:03 +00:00
|
|
|
midi = (midi & 0xFFFFFFF0) | realChannel;
|
|
|
|
if (_mainThreadCalled)
|
|
|
|
_music->putMidiCommandInQueue(midi);
|
|
|
|
else
|
|
|
|
_driver->send(midi);
|
2009-12-27 02:46:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MidiParser_SCI::parseNextEvent(EventInfo &info) {
|
|
|
|
// Set signal AFTER waiting for delta, otherwise we would set signal too soon resulting in all sorts of bugs
|
2010-01-21 22:33:35 +00:00
|
|
|
if (_dataincAdd) {
|
|
|
|
_dataincAdd = false;
|
|
|
|
_pSnd->dataInc += _dataincToAdd;
|
|
|
|
_pSnd->signal = 0x7f + _pSnd->dataInc;
|
2010-06-12 11:41:22 +00:00
|
|
|
debugC(4, kDebugLevelSound, "datainc %04x", _dataincToAdd);
|
2010-01-21 22:33:35 +00:00
|
|
|
}
|
2009-12-27 02:46:00 +00:00
|
|
|
if (_signalSet) {
|
|
|
|
_signalSet = false;
|
2010-08-18 20:00:18 +00:00
|
|
|
_pSnd->setSignal(_signalToSet);
|
|
|
|
|
2010-06-12 11:41:22 +00:00
|
|
|
debugC(4, kDebugLevelSound, "signal %04x", _signalToSet);
|
2009-12-27 02:46:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
info.start = _position._play_pos;
|
|
|
|
info.delta = 0;
|
|
|
|
while (*_position._play_pos == 0xF8) {
|
|
|
|
info.delta += 240;
|
|
|
|
_position._play_pos++;
|
|
|
|
}
|
|
|
|
info.delta += *(_position._play_pos++);
|
|
|
|
|
|
|
|
// Process the next info.
|
|
|
|
if ((_position._play_pos[0] & 0xF0) >= 0x80)
|
|
|
|
info.event = *(_position._play_pos++);
|
|
|
|
else
|
|
|
|
info.event = _position._running_status;
|
|
|
|
if (info.event < 0x80)
|
|
|
|
return;
|
|
|
|
|
|
|
|
_position._running_status = info.event;
|
|
|
|
switch (info.command()) {
|
|
|
|
case 0xC:
|
|
|
|
info.basic.param1 = *(_position._play_pos++);
|
|
|
|
info.basic.param2 = 0;
|
|
|
|
if (info.channel() == 0xF) {// SCI special case
|
2010-01-02 17:03:58 +00:00
|
|
|
if (info.basic.param1 != kSetSignalLoop) {
|
2011-08-28 14:06:57 +03:00
|
|
|
// At least in kq5/french&mac the first scene in the intro has
|
|
|
|
// a song that sets signal to 4 immediately on tick 0. Signal
|
|
|
|
// isn't set at that point by sierra sci and it would cause the
|
|
|
|
// castle daventry text to get immediately removed, so we
|
|
|
|
// currently filter it. Sierra SCI ignores them as well at that
|
|
|
|
// time. However, this filtering should only be performed for
|
|
|
|
// SCI1 and newer games. Signalling is done differently in SCI0
|
|
|
|
// though, so ignoring these signals in SCI0 games will result
|
|
|
|
// in glitches (e.g. the intro of LB1 Amiga gets stuck - bug
|
|
|
|
// #3297883). Refer to MusicEntry::setSignal() in sound/music.cpp.
|
|
|
|
if (_soundVersion <= SCI_VERSION_0_LATE ||
|
|
|
|
_position._play_tick || info.delta) {
|
2010-06-28 22:06:19 +00:00
|
|
|
_signalSet = true;
|
|
|
|
_signalToSet = info.basic.param1;
|
|
|
|
}
|
2009-12-27 02:46:00 +00:00
|
|
|
} else {
|
2010-06-10 20:52:04 +00:00
|
|
|
_loopTick = _position._play_tick + info.delta;
|
2009-12-27 02:46:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0xD:
|
|
|
|
info.basic.param1 = *(_position._play_pos++);
|
|
|
|
info.basic.param2 = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xB:
|
|
|
|
info.basic.param1 = *(_position._play_pos++);
|
|
|
|
info.basic.param2 = *(_position._play_pos++);
|
2010-11-26 00:05:27 +00:00
|
|
|
|
2010-11-27 17:29:42 +00:00
|
|
|
// Reference for some events:
|
|
|
|
// http://wiki.scummvm.org/index.php/SCI/Specifications/Sound/SCI0_Resource_Format#Status_Reference
|
|
|
|
// Handle common special events
|
|
|
|
switch (info.basic.param1) {
|
|
|
|
case kSetReverb:
|
|
|
|
if (info.basic.param2 == 127) // Set global reverb instead
|
|
|
|
_pSnd->reverb = _music->getGlobalReverb();
|
|
|
|
else
|
|
|
|
_pSnd->reverb = info.basic.param2;
|
|
|
|
|
|
|
|
((MidiPlayer *)_driver)->setReverb(_pSnd->reverb);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle events sent to the SCI special channel (15)
|
|
|
|
if (info.channel() == 0xF) {
|
|
|
|
switch (info.basic.param1) {
|
2010-11-27 18:27:02 +00:00
|
|
|
case kSetReverb:
|
|
|
|
// Already handled above
|
|
|
|
break;
|
2010-01-02 17:03:58 +00:00
|
|
|
case kMidiHold:
|
2010-01-02 18:16:12 +00:00
|
|
|
// Check if the hold ID marker is the same as the hold ID
|
|
|
|
// marker set for that song by cmdSetSoundHold.
|
2010-01-02 20:20:36 +00:00
|
|
|
// If it is, loop back, but don't stop notes when jumping.
|
2010-01-02 15:37:17 +00:00
|
|
|
if (info.basic.param2 == _pSnd->hold)
|
2010-01-02 20:20:36 +00:00
|
|
|
jumpToTick(_loopTick, false, false);
|
SCI/new music code:
- Resolved a deadlock with the mixer, and added appropriate mutexes (a result of the fact that SCI mixes MIDI and digital audio in the same list)
- Fixed sound playing when loading games, by properly resetting the MIDI driver
- Reverted savegame version to 14 - the changes in versions 15 and 16 don't have any effect on the currently enabled old music code, and the new music code is disabled by default, and is still prone to changes
- Now saving/loading signal, loop and hold for each sound, as well as reverb
- Added stub code for setting reverb and channel hold
- The signal, loop and hold values of each song are cached, like in SSCI and like what happens in Greg's SCI implementation. This allows a clear separation of the engine code from the rest of the engine. Reverted commits 46792 and 46797
- Removed duplicate song list accessing code
- Song cues are now updated in kAnimate for SCI0, like the old music code does, to compensate for the fact that SCI0 didn't poll for music changes via cmdUpdateCues, like what SCI01 and newer do
- Cleanup
svn-id: r46812
2010-01-01 06:41:52 +00:00
|
|
|
break;
|
2010-01-02 17:03:58 +00:00
|
|
|
case kUpdateCue:
|
2010-01-21 22:33:35 +00:00
|
|
|
_dataincAdd = true;
|
2009-12-27 02:46:00 +00:00
|
|
|
switch (_soundVersion) {
|
|
|
|
case SCI_VERSION_0_EARLY:
|
|
|
|
case SCI_VERSION_0_LATE:
|
2010-01-21 22:33:35 +00:00
|
|
|
_dataincToAdd = info.basic.param2;
|
2009-12-27 02:46:00 +00:00
|
|
|
break;
|
|
|
|
case SCI_VERSION_1_EARLY:
|
|
|
|
case SCI_VERSION_1_LATE:
|
2010-07-14 11:29:55 +00:00
|
|
|
case SCI_VERSION_2_1:
|
2010-01-21 22:33:35 +00:00
|
|
|
_dataincToAdd = 1;
|
2009-12-27 02:46:00 +00:00
|
|
|
break;
|
|
|
|
default:
|
2010-07-13 18:15:19 +00:00
|
|
|
error("unsupported _soundVersion");
|
2009-12-27 02:46:00 +00:00
|
|
|
}
|
SCI/new music code:
- Resolved a deadlock with the mixer, and added appropriate mutexes (a result of the fact that SCI mixes MIDI and digital audio in the same list)
- Fixed sound playing when loading games, by properly resetting the MIDI driver
- Reverted savegame version to 14 - the changes in versions 15 and 16 don't have any effect on the currently enabled old music code, and the new music code is disabled by default, and is still prone to changes
- Now saving/loading signal, loop and hold for each sound, as well as reverb
- Added stub code for setting reverb and channel hold
- The signal, loop and hold values of each song are cached, like in SSCI and like what happens in Greg's SCI implementation. This allows a clear separation of the engine code from the rest of the engine. Reverted commits 46792 and 46797
- Removed duplicate song list accessing code
- Song cues are now updated in kAnimate for SCI0, like the old music code does, to compensate for the fact that SCI0 didn't poll for music changes via cmdUpdateCues, like what SCI01 and newer do
- Cleanup
svn-id: r46812
2010-01-01 06:41:52 +00:00
|
|
|
break;
|
2010-01-22 12:26:12 +00:00
|
|
|
case kResetOnPause:
|
|
|
|
_resetOnPause = info.basic.param2;
|
|
|
|
break;
|
2010-01-03 16:11:31 +00:00
|
|
|
// Unhandled SCI commands
|
|
|
|
case 0x46: // LSL3 - binoculars
|
2010-01-25 00:13:32 +00:00
|
|
|
case 0x61: // Iceman (AdLib?)
|
2010-01-03 16:11:31 +00:00
|
|
|
case 0x73: // Hoyle
|
2010-01-15 07:40:07 +00:00
|
|
|
case 0xD1: // KQ4, when riding the unicorn
|
2010-01-03 16:11:31 +00:00
|
|
|
// Obscure SCI commands - ignored
|
|
|
|
break;
|
|
|
|
// Standard MIDI commands
|
2010-01-03 14:39:38 +00:00
|
|
|
case 0x01: // mod wheel
|
2010-01-03 15:59:43 +00:00
|
|
|
case 0x04: // foot controller
|
2010-01-03 14:39:38 +00:00
|
|
|
case 0x07: // channel volume
|
|
|
|
case 0x0A: // pan
|
2010-01-03 15:59:43 +00:00
|
|
|
case 0x0B: // expression
|
|
|
|
case 0x40: // sustain
|
|
|
|
case 0x79: // reset all
|
2010-01-03 14:39:38 +00:00
|
|
|
case 0x7B: // notes off
|
|
|
|
// These are all handled by the music driver, so ignore them
|
|
|
|
break;
|
|
|
|
case 0x4B: // voice mapping
|
|
|
|
// TODO: is any support for this needed at the MIDI parser level?
|
|
|
|
warning("Unhanded SCI MIDI command 0x%x - voice mapping (parameter %d)", info.basic.param1, info.basic.param2);
|
|
|
|
break;
|
SCI/new music code:
- Resolved a deadlock with the mixer, and added appropriate mutexes (a result of the fact that SCI mixes MIDI and digital audio in the same list)
- Fixed sound playing when loading games, by properly resetting the MIDI driver
- Reverted savegame version to 14 - the changes in versions 15 and 16 don't have any effect on the currently enabled old music code, and the new music code is disabled by default, and is still prone to changes
- Now saving/loading signal, loop and hold for each sound, as well as reverb
- Added stub code for setting reverb and channel hold
- The signal, loop and hold values of each song are cached, like in SSCI and like what happens in Greg's SCI implementation. This allows a clear separation of the engine code from the rest of the engine. Reverted commits 46792 and 46797
- Removed duplicate song list accessing code
- Song cues are now updated in kAnimate for SCI0, like the old music code does, to compensate for the fact that SCI0 didn't poll for music changes via cmdUpdateCues, like what SCI01 and newer do
- Cleanup
svn-id: r46812
2010-01-01 06:41:52 +00:00
|
|
|
default:
|
2010-01-03 14:39:38 +00:00
|
|
|
warning("Unhandled SCI MIDI command 0x%x (parameter %d)", info.basic.param1, info.basic.param2);
|
SCI/new music code:
- Resolved a deadlock with the mixer, and added appropriate mutexes (a result of the fact that SCI mixes MIDI and digital audio in the same list)
- Fixed sound playing when loading games, by properly resetting the MIDI driver
- Reverted savegame version to 14 - the changes in versions 15 and 16 don't have any effect on the currently enabled old music code, and the new music code is disabled by default, and is still prone to changes
- Now saving/loading signal, loop and hold for each sound, as well as reverb
- Added stub code for setting reverb and channel hold
- The signal, loop and hold values of each song are cached, like in SSCI and like what happens in Greg's SCI implementation. This allows a clear separation of the engine code from the rest of the engine. Reverted commits 46792 and 46797
- Removed duplicate song list accessing code
- Song cues are now updated in kAnimate for SCI0, like the old music code does, to compensate for the fact that SCI0 didn't poll for music changes via cmdUpdateCues, like what SCI01 and newer do
- Cleanup
svn-id: r46812
2010-01-01 06:41:52 +00:00
|
|
|
break;
|
2009-12-27 02:46:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
info.length = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x8:
|
|
|
|
case 0x9:
|
|
|
|
case 0xA:
|
|
|
|
case 0xE:
|
|
|
|
info.basic.param1 = *(_position._play_pos++);
|
|
|
|
info.basic.param2 = *(_position._play_pos++);
|
|
|
|
if (info.command() == 0x9 && info.basic.param2 == 0)
|
|
|
|
info.event = info.channel() | 0x80;
|
|
|
|
info.length = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xF: // System Common, Meta or SysEx event
|
|
|
|
switch (info.event & 0x0F) {
|
|
|
|
case 0x2: // Song Position Pointer
|
|
|
|
info.basic.param1 = *(_position._play_pos++);
|
|
|
|
info.basic.param2 = *(_position._play_pos++);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x3: // Song Select
|
|
|
|
info.basic.param1 = *(_position._play_pos++);
|
|
|
|
info.basic.param2 = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x6:
|
|
|
|
case 0x8:
|
|
|
|
case 0xA:
|
|
|
|
case 0xB:
|
|
|
|
case 0xC:
|
|
|
|
case 0xE:
|
|
|
|
info.basic.param1 = info.basic.param2 = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x0: // SysEx
|
|
|
|
info.length = readVLQ(_position._play_pos);
|
|
|
|
info.ext.data = _position._play_pos;
|
|
|
|
_position._play_pos += info.length;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xF: // META event
|
|
|
|
info.ext.type = *(_position._play_pos++);
|
|
|
|
info.length = readVLQ(_position._play_pos);
|
|
|
|
info.ext.data = _position._play_pos;
|
|
|
|
_position._play_pos += info.length;
|
|
|
|
if (info.ext.type == 0x2F) {// end of track reached
|
SCI/new music code:
- Resolved a deadlock with the mixer, and added appropriate mutexes (a result of the fact that SCI mixes MIDI and digital audio in the same list)
- Fixed sound playing when loading games, by properly resetting the MIDI driver
- Reverted savegame version to 14 - the changes in versions 15 and 16 don't have any effect on the currently enabled old music code, and the new music code is disabled by default, and is still prone to changes
- Now saving/loading signal, loop and hold for each sound, as well as reverb
- Added stub code for setting reverb and channel hold
- The signal, loop and hold values of each song are cached, like in SSCI and like what happens in Greg's SCI implementation. This allows a clear separation of the engine code from the rest of the engine. Reverted commits 46792 and 46797
- Removed duplicate song list accessing code
- Song cues are now updated in kAnimate for SCI0, like the old music code does, to compensate for the fact that SCI0 didn't poll for music changes via cmdUpdateCues, like what SCI01 and newer do
- Cleanup
svn-id: r46812
2010-01-01 06:41:52 +00:00
|
|
|
if (_pSnd->loop)
|
|
|
|
_pSnd->loop--;
|
2011-08-26 11:29:13 +03:00
|
|
|
// QFG3 abuses the hold flag. Its scripts call kDoSoundSetHold,
|
|
|
|
// but sometimes there's no hold marker in the associated songs
|
|
|
|
// (e.g. song 110, during the intro). The original interpreter
|
|
|
|
// treats this case as an infinite loop (bug #3311911).
|
|
|
|
if (_pSnd->loop || _pSnd->hold > 0) {
|
2009-12-30 21:22:00 +00:00
|
|
|
// We need to play it again...
|
2009-12-27 02:46:00 +00:00
|
|
|
jumpToTick(_loopTick);
|
|
|
|
} else {
|
2009-12-28 20:58:00 +00:00
|
|
|
_pSnd->status = kSoundStopped;
|
2010-08-18 20:00:18 +00:00
|
|
|
_pSnd->setSignal(SIGNAL_OFFSET);
|
SCI/new music code:
- Resolved a deadlock with the mixer, and added appropriate mutexes (a result of the fact that SCI mixes MIDI and digital audio in the same list)
- Fixed sound playing when loading games, by properly resetting the MIDI driver
- Reverted savegame version to 14 - the changes in versions 15 and 16 don't have any effect on the currently enabled old music code, and the new music code is disabled by default, and is still prone to changes
- Now saving/loading signal, loop and hold for each sound, as well as reverb
- Added stub code for setting reverb and channel hold
- The signal, loop and hold values of each song are cached, like in SSCI and like what happens in Greg's SCI implementation. This allows a clear separation of the engine code from the rest of the engine. Reverted commits 46792 and 46797
- Removed duplicate song list accessing code
- Song cues are now updated in kAnimate for SCI0, like the old music code does, to compensate for the fact that SCI0 didn't poll for music changes via cmdUpdateCues, like what SCI01 and newer do
- Cleanup
svn-id: r46812
2010-01-01 06:41:52 +00:00
|
|
|
|
2010-06-12 11:41:22 +00:00
|
|
|
debugC(4, kDebugLevelSound, "signal EOT");
|
2009-12-27 02:46:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
warning(
|
|
|
|
"MidiParser_SCI::parseNextEvent: Unsupported event code %x",
|
|
|
|
info.event);
|
|
|
|
} // // System Common, Meta or SysEx event
|
|
|
|
}// switch (info.command())
|
|
|
|
}
|
|
|
|
|
2010-11-25 16:09:45 +00:00
|
|
|
byte MidiParser_SCI::getSongReverb() {
|
2010-11-26 14:35:46 +00:00
|
|
|
assert(_track);
|
|
|
|
|
|
|
|
if (_soundVersion >= SCI_VERSION_1_EARLY) {
|
|
|
|
for (int i = 0; i < _track->channelCount; i++) {
|
|
|
|
SoundResource::Channel &channel = _track->channels[i];
|
|
|
|
// Peek ahead in the control channel to get the default reverb setting
|
|
|
|
if (channel.number == 15 && channel.size >= 7)
|
|
|
|
return channel.data[6];
|
2010-11-25 16:09:45 +00:00
|
|
|
}
|
2010-11-26 14:35:46 +00:00
|
|
|
}
|
2010-11-25 16:09:45 +00:00
|
|
|
|
2010-11-26 14:35:46 +00:00
|
|
|
return 127;
|
2010-11-25 16:09:45 +00:00
|
|
|
}
|
|
|
|
|
2010-06-14 22:35:49 +00:00
|
|
|
void MidiParser_SCI::allNotesOff() {
|
|
|
|
if (!_driver)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
// Turn off all active notes
|
|
|
|
for (i = 0; i < 128; ++i) {
|
|
|
|
for (j = 0; j < 16; ++j) {
|
2010-06-21 10:51:14 +00:00
|
|
|
if ((_active_notes[i] & (1 << j)) && (_channelRemap[j] != -1)){
|
|
|
|
sendToDriver(0x80 | j, i, 0);
|
2010-06-14 22:35:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Turn off all hanging notes
|
|
|
|
for (i = 0; i < ARRAYSIZE(_hanging_notes); i++) {
|
2010-06-21 10:51:14 +00:00
|
|
|
byte midiChannel = _hanging_notes[i].channel;
|
|
|
|
if ((_hanging_notes[i].time_left) && (_channelRemap[midiChannel] != -1)) {
|
|
|
|
sendToDriver(0x80 | midiChannel, _hanging_notes[i].note, 0);
|
2010-06-14 22:35:49 +00:00
|
|
|
_hanging_notes[i].time_left = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_hanging_notes_count = 0;
|
|
|
|
|
|
|
|
// To be sure, send an "All Note Off" event (but not all MIDI devices
|
|
|
|
// support this...).
|
|
|
|
|
2010-06-21 10:51:14 +00:00
|
|
|
for (i = 0; i < 16; ++i) {
|
2010-11-23 16:03:30 +00:00
|
|
|
if (_channelRemap[i] != -1) {
|
2010-06-21 10:51:14 +00:00
|
|
|
sendToDriver(0xB0 | i, 0x7b, 0); // All notes off
|
2010-11-23 16:03:30 +00:00
|
|
|
sendToDriver(0xB0 | i, 0x40, 0); // Also send a sustain off event (bug #3116608)
|
|
|
|
}
|
2010-06-21 10:51:14 +00:00
|
|
|
}
|
2010-06-14 22:35:49 +00:00
|
|
|
|
|
|
|
memset(_active_notes, 0, sizeof(_active_notes));
|
|
|
|
}
|
2009-12-28 21:00:59 +00:00
|
|
|
|
2010-09-01 19:20:17 +00:00
|
|
|
void MidiParser_SCI::setMasterVolume(byte masterVolume) {
|
|
|
|
assert(masterVolume <= MUSIC_MASTERVOLUME_MAX);
|
|
|
|
_masterVolume = masterVolume;
|
|
|
|
switch (_soundVersion) {
|
|
|
|
case SCI_VERSION_0_EARLY:
|
|
|
|
case SCI_VERSION_0_LATE:
|
|
|
|
// update driver master volume
|
|
|
|
setVolume(_volume);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SCI_VERSION_1_EARLY:
|
|
|
|
case SCI_VERSION_1_LATE:
|
|
|
|
case SCI_VERSION_2_1:
|
|
|
|
// directly set master volume (global volume is merged with channel volumes)
|
|
|
|
((MidiPlayer *)_driver)->setVolume(masterVolume);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
error("MidiParser_SCI::setVolume: Unsupported soundVersion");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-05 10:28:09 +00:00
|
|
|
void MidiParser_SCI::setVolume(byte volume) {
|
|
|
|
assert(volume <= MUSIC_VOLUME_MAX);
|
2010-06-28 10:48:09 +00:00
|
|
|
_volume = volume;
|
|
|
|
|
|
|
|
switch (_soundVersion) {
|
|
|
|
case SCI_VERSION_0_EARLY:
|
|
|
|
case SCI_VERSION_0_LATE: {
|
|
|
|
// SCI0 adlib driver doesn't support channel volumes, so we need to go this way
|
2010-09-01 19:20:17 +00:00
|
|
|
int16 globalVolume = _volume * _masterVolume / MUSIC_VOLUME_MAX;
|
2010-06-28 10:48:09 +00:00
|
|
|
((MidiPlayer *)_driver)->setVolume(globalVolume);
|
|
|
|
break;
|
|
|
|
}
|
2010-01-04 15:17:46 +00:00
|
|
|
|
2010-06-28 10:48:09 +00:00
|
|
|
case SCI_VERSION_1_EARLY:
|
|
|
|
case SCI_VERSION_1_LATE:
|
2010-07-14 11:29:55 +00:00
|
|
|
case SCI_VERSION_2_1:
|
2010-06-28 10:48:09 +00:00
|
|
|
// Send previous channel volumes again to actually update the volume
|
|
|
|
for (int i = 0; i < 15; i++)
|
|
|
|
if (_channelRemap[i] != -1)
|
|
|
|
sendToDriver(0xB0 + i, 7, _channelVolume[i]);
|
|
|
|
break;
|
2010-01-04 15:17:46 +00:00
|
|
|
|
2010-06-28 10:48:09 +00:00
|
|
|
default:
|
|
|
|
error("MidiParser_SCI::setVolume: Unsupported soundVersion");
|
2009-12-27 02:46:00 +00:00
|
|
|
}
|
|
|
|
}
|
2009-12-28 21:00:59 +00:00
|
|
|
|
|
|
|
} // End of namespace Sci
|