📄 audio_mp3drv.c
字号:
//=============================================================
// 文件名称: Audio_MP3Drv.c
// 功能描述: mp3播放
// 维护记录: 2007-01-16 v1.0
//=============================================================
#include "SPCE3200_Register.h"
#include "SPCE3200_Constant.h"
#include ".\MP4_Codec\MP4_Codec.h"
#define D_VolSel_0 0 //single channel will be 1/32 of max volume
#define D_VolSel_1 0x1<<6 //1/8
#define D_VolSel_2 0x2<<6 //1/2
#define D_VolSel_3 0x3<<6 //1
//MP3_Status
#define D_MP3_Play 0x0001
#define D_MP3_Pause 0x0002
#define D_MP3_Repeat 0x0004
#define D_MP3_Speed 0x0008
#define D_MP3_Data_End 0x0010
#define D_MP3_Encode 0x0020
#define D_MP3_Buf_Empty 0x0040
#define D_MP3_PCM_Empty 0x0080
#define SP4_BITSTREAM_FILL_BATCH 512
//Function definition
void SP4_FillSoftFIFO(unsigned short *TempPCM);
void SP4_EnableSoftCh(unsigned int Samplerate);
void SP4_read_bs(unsigned char *MP3_bs_buf, int temp_wp, int fill_size);
void SP4_read_bitstream(unsigned char *MP3_bs_buf, int *wp);
int SP4_get_bs_free_bytes(int wp);
//Variable definition
unsigned short *PCMAddress;
unsigned short *FIFOAddress;
unsigned char *g_pSP4_MP3Address;//unsigned short *Address;
//for KF
unsigned short *KFAudioEnd;
unsigned short SP4_FIFOArray[4096];
unsigned char MP3_bs_buf[SP4_MP3_BITSTREAM_BUFFER_SIZE];
short PCM_buf[1152*2];
short SP4_TempPCM[2048]; // half a SPU buffer
unsigned char decoder_instance[SP4_MP3_DECODER_WORK_SPACE];
unsigned short SP4_FIFOCounter=0, SP4_FIFO_Offset=0;
unsigned char SP4_TempData=0;//unsigned short SP4_TempData=0;
unsigned samplerate, bitrate;
int wp, rp;
int error_msg;
int space;
int pcm_cnt;
int pcm_wp, pcm_rp;
int temp_wp, temp_rp, TempPCM_ready, SP4_MP3Need_PCM_Flag;
int Fill_count;
int MP3_Status;
extern unsigned int MP4_State_Flag;
void SP4_FillSoftFIFO(unsigned short *TempPCM)
{
unsigned short TempValue;
unsigned short TempCounter;
for(TempCounter=0;TempCounter<2048;TempCounter++) // for stereo
{
TempValue = TempPCM[TempCounter];
TempValue ^= 0x8000;
SP4_FIFOArray[TempCounter+SP4_FIFO_Offset] = TempValue;
}
if(SP4_FIFOCounter != 0)
{
SP4_FIFO_Offset = 0;
SP4_FIFOCounter = 0;
}
else
{
SP4_FIFO_Offset += 2048;
SP4_FIFOCounter = 1;
}
}
void SP4_EnableSoftCh(unsigned int Samplerate)
{
unsigned int TempValue;
*P_DAC_BUFFER_SA = 0;
*P_DAC_FIFOBA_LOW = ((unsigned int)SP4_FIFOArray); // Set start address of buffer for SPU soft channel
*P_DAC_FIFOBA_HIGH = ((unsigned int)SP4_FIFOArray) >> 16;
if((MP3_Status&D_MP3_Speed) == 0)
{
TempValue = 27000000/Samplerate - 1; //Set sampling rate of current PCM file
*P_DAC_SAMPLE_CLK = TempValue;
}
*P_DAC_INT_STATUS = 0xC000 | 0x0004 | 0x0003; //Enable software channel as stereo, 8Kbytes buffer
*P_DAC_MODE_CTRL2 = (0x0608 | D_VolSel_1 | 0x1003); // for both channel
MP4_State_Flag |= MASK_MP4_AUDIO_READY;
}
unsigned int *MP3_Addr;
void SP4_Play_MP3(void)
{
*P_DAC_INT_STATUS = 0; //Stop SPU software channel
*P_DAC_MODE_CTRL2 = 0;
MP3_Status &= ~(D_MP3_Play | D_MP3_Pause); //Reset MP3 status
mp3_decoder_init(decoder_instance, MP3_bs_buf, 1);
g_pSP4_MP3Address = (unsigned char *)MP3_Addr; //MP3_Addr;
SP4_FIFOCounter=0;
SP4_FIFO_Offset=0;
wp = 0;
pcm_rp=0;
pcm_wp=0;
temp_wp=0;
TempPCM_ready=0;
// Fill buffer for playing. Data must be enough at first time.
SP4_read_bs(MP3_bs_buf, wp, SP4_MP3_BITSTREAM_BUFFER_SIZE-512);
wp = SP4_MP3_BITSTREAM_BUFFER_SIZE - 512;
Fill_count = 0;
SP4_MP3Need_PCM_Flag = 1;
MP3_Status |= D_MP3_Play;
}
void SP4_MP3_Service_Loop(void)
{
if( ((MP3_Status&D_MP3_Play) != 0) && ((MP3_Status&D_MP3_Pause) == 0) )
{
if(SP4_MP3Need_PCM_Flag == 1) //Check whether first or last half of FIFO need data
{
if(pcm_wp == pcm_rp) //Check whether PCM buffer is empty. If yes, decode next frame.
{
pcm_cnt = mp3_decoder_run(decoder_instance,wp,PCM_buf+pcm_wp); //Decode 1 frame and put data from pcm_rp.
pcm_wp += pcm_cnt*2;
if(pcm_wp >= 1152*2)
pcm_wp -= 1152*2;
}
do
{
SP4_TempPCM[temp_wp] = PCM_buf[pcm_rp];
pcm_rp ++;
if(pcm_rp >= 1152*2)
pcm_rp -= 1152*2;
temp_wp ++; // unit is words //Write pointer of SP4_TempPCM buffer, which spares data for SPU FIFO
if(temp_wp >= 2048)
{
temp_wp = 0;
TempPCM_ready = 1;
Fill_count++;
break; //Stop filling SP4_TempPCM buffer when it is full
}
}while(pcm_rp != pcm_wp); //or data in PCM buffer is empty.
error_msg = mp3_errno(decoder_instance);
if(error_msg != 0)
{
if((MP3_Status&D_MP3_Repeat) != 0)
{
SP4_Play_MP3();
SP4_MP3_Service_Loop();
SP4_MP3_Service_Loop();
SP4_MP3_Service_Loop();
SP4_MP3_Service_Loop();
SP4_MP3_Service_Loop();
SP4_MP3_Service_Loop();
SP4_MP3_Service_Loop();
SP4_MP3_Service_Loop();
}
}
space = SP4_get_bs_free_bytes(wp);
if(space > SP4_BITSTREAM_FILL_BATCH) //Check whether no. of data in MP3 buffer is lower than threshold
{
if(((char *)KFAudioEnd - (char *)g_pSP4_MP3Address) > 0)
{
SP4_read_bitstream(MP3_bs_buf, &wp);//If yes, fill new data.
}
else
{
MP4_State_Flag |= MASK_MP4_AUDIO_NEXT_KF;
}
}
if(TempPCM_ready == 1) //Check whether data in TempPCM buffer is enough to load to SPU FIFO
{
TempPCM_ready = 0;
if(Fill_count < 3)
SP4_FillSoftFIFO(SP4_TempPCM); //Fill data in SPU in the beginning. Spare 4K bytes data for 1st SPU IRQ.
else
{
SP4_MP3Need_PCM_Flag = 0;
}
if(Fill_count == 3)
{
bitrate = mp3_get_bitrate(decoder_instance);
samplerate = mp3_get_sampling_rate(decoder_instance);
SP4_EnableSoftCh(samplerate); // Start playing on SPU software channel
SP4_MP3Need_PCM_Flag = 0;
}
}
}
}
}
void SP4_Stop_MP3(void)
{
*P_DAC_INT_STATUS = 0;
*P_DAC_MODE_CTRL2 = 0;
MP3_Status = 0;
}
void SP4_Pause_MP3(void)
{
*P_DAC_INT_STATUS = 0;
*P_DAC_MODE_CTRL2 = 0;
MP3_Status |= D_MP3_Pause;
MP4_State_Flag &= ~MASK_MP4_AUDIO_READY;
}
void SP4_Resume_MP3(void)
{
Fill_count = 0;
SP4_MP3Need_PCM_Flag = 1;
MP3_Status &= ~D_MP3_Pause;
MP3_Status |= D_MP3_Play;
}
void SP4_Repeat_MP3(void)
{
MP3_Status |= D_MP3_Repeat;
}
void SP4_Cancel_Repeat_MP3(void)
{
MP3_Status &= ~D_MP3_Repeat;
}
int SP4_bs_byte_size(int wp)
{
int size;
int rp = mp3_decoder_read_index(decoder_instance);
size = wp - rp;
if(size < 0)
size += SP4_MP3_BITSTREAM_BUFFER_SIZE;
return(size);
}
int SP4_get_bs_free_bytes(int wp)
{
int space;
int rp = mp3_decoder_read_index(decoder_instance);
space = rp - wp;
if(space < 0)
space += SP4_MP3_BITSTREAM_BUFFER_SIZE;
return(space);
}
void SP4_read_bs(unsigned char *MP3_bs_buf, int temp_wp, int fill_size)
{
int count;
for(count=0;count<fill_size;count++)
{
SP4_TempData = *g_pSP4_MP3Address;
g_pSP4_MP3Address += 1;
if( (count+temp_wp) >= SP4_MP3_BITSTREAM_BUFFER_SIZE )
MP3_bs_buf[count+temp_wp-SP4_MP3_BITSTREAM_BUFFER_SIZE] = SP4_TempData;
else
MP3_bs_buf[count+temp_wp] = SP4_TempData;
}
}
void SP4_read_bitstream(unsigned char *MP3_bs_buf, int *wp)
{
int space;
int temp_wp;
int remains;
remains = (char *)KFAudioEnd - (char *)g_pSP4_MP3Address; //remaining audio data in a KF.
//r = remains%2;
temp_wp = *wp;
space = SP4_get_bs_free_bytes(temp_wp);
while(space > SP4_BITSTREAM_FILL_BATCH)
{
if (remains > SP4_BITSTREAM_FILL_BATCH)
{
SP4_read_bs(MP3_bs_buf, temp_wp, SP4_BITSTREAM_FILL_BATCH); //fill data in MP3_bs_buf
space -= SP4_BITSTREAM_FILL_BATCH;
temp_wp += SP4_BITSTREAM_FILL_BATCH;
if(temp_wp >= SP4_MP3_BITSTREAM_BUFFER_SIZE)
temp_wp -= SP4_MP3_BITSTREAM_BUFFER_SIZE;
remains -=SP4_BITSTREAM_FILL_BATCH;
}
else
{
if (remains > 0)
{
SP4_read_bs(MP3_bs_buf, temp_wp, remains); //fill data in MP3_bs_buf
space -= remains;
temp_wp += remains;
if(temp_wp >= SP4_MP3_BITSTREAM_BUFFER_SIZE)
temp_wp -= SP4_MP3_BITSTREAM_BUFFER_SIZE;
remains -=remains;
break;
}
else
{
break;
}
}
}
*wp = temp_wp;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -