From 431e813532d9d690ea1b0cf4d1b9e98aa896d331 Mon Sep 17 00:00:00 2001 From: Miika Pekkarinen Date: Sun, 19 Jun 2005 18:41:53 +0000 Subject: [PATCH] Some re-desing to buffer filling and track loading code and a few bug fixes. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6766 a1c6a512-1295-4272-9138-f99709370657 --- apps/playback.c | 207 +++++++++++++++++++++------------------- firmware/pcm_playback.c | 30 +++--- 2 files changed, 124 insertions(+), 113 deletions(-) diff --git a/apps/playback.c b/apps/playback.c index f4ec05b369..c6128ca007 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -71,6 +71,7 @@ static volatile bool paused; #define CODEC_MPC "/.rockbox/codecs/codecmpc.rock"; #define CODEC_WAVPACK "/.rockbox/codecs/codecwavpack.rock"; +#define AUDIO_FILL_CYCLE (1024*256) #define AUDIO_DEFAULT_WATERMARK (1024*256) #define AUDIO_DEFAULT_FILECHUNK (1024*32) @@ -84,6 +85,7 @@ static volatile bool paused; #define AUDIO_FLUSH_RELOAD 8 #define AUDIO_CODEC_DONE 9 #define AUDIO_FLUSH 10 +#define AUDIO_TRACK_CHANGED 11 #define CODEC_LOAD 1 #define CODEC_LOAD_DISK 2 @@ -125,6 +127,8 @@ static volatile int codecbufused; static volatile int buf_ridx; static volatile int buf_widx; +static int last_peek_offset; + /* Track information (count in file buffer, read/write indexes for track ring structure. */ static int track_count; @@ -424,6 +428,7 @@ void codec_configure_callback(int setting, void *value) void codec_track_changed(void) { track_changed = true; + // queue_post(&audio_queue, AUDIO_TRACK_CHANGED, 0); } void yield_codecs(void) @@ -438,25 +443,22 @@ void yield_codecs(void) void audio_fill_file_buffer(void) { - size_t i; + size_t i, size; int rc; - tracks[track_widx].start_pos = ci.curpos; - logf("Filling buffer..."); + if (current_fd < 0) + return ; + i = 0; - while ((off_t)i < tracks[track_widx].filerem) { + size = MIN(tracks[track_widx].filerem, AUDIO_FILL_CYCLE); + while (i < size) { /* Give codecs some processing time. */ yield_codecs(); - if (!queue_empty(&audio_queue)) { - logf("Filling interrupted"); - return ; - } - - if (fill_bytesleft < MIN((unsigned int)conf_filechunk, - tracks[track_widx].filerem - i)) + if (fill_bytesleft == 0) break ; rc = MIN(conf_filechunk, codecbuflen - buf_widx); + rc = MIN(rc, (off_t)fill_bytesleft); rc = read(current_fd, &codecbuf[buf_widx], rc); if (rc <= 0) { tracks[track_widx].filerem = 0; @@ -474,7 +476,8 @@ void audio_fill_file_buffer(void) codecbufused += i; tracks[track_widx].filerem -= i; tracks[track_widx].filepos += i; - logf("Done:%d", tracks[track_widx].available); + /*logf("Filled:%d/%d", tracks[track_widx].available, + tracks[track_widx].filerem);*/ if (tracks[track_widx].filerem == 0) { close(current_fd); current_fd = -1; @@ -569,6 +572,7 @@ bool loadcodec(const char *trackname, bool start_play) size = filesize(fd); if ((off_t)fill_bytesleft < size + conf_watermark) { logf("Not enough space"); + fill_bytesleft = 0; close(fd); return false; } @@ -576,11 +580,6 @@ bool loadcodec(const char *trackname, bool start_play) i = 0; while (i < size) { yield_codecs(); - if (!queue_empty(&audio_queue)) { - logf("Buffering interrupted"); - close(fd); - return false; - } copy_n = MIN(conf_filechunk, codecbuflen - buf_widx); rc = read(fd, &codecbuf[buf_widx], copy_n); @@ -609,7 +608,8 @@ bool audio_load_track(int offset, bool start_play, int peek_offset) int rc, i; int copy_n; - if (track_count >= MAX_TRACK) + if (track_count >= MAX_TRACK || tracks[track_widx].filesize != 0 + || current_fd >= 0) return false; trackname = playlist_peek(peek_offset); @@ -653,13 +653,6 @@ bool audio_load_track(int offset, bool start_play, int peek_offset) //logf("%s", trackname); logf("Buffering track:%d/%d", track_widx, track_ridx); - if (!queue_empty(&audio_queue)) { - logf("Interrupted!"); - //ci.stop_codec = true; - close(fd); - return false; - } - if (!get_metadata(&tracks[track_widx],fd,trackname,v1first)) { close(fd); return false; @@ -685,22 +678,11 @@ bool audio_load_track(int offset, bool start_play, int peek_offset) } i = tracks[track_widx].start_pos; + size = MIN(size, AUDIO_FILL_CYCLE); while (i < size) { /* Give codecs some processing time to prevent glitches. */ yield_codecs(); - /* Limit buffering size at first run. */ - if (conf_bufferlimit && (int)fill_bytesleft >= conf_bufferlimit) { - fill_bytesleft = conf_bufferlimit; - conf_bufferlimit = 0; - } - - if (!queue_empty(&audio_queue)) { - logf("Buffering interrupted"); - close(fd); - return false; - } - if (fill_bytesleft == 0) break ; @@ -737,7 +719,6 @@ bool audio_load_track(int offset, bool start_play, int peek_offset) if (tracks[track_widx].filerem != 0) { current_fd = fd; logf("Partially buf:%d", tracks[track_widx].available); - return false; } else { logf("Completely buf."); close(fd); @@ -750,20 +731,13 @@ bool audio_load_track(int offset, bool start_play, int peek_offset) return true; } -void audio_insert_tracks(int offset, bool start_playing, int peek_offset) -{ - fill_bytesleft = codecbuflen - codecbufused; - filling = true; - while (audio_load_track(offset, start_playing, peek_offset)) { - start_playing = false; - offset = 0; - peek_offset++; - } - filling = false; -} - void audio_play_start(int offset) { + if (current_fd >= 0) { + close(current_fd); + current_fd = -1; + } + memset(&tracks, 0, sizeof(struct track_info) * MAX_TRACK); sound_set(SOUND_VOLUME, global_settings.volume); track_count = 0; @@ -773,9 +747,17 @@ void audio_play_start(int offset) buf_widx = 0; codecbufused = 0; pcm_set_boost_mode(true); - audio_insert_tracks(offset, true, 0); + + fill_bytesleft = codecbuflen; + filling = true; + last_peek_offset = 0; + if (audio_load_track(offset, true, 0)) { + last_peek_offset++; + ata_sleep(); + } else { + logf("Failure"); + } pcm_set_boost_mode(false); - ata_sleep(); } void audio_clear_track_entries(void) @@ -791,25 +773,14 @@ void audio_clear_track_entries(void) } } -void audio_check_buffer(void) +void initialize_buffer_fill(void) { - int i; - int cur_idx; + int cur_idx, i; - /* Fill buffer as full as possible for cross-fader. */ - if (pcm_is_crossfade_enabled() && cur_ti->id3.length > 0 - && cur_ti->id3.length - cur_ti->id3.elapsed < 20000 && playing) - pcm_set_boost_mode(true); - - /* Start buffer filling as necessary. */ - if (codecbufused > conf_watermark || !queue_empty(&audio_queue) - || !playing || ci.stop_codec || ci.reload_codec) - return ; - - filling = true; pcm_set_boost_mode(true); fill_bytesleft = codecbuflen - codecbufused; + tracks[track_widx].start_pos = ci.curpos; /* Calculate real track count after throwing away old tracks. */ cur_idx = track_ridx; @@ -827,6 +798,30 @@ void audio_check_buffer(void) /* Mark all other entries null. */ audio_clear_track_entries(); +} + +void audio_check_buffer(void) +{ + /* Fill buffer as full as possible for cross-fader. */ + if (pcm_is_crossfade_enabled() && cur_ti->id3.length > 0 + && cur_ti->id3.length - cur_ti->id3.elapsed < 20000 && playing) + pcm_set_boost_mode(true); + + /* Start buffer filling as necessary. */ + if ((codecbufused > conf_watermark || !queue_empty(&audio_queue) + || !playing || ci.stop_codec || ci.reload_codec) && !filling) + return ; + + if (!filling) { + initialize_buffer_fill(); + filling = true; + } + + /* Limit buffering size at first run. */ + if (conf_bufferlimit && (int)fill_bytesleft >= conf_bufferlimit) { + fill_bytesleft = conf_bufferlimit; + conf_bufferlimit = 0; + } /* Try to load remainings of the file. */ if (tracks[track_widx].filerem > 0) @@ -836,18 +831,17 @@ void audio_check_buffer(void) if (tracks[track_widx].filerem == 0 && tracks[track_widx].filesize != 0) { if (++track_widx == MAX_TRACK) track_widx = 0; - logf("new ti: %d", track_widx); } - logf("ti: %d", track_widx); /* Load new files to fill the entire buffer. */ - if (tracks[track_widx].filerem == 0) - audio_insert_tracks(0, false, 1); - - pcm_set_boost_mode(false); - if (playing) - ata_sleep(); - filling = false; + if (audio_load_track(0, false, last_peek_offset)) { + last_peek_offset++; + } else if (tracks[track_widx].filerem == 0 || fill_bytesleft == 0) { + filling = false; + pcm_set_boost_mode(false); + if (playing) + ata_sleep(); + } } void audio_update_trackinfo(void) @@ -890,6 +884,7 @@ void audio_update_trackinfo(void) void audio_change_track(void) { + logf("change track"); if (track_ridx == track_widx) { logf("No more tracks"); while (pcm_is_playing()) @@ -914,6 +909,9 @@ bool codec_request_next_track_callback(void) /* Advance to next track. */ if (ci.reload_codec && new_track > 0) { + last_peek_offset--; + if (!playlist_check(1)) + return false; playlist_next(1); if (++track_ridx == MAX_TRACK) track_ridx = 0; @@ -927,6 +925,9 @@ bool codec_request_next_track_callback(void) /* Advance to previous track. */ else if (ci.reload_codec && new_track < 0) { + last_peek_offset++; + if (!playlist_check(-1)) + return false; playlist_next(-1); if (--track_ridx < 0) track_ridx = MAX_TRACK-1; @@ -942,6 +943,9 @@ bool codec_request_next_track_callback(void) /* Codec requested track change (next track). */ else { + last_peek_offset--; + if (!playlist_check(1)) + return false; playlist_next(1); if (++track_ridx >= MAX_TRACK) track_ridx = 0; @@ -992,19 +996,28 @@ void audio_thread(void) struct event ev; while (1) { + yield_codecs(); audio_check_buffer(); - queue_wait_w_tmo(&audio_queue, &ev, 100); + queue_wait_w_tmo(&audio_queue, &ev, 0); switch (ev.id) { case AUDIO_PLAY: + logf("starting..."); ci.stop_codec = true; ci.reload_codec = false; ci.seek_time = 0; - pcm_play_stop(); + //pcm_play_stop(); audio_play_start((int)ev.data); break ; case AUDIO_STOP: paused = false; + filling = false; + playing = false; + ci.stop_codec = true; + if (current_fd >= 0) { + close(current_fd); + current_fd = -1; + } pcm_play_stop(); pcm_play_pause(true); break ; @@ -1022,6 +1035,9 @@ void audio_thread(void) audio_invalidate_tracks(); break ; + case AUDIO_TRACK_CHANGED: + break ; + case AUDIO_CODEC_DONE: //if (playing) // audio_change_track(); @@ -1156,15 +1172,7 @@ void audio_play(int offset) void audio_stop(void) { logf("audio_stop"); - playing = false; - paused = false; - ci.stop_codec = true; - if (current_fd >= 0) { - close(current_fd); - current_fd = -1; - } queue_post(&audio_queue, AUDIO_STOP, 0); - pcm_play_pause(true); } void audio_pause(void) @@ -1183,37 +1191,36 @@ void audio_resume(void) //queue_post(&audio_queue, AUDIO_RESUME, 0); } -void audio_next(void) +static void initiate_track_change(int peek_index) { - logf("audio_next"); - new_track = 1; + if (!playlist_check(peek_index)) + return ; + + new_track = peek_index; ci.reload_codec = true; /* Detect if disk is spinning.. */ if (filling) { ci.stop_codec = true; - playlist_next(1); + playlist_next(peek_index); queue_post(&audio_queue, AUDIO_PLAY, 0); } else if (!pcm_crossfade_start()) { - pcm_play_stop(); + //pcm_play_stop(); } } +void audio_next(void) +{ + logf("audio_next"); + initiate_track_change(1); +} + void audio_prev(void) { logf("audio_prev"); - new_track = -1; - ci.reload_codec = true; - pcm_play_stop(); - - if (filling) { - ci.stop_codec = true; - playlist_next(-1); - queue_post(&audio_queue, AUDIO_PLAY, 0); - } - //queue_post(&audio_queue, AUDIO_PREV, 0); + initiate_track_change(-1); } void audio_ff_rewind(int newpos) diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c index 0ab3d0272f..da7f06fa29 100644 --- a/firmware/pcm_playback.c +++ b/firmware/pcm_playback.c @@ -27,6 +27,7 @@ #include "uda1380.h" #include "system.h" #endif +#include "logf.h" #include #include @@ -225,6 +226,7 @@ void pcm_play_stop(void) if (pcm_playing) { uda1380_enable_output(false); pcm_boost(false); + sleep(HZ/16); dma_stop(); } pcmbuf_unplayed_bytes = 0; @@ -384,36 +386,38 @@ bool pcm_is_lowdata(void) bool pcm_crossfade_start(void) { - //logf("cf:%d", audiobuffer_free / CHUNK_SIZE); - if (audiobuffer_free > CHUNK_SIZE * 4 || !crossfade_enabled) { + if (PCMBUF_SIZE - audiobuffer_free < CHUNK_SIZE * 4 || !crossfade_enabled) { return false; } + logf("crossfading!"); pcm_boost(true); crossfade_active = true; crossfade_pos = audiobuffer_pos; - crossfade_amount = (PCMBUF_SIZE - audiobuffer_free - CHUNK_SIZE * 22)/2; + crossfade_amount = (PCMBUF_SIZE - audiobuffer_free - (CHUNK_SIZE * 4))/2; crossfade_rem = crossfade_amount; audiobuffer_fillpos = 0; crossfade_pos -= crossfade_amount*2; if (crossfade_pos < 0) - crossfade_pos = PCMBUF_SIZE + crossfade_pos; + crossfade_pos += PCMBUF_SIZE; return true; } static __inline void crossfade(short *buf, const short *buf2, int length) { - while (length--) { - *buf = (int)((*buf * ((crossfade_rem)*1000/crossfade_amount))/1000); - *buf += (int)((*buf2 * ((crossfade_amount-crossfade_rem)*1000/crossfade_amount))/1000); - buf++; - buf2++; - if (--crossfade_rem <= 0) { - crossfade_active = false; - break ; - } + int i, size; + + logf("cfi: %d/%d", length, crossfade_rem); + size = MIN(length, crossfade_rem); + for (i = 0; i < length; i++) { + /* This is not yet realtime, needs optimizations for crossfade to work. */ + buf[i] = ((buf[i] * ((crossfade_rem)*1000/crossfade_amount))/1000) + + ((buf2[i] * ((crossfade_amount-crossfade_rem)*1000/crossfade_amount))/1000); } + + if (--crossfade_rem <= 0) + crossfade_active = false; } bool audiobuffer_insert(char *buf, size_t length)