1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Brandon Low 2006-04-22 14:40:13 +00:00
parent b5991b27ca
commit f3bc1efc49
16 changed files with 531 additions and 405 deletions

View file

@ -141,7 +141,6 @@ enum codec_status codec_start(struct codec_api *api)
ci->memset(iedata, 0, iend - iedata); ci->memset(iedata, 0, iend - iedata);
#endif #endif
ci->configure(CODEC_DSP_ENABLE, (bool *)true);
ci->configure(DSP_DITHER, (bool *)false); ci->configure(DSP_DITHER, (bool *)false);
ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_NONINTERLEAVED); ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)28); ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)28);
@ -185,9 +184,11 @@ next_track:
a52_decode_data(filebuf, filebuf + n); a52_decode_data(filebuf, filebuf + n);
ci->advance_buffer(n); ci->advance_buffer(n);
} }
retval = CODEC_OK;
if (ci->request_next_track()) if (ci->request_next_track())
goto next_track; goto next_track;
retval = CODEC_OK;
exit: exit:
a52_free(state); a52_free(state);
return retval; return retval;

View file

@ -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_CHUNKSIZE, (int *)(1024*16));
ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); 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_DITHER, (bool *)false);
ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_NONINTERLEAVED); ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(29)); ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(29));
@ -88,7 +87,7 @@ next_track:
if (!qtmovie_read(&input_stream, &demux_res)) { if (!qtmovie_read(&input_stream, &demux_res)) {
LOGF("FAAD: Error initialising file\n"); LOGF("FAAD: Error initialising file\n");
err = CODEC_ERROR; err = CODEC_ERROR;
goto exit; goto done;
} }
/* initialise the sound converter */ /* initialise the sound converter */
@ -98,7 +97,7 @@ next_track:
if (!hDecoder) { if (!hDecoder) {
LOGF("FAAD: Error opening decoder\n"); LOGF("FAAD: Error opening decoder\n");
err = CODEC_ERROR; err = CODEC_ERROR;
goto exit; goto done;
} }
NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(hDecoder); NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(hDecoder);
@ -112,7 +111,7 @@ next_track:
if (err) { if (err) {
LOGF("FAAD: Error initialising decoder: %d, type=%d\n", err,hDecoder->object_type); LOGF("FAAD: Error initialising decoder: %d, type=%d\n", err,hDecoder->object_type);
err = CODEC_ERROR; err = CODEC_ERROR;
goto exit; goto done;
} }
ci->id3->frequency=s; ci->id3->frequency=s;
@ -142,7 +141,7 @@ next_track:
&sample_byte_size)) { &sample_byte_size)) {
LOGF("AAC: Error in get_sample_info\n"); LOGF("AAC: Error in get_sample_info\n");
err = CODEC_ERROR; err = CODEC_ERROR;
goto exit; goto done;
} }
/* Request the required number of bytes from the input buffer */ /* Request the required number of bytes from the input buffer */
@ -156,7 +155,7 @@ next_track:
if (frameInfo.error > 0) { if (frameInfo.error > 0) {
LOGF("FAAD: decoding error \"%s\"\n", NeAACDecGetErrorMessage(frameInfo.error)); LOGF("FAAD: decoding error \"%s\"\n", NeAACDecGetErrorMessage(frameInfo.error));
err = CODEC_ERROR; err = CODEC_ERROR;
goto exit; goto done;
} }
/* Get the number of decoded samples */ /* Get the number of decoded samples */
@ -182,13 +181,14 @@ next_track:
i++; i++;
} }
err = CODEC_OK;
done:
LOGF("AAC: Decoded %d samples\n",samplesdone); LOGF("AAC: Decoded %d samples\n",samplesdone);
if (ci->request_next_track()) if (ci->request_next_track())
goto next_track; goto next_track;
err = CODEC_OK;
exit: exit:
return err; return err;
} }

View file

