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 /engines/sci/sfx | |
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
Diffstat (limited to 'engines/sci/sfx')
-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; |