From aba6ca0881d1481b4047b2d7834d70ca2eb5c64b Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Wed, 7 Feb 2007 00:51:50 +0000 Subject: [PATCH] Fix resampling clicking as much as possible at the moment. 1) Upsampling clicked because of size inaccuracies returned by DSP. Fix by simplifying audio system to use per-channel sample count from codec to pcm buffer. 2) Downsampling affected by 1) and was often starting passed the end of the data when not enough was available to generate an output sample. Fix by clamping input range to last sample in buffer and using the last sample value in the buffer. A perfect fix will require a double buffering scheme on the resampler to sufficient data during small data transients on both ends at all times of the down ratio on input and the up ratio on output. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12218 a1c6a512-1295-4272-9138-f99709370657 --- apps/codecs.c | 1 - apps/codecs.h | 7 +-- apps/codecs/a52.c | 7 +-- apps/codecs/aac.c | 8 +-- apps/codecs/adx.c | 7 ++- apps/codecs/aiff.c | 17 +++--- apps/codecs/alac.c | 5 +- apps/codecs/flac.c | 7 +-- apps/codecs/mpa.c | 10 ++-- apps/codecs/mpc.c | 7 +-- apps/codecs/nsf.c | 4 +- apps/codecs/shorten.c | 7 +-- apps/codecs/sid.c | 3 +- apps/codecs/vorbis.c | 5 +- apps/codecs/wav.c | 25 ++++---- apps/codecs/wavpack.c | 3 +- apps/dsp.c | 130 +++++++++++++++++------------------------- apps/dsp.h | 6 +- apps/pcmbuf.c | 30 +++++----- apps/pcmbuf.h | 8 +-- apps/playback.c | 129 ++++++++++++++--------------------------- 21 files changed, 170 insertions(+), 256 deletions(-) diff --git a/apps/codecs.c b/apps/codecs.c index 3af5158fbb..09fd6e522e 100644 --- a/apps/codecs.c +++ b/apps/codecs.c @@ -78,7 +78,6 @@ struct codec_api ci = { 0, /* seek_time */ NULL, /* get_codec_memory */ NULL, /* pcmbuf_insert */ - NULL, /* pcmbuf_insert_split */ NULL, /* set_elapsed */ NULL, /* read_filebuf */ NULL, /* request_buffer */ diff --git a/apps/codecs.h b/apps/codecs.h index e474c7a6bb..993ef3fecb 100644 --- a/apps/codecs.h +++ b/apps/codecs.h @@ -90,12 +90,12 @@ #define CODEC_ENC_MAGIC 0x52454E43 /* RENC */ /* increase this every time the api struct changes */ -#define CODEC_API_VERSION 12 +#define CODEC_API_VERSION 13 /* update this to latest version if a change to the api struct breaks backwards compatibility (and please take the opportunity to sort in any new function which are "waiting" at the end of the function table) */ -#define CODEC_MIN_API_VERSION 12 +#define CODEC_MIN_API_VERSION 13 /* codec return codes */ enum codec_status { @@ -133,8 +133,7 @@ struct codec_api { void* (*get_codec_memory)(size_t *size); /* Insert PCM data into audio buffer for playback. Playback will start automatically. */ - bool (*pcmbuf_insert)(const char *data, size_t length); - bool (*pcmbuf_insert_split)(const void *ch1, const void *ch2, size_t length); + bool (*pcmbuf_insert)(const void *ch1, const void *ch2, int count); /* Set song position in WPS (value in ms). */ void (*set_elapsed)(unsigned int value); diff --git a/apps/codecs/a52.c b/apps/codecs/a52.c index 4f41bfeaf5..028dff6db5 100644 --- a/apps/codecs/a52.c +++ b/apps/codecs/a52.c @@ -35,12 +35,9 @@ unsigned long frequency; /* used outside liba52 */ static uint8_t buf[3840] IBSS_ATTR; -void output_audio(sample_t *samples) +static inline void output_audio(sample_t *samples) { - do { - ci->yield(); - } while (!ci->pcmbuf_insert_split(&samples[0], &samples[256], - 256*sizeof(sample_t))); + ci->pcmbuf_insert(&samples[0], &samples[256], 256); } void a52_decode_data(uint8_t *start, uint8_t *end) diff --git a/apps/codecs/aac.c b/apps/codecs/aac.c index 4695caab4a..7656c416fe 100644 --- a/apps/codecs/aac.c +++ b/apps/codecs/aac.c @@ -183,12 +183,8 @@ next_track: /* Output the audio */ ci->yield(); - while (!ci->pcmbuf_insert_split(decoder->time_out[0], - decoder->time_out[1], - frame_info.samples * 2)) - { - ci->sleep(1); - } + ci->pcmbuf_insert(decoder->time_out[0], decoder->time_out[1], + frame_info.samples >> 1); /* Update the elapsed-time indicator */ sound_samples_done += sample_duration; diff --git a/apps/codecs/adx.c b/apps/codecs/adx.c index 608d9f0a3f..85e55a4c38 100644 --- a/apps/codecs/adx.c +++ b/apps/codecs/adx.c @@ -320,9 +320,10 @@ next_track: } } - /* 2 bytes per sample */ - while (!ci->pcmbuf_insert((char *)samples, sampleswritten*2)) - ci->yield(); + if (channels == 2) + sampleswritten >>= 1; /* make samples/channel */ + + ci->pcmbuf_insert(samples, NULL, sampleswritten); ci->set_elapsed( ((end_adr-start_adr)*loop_count + bufoff-chanstart)* diff --git a/apps/codecs/aiff.c b/apps/codecs/aiff.c index d1bb14aa64..628f9948ea 100644 --- a/apps/codecs/aiff.c +++ b/apps/codecs/aiff.c @@ -51,7 +51,8 @@ enum codec_status codec_main(void) uint16_t sample_size = 0; uint32_t sample_rate = 0; uint32_t i; - size_t n, bufsize; + size_t n; + int bufcount; int endofstream; unsigned char *buf; uint8_t *aifbuf; @@ -229,25 +230,27 @@ next_track: samples[i/4] = (SE(aifbuf[i])<<21)|(aifbuf[i + 1]<<13) |(aifbuf[i + 2]<<5)|(aifbuf[i + 3]>>3); } - bufsize = n; + bufcount = n >> 2; } else if (sample_size > 16) { for (i = 0; i < n; i += 3) { samples[i/3] = (SE(aifbuf[i])<<21)|(aifbuf[i + 1]<<13) |(aifbuf[i + 2]<<5); } - bufsize = n*4/3; + bufcount = n/3; } else if (sample_size > 8) { for (i = 0; i < n; i += 2) samples[i/2] = (SE(aifbuf[i])<<21)|(aifbuf[i + 1]<<13); - bufsize = n*2; + bufcount = n >> 1; } else { for (i = 0; i < n; i++) samples[i] = SE(aifbuf[i]) << 21; - bufsize = n*4; + bufcount = n; } - while (!ci->pcmbuf_insert((char *)samples, bufsize)) - ci->yield(); + if (num_channels == 2) + bufcount >>= 1; + + ci->pcmbuf_insert(samples, NULL, bufcount); ci->advance_buffer(n); bytesdone += n; diff --git a/apps/codecs/alac.c b/apps/codecs/alac.c index 1c1b14a0da..cfa713a29a 100644 --- a/apps/codecs/alac.c +++ b/apps/codecs/alac.c @@ -121,10 +121,7 @@ enum codec_status codec_main(void) /* Output the audio */ ci->yield(); - while(!ci->pcmbuf_insert_split(outputbuffer[0], - outputbuffer[1], - samplesdecoded*sizeof(int32_t))) - ci->yield(); + ci->pcmbuf_insert(outputbuffer[0], outputbuffer[1], samplesdecoded); /* Update the elapsed-time indicator */ samplesdone+=sample_duration; diff --git a/apps/codecs/flac.c b/apps/codecs/flac.c index 649c26a6bb..738e4bb391 100644 --- a/apps/codecs/flac.c +++ b/apps/codecs/flac.c @@ -489,11 +489,8 @@ enum codec_status codec_main(void) frame++; ci->yield(); - while(!ci->pcmbuf_insert_split((char*)&decoded0[fc.sample_skip], - (char*)&decoded1[fc.sample_skip], - (fc.blocksize-fc.sample_skip)*4)) { - ci->yield(); - } + ci->pcmbuf_insert(&decoded0[fc.sample_skip], &decoded1[fc.sample_skip], + fc.blocksize - fc.sample_skip); fc.sample_skip = 0; diff --git a/apps/codecs/mpa.c b/apps/codecs/mpa.c index 6e474c1abb..4c99778071 100644 --- a/apps/codecs/mpa.c +++ b/apps/codecs/mpa.c @@ -199,9 +199,9 @@ next_track: loop we will need to process the final frame that was decoded. */ if (framelength > 0) { /* In case of a mono file, the second array will be ignored. */ - ci->pcmbuf_insert_split(&synth.pcm.samples[0][samples_to_skip], - &synth.pcm.samples[1][samples_to_skip], - framelength * 4); + ci->pcmbuf_insert(&synth.pcm.samples[0][samples_to_skip], + &synth.pcm.samples[1][samples_to_skip], + framelength); /* Only skip samples for the first frame added. */ samples_to_skip = 0; @@ -244,8 +244,8 @@ next_track: /* Finish the remaining decoded frame. Cut the required samples from the end. */ if (framelength > stop_skip) - ci->pcmbuf_insert_split(synth.pcm.samples[0], synth.pcm.samples[1], - (framelength - stop_skip) * 4); + ci->pcmbuf_insert(synth.pcm.samples[0], synth.pcm.samples[1], + framelength - stop_skip); stream.error = 0; diff --git a/apps/codecs/mpc.c b/apps/codecs/mpc.c index 1075d88aa1..8aba8e50c2 100644 --- a/apps/codecs/mpc.c +++ b/apps/codecs/mpc.c @@ -168,10 +168,9 @@ next_track: retval = CODEC_ERROR; goto done; } else { - while (!ci->pcmbuf_insert_split(sample_buffer, - sample_buffer + MPC_FRAME_LENGTH, - status*sizeof(MPC_SAMPLE_FORMAT))) - ci->yield(); + ci->pcmbuf_insert(sample_buffer, + sample_buffer + MPC_FRAME_LENGTH, + status); samplesdone += status; ci->set_elapsed(samplesdone/frequency); } diff --git a/apps/codecs/nsf.c b/apps/codecs/nsf.c index 77043b60ce..f138fa1e01 100644 --- a/apps/codecs/nsf.c +++ b/apps/codecs/nsf.c @@ -4445,9 +4445,7 @@ init_nsf: goto init_nsf; } - while (!ci->pcmbuf_insert((char *)samples, written)) - ci->yield(); - + ci->pcmbuf_insert(samples, NULL, written >> 1); } print_timers(last_path,track); diff --git a/apps/codecs/shorten.c b/apps/codecs/shorten.c index 1b9563a676..3c099bc031 100644 --- a/apps/codecs/shorten.c +++ b/apps/codecs/shorten.c @@ -134,11 +134,8 @@ seek_start: /* Insert decoded samples in pcmbuf */ if (nsamples) { ci->yield(); - while (!ci->pcmbuf_insert_split((char*)(decoded0 + sc.nwrap), - (char*)(decoded1 + sc.nwrap), - 4*nsamples)) { - ci->yield(); - } + ci->pcmbuf_insert(decoded0 + sc.nwrap, decoded1 + sc.nwrap, + nsamples); /* Update the elapsed-time indicator */ samplesdone += nsamples; diff --git a/apps/codecs/sid.c b/apps/codecs/sid.c index 58eb725057..59683e9b6a 100644 --- a/apps/codecs/sid.c +++ b/apps/codecs/sid.c @@ -1309,8 +1309,7 @@ next_track: } } - while (!ci->pcmbuf_insert((char *)samples, CHUNK_SIZE*4)) - ci->yield(); + ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE); } if (ci->request_next_track()) diff --git a/apps/codecs/vorbis.c b/apps/codecs/vorbis.c index a6a90654b5..8ab4a95faa 100644 --- a/apps/codecs/vorbis.c +++ b/apps/codecs/vorbis.c @@ -217,10 +217,7 @@ next_track: } else if (n < 0) { DEBUGF("Error decoding frame\n"); } else { - while (!ci->pcmbuf_insert_split(pcm[0], pcm[1], - n*sizeof(ogg_int32_t))) { - ci->sleep(1); - } + ci->pcmbuf_insert(pcm[0], pcm[1], n); ci->set_offset(ov_raw_tell(&vf)); ci->set_elapsed(ov_time_tell(&vf)); } diff --git a/apps/codecs/wav.c b/apps/codecs/wav.c index 26cbf7f6a1..ec268a3a2b 100644 --- a/apps/codecs/wav.c +++ b/apps/codecs/wav.c @@ -212,7 +212,8 @@ enum codec_status codec_main(void) int bytespersample = 0; uint16_t bitspersample; uint32_t i; - size_t n, bufsize; + size_t n; + int bufcount; int endofstream; unsigned char *buf; uint8_t *wavbuf; @@ -466,34 +467,39 @@ next_track: (wavbuf[i + 1]<<5)|(wavbuf[i + 2]<<13)| (SE(wavbuf[i + 3])<<21); } - bufsize = n; + bufcount = n >> 2; } else if (bitspersample > 16) { for (i = 0; i < n; i += 3) { samples[i/3] = (wavbuf[i]<<5)| (wavbuf[i + 1]<<13)|(SE(wavbuf[i + 2])<<21); } - bufsize = n*4/3; + bufcount = n/3; } else if (bitspersample > 8) { for (i = 0; i < n; i += 2) { samples[i/2] = (wavbuf[i]<<13)|(SE(wavbuf[i + 1])<<21); } - bufsize = n*2; + bufcount = n >> 1; } else { for (i = 0; i < n; i++) { samples[i] = (wavbuf[i] - 0x80)<<21; } - bufsize = n*4; + bufcount = n; } + + if (channels == 2) + bufcount >>= 1; } else if (formattag == WAVE_FORMAT_ALAW || formattag == IBM_FORMAT_ALAW) { for (i = 0; i < n; i++) samples[i] = alaw2linear16[wavbuf[i]] << 13; - bufsize = n*4; + + bufcount = (channels == 2) ? (n >> 1) : n; } else if (formattag == WAVE_FORMAT_MULAW || formattag == IBM_FORMAT_MULAW) { for (i = 0; i < n; i++) samples[i] = ulaw2linear16[wavbuf[i]] << 13; - bufsize = n*4; + + bufcount = (channels == 2) ? (n >> 1) : n; } else if (formattag == WAVE_FORMAT_DVI_ADPCM) { unsigned int nblocks = chunksize/blockalign; @@ -508,15 +514,14 @@ next_track: goto done; } } - bufsize = nblocks*samplesperblock*channels*4; + bufcount = nblocks*samplesperblock; } else { DEBUGF("CODEC_ERROR: unsupported format %x\n", formattag); i = CODEC_ERROR; goto done; } - while (!ci->pcmbuf_insert((char *)samples, bufsize)) - ci->yield(); + ci->pcmbuf_insert(samples, NULL, bufcount); ci->advance_buffer(n); bytesdone += n; diff --git a/apps/codecs/wavpack.c b/apps/codecs/wavpack.c index e2c19c82e4..34616d75e9 100644 --- a/apps/codecs/wavpack.c +++ b/apps/codecs/wavpack.c @@ -118,8 +118,7 @@ enum codec_status codec_main(void) if (ci->stop_codec || ci->new_track) break; - while (!ci->pcmbuf_insert ((char *) temp_buffer, nsamples * nchans * 4)) - ci->sleep (1); + ci->pcmbuf_insert (temp_buffer, NULL, nsamples); ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10); ci->yield (); diff --git a/apps/dsp.c b/apps/dsp.c index c4630ada77..f7eb48ed03 100644 --- a/apps/dsp.c +++ b/apps/dsp.c @@ -40,8 +40,8 @@ #define WORD_FRACBITS 27 #define NATIVE_DEPTH 16 -#define SAMPLE_BUF_SIZE 256 -#define RESAMPLE_BUF_SIZE (256 * 4) /* Enough for 11,025 Hz -> 44,100 Hz*/ +#define SAMPLE_BUF_COUNT 256 +#define RESAMPLE_BUF_COUNT (256 * 4) /* Enough for 11,025 Hz -> 44,100 Hz*/ #define DEFAULT_GAIN 0x01000000 struct dsp_config @@ -116,8 +116,8 @@ static struct dsp_config *dsp; * of copying needed is minimized for that case. */ -static int32_t sample_buf[SAMPLE_BUF_SIZE] IBSS_ATTR; -static int32_t resample_buf[RESAMPLE_BUF_SIZE] IBSS_ATTR; +static int32_t sample_buf[SAMPLE_BUF_COUNT] IBSS_ATTR; +static int32_t resample_buf[RESAMPLE_BUF_COUNT] IBSS_ATTR; int sound_get_pitch(void) { @@ -139,14 +139,14 @@ void sound_set_pitch(int permille) */ static int convert_to_internal(const char* src[], int count, int32_t* dst[]) { - count = MIN(SAMPLE_BUF_SIZE / 2, count); + count = MIN(SAMPLE_BUF_COUNT / 2, count); if ((dsp->sample_depth <= NATIVE_DEPTH) || (dsp->stereo_mode == STEREO_INTERLEAVED)) { dst[0] = &sample_buf[0]; dst[1] = (dsp->stereo_mode == STEREO_MONO) - ? dst[0] : &sample_buf[SAMPLE_BUF_SIZE / 2]; + ? dst[0] : &sample_buf[SAMPLE_BUF_COUNT / 2]; } else { @@ -231,7 +231,7 @@ static void resampler_set_delta(int frequency) /* TODO: we really should have a separate set of resample functions for both mono and stereo to avoid all this internal branching and looping. */ -static long downsample(int32_t **dst, int32_t **src, int count, +static int downsample(int32_t **dst, int32_t **src, int count, struct resample_data *r) { long phase = r->phase; @@ -246,11 +246,14 @@ static long downsample(int32_t **dst, int32_t **src, int count, last_sample = r->last_sample[j]; /* Do we need last sample of previous frame for interpolation? */ if (pos > 0) - { last_sample = src[j][pos - 1]; - } - *d[j]++ = last_sample + FRACMUL((phase & 0xffff) << 15, - src[j][pos] - last_sample); + + /* Be sure starting position isn't passed the available data */ + if (pos < count) + *d[j]++ = last_sample + FRACMUL((phase & 0xffff) << 15, + src[j][pos] - last_sample); + else /* This is kinda nasty but works somewhat well for now */ + *d[j]++ = src[j][count - 1]; } phase += delta; @@ -316,7 +319,7 @@ static inline int resample(int32_t* src[], int count) if (dsp->frequency != NATIVE_FREQUENCY) { - int32_t* dst[2] = {&resample_buf[0], &resample_buf[RESAMPLE_BUF_SIZE / 2]}; + int32_t* dst[2] = {&resample_buf[0], &resample_buf[RESAMPLE_BUF_COUNT / 2]}; if (dsp->frequency < NATIVE_FREQUENCY) { @@ -619,7 +622,7 @@ static void apply_gain(int32_t* _src[], int _count) if (s0 != s1) { - d = &sample_buf[SAMPLE_BUF_SIZE / 2]; + d = &sample_buf[SAMPLE_BUF_COUNT / 2]; src[1] = d; s = *s1++; @@ -736,18 +739,17 @@ static void write_samples(short* dst, int32_t* src[], int count) } /* Process and convert src audio to dst based on the DSP configuration, - * reading size bytes of audio data. dst is assumed to be large enough; use - * dst_get_dest_size() to get the required size. src is an array of - * pointers; for mono and interleaved stereo, it contains one pointer to the - * start of the audio data; for non-interleaved stereo, it contains two - * pointers, one for each audio channel. Returns number of bytes written to - * dest. + * reading count number of audio samples. dst is assumed to be large + * enough; use dsp_output_count() to get the required number. src is an + * array of pointers; for mono and interleaved stereo, it contains one + * pointer to the start of the audio data and the other is ignored; for + * non-interleaved stereo, it contains two pointers, one for each audio + * channel. Returns number of bytes written to dst. */ -long dsp_process(char* dst, const char* src[], long size) +int dsp_process(char *dst, const char *src[], int count) { int32_t* tmp[2]; - long written = 0; - long factor; + int written = 0; int samples; #if defined(CPU_COLDFIRE) && !defined(SIMULATOR) @@ -759,14 +761,12 @@ long dsp_process(char* dst, const char* src[], long size) dsp = &dsp_conf[current_codec]; - factor = (dsp->stereo_mode != STEREO_MONO) ? 2 : 1; - size /= dsp->sample_bytes * factor; dsp_set_replaygain(false); - while (size > 0) + while (count > 0) { - samples = convert_to_internal(src, size, tmp); - size -= samples; + samples = convert_to_internal(src, count, tmp); + count -= samples; apply_gain(tmp, samples); samples = resample(tmp, samples); if (dsp->crossfeed_enabled && dsp->stereo_mode != STEREO_MONO) @@ -780,85 +780,61 @@ long dsp_process(char* dst, const char* src[], long size) dst += samples * sizeof(short) * 2; yield(); } + #if defined(CPU_COLDFIRE) && !defined(SIMULATOR) /* set old macsr again */ coldfire_set_macsr(old_macsr); #endif - return written * sizeof(short) * 2; + return written; } -/* Given size bytes of input data, calculate the maximum number of bytes of - * output data that would be generated (the calculation is not entirely - * exact and rounds upwards to be on the safe side; during resampling, - * the number of samples generated depends on the current state of the - * resampler). +/* Given count number of input samples, calculate the maximum number of + * samples of output data that would be generated (the calculation is not + * entirely exact and rounds upwards to be on the safe side; during + * resampling, the number of samples generated depends on the current state + * of the resampler). */ /* dsp_input_size MUST be called afterwards */ -long dsp_output_size(long size) +int dsp_output_count(int count) { dsp = &dsp_conf[current_codec]; - if (dsp->sample_depth > NATIVE_DEPTH) - { - size /= 2; - } - if (dsp->frequency != NATIVE_FREQUENCY) { - size = (long) ((((unsigned long) size * NATIVE_FREQUENCY) - + (dsp->frequency - 1)) / dsp->frequency); + count = (int)(((unsigned long)count * NATIVE_FREQUENCY + + (dsp->frequency - 1)) / dsp->frequency); } - /* round to the next multiple of 2 (these are shorts) */ - size = (size + 1) & ~1; + /* Now we have the resampled sample count which must not exceed + * RESAMPLE_BUF_COUNT/2 to avoid resample buffer overflow. One + * must call dsp_input_count() to get the correct input sample + * count. + */ + if (count > RESAMPLE_BUF_COUNT/2) + count = RESAMPLE_BUF_COUNT/2; - if (dsp->stereo_mode == STEREO_MONO) - { - size *= 2; - } - - /* now we have the size in bytes for two resampled channels, - * and the size in (short) must not exceed RESAMPLE_BUF_SIZE to - * avoid resample buffer overflow. One must call dsp_input_size() - * to get the correct input buffer size. */ - if (size > RESAMPLE_BUF_SIZE*2) - size = RESAMPLE_BUF_SIZE*2; - - return size; + return count; } -/* Given size bytes of output buffer, calculate number of bytes of input - * data that would be consumed in order to fill the output buffer. +/* Given count output samples, calculate number of input samples + * that would be consumed in order to fill the output buffer. */ -long dsp_input_size(long size) +int dsp_input_count(int count) { dsp = &dsp_conf[current_codec]; - - /* convert to number of output stereo samples. */ - size /= 2; - /* Mono means we need half input samples to fill the output buffer */ - if (dsp->stereo_mode == STEREO_MONO) - size /= 2; - - /* size is now the number of resampled input samples. Convert to + /* count is now the number of resampled input samples. Convert to original input samples. */ if (dsp->frequency != NATIVE_FREQUENCY) { /* Use the real resampling delta = - * (unsigned long) dsp->frequency * 65536 / NATIVE_FREQUENCY, and + * dsp->frequency * 65536 / NATIVE_FREQUENCY, and * round towards zero to avoid buffer overflows. */ - size = ((unsigned long)size * - resample_data[current_codec].delta) >> 16; + count = (int)(((unsigned long)count * + resample_data[current_codec].delta) >> 16); } - /* Convert back to bytes. */ - if (dsp->sample_depth > NATIVE_DEPTH) - size *= 4; - else - size *= 2; - - return size; + return count; } int dsp_stereo_mode(void) diff --git a/apps/dsp.h b/apps/dsp.h index ccea8cba34..5217224797 100644 --- a/apps/dsp.h +++ b/apps/dsp.h @@ -206,9 +206,9 @@ enum { #define DIV64(x, y, z) (long)(((long long)(x) << (z))/(y)) -long dsp_process(char *dest, const char *src[], long size); -long dsp_input_size(long size); -long dsp_output_size(long size); +int dsp_process(char *dest, const char *src[], int count); +int dsp_input_count(int count); +int dsp_output_count(int count); int dsp_stereo_mode(void); bool dsp_configure(int setting, void *value); void dsp_set_replaygain(bool always); diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index f9d60e9b58..e2b1d7f87b 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c @@ -791,21 +791,20 @@ static bool prepare_insert(size_t length) return true; } -void* pcmbuf_request_buffer(size_t length, size_t *realsize) +void* pcmbuf_request_buffer(int *count) { if (crossfade_init) crossfade_start(); if (crossfade_active) { - *realsize = MIN(length, PCMBUF_MIX_CHUNK); + *count = MIN(*count, PCMBUF_MIX_CHUNK/4); return fadebuf; } else { - if(prepare_insert(length)) + if(prepare_insert(*count << 2)) { size_t audiobuffer_index = audiobuffer_pos + audiobuffer_fillpos; - *realsize = length; if (pcmbuf_size - audiobuffer_index >= PCMBUF_MIN_CHUNK) { /* Usual case, there's space here */ @@ -821,34 +820,31 @@ void* pcmbuf_request_buffer(size_t length, size_t *realsize) } else { - *realsize = 0; return NULL; } } } -void* pcmbuf_request_voice_buffer(size_t length, size_t *realsize, bool mix) +void* pcmbuf_request_voice_buffer(int *count, bool mix) { if (mix) { if (pcmbuf_read == NULL) { - *realsize = 0; return NULL; } else if (pcmbuf_mix_chunk || pcmbuf_read->link) { - *realsize = MIN(length, PCMBUF_MIX_CHUNK); + *count = MIN(*count, PCMBUF_MIX_CHUNK/4); return voicebuf; } else { - *realsize = 0; return NULL; } } else - return pcmbuf_request_buffer(length, realsize); + return pcmbuf_request_buffer(count); } bool pcmbuf_is_crossfade_active(void) @@ -856,8 +852,10 @@ bool pcmbuf_is_crossfade_active(void) return crossfade_active || crossfade_init; } -void pcmbuf_write_complete(size_t length) +void pcmbuf_write_complete(int count) { + size_t length = (size_t)(unsigned int)count << 2; + if (crossfade_active) { flush_crossfade(fadebuf, length); @@ -874,8 +872,10 @@ void pcmbuf_write_complete(size_t length) } #if 0 -bool pcmbuf_insert_buffer(char *buf, size_t length) +bool pcmbuf_insert_buffer(char *buf, int count) { + size_t length = (size_t)(unsigned int)count << 2; + if (crossfade_active) { flush_crossfade(buf, length); @@ -980,7 +980,7 @@ int pcmbuf_mix_free(void) return 100; } -void pcmbuf_mix_voice(size_t length) +void pcmbuf_mix_voice(int count) { short *ibuf = (short *)voicebuf; short *obuf; @@ -998,9 +998,9 @@ void pcmbuf_mix_voice(size_t length) obuf = (short *)pcmbuf_mix_chunk->addr; chunk_samples = pcmbuf_mix_chunk->size / 2; - length /= 2; + count <<= 1; - while (length-- > 0) { + while (count-- > 0) { int sample = *ibuf++; if (pcmbuf_mix_sample >= chunk_samples) { diff --git a/apps/pcmbuf.h b/apps/pcmbuf.h index a408cdae42..5c35ecc291 100644 --- a/apps/pcmbuf.h +++ b/apps/pcmbuf.h @@ -63,16 +63,16 @@ void pcmbuf_set_position_callback(void (*callback)(size_t size)); size_t pcmbuf_free(void); unsigned int pcmbuf_get_latency(void); void pcmbuf_set_low_latency(bool state); -void pcmbuf_write_complete(size_t length); -void* pcmbuf_request_buffer(size_t length, size_t *realsize); -void* pcmbuf_request_voice_buffer(size_t length, size_t *realsize, bool mix); +void pcmbuf_write_complete(int count); +void* pcmbuf_request_buffer(int *count); +void* pcmbuf_request_voice_buffer(int *count, bool mix); bool pcmbuf_is_crossfade_enabled(void); void pcmbuf_crossfade_enable(bool on_off); int pcmbuf_usage(void); int pcmbuf_mix_free(void); void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude); -void pcmbuf_mix_voice(size_t length); +void pcmbuf_mix_voice(int count); int pcmbuf_used_descs(void); int pcmbuf_descs(void); diff --git a/apps/playback.c b/apps/playback.c index ff681bb85c..939643890e 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -1022,81 +1022,60 @@ static const char * get_codec_filename(int cod_spec) #ifdef PLAYBACK_VOICE -static bool voice_pcmbuf_insert_split_callback( - const void *ch1, const void *ch2, size_t length) +static bool voice_pcmbuf_insert_callback( + const void *ch1, const void *ch2, int count) { - const char* src[2]; - char *dest; - long input_size; - size_t output_size; + const char *src[2] = { ch1, ch2 }; - src[0] = ch1; - src[1] = ch2; - - if (dsp_stereo_mode() == STEREO_NONINTERLEAVED) - length *= 2; /* Length is per channel */ - - while (length) + while (count > 0) { - long est_output_size = dsp_output_size(length); - - while ((dest = pcmbuf_request_voice_buffer(est_output_size, - &output_size, playing)) == NULL) + int out_count = dsp_output_count(count); + int inp_count; + char *dest; + + while ((dest = pcmbuf_request_voice_buffer( + &out_count, playing)) == NULL) { if (playing && audio_codec_loaded) swap_codec(); else yield(); } - + /* Get the real input_size for output_size bytes, guarding * against resampling buffer overflows. */ - input_size = dsp_input_size(output_size); + inp_count = dsp_input_count(out_count); - if (input_size <= 0) + if (inp_count <= 0) { - DEBUGF("Error: dsp_input_size(%ld=dsp_output_size(%ld))=%ld<=0\n", - output_size, length, input_size); + DEBUGF("Error: dsp_input_count(%ld=dsp_output_count(%ld))=%ld<=0\n", + out_count, count, inp_count); /* If this happens, there are samples of codec data that don't * become a number of pcm samples, and something is broken */ return false; } /* Input size has grown, no error, just don't write more than length */ - if ((size_t)input_size > length) - input_size = length; + if (inp_count > count) + inp_count = count; - output_size = dsp_process(dest, src, input_size); + out_count = dsp_process(dest, src, inp_count); if (playing) { - pcmbuf_mix_voice(output_size); + pcmbuf_mix_voice(out_count); if ((pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) && audio_codec_loaded) swap_codec(); } else - pcmbuf_write_complete(output_size); + pcmbuf_write_complete(out_count); - length -= input_size; + count -= inp_count; } return true; -} /* voice_pcmbuf_insert_split_callback */ - -static bool voice_pcmbuf_insert_callback(const char *buf, size_t length) -{ - /* TODO: The audiobuffer API should probably be updated, and be based on - * pcmbuf_insert_split(). */ - long real_length = length; - - if (dsp_stereo_mode() == STEREO_NONINTERLEAVED) - length /= 2; /* Length is per channel */ - - /* Second channel is only used for non-interleaved stereo. */ - return voice_pcmbuf_insert_split_callback(buf, buf + (real_length / 2), - length); -} +} /* voice_pcmbuf_insert_callback */ static void* voice_get_memory_callback(size_t *size) { @@ -1321,30 +1300,22 @@ static void voice_thread(void) #endif /* PLAYBACK_VOICE */ /* --- Codec thread --- */ - -static bool codec_pcmbuf_insert_split_callback( - const void *ch1, const void *ch2, size_t length) +static bool codec_pcmbuf_insert_callback( + const void *ch1, const void *ch2, int count) { - const char* src[2]; - char *dest; - long input_size; - size_t output_size; + const char *src[2] = { ch1, ch2 }; - src[0] = ch1; - src[1] = ch2; - - if (dsp_stereo_mode() == STEREO_NONINTERLEAVED) - length *= 2; /* Length is per channel */ - - while (length) + while (count > 0) { - long est_output_size = dsp_output_size(length); + int out_count = dsp_output_count(count); + int inp_count; + char *dest; + /* Prevent audio from a previous track from playing */ if (ci.new_track || ci.stop_codec) return true; - while ((dest = pcmbuf_request_buffer(est_output_size, - &output_size)) == NULL) + while ((dest = pcmbuf_request_buffer(&out_count)) == NULL) { sleep(1); if (ci.seek_time || ci.new_track || ci.stop_codec) @@ -1353,24 +1324,24 @@ static bool codec_pcmbuf_insert_split_callback( /* Get the real input_size for output_size bytes, guarding * against resampling buffer overflows. */ - input_size = dsp_input_size(output_size); + inp_count = dsp_input_count(out_count); - if (input_size <= 0) + if (inp_count <= 0) { - DEBUGF("Error: dsp_input_size(%ld=dsp_output_size(%ld))=%ld<=0\n", - output_size, length, input_size); + DEBUGF("Error: dsp_input_count(%ld=dsp_output_count(%ld))=%ld<=0\n", + out_count, count, inp_count); /* If this happens, there are samples of codec data that don't * become a number of pcm samples, and something is broken */ return false; } /* Input size has grown, no error, just don't write more than length */ - if ((size_t)input_size > length) - input_size = length; + if (inp_count > count) + inp_count = count; - output_size = dsp_process(dest, src, input_size); + out_count = dsp_process(dest, src, inp_count); - pcmbuf_write_complete(output_size); + pcmbuf_write_complete(out_count); #ifdef PLAYBACK_VOICE if ((voice_is_playing || voice_thread_start) @@ -1381,26 +1352,12 @@ static bool codec_pcmbuf_insert_split_callback( swap_codec(); } #endif - - length -= input_size; + + count -= inp_count; } return true; -} /* codec_pcmbuf_insert_split_callback */ - -static bool codec_pcmbuf_insert_callback(const char *buf, size_t length) -{ - /* TODO: The audiobuffer API should probably be updated, and be based on - * pcmbuf_insert_split(). */ - long real_length = length; - - if (dsp_stereo_mode() == STEREO_NONINTERLEAVED) - length /= 2; /* Length is per channel */ - - /* Second channel is only used for non-interleaved stereo. */ - return codec_pcmbuf_insert_split_callback(buf, buf + (real_length / 2), - length); -} +} /* codec_pcmbuf_insert_callback */ static void* codec_get_memory_callback(size_t *size) { @@ -3523,7 +3480,6 @@ static void audio_playback_init(void) /* Initialize codec api. */ ci.read_filebuf = codec_filebuf_callback; ci.pcmbuf_insert = codec_pcmbuf_insert_callback; - ci.pcmbuf_insert_split = codec_pcmbuf_insert_split_callback; ci.get_codec_memory = codec_get_memory_callback; ci.request_buffer = codec_request_buffer_callback; ci.advance_buffer = codec_advance_buffer_callback; @@ -3543,7 +3499,6 @@ static void audio_playback_init(void) memset(&id3_voice, 0, sizeof(struct mp3entry)); ci_voice.read_filebuf = voice_filebuf_callback; ci_voice.pcmbuf_insert = voice_pcmbuf_insert_callback; - ci_voice.pcmbuf_insert_split = voice_pcmbuf_insert_split_callback; ci_voice.get_codec_memory = voice_get_memory_callback; ci_voice.request_buffer = voice_request_buffer_callback; ci_voice.advance_buffer = voice_advance_buffer_callback;