diff options
-rw-r--r-- | apps/plugins/pictureflow/pictureflow.c | 1739 |
1 files changed, 1208 insertions, 531 deletions
diff --git a/apps/plugins/pictureflow/pictureflow.c b/apps/plugins/pictureflow/pictureflow.c index 7d94eeb31f..91174604ea 100644 --- a/apps/plugins/pictureflow/pictureflow.c +++ b/apps/plugins/pictureflow/pictureflow.c @@ -236,7 +236,7 @@ typedef fb_data pix_t; #define THREAD_STACK_SIZE DEFAULT_STACK_SIZE + 0x200 #define CACHE_PREFIX PLUGIN_DEMOS_DATA_DIR "/pictureflow" -#define ALBUM_INDEX CACHE_PREFIX "/PF_album_idx.tmp" +#define ALBUM_INDEX CACHE_PREFIX "/pictureflow_album.idx" #define EV_EXIT 9999 #define EV_WAKEUP 1337 @@ -250,16 +250,83 @@ typedef fb_data pix_t; #define CACHE_UPDATE 1 /* Error return values */ +#define SUCCESS 0 #define ERROR_NO_ALBUMS -1 #define ERROR_BUFFER_FULL -2 #define ERROR_NO_ARTISTS -3 +#define ERROR_USER_ABORT -4 /* current version for cover cache */ #define CACHE_VERSION 3 #define CONFIG_VERSION 1 #define CONFIG_FILE "pictureflow.cfg" +#define INDEX_HDR "PFID" /** structs we use */ +struct pf_config_t +{ + /* config values */ + int slide_spacing; + int center_margin; + + int num_slides; + int zoom; + + int auto_wps; + int last_album; + + int backlight_mode; + int cache_version; + + int show_album_name; + bool resize; + bool show_fps; +}; + +struct pf_index_t { + uint32_t header; /*INDEX_HDR*/ + uint16_t artist_ct; + uint16_t album_ct; + + char *artist_names; + struct artist_data *artist_index; + size_t artist_len; + + unsigned int album_untagged_idx; + char *album_names; + struct album_data *album_index; + size_t album_len; + long album_untagged_seek; + + void * buf; + size_t buf_sz; +}; + +struct pf_track_t { + int count; + int cur_idx; + int sel; + int sel_pulse; + int last_sel; + int list_start; + int list_visible; + int list_y; + int list_h; + size_t borrowed; + struct track_data *index; + char *names; +}; + +struct albumart_t { + struct bitmap input_bmp; + char pfraw_file[MAX_PATH]; + char file[MAX_PATH]; + int idx; + int slides; + int inspected; + void * buf; + size_t buf_sz; +}; struct slide_data { int slide_index; @@ -277,14 +344,15 @@ struct slide_cache { }; struct album_data { - int name_idx; - int artist_idx; - long seek; + int name_idx; /* offset to the album name */ + int artist_idx; /* offset to the artist name */ + long artist_seek; /* artist taglist position */ + long seek; /* album taglist position */ }; struct artist_data { - int name_idx; - long seek; + int name_idx; /* offset to the artist name */ + long seek; /* artist taglist position */ }; struct track_data { @@ -309,6 +377,16 @@ struct load_slide_event_data { int cache_index; }; +struct pf_slide_cache +{ + struct slide_cache cache[SLIDE_CACHE_SIZE]; + int free; + int used; + int left_idx; + int right_idx; + int center_idx; +}; + enum pf_scroll_line_type { PF_SCROLL_TRACK = 0, PF_SCROLL_ALBUM, @@ -354,37 +432,27 @@ static char* show_album_name_conf[] = #define MAX_SPACING 40 #define MAX_MARGIN 80 -/* config values and their defaults */ -static int slide_spacing = DISPLAY_WIDTH / 4; -static int center_margin = (LCD_WIDTH - DISPLAY_WIDTH) / 12; -static int num_slides = 4; -static int zoom = 100; -static bool show_fps = false; -static int auto_wps = 0; -static int last_album = 0; -static int backlight_mode = 0; -static bool resize = true; -static int cache_version = 0; -static int show_album_name = (LCD_HEIGHT > 100) - ? ALBUM_NAME_TOP : ALBUM_NAME_BOTTOM; +static struct albumart_t aa_cache; +static struct pf_config_t pf_cfg; static struct configdata config[] = { - { TYPE_INT, 0, MAX_SPACING, { .int_p = &slide_spacing }, "slide spacing", + { TYPE_INT, 0, MAX_SPACING, { .int_p = &pf_cfg.slide_spacing }, "slide spacing", NULL }, - { TYPE_INT, 0, MAX_MARGIN, { .int_p = ¢er_margin }, "center margin", + { TYPE_INT, 0, MAX_MARGIN, { .int_p = &pf_cfg.center_margin }, "center margin", NULL }, - { TYPE_INT, 0, MAX_SLIDES_COUNT, { .int_p = &num_slides }, "slides count", + { TYPE_INT, 0, MAX_SLIDES_COUNT, { .int_p = &pf_cfg.num_slides }, "slides count", NULL }, - { TYPE_INT, 0, 300, { .int_p = &zoom }, "zoom", NULL }, - { TYPE_BOOL, 0, 1, { .bool_p = &show_fps }, "show fps", NULL }, - { TYPE_BOOL, 0, 1, { .bool_p = &resize }, "resize", NULL }, - { TYPE_INT, 0, 100, { .int_p = &cache_version }, "cache version", NULL }, - { TYPE_ENUM, 0, 5, { .int_p = &show_album_name }, "show album name", + { TYPE_INT, 0, 300, { .int_p = &pf_cfg.zoom }, "zoom", NULL }, + { TYPE_BOOL, 0, 1, { .bool_p = &pf_cfg.show_fps }, "show fps", NULL }, + { TYPE_BOOL, 0, 1, { .bool_p = &pf_cfg.resize }, "resize", NULL }, + { TYPE_INT, 0, 100, { .int_p = &pf_cfg.cache_version }, "cache version", NULL }, + { TYPE_ENUM, 0, 5, { .int_p = &pf_cfg.show_album_name }, "show album name", show_album_name_conf }, - { TYPE_INT, 0, 2, { .int_p = &auto_wps }, "auto wps", NULL }, - { TYPE_INT, 0, 999999, { .int_p = &last_album }, "last album", NULL }, - { TYPE_INT, 0, 1, { .int_p = &backlight_mode }, "backlight", NULL } + { TYPE_INT, 0, 2, { .int_p = &pf_cfg.auto_wps }, "auto wps", NULL }, + { TYPE_INT, 0, 999999, { .int_p = &pf_cfg.last_album }, "last album", NULL }, + { TYPE_INT, 0, 1, { .int_p = &pf_cfg.backlight_mode }, "backlight", NULL }, + { TYPE_INT, 0, 999999, { .int_p = &aa_cache.idx }, "art cache pos", NULL }, }; #define CONFIG_NUM_ITEMS (sizeof(config) / sizeof(struct configdata)) @@ -406,12 +474,7 @@ static PFreal offsetX; static PFreal offsetY; static int number_of_slides; -static struct slide_cache cache[SLIDE_CACHE_SIZE]; -static int cache_free; -static int cache_used = -1; -static int cache_left_index = -1; -static int cache_right_index = -1; -static int cache_center_index = -1; +static struct pf_slide_cache pf_sldcache; /* use long for aligning */ unsigned long thread_stack[THREAD_STACK_SIZE / sizeof(long)]; @@ -426,29 +489,12 @@ static struct tagcache_search tcs; static struct buflib_context buf_ctx; -static struct album_data *album; -static struct artist_data *artist; +static struct pf_index_t pf_idx; -static char *album_names; -static int album_count; +static struct pf_track_t pf_tracks; -static char *artist_names; -static int artist_count; - -static struct track_data *tracks; -static char *track_names; -static size_t borrowed = 0; -static int track_count; -static int track_index; -static int selected_track; -static int selected_track_pulse; void reset_track_list(void); -void * buf; -size_t buf_size; -void * uniqbuf; -size_t uniqbuf_size; - static bool thread_is_running; static int cover_animation_keyframe; @@ -456,14 +502,8 @@ static int extra_fade; static struct pf_scroll_line_info scroll_line_info; static struct pf_scroll_line scroll_lines[PF_MAX_SCROLL_LINES]; -static int prev_albumtxt_index = -1; -static int last_selected_track = -1; - -static int start_index_track_list = 0; -static int track_list_visible_entries = 0; -static int track_list_y; -static int track_list_h; +enum ePFS{ePFS_ARTIST = 0, ePFS_ALBUM}; /* Proposals for transitions: @@ -494,6 +534,45 @@ static int pf_state; static bool free_slide_prio(int prio); bool load_new_slide(void); int load_surface(int); +static void draw_progressbar(int step, int count, char *msg); +static void draw_splashscreen(unsigned char * buf_tmp, size_t buf_tmp_size); +static void free_all_slide_prio(int prio); + +static bool confirm_quit(void) +{ + const struct text_message prompt = + { (const char*[]) {"Quit?", "Progress will be lost"}, 2}; + enum yesno_res response = rb->gui_syncyesno_run(&prompt, NULL, NULL); + while (rb->button_get(false) == BUTTON_NONE) + ;; + + if(response == YESNO_NO) + return false; + else + return true; +} + +static void config_save(int cache_version) +{ + pf_cfg.cache_version = cache_version; + configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); +} + +static void config_set_defaults(struct pf_config_t *cfg) +{ + cfg->slide_spacing = DISPLAY_WIDTH / 4; + cfg->center_margin = (LCD_WIDTH - DISPLAY_WIDTH) / 12; + cfg->num_slides = 4; + cfg->zoom = 100; + cfg->show_fps = false; + cfg->auto_wps = 0; + cfg->last_album = 0; + cfg->backlight_mode = 0; + cfg->resize = true; + cfg->cache_version = 0; + cfg->show_album_name = (LCD_HEIGHT > 100) + ? ALBUM_NAME_TOP : ALBUM_NAME_BOTTOM; +} static inline PFreal fmul(PFreal a, PFreal b) { @@ -849,135 +928,538 @@ static void init_reflect_table(void) (5 * REFLECT_HEIGHT); } -/** - Create an index of all artists and albums from the database. - Also store the artists and album names so we can access them later. - */ -static int create_album_index(void) +static int compare_album_artists (const void *a_v, const void *b_v) { - artist = ((struct artist_data *)(buf_size + (char *) buf)) - 1; - rb->memset(&tcs, 0, sizeof(struct tagcache_search) ); - artist_count = 0; - rb->tagcache_search(&tcs, tag_albumartist); + uint32_t a = ((struct album_data *)a_v)->artist_idx; + uint32_t b = ((struct album_data *)b_v)->artist_idx; + return (int)(a - b); +} + +static void write_album_index(int idx, int name_idx, + long album_seek, int artist_idx, long artist_seek) +{ + pf_idx.album_index[idx].name_idx = name_idx; + pf_idx.album_index[idx].seek = album_seek; + pf_idx.album_index[idx].artist_idx = artist_idx; + pf_idx.album_index[idx].artist_seek = artist_seek; +} + +static inline void write_album_entry(struct tagcache_search *tcs, + int name_idx, unsigned int len) +{ + write_album_index(-pf_idx.album_ct, name_idx, tcs->result_seek, 0, -1); + pf_idx.album_len += len; + pf_idx.album_ct++; + + if (pf_idx.album_untagged_seek == -1 && rb->strcmp(UNTAGGED, tcs->result) == 0) + { + pf_idx.album_untagged_idx = name_idx; + pf_idx.album_untagged_seek = tcs->result_seek; + } +} + +static void write_artist_entry(struct tagcache_search *tcs, + int name_idx, unsigned int len) +{ + pf_idx.artist_index[-pf_idx.artist_ct].name_idx = name_idx; + pf_idx.artist_index[-pf_idx.artist_ct].seek = tcs->result_seek; + pf_idx.artist_len += len; + pf_idx.artist_ct++; +} + +/* adds tagcache_search results into artist/album index */ +static int get_tcs_search_res(int type, struct tagcache_search *tcs, + void **buf, size_t *bufsz) +{ + int ret = SUCCESS; unsigned int l, name_idx = 0; - artist_names = buf; - while (rb->tagcache_get_next(&tcs)) + void (*writefn)(struct tagcache_search *, int, unsigned int); + int data_size; + if (type == ePFS_ARTIST) + { + writefn = &write_artist_entry; + data_size = sizeof(struct artist_data); + } + else + { + writefn = &write_album_entry; + data_size = sizeof(struct album_data); + } + + while (rb->tagcache_get_next(tcs)) { - buf_size -= sizeof(struct artist_data); - l = tcs.result_len; - artist[-artist_count].name_idx = name_idx; - artist[-artist_count].seek = tcs.result_seek; - if ( l > buf_size ) + if (rb->button_get(false) > BUTTON_NONE) + { + if (confirm_quit()) + { + ret = ERROR_USER_ABORT; + break; + } else + rb->lcd_clear_display(); + } + + *bufsz -= data_size; + + l = tcs->result_len; + + if ( l > *bufsz ) + { /* not enough memory */ - return ERROR_BUFFER_FULL; - rb->strcpy(buf, tcs.result); - buf_size -= l; - buf = l + (char *)buf; + ret = ERROR_BUFFER_FULL; + break; + } + + rb->strcpy(*buf, tcs->result); + + *bufsz -= l; + *buf = l + (char *)*buf; + + writefn(tcs, name_idx, l); + name_idx += l; - artist_count++; } + rb->tagcache_search_finish(tcs); + return ret; +} + +/*adds <untagged> albums/artist to existing album index */ +static int create_album_untagged(struct tagcache_search *tcs, + void **buf, size_t *bufsz) +{ + int ret = SUCCESS; + int album_count = pf_idx.album_ct; /* store existing count */ + int total_count = pf_idx.album_ct + pf_idx.artist_ct * 2; + long seek; + int last, final, retry; + int i, j; + draw_splashscreen(*buf, *bufsz); + draw_progressbar(0, total_count, "Searching " UNTAGGED); + + /* search tagcache for all <untagged> albums & save the albumartist seek pos */ + if (rb->tagcache_search(tcs, tag_albumartist)) + { + rb->tagcache_search_add_filter(tcs, tag_album, pf_idx.album_untagged_seek); + + while (rb->tagcache_get_next(tcs)) + { + if (rb->button_get(false) > BUTTON_NONE) { + if (confirm_quit()) + return ERROR_USER_ABORT; + else + { + rb->lcd_clear_display(); + draw_progressbar(pf_idx.album_ct, total_count, + "Searching " UNTAGGED); + } + } + + if (tcs->result_seek == + pf_idx.album_index[-(pf_idx.album_ct - 1)].artist_seek) + continue; + + if (sizeof(struct album_data) > *bufsz) + { + /* not enough memory */ + ret = ERROR_BUFFER_FULL; + break; + } + + *bufsz -= sizeof(struct album_data); + write_album_index(-pf_idx.album_ct, pf_idx.album_untagged_idx, + pf_idx.album_untagged_seek, -1, tcs->result_seek); + + pf_idx.album_ct++; + draw_progressbar(pf_idx.album_ct, total_count, NULL); + } + rb->tagcache_search_finish(tcs); + + if (ret == SUCCESS) { + draw_splashscreen(*buf, *bufsz); + draw_progressbar(0, pf_idx.album_ct, "Finalizing " UNTAGGED); + + last = 0; + final = pf_idx.artist_ct; + retry = 0; + + /* map the artist_seek position to the artist name index */ + for (j = album_count; j < pf_idx.album_ct; j++) + { + if (rb->button_get(false) > BUTTON_NONE) { + if (confirm_quit()) + return ERROR_USER_ABORT; + else + { + rb->lcd_clear_display(); + draw_progressbar(j, pf_idx.album_ct, "Finalizing " UNTAGGED); + } + } + + draw_progressbar(j, pf_idx.album_ct, NULL); + seek = pf_idx.album_index[-j].artist_seek; + + retry_artist_lookup: + retry++; + for (i = last; i < final; i++) + { + if (seek == pf_idx.artist_index[i].seek) + { + int idx = pf_idx.artist_index[i].name_idx; + pf_idx.album_index[-j].artist_idx = idx; + last = i; /* last match, start here next loop */ + final = pf_idx.artist_ct; + retry = 0; + break; + } + } + if (retry > 0 && retry < 2) + { + /* no match start back at beginning */ + final = last; + last = 0; + goto retry_artist_lookup; + } + } + } + } + + return ret; +} + +/* Create an index of all artists from the database */ +static int build_artist_index(struct tagcache_search *tcs, + void **buf, size_t *bufsz) +{ + int i, res = SUCCESS; + struct artist_data* tmp_artist; + + /* artist index starts at end of buf it will be rearranged when finalized */ + pf_idx.artist_index = ((struct artist_data *)(*bufsz + (char *) *buf)) - 1; + pf_idx.artist_ct = 0; + pf_idx.artist_len = 0; + /* artist names starts at beginning of buf */ + pf_idx.artist_names = *buf; + + rb->tagcache_search(tcs, tag_albumartist); + res = get_tcs_search_res(ePFS_ARTIST, tcs, &(*buf), bufsz); + rb->tagcache_search_finish(tcs); + if (res < SUCCESS) + return res; + + ALIGN_BUFFER(*buf, *bufsz, 4); + + /* finalize the artist index */ + tmp_artist = (struct artist_data*)*buf; + for (i = pf_idx.artist_ct - 1; i >= 0; i--) + tmp_artist[i] = pf_idx.artist_index[-i]; + + pf_idx.artist_index = tmp_artist; + /* move buf ptr to end of artist_index */ + *buf = pf_idx.artist_index + pf_idx.artist_ct; + ALIGN_BUFFER(*buf, *bufsz, 4); + + if (res == SUCCESS) + { + if (pf_idx.artist_ct > 0) + res = pf_idx.artist_ct; + else + res = ERROR_NO_ALBUMS; + } + + return res; +} + + +/** + Create an index of all artists and albums from the database. + Also store the artists and album names so we can access them later. + */ +static int create_album_index(void) +{ + void *buf = pf_idx.buf; + size_t buf_size = pf_idx.buf_sz; + + struct album_data* tmp_album; + + int i, j, last, final, retry, res; + + draw_splashscreen(buf, buf_size); + ALIGN_BUFFER(buf, buf_size, 4); + +/* Artists */ + res = build_artist_index(&tcs, &buf, &buf_size); + if (res < SUCCESS) + return res; + +/* Albums */ + pf_idx.album_ct = 0; + pf_idx.album_len =0; + pf_idx.album_untagged_idx = 0; + pf_idx.album_untagged_seek = -1; + + /* album_index starts at end of buf it will be rearranged when finalized */ + pf_idx.album_index = ((struct album_data *)(buf_size + (char *)buf)) - 1; + /* album_names starts at the beginning of buf */ + pf_idx.album_names = buf; + + rb->tagcache_search(&tcs, tag_album); + res = get_tcs_search_res(ePFS_ALBUM, &tcs, &buf, &buf_size); rb->tagcache_search_finish(&tcs); + if (res < SUCCESS) + return res; ALIGN_BUFFER(buf, buf_size, 4); - int i; - struct artist_data* tmp_artist = (struct artist_data*)buf; - for (i = artist_count - 1; i >= 0; i--) - tmp_artist[i] = artist[-i]; - artist = tmp_artist; - buf = artist + artist_count; - - long artist_seek = 0; - int j = 0; - album_count = 0; - name_idx = 0; - album = ((struct album_data *)(buf_size + (char *) buf)) - 1; - album_names = buf; - for (j = 0; j < artist_count; j++){ - artist_seek = artist[j].seek; - rb->memset(&tcs, 0, sizeof(struct tagcache_search) ); - rb->tagcache_search(&tcs, tag_album); - /* Prevent duplicate entries in the search list. */ - rb->tagcache_search_set_uniqbuf(&tcs, uniqbuf, uniqbuf_size); - rb->tagcache_search_add_filter(&tcs, tag_albumartist, artist_seek); - while (rb->tagcache_get_next(&tcs)) + + /* Build artist list for untagged albums */ + res = create_album_untagged(&tcs, &buf, &buf_size); + + if (res < SUCCESS) + return res; + + ALIGN_BUFFER(buf, buf_size, 4); + + /* finalize the album index */ + tmp_album = (struct album_data*)buf; + for (i = pf_idx.album_ct - 1; i >= 0; i--) + tmp_album[i] = pf_idx.album_index[-i]; + + pf_idx.album_index = tmp_album; + /* move buf ptr to end of album_index */ + buf = pf_idx.album_index + pf_idx.album_ct; + ALIGN_BUFFER(buf, buf_size, 4); + +/* Assign indices */ + draw_splashscreen(buf, buf_size); + draw_progressbar(0, pf_idx.album_ct, "Assigning Albums"); + for (j = 0; j < pf_idx.album_ct; j++) + { + if (rb->button_get(false) > BUTTON_NONE) + { + if (confirm_quit()) + return ERROR_USER_ABORT; + else + { + rb->lcd_clear_display(); + draw_progressbar(j, pf_idx.album_ct, "Assigning Albums"); + } + + } + + draw_progressbar(j, pf_idx.album_ct, NULL); + if (pf_idx.album_index[j].artist_seek >= 0) { continue; } + + rb->tagcache_search(&tcs, tag_albumartist); + rb->tagcache_search_add_filter(&tcs, tag_album, pf_idx.album_index[j].seek); + + last = 0; + final = pf_idx.artist_ct; + retry = 0; + if (rb->tagcache_get_next(&tcs)) { - buf_size -= sizeof(struct album_data); - l = tcs.result_len; - album[-album_count].name_idx = name_idx; - album[-album_count].seek = tcs.result_seek; - album[-album_count].artist_idx = j; - if ( l > buf_size ) - /* not enough memory */ - return ERROR_BUFFER_FULL; - rb->strcpy(buf, tcs.result); - buf_size -= l; - buf = l + (char *)buf; - name_idx += l; - album_count++; +retry_artist_lookup: + retry++; + for (i = last; i < final; i++) + { + if (tcs.result_seek == pf_idx.artist_index[i].seek) + { + int idx = pf_idx.artist_index[i].name_idx; + pf_idx.album_index[j].artist_idx = idx; + pf_idx.album_index[j].artist_seek = tcs.result_seek; + last = i; /* last match, start here next loop */ + final = pf_idx.artist_ct; + retry = 0; + break; + } + } + if (retry > 0 && retry < 2) + { + /* no match start back at beginning */ + final = last; + last = 0; + goto retry_artist_lookup; + } } rb->tagcache_search_finish(&tcs); } + /* sort list order to find duplicates */ + rb->qsort(pf_idx.album_index, pf_idx.album_ct, + sizeof(struct album_data), compare_album_artists); + + draw_splashscreen(buf, buf_size); + draw_progressbar(0, pf_idx.album_ct, "Removing duplicates"); + /* mark duplicate albums for deletion */ + for (i = 0; i < pf_idx.album_ct - 1; i++) /* -1 don't check last entry */ + { + int idxi = pf_idx.album_index[i].artist_idx; + int seeki = pf_idx.album_index[i].seek; + + draw_progressbar(i, pf_idx.album_ct, NULL); + for (j = i + 1; j < pf_idx.album_ct; j++) + { + if (idxi > 0 && + idxi == pf_idx.album_index[j].artist_idx && + seeki == pf_idx.album_index[j].seek) + { + pf_idx.album_index[j].artist_idx = -1; + } + else + { + i = j - 1; + break; + } + } + } + + /* now fix the album list order */ + rb->qsort(pf_idx.album_index, pf_idx.album_ct, + sizeof(struct album_data), compare_album_artists); + + /* remove any extra untagged albums + * extra space is orphaned till restart */ + for (i = 0; i < pf_idx.album_ct; i++) + { + if (pf_idx.album_index[i].artist_idx > 0) + { + if (i > 0) { i--; } + pf_idx.album_index += i; + pf_idx.album_ct -= i; + break; + } + } + ALIGN_BUFFER(buf, buf_size, 4); - struct album_data* tmp_album = (struct album_data*)buf; - for (i = album_count - 1; i >= 0; i--) - tmp_album[i] = album[-i]; - album = tmp_album; - buf = album + album_count; + pf_idx.buf = buf; + pf_idx.buf_sz = buf_size; + pf_idx.artist_index = 0; - return (album_count > 0) ? 0 : ERROR_NO_ALBUMS; + return (pf_idx.album_ct > 0) ? 0 : ERROR_NO_ALBUMS; } - -/*Saves the artists+albums index into a binary file to be recovered the +/*Saves the album index into a binary file to be recovered the next time PictureFlow is launched*/ static int save_album_index(void){ int fd = rb->creat(ALBUM_INDEX,0666); + + struct pf_index_t data; + memcpy(&data, &pf_idx, sizeof(struct pf_index_t)); + if(fd >= 0) { - int unsigned_size = sizeof(unsigned int); - int int_size = sizeof(int); - rb->write(fd, artist_names, ((char *)buf - (char *)artist_names)); - unsigned int artist_pos = (char *)artist - (char *)artist_names; - rb->write(fd, &artist_pos, unsigned_size); - unsigned int album_names_pos = (char *)album_names - (char *)artist_names; - rb->write(fd, &album_names_pos, unsigned_size); - unsigned int album_pos = (char *)album - (char *)artist_names; - rb->write(fd, &album_pos, unsigned_size); - rb->write(fd, &artist_count, int_size); - rb->write(fd, &album_count, int_size); + rb->memcpy(&data.header, INDEX_HDR, sizeof(pf_idx.header)); + + rb->write(fd, &data, sizeof(struct pf_index_t)); + + rb->write(fd, data.artist_names, data.artist_len); + rb->write(fd, data.album_names, data.album_len); + + rb->write(fd, data.album_index, data.album_ct * sizeof(struct album_data)); + rb->close(fd); return 0; } return -1; } -/*Loads the artists+albums index information stored in the hard drive*/ +/* reads data from save file to buffer */ +static inline int read2buf(int fildes, void *buf, size_t nbyte){ + int read; + read = rb->read(fildes, buf, nbyte); + if (read < (int)nbyte) + return 0; + + return read; +} +/*Loads the album_index information stored in the hard drive*/ static int load_album_index(void){ - int fr = rb->open(ALBUM_INDEX, O_RDONLY); + + int i, fr = rb->open(ALBUM_INDEX, O_RDONLY); + struct pf_index_t data; + + void *bufstart = pf_idx.buf; + unsigned int bufstart_sz = pf_idx.buf_sz; + + void* buf = pf_idx.buf; + size_t buf_size = pf_idx.buf_sz; + + unsigned int name_sz, album_idx_sz; + int album_idx, artist_idx; + if (fr >= 0){ - int unsigned_size = sizeof(unsigned int); - int int_size = sizeof(int); - unsigned long filesize = rb->filesize(fr); - unsigned int pos = 0; - unsigned int extra_data_size = (sizeof(unsigned int)*3) + (sizeof(int)*2); - rb->read(fr,buf ,filesize-extra_data_size); - artist_names = buf; - buf = (char *)buf + (filesize-extra_data_size); - buf_size = buf_size-(filesize-extra_data_size); - rb->read(fr,&pos ,unsigned_size); - artist = (void *)artist_names + pos; - rb->read(fr,&pos ,unsigned_size); - album_names = (void *)artist_names + pos; - rb->read(fr,&pos ,unsigned_size); - album = (void *)artist_names + pos; - rb->read(fr,&artist_count ,int_size); - rb->read(fr,&album_count ,int_size); - rb->close(fr); - return 0; + const unsigned long filesize = rb->filesize(fr); + if (filesize > sizeof(data)) + { + if (rb->read(fr, &data, sizeof(data)) == sizeof(data) && + rb->memcmp(&(data.header), INDEX_HDR, sizeof(data.header)) == 0) + { + name_sz = data.artist_len + data.album_len; + album_idx_sz = data.album_ct * sizeof(struct album_data); + + if (name_sz + album_idx_sz > bufstart_sz) + goto failure; + + //rb->lseek(fr, sizeof(data) + 1, SEEK_SET); + /* artist names */ + ALIGN_BUFFER(buf, buf_size, 4); + if (read2buf(fr, buf, data.artist_len) == 0) + goto failure; + + data.artist_names = buf; + buf = (char *)buf + data.artist_len; + buf_size -= data.artist_len; + + /* album names */ + ALIGN_BUFFER(buf, buf_size, 4); + if (read2buf(fr, buf, data.album_len) == 0) + goto failure; + + data.album_names = buf; + buf = (char *)buf + data.album_len; + buf_size -= data.album_len; + + /* index of album names */ + ALIGN_BUFFER(buf, buf_size, 4); + if (read2buf(fr, buf, album_idx_sz) == 0) + goto failure; + + data.album_index = buf; + buf = (char *)buf + album_idx_sz; + buf_size -= album_idx_sz; + + rb->close(fr); + + /* sanity check loaded data */ + for (i = 0; i < data.album_ct; i++) + { + album_idx = data.album_index[i].name_idx; + artist_idx = data.album_index[i].artist_idx; + if (album_idx >= (int) data.album_len || + artist_idx >= (int) data.artist_len) + { + goto failure; + } + } + + memcpy(&pf_idx, &data, sizeof(struct pf_index_t)); + pf_idx.buf = buf; + pf_idx.buf_sz = buf_size; + + return 0; + } + } } + +failure: + rb->splash(HZ/2, "Failed to load index"); + if (fr >= 0) + rb->close(fr); + + pf_idx.buf = bufstart; + pf_idx.buf_sz = bufstart_sz; + pf_idx.artist_ct = 0; + pf_idx.album_ct = 0; return -1; + } /** @@ -985,7 +1467,18 @@ static int load_album_index(void){ */ static char* get_album_name(const int slide_index) { - return album_names + album[slide_index].name_idx; + char *name = pf_idx.album_names + pf_idx.album_index[slide_index].name_idx; + return name; +} + +/** + Return a pointer to the album name of the given slide_index + */ +static char* get_album_name_idx(const int slide_index, int *idx) +{ + *idx = pf_idx.album_index[slide_index].name_idx; + char *name = pf_idx.album_names + pf_idx.album_index[slide_index].name_idx; + return name; } /** @@ -993,13 +1486,14 @@ static char* get_album_name(const int slide_index) */ static char* get_album_artist(const int slide_index) { - if (slide_index < album_count && slide_index >= 0){ - int artist_pos = album[slide_index].artist_idx; - if (artist_pos < artist_count && artist_pos >= 0){ - return artist_names + artist[artist_pos].name_idx; + if (slide_index < pf_idx.album_ct && slide_index >= 0){ + int idx = pf_idx.album_index[slide_index].artist_idx; + if (idx >= 0 && idx < (int) pf_idx.artist_len) { + char *name = pf_idx.artist_names + idx; + return name; } } - return NULL; + return "?"; } @@ -1009,34 +1503,54 @@ static char* get_album_artist(const int slide_index) */ static char* get_track_name(const int track_index) { - if ( track_index < track_count ) - return track_names + tracks[track_index].name_idx; + if (track_index >= 0 && track_index < pf_tracks.count ) + return pf_tracks.names + pf_tracks.index[track_index].name_idx; return 0; } #if PF_PLAYBACK_CAPABLE static char* get_track_filename(const int track_index) { - if ( track_index < track_count ) - return track_names + tracks[track_index].filename_idx; + if ( track_index < pf_tracks.count ) + return pf_tracks.names + pf_tracks.index[track_index].filename_idx; return 0; } #endif static int get_wps_current_index(void) { + char* current_artist = UNTAGGED; + char* current_album = UNTAGGED; struct mp3entry *id3 = rb->audio_current_track(); - if(id3 && id3->album) { + if(id3) + { + /* we could be looking for the artist in either field */ + if(id3->albumartist) + current_artist = id3->albumartist; + else if(id3->artist) + current_artist = id3->artist; + + if (id3->album && rb->strlen(id3->album) > 0) + current_album = id3->album; + + //rb->splashf(1000, "%s, %s", current_album, current_artist); + int i; - for( i=0; i < album_count; i++ ) + int album_idx, artist_idx; + + for (i = 0; i < pf_idx.album_ct; i++ ) { - if(!rb->strcmp(album_names + album[i].name_idx, id3->album) && - !rb->strcmp(artist_names + artist[album[i].artist_idx].name_idx, - id3->albumartist)) + album_idx = pf_idx.album_index[i].name_idx; + artist_idx = pf_idx.album_index[i].artist_idx; + + if(!rb->strcmp(pf_idx.album_names + album_idx, current_album) && + !rb->strcmp(pf_idx.artist_names + artist_idx, current_artist)) return i; } + } - return last_album; + rb->splash(HZ/2, "Album Not Found!"); + return pf_cfg.last_album; } /** @@ -1054,50 +1568,81 @@ static int compare_tracks (const void *a_v, const void *b_v) */ static void create_track_index(const int slide_index) { - if ( slide_index == track_index ) + char temp[MAX_PATH + 1]; + if ( slide_index == pf_tracks.cur_idx ) return; - track_index = slide_index; if (!rb->tagcache_search(&tcs, tag_title)) goto fail; - rb->tagcache_search_add_filter(&tcs, tag_album, album[slide_index].seek); - rb->tagcache_search_add_filter(&tcs, tag_albumartist, - artist[album[slide_index].artist_idx].seek); + rb->tagcache_search_add_filter(&tcs, tag_album, + pf_idx.album_index[slide_index].seek); + + if (pf_idx.album_index[slide_index].artist_idx >= 0) + { + rb->tagcache_search_add_filter(&tcs, tag_albumartist, + pf_idx.album_index[slide_index].artist_seek); + } - track_count=0; int string_index = 0, track_num; int disc_num; + + char* result = NULL; size_t out = 0; - track_names = rb->buflib_buffer_out(&buf_ctx, &out); - borrowed += out; - int avail = borrowed; - tracks = (struct track_data*)(track_names + borrowed); + + pf_tracks.count = 0; + pf_tracks.names = rb->buflib_buffer_out(&buf_ctx, &out); + pf_tracks.borrowed += out; + int avail = pf_tracks.borrowed; + pf_tracks.index = (struct track_data*)(pf_tracks.names + pf_tracks.borrowed); while (rb->tagcache_get_next(&tcs)) { + result = NULL; + if (rb->strcmp(UNTAGGED, tcs.result) == 0) + { + /* show filename instead of <untaggged> */ + if (!rb->tagcache_retrieve(&tcs, tcs.idx_id, tag_filename, + temp, sizeof(temp) - 1)) + { + goto fail; + } + result = temp; + } + int len = 0, fn_idx = 0; avail -= sizeof(struct track_data); track_num = rb->tagcache_get_numeric(&tcs, tag_tracknumber); disc_num = rb->tagcache_get_numeric(&tcs, tag_discnumber); + if (result) + { + /* if filename remove the '/' */ + result = rb->strrchr(result, PATH_SEPCH); + if (result) + result++; + } + + if (!result) + result = tcs.result; + if (disc_num < 0) disc_num = 0; retry: if (track_num > 0) { if (disc_num) - fn_idx = 1 + rb->snprintf(track_names + string_index , avail, - "%d.%02d: %s", disc_num, track_num, tcs.result); + fn_idx = 1 + rb->snprintf(pf_tracks.names + string_index, avail, + "%d.%02d: %s", disc_num, track_num, result); else - fn_idx = 1 + rb->snprintf(track_names + string_index , avail, - "%d: %s", track_num, tcs.result); + fn_idx = 1 + rb->snprintf(pf_tracks.names + string_index, avail, + "%d: %s", track_num, result); } else { track_num = 0; - fn_idx = 1 + rb->snprintf(track_names + string_index, avail, - "%s", tcs.result); + fn_idx = 1 + rb->snprintf(pf_tracks.names + string_index, avail, + "%s", result); } if (fn_idx <= 0) goto fail; @@ -1106,11 +1651,12 @@ retry: if (remain >= MAX_PATH) { /* retrieve filename for building the playlist */ rb->tagcache_retrieve(&tcs, tcs.idx_id, tag_filename, - track_names + string_index + fn_idx, remain); - len = fn_idx + rb->strlen(track_names + string_index + fn_idx) + 1; + pf_tracks.names + string_index + fn_idx, remain); + + len = fn_idx + rb->strlen(pf_tracks.names + string_index + fn_idx) + 1; /* make sure track name and file name are really split by a \0, else * get_track_name might fail */ - *(track_names + string_index + fn_idx -1) = '\0'; + *(pf_tracks.names + string_index + fn_idx -1) = '\0'; } else /* request more buffer so that track and filename fit */ @@ -1127,38 +1673,43 @@ retry: out = 0; rb->buflib_buffer_out(&buf_ctx, &out); avail += out; - borrowed += out; + pf_tracks.borrowed += out; - struct track_data *new_tracks = - (struct track_data *)(out + (uintptr_t)tracks); + struct track_data *new_tracks; + new_tracks = (struct track_data *)(out + (uintptr_t)pf_tracks.index); - unsigned int bytes = track_count * sizeof(struct track_data); - if (track_count) - rb->memmove(new_tracks, tracks, bytes); - tracks = new_tracks; + unsigned int bytes = pf_tracks.count * sizeof(struct track_data); + if (pf_tracks.count) + rb->memmove(new_tracks, pf_tracks.index, bytes); + pf_tracks.index = new_tracks; } goto retry; } avail -= len; - tracks--; - tracks->sort = (disc_num << 24) + (track_num << 14) + track_count; - tracks->name_idx = string_index; - tracks->seek = tcs.result_seek; + pf_tracks.index--; + pf_tracks.index->sort = (disc_num << 24) + (track_num << 14); + pf_tracks.index->sort += pf_tracks.count; + pf_tracks.index->name_idx = string_index; + pf_tracks.index->seek = tcs.result_seek; #if PF_PLAYBACK_CAPABLE - tracks->filename_idx = fn_idx + string_index; + pf_tracks.index->filename_idx = fn_idx + string_index; #endif - track_count++; + pf_tracks.count++; string_index += len; } rb->tagcache_search_finish(&tcs); /* now fix the track list order */ - rb->qsort(tracks, track_count, sizeof(struct track_data), compare_tracks); + rb->qsort(pf_tracks.index, pf_tracks.count, + sizeof(struct track_data), compare_tracks); + + pf_tracks.cur_idx = slide_index; return; fail: - track_count = 0; + rb->tagcache_search_finish(&tcs); + pf_tracks.count = 0; return; } @@ -1176,14 +1727,16 @@ static bool get_albumart_for_index_from_db(const int slide_index, char *buf, rb->strlcpy( buf, EMPTY_SLIDE, buflen ); } - if (!rb->tagcache_search(&tcs, tag_filename)) + if (tcs.valid || !rb->tagcache_search(&tcs, tag_filename)) return false; bool result; /* find the first track of the album */ - rb->tagcache_search_add_filter(&tcs, tag_album, album[slide_index].seek); + rb->tagcache_search_add_filter(&tcs, tag_album, + pf_idx.album_index[slide_index].seek); + rb->tagcache_search_add_filter(&tcs, tag_albumartist, - artist[album[slide_index].artist_idx].seek); + pf_idx.album_index[slide_index].artist_seek); if ( rb->tagcache_get_next(&tcs) ) { struct mp3entry id3; @@ -1198,9 +1751,12 @@ static bool get_albumart_for_index_from_db(const int slide_index, char *buf, #endif { fd = rb->open(tcs.result, O_RDONLY); - rb->get_metadata(&id3, fd, tcs.result); - rb->close(fd); + if (fd) { + rb->get_metadata(&id3, fd, tcs.result); + rb->close(fd); + } } + if ( search_albumart_files(&id3, ":", buf, buflen) ) result = true; else @@ -1217,10 +1773,8 @@ static bool get_albumart_for_index_from_db(const int slide_index, char *buf, /** Draw the PictureFlow logo */ -static void draw_splashscreen(void) +static void draw_splashscreen(unsigned char * buf_tmp, size_t buf_tmp_size) { - unsigned char * buf_tmp = buf; - size_t buf_tmp_size = buf_size; struct screen* display = rb->screens[SCREEN_MAIN]; #if FB_DATA_SZ > 1 ALIGN_BUFFER(buf_tmp, buf_tmp_size, sizeof(fb_data)); @@ -1264,27 +1818,28 @@ static void draw_splashscreen(void) /** Draw a simple progress bar */ -static void draw_progressbar(int step) +static void draw_progressbar(int step, int count, char *msg) { - int txt_w, txt_h; + static int txt_w, txt_h; const int bar_height = 22; const int w = LCD_WIDTH - 20; const int x = 10; - + static int y; + if (msg != NULL) + { #if LCD_DEPTH > 1 - rb->lcd_set_background(N_BRIGHT(0)); - rb->lcd_set_foreground(N_BRIGHT(255)); + rb->lcd_set_background(N_BRIGHT(0)); + rb->lcd_set_foreground(N_BRIGHT(255)); #else - rb->lcd_set_drawmode(PICTUREFLOW_DRMODE); + rb->lcd_set_drawmode(PICTUREFLOW_DRMODE); #endif - rb->lcd_clear_display(); - rb->lcd_getstringsize("Preparing album artwork", &txt_w, &txt_h); - - int y = (LCD_HEIGHT - txt_h)/2; + rb->lcd_getstringsize(msg, &txt_w, &txt_h); - rb->lcd_putsxy((LCD_WIDTH - txt_w)/2, y, "Preparing album artwork"); - y += (txt_h + 5); + y = (LCD_HEIGHT - txt_h)/2; + rb->lcd_putsxy((LCD_WIDTH - txt_w)/2, y, msg); + y += (txt_h + 5); + } #if LCD_DEPTH > 1 rb->lcd_set_foreground(N_BRIGHT(100)); #endif @@ -1293,7 +1848,7 @@ static void draw_progressbar(int step) rb->lcd_set_foreground(N_PIX(165, 231, 82)); #endif - rb->lcd_fillrect(x+1, y+1, step * w / album_count, bar_height-2); + rb->lcd_fillrect(x+1, y+1, step * w / count, bar_height-2); #if LCD_DEPTH > 1 rb->lcd_set_foreground(N_BRIGHT(255)); #endif @@ -1327,7 +1882,7 @@ static bool save_pfraw(char* filename, struct bitmap *bm) struct pfraw_header bmph; bmph.width = bm->width; bmph.height = bm->height; - int fh = rb->creat( filename , 0666); + int fh = rb->open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666); if( fh < 0 ) return false; rb->write( fh, &bmph, sizeof( struct pfraw_header ) ); pix_t *data = (pix_t*)( bm->data ); @@ -1341,62 +1896,99 @@ static bool save_pfraw(char* filename, struct bitmap *bm) return true; } -/** - Precomupte the album art images and store them in CACHE_PREFIX. - Use the "?" bitmap if image is not found. - */ -static bool create_albumart_cache(void) +static bool incremental_albumart_cache(bool verbose) { - int ret; + if (!aa_cache.buf) + goto aa_failure; - int i, slides = 0; - struct bitmap input_bmp; + if (aa_cache.inspected >= pf_idx.album_ct) + return false; - char pfraw_file[MAX_PATH]; - char albumart_file[MAX_PATH]; + int idx, ret; + unsigned int hash_artist, hash_album; unsigned int format = FORMAT_NATIVE; - bool update = (cache_version == CACHE_UPDATE); - if (resize) + + bool update = (pf_cfg.cache_version == CACHE_UPDATE); + + if (pf_cfg.resize) format |= FORMAT_RESIZE|FORMAT_KEEP_ASPECT; - for (i=0; i < album_count; i++) - { - draw_progressbar(i); - rb->snprintf(pfraw_file, sizeof(pfraw_file), CACHE_PREFIX "/%x%x.pfraw", - mfnv(get_album_name(i)),mfnv(get_album_artist(i))); - /* delete existing cache, so it's a true rebuild */ - if(rb->file_exists(pfraw_file)) { - if(update) { - slides++; - continue; - } - rb->remove(pfraw_file); - } - if (!get_albumart_for_index_from_db(i, albumart_file, MAX_PATH)) - rb->strcpy(albumart_file, EMPTY_SLIDE_BMP); - - input_bmp.data = buf; - input_bmp.width = DISPLAY_WIDTH; - input_bmp.height = DISPLAY_HEIGHT; - ret = read_image_file(albumart_file, &input_bmp, buf_size, - format, &format_transposed); - if (ret <= 0) { - rb->splashf(HZ, "Album art is bad: %s", get_album_name(i)); - rb->strcpy(albumart_file, EMPTY_SLIDE_BMP); - ret = read_image_file(albumart_file, &input_bmp, buf_size, - format, &format_transposed); - if(ret <= 0) - continue; + + idx = aa_cache.idx; + if (idx >= pf_idx.album_ct || idx < 0) { idx = 0; } /* Rollover */ + + + aa_cache.idx++; + aa_cache.inspected++; + if (aa_cache.idx >= pf_idx.album_ct) { aa_cache.idx = 0; } /* Rollover */ + + if (!get_albumart_for_index_from_db(idx, aa_cache.file, sizeof(aa_cache.file))) + goto aa_failure; //rb->strcpy(aa_cache.file, EMPTY_SLIDE_BMP); + + hash_artist = mfnv(get_album_artist(idx)); + hash_album = mfnv(get_album_name(idx)); + + rb->snprintf(aa_cache.pfraw_file, sizeof(aa_cache.pfraw_file), + CACHE_PREFIX "/%x%x.pfraw", hash_album, hash_artist); + + if(rb->file_exists(aa_cache.pfraw_file)) { + if(update) { + aa_cache.slides++; + goto aa_success; } - if (!save_pfraw(pfraw_file, &input_bmp)) - { - rb->splash(HZ, "Could not write bmp"); - continue; + } + + aa_cache.input_bmp.data = aa_cache.buf; + aa_cache.input_bmp.width = DISPLAY_WIDTH; + aa_cache.input_bmp.height = DISPLAY_HEIGHT; + + ret = read_image_file(aa_cache.file, &aa_cache.input_bmp, + aa_cache.buf_sz, format, &format_transposed); + if (ret <= 0) { + if (verbose) { + rb->splashf(HZ, "Album art is bad: %s", get_album_name(idx)); } - slides++; - if ( rb->button_get(false) == PF_MENU ) return false; + + goto aa_failure; + } + rb->remove(aa_cache.pfraw_file); + + if (!save_pfraw(aa_cache.pfraw_file, &aa_cache.input_bmp)) + { + if (verbose) { rb->splash(HZ, "Could not write bmp"); } + goto aa_failure; + } + aa_cache.slides++; + +aa_failure: + if (verbose) + return false; + +aa_success: + if (aa_cache.inspected >= pf_idx.album_ct) + free_all_slide_prio(0); + + if(verbose)/* direct interaction with user */ + return true; + + return false; +} + +/** + Precomupte the album art images and store them in CACHE_PREFIX. + Use the "?" bitmap if image is not found. + */ +static bool create_albumart_cache(void) +{ + draw_splashscreen(pf_idx.buf, pf_idx.buf_sz); + draw_progressbar(0, pf_idx.album_ct, "Preparing artwork"); + for (int i=0; i < pf_idx.album_ct; i++) + { + incremental_albumart_cache(true); + draw_progressbar(aa_cache.inspected, pf_idx.album_ct, NULL); + if (rb->button_get(false) > BUTTON_NONE) + return true; } - draw_progressbar(i); - if ( slides == 0 ) { + if ( aa_cache.slides == 0 ) { /* Warn the user that we couldn't find any albumart */ rb->splash(2*HZ, ID2P(LANG_NO_ALBUMART_FOUND)); return false; @@ -1410,19 +2002,23 @@ static bool create_albumart_cache(void) */ static int create_empty_slide(bool force) { + const unsigned int format = FORMAT_NATIVE|FORMAT_RESIZE|FORMAT_KEEP_ASPECT; + + if (!aa_cache.buf) + return false; + if ( force || ! rb->file_exists( EMPTY_SLIDE ) ) { - struct bitmap input_bmp; - input_bmp.width = DISPLAY_WIDTH; - input_bmp.height = DISPLAY_HEIGHT; + aa_cache.input_bmp.width = DISPLAY_WIDTH; + aa_cache.input_bmp.height = DISPLAY_HEIGHT; #if LCD_DEPTH > 1 - input_bmp.format = FORMAT_NATIVE; + aa_cache.input_bmp.format = FORMAT_NATIVE; #endif - input_bmp.data = (char*)buf; - scaled_read_bmp_file(EMPTY_SLIDE_BMP, &input_bmp, - buf_size, - FORMAT_NATIVE|FORMAT_RESIZE|FORMAT_KEEP_ASPECT, - &format_transposed); - if (!save_pfraw(EMPTY_SLIDE, &input_bmp)) + aa_cache.input_bmp.data = (char*)aa_cache.buf; + + scaled_read_bmp_file(EMPTY_SLIDE_BMP, &aa_cache.input_bmp, + aa_cache.buf_sz, format, &format_transposed); + + if (!save_pfraw(EMPTY_SLIDE, &aa_cache.input_bmp)) return false; } @@ -1502,23 +2098,23 @@ static bool create_pf_thread(void) * the LRU cache of slides, and the list of free cache slots. */ -#define seek_right_while(start, cond) \ +#define _SEEK_RIGHT_WHILE(start, cond) \ ({ \ int ind_, next_ = (start); \ do { \ ind_ = next_; \ - next_ = cache[ind_].next; \ - } while (next_ != cache_used && (cond)); \ + next_ = pf_sldcache.cache[ind_].next; \ + } while (next_ != pf_sldcache.used && (cond)); \ ind_; \ }) -#define seek_left_while(start, cond) \ +#define _SEEK_LEFT_WHILE(start, cond) \ ({ \ int ind_, next_ = (start); \ do { \ ind_ = next_; \ - next_ = cache[ind_].prev; \ - } while (ind_ != cache_used && (cond)); \ + next_ = pf_sldcache.cache[ind_].prev; \ + } while (ind_ != pf_sldcache.used && (cond)); \ ind_; \ }) @@ -1528,8 +2124,8 @@ static bool create_pf_thread(void) */ static inline int lla_pop_item (int *head, int i) { - int prev = cache[i].prev; - int next = cache[i].next; + int prev = pf_sldcache.cache[i].prev; + int next = pf_sldcache.cache[i].next; if (i == next) { *head = -1; @@ -1537,8 +2133,8 @@ static inline int lla_pop_item (int *head, int i) } else if (i == *head) *head = next; - cache[next].prev = prev; - cache[prev].next = next; + pf_sldcache.cache[next].prev = prev; + pf_sldcache.cache[prev].next = next; return next; } @@ -1561,11 +2157,11 @@ static inline int lla_pop_head (int *head) static inline void lla_insert (int i, int p) { int next = p; - int prev = cache[next].prev; - cache[next].prev = i; - cache[prev].next = i; - cache[i].next = next; - cache[i].prev = prev; + int prev = pf_sldcache.cache[next].prev; + pf_sldcache.cache[next].prev = i; + pf_sldcache.cache[prev].next = i; + pf_sldcache.cache[i].next = next; + pf_sldcache.cache[i].prev = prev; } @@ -1577,8 +2173,8 @@ static inline void lla_insert_tail (int *head, int i) if (*head == -1) { *head = i; - cache[i].next = i; - cache[i].prev = i; + pf_sldcache.cache[i].next = i; + pf_sldcache.cache[i].prev = i; } else lla_insert(i, *head); } @@ -1588,7 +2184,7 @@ static inline void lla_insert_tail (int *head, int i) */ static inline void lla_insert_after(int i, int p) { - p = cache[p].next; + p = pf_sldcache.cache[p].next; lla_insert(i, p); } @@ -1611,16 +2207,16 @@ static inline void lla_insert_before(int *head, int i, int p) */ static inline void free_slide(int i) { - if (cache[i].hid != empty_slide_hid) - rb->buflib_free(&buf_ctx, cache[i].hid); - cache[i].index = -1; - lla_pop_item(&cache_used, i); - lla_insert_tail(&cache_free, i); - if (cache_used == -1) + if (pf_sldcache.cache[i].hid != empty_slide_hid) + rb->buflib_free(&buf_ctx, pf_sldcache.cache[i].hid); + pf_sldcache.cache[i].index = -1; + lla_pop_item(&pf_sldcache.used, i); + lla_insert_tail(&pf_sldcache.free, i); + if (pf_sldcache.used == -1) { - cache_right_index = -1; - cache_left_index = -1; - cache_center_index = -1; + pf_sldcache.right_idx = -1; + pf_sldcache.left_idx = -1; + pf_sldcache.center_idx = -1; } } @@ -1631,13 +2227,17 @@ static inline void free_slide(int i) */ static bool free_slide_prio(int prio) { - if (cache_used == -1) + if (pf_sldcache.used == -1) return false; - int i, l = cache_used, r = cache[cache_used].prev, prio_max; - int prio_l = cache[l].index < center_index ? - center_index - cache[l].index : 0; - int prio_r = cache[r].index > center_index ? - cache[r].index - center_index : 0; + + int i, prio_max; + int l = pf_sldcache.used; + int r = pf_sldcache.cache[pf_sldcache.used].prev; + + int prio_l = pf_sldcache.cache[l].index < center_index ? + center_index - pf_sldcache.cache[l].index : 0; + int prio_r = pf_sldcache.cache[r].index > center_index ? + pf_sldcache.cache[r].index - center_index : 0; if (prio_l > prio_r) { i = l; @@ -1648,16 +2248,27 @@ static bool free_slide_prio(int prio) } if (prio_max > prio) { - if (i == cache_left_index) - cache_left_index = cache[i].next; - if (i == cache_right_index) - cache_right_index = cache[i].prev; + if (i == pf_sldcache.left_idx) + pf_sldcache.left_idx = pf_sldcache.cache[i].next; + if (i == pf_sldcache.right_idx) + pf_sldcache.right_idx = pf_sldcache.cache[i].prev; free_slide(i); return true; } else return false; } + +/** + Free all slides ranked above the given priority. +*/ +static void free_all_slide_prio(int prio) +{ + while (free_slide_prio(prio)) + ;; +} + + /** Read the pfraw image given as filename and return the hid of the buffer */ @@ -1666,7 +2277,7 @@ static int read_pfraw(char* filename, int prio) struct pfraw_header bmph; int fh = rb->open(filename, O_RDONLY); if( fh < 0 ) { - cache_version = CACHE_UPDATE; + /* pf_cfg.cache_version = CACHE_UPDATE; -- don't invalidate on missing pfraw */ return empty_slide_hid; } else @@ -1711,19 +2322,20 @@ static inline bool load_and_prepare_surface(const int slide_index, const int prio) { char pfraw_file[MAX_PATH]; - + unsigned int hash_artist = mfnv(get_album_artist(slide_index)); + unsigned int hash_album = mfnv(get_album_name(slide_index)); rb->snprintf(pfraw_file, sizeof(pfraw_file), CACHE_PREFIX "/%x%x.pfraw", - mfnv(get_album_name(slide_index)),mfnv(get_album_artist(slide_index))); + hash_album, hash_artist); int hid = read_pfraw(pfraw_file, prio); if (!hid) return false; - cache[cache_index].hid = hid; + pf_sldcache.cache[cache_index].hid = hid; if ( cache_index < SLIDE_CACHE_SIZE ) { - cache[cache_index].index = slide_index; + pf_sldcache.cache[cache_index].index = slide_index; } return true; @@ -1737,107 +2349,121 @@ static inline bool load_and_prepare_surface(const int slide_index, bool load_new_slide(void) { int i = -1; - if (cache_center_index != -1) + + if (pf_sldcache.center_idx != -1) { int next, prev; - if (cache[cache_center_index].index != center_index) + if (pf_sldcache.cache[pf_sldcache.center_idx].index != center_index) { - if (cache[cache_center_index].index < center_index) + if (pf_sldcache.cache[pf_sldcache.center_idx].index < center_index) { - cache_center_index = seek_right_while(cache_center_index, - cache[next_].index <= center_index); - prev = cache_center_index; - next = cache[cache_center_index].next; + pf_sldcache.center_idx = _SEEK_RIGHT_WHILE(pf_sldcache.center_idx, + pf_sldcache.cache[next_].index <= center_index); + + prev = pf_sldcache.center_idx; + next = pf_sldcache.cache[pf_sldcache.center_idx].next; } else { - cache_center_index = seek_left_while(cache_center_index, - cache[next_].index >= center_index); - next = cache_center_index; - prev = cache[cache_center_index].prev; + pf_sldcache.center_idx = _SEEK_LEFT_WHILE(pf_sldcache.center_idx, + pf_sldcache.cache[next_].index >= center_index); + + next = pf_sldcache.center_idx; + prev = pf_sldcache.cache[pf_sldcache.center_idx].prev; } - if (cache[cache_center_index].index != center_index) + if (pf_sldcache.cache[pf_sldcache.center_idx].index != center_index) { - if (cache_free == -1) + if (pf_sldcache.free == -1) free_slide_prio(0); - i = lla_pop_head(&cache_free); + + i = lla_pop_head(&pf_sldcache.free); if (!load_and_prepare_surface(center_index, i, 0)) goto fail_and_refree; - if (cache[next].index == -1) + + if (pf_sldcache.cache[next].index == -1) { - if (cache[prev].index == -1) + if (pf_sldcache.cache[prev].index == -1) goto insert_first_slide; else - next = cache[prev].next; + next = pf_sldcache.cache[prev].next; } lla_insert(i, next); - if (cache[i].index < cache[cache_used].index) - cache_used = i; - cache_center_index = i; - cache_left_index = i; - cache_right_index = i; + if (pf_sldcache.cache[i].index < pf_sldcache.cache[pf_sldcache.used].index) + pf_sldcache.used = i; + + pf_sldcache.center_idx = i; + pf_sldcache.left_idx = i; + pf_sldcache.right_idx = i; return true; } } - if (cache[cache_left_index].index > - cache[cache_center_index].index) - cache_left_index = cache_center_index; - if (cache[cache_right_index].index < - cache[cache_center_index].index) - cache_right_index = cache_center_index; - cache_left_index = seek_left_while(cache_left_index, - cache[ind_].index - 1 == cache[next_].index); - cache_right_index = seek_right_while(cache_right_index, - cache[ind_].index - 1 == cache[next_].index); - int prio_l = cache[cache_center_index].index - - cache[cache_left_index].index + 1; - int prio_r = cache[cache_right_index].index - - cache[cache_center_index].index + 1; - if ((prio_l < prio_r || - cache[cache_right_index].index >= number_of_slides) && - cache[cache_left_index].index > 0) + int left, center, right; + left = pf_sldcache.cache[pf_sldcache.left_idx].index; + center = pf_sldcache.cache[pf_sldcache.center_idx].index; + right = pf_sldcache.cache[pf_sldcache.right_idx].index; + + if (left > center) + pf_sldcache.left_idx = pf_sldcache.center_idx; + if (right < center) + pf_sldcache.right_idx = pf_sldcache.center_idx; + + pf_sldcache.left_idx = _SEEK_LEFT_WHILE(pf_sldcache.left_idx, + pf_sldcache.cache[ind_].index - 1 == pf_sldcache.cache[next_].index); + + pf_sldcache.right_idx = _SEEK_RIGHT_WHILE(pf_sldcache.right_idx, + pf_sldcache.cache[ind_].index - 1 == pf_sldcache.cache[next_].index); + + + /* update indices */ + left = pf_sldcache.cache[pf_sldcache.left_idx].index; + center = pf_sldcache.cache[pf_sldcache.center_idx].index; + right = pf_sldcache.cache[pf_sldcache.right_idx].index; + + int prio_l = center - left + 1; + int prio_r = right - center + 1; + if ((prio_l < prio_r || right >= number_of_slides) && left > 0) { - if (cache_free == -1 && !free_slide_prio(prio_l)) + if (pf_sldcache.free == -1 && !free_slide_prio(prio_l)) return false; - i = lla_pop_head(&cache_free); - if (load_and_prepare_surface(cache[cache_left_index].index - - 1, i, prio_l)) + + i = lla_pop_head(&pf_sldcache.free); + if (load_and_prepare_surface(left - 1, i, prio_l)) { - lla_insert_before(&cache_used, i, cache_left_index); - cache_left_index = i; + lla_insert_before(&pf_sldcache.used, i, pf_sldcache.left_idx); + pf_sldcache.left_idx = i; return true; } - } else if(cache[cache_right_index].index < number_of_slides - 1) + } else if(right < number_of_slides - 1) { - if (cache_free == -1 && !free_slide_prio(prio_r)) + if (pf_sldcache.free == -1 && !free_slide_prio(prio_r)) return false; - i = lla_pop_head(&cache_free); - if (load_and_prepare_surface(cache[cache_right_index].index - + 1, i, prio_r)) + + i = lla_pop_head(&pf_sldcache.free); + if (load_and_prepare_surface(right + 1, i, prio_r)) { - lla_insert_after(i, cache_right_index); - cache_right_index = i; + lla_insert_after(i, pf_sldcache.right_idx); + pf_sldcache.right_idx = i; return true; } } } else { - i = lla_pop_head(&cache_free); + i = lla_pop_head(&pf_sldcache.free); if (load_and_prepare_surface(center_index, i, 0)) { insert_first_slide: - cache[i].next = i; - cache[i].prev = i; - cache_center_index = i; - cache_left_index = i; - cache_right_index = i; - cache_used = i; + pf_sldcache.cache[i].next = i; + pf_sldcache.cache[i].prev = i; + pf_sldcache.center_idx = i; + pf_sldcache.left_idx = i; + pf_sldcache.right_idx = i; + pf_sldcache.used = i; return true; } } fail_and_refree: if (i != -1) { - lla_insert_tail(&cache_free, i); + lla_insert_tail(&pf_sldcache.free, i); } return false; } @@ -1869,13 +2495,13 @@ static inline struct dim *surface(const int slide_index) if (slide_index >= number_of_slides) return 0; int i; - if ((i = cache_used ) != -1) + if ((i = pf_sldcache.used ) != -1) { do { - if (cache[i].index == slide_index) - return get_slide(cache[i].hid); - i = cache[i].next; - } while (i != cache_used); + if (pf_sldcache.cache[i].index == slide_index) + return get_slide(pf_sldcache.cache[i].hid); + i = pf_sldcache.cache[i].next; + } while (i != pf_sldcache.used); } return get_slide(empty_slide_hid); } @@ -1892,19 +2518,19 @@ static void reset_slides(void) center_slide.slide_index = center_index; int i; - for (i = 0; i < num_slides; i++) { + for (i = 0; i < pf_cfg.num_slides; i++) { struct slide_data *si = &left_slides[i]; si->angle = itilt; - si->cx = -(offsetX + slide_spacing * i * PFREAL_ONE); + si->cx = -(offsetX + pf_cfg.slide_spacing * i * PFREAL_ONE); si->cy = offsetY; si->slide_index = center_index - 1 - i; si->distance = 0; } - for (i = 0; i < num_slides; i++) { + for (i = 0; i < pf_cfg.num_slides; i++) { struct slide_data *si = &right_slides[i]; si->angle = -itilt; - si->cx = offsetX + slide_spacing * i * PFREAL_ONE; + si->cx = offsetX + pf_cfg.slide_spacing * i * PFREAL_ONE; si->cy = offsetY; si->slide_index = center_index + 1 + i; si->distance = 0; @@ -1928,14 +2554,14 @@ static void recalc_offsets(void) { PFreal xs = PFREAL_HALF - DISPLAY_WIDTH * PFREAL_HALF; PFreal zo; - PFreal xp = (DISPLAY_WIDTH * PFREAL_HALF - PFREAL_HALF + center_margin * - PFREAL_ONE) * zoom / 100; + PFreal xp = (DISPLAY_WIDTH * PFREAL_HALF - PFREAL_HALF + + pf_cfg.center_margin * PFREAL_ONE) * pf_cfg.zoom / 100; PFreal cosr, sinr; itilt = 70 * IANGLE_MAX / 360; /* approx. 70 degrees tilted */ cosr = fcos(-itilt); sinr = fsin(-itilt); - zo = CAM_DIST_R * 100 / zoom - CAM_DIST_R + + zo = CAM_DIST_R * 100 / pf_cfg.zoom - CAM_DIST_R + fmuln(MAXSLIDE_LEFT_R, sinr, PFREAL_SHIFT - 2, 0); offsetX = xp - fmul(xs, cosr) + fmuln(xp, zo + fmuln(xs, sinr, PFREAL_SHIFT - 2, 0), PFREAL_SHIFT - 2, 0) @@ -2033,7 +2659,7 @@ static void render_slide(struct slide_data *slide, const int alpha) PFreal cosr = fcos(slide->angle); PFreal sinr = fsin(slide->angle); - PFreal zo = PFREAL_ONE * slide->distance + CAM_DIST_R * 100 / zoom + PFreal zo = PFREAL_ONE * slide->distance + CAM_DIST_R * 100 / pf_cfg.zoom - CAM_DIST_R - fmuln(MAXSLIDE_LEFT_R, fabs(sinr), PFREAL_SHIFT - 2, 0); PFreal xs = slide_left, xsnum, xsnumi, xsden, xsdeni; PFreal xp = fdiv(CAM_DIST * (slide->cx + fmul(xs, cosr)), @@ -2132,7 +2758,7 @@ static void render_slide(struct slide_data *slide, const int alpha) } /** - Jump the the given slide_index + Jump to the given slide_index */ static inline void set_current_slide(const int slide_index) { @@ -2202,8 +2828,8 @@ static void render_all_slides(void) /* TODO: Optimizes this by e.g. invalidating rects */ mylcd_clear_display(); - int nleft = num_slides; - int nright = num_slides; + int nleft = pf_cfg.num_slides; + int nright = pf_cfg.num_slides; int alpha; int index; @@ -2242,7 +2868,7 @@ static void render_all_slides(void) } } alpha = 256; - if (step != 0 && num_slides <= 2) /* fading out center slide */ + if (step != 0 && pf_cfg.num_slides <= 2) /* fading out center slide */ alpha = (step > 0) ? 256 - fade / 2 : 128 + fade / 2; render_slide(¢er_slide, alpha); } @@ -2291,9 +2917,9 @@ static void update_scroll_animation(void) rb->queue_post(&thread_q, EV_WAKEUP, 0); slide_frame = index << 16; center_slide.slide_index = center_index; - for (i = 0; i < num_slides; i++) + for (i = 0; i < pf_cfg.num_slides; i++) left_slides[i].slide_index = center_index - 1 - i; - for (i = 0; i < num_slides; i++) + for (i = 0; i < pf_cfg.num_slides; i++) right_slides[i].slide_index = center_index + 1 + i; } @@ -2310,21 +2936,21 @@ static void update_scroll_animation(void) return; } - for (i = 0; i < num_slides; i++) { + for (i = 0; i < pf_cfg.num_slides; i++) { struct slide_data *si = &left_slides[i]; si->angle = itilt; si->cx = - -(offsetX + slide_spacing * i * PFREAL_ONE + step - * slide_spacing * ftick); + -(offsetX + pf_cfg.slide_spacing * i * PFREAL_ONE + step + * pf_cfg.slide_spacing * ftick); si->cy = offsetY; } - for (i = 0; i < num_slides; i++) { + for (i = 0; i < pf_cfg.num_slides; i++) { struct slide_data *si = &right_slides[i]; si->angle = -itilt; si->cx = - offsetX + slide_spacing * i * PFREAL_ONE - step - * slide_spacing * ftick; + offsetX + pf_cfg.slide_spacing * i * PFREAL_ONE - step + * pf_cfg.slide_spacing * ftick; si->cy = offsetY; } @@ -2409,13 +3035,13 @@ static int settings_menu(void) selection=rb->do_menu(&settings_menu,&selection, NULL, false); switch(selection) { case 0: - rb->set_bool(rb->str(LANG_DISPLAY_FPS), &show_fps); + rb->set_bool(rb->str(LANG_DISPLAY_FPS), &pf_cfg.show_fps); reset_track_list(); break; case 1: rb->set_int(rb->str(LANG_SPACING), "", 1, - &slide_spacing, + &pf_cfg.slide_spacing, NULL, 1, 0, 100, NULL ); recalc_offsets(); reset_slides(); @@ -2423,57 +3049,59 @@ static int settings_menu(void) case 2: rb->set_int(rb->str(LANG_CENTRE_MARGIN), "", 1, - ¢er_margin, + &pf_cfg.center_margin, NULL, 1, 0, 80, NULL ); recalc_offsets(); reset_slides(); break; case 3: - rb->set_int(rb->str(LANG_NUMBER_OF_SLIDES), "", 1, &num_slides, - NULL, 1, 1, MAX_SLIDES_COUNT, NULL ); + rb->set_int(rb->str(LANG_NUMBER_OF_SLIDES), "", 1, + &pf_cfg.num_slides, NULL, 1, 1, MAX_SLIDES_COUNT, NULL ); recalc_offsets(); reset_slides(); break; case 4: - rb->set_int(rb->str(LANG_ZOOM), "", 1, &zoom, + rb->set_int(rb->str(LANG_ZOOM), "", 1, &pf_cfg.zoom, NULL, 1, 10, 300, NULL ); recalc_offsets(); reset_slides(); break; case 5: - rb->set_option(rb->str(LANG_SHOW_ALBUM_TITLE), &show_album_name, - INT, album_name_options, 5, NULL); + rb->set_option(rb->str(LANG_SHOW_ALBUM_TITLE), + &pf_cfg.show_album_name, INT, album_name_options, 5, NULL); reset_track_list(); recalc_offsets(); reset_slides(); break; case 6: - old_val = resize; - rb->set_bool(rb->str(LANG_RESIZE_COVERS), &resize); - if (old_val == resize) /* changed? */ + old_val = pf_cfg.resize; + rb->set_bool(rb->str(LANG_RESIZE_COVERS), &pf_cfg.resize); + if (old_val == pf_cfg.resize) /* changed? */ break; /* fallthrough if changed, since cache needs to be rebuilt */ case 7: - cache_version = CACHE_REBUILD; + pf_cfg.cache_version = CACHE_REBUILD; rb->remove(EMPTY_SLIDE); configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); rb->splash(HZ, ID2P(LANG_CACHE_REBUILT_NEXT_RESTART)); break; case 8: - cache_version = CACHE_UPDATE; + pf_cfg.cache_version = CACHE_UPDATE; rb->remove(EMPTY_SLIDE); configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); rb->splash(HZ, ID2P(LANG_CACHE_REBUILT_NEXT_RESTART)); break; case 9: - rb->set_option(rb->str(LANG_WPS_INTEGRATION), &auto_wps, INT, wps_options, 3, NULL); + rb->set_option(rb->str(LANG_WPS_INTEGRATION), + &pf_cfg.auto_wps, INT, wps_options, 3, NULL); break; case 10: - rb->set_option(rb->str(LANG_BACKLIGHT), &backlight_mode, INT, backlight_options, 2, NULL); + rb->set_option(rb->str(LANG_BACKLIGHT), + &pf_cfg.backlight_mode, INT, backlight_options, 2, NULL); break; case MENU_ATTACHED_USB: @@ -2596,8 +3224,8 @@ static inline void draw_gradient(int y, int h) int r, inc, c; inc = (100 << 8) / h; c = 0; - selected_track_pulse = (selected_track_pulse+1) % 10; - int c2 = selected_track_pulse - 5; + pf_tracks.sel_pulse = (pf_tracks.sel_pulse+1) % 10; + int c2 = pf_tracks.sel_pulse - 5; for (r=0; r<h; r++) { #ifdef HAVE_LCD_COLOR mylcd_set_foreground(G_PIX(c2+80-(c >> 9), c2+100-(c >> 9), @@ -2616,30 +3244,30 @@ static inline void draw_gradient(int y, int h) static void track_list_yh(int char_height) { - switch (show_album_name) + switch (pf_cfg.show_album_name) { case ALBUM_NAME_HIDE: - track_list_y = (show_fps ? char_height : 0); - track_list_h = LCD_HEIGHT - track_list_y; + pf_tracks.list_y = (pf_cfg.show_fps ? char_height : 0); + pf_tracks.list_h = LCD_HEIGHT - pf_tracks.list_y; break; case ALBUM_NAME_BOTTOM: - track_list_y = (show_fps ? char_height : 0); - track_list_h = LCD_HEIGHT - track_list_y - (char_height * 3); + pf_tracks.list_y = (pf_cfg.show_fps ? char_height : 0); + pf_tracks.list_h = LCD_HEIGHT - pf_tracks.list_y - (char_height * 3); break; case ALBUM_AND_ARTIST_TOP: - track_list_y = char_height * 3; - track_list_h = LCD_HEIGHT - track_list_y - - (show_fps ? char_height : 0); + pf_tracks.list_y = char_height * 3; + pf_tracks.list_h = LCD_HEIGHT - pf_tracks.list_y - + (pf_cfg.show_fps ? char_height : 0); break; case ALBUM_AND_ARTIST_BOTTOM: - track_list_y = (show_fps ? char_height : 0); - track_list_h = LCD_HEIGHT - track_list_y - (char_height * 3); + pf_tracks.list_y = (pf_cfg.show_fps ? char_height : 0); + pf_tracks.list_h = LCD_HEIGHT - pf_tracks.list_y - (char_height * 3); break; case ALBUM_NAME_TOP: default: - track_list_y = char_height * 3; - track_list_h = LCD_HEIGHT - track_list_y - - (show_fps ? char_height : 0); + pf_tracks.list_y = char_height * 3; + pf_tracks.list_h = LCD_HEIGHT - pf_tracks.list_y - + (pf_cfg.show_fps ? char_height : 0); break; } } @@ -2652,18 +3280,20 @@ void reset_track_list(void) int char_height = rb->screens[SCREEN_MAIN]->getcharheight(); int total_height; track_list_yh(char_height); - track_list_visible_entries = fmin( track_list_h/char_height , track_count ); - start_index_track_list = 0; - selected_track = 0; - last_selected_track = -1; + pf_tracks.list_visible = + fmin( pf_tracks.list_h/char_height , pf_tracks.count ); + + pf_tracks.list_start = 0; + pf_tracks.sel = 0; + pf_tracks.last_sel = -1; /* let the tracklist start more centered * if the screen isn't filled with tracks */ - total_height = track_count*char_height; - if (total_height < track_list_h) + total_height = pf_tracks.count*char_height; + if (total_height < pf_tracks.list_h) { - track_list_y += (track_list_h - total_height) / 2; - track_list_h = total_height; + pf_tracks.list_y += (pf_tracks.list_h - total_height) / 2; + pf_tracks.list_h = total_height; } } @@ -2673,24 +3303,25 @@ void reset_track_list(void) static void show_track_list(void) { mylcd_clear_display(); - if ( center_slide.slide_index != track_index ) { + if ( center_slide.slide_index != pf_tracks.cur_idx ) { create_track_index(center_slide.slide_index); reset_track_list(); } int titletxt_w, titletxt_x, color, titletxt_h; titletxt_h = rb->screens[SCREEN_MAIN]->getcharheight(); - int titletxt_y = track_list_y; + int titletxt_y = pf_tracks.list_y; int track_i; - track_i = start_index_track_list; - for (;track_i < track_list_visible_entries+start_index_track_list; - track_i++) + int fade; + + track_i = pf_tracks.list_start; + for (; track_i < pf_tracks.list_visible + pf_tracks.list_start; track_i++) { char *trackname = get_track_name(track_i); - if ( track_i == selected_track ) { - if (selected_track != last_selected_track) { + if ( track_i == pf_tracks.sel ) { + if (pf_tracks.sel != pf_tracks.last_sel) { set_scroll_line(trackname, PF_SCROLL_TRACK); - last_selected_track = selected_track; + pf_tracks.last_sel = pf_tracks.sel; } draw_gradient(titletxt_y, titletxt_h); titletxt_x = get_scroll_line_offset(PF_SCROLL_TRACK); @@ -2699,7 +3330,8 @@ static void show_track_list(void) else { titletxt_w = mylcd_getstringsize(trackname, NULL, NULL); titletxt_x = (LCD_WIDTH-titletxt_w)/2; - color = 250 - (abs(selected_track - track_i) * 200 / track_count); + fade = (abs(pf_tracks.sel - track_i) * 200 / pf_tracks.count); + color = 250 - fade; } mylcd_set_foreground(G_BRIGHT(color)); mylcd_putsxy(titletxt_x,titletxt_y,trackname); @@ -2709,18 +3341,26 @@ static void show_track_list(void) static void select_next_track(void) { - if ( selected_track < track_count - 1 ) { - selected_track++; - if (selected_track==(track_list_visible_entries+start_index_track_list)) - start_index_track_list++; + if ( pf_tracks.sel < pf_tracks.count - 1 ) { + pf_tracks.sel++; + if (pf_tracks.sel==(pf_tracks.list_visible+pf_tracks.list_start)) + pf_tracks.list_start++; + } else { + /* Rollover */ + pf_tracks.sel = 0; + pf_tracks.list_start = 0; } } static void select_prev_track(void) { - if (selected_track > 0 ) { - if (selected_track==start_index_track_list) start_index_track_list--; - selected_track--; + if (pf_tracks.sel > 0 ) { + if (pf_tracks.sel==pf_tracks.list_start) pf_tracks.list_start--; + pf_tracks.sel--; + } else { + /* Rolllover */ + pf_tracks.sel = pf_tracks.count - 1; + pf_tracks.list_start = pf_tracks.count - pf_tracks.list_visible; } } @@ -2732,7 +3372,7 @@ static void start_playback(bool append) { static int old_playlist = -1, old_shuffle = 0; int count = 0; - int position = selected_track; + int position = pf_tracks.sel; int shuffle = rb->global_settings->playlist_shuffle; /* reuse existing playlist if possible * regenerate if shuffle is on or changed, since playlist index and @@ -2751,14 +3391,14 @@ static void start_playback(bool append) if (rb->playlist_insert_track(NULL, get_track_filename(count), PLAYLIST_INSERT_LAST, false, true) < 0) break; - } while(++count < track_count); + } while(++count < pf_tracks.count); rb->playlist_sync(NULL); } else return; if (rb->global_settings->playlist_shuffle) - position = rb->playlist_shuffle(*rb->current_tick, selected_track); + position = rb->playlist_shuffle(*rb->current_tick, pf_tracks.sel); play: /* TODO: can we adjust selected_track if !play_selected ? * if shuffle, we can't predict the playing track easily, and for either @@ -2775,12 +3415,14 @@ play: */ static void draw_album_text(void) { - if (show_album_name == ALBUM_NAME_HIDE) + if (pf_cfg.show_album_name == ALBUM_NAME_HIDE) return; + static int prev_albumtxt_index = -1; int albumtxt_index; int char_height; int albumtxt_x, albumtxt_y, artisttxt_x; + int album_idx = 0; char *albumtxt; char *artisttxt; @@ -2802,7 +3444,7 @@ static void draw_album_text(void) albumtxt_index = center_index; c= 255; } - albumtxt = get_album_name(albumtxt_index); + albumtxt = get_album_name_idx(albumtxt_index, &album_idx); mylcd_set_foreground(G_BRIGHT(c)); if (albumtxt_index != prev_albumtxt_index) { @@ -2811,15 +3453,13 @@ static void draw_album_text(void) } char_height = rb->screens[SCREEN_MAIN]->getcharheight(); - switch(show_album_name){ + switch(pf_cfg.show_album_name){ case ALBUM_AND_ARTIST_TOP: albumtxt_y = 0; break; case ALBUM_NAME_BOTTOM: - albumtxt_y = (LCD_HEIGHT - char_height - char_height/2 - 10); - break; case ALBUM_AND_ARTIST_BOTTOM: - albumtxt_y = (LCD_HEIGHT - char_height - char_height/2 - 20); + albumtxt_y = (LCD_HEIGHT - (char_height * 5 / 2)); break; case ALBUM_NAME_TOP: default: @@ -2828,15 +3468,21 @@ static void draw_album_text(void) } albumtxt_x = get_scroll_line_offset(PF_SCROLL_ALBUM); - mylcd_putsxy(albumtxt_x, albumtxt_y, albumtxt); - if ((show_album_name == ALBUM_AND_ARTIST_TOP) - || (show_album_name == ALBUM_AND_ARTIST_BOTTOM)){ + + if ((pf_cfg.show_album_name == ALBUM_AND_ARTIST_TOP) + || (pf_cfg.show_album_name == ALBUM_AND_ARTIST_BOTTOM)){ + + if (album_idx != (int) pf_idx.album_untagged_idx) + mylcd_putsxy(albumtxt_x, albumtxt_y, albumtxt); artisttxt = get_album_artist(albumtxt_index); set_scroll_line(artisttxt, PF_SCROLL_ARTIST); artisttxt_x = get_scroll_line_offset(PF_SCROLL_ARTIST); - mylcd_putsxy(artisttxt_x, albumtxt_y+20, artisttxt); + int y_offset = char_height + char_height/2; + mylcd_putsxy(artisttxt_x, albumtxt_y + y_offset, artisttxt); + } else { + mylcd_putsxy(albumtxt_x, albumtxt_y, albumtxt); } } @@ -2857,7 +3503,7 @@ static void error_wait(const char *message) */ static int pictureflow_main(void) { - int ret; + int ret = SUCCESS; rb->lcd_setfont(FONT_UI); @@ -2868,10 +3514,13 @@ static int pictureflow_main(void) } } + rb->memset(&aa_cache, 0, sizeof(struct albumart_t)); + config_set_defaults(&pf_cfg); + configfile_load(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); - if(auto_wps == 0) - draw_splashscreen(); - if(backlight_mode == 0) { + if(pf_cfg.auto_wps == 0) + draw_splashscreen(pf_idx.buf, pf_idx.buf_sz); + if(pf_cfg.backlight_mode == 0) { /* Turn off backlight timeout */ backlight_ignore_timeout(); } @@ -2879,19 +3528,20 @@ static int pictureflow_main(void) init_scroll_lines(); init_reflect_table(); - ALIGN_BUFFER(buf, buf_size, 4); + ALIGN_BUFFER(pf_idx.buf, pf_idx.buf_sz, 4); /*Scan will trigger when no file is found or the option was activated*/ - if ((cache_version != CACHE_VERSION)||(load_album_index() < 0)){ - rb->splash(HZ/2,"Creating album index, please wait"); + if ((pf_cfg.cache_version != CACHE_VERSION)||(load_album_index() < 0)){ + rb->splash(HZ/2,"Creating index, please wait"); ret = create_album_index(); + if (ret == 0){ - save_album_index(); + pf_cfg.cache_version = CACHE_REBUILD; + if (save_album_index() < 0) { + rb->splash(HZ, "Could not write index"); + }; } } - else{ - ret = 0; - } if (ret == ERROR_BUFFER_FULL) { error_wait("Not enough memory for album names"); @@ -2899,30 +3549,47 @@ static int pictureflow_main(void) } else if (ret == ERROR_NO_ALBUMS) { error_wait("No albums found. Please enable database"); return PLUGIN_ERROR; + } else if (ret == ERROR_USER_ABORT) { + error_wait("User aborted."); + return PLUGIN_ERROR; } - ALIGN_BUFFER(buf, buf_size, 4); - number_of_slides = album_count; - if ((cache_version != CACHE_VERSION) && !create_albumart_cache()) { - cache_version = CACHE_REBUILD; - configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); - error_wait("Could not create album art cache"); + ALIGN_BUFFER(pf_idx.buf, pf_idx.buf_sz, 4); + number_of_slides = pf_idx.album_ct; + + size_t aa_bufsz = ALIGN_DOWN(pf_idx.buf_sz / 4, 0x4); + + if (aa_bufsz < DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(pix_t)) + { + error_wait("Not enough memory for album art cache"); return PLUGIN_ERROR; } - if (!create_empty_slide(cache_version != CACHE_VERSION)) { - cache_version = CACHE_REBUILD; - configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); + pf_idx.buf_sz -= aa_bufsz; + ALIGN_BUFFER(pf_idx.buf, pf_idx.buf_sz, 4); + aa_cache.buf = (char*) pf_idx.buf + aa_bufsz; + aa_cache.buf_sz = aa_bufsz; + ALIGN_BUFFER(aa_cache.buf, aa_cache.buf_sz, 4); + + if (!create_empty_slide(pf_cfg.cache_version != CACHE_VERSION)) { + config_save(CACHE_REBUILD); error_wait("Could not load the empty slide"); return PLUGIN_ERROR; } - if (cache_version != CACHE_VERSION) + + if ((pf_cfg.cache_version != CACHE_VERSION) && !create_albumart_cache()) { + config_save(CACHE_REBUILD); + error_wait("Could not create album art cache"); + } else if(aa_cache.inspected < pf_idx.album_ct) { + rb->splash(HZ * 2, "Updating album art cache in background"); + } + + if (pf_cfg.cache_version != CACHE_VERSION) { - cache_version = CACHE_VERSION; - configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); + config_save(CACHE_VERSION); } - rb->buflib_init(&buf_ctx, (void *)buf, buf_size); + rb->buflib_init(&buf_ctx, (void *)pf_idx.buf, pf_idx.buf_sz); if (!(empty_slide_hid = read_pfraw(EMPTY_SLIDE, 0))) { @@ -2939,19 +3606,25 @@ static int pictureflow_main(void) /* initialize */ for (i = 0; i < SLIDE_CACHE_SIZE; i++) { - cache[i].hid = 0; - cache[i].index = 0; - cache[i].next = i + 1; - cache[i].prev = i - 1; - } - cache[0].prev = i - 1; - cache[i - 1].next = 0; - cache_free = 0; + pf_sldcache.cache[i].hid = 0; + pf_sldcache.cache[i].index = 0; + pf_sldcache.cache[i].next = i + 1; + pf_sldcache.cache[i].prev = i - 1; + } + pf_sldcache.cache[0].prev = i - 1; + pf_sldcache.cache[i - 1].next = 0; + + pf_sldcache.free = 0; + pf_sldcache.used = -1; + pf_sldcache.left_idx = -1; + pf_sldcache.right_idx = -1; + pf_sldcache.center_idx = -1; + buffer = LCD_BUF; pf_state = pf_idle; - track_index = -1; + pf_tracks.cur_idx = -1; extra_fade = 0; slide_frame = 0; step = 0; @@ -3009,6 +3682,7 @@ static int pictureflow_main(void) break; case pf_idle: render_all_slides(); + incremental_albumart_cache(false); break; } @@ -3019,7 +3693,7 @@ static int pictureflow_main(void) frames = 0; } /* Draw FPS */ - if (show_fps) + if (pf_cfg.show_fps) { #ifdef USEGSLIB mylcd_set_foreground(G_BRIGHT(255)); @@ -3027,7 +3701,7 @@ static int pictureflow_main(void) mylcd_set_foreground(G_PIX(255,0,0)); #endif rb->snprintf(fpstxt, sizeof(fpstxt), "FPS: %d", fps); - if (show_album_name == ALBUM_NAME_TOP) + if (pf_cfg.show_album_name == ALBUM_NAME_TOP) fpstxt_y = LCD_HEIGHT - rb->screens[SCREEN_MAIN]->getcharheight(); else @@ -3057,9 +3731,9 @@ static int pictureflow_main(void) case PF_BACK: if ( pf_state == pf_show_tracks ) { - rb->buflib_buffer_in(&buf_ctx, borrowed); - borrowed = 0; - track_index = -1; + rb->buflib_buffer_in(&buf_ctx, pf_tracks.borrowed); + pf_tracks.borrowed = 0; + pf_tracks.cur_idx = -1; pf_state = pf_cover_out; } if (pf_state == pf_idle || pf_state == pf_scrolling) @@ -3096,7 +3770,7 @@ static int pictureflow_main(void) break; #if PF_PLAYBACK_CAPABLE case PF_CONTEXT: - if ( auto_wps != 0 ) { + if ( pf_cfg.auto_wps != 0 ) { if( pf_state == pf_idle ) { create_track_index(center_slide.slide_index); reset_track_list(); @@ -3104,7 +3778,7 @@ static int pictureflow_main(void) rb->splash(HZ*2, ID2P(LANG_ADDED_TO_PLAYLIST)); } else if( pf_state == pf_show_tracks ) { - rb->playlist_insert_track(NULL, get_track_filename(selected_track), + rb->playlist_insert_track(NULL, get_track_filename(pf_tracks.sel), PLAYLIST_INSERT_LAST, false, true); rb->playlist_sync(NULL); rb->splash(HZ*2, ID2P(LANG_ADDED_TO_PLAYLIST)); @@ -3113,18 +3787,18 @@ static int pictureflow_main(void) break; #endif case PF_TRACKLIST: - if ( auto_wps == 1 && pf_state == pf_idle ) { + if ( pf_cfg.auto_wps == 1 && pf_state == pf_idle ) { pf_state = pf_cover_in; break; } case PF_SELECT: if ( pf_state == pf_idle ) { #if PF_PLAYBACK_CAPABLE - if(auto_wps == 1) { + if(pf_cfg.auto_wps == 1) { create_track_index(center_slide.slide_index); reset_track_list(); start_playback(false); - last_album = center_index; + pf_cfg.last_album = center_index; return PLUGIN_GOTO_WPS; } else @@ -3134,8 +3808,8 @@ static int pictureflow_main(void) else if ( pf_state == pf_show_tracks ) { #if PF_PLAYBACK_CAPABLE start_playback(false); - if(auto_wps != 0) { - last_album = center_index; + if(pf_cfg.auto_wps != 0) { + pf_cfg.last_album = center_index; return PLUGIN_GOTO_WPS; } #endif @@ -3154,6 +3828,10 @@ enum plugin_status plugin_start(const void *parameter) { int ret; (void) parameter; + + void * buf; + size_t buf_size; + atexit(cleanup); #ifdef HAVE_ADJUSTABLE_CPU_FREQ @@ -3171,11 +3849,6 @@ enum plugin_status plugin_start(const void *parameter) } #endif #endif - /* create unique entry buffer with 1/4 of the plugin buffer */ - uniqbuf = buf; - uniqbuf_size = ALIGN_DOWN(buf_size / 4, 0x8); - buf += uniqbuf_size; - buf_size -= uniqbuf_size; #ifdef USEGSLIB long grey_buf_used; @@ -3190,6 +3863,10 @@ enum plugin_status plugin_start(const void *parameter) buf = (void*)(grey_buf_used + (char*)buf); #endif + /* store buffer pointers and sizes */ + pf_idx.buf = buf; + pf_idx.buf_sz = buf_size; + ret = pictureflow_main(); if ( ret == PLUGIN_OK || ret == PLUGIN_GOTO_WPS) { if (configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, |