Patch #1038325 by Markus Braun, prevents WPS from setting the volume higher than 100
[kugel-rb.git] / firmware / mp3_playback.c
blob39760d3fab2e0152424a2ff11e36e8263228f1ab
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Code that has been in mpeg.c before, now creating an encapsulated play
11 * data module, to be used by other sources than file playback as well.
13 * Copyright (C) 2004 by Linus Nielsen Feltzing
15 * All files in this archive are subject to the GNU General Public License.
16 * See the file COPYING in the source tree root for full license agreement.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
22 #include <stdbool.h>
23 #include "config.h"
24 #include "debug.h"
25 #include "panic.h"
26 #include <kernel.h>
27 #include "mpeg.h" /* ToDo: remove crosslinks */
28 #include "mp3_playback.h"
29 #ifndef SIMULATOR
30 #include "i2c.h"
31 #include "mas.h"
32 #include "dac.h"
33 #include "system.h"
34 #include "hwcompat.h"
35 #endif
37 /* hacking into mpeg.c, recording is still there */
38 #if CONFIG_HWCODEC == MAS3587F
39 enum
41 MPEG_DECODER,
42 MPEG_ENCODER
43 } mpeg_mode;
44 #endif /* #ifdef MAS3587F */
46 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
47 extern unsigned long shadow_io_control_main;
48 #endif
50 /**** globals ****/
52 /* own version, independent of mpeg.c */
53 static bool paused; /* playback is paused */
54 static bool playing; /* We are playing an MP3 stream */
56 #ifndef SIMULATOR
57 /* for measuring the play time */
58 static long playstart_tick;
59 static long cumulative_ticks;
61 /* the registered callback function to ask for more mp3 data */
62 static void (*callback_for_more)(unsigned char**, int*);
63 #endif /* #ifndef SIMULATOR */
65 static const char* const units[] =
67 "%", /* Volume */
68 "dB", /* Bass */
69 "dB", /* Treble */
70 "%", /* Balance */
71 "dB", /* Loudness */
72 "", /* AVC */
73 "", /* Channels */
74 "dB", /* Left gain */
75 "dB", /* Right gain */
76 "dB", /* Mic gain */
77 "dB", /* MDB Strength */
78 "%", /* MDB Harmonics */
79 "Hz", /* MDB Center */
80 "Hz", /* MDB Shape */
81 "", /* MDB Enable */
82 "", /* Super bass */
85 static const int numdecimals[] =
87 0, /* Volume */
88 0, /* Bass */
89 0, /* Treble */
90 0, /* Balance */
91 0, /* Loudness */
92 0, /* AVC */
93 0, /* Channels */
94 1, /* Left gain */
95 1, /* Right gain */
96 1, /* Mic gain */
97 0, /* MDB Strength */
98 0, /* MDB Harmonics */
99 0, /* MDB Center */
100 0, /* MDB Shape */
101 0, /* MDB Enable */
102 0, /* Super bass */
105 static const int steps[] =
107 1, /* Volume */
108 1, /* Bass */
109 1, /* Treble */
110 1, /* Balance */
111 1, /* Loudness */
112 1, /* AVC */
113 1, /* Channels */
114 1, /* Left gain */
115 1, /* Right gain */
116 1, /* Mic gain */
117 1, /* MDB Strength */
118 1, /* MDB Harmonics */
119 10, /* MDB Center */
120 10, /* MDB Shape */
121 1, /* MDB Enable */
122 1, /* Super bass */
125 static const int minval[] =
127 0, /* Volume */
128 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
129 -12, /* Bass */
130 -12, /* Treble */
131 #else
132 -15, /* Bass */
133 -15, /* Treble */
134 #endif
135 -100, /* Balance */
136 0, /* Loudness */
137 -1, /* AVC */
138 0, /* Channels */
139 0, /* Left gain */
140 0, /* Right gain */
141 0, /* Mic gain */
142 0, /* MDB Strength */
143 0, /* MDB Harmonics */
144 20, /* MDB Center */
145 50, /* MDB Shape */
146 0, /* MDB Enable */
147 0, /* Super bass */
150 static const int maxval[] =
152 100, /* Volume */
153 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
154 12, /* Bass */
155 12, /* Treble */
156 #else
157 15, /* Bass */
158 15, /* Treble */
159 #endif
160 100, /* Balance */
161 17, /* Loudness */
162 4, /* AVC */
163 6, /* Channels */
164 15, /* Left gain */
165 15, /* Right gain */
166 15, /* Mic gain */
167 127, /* MDB Strength */
168 100, /* MDB Harmonics */
169 300, /* MDB Center */
170 300, /* MDB Shape */
171 1, /* MDB Enable */
172 1, /* Super bass */
175 static const int defaultval[] =
177 70, /* Volume */
178 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
179 6, /* Bass */
180 6, /* Treble */
181 #else
182 7, /* Bass */
183 7, /* Treble */
184 #endif
185 0, /* Balance */
186 0, /* Loudness */
187 0, /* AVC */
188 0, /* Channels */
189 8, /* Left gain */
190 8, /* Right gain */
191 2, /* Mic gain */
192 50, /* MDB Strength */
193 48, /* MDB Harmonics */
194 60, /* MDB Center */
195 90, /* MDB Shape */
196 0, /* MDB Enable */
197 0, /* Super bass */
200 const char *mpeg_sound_unit(int setting)
202 return units[setting];
205 int mpeg_sound_numdecimals(int setting)
207 return numdecimals[setting];
210 int mpeg_sound_steps(int setting)
212 return steps[setting];
215 int mpeg_sound_min(int setting)
217 return minval[setting];
220 int mpeg_sound_max(int setting)
222 return maxval[setting];
225 int mpeg_sound_default(int setting)
227 return defaultval[setting];
230 /* list of tracks in memory */
231 #define MAX_ID3_TAGS (1<<4) /* Must be power of 2 */
232 #define MAX_ID3_TAGS_MASK (MAX_ID3_TAGS - 1)
234 #ifndef SIMULATOR
235 static bool mpeg_is_initialized = false;
236 #endif
238 #ifndef SIMULATOR
240 unsigned long mas_version_code;
242 #if CONFIG_HWCODEC == MAS3507D
244 static const unsigned int bass_table[] =
246 0x9e400, /* -15dB */
247 0xa2800, /* -14dB */
248 0xa7400, /* -13dB */
249 0xac400, /* -12dB */
250 0xb1800, /* -11dB */
251 0xb7400, /* -10dB */
252 0xbd400, /* -9dB */
253 0xc3c00, /* -8dB */
254 0xca400, /* -7dB */
255 0xd1800, /* -6dB */
256 0xd8c00, /* -5dB */
257 0xe0400, /* -4dB */
258 0xe8000, /* -3dB */
259 0xefc00, /* -2dB */
260 0xf7c00, /* -1dB */
262 0x800, /* 1dB */
263 0x10000, /* 2dB */
264 0x17c00, /* 3dB */
265 0x1f800, /* 4dB */
266 0x27000, /* 5dB */
267 0x2e400, /* 6dB */
268 0x35800, /* 7dB */
269 0x3c000, /* 8dB */
270 0x42800, /* 9dB */
271 0x48800, /* 10dB */
272 0x4e400, /* 11dB */
273 0x53800, /* 12dB */
274 0x58800, /* 13dB */
275 0x5d400, /* 14dB */
276 0x61800 /* 15dB */
279 static const unsigned int treble_table[] =
281 0xb2c00, /* -15dB */
282 0xbb400, /* -14dB */
283 0xc1800, /* -13dB */
284 0xc6c00, /* -12dB */
285 0xcbc00, /* -11dB */
286 0xd0400, /* -10dB */
287 0xd5000, /* -9dB */
288 0xd9800, /* -8dB */
289 0xde000, /* -7dB */
290 0xe2800, /* -6dB */
291 0xe7e00, /* -5dB */
292 0xec000, /* -4dB */
293 0xf0c00, /* -3dB */
294 0xf5c00, /* -2dB */
295 0xfac00, /* -1dB */
297 0x5400, /* 1dB */
298 0xac00, /* 2dB */
299 0x10400, /* 3dB */
300 0x16000, /* 4dB */
301 0x1c000, /* 5dB */
302 0x22400, /* 6dB */
303 0x28400, /* 7dB */
304 0x2ec00, /* 8dB */
305 0x35400, /* 9dB */
306 0x3c000, /* 10dB */
307 0x42c00, /* 11dB */
308 0x49c00, /* 12dB */
309 0x51800, /* 13dB */
310 0x58400, /* 14dB */
311 0x5f800 /* 15dB */
314 static const unsigned int prescale_table[] =
316 0x80000, /* 0db */
317 0x8e000, /* 1dB */
318 0x9a400, /* 2dB */
319 0xa5800, /* 3dB */
320 0xaf400, /* 4dB */
321 0xb8000, /* 5dB */
322 0xbfc00, /* 6dB */
323 0xc6c00, /* 7dB */
324 0xcd000, /* 8dB */
325 0xd25c0, /* 9dB */
326 0xd7800, /* 10dB */
327 0xdc000, /* 11dB */
328 0xdfc00, /* 12dB */
329 0xe3400, /* 13dB */
330 0xe6800, /* 14dB */
331 0xe9400 /* 15dB */
333 #endif
335 bool dma_on; /* The DMA is active */
337 #if CONFIG_HWCODEC == MAS3507D
338 static void mas_poll_start(int interval_in_ms)
340 unsigned int count;
342 count = (FREQ * interval_in_ms) / 1000 / 8;
344 if(count > 0xffff)
346 panicf("Error! The MAS poll interval is too long (%d ms)\n",
347 interval_in_ms);
348 return;
351 /* We are using timer 1 */
353 TSTR &= ~0x02; /* Stop the timer */
354 TSNC &= ~0x02; /* No synchronization */
355 TMDR &= ~0x02; /* Operate normally */
357 TCNT1 = 0; /* Start counting at 0 */
358 GRA1 = count;
359 TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */
361 /* Enable interrupt on level 5 */
362 IPRC = (IPRC & ~0x000f) | 0x0005;
364 TSR1 &= ~0x02;
365 TIER1 = 0xf9; /* Enable GRA match interrupt */
367 TSTR |= 0x02; /* Start timer 1 */
369 #else
370 static void postpone_dma_tick(void)
372 unsigned int count;
374 count = FREQ / 2000 / 8;
376 /* We are using timer 1 */
378 TSTR &= ~0x02; /* Stop the timer */
379 TSNC &= ~0x02; /* No synchronization */
380 TMDR &= ~0x02; /* Operate normally */
382 TCNT1 = 0; /* Start counting at 0 */
383 GRA1 = count;
384 TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */
386 /* Enable interrupt on level 5 */
387 IPRC = (IPRC & ~0x000f) | 0x0005;
389 TSR1 &= ~0x02;
390 TIER1 = 0xf9; /* Enable GRA match interrupt */
392 TSTR |= 0x02; /* Start timer 1 */
394 #endif
397 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
398 void demand_irq_enable(bool on)
400 int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
402 if(on)
404 IPRA = (IPRA & 0xfff0) | 0x000b;
405 ICR &= ~0x0010; /* IRQ3 level sensitive */
407 else
408 IPRA &= 0xfff0;
410 set_irq_level(oldlevel);
412 #endif /* #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F) */
415 void play_tick(void)
417 if(playing && !paused)
419 /* Start DMA if it is disabled and the DEMAND pin is high */
420 if(!(SCR0 & 0x80) && (PBDR & 0x4000))
422 SCR0 |= 0x80;
425 playback_tick(); /* dirty call to mpeg.c */
429 #pragma interrupt
430 void DEI3(void)
432 unsigned char* start;
433 int size = 0;
435 if (callback_for_more != NULL)
437 callback_for_more(&start, &size);
440 if (size > 0)
442 DTCR3 = size & 0xffff;
443 SAR3 = (unsigned int) start;
445 else
447 CHCR3 &= ~0x0001; /* Disable the DMA interrupt */
450 CHCR3 &= ~0x0002; /* Clear DMA interrupt */
453 #pragma interrupt
454 void IMIA1(void) /* Timer 1 interrupt */
456 if(playing)
457 play_tick();
458 TSR1 &= ~0x01;
459 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
460 /* Disable interrupt */
461 IPRC &= ~0x000f;
462 #endif
465 #pragma interrupt
466 void IRQ6(void) /* PB14: MAS stop demand IRQ */
468 SCR0 &= ~0x80;
471 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
472 #pragma interrupt
473 void IRQ3(void) /* PA15: MAS demand IRQ */
475 /* Begin with setting the IRQ to edge sensitive */
476 ICR |= 0x0010;
478 #if CONFIG_HWCODEC == MAS3587F
479 if(mpeg_mode == MPEG_ENCODER)
480 rec_tick();
481 else
482 #endif
483 postpone_dma_tick();
485 #endif /* #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F) */
487 static void setup_sci0(void)
489 /* PB15 is I/O, PB14 is IRQ6, PB12 is SCK0, PB9 is TxD0 */
490 PBCR1 = (PBCR1 & 0x0cff) | 0x1208;
492 /* Set PB12 to output */
493 or_b(0x10, &PBIORH);
495 /* Disable serial port */
496 SCR0 = 0x00;
498 /* Synchronous, no prescale */
499 SMR0 = 0x80;
501 /* Set baudrate 1Mbit/s */
502 BRR0 = 0x03;
504 /* use SCK as serial clock output */
505 SCR0 = 0x01;
507 /* Clear FER and PER */
508 SSR0 &= 0xe7;
510 /* Set interrupt ITU2 and SCI0 priority to 0 */
511 IPRD &= 0x0ff0;
513 /* set PB15 and PB14 to inputs */
514 and_b(~0x80, &PBIORH);
515 and_b(~0x40, &PBIORH);
517 /* Enable End of DMA interrupt at prio 8 */
518 IPRC = (IPRC & 0xf0ff) | 0x0800;
520 /* Enable Tx (only!) */
521 SCR0 |= 0x20;
523 #endif /* SIMULATOR */
525 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
526 static void init_playback(void)
528 unsigned long val;
529 int rc;
531 mp3_play_pause(false);
533 mas_reset();
535 /* Enable the audio CODEC and the DSP core, max analog voltage range */
536 rc = mas_direct_config_write(MAS_CONTROL, 0x8c00);
537 if(rc < 0)
538 panicf("mas_ctrl_w: %d", rc);
540 /* Stop the current application */
541 val = 0;
542 mas_writemem(MAS_BANK_D0, MAS_D0_APP_SELECT, &val, 1);
545 mas_readmem(MAS_BANK_D0, MAS_D0_APP_RUNNING, &val, 1);
546 } while(val);
548 /* Enable the D/A Converter */
549 mas_codec_writereg(0x0, 0x0001);
551 /* ADC scale 0%, DSP scale 100% */
552 mas_codec_writereg(6, 0x0000);
553 mas_codec_writereg(7, 0x4000);
555 /* Disable SDO and SDI */
556 val = 0x0d;
557 mas_writemem(MAS_BANK_D0, MAS_D0_INTERFACE_CONTROL, &val, 1);
559 /* Set Demand mode and validate all settings */
560 shadow_io_control_main = 0x25;
561 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
563 /* Start the Layer2/3 decoder applications */
564 val = 0x0c;
565 mas_writemem(MAS_BANK_D0, MAS_D0_APP_SELECT, &val, 1);
568 mas_readmem(MAS_BANK_D0, MAS_D0_APP_RUNNING, &val, 1);
569 } while((val & 0x0c) != 0x0c);
571 mpeg_sound_channel_config(MPEG_SOUND_STEREO);
573 #if CONFIG_HWCODEC == MAS3587F
574 mpeg_mode = MPEG_DECODER;
575 #endif
577 /* set IRQ6 to edge detect */
578 ICR |= 0x02;
580 /* set IRQ6 prio 8 */
581 IPRB = ( IPRB & 0xff0f ) | 0x0080;
583 DEBUGF("MAS Decoding application started\n");
585 #endif /* #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F) */
587 #ifndef SIMULATOR
588 #if CONFIG_HWCODEC == MAS3507D
589 int current_left_volume = 0; /* all values in tenth of dB */
590 int current_right_volume = 0; /* all values in tenth of dB */
591 int current_treble = 0;
592 int current_bass = 0;
593 int current_balance = 0;
595 /* convert tenth of dB volume to register value */
596 static int tenthdb2reg(int db) {
597 if (db < -540)
598 return (db + 780) / 30;
599 else
600 return (db + 660) / 15;
603 void set_prescaled_volume(void)
605 int prescale;
606 int l, r;
608 prescale = MAX(current_bass, current_treble);
609 if (prescale < 0)
610 prescale = 0; /* no need to prescale if we don't boost
611 bass or treble */
613 mas_writereg(MAS_REG_KPRESCALE, prescale_table[prescale/10]);
615 /* gain up the analog volume to compensate the prescale reduction gain */
616 l = current_left_volume + prescale;
617 r = current_right_volume + prescale;
619 dac_volume(tenthdb2reg(l), tenthdb2reg(r), false);
621 #endif /* MAS3507D */
622 #endif /* !SIMULATOR */
624 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
625 unsigned long mdb_shape_shadow = 0;
626 unsigned long loudness_shadow = 0;
627 #endif
629 void mpeg_sound_set(int setting, int value)
631 #ifdef SIMULATOR
632 setting = value;
633 #else
634 #if CONFIG_HWCODEC == MAS3507D
635 int l, r;
636 #else
637 int tmp;
638 #endif
640 if(!mpeg_is_initialized)
641 return;
643 switch(setting)
645 case SOUND_VOLUME:
646 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
647 tmp = 0x7f00 * value / 100;
648 mas_codec_writereg(0x10, tmp & 0xff00);
649 #else
650 l = value;
651 r = value;
653 if(current_balance > 0)
655 l -= current_balance;
656 if(l < 0)
657 l = 0;
660 if(current_balance < 0)
662 r += current_balance;
663 if(r < 0)
664 r = 0;
667 l = 0x38 * l / 100;
668 r = 0x38 * r / 100;
670 /* store volume in tenth of dB */
671 current_left_volume = ( l < 0x08 ? l*30 - 780 : l*15 - 660 );
672 current_right_volume = ( r < 0x08 ? r*30 - 780 : r*15 - 660 );
674 set_prescaled_volume();
675 #endif
676 break;
678 case SOUND_BALANCE:
679 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
680 tmp = ((value * 127 / 100) & 0xff) << 8;
681 mas_codec_writereg(0x11, tmp & 0xff00);
682 #else
683 current_balance = value;
684 #endif
685 break;
687 case SOUND_BASS:
688 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
689 tmp = ((value * 8) & 0xff) << 8;
690 mas_codec_writereg(0x14, tmp & 0xff00);
691 #else
692 mas_writereg(MAS_REG_KBASS, bass_table[value+15]);
693 current_bass = (value) * 10;
694 set_prescaled_volume();
695 #endif
696 break;
698 case SOUND_TREBLE:
699 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
700 tmp = ((value * 8) & 0xff) << 8;
701 mas_codec_writereg(0x15, tmp & 0xff00);
702 #else
703 mas_writereg(MAS_REG_KTREBLE, treble_table[value+15]);
704 current_treble = (value) * 10;
705 set_prescaled_volume();
706 #endif
707 break;
709 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
710 case SOUND_LOUDNESS:
711 loudness_shadow = (loudness_shadow & 0x04) |
712 (MAX(MIN(value * 4, 0x44), 0) << 8);
713 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
714 break;
716 case SOUND_AVC:
717 switch (value) {
718 case 1: /* 20ms */
719 tmp = (0x1 << 8) | (0x8 << 12);
720 break;
721 case 2: /* 2s */
722 tmp = (0x2 << 8) | (0x8 << 12);
723 break;
724 case 3: /* 4s */
725 tmp = (0x4 << 8) | (0x8 << 12);
726 break;
727 case 4: /* 8s */
728 tmp = (0x8 << 8) | (0x8 << 12);
729 break;
730 case -1: /* turn off and then turn on again to decay quickly */
731 tmp = mas_codec_readreg(MAS_REG_KAVC);
732 mas_codec_writereg(MAS_REG_KAVC, 0);
733 break;
734 default: /* off */
735 tmp = 0;
736 break;
738 mas_codec_writereg(MAS_REG_KAVC, tmp);
739 break;
741 case SOUND_MDB_STRENGTH:
742 mas_codec_writereg(MAS_REG_KMDB_STR, (value & 0x7f) << 8);
743 break;
745 case SOUND_MDB_HARMONICS:
746 tmp = value * 127 / 100;
747 mas_codec_writereg(MAS_REG_KMDB_HAR, (tmp & 0x7f) << 8);
748 break;
750 case SOUND_MDB_CENTER:
751 mas_codec_writereg(MAS_REG_KMDB_FC, (value/10) << 8);
752 break;
754 case SOUND_MDB_SHAPE:
755 mdb_shape_shadow = (mdb_shape_shadow & 0x02) | ((value/10) << 8);
756 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
757 break;
759 case SOUND_MDB_ENABLE:
760 mdb_shape_shadow = (mdb_shape_shadow & ~0x02) | (value?2:0);
761 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
762 break;
764 case SOUND_SUPERBASS:
765 loudness_shadow = (loudness_shadow & ~0x04) |
766 (value?4:0);
767 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
768 break;
769 #endif
770 case SOUND_CHANNELS:
771 mpeg_sound_channel_config(value);
772 break;
774 #endif /* SIMULATOR */
777 int mpeg_val2phys(int setting, int value)
779 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
780 int result = 0;
782 switch(setting)
784 case SOUND_LEFT_GAIN:
785 case SOUND_RIGHT_GAIN:
786 result = (value - 2) * 15;
787 break;
789 case SOUND_MIC_GAIN:
790 result = value * 15 + 210;
791 break;
793 default:
794 result = value;
795 break;
797 return result;
798 #else
799 (void)setting;
800 return value;
801 #endif
804 void mpeg_sound_channel_config(int configuration)
806 #ifdef SIMULATOR
807 (void)configuration;
808 #else
809 unsigned long val_ll = 0x80000;
810 unsigned long val_lr = 0;
811 unsigned long val_rl = 0;
812 unsigned long val_rr = 0x80000;
814 switch(configuration)
816 case MPEG_SOUND_STEREO:
817 val_ll = 0x80000;
818 val_lr = 0;
819 val_rl = 0;
820 val_rr = 0x80000;
821 break;
823 case MPEG_SOUND_MONO:
824 val_ll = 0xc0000;
825 val_lr = 0xc0000;
826 val_rl = 0xc0000;
827 val_rr = 0xc0000;
828 break;
830 case MPEG_SOUND_MONO_LEFT:
831 val_ll = 0x80000;
832 val_lr = 0x80000;
833 val_rl = 0;
834 val_rr = 0;
835 break;
837 case MPEG_SOUND_MONO_RIGHT:
838 val_ll = 0;
839 val_lr = 0;
840 val_rl = 0x80000;
841 val_rr = 0x80000;
842 break;
844 case MPEG_SOUND_STEREO_NARROW:
845 val_ll = 0xa0000;
846 val_lr = 0xe0000;
847 val_rl = 0xe0000;
848 val_rr = 0xa0000;
849 break;
851 case MPEG_SOUND_STEREO_WIDE:
852 val_ll = 0x80000;
853 val_lr = 0x40000;
854 val_rl = 0x40000;
855 val_rr = 0x80000;
856 break;
858 case MPEG_SOUND_KARAOKE:
859 val_ll = 0x80001;
860 val_lr = 0x7ffff;
861 val_rl = 0x7ffff;
862 val_rr = 0x80001;
863 break;
866 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
867 mas_writemem(MAS_BANK_D0, MAS_D0_OUT_LL, &val_ll, 1); /* LL */
868 mas_writemem(MAS_BANK_D0, MAS_D0_OUT_LR, &val_lr, 1); /* LR */
869 mas_writemem(MAS_BANK_D0, MAS_D0_OUT_RL, &val_rl, 1); /* RL */
870 mas_writemem(MAS_BANK_D0, MAS_D0_OUT_RR, &val_rr, 1); /* RR */
871 #else
872 mas_writemem(MAS_BANK_D1, 0x7f8, &val_ll, 1); /* LL */
873 mas_writemem(MAS_BANK_D1, 0x7f9, &val_lr, 1); /* LR */
874 mas_writemem(MAS_BANK_D1, 0x7fa, &val_rl, 1); /* RL */
875 mas_writemem(MAS_BANK_D1, 0x7fb, &val_rr, 1); /* RR */
876 #endif
877 #endif
880 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
881 /* This function works by telling the decoder that we have another
882 crystal frequency than we actually have. It will adjust its internal
883 parameters and the result is that the audio is played at another pitch.
885 The pitch value is in tenths of percent.
887 void mpeg_set_pitch(int pitch)
889 unsigned long val;
891 /* invert pitch value */
892 pitch = 1000000/pitch;
894 /* Calculate the new (bogus) frequency */
895 val = 18432*pitch/1000;
897 mas_writemem(MAS_BANK_D0, MAS_D0_OFREQ_CONTROL, &val, 1);
899 /* We must tell the MAS that the frequency has changed.
900 This will unfortunately cause a short silence. */
901 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
903 #endif
905 void mp3_init(int volume, int bass, int treble, int balance, int loudness,
906 int avc, int channel_config,
907 int mdb_strength, int mdb_harmonics,
908 int mdb_center, int mdb_shape, bool mdb_enable,
909 bool superbass)
911 #ifdef SIMULATOR
912 (void)volume;
913 (void)bass;
914 (void)treble;
915 (void)balance;
916 (void)loudness;
917 (void)avc;
918 (void)channel_config;
919 (void)mdb_strength;
920 (void)mdb_harmonics;
921 (void)mdb_center;
922 (void)mdb_shape;
923 (void)mdb_enable;
924 (void)superbass;
925 #else
926 #if CONFIG_HWCODEC == MAS3507D
927 unsigned long val;
928 (void)loudness;
929 (void)avc;
930 (void)mdb_strength;
931 (void)mdb_harmonics;
932 (void)mdb_center;
933 (void)mdb_shape;
934 (void)mdb_enable;
935 (void)superbass;
936 #endif
938 setup_sci0();
940 #ifdef HAVE_MAS_SIBI_CONTROL
941 and_b(~0x01, &PBDRH); /* drive SIBI low */
942 and_b(~0x01, &PBIORH); /* output for PB8 */
943 #endif
945 #if CONFIG_HWCODEC == MAS3587F
946 or_b(0x08, &PAIORH); /* output for /PR */
947 init_playback();
949 mas_version_code = mas_readver();
950 DEBUGF("MAS3587 derivate %d, version %c%d\n",
951 (mas_version_code & 0xf000) >> 12,
952 'A' + ((mas_version_code & 0x0f00) >> 8), mas_version_code & 0xff);
953 #elif CONFIG_HW_CODEC == MAS3539F
954 or_b(0x08, &PAIORH); /* output for /PR */
955 init_playback();
957 mas_version_code = mas_readver();
958 DEBUGF("MAS3539 derivate %d, version %c%d\n",
959 (mas_version_code & 0xf000) >> 12,
960 'A' + ((mas_version_code & 0x0f00) >> 8), mas_version_code & 0xff);
961 #endif
963 #ifdef HAVE_DAC3550A
964 dac_init();
965 #endif
967 #if CONFIG_HWCODEC == MAS3507D
968 and_b(~0x20, &PBDRL);
969 sleep(HZ/5);
970 or_b(0x20, &PBDRL);
971 sleep(HZ/5);
973 /* set IRQ6 to edge detect */
974 ICR |= 0x02;
976 /* set IRQ6 prio 8 */
977 IPRB = ( IPRB & 0xff0f ) | 0x0080;
979 mas_readmem(MAS_BANK_D1, 0xff7, &mas_version_code, 1);
981 mas_writereg(0x3b, 0x20); /* Don't ask why. The data sheet doesn't say */
982 mas_run(1);
983 sleep(HZ);
985 /* Clear the upper 12 bits of the 32-bit samples */
986 mas_writereg(0xc5, 0);
987 mas_writereg(0xc6, 0);
989 /* We need to set the PLL for a 14.1318MHz crystal */
990 if(mas_version_code == 0x0601) /* Version F10? */
992 val = 0x5d9d0;
993 mas_writemem(MAS_BANK_D0, 0x32d, &val, 1);
994 val = 0xfffceceb;
995 mas_writemem(MAS_BANK_D0, 0x32e, &val, 1);
996 val = 0x0;
997 mas_writemem(MAS_BANK_D0, 0x32f, &val, 1);
998 mas_run(0x475);
1000 else
1002 val = 0x5d9d0;
1003 mas_writemem(MAS_BANK_D0, 0x36d, &val, 1);
1004 val = 0xfffceceb;
1005 mas_writemem(MAS_BANK_D0, 0x36e, &val, 1);
1006 val = 0x0;
1007 mas_writemem(MAS_BANK_D0, 0x36f, &val, 1);
1008 mas_run(0xfcb);
1011 #endif
1013 #if CONFIG_HWCODEC == MAS3507D
1014 mas_poll_start(1);
1016 mas_writereg(MAS_REG_KPRESCALE, 0xe9400);
1017 dac_enable(true);
1019 mpeg_sound_channel_config(channel_config);
1020 #endif
1022 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
1023 ICR &= ~0x0010; /* IRQ3 level sensitive */
1024 PACR1 = (PACR1 & 0x3fff) | 0x4000; /* PA15 is IRQ3 */
1025 #endif
1027 /* Must be done before calling mpeg_sound_set() */
1028 mpeg_is_initialized = true;
1030 mpeg_sound_set(SOUND_BASS, bass);
1031 mpeg_sound_set(SOUND_TREBLE, treble);
1032 mpeg_sound_set(SOUND_BALANCE, balance);
1033 mpeg_sound_set(SOUND_VOLUME, volume);
1035 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
1036 mpeg_sound_channel_config(channel_config);
1037 mpeg_sound_set(SOUND_LOUDNESS, loudness);
1038 mpeg_sound_set(SOUND_AVC, avc);
1039 mpeg_sound_set(SOUND_MDB_STRENGTH, mdb_strength);
1040 mpeg_sound_set(SOUND_MDB_HARMONICS, mdb_harmonics);
1041 mpeg_sound_set(SOUND_MDB_CENTER, mdb_center);
1042 mpeg_sound_set(SOUND_MDB_SHAPE, mdb_shape);
1043 mpeg_sound_set(SOUND_MDB_ENABLE, mdb_enable);
1044 mpeg_sound_set(SOUND_SUPERBASS, superbass);
1045 #endif
1046 #endif /* !SIMULATOR */
1048 playing = false;
1049 paused = true;
1052 void mp3_shutdown(void)
1054 #ifndef SIMULATOR
1055 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
1056 unsigned long val = 1;
1057 mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &val, 1); /* Mute */
1058 #endif
1060 #if CONFIG_HWCODEC == MAS3507D
1061 dac_volume(0, 0, false);
1062 #endif
1064 #endif
1067 /* new functions, to be exported to plugin API */
1069 #ifndef SIMULATOR
1071 void mp3_play_init(void)
1073 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
1074 init_playback();
1075 #endif
1076 playing = false;
1077 paused = true;
1078 callback_for_more = NULL;
1079 mp3_reset_playtime();
1082 void mp3_play_data(const unsigned char* start, int size,
1083 void (*get_more)(unsigned char** start, int* size) /* callback fn */
1086 /* init DMA */
1087 DAR3 = 0x5FFFEC3;
1088 CHCR3 &= ~0x0002; /* Clear interrupt */
1089 CHCR3 = 0x1504; /* Single address destination, TXI0, IE=1 */
1090 DMAOR = 0x0001; /* Enable DMA */
1092 callback_for_more = get_more;
1094 SAR3 = (unsigned int)start;
1095 DTCR3 = size & 0xffff;
1097 playing = true;
1098 paused = true;
1100 CHCR3 |= 0x0001; /* Enable DMA IRQ */
1102 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
1103 demand_irq_enable(true);
1104 #endif
1107 void mp3_play_pause(bool play)
1109 if (paused && play)
1110 { /* resume playback */
1111 SCR0 |= 0x80;
1112 paused = false;
1113 playstart_tick = current_tick;
1115 else if (!paused && !play)
1116 { /* stop playback */
1117 SCR0 &= 0x7f;
1118 paused = true;
1119 cumulative_ticks += current_tick - playstart_tick;
1123 void mp3_play_stop(void)
1125 playing = false;
1126 mp3_play_pause(false);
1127 CHCR3 &= ~0x0001; /* Disable the DMA interrupt */
1128 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
1129 demand_irq_enable(false);
1130 #endif
1133 long mp3_get_playtime(void)
1135 if (paused)
1136 return cumulative_ticks;
1137 else
1138 return cumulative_ticks + current_tick - playstart_tick;
1141 void mp3_reset_playtime(void)
1143 cumulative_ticks = 0;
1144 playstart_tick = current_tick;
1148 bool mp3_is_playing(void)
1150 return playing;
1154 /* returns the next byte position which would be transferred */
1155 unsigned char* mp3_get_pos(void)
1157 return (unsigned char*)SAR3;
1161 #endif /* #ifndef SIMULATOR */