forked from len0rd/rockbox
iRiver: Fixed broken items skipping on playlist: Now skipping and
marking them as bad instead of deleting the entries from playlist. Faster buffered track skipping and preventing glitches from previous tracks (still something might occur though, please report them). git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7647 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
ddad7197ed
commit
c52f7f1b5e
5 changed files with 113 additions and 30 deletions
|
@ -193,7 +193,7 @@ void pcmbuf_watermark_callback(int bytes_left)
|
||||||
{
|
{
|
||||||
/* Fill audio buffer by boosting cpu */
|
/* Fill audio buffer by boosting cpu */
|
||||||
pcmbuf_boost(true);
|
pcmbuf_boost(true);
|
||||||
if (bytes_left <= CHUNK_SIZE * 2)
|
if (bytes_left <= CHUNK_SIZE * 2 && crossfade_mode != CFM_FLUSH)
|
||||||
crossfade_active = false;
|
crossfade_active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,8 +347,9 @@ static void crossfade_start(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
logf("crossfade_start");
|
logf("crossfade_start");
|
||||||
audiobuffer_fillpos = 0;
|
|
||||||
pcmbuf_boost(true);
|
pcmbuf_boost(true);
|
||||||
|
while (audiobuffer_fillpos != 0)
|
||||||
|
pcmbuf_flush_fillpos();
|
||||||
crossfade_active = true;
|
crossfade_active = true;
|
||||||
crossfade_pos = audiobuffer_pos;
|
crossfade_pos = audiobuffer_pos;
|
||||||
|
|
||||||
|
@ -360,7 +361,7 @@ static void crossfade_start(void)
|
||||||
break ;
|
break ;
|
||||||
|
|
||||||
case CFM_FLUSH:
|
case CFM_FLUSH:
|
||||||
crossfade_amount = (bytesleft - (CHUNK_SIZE * 2))/2;
|
crossfade_amount = bytesleft /2;
|
||||||
crossfade_rem = crossfade_amount;
|
crossfade_rem = crossfade_amount;
|
||||||
break ;
|
break ;
|
||||||
}
|
}
|
||||||
|
@ -439,13 +440,10 @@ void* pcmbuf_request_buffer(long length, long *realsize)
|
||||||
{
|
{
|
||||||
void *ptr = NULL;
|
void *ptr = NULL;
|
||||||
|
|
||||||
if (crossfade_init)
|
if (!prepare_insert(length))
|
||||||
crossfade_start();
|
{
|
||||||
|
*realsize = 0;
|
||||||
while (audiobuffer_free < length + audiobuffer_fillpos
|
return NULL;
|
||||||
+ CHUNK_SIZE && !crossfade_active) {
|
|
||||||
pcmbuf_boost(false);
|
|
||||||
sleep(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crossfade_active) {
|
if (crossfade_active) {
|
||||||
|
@ -473,8 +471,6 @@ void pcmbuf_flush_buffer(long length)
|
||||||
int copy_n;
|
int copy_n;
|
||||||
char *buf;
|
char *buf;
|
||||||
|
|
||||||
prepare_insert(length);
|
|
||||||
|
|
||||||
if (crossfade_active) {
|
if (crossfade_active) {
|
||||||
buf = &guardbuf[0];
|
buf = &guardbuf[0];
|
||||||
length = MIN(length, PCMBUF_GUARD);
|
length = MIN(length, PCMBUF_GUARD);
|
||||||
|
|
|
@ -296,9 +296,15 @@ bool codec_pcmbuf_insert_split_callback(void *ch1, void *ch2,
|
||||||
}
|
}
|
||||||
|
|
||||||
while (length > 0) {
|
while (length > 0) {
|
||||||
|
/* This will prevent old audio from playing when skipping tracks. */
|
||||||
|
if (ci.reload_codec || ci.stop_codec)
|
||||||
|
return true;
|
||||||
|
|
||||||
while ((dest = pcmbuf_request_buffer(dsp_output_size(length),
|
while ((dest = pcmbuf_request_buffer(dsp_output_size(length),
|
||||||
&output_size)) == NULL) {
|
&output_size)) == NULL) {
|
||||||
yield();
|
sleep(1);
|
||||||
|
if (ci.reload_codec || ci.stop_codec)
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the real input_size for output_size bytes, guarding
|
/* Get the real input_size for output_size bytes, guarding
|
||||||
|
@ -1008,7 +1014,6 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
|
||||||
off_t size;
|
off_t size;
|
||||||
int rc, i;
|
int rc, i;
|
||||||
int copy_n;
|
int copy_n;
|
||||||
int playlist_index;
|
|
||||||
|
|
||||||
/* Stop buffer filling if there is no free track entries.
|
/* Stop buffer filling if there is no free track entries.
|
||||||
Don't fill up the last track entry (we wan't to store next track
|
Don't fill up the last track entry (we wan't to store next track
|
||||||
|
@ -1025,10 +1030,6 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
last_index = playlist_get_display_index();
|
last_index = playlist_get_display_index();
|
||||||
playlist_index = playlist_get_display_index() - 1
|
|
||||||
+ playlist_get_first_index(NULL) + peek_offset;
|
|
||||||
if (playlist_index >= playlist_amount())
|
|
||||||
playlist_index -= playlist_amount();
|
|
||||||
|
|
||||||
peek_again:
|
peek_again:
|
||||||
/* Get track name from current playlist read position. */
|
/* Get track name from current playlist read position. */
|
||||||
|
@ -1038,8 +1039,8 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
|
||||||
fd = open(trackname, O_RDONLY);
|
fd = open(trackname, O_RDONLY);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
logf("Open failed");
|
logf("Open failed");
|
||||||
/* Delete invalid entry from playlist. */
|
/* Skip invalid entry from playlist. */
|
||||||
playlist_delete(NULL, playlist_index);
|
playlist_skip_entry(NULL, peek_offset);
|
||||||
continue ;
|
continue ;
|
||||||
}
|
}
|
||||||
break ;
|
break ;
|
||||||
|
@ -1088,8 +1089,8 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
|
||||||
|
|
||||||
/* Try skipping to next track. */
|
/* Try skipping to next track. */
|
||||||
if (fill_bytesleft > 0) {
|
if (fill_bytesleft > 0) {
|
||||||
/* Delete invalid entry from playlist. */
|
/* Skip invalid entry from playlist. */
|
||||||
playlist_delete(NULL, playlist_index);
|
playlist_skip_entry(NULL, peek_offset);
|
||||||
goto peek_again;
|
goto peek_again;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1104,8 +1105,8 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
|
||||||
tracks[track_widx].filesize = 0;
|
tracks[track_widx].filesize = 0;
|
||||||
tracks[track_widx].filerem = 0;
|
tracks[track_widx].filerem = 0;
|
||||||
close(fd);
|
close(fd);
|
||||||
/* Delete invalid entry from playlist. */
|
/* Skip invalid entry from playlist. */
|
||||||
playlist_delete(NULL, playlist_index);
|
playlist_skip_entry(NULL, peek_offset);
|
||||||
goto peek_again;
|
goto peek_again;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,10 +99,10 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Each playlist index has a flag associated with it which identifies what
|
Each playlist index has a flag associated with it which identifies what
|
||||||
type of track it is. These flags are stored in the 3 high order bits of
|
type of track it is. These flags are stored in the 4 high order bits of
|
||||||
the index.
|
the index.
|
||||||
|
|
||||||
NOTE: This limits the playlist file size to a max of 512M.
|
NOTE: This limits the playlist file size to a max of 256M.
|
||||||
|
|
||||||
Bits 31-30:
|
Bits 31-30:
|
||||||
00 = Playlist track
|
00 = Playlist track
|
||||||
|
@ -112,8 +112,11 @@
|
||||||
Bit 29:
|
Bit 29:
|
||||||
0 = Added track
|
0 = Added track
|
||||||
1 = Queued track
|
1 = Queued track
|
||||||
|
Bit 28:
|
||||||
|
0 = Track entry is valid
|
||||||
|
1 = Track does not exist on disk and should be skipped
|
||||||
*/
|
*/
|
||||||
#define PLAYLIST_SEEK_MASK 0x1FFFFFFF
|
#define PLAYLIST_SEEK_MASK 0x07FFFFFF
|
||||||
#define PLAYLIST_INSERT_TYPE_MASK 0xC0000000
|
#define PLAYLIST_INSERT_TYPE_MASK 0xC0000000
|
||||||
#define PLAYLIST_QUEUE_MASK 0x20000000
|
#define PLAYLIST_QUEUE_MASK 0x20000000
|
||||||
|
|
||||||
|
@ -122,6 +125,7 @@
|
||||||
#define PLAYLIST_INSERT_TYPE_APPEND 0xC0000000
|
#define PLAYLIST_INSERT_TYPE_APPEND 0xC0000000
|
||||||
|
|
||||||
#define PLAYLIST_QUEUED 0x20000000
|
#define PLAYLIST_QUEUED 0x20000000
|
||||||
|
#define PLAYLIST_SKIPPED 0x10000000
|
||||||
|
|
||||||
#define PLAYLIST_DISPLAY_COUNT 10
|
#define PLAYLIST_DISPLAY_COUNT 10
|
||||||
|
|
||||||
|
@ -828,6 +832,72 @@ static int sort_playlist(struct playlist_info* playlist, bool start_current,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Marks the index of the track to be skipped that is "steps" away from
|
||||||
|
* current playing track.
|
||||||
|
*/
|
||||||
|
void playlist_skip_entry(struct playlist_info *playlist, int steps)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
|
||||||
|
if (playlist == NULL)
|
||||||
|
playlist = ¤t_playlist;
|
||||||
|
|
||||||
|
index = rotate_index(playlist, playlist->index);
|
||||||
|
index += steps;
|
||||||
|
if (index < 0 || index >= playlist->amount)
|
||||||
|
return ;
|
||||||
|
|
||||||
|
index = (index+playlist->first_index) % playlist->amount;
|
||||||
|
playlist->indices[index] |= PLAYLIST_SKIPPED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate how many steps we have to really step when skipping entries
|
||||||
|
* marked as bad.
|
||||||
|
*/
|
||||||
|
static int calculate_step_count(const struct playlist_info *playlist, int steps)
|
||||||
|
{
|
||||||
|
int i, count, direction;
|
||||||
|
int index;
|
||||||
|
int stepped_count = 0;
|
||||||
|
|
||||||
|
if (steps < 0)
|
||||||
|
{
|
||||||
|
direction = -1;
|
||||||
|
count = -steps;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
direction = 1;
|
||||||
|
count = steps;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = playlist->index;
|
||||||
|
i = 0;
|
||||||
|
while (i < count)
|
||||||
|
{
|
||||||
|
index += direction;
|
||||||
|
/* Boundary check */
|
||||||
|
if (index < 0)
|
||||||
|
index += playlist->amount;
|
||||||
|
if (index >= playlist->amount)
|
||||||
|
index -= playlist->amount;
|
||||||
|
|
||||||
|
/* Check if we found a bad entry. */
|
||||||
|
if (playlist->indices[index] & PLAYLIST_SKIPPED)
|
||||||
|
{
|
||||||
|
steps += direction;
|
||||||
|
/* Are all entries bad? */
|
||||||
|
if (stepped_count++ > playlist->amount)
|
||||||
|
break ;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return steps;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* returns the index of the track that is "steps" away from current playing
|
* returns the index of the track that is "steps" away from current playing
|
||||||
* track.
|
* track.
|
||||||
|
@ -848,6 +918,7 @@ static int get_next_index(const struct playlist_info* playlist, int steps,
|
||||||
(!global_settings.playlist_shuffle || playlist->amount <= 1))
|
(!global_settings.playlist_shuffle || playlist->amount <= 1))
|
||||||
repeat_mode = REPEAT_ALL;
|
repeat_mode = REPEAT_ALL;
|
||||||
|
|
||||||
|
steps = calculate_step_count(playlist, steps);
|
||||||
switch (repeat_mode)
|
switch (repeat_mode)
|
||||||
{
|
{
|
||||||
case REPEAT_SHUFFLE:
|
case REPEAT_SHUFFLE:
|
||||||
|
@ -856,7 +927,6 @@ static int get_next_index(const struct playlist_info* playlist, int steps,
|
||||||
case REPEAT_OFF:
|
case REPEAT_OFF:
|
||||||
{
|
{
|
||||||
current_index = rotate_index(playlist, current_index);
|
current_index = rotate_index(playlist, current_index);
|
||||||
|
|
||||||
next_index = current_index+steps;
|
next_index = current_index+steps;
|
||||||
if ((next_index < 0) || (next_index >= playlist->amount))
|
if ((next_index < 0) || (next_index >= playlist->amount))
|
||||||
next_index = -1;
|
next_index = -1;
|
||||||
|
@ -904,6 +974,10 @@ static int get_next_index(const struct playlist_info* playlist, int steps,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* No luck if the whole playlist was bad. */
|
||||||
|
if (playlist->indices[next_index] & PLAYLIST_SKIPPED)
|
||||||
|
return -1;
|
||||||
|
|
||||||
return next_index;
|
return next_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2652,8 +2726,12 @@ int playlist_get_track_info(struct playlist_info* playlist, int index,
|
||||||
info->attr |= PLAYLIST_ATTR_QUEUED;
|
info->attr |= PLAYLIST_ATTR_QUEUED;
|
||||||
else
|
else
|
||||||
info->attr |= PLAYLIST_ATTR_INSERTED;
|
info->attr |= PLAYLIST_ATTR_INSERTED;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (playlist->indices[index] & PLAYLIST_SKIPPED)
|
||||||
|
info->attr |= PLAYLIST_ATTR_SKIPPED;
|
||||||
|
|
||||||
info->index = index;
|
info->index = index;
|
||||||
info->display_index = rotate_index(playlist, index) + 1;
|
info->display_index = rotate_index(playlist, index) + 1;
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@ struct playlist_info
|
||||||
|
|
||||||
#define PLAYLIST_ATTR_QUEUED 0x01
|
#define PLAYLIST_ATTR_QUEUED 0x01
|
||||||
#define PLAYLIST_ATTR_INSERTED 0x02
|
#define PLAYLIST_ATTR_INSERTED 0x02
|
||||||
|
#define PLAYLIST_ATTR_SKIPPED 0x04
|
||||||
|
|
||||||
#define DEFAULT_DYNAMIC_PLAYLIST_NAME "/dynamic.m3u"
|
#define DEFAULT_DYNAMIC_PLAYLIST_NAME "/dynamic.m3u"
|
||||||
|
|
||||||
|
@ -99,6 +100,7 @@ int playlist_insert_directory(struct playlist_info* playlist,
|
||||||
bool recurse);
|
bool recurse);
|
||||||
int playlist_insert_playlist(struct playlist_info* playlist, char *filename,
|
int playlist_insert_playlist(struct playlist_info* playlist, char *filename,
|
||||||
int position, bool queue);
|
int position, bool queue);
|
||||||
|
void playlist_skip_entry(struct playlist_info *playlist, int steps);
|
||||||
int playlist_delete(struct playlist_info* playlist, int index);
|
int playlist_delete(struct playlist_info* playlist, int index);
|
||||||
int playlist_move(struct playlist_info* playlist, int index, int new_index);
|
int playlist_move(struct playlist_info* playlist, int index, int new_index);
|
||||||
int playlist_randomise(struct playlist_info* playlist, unsigned int seed,
|
int playlist_randomise(struct playlist_info* playlist, unsigned int seed,
|
||||||
|
|
|
@ -112,6 +112,7 @@ struct playlist_entry {
|
||||||
int index; /* Playlist index */
|
int index; /* Playlist index */
|
||||||
int display_index; /* Display index */
|
int display_index; /* Display index */
|
||||||
bool queued; /* Is track queued? */
|
bool queued; /* Is track queued? */
|
||||||
|
bool skipped; /* Is track marked as bad? */
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct playlist_viewer_info viewer;
|
static struct playlist_viewer_info viewer;
|
||||||
|
@ -381,6 +382,7 @@ static int load_entry(int index, int pos, char* p, int size)
|
||||||
tracks[pos].index = info.index;
|
tracks[pos].index = info.index;
|
||||||
tracks[pos].display_index = info.display_index;
|
tracks[pos].display_index = info.display_index;
|
||||||
tracks[pos].queued = info.attr & PLAYLIST_ATTR_QUEUED;
|
tracks[pos].queued = info.attr & PLAYLIST_ATTR_QUEUED;
|
||||||
|
tracks[pos].skipped = info.attr & PLAYLIST_ATTR_SKIPPED;
|
||||||
|
|
||||||
result = len;
|
result = len;
|
||||||
}
|
}
|
||||||
|
@ -424,14 +426,18 @@ static void format_name(char* dest, const char* src)
|
||||||
static void format_line(const struct playlist_entry* track, char* str, int len)
|
static void format_line(const struct playlist_entry* track, char* str, int len)
|
||||||
{
|
{
|
||||||
char name[MAX_PATH];
|
char name[MAX_PATH];
|
||||||
|
char *skipped = "";
|
||||||
|
|
||||||
format_name(name, track->name);
|
format_name(name, track->name);
|
||||||
|
|
||||||
|
if (track->skipped)
|
||||||
|
skipped = "(ERR) ";
|
||||||
|
|
||||||
if (global_settings.playlist_viewer_indices)
|
if (global_settings.playlist_viewer_indices)
|
||||||
/* Display playlist index */
|
/* Display playlist index */
|
||||||
snprintf(str, len, "%d. %s", track->display_index, name);
|
snprintf(str, len, "%d. %s%s", track->display_index, skipped, name);
|
||||||
else
|
else
|
||||||
snprintf(str, len, "%s", name);
|
snprintf(str, len, "%s%s", skipped, name);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue