forked from len0rd/rockbox
		
	git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18807 a1c6a512-1295-4272-9138-f99709370657
		
			
				
	
	
		
			619 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			619 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /***************************************************************************
 | |
|  *             __________               __   ___.
 | |
|  *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 | |
|  *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 | |
|  *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 | |
|  *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 | |
|  *                     \/            \/     \/    \/            \/
 | |
|  * $Id$
 | |
|  *
 | |
|  * Code that has been in mpeg.c before, now creating an encapsulated play
 | |
|  * data module, to be used by other sources than file playback as well.
 | |
|  *
 | |
|  * Copyright (C) 2004 by Linus Nielsen Feltzing
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU General Public License
 | |
|  * as published by the Free Software Foundation; either version 2
 | |
|  * of the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 | |
|  * KIND, either express or implied.
 | |
|  *
 | |
|  ****************************************************************************/
 | |
| #include <stdbool.h>
 | |
| #include "config.h"
 | |
| #include "debug.h"
 | |
| #include "panic.h"
 | |
| #include <kernel.h>
 | |
| #include "mp3_playback.h"
 | |
| #include "sound.h"
 | |
| #ifndef SIMULATOR
 | |
| #include "i2c.h"
 | |
| #include "mas.h"
 | |
| #include "dac.h"
 | |
| #include "system.h"
 | |
| #endif
 | |
| #include "audiohw.h"
 | |
| 
 | |
| /* hacking into mpeg.c, recording is still there */
 | |
| #if CONFIG_CODEC == MAS3587F
 | |
| enum
 | |
| {
 | |
|     MPEG_DECODER,
 | |
|     MPEG_ENCODER
 | |
| } mpeg_mode;
 | |
| #endif /* #ifdef MAS3587F */
 | |
| 
 | |
| #if ((CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)) && !defined(SIMULATOR)
 | |
| extern unsigned long shadow_io_control_main;
 | |
| extern unsigned shadow_codec_reg0;
 | |
| #endif
 | |
| 
 | |
| /**** globals ****/
 | |
| 
 | |
| /* own version, independent of mpeg.c */
 | |
| static bool paused; /* playback is paused */
 | |
| static bool playing; /* We are playing an MP3 stream */
 | |
| 
 | |
| #ifndef SIMULATOR
 | |
| /* for measuring the play time */
 | |
| static long playstart_tick;
 | |
| static long cumulative_ticks;
 | |
| 
 | |
| /* the registered callback function to ask for more mp3 data */
 | |
| static void (*callback_for_more)(unsigned char**, size_t*);
 | |
| #endif /* #ifndef SIMULATOR */
 | |
| 
 | |
| /* list of tracks in memory */
 | |
| #define MAX_ID3_TAGS (1<<4) /* Must be power of 2 */
 | |
| #define MAX_ID3_TAGS_MASK (MAX_ID3_TAGS - 1)
 | |
| 
 | |
| #ifndef SIMULATOR
 | |
| bool audio_is_initialized = false;
 | |
| #endif
 | |
| 
 | |
| /* FIX: this code pretty much assumes a MAS */
 | |
| 
 | |
| /* dirty calls to mpeg.c */
 | |
| extern void playback_tick(void);
 | |
| extern void rec_tick(void);
 | |
| 
 | |
| #ifndef SIMULATOR
 | |
| 
 | |
| unsigned long mas_version_code;
 | |
| 
 | |
| #if CONFIG_CODEC == MAS3507D
 | |
| static void mas_poll_start(void)
 | |
| {
 | |
|     unsigned int count;
 | |
| 
 | |
|     count = 9 * FREQ / 10000 / 8; /* 0.9 ms */
 | |
| 
 | |
|     /* We are using timer 1 */
 | |
|     
 | |
|     TSTR &= ~0x02; /* Stop the timer */
 | |
|     TSNC &= ~0x02; /* No synchronization */
 | |
|     TMDR &= ~0x02; /* Operate normally */
 | |
| 
 | |
|     TCNT1 = 0;   /* Start counting at 0 */
 | |
|     GRA1 = count;
 | |
|     TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */
 | |
| 
 | |
|     /* Enable interrupt on level 5 */
 | |
|     IPRC = (IPRC & ~0x000f) | 0x0005;
 | |
|     
 | |
|     TSR1 &= ~0x02;
 | |
|     TIER1 = 0xf9; /* Enable GRA match interrupt */
 | |
| 
 | |
|     TSTR |= 0x02; /* Start timer 1 */
 | |
| }
 | |
