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:
Linus Nielsen Feltzing 2003-04-20 22:00:30 +00:00
parent c6fb565dd9
commit 478da628f0
10 changed files with 153 additions and 91 deletions

View file

@ -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:

View file

@ -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

View file

@ -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 (f2_rec_screen())
return SYS_USB_CONNECTED;
update_countdown = 1; /* Update immediately */
if(mpeg_status())
{
if (f2_rec_screen())
return SYS_USB_CONNECTED;
update_countdown = 1; /* Update immediately */
}
break;
case BUTTON_F3:
if (f3_rec_screen())
return SYS_USB_CONNECTED;
update_countdown = 1; /* Update immediately */
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();

View file

@ -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;

View file

@ -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 */

View file

@ -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) );

View file

@ -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

View file

@ -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);

View file

@ -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);
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)
{
lseek(fd, startpos, SEEK_SET);
buf_init();
/* 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;
}
else
{
/* Fill in the MPEG version and sample rate into the Xing header */
buf[1] |= mpeg_version << 3;
buf[2] |= sample_rate << 2;
}
memcpy(buf + index + 100, cooltext, sizeof(cooltext));
/* 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
index = 36;
}
else {
if (info.channel_mode == 3) /* mono */
index = 13;
else
index = 21;
}
/* 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");

View file

@ -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 */