@ -98,11 +98,11 @@ next_track:
buf = ci->request_buffer(&n, 1024); buf = ci->request_buffer(&n, 1024);
if (n < 44) { if (n < 44) {
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
if ((memcmp(buf, "FORM", 4) != 0) || (memcmp(&buf[8], "AIFF", 4) != 0)) { if ((memcmp(buf, "FORM", 4) != 0) || (memcmp(&buf[8], "AIFF", 4) != 0)) {
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
buf += 12; buf += 12;
@ -117,7 +117,7 @@ next_track:
if (i != 18) { if (i != 18) {
DEBUGF("CODEC_ERROR: 'COMM' chunk size=%lu != 18\n", i); DEBUGF("CODEC_ERROR: 'COMM' chunk size=%lu != 18\n", i);
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
/* num_channels */ /* num_channels */
num_channels = ((buf[8]<<8)|buf[9]); num_channels = ((buf[8]<<8)|buf[9]);
@ -130,7 +130,7 @@ next_track:
if (buf[16] != 0x40) { if (buf[16] != 0x40) {
DEBUGF("CODEC_ERROR: weird sampling rate (no @)\n", i); DEBUGF("CODEC_ERROR: weird sampling rate (no @)\n", i);
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
sample_rate = ((buf[18]<<24)|(buf[19]<<16)|(buf[20]<<8)|buf[21])+1; sample_rate = ((buf[18]<<24)|(buf[19]<<16)|(buf[20]<<8)|buf[21])+1;
sample_rate = sample_rate >> (16 + 14 - buf[17]); sample_rate = sample_rate >> (16 + 14 - buf[17]);
@ -140,7 +140,7 @@ next_track:
if (sample_size == 0) { if (sample_size == 0) {
DEBUGF("CODEC_ERROR: unsupported chunk order\n"); DEBUGF("CODEC_ERROR: unsupported chunk order\n");
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
/* offset2snd */ /* offset2snd */
offset2snd = ((buf[8]<<8)|buf[9]); offset2snd = ((buf[8]<<8)|buf[9]);
@ -161,7 +161,7 @@ next_track:
if (n < (i + 8)) { if (n < (i + 8)) {
DEBUGF("CODEC_ERROR: AIFF header size > 1024\n"); DEBUGF("CODEC_ERROR: AIFF header size > 1024\n");
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
n -= i + 8; n -= i + 8;
} /* while 'SSND' */ } /* while 'SSND' */
@ -169,21 +169,20 @@ next_track:
if (num_channels == 0) { if (num_channels == 0) {
DEBUGF("CODEC_ERROR: 'COMM' chunk not found or 0-channels file\n"); DEBUGF("CODEC_ERROR: 'COMM' chunk not found or 0-channels file\n");
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
if (numbytes == 0) { if (numbytes == 0) {
DEBUGF("CODEC_ERROR: 'SSND' chunk not found or has zero length\n"); DEBUGF("CODEC_ERROR: 'SSND' chunk not found or has zero length\n");
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
if (sample_size > 24) { if (sample_size > 24) {
DEBUGF("CODEC_ERROR: PCM with more than 24 bits per sample " DEBUGF("CODEC_ERROR: PCM with more than 24 bits per sample "
"is unsupported\n"); "is unsupported\n");
i = CODEC_ERROR; 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_FREQUENCY, (long *)(ci->id3->frequency));
ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)28); ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)28);
@ -194,7 +193,7 @@ next_track:
} else { } else {
DEBUGF("CODEC_ERROR: more than 2 channels unsupported\n"); DEBUGF("CODEC_ERROR: more than 2 channels unsupported\n");
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
firstblockposn = 1024 - n; firstblockposn = 1024 - n;
@ -277,11 +276,12 @@ next_track:
ci->set_elapsed(bytesdone*1000LL/avgbytespersec); ci->set_elapsed(bytesdone*1000LL/avgbytespersec);
} }
i = CODEC_OK;
done:
if (ci->request_next_track()) if (ci->request_next_track())
goto next_track; goto next_track;
i = CODEC_OK;
exit: exit:
return i; return i;
} }

View file

@ -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_WATERMARK, (int *)(1024*512));
ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128)); 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_DITHER, (bool *)false);
ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_NONINTERLEAVED); ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(ALAC_OUTPUT_DEPTH-1)); 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)) { if (!qtmovie_read(&input_stream, &demux_res)) {
LOGF("ALAC: Error initialising file\n"); LOGF("ALAC: Error initialising file\n");
retval = CODEC_ERROR; retval = CODEC_ERROR;
goto exit; goto done;
} }
/* initialise the sound converter */ /* initialise the sound converter */
@ -121,7 +120,7 @@ enum codec_status codec_start(struct codec_api* api)
&sample_byte_size)) { &sample_byte_size)) {
LOGF("ALAC: Error in get_sample_info\n"); LOGF("ALAC: Error in get_sample_info\n");
retval = CODEC_ERROR; retval = CODEC_ERROR;
goto exit; goto done;
} }
/* Request the required number of bytes from the input buffer */ /* 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); buffer=ci->request_buffer(&n,sample_byte_size);
if (n!=sample_byte_size) { if (n!=sample_byte_size) {
retval = CODEC_ERROR; retval = CODEC_ERROR;
goto exit; goto done;
} }
/* Decode one block - returned samples will be host-endian */ /* Decode one block - returned samples will be host-endian */
@ -156,13 +155,14 @@ enum codec_status codec_start(struct codec_api* api)
i++; i++;
} }
retval = CODEC_OK;
done:
LOGF("ALAC: Decoded %d samples\n",samplesdone); LOGF("ALAC: Decoded %d samples\n",samplesdone);
if (ci->request_next_track()) if (ci->request_next_track())
goto next_track; goto next_track;
retval = CODEC_OK;
exit: exit:
return retval; return retval;
} }

