mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-08 12:45:26 -05:00
Xing headers now support mono better, added the 'editable files' option
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@3572 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
c6fb565dd9
commit
478da628f0
10 changed files with 153 additions and 91 deletions
|
|
@ -1467,3 +1467,8 @@ id: LANG_INVERT_CURSOR
|
|||
desc: in settings_menu
|
||||
eng: "Invert cursor"
|
||||
new:
|
||||
|
||||
id: LANG_RECORDING_EDITABLE
|
||||
desc: Editable recordings setting
|
||||
eng: "Editable files"
|
||||
new:
|
||||
|
|
|
|||
|
|
@ -251,11 +251,11 @@ static bool vbr_fix(void)
|
|||
flen, xingupdate);
|
||||
|
||||
if(num_frames) {
|
||||
/* Note: We don't need to pass any values for mpeg_version and
|
||||
sample_rate because they will be extracted from the mpeg stream */
|
||||
/* Note: We don't need to pass a template header because it will be
|
||||
taken from the mpeg stream */
|
||||
framelen = create_xing_header(fd, entry.first_frame_offset,
|
||||
flen, xingbuf, num_frames,
|
||||
0, 0, xingupdate, true);
|
||||
0, xingupdate, true);
|
||||
|
||||
/* Try to fit the Xing header first in the stream. Replace the existing
|
||||
VBR header if there is one, else see if there is room between the
|
||||
|
|
|
|||
|
|
@ -169,7 +169,8 @@ bool recording_screen(void)
|
|||
mpeg_set_recording_options(global_settings.rec_frequency,
|
||||
global_settings.rec_quality,
|
||||
global_settings.rec_source,
|
||||
global_settings.rec_channels);
|
||||
global_settings.rec_channels,
|
||||
global_settings.rec_editable);
|
||||
|
||||
set_gain();
|
||||
|
||||
|
|
@ -312,22 +313,29 @@ bool recording_screen(void)
|
|||
mpeg_set_recording_options(global_settings.rec_frequency,
|
||||
global_settings.rec_quality,
|
||||
global_settings.rec_source,
|
||||
global_settings.rec_channels);
|
||||
global_settings.rec_channels,
|
||||
global_settings.rec_editable);
|
||||
|
||||
set_gain();
|
||||
update_countdown = 1; /* Update immediately */
|
||||
break;
|
||||
|
||||
case BUTTON_F2:
|
||||
if(mpeg_status())
|
||||
{
|
||||
if (f2_rec_screen())
|
||||
return SYS_USB_CONNECTED;
|
||||
update_countdown = 1; /* Update immediately */
|
||||
}
|
||||
break;
|
||||
|
||||
case BUTTON_F3:
|
||||
if(mpeg_status())
|
||||
{
|
||||
if (f3_rec_screen())
|
||||
return SYS_USB_CONNECTED;
|
||||
update_countdown = 1; /* Update immediately */
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
|
@ -537,7 +545,8 @@ bool f2_rec_screen(void)
|
|||
mpeg_set_recording_options(global_settings.rec_frequency,
|
||||
global_settings.rec_quality,
|
||||
global_settings.rec_source,
|
||||
global_settings.rec_channels);
|
||||
global_settings.rec_channels,
|
||||
global_settings.rec_editable);
|
||||
|
||||
set_gain();
|
||||
|
||||
|
|
@ -621,7 +630,8 @@ bool f3_rec_screen(void)
|
|||
mpeg_set_recording_options(global_settings.rec_frequency,
|
||||
global_settings.rec_quality,
|
||||
global_settings.rec_source,
|
||||
global_settings.rec_channels);
|
||||
global_settings.rec_channels,
|
||||
global_settings.rec_editable);
|
||||
|
||||
set_gain();
|
||||
|
||||
|
|
|
|||
|
|
@ -96,8 +96,8 @@ offset abs
|
|||
0x16 0x2a <(int) Byte offset into resume file>
|
||||
0x1a 0x2e <time until disk spindown>
|
||||
0x1b 0x2f <browse current, play selected, queue_resume>
|
||||
0x1c 0x30 <peak meter hold timeout (bit 0-4)>,
|
||||
peak_meter_performance (bit 7)
|
||||
0x1c 0x30 <peak meter hold timeout (bit 0-4),
|
||||
rec_editable (bit 7)>
|
||||
0x1d 0x31 <(int) queue resume index>
|
||||
0x21 0x35 <repeat mode (bit 0-1), rec. channels (bit 2),
|
||||
mic gain (bit 4-7)>
|
||||
|
|
@ -125,7 +125,7 @@ modified unless the header & checksum test fails.
|
|||
|
||||
Rest of config block, only saved to disk:
|
||||
0xAE fade on pause/unpause/stop setting (bit 0)
|
||||
0xB0 peak meter clip hold timeout (bit 0-4)
|
||||
0xB0 peak meter clip hold timeout (bit 0-4), peak meter performance (bit 7)
|
||||
0xB1 peak meter release step size, peak_meter_dbfs (bit 7)
|
||||
0xB2 peak meter min either in -db or in percent
|
||||
0xB3 peak meter max either in -db or in percent
|
||||
|
|
@ -341,7 +341,8 @@ int settings_save( void )
|
|||
((global_settings.play_selected & 1) << 1) |
|
||||
((global_settings.queue_resume & 3) << 2));
|
||||
|
||||
config_block[0x1c] = (unsigned char)global_settings.peak_meter_hold;
|
||||
config_block[0x1c] = (unsigned char)global_settings.peak_meter_hold |
|
||||
(global_settings.rec_editable?0x80:0);
|
||||
|
||||
memcpy(&config_block[0x1d], &global_settings.queue_resume_index, 4);
|
||||
|
||||
|
|
@ -617,8 +618,11 @@ void settings_load(void)
|
|||
global_settings.queue_resume = (config_block[0x1b] >> 2) & 3;
|
||||
}
|
||||
|
||||
if (config_block[0x1c] != 0xFF)
|
||||
if (config_block[0x1c] != 0xFF) {
|
||||
global_settings.peak_meter_hold = (config_block[0x1c]) & 0x1f;
|
||||
global_settings.rec_editable =
|
||||
config_block[0x1c]?true:false;
|
||||
}
|
||||
|
||||
if (config_block[0x1d] != 0xFF)
|
||||
memcpy(&global_settings.queue_resume_index, &config_block[0x1d],
|
||||
|
|
@ -1029,6 +1033,9 @@ bool settings_load_config(char* file)
|
|||
static char* options[] = {"stereo", "mono"};
|
||||
set_cfg_option(&global_settings.rec_channels, value, options, 2);
|
||||
}
|
||||
else if (!strcasecmp(name, "editable recordings")) {
|
||||
set_cfg_bool(&global_settings.rec_editable, value);
|
||||
}
|
||||
#endif
|
||||
else if (!strcasecmp(name, "idle poweroff")) {
|
||||
static char* options[] = {"off","1","2","3","4","5","6","7","8",
|
||||
|
|
@ -1434,6 +1441,14 @@ bool settings_save_config(void)
|
|||
global_settings.rec_left_gain,
|
||||
global_settings.rec_right_gain);
|
||||
write(fd, buf, strlen(buf));
|
||||
|
||||
{
|
||||
static char* options[] = {"off", "on"};
|
||||
snprintf(buf, sizeof(buf), "editable recordings: %s\r\n",
|
||||
options[global_settings.rec_editable]);
|
||||
write(fd, buf, strlen(buf));
|
||||
}
|
||||
|
||||
#endif
|
||||
close(fd);
|
||||
|
||||
|
|
@ -1467,6 +1482,7 @@ void settings_reset(void) {
|
|||
global_settings.rec_mic_gain = 8;
|
||||
global_settings.rec_left_gain = 2; /* 0dB */
|
||||
global_settings.rec_right_gain = 2; /* 0dB */
|
||||
global_settings.rec_editable = false;
|
||||
global_settings.resume = RESUME_ASK;
|
||||
global_settings.contrast = DEFAULT_CONTRAST_SETTING;
|
||||
global_settings.invert = DEFAULT_INVERT_SETTING;
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ struct user_settings
|
|||
int rec_mic_gain; /* 0-15 */
|
||||
int rec_left_gain; /* 0-15 */
|
||||
int rec_right_gain; /* 0-15 */
|
||||
bool rec_editable; /* true means that the bit reservoir is off */
|
||||
|
||||
/* device settings */
|
||||
|
||||
|
|
|
|||
|
|
@ -219,6 +219,12 @@ static bool recquality(void)
|
|||
&global_settings.rec_quality,
|
||||
NULL, 1, 0, 7 );
|
||||
}
|
||||
|
||||
static bool receditable(void)
|
||||
{
|
||||
return set_bool(str(LANG_RECORDING_EDITABLE),
|
||||
&global_settings.rec_editable);
|
||||
}
|
||||
#endif /* HAVE_MAS3587F */
|
||||
|
||||
static void set_chanconf(int val)
|
||||
|
|
@ -275,6 +281,7 @@ bool recording_menu(void)
|
|||
{ str(LANG_RECORDING_FREQUENCY), recfrequency },
|
||||
{ str(LANG_RECORDING_SOURCE), recsource },
|
||||
{ str(LANG_RECORDING_CHANNELS), recchannels },
|
||||
{ str(LANG_RECORDING_EDITABLE), receditable },
|
||||
};
|
||||
|
||||
m=menu_init( items, sizeof items / sizeof(struct menu_items) );
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ int count_mp3_frames(int fd, int startpos, int filesize,
|
|||
void (*progressfunc)(int));
|
||||
int create_xing_header(int fd, int startpos, int filesize,
|
||||
unsigned char *buf, int num_frames,
|
||||
int mpeg_version, int sample_rate,
|
||||
unsigned long header_template,
|
||||
void (*progressfunc)(int), bool generate_toc);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@
|
|||
#define MPEG_PLAY_PENDING_THRESHOLD 0x10000
|
||||
#define MPEG_PLAY_PENDING_SWAPSIZE 0x10000
|
||||
|
||||
/* For ID3 info and VBR header */
|
||||
#define MPEG_RESERVED_HEADER_SPACE (4096 + 1500)
|
||||
|
||||
struct mpeg_debug
|
||||
{
|
||||
int mp3buflen;
|
||||
|
|
@ -84,7 +87,8 @@ void mpeg_init_recording(void);
|
|||
void mpeg_init_playback(void);
|
||||
void mpeg_record(char *filename);
|
||||
void mpeg_set_recording_options(int frequency, int quality,
|
||||
int source, int channel_mode);
|
||||
int source, int channel_mode,
|
||||
bool editable);
|
||||
void mpeg_set_recording_gain(int left, int right, int mic);
|
||||
unsigned long mpeg_recorded_time(void);
|
||||
unsigned long mpeg_num_recorded_bytes(void);
|
||||
|
|
|
|||
|
|
@ -530,14 +530,6 @@ int get_mp3file_info(int fd, struct mp3info *info)
|
|||
return bytecount;
|
||||
}
|
||||
|
||||
/* This is an MP3 header, 128kbit/s, with silence
|
||||
MPEG version and sample frequency are not set */
|
||||
static const unsigned char xing_frame_header[] = {
|
||||
0xff, 0xe2, 0x90, 0x64, 0x86, 0x1f
|
||||
};
|
||||
|
||||
static const char cooltext[] = "Rockbox rocks";
|
||||
|
||||
static void int2bytes(unsigned char *buf, int val)
|
||||
{
|
||||
buf[0] = (val >> 24) & 0xff;
|
||||
|
|
@ -602,55 +594,30 @@ int count_mp3_frames(int fd, int startpos, int filesize,
|
|||
}
|
||||
}
|
||||
|
||||
/* Note: mpeg_version and sample_rate are 2-bit values, as specified by the
|
||||
MPEG frame standard. See the tables above. */
|
||||
static const char cooltext[] = "Rockbox - rocks your box";
|
||||
|
||||
int create_xing_header(int fd, int startpos, int filesize,
|
||||
unsigned char *buf, int num_frames,
|
||||
int mpeg_version, int sample_rate,
|
||||
unsigned long header_template,
|
||||
void (*progressfunc)(int), bool generate_toc)
|
||||
{
|
||||
unsigned long header = 0;
|
||||
unsigned long saved_header = 0;
|
||||
struct mp3info info;
|
||||
int pos, last_pos;
|
||||
int i, j;
|
||||
int bytes;
|
||||
int filepos;
|
||||
int tocentry;
|
||||
int x;
|
||||
int index;
|
||||
unsigned char toc[100];
|
||||
|
||||
DEBUGF("create_xing_header()\n");
|
||||
|
||||
/* Create the frame header */
|
||||
memset(buf, 0, 1500);
|
||||
memcpy(buf, xing_frame_header, 6);
|
||||
|
||||
if(generate_toc)
|
||||
{
|
||||
lseek(fd, startpos, SEEK_SET);
|
||||
buf_init();
|
||||
|
||||
buf[36] = 'X';
|
||||
buf[36+1] = 'i';
|
||||
buf[36+2] = 'n';
|
||||
buf[36+3] = 'g';
|
||||
int2bytes(&buf[36+4], ((num_frames?VBR_FRAMES_FLAG:0) |
|
||||
(filesize?VBR_BYTES_FLAG:0) |
|
||||
(generate_toc?VBR_TOC_FLAG:0)));
|
||||
index = 36+8;
|
||||
if(num_frames)
|
||||
{
|
||||
int2bytes(&buf[index], num_frames);
|
||||
index += 4;
|
||||
}
|
||||
|
||||
if(filesize)
|
||||
{
|
||||
int2bytes(&buf[index], filesize - startpos);
|
||||
index += 4;
|
||||
}
|
||||
|
||||
if(generate_toc)
|
||||
{
|
||||
/* Generate filepos table */
|
||||
last_pos = 0;
|
||||
filepos = 0;
|
||||
|
|
@ -670,48 +637,90 @@ int create_xing_header(int fd, int startpos, int filesize,
|
|||
filepos += info.frame_size;
|
||||
}
|
||||
|
||||
/* Save one header for later use */
|
||||
/* Save a header for later use. Yes, we may be passed a header
|
||||
template in the header_template argument, but since we are
|
||||
reading headers from the stream anyway, we might as well
|
||||
use the ones we find. However, we only save one header, and
|
||||
we want to save one in te middle of the stream, just in case
|
||||
the first and the last headers are corrupt. */
|
||||
if(i == 1)
|
||||
saved_header = header;
|
||||
header_template = header;
|
||||
|
||||
if(progressfunc)
|
||||
{
|
||||
progressfunc(50 + i/2);
|
||||
}
|
||||
|
||||
tocentry = filepos * 256 / filesize;
|
||||
/* Fill in the TOC entry */
|
||||
toc[i] = filepos * 256 / filesize;
|
||||
|
||||
DEBUGF("Pos %d: %d relpos: %d filepos: %x tocentry: %x\n",
|
||||
i, pos, pos-last_pos, filepos, tocentry);
|
||||
|
||||
/* Fill in the TOC entry */
|
||||
buf[index + i] = tocentry;
|
||||
i, pos, pos-last_pos, filepos, toc[i]);
|
||||
|
||||
last_pos = pos;
|
||||
}
|
||||
|
||||
/* Copy the MPEG version and sample rate from the mpeg stream into
|
||||
the Xing header */
|
||||
saved_header &= (VERSION_MASK | SAMPLERATE_MASK);
|
||||
|
||||
buf[1] |= (saved_header >> 16) & 0xff;
|
||||
buf[2] |= (saved_header >> 8) & 0xff;
|
||||
}
|
||||
|
||||
/* Clear the frame */
|
||||
memset(buf, 0, 1500);
|
||||
|
||||
/* Use the template header and create a new one */
|
||||
mp3headerinfo(&info, header_template);
|
||||
|
||||
/* calculate position of VBR header */
|
||||
if ( info.version == MPEG_VERSION1 ) {
|
||||
if (info.channel_mode == 3) /* mono */
|
||||
index = 21;
|
||||
else
|
||||
{
|
||||
/* Fill in the MPEG version and sample rate into the Xing header */
|
||||
buf[1] |= mpeg_version << 3;
|
||||
buf[2] |= sample_rate << 2;
|
||||
index = 36;
|
||||
}
|
||||
else {
|
||||
if (info.channel_mode == 3) /* mono */
|
||||
index = 13;
|
||||
else
|
||||
index = 21;
|
||||
}
|
||||
|
||||
memcpy(buf + index + 100, cooltext, sizeof(cooltext));
|
||||
/* We ignore the Protection bit even if the rest of the stream is
|
||||
protected. (fixme?) */
|
||||
header = header_template & ~(BITRATE_MASK | PROTECTION_MASK);
|
||||
header |= 8 << 12; /* This gives us plenty of space, at least 192 bytes */
|
||||
|
||||
/* Write the header to the buffer */
|
||||
int2bytes(buf, header);
|
||||
|
||||
/* Now get the length of the newly created frame */
|
||||
header = BYTES2INT(buf[0], buf[1], buf[2], buf[3]);
|
||||
mp3headerinfo(&info, header);
|
||||
|
||||
/* Create the Xing data */
|
||||
buf[index] = 'X';
|
||||
buf[index+1] = 'i';
|
||||
buf[index+2] = 'n';
|
||||
buf[index+3] = 'g';
|
||||
int2bytes(&buf[index+4], ((num_frames?VBR_FRAMES_FLAG:0) |
|
||||
(filesize?VBR_BYTES_FLAG:0) |
|
||||
(generate_toc?VBR_TOC_FLAG:0)));
|
||||
index = index+8;
|
||||
if(num_frames)
|
||||
{
|
||||
int2bytes(&buf[index], num_frames);
|
||||
index += 4;
|
||||
}
|
||||
|
||||
if(filesize)
|
||||
{
|
||||
int2bytes(&buf[index], filesize - startpos);
|
||||
index += 4;
|
||||
}
|
||||
|
||||
/* Copy the TOC */
|
||||
memcpy(buf + index, toc, 100);
|
||||
|
||||
/* And some extra cool info */
|
||||
memcpy(buf + index + 100, cooltext, sizeof(cooltext));
|
||||
|
||||
#ifdef DEBUG
|
||||
for(i = 0;i < 417;i++)
|
||||
for(i = 0;i < info.framesize;i++)
|
||||
{
|
||||
if(i && !(i % 16))
|
||||
DEBUGF("\n");
|
||||
|
|
|
|||
|
|
@ -1266,6 +1266,7 @@ static void mpeg_thread(void)
|
|||
int amount_to_save;
|
||||
int writelen;
|
||||
int framelen;
|
||||
unsigned long saved_header;
|
||||
#endif
|
||||
|
||||
is_playing = false;
|
||||
|
|
@ -1840,10 +1841,10 @@ static void mpeg_thread(void)
|
|||
DEBUGF("Recording...\n");
|
||||
reset_mp3_buffer();
|
||||
|
||||
/* Advance the write pointer 4096+1500 bytes to make
|
||||
/* Advance the write pointer to make
|
||||
room for an ID3 tag plus a VBR header */
|
||||
mp3buf_write = 4096+1500;
|
||||
memset(mp3buf, 0, 4096+1500);
|
||||
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));
|
||||
|
|
@ -1884,13 +1885,16 @@ static void mpeg_thread(void)
|
|||
if(num_recorded_frames == 0x7ffff)
|
||||
num_recorded_frames = 0;
|
||||
|
||||
/* Read the first MP3 frame from the recorded stream */
|
||||
lseek(mpeg_file, MPEG_RESERVED_HEADER_SPACE, SEEK_SET);
|
||||
read(mpeg_file, &saved_header, 4);
|
||||
|
||||
framelen = create_xing_header(mpeg_file, 0, num_rec_bytes,
|
||||
mp3buf, num_recorded_frames,
|
||||
rec_version_index,
|
||||
rec_frequency_index,
|
||||
NULL, false);
|
||||
saved_header, NULL, false);
|
||||
|
||||
lseek(mpeg_file, 4096+1500-framelen, SEEK_SET);
|
||||
lseek(mpeg_file, MPEG_RESERVED_HEADER_SPACE-framelen,
|
||||
SEEK_SET);
|
||||
write(mpeg_file, mp3buf, framelen);
|
||||
close(mpeg_file);
|
||||
|
||||
|
|
@ -2823,7 +2827,8 @@ void mpeg_set_pitch(int pitch)
|
|||
|
||||
#ifdef HAVE_MAS3587F
|
||||
void mpeg_set_recording_options(int frequency, int quality,
|
||||
int source, int channel_mode)
|
||||
int source, int channel_mode,
|
||||
bool editable)
|
||||
{
|
||||
bool is_mpeg1;
|
||||
unsigned long val;
|
||||
|
|
@ -2844,6 +2849,11 @@ void mpeg_set_recording_options(int frequency, int quality,
|
|||
|
||||
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 */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue