From 6d6ca6b6a5641a0ab3657e60a1770a440cc52493 Mon Sep 17 00:00:00 2001 From: Miika Pekkarinen Date: Sun, 22 Jan 2006 10:25:07 +0000 Subject: Muting trick to prevent tiny pops and glitchless mp3 seeking. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8416 a1c6a512-1295-4272-9138-f99709370657 --- apps/codecs/mpa.c | 35 ++++++++++++++++++----------------- apps/pcmbuf.c | 31 ++++++++++++++++++++++++++++--- apps/playback.c | 8 +++----- firmware/export/pcm_playback.h | 1 + firmware/pcm_playback.c | 24 ++++++++++++------------ 5 files changed, 62 insertions(+), 37 deletions(-) diff --git a/apps/codecs/mpa.c b/apps/codecs/mpa.c index 2c946f3f0d..1be6222ccf 100644 --- a/apps/codecs/mpa.c +++ b/apps/codecs/mpa.c @@ -72,6 +72,22 @@ void recalc_samplecount(void) samplecount -= start_skip + stop_skip; } +void init_mad(void) +{ + ci->memset(&stream, 0, sizeof(struct mad_stream)); + ci->memset(&frame, 0, sizeof(struct mad_frame)); + ci->memset(&synth, 0, sizeof(struct mad_synth)); + + mad_stream_init(&stream); + mad_frame_init(&frame); + mad_synth_init(&synth); + + /* We do this so libmad doesn't try to call codec_calloc() */ + ci->memset(mad_frame_overlap, 0, sizeof(mad_frame_overlap)); + frame.overlap = &mad_frame_overlap; + stream.main_data = &mad_main_data; +} + /* this is the codec entry point */ enum codec_status codec_start(struct codec_api *api) { @@ -107,18 +123,7 @@ enum codec_status codec_start(struct codec_api *api) * Reinitializing seems to be necessary to avoid playback quircks when seeking. */ next_track: - ci->memset(&stream, 0, sizeof(struct mad_stream)); - ci->memset(&frame, 0, sizeof(struct mad_frame)); - ci->memset(&synth, 0, sizeof(struct mad_synth)); - - mad_stream_init(&stream); - mad_frame_init(&frame); - mad_synth_init(&synth); - - /* We do this so libmad doesn't try to call codec_calloc() */ - ci->memset(mad_frame_overlap, 0, sizeof(mad_frame_overlap)); - frame.overlap = &mad_frame_overlap; - stream.main_data = &mad_main_data; + init_mad(); file_end = 0; while (!*ci->taginfo_ready && !ci->stop_codec) @@ -168,11 +173,7 @@ enum codec_status codec_start(struct codec_api *api) if (!ci->seek_buffer(newpos)) goto next_track; ci->seek_complete(); - if (newpos == 0) - { - ci->id3->elapsed = 0; - goto next_track; - } + init_mad(); } /* Lock buffers */ diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index fc58d9ccb3..e21f735bbb 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c @@ -60,6 +60,8 @@ static bool crossfade_init; static int crossfade_pos; static int crossfade_rem; +static struct mutex pcmbuf_mutex; + /* Crossfade modes. If CFM_CROSSFADE is selected, normal * crossfader will activate. Selecting CFM_FLUSH is a special * operation that only overwrites the pcm buffer without crossfading. @@ -252,7 +254,14 @@ bool pcmbuf_crossfade_init(void) void pcmbuf_play_stop(void) { + mutex_lock(&pcmbuf_mutex); + + /** Prevent a very tiny pop from happening by muting audio + * until dma has been initialized. */ + pcm_mute(true); pcm_play_stop(); + pcm_mute(false); + last_chunksize = 0; pcmbuf_unplayed_bytes = 0; pcmbuf_mix_used_bytes = 0; @@ -266,11 +275,13 @@ void pcmbuf_play_stop(void) pcmbuf_set_boost_mode(false); pcmbuf_boost(false); - + + mutex_unlock(&pcmbuf_mutex); } void pcmbuf_init(long bufsize) { + mutex_init(&pcmbuf_mutex); pcmbuf_size = bufsize; audiobuffer = (char *)&audiobuf[(audiobufend - audiobuf) - pcmbuf_size - PCMBUF_GUARD]; @@ -304,7 +315,16 @@ void pcmbuf_flush_audio(void) void pcmbuf_play_start(void) { if (!pcm_is_playing() && pcmbuf_unplayed_bytes) + { + /** Prevent a very tiny pop from happening by muting audio + * until dma has been initialized. */ + pcm_mute(true); + pcm_play_data(pcmbuf_callback); + + /* Now unmute the audio. */ + pcm_mute(false); + } } /** @@ -314,6 +334,8 @@ void pcmbuf_flush_fillpos(void) { int copy_n; + mutex_lock(&pcmbuf_mutex); + copy_n = MIN(audiobuffer_fillpos, CHUNK_SIZE); if (copy_n) { @@ -324,7 +346,8 @@ void pcmbuf_flush_fillpos(void) /* This is a fatal error situation that should never happen. */ if (!pcm_is_playing()) { logf("pcm_flush_fillpos error"); - pcm_play_data(pcmbuf_callback); + pcmbuf_play_start(); + mutex_unlock(&pcmbuf_mutex); return ; } } @@ -336,6 +359,8 @@ void pcmbuf_flush_fillpos(void) audiobuffer_free -= copy_n; audiobuffer_fillpos -= copy_n; } + + mutex_unlock(&pcmbuf_mutex); } /** @@ -576,7 +601,7 @@ static bool prepare_insert(long length) crossfade_active = false; if (audiobuffer_free < pcmbuf_size - CHUNK_SIZE*4) { logf("pcm starting"); - pcm_play_data(pcmbuf_callback); + pcmbuf_play_start(); } } diff --git a/apps/playback.c b/apps/playback.c index 77a199bd81..779fd97bde 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -294,8 +294,6 @@ bool codec_pcmbuf_insert_split_callback(void *ch1, void *ch2, while (paused) { - if (pcm_is_playing()) - pcm_play_pause(false); sleep(1); if (ci.stop_codec || ci.reload_codec || ci.seek_time) return true; @@ -1845,15 +1843,15 @@ void audio_thread(void) case AUDIO_PAUSE: logf("audio_pause"); - /* We will pause the pcm playback in audiobuffer insert function - to prevent a loop inside the pcm buffer. */ - // pcm_play_pause(false); + pcm_mute(true); + pcm_play_pause(false); paused = true; break ; case AUDIO_RESUME: logf("audio_resume"); pcm_play_pause(true); + pcm_mute(false); paused = false; break ; diff --git a/firmware/export/pcm_playback.h b/firmware/export/pcm_playback.h index 3972e45768..5b61beb34d 100644 --- a/firmware/export/pcm_playback.h +++ b/firmware/export/pcm_playback.h @@ -29,6 +29,7 @@ void pcm_calculate_peaks(int *left, int *right); long pcm_get_bytes_waiting(void); void pcm_play_stop(void); +void pcm_mute(bool mute); void pcm_play_pause(bool play); bool pcm_is_paused(void); bool pcm_is_playing(void); diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c index 6a190e4d23..ccac7843ad 100644 --- a/firmware/pcm_playback.c +++ b/firmware/pcm_playback.c @@ -75,11 +75,6 @@ static void dma_start(const void *addr, long size) EBU1CONFIG = IIS_RESET | EBU_DEFPARM; #endif - /** Prevent a very tiny pop from happening by muting audio - * until dma has been initialized. */ - uda1380_mute(true); - sleep(HZ/16); - /* Set up DMA transfer */ SAR0 = ((unsigned long)addr); /* Source address */ DAR0 = (unsigned long)&PDOR3; /* Destination address */ @@ -92,9 +87,6 @@ static void dma_start(const void *addr, long size) EBU1CONFIG = EBU_DEFPARM; #endif DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_SINC | DMA_START; - - /* Now unmute the audio. */ - uda1380_mute(false); } /* Stops the DMA transfer and interrupt */ @@ -220,14 +212,17 @@ long pcm_get_bytes_waiting(void) return next_size + (BCR0 & 0xffffff); } +void pcm_mute(bool mute) +{ + uda1380_mute(mute); + if (mute) + sleep(HZ/16); +} + void pcm_play_stop(void) { if (pcm_playing) { - /* Same muting trick here to prevent a tiny pop. */ - uda1380_mute(true); - sleep(HZ/16); dma_stop(); - uda1380_mute(false); } } @@ -465,6 +460,11 @@ void pcm_play_stop(void) } } +void pcm_mute(bool mute) +{ + (void)mute; +} + void pcm_play_pause(bool play) { if(pcm_paused && play && next_size) -- cgit v1.2.3