summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/mpeg.c461
-rw-r--r--firmware/mpeg.h13
2 files changed, 420 insertions, 54 deletions
diff --git a/firmware/mpeg.c b/firmware/mpeg.c
index 206e67d3d3..d830b0aac5 100644
--- a/firmware/mpeg.c
+++ b/firmware/mpeg.c
@@ -37,6 +37,12 @@
37 37
38extern void bitswap(unsigned char *data, int length); 38extern void bitswap(unsigned char *data, int length);
39 39
40#ifdef HAVE_MAS3587F
41static void init_recording(void);
42static void init_playback(void);
43static void start_recording(void);
44#endif
45
40#ifndef SIMULATOR 46#ifndef SIMULATOR
41static int get_unplayed_space(void); 47static int get_unplayed_space(void);
42static int get_unswapped_space(void); 48static int get_unswapped_space(void);
@@ -50,8 +56,19 @@ static int get_unswapped_space(void);
50#define MPEG_PREV 6 56#define MPEG_PREV 6
51#define MPEG_FF_REWIND 7 57#define MPEG_FF_REWIND 7
52#define MPEG_FLUSH_RELOAD 8 58#define MPEG_FLUSH_RELOAD 8
59#define MPEG_RECORD 9
60#define MPEG_INIT_RECORDING 10
61#define MPEG_INIT_PLAYBACK 11
53#define MPEG_NEED_DATA 100 62#define MPEG_NEED_DATA 100
54#define MPEG_TRACK_CHANGE 101 63#define MPEG_TRACK_CHANGE 101
64#define MPEG_SAVE_DATA 102
65#define MPEG_STOP_DONE 103
66
67enum
68{
69 MPEG_DECODER,
70 MPEG_ENCODER
71} mpeg_mode;
55 72
56extern char* playlist_peek(int steps); 73extern char* playlist_peek(int steps);
57extern int playlist_next(int steps); 74extern int playlist_next(int steps);
@@ -67,7 +84,10 @@ static char *units[] =
67 "dB", /* Loudness */ 84 "dB", /* Loudness */
68 "%", /* Bass boost */ 85 "%", /* Bass boost */
69 "", /* AVC */ 86 "", /* AVC */
70 "" /* Channels */ 87 "", /* Channels */
88 "dB", /* Left gain */
89 "dB", /* Right gain */
90 "dB", /* Mic gain */
71}; 91};
72 92
73static int numdecimals[] = 93static int numdecimals[] =
@@ -79,7 +99,10 @@ static int numdecimals[] =
79 0, /* Loudness */ 99 0, /* Loudness */
80 0, /* Bass boost */ 100 0, /* Bass boost */
81 0, /* AVC */ 101 0, /* AVC */
82 0 /* Channels */ 102 0, /* Channels */
103 1, /* Left gain */
104 1, /* Right gain */
105 1, /* Mic gain */
83}; 106};
84 107
85static int minval[] = 108static int minval[] =
@@ -91,41 +114,50 @@ static int minval[] =
91 0, /* Loudness */ 114 0, /* Loudness */
92 0, /* Bass boost */ 115 0, /* Bass boost */
93 -1, /* AVC */ 116 -1, /* AVC */
94 0 /* Channels */ 117 0, /* Channels */
118 0, /* Left gain */
119 0, /* Right gain */
120 0, /* Mic gain */
95}; 121};
96 122
97static int maxval[] = 123static int maxval[] =
98{ 124{
99 100, /* Volume */ 125 100, /* Volume */
100#ifdef HAVE_MAS3587F 126#ifdef HAVE_MAS3587F
101 24, /* Bass */ 127 24, /* Bass */
102 24, /* Treble */ 128 24, /* Treble */
103#else 129#else
104 30, /* Bass */ 130 30, /* Bass */
105 30, /* Treble */ 131 30, /* Treble */
106#endif 132#endif
107 50, /* Balance */ 133 50, /* Balance */
108 17, /* Loudness */ 134 17, /* Loudness */
109 10, /* Bass boost */ 135 10, /* Bass boost */
110 3, /* AVC */ 136 3, /* AVC */
111 3 /* Channels */ 137 3, /* Channels */
138 15, /* Left gain */
139 15, /* Right gain */
140 15, /* Mic gain */
112}; 141};
113 142
114static int defaultval[] = 143static int defaultval[] =
115{ 144{
116 70, /* Volume */ 145 70, /* Volume */
117#ifdef HAVE_MAS3587F 146#ifdef HAVE_MAS3587F
118 12+6, /* Bass */ 147 12+6, /* Bass */
119 12+6, /* Treble */ 148 12+6, /* Treble */
120#else 149#else
121 15+7, /* Bass */ 150 15+7, /* Bass */
122 15+7, /* Treble */ 151 15+7, /* Treble */
123#endif 152#endif
124 0, /* Balance */ 153 0, /* Balance */
125 0, /* Loudness */ 154 0, /* Loudness */
126 0, /* Bass boost */ 155 0, /* Bass boost */
127 0, /* AVC */ 156 0, /* AVC */
128 0 /* Channels */ 157 0, /* Channels */
158 8, /* Left gain */
159 2, /* Right gain */
160 2, /* Mic gain */
129}; 161};
130 162
131char *mpeg_sound_unit(int setting) 163char *mpeg_sound_unit(int setting)
@@ -421,9 +453,9 @@ extern unsigned char mp3buf[];
421extern unsigned char mp3end[]; 453extern unsigned char mp3end[];
422 454
423static int mp3buflen; 455static int mp3buflen;
424static int mp3buf_write; 456int mp3buf_write;
425static int mp3buf_swapwrite; 457static int mp3buf_swapwrite;
426static int mp3buf_read; 458int mp3buf_read;
427 459
428static int last_dma_chunk_size; 460static int last_dma_chunk_size;
429 461
@@ -436,6 +468,12 @@ static bool dma_underrun; /* True when the DMA has stopped because of
436 slow disk reading (read error, shaking) */ 468 slow disk reading (read error, shaking) */
437static int lowest_watermark_level; /* Debug value to observe the buffer 469static int lowest_watermark_level; /* Debug value to observe the buffer
438 usage */ 470 usage */
471#ifdef HAVE_MAS3587F
472bool recording; /* We are recording */
473static bool is_recording; /* We are (attempting to) record */
474bool stop_pending;
475#endif
476
439static int mpeg_file; 477static int mpeg_file;
440 478
441void mpeg_get_debugdata(struct mpeg_debug *dbgdata) 479void mpeg_get_debugdata(struct mpeg_debug *dbgdata)
@@ -575,20 +613,69 @@ static void stop_dma(void)
575 dma_on = false; 613 dma_on = false;
576} 614}
577 615
616long current_dma_tick = 0;
617long timing_info_index = 0;
618long timing_info[1024];
619
578static void dma_tick(void) 620static void dma_tick(void)
579{ 621{
580 if(playing && !paused) 622 current_dma_tick++;
623
624#ifdef HAVE_MAS3587F
625 if(mpeg_mode == MPEG_DECODER)
581 { 626 {
582 /* Start DMA if it is disabled and the DEMAND pin is high */ 627#endif
583 if(!dma_on && (PBDR & 0x4000)) 628 if(playing && !paused)
584 { 629 {
585 if(!(SCR0 & 0x80)) 630 /* Start DMA if it is disabled and the DEMAND pin is high */
586 start_dma(); 631 if(!dma_on && (PBDR & 0x4000))
632 {
633 if(!(SCR0 & 0x80))
634 start_dma();
635 }
636 id3tags[tag_read_idx]->id3.elapsed +=
637 (current_tick - last_dma_tick) * 1000 / HZ;
638 last_dma_tick = current_tick;
587 } 639 }
588 id3tags[tag_read_idx]->id3.elapsed += 640#ifdef HAVE_MAS3587F
589 (current_tick - last_dma_tick) * 1000 / HZ;
590 last_dma_tick = current_tick;
591 } 641 }
642 else
643 {
644 int i;
645 int num_bytes = 0;
646 if(recording && (PBDR & 0x4000))
647 {
648 timing_info[timing_info_index++] = current_dma_tick;
649 TCNT2 = 0;
650 for(i = 0;i < 30;i++)
651 {
652 PADR |= 0x800;
653 while(PBDR & 0x8000) {};
654 mp3buf[mp3buf_write] = *(unsigned char *)0x4000000;
655 PADR &= ~0x800;
656
657 mp3buf_write++;
658 if(mp3buf_write >= mp3buflen)
659 mp3buf_write = 0;
660
661 num_bytes++;
662 while(!(PBDR & 0x8000)) {};
663 }
664 timing_info[timing_info_index++] = TCNT2 + (num_bytes << 16);
665
666 timing_info_index &= 0x3ff;
667
668 /* Signal to save the data if we are running out of buffer
669 space */
670 num_bytes = mp3buf_write - mp3buf_read;
671 if(num_bytes < 0)
672 num_bytes += mp3buflen;
673
674 if(mp3buflen - num_bytes < MPEG_LOW_WATER)
675 queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
676 }
677 }
678#endif
592} 679}
593 680
594static void reset_mp3_buffer(void) 681static void reset_mp3_buffer(void)
@@ -915,7 +1002,10 @@ static void mpeg_thread(void)
915 int amount_to_read; 1002 int amount_to_read;
916 int t1, t2; 1003 int t1, t2;
917 int start_offset; 1004 int start_offset;
918 1005#ifdef HAVE_MAS3587F
1006 int amount_to_save;
1007#endif
1008
919 is_playing = false; 1009 is_playing = false;
920 play_pending = false; 1010 play_pending = false;
921 playing = false; 1011 playing = false;
@@ -923,6 +1013,10 @@ static void mpeg_thread(void)
923 1013
924 while(1) 1014 while(1)
925 { 1015 {
1016#ifdef HAVE_MAS3587F
1017 if(mpeg_mode == MPEG_DECODER)
1018 {
1019#endif
926 yield(); 1020 yield();
927 1021
928 /* Swap if necessary, and don't block on the queue_wait() */ 1022 /* Swap if necessary, and don't block on the queue_wait() */
@@ -1429,7 +1523,101 @@ static void mpeg_thread(void)
1429 usb_wait_for_disconnect(&mpeg_queue); 1523 usb_wait_for_disconnect(&mpeg_queue);
1430#endif 1524#endif
1431 break; 1525 break;
1526
1527#ifdef HAVE_MAS3587F
1528 case MPEG_INIT_RECORDING:
1529 init_recording();
1530 break;
1531#endif
1532 }
1533#ifdef HAVE_MAS3587F
1432 } 1534 }
1535 else
1536 {
1537 int i;
1538
1539 yield();
1540 if(!queue_empty(&mpeg_queue))
1541 {
1542 queue_wait(&mpeg_queue, &ev);
1543 switch(ev.id)
1544 {
1545 case MPEG_RECORD:
1546 DEBUGF("Recording...\n");
1547 mpeg_file = open("/RECORD.MP3", O_WRONLY);
1548 if(mpeg_file < 0)
1549 panicf("recfile: %d", mpeg_file);
1550 reset_mp3_buffer();
1551 start_recording();
1552 break;
1553
1554 case MPEG_STOP:
1555 DEBUGF("MPEG_STOP\n");
1556 is_recording = false;
1557 recording = false;
1558
1559 /* Save the remaining data in the buffer */
1560 stop_pending = true;
1561 queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
1562 break;
1563
1564 case MPEG_STOP_DONE:
1565 DEBUGF("MPEG_STOP_DONE\n");
1566
1567 if(mpeg_file >= 0)
1568 close(mpeg_file);
1569
1570 for(i = 0;i < 512;i++)
1571 {
1572 DEBUGF("%d - %d us (%d bytes)\n", timing_info[i*2],
1573 (timing_info[i*2+1] & 0xffff) *
1574 10000 / 13824,
1575 timing_info[i*2+1] >> 16);
1576 }
1577 break;
1578
1579 case MPEG_SAVE_DATA:
1580 amount_to_save = mp3buf_write - mp3buf_read;
1581
1582 /* If the result is negative, the write index has
1583 wrapped */
1584 if(amount_to_save < 0)
1585 {
1586 amount_to_save = mp3buflen - mp3buf_read;
1587 }
1588
1589 /* Save data only if the buffer is getting full,
1590 or if we should stop recording */
1591 if(amount_to_save)
1592 {
1593 if(mp3buflen - amount_to_save < MPEG_LOW_WATER ||
1594 stop_pending)
1595 {
1596 write(mpeg_file, mp3buf + mp3buf_read,
1597 amount_to_save);
1598
1599 mp3buf_read += amount_to_save;
1600 if(mp3buf_read >= mp3buflen)
1601 mp3buf_read = 0;
1602
1603 queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
1604 }
1605 }
1606 else
1607 {
1608 /* We have saved all data, time to stop for real */
1609 if(stop_pending)
1610 queue_post(&mpeg_queue, MPEG_STOP_DONE, 0);
1611 }
1612 break;
1613
1614 case MPEG_INIT_PLAYBACK:
1615 init_playback();
1616 break;
1617 }
1618 }
1619 }
1620#endif
1433 } 1621 }
1434} 1622}
1435 1623
@@ -1503,6 +1691,127 @@ bool mpeg_has_changed_track(void)
1503 return false; 1691 return false;
1504} 1692}
1505 1693
1694#ifdef HAVE_MAS3587F
1695void mpeg_init_recording(void)
1696{
1697 queue_post(&mpeg_queue, MPEG_INIT_RECORDING, NULL);
1698 yield();
1699}
1700
1701void mpeg_init_playback(void)
1702{
1703 queue_post(&mpeg_queue, MPEG_INIT_PLAYBACK, NULL);
1704 yield();
1705}
1706
1707static void init_recording(void)
1708{
1709 unsigned long val;
1710
1711 /* Stop the current stream */
1712 play_pending = false;
1713 playing = false;
1714 stop_dma();
1715
1716 reset_mp3_buffer();
1717 remove_all_tags();
1718
1719 if(mpeg_file >= 0)
1720 close(mpeg_file);
1721
1722 /* Init the recording variables */
1723 recording = false;
1724 is_recording = false;
1725
1726 /* Stop the current application */
1727 val = 0;
1728 mas_writemem(MAS_BANK_D0,0x7f6,&val,1);
1729 do
1730 {
1731 mas_readmem(MAS_BANK_D0, 0x7f6, &val, 1);
1732 } while(val);
1733
1734 /* Enable the Left A/D Converter */
1735 mas_codec_writereg(0x0, 0xcccd);
1736
1737 /* Copy left channel to right (mono mode) */
1738 mas_codec_writereg(8, 0x8000);
1739
1740 /* ADC scale 100%, DSP scale 0% */
1741 mas_codec_writereg(6, 0x4000);
1742 mas_codec_writereg(7, 0x0000);
1743
1744 /* No mute */
1745 val = 0;
1746 mas_writemem(MAS_BANK_D0,0x7f9,&val,1);
1747
1748 /* Set Demand mode and validate all settings */
1749 val = 0x25;
1750 mas_writemem(MAS_BANK_D0,0x7f1,&val,1);
1751
1752 /* Start the encoder application */
1753 val = 0x40;
1754 mas_writemem(MAS_BANK_D0,0x7f6,&val,1);
1755 do
1756 {
1757 mas_readmem(MAS_BANK_D0, 0x7f6, &val, 1);
1758 } while(!(val & 0x40));
1759
1760 mpeg_mode = MPEG_ENCODER;
1761
1762 DEBUGF("MAS Recording application started\n");
1763}
1764
1765static void init_playback(void)
1766{
1767 unsigned long val;
1768
1769 mpeg_mode = MPEG_DECODER;
1770
1771 /* Stop the current application */
1772 val = 0;
1773 mas_writemem(MAS_BANK_D0,0x7f6,&val,1);
1774 do
1775 {
1776 mas_readmem(MAS_BANK_D0, 0x7f6, &val, 1);
1777 } while(val);
1778
1779 /* Enable the D/A Converter */
1780 mas_codec_writereg(0x0, 0x0001);
1781
1782 /* ADC scale 0%, DSP scale 100% */
1783 mas_codec_writereg(6, 0x0000);
1784 mas_codec_writereg(7, 0x4000);
1785
1786 /* Disable SDO and SDI */
1787 val = 0x0d;
1788 mas_writemem(MAS_BANK_D0,0x7f2,&val,1);
1789
1790 /* Set Demand mode and validate all settings */
1791 val = 0x25;
1792 mas_writemem(MAS_BANK_D0,0x7f1,&val,1);
1793
1794 /* Start the Layer2/3 decoder applications */
1795 val = 0x0c;
1796 mas_writemem(MAS_BANK_D0,0x7f6,&val,1);
1797
1798 DEBUGF("MAS Decoding application started\n");
1799}
1800
1801void mpeg_record(char *filename)
1802{
1803 is_recording = true;
1804 queue_post(&mpeg_queue, MPEG_RECORD, (void*)filename);
1805}
1806
1807static void start_recording(void)
1808{
1809 recording = true;
1810 stop_pending = false;
1811}
1812
1813#endif
1814
1506void mpeg_play(int offset) 1815void mpeg_play(int offset)
1507{ 1816{
1508#ifdef SIMULATOR 1817#ifdef SIMULATOR
@@ -1647,7 +1956,11 @@ int mpeg_status(void)
1647 1956
1648 if(paused) 1957 if(paused)
1649 ret |= MPEG_STATUS_PAUSE; 1958 ret |= MPEG_STATUS_PAUSE;
1650 1959
1960#ifdef HAVE_MAS3587F
1961 if(is_recording)
1962 ret |= MPEG_STATUS_RECORD;
1963#endif
1651 return ret; 1964 return ret;
1652} 1965}
1653 1966
@@ -1863,6 +2176,15 @@ int mpeg_val2phys(int setting, int value)
1863 case SOUND_SUPERBASS: 2176 case SOUND_SUPERBASS:
1864 result = value * 10; 2177 result = value * 10;
1865 break; 2178 break;
2179
2180 case SOUND_LEFT_GAIN:
2181 case SOUND_RIGHT_GAIN:
2182 result = (value - 2) * 15;
2183 break;
2184
2185 case SOUND_MIC_GAIN:
2186 result = value * 15 + 210;
2187 break;
1866#endif 2188#endif
1867 } 2189 }
1868 return result; 2190 return result;
@@ -2013,15 +2335,63 @@ void mpeg_set_pitch(int pitch)
2013} 2335}
2014#endif 2336#endif
2015 2337
2338#ifdef HAVE_MAS3587F
2339void mpeg_set_recording_options(int frequency, int quality,
2340 int source, int channel_mode)
2341{
2342 bool is_mpeg1;
2343 unsigned long val;
2344
2345 is_mpeg1 = (frequency < 3)?true:false;
2346
2347 val = (quality << 17) |
2348 ((frequency % 3) << 11) |
2349 ((is_mpeg1?1:0) << 9) |
2350 ((channel_mode * 2 + 1) << 6) |
2351 (1 << 5) /* MS-stereo */ |
2352 (1 << 2) /* Is an original */;
2353 mas_writemem(MAS_BANK_D0, 0x7f0, &val,1);
2354
2355 val = (((source < 2)?1:2) << 8) | /* Input select */
2356 (1 << 5) | /* SDO strobe invert */
2357 ((is_mpeg1?0:1) << 3) |
2358 (1 << 2) | /* Inverted SIBC clock signal */
2359 1; /* Validate */
2360 mas_writemem(MAS_BANK_D0, 0x7f1, &val,1);
2361
2362 if(source == 0) /* Mic */
2363 {
2364 /* Copy left channel to right (mono mode) */
2365 mas_codec_writereg(8, 0x8000);
2366 }
2367 else
2368 {
2369 /* Stereo input mode */
2370 mas_codec_writereg(8, 0);
2371 }
2372}
2373
2374void mpeg_set_recording_gain(int left, int right, int mic)
2375{
2376 /* Enable both left and right A/D */
2377 mas_codec_writereg(0x0,
2378 (left << 12) |
2379 (right << 8) |
2380 (mic << 4) |
2381 (mic?0x0008:0) | /* Connect left A/D to mic */
2382 0x0007);
2383}
2384#endif
2385
2016void mpeg_init(int volume, int bass, int treble, int balance, int loudness, int bass_boost, int avc) 2386void mpeg_init(int volume, int bass, int treble, int balance, int loudness, int bass_boost, int avc)
2017{ 2387{
2018#ifdef SIMULATOR 2388#ifdef SIMULATOR
2019 volume = bass = treble = balance = loudness = bass_boost = avc; 2389 volume = bass = treble = balance = loudness = bass_boost = avc;
2020#else 2390#else
2021 unsigned long val;
2022#ifdef HAVE_MAS3587F 2391#ifdef HAVE_MAS3587F
2023 int rc; 2392 int rc;
2024#else 2393#else
2394 unsigned long val;
2025 loudness = bass_boost = avc; 2395 loudness = bass_boost = avc;
2026#endif 2396#endif
2027 2397
@@ -2039,25 +2409,10 @@ void mpeg_init(int volume, int bass, int treble, int balance, int loudness, int
2039 if(rc < 0) 2409 if(rc < 0)
2040 panicf("mas_ctrl_r: %d", rc); 2410 panicf("mas_ctrl_r: %d", rc);
2041 2411
2412 init_playback();
2413
2042 mpeg_sound_channel_config(MPEG_SOUND_STEREO); 2414 mpeg_sound_channel_config(MPEG_SOUND_STEREO);
2043 2415
2044 /* Enable the D/A Converter */
2045 mas_codec_writereg(0x0, 0x0001);
2046
2047 /* DSP scale 100% */
2048 mas_codec_writereg(7, 0x4000);
2049
2050 /* Disable SDO and SDI */
2051 val = 0x0d;
2052 mas_writemem(MAS_BANK_D0,0x7f2,&val,1);
2053
2054 /* Set Demand mode and validate all settings */
2055 val = 0x25;
2056 mas_writemem(MAS_BANK_D0,0x7f1,&val,1);
2057
2058 /* Start the Layer2/3 decoder applications */
2059 val = 0x0c;
2060 mas_writemem(MAS_BANK_D0,0x7f6,&val,1);
2061#endif 2416#endif
2062 2417
2063#ifdef HAVE_DAC3550A 2418#ifdef HAVE_DAC3550A
diff --git a/firmware/mpeg.h b/firmware/mpeg.h
index 0e92e85db7..6e2c4987c2 100644
--- a/firmware/mpeg.h
+++ b/firmware/mpeg.h
@@ -72,7 +72,15 @@ int mpeg_sound_numdecimals(int setting);
72struct mp3entry* mpeg_current_track(void); 72struct mp3entry* mpeg_current_track(void);
73bool mpeg_has_changed_track(void); 73bool mpeg_has_changed_track(void);
74int mpeg_status(void); 74int mpeg_status(void);
75#ifdef HAVE_MAS3587F
75void mpeg_set_pitch(int percent); 76void mpeg_set_pitch(int percent);
77void mpeg_init_recording(void);
78void mpeg_init_playback(void);
79void mpeg_record(char *filename);
80void mpeg_set_recording_options(int frequency, int quality,
81 int source, int channel_mode);
82void mpeg_set_recording_gain(int left, int right, int mic);
83#endif
76void mpeg_get_debugdata(struct mpeg_debug *dbgdata); 84void mpeg_get_debugdata(struct mpeg_debug *dbgdata);
77 85
78#define SOUND_VOLUME 0 86#define SOUND_VOLUME 0
@@ -83,7 +91,10 @@ void mpeg_get_debugdata(struct mpeg_debug *dbgdata);
83#define SOUND_SUPERBASS 5 91#define SOUND_SUPERBASS 5
84#define SOUND_AVC 6 92#define SOUND_AVC 6
85#define SOUND_CHANNELS 7 93#define SOUND_CHANNELS 7
86#define SOUND_NUMSETTINGS 8 94#define SOUND_LEFT_GAIN 8
95#define SOUND_RIGHT_GAIN 9
96#define SOUND_MIC_GAIN 10
97#define SOUND_NUMSETTINGS 11
87 98
88#define MPEG_SOUND_STEREO 0 99#define MPEG_SOUND_STEREO 0
89#define MPEG_SOUND_MONO 1 100#define MPEG_SOUND_MONO 1