diff options
-rw-r--r-- | engines/sci/module.mk | 3 | ||||
-rw-r--r-- | engines/sci/sfx/core.cpp | 39 | ||||
-rw-r--r-- | engines/sci/sfx/iterator.cpp | 2 | ||||
-rw-r--r-- | engines/sci/sfx/mixer.cpp (renamed from engines/sci/sfx/mixer/soft.cpp) | 116 | ||||
-rw-r--r-- | engines/sci/sfx/mixer.h | 4 | ||||
-rw-r--r-- | engines/sci/sfx/pcm_device.cpp | 79 | ||||
-rw-r--r-- | engines/sci/sfx/sfx_pcm.h | 54 |
7 files changed, 85 insertions, 212 deletions
diff --git a/engines/sci/module.mk b/engines/sci/module.mk index cebd4b87f7..a175f13595 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -67,12 +67,11 @@ MODULE_OBJS = \ 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 \ diff --git a/engines/sci/sfx/core.cpp b/engines/sci/sfx/core.cpp index a08c0824b5..4f532b0e61 100644 --- a/engines/sci/sfx/core.cpp +++ b/engines/sci/sfx/core.cpp @@ -44,11 +44,10 @@ int sciprintf(char *msg, ...); 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 @@ void sfx_init(sfx_state_t *self, ResourceManager *resmgr, int flags) { 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 @@ void sfx_init(sfx_state_t *self, ResourceManager *resmgr, int flags) { 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 @@ void sfx_init(sfx_state_t *self, ResourceManager *resmgr, int flags) { /*------------------*/ // 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 @@ void sfx_exit(sfx_state_t *self) { 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. */ diff --git a/engines/sci/sfx/iterator.cpp b/engines/sci/sfx/iterator.cpp index d738d1222e..501ebb0ad9 100644 --- a/engines/sci/sfx/iterator.cpp +++ b/engines/sci/sfx/iterator.cpp @@ -676,7 +676,7 @@ static void _sci0_cleanup(sci0_song_iterator_t *self) { #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 */ diff --git a/engines/sci/sfx/mixer/soft.cpp b/engines/sci/sfx/mixer.cpp index 53e4d94399..a845627222 100644 --- a/engines/sci/sfx/mixer/soft.cpp +++ b/engines/sci/sfx/mixer.cpp @@ -30,6 +30,9 @@ #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 */ @@ -72,20 +75,41 @@ struct mixer_private { /* 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, sfx_pcm_device_t *device) { - self->dev = device; +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) * device->buf_size); - P->compbuf_r = (int32*)sci_malloc(sizeof(int32) * device->buf_size); + 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; } @@ -135,19 +159,19 @@ static void mix_subscribe(sfx_pcm_mixer_t *self, sfx_pcm_feed_t *feed) { feed->frame_size = SFX_PCM_FRAME_SIZE(feed->conf); - /* fs->buf_size = (self->dev->buf_size + /* fs->buf_size = (BUF_SIZE * (feed->conf.rate - + self->dev->conf.rate - 1)) - / self->dev->conf.rate; + + P->conf.rate - 1)) + / P->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))); + (BUF_SIZE * + (1 + (feed->conf.rate / P->conf.rate))); fprintf(stderr, " ---> %d/%d/%d/%d = %d\n", - self->dev->buf_size, + BUF_SIZE, feed->conf.rate, - self->dev->conf.rate, + P->conf.rate, feed->frame_size, fs->buf_size); @@ -159,7 +183,7 @@ static void mix_subscribe(sfx_pcm_mixer_t *self, sfx_pcm_feed_t *feed) { fs->buf[i] = 0xa5; } fs->scount = urat(0, 1); - fs->spd = urat(feed->conf.rate, self->dev->conf.rate); + 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; @@ -226,6 +250,9 @@ static void _mix_unsubscribe(sfx_pcm_mixer_t *self, sfx_pcm_feed_t *feed) { } 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); @@ -254,7 +281,7 @@ static void mix_exit(sfx_pcm_mixer_t *self) { static inline void mix_compute_output(sfx_pcm_mixer_t *self, int outplen) { int frame_i; - sfx_pcm_config_t conf = self->dev->conf; + 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; @@ -266,7 +293,7 @@ static inline void mix_compute_output(sfx_pcm_mixer_t *self, int outplen) { if (!P->writebuf) - P->writebuf = (byte*)sci_malloc(self->dev->buf_size * frame_size + 4); + P->writebuf = (byte*)sci_malloc(BUF_SIZE * frame_size + 4); if (conf.stereo) { if (conf.stereo == SFX_PCM_STEREO_RL) { @@ -374,28 +401,28 @@ static inline int mix_compute_buf_len(sfx_pcm_mixer_t *self, int *skip_frames) { P->played_this_second = 0; *skip_frames = 0; - return self->dev->buf_size; + return BUF_SIZE; } /* fprintf(stderr, "[%d:%d]S%d ", secs, usecs, P->skew);*/ msecs -= P->skew; - frame_pos = (msecs % 1000) * self->dev->conf.rate / 1000; + frame_pos = (msecs % 1000) * P->conf.rate / 1000; played_frames = frame_pos - P->played_this_second - + ((msecs / 1000 - P->lsec) * self->dev->conf.rate); + + ((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 > self->dev->buf_size) - played_frames = self->dev->buf_size; + 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, self->dev->conf.rate); + secs, usecs, frame_pos, played_frames, P->conf.rate); */ @@ -404,16 +431,16 @@ static inline int mix_compute_buf_len(sfx_pcm_mixer_t *self, int *skip_frames) { free_frames = played_frames; - if (free_frames > self->dev->buf_size) { + 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, self->dev->buf_size, free_frames); + played_frames, BUF_SIZE, free_frames); } diagnosed_too_slow = 1; - *skip_frames = free_frames - self->dev->buf_size; - free_frames = self->dev->buf_size; + *skip_frames = free_frames - BUF_SIZE; + free_frames = BUF_SIZE; } else *skip_frames = 0; @@ -423,14 +450,14 @@ static inline int mix_compute_buf_len(sfx_pcm_mixer_t *self, int *skip_frames) { /* /\* Disabled, broken *\/ */ /* if (0 && P->delta_observations > MIN_DELTA_OBSERVATIONS) { /\* Start improving after a while *\/ */ - /* int diff = self->dev->conf.rate - P->max_delta; */ + /* 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 = self->dev->buf_size; /\* Initially, keep the buffer full *\/ */ + /* recommended_frames = BUF_SIZE; /\* Initially, keep the buffer full *\/ */ #if (DEBUG >= 1) sciprintf("[soft-mixer] played since last time: %d, free: %d\n", @@ -443,15 +470,15 @@ static inline int mix_compute_buf_len(sfx_pcm_mixer_t *self, int *skip_frames) { result_frames = 0; P->played_this_second += result_frames; - while (P->played_this_second >= self->dev->conf.rate) { + while (P->played_this_second >= P->conf.rate) { /* Won't normally happen more than once */ - P->played_this_second -= self->dev->conf.rate; + P->played_this_second -= P->conf.rate; P->lsec++; } - if (result_frames > self->dev->buf_size) { + if (result_frames > BUF_SIZE) { fprintf(stderr, "[soft-mixer] Internal assertion failed: frames-to-write %d > %d\n", - result_frames, self->dev->buf_size); + result_frames, BUF_SIZE); } return result_frames; } @@ -781,27 +808,31 @@ static int mix_process_linear(sfx_pcm_mixer_t *self) { 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 (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, self->dev->conf.rate); + ts = sfx_timestamp_renormalise(P->outbuf_timestamp, P->conf.rate); } - rv = self->dev->output(self->dev, P->outbuf, - P->lastbuf_len, - (P->have_outbuf_timestamp) ? &ts : NULL); - - if (rv == SFX_ERROR) { + 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) @@ -814,8 +845,8 @@ static int mix_process_linear(sfx_pcm_mixer_t *self) { ** 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; + if (frames_skip > BUF_SIZE) + fake_buflen = BUF_SIZE; else fake_buflen = frames_skip; @@ -917,7 +948,6 @@ sfx_pcm_mixer_t sfx_pcm_mixer_soft_linear = { 0, 0, NULL, - NULL, NULL }; diff --git a/engines/sci/sfx/mixer.h b/engines/sci/sfx/mixer.h index 5f24482904..534085ad66 100644 --- a/engines/sci/sfx/mixer.h +++ b/engines/sci/sfx/mixer.h @@ -70,10 +70,9 @@ struct sfx_pcm_mixer_t { 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 @@ struct sfx_pcm_mixer_t { int feeds_nr; int feeds_allocd; sfx_pcm_feed_state_t *feeds; - sfx_pcm_device_t *dev; void *private_bits; }; diff --git a/engines/sci/sfx/pcm_device.cpp b/engines/sci/sfx/pcm_device.cpp deleted file mode 100644 index 5934b76b21..0000000000 --- a/engines/sci/sfx/pcm_device.cpp +++ /dev/null @@ -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 diff --git a/engines/sci/sfx/sfx_pcm.h b/engines/sci/sfx/sfx_pcm.h index 89ccee04d9..0459afd2ee 100644 --- a/engines/sci/sfx/sfx_pcm.h +++ b/engines/sci/sfx/sfx_pcm.h @@ -69,60 +69,6 @@ struct sfx_pcm_config_t { 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 */ |