[Scummvm-cvs-logs] SF.net SVN: scummvm:[38949] scummvm/trunk/engines/sci
fingolfin at users.sourceforge.net
fingolfin at users.sourceforge.net
Sat Feb 28 07:48:53 CET 2009
Revision: 38949
http://scummvm.svn.sourceforge.net/scummvm/?rev=38949&view=rev
Author: fingolfin
Date: 2009-02-28 06:48:53 +0000 (Sat, 28 Feb 2009)
Log Message:
-----------
SCI: Get rid around the first layer around the ScummVM audio mixer. Also resolve the FIXME about releasing the mixer channel we allocated
Modified Paths:
--------------
scummvm/trunk/engines/sci/module.mk
scummvm/trunk/engines/sci/sfx/core.cpp
scummvm/trunk/engines/sci/sfx/iterator.cpp
scummvm/trunk/engines/sci/sfx/mixer.h
scummvm/trunk/engines/sci/sfx/sfx_pcm.h
Added Paths:
-----------
scummvm/trunk/engines/sci/sfx/mixer.cpp
Removed Paths:
-------------
scummvm/trunk/engines/sci/sfx/mixer/soft.cpp
scummvm/trunk/engines/sci/sfx/pcm_device.cpp
Modified: scummvm/trunk/engines/sci/module.mk
===================================================================
--- scummvm/trunk/engines/sci/module.mk 2009-02-28 06:21:24 UTC (rev 38948)
+++ scummvm/trunk/engines/sci/module.mk 2009-02-28 06:48:53 UTC (rev 38949)
@@ -67,12 +67,11 @@
sfx/adlib.o \
sfx/core.o \
sfx/iterator.o \
- sfx/pcm_device.o \
+ sfx/mixer.o \
sfx/pcm-iterator.o \
sfx/songlib.o \
sfx/time.o \
sfx/device/devices.o \
- sfx/mixer/soft.o \
sfx/player/players.o \
sfx/player/polled.o \
sfx/player/realtime.o \
Modified: scummvm/trunk/engines/sci/sfx/core.cpp
===================================================================
--- scummvm/trunk/engines/sci/sfx/core.cpp 2009-02-28 06:21:24 UTC (rev 38948)
+++ scummvm/trunk/engines/sci/sfx/core.cpp 2009-02-28 06:48:53 UTC (rev 38949)
@@ -44,11 +44,10 @@
static sfx_player_t *player = NULL;
sfx_pcm_mixer_t *mixer = NULL;
-static sfx_pcm_device_t *pcm_device = NULL;
-extern sfx_pcm_device_t sfx_pcm_driver_scummvm;
+
int sfx_pcm_available() {
- return (pcm_device != NULL);
+ return (mixer != NULL);
}
void sfx_reset_player() {
@@ -375,14 +374,12 @@
if (flags & SFX_STATE_FLAG_NOSOUND) {
mixer = NULL;
- pcm_device = NULL;
player = NULL;
sciprintf("[SFX] Sound disabled.\n");
return;
}
mixer = getMixer();
- pcm_device = &sfx_pcm_driver_scummvm;
player = sfx_find_player(NULL);
@@ -390,25 +387,13 @@
fprintf(stderr, "[sfx-core] Initialising: flags=%x\n", flags);
#endif
- /*----------------*/
- /* Initialise PCM */
- /*----------------*/
+ /*------------------*/
+ /* Initialise mixer */
+ /*------------------*/
- if (!pcm_device) {
- sciprintf("[SFX] No PCM device found, disabling PCM support\n");
+ if (mixer->init(mixer)) {
+ sciprintf("[SFX] Failed to initialise PCM mixer; disabling PCM support\n");
mixer = NULL;
- } else {
- if (pcm_device->init(pcm_device)) {
- sciprintf("[SFX] Failed to open PCM device, disabling PCM support\n");
- mixer = NULL;
- pcm_device = NULL;
- } else {
- if (mixer->init(mixer, pcm_device)) {
- sciprintf("[SFX] Failed to initialise PCM mixer; disabling PCM support\n");
- mixer = NULL;
- pcm_device = NULL;
- }
- }
}
/*-------------------*/
@@ -433,14 +418,13 @@
/*------------------*/
// We initialise the timer last, so there is no possibility of the
- // timer callback being triggered while the pcm_device or player are
+ // timer callback being triggered while the mixer or player are
// still being initialized.
- if (pcm_device || (player && player->maintenance)) {
+ if (mixer || (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");
- pcm_device = NULL;
player = NULL;
mixer = NULL;
return;
@@ -462,11 +446,6 @@
song_lib_free(self->songlib);
- // FIXME: We need a pcm_device->exit() function to release the
- // mixer channel allocated for pcm_device in ScummVM's mixer.
- pcm_device = NULL;
-
-
/* WARNING: The mixer may hold feeds from the
** player, so we must stop the mixer BEFORE
** stopping the player. */
Modified: scummvm/trunk/engines/sci/sfx/iterator.cpp
===================================================================
--- scummvm/trunk/engines/sci/sfx/iterator.cpp 2009-02-28 06:21:24 UTC (rev 38948)
+++ scummvm/trunk/engines/sci/sfx/iterator.cpp 2009-02-28 06:48:53 UTC (rev 38949)
@@ -676,7 +676,7 @@
#define SCI01_INVALID_DEVICE 0xff
-/* First index determines whether DSP output is supported */
+/* Second index determines whether PCM output is supported */
static int sci0_to_sci1_device_map[][2] = {
{0x06, 0x0c}, /* MT-32 */
{0xff, 0xff}, /* YM FB-01 */
Deleted: scummvm/trunk/engines/sci/sfx/mixer/soft.cpp
===================================================================
--- scummvm/trunk/engines/sci/sfx/mixer/soft.cpp 2009-02-28 06:21:24 UTC (rev 38948)
+++ scummvm/trunk/engines/sci/sfx/mixer/soft.cpp 2009-02-28 06:48:53 UTC (rev 38949)
@@ -1,926 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "common/mutex.h"
-#include "common/system.h"
-
-#include "sci/tools.h"
-#include "sci/sfx/mixer.h"
-#include "sci/sci_memory.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()
-
-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 */
-
- /* Pause data */
- int paused;
-};
-
-#define P ((struct mixer_private *)(self->private_bits))
-
-
-static int mix_init(sfx_pcm_mixer_t *self, sfx_pcm_device_t *device) {
- self->dev = device;
- self->private_bits = new mixer_private();
- P->outbuf = P->writebuf = NULL;
- P->lastbuf_len = 0;
- P->compbuf_l = (int32*)sci_malloc(sizeof(int32) * device->buf_size);
- P->compbuf_r = (int32*)sci_malloc(sizeof(int32) * device->buf_size);
- P->played_this_second = 0;
- P->paused = 0;
-
- return SFX_OK;
-}
-
-static inline uint gcd(uint a, uint b) {
- while (a) {
- uint c = b % a;
- b = a;
- a = c;
- }
- 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;
-}
-
-static void mix_subscribe(sfx_pcm_mixer_t *self, sfx_pcm_feed_t *feed) {
- sfx_pcm_feed_state_t *fs;
- ACQUIRE_LOCK();
- if (!self->feeds) {
- self->feeds_allocd = 2;
- self->feeds = (sfx_pcm_feed_state_t*)sci_malloc(sizeof(sfx_pcm_feed_state_t)
- * self->feeds_allocd);
- } else if (self->feeds_allocd == self->feeds_nr) {
- self->feeds_allocd += 2;
- self->feeds = (sfx_pcm_feed_state_t*)sci_realloc(self->feeds,
- sizeof(sfx_pcm_feed_state_t)
- * self->feeds_allocd);
- }
-
- fs = self->feeds + self->feeds_nr++;
- fs->feed = feed;
-
- feed->frame_size = SFX_PCM_FRAME_SIZE(feed->conf);
-
- /* fs->buf_size = (self->dev->buf_size
- * (feed->conf.rate
- + self->dev->conf.rate - 1))
- / self->dev->conf.rate;
- */
- /* For the sake of people without 64 bit CPUs: */
- fs->buf_size = 2 + /* Additional safety */
- (self->dev->buf_size *
- (1 + (feed->conf.rate / self->dev->conf.rate)));
- fprintf(stderr, " ---> %d/%d/%d/%d = %d\n",
- self->dev->buf_size,
- feed->conf.rate,
- self->dev->conf.rate,
- feed->frame_size,
- fs->buf_size);
-
- fs->buf = (byte*)sci_malloc(fs->buf_size * feed->frame_size);
- fprintf(stderr, " ---> --> %d for %p at %p\n", fs->buf_size * feed->frame_size, (void *)fs, (void *)fs->buf);
- {
- int i;
- for (i = 0; i < fs->buf_size * feed->frame_size; i++)
- fs->buf[i] = 0xa5;
- }
- fs->scount = urat(0, 1);
- fs->spd = urat(feed->conf.rate, self->dev->conf.rate);
- fs->scount.den = fs->spd.den;
- fs->ch_old.left = 0;
- fs->ch_old.right = 0;
- fs->ch_new.left = 0;
- fs->ch_new.right = 0;
- fs->mode = SFX_PCM_FEED_MODE_ALIVE;
-
- /* If the feed can't provide us with timestamps, we don't need to wait for it to do so */
- fs->pending_review = (feed->get_timestamp) ? 1 : 0;
-
- fs->frame_bufstart = 0;
-
-#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
- RELEASE_LOCK();
-}
-
-
-static void _mix_unsubscribe(sfx_pcm_mixer_t *self, sfx_pcm_feed_t *feed) {
- int i;
-#ifdef DEBUG
- sciprintf("[soft-mixer] Unsubscribing %s-%x\n", feed->debug_name, feed->debug_nr);
-#endif
- for (i = 0; i < self->feeds_nr; i++) {
- sfx_pcm_feed_state_t *fs = self->feeds + i;
-
- if (fs->feed == feed) {
- feed->destroy(feed);
-
- if (fs->buf)
- free(fs->buf);
-
- self->feeds_nr--;
-
- /* Copy topmost into deleted so that we don't have any holes */
- if (i != self->feeds_nr)
- self->feeds[i] = self->feeds[self->feeds_nr];
-
- if (self->feeds_allocd > 8 && self->feeds_allocd > (self->feeds_nr << 1)) {
- /* Limit memory waste */
- self->feeds_allocd >>= 1;
- self->feeds
- = (sfx_pcm_feed_state_t*)sci_realloc(self->feeds,
- sizeof(sfx_pcm_feed_state_t)
- * self->feeds_allocd);
- }
-
- for (i = 0; i < self->feeds_nr; i++)
- fprintf(stderr, " Feed #%d: %s-%x\n",
- i, self->feeds[i].feed->debug_name,
- self->feeds[i].feed->debug_nr);
-
- return;
- }
- }
-
- fprintf(stderr, "[sfx-mixer] Assertion failed: Deleting invalid feed %p out of %d\n",
- (void *)feed, self->feeds_nr);
-
- BREAKPOINT();
-}
-
-static void mix_exit(sfx_pcm_mixer_t *self) {
- ACQUIRE_LOCK();
- while (self->feeds_nr)
- _mix_unsubscribe(self, self->feeds[0].feed);
- RELEASE_LOCK();
-
- 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;
- sfx_pcm_config_t conf = self->dev->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(self->dev->buf_size * frame_size + 4);
-
- if (conf.stereo) {
- if (conf.stereo == SFX_PCM_STEREO_RL) {
- lchan = P->writebuf + ((use_16) ? 2 : 1);
- rchan = P->writebuf;
- } else {
- lchan = P->writebuf;
- rchan = P->writebuf + ((use_16) ? 2 : 1);
- }
- } else
- lchan = P->writebuf;
-
-
- 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) {
- if (SFX_PCM_FORMAT_LE == (conf.format & SFX_PCM_FORMAT_ENDIANNESS)) {
- lchan[0] = left & 0xff;
- lchan[1] = (left >> 8) & 0xff;
- rchan[0] = right & 0xff;
- rchan[1] = (right >> 8) & 0xff;
- } else {
- lchan[1] = left & 0xff;
- lchan[0] = (left >> 8) & 0xff;
- rchan[1] = right & 0xff;
- rchan[0] = (right >> 8) & 0xff;
- }
-
- 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) {
- if (SFX_PCM_FORMAT_LE == (conf.format & SFX_PCM_FORMAT_ENDIANNESS)) {
- lchan[0] = left & 0xff;
- lchan[1] = (left >> 8) & 0xff;
- } else {
- lchan[1] = left & 0xff;
- lchan[0] = (left >> 8) & 0xff;
- }
-
- 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 self->dev->buf_size;
- }
-
- /* fprintf(stderr, "[%d:%d]S%d ", secs, usecs, P->skew);*/
-
- msecs -= P->skew;
-
- frame_pos = (msecs % 1000) * self->dev->conf.rate / 1000;
-
- played_frames = frame_pos - P->played_this_second
- + ((msecs / 1000 - P->lsec) * self->dev->conf.rate);
- /*
- fprintf(stderr, "%d:%d - %d:%d => %d\n", secs, frame_pos,
- P->lsec, P->played_this_second, played_frames);
- */
-
- if (played_frames > self->dev->buf_size)
- played_frames = self->dev->buf_size;
-
- /*
- 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, self->dev->conf.rate);
- */
-
-
- if (played_frames > P->max_delta)
- P->max_delta = played_frames;
-
- free_frames = played_frames;
-
- if (free_frames > self->dev->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, self->dev->buf_size, free_frames);
- }
- diagnosed_too_slow = 1;
-
- *skip_frames = free_frames - self->dev->buf_size;
- free_frames = self->dev->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 = self->dev->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 = self->dev->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 >= self->dev->conf.rate) {
- /* Won't normally happen more than once */
- P->played_this_second -= self->dev->conf.rate;
- P->lsec++;
- }
-
- if (result_frames > self->dev->buf_size) {
- fprintf(stderr, "[soft-mixer] Internal assertion failed: frames-to-write %d > %d\n",
- result_frames, self->dev->buf_size);
- }
- return result_frames;
-}
-
-
-
-#define READ_NEW_VALUES() \
- if (frames_left > 0) { \
- if (bias) { /* unsigned data */ \
- if (!use_16) { \
- c_new.left = (*lsrc) << 8; \
- c_new.right = (*rsrc) << 8; \
- } else { \
- if (conf.format & SFX_PCM_FORMAT_LE) { \
- c_new.left = lsrc[0] | lsrc[1] << 8; \
- c_new.right = rsrc[0] | rsrc[1] << 8; \
- } else { \
- c_new.left = lsrc[1] | lsrc[0] << 8; \
- c_new.right = rsrc[1] | rsrc[0] << 8; \
- } \
- } \
- } else { /* signed data */ \
- if (!use_16) { \
- c_new.left = (*((signed char *)lsrc)) << 8; \
- c_new.right = (*((signed char *)rsrc)) << 8; \
- } else { \
- if (conf.format & SFX_PCM_FORMAT_LE) { \
- c_new.left = lsrc[0] | ((signed char *)lsrc)[1] << 8; \
- c_new.right = rsrc[0] | ((signed char *)rsrc)[1] << 8; \
- } else { \
- c_new.left = lsrc[1] | ((signed char *)lsrc)[0] << 8; \
- c_new.right = rsrc[1] | ((signed char *)rsrc)[0] << 8; \
- } \
- } \
- } \
- \
- 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, int add_result,
- int len, sfx_timestamp_t *ts, sfx_timestamp_t base_ts) {
-/* if add_result is non-zero, P->outbuf should be added to rather than overwritten. */
-/* base_ts is the timestamp for the first frame */
- sfx_pcm_feed_state_t *fs = self->feeds + add_result;
- 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();
-
- fs = self->feeds + add_result;
- /* Reset in case of status update */
-
- switch (newmode) {
-
- 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 = 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);
- }
- }
-
- 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();
- fs = self->feeds + add_result;
-
- 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;
- }
-
-
-#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
-
-
- if (conf.stereo == SFX_PCM_STEREO_LR)
- rsrc += (use_16) ? 2 : 1;
- else if (conf.stereo == SFX_PCM_STEREO_RL)
- lsrc += (use_16) ? 2 : 1;
- /* Otherwise, we let both point to the same place */
-
-#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;
-
- 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;
-
- int frame_steps = fs->spd.val;
- int j;
-
- 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;
- }
- }
-
- 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);
-
- /* Normalise */
- left /= fs->spd.den;
- right /= fs->spd.den;
-
-
- 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);
- }
-
-
-#if (DEBUG >= 3)
- sciprintf("[soft-mixer] Ultimate result: %d:%d (frac %d:%d)\n", leftsum, rightsum, left, right);
-#endif
-
- if (add_result) {
- *(lchan++) += leftsum;
- *(rchan++) += rightsum;
- } else {
- *(lchan++) = leftsum;
- *(rchan++) = rightsum;
- }
-
- fs->scount.nom += fs->spd.nom; /* Count up fractional part */
- }
-
- fs->ch_old = c_old;
- fs->ch_new = c_new;
-
- /* 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));
- }
-
- /* 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();
- }
-
- 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 = 1;
- else
- fs->mode = SFX_PCM_FEED_MODE_DEAD; /* Done. */
- }
-}
-
-static int mix_process_linear(sfx_pcm_mixer_t *self) {
- ACQUIRE_LOCK();
- {
- int src_i; /* source feed index counter */
- 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(), self->dev->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, self->dev->conf.rate);
- }
-
- rv = self->dev->output(self->dev, P->outbuf,
- P->lastbuf_len,
- (P->have_outbuf_timestamp) ? &ts : NULL);
-
- if (rv == SFX_ERROR) {
- RELEASE_LOCK();
- return rv; /* error */
- }
- }
-
-#if (DEBUG >= 1)
- if (self->feeds_nr)
- sciprintf("[soft-mixer] Mixing %d output frames on %d input feeds\n", buflen, self->feeds_nr);
-#endif
- if (self->feeds_nr && !P->paused) {
- /* 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 > self->dev->buf_size)
- fake_buflen = self->dev->buf_size;
- else
- fake_buflen = frames_skip;
-
- frames_skip -= fake_buflen;
- } else {
- fake_buflen = buflen;
- frames_skip = -1; /* Mark us as being completely done */
- }
-
- for (src_i = 0; src_i < self->feeds_nr; src_i++) {
- mix_compute_input_linear(self, src_i,
- 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 */
- for (src_i = 0; src_i < self->feeds_nr; src_i++)
- if (self->feeds[src_i].mode == SFX_PCM_FEED_MODE_DEAD)
- _mix_unsubscribe(self, self->feeds[src_i].feed);
- } while (frames_skip >= 0);
-
- } else { /* Zero it out */
- memset(P->compbuf_l, 0, sizeof(int32) * buflen);
- memset(P->compbuf_r, 0, sizeof(int32) * buflen);
- }
-
-#if (DEBUG >= 1)
- if (self->feeds_nr)
- sciprintf("[soft-mixer] Done mixing for this session, the result will be our next output buffer\n");
-#endif
-
-#if (DEBUG >= 3)
- if (self->feeds_nr) {
- 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]);
- }
-#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;
-
- }
- RELEASE_LOCK();
- return SFX_OK;
-}
-
-static void mix_pause(sfx_pcm_mixer_t *self) {
- ACQUIRE_LOCK();
- P->paused = 1;
- RELEASE_LOCK();
-}
-
-static void mix_resume(sfx_pcm_mixer_t *self) {
- ACQUIRE_LOCK();
- P->paused = 0;
- RELEASE_LOCK();
-}
-
-sfx_pcm_mixer_t sfx_pcm_mixer_soft_linear = {
- "soft-linear",
- "0.1",
-
- mix_init,
- mix_exit,
- mix_subscribe,
- mix_pause,
- mix_resume,
- mix_process_linear,
-
- 0,
- 0,
- NULL,
- NULL,
- NULL
-};
-
-sfx_pcm_mixer_t *getMixer() { return &sfx_pcm_mixer_soft_linear; }
-
-} // End of namespace Sci
Copied: scummvm/trunk/engines/sci/sfx/mixer.cpp (from rev 38946, scummvm/trunk/engines/sci/sfx/mixer/soft.cpp)
===================================================================
--- scummvm/trunk/engines/sci/sfx/mixer.cpp (rev 0)
+++ scummvm/trunk/engines/sci/sfx/mixer.cpp 2009-02-28 06:48:53 UTC (rev 38949)
@@ -0,0 +1,956 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/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()
+
+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 */
+
+ /* Pause data */
+ int paused;
+
+ sfx_pcm_config_t conf;
+ int _framesize;
+ Audio::AppendableAudioStream *_audioStream;
+ Audio::SoundHandle _soundHandle;
+};
+
+#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->paused = 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;
+ }
+ 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;
+}
+
+static void mix_subscribe(sfx_pcm_mixer_t *self, sfx_pcm_feed_t *feed) {
+ sfx_pcm_feed_state_t *fs;
+ ACQUIRE_LOCK();
+ if (!self->feeds) {
+ self->feeds_allocd = 2;
+ self->feeds = (sfx_pcm_feed_state_t*)sci_malloc(sizeof(sfx_pcm_feed_state_t)
+ * self->feeds_allocd);
+ } else if (self->feeds_allocd == self->feeds_nr) {
+ self->feeds_allocd += 2;
+ self->feeds = (sfx_pcm_feed_state_t*)sci_realloc(self->feeds,
+ sizeof(sfx_pcm_feed_state_t)
+ * self->feeds_allocd);
+ }
+
+ fs = self->feeds + self->feeds_nr++;
+ fs->feed = 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);
+ fprintf(stderr, " ---> --> %d for %p at %p\n", fs->buf_size * feed->frame_size, (void *)fs, (void *)fs->buf);
+ {
+ int i;
+ for (i = 0; i < fs->buf_size * feed->frame_size; i++)
+ fs->buf[i] = 0xa5;
+ }
+ fs->scount = urat(0, 1);
+ fs->spd = urat(feed->conf.rate, P->conf.rate);
+ fs->scount.den = fs->spd.den;
+ fs->ch_old.left = 0;
+ fs->ch_old.right = 0;
+ fs->ch_new.left = 0;
+ fs->ch_new.right = 0;
+ fs->mode = SFX_PCM_FEED_MODE_ALIVE;
+
+ /* If the feed can't provide us with timestamps, we don't need to wait for it to do so */
+ fs->pending_review = (feed->get_timestamp) ? 1 : 0;
+
+ fs->frame_bufstart = 0;
+
+#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
+ RELEASE_LOCK();
+}
+
+
+static void _mix_unsubscribe(sfx_pcm_mixer_t *self, sfx_pcm_feed_t *feed) {
+ int i;
+#ifdef DEBUG
+ sciprintf("[soft-mixer] Unsubscribing %s-%x\n", feed->debug_name, feed->debug_nr);
+#endif
+ for (i = 0; i < self->feeds_nr; i++) {
+ sfx_pcm_feed_state_t *fs = self->feeds + i;
+
+ if (fs->feed == feed) {
+ feed->destroy(feed);
+
+ if (fs->buf)
+ free(fs->buf);
+
+ self->feeds_nr--;
+
+ /* Copy topmost into deleted so that we don't have any holes */
+ if (i != self->feeds_nr)
+ self->feeds[i] = self->feeds[self->feeds_nr];
+
+ if (self->feeds_allocd > 8 && self->feeds_allocd > (self->feeds_nr << 1)) {
+ /* Limit memory waste */
+ self->feeds_allocd >>= 1;
+ self->feeds
+ = (sfx_pcm_feed_state_t*)sci_realloc(self->feeds,
+ sizeof(sfx_pcm_feed_state_t)
+ * self->feeds_allocd);
+ }
+
+ for (i = 0; i < self->feeds_nr; i++)
+ fprintf(stderr, " Feed #%d: %s-%x\n",
+ i, self->feeds[i].feed->debug_name,
+ self->feeds[i].feed->debug_nr);
+
+ return;
+ }
+ }
+
+ fprintf(stderr, "[sfx-mixer] Assertion failed: Deleting invalid feed %p out of %d\n",
+ (void *)feed, self->feeds_nr);
+
+ BREAKPOINT();
+}
+
+static void mix_exit(sfx_pcm_mixer_t *self) {
+ g_system->getMixer()->stopHandle(P->_soundHandle);
+ P->_audioStream = 0;
+
+ ACQUIRE_LOCK();
+ while (self->feeds_nr)
+ _mix_unsubscribe(self, self->feeds[0].feed);
+ RELEASE_LOCK();
+
+ 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);
+
+ if (conf.stereo) {
+ if (conf.stereo == SFX_PCM_STEREO_RL) {
+ lchan = P->writebuf + ((use_16) ? 2 : 1);
+ rchan = P->writebuf;
+ } else {
+ lchan = P->writebuf;
+ rchan = P->writebuf + ((use_16) ? 2 : 1);
+ }
+ } else
+ lchan = P->writebuf;
+
+
+ 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) {
+ if (SFX_PCM_FORMAT_LE == (conf.format & SFX_PCM_FORMAT_ENDIANNESS)) {
+ lchan[0] = left & 0xff;
+ lchan[1] = (left >> 8) & 0xff;
+ rchan[0] = right & 0xff;
+ rchan[1] = (right >> 8) & 0xff;
+ } else {
+ lchan[1] = left & 0xff;
+ lchan[0] = (left >> 8) & 0xff;
+ rchan[1] = right & 0xff;
+ rchan[0] = (right >> 8) & 0xff;
+ }
+
+ 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) {
+ if (SFX_PCM_FORMAT_LE == (conf.format & SFX_PCM_FORMAT_ENDIANNESS)) {
+ lchan[0] = left & 0xff;
+ lchan[1] = (left >> 8) & 0xff;
+ } else {
+ lchan[1] = left & 0xff;
+ lchan[0] = (left >> 8) & 0xff;
+ }
+
+ 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;
+ }
+
+ /* 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;
+
+ /*
+ 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;
+}
+
+
+
+#define READ_NEW_VALUES() \
+ if (frames_left > 0) { \
+ if (bias) { /* unsigned data */ \
+ if (!use_16) { \
+ c_new.left = (*lsrc) << 8; \
+ c_new.right = (*rsrc) << 8; \
+ } else { \
+ if (conf.format & SFX_PCM_FORMAT_LE) { \
+ c_new.left = lsrc[0] | lsrc[1] << 8; \
+ c_new.right = rsrc[0] | rsrc[1] << 8; \
+ } else { \
+ c_new.left = lsrc[1] | lsrc[0] << 8; \
+ c_new.right = rsrc[1] | rsrc[0] << 8; \
+ } \
+ } \
+ } else { /* signed data */ \
+ if (!use_16) { \
+ c_new.left = (*((signed char *)lsrc)) << 8; \
+ c_new.right = (*((signed char *)rsrc)) << 8; \
+ } else { \
+ if (conf.format & SFX_PCM_FORMAT_LE) { \
+ c_new.left = lsrc[0] | ((signed char *)lsrc)[1] << 8; \
+ c_new.right = rsrc[0] | ((signed char *)rsrc)[1] << 8; \
+ } else { \
+ c_new.left = lsrc[1] | ((signed char *)lsrc)[0] << 8; \
+ c_new.right = rsrc[1] | ((signed char *)rsrc)[0] << 8; \
+ } \
+ } \
+ } \
+ \
+ 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, int add_result,
+ int len, sfx_timestamp_t *ts, sfx_timestamp_t base_ts) {
+/* if add_result is non-zero, P->outbuf should be added to rather than overwritten. */
+/* base_ts is the timestamp for the first frame */
+ sfx_pcm_feed_state_t *fs = self->feeds + add_result;
+ 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();
+
+ fs = self->feeds + add_result;
+ /* Reset in case of status update */
+
+ switch (newmode) {
+
+ 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 = 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);
+ }
+ }
+
+ 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();
+ fs = self->feeds + add_result;
+
+ 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;
+ }
+
+
+#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
+
+
+ if (conf.stereo == SFX_PCM_STEREO_LR)
+ rsrc += (use_16) ? 2 : 1;
+ else if (conf.stereo == SFX_PCM_STEREO_RL)
+ lsrc += (use_16) ? 2 : 1;
+ /* Otherwise, we let both point to the same place */
+
+#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;
+
+ 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;
+
+ int frame_steps = fs->spd.val;
+ int j;
+
+ 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;
+ }
+ }
+
+ 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);
+
+ /* Normalise */
+ left /= fs->spd.den;
+ right /= fs->spd.den;
+
+
+ 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);
+ }
+
+
+#if (DEBUG >= 3)
+ sciprintf("[soft-mixer] Ultimate result: %d:%d (frac %d:%d)\n", leftsum, rightsum, left, right);
+#endif
+
+ if (add_result) {
+ *(lchan++) += leftsum;
+ *(rchan++) += rightsum;
+ } else {
+ *(lchan++) = leftsum;
+ *(rchan++) = rightsum;
+ }
+
+ fs->scount.nom += fs->spd.nom; /* Count up fractional part */
+ }
+
+ fs->ch_old = c_old;
+ fs->ch_new = c_new;
+
+ /* 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));
+ }
+
+ /* 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();
+ }
+
+ 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 = 1;
+ else
+ fs->mode = SFX_PCM_FEED_MODE_DEAD; /* Done. */
+ }
+}
+
+static int mix_process_linear(sfx_pcm_mixer_t *self) {
+ ACQUIRE_LOCK();
+ {
+ int src_i; /* source feed index counter */
+ 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?)
+ }
+
+#if (DEBUG >= 1)
+ if (self->feeds_nr)
+ sciprintf("[soft-mixer] Mixing %d output frames on %d input feeds\n", buflen, self->feeds_nr);
+#endif
+ if (self->feeds_nr && !P->paused) {
+ /* 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 */
+ }
+
+ for (src_i = 0; src_i < self->feeds_nr; src_i++) {
+ mix_compute_input_linear(self, src_i,
+ 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 */
+ for (src_i = 0; src_i < self->feeds_nr; src_i++)
+ if (self->feeds[src_i].mode == SFX_PCM_FEED_MODE_DEAD)
+ _mix_unsubscribe(self, self->feeds[src_i].feed);
+ } while (frames_skip >= 0);
+
+ } else { /* Zero it out */
+ memset(P->compbuf_l, 0, sizeof(int32) * buflen);
+ memset(P->compbuf_r, 0, sizeof(int32) * buflen);
+ }
+
+#if (DEBUG >= 1)
+ if (self->feeds_nr)
+ sciprintf("[soft-mixer] Done mixing for this session, the result will be our next output buffer\n");
+#endif
+
+#if (DEBUG >= 3)
+ if (self->feeds_nr) {
+ 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]);
+ }
+#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;
+
+ }
+ RELEASE_LOCK();
+ return SFX_OK;
+}
+
+static void mix_pause(sfx_pcm_mixer_t *self) {
+ ACQUIRE_LOCK();
+ P->paused = 1;
+ RELEASE_LOCK();
+}
+
+static void mix_resume(sfx_pcm_mixer_t *self) {
+ ACQUIRE_LOCK();
+ P->paused = 0;
+ RELEASE_LOCK();
+}
+
+sfx_pcm_mixer_t sfx_pcm_mixer_soft_linear = {
+ "soft-linear",
+ "0.1",
+
+ mix_init,
+ mix_exit,
+ mix_subscribe,
+ mix_pause,
+ mix_resume,
+ mix_process_linear,
+
+ 0,
+ 0,
+ NULL,
+ NULL
+};
+
+sfx_pcm_mixer_t *getMixer() { return &sfx_pcm_mixer_soft_linear; }
+
+} // End of namespace Sci
Modified: scummvm/trunk/engines/sci/sfx/mixer.h
===================================================================
--- scummvm/trunk/engines/sci/sfx/mixer.h 2009-02-28 06:21:24 UTC (rev 38948)
+++ scummvm/trunk/engines/sci/sfx/mixer.h 2009-02-28 06:48:53 UTC (rev 38949)
@@ -70,10 +70,9 @@
const char *name;
const char *version;
- int (*init)(sfx_pcm_mixer_t *self, sfx_pcm_device_t *device);
+ int (*init)(sfx_pcm_mixer_t *self);
/* Initialises the mixer
** Parameters: (sfx_pcm_mixer_t *) self: Self reference
- ** (sfx_pcm_device_t *) device: An _already initialised_ PCM output driver
** Returns : (int) SFX_OK on success, SFX_ERROR otherwise
*/
@@ -109,7 +108,6 @@
int feeds_nr;
int feeds_allocd;
sfx_pcm_feed_state_t *feeds;
- sfx_pcm_device_t *dev;
void *private_bits;
};
Deleted: scummvm/trunk/engines/sci/sfx/pcm_device.cpp
===================================================================
--- scummvm/trunk/engines/sci/sfx/pcm_device.cpp 2009-02-28 06:21:24 UTC (rev 38948)
+++ scummvm/trunk/engines/sci/sfx/pcm_device.cpp 2009-02-28 06:48:53 UTC (rev 38949)
@@ -1,79 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "sci/sfx/sfx_time.h"
-#include "sci/sfx/sfx_pcm.h"
-#include "engines/engine.h"
-#include "sound/audiostream.h"
-#include "sound/mixer.h"
-
-namespace Sci {
-
-static int pcmout_scummvm_framesize;
-static Audio::AppendableAudioStream * pcmout_scummvm_audiostream;
-static Audio::SoundHandle pcmout_scummvm_sound_handle;
-
-
-static int pcmout_scummvm_init(sfx_pcm_device_t *self) {
- int pcmout_scummvm_audiostream_flags = Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_STEREO;
-
-#ifdef SCUMM_LITTLE_ENDIAN
- pcmout_scummvm_audiostream_flags |= Audio::Mixer::FLAG_LITTLE_ENDIAN;
-#endif
-
- self->buf_size = 2048 << 1;
- self->conf.rate = g_engine->_mixer->getOutputRate();
- self->conf.stereo = SFX_PCM_STEREO_LR;
- self->conf.format = SFX_PCM_FORMAT_S16_NATIVE;
- pcmout_scummvm_framesize = SFX_PCM_FRAME_SIZE(self->conf);
-
- pcmout_scummvm_audiostream = Audio::makeAppendableAudioStream(self->conf.rate, pcmout_scummvm_audiostream_flags);
- ::g_engine->_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &pcmout_scummvm_sound_handle, pcmout_scummvm_audiostream);
-
- return SFX_OK;
-}
-
-static int pcmout_scummvm_output(sfx_pcm_device_t *self, byte *buf, int count,
- sfx_timestamp_t *timestamp) {
-
- byte *__buf = new byte[count * pcmout_scummvm_framesize];
-
- memcpy(__buf, buf, count * pcmout_scummvm_framesize);
-
- pcmout_scummvm_audiostream->queueBuffer(__buf, count * pcmout_scummvm_framesize);
-
- return SFX_OK;
-}
-
-
-sfx_pcm_device_t sfx_pcm_driver_scummvm = {
- &pcmout_scummvm_init,
- &pcmout_scummvm_output,
- NULL,
- {0, 0, 0},
- 0
-};
-
-} // End of namespace Sci
Modified: scummvm/trunk/engines/sci/sfx/sfx_pcm.h
===================================================================
--- scummvm/trunk/engines/sci/sfx/sfx_pcm.h 2009-02-28 06:21:24 UTC (rev 38948)
+++ scummvm/trunk/engines/sci/sfx/sfx_pcm.h 2009-02-28 06:48:53 UTC (rev 38949)
@@ -69,60 +69,6 @@
unsigned int format; /* Sample format (SFX_PCM_FORMAT_*) */
};
-struct sfx_pcm_device_t {
- /* SFX devices are PCM players, i.e. output drivers for digitalised audio (sequences of audio samples).
- ** Implementors are (in general) allowed to export specifics of these devices and let the mixer handle
- ** endianness/signedness/bit size/mono-vs-stereo conversions.
- */
-
- int (*init)(sfx_pcm_device_t *self);
- /* Initializes the device
- ** Parameters: (sfx_pcm_device_t *) self: Self reference
- ** Returns : (int) SFX_OK on success, SFX_ERROR if the device could not be
- ** opened
- ** This should attempt to open the highest quality output allowed by any options
- ** specified beforehand.
- */
-
- int (*output)(sfx_pcm_device_t *self, byte *buf,
- int count, sfx_timestamp_t *timestamp);
- /* Writes output to the device
- ** Parameters: (sfx_pcm_device_t *) self: Self reference
- ** (byte *) buf: The buffer to write
- ** (int) count: Number of /frames/ that should be written
- ** (sfx_timestamp_t *) timestamp: Optional point in time
- ** for which the PCM data is scheduled
- ** Returns : (int) SFX_OK on success, SFX_ERROR on error
- ** The size of the buffer allocated as 'buf' equals buf_size.
- ** 'buf' is guaranteed not to be modified in between calls to 'output()'.
- ** 'timestamp' is guaranteed to be used only in sequential order, but not
- ** guaranteed to be used in all cases. It is guaranteed to be compaible with
- ** the sample rate used by the device itself (i.e., the sfx_time.h functionality
- ** is applicable)
- */
-
- sfx_timestamp_t
- (*get_output_timestamp)(sfx_pcm_device_t *self);
- /* Determines the timestamp for 'output'
- ** Parameters: (sfx_pcm_device_t *) self: Self reference
- ** Returns : (sfx_timestamp_t) A timestamp (with the device's conf.rate)
- ** describing the point in time at which
- ** the next frame passed to 'output'
- ** will be played
- ** This function is OPTIONAL and may be NULL, but it is recommended
- ** that pcm device implementers attempt to really implement it.
- */
-
- /* The following must be set after initialisation */
- sfx_pcm_config_t conf;
- int buf_size; /* Output buffer size, i.e. the number of frames (!)
- ** that can be queued by this driver before calling
- ** output() will block or fail, drained according
- ** to conf.rate */
-
-};
-
-
#define PCM_FEED_TIMESTAMP 0 /* New timestamp available */
#define PCM_FEED_IDLE 1 /* No sound ATM, but new timestamp may be available later */
#define PCM_FEED_EMPTY 2 /* Feed is finished, can be destroyed */
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
More information about the Scummvm-git-logs
mailing list