SCI: implement channel remapping for SCI1
svn-id: r49905
This commit is contained in:
parent
e7e8808aff
commit
af65de6e1a
9 changed files with 109 additions and 106 deletions
|
@ -859,7 +859,8 @@ bool Console::cmdShowInstruments(int argc, const char **argv) {
|
||||||
|
|
||||||
SciVersion doSoundVersion = _engine->_features->detectDoSoundType();
|
SciVersion doSoundVersion = _engine->_features->detectDoSoundType();
|
||||||
MidiPlayer *player = MidiPlayer_Midi_create(doSoundVersion);
|
MidiPlayer *player = MidiPlayer_Midi_create(doSoundVersion);
|
||||||
MidiParser_SCI *parser = new MidiParser_SCI(doSoundVersion);
|
MidiParser_SCI *parser; // = new MidiParser_SCI(doSoundVersion);
|
||||||
|
// FIXME: add SciMusic object
|
||||||
parser->setMidiDriver(player);
|
parser->setMidiDriver(player);
|
||||||
|
|
||||||
Common::List<ResourceId> *resources = _engine->getResMan()->listResources(kResourceTypeSound);
|
Common::List<ResourceId> *resources = _engine->getResMan()->listResources(kResourceTypeSound);
|
||||||
|
|
|
@ -513,7 +513,6 @@ public:
|
||||||
Track *getDigitalTrack();
|
Track *getDigitalTrack();
|
||||||
int getChannelFilterMask(int hardwareMask, bool wantsRhythm);
|
int getChannelFilterMask(int hardwareMask, bool wantsRhythm);
|
||||||
byte getInitialVoiceCount(byte channel);
|
byte getInitialVoiceCount(byte channel);
|
||||||
bool isChannelUsed(byte channel) const { return _channelsUsed & (1 << channel); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SciVersion _soundVersion;
|
SciVersion _soundVersion;
|
||||||
|
@ -521,9 +520,6 @@ private:
|
||||||
Track *_tracks;
|
Track *_tracks;
|
||||||
Resource *_innerResource;
|
Resource *_innerResource;
|
||||||
ResourceManager *_resMan;
|
ResourceManager *_resMan;
|
||||||
uint16 _channelsUsed;
|
|
||||||
|
|
||||||
void setChannelUsed(byte channel) { _channelsUsed |= (1 << channel); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace Sci
|
} // End of namespace Sci
|
||||||
|
|
|
@ -461,8 +461,6 @@ SoundResource::SoundResource(uint32 resNumber, ResourceManager *resMan, SciVersi
|
||||||
byte *dataEnd;
|
byte *dataEnd;
|
||||||
Channel *channel, *sampleChannel;
|
Channel *channel, *sampleChannel;
|
||||||
|
|
||||||
_channelsUsed = 0;
|
|
||||||
|
|
||||||
switch (_soundVersion) {
|
switch (_soundVersion) {
|
||||||
case SCI_VERSION_0_EARLY:
|
case SCI_VERSION_0_EARLY:
|
||||||
case SCI_VERSION_0_LATE:
|
case SCI_VERSION_0_LATE:
|
||||||
|
@ -552,7 +550,6 @@ SoundResource::SoundResource(uint32 resNumber, ResourceManager *resMan, SciVersi
|
||||||
channel->data = resource->data + READ_LE_UINT16(data + 2) + 2;
|
channel->data = resource->data + READ_LE_UINT16(data + 2) + 2;
|
||||||
channel->size = READ_LE_UINT16(data + 4) - 2; // Not counting channel header
|
channel->size = READ_LE_UINT16(data + 4) - 2; // Not counting channel header
|
||||||
channel->number = *(channel->data - 2);
|
channel->number = *(channel->data - 2);
|
||||||
setChannelUsed(channel->number);
|
|
||||||
channel->poly = *(channel->data - 1);
|
channel->poly = *(channel->data - 1);
|
||||||
channel->time = channel->prev = 0;
|
channel->time = channel->prev = 0;
|
||||||
if (channel->number == 0xFE) { // Digital channel
|
if (channel->number == 0xFE) { // Digital channel
|
||||||
|
|
|
@ -43,9 +43,10 @@ enum SciMidiCommands {
|
||||||
|
|
||||||
// MidiParser_SCI
|
// MidiParser_SCI
|
||||||
//
|
//
|
||||||
MidiParser_SCI::MidiParser_SCI(SciVersion soundVersion) :
|
MidiParser_SCI::MidiParser_SCI(SciVersion soundVersion, SciMusic *music) :
|
||||||
MidiParser() {
|
MidiParser() {
|
||||||
_soundVersion = soundVersion;
|
_soundVersion = soundVersion;
|
||||||
|
_music = music;
|
||||||
_mixedData = NULL;
|
_mixedData = NULL;
|
||||||
// mididata contains delta in 1/60th second
|
// mididata contains delta in 1/60th second
|
||||||
// values of ppqn and tempo are found experimentally and may be wrong
|
// values of ppqn and tempo are found experimentally and may be wrong
|
||||||
|
@ -59,10 +60,6 @@ MidiParser_SCI::MidiParser_SCI(SciVersion soundVersion) :
|
||||||
_dataincAdd = false;
|
_dataincAdd = false;
|
||||||
_dataincToAdd = 0;
|
_dataincToAdd = 0;
|
||||||
_resetOnPause = false;
|
_resetOnPause = false;
|
||||||
_channelsUsed = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++)
|
|
||||||
_channelRemap[i] = i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MidiParser_SCI::~MidiParser_SCI() {
|
MidiParser_SCI::~MidiParser_SCI() {
|
||||||
|
@ -78,6 +75,13 @@ bool MidiParser_SCI::loadMusic(SoundResource::Track *track, MusicEntry *psnd, in
|
||||||
if (_pSnd)
|
if (_pSnd)
|
||||||
setVolume(psnd->volume);
|
setVolume(psnd->volume);
|
||||||
|
|
||||||
|
for (int i = 0; i < 15; i++) {
|
||||||
|
_channelUsed[i] = false;
|
||||||
|
_channelRemap[i] = -1;
|
||||||
|
}
|
||||||
|
_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
|
||||||
|
|
||||||
if (channelFilterMask) {
|
if (channelFilterMask) {
|
||||||
// SCI0 only has 1 data stream, but we need to filter out channels depending on music hardware selection
|
// SCI0 only has 1 data stream, but we need to filter out channels depending on music hardware selection
|
||||||
midiFilterChannels(channelFilterMask);
|
midiFilterChannels(channelFilterMask);
|
||||||
|
@ -128,21 +132,24 @@ void MidiParser_SCI::unloadMusic() {
|
||||||
// Center the pitch wheels and hold pedal in preparation for the next piece of music
|
// Center the pitch wheels and hold pedal in preparation for the next piece of music
|
||||||
if (_driver && _pSnd) {
|
if (_driver && _pSnd) {
|
||||||
for (int i = 0; i < 16; ++i) {
|
for (int i = 0; i < 16; ++i) {
|
||||||
if (isChannelUsed(i)) {
|
int16 realChannel = _channelRemap[i];
|
||||||
_driver->send(0xE0 | i, 0, 0x40); // Reset pitch wheel
|
if (realChannel != -1) {
|
||||||
_driver->send(0xB0 | i, 0x40, 0); // Reset hold pedal
|
_driver->send(0xE0 | realChannel, 0, 0x40); // Reset pitch wheel
|
||||||
|
_driver->send(0xB0 | realChannel, 0x40, 0); // Reset hold pedal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++)
|
void MidiParser_SCI::sendToDriver(uint32 b) {
|
||||||
_channelRemap[i] = i;
|
// Channel remapping
|
||||||
|
int16 realChannel = _channelRemap[b & 0xf];
|
||||||
|
assert(realChannel != -1);
|
||||||
|
b = (b & 0xFFFFFFF0) | realChannel;
|
||||||
|
_driver->send(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiParser_SCI::parseNextEvent(EventInfo &info) {
|
void MidiParser_SCI::parseNextEvent(EventInfo &info) {
|
||||||
// Monitor which channels are used by this song
|
|
||||||
setChannelUsed(info.channel());
|
|
||||||
|
|
||||||
// Set signal AFTER waiting for delta, otherwise we would set signal too soon resulting in all sorts of bugs
|
// Set signal AFTER waiting for delta, otherwise we would set signal too soon resulting in all sorts of bugs
|
||||||
if (_dataincAdd) {
|
if (_dataincAdd) {
|
||||||
_dataincAdd = false;
|
_dataincAdd = false;
|
||||||
|
@ -334,8 +341,9 @@ void MidiParser_SCI::allNotesOff() {
|
||||||
// Turn off all active notes
|
// Turn off all active notes
|
||||||
for (i = 0; i < 128; ++i) {
|
for (i = 0; i < 128; ++i) {
|
||||||
for (j = 0; j < 16; ++j) {
|
for (j = 0; j < 16; ++j) {
|
||||||
if ((_active_notes[i] & (1 << j)) && isChannelUsed(j)){
|
int16 realChannel = _channelRemap[j];
|
||||||
_driver->send(0x80 | j, i, 0);
|
if ((_active_notes[i] & (1 << j)) && realChannel != -1){
|
||||||
|
_driver->send(0x80 | realChannel, i, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -353,8 +361,9 @@ void MidiParser_SCI::allNotesOff() {
|
||||||
// support this...).
|
// support this...).
|
||||||
|
|
||||||
for (i = 0; i < 16; ++i) {
|
for (i = 0; i < 16; ++i) {
|
||||||
if (isChannelUsed(i))
|
int16 realChannel = _channelRemap[i];
|
||||||
_driver->send(0xB0 | i, 0x7b, 0); // All notes off
|
if (realChannel != -1)
|
||||||
|
_driver->send(0xB0 | realChannel, 0x7b, 0); // All notes off
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(_active_notes, 0, sizeof(_active_notes));
|
memset(_active_notes, 0, sizeof(_active_notes));
|
||||||
|
@ -436,19 +445,23 @@ byte *MidiParser_SCI::midiMixChannels() {
|
||||||
default: // MIDI command
|
default: // MIDI command
|
||||||
if (command & 0x80) {
|
if (command & 0x80) {
|
||||||
par1 = *channel->data++;
|
par1 = *channel->data++;
|
||||||
|
|
||||||
// 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
|
} else {// running status
|
||||||
par1 = command;
|
par1 = command;
|
||||||
command = channel->prev;
|
command = channel->prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remember which channel got used for channel remapping
|
||||||
|
byte midiChannel = command & 0xF;
|
||||||
|
_channelUsed[midiChannel] = true;
|
||||||
|
// int16 realChannel = _channelRemap[midiChannel];
|
||||||
|
// if (realChannel == -1) {
|
||||||
|
// // We don't own this channel yet, so ask SciMusic to get it (or a remapped one)
|
||||||
|
// realChannel = _music->tryToOwnChannel(_pSnd, midiChannel);
|
||||||
|
// _channelRemap[midiChannel] = realChannel;
|
||||||
|
// }
|
||||||
|
// // Map new channel
|
||||||
|
// command = realChannel | (command & 0xF0);
|
||||||
|
|
||||||
if (command != global_prev)
|
if (command != global_prev)
|
||||||
*outData++ = command; // out command
|
*outData++ = command; // out command
|
||||||
*outData++ = par1;// pout par1
|
*outData++ = par1;// pout par1
|
||||||
|
@ -577,6 +590,17 @@ byte *MidiParser_SCI::midiFilterChannels(int channelMask) {
|
||||||
return _mixedData;
|
return _mixedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This will get called right before actual playing and will try to own the used channels
|
||||||
|
void MidiParser_SCI::tryToOwnChannels() {
|
||||||
|
for (int curChannel = 0; curChannel < 15; curChannel++) {
|
||||||
|
if (_channelUsed[curChannel]) {
|
||||||
|
if (_channelRemap[curChannel] == -1) {
|
||||||
|
_channelRemap[curChannel] = _music->tryToOwnChannel(_pSnd, curChannel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MidiParser_SCI::setVolume(byte volume) {
|
void MidiParser_SCI::setVolume(byte volume) {
|
||||||
// FIXME: This receives values > 127... throw a warning for now and clip the variable
|
// FIXME: This receives values > 127... throw a warning for now and clip the variable
|
||||||
if (volume > MUSIC_VOLUME_MAX) {
|
if (volume > MUSIC_VOLUME_MAX) {
|
||||||
|
|
|
@ -53,7 +53,7 @@ namespace Sci {
|
||||||
*/
|
*/
|
||||||
class MidiParser_SCI : public MidiParser {
|
class MidiParser_SCI : public MidiParser {
|
||||||
public:
|
public:
|
||||||
MidiParser_SCI(SciVersion soundVersion);
|
MidiParser_SCI(SciVersion soundVersion, SciMusic *music);
|
||||||
~MidiParser_SCI();
|
~MidiParser_SCI();
|
||||||
bool loadMusic(SoundResource::Track *track, MusicEntry *psnd, int channelFilterMask, SciVersion soundVersion);
|
bool loadMusic(SoundResource::Track *track, MusicEntry *psnd, int channelFilterMask, SciVersion soundVersion);
|
||||||
bool loadMusic(byte *, uint32) {
|
bool loadMusic(byte *, uint32) {
|
||||||
|
@ -73,25 +73,19 @@ public:
|
||||||
|
|
||||||
void allNotesOff();
|
void allNotesOff();
|
||||||
|
|
||||||
void remapChannel(byte channel, byte newChannel) {
|
|
||||||
assert(channel < 0xF); // don't touch special SCI channel 15
|
|
||||||
assert(newChannel < 0xF); // don't touch special SCI channel 15
|
|
||||||
_channelRemap[channel] = newChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearUsedChannels() { _channelsUsed = 0; }
|
|
||||||
|
|
||||||
const byte *getMixedData() const { return _mixedData; }
|
const byte *getMixedData() const { return _mixedData; }
|
||||||
|
|
||||||
protected:
|
void tryToOwnChannels();
|
||||||
bool isChannelUsed(byte channel) const { return _channelsUsed & (1 << channel); }
|
|
||||||
void setChannelUsed(byte channel) { _channelsUsed |= (1 << channel); }
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void sendToDriver(uint32 b);
|
||||||
void parseNextEvent(EventInfo &info);
|
void parseNextEvent(EventInfo &info);
|
||||||
byte *midiMixChannels();
|
byte *midiMixChannels();
|
||||||
byte *midiFilterChannels(int channelMask);
|
byte *midiFilterChannels(int channelMask);
|
||||||
byte midiGetNextChannel(long ticker);
|
byte midiGetNextChannel(long ticker);
|
||||||
|
|
||||||
|
SciMusic *_music;
|
||||||
|
|
||||||
SciVersion _soundVersion;
|
SciVersion _soundVersion;
|
||||||
byte *_mixedData;
|
byte *_mixedData;
|
||||||
SoundResource::Track *_track;
|
SoundResource::Track *_track;
|
||||||
|
@ -105,11 +99,8 @@ protected:
|
||||||
int16 _dataincToAdd;
|
int16 _dataincToAdd;
|
||||||
bool _resetOnPause;
|
bool _resetOnPause;
|
||||||
|
|
||||||
// A 16-bit mask, containing the channels used
|
bool _channelUsed[16];
|
||||||
// by the currently parsed song
|
int16 _channelRemap[16];
|
||||||
uint16 _channelsUsed;
|
|
||||||
|
|
||||||
byte _channelRemap[16];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace Sci
|
} // End of namespace Sci
|
||||||
|
|
|
@ -43,6 +43,9 @@ SciMusic::SciMusic(SciVersion soundVersion)
|
||||||
// Reserve some space in the playlist, to avoid expensive insertion
|
// Reserve some space in the playlist, to avoid expensive insertion
|
||||||
// operations
|
// operations
|
||||||
_playList.reserve(10);
|
_playList.reserve(10);
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
_usedChannel[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SciMusic::~SciMusic() {
|
SciMusic::~SciMusic() {
|
||||||
|
@ -174,20 +177,6 @@ void SciMusic::sortPlayList() {
|
||||||
Common::sort(_playList.begin(), _playList.end(), musicEntryCompare);
|
Common::sort(_playList.begin(), _playList.end(), musicEntryCompare);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SciMusic::findUsedChannels() {
|
|
||||||
// Reset list
|
|
||||||
for (int k = 0; k < 16; k++)
|
|
||||||
_usedChannels[k] = false;
|
|
||||||
|
|
||||||
const MusicList::const_iterator end = _playList.end();
|
|
||||||
for (MusicList::const_iterator i = _playList.begin(); i != end; ++i) {
|
|
||||||
for (int channel = 0; channel < 16; channel++) {
|
|
||||||
if ((*i)->soundRes && (*i)->soundRes->isChannelUsed(channel))
|
|
||||||
_usedChannels[channel] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SciMusic::soundInitSnd(MusicEntry *pSnd) {
|
void SciMusic::soundInitSnd(MusicEntry *pSnd) {
|
||||||
int channelFilterMask = 0;
|
int channelFilterMask = 0;
|
||||||
SoundResource::Track *track = pSnd->soundRes->getTrackByType(_pMidiDrv->getPlayId());
|
SoundResource::Track *track = pSnd->soundRes->getTrackByType(_pMidiDrv->getPlayId());
|
||||||
|
@ -224,34 +213,13 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) {
|
||||||
_mutex.lock();
|
_mutex.lock();
|
||||||
pSnd->soundType = Audio::Mixer::kMusicSoundType;
|
pSnd->soundType = Audio::Mixer::kMusicSoundType;
|
||||||
if (pSnd->pMidiParser == NULL) {
|
if (pSnd->pMidiParser == NULL) {
|
||||||
pSnd->pMidiParser = new MidiParser_SCI(_soundVersion);
|
pSnd->pMidiParser = new MidiParser_SCI(_soundVersion, this);
|
||||||
pSnd->pMidiParser->setMidiDriver(_pMidiDrv);
|
pSnd->pMidiParser->setMidiDriver(_pMidiDrv);
|
||||||
pSnd->pMidiParser->setTimerRate(_dwTempo);
|
pSnd->pMidiParser->setTimerRate(_dwTempo);
|
||||||
}
|
}
|
||||||
|
|
||||||
pSnd->pauseCounter = 0;
|
pSnd->pauseCounter = 0;
|
||||||
|
|
||||||
// TODO: Fix channel remapping. This doesn't quite work... (e.g. no difference in LSL1VGA)
|
|
||||||
#if 0
|
|
||||||
// Remap channels
|
|
||||||
findUsedChannels();
|
|
||||||
|
|
||||||
pSnd->pMidiParser->clearUsedChannels();
|
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
if (_usedChannels[i] && pSnd->soundRes->isChannelUsed(i)) {
|
|
||||||
int16 newChannel = getNextUnusedChannel();
|
|
||||||
if (newChannel >= 0) {
|
|
||||||
_usedChannels[newChannel] = true;
|
|
||||||
debug("Remapping channel %d to %d\n", i, newChannel);
|
|
||||||
pSnd->pMidiParser->remapChannel(i, newChannel);
|
|
||||||
} else {
|
|
||||||
warning("Attempt to remap channel %d, but no unused channels exist", i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Find out what channels to filter for SCI0
|
// Find out what channels to filter for SCI0
|
||||||
channelFilterMask = pSnd->soundRes->getChannelFilterMask(_pMidiDrv->getPlayId(), _pMidiDrv->hasRhythmChannel());
|
channelFilterMask = pSnd->soundRes->getChannelFilterMask(_pMidiDrv->getPlayId(), _pMidiDrv->hasRhythmChannel());
|
||||||
pSnd->pMidiParser->loadMusic(track, pSnd, channelFilterMask, _soundVersion);
|
pSnd->pMidiParser->loadMusic(track, pSnd, channelFilterMask, _soundVersion);
|
||||||
|
@ -263,6 +231,24 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This one checks, if requested channel is available -> in that case give caller that channel
|
||||||
|
// Otherwise look for an unused one
|
||||||
|
int16 SciMusic::tryToOwnChannel(MusicEntry *caller, int16 bestChannel) {
|
||||||
|
if (!_usedChannel[bestChannel]) {
|
||||||
|
// currently unused, so give it to caller directly
|
||||||
|
_usedChannel[bestChannel] = caller;
|
||||||
|
return bestChannel;
|
||||||
|
}
|
||||||
|
// otherwise look for unused channel
|
||||||
|
for (int channelNr = 0; channelNr < 15; channelNr++) {
|
||||||
|
if (!_usedChannel[channelNr]) {
|
||||||
|
_usedChannel[channelNr] = caller;
|
||||||
|
return channelNr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error("no free channels");
|
||||||
|
}
|
||||||
|
|
||||||
void SciMusic::onTimer() {
|
void SciMusic::onTimer() {
|
||||||
const MusicList::iterator end = _playList.end();
|
const MusicList::iterator end = _playList.end();
|
||||||
for (MusicList::iterator i = _playList.begin(); i != end; ++i)
|
for (MusicList::iterator i = _playList.begin(); i != end; ++i)
|
||||||
|
@ -324,6 +310,7 @@ void SciMusic::soundPlay(MusicEntry *pSnd) {
|
||||||
DisposeAfterUse::NO);
|
DisposeAfterUse::NO);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
pSnd->pMidiParser->tryToOwnChannels();
|
||||||
_mutex.lock();
|
_mutex.lock();
|
||||||
if (pSnd->pMidiParser) {
|
if (pSnd->pMidiParser) {
|
||||||
pSnd->pMidiParser->setVolume(pSnd->volume);
|
pSnd->pMidiParser->setVolume(pSnd->volume);
|
||||||
|
@ -388,6 +375,11 @@ void SciMusic::soundKill(MusicEntry *pSnd) {
|
||||||
|
|
||||||
_mutex.lock();
|
_mutex.lock();
|
||||||
uint sz = _playList.size(), i;
|
uint sz = _playList.size(), i;
|
||||||
|
// Remove used channels
|
||||||
|
for (i = 0; i < 15; i++) {
|
||||||
|
if (_usedChannel[i] == pSnd)
|
||||||
|
_usedChannel[i] = 0;
|
||||||
|
}
|
||||||
// Remove sound from playlist
|
// Remove sound from playlist
|
||||||
for (i = 0; i < sz; i++) {
|
for (i = 0; i < sz; i++) {
|
||||||
if (_playList[i] == pSnd) {
|
if (_playList[i] == pSnd) {
|
||||||
|
|
|
@ -196,6 +196,8 @@ public:
|
||||||
// where a deadlock can occur
|
// where a deadlock can occur
|
||||||
Common::Mutex _mutex;
|
Common::Mutex _mutex;
|
||||||
|
|
||||||
|
int16 tryToOwnChannel(MusicEntry *caller, int16 bestChannel);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void sortPlayList();
|
void sortPlayList();
|
||||||
|
|
||||||
|
@ -210,20 +212,11 @@ protected:
|
||||||
bool _bMultiMidi;
|
bool _bMultiMidi;
|
||||||
private:
|
private:
|
||||||
static void miditimerCallback(void *p);
|
static void miditimerCallback(void *p);
|
||||||
void findUsedChannels();
|
|
||||||
int16 getNextUnusedChannel() const {
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
if (!_usedChannels[i])
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
MusicList _playList;
|
MusicList _playList;
|
||||||
bool _soundOn;
|
bool _soundOn;
|
||||||
byte _masterVolume;
|
byte _masterVolume;
|
||||||
bool _usedChannels[16];
|
MusicEntry *_usedChannel[16];
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace Sci
|
} // End of namespace Sci
|
||||||
|
|
|
@ -67,6 +67,10 @@ void MidiParser::property(int prop, int value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MidiParser::sendToDriver(uint32 b) {
|
||||||
|
_driver->send(b);
|
||||||
|
}
|
||||||
|
|
||||||
void MidiParser::setTempo(uint32 tempo) {
|
void MidiParser::setTempo(uint32 tempo) {
|
||||||
_tempo = tempo;
|
_tempo = tempo;
|
||||||
if (_ppqn)
|
if (_ppqn)
|
||||||
|
@ -127,7 +131,7 @@ void MidiParser::hangingNote(byte channel, byte note, uint32 time_left, bool rec
|
||||||
best = ptr;
|
best = ptr;
|
||||||
if (ptr->time_left) {
|
if (ptr->time_left) {
|
||||||
if (recycle)
|
if (recycle)
|
||||||
_driver->send(0x80 | channel, note, 0);
|
sendToDriver(0x80 | channel, note, 0);
|
||||||
--_hanging_notes_count;
|
--_hanging_notes_count;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -172,7 +176,7 @@ void MidiParser::onTimer() {
|
||||||
for (i = ARRAYSIZE(_hanging_notes); i; --i, ++ptr) {
|
for (i = ARRAYSIZE(_hanging_notes); i; --i, ++ptr) {
|
||||||
if (ptr->time_left) {
|
if (ptr->time_left) {
|
||||||
if (ptr->time_left <= _timer_rate) {
|
if (ptr->time_left <= _timer_rate) {
|
||||||
_driver->send(0x80 | ptr->channel, ptr->note, 0);
|
sendToDriver(0x80 | ptr->channel, ptr->note, 0);
|
||||||
ptr->time_left = 0;
|
ptr->time_left = 0;
|
||||||
--_hanging_notes_count;
|
--_hanging_notes_count;
|
||||||
} else {
|
} else {
|
||||||
|
@ -232,7 +236,7 @@ void MidiParser::onTimer() {
|
||||||
else
|
else
|
||||||
activeNote(info.channel(), info.basic.param1, true);
|
activeNote(info.channel(), info.basic.param1, true);
|
||||||
}
|
}
|
||||||
_driver->send(info.event, info.basic.param1, info.basic.param2);
|
sendToDriver(info.event, info.basic.param1, info.basic.param2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -258,7 +262,7 @@ void MidiParser::allNotesOff() {
|
||||||
for (i = 0; i < 128; ++i) {
|
for (i = 0; i < 128; ++i) {
|
||||||
for (j = 0; j < 16; ++j) {
|
for (j = 0; j < 16; ++j) {
|
||||||
if (_active_notes[i] & (1 << j)) {
|
if (_active_notes[i] & (1 << j)) {
|
||||||
_driver->send(0x80 | j, i, 0);
|
sendToDriver(0x80 | j, i, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,7 +270,7 @@ void MidiParser::allNotesOff() {
|
||||||
// Turn off all hanging notes
|
// Turn off all hanging notes
|
||||||
for (i = 0; i < ARRAYSIZE(_hanging_notes); i++) {
|
for (i = 0; i < ARRAYSIZE(_hanging_notes); i++) {
|
||||||
if (_hanging_notes[i].time_left) {
|
if (_hanging_notes[i].time_left) {
|
||||||
_driver->send(0x80 | _hanging_notes[i].channel, _hanging_notes[i].note, 0);
|
sendToDriver(0x80 | _hanging_notes[i].channel, _hanging_notes[i].note, 0);
|
||||||
_hanging_notes[i].time_left = 0;
|
_hanging_notes[i].time_left = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -276,7 +280,7 @@ void MidiParser::allNotesOff() {
|
||||||
// support this...).
|
// support this...).
|
||||||
|
|
||||||
for (i = 0; i < 16; ++i) {
|
for (i = 0; i < 16; ++i) {
|
||||||
_driver->send(0xB0 | i, 0x7b, 0); // All notes off
|
sendToDriver(0xB0 | i, 0x7b, 0); // All notes off
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(_active_notes, 0, sizeof(_active_notes));
|
memset(_active_notes, 0, sizeof(_active_notes));
|
||||||
|
@ -348,7 +352,7 @@ void MidiParser::hangAllActiveNotes() {
|
||||||
for (j = 0; j < 16; ++j) {
|
for (j = 0; j < 16; ++j) {
|
||||||
if (temp_active[i] & (1 << j)) {
|
if (temp_active[i] & (1 << j)) {
|
||||||
activeNote(j, i, false);
|
activeNote(j, i, false);
|
||||||
_driver->send(0x80 | j, i, 0);
|
sendToDriver(0x80 | j, i, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -399,7 +403,7 @@ bool MidiParser::jumpToTick(uint32 tick, bool fireEvents, bool stopNotes) {
|
||||||
else
|
else
|
||||||
_driver->sysEx(info.ext.data, (uint16)info.length);
|
_driver->sysEx(info.ext.data, (uint16)info.length);
|
||||||
} else
|
} else
|
||||||
_driver->send(info.event, info.basic.param1, info.basic.param2);
|
sendToDriver(info.event, info.basic.param1, info.basic.param2);
|
||||||
}
|
}
|
||||||
|
|
||||||
parseNextEvent(_next_event);
|
parseNextEvent(_next_event);
|
||||||
|
@ -441,7 +445,7 @@ void MidiParser::unloadMusic() {
|
||||||
|
|
||||||
if (_driver) {
|
if (_driver) {
|
||||||
for (int i = 0; i < 16; ++i) {
|
for (int i = 0; i < 16; ++i) {
|
||||||
_driver->send(0xE0 | i, 0, 0x40);
|
sendToDriver(0xE0 | i, 0, 0x40);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -374,6 +374,11 @@ public:
|
||||||
void setTempo(uint32 tempo);
|
void setTempo(uint32 tempo);
|
||||||
void onTimer();
|
void onTimer();
|
||||||
|
|
||||||
|
virtual void sendToDriver(uint32 b);
|
||||||
|
void sendToDriver(byte status, byte firstOp, byte secondOp) {
|
||||||
|
sendToDriver(status | ((uint32)firstOp << 8) | ((uint32)secondOp << 16));
|
||||||
|
}
|
||||||
|
|
||||||
bool isPlaying() const { return (_position._play_pos != 0); }
|
bool isPlaying() const { return (_position._play_pos != 0); }
|
||||||
void stopPlaying();
|
void stopPlaying();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue