From 24b136f62de82d7419751b6aaeae0ad3d8497bea Mon Sep 17 00:00:00 2001 From: Jonathan Gordon Date: Mon, 20 Jul 2009 05:18:18 +0000 Subject: [PATCH] rework cuesheet support: swcodec: search for a .cue during buffering (with the possibility of adding embedded cuesheets later) hwcodec: search for a .cue when the id3 info for the current track is requested for the first time (disk should be spining so non issue) major beenfit from this is simplofy cuesheet handling code a bit... if mp3entry.cuesheet != NULL then there is a valid cuesheet.. no need to worry about if its enabled and preloaded. There is the possibility of putting the next/prev subtrack handling inside the playback code (as well as the id3 updating stuff (see FS#9789 for more info), but thats probably not a good idea. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21978 a1c6a512-1295-4272-9138-f99709370657 --- apps/cuesheet.c | 54 ++++++++++++++------------------------ apps/cuesheet.h | 11 +++----- apps/gui/gwps-common.c | 16 +++-------- apps/gui/gwps.c | 26 +++++------------- apps/main.c | 4 --- apps/menus/playback_menu.c | 2 +- apps/metadata.c | 7 ----- apps/metadata.h | 2 +- apps/mpeg.c | 54 +++++++++++++++++++++++++++++--------- apps/onplay.c | 8 +++--- apps/playback.c | 42 +++++++++++++++++++++++++++++ 11 files changed, 122 insertions(+), 104 deletions(-) diff --git a/apps/cuesheet.c b/apps/cuesheet.c index fa1d93f334..aaa2670a40 100644 --- a/apps/cuesheet.c +++ b/apps/cuesheet.c @@ -43,33 +43,6 @@ #define CUE_DIR ROCKBOX_DIR "/cue" -struct cuesheet *curr_cue; - -#if CONFIG_CODEC != SWCODEC -/* special trickery because the hwcodec playback engine is in firmware/ */ -static bool cuesheet_handler(const char *filename) -{ - return cuesheet_is_enabled() && look_for_cuesheet_file(filename, NULL); -} -#endif - -void cuesheet_init(void) -{ - if (global_settings.cuesheet) { - curr_cue = (struct cuesheet *)buffer_alloc(sizeof(struct cuesheet)); -#if CONFIG_CODEC != SWCODEC - audio_set_cuesheet_callback(cuesheet_handler); -#endif - } else { - curr_cue = NULL; - } -} - -bool cuesheet_is_enabled(void) -{ - return (curr_cue != NULL); -} - bool look_for_cuesheet_file(const char *trackpath, char *found_cue_path) { /* DEBUGF("look for cue file\n"); */ @@ -134,7 +107,6 @@ bool parse_cuesheet(char *file, struct cuesheet *cue) char *s; bool utf8 = false; - DEBUGF("cue parse\n"); int fd = open_utf8(file,O_RDONLY); if (fd < 0) { @@ -293,12 +265,8 @@ void browse_cuesheet(struct cuesheet *cue) gui_synclist_set_nb_items(&lists, 2*cue->track_count); gui_synclist_set_title(&lists, title, 0); - if (id3 && *id3->path && strcmp(id3->path, "No file!")) - { - look_for_cuesheet_file(id3->path, cuepath); - } - if (id3 && id3->cuesheet_type && !strcmp(cue->path, cuepath)) + if (id3) { gui_synclist_select_item(&lists, 2*cue_find_current_track(cue, id3->elapsed)); @@ -317,7 +285,7 @@ void browse_cuesheet(struct cuesheet *cue) if (id3 && *id3->path && strcmp(id3->path, "No file!")) { look_for_cuesheet_file(id3->path, cuepath); - if (id3->cuesheet_type && !strcmp(cue->path, cuepath)) + if (id3->cuesheet && !strcmp(cue->path, cuepath)) { sel = gui_synclist_get_sel_pos(&lists); seek(cue->tracks[sel/2].offset); @@ -351,8 +319,9 @@ bool display_cuesheet_content(char* filename) */ bool curr_cuesheet_skip(int direction, unsigned long curr_pos) { + struct cuesheet *curr_cue = audio_current_track()->cuesheet; int track = cue_find_current_track(curr_cue, curr_pos); - + if (direction >= 0 && track == curr_cue->track_count - 1) { /* we want to get out of the cuesheet */ @@ -406,6 +375,7 @@ static inline void draw_veritcal_line_mark(struct screen * screen, void cue_draw_markers(struct screen *screen, unsigned long tracklen, int x1, int x2, int y, int h) { + struct cuesheet *curr_cue = audio_current_track()->cuesheet; int i,xi; int w = x2 - x1; for (i=1; i < curr_cue->track_count; i++) @@ -415,3 +385,17 @@ void cue_draw_markers(struct screen *screen, unsigned long tracklen, } } #endif + +bool cuesheet_subtrack_changed(struct mp3entry *id3) +{ + struct cuesheet *cue = id3->cuesheet; + if (cue && (id3->elapsed < cue->curr_track->offset + || (cue->curr_track_idx < cue->track_count - 1 + && id3->elapsed >= (cue->curr_track+1)->offset))) + { + cue_find_current_track(cue, id3->elapsed); + cue_spoof_id3(cue, id3); + return true; + } + return false; +} diff --git a/apps/cuesheet.h b/apps/cuesheet.h index 41ee9be397..22ad92fdd3 100644 --- a/apps/cuesheet.h +++ b/apps/cuesheet.h @@ -52,14 +52,6 @@ struct cuesheet { struct cue_track_info *curr_track; }; -extern struct cuesheet *curr_cue; - -/* returns true if cuesheet support is initialised */ -bool cuesheet_is_enabled(void); - -/* allocates the cuesheet buffer */ -void cuesheet_init(void); - /* looks if there is a cuesheet file that has a name matching "trackpath" */ bool look_for_cuesheet_file(const char *trackpath, char *found_cue_path); @@ -90,4 +82,7 @@ void cue_draw_markers(struct screen *screen, unsigned long tracklen, int x1, int x2, int y, int h); #endif +/* check if the subtrack has changed */ +bool cuesheet_subtrack_changed(struct mp3entry *id3); + #endif diff --git a/apps/gui/gwps-common.c b/apps/gui/gwps-common.c index c0923a9ab5..dd6ac02d85 100644 --- a/apps/gui/gwps-common.c +++ b/apps/gui/gwps-common.c @@ -355,18 +355,8 @@ bool gui_wps_update(struct gui_wps *gwps) { struct mp3entry *id3 = gwps->state->id3; bool retval; - if (cuesheet_is_enabled() && id3->cuesheet_type - && (id3->elapsed < curr_cue->curr_track->offset - || (curr_cue->curr_track_idx < curr_cue->track_count - 1 - && id3->elapsed >= (curr_cue->curr_track+1)->offset))) - { - /* We've changed tracks within the cuesheet : - we need to update the ID3 info and refresh the WPS */ - gwps->state->do_full_update = true; - cue_find_current_track(curr_cue, id3->elapsed); - cue_spoof_id3(curr_cue, id3); - } - + gwps->state->do_full_update = gwps->state->do_full_update || + cuesheet_subtrack_changed(id3); retval = gui_wps_redraw(gwps, 0, gwps->state->do_full_update ? WPS_REFRESH_ALL : WPS_REFRESH_NON_STATIC); @@ -421,7 +411,7 @@ static void draw_progressbar(struct gui_wps *gwps, pb->x, pb->x + pb->width, y, pb->height); #endif - if ( cuesheet_is_enabled() && state->id3->cuesheet_type ) + if (state->id3->cuesheet) cue_draw_markers(display, state->id3->length, pb->x, pb->x + pb->width, y+1, pb->height-2); } diff --git a/apps/gui/gwps.c b/apps/gui/gwps.c index 9eea925220..eb1437c910 100644 --- a/apps/gui/gwps.c +++ b/apps/gui/gwps.c @@ -148,7 +148,7 @@ static void prev_track(unsigned long skip_thresh) } else { - if (cuesheet_is_enabled() && wps_state.id3->cuesheet_type) + if (wps_state.id3->cuesheet) { curr_cuesheet_skip(-1, wps_state.id3->elapsed); return; @@ -173,7 +173,7 @@ static void prev_track(unsigned long skip_thresh) static void next_track(void) { /* take care of if we're playing a cuesheet */ - if (cuesheet_is_enabled() && wps_state.id3->cuesheet_type) + if (wps_state.id3->cuesheet) { if (curr_cuesheet_skip(1, wps_state.id3->elapsed)) { @@ -557,7 +557,7 @@ long gui_wps_show(void) break; if (current_tick -last_right < HZ) { - if (cuesheet_is_enabled() && wps_state.id3->cuesheet_type) + if (wps_state.id3->cuesheet) { audio_next(); } @@ -577,7 +577,7 @@ long gui_wps_show(void) break; if (current_tick -last_left < HZ) { - if (cuesheet_is_enabled() && wps_state.id3->cuesheet_type) + if (wps_state.id3->cuesheet) { if (!wps_state.paused) #if (CONFIG_CODEC == SWCODEC) @@ -870,22 +870,10 @@ static void track_changed_callback(void *param) { wps_state.id3 = (struct mp3entry*)param; wps_state.nid3 = audio_next_track(); - - if (cuesheet_is_enabled() && wps_state.id3->cuesheet_type - && strcmp(wps_state.id3->path, curr_cue->audio_filename)) + if (wps_state.id3->cuesheet) { - /* the current cuesheet isn't the right one any more */ - /* We need to parse the new cuesheet */ - char cuepath[MAX_PATH]; - - if (look_for_cuesheet_file(wps_state.id3->path, cuepath) && - parse_cuesheet(cuepath, curr_cue)) - { - wps_state.id3->cuesheet_type = 1; - strcpy(curr_cue->audio_filename, wps_state.id3->path); - } - - cue_spoof_id3(curr_cue, wps_state.id3); + cue_find_current_track(wps_state.id3->cuesheet, wps_state.id3->elapsed); + cue_spoof_id3(wps_state.id3->cuesheet, wps_state.id3); } wps_state.do_full_update = true; } diff --git a/apps/main.c b/apps/main.c index a7c8bef6c0..929c946334 100644 --- a/apps/main.c +++ b/apps/main.c @@ -110,8 +110,6 @@ #include "m5636.h" #endif -#include "cuesheet.h" - #ifdef SIMULATOR #include "sim_tasks.h" #include "system-sdl.h" @@ -336,7 +334,6 @@ static void init(void) #endif /* CONFIG_CODEC != SWCODEC */ scrobbler_init(); - cuesheet_init(); #if CONFIG_CODEC == SWCODEC tdspeed_init(); #endif /* CONFIG_CODEC == SWCODEC */ @@ -552,7 +549,6 @@ static void init(void) tree_mem_init(); filetype_init(); scrobbler_init(); - cuesheet_init(); #if CONFIG_CODEC == SWCODEC tdspeed_init(); #endif /* CONFIG_CODEC == SWCODEC */ diff --git a/apps/menus/playback_menu.c b/apps/menus/playback_menu.c index 28e8601282..1e8670ebea 100644 --- a/apps/menus/playback_menu.c +++ b/apps/menus/playback_menu.c @@ -157,7 +157,7 @@ static int cuesheet_callback(int action,const struct menu_item_ex *this_item) switch (action) { case ACTION_EXIT_MENUITEM: /* on exit */ - if (!cuesheet_is_enabled() && global_settings.cuesheet) + if (global_settings.cuesheet) splash(HZ*2, ID2P(LANG_PLEASE_REBOOT)); break; } diff --git a/apps/metadata.c b/apps/metadata.c index b995e11d95..a0409a83ac 100644 --- a/apps/metadata.c +++ b/apps/metadata.c @@ -394,13 +394,6 @@ bool get_metadata(struct mp3entry* id3, int fd, const char* trackname) } /* We have successfully read the metadata from the file */ - -#ifndef __PCTOOL__ - if (cuesheet_is_enabled() && look_for_cuesheet_file(trackname, NULL)) - { - id3->cuesheet_type = 1; - } -#endif lseek(fd, 0, SEEK_SET); strlcpy(id3->path, trackname, sizeof(id3->path)); diff --git a/apps/metadata.h b/apps/metadata.h index 6c0201781a..f3b50c947d 100644 --- a/apps/metadata.h +++ b/apps/metadata.h @@ -239,7 +239,7 @@ struct mp3entry { #endif /* Cuesheet support */ - int cuesheet_type; /* 0: none, 1: external, 2: embedded */ + struct cuesheet *cuesheet; /* Musicbrainz Track ID */ char* mb_track_id; diff --git a/apps/mpeg.c b/apps/mpeg.c index 0e1217b5c8..5db0272752 100644 --- a/apps/mpeg.c +++ b/apps/mpeg.c @@ -40,6 +40,8 @@ #include "sound.h" #include "bitswap.h" #include "appevents.h" +#include "cuesheet.h" +#include "settings.h" #ifndef SIMULATOR #include "i2c.h" #include "mas.h" @@ -116,8 +118,9 @@ static int track_read_idx = 0; static int track_write_idx = 0; #endif /* !SIMULATOR */ -/* Cuesheet callback */ -static bool (*cuesheet_callback)(const char *filename) = NULL; +/* Cuesheet support */ +static struct cuesheet *curr_cuesheet = NULL; +static bool checked_for_cuesheet = false; static const char mpeg_thread_name[] = "mpeg"; static unsigned int mpeg_errno; @@ -265,6 +268,7 @@ static void remove_current_tag(void) { /* First move the index, so nobody tries to access the tag */ track_read_idx = (track_read_idx+1) & MAX_TRACK_ENTRIES_MASK; + checked_for_cuesheet = false; debug_tags(); } else @@ -470,11 +474,6 @@ unsigned long mpeg_get_last_header(void) #endif /* !SIMULATOR */ } -void audio_set_cuesheet_callback(bool (*handler)(const char *filename)) -{ - cuesheet_callback = handler; -} - #ifndef SIMULATOR /* Send callback events to notify about removing old tracks. */ static void generate_unbuffer_events(void) @@ -878,9 +877,6 @@ static struct trackdata *add_track_to_tag_list(const char *filename) if (track->id3.album) lcd_getstringsize(track->id3.album, NULL, NULL); #endif - if (cuesheet_callback) - if (cuesheet_callback(filename)) - track->id3.cuesheet_type = 1; /* if this track is the next track then let the UI know it can get it */ send_nid3_event = (track_write_idx == track_read_idx + 1); @@ -2047,10 +2043,28 @@ static void mpeg_thread(void) struct mp3entry* audio_current_track() { #ifdef SIMULATOR - return &taginfo; + struct mp3entry *id3 = &taginfo; #else /* !SIMULATOR */ if(num_tracks_in_memory()) - return &get_trackdata(0)->id3; + { + struct mp3entry *id3 = &get_trackdata(0)->id3; +#endif + if (!checked_for_cuesheet && curr_cuesheet && id3->cuesheet == NULL) + { + checked_for_cuesheet = true; /* only check once per track */ + char cuepath[MAX_PATH]; + + if (look_for_cuesheet_file(id3->path, cuepath) && + parse_cuesheet(cuepath, curr_cuesheet)) + { + strcpy(curr_cuesheet->audio_filename, id3->path); + id3->cuesheet = curr_cuesheet; + cue_spoof_id3(curr_cuesheet, id3); + } + } + return id3; +#ifndef SIMULATOR + } else return NULL; #endif /* !SIMULATOR */ @@ -2819,6 +2833,19 @@ static void mpeg_thread(void) { id3->elapsed+=1000; id3->offset+=1000; + if (id3->cuesheet) + { + struct cuesheet *cue = id3->cuesheet; + unsigned elapsed = id3->elapsed; + if (elapsed < cue->curr_track->offset || + (cue->curr_track_idx < cue->track_count-1 && + elapsed >= (cue->curr_track+1)->offset)) + { + cue_find_current_track(id3->cuesheet, id3->elapsed); + cue_spoof_id3(id3->cuesheet, id3); + send_event(PLAYBACK_EVENT_CUESHEET_TRACK_CHANGE, id3); + } + } } if (id3->elapsed>=id3->length) audio_next(); @@ -2831,6 +2858,9 @@ static void mpeg_thread(void) void audio_init(void) { mpeg_errno = 0; + /* cuesheet support */ + if (global_settings.cuesheet) + curr_cuesheet = (struct cuesheet*)buffer_alloc(sizeof(struct cuesheet)); #ifndef SIMULATOR audiobuflen = audiobufend - audiobuf; diff --git a/apps/onplay.c b/apps/onplay.c index 9f38b32fb4..ad71f7302e 100644 --- a/apps/onplay.c +++ b/apps/onplay.c @@ -967,9 +967,9 @@ MENUITEM_FUNCTION(rating_item, 0, ID2P(LANG_MENU_SET_RATING), static bool view_cue(void) { struct mp3entry* id3 = audio_current_track(); - if(id3 && cuesheet_is_enabled() && id3->cuesheet_type) + if(id3 && id3->cuesheet) { - browse_cuesheet(curr_cue); + browse_cuesheet(id3->cuesheet); } return false; } @@ -981,8 +981,8 @@ static int view_cue_item_callback(int action, switch (action) { case ACTION_REQUEST_MENUITEM: - if (!selected_file || !cuesheet_is_enabled() - || !id3 || !id3->cuesheet_type) + if (!selected_file + || !id3 || !id3->cuesheet) return ACTION_EXIT_MENUITEM; break; } diff --git a/apps/playback.c b/apps/playback.c index cee89d3bbb..7bd3f252ae 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -210,6 +210,9 @@ static struct mp3entry *thistrack_id3, /* the currently playing track */ * next track otherwise */ static struct mp3entry unbuffered_id3; /* the id3 for the first unbuffered track */ +/* for cuesheet support */ +static struct cuesheet *curr_cue = NULL; + /* Track info structure about songs in the file buffer (A/C-) */ struct track_info { int audio_hid; /* The ID for the track's buffer handle */ @@ -218,6 +221,7 @@ struct track_info { #ifdef HAVE_ALBUMART int aa_hid; /* The ID for the track's album art handle */ #endif + int cuesheet_hid; /* The ID for the track's parsed cueesheet handle */ size_t filesize; /* File total length */ @@ -384,6 +388,13 @@ static bool clear_track_info(struct track_info *track) } #endif + if (track->cuesheet_hid >= 0) { + if (bufclose(track->cuesheet_hid)) + track->cuesheet_hid = -1; + else + return false; + } + track->filesize = 0; track->taginfo_ready = false; @@ -566,6 +577,12 @@ struct mp3entry* audio_current_track(void) if (cur_idx == track_ridx && *thistrack_id3->path) { /* The usual case */ + if (tracks[cur_idx].cuesheet_hid >= 0) + { + bufread(tracks[cur_idx].cuesheet_hid, sizeof(struct cuesheet), curr_cue); + thistrack_id3->cuesheet = curr_cue; + cue_spoof_id3(thistrack_id3->cuesheet, thistrack_id3); + } return thistrack_id3; } else if (automatic_skip && offset == -1 && *othertrack_id3->path) @@ -574,6 +591,12 @@ struct mp3entry* audio_current_track(void) but the audio being played is still the same (now previous) track. othertrack_id3.elapsed is being updated in an ISR by codec_pcmbuf_position_callback */ + if (tracks[cur_idx].cuesheet_hid >= 0) + { + bufread(tracks[cur_idx].cuesheet_hid, sizeof(struct cuesheet), curr_cue); + othertrack_id3->cuesheet = curr_cue; + cue_spoof_id3(othertrack_id3->cuesheet, othertrack_id3); + } return othertrack_id3; } @@ -1826,7 +1849,21 @@ static void audio_finish_load_track(void) return; } + /* Try to load a cuesheet for the track */ + if (curr_cue) + { + char cuepath[MAX_PATH]; + struct cuesheet temp_cue; + + if (look_for_cuesheet_file(track_id3->path, cuepath) && + parse_cuesheet(cuepath, &temp_cue)) + { + strcpy(temp_cue.audio_filename, track_id3->path); + tracks[track_widx].cuesheet_hid = + bufalloc(&temp_cue, sizeof(struct cuesheet), TYPE_CUESHEET); + } + } #ifdef HAVE_ALBUMART if (tracks[track_widx].aa_hid < 0 && gui_sync_wps_uses_albumart()) { @@ -2602,6 +2639,10 @@ void audio_init(void) thistrack_id3 = &mp3entry_buf[0]; othertrack_id3 = &mp3entry_buf[1]; + /* cuesheet support */ + if (global_settings.cuesheet) + curr_cue = (struct cuesheet*)buffer_alloc(sizeof(struct cuesheet)); + /* initialize the buffer */ filebuf = audiobuf; @@ -2648,6 +2689,7 @@ void audio_init(void) #ifdef HAVE_ALBUMART tracks[i].aa_hid = -1; #endif + tracks[i].cuesheet_hid = -1; } add_event(BUFFER_EVENT_REBUFFER, false, buffering_handle_rebuffer_callback);