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.
|
|
|
|
*
|
|
|
|
* $URL$
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#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-01-04 19:50:58 +00:00
|
|
|
_volume = 0;
|
|
|
|
|
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;
|
2010-06-20 10:25:46 +00:00
|
|
|
|
|
|
|
_manualCommandCount = 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();
|
|
|
|
}
|
2009-12-28 21:00:59 +00:00
|
|
|
|
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-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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MidiParser_SCI::sendInitCommands() {
|
2010-06-11 14:47:13 +00:00
|
|
|
if (_pSnd) {
|
|
|
|
if (_soundVersion <= SCI_VERSION_0_LATE) {
|
|
|
|
// Set initial voice count
|
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-20 10:25:46 +00:00
|
|
|
sendToDriverQueue(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
|
|
|
}
|
|
|
|
|
2010-06-19 20:23:55 +00:00
|
|
|
// Send a velocity off signal to all channels
|
|
|
|
for (int i = 0; i < 15; ++i) {
|
2010-06-20 10:25:46 +00:00
|
|
|
sendToDriverQueue(0xB0 | i, 0x4E, 0); // Reset velocity
|
2010-06-19 20:23:55 +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-01-13 14:46:45 +00:00
|
|
|
|
2010-01-14 16:39:47 +00:00
|
|
|
// Center the pitch wheels and hold pedal in preparation for the next piece of music
|
2010-06-11 14:47:13 +00:00
|
|
|
if (_driver && _pSnd) {
|
2010-01-13 14:46:45 +00:00
|
|
|
for (int i = 0; i < 16; ++i) {
|
2010-06-16 21:02:58 +00:00
|
|
|
int16 realChannel = _channelRemap[i];
|
|
|
|
if (realChannel != -1) {
|
|
|
|
_driver->send(0xE0 | realChannel, 0, 0x40); // Reset pitch wheel
|
|
|
|
_driver->send(0xB0 | realChannel, 0x40, 0); // Reset hold pedal
|
2010-01-15 07:40:07 +00:00
|
|
|
}
|
2010-01-13 14:46:45 +00:00
|
|
|
}
|
|
|
|
}
|
2010-06-16 21:02:58 +00:00
|
|
|
}
|
2010-06-03 21:57:49 +00:00
|
|
|
|
2010-06-19 20:00:32 +00:00
|
|
|
// this is used for scripts sending direct midi commands to us. we verify in that case that the channel is actually
|
2010-06-20 10:25:46 +00:00
|
|
|
// used and actually store the command for getting really sent when being onTimer()
|
|
|
|
void MidiParser_SCI::sendToDriverQueue(uint32 b) {
|
2010-06-19 20:00:32 +00:00
|
|
|
byte midiChannel = b & 0xf;
|
|
|
|
|
|
|
|
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-20 10:25:46 +00:00
|
|
|
if (_manualCommandCount >= 200)
|
|
|
|
error("driver queue is full");
|
|
|
|
_manualCommands[_manualCommandCount] = b;
|
|
|
|
_manualCommandCount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This sends the stored commands from queue to driver (is supposed to get called only during onTimer())
|
|
|
|
// at least mt32 emulation doesn't like getting note-on commands from main thread (if we directly send, we would get
|
|
|
|
// a crash during piano scene in lsl5)
|
|
|
|
void MidiParser_SCI::sendQueueToDriver() {
|
|
|
|
int curCommand = 0;
|
|
|
|
|
|
|
|
while (curCommand < _manualCommandCount) {
|
|
|
|
sendToDriver(_manualCommands[curCommand]);
|
|
|
|
curCommand++;
|
|
|
|
}
|
|
|
|
_manualCommandCount = 0;
|
2010-06-19 20:00:32 +00:00
|
|
|
}
|
|
|
|
|
2010-06-16 21:02:58 +00:00
|
|
|
void MidiParser_SCI::sendToDriver(uint32 b) {
|
2010-06-17 11:54:54 +00:00
|
|
|
byte midiChannel = b & 0xf;
|
|
|
|
|
|
|
|
if ((b & 0xFFF0) == 0x4EB0) {
|
|
|
|
// this is channel mute only for sci1
|
|
|
|
// it's velocity control for sci0
|
|
|
|
if (_soundVersion >= SCI_VERSION_1_EARLY) {
|
|
|
|
_channelMuted[midiChannel] = b & 0xFF0000 ? true : false;
|
|
|
|
return; // don't send this to driver at all
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Is channel muted? if so, don't send command
|
|
|
|
if (_channelMuted[midiChannel])
|
|
|
|
return;
|
2010-06-16 21:02:58 +00:00
|
|
|
// Channel remapping
|
2010-06-17 11:54:54 +00:00
|
|
|
int16 realChannel = _channelRemap[midiChannel];
|
2010-06-19 20:00:32 +00:00
|
|
|
assert(realChannel != -1);
|
2010-06-18 02:16:00 +00:00
|
|
|
|
2010-06-16 21:02:58 +00:00
|
|
|
b = (b & 0xFFFFFFF0) | realChannel;
|
|
|
|
_driver->send(b);
|
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;
|
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
|
|
|
_pSnd->signal = _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) {
|
2009-12-27 02:46:00 +00:00
|
|
|
_signalSet = true;
|
|
|
|
_signalToSet = info.basic.param1;
|
|
|
|
} 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++);
|
|
|
|
if (info.channel() == 0xF) {// SCI special
|
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
|
|
|
// Reference for some events:
|
|
|
|
// http://wiki.scummvm.org/index.php/SCI/Specifications/Sound/SCI0_Resource_Format#Status_Reference
|
2010-01-05 01:22:16 +00:00
|
|
|
// Also, sci/sound/iterator/iterator.cpp, function BaseSongIterator::parseMidiCommand()
|
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
|
|
|
switch (info.basic.param1) {
|
2010-01-02 17:03:58 +00:00
|
|
|
case kSetReverb:
|
2010-01-22 12:26:12 +00:00
|
|
|
((MidiPlayer *)_driver)->setReverb(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;
|
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-01-21 22:33:35 +00:00
|
|
|
_dataincToAdd = 1;
|
2009-12-27 02:46:00 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
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
|
|
|
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
|
|
|
}
|
|
|
|
}
|
2010-06-17 11:54:54 +00:00
|
|
|
switch (info.basic.param1) {
|
|
|
|
case 7: // channel volume change -scale it
|
2010-01-05 10:28:09 +00:00
|
|
|
info.basic.param2 = info.basic.param2 * _volume / MUSIC_VOLUME_MAX;
|
2010-06-17 11:54:54 +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--;
|
|
|
|
if (_pSnd->loop) {
|
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;
|
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
|
|
|
_pSnd->signal = SIGNAL_OFFSET;
|
|
|
|
|
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-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-20 10:25:46 +00:00
|
|
|
if ((_active_notes[i] & (1 << j))){
|
|
|
|
sendToDriverQueue(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++) {
|
|
|
|
if (_hanging_notes[i].time_left) {
|
2010-06-20 10:25:46 +00:00
|
|
|
sendToDriverQueue(0x80 | _hanging_notes[i].channel, _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-20 10:25:46 +00:00
|
|
|
for (i = 0; i < 16; ++i)
|
|
|
|
sendToDriverQueue(0xB0 | i, 0x7b, 0); // All notes off
|
2010-06-14 22:35:49 +00:00
|
|
|
|
|
|
|
memset(_active_notes, 0, sizeof(_active_notes));
|
|
|
|
}
|
2009-12-28 21:00:59 +00:00
|
|
|
|
2009-12-27 02:46:00 +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;
|
2010-06-04 15:01:26 +00:00
|
|
|
next = *_track->channels[i].data; // when the next event should occur
|
2009-12-27 02:46:00 +00:00
|
|
|
if (next == 0xF8) // 0xF8 means 240 ticks delay
|
|
|
|
next = 240;
|
|
|
|
next += _track->channels[i].time;
|
|
|
|
if (next < closest) {
|
|
|
|
curr = i;
|
|
|
|
closest = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return curr;
|
|
|
|
}
|
2009-12-28 21:00:59 +00:00
|
|
|
|
2009-12-27 02:46:00 +00:00
|
|
|
byte *MidiParser_SCI::midiMixChannels() {
|
|
|
|
int totalSize = 0;
|
|
|
|
byte **dataPtr = new byte *[_track->channelCount];
|
|
|
|
|
|
|
|
for (int i = 0; i < _track->channelCount; i++) {
|
|
|
|
dataPtr[i] = _track->channels[i].data;
|
|
|
|
_track->channels[i].time = 0;
|
|
|
|
_track->channels[i].prev = 0;
|
|
|
|
totalSize += _track->channels[i].size;
|
|
|
|
}
|
|
|
|
|
2010-01-15 08:23:48 +00:00
|
|
|
byte *outData = new byte[totalSize * 2]; // FIXME: creates overhead and still may be not enough to hold all data
|
|
|
|
_mixedData = outData;
|
2009-12-27 02:46:00 +00:00
|
|
|
long ticker = 0;
|
2010-01-15 08:23:48 +00:00
|
|
|
byte curr, curDelta;
|
|
|
|
byte command = 0, par1, global_prev = 0;
|
2009-12-27 02:46:00 +00:00
|
|
|
long new_delta;
|
|
|
|
SoundResource::Channel *channel;
|
2010-01-15 08:23:48 +00:00
|
|
|
|
2010-06-11 14:47:13 +00:00
|
|
|
while ((curr = midiGetNextChannel(ticker)) != 0xFF) { // there is still an active channel
|
2009-12-27 02:46:00 +00:00
|
|
|
channel = &_track->channels[curr];
|
2010-01-15 08:23:48 +00:00
|
|
|
curDelta = *channel->data++;
|
2010-06-11 14:47:13 +00:00
|
|
|
channel->time += (curDelta == 0xF8 ? 240 : curDelta); // when the command is supposed to occur
|
2010-01-15 08:23:48 +00:00
|
|
|
if (curDelta == 0xF8)
|
2009-12-27 02:46:00 +00:00
|
|
|
continue;
|
|
|
|
new_delta = channel->time - ticker;
|
|
|
|
ticker += new_delta;
|
|
|
|
|
2010-01-15 08:23:48 +00:00
|
|
|
command = *channel->data++;
|
|
|
|
if (command != kEndOfTrack) {
|
2010-06-12 11:41:22 +00:00
|
|
|
debugC(4, kDebugLevelSound, "\nDELTA ");
|
2010-01-15 08:23:48 +00:00
|
|
|
// Write delta
|
2009-12-27 02:46:00 +00:00
|
|
|
while (new_delta > 240) {
|
2010-01-15 08:23:48 +00:00
|
|
|
*outData++ = 0xF8;
|
2010-06-12 11:41:22 +00:00
|
|
|
debugC(4, kDebugLevelSound, "F8 ");
|
2009-12-27 02:46:00 +00:00
|
|
|
new_delta -= 240;
|
|
|
|
}
|
2010-01-15 08:23:48 +00:00
|
|
|
*outData++ = (byte)new_delta;
|
2010-06-12 11:41:22 +00:00
|
|
|
debugC(4, kDebugLevelSound, "%02X ", (uint32)new_delta);
|
2009-12-27 02:46:00 +00:00
|
|
|
}
|
2010-01-15 08:23:48 +00:00
|
|
|
// Write command
|
|
|
|
switch (command) {
|
2009-12-27 02:46:00 +00:00
|
|
|
case 0xF0: // sysEx
|
2010-01-15 08:23:48 +00:00
|
|
|
*outData++ = command;
|
2010-06-12 11:41:22 +00:00
|
|
|
debugC(4, kDebugLevelSound, "%02X ", command);
|
2009-12-27 02:46:00 +00:00
|
|
|
do {
|
|
|
|
par1 = *channel->data++;
|
2010-01-15 08:23:48 +00:00
|
|
|
*outData++ = par1; // out
|
2009-12-27 02:46:00 +00:00
|
|
|
} while (par1 != 0xF7);
|
|
|
|
break;
|
2010-01-15 08:23:48 +00:00
|
|
|
case kEndOfTrack: // end of channel
|
2010-06-18 02:29:20 +00:00
|
|
|
// FIXME: Why does this need to be fixed? There's no
|
|
|
|
// additional information available
|
2009-12-27 02:46:00 +00:00
|
|
|
channel->time = -1; // FIXME
|
|
|
|
break;
|
|
|
|
default: // MIDI command
|
2010-06-04 15:01:26 +00:00
|
|
|
if (command & 0x80) {
|
2009-12-27 02:46:00 +00:00
|
|
|
par1 = *channel->data++;
|
2010-06-04 15:01:26 +00:00
|
|
|
} else {// running status
|
2010-01-15 08:23:48 +00:00
|
|
|
par1 = command;
|
|
|
|
command = channel->prev;
|
2009-12-27 02:46:00 +00:00
|
|
|
}
|
2010-06-16 21:02:58 +00:00
|
|
|
|
|
|
|
// remember which channel got used for channel remapping
|
|
|
|
byte midiChannel = command & 0xF;
|
|
|
|
_channelUsed[midiChannel] = true;
|
|
|
|
|
2010-01-15 08:23:48 +00:00
|
|
|
if (command != global_prev)
|
|
|
|
*outData++ = command; // out command
|
|
|
|
*outData++ = par1;// pout par1
|
|
|
|
if (nMidiParams[(command >> 4) - 8] == 2)
|
|
|
|
*outData++ = *channel->data++; // out par2
|
|
|
|
channel->prev = command;
|
|
|
|
global_prev = command;
|
|
|
|
}// switch(command)
|
2009-12-27 02:46:00 +00:00
|
|
|
}// while (curr)
|
2010-01-15 08:23:48 +00:00
|
|
|
|
|
|
|
// Insert stop event
|
|
|
|
*outData++ = 0; // Delta
|
|
|
|
*outData++ = 0xFF; // Meta event
|
|
|
|
*outData++ = 0x2F; // End of track (EOT)
|
|
|
|
*outData++ = 0x00;
|
|
|
|
*outData++ = 0x00;
|
2009-12-27 02:46:00 +00:00
|
|
|
|
|
|
|
for (int channelNr = 0; channelNr < _track->channelCount; channelNr++)
|
|
|
|
_track->channels[channelNr].data = dataPtr[channelNr];
|
|
|
|
|
|
|
|
delete[] dataPtr;
|
|
|
|
return _mixedData;
|
|
|
|
}
|
|
|
|
|
2009-12-28 21:00:59 +00:00
|
|
|
// 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.
|
2009-12-27 02:46:00 +00:00
|
|
|
byte *MidiParser_SCI::midiFilterChannels(int channelMask) {
|
|
|
|
SoundResource::Channel *channel = &_track->channels[0];
|
|
|
|
byte *channelData = channel->data;
|
|
|
|
byte *channelDataEnd = channel->data + channel->size;
|
2010-01-15 08:23:48 +00:00
|
|
|
byte *outData = new byte[channel->size + 5];
|
|
|
|
byte curChannel = 15, curByte, curDelta;
|
|
|
|
byte command = 0, lastCommand = 0;
|
2009-12-27 02:46:00 +00:00
|
|
|
int delta = 0;
|
2010-01-15 08:23:48 +00:00
|
|
|
int midiParamCount = 0;
|
2009-12-27 02:46:00 +00:00
|
|
|
|
2010-01-15 08:23:48 +00:00
|
|
|
_mixedData = outData;
|
2009-12-27 02:46:00 +00:00
|
|
|
|
|
|
|
while (channelData < channelDataEnd) {
|
|
|
|
curDelta = *channelData++;
|
|
|
|
if (curDelta == 0xF8) {
|
|
|
|
delta += 240;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
delta += curDelta;
|
|
|
|
curByte = *channelData++;
|
|
|
|
|
|
|
|
switch (curByte) {
|
|
|
|
case 0xF0: // sysEx
|
2010-01-02 17:03:58 +00:00
|
|
|
case kEndOfTrack: // end of channel
|
2009-12-27 02:46:00 +00:00
|
|
|
command = curByte;
|
|
|
|
curChannel = 15;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (curByte & 0x80) {
|
|
|
|
command = curByte;
|
|
|
|
curChannel = command & 0x0F;
|
|
|
|
midiParamCount = nMidiParams[(command >> 4) - 8];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((1 << curChannel) & channelMask) {
|
2010-01-02 17:03:58 +00:00
|
|
|
if (command != kEndOfTrack) {
|
2010-06-12 11:41:22 +00:00
|
|
|
debugC(4, kDebugLevelSound, "\nDELTA ");
|
2009-12-27 02:46:00 +00:00
|
|
|
// Write delta
|
|
|
|
while (delta > 240) {
|
2010-01-15 08:23:48 +00:00
|
|
|
*outData++ = 0xF8;
|
2010-06-12 11:41:22 +00:00
|
|
|
debugC(4, kDebugLevelSound, "F8 ");
|
2009-12-27 02:46:00 +00:00
|
|
|
delta -= 240;
|
|
|
|
}
|
2010-01-15 08:23:48 +00:00
|
|
|
*outData++ = (byte)delta;
|
2010-06-12 11:41:22 +00:00
|
|
|
debugC(4, kDebugLevelSound, "%02X ", delta);
|
2009-12-27 02:46:00 +00:00
|
|
|
delta = 0;
|
|
|
|
}
|
|
|
|
// Write command
|
|
|
|
switch (command) {
|
|
|
|
case 0xF0: // sysEx
|
2010-01-15 08:23:48 +00:00
|
|
|
*outData++ = command;
|
2010-06-12 11:41:22 +00:00
|
|
|
debugC(4, kDebugLevelSound, "%02X ", command);
|
2009-12-27 02:46:00 +00:00
|
|
|
do {
|
|
|
|
curByte = *channelData++;
|
2010-01-15 08:23:48 +00:00
|
|
|
*outData++ = curByte; // out
|
2009-12-27 02:46:00 +00:00
|
|
|
} while (curByte != 0xF7);
|
|
|
|
lastCommand = command;
|
|
|
|
break;
|
|
|
|
|
2010-01-02 17:03:58 +00:00
|
|
|
case kEndOfTrack: // end of channel
|
2009-12-27 02:46:00 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default: // MIDI command
|
2010-06-17 08:41:04 +00:00
|
|
|
// remember which channel got used for channel remapping
|
|
|
|
byte midiChannel = command & 0xF;
|
|
|
|
_channelUsed[midiChannel] = true;
|
|
|
|
|
2009-12-27 02:46:00 +00:00
|
|
|
if (lastCommand != command) {
|
2010-01-15 08:23:48 +00:00
|
|
|
*outData++ = command;
|
2010-06-12 11:41:22 +00:00
|
|
|
debugC(4, kDebugLevelSound, "%02X ", command);
|
2009-12-27 02:46:00 +00:00
|
|
|
lastCommand = command;
|
|
|
|
}
|
|
|
|
if (midiParamCount > 0) {
|
|
|
|
if (curByte & 0x80) {
|
2010-06-12 11:41:22 +00:00
|
|
|
debugC(4, kDebugLevelSound, "%02X ", *channelData);
|
2010-01-15 08:23:48 +00:00
|
|
|
*outData++ = *channelData++;
|
2009-12-27 02:46:00 +00:00
|
|
|
} else {
|
2010-06-12 11:41:22 +00:00
|
|
|
debugC(4, kDebugLevelSound, "%02X ", curByte);
|
2010-01-15 08:23:48 +00:00
|
|
|
*outData++ = curByte;
|
2009-12-27 02:46:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (midiParamCount > 1) {
|
2010-06-12 11:41:22 +00:00
|
|
|
debugC(4, kDebugLevelSound, "%02X ", *channelData);
|
2010-01-15 08:23:48 +00:00
|
|
|
*outData++ = *channelData++;
|
2009-12-27 02:46:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (curByte & 0x80) {
|
|
|
|
channelData += midiParamCount;
|
|
|
|
} else {
|
|
|
|
channelData += midiParamCount - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-01-15 08:23:48 +00:00
|
|
|
|
|
|
|
// Insert stop event
|
|
|
|
*outData++ = 0; // Delta
|
|
|
|
*outData++ = 0xFF; // Meta event
|
|
|
|
*outData++ = 0x2F; // End of track (EOT)
|
|
|
|
*outData++ = 0x00;
|
|
|
|
*outData++ = 0x00;
|
2009-12-27 02:46:00 +00:00
|
|
|
|
|
|
|
return _mixedData;
|
|
|
|
}
|
|
|
|
|
2010-06-16 21:02:58 +00:00
|
|
|
// This will get called right before actual playing and will try to own the used channels
|
|
|
|
void MidiParser_SCI::tryToOwnChannels() {
|
2010-06-16 21:07:26 +00:00
|
|
|
// We don't have SciMusic in case debug command show_instruments is used
|
|
|
|
if (!_music)
|
|
|
|
return;
|
2010-06-16 21:02:58 +00:00
|
|
|
for (int curChannel = 0; curChannel < 15; curChannel++) {
|
|
|
|
if (_channelUsed[curChannel]) {
|
|
|
|
if (_channelRemap[curChannel] == -1) {
|
|
|
|
_channelRemap[curChannel] = _music->tryToOwnChannel(_pSnd, curChannel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-05 10:28:09 +00:00
|
|
|
void MidiParser_SCI::setVolume(byte volume) {
|
2010-01-29 23:59:50 +00:00
|
|
|
// FIXME: This receives values > 127... throw a warning for now and clip the variable
|
|
|
|
if (volume > MUSIC_VOLUME_MAX) {
|
|
|
|
warning("attempted to set an invalid volume(%d)", volume);
|
|
|
|
volume = MUSIC_VOLUME_MAX; // reset
|
|
|
|
}
|
|
|
|
|
2010-01-05 10:28:09 +00:00
|
|
|
assert(volume <= MUSIC_VOLUME_MAX);
|
|
|
|
if (_volume != volume) {
|
|
|
|
_volume = volume;
|
2009-12-27 02:46:00 +00:00
|
|
|
|
2010-01-04 15:17:46 +00:00
|
|
|
switch (_soundVersion) {
|
|
|
|
case SCI_VERSION_0_EARLY:
|
|
|
|
case SCI_VERSION_0_LATE: {
|
|
|
|
int16 globalVolume = _volume * 15 / 127;
|
2010-01-05 10:28:09 +00:00
|
|
|
((MidiPlayer *)_driver)->setVolume(globalVolume);
|
2010-01-04 15:17:46 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case SCI_VERSION_1_EARLY:
|
|
|
|
case SCI_VERSION_1_LATE:
|
2010-06-18 13:36:29 +00:00
|
|
|
// sending volume change to all used channels
|
|
|
|
for (int i = 0; i < 15; i++)
|
2010-06-20 10:25:46 +00:00
|
|
|
sendToDriverQueue(0xB0 + i, 7, _volume);
|
2010-01-04 15:17:46 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
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
|