diff options
author | Eugene Sandulenko | 2009-02-15 11:39:07 +0000 |
---|---|---|
committer | Eugene Sandulenko | 2009-02-15 11:39:07 +0000 |
commit | e241843bec22600ab4ef98e7a085e82aac73fc93 (patch) | |
tree | 61a793884d3462e1feb80e80f202d8816d0c8ec4 /engines/sci/sfx/pcm_device/audiobuf.cpp | |
parent | e9f742806362a84ffdb176a7414318dd2ab4df89 (diff) | |
download | scummvm-rg350-e241843bec22600ab4ef98e7a085e82aac73fc93.tar.gz scummvm-rg350-e241843bec22600ab4ef98e7a085e82aac73fc93.tar.bz2 scummvm-rg350-e241843bec22600ab4ef98e7a085e82aac73fc93.zip |
- Remove some unneeded files
- Mass rename .c to .cpp
svn-id: r38227
Diffstat (limited to 'engines/sci/sfx/pcm_device/audiobuf.cpp')
-rw-r--r-- | engines/sci/sfx/pcm_device/audiobuf.cpp | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/engines/sci/sfx/pcm_device/audiobuf.cpp b/engines/sci/sfx/pcm_device/audiobuf.cpp new file mode 100644 index 0000000000..fa23708ce4 --- /dev/null +++ b/engines/sci/sfx/pcm_device/audiobuf.cpp @@ -0,0 +1,348 @@ +/*************************************************************************** + audiobuf.c Copyright (C) 2003 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. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ + +#include "audiobuf.h" + +#define NO_BUFFER_UNDERRUN 0 +#define SAW_BUFFER_UNDERRUN 1 +#define REPORTED_BUFFER_UNDERRUN 2 + +static int +buffer_underrun_status = NO_BUFFER_UNDERRUN; + + +static sfx_audio_buf_chunk_t * +sfx_audbuf_alloc_chunk(void) +{ + sfx_audio_buf_chunk_t *ch = (sfx_audio_buf_chunk_t*)sci_malloc(sizeof(sfx_audio_buf_chunk_t)); + ch->used = 0; + ch->next = NULL; + ch->prev = NULL; + + return ch; +} + +void +sfx_audbuf_init(sfx_audio_buf_t *buf, sfx_pcm_config_t pcm_conf) +{ + int framesize = SFX_PCM_FRAME_SIZE(pcm_conf); + byte silence[16]; + int silencew = pcm_conf.format & ~SFX_PCM_FORMAT_LMASK; + + /* Determine the correct 'silence' for the channel and install it */ + /* Conservatively assume stereo */ + if (pcm_conf.format & SFX_PCM_FORMAT_16) { + if (pcm_conf.format & SFX_PCM_FORMAT_LE) { + silence[0] = silencew & 0xff; + silence[1] = (silencew >> 8) & 0xff; + } else { + silence[0] = (silencew >> 8) & 0xff; + silence[1] = silencew & 0xff; + } + memcpy(silence + 2, silence, 2); + } else { + silence[0] = silencew; + silence[1] = silencew; + } + + buf->last = buf->first = sfx_audbuf_alloc_chunk(); + buf->unused = NULL; + memcpy(buf->last_frame, silence, framesize); /* Initialise, in case we + ** underrun before the + ** first write */ + buf->read_offset = 0; + buf->framesize = framesize; + buf->read_timestamp.secs = -1; /* Mark as inactive */ + buf->frames_nr = 0; +} + +static void +sfx_audbuf_free_chain(sfx_audio_buf_chunk_t *b) +{ + while (b) { + sfx_audio_buf_chunk_t *n = b->next; + sci_free(b); + b = n; + } +} + +void +sfx_audbuf_free(sfx_audio_buf_t *buf) +{ + sfx_audbuf_free_chain(buf->first); + sfx_audbuf_free_chain(buf->unused); + buf->first = buf->last = buf->unused = NULL; + buf->read_offset = (int) 0xdeadbeef; +} + +void +sfx_audbuf_write(sfx_audio_buf_t *buf, unsigned char *src, int frames) +{ + /* In here, we compute PER BYTE */ + int data_left = buf->framesize * frames; + + if (!buf->last) { + fprintf(stderr, "FATAL: Violation of audiobuf.h usage protocol: Must use 'init' before 'write'\n"); + exit(1); + } + + if (buffer_underrun_status == SAW_BUFFER_UNDERRUN) { + /* Print here to avoid threadsafeness issues */ + sciprintf("[audiobuf] Buffer underrun\n"); + buffer_underrun_status = REPORTED_BUFFER_UNDERRUN; + } + + buf->frames_nr += frames; + + while (data_left) { + int cpsize; + int buf_free; + buf_free = SFX_AUDIO_BUF_SIZE - buf->last->used; + + + if (buf_free >= data_left) + cpsize = data_left; + else + cpsize = buf_free; + + /* Copy and advance pointers */ + memcpy(buf->last->data + buf->last->used, src, cpsize); + data_left -= cpsize; + buf->last->used += cpsize; + src += cpsize; + + if (buf->last->used == SFX_AUDIO_BUF_SIZE) { + if (!buf->last->next) { + sfx_audio_buf_chunk_t *old = buf->last; + if (buf->unused) { /* Re-use old chunks */ + sfx_audio_buf_chunk_t *buf_next_unused = buf->unused->next; + buf->unused->next = NULL; + buf->unused->used = 0; + + buf->last->next = buf->unused; + buf->unused = buf_next_unused; + } else /* Allocate */ + buf->last->next = + sfx_audbuf_alloc_chunk(); + + buf->last->prev = old; + } + + buf->last = buf->last->next; + } + } + +#ifdef TRACE_BUFFER + { + sfx_audio_buf_chunk_t *c = buf->first; + int t = buf->read_offset; + + while (c) { + fprintf(stderr, "-> ["); + for (; t < c->used; t++) + fprintf(stderr, " %02x", c->data[t]); + t = 0; + fprintf(stderr, " ] "); + c = c->next; + } + fprintf(stderr, "\n"); + } +#endif + + if (frames && (src - buf->framesize) != buf->last_frame) + /* Backup last frame, unless we're already filling from it */ + memcpy(buf->last_frame, src - buf->framesize, buf->framesize); +} + +int +sfx_audbuf_read(sfx_audio_buf_t *buf, unsigned char *dest, int frames) +{ + int written = 0; + + if (frames <= 0) + return 0; + + if (buf->read_timestamp.secs >= 0) { + /* Have a timestamp? Must update it! */ + buf->read_timestamp = + sfx_timestamp_add(buf->read_timestamp, + frames); + + } + + buf->frames_nr -= frames; + if (buf->frames_nr < 0) + buf->frames_nr = 0; + +#ifdef TRACE_BUFFER + { + sfx_audio_buf_chunk_t *c = buf->first; + int t = buf->read_offset; + + while (c) { + fprintf(stderr, "-> ["); + for (; t < c->used; t++) + fprintf(stderr, " %02x", c->data[t]); + t = 0; + fprintf(stderr, " ] "); + c = c->next; + } + fprintf(stderr, "\n"); + } +#endif + + while (frames) { + int data_needed = frames * buf->framesize; + int rdbytes = data_needed; + int rdframes; + + if (rdbytes > buf->first->used - buf->read_offset) + rdbytes = buf->first->used - buf->read_offset; + + memcpy(dest, buf->first->data + buf->read_offset, rdbytes); + + buf->read_offset += rdbytes; + dest += rdbytes; + + if (buf->read_offset == SFX_AUDIO_BUF_SIZE) { + /* Continue to next, enqueue the current chunk as + ** being unused */ + sfx_audio_buf_chunk_t *lastfirst = buf->first; + + buf->first = buf->first->next; + lastfirst->next = buf->unused; + buf->unused = lastfirst; + + buf->read_offset = 0; + } + + rdframes = (rdbytes / buf->framesize); + frames -= rdframes; + written += rdframes; + + if (frames && + (!buf->first || buf->read_offset == buf->first->used)) { + fprintf(stderr, "Underrun by %d frames at %d\n", frames, + buf->read_timestamp.frame_rate); + /* Buffer underrun! */ + if (!buffer_underrun_status == NO_BUFFER_UNDERRUN) { + buffer_underrun_status = SAW_BUFFER_UNDERRUN; + } + do { + memcpy(dest, buf->last_frame, buf->framesize); + dest += buf->framesize; + } while (--frames); + } + + } + + return written; +} + +#if 0 +static void +_sfx_audbuf_rewind_stream(sfx_audio_buf_t *buf, int delta) +{ + if (delta > buf->frames_nr) + delta = buf->frames_nr; + + + fprintf(stderr, "Rewinding %d\n", delta); + buf->frames_nr -= delta; + + /* From here on, 'delta' means the number of BYTES to remove */ + delta *= buf->framesize; + + while (delta) { + if (buf->last->used >= delta) { + fprintf(stderr, "Subtracting from %d %d\n", buf->last->used, delta); + buf->last->used -= delta; + delta = 0; + } else { + fprintf(stderr, "Must do block-unuse\n"); + delta -= buf->last->used; + buf->last->used = 0; + buf->last->next = buf->unused; + buf->unused = buf->last; + buf->last = buf->unused->prev; + buf->unused->prev = NULL; + } + } +} +#endif + +void +sfx_audbuf_write_timestamp(sfx_audio_buf_t *buf, sfx_timestamp_t ts) +{ + sfx_timestamp_t newstamp; + + newstamp = sfx_timestamp_add(ts, -buf->frames_nr); + + + if (buf->read_timestamp.secs <= 0) + /* Initial stamp */ + buf->read_timestamp = newstamp; + else { + int delta = sfx_timestamp_frame_diff(newstamp, buf->read_timestamp); + long s1,s2,s3,u1,u2,u3; + sfx_timestamp_gettime(&(buf->read_timestamp), &s1, &u1); + sfx_timestamp_gettime(&(newstamp), &s2, &u2); + sfx_timestamp_gettime(&(ts), &s3, &u3); + + if (delta < 0) { +#if 0 + /* fprintf(stderr, "[SFX-BUF] audiobuf.c: Timestamp delta %d at %d: Must rewind (not implemented yet)\n", + delta, buf->read_timestamp.frame_rate);*/ + _sfx_audbuf_rewind_stream(buf, -delta); + buf->read_timestamp = newstamp; +#endif + } else if (delta > 0) { + fprintf(stderr, "[SFX-BUF] audiobuf.c: Timestamp delta %d at %d: Filling in as silence frames\n", + delta, buf->read_timestamp.frame_rate); + /* Fill up with silence */ + while (delta--) { + sfx_audbuf_write(buf, buf->last_frame, 1); + } + buf->read_timestamp = newstamp; + } + } +} + +int +sfx_audbuf_read_timestamp(sfx_audio_buf_t *buf, sfx_timestamp_t *ts) +{ + if (buf->read_timestamp.secs > 0) { + *ts = buf->read_timestamp; + return 0; + } else { + ts->secs = -1; + ts->usecs = -1; + ts->frame_offset = -1; + ts->frame_rate = -1; + return 1; /* No timestamp */ + } +} |