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-01-04 15:17:46 +00:00
|
|
|
MidiParser_SCI::MidiParser_SCI(SciVersion soundVersion) :
|
2009-12-27 02:46:00 +00:00
|
|
|
MidiParser() {
|
2010-01-04 15:17:46 +00:00
|
|
|
_soundVersion = soundVersion;
|
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-01-16 16:00:21 +00:00
|
|
|
_channelsUsed = 0;
|
2010-06-03 21:57:49 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < 16; i++)
|
|
|
|
_channelRemap[i] = i;
|
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;
|
|
|
|
|
|
|
|
setVolume(psnd->volume);
|
|
|
|
|
|
|
|
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;
|
|
|
|
setTrack(0);
|
|
|
|
_loopTick = 0;
|
2010-01-15 07:40:07 +00:00
|
|
|
|
2010-01-26 19:25:33 +00:00
|
|
|
if (_soundVersion <= SCI_VERSION_0_LATE) {
|
|
|
|
// Set initial voice count
|
|
|
|
for (int i = 0; i < 16; ++i) {
|
|
|
|
byte voiceCount = 0;
|
|
|
|
if (channelFilterMask & (1 << i))
|
|
|
|
voiceCount = psnd->soundRes->getInitialVoiceCount(i);
|
|
|
|
_driver->send(0xB0 | i, 0x4B, voiceCount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-15 22:15:58 +00:00
|
|
|
// Send a velocity off signal to all channels
|
|
|
|
for (int i = 0; i < 16; ++i) {
|
|
|
|
_driver->send(0xB0 | i, 0x4E, 0); // Reset velocity
|
|
|
|
}
|
|
|
|
|
2009-12-27 02:46:00 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MidiParser_SCI::unloadMusic() {
|
|
|
|
resetTracking();
|
2010-01-13 14:46:45 +00:00
|
|
|
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-01-13 14:46:45 +00:00
|
|
|
if (_driver) {
|
|
|
|
for (int i = 0; i < 16; ++i) {
|
2010-06-03 21:57:49 +00:00
|
|
|
if (isChannelUsed(i)) {
|
2010-01-15 07:40:07 +00:00
|
|
|
_driver->send(0xE0 | i, 0, 0x40); // Reset pitch wheel
|
|
|
|
_driver->send(0xB0 | i, 0x40, 0); // Reset hold pedal
|
|
|
|
}
|
2010-01-13 14:46:45 +00:00
|
|
|
}
|
|
|
|
}
|
2010-06-03 21:57:49 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < 16; i++)
|
|
|
|
_channelRemap[i] = i;
|
2009-12-27 02:46:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MidiParser_SCI::parseNextEvent(EventInfo &info) {
|
2010-01-15 07:40:07 +00:00
|
|
|
// Monitor which channels are used by this song
|
2010-06-03 21:57:49 +00:00
|
|
|
setChannelUsed(info.channel());
|
2010-01-15 07:40:07 +00:00
|
|
|
|
2009-12-27 02:46:00 +00:00
|
|
|
// 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;
|
|
|
|
debugC(2, kDebugLevelSound, "datainc %04x", _dataincToAdd);
|
|
|
|
}
|
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;
|
2009-12-27 02:46:00 +00:00
|
|
|
debugC(2, kDebugLevelSound, "signal %04x", _signalToSet);
|
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
|
|
|
_loopTick = _position._play_tick;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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
|
2010-01-03 14:39:38 +00:00
|
|
|
case 0x4E: // velocity control
|
2010-01-03 15:59:43 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
if (info.basic.param1 == 7) // channel volume change -scale it
|
2010-01-05 10:28:09 +00:00
|
|
|
info.basic.param2 = info.basic.param2 * _volume / MUSIC_VOLUME_MAX;
|
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;
|
|
|
|
|
2009-12-27 02:46:00 +00:00
|
|
|
debugC(2, kDebugLevelSound, "signal EOT");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
warning(
|
|
|
|
"MidiParser_SCI::parseNextEvent: Unsupported event code %x",
|
|
|
|
info.event);
|
|
|
|
} // // System Common, Meta or SysEx event
|
|
|
|
}// switch (info.command())
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2009-12-27 02:46:00 +00:00
|
|
|
while ((curr = midiGetNextChannel(ticker)) != 0xFF) { // there is still active channel
|
|
|
|
channel = &_track->channels[curr];
|
2010-01-15 08:23:48 +00:00
|
|
|
curDelta = *channel->data++;
|
|
|
|
channel->time += (curDelta == 0xF8 ? 240 : curDelta); // when the comamnd is supposed to occur
|
|
|
|
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) {
|
|
|
|
debugC(2, kDebugLevelSound, "\nDELTA ");
|
|
|
|
// Write delta
|
2009-12-27 02:46:00 +00:00
|
|
|
while (new_delta > 240) {
|
2010-01-15 08:23:48 +00:00
|
|
|
*outData++ = 0xF8;
|
|
|
|
debugC(2, 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-01-15 18:01:49 +00:00
|
|
|
debugC(2, 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;
|
|
|
|
debugC(2, 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
|
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
|
|
|
|
|
|
|
// TODO: Fix remapping
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
// Remap channel. Keep the upper 4 bits (command code) and change
|
|
|
|
// the lower 4 bits (channel)
|
|
|
|
byte remappedChannel = _channelRemap[par1 & 0xF];
|
|
|
|
par1 = (par1 & 0xF0) | (remappedChannel & 0xF);
|
|
|
|
#endif
|
|
|
|
} 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-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) {
|
2009-12-27 02:46:00 +00:00
|
|
|
debugC(2, kDebugLevelSound, "\nDELTA ");
|
|
|
|
// Write delta
|
|
|
|
while (delta > 240) {
|
2010-01-15 08:23:48 +00:00
|
|
|
*outData++ = 0xF8;
|
2009-12-27 02:46:00 +00:00
|
|
|
debugC(2, kDebugLevelSound, "F8 ");
|
|
|
|
delta -= 240;
|
|
|
|
}
|
2010-01-15 08:23:48 +00:00
|
|
|
*outData++ = (byte)delta;
|
2009-12-27 02:46:00 +00:00
|
|
|
debugC(2, kDebugLevelSound, "%02X ", delta);
|
|
|
|
delta = 0;
|
|
|
|
}
|
|
|
|
// Write command
|
|
|
|
switch (command) {
|
|
|
|
case 0xF0: // sysEx
|
2010-01-15 08:23:48 +00:00
|
|
|
*outData++ = command;
|
2009-12-27 02:46:00 +00:00
|
|
|
debugC(2, kDebugLevelSound, "%02X ", command);
|
|
|
|
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
|
|
|
|
if (lastCommand != command) {
|
2010-01-15 08:23:48 +00:00
|
|
|
*outData++ = command;
|
2009-12-27 02:46:00 +00:00
|
|
|
debugC(2, kDebugLevelSound, "%02X ", command);
|
|
|
|
lastCommand = command;
|
|
|
|
}
|
|
|
|
if (midiParamCount > 0) {
|
|
|
|
if (curByte & 0x80) {
|
|
|
|
debugC(2, kDebugLevelSound, "%02X ", *channelData);
|
2010-01-15 08:23:48 +00:00
|
|
|
*outData++ = *channelData++;
|
2009-12-27 02:46:00 +00:00
|
|
|
} else {
|
|
|
|
debugC(2, kDebugLevelSound, "%02X ", curByte);
|
2010-01-15 08:23:48 +00:00
|
|
|
*outData++ = curByte;
|
2009-12-27 02:46:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (midiParamCount > 1) {
|
|
|
|
debugC(2, 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-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:
|
|
|
|
// sending volume change to all active channels
|
|
|
|
for (int i = 0; i < _track->channelCount; i++)
|
|
|
|
if (_track->channels[i].number <= 0xF)
|
|
|
|
_driver->send(0xB0 + _track->channels[i].number, 7, _volume);
|
|
|
|
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
|