New recording feature: Prerecord up to 30 seconds before you press the Play key. Especially useful for FM radio recording. Also fixed a bug which didn't apply the recording settings correctly in the Radio screen.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4183 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
1c4ea83bba
commit
74976c1484
8 changed files with 565 additions and 284 deletions
|
@ -1847,3 +1847,13 @@ id: LANG_FLIP_DISPLAY
|
||||||
desc: in settings_menu, option to turn display+buttos by 180 degreed
|
desc: in settings_menu, option to turn display+buttos by 180 degreed
|
||||||
eng: "Upside Down"
|
eng: "Upside Down"
|
||||||
new:
|
new:
|
||||||
|
|
||||||
|
id: LANG_RECORD_PRERECORD
|
||||||
|
desc: in recording and radio screen
|
||||||
|
eng: "Prerecording"
|
||||||
|
new:
|
||||||
|
|
||||||
|
id: LANG_RECORD_PRERECORD_TIME
|
||||||
|
desc: in recording settings_menu
|
||||||
|
eng: "Prerecord time"
|
||||||
|
new:
|
||||||
|
|
|
@ -172,9 +172,10 @@ bool radio_screen(void)
|
||||||
|
|
||||||
mpeg_set_recording_options(global_settings.rec_frequency,
|
mpeg_set_recording_options(global_settings.rec_frequency,
|
||||||
global_settings.rec_quality,
|
global_settings.rec_quality,
|
||||||
1 /* Line In */,
|
1, /* Line In */
|
||||||
global_settings.rec_channels,
|
global_settings.rec_channels,
|
||||||
global_settings.rec_editable);
|
global_settings.rec_editable,
|
||||||
|
global_settings.rec_prerecord_time);
|
||||||
|
|
||||||
|
|
||||||
mpeg_set_recording_gain(mpeg_sound_default(SOUND_LEFT_GAIN),
|
mpeg_set_recording_gain(mpeg_sound_default(SOUND_LEFT_GAIN),
|
||||||
|
@ -230,7 +231,7 @@ bool radio_screen(void)
|
||||||
switch(button)
|
switch(button)
|
||||||
{
|
{
|
||||||
case BUTTON_OFF:
|
case BUTTON_OFF:
|
||||||
if(mpeg_status())
|
if(mpeg_status() == MPEG_STATUS_RECORD)
|
||||||
{
|
{
|
||||||
mpeg_stop();
|
mpeg_stop();
|
||||||
status_set_playmode(STATUS_STOP);
|
status_set_playmode(STATUS_STOP);
|
||||||
|
@ -244,17 +245,16 @@ bool radio_screen(void)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BUTTON_F3:
|
case BUTTON_F3:
|
||||||
/* Only act if the mpeg is stopped */
|
if(mpeg_status() == MPEG_STATUS_RECORD)
|
||||||
if(!mpeg_status())
|
|
||||||
{
|
{
|
||||||
have_recorded = true;
|
mpeg_new_file(rec_create_filename());
|
||||||
mpeg_record(rec_create_filename());
|
|
||||||
status_set_playmode(STATUS_RECORD);
|
|
||||||
update_screen = true;
|
update_screen = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mpeg_new_file(rec_create_filename());
|
have_recorded = true;
|
||||||
|
mpeg_record(rec_create_filename());
|
||||||
|
status_set_playmode(STATUS_RECORD);
|
||||||
update_screen = true;
|
update_screen = true;
|
||||||
}
|
}
|
||||||
last_seconds = 0;
|
last_seconds = 0;
|
||||||
|
@ -353,11 +353,12 @@ bool radio_screen(void)
|
||||||
|
|
||||||
case SYS_USB_CONNECTED:
|
case SYS_USB_CONNECTED:
|
||||||
/* Only accept USB connection when not recording */
|
/* Only accept USB connection when not recording */
|
||||||
if(!mpeg_status())
|
if(mpeg_status() != MPEG_STATUS_RECORD)
|
||||||
{
|
{
|
||||||
usb_screen();
|
usb_screen();
|
||||||
fmradio_set_status(0);
|
fmradio_set_status(0);
|
||||||
have_recorded = true; /* Refreshes the browser later on */
|
screen_freeze = true; /* Cosmetic: makes sure the
|
||||||
|
radio screen doesn't redraw */
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -368,6 +369,8 @@ bool radio_screen(void)
|
||||||
if(!screen_freeze)
|
if(!screen_freeze)
|
||||||
{
|
{
|
||||||
lcd_setmargins(0, 8);
|
lcd_setmargins(0, 8);
|
||||||
|
|
||||||
|
/* Only display the peak meter when not recording */
|
||||||
if(!mpeg_status())
|
if(!mpeg_status())
|
||||||
{
|
{
|
||||||
lcd_clearrect(0, 8 + fh*(top_of_screen + 3), LCD_WIDTH, fh);
|
lcd_clearrect(0, 8 + fh*(top_of_screen + 3), LCD_WIDTH, fh);
|
||||||
|
@ -415,7 +418,7 @@ bool radio_screen(void)
|
||||||
str(LANG_CHANNEL_MONO));
|
str(LANG_CHANNEL_MONO));
|
||||||
lcd_puts(0, top_of_screen + 2, buf);
|
lcd_puts(0, top_of_screen + 2, buf);
|
||||||
|
|
||||||
if(mpeg_status())
|
if(mpeg_status() == MPEG_STATUS_RECORD)
|
||||||
{
|
{
|
||||||
hours = seconds / 3600;
|
hours = seconds / 3600;
|
||||||
minutes = (seconds - (hours * 3600)) / 60;
|
minutes = (seconds - (hours * 3600)) / 60;
|
||||||
|
@ -424,6 +427,12 @@ bool radio_screen(void)
|
||||||
hours, minutes, seconds%60);
|
hours, minutes, seconds%60);
|
||||||
lcd_puts(0, top_of_screen + 3, buf);
|
lcd_puts(0, top_of_screen + 3, buf);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
snprintf(buf, 32, "%s %02d",
|
||||||
|
str(LANG_RECORD_PRERECORD), seconds%60);
|
||||||
|
lcd_puts(0, top_of_screen + 3, buf);
|
||||||
|
}
|
||||||
|
|
||||||
/* Only force the redraw if update_screen is true */
|
/* Only force the redraw if update_screen is true */
|
||||||
status_draw(update_screen);
|
status_draw(update_screen);
|
||||||
|
@ -687,7 +696,19 @@ bool radio_delete_preset(void)
|
||||||
|
|
||||||
static bool fm_recording_settings(void)
|
static bool fm_recording_settings(void)
|
||||||
{
|
{
|
||||||
return recording_menu(true);
|
bool ret;
|
||||||
|
|
||||||
|
ret = recording_menu(true);
|
||||||
|
if(!ret)
|
||||||
|
{
|
||||||
|
mpeg_set_recording_options(global_settings.rec_frequency,
|
||||||
|
global_settings.rec_quality,
|
||||||
|
1, /* Line In */
|
||||||
|
global_settings.rec_channels,
|
||||||
|
global_settings.rec_editable,
|
||||||
|
global_settings.rec_prerecord_time);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool radio_menu(void)
|
bool radio_menu(void)
|
||||||
|
|
|
@ -160,7 +160,8 @@ bool recording_screen(void)
|
||||||
global_settings.rec_quality,
|
global_settings.rec_quality,
|
||||||
global_settings.rec_source,
|
global_settings.rec_source,
|
||||||
global_settings.rec_channels,
|
global_settings.rec_channels,
|
||||||
global_settings.rec_editable);
|
global_settings.rec_editable,
|
||||||
|
global_settings.rec_prerecord_time);
|
||||||
|
|
||||||
set_gain();
|
set_gain();
|
||||||
|
|
||||||
|
@ -174,7 +175,7 @@ bool recording_screen(void)
|
||||||
switch(button)
|
switch(button)
|
||||||
{
|
{
|
||||||
case BUTTON_OFF:
|
case BUTTON_OFF:
|
||||||
if(mpeg_status())
|
if(mpeg_status() & MPEG_STATUS_RECORD)
|
||||||
{
|
{
|
||||||
mpeg_stop();
|
mpeg_stop();
|
||||||
status_set_playmode(STATUS_STOP);
|
status_set_playmode(STATUS_STOP);
|
||||||
|
@ -190,7 +191,7 @@ bool recording_screen(void)
|
||||||
|
|
||||||
case BUTTON_PLAY:
|
case BUTTON_PLAY:
|
||||||
/* Only act if the mpeg is stopped */
|
/* Only act if the mpeg is stopped */
|
||||||
if(!mpeg_status())
|
if(!(mpeg_status() & MPEG_STATUS_RECORD))
|
||||||
{
|
{
|
||||||
have_recorded = true;
|
have_recorded = true;
|
||||||
mpeg_record(rec_create_filename());
|
mpeg_record(rec_create_filename());
|
||||||
|
@ -305,13 +306,16 @@ bool recording_screen(void)
|
||||||
if (recording_menu(false))
|
if (recording_menu(false))
|
||||||
return SYS_USB_CONNECTED;
|
return SYS_USB_CONNECTED;
|
||||||
settings_save();
|
settings_save();
|
||||||
|
|
||||||
mpeg_set_recording_options(global_settings.rec_frequency,
|
mpeg_set_recording_options(global_settings.rec_frequency,
|
||||||
global_settings.rec_quality,
|
global_settings.rec_quality,
|
||||||
global_settings.rec_source,
|
global_settings.rec_source,
|
||||||
global_settings.rec_channels,
|
global_settings.rec_channels,
|
||||||
global_settings.rec_editable);
|
global_settings.rec_editable,
|
||||||
|
global_settings.rec_prerecord_time);
|
||||||
|
|
||||||
set_gain();
|
set_gain();
|
||||||
|
|
||||||
update_countdown = 1; /* Update immediately */
|
update_countdown = 1; /* Update immediately */
|
||||||
|
|
||||||
lcd_setfont(FONT_SYSFIXED);
|
lcd_setfont(FONT_SYSFIXED);
|
||||||
|
@ -319,7 +323,7 @@ bool recording_screen(void)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BUTTON_F2:
|
case BUTTON_F2:
|
||||||
if(!mpeg_status())
|
if(mpeg_status() != MPEG_STATUS_RECORD)
|
||||||
{
|
{
|
||||||
if (f2_rec_screen())
|
if (f2_rec_screen())
|
||||||
{
|
{
|
||||||
|
@ -332,7 +336,7 @@ bool recording_screen(void)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BUTTON_F3:
|
case BUTTON_F3:
|
||||||
if(!mpeg_status())
|
if(mpeg_status() != MPEG_STATUS_RECORD)
|
||||||
{
|
{
|
||||||
if (f3_rec_screen())
|
if (f3_rec_screen())
|
||||||
{
|
{
|
||||||
|
@ -346,14 +350,12 @@ bool recording_screen(void)
|
||||||
|
|
||||||
case SYS_USB_CONNECTED:
|
case SYS_USB_CONNECTED:
|
||||||
/* Only accept USB connection when not recording */
|
/* Only accept USB connection when not recording */
|
||||||
if(!mpeg_status())
|
if(mpeg_status() != MPEG_STATUS_RECORD)
|
||||||
{
|
{
|
||||||
usb_screen();
|
usb_screen();
|
||||||
have_recorded = true; /* Refreshes the browser later on */
|
have_recorded = true; /* Refreshes the browser later on */
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
lcd_setfont(FONT_SYSFIXED);
|
|
||||||
lcd_setmargins(global_settings.invert_cursor ? 0 : w, 8);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,21 +389,28 @@ bool recording_screen(void)
|
||||||
|
|
||||||
dseconds = rec_timesplit_seconds();
|
dseconds = rec_timesplit_seconds();
|
||||||
|
|
||||||
/* Display the split interval if the record timesplit
|
if(mpeg_status() & MPEG_STATUS_PRERECORD)
|
||||||
is active */
|
|
||||||
if (global_settings.rec_timesplit)
|
|
||||||
{
|
{
|
||||||
/* Display the record timesplit interval rather than
|
snprintf(buf, 32, "%s...", str(LANG_RECORD_PRERECORD));
|
||||||
the file size if the record timer is active */
|
|
||||||
dhours = dseconds / 3600;
|
|
||||||
dminutes = (dseconds - (dhours * 3600)) / 60;
|
|
||||||
snprintf(buf, 32, "%s %02d:%02d",
|
|
||||||
str(LANG_RECORD_TIMESPLIT_REC),
|
|
||||||
dhours, dminutes);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
snprintf(buf, 32, "%s %s", str(LANG_RECORDING_SIZE),
|
{
|
||||||
num2max5(mpeg_num_recorded_bytes(), buf2));
|
/* Display the split interval if the record timesplit
|
||||||
|
is active */
|
||||||
|
if (global_settings.rec_timesplit)
|
||||||
|
{
|
||||||
|
/* Display the record timesplit interval rather than
|
||||||
|
the file size if the record timer is active */
|
||||||
|
dhours = dseconds / 3600;
|
||||||
|
dminutes = (dseconds - (dhours * 3600)) / 60;
|
||||||
|
snprintf(buf, 32, "%s %02d:%02d",
|
||||||
|
str(LANG_RECORD_TIMESPLIT_REC),
|
||||||
|
dhours, dminutes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
snprintf(buf, 32, "%s %s", str(LANG_RECORDING_SIZE),
|
||||||
|
num2max5(mpeg_num_recorded_bytes(), buf2));
|
||||||
|
}
|
||||||
lcd_puts(0, 1, buf);
|
lcd_puts(0, 1, buf);
|
||||||
|
|
||||||
/* We will do file splitting regardless, since the OFF
|
/* We will do file splitting regardless, since the OFF
|
||||||
|
@ -622,7 +631,8 @@ bool f2_rec_screen(void)
|
||||||
global_settings.rec_quality,
|
global_settings.rec_quality,
|
||||||
global_settings.rec_source,
|
global_settings.rec_source,
|
||||||
global_settings.rec_channels,
|
global_settings.rec_channels,
|
||||||
global_settings.rec_editable);
|
global_settings.rec_editable,
|
||||||
|
global_settings.rec_prerecord_time);
|
||||||
|
|
||||||
set_gain();
|
set_gain();
|
||||||
|
|
||||||
|
@ -671,22 +681,6 @@ bool f3_rec_screen(void)
|
||||||
used = true;
|
used = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BUTTON_DOWN:
|
|
||||||
case BUTTON_F3 | BUTTON_DOWN:
|
|
||||||
global_settings.rec_frequency++;
|
|
||||||
if(global_settings.rec_frequency > 5)
|
|
||||||
global_settings.rec_frequency = 0;
|
|
||||||
used = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BUTTON_RIGHT:
|
|
||||||
case BUTTON_F3 | BUTTON_RIGHT:
|
|
||||||
global_settings.rec_channels++;
|
|
||||||
if(global_settings.rec_channels > 1)
|
|
||||||
global_settings.rec_channels = 0;
|
|
||||||
used = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BUTTON_F3 | BUTTON_REL:
|
case BUTTON_F3 | BUTTON_REL:
|
||||||
if ( used )
|
if ( used )
|
||||||
exit = true;
|
exit = true;
|
||||||
|
@ -707,10 +701,11 @@ bool f3_rec_screen(void)
|
||||||
global_settings.rec_quality,
|
global_settings.rec_quality,
|
||||||
global_settings.rec_source,
|
global_settings.rec_source,
|
||||||
global_settings.rec_channels,
|
global_settings.rec_channels,
|
||||||
global_settings.rec_editable);
|
global_settings.rec_editable,
|
||||||
|
global_settings.rec_prerecord_time);
|
||||||
|
|
||||||
set_gain();
|
set_gain();
|
||||||
|
|
||||||
settings_save();
|
settings_save();
|
||||||
lcd_setfont(FONT_UI);
|
lcd_setfont(FONT_UI);
|
||||||
|
|
||||||
|
|
|
@ -129,6 +129,9 @@ location used, and reset the setting in question with a factory default if
|
||||||
needed. Memory locations not used by a given version should not be
|
needed. Memory locations not used by a given version should not be
|
||||||
modified unless the header & checksum test fails.
|
modified unless the header & checksum test fails.
|
||||||
|
|
||||||
|
Because 0xff mean that the byte is unused, care must be taken so that
|
||||||
|
a used byte can't have the value 0xff. Either use only 7 bits, or make sure
|
||||||
|
that the value will never be 0xff.
|
||||||
|
|
||||||
Rest of config block, only saved to disk:
|
Rest of config block, only saved to disk:
|
||||||
0xA8 (char)jump scroll mode (only for player)
|
0xA8 (char)jump scroll mode (only for player)
|
||||||
|
@ -151,9 +154,8 @@ Rest of config block, only saved to disk:
|
||||||
0xB8 (char[20]) WPS file
|
0xB8 (char[20]) WPS file
|
||||||
0xCC (char[20]) Lang file
|
0xCC (char[20]) Lang file
|
||||||
0xE0 (char[20]) Font file
|
0xE0 (char[20]) Font file
|
||||||
0xF4 <unused>
|
0xF4 Prerecording time (bit 0-4)
|
||||||
0xF8 <unused>
|
0xF5-0xFF <unused>
|
||||||
0xFC <unused>
|
|
||||||
|
|
||||||
*************************************/
|
*************************************/
|
||||||
|
|
||||||
|
@ -432,6 +434,8 @@ int settings_save( void )
|
||||||
strncpy(&config_block[0xcc], global_settings.lang_file, MAX_FILENAME);
|
strncpy(&config_block[0xcc], global_settings.lang_file, MAX_FILENAME);
|
||||||
strncpy(&config_block[0xe0], global_settings.font_file, MAX_FILENAME);
|
strncpy(&config_block[0xe0], global_settings.font_file, MAX_FILENAME);
|
||||||
|
|
||||||
|
config_block[0xf4]=(unsigned char)global_settings.rec_prerecord_time;
|
||||||
|
|
||||||
if(save_config_buffer())
|
if(save_config_buffer())
|
||||||
{
|
{
|
||||||
lcd_clear_display();
|
lcd_clear_display();
|
||||||
|
@ -756,6 +760,10 @@ void settings_load(void)
|
||||||
strncpy(global_settings.wps_file, &config_block[0xb8], MAX_FILENAME);
|
strncpy(global_settings.wps_file, &config_block[0xb8], MAX_FILENAME);
|
||||||
strncpy(global_settings.lang_file, &config_block[0xcc], MAX_FILENAME);
|
strncpy(global_settings.lang_file, &config_block[0xcc], MAX_FILENAME);
|
||||||
strncpy(global_settings.font_file, &config_block[0xe0], MAX_FILENAME);
|
strncpy(global_settings.font_file, &config_block[0xe0], MAX_FILENAME);
|
||||||
|
|
||||||
|
if (config_block[0xf4] != 0xff)
|
||||||
|
global_settings.rec_prerecord_time = config_block[0xf4];
|
||||||
|
|
||||||
#ifdef HAVE_LCD_CHARCELLS
|
#ifdef HAVE_LCD_CHARCELLS
|
||||||
if (config_block[0xa8] != 0xff)
|
if (config_block[0xa8] != 0xff)
|
||||||
global_settings.jump_scroll = config_block[0xa8];
|
global_settings.jump_scroll = config_block[0xa8];
|
||||||
|
@ -1079,6 +1087,9 @@ bool settings_load_config(char* file)
|
||||||
else if (!strcasecmp(name, "editable recordings")) {
|
else if (!strcasecmp(name, "editable recordings")) {
|
||||||
set_cfg_bool(&global_settings.rec_editable, value);
|
set_cfg_bool(&global_settings.rec_editable, value);
|
||||||
}
|
}
|
||||||
|
else if (!strcasecmp(name, "prerecording time")) {
|
||||||
|
set_cfg_int(&global_settings.rec_prerecord_time, value, 0, 30);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
else if (!strcasecmp(name, "idle poweroff")) {
|
else if (!strcasecmp(name, "idle poweroff")) {
|
||||||
static char* options[] = {"off","1","2","3","4","5","6","7","8",
|
static char* options[] = {"off","1","2","3","4","5","6","7","8",
|
||||||
|
@ -1379,6 +1390,10 @@ bool settings_save_config(void)
|
||||||
fprintf(fd, "line in: %s\r\n", boolopt[global_settings.line_in]);
|
fprintf(fd, "line in: %s\r\n", boolopt[global_settings.line_in]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
fprintf(fd, "max files in dir: %d\r\n", global_settings.max_files_in_dir);
|
||||||
|
fprintf(fd, "max files in playlist: %d\r\n",
|
||||||
|
global_settings.max_files_in_playlist);
|
||||||
|
|
||||||
#ifdef HAVE_MAS3587F
|
#ifdef HAVE_MAS3587F
|
||||||
fprintf(fd, "#\r\n# Recording\r\n#\r\n");
|
fprintf(fd, "#\r\n# Recording\r\n#\r\n");
|
||||||
fprintf(fd, "rec quality: %d\r\n", global_settings.rec_quality);
|
fprintf(fd, "rec quality: %d\r\n", global_settings.rec_quality);
|
||||||
|
@ -1409,12 +1424,12 @@ bool settings_save_config(void)
|
||||||
fprintf(fd, "editable recordings: %s\r\n",
|
fprintf(fd, "editable recordings: %s\r\n",
|
||||||
boolopt[global_settings.rec_editable]);
|
boolopt[global_settings.rec_editable]);
|
||||||
|
|
||||||
|
fprintf(fd, "prerecording time: %d\r\n",
|
||||||
|
global_settings.rec_prerecord_time);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fprintf(fd, "max files in dir: %d\r\n", global_settings.max_files_in_dir);
|
fprintf(fd, "#\r\n# Playlists\r\n#\r\n");
|
||||||
fprintf(fd, "max files in playlist: %d\r\n",
|
|
||||||
global_settings.max_files_in_playlist);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
static char* options[] = {"off", "on", "ask"};
|
static char* options[] = {"off", "on", "ask"};
|
||||||
fprintf(fd, "recursive directory insert: %s\r\n",
|
fprintf(fd, "recursive directory insert: %s\r\n",
|
||||||
|
@ -1454,6 +1469,7 @@ void settings_reset(void) {
|
||||||
global_settings.rec_left_gain = 2; /* 0dB */
|
global_settings.rec_left_gain = 2; /* 0dB */
|
||||||
global_settings.rec_right_gain = 2; /* 0dB */
|
global_settings.rec_right_gain = 2; /* 0dB */
|
||||||
global_settings.rec_editable = false;
|
global_settings.rec_editable = false;
|
||||||
|
global_settings.rec_prerecord_time = 0;
|
||||||
global_settings.resume = RESUME_ASK;
|
global_settings.resume = RESUME_ASK;
|
||||||
global_settings.contrast = lcd_default_contrast();
|
global_settings.contrast = lcd_default_contrast();
|
||||||
global_settings.invert = DEFAULT_INVERT_SETTING;
|
global_settings.invert = DEFAULT_INVERT_SETTING;
|
||||||
|
|
|
@ -85,6 +85,8 @@ struct user_settings
|
||||||
5 = 01:00, 6 = 02:00, 7 = 04:00, 8 = 06:00
|
5 = 01:00, 6 = 02:00, 7 = 04:00, 8 = 06:00
|
||||||
9 = 08:00, 10= 10:00, 11= 12:00, 12= 18:00,
|
9 = 08:00, 10= 10:00, 11= 12:00, 12= 18:00,
|
||||||
13= 24:00 */
|
13= 24:00 */
|
||||||
|
|
||||||
|
int rec_prerecord_time; /* In seconds, 0-30, 0 means OFF */
|
||||||
|
|
||||||
/* device settings */
|
/* device settings */
|
||||||
|
|
||||||
|
|
|
@ -241,6 +241,20 @@ static bool rectimesplit(void)
|
||||||
names, 14, NULL );
|
names, 14, NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool recprerecord(void)
|
||||||
|
{
|
||||||
|
char *names[] = {
|
||||||
|
str(LANG_OFF),"1s","2s", "3s", "4s", "5s", "6s", "7s", "8s", "9s",
|
||||||
|
"10s", "11s", "12s", "13s", "14s", "15s", "16s", "17s", "18s", "19s",
|
||||||
|
"20s", "21s", "22s", "23s", "24s", "25s", "26s", "27s", "28s", "29s",
|
||||||
|
"30s"
|
||||||
|
};
|
||||||
|
|
||||||
|
return set_option(str(LANG_RECORD_PRERECORD_TIME),
|
||||||
|
&global_settings.rec_prerecord_time, INT,
|
||||||
|
names, 31, NULL );
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* HAVE_MAS3587F */
|
#endif /* HAVE_MAS3587F */
|
||||||
|
|
||||||
static void set_chanconf(int val)
|
static void set_chanconf(int val)
|
||||||
|
@ -294,7 +308,7 @@ bool recording_menu(bool no_source)
|
||||||
{
|
{
|
||||||
int m;
|
int m;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
struct menu_items menu[6];
|
struct menu_items menu[7];
|
||||||
bool result;
|
bool result;
|
||||||
|
|
||||||
menu[i].desc = str(LANG_RECORDING_QUALITY);
|
menu[i].desc = str(LANG_RECORDING_QUALITY);
|
||||||
|
@ -311,6 +325,8 @@ bool recording_menu(bool no_source)
|
||||||
menu[i++].function = receditable;
|
menu[i++].function = receditable;
|
||||||
menu[i].desc = str(LANG_RECORD_TIMESPLIT);
|
menu[i].desc = str(LANG_RECORD_TIMESPLIT);
|
||||||
menu[i++].function = rectimesplit;
|
menu[i++].function = rectimesplit;
|
||||||
|
menu[i].desc = str(LANG_RECORD_PRERECORD_TIME);
|
||||||
|
menu[i++].function = recprerecord;
|
||||||
|
|
||||||
m=menu_init( menu, i );
|
m=menu_init( menu, i );
|
||||||
result = menu_run(m);
|
result = menu_run(m);
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
#define MPEG_PLAY_PENDING_THRESHOLD 0x10000
|
#define MPEG_PLAY_PENDING_THRESHOLD 0x10000
|
||||||
#define MPEG_PLAY_PENDING_SWAPSIZE 0x10000
|
#define MPEG_PLAY_PENDING_SWAPSIZE 0x10000
|
||||||
|
|
||||||
|
#define MPEG_MAX_PRERECORD_SECONDS 30
|
||||||
|
|
||||||
/* For ID3 info and VBR header */
|
/* For ID3 info and VBR header */
|
||||||
#define MPEG_RESERVED_HEADER_SPACE (4096 + 1500)
|
#define MPEG_RESERVED_HEADER_SPACE (4096 + 1500)
|
||||||
|
|
||||||
|
@ -89,7 +91,7 @@ void mpeg_record(char *filename);
|
||||||
void mpeg_new_file(char *filename);
|
void mpeg_new_file(char *filename);
|
||||||
void mpeg_set_recording_options(int frequency, int quality,
|
void mpeg_set_recording_options(int frequency, int quality,
|
||||||
int source, int channel_mode,
|
int source, int channel_mode,
|
||||||
bool editable);
|
bool editable, int prerecord_time);
|
||||||
void mpeg_set_recording_gain(int left, int right, bool use_mic);
|
void mpeg_set_recording_gain(int left, int right, bool use_mic);
|
||||||
unsigned long mpeg_recorded_time(void);
|
unsigned long mpeg_recorded_time(void);
|
||||||
unsigned long mpeg_num_recorded_bytes(void);
|
unsigned long mpeg_num_recorded_bytes(void);
|
||||||
|
@ -123,7 +125,8 @@ void mpeg_error_clear(void);
|
||||||
#define MPEG_STATUS_PLAY 1
|
#define MPEG_STATUS_PLAY 1
|
||||||
#define MPEG_STATUS_PAUSE 2
|
#define MPEG_STATUS_PAUSE 2
|
||||||
#define MPEG_STATUS_RECORD 4
|
#define MPEG_STATUS_RECORD 4
|
||||||
#define MPEG_STATUS_ERROR 8
|
#define MPEG_STATUS_PRERECORD 8
|
||||||
|
#define MPEG_STATUS_ERROR 16
|
||||||
|
|
||||||
#define MPEGERR_DISK_FULL 1
|
#define MPEGERR_DISK_FULL 1
|
||||||
|
|
||||||
|
|
660
firmware/mpeg.c
660
firmware/mpeg.c
|
@ -44,6 +44,7 @@ extern void bitswap(unsigned char *data, int length);
|
||||||
#ifdef HAVE_MAS3587F
|
#ifdef HAVE_MAS3587F
|
||||||
static void init_recording(void);
|
static void init_recording(void);
|
||||||
static void init_playback(void);
|
static void init_playback(void);
|
||||||
|
static void start_prerecording(void);
|
||||||
static void start_recording(void);
|
static void start_recording(void);
|
||||||
static void stop_recording(void);
|
static void stop_recording(void);
|
||||||
static int get_unsaved_space(void);
|
static int get_unsaved_space(void);
|
||||||
|
@ -497,6 +498,17 @@ static char recording_filename[MAX_PATH];
|
||||||
static int rec_frequency_index; /* For create_xing_header() calls */
|
static int rec_frequency_index; /* For create_xing_header() calls */
|
||||||
static int rec_version_index; /* For create_xing_header() calls */
|
static int rec_version_index; /* For create_xing_header() calls */
|
||||||
static bool disable_xing_header; /* When splitting files */
|
static bool disable_xing_header; /* When splitting files */
|
||||||
|
|
||||||
|
static bool prerecording; /* True if prerecording is enabled */
|
||||||
|
static bool is_prerecording; /* True if we are prerecording */
|
||||||
|
static int prerecord_buffer[MPEG_MAX_PRERECORD_SECONDS]; /* Array of buffer
|
||||||
|
indexes for each
|
||||||
|
prerecorded
|
||||||
|
second */
|
||||||
|
static int prerecord_index; /* Current index in the prerecord buffer */
|
||||||
|
static int prerecording_max_seconds; /* Max number of seconds to store */
|
||||||
|
static int prerecord_count; /* Number of seconds in the prerecord buffer */
|
||||||
|
static int prerecord_timeout; /* The tick count of the next prerecord data store */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int mpeg_file;
|
static int mpeg_file;
|
||||||
|
@ -865,17 +877,38 @@ static void dma_tick(void)
|
||||||
|
|
||||||
num_rec_bytes += i;
|
num_rec_bytes += i;
|
||||||
|
|
||||||
/* Signal to save the data if we are running out of buffer
|
if(is_prerecording)
|
||||||
space */
|
|
||||||
num_bytes = mp3buf_write - mp3buf_read;
|
|
||||||
if(num_bytes < 0)
|
|
||||||
num_bytes += mp3buflen;
|
|
||||||
|
|
||||||
if(mp3buflen - num_bytes < MPEG_RECORDING_LOW_WATER && !saving)
|
|
||||||
{
|
{
|
||||||
saving = true;
|
if(TIME_AFTER(current_tick, prerecord_timeout))
|
||||||
queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
|
{
|
||||||
wake_up_thread();
|
prerecord_timeout = current_tick + HZ;
|
||||||
|
|
||||||
|
/* Store the write pointer every second */
|
||||||
|
prerecord_buffer[prerecord_index++] = mp3buf_write;
|
||||||
|
|
||||||
|
/* Wrap if necessary */
|
||||||
|
if(prerecord_index == prerecording_max_seconds)
|
||||||
|
prerecord_index = 0;
|
||||||
|
|
||||||
|
/* Update the number of seconds recorded */
|
||||||
|
if(prerecord_count < prerecording_max_seconds)
|
||||||
|
prerecord_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Signal to save the data if we are running out of buffer
|
||||||
|
space */
|
||||||
|
num_bytes = mp3buf_write - mp3buf_read;
|
||||||
|
if(num_bytes < 0)
|
||||||
|
num_bytes += mp3buflen;
|
||||||
|
|
||||||
|
if(mp3buflen - num_bytes < MPEG_RECORDING_LOW_WATER && !saving)
|
||||||
|
{
|
||||||
|
saving = true;
|
||||||
|
queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
|
||||||
|
wake_up_thread();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1887,20 +1920,84 @@ static void mpeg_thread(void)
|
||||||
switch(ev.id)
|
switch(ev.id)
|
||||||
{
|
{
|
||||||
case MPEG_RECORD:
|
case MPEG_RECORD:
|
||||||
DEBUGF("Recording...\n");
|
if(is_prerecording)
|
||||||
reset_mp3_buffer();
|
{
|
||||||
|
int startpos, i;
|
||||||
|
|
||||||
|
/* Go back prerecord_count seconds in the buffer */
|
||||||
|
startpos = prerecord_index - prerecord_count;
|
||||||
|
if(startpos < 0)
|
||||||
|
startpos += prerecording_max_seconds;
|
||||||
|
|
||||||
/* Advance the write pointer to make
|
/* Read the mp3 buffer pointer from the prerecord buffer */
|
||||||
room for an ID3 tag plus a VBR header */
|
startpos = prerecord_buffer[startpos];
|
||||||
mp3buf_write = MPEG_RESERVED_HEADER_SPACE;
|
|
||||||
memset(mp3buf, 0, MPEG_RESERVED_HEADER_SPACE);
|
|
||||||
|
|
||||||
/* Insert the ID3 header */
|
DEBUGF("Start looking at address %x (%x)\n",
|
||||||
memcpy(mp3buf, empty_id3_header, sizeof(empty_id3_header));
|
mp3buf+startpos, startpos);
|
||||||
|
|
||||||
|
saved_header = get_last_recorded_header();
|
||||||
|
|
||||||
|
mem_find_next_frame(startpos, &offset, 5000,
|
||||||
|
saved_header);
|
||||||
|
|
||||||
|
mp3buf_read = startpos + offset;
|
||||||
|
|
||||||
|
DEBUGF("New mp3buf_read address: %x (%x)\n",
|
||||||
|
mp3buf+mp3buf_read, mp3buf_read);
|
||||||
|
|
||||||
|
/* Make room for headers */
|
||||||
|
mp3buf_read -= MPEG_RESERVED_HEADER_SPACE;
|
||||||
|
if(mp3buf_read < 0)
|
||||||
|
{
|
||||||
|
/* Clear the bottom half */
|
||||||
|
memset(mp3buf, 0,
|
||||||
|
mp3buf_read + MPEG_RESERVED_HEADER_SPACE);
|
||||||
|
|
||||||
|
/* And the top half */
|
||||||
|
mp3buf_read += mp3buflen;
|
||||||
|
memset(mp3buf + mp3buf_read, 0,
|
||||||
|
mp3buflen - mp3buf_read);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memset(mp3buf + mp3buf_read, 0,
|
||||||
|
MPEG_RESERVED_HEADER_SPACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the empty ID3 header */
|
||||||
|
startpos = mp3buf_read;
|
||||||
|
for(i = 0;i < (int)sizeof(empty_id3_header);i++)
|
||||||
|
{
|
||||||
|
mp3buf[startpos++] = empty_id3_header[i];
|
||||||
|
if(startpos == mp3buflen)
|
||||||
|
startpos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGF("New mp3buf_read address (reservation): %x\n",
|
||||||
|
mp3buf+mp3buf_read);
|
||||||
|
|
||||||
|
DEBUGF("Prerecording...\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
reset_mp3_buffer();
|
||||||
|
|
||||||
|
num_rec_bytes = 0;
|
||||||
|
|
||||||
|
/* Advance the write pointer to make
|
||||||
|
room for an ID3 tag plus a VBR header */
|
||||||
|
mp3buf_write = MPEG_RESERVED_HEADER_SPACE;
|
||||||
|
memset(mp3buf, 0, MPEG_RESERVED_HEADER_SPACE);
|
||||||
|
|
||||||
|
/* Insert the ID3 header */
|
||||||
|
memcpy(mp3buf, empty_id3_header,
|
||||||
|
sizeof(empty_id3_header));
|
||||||
|
|
||||||
|
DEBUGF("Recording...\n");
|
||||||
|
}
|
||||||
|
|
||||||
start_recording();
|
start_recording();
|
||||||
demand_irq_enable(true);
|
|
||||||
|
|
||||||
mpeg_file = open(recording_filename, O_WRONLY|O_CREAT);
|
mpeg_file = open(recording_filename, O_WRONLY|O_CREAT);
|
||||||
|
|
||||||
if(mpeg_file < 0)
|
if(mpeg_file < 0)
|
||||||
|
@ -1910,14 +2007,13 @@ static void mpeg_thread(void)
|
||||||
|
|
||||||
case MPEG_STOP:
|
case MPEG_STOP:
|
||||||
DEBUGF("MPEG_STOP\n");
|
DEBUGF("MPEG_STOP\n");
|
||||||
demand_irq_enable(false);
|
|
||||||
|
|
||||||
/* Store the last recorded header for later use by the
|
/* Store the last recorded header for later use by the
|
||||||
Xing header generation */
|
Xing header generation */
|
||||||
saved_header = get_last_recorded_header();
|
saved_header = get_last_recorded_header();
|
||||||
|
|
||||||
stop_recording();
|
stop_recording();
|
||||||
|
|
||||||
/* Save the remaining data in the buffer */
|
/* Save the remaining data in the buffer */
|
||||||
stop_pending = true;
|
stop_pending = true;
|
||||||
queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
|
queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
|
||||||
|
@ -1942,6 +2038,11 @@ static void mpeg_thread(void)
|
||||||
if(num_recorded_frames == 0x7ffff)
|
if(num_recorded_frames == 0x7ffff)
|
||||||
num_recorded_frames = 0;
|
num_recorded_frames = 0;
|
||||||
|
|
||||||
|
/* Also, if we have been prerecording, the frame count
|
||||||
|
will be wrong */
|
||||||
|
if(prerecording)
|
||||||
|
num_recorded_frames = 0;
|
||||||
|
|
||||||
/* saved_header is saved right before stopping
|
/* saved_header is saved right before stopping
|
||||||
the MAS */
|
the MAS */
|
||||||
framelen = create_xing_header(mpeg_file, 0,
|
framelen = create_xing_header(mpeg_file, 0,
|
||||||
|
@ -1970,6 +2071,11 @@ static void mpeg_thread(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if(prerecording)
|
||||||
|
{
|
||||||
|
start_prerecording();
|
||||||
|
}
|
||||||
mpeg_stop_done = true;
|
mpeg_stop_done = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -2117,7 +2223,6 @@ static void mpeg_thread(void)
|
||||||
if(errno == ENOSPC)
|
if(errno == ENOSPC)
|
||||||
{
|
{
|
||||||
mpeg_errno = MPEGERR_DISK_FULL;
|
mpeg_errno = MPEGERR_DISK_FULL;
|
||||||
demand_irq_enable(false);
|
|
||||||
stop_recording();
|
stop_recording();
|
||||||
queue_post(&mpeg_queue, MPEG_STOP_DONE, 0);
|
queue_post(&mpeg_queue, MPEG_STOP_DONE, 0);
|
||||||
break;
|
break;
|
||||||
|
@ -2161,18 +2266,22 @@ static void mpeg_thread(void)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SYS_USB_CONNECTED:
|
case SYS_USB_CONNECTED:
|
||||||
is_playing = false;
|
/* We can safely go to USB mode if no recording
|
||||||
paused = false;
|
is taking place */
|
||||||
stop_playing();
|
if((!is_recording || is_prerecording) && mpeg_stop_done)
|
||||||
#ifndef SIMULATOR
|
{
|
||||||
|
/* Even if we aren't recording, we still call this
|
||||||
|
function, to put the MAS in monitoring mode,
|
||||||
|
to save power. */
|
||||||
|
stop_recording();
|
||||||
|
|
||||||
/* Tell the USB thread that we are safe */
|
/* Tell the USB thread that we are safe */
|
||||||
DEBUGF("mpeg_thread got SYS_USB_CONNECTED\n");
|
DEBUGF("mpeg_thread got SYS_USB_CONNECTED\n");
|
||||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||||
|
|
||||||
/* Wait until the USB cable is extracted again */
|
/* Wait until the USB cable is extracted again */
|
||||||
usb_wait_for_disconnect(&mpeg_queue);
|
usb_wait_for_disconnect(&mpeg_queue);
|
||||||
#endif
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2245,16 +2354,6 @@ bool mpeg_has_changed_track(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_MAS3587F
|
#ifdef HAVE_MAS3587F
|
||||||
void mpeg_init_recording(void)
|
|
||||||
{
|
|
||||||
init_recording_done = false;
|
|
||||||
queue_post(&mpeg_queue, MPEG_INIT_RECORDING, NULL);
|
|
||||||
|
|
||||||
while(!init_recording_done)
|
|
||||||
sleep_thread();
|
|
||||||
wake_up_thread();
|
|
||||||
}
|
|
||||||
|
|
||||||
void mpeg_init_playback(void)
|
void mpeg_init_playback(void)
|
||||||
{
|
{
|
||||||
init_playback_done = false;
|
init_playback_done = false;
|
||||||
|
@ -2265,99 +2364,14 @@ void mpeg_init_playback(void)
|
||||||
wake_up_thread();
|
wake_up_thread();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_recording(void)
|
|
||||||
{
|
|
||||||
unsigned long val;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
stop_playing();
|
|
||||||
is_playing = false;
|
|
||||||
paused = false;
|
|
||||||
|
|
||||||
reset_mp3_buffer();
|
|
||||||
remove_all_tags();
|
|
||||||
|
|
||||||
if(mpeg_file >= 0)
|
|
||||||
close(mpeg_file);
|
|
||||||
mpeg_file = -1;
|
|
||||||
|
|
||||||
/* Init the recording variables */
|
|
||||||
is_recording = false;
|
|
||||||
|
|
||||||
mas_reset();
|
|
||||||
|
|
||||||
/* Enable the audio CODEC and the DSP core, max analog voltage range */
|
|
||||||
rc = mas_direct_config_write(MAS_CONTROL, 0x8c00);
|
|
||||||
if(rc < 0)
|
|
||||||
panicf("mas_ctrl_w: %d", rc);
|
|
||||||
|
|
||||||
/* Stop the current application */
|
|
||||||
val = 0;
|
|
||||||
mas_writemem(MAS_BANK_D0,0x7f6,&val,1);
|
|
||||||
do
|
|
||||||
{
|
|
||||||
mas_readmem(MAS_BANK_D0, 0x7f7, &val, 1);
|
|
||||||
} while(val);
|
|
||||||
|
|
||||||
/* Perform black magic as described by the data sheet */
|
|
||||||
if((mas_version_code & 0xff) == 2)
|
|
||||||
{
|
|
||||||
DEBUGF("Performing MAS black magic for B2 version\n");
|
|
||||||
mas_writereg(0xa3, 0x98);
|
|
||||||
mas_writereg(0x94, 0xfffff);
|
|
||||||
val = 0;
|
|
||||||
mas_writemem(MAS_BANK_D1, 0, &val, 1);
|
|
||||||
mas_writereg(0xa3, 0x90);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Enable A/D Converters */
|
|
||||||
mas_codec_writereg(0x0, 0xcccd);
|
|
||||||
|
|
||||||
/* Copy left channel to right (mono mode) */
|
|
||||||
mas_codec_writereg(8, 0x8000);
|
|
||||||
|
|
||||||
/* ADC scale 0%, DSP scale 100%
|
|
||||||
We use the DSP output for monitoring, because it works with all
|
|
||||||
sources including S/PDIF */
|
|
||||||
mas_codec_writereg(6, 0x0000);
|
|
||||||
mas_codec_writereg(7, 0x4000);
|
|
||||||
|
|
||||||
/* No mute */
|
|
||||||
val = 0;
|
|
||||||
mas_writemem(MAS_BANK_D0, 0x7f9, &val, 1);
|
|
||||||
|
|
||||||
/* Set Demand mode, no monitoring and validate all settings */
|
|
||||||
val = 0x125;
|
|
||||||
mas_writemem(MAS_BANK_D0, 0x7f1, &val, 1);
|
|
||||||
|
|
||||||
/* Start the encoder application */
|
|
||||||
val = 0x40;
|
|
||||||
mas_writemem(MAS_BANK_D0, 0x7f6, &val, 1);
|
|
||||||
do
|
|
||||||
{
|
|
||||||
mas_readmem(MAS_BANK_D0, 0x7f7, &val, 1);
|
|
||||||
} while(!(val & 0x40));
|
|
||||||
|
|
||||||
/* We have started the recording application with monitoring OFF.
|
|
||||||
This is because we want to record at least one frame to fill the DMA
|
|
||||||
buffer, because the silly MAS will not negate EOD until at least one
|
|
||||||
DMA transfer has taken place.
|
|
||||||
Now let's wait for some data to be encoded. */
|
|
||||||
sleep(20);
|
|
||||||
|
|
||||||
/* Disable IRQ6 */
|
|
||||||
IPRB &= 0xff0f;
|
|
||||||
|
|
||||||
mpeg_mode = MPEG_ENCODER;
|
|
||||||
|
|
||||||
DEBUGF("MAS Recording application started\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void init_playback(void)
|
static void init_playback(void)
|
||||||
{
|
{
|
||||||
unsigned long val;
|
unsigned long val;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
if(mpeg_mode == MPEG_ENCODER)
|
||||||
|
stop_recording();
|
||||||
|
|
||||||
stop_dma();
|
stop_dma();
|
||||||
|
|
||||||
mas_reset();
|
mas_reset();
|
||||||
|
@ -2411,6 +2425,121 @@ static void init_playback(void)
|
||||||
DEBUGF("MAS Decoding application started\n");
|
DEBUGF("MAS Decoding application started\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** Recording functions
|
||||||
|
**
|
||||||
|
**
|
||||||
|
***************************************************************************/
|
||||||
|
void mpeg_init_recording(void)
|
||||||
|
{
|
||||||
|
init_recording_done = false;
|
||||||
|
queue_post(&mpeg_queue, MPEG_INIT_RECORDING, NULL);
|
||||||
|
|
||||||
|
while(!init_recording_done)
|
||||||
|
sleep_thread();
|
||||||
|
wake_up_thread();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_recording(void)
|
||||||
|
{
|
||||||
|
unsigned long val;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Disable IRQ6 */
|
||||||
|
IPRB &= 0xff0f;
|
||||||
|
|
||||||
|
stop_playing();
|
||||||
|
is_playing = false;
|
||||||
|
paused = false;
|
||||||
|
|
||||||
|
reset_mp3_buffer();
|
||||||
|
remove_all_tags();
|
||||||
|
|
||||||
|
if(mpeg_file >= 0)
|
||||||
|
close(mpeg_file);
|
||||||
|
mpeg_file = -1;
|
||||||
|
|
||||||
|
/* Init the recording variables */
|
||||||
|
is_recording = false;
|
||||||
|
is_prerecording = false;
|
||||||
|
|
||||||
|
mpeg_stop_done = true;
|
||||||
|
|
||||||
|
mas_reset();
|
||||||
|
|
||||||
|
/* Enable the audio CODEC and the DSP core, max analog voltage range */
|
||||||
|
rc = mas_direct_config_write(MAS_CONTROL, 0x8c00);
|
||||||
|
if(rc < 0)
|
||||||
|
panicf("mas_ctrl_w: %d", rc);
|
||||||
|
|
||||||
|
/* Stop the current application */
|
||||||
|
val = 0;
|
||||||
|
mas_writemem(MAS_BANK_D0,0x7f6,&val,1);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
mas_readmem(MAS_BANK_D0, 0x7f7, &val, 1);
|
||||||
|
} while(val);
|
||||||
|
|
||||||
|
/* Perform black magic as described by the data sheet */
|
||||||
|
if((mas_version_code & 0xff) == 2)
|
||||||
|
{
|
||||||
|
DEBUGF("Performing MAS black magic for B2 version\n");
|
||||||
|
mas_writereg(0xa3, 0x98);
|
||||||
|
mas_writereg(0x94, 0xfffff);
|
||||||
|
val = 0;
|
||||||
|
mas_writemem(MAS_BANK_D1, 0, &val, 1);
|
||||||
|
mas_writereg(0xa3, 0x90);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable A/D Converters */
|
||||||
|
mas_codec_writereg(0x0, 0xcccd);
|
||||||
|
|
||||||
|
/* Copy left channel to right (mono mode) */
|
||||||
|
mas_codec_writereg(8, 0x8000);
|
||||||
|
|
||||||
|
/* ADC scale 0%, DSP scale 100%
|
||||||
|
We use the DSP output for monitoring, because it works with all
|
||||||
|
sources including S/PDIF */
|
||||||
|
mas_codec_writereg(6, 0x0000);
|
||||||
|
mas_codec_writereg(7, 0x4000);
|
||||||
|
|
||||||
|
/* No mute */
|
||||||
|
val = 0;
|
||||||
|
mas_writemem(MAS_BANK_D0, 0x7f9, &val, 1);
|
||||||
|
|
||||||
|
/* Set Demand mode, no monitoring and validate all settings */
|
||||||
|
val = 0x125;
|
||||||
|
mas_writemem(MAS_BANK_D0, 0x7f1, &val, 1);
|
||||||
|
|
||||||
|
/* Start the encoder application */
|
||||||
|
val = 0x40;
|
||||||
|
mas_writemem(MAS_BANK_D0, 0x7f6, &val, 1);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
mas_readmem(MAS_BANK_D0, 0x7f7, &val, 1);
|
||||||
|
} while(!(val & 0x40));
|
||||||
|
|
||||||
|
/* We have started the recording application with monitoring OFF.
|
||||||
|
This is because we want to record at least one frame to fill the DMA
|
||||||
|
buffer, because the silly MAS will not negate EOD until at least one
|
||||||
|
DMA transfer has taken place.
|
||||||
|
Now let's wait for some data to be encoded. */
|
||||||
|
sleep(20);
|
||||||
|
|
||||||
|
/* Now set it to Monitoring mode as default, saves power */
|
||||||
|
val = 0x525;
|
||||||
|
mas_writemem(MAS_BANK_D0, 0x7f1, &val, 1);
|
||||||
|
|
||||||
|
mpeg_mode = MPEG_ENCODER;
|
||||||
|
|
||||||
|
DEBUGF("MAS Recording application started\n");
|
||||||
|
|
||||||
|
/* At this point, all settings are the reset MAS defaults, next thing is to
|
||||||
|
call mpeg_set_recording_options(). */
|
||||||
|
}
|
||||||
|
|
||||||
void mpeg_record(char *filename)
|
void mpeg_record(char *filename)
|
||||||
{
|
{
|
||||||
mpeg_errno = 0;
|
mpeg_errno = 0;
|
||||||
|
@ -2418,53 +2547,109 @@ void mpeg_record(char *filename)
|
||||||
strncpy(recording_filename, filename, MAX_PATH - 1);
|
strncpy(recording_filename, filename, MAX_PATH - 1);
|
||||||
recording_filename[MAX_PATH - 1] = 0;
|
recording_filename[MAX_PATH - 1] = 0;
|
||||||
|
|
||||||
num_rec_bytes = 0;
|
|
||||||
disable_xing_header = false;
|
disable_xing_header = false;
|
||||||
queue_post(&mpeg_queue, MPEG_RECORD, NULL);
|
queue_post(&mpeg_queue, MPEG_RECORD, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void start_prerecording(void)
|
||||||
|
{
|
||||||
|
unsigned long val;
|
||||||
|
|
||||||
|
DEBUGF("Starting prerecording\n");
|
||||||
|
|
||||||
|
prerecord_index = 0;
|
||||||
|
prerecord_count = 0;
|
||||||
|
prerecord_timeout = current_tick + HZ;
|
||||||
|
memset(prerecord_buffer, 0, sizeof(prerecord_buffer));
|
||||||
|
reset_mp3_buffer();
|
||||||
|
|
||||||
|
is_prerecording = true;
|
||||||
|
|
||||||
|
/* Stop monitoring and start the encoder */
|
||||||
|
mas_readmem(MAS_BANK_D0, 0x7f1, &val, 1);
|
||||||
|
val &= ~(1 << 10);
|
||||||
|
val |= 1;
|
||||||
|
mas_writemem(MAS_BANK_D0, 0x7f1, &val, 1);
|
||||||
|
DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f1, %x)\n", val);
|
||||||
|
|
||||||
|
/* Wait until the DSP has accepted the settings */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
mas_readmem(MAS_BANK_D0, 0x7f1, &val,1);
|
||||||
|
} while(val & 1);
|
||||||
|
|
||||||
|
sleep(20);
|
||||||
|
|
||||||
|
is_recording = true;
|
||||||
|
stop_pending = false;
|
||||||
|
saving = false;
|
||||||
|
|
||||||
|
demand_irq_enable(true);
|
||||||
|
}
|
||||||
|
|
||||||
static void start_recording(void)
|
static void start_recording(void)
|
||||||
{
|
{
|
||||||
unsigned long val;
|
unsigned long val;
|
||||||
|
|
||||||
num_recorded_frames = 0;
|
num_recorded_frames = 0;
|
||||||
|
|
||||||
/* Stop monitoring and record for real */
|
|
||||||
mas_readmem(MAS_BANK_D0, 0x7f1, &val, 1);
|
|
||||||
val &= ~(1 << 10);
|
|
||||||
val |= 1;
|
|
||||||
mas_writemem(MAS_BANK_D0, 0x7f1, &val, 1);
|
|
||||||
|
|
||||||
/* Wait until the DSP has accepted the settings */
|
if(is_prerecording)
|
||||||
do
|
|
||||||
{
|
{
|
||||||
mas_readmem(MAS_BANK_D0, 0x7f1, &val,1);
|
/* This will make the IRQ handler start recording
|
||||||
} while(val & 1);
|
for real, i.e send MPEG_SAVE_DATA messages when
|
||||||
|
the buffer is full */
|
||||||
sleep(20);
|
is_prerecording = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* If prerecording is off, we need to stop the monitoring
|
||||||
|
and start the encoder */
|
||||||
|
mas_readmem(MAS_BANK_D0, 0x7f1, &val, 1);
|
||||||
|
val &= ~(1 << 10);
|
||||||
|
val |= 1;
|
||||||
|
mas_writemem(MAS_BANK_D0, 0x7f1, &val, 1);
|
||||||
|
DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f1, %x)\n", val);
|
||||||
|
|
||||||
|
/* Wait until the DSP has accepted the settings */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
mas_readmem(MAS_BANK_D0, 0x7f1, &val,1);
|
||||||
|
} while(val & 1);
|
||||||
|
|
||||||
|
sleep(20);
|
||||||
|
}
|
||||||
|
|
||||||
/* Store the current time */
|
|
||||||
record_start_time = current_tick;
|
|
||||||
|
|
||||||
is_recording = true;
|
is_recording = true;
|
||||||
stop_pending = false;
|
stop_pending = false;
|
||||||
saving = false;
|
saving = false;
|
||||||
|
|
||||||
|
/* Store the current time */
|
||||||
|
if(prerecording)
|
||||||
|
record_start_time = current_tick - prerecord_count * HZ;
|
||||||
|
else
|
||||||
|
record_start_time = current_tick;
|
||||||
|
|
||||||
|
demand_irq_enable(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stop_recording(void)
|
static void stop_recording(void)
|
||||||
{
|
{
|
||||||
unsigned long val;
|
unsigned long val;
|
||||||
|
|
||||||
is_recording = false;
|
demand_irq_enable(false);
|
||||||
|
|
||||||
|
is_recording = false;
|
||||||
|
is_prerecording = false;
|
||||||
|
|
||||||
/* Read the number of frames recorded */
|
/* Read the number of frames recorded */
|
||||||
mas_readmem(MAS_BANK_D0, 0xfd0, &num_recorded_frames, 1);
|
mas_readmem(MAS_BANK_D0, 0xfd0, &num_recorded_frames, 1);
|
||||||
|
|
||||||
/* Start monitoring */
|
/* Start monitoring */
|
||||||
mas_readmem(MAS_BANK_D0, 0x7f1, &val, 1);
|
mas_readmem(MAS_BANK_D0, 0x7f1, &val, 1);
|
||||||
val |= (1 << 10) | 1;
|
val |= (1 << 10) | 1;
|
||||||
mas_writemem(MAS_BANK_D0, 0x7f1, &val, 1);
|
mas_writemem(MAS_BANK_D0, 0x7f1, &val, 1);
|
||||||
|
DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f1, %x)\n", val);
|
||||||
|
|
||||||
/* Wait until the DSP has accepted the settings */
|
/* Wait until the DSP has accepted the settings */
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -2474,6 +2659,82 @@ static void stop_recording(void)
|
||||||
drain_dma_buffer();
|
drain_dma_buffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mpeg_set_recording_options(int frequency, int quality,
|
||||||
|
int source, int channel_mode,
|
||||||
|
bool editable, int prerecord_time)
|
||||||
|
{
|
||||||
|
bool is_mpeg1;
|
||||||
|
unsigned long val;
|
||||||
|
|
||||||
|
is_mpeg1 = (frequency < 3)?true:false;
|
||||||
|
|
||||||
|
rec_version_index = is_mpeg1?3:2;
|
||||||
|
rec_frequency_index = frequency % 3;
|
||||||
|
|
||||||
|
val = (quality << 17) |
|
||||||
|
(rec_frequency_index << 10) |
|
||||||
|
((is_mpeg1?1:0) << 9) |
|
||||||
|
(1 << 8) | /* CRC on */
|
||||||
|
(((channel_mode * 2 + 1) & 3) << 6) |
|
||||||
|
(1 << 5) /* MS-stereo */ |
|
||||||
|
(1 << 2) /* Is an original */;
|
||||||
|
mas_writemem(MAS_BANK_D0, 0x7f0, &val,1);
|
||||||
|
|
||||||
|
DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f0, %x)\n", val);
|
||||||
|
|
||||||
|
val = editable?4:0;
|
||||||
|
mas_writemem(MAS_BANK_D0, 0x7f9, &val,1);
|
||||||
|
|
||||||
|
DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f9, %x)\n", val);
|
||||||
|
|
||||||
|
val = (((source < 2)?1:2) << 8) | /* Input select */
|
||||||
|
(1 << 5) | /* SDO strobe invert */
|
||||||
|
((is_mpeg1?0:1) << 3) |
|
||||||
|
(1 << 2) | /* Inverted SIBC clock signal */
|
||||||
|
1; /* Validate */
|
||||||
|
mas_writemem(MAS_BANK_D0, 0x7f1, &val,1);
|
||||||
|
|
||||||
|
DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f1, %x)\n", val);
|
||||||
|
|
||||||
|
drain_dma_buffer();
|
||||||
|
|
||||||
|
if(source == 0) /* Mic */
|
||||||
|
{
|
||||||
|
/* Copy left channel to right (mono mode) */
|
||||||
|
mas_codec_writereg(8, 0x8000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Stereo input mode */
|
||||||
|
mas_codec_writereg(8, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
prerecording_max_seconds = prerecord_time;
|
||||||
|
if(prerecording_max_seconds)
|
||||||
|
{
|
||||||
|
prerecording = true;
|
||||||
|
start_prerecording();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prerecording = false;
|
||||||
|
is_prerecording = false;
|
||||||
|
is_recording = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If use_mic is true, the left gain is used */
|
||||||
|
void mpeg_set_recording_gain(int left, int right, bool use_mic)
|
||||||
|
{
|
||||||
|
/* Enable both left and right A/D */
|
||||||
|
mas_codec_writereg(0x0,
|
||||||
|
(left << 12) |
|
||||||
|
(right << 8) |
|
||||||
|
(left << 4) |
|
||||||
|
(use_mic?0x0008:0) | /* Connect left A/D to mic */
|
||||||
|
0x0007);
|
||||||
|
}
|
||||||
|
|
||||||
void mpeg_new_file(char *filename)
|
void mpeg_new_file(char *filename)
|
||||||
{
|
{
|
||||||
mpeg_errno = 0;
|
mpeg_errno = 0;
|
||||||
|
@ -2492,16 +2753,37 @@ void mpeg_new_file(char *filename)
|
||||||
|
|
||||||
unsigned long mpeg_recorded_time(void)
|
unsigned long mpeg_recorded_time(void)
|
||||||
{
|
{
|
||||||
|
if(is_prerecording)
|
||||||
|
return prerecord_count * HZ;
|
||||||
|
|
||||||
if(is_recording)
|
if(is_recording)
|
||||||
return current_tick - record_start_time;
|
return current_tick - record_start_time;
|
||||||
else
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long mpeg_num_recorded_bytes(void)
|
unsigned long mpeg_num_recorded_bytes(void)
|
||||||
{
|
{
|
||||||
|
int num_bytes;
|
||||||
|
int index;
|
||||||
|
|
||||||
if(is_recording)
|
if(is_recording)
|
||||||
return num_rec_bytes;
|
{
|
||||||
|
if(is_prerecording)
|
||||||
|
{
|
||||||
|
index = prerecord_index - prerecord_count;
|
||||||
|
if(index < 0)
|
||||||
|
index += prerecording_max_seconds;
|
||||||
|
|
||||||
|
num_bytes = mp3buf_write - prerecord_buffer[index];
|
||||||
|
if(num_bytes < 0)
|
||||||
|
num_bytes += mp3buflen;
|
||||||
|
|
||||||
|
return num_bytes;;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return num_rec_bytes;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2660,8 +2942,11 @@ int mpeg_status(void)
|
||||||
ret |= MPEG_STATUS_PAUSE;
|
ret |= MPEG_STATUS_PAUSE;
|
||||||
|
|
||||||
#ifdef HAVE_MAS3587F
|
#ifdef HAVE_MAS3587F
|
||||||
if(is_recording)
|
if(is_recording && !is_prerecording)
|
||||||
ret |= MPEG_STATUS_RECORD;
|
ret |= MPEG_STATUS_RECORD;
|
||||||
|
|
||||||
|
if(is_prerecording)
|
||||||
|
ret |= MPEG_STATUS_PRERECORD;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(mpeg_errno)
|
if(mpeg_errno)
|
||||||
|
@ -3057,73 +3342,6 @@ void mpeg_set_pitch(int pitch)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_MAS3587F
|
|
||||||
void mpeg_set_recording_options(int frequency, int quality,
|
|
||||||
int source, int channel_mode,
|
|
||||||
bool editable)
|
|
||||||
{
|
|
||||||
bool is_mpeg1;
|
|
||||||
unsigned long val;
|
|
||||||
|
|
||||||
is_mpeg1 = (frequency < 3)?true:false;
|
|
||||||
|
|
||||||
rec_version_index = is_mpeg1?3:2;
|
|
||||||
rec_frequency_index = frequency % 3;
|
|
||||||
|
|
||||||
val = (quality << 17) |
|
|
||||||
(rec_frequency_index << 10) |
|
|
||||||
((is_mpeg1?1:0) << 9) |
|
|
||||||
(1 << 8) | /* CRC on */
|
|
||||||
(((channel_mode * 2 + 1) & 3) << 6) |
|
|
||||||
(1 << 5) /* MS-stereo */ |
|
|
||||||
(1 << 2) /* Is an original */;
|
|
||||||
mas_writemem(MAS_BANK_D0, 0x7f0, &val,1);
|
|
||||||
|
|
||||||
DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f0, %x)\n", val);
|
|
||||||
|
|
||||||
val = editable?4:0;
|
|
||||||
mas_writemem(MAS_BANK_D0, 0x7f9, &val,1);
|
|
||||||
|
|
||||||
DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f9, %x)\n", val);
|
|
||||||
|
|
||||||
val = ((!is_recording << 10) | /* Monitoring */
|
|
||||||
((source < 2)?1:2) << 8) | /* Input select */
|
|
||||||
(1 << 5) | /* SDO strobe invert */
|
|
||||||
((is_mpeg1?0:1) << 3) |
|
|
||||||
(1 << 2) | /* Inverted SIBC clock signal */
|
|
||||||
1; /* Validate */
|
|
||||||
mas_writemem(MAS_BANK_D0, 0x7f1, &val,1);
|
|
||||||
|
|
||||||
DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f1, %x)\n", val);
|
|
||||||
|
|
||||||
drain_dma_buffer();
|
|
||||||
|
|
||||||
if(source == 0) /* Mic */
|
|
||||||
{
|
|
||||||
/* Copy left channel to right (mono mode) */
|
|
||||||
mas_codec_writereg(8, 0x8000);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Stereo input mode */
|
|
||||||
mas_codec_writereg(8, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If use_mic is true, the left gain is used */
|
|
||||||
void mpeg_set_recording_gain(int left, int right, bool use_mic)
|
|
||||||
{
|
|
||||||
/* Enable both left and right A/D */
|
|
||||||
mas_codec_writereg(0x0,
|
|
||||||
(left << 12) |
|
|
||||||
(right << 8) |
|
|
||||||
(left << 4) |
|
|
||||||
(use_mic?0x0008:0) | /* Connect left A/D to mic */
|
|
||||||
0x0007);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SIMULATOR
|
#ifdef SIMULATOR
|
||||||
static char mpeg_stack[DEFAULT_STACK_SIZE];
|
static char mpeg_stack[DEFAULT_STACK_SIZE];
|
||||||
static char mpeg_thread_name[] = "mpeg";
|
static char mpeg_thread_name[] = "mpeg";
|
||||||
|
|
Loading…
Reference in a new issue