summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/lang/english.lang10
-rw-r--r--apps/recorder/radio.c47
-rw-r--r--apps/recorder/recording.c75
-rw-r--r--apps/settings.c30
-rw-r--r--apps/settings.h2
-rw-r--r--apps/sound_menu.c18
-rw-r--r--firmware/export/mpeg.h7
-rw-r--r--firmware/mpeg.c582
8 files changed, 526 insertions, 245 deletions
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index ffdc12b306..5cad562a7f 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -1847,3 +1847,13 @@ id: LANG_FLIP_DISPLAY
1847desc: in settings_menu, option to turn display+buttos by 180 degreed 1847desc: in settings_menu, option to turn display+buttos by 180 degreed
1848eng: "Upside Down" 1848eng: "Upside Down"
1849new: 1849new:
1850
1851id: LANG_RECORD_PRERECORD
1852desc: in recording and radio screen
1853eng: "Prerecording"
1854new:
1855
1856id: LANG_RECORD_PRERECORD_TIME
1857desc: in recording settings_menu
1858eng: "Prerecord time"
1859new:
diff --git a/apps/recorder/radio.c b/apps/recorder/radio.c
index ab0c1eb004..519e919964 100644
--- a/apps/recorder/radio.c
+++ b/apps/recorder/radio.c
@@ -172,9 +172,10 @@ bool radio_screen(void)
172 172
173 mpeg_set_recording_options(global_settings.rec_frequency, 173 mpeg_set_recording_options(global_settings.rec_frequency,
174 global_settings.rec_quality, 174 global_settings.rec_quality,
175 1 /* Line In */, 175 1, /* Line In */
176 global_settings.rec_channels, 176 global_settings.rec_channels,
177 global_settings.rec_editable); 177 global_settings.rec_editable,
178 global_settings.rec_prerecord_time);
178 179
179 180
180 mpeg_set_recording_gain(mpeg_sound_default(SOUND_LEFT_GAIN), 181 mpeg_set_recording_gain(mpeg_sound_default(SOUND_LEFT_GAIN),
@@ -230,7 +231,7 @@ bool radio_screen(void)
230 switch(button) 231 switch(button)
231 { 232 {
232 case BUTTON_OFF: 233 case BUTTON_OFF:
233 if(mpeg_status()) 234 if(mpeg_status() == MPEG_STATUS_RECORD)
234 { 235 {
235 mpeg_stop(); 236 mpeg_stop();
236 status_set_playmode(STATUS_STOP); 237 status_set_playmode(STATUS_STOP);
@@ -244,17 +245,16 @@ bool radio_screen(void)
244 break; 245 break;
245 246
246 case BUTTON_F3: 247 case BUTTON_F3:
247 /* Only act if the mpeg is stopped */ 248 if(mpeg_status() == MPEG_STATUS_RECORD)
248 if(!mpeg_status())
249 { 249 {
250 have_recorded = true; 250 mpeg_new_file(rec_create_filename());
251 mpeg_record(rec_create_filename());
252 status_set_playmode(STATUS_RECORD);
253 update_screen = true; 251 update_screen = true;
254 } 252 }
255 else 253 else
256 { 254 {
257 mpeg_new_file(rec_create_filename()); 255 have_recorded = true;
256 mpeg_record(rec_create_filename());
257 status_set_playmode(STATUS_RECORD);
258 update_screen = true; 258 update_screen = true;
259 } 259 }
260 last_seconds = 0; 260 last_seconds = 0;
@@ -353,11 +353,12 @@ bool radio_screen(void)
353 353
354 case SYS_USB_CONNECTED: 354 case SYS_USB_CONNECTED:
355 /* Only accept USB connection when not recording */ 355 /* Only accept USB connection when not recording */
356 if(!mpeg_status()) 356 if(mpeg_status() != MPEG_STATUS_RECORD)
357 { 357 {
358 usb_screen(); 358 usb_screen();
359 fmradio_set_status(0); 359 fmradio_set_status(0);
360 have_recorded = true; /* Refreshes the browser later on */ 360 screen_freeze = true; /* Cosmetic: makes sure the
361 radio screen doesn't redraw */
361 done = true; 362 done = true;
362 } 363 }
363 break; 364 break;
@@ -368,6 +369,8 @@ bool radio_screen(void)
368 if(!screen_freeze) 369 if(!screen_freeze)
369 { 370 {
370 lcd_setmargins(0, 8); 371 lcd_setmargins(0, 8);
372
373 /* Only display the peak meter when not recording */
371 if(!mpeg_status()) 374 if(!mpeg_status())
372 { 375 {
373 lcd_clearrect(0, 8 + fh*(top_of_screen + 3), LCD_WIDTH, fh); 376 lcd_clearrect(0, 8 + fh*(top_of_screen + 3), LCD_WIDTH, fh);
@@ -415,7 +418,7 @@ bool radio_screen(void)
415 str(LANG_CHANNEL_MONO)); 418 str(LANG_CHANNEL_MONO));
416 lcd_puts(0, top_of_screen + 2, buf); 419 lcd_puts(0, top_of_screen + 2, buf);
417 420
418 if(mpeg_status()) 421 if(mpeg_status() == MPEG_STATUS_RECORD)
419 { 422 {
420 hours = seconds / 3600; 423 hours = seconds / 3600;
421 minutes = (seconds - (hours * 3600)) / 60; 424 minutes = (seconds - (hours * 3600)) / 60;
@@ -424,6 +427,12 @@ bool radio_screen(void)
424 hours, minutes, seconds%60); 427 hours, minutes, seconds%60);
425 lcd_puts(0, top_of_screen + 3, buf); 428 lcd_puts(0, top_of_screen + 3, buf);
426 } 429 }
430 else
431 {
432 snprintf(buf, 32, "%s %02d",
433 str(LANG_RECORD_PRERECORD), seconds%60);
434 lcd_puts(0, top_of_screen + 3, buf);
435 }
427 436
428 /* Only force the redraw if update_screen is true */ 437 /* Only force the redraw if update_screen is true */
429 status_draw(update_screen); 438 status_draw(update_screen);
@@ -687,7 +696,19 @@ bool radio_delete_preset(void)
687 696
688static bool fm_recording_settings(void) 697static bool fm_recording_settings(void)
689{ 698{
690 return recording_menu(true); 699 bool ret;
700
701 ret = recording_menu(true);
702 if(!ret)
703 {
704 mpeg_set_recording_options(global_settings.rec_frequency,
705 global_settings.rec_quality,
706 1, /* Line In */
707 global_settings.rec_channels,
708 global_settings.rec_editable,
709 global_settings.rec_prerecord_time);
710 }
711 return ret;
691} 712}
692 713
693bool radio_menu(void) 714bool radio_menu(void)
diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c
index d94508e547..bc26ff8495 100644
--- a/apps/recorder/recording.c
+++ b/apps/recorder/recording.c
@@ -160,7 +160,8 @@ bool recording_screen(void)
160 global_settings.rec_quality, 160 global_settings.rec_quality,
161 global_settings.rec_source, 161 global_settings.rec_source,
162 global_settings.rec_channels, 162 global_settings.rec_channels,
163 global_settings.rec_editable); 163 global_settings.rec_editable,
164 global_settings.rec_prerecord_time);
164 165
165 set_gain(); 166 set_gain();
166 167
@@ -174,7 +175,7 @@ bool recording_screen(void)
174 switch(button) 175 switch(button)
175 { 176 {
176 case BUTTON_OFF: 177 case BUTTON_OFF:
177 if(mpeg_status()) 178 if(mpeg_status() & MPEG_STATUS_RECORD)
178 { 179 {
179 mpeg_stop(); 180 mpeg_stop();
180 status_set_playmode(STATUS_STOP); 181 status_set_playmode(STATUS_STOP);
@@ -190,7 +191,7 @@ bool recording_screen(void)
190 191
191 case BUTTON_PLAY: 192 case BUTTON_PLAY:
192 /* Only act if the mpeg is stopped */ 193 /* Only act if the mpeg is stopped */
193 if(!mpeg_status()) 194 if(!(mpeg_status() & MPEG_STATUS_RECORD))
194 { 195 {
195 have_recorded = true; 196 have_recorded = true;
196 mpeg_record(rec_create_filename()); 197 mpeg_record(rec_create_filename());
@@ -305,13 +306,16 @@ bool recording_screen(void)
305 if (recording_menu(false)) 306 if (recording_menu(false))
306 return SYS_USB_CONNECTED; 307 return SYS_USB_CONNECTED;
307 settings_save(); 308 settings_save();
309
308 mpeg_set_recording_options(global_settings.rec_frequency, 310 mpeg_set_recording_options(global_settings.rec_frequency,
309 global_settings.rec_quality, 311 global_settings.rec_quality,
310 global_settings.rec_source, 312 global_settings.rec_source,
311 global_settings.rec_channels, 313 global_settings.rec_channels,
312 global_settings.rec_editable); 314 global_settings.rec_editable,
315 global_settings.rec_prerecord_time);
313 316
314 set_gain(); 317 set_gain();
318
315 update_countdown = 1; /* Update immediately */ 319 update_countdown = 1; /* Update immediately */
316 320
317 lcd_setfont(FONT_SYSFIXED); 321 lcd_setfont(FONT_SYSFIXED);
@@ -319,7 +323,7 @@ bool recording_screen(void)
319 break; 323 break;
320 324
321 case BUTTON_F2: 325 case BUTTON_F2:
322 if(!mpeg_status()) 326 if(mpeg_status() != MPEG_STATUS_RECORD)
323 { 327 {
324 if (f2_rec_screen()) 328 if (f2_rec_screen())
325 { 329 {
@@ -332,7 +336,7 @@ bool recording_screen(void)
332 break; 336 break;
333 337
334 case BUTTON_F3: 338 case BUTTON_F3:
335 if(!mpeg_status()) 339 if(mpeg_status() != MPEG_STATUS_RECORD)
336 { 340 {
337 if (f3_rec_screen()) 341 if (f3_rec_screen())
338 { 342 {
@@ -346,14 +350,12 @@ bool recording_screen(void)
346 350
347 case SYS_USB_CONNECTED: 351 case SYS_USB_CONNECTED:
348 /* Only accept USB connection when not recording */ 352 /* Only accept USB connection when not recording */
349 if(!mpeg_status()) 353 if(mpeg_status() != MPEG_STATUS_RECORD)
350 { 354 {
351 usb_screen(); 355 usb_screen();
352 have_recorded = true; /* Refreshes the browser later on */ 356 have_recorded = true; /* Refreshes the browser later on */
353 done = true; 357 done = true;
354 } 358 }
355 lcd_setfont(FONT_SYSFIXED);
356 lcd_setmargins(global_settings.invert_cursor ? 0 : w, 8);
357 break; 359 break;
358 } 360 }
359 361
@@ -387,21 +389,28 @@ bool recording_screen(void)
387 389
388 dseconds = rec_timesplit_seconds(); 390 dseconds = rec_timesplit_seconds();
389 391
390 /* Display the split interval if the record timesplit 392 if(mpeg_status() & MPEG_STATUS_PRERECORD)
391 is active */
392 if (global_settings.rec_timesplit)
393 { 393 {
394 /* Display the record timesplit interval rather than 394 snprintf(buf, 32, "%s...", str(LANG_RECORD_PRERECORD));
395 the file size if the record timer is active */
396 dhours = dseconds / 3600;
397 dminutes = (dseconds - (dhours * 3600)) / 60;
398 snprintf(buf, 32, "%s %02d:%02d",
399 str(LANG_RECORD_TIMESPLIT_REC),
400 dhours, dminutes);
401 } 395 }
402 else 396 else
403 snprintf(buf, 32, "%s %s", str(LANG_RECORDING_SIZE), 397 {
404 num2max5(mpeg_num_recorded_bytes(), buf2)); 398 /* Display the split interval if the record timesplit
399 is active */
400 if (global_settings.rec_timesplit)
401 {
402 /* Display the record timesplit interval rather than
403 the file size if the record timer is active */
404 dhours = dseconds / 3600;
405 dminutes = (dseconds - (dhours * 3600)) / 60;
406 snprintf(buf, 32, "%s %02d:%02d",
407 str(LANG_RECORD_TIMESPLIT_REC),
408 dhours, dminutes);
409 }
410 else
411 snprintf(buf, 32, "%s %s", str(LANG_RECORDING_SIZE),
412 num2max5(mpeg_num_recorded_bytes(), buf2));
413 }
405 lcd_puts(0, 1, buf); 414 lcd_puts(0, 1, buf);
406 415
407 /* We will do file splitting regardless, since the OFF 416 /* We will do file splitting regardless, since the OFF
@@ -622,7 +631,8 @@ bool f2_rec_screen(void)
622 global_settings.rec_quality, 631 global_settings.rec_quality,
623 global_settings.rec_source, 632 global_settings.rec_source,
624 global_settings.rec_channels, 633 global_settings.rec_channels,
625 global_settings.rec_editable); 634 global_settings.rec_editable,
635 global_settings.rec_prerecord_time);
626 636
627 set_gain(); 637 set_gain();
628 638
@@ -671,22 +681,6 @@ bool f3_rec_screen(void)
671 used = true; 681 used = true;
672 break; 682 break;
673 683
674 case BUTTON_DOWN:
675 case BUTTON_F3 | BUTTON_DOWN:
676 global_settings.rec_frequency++;
677 if(global_settings.rec_frequency > 5)
678 global_settings.rec_frequency = 0;
679 used = true;
680 break;
681
682 case BUTTON_RIGHT:
683 case BUTTON_F3 | BUTTON_RIGHT:
684 global_settings.rec_channels++;
685 if(global_settings.rec_channels > 1)
686 global_settings.rec_channels = 0;
687 used = true;
688 break;
689
690 case BUTTON_F3 | BUTTON_REL: 684 case BUTTON_F3 | BUTTON_REL:
691 if ( used ) 685 if ( used )
692 exit = true; 686 exit = true;
@@ -707,10 +701,11 @@ bool f3_rec_screen(void)
707 global_settings.rec_quality, 701 global_settings.rec_quality,
708 global_settings.rec_source, 702 global_settings.rec_source,
709 global_settings.rec_channels, 703 global_settings.rec_channels,
710 global_settings.rec_editable); 704 global_settings.rec_editable,
705 global_settings.rec_prerecord_time);
711 706
712 set_gain(); 707 set_gain();
713 708
714 settings_save(); 709 settings_save();
715 lcd_setfont(FONT_UI); 710 lcd_setfont(FONT_UI);
716 711
diff --git a/apps/settings.c b/apps/settings.c
index b2fa22170b..35e75d12ca 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -129,6 +129,9 @@ location used, and reset the setting in question with a factory default if
129needed. Memory locations not used by a given version should not be 129needed. Memory locations not used by a given version should not be
130modified unless the header & checksum test fails. 130modified unless the header & checksum test fails.
131 131
132Because 0xff mean that the byte is unused, care must be taken so that
133a used byte can't have the value 0xff. Either use only 7 bits, or make sure
134that the value will never be 0xff.
132 135
133Rest of config block, only saved to disk: 136Rest of config block, only saved to disk:
1340xA8 (char)jump scroll mode (only for player) 1370xA8 (char)jump scroll mode (only for player)
@@ -151,9 +154,8 @@ Rest of config block, only saved to disk:
1510xB8 (char[20]) WPS file 1540xB8 (char[20]) WPS file
1520xCC (char[20]) Lang file 1550xCC (char[20]) Lang file
1530xE0 (char[20]) Font file 1560xE0 (char[20]) Font file
1540xF4 <unused> 1570xF4 Prerecording time (bit 0-4)
1550xF8 <unused> 1580xF5-0xFF <unused>
1560xFC <unused>
157 159
158*************************************/ 160*************************************/
159 161
@@ -432,6 +434,8 @@ int settings_save( void )
432 strncpy(&config_block[0xcc], global_settings.lang_file, MAX_FILENAME); 434 strncpy(&config_block[0xcc], global_settings.lang_file, MAX_FILENAME);
433 strncpy(&config_block[0xe0], global_settings.font_file, MAX_FILENAME); 435 strncpy(&config_block[0xe0], global_settings.font_file, MAX_FILENAME);
434 436
437 config_block[0xf4]=(unsigned char)global_settings.rec_prerecord_time;
438
435 if(save_config_buffer()) 439 if(save_config_buffer())
436 { 440 {
437 lcd_clear_display(); 441 lcd_clear_display();
@@ -756,6 +760,10 @@ void settings_load(void)
756 strncpy(global_settings.wps_file, &config_block[0xb8], MAX_FILENAME); 760 strncpy(global_settings.wps_file, &config_block[0xb8], MAX_FILENAME);
757 strncpy(global_settings.lang_file, &config_block[0xcc], MAX_FILENAME); 761 strncpy(global_settings.lang_file, &config_block[0xcc], MAX_FILENAME);
758 strncpy(global_settings.font_file, &config_block[0xe0], MAX_FILENAME); 762 strncpy(global_settings.font_file, &config_block[0xe0], MAX_FILENAME);
763
764 if (config_block[0xf4] != 0xff)
765 global_settings.rec_prerecord_time = config_block[0xf4];
766
759#ifdef HAVE_LCD_CHARCELLS 767#ifdef HAVE_LCD_CHARCELLS
760 if (config_block[0xa8] != 0xff) 768 if (config_block[0xa8] != 0xff)
761 global_settings.jump_scroll = config_block[0xa8]; 769 global_settings.jump_scroll = config_block[0xa8];
@@ -1079,6 +1087,9 @@ bool settings_load_config(char* file)
1079 else if (!strcasecmp(name, "editable recordings")) { 1087 else if (!strcasecmp(name, "editable recordings")) {
1080 set_cfg_bool(&global_settings.rec_editable, value); 1088 set_cfg_bool(&global_settings.rec_editable, value);
1081 } 1089 }
1090 else if (!strcasecmp(name, "prerecording time")) {
1091 set_cfg_int(&global_settings.rec_prerecord_time, value, 0, 30);
1092 }
1082#endif 1093#endif
1083 else if (!strcasecmp(name, "idle poweroff")) { 1094 else if (!strcasecmp(name, "idle poweroff")) {
1084 static char* options[] = {"off","1","2","3","4","5","6","7","8", 1095 static char* options[] = {"off","1","2","3","4","5","6","7","8",
@@ -1379,6 +1390,10 @@ bool settings_save_config(void)
1379 fprintf(fd, "line in: %s\r\n", boolopt[global_settings.line_in]); 1390 fprintf(fd, "line in: %s\r\n", boolopt[global_settings.line_in]);
1380#endif 1391#endif
1381 1392
1393 fprintf(fd, "max files in dir: %d\r\n", global_settings.max_files_in_dir);
1394 fprintf(fd, "max files in playlist: %d\r\n",
1395 global_settings.max_files_in_playlist);
1396
1382#ifdef HAVE_MAS3587F 1397#ifdef HAVE_MAS3587F
1383 fprintf(fd, "#\r\n# Recording\r\n#\r\n"); 1398 fprintf(fd, "#\r\n# Recording\r\n#\r\n");
1384 fprintf(fd, "rec quality: %d\r\n", global_settings.rec_quality); 1399 fprintf(fd, "rec quality: %d\r\n", global_settings.rec_quality);
@@ -1409,12 +1424,12 @@ bool settings_save_config(void)
1409 fprintf(fd, "editable recordings: %s\r\n", 1424 fprintf(fd, "editable recordings: %s\r\n",
1410 boolopt[global_settings.rec_editable]); 1425 boolopt[global_settings.rec_editable]);
1411 1426
1427 fprintf(fd, "prerecording time: %d\r\n",
1428 global_settings.rec_prerecord_time);
1429
1412#endif 1430#endif
1413 1431
1414 fprintf(fd, "max files in dir: %d\r\n", global_settings.max_files_in_dir); 1432 fprintf(fd, "#\r\n# Playlists\r\n#\r\n");
1415 fprintf(fd, "max files in playlist: %d\r\n",
1416 global_settings.max_files_in_playlist);
1417
1418 { 1433 {
1419 static char* options[] = {"off", "on", "ask"}; 1434 static char* options[] = {"off", "on", "ask"};
1420 fprintf(fd, "recursive directory insert: %s\r\n", 1435 fprintf(fd, "recursive directory insert: %s\r\n",
@@ -1454,6 +1469,7 @@ void settings_reset(void) {
1454 global_settings.rec_left_gain = 2; /* 0dB */ 1469 global_settings.rec_left_gain = 2; /* 0dB */
1455 global_settings.rec_right_gain = 2; /* 0dB */ 1470 global_settings.rec_right_gain = 2; /* 0dB */
1456 global_settings.rec_editable = false; 1471 global_settings.rec_editable = false;
1472 global_settings.rec_prerecord_time = 0;
1457 global_settings.resume = RESUME_ASK; 1473 global_settings.resume = RESUME_ASK;
1458 global_settings.contrast = lcd_default_contrast(); 1474 global_settings.contrast = lcd_default_contrast();
1459 global_settings.invert = DEFAULT_INVERT_SETTING; 1475 global_settings.invert = DEFAULT_INVERT_SETTING;
diff --git a/apps/settings.h b/apps/settings.h
index 074be0690a..49327b2f80 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -85,6 +85,8 @@ struct user_settings
85 5 = 01:00, 6 = 02:00, 7 = 04:00, 8 = 06:00 85 5 = 01:00, 6 = 02:00, 7 = 04:00, 8 = 06:00
86 9 = 08:00, 10= 10:00, 11= 12:00, 12= 18:00, 86 9 = 08:00, 10= 10:00, 11= 12:00, 12= 18:00,
87 13= 24:00 */ 87 13= 24:00 */
88
89 int rec_prerecord_time; /* In seconds, 0-30, 0 means OFF */
88 90
89 /* device settings */ 91 /* device settings */
90 92
diff --git a/apps/sound_menu.c b/apps/sound_menu.c
index c5e254794e..557013df8a 100644
--- a/apps/sound_menu.c
+++ b/apps/sound_menu.c
@@ -241,6 +241,20 @@ static bool rectimesplit(void)
241 names, 14, NULL ); 241 names, 14, NULL );
242} 242}
243 243
244static bool recprerecord(void)
245{
246 char *names[] = {
247 str(LANG_OFF),"1s","2s", "3s", "4s", "5s", "6s", "7s", "8s", "9s",
248 "10s", "11s", "12s", "13s", "14s", "15s", "16s", "17s", "18s", "19s",
249 "20s", "21s", "22s", "23s", "24s", "25s", "26s", "27s", "28s", "29s",
250 "30s"
251 };
252
253 return set_option(str(LANG_RECORD_PRERECORD_TIME),
254 &global_settings.rec_prerecord_time, INT,
255 names, 31, NULL );
256}
257
244#endif /* HAVE_MAS3587F */ 258#endif /* HAVE_MAS3587F */
245 259
246static void set_chanconf(int val) 260static void set_chanconf(int val)
@@ -294,7 +308,7 @@ bool recording_menu(bool no_source)
294{ 308{
295 int m; 309 int m;
296 int i = 0; 310 int i = 0;
297 struct menu_items menu[6]; 311 struct menu_items menu[7];
298 bool result; 312 bool result;
299 313
300 menu[i].desc = str(LANG_RECORDING_QUALITY); 314 menu[i].desc = str(LANG_RECORDING_QUALITY);
@@ -311,6 +325,8 @@ bool recording_menu(bool no_source)
311 menu[i++].function = receditable; 325 menu[i++].function = receditable;
312 menu[i].desc = str(LANG_RECORD_TIMESPLIT); 326 menu[i].desc = str(LANG_RECORD_TIMESPLIT);
313 menu[i++].function = rectimesplit; 327 menu[i++].function = rectimesplit;
328 menu[i].desc = str(LANG_RECORD_PRERECORD_TIME);
329 menu[i++].function = recprerecord;
314 330
315 m=menu_init( menu, i ); 331 m=menu_init( menu, i );
316 result = menu_run(m); 332 result = menu_run(m);
diff --git a/firmware/export/mpeg.h b/firmware/export/mpeg.h
index 63eecf51db..bbace28ecd 100644
--- a/firmware/export/mpeg.h
+++ b/firmware/export/mpeg.h
@@ -32,6 +32,8 @@
32#define MPEG_PLAY_PENDING_THRESHOLD 0x10000 32#define MPEG_PLAY_PENDING_THRESHOLD 0x10000
33#define MPEG_PLAY_PENDING_SWAPSIZE 0x10000 33#define MPEG_PLAY_PENDING_SWAPSIZE 0x10000
34 34
35#define MPEG_MAX_PRERECORD_SECONDS 30
36
35/* For ID3 info and VBR header */ 37/* For ID3 info and VBR header */
36#define MPEG_RESERVED_HEADER_SPACE (4096 + 1500) 38#define MPEG_RESERVED_HEADER_SPACE (4096 + 1500)
37 39
@@ -89,7 +91,7 @@ void mpeg_record(char *filename);
89void mpeg_new_file(char *filename); 91void mpeg_new_file(char *filename);
90void mpeg_set_recording_options(int frequency, int quality, 92void mpeg_set_recording_options(int frequency, int quality,
91 int source, int channel_mode, 93 int source, int channel_mode,
92 bool editable); 94 bool editable, int prerecord_time);
93void mpeg_set_recording_gain(int left, int right, bool use_mic); 95void mpeg_set_recording_gain(int left, int right, bool use_mic);
94unsigned long mpeg_recorded_time(void); 96unsigned long mpeg_recorded_time(void);
95unsigned long mpeg_num_recorded_bytes(void); 97unsigned long mpeg_num_recorded_bytes(void);
@@ -123,7 +125,8 @@ void mpeg_error_clear(void);
123#define MPEG_STATUS_PLAY 1 125#define MPEG_STATUS_PLAY 1
124#define MPEG_STATUS_PAUSE 2 126#define MPEG_STATUS_PAUSE 2
125#define MPEG_STATUS_RECORD 4 127#define MPEG_STATUS_RECORD 4
126#define MPEG_STATUS_ERROR 8 128#define MPEG_STATUS_PRERECORD 8
129#define MPEG_STATUS_ERROR 16
127 130
128#define MPEGERR_DISK_FULL 1 131#define MPEGERR_DISK_FULL 1
129 132
diff --git a/firmware/mpeg.c b/firmware/mpeg.c
index 80e871597e..43da221800 100644
--- a/firmware/mpeg.c
+++ b/firmware/mpeg.c
@@ -44,6 +44,7 @@ extern void bitswap(unsigned char *data, int length);
44#ifdef HAVE_MAS3587F 44#ifdef HAVE_MAS3587F
45static void init_recording(void); 45static void init_recording(void);
46static void init_playback(void); 46static void init_playback(void);
47static void start_prerecording(void);
47static void start_recording(void); 48static void start_recording(void);
48static void stop_recording(void); 49static void stop_recording(void);
49static int get_unsaved_space(void); 50static int get_unsaved_space(void);
@@ -497,6 +498,17 @@ static char recording_filename[MAX_PATH];
497static int rec_frequency_index; /* For create_xing_header() calls */ 498static int rec_frequency_index; /* For create_xing_header() calls */
498static int rec_version_index; /* For create_xing_header() calls */ 499static int rec_version_index; /* For create_xing_header() calls */
499static bool disable_xing_header; /* When splitting files */ 500static bool disable_xing_header; /* When splitting files */
501
502static bool prerecording; /* True if prerecording is enabled */
503static bool is_prerecording; /* True if we are prerecording */
504static int prerecord_buffer[MPEG_MAX_PRERECORD_SECONDS]; /* Array of buffer
505 indexes for each
506 prerecorded
507 second */
508static int prerecord_index; /* Current index in the prerecord buffer */
509static int prerecording_max_seconds; /* Max number of seconds to store */
510static int prerecord_count; /* Number of seconds in the prerecord buffer */
511static int prerecord_timeout; /* The tick count of the next prerecord data store */
500#endif 512#endif
501 513
502static int mpeg_file; 514static int mpeg_file;
@@ -865,17 +877,38 @@ static void dma_tick(void)
865 877
866 num_rec_bytes += i; 878 num_rec_bytes += i;
867 879
868 /* Signal to save the data if we are running out of buffer 880 if(is_prerecording)
869 space */ 881 {
870 num_bytes = mp3buf_write - mp3buf_read; 882 if(TIME_AFTER(current_tick, prerecord_timeout))
871 if(num_bytes < 0) 883 {
872 num_bytes += mp3buflen; 884 prerecord_timeout = current_tick + HZ;
885
886 /* Store the write pointer every second */
887 prerecord_buffer[prerecord_index++] = mp3buf_write;
888
889 /* Wrap if necessary */
890 if(prerecord_index == prerecording_max_seconds)
891 prerecord_index = 0;
873 892
874 if(mp3buflen - num_bytes < MPEG_RECORDING_LOW_WATER && !saving) 893 /* Update the number of seconds recorded */
894 if(prerecord_count < prerecording_max_seconds)
895 prerecord_count++;
896 }
897 }
898 else
875 { 899 {
876 saving = true; 900 /* Signal to save the data if we are running out of buffer
877 queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); 901 space */
878 wake_up_thread(); 902 num_bytes = mp3buf_write - mp3buf_read;
903 if(num_bytes < 0)
904 num_bytes += mp3buflen;
905
906 if(mp3buflen - num_bytes < MPEG_RECORDING_LOW_WATER && !saving)
907 {
908 saving = true;
909 queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
910 wake_up_thread();
911 }
879 } 912 }
880 } 913 }
881 } 914 }
@@ -1887,20 +1920,84 @@ static void mpeg_thread(void)
1887 switch(ev.id) 1920 switch(ev.id)
1888 { 1921 {
1889 case MPEG_RECORD: 1922 case MPEG_RECORD:
1890 DEBUGF("Recording...\n"); 1923 if(is_prerecording)
1891 reset_mp3_buffer(); 1924 {
1925 int startpos, i;
1926
1927 /* Go back prerecord_count seconds in the buffer */
1928 startpos = prerecord_index - prerecord_count;
1929 if(startpos < 0)
1930 startpos += prerecording_max_seconds;
1931
1932 /* Read the mp3 buffer pointer from the prerecord buffer */
1933 startpos = prerecord_buffer[startpos];
1934
1935 DEBUGF("Start looking at address %x (%x)\n",
1936 mp3buf+startpos, startpos);
1937
1938 saved_header = get_last_recorded_header();
1939
1940 mem_find_next_frame(startpos, &offset, 5000,
1941 saved_header);
1942
1943 mp3buf_read = startpos + offset;
1944
1945 DEBUGF("New mp3buf_read address: %x (%x)\n",
1946 mp3buf+mp3buf_read, mp3buf_read);
1892 1947
1893 /* Advance the write pointer to make 1948 /* Make room for headers */
1894 room for an ID3 tag plus a VBR header */ 1949 mp3buf_read -= MPEG_RESERVED_HEADER_SPACE;
1895 mp3buf_write = MPEG_RESERVED_HEADER_SPACE; 1950 if(mp3buf_read < 0)
1896 memset(mp3buf, 0, MPEG_RESERVED_HEADER_SPACE); 1951 {
1952 /* Clear the bottom half */
1953 memset(mp3buf, 0,
1954 mp3buf_read + MPEG_RESERVED_HEADER_SPACE);
1897 1955
1898 /* Insert the ID3 header */ 1956 /* And the top half */
1899 memcpy(mp3buf, empty_id3_header, sizeof(empty_id3_header)); 1957 mp3buf_read += mp3buflen;
1958 memset(mp3buf + mp3buf_read, 0,
1959 mp3buflen - mp3buf_read);
1960 }
1961 else
1962 {
1963 memset(mp3buf + mp3buf_read, 0,
1964 MPEG_RESERVED_HEADER_SPACE);
1965 }
1966
1967 /* Copy the empty ID3 header */
1968 startpos = mp3buf_read;
1969 for(i = 0;i < (int)sizeof(empty_id3_header);i++)
1970 {
1971 mp3buf[startpos++] = empty_id3_header[i];
1972 if(startpos == mp3buflen)
1973 startpos = 0;
1974 }
1975
1976 DEBUGF("New mp3buf_read address (reservation): %x\n",
1977 mp3buf+mp3buf_read);
1978
1979 DEBUGF("Prerecording...\n");
1980 }
1981 else
1982 {
1983 reset_mp3_buffer();
1984
1985 num_rec_bytes = 0;
1986
1987 /* Advance the write pointer to make
1988 room for an ID3 tag plus a VBR header */
1989 mp3buf_write = MPEG_RESERVED_HEADER_SPACE;
1990 memset(mp3buf, 0, MPEG_RESERVED_HEADER_SPACE);
1991
1992 /* Insert the ID3 header */
1993 memcpy(mp3buf, empty_id3_header,
1994 sizeof(empty_id3_header));
1995
1996 DEBUGF("Recording...\n");
1997 }
1900 1998
1901 start_recording(); 1999 start_recording();
1902 demand_irq_enable(true); 2000
1903
1904 mpeg_file = open(recording_filename, O_WRONLY|O_CREAT); 2001 mpeg_file = open(recording_filename, O_WRONLY|O_CREAT);
1905 2002
1906 if(mpeg_file < 0) 2003 if(mpeg_file < 0)
@@ -1910,14 +2007,13 @@ static void mpeg_thread(void)
1910 2007
1911 case MPEG_STOP: 2008 case MPEG_STOP:
1912 DEBUGF("MPEG_STOP\n"); 2009 DEBUGF("MPEG_STOP\n");
1913 demand_irq_enable(false);
1914 2010
1915 /* Store the last recorded header for later use by the 2011 /* Store the last recorded header for later use by the
1916 Xing header generation */ 2012 Xing header generation */
1917 saved_header = get_last_recorded_header(); 2013 saved_header = get_last_recorded_header();
1918 2014
1919 stop_recording(); 2015 stop_recording();
1920 2016
1921 /* Save the remaining data in the buffer */ 2017 /* Save the remaining data in the buffer */
1922 stop_pending = true; 2018 stop_pending = true;
1923 queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); 2019 queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
@@ -1942,6 +2038,11 @@ static void mpeg_thread(void)
1942 if(num_recorded_frames == 0x7ffff) 2038 if(num_recorded_frames == 0x7ffff)
1943 num_recorded_frames = 0; 2039 num_recorded_frames = 0;
1944 2040
2041 /* Also, if we have been prerecording, the frame count
2042 will be wrong */
2043 if(prerecording)
2044 num_recorded_frames = 0;
2045
1945 /* saved_header is saved right before stopping 2046 /* saved_header is saved right before stopping
1946 the MAS */ 2047 the MAS */
1947 framelen = create_xing_header(mpeg_file, 0, 2048 framelen = create_xing_header(mpeg_file, 0,
@@ -1970,6 +2071,11 @@ static void mpeg_thread(void)
1970 } 2071 }
1971 } 2072 }
1972#endif 2073#endif
2074
2075 if(prerecording)
2076 {
2077 start_prerecording();
2078 }
1973 mpeg_stop_done = true; 2079 mpeg_stop_done = true;
1974 break; 2080 break;
1975 2081
@@ -2117,7 +2223,6 @@ static void mpeg_thread(void)
2117 if(errno == ENOSPC) 2223 if(errno == ENOSPC)
2118 { 2224 {
2119 mpeg_errno = MPEGERR_DISK_FULL; 2225 mpeg_errno = MPEGERR_DISK_FULL;
2120 demand_irq_enable(false);
2121 stop_recording(); 2226 stop_recording();
2122 queue_post(&mpeg_queue, MPEG_STOP_DONE, 0); 2227 queue_post(&mpeg_queue, MPEG_STOP_DONE, 0);
2123 break; 2228 break;
@@ -2161,18 +2266,22 @@ static void mpeg_thread(void)
2161 break; 2266 break;
2162 2267
2163 case SYS_USB_CONNECTED: 2268 case SYS_USB_CONNECTED:
2164 is_playing = false; 2269 /* We can safely go to USB mode if no recording
2165 paused = false; 2270 is taking place */
2166 stop_playing(); 2271 if((!is_recording || is_prerecording) && mpeg_stop_done)
2167#ifndef SIMULATOR 2272 {
2273 /* Even if we aren't recording, we still call this
2274 function, to put the MAS in monitoring mode,
2275 to save power. */
2276 stop_recording();
2168 2277
2169 /* Tell the USB thread that we are safe */ 2278 /* Tell the USB thread that we are safe */
2170 DEBUGF("mpeg_thread got SYS_USB_CONNECTED\n"); 2279 DEBUGF("mpeg_thread got SYS_USB_CONNECTED\n");
2171 usb_acknowledge(SYS_USB_CONNECTED_ACK); 2280 usb_acknowledge(SYS_USB_CONNECTED_ACK);
2172 2281
2173 /* Wait until the USB cable is extracted again */ 2282 /* Wait until the USB cable is extracted again */
2174 usb_wait_for_disconnect(&mpeg_queue); 2283 usb_wait_for_disconnect(&mpeg_queue);
2175#endif 2284 }
2176 break; 2285 break;
2177 } 2286 }
2178 } 2287 }
@@ -2245,22 +2354,90 @@ bool mpeg_has_changed_track(void)
2245} 2354}
2246 2355
2247#ifdef HAVE_MAS3587F 2356#ifdef HAVE_MAS3587F
2248void mpeg_init_recording(void) 2357void mpeg_init_playback(void)
2249{ 2358{
2250 init_recording_done = false; 2359 init_playback_done = false;
2251 queue_post(&mpeg_queue, MPEG_INIT_RECORDING, NULL); 2360 queue_post(&mpeg_queue, MPEG_INIT_PLAYBACK, NULL);
2252 2361
2253 while(!init_recording_done) 2362 while(!init_playback_done)
2254 sleep_thread(); 2363 sleep_thread();
2255 wake_up_thread(); 2364 wake_up_thread();
2256} 2365}
2257 2366
2258void mpeg_init_playback(void) 2367static void init_playback(void)
2259{ 2368{
2260 init_playback_done = false; 2369 unsigned long val;
2261 queue_post(&mpeg_queue, MPEG_INIT_PLAYBACK, NULL); 2370 int rc;
2262 2371
2263 while(!init_playback_done) 2372 if(mpeg_mode == MPEG_ENCODER)
2373 stop_recording();
2374
2375 stop_dma();
2376
2377 mas_reset();
2378
2379 /* Enable the audio CODEC and the DSP core, max analog voltage range */
2380 rc = mas_direct_config_write(MAS_CONTROL, 0x8c00);
2381 if(rc < 0)
2382 panicf("mas_ctrl_w: %d", rc);
2383
2384 /* Stop the current application */
2385 val = 0;
2386 mas_writemem(MAS_BANK_D0,0x7f6,&val,1);
2387 do
2388 {
2389 mas_readmem(MAS_BANK_D0, 0x7f7, &val, 1);
2390 } while(val);
2391
2392 /* Enable the D/A Converter */
2393 mas_codec_writereg(0x0, 0x0001);
2394
2395 /* ADC scale 0%, DSP scale 100% */
2396 mas_codec_writereg(6, 0x0000);
2397 mas_codec_writereg(7, 0x4000);
2398
2399 /* Disable SDO and SDI */
2400 val = 0x0d;
2401 mas_writemem(MAS_BANK_D0,0x7f2,&val,1);
2402
2403 /* Set Demand mode and validate all settings */
2404 val = 0x25;
2405 mas_writemem(MAS_BANK_D0,0x7f1,&val,1);
2406
2407 /* Start the Layer2/3 decoder applications */
2408 val = 0x0c;
2409 mas_writemem(MAS_BANK_D0,0x7f6,&val,1);
2410 do
2411 {
2412 mas_readmem(MAS_BANK_D0, 0x7f7, &val, 1);
2413 } while((val & 0x0c) != 0x0c);
2414
2415 mpeg_sound_channel_config(MPEG_SOUND_STEREO);
2416
2417 mpeg_mode = MPEG_DECODER;
2418
2419 /* set IRQ6 to edge detect */
2420 ICR |= 0x02;
2421
2422 /* set IRQ6 prio 8 */
2423 IPRB = ( IPRB & 0xff0f ) | 0x0080;
2424
2425 DEBUGF("MAS Decoding application started\n");
2426}
2427
2428/****************************************************************************
2429 **
2430 **
2431 ** Recording functions
2432 **
2433 **
2434 ***************************************************************************/
2435void mpeg_init_recording(void)
2436{
2437 init_recording_done = false;
2438 queue_post(&mpeg_queue, MPEG_INIT_RECORDING, NULL);
2439
2440 while(!init_recording_done)
2264 sleep_thread(); 2441 sleep_thread();
2265 wake_up_thread(); 2442 wake_up_thread();
2266} 2443}
@@ -2270,6 +2447,9 @@ static void init_recording(void)
2270 unsigned long val; 2447 unsigned long val;
2271 int rc; 2448 int rc;
2272 2449
2450 /* Disable IRQ6 */
2451 IPRB &= 0xff0f;
2452
2273 stop_playing(); 2453 stop_playing();
2274 is_playing = false; 2454 is_playing = false;
2275 paused = false; 2455 paused = false;
@@ -2283,6 +2463,9 @@ static void init_recording(void)
2283 2463
2284 /* Init the recording variables */ 2464 /* Init the recording variables */
2285 is_recording = false; 2465 is_recording = false;
2466 is_prerecording = false;
2467
2468 mpeg_stop_done = true;
2286 2469
2287 mas_reset(); 2470 mas_reset();
2288 2471
@@ -2324,7 +2507,7 @@ static void init_recording(void)
2324 2507
2325 /* No mute */ 2508 /* No mute */
2326 val = 0; 2509 val = 0;
2327 mas_writemem(MAS_BANK_D0, 0x7f9, &val, 1); 2510 mas_writemem(MAS_BANK_D0, 0x7f9, &val, 1);
2328 2511
2329 /* Set Demand mode, no monitoring and validate all settings */ 2512 /* Set Demand mode, no monitoring and validate all settings */
2330 val = 0x125; 2513 val = 0x125;
@@ -2345,70 +2528,16 @@ static void init_recording(void)
2345 Now let's wait for some data to be encoded. */ 2528 Now let's wait for some data to be encoded. */
2346 sleep(20); 2529 sleep(20);
2347 2530
2348 /* Disable IRQ6 */ 2531 /* Now set it to Monitoring mode as default, saves power */
2349 IPRB &= 0xff0f; 2532 val = 0x525;
2533 mas_writemem(MAS_BANK_D0, 0x7f1, &val, 1);
2350 2534
2351 mpeg_mode = MPEG_ENCODER; 2535 mpeg_mode = MPEG_ENCODER;
2352 2536
2353 DEBUGF("MAS Recording application started\n"); 2537 DEBUGF("MAS Recording application started\n");
2354}
2355
2356static void init_playback(void)
2357{
2358 unsigned long val;
2359 int rc;
2360
2361 stop_dma();
2362
2363 mas_reset();
2364
2365 /* Enable the audio CODEC and the DSP core, max analog voltage range */
2366 rc = mas_direct_config_write(MAS_CONTROL, 0x8c00);
2367 if(rc < 0)
2368 panicf("mas_ctrl_w: %d", rc);
2369
2370 /* Stop the current application */
2371 val = 0;
2372 mas_writemem(MAS_BANK_D0,0x7f6,&val,1);
2373 do
2374 {
2375 mas_readmem(MAS_BANK_D0, 0x7f7, &val, 1);
2376 } while(val);
2377
2378 /* Enable the D/A Converter */
2379 mas_codec_writereg(0x0, 0x0001);
2380
2381 /* ADC scale 0%, DSP scale 100% */
2382 mas_codec_writereg(6, 0x0000);
2383 mas_codec_writereg(7, 0x4000);
2384
2385 /* Disable SDO and SDI */
2386 val = 0x0d;
2387 mas_writemem(MAS_BANK_D0,0x7f2,&val,1);
2388
2389 /* Set Demand mode and validate all settings */
2390 val = 0x25;
2391 mas_writemem(MAS_BANK_D0,0x7f1,&val,1);
2392
2393 /* Start the Layer2/3 decoder applications */
2394 val = 0x0c;
2395 mas_writemem(MAS_BANK_D0,0x7f6,&val,1);
2396 do
2397 {
2398 mas_readmem(MAS_BANK_D0, 0x7f7, &val, 1);
2399 } while((val & 0x0c) != 0x0c);
2400
2401 mpeg_sound_channel_config(MPEG_SOUND_STEREO);
2402
2403 mpeg_mode = MPEG_DECODER;
2404
2405 /* set IRQ6 to edge detect */
2406 ICR |= 0x02;
2407
2408 /* set IRQ6 prio 8 */
2409 IPRB = ( IPRB & 0xff0f ) | 0x0080;
2410 2538
2411 DEBUGF("MAS Decoding application started\n"); 2539 /* At this point, all settings are the reset MAS defaults, next thing is to
2540 call mpeg_set_recording_options(). */
2412} 2541}
2413 2542
2414void mpeg_record(char *filename) 2543void mpeg_record(char *filename)
@@ -2418,53 +2547,109 @@ void mpeg_record(char *filename)
2418 strncpy(recording_filename, filename, MAX_PATH - 1); 2547 strncpy(recording_filename, filename, MAX_PATH - 1);
2419 recording_filename[MAX_PATH - 1] = 0; 2548 recording_filename[MAX_PATH - 1] = 0;
2420 2549
2421 num_rec_bytes = 0;
2422 disable_xing_header = false; 2550 disable_xing_header = false;
2423 queue_post(&mpeg_queue, MPEG_RECORD, NULL); 2551 queue_post(&mpeg_queue, MPEG_RECORD, NULL);
2424} 2552}
2425 2553
2426static void start_recording(void) 2554static void start_prerecording(void)
2427{ 2555{
2428 unsigned long val; 2556 unsigned long val;
2429 2557
2430 num_recorded_frames = 0; 2558 DEBUGF("Starting prerecording\n");
2431 2559
2432 /* Stop monitoring and record for real */ 2560 prerecord_index = 0;
2561 prerecord_count = 0;
2562 prerecord_timeout = current_tick + HZ;
2563 memset(prerecord_buffer, 0, sizeof(prerecord_buffer));
2564 reset_mp3_buffer();
2565
2566 is_prerecording = true;
2567
2568 /* Stop monitoring and start the encoder */
2433 mas_readmem(MAS_BANK_D0, 0x7f1, &val, 1); 2569 mas_readmem(MAS_BANK_D0, 0x7f1, &val, 1);
2434 val &= ~(1 << 10); 2570 val &= ~(1 << 10);
2435 val |= 1; 2571 val |= 1;
2436 mas_writemem(MAS_BANK_D0, 0x7f1, &val, 1); 2572 mas_writemem(MAS_BANK_D0, 0x7f1, &val, 1);
2573 DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f1, %x)\n", val);
2437 2574
2438 /* Wait until the DSP has accepted the settings */ 2575 /* Wait until the DSP has accepted the settings */
2439 do 2576 do
2440 { 2577 {
2441 mas_readmem(MAS_BANK_D0, 0x7f1, &val,1); 2578 mas_readmem(MAS_BANK_D0, 0x7f1, &val,1);
2442 } while(val & 1); 2579 } while(val & 1);
2443
2444 sleep(20);
2445 2580
2446 /* Store the current time */ 2581 sleep(20);
2447 record_start_time = current_tick;
2448 2582
2449 is_recording = true; 2583 is_recording = true;
2450 stop_pending = false; 2584 stop_pending = false;
2451 saving = false; 2585 saving = false;
2586
2587 demand_irq_enable(true);
2588}
2589
2590static void start_recording(void)
2591{
2592 unsigned long val;
2593
2594 num_recorded_frames = 0;
2595
2596 if(is_prerecording)
2597 {
2598 /* This will make the IRQ handler start recording
2599 for real, i.e send MPEG_SAVE_DATA messages when
2600 the buffer is full */
2601 is_prerecording = false;
2602 }
2603 else
2604 {
2605 /* If prerecording is off, we need to stop the monitoring
2606 and start the encoder */
2607 mas_readmem(MAS_BANK_D0, 0x7f1, &val, 1);
2608 val &= ~(1 << 10);
2609 val |= 1;
2610 mas_writemem(MAS_BANK_D0, 0x7f1, &val, 1);
2611 DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f1, %x)\n", val);
2612
2613 /* Wait until the DSP has accepted the settings */
2614 do
2615 {
2616 mas_readmem(MAS_BANK_D0, 0x7f1, &val,1);
2617 } while(val & 1);
2618
2619 sleep(20);
2620 }
2621
2622 is_recording = true;
2623 stop_pending = false;
2624 saving = false;
2625
2626 /* Store the current time */
2627 if(prerecording)
2628 record_start_time = current_tick - prerecord_count * HZ;
2629 else
2630 record_start_time = current_tick;
2631
2632 demand_irq_enable(true);
2452} 2633}
2453 2634
2454static void stop_recording(void) 2635static void stop_recording(void)
2455{ 2636{
2456 unsigned long val; 2637 unsigned long val;
2457 2638
2458 is_recording = false; 2639 demand_irq_enable(false);
2459 2640
2641 is_recording = false;
2642 is_prerecording = false;
2643
2460 /* Read the number of frames recorded */ 2644 /* Read the number of frames recorded */
2461 mas_readmem(MAS_BANK_D0, 0xfd0, &num_recorded_frames, 1); 2645 mas_readmem(MAS_BANK_D0, 0xfd0, &num_recorded_frames, 1);
2462 2646
2463 /* Start monitoring */ 2647 /* Start monitoring */
2464 mas_readmem(MAS_BANK_D0, 0x7f1, &val, 1); 2648 mas_readmem(MAS_BANK_D0, 0x7f1, &val, 1);
2465 val |= (1 << 10) | 1; 2649 val |= (1 << 10) | 1;
2466 mas_writemem(MAS_BANK_D0, 0x7f1, &val, 1); 2650 mas_writemem(MAS_BANK_D0, 0x7f1, &val, 1);
2467 2651 DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f1, %x)\n", val);
2652
2468 /* Wait until the DSP has accepted the settings */ 2653 /* Wait until the DSP has accepted the settings */
2469 do 2654 do
2470 { 2655 {
@@ -2474,6 +2659,82 @@ static void stop_recording(void)
2474 drain_dma_buffer(); 2659 drain_dma_buffer();
2475} 2660}
2476 2661
2662void mpeg_set_recording_options(int frequency, int quality,
2663 int source, int channel_mode,
2664 bool editable, int prerecord_time)
2665{
2666 bool is_mpeg1;
2667 unsigned long val;
2668
2669 is_mpeg1 = (frequency < 3)?true:false;
2670
2671 rec_version_index = is_mpeg1?3:2;
2672 rec_frequency_index = frequency % 3;
2673
2674 val = (quality << 17) |
2675 (rec_frequency_index << 10) |
2676 ((is_mpeg1?1:0) << 9) |
2677 (1 << 8) | /* CRC on */
2678 (((channel_mode * 2 + 1) & 3) << 6) |
2679 (1 << 5) /* MS-stereo */ |
2680 (1 << 2) /* Is an original */;
2681 mas_writemem(MAS_BANK_D0, 0x7f0, &val,1);
2682
2683 DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f0, %x)\n", val);
2684
2685 val = editable?4:0;
2686 mas_writemem(MAS_BANK_D0, 0x7f9, &val,1);
2687
2688 DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f9, %x)\n", val);
2689
2690 val = (((source < 2)?1:2) << 8) | /* Input select */
2691 (1 << 5) | /* SDO strobe invert */
2692 ((is_mpeg1?0:1) << 3) |
2693 (1 << 2) | /* Inverted SIBC clock signal */
2694 1; /* Validate */
2695 mas_writemem(MAS_BANK_D0, 0x7f1, &val,1);
2696
2697 DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f1, %x)\n", val);
2698
2699 drain_dma_buffer();
2700
2701 if(source == 0) /* Mic */
2702 {
2703 /* Copy left channel to right (mono mode) */
2704 mas_codec_writereg(8, 0x8000);
2705 }
2706 else
2707 {
2708 /* Stereo input mode */
2709 mas_codec_writereg(8, 0);
2710 }
2711
2712 prerecording_max_seconds = prerecord_time;
2713 if(prerecording_max_seconds)
2714 {
2715 prerecording = true;
2716 start_prerecording();
2717 }
2718 else
2719 {
2720 prerecording = false;
2721 is_prerecording = false;
2722 is_recording = false;
2723 }
2724}
2725
2726/* If use_mic is true, the left gain is used */
2727void mpeg_set_recording_gain(int left, int right, bool use_mic)
2728{
2729 /* Enable both left and right A/D */
2730 mas_codec_writereg(0x0,
2731 (left << 12) |
2732 (right << 8) |
2733 (left << 4) |
2734 (use_mic?0x0008:0) | /* Connect left A/D to mic */
2735 0x0007);
2736}
2737
2477void mpeg_new_file(char *filename) 2738void mpeg_new_file(char *filename)
2478{ 2739{
2479 mpeg_errno = 0; 2740 mpeg_errno = 0;
@@ -2492,16 +2753,37 @@ void mpeg_new_file(char *filename)
2492 2753
2493unsigned long mpeg_recorded_time(void) 2754unsigned long mpeg_recorded_time(void)
2494{ 2755{
2756 if(is_prerecording)
2757 return prerecord_count * HZ;
2758
2495 if(is_recording) 2759 if(is_recording)
2496 return current_tick - record_start_time; 2760 return current_tick - record_start_time;
2497 else 2761
2498 return 0; 2762 return 0;
2499} 2763}
2500 2764
2501unsigned long mpeg_num_recorded_bytes(void) 2765unsigned long mpeg_num_recorded_bytes(void)
2502{ 2766{
2767 int num_bytes;
2768 int index;
2769
2503 if(is_recording) 2770 if(is_recording)
2504 return num_rec_bytes; 2771 {
2772 if(is_prerecording)
2773 {
2774 index = prerecord_index - prerecord_count;
2775 if(index < 0)
2776 index += prerecording_max_seconds;
2777
2778 num_bytes = mp3buf_write - prerecord_buffer[index];
2779 if(num_bytes < 0)
2780 num_bytes += mp3buflen;
2781
2782 return num_bytes;;
2783 }
2784 else
2785 return num_rec_bytes;
2786 }
2505 else 2787 else
2506 return 0; 2788 return 0;
2507} 2789}
@@ -2660,8 +2942,11 @@ int mpeg_status(void)
2660 ret |= MPEG_STATUS_PAUSE; 2942 ret |= MPEG_STATUS_PAUSE;
2661 2943
2662#ifdef HAVE_MAS3587F 2944#ifdef HAVE_MAS3587F
2663 if(is_recording) 2945 if(is_recording && !is_prerecording)
2664 ret |= MPEG_STATUS_RECORD; 2946 ret |= MPEG_STATUS_RECORD;
2947
2948 if(is_prerecording)
2949 ret |= MPEG_STATUS_PRERECORD;
2665#endif 2950#endif
2666 2951
2667 if(mpeg_errno) 2952 if(mpeg_errno)
@@ -3057,73 +3342,6 @@ void mpeg_set_pitch(int pitch)
3057} 3342}
3058#endif 3343#endif
3059 3344
3060#ifdef HAVE_MAS3587F
3061void mpeg_set_recording_options(int frequency, int quality,
3062 int source, int channel_mode,
3063 bool editable)
3064{
3065 bool is_mpeg1;
3066 unsigned long val;
3067
3068 is_mpeg1 = (frequency < 3)?true:false;
3069
3070 rec_version_index = is_mpeg1?3:2;
3071 rec_frequency_index = frequency % 3;
3072
3073 val = (quality << 17) |
3074 (rec_frequency_index << 10) |
3075 ((is_mpeg1?1:0) << 9) |
3076 (1 << 8) | /* CRC on */
3077 (((channel_mode * 2 + 1) & 3) << 6) |
3078 (1 << 5) /* MS-stereo */ |
3079 (1 << 2) /* Is an original */;
3080 mas_writemem(MAS_BANK_D0, 0x7f0, &val,1);
3081
3082 DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f0, %x)\n", val);
3083
3084 val = editable?4:0;
3085 mas_writemem(MAS_BANK_D0, 0x7f9, &val,1);
3086
3087 DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f9, %x)\n", val);
3088
3089 val = ((!is_recording << 10) | /* Monitoring */
3090 ((source < 2)?1:2) << 8) | /* Input select */
3091 (1 << 5) | /* SDO strobe invert */
3092 ((is_mpeg1?0:1) << 3) |
3093 (1 << 2) | /* Inverted SIBC clock signal */
3094 1; /* Validate */
3095 mas_writemem(MAS_BANK_D0, 0x7f1, &val,1);
3096
3097 DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f1, %x)\n", val);
3098
3099 drain_dma_buffer();
3100
3101 if(source == 0) /* Mic */
3102 {
3103 /* Copy left channel to right (mono mode) */
3104 mas_codec_writereg(8, 0x8000);
3105 }
3106 else
3107 {
3108 /* Stereo input mode */
3109 mas_codec_writereg(8, 0);
3110 }
3111}
3112
3113/* If use_mic is true, the left gain is used */
3114void mpeg_set_recording_gain(int left, int right, bool use_mic)
3115{
3116 /* Enable both left and right A/D */
3117 mas_codec_writereg(0x0,
3118 (left << 12) |
3119 (right << 8) |
3120 (left << 4) |
3121 (use_mic?0x0008:0) | /* Connect left A/D to mic */
3122 0x0007);
3123}
3124
3125#endif
3126
3127#ifdef SIMULATOR 3345#ifdef SIMULATOR
3128static char mpeg_stack[DEFAULT_STACK_SIZE]; 3346static char mpeg_stack[DEFAULT_STACK_SIZE];
3129static char mpeg_thread_name[] = "mpeg"; 3347static char mpeg_thread_name[] = "mpeg";