aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/sfx
diff options
context:
space:
mode:
authorMax Horn2009-03-01 21:23:44 +0000
committerMax Horn2009-03-01 21:23:44 +0000
commit00db87563ae01ef60a86c4da6c7b376e74f10a8b (patch)
tree0d4c102304899c32a79cb769a4b85bfa4f275ee6 /engines/sci/sfx
parenta718713925ef79ddfa9dd545134a46eb918441ba (diff)
downloadscummvm-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.cpp37
-rw-r--r--engines/sci/sfx/mixer.cpp937
-rw-r--r--engines/sci/sfx/mixer.h62
-rw-r--r--engines/sci/sfx/mixer/test.cpp347
-rw-r--r--engines/sci/sfx/player/polled.cpp5
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, &timestamp,
- 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;