| #elif CONFIG_CODEC != SWCODEC
 | |
| static void postpone_dma_tick(void)
 | |
| {
 | |
|     unsigned int count;
 | |
| 
 | |
|     count = 8 * FREQ / 10000 / 8; /* 0.8 ms */
 | |
| 
 | |
|     /* We are using timer 1 */
 | |
|     
 | |
|     TSTR &= ~0x02; /* Stop the timer */
 | |
|     TSNC &= ~0x02; /* No synchronization */
 | |
|     TMDR &= ~0x02; /* Operate normally */
 | |
| 
 | |
|     TCNT1 = 0;   /* Start counting at 0 */
 | |
|     GRA1 = count;
 | |
|     TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */
 | |
| 
 | |
|     /* Enable interrupt on level 5 */
 | |
|     IPRC = (IPRC & ~0x000f) | 0x0005;
 | |
|     
 | |
|     TSR1 &= ~0x02;
 | |
|     TIER1 = 0xf9; /* Enable GRA match interrupt */
 | |
| 
 | |
|     TSTR |= 0x02; /* Start timer 1 */
 | |
| }
 | |
| #endif
 | |
| 
 | |
| 
 | |
| #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
 | |
| void demand_irq_enable(bool on)
 | |
| {
 | |
|     int oldlevel = disable_irq_save();
 | |
|     
 | |
|     if(on)
 | |
|     {
 | |
|         IPRA = (IPRA & 0xfff0) | 0x000b;
 | |
|         ICR &= ~0x0010; /* IRQ3 level sensitive */
 | |
|     }
 | |
|     else
 | |
|         IPRA &= 0xfff0;
 | |
| 
 | |
|     restore_irq(oldlevel);
 | |
| }
 | |
| #endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
 | |
| 
 | |
| 
 | |
| static void play_tick(void)
 | |
| {
 | |
|     if(playing && !paused)
 | |
|     {
 | |
|         /* Start DMA if it is disabled and the DEMAND pin is high */
 | |
|         if(!(SCR0 & 0x80) && (PBDR & 0x4000))
 | |
|         {
 | |
|             SCR0 |= 0x80;
 | |
|         }
 | |
| 
 | |
|         playback_tick(); /* dirty call to mpeg.c */
 | |
|     }
 | |
| }
 | |
| 
 | |
| void DEI3(void) __attribute__((interrupt_handler));
 | |
| void DEI3(void)
 | |
| {
 | |
|     unsigned char* start;
 | |
|     size_t size = 0;
 | |
| 
 | |
|     if (callback_for_more != NULL)
 | |
|     {
 | |
|         callback_for_more(&start, &size);
 | |
|     }
 | |
|     
 | |
|     if (size > 0)
 | |
|     {
 | |
|         DTCR3 = size & 0xffff;
 | |
|         SAR3 = (unsigned int) start;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         CHCR3 &= ~0x0001; /* Disable the DMA interrupt */
 | |
|     }
 | |
| 
 | |
|     CHCR3 &= ~0x0002; /* Clear DMA interrupt */
 | |
| }
 | |
| 
 | |
| void IMIA1(void) __attribute__((interrupt_handler));
 | |
| void IMIA1(void) /* Timer 1 interrupt */
 | |
