diff options
| author | Tony Puccinelli | 2010-08-11 01:11:16 +0000 | 
|---|---|---|
| committer | Tony Puccinelli | 2010-08-11 01:11:16 +0000 | 
| commit | 3a7a0ba720f219c4780cf19d196cda9c0456a20b (patch) | |
| tree | fe7f45242447dc7d14447babbdea9fbbb771c506 /engines/sci/sound/iterator | |
| parent | 6543062e5701e8011a4b12abffa8afca56f30b3f (diff) | |
| parent | fffec23a02cc88ed8daba0a3b50007b7e220c075 (diff) | |
| download | scummvm-rg350-3a7a0ba720f219c4780cf19d196cda9c0456a20b.tar.gz scummvm-rg350-3a7a0ba720f219c4780cf19d196cda9c0456a20b.tar.bz2 scummvm-rg350-3a7a0ba720f219c4780cf19d196cda9c0456a20b.zip | |
manually merged engines from trunk into branch
svn-id: r51964
Diffstat (limited to 'engines/sci/sound/iterator')
| -rw-r--r-- | engines/sci/sound/iterator/core.cpp | 1013 | ||||
| -rw-r--r-- | engines/sci/sound/iterator/core.h | 209 | ||||
| -rw-r--r-- | engines/sci/sound/iterator/iterator.cpp | 1686 | ||||
| -rw-r--r-- | engines/sci/sound/iterator/iterator.h | 326 | ||||
| -rw-r--r-- | engines/sci/sound/iterator/iterator_internal.h | 276 | ||||
| -rw-r--r-- | engines/sci/sound/iterator/songlib.cpp | 189 | ||||
| -rw-r--r-- | engines/sci/sound/iterator/songlib.h | 171 | ||||
| -rw-r--r-- | engines/sci/sound/iterator/test-iterator.cpp | 423 | 
8 files changed, 0 insertions, 4293 deletions
| diff --git a/engines/sci/sound/iterator/core.cpp b/engines/sci/sound/iterator/core.cpp deleted file mode 100644 index 7cd730b3e2..0000000000 --- a/engines/sci/sound/iterator/core.cpp +++ /dev/null @@ -1,1013 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/* Sound subsystem core: Event handler, sound player dispatching */ - -#include "sci/sci.h" -#ifdef USE_OLD_MUSIC_FUNCTIONS - -#include "sci/sound/iterator/core.h" -#include "sci/sound/iterator/iterator.h" -#include "sci/sound/drivers/mididriver.h" - -#include "common/system.h" -#include "common/timer.h" - -#include "sound/mixer.h" - -namespace Sci { - -/* Plays a song iterator that found a PCM through a PCM device, if possible -** Parameters: (SongIterator *) it: The iterator to play -**             (SongHandle) handle: Debug handle -** Returns   : (int) 0 if the effect will not be played, nonzero if it will -** This assumes that the last call to 'it->next()' returned SI_PCM. -*/ -static int sfx_play_iterator_pcm(SongIterator *it, SongHandle handle); - - -#pragma mark - - - -class SfxPlayer { -public: -	/** Number of voices that can play simultaneously */ -	int _polyphony; - -protected: -	SciVersion _soundVersion; -	MidiPlayer *_mididrv; - -	SongIterator *_iterator; -	Audio::Timestamp _wakeupTime; -	Audio::Timestamp _currentTime; -	uint32 _pauseTimeDiff; - -	bool _paused; -	bool _iteratorIsDone; -	uint32 _tempo; - -	Common::Mutex _mutex; -	int _volume; - -	void play_song(SongIterator *it); -	static void player_timer_callback(void *refCon); - -public: -	SfxPlayer(SciVersion soundVersion); -	~SfxPlayer(); - -	/** -	 * Initializes the player. -	 * @param resMan	a resource manager for driver initialization -	 * @param expected_latency	expected delay in between calls to 'maintenance' (in microseconds) -	 * @return	Common::kNoError on success, Common::kUnknownError on failure -	 */ -	Common::Error init(ResourceManager *resMan, int expected_latency); - -	/** -	 * Adds an iterator to the song player -	 * @param it		The iterator to play -	 * @param start_time	The time to assume as the time the first MIDI command executes at -	 * @return	Common::kNoError on success, Common::kUnknownError on failure -	 * -	 * The iterator should not be cloned (to avoid memory leaks) and -	 * may be modified according to the needs of the player. -	 * Implementors may use the 'sfx_iterator_combine()' function -	 * to add iterators onto their already existing iterators. -	 */ -	Common::Error add_iterator(SongIterator *it, uint32 start_time); - -	/** -	 * Stops the currently playing song and deletes the associated iterator. -	 * @return	Common::kNoError on success, Common::kUnknownError on failure -	 */ -	Common::Error stop(); - -	/** -	 * Transmits a song iterator message to the active song. -	 * @param msg	the message to transmit -	 * @return	Common::kNoError on success, Common::kUnknownError on failure -	 */ -	Common::Error iterator_message(const SongIterator::Message &msg); - -	/** -	 * Pauses song playing. -	 * @return	Common::kNoError on success, Common::kUnknownError on failure -	 */ -	Common::Error pause(); - -	/** -	 * Resumes song playing after a pause. -	 * @return	Common::kNoError on success, Common::kUnknownError on failure -	 */ -	Common::Error resume(); - -	/** -	 * Pass a raw MIDI event to the synth. -	 * @param argc	length of buffer holding the midi event -	 * @param argv	the buffer itself -	 */ -	void tell_synth(int buf_nr, byte *buf); - -	void setVolume(int vol); - -	int getVolume(); -}; - -SfxPlayer::SfxPlayer(SciVersion soundVersion) -	: _soundVersion(soundVersion), _wakeupTime(0, SFX_TICKS_PER_SEC), _currentTime(0, 1)  { -	_polyphony = 0; - -	_mididrv = 0; - -	_iterator = NULL; -	_pauseTimeDiff = 0; - -	_paused = false; -	_iteratorIsDone = false; -	_tempo = 0; - -	_volume = 15; -} - -SfxPlayer::~SfxPlayer() { -	if (_mididrv) { -		_mididrv->close(); -		delete _mididrv; -	} -	delete _iterator; -	_iterator = NULL; -} - -void SfxPlayer::play_song(SongIterator *it) { -	while (_iterator && _wakeupTime.msecsDiff(_currentTime) <= 0) { -		int delay; -		byte buf[8]; -		int result; - -		switch ((delay = songit_next(&(_iterator), -		                             buf, &result, -		                             IT_READER_MASK_ALL -		                             | IT_READER_MAY_FREE -		                             | IT_READER_MAY_CLEAN))) { - -		case SI_FINISHED: -			delete _iterator; -			_iterator = NULL; -			_iteratorIsDone = true; -			return; - -		case SI_IGNORE: -		case SI_LOOP: -		case SI_RELATIVE_CUE: -		case SI_ABSOLUTE_CUE: -			break; - -		case SI_PCM: -			sfx_play_iterator_pcm(_iterator, 0); -			break; - -		case 0: -			static_cast<MidiDriver *>(_mididrv)->send(buf[0], buf[1], buf[2]); - -			break; - -		default: -			_wakeupTime = _wakeupTime.addFrames(delay); -		} -	} -} - -void SfxPlayer::tell_synth(int buf_nr, byte *buf) { -	byte op1 = (buf_nr < 2 ? 0 : buf[1]); -	byte op2 = (buf_nr < 3 ? 0 : buf[2]); - -	static_cast<MidiDriver *>(_mididrv)->send(buf[0], op1, op2); -} - -void SfxPlayer::player_timer_callback(void *refCon) { -	SfxPlayer *thePlayer = (SfxPlayer *)refCon; -	assert(refCon); -	Common::StackLock lock(thePlayer->_mutex); - -	if (thePlayer->_iterator && !thePlayer->_iteratorIsDone && !thePlayer->_paused) { -		thePlayer->play_song(thePlayer->_iterator); -	} - -	thePlayer->_currentTime = thePlayer->_currentTime.addFrames(1); -} - -/* API implementation */ - -Common::Error SfxPlayer::init(ResourceManager *resMan, int expected_latency) { -	MidiDriverType musicDriver = MidiDriver::detectMusicDriver(MDT_PCSPK | MDT_ADLIB); - -	switch (musicDriver) { -	case MD_ADLIB: -		// FIXME: There's no Amiga sound option, so we hook it up to AdLib -		if (g_sci->getPlatform() == Common::kPlatformAmiga) -			_mididrv = MidiPlayer_Amiga_create(_soundVersion); -		else -			_mididrv = MidiPlayer_AdLib_create(_soundVersion); -		break; -	case MD_PCJR: -		_mididrv = MidiPlayer_PCJr_create(_soundVersion); -		break; -	case MD_PCSPK: -		_mididrv = MidiPlayer_PCSpeaker_create(_soundVersion); -		break; -	default: -		break; -	} - -	assert(_mididrv); - -	_polyphony = _mididrv->getPolyphony(); - -	_tempo = _mididrv->getBaseTempo(); -    uint32 time = g_system->getMillis(); -	_currentTime = Audio::Timestamp(time, 1000000 / _tempo); -	_wakeupTime = Audio::Timestamp(time, SFX_TICKS_PER_SEC); - -	_mididrv->setTimerCallback(this, player_timer_callback); -	_mididrv->open(resMan); -	_mididrv->setVolume(_volume); - -	return Common::kNoError; -} - -Common::Error SfxPlayer::add_iterator(SongIterator *it, uint32 start_time) { -	Common::StackLock lock(_mutex); -	SIMSG_SEND(it, SIMSG_SET_PLAYMASK(_mididrv->getPlayId())); -	SIMSG_SEND(it, SIMSG_SET_RHYTHM(_mididrv->hasRhythmChannel())); - -	if (_iterator == NULL) { -		// Resync with clock -		_currentTime = Audio::Timestamp(g_system->getMillis(), 1000000 / _tempo); -		_wakeupTime = Audio::Timestamp(start_time, SFX_TICKS_PER_SEC); -	} - -	_iterator = sfx_iterator_combine(_iterator, it); -	_iteratorIsDone = false; - -	return Common::kNoError; -} - -Common::Error SfxPlayer::stop() { -	debug(3, "Player: Stopping song iterator %p", (void *)_iterator); -	Common::StackLock lock(_mutex); -	delete _iterator; -	_iterator = NULL; -	for (int i = 0; i < MIDI_CHANNELS; i++) -		static_cast<MidiDriver *>(_mididrv)->send(0xb0 + i, SCI_MIDI_CHANNEL_NOTES_OFF, 0); - -	return Common::kNoError; -} - -Common::Error SfxPlayer::iterator_message(const SongIterator::Message &msg) { -	Common::StackLock lock(_mutex); -	if (!_iterator) { -		return Common::kUnknownError; -	} - -	songit_handle_message(&_iterator, msg); - -	return Common::kNoError; -} - -Common::Error SfxPlayer::pause() { -	Common::StackLock lock(_mutex); - -	_paused = true; -	_pauseTimeDiff = _wakeupTime.msecsDiff(_currentTime); - -	_mididrv->playSwitch(false); - -	return Common::kNoError; -} - -Common::Error SfxPlayer::resume() { -	Common::StackLock lock(_mutex); - -	_wakeupTime = Audio::Timestamp(_currentTime.msecs() + _pauseTimeDiff, SFX_TICKS_PER_SEC); -	_mididrv->playSwitch(true); -	_paused = false; - -	return Common::kNoError; -} - -void SfxPlayer::setVolume(int vol) { -	_mididrv->setVolume(vol); -} - -int SfxPlayer::getVolume() { -	return _mididrv->getVolume(); -} - -#pragma mark - - -void SfxState::sfx_reset_player() { -	if (_player) -		_player->stop(); -} - -void SfxState::sfx_player_tell_synth(int buf_nr, byte *buf) { -	if (_player) -		_player->tell_synth(buf_nr, buf); -} - -int SfxState::sfx_get_player_polyphony() { -	if (_player) -		return _player->_polyphony; -	else -		return 0; -} - -SfxState::SfxState() { -	_player = NULL; -	_it = NULL; -	_flags = 0; -	_song = NULL; -	_suspended = 0; -} - -SfxState::~SfxState() { -} - - -void SfxState::freezeTime() { -	/* Freezes the top song delay time */ -	const Audio::Timestamp ctime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC); -	Song *song = _song; - -	while (song) { -		song->_delay = song->_wakeupTime.frameDiff(ctime); -		if (song->_delay < 0) -			song->_delay = 0; - -		song = song->_nextPlaying; -	} -} - -void SfxState::thawTime() { -	/* inverse of freezeTime() */ -	const Audio::Timestamp ctime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC); -	Song *song = _song; - -	while (song) { -		song->_wakeupTime = ctime.addFrames(song->_delay); - -		song = song->_nextPlaying; -	} -} - -#if 0 -// Unreferenced - removed -static void _dump_playing_list(SfxState *self, char *msg) { -	Song *song = self->_song; - -	fprintf(stderr, "[] Song list : [ "); -	song = *(self->_songlib.lib); -	while (song) { -		fprintf(stderr, "%08lx:%d ", song->handle, song->_status); -		song = song->_nextPlaying; -	} -	fprintf(stderr, "]\n"); - -	fprintf(stderr, "[] Play list (%s) : [ " , msg); - -	while (song) { -		fprintf(stderr, "%08lx ", song->handle); -		song = song->_nextPlaying; -	} - -	fprintf(stderr, "]\n"); -} -#endif - -#if 0 -static void _dump_songs(SfxState *self) { -	Song *song = self->_song; - -	fprintf(stderr, "Cue iterators:\n"); -	song = *(self->_songlib.lib); -	while (song) { -		fprintf(stderr, "  **\tHandle %08x (p%d): status %d\n", -		        song->handle, song->_priority, song->_status); -		SIMSG_SEND(song->_it, SIMSG_PRINT(1)); -		song = song->_next; -	} - -	if (self->_player) { -		fprintf(stderr, "Audio iterator:\n"); -		self->_player->iterator_message(SongIterator::Message(0, SIMSG_PRINT(1))); -	} -} -#endif - -bool SfxState::isPlaying(Song *song) { -	Song *playing_song = _song; - -	/*	_dump_playing_list(this, "is-playing");*/ - -	while (playing_song) { -		if (playing_song == song) -			return true; -		playing_song = playing_song->_nextPlaying; -	} -	return false; -} - -void SfxState::setSongStatus(Song *song, int status) { -	const Audio::Timestamp ctime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC); - -	switch (status) { - -	case SOUND_STATUS_STOPPED: -		// Reset -		song->_it->init(); -		break; - -	case SOUND_STATUS_SUSPENDED: -	case SOUND_STATUS_WAITING: -		if (song->_status == SOUND_STATUS_PLAYING) { -			// Update delay, set wakeup_time -			song->_delay += song->_wakeupTime.frameDiff(ctime); -			song->_wakeupTime = ctime; -		} -		if (status == SOUND_STATUS_SUSPENDED) -			break; - -		/* otherwise... */ - -	case SOUND_STATUS_PLAYING: -		if (song->_status == SOUND_STATUS_STOPPED) { -			// Starting anew -			song->_wakeupTime = ctime; -		} - -		if (isPlaying(song)) -			status = SOUND_STATUS_PLAYING; -		else -			status = SOUND_STATUS_WAITING; -		break; - -	default: -		fprintf(stderr, "%s L%d: Attempt to set invalid song" -		        " state %d!\n", __FILE__, __LINE__, status); -		return; - -	} -	song->_status = status; -} - -/* Update internal state iff only one song may be played */ -void SfxState::updateSingleSong() { -	Song *newsong = _songlib.findFirstActive(); - -	if (newsong != _song) { -		freezeTime(); /* Store song delay time */ - -		if (_player) -			_player->stop(); - -		if (newsong) { -			if (!newsong->_it) -				return; /* Restore in progress and not ready for this yet */ - -			/* Change song */ -			if (newsong->_status == SOUND_STATUS_WAITING) -				setSongStatus(newsong, SOUND_STATUS_PLAYING); - -			/* Change instrument mappings */ -		} else { -			/* Turn off sound */ -		} -		if (_song) { -			if (_song->_status == SOUND_STATUS_PLAYING) -				setSongStatus(newsong, SOUND_STATUS_WAITING); -		} - -		Common::String debugMessage = "[SFX] Changing active song:"; -		if (!_song) { -			debugMessage += " New song:"; -		} else { -			char tmp[50]; -			sprintf(tmp, " pausing %08lx, now playing ", _song->_handle); -			debugMessage += tmp; -		} - -		if (newsong) { -			char tmp[20]; -			sprintf(tmp, "%08lx\n", newsong->_handle); -			debugMessage += tmp; -		} else { -			debugMessage += " none\n"; -		} - -		debugC(2, kDebugLevelSound, "%s", debugMessage.c_str()); - -		_song = newsong; -		thawTime(); /* Recover song delay time */ - -		if (newsong && _player) { -			SongIterator *clonesong = newsong->_it->clone(newsong->_delay); - -			_player->add_iterator(clonesong, newsong->_wakeupTime.msecs()); -		} -	} -} - - -void SfxState::updateMultiSong() { -	Song *oldfirst = _song; -	Song *oldseeker; -	Song *newsong = _songlib.findFirstActive(); -	Song *newseeker; -	Song not_playing_anymore; /* Dummy object, referenced by -				    ** songs which are no longer -				    ** active.  */ - -	/*	_dump_playing_list(this, "before");*/ -	freezeTime(); /* Store song delay time */ - -	// WORKAROUND: sometimes, newsong can be NULL (e.g. in SQ4). -	// Handle this here, so that we avoid a crash -	if (!newsong) { -		// Iterators should get freed when there's only one song left playing -		if(oldfirst && oldfirst->_status == SOUND_STATUS_STOPPED) { -			debugC(2, kDebugLevelSound, "[SFX] Stopping song %lx", oldfirst->_handle); -			if (_player && oldfirst->_it) -				_player->iterator_message(SongIterator::Message(oldfirst->_it->ID, SIMSG_STOP)); -		} -		return; -	} - -	for (newseeker = newsong; newseeker; -	        newseeker = newseeker->_nextPlaying) { -		if (!newseeker || !newseeker->_it) -			return; /* Restore in progress and not ready for this yet */ -	} - -	/* First, put all old songs into the 'stopping' list and -	** mark their 'next-playing' as not_playing_anymore.  */ -	for (oldseeker = oldfirst; oldseeker; -	        oldseeker = oldseeker->_nextStopping) { -		oldseeker->_nextStopping = oldseeker->_nextPlaying; -		oldseeker->_nextPlaying = ¬_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", oldseeker->_handle); - -			if (_player && oldseeker->_it) -				_player->iterator_message(SongIterator::Message(oldseeker->_it->ID, SIMSG_STOP)); -			oldseeker->_nextPlaying = NULL; /* Clear this pointer; we don't need the tag anymore */ -		} - -	for (newseeker = newsong; newseeker; newseeker = newseeker->_nextPlaying) { -		if (newseeker->_status != SOUND_STATUS_PLAYING && _player) { -			debugC(2, kDebugLevelSound, "[SFX] Adding song %lx", newseeker->_it->ID); - -			SongIterator *clonesong = newseeker->_it->clone(newseeker->_delay); -			_player->add_iterator(clonesong, g_system->getMillis()); -		} -		setSongStatus(newseeker, SOUND_STATUS_PLAYING); -	} - -	_song = newsong; -	thawTime(); -	/*	_dump_playing_list(this, "after");*/ -} - -/* Update internal state */ -void SfxState::update() { -	if (_flags & SFX_STATE_FLAG_MULTIPLAY) -		updateMultiSong(); -	else -		updateSingleSong(); -} - -static int sfx_play_iterator_pcm(SongIterator *it, SongHandle handle) { -#ifdef DEBUG_SONG_API -	fprintf(stderr, "[sfx-core] Playing PCM: %08lx\n", handle); -#endif -	if (g_system->getMixer()->isReady()) { -		Audio::AudioStream *newfeed = it->getAudioStream(); -		if (newfeed) { -			g_system->getMixer()->playStream(Audio::Mixer::kSFXSoundType, 0, newfeed); -			return 1; -		} -	} -	return 0; -} - -#define DELAY (1000000 / SFX_TICKS_PER_SEC) - -void SfxState::sfx_init(ResourceManager *resMan, int flags, SciVersion soundVersion) { -	_songlib._lib = 0; -	_song = NULL; -	_flags = flags; - -	_player = NULL; - -	if (flags & SFX_STATE_FLAG_NOSOUND) { -		warning("[SFX] Sound disabled"); -		return; -	} - -#ifdef DEBUG_SONG_API -	fprintf(stderr, "[sfx-core] Initialising: flags=%x\n", flags); -#endif - -	/*-------------------*/ -	/* Initialise player */ -	/*-------------------*/ - -	if (!resMan) { -		warning("[SFX] Warning: No resource manager present, cannot initialise player"); -		return; -	} - -	_player = new SfxPlayer(soundVersion); - -	if (!_player) { -		warning("[SFX] No song player found"); -		return; -	} - -	if (_player->init(resMan, DELAY / 1000)) { -		warning("[SFX] Song player reported error, disabled"); -		delete _player; -		_player = NULL; -	} - -	_resMan = resMan; -} - -void SfxState::sfx_exit() { -#ifdef DEBUG_SONG_API -	fprintf(stderr, "[sfx-core] Uninitialising\n"); -#endif - -	delete _player; -	_player = 0; - -	g_system->getMixer()->stopAll(); - -	_songlib.freeSounds(); -} - -void SfxState::sfx_suspend(bool suspend) { -#ifdef DEBUG_SONG_API -	fprintf(stderr, "[sfx-core] Suspending? = %d\n", suspend); -#endif -	if (suspend && (!_suspended)) { -		/* suspend */ - -		freezeTime(); -		if (_player) -			_player->pause(); -		/* Suspend song player */ - -	} else if (!suspend && (_suspended)) { -		/* unsuspend */ - -		thawTime(); -		if (_player) -			_player->resume(); - -		/* Unsuspend song player */ -	} - -	_suspended = suspend; -} - -int SfxState::sfx_poll(SongHandle *handle, int *cue) { -	if (!_song) -		return 0; /* No milk today */ - -	*handle = _song->_handle; - -#ifdef DEBUG_SONG_API -	fprintf(stderr, "[sfx-core] Polling any (%08lx)\n", *handle); -#endif -	return sfx_poll_specific(*handle, cue); -} - -int SfxState::sfx_poll_specific(SongHandle handle, int *cue) { -	const Audio::Timestamp ctime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC); -	Song *song = _song; - -	while (song && song->_handle != handle) -		song = song->_nextPlaying; - -	if (!song) -		return 0; /* Song not playing */ - -	debugC(2, kDebugLevelSound, "[SFX:CUE] Polled song %08lx ", handle); - -	while (1) { -		if (song->_wakeupTime.frameDiff(ctime) > 0) -			return 0; /* Patience, young hacker! */ - -		byte buf[8]; -		int result = songit_next(&(song->_it), buf, cue, IT_READER_MASK_ALL); - -		switch (result) { - -		case SI_FINISHED: -			setSongStatus(song, SOUND_STATUS_STOPPED); -			update(); -			/* ...fall through... */ -		case SI_LOOP: -		case SI_RELATIVE_CUE: -		case SI_ABSOLUTE_CUE: -			if (result == SI_FINISHED) -				debugC(2, kDebugLevelSound, " => finished"); -			else { -				if (result == SI_LOOP) -					debugC(2, kDebugLevelSound, " => Loop: %d (0x%x)", *cue, *cue); -				else -					debugC(2, kDebugLevelSound, " => Cue: %d (0x%x)", *cue, *cue); - -			} -			return result; - -		default: -			if (result > 0) -				song->_wakeupTime = song->_wakeupTime.addFrames(result); - -			/* Delay */ -			break; -		} -	} - -} - - -/*****************/ -/*  Song basics  */ -/*****************/ - -void SfxState::sfx_add_song(SongIterator *it, int priority, SongHandle handle, int number) { -	Song *song = _songlib.findSong(handle); - -#ifdef DEBUG_SONG_API -	fprintf(stderr, "[sfx-core] Adding song: %08lx at %d, it=%p\n", handle, priority, it); -#endif -	if (!it) { -		error("[SFX] Attempt to add empty song with handle %08lx", handle); -		return; -	} - -	it->init(); - -	/* If we're already playing this, stop it */ -	/* Tell player to shut up */ -//	_dump_songs(this); - -	if (_player) -		_player->iterator_message(SongIterator::Message(handle, SIMSG_STOP)); - -	if (song) { -		setSongStatus( song, SOUND_STATUS_STOPPED); - -		fprintf(stderr, "Overwriting old song (%08lx) ...\n", handle); -		if (song->_status == SOUND_STATUS_PLAYING || song->_status == SOUND_STATUS_SUSPENDED) { -			delete it; -			error("Unexpected (error): Song %ld still playing/suspended (%d)", -			        handle, song->_status); -			return; -		} else { -			_songlib.removeSong(handle); /* No duplicates */ -		} - -	} - -	song = new Song(handle, it, priority); -	song->_resourceNum = number; -	song->_hold = 0; -	song->_loops = 0; -	song->_wakeupTime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC); -	_songlib.addSong(song); -	_song = NULL; /* As above */ -	update(); - -	return; -} - -void SfxState::sfx_remove_song(SongHandle handle) { -#ifdef DEBUG_SONG_API -	fprintf(stderr, "[sfx-core] Removing song: %08lx\n", handle); -#endif -	if (_song && _song->_handle == handle) -		_song = NULL; - -	_songlib.removeSong(handle); -	update(); -} - - - -/**********************/ -/* Song modifications */ -/**********************/ - -#define ASSERT_SONG(s) if (!(s)) { warning("Looking up song handle %08lx failed in %s, L%d", handle, __FILE__, __LINE__); return; } - -void SfxState::sfx_song_set_status(SongHandle handle, int status) { -	Song *song = _songlib.findSong(handle); -	ASSERT_SONG(song); -#ifdef DEBUG_SONG_API -	fprintf(stderr, "[sfx-core] Setting song status to %d" -	        " (0:stop, 1:play, 2:susp, 3:wait): %08lx\n", status, handle); -#endif - -	setSongStatus(song, status); - -	update(); -} - -void SfxState::sfx_song_set_fade(SongHandle handle, fade_params_t *params) { -#ifdef DEBUG_SONG_API -	static const char *stopmsg[] = {"??? Should not happen", "Do not stop afterwards", "Stop afterwards"}; -#endif -	Song *song = _songlib.findSong(handle); - -	ASSERT_SONG(song); - -#ifdef DEBUG_SONG_API -	fprintf(stderr, "[sfx-core] Setting fade params of %08lx to " -	        "final volume %d in steps of %d per %d ticks. %s.", -	        handle, fade->final_volume, fade->step_size, fade->ticks_per_step, -	        stopmsg[fade->action]); -#endif - -	SIMSG_SEND_FADE(song->_it, params); - -	update(); -} - -void SfxState::sfx_song_renice(SongHandle handle, int priority) { -	Song *song = _songlib.findSong(handle); -	ASSERT_SONG(song); -#ifdef DEBUG_SONG_API -	fprintf(stderr, "[sfx-core] Renicing song %08lx to %d\n", -	        handle, priority); -#endif - -	song->_priority = priority; - -	update(); -} - -void SfxState::sfx_song_set_loops(SongHandle handle, int loops) { -	Song *song = _songlib.findSong(handle); -	SongIterator::Message msg = SongIterator::Message(handle, SIMSG_SET_LOOPS(loops)); -	ASSERT_SONG(song); - -	song->_loops = loops; -#ifdef DEBUG_SONG_API -	fprintf(stderr, "[sfx-core] Setting loops on %08lx to %d\n", -	        handle, loops); -#endif -	songit_handle_message(&(song->_it), msg); - -	if (_player/* && _player->send_iterator_message*/) -		/* FIXME: The above should be optional! */ -		_player->iterator_message(msg); -} - -void SfxState::sfx_song_set_hold(SongHandle handle, int hold) { -	Song *song = _songlib.findSong(handle); -	SongIterator::Message msg = SongIterator::Message(handle, SIMSG_SET_HOLD(hold)); -	ASSERT_SONG(song); - -	song->_hold = hold; -#ifdef DEBUG_SONG_API -	fprintf(stderr, "[sfx-core] Setting hold on %08lx to %d\n", -	        handle, hold); -#endif -	songit_handle_message(&(song->_it), msg); - -	if (_player/* && _player->send_iterator_message*/) -		/* FIXME: The above should be optional! */ -		_player->iterator_message(msg); -} - -/* Different from the one in iterator.c */ -static const int MIDI_cmdlen[16] = {0, 0, 0, 0, 0, 0, 0, 0, -                                    3, 3, 0, 3, 2, 0, 3, 0 -                                   }; - -static const SongHandle midi_send_base = 0xffff0000; - -Common::Error SfxState::sfx_send_midi(SongHandle handle, int channel, -	int command, int arg1, int arg2) { -	byte buffer[5]; - -	/* Yes, in that order. SCI channel mutes are actually done via -	   a counting semaphore. 0 means to decrement the counter, 1 -	   to increment it. */ -	static const char *channel_state[] = {"ON", "OFF"}; - -	if (command == 0xb0 && -	        arg1 == SCI_MIDI_CHANNEL_MUTE) { -		warning("TODO: channel mute (channel %d %s)", channel, channel_state[arg2]); -		/* We need to have a GET_PLAYMASK interface to use -		   here. SET_PLAYMASK we've got. -		*/ -		return Common::kNoError; -	} - -	buffer[0] = channel | command; /* No channel remapping yet */ - -	switch (command) { -	case 0x80 : -	case 0x90 : -	case 0xb0 : -		buffer[1] = arg1 & 0xff; -		buffer[2] = arg2 & 0xff; -		break; -	case 0xc0 : -		buffer[1] = arg1 & 0xff; -		break; -	case 0xe0 : -		buffer[1] = (arg1 & 0x7f) | 0x80; -		buffer[2] = (arg1 & 0xff00) >> 7; -		break; -	default: -		warning("Unexpected explicit MIDI command %02x", command); -		return Common::kUnknownError; -	} - -	if (_player) -		_player->tell_synth(MIDI_cmdlen[command >> 4], buffer); -	return Common::kNoError; -} - -int SfxState::sfx_getVolume() { -	return _player->getVolume(); -} - -void SfxState::sfx_setVolume(int volume) { -	_player->setVolume(volume); -} - -void SfxState::sfx_all_stop() { -#ifdef DEBUG_SONG_API -	fprintf(stderr, "[sfx-core] All stop\n"); -#endif - -	_songlib.freeSounds(); -	update(); -} - -} // End of namespace Sci - -#endif	// USE_OLD_MUSIC_FUNCTIONS diff --git a/engines/sci/sound/iterator/core.h b/engines/sci/sound/iterator/core.h deleted file mode 100644 index a44fe2ecae..0000000000 --- a/engines/sci/sound/iterator/core.h +++ /dev/null @@ -1,209 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/* Sound engine */ -#ifndef SCI_SFX_CORE_H -#define SCI_SFX_CORE_H - -#include "common/error.h" - -#include "sci/sci.h"	// for USE_OLD_MUSIC_FUNCTIONS - -#ifdef USE_OLD_MUSIC_FUNCTIONS -#include "sci/sound/iterator/songlib.h" -#include "sci/resource.h" - -namespace Sci { - -class SfxPlayer; -class SongIterator; -struct fade_params_t; - -#define SFX_TICKS_PER_SEC 60 /* MIDI ticks per second */ - - -#define SFX_STATE_FLAG_MULTIPLAY (1 << 0) /* More than one song playable -** simultaneously ? */ -#define SFX_STATE_FLAG_NOSOUND	 (1 << 1) /* Completely disable sound playing */ - -class SfxState { -private: -	SfxPlayer *_player; - -public:	// FIXME, make private -	SongIterator *_it; /**< The song iterator at the heart of things */ -	uint _flags; /**< SFX_STATE_FLAG_* */ -	SongLibrary _songlib; /**< Song library */ -	Song *_song; /**< Active song, or start of active song chain */ -	bool _suspended; /**< Whether we are suspended */ -	ResourceManager *_resMan; - -public: -	SfxState(); -	~SfxState(); - -	/***********/ -	/* General */ -	/***********/ - -	/* Initializes the sound engine -	** Parameters: (ResourceManager *) resMan: Resource manager for initialization -	**             (int) flags: SFX_STATE_FLAG_* -	*/ -	void sfx_init(ResourceManager *resMan, int flags, SciVersion soundVersion); - -	/** Deinitializes the sound subsystem. */ -	void sfx_exit(); - -	/* Suspends/unsuspends the sound sybsystem -	** Parameters: (int) suspend: Whether to suspend (non-null) or to unsuspend -	*/ -	void sfx_suspend(bool suspend); - -	/* Polls the sound server for cues etc. -	** Returns   : (int) 0 if the cue queue is empty, SI_LOOP, SI_CUE, or SI_FINISHED otherwise -	**             (SongHandle) *handle: The affected handle -	**             (int) *cue: The sound cue number (if SI_CUE), or the loop number (if SI_LOOP) -	*/ -	int sfx_poll(SongHandle *handle, int *cue); - -	/* Polls the sound server for cues etc. -	** Parameters: (SongHandle) handle: The handle to poll -	** Returns   : (int) 0 if the cue queue is empty, SI_LOOP, SI_CUE, or SI_FINISHED otherwise -	**             (int) *cue: The sound cue number (if SI_CUE), or the loop number (if SI_LOOP) -	*/ -	int sfx_poll_specific(SongHandle handle, int *cue); - -	/* Determines the current global volume settings -	** Returns   : (int) The global volume, between 0 (silent) and 127 (max. volume) -	*/ -	int sfx_getVolume(); - -	/* Determines the current global volume settings -	** Parameters: (int) volume: The new global volume, between 0 and 127 (see above) -	*/ -	void sfx_setVolume(int volume); - -	/* Stops all songs currently playing, purges song library -	*/ -	void sfx_all_stop(); - - -	/*****************/ -	/*  Song basics  */ -	/*****************/ - -	/* Adds a song to the internal sound library -	** Parameters: (SongIterator *) it: The iterator describing the song -	**             (int) priority: Initial song priority (higher <-> more important) -	**             (SongHandle) handle: The handle to associate with the song -	*/ -	void sfx_add_song(SongIterator *it, int priority, SongHandle handle, int resnum); - - -	/* Deletes a song and its associated song iterator from the song queue -	** Parameters: (SongHandle) handle: The song to remove -	*/ -	void sfx_remove_song(SongHandle handle); - - -	/**********************/ -	/* Song modifications */ -	/**********************/ - - -	/* Sets the song status, i.e. whether it is playing, suspended, or stopped. -	** Parameters: (SongHandle) handle: Handle of the song to modify -	**             (int) status: The song status the song should assume -	** WAITING and PLAYING are set implicitly and essentially describe the same state -	** as far as this function is concerned. -	*/ -	void sfx_song_set_status(SongHandle handle, int status); - -	/* Sets the new song priority -	** Parameters: (SongHandle) handle: The handle to modify -	**             (int) priority: The priority to set -	*/ -	void sfx_song_renice(SongHandle handle, int priority); - -	/* Sets the number of loops for the specified song -	** Parameters: (SongHandle) handle: The song handle to reference -	**             (int) loops: Number of loops to set -	*/ -	void sfx_song_set_loops(SongHandle handle, int loops); - -	/* Sets the number of loops for the specified song -	** Parameters: (SongHandle) handle: The song handle to reference -	**             (int) hold: Number of loops to setn -	*/ -	void sfx_song_set_hold(SongHandle handle, int hold); - -	/* Instructs a song to be faded out -	** Parameters: (SongHandle) handle: The song handle to reference -	**             (fade_params_t *) fade_setup: The precise fade-out configuration to use -	*/ -	void sfx_song_set_fade(SongHandle handle, fade_params_t *fade_setup); - - -	// Previously undocumented: -	Common::Error sfx_send_midi(SongHandle handle, int channel, -		int command, int arg1, int arg2); - -	// misc - -	/** -	 * Determines the polyphony of the player in use. -	 * @return Number of voices the active player can emit -	 */ -	int sfx_get_player_polyphony(); - -	/** -	 * Tells the player to stop its internal iterator. -	 */ -	void sfx_reset_player(); - -	/** -	 * Pass a raw MIDI event to the synth of the player. -	 * @param	argc	Length of buffer holding the midi event -	 * @param	argv	The buffer itself -	 */ -	void sfx_player_tell_synth(int buf_nr, byte *buf); - -protected: -	void freezeTime(); -	void thawTime(); - -	bool isPlaying(Song *song); -	void setSongStatus(Song *song, int status); -	void updateSingleSong(); -	void updateMultiSong(); -	void update(); -}; - -} // End of namespace Sci - -#endif	// USE_OLD_MUSIC_FUNCTIONS - -#endif // SCI_SFX_CORE_H diff --git a/engines/sci/sound/iterator/iterator.cpp b/engines/sci/sound/iterator/iterator.cpp deleted file mode 100644 index 5d9d63e5af..0000000000 --- a/engines/sci/sound/iterator/iterator.cpp +++ /dev/null @@ -1,1686 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/* Song iterators */ - -#include "common/util.h" - -#include "sci/sci.h" -#ifdef USE_OLD_MUSIC_FUNCTIONS - -#include "sci/sound/iterator/iterator_internal.h" -#include "sci/engine/state.h"	// for sfx_player_tell_synth :/ -#include "sci/sound/iterator/core.h"	// for sfx_player_tell_synth - -#include "sound/audiostream.h" -#include "sound/mixer.h" -#include "sound/decoders/raw.h" - -namespace Sci { - - -static const int MIDI_cmdlen[16] = {0, 0, 0, 0, 0, 0, 0, 0, -                                    2, 2, 2, 2, 1, 1, 2, 0 -                                   }; - -/*#define DEBUG_DECODING*/ -/*#define DEBUG_VERBOSE*/ - -/** Find first set bit in bits and return its index. Returns 0 if bits is 0. */ -static int sci_ffs(int bits) { -	if (!bits) -		return 0; - -	int retval = 1; - -	while (!(bits & 1)) { -		retval++; -		bits >>= 1; -	} - -	return retval; -} - -static void print_tabs_id(int nr, songit_id_t id) { -	while (nr-- > 0) -		fprintf(stderr, "\t"); - -	fprintf(stderr, "[%08lx] ", id); -} - -BaseSongIterator::BaseSongIterator(byte *data, uint size, songit_id_t id) -	: _data(data, size) { -	ID = id; -} - -/************************************/ -/*-- SCI0 iterator implementation --*/ -/************************************/ - -#define SCI0_MIDI_OFFSET 33 -#define SCI0_END_OF_SONG 0xfc /* proprietary MIDI command */ - -#define SCI0_PCM_SAMPLE_RATE_OFFSET 0x0e -#define SCI0_PCM_SIZE_OFFSET 0x20 -#define SCI0_PCM_DATA_OFFSET 0x2c - -#define CHECK_FOR_END_ABSOLUTE(offset) \ -	if (offset > _data.size()) { \ -		warning("Reached end of song without terminator (%x/%x) at %d", offset, _data.size(), __LINE__); \ -		return SI_FINISHED; \ -	} - -#define CHECK_FOR_END(offset_augment) \ -	if ((channel->offset + (offset_augment)) > channel->end) { \ -		channel->state = SI_STATE_FINISHED; \ -		warning("Reached end of track %d without terminator (%x+%x/%x) at %d", channel->id, channel->offset, offset_augment, channel->end, __LINE__); \ -		return SI_FINISHED; \ -	} - - -static int _parse_ticks(byte *data, int *offset_p, int size) { -	int ticks = 0; -	int tempticks; -	int offset = 0; - -	do { -		tempticks = data[offset++]; -		ticks += (tempticks == SCI_MIDI_TIME_EXPANSION_PREFIX) ? -		         SCI_MIDI_TIME_EXPANSION_LENGTH : tempticks; -	} while (tempticks == SCI_MIDI_TIME_EXPANSION_PREFIX -	         && offset < size); - -	if (offset_p) -		*offset_p = offset; - -	return ticks; -} - - -static int _sci0_get_pcm_data(Sci0SongIterator *self, int *rate, int *xoffset, uint *xsize); - - -#define PARSE_FLAG_LOOPS_UNLIMITED (1 << 0) /* Unlimited # of loops? */ -#define PARSE_FLAG_PARAMETRIC_CUE (1 << 1) /* Assume that cues take an additional "cue value" argument */ -/* This implements a difference between SCI0 and SCI1 cues. */ - -void SongIteratorChannel::init(int id_, int offset_, int end_) { -	playmask = PLAYMASK_NONE; /* Disable all channels */ -	id = id_; -	state = SI_STATE_DELTA_TIME; -	loop_timepos = 0; -	total_timepos = 0; -	timepos_increment = 0; -	delay = 0; /* Only used for more than one channel */ -	last_cmd = 0xfe; - -	offset = loop_offset = initial_offset = offset_; -	end = end_; -} - -void SongIteratorChannel::resetSynthChannels() { -	byte buf[5]; - -	// FIXME: Evil hack -	SfxState &sound = g_sci->getEngineState()->_sound; - -	for (int i = 0; i < MIDI_CHANNELS; i++) { -		if (playmask & (1 << i)) { -			buf[0] = 0xe0 | i; /* Pitch bend */ -			buf[1] = 0x80; /* Wheel center */ -			buf[2] = 0x40; -			sound.sfx_player_tell_synth(3, buf); - -			buf[0] = 0xb0 | i; // Set control -			buf[1] = 0x40; // Hold pedal -			buf[2] = 0x00; // Off -			sound.sfx_player_tell_synth(3, buf); -			/* TODO: Reset other controls? */ -		} -	} -} - -int BaseSongIterator::parseMidiCommand(byte *buf, int *result, SongIteratorChannel *channel, int flags) { -	byte cmd; -	int paramsleft; -	int midi_op; -	int midi_channel; - -	channel->state = SI_STATE_DELTA_TIME; - -	cmd = _data[channel->offset++]; - -	if (!(cmd & 0x80)) { -		/* 'Running status' mode */ -		channel->offset--; -		cmd = channel->last_cmd; -	} - -	if (cmd == 0xfe) { -		warning("song iterator subsystem: Corrupted sound resource detected."); -		return SI_FINISHED; -	} - -	midi_op = cmd >> 4; -	midi_channel = cmd & 0xf; -	paramsleft = MIDI_cmdlen[midi_op]; - -#if 0 -	if (1) { -		fprintf(stderr, "[IT]: off=%x, cmd=%02x, takes %d args ", -		        channel->offset - 1, cmd, paramsleft); -		fprintf(stderr, "[%02x %02x <%02x> %02x %02x %02x]\n", -		        _data[channel->offset-3], -		        _data[channel->offset-2], -		        _data[channel->offset-1], -		        _data[channel->offset], -		        _data[channel->offset+1], -		        _data[channel->offset+2]); -	} -#endif - -	buf[0] = cmd; - - -	CHECK_FOR_END(paramsleft); -	memcpy(buf + 1, _data.begin() + channel->offset, paramsleft); -	*result = 1 + paramsleft; - -	channel->offset += paramsleft; - -	channel->last_cmd = cmd; - -	/* Are we supposed to play this channel? */ -	if ( -	    /* First, exclude "global" properties-- such as cues-- from consideration */ -	    (midi_op < 0xf -	     && !(cmd == SCI_MIDI_SET_SIGNAL) -	     && !(SCI_MIDI_CONTROLLER(cmd) -	          && buf[1] == SCI_MIDI_CUMULATIVE_CUE)) - -	    /* Next, check if the channel is allowed */ -	    && (!((1 << midi_channel) & channel->playmask))) -		return  /* Execute next command */ -		    nextCommand(buf, result); - - -	if (cmd == SCI_MIDI_EOT) { -		/* End of track? */ -		channel->resetSynthChannels(); -		if (_loops > 1) { -			/* If allowed, decrement the number of loops */ -			if (!(flags & PARSE_FLAG_LOOPS_UNLIMITED)) -				*result = --_loops; - -#ifdef DEBUG_DECODING -			fprintf(stderr, "%s L%d: (%p):%d Looping ", __FILE__, __LINE__, this, channel->id); -			if (flags & PARSE_FLAG_LOOPS_UNLIMITED) -				fprintf(stderr, "(indef.)"); -			else -				fprintf(stderr, "(%d)", _loops); -			fprintf(stderr, " %x -> %x\n", -			        channel->offset, channel->loop_offset); -#endif -			channel->offset = channel->loop_offset; -			channel->state = SI_STATE_DELTA_TIME; -			channel->total_timepos = channel->loop_timepos; -			channel->last_cmd = 0xfe; -			debugC(2, kDebugLevelSound, "Looping song iterator %08lx.", ID); -			return SI_LOOP; -		} else { -			channel->state = SI_STATE_FINISHED; -			return SI_FINISHED; -		} - -	} else if (cmd == SCI_MIDI_SET_SIGNAL) { -		if (buf[1] == SCI_MIDI_SET_SIGNAL_LOOP) { -			channel->loop_offset = channel->offset; -			channel->loop_timepos = channel->total_timepos; - -			return /* Execute next command */ -			    nextCommand(buf, result); -		} else { -			/* Used to be conditional <= 127 */ -			*result = buf[1]; /* Absolute cue */ -			return SI_ABSOLUTE_CUE; -		} -	} else if (SCI_MIDI_CONTROLLER(cmd)) { -		switch (buf[1]) { - -		case SCI_MIDI_CUMULATIVE_CUE: -			if (flags & PARSE_FLAG_PARAMETRIC_CUE) -				_ccc += buf[2]; -			else { /* No parameter to CC */ -				_ccc++; -				/*				channel->offset--; */ -			} -			*result = _ccc; -			return SI_RELATIVE_CUE; - -		case SCI_MIDI_RESET_ON_SUSPEND: -			_resetflag = buf[2]; -			break; - -		case SCI_MIDI_SET_POLYPHONY: -			_polyphony[midi_channel] = buf[2]; - -#if 0 -			{ -				Sci1SongIterator *self1 = (Sci1SongIterator *)this; -				int i; -				int voices = 0; -				for (i = 0; i < self1->_numChannels; i++) { -					voices += _polyphony[i]; -				} - -				printf("SET_POLYPHONY(%d, %d) for a total of %d voices\n", midi_channel, buf[2], voices); -				printf("[iterator] DEBUG: Polyphony = [ "); -				for (i = 0; i < self1->_numChannels; i++) -					printf("%d ", _polyphony[i]); -				printf("]\n"); -				printf("[iterator] DEBUG: Importance = [ "); -				printf("]\n"); -			} -#endif -			break; - -		case SCI_MIDI_SET_REVERB: -			break; - -		case SCI_MIDI_CHANNEL_MUTE: -			warning("CHANNEL_MUTE(%d, %d)", midi_channel, buf[2]); -			break; - -		case SCI_MIDI_HOLD: { -			// Safe cast: This controller is only used in SCI1 -			Sci1SongIterator *self1 = (Sci1SongIterator *)this; - -			if (buf[2] == self1->_hold) { -				channel->offset = channel->initial_offset; -				channel->state = SI_STATE_COMMAND; -				channel->total_timepos = 0; - -				self1->_numLoopedChannels = self1->_numActiveChannels - 1; - -				// FIXME: -				// This implementation of hold breaks getting out of the -				// limo when visiting the airport near the start of LSL5. -				// It seems like all channels should be reset here somehow, -				// but not sure how. -				// Forcing all channel offsets to 0 seems to fix the hang, -				// but somehow slows the exit sequence down to take 20 seconds -				// instead of about 3. - -				return SI_LOOP; -			} - -			break; -		} -		case 0x04: /* UNKNOWN NYI (happens in LSL2 gameshow) */ -		case 0x46: /* UNKNOWN NYI (happens in LSL3 binoculars) */ -		case 0x61: /* UNKNOWN NYI (special for AdLib? Iceman) */ -		case 0x73: /* UNKNOWN NYI (happens in Hoyle) */ -		case 0xd1: /* UNKNOWN NYI (happens in KQ4 when riding the unicorn) */ -			return /* Execute next command */ -			    nextCommand(buf, result); - -		case 0x01: /* modulation */ -		case 0x07: /* volume */ -		case 0x0a: /* panpot */ -		case 0x0b: /* expression */ -		case 0x40: /* hold */ -		case 0x79: /* reset all */ -			/* No special treatment neccessary */ -			break; - -		} -		return 0; - -	} else { -#if 0 -		/* Perform remapping, if neccessary */ -		if (cmd != SCI_MIDI_SET_SIGNAL -				&& cmd < 0xf0) { /* Not a generic command */ -			int chan = cmd & 0xf; -			int op = cmd & 0xf0; - -			chan = channel_remap[chan]; -			buf[0] = chan | op; -		} -#endif - -		/* Process as normal MIDI operation */ -		return 0; -	} -} - -int BaseSongIterator::processMidi(byte *buf, int *result, -	SongIteratorChannel *channel, int flags) { -	CHECK_FOR_END(0); - -	switch (channel->state) { - -	case SI_STATE_PCM: { -		if (_data[channel->offset] == 0 -		        && _data[channel->offset + 1] == SCI_MIDI_EOT) -			/* Fake one extra tick to trick the interpreter into not killing the song iterator right away */ -			channel->state = SI_STATE_PCM_MAGIC_DELTA; -		else -			channel->state = SI_STATE_DELTA_TIME; -		return SI_PCM; -	} - -	case SI_STATE_PCM_MAGIC_DELTA: { -		int rate; -		int offset; -		uint size; -		int delay; -		if (_sci0_get_pcm_data((Sci0SongIterator *)this, &rate, &offset, &size)) -			return SI_FINISHED; /* 'tis broken */ -		channel->state = SI_STATE_FINISHED; -		delay = (size * 50 + rate - 1) / rate; /* number of ticks to completion*/ - -		debugC(2, kDebugLevelSound, "delaying %d ticks", delay); -		return delay; -	} - -	case SI_STATE_UNINITIALISED: -		warning("Attempt to read command from uninitialized iterator"); -		init(); -		return nextCommand(buf, result); - -	case SI_STATE_FINISHED: -		return SI_FINISHED; - -	case SI_STATE_DELTA_TIME: { -		int offset; -		int ticks = _parse_ticks(_data.begin() + channel->offset, -		                         &offset, -		                         _data.size() - channel->offset); - -		channel->offset += offset; -		channel->delay += ticks; -		channel->timepos_increment = ticks; - -		CHECK_FOR_END(0); - -		channel->state = SI_STATE_COMMAND; - -		if (ticks) -			return ticks; -	} - -	/* continute otherwise... */ - -	case SI_STATE_COMMAND: { -		int retval; -		channel->total_timepos += channel->timepos_increment; -		channel->timepos_increment = 0; - -		retval = parseMidiCommand(buf, result, channel, flags); - -		if (retval == SI_FINISHED) { -			if (_numActiveChannels) -				--(_numActiveChannels); -#ifdef DEBUG_DECODING -			fprintf(stderr, "%s L%d: (%p):%d Finished channel, %d channels left\n", -			        __FILE__, __LINE__, this, channel->id, -			        _numActiveChannels); -#endif -			/* If we still have channels left... */ -			if (_numActiveChannels) { -				return nextCommand(buf, result); -			} - -			/* Otherwise, we have reached the end */ -			_loops = 0; -		} - -		return retval; -	} - -	default: -		error("Invalid iterator state %d", channel->state); -		return SI_FINISHED; -	} -} - -int Sci0SongIterator::nextCommand(byte *buf, int *result) { -	return processMidi(buf, result, &_channel, PARSE_FLAG_PARAMETRIC_CUE); -} - -static int _sci0_header_magic_p(byte *data, int offset, int size) { -	if (offset + 0x10 > size) -		return 0; -	return (data[offset] == 0x1a) -	    && (data[offset + 1] == 0x00) -	    && (data[offset + 2] == 0x01) -	    && (data[offset + 3] == 0x00); -} - - -static int _sci0_get_pcm_data(Sci0SongIterator *self, -	int *rate, int *xoffset, uint *xsize) { -	int tries = 2; -	bool found_it = false; -	byte *pcm_data; -	int size; -	uint offset = SCI0_MIDI_OFFSET; - -	if (self->_data[0] != 2) -		return 1; -	/* No such luck */ - -	while ((tries--) && (offset < self->_data.size()) && (!found_it)) { -		// Search through the garbage manually -		// FIXME: Replace offset by an iterator -		Common::Array<byte>::iterator iter = Common::find(self->_data.begin() + offset, self->_data.end(), SCI0_END_OF_SONG); - -		if (iter == self->_data.end()) { -			warning("Playing unterminated song"); -			return 1; -		} - -		// add one to move it past the END_OF_SONG marker -		iter++; -		offset = iter - self->_data.begin();	// FIXME - - -		if (_sci0_header_magic_p(self->_data.begin(), offset, self->_data.size())) -			found_it = true; -	} - -	if (!found_it) { -		warning("Song indicates presence of PCM, but" -		        " none found (finally at offset %04x)", offset); - -		return 1; -	} - -	pcm_data = self->_data.begin() + offset; - -	size = READ_LE_UINT16(pcm_data + SCI0_PCM_SIZE_OFFSET); - -	/* Two of the format parameters are fixed by design: */ -	*rate = READ_LE_UINT16(pcm_data + SCI0_PCM_SAMPLE_RATE_OFFSET); - -	if (offset + SCI0_PCM_DATA_OFFSET + size != self->_data.size()) { -		int d = offset + SCI0_PCM_DATA_OFFSET + size - self->_data.size(); - -		warning("PCM advertizes %d bytes of data, but %d" -		        " bytes are trailing in the resource", -		        size, self->_data.size() - (offset + SCI0_PCM_DATA_OFFSET)); - -		if (d > 0) -			size -= d; /* Fix this */ -	} - -	*xoffset = offset; -	*xsize = size; - -	return 0; -} - -static Audio::AudioStream *makeStream(byte *data, int size, int rate) { -	debugC(2, kDebugLevelSound, "Playing PCM data of size %d, rate %d", size, rate); - -	// Duplicate the data -	byte *sound = (byte *)malloc(size); -	memcpy(sound, data, size); - -	// Convert stream format flags -	int flags = Audio::FLAG_UNSIGNED; -	return Audio::makeRawStream(sound, size, rate, flags); -} - -Audio::AudioStream *Sci0SongIterator::getAudioStream() { -	int rate; -	int offset; -	uint size; -	if (_sci0_get_pcm_data(this, &rate, &offset, &size)) -		return NULL; - -	_channel.state = SI_STATE_FINISHED; /* Don't play both PCM and music */ - -	return makeStream(_data.begin() + offset + SCI0_PCM_DATA_OFFSET, size, rate); -} - -SongIterator *Sci0SongIterator::handleMessage(Message msg) { -	if (msg._class == _SIMSG_BASE) { -		switch (msg._type) { - -		case _SIMSG_BASEMSG_PRINT: -			print_tabs_id(msg._arg.i, ID); -			debugC(2, kDebugLevelSound, "SCI0: dev=%d, active-chan=%d, size=%d, loops=%d", -			        _deviceId, _numActiveChannels, _data.size(), _loops); -			break; - -		case _SIMSG_BASEMSG_SET_LOOPS: -			_loops = msg._arg.i; -			break; - -		case _SIMSG_BASEMSG_STOP: { -			songit_id_t sought_id = msg.ID; - -			if (sought_id == ID) -				_channel.state = SI_STATE_FINISHED; -			break; -		} - -		case _SIMSG_BASEMSG_SET_PLAYMASK: { -			int i; -			_deviceId = msg._arg.i; - -			/* Set all but the rhytm channel mask bits */ -			_channel.playmask &= ~(1 << MIDI_RHYTHM_CHANNEL); - -			for (i = 0; i < MIDI_CHANNELS; i++) -				if (_data[2 + (i << 1)] & _deviceId -				        && i != MIDI_RHYTHM_CHANNEL) -					_channel.playmask |= (1 << i); -		} -		break; - -		case _SIMSG_BASEMSG_SET_RHYTHM: -			_channel.playmask &= ~(1 << MIDI_RHYTHM_CHANNEL); -			if (msg._arg.i) -				_channel.playmask |= (1 << MIDI_RHYTHM_CHANNEL); -			break; - -		case _SIMSG_BASEMSG_SET_FADE: { -			fade_params_t *fp = (fade_params_t *) msg._arg.p; -			fade.action = fp->action; -			fade.final_volume = fp->final_volume; -			fade.ticks_per_step = fp->ticks_per_step; -			fade.step_size = fp->step_size; -			break; -		} - -		default: -			return NULL; -		} - -		return this; -	} -	return NULL; -} - -int Sci0SongIterator::getTimepos() { -	return _channel.total_timepos; -} - -Sci0SongIterator::Sci0SongIterator(byte *data, uint size, songit_id_t id) - : BaseSongIterator(data, size, id) { -	channel_mask = 0xffff;	// Allocate all channels by default -	_channel.state = SI_STATE_UNINITIALISED; - -	for (int i = 0; i < MIDI_CHANNELS; i++) -		_polyphony[i] = data[1 + (i << 1)]; - -	init(); -} - -void Sci0SongIterator::init() { -	fade.action = FADE_ACTION_NONE; -	_resetflag = 0; -	_loops = 0; -	priority = 0; - -	_ccc = 0; /* Reset cumulative cue counter */ -	_numActiveChannels = 1; -	_channel.init(0, SCI0_MIDI_OFFSET, _data.size()); -	_channel.resetSynthChannels(); - -	if (_data[0] == 2) /* Do we have an embedded PCM? */ -		_channel.state = SI_STATE_PCM; -} - -SongIterator *Sci0SongIterator::clone(int delta) { -	Sci0SongIterator *newit = new Sci0SongIterator(*this); -	return newit; -} - - -/***************************/ -/*-- SCI1 song iterators --*/ -/***************************/ - -int Sci1SongIterator::initSample(const int offset) { -	Sci1Sample sample; -	int rate; -	int length; -	int begin; -	int end; - -	CHECK_FOR_END_ABSOLUTE((uint)offset + 10); -	if (_data[offset + 1] != 0) -		warning("[iterator-1] In sample at offset 0x04x: Byte #1 is %02x instead of zero", -		          _data[offset + 1]); - -	rate = (int16)READ_LE_UINT16(_data.begin() + offset + 2); -	length = READ_LE_UINT16(_data.begin() + offset + 4); -	begin = (int16)READ_LE_UINT16(_data.begin() + offset + 6); -	end = (int16)READ_LE_UINT16(_data.begin() + offset + 8); - -	CHECK_FOR_END_ABSOLUTE((uint)(offset + 10 + length)); - -	sample.delta = begin; -	sample.size = length; -	sample._data = _data.begin() + offset + 10; - -#ifdef DEBUG_VERBOSE -	fprintf(stderr, "[SAMPLE] %x/%x/%x/%x l=%x\n", -	        offset + 10, begin, end, _data.size(), length); -#endif - -	sample.rate = rate; - -	sample.announced = false; - -	/* Insert into the sample list at the right spot, keeping it sorted by delta */ -	Common::List<Sci1Sample>::iterator seeker = _samples.begin(); -	while (seeker != _samples.end() && seeker->delta < begin) -		++seeker; -	_samples.insert(seeker, sample); - -	return 0; /* Everything's fine */ -} - -int Sci1SongIterator::initSong() { -	int last_time; -	uint offset = 0; -	_numChannels = 0; -	_samples.clear(); -//	_deviceId = 0x0c; - -	if (_data[offset] == 0xf0) { -		priority = _data[offset + 1]; - -		offset += 8; -	} - -	while (_data[offset] != 0xff -	        && _data[offset] != _deviceId) { -		offset++; -		CHECK_FOR_END_ABSOLUTE(offset + 1); -		while (_data[offset] != 0xff) { -			CHECK_FOR_END_ABSOLUTE(offset + 7); -			offset += 6; -		} -		offset++; -	} - -	if (_data[offset] == 0xff) { -		warning("[iterator] Song does not support hardware 0x%02x", _deviceId); -		return 1; -	} - -	offset++; - -	while (_data[offset] != 0xff) { /* End of list? */ -		uint track_offset; -		int end; -		offset += 2; - -		CHECK_FOR_END_ABSOLUTE(offset + 4); - -		track_offset = READ_LE_UINT16(_data.begin() + offset); -		end = READ_LE_UINT16(_data.begin() + offset + 2); - -		CHECK_FOR_END_ABSOLUTE(track_offset - 1); - -		if (_data[track_offset] == 0xfe) { -			if (initSample(track_offset)) -				return 1; /* Error */ -		} else { -			/* Regular MIDI channel */ -			if (_numChannels >= MIDI_CHANNELS) { -				warning("[iterator] Song has more than %d channels, cutting them off", -				          MIDI_CHANNELS); -				break; /* Scan for remaining samples */ -			} else { -				int channel_nr = _data[track_offset] & 0xf; -				SongIteratorChannel &channel = _channels[_numChannels++]; - -				/* -				if (_data[track_offset] & 0xf0) -					printf("Channel %d has mapping bits %02x\n", -					       channel_nr, _data[track_offset] & 0xf0); -				*/ - -				// Add 2 to skip over header bytes */ -				channel.init(channel_nr, track_offset + 2, track_offset + end); -				channel.resetSynthChannels(); - -				_polyphony[_numChannels - 1] = _data[channel.offset - 1] & 15; - -				channel.playmask = ~0; /* Enable all */ -				channel_mask |= (1 << channel_nr); - -				CHECK_FOR_END_ABSOLUTE(offset + end); -			} -		} -		offset += 4; -		CHECK_FOR_END_ABSOLUTE(offset); -	} - -	/* Now ensure that sample deltas are relative to the previous sample */ -	last_time = 0; -	_numActiveChannels = _numChannels; -	_numLoopedChannels = 0; - -	for (Common::List<Sci1Sample>::iterator seeker = _samples.begin(); -			seeker != _samples.end(); ++seeker) { -		int prev_last_time = last_time; -		//printf("[iterator] Detected sample: %d Hz, %d bytes at time %d\n", -		//          seeker->format.rate, seeker->size, seeker->delta); -		last_time = seeker->delta; -		seeker->delta -= prev_last_time; -	} - -	return 0; /* Success */ -} - -int Sci1SongIterator::getSmallestDelta() const { -	int d = -1; -	for (int i = 0; i < _numChannels; i++) -		if (_channels[i].state == SI_STATE_COMMAND -		        && (d == -1 || _channels[i].delay < d)) -			d = _channels[i].delay; - -	if (!_samples.empty() && _samples.begin()->delta < d) -		return _samples.begin()->delta; -	else -		return d; -} - -void Sci1SongIterator::updateDelta(int delta) { -	if (!_samples.empty()) -		_samples.begin()->delta -= delta; - -	for (int i = 0; i < _numChannels; i++) -		if (_channels[i].state == SI_STATE_COMMAND) -			_channels[i].delay -= delta; -} - -bool Sci1SongIterator::noDeltaTime() const { -	for (int i = 0; i < _numChannels; i++) -		if (_channels[i].state == SI_STATE_DELTA_TIME) -			return false; -	return true; -} - -#define COMMAND_INDEX_NONE -1 -#define COMMAND_INDEX_PCM -2 - -int Sci1SongIterator::getCommandIndex() const { -	/* Determine the channel # of the next active event, or -1 */ -	int i; -	int base_delay = 0x7ffffff; -	int best_chan = COMMAND_INDEX_NONE; - -	for (i = 0; i < _numChannels; i++) -		if ((_channels[i].state != SI_STATE_PENDING) -		        && (_channels[i].state != SI_STATE_FINISHED))  { - -			if ((_channels[i].state == SI_STATE_DELTA_TIME) -			        && (_channels[i].delay == 0)) -				return i; -			/* First, read all unknown delta times */ - -			if (_channels[i].delay < base_delay) { -				best_chan = i; -				base_delay = _channels[i].delay; -			} -		} - -	if (!_samples.empty() && base_delay >= _samples.begin()->delta) -		return COMMAND_INDEX_PCM; - -	return best_chan; -} - - -Audio::AudioStream *Sci1SongIterator::getAudioStream() { -	Common::List<Sci1Sample>::iterator sample = _samples.begin(); -	if (sample != _samples.end() && sample->delta <= 0) { -		Audio::AudioStream *feed = makeStream(sample->_data, sample->size, sample->rate); -		_samples.erase(sample); - -		return feed; -	} else -		return NULL; -} - -int Sci1SongIterator::nextCommand(byte *buf, int *result) { - -	if (!_initialised) { -		//printf("[iterator] DEBUG: Initialising for %d\n", _deviceId); -		_initialised = true; -		if (initSong()) -			return SI_FINISHED; -	} - - -	if (_delayRemaining) { -		int delay = _delayRemaining; -		_delayRemaining = 0; -		return delay; -	} - -	int retval = 0; -	do {	 /* All delays must be processed separately */ -		int chan = getCommandIndex(); - -		if (chan == COMMAND_INDEX_NONE) { -			return SI_FINISHED; -		} - -		if (chan == COMMAND_INDEX_PCM) { - -			if (_samples.begin()->announced) { -				/* Already announced; let's discard it */ -				Audio::AudioStream *feed = getAudioStream(); -				delete feed; -			} else { -				int delay = _samples.begin()->delta; - -				if (delay) { -					updateDelta(delay); -					return delay; -				} -				/* otherwise we're touching a PCM */ -				_samples.begin()->announced = true; -				return SI_PCM; -			} -		} else { /* Not a PCM */ - -			retval = processMidi(buf, result, -			                     &(_channels[chan]), -			                     PARSE_FLAG_LOOPS_UNLIMITED); - -			if (retval == SI_LOOP) { -				_numLoopedChannels++; -				_channels[chan].state = SI_STATE_PENDING; -				_channels[chan].delay = 0; - -				if (_numLoopedChannels == _numActiveChannels) { -					int i; - -					/* Everyone's ready: Let's loop */ -					for (i = 0; i < _numChannels; i++) -						if (_channels[i].state == SI_STATE_PENDING) -							_channels[i].state = SI_STATE_DELTA_TIME; - -					_numLoopedChannels = 0; -					return SI_LOOP; -				} -			} else if (retval == SI_FINISHED) { -#ifdef DEBUG -				fprintf(stderr, "FINISHED some channel\n"); -#endif -			} else if (retval > 0) { -				int sd ; -				sd = getSmallestDelta(); - -				if (noDeltaTime() && sd) { -					/* No other channel is ready */ -					updateDelta(sd); - -					/* Only from here do we return delta times */ -					return sd; -				} -			} - -		} /* Not a PCM */ - -	} while (retval > 0); - -	return retval; -} - -SongIterator *Sci1SongIterator::handleMessage(Message msg) { -	if (msg._class == _SIMSG_BASE) { /* May extend this in the future */ -		switch (msg._type) { - -		case _SIMSG_BASEMSG_PRINT: { -			int playmask = 0; -			int i; - -			for (i = 0; i < _numChannels; i++) -				playmask |= _channels[i].playmask; - -			print_tabs_id(msg._arg.i, ID); -			debugC(2, kDebugLevelSound, "SCI1: chan-nr=%d, playmask=%04x", -			        _numChannels, playmask); -		} -		break; - -		case _SIMSG_BASEMSG_STOP: { -			songit_id_t sought_id = msg.ID; -			int i; - -			if (sought_id == ID) { -				ID = 0; - -				for (i = 0; i < _numChannels; i++) -					_channels[i].state = SI_STATE_FINISHED; -			} -			break; -		} - -		case _SIMSG_BASEMSG_SET_PLAYMASK: -			if (msg.ID == ID) { -				channel_mask = 0; - -				_deviceId = msg._arg.i; - -				if (_initialised) { -					int i; -					int toffset = -1; - -					for (i = 0; i < _numChannels; i++) -						if (_channels[i].state != SI_STATE_FINISHED -						        && _channels[i].total_timepos > toffset) { -							toffset = _channels[i].total_timepos -							          + _channels[i].timepos_increment -							          - _channels[i].delay; -						} - -					/* Find an active channel so that we can -					** get the correct time offset  */ - -					initSong(); - -					toffset -= _delayRemaining; -					_delayRemaining = 0; - -					if (toffset > 0) -						return new_fast_forward_iterator(this, toffset); -				} else { -					initSong(); -					_initialised = true; -				} - -				break; - -			} - -		case _SIMSG_BASEMSG_SET_LOOPS: -			if (msg.ID == ID) -				_loops = (msg._arg.i > 32767) ? 99 : 0; -			/* 99 is arbitrary, but we can't use '1' because of -			** the way we're testing in the decoding section.  */ -			break; - -		case _SIMSG_BASEMSG_SET_HOLD: -			_hold = msg._arg.i; -			break; -		case _SIMSG_BASEMSG_SET_RHYTHM: -			/* Ignore */ -			break; - -		case _SIMSG_BASEMSG_SET_FADE: { -			fade_params_t *fp = (fade_params_t *) msg._arg.p; -			fade.action = fp->action; -			fade.final_volume = fp->final_volume; -			fade.ticks_per_step = fp->ticks_per_step; -			fade.step_size = fp->step_size; -			break; -		} - -		default: -			warning("Unsupported command %d to SCI1 iterator", msg._type); -		} -		return this; -	} -	return NULL; -} - -Sci1SongIterator::Sci1SongIterator(byte *data, uint size, songit_id_t id) - : BaseSongIterator(data, size, id) { -	channel_mask = 0; // Defer channel allocation - -	for (int i = 0; i < MIDI_CHANNELS; i++) -		_polyphony[i] = 0; // Unknown - -	init(); -} - -void Sci1SongIterator::init() { -	fade.action = FADE_ACTION_NONE; -	_resetflag = 0; -	_loops = 0; -	priority = 0; - -	_ccc = 0; -	_deviceId = 0x00; // Default to Sound Blaster/AdLib for purposes of cue computation -	_numChannels = 0; -	_initialised = false; -	_delayRemaining = 0; -	_loops = 0; -	_hold = 0; -	memset(_polyphony, 0, sizeof(_polyphony)); -} - -Sci1SongIterator::~Sci1SongIterator() { -} - - -SongIterator *Sci1SongIterator::clone(int delta) { -	Sci1SongIterator *newit = new Sci1SongIterator(*this); -	newit->_delayRemaining = delta; -	return newit; -} - -int Sci1SongIterator::getTimepos() { -	int max = 0; -	int i; - -	for (i = 0; i < _numChannels; i++) -		if (_channels[i].total_timepos > max) -			max = _channels[i].total_timepos; - -	return max; -} - -/** - * A song iterator with the purpose of sending notes-off channel commands. - */ -class CleanupSongIterator : public SongIterator { -public: -	CleanupSongIterator(uint channels) { -		channel_mask = channels; -		ID = 17; -	} - -	int nextCommand(byte *buf, int *result); -	Audio::AudioStream *getAudioStream() { return NULL; } -	SongIterator *handleMessage(Message msg); -	int getTimepos() { return 0; } -	SongIterator *clone(int delta) { return new CleanupSongIterator(*this); } -}; - -SongIterator *CleanupSongIterator::handleMessage(Message msg) { -	if (msg._class == _SIMSG_BASEMSG_PRINT && msg._type == _SIMSG_BASEMSG_PRINT) { -		print_tabs_id(msg._arg.i, ID); -		debugC(2, kDebugLevelSound, "CLEANUP"); -	} - -	return NULL; -} - -int CleanupSongIterator::nextCommand(byte *buf, int *result) { -	/* Task: Return channel-notes-off for each channel */ -	if (channel_mask) { -		int bs = sci_ffs(channel_mask) - 1; - -		channel_mask &= ~(1 << bs); -		buf[0] = 0xb0 | bs; /* Controller */ -		buf[1] = SCI_MIDI_CHANNEL_NOTES_OFF; -		buf[2] = 0; /* Hmm... */ -		*result = 3; -		return 0; -	} else -		return SI_FINISHED; -} - -/**********************/ -/*-- Timer iterator --*/ -/**********************/ -int TimerSongIterator::nextCommand(byte *buf, int *result) { -	if (_delta) { -		int d = _delta; -		_delta = 0; -		return d; -	} -	return SI_FINISHED; -} - -SongIterator *new_timer_iterator(int delta) { -	return new TimerSongIterator(delta); -} - -/**********************************/ -/*-- Fast-forward song iterator --*/ -/**********************************/ - -int FastForwardSongIterator::nextCommand(byte *buf, int *result) { -	if (_delta <= 0) -		return SI_MORPH; /* Did our duty */ - -	while (1) { -		int rv = _delegate->nextCommand(buf, result); - -		if (rv > 0) { -			/* Subtract from the delta we want to wait */ -			_delta -= rv; - -			/* Done */ -			if (_delta < 0) -				return -_delta; -		} - -		if (rv <= 0) -			return rv; -	} -} - -Audio::AudioStream *FastForwardSongIterator::getAudioStream() { -	return _delegate->getAudioStream(); -} - -SongIterator *FastForwardSongIterator::handleMessage(Message msg) { -	if (msg._class == _SIMSG_PLASTICWRAP) { -		assert(msg._type == _SIMSG_PLASTICWRAP_ACK_MORPH); - -		if (_delta <= 0) { -			SongIterator *it = _delegate; -			delete this; -			return it; -		} - -		warning("[ff-iterator] Morphing without need"); -		return this; -	} - -	if (msg._class == _SIMSG_BASE && msg._type == _SIMSG_BASEMSG_PRINT) { -		print_tabs_id(msg._arg.i, ID); -		debugC(2, kDebugLevelSound, "FASTFORWARD:"); -		msg._arg.i++; -	} - -	// And continue with the delegate -	songit_handle_message(&_delegate, msg); - -	return NULL; -} - - -int FastForwardSongIterator::getTimepos() { -	return _delegate->getTimepos(); -} - -FastForwardSongIterator::FastForwardSongIterator(SongIterator *capsit, int delta) -	: _delegate(capsit), _delta(delta) { - -	channel_mask = capsit->channel_mask; -} - -SongIterator *FastForwardSongIterator::clone(int delta) { -	FastForwardSongIterator *newit = new FastForwardSongIterator(*this); -	newit->_delegate = _delegate->clone(delta); -	return newit; -} - -SongIterator *new_fast_forward_iterator(SongIterator *capsit, int delta) { -	if (capsit == NULL) -		return NULL; - -	FastForwardSongIterator *it = new FastForwardSongIterator(capsit, delta); -	return it; -} - - -/********************/ -/*-- Tee iterator --*/ -/********************/ - - -static void song_iterator_add_death_listener(SongIterator *it, TeeSongIterator *client) { -	for (int i = 0; i < SONGIT_MAX_LISTENERS; ++i) { -		if (it->_deathListeners[i] == 0) { -			it->_deathListeners[i] = client; -			return; -		} -	} -	error("FATAL: Too many death listeners for song iterator"); -} - -static void song_iterator_remove_death_listener(SongIterator *it, TeeSongIterator *client) { -	for (int i = 0; i < SONGIT_MAX_LISTENERS; ++i) { -		if (it->_deathListeners[i] == client) { -			it->_deathListeners[i] = 0; -			return; -		} -	} -} - -static void song_iterator_transfer_death_listeners(SongIterator *it, SongIterator *it_from) { -	for (int i = 0; i < SONGIT_MAX_LISTENERS; ++i) { -		if (it_from->_deathListeners[i]) -			song_iterator_add_death_listener(it, it_from->_deathListeners[i]); -		it_from->_deathListeners[i] = 0; -	} -} - -static void songit_tee_death_notification(TeeSongIterator *self, SongIterator *corpse) { -	if (corpse == self->_children[TEE_LEFT].it) { -		self->_status &= ~TEE_LEFT_ACTIVE; -		self->_children[TEE_LEFT].it = NULL; -	} else if (corpse == self->_children[TEE_RIGHT].it) { -		self->_status &= ~TEE_RIGHT_ACTIVE; -		self->_children[TEE_RIGHT].it = NULL; -	} else { -		error("songit_tee_death_notification() failed: Breakpoint in %s, line %d", __FILE__, __LINE__); -	} -} - -TeeSongIterator::TeeSongIterator(SongIterator *left, SongIterator *right) { -	int i; -	int firstfree = 1; /* First free channel */ -	int incomplete_map = 0; - -	_readyToMorph = false; -	_status = TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE; - -	_children[TEE_LEFT].it = left; -	_children[TEE_RIGHT].it = right; - -	/* Default to lhs channels */ -	channel_mask = left->channel_mask; -	for (i = 0; i < 16; i++) -		if (channel_mask & (1 << i) & right->channel_mask -		        && (i != MIDI_RHYTHM_CHANNEL) /* Share rhythm */) { /*conflict*/ -			while ((firstfree == MIDI_RHYTHM_CHANNEL) -			        /* Either if it's the rhythm channel or if it's taken */ -			        || (firstfree < MIDI_CHANNELS -			            && ((1 << firstfree) & channel_mask))) -				++firstfree; - -			if (firstfree == MIDI_CHANNELS) { -				incomplete_map = 1; -				//warning("[songit-tee <%08lx,%08lx>] Could not remap right channel #%d: Out of channels", -				//        left->ID, right->ID, i); -			} else { -				_children[TEE_RIGHT].it->channel_remap[i] = firstfree; - -				channel_mask |= (1 << firstfree); -			} -		} -#ifdef DEBUG_TEE_ITERATOR -	if (incomplete_map) { -		int c; -		fprintf(stderr, "[songit-tee <%08lx,%08lx>] Channels:" -		        " %04x <- %04x | %04x\n", -		        left->ID, right->ID, -		        channel_mask, -		        left->channel_mask, right->channel_mask); -		for (c = 0 ; c < 2; c++) -			for (i = 0 ; i < 16; i++) -				fprintf(stderr, "  map [%d][%d] -> %d\n", -				        c, i, _children[c].it->channel_remap[i]); -	} -#endif - - -	song_iterator_add_death_listener(left, this); -	song_iterator_add_death_listener(right, this); -} - -TeeSongIterator::~TeeSongIterator() { -	// When we die, remove any listeners from our children -	if (_children[TEE_LEFT].it) { -		song_iterator_remove_death_listener(_children[TEE_LEFT].it, this); -	} - -	if (_children[TEE_RIGHT].it) { -		song_iterator_remove_death_listener(_children[TEE_RIGHT].it, this); -	} -} - - -int TeeSongIterator::nextCommand(byte *buf, int *result) { -	static const int ready_masks[2] = {TEE_LEFT_READY, TEE_RIGHT_READY}; -	static const int active_masks[2] = {TEE_LEFT_ACTIVE, TEE_RIGHT_ACTIVE}; -	static const int pcm_masks[2] = {TEE_LEFT_PCM, TEE_RIGHT_PCM}; -	int i; -	int retid; - -#ifdef DEBUG_TEE_ITERATOR -	fprintf(stderr, "[Tee] %02x\n", _status); -#endif - -	if (!(_status & (TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE))) -		/* None is active? */ -		return SI_FINISHED; - -	if (_readyToMorph) -		return SI_MORPH; - -	if ((_status & (TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE)) -	        != (TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE)) { -		/* Not all are is active? */ -		int which = 0; -#ifdef DEBUG_TEE_ITERATOR -		fprintf(stderr, "\tRequesting transformation...\n"); -#endif -		if (_status & TEE_LEFT_ACTIVE) -			which = TEE_LEFT; -		else if (_status & TEE_RIGHT_ACTIVE) -			which = TEE_RIGHT; -		memcpy(buf, _children[which].buf, sizeof(buf)); -		*result = _children[which].result; -		_readyToMorph = true; -		return _children[which].retval; -	} - -	/* First, check for unreported PCMs */ -	for (i = TEE_LEFT; i <= TEE_RIGHT; i++) -		if ((_status & (ready_masks[i] | pcm_masks[i])) -		        == (ready_masks[i] | pcm_masks[i])) { -			_status &= ~ready_masks[i]; -			return SI_PCM; -		} - -	for (i = TEE_LEFT; i <= TEE_RIGHT; i++) -		if (!(_status & ready_masks[i])) { - -			/* Buffers aren't ready yet */ -			_children[i].retval = -			    songit_next(&(_children[i].it), -			                _children[i].buf, -			                &(_children[i].result), -			                IT_READER_MASK_ALL -			                | IT_READER_MAY_FREE -			                | IT_READER_MAY_CLEAN); - -			_status |= ready_masks[i]; -#ifdef DEBUG_TEE_ITERATOR -			fprintf(stderr, "\t Must check %d: %d\n", i, _children[i].retval); -#endif - -			if (_children[i].retval == SI_ABSOLUTE_CUE || -			        _children[i].retval == SI_RELATIVE_CUE) -				return _children[i].retval; -			if (_children[i].retval == SI_FINISHED) { -				_status &= ~active_masks[i]; -				/* Recurse to complete */ -#ifdef DEBUG_TEE_ITERATOR -				fprintf(stderr, "\t Child %d signalled completion, recursing w/ status %02x\n", i, _status); -#endif -				return nextCommand(buf, result); -			} else if (_children[i].retval == SI_PCM) { -				_status |= pcm_masks[i]; -				_status &= ~ready_masks[i]; -				return SI_PCM; -			} -		} - - -	/* We've already handled PCM, MORPH and FINISHED, CUEs & LOOP remain */ - -	retid = TEE_LEFT; -	if ((_children[TEE_LEFT].retval > 0) -	        /* Asked to delay */ -	        && (_children[TEE_RIGHT].retval <= _children[TEE_LEFT].retval)) -		/* Is not delaying or not delaying as much */ -		retid = TEE_RIGHT; - -#ifdef DEBUG_TEE_ITERATOR -	fprintf(stderr, "\tl:%d / r:%d / chose %d\n", -	        _children[TEE_LEFT].retval, _children[TEE_RIGHT].retval, retid); -#endif - -	/* Adjust delta times */ -	if (_children[retid].retval > 0 -	        && _children[1-retid].retval > 0) { -		if (_children[1-retid].retval -		        == _children[retid].retval) -			/* If both _children wait the same amount of time, -			** we have to re-fetch commands from both  */ -			_status &= ~ready_masks[1-retid]; -		else -			/* If they don't, we can/must re-use the other -			** child's delay time  */ -			_children[1-retid].retval -			-= _children[retid].retval; -	} - -	_status &= ~ready_masks[retid]; -	memcpy(buf, _children[retid].buf, sizeof(buf)); -	*result = _children[retid].result; - -	return _children[retid].retval; -} - -Audio::AudioStream *TeeSongIterator::getAudioStream() { -	static const int pcm_masks[2] = {TEE_LEFT_PCM, TEE_RIGHT_PCM}; -	int i; - -	for (i = TEE_LEFT; i <= TEE_RIGHT; i++) -		if (_status & pcm_masks[i]) { -			_status &= ~pcm_masks[i]; -			return _children[i].it->getAudioStream(); -		} - -	return NULL; // No iterator -} - -SongIterator *TeeSongIterator::handleMessage(Message msg) { -	if (msg._class == _SIMSG_PLASTICWRAP) { -		assert(msg._type == _SIMSG_PLASTICWRAP_ACK_MORPH); - -		SongIterator *old_it; -		if (!(_status & (TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE))) { -			delete this; -			return NULL; -		} else if (!(_status & TEE_LEFT_ACTIVE)) { -			delete _children[TEE_LEFT].it; -			_children[TEE_LEFT].it = 0; -			old_it = _children[TEE_RIGHT].it; -			song_iterator_remove_death_listener(old_it, this); -			song_iterator_transfer_death_listeners(old_it, this); -			delete this; -			return old_it; -		} else if (!(_status & TEE_RIGHT_ACTIVE)) { -			delete _children[TEE_RIGHT].it; -			_children[TEE_RIGHT].it = 0; -			old_it = _children[TEE_LEFT].it; -			song_iterator_remove_death_listener(old_it, this); -			song_iterator_transfer_death_listeners(old_it, this); -			delete this; -			return old_it; -		} - -		warning("[tee-iterator] Morphing without need"); -		return this; -	} - -	if (msg._class == _SIMSG_BASE && msg._type == _SIMSG_BASEMSG_PRINT) { -		print_tabs_id(msg._arg.i, ID); -		debugC(2, kDebugLevelSound, "TEE:"); -		msg._arg.i++; -	} - -	// And continue with the children -	if (_children[TEE_LEFT].it) -		songit_handle_message(&(_children[TEE_LEFT].it), msg); -	if (_children[TEE_RIGHT].it) -		songit_handle_message(&(_children[TEE_RIGHT].it), msg); - -	return NULL; -} - -void TeeSongIterator::init() { -	_status = TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE; -	_children[TEE_LEFT].it->init(); -	_children[TEE_RIGHT].it->init(); -} - -SongIterator *TeeSongIterator::clone(int delta) { -	TeeSongIterator *newit = new TeeSongIterator(*this); - -	if (_children[TEE_LEFT].it) -		newit->_children[TEE_LEFT].it = _children[TEE_LEFT].it->clone(delta); -	if (_children[TEE_RIGHT].it) -		newit->_children[TEE_RIGHT].it = _children[TEE_RIGHT].it->clone(delta); - -	return newit; -} - - -/*************************************/ -/*-- General purpose functionality --*/ -/*************************************/ - -int songit_next(SongIterator **it, byte *buf, int *result, int mask) { -	int retval; - -	if (!*it) -		return SI_FINISHED; - -	do { -		retval = (*it)->nextCommand(buf, result); -		if (retval == SI_MORPH) { -			debugC(2, kDebugLevelSound, "  Morphing %p (stored at %p)", (void *)*it, (void *)it); -			if (!SIMSG_SEND((*it), SIMSG_ACK_MORPH)) { -				error("SI_MORPH failed. Breakpoint in %s, line %d", __FILE__, __LINE__); -			} else -				debugC(2, kDebugLevelSound, "SI_MORPH successful"); -		} - -		if (retval == SI_FINISHED) -			debugC(2, kDebugLevelSound, "[song-iterator] Song finished. mask = %04x, cm=%04x", -			        mask, (*it)->channel_mask); -		if (retval == SI_FINISHED -		        && (mask & IT_READER_MAY_CLEAN) -		        && (*it)->channel_mask) { /* This last test will fail -					       ** with a terminated -					       ** cleanup iterator */ -			int channel_mask = (*it)->channel_mask; - -			SongIterator *old_it = *it; -			*it = new CleanupSongIterator(channel_mask); -			for(uint i = 0; i < MIDI_CHANNELS; i++) -				(*it)->channel_remap[i] = old_it->channel_remap[i]; -			song_iterator_transfer_death_listeners(*it, old_it); -			if (mask & IT_READER_MAY_FREE) -				delete old_it; -			retval = -9999; /* Continue */ -		} -	} while (!(  /* Until one of the following holds */ -	             (retval > 0 && (mask & IT_READER_MASK_DELAY)) -	             || (retval == 0 && (mask & IT_READER_MASK_MIDI)) -	             || (retval == SI_LOOP && (mask & IT_READER_MASK_LOOP)) -	             || (retval == SI_ABSOLUTE_CUE && -	                 (mask & IT_READER_MASK_CUE)) -	             || (retval == SI_RELATIVE_CUE && -	                 (mask & IT_READER_MASK_CUE)) -	             || (retval == SI_PCM && (mask & IT_READER_MASK_PCM)) -	             || (retval == SI_FINISHED) -	         )); - -	if (retval == SI_FINISHED && (mask & IT_READER_MAY_FREE)) { -		delete *it; -		*it = NULL; -	} - -	return retval; -} - -SongIterator::SongIterator() { -	ID = 0; -	channel_mask = 0; -	fade.action = FADE_ACTION_NONE; -	priority = 0; -	memset(_deathListeners, 0, sizeof(_deathListeners)); - -	// By default, don't remap -	for (uint i = 0; i < 16; i++) -		channel_remap[i] = i; -} - -SongIterator::SongIterator(const SongIterator &si) { -	ID = si.ID; -	channel_mask = si.channel_mask; -	fade = si.fade; -	priority = si.priority; -	memset(_deathListeners, 0, sizeof(_deathListeners)); - -	for (uint i = 0; i < 16; i++) -		channel_remap[i] = si.channel_remap[i]; -} - - -SongIterator::~SongIterator() { -	for (int i = 0; i < SONGIT_MAX_LISTENERS; ++i) -		if (_deathListeners[i]) -			songit_tee_death_notification(_deathListeners[i], this); -} - -SongIterator *songit_new(byte *data, uint size, SongIteratorType type, songit_id_t id) { -	BaseSongIterator *it; - -	if (!data || size < 22) { -		warning("Attempt to instantiate song iterator for null song data"); -		return NULL; -	} - - -	switch (type) { -	case SCI_SONG_ITERATOR_TYPE_SCI0: -		it = new Sci0SongIterator(data, size, id); -		break; - -	case SCI_SONG_ITERATOR_TYPE_SCI1: -		it = new Sci1SongIterator(data, size, id); -		break; - -	default: -		/**-- Invalid/unsupported sound resources --**/ -		warning("Attempt to instantiate invalid/unknown song iterator type %d", type); -		return NULL; -	} - -	return it; -} - -int songit_handle_message(SongIterator **it_reg_p, SongIterator::Message msg) { -	SongIterator *it = *it_reg_p; -	SongIterator *newit; - -	newit = it->handleMessage(msg); - -	if (!newit) -		return 0; /* Couldn't handle */ - -	*it_reg_p = newit; /* Might have self-morphed */ -	return 1; -} - -SongIterator *sfx_iterator_combine(SongIterator *it1, SongIterator *it2) { -	if (it1 == NULL) -		return it2; -	if (it2 == NULL) -		return it1; - -	/* Both are non-NULL: */ -	return new TeeSongIterator(it1, it2); -} - -} // End of namespace Sci - -#endif	// USE_OLD_MUSIC_FUNCTIONS diff --git a/engines/sci/sound/iterator/iterator.h b/engines/sci/sound/iterator/iterator.h deleted file mode 100644 index e5c8f50702..0000000000 --- a/engines/sci/sound/iterator/iterator.h +++ /dev/null @@ -1,326 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/* Song iterator declarations */ - -#ifndef SCI_SFX_SFX_ITERATOR_H -#define SCI_SFX_SFX_ITERATOR_H - -#include "sci/sci.h"	// for USE_OLD_MUSIC_FUNCTIONS - -#ifdef USE_OLD_MUSIC_FUNCTIONS -#include "sci/sound/drivers/mididriver.h" - -namespace Audio { -	class AudioStream; -} - -namespace Sci { - -enum SongIteratorStatus { -	SI_FINISHED = -1,		/**< Song finished playing */ -	SI_LOOP = -2,			/**< Song just looped */ -	SI_ABSOLUTE_CUE = -3,	/**< Found a song cue (absolute) */ -	SI_RELATIVE_CUE = -4,	/**< Found a song cue (relative) */ -	SI_PCM = -5,			/**< Found a PCM */ -	SI_IGNORE = -6,			/**< This event got edited out by the remapper */ -	SI_MORPH = -255			/**< Song iterator requested self-morph. */ -}; - -#define FADE_ACTION_NONE              0 -#define FADE_ACTION_FADE_AND_STOP     1 -#define FADE_ACTION_FADE_AND_CONT     2 - -struct fade_params_t { -	int ticks_per_step; -	int final_volume; -	int step_size; -	int action; -}; - -/* Helper defs for messages */ -enum { -	_SIMSG_BASE, /* Any base decoder */ -	_SIMSG_PLASTICWRAP  /* Any "Plastic" (discardable) wrapper decoder */ -}; - -/* Base messages */ -enum { -	_SIMSG_BASEMSG_SET_LOOPS, /* Set loops */ -	_SIMSG_BASEMSG_SET_PLAYMASK, /* Set the current playmask for filtering */ -	_SIMSG_BASEMSG_SET_RHYTHM, /* Activate/deactivate rhythm channel */ -	_SIMSG_BASEMSG_ACK_MORPH, /* Acknowledge self-morph */ -	_SIMSG_BASEMSG_STOP, /* Stop iterator */ -	_SIMSG_BASEMSG_PRINT, /* Print self to stderr, after printing param1 tabs */ -	_SIMSG_BASEMSG_SET_HOLD, /* Set value of hold parameter to expect */ -	_SIMSG_BASEMSG_SET_FADE /* Set fade parameters */ -}; - -/* "Plastic" (discardable) wrapper messages */ -enum { -	_SIMSG_PLASTICWRAP_ACK_MORPH = _SIMSG_BASEMSG_ACK_MORPH /* Acknowledge self-morph */ -}; - -/* Messages */ -#define SIMSG_SET_LOOPS(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_LOOPS,(x) -#define SIMSG_SET_PLAYMASK(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_PLAYMASK,(x) -#define SIMSG_SET_RHYTHM(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_RHYTHM,(x) -#define SIMSG_ACK_MORPH _SIMSG_PLASTICWRAP,_SIMSG_PLASTICWRAP_ACK_MORPH,0 -#define SIMSG_STOP _SIMSG_BASE,_SIMSG_BASEMSG_STOP,0 -#define SIMSG_PRINT(indentation) _SIMSG_BASE,_SIMSG_BASEMSG_PRINT,(indentation) -#define SIMSG_SET_HOLD(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_HOLD,(x) - -/* Message transmission macro: Takes song reference, message reference */ -#define SIMSG_SEND(o, m) songit_handle_message(&(o), SongIterator::Message((o)->ID, m)) -#define SIMSG_SEND_FADE(o, m) songit_handle_message(&(o), SongIterator::Message((o)->ID, _SIMSG_BASE, _SIMSG_BASEMSG_SET_FADE, m)) - -typedef unsigned long songit_id_t; - - -#define SONGIT_MAX_LISTENERS 2 - -class TeeSongIterator; - -class SongIterator { -public: -	struct Message { -		songit_id_t ID; -		uint _class; /* Type of iterator supposed to receive this */ -		uint _type; -		union { -			uint i; -			void *p; -		} _arg; - -		Message() : ID(0), _class(0xFFFF), _type(0xFFFF) {} - -		/** -		 * Create a song iterator message. -		 * -		 * @param id: song ID the message is targeted to -		 * @param recipient_class: Message recipient class -		 * @param type	message type -		 * @param a		argument -		 * -		 * @note You should only use this with the SIMSG_* macros -		 */ -		Message(songit_id_t id, int recipient_class, int type, int a) -			: ID(id), _class(recipient_class), _type(type) { -			_arg.i = a; -		} - -		/** -		 * Create a song iterator message, wherein the first parameter is a pointer. -		 * -		 * @param id: song ID the message is targeted to -		 * @param recipient_class: Message recipient class -		 * @param type	message type -		 * @param a		argument -		 * -		 * @note You should only use this with the SIMSG_* macros -		 */ -		Message(songit_id_t id, int recipient_class, int type, void *a) -			: ID(id), _class(recipient_class), _type(type) { -			_arg.p = a; -		} -	}; - -public: -	songit_id_t ID; -	uint16 channel_mask; /* Bitmask of all channels this iterator will use */ -	fade_params_t fade; -	int priority; - -	/* Death listeners */ -	/* These are not reset during initialisation */ -	TeeSongIterator *_deathListeners[SONGIT_MAX_LISTENERS]; - -	/* See songit_* for the constructor and non-virtual member functions */ - -	byte channel_remap[MIDI_CHANNELS]; ///< Remapping for channels - -public: -	SongIterator(); -	SongIterator(const SongIterator &); -	virtual ~SongIterator(); - -	/** -	 * Resets/initializes the sound iterator. -	 */ -	virtual void init() {} - -	/** -	 * Reads the next MIDI operation _or_ delta time. -	 * @param buf		The buffer to write to (needs to be able to store at least 4 bytes) -	 * @param result	Number of bytes written to the buffer -	 *                   (equals the number of bytes that need to be passed -	 *                   to the lower layers) for 0, the cue value for SI_CUE, -	 *                   or the number of loops remaining for SI_LOOP. -	 * @return zero if a MIDI operation was written, SI_FINISHED -	 *                   if the song has finished playing, SI_LOOP if looping -	 *                   (after updating the loop variable), SI_CUE if we found -	 *                   a cue, SI_PCM if a PCM was found, or the number of ticks -	 *                   to wait before this function should be called next. -	 * -	 * @note	If SI_PCM is returned, get_pcm() may be used to retrieve the associated -	 * PCM, but this must be done before any subsequent calls to next(). -	 * -	 * @todo	The actual buffer size should either be specified or passed in, so that -	 *			we can detect buffer overruns. -	 */ -	virtual int nextCommand(byte *buf, int *result) = 0; - -	/** -	 Checks for the presence of a pcm sample. -	 * @return NULL if no PCM data was found, an AudioStream otherwise. -	 */ -	virtual Audio::AudioStream *getAudioStream() = 0; - -	/** -	 * Handles a message to the song iterator. -	 * @param msg	the message to handle -	 * @return NULL if the message was not understood, -	 *             this if the message could be handled, or a new song iterator -	 *             if the current iterator had to be morphed (but the message could -	 *             still be handled) -	 * -	 * @note This function is not supposed to be called directly; use -	 * songit_handle_message() instead. It should not recurse, since songit_handle_message() -	 * takes care of that and makes sure that its delegate received the message (and -	 * was morphed) before self. -	 */ -	virtual SongIterator *handleMessage(Message msg) = 0; - -	/** -	 * Gets the song position to store in a savegame. -	 */ -	virtual int getTimepos() = 0; - -	/** -	 * Clone this song iterator. -	 * @param delta		number of ticks that still need to elapse until the -	 * 					next item should be read from the song iterator -	 */ -	virtual SongIterator *clone(int delta) = 0; - - -private: -	// Make the assignment operator unreachable, just in case... -	SongIterator& operator=(const SongIterator&); -}; - - -/********************************/ -/*-- Song iterator operations --*/ -/********************************/ - -enum SongIteratorType { -	SCI_SONG_ITERATOR_TYPE_SCI0 = 0, -	SCI_SONG_ITERATOR_TYPE_SCI1 = 1 -}; - -#define IT_READER_MASK_MIDI	(1 << 0) -#define IT_READER_MASK_DELAY	(1 << 1) -#define IT_READER_MASK_LOOP	(1 << 2) -#define IT_READER_MASK_CUE	(1 << 3) -#define IT_READER_MASK_PCM	(1 << 4) -#define IT_READER_MAY_FREE	(1 << 10) /* Free SI_FINISHED iterators */ -#define IT_READER_MAY_CLEAN	(1 << 11) -/* MAY_CLEAN: May instantiate cleanup iterators -** (use for players; this closes open channels at the end of a song) */ - -#define IT_READER_MASK_ALL (  IT_READER_MASK_MIDI	\ -			    | IT_READER_MASK_DELAY	\ -			    | IT_READER_MASK_LOOP	\ -			    | IT_READER_MASK_CUE	\ -			    | IT_READER_MASK_PCM ) - -/* Convenience wrapper around it->next -** Parameters: (SongIterator **it) Reference to the iterator to access -**             (byte *) buf: The buffer to write to (needs to be able to -**                           store at least 4 bytes) -**             (int) mask: IT_READER_MASK options specifying the events to -**                   listen for -** Returns   : (int) zero if a MIDI operation was written, SI_FINISHED -**                   if the song has finished playing, SI_LOOP if looping -**                   (after updating the loop variable), SI_CUE if we found -**                   a cue, SI_PCM if a PCM was found, or the number of ticks -**                   to wait before this function should be called next. -**             (int) *result: Number of bytes written to the buffer -**                   (equals the number of bytes that need to be passed -**                   to the lower layers) for 0, the cue value for SI_CUE, -**                   or the number of loops remaining for SI_LOOP. -*/ -int songit_next(SongIterator **it, byte *buf, int *result, int mask); - -/* Constructs a new song iterator object -** Parameters: (byte *) data: The song data to iterate over -**             (uint) size: Number of bytes in the song -**             (int) type: One of the SCI_SONG_ITERATOR_TYPEs -**             (songit_id_t) id: An ID for addressing the song iterator -** Returns   : (SongIterator *) A newly allocated but uninitialized song -**             iterator, or NULL if 'type' was invalid or unsupported -*/ -SongIterator *songit_new(byte *data, uint size, SongIteratorType type, songit_id_t id); - -/* Constructs a new song timer iterator object -** Parameters: (int) delta: The delta after which to fire SI_FINISHED -** Returns   : (SongIterator *) A newly allocated but uninitialized song -**             iterator -*/ -SongIterator *new_timer_iterator(int delta); - -/* Handles a message to the song iterator -** Parameters: (SongIterator **): A reference to the variable storing the song iterator -** Returns   : (int) Non-zero if the message was understood -** The song iterator may polymorph as result of msg, so a writeable reference is required. -*/ -int songit_handle_message(SongIterator **it_reg, SongIterator::Message msg); - - -/* Creates a new song iterator which fast-forwards -** Parameters: (SongIterator *) it: The iterator to wrap -**             (int) delta: The number of ticks to skip -** Returns   : (SongIterator) A newly created song iterator -**                               which skips all delta times -**                               until 'delta' has been used up -*/ -SongIterator *new_fast_forward_iterator(SongIterator *it, int delta); - -/* Combines two song iterators into one -** Parameters: (sfx_iterator_t *) it1: One of the two iterators, or NULL -**             (sfx_iterator_t *) it2: The other iterator, or NULL -** Returns   : (sfx_iterator_t *) A combined iterator -** If a combined iterator is returned, it will be flagged to be allowed to -** dispose of 'it1' and 'it2', where applicable. This means that this -** call should be used by song players, but not by the core sound system -*/ -SongIterator *sfx_iterator_combine(SongIterator *it1, SongIterator *it2); - -} // End of namespace Sci - -#endif	// USE_OLD_MUSIC_FUNCTIONS - -#endif // SCI_SFX_SFX_ITERATOR_H diff --git a/engines/sci/sound/iterator/iterator_internal.h b/engines/sci/sound/iterator/iterator_internal.h deleted file mode 100644 index 5a0f0d3ec9..0000000000 --- a/engines/sci/sound/iterator/iterator_internal.h +++ /dev/null @@ -1,276 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#ifndef SCI_SFX_SFX_ITERATOR_INTERNAL -#define SCI_SFX_SFX_ITERATOR_INTERNAL - -#include "sci/sci.h"	// for USE_OLD_MUSIC_FUNCTIONS - -#ifdef USE_OLD_MUSIC_FUNCTIONS -#include "sci/sound/iterator/iterator.h" -#include "sci/sound/drivers/mididriver.h" - -#include "common/array.h" -#include "common/list.h" - -namespace Sci { - -/* Iterator types */ - -enum { -	SI_STATE_UNINITIALISED		= -1, -	SI_STATE_DELTA_TIME			= 0,	///< Now at a delta time -	SI_STATE_COMMAND			= 1,	///< Now at a MIDI operation -	SI_STATE_PENDING			= 2,	///< Pending for loop -	SI_STATE_FINISHED			= 3,	///< End of song -	SI_STATE_PCM				= 4,	///< Should report a PCM next (-> DELTA_TIME) -	SI_STATE_PCM_MAGIC_DELTA	= 5		///< Should report a ``magic'' one tick delta time next (goes on to FINISHED) -}; - -struct SongIteratorChannel { - -	int state;	///< State of this song iterator channel -	int offset;	///< Offset into the data chunk */ -	int end;	///< Last allowed byte in track */ -	int id;		///< Some channel ID */ - -	/** -	 * Number of ticks before the specified channel is next used, or -	 * CHANNEL_DELAY_MISSING to indicate that the delay has not yet -	 * been read. -	 */ -	int delay; - -	/* Two additional offsets for recovering: */ -	int loop_offset; -	int initial_offset; - -	int playmask;			///< Active playmask (MIDI channels to play in here) */ -	int loop_timepos;		///< Total delay for this channel's loop marker */ -	int total_timepos;		///< Number of ticks since the beginning, ignoring loops */ -	int timepos_increment;	///< Number of ticks until the next command (to add) */ - -	byte last_cmd;			///< Last operation executed, for running status */ - -public: -	void init(int id, int offset, int end); -	void resetSynthChannels(); -}; - -class BaseSongIterator : public SongIterator { -public: -	int _polyphony[MIDI_CHANNELS];	///< # of simultaneous notes on each - -	int _ccc;					///< Cumulative cue counter, for those who need it -	byte _resetflag;			///< for 0x4C -- on DoSound StopSound, do we return to start? -	int _deviceId;				///< ID of the device we generating events for -	int _numActiveChannels;		///< Number of active channels -	Common::Array<byte> _data;	///< Song data - -	int _loops; ///< Number of loops remaining - -public: -	BaseSongIterator(byte *data, uint size, songit_id_t id); - -protected: -	int parseMidiCommand(byte *buf, int *result, SongIteratorChannel *channel, int flags); -	int processMidi(byte *buf, int *result, SongIteratorChannel *channel, int flags); -}; - -/********************************/ -/*--------- SCI 0 --------------*/ -/********************************/ - -class Sci0SongIterator : public BaseSongIterator { -public: -	SongIteratorChannel _channel; - -public: -	Sci0SongIterator(byte *data, uint size, songit_id_t id); - -	int nextCommand(byte *buf, int *result); -	Audio::AudioStream *getAudioStream(); -	SongIterator *handleMessage(Message msg); -	void init(); -	int getTimepos(); -	SongIterator *clone(int delta); -}; - - -/********************************/ -/*--------- SCI 1 --------------*/ -/********************************/ - - -struct Sci1Sample { -	/** -	 * Time left-- initially, this is 'Sample point 1'. -	 * After initialisation, it is 'sample point 1 minus the sample -	 * point of the previous sample' -	 */ -	int delta; -	int size; -	bool announced; /* Announced for download (SI_PCM) */ -	int rate; -	byte *_data; -}; - -class Sci1SongIterator : public BaseSongIterator { -public: -	SongIteratorChannel _channels[MIDI_CHANNELS]; - -	/* Invariant: Whenever channels[i].delay == CHANNEL_DELAY_MISSING, -	** channel_offset[i] points to a delta time object. */ - -	bool _initialised; /**!< Whether the MIDI channel setup has been initialised */ -	int _numChannels; /**!< Number of channels actually used */ -	Common::List<Sci1Sample> _samples; -	int _numLoopedChannels; /**!< Number of channels that are ready to loop */ - -	int _delayRemaining; /**!< Number of ticks that haven't been polled yet */ -	int _hold; - -public: -	Sci1SongIterator(byte *data, uint size, songit_id_t id); -	~Sci1SongIterator(); - -	int nextCommand(byte *buf, int *result); -	Audio::AudioStream *getAudioStream(); -	SongIterator *handleMessage(Message msg); -	void init(); -	int getTimepos(); -	SongIterator *clone(int delta); - -private: -	int initSample(const int offset); -	int initSong(); - -	int getSmallestDelta() const; - -	void updateDelta(int delta); - -	/** Checks that none of the channels is waiting for its delta to be read */ -	bool noDeltaTime() const; - -	/** Determine the channel # of the next active event, or -1 */ -	int getCommandIndex() const; -}; - -#define PLAYMASK_NONE 0x0 - -/***************************/ -/*--------- Timer ---------*/ -/***************************/ - -/** - * A song iterator which waits a specified time and then fires - * SI_FINISHED. Used by DoSound, where audio resources are played (SCI1) - */ -class TimerSongIterator : public SongIterator { -protected: -	int _delta; /**!< Remaining time */ - -public: -	TimerSongIterator(int delta) : _delta(delta) {} - -	int nextCommand(byte *buf, int *result); -	Audio::AudioStream *getAudioStream() { return NULL; } -	SongIterator *handleMessage(Message msg) { return NULL; } -	int getTimepos() { return 0; } -	SongIterator *clone(int delta) { return new TimerSongIterator(*this); } -}; - -/**********************************/ -/*--------- Fast Forward ---------*/ -/**********************************/ - -/** - * A song iterator which fast-forwards another iterator. - * Skips all delta times until a specified 'delta' has been used up. - */ -class FastForwardSongIterator : public SongIterator { -protected: -	SongIterator *_delegate; -	int _delta; /**!< Remaining time */ - -public: -	FastForwardSongIterator(SongIterator *capsit, int delta); - -	int nextCommand(byte *buf, int *result); -	Audio::AudioStream *getAudioStream(); -	SongIterator *handleMessage(Message msg); -	int getTimepos(); -	SongIterator *clone(int delta); -}; - - -/**********************************/ -/*--------- Tee iterator ---------*/ -/**********************************/ - -enum { -	TEE_LEFT = 0, -	TEE_RIGHT = 1, -	TEE_LEFT_ACTIVE  = (1<<0), -	TEE_RIGHT_ACTIVE = (1<<1), -	TEE_LEFT_READY  = (1<<2), /**!< left result is ready */ -	TEE_RIGHT_READY = (1<<3), /**!< right result is ready */ -	TEE_LEFT_PCM = (1<<4), -	TEE_RIGHT_PCM = (1<<5) -}; - -/** - * This iterator combines two iterators, returns the next event available from either. - */ -class TeeSongIterator : public SongIterator { -public: -	int _status; - -	bool _readyToMorph; /**!< One of TEE_MORPH_* above */ - -	struct { -		SongIterator *it; -		byte buf[4]; -		int result; -		int retval; -	} _children[2]; - -public: -	TeeSongIterator(SongIterator *left, SongIterator *right); -	~TeeSongIterator(); - -	int nextCommand(byte *buf, int *result); -	Audio::AudioStream *getAudioStream(); -	SongIterator *handleMessage(Message msg); -	void init(); -	int getTimepos() { return 0; } -	SongIterator *clone(int delta); -}; - -} // End of namespace Sci - -#endif	// USE_OLD_MUSIC_FUNCTIONS - -#endif // SCI_SFX_SFX_ITERATOR_INTERNAL diff --git a/engines/sci/sound/iterator/songlib.cpp b/engines/sci/sound/iterator/songlib.cpp deleted file mode 100644 index 8bc2e8f476..0000000000 --- a/engines/sci/sound/iterator/songlib.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "sci/sci.h"	// for USE_OLD_MUSIC_FUNCTIONS - -#ifdef USE_OLD_MUSIC_FUNCTIONS -#include "sci/sound/iterator/core.h" -#include "sci/sound/iterator/iterator.h" - -namespace Sci { - -#define debug_stream stderr - -Song::Song() : _wakeupTime(0, SFX_TICKS_PER_SEC) { -	_handle = 0; -	_resourceNum = 0; -	_priority = 0; -	_status = SOUND_STATUS_STOPPED; - -	_restoreBehavior = RESTORE_BEHAVIOR_CONTINUE; -	_restoreTime = 0; - -	_loops = 0; -	_hold = 0; - -	_it = 0; -	_delay = 0; - -	_next = NULL; -	_nextPlaying = NULL; -	_nextStopping = NULL; -} - -Song::Song(SongHandle handle, SongIterator *it, int priority) : _wakeupTime(0, SFX_TICKS_PER_SEC) { -	_handle = handle; -	_resourceNum = 0; -	_priority = priority; -	_status = SOUND_STATUS_STOPPED; - -	_restoreBehavior = RESTORE_BEHAVIOR_CONTINUE; -	_restoreTime = 0; - -	_loops = 0; -	_hold = 0; - -	_it = it; -	_delay = 0; - -	_next = NULL; -	_nextPlaying = NULL; -	_nextStopping = NULL; -} - -void SongLibrary::addSong(Song *song) { -	Song **seeker = NULL; -	int pri	= song->_priority; - -	if (NULL == song) { -		warning("addSong(): NULL passed for song"); -		return; -	} - -	seeker = &_lib; -	while (*seeker && ((*seeker)->_priority > pri)) -		seeker = &((*seeker)->_next); - -	song->_next = *seeker; -	*seeker = song; -} - -void SongLibrary::freeSounds() { -	Song *next = _lib; -	while (next) { -		Song *song = next; -		delete song->_it; -		song->_it = NULL; -		next = song->_next; -		delete song; -	} -	_lib = NULL; -} - - -Song *SongLibrary::findSong(SongHandle handle) { -	Song *seeker = _lib; - -	while (seeker) { -		if (seeker->_handle == handle) -			break; -		seeker = seeker->_next; -	} - -	return seeker; -} - -Song *SongLibrary::findNextActive(Song *other) { -	Song *seeker = other ? other->_next : _lib; - -	while (seeker) { -		if ((seeker->_status == SOUND_STATUS_WAITING) || -		        (seeker->_status == SOUND_STATUS_PLAYING)) -			break; -		seeker = seeker->_next; -	} - -	/* Only return songs that have equal priority */ -	if (other && seeker && other->_priority > seeker->_priority) -		return NULL; - -	return seeker; -} - -Song *SongLibrary::findFirstActive() { -	return findNextActive(NULL); -} - -int SongLibrary::removeSong(SongHandle handle) { -	int retval; -	Song *goner = _lib; - -	if (!goner) -		return -1; - -	if (goner->_handle == handle) -		_lib = goner->_next; - -	else { -		while ((goner->_next) && (goner->_next->_handle != handle)) -			goner = goner->_next; - -		if (goner->_next) { /* Found him? */ -			Song *oldnext = goner->_next; - -			goner->_next = goner->_next->_next; -			goner = oldnext; -		} else return -1; /* No. */ -	} - -	retval = goner->_status; - -	delete goner->_it; -	delete goner; - -	return retval; -} - -int SongLibrary::countSongs() { -	Song *seeker = _lib; -	int retval = 0; - -	while (seeker) { -		retval++; -		seeker = seeker->_next; -	} - -	return retval; -} - -void SongLibrary::setSongRestoreBehavior(SongHandle handle, RESTORE_BEHAVIOR action) { -	Song *seeker = findSong(handle); - -	seeker->_restoreBehavior = action; -} - -} // End of namespace Sci - -#endif	// USE_OLD_MUSIC_FUNCTIONS diff --git a/engines/sci/sound/iterator/songlib.h b/engines/sci/sound/iterator/songlib.h deleted file mode 100644 index acb704edaa..0000000000 --- a/engines/sci/sound/iterator/songlib.h +++ /dev/null @@ -1,171 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/* Song library */ - -#ifndef SCI_SFX_SFX_SONGLIB_H -#define SCI_SFX_SFX_SONGLIB_H - -#include "common/scummsys.h" -#include "sound/timestamp.h" - -#include "sci/sci.h"	// for USE_OLD_MUSIC_FUNCTIONS -#ifdef USE_OLD_MUSIC_FUNCTIONS - -namespace Sci { - -class SongIterator; - -#define SOUND_STATUS_STOPPED   0 -#define SOUND_STATUS_PLAYING   1 -#define SOUND_STATUS_SUSPENDED 2 -/* suspended: only if ordered from kernel space */ -#define SOUND_STATUS_WAITING   3 -/* "waiting" means "tagged for playing, but not active right now" */ - -typedef unsigned long SongHandle; - -enum RESTORE_BEHAVIOR { -	RESTORE_BEHAVIOR_CONTINUE, /* restart a song when restored from -				     a saved game */ -	RESTORE_BEHAVIOR_RESTART /* continue it from where it was */ -}; - -class Song { -public: -	SongHandle _handle; -	int _resourceNum; /**<! Resource number */ -	int _priority; /**!< Song priority (more important if priority is higher) */ -	int _status;   /* See above */ - -	int _restoreBehavior; -	int _restoreTime; - -	/* Grabbed from the sound iterator, for save/restore purposes */ -	int _loops; -	int _hold; - -	SongIterator *_it; -	int _delay; /**!< Delay before accessing the iterator, in ticks */ - -	Audio::Timestamp _wakeupTime; /**!< Timestamp indicating the next MIDI event */ - -	Song *_next; /**!< Next song or NULL if this is the last one */ - -	/** -	 * Next playing song. Used by the core song system. -	 */ -	Song *_nextPlaying; - -	/** -	 * Next song pending stopping. Used exclusively by the core song system's -	 * _update_multi_song() -	 */ -	Song *_nextStopping; - -public: - -	Song(); - -	/** -	 * Initializes a new song. -	 * @param handle	the sound handle -	 * @param it		the song -	 * @param priority	the song's priority -	 * @return a freshly allocated song -	 */ -	Song(SongHandle handle, SongIterator *it, int priority); -}; - - -class SongLibrary { -public: -	Song *_lib; - -public: -	SongLibrary() : _lib(0) {} - -	/** Frees a song library. */ -	void freeSounds(); - -	/** -	 * Adds a song to a song library. -	 * @param song		song to add -	 */ -	void addSong(Song *song); - -	/** -	 * Looks up the song with the specified handle. -	 * @param handle	sound handle to look for -	 * @return the song or NULL if it wasn't found -	 */ -	Song *findSong(SongHandle handle); - -	/** -	 * Finds the first song playing with the highest priority. -	 * @return the song that should be played next, or NULL if there is none -	 */ -	Song *findFirstActive(); - -	/** -	 * Finds the next song playing with the highest priority. -	 * -	 * The functions 'findFirstActive' and 'findNextActive' -	 * allow to iterate over all songs that satisfy the requirement of -	 * being 'playable'. -	 * -	 * @param song		a song previously returned from the song library -	 * @return the next song to play relative to 'song', or NULL if none are left -	 */ -	Song *findNextActive(Song *song); - -	/** -	 * Removes a song from the library. -	 * @param handle		handle of the song to remove -	 * @return the status of the song that was removed -	 */ -	int removeSong(SongHandle handle); - -	/** -	 * Counts the number of songs in a song library. -	 * @return the number of songs -	 */ -	int countSongs(); - -	/** -	 * Determines what should be done with the song "handle" when restoring -	 * it from a saved game. -	 * @param handle	sound handle being restored -	 * @param action	desired action -	 */ -	void setSongRestoreBehavior(SongHandle handle, -		RESTORE_BEHAVIOR action); -}; - -} // End of namespace Sci - -#endif	// USE_OLD_MUSIC_FUNCTIONS - -#endif // SCI_SSFX_SFX_SONGLIB_H diff --git a/engines/sci/sound/iterator/test-iterator.cpp b/engines/sci/sound/iterator/test-iterator.cpp deleted file mode 100644 index 0d603a89fd..0000000000 --- a/engines/sci/sound/iterator/test-iterator.cpp +++ /dev/null @@ -1,423 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "iterator.h" -#include "iterator_internal.h" -#include <stdarg.h> -#include <stdio.h> - -using namespace Sci; - -#define ASSERT_S(x) if (!(x)) { error("Failed assertion in L%d: " #x, __LINE__); return; } -#define ASSERT(x) ASSERT_S(x) - -/* Tests the song iterators */ - -int errors = 0; - -void error(char *fmt, ...) { -	va_list ap; - -	fprintf(stderr, "[ERROR] "); -	va_start(ap, fmt); -	vfprintf(stderr, fmt, ap); -	va_end(ap); - -	++errors; -} - - -/* The simple iterator will finish after a fixed amount of time.  Before that, -** it emits (absolute) cues in ascending order.  */ -struct simple_iterator : public SongIterator { -	int lifetime_remaining; -	char *cues; -	int cue_counter; -	int cue_progress; -	int cues_nr; -}; - -int simple_it_next(SongIterator *_self, unsigned char *buf, int *result) { -	simple_iterator *self = (simple_iterator *)_self; - -	if (self->lifetime_remaining == -1) { -		error("Song iterator called post mortem"); -		return SI_FINISHED; -	} - -	if (self->lifetime_remaining) { - -		if (self->cue_counter < self->cues_nr) { -			int time_to_cue = self->cues[self->cue_counter]; - -			if (self->cue_progress == time_to_cue) { -				++self->cue_counter; -				self->cue_progress = 0; -				*result = self->cue_counter; -				return SI_ABSOLUTE_CUE; -			} else { -				int retval = time_to_cue - self->cue_progress; -				self->cue_progress = time_to_cue; - -				if (retval > self->lifetime_remaining) { -					retval = self->lifetime_remaining; -					self->lifetime_remaining = 0; -					self->cue_progress = retval; -					return retval; -				} - -				self->lifetime_remaining -= retval; -				return retval; -			} -		} else { -			int retval = self->lifetime_remaining; -			self->lifetime_remaining = 0; -			return retval; -		} - -	} else { -		self->lifetime_remaining = -1; -		return SI_FINISHED; -	} -} - -Audio::AudioStream *simple_it_pcm_feed(SongIterator *_self) { -	error("No PCM feed"); -	return NULL; -} - -void simple_it_init(SongIterator *_self) { -} - -SongIterator *simple_it_handle_message(SongIterator *_self, SongIterator::Message msg) { -	return NULL; -} - -void simple_it_cleanup(SongIterator *_self) { -} - -/* Initialises the simple iterator. -** Parameters: (int) delay: Number of ticks until the iterator finishes -**             (int *) cues: An array of cue delays (cue values are [1,2...]) -**             (int) cues_nr:  Number of cues in ``cues'' -** The first cue is emitted after cues[0] ticks, and it is 1.  After cues[1] additional ticks -** the next cue is emitted, and so on. */ -SongIterator *setup_simple_iterator(int delay, char *cues, int cues_nr) { -	simple_iterator.lifetime_remaining = delay; -	simple_iterator.cues = cues; -	simple_iterator.cue_counter = 0; -	simple_iterator.cues_nr = cues_nr; -	simple_iterator.cue_progress = 0; - -	simple_iterator.ID = 42; -	simple_iterator.channel_mask = 0x004f; -	simple_iterator.flags = 0; -	simple_iterator.priority = 1; - -	simple_iterator.death_listeners_nr = 0; - -	simple_iterator.cleanup = simple_it_cleanup; -	simple_iterator.init = simple_it_init; -	simple_iterator.handle_message = simple_it_handle_message; -	simple_iterator.get_pcm_feed = simple_it_pcm_feed; -	simple_iterator.next = simple_it_next; - -	return (SongIterator *) &simple_iterator; -} - -#define ASSERT_SIT ASSERT(it == simple_it) -#define ASSERT_FFIT ASSERT(it == ff_it) -#define ASSERT_NEXT(n) ASSERT(songit_next(&it, data, &result, IT_READER_MASK_ALL) == n) -#define ASSERT_RESULT(n) ASSERT(result == n) -#define ASSERT_CUE(n) ASSERT_NEXT(SI_ABSOLUTE_CUE); ASSERT_RESULT(n) - -void test_simple_it() { -	SongIterator *it; -	SongIterator *simple_it = (SongIterator *) & simple_iterator; -	unsigned char data[4]; -	int result; -	puts("[TEST] simple iterator (test artifact)"); - -	it = setup_simple_iterator(42, NULL, 0); - -	ASSERT_SIT; -	ASSERT_NEXT(42); -	ASSERT_SIT; -	ASSERT_NEXT(SI_FINISHED); -	ASSERT_SIT; - -	it = setup_simple_iterator(42, "\003\004", 2); -	ASSERT_SIT; -	ASSERT_NEXT(3); -	ASSERT_CUE(1); -	ASSERT_SIT; -	ASSERT_NEXT(4); -	ASSERT_CUE(2); -	ASSERT_SIT; -//	warning("XXX => %d", songit_next(&it, data, &result, IT_READER_MASK_ALL)); -	ASSERT_NEXT(35); -	ASSERT_NEXT(SI_FINISHED); -	ASSERT_SIT; - -	puts("[TEST] Test OK."); -} - -void test_fastforward() { -	SongIterator *it; -	SongIterator *simple_it = (SongIterator *) & simple_iterator; -	SongIterator *ff_it; -	unsigned char data[4]; -	int result; -	puts("[TEST] fast-forward iterator"); - -	it = setup_simple_iterator(42, NULL, 0); -	ff_it = it = new_fast_forward_iterator(it, 0); -	ASSERT_FFIT; -	ASSERT_NEXT(42); -	ASSERT_SIT; /* Must have morphed back */ -	ASSERT_NEXT(SI_FINISHED); -	ASSERT_SIT; - -	it = setup_simple_iterator(42, NULL, 0); -	ff_it = it = new_fast_forward_iterator(it, 1); -	ASSERT_FFIT; -	ASSERT_NEXT(41); -	/* May or may not have morphed back here */ -	ASSERT_NEXT(SI_FINISHED); -	ASSERT_SIT; - -	it = setup_simple_iterator(42, NULL, 0); -	ff_it = it = new_fast_forward_iterator(it, 41); -	ASSERT_FFIT; -	ASSERT_NEXT(1); -	/* May or may not have morphed back here */ -	ASSERT_NEXT(SI_FINISHED); -	ASSERT_SIT; - -	it = setup_simple_iterator(42, NULL, 0); -	ff_it = it = new_fast_forward_iterator(it, 42); -	ASSERT_NEXT(SI_FINISHED); -	/* May or may not have morphed back here */ - -	it = setup_simple_iterator(42, NULL, 0); -	ff_it = it = new_fast_forward_iterator(it, 10000); -	ASSERT_NEXT(SI_FINISHED); -	/* May or may not have morphed back here */ - -	it = setup_simple_iterator(42, "\003\004", 2); -	ff_it = it = new_fast_forward_iterator(it, 2); -	ASSERT_FFIT; -	ASSERT_NEXT(1); -	ASSERT_CUE(1); -	ASSERT_SIT; -	ASSERT_NEXT(4); -	ASSERT_CUE(2); -	ASSERT_SIT; -	ASSERT_NEXT(35); -	ASSERT_NEXT(SI_FINISHED); -	ASSERT_SIT; - -	it = setup_simple_iterator(42, "\003\004", 2); -	ff_it = it = new_fast_forward_iterator(it, 5); -	ASSERT_FFIT; -	ASSERT_CUE(1); -	ASSERT_FFIT; -	ASSERT_NEXT(2); -	ASSERT_CUE(2); -	ASSERT_SIT; -	ASSERT_NEXT(35); -	ASSERT_NEXT(SI_FINISHED); -	ASSERT_SIT; - -	it = setup_simple_iterator(42, "\003\004", 2); -	ff_it = it = new_fast_forward_iterator(it, 41); -	ASSERT_FFIT; -	ASSERT_CUE(1); -	ASSERT_FFIT; -	ASSERT_CUE(2); -	ASSERT_FFIT; -	ASSERT_NEXT(1); -	ASSERT_NEXT(SI_FINISHED); -	ASSERT_SIT; - -	puts("[TEST] Test OK."); -} - -#define SIMPLE_SONG_SIZE 50 - -static unsigned char simple_song[SIMPLE_SONG_SIZE] = { -	0x00, /* Regular song */ -	/* Only use channel 0 for all devices */ -	0x02, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -	/* Song begins here */ -	42, 0x90, 60, 0x7f,		/* Play C after 42 ticks */ -	02, 64, 0x42,			/* Play E after 2 more ticks, using running status mode */ -	0xf8, 10, 0x80, 60, 0x02,	/* Stop C after 250 ticks */ -	0, 64, 0x00,			/* Stop E immediately */ -	00, 0xfc	/* Stop song */ -}; - -#define ASSERT_MIDI3(cmd, arg0, arg1) \ -	ASSERT(data[0] == cmd);		\ -	ASSERT(data[1] == arg0);	\ -	ASSERT(data[2] == arg1); - -void test_iterator_sci0() { -	SongIterator *it = songit_new(simple_song, SIMPLE_SONG_SIZE, SCI_SONG_ITERATOR_TYPE_SCI0, 0l); -	unsigned char data[4]; -	int result; -	SIMSG_SEND(it, SIMSG_SET_PLAYMASK(0x0001)); /* Initialise song, enabling channel 0 */ - -	puts("[TEST] SCI0-style song"); -	ASSERT_NEXT(42); -	ASSERT_NEXT(0); -	ASSERT_MIDI3(0x90, 60, 0x7f); -	ASSERT_NEXT(2); -	ASSERT_NEXT(0); -	ASSERT_MIDI3(0x90, 64, 0x42); -	ASSERT_NEXT(250); -	ASSERT_NEXT(0); -	ASSERT_MIDI3(0x80, 60, 0x02); -	ASSERT_NEXT(0); -	ASSERT_MIDI3(0x80, 64, 0x00); -	ASSERT_NEXT(SI_FINISHED); -	puts("[TEST] Test OK."); -} - - - -void test_iterator_sci0_loop() { -	SongIterator *it = songit_new(simple_song, SIMPLE_SONG_SIZE, SCI_SONG_ITERATOR_TYPE_SCI0, 0l); -	unsigned char data[4]; -	int result; -	SIMSG_SEND(it, SIMSG_SET_PLAYMASK(0x0001)); /* Initialise song, enabling channel 0 */ -	SIMSG_SEND(it, SIMSG_SET_LOOPS(2)); /* Loop one additional time */ - -	puts("[TEST] SCI0-style song with looping"); -	ASSERT_NEXT(42); -	ASSERT_NEXT(0); -	ASSERT_MIDI3(0x90, 60, 0x7f); -	ASSERT_NEXT(2); -	ASSERT_NEXT(0); -	ASSERT_MIDI3(0x90, 64, 0x42); -	ASSERT_NEXT(250); -	ASSERT_NEXT(0); -	ASSERT_MIDI3(0x80, 60, 0x02); -	ASSERT_NEXT(0); -	ASSERT_MIDI3(0x80, 64, 0x00); -	ASSERT_NEXT(SI_LOOP); -	ASSERT_NEXT(42); -	ASSERT_NEXT(0); -	ASSERT_MIDI3(0x90, 60, 0x7f); -	ASSERT_NEXT(2); -	ASSERT_NEXT(0); -	ASSERT_MIDI3(0x90, 64, 0x42); -	ASSERT_NEXT(250); -	ASSERT_NEXT(0); -	ASSERT_MIDI3(0x80, 60, 0x02); -	ASSERT_NEXT(0); -	ASSERT_MIDI3(0x80, 64, 0x00); -	ASSERT_NEXT(SI_FINISHED); -	puts("[TEST] Test OK."); -} - - - -#define LOOP_SONG_SIZE 54 - -unsigned char loop_song[LOOP_SONG_SIZE] = { -	0x00, /* Regular song song */ -	/* Only use channel 0 for all devices */ -	0x02, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -	/* Song begins here */ -	42, 0x90, 60, 0x7f,	/* Play C after 42 ticks */ -	13, 0x80, 60, 0x00,	/* Stop C after 13 ticks */ -	00, 0xCF, 0x7f,	/* Set loop point */ -	02, 0x90, 64, 0x42,	/* Play E after 2 more ticks, using running status mode */ -	03, 0x80, 64, 0x00,	/* Stop E after 3 ticks */ -	00, 0xfc	/* Stop song/loop */ -}; - - -void test_iterator_sci0_mark_loop() { -	SongIterator *it = songit_new(loop_song, LOOP_SONG_SIZE, SCI_SONG_ITERATOR_TYPE_SCI0, 0l); -	unsigned char data[4]; -	int result; -	SIMSG_SEND(it, SIMSG_SET_PLAYMASK(0x0001)); /* Initialise song, enabling channel 0 */ -	SIMSG_SEND(it, SIMSG_SET_LOOPS(3)); /* Loop once more */ - -	puts("[TEST] SCI0-style song with loop mark, looping"); -	ASSERT_NEXT(42); -	ASSERT_NEXT(0); -	ASSERT_MIDI3(0x90, 60, 0x7f); -	ASSERT_NEXT(13); -	ASSERT_NEXT(0); -	ASSERT_MIDI3(0x80, 60, 0x00); -	/* Loop point here: we don't observe that in the iterator interface yet, though */ -	ASSERT_NEXT(2); -	ASSERT_NEXT(0); -	ASSERT_MIDI3(0x90, 64, 0x42); -	ASSERT_NEXT(3); -	ASSERT_NEXT(0); -	ASSERT_MIDI3(0x80, 64, 0x00); -	/* Now we loop back to the loop pont */ -	ASSERT_NEXT(SI_LOOP); -	ASSERT_NEXT(2); -	ASSERT_NEXT(0); -	ASSERT_MIDI3(0x90, 64, 0x42); -	ASSERT_NEXT(3); -	ASSERT_NEXT(0); -	ASSERT_MIDI3(0x80, 64, 0x00); -	/* ...and one final time */ -	ASSERT_NEXT(SI_LOOP); -	ASSERT_NEXT(2); -	ASSERT_NEXT(0); -	ASSERT_MIDI3(0x90, 64, 0x42); -	ASSERT_NEXT(3); -	ASSERT_NEXT(0); -	ASSERT_MIDI3(0x80, 64, 0x00); - -	ASSERT_NEXT(SI_FINISHED); -	puts("[TEST] Test OK."); -} - - - -int main(int argc, char **argv) { -	test_simple_it(); -	test_fastforward(); -	test_iterator_sci0(); -	test_iterator_sci0_loop(); -	test_iterator_sci0_mark_loop(); -	if (errors != 0) -		warning("[ERROR] %d errors total", errors); -	return (errors != 0); -} | 
