summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/tagtree.c198
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)
118static uint32_t uniqbuf[UNIQBUF_SIZE / sizeof(uint32_t)]; 119static 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
126static 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 */
2147static void shuffle_bool_array(bool array[], int size) 2140static 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
2156static 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
2170static bool insert_all_playlist(struct tree_context *c, 2159static 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 }