diff options
| author | Max Horn | 2009-03-01 21:23:44 +0000 | 
|---|---|---|
| committer | Max Horn | 2009-03-01 21:23:44 +0000 | 
| commit | 00db87563ae01ef60a86c4da6c7b376e74f10a8b (patch) | |
| tree | 0d4c102304899c32a79cb769a4b85bfa4f275ee6 | |
| parent | a718713925ef79ddfa9dd545134a46eb918441ba (diff) | |
| download | scummvm-rg350-00db87563ae01ef60a86c4da6c7b376e74f10a8b.tar.gz scummvm-rg350-00db87563ae01ef60a86c4da6c7b376e74f10a8b.tar.bz2 scummvm-rg350-00db87563ae01ef60a86c4da6c7b376e74f10a8b.zip | |
SCI: Reimplemented the SCI mixer based on the old SCI DC mixer by walter, and by taking advantage of ScummVM's mixers capabilities. Got rid of sfx_pcm_mixer_t
svn-id: r39053
| -rw-r--r-- | engines/sci/sfx/core.cpp | 37 | ||||
| -rw-r--r-- | engines/sci/sfx/mixer.cpp | 937 | ||||
| -rw-r--r-- | engines/sci/sfx/mixer.h | 62 | ||||
| -rw-r--r-- | engines/sci/sfx/mixer/test.cpp | 347 | ||||
| -rw-r--r-- | engines/sci/sfx/player/polled.cpp | 5 | 
5 files changed, 167 insertions, 1221 deletions
| diff --git a/engines/sci/sfx/core.cpp b/engines/sci/sfx/core.cpp index f9d19f7176..c0a73a4d4b 100644 --- a/engines/sci/sfx/core.cpp +++ b/engines/sci/sfx/core.cpp @@ -33,6 +33,7 @@  #include "common/system.h"  #include "common/timer.h" +#include "sound/mixer.h"  namespace Sci { @@ -43,11 +44,10 @@ int sciprintf(char *msg, ...);  #endif  static sfx_player_t *player = NULL; -sfx_pcm_mixer_t *mixer = NULL;  int sfx_pcm_available() { -	return (mixer != NULL); +	return g_system->getMixer()->isReady();  }  void sfx_reset_player() { @@ -340,11 +340,11 @@ int sfx_play_iterator_pcm(song_iterator_t *it, song_handle_t handle) {  #ifdef DEBUG_SONG_API  	fprintf(stderr, "[sfx-core] Playing PCM: %08lx\n", handle);  #endif -	if (mixer) { +	if (g_system->getMixer()->isReady()) {  		sfx_pcm_feed_t *newfeed = it->get_pcm_feed(it);  		if (newfeed) {  			newfeed->debug_nr = (int) handle; -			mixer->subscribe(mixer, newfeed); +			mixer_subscribe(newfeed);  			return 1;  		}  	} @@ -362,8 +362,7 @@ static void _sfx_timer_callback(void *data) {  	if (player)  		player->maintenance(); -	if (mixer) -		mixer->process(mixer); +	mixer_process();  }  void sfx_init(sfx_state_t *self, ResourceManager *resmgr, int flags) { @@ -373,13 +372,11 @@ void sfx_init(sfx_state_t *self, ResourceManager *resmgr, int flags) {  	self->debug = 0; /* Disable all debugging by default */  	if (flags & SFX_STATE_FLAG_NOSOUND) { -		mixer = NULL;  		player = NULL;  		sciprintf("[SFX] Sound disabled.\n");  		return;  	} -	mixer = getMixer();  	player = sfx_find_player(NULL); @@ -387,15 +384,6 @@ void sfx_init(sfx_state_t *self, ResourceManager *resmgr, int flags) {  	fprintf(stderr, "[sfx-core] Initialising: flags=%x\n", flags);  #endif -	/*------------------*/ -	/* Initialise mixer */ -	/*------------------*/ - -	if (mixer->init(mixer)) { -		sciprintf("[SFX] Failed to initialise PCM mixer; disabling PCM support\n"); -		mixer = NULL; -	} -  	/*-------------------*/  	/* Initialise player */  	/*-------------------*/ @@ -421,12 +409,11 @@ void sfx_init(sfx_state_t *self, ResourceManager *resmgr, int flags) {  	// timer callback being triggered while the mixer or player are  	// still being initialized. -	if (mixer || (player && player->maintenance)) { +	if (g_system->getMixer()->isReady() || (player && player->maintenance)) {  		if (!g_system->getTimerManager()->installTimerProc(&_sfx_timer_callback, DELAY, NULL)) {  			warning("[SFX] " __FILE__": Timer failed to initialize");  			warning("[SFX] Disabled sound support");  			player = NULL; -			mixer = NULL;  			return;  		}  	} /* With no PCM device and no player, we don't need a timer */ @@ -446,16 +433,12 @@ void sfx_exit(sfx_state_t *self) {  	song_lib_free(self->songlib); -	/* WARNING: The mixer may hold feeds from the -	** player, so we must stop the mixer BEFORE -	** stopping the player. */ -	if (mixer) { -		mixer->exit(mixer); -		mixer = NULL; -	} +	// WARNING: The mixer may hold feeds from the player, so we must +	// stop the mixer BEFORE stopping the player. +	g_system->getMixer()->stopAll();  	if (player) -		/* See above: This must happen AFTER stopping the mixer */ +		// See above: This must happen AFTER stopping the mixer  		player->exit();  } diff --git a/engines/sci/sfx/mixer.cpp b/engines/sci/sfx/mixer.cpp index 09441f9ab6..0293be4ad3 100644 --- a/engines/sci/sfx/mixer.cpp +++ b/engines/sci/sfx/mixer.cpp @@ -23,858 +23,203 @@   *   */ -#include "common/list.h" -#include "common/mutex.h"  #include "common/system.h"  #include "sci/tools.h"  #include "sci/sfx/mixer.h" -#include "sci/sci_memory.h"  #include "sound/audiostream.h"  #include "sound/mixer.h"  namespace Sci { -/* Max. number of milliseconds in difference allowed between independent audio streams */ -#define TIMESTAMP_MAX_ALLOWED_DELTA 2 - -/*#define DEBUG 3*/ -/* Set DEBUG to one of the following: -** anything -- high-level debugging (feed subscriptions/deletions etc.) -**     >= 1 -- rough input and output analysis (once per call) -**     >= 2 -- more detailed input analysis (once per call and feed) -**     >= 3 -- fully detailed input and output analysis (once per frame and feed) -*/ - -//#define DEBUG 1 - -#define MIN_DELTA_OBSERVATIONS 100 /* Number of times the mixer is called before it starts trying to improve latency */ -#define MAX_DELTA_OBSERVATIONS 1000000 /* Number of times the mixer is called before we assume we truly understand timing */ - -static int diagnosed_too_slow = 0; - -#define ACQUIRE_LOCK() P->_mixerLock.lock() -#define RELEASE_LOCK() P->_mixerLock.unlock() - -#define SFX_PCM_FEED_MODE_ALIVE 0 -#define SFX_PCM_FEED_MODE_DEAD 1 - - - -/** Finitary unsigned rational numbers */ -struct sfx_pcm_urat_t { -	int nom, den; -	int val; - -	/* Total value: val + nom/den, where (nom < den) guaranteed. */ -}; - -struct twochannel_data { -	int left, right; -}; - -struct PCMFeedState { -	sfx_pcm_feed_t *feed; - -	/* The following fields are for use by the mixer only and must not be -	** touched by pcm_feed code.  */ -	byte *buf; /* dynamically allocated buffer for this feed, used in some circumstances. */ -	int buf_size; /* Number of frames that fit into the buffer */ -	sfx_pcm_urat_t spd; /* source frames per destination frames */ -	sfx_pcm_urat_t scount; /* Frame counter, backed up in between calls */ -	int frame_bufstart; /* Left-over frames at the beginning of the buffer */ -	int mode; /* Whether the feed is alive or pending destruction */ - -	bool pending_review; /* Timestamp needs to be checked for this stream */ -	twochannel_data ch_old, ch_new; /* Intermediate results of output computation */ - -	PCMFeedState(sfx_pcm_feed_t *f); -	~PCMFeedState(); -}; - -struct mixer_private { -	Common::Mutex _mixerLock; -	byte *outbuf; /* Output buffer to write to the PCM device next time */ -	sfx_timestamp_t outbuf_timestamp; /* Timestamp associated with the output buffer */ -	int have_outbuf_timestamp; /* Whether we really _have_ an associated timestamp */ -	byte *writebuf; /* Buffer we're supposed to write to */ -	int32 *compbuf_l, *compbuf_r; /* Intermediate buffers for computation */ -	int lastbuf_len; /* Number of frames stored in the last buffer */ - -	uint32 skew; /* Millisecond relative to which we compute time. This is the millisecond -		   ** part of the first time we emitted sound, to simplify some computations.  */ -	uint32 lsec; /* Last point in time we updated buffers, if any (seconds since the epoch) */ -	int played_this_second; /* Number of frames emitted so far in second lsec */ - -	int max_delta; /* maximum observed time delta (using 'frames' as a metric unit) */ -	int delta_observations; /* Number of times we played; confidence measure for max_delta */ - -	sfx_pcm_config_t conf; -	int _framesize; -	Audio::AppendableAudioStream *_audioStream; -	Audio::SoundHandle _soundHandle; - -	Common::List<PCMFeedState> _feeds; -}; - -#define P ((struct mixer_private *)(self->private_bits)) - -enum { -	BUF_SIZE = 2048 << 1 -}; - -static int mix_init(sfx_pcm_mixer_t *self) { -	self->private_bits = new mixer_private(); -	P->outbuf = P->writebuf = NULL; -	P->lastbuf_len = 0; -	P->compbuf_l = (int32*)sci_malloc(sizeof(int32) * BUF_SIZE); -	P->compbuf_r = (int32*)sci_malloc(sizeof(int32) * BUF_SIZE); -	P->played_this_second = 0; -	 -	P->conf.rate = g_system->getMixer()->getOutputRate(); -	P->conf.stereo = SFX_PCM_STEREO_LR; -	P->conf.format = SFX_PCM_FORMAT_S16_NATIVE; -	P->_framesize = SFX_PCM_FRAME_SIZE(P->conf); - -	int flags = Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_STEREO; -#ifdef SCUMM_LITTLE_ENDIAN -	flags |= Audio::Mixer::FLAG_LITTLE_ENDIAN; -#endif - -	P->_audioStream = Audio::makeAppendableAudioStream(P->conf.rate, flags); -	g_system->getMixer()->playInputStream(Audio::Mixer::kSFXSoundType, &P->_soundHandle, P->_audioStream); - -	return SFX_OK; -} - -static inline uint gcd(uint a, uint b) { -	while (a) { -		uint c = b % a; -		b = a; -		a = c; +class PCMFeedAudioStream : public Audio::AudioStream { +protected: +	enum FeedMode { +		FEED_MODE_ALIVE, +		FEED_MODE_IDLE, +		FEED_MODE_DEAD, +		FEED_MODE_RESTART +	}; + +	/* Whether feed is alive or dead. */ +	FeedMode _mode; + +	/* Blank gap in frames. */ +	int _gap; + +	/* Feed. */ +	sfx_pcm_feed_t *_feed; + +	/* Timestamp of next frame requested by stream driver. */ +	sfx_timestamp_t _time; + +public: +	PCMFeedAudioStream(sfx_pcm_feed_t *feed) : _feed(feed) { +		_feed->frame_size = SFX_PCM_FRAME_SIZE(_feed->conf); +		_mode = FEED_MODE_ALIVE; +		_gap = 0; +		_time = sfx_new_timestamp(g_system->getMillis(), _feed->conf.rate);  	} -	return b; -} - -static sfx_pcm_urat_t urat(unsigned int nom, unsigned int denom) { -	sfx_pcm_urat_t rv; -	unsigned int g; - -	rv.val = nom / denom; -	nom -= rv.val * denom; -	if (nom == 0) -		g = 1; -	else -		g = gcd(nom, denom); - -	rv.nom = nom / g; -	rv.den = denom / g; - -	return rv; -} - -PCMFeedState::PCMFeedState(sfx_pcm_feed_t *f) : feed(f) { -	buf = 0; -	buf_size = 0; -	spd = scount = urat(0, 1); -	frame_bufstart = 0; -	mode = SFX_PCM_FEED_MODE_ALIVE; -	frame_bufstart = 0; - -	/* If the feed can't provide us with timestamps, we don't need to wait for it to do so */ -	pending_review = (feed->get_timestamp) ? true : false; - -	memset(&ch_old, 0, sizeof(twochannel_data)); -	memset(&ch_new, 0, sizeof(twochannel_data)); -} - -PCMFeedState::~PCMFeedState() { -	if (feed) -		feed->destroy(feed); -	free(buf); -} - -static void mix_subscribe(sfx_pcm_mixer_t *self, sfx_pcm_feed_t *feed) { -	ACQUIRE_LOCK(); - -	PCMFeedState fs(feed); - -	feed->frame_size = SFX_PCM_FRAME_SIZE(feed->conf); - -	/*	fs->buf_size = (BUF_SIZE -			  * (feed->conf.rate -			     + P->conf.rate - 1)) -		/ P->conf.rate; -	*/ -	/* For the sake of people without 64 bit CPUs: */ -	fs.buf_size = 2 + /* Additional safety */ -	               (BUF_SIZE * -	                (1 + (feed->conf.rate / P->conf.rate))); -	fprintf(stderr, " ---> %d/%d/%d/%d = %d\n", -	        BUF_SIZE, -	        feed->conf.rate, -	        P->conf.rate, -	        feed->frame_size, -	        fs.buf_size); - -	fs.buf = (byte*)sci_malloc(fs.buf_size * feed->frame_size); -	memset(fs.buf, 0xa5, fs.buf_size * feed->frame_size); -	fs.scount = urat(0, 1); -	fs.spd = urat(feed->conf.rate, P->conf.rate); -	fs.scount.den = fs.spd.den; - -#ifdef DEBUG -	sciprintf("[soft-mixer] Subscribed %s-%x (%d Hz, %d/%x) at %d+%d/%d, buffer size %d\n", -	          feed->debug_name, feed->debug_nr, feed->conf.rate, feed->conf.stereo, feed->conf.format, -	          fs->spd.val, fs->spd.nom, fs->spd.den, fs->buf_size); -#endif - -	P->_feeds.push_back(fs); - -	// HACK: the copy of fs made in P->_feeds is a shallow copy, -	// so we need to prevent fs.buf and fs.feed from being destroyed when -	// fs goes out of scope -	fs.buf = 0; -	fs.feed = 0; - -	RELEASE_LOCK(); -} - - -static void mix_exit(sfx_pcm_mixer_t *self) { -	g_system->getMixer()->stopHandle(P->_soundHandle); -	P->_audioStream = 0; - -	free(P->outbuf); -	free(P->writebuf); - -	free(P->compbuf_l); -	free(P->compbuf_r); - -	delete P; -	self->private_bits = NULL; - -#ifdef DEBUG -	sciprintf("[soft-mixer] Uninitialising mixer\n"); -#endif -} - - -#define LIMIT_16_BITS(v)			\ -		if (v < -32767)			\ -			v = -32768;		\ -		else if (v > 32766)		\ -			v = 32767 - -static inline void mix_compute_output(sfx_pcm_mixer_t *self, int outplen) { -	int frame_i; -	const sfx_pcm_config_t conf = P->conf; -	int use_16 = conf.format & SFX_PCM_FORMAT_16; -	int bias = conf.format & ~SFX_PCM_FORMAT_LMASK; -	byte *lchan, *rchan = NULL; -	/* Don't see how this could possibly wind up being -	** used w/o initialisation, but you never know... */ -	int32 *lsrc = P->compbuf_l; -	int32 *rsrc = P->compbuf_r; -	int frame_size = SFX_PCM_FRAME_SIZE(conf); - -	if (!P->writebuf) -		P->writebuf = (byte*)sci_malloc(BUF_SIZE * frame_size + 4); - -	lchan = P->writebuf; -	if (conf.stereo) -		rchan = P->writebuf + ((use_16) ? 2 : 1); - - -	for (frame_i = 0; frame_i < outplen; frame_i++) { -		int left = *lsrc++; -		int right = *rsrc++; - -		if (conf.stereo) { -			LIMIT_16_BITS(left); -			LIMIT_16_BITS(right); - -			if (!use_16) { -				left >>= 8; -				right >>= 8; -			} - -			left += bias; -			right += bias; - -			if (use_16) { -				*(int16 *)lchan = left; -				*(int16 *)rchan = right; - -				lchan += 4; -				rchan += 4; -			} else { -				*lchan = left & 0xff; -				*rchan = right & 0xff; - -				lchan += 2; -				rchan += 2; -			} - -		} else { -			left += right; -			left >>= 1; -			LIMIT_16_BITS(left); -			if (!use_16) -				left >>= 8; - -			left += bias; - -			if (use_16) { -				*(int16 *)lchan = left; - -				lchan += 2; -			} else { -				*lchan = left & 0xff; -				lchan += 1; -			} -		} -	} -} - -static inline void mix_swap_buffers(sfx_pcm_mixer_t *self) { /* Swap buffers */ -	byte *tmp = P->outbuf; -	P->outbuf = P->writebuf; -	P->writebuf = tmp; -} - -static inline int mix_compute_buf_len(sfx_pcm_mixer_t *self, int *skip_frames) { -/* Computes the number of frames we ought to write. It tries to minimise the number, -** in order to reduce latency. */ -/* It sets 'skip_frames' to the number of frames to assume lost by latency, effectively -** skipping them.  */ -	int free_frames; -	int played_frames = 0; /* since the last call */ -	uint32 msecs; -	int frame_pos; -	int result_frames; - -	msecs = g_system->getMillis(); - -	if (!P->outbuf) { -		/* Called for the first time ever? */ -		P->skew = msecs % 1000; -		P->lsec = msecs / 1000; -		P->max_delta = 0; -		P->delta_observations = 0; -		P->played_this_second = 0; -		*skip_frames = 0; - -		return BUF_SIZE; +	~PCMFeedAudioStream() { +		_feed->destroy(_feed);  	} -	/*	fprintf(stderr, "[%d:%d]S%d ", secs, usecs, P->skew);*/ - -	msecs -= P->skew; - -	frame_pos = (msecs % 1000) * P->conf.rate / 1000; - -	played_frames = frame_pos - P->played_this_second -	                + ((msecs / 1000 - P->lsec) * P->conf.rate); -	/* -	fprintf(stderr, "%d:%d - %d:%d  => %d\n", secs, frame_pos, -		P->lsec, P->played_this_second, played_frames); -	*/ - -	if (played_frames > BUF_SIZE) -		played_frames = BUF_SIZE; +	virtual int readBuffer(int16 *buffer, const int numSamples); -	/* -	fprintf(stderr, "Between %d:? offset=%d and %d:%d offset=%d: Played %d at %d\n", P->lsec, P->played_this_second, -	secs, usecs, frame_pos, played_frames, P->conf.rate); -	*/ - - -	if (played_frames > P->max_delta) -		P->max_delta = played_frames; - -	free_frames = played_frames; - -	if (free_frames > BUF_SIZE) { -		if (!diagnosed_too_slow) { -			sciprintf("[sfx-mixer] Your timer is too slow for your PCM output device (%d/%d), free=%d.\n" -			          "[sfx-mixer] You might want to try changing the device, timer, or mixer, if possible.\n", -			          played_frames, BUF_SIZE, free_frames); -		} -		diagnosed_too_slow = 1; - -		*skip_frames = free_frames - BUF_SIZE; -		free_frames = BUF_SIZE; -	} else -		*skip_frames = 0; - -	++P->delta_observations; -	if (P->delta_observations > MAX_DELTA_OBSERVATIONS) -		P->delta_observations = MAX_DELTA_OBSERVATIONS; - -	/*	/\* Disabled, broken *\/ */ -	/*	if (0 && P->delta_observations > MIN_DELTA_OBSERVATIONS) { /\* Start improving after a while *\/ */ -	/*		int diff = P->conf.rate - P->max_delta; */ - -	/*		/\* log-approximate P->max_delta over time *\/ */ -	/*		recommended_frames = P->max_delta + */ -	/*			((diff * MIN_DELTA_OBSERVATIONS) / P->delta_observations); */ -	/* /\* WTF? *\/ */ -	/*	} else */ -	/*		recommended_frames = BUF_SIZE; /\* Initially, keep the buffer full *\/ */ - -#if (DEBUG >= 1) -	sciprintf("[soft-mixer] played since last time: %d, free: %d\n", -	          played_frames, free_frames); -#endif - -	result_frames = free_frames; - -	if (result_frames < 0) -		result_frames = 0; - -	P->played_this_second += result_frames; -	while (P->played_this_second >= P->conf.rate) { -		/* Won't normally happen more than once */ -		P->played_this_second -= P->conf.rate; -		P->lsec++; -	} - -	if (result_frames > BUF_SIZE) { -		fprintf(stderr, "[soft-mixer] Internal assertion failed: frames-to-write %d > %d\n", -		        result_frames, BUF_SIZE); -	} -	return result_frames; -} +	virtual bool isStereo() const { return _feed->conf.stereo; } +	virtual int getRate() const { return _feed->conf.rate; } +	virtual bool endOfData() const { return _mode == FEED_MODE_DEAD; } +protected: +	void queryTimestamp(); +}; -#define READ_NEW_VALUES() \ -		if (frames_left > 0) {						\ -			if (!use_16) {						\ -				c_new.left = (*lsrc) << 8;			\ -				c_new.right = (*rsrc) << 8;			\ -			} else {								\ -				c_new.left = *((int16 *)lsrc);	\ -				c_new.right = *((int16 *)rsrc);	\ -			}									\ -										\ -			c_new.left -= bias;					\ -			c_new.right -= bias;					\ -										\ -			lsrc += frame_size;					\ -			rsrc += frame_size;					\ -		} else {							\ -			c_new.left = c_new.right = 0;				\ -			break;							\ -		} - - -static volatile int xx_offset; -static volatile int xx_size; - -static void mix_compute_input_linear(sfx_pcm_mixer_t *self, -									 const Common::List<PCMFeedState>::iterator &fs, -									 int len, sfx_timestamp_t *ts, sfx_timestamp_t base_ts) { -/* base_ts is the timestamp for the first frame */ -/* if add_result is non-zero, P->outbuf should be added to rather than overwritten. */ -	const bool add_result = (P->_feeds.begin() != fs); -	sfx_pcm_feed_t *f = fs->feed; -	sfx_pcm_config_t conf = f->conf; -	int use_16 = conf.format & SFX_PCM_FORMAT_16; -	int32 *lchan = P->compbuf_l; -	int32 *rchan = P->compbuf_r; -	int frame_size = f->frame_size; -	byte *wr_dest = fs->buf + (frame_size * fs->frame_bufstart); -	byte *lsrc = fs->buf; -	byte *rsrc = fs->buf; -	/* Location to write to */ -	int frames_nr; -	int bias = (conf.format & ~SFX_PCM_FORMAT_LMASK) ? 0x8000 : 0; -	/* We use this only on a 16 bit level here */ - -	/* The two most extreme source frames we consider for a -	** destination frame  */ -	struct twochannel_data c_old = fs->ch_old; -	struct twochannel_data c_new = fs->ch_new; - -	int frames_read = 0; -	int frames_left; -	int write_offset; /* Iterator for translation */ -	int delay_frames = 0; /* Number of frames (dest buffer) at the beginning we skip */ - -	/* First, compute the number of frames we want to retrieve */ -	frames_nr = fs->spd.val * len; -	/* A little complicated since we must consider partial frames */ -	frames_nr += (fs->spd.nom * len -	              + (fs->scount.den - fs->scount.nom) /* remember that we may have leftovers */ -	              + (fs->spd.den - 1 /* round up */) -	             ) -	             / fs->spd.den; - -	ts->msecs = 0; - -	if (frames_nr > fs->buf_size) { -		fprintf(stderr, "%d (%d*%d + somethign) bytes, but only %d allowed!!!!!\n", -		        frames_nr * f->frame_size, -		        fs->spd.val, len, -		        fs->buf_size); -		BREAKPOINT(); -	} - -	if (fs->pending_review) { -		int newmode = PCM_FEED_EMPTY; /* empty unless a get_timestamp() tells otherwise */ - -		RELEASE_LOCK(); -		/* Retrieve timestamp */ -		if (f->get_timestamp) -			newmode = f->get_timestamp(f, ts); -		ACQUIRE_LOCK(); +void PCMFeedAudioStream::queryTimestamp() { +	if (_feed->get_timestamp) { +		sfx_timestamp_t stamp; +		int val = _feed->get_timestamp(_feed, &stamp); -		switch (newmode) { +		switch (val) {  		case PCM_FEED_TIMESTAMP: -			/* Compute the number of frames the returned timestamp is in the future: */ -			delay_frames = -			    sfx_timestamp_frame_diff(sfx_timestamp_renormalise(*ts, base_ts.frame_rate), -			                             base_ts); - -			if (delay_frames <= 0) -				/* Start ASAP, even if it's too late */ -				delay_frames = 0; -			else -				if (delay_frames > len) -					delay_frames = len; -			fs->pending_review = false; +			_gap = sfx_timestamp_frame_diff(stamp, _time); + +			if (_gap >= 0) +				_mode = FEED_MODE_ALIVE; +			else { +				// FIXME: I don't quite understand what FEED_MODE_RESTART is for. +				// The original DC mixer seemed to just stop and restart the stream. +				// But why? To catch up with lagging sound? +				_mode = FEED_MODE_RESTART; +				_time = sfx_new_timestamp(g_system->getMillis(), _feed->conf.rate); +				_gap = sfx_timestamp_frame_diff(stamp, _time); + +				if (_gap < 0) +					_gap = 0; +			}  			break; - -		case PCM_FEED_EMPTY: -			fs->mode = SFX_PCM_FEED_MODE_DEAD; -			// ...fall through...  		case PCM_FEED_IDLE: -			/* Clear audio buffer, if neccessary, and return */ -			if (!add_result) { -				memset(P->compbuf_l, 0, sizeof(int32) * len); -				memset(P->compbuf_r, 0, sizeof(int32) * len); -			} -			return; - -		default: -			error("[soft-mixer] Fatal: Invalid mode returned by PCM feed %s-%d's get_timestamp(): %d", -			        f->debug_name, f->debug_nr, newmode); +			_mode = FEED_MODE_IDLE; +			break; +		case PCM_FEED_EMPTY: +			_mode = FEED_MODE_DEAD; +			_gap = 0;  		} +	} else { +		_mode = FEED_MODE_DEAD; +		_gap = 0;  	} +} -	RELEASE_LOCK(); -	/* Make sure we have sufficient information */ -	if (frames_nr > delay_frames + fs->frame_bufstart) -		frames_read = -		    f->poll(f, wr_dest, -		            frames_nr -		            - delay_frames -		            - fs->frame_bufstart); - -	ACQUIRE_LOCK(); - -	frames_read += fs->frame_bufstart; -	frames_left = frames_read; - -	/* Reset in case of status update */ - -	/* Skip at the beginning: */ -	if (delay_frames) { -		if (!add_result) { -			memset(lchan, 0, sizeof(int32) * delay_frames); -			memset(rchan, 0, sizeof(int32) * delay_frames); -		} -		lchan += delay_frames; -		rchan += delay_frames; - -		len -= delay_frames; +static void U8_to_S16(byte *buf, int samples) { +	for (int i = samples - 1; i >= 0; i--) { +		buf[i * 2 + 1] = buf[i] - 0x80; +		buf[i * 2] = 0;  	} +} +int PCMFeedAudioStream::readBuffer(int16 *buffer, const int numSamples) { +	// FIXME: If ScummVM's mixer supported timestamps, then it would pass them +	// as a parameter to this function. But currently, it doesn't. Therefore, we +	// create a fake timestamp based on the current time. For comparison, a real +	// timestamp could be adjusted for pauses in sound processing. And it would +	// be synced for all audio streams. +	sfx_timestamp_t timestamp = sfx_new_timestamp(g_system->getMillis(), _feed->conf.rate); -#if (DEBUG >= 2) -	sciprintf("[soft-mixer] Examining %s-%x (frame size %d); read %d/%d/%d, re-using %d frames\n", -	          f->debug_name, f->debug_nr, frame_size, frames_read, frames_nr, -	          fs->buf_size, fs->frame_bufstart); -#endif - +	int channels, frames_req; +	int frames_recv = 0; -	if (conf.stereo == SFX_PCM_STEREO_LR) -		rsrc += (use_16) ? 2 : 1; -	/* Otherwise, we let both point to the same place */ +	_time = timestamp; +	channels = _feed->conf.stereo == SFX_PCM_MONO ? 1 : 2; +	frames_req = numSamples / channels; -#if (DEBUG >= 2) -	sciprintf("[soft-mixer] Stretching theoretical %d (physical %d) results to %d\n", frames_nr, frames_left, len); -#endif -	for (write_offset = 0; write_offset < len; write_offset++) { -		int leftsum = 0; /* Sum of any complete frames we used */ -		int rightsum = 0; +	while (frames_req != frames_recv) { +		int frames_left = frames_req - frames_recv; +		byte *buf_pos = ((byte *)buffer) + frames_recv * channels * 2; -		int left; /* Sum of the two most extreme source frames -			  ** we considered, i.e. the oldest and newest -			  ** one corresponding to the output frame we are -			  ** computing  */ -		int right; +		if (_mode == FEED_MODE_IDLE) +			queryTimestamp(); -		int frame_steps = fs->spd.val; -		int j; +		if (_mode == FEED_MODE_IDLE || _mode == FEED_MODE_DEAD) { +			memset(buf_pos, 0, frames_left * channels * 2); -		if (fs->scount.nom >= fs->scount.den) { -			fs->scount.nom -= fs->scount.den; /* Ensure fractional part < 1 */ -			++frame_steps; -		} -		if (frame_steps) -			c_old = c_new; - -#if 0 -		if (write_offset == 0) { -			READ_NEW_VALUES(); -			--frames_left; -#if (DEBUG >= 3) -			sciprintf("[soft-mixer] Initial read %d:%d\n", c_new.left, c_new.right); -#endif -			c_old = c_new; -		} -#endif - -		for (j = 0; j < frame_steps; j++) { -			READ_NEW_VALUES(); -			--frames_left; -#if (DEBUG >= 3) -			sciprintf("[soft-mixer] Step %d/%d made %d:%d\n", j, frame_steps, c_new.left, c_new.right); -#endif - -			/* The last frame will be subject to the fractional -			** part analysis, so we add it to 'left' and 'right' -			** later-- all others are added to (leftsum, rightsum). -			*/ -			if (j + 1 < frame_steps) { -				leftsum += c_new.left; -				rightsum += c_new.right; -			} +			_time = sfx_timestamp_add(_time, frames_left); +			break;  		} -		left = c_new.left * fs->scount.nom -		       + c_old.left * (fs->scount.den - fs->scount.nom); -		right = c_new.right * fs->scount.nom -		        + c_old.right * (fs->scount.den - fs->scount.nom); +		if (_gap) { +			int frames = _gap; -		/* Normalise */ -		left  /= fs->spd.den; -		right /= fs->spd.den; +			if (frames > frames_left) +				frames = frames_left; +			memset(buf_pos, 0, frames * channels * 2); -		leftsum += left; -		rightsum += right; - - -		/* Make sure to divide by the number of frames we added here */ -		if (frame_steps > 1) { -			leftsum  /= (frame_steps); -			rightsum /= (frame_steps); -		} +			_gap -= frames; +			frames_recv += frames; +			_time = sfx_timestamp_add(_time, frames); +		} else { +			int frames = _feed->poll(_feed, buf_pos, frames_left); +			if (_feed->conf.format == SFX_PCM_FORMAT_U8) +				U8_to_S16(buf_pos, frames * channels); -#if (DEBUG >= 3) -		sciprintf("[soft-mixer] Ultimate result: %d:%d (frac %d:%d)\n", leftsum, rightsum, left, right); -#endif +			frames_recv += frames; +			_time = sfx_timestamp_add(_time, frames); -		if (add_result) { -			*(lchan++) += leftsum; -			*(rchan++) += rightsum; -		} else { -			*(lchan++) = leftsum; -			*(rchan++) = rightsum; +			if (frames < frames_left) +				queryTimestamp();  		} - -		fs->scount.nom += fs->spd.nom; /* Count up fractional part */  	} -	fs->ch_old = c_old; -	fs->ch_new = c_new; +	return numSamples; +} -	/* If neccessary, zero out the rest */ -	if (write_offset < len && !add_result) { -		memset(lchan, 0, sizeof(int32) * (len - write_offset)); -		memset(rchan, 0, sizeof(int32) * (len - write_offset)); +void mixer_subscribe(sfx_pcm_feed_t *feed) { +	if ((feed->conf.format != SFX_PCM_FORMAT_S16_NATIVE) && (feed->conf.format != SFX_PCM_FORMAT_U8)) { +		error("[soft-mixer] Unsupported feed format %d", feed->conf.format);  	} +	 +	PCMFeedAudioStream *newStream = new PCMFeedAudioStream(feed); -	/* Save whether we have a partial frame still stored */ -	fs->frame_bufstart = frames_left; - -	if (frames_left) { -		xx_offset = ((frames_read - frames_left) * f->frame_size); -		xx_size = frames_left * f->frame_size; -		if (xx_offset + xx_size -		        >= fs->buf_size * f->frame_size) { -			fprintf(stderr, "offset %d >= max %d!\n", -			        (xx_offset + xx_size), fs->buf_size * f->frame_size); -			BREAKPOINT(); -		} +	// FIXME: Is this sound type appropriate? The mixer seems to handle music, too. +	g_system->getMixer()->playInputStream(Audio::Mixer::kSFXSoundType, 0, newStream); -		memmove(fs->buf, -		        fs->buf + ((frames_read - frames_left) * f->frame_size), -		        frames_left * f->frame_size); -	} -#if (DEBUG >= 2) -	sciprintf("[soft-mixer] Leaving %d over\n", fs->frame_bufstart); -#endif - -	if (frames_read + delay_frames < frames_nr) { -		if (f->get_timestamp) /* Can resume? */ -			fs->pending_review = true; -		else -			fs->mode = SFX_PCM_FEED_MODE_DEAD; /* Done. */ -	} +	debug(2, "[soft-mixer] Subscribed %s-%x (%d Hz, %d/%x)", +	          feed->debug_name, feed->debug_nr, feed->conf.rate, feed->conf.stereo, feed->conf.format);  } -static int mix_process_linear(sfx_pcm_mixer_t *self) { -	ACQUIRE_LOCK(); -	{ -		int frames_skip; /* Number of frames to discard, rather than to emit */ -		int buflen = mix_compute_buf_len(self, &frames_skip); /* Compute # of frames we must compute and write */ -		int fake_buflen; -		int timestamp_max_delta = 0; -		int have_timestamp = 0; -		sfx_timestamp_t start_timestamp; /* The timestamp at which the first frame will be played */ -		sfx_timestamp_t min_timestamp; -		min_timestamp.msecs = 0; -		sfx_timestamp_t timestamp; - -//		if (self->dev->get_output_timestamp) -//			start_timestamp = self->dev->get_output_timestamp(self->dev); -//		else -			start_timestamp = sfx_new_timestamp(g_system->getMillis(), P->conf.rate); - -		if ((P->outbuf) && (P->lastbuf_len)) { -			sfx_timestamp_t ts; -			int rv; - -			if (P->have_outbuf_timestamp) { -				ts = sfx_timestamp_renormalise(P->outbuf_timestamp, P->conf.rate); -			} -			const int totalBufSize = P->lastbuf_len * P->_framesize; -			byte *buf = new byte[totalBufSize]; -			if (!buf) { -				RELEASE_LOCK(); -				return rv; /* error */ -			} -			memcpy(buf, P->outbuf, totalBufSize); -			P->_audioStream->queueBuffer(buf, totalBufSize); -			// TODO: We currently ignore the timestamp: -			//    (P->have_outbuf_timestamp) ? &ts : NULL -			// Re-add support for that? Maybe by enhancing the ScummVM mixer (i.e., -			// expanding the getTotalPlayTime() audiostream API to "proper" timestamps?) -		} +int mixer_process() { +	// TODO +/* +	feed_state_t *state, *state_next; -#if (DEBUG >= 1) -		if (P->_feeds.size()) -			sciprintf("[soft-mixer] Mixing %d output frames on %d input feeds\n", buflen, P->_feeds.size()); -#endif -		if (!P->_feeds.empty()) { -			/* Below, we read out all feeds in case we have to skip frames first, then get the -			** most current sound. 'fake_buflen' is either the actual buflen (for the last iteration) -			** or a fraction of the buf length to discard.  */ -			do { -				if (frames_skip) { -					if (frames_skip > BUF_SIZE) -						fake_buflen = BUF_SIZE; -					else -						fake_buflen = frames_skip; - -					frames_skip -= fake_buflen; -				} else { -					fake_buflen = buflen; -					frames_skip = -1; /* Mark us as being completely done */ -				} - -				Common::List<PCMFeedState>::iterator iter = P->_feeds.begin(); -				for (iter = P->_feeds.begin(); iter != P->_feeds.end(); ++iter) { -					mix_compute_input_linear(self, iter, -					                         fake_buflen, ×tamp, -					                         start_timestamp); - -					if (timestamp.msecs > 0) { -						if (have_timestamp) { -							int diff = sfx_timestamp_msecs_diff(min_timestamp, timestamp); -							if (diff > 0) { -								/* New earlier timestamp */ -								timestamp = min_timestamp; -								timestamp_max_delta += diff; -							} else if (diff > timestamp_max_delta) -								timestamp_max_delta = diff; -							/* New max delta for timestamp */ -						} else { -							min_timestamp = timestamp; -							have_timestamp = 1; -						} -					} -				} -				/* Destroy all feeds we finished */ -				iter = P->_feeds.begin(); -				while (iter != P->_feeds.end()) { -					if (iter->mode == SFX_PCM_FEED_MODE_DEAD) -						iter = P->_feeds.erase(iter); -					else -						++iter; -				} -			} while (frames_skip >= 0); - -		} else { /* Zero it out */ -			memset(P->compbuf_l, 0, sizeof(int32) * buflen); -			memset(P->compbuf_r, 0, sizeof(int32) * buflen); -		} +	TAILQ_FOREACH(state, &feeds, entry) { +		snd_stream_poll(handle); +	} -#if (DEBUG >= 1) -		if (P->_feeds.size()) -			sciprintf("[soft-mixer] Done mixing for this session, the result will be our next output buffer\n"); -#endif - -#if (DEBUG >= 3) -		if (P->_feeds.size()) { -			int i; -			sciprintf("[soft-mixer] Intermediate representation:\n"); -			for (i = 0; i < buflen; i++) -				sciprintf("[soft-mixer] Offset %d:\t[%04x:%04x]\t%d:%d\n", i, -				          P->compbuf_l[i] & 0xffff, P->compbuf_r[i] & 0xffff, -				          P->compbuf_l[i], P->compbuf_r[i]); +	state = TAILQ_FIRST(&feeds); +	while (state) { +		state_next = TAILQ_NEXT(state, entry); +		if (_mode == FEED_MODE_DEAD) { +			snd_stream_stop(handle); +			snd_stream_destroy(handle); +			feed->destroy(feed); +			TAILQ_REMOVE(&feeds, state, entry);  		} -#endif - -		if (timestamp_max_delta > TIMESTAMP_MAX_ALLOWED_DELTA) -			sciprintf("[soft-mixer] Warning: Difference in timestamps between audio feeds is %d ms\n", timestamp_max_delta); - -		mix_compute_output(self, buflen); -		P->lastbuf_len = buflen; - -		/* Finalize */ -		mix_swap_buffers(self); -		if (have_timestamp) -			P->outbuf_timestamp = sfx_timestamp_add(min_timestamp, -			                                        timestamp_max_delta * 500); -		P->have_outbuf_timestamp = have_timestamp; - +		else if (_mode == FEED_MODE_RESTART) { +			snd_stream_stop(handle); +			snd_stream_start(handle, feed->conf.rate, +					 feed->conf.stereo != SFX_PCM_MONO); +			_mode = FEED_MODE_ALIVE; +		} +		state = state_next;  	} -	RELEASE_LOCK(); +*/  	return SFX_OK;  } -sfx_pcm_mixer_t sfx_pcm_mixer_soft_linear = { -	"soft-linear", -	"0.1", - -	mix_init, -	mix_exit, -	mix_subscribe, -	mix_process_linear, - -	NULL -}; - -sfx_pcm_mixer_t *getMixer() { return &sfx_pcm_mixer_soft_linear; } -  } // End of namespace Sci diff --git a/engines/sci/sfx/mixer.h b/engines/sci/sfx/mixer.h index c68fc29936..8fab69bded 100644 --- a/engines/sci/sfx/mixer.h +++ b/engines/sci/sfx/mixer.h @@ -30,53 +30,21 @@  namespace Sci { -struct sfx_pcm_mixer_t { -	/* Mixers are the heart of all matters PCM. They take PCM data from subscribed feeds, -	** mix it (hence the name) and ask the pcm device they are attached to to play the -	** result.  */ - -	const char *name; -	const char *version; - -	int (*init)(sfx_pcm_mixer_t *self); -	/* Initialises the mixer -	** Parameters: (sfx_pcm_mixer_t *) self: Self reference -	** Returns   : (int) SFX_OK on success, SFX_ERROR otherwise -	*/ - -	void (*exit)(sfx_pcm_mixer_t *self); -	/* Uninitialises the mixer -	** Parameters: (sfx_pcm_mixer_t *) self: Self reference -	** Also uninitialises all feeds and the attached output device. -	*/ - -	void (*subscribe)(sfx_pcm_mixer_t *self, sfx_pcm_feed_t *feed); -	/* Subscribes the mixer to a new feed -	** Parameters: (sfx_pcm_mixer_t *) self: Self reference -	**             (sfx_pcm_feed_t *) feed: The feed to subscribe to -	*/ - -	int (*process)(sfx_pcm_mixer_t *self); -	/* Processes all feeds, mixes their results, and passes everything to the output device -	** Returns  : (int) SFX_OK on success, SFX_ERROR otherwise (output device error or -	**                  internal assertion failure) -	** Effects  : All feeds are poll()ed, and the device is asked to output(). Buffer size -	**            depends on the time that has passed since the last call to process(), if -	**            any. -	*/ - -	void *private_bits; -}; - -sfx_pcm_mixer_t *sfx_pcm_find_mixer(char *name); -/* Looks up a mixer by name, or a default mixer -** Parameters: (char *) name: Name of the mixer to look for, or NULL to -**                            take a default -*/ - -extern sfx_pcm_mixer_t *mixer; /* _THE_ global pcm mixer */ - -sfx_pcm_mixer_t *getMixer(); +/** + * Subscribes the mixer to a new feed. + * @param feed	The feed to subscribe to + */ +void mixer_subscribe(sfx_pcm_feed_t *feed); + +/** + * Processes all feeds, mixes their results, and passes everything to the output device. + * Returns  : (int) SFX_OK on success, SFX_ERROR otherwise (output device error or + *                  internal assertion failure) + * Effects  : All feeds are poll()ed, and the device is asked to output(). Buffer size + *            depends on the time that has passed since the last call to process(), if + *            any. + */ +int mixer_process();  } // End of namespace Sci diff --git a/engines/sci/sfx/mixer/test.cpp b/engines/sci/sfx/mixer/test.cpp deleted file mode 100644 index 8d7f31e059..0000000000 --- a/engines/sci/sfx/mixer/test.cpp +++ /dev/null @@ -1,347 +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$ - * - */ - -/* Mixer inspection/test program */ - - -#include "../mixer.h" -#include <time.h> - -namespace Sci { - -#if 0 -sfx_pcm_mixer_t *mix; - -int dev_init(sfx_pcm_device_t *self); -void dev_exit(sfx_pcm_device_t *self); -int dev_option(sfx_pcm_device_t *self, char *name, char *value); -int dev_output(sfx_pcm_device_t *self, byte *buf, int count); - -#define MIN_OUTPUT 128 -/* Min amount of output to compute */ - -#define DEVICES_NR 10 - -sfx_pcm_device_t devices[DEVICES_NR] = { -	{ "test-1", "0", dev_init, dev_exit, dev_option, dev_output, -		{ 200, SFX_PCM_MONO, SFX_PCM_FORMAT_U8 }, 1024, NULL }, -#if (DEVICES_NR > 1) -	{ "test-2", "0", dev_init, dev_exit, dev_option, dev_output, { 200, SFX_PCM_STEREO_LR, SFX_PCM_FORMAT_U8 }, 1024, NULL -	}, -	{ "test-3", "0", dev_init, dev_exit, dev_option, dev_output, -	  { 200, SFX_PCM_STEREO_RL, SFX_PCM_FORMAT_U8 }, 1024, NULL }, -	{ "test-4", "0", dev_init, dev_exit, dev_option, dev_output, -	  { 200, SFX_PCM_MONO, SFX_PCM_FORMAT_S8 }, 1024, NULL }, -	{ "test-5", "0", dev_init, dev_exit, dev_option, dev_output, -	  { 200, SFX_PCM_MONO, SFX_PCM_FORMAT_U16_LE }, 1024, NULL }, -	{ "test-6", "0", dev_init, dev_exit, dev_option, dev_output, -	  { 200, SFX_PCM_MONO, SFX_PCM_FORMAT_U16_BE }, 1024, NULL }, -	{ "test-7", "0", dev_init, dev_exit, dev_option, dev_output, -	  { 200, SFX_PCM_MONO, SFX_PCM_FORMAT_S16_LE }, 1024, NULL }, -	{ "test-8", "0", dev_init, dev_exit, dev_option, dev_output, -	  { 200, SFX_PCM_MONO, SFX_PCM_FORMAT_S16_BE }, 1024, NULL }, -	{ "test-9", "0", dev_init, dev_exit, dev_option, dev_output, -	  { 200, SFX_PCM_STEREO_RL, SFX_PCM_FORMAT_S16_LE }, 1024, NULL }, -	{ "test-10", "0", dev_init, dev_exit, dev_option, dev_output, -	  { 200, SFX_PCM_STEREO_LR, SFX_PCM_FORMAT_U16_BE }, 1024, NULL } -#endif -}; - -int output_count; - -int dev_init(sfx_pcm_device_t *self) { -	output_count = 0; - -	fprintf(stderr, "[DEV] Initialised device %p as follows:\n" -	        "\trate = %d\n" -	        "\tstereo = %s\n" -	        "\tbias = %x\n" -	        "\tbytes/sample = %d\n" -	        "\tendianness = %s\n", -	        self, -	        self->conf.rate, -	        self->conf.stereo ? ((self->conf.stereo == SFX_PCM_STEREO_LR) ? "Left, Right" : "Right, Left") : "No", -			        self->conf.format & ~SFX_PCM_FORMAT_LMASK, -			        (self->conf.format & SFX_PCM_FORMAT_16) ? 2 : 1, -			        ((self->conf.format & SFX_PCM_FORMAT_ENDIANNESS) == SFX_PCM_FORMAT_BE) ? "big" : "little"); -	return 0; -} - -void dev_exit(sfx_pcm_device_t *self) { -	fprintf(stderr, "[DEV] Uninitialising device\n"); -} - -int dev_option(sfx_pcm_device_t *self, char *name, char *value) { -	fprintf(stderr, "[DEV] Set option '%s' to '%s'\n", name, value); -	return 0; -} - -int dev_output_enabled = 0; - -int dev_output(sfx_pcm_device_t *self, byte *buf, int count) { -	int mono_sample_size = ((self->conf.format & SFX_PCM_FORMAT_16) ? 2 : 1); -	int sample_size = (self->conf.stereo ? 2 : 1) * mono_sample_size; -	int bias = self->conf.format & ~SFX_PCM_FORMAT_LMASK; -	int is_bigendian = (self->conf.format & SFX_PCM_FORMAT_ENDIANNESS) == SFX_PCM_FORMAT_BE; -	byte *left_channel = buf; -	byte *right_channel = buf; - -	if (!dev_output_enabled) -		return 0; - -	if (self->conf.format & SFX_PCM_FORMAT_16) -		bias <<= 8; - -	if (self->conf.stereo == SFX_PCM_STEREO_LR) -		right_channel += mono_sample_size; -	if (self->conf.stereo == SFX_PCM_STEREO_RL) -		left_channel += mono_sample_size; - -	while (count--) { -		int right = right_channel[0]; -		int left = left_channel[0]; -		int second_byte = ((self->conf.format & SFX_PCM_FORMAT_16) ? 1 : 0); - -		if (second_byte) { - -			if (is_bigendian) { -				left = left << 8 | left_channel[1]; -				right = right << 8 | right_channel[1]; -			} else { -				left = left | left_channel[1] << 8; -				right = right | right_channel[1] << 8; -			} -		} - -		left -= bias; -		right -= bias; - -		if (!second_byte) { -			left <<= 8; -			right <<= 8; -		} - -		fprintf(stderr, "[DEV] %p play %04x:\t%04x %04x\n", self, output_count++, left & 0xffff, right & 0xffff); - -		left_channel += sample_size; -		right_channel += sample_size; -	} -	return 0; -} - -/* Feeds for debugging */ - -struct int_struct { -	int i; -}; - -int feed_poll(sfx_pcm_feed_t *self, byte *dest, int size); -void feed_destroy(sfx_pcm_feed_t *self); - -int_struct private_bits[10] = { -	{0}, -	{0}, -	{0}, -	{0}, -	{0}, -	{0}, -	{0}, -	{0}, -	{0} -}; - - -struct sample_feed_t { -	int start; -	int samples_nr; -	byte *data; -}; - -#define FEEDS_NR 4 - -sfx_pcm_feed_t feeds[FEEDS_NR] = { -	{ feed_poll, feed_destroy, &(private_bits[0]), -		{ 200, SFX_PCM_MONO, SFX_PCM_FORMAT_S8 }, "test-feed", 0, 0} -#if FEEDS_NR > 1 -	, { feed_poll, feed_destroy, &(private_bits[1]), -	    { 400, SFX_PCM_MONO, SFX_PCM_FORMAT_U8 }, "test-feed", 1, 0} -#endif -#if FEEDS_NR > 2 -	, { feed_poll, feed_destroy, &(private_bits[2]), -	    { 20, SFX_PCM_MONO, SFX_PCM_FORMAT_S16_LE }, "test-feed", 2, 0} -#endif -#if FEEDS_NR > 3 -	, { feed_poll, feed_destroy, &(private_bits[3]), -	    { 150, SFX_PCM_STEREO_LR, SFX_PCM_FORMAT_S8 }, "test-feed", 3, 0} -#endif -	/* -	,{ feed_poll, feed_destroy, &(private_bits[4]), -	  {}, "test-feed", 4, 0} -	,{ feed_poll, feed_destroy, &(private_bits[5]), -	  {}, "test-feed", 5, 0} -	*/ -}; - -byte feed_data_0[] = {0xfd, 0xfe, 0xff, 0, 1, 2, 3, 4, 5, 6}; -byte feed_data_1[] = {0x80, 0x90, 0xA0, 0xB0, 0xC0, -                      0xD0, 0xD0, 0xC0, 0xB0, 0xA0, 0x90, 0x80 -                     }; -byte feed_data_2[] = {0x00, 0x00, -                      0x00, 0x80, -                      0xe8, 0x03 -                     }; -byte feed_data_3[] = {0x00, 0x10, -                      0x01, 0x20, -                      0x02, 0x30 -                     }; - -sample_feed_t sample_feeds[FEEDS_NR] = { -	{ 1, 10, feed_data_0 } -#if FEEDS_NR > 1 -	, { 21, 12, feed_data_1 } -#endif -#if FEEDS_NR > 2 -	, { 0, 3, feed_data_2 } -#endif -#if FEEDS_NR > 3 -	, { 40, 3, feed_data_3 } -#endif -}; - -void feed_destroy(sfx_pcm_feed_t *self) { -	int_struct *s = (int_struct *) self->internal; -	s->i = 0; /* reset */ -} - - -int feed_poll(sfx_pcm_feed_t *self, byte *dest, int size) { -	int_struct *s = (int_struct *) self->internal; -	int sample_size = self->sample_size; -	sample_feed_t *data = &(sample_feeds[self->debug_nr]); -	int bias = self->conf.format & ~SFX_PCM_FORMAT_LMASK; -	byte neutral[4] = {0, 0, 0, 0}; -	int i; -	fprintf(stderr, "[feed] Asked for %d at %p, ss=%d\n", size, dest, sample_size); -	if (bias) { -		byte first = bias >> 8; -		byte second = bias & 0xff; - -		if ((self->conf.format & SFX_PCM_FORMAT_ENDIANNESS) == SFX_PCM_FORMAT_LE) { -			int t = first; -			first = second; -			second = t; -		} - -		if (self->conf.format & SFX_PCM_FORMAT_16) { -			neutral[0] = first; -			neutral[1] = second; -			neutral[2] = first; -			neutral[3] = second; -		} else { -			neutral[0] = bias; -			neutral[1] = bias; -		} -	} - -	for (i = 0; i < size; i++) { -		int t = s->i - data->start; - -		if (t >= data->samples_nr) -			return i; - -		if (t >= 0) -			memcpy(dest, data->data + t * sample_size, sample_size); -		else -			memcpy(dest, neutral, sample_size); - -		dest += sample_size; -		s->i++; -	} -	return size; -} - - - - -extern FILE *con_file; - -#define DELAY	usleep((rand() / (RAND_MAX / 250L))) - - -int main(int argc, char **argv) { -	int dev_nr; - -	mix = sfx_pcm_find_mixer(NULL); - -	if (!mix) { -		fprintf(stderr, "Error: Could not find a mixer!\n"); -		return 1; -	} else { -		fprintf(stderr, "Running %s, v%s\n", -		        mix->name, mix->version); -	} -	con_file = stderr; - -	srand(time(NULL)); - -	for (dev_nr = 0; dev_nr < DEVICES_NR; dev_nr++) { -		sfx_pcm_device_t *dev = &(devices[dev_nr++]); -		int j; -		dev->init(dev); -		mix->init(mix, dev); - -		dev_output_enabled = 0; -		/* Prime it to our timing */ -		for (j = 0; j < 250; j++) { -			DELAY; -			mix->process(mix); -		} -		dev_output_enabled = 1; - -		fprintf(stderr, "[test] Subscribing...\n"); - -		for (j = 0; j < FEEDS_NR; j++) -			mix->subscribe(mix, &(feeds[j])); - -		fprintf(stderr, "[test] Subscribed %d feeds.\n", -		        FEEDS_NR); - -		while (output_count < MIN_OUTPUT) { -			DELAY; -			mix->process(mix); -			fprintf(stderr, "<tick>\n"); -		} - -		fprintf(stderr, "[test] Preparing finalisation\n"); -		mix->exit(mix); -		fprintf(stderr, "[test] Mixer uninitialised\n"); -	} -} - -#else -int main() {} -#endif - -} // End of namespace Sci diff --git a/engines/sci/sfx/player/polled.cpp b/engines/sci/sfx/player/polled.cpp index e0496008c9..887ef6327d 100644 --- a/engines/sci/sfx/player/polled.cpp +++ b/engines/sci/sfx/player/polled.cpp @@ -161,9 +161,6 @@ static int pp_set_option(char *name, char *value) {  static int pp_init(ResourceManager *resmgr, int expected_latency) {  	Resource *res = NULL, *res2 = NULL; -	if (!mixer) -		return SFX_ERROR; -  	/* FIXME Temporary hack to detect Amiga games. */  	if (!Common::File::exists("bank.001"))  		seq = sfx_find_softseq(NULL); @@ -196,7 +193,7 @@ static int pp_init(ResourceManager *resmgr, int expected_latency) {  	pcmfeed.conf = seq->pcm_conf;  	seq->set_volume(seq, volume); -	mixer->subscribe(mixer, &pcmfeed); +	mixer_subscribe(&pcmfeed);  	sfx_player_polled.polyphony = seq->polyphony;  	return SFX_OK; | 
