diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/plugin.c | 3 | ||||
-rw-r--r-- | apps/plugin.h | 5 | ||||
-rw-r--r-- | apps/plugins/pictureflow/pictureflow.c | 258 | ||||
-rw-r--r-- | apps/screens.c | 6 |
4 files changed, 256 insertions, 16 deletions
diff --git a/apps/plugin.c b/apps/plugin.c index b017db017b..7c6e91424a 100644 --- a/apps/plugin.c +++ b/apps/plugin.c | |||
@@ -821,6 +821,9 @@ static const struct plugin_api rockbox_api = { | |||
821 | 821 | ||
822 | /* new stuff at the end, sort into place next time | 822 | /* new stuff at the end, sort into place next time |
823 | the API gets incompatible */ | 823 | the API gets incompatible */ |
824 | |||
825 | splash_progress, | ||
826 | splash_progress_set_delay, | ||
824 | }; | 827 | }; |
825 | 828 | ||
826 | static int plugin_buffer_handle; | 829 | static int plugin_buffer_handle; |
diff --git a/apps/plugin.h b/apps/plugin.h index ed688eb753..768fc0ff27 100644 --- a/apps/plugin.h +++ b/apps/plugin.h | |||
@@ -157,7 +157,7 @@ int plugin_open(const char *plugin, const char *parameter); | |||
157 | #define PLUGIN_MAGIC 0x526F634B /* RocK */ | 157 | #define PLUGIN_MAGIC 0x526F634B /* RocK */ |
158 | 158 | ||
159 | /* increase this every time the api struct changes */ | 159 | /* increase this every time the api struct changes */ |
160 | #define PLUGIN_API_VERSION 260 | 160 | #define PLUGIN_API_VERSION 261 |
161 | 161 | ||
162 | /* update this to latest version if a change to the api struct breaks | 162 | /* update this to latest version if a change to the api struct breaks |
163 | backwards compatibility (and please take the opportunity to sort in any | 163 | backwards compatibility (and please take the opportunity to sort in any |
@@ -945,6 +945,9 @@ struct plugin_api { | |||
945 | #endif | 945 | #endif |
946 | /* new stuff at the end, sort into place next time | 946 | /* new stuff at the end, sort into place next time |
947 | the API gets incompatible */ | 947 | the API gets incompatible */ |
948 | |||
949 | void (*splash_progress)(int current, int total, const char *fmt, ...) ATTRIBUTE_PRINTF(3, 4); | ||
950 | void (*splash_progress_set_delay)(long delay_ticks); | ||
948 | }; | 951 | }; |
949 | 952 | ||
950 | /* plugin header */ | 953 | /* plugin header */ |
diff --git a/apps/plugins/pictureflow/pictureflow.c b/apps/plugins/pictureflow/pictureflow.c index 54497d8306..61d0b64e94 100644 --- a/apps/plugins/pictureflow/pictureflow.c +++ b/apps/plugins/pictureflow/pictureflow.c | |||
@@ -397,6 +397,26 @@ struct track_data { | |||
397 | #endif | 397 | #endif |
398 | }; | 398 | }; |
399 | 399 | ||
400 | #if PF_PLAYBACK_CAPABLE | ||
401 | struct multiple_tracks_id3 { | ||
402 | unsigned long length; | ||
403 | unsigned long filesize; | ||
404 | unsigned long frequency; | ||
405 | unsigned int artist_hash; | ||
406 | unsigned int composer_hash; | ||
407 | unsigned int albumartist_hash; | ||
408 | unsigned int grouping_hash; | ||
409 | unsigned int comment_hash; | ||
410 | unsigned int album_hash; | ||
411 | unsigned int genre_hash; | ||
412 | unsigned int codectype; | ||
413 | unsigned int bitrate; | ||
414 | bool filesize_ovf; | ||
415 | bool length_ovf; | ||
416 | bool vbr; | ||
417 | }; | ||
418 | #endif | ||
419 | |||
400 | struct rect { | 420 | struct rect { |
401 | int left; | 421 | int left; |
402 | int right; | 422 | int right; |
@@ -558,6 +578,8 @@ static struct pf_index_t pf_idx; | |||
558 | 578 | ||
559 | static struct pf_track_t pf_tracks; | 579 | static struct pf_track_t pf_tracks; |
560 | 580 | ||
581 | static struct mp3entry id3; | ||
582 | |||
561 | void reset_track_list(void); | 583 | void reset_track_list(void); |
562 | 584 | ||
563 | static bool thread_is_running; | 585 | static bool thread_is_running; |
@@ -2093,7 +2115,6 @@ static bool get_albumart_for_index_from_db(const int slide_index, char *buf, | |||
2093 | pf_idx.album_index[slide_index].artist_seek); | 2115 | pf_idx.album_index[slide_index].artist_seek); |
2094 | 2116 | ||
2095 | if ( rb->tagcache_get_next(&tcs) ) { | 2117 | if ( rb->tagcache_get_next(&tcs) ) { |
2096 | struct mp3entry id3; | ||
2097 | int fd; | 2118 | int fd; |
2098 | 2119 | ||
2099 | #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) | 2120 | #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) |
@@ -2218,6 +2239,9 @@ static unsigned int mfnv(char *str) | |||
2218 | const unsigned int p = 16777619; | 2239 | const unsigned int p = 16777619; |
2219 | unsigned int hash = 0x811C9DC5; // 2166136261; | 2240 | unsigned int hash = 0x811C9DC5; // 2166136261; |
2220 | 2241 | ||
2242 | if (!str) | ||
2243 | return 0; | ||
2244 | |||
2221 | while(*str) | 2245 | while(*str) |
2222 | hash = (hash ^ *str++) * p; | 2246 | hash = (hash ^ *str++) * p; |
2223 | hash += hash << 13; | 2247 | hash += hash << 13; |
@@ -4010,6 +4034,169 @@ static void select_prev_album(void) | |||
4010 | } | 4034 | } |
4011 | 4035 | ||
4012 | #if PF_PLAYBACK_CAPABLE | 4036 | #if PF_PLAYBACK_CAPABLE |
4037 | static void collect_id3(struct multiple_tracks_id3 *mul_id3, bool is_first_track) | ||
4038 | { | ||
4039 | if (is_first_track) | ||
4040 | { | ||
4041 | mul_id3->artist_hash = mfnv(id3.artist); | ||
4042 | mul_id3->album_hash = mfnv(id3.album); | ||
4043 | mul_id3->genre_hash = mfnv(id3.genre_string); | ||
4044 | mul_id3->composer_hash = mfnv(id3.composer); | ||
4045 | mul_id3->albumartist_hash = mfnv(id3.albumartist); | ||
4046 | mul_id3->grouping_hash = mfnv(id3.grouping); | ||
4047 | mul_id3->comment_hash = mfnv(id3.comment); | ||
4048 | mul_id3->codectype = id3.codectype; | ||
4049 | mul_id3->vbr = id3.vbr; | ||
4050 | mul_id3->bitrate = id3.bitrate; | ||
4051 | mul_id3->frequency = id3.frequency; | ||
4052 | } | ||
4053 | else | ||
4054 | { | ||
4055 | if (mul_id3->artist_hash && (mfnv(id3.artist) != mul_id3->artist_hash)) | ||
4056 | mul_id3->artist_hash = 0; | ||
4057 | if (mul_id3->album_hash && (mfnv(id3.album) != mul_id3->album_hash)) | ||
4058 | mul_id3->album_hash = 0; | ||
4059 | if (mul_id3->genre_hash && (mfnv(id3.genre_string) != mul_id3->genre_hash)) | ||
4060 | mul_id3->genre_hash = 0; | ||
4061 | if (mul_id3->composer_hash && (mfnv(id3.composer) != mul_id3->composer_hash)) | ||
4062 | mul_id3->composer_hash = 0; | ||
4063 | if (mul_id3->albumartist_hash && (mfnv(id3.albumartist) != | ||
4064 | mul_id3->albumartist_hash)) | ||
4065 | mul_id3->albumartist_hash = 0; | ||
4066 | if (mul_id3->grouping_hash && (mfnv(id3.grouping) != mul_id3->grouping_hash)) | ||
4067 | mul_id3->grouping_hash = 0; | ||
4068 | if (mul_id3->comment_hash && (mfnv(id3.comment) != mul_id3->comment_hash)) | ||
4069 | mul_id3->comment_hash = 0; | ||
4070 | |||
4071 | if (mul_id3->codectype && (id3.codectype != mul_id3->codectype)) | ||
4072 | mul_id3->codectype = AFMT_UNKNOWN; | ||
4073 | if (mul_id3->bitrate && (id3.bitrate != mul_id3->bitrate || | ||
4074 | id3.vbr != mul_id3->vbr)) | ||
4075 | mul_id3->bitrate = 0; | ||
4076 | if (mul_id3->frequency && (id3.frequency != mul_id3->frequency)) | ||
4077 | mul_id3->frequency = 0; | ||
4078 | } | ||
4079 | |||
4080 | if (ULONG_MAX - mul_id3->length < id3.length) | ||
4081 | { | ||
4082 | mul_id3->length_ovf = true; | ||
4083 | mul_id3->length = 0; | ||
4084 | } | ||
4085 | else if (!mul_id3->length_ovf) | ||
4086 | mul_id3->length += id3.length; | ||
4087 | |||
4088 | if (INT_MAX - mul_id3->filesize < id3.filesize) /* output_dyn_value expects int */ | ||
4089 | { | ||
4090 | mul_id3->filesize_ovf = true; | ||
4091 | mul_id3->filesize = 0; | ||
4092 | } | ||
4093 | else if (!mul_id3->filesize_ovf) | ||
4094 | mul_id3->filesize += id3.filesize; | ||
4095 | } | ||
4096 | |||
4097 | |||
4098 | static void write_id3_mul_tracks(struct multiple_tracks_id3 *mul_id3) | ||
4099 | { | ||
4100 | id3.path[0] = '\0'; | ||
4101 | id3.title = NULL; | ||
4102 | if (!mul_id3->artist_hash) | ||
4103 | id3.artist = NULL; | ||
4104 | if (!mul_id3->album_hash) | ||
4105 | id3.album = NULL; | ||
4106 | if (!mul_id3->genre_hash) | ||
4107 | id3.genre_string = NULL; | ||
4108 | if (!mul_id3->composer_hash) | ||
4109 | id3.composer = NULL; | ||
4110 | if (!mul_id3->albumartist_hash) | ||
4111 | id3.albumartist = NULL; | ||
4112 | if (!mul_id3->grouping_hash) | ||
4113 | id3.grouping = NULL; | ||
4114 | if (!mul_id3->comment_hash) | ||
4115 | id3.comment = NULL; | ||
4116 | id3.disc_string = NULL; | ||
4117 | id3.track_string = NULL; | ||
4118 | id3.year_string = NULL; | ||
4119 | id3.year = pf_idx.album_index[center_index].year; | ||
4120 | id3.length = mul_id3->length; | ||
4121 | id3.filesize = mul_id3->filesize; | ||
4122 | id3.frequency = mul_id3->frequency; | ||
4123 | id3.bitrate = mul_id3->bitrate; | ||
4124 | id3.codectype = mul_id3->codectype; | ||
4125 | id3.vbr = mul_id3->vbr; | ||
4126 | id3.discnum = 0; | ||
4127 | id3.tracknum = 0; | ||
4128 | id3.track_level = 0; | ||
4129 | id3.album_level = 0; | ||
4130 | } | ||
4131 | |||
4132 | static void init_mul_id3(struct multiple_tracks_id3 *mul_id3) | ||
4133 | { | ||
4134 | mul_id3->artist_hash = 0; | ||
4135 | mul_id3->album_hash = 0; | ||
4136 | mul_id3->genre_hash = 0; | ||
4137 | mul_id3->composer_hash = 0; | ||
4138 | mul_id3->albumartist_hash = 0; | ||
4139 | mul_id3->grouping_hash = 0; | ||
4140 | mul_id3->comment_hash = 0; | ||
4141 | mul_id3->codectype = 0; | ||
4142 | mul_id3->vbr = false; | ||
4143 | mul_id3->bitrate = 0; | ||
4144 | mul_id3->frequency = 0; | ||
4145 | mul_id3->length = 0; | ||
4146 | mul_id3->filesize = 0; | ||
4147 | mul_id3->length_ovf = false; | ||
4148 | mul_id3->filesize_ovf = false; | ||
4149 | } | ||
4150 | |||
4151 | static int show_id3_info(const char *selected_file) | ||
4152 | { | ||
4153 | int fd, i; | ||
4154 | unsigned long last_tick; | ||
4155 | const char *file_name; | ||
4156 | bool id3_retrieval_successful; | ||
4157 | bool is_multiple_tracks = insert_whole_album && pf_tracks.count > 1; | ||
4158 | struct multiple_tracks_id3 mul_id3; | ||
4159 | |||
4160 | init_mul_id3(&mul_id3); | ||
4161 | |||
4162 | last_tick = *(rb->current_tick) + HZ/2; | ||
4163 | rb->splash_progress_set_delay(HZ / 2); /* wait 1/2 sec before progress */ | ||
4164 | i = 0; | ||
4165 | do { | ||
4166 | id3_retrieval_successful = false; | ||
4167 | file_name = i == 0 ? selected_file : get_track_filename(i); | ||
4168 | fd = rb->open(file_name, O_RDONLY); | ||
4169 | if (fd >= 0) | ||
4170 | { | ||
4171 | if (rb->get_metadata(&id3, fd, file_name)) | ||
4172 | id3_retrieval_successful = true; | ||
4173 | rb->close(fd); | ||
4174 | } | ||
4175 | if (!id3_retrieval_successful) | ||
4176 | return 0; | ||
4177 | |||
4178 | if (is_multiple_tracks) | ||
4179 | { | ||
4180 | rb->splash_progress(i, pf_tracks.count, | ||
4181 | "%s (%s)", rb->str(LANG_WAIT), rb->str(LANG_OFF_ABORT)); | ||
4182 | if (TIME_AFTER(*(rb->current_tick), last_tick + HZ/4)) | ||
4183 | { | ||
4184 | if (rb->action_userabort(TIMEOUT_NOBLOCK)) | ||
4185 | return 0; | ||
4186 | last_tick = *(rb->current_tick); | ||
4187 | } | ||
4188 | |||
4189 | collect_id3(&mul_id3, i == 0); | ||
4190 | rb->yield(); | ||
4191 | } | ||
4192 | } while (++i < pf_tracks.count && is_multiple_tracks); | ||
4193 | |||
4194 | if (is_multiple_tracks) | ||
4195 | write_id3_mul_tracks(&mul_id3); | ||
4196 | |||
4197 | return rb->browse_id3(&id3, 0, 0, NULL) ? PLUGIN_USB_CONNECTED : 0; | ||
4198 | } | ||
4199 | |||
4013 | 4200 | ||
4014 | static bool playlist_insert(int position, bool queue, bool create_new) | 4201 | static bool playlist_insert(int position, bool queue, bool create_new) |
4015 | { | 4202 | { |
@@ -4061,14 +4248,8 @@ static bool track_list_ready(void) | |||
4061 | return true; | 4248 | return true; |
4062 | } | 4249 | } |
4063 | 4250 | ||
4064 | /** | ||
4065 | Brings up "Current Playlist" menu with first | ||
4066 | track of selection. | ||
4067 | 4251 | ||
4068 | Onplay menu code calls back playlist_insert for | 4252 | static bool context_menu_ready(void) |
4069 | adding all of the tracks. | ||
4070 | */ | ||
4071 | static void show_current_playlist_menu(void) | ||
4072 | { | 4253 | { |
4073 | #ifdef USEGSLIB | 4254 | #ifdef USEGSLIB |
4074 | grey_show(false); | 4255 | grey_show(false); |
@@ -4080,13 +4261,23 @@ static void show_current_playlist_menu(void) | |||
4080 | #ifdef USEGSLIB | 4261 | #ifdef USEGSLIB |
4081 | grey_show(true); | 4262 | grey_show(true); |
4082 | #endif | 4263 | #endif |
4083 | return; | 4264 | return false; |
4084 | } | 4265 | } |
4266 | #if LCD_DEPTH > 1 | ||
4267 | #ifdef USEGSLIB | ||
4268 | rb->lcd_set_foreground(N_BRIGHT(0)); | ||
4269 | rb->lcd_set_background(N_BRIGHT(255)); | ||
4270 | #endif | ||
4271 | #endif | ||
4085 | insert_whole_album = pf_state != pf_show_tracks; | 4272 | insert_whole_album = pf_state != pf_show_tracks; |
4086 | FOR_NB_SCREENS(i) | 4273 | FOR_NB_SCREENS(i) |
4087 | rb->viewportmanager_theme_enable(i, true, NULL); | 4274 | rb->viewportmanager_theme_enable(i, true, NULL); |
4088 | rb->onplay_show_playlist_menu(get_track_filename(pf_tracks.sel), | 4275 | |
4089 | &playlist_insert); | 4276 | return true; |
4277 | } | ||
4278 | |||
4279 | static void context_menu_cleanup(void) | ||
4280 | { | ||
4090 | FOR_NB_SCREENS(i) | 4281 | FOR_NB_SCREENS(i) |
4091 | rb->viewportmanager_theme_undo(i, false); | 4282 | rb->viewportmanager_theme_undo(i, false); |
4092 | if (insert_whole_album) | 4283 | if (insert_whole_album) |
@@ -4098,6 +4289,39 @@ static void show_current_playlist_menu(void) | |||
4098 | } | 4289 | } |
4099 | 4290 | ||
4100 | 4291 | ||
4292 | static int context_menu(void) | ||
4293 | { | ||
4294 | char *file_name = get_track_filename(pf_tracks.sel); | ||
4295 | |||
4296 | enum { | ||
4297 | PF_CURRENT_PLAYLIST = 0, | ||
4298 | PF_ID3_INFO | ||
4299 | }; | ||
4300 | MENUITEM_STRINGLIST(context_menu, ID2P(LANG_ONPLAY_MENU_TITLE), NULL, | ||
4301 | ID2P(LANG_PLAYING_NEXT), | ||
4302 | ID2P(LANG_MENU_SHOW_ID3_INFO)); | ||
4303 | |||
4304 | while (1) { | ||
4305 | switch (rb->do_menu(&context_menu, | ||
4306 | NULL, NULL, false)) { | ||
4307 | |||
4308 | case PF_CURRENT_PLAYLIST: | ||
4309 | rb->onplay_show_playlist_menu(file_name, | ||
4310 | &playlist_insert); | ||
4311 | return 0; | ||
4312 | case PF_ID3_INFO: | ||
4313 | return show_id3_info(file_name); | ||
4314 | case MENU_ATTACHED_USB: | ||
4315 | return PLUGIN_USB_CONNECTED; | ||
4316 | default: | ||
4317 | return 0; | ||
4318 | |||
4319 | } | ||
4320 | } | ||
4321 | } | ||
4322 | |||
4323 | |||
4324 | |||
4101 | /* | 4325 | /* |
4102 | * Puts selected album's tracks into a newly created playlist and starts playing | 4326 | * Puts selected album's tracks into a newly created playlist and starts playing |
4103 | */ | 4327 | */ |
@@ -4247,7 +4471,6 @@ static void set_initial_slide(const char* selected_file) | |||
4247 | pf_cfg.last_album); | 4471 | pf_cfg.last_album); |
4248 | else | 4472 | else |
4249 | { | 4473 | { |
4250 | static struct mp3entry id3; | ||
4251 | #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) | 4474 | #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) |
4252 | if (rb->tagcache_fill_tags(&id3, selected_file)) | 4475 | if (rb->tagcache_fill_tags(&id3, selected_file)) |
4253 | set_current_slide(id3_get_index(&id3)); | 4476 | set_current_slide(id3_get_index(&id3)); |
@@ -4601,8 +4824,8 @@ static int pictureflow_main(const char* selected_file) | |||
4601 | #if PF_PLAYBACK_CAPABLE | 4824 | #if PF_PLAYBACK_CAPABLE |
4602 | case PF_CONTEXT: | 4825 | case PF_CONTEXT: |
4603 | if (pf_state == pf_idle || pf_state == pf_scrolling || | 4826 | if (pf_state == pf_idle || pf_state == pf_scrolling || |
4604 | pf_state == pf_show_tracks || pf_state == pf_cover_out) { | 4827 | pf_state == pf_show_tracks || pf_state == pf_cover_out) |
4605 | 4828 | { | |
4606 | if ( pf_state == pf_scrolling) | 4829 | if ( pf_state == pf_scrolling) |
4607 | { | 4830 | { |
4608 | set_current_slide(target); | 4831 | set_current_slide(target); |
@@ -4611,7 +4834,12 @@ static int pictureflow_main(const char* selected_file) | |||
4611 | else if (pf_state == pf_cover_out) | 4834 | else if (pf_state == pf_cover_out) |
4612 | interrupt_cover_out_animation(); | 4835 | interrupt_cover_out_animation(); |
4613 | 4836 | ||
4614 | show_current_playlist_menu(); | 4837 | if (context_menu_ready()) |
4838 | { | ||
4839 | ret = context_menu(); | ||
4840 | context_menu_cleanup(); | ||
4841 | if ( ret != 0 ) return ret; | ||
4842 | } | ||
4615 | } | 4843 | } |
4616 | break; | 4844 | break; |
4617 | #endif | 4845 | #endif |
diff --git a/apps/screens.c b/apps/screens.c index 91280a72f1..869d081498 100644 --- a/apps/screens.c +++ b/apps/screens.c | |||
@@ -622,6 +622,8 @@ static const char * id3_get_or_speak_info(int selected_item, void* data, | |||
622 | talk_spell(val, true); | 622 | talk_spell(val, true); |
623 | break; | 623 | break; |
624 | case LANG_ID3_BITRATE: | 624 | case LANG_ID3_BITRATE: |
625 | if (!id3->bitrate) | ||
626 | return NULL; | ||
625 | snprintf(buffer, buffer_len, "%d kbps%s", id3->bitrate, | 627 | snprintf(buffer, buffer_len, "%d kbps%s", id3->bitrate, |
626 | id3->vbr ? str(LANG_ID3_VBR) : (const unsigned char*) ""); | 628 | id3->vbr ? str(LANG_ID3_VBR) : (const unsigned char*) ""); |
627 | val=buffer; | 629 | val=buffer; |
@@ -633,6 +635,8 @@ static const char * id3_get_or_speak_info(int selected_item, void* data, | |||
633 | } | 635 | } |
634 | break; | 636 | break; |
635 | case LANG_ID3_FREQUENCY: | 637 | case LANG_ID3_FREQUENCY: |
638 | if (!id3->frequency) | ||
639 | return NULL; | ||
636 | snprintf(buffer, buffer_len, "%ld Hz", id3->frequency); | 640 | snprintf(buffer, buffer_len, "%ld Hz", id3->frequency); |
637 | val=buffer; | 641 | val=buffer; |
638 | if(say_it) | 642 | if(say_it) |
@@ -661,6 +665,8 @@ static const char * id3_get_or_speak_info(int selected_item, void* data, | |||
661 | talk_spell(val, true); | 665 | talk_spell(val, true); |
662 | break; | 666 | break; |
663 | case LANG_FILESIZE: /* not LANG_ID3_FILESIZE because the string is shared */ | 667 | case LANG_FILESIZE: /* not LANG_ID3_FILESIZE because the string is shared */ |
668 | if (!id3->filesize) | ||
669 | return NULL; | ||
664 | output_dyn_value(buffer, buffer_len, id3->filesize, byte_units, 4, true); | 670 | output_dyn_value(buffer, buffer_len, id3->filesize, byte_units, 4, true); |
665 | val=buffer; | 671 | val=buffer; |
666 | if(say_it && val) | 672 | if(say_it && val) |