First commit of reworking voice to be mroe stable on swcodec
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9758 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/codecs/a52.c b/apps/codecs/a52.c
index 8ad9d37..71e0fda 100644
--- a/apps/codecs/a52.c
+++ b/apps/codecs/a52.c
@@ -141,7 +141,6 @@
ci->memset(iedata, 0, iend - iedata);
#endif
- ci->configure(CODEC_DSP_ENABLE, (bool *)true);
ci->configure(DSP_DITHER, (bool *)false);
ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)28);
@@ -185,9 +184,11 @@
a52_decode_data(filebuf, filebuf + n);
ci->advance_buffer(n);
}
+ retval = CODEC_OK;
+
if (ci->request_next_track())
goto next_track;
- retval = CODEC_OK;
+
exit:
a52_free(state);
return retval;
diff --git a/apps/codecs/aac.c b/apps/codecs/aac.c
index 02d4606..532082f 100644
--- a/apps/codecs/aac.c
+++ b/apps/codecs/aac.c
@@ -63,7 +63,6 @@
ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*16));
ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
- ci->configure(CODEC_DSP_ENABLE, (bool *)true);
ci->configure(DSP_DITHER, (bool *)false);
ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(29));
@@ -88,7 +87,7 @@
if (!qtmovie_read(&input_stream, &demux_res)) {
LOGF("FAAD: Error initialising file\n");
err = CODEC_ERROR;
- goto exit;
+ goto done;
}
/* initialise the sound converter */
@@ -98,7 +97,7 @@
if (!hDecoder) {
LOGF("FAAD: Error opening decoder\n");
err = CODEC_ERROR;
- goto exit;
+ goto done;
}
NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(hDecoder);
@@ -112,7 +111,7 @@
if (err) {
LOGF("FAAD: Error initialising decoder: %d, type=%d\n", err,hDecoder->object_type);
err = CODEC_ERROR;
- goto exit;
+ goto done;
}
ci->id3->frequency=s;
@@ -142,7 +141,7 @@
&sample_byte_size)) {
LOGF("AAC: Error in get_sample_info\n");
err = CODEC_ERROR;
- goto exit;
+ goto done;
}
/* Request the required number of bytes from the input buffer */
@@ -156,7 +155,7 @@
if (frameInfo.error > 0) {
LOGF("FAAD: decoding error \"%s\"\n", NeAACDecGetErrorMessage(frameInfo.error));
err = CODEC_ERROR;
- goto exit;
+ goto done;
}
/* Get the number of decoded samples */
@@ -182,13 +181,14 @@
i++;
}
+ err = CODEC_OK;
+done:
LOGF("AAC: Decoded %d samples\n",samplesdone);
if (ci->request_next_track())
goto next_track;
- err = CODEC_OK;
exit:
return err;
}
diff --git a/apps/codecs/aiff.c b/apps/codecs/aiff.c
index 20d2dd3..1e7adca 100644
--- a/apps/codecs/aiff.c
+++ b/apps/codecs/aiff.c
@@ -98,11 +98,11 @@
buf = ci->request_buffer(&n, 1024);
if (n < 44) {
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
if ((memcmp(buf, "FORM", 4) != 0) || (memcmp(&buf[8], "AIFF", 4) != 0)) {
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
buf += 12;
@@ -117,7 +117,7 @@
if (i != 18) {
DEBUGF("CODEC_ERROR: 'COMM' chunk size=%lu != 18\n", i);
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
/* num_channels */
num_channels = ((buf[8]<<8)|buf[9]);
@@ -130,7 +130,7 @@
if (buf[16] != 0x40) {
DEBUGF("CODEC_ERROR: weird sampling rate (no @)\n", i);
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
sample_rate = ((buf[18]<<24)|(buf[19]<<16)|(buf[20]<<8)|buf[21])+1;
sample_rate = sample_rate >> (16 + 14 - buf[17]);
@@ -140,7 +140,7 @@
if (sample_size == 0) {
DEBUGF("CODEC_ERROR: unsupported chunk order\n");
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
/* offset2snd */
offset2snd = ((buf[8]<<8)|buf[9]);
@@ -161,7 +161,7 @@
if (n < (i + 8)) {
DEBUGF("CODEC_ERROR: AIFF header size > 1024\n");
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
n -= i + 8;
} /* while 'SSND' */
@@ -169,21 +169,20 @@
if (num_channels == 0) {
DEBUGF("CODEC_ERROR: 'COMM' chunk not found or 0-channels file\n");
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
if (numbytes == 0) {
DEBUGF("CODEC_ERROR: 'SSND' chunk not found or has zero length\n");
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
if (sample_size > 24) {
DEBUGF("CODEC_ERROR: PCM with more than 24 bits per sample "
"is unsupported\n");
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
- ci->configure(CODEC_DSP_ENABLE, (bool *)true);
ci->configure(DSP_SET_FREQUENCY, (long *)(ci->id3->frequency));
ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)28);
@@ -194,7 +193,7 @@
} else {
DEBUGF("CODEC_ERROR: more than 2 channels unsupported\n");
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
firstblockposn = 1024 - n;
@@ -277,11 +276,12 @@
ci->set_elapsed(bytesdone*1000LL/avgbytespersec);
}
+ i = CODEC_OK;
+done:
if (ci->request_next_track())
goto next_track;
- i = CODEC_OK;
exit:
return i;
}
diff --git a/apps/codecs/alac.c b/apps/codecs/alac.c
index 73f45fc..01172ee 100644
--- a/apps/codecs/alac.c
+++ b/apps/codecs/alac.c
@@ -64,7 +64,6 @@
ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128));
- ci->configure(CODEC_DSP_ENABLE, (bool *)true);
ci->configure(DSP_DITHER, (bool *)false);
ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(ALAC_OUTPUT_DEPTH-1));
@@ -89,7 +88,7 @@
if (!qtmovie_read(&input_stream, &demux_res)) {
LOGF("ALAC: Error initialising file\n");
retval = CODEC_ERROR;
- goto exit;
+ goto done;
}
/* initialise the sound converter */
@@ -121,7 +120,7 @@
&sample_byte_size)) {
LOGF("ALAC: Error in get_sample_info\n");
retval = CODEC_ERROR;
- goto exit;
+ goto done;
}
/* Request the required number of bytes from the input buffer */
@@ -129,7 +128,7 @@
buffer=ci->request_buffer(&n,sample_byte_size);
if (n!=sample_byte_size) {
retval = CODEC_ERROR;
- goto exit;
+ goto done;
}
/* Decode one block - returned samples will be host-endian */
@@ -156,13 +155,14 @@
i++;
}
+ retval = CODEC_OK;
+done:
LOGF("ALAC: Decoded %d samples\n",samplesdone);
if (ci->request_next_track())
goto next_track;
- retval = CODEC_OK;
exit:
return retval;
}
diff --git a/apps/codecs/flac.c b/apps/codecs/flac.c
index cc2ce63..5e392da 100644
--- a/apps/codecs/flac.c
+++ b/apps/codecs/flac.c
@@ -224,7 +224,7 @@
{
int8_t *buf;
FLACContext fc;
- uint32_t samplesdone;
+ uint32_t samplesdone = 0;
uint32_t elapsedtime;
size_t bytesleft;
int consumed;
@@ -244,7 +244,6 @@
ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128));
- ci->configure(CODEC_DSP_ENABLE, (bool *)true);
ci->configure(DSP_DITHER, (bool *)false);
ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(FLAC_OUTPUT_DEPTH-1));
@@ -260,7 +259,7 @@
if (!flac_init(&fc,ci->id3->first_frame_offset)) {
LOGF("FLAC: Error initialising codec\n");
retval = CODEC_ERROR;
- goto exit;
+ goto done;
}
while (!*ci->taginfo_ready)
@@ -292,7 +291,7 @@
bytesleft,ci->yield)) < 0) {
LOGF("FLAC: Frame %d, error %d\n",frame,res);
retval = CODEC_ERROR;
- goto exit;
+ goto done;
}
consumed=fc.gb.index/8;
frame++;
@@ -312,12 +311,14 @@
buf = ci->request_buffer(&bytesleft, MAX_FRAMESIZE);
}
+ retval = CODEC_OK;
+
+done:
LOGF("FLAC: Decoded %d samples\n",samplesdone);
if (ci->request_next_track())
goto next_track;
- retval = CODEC_OK;
exit:
return retval;
}
diff --git a/apps/codecs/mpa.c b/apps/codecs/mpa.c
index 7219095..51038c5 100644
--- a/apps/codecs/mpa.c
+++ b/apps/codecs/mpa.c
@@ -91,7 +91,7 @@
/* this is the codec entry point */
enum codec_status codec_start(struct codec_api *api)
{
- int status = CODEC_OK;
+ int status;
size_t size;
int file_end;
int frame_skip; /* samples to skip current frame */
@@ -110,7 +110,6 @@
/* Create a decoder instance */
- ci->configure(CODEC_DSP_ENABLE, (bool *)true);
ci->configure(DSP_DITHER, (bool *)false);
ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(MAD_F_FRACBITS));
ci->configure(DSP_SET_CLIP_MIN, (int *)-MAD_F_ONE);
@@ -122,6 +121,7 @@
* for gapless playback.
* Reinitializing seems to be necessary to avoid playback quircks when seeking. */
next_track:
+ status = CODEC_OK;
init_mad();
@@ -171,7 +171,7 @@
ci->id3->first_frame_offset;
if (!ci->seek_buffer(newpos))
- goto next_track;
+ break;
ci->seek_complete();
init_mad();
}
@@ -192,7 +192,7 @@
break;
/* Fill the buffer */
- if (stream.next_frame)
+ if (stream.next_frame && stream.next_frame != stream.this_frame)
ci->advance_buffer_loc((void *)stream.next_frame);
else
ci->advance_buffer(size);
diff --git a/apps/codecs/mpc.c b/apps/codecs/mpc.c
index 4201b25..ee63901 100644
--- a/apps/codecs/mpc.c
+++ b/apps/codecs/mpc.c
@@ -90,7 +90,6 @@
ci->memset(iedata, 0, iend - iedata);
#endif
- ci->configure(CODEC_DSP_ENABLE, (bool *)true);
ci->configure(DSP_DITHER, (bool *)false);
ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)(28));
ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (long *)(1024*16));
@@ -113,7 +112,7 @@
mpc_streaminfo_init(&info);
if (mpc_streaminfo_read(&info, &reader) != ERROR_CODE_OK) {
retval = CODEC_ERROR;
- goto exit;
+ goto done;
}
frequency = info.sample_freq;
ci->configure(DSP_SET_FREQUENCY, (long *)(long)info.sample_freq);
@@ -127,7 +126,7 @@
ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_MONO);
else {
retval = CODEC_ERROR;
- goto exit;
+ goto done;
}
codec_set_replaygain(ci->id3);
@@ -135,7 +134,7 @@
mpc_decoder_setup(&decoder, &reader);
if (!mpc_decoder_initialize(&decoder, &info)) {
retval = CODEC_ERROR;
- goto exit;
+ goto done;
}
/* This is the decoding loop. */
@@ -171,7 +170,7 @@
ci->yield();
if (status == (unsigned)(-1)) { /* decode error */
retval = CODEC_ERROR;
- goto exit;
+ goto done;
} else {
while (!ci->pcmbuf_insert_split(sample_buffer,
sample_buffer + MPC_FRAME_LENGTH,
@@ -181,11 +180,12 @@
ci->set_elapsed(samplesdone/(frequency/1000));
}
} while (status != 0);
-
+ retval = CODEC_OK;
+
+done:
if (ci->request_next_track())
goto next_track;
- retval = CODEC_OK;
exit:
return retval;
}
diff --git a/apps/codecs/shorten.c b/apps/codecs/shorten.c
index 03a0802..8d62a12 100644
--- a/apps/codecs/shorten.c
+++ b/apps/codecs/shorten.c
@@ -63,7 +63,6 @@
ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128));
- ci->configure(CODEC_DSP_ENABLE, (bool *)true);
ci->configure(DSP_DITHER, (bool *)false);
ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(SHN_OUTPUT_DEPTH-1));
@@ -146,7 +145,7 @@
if (res == FN_ERROR) {
LOGF("Shorten: shorten_decode_frames error (%d)\n", samplesdone);
- return CODEC_ERROR;
+ break;
} else {
/* Insert decoded samples in pcmbuf */
if (nsamples) {
diff --git a/apps/codecs/vorbis.c b/apps/codecs/vorbis.c
index a9a2745..1900364 100644
--- a/apps/codecs/vorbis.c
+++ b/apps/codecs/vorbis.c
@@ -129,7 +129,6 @@
rb->memset(iedata, 0, iend - iedata);
#endif
- rb->configure(CODEC_DSP_ENABLE, (bool *)true);
rb->configure(DSP_DITHER, (bool *)false);
rb->configure(DSP_SET_SAMPLE_DEPTH, (long *)24);
rb->configure(DSP_SET_CLIP_MAX, (long *)((1 << 24) - 1));
@@ -194,7 +193,7 @@
} else {
//rb->logf("ov_open: %d", error);
error = CODEC_ERROR;
- goto exit;
+ goto done;
}
if (rb->id3->offset) {
@@ -224,7 +223,7 @@
if (current_section != previous_section) {
if (!vorbis_set_codec_parameters(&vf)) {
error = CODEC_ERROR;
- goto exit;
+ goto done;
} else {
previous_section = current_section;
}
@@ -243,7 +242,9 @@
rb->set_elapsed(ov_time_tell(&vf));
}
}
+ error = CODEC_OK;
+done:
if (rb->request_next_track()) {
/* Clean things up for the next track */
vf.dataoffsets = NULL;
@@ -255,7 +256,6 @@
goto next_track;
}
- error = CODEC_OK;
exit:
return error;
}
diff --git a/apps/codecs/wav.c b/apps/codecs/wav.c
index c89d121..d9be0a3 100644
--- a/apps/codecs/wav.c
+++ b/apps/codecs/wav.c
@@ -242,7 +242,6 @@
ci->memset(iedata, 0, iend - iedata);
#endif
- ci->configure(CODEC_DSP_ENABLE, (bool *)true);
ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)28);
ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256));
@@ -261,11 +260,11 @@
buf = ci->request_buffer(&n, 1024);
if (n < 44) {
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
if ((memcmp(buf, "RIFF", 4) != 0) || (memcmp(&buf[8], "WAVE", 4) != 0)) {
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
buf += 12;
@@ -281,7 +280,7 @@
if (i < 16) {
DEBUGF("CODEC_ERROR: 'fmt ' chunk size=%lu < 16\n", i);
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
/* wFormatTag */
formattag=buf[8]|(buf[9]<<8);
@@ -309,7 +308,7 @@
DEBUGF("CODEC_ERROR: dvi_adpcm is missing "
"SamplesPerBlock value\n");
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
samplesperblock = buf[26]|(buf[27]<<8);
} else if (formattag == WAVE_FORMAT_EXTENSIBLE) {
@@ -317,7 +316,7 @@
DEBUGF("CODEC_ERROR: WAVE_FORMAT_EXTENSIBLE is "
"missing extension\n");
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
/* wValidBitsPerSample */
bitspersample = buf[26]|(buf[27]<<8);
@@ -344,7 +343,7 @@
if (n < (i + 8)) {
DEBUGF("CODEC_ERROR: WAVE header size > 1024\n");
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
n -= i + 8;
}
@@ -352,12 +351,12 @@
if (channels == 0) {
DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-channels file\n");
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
if (numbytes == 0) {
DEBUGF("CODEC_ERROR: 'data' chunk not found or has zero-length\n");
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
if (formattag != WAVE_FORMAT_PCM && totalsamples == 0) {
/* This is non-fatal for some formats */
@@ -368,7 +367,7 @@
if (bitspersample != 8) {
DEBUGF("CODEC_ERROR: alaw and mulaw must have 8 bitspersample\n");
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
bytespersample = channels;
}
@@ -376,13 +375,13 @@
&& bitspersample != 4 && bitspersample != 3) {
DEBUGF("CODEC_ERROR: dvi_adpcm must have 3 or 4 bitspersample\n");
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
if (formattag == WAVE_FORMAT_PCM && bitspersample > 32) {
DEBUGF("CODEC_ERROR: pcm with more than 32 bitspersample "
"is unsupported\n");
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
ci->configure(DSP_SET_FREQUENCY, (long *)(ci->id3->frequency));
@@ -393,7 +392,7 @@
} else {
DEBUGF("CODEC_ERROR: more than 2 channels\n");
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
if (totalsamples == 0) {
@@ -406,7 +405,7 @@
} else {
DEBUGF("CODEC_ERROR: cannot compute totalsamples\n");
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
}
@@ -505,14 +504,14 @@
samples + i*samplesperblock*channels,
&decodedsize) != CODEC_OK) {
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
}
bufsize = nblocks*samplesperblock*channels*4;
} else {
DEBUGF("CODEC_ERROR: unsupported format %x\n", formattag);
i = CODEC_ERROR;
- goto exit;
+ goto done;
}
while (!ci->pcmbuf_insert((char *)samples, bufsize))
@@ -524,11 +523,12 @@
endofstream = 1;
ci->set_elapsed(bytesdone*1000LL/avgbytespersec);
}
+ i = CODEC_OK;
+done:
if (ci->request_next_track())
goto next_track;
- i = CODEC_OK;
exit:
return i;
}
diff --git a/apps/codecs/wavpack.c b/apps/codecs/wavpack.c
index f864aa3..1871b46 100644
--- a/apps/codecs/wavpack.c
+++ b/apps/codecs/wavpack.c
@@ -75,7 +75,6 @@
while (!*ci->taginfo_ready && !ci->stop_codec)
ci->sleep(1);
- ci->configure(CODEC_DSP_ENABLE, (bool *)true);
ci->configure(DSP_SET_FREQUENCY, (long *)(ci->id3->frequency));
codec_set_replaygain(ci->id3);
@@ -84,7 +83,7 @@
if (!wpc) {
retval = CODEC_ERROR;
- goto exit;
+ goto done;
}
bps = WavpackGetBytesPerSample (wpc);
@@ -143,11 +142,12 @@
ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10);
ci->yield ();
}
+ retval = CODEC_OK;
+done:
if (ci->request_next_track())
goto next_track;
- retval = CODEC_OK;
exit:
return retval;
}
diff --git a/apps/dsp.h b/apps/dsp.h
index 501e238..9d0f7de 100644
--- a/apps/dsp.h
+++ b/apps/dsp.h
@@ -31,7 +31,6 @@
enum {
CODEC_SET_FILEBUF_WATERMARK = 1,
CODEC_SET_FILEBUF_CHUNKSIZE,
- CODEC_DSP_ENABLE,
DSP_SET_FREQUENCY,
DSP_SWITCH_FREQUENCY,
DSP_SET_CLIP_MIN,
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c
index 071e5d4..85a23e7 100644
--- a/apps/pcmbuf.c
+++ b/apps/pcmbuf.c
@@ -48,7 +48,8 @@
size_t audiobuffer_free IDATA_ATTR;
/* Amount audiobuffer_pos will be increased.*/
static size_t audiobuffer_fillpos IDATA_ATTR;
-static char *guardbuf IDATA_ATTR;
+static char *fadebuf IDATA_ATTR;
+static char *voicebuf IDATA_ATTR;
static void (*pcmbuf_event_handler)(void) IDATA_ATTR;
static void (*position_callback)(size_t size) IDATA_ATTR;
@@ -93,9 +94,9 @@
static struct pcmbufdesc *pcmbuf_write_end IDATA_ATTR;
static size_t last_chunksize IDATA_ATTR;
static size_t pcmbuf_unplayed_bytes IDATA_ATTR;
-static size_t pcmbuf_mix_used_bytes IDATA_ATTR;
static size_t pcmbuf_watermark IDATA_ATTR;
-static short *mixpos IDATA_ATTR;
+static struct pcmbufdesc *pcmbuf_mix_chunk IDATA_ATTR;
+static size_t pcmbuf_mix_sample IDATA_ATTR;
static bool low_latency_mode = false;
/* Helpful macros for use in conditionals this assumes some of the above
@@ -151,6 +152,10 @@
/* Put the finished buffer back into circulation */
pcmbuf_write_end->link = pcmbuf_current;
pcmbuf_write_end = pcmbuf_current;
+
+ /* If we've read through the mix chunk while it's still mixing there */
+ if (pcmbuf_current == pcmbuf_mix_chunk)
+ pcmbuf_mix_chunk = NULL;
}
process_new_buffer:
@@ -162,9 +167,10 @@
if(pcmbuf_new)
{
size_t current_size = pcmbuf_new->size;
+
pcmbuf_unplayed_bytes -= current_size;
- *realsize = current_size;
last_chunksize = current_size;
+ *realsize = current_size;
*realstart = pcmbuf_new->addr;
}
else
@@ -219,14 +225,10 @@
/* Update bytes counters */
pcmbuf_unplayed_bytes += size;
- if (pcmbuf_mix_used_bytes > size)
- pcmbuf_mix_used_bytes -= size;
- else
- pcmbuf_mix_used_bytes = 0;
audiobuffer_pos += size;
if (audiobuffer_pos >= pcmbuf_size)
- audiobuffer_pos = 0;
+ audiobuffer_pos -= pcmbuf_size;
audiobuffer_fillpos = 0;
}
@@ -299,7 +301,7 @@
pcm_mute(false);
pcmbuf_unplayed_bytes = 0;
- pcmbuf_mix_used_bytes = 0;
+ pcmbuf_mix_chunk = NULL;
if (pcmbuf_read) {
pcmbuf_write_end->link = pcmbuf_read;
pcmbuf_write_end = pcmbuf_read_end;
@@ -351,9 +353,10 @@
pcmbuf_size = bufsize;
pcmbuf_descsize = pcmbuf_descs()*sizeof(struct pcmbufdesc);
audiobuffer = (char *)&audiobuf[(audiobufend - audiobuf) -
- (pcmbuf_size + PCMBUF_FADE_CHUNK + pcmbuf_descsize)];
- guardbuf = &audiobuffer[pcmbuf_size];
- pcmbuf_write = (struct pcmbufdesc *)(&guardbuf[PCMBUF_FADE_CHUNK]);
+ (pcmbuf_size + PCMBUF_MIX_CHUNK * 2 + pcmbuf_descsize)];
+ fadebuf = &audiobuffer[pcmbuf_size];
+ voicebuf = &fadebuf[PCMBUF_MIX_CHUNK];
+ pcmbuf_write = (struct pcmbufdesc *)(&voicebuf[PCMBUF_MIX_CHUNK]);
pcmbuf_init_pcmbuffers();
position_callback = NULL;
pcmbuf_event_handler = NULL;
@@ -444,7 +447,7 @@
/* Fade out the specified amount of the already processed audio */
size_t total_fade_out = fade_out_rem;
short *buf = (short *)&audiobuffer[crossfade_pos + fade_out_delay * 2];
- short *buf_end = (short *)guardbuf;
+ short *buf_end = (short *)fadebuf;
/* Wrap the starting position if needed */
if (buf >= buf_end) buf -= pcmbuf_size / 2;
@@ -738,8 +741,8 @@
crossfade_start();
if (crossfade_active) {
- *realsize = MIN(length, PCMBUF_FADE_CHUNK);
- return &guardbuf[0];
+ *realsize = MIN(length, PCMBUF_MIX_CHUNK);
+ return fadebuf;
}
else
{
@@ -772,8 +775,16 @@
{
if (mix)
{
- *realsize = MIN(length, PCMBUF_FADE_CHUNK);
- return &guardbuf[0];
+ if (pcmbuf_mix_chunk || pcmbuf_read->link)
+ {
+ *realsize = MIN(length, PCMBUF_MIX_CHUNK);
+ return voicebuf;
+ }
+ else
+ {
+ *realsize = 0;
+ return NULL;
+ }
}
else
return pcmbuf_request_buffer(length, realsize);
@@ -787,7 +798,7 @@
void pcmbuf_write_complete(size_t length)
{
if (crossfade_active)
- flush_crossfade(guardbuf, length);
+ flush_crossfade(fadebuf, length);
else
{
audiobuffer_free -= length;
@@ -814,16 +825,16 @@
}
/* Get a pointer to where to mix immediate audio */
-static inline short* get_mix_insert_pos(void) {
- /* Give at least 1/8s clearance here */
- size_t pcmbuf_mix_back_pos =
- pcmbuf_unplayed_bytes - NATIVE_FREQUENCY * 4 / 8;
+static inline short* get_mix_insert_buf(void) {
+ if (pcmbuf_read->link)
+ {
+ /* Get the next chunk */
+ char *pcmbuf_mix_buf = pcmbuf_read->link->addr;
- if (audiobuffer_pos < pcmbuf_mix_back_pos)
- return (short *)&audiobuffer[pcmbuf_size +
- audiobuffer_pos - pcmbuf_mix_back_pos];
- else
- return (short *)&audiobuffer[audiobuffer_pos - pcmbuf_mix_back_pos];
+ /* Give at least 1/8s clearance. TODO: Check size here? */
+ return (short *)&pcmbuf_mix_buf[NATIVE_FREQUENCY * 4 / 8];
+ }
+ return NULL;
}
/* Generates a constant square wave sound with a given frequency
@@ -834,12 +845,12 @@
unsigned int interval = NATIVE_FREQUENCY / frequency;
long sample;
short *buf;
- short *pcmbuf_end = (short *)guardbuf;
+ short *pcmbuf_end = (short *)fadebuf;
size_t samples = NATIVE_FREQUENCY / 1000 * duration;
if (pcm_is_playing())
{
- buf = get_mix_insert_pos();
+ buf = get_mix_insert_buf();
while (i++ < samples)
{
sample = *buf;
@@ -888,35 +899,56 @@
return pcmbuf_unplayed_bytes * 100 / pcmbuf_size;
}
-int pcmbuf_mix_usage(void)
+int pcmbuf_mix_free(void)
{
- return pcmbuf_mix_used_bytes * 100 / pcmbuf_unplayed_bytes;
+ if (pcmbuf_mix_chunk)
+ {
+ size_t my_mix_end =
+ (size_t)&((short *)pcmbuf_mix_chunk->addr)[pcmbuf_mix_sample];
+ size_t my_write_pos = (size_t)&audiobuffer[audiobuffer_pos];
+ if (my_write_pos < my_mix_end)
+ my_write_pos += pcmbuf_size;
+ return (my_write_pos - my_mix_end) * 100 / pcmbuf_unplayed_bytes;
+ }
+ return 100;
}
-void pcmbuf_reset_mixpos(void)
+/* This function does not check for writing over the current main insertion
+ * point of the pcm buffer (audiobuffer_fillpos) so that must be checked by
+ * the caller */
+void pcmbuf_mix_voice(size_t length)
{
- mixpos = get_mix_insert_pos();
- pcmbuf_mix_used_bytes = 0;
-}
+ short *ibuf = (short *)voicebuf;
+ short *obuf;
+ size_t chunk_samples;
-void pcmbuf_mix(char *buf, size_t length)
-{
- short *ibuf = (short *)buf;
- short *pcmbuf_end = (short *)guardbuf;
+ if (!pcmbuf_mix_chunk && pcmbuf_read)
+ {
+ pcmbuf_mix_chunk = pcmbuf_read->link;
+ /* Start 1/8s into the next chunk */
+ pcmbuf_mix_sample = NATIVE_FREQUENCY * 4 / 16;
+ }
+ if (!pcmbuf_mix_chunk)
+ return;
- if (pcmbuf_mix_used_bytes == 0)
- pcmbuf_reset_mixpos();
+ obuf = (short *)pcmbuf_mix_chunk->addr;
+ chunk_samples = pcmbuf_mix_chunk->size / 2;
- pcmbuf_mix_used_bytes += length;
length /= 2;
while (length-- > 0) {
long sample = *ibuf++;
- sample += *mixpos >> 2;
- *mixpos++ = MIN(MAX(sample, -32768), 32767);
-
- if (mixpos >= pcmbuf_end)
- mixpos = (short *)audiobuffer;
+ if (pcmbuf_mix_sample >= chunk_samples)
+ {
+ pcmbuf_mix_chunk = pcmbuf_mix_chunk->link;
+ if (!pcmbuf_mix_chunk)
+ return;
+ pcmbuf_mix_sample = 0;
+ obuf = pcmbuf_mix_chunk->addr;
+ chunk_samples = pcmbuf_mix_chunk->size / 2;
+ }
+ sample += obuf[pcmbuf_mix_sample];
+ obuf[pcmbuf_mix_sample++] = MIN(MAX(sample, -32768), 32767);
}
}
diff --git a/apps/pcmbuf.h b/apps/pcmbuf.h
index b659e8f..819d501 100644
--- a/apps/pcmbuf.h
+++ b/apps/pcmbuf.h
@@ -27,7 +27,7 @@
non-fatal) */
#define PCMBUF_MIN_CHUNK 4096 /* We try to never feed a chunk smaller than
this to the DMA */
-#define PCMBUF_FADE_CHUNK 8192 /* This is the maximum size of one packet
+#define PCMBUF_MIX_CHUNK 8192 /* This is the maximum size of one packet
for mixing (crossfade or voice) */
/* Returns true if the buffer needs to change size */
@@ -64,10 +64,9 @@
void pcmbuf_crossfade_enable(bool on_off);
int pcmbuf_usage(void);
-int pcmbuf_mix_usage(void);
+int pcmbuf_mix_free(void);
void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude);
-void pcmbuf_reset_mixpos(void);
-void pcmbuf_mix(char *buf, size_t length);
+void pcmbuf_mix_voice(size_t length);
int pcmbuf_used_descs(void);
int pcmbuf_descs(void);
diff --git a/apps/playback.c b/apps/playback.c
index c34f83a..35f5d7f 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -126,6 +126,9 @@
Q_CODEC_REQUEST_COMPLETE,
Q_CODEC_REQUEST_FAILED,
+ Q_VOICE_PLAY,
+ Q_VOICE_STOP,
+
Q_CODEC_LOAD,
Q_CODEC_LOAD_DISK,
};
@@ -160,6 +163,12 @@
static long voice_codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
IBSS_ATTR;
static const char voice_codec_thread_name[] = "voice codec";
+struct voice_info {
+ void (*callback)(unsigned char **start, int *size);
+ int size;
+ char *buf;
+};
+
static struct mutex mutex_codecthread;
static struct event_queue codec_callback_queue;
@@ -170,12 +179,12 @@
static size_t voice_remaining;
static bool voice_is_playing;
static void (*voice_getmore)(unsigned char** start, int* size);
+static int voice_thread_num = -1;
/* Is file buffer currently being refilled? */
-static volatile bool filling;
-static volatile bool filling_short;
+static volatile bool filling IDATA_ATTR;
-volatile int current_codec;
+volatile int current_codec IDATA_ATTR;
extern unsigned char codecbuf[];
/* Ring buffer where tracks and codecs are loaded. */
@@ -188,8 +197,8 @@
size_t filebufused;
/* Ring buffer read and write indexes. */
-static volatile size_t buf_ridx;
-static volatile size_t buf_widx;
+static volatile size_t buf_ridx IDATA_ATTR;
+static volatile size_t buf_widx IDATA_ATTR;
#ifndef SIMULATOR
static unsigned char *iram_buf[2];
@@ -244,18 +253,18 @@
static bool v1first = false;
static void mp3_set_elapsed(struct mp3entry* id3);
-int mp3_get_file_pos(void);
+static int mp3_get_file_pos(void);
-static void audio_clear_track_entries(bool clear_unbuffered);
-static void initialize_buffer_fill(bool clear_tracks, bool short_fill);
-static void audio_fill_file_buffer(
- bool start_play, bool short_fill, size_t offset);
+static void audio_clear_track_entries(
+ bool clear_buffered, bool clear_unbuffered);
+static void initialize_buffer_fill(bool clear_tracks);
+static void audio_fill_file_buffer(bool start_play, size_t offset);
static void swap_codec(void)
{
int my_codec = current_codec;
- logf("swapping out codec:%d", current_codec);
+ logf("swapping out codec:%d", my_codec);
/* Save our current IRAM and DRAM */
#ifndef SIMULATOR
@@ -281,7 +290,7 @@
invalidate_icache();
memcpy(codecbuf, dram_buf[my_codec], CODEC_SIZE);
- logf("codec resuming:%d", current_codec);
+ logf("resuming codec:%d", my_codec);
}
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
@@ -289,9 +298,6 @@
{
static bool voice_cpu_boosted = false;
- if (!voice_codec_loaded)
- state = false;
-
if (state != voice_cpu_boosted)
{
cpu_boost(state);
@@ -302,8 +308,8 @@
#define voice_boost_cpu(state) do { } while(0)
#endif
-bool codec_pcmbuf_insert_split_callback(const void *ch1, const void *ch2,
- size_t length)
+static bool voice_pcmbuf_insert_split_callback(
+ const void *ch1, const void *ch2, size_t length)
{
const char* src[2];
char *dest;
@@ -316,25 +322,75 @@
if (dsp_stereo_mode() == STEREO_NONINTERLEAVED)
length *= 2; /* Length is per channel */
- while (length > 0) {
+ do {
long est_output_size = dsp_output_size(length);
- if (current_codec == CODEC_IDX_VOICE) {
- while ((dest = pcmbuf_request_voice_buffer(est_output_size,
- &output_size, audio_codec_loaded)) == NULL)
- sleep(1);
+ while ((dest = pcmbuf_request_voice_buffer(est_output_size,
+ &output_size, playing)) == NULL)
+ if (playing)
+ 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);
+
+ if (input_size <= 0) {
+ DEBUGF("Error: dsp_input_size(%ld=dsp_output_size(%ld))=%ld<=0\n",
+ output_size, length, input_size);
+ /* 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;
+
+ output_size = dsp_process(dest, src, input_size);
+
+ if (playing)
+ {
+ pcmbuf_mix_voice(output_size);
+ if (pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30)
+ swap_codec();
}
else
- {
- /* Prevent audio from a previous position from hitting the buffer */
- if (ci.new_track || ci.stop_codec)
- return true;
+ pcmbuf_write_complete(output_size);
- while ((dest = pcmbuf_request_buffer(est_output_size,
- &output_size)) == NULL) {
- sleep(1);
- if (ci.seek_time || ci.new_track || ci.stop_codec)
- return true;
- }
+ length -= input_size;
+
+ } while (length > 0);
+
+
+ return true;
+}
+
+static bool codec_pcmbuf_insert_split_callback(
+ const void *ch1, const void *ch2, size_t length)
+{
+ const char* src[2];
+ char *dest;
+ long input_size;
+ size_t output_size;
+
+ src[0] = ch1;
+ src[1] = ch2;
+
+ if (dsp_stereo_mode() == STEREO_NONINTERLEAVED)
+ length *= 2; /* Length is per channel */
+
+ do {
+ long est_output_size = dsp_output_size(length);
+ /* 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) {
+ sleep(1);
+ if (ci.seek_time || ci.new_track || ci.stop_codec)
+ return true;
}
/* Get the real input_size for output_size bytes, guarding
@@ -344,73 +400,66 @@
if (input_size <= 0) {
DEBUGF("Error: dsp_input_size(%ld=dsp_output_size(%ld))=%ld<=0\n",
output_size, length, input_size);
- /* If this happens, then some samples have been lost */
- break;
+ /* If this happens, there are samples of codec data that don't
+ * become a number of pcm samples, and something is broken */
+ return false;
}
- if ((size_t)input_size > length) {
- DEBUGF("Error: dsp_input_size(%ld=dsp_output_size(%ld))=%ld>%ld\n",
- output_size, length, input_size, length);
+ /* Input size has grown, no error, just don't write more than length */
+ if ((size_t)input_size > length)
input_size = length;
- }
output_size = dsp_process(dest, src, input_size);
- /* Hotswap between audio and voice codecs as necessary. */
- switch (current_codec)
- {
- case CODEC_IDX_AUDIO:
- pcmbuf_write_complete(output_size);
- if (voice_is_playing && pcmbuf_usage() > 30
- && pcmbuf_mix_usage() < 20)
- {
- voice_boost_cpu(true);
- swap_codec();
- voice_boost_cpu(false);
- }
- break ;
+ pcmbuf_write_complete(output_size);
- case CODEC_IDX_VOICE:
- if (audio_codec_loaded) {
- pcmbuf_mix(dest, output_size);
- if ((pcmbuf_usage() < 10)
- || pcmbuf_mix_usage() > 70)
- swap_codec();
- } else
- pcmbuf_write_complete(output_size);
- break ;
- }
+ if (voice_is_playing && pcm_is_playing() &&
+ pcmbuf_usage() > 30 && pcmbuf_mix_free() > 80)
+ swap_codec();
length -= input_size;
- }
+
+ } while (length > 0);
return true;
}
-bool codec_pcmbuf_insert_callback(const char *buf, size_t length)
+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);
+}
+
+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);
}
-void* get_codec_memory_callback(size_t *size)
+static void* get_voice_memory_callback(size_t *size)
{
- if (current_codec == CODEC_IDX_VOICE)
- {
- *size = 0;
- return NULL;
- }
+ *size = 0;
+ return NULL;
+}
+static void* get_codec_memory_callback(size_t *size)
+{
*size = MALLOC_BUFSIZE;
if (voice_codec_loaded)
return &audiobuf[talk_get_bufsize()];
@@ -430,14 +479,15 @@
}
}
-void codec_set_elapsed_callback(unsigned int value)
+static void voice_set_elapsed_callback(unsigned int value)
+{
+ (void)value;
+}
+
+static void codec_set_elapsed_callback(unsigned int value)
{
unsigned int latency;
- /* We don't save or display offsets for voice */
- if (current_codec == CODEC_IDX_VOICE)
- return ;
-
#ifdef AB_REPEAT_ENABLE
ab_position_report(value);
#endif
@@ -450,16 +500,14 @@
cur_ti->id3.elapsed = value - latency;
}
-void codec_set_offset_callback(size_t value)
+static void voice_set_offset_callback(size_t value)
{
- unsigned int latency;
+ (void)value;
+}
- /* We don't save or display offsets for voice */
- if (current_codec == CODEC_IDX_VOICE)
- return ;
-
- latency = pcmbuf_get_latency() * cur_ti->id3.bitrate / 8;
-
+static void codec_set_offset_callback(size_t value)
+{
+ unsigned int latency = pcmbuf_get_latency() * cur_ti->id3.bitrate / 8;
if (value < latency)
cur_ti->id3.offset = 0;
else
@@ -512,14 +560,22 @@
queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
}
+static size_t voice_filebuf_callback(void *ptr, size_t size)
+{
+ (void)ptr;
+ (void)size;
+
+ return 0;
+}
+
/* copy up-to size bytes into ptr and return the actual size copied */
-size_t codec_filebuf_callback(void *ptr, size_t size)
+static size_t codec_filebuf_callback(void *ptr, size_t size)
{
char *buf = (char *)ptr;
size_t copy_n;
size_t part_n;
- if (ci.stop_codec || !playing || current_codec == CODEC_IDX_VOICE)
+ if (ci.stop_codec || !playing)
return 0;
/* The ammount to copy is the lesser of the requested amount and the
@@ -554,39 +610,91 @@
return copy_n;
}
-void* voice_request_data(size_t *realsize, size_t reqsize)
+static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize)
{
- while (queue_empty(&voice_codec_queue) && (voice_remaining == 0
- || voicebuf == NULL) && !ci_voice.stop_codec)
+ struct event ev;
+
+ if (ci_voice.new_track)
{
- yield();
- if (audio_codec_loaded && (pcmbuf_usage() < 30
- || !voice_is_playing || voicebuf == NULL))
- swap_codec();
- else if (!voice_is_playing)
+ *realsize = 0;
+ return NULL;
+ }
+
+ while (1)
+ {
+ if (voice_is_playing)
+ queue_wait_w_tmo(&voice_codec_queue, &ev, 0);
+ else if (playing)
{
- voice_boost_cpu(false);
- if (!pcm_is_playing())
- pcmbuf_boost(false);
- sleep(HZ/16);
+ queue_wait_w_tmo(&voice_codec_queue, &ev, 0);
+ if (ev.id == SYS_TIMEOUT)
+ ev.id = Q_AUDIO_PLAY;
}
+ else
+ queue_wait(&voice_codec_queue, &ev);
- if (voice_remaining)
- voice_is_playing = true;
- else if (voice_getmore != NULL)
- {
- voice_getmore((unsigned char **)&voicebuf, (int *)&voice_remaining);
+ switch (ev.id) {
+ case Q_AUDIO_PLAY:
+ swap_codec();
+ break;
- if (!voice_remaining)
- {
- voice_is_playing = false;
- /* Force pcm playback. */
- pcmbuf_play_start();
- }
+ case Q_VOICE_STOP:
+ if (voice_is_playing)
+ {
+ /* Clear the current buffer */
+ voice_is_playing = false;
+ voice_getmore = NULL;
+ voice_remaining = 0;
+ voicebuf = NULL;
+ voice_boost_cpu(false);
+ ci_voice.new_track = 1;
+ /* Force the codec to think it's changing tracks */
+ *realsize = 0;
+ return NULL;
+ }
+ else
+ break;
+
+ case SYS_USB_CONNECTED:
+ logf("USB: Audio core");
+ usb_acknowledge(SYS_USB_CONNECTED_ACK);
+ if (audio_codec_loaded)
+ swap_codec();
+ usb_wait_for_disconnect(&voice_codec_queue);
+ break;
+
+ case Q_VOICE_PLAY:
+ {
+ struct voice_info *voice_data;
+ voice_is_playing = true;
+ voice_boost_cpu(true);
+ voice_data = ev.data;
+ voice_remaining = voice_data->size;
+ voicebuf = voice_data->buf;
+ voice_getmore = voice_data->callback;
+ }
+ case SYS_TIMEOUT:
+ goto voice_play_clip;
}
}
- voice_is_playing = true;
+voice_play_clip:
+
+ if (voice_remaining == 0 || voicebuf == NULL)
+ {
+ if (voice_getmore)
+ voice_getmore((unsigned char **)&voicebuf, (int *)&voice_remaining);
+
+ /* If this clip is done */
+ if (!voice_remaining)
+ {
+ queue_post(&voice_codec_queue, Q_VOICE_STOP, 0);
+ /* Force pcm playback. */
+ if (!pcm_is_playing())
+ pcmbuf_play_start();
+ }
+ }
+
*realsize = MIN(voice_remaining, reqsize);
if (*realsize == 0)
@@ -595,14 +703,10 @@
return voicebuf;
}
-void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
+static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
{
size_t short_n, copy_n, buf_rem;
- /* Voice codec. */
- if (current_codec == CODEC_IDX_VOICE)
- return voice_request_data(realsize, reqsize);
-
if (!playing) {
*realsize = 0;
return NULL;
@@ -654,7 +758,7 @@
}
/* Count the data BETWEEN the selected tracks */
-size_t buffer_count_tracks(int from_track, int to_track) {
+static size_t buffer_count_tracks(int from_track, int to_track) {
size_t amount = 0;
bool need_wrap = to_track < from_track;
@@ -772,6 +876,7 @@
/* Reset buffer and track pointers */
buf_ridx = buf_widx = 0;
track_widx = track_ridx;
+ audio_clear_track_entries(false, true);
filebufused = 0;
/* Cause the buffer fill to return as soon as the codec is loaded */
@@ -780,7 +885,7 @@
last_peek_offset = -1;
cur_ti->filesize = 0;
cur_ti->start_pos = 0;
- audio_fill_file_buffer(false, true, 0);
+ audio_fill_file_buffer(false, 0);
}
static void audio_check_new_track(void)
@@ -935,7 +1040,7 @@
track_widx = track_ridx;
last_peek_offset = 0;
- initialize_buffer_fill(true, true);
+ initialize_buffer_fill(true);
if (newpos > AUDIO_REBUFFER_GUESS_SIZE)
cur_ti->start_pos = newpos - AUDIO_REBUFFER_GUESS_SIZE;
@@ -950,16 +1055,15 @@
queue_post(&codec_callback_queue, Q_CODEC_REQUEST_COMPLETE, 0);
}
-void codec_advance_buffer_callback(size_t amount)
+static void voice_advance_buffer_callback(size_t amount)
{
- if (current_codec == CODEC_IDX_VOICE) {
- amount = MIN(amount, voice_remaining);
- voicebuf += amount;
- voice_remaining -= amount;
+ amount = MIN(amount, voice_remaining);
+ voicebuf += amount;
+ voice_remaining -= amount;
+}
- return ;
- }
-
+static void codec_advance_buffer_callback(size_t amount)
+{
if (amount > cur_ti->available + cur_ti->filerem)
amount = cur_ti->available + cur_ti->filerem;
@@ -989,19 +1093,25 @@
codec_set_offset_callback(ci.curpos);
}
-void codec_advance_buffer_loc_callback(void *ptr)
+static void voice_advance_buffer_loc_callback(void *ptr)
{
- size_t amount;
+ size_t amount = (size_t)ptr - (size_t)voicebuf;
+ voice_advance_buffer_callback(amount);
+}
- if (current_codec == CODEC_IDX_VOICE)
- amount = (size_t)ptr - (size_t)voicebuf;
- else
- amount = (size_t)ptr - (size_t)&filebuf[buf_ridx];
-
+static void codec_advance_buffer_loc_callback(void *ptr)
+{
+ size_t amount = (size_t)ptr - (size_t)&filebuf[buf_ridx];
codec_advance_buffer_callback(amount);
}
-off_t codec_mp3_get_filepos_callback(int newtime)
+static off_t voice_mp3_get_filepos_callback(int newtime)
+{
+ (void)newtime;
+ return 0;
+}
+
+static off_t codec_mp3_get_filepos_callback(int newtime)
{
off_t newpos;
@@ -1011,7 +1121,12 @@
return newpos;
}
-void codec_seek_complete_callback(void)
+static void voice_do_nothing(void)
+{
+ return;
+}
+
+static void codec_seek_complete_callback(void)
{
logf("seek_complete");
if (pcm_is_paused()) {
@@ -1024,13 +1139,16 @@
ci.seek_time = 0;
}
-bool codec_seek_buffer_callback(size_t newpos)
+static bool voice_seek_buffer_callback(size_t newpos)
+{
+ (void)newpos;
+ return false;
+}
+
+static bool codec_seek_buffer_callback(size_t newpos)
{
int difference;
- if (current_codec == CODEC_IDX_VOICE)
- return false;
-
if (newpos >= cur_ti->filesize)
newpos = cur_ti->filesize - 1;
@@ -1083,7 +1201,7 @@
size_t bytes;
if (current_codec == CODEC_IDX_VOICE)
- return ;
+ return;
if (!filebuf)
return; /* Audio buffers not yet set up */
@@ -1105,13 +1223,6 @@
conf_filechunk = (unsigned long)value;
break;
- case CODEC_DSP_ENABLE:
- if ((bool)value)
- ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
- else
- ci.pcmbuf_insert = pcmbuf_insert_buffer;
- break ;
-
default:
if (!dsp_configure(setting, value)) { logf("Illegal key:%d", setting); }
}
@@ -1165,7 +1276,7 @@
}
/* FIXME: This code should be made more generic and move to metadata.c */
-void strip_id3v1_tag(void)
+static void strip_id3v1_tag(void)
{
int i;
static const unsigned char tag[] = "TAG";
@@ -1259,10 +1370,6 @@
track_widx = 0;
tracks[track_widx].filesize = 0;
- /* If we're short filling, and have at least twice the watermark
- * of data, stop filling after this track */
- if (filling_short && filebufused > conf_watermark * 2)
- fill_bytesleft = 0;
} else {
logf("Partially buf:%dB",
tracks[track_widx].filesize - tracks[track_widx].filerem);
@@ -1526,7 +1633,6 @@
conf_watermark = AUDIO_DEFAULT_WATERMARK;
conf_filechunk = AUDIO_DEFAULT_FILECHUNK;
dsp_configure(DSP_RESET, 0);
- ci.configure(CODEC_DSP_ENABLE, false);
current_codec = last_codec;
}
@@ -1628,7 +1734,8 @@
return true;
}
-static void audio_clear_track_entries(bool clear_unbuffered)
+static void audio_clear_track_entries(
+ bool clear_buffered, bool clear_unbuffered)
{
int cur_idx = track_widx;
int last_idx = -1;
@@ -1644,16 +1751,18 @@
/* If the track is buffered, conditionally clear/notify,
* otherwise clear the track if that option is selected */
if (tracks[cur_idx].event_sent) {
- if (last_idx >= 0)
- {
- /* If there is an unbuffer callback, call it, otherwise, just
- * clear the track */
- if (track_unbuffer_callback)
- track_unbuffer_callback(&tracks[last_idx].id3, false);
+ if (clear_buffered) {
+ if (last_idx >= 0)
+ {
+ /* If there is an unbuffer callback, call it, otherwise,
+ * just clear the track */
+ if (track_unbuffer_callback)
+ track_unbuffer_callback(&tracks[last_idx].id3, false);
- memset(&tracks[last_idx], 0, sizeof(struct track_info));
+ memset(&tracks[last_idx], 0, sizeof(struct track_info));
+ }
+ last_idx = cur_idx;
}
- last_idx = cur_idx;
} else if (clear_unbuffered)
memset(&tracks[cur_idx], 0, sizeof(struct track_info));
}
@@ -1686,6 +1795,7 @@
/* Save the current playing spot, or NULL if the playlist has ended */
playlist_update_resume_info(playlist_end?NULL:audio_current_track());
}
+ filebufused = 0;
playing = false;
filling = false;
paused = false;
@@ -1733,7 +1843,7 @@
last_peek_offset = -1;
- audio_fill_file_buffer(true, true, offset);
+ audio_fill_file_buffer(true, offset);
}
/* Send callback events to notify about new tracks. */
@@ -1772,20 +1882,11 @@
}
}
-static void initialize_buffer_fill(bool clear_tracks, bool short_fill)
+static void initialize_buffer_fill(bool clear_tracks)
{
- if (short_fill) {
- filling_short = true;
- fill_bytesleft = filebuflen >> 2;
- cur_ti->start_pos = ci.curpos;
- }
- /* Recalculate remaining bytes to buffer */
- else if (!filling_short)
- {
- fill_bytesleft = filebuflen - filebufused;
- if (buf_ridx > cur_ti->buf_idx)
- cur_ti->start_pos = buf_ridx - cur_ti->buf_idx;
- }
+ fill_bytesleft = filebuflen - filebufused;
+ if (buf_ridx > cur_ti->buf_idx)
+ cur_ti->start_pos = buf_ridx - cur_ti->buf_idx;
/* Don't initialize if we're already initialized */
if (filling)
@@ -1794,7 +1895,7 @@
logf("Starting buffer fill");
if (clear_tracks)
- audio_clear_track_entries(short_fill);
+ audio_clear_track_entries(true, false);
/* Save the current resume position once. */
playlist_update_resume_info(audio_current_track());
@@ -1802,10 +1903,9 @@
filling = true;
}
-static void audio_fill_file_buffer(
- bool start_play, bool short_fill, size_t offset)
+static void audio_fill_file_buffer(bool start_play, size_t offset)
{
- initialize_buffer_fill(!start_play, short_fill);
+ initialize_buffer_fill(!start_play);
/* If we have a partially buffered track, continue loading,
* otherwise load a new track */
@@ -1821,7 +1921,6 @@
generate_postbuffer_events();
filling = false;
- filling_short = false;
#ifndef SIMULATOR
if (playing)
@@ -1899,17 +1998,16 @@
}
}
+static bool voice_request_next_track_callback(void)
+{
+ ci_voice.new_track = 0;
+ return true;
+}
+
static bool codec_request_next_track_callback(void)
{
int prev_codectype;
- if (current_codec == CODEC_IDX_VOICE) {
- voice_remaining = 0;
- /* Terminate the codec if there are messages waiting on the queue or
- the core has been requested the codec to be terminated. */
- return !ci_voice.stop_codec && queue_empty(&voice_codec_queue);
- }
-
if (ci.stop_codec || !playing)
return false;
@@ -1941,7 +2039,7 @@
track_widx = track_ridx;
- audio_clear_track_entries(true);
+ audio_clear_track_entries(true, true);
/* If the current track is fully buffered, advance the write pointer */
if (tracks[track_widx].filerem == 0)
@@ -1993,7 +2091,7 @@
if (!filling)
if (!playing || playlist_end || ci.stop_codec)
break;
- audio_fill_file_buffer(false, false, 0);
+ audio_fill_file_buffer(false, 0);
break;
case Q_AUDIO_PLAY:
@@ -2075,7 +2173,7 @@
}
}
-void codec_thread(void)
+static void codec_thread(void)
{
struct event ev;
int status;
@@ -2088,16 +2186,18 @@
switch (ev.id) {
case Q_CODEC_LOAD_DISK:
logf("Codec load disk");
- ci.stop_codec = false;
audio_codec_loaded = true;
+ if (voice_codec_loaded)
+ queue_post(&voice_codec_queue, Q_AUDIO_PLAY, 0);
mutex_lock(&mutex_codecthread);
current_codec = CODEC_IDX_AUDIO;
+ ci.stop_codec = false;
status = codec_load_file((const char *)ev.data, &ci);
mutex_unlock(&mutex_codecthread);
break ;
case Q_CODEC_LOAD:
- logf("Codec start");
+ logf("Codec load ram");
if (!cur_ti->has_codec) {
logf("Codec slot is empty!");
/* Wait for the pcm buffer to go empty */
@@ -2109,11 +2209,13 @@
break ;
}
- ci.stop_codec = false;
- wrap = (size_t)&filebuf[filebuflen] - (size_t)cur_ti->codecbuf;
audio_codec_loaded = true;
+ if (voice_codec_loaded)
+ queue_post(&voice_codec_queue, Q_AUDIO_PLAY, 0);
mutex_lock(&mutex_codecthread);
current_codec = CODEC_IDX_AUDIO;
+ ci.stop_codec = false;
+ wrap = (size_t)&filebuf[filebuflen] - (size_t)cur_ti->codecbuf;
status = codec_load_ram(cur_ti->codecbuf, cur_ti->codecsize,
&filebuf[0], wrap, &ci);
mutex_unlock(&mutex_codecthread);
@@ -2121,28 +2223,26 @@
#ifndef SIMULATOR
case SYS_USB_CONNECTED:
- while (voice_codec_loaded) {
- if (current_codec != CODEC_IDX_VOICE)
- swap_codec();
- sleep(1);
- }
queue_clear(&codec_queue);
logf("USB: Audio codec");
usb_acknowledge(SYS_USB_CONNECTED_ACK);
+ if (voice_codec_loaded)
+ swap_codec();
usb_wait_for_disconnect(&codec_queue);
break ;
#endif
}
if (audio_codec_loaded)
+ {
if (ci.stop_codec)
{
status = CODEC_OK;
if (!playing)
pcmbuf_play_stop();
}
-
- audio_codec_loaded = false;
+ audio_codec_loaded = false;
+ }
switch (ev.id) {
case Q_CODEC_LOAD_DISK:
@@ -2163,6 +2263,10 @@
logf("Codec finished");
if (ci.stop_codec)
{
+ /* Wait for the audio to stop playing before
+ * triggering the WPS exit */
+ while(pcm_is_playing())
+ sleep(1);
queue_post(&audio_queue, Q_AUDIO_STOP, 0);
break;
}
@@ -2186,12 +2290,20 @@
filebuf = (char *)&audiobuf[MALLOC_BUFSIZE];
filebuflen = audiobufend - audiobuf - MALLOC_BUFSIZE - GUARD_BUFSIZE -
- (pcmbuf_get_bufsize() + get_pcmbuf_descsize() + PCMBUF_FADE_CHUNK);
+ (pcmbuf_get_bufsize() + get_pcmbuf_descsize() + PCMBUF_MIX_CHUNK * 2);
- if (talk_get_bufsize() && voice_codec_loaded)
+ if (talk_get_bufsize())
{
filebuf = &filebuf[talk_get_bufsize()];
filebuflen -= 2*CODEC_IRAM_SIZE + 2*CODEC_SIZE + talk_get_bufsize();
+
+#ifndef SIMULATOR
+ iram_buf[0] = &filebuf[filebuflen];
+ iram_buf[1] = &filebuf[filebuflen+CODEC_IRAM_SIZE];
+#endif
+ dram_buf[0] = (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE*2];
+ dram_buf[1] =
+ (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE*2+CODEC_SIZE];
}
/* Ensure that everything is aligned */
@@ -2199,60 +2311,25 @@
filebuf += offset;
filebuflen -= offset;
filebuflen &= ~3;
-
-#ifndef SIMULATOR
- iram_buf[0] = &filebuf[filebuflen];
- iram_buf[1] = &filebuf[filebuflen+CODEC_IRAM_SIZE];
-#endif
- dram_buf[0] = (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE*2];
- dram_buf[1] =
- (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE*2+CODEC_SIZE];
-
}
-void voice_codec_thread(void)
+static void voice_codec_thread(void)
{
- struct event ev;
- int status;
+ while (1)
+ {
+ logf("Loading voice codec");
+ voice_codec_loaded = true;
+ mutex_lock(&mutex_codecthread);
+ current_codec = CODEC_IDX_VOICE;
+ dsp_configure(DSP_RESET, 0);
+ voice_remaining = 0;
+ voice_getmore = NULL;
- current_codec = CODEC_IDX_AUDIO;
- voice_codec_loaded = false;
- while (1) {
- status = 0;
- voice_is_playing = false;
- queue_wait(&voice_codec_queue, &ev);
- switch (ev.id) {
- case Q_CODEC_LOAD_DISK:
- logf("Loading voice codec");
- audio_stop_playback();
- mutex_lock(&mutex_codecthread);
- current_codec = CODEC_IDX_VOICE;
- dsp_configure(DSP_RESET, 0);
- ci.configure(CODEC_DSP_ENABLE, (bool *)true);
- voice_remaining = 0;
- voice_getmore = NULL;
- voice_codec_loaded = true;
- reset_buffer();
- ci_voice.stop_codec = false;
+ codec_load_file(CODEC_MPA_L3, &ci_voice);
- status = codec_load_file((char *)ev.data, &ci_voice);
-
- logf("Voice codec finished");
- audio_stop_playback();
- mutex_unlock(&mutex_codecthread);
- current_codec = CODEC_IDX_AUDIO;
- voice_codec_loaded = false;
- reset_buffer();
- break ;
-
-#ifndef SIMULATOR
- case SYS_USB_CONNECTED:
- logf("USB: Voice codec");
- usb_acknowledge(SYS_USB_CONNECTED_ACK);
- usb_wait_for_disconnect(&voice_codec_queue);
- break ;
-#endif
- }
+ logf("Voice codec finished");
+ mutex_unlock(&mutex_codecthread);
+ voice_codec_loaded = false;
}
}
@@ -2261,20 +2338,24 @@
if (!filebuf)
return; /* Audio buffers not yet set up */
- while (voice_codec_loaded)
+ if (voice_thread_num >= 0)
{
logf("Terminating voice codec");
- ci_voice.stop_codec = true;
- sleep(1);
+ remove_thread(voice_thread_num);
+ queue_delete(&voice_codec_queue);
+ voice_thread_num = -1;
+ voice_codec_loaded = false;
}
if (!talk_get_bufsize())
return ;
logf("Starting voice codec");
- queue_post(&voice_codec_queue, Q_CODEC_LOAD_DISK, (void *)CODEC_MPA_L3);
+ queue_init(&voice_codec_queue);
+ voice_thread_num = create_thread(voice_codec_thread, voice_codec_stack,
+ sizeof(voice_codec_stack), voice_codec_thread_name);
while (!voice_codec_loaded)
- sleep(1);
+ yield();
}
struct mp3entry* audio_current_track(void)
@@ -2495,7 +2576,7 @@
}
/* Copied from mpeg.c. Should be moved somewhere else. */
-int mp3_get_file_pos(void)
+static int mp3_get_file_pos(void)
{
int pos = -1;
struct mp3entry *id3 = audio_current_track();
@@ -2553,11 +2634,19 @@
void mp3_play_data(const unsigned char* start, int size,
void (*get_more)(unsigned char** start, int* size))
{
- voice_getmore = get_more;
- voicebuf = (char *)start;
- voice_remaining = size;
+ static struct voice_info voice_clip;
+ voice_clip.callback = get_more;
+ voice_clip.buf = (char *)start;
+ voice_clip.size = size;
+ queue_post(&voice_codec_queue, Q_VOICE_STOP, 0);
+ queue_post(&voice_codec_queue, Q_VOICE_PLAY, &voice_clip);
voice_is_playing = true;
- pcmbuf_reset_mixpos();
+ voice_boost_cpu(true);
+}
+
+void mp3_play_stop(void)
+{
+ queue_post(&voice_codec_queue, Q_VOICE_STOP, 0);
}
void audio_set_buffer_margin(int setting)
@@ -2579,10 +2668,6 @@
if (!filebuf)
return; /* Audio buffers not yet set up */
- /* Store the track resume position */
- if (was_playing)
- offset = cur_ti->id3.offset;
-
if (enable)
seconds = global_settings.crossfade_fade_out_delay
+ global_settings.crossfade_fade_out_duration;
@@ -2596,8 +2681,12 @@
if (was_playing)
{
+ /* Store the track resume position */
+ offset = cur_ti->id3.offset;
/* Playback has to be stopped before changing the buffer size. */
- audio_stop_playback();
+ queue_post(&audio_queue, Q_AUDIO_STOP, 0);
+ while (audio_codec_loaded)
+ yield();
gui_syncsplash(0, true, (char *)str(LANG_RESTARTING_PLAYBACK));
}
@@ -2612,11 +2701,11 @@
/* Restart playback. */
if (was_playing) {
- audio_play(offset);
+ playing = true;
+ queue_post(&audio_queue, Q_AUDIO_PLAY, (void *)offset);
/* Wait for the playback to start again (and display the splash
screen during that period. */
- playing = true;
while (playing && !audio_codec_loaded)
yield();
}
@@ -2648,8 +2737,7 @@
{
(void)id3;
- logf("tce:%s", id3->artist);
- logf("tce:%s", id3->album);
+ logf("tce:%s", id3->path);
}
#endif
@@ -2674,7 +2762,7 @@
/* Initialize codec api. */
ci.read_filebuf = codec_filebuf_callback;
- ci.pcmbuf_insert = pcmbuf_insert_buffer;
+ ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
ci.pcmbuf_insert_split = codec_pcmbuf_insert_split_callback;
ci.get_codec_memory = get_codec_memory_callback;
ci.request_buffer = codec_request_buffer_callback;
@@ -2689,18 +2777,30 @@
ci.configure = codec_configure_callback;
ci.discard_codec = codec_discard_codec_callback;
+ /* Initialize voice codec api. */
memcpy(&ci_voice, &ci, sizeof(struct codec_api));
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 = get_voice_memory_callback;
+ ci_voice.request_buffer = voice_request_buffer_callback;
+ ci_voice.advance_buffer = voice_advance_buffer_callback;
+ ci_voice.advance_buffer_loc = voice_advance_buffer_loc_callback;
+ ci_voice.request_next_track = voice_request_next_track_callback;
+ ci_voice.mp3_get_filepos = voice_mp3_get_filepos_callback;
+ ci_voice.seek_buffer = voice_seek_buffer_callback;
+ ci_voice.seek_complete = voice_do_nothing;
+ ci_voice.set_elapsed = voice_set_elapsed_callback;
+ ci_voice.set_offset = voice_set_offset_callback;
+ ci_voice.discard_codec = voice_do_nothing;
ci_voice.taginfo_ready = &voicetagtrue;
ci_voice.id3 = &id3_voice;
- ci_voice.pcmbuf_insert = codec_pcmbuf_insert_callback;
id3_voice.frequency = 11200;
id3_voice.length = 1000000L;
create_thread(codec_thread, codec_stack, sizeof(codec_stack),
codec_thread_name);
- create_thread(voice_codec_thread, voice_codec_stack,
- sizeof(voice_codec_stack), voice_codec_thread_name);
while (1)
{
@@ -2720,8 +2820,9 @@
filebuf = (char *)&audiobuf[MALLOC_BUFSIZE];
- /* Apply relevant settings */
- audio_set_buffer_margin(global_settings.buffer_margin);
+ /* FIXME: This call will infinite loop if called on the audio thread
+ * while playing, fortunately this is an init call so that should be
+ * impossible. */
audio_set_crossfade(global_settings.crossfade);
sound_settings_apply();
@@ -2750,7 +2851,6 @@
queue_init(&audio_queue);
queue_init(&codec_queue);
- queue_init(&voice_codec_queue);
/* clear, not init to create a private queue */
queue_clear(&codec_callback_queue);