diff options
author | Filippos Karapetis | 2010-01-05 01:22:16 +0000 |
---|---|---|
committer | Filippos Karapetis | 2010-01-05 01:22:16 +0000 |
commit | 84cd8d2dc7673bf883945cfdf600d98769817bc6 (patch) | |
tree | 9a57872c63fbf0a144b5fdd463d6bda43aa714df /engines/sci/sfx | |
parent | d8c59f5baa386a6baaf62685b794c2531b9cdd64 (diff) | |
download | scummvm-rg350-84cd8d2dc7673bf883945cfdf600d98769817bc6.tar.gz scummvm-rg350-84cd8d2dc7673bf883945cfdf600d98769817bc6.tar.bz2 scummvm-rg350-84cd8d2dc7673bf883945cfdf600d98769817bc6.zip |
Renamed /gui to /graphics and /sfx to /sound, to better illustrate their purpose
svn-id: r47007
Diffstat (limited to 'engines/sci/sfx')
26 files changed, 0 insertions, 10947 deletions
diff --git a/engines/sci/sfx/audio.cpp b/engines/sci/sfx/audio.cpp deleted file mode 100644 index d2cb72fec1..0000000000 --- a/engines/sci/sfx/audio.cpp +++ /dev/null @@ -1,355 +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/resource.h" -#include "sci/engine/kernel.h" -#include "sci/engine/seg_manager.h" -#include "sci/sfx/audio.h" - -#include "common/system.h" - -#include "sound/audiostream.h" -#include "sound/audiocd.h" -#include "sound/wave.h" - -namespace Sci { - -AudioPlayer::AudioPlayer(ResourceManager *resMan) : _resMan(resMan), _audioRate(11025), - _syncResource(NULL), _syncOffset(0), _audioCdStart(0) { - - _mixer = g_system->getMixer(); -} - -AudioPlayer::~AudioPlayer() { - stopAllAudio(); -} - -void AudioPlayer::stopAllAudio() { - stopSoundSync(); - stopAudio(); - if (_audioCdStart > 0) - audioCdStop(); -} - -int AudioPlayer::startAudio(uint16 module, uint32 number) { - int sampleLen; - Audio::AudioStream *audioStream = getAudioStream(number, module, &sampleLen); - - if (audioStream) { - _mixer->playInputStream(Audio::Mixer::kSpeechSoundType, &_audioHandle, audioStream); - return sampleLen; - } - - return 0; -} - -void AudioPlayer::stopAudio() { - _mixer->stopHandle(_audioHandle); -} - -void AudioPlayer::pauseAudio() { - _mixer->pauseHandle(_audioHandle, true); -} - -void AudioPlayer::resumeAudio() { - _mixer->pauseHandle(_audioHandle, false); -} - -int AudioPlayer::getAudioPosition() { - if (_mixer->isSoundHandleActive(_audioHandle)) - return _mixer->getSoundElapsedTime(_audioHandle) * 6 / 100; // return elapsed time in ticks - else - return -1; // Sound finished -} - -enum SolFlags { - kSolFlagCompressed = 1 << 0, - kSolFlagUnknown = 1 << 1, - kSolFlag16Bit = 1 << 2, - kSolFlagIsSigned = 1 << 3 -}; - -// FIXME: Move this to sound/adpcm.cpp? -// Note that the 16-bit version is also used in coktelvideo.cpp -static const uint16 tableDPCM16[128] = { - 0x0000, 0x0008, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0070, 0x0080, - 0x0090, 0x00A0, 0x00B0, 0x00C0, 0x00D0, 0x00E0, 0x00F0, 0x0100, 0x0110, 0x0120, - 0x0130, 0x0140, 0x0150, 0x0160, 0x0170, 0x0180, 0x0190, 0x01A0, 0x01B0, 0x01C0, - 0x01D0, 0x01E0, 0x01F0, 0x0200, 0x0208, 0x0210, 0x0218, 0x0220, 0x0228, 0x0230, - 0x0238, 0x0240, 0x0248, 0x0250, 0x0258, 0x0260, 0x0268, 0x0270, 0x0278, 0x0280, - 0x0288, 0x0290, 0x0298, 0x02A0, 0x02A8, 0x02B0, 0x02B8, 0x02C0, 0x02C8, 0x02D0, - 0x02D8, 0x02E0, 0x02E8, 0x02F0, 0x02F8, 0x0300, 0x0308, 0x0310, 0x0318, 0x0320, - 0x0328, 0x0330, 0x0338, 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, - 0x0378, 0x0380, 0x0388, 0x0390, 0x0398, 0x03A0, 0x03A8, 0x03B0, 0x03B8, 0x03C0, - 0x03C8, 0x03D0, 0x03D8, 0x03E0, 0x03E8, 0x03F0, 0x03F8, 0x0400, 0x0440, 0x0480, - 0x04C0, 0x0500, 0x0540, 0x0580, 0x05C0, 0x0600, 0x0640, 0x0680, 0x06C0, 0x0700, - 0x0740, 0x0780, 0x07C0, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00, - 0x0F00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000 -}; - -static const byte tableDPCM8[8] = {0, 1, 2, 3, 6, 10, 15, 21}; - -static void deDPCM16(byte *soundBuf, Common::SeekableReadStream &audioStream, uint32 n) { - int16 *out = (int16 *) soundBuf; - - int32 s = 0; - for (uint32 i = 0; i < n; i++) { - byte b = audioStream.readByte(); - if (b & 0x80) - s -= tableDPCM16[b & 0x7f]; - else - s += tableDPCM16[b]; - - s = CLIP<int32>(s, -32768, 32767); - *out++ = s; - } -} - -static void deDPCM8Nibble(byte *soundBuf, int32 &s, byte b) { - if (b & 8) - s -= tableDPCM8[7 - (b & 7)]; - else - s += tableDPCM8[b & 7]; - s = CLIP<int32>(s, 0, 255); - *soundBuf = TO_LE_16(s); -} - -static void deDPCM8(byte *soundBuf, Common::SeekableReadStream &audioStream, uint32 n) { - int32 s = 0x80; - - for (uint i = 0; i < n; i++) { - byte b = audioStream.readByte(); - - deDPCM8Nibble(soundBuf++, s, b >> 4); - deDPCM8Nibble(soundBuf++, s, b & 0xf); - } -} - -// 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) { - warning("SOL audio header of size %i not supported", headerSize); - return false; - } - - audioStream->readUint32LE(); // skip "SOL" + 0 (4 bytes) - audioRate = audioStream->readUint16LE(); - audioFlags = audioStream->readByte(); - - size = audioStream->readUint32LE(); - return true; -} - -static byte* readSOLAudio(Common::SeekableReadStream *audioStream, uint32 &size, byte audioFlags, byte &flags) { - byte *buffer; - - // Convert the SOL stream flags to our own format - flags = 0; - if (audioFlags & kSolFlag16Bit) - flags |= Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_LITTLE_ENDIAN; - - if (!(audioFlags & kSolFlagIsSigned)) - flags |= Audio::Mixer::FLAG_UNSIGNED; - - if (audioFlags & kSolFlagCompressed) { - buffer = (byte *)malloc(size * 2); - - if (audioFlags & kSolFlag16Bit) - deDPCM16(buffer, *audioStream, size); - else - deDPCM8(buffer, *audioStream, size); - - size *= 2; - } else { - // We assume that the sound data is raw PCM - buffer = (byte *)malloc(size); - audioStream->read(buffer, size); - } - - return buffer; -} - -Audio::AudioStream* AudioPlayer::getAudioStream(uint32 number, uint32 volume, int *sampleLen) { - Audio::AudioStream *audioStream = 0; - uint32 size = 0; - byte *data = 0; - byte flags = 0; - Sci::Resource* audioRes; - - if (volume == 65535) { - audioRes = _resMan->findResource(ResourceId(kResourceTypeAudio, number), false); - if (!audioRes) { - warning("Failed to find audio entry %i", number); - return NULL; - } - } else { - audioRes = _resMan->findResource(ResourceId(kResourceTypeAudio36, volume, number), false); - if (!audioRes) { - warning("Failed to find audio entry (%i, %i, %i, %i, %i)", volume, (number >> 24) & 0xff, - (number >> 16) & 0xff, (number >> 8) & 0xff, number & 0xff); - return NULL; - } - } - - byte audioFlags; - - if (audioRes->headerSize > 0) { - // SCI1.1 - Common::MemoryReadStream headerStream(audioRes->header, audioRes->headerSize, Common::DisposeAfterUse::NO); - - if (readSOLHeader(&headerStream, audioRes->headerSize, size, _audioRate, audioFlags)) { - Common::MemoryReadStream dataStream(audioRes->data, audioRes->size, Common::DisposeAfterUse::NO); - data = readSOLAudio(&dataStream, size, audioFlags, flags); - } - } else { - // SCI1 or WAVE file - if (audioRes->size > 4) { - if (memcmp(audioRes->data, "RIFF", 4) == 0) { - // WAVE detected - Common::MemoryReadStream *waveStream = new Common::MemoryReadStream(audioRes->data, audioRes->size, Common::DisposeAfterUse::NO); - audioStream = Audio::makeWAVStream(waveStream, true, false); - } - } - if (!audioStream) { - // SCI1 raw audio - size = audioRes->size; - data = (byte *)malloc(size); - assert(data); - memcpy(data, audioRes->data, size); - flags = Audio::Mixer::FLAG_UNSIGNED; - } - } - - if (data) { - audioStream = Audio::makeLinearInputStream(data, size, _audioRate, - flags | Audio::Mixer::FLAG_AUTOFREE, 0, 0); - } - if (audioStream) { - *sampleLen = (flags & Audio::Mixer::FLAG_16BITS ? size >> 1 : size) * 60 / _audioRate; - return audioStream; - } - - return NULL; -} - -void AudioPlayer::setSoundSync(ResourceId id, reg_t syncObjAddr, SegManager *segMan) { - _syncResource = _resMan->findResource(id, 1); - _syncOffset = 0; - - if (_syncResource) { - PUT_SEL32V(segMan, syncObjAddr, syncCue, 0); - } else { - warning("setSoundSync: failed to find resource %s", id.toString().c_str()); - // Notify the scripts to stop sound sync - PUT_SEL32V(segMan, syncObjAddr, syncCue, SIGNAL_OFFSET); - } -} - -void AudioPlayer::doSoundSync(reg_t syncObjAddr, SegManager *segMan) { - if (_syncResource && (_syncOffset < _syncResource->size - 1)) { - int16 syncCue = -1; - int16 syncTime = (int16)READ_LE_UINT16(_syncResource->data + _syncOffset); - - _syncOffset += 2; - - if ((syncTime != -1) && (_syncOffset < _syncResource->size - 1)) { - syncCue = (int16)READ_LE_UINT16(_syncResource->data + _syncOffset); - _syncOffset += 2; - } - - PUT_SEL32V(segMan, syncObjAddr, syncTime, syncTime); - PUT_SEL32V(segMan, syncObjAddr, syncCue, syncCue); - } -} - -void AudioPlayer::stopSoundSync() { - if (_syncResource) { - _resMan->unlockResource(_syncResource); - _syncResource = NULL; - } -} - -int AudioPlayer::audioCdPlay(int track, int start, int duration) { - if (getSciVersion() == SCI_VERSION_1_1) { - // King's Quest VI CD Audio format - _audioCdStart = g_system->getMillis(); - - // Subtract one from track. KQ6 starts at track 1, while ScummVM - // ignores the data track and considers track 2 to be track 1. - AudioCD.play(track - 1, 1, start, duration); - return 1; - } else { - // Jones in the Fast Lane CD Audio format - uint32 length = 0; - - audioCdStop(); - - Common::File audioMap; - if(!audioMap.open("cdaudio.map")) - error("Could not open cdaudio.map"); - - while (audioMap.pos() < audioMap.size()) { - uint16 res = audioMap.readUint16LE(); - uint32 startFrame = audioMap.readUint16LE(); - startFrame += audioMap.readByte() << 16; - audioMap.readByte(); // Unknown, always 0x20 - length = audioMap.readUint16LE(); - length += audioMap.readByte() << 16; - audioMap.readByte(); // Unknown, always 0x00 - - // Jones uses the track as the resource value in the map - if (res == track) { - AudioCD.play(1, 1, startFrame, length); - _audioCdStart = g_system->getMillis(); - break; - } - } - - audioMap.close(); - - return length * 60 / 75; // return sample length in ticks - } -} - -void AudioPlayer::audioCdStop() { - _audioCdStart = 0; - AudioCD.stop(); -} - -void AudioPlayer::audioCdUpdate() { - AudioCD.updateCD(); -} - -int AudioPlayer::audioCdPosition() { - // Return -1 if the sample is done playing. Converting to frames to compare. - if (((g_system->getMillis() - _audioCdStart) * 75 / 1000) >= (uint32)AudioCD.getStatus().duration) - return -1; - - // Return the position otherwise (in ticks). - return (g_system->getMillis() - _audioCdStart) * 60 / 1000; -} - -} // End of namespace Sci diff --git a/engines/sci/sfx/audio.h b/engines/sci/sfx/audio.h deleted file mode 100644 index f71cabc735..0000000000 --- a/engines/sci/sfx/audio.h +++ /dev/null @@ -1,98 +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_AUDIO_H -#define SCI_AUDIO_H - -#include "sound/mixer.h" - -namespace Sci { - -enum AudioCommands { - // TODO: find the difference between kSci1AudioWPlay and kSci1AudioPlay - kSciAudioWPlay = 1, /* Plays an audio stream */ - kSciAudioPlay = 2, /* Plays an audio stream */ - kSciAudioStop = 3, /* Stops an audio stream */ - kSciAudioPause = 4, /* Pauses an audio stream */ - kSciAudioResume = 5, /* Resumes an audio stream */ - kSciAudioPosition = 6, /* Return current position in audio stream */ - kSciAudioRate = 7, /* Return audio rate */ - kSciAudioVolume = 8, /* Return audio volume */ - kSciAudioLanguage = 9, /* Return audio language */ - kSciAudioCD = 10 /* Plays SCI1.1 CD audio */ -}; - -enum AudioSyncCommands { - kSciAudioSyncStart = 0, - kSciAudioSyncNext = 1, - kSciAudioSyncStop = 2 -}; - -#define AUDIO_VOLUME_MAX 127 - -class Resource; -class ResourceId; -class ResourceManager; -class SegManager; - -class AudioPlayer { -public: - AudioPlayer(ResourceManager *resMan); - ~AudioPlayer(); - - void setAudioRate(uint16 rate) { _audioRate = rate; } - Audio::SoundHandle* getAudioHandle() { return &_audioHandle; } - Audio::AudioStream* getAudioStream(uint32 number, uint32 volume, int *sampleLen); - int getAudioPosition(); - int startAudio(uint16 module, uint32 tuple); - void stopAudio(); - void pauseAudio(); - void resumeAudio(); - - void setSoundSync(ResourceId id, reg_t syncObjAddr, SegManager *segMan); - void doSoundSync(reg_t syncObjAddr, SegManager *segMan); - void stopSoundSync(); - - int audioCdPlay(int track, int start, int duration); - void audioCdStop(); - void audioCdUpdate(); - int audioCdPosition(); - - void stopAllAudio(); - -private: - ResourceManager *_resMan; - uint16 _audioRate; - Audio::SoundHandle _audioHandle; - Audio::Mixer* _mixer; - Resource *_syncResource; /**< Used by kDoSync for speech syncing in CD talkie games */ - uint _syncOffset; - uint32 _audioCdStart; -}; - -} // End of namespace Sci - -#endif // SCI_SFX_CORE_H diff --git a/engines/sci/sfx/iterator/core.cpp b/engines/sci/sfx/iterator/core.cpp deleted file mode 100644 index bc90a555a6..0000000000 --- a/engines/sci/sfx/iterator/core.cpp +++ /dev/null @@ -1,1015 +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/sfx/iterator/core.h" -#include "sci/sfx/iterator/iterator.h" -#include "sci/sfx/softseq/mididriver.h" - -#include "sci/sfx/softseq/pcjr.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 (((SciEngine *)g_engine)->getPlatform() == Common::kPlatformAmiga) - _mididrv = MidiPlayer_Amiga_create(); - else - _mididrv = MidiPlayer_Adlib_create(); - break; - case MD_PCJR: - _mididrv = new MidiPlayer_PCJr(); - break; - case MD_PCSPK: - _mididrv = new MidiPlayer_PCSpeaker(); - 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->getPlayMask(_soundVersion))); - 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\n", 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 = ¬_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 == ¬_playing_anymore) { - setSongStatus(oldseeker, SOUND_STATUS_SUSPENDED); - debugC(2, kDebugLevelSound, "[SFX] Stopping song %lx\n", 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\n", 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()->playInputStream(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/sfx/iterator/core.h b/engines/sci/sfx/iterator/core.h deleted file mode 100644 index 944b3d0a0f..0000000000 --- a/engines/sci/sfx/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/sfx/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/sfx/iterator/iterator.cpp b/engines/sci/sfx/iterator/iterator.cpp deleted file mode 100644 index 924e1de0bc..0000000000 --- a/engines/sci/sfx/iterator/iterator.cpp +++ /dev/null @@ -1,1707 +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/sfx/iterator/iterator_internal.h" -#include "sci/engine/state.h" // for sfx_player_tell_synth :/ -#include "sci/sfx/iterator/core.h" // for sfx_player_tell_synth - -#include "sound/audiostream.h" -#include "sound/mixer.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 = ((SciEngine*)g_engine)->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.\n", 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\n", 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\n", size, rate); - - // Duplicate the data - byte *sound = (byte *)malloc(size); - memcpy(sound, data, size); - - // Convert stream format flags - int flags = Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_UNSIGNED; - return Audio::makeLinearInputStream(sound, size, rate, flags, 0, 0); -} - -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\n", - _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 --*/ -/***************************/ - -#define SCI01_INVALID_DEVICE 0xff - -/* Second index determines whether PCM output is supported */ -static const int sci0_to_sci1_device_map[][2] = { - {0x06, 0x0c}, /* MT-32 */ - {0xff, 0xff}, /* YM FB-01 */ - {0x00, 0x00}, /* CMS/Game Blaster-- we assume OPL/2 here... */ - {0xff, 0xff}, /* Casio MT540/CT460 */ - {0x13, 0x13}, /* Tandy 3-voice */ - {0x12, 0x12}, /* PC speaker */ - {0xff, 0xff}, - {0xff, 0xff}, -}; /* Maps bit number to device ID */ - -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\n", - _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 - = sci0_to_sci1_device_map - [sci_ffs(msg._arg.i & 0xff) - 1] - [g_system->getMixer()->isReady()] - ; - - if (_deviceId == 0xff) { - warning("[iterator] Device %d(%d) not supported", - msg._arg.i & 0xff, g_system->getMixer()->isReady()); - } - 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\n"); - } - - 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:\n"); - 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:\n"); - 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)\n", (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\n"); - } - - if (retval == SI_FINISHED) - debugC(2, kDebugLevelSound, "[song-iterator] Song finished. mask = %04x, cm=%04x\n", - 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/sfx/iterator/iterator.h b/engines/sci/sfx/iterator/iterator.h deleted file mode 100644 index ffd0679213..0000000000 --- a/engines/sci/sfx/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/sfx/softseq/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/sfx/iterator/iterator_internal.h b/engines/sci/sfx/iterator/iterator_internal.h deleted file mode 100644 index f41b388008..0000000000 --- a/engines/sci/sfx/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/sfx/iterator/iterator.h" -#include "sci/sfx/softseq/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/sfx/iterator/songlib.cpp b/engines/sci/sfx/iterator/songlib.cpp deleted file mode 100644 index b5ce9c34ac..0000000000 --- a/engines/sci/sfx/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/sfx/iterator/core.h" -#include "sci/sfx/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/sfx/iterator/songlib.h b/engines/sci/sfx/iterator/songlib.h deleted file mode 100644 index acb704edaa..0000000000 --- a/engines/sci/sfx/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/sfx/iterator/test-iterator.cpp b/engines/sci/sfx/iterator/test-iterator.cpp deleted file mode 100644 index 0d603a89fd..0000000000 --- a/engines/sci/sfx/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/sfx/midiparser.cpp b/engines/sci/sfx/midiparser.cpp deleted file mode 100644 index 82b1c89a77..0000000000 --- a/engines/sci/sfx/midiparser.cpp +++ /dev/null @@ -1,506 +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/engine/kernel.h" -#include "sci/engine/state.h" -#include "sci/sfx/midiparser.h" -#include "sci/sfx/softseq/mididriver.h" - -namespace Sci { - -static const int nMidiParams[] = { 2, 2, 2, 2, 1, 1, 2, 0 }; - -enum SciMidiCommands { - kSetSignalLoop = 0x7F, - kEndOfTrack = 0xFC, - kSetReverb = 0x50, - kMidiHold = 0x52, - kUpdateCue = 0x60 -}; - -// MidiParser_SCI -// -MidiParser_SCI::MidiParser_SCI(SciVersion soundVersion) : - MidiParser() { - _soundVersion = soundVersion; - _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; - - _signalSet = false; - _signalToSet = 0; -} - -MidiParser_SCI::~MidiParser_SCI() { - unloadMusic(); -} - -bool MidiParser_SCI::loadMusic(SoundResource::Track *track, MusicEntry *psnd, int channelFilterMask, SciVersion soundVersion) { - unloadMusic(); - _track = track; - _pSnd = psnd; - _soundVersion = soundVersion; - - setVolume(psnd->volume); - - if (channelFilterMask) { - // SCI0 only has 1 data stream, but we need to filter out channels depending on music hardware selection - midiFilterChannels(channelFilterMask); - } else { - midiMixChannels(); - } - - _num_tracks = 1; - _tracks[0] = _mixedData; - setTrack(0); - _loopTick = 0; - return true; -} - -void MidiParser_SCI::unloadMusic() { - allNotesOff(); - resetTracking(); - _num_tracks = 0; - if (_mixedData) { - delete[] _mixedData; - _mixedData = NULL; - } -} - -void MidiParser_SCI::parseNextEvent(EventInfo &info) { - // Set signal AFTER waiting for delta, otherwise we would set signal too soon resulting in all sorts of bugs - if (_signalSet) { - _signalSet = false; - _pSnd->signal = _signalToSet; - debugC(2, kDebugLevelSound, "signal %04x", _signalToSet); - } - - info.start = _position._play_pos; - info.delta = 0; - while (*_position._play_pos == 0xF8) { - info.delta += 240; - _position._play_pos++; - } - info.delta += *(_position._play_pos++); - - // Process the next info. - if ((_position._play_pos[0] & 0xF0) >= 0x80) - info.event = *(_position._play_pos++); - else - info.event = _position._running_status; - if (info.event < 0x80) - return; - - _position._running_status = info.event; - switch (info.command()) { - case 0xC: - info.basic.param1 = *(_position._play_pos++); - info.basic.param2 = 0; - if (info.channel() == 0xF) {// SCI special case - if (info.basic.param1 != kSetSignalLoop) { - _signalSet = true; - _signalToSet = info.basic.param1; - } else { - _loopTick = _position._play_tick; - } - } - break; - case 0xD: - info.basic.param1 = *(_position._play_pos++); - info.basic.param2 = 0; - break; - - case 0xB: - info.basic.param1 = *(_position._play_pos++); - info.basic.param2 = *(_position._play_pos++); - if (info.channel() == 0xF) {// SCI special - // Reference for some events: - // http://wiki.scummvm.org/index.php/SCI/Specifications/Sound/SCI0_Resource_Format#Status_Reference - // Also, sci/sfx/iterator/iterator.cpp, function BaseSongIterator::parseMidiCommand() - switch (info.basic.param1) { - case kSetReverb: - // TODO: Not implemented yet - break; - case kMidiHold: - // Check if the hold ID marker is the same as the hold ID - // marker set for that song by cmdSetSoundHold. - // If it is, loop back, but don't stop notes when jumping. - if (info.basic.param2 == _pSnd->hold) - jumpToTick(_loopTick, false, false); - break; - case kUpdateCue: - switch (_soundVersion) { - case SCI_VERSION_0_EARLY: - case SCI_VERSION_0_LATE: - _pSnd->dataInc += info.basic.param2; - _signalSet = true; - _signalToSet = 0x7f + _pSnd->dataInc; - break; - case SCI_VERSION_1_EARLY: - case SCI_VERSION_1_LATE: - _pSnd->dataInc++; - break; - default: - break; - } - break; - // Unhandled SCI commands - case 0x46: // LSL3 - binoculars - case 0x61: // Iceman (Adlib?) - case 0x73: // Hoyle - case 0xd1: // KQ4, when riding the unicorn - // Obscure SCI commands - ignored - break; - // Standard MIDI commands - case 0x01: // mod wheel - case 0x04: // foot controller - case 0x07: // channel volume - 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 - break; - case 0x4B: // voice mapping - // TODO: is any support for this needed at the MIDI parser level? - warning("Unhanded SCI MIDI command 0x%x - voice mapping (parameter %d)", info.basic.param1, info.basic.param2); - break; - default: - warning("Unhandled SCI MIDI command 0x%x (parameter %d)", info.basic.param1, info.basic.param2); - break; - } - } - if (info.basic.param1 == 7) // channel volume change -scale it - info.basic.param2 = info.basic.param2 * _volume / 0x7F; - info.length = 0; - break; - - case 0x8: - case 0x9: - case 0xA: - case 0xE: - info.basic.param1 = *(_position._play_pos++); - info.basic.param2 = *(_position._play_pos++); - if (info.command() == 0x9 && info.basic.param2 == 0) - info.event = info.channel() | 0x80; - info.length = 0; - break; - - case 0xF: // System Common, Meta or SysEx event - switch (info.event & 0x0F) { - case 0x2: // Song Position Pointer - info.basic.param1 = *(_position._play_pos++); - info.basic.param2 = *(_position._play_pos++); - break; - - case 0x3: // Song Select - info.basic.param1 = *(_position._play_pos++); - info.basic.param2 = 0; - break; - - case 0x6: - case 0x8: - case 0xA: - case 0xB: - case 0xC: - case 0xE: - info.basic.param1 = info.basic.param2 = 0; - break; - - case 0x0: // SysEx - info.length = readVLQ(_position._play_pos); - info.ext.data = _position._play_pos; - _position._play_pos += info.length; - break; - - case 0xF: // META event - info.ext.type = *(_position._play_pos++); - info.length = readVLQ(_position._play_pos); - info.ext.data = _position._play_pos; - _position._play_pos += info.length; - if (info.ext.type == 0x2F) {// end of track reached - if (_pSnd->loop) - _pSnd->loop--; - if (_pSnd->loop) { - // We need to play it again... - jumpToTick(_loopTick); - } else { - _pSnd->status = kSoundStopped; - _pSnd->signal = SIGNAL_OFFSET; - - debugC(2, kDebugLevelSound, "signal EOT"); - } - } - break; - default: - warning( - "MidiParser_SCI::parseNextEvent: Unsupported event code %x", - info.event); - } // // System Common, Meta or SysEx event - }// switch (info.command()) -} - - -byte MidiParser_SCI::midiGetNextChannel(long ticker) { - byte curr = 0xFF; - long closest = ticker + 1000000, next = 0; - - for (int i = 0; i < _track->channelCount; i++) { - if (_track->channels[i].time == -1) // channel ended - continue; - next = *_track->channels[i].data; // when the next event shoudl occur - if (next == 0xF8) // 0xF8 means 240 ticks delay - next = 240; - next += _track->channels[i].time; - if (next < closest) { - curr = i; - closest = next; - } - } - - return curr; -} - -byte *MidiParser_SCI::midiMixChannels() { - int totalSize = 0; - byte **dataPtr = new byte *[_track->channelCount]; - - for (int i = 0; i < _track->channelCount; i++) { - dataPtr[i] = _track->channels[i].data; - _track->channels[i].time = 0; - _track->channels[i].prev = 0; - totalSize += _track->channels[i].size; - } - - byte *mixedData = new byte[totalSize * 2]; // FIXME: creates overhead and still may be not enough to hold all data - _mixedData = mixedData; - long ticker = 0; - byte curr, delta; - byte cmd, par1, global_prev = 0; - long new_delta; - SoundResource::Channel *channel; - while ((curr = midiGetNextChannel(ticker)) != 0xFF) { // there is still active channel - channel = &_track->channels[curr]; - delta = *channel->data++; - channel->time += (delta == 0xF8 ? 240 : delta); // when the comamnd is supposed to occur - if (delta == 0xF8) - continue; - new_delta = channel->time - ticker; - ticker += new_delta; - - cmd = *channel->data++; - if (cmd != kEndOfTrack) { - // output new delta - while (new_delta > 240) { - *mixedData++ = 0xF8; - new_delta -= 240; - } - *mixedData++ = (byte)new_delta; - } - switch (cmd) { - case 0xF0: // sysEx - *mixedData++ = cmd; - do { - par1 = *channel->data++; - *mixedData++ = par1; // out - } while (par1 != 0xF7); - break; - case kEndOfTrack: // end channel - channel->time = -1; // FIXME - break; - default: // MIDI command - if (cmd & 0x80) - par1 = *channel->data++; - else {// running status - par1 = cmd; - cmd = channel->prev; - } - if (cmd != global_prev) - *mixedData++ = cmd; // out cmd - *mixedData++ = par1;// pout par1 - if (nMidiParams[(cmd >> 4) - 8] == 2) - *mixedData++ = *channel->data++; // out par2 - channel->prev = cmd; - global_prev = cmd; - }// switch(cmd) - }// while (curr) - // mixing finished. inserting stop event - *mixedData++ = 0; - *mixedData++ = 0xFF; - *mixedData++ = 0x2F; - *mixedData++ = 0x00; - *mixedData++ = 0x00; - - for (int channelNr = 0; channelNr < _track->channelCount; channelNr++) - _track->channels[channelNr].data = dataPtr[channelNr]; - - delete[] dataPtr; - return _mixedData; -} - -// 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 *filterData = new byte[channel->size + 5]; - byte curChannel, curByte, curDelta; - byte command, lastCommand; - int delta = 0; - //int dataLeft = channel->size; - int midiParamCount; - - _mixedData = filterData; - command = 0; - midiParamCount = 0; - lastCommand = 0; - curChannel = 15; - - while (channelData < channelDataEnd) { - curDelta = *channelData++; - if (curDelta == 0xF8) { - delta += 240; - continue; - } - delta += curDelta; - curByte = *channelData++; - - switch (curByte) { - case 0xF0: // sysEx - 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) { - debugC(2, kDebugLevelSound, "\nDELTA "); - // Write delta - while (delta > 240) { - *filterData++ = 0xF8; - debugC(2, kDebugLevelSound, "F8 "); - delta -= 240; - } - *filterData++ = (byte)delta; - debugC(2, kDebugLevelSound, "%02X ", delta); - delta = 0; - } - // Write command - switch (command) { - case 0xF0: // sysEx - *filterData++ = command; - debugC(2, kDebugLevelSound, "%02X ", command); - do { - curByte = *channelData++; - *filterData++ = curByte; // out - } while (curByte != 0xF7); - lastCommand = command; - break; - - case kEndOfTrack: // end of channel - break; - - default: // MIDI command - if (lastCommand != command) { - *filterData++ = command; - debugC(2, kDebugLevelSound, "%02X ", command); - lastCommand = command; - } - if (midiParamCount > 0) { - if (curByte & 0x80) { - debugC(2, kDebugLevelSound, "%02X ", *channelData); - *filterData++ = *channelData++; - } else { - debugC(2, kDebugLevelSound, "%02X ", curByte); - *filterData++ = curByte; - } - } - if (midiParamCount > 1) { - debugC(2, kDebugLevelSound, "%02X ", *channelData); - *filterData++ = *channelData++; - } - } - } else { - if (curByte & 0x80) { - channelData += midiParamCount; - } else { - channelData += midiParamCount - 1; - } - } - } - // Stop event - *filterData++ = 0; // delta - *filterData++ = 0xFF; // Meta-Event - *filterData++ = 0x2F; // End-Of-Track - *filterData++ = 0x00; - *filterData++ = 0x00; - - return _mixedData; -} - -void MidiParser_SCI::setVolume(byte bVolume) { - if (bVolume > 0x7F) - bVolume = 0x7F; - if (_volume != bVolume) { - _volume = bVolume; - - switch (_soundVersion) { - case SCI_VERSION_0_EARLY: - case SCI_VERSION_0_LATE: { - MidiPlayer *SCIDriver = (MidiPlayer *)_driver; - int16 globalVolume = _volume * 15 / 127; - SCIDriver->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; - - default: - error("MidiParser_SCI::setVolume: Unsupported soundVersion"); - } - } -} - -} // End of namespace Sci diff --git a/engines/sci/sfx/midiparser.h b/engines/sci/sfx/midiparser.h deleted file mode 100644 index 0eb2eb0bc1..0000000000 --- a/engines/sci/sfx/midiparser.h +++ /dev/null @@ -1,85 +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_MIDIPARSER_H -#define SCI_MIDIPARSER_H - -#include "sci/resource.h" -#include "sci/sfx/music.h" -#include "sound/midiparser.h" - -/* - Sound drivers info: (from driver cmd0) - Adlib/SB : track 0 , voices 9 , patch 3 ah=1 - ProAudioSp: track 0 , voices 9 , patch 3 ah=17 - GenerlMIDI: track 7 , voices 32, patch 4 ah=1 SCI1.1 - Game Blast: track 9 , voices 12, patch 101 ah=1 - MT-32 : track 12, voices 32, patch 1 ah=1 - PC Speaker: track 18, voices 1 , patch 0xFF ah=1 - Tandy : track 19, voices 3 , patch 101 ah=1 - IBM PS/1 : track 19, voices 3 , patch 101 ah=1 - - */ - -namespace Sci { - -class MidiParser_SCI : public MidiParser { -public: - MidiParser_SCI(SciVersion soundVersion); - ~MidiParser_SCI(); - bool loadMusic(SoundResource::Track *track, MusicEntry *psnd, int channelFilterMask, SciVersion soundVersion); - bool loadMusic(byte *, uint32) { - return false; - } - void unloadMusic(); - void setVolume(byte bVolume); - void stop() { - _abort_parse = true; - allNotesOff(); - } - void pause() { - allNotesOff(); - } - -protected: - void parseNextEvent(EventInfo &info); - byte *midiMixChannels(); - byte *midiFilterChannels(int channelMask); - byte midiGetNextChannel(long ticker); - - SciVersion _soundVersion; - byte *_mixedData; - SoundResource::Track *_track; - MusicEntry *_pSnd; - uint32 _loopTick; - byte _volume; - - bool _signalSet; - int16 _signalToSet; -}; - -} // End of namespace Sci - -#endif diff --git a/engines/sci/sfx/music.cpp b/engines/sci/sfx/music.cpp deleted file mode 100644 index 30721f0531..0000000000 --- a/engines/sci/sfx/music.cpp +++ /dev/null @@ -1,573 +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 "sound/audiostream.h" -#include "common/config-manager.h" - -#include "sci/sci.h" -#include "sci/console.h" -#include "sci/resource.h" -#include "sci/engine/kernel.h" -#include "sci/engine/state.h" -#include "sci/sfx/midiparser.h" -#include "sci/sfx/music.h" -#include "sci/sfx/softseq/pcjr.h" - -namespace Sci { - -SciMusic::SciMusic(SciVersion soundVersion) - : _soundVersion(soundVersion), _soundOn(true) { - - // Reserve some space in the playlist, to avoid expensive insertion - // operations - _playList.reserve(10); -} - -SciMusic::~SciMusic() { - if (_pMidiDrv) { - _pMidiDrv->close(); - delete _pMidiDrv; - } -} - -void SciMusic::init() { - // system init - _pMixer = g_system->getMixer(); - _pMixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt( - "sfx_volume")); - _pMixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, - ConfMan.getInt("speech_volume")); - _pMixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, - ConfMan.getInt("music_volume")); - // SCI sound init - _dwTempo = 0; - - const MidiDriverDescription *md = MidiDriver::findMusicDriver(ConfMan.get("music_driver")); - _midiType = md ? md->id : MD_AUTO; - - switch (_midiType) { - case MD_ADLIB: - // FIXME: There's no Amiga sound option, so we hook it up to Adlib - if (((SciEngine *)g_engine)->getPlatform() == Common::kPlatformAmiga) - _pMidiDrv = MidiPlayer_Amiga_create(); - else - _pMidiDrv = MidiPlayer_Adlib_create(); - break; - case MD_PCJR: - _pMidiDrv = new MidiPlayer_PCJr(); - break; - case MD_PCSPK: - _pMidiDrv = new MidiPlayer_PCSpeaker(); - break; - case MD_MT32: - // TODO - default: - warning("Unhandled MIDI type, switching to Adlib"); - _midiType = MD_ADLIB; - _pMidiDrv = MidiPlayer_Adlib_create(); - break; - } - - if (_pMidiDrv) { - _pMidiDrv->open(); - _pMidiDrv->setTimerCallback(this, &miditimerCallback); - _dwTempo = _pMidiDrv->getBaseTempo(); - } else - warning("Can't initialise music driver"); - _bMultiMidi = ConfMan.getBool("multi_midi"); -} - -void SciMusic::clearPlayList() { - _pMixer->stopAll(); - - _mutex.lock(); - while (!_playList.empty()) { - soundStop(_playList[0]); - soundKill(_playList[0]); - } - _mutex.unlock(); -} - -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); - - _soundOn = soundOnFlag; - _pMidiDrv->playSwitch(soundOnFlag); -} - -uint16 SciMusic::soundGetVoices() { - Common::StackLock lock(_mutex); - - return _pMidiDrv->getPolyphony(); -} - -MusicEntry *SciMusic::getSlot(reg_t obj) { - Common::StackLock lock(_mutex); - - const MusicList::iterator end = _playList.end(); - for (MusicList::iterator i = _playList.begin(); i != end; ++i) { - if ((*i)->soundObj == obj) - return *i; - } - - return NULL; -} - -void SciMusic::setReverb(byte reverb) { - _reverb = reverb; - - // TODO: actually set reverb for MT-32 - - // A good test case for this are the first two rooms in Longbow: - // reverb is set for the first room (the cave) and is subsequently - // cleared when Robin exits the cave -} - -void SciMusic::resetDriver() { - Common::StackLock lock(_mutex); - - _pMidiDrv->close(); - _pMidiDrv->open(); - _pMidiDrv->setTimerCallback(this, &miditimerCallback); -} - -static int f_compare(const void *arg1, const void *arg2) { - return ((const MusicEntry *)arg2)->prio - ((const MusicEntry *)arg1)->prio; -} - -void SciMusic::sortPlayList() { - MusicEntry ** pData = _playList.begin(); - qsort(pData, _playList.size(), sizeof(MusicEntry *), &f_compare); -} - -#if 0 -void SciMusic::patchSysEx(byte * addr, byte *pdata, int len) { - byte *buff = new byte[7 + len + 1]; - uint16 chk = 0; - int i; - - buff[0] = 0x41; - buff[1] = 0x10; - buff[2] = 0x16; - buff[3] = 0x12; - buff[4] = addr[0]; - buff[5] = addr[1]; - buff[6] = addr[2]; - for (i = 0; i < len; i++) { - buff[7 + i] = pdata[i]; - chk += pdata[i]; - } - chk += addr[0] + addr[1] + addr[2]; - buff[7 + i] = 128 - chk % 128; - _pMidiDrv->sysEx(buff, len + 8); - delete[] buff; -} - -void SciMusic::patchUpdateAddr(byte *addr, int len) { - addr[2] += len; - if (addr[2] >= 0x7F) { - addr[1]++; - addr[2] -= 0x80; - } -} -#endif - -// FIXME: This should be done at the driver level -#if 0 -void SciMusic::loadPatch() { - if (_midiType == MD_MT32) - loadPatchMT32(); -} -#endif - -#if 0 -// currently loads patch 1.pat for Roland/MT-32 device -void SciMusic::loadPatchMT32() { - //byte sysText[] = { 0x20, 0, 0 }; - byte sysMem[] = { 0x5, 0, 0 }; // patch memory - byte sysRhytm[] = { 0x3, 0x1, 0x10 }; // rhytm - byte sysMsg3[15] = { 0x41, 0x10, 0x16, 0x12, 0x52, 0, 0xA, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x20, 0x80 }; - byte sysTimbre[] = { 0x8, 0, 0 }; // timbre memory - byte sysSystem[] = { 0x10, 0, 4 }; // partial reserve & midi channel - byte arr[3][11]; - - Resource *res = ((SciEngine *)g_engine)->getResourceManager()->findResource(ResourceId(kResourceTypePatch, 1), 0); - - if (res) { - byte *pData = res->data, *p; - // welcome message - //patchSysEx(sysText, pData + 20, 20); - // reading reverb mode, time and level - p = pData + 74; - for (int i = 0; i < 11; i++) { - arr[0][i] = *p++; - arr[1][i] = *p++; - arr[2][i] = *p++; - } - // sub_657 - patch memory - for (int i = 0; i < 48; i++) { - patchSysEx(sysMem, p, 8); - patchUpdateAddr(sysMem, 8); - p += 8; - } - // sub_696 - timbre - byte dl = *p++, cl = 0; - while (dl--) { - patchSysEx(sysTimbre, p, 14); // common area - patchUpdateAddr(sysTimbre, 14); - patchSysEx(sysTimbre, p + 14, 58);// partial 1 - patchUpdateAddr(sysTimbre, 58); - patchSysEx(sysTimbre, p + 72, 58);// partial 2 - patchUpdateAddr(sysTimbre, 58); - patchSysEx(sysTimbre, p + 130, 58);// partial 3 - patchUpdateAddr(sysTimbre, 58); - patchSysEx(sysTimbre, p + 188, 58);// partial 4 - patchUpdateAddr(sysTimbre, 58); - p += 246; - cl += 2; - sysTimbre[1] = cl; - sysTimbre[2] = 0; - } - // patch memory or rhytm - uint16 flag = READ_BE_UINT16(p); - p += 2; - if (flag == 0xABCD) { - // sub_657 - for (int i = 0; i < 48; i++) { - patchSysEx(sysMem, p, 8); - patchUpdateAddr(sysMem, 8); - p += 8; - } - } else if (flag == 0xDCBA) { - // sub_756 - for (int i = 0; i < 64; i++) { - patchSysEx(sysRhytm, p, 4); - patchUpdateAddr(sysRhytm, 4); - p += 4; - } - patchSysEx(sysSystem, p, 18); - } - // after-init text message - //patchSysEx(sysText, pData, 20); - // some final sysex - _pMidiDrv->sysEx(sysMsg3, 15); - // releasing patch resource - //g_sci->ResMgr.ResUnload(SCI_RES_PATCH, 1); - debug("MT-32 patch loaded"); - } -} -#endif - - -void SciMusic::soundInitSnd(MusicEntry *pSnd) { - SoundResource::Track *track = NULL; - int channelFilterMask = 0; - - switch (_midiType) { - case MD_PCSPK: - track = pSnd->soundRes->getTrackByType(SoundResource::TRACKTYPE_SPEAKER); - break; - case MD_PCJR: - track = pSnd->soundRes->getTrackByType(SoundResource::TRACKTYPE_TANDY); - break; - case MD_ADLIB: - track = pSnd->soundRes->getTrackByType(SoundResource::TRACKTYPE_ADLIB); - break; - case MD_MT32: - track = pSnd->soundRes->getTrackByType(SoundResource::TRACKTYPE_MT32); - break; - default: - // Should never occur - error("soundInitSnd: Unknown MIDI type"); - break; - } - - if (track) { - // If MIDI device is selected but there is no digital track in sound resource - // try to use adlib's digital sample if possible - if (_bMultiMidi && pSnd->soundRes->getTrackByType(SoundResource::TRACKTYPE_ADLIB)->digitalChannelNr != -1) - track = pSnd->soundRes->getTrackByType(SoundResource::TRACKTYPE_ADLIB); - // Play digital sample - if (track->digitalChannelNr != -1) { - byte *channelData = track->channels[track->digitalChannelNr].data; - delete pSnd->pStreamAud; - pSnd->pStreamAud = Audio::makeLinearInputStream(channelData, track->digitalSampleSize, track->digitalSampleRate, - Audio::Mixer::FLAG_UNSIGNED, 0, 0); - pSnd->soundType = Audio::Mixer::kSFXSoundType; - pSnd->hCurrentAud = Audio::SoundHandle(); - } else { - // play MIDI track - _mutex.lock(); - pSnd->soundType = Audio::Mixer::kMusicSoundType; - if (pSnd->pMidiParser == NULL) { - pSnd->pMidiParser = new MidiParser_SCI(_soundVersion); - pSnd->pMidiParser->setMidiDriver(_pMidiDrv); - pSnd->pMidiParser->setTimerRate(_dwTempo); - pSnd->pMidiParser->property(MidiParser::mpCenterPitchWheelOnUnload, 1); - } - - pSnd->pauseCounter = 0; - - // Find out what channels to filter for SCI0 - channelFilterMask = pSnd->soundRes->getChannelFilterMask(_pMidiDrv->getPlayMask(_soundVersion)); - 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); - _mutex.unlock(); - } - } -} - -void SciMusic::onTimer() { - const MusicList::iterator end = _playList.end(); - for (MusicList::iterator i = _playList.begin(); i != end; ++i) - (*i)->onTimer(); -} - -void SciMusic::soundPlay(MusicEntry *pSnd) { - _mutex.lock(); - - uint sz = _playList.size(), i; - // searching if sound is already in _playList - for (i = 0; i < sz && _playList[i] != pSnd; i++) - ; - if (i == sz) {// not found - _playList.push_back(pSnd); - sortPlayList(); - } - - _mutex.unlock(); // unlock to perform mixer-related calls - - if (pSnd->pStreamAud && !_pMixer->isSoundHandleActive(pSnd->hCurrentAud)) { - // Are we supposed to loop the stream? - if (pSnd->loop > 1) - pSnd->pStreamAud->setNumLoops(pSnd->loop); - else - pSnd->pStreamAud->setNumLoops(1); - _pMixer->playInputStream(pSnd->soundType, &pSnd->hCurrentAud, - pSnd->pStreamAud, -1, pSnd->volume, 0, false); - } else { - _mutex.lock(); - if (pSnd->pMidiParser) { - pSnd->pMidiParser->setVolume(pSnd->volume); - if (pSnd->status == kSoundStopped) - pSnd->pMidiParser->jumpToTick(0); - } - _mutex.unlock(); - } - - pSnd->status = kSoundPlaying; -} - -void SciMusic::soundStop(MusicEntry *pSnd) { - pSnd->status = kSoundStopped; - if (pSnd->pStreamAud) - _pMixer->stopHandle(pSnd->hCurrentAud); - - _mutex.lock(); - if (pSnd->pMidiParser) - pSnd->pMidiParser->stop(); - _mutex.unlock(); -} - -void SciMusic::soundSetVolume(MusicEntry *pSnd, byte volume) { - assert(volume <= MUSIC_VOLUME_MAX); - if (pSnd->pStreamAud) { - _pMixer->setChannelVolume(pSnd->hCurrentAud, volume * 2); // Mixer is 0-255, SCI is 0-127 - } else if (pSnd->pMidiParser) { - _mutex.lock(); - pSnd->pMidiParser->setVolume(volume); - _mutex.unlock(); - } -} - -void SciMusic::soundSetPriority(MusicEntry *pSnd, byte prio) { - Common::StackLock lock(_mutex); - - pSnd->prio = prio; - sortPlayList(); -} - -void SciMusic::soundKill(MusicEntry *pSnd) { - pSnd->status = kSoundStopped; - - _mutex.lock(); - if (pSnd->pMidiParser) { - pSnd->pMidiParser->unloadMusic(); - delete pSnd->pMidiParser; - pSnd->pMidiParser = NULL; - } - _mutex.unlock(); - - if (pSnd->pStreamAud) { - _pMixer->stopHandle(pSnd->hCurrentAud); - pSnd->pStreamAud = NULL; - } - - _mutex.lock(); - uint sz = _playList.size(), i; - // Remove sound from playlist - for (i = 0; i < sz; i++) { - if (_playList[i] == pSnd) { - delete _playList[i]->soundRes; - delete _playList[i]; - _playList.remove_at(i); - break; - } - } - _mutex.unlock(); -} - -void SciMusic::soundPause(MusicEntry *pSnd) { - pSnd->pauseCounter++; - if (pSnd->status != kSoundPlaying) - return; - pSnd->status = kSoundPaused; - if (pSnd->pStreamAud) { - _pMixer->pauseHandle(pSnd->hCurrentAud, true); - } else { - _mutex.lock(); - if (pSnd->pMidiParser) - pSnd->pMidiParser->pause(); - _mutex.unlock(); - } -} - -void SciMusic::soundResume(MusicEntry *pSnd) { - if (pSnd->pauseCounter > 0) - pSnd->pauseCounter--; - if (pSnd->pauseCounter != 0) - return; - if (pSnd->status != kSoundPaused) - return; - soundPlay(pSnd); -} - -uint16 SciMusic::soundGetMasterVolume() { - return (_pMixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) + 8) * 0xF / Audio::Mixer::kMaxMixerVolume; -} - -void SciMusic::soundSetMasterVolume(uint16 vol) { - vol = vol & 0xF; // 0..15 - vol = vol * Audio::Mixer::kMaxMixerVolume / 0xF; - // "master volume" is music and SFX only, speech (audio resources) are supposed to be unaffected - _pMixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, vol); - _pMixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, vol); -} - -void SciMusic::printPlayList(Console *con) { - Common::StackLock lock(_mutex); - - const char *musicStatus[] = { "Stopped", "Initialized", "Paused", "Playing" }; - - const MusicList::iterator end = _playList.end(); - for (MusicList::iterator i = _playList.begin(); i != end; ++i) { - con->DebugPrintf("%d: %04x:%04x, priority: %d, status: %s\n", i, - PRINT_REG((*i)->soundObj), (*i)->prio, - musicStatus[(*i)->status]); - } -} - -MusicEntry::MusicEntry() { - soundObj = NULL_REG; - - soundRes = 0; - resnum = 0; - - dataInc = 0; - ticker = 0; - signal = 0; - prio = 0; - loop = 0; - volume = MUSIC_VOLUME_DEFAULT; - hold = 0; - - pauseCounter = 0; - sampleLoopCounter = 0; - - fadeTo = 0; - fadeStep = 0; - fadeTicker = 0; - fadeTickerStep = 0; - fadeSetVolume = false; - fadeCompleted = false; - - status = kSoundStopped; - - soundType = Audio::Mixer::kMusicSoundType; - - pStreamAud = 0; - pMidiParser = 0; -} - -MusicEntry::~MusicEntry() { -} - -void MusicEntry::onTimer() { - if (status != kSoundPlaying) - return; - - // Fade MIDI and digital sound effects - if (fadeStep) - doFade(); - - // Only process MIDI streams in this thread, not digital sound effects - if (pMidiParser) { - pMidiParser->onTimer(); - ticker = (uint16)pMidiParser->getTick(); - } -} - -void MusicEntry::doFade() { - if (fadeTicker) - fadeTicker--; - else { - int16 fadeVolume = volume; - fadeTicker = fadeTickerStep; - fadeVolume += fadeStep; - if (((fadeStep > 0) && (fadeVolume >= fadeTo)) || ((fadeStep < 0) && (fadeVolume <= fadeTo))) { - fadeVolume = fadeTo; - fadeStep = 0; - fadeCompleted = true; - } - volume = fadeVolume; - - // Only process MIDI streams in this thread, not digital sound effects - if (pMidiParser) - pMidiParser->setVolume(volume); - fadeSetVolume = true; // set flag so that SoundCommandParser::cmdUpdateCues will set the volume of the stream - } -} - -} // End of namespace Sci diff --git a/engines/sci/sfx/music.h b/engines/sci/sfx/music.h deleted file mode 100644 index 0b7d880112..0000000000 --- a/engines/sci/sfx/music.h +++ /dev/null @@ -1,219 +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_MUSIC_H -#define SCI_MUSIC_H - -#include "common/savefile.h" -#include "common/serializer.h" -#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" -#include "sci/sfx/softseq/mididriver.h" - -namespace Sci { - -enum TrackType { - kTrackAdlib = 0, - kTrackGameBlaster = 9, - kTrackMT32 = 12, - kTrackSpeaker = 18, - kTrackTandy = 19 -}; - -enum SoundStatus { - kSoundStopped = 0, - kSoundInitialized = 1, - kSoundPaused = 2, - kSoundPlaying = 3 -}; - -#define MUSIC_VOLUME_DEFAULT 127 -#define MUSIC_VOLUME_MAX 127 - -class MidiParser_SCI; -class SegManager; - -class MusicEntry -#ifndef USE_OLD_MUSIC_FUNCTIONS - : public Common::Serializable -#endif -{ -public: - // Do not get these directly for the sound objects! - // It's a bad idea, as the sound code (i.e. the SciMusic - // class) should be as separate as possible from the rest - // of the engine - - reg_t soundObj; - - SoundResource *soundRes; - uint16 resnum; - - uint16 dataInc; - uint16 ticker; - uint16 signal; - byte prio; - uint16 loop; - byte volume; - byte hold; - - int16 pauseCounter; - uint sampleLoopCounter; - - byte fadeTo; - short fadeStep; - uint32 fadeTicker; - uint32 fadeTickerStep; - bool fadeSetVolume; - bool fadeCompleted; - - SoundStatus status; - - Audio::Mixer::SoundType soundType; - -#ifndef USE_OLD_MUSIC_FUNCTIONS -//protected: -#endif - MidiParser_SCI *pMidiParser; - Audio::AudioStream* pStreamAud; - Audio::SoundHandle hCurrentAud; - -public: - MusicEntry(); - ~MusicEntry(); - - void doFade(); - void onTimer(); - -#ifndef USE_OLD_MUSIC_FUNCTIONS - virtual void saveLoadWithSerializer(Common::Serializer &ser); -#endif -}; - -typedef Common::Array<MusicEntry *> MusicList; - -class SciMusic -#ifndef USE_OLD_MUSIC_FUNCTIONS - : public Common::Serializable -#endif -{ - -public: - SciMusic(SciVersion soundVersion); - ~SciMusic(); - - void init(); -#if 0 - void loadPatch(); -#endif - void onTimer(); - void clearPlayList(); - - // sound and midi functions - void soundInitSnd(MusicEntry *pSnd); - void soundPlay(MusicEntry *pSnd); - void soundStop(MusicEntry *pSnd); - void soundKill(MusicEntry *pSnd); - void soundPause(MusicEntry *pSnd); - void soundResume(MusicEntry *pSnd); - void soundSetVolume(MusicEntry *pSnd, byte volume); - void soundSetPriority(MusicEntry *pSnd, byte prio); - uint16 soundGetMasterVolume(); - void soundSetMasterVolume(uint16 vol); - uint16 soundGetSoundOn() const { return _soundOn; } - void soundSetSoundOn(bool soundOnFlag); - uint16 soundGetVoices(); - uint32 soundGetTempo() const { return _dwTempo; } - - MusicEntry *getSlot(reg_t obj); - - void pushBackSlot(MusicEntry *slotEntry) { - Common::StackLock lock(_mutex); - _playList.push_back(slotEntry); - } - - void printPlayList(Console *con); - - // The following two methods are NOT thread safe - make sure that - // the mutex is always locked before calling them - MusicList::iterator getPlayListStart() { return _playList.begin(); } - MusicList::iterator getPlayListEnd() { return _playList.end(); } - - void sendMidiCommand (uint32 cmd) { - Common::StackLock lock(_mutex); - _pMidiDrv->send(cmd); - } - - void setReverb(byte reverb); - - void resetDriver(); - -#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 - // include references to the mixer, otherwise there will probably be situations - // where a deadlock can occur - Common::Mutex _mutex; - -protected: - byte findAudEntry(uint16 nAud, byte&oVolume, uint32& oOffset, uint32&oSize); - void sortPlayList(); -#if 0 - void loadPatchMT32(); - void patchSysEx(byte * addr, byte *pdata, int len); - void patchUpdateAddr(byte *addr, int len); -#endif - - SciVersion _soundVersion; - - Audio::Mixer *_pMixer; - MidiPlayer *_pMidiDrv; - MidiDriverType _midiType; - - uint32 _dwTempo; - // 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); - - MusicList _playList; - bool _soundOn; - byte _reverb; -}; - -} // End of namespace Sci - -#endif diff --git a/engines/sci/sfx/seq/gm.cpp b/engines/sci/sfx/seq/gm.cpp deleted file mode 100644 index 9e2a61db47..0000000000 --- a/engines/sci/sfx/seq/gm.cpp +++ /dev/null @@ -1,167 +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 "common/util.h" - -#include "sci/sfx/seq/midiwriter.h" -#include "sci/sfx/seq/instrument-map.h" - -namespace Sci { - -#if 0 -static midi_writer_t *writer = NULL; - -static Common::Error midi_gm_open(int patch_len, byte *data, int patch2_len, byte *data2, void *device) { - sfx_instrument_map_t *instrument_map = sfx_instrument_map_load_sci(data, patch_len); - - if (!instrument_map) { - warning("[GM] No GM instrument map found, trying MT-32 instrument map.."); - instrument_map = sfx_instrument_map_mt32_to_gm(data2, patch2_len); - } - - writer = sfx_mapped_writer((midi_writer_t *) device, instrument_map); - - if (!writer) - return Common::kUnknownError; - - if (writer->reset_timer) - writer->reset_timer(writer); - - return Common::kNoError; -} - -static Common::Error midi_gm_close() { - return Common::kNoError; -} - -static Common::Error midi_gm_event(byte command, int argc, byte *argv) { - byte data[4]; - - assert(argc < 4); - data[0] = command; - memcpy(data + 1, argv, argc); - - writer->write(writer, data, argc + 1); - - return Common::kNoError; -} - -static Common::Error midi_gm_delay(int ticks) { - writer->delay(writer, ticks); - - return Common::kNoError; -} - -static Common::Error midi_gm_reset_timer(uint32 ts) { - writer->reset_timer(writer); - - return Common::kNoError; -} - -#define MIDI_MASTER_VOLUME_LEN 8 - -static Common::Error midi_gm_volume(uint8 volume) { - byte data[MIDI_MASTER_VOLUME_LEN] = { - 0xf0, - 0x7f, - 0x7f, - 0x04, - 0x01, - volume, - volume, - 0xf7 - }; - - writer->write(writer, data, MIDI_MASTER_VOLUME_LEN); - if (writer->flush) - writer->flush(writer); - - return Common::kNoError; -} - -static Common::Error midi_gm_allstop() { - byte data[3] = { 0xb0, - 0x78, /* all sound off */ - 0 - }; - int i; - - /* All sound off on all channels */ - for (i = 0; i < 16; i++) { - data[0] = 0xb0 | i; - writer->write(writer, data, 3); - } - if (writer->flush) - writer->flush(writer); - - return Common::kNoError; -} - -static Common::Error midi_gm_reverb(int reverb) { - byte data[3] = { 0xb0, - 91, /* set reverb */ - reverb - }; - int i; - - /* Set reverb on all channels */ - for (i = 0; i < 16; i++) - if (i != 9) { - data[0] = 0xb0 | i; - writer->write(writer, data, 3); - } - if (writer->flush) - writer->flush(writer); - - return Common::kNoError; -} - -static Common::Error midi_gm_set_option(char *x, char *y) { - return Common::kUnknownError; -} - -sfx_sequencer_t sfx_sequencer_gm = { - "General MIDI", - "0.1", - SFX_DEVICE_MIDI, - &midi_gm_set_option, - &midi_gm_open, - &midi_gm_close, - &midi_gm_event, - &midi_gm_delay, - &midi_gm_reset_timer, - &midi_gm_allstop, - &midi_gm_volume, - &midi_gm_reverb, - 004, /* patch.004 */ - 001, /* patch.001 */ - 0x01, /* playflag */ - 1, /* do play rhythm */ - 64, /* max polyphony */ - 0 /* no write-ahead needed inherently */ -}; -#endif - -} // End of namespace Sci diff --git a/engines/sci/sfx/seq/instrument-map.cpp b/engines/sci/sfx/seq/instrument-map.cpp deleted file mode 100644 index 7c13f7f78e..0000000000 --- a/engines/sci/sfx/seq/instrument-map.cpp +++ /dev/null @@ -1,505 +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 "common/scummsys.h" -#include "sci/sfx/softseq/mididriver.h" -#include "sci/sfx/seq/instrument-map.h" - -namespace Sci { - -sfx_instrument_map_t *sfx_instrument_map_new(int velocity_maps_nr) { - sfx_instrument_map_t *map = (sfx_instrument_map_t *)malloc(sizeof(sfx_instrument_map_t)); - int i; - - map->initialisation_block_size = 0; - map->initialisation_block = NULL; - - map->velocity_maps_nr = velocity_maps_nr; - map->percussion_velocity_map_index = SFX_NO_VELOCITY_MAP; - - if (velocity_maps_nr == 0) - map->velocity_map = NULL; /* Yes, this complicates control flow needlessly, but it avoids some of the pointless - ** warnings that certain memory tools seem to find appropriate. */ - else { - map->velocity_map = (byte **)malloc(sizeof(byte *) * velocity_maps_nr); - for (i = 0; i < velocity_maps_nr; ++i) - map->velocity_map[i] = (byte *)malloc(SFX_VELOCITIES_NR); - } - for (i = 0; i < SFX_INSTRUMENTS_NR; ++i) - map->velocity_map_index[i] = SFX_NO_VELOCITY_MAP; - - map->percussion_volume_adjust = 0; - for (i = 0; i < SFX_RHYTHM_NR; ++i) - map->percussion_map[i] = i; - - - for (i = 0; i < SFX_INSTRUMENTS_NR; ++i) { - map->patch_map[i].patch = i; - map->patch_key_shift[i] = 0; - map->patch_volume_adjust[i] = 0; - } - - return map; -} - -void sfx_instrument_map_free(sfx_instrument_map_t *map) { - if (!map) - return; - - if (map->velocity_map) { - int i; - for (i = 0; i < map->velocity_maps_nr; i++) - free(map->velocity_map[i]); - free(map->velocity_map); - map->velocity_map = NULL; - } - - if (map->initialisation_block) { - free(map->initialisation_block); - map->initialisation_block = NULL; - } - - free(map); -} - -#define PATCH_MAP_OFFSET 0x0000 -#define PATCH_KEY_SHIFT_OFFSET 0x0080 -#define PATCH_VOLUME_ADJUST_OFFSET 0x0100 -#define PATCH_PERCUSSION_MAP_OFFSET 0x0180 -#define PATCH_PERCUSSION_VOLUME_ADJUST 0x0200 -#define PATCH_VELOCITY_MAP_INDEX 0x0201 -#define PATCH_VELOCITY_MAP(i) (0x0281 + (0x80 * i)) -#define PATCH_INIT_DATA_SIZE_LE 0x0481 -#define PATCH_INIT_DATA 0x0483 - -#define PATCH_INSTRUMENT_MAPS_NR 4 - -#define PATCH_MIN_SIZE PATCH_INIT_DATA - - -static int patch001_type0_length(byte *data, size_t length) { - unsigned int pos = 492 + 246 * data[491]; - - /* printf("timbres %d (post = %04x)\n",data[491], pos);*/ - - if ((length >= (pos + 386)) && (data[pos] == 0xAB) && (data[pos + 1] == 0xCD)) - pos += 386; - - /* printf("pos = %04x (%02x %02x)\n", pos, data[pos], data[pos + 1]); */ - - if ((length >= (pos + 267)) && (data[pos] == 0xDC) && (data[pos + 1] == 0xBA)) - pos += 267; - - /* printf("pos = %04x %04x (%d)\n", pos, length, pos-length); */ - - - if (pos == length) - return 1; - return 0; -} - -static int patch001_type1_length(byte *data, size_t length) { - if ((length >= 1155) && (((data[1154] << 8) + data[1153] + 1155) == (int)length)) - return 1; - return 0; -} - -int sfx_instrument_map_detect(byte *data, size_t length) { - /* length test */ - if (length < 1155) - return SFX_MAP_MT32; - if (length > 16889) - return SFX_MAP_MT32_GM; - if (patch001_type0_length(data, length) && - !patch001_type1_length(data, length)) - return SFX_MAP_MT32; - if (patch001_type1_length(data, length) && - !patch001_type0_length(data, length)) - return SFX_MAP_MT32_GM; - return SFX_MAP_UNKNOWN; -} - - -sfx_instrument_map_t *sfx_instrument_map_load_sci(byte *data, size_t size) { - sfx_instrument_map_t * map; - int i, m; - - if (data == NULL) - return NULL; - - if (size < PATCH_MIN_SIZE) { - warning("[instrument-map] Instrument map too small: %d of %d", (int) size, PATCH_MIN_SIZE); - return NULL; - } - - map = sfx_instrument_map_new(PATCH_INSTRUMENT_MAPS_NR); - - /* Set up MIDI intialisation data */ - map->initialisation_block_size = (int16)READ_LE_UINT16(data + PATCH_INIT_DATA_SIZE_LE); - if (map->initialisation_block_size) { - if (size < PATCH_MIN_SIZE + map->initialisation_block_size) { - warning("[instrument-map] Instrument map too small for initialisation block: %d of %d", (int) size, PATCH_MIN_SIZE); - return NULL; - } - - if (size > PATCH_MIN_SIZE + map->initialisation_block_size) - warning("[instrument-map] Instrument larger than required by initialisation block: %d of %d", (int) size, PATCH_MIN_SIZE); - - if (map->initialisation_block_size != 0) { - map->initialisation_block = (byte *)malloc(map->initialisation_block_size); - memcpy(map->initialisation_block, data + PATCH_INIT_DATA, map->initialisation_block_size); - } - } - - /* Set up basic instrument info */ - for (i = 0; i < SFX_INSTRUMENTS_NR; i++) { - map->patch_map[i].patch = (char)data[PATCH_MAP_OFFSET + i]; - map->patch_key_shift[i] = (char)data[PATCH_KEY_SHIFT_OFFSET + i]; - map->patch_volume_adjust[i] = (char)data[PATCH_VOLUME_ADJUST_OFFSET + i]; - map->patch_bend_range[i] = SFX_UNMAPPED; - map->velocity_map_index[i] = data[PATCH_VELOCITY_MAP_INDEX + i]; - } - - /* Set up percussion maps */ - map->percussion_volume_adjust = data[PATCH_PERCUSSION_VOLUME_ADJUST]; - for (i = 0; i < SFX_RHYTHM_NR; i++) { - map->percussion_map[i] = data[PATCH_PERCUSSION_MAP_OFFSET + i]; - map->percussion_velocity_scale[i] = SFX_MAX_VELOCITY; - } - - /* Set up velocity maps */ - for (m = 0; m < PATCH_INSTRUMENT_MAPS_NR; m++) { - byte *velocity_map = map->velocity_map[m]; - for (i = 0; i < SFX_VELOCITIES_NR; i++) - velocity_map[i] = data[PATCH_VELOCITY_MAP(m) + i]; - } - - map->percussion_velocity_map_index = 0; - - return map; -} - - -/* Output with the instrument map */ -#define MIDI_CHANNELS_NR 0x10 - -struct decorated_midi_writer_t : public midi_writer_t { - midi_writer_t *writer; - sfx_patch_map_t patches[MIDI_CHANNELS_NR]; - sfx_instrument_map_t *map; -}; - - -static void init_decorated(struct _midi_writer *self_) { - decorated_midi_writer_t *self = (decorated_midi_writer_t *) self_; - self->writer->init(self->writer); -} - -static void set_option_decorated(struct _midi_writer *self_, char *name, char *value) { - decorated_midi_writer_t *self = (decorated_midi_writer_t *) self_; - self->writer->set_option(self->writer, name, value); -} - -static void delay_decorated(struct _midi_writer *self_, int ticks) { - decorated_midi_writer_t *self = (decorated_midi_writer_t *) self_; - self->writer->delay(self->writer, ticks); -} - -static void flush_decorated(struct _midi_writer *self_) { - decorated_midi_writer_t *self = (decorated_midi_writer_t *) self_; - if (self->writer->flush) - self->writer->flush(self->writer); -} - -static void reset_timer_decorated(struct _midi_writer *self_) { - decorated_midi_writer_t *self = (decorated_midi_writer_t *) self_; - self->writer->reset_timer(self->writer); -} - - -static void close_decorated(decorated_midi_writer_t *self) { - sfx_instrument_map_free(self->map); - self->map = NULL; - self->writer->close(self->writer); - free((void *)self->name); - self->name = NULL; - free(self); -} - -#define BOUND_127(x) (((x) < 0)? 0 : (((x) > 0x7f)? 0x7f : (x))) - -static int bound_hard_127(int i, const char *descr) { - int r = BOUND_127(i); - if (r != i) - warning("[instrument-map] Hard-clipping %02x to %02x in %s", i, r, descr); - return r; -} - -static Common::Error set_bend_range(midi_writer_t *writer, int channel, int range) { - byte buf[3] = {0xb0, 0x65, 0x00}; - - buf[0] |= channel & 0xf; - if (writer->write(writer, buf, 3) != Common::kNoError) - return Common::kUnknownError; - - buf[1] = 0x64; - if (writer->write(writer, buf, 3) != Common::kNoError) - return Common::kUnknownError; - - buf[1] = 0x06; - buf[2] = BOUND_127(range); - if (writer->write(writer, buf, 3) != Common::kNoError) - return Common::kUnknownError; - - buf[1] = 0x26; - buf[2] = 0; - if (writer->write(writer, buf, 3) != Common::kNoError) - return Common::kUnknownError; - - return Common::kNoError; -} - -static Common::Error write_decorated(decorated_midi_writer_t *self, byte *buf, int len) { - sfx_instrument_map_t *map = self->map; - int op = *buf & 0xf0; - int chan = *buf & 0x0f; - int patch = self->patches[chan].patch; - int rhythm = self->patches[chan].rhythm; - - assert(len >= 1); - - if (op == 0xC0 && chan != MIDI_RHYTHM_CHANNEL) { /* Program change */ - /*int*/ - patch = bound_hard_127(buf[1], "program change"); - int instrument = map->patch_map[patch].patch; - int bend_range = map->patch_bend_range[patch]; - - self->patches[chan] = map->patch_map[patch]; - - if (instrument == SFX_UNMAPPED || instrument == SFX_MAPPED_TO_RHYTHM) - return Common::kNoError; - - assert(len >= 2); - buf[1] = bound_hard_127(instrument, "patch lookup"); - - if (self->writer->write(self->writer, buf, len) != Common::kNoError) - return Common::kUnknownError; - - if (bend_range != SFX_UNMAPPED) - return set_bend_range(self->writer, chan, bend_range); - - return Common::kNoError; - } - - if (chan == MIDI_RHYTHM_CHANNEL || patch == SFX_MAPPED_TO_RHYTHM) { - /* Rhythm channel handling */ - switch (op) { - case 0x80: - case 0x90: { /* Note off / note on */ - int velocity, instrument, velocity_map_index, velocity_scale; - - if (patch == SFX_MAPPED_TO_RHYTHM) { - buf[0] = (buf[0] & ~0x0f) | MIDI_RHYTHM_CHANNEL; - instrument = rhythm; - velocity_scale = SFX_MAX_VELOCITY; - } else { - int instrument_index = bound_hard_127(buf[1], "rhythm instrument index"); - instrument = map->percussion_map[instrument_index]; - velocity_scale = map->percussion_velocity_scale[instrument_index]; - } - - if (instrument == SFX_UNMAPPED) - return Common::kNoError; - - assert(len >= 3); - - velocity = bound_hard_127(buf[2], "rhythm velocity"); - velocity_map_index = map->percussion_velocity_map_index; - - if (velocity_map_index != SFX_NO_VELOCITY_MAP) - velocity = BOUND_127(velocity + map->velocity_map[velocity_map_index][velocity]); - - velocity = BOUND_127(velocity * velocity_scale / SFX_MAX_VELOCITY); - - buf[1] = bound_hard_127(instrument, "rhythm instrument"); - buf[2] = velocity; - - break; - } - - case 0xB0: { /* Controller change */ - assert(len >= 3); - if (buf[1] == 0x7) /* Volume change */ - buf[2] = BOUND_127(buf[2] + map->percussion_volume_adjust); - break; - } - - default: - break; - } - - } else { - /* Instrument channel handling */ - - if (patch == SFX_UNMAPPED) - return Common::kNoError; - - switch (op) { - case 0x80: - case 0x90: { /* Note off / note on */ - int note = bound_hard_127(buf[1], "note"); - int velocity = bound_hard_127(buf[2], "velocity"); - int velocity_map_index = map->velocity_map_index[patch]; - assert(len >= 3); - - note += map->patch_key_shift[patch]; - /* Not the most efficient solutions, but the least error-prone */ - while (note < 0) - note += 12; - while (note > 0x7f) - note -= 12; - - if (velocity_map_index != SFX_NO_VELOCITY_MAP) - velocity = BOUND_127(velocity + map->velocity_map[velocity_map_index][velocity]); - - buf[1] = note; - buf[2] = velocity; - break; - } - - case 0xB0: /* Controller change */ - assert(len >= 3); - if (buf[1] == 0x7) /* Volume change */ - buf[2] = BOUND_127(buf[2] + map->patch_volume_adjust[patch]); - break; - - default: - break; - } - } - - return self->writer->write(self->writer, buf, len); -} - -#define MIDI_BYTES_PER_SECOND 3250 /* This seems to be the minimum guarantee by the standard */ -#define MAX_PER_TICK (MIDI_BYTES_PER_SECOND / 60) /* After this, we ought to issue one tick of pause */ - -static void init(midi_writer_t *writer, byte *data, size_t len) { - size_t offset = 0; - byte status = 0; - - /* Send init data as separate MIDI commands */ - while (offset < len) { - int args; - byte op = data[offset]; - byte msg[3]; - int i; - - if (op == 0xf0) { - int msg_len; - byte *find = (byte *) memchr(data + offset, 0xf7, len - offset); - - if (!find) { - warning("[instrument-map] Failed to find end of sysex message"); - return; - } - - msg_len = find - data - offset + 1; - writer->write(writer, data + offset, msg_len); - - /* Wait at least 40ms after sysex */ - writer->delay(writer, 3); - offset += msg_len; - continue; - } - - if (op < 0x80) - op = status; - else { - status = op; - offset++; - } - - msg[0] = op; - - switch (op & 0xf0) { - case 0xc0: - case 0xd0: - args = 1; - break; - default: - args = 2; - } - - if (args + offset > len) { - warning("[instrument-map] Insufficient bytes remaining for MIDI command %02x", op); - return; - } - - for (i = 0; i < args; i++) - msg[i + 1] = data[offset + i]; - - writer->write(writer, msg, args + 1); - offset += args; - - if (writer->flush) - writer->flush(writer); - } -} - -#define NAME_SUFFIX "+instruments" - -midi_writer_t *sfx_mapped_writer(midi_writer_t *writer, sfx_instrument_map_t *map) { - int i; - decorated_midi_writer_t *retval; - - if (map == NULL) - return writer; - - retval = (decorated_midi_writer_t *)malloc(sizeof(decorated_midi_writer_t)); - retval->writer = writer; - retval->name = (char *)malloc(strlen(writer->name) + strlen(NAME_SUFFIX) + 1); - strcpy(retval->name, writer->name); - strcat(retval->name, NAME_SUFFIX); - - retval->init = (Common::Error (*)(midi_writer_t *)) init_decorated; - retval->set_option = (Common::Error (*)(midi_writer_t *, char *, char *)) set_option_decorated; - retval->write = (Common::Error (*)(midi_writer_t *, byte *, int)) write_decorated; - retval->delay = (void (*)(midi_writer_t *, int)) delay_decorated; - retval->flush = (void (*)(midi_writer_t *)) flush_decorated; - retval->reset_timer = (void (*)(midi_writer_t *)) reset_timer_decorated; - retval->close = (void (*)(midi_writer_t *)) close_decorated; - - retval->map = map; - - init(writer, map->initialisation_block, map->initialisation_block_size); - - for (i = 0; i < MIDI_CHANNELS_NR; i++) - retval->patches[i].patch = SFX_UNMAPPED; - - return (midi_writer_t *) retval; -} - -} // End of namespace Sci diff --git a/engines/sci/sfx/seq/instrument-map.h b/engines/sci/sfx/seq/instrument-map.h deleted file mode 100644 index e0c52ca735..0000000000 --- a/engines/sci/sfx/seq/instrument-map.h +++ /dev/null @@ -1,125 +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$ - * - */ - -/* Implementation of SCI instrument maps for GM and MT-32. */ - -#ifndef SCI_SFX_SEQ_INSTRUMENT_MAP_H -#define SCI_SFX_SEQ_INSTRUMENT_MAP_H - -#include "sci/sfx/seq/midiwriter.h" - -namespace Sci { - -#define SFX_INSTRUMENTS_NR 0x80 -#define SFX_RHYTHM_NR 0x80 -#define SFX_VELOCITIES_NR 0x80 -#define SFX_NO_VELOCITY_MAP -1 /* use in velocity_map_index to indicate that no map should be used */ - -/* Instrument map types */ -#define SFX_MAP_UNKNOWN 0 -#define SFX_MAP_MT32 1 /* Original MT-32 map format */ -#define SFX_MAP_MT32_GM 2 /* More recent map format used for both MT-32 and GM */ - -/* Patch not mapped */ -#define SFX_UNMAPPED -1 -/* Patch mapped to rhythm key */ -#define SFX_MAPPED_TO_RHYTHM -2 - -/* Maximum velocity (used for scaling) */ -#define SFX_MAX_VELOCITY 128 - -struct sfx_patch_map_t { - int patch; /* Native instrument, SFX_UNMAPPED or SFX_MAPPED_TO_RHYTHM */ - int rhythm; /* Rhythm key when patch == SFX_MAPPED_TO_RHYTHM */ -}; - -struct sfx_instrument_map_t { - sfx_patch_map_t patch_map[SFX_INSTRUMENTS_NR]; /* Map patch nr to which native instrument or rhythm key */ - int patch_key_shift[SFX_INSTRUMENTS_NR]; /* Shift patch key by how much? */ - int patch_volume_adjust[SFX_INSTRUMENTS_NR]; /* Adjust controller 7 by how much? */ - int patch_bend_range[SFX_INSTRUMENTS_NR]; /* Bend range in semitones or SFX_UNMAPPED for default */ - - int percussion_map[SFX_RHYTHM_NR]; /* Map percussion instrument (RHYTH_CHANNEL) to what native 'key'? */ - int percussion_volume_adjust; /* unused in SCI patches */ - - int velocity_map_index[SFX_INSTRUMENTS_NR]; /* Velocity translation map to use for that instrument */ - int velocity_maps_nr; /* How many velocity translation maps do we have? */ - byte **velocity_map; /* velocity_maps_nr entries, each of size SFX_VELOCITIES_NR */ - int percussion_velocity_map_index; /* Special index for the percussion map */ - int percussion_velocity_scale[SFX_INSTRUMENTS_NR]; /* Velocity scale (0 - SFX_PERC_MAX_VOL) */ - - size_t initialisation_block_size; - byte *initialisation_block; /* Initial MIDI commands to set up the device */ -}; - -sfx_instrument_map_t *sfx_instrument_map_new(int velocity_maps_nr); -/* Constructs a new default-initialised velocity map -** Parameters: (int) velocity_maps_nr: Number of velocity maps to allocate -** Returns : (sfx_instrument_map *) an initialised instrument map -*/ - -void sfx_instrument_map_free(sfx_instrument_map_t *map); -/* Deallocates an instrument map -** Parameters: (sfx_instrument_map *) map: The map to deallocate, or NULL for a no-op -*/ - -sfx_instrument_map_t *sfx_instrument_map_load_sci(byte *data, size_t length); -/* Allocate and initialise an instrument map from SCI data -** Parameters: (byte *) Pointer to the data to initialise from -** (size_t) Number of bytes to expect within -** Returns : (sfx_instrument_map_t *) An initialised instrument map for these settings, or NULL -** if `data' is NULL or `data' and `length' do not permit a valid instrument map -** If `data' is null, the function will return NULL quietly. -*/ - -sfx_instrument_map_t *sfx_instrument_map_mt32_to_gm(byte *data, size_t size); -/* Allocate and initialise an instrument map from MT-32 patch data -** Parameters: (byte *) Pointer to the MT-32 patch data to initialise from -** (size_t) Number of bytes to expect within -** Returns : (sfx_instrument_map_t *) An initialised instrument map for these settings -** If `data' is null or invalid, the function will return a default MT-32 to GM map. -*/ - -int sfx_instrument_map_detect(byte *data, size_t size); -/* Detects the type of patch data -** Parameters: (byte *) Pointer to the patch data -** (size_t) Number of bytes to expect within -** Returns : (int) SFX_MAP_SCI1 for an SCI1 instrument map, SFX_MAP_SCI0_MT32 for SCI0 MT-32 patch data, -** or SFX_MAP_UNKNOWN for unknown. -*/ - -midi_writer_t *sfx_mapped_writer(midi_writer_t *writer, sfx_instrument_map_t *map); -/* Wrap a midi_writer_t into an instrument map -** Parameters: (midi_writer_t *) writer: The writer to wrap -** (sfx_instrument_map_t *) map: The map to apply to all commands going into the writer, or NULL -** Returns : (midi_writer_t *) A MIDI writer that preprocesses all data by `map' and otherwise relies on `writer' -** Effects : If successful and neccessary, this operation will send initialisation messages to the writer, as needed. -** If `map' is NULL, this returns `writer'. Otherwise it sets up a Decorator that handles translation and automatically -** deallocates the instrument map when the writer is closed. -*/ - -} // End of namespace Sci - -#endif // SCI_SFX_SEQ_INSTRUMENT_MAP_H diff --git a/engines/sci/sfx/seq/map-mt32-to-gm.cpp b/engines/sci/sfx/seq/map-mt32-to-gm.cpp deleted file mode 100644 index 269f6cb24f..0000000000 --- a/engines/sci/sfx/seq/map-mt32-to-gm.cpp +++ /dev/null @@ -1,792 +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 "common/scummsys.h" -#include "sci/resource.h" -#include "sci/engine/state.h" -#include "sci/sfx/seq/instrument-map.h" - -namespace Sci { - -#define DEBUG_MT32_TO_GM - -static const char *GM_Instrument_Names[] = { - /*000*/ "Acoustic Grand Piano", - /*001*/ "Bright Acoustic Piano", - /*002*/ "Electric Grand Piano", - /*003*/ "Honky-tonk Piano", - /*004*/ "Electric Piano 1", - /*005*/ "Electric Piano 2", - /*006*/ "Harpsichord", - /*007*/ "Clavinet", - /*008*/ "Celesta", - /*009*/ "Glockenspiel", - /*010*/ "Music Box", - /*011*/ "Vibraphone", - /*012*/ "Marimba", - /*013*/ "Xylophone", - /*014*/ "Tubular Bells", - /*015*/ "Dulcimer", - /*016*/ "Drawbar Organ", - /*017*/ "Percussive Organ", - /*018*/ "Rock Organ", - /*019*/ "Church Organ", - /*020*/ "Reed Organ", - /*021*/ "Accordion", - /*022*/ "Harmonica", - /*023*/ "Tango Accordion", - /*024*/ "Acoustic Guitar (nylon)", - /*025*/ "Acoustic Guitar (steel)", - /*026*/ "Electric Guitar (jazz)", - /*027*/ "Electric Guitar (clean)", - /*028*/ "Electric Guitar (muted)", - /*029*/ "Overdriven Guitar", - /*030*/ "Distortion Guitar", - /*031*/ "Guitar Harmonics", - /*032*/ "Acoustic Bass", - /*033*/ "Electric Bass (finger)", - /*034*/ "Electric Bass (pick)", - /*035*/ "Fretless Bass", - /*036*/ "Slap Bass 1", - /*037*/ "Slap Bass 2", - /*038*/ "Synth Bass 1", - /*039*/ "Synth Bass 2", - /*040*/ "Violin", - /*041*/ "Viola", - /*042*/ "Cello", - /*043*/ "Contrabass", - /*044*/ "Tremolo Strings", - /*045*/ "Pizzicato Strings", - /*046*/ "Orchestral Harp", - /*047*/ "Timpani", - /*048*/ "String Ensemble 1", - /*049*/ "String Ensemble 2", - /*050*/ "SynthStrings 1", - /*051*/ "SynthStrings 2", - /*052*/ "Choir Aahs", - /*053*/ "Voice Oohs", - /*054*/ "Synth Voice", - /*055*/ "Orchestra Hit", - /*056*/ "Trumpet", - /*057*/ "Trombone", - /*058*/ "Tuba", - /*059*/ "Muted Trumpet", - /*060*/ "French Horn", - /*061*/ "Brass Section", - /*062*/ "SynthBrass 1", - /*063*/ "SynthBrass 2", - /*064*/ "Soprano Sax", - /*065*/ "Alto Sax", - /*066*/ "Tenor Sax", - /*067*/ "Baritone Sax", - /*068*/ "Oboe", - /*069*/ "English Horn", - /*070*/ "Bassoon", - /*071*/ "Clarinet", - /*072*/ "Piccolo", - /*073*/ "Flute", - /*074*/ "Recorder", - /*075*/ "Pan Flute", - /*076*/ "Blown Bottle", - /*077*/ "Shakuhachi", - /*078*/ "Whistle", - /*079*/ "Ocarina", - /*080*/ "Lead 1 (square)", - /*081*/ "Lead 2 (sawtooth)", - /*082*/ "Lead 3 (calliope)", - /*083*/ "Lead 4 (chiff)", - /*084*/ "Lead 5 (charang)", - /*085*/ "Lead 6 (voice)", - /*086*/ "Lead 7 (fifths)", - /*087*/ "Lead 8 (bass+lead)", - /*088*/ "Pad 1 (new age)", - /*089*/ "Pad 2 (warm)", - /*090*/ "Pad 3 (polysynth)", - /*091*/ "Pad 4 (choir)", - /*092*/ "Pad 5 (bowed)", - /*093*/ "Pad 6 (metallic)", - /*094*/ "Pad 7 (halo)", - /*095*/ "Pad 8 (sweep)", - /*096*/ "FX 1 (rain)", - /*097*/ "FX 2 (soundtrack)", - /*098*/ "FX 3 (crystal)", - /*099*/ "FX 4 (atmosphere)", - /*100*/ "FX 5 (brightness)", - /*101*/ "FX 6 (goblins)", - /*102*/ "FX 7 (echoes)", - /*103*/ "FX 8 (sci-fi)", - /*104*/ "Sitar", - /*105*/ "Banjo", - /*106*/ "Shamisen", - /*107*/ "Koto", - /*108*/ "Kalimba", - /*109*/ "Bag pipe", - /*110*/ "Fiddle", - /*111*/ "Shannai", - /*112*/ "Tinkle Bell", - /*113*/ "Agogo", - /*114*/ "Steel Drums", - /*115*/ "Woodblock", - /*116*/ "Taiko Drum", - /*117*/ "Melodic Tom", - /*118*/ "Synth Drum", - /*119*/ "Reverse Cymbal", - /*120*/ "Guitar Fret Noise", - /*121*/ "Breath Noise", - /*122*/ "Seashore", - /*123*/ "Bird Tweet", - /*124*/ "Telephone Ring", - /*125*/ "Helicopter", - /*126*/ "Applause", - /*127*/ "Gunshot" -}; - -/* The GM Percussion map is downwards compatible to the MT32 map, which is used in SCI */ -static const char *GM_Percussion_Names[] = { - /*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /*20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /*30*/ 0, 0, 0, 0, - /* The preceeding percussions are not covered by the GM standard */ - /*34*/ "Acoustic Bass Drum", - /*35*/ "Bass Drum 1", - /*36*/ "Side Stick", - /*37*/ "Acoustic Snare", - /*38*/ "Hand Clap", - /*39*/ "Electric Snare", - /*40*/ "Low Floor Tom", - /*41*/ "Closed Hi-Hat", - /*42*/ "High Floor Tom", - /*43*/ "Pedal Hi-Hat", - /*44*/ "Low Tom", - /*45*/ "Open Hi-Hat", - /*46*/ "Low-Mid Tom", - /*47*/ "Hi-Mid Tom", - /*48*/ "Crash Cymbal 1", - /*49*/ "High Tom", - /*50*/ "Ride Cymbal 1", - /*51*/ "Chinese Cymbal", - /*52*/ "Ride Bell", - /*53*/ "Tambourine", - /*54*/ "Splash Cymbal", - /*55*/ "Cowbell", - /*56*/ "Crash Cymbal 2", - /*57*/ "Vibraslap", - /*58*/ "Ride Cymbal 2", - /*59*/ "Hi Bongo", - /*60*/ "Low Bongo", - /*61*/ "Mute Hi Conga", - /*62*/ "Open Hi Conga", - /*63*/ "Low Conga", - /*64*/ "High Timbale", - /*65*/ "Low Timbale", - /*66*/ "High Agogo", - /*67*/ "Low Agogo", - /*68*/ "Cabasa", - /*69*/ "Maracas", - /*70*/ "Short Whistle", - /*71*/ "Long Whistle", - /*72*/ "Short Guiro", - /*73*/ "Long Guiro", - /*74*/ "Claves", - /*75*/ "Hi Wood Block", - /*76*/ "Low Wood Block", - /*77*/ "Mute Cuica", - /*78*/ "Open Cuica", - /*79*/ "Mute Triangle", - /*80*/ "Open Triangle" -}; - -/******************************************* - * Fancy instrument mappings begin here... * - *******************************************/ - - -static struct { - const char *name; - int8 gm_instr; - int8 gm_rhythm_key; -} MT32_PresetTimbreMaps[] = { - /*000*/ {"AcouPiano1", 0, SFX_UNMAPPED}, - /*001*/ {"AcouPiano2", 1, SFX_UNMAPPED}, - /*002*/ {"AcouPiano3", 0, SFX_UNMAPPED}, - /*003*/ {"ElecPiano1", 4, SFX_UNMAPPED}, - /*004*/ {"ElecPiano2", 5, SFX_UNMAPPED}, - /*005*/ {"ElecPiano3", 4, SFX_UNMAPPED}, - /*006*/ {"ElecPiano4", 5, SFX_UNMAPPED}, - /*007*/ {"Honkytonk ", 3, SFX_UNMAPPED}, - /*008*/ {"Elec Org 1", 16, SFX_UNMAPPED}, - /*009*/ {"Elec Org 2", 17, SFX_UNMAPPED}, - /*010*/ {"Elec Org 3", 18, SFX_UNMAPPED}, - /*011*/ {"Elec Org 4", 18, SFX_UNMAPPED}, - /*012*/ {"Pipe Org 1", 19, SFX_UNMAPPED}, - /*013*/ {"Pipe Org 2", 19, SFX_UNMAPPED}, - /*014*/ {"Pipe Org 3", 20, SFX_UNMAPPED}, - /*015*/ {"Accordion ", 21, SFX_UNMAPPED}, - /*016*/ {"Harpsi 1 ", 6, SFX_UNMAPPED}, - /*017*/ {"Harpsi 2 ", 6, SFX_UNMAPPED}, - /*018*/ {"Harpsi 3 ", 6, SFX_UNMAPPED}, - /*019*/ {"Clavi 1 ", 7, SFX_UNMAPPED}, - /*020*/ {"Clavi 2 ", 7, SFX_UNMAPPED}, - /*021*/ {"Clavi 3 ", 7, SFX_UNMAPPED}, - /*022*/ {"Celesta 1 ", 8, SFX_UNMAPPED}, - /*023*/ {"Celesta 2 ", 8, SFX_UNMAPPED}, - /*024*/ {"Syn Brass1", 62, SFX_UNMAPPED}, - /*025*/ {"Syn Brass2", 63, SFX_UNMAPPED}, - /*026*/ {"Syn Brass3", 62, SFX_UNMAPPED}, - /*027*/ {"Syn Brass4", 63, SFX_UNMAPPED}, - /*028*/ {"Syn Bass 1", 38, SFX_UNMAPPED}, - /*029*/ {"Syn Bass 2", 39, SFX_UNMAPPED}, - /*030*/ {"Syn Bass 3", 38, SFX_UNMAPPED}, - /*031*/ {"Syn Bass 4", 39, SFX_UNMAPPED}, - /*032*/ {"Fantasy ", 88, SFX_UNMAPPED}, - /*033*/ {"Harmo Pan ", 89, SFX_UNMAPPED}, - /*034*/ {"Chorale ", 52, SFX_UNMAPPED}, - /*035*/ {"Glasses ", 98, SFX_UNMAPPED}, - /*036*/ {"Soundtrack", 97, SFX_UNMAPPED}, - /*037*/ {"Atmosphere", 99, SFX_UNMAPPED}, - /*038*/ {"Warm Bell ", 89, SFX_UNMAPPED}, - /*039*/ {"Funny Vox ", 85, SFX_UNMAPPED}, - /*040*/ {"Echo Bell ", 39, SFX_UNMAPPED}, - /*041*/ {"Ice Rain ", 101, SFX_UNMAPPED}, - /*042*/ {"Oboe 2001 ", 68, SFX_UNMAPPED}, - /*043*/ {"Echo Pan ", 87, SFX_UNMAPPED}, - /*044*/ {"DoctorSolo", 86, SFX_UNMAPPED}, - /*045*/ {"Schooldaze", 103, SFX_UNMAPPED}, - /*046*/ {"BellSinger", 88, SFX_UNMAPPED}, - /*047*/ {"SquareWave", 80, SFX_UNMAPPED}, - /*048*/ {"Str Sect 1", 48, SFX_UNMAPPED}, - /*049*/ {"Str Sect 2", 48, SFX_UNMAPPED}, - /*050*/ {"Str Sect 3", 49, SFX_UNMAPPED}, - /*051*/ {"Pizzicato ", 45, SFX_UNMAPPED}, - /*052*/ {"Violin 1 ", 40, SFX_UNMAPPED}, - /*053*/ {"Violin 2 ", 40, SFX_UNMAPPED}, - /*054*/ {"Cello 1 ", 42, SFX_UNMAPPED}, - /*055*/ {"Cello 2 ", 42, SFX_UNMAPPED}, - /*056*/ {"Contrabass", 43, SFX_UNMAPPED}, - /*057*/ {"Harp 1 ", 46, SFX_UNMAPPED}, - /*058*/ {"Harp 2 ", 46, SFX_UNMAPPED}, - /*059*/ {"Guitar 1 ", 24, SFX_UNMAPPED}, - /*060*/ {"Guitar 2 ", 25, SFX_UNMAPPED}, - /*061*/ {"Elec Gtr 1", 26, SFX_UNMAPPED}, - /*062*/ {"Elec Gtr 2", 27, SFX_UNMAPPED}, - /*063*/ {"Sitar ", 104, SFX_UNMAPPED}, - /*064*/ {"Acou Bass1", 32, SFX_UNMAPPED}, - /*065*/ {"Acou Bass2", 33, SFX_UNMAPPED}, - /*066*/ {"Elec Bass1", 34, SFX_UNMAPPED}, - /*067*/ {"Elec Bass2", 39, SFX_UNMAPPED}, - /*068*/ {"Slap Bass1", 36, SFX_UNMAPPED}, - /*069*/ {"Slap Bass2", 37, SFX_UNMAPPED}, - /*070*/ {"Fretless 1", 35, SFX_UNMAPPED}, - /*071*/ {"Fretless 2", 35, SFX_UNMAPPED}, - /*072*/ {"Flute 1 ", 73, SFX_UNMAPPED}, - /*073*/ {"Flute 2 ", 73, SFX_UNMAPPED}, - /*074*/ {"Piccolo 1 ", 72, SFX_UNMAPPED}, - /*075*/ {"Piccolo 2 ", 72, SFX_UNMAPPED}, - /*076*/ {"Recorder ", 74, SFX_UNMAPPED}, - /*077*/ {"Panpipes ", 75, SFX_UNMAPPED}, - /*078*/ {"Sax 1 ", 64, SFX_UNMAPPED}, - /*079*/ {"Sax 2 ", 65, SFX_UNMAPPED}, - /*080*/ {"Sax 3 ", 66, SFX_UNMAPPED}, - /*081*/ {"Sax 4 ", 67, SFX_UNMAPPED}, - /*082*/ {"Clarinet 1", 71, SFX_UNMAPPED}, - /*083*/ {"Clarinet 2", 71, SFX_UNMAPPED}, - /*084*/ {"Oboe ", 68, SFX_UNMAPPED}, - /*085*/ {"Engl Horn ", 69, SFX_UNMAPPED}, - /*086*/ {"Bassoon ", 70, SFX_UNMAPPED}, - /*087*/ {"Harmonica ", 22, SFX_UNMAPPED}, - /*088*/ {"Trumpet 1 ", 56, SFX_UNMAPPED}, - /*089*/ {"Trumpet 2 ", 56, SFX_UNMAPPED}, - /*090*/ {"Trombone 1", 57, SFX_UNMAPPED}, - /*091*/ {"Trombone 2", 57, SFX_UNMAPPED}, - /*092*/ {"Fr Horn 1 ", 60, SFX_UNMAPPED}, - /*093*/ {"Fr Horn 2 ", 60, SFX_UNMAPPED}, - /*094*/ {"Tuba ", 58, SFX_UNMAPPED}, - /*095*/ {"Brs Sect 1", 61, SFX_UNMAPPED}, - /*096*/ {"Brs Sect 2", 61, SFX_UNMAPPED}, - /*097*/ {"Vibe 1 ", 11, SFX_UNMAPPED}, - /*098*/ {"Vibe 2 ", 11, SFX_UNMAPPED}, - /*099*/ {"Syn Mallet", 15, SFX_UNMAPPED}, - /*100*/ {"Wind Bell ", 88, SFX_UNMAPPED}, - /*101*/ {"Glock ", 9, SFX_UNMAPPED}, - /*102*/ {"Tube Bell ", 14, SFX_UNMAPPED}, - /*103*/ {"Xylophone ", 13, SFX_UNMAPPED}, - /*104*/ {"Marimba ", 12, SFX_UNMAPPED}, - /*105*/ {"Koto ", 107, SFX_UNMAPPED}, - /*106*/ {"Sho ", 111, SFX_UNMAPPED}, - /*107*/ {"Shakuhachi", 77, SFX_UNMAPPED}, - /*108*/ {"Whistle 1 ", 78, SFX_UNMAPPED}, - /*109*/ {"Whistle 2 ", 78, SFX_UNMAPPED}, - /*110*/ {"BottleBlow", 76, SFX_UNMAPPED}, - /*111*/ {"BreathPipe", 121, SFX_UNMAPPED}, - /*112*/ {"Timpani ", 47, SFX_UNMAPPED}, - /*113*/ {"MelodicTom", 117, SFX_UNMAPPED}, - /*114*/ {"Deep Snare", SFX_MAPPED_TO_RHYTHM, 37}, - /*115*/ {"Elec Perc1", 115, SFX_UNMAPPED}, /* ? */ - /*116*/ {"Elec Perc2", 118, SFX_UNMAPPED}, /* ? */ - /*117*/ {"Taiko ", 116, SFX_UNMAPPED}, - /*118*/ {"Taiko Rim ", 118, SFX_UNMAPPED}, - /*119*/ {"Cymbal ", SFX_MAPPED_TO_RHYTHM, 50}, - /*120*/ {"Castanets ", SFX_MAPPED_TO_RHYTHM, SFX_UNMAPPED}, - /*121*/ {"Triangle ", 112, SFX_UNMAPPED}, - /*122*/ {"Orche Hit ", 55, SFX_UNMAPPED}, - /*123*/ {"Telephone ", 124, SFX_UNMAPPED}, - /*124*/ {"Bird Tweet", 123, SFX_UNMAPPED}, - /*125*/ {"OneNoteJam", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? */ - /*126*/ {"WaterBells", 98, SFX_UNMAPPED}, - /*127*/ {"JungleTune", SFX_UNMAPPED, SFX_UNMAPPED} /* ? */ -}; - -static struct { - const char *name; - int8 gm_instr; - int8 gm_rhythmkey; -} MT32_RhythmTimbreMaps[] = { - /*00*/ {"Acou BD ", SFX_MAPPED_TO_RHYTHM, 34}, - /*01*/ {"Acou SD ", SFX_MAPPED_TO_RHYTHM, 37}, - /*02*/ {"Acou HiTom", 117, 49}, - /*03*/ {"AcouMidTom", 117, 46}, - /*04*/ {"AcouLowTom", 117, 40}, - /*05*/ {"Elec SD ", SFX_MAPPED_TO_RHYTHM, 39}, - /*06*/ {"Clsd HiHat", SFX_MAPPED_TO_RHYTHM, 41}, - /*07*/ {"OpenHiHat1", SFX_MAPPED_TO_RHYTHM, 45}, - /*08*/ {"Crash Cym ", SFX_MAPPED_TO_RHYTHM, 48}, - /*09*/ {"Ride Cym ", SFX_MAPPED_TO_RHYTHM, 50}, - /*10*/ {"Rim Shot ", SFX_MAPPED_TO_RHYTHM, 36}, - /*11*/ {"Hand Clap ", SFX_MAPPED_TO_RHYTHM, 38}, - /*12*/ {"Cowbell ", SFX_MAPPED_TO_RHYTHM, 55}, - /*13*/ {"Mt HiConga", SFX_MAPPED_TO_RHYTHM, 61}, - /*14*/ {"High Conga", SFX_MAPPED_TO_RHYTHM, 62}, - /*15*/ {"Low Conga ", SFX_MAPPED_TO_RHYTHM, 63}, - /*16*/ {"Hi Timbale", SFX_MAPPED_TO_RHYTHM, 64}, - /*17*/ {"LowTimbale", SFX_MAPPED_TO_RHYTHM, 65}, - /*18*/ {"High Bongo", SFX_MAPPED_TO_RHYTHM, 59}, - /*19*/ {"Low Bongo ", SFX_MAPPED_TO_RHYTHM, 60}, - /*20*/ {"High Agogo", 113, 66}, - /*21*/ {"Low Agogo ", 113, 67}, - /*22*/ {"Tambourine", SFX_MAPPED_TO_RHYTHM, 53}, - /*23*/ {"Claves ", SFX_MAPPED_TO_RHYTHM, 74}, - /*24*/ {"Maracas ", SFX_MAPPED_TO_RHYTHM, 69}, - /*25*/ {"SmbaWhis L", 78, 71}, - /*26*/ {"SmbaWhis S", 78, 70}, - /*27*/ {"Cabasa ", SFX_MAPPED_TO_RHYTHM, 68}, - /*28*/ {"Quijada ", SFX_MAPPED_TO_RHYTHM, 72}, - /*29*/ {"OpenHiHat2", SFX_MAPPED_TO_RHYTHM, 43} -}; - -static int8 MT32_PresetRhythmKeymap[] = { - SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, - SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, - SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, - SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, 34, 34, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, SFX_UNMAPPED, SFX_UNMAPPED, 53, SFX_UNMAPPED, 55, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, SFX_UNMAPPED, 74, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, - SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, - SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, - SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, - SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, - SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED -}; - -/* +++ - Don't change unless you've got a good reason - ++ - Looks good, sounds ok - + - Not too bad, but is it right? - ? - Where do I map this one? - ?? - Any good ideas? - ??? - I'm clueless? - R - Rhythm... */ -static struct { - const char *name; - int8 gm_instr; - int8 gm_rhythm_key; -} MT32_MemoryTimbreMaps[] = { - {"AccPnoKA2 ", 1, SFX_UNMAPPED}, /* ++ (KQ1) */ - {"Acou BD ", SFX_MAPPED_TO_RHYTHM, 34}, /* R (PQ2) */ - {"Acou SD ", SFX_MAPPED_TO_RHYTHM, 37}, /* R (PQ2) */ - {"AcouPnoKA ", 0, SFX_UNMAPPED}, /* ++ (KQ1) */ - {"BASS ", 32, SFX_UNMAPPED}, /* + (LSL3) */ - {"BASSOONPCM", 70, SFX_UNMAPPED}, /* + (CB) */ - {"BEACH WAVE", 122, SFX_UNMAPPED}, /* + (LSL3) */ - {"BagPipes ", 109, SFX_UNMAPPED}, - {"BassPizzMS", 45, SFX_UNMAPPED}, /* ++ (HQ) */ - {"BassoonKA ", 70, SFX_UNMAPPED}, /* ++ (KQ1) */ - {"Bell MS", 112, SFX_UNMAPPED}, /* ++ (iceMan) */ - {"Bells MS", 112, SFX_UNMAPPED}, /* + (HQ) */ - {"Big Bell ", 14, SFX_UNMAPPED}, /* + (CB) */ - {"Bird Tweet", 123, SFX_UNMAPPED}, - {"BrsSect MS", 61, SFX_UNMAPPED}, /* +++ (iceMan) */ - {"CLAPPING ", 126, SFX_UNMAPPED}, /* ++ (LSL3) */ - {"Cabasa ", SFX_MAPPED_TO_RHYTHM, 68}, /* R (HBoG) */ - {"Calliope ", 82, SFX_UNMAPPED}, /* +++ (HQ) */ - {"CelticHarp", 46, SFX_UNMAPPED}, /* ++ (CoC) */ - {"Chicago MS", 1, SFX_UNMAPPED}, /* ++ (iceMan) */ - {"Chop ", 117, SFX_UNMAPPED}, - {"Chorale MS", 52, SFX_UNMAPPED}, /* + (CoC) */ - {"ClarinetMS", 71, SFX_UNMAPPED}, - {"Claves ", SFX_MAPPED_TO_RHYTHM, 74}, /* R (PQ2) */ - {"Claw MS", 118, SFX_UNMAPPED}, /* + (HQ) */ - {"ClockBell ", 14, SFX_UNMAPPED}, /* + (CB) */ - {"ConcertCym", SFX_MAPPED_TO_RHYTHM, 54}, /* R ? (KQ1) */ - {"Conga MS", SFX_MAPPED_TO_RHYTHM, 63}, /* R (HQ) */ - {"CoolPhone ", 124, SFX_UNMAPPED}, /* ++ (LSL3) */ - {"CracklesMS", 115, SFX_UNMAPPED}, /* ? (CoC, HQ) */ - {"CreakyD MS", SFX_UNMAPPED, SFX_UNMAPPED}, /* ??? (KQ1) */ - {"Cricket ", 120, SFX_UNMAPPED}, /* ? (CB) */ - {"CrshCymbMS", SFX_MAPPED_TO_RHYTHM, 56}, /* R +++ (iceMan) */ - {"CstlGateMS", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? (HQ) */ - {"CymSwellMS", SFX_MAPPED_TO_RHYTHM, 54}, /* R ? (CoC, HQ) */ - {"CymbRollKA", SFX_MAPPED_TO_RHYTHM, 56}, /* R ? (KQ1) */ - {"Cymbal Lo ", SFX_UNMAPPED, SFX_UNMAPPED}, /* R ? (LSL3) */ - {"card ", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? (HBoG) */ - {"DirtGtr MS", 30, SFX_UNMAPPED}, /* + (iceMan) */ - {"DirtGtr2MS", 29, SFX_UNMAPPED}, /* + (iceMan) */ - {"E Bass MS", 33, SFX_UNMAPPED}, /* + (SQ3) */ - {"ElecBassMS", 33, SFX_UNMAPPED}, - {"ElecGtr MS", 27, SFX_UNMAPPED}, /* ++ (iceMan) */ - {"EnglHornMS", 69, SFX_UNMAPPED}, - {"FantasiaKA", 88, SFX_UNMAPPED}, - {"Fantasy ", 99, SFX_UNMAPPED}, /* + (PQ2) */ - {"Fantasy2MS", 99, SFX_UNMAPPED}, /* ++ (CoC, HQ) */ - {"Filter MS", 95, SFX_UNMAPPED}, /* +++ (iceMan) */ - {"Filter2 MS", 95, SFX_UNMAPPED}, /* ++ (iceMan) */ - {"Flame2 MS", 121, SFX_UNMAPPED}, /* ? (HQ) */ - {"Flames MS", 121, SFX_UNMAPPED}, /* ? (HQ) */ - {"Flute MS", 73, SFX_UNMAPPED}, /* +++ (HQ) */ - {"FogHorn MS", 58, SFX_UNMAPPED}, - {"FrHorn1 MS", 60, SFX_UNMAPPED}, /* +++ (HQ) */ - {"FunnyTrmp ", 56, SFX_UNMAPPED}, /* ++ (CB) */ - {"GameSnd MS", 80, SFX_UNMAPPED}, - {"Glock MS", 9, SFX_UNMAPPED}, /* +++ (HQ) */ - {"Gunshot ", 127, SFX_UNMAPPED}, /* +++ (CB) */ - {"Hammer MS", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? (HQ) */ - {"Harmonica2", 22, SFX_UNMAPPED}, /* +++ (CB) */ - {"Harpsi 1 ", 6, SFX_UNMAPPED}, /* + (HBoG) */ - {"Harpsi 2 ", 6, SFX_UNMAPPED}, /* +++ (CB) */ - {"Heart MS", 116, SFX_UNMAPPED}, /* ? (iceMan) */ - {"Horse1 MS", 115, SFX_UNMAPPED}, /* ? (CoC, HQ) */ - {"Horse2 MS", 115, SFX_UNMAPPED}, /* ? (CoC, HQ) */ - {"InHale MS", 121, SFX_UNMAPPED}, /* ++ (iceMan) */ - {"KNIFE ", 120, SFX_UNMAPPED}, /* ? (LSL3) */ - {"KenBanjo ", 105, SFX_UNMAPPED}, /* +++ (CB) */ - {"Kiss MS", 25, SFX_UNMAPPED}, /* ++ (HQ) */ - {"KongHit ", SFX_UNMAPPED, SFX_UNMAPPED}, /* ??? (KQ1) */ - {"Koto ", 107, SFX_UNMAPPED}, /* +++ (PQ2) */ - {"Laser MS", 81, SFX_UNMAPPED}, /* ?? (HQ) */ - {"Meeps MS", 62, SFX_UNMAPPED}, /* ? (HQ) */ - {"MTrak MS", 62, SFX_UNMAPPED}, /* ?? (iceMan) */ - {"MachGun MS", 127, SFX_UNMAPPED}, /* ? (iceMan) */ - {"OCEANSOUND", 122, SFX_UNMAPPED}, /* + (LSL3) */ - {"Oboe 2001 ", 68, SFX_UNMAPPED}, /* + (PQ2) */ - {"Ocean MS", 122, SFX_UNMAPPED}, /* + (iceMan) */ - {"PPG 2.3 MS", 75, SFX_UNMAPPED}, /* ? (iceMan) */ - {"PianoCrank", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? (CB) */ - {"PicSnareMS", SFX_MAPPED_TO_RHYTHM, 39}, /* R ? (iceMan) */ - {"PiccoloKA ", 72, SFX_UNMAPPED}, /* +++ (KQ1) */ - {"PinkBassMS", 39, SFX_UNMAPPED}, - {"Pizz2 ", 45, SFX_UNMAPPED}, /* ++ (CB) */ - {"Portcullis", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? (KQ1) */ - {"Raspbry MS", 81, SFX_UNMAPPED}, /* ? (HQ) */ - {"RatSqueek ", 72, SFX_UNMAPPED}, /* ? (CB, CoC) */ - {"Record78 ", SFX_UNMAPPED, SFX_UNMAPPED}, /* +++ (CB) */ - {"RecorderMS", 74, SFX_UNMAPPED}, /* +++ (CoC) */ - {"Red Baron ", 125, SFX_UNMAPPED}, /* ? (CB) */ - {"ReedPipMS ", 20, SFX_UNMAPPED}, /* +++ (Coc) */ - {"RevCymb MS", 119, SFX_UNMAPPED}, - {"RifleShot ", 127, SFX_UNMAPPED}, /* + (CB) */ - {"RimShot MS", SFX_MAPPED_TO_RHYTHM, 36}, /* R */ - {"SHOWER ", 52, SFX_UNMAPPED}, /* ? (LSL3) */ - {"SQ Bass MS", 32, SFX_UNMAPPED}, /* + (SQ3) */ - {"ShakuVibMS", 79, SFX_UNMAPPED}, /* + (iceMan) */ - {"SlapBassMS", 36, SFX_UNMAPPED}, /* +++ (iceMan) */ - {"Snare MS", SFX_MAPPED_TO_RHYTHM, 37}, /* R (HQ) */ - {"Some Birds", 123, SFX_UNMAPPED}, /* + (CB) */ - {"Sonar MS", 78, SFX_UNMAPPED}, /* ? (iceMan) */ - {"Soundtrk2 ", 97, SFX_UNMAPPED}, /* +++ (CB) */ - {"Soundtrack", 97, SFX_UNMAPPED}, /* ++ (CoC) */ - {"SqurWaveMS", 80, SFX_UNMAPPED}, - {"StabBassMS", 34, SFX_UNMAPPED}, /* + (iceMan) */ - {"SteelDrmMS", 114, SFX_UNMAPPED}, /* +++ (iceMan) */ - {"StrSect1MS", 48, SFX_UNMAPPED}, /* ++ (HQ) */ - {"String MS", 45, SFX_UNMAPPED}, /* + (CoC) */ - {"Syn-Choir ", 91, SFX_UNMAPPED}, - {"Syn Brass4", 63, SFX_UNMAPPED}, /* ++ (PQ2) */ - {"SynBass MS", 38, SFX_UNMAPPED}, - {"SwmpBackgr", 120, SFX_UNMAPPED}, /* ?? (CB,HQ) */ - {"T-Bone2 MS", 57, SFX_UNMAPPED}, /* +++ (HQ) */ - {"Taiko ", 116, 34}, /* +++ (Coc) */ - {"Taiko Rim ", 118, 36}, /* +++ (LSL3) */ - {"Timpani1 ", 47, SFX_UNMAPPED}, /* +++ (CB) */ - {"Tom MS", 117, 47}, /* +++ (iceMan) */ - {"Toms MS", 117, 47}, /* +++ (CoC, HQ) */ - {"Tpt1prtl ", 56, SFX_UNMAPPED}, /* +++ (KQ1) */ - {"TriangleMS", 112, 80}, /* R (CoC) */ - {"Trumpet 1 ", 56, SFX_UNMAPPED}, /* +++ (CoC) */ - {"Type MS", 114, SFX_UNMAPPED}, /* ? (iceMan) */ - {"WaterBells", 98, SFX_UNMAPPED}, /* + (PQ2) */ - {"WaterFallK", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? (KQ1) */ - {"Whiporill ", 123, SFX_UNMAPPED}, /* + (CB) */ - {"Wind ", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? (CB) */ - {"Wind MS", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? (HQ, iceMan) */ - {"Wind2 MS", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? (CoC) */ - {"Woodpecker", 115, SFX_UNMAPPED}, /* ? (CB) */ - {"WtrFall MS", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? (CoC, HQ, iceMan) */ - {0, 0, 0} -}; - -static int8 lookup_instrument(const char *iname) { - int i = 0; - - while (MT32_MemoryTimbreMaps[i].name) { - if (scumm_strnicmp(iname, MT32_MemoryTimbreMaps[i].name, 10) == 0) - return MT32_MemoryTimbreMaps[i].gm_instr; - i++; - } - return SFX_UNMAPPED; -} - -static int8 lookup_rhythm_key(const char *iname) { - int i = 0; - - while (MT32_MemoryTimbreMaps[i].name) { - if (scumm_strnicmp(iname, MT32_MemoryTimbreMaps[i].name, 10) == 0) - return MT32_MemoryTimbreMaps[i].gm_rhythm_key; - i++; - } - return SFX_UNMAPPED; -} - -static void print_map(int sci, int ins, int rhythm, int mt32) { -#ifdef DEBUG_MT32_TO_GM - if (ins == SFX_UNMAPPED || (ins == SFX_MAPPED_TO_RHYTHM && rhythm == SFX_UNMAPPED)) { - printf("[MT32-to-GM] No mapping available for [%i] `%s' (%i)\n", - sci, MT32_PresetTimbreMaps[mt32].name, mt32); - return; - } - - if (ins == SFX_MAPPED_TO_RHYTHM) { - printf("[MT32-to-GM] Mapping [%i] `%s' (%i) to `%s' [R] (%i)\n", - sci, MT32_PresetTimbreMaps[mt32].name, mt32, - GM_Percussion_Names[rhythm], rhythm); - return; - } - - printf("[MT32-to-GM] Mapping [%i] `%s' (%i) to `%s' (%i)\n", - sci, MT32_PresetTimbreMaps[mt32].name, mt32, - GM_Instrument_Names[ins], ins); -#endif -} - -static void print_map_mem(int sci, int ins, int rhythm, char *mt32) { -#ifdef DEBUG_MT32_TO_GM - char name[11]; - - strncpy(name, mt32, 10); - name[10] = 0; - - if (ins == SFX_UNMAPPED || (ins == SFX_MAPPED_TO_RHYTHM && rhythm == SFX_UNMAPPED)) { - printf("[MT32-to-GM] No mapping available for [%i] `%s'\n", - sci, name); - return; - } - - if (ins == SFX_MAPPED_TO_RHYTHM) { - printf("[MT32-to-GM] Mapping [%i] `%s' to `%s' [R] (%i)\n", - sci, name, GM_Percussion_Names[rhythm], rhythm); - return; - } - - printf("[MT32-to-GM] Mapping [%i] `%s' to `%s' (%i)\n", - sci, name, GM_Instrument_Names[ins], ins); -#endif -} - -static void print_map_rhythm(int sci, int ins, int rhythm, int mt32) { -#ifdef DEBUG_MT32_TO_GM - if (ins == SFX_UNMAPPED || (ins == SFX_MAPPED_TO_RHYTHM && rhythm == SFX_UNMAPPED)) { - printf("[MT32-to-GM] No mapping available for [%i] `%s' [R] (%i)\n", - sci, MT32_RhythmTimbreMaps[mt32].name, mt32); - return; - } - - if (ins == SFX_MAPPED_TO_RHYTHM) { - printf("[MT32-to-GM] Mapping [%i] `%s' [R] (%i) to `%s' [R] (%i)\n", - sci, MT32_RhythmTimbreMaps[mt32].name, mt32, - GM_Percussion_Names[rhythm], rhythm); - return; - } - - printf("[MT32-to-GM] Mapping [%i] `%s' [R] (%i) to `%s' (%i)\n", - sci, MT32_RhythmTimbreMaps[mt32].name, mt32, - GM_Instrument_Names[ins], ins); -#endif -} - -static void print_map_rhythm_mem(int sci, int rhythm, char *mt32) { -#ifdef DEBUG_MT32_TO_GM - char name[11]; - - strncpy(name, mt32, 10); - name[10] = 0; - - if (rhythm == SFX_UNMAPPED) { - printf("[MT32-to-GM] No mapping available for [%i] `%s'\n", - sci, name); - return; - } - - printf("[MT32-to-GM] Mapping [%i] `%s' to `%s' (%i)\n", - sci, name, GM_Percussion_Names[rhythm], rhythm); -#endif -} - -sfx_instrument_map_t *sfx_instrument_map_mt32_to_gm(byte *data, size_t size) { - int memtimbres, patches; - uint8 group, number, keyshift, finetune, bender_range; - uint8 *patchpointer; - uint32 pos; - sfx_instrument_map_t * map; - int i; - int type; - - map = sfx_instrument_map_new(0); - - for (i = 0; i < SFX_INSTRUMENTS_NR; i++) { - map->patch_map[i].patch = MT32_PresetTimbreMaps[i].gm_instr; - map->patch_key_shift[i] = 0; - map->patch_volume_adjust[i] = 0; - map->patch_bend_range[i] = 12; - map->velocity_map_index[i] = SFX_NO_VELOCITY_MAP; - } - - map->percussion_volume_adjust = 0; - map->percussion_velocity_map_index = SFX_NO_VELOCITY_MAP; - - for (i = 0; i < SFX_RHYTHM_NR; i++) { - map->percussion_map[i] = MT32_PresetRhythmKeymap[i]; - map->percussion_velocity_scale[i] = SFX_MAX_VELOCITY; - } - - if (!data) { - printf("[MT32-to-GM] No MT-32 patch data supplied, using default mapping\n"); - return map; - } - - type = sfx_instrument_map_detect(data, size); - - if (type == SFX_MAP_UNKNOWN) { - printf("[MT32-to-GM] Patch data format unknown, using default mapping\n"); - return map; - } - if (type == SFX_MAP_MT32_GM) { - printf("[MT32-to-GM] Patch data format not supported, using default mapping\n"); - return map; - } - - memtimbres = *(data + 0x1EB); - pos = 0x1EC + memtimbres * 0xF6; - - if (size > pos && ((0x100 * *(data + pos) + *(data + pos + 1)) == 0xABCD)) { - patches = 96; - pos += 2 + 8 * 48; - } else - patches = 48; - - printf("[MT32-to-GM] %d MT-32 Patches detected\n", patches); - printf("[MT32-to-GM] %d MT-32 Memory Timbres\n", memtimbres); - - printf("[MT32-to-GM] Mapping patches..\n"); - - for (i = 0; i < patches; i++) { - char *name; - - if (i < 48) - patchpointer = data + 0x6B + 8 * i; - else - patchpointer = data + 0x1EC + 8 * (i - 48) + memtimbres * 0xF6 + 2; - - group = *patchpointer; - number = *(patchpointer + 1); - keyshift = *(patchpointer + 2); - finetune = *(patchpointer + 3); - bender_range = *(patchpointer + 4); - - switch (group) { - case 0: - map->patch_map[i].patch = MT32_PresetTimbreMaps[number].gm_instr; - map->patch_map[i].rhythm = MT32_PresetTimbreMaps[number].gm_rhythm_key; - print_map(i, map->patch_map[i].patch, map->patch_map[i].rhythm, number); - break; - case 1: - map->patch_map[i].patch = MT32_PresetTimbreMaps[number + 64].gm_instr; - map->patch_map[i].rhythm = MT32_PresetTimbreMaps[number + 64].gm_rhythm_key; - print_map(i, map->patch_map[i].patch, map->patch_map[i].rhythm, number + 64); - break; - case 2: - name = (char *) data + 0x1EC + number * 0xF6; - map->patch_map[i].patch = lookup_instrument(name); - map->patch_map[i].rhythm = SFX_UNMAPPED; - print_map_mem(i, map->patch_map[i].patch, map->patch_map[i].rhythm, name); - break; - case 3: - map->patch_map[i].patch = MT32_RhythmTimbreMaps[number].gm_instr; - map->patch_map[i].rhythm = SFX_UNMAPPED; - print_map_rhythm(i, map->patch_map[i].patch, map->patch_map[i].rhythm, number); - break; - default: - break; - } - - /* map->patch_key_shift[i] = (int) (keyshift & 0x3F) - 24; */ - map->patch_bend_range[i] = bender_range & 0x1F; - } - - if (size > pos && ((0x100 * *(data + pos) + *(data + pos + 1)) == 0xDCBA)) { - printf("[MT32-to-GM] Mapping percussion..\n"); - - for (i = 0; i < 64 ; i++) { - number = *(data + pos + 4 * i + 2); - - if (number < 64) { - char *name = (char *) data + 0x1EC + number * 0xF6; - map->percussion_map[i + 23] = lookup_rhythm_key(name); - print_map_rhythm_mem(i, map->percussion_map[i + 23], name); - } else { - if (number < 94) { - map->percussion_map[i + 23] = MT32_RhythmTimbreMaps[number - 64].gm_rhythmkey; - print_map_rhythm(i, SFX_MAPPED_TO_RHYTHM, map->percussion_map[i + 23], number - 64); - } else - map->percussion_map[i + 23] = SFX_UNMAPPED; - } - - map->percussion_velocity_scale[i + 23] = *(data + pos + 4 * i + 3) * SFX_MAX_VELOCITY / 100; - } - } - - return map; -} - -} // End of namespace Sci diff --git a/engines/sci/sfx/seq/midiwriter.h b/engines/sci/sfx/seq/midiwriter.h deleted file mode 100644 index 24e432ffc4..0000000000 --- a/engines/sci/sfx/seq/midiwriter.h +++ /dev/null @@ -1,88 +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 player structure */ - -#ifndef SCI_SFX_SEQ_MIDIWRITER_H -#define SCI_SFX_SEQ_MIDIWRITER_H - -#include "common/scummsys.h" -#include "common/error.h" - -namespace Sci { - -struct midi_writer_t { - char *name; /* Name description of the device */ - - Common::Error (*init)(midi_writer_t *self); - /* Initializes the writer - ** Parameters: (midi_writer_t *) self: Self reference - ** Returns : (int) Common::kNoError on success, Common::kUnknownError if the device could not be - ** opened - */ - - Common::Error (*set_option)(midi_writer_t *self, char *name, char *value); - /* Sets an option for the writer - ** Parameters: (char *) name: Name of the option to set - ** (char *) value: Value of the option to set - ** Returns : (int) Common::kNoError on success, Common::kUnknownError otherwise (unsupported option) - */ - - Common::Error (*write)(midi_writer_t *self, unsigned char *buf, int len); - /* Writes some bytes to the MIDI stream - ** Parameters: (char *) buf: The buffer to write - ** (int) len: Number of bytes to write - ** Returns : (int) Common::kNoError on success, Common::kUnknownError on failure - ** No delta time is expected here. - */ - - void (*delay)(midi_writer_t *self, int ticks); - /* Introduces an explicit delay - ** Parameters: (int) ticks: Number of 60 Hz ticks to sleep - */ - - void (*flush)(midi_writer_t *self); /* May be NULL */ - /* Flushes the MIDI file descriptor - ** Parameters: (midi_writer_t *) self: Self reference - */ - - void (*reset_timer)(midi_writer_t *self); - /* Resets the timer associated with this device - ** Parameters: (midi_writer_t *) self: Self reference - ** This function makes sure that a subsequent write would have effect - ** immediately, and any delay() would be relative to the point in time - ** this function was invoked at. - */ - - void (*close)(midi_writer_t *self); - /* Closes the associated MIDI device - ** Parameters: (midi_writer_t *) self: Self reference - */ -}; - - -} // End of namespace Sci - -#endif // SCI_SFX_SEQ_MIDIWRITER_H diff --git a/engines/sci/sfx/softseq/adlib.cpp b/engines/sci/sfx/softseq/adlib.cpp deleted file mode 100644 index 11802917a2..0000000000 --- a/engines/sci/sfx/softseq/adlib.cpp +++ /dev/null @@ -1,827 +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" - -#include "sound/fmopl.h" -#include "sound/softsynth/emumidi.h" - -#include "sci/resource.h" -#include "sci/sfx/softseq/mididriver.h" - -namespace Sci { - -#ifdef __DC__ -#define STEREO false -#else -#define STEREO true -#endif - -// FIXME: We don't seem to be sending the polyphony init data, so disable this for now -#define ADLIB_DISABLE_VOICE_MAPPING - -class MidiDriver_Adlib : public MidiDriver_Emulated { -public: - enum { - kVoices = 9, - kRhythmKeys = 62 - }; - - MidiDriver_Adlib(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer), _playSwitch(true), _masterVolume(15), _rhythmKeyMap(0), _opl(0) { } - virtual ~MidiDriver_Adlib() { } - - // MidiDriver - int open(bool isSCI0); - void close(); - void send(uint32 b); - MidiChannel *allocateChannel() { return NULL; } - MidiChannel *getPercussionChannel() { return NULL; } - - // AudioStream - bool isStereo() const { return _stereo; } - int getRate() const { return _mixer->getOutputRate(); } - - // MidiDriver_Emulated - void generateSamples(int16 *buf, int len); - - void setVolume(byte volume); - void playSwitch(bool play); - bool loadResource(const byte *data, uint size); - virtual uint32 property(int prop, uint32 param); - -private: - enum ChannelID { - kLeftChannel = 1, - kRightChannel = 2 - }; - - struct AdlibOperator { - bool amplitudeMod; - bool vibrato; - bool envelopeType; - bool kbScaleRate; - byte frequencyMult; // (0-15) - byte kbScaleLevel; // (0-3) - byte totalLevel; // (0-63, 0=max, 63=min) - byte attackRate; // (0-15) - byte decayRate; // (0-15) - byte sustainLevel; // (0-15) - byte releaseRate; // (0-15) - byte waveForm; // (0-3) - }; - - struct AdlibModulator { - byte feedback; // (0-7) - bool algorithm; - }; - - struct AdlibPatch { - AdlibOperator op[2]; - AdlibModulator mod; - }; - - struct Channel { - uint8 patch; // Patch setting - uint8 volume; // Channel volume (0-63) - uint8 pan; // Pan setting (0-127, 64 is center) - uint8 holdPedal; // Hold pedal setting (0 to 63 is off, 127 to 64 is on) - uint8 extraVoices; // The number of additional voices this channel optimally needs - uint16 pitchWheel; // Pitch wheel setting (0-16383, 8192 is center) - uint8 lastVoice; // Last voice used for this MIDI channel - bool enableVelocity; // Enable velocity control (SCI0) - - Channel() : patch(0), volume(63), pan(64), holdPedal(0), extraVoices(0), - pitchWheel(8192), lastVoice(0), enableVelocity(false) { } - }; - - struct AdlibVoice { - int8 channel; // MIDI channel that this voice is assigned to or -1 - int8 note; // Currently playing MIDI note or -1 - int patch; // Currently playing patch or -1 - uint8 velocity; // Note velocity - bool isSustained; // Flag indicating a note that is being sustained by the hold pedal - uint16 age; // Age of the current note - - AdlibVoice() : channel(-1), note(-1), patch(-1), velocity(0), isSustained(false), age(0) { } - }; - - bool _stereo; - bool _isSCI0; - OPL::OPL *_opl; - bool _playSwitch; - int _masterVolume; - Channel _channels[MIDI_CHANNELS]; - AdlibVoice _voices[kVoices]; - byte *_rhythmKeyMap; - Common::Array<AdlibPatch> _patches; - - void loadInstrument(const byte *ins); - void voiceOn(int voice, int note, int velocity); - void voiceOff(int voice); - void setPatch(int voice, int patch); - void setNote(int voice, int note, bool key); - void setVelocity(int voice); - void setOperator(int oper, AdlibOperator &op); - void setRegister(int reg, int value, int channels = kLeftChannel | kRightChannel); - void renewNotes(int channel, bool key); - void noteOn(int channel, int note, int velocity); - void noteOff(int channel, int note); - int findVoice(int channel); - void voiceMapping(int channel, int voices); - void assignVoices(int channel, int voices); - void releaseVoices(int channel, int voices); - void donateVoices(); - int findVoiceBasic(int channel); - void setVelocityReg(int regOffset, int velocity, int kbScaleLevel, int pan); - int calcVelocity(int voice, int op); -}; - -class MidiPlayer_Adlib : public MidiPlayer { -public: - MidiPlayer_Adlib() { _driver = new MidiDriver_Adlib(g_system->getMixer()); } - int open(ResourceManager *resMan); - int getPlayMask(SciVersion soundVersion); - int getPolyphony() const { return MidiDriver_Adlib::kVoices; } - bool hasRhythmChannel() const { return false; } - void setVolume(byte volume) { static_cast<MidiDriver_Adlib *>(_driver)->setVolume(volume); } - void playSwitch(bool play) { static_cast<MidiDriver_Adlib *>(_driver)->playSwitch(play); } - void loadInstrument(int idx, byte *data); -}; - -static const byte registerOffset[MidiDriver_Adlib::kVoices] = { - 0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, 0x12 -}; - -static const byte velocityMap1[64] = { - 0x00, 0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x12, 0x13, - 0x14, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x1c, 0x1d, - 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, - 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2d, 0x2d, 0x2e, - 0x2f, 0x30, 0x31, 0x32, 0x32, 0x33, 0x34, 0x34, - 0x35, 0x36, 0x36, 0x37, 0x38, 0x38, 0x39, 0x3a, - 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, - 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f -}; - -static const byte velocityMap2[64] = { - 0x00, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, - 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x21, - 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, - 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x2f, 0x30, - 0x31, 0x32, 0x32, 0x33, 0x34, 0x34, 0x35, 0x36, - 0x36, 0x37, 0x38, 0x38, 0x39, 0x39, 0x3a, 0x3a, - 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, - 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f -}; - -static const int ym3812_note[13] = { - 0x157, 0x16b, 0x181, 0x198, 0x1b0, 0x1ca, - 0x1e5, 0x202, 0x220, 0x241, 0x263, 0x287, - 0x2ae -}; - -int MidiDriver_Adlib::open(bool isSCI0) { - int rate = _mixer->getOutputRate(); - - _stereo = STEREO; - - debug(3, "ADLIB: Starting driver in %s mode", (isSCI0 ? "SCI0" : "SCI1")); - _isSCI0 = isSCI0; - - _opl = OPL::Config::create(isStereo() ? OPL::Config::kDualOpl2 : OPL::Config::kOpl2); - - // Try falling back to mono, thus plain OPL2 emualtor, when no Dual OPL2 is available. - if (!_opl && _stereo) { - _stereo = false; - _opl = OPL::Config::create(OPL::Config::kOpl2); - } - - if (!_opl) - return -1; - - _opl->init(rate); - - setRegister(0xBD, 0); - setRegister(0x08, 0); - setRegister(0x01, 0x20); - - MidiDriver_Emulated::open(); - - _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_mixerSoundHandle, this, -1, _mixer->kMaxChannelVolume, 0, false); - - return 0; -} - -void MidiDriver_Adlib::close() { - _mixer->stopHandle(_mixerSoundHandle); - - delete _opl; - delete[] _rhythmKeyMap; -} - -void MidiDriver_Adlib::setVolume(byte volume) { - _masterVolume = volume; - renewNotes(-1, true); -} - -// MIDI messages can be found at http://www.midi.org/techspecs/midimessages.php -void MidiDriver_Adlib::send(uint32 b) { - byte command = b & 0xf0; - byte channel = b & 0xf; - byte op1 = (b >> 8) & 0xff; - byte op2 = (b >> 16) & 0xff; - - switch (command) { - case 0x80: - noteOff(channel, op1); - break; - case 0x90: - noteOn(channel, op1, op2); - break; - case 0xe0: - _channels[channel].pitchWheel = (op1 & 0x7f) | ((op2 & 0x7f) << 7); - renewNotes(channel, true); - break; - case 0xb0: - switch (op1) { - case 0x07: - _channels[channel].volume = op2 >> 1; - renewNotes(channel, true); - break; - case 0x0a: - _channels[channel].pan = op2; - renewNotes(channel, true); - break; - case 0x40: - _channels[channel].holdPedal = op2; - if (op2 == 0) { - for (int i = 0; i < kVoices; i++) { - if ((_voices[i].channel == channel) && _voices[i].isSustained) - voiceOff(i); - } - } - break; - case 0x4b: -#ifndef ADLIB_DISABLE_VOICE_MAPPING - voiceMapping(channel, op2); -#endif - break; - case 0x4e: - // FIXME: this flag should be set to 0 when a new song is started - debug(3, "ADLIB: Setting velocity control flag for channel %i to %i", channel, op2); - _channels[channel].enableVelocity = op2; - break; - case SCI_MIDI_CHANNEL_NOTES_OFF: - for (int i = 0; i < kVoices; i++) - if ((_voices[i].channel == channel) && (_voices[i].note != -1)) - voiceOff(i); - break; - default: - //warning("ADLIB: ignoring MIDI command %02x %02x %02x", command | channel, op1, op2); - break; - } - break; - case 0xc0: - _channels[channel].patch = op1; - break; - // The original adlib driver from sierra ignores aftertouch completely, so should we - case 0xa0: // Polyphonic key pressure (aftertouch) - case 0xd0: // Channel pressure (aftertouch) - break; - case 0xf0: // SysEx, ignore it - break; - default: - warning("ADLIB: Unknown event %02x", command); - } -} - -void MidiDriver_Adlib::generateSamples(int16 *data, int len) { - if (isStereo()) - len <<= 1; - _opl->readBuffer(data, len); - - // Increase the age of the notes - for (int i = 0; i < kVoices; i++) { - if (_voices[i].note != -1) - _voices[i].age++; - } -} - -void MidiDriver_Adlib::loadInstrument(const byte *ins) { - AdlibPatch patch; - - // Set data for the operators - for (int i = 0; i < 2; i++) { - const byte *op = ins + i * 13; - patch.op[i].kbScaleLevel = op[0] & 0x3; - patch.op[i].frequencyMult = op[1] & 0xf; - patch.op[i].attackRate = op[3] & 0xf; - patch.op[i].sustainLevel = op[4] & 0xf; - patch.op[i].envelopeType = op[5]; - patch.op[i].decayRate = op[6] & 0xf; - patch.op[i].releaseRate = op[7] & 0xf; - patch.op[i].totalLevel = op[8] & 0x3f; - patch.op[i].amplitudeMod = op[9]; - patch.op[i].vibrato = op[10]; - patch.op[i].kbScaleRate = op[11]; - } - patch.op[0].waveForm = ins[26] & 0x3; - patch.op[1].waveForm = ins[27] & 0x3; - - // Set data for the modulator - patch.mod.feedback = ins[2] & 0x7; - patch.mod.algorithm = !ins[12]; // Flag is inverted - - _patches.push_back(patch); -} - -void MidiDriver_Adlib::voiceMapping(int channel, int voices) { - int curVoices = 0; - - for (int i = 0; i < kVoices; i++) - if (_voices[i].channel == channel) - curVoices++; - - curVoices += _channels[channel].extraVoices; - - if (curVoices < voices) { - debug(3, "ADLIB: assigning %i additional voices to channel %i", voices - curVoices, channel); - assignVoices(channel, voices - curVoices); - } else if (curVoices > voices) { - debug(3, "ADLIB: releasing %i voices from channel %i", curVoices - voices, channel); - releaseVoices(channel, curVoices - voices); - donateVoices(); - } -} - -void MidiDriver_Adlib::assignVoices(int channel, int voices) { - assert(voices > 0); - - for (int i = 0; i < kVoices; i++) - if (_voices[i].channel == -1) { - _voices[i].channel = channel; - if (--voices == 0) - return; - } - - _channels[channel].extraVoices += voices; -} - -void MidiDriver_Adlib::releaseVoices(int channel, int voices) { - if (_channels[channel].extraVoices >= voices) { - _channels[channel].extraVoices -= voices; - return; - } - - voices -= _channels[channel].extraVoices; - _channels[channel].extraVoices = 0; - - for (int i = 0; i < kVoices; i++) { - if ((_voices[i].channel == channel) && (_voices[i].note == -1)) { - _voices[i].channel = -1; - if (--voices == 0) - return; - } - } - - for (int i = 0; i < kVoices; i++) { - if (_voices[i].channel == channel) { - voiceOff(i); - _voices[i].channel = -1; - if (--voices == 0) - return; - } - } -} - -void MidiDriver_Adlib::donateVoices() { - int freeVoices = 0; - - for (int i = 0; i < kVoices; i++) - if (_voices[i].channel == -1) - freeVoices++; - - if (freeVoices == 0) - return; - - for (int i = 0; i < MIDI_CHANNELS; i++) { - if (_channels[i].extraVoices >= freeVoices) { - assignVoices(i, freeVoices); - _channels[i].extraVoices -= freeVoices; - return; - } else if (_channels[i].extraVoices > 0) { - assignVoices(i, _channels[i].extraVoices); - freeVoices -= _channels[i].extraVoices; - _channels[i].extraVoices = 0; - } - } -} - -void MidiDriver_Adlib::renewNotes(int channel, bool key) { - for (int i = 0; i < kVoices; i++) { - // Update all notes playing this channel - if ((channel == -1) || (_voices[i].channel == channel)) { - if (_voices[i].note != -1) - setNote(i, _voices[i].note, key); - } - } -} - -void MidiDriver_Adlib::noteOn(int channel, int note, int velocity) { - if (velocity == 0) - return noteOff(channel, note); - - velocity >>= 1; - - // Check for playable notes - if ((note < 12) || (note > 107)) - return; - - for (int i = 0; i < kVoices; i++) { - if ((_voices[i].channel == channel) && (_voices[i].note == note)) { - voiceOff(i); - voiceOn(i, note, velocity); - return; - } - } - -#ifdef ADLIB_DISABLE_VOICE_MAPPING - int voice = findVoiceBasic(channel); -#else - int voice = findVoice(channel); -#endif - - if (voice == -1) { - debug(3, "ADLIB: failed to find free voice assigned to channel %i", channel); - return; - } - - voiceOn(voice, note, velocity); -} - -// FIXME: Temporary, see comment at top of file regarding ADLIB_DISABLE_VOICE_MAPPING -int MidiDriver_Adlib::findVoiceBasic(int channel) { - int voice = -1; - int oldestVoice = -1; - int oldestAge = -1; - - // Try to find a voice assigned to this channel that is free (round-robin) - for (int i = 0; i < kVoices; i++) { - int v = (_channels[channel].lastVoice + i + 1) % kVoices; - - if (_voices[v].note == -1) { - voice = v; - break; - } - - // We also keep track of the oldest note in case the search fails - if (_voices[v].age > oldestAge) { - oldestAge = _voices[v].age; - oldestVoice = v; - } - } - - if (voice == -1) { - if (oldestVoice != -1) { - voiceOff(oldestVoice); - voice = oldestVoice; - } else { - return -1; - } - } - - _voices[voice].channel = channel; - _channels[channel].lastVoice = voice; - return voice; -} - -int MidiDriver_Adlib::findVoice(int channel) { - int voice = -1; - int oldestVoice = -1; - uint32 oldestAge = 0; - - // Try to find a voice assigned to this channel that is free (round-robin) - for (int i = 0; i < kVoices; i++) { - int v = (_channels[channel].lastVoice + i + 1) % kVoices; - - if (_voices[v].channel == channel) { - if (_voices[v].note == -1) { - voice = v; - break; - } - - // We also keep track of the oldest note in case the search fails - // Notes started in the current time slice will not be selected - if (_voices[v].age > oldestAge) { - oldestAge = _voices[v].age; - oldestVoice = v; - } - } - } - - if (voice == -1) { - if (oldestVoice != -1) { - voiceOff(oldestVoice); - voice = oldestVoice; - } else { - return -1; - } - } - - _channels[channel].lastVoice = voice; - return voice; -} - -void MidiDriver_Adlib::noteOff(int channel, int note) { - for (int i = 0; i < kVoices; i++) { - if ((_voices[i].channel == channel) && (_voices[i].note == note)) { - if (_channels[channel].holdPedal) - _voices[i].isSustained = true; - else - voiceOff(i); - return; - } - } -} - -void MidiDriver_Adlib::voiceOn(int voice, int note, int velocity) { - int channel = _voices[voice].channel; - int patch; - - _voices[voice].age = 0; - - if ((channel == 9) && _rhythmKeyMap) { - patch = CLIP(note, 27, 88) + 101; - } else { - patch = _channels[channel].patch; - } - - // Set patch if different from current patch - if ((patch != _voices[voice].patch) && _playSwitch) - setPatch(voice, patch); - - _voices[voice].velocity = velocity; - setNote(voice, note, true); -} - -void MidiDriver_Adlib::voiceOff(int voice) { - _voices[voice].isSustained = false; - setNote(voice, _voices[voice].note, 0); - _voices[voice].note = -1; - _voices[voice].age = 0; -} - -void MidiDriver_Adlib::setNote(int voice, int note, bool key) { - int channel = _voices[voice].channel; - int n, fre, oct; - float delta; - int bend = _channels[channel].pitchWheel; - - if ((channel == 9) && _rhythmKeyMap) { - note = _rhythmKeyMap[CLIP(note, 27, 88) - 27]; - } - - _voices[voice].note = note; - - delta = 0; - - n = note % 12; - - if (bend < 8192) - bend = 8192 - bend; - delta = (float)pow(2.0, (bend % 8192) / 8192.0); - - if (bend > 8192) - fre = (int)(ym3812_note[n] * delta); - else - fre = (int)(ym3812_note[n] / delta); - - oct = note / 12 - 1; - - if (oct < 0) - oct = 0; - - if (oct > 7) - oct = 7; - - setRegister(0xA0 + voice, fre & 0xff); - setRegister(0xB0 + voice, (key << 5) | (oct << 2) | (fre >> 8)); - - setVelocity(voice); -} - -void MidiDriver_Adlib::setVelocity(int voice) { - AdlibPatch &patch = _patches[_voices[voice].patch]; - int pan = _channels[_voices[voice].channel].pan; - setVelocityReg(registerOffset[voice] + 3, calcVelocity(voice, 1), patch.op[1].kbScaleLevel, pan); - - // In AM mode we need to set the level for both operators - if (_patches[_voices[voice].patch].mod.algorithm == 1) - setVelocityReg(registerOffset[voice], calcVelocity(voice, 0), patch.op[0].kbScaleLevel, pan); -} - -int MidiDriver_Adlib::calcVelocity(int voice, int op) { - if (_isSCI0) { - int velocity = _masterVolume; - - if (velocity > 0) - velocity += 3; - - if (velocity > 15) - velocity = 15; - - int insVelocity; - if (_channels[_voices[voice].channel].enableVelocity) - insVelocity = _voices[voice].velocity; - else - insVelocity = 63 - _patches[_voices[voice].patch].op[op].totalLevel; - - // Note: Later SCI0 has a static table that is close to this formula, but not exactly the same. - // Early SCI0 does (velocity * (insVelocity / 15)) - return velocity * insVelocity / 15; - } else { - AdlibOperator &oper = _patches[_voices[voice].patch].op[op]; - int velocity = _channels[_voices[voice].channel].volume + 1; - velocity = velocity * (velocityMap1[_voices[voice].velocity] + 1) / 64; - velocity = velocity * (_masterVolume + 1) / 16; - - if (--velocity < 0) - velocity = 0; - - return velocityMap2[velocity] * (63 - oper.totalLevel) / 63; - } -} - -void MidiDriver_Adlib::setVelocityReg(int regOffset, int velocity, int kbScaleLevel, int pan) { - if (!_playSwitch) - velocity = 0; - - if (isStereo()) { - int velLeft = velocity; - int velRight = velocity; - - if (pan > 0x40) - velLeft = velLeft * (0x7f - pan) / 0x3f; - else if (pan < 0x40) - velRight = velRight * pan / 0x40; - - setRegister(0x40 + regOffset, (kbScaleLevel << 6) | (63 - velLeft), kLeftChannel); - setRegister(0x40 + regOffset, (kbScaleLevel << 6) | (63 - velRight), kRightChannel); - } else { - setRegister(0x40 + regOffset, (kbScaleLevel << 6) | (63 - velocity)); - } -} - -void MidiDriver_Adlib::setPatch(int voice, int patch) { - if ((patch < 0) || ((uint)patch >= _patches.size())) { - warning("ADLIB: Invalid patch %i requested", patch); - patch = 0; - } - - _voices[voice].patch = patch; - AdlibModulator &mod = _patches[patch].mod; - - // Set the common settings for both operators - setOperator(registerOffset[voice], _patches[patch].op[0]); - setOperator(registerOffset[voice] + 3, _patches[patch].op[1]); - - // Set the additional settings for the modulator - byte algorithm = mod.algorithm ? 1 : 0; - setRegister(0xC0 + voice, (mod.feedback << 1) | algorithm); -} - -void MidiDriver_Adlib::setOperator(int reg, AdlibOperator &op) { - setRegister(0x40 + reg, (op.kbScaleLevel << 6) | op.totalLevel); - setRegister(0x60 + reg, (op.attackRate << 4) | op.decayRate); - setRegister(0x80 + reg, (op.sustainLevel << 4) | op.releaseRate); - setRegister(0x20 + reg, (op.amplitudeMod << 7) | (op.vibrato << 6) - | (op.envelopeType << 5) | (op.kbScaleRate << 4) | op.frequencyMult); - setRegister(0xE0 + reg, op.waveForm); -} - -void MidiDriver_Adlib::setRegister(int reg, int value, int channels) { - if (channels & kLeftChannel) { - _opl->write(0x220, reg); - _opl->write(0x221, value); - } - - if (isStereo()) { - if (channels & kRightChannel) { - _opl->write(0x222, reg); - _opl->write(0x223, value); - } - } -} - -void MidiDriver_Adlib::playSwitch(bool play) { - _playSwitch = play; - renewNotes(-1, 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); - return false; - } - - for (int i = 0; i < 48; i++) - loadInstrument(data + (28 * i)); - - if (size == 2690) { - for (int i = 48; i < 96; i++) - loadInstrument(data + 2 + (28 * i)); - } else if (size == 5382) { - for (int i = 48; i < 190; i++) - loadInstrument(data + (28 * i)); - _rhythmKeyMap = new byte[kRhythmKeys]; - memcpy(_rhythmKeyMap, data + 5320, kRhythmKeys); - } - - return true; -} - -uint32 MidiDriver_Adlib::property(int prop, uint32 param) { - switch(prop) { - case MIDI_PROP_MASTER_VOLUME: - if (param != 0xffff) - _masterVolume = param; - return _masterVolume; - default: - break; - } - return 0; -} - - -int MidiPlayer_Adlib::open(ResourceManager *resMan) { - assert(resMan != NULL); - - // Load up the patch.003 file, parse out the instruments - Resource *res = resMan->findResource(ResourceId(kResourceTypePatch, 3), 0); - bool ok = false; - - if (res) { - ok = static_cast<MidiDriver_Adlib *>(_driver)->loadResource(res->data, res->size); - } else { - // Early SCI0 games have the sound bank embedded in the adlib driver - - Common::File f; - - if (f.open("ADL.DRV")) { - int size = f.size(); - const uint patchSize = 1344; - - if ((size == 5684) || (size == 5720) || (size == 5727)) { - byte *buf = new byte[patchSize]; - - if (f.seek(0x45a) && (f.read(buf, patchSize) == patchSize)) - ok = static_cast<MidiDriver_Adlib *>(_driver)->loadResource(buf, patchSize); - - delete[] buf; - } - } - } - - if (!ok) { - warning("ADLIB: Failed to load patch.003"); - return -1; - } - - return static_cast<MidiDriver_Adlib *>(_driver)->open(getSciVersion() <= SCI_VERSION_0_LATE); -} - -int MidiPlayer_Adlib::getPlayMask(SciVersion soundVersion) { - return (soundVersion == SCI_VERSION_0_EARLY) ? 0x01 : 0x04; -} - -MidiPlayer *MidiPlayer_Adlib_create() { - return new MidiPlayer_Adlib(); -} - -MidiDriver *MidiDriver_Adlib_create() { - return new MidiDriver_Adlib(g_system->getMixer()); -} - -} // End of namespace Sci diff --git a/engines/sci/sfx/softseq/amiga.cpp b/engines/sci/sfx/softseq/amiga.cpp deleted file mode 100644 index d16e82fab5..0000000000 --- a/engines/sci/sfx/softseq/amiga.cpp +++ /dev/null @@ -1,676 +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 "sound/softsynth/emumidi.h" -#include "sci/sfx/softseq/mididriver.h" - -#include "common/file.h" -#include "common/frac.h" -#include "common/util.h" - -namespace Sci { - -/* #define DEBUG */ - -// Frequencies for every note -// FIXME Store only one octave -static const int freq_table[] = { - 58, 62, 65, 69, 73, 78, 82, 87, - 92, 98, 104, 110, 117, 124, 131, 139, - 147, 156, 165, 175, 185, 196, 208, 220, - 234, 248, 262, 278, 294, 312, 331, 350, - 371, 393, 417, 441, 468, 496, 525, 556, - 589, 625, 662, 701, 743, 787, 834, 883, - 936, 992, 1051, 1113, 1179, 1250, 1324, 1403, - 1486, 1574, 1668, 1767, 1872, 1984, 2102, 2227, - 2359, 2500, 2648, 2806, 2973, 3149, 3337, 3535, - 3745, 3968, 4204, 4454, 4719, 5000, 5297, 5612, - 5946, 6299, 6674, 7071, 7491, 7937, 8408, 8908, - 9438, 10000, 10594, 11224, 11892, 12599, 13348, 14142, - 14983, 15874, 16817, 17817, 18877, 20000, 21189, 22449, - 23784, 25198, 26696, 28284, 29966, 31748, 33635, 35635, - 37754, 40000, 42378, 44898, 47568, 50396, 53393, 56568, - 59932, 63496, 67271, 71271, 75509, 80000, 84757, 89796 -}; - -class MidiDriver_Amiga : public MidiDriver_Emulated { -public: - enum { - kVoices = 4 - }; - - MidiDriver_Amiga(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer), _playSwitch(true), _masterVolume(15) { } - virtual ~MidiDriver_Amiga() { } - - // MidiDriver - int open(); - void close(); - void send(uint32 b); - MidiChannel *allocateChannel() { return NULL; } - MidiChannel *getPercussionChannel() { return NULL; } - - // AudioStream - bool isStereo() const { return true; } - int getRate() const { return _mixer->getOutputRate(); } - - // MidiDriver_Emulated - void generateSamples(int16 *buf, int len); - - void setVolume(byte volume); - void playSwitch(bool play); - virtual uint32 property(int prop, uint32 param); - -private: - enum { - kModeLoop = 1 << 0, // Instrument looping flag - kModePitch = 1 << 1 // Instrument pitch changes flag - }; - - enum { - kChannels = 10, - kBaseFreq = 20000, // Samplerate of the instrument bank - kPanLeft = 91, - kPanRight = 164 - }; - - struct Channel { - int instrument; - int volume; - int pan; - }; - - struct Envelope { - int length; // Phase period length in samples - int delta; // Velocity delta per period - int target; // Target velocity - }; - - struct Voice { - int instrument; - int note; - int note_velocity; - int velocity; - int envelope; - int envelope_samples; // Number of samples till next envelope event - int decay; - int looping; - int hw_channel; - frac_t offset; - frac_t rate; - }; - - struct Instrument { - char name[30]; - int mode; - int size; // Size of non-looping part in bytes - int loop_size; // Starting offset and size of loop in bytes - int transpose; // Transpose value in semitones - Envelope envelope[4]; // Envelope - int8 *samples; - int8 *loop; - }; - - struct Bank { - char name[30]; - uint size; - Instrument *instruments[256]; - }; - - bool _playSwitch; - int _masterVolume; - int _frequency; - Envelope _envDecay; - Bank _bank; // Instrument bank - - Channel _channels[MIDI_CHANNELS]; - /* Internal channels */ - Voice _voices[kChannels]; - - void setEnvelope(Voice *channel, Envelope *envelope, int phase); - int interpolate(int8 *samples, frac_t offset); - void playInstrument(int16 *dest, Voice *channel, int count); - void changeInstrument(int channel, int instrument); - void stopChannel(int ch); - void stopNote(int ch, int note); - void startNote(int ch, int note, int velocity); - Instrument *readInstrument(Common::File &file, int *id); -}; - -void MidiDriver_Amiga::setEnvelope(Voice *channel, Envelope *envelope, int phase) { - channel->envelope = phase; - channel->envelope_samples = envelope[phase].length; - - if (phase == 0) - channel->velocity = channel->note_velocity / 2; - else - channel->velocity = envelope[phase - 1].target; -} - -int MidiDriver_Amiga::interpolate(int8 *samples, frac_t offset) { - int x = fracToInt(offset); - int diff = (samples[x + 1] - samples[x]) << 8; - - return (samples[x] << 8) + fracToInt(diff * (offset & FRAC_LO_MASK)); -} - -void MidiDriver_Amiga::playInstrument(int16 *dest, Voice *channel, int count) { - int index = 0; - int vol = _channels[channel->hw_channel].volume; - Instrument *instrument = _bank.instruments[channel->instrument]; - - while (1) { - /* Available source samples until end of segment */ - frac_t lin_avail; - int seg_end, rem, i, amount; - int8 *samples; - - if (channel->looping) { - samples = instrument->loop; - seg_end = instrument->loop_size; - } else { - samples = instrument->samples; - seg_end = instrument->size; - } - - lin_avail = intToFrac(seg_end) - channel->offset; - - rem = count - index; - - /* Amount of destination samples that we will compute this iteration */ - amount = lin_avail / channel->rate; - - if (lin_avail % channel->rate) - amount++; - - if (amount > rem) - amount = rem; - - /* Stop at next envelope event */ - if ((channel->envelope_samples != -1) && (amount > channel->envelope_samples)) - amount = channel->envelope_samples; - - for (i = 0; i < amount; i++) { - dest[index++] = interpolate(samples, channel->offset) * channel->velocity / 64 * channel->note_velocity * vol / (127 * 127); - channel->offset += channel->rate; - } - - if (channel->envelope_samples != -1) - channel->envelope_samples -= amount; - - if (channel->envelope_samples == 0) { - Envelope *envelope; - int delta, target, velocity; - - if (channel->decay) - envelope = &_envDecay; - else - envelope = &instrument->envelope[channel->envelope]; - - delta = envelope->delta; - target = envelope->target; - velocity = channel->velocity - envelope->delta; - - /* Check whether we have reached the velocity target for the current phase */ - if ((delta >= 0 && velocity <= target) || (delta < 0 && velocity >= target)) { - channel->velocity = target; - - /* Stop note after velocity has dropped to 0 */ - if (target == 0) { - channel->note = -1; - break; - } else - switch (channel->envelope) { - case 0: - case 2: - /* Go to next phase */ - setEnvelope(channel, instrument->envelope, channel->envelope + 1); - break; - case 1: - case 3: - /* Stop envelope */ - channel->envelope_samples = -1; - break; - } - } else { - /* We haven't reached the target yet */ - channel->envelope_samples = envelope->length; - channel->velocity = velocity; - } - } - - if (index == count) - break; - - if (fracToInt(channel->offset) >= seg_end) { - if (instrument->mode & kModeLoop) { - /* Loop the samples */ - channel->offset -= intToFrac(seg_end); - channel->looping = 1; - } else { - /* All samples have been played */ - channel->note = -1; - break; - } - } - } -} - -void MidiDriver_Amiga::changeInstrument(int channel, int instrument) { -#ifdef DEBUG - if (_bank.instruments[instrument]) - printf("[sfx:seq:amiga] Setting channel %i to \"%s\" (%i)\n", channel, _bank.instruments[instrument]->name, instrument); - else - warning("[sfx:seq:amiga] instrument %i does not exist (channel %i)", instrument, channel); -#endif - _channels[channel].instrument = instrument; -} - -void MidiDriver_Amiga::stopChannel(int ch) { - int i; - - /* Start decay phase for note on this hw channel, if any */ - for (i = 0; i < kChannels; i++) - if (_voices[i].note != -1 && _voices[i].hw_channel == ch && !_voices[i].decay) { - /* Trigger fast decay envelope */ - _voices[i].decay = 1; - _voices[i].envelope_samples = _envDecay.length; - break; - } -} - -void MidiDriver_Amiga::stopNote(int ch, int note) { - int channel; - Instrument *instrument; - - for (channel = 0; channel < kChannels; channel++) - if (_voices[channel].note == note && _voices[channel].hw_channel == ch && !_voices[channel].decay) - break; - - if (channel == kChannels) { -#ifdef DEBUG - warning("[sfx:seq:amiga] cannot stop note %i on channel %i", note, ch); -#endif - return; - } - - instrument = _bank.instruments[_voices[channel].instrument]; - - /* Start the envelope phases for note-off if looping is on and envelope is enabled */ - if ((instrument->mode & kModeLoop) && (instrument->envelope[0].length != 0)) - setEnvelope(&_voices[channel], instrument->envelope, 2); -} - -void MidiDriver_Amiga::startNote(int ch, int note, int velocity) { - Instrument *instrument; - int channel; - - if (_channels[ch].instrument < 0 || _channels[ch].instrument > 255) { - warning("[sfx:seq:amiga] invalid instrument %i on channel %i", _channels[ch].instrument, ch); - return; - } - - instrument = _bank.instruments[_channels[ch].instrument]; - - if (!instrument) { - warning("[sfx:seq:amiga] instrument %i does not exist", _channels[ch].instrument); - return; - } - - for (channel = 0; channel < kChannels; channel++) - if (_voices[channel].note == -1) - break; - - if (channel == kChannels) { - warning("[sfx:seq:amiga] could not find a free channel"); - return; - } - - stopChannel(ch); - - if (instrument->mode & kModePitch) { - int fnote = note + instrument->transpose; - - if (fnote < 0 || fnote > 127) { - warning("[sfx:seq:amiga] illegal note %i\n", fnote); - return; - } - - /* Compute rate for note */ - _voices[channel].rate = doubleToFrac(freq_table[fnote] / (double) _frequency); - } else - _voices[channel].rate = doubleToFrac(kBaseFreq / (double) _frequency); - - _voices[channel].instrument = _channels[ch].instrument; - _voices[channel].note = note; - _voices[channel].note_velocity = velocity; - - if ((instrument->mode & kModeLoop) && (instrument->envelope[0].length != 0)) - setEnvelope(&_voices[channel], instrument->envelope, 0); - else { - _voices[channel].velocity = 64; - _voices[channel].envelope_samples = -1; - } - - _voices[channel].offset = 0; - _voices[channel].hw_channel = ch; - _voices[channel].decay = 0; - _voices[channel].looping = 0; -} - -MidiDriver_Amiga::Instrument *MidiDriver_Amiga::readInstrument(Common::File &file, int *id) { - Instrument *instrument; - byte header[61]; - int size; - int seg_size[3]; - int loop_offset; - int i; - - if (file.read(header, 61) < 61) { - warning("[sfx:seq:amiga] failed to read instrument header"); - return NULL; - } - - instrument = new Instrument; - - seg_size[0] = READ_BE_UINT16(header + 35) * 2; - seg_size[1] = READ_BE_UINT16(header + 41) * 2; - seg_size[2] = READ_BE_UINT16(header + 47) * 2; - - instrument->mode = header[33]; - instrument->transpose = (int8) header[34]; - for (i = 0; i < 4; i++) { - int length = (int8) header[49 + i]; - - if (length == 0 && i > 0) - length = 256; - - instrument->envelope[i].length = length * _frequency / 60; - instrument->envelope[i].delta = (int8)header[53 + i]; - instrument->envelope[i].target = header[57 + i]; - } - /* Final target must be 0 */ - instrument->envelope[3].target = 0; - - loop_offset = READ_BE_UINT32(header + 37) & ~1; - size = seg_size[0] + seg_size[1] + seg_size[2]; - - *id = READ_BE_UINT16(header); - - strncpy(instrument->name, (char *) header + 2, 29); - instrument->name[29] = 0; -#ifdef DEBUG - printf("[sfx:seq:amiga] Reading instrument %i: \"%s\" (%i bytes)\n", - *id, instrument->name, size); - printf(" Mode: %02x\n", instrument->mode); - printf(" Looping: %s\n", instrument->mode & kModeLoop ? "on" : "off"); - printf(" Pitch changes: %s\n", instrument->mode & kModePitch ? "on" : "off"); - printf(" Segment sizes: %i %i %i\n", seg_size[0], seg_size[1], seg_size[2]); - printf(" Segment offsets: 0 %i %i\n", loop_offset, read_int32(header + 43)); -#endif - instrument->samples = (int8 *) malloc(size + 1); - if (file.read(instrument->samples, size) < (unsigned int)size) { - warning("[sfx:seq:amiga] failed to read instrument samples"); - free(instrument->samples); - delete instrument; - return NULL; - } - - if (instrument->mode & kModeLoop) { - if (loop_offset + seg_size[1] > size) { -#ifdef DEBUG - warning("[sfx:seq:amiga] looping samples extend %i bytes past end of sample block", - loop_offset + seg_size[1] - size); -#endif - seg_size[1] = size - loop_offset; - } - - if (seg_size[1] < 0) { - warning("[sfx:seq:amiga] invalid looping point"); - free(instrument->samples); - delete instrument; - return NULL; - } - - instrument->size = seg_size[0]; - instrument->loop_size = seg_size[1]; - - instrument->loop = (int8*)malloc(instrument->loop_size + 1); - memcpy(instrument->loop, instrument->samples + loop_offset, instrument->loop_size); - - instrument->samples[instrument->size] = instrument->loop[0]; - instrument->loop[instrument->loop_size] = instrument->loop[0]; - } else { - instrument->loop = NULL; - instrument->size = size; - instrument->samples[instrument->size] = 0; - } - - return instrument; -} - -uint32 MidiDriver_Amiga::property(int prop, uint32 param) { - switch(prop) { - case MIDI_PROP_MASTER_VOLUME: - if (param != 0xffff) - _masterVolume = param; - return _masterVolume; - default: - break; - } - return 0; -} - -int MidiDriver_Amiga::open() { - _frequency = _mixer->getOutputRate(); - _envDecay.length = _frequency / (32 * 64); - _envDecay.delta = 1; - _envDecay.target = 0; - - Common::File file; - byte header[40]; - - if (!file.open("bank.001")) { - warning("[sfx:seq:amiga] file bank.001 not found"); - return Common::kUnknownError; - } - - if (file.read(header, 40) < 40) { - warning("[sfx:seq:amiga] failed to read header of file bank.001"); - return Common::kUnknownError; - } - - for (uint i = 0; i < 256; i++) - _bank.instruments[i] = NULL; - - for (uint i = 0; i < kChannels; i++) { - _voices[i].note = -1; - _voices[i].hw_channel = 0; - } - - for (uint i = 0; i < MIDI_CHANNELS; i++) { - _channels[i].instrument = -1; - _channels[i].volume = 127; - _channels[i].pan = (i % 4 == 0 || i % 4 == 3 ? kPanLeft : kPanRight); - } - - _bank.size = READ_BE_UINT16(header + 38); - strncpy(_bank.name, (char *) header + 8, 29); - _bank.name[29] = 0; -#ifdef DEBUG - printf("[sfx:seq:amiga] Reading %i instruments from bank \"%s\"\n", _bank.size, _bank.name); -#endif - - for (uint i = 0; i < _bank.size; i++) { - int id; - Instrument *instrument = readInstrument(file, &id); - - if (!instrument) { - warning("[sfx:seq:amiga] failed to read bank.001"); - return Common::kUnknownError; - } - - if (id < 0 || id > 255) { - warning("[sfx:seq:amiga] Error: instrument ID out of bounds"); - return Common::kUnknownError; - } - - _bank.instruments[id] = instrument; - } - - MidiDriver_Emulated::open(); - - _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_mixerSoundHandle, this, -1, _mixer->kMaxChannelVolume, 0, false); - - return Common::kNoError; -} - -void MidiDriver_Amiga::close() { - _mixer->stopHandle(_mixerSoundHandle); - - for (uint i = 0; i < _bank.size; i++) { - if (_bank.instruments[i]) { - if (_bank.instruments[i]->loop) - free(_bank.instruments[i]->loop); - free(_bank.instruments[i]->samples); - delete _bank.instruments[i]; - } - } -} - -void MidiDriver_Amiga::playSwitch(bool play) { - _playSwitch = play; -} - -void MidiDriver_Amiga::setVolume(byte volume_) { - _masterVolume = volume_; -} - -void MidiDriver_Amiga::send(uint32 b) { - byte command = b & 0xf0; - byte channel = b & 0xf; - byte op1 = (b >> 8) & 0xff; - byte op2 = (b >> 16) & 0xff; - - switch (command) { - case 0x80: - stopNote(channel, op1); - break; - case 0x90: - if (op2 > 0) - startNote(channel, op1, op2); - else - stopNote(channel, op1); - break; - case 0xb0: - switch (op1) { - case 0x07: - _channels[channel].volume = op2; - break; - case 0x0a: -#ifdef DEBUG - warning("[sfx:seq:amiga] ignoring pan 0x%02x event for channel %i", op2, channel); -#endif - break; - case 0x7b: - stopChannel(channel); - break; - default: - warning("[sfx:seq:amiga] unknown control event 0x%02x", op1); - } - break; - case 0xc0: - changeInstrument(channel, op1); - break; - default: - warning("[sfx:seq:amiga] unknown event %02x", command); - } -} - -void MidiDriver_Amiga::generateSamples(int16 *data, int len) { - if (len == 0) - return; - - int16 *buffers = (int16*)malloc(len * 2 * kChannels); - - memset(buffers, 0, len * 2 * kChannels); - - /* Generate samples for all notes */ - for (int i = 0; i < kChannels; i++) - if (_voices[i].note >= 0) - playInstrument(buffers + i * len, &_voices[i], len); - - if (isStereo()) { - for (int j = 0; j < len; j++) { - int mixedl = 0, mixedr = 0; - - /* Mix and pan */ - for (int i = 0; i < kChannels; i++) { - mixedl += buffers[i * len + j] * (256 - _channels[_voices[i].hw_channel].pan); - mixedr += buffers[i * len + j] * _channels[_voices[i].hw_channel].pan; - } - - /* Adjust volume */ - data[2 * j] = mixedl * _masterVolume >> 13; - data[2 * j + 1] = mixedr * _masterVolume >> 13; - } - } else { - for (int j = 0; j < len; j++) { - int mixed = 0; - - /* Mix */ - for (int i = 0; i < kChannels; i++) - mixed += buffers[i * len + j]; - - /* Adjust volume */ - data[j] = mixed * _masterVolume >> 6; - } - } - - free(buffers); -} - -class MidiPlayer_Amiga : public MidiPlayer { -public: - MidiPlayer_Amiga() { _driver = new MidiDriver_Amiga(g_system->getMixer()); } - int getPlayMask(SciVersion soundVersion); - int getPolyphony() const { return MidiDriver_Amiga::kVoices; } - bool hasRhythmChannel() const { return false; } - void setVolume(byte volume) { static_cast<MidiDriver_Amiga *>(_driver)->setVolume(volume); } - void playSwitch(bool play) { static_cast<MidiDriver_Amiga *>(_driver)->playSwitch(play); } - void loadInstrument(int idx, byte *data); -}; - -MidiPlayer *MidiPlayer_Amiga_create() { - return new MidiPlayer_Amiga(); -} - -int MidiPlayer_Amiga::getPlayMask(SciVersion soundVersion) { - if (soundVersion == SCI_VERSION_0_EARLY) - error("No amiga support for sci0early"); - - return 0x40; -} - -} // End of namespace Sci diff --git a/engines/sci/sfx/softseq/mididriver.h b/engines/sci/sfx/softseq/mididriver.h deleted file mode 100644 index df0532d732..0000000000 --- a/engines/sci/sfx/softseq/mididriver.h +++ /dev/null @@ -1,110 +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_SOFTSEQ_MIDIDRIVER_H -#define SCI_SFX_SOFTSEQ_MIDIDRIVER_H - -#include "sci/sci.h" -#include "sound/mididrv.h" -#include "sound/softsynth/emumidi.h" -#include "common/error.h" - -namespace Sci { - -class ResourceManager; - -enum { - MIDI_CHANNELS = 16, - MIDI_PROP_MASTER_VOLUME = 0 -}; - - -#define MIDI_RHYTHM_CHANNEL 9 - -/* Special SCI sound stuff */ - -#define SCI_MIDI_TIME_EXPANSION_PREFIX 0xF8 -#define SCI_MIDI_TIME_EXPANSION_LENGTH 240 - -#define SCI_MIDI_EOT 0xFC -#define SCI_MIDI_SET_SIGNAL 0xCF -#define SCI_MIDI_SET_POLYPHONY 0x4B -#define SCI_MIDI_RESET_ON_SUSPEND 0x4C -#define SCI_MIDI_CHANNEL_MUTE 0x4E -#define SCI_MIDI_SET_REVERB 0x50 -#define SCI_MIDI_HOLD 0x52 -#define SCI_MIDI_CUMULATIVE_CUE 0x60 -#define SCI_MIDI_CHANNEL_SOUND_OFF 0x78 /* all-sound-off for Bn */ -#define SCI_MIDI_CHANNEL_NOTES_OFF 0x7B /* all-notes-off for Bn */ - -#define SCI_MIDI_SET_SIGNAL_LOOP 0x7F -/* If this is the parameter of 0xCF, the loop point is set here */ - -#define SCI_MIDI_CONTROLLER(status) ((status & 0xF0) == 0xB0) - -class MidiPlayer : public MidiDriver { -protected: - MidiDriver *_driver; -public: - int open() { - ResourceManager *resMan = ((SciEngine *)g_engine)->getResourceManager(); // HACK - return open(resMan); - } - virtual int open(ResourceManager *resMan) { return _driver->open(); } - virtual void close() { _driver->close(); } - virtual void send(uint32 b) { _driver->send(b); } - uint32 getBaseTempo() { return _driver->getBaseTempo(); } - virtual bool hasRhythmChannel() const = 0; - MidiChannel *allocateChannel() { return _driver->allocateChannel(); } - MidiChannel *getPercussionChannel() { return _driver->getPercussionChannel(); } - void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) { _driver->setTimerCallback(timer_param, timer_proc); } - - virtual int getPlayMask(SciVersion soundVersion) = 0; - virtual int getPolyphony() const = 0; - - virtual void setVolume(byte volume) { - if(_driver) - _driver->property(MIDI_PROP_MASTER_VOLUME, volume); - } - - virtual int getVolume() { - return _driver ? _driver->property(MIDI_PROP_MASTER_VOLUME, 0xffff) : 0; - } - - virtual void playSwitch(bool play) { - if (!play) { - // Send "All Sound Off" on all channels - for (int i = 0; i < MIDI_CHANNELS; ++i) - _driver->send(0xb0 + i, SCI_MIDI_CHANNEL_NOTES_OFF, 0); - } - } -}; - -extern MidiPlayer *MidiPlayer_Adlib_create(); -extern MidiPlayer *MidiPlayer_Amiga_create(); - -} // End of namespace Sci - -#endif // SCI_SFX_SOFTSEQ_MIDIDRIVER_H diff --git a/engines/sci/sfx/softseq/pcjr.cpp b/engines/sci/sfx/softseq/pcjr.cpp deleted file mode 100644 index a80a188751..0000000000 --- a/engines/sci/sfx/softseq/pcjr.cpp +++ /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$ - * - */ - -#include "sci/sfx/softseq/mididriver.h" -#include "sci/sfx/softseq/pcjr.h" - -namespace Sci { - -#define FREQUENCY 44100 -#define VOLUME_SHIFT 3 - -#define BASE_NOTE 129 // A10 -#define BASE_OCTAVE 10 // A10, as I said - -const static int freq_table[12] = { // A4 is 440Hz, halftone map is x |-> ** 2^(x/12) - 28160, // A10 - 29834, - 31608, - 33488, - 35479, - 37589, - 39824, - 42192, - 44701, - 47359, - 50175, - 53159 -}; - -static inline int get_freq(int note) { - int halftone_delta = note - BASE_NOTE; - int oct_diff = ((halftone_delta + BASE_OCTAVE * 12) / 12) - BASE_OCTAVE; - int halftone_index = (halftone_delta + (12 * 100)) % 12 ; - int freq = (!note) ? 0 : freq_table[halftone_index] / (1 << (-oct_diff)); - - return freq; -} - -void MidiDriver_PCJr::send(uint32 b) { - byte command = b & 0xff; - byte op1 = (b >> 8) & 0xff; - byte op2 = (b >> 16) & 0xff; - int i; - int mapped_chan = -1; - int chan_nr = command & 0xf; - - // First, test for channel having been assigned already - if (_channels_assigned & (1 << chan_nr)) { - // Already assigned this channel number: - for (i = 0; i < _channels_nr; i++) - if (_chan_nrs[i] == chan_nr) { - mapped_chan = i; - break; - } - } else if ((command & 0xe0) == 0x80) { - // Assign new channel round-robin - - // Mark channel as unused: - if (_chan_nrs[_channel_assigner] >= 0) - _channels_assigned &= ~(1 << _chan_nrs[_channel_assigner]); - - // Remember channel: - _chan_nrs[_channel_assigner] = chan_nr; - // Mark channel as used - _channels_assigned |= (1 << _chan_nrs[_channel_assigner]); - - // Save channel for use later in this call: - mapped_chan = _channel_assigner; - // Round-ropin iterate channel assigner: - _channel_assigner = (_channel_assigner + 1) % _channels_nr; - } - - if (mapped_chan == -1) - return; - - switch (command & 0xf0) { - - case 0x80: - if (op1 == _notes[mapped_chan]) - _notes[mapped_chan] = 0; - break; - - case 0x90: - if (!op2) { - if (op1 == _notes[mapped_chan]) - _notes[mapped_chan] = 0; - } else { - _notes[mapped_chan] = op1; - _volumes[mapped_chan] = op2; - } - break; - - case 0xb0: - if ((op1 == SCI_MIDI_CHANNEL_NOTES_OFF) || (op1 == SCI_MIDI_CHANNEL_SOUND_OFF)) - _notes[mapped_chan] = 0; - break; - - default: - debug(2, "Unused MIDI command %02x %02x %02x", command, op1, op2); - break; /* ignore */ - } -} - -void MidiDriver_PCJr::generateSamples(int16 *data, int len) { - int i; - int chan; - int freq[kMaxChannels]; - - for (chan = 0; chan < _channels_nr; chan++) - freq[chan] = get_freq(_notes[chan]); - - for (i = 0; i < len; i++) { - int16 result = 0; - - for (chan = 0; chan < _channels_nr; chan++) - if (_notes[chan]) { - int volume = (_global_volume * _volumes[chan]) - >> VOLUME_SHIFT; - - _freq_count[chan] += freq[chan]; - while (_freq_count[chan] >= (FREQUENCY << 1)) - _freq_count[chan] -= (FREQUENCY << 1); - - if (_freq_count[chan] - freq[chan] < 0) { - /* Unclean rising edge */ - int l = volume << 1; - result += -volume + (l * _freq_count[chan]) / freq[chan]; - } else if (_freq_count[chan] >= FREQUENCY - && _freq_count[chan] - freq[chan] < FREQUENCY) { - /* Unclean falling edge */ - int l = volume << 1; - result += volume - (l * (_freq_count[chan] - FREQUENCY)) / freq[chan]; - } else { - if (_freq_count[chan] < FREQUENCY) - result += volume; - else - result += -volume; - } - } - data[i] = result; - } -} - -int MidiDriver_PCJr::open(int channels) { - if (_isOpen) - return MERR_ALREADY_OPEN; - - if (channels > kMaxChannels) - return -1; - - _channels_nr = channels; - _global_volume = 100; - for (int i = 0; i < _channels_nr; i++) { - _volumes[i] = 100; - _notes[i] = 0; - _freq_count[i] = 0; - _chan_nrs[i] = -1; - } - _channel_assigner = 0; - _channels_assigned = 0; - - MidiDriver_Emulated::open(); - - _mixer->playInputStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1); - - return 0; -} - -void MidiDriver_PCJr::close() { - _mixer->stopHandle(_mixerSoundHandle); -} - -int MidiPlayer_PCJr::getPlayMask(SciVersion soundVersion) { - if (soundVersion == SCI_VERSION_0_EARLY) - return 0x10; // FIXME: Not correct - - return 0x10; -} - -int MidiPlayer_PCSpeaker::getPlayMask(SciVersion soundVersion) { - if (soundVersion == SCI_VERSION_0_EARLY) - return 0x02; - - return 0x20; -} - -} // End of namespace Sci diff --git a/engines/sci/sfx/softseq/pcjr.h b/engines/sci/sfx/softseq/pcjr.h deleted file mode 100644 index 60032817fd..0000000000 --- a/engines/sci/sfx/softseq/pcjr.h +++ /dev/null @@ -1,84 +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/sfx/softseq/mididriver.h" - -namespace Sci { - -class MidiDriver_PCJr : public MidiDriver_Emulated { -public: - friend class MidiPlayer_PCJr; - - enum { - kMaxChannels = 3 - }; - - MidiDriver_PCJr(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer) { } - ~MidiDriver_PCJr() { } - - // MidiDriver - int open() { return open(kMaxChannels); } - void close(); - void send(uint32 b); - MidiChannel *allocateChannel() { return NULL; } - MidiChannel *getPercussionChannel() { return NULL; } - - // AudioStream - bool isStereo() const { return false; } - int getRate() const { return _mixer->getOutputRate(); } - - // MidiDriver_Emulated - void generateSamples(int16 *buf, int len); - - int open(int channels); -private: - int _channels_nr; - int _global_volume; // Base volume - int _volumes[kMaxChannels]; - int _notes[kMaxChannels]; // Current halftone, or 0 if off - int _freq_count[kMaxChannels]; - int _channel_assigner; - int _channels_assigned; - int _chan_nrs[kMaxChannels]; -}; - -class MidiPlayer_PCJr : public MidiPlayer { -public: - MidiPlayer_PCJr() { _driver = new MidiDriver_PCJr(g_system->getMixer()); } - int open(ResourceManager *resMan) { return static_cast<MidiDriver_PCJr *>(_driver)->open(getPolyphony()); } - int getPlayMask(SciVersion soundVersion); - int getPolyphony() const { return 3; } - bool hasRhythmChannel() const { return false; } - void setVolume(byte volume) { static_cast<MidiDriver_PCJr *>(_driver)->_global_volume = volume; } -}; - -class MidiPlayer_PCSpeaker : public MidiPlayer_PCJr { -public: - int getPlayMask(SciVersion soundVersion); - int getPolyphony() const { return 1; } -}; - -} // End of namespace Sci - diff --git a/engines/sci/sfx/soundcmd.cpp b/engines/sci/sfx/soundcmd.cpp deleted file mode 100644 index f42ecc1099..0000000000 --- a/engines/sci/sfx/soundcmd.cpp +++ /dev/null @@ -1,1090 +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/sfx/iterator/iterator.h" // for SongIteratorStatus -#endif - -#include "sci/sfx/music.h" -#include "sci/sfx/soundcmd.h" - -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 = GET_SEL32V(segMan, obj, number); - Resource *song = resMan->findResource(ResourceId(kResourceTypeSound, song_nr), 0); - int flags = GET_SEL32V(segMan, obj, 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); - PUT_SEL32V(segMan, obj, 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)\n", - PRINT_REG(obj), cue); - /* PUT_SEL32V(segMan, obj, loops, GET_SEL32V(segMan, obj, loop) - 1);*/ - PUT_SEL32V(segMan, obj, signal, SIGNAL_OFFSET); - break; - - case SI_RELATIVE_CUE: - debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x received relative cue %d\n", - PRINT_REG(obj), cue); - PUT_SEL32V(segMan, obj, signal, cue + 0x7f); - break; - - case SI_ABSOLUTE_CUE: - debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x received absolute cue %d\n", - PRINT_REG(obj), cue); - PUT_SEL32V(segMan, obj, signal, cue); - break; - - case SI_FINISHED: - debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x finished\n", - PRINT_REG(obj)); - PUT_SEL32V(segMan, obj, signal, SIGNAL_OFFSET); - PUT_SEL32V(segMan, obj, state, kSoundStopped); - break; - - default: - warning("Unexpected result from sfx_poll: %d", result); - break; - } - } -} - -#endif -SoundCommandParser::SoundCommandParser(ResourceManager *resMan, SegManager *segMan, AudioPlayer *audio, SciVersion soundVersion) : - _resMan(resMan), _segMan(segMan), _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 = &((SciEngine *)g_engine)->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; - } -} - -SoundCommandParser::~SoundCommandParser() { -} - -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; -} - -void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) { - if (!obj.segment) - return; - - int number = obj.segment ? GET_SEL32V(_segMan, obj, number) : 0; - -#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 (GET_SEL32V(_segMan, obj, nodePtr)) { - _state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED); - _state->sfx_remove_song(handle); - } - } - - if (!obj.segment || !_resMan->testResource(ResourceId(kResourceTypeSound, number))) - return; - - _state->sfx_add_song(build_iterator(_resMan, number, type, handle), 0, handle, number); - - - // Notify the engine - if (_soundVersion <= SCI_VERSION_0_LATE) - PUT_SEL32V(_segMan, obj, state, kSoundInitialized); - else - PUT_SEL32(_segMan, obj, nodePtr, obj); - - PUT_SEL32(_segMan, obj, handle, obj); - -#else - - MusicEntry *newSound = new MusicEntry(); - newSound->resnum = number; - if (number && _resMan->testResource(ResourceId(kResourceTypeSound, number))) - newSound->soundRes = new SoundResource(number, _resMan, _soundVersion); - else - newSound->soundRes = 0; - - newSound->soundObj = obj; - newSound->loop = GET_SEL32V(_segMan, obj, loop); - newSound->prio = GET_SEL32V(_segMan, obj, pri) & 0xFF; - if (_soundVersion >= SCI_VERSION_1_LATE) - newSound->volume = CLIP<int>(GET_SEL32V(_segMan, obj, vol), 0, MUSIC_VOLUME_MAX); - - // Check if a track with the same sound object is already playing - MusicEntry *oldSound = _music->getSlot(obj); - if (oldSound) - cmdDisposeSound(obj, value); - - // 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 (getSciVersion() >= SCI_VERSION_1_1 && _resMan->testResource(ResourceId(kResourceTypeAudio, number))) { - // Found a relevant audio resource, play it - int sampleLen; - newSound->pStreamAud = _audio->getAudioStream(number, 65535, &sampleLen); - newSound->soundType = Audio::Mixer::kSpeechSoundType; - } else { - if (newSound->soundRes) - _music->soundInitSnd(newSound); - } - - _music->pushBackSlot(newSound); - - if (newSound->soundRes || newSound->pStreamAud) { - // Notify the engine - if (_soundVersion <= SCI_VERSION_0_LATE) - PUT_SEL32V(_segMan, obj, state, kSoundInitialized); - else - PUT_SEL32(_segMan, obj, nodePtr, obj); - - PUT_SEL32(_segMan, obj, 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, GET_SEL32V(_segMan, obj, loop)); - PUT_SEL32V(_segMan, obj, state, kSoundPlaying); - } else if (_soundVersion == SCI_VERSION_1_EARLY) { - _state->sfx_song_set_status(handle, SOUND_STATUS_PLAYING); - _state->sfx_song_set_loops(handle, GET_SEL32V(_segMan, obj, loop)); - _state->sfx_song_renice(handle, GET_SEL32V(_segMan, obj, pri)); - RESTORE_BEHAVIOR rb = (RESTORE_BEHAVIOR) value; /* Too lazy to look up a default value for this */ - _state->_songlib.setSongRestoreBehavior(handle, rb); - PUT_SEL32V(_segMan, obj, signal, 0); - } else if (_soundVersion == SCI_VERSION_1_LATE) { - int looping = GET_SEL32V(_segMan, obj, loop); - //int vol = GET_SEL32V(_segMan, obj, vol); - int pri = GET_SEL32V(_segMan, obj, pri); - int sampleLen = 0; - Song *song = _state->_songlib.findSong(handle); - int songNumber = GET_SEL32V(_segMan, obj, number); - - if (GET_SEL32V(_segMan, obj, nodePtr) && (song && songNumber != song->_resourceNum)) { - _state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED); - _state->sfx_remove_song(handle); - PUT_SEL32(_segMan, obj, nodePtr, NULL_REG); - } - - if (!GET_SEL32V(_segMan, obj, 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); - PUT_SEL32V(_segMan, obj, signal, SIGNAL_OFFSET); - return; - } - debugC(2, kDebugLevelSound, "Initializing song number %d\n", songNumber); - _state->sfx_add_song(build_iterator(_resMan, songNumber, SCI_SONG_ITERATOR_TYPE_SCI1, - handle), 0, handle, songNumber); - } - - PUT_SEL32(_segMan, obj, nodePtr, obj); - PUT_SEL32(_segMan, obj, 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); - PUT_SEL32V(_segMan, obj, signal, 0); - } - } - -#else - - MusicEntry *musicSlot = _music->getSlot(obj); - if (!musicSlot) { - warning("cmdPlaySound: Slot not found (%04x:%04x)", PRINT_REG(obj)); - return; - } - - int number = obj.segment ? GET_SEL32V(_segMan, obj, number) : -1; - - if (musicSlot->resnum != number) { // another sound loaded into struct - cmdDisposeSound(obj, value); - cmdInitSound(obj, value); - // Find slot again :) - musicSlot = _music->getSlot(obj); - } - int16 loop = GET_SEL32V(_segMan, obj, loop); - debugC(2, kDebugLevelSound, "cmdPlaySound: resource number %d, loop %d", number, loop); - - PUT_SEL32(_segMan, obj, handle, obj); - - if (_soundVersion >= SCI_VERSION_1_EARLY) { - PUT_SEL32(_segMan, obj, nodePtr, obj); - PUT_SEL32V(_segMan, obj, min, 0); - PUT_SEL32V(_segMan, obj, sec, 0); - PUT_SEL32V(_segMan, obj, frame, 0); - PUT_SEL32V(_segMan, obj, signal, 0); - } else { - PUT_SEL32V(_segMan, obj, state, kSoundPlaying); - } - - musicSlot->loop = GET_SEL32V(_segMan, obj, loop); - musicSlot->prio = GET_SEL32V(_segMan, obj, priority); - if (_soundVersion >= SCI_VERSION_1_LATE) - musicSlot->volume = GET_SEL32V(_segMan, obj, vol); - _music->soundPlay(musicSlot); - -#endif - -} - -void SoundCommandParser::cmdDummy(reg_t obj, int16 value) { - warning("cmdDummy invoked"); // not supposed to occur -} - -#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) - PUT_SEL32V(_segMan, obj, state, newStatus); - } -} -#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) - PUT_SEL32V(_segMan, obj, handle, 0x0000); - } - -#else - - MusicEntry *musicSlot = _music->getSlot(obj); - if (!musicSlot) { - warning("cmdDisposeSound: Slot not found (%04x:%04x)", PRINT_REG(obj)); - return; - } - - cmdStopSound(obj, value); - - _music->soundKill(musicSlot); - if (_soundVersion >= SCI_VERSION_1_EARLY) - PUT_SEL32(_segMan, obj, nodePtr, NULL_REG); - else - PUT_SEL32V(_segMan, obj, state, kSoundStopped); -#endif -} - -void SoundCommandParser::cmdStopSound(reg_t obj, int16 value) { - if (!obj.segment) - return; - -#ifdef USE_OLD_MUSIC_FUNCTIONS - changeSoundStatus(obj, SOUND_STATUS_STOPPED); - - if (_soundVersion >= SCI_VERSION_1_EARLY) - PUT_SEL32V(_segMan, obj, signal, SIGNAL_OFFSET); -#else - MusicEntry *musicSlot = _music->getSlot(obj); - if (!musicSlot) { - warning("cmdStopSound: Slot not found (%04x:%04x)", PRINT_REG(obj)); - return; - } - - PUT_SEL32V(_segMan, obj, handle, 0); - if (_soundVersion <= SCI_VERSION_0_LATE) - PUT_SEL32V(_segMan, obj, state, kSoundStopped); - else - PUT_SEL32V(_segMan, obj, 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 - - MusicEntry *musicSlot = NULL; - MusicList::iterator slotLoop = NULL; - MusicList::iterator listEnd = NULL; - - if (!obj.segment) { - // Pausing/Resuming the whole playlist was introduced - // in the SCI1 late sound scheme - if (_soundVersion <= SCI_VERSION_1_EARLY) - return; - _music->_mutex.lock(); - slotLoop = _music->getPlayListStart(); - listEnd = _music->getPlayListEnd(); - musicSlot = *slotLoop; - _music->_mutex.unlock(); - } else { - _music->_mutex.lock(); - musicSlot = _music->getSlot(obj); - _music->_mutex.unlock(); - if (!musicSlot) { - warning("cmdPauseSound: Slot not found (%04x:%04x)", PRINT_REG(obj)); - return; - } - } - - do { - if (_soundVersion <= SCI_VERSION_0_LATE) { - PUT_SEL32V(_segMan, musicSlot->soundObj, state, kSoundPaused); - _music->soundPause(musicSlot); - } else { - if (value) - _music->soundPause(musicSlot); - else - _music->soundResume(musicSlot); - } - - if (slotLoop) { - if (slotLoop == listEnd) { - break; - } else { - _music->_mutex.lock(); - musicSlot = *(slotLoop++); - _music->_mutex.unlock(); - } - } - } while (slotLoop); - -#endif -} - -void SoundCommandParser::cmdResumeSound(reg_t obj, int16 value) { - // SCI0 only command - - if (!obj.segment) - return; - -#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; - } - - PUT_SEL32V(_segMan, musicSlot->soundObj, state, kSoundPlaying); - _music->soundResume(musicSlot); -#endif -} - -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 -} - -void SoundCommandParser::cmdMasterVolume(reg_t obj, int16 value) { -#ifdef USE_OLD_MUSIC_FUNCTIONS - if (obj != SIGNAL_REG) - _state->sfx_setVolume(obj.toSint16()); - - _acc = make_reg(0, _state->sfx_getVolume()); -#else - debugC(2, kDebugLevelSound, "cmdMasterVolume: %d", value); - if (_argc > 1) // the first parameter is the sound command - _music->soundSetMasterVolume(obj.toSint16()); - _acc = make_reg(0, _music->soundGetMasterVolume()); -#endif -} - -void SoundCommandParser::cmdFadeSound(reg_t obj, int16 value) { - if (!obj.segment) - return; - -#ifdef USE_OLD_MUSIC_FUNCTIONS - SongHandle handle = FROBNICATE_HANDLE(obj); - if (_soundVersion != SCI_VERSION_1_LATE) { - /*s->sound_server->command(s, SOUND_COMMAND_FADE_HANDLE, obj, 120);*/ /* Fade out in 2 secs */ - /* 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) - PUT_SEL32V(_segMan, obj, state, SOUND_STATUS_STOPPED); - PUT_SEL32V(_segMan, obj, 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()) { - PUT_SEL32V(_segMan, obj, signal, SIGNAL_OFFSET); - _state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED); - } else { - // FIXME: Support fade-and-continue. For now, send signal right away. - PUT_SEL32V(_segMan, obj, signal, SIGNAL_OFFSET); - } - } -#else - MusicEntry *musicSlot = _music->getSlot(obj); - if (!musicSlot) { - warning("cmdFadeSound: Slot not found (%04x:%04x)", PRINT_REG(obj)); - return; - } - - 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 - musicSlot->fadeTo = 0; - musicSlot->fadeStep = -5; - musicSlot->fadeTickerStep = 10 * 16667 / _music->soundGetTempo(); - musicSlot->fadeTicker = 0; - break; - - case 5: // Possibly SCI1?! - case 6: // SCI 1.1 TODO: find out what additional parameter is - 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(); - musicSlot->fadeTicker = 0; - break; - - default: - error("cmdFadeSound: unsupported argc %d", _argc); - } - - debugC(2, kDebugLevelSound, "cmdFadeSound: to %d, step %d, ticker %d", musicSlot->fadeTo, musicSlot->fadeStep, musicSlot->fadeTickerStep); -#endif -} - -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 -} - -void SoundCommandParser::cmdUpdateSound(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 && obj.segment) { - _state->sfx_song_set_loops(handle, GET_SEL32V(_segMan, obj, loop)); - script_set_priority(_resMan, _segMan, _state, obj, GET_SEL32V(_segMan, obj, pri)); - } -#else - MusicEntry *musicSlot = _music->getSlot(obj); - if (!musicSlot) { - warning("cmdUpdateSound: Slot not found (%04x:%04x)", PRINT_REG(obj)); - return; - } - - musicSlot->loop = GET_SEL32V(_segMan, obj, loop); - int16 objVol = CLIP<int>(GET_SEL32V(_segMan, obj, vol), 0, 255); - if (objVol != musicSlot->volume) - _music->soundSetVolume(musicSlot, objVol); - uint32 objPrio = GET_SEL32V(_segMan, obj, pri); - if (objPrio != musicSlot->prio) - _music->soundSetPriority(musicSlot, objPrio); - -#endif -} - -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\n", - PRINT_REG(obj), signal); - debugC(2, kDebugLevelSound, "abs-signal %04X\n", signal); - PUT_SEL32V(_segMan, obj, signal, signal); - break; - - case SI_RELATIVE_CUE: - debugC(2, kDebugLevelSound, "--- [CUE] %04x:%04x Relative Cue: %d\n", - PRINT_REG(obj), signal); - - /* FIXME to match commented-out semantics - * below, with proper storage of dataInc and - * signal in the iterator code. */ - PUT_SEL32V(_segMan, obj, dataInc, signal); - debugC(2, kDebugLevelSound, "rel-signal %04X\n", signal); - if (_soundVersion == SCI_VERSION_1_EARLY) - PUT_SEL32V(_segMan, obj, signal, signal); - else - PUT_SEL32V(_segMan, obj, signal, signal + 127); - break; - - case SI_FINISHED: - debugC(2, kDebugLevelSound, "--- [FINISHED] %04x:%04x\n", PRINT_REG(obj)); - PUT_SEL32V(_segMan, obj, signal, SIGNAL_OFFSET); - break; - - case SI_LOOP: - break; // Doesn't happen - } - - //switch (signal) { - //case 0x00: - // if (dataInc!=GET_SEL32V(segMan, obj, dataInc)) { - // PUT_SEL32V(segMan, obj, dataInc, dataInc); - // PUT_SEL32V(segMan, obj, signal, dataInc+0x7f); - // } else { - // PUT_SEL32V(segMan, obj, signal, signal); - // } - // break; - //case 0xFF: // May be unnecessary - // s->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED); - // break; - //default : - // if (dataInc!=GET_SEL32V(segMan, obj, dataInc)) { - // PUT_SEL32V(segMan, obj, dataInc, dataInc); - // PUT_SEL32V(segMan, obj, signal, dataInc + 0x7f); - // } else { - // PUT_SEL32V(segMan, obj, signal, signal); - // } - // break; - //} - - if (_soundVersion == SCI_VERSION_1_EARLY) { - PUT_SEL32V(_segMan, obj, min, min); - PUT_SEL32V(_segMan, obj, sec, sec); - PUT_SEL32V(_segMan, obj, frame, frame); - } -#else - MusicEntry *musicSlot = _music->getSlot(obj); - if (!musicSlot) { - warning("cmdUpdateCues: Slot not found (%04x:%04x)", PRINT_REG(obj)); - return; - } - - if (musicSlot->pStreamAud) { - // Update digital sound effect slots here - Audio::Mixer *mixer = g_system->getMixer(); - - uint currentLoopCounter = musicSlot->pStreamAud->getNumPlayedLoops(); - if (currentLoopCounter != musicSlot->sampleLoopCounter) { - // during last time we looped at least one time, update loop accordingly - musicSlot->loop -= currentLoopCounter - musicSlot->sampleLoopCounter; - musicSlot->sampleLoopCounter = currentLoopCounter; - } - if (!mixer->isSoundHandleActive(musicSlot->hCurrentAud)) { - cmdStopSound(obj, 0); - } else { - musicSlot->ticker = (uint16)(mixer->getSoundElapsedTime(musicSlot->hCurrentAud) * 0.06); - } - // We get a flag from MusicEntry::doFade() here to set volume for the stream - if (musicSlot->fadeSetVolume) { - mixer->setChannelVolume(musicSlot->hCurrentAud, musicSlot->volume); - musicSlot->fadeSetVolume = false; - } - } else { - switch (musicSlot->signal) { - case 0: - if (musicSlot->dataInc != GET_SEL32V(_segMan, obj, dataInc)) { - PUT_SEL32V(_segMan, obj, dataInc, musicSlot->dataInc); - PUT_SEL32V(_segMan, obj, signal, musicSlot->dataInc + 127); - } - break; - case SIGNAL_OFFSET: - PUT_SEL32V(_segMan, obj, signal, SIGNAL_OFFSET); - break; - default: - // Sync the signal of the sound object - PUT_SEL32V(_segMan, obj, signal, musicSlot->signal); - break; - } - } - - if (musicSlot->fadeCompleted) { - musicSlot->fadeCompleted = false; - if (_soundVersion <= SCI_VERSION_0_LATE) { - cmdStopSound(obj, 0); - } else { - PUT_SEL32V(_segMan, obj, signal, SIGNAL_OFFSET); - } - } - - // Sync loop selector for SCI0 - if (_soundVersion <= SCI_VERSION_0_LATE) - PUT_SEL32V(_segMan, obj, loop, musicSlot->loop); - - musicSlot->signal = 0; - - if (_soundVersion >= SCI_VERSION_1_EARLY) { - PUT_SEL32V(_segMan, obj, min, musicSlot->ticker / 3600); - PUT_SEL32V(_segMan, obj, sec, musicSlot->ticker % 3600 / 60); - PUT_SEL32V(_segMan, obj, 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 -} - -void SoundCommandParser::cmdReverb(reg_t obj, int16 value) { -#ifndef USE_OLD_MUSIC_FUNCTIONS - _music->setReverb(obj.toUint16() & 0xF); -#endif -} - -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 - MusicEntry *musicSlot = _music->getSlot(obj); - if (!musicSlot) { - warning("cmdSetSoundHold: Slot not found (%04x:%04x)", PRINT_REG(obj)); - return; - } - - // Set the special hold marker ID where the song should be looped at. - musicSlot->hold = value; -#endif -} - -void SoundCommandParser::cmdGetAudioCapability(reg_t obj, int16 value) { - // Tests for digital audio support - _acc = make_reg(0, 1); -} - -void SoundCommandParser::cmdStopAllSounds(reg_t obj, int16 value) { -#ifndef USE_OLD_MUSIC_FUNCTIONS - Common::StackLock(_music->_mutex); - - const MusicList::iterator end = _music->getPlayListEnd(); - for (MusicList::iterator i = _music->getPlayListStart(); i != end; ++i) { - if (_soundVersion <= SCI_VERSION_0_LATE) - PUT_SEL32V(_segMan, (*i)->soundObj, state, kSoundStopped); - else - PUT_SEL32V(_segMan, (*i)->soundObj, signal, SIGNAL_OFFSET); - - (*i)->dataInc = 0; - _music->soundStop(*i); - } -#endif -} - -void SoundCommandParser::cmdSetSoundVolume(reg_t obj, int16 value) { - if (!obj.segment) - return; - -#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 - //warning("cmdSetSoundVolume: Slot not found (%04x:%04x)", PRINT_REG(obj)); - return; - } - - debugC(2, kDebugLevelSound, "cmdSetSoundVolume: %d", value); - - value = CLIP<int>(value, 0, MUSIC_VOLUME_MAX); - - if (musicSlot->volume != value) { - musicSlot->volume = value; - _music->soundSetVolume(musicSlot, value); - PUT_SEL32V(_segMan, obj, vol, value); - } -#endif -} - -void SoundCommandParser::cmdSetSoundPriority(reg_t obj, int16 value) { - if (!obj.segment) - return; - -#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; - } - - if (value == -1) { - // Set priority from the song data - Resource *song = _resMan->findResource(ResourceId(kResourceTypeSound, musicSlot->resnum), 0); - 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"); - - //pSnd->prio=0;field_15B=0 - PUT_SEL32V(_segMan, obj, flags, GET_SEL32V(_segMan, obj, flags) & 0xFD); - } else { - // Scripted priority - - //pSnd->field_15B=1; - PUT_SEL32V(_segMan, obj, flags, GET_SEL32V(_segMan, obj, flags) | 2); - //DoSOund(0xF,hobj,w) - } -#endif -} - -void SoundCommandParser::cmdSetSoundLoop(reg_t obj, int16 value) { - if (!obj.segment) - return; - -#ifdef USE_OLD_MUSIC_FUNCTIONS - if (!GET_SEL32(_segMan, obj, 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 - if (value == -1) { - warning("cmdSetSoundLoop: Slot not found (%04x:%04x) and the song was requested to be looped", PRINT_REG(obj)); - } else { - // Doesn't really matter - } - return; - } - if (value == -1) { - musicSlot->loop = 0xFFFF; - } else { - musicSlot->loop = 1; // actually plays the music once - } - - PUT_SEL32V(_segMan, obj, loop, musicSlot->loop); -#endif -} - -void SoundCommandParser::cmdSuspendSound(reg_t obj, int16 value) { - // TODO - warning("STUB: cmdSuspendSound"); -} - -#ifndef USE_OLD_MUSIC_FUNCTIONS - -void SoundCommandParser::updateSci0Cues() { - Common::StackLock(_music->_mutex); - - 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 - if ((*i)->signal == 0 && (*i)->status != kSoundPlaying) - continue; - - cmdUpdateCues((*i)->soundObj, 0); - } -} - -#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); - - _music->resetDriver(); - - const MusicList::iterator end = _music->getPlayListEnd(); - for (MusicList::iterator i = _music->getPlayListStart(); i != end; ++i) { - if (savegame_version < 14) { - (*i)->dataInc = GET_SEL32V(_segMan, (*i)->soundObj, dataInc); - (*i)->signal = GET_SEL32V(_segMan, (*i)->soundObj, signal); - - if (_soundVersion >= SCI_VERSION_1_LATE) - (*i)->volume = GET_SEL32V(_segMan, (*i)->soundObj, vol); - } - - if ((*i)->resnum && _resMan->testResource(ResourceId(kResourceTypeSound, (*i)->resnum))) { - (*i)->soundRes = new SoundResource((*i)->resnum, _resMan, _soundVersion); - _music->soundInitSnd(*i); - } else { - (*i)->soundRes = 0; - } - if ((*i)->status == kSoundPlaying) - cmdPlaySound((*i)->soundObj, 0); - } - -#endif -} - -void SoundCommandParser::printPlayList(Console *con) { -#ifndef USE_OLD_MUSIC_FUNCTIONS - _music->printPlayList(con); -#endif -} - -void SoundCommandParser::resetDriver() { -#ifndef USE_OLD_MUSIC_FUNCTIONS - _music->resetDriver(); -#endif -} - -} // End of namespace Sci diff --git a/engines/sci/sfx/soundcmd.h b/engines/sci/sfx/soundcmd.h deleted file mode 100644 index 548dcf3889..0000000000 --- a/engines/sci/sfx/soundcmd.h +++ /dev/null @@ -1,122 +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_SOUNDCMD_H -#define SCI_SOUNDCMD_H - -#include "sci/sci.h" // for USE_OLD_MUSIC_FUNCTIONS - -#include "common/list.h" -#include "sci/engine/state.h" - -namespace Sci { - -class Console; -class SciMusic; -class SoundCommandParser; -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; -}; - -class SoundCommandParser { -public: - SoundCommandParser(ResourceManager *resMan, SegManager *segMan, AudioPlayer *audio, SciVersion soundVersion); - ~SoundCommandParser(); - -#ifdef USE_OLD_MUSIC_FUNCTIONS - void updateSfxState(SfxState *newState) { _state = newState; } -#endif - - reg_t parseCommand(int argc, reg_t *argv, reg_t acc); - void clearPlayList(); - void syncPlayList(Common::Serializer &s); - void reconstructPlayList(int savegame_version); - void printPlayList(Console *con); - void resetDriver(); - -#ifndef USE_OLD_MUSIC_FUNCTIONS - /** - * 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 - * scripts. In SCI0, we invoke this from kAnimate (which is called very often). SCI01 - * and later have a specific callback function, cmdUpdateCues, which is called regularly - * by the engine scripts themselves, so the engine itself polls for changes to the music - */ - void updateSci0Cues(); -#endif - -private: - Common::Array<MusicEntryCommand*> _soundCommands; - ResourceManager *_resMan; - SegManager *_segMan; -#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); - -#ifdef USE_OLD_MUSIC_FUNCTIONS - void changeSoundStatus(reg_t obj, int newStatus); -#endif -}; - -} // End of namespace Sci - -#endif // SCI_SOUNDCMD_H |