| {
 | |
|     if(playing)
 | |
|         play_tick();
 | |
|     TSR1 &= ~0x01;
 | |
| #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
 | |
|     /* Disable interrupt */
 | |
|     IPRC &= ~0x000f;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void IRQ6(void) __attribute__((interrupt_handler));
 | |
| void IRQ6(void) /* PB14: MAS stop demand IRQ */
 | |
| {
 | |
|     SCR0 &= ~0x80;
 | |
| }
 | |
| 
 | |
| #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
 | |
| void IRQ3(void) __attribute__((interrupt_handler));
 | |
| void IRQ3(void) /* PA15: MAS demand IRQ */
 | |
| {
 | |
|     /* Begin with setting the IRQ to edge sensitive */
 | |
|     ICR |= 0x0010;
 | |
| 
 | |
| #if CONFIG_CODEC == MAS3587F
 | |
|     if(mpeg_mode == MPEG_ENCODER)
 | |
|         rec_tick();
 | |
|     else
 | |
| #endif
 | |
|         postpone_dma_tick();
 | |
| 
 | |
|     /* Workaround for sh-elf-gcc 3.3.x bug with -O2 or -Os and ISRs
 | |
|      * (invalid cross-jump optimisation) */
 | |
|     asm volatile ("");
 | |
| }
 | |
| #endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
 | |
| 
 | |
| static void setup_sci0(void)
 | |
| {
 | |
|     /* PB15 is I/O, PB14 is IRQ6, PB12 is SCK0, PB9 is TxD0 */
 | |
|     PBCR1 = (PBCR1 & 0x0cff) | 0x1208;
 | |
|     
 | |
|     /* Set PB12 to output */
 | |
|     or_b(0x10, &PBIORH);
 | |
| 
 | |
|     /* Disable serial port */
 | |
|     SCR0 = 0x00;
 | |
| 
 | |
|     /* Synchronous, no prescale */
 | |
|     SMR0 = 0x80;
 | |
| 
 | |
|     /* Set baudrate 1Mbit/s */
 | |
|     BRR0 = 0x02;
 | |
| 
 | |
|     /* use SCK as serial clock output */
 | |
|     SCR0 = 0x01;
 | |
| 
 | |
|     /* Clear FER and PER */
 | |
|     SSR0 &= 0xe7;
 | |
| 
 | |
|     /* Set interrupt ITU2 and SCI0 priority to 0 */
 | |
|     IPRD &= 0x0ff0;
 | |
| 
 | |
|     /* set PB15 and PB14 to inputs */
 | |
|      and_b(~0x80, &PBIORH);
 | |
|      and_b(~0x40, &PBIORH);
 | |
| 
 | |
|     /* Enable End of DMA interrupt at prio 8 */
 | |
|     IPRC = (IPRC & 0xf0ff) | 0x0800;
 | |
|     
 | |
|     /* Enable Tx (only!) */
 | |
|     SCR0 |= 0x20;
 | |
| }
 | |
| 
 | |
| #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
 | |
| static void init_playback(void)
 | |
| {
 | |
|     unsigned long val;
 | |
|     int rc;
 | |
| 
 | |
|     mp3_play_pause(false);
 | |
|     
 | |
|     mas_reset();
 | |
| 
 | |
|     /* Enable the audio CODEC and the DSP core, max analog voltage range */
 | |
|     rc = mas_direct_config_write(MAS_CONTROL, 0x8c00);
 | |
|     if(rc < 0)
 | |
|         panicf("mas_ctrl_w: %d", rc);
 | |
| 
 | |
|     /* Stop the current application */
 | |
|     val = 0;
 | |
|     mas_writemem(MAS_BANK_D0, MAS_D0_APP_SELECT, &val, 1);
 | |
|     do
 | |
|     {
 | |
|         mas_readmem(MAS_BANK_D0, MAS_D0_APP_RUNNING, &val, 1);
 | |
|     } while(val);
 | |
|     
 | |
|     /* Enable the D/A Converter */
 | |
|     shadow_codec_reg0 = 0x0001;
 | |
|     mas_codec_writereg(0x0, shadow_codec_reg0);
 | |
| 
 | |
|     /* ADC scale 0%, DSP scale 100% */
 | |
|     mas_codec_writereg(6, 0x0000);
 | |
|     mas_codec_writereg(7, 0x4000);
 | |
| 
 | |
| #ifdef HAVE_SPDIF_OUT
 | |
|     val = 0x09; /* Disable SDO and SDI, low impedance S/PDIF outputs */
 | |
| #else
 | |
|     val = 0x2d; /* Disable SDO and SDI, disable S/PDIF output */
 | |
| #endif
 | |
|     mas_writemem(MAS_BANK_D0, MAS_D0_INTERFACE_CONTROL, &val, 1);
 | |
| 
 | |
|     /* Set Demand mode and validate all settings */
 | |
|     shadow_io_control_main = 0x25;
 | |
|     mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
 | |
| 
 | |
|     /* Start the Layer2/3 decoder applications */
 | |
|     val = 0x0c;
 | |
|     mas_writemem(MAS_BANK_D0, MAS_D0_APP_SELECT, &val, 1);
 | |
|     do
 | |
|     {
 | |
|         mas_readmem(MAS_BANK_D0, MAS_D0_APP_RUNNING, &val, 1);
 | |
|     } while((val & 0x0c) != 0x0c);
 | |
| 
 | |
| #if CONFIG_CODEC == MAS3587F
 | |
|     mpeg_mode = MPEG_DECODER;
 | |
| #endif
 | |
| 
 | |
|     /* set IRQ6 to edge detect */
 | |
|     ICR |= 0x02;
 | |
| 
 | |
|     /* set IRQ6 prio 8 */
 | |
|     IPRB = ( IPRB & 0xff0f ) | 0x0080;
 | |
| 
 | |
|     DEBUGF("MAS Decoding application started\n");
 | |
| }
 | |
| #endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
 | |
| #endif /* SIMULATOR */
 | |
| 
 | |
| void mp3_init(int volume, int bass, int treble, int balance, int loudness,
 | |
|               int avc, int channel_config, int stereo_width,
 | |
|               int mdb_strength, int mdb_harmonics,
 | |
|               int mdb_center, int mdb_shape, bool mdb_enable,
 | |
|               bool superbass)
 | |
| {
 | |
| #ifdef SIMULATOR
 | |
|     (void)volume;
 | |
|     (void)bass;
 | |
|     (void)treble;
 | |
|     (void)balance;
 | |
|     (void)loudness;
 | |
|     (void)avc;
 | |
|     (void)channel_config;
 | |
|     (void)stereo_width;
 | |
|     (void)mdb_strength;
 | |
|     (void)mdb_harmonics;
 | |
|     (void)mdb_center;
 | |
|     (void)mdb_shape;
 | |
|     (void)mdb_enable;
 | |
|     (void)superbass;
 | |
| #else
 | |
| #if CONFIG_CODEC == MAS3507D
 | |
|     unsigned long val;
 | |
|     (void)loudness;
 | |
|     (void)avc;
 | |
|     (void)mdb_strength;
 | |
|     (void)mdb_harmonics;
 | |
|     (void)mdb_center;
 | |
|     (void)mdb_shape;
 | |
|     (void)mdb_enable;
 | |
|     (void)superbass;
 | |
| #endif
 | |
| 
 | |
|     setup_sci0();
 | |
| 
 | |
| #ifdef HAVE_MAS_SIBI_CONTROL
 | |
|     and_b(~0x01, &PBDRH); /* drive SIBI low */
 | |
|     or_b(0x01, &PBIORH); /* output for PB8 */
 | |
| #endif
 | |
| 
 | |
| #if CONFIG_CODEC == MAS3507D
 | |
|     mas_reset();
 | |
| #elif CONFIG_CODEC == MAS3587F
 | |
|     or_b(0x08, &PAIORH); /* output for /PR */
 | |
|     init_playback();
 | |
|     
 | |
|     mas_version_code = mas_readver();
 | |
|     DEBUGF("MAS3587 derivate %d, version %c%d\n",
 | |
|            (mas_version_code & 0xf000) >> 12,
 | |
|            'A' + ((mas_version_code & 0x0f00) >> 8), mas_version_code & 0xff);
 | |
| #elif CONFIG_CODEC == MAS3539F
 | |
|     or_b(0x08, &PAIORH); /* output for /PR */
 | |
|     init_playback();
 | |
|     
 | |
|     mas_version_code = mas_readver();
 | |
|     DEBUGF("MAS3539 derivate %d, version %c%d\n",
 | |
|            (mas_version_code & 0xf000) >> 12,
 | |
|            'A' + ((mas_version_code & 0x0f00) >> 8), mas_version_code & 0xff);
 | |
| #endif
 | |
| 
 | |
| #ifdef HAVE_DAC3550A
 | |
|     dac_init();
 | |
| #endif
 | |
|     
 | |
| #if CONFIG_CODEC == MAS3507D
 | |
|     /* set IRQ6 to edge detect */
 | |
|     ICR |= 0x02;
 | |
| 
 | |
|     /* set IRQ6 prio 8 */
 | |
|     IPRB = ( IPRB & 0xff0f ) | 0x0080;
 | |
| 
 | |
|     mas_readmem(MAS_BANK_D1, 0xff7, &mas_version_code, 1);
 | |
|     
 | |
|     mas_writereg(0x3b, 0x20); /* Don't ask why. The data sheet doesn't say */
 | |
|     mas_run(1);
 | |
|     sleep(HZ);
 | |
| 
 | |
|     /* Clear the upper 12 bits of the 32-bit samples */
 | |
|     mas_writereg(0xc5, 0);
 | |
|     mas_writereg(0xc6, 0);
 | |
|     
 | |
|     /* We need to set the PLL for a 14.31818MHz crystal */
 | |
|     if(mas_version_code == 0x0601) /* Version F10? */
 | |
|     {
 | |
|         val = 0x5d9d0;
 | |
|         mas_writemem(MAS_BANK_D0, 0x32d, &val, 1);
 | |
|         val = 0xfffceceb;
 | |
|         mas_writemem(MAS_BANK_D0, 0x32e, &val, 1);
 | |
|         val = 0x0;
 | |
|         mas_writemem(MAS_BANK_D0, 0x32f, &val, 1);
 | |
|         mas_run(0x475);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         val = 0x5d9d0;
 | |
|         mas_writemem(MAS_BANK_D0, 0x36d, &val, 1);
 | |
|         val = 0xfffceceb;
 | |
|         mas_writemem(MAS_BANK_D0, 0x36e, &val, 1);
 | |
|         val = 0x0;
 | |
|         mas_writemem(MAS_BANK_D0, 0x36f, &val, 1);
 | |
|         mas_run(0xfcb);
 | |
|     }
 | |
|     
 | |
| #endif
 | |
| 
 | |
| #if CONFIG_CODEC == MAS3507D
 | |
|     mas_poll_start();
 | |
| 
 | |
|     mas_writereg(MAS_REG_KPRESCALE, 0xe9400);
 | |
|     dac_enable(true);
 | |
| #endif
 | |
| 
 | |
| #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
 | |
|     ICR &= ~0x0010; /* IRQ3 level sensitive */
 | |
|     PACR1 = (PACR1 & 0x3fff) | 0x4000; /* PA15 is IRQ3 */
 | |
| #endif
 | |
| 
 | |
|     /* Must be done before calling sound_set() */
 | |
|     audio_is_initialized = true;
 | |
| 
 | |
|     sound_set(SOUND_BASS, bass);
 | |
|     sound_set(SOUND_TREBLE, treble);
 | |
|     sound_set(SOUND_BALANCE, balance);
 | |
|     sound_set(SOUND_VOLUME, volume);
 | |
|     sound_set(SOUND_CHANNELS, channel_config);
 | |
|     sound_set(SOUND_STEREO_WIDTH, stereo_width);
 | |
|     
 | |
| #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
 | |
|     sound_set(SOUND_LOUDNESS, loudness);
 | |
|     sound_set(SOUND_AVC, avc);
 | |
|     sound_set(SOUND_MDB_STRENGTH, mdb_strength);
 | |
|     sound_set(SOUND_MDB_HARMONICS, mdb_harmonics);
 | |
|     sound_set(SOUND_MDB_CENTER, mdb_center);
 | |
|     sound_set(SOUND_MDB_SHAPE, mdb_shape);
 | |
|     sound_set(SOUND_MDB_ENABLE, mdb_enable);
 | |
|     sound_set(SOUND_SUPERBASS, superbass);
 | |
| #endif
 | |
| #endif /* !SIMULATOR */
 | |
| 
 | |
|     playing = false;
 | |
|     paused = true;
 | |
| }
 | |
| 
 | |
| void mp3_shutdown(void)
 | |
| {
 | |
| #ifndef SIMULATOR
 | |
| #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
 | |
|     unsigned long val = 1;
 | |
|     mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &val, 1); /* Mute */
 | |
| #endif
 | |
| 
 | |
| #if CONFIG_CODEC == MAS3507D
 | |
|     dac_volume(0, 0, false);
 | |
| #endif
 | |
| 
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /* new functions, to be exported to plugin API */
 | |
| 
 | |
| #ifndef SIMULATOR
 | |
| 
 | |
| void mp3_play_init(void)
 | |
| {
 | |
| #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
 | |
|     init_playback();
 | |
| #endif
 | |
|     playing = false;
 | |
|     paused = true;
 | |
|     callback_for_more = NULL;
 | |
|     mp3_reset_playtime();
 | |
| }
 | |
| 
 | |
| void mp3_play_data(const unsigned char* start, int size,
 | |
|     void (*get_more)(unsigned char** start, size_t* size) /* callback fn */
 | |
| )
 | |
| {
 | |
|     /* init DMA */
 | |
|     DAR3 = 0x5FFFEC3;
 | |
|     CHCR3 &= ~0x0002; /* Clear interrupt */
 | |
|     CHCR3 = 0x1504; /* Single address destination, TXI0, IE=1 */
 | |
|     DMAOR = 0x0001; /* Enable DMA */
 | |
|     
 | |
|     callback_for_more = get_more;
 | |
| 
 | |
|     SAR3 = (unsigned int)start;
 | |
|     DTCR3 = size & 0xffff;
 | |
| 
 | |
|     playing = true;
 | |
|     paused = true;
 | |
| 
 | |
|     CHCR3 |= 0x0001; /* Enable DMA IRQ */
 | |
| 
 | |
| #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
 | |
|     demand_irq_enable(true);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void mp3_play_pause(bool play)
 | |
| {
 | |
|     if (paused && play)
 | |
|     {   /* resume playback */
 | |
|         SCR0 |= 0x80;
 | |
|         paused = false;
 | |
|         playstart_tick = current_tick;
 | |
|     }
 | |
|     else if (!paused && !play)
 | |
|     {   /* stop playback */
 | |
|         SCR0 &= 0x7f;
 | |
|         paused = true;
 | |
|         cumulative_ticks += current_tick - playstart_tick;
 | |
|     }
 | |
| }     
 | |
| 
 | |
| bool mp3_pause_done(void)
 | |
| {
 | |
|     unsigned long frame_count;
 | |
| 
 | |
|     if (!paused)
 | |
|         return false;
 | |
|     
 | |
|     mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT, &frame_count, 1);
 | |
|     /* This works because the frame counter never wraps,
 | |
|      * i.e. zero always means lost sync. */
 | |
|     return frame_count == 0;
 | |
| }
 | |
| 
 | |
| void mp3_play_stop(void)
 | |
| {
 | |
|     playing = false;
 | |
|     mp3_play_pause(false);
 | |
|     CHCR3 &= ~0x0001; /* Disable the DMA interrupt */
 | |
| #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
 | |
|     demand_irq_enable(false);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| long mp3_get_playtime(void)
 | |
| {
 | |
|     if (paused)
 | |
|         return cumulative_ticks;
 | |
|     else
 | |
|         return cumulative_ticks + current_tick - playstart_tick;
 | |
| }
 | |
| 
 | |
| void mp3_reset_playtime(void)
 | |
| {
 | |
|     cumulative_ticks = 0;
 | |
|     playstart_tick = current_tick;
 | |
| }
 | |
| 
 | |
| bool mp3_is_playing(void)
 | |
| {
 | |
|     return playing;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* returns the next byte position which would be transferred */
 | |
| unsigned char* mp3_get_pos(void)
 | |
| {
 | |
|     return (unsigned char*)SAR3;
 | |
| }
 | |
| #else  /* #ifndef SIMULATOR */
 | |
| 
 | |
| void mp3_play_pause(bool play)
 | |
| {
 | |
|     (void)play;
 | |
| }
 | |
| void mp3_play_stop(void)
 | |
| {
 | |
| }
 | |
| 
 | |
| unsigned char* mp3_get_pos(void)
 | |
| {
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| void mp3_play_data(const unsigned char* start, int size,
 | |
|     void (*get_more)(unsigned char** start, size_t* size) /* callback fn */
 | |
| )
 | |
| {
 | |
|     (void)start; (void)size; (void)get_more;
 | |
| }
 | |
| #endif 
 |