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
This commit is contained in:
Michael Sevakis 2007-02-07 00:51:50 +00:00
parent dd50c863e6
commit aba6ca0881
21 changed files with 170 additions and 256 deletions

View file

@ -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 */

View file

@ -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);

View file

@ -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)

View file

@ -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;

View file

@ -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)*

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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);
}

View file

@ -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);

View file

@ -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;

View file

@ -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())

View file

@ -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));
}

View file

@ -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;

View file

@ -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 ();

View file

@ -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)

View file

@ -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);

View file

@ -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)
{

View file

@ -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);

View file

@ -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;