aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/sound
diff options
context:
space:
mode:
authorAlejandro Marzini2010-07-13 04:31:15 +0000
committerAlejandro Marzini2010-07-13 04:31:15 +0000
commit609e08d5dbae3179eddf981abe73d69009432de4 (patch)
treecddbd0a0e69eaa53b85f98f96dc410a307773f08 /engines/sci/sound
parent8b6a670391f1b5103e3761d78eef8f41d64cf8cd (diff)
parent03c0faa5d76f547603ee6389cdf958e2a6f0f43d (diff)
downloadscummvm-rg350-609e08d5dbae3179eddf981abe73d69009432de4.tar.gz
scummvm-rg350-609e08d5dbae3179eddf981abe73d69009432de4.tar.bz2
scummvm-rg350-609e08d5dbae3179eddf981abe73d69009432de4.zip
Merged from trunk, from Rev 49499 to HEAD
svn-id: r50840
Diffstat (limited to 'engines/sci/sound')
-rw-r--r--engines/sci/sound/audio.cpp83
-rw-r--r--engines/sci/sound/audio.h5
-rw-r--r--engines/sci/sound/drivers/adlib.cpp14
-rw-r--r--engines/sci/sound/drivers/fb01.cpp4
-rw-r--r--engines/sci/sound/drivers/midi.cpp25
-rw-r--r--engines/sci/sound/drivers/mididriver.h1
-rw-r--r--engines/sci/sound/iterator/core.cpp1013
-rw-r--r--engines/sci/sound/iterator/core.h209
-rw-r--r--engines/sci/sound/iterator/iterator.cpp1686
-rw-r--r--engines/sci/sound/iterator/iterator.h326
-rw-r--r--engines/sci/sound/iterator/iterator_internal.h276
-rw-r--r--engines/sci/sound/iterator/songlib.cpp189
-rw-r--r--engines/sci/sound/iterator/songlib.h171
-rw-r--r--engines/sci/sound/iterator/test-iterator.cpp423
-rw-r--r--engines/sci/sound/midiparser_sci.cpp659
-rw-r--r--engines/sci/sound/midiparser_sci.h40
-rw-r--r--engines/sci/sound/music.cpp266
-rw-r--r--engines/sci/sound/music.h60
-rw-r--r--engines/sci/sound/soundcmd.cpp919
-rw-r--r--engines/sci/sound/soundcmd.h97
20 files changed, 960 insertions, 5506 deletions
diff --git a/engines/sci/sound/audio.cpp b/engines/sci/sound/audio.cpp
index 7ecce3b2a3..d9e9d2e8db 100644
--- a/engines/sci/sound/audio.cpp
+++ b/engines/sci/sound/audio.cpp
@@ -24,20 +24,21 @@
*/
#include "sci/resource.h"
-#include "sci/engine/selector.h"
#include "sci/engine/kernel.h"
+#include "sci/engine/selector.h"
#include "sci/engine/seg_manager.h"
#include "sci/sound/audio.h"
-#include "common/system.h"
#include "common/file.h"
+#include "common/system.h"
#include "sound/audiostream.h"
-#include "sound/decoders/raw.h"
-#include "sound/decoders/wave.h"
+#include "sound/decoders/aiff.h"
#include "sound/decoders/flac.h"
#include "sound/decoders/mp3.h"
+#include "sound/decoders/raw.h"
#include "sound/decoders/vorbis.h"
+#include "sound/decoders/wave.h"
namespace Sci {
@@ -45,6 +46,7 @@ AudioPlayer::AudioPlayer(ResourceManager *resMan) : _resMan(resMan), _audioRate(
_syncResource(NULL), _syncOffset(0), _audioCdStart(0) {
_mixer = g_system->getMixer();
+ _wPlayFlag = false;
}
AudioPlayer::~AudioPlayer() {
@@ -63,11 +65,30 @@ int AudioPlayer::startAudio(uint16 module, uint32 number) {
Audio::AudioStream *audioStream = getAudioStream(number, module, &sampleLen);
if (audioStream) {
+ _wPlayFlag = false;
_mixer->playStream(Audio::Mixer::kSpeechSoundType, &_audioHandle, audioStream);
return sampleLen;
+ } else {
+ // Don't throw a warning in this case. getAudioStream() already has. Some games
+ // do miss audio entries (perhaps because of a typo, or because they were simply
+ // forgotten).
+ return 0;
}
+}
- return 0;
+int AudioPlayer::wPlayAudio(uint16 module, uint32 tuple) {
+ // Get the audio sample length and set the wPlay flag so we return 0 on
+ // position. SSCI pre-loads the audio here, but it's much easier for us to
+ // just get the sample length and return that. wPlayAudio should *not*
+ // actually start the sample.
+
+ int sampleLen = 0;
+ Audio::AudioStream *audioStream = getAudioStream(tuple, module, &sampleLen);
+ if (!audioStream)
+ warning("wPlayAudio: unable to create stream for audio tuple %d, module %d", tuple, module);
+ delete audioStream;
+ _wPlayFlag = true;
+ return sampleLen;
}
void AudioPlayer::stopAudio() {
@@ -85,6 +106,8 @@ void AudioPlayer::resumeAudio() {
int AudioPlayer::getAudioPosition() {
if (_mixer->isSoundHandleActive(_audioHandle))
return _mixer->getSoundElapsedTime(_audioHandle) * 6 / 100; // return elapsed time in ticks
+ else if (_wPlayFlag)
+ return 0; // Sound has "loaded" so return that it hasn't started
else
return -1; // Sound finished
}
@@ -160,17 +183,28 @@ static void deDPCM8(byte *soundBuf, Common::SeekableReadStream &audioStream, uin
// Sierra SOL audio file reader
// Check here for more info: http://wiki.multimedia.cx/index.php?title=Sierra_Audio
-static bool readSOLHeader(Common::SeekableReadStream *audioStream, int headerSize, uint32 &size, uint16 &audioRate, byte &audioFlags) {
- if (headerSize != 11 && headerSize != 12) {
+static bool readSOLHeader(Common::SeekableReadStream *audioStream, int headerSize, uint32 &size, uint16 &audioRate, byte &audioFlags, uint32 resSize) {
+ if (headerSize != 7 && headerSize != 11 && headerSize != 12) {
warning("SOL audio header of size %i not supported", headerSize);
return false;
}
- audioStream->readUint32LE(); // skip "SOL" + 0 (4 bytes)
+ uint32 tag = audioStream->readUint32BE();
+
+ if (tag != MKID_BE('SOL\0')) {
+ warning("No 'SOL' FourCC found");
+ return false;
+ }
+
audioRate = audioStream->readUint16LE();
audioFlags = audioStream->readByte();
- size = audioStream->readUint32LE();
+ // For the QFG3 demo format, just use the resource size
+ // Otherwise, load it from the header
+ if (headerSize == 7)
+ size = resSize;
+ else
+ size = audioStream->readUint32LE();
return true;
}
@@ -238,9 +272,11 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
// Compressed audio made by our tool
byte *compressedData = (byte *)malloc(audioRes->size);
assert(compressedData);
- // We copy over the compressed data in our own buffer. If we don't do this resourcemanager may free the data
- // later. All other compression-types already decompress completely into an additional buffer here.
- // MP3/OGG/FLAC decompression works on-the-fly instead.
+ // We copy over the compressed data in our own buffer. We have to do
+ // this, because ResourceManager may free the original data late. All
+ // other compression types already decompress completely into an
+ // additional buffer here. MP3/OGG/FLAC decompression works on-the-fly
+ // instead.
memcpy(compressedData, audioRes->data, audioRes->size);
Common::MemoryReadStream *compressedStream = new Common::MemoryReadStream(compressedData, audioRes->size, DisposeAfterUse::YES);
@@ -270,7 +306,7 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
// SCI1.1
Common::MemoryReadStream headerStream(audioRes->_header, audioRes->_headerSize, DisposeAfterUse::NO);
- if (readSOLHeader(&headerStream, audioRes->_headerSize, size, _audioRate, audioFlags)) {
+ if (readSOLHeader(&headerStream, audioRes->_headerSize, size, _audioRate, audioFlags, audioRes->size)) {
Common::MemoryReadStream dataStream(audioRes->data, audioRes->size, DisposeAfterUse::NO);
data = readSOLAudio(&dataStream, size, audioFlags, flags);
}
@@ -286,6 +322,18 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
waveStream->seek(0, SEEK_SET);
audioStream = Audio::makeWAVStream(waveStream, DisposeAfterUse::YES);
+ } else if (audioRes->size > 4 && READ_BE_UINT32(audioRes->data) == MKID_BE('FORM')) {
+ // AIFF detected
+ Common::MemoryReadStream *waveStream = new Common::MemoryReadStream(audioRes->data, audioRes->size, DisposeAfterUse::NO);
+
+ // Calculate samplelen from AIFF header
+ int waveSize = 0, waveRate = 0;
+ byte waveFlags = 0;
+ Audio::loadAIFFFromStream(*waveStream, waveSize, waveRate, waveFlags);
+ *sampleLen = (waveFlags & Audio::FLAG_16BITS ? waveSize >> 1 : waveSize) * 60 / waveRate;
+
+ waveStream->seek(0, SEEK_SET);
+ audioStream = Audio::makeAIFFStream(waveStream, DisposeAfterUse::YES);
} else if (audioRes->size > 14 && READ_BE_UINT16(audioRes->data) == 1 && READ_BE_UINT16(audioRes->data + 2) == 1
&& READ_BE_UINT16(audioRes->data + 4) == 5 && READ_BE_UINT32(audioRes->data + 10) == 0x00018051) {
// Mac snd detected
@@ -317,13 +365,12 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
}
if (audioSeekStream) {
- *sampleLen = (audioSeekStream->getLength().msecs() * 10000) / 166666; // we translate msecs to ticks
- // Original code
- //*sampleLen = (flags & Audio::FLAG_16BITS ? size >> 1 : size) * 60 / _audioRate;
+ *sampleLen = (audioSeekStream->getLength().msecs() * 60) / 1000; // we translate msecs to ticks
audioStream = audioSeekStream;
}
- // We have to make sure that we don't depend on resource manager pointers after this point, because the actual
- // audio resource may get unloaded by resource manager at any time
+ // We have to make sure that we don't depend on resource manager pointers
+ // after this point, because the actual audio resource may get unloaded by
+ // resource manager at any time.
if (audioStream)
return audioStream;
diff --git a/engines/sci/sound/audio.h b/engines/sci/sound/audio.h
index 9fc3cbac51..7c1221fc4c 100644
--- a/engines/sci/sound/audio.h
+++ b/engines/sci/sound/audio.h
@@ -33,8 +33,7 @@
namespace Sci {
enum AudioCommands {
- // TODO: find the difference between kSci1AudioWPlay and kSci1AudioPlay
- kSciAudioWPlay = 1, /* Plays an audio stream */
+ kSciAudioWPlay = 1, /* Loads an audio stream */
kSciAudioPlay = 2, /* Plays an audio stream */
kSciAudioStop = 3, /* Stops an audio stream */
kSciAudioPause = 4, /* Pauses an audio stream */
@@ -69,6 +68,7 @@ public:
Audio::RewindableAudioStream *getAudioStream(uint32 number, uint32 volume, int *sampleLen);
int getAudioPosition();
int startAudio(uint16 module, uint32 tuple);
+ int wPlayAudio(uint16 module, uint32 tuple);
void stopAudio();
void pauseAudio();
void resumeAudio();
@@ -92,6 +92,7 @@ private:
Resource *_syncResource; /**< Used by kDoSync for speech syncing in CD talkie games */
uint _syncOffset;
uint32 _audioCdStart;
+ bool _wPlayFlag;
};
} // End of namespace Sci
diff --git a/engines/sci/sound/drivers/adlib.cpp b/engines/sci/sound/drivers/adlib.cpp
index a743e4b5d9..55c3640c9d 100644
--- a/engines/sci/sound/drivers/adlib.cpp
+++ b/engines/sci/sound/drivers/adlib.cpp
@@ -704,6 +704,7 @@ void MidiDriver_AdLib::setVelocityReg(int regOffset, int velocity, int kbScaleLe
void MidiDriver_AdLib::setPatch(int voice, int patch) {
if ((patch < 0) || ((uint)patch >= _patches.size())) {
warning("ADLIB: Invalid patch %i requested", patch);
+ // Substitute instrument 0
patch = 0;
}
@@ -749,17 +750,24 @@ void MidiDriver_AdLib::playSwitch(bool play) {
bool MidiDriver_AdLib::loadResource(const byte *data, uint size) {
if ((size != 1344) && (size != 2690) && (size != 5382)) {
- warning("ADLIB: Unsupported patch format (%i bytes)", size);
+ error("ADLIB: Unsupported patch format (%i bytes)", size);
return false;
}
for (int i = 0; i < 48; i++)
loadInstrument(data + (28 * i));
- if (size == 2690) {
+ if (size == 1344) {
+ byte dummy[28] = {0};
+
+ // Only 48 instruments, add dummies
+ for (int i = 0; i < 48; i++)
+ loadInstrument(dummy);
+ } else if (size == 2690) {
for (int i = 48; i < 96; i++)
loadInstrument(data + 2 + (28 * i));
- } else if (size == 5382) {
+ } else {
+ // SCI1.1 and later
for (int i = 48; i < 190; i++)
loadInstrument(data + (28 * i));
_rhythmKeyMap = new byte[kRhythmKeys];
diff --git a/engines/sci/sound/drivers/fb01.cpp b/engines/sci/sound/drivers/fb01.cpp
index 7e9fbd51a1..ab9b2e3df5 100644
--- a/engines/sci/sound/drivers/fb01.cpp
+++ b/engines/sci/sound/drivers/fb01.cpp
@@ -128,8 +128,8 @@ private:
};
MidiPlayer_Fb01::MidiPlayer_Fb01(SciVersion version) : MidiPlayer(version), _playSwitch(true), _masterVolume(15), _timerParam(NULL), _timerProc(NULL) {
- MidiDriverType midiType = MidiDriver::detectMusicDriver(MDT_MIDI);
- _driver = createMidi(midiType);
+ MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI);
+ _driver = createMidi(dev);
_sysExBuf[0] = 0x43;
_sysExBuf[1] = 0x75;
diff --git a/engines/sci/sound/drivers/midi.cpp b/engines/sci/sound/drivers/midi.cpp
index 2432a8fab0..1ef0781906 100644
--- a/engines/sci/sound/drivers/midi.cpp
+++ b/engines/sci/sound/drivers/midi.cpp
@@ -55,6 +55,7 @@ public:
bool hasRhythmChannel() const { return true; }
byte getPlayId();
int getPolyphony() const { return kVoices; }
+ int getFirstChannel();
void setVolume(byte volume);
int getVolume();
void setReverb(byte reverb);
@@ -119,10 +120,10 @@ private:
};
MidiPlayer_Midi::MidiPlayer_Midi(SciVersion version) : MidiPlayer(version), _playSwitch(true), _masterVolume(15), _isMt32(false), _hasReverb(false), _isOldPatchFormat(true) {
- MidiDriverType midiType = MidiDriver::detectMusicDriver(MDT_MIDI);
- _driver = createMidi(midiType);
+ MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI);
+ _driver = createMidi(dev);
- if (midiType == MD_MT32 || ConfMan.getBool("native_mt32"))
+ if (MidiDriver::getMusicType(dev) == MT_MT32 || ConfMan.getBool("native_mt32"))
_isMt32 = true;
_sysExBuf[0] = 0x41;
@@ -271,6 +272,17 @@ void MidiPlayer_Midi::setPatch(int channel, int patch) {
_driver->setPitchBendRange(channel, bendRange);
_driver->send(0xc0 | channel, _patchMap[patch], 0);
+
+ // Send a pointless command to work around a firmware bug in common
+ // USB-MIDI cables. If the first MIDI command in a USB packet is a
+ // Cx or Dx command, the second command in the packet is dropped
+ // somewhere.
+ // FIXME: consider putting a workaround in the MIDI backend drivers
+ // instead.
+ // Known to be affected: alsa, coremidi
+ // Known *not* to be affected: windows (only seems to send one MIDI
+ // command per USB packet even if the device allows larger packets).
+ _driver->send(0xb0 | channel, 0x0a, _channels[channel].pan);
}
void MidiPlayer_Midi::send(uint32 b) {
@@ -306,6 +318,13 @@ void MidiPlayer_Midi::send(uint32 b) {
}
}
+// We return 1 for mt32, because if we remap channels to 0 for mt32, those won't get played at all
+int MidiPlayer_Midi::getFirstChannel() {
+ if (_isMt32)
+ return 1;
+ return 0;
+}
+
void MidiPlayer_Midi::setVolume(byte volume) {
_masterVolume = volume;
diff --git a/engines/sci/sound/drivers/mididriver.h b/engines/sci/sound/drivers/mididriver.h
index 12d3e57f5d..58803db260 100644
--- a/engines/sci/sound/drivers/mididriver.h
+++ b/engines/sci/sound/drivers/mididriver.h
@@ -86,6 +86,7 @@ public:
virtual byte getPlayId() = 0;
virtual int getPolyphony() const = 0;
+ virtual int getFirstChannel() { return 0; };
virtual void setVolume(byte volume) {
if(_driver)
diff --git a/engines/sci/sound/iterator/core.cpp b/engines/sci/sound/iterator/core.cpp
deleted file mode 100644
index 7cd730b3e2..0000000000
--- a/engines/sci/sound/iterator/core.cpp
+++ /dev/null
@@ -1,1013 +0,0 @@
-/* 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$
- *
- */
-
-/* Sound subsystem core: Event handler, sound player dispatching */
-
-#include "sci/sci.h"
-#ifdef USE_OLD_MUSIC_FUNCTIONS
-
-#include "sci/sound/iterator/core.h"
-#include "sci/sound/iterator/iterator.h"
-#include "sci/sound/drivers/mididriver.h"
-
-#include "common/system.h"
-#include "common/timer.h"
-
-#include "sound/mixer.h"
-
-namespace Sci {
-
-/* Plays a song iterator that found a PCM through a PCM device, if possible
-** Parameters: (SongIterator *) it: The iterator to play
-** (SongHandle) handle: Debug handle
-** Returns : (int) 0 if the effect will not be played, nonzero if it will
-** This assumes that the last call to 'it->next()' returned SI_PCM.
-*/
-static int sfx_play_iterator_pcm(SongIterator *it, SongHandle handle);
-
-
-#pragma mark -
-
-
-class SfxPlayer {
-public:
- /** Number of voices that can play simultaneously */
- int _polyphony;
-
-protected:
- SciVersion _soundVersion;
- MidiPlayer *_mididrv;
-
- SongIterator *_iterator;
- Audio::Timestamp _wakeupTime;
- Audio::Timestamp _currentTime;
- uint32 _pauseTimeDiff;
-
- bool _paused;
- bool _iteratorIsDone;
- uint32 _tempo;
-
- Common::Mutex _mutex;
- int _volume;
-
- void play_song(SongIterator *it);
- static void player_timer_callback(void *refCon);
-
-public:
- SfxPlayer(SciVersion soundVersion);
- ~SfxPlayer();
-
- /**
- * Initializes the player.
- * @param resMan a resource manager for driver initialization
- * @param expected_latency expected delay in between calls to 'maintenance' (in microseconds)
- * @return Common::kNoError on success, Common::kUnknownError on failure
- */
- Common::Error init(ResourceManager *resMan, int expected_latency);
-
- /**
- * Adds an iterator to the song player
- * @param it The iterator to play
- * @param start_time The time to assume as the time the first MIDI command executes at
- * @return Common::kNoError on success, Common::kUnknownError on failure
- *
- * The iterator should not be cloned (to avoid memory leaks) and
- * may be modified according to the needs of the player.
- * Implementors may use the 'sfx_iterator_combine()' function
- * to add iterators onto their already existing iterators.
- */
- Common::Error add_iterator(SongIterator *it, uint32 start_time);
-
- /**
- * Stops the currently playing song and deletes the associated iterator.
- * @return Common::kNoError on success, Common::kUnknownError on failure
- */
- Common::Error stop();
-
- /**
- * Transmits a song iterator message to the active song.
- * @param msg the message to transmit
- * @return Common::kNoError on success, Common::kUnknownError on failure
- */
- Common::Error iterator_message(const SongIterator::Message &msg);
-
- /**
- * Pauses song playing.
- * @return Common::kNoError on success, Common::kUnknownError on failure
- */
- Common::Error pause();
-
- /**
- * Resumes song playing after a pause.
- * @return Common::kNoError on success, Common::kUnknownError on failure
- */
- Common::Error resume();
-
- /**
- * Pass a raw MIDI event to the synth.
- * @param argc length of buffer holding the midi event
- * @param argv the buffer itself
- */
- void tell_synth(int buf_nr, byte *buf);
-
- void setVolume(int vol);
-
- int getVolume();
-};
-
-SfxPlayer::SfxPlayer(SciVersion soundVersion)
- : _soundVersion(soundVersion), _wakeupTime(0, SFX_TICKS_PER_SEC), _currentTime(0, 1) {
- _polyphony = 0;
-
- _mididrv = 0;
-
- _iterator = NULL;
- _pauseTimeDiff = 0;
-
- _paused = false;
- _iteratorIsDone = false;
- _tempo = 0;
-
- _volume = 15;
-}
-
-SfxPlayer::~SfxPlayer() {
- if (_mididrv) {
- _mididrv->close();
- delete _mididrv;
- }
- delete _iterator;
- _iterator = NULL;
-}
-
-void SfxPlayer::play_song(SongIterator *it) {
- while (_iterator && _wakeupTime.msecsDiff(_currentTime) <= 0) {
- int delay;
- byte buf[8];
- int result;
-
- switch ((delay = songit_next(&(_iterator),
- buf, &result,
- IT_READER_MASK_ALL
- | IT_READER_MAY_FREE
- | IT_READER_MAY_CLEAN))) {
-
- case SI_FINISHED:
- delete _iterator;
- _iterator = NULL;
- _iteratorIsDone = true;
- return;
-
- case SI_IGNORE:
- case SI_LOOP:
- case SI_RELATIVE_CUE:
- case SI_ABSOLUTE_CUE:
- break;
-
- case SI_PCM:
- sfx_play_iterator_pcm(_iterator, 0);
- break;
-
- case 0:
- static_cast<MidiDriver *>(_mididrv)->send(buf[0], buf[1], buf[2]);
-
- break;
-
- default:
- _wakeupTime = _wakeupTime.addFrames(delay);
- }
- }
-}
-
-void SfxPlayer::tell_synth(int buf_nr, byte *buf) {
- byte op1 = (buf_nr < 2 ? 0 : buf[1]);
- byte op2 = (buf_nr < 3 ? 0 : buf[2]);
-
- static_cast<MidiDriver *>(_mididrv)->send(buf[0], op1, op2);
-}
-
-void SfxPlayer::player_timer_callback(void *refCon) {
- SfxPlayer *thePlayer = (SfxPlayer *)refCon;
- assert(refCon);
- Common::StackLock lock(thePlayer->_mutex);
-
- if (thePlayer->_iterator && !thePlayer->_iteratorIsDone && !thePlayer->_paused) {
- thePlayer->play_song(thePlayer->_iterator);
- }
-
- thePlayer->_currentTime = thePlayer->_currentTime.addFrames(1);
-}
-
-/* API implementation */
-
-Common::Error SfxPlayer::init(ResourceManager *resMan, int expected_latency) {
- MidiDriverType musicDriver = MidiDriver::detectMusicDriver(MDT_PCSPK | MDT_ADLIB);
-
- switch (musicDriver) {
- case MD_ADLIB:
- // FIXME: There's no Amiga sound option, so we hook it up to AdLib
- if (g_sci->getPlatform() == Common::kPlatformAmiga)
- _mididrv = MidiPlayer_Amiga_create(_soundVersion);
- else
- _mididrv = MidiPlayer_AdLib_create(_soundVersion);
- break;
- case MD_PCJR:
- _mididrv = MidiPlayer_PCJr_create(_soundVersion);
- break;
- case MD_PCSPK:
- _mididrv = MidiPlayer_PCSpeaker_create(_soundVersion);
- break;
- default:
- break;
- }
-
- assert(_mididrv);
-
- _polyphony = _mididrv->getPolyphony();
-
- _tempo = _mididrv->getBaseTempo();
- uint32 time = g_system->getMillis();
- _currentTime = Audio::Timestamp(time, 1000000 / _tempo);
- _wakeupTime = Audio::Timestamp(time, SFX_TICKS_PER_SEC);
-
- _mididrv->setTimerCallback(this, player_timer_callback);
- _mididrv->open(resMan);
- _mididrv->setVolume(_volume);
-
- return Common::kNoError;
-}
-
-Common::Error SfxPlayer::add_iterator(SongIterator *it, uint32 start_time) {
- Common::StackLock lock(_mutex);
- SIMSG_SEND(it, SIMSG_SET_PLAYMASK(_mididrv->getPlayId()));
- SIMSG_SEND(it, SIMSG_SET_RHYTHM(_mididrv->hasRhythmChannel()));
-
- if (_iterator == NULL) {
- // Resync with clock
- _currentTime = Audio::Timestamp(g_system->getMillis(), 1000000 / _tempo);
- _wakeupTime = Audio::Timestamp(start_time, SFX_TICKS_PER_SEC);
- }
-
- _iterator = sfx_iterator_combine(_iterator, it);
- _iteratorIsDone = false;
-
- return Common::kNoError;
-}
-
-Common::Error SfxPlayer::stop() {
- debug(3, "Player: Stopping song iterator %p", (void *)_iterator);
- Common::StackLock lock(_mutex);
- delete _iterator;
- _iterator = NULL;
- for (int i = 0; i < MIDI_CHANNELS; i++)
- static_cast<MidiDriver *>(_mididrv)->send(0xb0 + i, SCI_MIDI_CHANNEL_NOTES_OFF, 0);
-
- return Common::kNoError;
-}
-
-Common::Error SfxPlayer::iterator_message(const SongIterator::Message &msg) {
- Common::StackLock lock(_mutex);
- if (!_iterator) {
- return Common::kUnknownError;
- }
-
- songit_handle_message(&_iterator, msg);
-
- return Common::kNoError;
-}
-
-Common::Error SfxPlayer::pause() {
- Common::StackLock lock(_mutex);
-
- _paused = true;
- _pauseTimeDiff = _wakeupTime.msecsDiff(_currentTime);
-
- _mididrv->playSwitch(false);
-
- return Common::kNoError;
-}
-
-Common::Error SfxPlayer::resume() {
- Common::StackLock lock(_mutex);
-
- _wakeupTime = Audio::Timestamp(_currentTime.msecs() + _pauseTimeDiff, SFX_TICKS_PER_SEC);
- _mididrv->playSwitch(true);
- _paused = false;
-
- return Common::kNoError;
-}
-
-void SfxPlayer::setVolume(int vol) {
- _mididrv->setVolume(vol);
-}
-
-int SfxPlayer::getVolume() {
- return _mididrv->getVolume();
-}
-
-#pragma mark -
-
-void SfxState::sfx_reset_player() {
- if (_player)
- _player->stop();
-}
-
-void SfxState::sfx_player_tell_synth(int buf_nr, byte *buf) {
- if (_player)
- _player->tell_synth(buf_nr, buf);
-}
-
-int SfxState::sfx_get_player_polyphony() {
- if (_player)
- return _player->_polyphony;
- else
- return 0;
-}
-
-SfxState::SfxState() {
- _player = NULL;
- _it = NULL;
- _flags = 0;
- _song = NULL;
- _suspended = 0;
-}
-
-SfxState::~SfxState() {
-}
-
-
-void SfxState::freezeTime() {
- /* Freezes the top song delay time */
- const Audio::Timestamp ctime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC);
- Song *song = _song;
-
- while (song) {
- song->_delay = song->_wakeupTime.frameDiff(ctime);
- if (song->_delay < 0)
- song->_delay = 0;
-
- song = song->_nextPlaying;
- }
-}
-
-void SfxState::thawTime() {
- /* inverse of freezeTime() */
- const Audio::Timestamp ctime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC);
- Song *song = _song;
-
- while (song) {
- song->_wakeupTime = ctime.addFrames(song->_delay);
-
- song = song->_nextPlaying;
- }
-}
-
-#if 0
-// Unreferenced - removed
-static void _dump_playing_list(SfxState *self, char *msg) {
- Song *song = self->_song;
-
- fprintf(stderr, "[] Song list : [ ");
- song = *(self->_songlib.lib);
- while (song) {
- fprintf(stderr, "%08lx:%d ", song->handle, song->_status);
- song = song->_nextPlaying;
- }
- fprintf(stderr, "]\n");
-
- fprintf(stderr, "[] Play list (%s) : [ " , msg);
-
- while (song) {
- fprintf(stderr, "%08lx ", song->handle);
- song = song->_nextPlaying;
- }
-
- fprintf(stderr, "]\n");
-}
-#endif
-
-#if 0
-static void _dump_songs(SfxState *self) {
- Song *song = self->_song;
-
- fprintf(stderr, "Cue iterators:\n");
- song = *(self->_songlib.lib);
- while (song) {
- fprintf(stderr, " **\tHandle %08x (p%d): status %d\n",
- song->handle, song->_priority, song->_status);
- SIMSG_SEND(song->_it, SIMSG_PRINT(1));
- song = song->_next;
- }
-
- if (self->_player) {
- fprintf(stderr, "Audio iterator:\n");
- self->_player->iterator_message(SongIterator::Message(0, SIMSG_PRINT(1)));
- }
-}
-#endif
-
-bool SfxState::isPlaying(Song *song) {
- Song *playing_song = _song;
-
- /* _dump_playing_list(this, "is-playing");*/
-
- while (playing_song) {
- if (playing_song == song)
- return true;
- playing_song = playing_song->_nextPlaying;
- }
- return false;
-}
-
-void SfxState::setSongStatus(Song *song, int status) {
- const Audio::Timestamp ctime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC);
-
- switch (status) {
-
- case SOUND_STATUS_STOPPED:
- // Reset
- song->_it->init();
- break;
-
- case SOUND_STATUS_SUSPENDED:
- case SOUND_STATUS_WAITING:
- if (song->_status == SOUND_STATUS_PLAYING) {
- // Update delay, set wakeup_time
- song->_delay += song->_wakeupTime.frameDiff(ctime);
- song->_wakeupTime = ctime;
- }
- if (status == SOUND_STATUS_SUSPENDED)
- break;
-
- /* otherwise... */
-
- case SOUND_STATUS_PLAYING:
- if (song->_status == SOUND_STATUS_STOPPED) {
- // Starting anew
- song->_wakeupTime = ctime;
- }
-
- if (isPlaying(song))
- status = SOUND_STATUS_PLAYING;
- else
- status = SOUND_STATUS_WAITING;
- break;
-
- default:
- fprintf(stderr, "%s L%d: Attempt to set invalid song"
- " state %d!\n", __FILE__, __LINE__, status);
- return;
-
- }
- song->_status = status;
-}
-
-/* Update internal state iff only one song may be played */
-void SfxState::updateSingleSong() {
- Song *newsong = _songlib.findFirstActive();
-
- if (newsong != _song) {
- freezeTime(); /* Store song delay time */
-
- if (_player)
- _player->stop();
-
- if (newsong) {
- if (!newsong->_it)
- return; /* Restore in progress and not ready for this yet */
-
- /* Change song */
- if (newsong->_status == SOUND_STATUS_WAITING)
- setSongStatus(newsong, SOUND_STATUS_PLAYING);
-
- /* Change instrument mappings */
- } else {
- /* Turn off sound */
- }
- if (_song) {
- if (_song->_status == SOUND_STATUS_PLAYING)
- setSongStatus(newsong, SOUND_STATUS_WAITING);
- }
-
- Common::String debugMessage = "[SFX] Changing active song:";
- if (!_song) {
- debugMessage += " New song:";
- } else {
- char tmp[50];
- sprintf(tmp, " pausing %08lx, now playing ", _song->_handle);
- debugMessage += tmp;
- }
-
- if (newsong) {
- char tmp[20];
- sprintf(tmp, "%08lx\n", newsong->_handle);
- debugMessage += tmp;
- } else {
- debugMessage += " none\n";
- }
-
- debugC(2, kDebugLevelSound, "%s", debugMessage.c_str());
-
- _song = newsong;
- thawTime(); /* Recover song delay time */
-
- if (newsong && _player) {
- SongIterator *clonesong = newsong->_it->clone(newsong->_delay);
-
- _player->add_iterator(clonesong, newsong->_wakeupTime.msecs());
- }
- }
-}
-
-
-void SfxState::updateMultiSong() {
- Song *oldfirst = _song;
- Song *oldseeker;
- Song *newsong = _songlib.findFirstActive();
- Song *newseeker;
- Song not_playing_anymore; /* Dummy object, referenced by
- ** songs which are no longer
- ** active. */
-
- /* _dump_playing_list(this, "before");*/
- freezeTime(); /* Store song delay time */
-
- // WORKAROUND: sometimes, newsong can be NULL (e.g. in SQ4).
- // Handle this here, so that we avoid a crash
- if (!newsong) {
- // Iterators should get freed when there's only one song left playing
- if(oldfirst && oldfirst->_status == SOUND_STATUS_STOPPED) {
- debugC(2, kDebugLevelSound, "[SFX] Stopping song %lx", oldfirst->_handle);
- if (_player && oldfirst->_it)
- _player->iterator_message(SongIterator::Message(oldfirst->_it->ID, SIMSG_STOP));
- }
- return;
- }
-
- for (newseeker = newsong; newseeker;
- newseeker = newseeker->_nextPlaying) {
- if (!newseeker || !newseeker->_it)
- return; /* Restore in progress and not ready for this yet */
- }
-
- /* First, put all old songs into the 'stopping' list and
- ** mark their 'next-playing' as not_playing_anymore. */
- for (oldseeker = oldfirst; oldseeker;
- oldseeker = oldseeker->_nextStopping) {
- oldseeker->_nextStopping = oldseeker->_nextPlaying;
- oldseeker->_nextPlaying = &not_playing_anymore;
-
- if (oldseeker == oldseeker->_nextPlaying) {
- error("updateMultiSong() failed. Breakpoint in %s, line %d", __FILE__, __LINE__);
- }
- }
-
- /* Second, re-generate the new song queue. */
- for (newseeker = newsong; newseeker; newseeker = newseeker->_nextPlaying) {
- newseeker->_nextPlaying = _songlib.findNextActive(newseeker);
-
- if (newseeker == newseeker->_nextPlaying) {
- error("updateMultiSong() failed. Breakpoint in %s, line %d", __FILE__, __LINE__);
- }
- }
- /* We now need to update the currently playing song list, because we're
- ** going to use some functions that require this list to be in a sane
- ** state (particularly isPlaying(), indirectly */
- _song = newsong;
-
- /* Third, stop all old songs */
- for (oldseeker = oldfirst; oldseeker;
- oldseeker = oldseeker->_nextStopping)
- if (oldseeker->_nextPlaying == &not_playing_anymore) {
- setSongStatus(oldseeker, SOUND_STATUS_SUSPENDED);
- debugC(2, kDebugLevelSound, "[SFX] Stopping song %lx", oldseeker->_handle);
-
- if (_player && oldseeker->_it)
- _player->iterator_message(SongIterator::Message(oldseeker->_it->ID, SIMSG_STOP));
- oldseeker->_nextPlaying = NULL; /* Clear this pointer; we don't need the tag anymore */
- }
-
- for (newseeker = newsong; newseeker; newseeker = newseeker->_nextPlaying) {
- if (newseeker->_status != SOUND_STATUS_PLAYING && _player) {
- debugC(2, kDebugLevelSound, "[SFX] Adding song %lx", newseeker->_it->ID);
-
- SongIterator *clonesong = newseeker->_it->clone(newseeker->_delay);
- _player->add_iterator(clonesong, g_system->getMillis());
- }
- setSongStatus(newseeker, SOUND_STATUS_PLAYING);
- }
-
- _song = newsong;
- thawTime();
- /* _dump_playing_list(this, "after");*/
-}
-
-/* Update internal state */
-void SfxState::update() {
- if (_flags & SFX_STATE_FLAG_MULTIPLAY)
- updateMultiSong();
- else
- updateSingleSong();
-}
-
-static int sfx_play_iterator_pcm(SongIterator *it, SongHandle handle) {
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Playing PCM: %08lx\n", handle);
-#endif
- if (g_system->getMixer()->isReady()) {
- Audio::AudioStream *newfeed = it->getAudioStream();
- if (newfeed) {
- g_system->getMixer()->playStream(Audio::Mixer::kSFXSoundType, 0, newfeed);
- return 1;
- }
- }
- return 0;
-}
-
-#define DELAY (1000000 / SFX_TICKS_PER_SEC)
-
-void SfxState::sfx_init(ResourceManager *resMan, int flags, SciVersion soundVersion) {
- _songlib._lib = 0;
- _song = NULL;
- _flags = flags;
-
- _player = NULL;
-
- if (flags & SFX_STATE_FLAG_NOSOUND) {
- warning("[SFX] Sound disabled");
- return;
- }
-
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Initialising: flags=%x\n", flags);
-#endif
-
- /*-------------------*/
- /* Initialise player */
- /*-------------------*/
-
- if (!resMan) {
- warning("[SFX] Warning: No resource manager present, cannot initialise player");
- return;
- }
-
- _player = new SfxPlayer(soundVersion);
-
- if (!_player) {
- warning("[SFX] No song player found");
- return;
- }
-
- if (_player->init(resMan, DELAY / 1000)) {
- warning("[SFX] Song player reported error, disabled");
- delete _player;
- _player = NULL;
- }
-
- _resMan = resMan;
-}
-
-void SfxState::sfx_exit() {
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Uninitialising\n");
-#endif
-
- delete _player;
- _player = 0;
-
- g_system->getMixer()->stopAll();
-
- _songlib.freeSounds();
-}
-
-void SfxState::sfx_suspend(bool suspend) {
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Suspending? = %d\n", suspend);
-#endif
- if (suspend && (!_suspended)) {
- /* suspend */
-
- freezeTime();
- if (_player)
- _player->pause();
- /* Suspend song player */
-
- } else if (!suspend && (_suspended)) {
- /* unsuspend */
-
- thawTime();
- if (_player)
- _player->resume();
-
- /* Unsuspend song player */
- }
-
- _suspended = suspend;
-}
-
-int SfxState::sfx_poll(SongHandle *handle, int *cue) {
- if (!_song)
- return 0; /* No milk today */
-
- *handle = _song->_handle;
-
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Polling any (%08lx)\n", *handle);
-#endif
- return sfx_poll_specific(*handle, cue);
-}
-
-int SfxState::sfx_poll_specific(SongHandle handle, int *cue) {
- const Audio::Timestamp ctime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC);
- Song *song = _song;
-
- while (song && song->_handle != handle)
- song = song->_nextPlaying;
-
- if (!song)
- return 0; /* Song not playing */
-
- debugC(2, kDebugLevelSound, "[SFX:CUE] Polled song %08lx ", handle);
-
- while (1) {
- if (song->_wakeupTime.frameDiff(ctime) > 0)
- return 0; /* Patience, young hacker! */
-
- byte buf[8];
- int result = songit_next(&(song->_it), buf, cue, IT_READER_MASK_ALL);
-
- switch (result) {
-
- case SI_FINISHED:
- setSongStatus(song, SOUND_STATUS_STOPPED);
- update();
- /* ...fall through... */
- case SI_LOOP:
- case SI_RELATIVE_CUE:
- case SI_ABSOLUTE_CUE:
- if (result == SI_FINISHED)
- debugC(2, kDebugLevelSound, " => finished");
- else {
- if (result == SI_LOOP)
- debugC(2, kDebugLevelSound, " => Loop: %d (0x%x)", *cue, *cue);
- else
- debugC(2, kDebugLevelSound, " => Cue: %d (0x%x)", *cue, *cue);
-
- }
- return result;
-
- default:
- if (result > 0)
- song->_wakeupTime = song->_wakeupTime.addFrames(result);
-
- /* Delay */
- break;
- }
- }
-
-}
-
-
-/*****************/
-/* Song basics */
-/*****************/
-
-void SfxState::sfx_add_song(SongIterator *it, int priority, SongHandle handle, int number) {
- Song *song = _songlib.findSong(handle);
-
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Adding song: %08lx at %d, it=%p\n", handle, priority, it);
-#endif
- if (!it) {
- error("[SFX] Attempt to add empty song with handle %08lx", handle);
- return;
- }
-
- it->init();
-
- /* If we're already playing this, stop it */
- /* Tell player to shut up */
-// _dump_songs(this);
-
- if (_player)
- _player->iterator_message(SongIterator::Message(handle, SIMSG_STOP));
-
- if (song) {
- setSongStatus( song, SOUND_STATUS_STOPPED);
-
- fprintf(stderr, "Overwriting old song (%08lx) ...\n", handle);
- if (song->_status == SOUND_STATUS_PLAYING || song->_status == SOUND_STATUS_SUSPENDED) {
- delete it;
- error("Unexpected (error): Song %ld still playing/suspended (%d)",
- handle, song->_status);
- return;
- } else {
- _songlib.removeSong(handle); /* No duplicates */
- }
-
- }
-
- song = new Song(handle, it, priority);
- song->_resourceNum = number;
- song->_hold = 0;
- song->_loops = 0;
- song->_wakeupTime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC);
- _songlib.addSong(song);
- _song = NULL; /* As above */
- update();
-
- return;
-}
-
-void SfxState::sfx_remove_song(SongHandle handle) {
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Removing song: %08lx\n", handle);
-#endif
- if (_song && _song->_handle == handle)
- _song = NULL;
-
- _songlib.removeSong(handle);
- update();
-}
-
-
-
-/**********************/
-/* Song modifications */
-/**********************/
-
-#define ASSERT_SONG(s) if (!(s)) { warning("Looking up song handle %08lx failed in %s, L%d", handle, __FILE__, __LINE__); return; }
-
-void SfxState::sfx_song_set_status(SongHandle handle, int status) {
- Song *song = _songlib.findSong(handle);
- ASSERT_SONG(song);
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Setting song status to %d"
- " (0:stop, 1:play, 2:susp, 3:wait): %08lx\n", status, handle);
-#endif
-
- setSongStatus(song, status);
-
- update();
-}
-
-void SfxState::sfx_song_set_fade(SongHandle handle, fade_params_t *params) {
-#ifdef DEBUG_SONG_API
- static const char *stopmsg[] = {"??? Should not happen", "Do not stop afterwards", "Stop afterwards"};
-#endif
- Song *song = _songlib.findSong(handle);
-
- ASSERT_SONG(song);
-
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Setting fade params of %08lx to "
- "final volume %d in steps of %d per %d ticks. %s.",
- handle, fade->final_volume, fade->step_size, fade->ticks_per_step,
- stopmsg[fade->action]);
-#endif
-
- SIMSG_SEND_FADE(song->_it, params);
-
- update();
-}
-
-void SfxState::sfx_song_renice(SongHandle handle, int priority) {
- Song *song = _songlib.findSong(handle);
- ASSERT_SONG(song);
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Renicing song %08lx to %d\n",
- handle, priority);
-#endif
-
- song->_priority = priority;
-
- update();
-}
-
-void SfxState::sfx_song_set_loops(SongHandle handle, int loops) {
- Song *song = _songlib.findSong(handle);
- SongIterator::Message msg = SongIterator::Message(handle, SIMSG_SET_LOOPS(loops));
- ASSERT_SONG(song);
-
- song->_loops = loops;
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Setting loops on %08lx to %d\n",
- handle, loops);
-#endif
- songit_handle_message(&(song->_it), msg);
-
- if (_player/* && _player->send_iterator_message*/)
- /* FIXME: The above should be optional! */
- _player->iterator_message(msg);
-}
-
-void SfxState::sfx_song_set_hold(SongHandle handle, int hold) {
- Song *song = _songlib.findSong(handle);
- SongIterator::Message msg = SongIterator::Message(handle, SIMSG_SET_HOLD(hold));
- ASSERT_SONG(song);
-
- song->_hold = hold;
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Setting hold on %08lx to %d\n",
- handle, hold);
-#endif
- songit_handle_message(&(song->_it), msg);
-
- if (_player/* && _player->send_iterator_message*/)
- /* FIXME: The above should be optional! */
- _player->iterator_message(msg);
-}
-
-/* Different from the one in iterator.c */
-static const int MIDI_cmdlen[16] = {0, 0, 0, 0, 0, 0, 0, 0,
- 3, 3, 0, 3, 2, 0, 3, 0
- };
-
-static const SongHandle midi_send_base = 0xffff0000;
-
-Common::Error SfxState::sfx_send_midi(SongHandle handle, int channel,
- int command, int arg1, int arg2) {
- byte buffer[5];
-
- /* Yes, in that order. SCI channel mutes are actually done via
- a counting semaphore. 0 means to decrement the counter, 1
- to increment it. */
- static const char *channel_state[] = {"ON", "OFF"};
-
- if (command == 0xb0 &&
- arg1 == SCI_MIDI_CHANNEL_MUTE) {
- warning("TODO: channel mute (channel %d %s)", channel, channel_state[arg2]);
- /* We need to have a GET_PLAYMASK interface to use
- here. SET_PLAYMASK we've got.
- */
- return Common::kNoError;
- }
-
- buffer[0] = channel | command; /* No channel remapping yet */
-
- switch (command) {
- case 0x80 :
- case 0x90 :
- case 0xb0 :
- buffer[1] = arg1 & 0xff;
- buffer[2] = arg2 & 0xff;
- break;
- case 0xc0 :
- buffer[1] = arg1 & 0xff;
- break;
- case 0xe0 :
- buffer[1] = (arg1 & 0x7f) | 0x80;
- buffer[2] = (arg1 & 0xff00) >> 7;
- break;
- default:
- warning("Unexpected explicit MIDI command %02x", command);
- return Common::kUnknownError;
- }
-
- if (_player)
- _player->tell_synth(MIDI_cmdlen[command >> 4], buffer);
- return Common::kNoError;
-}
-
-int SfxState::sfx_getVolume() {
- return _player->getVolume();
-}
-
-void SfxState::sfx_setVolume(int volume) {
- _player->setVolume(volume);
-}
-
-void SfxState::sfx_all_stop() {
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] All stop\n");
-#endif
-
- _songlib.freeSounds();
- update();
-}
-
-} // End of namespace Sci
-
-#endif // USE_OLD_MUSIC_FUNCTIONS
diff --git a/engines/sci/sound/iterator/core.h b/engines/sci/sound/iterator/core.h
deleted file mode 100644
index a44fe2ecae..0000000000
--- a/engines/sci/sound/iterator/core.h
+++ /dev/null
@@ -1,209 +0,0 @@
-/* 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$
- *
- */
-
-/* Sound engine */
-#ifndef SCI_SFX_CORE_H
-#define SCI_SFX_CORE_H
-
-#include "common/error.h"
-
-#include "sci/sci.h" // for USE_OLD_MUSIC_FUNCTIONS
-
-#ifdef USE_OLD_MUSIC_FUNCTIONS
-#include "sci/sound/iterator/songlib.h"
-#include "sci/resource.h"
-
-namespace Sci {
-
-class SfxPlayer;
-class SongIterator;
-struct fade_params_t;
-
-#define SFX_TICKS_PER_SEC 60 /* MIDI ticks per second */
-
-
-#define SFX_STATE_FLAG_MULTIPLAY (1 << 0) /* More than one song playable
-** simultaneously ? */
-#define SFX_STATE_FLAG_NOSOUND (1 << 1) /* Completely disable sound playing */
-
-class SfxState {
-private:
- SfxPlayer *_player;
-
-public: // FIXME, make private
- SongIterator *_it; /**< The song iterator at the heart of things */
- uint _flags; /**< SFX_STATE_FLAG_* */
- SongLibrary _songlib; /**< Song library */
- Song *_song; /**< Active song, or start of active song chain */
- bool _suspended; /**< Whether we are suspended */
- ResourceManager *_resMan;
-
-public:
- SfxState();
- ~SfxState();
-
- /***********/
- /* General */
- /***********/
-
- /* Initializes the sound engine
- ** Parameters: (ResourceManager *) resMan: Resource manager for initialization
- ** (int) flags: SFX_STATE_FLAG_*
- */
- void sfx_init(ResourceManager *resMan, int flags, SciVersion soundVersion);
-
- /** Deinitializes the sound subsystem. */
- void sfx_exit();
-
- /* Suspends/unsuspends the sound sybsystem
- ** Parameters: (int) suspend: Whether to suspend (non-null) or to unsuspend
- */
- void sfx_suspend(bool suspend);
-
- /* Polls the sound server for cues etc.
- ** Returns : (int) 0 if the cue queue is empty, SI_LOOP, SI_CUE, or SI_FINISHED otherwise
- ** (SongHandle) *handle: The affected handle
- ** (int) *cue: The sound cue number (if SI_CUE), or the loop number (if SI_LOOP)
- */
- int sfx_poll(SongHandle *handle, int *cue);
-
- /* Polls the sound server for cues etc.
- ** Parameters: (SongHandle) handle: The handle to poll
- ** Returns : (int) 0 if the cue queue is empty, SI_LOOP, SI_CUE, or SI_FINISHED otherwise
- ** (int) *cue: The sound cue number (if SI_CUE), or the loop number (if SI_LOOP)
- */
- int sfx_poll_specific(SongHandle handle, int *cue);
-
- /* Determines the current global volume settings
- ** Returns : (int) The global volume, between 0 (silent) and 127 (max. volume)
- */
- int sfx_getVolume();
-
- /* Determines the current global volume settings
- ** Parameters: (int) volume: The new global volume, between 0 and 127 (see above)
- */
- void sfx_setVolume(int volume);
-
- /* Stops all songs currently playing, purges song library
- */
- void sfx_all_stop();
-
-
- /*****************/
- /* Song basics */
- /*****************/
-
- /* Adds a song to the internal sound library
- ** Parameters: (SongIterator *) it: The iterator describing the song
- ** (int) priority: Initial song priority (higher <-> more important)
- ** (SongHandle) handle: The handle to associate with the song
- */
- void sfx_add_song(SongIterator *it, int priority, SongHandle handle, int resnum);
-
-
- /* Deletes a song and its associated song iterator from the song queue
- ** Parameters: (SongHandle) handle: The song to remove
- */
- void sfx_remove_song(SongHandle handle);
-
-
- /**********************/
- /* Song modifications */
- /**********************/
-
-
- /* Sets the song status, i.e. whether it is playing, suspended, or stopped.
- ** Parameters: (SongHandle) handle: Handle of the song to modify
- ** (int) status: The song status the song should assume
- ** WAITING and PLAYING are set implicitly and essentially describe the same state
- ** as far as this function is concerned.
- */
- void sfx_song_set_status(SongHandle handle, int status);
-
- /* Sets the new song priority
- ** Parameters: (SongHandle) handle: The handle to modify
- ** (int) priority: The priority to set
- */
- void sfx_song_renice(SongHandle handle, int priority);
-
- /* Sets the number of loops for the specified song
- ** Parameters: (SongHandle) handle: The song handle to reference
- ** (int) loops: Number of loops to set
- */
- void sfx_song_set_loops(SongHandle handle, int loops);
-
- /* Sets the number of loops for the specified song
- ** Parameters: (SongHandle) handle: The song handle to reference
- ** (int) hold: Number of loops to setn
- */
- void sfx_song_set_hold(SongHandle handle, int hold);
-
- /* Instructs a song to be faded out
- ** Parameters: (SongHandle) handle: The song handle to reference
- ** (fade_params_t *) fade_setup: The precise fade-out configuration to use
- */
- void sfx_song_set_fade(SongHandle handle, fade_params_t *fade_setup);
-
-
- // Previously undocumented:
- Common::Error sfx_send_midi(SongHandle handle, int channel,
- int command, int arg1, int arg2);
-
- // misc
-
- /**
- * Determines the polyphony of the player in use.
- * @return Number of voices the active player can emit
- */
- int sfx_get_player_polyphony();
-
- /**
- * Tells the player to stop its internal iterator.
- */
- void sfx_reset_player();
-
- /**
- * Pass a raw MIDI event to the synth of the player.
- * @param argc Length of buffer holding the midi event
- * @param argv The buffer itself
- */
- void sfx_player_tell_synth(int buf_nr, byte *buf);
-
-protected:
- void freezeTime();
- void thawTime();
-
- bool isPlaying(Song *song);
- void setSongStatus(Song *song, int status);
- void updateSingleSong();
- void updateMultiSong();
- void update();
-};
-
-} // End of namespace Sci
-
-#endif // USE_OLD_MUSIC_FUNCTIONS
-
-#endif // SCI_SFX_CORE_H
diff --git a/engines/sci/sound/iterator/iterator.cpp b/engines/sci/sound/iterator/iterator.cpp
deleted file mode 100644
index 5d9d63e5af..0000000000
--- a/engines/sci/sound/iterator/iterator.cpp
+++ /dev/null
@@ -1,1686 +0,0 @@
-/* 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$
- *
- */
-
-/* Song iterators */
-
-#include "common/util.h"
-
-#include "sci/sci.h"
-#ifdef USE_OLD_MUSIC_FUNCTIONS
-
-#include "sci/sound/iterator/iterator_internal.h"
-#include "sci/engine/state.h" // for sfx_player_tell_synth :/
-#include "sci/sound/iterator/core.h" // for sfx_player_tell_synth
-
-#include "sound/audiostream.h"
-#include "sound/mixer.h"
-#include "sound/decoders/raw.h"
-
-namespace Sci {
-
-
-static const int MIDI_cmdlen[16] = {0, 0, 0, 0, 0, 0, 0, 0,
- 2, 2, 2, 2, 1, 1, 2, 0
- };
-
-/*#define DEBUG_DECODING*/
-/*#define DEBUG_VERBOSE*/
-
-/** Find first set bit in bits and return its index. Returns 0 if bits is 0. */
-static int sci_ffs(int bits) {
- if (!bits)
- return 0;
-
- int retval = 1;
-
- while (!(bits & 1)) {
- retval++;
- bits >>= 1;
- }
-
- return retval;
-}
-
-static void print_tabs_id(int nr, songit_id_t id) {
- while (nr-- > 0)
- fprintf(stderr, "\t");
-
- fprintf(stderr, "[%08lx] ", id);
-}
-
-BaseSongIterator::BaseSongIterator(byte *data, uint size, songit_id_t id)
- : _data(data, size) {
- ID = id;
-}
-
-/************************************/
-/*-- SCI0 iterator implementation --*/
-/************************************/
-
-#define SCI0_MIDI_OFFSET 33
-#define SCI0_END_OF_SONG 0xfc /* proprietary MIDI command */
-
-#define SCI0_PCM_SAMPLE_RATE_OFFSET 0x0e
-#define SCI0_PCM_SIZE_OFFSET 0x20
-#define SCI0_PCM_DATA_OFFSET 0x2c
-
-#define CHECK_FOR_END_ABSOLUTE(offset) \
- if (offset > _data.size()) { \
- warning("Reached end of song without terminator (%x/%x) at %d", offset, _data.size(), __LINE__); \
- return SI_FINISHED; \
- }
-
-#define CHECK_FOR_END(offset_augment) \
- if ((channel->offset + (offset_augment)) > channel->end) { \
- channel->state = SI_STATE_FINISHED; \
- warning("Reached end of track %d without terminator (%x+%x/%x) at %d", channel->id, channel->offset, offset_augment, channel->end, __LINE__); \
- return SI_FINISHED; \
- }
-
-
-static int _parse_ticks(byte *data, int *offset_p, int size) {
- int ticks = 0;
- int tempticks;
- int offset = 0;
-
- do {
- tempticks = data[offset++];
- ticks += (tempticks == SCI_MIDI_TIME_EXPANSION_PREFIX) ?
- SCI_MIDI_TIME_EXPANSION_LENGTH : tempticks;
- } while (tempticks == SCI_MIDI_TIME_EXPANSION_PREFIX
- && offset < size);
-
- if (offset_p)
- *offset_p = offset;
-
- return ticks;
-}
-
-
-static int _sci0_get_pcm_data(Sci0SongIterator *self, int *rate, int *xoffset, uint *xsize);
-
-
-#define PARSE_FLAG_LOOPS_UNLIMITED (1 << 0) /* Unlimited # of loops? */
-#define PARSE_FLAG_PARAMETRIC_CUE (1 << 1) /* Assume that cues take an additional "cue value" argument */
-/* This implements a difference between SCI0 and SCI1 cues. */
-
-void SongIteratorChannel::init(int id_, int offset_, int end_) {
- playmask = PLAYMASK_NONE; /* Disable all channels */
- id = id_;
- state = SI_STATE_DELTA_TIME;
- loop_timepos = 0;
- total_timepos = 0;
- timepos_increment = 0;
- delay = 0; /* Only used for more than one channel */
- last_cmd = 0xfe;
-
- offset = loop_offset = initial_offset = offset_;
- end = end_;
-}
-
-void SongIteratorChannel::resetSynthChannels() {
- byte buf[5];
-
- // FIXME: Evil hack
- SfxState &sound = g_sci->getEngineState()->_sound;
-
- for (int i = 0; i < MIDI_CHANNELS; i++) {
- if (playmask & (1 << i)) {
- buf[0] = 0xe0 | i; /* Pitch bend */
- buf[1] = 0x80; /* Wheel center */
- buf[2] = 0x40;
- sound.sfx_player_tell_synth(3, buf);
-
- buf[0] = 0xb0 | i; // Set control
- buf[1] = 0x40; // Hold pedal
- buf[2] = 0x00; // Off
- sound.sfx_player_tell_synth(3, buf);
- /* TODO: Reset other controls? */
- }
- }
-}
-
-int BaseSongIterator::parseMidiCommand(byte *buf, int *result, SongIteratorChannel *channel, int flags) {
- byte cmd;
- int paramsleft;
- int midi_op;
- int midi_channel;
-
- channel->state = SI_STATE_DELTA_TIME;
-
- cmd = _data[channel->offset++];
-
- if (!(cmd & 0x80)) {
- /* 'Running status' mode */
- channel->offset--;
- cmd = channel->last_cmd;
- }
-
- if (cmd == 0xfe) {
- warning("song iterator subsystem: Corrupted sound resource detected.");
- return SI_FINISHED;
- }
-
- midi_op = cmd >> 4;
- midi_channel = cmd & 0xf;
- paramsleft = MIDI_cmdlen[midi_op];
-
-#if 0
- if (1) {
- fprintf(stderr, "[IT]: off=%x, cmd=%02x, takes %d args ",
- channel->offset - 1, cmd, paramsleft);
- fprintf(stderr, "[%02x %02x <%02x> %02x %02x %02x]\n",
- _data[channel->offset-3],
- _data[channel->offset-2],
- _data[channel->offset-1],
- _data[channel->offset],
- _data[channel->offset+1],
- _data[channel->offset+2]);
- }
-#endif
-
- buf[0] = cmd;
-
-
- CHECK_FOR_END(paramsleft);
- memcpy(buf + 1, _data.begin() + channel->offset, paramsleft);
- *result = 1 + paramsleft;
-
- channel->offset += paramsleft;
-
- channel->last_cmd = cmd;
-
- /* Are we supposed to play this channel? */
- if (
- /* First, exclude "global" properties-- such as cues-- from consideration */
- (midi_op < 0xf
- && !(cmd == SCI_MIDI_SET_SIGNAL)
- && !(SCI_MIDI_CONTROLLER(cmd)
- && buf[1] == SCI_MIDI_CUMULATIVE_CUE))
-
- /* Next, check if the channel is allowed */
- && (!((1 << midi_channel) & channel->playmask)))
- return /* Execute next command */
- nextCommand(buf, result);
-
-
- if (cmd == SCI_MIDI_EOT) {
- /* End of track? */
- channel->resetSynthChannels();
- if (_loops > 1) {
- /* If allowed, decrement the number of loops */
- if (!(flags & PARSE_FLAG_LOOPS_UNLIMITED))
- *result = --_loops;
-
-#ifdef DEBUG_DECODING
- fprintf(stderr, "%s L%d: (%p):%d Looping ", __FILE__, __LINE__, this, channel->id);
- if (flags & PARSE_FLAG_LOOPS_UNLIMITED)
- fprintf(stderr, "(indef.)");
- else
- fprintf(stderr, "(%d)", _loops);
- fprintf(stderr, " %x -> %x\n",
- channel->offset, channel->loop_offset);
-#endif
- channel->offset = channel->loop_offset;
- channel->state = SI_STATE_DELTA_TIME;
- channel->total_timepos = channel->loop_timepos;
- channel->last_cmd = 0xfe;
- debugC(2, kDebugLevelSound, "Looping song iterator %08lx.", ID);
- return SI_LOOP;
- } else {
- channel->state = SI_STATE_FINISHED;
- return SI_FINISHED;
- }
-
- } else if (cmd == SCI_MIDI_SET_SIGNAL) {
- if (buf[1] == SCI_MIDI_SET_SIGNAL_LOOP) {
- channel->loop_offset = channel->offset;
- channel->loop_timepos = channel->total_timepos;
-
- return /* Execute next command */
- nextCommand(buf, result);
- } else {
- /* Used to be conditional <= 127 */
- *result = buf[1]; /* Absolute cue */
- return SI_ABSOLUTE_CUE;
- }
- } else if (SCI_MIDI_CONTROLLER(cmd)) {
- switch (buf[1]) {
-
- case SCI_MIDI_CUMULATIVE_CUE:
- if (flags & PARSE_FLAG_PARAMETRIC_CUE)
- _ccc += buf[2];
- else { /* No parameter to CC */
- _ccc++;
- /* channel->offset--; */
- }
- *result = _ccc;
- return SI_RELATIVE_CUE;
-
- case SCI_MIDI_RESET_ON_SUSPEND:
- _resetflag = buf[2];
- break;
-
- case SCI_MIDI_SET_POLYPHONY:
- _polyphony[midi_channel] = buf[2];
-
-#if 0
- {
- Sci1SongIterator *self1 = (Sci1SongIterator *)this;
- int i;
- int voices = 0;
- for (i = 0; i < self1->_numChannels; i++) {
- voices += _polyphony[i];
- }
-
- printf("SET_POLYPHONY(%d, %d) for a total of %d voices\n", midi_channel, buf[2], voices);
- printf("[iterator] DEBUG: Polyphony = [ ");
- for (i = 0; i < self1->_numChannels; i++)
- printf("%d ", _polyphony[i]);
- printf("]\n");
- printf("[iterator] DEBUG: Importance = [ ");
- printf("]\n");
- }
-#endif
- break;
-
- case SCI_MIDI_SET_REVERB:
- break;
-
- case SCI_MIDI_CHANNEL_MUTE:
- warning("CHANNEL_MUTE(%d, %d)", midi_channel, buf[2]);
- break;
-
- case SCI_MIDI_HOLD: {
- // Safe cast: This controller is only used in SCI1
- Sci1SongIterator *self1 = (Sci1SongIterator *)this;
-
- if (buf[2] == self1->_hold) {
- channel->offset = channel->initial_offset;
- channel->state = SI_STATE_COMMAND;
- channel->total_timepos = 0;
-
- self1->_numLoopedChannels = self1->_numActiveChannels - 1;
-
- // FIXME:
- // This implementation of hold breaks getting out of the
- // limo when visiting the airport near the start of LSL5.
- // It seems like all channels should be reset here somehow,
- // but not sure how.
- // Forcing all channel offsets to 0 seems to fix the hang,
- // but somehow slows the exit sequence down to take 20 seconds
- // instead of about 3.
-
- return SI_LOOP;
- }
-
- break;
- }
- case 0x04: /* UNKNOWN NYI (happens in LSL2 gameshow) */
- case 0x46: /* UNKNOWN NYI (happens in LSL3 binoculars) */
- case 0x61: /* UNKNOWN NYI (special for AdLib? Iceman) */
- case 0x73: /* UNKNOWN NYI (happens in Hoyle) */
- case 0xd1: /* UNKNOWN NYI (happens in KQ4 when riding the unicorn) */
- return /* Execute next command */
- nextCommand(buf, result);
-
- case 0x01: /* modulation */
- case 0x07: /* volume */
- case 0x0a: /* panpot */
- case 0x0b: /* expression */
- case 0x40: /* hold */
- case 0x79: /* reset all */
- /* No special treatment neccessary */
- break;
-
- }
- return 0;
-
- } else {
-#if 0
- /* Perform remapping, if neccessary */
- if (cmd != SCI_MIDI_SET_SIGNAL
- && cmd < 0xf0) { /* Not a generic command */
- int chan = cmd & 0xf;
- int op = cmd & 0xf0;
-
- chan = channel_remap[chan];
- buf[0] = chan | op;
- }
-#endif
-
- /* Process as normal MIDI operation */
- return 0;
- }
-}
-
-int BaseSongIterator::processMidi(byte *buf, int *result,
- SongIteratorChannel *channel, int flags) {
- CHECK_FOR_END(0);
-
- switch (channel->state) {
-
- case SI_STATE_PCM: {
- if (_data[channel->offset] == 0
- && _data[channel->offset + 1] == SCI_MIDI_EOT)
- /* Fake one extra tick to trick the interpreter into not killing the song iterator right away */
- channel->state = SI_STATE_PCM_MAGIC_DELTA;
- else
- channel->state = SI_STATE_DELTA_TIME;
- return SI_PCM;
- }
-
- case SI_STATE_PCM_MAGIC_DELTA: {
- int rate;
- int offset;
- uint size;
- int delay;
- if (_sci0_get_pcm_data((Sci0SongIterator *)this, &rate, &offset, &size))
- return SI_FINISHED; /* 'tis broken */
- channel->state = SI_STATE_FINISHED;
- delay = (size * 50 + rate - 1) / rate; /* number of ticks to completion*/
-
- debugC(2, kDebugLevelSound, "delaying %d ticks", delay);
- return delay;
- }
-
- case SI_STATE_UNINITIALISED:
- warning("Attempt to read command from uninitialized iterator");
- init();
- return nextCommand(buf, result);
-
- case SI_STATE_FINISHED:
- return SI_FINISHED;
-
- case SI_STATE_DELTA_TIME: {
- int offset;
- int ticks = _parse_ticks(_data.begin() + channel->offset,
- &offset,
- _data.size() - channel->offset);
-
- channel->offset += offset;
- channel->delay += ticks;
- channel->timepos_increment = ticks;
-
- CHECK_FOR_END(0);
-
- channel->state = SI_STATE_COMMAND;
-
- if (ticks)
- return ticks;
- }
-
- /* continute otherwise... */
-
- case SI_STATE_COMMAND: {
- int retval;
- channel->total_timepos += channel->timepos_increment;
- channel->timepos_increment = 0;
-
- retval = parseMidiCommand(buf, result, channel, flags);
-
- if (retval == SI_FINISHED) {
- if (_numActiveChannels)
- --(_numActiveChannels);
-#ifdef DEBUG_DECODING
- fprintf(stderr, "%s L%d: (%p):%d Finished channel, %d channels left\n",
- __FILE__, __LINE__, this, channel->id,
- _numActiveChannels);
-#endif
- /* If we still have channels left... */
- if (_numActiveChannels) {
- return nextCommand(buf, result);
- }
-
- /* Otherwise, we have reached the end */
- _loops = 0;
- }
-
- return retval;
- }
-
- default:
- error("Invalid iterator state %d", channel->state);
- return SI_FINISHED;
- }
-}
-
-int Sci0SongIterator::nextCommand(byte *buf, int *result) {
- return processMidi(buf, result, &_channel, PARSE_FLAG_PARAMETRIC_CUE);
-}
-
-static int _sci0_header_magic_p(byte *data, int offset, int size) {
- if (offset + 0x10 > size)
- return 0;
- return (data[offset] == 0x1a)
- && (data[offset + 1] == 0x00)
- && (data[offset + 2] == 0x01)
- && (data[offset + 3] == 0x00);
-}
-
-
-static int _sci0_get_pcm_data(Sci0SongIterator *self,
- int *rate, int *xoffset, uint *xsize) {
- int tries = 2;
- bool found_it = false;
- byte *pcm_data;
- int size;
- uint offset = SCI0_MIDI_OFFSET;
-
- if (self->_data[0] != 2)
- return 1;
- /* No such luck */
-
- while ((tries--) && (offset < self->_data.size()) && (!found_it)) {
- // Search through the garbage manually
- // FIXME: Replace offset by an iterator
- Common::Array<byte>::iterator iter = Common::find(self->_data.begin() + offset, self->_data.end(), SCI0_END_OF_SONG);
-
- if (iter == self->_data.end()) {
- warning("Playing unterminated song");
- return 1;
- }
-
- // add one to move it past the END_OF_SONG marker
- iter++;
- offset = iter - self->_data.begin(); // FIXME
-
-
- if (_sci0_header_magic_p(self->_data.begin(), offset, self->_data.size()))
- found_it = true;
- }
-
- if (!found_it) {
- warning("Song indicates presence of PCM, but"
- " none found (finally at offset %04x)", offset);
-
- return 1;
- }
-
- pcm_data = self->_data.begin() + offset;
-
- size = READ_LE_UINT16(pcm_data + SCI0_PCM_SIZE_OFFSET);
-
- /* Two of the format parameters are fixed by design: */
- *rate = READ_LE_UINT16(pcm_data + SCI0_PCM_SAMPLE_RATE_OFFSET);
-
- if (offset + SCI0_PCM_DATA_OFFSET + size != self->_data.size()) {
- int d = offset + SCI0_PCM_DATA_OFFSET + size - self->_data.size();
-
- warning("PCM advertizes %d bytes of data, but %d"
- " bytes are trailing in the resource",
- size, self->_data.size() - (offset + SCI0_PCM_DATA_OFFSET));
-
- if (d > 0)
- size -= d; /* Fix this */
- }
-
- *xoffset = offset;
- *xsize = size;
-
- return 0;
-}
-
-static Audio::AudioStream *makeStream(byte *data, int size, int rate) {
- debugC(2, kDebugLevelSound, "Playing PCM data of size %d, rate %d", size, rate);
-
- // Duplicate the data
- byte *sound = (byte *)malloc(size);
- memcpy(sound, data, size);
-
- // Convert stream format flags
- int flags = Audio::FLAG_UNSIGNED;
- return Audio::makeRawStream(sound, size, rate, flags);
-}
-
-Audio::AudioStream *Sci0SongIterator::getAudioStream() {
- int rate;
- int offset;
- uint size;
- if (_sci0_get_pcm_data(this, &rate, &offset, &size))
- return NULL;
-
- _channel.state = SI_STATE_FINISHED; /* Don't play both PCM and music */
-
- return makeStream(_data.begin() + offset + SCI0_PCM_DATA_OFFSET, size, rate);
-}
-
-SongIterator *Sci0SongIterator::handleMessage(Message msg) {
- if (msg._class == _SIMSG_BASE) {
- switch (msg._type) {
-
- case _SIMSG_BASEMSG_PRINT:
- print_tabs_id(msg._arg.i, ID);
- debugC(2, kDebugLevelSound, "SCI0: dev=%d, active-chan=%d, size=%d, loops=%d",
- _deviceId, _numActiveChannels, _data.size(), _loops);
- break;
-
- case _SIMSG_BASEMSG_SET_LOOPS:
- _loops = msg._arg.i;
- break;
-
- case _SIMSG_BASEMSG_STOP: {
- songit_id_t sought_id = msg.ID;
-
- if (sought_id == ID)
- _channel.state = SI_STATE_FINISHED;
- break;
- }
-
- case _SIMSG_BASEMSG_SET_PLAYMASK: {
- int i;
- _deviceId = msg._arg.i;
-
- /* Set all but the rhytm channel mask bits */
- _channel.playmask &= ~(1 << MIDI_RHYTHM_CHANNEL);
-
- for (i = 0; i < MIDI_CHANNELS; i++)
- if (_data[2 + (i << 1)] & _deviceId
- && i != MIDI_RHYTHM_CHANNEL)
- _channel.playmask |= (1 << i);
- }
- break;
-
- case _SIMSG_BASEMSG_SET_RHYTHM:
- _channel.playmask &= ~(1 << MIDI_RHYTHM_CHANNEL);
- if (msg._arg.i)
- _channel.playmask |= (1 << MIDI_RHYTHM_CHANNEL);
- break;
-
- case _SIMSG_BASEMSG_SET_FADE: {
- fade_params_t *fp = (fade_params_t *) msg._arg.p;
- fade.action = fp->action;
- fade.final_volume = fp->final_volume;
- fade.ticks_per_step = fp->ticks_per_step;
- fade.step_size = fp->step_size;
- break;
- }
-
- default:
- return NULL;
- }
-
- return this;
- }
- return NULL;
-}
-
-int Sci0SongIterator::getTimepos() {
- return _channel.total_timepos;
-}
-
-Sci0SongIterator::Sci0SongIterator(byte *data, uint size, songit_id_t id)
- : BaseSongIterator(data, size, id) {
- channel_mask = 0xffff; // Allocate all channels by default
- _channel.state = SI_STATE_UNINITIALISED;
-
- for (int i = 0; i < MIDI_CHANNELS; i++)
- _polyphony[i] = data[1 + (i << 1)];
-
- init();
-}
-
-void Sci0SongIterator::init() {
- fade.action = FADE_ACTION_NONE;
- _resetflag = 0;
- _loops = 0;
- priority = 0;
-
- _ccc = 0; /* Reset cumulative cue counter */
- _numActiveChannels = 1;
- _channel.init(0, SCI0_MIDI_OFFSET, _data.size());
- _channel.resetSynthChannels();
-
- if (_data[0] == 2) /* Do we have an embedded PCM? */
- _channel.state = SI_STATE_PCM;
-}
-
-SongIterator *Sci0SongIterator::clone(int delta) {
- Sci0SongIterator *newit = new Sci0SongIterator(*this);
- return newit;
-}
-
-
-/***************************/
-/*-- SCI1 song iterators --*/
-/***************************/
-
-int Sci1SongIterator::initSample(const int offset) {
- Sci1Sample sample;
- int rate;
- int length;
- int begin;
- int end;
-
- CHECK_FOR_END_ABSOLUTE((uint)offset + 10);
- if (_data[offset + 1] != 0)
- warning("[iterator-1] In sample at offset 0x04x: Byte #1 is %02x instead of zero",
- _data[offset + 1]);
-
- rate = (int16)READ_LE_UINT16(_data.begin() + offset + 2);
- length = READ_LE_UINT16(_data.begin() + offset + 4);
- begin = (int16)READ_LE_UINT16(_data.begin() + offset + 6);
- end = (int16)READ_LE_UINT16(_data.begin() + offset + 8);
-
- CHECK_FOR_END_ABSOLUTE((uint)(offset + 10 + length));
-
- sample.delta = begin;
- sample.size = length;
- sample._data = _data.begin() + offset + 10;
-
-#ifdef DEBUG_VERBOSE
- fprintf(stderr, "[SAMPLE] %x/%x/%x/%x l=%x\n",
- offset + 10, begin, end, _data.size(), length);
-#endif
-
- sample.rate = rate;
-
- sample.announced = false;
-
- /* Insert into the sample list at the right spot, keeping it sorted by delta */
- Common::List<Sci1Sample>::iterator seeker = _samples.begin();
- while (seeker != _samples.end() && seeker->delta < begin)
- ++seeker;
- _samples.insert(seeker, sample);
-
- return 0; /* Everything's fine */
-}
-
-int Sci1SongIterator::initSong() {
- int last_time;
- uint offset = 0;
- _numChannels = 0;
- _samples.clear();
-// _deviceId = 0x0c;
-
- if (_data[offset] == 0xf0) {
- priority = _data[offset + 1];
-
- offset += 8;
- }
-
- while (_data[offset] != 0xff
- && _data[offset] != _deviceId) {
- offset++;
- CHECK_FOR_END_ABSOLUTE(offset + 1);
- while (_data[offset] != 0xff) {
- CHECK_FOR_END_ABSOLUTE(offset + 7);
- offset += 6;
- }
- offset++;
- }
-
- if (_data[offset] == 0xff) {
- warning("[iterator] Song does not support hardware 0x%02x", _deviceId);
- return 1;
- }
-
- offset++;
-
- while (_data[offset] != 0xff) { /* End of list? */
- uint track_offset;
- int end;
- offset += 2;
-
- CHECK_FOR_END_ABSOLUTE(offset + 4);
-
- track_offset = READ_LE_UINT16(_data.begin() + offset);
- end = READ_LE_UINT16(_data.begin() + offset + 2);
-
- CHECK_FOR_END_ABSOLUTE(track_offset - 1);
-
- if (_data[track_offset] == 0xfe) {
- if (initSample(track_offset))
- return 1; /* Error */
- } else {
- /* Regular MIDI channel */
- if (_numChannels >= MIDI_CHANNELS) {
- warning("[iterator] Song has more than %d channels, cutting them off",
- MIDI_CHANNELS);
- break; /* Scan for remaining samples */
- } else {
- int channel_nr = _data[track_offset] & 0xf;
- SongIteratorChannel &channel = _channels[_numChannels++];
-
- /*
- if (_data[track_offset] & 0xf0)
- printf("Channel %d has mapping bits %02x\n",
- channel_nr, _data[track_offset] & 0xf0);
- */
-
- // Add 2 to skip over header bytes */
- channel.init(channel_nr, track_offset + 2, track_offset + end);
- channel.resetSynthChannels();
-
- _polyphony[_numChannels - 1] = _data[channel.offset - 1] & 15;
-
- channel.playmask = ~0; /* Enable all */
- channel_mask |= (1 << channel_nr);
-
- CHECK_FOR_END_ABSOLUTE(offset + end);
- }
- }
- offset += 4;
- CHECK_FOR_END_ABSOLUTE(offset);
- }
-
- /* Now ensure that sample deltas are relative to the previous sample */
- last_time = 0;
- _numActiveChannels = _numChannels;
- _numLoopedChannels = 0;
-
- for (Common::List<Sci1Sample>::iterator seeker = _samples.begin();
- seeker != _samples.end(); ++seeker) {
- int prev_last_time = last_time;
- //printf("[iterator] Detected sample: %d Hz, %d bytes at time %d\n",
- // seeker->format.rate, seeker->size, seeker->delta);
- last_time = seeker->delta;
- seeker->delta -= prev_last_time;
- }
-
- return 0; /* Success */
-}
-
-int Sci1SongIterator::getSmallestDelta() const {
- int d = -1;
- for (int i = 0; i < _numChannels; i++)
- if (_channels[i].state == SI_STATE_COMMAND
- && (d == -1 || _channels[i].delay < d))
- d = _channels[i].delay;
-
- if (!_samples.empty() && _samples.begin()->delta < d)
- return _samples.begin()->delta;
- else
- return d;
-}
-
-void Sci1SongIterator::updateDelta(int delta) {
- if (!_samples.empty())
- _samples.begin()->delta -= delta;
-
- for (int i = 0; i < _numChannels; i++)
- if (_channels[i].state == SI_STATE_COMMAND)
- _channels[i].delay -= delta;
-}
-
-bool Sci1SongIterator::noDeltaTime() const {
- for (int i = 0; i < _numChannels; i++)
- if (_channels[i].state == SI_STATE_DELTA_TIME)
- return false;
- return true;
-}
-
-#define COMMAND_INDEX_NONE -1
-#define COMMAND_INDEX_PCM -2
-
-int Sci1SongIterator::getCommandIndex() const {
- /* Determine the channel # of the next active event, or -1 */
- int i;
- int base_delay = 0x7ffffff;
- int best_chan = COMMAND_INDEX_NONE;
-
- for (i = 0; i < _numChannels; i++)
- if ((_channels[i].state != SI_STATE_PENDING)
- && (_channels[i].state != SI_STATE_FINISHED)) {
-
- if ((_channels[i].state == SI_STATE_DELTA_TIME)
- && (_channels[i].delay == 0))
- return i;
- /* First, read all unknown delta times */
-
- if (_channels[i].delay < base_delay) {
- best_chan = i;
- base_delay = _channels[i].delay;
- }
- }
-
- if (!_samples.empty() && base_delay >= _samples.begin()->delta)
- return COMMAND_INDEX_PCM;
-
- return best_chan;
-}
-
-
-Audio::AudioStream *Sci1SongIterator::getAudioStream() {
- Common::List<Sci1Sample>::iterator sample = _samples.begin();
- if (sample != _samples.end() && sample->delta <= 0) {
- Audio::AudioStream *feed = makeStream(sample->_data, sample->size, sample->rate);
- _samples.erase(sample);
-
- return feed;
- } else
- return NULL;
-}
-
-int Sci1SongIterator::nextCommand(byte *buf, int *result) {
-
- if (!_initialised) {
- //printf("[iterator] DEBUG: Initialising for %d\n", _deviceId);
- _initialised = true;
- if (initSong())
- return SI_FINISHED;
- }
-
-
- if (_delayRemaining) {
- int delay = _delayRemaining;
- _delayRemaining = 0;
- return delay;
- }
-
- int retval = 0;
- do { /* All delays must be processed separately */
- int chan = getCommandIndex();
-
- if (chan == COMMAND_INDEX_NONE) {
- return SI_FINISHED;
- }
-
- if (chan == COMMAND_INDEX_PCM) {
-
- if (_samples.begin()->announced) {
- /* Already announced; let's discard it */
- Audio::AudioStream *feed = getAudioStream();
- delete feed;
- } else {
- int delay = _samples.begin()->delta;
-
- if (delay) {
- updateDelta(delay);
- return delay;
- }
- /* otherwise we're touching a PCM */
- _samples.begin()->announced = true;
- return SI_PCM;
- }
- } else { /* Not a PCM */
-
- retval = processMidi(buf, result,
- &(_channels[chan]),
- PARSE_FLAG_LOOPS_UNLIMITED);
-
- if (retval == SI_LOOP) {
- _numLoopedChannels++;
- _channels[chan].state = SI_STATE_PENDING;
- _channels[chan].delay = 0;
-
- if (_numLoopedChannels == _numActiveChannels) {
- int i;
-
- /* Everyone's ready: Let's loop */
- for (i = 0; i < _numChannels; i++)
- if (_channels[i].state == SI_STATE_PENDING)
- _channels[i].state = SI_STATE_DELTA_TIME;
-
- _numLoopedChannels = 0;
- return SI_LOOP;
- }
- } else if (retval == SI_FINISHED) {
-#ifdef DEBUG
- fprintf(stderr, "FINISHED some channel\n");
-#endif
- } else if (retval > 0) {
- int sd ;
- sd = getSmallestDelta();
-
- if (noDeltaTime() && sd) {
- /* No other channel is ready */
- updateDelta(sd);
-
- /* Only from here do we return delta times */
- return sd;
- }
- }
-
- } /* Not a PCM */
-
- } while (retval > 0);
-
- return retval;
-}
-
-SongIterator *Sci1SongIterator::handleMessage(Message msg) {
- if (msg._class == _SIMSG_BASE) { /* May extend this in the future */
- switch (msg._type) {
-
- case _SIMSG_BASEMSG_PRINT: {
- int playmask = 0;
- int i;
-
- for (i = 0; i < _numChannels; i++)
- playmask |= _channels[i].playmask;
-
- print_tabs_id(msg._arg.i, ID);
- debugC(2, kDebugLevelSound, "SCI1: chan-nr=%d, playmask=%04x",
- _numChannels, playmask);
- }
- break;
-
- case _SIMSG_BASEMSG_STOP: {
- songit_id_t sought_id = msg.ID;
- int i;
-
- if (sought_id == ID) {
- ID = 0;
-
- for (i = 0; i < _numChannels; i++)
- _channels[i].state = SI_STATE_FINISHED;
- }
- break;
- }
-
- case _SIMSG_BASEMSG_SET_PLAYMASK:
- if (msg.ID == ID) {
- channel_mask = 0;
-
- _deviceId = msg._arg.i;
-
- if (_initialised) {
- int i;
- int toffset = -1;
-
- for (i = 0; i < _numChannels; i++)
- if (_channels[i].state != SI_STATE_FINISHED
- && _channels[i].total_timepos > toffset) {
- toffset = _channels[i].total_timepos
- + _channels[i].timepos_increment
- - _channels[i].delay;
- }
-
- /* Find an active channel so that we can
- ** get the correct time offset */
-
- initSong();
-
- toffset -= _delayRemaining;
- _delayRemaining = 0;
-
- if (toffset > 0)
- return new_fast_forward_iterator(this, toffset);
- } else {
- initSong();
- _initialised = true;
- }
-
- break;
-
- }
-
- case _SIMSG_BASEMSG_SET_LOOPS:
- if (msg.ID == ID)
- _loops = (msg._arg.i > 32767) ? 99 : 0;
- /* 99 is arbitrary, but we can't use '1' because of
- ** the way we're testing in the decoding section. */
- break;
-
- case _SIMSG_BASEMSG_SET_HOLD:
- _hold = msg._arg.i;
- break;
- case _SIMSG_BASEMSG_SET_RHYTHM:
- /* Ignore */
- break;
-
- case _SIMSG_BASEMSG_SET_FADE: {
- fade_params_t *fp = (fade_params_t *) msg._arg.p;
- fade.action = fp->action;
- fade.final_volume = fp->final_volume;
- fade.ticks_per_step = fp->ticks_per_step;
- fade.step_size = fp->step_size;
- break;
- }
-
- default:
- warning("Unsupported command %d to SCI1 iterator", msg._type);
- }
- return this;
- }
- return NULL;
-}
-
-Sci1SongIterator::Sci1SongIterator(byte *data, uint size, songit_id_t id)
- : BaseSongIterator(data, size, id) {
- channel_mask = 0; // Defer channel allocation
-
- for (int i = 0; i < MIDI_CHANNELS; i++)
- _polyphony[i] = 0; // Unknown
-
- init();
-}
-
-void Sci1SongIterator::init() {
- fade.action = FADE_ACTION_NONE;
- _resetflag = 0;
- _loops = 0;
- priority = 0;
-
- _ccc = 0;
- _deviceId = 0x00; // Default to Sound Blaster/AdLib for purposes of cue computation
- _numChannels = 0;
- _initialised = false;
- _delayRemaining = 0;
- _loops = 0;
- _hold = 0;
- memset(_polyphony, 0, sizeof(_polyphony));
-}
-
-Sci1SongIterator::~Sci1SongIterator() {
-}
-
-
-SongIterator *Sci1SongIterator::clone(int delta) {
- Sci1SongIterator *newit = new Sci1SongIterator(*this);
- newit->_delayRemaining = delta;
- return newit;
-}
-
-int Sci1SongIterator::getTimepos() {
- int max = 0;
- int i;
-
- for (i = 0; i < _numChannels; i++)
- if (_channels[i].total_timepos > max)
- max = _channels[i].total_timepos;
-
- return max;
-}
-
-/**
- * A song iterator with the purpose of sending notes-off channel commands.
- */
-class CleanupSongIterator : public SongIterator {
-public:
- CleanupSongIterator(uint channels) {
- channel_mask = channels;
- ID = 17;
- }
-
- int nextCommand(byte *buf, int *result);
- Audio::AudioStream *getAudioStream() { return NULL; }
- SongIterator *handleMessage(Message msg);
- int getTimepos() { return 0; }
- SongIterator *clone(int delta) { return new CleanupSongIterator(*this); }
-};
-
-SongIterator *CleanupSongIterator::handleMessage(Message msg) {
- if (msg._class == _SIMSG_BASEMSG_PRINT && msg._type == _SIMSG_BASEMSG_PRINT) {
- print_tabs_id(msg._arg.i, ID);
- debugC(2, kDebugLevelSound, "CLEANUP");
- }
-
- return NULL;
-}
-
-int CleanupSongIterator::nextCommand(byte *buf, int *result) {
- /* Task: Return channel-notes-off for each channel */
- if (channel_mask) {
- int bs = sci_ffs(channel_mask) - 1;
-
- channel_mask &= ~(1 << bs);
- buf[0] = 0xb0 | bs; /* Controller */
- buf[1] = SCI_MIDI_CHANNEL_NOTES_OFF;
- buf[2] = 0; /* Hmm... */
- *result = 3;
- return 0;
- } else
- return SI_FINISHED;
-}
-
-/**********************/
-/*-- Timer iterator --*/
-/**********************/
-int TimerSongIterator::nextCommand(byte *buf, int *result) {
- if (_delta) {
- int d = _delta;
- _delta = 0;
- return d;
- }
- return SI_FINISHED;
-}
-
-SongIterator *new_timer_iterator(int delta) {
- return new TimerSongIterator(delta);
-}
-
-/**********************************/
-/*-- Fast-forward song iterator --*/
-/**********************************/
-
-int FastForwardSongIterator::nextCommand(byte *buf, int *result) {
- if (_delta <= 0)
- return SI_MORPH; /* Did our duty */
-
- while (1) {
- int rv = _delegate->nextCommand(buf, result);
-
- if (rv > 0) {
- /* Subtract from the delta we want to wait */
- _delta -= rv;
-
- /* Done */
- if (_delta < 0)
- return -_delta;
- }
-
- if (rv <= 0)
- return rv;
- }
-}
-
-Audio::AudioStream *FastForwardSongIterator::getAudioStream() {
- return _delegate->getAudioStream();
-}
-
-SongIterator *FastForwardSongIterator::handleMessage(Message msg) {
- if (msg._class == _SIMSG_PLASTICWRAP) {
- assert(msg._type == _SIMSG_PLASTICWRAP_ACK_MORPH);
-
- if (_delta <= 0) {
- SongIterator *it = _delegate;
- delete this;
- return it;
- }
-
- warning("[ff-iterator] Morphing without need");
- return this;
- }
-
- if (msg._class == _SIMSG_BASE && msg._type == _SIMSG_BASEMSG_PRINT) {
- print_tabs_id(msg._arg.i, ID);
- debugC(2, kDebugLevelSound, "FASTFORWARD:");
- msg._arg.i++;
- }
-
- // And continue with the delegate
- songit_handle_message(&_delegate, msg);
-
- return NULL;
-}
-
-
-int FastForwardSongIterator::getTimepos() {
- return _delegate->getTimepos();
-}
-
-FastForwardSongIterator::FastForwardSongIterator(SongIterator *capsit, int delta)
- : _delegate(capsit), _delta(delta) {
-
- channel_mask = capsit->channel_mask;
-}
-
-SongIterator *FastForwardSongIterator::clone(int delta) {
- FastForwardSongIterator *newit = new FastForwardSongIterator(*this);
- newit->_delegate = _delegate->clone(delta);
- return newit;
-}
-
-SongIterator *new_fast_forward_iterator(SongIterator *capsit, int delta) {
- if (capsit == NULL)
- return NULL;
-
- FastForwardSongIterator *it = new FastForwardSongIterator(capsit, delta);
- return it;
-}
-
-
-/********************/
-/*-- Tee iterator --*/
-/********************/
-
-
-static void song_iterator_add_death_listener(SongIterator *it, TeeSongIterator *client) {
- for (int i = 0; i < SONGIT_MAX_LISTENERS; ++i) {
- if (it->_deathListeners[i] == 0) {
- it->_deathListeners[i] = client;
- return;
- }
- }
- error("FATAL: Too many death listeners for song iterator");
-}
-
-static void song_iterator_remove_death_listener(SongIterator *it, TeeSongIterator *client) {
- for (int i = 0; i < SONGIT_MAX_LISTENERS; ++i) {
- if (it->_deathListeners[i] == client) {
- it->_deathListeners[i] = 0;
- return;
- }
- }
-}
-
-static void song_iterator_transfer_death_listeners(SongIterator *it, SongIterator *it_from) {
- for (int i = 0; i < SONGIT_MAX_LISTENERS; ++i) {
- if (it_from->_deathListeners[i])
- song_iterator_add_death_listener(it, it_from->_deathListeners[i]);
- it_from->_deathListeners[i] = 0;
- }
-}
-
-static void songit_tee_death_notification(TeeSongIterator *self, SongIterator *corpse) {
- if (corpse == self->_children[TEE_LEFT].it) {
- self->_status &= ~TEE_LEFT_ACTIVE;
- self->_children[TEE_LEFT].it = NULL;
- } else if (corpse == self->_children[TEE_RIGHT].it) {
- self->_status &= ~TEE_RIGHT_ACTIVE;
- self->_children[TEE_RIGHT].it = NULL;
- } else {
- error("songit_tee_death_notification() failed: Breakpoint in %s, line %d", __FILE__, __LINE__);
- }
-}
-
-TeeSongIterator::TeeSongIterator(SongIterator *left, SongIterator *right) {
- int i;
- int firstfree = 1; /* First free channel */
- int incomplete_map = 0;
-
- _readyToMorph = false;
- _status = TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE;
-
- _children[TEE_LEFT].it = left;
- _children[TEE_RIGHT].it = right;
-
- /* Default to lhs channels */
- channel_mask = left->channel_mask;
- for (i = 0; i < 16; i++)
- if (channel_mask & (1 << i) & right->channel_mask
- && (i != MIDI_RHYTHM_CHANNEL) /* Share rhythm */) { /*conflict*/
- while ((firstfree == MIDI_RHYTHM_CHANNEL)
- /* Either if it's the rhythm channel or if it's taken */
- || (firstfree < MIDI_CHANNELS
- && ((1 << firstfree) & channel_mask)))
- ++firstfree;
-
- if (firstfree == MIDI_CHANNELS) {
- incomplete_map = 1;
- //warning("[songit-tee <%08lx,%08lx>] Could not remap right channel #%d: Out of channels",
- // left->ID, right->ID, i);
- } else {
- _children[TEE_RIGHT].it->channel_remap[i] = firstfree;
-
- channel_mask |= (1 << firstfree);
- }
- }
-#ifdef DEBUG_TEE_ITERATOR
- if (incomplete_map) {
- int c;
- fprintf(stderr, "[songit-tee <%08lx,%08lx>] Channels:"
- " %04x <- %04x | %04x\n",
- left->ID, right->ID,
- channel_mask,
- left->channel_mask, right->channel_mask);
- for (c = 0 ; c < 2; c++)
- for (i = 0 ; i < 16; i++)
- fprintf(stderr, " map [%d][%d] -> %d\n",
- c, i, _children[c].it->channel_remap[i]);
- }
-#endif
-
-
- song_iterator_add_death_listener(left, this);
- song_iterator_add_death_listener(right, this);
-}
-
-TeeSongIterator::~TeeSongIterator() {
- // When we die, remove any listeners from our children
- if (_children[TEE_LEFT].it) {
- song_iterator_remove_death_listener(_children[TEE_LEFT].it, this);
- }
-
- if (_children[TEE_RIGHT].it) {
- song_iterator_remove_death_listener(_children[TEE_RIGHT].it, this);
- }
-}
-
-
-int TeeSongIterator::nextCommand(byte *buf, int *result) {
- static const int ready_masks[2] = {TEE_LEFT_READY, TEE_RIGHT_READY};
- static const int active_masks[2] = {TEE_LEFT_ACTIVE, TEE_RIGHT_ACTIVE};
- static const int pcm_masks[2] = {TEE_LEFT_PCM, TEE_RIGHT_PCM};
- int i;
- int retid;
-
-#ifdef DEBUG_TEE_ITERATOR
- fprintf(stderr, "[Tee] %02x\n", _status);
-#endif
-
- if (!(_status & (TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE)))
- /* None is active? */
- return SI_FINISHED;
-
- if (_readyToMorph)
- return SI_MORPH;
-
- if ((_status & (TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE))
- != (TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE)) {
- /* Not all are is active? */
- int which = 0;
-#ifdef DEBUG_TEE_ITERATOR
- fprintf(stderr, "\tRequesting transformation...\n");
-#endif
- if (_status & TEE_LEFT_ACTIVE)
- which = TEE_LEFT;
- else if (_status & TEE_RIGHT_ACTIVE)
- which = TEE_RIGHT;
- memcpy(buf, _children[which].buf, sizeof(buf));
- *result = _children[which].result;
- _readyToMorph = true;
- return _children[which].retval;
- }
-
- /* First, check for unreported PCMs */
- for (i = TEE_LEFT; i <= TEE_RIGHT; i++)
- if ((_status & (ready_masks[i] | pcm_masks[i]))
- == (ready_masks[i] | pcm_masks[i])) {
- _status &= ~ready_masks[i];
- return SI_PCM;
- }
-
- for (i = TEE_LEFT; i <= TEE_RIGHT; i++)
- if (!(_status & ready_masks[i])) {
-
- /* Buffers aren't ready yet */
- _children[i].retval =
- songit_next(&(_children[i].it),
- _children[i].buf,
- &(_children[i].result),
- IT_READER_MASK_ALL
- | IT_READER_MAY_FREE
- | IT_READER_MAY_CLEAN);
-
- _status |= ready_masks[i];
-#ifdef DEBUG_TEE_ITERATOR
- fprintf(stderr, "\t Must check %d: %d\n", i, _children[i].retval);
-#endif
-
- if (_children[i].retval == SI_ABSOLUTE_CUE ||
- _children[i].retval == SI_RELATIVE_CUE)
- return _children[i].retval;
- if (_children[i].retval == SI_FINISHED) {
- _status &= ~active_masks[i];
- /* Recurse to complete */
-#ifdef DEBUG_TEE_ITERATOR
- fprintf(stderr, "\t Child %d signalled completion, recursing w/ status %02x\n", i, _status);
-#endif
- return nextCommand(buf, result);
- } else if (_children[i].retval == SI_PCM) {
- _status |= pcm_masks[i];
- _status &= ~ready_masks[i];
- return SI_PCM;
- }
- }
-
-
- /* We've already handled PCM, MORPH and FINISHED, CUEs & LOOP remain */
-
- retid = TEE_LEFT;
- if ((_children[TEE_LEFT].retval > 0)
- /* Asked to delay */
- && (_children[TEE_RIGHT].retval <= _children[TEE_LEFT].retval))
- /* Is not delaying or not delaying as much */
- retid = TEE_RIGHT;
-
-#ifdef DEBUG_TEE_ITERATOR
- fprintf(stderr, "\tl:%d / r:%d / chose %d\n",
- _children[TEE_LEFT].retval, _children[TEE_RIGHT].retval, retid);
-#endif
-
- /* Adjust delta times */
- if (_children[retid].retval > 0
- && _children[1-retid].retval > 0) {
- if (_children[1-retid].retval
- == _children[retid].retval)
- /* If both _children wait the same amount of time,
- ** we have to re-fetch commands from both */
- _status &= ~ready_masks[1-retid];
- else
- /* If they don't, we can/must re-use the other
- ** child's delay time */
- _children[1-retid].retval
- -= _children[retid].retval;
- }
-
- _status &= ~ready_masks[retid];
- memcpy(buf, _children[retid].buf, sizeof(buf));
- *result = _children[retid].result;
-
- return _children[retid].retval;
-}
-
-Audio::AudioStream *TeeSongIterator::getAudioStream() {
- static const int pcm_masks[2] = {TEE_LEFT_PCM, TEE_RIGHT_PCM};
- int i;
-
- for (i = TEE_LEFT; i <= TEE_RIGHT; i++)
- if (_status & pcm_masks[i]) {
- _status &= ~pcm_masks[i];
- return _children[i].it->getAudioStream();
- }
-
- return NULL; // No iterator
-}
-
-SongIterator *TeeSongIterator::handleMessage(Message msg) {
- if (msg._class == _SIMSG_PLASTICWRAP) {
- assert(msg._type == _SIMSG_PLASTICWRAP_ACK_MORPH);
-
- SongIterator *old_it;
- if (!(_status & (TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE))) {
- delete this;
- return NULL;
- } else if (!(_status & TEE_LEFT_ACTIVE)) {
- delete _children[TEE_LEFT].it;
- _children[TEE_LEFT].it = 0;
- old_it = _children[TEE_RIGHT].it;
- song_iterator_remove_death_listener(old_it, this);
- song_iterator_transfer_death_listeners(old_it, this);
- delete this;
- return old_it;
- } else if (!(_status & TEE_RIGHT_ACTIVE)) {
- delete _children[TEE_RIGHT].it;
- _children[TEE_RIGHT].it = 0;
- old_it = _children[TEE_LEFT].it;
- song_iterator_remove_death_listener(old_it, this);
- song_iterator_transfer_death_listeners(old_it, this);
- delete this;
- return old_it;
- }
-
- warning("[tee-iterator] Morphing without need");
- return this;
- }
-
- if (msg._class == _SIMSG_BASE && msg._type == _SIMSG_BASEMSG_PRINT) {
- print_tabs_id(msg._arg.i, ID);
- debugC(2, kDebugLevelSound, "TEE:");
- msg._arg.i++;
- }
-
- // And continue with the children
- if (_children[TEE_LEFT].it)
- songit_handle_message(&(_children[TEE_LEFT].it), msg);
- if (_children[TEE_RIGHT].it)
- songit_handle_message(&(_children[TEE_RIGHT].it), msg);
-
- return NULL;
-}
-
-void TeeSongIterator::init() {
- _status = TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE;
- _children[TEE_LEFT].it->init();
- _children[TEE_RIGHT].it->init();
-}
-
-SongIterator *TeeSongIterator::clone(int delta) {
- TeeSongIterator *newit = new TeeSongIterator(*this);
-
- if (_children[TEE_LEFT].it)
- newit->_children[TEE_LEFT].it = _children[TEE_LEFT].it->clone(delta);
- if (_children[TEE_RIGHT].it)
- newit->_children[TEE_RIGHT].it = _children[TEE_RIGHT].it->clone(delta);
-
- return newit;
-}
-
-
-/*************************************/
-/*-- General purpose functionality --*/
-/*************************************/
-
-int songit_next(SongIterator **it, byte *buf, int *result, int mask) {
- int retval;
-
- if (!*it)
- return SI_FINISHED;
-
- do {
- retval = (*it)->nextCommand(buf, result);
- if (retval == SI_MORPH) {
- debugC(2, kDebugLevelSound, " Morphing %p (stored at %p)", (void *)*it, (void *)it);
- if (!SIMSG_SEND((*it), SIMSG_ACK_MORPH)) {
- error("SI_MORPH failed. Breakpoint in %s, line %d", __FILE__, __LINE__);
- } else
- debugC(2, kDebugLevelSound, "SI_MORPH successful");
- }
-
- if (retval == SI_FINISHED)
- debugC(2, kDebugLevelSound, "[song-iterator] Song finished. mask = %04x, cm=%04x",
- mask, (*it)->channel_mask);
- if (retval == SI_FINISHED
- && (mask & IT_READER_MAY_CLEAN)
- && (*it)->channel_mask) { /* This last test will fail
- ** with a terminated
- ** cleanup iterator */
- int channel_mask = (*it)->channel_mask;
-
- SongIterator *old_it = *it;
- *it = new CleanupSongIterator(channel_mask);
- for(uint i = 0; i < MIDI_CHANNELS; i++)
- (*it)->channel_remap[i] = old_it->channel_remap[i];
- song_iterator_transfer_death_listeners(*it, old_it);
- if (mask & IT_READER_MAY_FREE)
- delete old_it;
- retval = -9999; /* Continue */
- }
- } while (!( /* Until one of the following holds */
- (retval > 0 && (mask & IT_READER_MASK_DELAY))
- || (retval == 0 && (mask & IT_READER_MASK_MIDI))
- || (retval == SI_LOOP && (mask & IT_READER_MASK_LOOP))
- || (retval == SI_ABSOLUTE_CUE &&
- (mask & IT_READER_MASK_CUE))
- || (retval == SI_RELATIVE_CUE &&
- (mask & IT_READER_MASK_CUE))
- || (retval == SI_PCM && (mask & IT_READER_MASK_PCM))
- || (retval == SI_FINISHED)
- ));
-
- if (retval == SI_FINISHED && (mask & IT_READER_MAY_FREE)) {
- delete *it;
- *it = NULL;
- }
-
- return retval;
-}
-
-SongIterator::SongIterator() {
- ID = 0;
- channel_mask = 0;
- fade.action = FADE_ACTION_NONE;
- priority = 0;
- memset(_deathListeners, 0, sizeof(_deathListeners));
-
- // By default, don't remap
- for (uint i = 0; i < 16; i++)
- channel_remap[i] = i;
-}
-
-SongIterator::SongIterator(const SongIterator &si) {
- ID = si.ID;
- channel_mask = si.channel_mask;
- fade = si.fade;
- priority = si.priority;
- memset(_deathListeners, 0, sizeof(_deathListeners));
-
- for (uint i = 0; i < 16; i++)
- channel_remap[i] = si.channel_remap[i];
-}
-
-
-SongIterator::~SongIterator() {
- for (int i = 0; i < SONGIT_MAX_LISTENERS; ++i)
- if (_deathListeners[i])
- songit_tee_death_notification(_deathListeners[i], this);
-}
-
-SongIterator *songit_new(byte *data, uint size, SongIteratorType type, songit_id_t id) {
- BaseSongIterator *it;
-
- if (!data || size < 22) {
- warning("Attempt to instantiate song iterator for null song data");
- return NULL;
- }
-
-
- switch (type) {
- case SCI_SONG_ITERATOR_TYPE_SCI0:
- it = new Sci0SongIterator(data, size, id);
- break;
-
- case SCI_SONG_ITERATOR_TYPE_SCI1:
- it = new Sci1SongIterator(data, size, id);
- break;
-
- default:
- /**-- Invalid/unsupported sound resources --**/
- warning("Attempt to instantiate invalid/unknown song iterator type %d", type);
- return NULL;
- }
-
- return it;
-}
-
-int songit_handle_message(SongIterator **it_reg_p, SongIterator::Message msg) {
- SongIterator *it = *it_reg_p;
- SongIterator *newit;
-
- newit = it->handleMessage(msg);
-
- if (!newit)
- return 0; /* Couldn't handle */
-
- *it_reg_p = newit; /* Might have self-morphed */
- return 1;
-}
-
-SongIterator *sfx_iterator_combine(SongIterator *it1, SongIterator *it2) {
- if (it1 == NULL)
- return it2;
- if (it2 == NULL)
- return it1;
-
- /* Both are non-NULL: */
- return new TeeSongIterator(it1, it2);
-}
-
-} // End of namespace Sci
-
-#endif // USE_OLD_MUSIC_FUNCTIONS
diff --git a/engines/sci/sound/iterator/iterator.h b/engines/sci/sound/iterator/iterator.h
deleted file mode 100644
index e5c8f50702..0000000000
--- a/engines/sci/sound/iterator/iterator.h
+++ /dev/null
@@ -1,326 +0,0 @@
-/* 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$
- *
- */
-
-/* Song iterator declarations */
-
-#ifndef SCI_SFX_SFX_ITERATOR_H
-#define SCI_SFX_SFX_ITERATOR_H
-
-#include "sci/sci.h" // for USE_OLD_MUSIC_FUNCTIONS
-
-#ifdef USE_OLD_MUSIC_FUNCTIONS
-#include "sci/sound/drivers/mididriver.h"
-
-namespace Audio {
- class AudioStream;
-}
-
-namespace Sci {
-
-enum SongIteratorStatus {
- SI_FINISHED = -1, /**< Song finished playing */
- SI_LOOP = -2, /**< Song just looped */
- SI_ABSOLUTE_CUE = -3, /**< Found a song cue (absolute) */
- SI_RELATIVE_CUE = -4, /**< Found a song cue (relative) */
- SI_PCM = -5, /**< Found a PCM */
- SI_IGNORE = -6, /**< This event got edited out by the remapper */
- SI_MORPH = -255 /**< Song iterator requested self-morph. */
-};
-
-#define FADE_ACTION_NONE 0
-#define FADE_ACTION_FADE_AND_STOP 1
-#define FADE_ACTION_FADE_AND_CONT 2
-
-struct fade_params_t {
- int ticks_per_step;
- int final_volume;
- int step_size;
- int action;
-};
-
-/* Helper defs for messages */
-enum {
- _SIMSG_BASE, /* Any base decoder */
- _SIMSG_PLASTICWRAP /* Any "Plastic" (discardable) wrapper decoder */
-};
-
-/* Base messages */
-enum {
- _SIMSG_BASEMSG_SET_LOOPS, /* Set loops */
- _SIMSG_BASEMSG_SET_PLAYMASK, /* Set the current playmask for filtering */
- _SIMSG_BASEMSG_SET_RHYTHM, /* Activate/deactivate rhythm channel */
- _SIMSG_BASEMSG_ACK_MORPH, /* Acknowledge self-morph */
- _SIMSG_BASEMSG_STOP, /* Stop iterator */
- _SIMSG_BASEMSG_PRINT, /* Print self to stderr, after printing param1 tabs */
- _SIMSG_BASEMSG_SET_HOLD, /* Set value of hold parameter to expect */
- _SIMSG_BASEMSG_SET_FADE /* Set fade parameters */
-};
-
-/* "Plastic" (discardable) wrapper messages */
-enum {
- _SIMSG_PLASTICWRAP_ACK_MORPH = _SIMSG_BASEMSG_ACK_MORPH /* Acknowledge self-morph */
-};
-
-/* Messages */
-#define SIMSG_SET_LOOPS(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_LOOPS,(x)
-#define SIMSG_SET_PLAYMASK(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_PLAYMASK,(x)
-#define SIMSG_SET_RHYTHM(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_RHYTHM,(x)
-#define SIMSG_ACK_MORPH _SIMSG_PLASTICWRAP,_SIMSG_PLASTICWRAP_ACK_MORPH,0
-#define SIMSG_STOP _SIMSG_BASE,_SIMSG_BASEMSG_STOP,0
-#define SIMSG_PRINT(indentation) _SIMSG_BASE,_SIMSG_BASEMSG_PRINT,(indentation)
-#define SIMSG_SET_HOLD(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_HOLD,(x)
-
-/* Message transmission macro: Takes song reference, message reference */
-#define SIMSG_SEND(o, m) songit_handle_message(&(o), SongIterator::Message((o)->ID, m))
-#define SIMSG_SEND_FADE(o, m) songit_handle_message(&(o), SongIterator::Message((o)->ID, _SIMSG_BASE, _SIMSG_BASEMSG_SET_FADE, m))
-
-typedef unsigned long songit_id_t;
-
-
-#define SONGIT_MAX_LISTENERS 2
-
-class TeeSongIterator;
-
-class SongIterator {
-public:
- struct Message {
- songit_id_t ID;
- uint _class; /* Type of iterator supposed to receive this */
- uint _type;
- union {
- uint i;
- void *p;
- } _arg;
-
- Message() : ID(0), _class(0xFFFF), _type(0xFFFF) {}
-
- /**
- * Create a song iterator message.
- *
- * @param id: song ID the message is targeted to
- * @param recipient_class: Message recipient class
- * @param type message type
- * @param a argument
- *
- * @note You should only use this with the SIMSG_* macros
- */
- Message(songit_id_t id, int recipient_class, int type, int a)
- : ID(id), _class(recipient_class), _type(type) {
- _arg.i = a;
- }
-
- /**
- * Create a song iterator message, wherein the first parameter is a pointer.
- *
- * @param id: song ID the message is targeted to
- * @param recipient_class: Message recipient class
- * @param type message type
- * @param a argument
- *
- * @note You should only use this with the SIMSG_* macros
- */
- Message(songit_id_t id, int recipient_class, int type, void *a)
- : ID(id), _class(recipient_class), _type(type) {
- _arg.p = a;
- }
- };
-
-public:
- songit_id_t ID;
- uint16 channel_mask; /* Bitmask of all channels this iterator will use */
- fade_params_t fade;
- int priority;
-
- /* Death listeners */
- /* These are not reset during initialisation */
- TeeSongIterator *_deathListeners[SONGIT_MAX_LISTENERS];
-
- /* See songit_* for the constructor and non-virtual member functions */
-
- byte channel_remap[MIDI_CHANNELS]; ///< Remapping for channels
-
-public:
- SongIterator();
- SongIterator(const SongIterator &);
- virtual ~SongIterator();
-
- /**
- * Resets/initializes the sound iterator.
- */
- virtual void init() {}
-
- /**
- * Reads the next MIDI operation _or_ delta time.
- * @param buf The buffer to write to (needs to be able to store at least 4 bytes)
- * @param result Number of bytes written to the buffer
- * (equals the number of bytes that need to be passed
- * to the lower layers) for 0, the cue value for SI_CUE,
- * or the number of loops remaining for SI_LOOP.
- * @return zero if a MIDI operation was written, SI_FINISHED
- * if the song has finished playing, SI_LOOP if looping
- * (after updating the loop variable), SI_CUE if we found
- * a cue, SI_PCM if a PCM was found, or the number of ticks
- * to wait before this function should be called next.
- *
- * @note If SI_PCM is returned, get_pcm() may be used to retrieve the associated
- * PCM, but this must be done before any subsequent calls to next().
- *
- * @todo The actual buffer size should either be specified or passed in, so that
- * we can detect buffer overruns.
- */
- virtual int nextCommand(byte *buf, int *result) = 0;
-
- /**
- Checks for the presence of a pcm sample.
- * @return NULL if no PCM data was found, an AudioStream otherwise.
- */
- virtual Audio::AudioStream *getAudioStream() = 0;
-
- /**
- * Handles a message to the song iterator.
- * @param msg the message to handle
- * @return NULL if the message was not understood,
- * this if the message could be handled, or a new song iterator
- * if the current iterator had to be morphed (but the message could
- * still be handled)
- *
- * @note This function is not supposed to be called directly; use
- * songit_handle_message() instead. It should not recurse, since songit_handle_message()
- * takes care of that and makes sure that its delegate received the message (and
- * was morphed) before self.
- */
- virtual SongIterator *handleMessage(Message msg) = 0;
-
- /**
- * Gets the song position to store in a savegame.
- */
- virtual int getTimepos() = 0;
-
- /**
- * Clone this song iterator.
- * @param delta number of ticks that still need to elapse until the
- * next item should be read from the song iterator
- */
- virtual SongIterator *clone(int delta) = 0;
-
-
-private:
- // Make the assignment operator unreachable, just in case...
- SongIterator& operator=(const SongIterator&);
-};
-
-
-/********************************/
-/*-- Song iterator operations --*/
-/********************************/
-
-enum SongIteratorType {
- SCI_SONG_ITERATOR_TYPE_SCI0 = 0,
- SCI_SONG_ITERATOR_TYPE_SCI1 = 1
-};
-
-#define IT_READER_MASK_MIDI (1 << 0)
-#define IT_READER_MASK_DELAY (1 << 1)
-#define IT_READER_MASK_LOOP (1 << 2)
-#define IT_READER_MASK_CUE (1 << 3)
-#define IT_READER_MASK_PCM (1 << 4)
-#define IT_READER_MAY_FREE (1 << 10) /* Free SI_FINISHED iterators */
-#define IT_READER_MAY_CLEAN (1 << 11)
-/* MAY_CLEAN: May instantiate cleanup iterators
-** (use for players; this closes open channels at the end of a song) */
-
-#define IT_READER_MASK_ALL ( IT_READER_MASK_MIDI \
- | IT_READER_MASK_DELAY \
- | IT_READER_MASK_LOOP \
- | IT_READER_MASK_CUE \
- | IT_READER_MASK_PCM )
-
-/* Convenience wrapper around it->next
-** Parameters: (SongIterator **it) Reference to the iterator to access
-** (byte *) buf: The buffer to write to (needs to be able to
-** store at least 4 bytes)
-** (int) mask: IT_READER_MASK options specifying the events to
-** listen for
-** Returns : (int) zero if a MIDI operation was written, SI_FINISHED
-** if the song has finished playing, SI_LOOP if looping
-** (after updating the loop variable), SI_CUE if we found
-** a cue, SI_PCM if a PCM was found, or the number of ticks
-** to wait before this function should be called next.
-** (int) *result: Number of bytes written to the buffer
-** (equals the number of bytes that need to be passed
-** to the lower layers) for 0, the cue value for SI_CUE,
-** or the number of loops remaining for SI_LOOP.
-*/
-int songit_next(SongIterator **it, byte *buf, int *result, int mask);
-
-/* Constructs a new song iterator object
-** Parameters: (byte *) data: The song data to iterate over
-** (uint) size: Number of bytes in the song
-** (int) type: One of the SCI_SONG_ITERATOR_TYPEs
-** (songit_id_t) id: An ID for addressing the song iterator
-** Returns : (SongIterator *) A newly allocated but uninitialized song
-** iterator, or NULL if 'type' was invalid or unsupported
-*/
-SongIterator *songit_new(byte *data, uint size, SongIteratorType type, songit_id_t id);
-
-/* Constructs a new song timer iterator object
-** Parameters: (int) delta: The delta after which to fire SI_FINISHED
-** Returns : (SongIterator *) A newly allocated but uninitialized song
-** iterator
-*/
-SongIterator *new_timer_iterator(int delta);
-
-/* Handles a message to the song iterator
-** Parameters: (SongIterator **): A reference to the variable storing the song iterator
-** Returns : (int) Non-zero if the message was understood
-** The song iterator may polymorph as result of msg, so a writeable reference is required.
-*/
-int songit_handle_message(SongIterator **it_reg, SongIterator::Message msg);
-
-
-/* Creates a new song iterator which fast-forwards
-** Parameters: (SongIterator *) it: The iterator to wrap
-** (int) delta: The number of ticks to skip
-** Returns : (SongIterator) A newly created song iterator
-** which skips all delta times
-** until 'delta' has been used up
-*/
-SongIterator *new_fast_forward_iterator(SongIterator *it, int delta);
-
-/* Combines two song iterators into one
-** Parameters: (sfx_iterator_t *) it1: One of the two iterators, or NULL
-** (sfx_iterator_t *) it2: The other iterator, or NULL
-** Returns : (sfx_iterator_t *) A combined iterator
-** If a combined iterator is returned, it will be flagged to be allowed to
-** dispose of 'it1' and 'it2', where applicable. This means that this
-** call should be used by song players, but not by the core sound system
-*/
-SongIterator *sfx_iterator_combine(SongIterator *it1, SongIterator *it2);
-
-} // End of namespace Sci
-
-#endif // USE_OLD_MUSIC_FUNCTIONS
-
-#endif // SCI_SFX_SFX_ITERATOR_H
diff --git a/engines/sci/sound/iterator/iterator_internal.h b/engines/sci/sound/iterator/iterator_internal.h
deleted file mode 100644
index 5a0f0d3ec9..0000000000
--- a/engines/sci/sound/iterator/iterator_internal.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/* 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$
- *
- */
-
-#ifndef SCI_SFX_SFX_ITERATOR_INTERNAL
-#define SCI_SFX_SFX_ITERATOR_INTERNAL
-
-#include "sci/sci.h" // for USE_OLD_MUSIC_FUNCTIONS
-
-#ifdef USE_OLD_MUSIC_FUNCTIONS
-#include "sci/sound/iterator/iterator.h"
-#include "sci/sound/drivers/mididriver.h"
-
-#include "common/array.h"
-#include "common/list.h"
-
-namespace Sci {
-
-/* Iterator types */
-
-enum {
- SI_STATE_UNINITIALISED = -1,
- SI_STATE_DELTA_TIME = 0, ///< Now at a delta time
- SI_STATE_COMMAND = 1, ///< Now at a MIDI operation
- SI_STATE_PENDING = 2, ///< Pending for loop
- SI_STATE_FINISHED = 3, ///< End of song
- SI_STATE_PCM = 4, ///< Should report a PCM next (-> DELTA_TIME)
- SI_STATE_PCM_MAGIC_DELTA = 5 ///< Should report a ``magic'' one tick delta time next (goes on to FINISHED)
-};
-
-struct SongIteratorChannel {
-
- int state; ///< State of this song iterator channel
- int offset; ///< Offset into the data chunk */
- int end; ///< Last allowed byte in track */
- int id; ///< Some channel ID */
-
- /**
- * Number of ticks before the specified channel is next used, or
- * CHANNEL_DELAY_MISSING to indicate that the delay has not yet
- * been read.
- */
- int delay;
-
- /* Two additional offsets for recovering: */
- int loop_offset;
- int initial_offset;
-
- int playmask; ///< Active playmask (MIDI channels to play in here) */
- int loop_timepos; ///< Total delay for this channel's loop marker */
- int total_timepos; ///< Number of ticks since the beginning, ignoring loops */
- int timepos_increment; ///< Number of ticks until the next command (to add) */
-
- byte last_cmd; ///< Last operation executed, for running status */
-
-public:
- void init(int id, int offset, int end);
- void resetSynthChannels();
-};
-
-class BaseSongIterator : public SongIterator {
-public:
- int _polyphony[MIDI_CHANNELS]; ///< # of simultaneous notes on each
-
- int _ccc; ///< Cumulative cue counter, for those who need it
- byte _resetflag; ///< for 0x4C -- on DoSound StopSound, do we return to start?
- int _deviceId; ///< ID of the device we generating events for
- int _numActiveChannels; ///< Number of active channels
- Common::Array<byte> _data; ///< Song data
-
- int _loops; ///< Number of loops remaining
-
-public:
- BaseSongIterator(byte *data, uint size, songit_id_t id);
-
-protected:
- int parseMidiCommand(byte *buf, int *result, SongIteratorChannel *channel, int flags);
- int processMidi(byte *buf, int *result, SongIteratorChannel *channel, int flags);
-};
-
-/********************************/
-/*--------- SCI 0 --------------*/
-/********************************/
-
-class Sci0SongIterator : public BaseSongIterator {
-public:
- SongIteratorChannel _channel;
-
-public:
- Sci0SongIterator(byte *data, uint size, songit_id_t id);
-
- int nextCommand(byte *buf, int *result);
- Audio::AudioStream *getAudioStream();
- SongIterator *handleMessage(Message msg);
- void init();
- int getTimepos();
- SongIterator *clone(int delta);
-};
-
-
-/********************************/
-/*--------- SCI 1 --------------*/
-/********************************/
-
-
-struct Sci1Sample {
- /**
- * Time left-- initially, this is 'Sample point 1'.
- * After initialisation, it is 'sample point 1 minus the sample
- * point of the previous sample'
- */
- int delta;
- int size;
- bool announced; /* Announced for download (SI_PCM) */
- int rate;
- byte *_data;
-};
-
-class Sci1SongIterator : public BaseSongIterator {
-public:
- SongIteratorChannel _channels[MIDI_CHANNELS];
-
- /* Invariant: Whenever channels[i].delay == CHANNEL_DELAY_MISSING,
- ** channel_offset[i] points to a delta time object. */
-
- bool _initialised; /**!< Whether the MIDI channel setup has been initialised */
- int _numChannels; /**!< Number of channels actually used */
- Common::List<Sci1Sample> _samples;
- int _numLoopedChannels; /**!< Number of channels that are ready to loop */
-
- int _delayRemaining; /**!< Number of ticks that haven't been polled yet */
- int _hold;
-
-public:
- Sci1SongIterator(byte *data, uint size, songit_id_t id);
- ~Sci1SongIterator();
-
- int nextCommand(byte *buf, int *result);
- Audio::AudioStream *getAudioStream();
- SongIterator *handleMessage(Message msg);
- void init();
- int getTimepos();
- SongIterator *clone(int delta);
-
-private:
- int initSample(const int offset);
- int initSong();
-
- int getSmallestDelta() const;
-
- void updateDelta(int delta);
-
- /** Checks that none of the channels is waiting for its delta to be read */
- bool noDeltaTime() const;
-
- /** Determine the channel # of the next active event, or -1 */
- int getCommandIndex() const;
-};
-
-#define PLAYMASK_NONE 0x0
-
-/***************************/
-/*--------- Timer ---------*/
-/***************************/
-
-/**
- * A song iterator which waits a specified time and then fires
- * SI_FINISHED. Used by DoSound, where audio resources are played (SCI1)
- */
-class TimerSongIterator : public SongIterator {
-protected:
- int _delta; /**!< Remaining time */
-
-public:
- TimerSongIterator(int delta) : _delta(delta) {}
-
- int nextCommand(byte *buf, int *result);
- Audio::AudioStream *getAudioStream() { return NULL; }
- SongIterator *handleMessage(Message msg) { return NULL; }
- int getTimepos() { return 0; }
- SongIterator *clone(int delta) { return new TimerSongIterator(*this); }
-};
-
-/**********************************/
-/*--------- Fast Forward ---------*/
-/**********************************/
-
-/**
- * A song iterator which fast-forwards another iterator.
- * Skips all delta times until a specified 'delta' has been used up.
- */
-class FastForwardSongIterator : public SongIterator {
-protected:
- SongIterator *_delegate;
- int _delta; /**!< Remaining time */
-
-public:
- FastForwardSongIterator(SongIterator *capsit, int delta);
-
- int nextCommand(byte *buf, int *result);
- Audio::AudioStream *getAudioStream();
- SongIterator *handleMessage(Message msg);
- int getTimepos();
- SongIterator *clone(int delta);
-};
-
-
-/**********************************/
-/*--------- Tee iterator ---------*/
-/**********************************/
-
-enum {
- TEE_LEFT = 0,
- TEE_RIGHT = 1,
- TEE_LEFT_ACTIVE = (1<<0),
- TEE_RIGHT_ACTIVE = (1<<1),
- TEE_LEFT_READY = (1<<2), /**!< left result is ready */
- TEE_RIGHT_READY = (1<<3), /**!< right result is ready */
- TEE_LEFT_PCM = (1<<4),
- TEE_RIGHT_PCM = (1<<5)
-};
-
-/**
- * This iterator combines two iterators, returns the next event available from either.
- */
-class TeeSongIterator : public SongIterator {
-public:
- int _status;
-
- bool _readyToMorph; /**!< One of TEE_MORPH_* above */
-
- struct {
- SongIterator *it;
- byte buf[4];
- int result;
- int retval;
- } _children[2];
-
-public:
- TeeSongIterator(SongIterator *left, SongIterator *right);
- ~TeeSongIterator();
-
- int nextCommand(byte *buf, int *result);
- Audio::AudioStream *getAudioStream();
- SongIterator *handleMessage(Message msg);
- void init();
- int getTimepos() { return 0; }
- SongIterator *clone(int delta);
-};
-
-} // End of namespace Sci
-
-#endif // USE_OLD_MUSIC_FUNCTIONS
-
-#endif // SCI_SFX_SFX_ITERATOR_INTERNAL
diff --git a/engines/sci/sound/iterator/songlib.cpp b/engines/sci/sound/iterator/songlib.cpp
deleted file mode 100644
index 8bc2e8f476..0000000000
--- a/engines/sci/sound/iterator/songlib.cpp
+++ /dev/null
@@ -1,189 +0,0 @@
-/* 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/sci.h" // for USE_OLD_MUSIC_FUNCTIONS
-
-#ifdef USE_OLD_MUSIC_FUNCTIONS
-#include "sci/sound/iterator/core.h"
-#include "sci/sound/iterator/iterator.h"
-
-namespace Sci {
-
-#define debug_stream stderr
-
-Song::Song() : _wakeupTime(0, SFX_TICKS_PER_SEC) {
- _handle = 0;
- _resourceNum = 0;
- _priority = 0;
- _status = SOUND_STATUS_STOPPED;
-
- _restoreBehavior = RESTORE_BEHAVIOR_CONTINUE;
- _restoreTime = 0;
-
- _loops = 0;
- _hold = 0;
-
- _it = 0;
- _delay = 0;
-
- _next = NULL;
- _nextPlaying = NULL;
- _nextStopping = NULL;
-}
-
-Song::Song(SongHandle handle, SongIterator *it, int priority) : _wakeupTime(0, SFX_TICKS_PER_SEC) {
- _handle = handle;
- _resourceNum = 0;
- _priority = priority;
- _status = SOUND_STATUS_STOPPED;
-
- _restoreBehavior = RESTORE_BEHAVIOR_CONTINUE;
- _restoreTime = 0;
-
- _loops = 0;
- _hold = 0;
-
- _it = it;
- _delay = 0;
-
- _next = NULL;
- _nextPlaying = NULL;
- _nextStopping = NULL;
-}
-
-void SongLibrary::addSong(Song *song) {
- Song **seeker = NULL;
- int pri = song->_priority;
-
- if (NULL == song) {
- warning("addSong(): NULL passed for song");
- return;
- }
-
- seeker = &_lib;
- while (*seeker && ((*seeker)->_priority > pri))
- seeker = &((*seeker)->_next);
-
- song->_next = *seeker;
- *seeker = song;
-}
-
-void SongLibrary::freeSounds() {
- Song *next = _lib;
- while (next) {
- Song *song = next;
- delete song->_it;
- song->_it = NULL;
- next = song->_next;
- delete song;
- }
- _lib = NULL;
-}
-
-
-Song *SongLibrary::findSong(SongHandle handle) {
- Song *seeker = _lib;
-
- while (seeker) {
- if (seeker->_handle == handle)
- break;
- seeker = seeker->_next;
- }
-
- return seeker;
-}
-
-Song *SongLibrary::findNextActive(Song *other) {
- Song *seeker = other ? other->_next : _lib;
-
- while (seeker) {
- if ((seeker->_status == SOUND_STATUS_WAITING) ||
- (seeker->_status == SOUND_STATUS_PLAYING))
- break;
- seeker = seeker->_next;
- }
-
- /* Only return songs that have equal priority */
- if (other && seeker && other->_priority > seeker->_priority)
- return NULL;
-
- return seeker;
-}
-
-Song *SongLibrary::findFirstActive() {
- return findNextActive(NULL);
-}
-
-int SongLibrary::removeSong(SongHandle handle) {
- int retval;
- Song *goner = _lib;
-
- if (!goner)
- return -1;
-
- if (goner->_handle == handle)
- _lib = goner->_next;
-
- else {
- while ((goner->_next) && (goner->_next->_handle != handle))
- goner = goner->_next;
-
- if (goner->_next) { /* Found him? */
- Song *oldnext = goner->_next;
-
- goner->_next = goner->_next->_next;
- goner = oldnext;
- } else return -1; /* No. */
- }
-
- retval = goner->_status;
-
- delete goner->_it;
- delete goner;
-
- return retval;
-}
-
-int SongLibrary::countSongs() {
- Song *seeker = _lib;
- int retval = 0;
-
- while (seeker) {
- retval++;
- seeker = seeker->_next;
- }
-
- return retval;
-}
-
-void SongLibrary::setSongRestoreBehavior(SongHandle handle, RESTORE_BEHAVIOR action) {
- Song *seeker = findSong(handle);
-
- seeker->_restoreBehavior = action;
-}
-
-} // End of namespace Sci
-
-#endif // USE_OLD_MUSIC_FUNCTIONS
diff --git a/engines/sci/sound/iterator/songlib.h b/engines/sci/sound/iterator/songlib.h
deleted file mode 100644
index acb704edaa..0000000000
--- a/engines/sci/sound/iterator/songlib.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/* 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$
- *
- */
-
-/* Song library */
-
-#ifndef SCI_SFX_SFX_SONGLIB_H
-#define SCI_SFX_SFX_SONGLIB_H
-
-#include "common/scummsys.h"
-#include "sound/timestamp.h"
-
-#include "sci/sci.h" // for USE_OLD_MUSIC_FUNCTIONS
-#ifdef USE_OLD_MUSIC_FUNCTIONS
-
-namespace Sci {
-
-class SongIterator;
-
-#define SOUND_STATUS_STOPPED 0
-#define SOUND_STATUS_PLAYING 1
-#define SOUND_STATUS_SUSPENDED 2
-/* suspended: only if ordered from kernel space */
-#define SOUND_STATUS_WAITING 3
-/* "waiting" means "tagged for playing, but not active right now" */
-
-typedef unsigned long SongHandle;
-
-enum RESTORE_BEHAVIOR {
- RESTORE_BEHAVIOR_CONTINUE, /* restart a song when restored from
- a saved game */
- RESTORE_BEHAVIOR_RESTART /* continue it from where it was */
-};
-
-class Song {
-public:
- SongHandle _handle;
- int _resourceNum; /**<! Resource number */
- int _priority; /**!< Song priority (more important if priority is higher) */
- int _status; /* See above */
-
- int _restoreBehavior;
- int _restoreTime;
-
- /* Grabbed from the sound iterator, for save/restore purposes */
- int _loops;
- int _hold;
-
- SongIterator *_it;
- int _delay; /**!< Delay before accessing the iterator, in ticks */
-
- Audio::Timestamp _wakeupTime; /**!< Timestamp indicating the next MIDI event */
-
- Song *_next; /**!< Next song or NULL if this is the last one */
-
- /**
- * Next playing song. Used by the core song system.
- */
- Song *_nextPlaying;
-
- /**
- * Next song pending stopping. Used exclusively by the core song system's
- * _update_multi_song()
- */
- Song *_nextStopping;
-
-public:
-
- Song();
-
- /**
- * Initializes a new song.
- * @param handle the sound handle
- * @param it the song
- * @param priority the song's priority
- * @return a freshly allocated song
- */
- Song(SongHandle handle, SongIterator *it, int priority);
-};
-
-
-class SongLibrary {
-public:
- Song *_lib;
-
-public:
- SongLibrary() : _lib(0) {}
-
- /** Frees a song library. */
- void freeSounds();
-
- /**
- * Adds a song to a song library.
- * @param song song to add
- */
- void addSong(Song *song);
-
- /**
- * Looks up the song with the specified handle.
- * @param handle sound handle to look for
- * @return the song or NULL if it wasn't found
- */
- Song *findSong(SongHandle handle);
-
- /**
- * Finds the first song playing with the highest priority.
- * @return the song that should be played next, or NULL if there is none
- */
- Song *findFirstActive();
-
- /**
- * Finds the next song playing with the highest priority.
- *
- * The functions 'findFirstActive' and 'findNextActive'
- * allow to iterate over all songs that satisfy the requirement of
- * being 'playable'.
- *
- * @param song a song previously returned from the song library
- * @return the next song to play relative to 'song', or NULL if none are left
- */
- Song *findNextActive(Song *song);
-
- /**
- * Removes a song from the library.
- * @param handle handle of the song to remove
- * @return the status of the song that was removed
- */
- int removeSong(SongHandle handle);
-
- /**
- * Counts the number of songs in a song library.
- * @return the number of songs
- */
- int countSongs();
-
- /**
- * Determines what should be done with the song "handle" when restoring
- * it from a saved game.
- * @param handle sound handle being restored
- * @param action desired action
- */
- void setSongRestoreBehavior(SongHandle handle,
- RESTORE_BEHAVIOR action);
-};
-
-} // End of namespace Sci
-
-#endif // USE_OLD_MUSIC_FUNCTIONS
-
-#endif // SCI_SSFX_SFX_SONGLIB_H
diff --git a/engines/sci/sound/iterator/test-iterator.cpp b/engines/sci/sound/iterator/test-iterator.cpp
deleted file mode 100644
index 0d603a89fd..0000000000
--- a/engines/sci/sound/iterator/test-iterator.cpp
+++ /dev/null
@@ -1,423 +0,0 @@
-/* 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 "iterator.h"
-#include "iterator_internal.h"
-#include <stdarg.h>
-#include <stdio.h>
-
-using namespace Sci;
-
-#define ASSERT_S(x) if (!(x)) { error("Failed assertion in L%d: " #x, __LINE__); return; }
-#define ASSERT(x) ASSERT_S(x)
-
-/* Tests the song iterators */
-
-int errors = 0;
-
-void error(char *fmt, ...) {
- va_list ap;
-
- fprintf(stderr, "[ERROR] ");
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
-
- ++errors;
-}
-
-
-/* The simple iterator will finish after a fixed amount of time. Before that,
-** it emits (absolute) cues in ascending order. */
-struct simple_iterator : public SongIterator {
- int lifetime_remaining;
- char *cues;
- int cue_counter;
- int cue_progress;
- int cues_nr;
-};
-
-int simple_it_next(SongIterator *_self, unsigned char *buf, int *result) {
- simple_iterator *self = (simple_iterator *)_self;
-
- if (self->lifetime_remaining == -1) {
- error("Song iterator called post mortem");
- return SI_FINISHED;
- }
-
- if (self->lifetime_remaining) {
-
- if (self->cue_counter < self->cues_nr) {
- int time_to_cue = self->cues[self->cue_counter];
-
- if (self->cue_progress == time_to_cue) {
- ++self->cue_counter;
- self->cue_progress = 0;
- *result = self->cue_counter;
- return SI_ABSOLUTE_CUE;
- } else {
- int retval = time_to_cue - self->cue_progress;
- self->cue_progress = time_to_cue;
-
- if (retval > self->lifetime_remaining) {
- retval = self->lifetime_remaining;
- self->lifetime_remaining = 0;
- self->cue_progress = retval;
- return retval;
- }
-
- self->lifetime_remaining -= retval;
- return retval;
- }
- } else {
- int retval = self->lifetime_remaining;
- self->lifetime_remaining = 0;
- return retval;
- }
-
- } else {
- self->lifetime_remaining = -1;
- return SI_FINISHED;
- }
-}
-
-Audio::AudioStream *simple_it_pcm_feed(SongIterator *_self) {
- error("No PCM feed");
- return NULL;
-}
-
-void simple_it_init(SongIterator *_self) {
-}
-
-SongIterator *simple_it_handle_message(SongIterator *_self, SongIterator::Message msg) {
- return NULL;
-}
-
-void simple_it_cleanup(SongIterator *_self) {
-}
-
-/* Initialises the simple iterator.
-** Parameters: (int) delay: Number of ticks until the iterator finishes
-** (int *) cues: An array of cue delays (cue values are [1,2...])
-** (int) cues_nr: Number of cues in ``cues''
-** The first cue is emitted after cues[0] ticks, and it is 1. After cues[1] additional ticks
-** the next cue is emitted, and so on. */
-SongIterator *setup_simple_iterator(int delay, char *cues, int cues_nr) {
- simple_iterator.lifetime_remaining = delay;
- simple_iterator.cues = cues;
- simple_iterator.cue_counter = 0;
- simple_iterator.cues_nr = cues_nr;
- simple_iterator.cue_progress = 0;
-
- simple_iterator.ID = 42;
- simple_iterator.channel_mask = 0x004f;
- simple_iterator.flags = 0;
- simple_iterator.priority = 1;
-
- simple_iterator.death_listeners_nr = 0;
-
- simple_iterator.cleanup = simple_it_cleanup;
- simple_iterator.init = simple_it_init;
- simple_iterator.handle_message = simple_it_handle_message;
- simple_iterator.get_pcm_feed = simple_it_pcm_feed;
- simple_iterator.next = simple_it_next;
-
- return (SongIterator *) &simple_iterator;
-}
-
-#define ASSERT_SIT ASSERT(it == simple_it)
-#define ASSERT_FFIT ASSERT(it == ff_it)
-#define ASSERT_NEXT(n) ASSERT(songit_next(&it, data, &result, IT_READER_MASK_ALL) == n)
-#define ASSERT_RESULT(n) ASSERT(result == n)
-#define ASSERT_CUE(n) ASSERT_NEXT(SI_ABSOLUTE_CUE); ASSERT_RESULT(n)
-
-void test_simple_it() {
- SongIterator *it;
- SongIterator *simple_it = (SongIterator *) & simple_iterator;
- unsigned char data[4];
- int result;
- puts("[TEST] simple iterator (test artifact)");
-
- it = setup_simple_iterator(42, NULL, 0);
-
- ASSERT_SIT;
- ASSERT_NEXT(42);
- ASSERT_SIT;
- ASSERT_NEXT(SI_FINISHED);
- ASSERT_SIT;
-
- it = setup_simple_iterator(42, "\003\004", 2);
- ASSERT_SIT;
- ASSERT_NEXT(3);
- ASSERT_CUE(1);
- ASSERT_SIT;
- ASSERT_NEXT(4);
- ASSERT_CUE(2);
- ASSERT_SIT;
-// warning("XXX => %d", songit_next(&it, data, &result, IT_READER_MASK_ALL));
- ASSERT_NEXT(35);
- ASSERT_NEXT(SI_FINISHED);
- ASSERT_SIT;
-
- puts("[TEST] Test OK.");
-}
-
-void test_fastforward() {
- SongIterator *it;
- SongIterator *simple_it = (SongIterator *) & simple_iterator;
- SongIterator *ff_it;
- unsigned char data[4];
- int result;
- puts("[TEST] fast-forward iterator");
-
- it = setup_simple_iterator(42, NULL, 0);
- ff_it = it = new_fast_forward_iterator(it, 0);
- ASSERT_FFIT;
- ASSERT_NEXT(42);
- ASSERT_SIT; /* Must have morphed back */
- ASSERT_NEXT(SI_FINISHED);
- ASSERT_SIT;
-
- it = setup_simple_iterator(42, NULL, 0);
- ff_it = it = new_fast_forward_iterator(it, 1);
- ASSERT_FFIT;
- ASSERT_NEXT(41);
- /* May or may not have morphed back here */
- ASSERT_NEXT(SI_FINISHED);
- ASSERT_SIT;
-
- it = setup_simple_iterator(42, NULL, 0);
- ff_it = it = new_fast_forward_iterator(it, 41);
- ASSERT_FFIT;
- ASSERT_NEXT(1);
- /* May or may not have morphed back here */
- ASSERT_NEXT(SI_FINISHED);
- ASSERT_SIT;
-
- it = setup_simple_iterator(42, NULL, 0);
- ff_it = it = new_fast_forward_iterator(it, 42);
- ASSERT_NEXT(SI_FINISHED);
- /* May or may not have morphed back here */
-
- it = setup_simple_iterator(42, NULL, 0);
- ff_it = it = new_fast_forward_iterator(it, 10000);
- ASSERT_NEXT(SI_FINISHED);
- /* May or may not have morphed back here */
-
- it = setup_simple_iterator(42, "\003\004", 2);
- ff_it = it = new_fast_forward_iterator(it, 2);
- ASSERT_FFIT;
- ASSERT_NEXT(1);
- ASSERT_CUE(1);
- ASSERT_SIT;
- ASSERT_NEXT(4);
- ASSERT_CUE(2);
- ASSERT_SIT;
- ASSERT_NEXT(35);
- ASSERT_NEXT(SI_FINISHED);
- ASSERT_SIT;
-
- it = setup_simple_iterator(42, "\003\004", 2);
- ff_it = it = new_fast_forward_iterator(it, 5);
- ASSERT_FFIT;
- ASSERT_CUE(1);
- ASSERT_FFIT;
- ASSERT_NEXT(2);
- ASSERT_CUE(2);
- ASSERT_SIT;
- ASSERT_NEXT(35);
- ASSERT_NEXT(SI_FINISHED);
- ASSERT_SIT;
-
- it = setup_simple_iterator(42, "\003\004", 2);
- ff_it = it = new_fast_forward_iterator(it, 41);
- ASSERT_FFIT;
- ASSERT_CUE(1);
- ASSERT_FFIT;
- ASSERT_CUE(2);
- ASSERT_FFIT;
- ASSERT_NEXT(1);
- ASSERT_NEXT(SI_FINISHED);
- ASSERT_SIT;
-
- puts("[TEST] Test OK.");
-}
-
-#define SIMPLE_SONG_SIZE 50
-
-static unsigned char simple_song[SIMPLE_SONG_SIZE] = {
- 0x00, /* Regular song */
- /* Only use channel 0 for all devices */
- 0x02, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* Song begins here */
- 42, 0x90, 60, 0x7f, /* Play C after 42 ticks */
- 02, 64, 0x42, /* Play E after 2 more ticks, using running status mode */
- 0xf8, 10, 0x80, 60, 0x02, /* Stop C after 250 ticks */
- 0, 64, 0x00, /* Stop E immediately */
- 00, 0xfc /* Stop song */
-};
-
-#define ASSERT_MIDI3(cmd, arg0, arg1) \
- ASSERT(data[0] == cmd); \
- ASSERT(data[1] == arg0); \
- ASSERT(data[2] == arg1);
-
-void test_iterator_sci0() {
- SongIterator *it = songit_new(simple_song, SIMPLE_SONG_SIZE, SCI_SONG_ITERATOR_TYPE_SCI0, 0l);
- unsigned char data[4];
- int result;
- SIMSG_SEND(it, SIMSG_SET_PLAYMASK(0x0001)); /* Initialise song, enabling channel 0 */
-
- puts("[TEST] SCI0-style song");
- ASSERT_NEXT(42);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x90, 60, 0x7f);
- ASSERT_NEXT(2);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x90, 64, 0x42);
- ASSERT_NEXT(250);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x80, 60, 0x02);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x80, 64, 0x00);
- ASSERT_NEXT(SI_FINISHED);
- puts("[TEST] Test OK.");
-}
-
-
-
-void test_iterator_sci0_loop() {
- SongIterator *it = songit_new(simple_song, SIMPLE_SONG_SIZE, SCI_SONG_ITERATOR_TYPE_SCI0, 0l);
- unsigned char data[4];
- int result;
- SIMSG_SEND(it, SIMSG_SET_PLAYMASK(0x0001)); /* Initialise song, enabling channel 0 */
- SIMSG_SEND(it, SIMSG_SET_LOOPS(2)); /* Loop one additional time */
-
- puts("[TEST] SCI0-style song with looping");
- ASSERT_NEXT(42);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x90, 60, 0x7f);
- ASSERT_NEXT(2);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x90, 64, 0x42);
- ASSERT_NEXT(250);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x80, 60, 0x02);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x80, 64, 0x00);
- ASSERT_NEXT(SI_LOOP);
- ASSERT_NEXT(42);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x90, 60, 0x7f);
- ASSERT_NEXT(2);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x90, 64, 0x42);
- ASSERT_NEXT(250);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x80, 60, 0x02);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x80, 64, 0x00);
- ASSERT_NEXT(SI_FINISHED);
- puts("[TEST] Test OK.");
-}
-
-
-
-#define LOOP_SONG_SIZE 54
-
-unsigned char loop_song[LOOP_SONG_SIZE] = {
- 0x00, /* Regular song song */
- /* Only use channel 0 for all devices */
- 0x02, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* Song begins here */
- 42, 0x90, 60, 0x7f, /* Play C after 42 ticks */
- 13, 0x80, 60, 0x00, /* Stop C after 13 ticks */
- 00, 0xCF, 0x7f, /* Set loop point */
- 02, 0x90, 64, 0x42, /* Play E after 2 more ticks, using running status mode */
- 03, 0x80, 64, 0x00, /* Stop E after 3 ticks */
- 00, 0xfc /* Stop song/loop */
-};
-
-
-void test_iterator_sci0_mark_loop() {
- SongIterator *it = songit_new(loop_song, LOOP_SONG_SIZE, SCI_SONG_ITERATOR_TYPE_SCI0, 0l);
- unsigned char data[4];
- int result;
- SIMSG_SEND(it, SIMSG_SET_PLAYMASK(0x0001)); /* Initialise song, enabling channel 0 */
- SIMSG_SEND(it, SIMSG_SET_LOOPS(3)); /* Loop once more */
-
- puts("[TEST] SCI0-style song with loop mark, looping");
- ASSERT_NEXT(42);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x90, 60, 0x7f);
- ASSERT_NEXT(13);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x80, 60, 0x00);
- /* Loop point here: we don't observe that in the iterator interface yet, though */
- ASSERT_NEXT(2);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x90, 64, 0x42);
- ASSERT_NEXT(3);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x80, 64, 0x00);
- /* Now we loop back to the loop pont */
- ASSERT_NEXT(SI_LOOP);
- ASSERT_NEXT(2);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x90, 64, 0x42);
- ASSERT_NEXT(3);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x80, 64, 0x00);
- /* ...and one final time */
- ASSERT_NEXT(SI_LOOP);
- ASSERT_NEXT(2);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x90, 64, 0x42);
- ASSERT_NEXT(3);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x80, 64, 0x00);
-
- ASSERT_NEXT(SI_FINISHED);
- puts("[TEST] Test OK.");
-}
-
-
-
-int main(int argc, char **argv) {
- test_simple_it();
- test_fastforward();
- test_iterator_sci0();
- test_iterator_sci0_loop();
- test_iterator_sci0_mark_loop();
- if (errors != 0)
- warning("[ERROR] %d errors total", errors);
- return (errors != 0);
-}
diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp
index 3ee8a3a83d..cc09ba79f0 100644
--- a/engines/sci/sound/midiparser_sci.cpp
+++ b/engines/sci/sound/midiparser_sci.cpp
@@ -43,30 +43,39 @@ enum SciMidiCommands {
// MidiParser_SCI
//
-MidiParser_SCI::MidiParser_SCI(SciVersion soundVersion) :
+MidiParser_SCI::MidiParser_SCI(SciVersion soundVersion, SciMusic *music) :
MidiParser() {
_soundVersion = soundVersion;
+ _music = music;
_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);
- _volume = 0;
+ _volume = 127;
_signalSet = false;
_signalToSet = 0;
_dataincAdd = false;
_dataincToAdd = 0;
_resetOnPause = false;
- _channelsUsed = 0;
-
- for (int i = 0; i < 16; i++)
- _channelRemap[i] = i;
+ _pSnd = 0;
}
MidiParser_SCI::~MidiParser_SCI() {
unloadMusic();
+ // we do this, so that MidiParser won't be able to call his own ::allNotesOff()
+ // this one would affect all channels and we can't let that happen
+ _driver = 0;
+}
+
+void MidiParser_SCI::mainThreadBegin() {
+ _mainThreadCalled = true;
+}
+
+void MidiParser_SCI::mainThreadEnd() {
+ _mainThreadCalled = false;
}
bool MidiParser_SCI::loadMusic(SoundResource::Track *track, MusicEntry *psnd, int channelFilterMask, SciVersion soundVersion) {
@@ -75,7 +84,14 @@ bool MidiParser_SCI::loadMusic(SoundResource::Track *track, MusicEntry *psnd, in
_pSnd = psnd;
_soundVersion = soundVersion;
- setVolume(psnd->volume);
+ for (int i = 0; i < 16; i++) {
+ _channelUsed[i] = false;
+ _channelRemap[i] = -1;
+ _channelMuted[i] = false;
+ _channelVolume[i] = 127;
+ }
+ _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) {
// SCI0 only has 1 data stream, but we need to filter out channels depending on music hardware selection
@@ -86,30 +102,272 @@ bool MidiParser_SCI::loadMusic(SoundResource::Track *track, MusicEntry *psnd, in
_num_tracks = 1;
_tracks[0] = _mixedData;
- setTrack(0);
+ if (_pSnd)
+ setTrack(0);
_loopTick = 0;
- 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);
+ return true;
+}
+
+byte MidiParser_SCI::midiGetNextChannel(long ticker) {
+ byte curr = 0xFF;
+ long closest = ticker + 1000000, next = 0;
+
+ for (int i = 0; i < _track->channelCount; i++) {
+ if (_track->channels[i].time == -1) // channel ended
+ continue;
+ SoundResource::Channel *curChannel = &_track->channels[i];
+ if (curChannel->curPos >= curChannel->size)
+ continue;
+ next = curChannel->data[curChannel->curPos]; // when the next event should occur
+ if (next == 0xF8) // 0xF8 means 240 ticks delay
+ next = 240;
+ next += _track->channels[i].time;
+ if (next < closest) {
+ curr = i;
+ closest = next;
+ }
+ }
+
+ return curr;
+}
+
+byte *MidiParser_SCI::midiMixChannels() {
+ int totalSize = 0;
+
+ for (int i = 0; i < _track->channelCount; i++) {
+ _track->channels[i].time = 0;
+ _track->channels[i].prev = 0;
+ _track->channels[i].curPos = 0;
+ totalSize += _track->channels[i].size;
+ }
+
+ byte *outData = new byte[totalSize * 2]; // FIXME: creates overhead and still may be not enough to hold all data
+ _mixedData = outData;
+ long ticker = 0;
+ byte channelNr, curDelta;
+ byte midiCommand = 0, midiParam, global_prev = 0;
+ long newDelta;
+ SoundResource::Channel *channel;
+
+ while ((channelNr = midiGetNextChannel(ticker)) != 0xFF) { // there is still an active channel
+ channel = &_track->channels[channelNr];
+ curDelta = channel->data[channel->curPos++];
+ channel->time += (curDelta == 0xF8 ? 240 : curDelta); // when the command is supposed to occur
+ if (curDelta == 0xF8)
+ continue;
+ newDelta = channel->time - ticker;
+ ticker += newDelta;
+
+ midiCommand = channel->data[channel->curPos++];
+ if (midiCommand != kEndOfTrack) {
+ // Write delta
+ while (newDelta > 240) {
+ *outData++ = 0xF8;
+ newDelta -= 240;
+ }
+ *outData++ = (byte)newDelta;
+ }
+ // Write command
+ switch (midiCommand) {
+ case 0xF0: // sysEx
+ *outData++ = midiCommand;
+ do {
+ midiParam = channel->data[channel->curPos++];
+ *outData++ = midiParam;
+ } while (midiParam != 0xF7);
+ break;
+ case kEndOfTrack: // end of channel
+ channel->time = -1;
+ break;
+ default: // MIDI command
+ if (midiCommand & 0x80) {
+ midiParam = channel->data[channel->curPos++];
+ } else {// running status
+ midiParam = midiCommand;
+ midiCommand = channel->prev;
+ }
+
+ // remember which channel got used for channel remapping
+ byte midiChannel = midiCommand & 0xF;
+ _channelUsed[midiChannel] = true;
+
+ if (midiCommand != global_prev)
+ *outData++ = midiCommand;
+ *outData++ = midiParam;
+ if (nMidiParams[(midiCommand >> 4) - 8] == 2)
+ *outData++ = channel->data[channel->curPos++];
+ channel->prev = midiCommand;
+ global_prev = midiCommand;
+ }
+ }
+
+ // Insert stop event
+ *outData++ = 0; // Delta
+ *outData++ = 0xFF; // Meta event
+ *outData++ = 0x2F; // End of track (EOT)
+ *outData++ = 0x00;
+ *outData++ = 0x00;
+ return _mixedData;
+}
+
+// This is used for SCI0 sound-data. SCI0 only has one stream that may
+// contain several channels and according to output device we remove
+// certain channels from that data.
+byte *MidiParser_SCI::midiFilterChannels(int channelMask) {
+ SoundResource::Channel *channel = &_track->channels[0];
+ byte *channelData = channel->data;
+ byte *channelDataEnd = channel->data + channel->size;
+ byte *outData = new byte[channel->size + 5];
+ byte curChannel = 15, curByte, curDelta;
+ byte command = 0, lastCommand = 0;
+ int delta = 0;
+ int midiParamCount = 0;
+
+ _mixedData = outData;
+
+ while (channelData < channelDataEnd) {
+ curDelta = *channelData++;
+ if (curDelta == 0xF8) {
+ delta += 240;
+ continue;
+ }
+ delta += curDelta;
+ curByte = *channelData++;
+
+ switch (curByte) {
+ case 0xF0: // sysEx
+ case kEndOfTrack: // end of channel
+ command = curByte;
+ curChannel = 15;
+ break;
+ default:
+ if (curByte & 0x80) {
+ command = curByte;
+ curChannel = command & 0x0F;
+ midiParamCount = nMidiParams[(command >> 4) - 8];
+ }
+ }
+ if ((1 << curChannel) & channelMask) {
+ if (command != kEndOfTrack) {
+ // Write delta
+ while (delta > 240) {
+ *outData++ = 0xF8;
+ delta -= 240;
+ }
+ *outData++ = (byte)delta;
+ delta = 0;
+ }
+ // Write command
+ switch (command) {
+ case 0xF0: // sysEx
+ *outData++ = command;
+ do {
+ curByte = *channelData++;
+ *outData++ = curByte; // out
+ } while (curByte != 0xF7);
+ lastCommand = command;
+ break;
+
+ case kEndOfTrack: // end of channel
+ break;
+
+ default: // MIDI command
+ // remember which channel got used for channel remapping
+ byte midiChannel = command & 0xF;
+ _channelUsed[midiChannel] = true;
+
+ if (lastCommand != command) {
+ *outData++ = command;
+ lastCommand = command;
+ }
+ if (midiParamCount > 0) {
+ if (curByte & 0x80)
+ *outData++ = *channelData++;
+ else
+ *outData++ = curByte;
+ }
+ if (midiParamCount > 1) {
+ *outData++ = *channelData++;
+ }
+ }
+ } else {
+ if (curByte & 0x80)
+ channelData += midiParamCount;
+ else
+ channelData += midiParamCount - 1;
+ }
+ }
+
+ // Insert stop event
+ *outData++ = 0; // Delta
+ *outData++ = 0xFF; // Meta event
+ *outData++ = 0x2F; // End of track (EOT)
+ *outData++ = 0x00;
+ *outData++ = 0x00;
+
+ return _mixedData;
+}
+
+// This will get called right before actual playing and will try to own the used channels
+void MidiParser_SCI::tryToOwnChannels() {
+ // We don't have SciMusic in case debug command show_instruments is used
+ if (!_music)
+ return;
+ for (int curChannel = 0; curChannel < 15; curChannel++) {
+ if (_channelUsed[curChannel]) {
+ if (_channelRemap[curChannel] == -1) {
+ _channelRemap[curChannel] = _music->tryToOwnChannel(_pSnd, curChannel);
+ }
+ }
+ }
+}
+
+void MidiParser_SCI::lostChannels() {
+ for (int curChannel = 0; curChannel < 15; curChannel++)
+ if ((_channelUsed[curChannel]) && (curChannel != 9))
+ _channelRemap[curChannel] = -1;
+}
+
+void MidiParser_SCI::sendInitCommands() {
+ // reset our "global" volume and channel volumes
+ _volume = 127;
+ for (int i = 0; i < 16; i++)
+ _channelVolume[i] = 127;
+
+ // Set initial voice count
+ if (_pSnd) {
+ if (_soundVersion <= SCI_VERSION_0_LATE) {
+ for (int i = 0; i < 15; ++i) {
+ byte voiceCount = 0;
+ if (_channelUsed[i]) {
+ voiceCount = _pSnd->soundRes->getInitialVoiceCount(i);
+ sendToDriver(0xB0 | i, 0x4B, voiceCount);
+ }
+ }
}
}
// Send a velocity off signal to all channels
- for (int i = 0; i < 16; ++i) {
- _driver->send(0xB0 | i, 0x4E, 0); // Reset velocity
+ for (int i = 0; i < 15; ++i) {
+ if (_channelUsed[i])
+ sendToDriver(0xB0 | i, 0x4E, 0); // Reset velocity
}
- return true;
+ // Center the pitch wheels and hold pedal in preparation for the next piece of music
+ for (int i = 0; i < 16; ++i) {
+ if (_channelUsed[i]) {
+ sendToDriver(0xE0 | i, 0, 0x40); // Reset pitch wheel
+ sendToDriver(0xB0 | i, 0x40, 0); // Reset hold pedal
+ }
+ }
}
void MidiParser_SCI::unloadMusic() {
- resetTracking();
- allNotesOff();
+ if (_pSnd) {
+ resetTracking();
+ allNotesOff();
+ }
_num_tracks = 0;
_active_track = 255;
_resetOnPause = false;
@@ -118,36 +376,76 @@ void MidiParser_SCI::unloadMusic() {
delete[] _mixedData;
_mixedData = NULL;
}
+}
- // Center the pitch wheels and hold pedal in preparation for the next piece of music
- if (_driver) {
- for (int i = 0; i < 16; ++i) {
- if (isChannelUsed(i)) {
- _driver->send(0xE0 | i, 0, 0x40); // Reset pitch wheel
- _driver->send(0xB0 | i, 0x40, 0); // Reset hold pedal
- }
+// this is used for scripts sending midi commands to us. we verify in that case that the channel is actually
+// used, so that channel remapping will work as well and then send them on
+void MidiParser_SCI::sendFromScriptToDriver(uint32 midi) {
+ byte midiChannel = midi & 0xf;
+
+ if (!_channelUsed[midiChannel]) {
+ // trying to send to an unused channel
+ // this happens for cmdSendMidi at least in sq1vga right at the start, it's a script issue
+ return;
+ }
+ if (_channelRemap[midiChannel] == -1) {
+ // trying to send to an unmapped channel
+ // this happens for cmdSendMidi at least in sq1vga right at the start, scripts are pausing the sound
+ // and then sending manually. it's a script issue
+ return;
+ }
+ sendToDriver(midi);
+}
+
+void MidiParser_SCI::sendToDriver(uint32 midi) {
+ byte midiChannel = midi & 0xf;
+
+ if ((midi & 0xFFF0) == 0x4EB0) {
+ // this is channel mute only for sci1
+ // it's velocity control for sci0
+ if (_soundVersion >= SCI_VERSION_1_EARLY) {
+ _channelMuted[midiChannel] = midi & 0xFF0000 ? true : false;
+ return; // don't send this to driver at all
}
}
- for (int i = 0; i < 16; i++)
- _channelRemap[i] = i;
+ // Is channel muted? if so, don't send command
+ if (_channelMuted[midiChannel])
+ return;
+
+ if ((midi & 0xFFF0) == 0x07B0) {
+ // someone trying to set channel volume?
+ int channelVolume = (midi >> 16) & 0xFF;
+ // Remember, if we need to set it ourselves
+ _channelVolume[midiChannel] = channelVolume;
+ // Adjust volume accordingly to current "global" volume
+ channelVolume = channelVolume * _volume / 127;
+ midi = (midi & 0xFFF0) | ((channelVolume & 0xFF) << 16);
+ }
+
+ // Channel remapping
+ int16 realChannel = _channelRemap[midiChannel];
+ assert(realChannel != -1);
+
+ midi = (midi & 0xFFFFFFF0) | realChannel;
+ if (_mainThreadCalled)
+ _music->putMidiCommandInQueue(midi);
+ else
+ _driver->send(midi);
}
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
if (_dataincAdd) {
_dataincAdd = false;
_pSnd->dataInc += _dataincToAdd;
_pSnd->signal = 0x7f + _pSnd->dataInc;
- debugC(2, kDebugLevelSound, "datainc %04x", _dataincToAdd);
+ debugC(4, kDebugLevelSound, "datainc %04x", _dataincToAdd);
}
if (_signalSet) {
_signalSet = false;
_pSnd->signal = _signalToSet;
- debugC(2, kDebugLevelSound, "signal %04x", _signalToSet);
+ debugC(4, kDebugLevelSound, "signal %04x", _signalToSet);
}
info.start = _position._play_pos;
@@ -173,10 +471,16 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) {
info.basic.param2 = 0;
if (info.channel() == 0xF) {// SCI special case
if (info.basic.param1 != kSetSignalLoop) {
- _signalSet = true;
- _signalToSet = info.basic.param1;
+ // at least in kq5/french&mac the first scene in the intro has a song that sets signal to 4 immediately
+ // on tick 0. Signal isn't set at that point by sierra sci and it would cause the castle daventry text to
+ // get immediately removed, so we currently filter it.
+ // Sierra SCI ignores them as well at that time
+ if (_position._play_tick) {
+ _signalSet = true;
+ _signalToSet = info.basic.param1;
+ }
} else {
- _loopTick = _position._play_tick;
+ _loopTick = _position._play_tick + info.delta;
}
}
break;
@@ -235,7 +539,6 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) {
case 0x0A: // pan
case 0x0B: // expression
case 0x40: // sustain
- case 0x4E: // velocity control
case 0x79: // reset all
case 0x7B: // notes off
// These are all handled by the music driver, so ignore them
@@ -249,8 +552,6 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) {
break;
}
}
- if (info.basic.param1 == 7) // channel volume change -scale it
- info.basic.param2 = info.basic.param2 * _volume / MUSIC_VOLUME_MAX;
info.length = 0;
break;
@@ -307,7 +608,7 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) {
_pSnd->status = kSoundStopped;
_pSnd->signal = SIGNAL_OFFSET;
- debugC(2, kDebugLevelSound, "signal EOT");
+ debugC(4, kDebugLevelSound, "signal EOT");
}
}
break;
@@ -319,254 +620,66 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) {
}// switch (info.command())
}
+void MidiParser_SCI::allNotesOff() {
+ if (!_driver)
+ return;
-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 should occur
- if (next == 0xF8) // 0xF8 means 240 ticks delay
- next = 240;
- next += _track->channels[i].time;
- if (next < closest) {
- curr = i;
- closest = next;
- }
- }
-
- return curr;
-}
-
-byte *MidiParser_SCI::midiMixChannels() {
- int totalSize = 0;
- 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 *outData = new byte[totalSize * 2]; // FIXME: creates overhead and still may be not enough to hold all data
- _mixedData = outData;
- long ticker = 0;
- byte curr, curDelta;
- byte command = 0, par1, global_prev = 0;
- long new_delta;
- SoundResource::Channel *channel;
-
- while ((curr = midiGetNextChannel(ticker)) != 0xFF) { // there is still active channel
- channel = &_track->channels[curr];
- curDelta = *channel->data++;
- channel->time += (curDelta == 0xF8 ? 240 : curDelta); // when the comamnd is supposed to occur
- if (curDelta == 0xF8)
- continue;
- new_delta = channel->time - ticker;
- ticker += new_delta;
-
- command = *channel->data++;
- if (command != kEndOfTrack) {
- debugC(2, kDebugLevelSound, "\nDELTA ");
- // Write delta
- while (new_delta > 240) {
- *outData++ = 0xF8;
- debugC(2, kDebugLevelSound, "F8 ");
- new_delta -= 240;
- }
- *outData++ = (byte)new_delta;
- debugC(2, kDebugLevelSound, "%02X ", (uint32)new_delta);
- }
- // Write command
- switch (command) {
- case 0xF0: // sysEx
- *outData++ = command;
- debugC(2, kDebugLevelSound, "%02X ", command);
- do {
- par1 = *channel->data++;
- *outData++ = par1; // out
- } while (par1 != 0xF7);
- break;
- case kEndOfTrack: // end of channel
- channel->time = -1; // FIXME
- break;
- default: // MIDI command
- if (command & 0x80) {
- par1 = *channel->data++;
-
- // TODO: Fix remapping
+ int i, j;
-#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
- par1 = command;
- command = channel->prev;
+ // Turn off all active notes
+ for (i = 0; i < 128; ++i) {
+ for (j = 0; j < 16; ++j) {
+ if ((_active_notes[i] & (1 << j)) && (_channelRemap[j] != -1)){
+ sendToDriver(0x80 | j, i, 0);
}
- 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)
- }// while (curr)
-
- // Insert stop event
- *outData++ = 0; // Delta
- *outData++ = 0xFF; // Meta event
- *outData++ = 0x2F; // End of track (EOT)
- *outData++ = 0x00;
- *outData++ = 0x00;
-
- for (int channelNr = 0; channelNr < _track->channelCount; channelNr++)
- _track->channels[channelNr].data = dataPtr[channelNr];
-
- delete[] dataPtr;
- return _mixedData;
-}
-
-// This is used for SCI0 sound-data. SCI0 only has one stream that may
-// contain several channels and according to output device we remove
-// certain channels from that data.
-byte *MidiParser_SCI::midiFilterChannels(int channelMask) {
- SoundResource::Channel *channel = &_track->channels[0];
- byte *channelData = channel->data;
- byte *channelDataEnd = channel->data + channel->size;
- byte *outData = new byte[channel->size + 5];
- byte curChannel = 15, curByte, curDelta;
- byte command = 0, lastCommand = 0;
- int delta = 0;
- int midiParamCount = 0;
-
- _mixedData = outData;
-
- while (channelData < channelDataEnd) {
- curDelta = *channelData++;
- if (curDelta == 0xF8) {
- delta += 240;
- continue;
}
- delta += curDelta;
- curByte = *channelData++;
+ }
- switch (curByte) {
- case 0xF0: // sysEx
- case kEndOfTrack: // end of channel
- command = curByte;
- curChannel = 15;
- break;
- default:
- if (curByte & 0x80) {
- command = curByte;
- curChannel = command & 0x0F;
- midiParamCount = nMidiParams[(command >> 4) - 8];
- }
+ // Turn off all hanging notes
+ for (i = 0; i < ARRAYSIZE(_hanging_notes); i++) {
+ byte midiChannel = _hanging_notes[i].channel;
+ if ((_hanging_notes[i].time_left) && (_channelRemap[midiChannel] != -1)) {
+ sendToDriver(0x80 | midiChannel, _hanging_notes[i].note, 0);
+ _hanging_notes[i].time_left = 0;
}
- if ((1 << curChannel) & channelMask) {
- if (command != kEndOfTrack) {
- debugC(2, kDebugLevelSound, "\nDELTA ");
- // Write delta
- while (delta > 240) {
- *outData++ = 0xF8;
- debugC(2, kDebugLevelSound, "F8 ");
- delta -= 240;
- }
- *outData++ = (byte)delta;
- debugC(2, kDebugLevelSound, "%02X ", delta);
- delta = 0;
- }
- // Write command
- switch (command) {
- case 0xF0: // sysEx
- *outData++ = command;
- debugC(2, kDebugLevelSound, "%02X ", command);
- do {
- curByte = *channelData++;
- *outData++ = curByte; // out
- } while (curByte != 0xF7);
- lastCommand = command;
- break;
+ }
+ _hanging_notes_count = 0;
- case kEndOfTrack: // end of channel
- break;
+ // To be sure, send an "All Note Off" event (but not all MIDI devices
+ // support this...).
- default: // MIDI command
- if (lastCommand != command) {
- *outData++ = command;
- debugC(2, kDebugLevelSound, "%02X ", command);
- lastCommand = command;
- }
- if (midiParamCount > 0) {
- if (curByte & 0x80) {
- debugC(2, kDebugLevelSound, "%02X ", *channelData);
- *outData++ = *channelData++;
- } else {
- debugC(2, kDebugLevelSound, "%02X ", curByte);
- *outData++ = curByte;
- }
- }
- if (midiParamCount > 1) {
- debugC(2, kDebugLevelSound, "%02X ", *channelData);
- *outData++ = *channelData++;
- }
- }
- } else {
- if (curByte & 0x80) {
- channelData += midiParamCount;
- } else {
- channelData += midiParamCount - 1;
- }
- }
+ for (i = 0; i < 16; ++i) {
+ if (_channelRemap[i] != -1)
+ sendToDriver(0xB0 | i, 0x7b, 0); // All notes off
}
- // Insert stop event
- *outData++ = 0; // Delta
- *outData++ = 0xFF; // Meta event
- *outData++ = 0x2F; // End of track (EOT)
- *outData++ = 0x00;
- *outData++ = 0x00;
-
- return _mixedData;
+ memset(_active_notes, 0, sizeof(_active_notes));
}
void MidiParser_SCI::setVolume(byte volume) {
- // 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
- }
-
assert(volume <= MUSIC_VOLUME_MAX);
- if (_volume != volume) {
- _volume = volume;
-
- switch (_soundVersion) {
- case SCI_VERSION_0_EARLY:
- case SCI_VERSION_0_LATE: {
- int16 globalVolume = _volume * 15 / 127;
- ((MidiPlayer *)_driver)->setVolume(globalVolume);
- break;
- }
+ _volume = volume;
+
+ switch (_soundVersion) {
+ case SCI_VERSION_0_EARLY:
+ case SCI_VERSION_0_LATE: {
+ // SCI0 adlib driver doesn't support channel volumes, so we need to go this way
+ // TODO: this should take the actual master volume into account
+ int16 globalVolume = _volume * 15 / 127;
+ ((MidiPlayer *)_driver)->setVolume(globalVolume);
+ 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;
+ case SCI_VERSION_1_EARLY:
+ case SCI_VERSION_1_LATE:
+ // Send previous channel volumes again to actually update the volume
+ for (int i = 0; i < 15; i++)
+ if (_channelRemap[i] != -1)
+ sendToDriver(0xB0 + i, 7, _channelVolume[i]);
+ break;
- default:
- error("MidiParser_SCI::setVolume: Unsupported soundVersion");
- }
+ default:
+ error("MidiParser_SCI::setVolume: Unsupported soundVersion");
}
}
diff --git a/engines/sci/sound/midiparser_sci.h b/engines/sci/sound/midiparser_sci.h
index 9d4b5a39da..90db06e539 100644
--- a/engines/sci/sound/midiparser_sci.h
+++ b/engines/sci/sound/midiparser_sci.h
@@ -53,12 +53,17 @@ namespace Sci {
*/
class MidiParser_SCI : public MidiParser {
public:
- MidiParser_SCI(SciVersion soundVersion);
+ MidiParser_SCI(SciVersion soundVersion, SciMusic *music);
~MidiParser_SCI();
+
+ void mainThreadBegin();
+ void mainThreadEnd();
+
bool loadMusic(SoundResource::Track *track, MusicEntry *psnd, int channelFilterMask, SciVersion soundVersion);
bool loadMusic(byte *, uint32) {
return false;
}
+ void sendInitCommands();
void unloadMusic();
void setVolume(byte volume);
void stop() {
@@ -71,23 +76,29 @@ public:
jumpToTick(0);
}
- 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 allNotesOff();
- void clearUsedChannels() { _channelsUsed = 0; }
+ const byte *getMixedData() const { return _mixedData; }
-protected:
- bool isChannelUsed(byte channel) const { return _channelsUsed & (1 << channel); }
- void setChannelUsed(byte channel) { _channelsUsed |= (1 << channel); }
+ void tryToOwnChannels();
+ void lostChannels();
+ void sendFromScriptToDriver(uint32 midi);
+ void sendToDriver(uint32 midi);
+ void sendToDriver(byte status, byte firstOp, byte secondOp) {
+ sendToDriver(status | ((uint32)firstOp << 8) | ((uint32)secondOp << 16));
+ }
+protected:
void parseNextEvent(EventInfo &info);
byte *midiMixChannels();
byte *midiFilterChannels(int channelMask);
byte midiGetNextChannel(long ticker);
+ SciMusic *_music;
+
+ // this is set, when main thread calls us -> we send commands to queue instead to driver
+ bool _mainThreadCalled;
+
SciVersion _soundVersion;
byte *_mixedData;
SoundResource::Track *_track;
@@ -101,11 +112,10 @@ protected:
int16 _dataincToAdd;
bool _resetOnPause;
- // A 16-bit mask, containing the channels used
- // by the currently parsed song
- uint16 _channelsUsed;
-
- byte _channelRemap[16];
+ bool _channelUsed[16];
+ int16 _channelRemap[16];
+ bool _channelMuted[16];
+ byte _channelVolume[16];
};
} // End of namespace Sci
diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp
index fa5716e7cc..55a7e1fdc4 100644
--- a/engines/sci/sound/music.cpp
+++ b/engines/sci/sound/music.cpp
@@ -43,6 +43,11 @@ SciMusic::SciMusic(SciVersion soundVersion)
// Reserve some space in the playlist, to avoid expensive insertion
// operations
_playList.reserve(10);
+
+ for (int i = 0; i < 16; i++)
+ _usedChannel[i] = 0;
+
+ _queuedCommands.reserve(1000);
}
SciMusic::~SciMusic() {
@@ -58,31 +63,30 @@ void SciMusic::init() {
// SCI sound init
_dwTempo = 0;
- MidiDriverType midiType;
-
// Default to MIDI in SCI32 games, as many don't have AdLib support.
- // WORKAROUND: Default to MIDI in Amiga SCI1_EGA+ games as we don't support those patches yet.
- // We also don't yet support the 7.pat file of SCI1+ Mac games or SCI0 Mac patches, so we
- // default to MIDI in those games to let them run.
+ // WORKAROUND: Default to MIDI in Amiga SCI1_EGA+ games as we don't support
+ // those patches yet. We also don't yet support the 7.pat file of SCI1+ Mac
+ // games or SCI0 Mac patches, so we default to MIDI in those games to let
+ // them run.
Common::Platform platform = g_sci->getPlatform();
-
- if (getSciVersion() >= SCI_VERSION_2 || platform == Common::kPlatformMacintosh || (platform == Common::kPlatformAmiga && getSciVersion() >= SCI_VERSION_1_EGA))
- midiType = MidiDriver::detectMusicDriver(MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MIDI);
- else
- midiType = MidiDriver::detectMusicDriver(MDT_PCSPK | MDT_ADLIB | MDT_MIDI);
-
- switch (midiType) {
- case MD_ADLIB:
+ uint32 dev = MidiDriver::detectDevice(
+ (getSciVersion() >= SCI_VERSION_2 || platform == Common::kPlatformMacintosh ||
+ (platform == Common::kPlatformAmiga && getSciVersion() >= SCI_VERSION_1_EGA))
+ ? (MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM)
+ : (MDT_PCSPK | MDT_ADLIB | MDT_MIDI));
+
+ switch (MidiDriver::getMusicType(dev)) {
+ case MT_ADLIB:
// FIXME: There's no Amiga sound option, so we hook it up to AdLib
if (g_sci->getPlatform() == Common::kPlatformAmiga)
_pMidiDrv = MidiPlayer_Amiga_create(_soundVersion);
else
_pMidiDrv = MidiPlayer_AdLib_create(_soundVersion);
break;
- case MD_PCJR:
+ case MT_PCJR:
_pMidiDrv = MidiPlayer_PCJr_create(_soundVersion);
break;
- case MD_PCSPK:
+ case MT_PCSPK:
_pMidiDrv = MidiPlayer_PCSpeaker_create(_soundVersion);
break;
default:
@@ -100,6 +104,49 @@ void SciMusic::init() {
}
_bMultiMidi = ConfMan.getBool("multi_midi");
+
+ // Find out what the first possible channel is (used, when doing channel
+ // remapping).
+ _driverFirstChannel = _pMidiDrv->getFirstChannel();
+}
+
+void SciMusic::miditimerCallback(void *p) {
+ SciMusic *sciMusic = (SciMusic *)p;
+
+ Common::StackLock lock(sciMusic->_mutex);
+ sciMusic->onTimer();
+}
+
+void SciMusic::onTimer() {
+ const MusicList::iterator end = _playList.end();
+ // sending out queued commands that were "sent" via main thread
+ sendMidiCommandsFromQueue();
+
+ for (MusicList::iterator i = _playList.begin(); i != end; ++i)
+ (*i)->onTimer();
+}
+
+void SciMusic::putMidiCommandInQueue(byte status, byte firstOp, byte secondOp) {
+ putMidiCommandInQueue(status | ((uint32)firstOp << 8) | ((uint32)secondOp << 16));
+}
+
+void SciMusic::putMidiCommandInQueue(uint32 midi) {
+ _queuedCommands.push_back(midi);
+}
+
+// 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 SciMusic::sendMidiCommandsFromQueue() {
+ uint curCommand = 0;
+ uint commandCount = _queuedCommands.size();
+
+ while (curCommand < commandCount) {
+ _pMidiDrv->send(_queuedCommands[curCommand]);
+ curCommand++;
+ }
+ _queuedCommands.clear();
}
void SciMusic::clearPlayList() {
@@ -119,22 +166,12 @@ void SciMusic::pauseAll(bool pause) {
}
void SciMusic::stopAll() {
- Common::StackLock lock(_mutex);
-
const MusicList::iterator end = _playList.end();
for (MusicList::iterator i = _playList.begin(); i != end; ++i) {
soundStop(*i);
}
}
-
-void SciMusic::miditimerCallback(void *p) {
- SciMusic *aud = (SciMusic *)p;
-
- Common::StackLock lock(aud->_mutex);
- aud->onTimer();
-}
-
void SciMusic::soundSetSoundOn(bool soundOnFlag) {
Common::StackLock lock(_mutex);
@@ -160,6 +197,24 @@ MusicEntry *SciMusic::getSlot(reg_t obj) {
return NULL;
}
+// We return the currently active music slot for SCI0
+MusicEntry *SciMusic::getActiveSci0MusicSlot() {
+ const MusicList::iterator end = _playList.end();
+ MusicEntry *highestPrioritySlot = NULL;
+ for (MusicList::iterator i = _playList.begin(); i != end; ++i) {
+ MusicEntry *playSlot = *i;
+ if (playSlot->pMidiParser) {
+ if (playSlot->status == kSoundPlaying)
+ return playSlot;
+ if (playSlot->status == kSoundPaused) {
+ if ((!highestPrioritySlot) || (highestPrioritySlot->priority < playSlot->priority))
+ highestPrioritySlot = playSlot;
+ }
+ }
+ }
+ return highestPrioritySlot;
+}
+
void SciMusic::setReverb(byte reverb) {
Common::StackLock lock(_mutex);
_pMidiDrv->setReverb(reverb);
@@ -174,28 +229,14 @@ void SciMusic::sortPlayList() {
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) {
int channelFilterMask = 0;
SoundResource::Track *track = pSnd->soundRes->getTrackByType(_pMidiDrv->getPlayId());
- // If MIDI device is selected but there is no digital track in sound resource
- // try to use adlib's digital sample if possible
- // Also, if the track couldn't be found, load the digital track, as some games
- // depend on this (e.g. the Longbow demo)
+ // If MIDI device is selected but there is no digital track in sound
+ // resource try to use adlib's digital sample if possible. Also, if the
+ // track couldn't be found, load the digital track, as some games depend on
+ // this (e.g. the Longbow demo).
if (!track || (_bMultiMidi && track->digitalChannelNr == -1)) {
SoundResource::Track *digital = pSnd->soundRes->getDigitalTrack();
if (digital)
@@ -224,49 +265,53 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) {
_mutex.lock();
pSnd->soundType = Audio::Mixer::kMusicSoundType;
if (pSnd->pMidiParser == NULL) {
- pSnd->pMidiParser = new MidiParser_SCI(_soundVersion);
+ pSnd->pMidiParser = new MidiParser_SCI(_soundVersion, this);
pSnd->pMidiParser->setMidiDriver(_pMidiDrv);
pSnd->pMidiParser->setTimerRate(_dwTempo);
}
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
channelFilterMask = pSnd->soundRes->getChannelFilterMask(_pMidiDrv->getPlayId(), _pMidiDrv->hasRhythmChannel());
- pSnd->pMidiParser->loadMusic(track, pSnd, channelFilterMask, _soundVersion);
- // Fast forward to the last position and perform associated events when loading
- pSnd->pMidiParser->jumpToTick(pSnd->ticker, true);
+ pSnd->pMidiParser->mainThreadBegin();
+ pSnd->pMidiParser->loadMusic(track, pSnd, channelFilterMask, _soundVersion);
+ pSnd->pMidiParser->mainThreadEnd();
_mutex.unlock();
}
}
}
-void SciMusic::onTimer() {
- const MusicList::iterator end = _playList.end();
- for (MusicList::iterator i = _playList.begin(); i != end; ++i)
- (*i)->onTimer();
+// 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) {
+ // Don't even try this for SCI0
+ if (_soundVersion <= SCI_VERSION_0_LATE)
+ return 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 = _driverFirstChannel; channelNr < 15; channelNr++) {
+ if (!_usedChannel[channelNr]) {
+ _usedChannel[channelNr] = caller;
+ return channelNr;
+ }
+ }
+ error("no free channels");
+}
+
+void SciMusic::freeChannels(MusicEntry *caller) {
+ // Remove used channels
+ for (int i = 0; i < 15; i++) {
+ if (_usedChannel[i] == caller)
+ _usedChannel[i] = 0;
+ }
+ // Also tell midiparser, that he lost ownership
+ caller->pMidiParser->lostChannels();
}
void SciMusic::soundPlay(MusicEntry *pSnd) {
@@ -294,7 +339,7 @@ void SciMusic::soundPlay(MusicEntry *pSnd) {
if ((_soundVersion <= SCI_VERSION_0_LATE) && (alreadyPlaying)) {
// Music already playing in SCI0?
if (pSnd->priority > alreadyPlaying->priority) {
- // And new priority higher? pause previous music and play new one immediately
+ // And new priority higher? pause previous music and play new one immediately.
// Example of such case: lsl3, when getting points (jingle is played then)
soundPause(alreadyPlaying);
alreadyPlaying->isQueued = true;
@@ -317,34 +362,54 @@ void SciMusic::soundPlay(MusicEntry *pSnd) {
pSnd->pLoopStream, -1, pSnd->volume, 0,
DisposeAfterUse::NO);
} else {
+ // Rewind in case we play the same sample multiple times
+ // (non-looped) like in pharkas right at the start
+ pSnd->pStreamAud->rewind();
_pMixer->playStream(pSnd->soundType, &pSnd->hCurrentAud,
pSnd->pStreamAud, -1, pSnd->volume, 0,
DisposeAfterUse::NO);
}
} else {
- _mutex.lock();
if (pSnd->pMidiParser) {
- pSnd->pMidiParser->setVolume(pSnd->volume);
+ _mutex.lock();
+ pSnd->pMidiParser->mainThreadBegin();
+ pSnd->pMidiParser->tryToOwnChannels();
if (pSnd->status == kSoundStopped)
+ pSnd->pMidiParser->sendInitCommands();
+ pSnd->pMidiParser->setVolume(pSnd->volume);
+ if (pSnd->status == kSoundStopped) {
pSnd->pMidiParser->jumpToTick(0);
+ } else {
+ // Fast forward to the last position and perform associated events when loading
+ pSnd->pMidiParser->jumpToTick(pSnd->ticker, true);
+ }
+ pSnd->pMidiParser->mainThreadEnd();
+ _mutex.unlock();
}
- _mutex.unlock();
}
pSnd->status = kSoundPlaying;
}
void SciMusic::soundStop(MusicEntry *pSnd) {
+ SoundStatus previousStatus = pSnd->status;
pSnd->status = kSoundStopped;
if (_soundVersion <= SCI_VERSION_0_LATE)
pSnd->isQueued = false;
if (pSnd->pStreamAud)
_pMixer->stopHandle(pSnd->hCurrentAud);
- _mutex.lock();
- if (pSnd->pMidiParser)
- pSnd->pMidiParser->stop();
- _mutex.unlock();
+ if (pSnd->pMidiParser) {
+ _mutex.lock();
+ pSnd->pMidiParser->mainThreadBegin();
+ // We shouldn't call stop in case it's paused, otherwise we would send
+ // allNotesOff() again
+ if (previousStatus == kSoundPlaying)
+ pSnd->pMidiParser->stop();
+ freeChannels(pSnd);
+ pSnd->pMidiParser->mainThreadEnd();
+ _mutex.unlock();
+ }
}
void SciMusic::soundSetVolume(MusicEntry *pSnd, byte volume) {
@@ -353,7 +418,9 @@ void SciMusic::soundSetVolume(MusicEntry *pSnd, byte volume) {
_pMixer->setChannelVolume(pSnd->hCurrentAud, volume * 2); // Mixer is 0-255, SCI is 0-127
} else if (pSnd->pMidiParser) {
_mutex.lock();
+ pSnd->pMidiParser->mainThreadBegin();
pSnd->pMidiParser->setVolume(volume);
+ pSnd->pMidiParser->mainThreadEnd();
_mutex.unlock();
}
}
@@ -368,13 +435,15 @@ void SciMusic::soundSetPriority(MusicEntry *pSnd, byte prio) {
void SciMusic::soundKill(MusicEntry *pSnd) {
pSnd->status = kSoundStopped;
- _mutex.lock();
if (pSnd->pMidiParser) {
+ _mutex.lock();
+ pSnd->pMidiParser->mainThreadBegin();
pSnd->pMidiParser->unloadMusic();
+ pSnd->pMidiParser->mainThreadEnd();
delete pSnd->pMidiParser;
pSnd->pMidiParser = NULL;
+ _mutex.unlock();
}
- _mutex.unlock();
if (pSnd->pStreamAud) {
_pMixer->stopHandle(pSnd->hCurrentAud);
@@ -406,10 +475,14 @@ void SciMusic::soundPause(MusicEntry *pSnd) {
if (pSnd->pStreamAud) {
_pMixer->pauseHandle(pSnd->hCurrentAud, true);
} else {
- _mutex.lock();
- if (pSnd->pMidiParser)
+ if (pSnd->pMidiParser) {
+ _mutex.lock();
+ pSnd->pMidiParser->mainThreadBegin();
pSnd->pMidiParser->pause();
- _mutex.unlock();
+ freeChannels(pSnd);
+ pSnd->pMidiParser->mainThreadEnd();
+ _mutex.unlock();
+ }
}
}
@@ -448,6 +521,21 @@ void SciMusic::soundSetMasterVolume(uint16 vol) {
_pMidiDrv->setVolume(vol);
}
+void SciMusic::sendMidiCommand(uint32 cmd) {
+ Common::StackLock lock(_mutex);
+ _pMidiDrv->send(cmd);
+}
+
+void SciMusic::sendMidiCommand(MusicEntry *pSnd, uint32 cmd) {
+ Common::StackLock lock(_mutex);
+ if (!pSnd->pMidiParser)
+ error("tried to cmdSendMidi on non midi slot (%04x:%04x)", PRINT_REG(pSnd->soundObj));
+
+ pSnd->pMidiParser->mainThreadBegin();
+ pSnd->pMidiParser->sendFromScriptToDriver(cmd);
+ pSnd->pMidiParser->mainThreadEnd();
+}
+
void SciMusic::printPlayList(Console *con) {
Common::StackLock lock(_mutex);
@@ -567,14 +655,6 @@ void MusicEntry::doFade() {
fadeStep = 0;
fadeCompleted = true;
}
-#ifdef ENABLE_SCI32
- // Disable fading for SCI32 - sound drivers have issues when fading in (gabriel knight 1 sierra title)
- if (getSciVersion() >= SCI_VERSION_2) {
- volume = fadeTo;
- fadeStep = 0;
- fadeCompleted = true;
- }
-#endif
// Only process MIDI streams in this thread, not digital sound effects
if (pMidiParser) {
diff --git a/engines/sci/sound/music.h b/engines/sci/sound/music.h
index 83cd59e89b..943a5bd2a8 100644
--- a/engines/sci/sound/music.h
+++ b/engines/sci/sound/music.h
@@ -26,15 +26,11 @@
#ifndef SCI_MUSIC_H
#define SCI_MUSIC_H
-#ifndef USE_OLD_MUSIC_FUNCTIONS
#include "common/serializer.h"
-#endif
#include "common/mutex.h"
#include "sound/mixer.h"
#include "sound/audiostream.h"
-//#include "sound/mididrv.h"
-//#include "sound/midiparser.h"
#include "sci/sci.h"
#include "sci/resource.h"
@@ -55,11 +51,7 @@ enum SoundStatus {
class MidiParser_SCI;
class SegManager;
-class MusicEntry
-#ifndef USE_OLD_MUSIC_FUNCTIONS
- : public Common::Serializable
-#endif
-{
+class MusicEntry : public Common::Serializable {
public:
// Do not get these directly for the sound objects!
// It's a bad idea, as the sound code (i.e. the SciMusic
@@ -96,9 +88,6 @@ public:
Audio::Mixer::SoundType soundType;
-#ifndef USE_OLD_MUSIC_FUNCTIONS
-//protected:
-#endif
MidiParser_SCI *pMidiParser;
// TODO: We need to revise how we store the different
@@ -114,25 +103,28 @@ public:
void doFade();
void onTimer();
-#ifndef USE_OLD_MUSIC_FUNCTIONS
virtual void saveLoadWithSerializer(Common::Serializer &ser);
-#endif
};
typedef Common::Array<MusicEntry *> MusicList;
+typedef Common::Array<uint32> MidiCommandQueue;
-class SciMusic
-#ifndef USE_OLD_MUSIC_FUNCTIONS
- : public Common::Serializable
-#endif
-{
+class SciMusic : public Common::Serializable {
public:
SciMusic(SciVersion soundVersion);
~SciMusic();
void init();
+
void onTimer();
+ void putMidiCommandInQueue(byte status, byte firstOp, byte secondOp);
+ void putMidiCommandInQueue(uint32 midi);
+private:
+ static void miditimerCallback(void *p);
+ void sendMidiCommandsFromQueue();
+
+public:
void clearPlayList();
void pauseAll(bool pause);
void stopAll();
@@ -165,6 +157,7 @@ public:
}
MusicEntry *getSlot(reg_t obj);
+ MusicEntry *getActiveSci0MusicSlot();
void pushBackSlot(MusicEntry *slotEntry) {
Common::StackLock lock(_mutex);
@@ -179,16 +172,12 @@ public:
MusicList::iterator getPlayListStart() { return _playList.begin(); }
MusicList::iterator getPlayListEnd() { return _playList.end(); }
- void sendMidiCommand(uint32 cmd) {
- Common::StackLock lock(_mutex);
- _pMidiDrv->send(cmd);
- }
+ void sendMidiCommand(uint32 cmd);
+ void sendMidiCommand(MusicEntry *pSnd, uint32 cmd);
void setReverb(byte reverb);
-#ifndef USE_OLD_MUSIC_FUNCTIONS
virtual void saveLoadWithSerializer(Common::Serializer &ser);
-#endif
// Mutex for music code. Used to guard access to the song playlist, to the
// MIDI parser and to the MIDI driver/player. Note that guarded code must NOT
@@ -196,6 +185,9 @@ public:
// where a deadlock can occur
Common::Mutex _mutex;
+ int16 tryToOwnChannel(MusicEntry *caller, int16 bestChannel);
+ void freeChannels(MusicEntry *caller);
+
protected:
void sortPlayList();
@@ -208,22 +200,16 @@ protected:
// Mixed AdLib/MIDI mode: when enabled from the ScummVM sound options screen,
// and a sound has a digital track, the sound from the AdLib track is played
bool _bMultiMidi;
-private:
- static void miditimerCallback(void *p);
- void findUsedChannels();
- int16 getNextUnusedChannel() const {
- for (int i = 0; i < 16; i++) {
- if (!_usedChannels[i])
- return i;
- }
-
- return -1;
- }
+private:
MusicList _playList;
bool _soundOn;
byte _masterVolume;
- bool _usedChannels[16];
+ MusicEntry *_usedChannel[16];
+
+ MidiCommandQueue _queuedCommands;
+
+ int _driverFirstChannel;
};
} // End of namespace Sci
diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp
index ece4c1430c..51832af09f 100644
--- a/engines/sci/sound/soundcmd.cpp
+++ b/engines/sci/sound/soundcmd.cpp
@@ -23,17 +23,12 @@
*
*/
-#include "sci/sci.h" // for USE_OLD_MUSIC_FUNCTIONS
-
-#ifdef USE_OLD_MUSIC_FUNCTIONS
-#include "sci/sound/iterator/iterator.h" // for SongIteratorStatus
-#endif
-
#include "common/config-manager.h"
#include "sci/sound/audio.h"
#include "sci/sound/music.h"
#include "sci/sound/soundcmd.h"
+#include "sci/engine/kernel.h"
#include "sci/engine/selector.h"
namespace Sci {
@@ -41,258 +36,29 @@ namespace Sci {
#define SCI1_SOUND_FLAG_MAY_PAUSE 1 /* Only here for completeness; The interpreter doesn't touch this bit */
#define SCI1_SOUND_FLAG_SCRIPTED_PRI 2 /* but does touch this */
-#ifdef USE_OLD_MUSIC_FUNCTIONS
-#define FROBNICATE_HANDLE(reg) ((reg).segment << 16 | (reg).offset)
-#define DEFROBNICATE_HANDLE(handle) (make_reg((handle >> 16) & 0xffff, handle & 0xffff))
-#endif
-
-#define SOUNDCOMMAND(x) _soundCommands.push_back(new MusicEntryCommand(#x, &SoundCommandParser::x))
-
-#ifdef USE_OLD_MUSIC_FUNCTIONS
-static void script_set_priority(ResourceManager *resMan, SegManager *segMan, SfxState *state, reg_t obj, int priority) {
- int song_nr = readSelectorValue(segMan, obj, SELECTOR(number));
- Resource *song = resMan->findResource(ResourceId(kResourceTypeSound, song_nr), 0);
- int flags = readSelectorValue(segMan, obj, SELECTOR(flags));
-
- if (priority == -1) {
- if (song->data[0] == 0xf0)
- priority = song->data[1];
- else
- warning("Attempt to unset song priority when there is no built-in value");
-
- flags &= ~SCI1_SOUND_FLAG_SCRIPTED_PRI;
- } else flags |= SCI1_SOUND_FLAG_SCRIPTED_PRI;
-
- state->sfx_song_renice(FROBNICATE_HANDLE(obj), priority);
- writeSelectorValue(segMan, obj, SELECTOR(flags), flags);
-}
-
-SongIterator *build_iterator(ResourceManager *resMan, int song_nr, SongIteratorType type, songit_id_t id) {
- Resource *song = resMan->findResource(ResourceId(kResourceTypeSound, song_nr), 0);
-
- if (!song)
- return NULL;
-
- return songit_new(song->data, song->size, type, id);
-}
-
-void process_sound_events(EngineState *s) { /* Get all sound events, apply their changes to the heap */
- int result;
- SongHandle handle;
- int cue;
- SegManager *segMan = s->_segMan;
-
- if (getSciVersion() > SCI_VERSION_01)
- return;
- // SCI1 and later explicitly poll for everything
-
- while ((result = s->_sound.sfx_poll(&handle, &cue))) {
- reg_t obj = DEFROBNICATE_HANDLE(handle);
- if (!s->_segMan->isObject(obj)) {
- warning("Non-object %04x:%04x received sound signal (%d/%d)", PRINT_REG(obj), result, cue);
- return;
- }
-
- switch (result) {
-
- case SI_LOOP:
- debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x looped (to %d)",
- PRINT_REG(obj), cue);
- /* writeSelectorValue(segMan, obj, SELECTOR(loops), readSelectorValue(segMan, obj, SELECTOR(loop));; - 1);*/
- writeSelectorValue(segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
- break;
-
- case SI_RELATIVE_CUE:
- debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x received relative cue %d",
- PRINT_REG(obj), cue);
- writeSelectorValue(segMan, obj, SELECTOR(signal), cue + 0x7f);
- break;
-
- case SI_ABSOLUTE_CUE:
- debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x received absolute cue %d",
- PRINT_REG(obj), cue);
- writeSelectorValue(segMan, obj, SELECTOR(signal), cue);
- break;
-
- case SI_FINISHED:
- debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x finished",
- PRINT_REG(obj));
- writeSelectorValue(segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
- writeSelectorValue(segMan, obj, SELECTOR(state), kSoundStopped);
- break;
-
- default:
- warning("Unexpected result from sfx_poll: %d", result);
- break;
- }
- }
-}
-
-#endif
SoundCommandParser::SoundCommandParser(ResourceManager *resMan, SegManager *segMan, Kernel *kernel, AudioPlayer *audio, SciVersion soundVersion) :
_resMan(resMan), _segMan(segMan), _kernel(kernel), _audio(audio), _soundVersion(soundVersion) {
-#ifdef USE_OLD_MUSIC_FUNCTIONS
- // The following hack is needed to ease the change from old to new sound code (because the new sound code does not use SfxState)
- _state = &g_sci->getEngineState()->_sound; // HACK
-#endif
-
- #ifndef USE_OLD_MUSIC_FUNCTIONS
- _music = new SciMusic(_soundVersion);
- _music->init();
- #endif
-
- switch (_soundVersion) {
- case SCI_VERSION_0_EARLY:
- case SCI_VERSION_0_LATE:
- SOUNDCOMMAND(cmdInitSound);
- SOUNDCOMMAND(cmdPlaySound);
- SOUNDCOMMAND(cmdDummy);
- SOUNDCOMMAND(cmdDisposeSound);
- SOUNDCOMMAND(cmdMuteSound);
- SOUNDCOMMAND(cmdStopSound);
- SOUNDCOMMAND(cmdPauseSound);
- SOUNDCOMMAND(cmdResumeSound);
- SOUNDCOMMAND(cmdMasterVolume);
- SOUNDCOMMAND(cmdUpdateSound);
- SOUNDCOMMAND(cmdFadeSound);
- SOUNDCOMMAND(cmdGetPolyphony);
- SOUNDCOMMAND(cmdStopAllSounds);
- _cmdUpdateCuesIndex = -1;
- break;
- case SCI_VERSION_1_EARLY:
- SOUNDCOMMAND(cmdMasterVolume);
- SOUNDCOMMAND(cmdMuteSound);
- SOUNDCOMMAND(cmdDummy);
- SOUNDCOMMAND(cmdGetPolyphony);
- SOUNDCOMMAND(cmdUpdateSound);
- SOUNDCOMMAND(cmdInitSound);
- SOUNDCOMMAND(cmdDisposeSound);
- SOUNDCOMMAND(cmdPlaySound);
- SOUNDCOMMAND(cmdStopSound);
- SOUNDCOMMAND(cmdPauseSound);
- SOUNDCOMMAND(cmdFadeSound);
- SOUNDCOMMAND(cmdUpdateCues);
- SOUNDCOMMAND(cmdSendMidi);
- SOUNDCOMMAND(cmdReverb);
- SOUNDCOMMAND(cmdSetSoundHold);
- _cmdUpdateCuesIndex = 11;
- break;
- case SCI_VERSION_1_LATE:
- SOUNDCOMMAND(cmdMasterVolume);
- SOUNDCOMMAND(cmdMuteSound);
- SOUNDCOMMAND(cmdDummy);
- SOUNDCOMMAND(cmdGetPolyphony);
- SOUNDCOMMAND(cmdGetAudioCapability);
- SOUNDCOMMAND(cmdSuspendSound);
- SOUNDCOMMAND(cmdInitSound);
- SOUNDCOMMAND(cmdDisposeSound);
- SOUNDCOMMAND(cmdPlaySound);
- SOUNDCOMMAND(cmdStopSound);
- SOUNDCOMMAND(cmdPauseSound);
- SOUNDCOMMAND(cmdFadeSound);
- SOUNDCOMMAND(cmdSetSoundHold);
- SOUNDCOMMAND(cmdDummy);
- SOUNDCOMMAND(cmdSetSoundVolume);
- SOUNDCOMMAND(cmdSetSoundPriority);
- SOUNDCOMMAND(cmdSetSoundLoop);
- SOUNDCOMMAND(cmdUpdateCues);
- SOUNDCOMMAND(cmdSendMidi);
- SOUNDCOMMAND(cmdReverb);
- SOUNDCOMMAND(cmdUpdateSound);
- _cmdUpdateCuesIndex = 17;
- break;
- default:
- warning("Sound command parser: unknown sound version %d", _soundVersion);
- break;
- }
+ _music = new SciMusic(_soundVersion);
+ _music->init();
}
SoundCommandParser::~SoundCommandParser() {
- for (SoundCommandContainer::iterator i = _soundCommands.begin(); i != _soundCommands.end(); ++i)
- delete *i;
-
-#ifndef USE_OLD_MUSIC_FUNCTIONS
delete _music;
-#endif
}
-reg_t SoundCommandParser::parseCommand(int argc, reg_t *argv, reg_t acc) {
- uint16 command = argv[0].toUint16();
- reg_t obj = (argc > 1) ? argv[1] : NULL_REG;
- int16 value = (argc > 2) ? argv[2].toSint16() : 0;
- _acc = acc;
- _argc = argc;
- _argv = argv;
-
- if (argc == 6) { // cmdSendMidi
- byte channel = argv[2].toUint16() & 0xf;
- byte midiCmd = argv[3].toUint16() & 0xff;
-
- uint16 controller = argv[4].toUint16();
- uint16 param = argv[5].toUint16();
-
- _midiCommand = (channel | midiCmd) | ((uint32)controller << 8) | ((uint32)param << 16);
- }
-
- if (command < _soundCommands.size()) {
- if (command != _cmdUpdateCuesIndex) {
- //printf("%s, object %04x:%04x\n", _soundCommands[command]->desc, PRINT_REG(obj)); // debug
- debugC(2, kDebugLevelSound, "%s, object %04x:%04x", _soundCommands[command]->desc, PRINT_REG(obj));
- }
-
- (this->*(_soundCommands[command]->sndCmd))(obj, value);
- } else {
- warning("Invalid sound command requested (%d), valid range is 0-%d", command, _soundCommands.size() - 1);
- }
-
- return _acc;
+reg_t SoundCommandParser::kDoSoundInit(int argc, reg_t *argv, reg_t acc) {
+ processInitSound(argv[0]);
+ return acc;
}
-void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) {
- if (!obj.segment)
- return;
-
+void SoundCommandParser::processInitSound(reg_t obj) {
int resourceId = readSelectorValue(_segMan, obj, SELECTOR(number));
-#ifdef USE_OLD_MUSIC_FUNCTIONS
-
- SongHandle handle = FROBNICATE_HANDLE(obj);
-
- if (_soundVersion != SCI_VERSION_1_LATE) {
- if (!obj.segment)
- return;
- }
-
- SongIteratorType type = (_soundVersion <= SCI_VERSION_0_LATE) ? SCI_SONG_ITERATOR_TYPE_SCI0 : SCI_SONG_ITERATOR_TYPE_SCI1;
-
- if (_soundVersion <= SCI_VERSION_0_LATE) {
- if (readSelectorValue(_segMan, obj, SELECTOR(nodePtr))) {
- _state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
- _state->sfx_remove_song(handle);
- }
- }
-
- if (!obj.segment || !_resMan->testResource(ResourceId(kResourceTypeSound, resourceId)))
- return;
-
- _state->sfx_add_song(build_iterator(_resMan, resourceId, type, handle), 0, handle, resourceId);
-
-
- // Notify the engine
- if (_soundVersion <= SCI_VERSION_0_LATE)
- writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundInitialized);
- else
- writeSelector(_segMan, obj, SELECTOR(nodePtr), obj);
-
- writeSelector(_segMan, obj, SELECTOR(handle), obj);
-
-#else
-
// Check if a track with the same sound object is already playing
MusicEntry *oldSound = _music->getSlot(obj);
if (oldSound)
- cmdDisposeSound(obj, value);
+ processDisposeSound(obj);
MusicEntry *newSound = new MusicEntry();
newSound->resourceId = resourceId;
@@ -307,6 +73,9 @@ void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) {
if (_soundVersion >= SCI_VERSION_1_EARLY)
newSound->volume = CLIP<int>(readSelectorValue(_segMan, obj, SELECTOR(vol)), 0, MUSIC_VOLUME_MAX);
+ debugC(2, kDebugLevelSound, "kDoSound(init): number %d, loop %d, prio %d, vol %d", resourceId,
+ newSound->loop, newSound->priority, newSound->volume);
+
// In SCI1.1 games, sound effects are started from here. If we can find
// a relevant audio resource, play it, otherwise switch to synthesized
// effects. If the resource exists, play it using map 65535 (sound
@@ -333,98 +102,28 @@ void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) {
writeSelector(_segMan, obj, SELECTOR(handle), obj);
}
-#endif
-
}
-void SoundCommandParser::cmdPlaySound(reg_t obj, int16 value) {
- if (!obj.segment)
- return;
-
-#ifdef USE_OLD_MUSIC_FUNCTIONS
- SongHandle handle = FROBNICATE_HANDLE(obj);
-
- if (_soundVersion <= SCI_VERSION_0_LATE) {
- _state->sfx_song_set_status(handle, SOUND_STATUS_PLAYING);
- _state->sfx_song_set_loops(handle, readSelectorValue(_segMan, obj, SELECTOR(loop)));
- writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundPlaying);
- } else if (_soundVersion == SCI_VERSION_1_EARLY) {
- _state->sfx_song_set_status(handle, SOUND_STATUS_PLAYING);
- _state->sfx_song_set_loops(handle, readSelectorValue(_segMan, obj, SELECTOR(loop)));
- _state->sfx_song_renice(handle, readSelectorValue(_segMan, obj, SELECTOR(pri)));
- RESTORE_BEHAVIOR rb = (RESTORE_BEHAVIOR) value; /* Too lazy to look up a default value for this */
- _state->_songlib.setSongRestoreBehavior(handle, rb);
- writeSelectorValue(_segMan, obj, SELECTOR(signal), 0);
- } else if (_soundVersion == SCI_VERSION_1_LATE) {
- int looping = readSelectorValue(_segMan, obj, SELECTOR(loop));
- //int vol = readSelectorValue(_segMan, obj, SELECTOR(vol));
- int pri = readSelectorValue(_segMan, obj, SELECTOR(pri));
- int sampleLen = 0;
- Song *song = _state->_songlib.findSong(handle);
- int songNumber = readSelectorValue(_segMan, obj, SELECTOR(number));
-
- if (readSelectorValue(_segMan, obj, SELECTOR(nodePtr)) && (song && songNumber != song->_resourceNum)) {
- _state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
- _state->sfx_remove_song(handle);
- writeSelector(_segMan, obj, SELECTOR(nodePtr), NULL_REG);
- }
-
- if (!readSelectorValue(_segMan, obj, SELECTOR(nodePtr)) && obj.segment) {
- // In SCI1.1 games, sound effects are started from here. If we can find
- // a relevant audio resource, play it, otherwise switch to synthesized
- // effects. If the resource exists, play it using map 65535 (sound
- // effects map)
- if (_resMan->testResource(ResourceId(kResourceTypeAudio, songNumber)) &&
- getSciVersion() >= SCI_VERSION_1_1) {
- // Found a relevant audio resource, play it
- _audio->stopAudio();
- warning("Initializing audio resource instead of requested sound resource %d", songNumber);
- sampleLen = _audio->startAudio(65535, songNumber);
- // Also create iterator, that will fire SI_FINISHED event, when the sound is done playing
- _state->sfx_add_song(new_timer_iterator(sampleLen), 0, handle, songNumber);
- } else {
- if (!_resMan->testResource(ResourceId(kResourceTypeSound, songNumber))) {
- warning("Could not open song number %d", songNumber);
- // Send a "stop handle" event so that the engine won't wait forever here
- _state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
- writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
- return;
- }
- debugC(2, kDebugLevelSound, "Initializing song number %d", songNumber);
- _state->sfx_add_song(build_iterator(_resMan, songNumber, SCI_SONG_ITERATOR_TYPE_SCI1,
- handle), 0, handle, songNumber);
- }
-
- writeSelector(_segMan, obj, SELECTOR(nodePtr), obj);
- writeSelector(_segMan, obj, SELECTOR(handle), obj);
- }
-
- if (obj.segment) {
- _state->sfx_song_set_status(handle, SOUND_STATUS_PLAYING);
- _state->sfx_song_set_loops(handle, looping);
- _state->sfx_song_renice(handle, pri);
- writeSelectorValue(_segMan, obj, SELECTOR(signal), 0);
- }
- }
-
-#else
+reg_t SoundCommandParser::kDoSoundPlay(int argc, reg_t *argv, reg_t acc) {
+ processPlaySound(argv[0]);
+ return acc;
+}
+void SoundCommandParser::processPlaySound(reg_t obj) {
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
- warning("cmdPlaySound: Slot not found (%04x:%04x)", PRINT_REG(obj));
+ warning("kDoSound(play): Slot not found (%04x:%04x)", PRINT_REG(obj));
return;
}
int resourceId = obj.segment ? readSelectorValue(_segMan, obj, SELECTOR(number)) : -1;
if (musicSlot->resourceId != resourceId) { // another sound loaded into struct
- cmdDisposeSound(obj, value);
- cmdInitSound(obj, value);
+ processDisposeSound(obj);
+ processInitSound(obj);
// Find slot again :)
musicSlot = _music->getSlot(obj);
}
- int16 loop = readSelectorValue(_segMan, obj, SELECTOR(loop));
- debugC(2, kDebugLevelSound, "cmdPlaySound: resource number %d, loop %d", resourceId, loop);
writeSelector(_segMan, obj, SELECTOR(handle), obj);
@@ -442,51 +141,31 @@ void SoundCommandParser::cmdPlaySound(reg_t obj, int16 value) {
musicSlot->priority = readSelectorValue(_segMan, obj, SELECTOR(priority));
if (_soundVersion >= SCI_VERSION_1_EARLY)
musicSlot->volume = readSelectorValue(_segMan, obj, SELECTOR(vol));
- _music->soundPlay(musicSlot);
-#endif
+ debugC(2, kDebugLevelSound, "kDoSound(play): number %d, loop %d, prio %d, vol %d", resourceId,
+ musicSlot->loop, musicSlot->priority, musicSlot->volume);
+ _music->soundPlay(musicSlot);
}
-void SoundCommandParser::cmdDummy(reg_t obj, int16 value) {
+reg_t SoundCommandParser::kDoSoundDummy(int argc, reg_t *argv, reg_t acc) {
warning("cmdDummy invoked"); // not supposed to occur
+ return acc;
}
-#ifdef USE_OLD_MUSIC_FUNCTIONS
-void SoundCommandParser::changeSoundStatus(reg_t obj, int newStatus) {
- SongHandle handle = FROBNICATE_HANDLE(obj);
- if (obj.segment) {
- _state->sfx_song_set_status(handle, newStatus);
- if (_soundVersion <= SCI_VERSION_0_LATE)
- writeSelectorValue(_segMan, obj, SELECTOR(state), newStatus);
- }
+reg_t SoundCommandParser::kDoSoundDispose(int argc, reg_t *argv, reg_t acc) {
+ processDisposeSound(argv[0]);
+ return acc;
}
-#endif
-
-void SoundCommandParser::cmdDisposeSound(reg_t obj, int16 value) {
- if (!obj.segment)
- return;
-
-#ifdef USE_OLD_MUSIC_FUNCTIONS
- SongHandle handle = FROBNICATE_HANDLE(obj);
- changeSoundStatus(obj, SOUND_STATUS_STOPPED);
-
- if (obj.segment) {
- _state->sfx_remove_song(handle);
-
- if (_soundVersion <= SCI_VERSION_0_LATE)
- writeSelectorValue(_segMan, obj, SELECTOR(handle), 0x0000);
- }
-
-#else
+void SoundCommandParser::processDisposeSound(reg_t obj) {
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
- warning("cmdDisposeSound: Slot not found (%04x:%04x)", PRINT_REG(obj));
+ warning("kDoSound(dispose): Slot not found (%04x:%04x)", PRINT_REG(obj));
return;
}
- cmdStopSound(obj, value);
+ processStopSound(obj, false);
_music->soundKill(musicSlot);
writeSelectorValue(_segMan, obj, SELECTOR(handle), 0);
@@ -494,26 +173,17 @@ void SoundCommandParser::cmdDisposeSound(reg_t obj, int16 value) {
writeSelector(_segMan, obj, SELECTOR(nodePtr), NULL_REG);
else
writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundStopped);
-#endif
}
-void SoundCommandParser::cmdStopSound(reg_t obj, int16 value) {
- processStopSound(obj, value, false);
+reg_t SoundCommandParser::kDoSoundStop(int argc, reg_t *argv, reg_t acc) {
+ processStopSound(argv[0], false);
+ return acc;
}
-void SoundCommandParser::processStopSound(reg_t obj, int16 value, bool sampleFinishedPlaying) {
- if (!obj.segment)
- return;
-
-#ifdef USE_OLD_MUSIC_FUNCTIONS
- changeSoundStatus(obj, SOUND_STATUS_STOPPED);
-
- if (_soundVersion >= SCI_VERSION_1_EARLY)
- writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
-#else
+void SoundCommandParser::processStopSound(reg_t obj, bool sampleFinishedPlaying) {
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
- warning("cmdStopSound: Slot not found (%04x:%04x)", PRINT_REG(obj));
+ warning("kDoSound(stop): Slot not found (%04x:%04x)", PRINT_REG(obj));
return;
}
@@ -523,204 +193,156 @@ void SoundCommandParser::processStopSound(reg_t obj, int16 value, bool sampleFin
writeSelectorValue(_segMan, obj, SELECTOR(handle), 0);
}
- // Set signal selector in sound SCI0 games only, when the sample has finished playing
- // If we don't set it at all, we get a problem when using vaporizer on the 2 guys
- // If we set it all the time, we get no music in sq3new and kq1
- // FIXME: this *may* be wrong, it's impossible to find out in sierra DOS sci, because SCI0 under DOS didn't have
- // sfx drivers included
- // We need to set signal in sound SCI1+ games all the time
+ // Set signal selector in sound SCI0 games only, when the sample has
+ // finished playing. If we don't set it at all, we get a problem when using
+ // vaporizer on the 2 guys. If we set it all the time, we get no music in
+ // sq3new and kq1.
+ // FIXME: This *may* be wrong, it's impossible to find out in Sierra DOS
+ // SCI, because SCI0 under DOS didn't have sfx drivers included.
+ // We need to set signal in sound SCI1+ games all the time.
if ((_soundVersion > SCI_VERSION_0_LATE) || sampleFinishedPlaying)
writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
musicSlot->dataInc = 0;
musicSlot->signal = 0;
_music->soundStop(musicSlot);
-#endif
}
-void SoundCommandParser::cmdPauseSound(reg_t obj, int16 value) {
-#ifdef USE_OLD_MUSIC_FUNCTIONS
- if (!obj.segment)
- return;
-
- if (_soundVersion <= SCI_VERSION_0_LATE)
- changeSoundStatus(obj, SOUND_STATUS_SUSPENDED);
- else
- changeSoundStatus(obj, value ? SOUND_STATUS_SUSPENDED : SOUND_STATUS_PLAYING);
-#else
+reg_t SoundCommandParser::kDoSoundPause(int argc, reg_t *argv, reg_t acc) {
+ if (_soundVersion <= SCI_VERSION_0_LATE) {
+ // SCI0 games give us 0/1 for either resuming or pausing the current music
+ // this one doesn't count, so pausing 2 times and resuming once means here that we are supposed to resume
+ uint16 value = argv[0].toUint16();
+ MusicEntry *musicSlot = _music->getActiveSci0MusicSlot();
+ switch (value) {
+ case 1:
+ if ((musicSlot) && (musicSlot->status == kSoundPlaying)) {
+ _music->soundPause(musicSlot);
+ writeSelectorValue(_segMan, musicSlot->soundObj, SELECTOR(state), kSoundPaused);
+ }
+ return make_reg(0, 0);
+ case 0:
+ if ((musicSlot) && (musicSlot->status == kSoundPaused)) {
+ _music->soundResume(musicSlot);
+ writeSelectorValue(_segMan, musicSlot->soundObj, SELECTOR(state), kSoundPlaying);
+ return make_reg(0, 1);
+ }
+ return make_reg(0, 0);
+ default:
+ error("kDoSound(pause): parameter 0 is invalid for sound-sci0");
+ }
+ }
+ reg_t obj = argv[0];
+ uint16 value = argc > 1 ? argv[1].toUint16() : 0;
if (!obj.segment) { // pause the whole playlist
- // Pausing/Resuming the whole playlist was introduced
- // in the SCI1 late sound scheme
- if (_soundVersion <= SCI_VERSION_1_EARLY)
- return;
-
_music->pauseAll(value);
} else { // pause a playlist slot
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
- warning("cmdPauseSound: Slot not found (%04x:%04x)", PRINT_REG(obj));
- return;
+ warning("kDoSound(pause): Slot not found (%04x:%04x)", PRINT_REG(obj));
+ return acc;
}
- if (_soundVersion <= SCI_VERSION_0_LATE) {
- // Always pause the sound in SCI0 games. It's resumed in cmdResumeSound()
- writeSelectorValue(_segMan, musicSlot->soundObj, SELECTOR(state), kSoundPaused);
- _music->soundPause(musicSlot);
- } else {
- _music->soundToggle(musicSlot, value);
- }
+ _music->soundToggle(musicSlot, value);
}
-
-#endif
+ return acc;
}
-void SoundCommandParser::cmdResumeSound(reg_t obj, int16 value) {
- // SCI0 only command
-
- if (!obj.segment)
- return;
+// SCI0 only command
+reg_t SoundCommandParser::kDoSoundResume(int argc, reg_t *argv, reg_t acc) {
+ // this doesn't seem to do what we think it's doing
+ // it's called with no arguments at all (just restore a game in qfg1)
+ return acc;
+ reg_t obj = argv[0];
-#ifdef USE_OLD_MUSIC_FUNCTIONS
- changeSoundStatus(obj, SOUND_STATUS_PLAYING);
-#else
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
- warning("cmdResumeSound: Slot not found (%04x:%04x)", PRINT_REG(obj));
- return;
+ warning("kDoSound(resume):: Slot not found (%04x:%04x)", PRINT_REG(obj));
+ return acc;
}
writeSelectorValue(_segMan, musicSlot->soundObj, SELECTOR(state), kSoundPlaying);
_music->soundResume(musicSlot);
-#endif
+ return acc;
}
-void SoundCommandParser::cmdMuteSound(reg_t obj, int16 value) {
-#ifndef USE_OLD_MUSIC_FUNCTIONS
- if (_argc > 1) // the first parameter is the sound command
- _music->soundSetSoundOn(obj.toUint16());
- _acc = make_reg(0, _music->soundGetSoundOn());
-#endif
+reg_t SoundCommandParser::kDoSoundMute(int argc, reg_t *argv, reg_t acc) {
+ if (argc > 0)
+ _music->soundSetSoundOn(argv[0].toUint16());
+ return make_reg(0, _music->soundGetSoundOn());
}
-void SoundCommandParser::cmdMasterVolume(reg_t obj, int16 value) {
-#ifdef USE_OLD_MUSIC_FUNCTIONS
- _acc = make_reg(0, _state->sfx_getVolume());
-
- if (obj != SIGNAL_REG)
- _state->sfx_setVolume(obj.toSint16());
-#else
- debugC(2, kDebugLevelSound, "cmdMasterVolume: %d", value);
- _acc = make_reg(0, _music->soundGetMasterVolume());
+reg_t SoundCommandParser::kDoSoundMasterVolume(int argc, reg_t *argv, reg_t acc) {
+ acc = make_reg(0, _music->soundGetMasterVolume());
- if (_argc > 1) { // the first parameter is the sound command
- int vol = CLIP<int16>(obj.toSint16(), 0, kMaxSciVolume);
+ if (argc > 0) {
+ debugC(2, kDebugLevelSound, "kDoSound(masterVolume): %d", argv[0].toSint16());
+ int vol = CLIP<int16>(argv[0].toSint16(), 0, kMaxSciVolume);
vol = vol * Audio::Mixer::kMaxMixerVolume / kMaxSciVolume;
ConfMan.setInt("music_volume", vol);
ConfMan.setInt("sfx_volume", vol);
g_engine->syncSoundSettings();
}
-#endif
+ return acc;
}
-void SoundCommandParser::cmdFadeSound(reg_t obj, int16 value) {
- if (!obj.segment)
- return;
+reg_t SoundCommandParser::kDoSoundFade(int argc, reg_t *argv, reg_t acc) {
+ reg_t obj = argv[0];
-#ifdef USE_OLD_MUSIC_FUNCTIONS
- SongHandle handle = FROBNICATE_HANDLE(obj);
- if (_soundVersion != SCI_VERSION_1_LATE) {
- /* FIXME: The next couple of lines actually STOP the handle, rather
- ** than fading it! */
- _state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
- if (_soundVersion <= SCI_VERSION_0_LATE)
- writeSelectorValue(_segMan, obj, SELECTOR(state), SOUND_STATUS_STOPPED);
- writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
- } else {
- fade_params_t fade;
- fade.final_volume = _argv[2].toUint16();
- fade.ticks_per_step = _argv[3].toUint16();
- fade.step_size = _argv[4].toUint16();
- fade.action = _argv[5].toUint16() ?
- FADE_ACTION_FADE_AND_STOP :
- FADE_ACTION_FADE_AND_CONT;
-
- _state->sfx_song_set_fade(handle, &fade);
-
- /* FIXME: The next couple of lines actually STOP the handle, rather
- ** than fading it! */
- if (_argv[5].toUint16()) {
- writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
- _state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
- } else {
- // FIXME: Support fade-and-continue. For now, send signal right away.
- writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
- }
- }
-#else
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
- warning("cmdFadeSound: Slot not found (%04x:%04x)", PRINT_REG(obj));
- return;
+ warning("kDoSound(fade): Slot not found (%04x:%04x)", PRINT_REG(obj));
+ return acc;
}
int volume = musicSlot->volume;
- switch (_argc) {
- case 2: // SCI0
- // SCI0 fades out all the time and when fadeout is done it will also stop the music from playing
+ // If sound is not playing currently, set signal directly
+ if (musicSlot->status != kSoundPlaying) {
+ debugC(2, kDebugLevelSound, "kDoSound(fade): fading requested, but sound is currently not playing");
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ return acc;
+ }
+
+ switch (argc) {
+ case 1: // SCI0
+ // SCI0 fades out all the time and when fadeout is done it will also
+ // stop the music from playing
musicSlot->fadeTo = 0;
musicSlot->fadeStep = -5;
musicSlot->fadeTickerStep = 10 * 16667 / _music->soundGetTempo();
musicSlot->fadeTicker = 0;
break;
- case 5: // SCI01+
- case 6: // SCI1+ (SCI1 late sound scheme), with fade and continue
- musicSlot->fadeTo = CLIP<uint16>(_argv[2].toUint16(), 0, MUSIC_VOLUME_MAX);
- musicSlot->fadeStep = volume > _argv[2].toUint16() ? -_argv[4].toUint16() : _argv[4].toUint16();
- musicSlot->fadeTickerStep = _argv[3].toUint16() * 16667 / _music->soundGetTempo();
+ case 4: // SCI01+
+ case 5: // SCI1+ (SCI1 late sound scheme), with fade and continue
+ musicSlot->fadeTo = CLIP<uint16>(argv[1].toUint16(), 0, MUSIC_VOLUME_MAX);
+ musicSlot->fadeStep = volume > argv[1].toUint16() ? -argv[3].toUint16() : argv[3].toUint16();
+ musicSlot->fadeTickerStep = argv[2].toUint16() * 16667 / _music->soundGetTempo();
musicSlot->fadeTicker = 0;
- musicSlot->stopAfterFading = (_argc == 6) ? (_argv[5].toUint16() != 0) : false;
+ musicSlot->stopAfterFading = (argc == 5) ? (argv[4].toUint16() != 0) : false;
break;
default:
- error("cmdFadeSound: unsupported argc %d", _argc);
- }
-
- // If sound is not playing currently, set signal directly
- if (musicSlot->status != kSoundPlaying) {
- warning("cmdFadeSound: fading requested, but sound is currently not playing");
- writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ error("kDoSound(fade): unsupported argc %d", argc);
}
- debugC(2, kDebugLevelSound, "cmdFadeSound: to %d, step %d, ticker %d", musicSlot->fadeTo, musicSlot->fadeStep, musicSlot->fadeTickerStep);
-#endif
+ debugC(2, kDebugLevelSound, "kDoSound(fade): to %d, step %d, ticker %d", musicSlot->fadeTo, musicSlot->fadeStep, musicSlot->fadeTickerStep);
+ return acc;
}
-void SoundCommandParser::cmdGetPolyphony(reg_t obj, int16 value) {
-#ifdef USE_OLD_MUSIC_FUNCTIONS
- _acc = make_reg(0, _state->sfx_get_player_polyphony());
-#else
- _acc = make_reg(0, _music->soundGetVoices()); // Get the number of voices
-#endif
+reg_t SoundCommandParser::kDoSoundGetPolyphony(int argc, reg_t *argv, reg_t acc) {
+ return make_reg(0, _music->soundGetVoices()); // Get the number of voices
}
-void SoundCommandParser::cmdUpdateSound(reg_t obj, int16 value) {
- if (!obj.segment)
- return;
+reg_t SoundCommandParser::kDoSoundUpdate(int argc, reg_t *argv, reg_t acc) {
+ reg_t obj = argv[0];
-#ifdef USE_OLD_MUSIC_FUNCTIONS
- SongHandle handle = FROBNICATE_HANDLE(obj);
- if (_soundVersion <= SCI_VERSION_0_LATE && obj.segment) {
- _state->sfx_song_set_loops(handle, readSelectorValue(_segMan, obj, SELECTOR(loop)));
- script_set_priority(_resMan, _segMan, _state, obj, readSelectorValue(_segMan, obj, SELECTOR(pri)));
- }
-#else
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
- warning("cmdUpdateSound: Slot not found (%04x:%04x)", PRINT_REG(obj));
- return;
+ warning("kDoSound(update): Slot not found (%04x:%04x)", PRINT_REG(obj));
+ return acc;
}
musicSlot->loop = readSelectorValue(_segMan, obj, SELECTOR(loop));
@@ -730,88 +352,18 @@ void SoundCommandParser::cmdUpdateSound(reg_t obj, int16 value) {
uint32 objPrio = readSelectorValue(_segMan, obj, SELECTOR(pri));
if (objPrio != musicSlot->priority)
_music->soundSetPriority(musicSlot, objPrio);
-
-#endif
+ return acc;
}
-void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
- if (!obj.segment)
- return;
-
-#ifdef USE_OLD_MUSIC_FUNCTIONS
- int signal = 0;
- int min = 0;
- int sec = 0;
- int frame = 0;
- int result = SI_LOOP; // small hack
- SongHandle handle = FROBNICATE_HANDLE(obj);
-
- while (result == SI_LOOP)
- result = _state->sfx_poll_specific(handle, &signal);
-
- switch (result) {
- case SI_ABSOLUTE_CUE:
- debugC(2, kDebugLevelSound, "--- [CUE] %04x:%04x Absolute Cue: %d",
- PRINT_REG(obj), signal);
- debugC(2, kDebugLevelSound, "abs-signal %04X", signal);
- writeSelectorValue(_segMan, obj, SELECTOR(signal), signal);
- break;
-
- case SI_RELATIVE_CUE:
- debugC(2, kDebugLevelSound, "--- [CUE] %04x:%04x Relative Cue: %d",
- PRINT_REG(obj), signal);
-
- /* FIXME to match commented-out semantics
- * below, with proper storage of dataInc and
- * signal in the iterator code. */
- writeSelectorValue(_segMan, obj, SELECTOR(dataInc), signal);
- debugC(2, kDebugLevelSound, "rel-signal %04X", signal);
- if (_soundVersion == SCI_VERSION_1_EARLY)
- writeSelectorValue(_segMan, obj, SELECTOR(signal), signal);
- else
- writeSelectorValue(_segMan, obj, SELECTOR(signal), signal + 127);
- break;
-
- case SI_FINISHED:
- debugC(2, kDebugLevelSound, "--- [FINISHED] %04x:%04x", PRINT_REG(obj));
- writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
- break;
-
- case SI_LOOP:
- break; // Doesn't happen
- }
+reg_t SoundCommandParser::kDoSoundUpdateCues(int argc, reg_t *argv, reg_t acc) {
+ processUpdateCues(argv[0]);
+ return acc;
+}
- //switch (signal) {
- //case 0x00:
- // if (dataInc != readSelectorValue(segMan, obj, SELECTOR(dataInc))) {
- // writeSelectorValue(segMan, obj, SELECTOR(dataInc), dataInc);
- // writeSelectorValue(segMan, obj, SELECTOR(signal), dataInc+0x7f);
- // } else {
- // writeSelectorValue(segMan, obj, SELECTOR(signal), signal);
- // }
- // break;
- //case 0xFF: // May be unnecessary
- // s->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
- // break;
- //default :
- // if (dataInc != readSelectorValue(segMan, obj, SELECTOR(dataInc))) {
- // writeSelectorValue(segMan, obj, SELECTOR(dataInc), dataInc);
- // writeSelectorValue(segMan, obj, SELECTOR(signal), dataInc + 0x7f);
- // } else {
- // writeSelectorValue(segMan, obj, SELECTOR(signal), signal);
- // }
- // break;
- //}
-
- if (_soundVersion == SCI_VERSION_1_EARLY) {
- writeSelectorValue(_segMan, obj, SELECTOR(min), min);
- writeSelectorValue(_segMan, obj, SELECTOR(sec), sec);
- writeSelectorValue(_segMan, obj, SELECTOR(frame), frame);
- }
-#else
+void SoundCommandParser::processUpdateCues(reg_t obj) {
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
- warning("cmdUpdateCues: Slot not found (%04x:%04x)", PRINT_REG(obj));
+ warning("kDoSound(updateCues): Slot not found (%04x:%04x)", PRINT_REG(obj));
return;
}
@@ -828,7 +380,7 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
musicSlot->sampleLoopCounter = currentLoopCounter;
}
if ((!_music->soundIsActive(musicSlot)) && (musicSlot->status != kSoundPaused)) {
- processStopSound(obj, 0, true);
+ processStopSound(obj, true);
} else {
_music->updateAudioStreamTicker(musicSlot);
}
@@ -841,7 +393,7 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
// Update MIDI slots
if (musicSlot->signal == 0) {
if (musicSlot->dataInc != readSelectorValue(_segMan, obj, SELECTOR(dataInc))) {
- if (_kernel->_selectorCache.dataInc > -1)
+ if (SELECTOR(dataInc) > -1)
writeSelectorValue(_segMan, obj, SELECTOR(dataInc), musicSlot->dataInc);
writeSelectorValue(_segMan, obj, SELECTOR(signal), musicSlot->dataInc + 127);
}
@@ -850,13 +402,15 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
writeSelectorValue(_segMan, obj, SELECTOR(signal), musicSlot->signal);
// We need to do this especially because state selector needs to get updated
if (musicSlot->signal == SIGNAL_OFFSET)
- cmdStopSound(obj, 0);
+ processStopSound(obj, false);
}
} else {
- // Slot actually has no data (which would mean that a sound-resource w/ unsupported data is used
+ // Slot actually has no data (which would mean that a sound-resource w/
+ // unsupported data is used.
// (example lsl5 - sound resource 744 - it's roland exclusive
writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
- // If we don't set signal here, at least the switch to the mud wrestling room in lsl5 will not work
+ // If we don't set signal here, at least the switch to the mud wrestling
+ // room in lsl5 will not work.
}
if (musicSlot->fadeCompleted) {
@@ -864,10 +418,10 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
// We need signal for sci0 at least in iceman as well (room 14, fireworks)
writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
if (_soundVersion <= SCI_VERSION_0_LATE) {
- cmdStopSound(obj, 0);
+ processStopSound(obj, false);
} else {
if (musicSlot->stopAfterFading)
- cmdStopSound(obj, 0);
+ processStopSound(obj, false);
}
}
@@ -882,48 +436,58 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
writeSelectorValue(_segMan, obj, SELECTOR(sec), musicSlot->ticker % 3600 / 60);
writeSelectorValue(_segMan, obj, SELECTOR(frame), musicSlot->ticker);
}
-
-#endif
}
-void SoundCommandParser::cmdSendMidi(reg_t obj, int16 value) {
-#ifdef USE_OLD_MUSIC_FUNCTIONS
- //SongHandle handle = FROBNICATE_HANDLE(obj);
- //_state->sfx_send_midi(handle, value, _midiCmd, _controller, _param);
-#else
- _music->sendMidiCommand(_midiCommand);
-#endif
+reg_t SoundCommandParser::kDoSoundSendMidi(int argc, reg_t *argv, reg_t acc) {
+ reg_t obj = argv[0];
+ byte channel = argv[1].toUint16() & 0xf;
+ byte midiCmd = argv[2].toUint16() & 0xff;
+
+ uint16 controller = argv[3].toUint16();
+ uint16 param = argv[4].toUint16();
+
+ if (channel)
+ channel--; // channel is given 1-based, we are using 0-based
+
+ uint32 midiCommand = (channel | midiCmd) | ((uint32)controller << 8) | ((uint32)param << 16);
+
+ MusicEntry *musicSlot = _music->getSlot(obj);
+ if (!musicSlot) {
+ // TODO: maybe it's possible to call this with obj == 0:0 and send directly?!
+ // if so, allow it
+ //_music->sendMidiCommand(_midiCommand);
+ warning("kDoSound(sendMidi): Slot not found (%04x:%04x)", PRINT_REG(obj));
+ return acc;
+ }
+ _music->sendMidiCommand(musicSlot, midiCommand);
+ return acc;
}
-void SoundCommandParser::cmdReverb(reg_t obj, int16 value) {
-#ifndef USE_OLD_MUSIC_FUNCTIONS
- _music->setReverb(obj.toUint16() & 0xF);
-#endif
+reg_t SoundCommandParser::kDoSoundReverb(int argc, reg_t *argv, reg_t acc) {
+ _music->setReverb(argv[0].toUint16() & 0xF);
+ return acc;
}
-void SoundCommandParser::cmdSetSoundHold(reg_t obj, int16 value) {
-#ifdef USE_OLD_MUSIC_FUNCTIONS
- SongHandle handle = FROBNICATE_HANDLE(obj);
- _state->sfx_song_set_hold(handle, value);
-#else
+reg_t SoundCommandParser::kDoSoundSetHold(int argc, reg_t *argv, reg_t acc) {
+ reg_t obj = argv[0];
+
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
- warning("cmdSetSoundHold: Slot not found (%04x:%04x)", PRINT_REG(obj));
- return;
+ warning("kDoSound(setHold): Slot not found (%04x:%04x)", PRINT_REG(obj));
+ return acc;
}
// Set the special hold marker ID where the song should be looped at.
- musicSlot->hold = value;
-#endif
+ musicSlot->hold = argv[1].toSint16();
+ return acc;
}
-void SoundCommandParser::cmdGetAudioCapability(reg_t obj, int16 value) {
+reg_t SoundCommandParser::kDoSoundGetAudioCapability(int argc, reg_t *argv, reg_t acc) {
// Tests for digital audio support
- _acc = make_reg(0, 1);
+ return make_reg(0, 1);
}
-void SoundCommandParser::cmdStopAllSounds(reg_t obj, int16 value) {
-#ifndef USE_OLD_MUSIC_FUNCTIONS
+reg_t SoundCommandParser::kDoSoundStopAll(int argc, reg_t *argv, reg_t acc) {
Common::StackLock(_music->_mutex);
const MusicList::iterator end = _music->getPlayListEnd();
@@ -931,32 +495,31 @@ void SoundCommandParser::cmdStopAllSounds(reg_t obj, int16 value) {
if (_soundVersion <= SCI_VERSION_0_LATE) {
writeSelectorValue(_segMan, (*i)->soundObj, SELECTOR(state), kSoundStopped);
} else {
- writeSelectorValue(_segMan, obj, SELECTOR(handle), 0);
+ writeSelectorValue(_segMan, (*i)->soundObj, SELECTOR(handle), 0);
writeSelectorValue(_segMan, (*i)->soundObj, SELECTOR(signal), SIGNAL_OFFSET);
}
(*i)->dataInc = 0;
_music->soundStop(*i);
}
-#endif
+ return acc;
}
-void SoundCommandParser::cmdSetSoundVolume(reg_t obj, int16 value) {
- if (!obj.segment)
- return;
+reg_t SoundCommandParser::kDoSoundSetVolume(int argc, reg_t *argv, reg_t acc) {
+ reg_t obj = argv[0];
+ int16 value = argv[1].toSint16();
-#ifndef USE_OLD_MUSIC_FUNCTIONS
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
// Do not throw a warning if the sound can't be found, as in some games
- // this is called before the actual sound is loaded (e.g. SQ4CD, with the
- // drum sounds of the energizer bunny at the beginning), so this is normal
- // behavior
+ // this is called before the actual sound is loaded (e.g. SQ4CD, with
+ // the drum sounds of the energizer bunny at the beginning), so this is
+ // normal behavior.
//warning("cmdSetSoundVolume: Slot not found (%04x:%04x)", PRINT_REG(obj));
- return;
+ return acc;
}
- debugC(2, kDebugLevelSound, "cmdSetSoundVolume: %d", value);
+ debugC(2, kDebugLevelSound, "kDoSound(setVolume): %d", value);
value = CLIP<int>(value, 0, MUSIC_VOLUME_MAX);
@@ -965,20 +528,17 @@ void SoundCommandParser::cmdSetSoundVolume(reg_t obj, int16 value) {
_music->soundSetVolume(musicSlot, value);
writeSelectorValue(_segMan, obj, SELECTOR(vol), value);
}
-#endif
+ return acc;
}
-void SoundCommandParser::cmdSetSoundPriority(reg_t obj, int16 value) {
- if (!obj.segment)
- return;
+reg_t SoundCommandParser::kDoSoundSetPriority(int argc, reg_t *argv, reg_t acc) {
+ reg_t obj = argv[0];
+ int16 value = argv[1].toSint16();
-#ifdef USE_OLD_MUSIC_FUNCTIONS
- script_set_priority(_resMan, _segMan, _state, obj, value);
-#else
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
- warning("cmdSetSoundPriority: Slot not found (%04x:%04x)", PRINT_REG(obj));
- return;
+ warning("kDoSound(setPriority): Slot not found (%04x:%04x)", PRINT_REG(obj));
+ return acc;
}
if (value == -1) {
@@ -987,7 +547,7 @@ void SoundCommandParser::cmdSetSoundPriority(reg_t obj, int16 value) {
if (song->data[0] == 0xf0)
_music->soundSetPriority(musicSlot, song->data[1]);
else
- warning("cmdSetSoundPriority: Attempt to unset song priority when there is no built-in value");
+ warning("kDoSound(setPriority): Attempt to unset song priority when there is no built-in value");
//pSnd->prio=0;field_15B=0
writeSelectorValue(_segMan, obj, SELECTOR(flags), readSelectorValue(_segMan, obj, SELECTOR(flags)) & 0xFD);
@@ -998,32 +558,26 @@ void SoundCommandParser::cmdSetSoundPriority(reg_t obj, int16 value) {
writeSelectorValue(_segMan, obj, SELECTOR(flags), readSelectorValue(_segMan, obj, SELECTOR(flags)) | 2);
//DoSOund(0xF,hobj,w)
}
-#endif
+ return acc;
}
-void SoundCommandParser::cmdSetSoundLoop(reg_t obj, int16 value) {
- if (!obj.segment)
- return;
+reg_t SoundCommandParser::kDoSoundSetLoop(int argc, reg_t *argv, reg_t acc) {
+ reg_t obj = argv[0];
+ int16 value = argv[1].toSint16();
-#ifdef USE_OLD_MUSIC_FUNCTIONS
- if (!readSelector(_segMan, obj, SELECTOR(nodePtr)).isNull()) {
- SongHandle handle = FROBNICATE_HANDLE(obj);
- _state->sfx_song_set_loops(handle, value);
- }
-#else
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
// Apparently, it's perfectly normal for a game to call cmdSetSoundLoop
// before actually initializing the sound and adding it to the playlist
// with cmdInitSound. Usually, it doesn't matter if the game doesn't
// request to loop the sound, so in this case, don't throw any warning,
- // otherwise do, because the sound won't be looped
+ // otherwise do, because the sound won't be looped.
if (value == -1) {
- warning("cmdSetSoundLoop: Slot not found (%04x:%04x) and the song was requested to be looped", PRINT_REG(obj));
+ warning("kDoSound(setLoop): Slot not found (%04x:%04x) and the song was requested to be looped", PRINT_REG(obj));
} else {
// Doesn't really matter
}
- return;
+ return acc;
}
if (value == -1) {
musicSlot->loop = 0xFFFF;
@@ -1032,40 +586,37 @@ void SoundCommandParser::cmdSetSoundLoop(reg_t obj, int16 value) {
}
writeSelectorValue(_segMan, obj, SELECTOR(loop), musicSlot->loop);
-#endif
+ return acc;
}
-void SoundCommandParser::cmdSuspendSound(reg_t obj, int16 value) {
+reg_t SoundCommandParser::kDoSoundSuspend(int argc, reg_t *argv, reg_t acc) {
// TODO
- warning("STUB: cmdSuspendSound");
+ warning("kDoSound(suspend): STUB");
+ return acc;
}
-#ifndef USE_OLD_MUSIC_FUNCTIONS
-
void SoundCommandParser::updateSci0Cues() {
bool noOnePlaying = true;
MusicEntry *pWaitingForPlay = NULL;
- _music->_mutex.lock();
-
const MusicList::iterator end = _music->getPlayListEnd();
for (MusicList::iterator i = _music->getPlayListStart(); i != end; ++i) {
// Is the sound stopped, and the sound object updated too? If yes, skip
- // this sound, as SCI0 only allows one active song
+ // this sound, as SCI0 only allows one active song.
if ((*i)->isQueued) {
pWaitingForPlay = (*i);
- // FIXME (?) - in iceman 2 songs are queued when playing the door sound - if we use the first song for resuming
- // then it's the wrong one. Both songs have same priority. Maybe the new sound function in sci0
- // is somehow responsible
+ // FIXME(?): In iceman 2 songs are queued when playing the door
+ // sound - if we use the first song for resuming then it's the wrong
+ // one. Both songs have same priority. Maybe the new sound function
+ // in sci0 is somehow responsible.
continue;
}
if ((*i)->signal == 0 && (*i)->status != kSoundPlaying)
continue;
- cmdUpdateCues((*i)->soundObj, 0);
+ processUpdateCues((*i)->soundObj);
noOnePlaying = false;
}
- _music->_mutex.unlock();
if (noOnePlaying && pWaitingForPlay) {
// If there is a queued entry, play it now ffs: SciMusic::soundPlay()
@@ -1074,90 +625,40 @@ void SoundCommandParser::updateSci0Cues() {
}
}
-#endif
-
void SoundCommandParser::clearPlayList() {
-#ifndef USE_OLD_MUSIC_FUNCTIONS
_music->clearPlayList();
-#endif
-}
-
-void SoundCommandParser::syncPlayList(Common::Serializer &s) {
-#ifndef USE_OLD_MUSIC_FUNCTIONS
- _music->saveLoadWithSerializer(s);
-#endif
-}
-
-void SoundCommandParser::reconstructPlayList(int savegame_version) {
-#ifndef USE_OLD_MUSIC_FUNCTIONS
- Common::StackLock lock(_music->_mutex);
-
- const MusicList::iterator end = _music->getPlayListEnd();
- for (MusicList::iterator i = _music->getPlayListStart(); i != end; ++i) {
- if ((*i)->resourceId && _resMan->testResource(ResourceId(kResourceTypeSound, (*i)->resourceId))) {
- (*i)->soundRes = new SoundResource((*i)->resourceId, _resMan, _soundVersion);
- _music->soundInitSnd(*i);
- } else {
- (*i)->soundRes = 0;
- }
- if ((*i)->status == kSoundPlaying) {
- if (savegame_version < 14) {
- (*i)->dataInc = readSelectorValue(_segMan, (*i)->soundObj, SELECTOR(dataInc));
- (*i)->signal = readSelectorValue(_segMan, (*i)->soundObj, SELECTOR(signal));
-
- if (_soundVersion >= SCI_VERSION_1_LATE)
- (*i)->volume = readSelectorValue(_segMan, (*i)->soundObj, SELECTOR(vol));
- }
-
- cmdPlaySound((*i)->soundObj, 0);
- }
- }
-
-#endif
}
void SoundCommandParser::printPlayList(Console *con) {
-#ifndef USE_OLD_MUSIC_FUNCTIONS
_music->printPlayList(con);
-#endif
}
void SoundCommandParser::printSongInfo(reg_t obj, Console *con) {
-#ifndef USE_OLD_MUSIC_FUNCTIONS
_music->printSongInfo(obj, con);
-#endif
}
void SoundCommandParser::stopAllSounds() {
-#ifndef USE_OLD_MUSIC_FUNCTIONS
_music->stopAll();
-#endif
}
void SoundCommandParser::startNewSound(int number) {
-#ifndef USE_OLD_MUSIC_FUNCTIONS
Common::StackLock lock(_music->_mutex);
// Overwrite the first sound in the playlist
MusicEntry *song = *_music->getPlayListStart();
reg_t soundObj = song->soundObj;
- cmdDisposeSound(soundObj, 0);
+ processDisposeSound(soundObj);
writeSelectorValue(_segMan, soundObj, SELECTOR(number), number);
- cmdInitSound(soundObj, 0);
- cmdPlaySound(soundObj, 0);
-#endif
+ processInitSound(soundObj);
+ processPlaySound(soundObj);
}
void SoundCommandParser::setMasterVolume(int vol) {
-#ifndef USE_OLD_MUSIC_FUNCTIONS
_music->soundSetMasterVolume(vol);
-#endif
}
void SoundCommandParser::pauseAll(bool pause) {
-#ifndef USE_OLD_MUSIC_FUNCTIONS
_music->pauseAll(pause);
-#endif
}
} // End of namespace Sci
diff --git a/engines/sci/sound/soundcmd.h b/engines/sci/sound/soundcmd.h
index 09cca23450..a8bc1eb280 100644
--- a/engines/sci/sound/soundcmd.h
+++ b/engines/sci/sound/soundcmd.h
@@ -26,8 +26,6 @@
#ifndef SCI_SOUNDCMD_H
#define SCI_SOUNDCMD_H
-#include "sci/sci.h" // for USE_OLD_MUSIC_FUNCTIONS
-
#include "common/list.h"
#include "sci/engine/state.h"
@@ -36,13 +34,13 @@ namespace Sci {
class Console;
class SciMusic;
class SoundCommandParser;
-typedef void (SoundCommandParser::*SoundCommand)(reg_t obj, int16 value);
+//typedef void (SoundCommandParser::*SoundCommand)(reg_t obj, int16 value);
-struct MusicEntryCommand {
- MusicEntryCommand(const char *d, SoundCommand c) : sndCmd(c), desc(d) {}
- SoundCommand sndCmd;
- const char *desc;
-};
+//struct MusicEntryCommand {
+// MusicEntryCommand(const char *d, SoundCommand c) : sndCmd(c), desc(d) {}
+// SoundCommand sndCmd;
+// const char *desc;
+//};
class SoundCommandParser {
public:
@@ -53,11 +51,7 @@ public:
kMaxSciVolume = 15
};
-#ifdef USE_OLD_MUSIC_FUNCTIONS
- void updateSfxState(SfxState *newState) { _state = newState; }
-#endif
-
- reg_t parseCommand(int argc, reg_t *argv, reg_t acc);
+ //reg_t parseCommand(int argc, reg_t *argv, reg_t acc);
// Functions used for game state loading
void clearPlayList();
@@ -69,14 +63,14 @@ public:
void pauseAll(bool pause);
// Debug console functions
- void playSound(reg_t obj) { cmdPlaySound(obj, 0); }
- void stopSound(reg_t obj) { cmdStopSound(obj, 0); }
void startNewSound(int number);
void stopAllSounds();
void printPlayList(Console *con);
void printSongInfo(reg_t obj, Console *con);
-#ifndef USE_OLD_MUSIC_FUNCTIONS
+ void processPlaySound(reg_t obj);
+ void processStopSound(reg_t obj, bool sampleFinishedPlaying);
+
/**
* Synchronizes the current state of the music list to the rest of the engine, so that
* the changes that the sound thread makes to the music are registered with the engine
@@ -85,56 +79,43 @@ public:
* by the engine scripts themselves, so the engine itself polls for changes to the music
*/
void updateSci0Cues();
-#endif
+
+ reg_t kDoSoundInit(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundPlay(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundDummy(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundMute(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundPause(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundResume(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundStop(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundStopAll(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundDispose(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundMasterVolume(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundFade(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundGetPolyphony(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundUpdate(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundUpdateCues(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundSendMidi(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundReverb(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundSetHold(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundGetAudioCapability(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundSetVolume(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundSetPriority(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundSetLoop(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundSuspend(int argc, reg_t *argv, reg_t acc);
private:
- typedef Common::Array<MusicEntryCommand *> SoundCommandContainer;
- SoundCommandContainer _soundCommands;
+ //typedef Common::Array<MusicEntryCommand *> SoundCommandContainer;
+ //SoundCommandContainer _soundCommands;
ResourceManager *_resMan;
SegManager *_segMan;
Kernel *_kernel;
-#ifdef USE_OLD_MUSIC_FUNCTIONS
- SfxState *_state;
- int _midiCmd, _controller, _param;
-#else
SciMusic *_music;
-#endif
AudioPlayer *_audio;
SciVersion _soundVersion;
- int _argc;
- reg_t *_argv; // for cmdFadeSound
- uint32 _midiCommand; // for cmdSendMidi
- reg_t _acc;
- int _cmdUpdateCuesIndex;
-
- void cmdInitSound(reg_t obj, int16 value);
- void cmdPlaySound(reg_t obj, int16 value);
- void cmdDummy(reg_t obj, int16 value);
- void cmdMuteSound(reg_t obj, int16 value);
- void cmdPauseSound(reg_t obj, int16 value);
- void cmdResumeSound(reg_t obj, int16 value);
- void cmdStopSound(reg_t obj, int16 value);
- void cmdDisposeSound(reg_t obj, int16 value);
- void cmdMasterVolume(reg_t obj, int16 value);
- void cmdFadeSound(reg_t obj, int16 value);
- void cmdGetPolyphony(reg_t obj, int16 value);
- void cmdStopAllSounds(reg_t obj, int16 value);
- void cmdUpdateSound(reg_t obj, int16 value);
- void cmdUpdateCues(reg_t obj, int16 value);
- void cmdSendMidi(reg_t obj, int16 value);
- void cmdReverb(reg_t obj, int16 value);
- void cmdSetSoundHold(reg_t obj, int16 value);
- void cmdGetAudioCapability(reg_t obj, int16 value);
- void cmdSetSoundVolume(reg_t obj, int16 value);
- void cmdSetSoundPriority(reg_t obj, int16 value);
- void cmdSetSoundLoop(reg_t obj, int16 value);
- void cmdSuspendSound(reg_t obj, int16 value);
-
- void processStopSound(reg_t obj, int16 value, bool sampleFinishedPlaying);
-
-#ifdef USE_OLD_MUSIC_FUNCTIONS
- void changeSoundStatus(reg_t obj, int newStatus);
-#endif
+
+ void processInitSound(reg_t obj);
+ void processDisposeSound(reg_t obj);
+ void processUpdateCues(reg_t obj);
};
} // End of namespace Sci