diff options
author | Linus Nielsen Feltzing <linus@haxx.se> | 2003-04-20 22:00:30 +0000 |
---|---|---|
committer | Linus Nielsen Feltzing <linus@haxx.se> | 2003-04-20 22:00:30 +0000 |
commit | 478da628f0eb5fb3b5163dab459927ada52badfc (patch) | |
tree | 04e27d8bd6122a23c0fe483c4d35e149d1953179 /firmware | |
parent | c6fb565dd98d2da0cd5ba0e29b73c49617edcb9c (diff) | |
download | rockbox-478da628f0eb5fb3b5163dab459927ada52badfc.tar.gz rockbox-478da628f0eb5fb3b5163dab459927ada52badfc.zip |
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
Diffstat (limited to 'firmware')
-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 |
4 files changed, 95 insertions, 72 deletions
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 */ |