summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiika Pekkarinen <miipekk@ihme.org>2005-06-29 20:50:58 +0000
committerMiika Pekkarinen <miipekk@ihme.org>2005-06-29 20:50:58 +0000
commit84d6f9e89bf1bae7e3669e487541f91f27a86b0a (patch)
tree29b26568e10f3bf57ef5f334fdfc96ef43102ab4
parentcc377d5d18534c57d091e04573956c9b747b4ab6 (diff)
Fixed slow track switching and track pre-buffering. Fixed rockboy
crash while audio is playing. Some buffering adjustments made. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6930 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/playback.c29
-rw-r--r--firmware/export/pcm_playback.h2
-rw-r--r--firmware/pcm_playback.c97
3 files changed, 97 insertions, 31 deletions
diff --git a/apps/playback.c b/apps/playback.c
index e6cc68af6b..dccf632dc9 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -61,6 +61,7 @@
#include "sound.h"
#include "metadata.h"
+static volatile bool codec_loaded;
static volatile bool playing;
static volatile bool paused;
@@ -213,11 +214,20 @@ bool pcm_is_playing(void)
return false;
}
+bool pcm_is_crossfade_active(void)
+{
+ return false;
+}
+
bool pcm_is_lowdata(void)
{
return false;
}
+void pcm_flush_audio(void)
+{
+}
+
bool pcm_crossfade_init(void)
{
return false;
@@ -487,7 +497,8 @@ bool codec_seek_buffer_callback(off_t newpos)
if (difference >= 0) {
logf("seek: +%d", difference);
codec_advance_buffer_callback(difference);
- pcm_play_stop();
+ if (!pcm_is_crossfade_active())
+ pcm_play_stop();
return true;
}
@@ -508,6 +519,7 @@ bool codec_seek_buffer_callback(off_t newpos)
if (buf_ridx < 0)
buf_ridx = codecbuflen + buf_ridx;
ci.curpos -= difference;
+ if (!pcm_is_crossfade_active())
pcm_play_stop();
return true;
@@ -554,7 +566,7 @@ void yield_codecs(void)
if (!pcm_is_playing())
sleep(5);
while (pcm_is_lowdata() && !ci.stop_codec &&
- playing && queue_empty(&audio_queue))
+ playing && queue_empty(&audio_queue) && codecbufused > (128*1024))
yield();
}
@@ -937,8 +949,7 @@ void audio_check_buffer(void)
/* Limit buffering size at first run. */
if (conf_bufferlimit && (int)fill_bytesleft >= conf_bufferlimit) {
- fill_bytesleft = conf_bufferlimit;
- conf_bufferlimit = 0;
+ fill_bytesleft = conf_bufferlimit - codecbufused;
}
/* Try to load remainings of the file. */
@@ -956,6 +967,7 @@ void audio_check_buffer(void)
last_peek_offset++;
} else if (tracks[track_widx].filerem == 0 || fill_bytesleft == 0) {
filling = false;
+ conf_bufferlimit = 0;
pcm_set_boost_mode(false);
if (playing)
ata_sleep();
@@ -1128,7 +1140,7 @@ void audio_thread(void)
ci.stop_codec = true;
ci.reload_codec = false;
ci.seek_time = 0;
- //pcm_play_stop();
+ pcm_flush_audio();
audio_play_start((int)ev.data);
break ;
@@ -1195,6 +1207,7 @@ void codec_thread(void)
switch (ev.id) {
case CODEC_LOAD_DISK:
ci.stop_codec = false;
+ codec_loaded = true;
status = codec_load_file((char *)ev.data);
break ;
@@ -1209,6 +1222,7 @@ void codec_thread(void)
ci.stop_codec = false;
wrap = (int)&codecbuf[codecbuflen] - (int)cur_ti->codecbuf;
+ codec_loaded = true;
status = codec_load_ram(cur_ti->codecbuf, codecsize,
&codecbuf[0], wrap);
break ;
@@ -1220,6 +1234,8 @@ void codec_thread(void)
break ;
#endif
}
+
+ codec_loaded = false;
switch (ev.id) {
case CODEC_LOAD_DISK:
@@ -1297,6 +1313,8 @@ void audio_stop(void)
{
logf("audio_stop");
queue_post(&audio_queue, AUDIO_STOP, 0);
+ while (playing || codec_loaded)
+ yield();
}
void audio_pause(void)
@@ -1524,6 +1542,7 @@ void audio_init(void)
filling = false;
codecbuf = &audiobuf[MALLOC_BUFSIZE];
playing = false;
+ codec_loaded = false;
paused = false;
track_changed = false;
current_fd = -1;
diff --git a/firmware/export/pcm_playback.h b/firmware/export/pcm_playback.h
index 07e33e96bf..554e975354 100644
--- a/firmware/export/pcm_playback.h
+++ b/firmware/export/pcm_playback.h
@@ -35,6 +35,7 @@ void pcm_play_data(const unsigned char* start, int size,
void pcm_play_stop(void);
void pcm_play_pause(bool play);
bool pcm_is_playing(void);
+bool pcm_is_crossfade_active(void);
/* These functions are for playing chained buffers of PCM data */
void pcm_play_init(void);
@@ -45,6 +46,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_flush_buffer(long length);
bool pcm_crossfade_init(void);
void audiobuffer_add_event(void (*event_handler)(void));
unsigned int audiobuffer_get_latency(void);
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c
index b0bdfbbb32..03cc106016 100644
--- a/firmware/pcm_playback.c
+++ b/firmware/pcm_playback.c
@@ -47,7 +47,7 @@
/* Must be a power of 2 */
#define NUM_PCM_BUFFERS (PCMBUF_SIZE / CHUNK_SIZE)
#define NUM_PCM_BUFFERS_MASK (NUM_PCM_BUFFERS - 1)
-#define PCM_WATERMARK (CHUNK_SIZE * 4)
+#define PCM_WATERMARK (CHUNK_SIZE * 6)
#define PCM_CF_WATERMARK (PCMBUF_SIZE - CHUNK_SIZE*8)
static bool pcm_playing;
@@ -60,6 +60,16 @@ long audiobuffer_free;
static long audiobuffer_fillpos;
static bool boost_mode;
+/* 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.
+ */
+enum {
+ CFM_CROSSFADE,
+ CFM_FLUSH
+};
+
+static int crossfade_mode;
static bool crossfade_enabled;
static bool crossfade_active;
static bool crossfade_init;
@@ -346,8 +356,6 @@ bool pcm_play_add_chunk(void *addr, int size, void (*callback)(void))
void pcm_watermark_callback(int bytes_left)
{
- (void)bytes_left;
-
/* Fill audio buffer by boosting cpu */
pcm_boost(true);
if (bytes_left <= CHUNK_SIZE * 2)
@@ -395,12 +403,25 @@ bool pcm_crossfade_init(void)
return false;
}
logf("crossfading!");
+ crossfade_mode = CFM_CROSSFADE;
crossfade_init = true;
return true;
}
+/** Initialize a track switch so that audio playback will not stop but
+ * the switch to next track would happen as soon as possible.
+ */
+void pcm_flush_audio(void)
+{
+ if (crossfade_init || crossfade_active)
+ return ;
+
+ crossfade_mode = CFM_FLUSH;
+ crossfade_init = true;
+}
+
void pcm_flush_fillpos(void)
{
if (audiobuffer_fillpos) {
@@ -419,19 +440,29 @@ void pcm_flush_fillpos(void)
static void crossfade_start(void)
{
- if (!crossfade_init)
- return ;
-
crossfade_init = 0;
- if (PCMBUF_SIZE - audiobuffer_free < CHUNK_SIZE * 6)
+ if (PCMBUF_SIZE - audiobuffer_free < CHUNK_SIZE * 4) {
+ if (crossfade_mode == CFM_FLUSH)
+ pcm_play_stop();
return ;
-
+ }
+
pcm_flush_fillpos();
pcm_boost(true);
crossfade_active = true;
crossfade_pos = audiobuffer_pos;
- crossfade_amount = (PCMBUF_SIZE - audiobuffer_free - (CHUNK_SIZE * 2))/2;
- crossfade_rem = crossfade_amount;
+
+ switch (crossfade_mode) {
+ case CFM_CROSSFADE:
+ crossfade_amount = (PCMBUF_SIZE - audiobuffer_free - (CHUNK_SIZE * 2))/2;
+ crossfade_rem = crossfade_amount;
+ break ;
+
+ case CFM_FLUSH:
+ crossfade_amount = (PCMBUF_SIZE - audiobuffer_free - (CHUNK_SIZE * 2))/2;
+ crossfade_rem = crossfade_amount;
+ break ;
+ }
crossfade_pos -= crossfade_amount*2;
if (crossfade_pos < 0)
@@ -441,25 +472,40 @@ static void crossfade_start(void)
static __inline
int crossfade(short *buf, const short *buf2, int length)
{
- int i, size;
- int val1 = (crossfade_rem<<10)/crossfade_amount;
- int val2 = ((crossfade_amount-crossfade_rem)<<10)/crossfade_amount;
+ int size, i;
+ int val1, val2;
- // logf("cfi: %d/%d", length, crossfade_rem);
size = MIN(length, crossfade_rem);
- for (i = 0; i < size; i++) {
- buf[i] = ((buf[i] * val1) + (buf2[i] * val2)) >> 10;
+ switch (crossfade_mode) {
+ case CFM_CROSSFADE:
+ val1 = (crossfade_rem<<10)/crossfade_amount;
+ val2 = ((crossfade_amount-crossfade_rem)<<10)/crossfade_amount;
+
+ for (i = 0; i < size; i++) {
+ buf[i] = ((buf[i] * val1) + (buf2[i] * val2)) >> 10;
+ }
+ break ;
+
+ case CFM_FLUSH:
+ for (i = 0; i < size; i++) {
+ buf[i] = buf2[i];
+ }
+ //memcpy((char *)buf, (char *)buf2, size*2);
+ break ;
}
- crossfade_rem -= i;
+
+ crossfade_rem -= size;
if (crossfade_rem <= 0)
crossfade_active = false;
-
+
return size;
}
inline static bool prepare_insert(long length)
{
- crossfade_start();
+ if (crossfade_init)
+ crossfade_start();
+
if (audiobuffer_free < length + audiobuffer_fillpos
+ CHUNK_SIZE && !crossfade_active) {
pcm_boost(false);
@@ -487,15 +533,12 @@ void* pcm_request_buffer(long length, long *realsize)
if (crossfade_active) {
*realsize = MIN(length, PCMBUF_GUARD);
- //logf("cfb:%d/%d", *realsize, length);
ptr = &guardbuf[0];
} else {
*realsize = MIN(length, PCMBUF_SIZE - audiobuffer_pos
- audiobuffer_fillpos);
if (*realsize < length) {
- //logf("gbr1:%d/%d", *realsize, length);
*realsize += MIN((long)(length - *realsize), PCMBUF_GUARD);
- //logf("gbr2:%d/%d", *realsize, length);
}
ptr = &audiobuffer[audiobuffer_pos + audiobuffer_fillpos];
}
@@ -503,17 +546,20 @@ void* pcm_request_buffer(long length, long *realsize)
return ptr;
}
+bool pcm_is_crossfade_active(void)
+{
+ return crossfade_active;
+}
+
void pcm_flush_buffer(long length)
{
int copy_n;
char *buf;
if (crossfade_active) {
- //logf("cfbf");
buf = &guardbuf[0];
length = MIN(length, PCMBUF_GUARD);
while (length > 0 && crossfade_active) {
- //logf("cfl:%d", length);
copy_n = MIN(length, PCMBUF_SIZE - crossfade_pos);
copy_n = 2 * crossfade((short *)&audiobuffer[crossfade_pos],
(const short *)buf, copy_n/2);
@@ -525,7 +571,6 @@ void pcm_flush_buffer(long length)
}
while (length > 0) {
- //logf("cfl2:%d", length);
copy_n = MIN(length, PCMBUF_SIZE - audiobuffer_pos);
memcpy(&audiobuffer[audiobuffer_pos], buf, copy_n);
audiobuffer_fillpos = copy_n;
@@ -545,7 +590,6 @@ void pcm_flush_buffer(long length)
copy_n = audiobuffer_fillpos - (PCMBUF_SIZE - audiobuffer_pos);
if (copy_n > 0) {
- //logf("gbu:%d/%d/%d", copy_n, audiobuffer_fillpos, audiobuffer_pos);
audiobuffer_fillpos -= copy_n;
pcm_flush_fillpos();
copy_n = MIN(copy_n, PCMBUF_GUARD);
@@ -652,6 +696,7 @@ void pcm_play_start(void)
pcm_play_set_watermark(PCM_WATERMARK, pcm_watermark_callback);
}
crossfade_active = false;
+
if(!pcm_is_playing())
{
size = MIN(desc->size, 32768);