summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2013-07-17 08:06:06 -0400
committerMichael Sevakis <jethead71@rockbox.org>2014-03-10 04:13:53 +0100
commit5ee13ebd39c7c39c4086a2657b1aa170c10af1aa (patch)
tree01c082f1c551241d9087df905b202d3496f070dc /apps
parent31b712286721dd606940c7b557d03e3f714b9604 (diff)
downloadrockbox-5ee13ebd39c7c39c4086a2657b1aa170c10af1aa.tar.gz
rockbox-5ee13ebd39c7c39c4086a2657b1aa170c10af1aa.zip
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 <jethead71@rockbox.org> Tested: Michael Sevakis <jethead71@rockbox.org>
Diffstat (limited to 'apps')
-rw-r--r--apps/cuesheet.c104
-rw-r--r--apps/cuesheet.h2
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 @@
42 42
43#define CUE_DIR ROCKBOX_DIR "/cue" 43#define CUE_DIR ROCKBOX_DIR "/cue"
44 44
45bool look_for_cuesheet_file(struct mp3entry *track_id3, struct cuesheet_file *cue_file) 45static bool search_for_cuesheet(const char *path, struct cuesheet_file *cue_file)
46{ 46{
47 /* DEBUGF("look for cue file\n"); */
48 size_t len; 47 size_t len;
49 char cuepath[MAX_PATH]; 48 char cuepath[MAX_PATH];
50 char *dot, *slash, *slash_cuepath; 49 char *dot, *slash, *slash_cuepath;
51 50
52 if (track_id3->has_embedded_cuesheet)
53 {
54 cue_file->pos = track_id3->embedded_cuesheet.pos;
55 cue_file->size = track_id3->embedded_cuesheet.size;
56 cue_file->encoding = track_id3->embedded_cuesheet.encoding;
57 strlcpy(cue_file->path, track_id3->path, MAX_PATH);
58 return true;
59 }
60
61 cue_file->pos = 0; 51 cue_file->pos = 0;
62 cue_file->size = 0; 52 cue_file->size = 0;
63 cue_file->path[0] = '\0'; 53 cue_file->path[0] = '\0';
64 slash = strrchr(track_id3->path, '/'); 54 slash = strrchr(path, '/');
65 if (!slash) 55 if (!slash)
66 return false; 56 return false;
67 len = strlcpy(cuepath, track_id3->path, MAX_PATH); 57 len = strlcpy(cuepath, path, MAX_PATH);
68 slash_cuepath = &cuepath[slash - track_id3->path]; 58 slash_cuepath = &cuepath[slash - path];
69 dot = strrchr(slash_cuepath, '.'); 59 dot = strrchr(slash_cuepath, '.');
70 if (dot) 60 if (dot)
71 strlcpy(dot, ".cue", MAX_PATH - (dot-cuepath)); 61 strlcpy(dot, ".cue", MAX_PATH - (dot-cuepath));
@@ -82,7 +72,7 @@ bool look_for_cuesheet_file(struct mp3entry *track_id3, struct cuesheet_file *cu
82skip: 72skip:
83 if ((len+4) >= MAX_PATH) 73 if ((len+4) >= MAX_PATH)
84 return false; 74 return false;
85 strlcpy(cuepath, track_id3->path, MAX_PATH); 75 strlcpy(cuepath, path, MAX_PATH);
86 strlcat(cuepath, ".cue", MAX_PATH); 76 strlcat(cuepath, ".cue", MAX_PATH);
87 if (!file_exists(cuepath)) 77 if (!file_exists(cuepath))
88 return false; 78 return false;
@@ -93,6 +83,21 @@ skip:
93 return true; 83 return true;
94} 84}
95 85
86bool look_for_cuesheet_file(struct mp3entry *track_id3, struct cuesheet_file *cue_file)
87{
88 /* DEBUGF("look for cue file\n"); */
89 if (track_id3->has_embedded_cuesheet)
90 {
91 cue_file->pos = track_id3->embedded_cuesheet.pos;
92 cue_file->size = track_id3->embedded_cuesheet.size;
93 cue_file->encoding = track_id3->embedded_cuesheet.encoding;
94 strlcpy(cue_file->path, track_id3->path, MAX_PATH);
95 return true;
96 }
97
98 return search_for_cuesheet(track_id3->path, cue_file);
99}
100
96static char *get_string(const char *line) 101static char *get_string(const char *line)
97{ 102{
98 char *start, *end; 103 char *start, *end;
@@ -169,6 +174,9 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
169 strcpy(cue->path, cue_file->path); 174 strcpy(cue->path, cue_file->path);
170 cue->curr_track = cue->tracks; 175 cue->curr_track = cue->tracks;
171 176
177 if (is_embedded)
178 strcpy(cue->file, cue->path);
179
172 while ((line_len = read_line(fd, line, read_bytes)) > 0 180 while ((line_len = read_line(fd, line, read_bytes)) > 0
173 && cue->track_count < MAX_TRACKS ) 181 && cue->track_count < MAX_TRACKS )
174 { 182 {
@@ -208,13 +216,17 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
208 } 216 }
209 else if (!strncmp(s, "TITLE", 5) 217 else if (!strncmp(s, "TITLE", 5)
210 || !strncmp(s, "PERFORMER", 9) 218 || !strncmp(s, "PERFORMER", 9)
211 || !strncmp(s, "SONGWRITER", 10)) 219 || !strncmp(s, "SONGWRITER", 10)
220 || !strncmp(s, "FILE", 4))
212 { 221 {
213 char *dest = NULL; 222 char *dest = NULL;
214 char *string = get_string(s); 223 char *string = get_string(s);
215 if (!string) 224 if (!string)
216 break; 225 break;
217 226
227 size_t count = MAX_NAME*3 + 1;
228 size_t count8859 = MAX_NAME;
229
218 switch (*s) 230 switch (*s)
219 { 231 {
220 case 'T': /* TITLE */ 232 case 'T': /* TITLE */
@@ -231,6 +243,15 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
231 dest = (cue->track_count <= 0) ? cue->songwriter : 243 dest = (cue->track_count <= 0) ? cue->songwriter :
232 cue->tracks[cue->track_count-1].songwriter; 244 cue->tracks[cue->track_count-1].songwriter;
233 break; 245 break;
246
247 case 'F': /* FILE */
248 if (is_embedded || cue->track_count > 0)
249 break;
250
251 dest = cue->file;
252 count = MAX_PATH;
253 count8859 = MAX_PATH/3;
254 break;
234 } 255 }
235 256
236 if (dest) 257 if (dest)
@@ -238,12 +259,12 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
238 if (char_enc == CHAR_ENC_ISO_8859_1) 259 if (char_enc == CHAR_ENC_ISO_8859_1)
239 { 260 {
240 dest = iso_decode(string, dest, -1, 261 dest = iso_decode(string, dest, -1,
241 MIN(strlen(string), MAX_NAME)); 262 MIN(strlen(string), count8859));
242 *dest = '\0'; 263 *dest = '\0';
243 } 264 }
244 else 265 else
245 { 266 {
246 strlcpy(dest, string, MAX_NAME*3 + 1); 267 strlcpy(dest, string, count);
247 } 268 }
248 } 269 }
249 } 270 }
@@ -258,6 +279,16 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
258 } 279 }
259 close(fd); 280 close(fd);
260 281
282 /* If just a filename, add path information from cuesheet path */
283 if (*cue->file && !strrchr(cue->file, '/'))
284 {
285 strcpy(line, cue->file);
286 strcpy(cue->file, cue->path);
287 char *slash = strrchr(cue->file, '/');
288 if (!slash++) slash = cue->file;
289 strlcpy(slash, line, MAX_PATH - (slash - cue->file));
290 }
291
261 /* If some songs don't have performer info, we copy the cuesheet performer */ 292 /* If some songs don't have performer info, we copy the cuesheet performer */
262 int i; 293 int i;
263 for (i = 0; i < cue->track_count; i++) 294 for (i = 0; i < cue->track_count; i++)
@@ -329,7 +360,6 @@ void browse_cuesheet(struct cuesheet *cue)
329 struct gui_synclist lists; 360 struct gui_synclist lists;
330 int action; 361 int action;
331 bool done = false; 362 bool done = false;
332 int sel;
333 char title[MAX_PATH]; 363 char title[MAX_PATH];
334 struct cuesheet_file cue_file; 364 struct cuesheet_file cue_file;
335 struct mp3entry *id3 = audio_current_track(); 365 struct mp3entry *id3 = audio_current_track();
@@ -355,17 +385,41 @@ void browse_cuesheet(struct cuesheet *cue)
355 switch (action) 385 switch (action)
356 { 386 {
357 case ACTION_STD_OK: 387 case ACTION_STD_OK:
388 {
389 bool startit = true;
390 unsigned long elapsed =
391 cue->tracks[gui_synclist_get_sel_pos(&lists)/2].offset;
392
358 id3 = audio_current_track(); 393 id3 = audio_current_track();
359 if (id3 && *id3->path && strcmp(id3->path, "No file!")) 394 if (id3 && *id3->path)
360 { 395 {
361 look_for_cuesheet_file(id3, &cue_file); 396 look_for_cuesheet_file(id3, &cue_file);
362 if (id3->cuesheet && !strcmp(cue->path, cue_file.path)) 397 if (!strcmp(cue->path, cue_file.path))
363 { 398 startit = false;
364 sel = gui_synclist_get_sel_pos(&lists); 399 }
365 seek(cue->tracks[sel/2].offset); 400
366 } 401 if (!startit)
402 startit = !seek(elapsed);
403
404 if (!startit || !*cue->file)
405 break;
406
407 /* check that this cue is the same one that would be found by
408 a search from playback */
409 char file[MAX_PATH];
410 strlcpy(file, cue->file, MAX_PATH);
411
412 if (!strcmp(cue->path, file) || /* if embedded */
413 (search_for_cuesheet(file, &cue_file) &&
414 !strcmp(cue->path, cue_file.path)))
415 {
416 char *fname = strrsplt(file, '/');
417 char *dirname = fname <= file + 1 ? "/" : file;
418 bookmark_play(dirname, 0, elapsed, 0, current_tick, fname);
367 } 419 }
368 break; 420 break;
421 } /* ACTION_STD_OK */
422
369 case ACTION_STD_CANCEL: 423 case ACTION_STD_CANCEL:
370 done = true; 424 done = true;
371 } 425 }
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 {
39 39
40struct cuesheet { 40struct cuesheet {
41 char path[MAX_PATH]; 41 char path[MAX_PATH];
42 42 char file[MAX_PATH];
43 char title[MAX_NAME*3+1]; 43 char title[MAX_NAME*3+1];
44 char performer[MAX_NAME*3+1]; 44 char performer[MAX_NAME*3+1];
45 char songwriter[MAX_NAME*3+1]; 45 char songwriter[MAX_NAME*3+1];