From 5ee13ebd39c7c39c4086a2657b1aa170c10af1aa Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Wed, 17 Jul 2013 08:06:06 -0400 Subject: [PATCH] Implements starting playback from a cuesheet. Before time-based resume this was impossible since playback could not be started at a specified elapsed time, only seeked with playback already running. Right now the "FILE" field is used, if present, to do the lookup from from the .cue to the audio file when it is separate from the audio file. If no path is specified, the .cue and audio file must be in the same directory. When the cuesheet is embedded, the containing file is used and the FILE field is ignored. Supports starting playback and seeking to cue points from the cuesheet browser even without Cuesheet Support turned on. Change-Id: Ib5b534c406f179a7f8c7042a31572b24a62c0731 Reviewed-on: http://gerrit.rockbox.org/522 Reviewed-by: Michael Sevakis Tested: Michael Sevakis --- apps/cuesheet.c | 104 ++++++++++++++++++++++++++++++++++++------------ apps/cuesheet.h | 2 +- 2 files changed, 80 insertions(+), 26 deletions(-) diff --git a/apps/cuesheet.c b/apps/cuesheet.c index 73dd19fdab..52b8c5703b 100644 --- a/apps/cuesheet.c +++ b/apps/cuesheet.c @@ -42,30 +42,20 @@ #define CUE_DIR ROCKBOX_DIR "/cue" -bool look_for_cuesheet_file(struct mp3entry *track_id3, struct cuesheet_file *cue_file) +static bool search_for_cuesheet(const char *path, struct cuesheet_file *cue_file) { - /* DEBUGF("look for cue file\n"); */ size_t len; char cuepath[MAX_PATH]; char *dot, *slash, *slash_cuepath; - if (track_id3->has_embedded_cuesheet) - { - cue_file->pos = track_id3->embedded_cuesheet.pos; - cue_file->size = track_id3->embedded_cuesheet.size; - cue_file->encoding = track_id3->embedded_cuesheet.encoding; - strlcpy(cue_file->path, track_id3->path, MAX_PATH); - return true; - } - cue_file->pos = 0; cue_file->size = 0; cue_file->path[0] = '\0'; - slash = strrchr(track_id3->path, '/'); + slash = strrchr(path, '/'); if (!slash) return false; - len = strlcpy(cuepath, track_id3->path, MAX_PATH); - slash_cuepath = &cuepath[slash - track_id3->path]; + len = strlcpy(cuepath, path, MAX_PATH); + slash_cuepath = &cuepath[slash - path]; dot = strrchr(slash_cuepath, '.'); if (dot) strlcpy(dot, ".cue", MAX_PATH - (dot-cuepath)); @@ -82,7 +72,7 @@ bool look_for_cuesheet_file(struct mp3entry *track_id3, struct cuesheet_file *cu skip: if ((len+4) >= MAX_PATH) return false; - strlcpy(cuepath, track_id3->path, MAX_PATH); + strlcpy(cuepath, path, MAX_PATH); strlcat(cuepath, ".cue", MAX_PATH); if (!file_exists(cuepath)) return false; @@ -93,6 +83,21 @@ skip: return true; } +bool look_for_cuesheet_file(struct mp3entry *track_id3, struct cuesheet_file *cue_file) +{ + /* DEBUGF("look for cue file\n"); */ + if (track_id3->has_embedded_cuesheet) + { + cue_file->pos = track_id3->embedded_cuesheet.pos; + cue_file->size = track_id3->embedded_cuesheet.size; + cue_file->encoding = track_id3->embedded_cuesheet.encoding; + strlcpy(cue_file->path, track_id3->path, MAX_PATH); + return true; + } + + return search_for_cuesheet(track_id3->path, cue_file); +} + static char *get_string(const char *line) { char *start, *end; @@ -169,6 +174,9 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue) strcpy(cue->path, cue_file->path); cue->curr_track = cue->tracks; + if (is_embedded) + strcpy(cue->file, cue->path); + while ((line_len = read_line(fd, line, read_bytes)) > 0 && cue->track_count < MAX_TRACKS ) { @@ -208,13 +216,17 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue) } else if (!strncmp(s, "TITLE", 5) || !strncmp(s, "PERFORMER", 9) - || !strncmp(s, "SONGWRITER", 10)) + || !strncmp(s, "SONGWRITER", 10) + || !strncmp(s, "FILE", 4)) { char *dest = NULL; char *string = get_string(s); if (!string) break; + size_t count = MAX_NAME*3 + 1; + size_t count8859 = MAX_NAME; + switch (*s) { case 'T': /* TITLE */ @@ -231,6 +243,15 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue) dest = (cue->track_count <= 0) ? cue->songwriter : cue->tracks[cue->track_count-1].songwriter; break; + + case 'F': /* FILE */ + if (is_embedded || cue->track_count > 0) + break; + + dest = cue->file; + count = MAX_PATH; + count8859 = MAX_PATH/3; + break; } if (dest) @@ -238,12 +259,12 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue) if (char_enc == CHAR_ENC_ISO_8859_1) { dest = iso_decode(string, dest, -1, - MIN(strlen(string), MAX_NAME)); + MIN(strlen(string), count8859)); *dest = '\0'; } else { - strlcpy(dest, string, MAX_NAME*3 + 1); + strlcpy(dest, string, count); } } } @@ -258,6 +279,16 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue) } close(fd); + /* If just a filename, add path information from cuesheet path */ + if (*cue->file && !strrchr(cue->file, '/')) + { + strcpy(line, cue->file); + strcpy(cue->file, cue->path); + char *slash = strrchr(cue->file, '/'); + if (!slash++) slash = cue->file; + strlcpy(slash, line, MAX_PATH - (slash - cue->file)); + } + /* If some songs don't have performer info, we copy the cuesheet performer */ int i; for (i = 0; i < cue->track_count; i++) @@ -329,7 +360,6 @@ void browse_cuesheet(struct cuesheet *cue) struct gui_synclist lists; int action; bool done = false; - int sel; char title[MAX_PATH]; struct cuesheet_file cue_file; struct mp3entry *id3 = audio_current_track(); @@ -355,17 +385,41 @@ void browse_cuesheet(struct cuesheet *cue) switch (action) { case ACTION_STD_OK: + { + bool startit = true; + unsigned long elapsed = + cue->tracks[gui_synclist_get_sel_pos(&lists)/2].offset; + id3 = audio_current_track(); - if (id3 && *id3->path && strcmp(id3->path, "No file!")) + if (id3 && *id3->path) { look_for_cuesheet_file(id3, &cue_file); - if (id3->cuesheet && !strcmp(cue->path, cue_file.path)) - { - sel = gui_synclist_get_sel_pos(&lists); - seek(cue->tracks[sel/2].offset); - } + if (!strcmp(cue->path, cue_file.path)) + startit = false; + } + + if (!startit) + startit = !seek(elapsed); + + if (!startit || !*cue->file) + break; + + /* check that this cue is the same one that would be found by + a search from playback */ + char file[MAX_PATH]; + strlcpy(file, cue->file, MAX_PATH); + + if (!strcmp(cue->path, file) || /* if embedded */ + (search_for_cuesheet(file, &cue_file) && + !strcmp(cue->path, cue_file.path))) + { + char *fname = strrsplt(file, '/'); + char *dirname = fname <= file + 1 ? "/" : file; + bookmark_play(dirname, 0, elapsed, 0, current_tick, fname); } break; + } /* ACTION_STD_OK */ + case ACTION_STD_CANCEL: done = true; } diff --git a/apps/cuesheet.h b/apps/cuesheet.h index 31841dacf6..0b9503a9bb 100644 --- a/apps/cuesheet.h +++ b/apps/cuesheet.h @@ -39,7 +39,7 @@ struct cue_track_info { struct cuesheet { char path[MAX_PATH]; - + char file[MAX_PATH]; char title[MAX_NAME*3+1]; char performer[MAX_NAME*3+1]; char songwriter[MAX_NAME*3+1];