From b4bc106efbf0e7e51a5602fec8ac75dbab9bc969 Mon Sep 17 00:00:00 2001 From: Miika Pekkarinen Date: Thu, 9 Jun 2005 07:19:16 +0000 Subject: Fixed forward next track bugs (still some pause issues though). Added experimental cross-fader. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6632 a1c6a512-1295-4272-9138-f99709370657 --- apps/playback.c | 65 +++++++++++++++++++++++------------- apps/plugins/codecmpa.c | 1 + firmware/export/pcm_playback.h | 1 + firmware/pcm_playback.c | 76 +++++++++++++++++++++++++++++++++++++----- 4 files changed, 111 insertions(+), 32 deletions(-) diff --git a/apps/playback.c b/apps/playback.c index 3a9f229e15..c0c71a173d 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -68,7 +68,7 @@ static volatile bool paused; #define CODEC_WAV "/.rockbox/codecs/codecwav.rock"; #define AUDIO_WATERMARK 0x70000 -#define AUDIO_FILE_CHUNK (1024*256) +#define AUDIO_FILE_CHUNK (1024*512) #define AUDIO_PLAY 1 #define AUDIO_STOP 2 @@ -107,6 +107,9 @@ static const char codec_thread_name[] = "codec"; /* Is file buffer currently being refilled? */ static volatile bool filling; +/* Interrupts buffer filling. */ +static volatile bool interrupt; + /* Ring buffer where tracks and codecs are loaded. */ char *codecbuf; @@ -398,8 +401,8 @@ int probe_file_format(const char *filename) void yield_codecs(void) { -#ifndef SIMULATOR yield(); +#ifndef SIMULATOR if (!pcm_is_playing()) sleep(5); while (pcm_is_lowdata()) @@ -420,7 +423,7 @@ void audio_fill_file_buffer(void) /* Give codecs some processing time. */ yield_codecs(); - if (!playing) { + if (interrupt) { logf("Filling interrupted"); close(current_fd); current_fd = -1; @@ -540,7 +543,7 @@ bool loadcodec(const char *trackname, bool start_play) i = 0; while (i < size) { yield_codecs(); - if (!playing) { + if (interrupt) { logf("Buffering interrupted"); close(fd); return false; @@ -610,7 +613,7 @@ 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 (!playing) { + if (interrupt) { close(fd); return false; } @@ -717,7 +720,7 @@ bool audio_load_track(int offset, bool start_play, int peek_offset) while (i < size) { /* Give codecs some processing time to prevent glitches. */ yield_codecs(); - if (!playing) { + if (interrupt) { logf("Buffering interrupted"); close(fd); return false; @@ -803,8 +806,14 @@ void audio_check_buffer(void) int i; int cur_idx; + /* Fill buffer as full as possible for cross-fader. */ +#ifndef SIMULATOR + if (cur_ti->id3.length - cur_ti->id3.elapsed < 20000) + pcm_set_boost_mode(true); +#endif + /* Start buffer filling as necessary. */ - if (codecbufused > AUDIO_WATERMARK || !playing) + if (codecbufused > AUDIO_WATERMARK || !interrupt) return ; filling = true; @@ -863,6 +872,9 @@ void audio_update_trackinfo(void) buf_ridx += cur_ti->codecsize; if (buf_ridx >= codecbuflen) buf_ridx -= codecbuflen; + pcm_crossfade_start(); + if (!filling) + pcm_set_boost_mode(false); } else { buf_ridx -= ci.curpos; codecbufused += ci.curpos; @@ -978,14 +990,13 @@ void audio_thread(void) queue_wait_w_tmo(&audio_queue, &ev, 0); switch (ev.id) { case AUDIO_PLAY: + interrupt = false; ci.stop_codec = true; ci.reload_codec = false; ci.seek_time = 0; #ifndef SIMULATOR pcm_play_stop(); - pcm_play_pause(true); #endif - playing = true; paused = false; audio_play_start((int)ev.data); break ; @@ -993,8 +1004,8 @@ void audio_thread(void) case AUDIO_STOP: #ifndef SIMULATOR pcm_play_stop(); + pcm_play_pause(true); #endif - paused = false; break ; case AUDIO_PAUSE: @@ -1017,6 +1028,7 @@ void audio_thread(void) ci.stop_codec = true; logf("USB Connection"); pcm_play_stop(); + pcm_play_pause(true); usb_acknowledge(SYS_USB_CONNECTED_ACK); usb_wait_for_disconnect(&audio_queue); break ; @@ -1076,12 +1088,14 @@ void codec_thread(void) logf("Codec finished"); } - queue_post(&audio_queue, AUDIO_CODEC_DONE, (void *)status); if (playing && !ci.stop_codec && !ci.reload_codec) { audio_change_track(); + } else if (ci.reload_codec) { + interrupt = true; } else { playing = false; } + queue_post(&audio_queue, AUDIO_CODEC_DONE, (void *)status); } } } @@ -1129,17 +1143,17 @@ bool audio_has_changed_track(void) void audio_play(int offset) { logf("audio_play"); - playing = false; ci.stop_codec = true; + playing = false; +#ifndef SIMULATOR + pcm_play_pause(true); +#endif queue_post(&audio_queue, AUDIO_PLAY, (void *)offset); } void audio_stop(void) { logf("audio_stop"); - if (!playing) - return ; - playing = false; ci.stop_codec = true; if (current_fd) { @@ -1147,6 +1161,9 @@ void audio_stop(void) current_fd = -1; } queue_post(&audio_queue, AUDIO_STOP, 0); +#ifndef SIMULATOR + pcm_play_pause(true); +#endif } void audio_pause(void) @@ -1174,16 +1191,17 @@ void audio_next(void) logf("audio_next"); new_track = 1; ci.reload_codec = true; -#ifndef SIMULATOR - pcm_play_stop(); -#endif /* Detect if disk is spinning.. */ if (filling) { - playlist_next(1); - playing = false; + interrupt = true; ci.stop_codec = true; + playlist_next(1); queue_post(&audio_queue, AUDIO_PLAY, 0); + } else { +#ifndef SIMULATOR + pcm_play_stop(); +#endif } } @@ -1197,9 +1215,9 @@ void audio_prev(void) #endif if (filling) { - playlist_next(-1); - playing = false; + interrupt = true; ci.stop_codec = true; + playlist_next(-1); queue_post(&audio_queue, AUDIO_PLAY, 0); } //queue_post(&audio_queue, AUDIO_PREV, 0); @@ -1377,7 +1395,8 @@ void audio_init(void) - MALLOC_BUFSIZE - GUARD_BUFSIZE; //codecbuflen = 2*512*1024; codecbufused = 0; - filling = 0; + filling = false; + interrupt = false; codecbuf = &audiobuf[MALLOC_BUFSIZE]; playing = false; paused = false; diff --git a/apps/plugins/codecmpa.c b/apps/plugins/codecmpa.c index 1125b4bf18..46014127b8 100644 --- a/apps/plugins/codecmpa.c +++ b/apps/plugins/codecmpa.c @@ -381,6 +381,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm) /* Flush the buffer if it is full. */ if(OutputPtr==OutputBufferEnd) { + rb->yield(); #ifdef DEBUG_GAPLESS rb->write(fd, OutputBuffer, OUTPUT_BUFFER_SIZE); #endif diff --git a/firmware/export/pcm_playback.h b/firmware/export/pcm_playback.h index 3c29018394..d101c823ba 100644 --- a/firmware/export/pcm_playback.h +++ b/firmware/export/pcm_playback.h @@ -42,6 +42,7 @@ void pcm_play_set_watermark(int numbytes, void (*callback)(int bytes_left)); void pcm_set_boost_mode(bool state); bool pcm_is_lowdata(void); +void pcm_crossfade_start(void); unsigned int audiobuffer_get_latency(void); bool audiobuffer_insert(char *buf, size_t length); diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c index 99a71c2f41..ab4f0c0375 100644 --- a/firmware/pcm_playback.c +++ b/firmware/pcm_playback.c @@ -56,6 +56,11 @@ static volatile size_t audiobuffer_free; static size_t audiobuffer_fillpos; static bool boost_mode; +static bool crossfade_active; +static int crossfade_pos; +static int crossfade_amount; +static int crossfade_rem; + static unsigned char *next_start; static long next_size; @@ -106,6 +111,9 @@ void pcm_boost(bool state) { static bool boost_state = false; + if (crossfade_active) + return ; + if (state != boost_state) { cpu_boost(state); boost_state = state; @@ -334,6 +342,7 @@ void pcm_watermark_callback(int bytes_left) /* Fill audio buffer by boosting cpu */ pcm_boost(true); + crossfade_active = false; } void pcm_set_boost_mode(bool state) @@ -373,11 +382,43 @@ bool pcm_is_lowdata(void) return false; } +void pcm_crossfade_start(void) +{ + if (audiobuffer_free > CHUNK_SIZE * 4) { + return ; + } + pcm_boost(true); + crossfade_active = true; + crossfade_pos = audiobuffer_pos; + crossfade_amount = (PCMBUF_SIZE - audiobuffer_free - CHUNK_SIZE * 22)/2; + crossfade_rem = crossfade_amount; + audiobuffer_fillpos = 0; + + crossfade_pos -= crossfade_amount*2; + if (crossfade_pos < 0) + crossfade_pos = PCMBUF_SIZE + crossfade_pos; +} + +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 ; + } + } +} + bool audiobuffer_insert(char *buf, size_t length) { size_t copy_n = 0; - if (audiobuffer_free < length + CHUNK_SIZE) { + if (audiobuffer_free < length + CHUNK_SIZE && !crossfade_active) { if (!boost_mode) pcm_boost(false); return false; @@ -385,19 +426,35 @@ bool audiobuffer_insert(char *buf, size_t length) if (!pcm_is_playing() && !pcm_paused) { pcm_boost(true); + crossfade_active = false; if (audiobuffer_free < PCMBUF_SIZE - CHUNK_SIZE*2) pcm_play_start(); } while (length > 0) { - copy_n = MIN(length, PCMBUF_SIZE - audiobuffer_pos - - audiobuffer_fillpos); - copy_n = MIN(CHUNK_SIZE, copy_n); - memcpy(&audiobuffer[audiobuffer_pos+audiobuffer_fillpos], - buf, copy_n); - buf += copy_n; - audiobuffer_free -= copy_n; - length -= copy_n; + if (!crossfade_active) { + copy_n = MIN(length, PCMBUF_SIZE - audiobuffer_pos - + audiobuffer_fillpos); + copy_n = MIN(CHUNK_SIZE, copy_n); + + memcpy(&audiobuffer[audiobuffer_pos+audiobuffer_fillpos], + buf, copy_n); + buf += copy_n; + audiobuffer_free -= copy_n; + length -= copy_n; + + } else { + copy_n = MIN(length, PCMBUF_SIZE - (unsigned int)crossfade_pos); + + crossfade((short *)&audiobuffer[crossfade_pos], + (const short *)buf, copy_n/2); + buf += copy_n; + length -= copy_n; + crossfade_pos += copy_n; + if (crossfade_pos >= PCMBUF_SIZE) + crossfade_pos -= PCMBUF_SIZE; + continue ; + } /* Pre-buffer to meet CHUNK_SIZE requirement */ if (copy_n + audiobuffer_fillpos < CHUNK_SIZE && length == 0) { @@ -452,6 +509,7 @@ void pcm_play_start(void) int size; char *start; + crossfade_active = false; if(!pcm_is_playing()) { size = MIN(desc->size, 32768); -- cgit v1.2.3