diff options
author | Brandon Low <lostlogic@rockbox.org> | 2006-04-22 14:40:13 +0000 |
---|---|---|
committer | Brandon Low <lostlogic@rockbox.org> | 2006-04-22 14:40:13 +0000 |
commit | f3bc1efc49826454a895c1c1f46fbe2cfd23f492 (patch) | |
tree | 676d501a9e75a9420f07a13f1d7fc1c5820b432a /apps | |
parent | b5991b27cafa8cc8bd2e86e04110beec34a587e0 (diff) | |
download | rockbox-f3bc1efc49826454a895c1c1f46fbe2cfd23f492.tar.gz rockbox-f3bc1efc49826454a895c1c1f46fbe2cfd23f492.zip |
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
Diffstat (limited to 'apps')
-rw-r--r-- | apps/codecs/a52.c | 5 | ||||
-rw-r--r-- | apps/codecs/aac.c | 14 | ||||
-rw-r--r-- | apps/codecs/aiff.c | 24 | ||||
-rw-r--r-- | apps/codecs/alac.c | 10 | ||||
-rw-r--r-- | apps/codecs/flac.c | 11 | ||||
-rw-r--r-- | apps/codecs/mpa.c | 8 | ||||
-rw-r--r-- | apps/codecs/mpc.c | 14 | ||||
-rw-r--r-- | apps/codecs/shorten.c | 3 | ||||
-rw-r--r-- | apps/codecs/vorbis.c | 8 | ||||
-rw-r--r-- | apps/codecs/wav.c | 34 | ||||
-rw-r--r-- | apps/codecs/wavpack.c | 6 | ||||
-rw-r--r-- | apps/dsp.h | 1 | ||||
-rw-r--r-- | apps/pcmbuf.c | 130 | ||||
-rw-r--r-- | apps/pcmbuf.h | 7 | ||||
-rw-r--r-- | apps/playback.c | 656 |
15 files changed, 531 insertions, 400 deletions
diff --git a/apps/codecs/a52.c b/apps/codecs/a52.c index 8ad9d37d33..71e0fda432 100644 --- a/apps/codecs/a52.c +++ b/apps/codecs/a52.c @@ -141,7 +141,6 @@ enum codec_status codec_start(struct codec_api *api) 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 @@ next_track: 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 02d460651c..532082ff05 100644 --- a/apps/codecs/aac.c +++ b/apps/codecs/aac.c @@ -63,7 +63,6 @@ enum codec_status codec_start(struct codec_api* api) 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 @@ next_track: 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 @@ next_track: if (!hDecoder) { LOGF("FAAD: Error opening decoder\n"); err = CODEC_ERROR; - goto exit; + goto done; } NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(hDecoder); @@ -112,7 +111,7 @@ next_track: 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 @@ next_track: &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 @@ next_track: 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 @@ next_track: 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 20d2dd3aa0..1e7adca220 100644 --- a/apps/codecs/aiff.c +++ b/apps/codecs/aiff.c @@ -98,11 +98,11 @@ next_track: 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 @@ next_track: 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 @@ next_track: 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 @@ next_track: 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 @@ next_track: 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 @@ next_track: 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 @@ next_track: } else { DEBUGF("CODEC_ERROR: more than 2 channels unsupported\n"); i = CODEC_ERROR; - goto exit; + goto done; } firstblockposn = 1024 - n; @@ -277,11 +276,12 @@ next_track: 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 73f45fc213..01172eed2b 100644 --- a/apps/codecs/alac.c +++ b/apps/codecs/alac.c @@ -64,7 +64,6 @@ enum codec_status codec_start(struct codec_api* api) 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 @@ enum codec_status codec_start(struct codec_api* api) 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 @@ enum codec_status codec_start(struct codec_api* api) &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 @@ enum codec_status codec_start(struct codec_api* api) 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 @@ enum codec_status codec_start(struct codec_api* api) 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 cc2ce636ab..5e392da8e7 100644 --- a/apps/codecs/flac.c +++ b/apps/codecs/flac.c @@ -224,7 +224,7 @@ enum codec_status codec_start(struct codec_api* api) { int8_t *buf; FLACContext fc; - uint32_t samplesdone; + uint32_t samplesdone = 0; uint32_t elapsedtime; size_t bytesleft; int consumed; @@ -244,7 +244,6 @@ enum codec_status codec_start(struct codec_api* api) 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 @@ enum codec_status codec_start(struct codec_api* api) 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 @@ enum codec_status codec_start(struct codec_api* api) 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 @@ enum codec_status codec_start(struct codec_api* api) 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 7219095591..51038c5244 100644 --- a/apps/codecs/mpa.c +++ b/apps/codecs/mpa.c @@ -91,7 +91,7 @@ void init_mad(void) /* 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 @@ enum codec_status codec_start(struct codec_api *api) /* 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 @@ enum codec_status codec_start(struct codec_api *api) * 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 @@ enum codec_status codec_start(struct codec_api *api) ci->id3->first_frame_offset; if (!ci->seek_buffer(newpos)) - goto next_track; + break; ci->seek_complete(); init_mad(); } @@ -192,7 +192,7 @@ enum codec_status codec_start(struct codec_api *api) 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 4201b2591c..ee639012b9 100644 --- a/apps/codecs/mpc.c +++ b/apps/codecs/mpc.c @@ -90,7 +90,6 @@ enum codec_status codec_start(struct codec_api *api) 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 @@ next_track: 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 @@ next_track: 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 @@ next_track: 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 @@ next_track: 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 @@ next_track: 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 03a08021a7..8d62a12f03 100644 --- a/apps/codecs/shorten.c +++ b/apps/codecs/shorten.c @@ -63,7 +63,6 @@ enum codec_status codec_start(struct codec_api* api) 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 @@ seek_start: 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 a9a274500c..1900364a89 100644 --- a/apps/codecs/vorbis.c +++ b/apps/codecs/vorbis.c @@ -129,7 +129,6 @@ enum codec_status codec_start(struct codec_api *api) 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 @@ next_track: } else { //rb->logf("ov_open: %d", error); error = CODEC_ERROR; - goto exit; + goto done; } if (rb->id3->offset) { @@ -224,7 +223,7 @@ next_track: 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 @@ next_track: 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 @@ next_track: goto next_track; } - error = CODEC_OK; exit: return error; } diff --git a/apps/codecs/wav.c b/apps/codecs/wav.c index c89d121c6a..d9be0a3420 100644 --- a/apps/codecs/wav.c +++ b/apps/codecs/wav.c @@ -242,7 +242,6 @@ enum codec_status codec_start(struct codec_api *api) 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 @@ next_track: 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 @@ next_track: 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 @@ next_track: 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 @@ next_track: 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 @@ next_track: 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 @@ next_track: 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 @@ next_track: 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 @@ next_track: && 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 @@ next_track: } else { DEBUGF("CODEC_ERROR: more than 2 channels\n"); i = CODEC_ERROR; - goto exit; + goto done; } if (totalsamples == 0) { @@ -406,7 +405,7 @@ next_track: } else { DEBUGF("CODEC_ERROR: cannot compute totalsamples\n"); i = CODEC_ERROR; - goto exit; + goto done; } } @@ -505,14 +504,14 @@ next_track: 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 @@ next_track: 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 f864aa3ec6..1871b46f67 100644 --- a/apps/codecs/wavpack.c +++ b/apps/codecs/wavpack.c @@ -75,7 +75,6 @@ enum codec_status codec_start(struct codec_api* api) 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 @@ enum codec_status codec_start(struct codec_api* api) if (!wpc) { retval = CODEC_ERROR; - goto exit; + goto done; } bps = WavpackGetBytesPerSample (wpc); @@ -143,11 +142,12 @@ enum codec_status codec_start(struct codec_api* api) 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 501e238a54..9d0f7de0db 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 071e5d4b3b..85a23e78bd 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c @@ -48,7 +48,8 @@ static size_t audiobuffer_pos IDATA_ATTR; 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 IDATA_ATTR; 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 @@ static void pcmbuf_callback(unsigned char** start, size_t* size) /* 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 @@ process_new_buffer: 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 @@ static inline void pcmbuf_add_chunk(void) /* 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 @@ void pcmbuf_play_stop(void) 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 @@ void pcmbuf_init(size_t bufsize) 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 @@ static void crossfade_process_buffer(size_t fade_in_delay, /* 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 @@ void* pcmbuf_request_buffer(size_t length, size_t *realsize) 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 @@ void* pcmbuf_request_voice_buffer(size_t length, size_t *realsize, bool mix) { 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 @@ bool pcmbuf_is_crossfade_active(void) 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 @@ bool pcmbuf_insert_buffer(const char *buf, size_t length) } /* 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; - - 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]; +static inline short* get_mix_insert_buf(void) { + if (pcmbuf_read->link) + { + /* Get the next chunk */ + char *pcmbuf_mix_buf = pcmbuf_read->link->addr; + + /* 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 @@ void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude) 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 @@ int pcmbuf_usage(void) 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 b659e8fa4e..819d5011cf 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 @@ bool pcmbuf_is_crossfade_enabled(void); 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 c34f83a4ca..35f5d7fff8 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -126,6 +126,9 @@ enum { 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 struct event_queue voice_codec_queue; 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 char *voicebuf; 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 filebuflen; 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 size_t buffer_margin; 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 @@ static void swap_codec(void) 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 void voice_boost_cpu(bool state) { static bool voice_cpu_boosted = false; - if (!voice_codec_loaded) - state = false; - if (state != voice_cpu_boosted) { cpu_boost(state); @@ -302,8 +308,8 @@ static void voice_boost_cpu(bool state) #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 @@ bool codec_pcmbuf_insert_split_callback(const void *ch1, const void *ch2, 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; } - else + + /* 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) { - /* Prevent audio from a previous position from hitting the buffer */ - if (ci.new_track || ci.stop_codec) - return true; + pcmbuf_mix_voice(output_size); + if (pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) + swap_codec(); + } + else + 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 @@ bool codec_pcmbuf_insert_split_callback(const void *ch1, const void *ch2, 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,13 +479,14 @@ static void pcmbuf_position_callback(size_t size) { } } -void codec_set_elapsed_callback(unsigned int value) +static void voice_set_elapsed_callback(unsigned int value) { - unsigned int latency; + (void)value; +} - /* We don't save or display offsets for voice */ - if (current_codec == CODEC_IDX_VOICE) - return ; +static void codec_set_elapsed_callback(unsigned int value) +{ + unsigned int latency; #ifdef AB_REPEAT_ENABLE ab_position_report(value); @@ -450,16 +500,14 @@ void codec_set_elapsed_callback(unsigned int value) 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; - - /* 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; + (void)value; +} +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 @@ static void advance_buffer_counters(size_t amount) { 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 @@ size_t codec_filebuf_callback(void *ptr, size_t size) 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) - { + switch (ev.id) { + case Q_AUDIO_PLAY: + swap_codec(); + break; + + 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_play_clip: + + if (voice_remaining == 0 || voicebuf == NULL) + { + if (voice_getmore) voice_getmore((unsigned char **)&voicebuf, (int *)&voice_remaining); - if (!voice_remaining) - { - voice_is_playing = false; - /* Force pcm playback. */ + /* 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(); - } } } - - voice_is_playing = true; + *realsize = MIN(voice_remaining, reqsize); if (*realsize == 0) @@ -595,14 +703,10 @@ void* voice_request_data(size_t *realsize, size_t reqsize) 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 @@ static int get_codec_base_type(int type) } /* 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 @@ static void audio_rebuffer(void) /* 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 @@ static void audio_rebuffer(void) 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 @@ static void rebuffer_and_seek(size_t newpos) 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 @@ static void rebuffer_and_seek(size_t newpos) 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; - - return ; - } + amount = MIN(amount, voice_remaining); + voicebuf += amount; + voice_remaining -= amount; +} +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 @@ void codec_advance_buffer_callback(size_t amount) 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; - - if (current_codec == CODEC_IDX_VOICE) - amount = (size_t)ptr - (size_t)voicebuf; - else - amount = (size_t)ptr - (size_t)&filebuf[buf_ridx]; + size_t amount = (size_t)ptr - (size_t)voicebuf; + voice_advance_buffer_callback(amount); +} +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 @@ off_t codec_mp3_get_filepos_callback(int newtime) 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,12 +1139,15 @@ void codec_seek_complete_callback(void) ci.seek_time = 0; } -bool codec_seek_buffer_callback(size_t newpos) +static bool voice_seek_buffer_callback(size_t newpos) { - int difference; + (void)newpos; + return false; +} - if (current_codec == CODEC_IDX_VOICE) - return false; +static bool codec_seek_buffer_callback(size_t newpos) +{ + int difference; if (newpos >= cur_ti->filesize) newpos = cur_ti->filesize - 1; @@ -1083,7 +1201,7 @@ static void set_filebuf_watermark(int seconds) size_t bytes; if (current_codec == CODEC_IDX_VOICE) - return ; + return; if (!filebuf) return; /* Audio buffers not yet set up */ @@ -1105,13 +1223,6 @@ static void codec_configure_callback(int setting, void *value) 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 @@ static bool yield_codecs(void) } /* 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 @@ static void audio_read_file(void) 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 @@ static bool audio_load_track(int offset, bool start_play) 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 @@ static bool audio_load_track(int offset, bool start_play) 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 @@ static void audio_clear_track_entries(bool clear_unbuffered) /* 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 @@ static void audio_stop_playback(void) /* 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 @@ static void audio_play_start(size_t offset) 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 generate_postbuffer_events(void) } } -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 @@ static void initialize_buffer_fill(bool clear_tracks, bool short_fill) 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 @@ static void initialize_buffer_fill(bool clear_tracks, bool short_fill) 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 @@ static void audio_fill_file_buffer( generate_postbuffer_events(); filling = false; - filling_short = false; #ifndef SIMULATOR if (playing) @@ -1899,17 +1998,16 @@ static bool load_next_track(void) { } } +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 @@ void audio_invalidate_tracks(void) 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 @@ void audio_thread(void) 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 audio_thread(void) } } -void codec_thread(void) +static void codec_thread(void) { struct event ev; int status; @@ -2088,16 +2186,18 @@ void codec_thread(void) 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 @@ void codec_thread(void) 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 @@ void codec_thread(void) #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 @@ void codec_thread(void) 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 @@ static void reset_buffer(void) 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 @@ static void reset_buffer(void) 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; - - 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 ; + codec_load_file(CODEC_MPA_L3, &ci_voice); -#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 @@ void voice_init(void) 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 @@ static void mp3_set_elapsed(struct mp3entry* id3) } /* 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 @@ int mp3_get_file_pos(void) 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 @@ void audio_set_crossfade(int enable) 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 @@ void audio_set_crossfade(int enable) 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 @@ void audio_set_crossfade(int enable) /* 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 test_track_changed_event(struct mp3entry *id3) { (void)id3; - logf("tce:%s", id3->artist); - logf("tce:%s", id3->album); + logf("tce:%s", id3->path); } #endif @@ -2674,7 +2762,7 @@ static void playback_init(void) /* 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 @@ static void playback_init(void) 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 @@ static void playback_init(void) 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 @@ void audio_preinit(void) 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); |