aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/sfx/pcm_device/sdl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/sfx/pcm_device/sdl.cpp')
-rw-r--r--engines/sci/sfx/pcm_device/sdl.cpp272
1 files changed, 272 insertions, 0 deletions
diff --git a/engines/sci/sfx/pcm_device/sdl.cpp b/engines/sci/sfx/pcm_device/sdl.cpp
new file mode 100644
index 0000000000..bd125835cb
--- /dev/null
+++ b/engines/sci/sfx/pcm_device/sdl.cpp
@@ -0,0 +1,272 @@
+/***************************************************************************
+ sdl.c Copyright (C) 2002 Solomon Peachy, Claudio Matsuoka,
+ 2003,04 Christoph Reichenbach
+
+ This program may be modified and copied freely according to the terms of
+ the GNU general public license (GPL), as long as the above copyright
+ notice and the licensing information contained herein are preserved.
+
+ Please refer to www.gnu.org for licensing details.
+
+ This work is provided AS IS, without warranty of any kind, expressed or
+ implied, including but not limited to the warranties of merchantibility,
+ noninfringement, and fitness for a specific purpose. The author will not
+ be held liable for any damage caused by this work or derivatives of it.
+
+ By using this source code, you agree to the licensing terms as stated
+ above.
+
+***************************************************************************/
+
+#include <sfx_pcm.h>
+#include "audiobuf.h"
+
+#ifdef HAVE_SDL
+
+#if !defined(_MSC_VER)
+# include <sys/time.h>
+#endif
+
+#include <SDL_config.h>
+#undef HAVE_ICONV
+#undef HAVE_ICONV_H
+#undef HAVE_ALLOCA_H
+
+#include <SDL.h>
+
+#define DELTA_TIME_LIMIT 10000 /* Report errors above this delta time */
+
+static sfx_audio_buf_t audio_buffer;
+static void (*sdl_sfx_timer_callback)(void *data);
+static void *sdl_sfx_timer_data;
+static int frame_size;
+static int buf_size;
+static int rate;
+static long last_callback_secs, last_callback_usecs;
+static int last_callback_len;
+
+static sfx_timestamp_t
+pcmout_sdl_output_timestamp(sfx_pcm_device_t *self)
+{
+ /* Number of frames enqueued in the output device: */
+ int delta = (buf_size - last_callback_len) / frame_size
+ /* Number of frames enqueued in the internal audio buffer: */
+ + audio_buffer.frames_nr;
+
+ return sfx_timestamp_add(sfx_new_timestamp(last_callback_secs,
+ last_callback_usecs,
+ rate),
+ delta);
+}
+
+FILE *fil = NULL;
+
+static void
+timer_sdl_internal_callback(void *userdata, byte *dest, int len)
+{
+ sci_gettime(&last_callback_secs, &last_callback_usecs);
+ last_callback_len = len;
+
+ if (sdl_sfx_timer_callback)
+ sdl_sfx_timer_callback(sdl_sfx_timer_data);
+
+#if 0
+ if (!sfx_audbuf_read_timestamp(&audio_buffer, &ts)) {
+ int delta = (buf_size - len) / frame_size;
+ sfx_timestamp_t real_ts;
+ long deltatime;
+ long sec2, usec2;
+ sci_gettime(&sec2, &usec2);
+
+ real_ts = sfx_timestamp_add(sfx_new_timestamp(sec, usec, rate), delta);
+
+ deltatime = sfx_timestamp_usecs_diff(ts, real_ts);
+
+ fprintf(stderr, "[SDL] Frames requested: %d Playing %ld too late. Needed %ldus for computations.\n",
+ len / frame_size, deltatime,
+ (usec2-usec) + (sec2-sec)*1000000);
+
+ if (abs(deltatime) > DELTA_TIME_LIMIT)
+ sciprintf("[SND:SDL] Very high delta time for PCM playback: %ld too late (%d frames in the future)\n",
+ deltatime, sfx_timestamp_frame_diff(sfx_new_timestamp(sec, usec, rate), ts));
+
+#if 0
+ if (deltatime < 0) {
+ /* Read and discard frames, explicitly underrunning */
+ int max_read = len / frame_size;
+ int frames_to_kill = sfx_timestamp_frame_diff(real_ts, ts);
+
+ while (frames_to_kill) {
+ int d = frames_to_kill > max_read? max_read : frames_to_kill;
+ sfx_audbuf_read(&audio_buffer, dest, d);
+ frames_to_kill -= d;
+ }
+ }
+#endif
+ }
+#endif
+ sfx_audbuf_read(&audio_buffer, dest, len / frame_size);
+
+#if 0
+ if (!fil) {
+ fil = fopen("/tmp/sdl.log", "w");
+ }
+ {
+ int i;
+ int end = len / frame_size;
+ gint16 *d = dest;
+ fprintf(fil, "Writing %d/%d\n", len, frame_size);
+ for (i = 0; i < end; i++) {
+ fprintf(fil, "\t%d\t%d\n", d[0], d[1]);
+ d += 2;
+ }
+ }
+#endif
+}
+
+
+static int
+pcmout_sdl_init(sfx_pcm_device_t *self)
+{
+ SDL_AudioSpec a;
+
+ if (SDL_Init(SDL_INIT_AUDIO|SDL_INIT_NOPARACHUTE) != 0) {
+ fprintf (stderr, "[SND:SDL] Error while initialising: %s\n", SDL_GetError());
+ return -1;
+ }
+
+ a.freq = 44100; /* FIXME */
+#ifdef WORDS_BIGENDIAN
+ a.format = AUDIO_S16MSB; /* FIXME */
+#else
+ a.format = AUDIO_S16LSB; /* FIXME */
+#endif
+ a.channels = 2; /* FIXME */
+ a.samples = 2048; /* FIXME */
+ a.callback = timer_sdl_internal_callback;
+ a.userdata = NULL;
+
+ if (SDL_OpenAudio (&a, NULL) < 0) {
+ fprintf (stderr, "[SND:SDL] Error while opening audio: %s\n", SDL_GetError());
+ return SFX_ERROR;
+ }
+
+ buf_size = a.samples;
+ rate = a.freq;
+
+ self->buf_size = a.samples << 1; /* Looks like they're using double size */
+ self->conf.rate = a.freq;
+ self->conf.stereo = a.channels > 1;
+ self->conf.format = SFX_PCM_FORMAT_S16_NATIVE;
+
+ frame_size = SFX_PCM_FRAME_SIZE(self->conf);
+
+ sfx_audbuf_init(&audio_buffer, self->conf);
+ SDL_PauseAudio (0);
+
+ return SFX_OK;
+}
+
+int
+pcmout_sdl_output(sfx_pcm_device_t *self, byte *buf,
+ int count, sfx_timestamp_t *ts)
+{
+ if (ts)
+ sfx_audbuf_write_timestamp(&audio_buffer, *ts);
+ sfx_audbuf_write(&audio_buffer, buf, count);
+ return SFX_OK;
+}
+
+
+static int
+pcmout_sdl_set_option(sfx_pcm_device_t *self, char *name, char *value)
+{
+ return SFX_ERROR; /* Option not supported */
+}
+
+static void
+pcmout_sdl_exit(sfx_pcm_device_t *self)
+{
+ SDL_PauseAudio (1);
+ SDL_CloseAudio();
+ sfx_audbuf_free(&audio_buffer);
+
+ SDL_QuitSubSystem(SDL_INIT_AUDIO);
+
+ if (!SDL_WasInit(SDL_INIT_EVERYTHING)) {
+ sciprintf("[SND:SDL] No active SDL subsystems found.. shutting down SDL\n");
+ SDL_Quit();
+ }
+}
+
+
+static int
+timer_sdl_set_option(char *name, char *value)
+{
+ return SFX_ERROR;
+}
+
+
+static int
+timer_sdl_init(void (*callback)(void *data), void *data)
+{
+ sdl_sfx_timer_callback = callback;
+ sdl_sfx_timer_data = data;
+
+
+ return SFX_OK;
+}
+
+static int
+timer_sdl_stop(void)
+{
+ sdl_sfx_timer_callback = NULL;
+
+ return SFX_OK;
+}
+
+static int
+timer_sdl_block(void)
+{
+ SDL_LockAudio();
+
+ return SFX_OK;
+}
+
+static int
+timer_sdl_unblock(void)
+{
+ SDL_UnlockAudio();
+
+ return SFX_OK;
+}
+
+#define SDL_PCM_VERSION "0.1"
+
+sfx_timer_t pcmout_sdl_timer = {
+ "sdl-pcm-timer",
+ SDL_PCM_VERSION,
+ 0,
+ 0,
+ timer_sdl_set_option,
+ timer_sdl_init,
+ timer_sdl_stop,
+ timer_sdl_block,
+ timer_sdl_unblock
+};
+
+sfx_pcm_device_t sfx_pcm_driver_sdl = {
+ "sdl",
+ SDL_PCM_VERSION,
+ pcmout_sdl_init,
+ pcmout_sdl_exit,
+ pcmout_sdl_set_option,
+ pcmout_sdl_output,
+ pcmout_sdl_output_timestamp,
+ {0, 0, 0},
+ 0,
+ &pcmout_sdl_timer,
+ NULL
+};
+
+#endif