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"
|
|
|
|
#include "sci/sfx/midiparser.h"
|
|
|
|
|
|
|
|
namespace Sci {
|
|
|
|
|
|
|
|
static const int nMidiParams[] = { 2, 2, 2, 2, 1, 1, 2, 0 };
|
|
|
|
|
2010-01-02 17:03:58 +00:00
|
|
|
enum SciSysExCommands {
|
|
|
|
kSetSignalLoop = 0x7F,
|
|
|
|
kEndOfTrack = 0xFC,
|
|
|
|
kSetReverb = 0x50,
|
|
|
|
kMidiHold = 0x52,
|
|
|
|
kUpdateCue = 0x60
|
|
|
|
};
|
2009-12-28 21:00:59 +00:00
|
|
|
|
2009-12-27 02:46:00 +00:00
|
|
|
// MidiParser_SCI
|
|
|
|
//
|
|
|
|
MidiParser_SCI::MidiParser_SCI() :
|
|
|
|
MidiParser() {
|
|
|
|
_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);
|
|
|
|
|
|
|
|
_signalSet = false;
|
|
|
|
_signalToSet = 0;
|
|
|
|
}
|
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;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MidiParser_SCI::unloadMusic() {
|
|
|
|
allNotesOff();
|
|
|
|
resetTracking();
|
|
|
|
_num_tracks = 0;
|
|
|
|
if (_mixedData) {
|
|
|
|
delete[] _mixedData;
|
|
|
|
_mixedData = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
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
|
|
|
|
// Also, sci/sfx/iterator/iterator.cpp, function BaseSongIterator::parseMidiCommand()
|
|
|
|
switch (info.basic.param1) {
|
2010-01-02 17:03:58 +00:00
|
|
|
case kSetReverb:
|
|
|
|
// TODO: Not implemented yet
|
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 15:37:17 +00:00
|
|
|
// Check if the hold ID marker is the same as the hold ID marker set for that song by
|
|
|
|
// cmdSetSoundHold. If it is, set the loop position
|
|
|
|
if (info.basic.param2 == _pSnd->hold)
|
|
|
|
_loopTick = _position._play_tick;
|
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:
|
2009-12-27 02:46:00 +00:00
|
|
|
switch (_soundVersion) {
|
|
|
|
case SCI_VERSION_0_EARLY:
|
|
|
|
case SCI_VERSION_0_LATE:
|
|
|
|
_pSnd->dataInc += info.basic.param2;
|
|
|
|
_signalSet = true;
|
|
|
|
_signalToSet = 0x7f + _pSnd->dataInc;
|
|
|
|
break;
|
|
|
|
case SCI_VERSION_1_EARLY:
|
|
|
|
case SCI_VERSION_1_LATE:
|
|
|
|
_pSnd->dataInc++;
|
|
|
|
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;
|
|
|
|
case 0x1: // unknown (example case: LB2CD)
|
|
|
|
case 0xA: // unknown (example case: LB2CD)
|
|
|
|
default:
|
|
|
|
warning("Unhandled SCI SysEx 0x%x (parameter %d)", info.basic.param1, info.basic.param2);
|
|
|
|
break;
|
2009-12-27 02:46:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (info.basic.param1 == 7) // channel volume change -scale it
|
|
|
|
info.basic.param2 = info.basic.param2 * _volume / 0x7F;
|
|
|
|
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;
|
|
|
|
next = *_track->channels[i].data; // when the next event shoudl 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;
|
|
|
|
}
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
byte *mixedData = new byte[totalSize * 2]; // FIXME: creates overhead and still may be not enough to hold all data
|
|
|
|
_mixedData = mixedData;
|
|
|
|
long ticker = 0;
|
|
|
|
byte curr, delta;
|
|
|
|
byte cmd, par1, global_prev = 0;
|
|
|
|
long new_delta;
|
|
|
|
SoundResource::Channel *channel;
|
|
|
|
while ((curr = midiGetNextChannel(ticker)) != 0xFF) { // there is still active channel
|
|
|
|
channel = &_track->channels[curr];
|
|
|
|
delta = *channel->data++;
|
|
|
|
channel->time += (delta == 0xF8 ? 240 : delta); // when the comamnd is supposed to occur
|
|
|
|
if (delta == 0xF8)
|
|
|
|
continue;
|
|
|
|
new_delta = channel->time - ticker;
|
|
|
|
ticker += new_delta;
|
|
|
|
|
|
|
|
cmd = *channel->data++;
|
2010-01-02 17:03:58 +00:00
|
|
|
if (cmd != kEndOfTrack) {
|
2009-12-27 02:46:00 +00:00
|
|
|
// output new delta
|
|
|
|
while (new_delta > 240) {
|
|
|
|
*mixedData++ = 0xF8;
|
|
|
|
new_delta -= 240;
|
|
|
|
}
|
|
|
|
*mixedData++ = (byte)new_delta;
|
|
|
|
}
|
|
|
|
switch (cmd) {
|
|
|
|
case 0xF0: // sysEx
|
|
|
|
*mixedData++ = cmd;
|
|
|
|
do {
|
|
|
|
par1 = *channel->data++;
|
|
|
|
*mixedData++ = par1; // out
|
|
|
|
} while (par1 != 0xF7);
|
|
|
|
break;
|
2010-01-02 17:03:58 +00:00
|
|
|
case kEndOfTrack: // end channel
|
2009-12-27 02:46:00 +00:00
|
|
|
channel->time = -1; // FIXME
|
|
|
|
break;
|
|
|
|
default: // MIDI command
|
|
|
|
if (cmd & 0x80)
|
|
|
|
par1 = *channel->data++;
|
|
|
|
else {// running status
|
|
|
|
par1 = cmd;
|
|
|
|
cmd = channel->prev;
|
|
|
|
}
|
|
|
|
if (cmd != global_prev)
|
|
|
|
*mixedData++ = cmd; // out cmd
|
|
|
|
*mixedData++ = par1;// pout par1
|
|
|
|
if (nMidiParams[(cmd >> 4) - 8] == 2)
|
|
|
|
*mixedData++ = *channel->data++; // out par2
|
|
|
|
channel->prev = cmd;
|
|
|
|
global_prev = cmd;
|
|
|
|
}// switch(cmd)
|
|
|
|
}// while (curr)
|
|
|
|
// mixing finished. inserting stop event
|
|
|
|
*mixedData++ = 0;
|
|
|
|
*mixedData++ = 0xFF;
|
|
|
|
*mixedData++ = 0x2F;
|
|
|
|
*mixedData++ = 0x00;
|
|
|
|
*mixedData++ = 0x00;
|
|
|
|
|
|
|
|
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;
|
|
|
|
byte *filterData = new byte[channel->size + 5];
|
|
|
|
byte curChannel, curByte, curDelta;
|
|
|
|
byte command, lastCommand;
|
|
|
|
int delta = 0;
|
|
|
|
//int dataLeft = channel->size;
|
|
|
|
int midiParamCount;
|
|
|
|
|
|
|
|
_mixedData = filterData;
|
|
|
|
command = 0;
|
|
|
|
midiParamCount = 0;
|
|
|
|
lastCommand = 0;
|
|
|
|
curChannel = 15;
|
|
|
|
|
|
|
|
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) {
|
|
|
|
*filterData++ = 0xF8;
|
|
|
|
debugC(2, kDebugLevelSound, "F8 ");
|
|
|
|
delta -= 240;
|
|
|
|
}
|
|
|
|
*filterData++ = (byte)delta;
|
|
|
|
debugC(2, kDebugLevelSound, "%02X ", delta);
|
|
|
|
delta = 0;
|
|
|
|
}
|
|
|
|
// Write command
|
|
|
|
switch (command) {
|
|
|
|
case 0xF0: // sysEx
|
|
|
|
*filterData++ = command;
|
|
|
|
debugC(2, kDebugLevelSound, "%02X ", command);
|
|
|
|
do {
|
|
|
|
curByte = *channelData++;
|
|
|
|
*filterData++ = curByte; // out
|
|
|
|
} 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) {
|
|
|
|
*filterData++ = command;
|
|
|
|
debugC(2, kDebugLevelSound, "%02X ", command);
|
|
|
|
lastCommand = command;
|
|
|
|
}
|
|
|
|
if (midiParamCount > 0) {
|
|
|
|
if (curByte & 0x80) {
|
|
|
|
debugC(2, kDebugLevelSound, "%02X ", *channelData);
|
|
|
|
*filterData++ = *channelData++;
|
|
|
|
} else {
|
|
|
|
debugC(2, kDebugLevelSound, "%02X ", curByte);
|
|
|
|
*filterData++ = curByte;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (midiParamCount > 1) {
|
|
|
|
debugC(2, kDebugLevelSound, "%02X ", *channelData);
|
|
|
|
*filterData++ = *channelData++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (curByte & 0x80) {
|
|
|
|
channelData += midiParamCount;
|
|
|
|
} else {
|
|
|
|
channelData += midiParamCount - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Stop event
|
|
|
|
*filterData++ = 0; // delta
|
|
|
|
*filterData++ = 0xFF; // Meta-Event
|
|
|
|
*filterData++ = 0x2F; // End-Of-Track
|
|
|
|
*filterData++ = 0x00;
|
|
|
|
*filterData++ = 0x00;
|
|
|
|
|
|
|
|
return _mixedData;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MidiParser_SCI::setVolume(byte bVolume) {
|
|
|
|
if (bVolume > 0x7F)
|
|
|
|
bVolume = 0x7F;
|
|
|
|
if (_volume != bVolume) {
|
|
|
|
_volume = bVolume;
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
}
|
2009-12-28 21:00:59 +00:00
|
|
|
|
|
|
|
} // End of namespace Sci
|