View file

@ -224,7 +224,7 @@ enum codec_status codec_start(struct codec_api* api)
{ {
int8_t *buf; int8_t *buf;
FLACContext fc; FLACContext fc;
uint32_t samplesdone; uint32_t samplesdone = 0;
uint32_t elapsedtime; uint32_t elapsedtime;
size_t bytesleft; size_t bytesleft;
int consumed; 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_WATERMARK, (int *)(1024*512));
ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128)); 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_DITHER, (bool *)false);
ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_NONINTERLEAVED); ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(FLAC_OUTPUT_DEPTH-1)); 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)) { if (!flac_init(&fc,ci->id3->first_frame_offset)) {
LOGF("FLAC: Error initialising codec\n"); LOGF("FLAC: Error initialising codec\n");
retval = CODEC_ERROR; retval = CODEC_ERROR;
goto exit; goto done;
} }
while (!*ci->taginfo_ready) while (!*ci->taginfo_ready)
@ -292,7 +291,7 @@ enum codec_status codec_start(struct codec_api* api)
bytesleft,ci->yield)) < 0) { bytesleft,ci->yield)) < 0) {
LOGF("FLAC: Frame %d, error %d\n",frame,res); LOGF("FLAC: Frame %d, error %d\n",frame,res);
retval = CODEC_ERROR; retval = CODEC_ERROR;
goto exit; goto done;
} }
consumed=fc.gb.index/8; consumed=fc.gb.index/8;
frame++; frame++;
@ -312,12 +311,14 @@ enum codec_status codec_start(struct codec_api* api)
buf = ci->request_buffer(&bytesleft, MAX_FRAMESIZE); buf = ci->request_buffer(&bytesleft, MAX_FRAMESIZE);
} }
retval = CODEC_OK;
done:
LOGF("FLAC: Decoded %d samples\n",samplesdone); LOGF("FLAC: Decoded %d samples\n",samplesdone);
if (ci->request_next_track()) if (ci->request_next_track())
goto next_track; goto next_track;
retval = CODEC_OK;
exit: exit:
return retval; return retval;
} }

View file

@ -91,7 +91,7 @@ void init_mad(void)
/* this is the codec entry point */ /* this is the codec entry point */
enum codec_status codec_start(struct codec_api *api) enum codec_status codec_start(struct codec_api *api)
{ {
int status = CODEC_OK; int status;
size_t size; size_t size;
int file_end; int file_end;
int frame_skip; /* samples to skip current frame */ 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 */ /* Create a decoder instance */
ci->configure(CODEC_DSP_ENABLE, (bool *)true);
ci->configure(DSP_DITHER, (bool *)false); ci->configure(DSP_DITHER, (bool *)false);
ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(MAD_F_FRACBITS)); ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(MAD_F_FRACBITS));
ci->configure(DSP_SET_CLIP_MIN, (int *)-MAD_F_ONE); 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. * for gapless playback.
* Reinitializing seems to be necessary to avoid playback quircks when seeking. */ * Reinitializing seems to be necessary to avoid playback quircks when seeking. */
next_track: next_track:
status = CODEC_OK;
init_mad(); init_mad();
@ -171,7 +171,7 @@ enum codec_status codec_start(struct codec_api *api)
ci->id3->first_frame_offset; ci->id3->first_frame_offset;
if (!ci->seek_buffer(newpos)) if (!ci->seek_buffer(newpos))
goto next_track; break;
ci->seek_complete(); ci->seek_complete();
init_mad(); init_mad();
} }
@ -192,7 +192,7 @@ enum codec_status codec_start(struct codec_api *api)
break; break;
/* Fill the buffer */ /* 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); ci->advance_buffer_loc((void *)stream.next_frame);
else else
ci->advance_buffer(size); ci->advance_buffer(size);

View file

@ -90,7 +90,6 @@ enum codec_status codec_start(struct codec_api *api)
ci->memset(iedata, 0, iend - iedata); ci->memset(iedata, 0, iend - iedata);
#endif #endif
ci->configure(CODEC_DSP_ENABLE, (bool *)true);
ci->configure(DSP_DITHER, (bool *)false); ci->configure(DSP_DITHER, (bool *)false);
ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)(28)); ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)(28));
ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (long *)(1024*16)); ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (long *)(1024*16));
@ -113,7 +112,7 @@ next_track:
mpc_streaminfo_init(&info); mpc_streaminfo_init(&info);
if (mpc_streaminfo_read(&info, &reader) != ERROR_CODE_OK) { if (mpc_streaminfo_read(&info, &reader) != ERROR_CODE_OK) {
retval = CODEC_ERROR; retval = CODEC_ERROR;
goto exit; goto done;
} }
frequency = info.sample_freq; frequency = info.sample_freq;
ci->configure(DSP_SET_FREQUENCY, (long *)(long)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); ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_MONO);
else { else {
retval = CODEC_ERROR; retval = CODEC_ERROR;
goto exit; goto done;
} }
codec_set_replaygain(ci->id3); codec_set_replaygain(ci->id3);
@ -135,7 +134,7 @@ next_track:
mpc_decoder_setup(&decoder, &reader); mpc_decoder_setup(&decoder, &reader);
if (!mpc_decoder_initialize(&decoder, &info)) { if (!mpc_decoder_initialize(&decoder, &info)) {
retval = CODEC_ERROR; retval = CODEC_ERROR;
goto exit; goto done;
} }
/* This is the decoding loop. */ /* This is the decoding loop. */
@ -171,7 +170,7 @@ next_track:
ci->yield(); ci->yield();
if (status == (unsigned)(-1)) { /* decode error */ if (status == (unsigned)(-1)) { /* decode error */
retval = CODEC_ERROR; retval = CODEC_ERROR;
goto exit; goto done;
} else { } else {
while (!ci->pcmbuf_insert_split(sample_buffer, while (!ci->pcmbuf_insert_split(sample_buffer,
sample_buffer + MPC_FRAME_LENGTH, sample_buffer + MPC_FRAME_LENGTH,
@ -181,11 +180,12 @@ next_track:
ci->set_elapsed(samplesdone/(frequency/1000)); ci->set_elapsed(samplesdone/(frequency/1000));
} }
} while (status != 0); } while (status != 0);
retval = CODEC_OK;
done:
if (ci->request_next_track()) if (ci->request_next_track())
goto next_track; goto next_track;
retval = CODEC_OK;
exit: exit:
return retval; return retval;
} }

