diff options
-rw-r--r-- | apps/lang/english.lang | 5 | ||||
-rw-r--r-- | apps/onplay.c | 6 | ||||
-rw-r--r-- | apps/recorder/recording.c | 30 | ||||
-rw-r--r-- | apps/settings.c | 26 | ||||
-rw-r--r-- | apps/settings.h | 1 | ||||
-rw-r--r-- | apps/sound_menu.c | 7 | ||||
-rw-r--r-- | firmware/export/mp3data.h | 2 | ||||
-rw-r--r-- | firmware/export/mpeg.h | 6 | ||||
-rw-r--r-- | firmware/mp3data.c | 133 | ||||
-rw-r--r-- | firmware/mpeg.c | 26 |
10 files changed, 152 insertions, 90 deletions
diff --git a/apps/lang/english.lang b/apps/lang/english.lang index e080491e2c..15d9039018 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang | |||
@@ -1467,3 +1467,8 @@ id: LANG_INVERT_CURSOR | |||
1467 | desc: in settings_menu | 1467 | desc: in settings_menu |
1468 | eng: "Invert cursor" | 1468 | eng: "Invert cursor" |
1469 | new: | 1469 | new: |
1470 | |||
1471 | id: LANG_RECORDING_EDITABLE | ||
1472 | desc: Editable recordings setting | ||
1473 | eng: "Editable files" | ||
1474 | new: | ||
diff --git a/apps/onplay.c b/apps/onplay.c index 3ba4c1b49c..14e3cdd7a7 100644 --- a/apps/onplay.c +++ b/apps/onplay.c | |||
@@ -251,11 +251,11 @@ static bool vbr_fix(void) | |||
251 | flen, xingupdate); | 251 | flen, xingupdate); |
252 | 252 | ||
253 | if(num_frames) { | 253 | if(num_frames) { |
254 | /* Note: We don't need to pass any values for mpeg_version and | 254 | /* Note: We don't need to pass a template header because it will be |
255 | sample_rate because they will be extracted from the mpeg stream */ | 255 | taken from the mpeg stream */ |
256 | framelen = create_xing_header(fd, entry.first_frame_offset, | 256 | framelen = create_xing_header(fd, entry.first_frame_offset, |
257 | flen, xingbuf, num_frames, | 257 | flen, xingbuf, num_frames, |
258 | 0, 0, xingupdate, true); | 258 | 0, xingupdate, true); |
259 | 259 | ||
260 | /* Try to fit the Xing header first in the stream. Replace the existing | 260 | /* Try to fit the Xing header first in the stream. Replace the existing |
261 | VBR header if there is one, else see if there is room between the | 261 | VBR header if there is one, else see if there is room between the |
diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c index cf295db19c..14bd37d950 100644 --- a/apps/recorder/recording.c +++ b/apps/recorder/recording.c | |||
@@ -169,7 +169,8 @@ bool recording_screen(void) | |||
169 | mpeg_set_recording_options(global_settings.rec_frequency, | 169 | mpeg_set_recording_options(global_settings.rec_frequency, |
170 | global_settings.rec_quality, | 170 | global_settings.rec_quality, |
171 | global_settings.rec_source, | 171 | global_settings.rec_source, |
172 | global_settings.rec_channels); | 172 | global_settings.rec_channels, |
173 | global_settings.rec_editable); | ||
173 | 174 | ||
174 | set_gain(); | 175 | set_gain(); |
175 | 176 | ||
@@ -312,22 +313,29 @@ bool recording_screen(void) | |||
312 | mpeg_set_recording_options(global_settings.rec_frequency, | 313 | mpeg_set_recording_options(global_settings.rec_frequency, |
313 | global_settings.rec_quality, | 314 | global_settings.rec_quality, |
314 | global_settings.rec_source, | 315 | global_settings.rec_source, |
315 | global_settings.rec_channels); | 316 | global_settings.rec_channels, |
317 | global_settings.rec_editable); | ||
316 | 318 | ||
317 | set_gain(); | 319 | set_gain(); |
318 | update_countdown = 1; /* Update immediately */ | 320 | update_countdown = 1; /* Update immediately */ |
319 | break; | 321 | break; |
320 | 322 | ||
321 | case BUTTON_F2: | 323 | case BUTTON_F2: |
322 | if (f2_rec_screen()) | 324 | if(mpeg_status()) |
323 | return SYS_USB_CONNECTED; | 325 | { |
324 | update_countdown = 1; /* Update immediately */ | 326 | if (f2_rec_screen()) |
327 | return SYS_USB_CONNECTED; | ||
328 | update_countdown = 1; /* Update immediately */ | ||
329 | } | ||
325 | break; | 330 | break; |
326 | 331 | ||
327 | case BUTTON_F3: | 332 | case BUTTON_F3: |
328 | if (f3_rec_screen()) | 333 | if(mpeg_status()) |
329 | return SYS_USB_CONNECTED; | 334 | { |
330 | update_countdown = 1; /* Update immediately */ | 335 | if (f3_rec_screen()) |
336 | return SYS_USB_CONNECTED; | ||
337 | update_countdown = 1; /* Update immediately */ | ||
338 | } | ||
331 | break; | 339 | break; |
332 | 340 | ||
333 | } | 341 | } |
@@ -537,7 +545,8 @@ bool f2_rec_screen(void) | |||
537 | mpeg_set_recording_options(global_settings.rec_frequency, | 545 | mpeg_set_recording_options(global_settings.rec_frequency, |
538 | global_settings.rec_quality, | 546 | global_settings.rec_quality, |
539 | global_settings.rec_source, | 547 | global_settings.rec_source, |
540 | global_settings.rec_channels); | 548 | global_settings.rec_channels, |
549 | global_settings.rec_editable); | ||
541 | 550 | ||
542 | set_gain(); | 551 | set_gain(); |
543 | 552 | ||
@@ -621,7 +630,8 @@ bool f3_rec_screen(void) | |||
621 | mpeg_set_recording_options(global_settings.rec_frequency, | 630 | mpeg_set_recording_options(global_settings.rec_frequency, |
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, |
634 | global_settings.rec_editable); | ||
625 | 635 | ||
626 | set_gain(); | 636 | set_gain(); |
627 | 637 | ||
diff --git a/apps/settings.c b/apps/settings.c index 8c132c5f9b..8b74df852b 100644 --- a/apps/settings.c +++ b/apps/settings.c | |||
@@ -96,8 +96,8 @@ offset abs | |||
96 | 0x16 0x2a <(int) Byte offset into resume file> | 96 | 0x16 0x2a <(int) Byte offset into resume file> |
97 | 0x1a 0x2e <time until disk spindown> | 97 | 0x1a 0x2e <time until disk spindown> |
98 | 0x1b 0x2f <browse current, play selected, queue_resume> | 98 | 0x1b 0x2f <browse current, play selected, queue_resume> |
99 | 0x1c 0x30 <peak meter hold timeout (bit 0-4)>, | 99 | 0x1c 0x30 <peak meter hold timeout (bit 0-4), |
100 | peak_meter_performance (bit 7) | 100 | rec_editable (bit 7)> |
101 | 0x1d 0x31 <(int) queue resume index> | 101 | 0x1d 0x31 <(int) queue resume index> |
102 | 0x21 0x35 <repeat mode (bit 0-1), rec. channels (bit 2), | 102 | 0x21 0x35 <repeat mode (bit 0-1), rec. channels (bit 2), |
103 | mic gain (bit 4-7)> | 103 | mic gain (bit 4-7)> |
@@ -125,7 +125,7 @@ modified unless the header & checksum test fails. | |||
125 | 125 | ||
126 | Rest of config block, only saved to disk: | 126 | Rest of config block, only saved to disk: |
127 | 0xAE fade on pause/unpause/stop setting (bit 0) | 127 | 0xAE fade on pause/unpause/stop setting (bit 0) |
128 | 0xB0 peak meter clip hold timeout (bit 0-4) | 128 | 0xB0 peak meter clip hold timeout (bit 0-4), peak meter performance (bit 7) |
129 | 0xB1 peak meter release step size, peak_meter_dbfs (bit 7) | 129 | 0xB1 peak meter release step size, peak_meter_dbfs (bit 7) |
130 | 0xB2 peak meter min either in -db or in percent | 130 | 0xB2 peak meter min either in -db or in percent |
131 | 0xB3 peak meter max either in -db or in percent | 131 | 0xB3 peak meter max either in -db or in percent |
@@ -341,7 +341,8 @@ int settings_save( void ) | |||
341 | ((global_settings.play_selected & 1) << 1) | | 341 | ((global_settings.play_selected & 1) << 1) | |
342 | ((global_settings.queue_resume & 3) << 2)); | 342 | ((global_settings.queue_resume & 3) << 2)); |
343 | 343 | ||
344 | config_block[0x1c] = (unsigned char)global_settings.peak_meter_hold; | 344 | config_block[0x1c] = (unsigned char)global_settings.peak_meter_hold | |
345 | (global_settings.rec_editable?0x80:0); | ||
345 | 346 | ||
346 | memcpy(&config_block[0x1d], &global_settings.queue_resume_index, 4); | 347 | memcpy(&config_block[0x1d], &global_settings.queue_resume_index, 4); |
347 | 348 | ||
@@ -617,8 +618,11 @@ void settings_load(void) | |||
617 | global_settings.queue_resume = (config_block[0x1b] >> 2) & 3; | 618 | global_settings.queue_resume = (config_block[0x1b] >> 2) & 3; |
618 | } | 619 | } |
619 | 620 | ||
620 | if (config_block[0x1c] != 0xFF) | 621 | if (config_block[0x1c] != 0xFF) { |
621 | global_settings.peak_meter_hold = (config_block[0x1c]) & 0x1f; | 622 | global_settings.peak_meter_hold = (config_block[0x1c]) & 0x1f; |
623 | global_settings.rec_editable = | ||
624 | config_block[0x1c]?true:false; | ||
625 | } | ||
622 | 626 | ||
623 | if (config_block[0x1d] != 0xFF) | 627 | if (config_block[0x1d] != 0xFF) |
624 | memcpy(&global_settings.queue_resume_index, &config_block[0x1d], | 628 | memcpy(&global_settings.queue_resume_index, &config_block[0x1d], |
@@ -1029,6 +1033,9 @@ bool settings_load_config(char* file) | |||
1029 | static char* options[] = {"stereo", "mono"}; | 1033 | static char* options[] = {"stereo", "mono"}; |
1030 | set_cfg_option(&global_settings.rec_channels, value, options, 2); | 1034 | set_cfg_option(&global_settings.rec_channels, value, options, 2); |
1031 | } | 1035 | } |
1036 | else if (!strcasecmp(name, "editable recordings")) { | ||
1037 | set_cfg_bool(&global_settings.rec_editable, value); | ||
1038 | } | ||
1032 | #endif | 1039 | #endif |
1033 | else if (!strcasecmp(name, "idle poweroff")) { | 1040 | else if (!strcasecmp(name, "idle poweroff")) { |
1034 | static char* options[] = {"off","1","2","3","4","5","6","7","8", | 1041 | static char* options[] = {"off","1","2","3","4","5","6","7","8", |
@@ -1434,6 +1441,14 @@ bool settings_save_config(void) | |||
1434 | global_settings.rec_left_gain, | 1441 | global_settings.rec_left_gain, |
1435 | global_settings.rec_right_gain); | 1442 | global_settings.rec_right_gain); |
1436 | write(fd, buf, strlen(buf)); | 1443 | write(fd, buf, strlen(buf)); |
1444 | |||
1445 | { | ||
1446 | static char* options[] = {"off", "on"}; | ||
1447 | snprintf(buf, sizeof(buf), "editable recordings: %s\r\n", | ||
1448 | options[global_settings.rec_editable]); | ||
1449 | write(fd, buf, strlen(buf)); | ||
1450 | } | ||
1451 | |||
1437 | #endif | 1452 | #endif |
1438 | close(fd); | 1453 | close(fd); |
1439 | 1454 | ||
@@ -1467,6 +1482,7 @@ void settings_reset(void) { | |||
1467 | global_settings.rec_mic_gain = 8; | 1482 | global_settings.rec_mic_gain = 8; |
1468 | global_settings.rec_left_gain = 2; /* 0dB */ | 1483 | global_settings.rec_left_gain = 2; /* 0dB */ |
1469 | global_settings.rec_right_gain = 2; /* 0dB */ | 1484 | global_settings.rec_right_gain = 2; /* 0dB */ |
1485 | global_settings.rec_editable = false; | ||
1470 | global_settings.resume = RESUME_ASK; | 1486 | global_settings.resume = RESUME_ASK; |
1471 | global_settings.contrast = DEFAULT_CONTRAST_SETTING; | 1487 | global_settings.contrast = DEFAULT_CONTRAST_SETTING; |
1472 | global_settings.invert = DEFAULT_INVERT_SETTING; | 1488 | global_settings.invert = DEFAULT_INVERT_SETTING; |
diff --git a/apps/settings.h b/apps/settings.h index 7876a18afa..0ff7cb2102 100644 --- a/apps/settings.h +++ b/apps/settings.h | |||
@@ -74,6 +74,7 @@ struct user_settings | |||
74 | int rec_mic_gain; /* 0-15 */ | 74 | int rec_mic_gain; /* 0-15 */ |
75 | int rec_left_gain; /* 0-15 */ | 75 | int rec_left_gain; /* 0-15 */ |
76 | int rec_right_gain; /* 0-15 */ | 76 | int rec_right_gain; /* 0-15 */ |
77 | bool rec_editable; /* true means that the bit reservoir is off */ | ||
77 | 78 | ||
78 | /* device settings */ | 79 | /* device settings */ |
79 | 80 | ||
diff --git a/apps/sound_menu.c b/apps/sound_menu.c index 9ac95e46b8..84d389a47a 100644 --- a/apps/sound_menu.c +++ b/apps/sound_menu.c | |||
@@ -219,6 +219,12 @@ static bool recquality(void) | |||
219 | &global_settings.rec_quality, | 219 | &global_settings.rec_quality, |
220 | NULL, 1, 0, 7 ); | 220 | NULL, 1, 0, 7 ); |
221 | } | 221 | } |
222 | |||
223 | static bool receditable(void) | ||
224 | { | ||
225 | return set_bool(str(LANG_RECORDING_EDITABLE), | ||
226 | &global_settings.rec_editable); | ||
227 | } | ||
222 | #endif /* HAVE_MAS3587F */ | 228 | #endif /* HAVE_MAS3587F */ |
223 | 229 | ||
224 | static void set_chanconf(int val) | 230 | static void set_chanconf(int val) |
@@ -275,6 +281,7 @@ bool recording_menu(void) | |||
275 | { str(LANG_RECORDING_FREQUENCY), recfrequency }, | 281 | { str(LANG_RECORDING_FREQUENCY), recfrequency }, |
276 | { str(LANG_RECORDING_SOURCE), recsource }, | 282 | { str(LANG_RECORDING_SOURCE), recsource }, |
277 | { str(LANG_RECORDING_CHANNELS), recchannels }, | 283 | { str(LANG_RECORDING_CHANNELS), recchannels }, |
284 | { str(LANG_RECORDING_EDITABLE), receditable }, | ||
278 | }; | 285 | }; |
279 | 286 | ||
280 | m=menu_init( items, sizeof items / sizeof(struct menu_items) ); | 287 | m=menu_init( items, sizeof items / sizeof(struct menu_items) ); |
diff --git a/firmware/export/mp3data.h b/firmware/export/mp3data.h index d180935aa4..6b3ff83b1a 100644 --- a/firmware/export/mp3data.h +++ b/firmware/export/mp3data.h | |||
@@ -61,7 +61,7 @@ int count_mp3_frames(int fd, int startpos, int filesize, | |||
61 | void (*progressfunc)(int)); | 61 | void (*progressfunc)(int)); |
62 | int create_xing_header(int fd, int startpos, int filesize, | 62 | int create_xing_header(int fd, int startpos, int filesize, |
63 | unsigned char *buf, int num_frames, | 63 | unsigned char *buf, int num_frames, |
64 | int mpeg_version, int sample_rate, | 64 | unsigned long header_template, |
65 | void (*progressfunc)(int), bool generate_toc); | 65 | void (*progressfunc)(int), bool generate_toc); |
66 | 66 | ||
67 | #endif | 67 | #endif |
diff --git a/firmware/export/mpeg.h b/firmware/export/mpeg.h index e971aaac33..d939567f3d 100644 --- a/firmware/export/mpeg.h +++ b/firmware/export/mpeg.h | |||
@@ -32,6 +32,9 @@ | |||
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 | /* For ID3 info and VBR header */ | ||
36 | #define MPEG_RESERVED_HEADER_SPACE (4096 + 1500) | ||
37 | |||
35 | struct mpeg_debug | 38 | struct mpeg_debug |
36 | { | 39 | { |
37 | int mp3buflen; | 40 | int mp3buflen; |
@@ -84,7 +87,8 @@ void mpeg_init_recording(void); | |||
84 | void mpeg_init_playback(void); | 87 | void mpeg_init_playback(void); |
85 | void mpeg_record(char *filename); | 88 | void mpeg_record(char *filename); |
86 | void mpeg_set_recording_options(int frequency, int quality, | 89 | void mpeg_set_recording_options(int frequency, int quality, |
87 | int source, int channel_mode); | 90 | int source, int channel_mode, |
91 | bool editable); | ||
88 | void mpeg_set_recording_gain(int left, int right, int mic); | 92 | void mpeg_set_recording_gain(int left, int right, int mic); |
89 | unsigned long mpeg_recorded_time(void); | 93 | unsigned long mpeg_recorded_time(void); |
90 | unsigned long mpeg_num_recorded_bytes(void); | 94 | unsigned long mpeg_num_recorded_bytes(void); |
diff --git a/firmware/mp3data.c b/firmware/mp3data.c index 415d3bf3d1..1cbf8e54ee 100644 --- a/firmware/mp3data.c +++ b/firmware/mp3data.c | |||
@@ -530,14 +530,6 @@ int get_mp3file_info(int fd, struct mp3info *info) | |||
530 | return bytecount; | 530 | return bytecount; |
531 | } | 531 | } |
532 | 532 | ||
533 | /* This is an MP3 header, 128kbit/s, with silence | ||
534 | MPEG version and sample frequency are not set */ | ||
535 | static const unsigned char xing_frame_header[] = { | ||
536 | 0xff, 0xe2, 0x90, 0x64, 0x86, 0x1f | ||
537 | }; | ||
538 | |||
539 | static const char cooltext[] = "Rockbox rocks"; | ||
540 | |||
541 | static void int2bytes(unsigned char *buf, int val) | 533 | static void int2bytes(unsigned char *buf, int val) |
542 | { | 534 | { |
543 | buf[0] = (val >> 24) & 0xff; | 535 | buf[0] = (val >> 24) & 0xff; |
@@ -602,55 +594,30 @@ int count_mp3_frames(int fd, int startpos, int filesize, | |||
602 | } | 594 | } |
603 | } | 595 | } |
604 | 596 | ||
605 | /* Note: mpeg_version and sample_rate are 2-bit values, as specified by the | 597 | static const char cooltext[] = "Rockbox - rocks your box"; |
606 | MPEG frame standard. See the tables above. */ | 598 | |
607 | int create_xing_header(int fd, int startpos, int filesize, | 599 | int create_xing_header(int fd, int startpos, int filesize, |
608 | unsigned char *buf, int num_frames, | 600 | unsigned char *buf, int num_frames, |
609 | int mpeg_version, int sample_rate, | 601 | unsigned long header_template, |
610 | void (*progressfunc)(int), bool generate_toc) | 602 | void (*progressfunc)(int), bool generate_toc) |
611 | { | 603 | { |
612 | unsigned long header = 0; | 604 | unsigned long header = 0; |
613 | unsigned long saved_header = 0; | ||
614 | struct mp3info info; | 605 | struct mp3info info; |
615 | int pos, last_pos; | 606 | int pos, last_pos; |
616 | int i, j; | 607 | int i, j; |
617 | int bytes; | 608 | int bytes; |
618 | int filepos; | 609 | int filepos; |
619 | int tocentry; | ||
620 | int x; | 610 | int x; |
621 | int index; | 611 | int index; |
612 | unsigned char toc[100]; | ||
622 | 613 | ||
623 | DEBUGF("create_xing_header()\n"); | 614 | DEBUGF("create_xing_header()\n"); |
624 | 615 | ||
625 | /* Create the frame header */ | ||
626 | memset(buf, 0, 1500); | ||
627 | memcpy(buf, xing_frame_header, 6); | ||
628 | |||
629 | lseek(fd, startpos, SEEK_SET); | ||
630 | buf_init(); | ||
631 | |||
632 | buf[36] = 'X'; | ||
633 | buf[36+1] = 'i'; | ||
634 | buf[36+2] = 'n'; | ||
635 | buf[36+3] = 'g'; | ||
636 | int2bytes(&buf[36+4], ((num_frames?VBR_FRAMES_FLAG:0) | | ||
637 | (filesize?VBR_BYTES_FLAG:0) | | ||
638 | (generate_toc?VBR_TOC_FLAG:0))); | ||
639 | index = 36+8; | ||
640 | if(num_frames) | ||
641 | { | ||
642 | int2bytes(&buf[index], num_frames); | ||
643 | index += 4; | ||
644 | } | ||
645 | |||
646 | if(filesize) | ||
647 | { | ||
648 | int2bytes(&buf[index], filesize - startpos); | ||
649 | index += 4; | ||
650 | } | ||
651 | |||
652 | if(generate_toc) | 616 | if(generate_toc) |
653 | { | 617 | { |
618 | lseek(fd, startpos, SEEK_SET); | ||
619 | buf_init(); | ||
620 | |||
654 | /* Generate filepos table */ | 621 | /* Generate filepos table */ |
655 | last_pos = 0; | 622 | last_pos = 0; |
656 | filepos = 0; | 623 | filepos = 0; |
@@ -670,48 +637,90 @@ int create_xing_header(int fd, int startpos, int filesize, | |||
670 | filepos += info.frame_size; | 637 | filepos += info.frame_size; |
671 | } | 638 | } |
672 | 639 | ||
673 | /* Save one header for later use */ | 640 | /* Save a header for later use. Yes, we may be passed a header |
641 | template in the header_template argument, but since we are | ||
642 | reading headers from the stream anyway, we might as well | ||
643 | use the ones we find. However, we only save one header, and | ||
644 | we want to save one in te middle of the stream, just in case | ||
645 | the first and the last headers are corrupt. */ | ||
674 | if(i == 1) | 646 | if(i == 1) |
675 | saved_header = header; | 647 | header_template = header; |
676 | 648 | ||
677 | if(progressfunc) | 649 | if(progressfunc) |
678 | { | 650 | { |
679 | progressfunc(50 + i/2); | 651 | progressfunc(50 + i/2); |
680 | } | 652 | } |
681 | 653 | ||
682 | tocentry = filepos * 256 / filesize; | 654 | /* Fill in the TOC entry */ |
655 | toc[i] = filepos * 256 / filesize; | ||
683 | 656 | ||
684 | DEBUGF("Pos %d: %d relpos: %d filepos: %x tocentry: %x\n", | 657 | DEBUGF("Pos %d: %d relpos: %d filepos: %x tocentry: %x\n", |
685 | i, pos, pos-last_pos, filepos, tocentry); | 658 | i, pos, pos-last_pos, filepos, toc[i]); |
686 | |||
687 | /* Fill in the TOC entry */ | ||
688 | buf[index + i] = tocentry; | ||
689 | 659 | ||
690 | last_pos = pos; | 660 | last_pos = pos; |
691 | } | 661 | } |
662 | } | ||
663 | |||
664 | /* Clear the frame */ | ||
665 | memset(buf, 0, 1500); | ||
692 | 666 | ||
693 | /* Copy the MPEG version and sample rate from the mpeg stream into | 667 | /* Use the template header and create a new one */ |
694 | the Xing header */ | 668 | mp3headerinfo(&info, header_template); |
695 | saved_header &= (VERSION_MASK | SAMPLERATE_MASK); | 669 | |
670 | /* calculate position of VBR header */ | ||
671 | if ( info.version == MPEG_VERSION1 ) { | ||
672 | if (info.channel_mode == 3) /* mono */ | ||
673 | index = 21; | ||
674 | else | ||
675 | index = 36; | ||
676 | } | ||
677 | else { | ||
678 | if (info.channel_mode == 3) /* mono */ | ||
679 | index = 13; | ||
680 | else | ||
681 | index = 21; | ||
682 | } | ||
683 | |||
684 | /* We ignore the Protection bit even if the rest of the stream is | ||
685 | protected. (fixme?) */ | ||
686 | header = header_template & ~(BITRATE_MASK | PROTECTION_MASK); | ||
687 | header |= 8 << 12; /* This gives us plenty of space, at least 192 bytes */ | ||
688 | |||
689 | /* Write the header to the buffer */ | ||
690 | int2bytes(buf, header); | ||
696 | 691 | ||
697 | buf[1] |= (saved_header >> 16) & 0xff; | 692 | /* Now get the length of the newly created frame */ |
698 | buf[2] |= (saved_header >> 8) & 0xff; | 693 | mp3headerinfo(&info, header); |
694 | |||
695 | /* Create the Xing data */ | ||
696 | buf[index] = 'X'; | ||
697 | buf[index+1] = 'i'; | ||
698 | buf[index+2] = 'n'; | ||
699 | buf[index+3] = 'g'; | ||
700 | int2bytes(&buf[index+4], ((num_frames?VBR_FRAMES_FLAG:0) | | ||
701 | (filesize?VBR_BYTES_FLAG:0) | | ||
702 | (generate_toc?VBR_TOC_FLAG:0))); | ||
703 | index = index+8; | ||
704 | if(num_frames) | ||
705 | { | ||
706 | int2bytes(&buf[index], num_frames); | ||
707 | index += 4; | ||
699 | } | 708 | } |
700 | else | 709 | |
710 | if(filesize) | ||
701 | { | 711 | { |
702 | /* Fill in the MPEG version and sample rate into the Xing header */ | 712 | int2bytes(&buf[index], filesize - startpos); |
703 | buf[1] |= mpeg_version << 3; | 713 | index += 4; |
704 | buf[2] |= sample_rate << 2; | ||
705 | } | 714 | } |
706 | 715 | ||
716 | /* Copy the TOC */ | ||
717 | memcpy(buf + index, toc, 100); | ||
718 | |||
719 | /* And some extra cool info */ | ||
707 | memcpy(buf + index + 100, cooltext, sizeof(cooltext)); | 720 | memcpy(buf + index + 100, cooltext, sizeof(cooltext)); |
708 | 721 | ||
709 | /* Now get the length of the newly created frame */ | ||
710 | header = BYTES2INT(buf[0], buf[1], buf[2], buf[3]); | ||
711 | mp3headerinfo(&info, header); | ||
712 | |||
713 | #ifdef DEBUG | 722 | #ifdef DEBUG |
714 | for(i = 0;i < 417;i++) | 723 | for(i = 0;i < info.framesize;i++) |
715 | { | 724 | { |
716 | if(i && !(i % 16)) | 725 | if(i && !(i % 16)) |
717 | DEBUGF("\n"); | 726 | DEBUGF("\n"); |
diff --git a/firmware/mpeg.c b/firmware/mpeg.c index 7e48040da2..11837d608e 100644 --- a/firmware/mpeg.c +++ b/firmware/mpeg.c | |||
@@ -1266,6 +1266,7 @@ static void mpeg_thread(void) | |||
1266 | int amount_to_save; | 1266 | int amount_to_save; |
1267 | int writelen; | 1267 | int writelen; |
1268 | int framelen; | 1268 | int framelen; |
1269 | unsigned long saved_header; | ||
1269 | #endif | 1270 | #endif |
1270 | 1271 | ||
1271 | is_playing = false; | 1272 | is_playing = false; |
@@ -1840,10 +1841,10 @@ static void mpeg_thread(void) | |||
1840 | DEBUGF("Recording...\n"); | 1841 | DEBUGF("Recording...\n"); |
1841 | reset_mp3_buffer(); | 1842 | reset_mp3_buffer(); |
1842 | 1843 | ||
1843 | /* Advance the write pointer 4096+1500 bytes to make | 1844 | /* Advance the write pointer to make |
1844 | room for an ID3 tag plus a VBR header */ | 1845 | room for an ID3 tag plus a VBR header */ |
1845 | mp3buf_write = 4096+1500; | 1846 | mp3buf_write = MPEG_RESERVED_HEADER_SPACE; |
1846 | memset(mp3buf, 0, 4096+1500); | 1847 | memset(mp3buf, 0, MPEG_RESERVED_HEADER_SPACE); |
1847 | 1848 | ||
1848 | /* Insert the ID3 header */ | 1849 | /* Insert the ID3 header */ |
1849 | memcpy(mp3buf, empty_id3_header, sizeof(empty_id3_header)); | 1850 | memcpy(mp3buf, empty_id3_header, sizeof(empty_id3_header)); |
@@ -1883,14 +1884,17 @@ static void mpeg_thread(void) | |||
1883 | we can no longer trust it */ | 1884 | we can no longer trust it */ |
1884 | if(num_recorded_frames == 0x7ffff) | 1885 | if(num_recorded_frames == 0x7ffff) |
1885 | num_recorded_frames = 0; | 1886 | num_recorded_frames = 0; |
1887 | |||
1888 | /* Read the first MP3 frame from the recorded stream */ | ||
1889 | lseek(mpeg_file, MPEG_RESERVED_HEADER_SPACE, SEEK_SET); | ||
1890 | read(mpeg_file, &saved_header, 4); | ||
1886 | 1891 | ||
1887 | framelen = create_xing_header(mpeg_file, 0, num_rec_bytes, | 1892 | framelen = create_xing_header(mpeg_file, 0, num_rec_bytes, |
1888 | mp3buf, num_recorded_frames, | 1893 | mp3buf, num_recorded_frames, |
1889 | rec_version_index, | 1894 | saved_header, NULL, false); |
1890 | rec_frequency_index, | ||
1891 | NULL, false); | ||
1892 | 1895 | ||
1893 | lseek(mpeg_file, 4096+1500-framelen, SEEK_SET); | 1896 | lseek(mpeg_file, MPEG_RESERVED_HEADER_SPACE-framelen, |
1897 | SEEK_SET); | ||
1894 | write(mpeg_file, mp3buf, framelen); | 1898 | write(mpeg_file, mp3buf, framelen); |
1895 | close(mpeg_file); | 1899 | close(mpeg_file); |
1896 | 1900 | ||
@@ -2823,7 +2827,8 @@ void mpeg_set_pitch(int pitch) | |||
2823 | 2827 | ||
2824 | #ifdef HAVE_MAS3587F | 2828 | #ifdef HAVE_MAS3587F |
2825 | void mpeg_set_recording_options(int frequency, int quality, | 2829 | void mpeg_set_recording_options(int frequency, int quality, |
2826 | int source, int channel_mode) | 2830 | int source, int channel_mode, |
2831 | bool editable) | ||
2827 | { | 2832 | { |
2828 | bool is_mpeg1; | 2833 | bool is_mpeg1; |
2829 | unsigned long val; | 2834 | unsigned long val; |
@@ -2844,6 +2849,11 @@ void mpeg_set_recording_options(int frequency, int quality, | |||
2844 | 2849 | ||
2845 | DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f0, %x)\n", val); | 2850 | DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f0, %x)\n", val); |
2846 | 2851 | ||
2852 | val = editable?4:0; | ||
2853 | mas_writemem(MAS_BANK_D0, 0x7f9, &val,1); | ||
2854 | |||
2855 | DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f9, %x)\n", val); | ||
2856 | |||
2847 | val = ((!is_recording << 10) | /* Monitoring */ | 2857 | val = ((!is_recording << 10) | /* Monitoring */ |
2848 | ((source < 2)?1:2) << 8) | /* Input select */ | 2858 | ((source < 2)?1:2) << 8) | /* Input select */ |
2849 | (1 << 5) | /* SDO strobe invert */ | 2859 | (1 << 5) | /* SDO strobe invert */ |