summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/playlist.c16
-rw-r--r--apps/playlist.h5
-rw-r--r--apps/settings.c247
-rw-r--r--apps/settings.h8
-rw-r--r--apps/settings_menu.c7
-rw-r--r--apps/tree.c129
-rw-r--r--apps/wps.c22
-rw-r--r--firmware/drivers/ata.c1
-rw-r--r--firmware/id3.h4
-rw-r--r--firmware/mpeg.c74
-rw-r--r--firmware/mpeg.h2
-rw-r--r--uisimulator/common/stubs.c4
12 files changed, 377 insertions, 142 deletions
diff --git a/apps/playlist.c b/apps/playlist.c
index 0cb9d09f32..f3081397f6 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -66,7 +66,7 @@ int playlist_add(char *filename)
66 return 0; 66 return 0;
67} 67}
68 68
69char* playlist_next(int steps) 69char* playlist_next(int steps, int* index)
70{ 70{
71 int seek; 71 int seek;
72 int max; 72 int max;
@@ -103,7 +103,9 @@ char* playlist_next(int steps)
103 else 103 else
104 return NULL; 104 return NULL;
105 } 105 }
106 106
107 if (index)
108 *index = playlist.index;
107 109
108 /* Zero-terminate the file name */ 110 /* Zero-terminate the file name */
109 seek=0; 111 seek=0;
@@ -165,7 +167,11 @@ char* playlist_next(int steps)
165 } 167 }
166} 168}
167 169
168void play_list(char *dir, char *file, int start_index) 170void play_list(char *dir,
171 char *file,
172 int start_index,
173 int start_offset,
174 int random_seed )
169{ 175{
170 char *sep=""; 176 char *sep="";
171 int dirlen; 177 int dirlen;
@@ -211,7 +217,7 @@ void play_list(char *dir, char *file, int start_index)
211 status_draw(); 217 status_draw();
212 lcd_update(); 218 lcd_update();
213 } 219 }
214 randomise_playlist( current_tick ); 220 randomise_playlist( random_seed );
215 } 221 }
216 222
217 if(!playlist.in_ram) { 223 if(!playlist.in_ram) {
@@ -220,7 +226,7 @@ void play_list(char *dir, char *file, int start_index)
220 lcd_update(); 226 lcd_update();
221 } 227 }
222 /* also make the first song get playing */ 228 /* also make the first song get playing */
223 mpeg_play(playlist_next(0)); 229 mpeg_play(start_offset);
224} 230}
225 231
226/* 232/*
diff --git a/apps/playlist.h b/apps/playlist.h
index 312964fd8c..e0c0841207 100644
--- a/apps/playlist.h
+++ b/apps/playlist.h
@@ -40,8 +40,9 @@ typedef struct
40extern playlist_info_t playlist; 40extern playlist_info_t playlist;
41extern bool playlist_shuffle; 41extern bool playlist_shuffle;
42 42
43void play_list(char *dir, char *file, int start_index); 43void play_list(char *dir, char *file, int start_index,
44char* playlist_next(int steps); 44 int start_offset, int random_seed );
45char* playlist_next(int steps, int* id);
45void randomise_playlist( unsigned int seed ); 46void randomise_playlist( unsigned int seed );
46void sort_playlist(void); 47void sort_playlist(void);
47void empty_playlist(void); 48void empty_playlist(void);
diff --git a/apps/settings.c b/apps/settings.c
index f8b6870863..41d04c2819 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -37,10 +37,9 @@
37 37
38struct user_settings global_settings; 38struct user_settings global_settings;
39 39
40static unsigned short last_checksum = 0;
41
42#define CONFIG_BLOCK_VERSION 1 40#define CONFIG_BLOCK_VERSION 1
43#define CONFIG_BLOCK_SIZE 44 41#define CONFIG_BLOCK_SIZE 512
42#define RTC_BLOCK_SIZE 44
44 43
45/******************************************** 44/********************************************
46 45
@@ -64,6 +63,8 @@ offset abs
640x0f 0x23 <scroll speed & WPS display byte> 630x0f 0x23 <scroll speed & WPS display byte>
650x10 0x24 <playlist options byte> 640x10 0x24 <playlist options byte>
660x11 0x25 <AVC byte> 650x11 0x25 <AVC byte>
660x12 0x26 <(int) Resume playlist index, or -1 if no playlist resume>
670x16 0x2b <(int) Byte offset into resume file>
67 68
68 <all unused space filled with 0xff> 69 <all unused space filled with 0xff>
69 70
@@ -81,24 +82,30 @@ location used, and reset the setting in question with a factory default if
81needed. Memory locations not used by a given version should not be 82needed. Memory locations not used by a given version should not be
82modified unless the header & checksum test fails. 83modified unless the header & checksum test fails.
83 84
85
86Rest of config block, only saved to disk:
87
880xF8 (int) Playlist shuffle seed
890xFC (char[260]) Resume playlist (path/to/dir or path/to/playlist.m3u)
90
84*************************************/ 91*************************************/
85 92
86#include "rtc.h" 93#include "rtc.h"
87static unsigned char rtc_config_block[CONFIG_BLOCK_SIZE]; 94static unsigned char config_block[CONFIG_BLOCK_SIZE];
88 95
89/* 96/*
90 * Calculates the checksum for the config block and places it in the given 2-byte buffer 97 * Calculates the checksum for the config block and returns it
91 */ 98 */
92 99
93static unsigned short calculate_config_checksum(void) 100static unsigned short calculate_config_checksum(unsigned char* buf)
94{ 101{
95 unsigned int i; 102 unsigned int i;
96 unsigned char cksum[2]; 103 unsigned char cksum[2];
97 cksum[0] = cksum[1] = 0; 104 cksum[0] = cksum[1] = 0;
98 105
99 for (i=0; i < CONFIG_BLOCK_SIZE - 2; i+=2 ) { 106 for (i=0; i < RTC_BLOCK_SIZE - 2; i+=2 ) {
100 cksum[0] ^= rtc_config_block[i]; 107 cksum[0] ^= buf[i];
101 cksum[1] ^= rtc_config_block[i+1]; 108 cksum[1] ^= buf[i+1];
102 } 109 }
103 110
104 return (cksum[0] << 8) | cksum[1]; 111 return (cksum[0] << 8) | cksum[1];
@@ -112,12 +119,12 @@ static void init_config_buffer( void )
112 DEBUGF( "init_config_buffer()\n" ); 119 DEBUGF( "init_config_buffer()\n" );
113 120
114 /* reset to 0xff - all unused */ 121 /* reset to 0xff - all unused */
115 memset(rtc_config_block, 0xff, CONFIG_BLOCK_SIZE); 122 memset(config_block, 0xff, CONFIG_BLOCK_SIZE);
116 /* insert header */ 123 /* insert header */
117 rtc_config_block[0] = 'R'; 124 config_block[0] = 'R';
118 rtc_config_block[1] = 'o'; 125 config_block[1] = 'o';
119 rtc_config_block[2] = 'c'; 126 config_block[2] = 'c';
120 rtc_config_block[3] = CONFIG_BLOCK_VERSION; 127 config_block[3] = CONFIG_BLOCK_VERSION;
121} 128}
122 129
123/* 130/*
@@ -126,7 +133,6 @@ static void init_config_buffer( void )
126static int save_config_buffer( void ) 133static int save_config_buffer( void )
127{ 134{
128 unsigned short chksum; 135 unsigned short chksum;
129
130#ifdef HAVE_RTC 136#ifdef HAVE_RTC
131 unsigned int i; 137 unsigned int i;
132#endif 138#endif
@@ -134,36 +140,29 @@ static int save_config_buffer( void )
134 DEBUGF( "save_config_buffer()\n" ); 140 DEBUGF( "save_config_buffer()\n" );
135 141
136 /* update the checksum in the end of the block before saving */ 142 /* update the checksum in the end of the block before saving */
137 chksum = calculate_config_checksum(); 143 chksum = calculate_config_checksum(config_block);
138 rtc_config_block[ CONFIG_BLOCK_SIZE - 2 ] = chksum >> 8; 144 config_block[ RTC_BLOCK_SIZE - 2 ] = chksum >> 8;
139 rtc_config_block[ CONFIG_BLOCK_SIZE - 1 ] = chksum & 0xff; 145 config_block[ RTC_BLOCK_SIZE - 1 ] = chksum & 0xff;
140
141 /* don't save if no changes were made */
142 if ( chksum == last_checksum )
143 return 0;
144 last_checksum = chksum;
145 146
146#ifdef HAVE_RTC 147#ifdef HAVE_RTC
147 /* FIXME: okay, it _would_ be cleaner and faster to implement rtc_write so 148 /* FIXME: okay, it _would_ be cleaner and faster to implement rtc_write so
148 that it would write a number of bytes at a time since the RTC chip 149 that it would write a number of bytes at a time since the RTC chip
149 supports that, but this will have to do for now 8-) */ 150 supports that, but this will have to do for now 8-) */
150 for (i=0; i < CONFIG_BLOCK_SIZE; i++ ) { 151 for (i=0; i < RTC_BLOCK_SIZE; i++ ) {
151 int r = rtc_write(0x14+i, rtc_config_block[i]); 152 int r = rtc_write(0x14+i, config_block[i]);
152 if (r) { 153 if (r) {
153 DEBUGF( "save_config_buffer: rtc_write failed at addr 0x%02x: %d\n", 14+i, r ); 154 DEBUGF( "save_config_buffer: rtc_write failed at addr 0x%02x: %d\n", 14+i, r );
154 return r; 155 return r;
155 } 156 }
156 } 157 }
157 158
158#else 159#endif
159 160
160 if(battery_level_safe() && (fat_startsector()!=0)) 161 if (fat_startsector() != 0)
161 ata_delayed_write( 61, rtc_config_block); 162 ata_delayed_write( 61, config_block);
162 else 163 else
163 return -1; 164 return -1;
164 165
165#endif
166
167 return 0; 166 return 0;
168} 167}
169 168
@@ -173,40 +172,61 @@ static int save_config_buffer( void )
173static int load_config_buffer( void ) 172static int load_config_buffer( void )
174{ 173{
175 unsigned short chksum; 174 unsigned short chksum;
175 bool correct = false;
176 176
177#ifdef HAVE_RTC 177#ifdef HAVE_RTC
178 unsigned int i; 178 unsigned int i;
179 unsigned char rtc_block[RTC_BLOCK_SIZE];
179#endif 180#endif
180 181
181 DEBUGF( "load_config_buffer()\n" ); 182 DEBUGF( "load_config_buffer()\n" );
182 183
184 if (fat_startsector() != 0) {
185 ata_read_sectors( 61, 1, config_block);
186
187 /* calculate the checksum, check it and the header */
188 chksum = calculate_config_checksum(config_block);
189
190 if (config_block[0] == 'R' &&
191 config_block[1] == 'o' &&
192 config_block[2] == 'c' &&
193 config_block[3] == CONFIG_BLOCK_VERSION &&
194 (chksum >> 8) == config_block[RTC_BLOCK_SIZE - 2] &&
195 (chksum & 0xff) == config_block[RTC_BLOCK_SIZE - 1])
196 {
197 DEBUGF( "load_config_buffer: header & checksum test ok\n" );
198 correct = true;
199 }
200 }
201
183#ifdef HAVE_RTC 202#ifdef HAVE_RTC
184 /* FIXME: the same comment applies here as for rtc_write */ 203 /* read rtc block */
185 for (i=0; i < CONFIG_BLOCK_SIZE; i++ ) 204 for (i=0; i < RTC_BLOCK_SIZE; i++ )
186 rtc_config_block[i] = rtc_read(0x14+i); 205 rtc_block[i] = rtc_read(0x14+i);
187#else 206
188 ata_read_sectors( 61, 1, rtc_config_block); 207 chksum = calculate_config_checksum(rtc_block);
189#endif
190
191 /* calculate the checksum, check it and the header */
192 chksum = calculate_config_checksum();
193 208
194 if (rtc_config_block[0] == 'R' && 209 /* if rtc block is ok, use that */
195 rtc_config_block[1] == 'o' && 210 if (rtc_block[0] == 'R' &&
196 rtc_config_block[2] == 'c' && 211 rtc_block[1] == 'o' &&
197 rtc_config_block[3] == CONFIG_BLOCK_VERSION && 212 rtc_block[2] == 'c' &&
198 (chksum >> 8) == rtc_config_block[CONFIG_BLOCK_SIZE - 2] && 213 rtc_block[3] == CONFIG_BLOCK_VERSION &&
199 (chksum & 0xff) == rtc_config_block[CONFIG_BLOCK_SIZE - 1]) 214 (chksum >> 8) == rtc_block[RTC_BLOCK_SIZE - 2] &&
215 (chksum & 0xff) == rtc_block[RTC_BLOCK_SIZE - 1])
200 { 216 {
201 DEBUGF( "load_config_buffer: header & checksum test ok\n" ); 217 memcpy(config_block, rtc_block, RTC_BLOCK_SIZE);
202 last_checksum = chksum; 218 correct = true;
203 return 0; /* header and checksum is valid */
204 } 219 }
220#endif
205 221
206 /* if checksum is not valid, initialize the config buffer to all-unused */ 222 if ( !correct ) {
207 DEBUGF( "load_config_buffer: header & checksum test failed\n" ); 223 /* if checksum is not valid, clear the config buffer */
208 init_config_buffer(); 224 DEBUGF( "load_config_buffer: header & checksum test failed\n" );
209 return 1; 225 init_config_buffer();
226 return -1;
227 }
228
229 return 0;
210} 230}
211 231
212/* 232/*
@@ -218,33 +238,47 @@ int settings_save( void )
218 238
219 /* update the config block buffer with current 239 /* update the config block buffer with current
220 settings and save the block in the RTC */ 240 settings and save the block in the RTC */
221 rtc_config_block[0x4] = (unsigned char)global_settings.volume; 241 config_block[0x4] = (unsigned char)global_settings.volume;
222 rtc_config_block[0x5] = (unsigned char)global_settings.balance; 242 config_block[0x5] = (unsigned char)global_settings.balance;
223 rtc_config_block[0x6] = (unsigned char)global_settings.bass; 243 config_block[0x6] = (unsigned char)global_settings.bass;
224 rtc_config_block[0x7] = (unsigned char)global_settings.treble; 244 config_block[0x7] = (unsigned char)global_settings.treble;
225 rtc_config_block[0x8] = (unsigned char)global_settings.loudness; 245 config_block[0x8] = (unsigned char)global_settings.loudness;
226 rtc_config_block[0x9] = (unsigned char)global_settings.bass_boost; 246 config_block[0x9] = (unsigned char)global_settings.bass_boost;
227 247
228 rtc_config_block[0xa] = (unsigned char)global_settings.contrast; 248 config_block[0xa] = (unsigned char)global_settings.contrast;
229 rtc_config_block[0xb] = (unsigned char)global_settings.backlight; 249 config_block[0xb] = (unsigned char)global_settings.backlight;
230 rtc_config_block[0xc] = (unsigned char)global_settings.poweroff; 250 config_block[0xc] = (unsigned char)global_settings.poweroff;
231 rtc_config_block[0xd] = (unsigned char)global_settings.resume; 251 config_block[0xd] = (unsigned char)global_settings.resume;
232 252
233 rtc_config_block[0xe] = (unsigned char) 253 config_block[0xe] = (unsigned char)
234 ((global_settings.playlist_shuffle & 1) | 254 ((global_settings.playlist_shuffle & 1) |
235 ((global_settings.mp3filter & 1) << 1) | 255 ((global_settings.mp3filter & 1) << 1) |
236 ((global_settings.sort_case & 1) << 2) | 256 ((global_settings.sort_case & 1) << 2) |
237 ((global_settings.discharge & 1) << 3) | 257 ((global_settings.discharge & 1) << 3) |
238 ((global_settings.statusbar & 1) << 4)); 258 ((global_settings.statusbar & 1) << 4));
239 259
240 rtc_config_block[0xf] = (unsigned char) 260 config_block[0xf] = (unsigned char)
241 ((global_settings.scroll_speed << 3) | 261 ((global_settings.scroll_speed << 3) |
242 (global_settings.wps_display & 7)); 262 (global_settings.wps_display & 7));
243 263
244 rtc_config_block[0x11] = (unsigned char)global_settings.avc; 264 config_block[0x10] = (unsigned char)global_settings.ff_rewind;
265 config_block[0x11] = (unsigned char)global_settings.avc;
245 266
246 memcpy(&rtc_config_block[0x24], &global_settings.total_uptime, 4); 267 memcpy(&config_block[0x12], &global_settings.resume_index, 4);
268 memcpy(&config_block[0x16], &global_settings.resume_offset, 4);
269 memcpy(&config_block[0xF8], &global_settings.resume_seed, 4);
270
271 memcpy(&config_block[0x24], &global_settings.total_uptime, 4);
272 strncpy(&config_block[0xFC], global_settings.resume_file, MAX_PATH);
247 273
274 DEBUGF("+Resume file %s\n",global_settings.resume_file);
275 DEBUGF("+Resume index %X offset %X\n",
276 global_settings.resume_index,
277 global_settings.resume_offset);
278 DEBUGF("+Resume shuffle %s seed %X\n",
279 global_settings.playlist_shuffle?"on":"off",
280 global_settings.resume_seed);
281
248 if(save_config_buffer()) 282 if(save_config_buffer())
249 { 283 {
250 lcd_clear_display(); 284 lcd_clear_display();
@@ -277,51 +311,65 @@ void settings_load(void)
277 /* load the buffer from the RTC (resets it to all-unused if the block 311 /* load the buffer from the RTC (resets it to all-unused if the block
278 is invalid) and decode the settings which are set in the block */ 312 is invalid) and decode the settings which are set in the block */
279 if (!load_config_buffer()) { 313 if (!load_config_buffer()) {
280 if (rtc_config_block[0x4] != 0xFF) 314 if (config_block[0x4] != 0xFF)
281 global_settings.volume = rtc_config_block[0x4]; 315 global_settings.volume = config_block[0x4];
282 if (rtc_config_block[0x5] != 0xFF) 316 if (config_block[0x5] != 0xFF)
283 global_settings.balance = rtc_config_block[0x5]; 317 global_settings.balance = config_block[0x5];
284 if (rtc_config_block[0x6] != 0xFF) 318 if (config_block[0x6] != 0xFF)
285 global_settings.bass = rtc_config_block[0x6]; 319 global_settings.bass = config_block[0x6];
286 if (rtc_config_block[0x7] != 0xFF) 320 if (config_block[0x7] != 0xFF)
287 global_settings.treble = rtc_config_block[0x7]; 321 global_settings.treble = config_block[0x7];
288 if (rtc_config_block[0x8] != 0xFF) 322 if (config_block[0x8] != 0xFF)
289 global_settings.loudness = rtc_config_block[0x8]; 323 global_settings.loudness = config_block[0x8];
290 if (rtc_config_block[0x9] != 0xFF) 324 if (config_block[0x9] != 0xFF)
291 global_settings.bass_boost = rtc_config_block[0x9]; 325 global_settings.bass_boost = config_block[0x9];
292 326
293 if (rtc_config_block[0xa] != 0xFF) { 327 if (config_block[0xa] != 0xFF) {
294 global_settings.contrast = rtc_config_block[0xa]; 328 global_settings.contrast = config_block[0xa];
295 if ( global_settings.contrast < MIN_CONTRAST_SETTING ) 329 if ( global_settings.contrast < MIN_CONTRAST_SETTING )
296 global_settings.contrast = DEFAULT_CONTRAST_SETTING; 330 global_settings.contrast = DEFAULT_CONTRAST_SETTING;
297 } 331 }
298 if (rtc_config_block[0xb] != 0xFF) 332 if (config_block[0xb] != 0xFF)
299 global_settings.backlight = rtc_config_block[0xb]; 333 global_settings.backlight = config_block[0xb];
300 if (rtc_config_block[0xc] != 0xFF) 334 if (config_block[0xc] != 0xFF)
301 global_settings.poweroff = rtc_config_block[0xc]; 335 global_settings.poweroff = config_block[0xc];
302 if (rtc_config_block[0xd] != 0xFF) 336 if (config_block[0xd] != 0xFF)
303 global_settings.resume = rtc_config_block[0xd]; 337 global_settings.resume = config_block[0xd];
304 if (rtc_config_block[0xe] != 0xFF) { 338 if (config_block[0xe] != 0xFF) {
305 global_settings.playlist_shuffle = rtc_config_block[0xe] & 1; 339 global_settings.playlist_shuffle = config_block[0xe] & 1;
306 global_settings.mp3filter = (rtc_config_block[0xe] >> 1) & 1; 340 global_settings.mp3filter = (config_block[0xe] >> 1) & 1;
307 global_settings.sort_case = (rtc_config_block[0xe] >> 2) & 1; 341 global_settings.sort_case = (config_block[0xe] >> 2) & 1;
308 global_settings.discharge = (rtc_config_block[0xe] >> 3) & 1; 342 global_settings.discharge = (config_block[0xe] >> 3) & 1;
309 global_settings.statusbar = (rtc_config_block[0xe] >> 4) & 1; 343 global_settings.statusbar = (config_block[0xe] >> 4) & 1;
310 } 344 }
311 345
312 c = rtc_config_block[0xf] >> 3; 346 c = config_block[0xf] >> 3;
313 if (c != 31) 347 if (c != 31)
314 global_settings.scroll_speed = c; 348 global_settings.scroll_speed = c;
315 349
316 c = rtc_config_block[0xf] & 7; 350 c = config_block[0xf] & 7;
317 if (c != 7) 351 if (c != 7)
318 global_settings.wps_display = c; 352 global_settings.wps_display = c;
319 353
320 if (rtc_config_block[0x11] != 0xFF) 354 if (config_block[0x10] != 0xFF)
321 global_settings.avc = rtc_config_block[0x11]; 355 global_settings.ff_rewind = config_block[0x10];
356
357 if (config_block[0x11] != 0xFF)
358 global_settings.avc = config_block[0x11];
359
360 if (config_block[0x12] != 0xFF)
361 memcpy(&global_settings.resume_index, &config_block[0x12], 4);
362
363 if (config_block[0x16] != 0xFF)
364 memcpy(&global_settings.resume_offset, &config_block[0x16], 4);
365
366 memcpy(&global_settings.resume_seed, &config_block[0xF8], 4);
367
368 if (config_block[0x24] != 0xFF)
369 memcpy(&global_settings.total_uptime, &config_block[0x24], 4);
322 370
323 if (rtc_config_block[0x24] != 0xFF) 371 strncpy(global_settings.resume_file, &config_block[0xFC], MAX_PATH);
324 memcpy(&global_settings.total_uptime, &rtc_config_block[0x24], 4); 372 global_settings.resume_file[MAX_PATH]=0;
325 } 373 }
326 lcd_set_contrast(global_settings.contrast); 374 lcd_set_contrast(global_settings.contrast);
327 lcd_scroll_speed(global_settings.scroll_speed); 375 lcd_scroll_speed(global_settings.scroll_speed);
@@ -345,6 +393,7 @@ void settings_reset(void) {
345 global_settings.loudness = mpeg_sound_default(SOUND_LOUDNESS); 393 global_settings.loudness = mpeg_sound_default(SOUND_LOUDNESS);
346 global_settings.bass_boost = mpeg_sound_default(SOUND_SUPERBASS); 394 global_settings.bass_boost = mpeg_sound_default(SOUND_SUPERBASS);
347 global_settings.avc = mpeg_sound_default(SOUND_AVC); 395 global_settings.avc = mpeg_sound_default(SOUND_AVC);
396 global_settings.resume = true;
348 global_settings.contrast = DEFAULT_CONTRAST_SETTING; 397 global_settings.contrast = DEFAULT_CONTRAST_SETTING;
349 global_settings.poweroff = DEFAULT_POWEROFF_SETTING; 398 global_settings.poweroff = DEFAULT_POWEROFF_SETTING;
350 global_settings.backlight = DEFAULT_BACKLIGHT_SETTING; 399 global_settings.backlight = DEFAULT_BACKLIGHT_SETTING;
@@ -358,6 +407,8 @@ void settings_reset(void) {
358 global_settings.total_uptime = 0; 407 global_settings.total_uptime = 0;
359 global_settings.scroll_speed = 8; 408 global_settings.scroll_speed = 8;
360 global_settings.ff_rewind = DEFAULT_FF_REWIND_SETTING; 409 global_settings.ff_rewind = DEFAULT_FF_REWIND_SETTING;
410 global_settings.resume_index = -1;
411 global_settings.resume_offset = -1;
361} 412}
362 413
363 414
diff --git a/apps/settings.h b/apps/settings.h
index ba2a109f1a..f3f6d84327 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -21,6 +21,7 @@
21#define __SETTINGS_H__ 21#define __SETTINGS_H__
22 22
23#include <stdbool.h> 23#include <stdbool.h>
24#include "file.h"
24 25
25/* data structures */ 26/* data structures */
26 27
@@ -49,8 +50,11 @@ struct user_settings
49 50
50 /* resume settings */ 51 /* resume settings */
51 52
52 int resume; /* power-on song resume: 0=no. 1=yes song. 2=yes pl */ 53 bool resume; /* resume option on/off */
53 int track_time; /* number of seconds into the track to resume */ 54 int resume_index; /* index in playlist (-1 for no active resume) */
55 int resume_offset; /* byte offset in mp3 file */
56 int resume_seed; /* random seed for playlist shuffle */
57 unsigned char resume_file[MAX_PATH+1]; /* playlist name (or dir) */
54 58
55 /* misc options */ 59 /* misc options */
56 60
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index 0de99b0335..e66d0f389c 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -57,6 +57,11 @@ static void sort_case(void)
57 set_bool( "[Sort case sensitive]", &global_settings.sort_case ); 57 set_bool( "[Sort case sensitive]", &global_settings.sort_case );
58} 58}
59 59
60static void resume(void)
61{
62 set_bool( "[Resume]", &global_settings.resume );
63}
64
60static void backlight_timer(void) 65static void backlight_timer(void)
61{ 66{
62 char* names[] = { "off", "on ", 67 char* names[] = { "off", "on ",
@@ -153,13 +158,13 @@ void settings_menu(void)
153 { "Time/Date", timedate_set }, 158 { "Time/Date", timedate_set },
154#endif 159#endif
155 { "FF/Rewind", ff_rewind }, 160 { "FF/Rewind", ff_rewind },
161 { "Resume", resume },
156 }; 162 };
157 bool old_shuffle = global_settings.playlist_shuffle; 163 bool old_shuffle = global_settings.playlist_shuffle;
158 164
159 m=menu_init( items, sizeof items / sizeof(struct menu_items) ); 165 m=menu_init( items, sizeof items / sizeof(struct menu_items) );
160 menu_run(m); 166 menu_run(m);
161 menu_exit(m); 167 menu_exit(m);
162 settings_save();
163 168
164 if (old_shuffle != global_settings.playlist_shuffle) 169 if (old_shuffle != global_settings.playlist_shuffle)
165 { 170 {
diff --git a/apps/tree.c b/apps/tree.c
index d2660513a5..5312885f19 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -102,12 +102,14 @@ extern unsigned char bitmap_icons_6x8[LastIcon][6];
102#define TREE_EXIT BUTTON_LEFT 102#define TREE_EXIT BUTTON_LEFT
103#define TREE_ENTER BUTTON_RIGHT 103#define TREE_ENTER BUTTON_RIGHT
104#define TREE_MENU BUTTON_F1 104#define TREE_MENU BUTTON_F1
105#define RELEASE_MASK (BUTTON_OFF)
105#else 106#else
106#define TREE_NEXT BUTTON_RIGHT 107#define TREE_NEXT BUTTON_RIGHT
107#define TREE_PREV BUTTON_LEFT 108#define TREE_PREV BUTTON_LEFT
108#define TREE_EXIT BUTTON_STOP 109#define TREE_EXIT BUTTON_STOP
109#define TREE_ENTER BUTTON_PLAY 110#define TREE_ENTER BUTTON_PLAY
110#define TREE_MENU BUTTON_MENU 111#define TREE_MENU BUTTON_MENU
112#define RELEASE_MASK (BUTTON_STOP)
111#endif /* HAVE_RECORDER_KEYPAD */ 113#endif /* HAVE_RECORDER_KEYPAD */
112 114
113#define TREE_ATTR_M3U 0x80 /* unused by FAT attributes */ 115#define TREE_ATTR_M3U 0x80 /* unused by FAT attributes */
@@ -292,6 +294,98 @@ static int showdir(char *path, int start)
292 return filesindir; 294 return filesindir;
293} 295}
294 296
297bool ask_resume(void)
298{
299 lcd_clear_display();
300 lcd_puts(0,0,"Resume?");
301#ifdef HAVE_LCD_CHARCELLS
302 lcd_puts(0,1,"(Play/Stop)");
303#else
304 lcd_puts(0,1,"Play = Yes");
305 lcd_puts(0,2,"Any other = No");
306#endif
307 lcd_update();
308 if (button_get(true) == BUTTON_PLAY)
309 return true;
310 return false;
311}
312
313void start_resume(void)
314{
315 if ( global_settings.resume &&
316 global_settings.resume_index != -1 ) {
317 int len = strlen(global_settings.resume_file);
318
319 DEBUGF("Resume file %s\n",global_settings.resume_file);
320 DEBUGF("Resume index %X offset %X\n",
321 global_settings.resume_index,
322 global_settings.resume_offset);
323 DEBUGF("Resume shuffle %s seed %X\n",
324 global_settings.playlist_shuffle?"on":"off",
325 global_settings.resume_seed);
326
327 /* playlist? */
328 if (!strcasecmp(&global_settings.resume_file[len-4], ".m3u")) {
329 char* slash;
330
331 /* check that the file exists */
332 int fd = open(global_settings.resume_file, O_RDONLY);
333 if(fd<0)
334 return;
335 close(fd);
336
337 if (!ask_resume())
338 return;
339
340 slash = strrchr(global_settings.resume_file,'/');
341 if (slash) {
342 *slash=0;
343 play_list(global_settings.resume_file,
344 slash+1,
345 global_settings.resume_index,
346 global_settings.resume_offset,
347 global_settings.resume_seed );
348 *slash='/';
349 }
350 else {
351 /* check that the dir exists */
352 DIR* dir = opendir(global_settings.resume_file);
353 if(!dir)
354 return;
355 closedir(dir);
356
357 if (!ask_resume())
358 return;
359
360 play_list("/",
361 global_settings.resume_file,
362 global_settings.resume_index,
363 global_settings.resume_offset,
364 global_settings.resume_seed );
365 }
366 }
367 else {
368 int start_index;
369
370 if (!ask_resume())
371 return;
372
373 if (showdir(global_settings.resume_file, 0) < 0 )
374 return;
375 start_index = build_playlist(global_settings.resume_index);
376 play_list(global_settings.resume_file,
377 NULL,
378 start_index,
379 global_settings.resume_offset,
380 global_settings.resume_seed);
381 }
382
383 status_set_playmode(STATUS_PLAY);
384 status_draw();
385 wps_show();
386 }
387}
388
295bool dirbrowse(char *root) 389bool dirbrowse(char *root)
296{ 390{
297 int numentries=0; 391 int numentries=0;
@@ -317,6 +411,9 @@ bool dirbrowse(char *root)
317 tree_max_on_screen = TREE_MAX_ON_SCREEN; 411 tree_max_on_screen = TREE_MAX_ON_SCREEN;
318#endif 412#endif
319 413
414 start_resume();
415 button_set_release(RELEASE_MASK);
416
320 memcpy(currdir,root,sizeof(currdir)); 417 memcpy(currdir,root,sizeof(currdir));
321 numentries = showdir(root, start); 418 numentries = showdir(root, start);
322 if (numentries == -1) 419 if (numentries == -1)
@@ -350,6 +447,7 @@ bool dirbrowse(char *root)
350 restore = true; 447 restore = true;
351 } 448 }
352 break; 449 break;
450
353#ifdef HAVE_RECORDER_KEYPAD 451#ifdef HAVE_RECORDER_KEYPAD
354 case BUTTON_OFF: 452 case BUTTON_OFF:
355 mpeg_stop(); 453 mpeg_stop();
@@ -357,7 +455,15 @@ bool dirbrowse(char *root)
357 status_draw(); 455 status_draw();
358 restore = true; 456 restore = true;
359 break; 457 break;
458
459 case BUTTON_OFF | BUTTON_REL:
460#else
461 case BUTTON_STOP | BUTTON_REL:
360#endif 462#endif
463 global_settings.resume_index = -1;
464 settings_save();
465 break;
466
361 467
362 case TREE_ENTER: 468 case TREE_ENTER:
363#ifdef HAVE_RECORDER_KEYPAD 469#ifdef HAVE_RECORDER_KEYPAD
@@ -383,16 +489,34 @@ bool dirbrowse(char *root)
383 dircursor=0; 489 dircursor=0;
384 start=0; 490 start=0;
385 } else { 491 } else {
492 int seed = current_tick;
386 lcd_stop_scroll(); 493 lcd_stop_scroll();
387 if(dircache[dircursor+start].attr & TREE_ATTR_M3U ) 494 if(dircache[dircursor+start].attr & TREE_ATTR_M3U )
388 { 495 {
496 if ( global_settings.resume )
497 snprintf(global_settings.resume_file,
498 MAX_PATH, "%s/%s",
499 currdir,
500 dircache[dircursor+start].name);
389 play_list(currdir, 501 play_list(currdir,
390 dircache[dircursor+start].name, 0); 502 dircache[dircursor+start].name,
503 0, 0, seed );
391 } 504 }
392 else { 505 else {
506 if ( global_settings.resume )
507 strncpy(global_settings.resume_file,
508 currdir, MAX_PATH);
393 start_index = build_playlist(dircursor+start); 509 start_index = build_playlist(dircursor+start);
394 play_list(currdir, NULL, start_index); 510 play_list(currdir, NULL, start_index, 0, seed);
395 } 511 }
512
513 if ( global_settings.resume ) {
514 global_settings.resume_index = 0;
515 global_settings.resume_offset = 0;
516 global_settings.resume_seed = seed;
517 settings_save();
518 }
519
396 status_set_playmode(STATUS_PLAY); 520 status_set_playmode(STATUS_PLAY);
397 status_draw(); 521 status_draw();
398 lcd_stop_scroll(); 522 lcd_stop_scroll();
@@ -405,6 +529,7 @@ bool dirbrowse(char *root)
405 dirlevel = 0; 529 dirlevel = 0;
406 dircursor = 0; 530 dircursor = 0;
407 start = 0; 531 start = 0;
532 global_settings.resume_index = -1;
408 } 533 }
409 } 534 }
410 restore = true; 535 restore = true;
diff --git a/apps/wps.c b/apps/wps.c
index 240bc96f07..5b30d2ba0e 100644
--- a/apps/wps.c
+++ b/apps/wps.c
@@ -34,6 +34,7 @@
34#include "powermgmt.h" 34#include "powermgmt.h"
35#include "status.h" 35#include "status.h"
36#include "main_menu.h" 36#include "main_menu.h"
37#include "ata.h"
37#ifdef HAVE_LCD_BITMAP 38#ifdef HAVE_LCD_BITMAP
38#include "icons.h" 39#include "icons.h"
39#include "widgets.h" 40#include "widgets.h"
@@ -462,6 +463,13 @@ int wps_show(void)
462 { 463 {
463 mpeg_pause(); 464 mpeg_pause();
464 status_set_playmode(STATUS_PAUSE); 465 status_set_playmode(STATUS_PAUSE);
466 if (global_settings.resume) {
467 status_draw();
468 settings_save();
469#ifndef HAVE_RTC
470 ata_flush();
471#endif
472 }
465 } 473 }
466 else 474 else
467 { 475 {
@@ -577,7 +585,6 @@ int wps_show(void)
577 mpeg_ff_rewind(ff_rewind_count); 585 mpeg_ff_rewind(ff_rewind_count);
578 ff_rewind_count = 0; 586 ff_rewind_count = 0;
579 ff_rewind = false; 587 ff_rewind = false;
580 status_set_playmode(STATUS_PLAY);
581#ifdef HAVE_LCD_CHARCELLS 588#ifdef HAVE_LCD_CHARCELLS
582 draw_screen(id3); 589 draw_screen(id3);
583#endif 590#endif
@@ -589,7 +596,6 @@ int wps_show(void)
589#endif 596#endif
590 { 597 {
591 mpeg_prev(); 598 mpeg_prev();
592 status_set_playmode(STATUS_PLAY);
593 } 599 }
594 } 600 }
595#ifdef HAVE_PLAYER_KEYPAD 601#ifdef HAVE_PLAYER_KEYPAD
@@ -612,7 +618,6 @@ int wps_show(void)
612 mpeg_ff_rewind(ff_rewind_count); 618 mpeg_ff_rewind(ff_rewind_count);
613 ff_rewind_count = 0; 619 ff_rewind_count = 0;
614 ff_rewind = false; 620 ff_rewind = false;
615 status_set_playmode(STATUS_PLAY);
616#ifdef HAVE_LCD_CHARCELLS 621#ifdef HAVE_LCD_CHARCELLS
617 draw_screen(id3); 622 draw_screen(id3);
618#endif 623#endif
@@ -624,7 +629,6 @@ int wps_show(void)
624#endif 629#endif
625 { 630 {
626 mpeg_next(); 631 mpeg_next();
627 status_set_playmode(STATUS_PLAY);
628 } 632 }
629 } 633 }
630#ifdef HAVE_PLAYER_KEYPAD 634#ifdef HAVE_PLAYER_KEYPAD
@@ -862,6 +866,16 @@ int wps_show(void)
862 if (mpeg_is_playing() && id3) 866 if (mpeg_is_playing() && id3)
863 display_file_time(id3->elapsed, id3->length); 867 display_file_time(id3->elapsed, id3->length);
864 868
869 /* save resume data */
870 if ( id3 &&
871 global_settings.resume &&
872 global_settings.resume_offset != id3->offset ) {
873 DEBUGF("R%X,%X (%X)\n",global_settings.resume_offset,id3->offset,id3);
874 global_settings.resume_index = id3->index;
875 global_settings.resume_offset = id3->offset;
876 settings_save();
877 }
878
865 status_draw(); 879 status_draw();
866 break; 880 break;
867 } 881 }
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c
index 5c8ba2d1b8..620f629e6e 100644
--- a/firmware/drivers/ata.c
+++ b/firmware/drivers/ata.c
@@ -304,6 +304,7 @@ extern void ata_delayed_write(unsigned long sector, void* buf)
304extern void ata_flush(void) 304extern void ata_flush(void)
305{ 305{
306 if ( delayed_write ) { 306 if ( delayed_write ) {
307 DEBUGF("ata_flush()\n");
307 delayed_write = false; 308 delayed_write = false;
308 ata_write_sectors(delayed_sector_num, 1, delayed_sector); 309 ata_write_sectors(delayed_sector_num, 1, delayed_sector);
309 } 310 }
diff --git a/firmware/id3.h b/firmware/id3.h
index 1a5bc7441e..d76614f540 100644
--- a/firmware/id3.h
+++ b/firmware/id3.h
@@ -47,6 +47,10 @@ struct mp3entry {
47 /* these following two fields are used for local buffering */ 47 /* these following two fields are used for local buffering */
48 char id3v2buf[300]; 48 char id3v2buf[300];
49 char id3v1buf[3][32]; 49 char id3v1buf[3][32];
50
51 /* resume related */
52 int offset; /* bytes played */
53 int index; /* playlist index */
50}; 54};
51 55
52#define VBR_FRAMES_FLAG 0x01 56#define VBR_FRAMES_FLAG 0x01
diff --git a/firmware/mpeg.c b/firmware/mpeg.c
index a8442f2e85..13562190ce 100644
--- a/firmware/mpeg.c
+++ b/firmware/mpeg.c
@@ -52,7 +52,8 @@
52#define MPEG_SWAP_DATA 101 52#define MPEG_SWAP_DATA 101
53#define MPEG_TRACK_CHANGE 102 53#define MPEG_TRACK_CHANGE 102
54 54
55extern char* playlist_next(int steps); 55extern char* playlist_next(int steps, int* id);
56extern void update_file_pos( int id, int pos );
56 57
57static char *units[] = 58static char *units[] =
58{ 59{
@@ -243,6 +244,7 @@ static void remove_all_tags(void)
243} 244}
244#endif 245#endif
245 246
247static bool paused; /* playback is paused */
246#ifdef SIMULATOR 248#ifdef SIMULATOR
247static bool playing = false; 249static bool playing = false;
248static bool play_pending = false; 250static bool play_pending = false;
@@ -502,7 +504,7 @@ static void stop_dma(void)
502 504
503static void dma_tick(void) 505static void dma_tick(void)
504{ 506{
505 if(playing) 507 if(playing && !paused)
506 { 508 {
507 /* Start DMA if it is disabled and the DEMAND pin is high */ 509 /* Start DMA if it is disabled and the DEMAND pin is high */
508 if(!dma_on && (PBDR & 0x4000)) 510 if(!dma_on && (PBDR & 0x4000))
@@ -594,6 +596,7 @@ void DEI3(void)
594 596
595 DTCR3 = last_dma_chunk_size & 0xffff; 597 DTCR3 = last_dma_chunk_size & 0xffff;
596 SAR3 = (unsigned int)mp3buf + mp3buf_read; 598 SAR3 = (unsigned int)mp3buf + mp3buf_read;
599 id3tags[tag_read_idx]->id3.offset += last_dma_chunk_size;
597 } 600 }
598 else 601 else
599 { 602 {
@@ -646,10 +649,11 @@ static void add_track_to_tag_list(char *filename)
646/* If next_track is true, opens the next track, if false, opens prev track */ 649/* If next_track is true, opens the next track, if false, opens prev track */
647static int new_file(int steps) 650static int new_file(int steps)
648{ 651{
649 char *trackname;
650
651 do { 652 do {
652 trackname = playlist_next( steps ); 653 char *trackname;
654 int index;
655
656 trackname = playlist_next( steps, &index );
653 if ( !trackname ) 657 if ( !trackname )
654 return -1; 658 return -1;
655 659
@@ -666,6 +670,8 @@ static int new_file(int steps)
666 lseek(mpeg_file, 670 lseek(mpeg_file,
667 id3tags[tag_read_idx]->id3.id3v2len & ~1, 671 id3tags[tag_read_idx]->id3.id3v2len & ~1,
668 SEEK_SET); 672 SEEK_SET);
673 id3tags[tag_read_idx]->id3.index = index;
674 id3tags[tag_read_idx]->id3.offset = 0;
669 } 675 }
670 } while ( mpeg_file < 0 ); 676 } while ( mpeg_file < 0 );
671 677
@@ -706,6 +712,7 @@ static void mpeg_thread(void)
706 int amount_to_read; 712 int amount_to_read;
707 int amount_to_swap; 713 int amount_to_swap;
708 int t1, t2; 714 int t1, t2;
715 int start_offset;
709 716
710 play_pending = false; 717 play_pending = false;
711 playing = false; 718 playing = false;
@@ -720,7 +727,7 @@ static void mpeg_thread(void)
720 switch(ev.id) 727 switch(ev.id)
721 { 728 {
722 case MPEG_PLAY: 729 case MPEG_PLAY:
723 DEBUGF("MPEG_PLAY %s\n",ev.data); 730 DEBUGF("MPEG_PLAY\n");
724 /* Stop the current stream */ 731 /* Stop the current stream */
725 play_pending = false; 732 play_pending = false;
726 playing = false; 733 playing = false;
@@ -732,18 +739,21 @@ static void mpeg_thread(void)
732 if(mpeg_file >= 0) 739 if(mpeg_file >= 0)
733 close(mpeg_file); 740 close(mpeg_file);
734 741
735 mpeg_file = open((char*)ev.data, O_RDONLY); 742 if ( new_file(0) == -1 )
736 while (mpeg_file < 0) { 743 return;
737 DEBUGF("Couldn't open file: %s\n",ev.data); 744
738 if ( new_file(1) == -1 ) 745 start_offset = (int)ev.data;
739 return; 746 if (start_offset) {
747 lseek(mpeg_file, start_offset, SEEK_SET);
748 id3tags[tag_read_idx]->id3.offset = start_offset;
740 } 749 }
750 else {
751 /* skip past id3v2 tag (to an even byte) */
752 lseek(mpeg_file,
753 id3tags[tag_read_idx]->id3.id3v2len & ~1,
754 SEEK_SET);
741 755
742 add_track_to_tag_list((char *)ev.data); 756 }
743 /* skip past id3v2 tag (to an even byte) */
744 lseek(mpeg_file,
745 id3tags[tag_read_idx]->id3.id3v2len & ~1,
746 SEEK_SET);
747 757
748 /* Make it read more data */ 758 /* Make it read more data */
749 filling = true; 759 filling = true;
@@ -752,6 +762,7 @@ static void mpeg_thread(void)
752 /* Tell the file loading code that we want to start playing 762 /* Tell the file loading code that we want to start playing
753 as soon as we have some data */ 763 as soon as we have some data */
754 play_pending = true; 764 play_pending = true;
765 paused = false;
755 766
756 current_track_counter++; 767 current_track_counter++;
757 break; 768 break;
@@ -764,6 +775,7 @@ static void mpeg_thread(void)
764 case MPEG_PAUSE: 775 case MPEG_PAUSE:
765 DEBUGF("MPEG_PAUSE\n"); 776 DEBUGF("MPEG_PAUSE\n");
766 /* Stop the current stream */ 777 /* Stop the current stream */
778 paused = true;
767 playing = false; 779 playing = false;
768 pause_tick = current_tick; 780 pause_tick = current_tick;
769 stop_dma(); 781 stop_dma();
@@ -775,6 +787,7 @@ static void mpeg_thread(void)
775 playing = true; 787 playing = true;
776 last_dma_tick += current_tick - pause_tick; 788 last_dma_tick += current_tick - pause_tick;
777 pause_tick = 0; 789 pause_tick = 0;
790 paused = false;
778 start_dma(); 791 start_dma();
779 break; 792 break;
780 793
@@ -799,7 +812,8 @@ static void mpeg_thread(void)
799 play_pending = true; 812 play_pending = true;
800 } else { 813 } else {
801 playing = true; 814 playing = true;
802 start_dma(); 815 if (!paused)
816 start_dma();
803 } 817 }
804 818
805 track_change(); 819 track_change();
@@ -931,7 +945,8 @@ static void mpeg_thread(void)
931 playing = true; 945 playing = true;
932 last_dma_tick = current_tick; 946 last_dma_tick = current_tick;
933 init_dma(); 947 init_dma();
934 start_dma(); 948 if (!paused)
949 start_dma();
935 } 950 }
936 else 951 else
937 { 952 {
@@ -1016,7 +1031,8 @@ static void mpeg_thread(void)
1016 1031
1017 last_dma_tick = current_tick; 1032 last_dma_tick = current_tick;
1018 init_dma(); 1033 init_dma();
1019 start_dma(); 1034 if (!paused)
1035 start_dma();
1020 1036
1021 /* Tell ourselves that we need more data */ 1037 /* Tell ourselves that we need more data */
1022 queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); 1038 queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
@@ -1188,7 +1204,7 @@ static void setup_sci0(void)
1188static struct mp3entry taginfo; 1204static struct mp3entry taginfo;
1189#endif 1205#endif
1190 1206
1191struct mp3entry* mpeg_current_track(void) 1207struct mp3entry* mpeg_current_track()
1192{ 1208{
1193#ifdef SIMULATOR 1209#ifdef SIMULATOR
1194 return &taginfo; 1210 return &taginfo;
@@ -1210,13 +1226,17 @@ bool mpeg_has_changed_track(void)
1210 return false; 1226 return false;
1211} 1227}
1212 1228
1213void mpeg_play(char* trackname) 1229void mpeg_play(int offset)
1214{ 1230{
1215#ifdef SIMULATOR 1231#ifdef SIMULATOR
1216 mp3info(&taginfo, trackname); 1232 char* trackname = playlist_next( 0, NULL );
1217 playing = true; 1233 if ( trackname ) {
1234 mp3info(&taginfo, trackname);
1235 playing = true;
1236 }
1237 (void)offset;
1218#else 1238#else
1219 queue_post(&mpeg_queue, MPEG_PLAY, trackname); 1239 queue_post(&mpeg_queue, MPEG_PLAY, (void*)offset);
1220#endif 1240#endif
1221} 1241}
1222 1242
@@ -1252,7 +1272,7 @@ void mpeg_next(void)
1252#ifndef SIMULATOR 1272#ifndef SIMULATOR
1253 queue_post(&mpeg_queue, MPEG_NEXT, NULL); 1273 queue_post(&mpeg_queue, MPEG_NEXT, NULL);
1254#else 1274#else
1255 char* file = playlist_next(1); 1275 char* file = playlist_next(1,NULL);
1256 mp3info(&taginfo, file); 1276 mp3info(&taginfo, file);
1257 current_track_counter++; 1277 current_track_counter++;
1258 playing = true; 1278 playing = true;
@@ -1264,7 +1284,7 @@ void mpeg_prev(void)
1264#ifndef SIMULATOR 1284#ifndef SIMULATOR
1265 queue_post(&mpeg_queue, MPEG_PREV, NULL); 1285 queue_post(&mpeg_queue, MPEG_PREV, NULL);
1266#else 1286#else
1267 char* file = playlist_next(-1); 1287 char* file = playlist_next(-1,NULL);
1268 mp3info(&taginfo, file); 1288 mp3info(&taginfo, file);
1269 current_track_counter--; 1289 current_track_counter--;
1270 playing = true; 1290 playing = true;
@@ -1282,7 +1302,7 @@ void mpeg_ff_rewind(int change)
1282 1302
1283bool mpeg_is_playing(void) 1303bool mpeg_is_playing(void)
1284{ 1304{
1285 return playing || play_pending; 1305 return (playing || play_pending) && (!paused) ;
1286} 1306}
1287 1307
1288#ifndef SIMULATOR 1308#ifndef SIMULATOR
diff --git a/firmware/mpeg.h b/firmware/mpeg.h
index 48367317dc..69110b34ec 100644
--- a/firmware/mpeg.h
+++ b/firmware/mpeg.h
@@ -22,7 +22,7 @@
22#include <stdbool.h> 22#include <stdbool.h>
23 23
24void mpeg_init(int volume, int bass, int treble, int balance, int loudness, int bass_boost, int avc); 24void mpeg_init(int volume, int bass, int treble, int balance, int loudness, int bass_boost, int avc);
25void mpeg_play(char* trackname); 25void mpeg_play(int offset);
26void mpeg_stop(void); 26void mpeg_stop(void);
27void mpeg_pause(void); 27void mpeg_pause(void);
28void mpeg_resume(void); 28void mpeg_resume(void);
diff --git a/uisimulator/common/stubs.c b/uisimulator/common/stubs.c
index 22623dcb5e..1446b82a4d 100644
--- a/uisimulator/common/stubs.c
+++ b/uisimulator/common/stubs.c
@@ -80,3 +80,7 @@ void ata_delayed_write(unsigned long sector, void* buf)
80{ 80{
81 ata_write_sectors(sector,1,buf); 81 ata_write_sectors(sector,1,buf);
82} 82}
83
84void ata_flush(void)
85{
86}