View file

@ -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_WATERMARK, (int *)(1024*512));
ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128)); 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_DITHER, (bool *)false);
ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_NONINTERLEAVED); ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(SHN_OUTPUT_DEPTH-1)); ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(SHN_OUTPUT_DEPTH-1));
@ -146,7 +145,7 @@ seek_start:
if (res == FN_ERROR) { if (res == FN_ERROR) {
LOGF("Shorten: shorten_decode_frames error (%d)\n", samplesdone); LOGF("Shorten: shorten_decode_frames error (%d)\n", samplesdone);
return CODEC_ERROR; break;
} else { } else {
/* Insert decoded samples in pcmbuf */ /* Insert decoded samples in pcmbuf */
if (nsamples) { if (nsamples) {

View file

@ -129,7 +129,6 @@ enum codec_status codec_start(struct codec_api *api)
rb->memset(iedata, 0, iend - iedata); rb->memset(iedata, 0, iend - iedata);
#endif #endif
rb->configure(CODEC_DSP_ENABLE, (bool *)true);
rb->configure(DSP_DITHER, (bool *)false); rb->configure(DSP_DITHER, (bool *)false);
rb->configure(DSP_SET_SAMPLE_DEPTH, (long *)24); rb->configure(DSP_SET_SAMPLE_DEPTH, (long *)24);
rb->configure(DSP_SET_CLIP_MAX, (long *)((1 << 24) - 1)); rb->configure(DSP_SET_CLIP_MAX, (long *)((1 << 24) - 1));
@ -194,7 +193,7 @@ next_track:
} else { } else {
//rb->logf("ov_open: %d", error); //rb->logf("ov_open: %d", error);
error = CODEC_ERROR; error = CODEC_ERROR;
goto exit; goto done;
} }
if (rb->id3->offset) { if (rb->id3->offset) {
@ -224,7 +223,7 @@ next_track:
if (current_section != previous_section) { if (current_section != previous_section) {
if (!vorbis_set_codec_parameters(&vf)) { if (!vorbis_set_codec_parameters(&vf)) {
error = CODEC_ERROR; error = CODEC_ERROR;
goto exit; goto done;
} else { } else {
previous_section = current_section; previous_section = current_section;
} }
@ -243,7 +242,9 @@ next_track:
rb->set_elapsed(ov_time_tell(&vf)); rb->set_elapsed(ov_time_tell(&vf));
} }
} }
error = CODEC_OK;
done:
if (rb->request_next_track()) { if (rb->request_next_track()) {
/* Clean things up for the next track */ /* Clean things up for the next track */
vf.dataoffsets = NULL; vf.dataoffsets = NULL;
@ -255,7 +256,6 @@ next_track:
goto next_track; goto next_track;
} }
error = CODEC_OK;
exit: exit:
return error; return error;
} }

