From 0e159f13cf4562cf17d0a2edd16bfd3b665c8473 Mon Sep 17 00:00:00 2001 From: Miika Pekkarinen Date: Fri, 20 Jan 2006 22:02:44 +0000 Subject: Fixed a few iriver playback quirks and issues with previous fixes. Also fixed "TST.." bug when seeking and possible an enhancement to mp3 gapless playback also. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8402 a1c6a512-1295-4272-9138-f99709370657 --- apps/codecs/mpa.c | 25 ++++++++---- apps/pcmbuf.c | 3 +- apps/playback.c | 100 +++++++++++++++++++++++++++++++++--------------- firmware/pcm_playback.c | 3 ++ 4 files changed, 91 insertions(+), 40 deletions(-) diff --git a/apps/codecs/mpa.c b/apps/codecs/mpa.c index 3ee2b352f1..2c946f3f0d 100644 --- a/apps/codecs/mpa.c +++ b/apps/codecs/mpa.c @@ -101,6 +101,12 @@ enum codec_status codec_start(struct codec_api *api) ci->configure(DSP_SET_CLIP_MAX, (int *)(MAD_F_ONE - 1)); ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*16)); + /** This label might need to be moved above all the init code, but I don't + * think reiniting the codec is necessary for MPEG. It might even be unwanted + * for gapless playback. + * 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)); @@ -114,10 +120,6 @@ enum codec_status codec_start(struct codec_api *api) frame.overlap = &mad_frame_overlap; stream.main_data = &mad_main_data; - /* This label might need to be moved above all the init code, but I don't - think reiniting the codec is necessary for MPEG. It might even be unwanted - for gapless playback */ -next_track: file_end = 0; while (!*ci->taginfo_ready && !ci->stop_codec) ci->sleep(1); @@ -156,14 +158,21 @@ next_track: samplesdone = ((int64_t) (ci->seek_time - 1)) * current_frequency / 1000; - newpos = ci->mp3_get_filepos(ci->seek_time-1) + - ci->id3->first_frame_offset; + + if (ci->seek_time-1 == 0) + newpos = 0; + else + newpos = ci->mp3_get_filepos(ci->seek_time-1) + + ci->id3->first_frame_offset; if (!ci->seek_buffer(newpos)) goto next_track; - if (newpos == 0) - samples_to_skip = start_skip; ci->seek_complete(); + if (newpos == 0) + { + ci->id3->elapsed = 0; + goto next_track; + } } /* Lock buffers */ diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index f1988fd3f4..66dd47eb3d 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c @@ -229,7 +229,8 @@ bool pcmbuf_is_lowdata(void) bool pcmbuf_crossfade_init(void) { - if (pcmbuf_size - audiobuffer_free < CHUNK_SIZE * 8 || !crossfade_enabled + if (pcmbuf_size - audiobuffer_free < CHUNK_SIZE * 8 + || !pcmbuf_is_crossfade_enabled() || crossfade_active || crossfade_init) { pcmbuf_flush_audio(); return false; diff --git a/apps/playback.c b/apps/playback.c index ff2f9d58cc..3da4b6fbdb 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -653,7 +653,7 @@ void codec_seek_complete_callback(void) { /* assume we're called from non-voice codec, as they shouldn't seek */ ci.seek_time = 0; - pcmbuf_flush_audio(); + pcmbuf_play_stop(); } bool codec_seek_buffer_callback(off_t newpos) @@ -1288,6 +1288,15 @@ static void audio_clear_track_entries(bool buffered_only) } } +static void stop_codec_flush(void) +{ + ci.stop_codec = true; + pcmbuf_play_stop(); + while (audio_codec_loaded) + yield(); + pcmbuf_play_stop(); +} + static void audio_stop_playback(bool resume) { logf("stop_playback:%d", resume); @@ -1296,14 +1305,11 @@ static void audio_stop_playback(bool resume) playlist_update_resume_info(resume ? audio_current_track() : NULL); playing = false; filling = false; - ci.stop_codec = true; + stop_codec_flush(); if (current_fd >= 0) { close(current_fd); current_fd = -1; } - pcmbuf_play_stop(); - while (audio_codec_loaded) - yield(); track_count = 0; /* Mark all entries null. */ @@ -1478,16 +1484,26 @@ static void audio_update_trackinfo(void) ci.curpos = 0; cur_ti->start_pos = 0; ci.taginfo_ready = (bool *)&cur_ti->taginfo_ready; - if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()) { + + /* Manual track change (always crossfade or flush audio). */ + if (new_track) + { pcmbuf_crossfade_init(); codec_track_changed(); - } else { - pcmbuf_add_event(codec_track_changed); } - /* Manual track change. */ - if (new_track) + /* Automatic track change with crossfade. */ + else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()) + { + pcmbuf_crossfade_init(); codec_track_changed(); + } + + /* Gapless playback. */ + else + { + pcmbuf_add_event(codec_track_changed); + } } enum { @@ -1497,7 +1513,7 @@ enum { }; /* Should handle all situations. */ -static int skip_next_track(void) +static int skip_next_track(bool inside_codec_thread) { logf("skip next"); /* Manual track skipping. */ @@ -1529,10 +1545,16 @@ static int skip_next_track(void) ci.reload_codec = true; /* Stop playback if manual track change. */ if (new_track != 0 && !pcmbuf_is_crossfade_enabled()) - pcmbuf_play_stop(); + { + if (inside_codec_thread) + pcmbuf_play_stop(); + else + stop_codec_flush(); + } + else if (pcmbuf_is_crossfade_enabled()) + pcmbuf_crossfade_init(); - /* Don't flush buffer */ - queue_post(&audio_queue, AUDIO_PLAY, (bool *)false); + queue_post(&audio_queue, AUDIO_PLAY, 0); return SKIP_OK_DISK; } @@ -1552,7 +1574,7 @@ static int skip_next_track(void) return SKIP_OK_RAM; } -static int skip_previous_track(void) +static int skip_previous_track(bool inside_codec_thread) { logf("skip previous"); last_peek_offset++; @@ -1566,10 +1588,14 @@ static int skip_previous_track(void) ci.reload_codec = true; /* Stop playback. */ /* FIXME: Only stop playback if disk is not spinning! */ - if (!pcmbuf_is_crossfade_enabled()) + if (pcmbuf_is_crossfade_enabled()) + pcmbuf_crossfade_init(); + else if (inside_codec_thread) pcmbuf_play_stop(); + else + stop_codec_flush(); - queue_post(&audio_queue, AUDIO_PLAY, (bool *)true); + queue_post(&audio_queue, AUDIO_PLAY, 0); return SKIP_OK_DISK; } @@ -1583,6 +1609,7 @@ static int skip_previous_track(void) cur_ti->available = cur_ti->filesize; if (buf_ridx < 0) buf_ridx += filebuflen; + audio_update_trackinfo(); return SKIP_OK_RAM; @@ -1595,7 +1622,7 @@ static void audio_change_track(void) if (!ci.reload_codec) { - if (skip_next_track() == SKIP_FAIL) + if (skip_next_track(false) == SKIP_FAIL) { logf("No more tracks"); while (pcm_is_playing()) @@ -1607,8 +1634,8 @@ static void audio_change_track(void) ci.reload_codec = false; /* Needed for fast skipping. */ - //if (cur_ti->codecsize > 0) - // queue_post(&codec_queue, CODEC_LOAD, 0); + if (cur_ti->codecsize > 0) + queue_post(&codec_queue, CODEC_LOAD, 0); } bool codec_request_next_track_callback(void) @@ -1629,13 +1656,13 @@ bool codec_request_next_track_callback(void) /* Advance to next track. */ if (new_track >= 0 || !ci.reload_codec) { - if (skip_next_track() != SKIP_OK_RAM) + if (skip_next_track(true) != SKIP_OK_RAM) return false; } /* Advance to previous track. */ else { - if (skip_previous_track() != SKIP_OK_RAM) + if (skip_previous_track(true) != SKIP_OK_RAM) return false; } @@ -1654,7 +1681,7 @@ bool codec_request_next_track_callback(void) if (cur_ti->codecsize == 0) { logf("Loading from disk [2]..."); - queue_post(&audio_queue, AUDIO_PLAY, (bool *)(new_track != 0)); + queue_post(&audio_queue, AUDIO_PLAY, 0); } else ci.reload_codec = true; @@ -1692,12 +1719,15 @@ static void initiate_track_change(int peek_index) { /* Detect if disk is spinning or already loading. */ if (filling || ci.reload_codec || !audio_codec_loaded) { - queue_post(&audio_queue, AUDIO_PLAY, (bool *)true); + if (pcmbuf_is_crossfade_enabled()) + pcmbuf_crossfade_init(); + else + pcmbuf_play_stop(); + ci.stop_codec = true; + queue_post(&audio_queue, AUDIO_PLAY, 0); } else { new_track = peek_index; ci.reload_codec = true; - if (!pcmbuf_is_crossfade_enabled()) - pcmbuf_flush_audio(); } codec_track_changed(); @@ -1771,14 +1801,10 @@ void audio_thread(void) ci.reload_codec = false; ci.seek_time = 0; - /* Only flush audio if it has been requested. */ - if ((bool)ev.data) - pcmbuf_crossfade_init(); - while (audio_codec_loaded) yield(); + audio_play_start((int)ev.data); - playlist_update_resume_info(audio_current_track()); /* If there are no tracks in the playlist, then the playlist @@ -2091,6 +2117,18 @@ bool audio_has_changed_track(void) void audio_play(int offset) { logf("audio_play"); + if (pcmbuf_is_crossfade_enabled()) + { + ci.stop_codec = true; + sleep(1); + pcmbuf_crossfade_init(); + } + else + { + stop_codec_flush(); + pcmbuf_play_stop(); + } + queue_post(&audio_queue, AUDIO_PLAY, (void *)offset); } diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c index 62a48b5855..fe71fa3862 100644 --- a/firmware/pcm_playback.c +++ b/firmware/pcm_playback.c @@ -221,6 +221,9 @@ void pcm_play_stop(void) void pcm_play_pause(bool play) { + if (!pcm_playing) + return ; + if(pcm_paused && play && next_size) { logf("unpause"); -- cgit v1.2.3