diff options
Diffstat (limited to 'apps/tagtree.c')
-rw-r--r-- | apps/tagtree.c | 270 |
1 files changed, 225 insertions, 45 deletions
diff --git a/apps/tagtree.c b/apps/tagtree.c index d2e27a3e58..1a49936f45 100644 --- a/apps/tagtree.c +++ b/apps/tagtree.c | |||
@@ -56,6 +56,8 @@ | |||
56 | #include "playback.h" | 56 | #include "playback.h" |
57 | #include "strnatcmp.h" | 57 | #include "strnatcmp.h" |
58 | #include "panic.h" | 58 | #include "panic.h" |
59 | #include "onplay.h" | ||
60 | #include "plugin.h" | ||
59 | 61 | ||
60 | #define str_or_empty(x) (x ? x : "(NULL)") | 62 | #define str_or_empty(x) (x ? x : "(NULL)") |
61 | 63 | ||
@@ -64,6 +66,10 @@ | |||
64 | 66 | ||
65 | static int tagtree_play_folder(struct tree_context* c); | 67 | static int tagtree_play_folder(struct tree_context* c); |
66 | 68 | ||
69 | /* reuse of tagtree data after tagtree_play_folder() */ | ||
70 | static uint32_t loaded_entries_crc = 0; | ||
71 | |||
72 | |||
67 | /* this needs to be same size as struct entry (tree.h) and name needs to be | 73 | /* this needs to be same size as struct entry (tree.h) and name needs to be |
68 | * the first; so that they're compatible enough to walk arrays of both | 74 | * the first; so that they're compatible enough to walk arrays of both |
69 | * derefencing the name member*/ | 75 | * derefencing the name member*/ |
@@ -71,6 +77,7 @@ struct tagentry { | |||
71 | char* name; | 77 | char* name; |
72 | int newtable; | 78 | int newtable; |
73 | int extraseek; | 79 | int extraseek; |
80 | int customaction; | ||
74 | }; | 81 | }; |
75 | 82 | ||
76 | static struct tagentry* tagtree_get_entry(struct tree_context *c, int id); | 83 | static struct tagentry* tagtree_get_entry(struct tree_context *c, int id); |
@@ -78,10 +85,10 @@ static struct tagentry* tagtree_get_entry(struct tree_context *c, int id); | |||
78 | #define SEARCHSTR_SIZE 256 | 85 | #define SEARCHSTR_SIZE 256 |
79 | 86 | ||
80 | enum table { | 87 | enum table { |
81 | ROOT = 1, | 88 | TABLE_ROOT = 1, |
82 | NAVIBROWSE, | 89 | TABLE_NAVIBROWSE, |
83 | ALLSUBENTRIES, | 90 | TABLE_ALLSUBENTRIES, |
84 | PLAYTRACK, | 91 | TABLE_PLAYTRACK, |
85 | }; | 92 | }; |
86 | 93 | ||
87 | static const struct id3_to_search_mapping { | 94 | static const struct id3_to_search_mapping { |
@@ -108,6 +115,7 @@ enum variables { | |||
108 | menu_next, | 115 | menu_next, |
109 | menu_load, | 116 | menu_load, |
110 | menu_reload, | 117 | menu_reload, |
118 | menu_shuffle_songs, | ||
111 | }; | 119 | }; |
112 | 120 | ||
113 | /* Capacity 10 000 entries (for example 10k different artists) */ | 121 | /* Capacity 10 000 entries (for example 10k different artists) */ |
@@ -276,6 +284,20 @@ static struct buflib_callbacks ops = { | |||
276 | .shrink_callback = NULL, | 284 | .shrink_callback = NULL, |
277 | }; | 285 | }; |
278 | 286 | ||
287 | static uint32_t tagtree_data_crc(struct tree_context* c) | ||
288 | { | ||
289 | char* buf; | ||
290 | uint32_t crc; | ||
291 | buf = core_get_data(tagtree_handle); /* data for the search clauses etc */ | ||
292 | crc = crc_32(buf, tagtree_buf_used, c->dirlength); | ||
293 | buf = core_get_data(c->cache.name_buffer_handle); /* names */ | ||
294 | crc = crc_32(buf, c->cache.name_buffer_size, crc); | ||
295 | buf = core_get_data(c->cache.entries_handle); /* tagentries */ | ||
296 | crc = crc_32(buf, c->cache.max_entries * sizeof(struct tagentry), crc); | ||
297 | logf("%s 0x%x", __func__, crc); | ||
298 | return crc; | ||
299 | } | ||
300 | |||
279 | static void* tagtree_alloc(size_t size) | 301 | static void* tagtree_alloc(size_t size) |
280 | { | 302 | { |
281 | size = ALIGN_UP(size, sizeof(void*)); | 303 | size = ALIGN_UP(size, sizeof(void*)); |
@@ -338,6 +360,7 @@ static int get_tag(int *tag) | |||
338 | TAG_MATCH("Pm", tag_virt_playtime_min), | 360 | TAG_MATCH("Pm", tag_virt_playtime_min), |
339 | TAG_MATCH("Ps", tag_virt_playtime_sec), | 361 | TAG_MATCH("Ps", tag_virt_playtime_sec), |
340 | TAG_MATCH("->", menu_next), | 362 | TAG_MATCH("->", menu_next), |
363 | TAG_MATCH("~>", menu_shuffle_songs), | ||
341 | 364 | ||
342 | TAG_MATCH("==>", menu_load), | 365 | TAG_MATCH("==>", menu_load), |
343 | 366 | ||
@@ -820,7 +843,7 @@ static bool parse_search(struct menu_entry *entry, const char *str) | |||
820 | return true; | 843 | return true; |
821 | } | 844 | } |
822 | 845 | ||
823 | if (entry->type != menu_next) | 846 | if (entry->type != menu_next && entry->type != menu_shuffle_songs) |
824 | return false; | 847 | return false; |
825 | 848 | ||
826 | while (inst->tagorder_count < MAX_TAGS) | 849 | while (inst->tagorder_count < MAX_TAGS) |
@@ -847,7 +870,7 @@ static bool parse_search(struct menu_entry *entry, const char *str) | |||
847 | 870 | ||
848 | inst->tagorder_count++; | 871 | inst->tagorder_count++; |
849 | 872 | ||
850 | if (get_tag(&type) <= 0 || type != menu_next) | 873 | if (get_tag(&type) <= 0 || (type != menu_next && type != menu_shuffle_songs)) |
851 | break; | 874 | break; |
852 | } | 875 | } |
853 | 876 | ||
@@ -1245,6 +1268,7 @@ static void tagtree_unload(struct tree_context *c) | |||
1245 | dptr->name = NULL; | 1268 | dptr->name = NULL; |
1246 | dptr->newtable = 0; | 1269 | dptr->newtable = 0; |
1247 | dptr->extraseek = 0; | 1270 | dptr->extraseek = 0; |
1271 | dptr->customaction = ONPLAY_NO_CUSTOMACTION; | ||
1248 | dptr++; | 1272 | dptr++; |
1249 | } | 1273 | } |
1250 | } | 1274 | } |
@@ -1454,7 +1478,7 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init) | |||
1454 | #endif | 1478 | #endif |
1455 | , 0, 0, 0); | 1479 | , 0, 0, 0); |
1456 | 1480 | ||
1457 | if (c->currtable == ALLSUBENTRIES) | 1481 | if (c->currtable == TABLE_ALLSUBENTRIES) |
1458 | { | 1482 | { |
1459 | tag = tag_title; | 1483 | tag = tag_title; |
1460 | level--; | 1484 | level--; |
@@ -1544,17 +1568,19 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init) | |||
1544 | { | 1568 | { |
1545 | if (offset == 0) | 1569 | if (offset == 0) |
1546 | { | 1570 | { |
1547 | dptr->newtable = ALLSUBENTRIES; | 1571 | dptr->newtable = TABLE_ALLSUBENTRIES; |
1548 | dptr->name = str(LANG_TAGNAVI_ALL_TRACKS); | 1572 | dptr->name = str(LANG_TAGNAVI_ALL_TRACKS); |
1573 | dptr->customaction = ONPLAY_NO_CUSTOMACTION; | ||
1549 | dptr++; | 1574 | dptr++; |
1550 | current_entry_count++; | 1575 | current_entry_count++; |
1551 | special_entry_count++; | 1576 | special_entry_count++; |
1552 | } | 1577 | } |
1553 | if (offset <= 1) | 1578 | if (offset <= 1) |
1554 | { | 1579 | { |
1555 | dptr->newtable = NAVIBROWSE; | 1580 | dptr->newtable = TABLE_NAVIBROWSE; |
1556 | dptr->name = str(LANG_TAGNAVI_RANDOM); | 1581 | dptr->name = str(LANG_TAGNAVI_RANDOM); |
1557 | dptr->extraseek = -1; | 1582 | dptr->extraseek = -1; |
1583 | dptr->customaction = ONPLAY_NO_CUSTOMACTION; | ||
1558 | dptr++; | 1584 | dptr++; |
1559 | current_entry_count++; | 1585 | current_entry_count++; |
1560 | special_entry_count++; | 1586 | special_entry_count++; |
@@ -1568,14 +1594,15 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init) | |||
1568 | if (total_count++ < offset) | 1594 | if (total_count++ < offset) |
1569 | continue; | 1595 | continue; |
1570 | 1596 | ||
1571 | dptr->newtable = NAVIBROWSE; | 1597 | dptr->newtable = TABLE_NAVIBROWSE; |
1572 | if (tag == tag_title || tag == tag_filename) | 1598 | if (tag == tag_title || tag == tag_filename) |
1573 | { | 1599 | { |
1574 | dptr->newtable = PLAYTRACK; | 1600 | dptr->newtable = TABLE_PLAYTRACK; |
1575 | dptr->extraseek = tcs.idx_id; | 1601 | dptr->extraseek = tcs.idx_id; |
1576 | } | 1602 | } |
1577 | else | 1603 | else |
1578 | dptr->extraseek = tcs.result_seek; | 1604 | dptr->extraseek = tcs.result_seek; |
1605 | dptr->customaction = ONPLAY_NO_CUSTOMACTION; | ||
1579 | 1606 | ||
1580 | fmt = NULL; | 1607 | fmt = NULL; |
1581 | /* Check the format */ | 1608 | /* Check the format */ |
@@ -1758,7 +1785,7 @@ static int load_root(struct tree_context *c) | |||
1758 | int i; | 1785 | int i; |
1759 | 1786 | ||
1760 | tc = c; | 1787 | tc = c; |
1761 | c->currtable = ROOT; | 1788 | c->currtable = TABLE_ROOT; |
1762 | if (c->dirlevel == 0) | 1789 | if (c->dirlevel == 0) |
1763 | c->currextra = rootmenu; | 1790 | c->currextra = rootmenu; |
1764 | 1791 | ||
@@ -1775,13 +1802,21 @@ static int load_root(struct tree_context *c) | |||
1775 | switch (menu->items[i]->type) | 1802 | switch (menu->items[i]->type) |
1776 | { | 1803 | { |
1777 | case menu_next: | 1804 | case menu_next: |
1778 | dptr->newtable = NAVIBROWSE; | 1805 | dptr->newtable = TABLE_NAVIBROWSE; |
1779 | dptr->extraseek = i; | 1806 | dptr->extraseek = i; |
1807 | dptr->customaction = ONPLAY_NO_CUSTOMACTION; | ||
1780 | break; | 1808 | break; |
1781 | 1809 | ||
1782 | case menu_load: | 1810 | case menu_load: |
1783 | dptr->newtable = ROOT; | 1811 | dptr->newtable = TABLE_ROOT; |
1784 | dptr->extraseek = menu->items[i]->link; | 1812 | dptr->extraseek = menu->items[i]->link; |
1813 | dptr->customaction = ONPLAY_NO_CUSTOMACTION; | ||
1814 | break; | ||
1815 | |||
1816 | case menu_shuffle_songs: | ||
1817 | dptr->newtable = TABLE_NAVIBROWSE; | ||
1818 | dptr->extraseek = i; | ||
1819 | dptr->customaction = ONPLAY_CUSTOMACTION_SHUFFLE_SONGS; | ||
1785 | break; | 1820 | break; |
1786 | } | 1821 | } |
1787 | 1822 | ||
@@ -1796,6 +1831,8 @@ static int load_root(struct tree_context *c) | |||
1796 | 1831 | ||
1797 | int tagtree_load(struct tree_context* c) | 1832 | int tagtree_load(struct tree_context* c) |
1798 | { | 1833 | { |
1834 | logf( "%s", __func__); | ||
1835 | |||
1799 | int count; | 1836 | int count; |
1800 | int table = c->currtable; | 1837 | int table = c->currtable; |
1801 | 1838 | ||
@@ -1804,20 +1841,32 @@ int tagtree_load(struct tree_context* c) | |||
1804 | if (!table) | 1841 | if (!table) |
1805 | { | 1842 | { |
1806 | c->dirfull = false; | 1843 | c->dirfull = false; |
1807 | table = ROOT; | 1844 | table = TABLE_ROOT; |
1808 | c->currtable = table; | 1845 | c->currtable = table; |
1809 | c->currextra = rootmenu; | 1846 | c->currextra = rootmenu; |
1810 | } | 1847 | } |
1811 | 1848 | ||
1812 | switch (table) | 1849 | switch (table) |
1813 | { | 1850 | { |
1814 | case ROOT: | 1851 | case TABLE_ROOT: |
1852 | logf( "root..."); | ||
1815 | count = load_root(c); | 1853 | count = load_root(c); |
1816 | break; | 1854 | break; |
1817 | 1855 | ||
1818 | case ALLSUBENTRIES: | 1856 | case TABLE_ALLSUBENTRIES: |
1819 | case NAVIBROWSE: | 1857 | case TABLE_NAVIBROWSE: |
1820 | logf("navibrowse..."); | 1858 | logf("navibrowse..."); |
1859 | |||
1860 | if (loaded_entries_crc != 0) | ||
1861 | { | ||
1862 | if (loaded_entries_crc == tagtree_data_crc(c)) | ||
1863 | { | ||
1864 | count = c->dirlength; | ||
1865 | logf("Reusing %d entries", count); | ||
1866 | break; | ||
1867 | } | ||
1868 | } | ||
1869 | |||
1821 | cpu_boost(true); | 1870 | cpu_boost(true); |
1822 | count = retrieve_entries(c, 0, true); | 1871 | count = retrieve_entries(c, 0, true); |
1823 | cpu_boost(false); | 1872 | cpu_boost(false); |
@@ -1828,6 +1877,8 @@ int tagtree_load(struct tree_context* c) | |||
1828 | return -1; | 1877 | return -1; |
1829 | } | 1878 | } |
1830 | 1879 | ||
1880 | loaded_entries_crc = 0; | ||
1881 | |||
1831 | if (count < 0) | 1882 | if (count < 0) |
1832 | { | 1883 | { |
1833 | if (count != RELOAD_TAGTREE) | 1884 | if (count != RELOAD_TAGTREE) |
@@ -1860,6 +1911,8 @@ int tagtree_load(struct tree_context* c) | |||
1860 | */ | 1911 | */ |
1861 | int tagtree_enter(struct tree_context* c, bool is_visible) | 1912 | int tagtree_enter(struct tree_context* c, bool is_visible) |
1862 | { | 1913 | { |
1914 | logf( "%s", __func__); | ||
1915 | |||
1863 | int rc = 0; | 1916 | int rc = 0; |
1864 | struct tagentry *dptr; | 1917 | struct tagentry *dptr; |
1865 | struct mp3entry *id3; | 1918 | struct mp3entry *id3; |
@@ -1921,16 +1974,16 @@ int tagtree_enter(struct tree_context* c, bool is_visible) | |||
1921 | core_pin(tagtree_handle); | 1974 | core_pin(tagtree_handle); |
1922 | 1975 | ||
1923 | switch (c->currtable) { | 1976 | switch (c->currtable) { |
1924 | case ROOT: | 1977 | case TABLE_ROOT: |
1925 | c->currextra = newextra; | 1978 | c->currextra = newextra; |
1926 | 1979 | ||
1927 | if (newextra == ROOT) | 1980 | if (newextra == TABLE_ROOT) |
1928 | { | 1981 | { |
1929 | menu = menus[seek]; | 1982 | menu = menus[seek]; |
1930 | c->currextra = seek; | 1983 | c->currextra = seek; |
1931 | } | 1984 | } |
1932 | 1985 | ||
1933 | else if (newextra == NAVIBROWSE) | 1986 | else if (newextra == TABLE_NAVIBROWSE) |
1934 | { | 1987 | { |
1935 | int i, j; | 1988 | int i, j; |
1936 | 1989 | ||
@@ -2005,9 +2058,9 @@ int tagtree_enter(struct tree_context* c, bool is_visible) | |||
2005 | 2058 | ||
2006 | break; | 2059 | break; |
2007 | 2060 | ||
2008 | case NAVIBROWSE: | 2061 | case TABLE_NAVIBROWSE: |
2009 | case ALLSUBENTRIES: | 2062 | case TABLE_ALLSUBENTRIES: |
2010 | if (newextra == PLAYTRACK) | 2063 | if (newextra == TABLE_PLAYTRACK) |
2011 | { | 2064 | { |
2012 | adjust_selection = false; | 2065 | adjust_selection = false; |
2013 | 2066 | ||
@@ -2059,6 +2112,7 @@ int tagtree_enter(struct tree_context* c, bool is_visible) | |||
2059 | /* Exits current database menu or table */ | 2112 | /* Exits current database menu or table */ |
2060 | void tagtree_exit(struct tree_context* c, bool is_visible) | 2113 | void tagtree_exit(struct tree_context* c, bool is_visible) |
2061 | { | 2114 | { |
2115 | logf( "%s", __func__); | ||
2062 | if (is_visible) /* update selection history only for user-selected items */ | 2116 | if (is_visible) /* update selection history only for user-selected items */ |
2063 | { | 2117 | { |
2064 | if (c->selected_item != selected_item_history[c->dirlevel]) | 2118 | if (c->selected_item != selected_item_history[c->dirlevel]) |
@@ -2102,15 +2156,54 @@ int tagtree_get_filename(struct tree_context* c, char *buf, int buflen) | |||
2102 | return 0; | 2156 | return 0; |
2103 | } | 2157 | } |
2104 | 2158 | ||
2159 | int tagtree_get_custom_action(struct tree_context* c) | ||
2160 | { | ||
2161 | return tagtree_get_entry(c, c->selected_item)->customaction; | ||
2162 | } | ||
2163 | |||
2164 | static void swap_array_bool(bool *a, bool *b) | ||
2165 | { | ||
2166 | bool temp = *a; | ||
2167 | *a = *b; | ||
2168 | *b = temp; | ||
2169 | } | ||
2170 | |||
2171 | /** | ||
2172 | * Randomly shuffle an array using the Fisher-Yates algorithm : | ||
2173 | * https://en.wikipedia.org/wiki/Random_permutation | ||
2174 | * This algorithm has a linear complexity. | ||
2175 | * Don't forget to srand before call to use it with a relevant seed. | ||
2176 | */ | ||
2177 | static bool* fill_random_playlist_indexes(bool *bool_array, size_t arr_sz, | ||
2178 | size_t track_count, size_t max_slots) | ||
2179 | { | ||
2180 | size_t i; | ||
2181 | if (track_count * sizeof(bool) > arr_sz || max_slots > track_count) | ||
2182 | return NULL; | ||
2183 | |||
2184 | for (i = 0; i < arr_sz; i++) /* fill max_slots with TRUE */ | ||
2185 | bool_array[i] = i < max_slots; | ||
2186 | |||
2187 | /* shuffle bool array */ | ||
2188 | for (i = track_count - 1; i > 0; i--) | ||
2189 | { | ||
2190 | int j = rand() % (i + 1); | ||
2191 | swap_array_bool(&bool_array[i], &bool_array[j]); | ||
2192 | } | ||
2193 | return bool_array; | ||
2194 | } | ||
2105 | 2195 | ||
2106 | static bool insert_all_playlist(struct tree_context *c, | 2196 | static bool insert_all_playlist(struct tree_context *c, |
2107 | const char* playlist, bool new_playlist, | 2197 | const char* playlist, bool new_playlist, |
2108 | int position, bool queue) | 2198 | int position, bool queue) |
2109 | { | 2199 | { |
2110 | struct tagcache_search tcs; | 2200 | struct tagcache_search tcs; |
2111 | int i, n; | 2201 | int n; |
2112 | int fd = -1; | 2202 | int fd = -1; |
2113 | unsigned long last_tick; | 2203 | unsigned long last_tick; |
2204 | int slots_remaining = 0; | ||
2205 | bool fill_randomly = false; | ||
2206 | bool *rand_bool_array = NULL; | ||
2114 | char buf[MAX_PATH]; | 2207 | char buf[MAX_PATH]; |
2115 | 2208 | ||
2116 | cpu_boost(true); | 2209 | cpu_boost(true); |
@@ -2148,40 +2241,114 @@ static bool insert_all_playlist(struct tree_context *c, | |||
2148 | last_tick = current_tick + HZ/2; /* Show splash after 0.5 seconds have passed */ | 2241 | last_tick = current_tick + HZ/2; /* Show splash after 0.5 seconds have passed */ |
2149 | splash_progress_set_delay(HZ / 2); /* wait 1/2 sec before progress */ | 2242 | splash_progress_set_delay(HZ / 2); /* wait 1/2 sec before progress */ |
2150 | n = c->filesindir; | 2243 | n = c->filesindir; |
2151 | for (i = 0; i < n; i++) | 2244 | |
2245 | if (playlist == NULL) | ||
2152 | { | 2246 | { |
2247 | int max_playlist_size = playlist_get_current()->max_playlist_size; | ||
2248 | slots_remaining = max_playlist_size - playlist_get_current()->amount; | ||
2249 | if (slots_remaining <= 0) | ||
2250 | { | ||
2251 | logf("Playlist has no space remaining"); | ||
2252 | cpu_boost(false); | ||
2253 | return false; | ||
2254 | } | ||
2153 | 2255 | ||
2154 | splash_progress(i, n, "%s (%s)", str(LANG_WAIT), str(LANG_OFF_ABORT)); | 2256 | fill_randomly = n > slots_remaining; |
2257 | |||
2258 | if (fill_randomly) | ||
2259 | { | ||
2260 | srand(current_tick); | ||
2261 | size_t bufsize = 0; | ||
2262 | bool *buffer = (bool *) plugin_get_buffer(&bufsize); | ||
2263 | rand_bool_array = fill_random_playlist_indexes(buffer, bufsize, | ||
2264 | n, slots_remaining); | ||
2265 | |||
2266 | talk_id(LANG_RANDOM_SHUFFLE_RANDOM_SELECTIVE_SONGS_SUMMARY, true); | ||
2267 | splashf(HZ * 2, str(LANG_RANDOM_SHUFFLE_RANDOM_SELECTIVE_SONGS_SUMMARY), | ||
2268 | slots_remaining); | ||
2269 | } | ||
2270 | } | ||
2271 | |||
2272 | bool exit_loop_now = false; | ||
2273 | for (int i = 0; i < n; i++) | ||
2274 | { | ||
2155 | if (TIME_AFTER(current_tick, last_tick + HZ/4)) | 2275 | if (TIME_AFTER(current_tick, last_tick + HZ/4)) |
2156 | { | 2276 | { |
2277 | splash_progress(i, n, "%s (%s)", str(LANG_WAIT), str(LANG_OFF_ABORT)); | ||
2157 | if (action_userabort(TIMEOUT_NOBLOCK)) | 2278 | if (action_userabort(TIMEOUT_NOBLOCK)) |
2279 | { | ||
2280 | exit_loop_now = true; | ||
2158 | break; | 2281 | break; |
2282 | } | ||
2159 | last_tick = current_tick; | 2283 | last_tick = current_tick; |
2160 | } | 2284 | } |
2161 | 2285 | ||
2162 | if (!tagcache_retrieve(&tcs, tagtree_get_entry(c, i)->extraseek, | 2286 | if (playlist == NULL) |
2163 | tcs.type, buf, sizeof buf)) | ||
2164 | { | 2287 | { |
2165 | continue; | 2288 | if (fill_randomly) |
2289 | { | ||
2290 | int remaining_tracks = n - i; | ||
2291 | if (remaining_tracks > slots_remaining) | ||
2292 | { | ||
2293 | if (rand_bool_array) | ||
2294 | { | ||
2295 | /* Skip the track if rand_bool_array[i] is FALSE */ | ||
2296 | if (!rand_bool_array[i]) | ||
2297 | continue; | ||
2298 | } | ||
2299 | else | ||
2300 | { | ||
2301 | /* Generate random value between 0 and remaining_tracks - 1 */ | ||
2302 | int selrange = RAND_MAX / remaining_tracks; /* Improve distribution */ | ||
2303 | int random; | ||
2304 | |||
2305 | for (int r = 0; r < 0x0FFF; r++) /* limit loops */ | ||
2306 | { | ||
2307 | random = rand() / selrange; | ||
2308 | if (random < remaining_tracks) | ||
2309 | break; | ||
2310 | else | ||
2311 | random = 0; | ||
2312 | } | ||
2313 | /* Skip the track if random >= slots_remaining */ | ||
2314 | if (random >= slots_remaining) | ||
2315 | continue; | ||
2316 | } | ||
2317 | } | ||
2318 | } | ||
2166 | } | 2319 | } |
2167 | 2320 | ||
2321 | if (!tagcache_retrieve(&tcs, tagtree_get_entry(c, i)->extraseek, tcs.type, buf, sizeof buf)) | ||
2322 | continue; | ||
2323 | |||
2168 | if (playlist == NULL) | 2324 | if (playlist == NULL) |
2169 | { | 2325 | { |
2170 | if (playlist_insert_track(NULL, buf, position, queue, false) < 0) | 2326 | if (fill_randomly) |
2171 | { | 2327 | { |
2328 | if (--slots_remaining <= 0) | ||
2329 | { | ||
2330 | exit_loop_now = true; | ||
2331 | break; | ||
2332 | } | ||
2333 | } | ||
2334 | |||
2335 | if (playlist_insert_track(NULL, buf, position, queue, false) < 0) { | ||
2172 | logf("playlist_insert_track failed"); | 2336 | logf("playlist_insert_track failed"); |
2337 | exit_loop_now = true; | ||
2173 | break; | 2338 | break; |
2174 | } | 2339 | } |
2175 | } | 2340 | } |
2176 | else if (fdprintf(fd, "%s\n", buf) <= 0) | 2341 | else if (fdprintf(fd, "%s\n", buf) <= 0) |
2177 | break; | 2342 | { |
2178 | 2343 | exit_loop_now = true; | |
2344 | break; | ||
2345 | } | ||
2179 | yield(); | 2346 | yield(); |
2180 | |||
2181 | if (playlist == NULL && position == PLAYLIST_INSERT_FIRST) | 2347 | if (playlist == NULL && position == PLAYLIST_INSERT_FIRST) |
2182 | { | ||
2183 | position = PLAYLIST_INSERT; | 2348 | position = PLAYLIST_INSERT; |
2184 | } | 2349 | |
2350 | if (exit_loop_now) | ||
2351 | break; | ||
2185 | } | 2352 | } |
2186 | if (playlist == NULL) | 2353 | if (playlist == NULL) |
2187 | playlist_sync(NULL); | 2354 | playlist_sync(NULL); |
@@ -2196,14 +2363,14 @@ static bool insert_all_playlist(struct tree_context *c, | |||
2196 | static bool goto_allsubentries(int newtable) | 2363 | static bool goto_allsubentries(int newtable) |
2197 | { | 2364 | { |
2198 | int i = 0; | 2365 | int i = 0; |
2199 | while (i < 2 && (newtable == NAVIBROWSE || newtable == ALLSUBENTRIES)) | 2366 | while (i < 2 && (newtable == TABLE_NAVIBROWSE || newtable == TABLE_ALLSUBENTRIES)) |
2200 | { | 2367 | { |
2201 | tagtree_enter(tc, false); | 2368 | tagtree_enter(tc, false); |
2202 | tagtree_load(tc); | 2369 | tagtree_load(tc); |
2203 | newtable = tagtree_get_entry(tc, tc->selected_item)->newtable; | 2370 | newtable = tagtree_get_entry(tc, tc->selected_item)->newtable; |
2204 | i++; | 2371 | i++; |
2205 | } | 2372 | } |
2206 | return (newtable == PLAYTRACK); | 2373 | return (newtable == TABLE_PLAYTRACK); |
2207 | } | 2374 | } |
2208 | 2375 | ||
2209 | static void reset_tc_to_prev(int dirlevel, int selected_item) | 2376 | static void reset_tc_to_prev(int dirlevel, int selected_item) |
@@ -2233,7 +2400,7 @@ static bool tagtree_insert_selection(int position, bool queue, | |||
2233 | 2400 | ||
2234 | newtable = tagtree_get_entry(tc, tc->selected_item)->newtable; | 2401 | newtable = tagtree_get_entry(tc, tc->selected_item)->newtable; |
2235 | 2402 | ||
2236 | if (newtable == PLAYTRACK) /* Insert a single track? */ | 2403 | if (newtable == TABLE_PLAYTRACK) /* Insert a single track? */ |
2237 | { | 2404 | { |
2238 | if (tagtree_get_filename(tc, buf, sizeof buf) < 0) | 2405 | if (tagtree_get_filename(tc, buf, sizeof buf) < 0) |
2239 | return false; | 2406 | return false; |
@@ -2342,6 +2509,7 @@ int tagtree_add_to_playlist(const char* playlist, bool new_playlist) | |||
2342 | 2509 | ||
2343 | static int tagtree_play_folder(struct tree_context* c) | 2510 | static int tagtree_play_folder(struct tree_context* c) |
2344 | { | 2511 | { |
2512 | logf( "%s", __func__); | ||
2345 | int start_index = c->selected_item; | 2513 | int start_index = c->selected_item; |
2346 | 2514 | ||
2347 | if (playlist_create(NULL, NULL) < 0) | 2515 | if (playlist_create(NULL, NULL) < 0) |
@@ -2353,14 +2521,26 @@ static int tagtree_play_folder(struct tree_context* c) | |||
2353 | if (!insert_all_playlist(c, NULL, false, PLAYLIST_INSERT_LAST, false)) | 2521 | if (!insert_all_playlist(c, NULL, false, PLAYLIST_INSERT_LAST, false)) |
2354 | return -2; | 2522 | return -2; |
2355 | 2523 | ||
2524 | int n = c->filesindir; | ||
2525 | bool has_playlist_been_randomized = n > playlist_get_current()->max_playlist_size; | ||
2526 | if (has_playlist_been_randomized) | ||
2527 | { | ||
2528 | /* We need to recalculate the start index based on a percentage to put the user | ||
2529 | around its desired start position and avoid out of bounds */ | ||
2530 | |||
2531 | int percentage_start_index = 100 * start_index / n; | ||
2532 | start_index = percentage_start_index * playlist_get_current()->amount / 100; | ||
2533 | } | ||
2534 | |||
2356 | if (global_settings.playlist_shuffle) | 2535 | if (global_settings.playlist_shuffle) |
2357 | { | 2536 | { |
2358 | start_index = playlist_shuffle(current_tick, c->selected_item); | 2537 | start_index = playlist_shuffle(current_tick, start_index); |
2359 | if (!global_settings.play_selected) | 2538 | if (!global_settings.play_selected) |
2360 | start_index = 0; | 2539 | start_index = 0; |
2361 | } | 2540 | } |
2362 | 2541 | ||
2363 | playlist_start(start_index, 0, 0); | 2542 | playlist_start(start_index, 0, 0); |
2543 | loaded_entries_crc = tagtree_data_crc(c); /* save crc in case we return */ | ||
2364 | return 0; | 2544 | return 0; |
2365 | } | 2545 | } |
2366 | 2546 | ||
@@ -2403,11 +2583,11 @@ char *tagtree_get_title(struct tree_context* c) | |||
2403 | { | 2583 | { |
2404 | switch (c->currtable) | 2584 | switch (c->currtable) |
2405 | { | 2585 | { |
2406 | case ROOT: | 2586 | case TABLE_ROOT: |
2407 | return menu->title; | 2587 | return menu->title; |
2408 | 2588 | ||
2409 | case NAVIBROWSE: | 2589 | case TABLE_NAVIBROWSE: |
2410 | case ALLSUBENTRIES: | 2590 | case TABLE_ALLSUBENTRIES: |
2411 | return current_title[c->currextra]; | 2591 | return current_title[c->currextra]; |
2412 | } | 2592 | } |
2413 | 2593 | ||
@@ -2419,7 +2599,7 @@ int tagtree_get_attr(struct tree_context* c) | |||
2419 | int attr = -1; | 2599 | int attr = -1; |
2420 | switch (c->currtable) | 2600 | switch (c->currtable) |
2421 | { | 2601 | { |
2422 | case NAVIBROWSE: | 2602 | case TABLE_NAVIBROWSE: |
2423 | if (csi->tagorder[c->currextra] == tag_title | 2603 | if (csi->tagorder[c->currextra] == tag_title |
2424 | || csi->tagorder[c->currextra] == tag_virt_basename) | 2604 | || csi->tagorder[c->currextra] == tag_virt_basename) |
2425 | attr = FILE_ATTR_AUDIO; | 2605 | attr = FILE_ATTR_AUDIO; |
@@ -2427,7 +2607,7 @@ int tagtree_get_attr(struct tree_context* c) | |||
2427 | attr = ATTR_DIRECTORY; | 2607 | attr = ATTR_DIRECTORY; |
2428 | break; | 2608 | break; |
2429 | 2609 | ||
2430 | case ALLSUBENTRIES: | 2610 | case TABLE_ALLSUBENTRIES: |
2431 | attr = FILE_ATTR_AUDIO; | 2611 | attr = FILE_ATTR_AUDIO; |
2432 | break; | 2612 | break; |
2433 | 2613 | ||