View file

@ -242,7 +242,6 @@ enum codec_status codec_start(struct codec_api *api)
ci->memset(iedata, 0, iend - iedata); ci->memset(iedata, 0, iend - iedata);
#endif #endif
ci->configure(CODEC_DSP_ENABLE, (bool *)true);
ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)28); ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)28);
ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256)); ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256));
@ -261,11 +260,11 @@ next_track:
buf = ci->request_buffer(&n, 1024); buf = ci->request_buffer(&n, 1024);
if (n < 44) { if (n < 44) {
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
if ((memcmp(buf, "RIFF", 4) != 0) || (memcmp(&buf[8], "WAVE", 4) != 0)) { if ((memcmp(buf, "RIFF", 4) != 0) || (memcmp(&buf[8], "WAVE", 4) != 0)) {
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
buf += 12; buf += 12;
@ -281,7 +280,7 @@ next_track:
if (i < 16) { if (i < 16) {
DEBUGF("CODEC_ERROR: 'fmt ' chunk size=%lu < 16\n", i); DEBUGF("CODEC_ERROR: 'fmt ' chunk size=%lu < 16\n", i);
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
/* wFormatTag */ /* wFormatTag */
formattag=buf[8]|(buf[9]<<8); formattag=buf[8]|(buf[9]<<8);
@ -309,7 +308,7 @@ next_track:
DEBUGF("CODEC_ERROR: dvi_adpcm is missing " DEBUGF("CODEC_ERROR: dvi_adpcm is missing "
"SamplesPerBlock value\n"); "SamplesPerBlock value\n");
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
samplesperblock = buf[26]|(buf[27]<<8); samplesperblock = buf[26]|(buf[27]<<8);
} else if (formattag == WAVE_FORMAT_EXTENSIBLE) { } else if (formattag == WAVE_FORMAT_EXTENSIBLE) {
@ -317,7 +316,7 @@ next_track:
DEBUGF("CODEC_ERROR: WAVE_FORMAT_EXTENSIBLE is " DEBUGF("CODEC_ERROR: WAVE_FORMAT_EXTENSIBLE is "
"missing extension\n"); "missing extension\n");
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
/* wValidBitsPerSample */ /* wValidBitsPerSample */
bitspersample = buf[26]|(buf[27]<<8); bitspersample = buf[26]|(buf[27]<<8);
@ -344,7 +343,7 @@ next_track:
if (n < (i + 8)) { if (n < (i + 8)) {
DEBUGF("CODEC_ERROR: WAVE header size > 1024\n"); DEBUGF("CODEC_ERROR: WAVE header size > 1024\n");
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
n -= i + 8; n -= i + 8;
} }
@ -352,12 +351,12 @@ next_track:
if (channels == 0) { if (channels == 0) {
DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-channels file\n"); DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-channels file\n");
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
if (numbytes == 0) { if (numbytes == 0) {
DEBUGF("CODEC_ERROR: 'data' chunk not found or has zero-length\n"); DEBUGF("CODEC_ERROR: 'data' chunk not found or has zero-length\n");
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
if (formattag != WAVE_FORMAT_PCM && totalsamples == 0) { if (formattag != WAVE_FORMAT_PCM && totalsamples == 0) {
/* This is non-fatal for some formats */ /* This is non-fatal for some formats */
@ -368,7 +367,7 @@ next_track:
if (bitspersample != 8) { if (bitspersample != 8) {
DEBUGF("CODEC_ERROR: alaw and mulaw must have 8 bitspersample\n"); DEBUGF("CODEC_ERROR: alaw and mulaw must have 8 bitspersample\n");
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
bytespersample = channels; bytespersample = channels;
} }
@ -376,13 +375,13 @@ next_track:
&& bitspersample != 4 && bitspersample != 3) { && bitspersample != 4 && bitspersample != 3) {
DEBUGF("CODEC_ERROR: dvi_adpcm must have 3 or 4 bitspersample\n"); DEBUGF("CODEC_ERROR: dvi_adpcm must have 3 or 4 bitspersample\n");
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
if (formattag == WAVE_FORMAT_PCM && bitspersample > 32) { if (formattag == WAVE_FORMAT_PCM && bitspersample > 32) {
DEBUGF("CODEC_ERROR: pcm with more than 32 bitspersample " DEBUGF("CODEC_ERROR: pcm with more than 32 bitspersample "
"is unsupported\n"); "is unsupported\n");
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
ci->configure(DSP_SET_FREQUENCY, (long *)(ci->id3->frequency)); ci->configure(DSP_SET_FREQUENCY, (long *)(ci->id3->frequency));
@ -393,7 +392,7 @@ next_track:
} else { } else {
DEBUGF("CODEC_ERROR: more than 2 channels\n"); DEBUGF("CODEC_ERROR: more than 2 channels\n");
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
if (totalsamples == 0) { if (totalsamples == 0) {
@ -406,7 +405,7 @@ next_track:
} else { } else {
DEBUGF("CODEC_ERROR: cannot compute totalsamples\n"); DEBUGF("CODEC_ERROR: cannot compute totalsamples\n");
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
} }
@ -505,14 +504,14 @@ next_track:
samples + i*samplesperblock*channels, samples + i*samplesperblock*channels,
&decodedsize) != CODEC_OK) { &decodedsize) != CODEC_OK) {
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
} }
bufsize = nblocks*samplesperblock*channels*4; bufsize = nblocks*samplesperblock*channels*4;
} else { } else {
DEBUGF("CODEC_ERROR: unsupported format %x\n", formattag); DEBUGF("CODEC_ERROR: unsupported format %x\n", formattag);
i = CODEC_ERROR; i = CODEC_ERROR;
goto exit; goto done;
} }
while (!ci->pcmbuf_insert((char *)samples, bufsize)) while (!ci->pcmbuf_insert((char *)samples, bufsize))
@ -524,11 +523,12 @@ next_track:
endofstream = 1; endofstream = 1;
ci->set_elapsed(bytesdone*1000LL/avgbytespersec); ci->set_elapsed(bytesdone*1000LL/avgbytespersec);
} }
i = CODEC_OK;
done:
if (ci->request_next_track()) if (ci->request_next_track())
goto next_track; goto next_track;
i = CODEC_OK;
exit: exit:
return i; return i;
} }

View file

@ -75,7 +75,6 @@ enum codec_status codec_start(struct codec_api* api)
while (!*ci->taginfo_ready && !ci->stop_codec) while (!*ci->taginfo_ready && !ci->stop_codec)
ci->sleep(1); ci->sleep(1);
ci->configure(CODEC_DSP_ENABLE, (bool *)true);
ci->configure(DSP_SET_FREQUENCY, (long *)(ci->id3->frequency)); ci->configure(DSP_SET_FREQUENCY, (long *)(ci->id3->frequency));
codec_set_replaygain(ci->id3); codec_set_replaygain(ci->id3);
@ -84,7 +83,7 @@ enum codec_status codec_start(struct codec_api* api)
if (!wpc) { if (!wpc) {
retval = CODEC_ERROR; retval = CODEC_ERROR;
goto exit; goto done;
} }
bps = WavpackGetBytesPerSample (wpc); 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->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10);
ci->yield (); ci->yield ();
} }
retval = CODEC_OK;
done:
if (ci->request_next_track()) if (ci->request_next_track())
goto next_track; goto next_track;
retval = CODEC_OK;
exit: exit:
return retval; return retval;
} }

