diff options
Diffstat (limited to 'firmware/mpeg.c')
-rw-r--r-- | firmware/mpeg.c | 320 |
1 files changed, 198 insertions, 122 deletions
diff --git a/firmware/mpeg.c b/firmware/mpeg.c index 9470e7d84b..92f11e1b84 100644 --- a/firmware/mpeg.c +++ b/firmware/mpeg.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include "string.h" | 26 | #include "string.h" |
27 | #include <kernel.h> | 27 | #include <kernel.h> |
28 | #include "thread.h" | 28 | #include "thread.h" |
29 | #include "mp3data.h" | ||
29 | #ifndef SIMULATOR | 30 | #ifndef SIMULATOR |
30 | #include "i2c.h" | 31 | #include "i2c.h" |
31 | #include "mas.h" | 32 | #include "mas.h" |
@@ -302,7 +303,7 @@ static void remove_all_tags(void) | |||
302 | static void set_elapsed(struct mp3entry* id3) | 303 | static void set_elapsed(struct mp3entry* id3) |
303 | { | 304 | { |
304 | if ( id3->vbr ) { | 305 | if ( id3->vbr ) { |
305 | if ( id3->vbrflags & VBR_TOC_FLAG ) { | 306 | if ( id3->has_toc ) { |
306 | /* calculate elapsed time using TOC */ | 307 | /* calculate elapsed time using TOC */ |
307 | int i; | 308 | int i; |
308 | unsigned int remainder, plen, relpos, nextpos; | 309 | unsigned int remainder, plen, relpos, nextpos; |
@@ -1482,7 +1483,7 @@ static void mpeg_thread(void) | |||
1482 | 1483 | ||
1483 | if (id3->vbr) | 1484 | if (id3->vbr) |
1484 | { | 1485 | { |
1485 | if (id3->vbrflags & VBR_TOC_FLAG) | 1486 | if (id3->has_toc) |
1486 | { | 1487 | { |
1487 | /* Use the TOC to find the new position */ | 1488 | /* Use the TOC to find the new position */ |
1488 | unsigned int percent, remainder; | 1489 | unsigned int percent, remainder; |
@@ -1528,10 +1529,10 @@ static void mpeg_thread(void) | |||
1528 | transition properly to the next song */ | 1529 | transition properly to the next song */ |
1529 | newpos = id3->filesize - id3->id3v1len - 1; | 1530 | newpos = id3->filesize - id3->id3v1len - 1; |
1530 | } | 1531 | } |
1531 | else if (newpos < (int)id3->id3v2len) | 1532 | else if (newpos < (int)id3->first_frame_offset) |
1532 | { | 1533 | { |
1533 | /* skip past id3v2 tag */ | 1534 | /* skip past id3v2 tag and other leading garbage */ |
1534 | newpos = id3->id3v2len; | 1535 | newpos = id3->first_frame_offset; |
1535 | } | 1536 | } |
1536 | 1537 | ||
1537 | if (mpeg_file >= 0) | 1538 | if (mpeg_file >= 0) |
@@ -1720,7 +1721,7 @@ static void mpeg_thread(void) | |||
1720 | t2 = current_tick; | 1721 | t2 = current_tick; |
1721 | DEBUGF("time: %d\n", t2 - t1); | 1722 | DEBUGF("time: %d\n", t2 - t1); |
1722 | DEBUGF("R: %x\n", len); | 1723 | DEBUGF("R: %x\n", len); |
1723 | 1724 | ||
1724 | /* Now make sure that we don't feed the MAS with ID3V1 | 1725 | /* Now make sure that we don't feed the MAS with ID3V1 |
1725 | data */ | 1726 | data */ |
1726 | if (len < amount_to_read) | 1727 | if (len < amount_to_read) |
@@ -1734,19 +1735,19 @@ static void mpeg_thread(void) | |||
1734 | { | 1735 | { |
1735 | if(tagptr >= mp3buflen) | 1736 | if(tagptr >= mp3buflen) |
1736 | tagptr -= mp3buflen; | 1737 | tagptr -= mp3buflen; |
1737 | 1738 | ||
1738 | if(mp3buf[tagptr] != tag[i]) | 1739 | if(mp3buf[tagptr] != tag[i]) |
1739 | taglen = 0; | 1740 | taglen = 0; |
1740 | 1741 | ||
1741 | tagptr++; | 1742 | tagptr++; |
1742 | } | 1743 | } |
1743 | 1744 | ||
1744 | if(taglen) | 1745 | if(taglen) |
1745 | { | 1746 | { |
1746 | /* Skip id3v1 tag */ | 1747 | /* Skip id3v1 tag */ |
1747 | DEBUGF("Skipping ID3v1 tag\n"); | 1748 | DEBUGF("Skipping ID3v1 tag\n"); |
1748 | len -= taglen; | 1749 | len -= taglen; |
1749 | 1750 | ||
1750 | /* The very rare case when the entire tag | 1751 | /* The very rare case when the entire tag |
1751 | wasn't read in this read() call must be | 1752 | wasn't read in this read() call must be |
1752 | taken care of */ | 1753 | taken care of */ |
@@ -1819,131 +1820,135 @@ static void mpeg_thread(void) | |||
1819 | } | 1820 | } |
1820 | else | 1821 | else |
1821 | { | 1822 | { |
1822 | /* This doesn't look neccessary... | 1823 | queue_wait(&mpeg_queue, &ev); |
1823 | yield(); | 1824 | switch(ev.id) |
1824 | if(!queue_empty(&mpeg_queue)) | 1825 | { |
1825 | {*/ | 1826 | case MPEG_RECORD: |
1826 | queue_wait(&mpeg_queue, &ev); | 1827 | DEBUGF("Recording...\n"); |
1827 | switch(ev.id) | 1828 | reset_mp3_buffer(); |
1828 | { | ||
1829 | case MPEG_RECORD: | ||
1830 | DEBUGF("Recording...\n"); | ||
1831 | reset_mp3_buffer(); | ||
1832 | start_recording(); | ||
1833 | demand_irq_enable(true); | ||
1834 | mpeg_file = creat(recording_filename, O_WRONLY); | ||
1835 | |||
1836 | if(mpeg_file < 0) | ||
1837 | panicf("recfile: %d", mpeg_file); | ||
1838 | |||
1839 | close(mpeg_file); | ||
1840 | mpeg_file = -1; | ||
1841 | break; | ||
1842 | |||
1843 | case MPEG_STOP: | ||
1844 | DEBUGF("MPEG_STOP\n"); | ||
1845 | demand_irq_enable(false); | ||
1846 | stop_recording(); | ||
1847 | |||
1848 | /* Save the remaining data in the buffer */ | ||
1849 | stop_pending = true; | ||
1850 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); | ||
1851 | break; | ||
1852 | 1829 | ||
1853 | case MPEG_STOP_DONE: | 1830 | /* Advance the write pointer 4096+417 bytes to make |
1854 | DEBUGF("MPEG_STOP_DONE\n"); | 1831 | room for an ID3 tag plus a VBR header */ |
1832 | mp3buf_write = 4096+417; | ||
1833 | memset(mp3buf, 0, 4096+417); | ||
1855 | 1834 | ||
1856 | if(mpeg_file >= 0) | 1835 | start_recording(); |
1857 | close(mpeg_file); | 1836 | demand_irq_enable(true); |
1858 | mpeg_file = -1; | 1837 | |
1838 | mpeg_file = creat(recording_filename, O_WRONLY); | ||
1839 | |||
1840 | if(mpeg_file < 0) | ||
1841 | panicf("recfile: %d", mpeg_file); | ||
1859 | 1842 | ||
1843 | |||
1844 | close(mpeg_file); | ||
1845 | |||
1846 | mpeg_file = -1; | ||
1847 | break; | ||
1848 | |||
1849 | case MPEG_STOP: | ||
1850 | DEBUGF("MPEG_STOP\n"); | ||
1851 | demand_irq_enable(false); | ||
1852 | stop_recording(); | ||
1853 | |||
1854 | /* Save the remaining data in the buffer */ | ||
1855 | stop_pending = true; | ||
1856 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); | ||
1857 | break; | ||
1858 | |||
1859 | case MPEG_STOP_DONE: | ||
1860 | DEBUGF("MPEG_STOP_DONE\n"); | ||
1861 | |||
1862 | if(mpeg_file >= 0) | ||
1863 | close(mpeg_file); | ||
1864 | mpeg_file = -1; | ||
1865 | |||
1860 | #ifdef DEBUG1 | 1866 | #ifdef DEBUG1 |
1867 | { | ||
1868 | int i; | ||
1869 | for(i = 0;i < 512;i++) | ||
1861 | { | 1870 | { |
1862 | int i; | 1871 | DEBUGF("%d - %d us (%d bytes)\n", |
1863 | for(i = 0;i < 512;i++) | 1872 | timing_info[i*2], |
1864 | { | 1873 | (timing_info[i*2+1] & 0xffff) * |
1865 | DEBUGF("%d - %d us (%d bytes)\n", | 1874 | 10000 / 13824, |
1866 | timing_info[i*2], | 1875 | timing_info[i*2+1] >> 16); |
1867 | (timing_info[i*2+1] & 0xffff) * | ||
1868 | 10000 / 13824, | ||
1869 | timing_info[i*2+1] >> 16); | ||
1870 | } | ||
1871 | } | 1876 | } |
1877 | } | ||
1872 | #endif | 1878 | #endif |
1873 | mpeg_stop_done = true; | 1879 | mpeg_stop_done = true; |
1874 | break; | 1880 | break; |
1875 | 1881 | ||
1876 | case MPEG_SAVE_DATA: | 1882 | case MPEG_SAVE_DATA: |
1877 | amount_to_save = mp3buf_write - mp3buf_read; | 1883 | amount_to_save = mp3buf_write - mp3buf_read; |
1878 | 1884 | ||
1879 | /* If the result is negative, the write index has | 1885 | /* If the result is negative, the write index has |
1880 | wrapped */ | 1886 | wrapped */ |
1881 | if(amount_to_save < 0) | 1887 | if(amount_to_save < 0) |
1882 | { | 1888 | { |
1883 | amount_to_save += mp3buflen; | 1889 | amount_to_save += mp3buflen; |
1884 | } | 1890 | } |
1885 | 1891 | ||
1886 | DEBUGF("r: %x w: %x\n", mp3buf_read, mp3buf_write); | 1892 | DEBUGF("r: %x w: %x\n", mp3buf_read, mp3buf_write); |
1887 | DEBUGF("ats: %x\n", amount_to_save); | 1893 | DEBUGF("ats: %x\n", amount_to_save); |
1888 | /* Save data only if the buffer is getting full, | 1894 | /* Save data only if the buffer is getting full, |
1889 | or if we should stop recording */ | 1895 | or if we should stop recording */ |
1890 | if(amount_to_save) | 1896 | if(amount_to_save) |
1897 | { | ||
1898 | if(mp3buflen - amount_to_save < MPEG_LOW_WATER || | ||
1899 | stop_pending) | ||
1891 | { | 1900 | { |
1892 | if(mp3buflen - amount_to_save < MPEG_LOW_WATER || | 1901 | int rc; |
1893 | stop_pending) | 1902 | |
1894 | { | 1903 | /* Only save up to the end of the buffer */ |
1895 | int rc; | 1904 | writelen = MIN(amount_to_save, |
1896 | 1905 | mp3buflen - mp3buf_read); | |
1897 | /* Only save up to the end of the buffer */ | 1906 | |
1898 | writelen = MIN(amount_to_save, | 1907 | DEBUGF("wrl: %x\n", writelen); |
1899 | mp3buflen - mp3buf_read); | 1908 | mpeg_file = open(recording_filename, |
1900 | 1909 | O_WRONLY| O_APPEND); | |
1901 | DEBUGF("wrl: %x\n", writelen); | 1910 | if(mpeg_file < 0) |
1902 | mpeg_file = open(recording_filename, | 1911 | panicf("rec open: %d", mpeg_file); |
1903 | O_WRONLY| O_APPEND); | 1912 | |
1904 | if(mpeg_file < 0) | 1913 | rc = write(mpeg_file, mp3buf + mp3buf_read, |
1905 | panicf("rec open: %d", mpeg_file); | 1914 | writelen); |
1906 | 1915 | ||
1907 | rc = write(mpeg_file, mp3buf + mp3buf_read, | 1916 | if(rc < 0) |
1908 | writelen); | 1917 | panicf("rec wrt: %d", rc); |
1909 | 1918 | ||
1910 | if(rc < 0) | 1919 | rc = close(mpeg_file); |
1911 | panicf("rec wrt: %d", rc); | 1920 | if(rc < 0) |
1912 | 1921 | panicf("rec cls: %d", rc); | |
1913 | rc = close(mpeg_file); | 1922 | |
1914 | if(rc < 0) | 1923 | mpeg_file = -1; |
1915 | panicf("rec cls: %d", rc); | 1924 | DEBUGF("rc: %x\n", rc); |
1916 | 1925 | ||
1917 | mpeg_file = -1; | 1926 | mp3buf_read += amount_to_save; |
1918 | DEBUGF("rc: %x\n", rc); | 1927 | if(mp3buf_read >= mp3buflen) |
1919 | 1928 | mp3buf_read = 0; | |
1920 | mp3buf_read += amount_to_save; | 1929 | |
1921 | if(mp3buf_read >= mp3buflen) | 1930 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); |
1922 | mp3buf_read = 0; | ||
1923 | |||
1924 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); | ||
1925 | } | ||
1926 | else | ||
1927 | { | ||
1928 | saving = false; | ||
1929 | } | ||
1930 | } | 1931 | } |
1931 | else | 1932 | else |
1932 | { | 1933 | { |
1933 | /* We have saved all data, | ||
1934 | time to stop for real */ | ||
1935 | if(stop_pending) | ||
1936 | queue_post(&mpeg_queue, MPEG_STOP_DONE, 0); | ||
1937 | saving = false; | 1934 | saving = false; |
1938 | } | 1935 | } |
1939 | break; | 1936 | } |
1940 | 1937 | else | |
1941 | case MPEG_INIT_PLAYBACK: | 1938 | { |
1942 | init_playback(); | 1939 | /* We have saved all data, |
1943 | init_playback_done = true; | 1940 | time to stop for real */ |
1944 | break; | 1941 | if(stop_pending) |
1945 | } | 1942 | queue_post(&mpeg_queue, MPEG_STOP_DONE, 0); |
1946 | /*}*/ | 1943 | saving = false; |
1944 | } | ||
1945 | break; | ||
1946 | |||
1947 | case MPEG_INIT_PLAYBACK: | ||
1948 | init_playback(); | ||
1949 | init_playback_done = true; | ||
1950 | break; | ||
1951 | } | ||
1947 | } | 1952 | } |
1948 | #endif | 1953 | #endif |
1949 | } | 1954 | } |
@@ -2981,3 +2986,74 @@ void mpeg_init(int volume, int bass, int treble, int balance, int loudness, | |||
2981 | dbg_cnt2us(0); | 2986 | dbg_cnt2us(0); |
2982 | #endif | 2987 | #endif |
2983 | } | 2988 | } |
2989 | |||
2990 | int d_1; | ||
2991 | int d_2; | ||
2992 | |||
2993 | int mpeg_create_xing_header(char *filename, void (*progressfunc)(int)) | ||
2994 | { | ||
2995 | struct mp3entry entry; | ||
2996 | char xingbuf[417]; | ||
2997 | int fd; | ||
2998 | int rc; | ||
2999 | int flen; | ||
3000 | int num_frames; | ||
3001 | int fpos; | ||
3002 | |||
3003 | if(progressfunc) | ||
3004 | progressfunc(0); | ||
3005 | |||
3006 | rc = mp3info(&entry, filename); | ||
3007 | if(rc < 0) | ||
3008 | return rc * 10 - 1; | ||
3009 | |||
3010 | fd = open(filename, O_RDWR); | ||
3011 | if(fd < 0) | ||
3012 | return fd * 10 - 2; | ||
3013 | |||
3014 | flen = lseek(fd, 0, SEEK_END); | ||
3015 | |||
3016 | d_1 = entry.first_frame_offset; | ||
3017 | d_2 = entry.filesize; | ||
3018 | |||
3019 | if(progressfunc) | ||
3020 | progressfunc(0); | ||
3021 | |||
3022 | num_frames = count_mp3_frames(fd, entry.first_frame_offset, | ||
3023 | flen, | ||
3024 | progressfunc); | ||
3025 | |||
3026 | create_xing_header(fd, entry.first_frame_offset, | ||
3027 | flen, xingbuf, num_frames, progressfunc); | ||
3028 | |||
3029 | /* Try to fit the Xing header first in the stream. Replace the existing | ||
3030 | Xing header if there is one, else see if there is room between the | ||
3031 | ID3 tag and the first MP3 frame. */ | ||
3032 | if(entry.xing_header_pos) | ||
3033 | { | ||
3034 | /* Reuse existing Xing header */ | ||
3035 | fpos = entry.xing_header_pos; | ||
3036 | } | ||
3037 | else | ||
3038 | { | ||
3039 | /* Any room between ID3 tag and first MP3 frame? */ | ||
3040 | if(entry.first_frame_offset - entry.id3v2len > 417) | ||
3041 | { | ||
3042 | fpos = entry.first_frame_offset - 417; | ||
3043 | } | ||
3044 | else | ||
3045 | { | ||
3046 | close(fd); | ||
3047 | return -3; | ||
3048 | } | ||
3049 | } | ||
3050 | |||
3051 | lseek(fd, fpos, SEEK_SET); | ||
3052 | write(fd, xingbuf, 417); | ||
3053 | close(fd); | ||
3054 | |||
3055 | if(progressfunc) | ||
3056 | progressfunc(100); | ||
3057 | |||
3058 | return 0; | ||
3059 | } | ||