summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiika Pekkarinen <miipekk@ihme.org>2005-06-09 07:19:16 +0000
committerMiika Pekkarinen <miipekk@ihme.org>2005-06-09 07:19:16 +0000
commitb4bc106efbf0e7e51a5602fec8ac75dbab9bc969 (patch)
tree288feec87d016f575fbb6d4aa9285b9293732272
parentb24549616ba0ee65d91350e45d3ee695d1e572bf (diff)
downloadrockbox-b4bc106efbf0e7e51a5602fec8ac75dbab9bc969.tar.gz
rockbox-b4bc106efbf0e7e51a5602fec8ac75dbab9bc969.zip
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
-rw-r--r--apps/playback.c65
-rw-r--r--apps/plugins/codecmpa.c1
-rw-r--r--firmware/export/pcm_playback.h1
-rw-r--r--firmware/pcm_playback.c76
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);