View file

@ -31,7 +31,6 @@
enum { enum {
CODEC_SET_FILEBUF_WATERMARK = 1, CODEC_SET_FILEBUF_WATERMARK = 1,
CODEC_SET_FILEBUF_CHUNKSIZE, CODEC_SET_FILEBUF_CHUNKSIZE,
CODEC_DSP_ENABLE,
DSP_SET_FREQUENCY, DSP_SET_FREQUENCY,
DSP_SWITCH_FREQUENCY, DSP_SWITCH_FREQUENCY,
DSP_SET_CLIP_MIN, DSP_SET_CLIP_MIN,

View file

@ -48,7 +48,8 @@ static size_t audiobuffer_pos IDATA_ATTR;
size_t audiobuffer_free IDATA_ATTR; size_t audiobuffer_free IDATA_ATTR;
/* Amount audiobuffer_pos will be increased.*/ /* Amount audiobuffer_pos will be increased.*/
static size_t audiobuffer_fillpos IDATA_ATTR; 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 (*pcmbuf_event_handler)(void) IDATA_ATTR;
static void (*position_callback)(size_t size) 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 struct pcmbufdesc *pcmbuf_write_end IDATA_ATTR;
static size_t last_chunksize IDATA_ATTR; static size_t last_chunksize IDATA_ATTR;
static size_t pcmbuf_unplayed_bytes 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 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; static bool low_latency_mode = false;
/* Helpful macros for use in conditionals this assumes some of the above /* 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 */ /* Put the finished buffer back into circulation */
pcmbuf_write_end->link = pcmbuf_current; pcmbuf_write_end->link = pcmbuf_current;
pcmbuf_write_end = 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: process_new_buffer:
@ -162,9 +167,10 @@ process_new_buffer:
if(pcmbuf_new) if(pcmbuf_new)
{ {
size_t current_size = pcmbuf_new->size; size_t current_size = pcmbuf_new->size;
pcmbuf_unplayed_bytes -= current_size; pcmbuf_unplayed_bytes -= current_size;
*realsize = current_size;
last_chunksize = current_size; last_chunksize = current_size;
*realsize = current_size;
*realstart = pcmbuf_new->addr; *realstart = pcmbuf_new->addr;
} }
else else
@ -219,14 +225,10 @@ static inline void pcmbuf_add_chunk(void)
/* Update bytes counters */ /* Update bytes counters */
pcmbuf_unplayed_bytes += size; pcmbuf_unplayed_bytes += size;
if (pcmbuf_mix_used_bytes > size)
pcmbuf_mix_used_bytes -= size;
else
pcmbuf_mix_used_bytes = 0;
audiobuffer_pos += size; audiobuffer_pos += size;
if (audiobuffer_pos >= pcmbuf_size) if (audiobuffer_pos >= pcmbuf_size)
audiobuffer_pos = 0; audiobuffer_pos -= pcmbuf_size;
audiobuffer_fillpos = 0; audiobuffer_fillpos = 0;
} }
@ -299,7 +301,7 @@ void pcmbuf_play_stop(void)
pcm_mute(false); pcm_mute(false);
pcmbuf_unplayed_bytes = 0; pcmbuf_unplayed_bytes = 0;
pcmbuf_mix_used_bytes = 0; pcmbuf_mix_chunk = NULL;
if (pcmbuf_read) { if (pcmbuf_read) {
pcmbuf_write_end->link = pcmbuf_read; pcmbuf_write_end->link = pcmbuf_read;
pcmbuf_write_end = pcmbuf_read_end; pcmbuf_write_end = pcmbuf_read_end;
@ -351,9 +353,10 @@ void pcmbuf_init(size_t bufsize)
pcmbuf_size = bufsize; pcmbuf_size = bufsize;
pcmbuf_descsize = pcmbuf_descs()*sizeof(struct pcmbufdesc); pcmbuf_descsize = pcmbuf_descs()*sizeof(struct pcmbufdesc);
audiobuffer = (char *)&audiobuf[(audiobufend - audiobuf) - audiobuffer = (char *)&audiobuf[(audiobufend - audiobuf) -
(pcmbuf_size + PCMBUF_FADE_CHUNK + pcmbuf_descsize)]; (pcmbuf_size + PCMBUF_MIX_CHUNK * 2 + pcmbuf_descsize)];
guardbuf = &audiobuffer[pcmbuf_size]; fadebuf = &audiobuffer[pcmbuf_size];
pcmbuf_write = (struct pcmbufdesc *)(&guardbuf[PCMBUF_FADE_CHUNK]); voicebuf = &fadebuf[PCMBUF_MIX_CHUNK];
pcmbuf_write = (struct pcmbufdesc *)(&voicebuf[PCMBUF_MIX_CHUNK]);
pcmbuf_init_pcmbuffers(); pcmbuf_init_pcmbuffers();
position_callback = NULL; position_callback = NULL;
pcmbuf_event_handler = 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 */ /* Fade out the specified amount of the already processed audio */
size_t total_fade_out = fade_out_rem; size_t total_fade_out = fade_out_rem;
short *buf = (short *)&audiobuffer[crossfade_pos + fade_out_delay * 2]; 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 */ /* Wrap the starting position if needed */
if (buf >= buf_end) buf -= pcmbuf_size / 2; if (buf >= buf_end) buf -= pcmbuf_size / 2;
@ -738,8 +741,8 @@ void* pcmbuf_request_buffer(size_t length, size_t *realsize)
crossfade_start(); crossfade_start();
if (crossfade_active) { if (crossfade_active) {
*realsize = MIN(length, PCMBUF_FADE_CHUNK); *realsize = MIN(length, PCMBUF_MIX_CHUNK);
return &guardbuf[0]; return fadebuf;
} }
else else
{ {
@ -772,8 +775,16 @@ void* pcmbuf_request_voice_buffer(size_t length, size_t *realsize, bool mix)
{ {
if (mix) if (mix)
{ {
*realsize = MIN(length, PCMBUF_FADE_CHUNK); if (pcmbuf_mix_chunk || pcmbuf_read->link)
return &guardbuf[0]; {
*realsize = MIN(length, PCMBUF_MIX_CHUNK);
return voicebuf;
}
else
{
*realsize = 0;
return NULL;
}
} }
else else
return pcmbuf_request_buffer(length, realsize); return pcmbuf_request_buffer(length, realsize);
@ -787,7 +798,7 @@ bool pcmbuf_is_crossfade_active(void)
void pcmbuf_write_complete(size_t length) void pcmbuf_write_complete(size_t length)
{ {
if (crossfade_active) if (crossfade_active)
flush_crossfade(guardbuf, length); flush_crossfade(fadebuf, length);
else else
{ {
audiobuffer_free -= length; 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 */ /* Get a pointer to where to mix immediate audio */
static inline short* get_mix_insert_pos(void) { static inline short* get_mix_insert_buf(void) {
/* Give at least 1/8s clearance here */ if (pcmbuf_read->link)
size_t pcmbuf_mix_back_pos = {
pcmbuf_unplayed_bytes - NATIVE_FREQUENCY * 4 / 8; /* Get the next chunk */
char *pcmbuf_mix_buf = pcmbuf_read->link->addr;
if (audiobuffer_pos < pcmbuf_mix_back_pos) /* Give at least 1/8s clearance. TODO: Check size here? */
return (short *)&audiobuffer[pcmbuf_size + return (short *)&pcmbuf_mix_buf[NATIVE_FREQUENCY * 4 / 8];
audiobuffer_pos - pcmbuf_mix_back_pos]; }
else return NULL;
return (short *)&audiobuffer[audiobuffer_pos - pcmbuf_mix_back_pos];
} }
/* Generates a constant square wave sound with a given frequency /* 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; unsigned int interval = NATIVE_FREQUENCY / frequency;
long sample; long sample;
short *buf; short *buf;
short *pcmbuf_end = (short *)guardbuf; short *pcmbuf_end = (short *)fadebuf;
size_t samples = NATIVE_FREQUENCY / 1000 * duration; size_t samples = NATIVE_FREQUENCY / 1000 * duration;
if (pcm_is_playing()) if (pcm_is_playing())
{ {
buf = get_mix_insert_pos(); buf = get_mix_insert_buf();
while (i++ < samples) while (i++ < samples)
{ {
sample = *buf; sample = *buf;
@ -888,35 +899,56 @@ int pcmbuf_usage(void)
return pcmbuf_unplayed_bytes * 100 / pcmbuf_size; 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(); short *ibuf = (short *)voicebuf;
pcmbuf_mix_used_bytes = 0; short *obuf;
} size_t chunk_samples;
void pcmbuf_mix(char *buf, size_t length) if (!pcmbuf_mix_chunk && pcmbuf_read)
{ {
short *ibuf = (short *)buf; pcmbuf_mix_chunk = pcmbuf_read->link;
short *pcmbuf_end = (short *)guardbuf; /* 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) obuf = (short *)pcmbuf_mix_chunk->addr;
pcmbuf_reset_mixpos(); chunk_samples = pcmbuf_mix_chunk->size / 2;
pcmbuf_mix_used_bytes += length;
length /= 2; length /= 2;
while (length-- > 0) { while (length-- > 0) {
long sample = *ibuf++; long sample = *ibuf++;
sample += *mixpos >> 2; if (pcmbuf_mix_sample >= chunk_samples)
*mixpos++ = MIN(MAX(sample, -32768), 32767); {
pcmbuf_mix_chunk = pcmbuf_mix_chunk->link;
if (mixpos >= pcmbuf_end) if (!pcmbuf_mix_chunk)
mixpos = (short *)audiobuffer; 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);
} }
} }

View file

@ -27,7 +27,7 @@
non-fatal) */ non-fatal) */
#define PCMBUF_MIN_CHUNK 4096 /* We try to never feed a chunk smaller than #define PCMBUF_MIN_CHUNK 4096 /* We try to never feed a chunk smaller than
this to the DMA */ 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) */ for mixing (crossfade or voice) */
/* Returns true if the buffer needs to change size */ /* 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); void pcmbuf_crossfade_enable(bool on_off);
int pcmbuf_usage(void); 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_beep(unsigned int frequency, size_t duration, int amplitude);
void pcmbuf_reset_mixpos(void); void pcmbuf_mix_voice(size_t length);
void pcmbuf_mix(char *buf, size_t length);
int pcmbuf_used_descs(void); int pcmbuf_used_descs(void);
int pcmbuf_descs(void); int pcmbuf_descs(void);

File diff suppressed because it is too large Load diff

View file

@ -629,11 +629,6 @@ void mp3_shutdown(void)
/* a dummy */ /* a dummy */
} }
void mp3_play_stop(void)
{
/* a dummy */
}
void mp3_play_pause(bool play) void mp3_play_pause(bool play)
{ {
/* a dummy */ /* a dummy */