diff options
Diffstat (limited to 'apps/tagtree.c')
-rw-r--r-- | apps/tagtree.c | 198 |
1 files changed, 94 insertions, 104 deletions
diff --git a/apps/tagtree.c b/apps/tagtree.c index 562ad44863..126fb04678 100644 --- a/apps/tagtree.c +++ b/apps/tagtree.c | |||
@@ -57,6 +57,7 @@ | |||
57 | #include "strnatcmp.h" | 57 | #include "strnatcmp.h" |
58 | #include "panic.h" | 58 | #include "panic.h" |
59 | #include "onplay.h" | 59 | #include "onplay.h" |
60 | #include "plugin.h" | ||
60 | 61 | ||
61 | #define str_or_empty(x) (x ? x : "(NULL)") | 62 | #define str_or_empty(x) (x ? x : "(NULL)") |
62 | 63 | ||
@@ -117,14 +118,6 @@ enum variables { | |||
117 | #define UNIQBUF_SIZE (64*1024) | 118 | #define UNIQBUF_SIZE (64*1024) |
118 | static uint32_t uniqbuf[UNIQBUF_SIZE / sizeof(uint32_t)]; | 119 | static uint32_t uniqbuf[UNIQBUF_SIZE / sizeof(uint32_t)]; |
119 | 120 | ||
120 | #if MEMORYSIZE > 2 | ||
121 | #define INSERT_ALL_PLAYLIST_MAX_SEGMENT_SIZE (1024) | ||
122 | #else | ||
123 | /* Lower quality randomness for low-ram devices using smaller segments */ | ||
124 | #define INSERT_ALL_PLAYLIST_MAX_SEGMENT_SIZE (128) | ||
125 | #endif | ||
126 | static bool selective_random_playlist_indexes[INSERT_ALL_PLAYLIST_MAX_SEGMENT_SIZE]; | ||
127 | |||
128 | #define MAX_TAGS 5 | 121 | #define MAX_TAGS 5 |
129 | #define MAX_MENU_ID_SIZE 32 | 122 | #define MAX_MENU_ID_SIZE 32 |
130 | 123 | ||
@@ -2141,30 +2134,26 @@ static void swap_array_bool(bool *a, bool *b) | |||
2141 | /** | 2134 | /** |
2142 | * Randomly shuffle an array using the Fisher-Yates algorithm : | 2135 | * Randomly shuffle an array using the Fisher-Yates algorithm : |
2143 | * https://en.wikipedia.org/wiki/Random_permutation | 2136 | * https://en.wikipedia.org/wiki/Random_permutation |
2144 | * This algorithm has a linear complexity. Don't forget to srand | 2137 | * This algorithm has a linear complexity. |
2145 | * before call to use it with a relevant seed. | 2138 | * Don't forget to srand before call to use it with a relevant seed. |
2146 | */ | 2139 | */ |
2147 | static void shuffle_bool_array(bool array[], int size) | 2140 | static bool* fill_random_playlist_indexes(bool *bool_array, size_t arr_sz, |
2141 | size_t track_count, size_t max_slots) | ||
2148 | { | 2142 | { |
2149 | for (int i = size - 1; i > 0; i--) | 2143 | size_t i; |
2144 | if (track_count * sizeof(bool) > arr_sz || max_slots > track_count) | ||
2145 | return NULL; | ||
2146 | |||
2147 | for (i = 0; i < arr_sz; i++) /* fill max_slots with TRUE */ | ||
2148 | bool_array[i] = i < max_slots; | ||
2149 | |||
2150 | /* shuffle bool array */ | ||
2151 | for (i = track_count - 1; i > 0; i--) | ||
2150 | { | 2152 | { |
2151 | int j = rand() % (i + 1); | 2153 | int j = rand() % (i + 1); |
2152 | swap_array_bool(&array[i], &array[j]); | 2154 | swap_array_bool(&bool_array[i], &bool_array[j]); |
2153 | } | 2155 | } |
2154 | } | 2156 | return bool_array; |
2155 | |||
2156 | static bool fill_random_playlist_indexes(int current_segment_n, | ||
2157 | int current_segment_max_space) | ||
2158 | { | ||
2159 | if (current_segment_n == 0 || current_segment_max_space == 0) | ||
2160 | return false; | ||
2161 | if (current_segment_max_space > current_segment_n) | ||
2162 | current_segment_max_space = current_segment_n; | ||
2163 | for (int i = 0; i < current_segment_n; i++) | ||
2164 | selective_random_playlist_indexes[i] = i < current_segment_max_space; | ||
2165 | srand(current_tick); | ||
2166 | shuffle_bool_array(selective_random_playlist_indexes, current_segment_n); | ||
2167 | return true; | ||
2168 | } | 2157 | } |
2169 | 2158 | ||
2170 | static bool insert_all_playlist(struct tree_context *c, | 2159 | static bool insert_all_playlist(struct tree_context *c, |
@@ -2175,6 +2164,9 @@ static bool insert_all_playlist(struct tree_context *c, | |||
2175 | int n; | 2164 | int n; |
2176 | int fd = -1; | 2165 | int fd = -1; |
2177 | unsigned long last_tick; | 2166 | unsigned long last_tick; |
2167 | int slots_remaining = 0; | ||
2168 | bool fill_randomly = false; | ||
2169 | bool *rand_bool_array = NULL; | ||
2178 | char buf[MAX_PATH]; | 2170 | char buf[MAX_PATH]; |
2179 | 2171 | ||
2180 | cpu_boost(true); | 2172 | cpu_boost(true); |
@@ -2213,113 +2205,111 @@ static bool insert_all_playlist(struct tree_context *c, | |||
2213 | splash_progress_set_delay(HZ / 2); /* wait 1/2 sec before progress */ | 2205 | splash_progress_set_delay(HZ / 2); /* wait 1/2 sec before progress */ |
2214 | n = c->filesindir; | 2206 | n = c->filesindir; |
2215 | 2207 | ||
2216 | int max_playlist_size = playlist_get_current()->max_playlist_size; | ||
2217 | int playlist_amount = playlist_get_current()->amount; | ||
2218 | int segment_size = INSERT_ALL_PLAYLIST_MAX_SEGMENT_SIZE; | ||
2219 | int segments_count = n / segment_size; | ||
2220 | int leftovers_segment_size = n - (segments_count * segment_size); | ||
2221 | bool fill_randomly = false; | ||
2222 | |||
2223 | if (playlist == NULL) | 2208 | if (playlist == NULL) |
2224 | { | 2209 | { |
2225 | bool will_exceed = n > max_playlist_size; | 2210 | int max_playlist_size = playlist_get_current()->max_playlist_size; |
2226 | fill_randomly = will_exceed; | 2211 | slots_remaining = max_playlist_size - playlist_get_current()->amount; |
2227 | } | 2212 | if (slots_remaining <= 0) |
2228 | if (leftovers_segment_size > 0 && fill_randomly) | ||
2229 | { | ||
2230 | /* We need to re-balance the segments so the randomness will be | ||
2231 | * coherent and balanced the same through all segments */ | ||
2232 | while (leftovers_segment_size + segments_count < segment_size) | ||
2233 | { | 2213 | { |
2234 | segment_size--; // -1 to all other segments | 2214 | logf("Playlist has no space remaining"); |
2235 | leftovers_segment_size += segments_count; | 2215 | cpu_boost(false); |
2216 | return false; | ||
2236 | } | 2217 | } |
2237 | } | ||
2238 | if (leftovers_segment_size > 0) | ||
2239 | segments_count += 1; | ||
2240 | |||
2241 | int max_available_space = max_playlist_size - playlist_amount; | ||
2242 | int max_space_per_segment = max_available_space / segments_count; | ||
2243 | |||
2244 | int remaining_space = | ||
2245 | max_available_space - (max_space_per_segment * segments_count); | ||
2246 | 2218 | ||
2247 | if (fill_randomly) | 2219 | fill_randomly = n > slots_remaining; |
2248 | { | 2220 | |
2249 | talk_id(LANG_RANDOM_SHUFFLE_RANDOM_SELECTIVE_SONGS_SUMMARY, true); | 2221 | if (fill_randomly) |
2250 | splashf(HZ * 3, str(LANG_RANDOM_SHUFFLE_RANDOM_SELECTIVE_SONGS_SUMMARY), | 2222 | { |
2251 | max_space_per_segment * segments_count + remaining_space); | 2223 | srand(current_tick); |
2252 | /* logf("sz=%d lsz=%d sc=%d rcps=%d", segment_size, leftovers_segment_size, | 2224 | size_t bufsize = 0; |
2253 | segments_count, max_available_space_per_segment); */ | 2225 | bool *buffer = (bool *) plugin_get_buffer(&bufsize); |
2226 | rand_bool_array = fill_random_playlist_indexes(buffer, bufsize, | ||
2227 | n, slots_remaining); | ||
2228 | |||
2229 | talk_id(LANG_RANDOM_SHUFFLE_RANDOM_SELECTIVE_SONGS_SUMMARY, true); | ||
2230 | splashf(HZ * 2, str(LANG_RANDOM_SHUFFLE_RANDOM_SELECTIVE_SONGS_SUMMARY), | ||
2231 | slots_remaining); | ||
2232 | } | ||
2254 | } | 2233 | } |
2255 | 2234 | ||
2256 | bool exit_loop_now = false; | 2235 | bool exit_loop_now = false; |
2257 | for (int i = 0; i < segments_count; i++) | 2236 | for (int i = 0; i < n; i++) |
2258 | { | 2237 | { |
2259 | int cur_segment_size = segment_size; | 2238 | if (TIME_AFTER(current_tick, last_tick + HZ/4)) |
2260 | int cur_segment_start = i * segment_size; | ||
2261 | int cur_segment_end; | ||
2262 | int space_per_segment = max_space_per_segment; | ||
2263 | |||
2264 | if (i + 1 >= segments_count && leftovers_segment_size > 0) | ||
2265 | { | ||
2266 | /* add any remaining tracks to the last segment */ | ||
2267 | space_per_segment += remaining_space; | ||
2268 | cur_segment_size = leftovers_segment_size; | ||
2269 | } | ||
2270 | else if (fill_randomly) | ||
2271 | { | 2239 | { |
2272 | /* add an extra track to some of the segments */ | 2240 | splash_progress(i, n, "%s (%s)", str(LANG_WAIT), str(LANG_OFF_ABORT)); |
2273 | if (remaining_space > 0 && (i & 7) != 7) | 2241 | if (action_userabort(TIMEOUT_NOBLOCK)) |
2274 | { | 2242 | { |
2275 | space_per_segment++; | 2243 | exit_loop_now = true; |
2276 | remaining_space--; | 2244 | break; |
2277 | } | 2245 | } |
2246 | last_tick = current_tick; | ||
2278 | } | 2247 | } |
2279 | if (fill_randomly) | ||
2280 | { | ||
2281 | fill_randomly = fill_random_playlist_indexes(cur_segment_size, | ||
2282 | space_per_segment); | ||
2283 | } | ||
2284 | |||
2285 | cur_segment_end = cur_segment_start + cur_segment_size; | ||
2286 | 2248 | ||
2287 | for (int j = cur_segment_start; j < cur_segment_end && !exit_loop_now; j++) | 2249 | if (playlist == NULL) |
2288 | { | 2250 | { |
2289 | if (TIME_AFTER(current_tick, last_tick + HZ/4)) | 2251 | if (fill_randomly) |
2290 | { | 2252 | { |
2291 | splash_progress(j, n, "%s (%s)", str(LANG_WAIT), str(LANG_OFF_ABORT)); | 2253 | int remaining_tracks = n - i; |
2292 | if (action_userabort(TIMEOUT_NOBLOCK)) | 2254 | if (remaining_tracks > slots_remaining) |
2293 | { | 2255 | { |
2294 | exit_loop_now = true; | 2256 | if (rand_bool_array) |
2295 | break; | 2257 | { |
2258 | /* Skip the track if rand_bool_array[i] is FALSE */ | ||
2259 | if (!rand_bool_array[i]) | ||
2260 | continue; | ||
2261 | } | ||
2262 | else | ||
2263 | { | ||
2264 | /* Generate random value between 0 and remaining_tracks - 1 */ | ||
2265 | int selrange = RAND_MAX / remaining_tracks; /* Improve distribution */ | ||
2266 | int random; | ||
2267 | |||
2268 | for (int r = 0; r < 0x0FFF; r++) /* limit loops */ | ||
2269 | { | ||
2270 | random = rand() / selrange; | ||
2271 | if (random < remaining_tracks) | ||
2272 | break; | ||
2273 | else | ||
2274 | random = 0; | ||
2275 | } | ||
2276 | /* Skip the track if random >= slots_remaining */ | ||
2277 | if (random >= slots_remaining) | ||
2278 | continue; | ||
2279 | } | ||
2296 | } | 2280 | } |
2297 | last_tick = current_tick; | ||
2298 | } | 2281 | } |
2282 | } | ||
2299 | 2283 | ||
2300 | if (fill_randomly && !selective_random_playlist_indexes[j % segment_size]) | 2284 | if (!tagcache_retrieve(&tcs, tagtree_get_entry(c, i)->extraseek, tcs.type, buf, sizeof buf)) |
2301 | continue; | 2285 | continue; |
2302 | |||
2303 | if (!tagcache_retrieve(&tcs, tagtree_get_entry(c, j)->extraseek, tcs.type, buf, sizeof buf)) | ||
2304 | continue; | ||
2305 | 2286 | ||
2306 | if (playlist == NULL) | 2287 | if (playlist == NULL) |
2288 | { | ||
2289 | if (fill_randomly) | ||
2307 | { | 2290 | { |
2308 | if (playlist_insert_track(NULL, buf, position, queue, false) < 0) { | 2291 | if (--slots_remaining <= 0) |
2309 | logf("playlist_insert_track failed"); | 2292 | { |
2310 | exit_loop_now = true; | 2293 | exit_loop_now = true; |
2311 | break; | 2294 | break; |
2312 | } | 2295 | } |
2313 | } | 2296 | } |
2314 | else if (fdprintf(fd, "%s\n", buf) <= 0) | 2297 | |
2315 | { | 2298 | if (playlist_insert_track(NULL, buf, position, queue, false) < 0) { |
2299 | logf("playlist_insert_track failed"); | ||
2316 | exit_loop_now = true; | 2300 | exit_loop_now = true; |
2317 | break; | 2301 | break; |
2318 | } | 2302 | } |
2319 | yield(); | ||
2320 | if (playlist == NULL && position == PLAYLIST_INSERT_FIRST) | ||
2321 | position = PLAYLIST_INSERT; | ||
2322 | } | 2303 | } |
2304 | else if (fdprintf(fd, "%s\n", buf) <= 0) | ||
2305 | { | ||
2306 | exit_loop_now = true; | ||
2307 | break; | ||
2308 | } | ||
2309 | yield(); | ||
2310 | if (playlist == NULL && position == PLAYLIST_INSERT_FIRST) | ||
2311 | position = PLAYLIST_INSERT; | ||
2312 | |||
2323 | if (exit_loop_now) | 2313 | if (exit_loop_now) |
2324 | break; | 2314 | break; |
2325 | } | 2315 | } |