summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/playlist.c186
-rw-r--r--apps/playlist.h7
-rw-r--r--apps/settings.c20
-rw-r--r--apps/settings.h5
4 files changed, 157 insertions, 61 deletions
diff --git a/apps/playlist.c b/apps/playlist.c
index ff6ef0ed37..f834a3d5e7 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -93,14 +93,14 @@
93static struct playlist_info playlist; 93static struct playlist_info playlist;
94 94
95#define PLAYLIST_CONTROL_FILE ROCKBOX_DIR "/.playlist_control" 95#define PLAYLIST_CONTROL_FILE ROCKBOX_DIR "/.playlist_control"
96#define PLAYLIST_CONTROL_FILE_VERSION 1 96#define PLAYLIST_CONTROL_FILE_VERSION 2
97 97
98/* 98/*
99 Each playlist index has a flag associated with it which identifies what 99 Each playlist index has a flag associated with it which identifies what
100 type of track it is. These flags are stored in the 3 high order bits of 100 type of track it is. These flags are stored in the 3 high order bits of
101 the index. 101 the index.
102 102
103 NOTE: This limits the playlist file size to a max of 512K. 103 NOTE: This limits the playlist file size to a max of 512M.
104 104
105 Bits 31-30: 105 Bits 31-30:
106 00 = Playlist track 106 00 = Playlist track
@@ -145,6 +145,7 @@ static int format_track_path(char *dest, char *src, int buf_length, int max,
145 char *dir); 145 char *dir);
146static void display_playlist_count(int count, char *fmt); 146static void display_playlist_count(int count, char *fmt);
147static void display_buffer_full(void); 147static void display_buffer_full(void);
148static int flush_pending_control(void);
148 149
149/* 150/*
150 * remove any files and indices associated with the playlist 151 * remove any files and indices associated with the playlist
@@ -170,6 +171,7 @@ static void empty_playlist(bool resume)
170 playlist.first_index = 0; 171 playlist.first_index = 0;
171 playlist.amount = 0; 172 playlist.amount = 0;
172 playlist.last_insert_pos = -1; 173 playlist.last_insert_pos = -1;
174 playlist.shuffle_flush = false;
173 175
174 if (!resume) 176 if (!resume)
175 { 177 {
@@ -180,6 +182,10 @@ static void empty_playlist(bool resume)
180 fd = creat(PLAYLIST_CONTROL_FILE, 0000200); 182 fd = creat(PLAYLIST_CONTROL_FILE, 0000200);
181 if (fd >= 0) 183 if (fd >= 0)
182 close(fd); 184 close(fd);
185
186 /* Reset resume settings */
187 global_settings.resume_first_index = 0;
188 global_settings.resume_seed = -1;
183 } 189 }
184} 190}
185 191
@@ -357,8 +363,16 @@ static int add_track_to_playlist(char *filename, int position, bool queue,
357 363
358 if (playlist.amount > 0 && insert_position <= playlist.first_index && 364 if (playlist.amount > 0 && insert_position <= playlist.first_index &&
359 position != PLAYLIST_PREPEND) 365 position != PLAYLIST_PREPEND)
366 {
360 playlist.first_index++; 367 playlist.first_index++;
361 368
369 if (seek_pos < 0)
370 {
371 global_settings.resume_first_index = playlist.first_index;
372 settings_save();
373 }
374 }
375
362 if (insert_position < playlist.last_insert_pos || 376 if (insert_position < playlist.last_insert_pos ||
363 (insert_position == playlist.last_insert_pos && position < 0)) 377 (insert_position == playlist.last_insert_pos && position < 0))
364 playlist.last_insert_pos++; 378 playlist.last_insert_pos++;
@@ -367,6 +381,9 @@ static int add_track_to_playlist(char *filename, int position, bool queue,
367 { 381 {
368 int result = -1; 382 int result = -1;
369 383
384 if (flush_pending_control() < 0)
385 return -1;
386
370 mutex_lock(&playlist.control_mutex); 387 mutex_lock(&playlist.control_mutex);
371 388
372 if (lseek(playlist.control_fd, 0, SEEK_END) >= 0) 389 if (lseek(playlist.control_fd, 0, SEEK_END) >= 0)
@@ -525,8 +542,16 @@ static int remove_track_from_playlist(int position, bool write)
525 playlist.index--; 542 playlist.index--;
526 543
527 if (position < playlist.first_index) 544 if (position < playlist.first_index)
545 {
528 playlist.first_index--; 546 playlist.first_index--;
529 547
548 if (write)
549 {
550 global_settings.resume_first_index = playlist.first_index;
551 settings_save();
552 }
553 }
554
530 if (position <= playlist.last_insert_pos) 555 if (position <= playlist.last_insert_pos)
531 playlist.last_insert_pos--; 556 playlist.last_insert_pos--;
532 557
@@ -534,6 +559,9 @@ static int remove_track_from_playlist(int position, bool write)
534 { 559 {
535 int result = -1; 560 int result = -1;
536 561
562 if (flush_pending_control() < 0)
563 return -1;
564
537 mutex_lock(&playlist.control_mutex); 565 mutex_lock(&playlist.control_mutex);
538 566
539 if (lseek(playlist.control_fd, 0, SEEK_END) >= 0) 567 if (lseek(playlist.control_fd, 0, SEEK_END) >= 0)
@@ -568,6 +596,10 @@ static int randomise_playlist(unsigned int seed, bool start_current, bool write)
568 int store; 596 int store;
569 unsigned int current = playlist.indices[playlist.index]; 597 unsigned int current = playlist.indices[playlist.index];
570 598
599 /* seed 0 is used to identify sorted playlist for resume purposes */
600 if (seed == 0)
601 seed = 1;
602
571 /* seed with the given seed */ 603 /* seed with the given seed */
572 srand(seed); 604 srand(seed);
573 605
@@ -589,29 +621,13 @@ static int randomise_playlist(unsigned int seed, bool start_current, bool write)
589 /* indices have been moved so last insert position is no longer valid */ 621 /* indices have been moved so last insert position is no longer valid */
590 playlist.last_insert_pos = -1; 622 playlist.last_insert_pos = -1;
591 623
592 if (write && playlist.control_fd >= 0) 624 if (write)
593 { 625 {
594 int result = -1; 626 /* Don't write to disk immediately. Instead, save in settings and
595 627 only flush if playlist is modified (insertion/deletion) */
596 mutex_lock(&playlist.control_mutex); 628 playlist.shuffle_flush = true;
597 629 global_settings.resume_seed = seed;
598 if (lseek(playlist.control_fd, 0, SEEK_END) >= 0) 630 settings_save();
599 {
600 if (fprintf(playlist.control_fd, "S:%d:%d\n", seed,
601 playlist.first_index) > 0)
602 {
603 fsync(playlist.control_fd);
604 result = 0;
605 }
606 }
607
608 mutex_unlock(&playlist.control_mutex);
609
610 if (result < 0)
611 {
612 splash(HZ*2, 0, true, str(LANG_PLAYLIST_CONTROL_UPDATE_ERROR));
613 return result;
614 }
615 } 631 }
616 632
617 return 0; 633 return 0;
@@ -637,27 +653,11 @@ static int sort_playlist(bool start_current, bool write)
637 653
638 if (write && playlist.control_fd >= 0) 654 if (write && playlist.control_fd >= 0)
639 { 655 {
640 int result = -1; 656 /* Don't write to disk immediately. Instead, save in settings and
641 657 only flush if playlist is modified (insertion/deletion) */
642 mutex_lock(&playlist.control_mutex); 658 playlist.shuffle_flush = true;
643 659 global_settings.resume_seed = 0;
644 if (lseek(playlist.control_fd, 0, SEEK_END) >= 0) 660 settings_save();
645 {
646 if (fprintf(playlist.control_fd, "U:%d\n", playlist.first_index) >
647 0)
648 {
649 fsync(playlist.control_fd);
650 result = 0;
651 }
652 }
653
654 mutex_unlock(&playlist.control_mutex);
655
656 if (result < 0)
657 {
658 splash(HZ*2, 0, true, str(LANG_PLAYLIST_CONTROL_UPDATE_ERROR));
659 return result;
660 }
661 } 661 }
662 662
663 return 0; 663 return 0;
@@ -745,7 +745,9 @@ static void find_and_set_playlist_index(unsigned int seek)
745 { 745 {
746 if (playlist.indices[i] == seek) 746 if (playlist.indices[i] == seek)
747 { 747 {
748 playlist.index = playlist.first_index = i; 748 playlist.index = global_settings.resume_first_index =
749 playlist.first_index = i;
750 settings_save();
749 break; 751 break;
750 } 752 }
751 } 753 }
@@ -941,6 +943,56 @@ static void display_buffer_full(void)
941} 943}
942 944
943/* 945/*
946 * Flush any pending control commands to disk. Called when playlist is being
947 * modified. Returns 0 on success and -1 on failure.
948 */
949static int flush_pending_control(void)
950{
951 int result = 0;
952
953 if (playlist.shuffle_flush && global_settings.resume_seed >= 0)
954 {
955 /* pending shuffle */
956 mutex_lock(&playlist.control_mutex);
957
958 if (lseek(playlist.control_fd, 0, SEEK_END) >= 0)
959 {
960 if (global_settings.resume_seed == 0)
961 result = fprintf(playlist.control_fd, "U:%d\n",
962 playlist.first_index);
963 else
964 result = fprintf(playlist.control_fd, "S:%d:%d\n",
965 global_settings.resume_seed, playlist.first_index);
966
967 if (result > 0)
968 {
969 fsync(playlist.control_fd);
970
971 playlist.shuffle_flush = false;
972 global_settings.resume_seed = -1;
973 settings_save();
974
975 result = 0;
976 }
977 else
978 result = -1;
979 }
980 else
981 result = -1;
982
983 mutex_unlock(&playlist.control_mutex);
984
985 if (result < 0)
986 {
987 splash(HZ*2, 0, true, str(LANG_PLAYLIST_CONTROL_UPDATE_ERROR));
988 return result;
989 }
990 }
991
992 return result;
993}
994
995/*
944 * Initialize playlist entries at startup 996 * Initialize playlist entries at startup
945 */ 997 */
946void playlist_init(void) 998void playlist_init(void)
@@ -1008,6 +1060,7 @@ int playlist_resume(void)
1008 int nread; 1060 int nread;
1009 int total_read = 0; 1061 int total_read = 0;
1010 bool first = true; 1062 bool first = true;
1063 bool sorted = true;
1011 1064
1012 enum { 1065 enum {
1013 resume_playlist, 1066 resume_playlist,
@@ -1089,11 +1142,7 @@ int playlist_resume(void)
1089 version = atoi(str1); 1142 version = atoi(str1);
1090 1143
1091 if (version != PLAYLIST_CONTROL_FILE_VERSION) 1144 if (version != PLAYLIST_CONTROL_FILE_VERSION)
1092 { 1145 return -1;
1093 result = -1;
1094 exit_loop = true;
1095 break;
1096 }
1097 1146
1098 update_playlist_filename(str2, str3); 1147 update_playlist_filename(str2, str3);
1099 1148
@@ -1177,12 +1226,19 @@ int playlist_resume(void)
1177 break; 1226 break;
1178 } 1227 }
1179 1228
1229 if (!sorted)
1230 {
1231 /* Always sort list before shuffling */
1232 sort_playlist(false, false);
1233 }
1234
1180 seed = atoi(str1); 1235 seed = atoi(str1);
1181 playlist.first_index = atoi(str2); 1236 playlist.first_index = atoi(str2);
1182 1237
1183 if (randomise_playlist(seed, false, false) < 0) 1238 if (randomise_playlist(seed, false, false) < 0)
1184 return -1; 1239 return -1;
1185 1240
1241 sorted = false;
1186 break; 1242 break;
1187 } 1243 }
1188 case resume_unshuffle: 1244 case resume_unshuffle:
@@ -1200,6 +1256,7 @@ int playlist_resume(void)
1200 if (sort_playlist(false, false) < 0) 1256 if (sort_playlist(false, false) < 0)
1201 return -1; 1257 return -1;
1202 1258
1259 sorted = true;
1203 break; 1260 break;
1204 } 1261 }
1205 case resume_reset: 1262 case resume_reset:
@@ -1334,7 +1391,26 @@ int playlist_resume(void)
1334 1391
1335 /* Terminate on EOF */ 1392 /* Terminate on EOF */
1336 if(nread <= 0) 1393 if(nread <= 0)
1394 {
1395 if (global_settings.resume_seed >= 0)
1396 {
1397 /* Apply shuffle command saved in settings */
1398 if (global_settings.resume_seed == 0)
1399 sort_playlist(false, true);
1400 else
1401 {
1402 if (!sorted)
1403 sort_playlist(false, false);
1404
1405 randomise_playlist(global_settings.resume_seed, false,
1406 true);
1407 }
1408
1409 playlist.first_index = global_settings.resume_first_index;
1410 }
1411
1337 break; 1412 break;
1413 }
1338 } 1414 }
1339 1415
1340 return 0; 1416 return 0;
@@ -1557,7 +1633,8 @@ int playlist_shuffle(int random_seed, int start_index)
1557 { 1633 {
1558 /* store the seek position before the shuffle */ 1634 /* store the seek position before the shuffle */
1559 seek_pos = playlist.indices[start_index]; 1635 seek_pos = playlist.indices[start_index];
1560 playlist.index = playlist.first_index = start_index; 1636 playlist.index = global_settings.resume_first_index =
1637 playlist.first_index = start_index;
1561 start_current = true; 1638 start_current = true;
1562 } 1639 }
1563 1640
@@ -1565,6 +1642,9 @@ int playlist_shuffle(int random_seed, int start_index)
1565 1642
1566 randomise_playlist(random_seed, start_current, true); 1643 randomise_playlist(random_seed, start_current, true);
1567 1644
1645 /* Flush shuffle command to disk */
1646 flush_pending_control();
1647
1568 return playlist.index; 1648 return playlist.index;
1569} 1649}
1570 1650
@@ -1734,7 +1814,7 @@ int playlist_next(int steps)
1734 1814
1735/* Get resume info for current playing song. If return value is -1 then 1815/* Get resume info for current playing song. If return value is -1 then
1736 settings shouldn't be saved. */ 1816 settings shouldn't be saved. */
1737int playlist_get_resume_info(int *resume_index) 1817int playlist_get_resume_info(short *resume_index)
1738{ 1818{
1739 *resume_index = playlist.index; 1819 *resume_index = playlist.index;
1740 1820
diff --git a/apps/playlist.h b/apps/playlist.h
index 0b30e7a3e1..45ecba505c 100644
--- a/apps/playlist.h
+++ b/apps/playlist.h
@@ -39,10 +39,11 @@ struct playlist_info
39 char *buffer; /* buffer for in-ram playlists */ 39 char *buffer; /* buffer for in-ram playlists */
40 int buffer_size; /* size of buffer */ 40 int buffer_size; /* size of buffer */
41 int buffer_end_pos; /* last position where buffer was written */ 41 int buffer_end_pos; /* last position where buffer was written */
42 int index; /* index of current playing track */ 42 short index; /* index of current playing track */
43 int first_index; /* index of first song in playlist */ 43 short first_index; /* index of first song in playlist */
44 int amount; /* number of tracks in the index */ 44 int amount; /* number of tracks in the index */
45 int last_insert_pos; /* last position we inserted a track */ 45 int last_insert_pos; /* last position we inserted a track */
46 bool shuffle_flush; /* Does shuffle value need to be flushed? */
46 struct mutex control_mutex; /* mutex for control file access */ 47 struct mutex control_mutex; /* mutex for control file access */
47}; 48};
48 49
@@ -62,7 +63,7 @@ int playlist_start(int start_index, int offset);
62bool playlist_check(int steps); 63bool playlist_check(int steps);
63char *playlist_peek(int steps); 64char *playlist_peek(int steps);
64int playlist_next(int steps); 65int playlist_next(int steps);
65int playlist_get_resume_info(int *resume_index); 66int playlist_get_resume_info(short *resume_index);
66int playlist_get_display_index(void); 67int playlist_get_display_index(void);
67int playlist_amount(void); 68int playlist_amount(void);
68char *playlist_name(char *buf, int buf_size); 69char *playlist_name(char *buf, int buf_size);
diff --git a/apps/settings.c b/apps/settings.c
index 6a7fe971a2..3c56257db4 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -97,13 +97,14 @@ offset abs
970x0f 0x23 <volume type, battery type, timeformat, scroll speed> 970x0f 0x23 <volume type, battery type, timeformat, scroll speed>
980x10 0x24 <ff/rewind min step, acceleration rate> 980x10 0x24 <ff/rewind min step, acceleration rate>
990x11 0x25 <AVC, channel config> 990x11 0x25 <AVC, channel config>
1000x12 0x26 <(int) Resume playlist index, or -1 if no playlist resume> 1000x12 0x26 <(short) Resume playlist index, or -1 if no playlist resume>
1010x14 0x28 <(short) Resume playlist first index>
1010x16 0x2a <(int) Byte offset into resume file> 1020x16 0x2a <(int) Byte offset into resume file>
1020x1a 0x2e <time until disk spindown> 1030x1a 0x2e <time until disk spindown>
1030x1b 0x2f <browse current, play selected, recursive dir insert> 1040x1b 0x2f <browse current, play selected, recursive dir insert>
1040x1c 0x30 <peak meter hold timeout (bit 0-4), 1050x1c 0x30 <peak meter hold timeout (bit 0-4),
105 rec_editable (bit 7)> 106 rec_editable (bit 7)>
1060x1d 0x31 <unused> 1070x1d 0x31 <(int) Resume shuffle seed, or -1 if no shuffle>
1070x21 0x35 <repeat mode (bit 0-1), rec. channels (bit 2), 1080x21 0x35 <repeat mode (bit 0-1), rec. channels (bit 2),
108 mic gain (bit 4-7)> 109 mic gain (bit 4-7)>
1090x22 0x36 <rec. quality (bit 0-2), source (bit 3-4), frequency (bit 5-7)> 1100x22 0x36 <rec. quality (bit 0-2), source (bit 3-4), frequency (bit 5-7)>
@@ -347,7 +348,8 @@ int settings_save( void )
347 ((global_settings.avc & 0x03) | 348 ((global_settings.avc & 0x03) |
348 ((global_settings.channel_config & 0x07) << 2)); 349 ((global_settings.channel_config & 0x07) << 2));
349 350
350 memcpy(&config_block[0x12], &global_settings.resume_index, 4); 351 memcpy(&config_block[0x12], &global_settings.resume_index, 2);
352 memcpy(&config_block[0x14], &global_settings.resume_first_index, 2);
351 memcpy(&config_block[0x16], &global_settings.resume_offset, 4); 353 memcpy(&config_block[0x16], &global_settings.resume_offset, 4);
352 DEBUGF( "+Resume index %X offset %X\n", 354 DEBUGF( "+Resume index %X offset %X\n",
353 global_settings.resume_index, 355 global_settings.resume_index,
@@ -362,6 +364,8 @@ int settings_save( void )
362 config_block[0x1c] = (unsigned char)global_settings.peak_meter_hold | 364 config_block[0x1c] = (unsigned char)global_settings.peak_meter_hold |
363 (global_settings.rec_editable?0x80:0); 365 (global_settings.rec_editable?0x80:0);
364 366
367 memcpy(&config_block[0x1d], &global_settings.resume_seed, 4);
368
365 config_block[0x21] = (unsigned char) 369 config_block[0x21] = (unsigned char)
366 ((global_settings.repeat_mode & 3) | 370 ((global_settings.repeat_mode & 3) |
367 ((global_settings.rec_channels & 1) << 2) | 371 ((global_settings.rec_channels & 1) << 2) |
@@ -636,7 +640,10 @@ void settings_load(void)
636 } 640 }
637 641
638 if (config_block[0x12] != 0xFF) 642 if (config_block[0x12] != 0xFF)
639 memcpy(&global_settings.resume_index, &config_block[0x12], 4); 643 memcpy(&global_settings.resume_index, &config_block[0x12], 2);
644
645 if (config_block[0x14] != 0xFF)
646 memcpy(&global_settings.resume_first_index, &config_block[0x14], 2);
640 647
641 if (config_block[0x16] != 0xFF) 648 if (config_block[0x16] != 0xFF)
642 memcpy(&global_settings.resume_offset, &config_block[0x16], 4); 649 memcpy(&global_settings.resume_offset, &config_block[0x16], 4);
@@ -657,6 +664,9 @@ void settings_load(void)
657 (config_block[0x1c] & 0x80)?true:false; 664 (config_block[0x1c] & 0x80)?true:false;
658 } 665 }
659 666
667 if (config_block[0x1d] != 0xFF)
668 memcpy(&global_settings.resume_seed, &config_block[0x1d], 4);
669
660 if (config_block[0x21] != 0xFF) 670 if (config_block[0x21] != 0xFF)
661 { 671 {
662 global_settings.repeat_mode = config_block[0x21] & 3; 672 global_settings.repeat_mode = config_block[0x21] & 3;
@@ -1468,7 +1478,9 @@ void settings_reset(void) {
1468 global_settings.ff_rewind_min_step = DEFAULT_FF_REWIND_MIN_STEP; 1478 global_settings.ff_rewind_min_step = DEFAULT_FF_REWIND_MIN_STEP;
1469 global_settings.ff_rewind_accel = DEFAULT_FF_REWIND_ACCEL_SETTING; 1479 global_settings.ff_rewind_accel = DEFAULT_FF_REWIND_ACCEL_SETTING;
1470 global_settings.resume_index = -1; 1480 global_settings.resume_index = -1;
1481 global_settings.resume_first_index = 0;
1471 global_settings.resume_offset = -1; 1482 global_settings.resume_offset = -1;
1483 global_settings.resume_seed = -1;
1472 global_settings.disk_spindown = 5; 1484 global_settings.disk_spindown = 5;
1473 global_settings.disk_poweroff = false; 1485 global_settings.disk_poweroff = false;
1474 global_settings.buffer_margin = 0; 1486 global_settings.buffer_margin = 0;
diff --git a/apps/settings.h b/apps/settings.h
index c0e785489a..b96f4c6410 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -104,8 +104,11 @@ struct user_settings
104 /* resume settings */ 104 /* resume settings */
105 105
106 int resume; /* resume option: 0=off, 1=ask, 2=on */ 106 int resume; /* resume option: 0=off, 1=ask, 2=on */
107 int resume_index; /* index in playlist (-1 for no active resume) */ 107 short resume_index; /* index in playlist (-1 for no active resume) */
108 short resume_first_index; /* index of first track in playlist */
108 int resume_offset; /* byte offset in mp3 file */ 109 int resume_offset; /* byte offset in mp3 file */
110 int resume_seed; /* shuffle seed (-1=no resume shuffle 0=sorted
111 >0=shuffled) */
109 112
110 unsigned char font_file[MAX_FILENAME+1]; /* last font */ 113 unsigned char font_file[MAX_FILENAME+1]; /* last font */
111 unsigned char wps_file[MAX_FILENAME+1]; /* last wps */ 114 unsigned char wps_file[MAX_FILENAME+1]; /* last wps */