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
This commit is contained in:
Miika Pekkarinen 2005-06-09 07:19:16 +00:00
parent b24549616b
commit b4bc106efb
4 changed files with 111 additions and 32 deletions

View file

@ -68,7 +68,7 @@ static volatile bool paused;
#define CODEC_WAV "/.rockbox/codecs/codecwav.rock"; #define CODEC_WAV "/.rockbox/codecs/codecwav.rock";
#define AUDIO_WATERMARK 0x70000 #define AUDIO_WATERMARK 0x70000
#define AUDIO_FILE_CHUNK (1024*256) #define AUDIO_FILE_CHUNK (1024*512)
#define AUDIO_PLAY 1 #define AUDIO_PLAY 1
#define AUDIO_STOP 2 #define AUDIO_STOP 2
@ -107,6 +107,9 @@ static const char codec_thread_name[] = "codec";
/* Is file buffer currently being refilled? */ /* Is file buffer currently being refilled? */
static volatile bool filling; static volatile bool filling;
/* Interrupts buffer filling. */
static volatile bool interrupt;
/* Ring buffer where tracks and codecs are loaded. */ /* Ring buffer where tracks and codecs are loaded. */
char *codecbuf; char *codecbuf;
@ -398,8 +401,8 @@ int probe_file_format(const char *filename)
void yield_codecs(void) void yield_codecs(void)
{ {
#ifndef SIMULATOR
yield(); yield();
#ifndef SIMULATOR
if (!pcm_is_playing()) if (!pcm_is_playing())
sleep(5); sleep(5);
while (pcm_is_lowdata()) while (pcm_is_lowdata())
@ -420,7 +423,7 @@ void audio_fill_file_buffer(void)
/* Give codecs some processing time. */ /* Give codecs some processing time. */
yield_codecs(); yield_codecs();
if (!playing) { if (interrupt) {
logf("Filling interrupted"); logf("Filling interrupted");
close(current_fd); close(current_fd);
current_fd = -1; current_fd = -1;
@ -540,7 +543,7 @@ bool loadcodec(const char *trackname, bool start_play)
i = 0; i = 0;
while (i < size) { while (i < size) {
yield_codecs(); yield_codecs();
if (!playing) { if (interrupt) {
logf("Buffering interrupted"); logf("Buffering interrupted");
close(fd); close(fd);
return false; return false;
@ -610,7 +613,7 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
logf("%s", trackname); logf("%s", trackname);
logf("Buffering track:%d/%d", track_widx, track_ridx); logf("Buffering track:%d/%d", track_widx, track_ridx);
if (!playing) { if (interrupt) {
close(fd); close(fd);
return false; return false;
} }
@ -717,7 +720,7 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
while (i < size) { while (i < size) {
/* Give codecs some processing time to prevent glitches. */ /* Give codecs some processing time to prevent glitches. */
yield_codecs(); yield_codecs();
if (!playing) { if (interrupt) {
logf("Buffering interrupted"); logf("Buffering interrupted");
close(fd); close(fd);
return false; return false;
@ -803,8 +806,14 @@ void audio_check_buffer(void)
int i; int i;
int cur_idx; 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. */ /* Start buffer filling as necessary. */
if (codecbufused > AUDIO_WATERMARK || !playing) if (codecbufused > AUDIO_WATERMARK || !interrupt)
return ; return ;
filling = true; filling = true;
@ -863,6 +872,9 @@ void audio_update_trackinfo(void)
buf_ridx += cur_ti->codecsize; buf_ridx += cur_ti->codecsize;
if (buf_ridx >= codecbuflen) if (buf_ridx >= codecbuflen)
buf_ridx -= codecbuflen; buf_ridx -= codecbuflen;
pcm_crossfade_start();
if (!filling)
pcm_set_boost_mode(false);
} else { } else {
buf_ridx -= ci.curpos; buf_ridx -= ci.curpos;
codecbufused += ci.curpos; codecbufused += ci.curpos;
@ -978,14 +990,13 @@ void audio_thread(void)
queue_wait_w_tmo(&audio_queue, &ev, 0); queue_wait_w_tmo(&audio_queue, &ev, 0);
switch (ev.id) { switch (ev.id) {
case AUDIO_PLAY: case AUDIO_PLAY:
interrupt = false;
ci.stop_codec = true; ci.stop_codec = true;
ci.reload_codec = false; ci.reload_codec = false;
ci.seek_time = 0; ci.seek_time = 0;
#ifndef SIMULATOR #ifndef SIMULATOR
pcm_play_stop(); pcm_play_stop();
pcm_play_pause(true);
#endif #endif
playing = true;
paused = false; paused = false;
audio_play_start((int)ev.data); audio_play_start((int)ev.data);
break ; break ;
@ -993,8 +1004,8 @@ void audio_thread(void)
case AUDIO_STOP: case AUDIO_STOP:
#ifndef SIMULATOR #ifndef SIMULATOR
pcm_play_stop(); pcm_play_stop();
pcm_play_pause(true);
#endif #endif
paused = false;
break ; break ;
case AUDIO_PAUSE: case AUDIO_PAUSE:
@ -1017,6 +1028,7 @@ void audio_thread(void)
ci.stop_codec = true; ci.stop_codec = true;
logf("USB Connection"); logf("USB Connection");
pcm_play_stop(); pcm_play_stop();
pcm_play_pause(true);
usb_acknowledge(SYS_USB_CONNECTED_ACK); usb_acknowledge(SYS_USB_CONNECTED_ACK);
usb_wait_for_disconnect(&audio_queue); usb_wait_for_disconnect(&audio_queue);
break ; break ;
@ -1076,12 +1088,14 @@ void codec_thread(void)
logf("Codec finished"); logf("Codec finished");
} }
queue_post(&audio_queue, AUDIO_CODEC_DONE, (void *)status);
if (playing && !ci.stop_codec && !ci.reload_codec) { if (playing && !ci.stop_codec && !ci.reload_codec) {
audio_change_track(); audio_change_track();
} else if (ci.reload_codec) {
interrupt = true;
} else { } else {
playing = false; 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) void audio_play(int offset)
{ {
logf("audio_play"); logf("audio_play");
playing = false;
ci.stop_codec = true; ci.stop_codec = true;
playing = false;
#ifndef SIMULATOR
pcm_play_pause(true);
#endif
queue_post(&audio_queue, AUDIO_PLAY, (void *)offset); queue_post(&audio_queue, AUDIO_PLAY, (void *)offset);
} }
void audio_stop(void) void audio_stop(void)
{ {
logf("audio_stop"); logf("audio_stop");
if (!playing)
return ;
playing = false; playing = false;
ci.stop_codec = true; ci.stop_codec = true;
if (current_fd) { if (current_fd) {
@ -1147,6 +1161,9 @@ void audio_stop(void)
current_fd = -1; current_fd = -1;
} }
queue_post(&audio_queue, AUDIO_STOP, 0); queue_post(&audio_queue, AUDIO_STOP, 0);
#ifndef SIMULATOR
pcm_play_pause(true);
#endif
} }
void audio_pause(void) void audio_pause(void)
@ -1174,16 +1191,17 @@ void audio_next(void)
logf("audio_next"); logf("audio_next");
new_track = 1; new_track = 1;
ci.reload_codec = true; ci.reload_codec = true;
#ifndef SIMULATOR
pcm_play_stop();
#endif
/* Detect if disk is spinning.. */ /* Detect if disk is spinning.. */
if (filling) { if (filling) {
playlist_next(1); interrupt = true;
playing = false;
ci.stop_codec = true; ci.stop_codec = true;
playlist_next(1);
queue_post(&audio_queue, AUDIO_PLAY, 0); queue_post(&audio_queue, AUDIO_PLAY, 0);
} else {
#ifndef SIMULATOR
pcm_play_stop();
#endif
} }
} }
@ -1197,9 +1215,9 @@ void audio_prev(void)
#endif #endif
if (filling) { if (filling) {
playlist_next(-1); interrupt = true;
playing = false;
ci.stop_codec = true; ci.stop_codec = true;
playlist_next(-1);
queue_post(&audio_queue, AUDIO_PLAY, 0); queue_post(&audio_queue, AUDIO_PLAY, 0);
} }
//queue_post(&audio_queue, AUDIO_PREV, 0); //queue_post(&audio_queue, AUDIO_PREV, 0);
@ -1377,7 +1395,8 @@ void audio_init(void)
- MALLOC_BUFSIZE - GUARD_BUFSIZE; - MALLOC_BUFSIZE - GUARD_BUFSIZE;
//codecbuflen = 2*512*1024; //codecbuflen = 2*512*1024;
codecbufused = 0; codecbufused = 0;
filling = 0; filling = false;
interrupt = false;
codecbuf = &audiobuf[MALLOC_BUFSIZE]; codecbuf = &audiobuf[MALLOC_BUFSIZE];
playing = false; playing = false;
paused = false; paused = false;

View file

@ -381,6 +381,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
/* Flush the buffer if it is full. */ /* Flush the buffer if it is full. */
if(OutputPtr==OutputBufferEnd) if(OutputPtr==OutputBufferEnd)
{ {
rb->yield();
#ifdef DEBUG_GAPLESS #ifdef DEBUG_GAPLESS
rb->write(fd, OutputBuffer, OUTPUT_BUFFER_SIZE); rb->write(fd, OutputBuffer, OUTPUT_BUFFER_SIZE);
#endif #endif

View file

@ -42,6 +42,7 @@ void pcm_play_set_watermark(int numbytes, void (*callback)(int bytes_left));
void pcm_set_boost_mode(bool state); void pcm_set_boost_mode(bool state);
bool pcm_is_lowdata(void); bool pcm_is_lowdata(void);
void pcm_crossfade_start(void);
unsigned int audiobuffer_get_latency(void); unsigned int audiobuffer_get_latency(void);
bool audiobuffer_insert(char *buf, size_t length); bool audiobuffer_insert(char *buf, size_t length);

View file

@ -56,6 +56,11 @@ static volatile size_t audiobuffer_free;
static size_t audiobuffer_fillpos; static size_t audiobuffer_fillpos;
static bool boost_mode; 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 unsigned char *next_start;
static long next_size; static long next_size;
@ -106,6 +111,9 @@ void pcm_boost(bool state)
{ {
static bool boost_state = false; static bool boost_state = false;
if (crossfade_active)
return ;
if (state != boost_state) { if (state != boost_state) {
cpu_boost(state); cpu_boost(state);
boost_state = state; boost_state = state;
@ -334,6 +342,7 @@ void pcm_watermark_callback(int bytes_left)
/* Fill audio buffer by boosting cpu */ /* Fill audio buffer by boosting cpu */
pcm_boost(true); pcm_boost(true);
crossfade_active = false;
} }
void pcm_set_boost_mode(bool state) void pcm_set_boost_mode(bool state)
@ -373,11 +382,43 @@ bool pcm_is_lowdata(void)
return false; 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) bool audiobuffer_insert(char *buf, size_t length)
{ {
size_t copy_n = 0; size_t copy_n = 0;
if (audiobuffer_free < length + CHUNK_SIZE) { if (audiobuffer_free < length + CHUNK_SIZE && !crossfade_active) {
if (!boost_mode) if (!boost_mode)
pcm_boost(false); pcm_boost(false);
return false; return false;
@ -385,19 +426,35 @@ bool audiobuffer_insert(char *buf, size_t length)
if (!pcm_is_playing() && !pcm_paused) { if (!pcm_is_playing() && !pcm_paused) {
pcm_boost(true); pcm_boost(true);
crossfade_active = false;
if (audiobuffer_free < PCMBUF_SIZE - CHUNK_SIZE*2) if (audiobuffer_free < PCMBUF_SIZE - CHUNK_SIZE*2)
pcm_play_start(); pcm_play_start();
} }
while (length > 0) { while (length > 0) {
copy_n = MIN(length, PCMBUF_SIZE - audiobuffer_pos - if (!crossfade_active) {
audiobuffer_fillpos); copy_n = MIN(length, PCMBUF_SIZE - audiobuffer_pos -
copy_n = MIN(CHUNK_SIZE, copy_n); audiobuffer_fillpos);
memcpy(&audiobuffer[audiobuffer_pos+audiobuffer_fillpos], copy_n = MIN(CHUNK_SIZE, copy_n);
buf, copy_n);
buf += copy_n; memcpy(&audiobuffer[audiobuffer_pos+audiobuffer_fillpos],
audiobuffer_free -= copy_n; buf, copy_n);
length -= 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 */ /* Pre-buffer to meet CHUNK_SIZE requirement */
if (copy_n + audiobuffer_fillpos < CHUNK_SIZE && length == 0) { if (copy_n + audiobuffer_fillpos < CHUNK_SIZE && length == 0) {
@ -452,6 +509,7 @@ void pcm_play_start(void)
int size; int size;
char *start; char *start;
crossfade_active = false;
if(!pcm_is_playing()) if(!pcm_is_playing())
{ {
size = MIN(desc->size, 32768); size = MIN(desc->size, 32768);