1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
27 #include "mpeg.h" /* ToDo: remove crosslinks */
28 #include "mp3_playback.h"
37 /* hacking into mpeg.c, recording is still there */
45 unsigned long shadow_7f1
;
47 #endif /* #ifdef HAVE_MAS3587F */
51 /* own version, independent of mpeg.c */
52 static bool paused
; /* playback is paused */
53 static bool playing
; /* We are playing an MP3 stream */
56 /* for measuring the play time */
57 static long playstart_tick
;
58 static long cumulative_ticks
;
60 /* the registered callback function to ask for more mp3 data */
61 static void (*callback_for_more
)(unsigned char**, int*);
62 #endif /* #ifndef SIMULATOR */
64 static char *units
[] =
75 "dB", /* Right gain */
79 static int numdecimals
[] =
114 static int maxval
[] =
126 100, /* Bass boost */
134 static int defaultval
[] =
154 char *mpeg_sound_unit(int setting
)
156 return units
[setting
];
159 int mpeg_sound_numdecimals(int setting
)
161 return numdecimals
[setting
];
164 int mpeg_sound_min(int setting
)
166 return minval
[setting
];
169 int mpeg_sound_max(int setting
)
171 return maxval
[setting
];
174 int mpeg_sound_default(int setting
)
176 return defaultval
[setting
];
179 /* list of tracks in memory */
180 #define MAX_ID3_TAGS (1<<4) /* Must be power of 2 */
181 #define MAX_ID3_TAGS_MASK (MAX_ID3_TAGS - 1)
184 static bool mpeg_is_initialized
= false;
189 unsigned long mas_version_code
;
193 static unsigned int bass_table
[] =
228 static unsigned int treble_table
[] =
263 static unsigned int prescale_table
[] =
284 bool dma_on
; /* The DMA is active */
287 static void mas_poll_start(int interval_in_ms
)
291 count
= (FREQ
* interval_in_ms
) / 1000 / 8;
295 panicf("Error! The MAS poll interval is too long (%d ms)\n",
300 /* We are using timer 1 */
302 TSTR
&= ~0x02; /* Stop the timer */
303 TSNC
&= ~0x02; /* No synchronization */
304 TMDR
&= ~0x02; /* Operate normally */
306 TCNT1
= 0; /* Start counting at 0 */
308 TCR1
= 0x23; /* Clear at GRA match, sysclock/8 */
310 /* Enable interrupt on level 5 */
311 IPRC
= (IPRC
& ~0x000f) | 0x0005;
314 TIER1
= 0xf9; /* Enable GRA match interrupt */
316 TSTR
|= 0x02; /* Start timer 1 */
319 static void postpone_dma_tick(void)
323 count
= FREQ
/ 2000 / 8;
325 /* We are using timer 1 */
327 TSTR
&= ~0x02; /* Stop the timer */
328 TSNC
&= ~0x02; /* No synchronization */
329 TMDR
&= ~0x02; /* Operate normally */
331 TCNT1
= 0; /* Start counting at 0 */
333 TCR1
= 0x23; /* Clear at GRA match, sysclock/8 */
335 /* Enable interrupt on level 5 */
336 IPRC
= (IPRC
& ~0x000f) | 0x0005;
339 TIER1
= 0xf9; /* Enable GRA match interrupt */
341 TSTR
|= 0x02; /* Start timer 1 */
347 void demand_irq_enable(bool on
)
349 int oldlevel
= set_irq_level(HIGHEST_IRQ_LEVEL
);
353 IPRA
= (IPRA
& 0xfff0) | 0x000b;
354 ICR
&= ~0x0010; /* IRQ3 level sensitive */
359 set_irq_level(oldlevel
);
361 #endif /* #ifdef HAVE_MAS3587F */
366 if(playing
&& !paused
)
368 /* Start DMA if it is disabled and the DEMAND pin is high */
369 if(!(SCR0
& 0x80) && (PBDR
& 0x4000))
374 playback_tick(); /* dirty call to mpeg.c */
381 unsigned char* start
;
384 if (callback_for_more
!= NULL
)
386 callback_for_more(&start
, &size
);
391 DTCR3
= size
& 0xffff;
392 SAR3
= (unsigned int) start
;
396 CHCR3
&= ~0x0001; /* Disable the DMA interrupt */
399 CHCR3
&= ~0x0002; /* Clear DMA interrupt */
403 void IMIA1(void) /* Timer 1 interrupt */
409 /* Disable interrupt */
411 #endif /* #ifdef HAVE_MAS3587F */
415 void IRQ6(void) /* PB14: MAS stop demand IRQ */
422 void IRQ3(void) /* PA15: MAS demand IRQ */
424 /* Begin with setting the IRQ to edge sensitive */
427 if(mpeg_mode
== MPEG_ENCODER
)
432 #endif /* #ifdef HAVE_MAS3587F */
434 static void setup_sci0(void)
436 /* PB15 is I/O, PB14 is IRQ6, PB12 is SCK0, PB9 is TxD0 */
437 PBCR1
= (PBCR1
& 0x0cff) | 0x1208;
439 /* Set PB12 to output */
442 /* Disable serial port */
445 /* Synchronous, no prescale */
448 /* Set baudrate 1Mbit/s */
451 /* use SCK as serial clock output */
454 /* Clear FER and PER */
457 /* Set interrupt ITU2 and SCI0 priority to 0 */
460 /* set PB15 and PB14 to inputs */
461 and_b(~0x80, &PBIORH
);
462 and_b(~0x40, &PBIORH
);
464 /* Enable End of DMA interrupt at prio 8 */
465 IPRC
= (IPRC
& 0xf0ff) | 0x0800;
467 /* Enable Tx (only!) */
470 #endif /* SIMULATOR */
473 static void init_playback(void)
478 mp3_play_pause(false);
482 /* Enable the audio CODEC and the DSP core, max analog voltage range */
483 rc
= mas_direct_config_write(MAS_CONTROL
, 0x8c00);
485 panicf("mas_ctrl_w: %d", rc
);
487 /* Stop the current application */
489 mas_writemem(MAS_BANK_D0
,0x7f6,&val
,1);
492 mas_readmem(MAS_BANK_D0
, 0x7f7, &val
, 1);
495 /* Enable the D/A Converter */
496 mas_codec_writereg(0x0, 0x0001);
498 /* ADC scale 0%, DSP scale 100% */
499 mas_codec_writereg(6, 0x0000);
500 mas_codec_writereg(7, 0x4000);
502 /* Disable SDO and SDI */
504 mas_writemem(MAS_BANK_D0
,0x7f2,&val
,1);
506 /* Set Demand mode and validate all settings */
508 mas_writemem(MAS_BANK_D0
,0x7f1,&val
,1);
510 /* Start the Layer2/3 decoder applications */
512 mas_writemem(MAS_BANK_D0
,0x7f6,&val
,1);
515 mas_readmem(MAS_BANK_D0
, 0x7f7, &val
, 1);
516 } while((val
& 0x0c) != 0x0c);
518 mpeg_sound_channel_config(MPEG_SOUND_STEREO
);
520 mpeg_mode
= MPEG_DECODER
;
522 /* set IRQ6 to edge detect */
525 /* set IRQ6 prio 8 */
526 IPRB
= ( IPRB
& 0xff0f ) | 0x0080;
528 DEBUGF("MAS Decoding application started\n");
530 #endif /* #ifdef HAVE_MAS3587F */
534 int current_left_volume
= 0; /* all values in tenth of dB */
535 int current_right_volume
= 0; /* all values in tenth of dB */
536 int current_treble
= 0;
537 int current_bass
= 0;
538 int current_balance
= 0;
540 /* convert tenth of dB volume to register value */
541 static int tenthdb2reg(int db
) {
543 return (db
+ 780) / 30;
545 return (db
+ 660) / 15;
548 void set_prescaled_volume(void)
553 prescale
= MAX(current_bass
, current_treble
);
555 prescale
= 0; /* no need to prescale if we don't boost
558 mas_writereg(MAS_REG_KPRESCALE
, prescale_table
[prescale
/10]);
560 /* gain up the analog volume to compensate the prescale reduction gain */
561 l
= current_left_volume
+ prescale
;
562 r
= current_right_volume
+ prescale
;
564 dac_volume(tenthdb2reg(l
), tenthdb2reg(r
), false);
566 #endif /* HAVE_MAS3507D */
567 #endif /* !SIMULATOR */
569 void mpeg_sound_set(int setting
, int value
)
580 if(!mpeg_is_initialized
)
587 tmp
= 0x7f00 * value
/ 100;
588 mas_codec_writereg(0x10, tmp
& 0xff00);
593 if(current_balance
> 0)
595 l
-= current_balance
;
600 if(current_balance
< 0)
602 r
+= current_balance
;
610 /* store volume in tenth of dB */
611 current_left_volume
= ( l
< 0x08 ? l
*30 - 780 : l
*15 - 660 );
612 current_right_volume
= ( r
< 0x08 ? r
*30 - 780 : r
*15 - 660 );
614 set_prescaled_volume();
620 tmp
= ((value
* 127 / 100) & 0xff) << 8;
621 mas_codec_writereg(0x11, tmp
& 0xff00);
627 tmp
= ((value
* 8) & 0xff) << 8;
628 mas_codec_writereg(0x14, tmp
& 0xff00);
630 mas_writereg(MAS_REG_KBASS
, bass_table
[value
+15]);
631 current_bass
= (value
) * 10;
632 set_prescaled_volume();
638 tmp
= ((value
* 8) & 0xff) << 8;
639 mas_codec_writereg(0x15, tmp
& 0xff00);
641 mas_writereg(MAS_REG_KTREBLE
, treble_table
[value
+15]);
642 current_treble
= (value
) * 10;
643 set_prescaled_volume();
648 case SOUND_SUPERBASS
:
650 tmp
= MAX(MIN(value
* 127 / 100, 0x7f), 0);
651 mas_codec_writereg(MAS_REG_KMDB_STR
, (tmp
& 0xff) << 8);
652 tmp
= 0x30; /* MDB_HAR: Space for experiment here */
653 mas_codec_writereg(MAS_REG_KMDB_HAR
, (tmp
& 0xff) << 8);
654 tmp
= 60 / 10; /* calculate MDB_FC, 60hz - experiment here,
655 this would depend on the earphones...
656 perhaps make it tunable? */
657 mas_codec_writereg(MAS_REG_KMDB_FC
, (tmp
& 0xff) << 8);
658 tmp
= (3 * tmp
) / 2; /* calculate MDB_SHAPE */
659 mas_codec_writereg(MAS_REG_KMDB_SWITCH
,
660 ((tmp
& 0xff) << 8) /* MDB_SHAPE */
661 | 2); /* MDB_SWITCH enable */
663 mas_codec_writereg(MAS_REG_KMDB_STR
, 0);
664 mas_codec_writereg(MAS_REG_KMDB_HAR
, 0);
665 mas_codec_writereg(MAS_REG_KMDB_SWITCH
, 0); /* MDB_SWITCH disable */
670 tmp
= MAX(MIN(value
* 4, 0x44), 0);
671 mas_codec_writereg(MAS_REG_KLOUDNESS
, (tmp
& 0xff) << 8);
677 tmp
= (0x1 << 8) | (0x8 << 12);
680 tmp
= (0x2 << 8) | (0x8 << 12);
683 tmp
= (0x4 << 8) | (0x8 << 12);
686 tmp
= (0x8 << 8) | (0x8 << 12);
688 case -1: /* turn off and then turn on again to decay quickly */
689 tmp
= mas_codec_readreg(MAS_REG_KAVC
);
690 mas_codec_writereg(MAS_REG_KAVC
, 0);
696 mas_codec_writereg(MAS_REG_KAVC
, tmp
);
700 mpeg_sound_channel_config(value
);
703 #endif /* SIMULATOR */
706 int mpeg_val2phys(int setting
, int value
)
713 case SOUND_LEFT_GAIN
:
714 case SOUND_RIGHT_GAIN
:
715 result
= (value
- 2) * 15;
719 result
= value
* 15 + 210;
733 void mpeg_sound_channel_config(int configuration
)
738 unsigned long val_ll
= 0x80000;
739 unsigned long val_lr
= 0;
740 unsigned long val_rl
= 0;
741 unsigned long val_rr
= 0x80000;
743 switch(configuration
)
745 case MPEG_SOUND_STEREO
:
752 case MPEG_SOUND_MONO
:
759 case MPEG_SOUND_MONO_LEFT
:
766 case MPEG_SOUND_MONO_RIGHT
:
773 case MPEG_SOUND_STEREO_NARROW
:
780 case MPEG_SOUND_STEREO_WIDE
:
787 case MPEG_SOUND_KARAOKE
:
796 mas_writemem(MAS_BANK_D0
, 0x7fc, &val_ll
, 1); /* LL */
797 mas_writemem(MAS_BANK_D0
, 0x7fd, &val_lr
, 1); /* LR */
798 mas_writemem(MAS_BANK_D0
, 0x7fe, &val_rl
, 1); /* RL */
799 mas_writemem(MAS_BANK_D0
, 0x7ff, &val_rr
, 1); /* RR */
801 mas_writemem(MAS_BANK_D1
, 0x7f8, &val_ll
, 1); /* LL */
802 mas_writemem(MAS_BANK_D1
, 0x7f9, &val_lr
, 1); /* LR */
803 mas_writemem(MAS_BANK_D1
, 0x7fa, &val_rl
, 1); /* RL */
804 mas_writemem(MAS_BANK_D1
, 0x7fb, &val_rr
, 1); /* RR */
810 /* This function works by telling the decoder that we have another
811 crystal frequency than we actually have. It will adjust its internal
812 parameters and the result is that the audio is played at another pitch.
814 The pitch value is in tenths of percent.
816 void mpeg_set_pitch(int pitch
)
820 /* invert pitch value */
821 pitch
= 1000000/pitch
;
823 /* Calculate the new (bogus) frequency */
824 val
= 18432*pitch
/1000;
826 mas_writemem(MAS_BANK_D0
,0x7f3,&val
,1);
828 /* We must tell the MAS that the frequency has changed.
829 This will unfortunately cause a short silence. */
830 mas_writemem(MAS_BANK_D0
,0x7f1,&shadow_7f1
,1);
834 void mp3_init(int volume
, int bass
, int treble
, int balance
, int loudness
,
835 int bass_boost
, int avc
, int channel_config
)
838 volume
= bass
= treble
= balance
= loudness
839 = bass_boost
= avc
= channel_config
;
843 loudness
= bass_boost
= avc
;
849 or_b(0x08, &PAIORH
); /* output for /PR */
852 mas_version_code
= mas_readver();
853 DEBUGF("MAS3587 derivate %d, version B%d\n",
854 (mas_version_code
& 0xff00) >> 8, mas_version_code
& 0xff);
862 and_b(~0x20, &PBDRL
);
867 /* set IRQ6 to edge detect */
870 /* set IRQ6 prio 8 */
871 IPRB
= ( IPRB
& 0xff0f ) | 0x0080;
873 mas_readmem(MAS_BANK_D1
, 0xff7, &mas_version_code
, 1);
875 mas_writereg(0x3b, 0x20); /* Don't ask why. The data sheet doesn't say */
879 /* Clear the upper 12 bits of the 32-bit samples */
880 mas_writereg(0xc5, 0);
881 mas_writereg(0xc6, 0);
883 /* We need to set the PLL for a 14.1318MHz crystal */
884 if(mas_version_code
== 0x0601) /* Version F10? */
887 mas_writemem(MAS_BANK_D0
, 0x32d, &val
, 1);
889 mas_writemem(MAS_BANK_D0
, 0x32e, &val
, 1);
891 mas_writemem(MAS_BANK_D0
, 0x32f, &val
, 1);
897 mas_writemem(MAS_BANK_D0
, 0x36d, &val
, 1);
899 mas_writemem(MAS_BANK_D0
, 0x36e, &val
, 1);
901 mas_writemem(MAS_BANK_D0
, 0x36f, &val
, 1);
910 mas_writereg(MAS_REG_KPRESCALE
, 0xe9400);
913 mpeg_sound_channel_config(channel_config
);
917 ICR
&= ~0x0010; /* IRQ3 level sensitive */
918 PACR1
= (PACR1
& 0x3fff) | 0x4000; /* PA15 is IRQ3 */
921 /* Must be done before calling mpeg_sound_set() */
922 mpeg_is_initialized
= true;
924 mpeg_sound_set(SOUND_BASS
, bass
);
925 mpeg_sound_set(SOUND_TREBLE
, treble
);
926 mpeg_sound_set(SOUND_BALANCE
, balance
);
927 mpeg_sound_set(SOUND_VOLUME
, volume
);
930 mpeg_sound_channel_config(channel_config
);
931 mpeg_sound_set(SOUND_LOUDNESS
, loudness
);
932 mpeg_sound_set(SOUND_SUPERBASS
, bass_boost
);
933 mpeg_sound_set(SOUND_AVC
, avc
);
935 #endif /* !SIMULATOR */
942 /* new functions, to be exported to plugin API */
946 void mp3_play_init(void)
953 callback_for_more
= NULL
;
954 mp3_reset_playtime();
957 void mp3_play_data(unsigned char* start
, int size
,
958 void (*get_more
)(unsigned char** start
, int* size
) /* callback fn */
963 CHCR3
&= ~0x0002; /* Clear interrupt */
964 CHCR3
= 0x1504; /* Single address destination, TXI0, IE=1 */
965 DMAOR
= 0x0001; /* Enable DMA */
967 callback_for_more
= get_more
;
969 SAR3
= (unsigned int)start
;
970 DTCR3
= size
& 0xffff;
975 CHCR3
|= 0x0001; /* Enable DMA IRQ */
978 demand_irq_enable(true);
982 void mp3_play_pause(bool play
)
985 { /* resume playback */
988 playstart_tick
= current_tick
;
990 else if (!paused
&& !play
)
991 { /* stop playback */
994 cumulative_ticks
+= current_tick
- playstart_tick
;
998 void mp3_play_stop(void)
1001 mp3_play_pause(false);
1002 CHCR3
&= ~0x0001; /* Disable the DMA interrupt */
1003 #ifdef HAVE_MAS3587F
1004 demand_irq_enable(false);
1008 long mp3_get_playtime(void)
1011 return cumulative_ticks
;
1013 return cumulative_ticks
+ current_tick
- playstart_tick
;
1016 void mp3_reset_playtime(void)
1018 cumulative_ticks
= 0;
1019 playstart_tick
= current_tick
;
1023 bool mp3_is_playing(void)
1029 /* returns the next byte position which would be transferred */
1030 unsigned char* mp3_get_pos(void)
1032 return (unsigned char*)SAR3
;
1036 #endif /* #ifndef SIMULATOR */