⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mp3drv_v1.3.c

📁 凌阳SPCE3200多媒体开发板自带源程序。共安排了32个子目录
💻 C
字号:
//#include ".\include\TypeDef.h"					  							//Type definition.
//#include ".\include\SPU.h"                          							//SPU Register Defination.
//#include ".\include\SPG290.h"											//System Registers.
//#include ".\library\mp3.h"
//#include ".\library\EQ.h"

#include ".\Peripheral\PeripheralHeader.h"
#include ".\Function\FunctionHeader.h"
#include ".\System\SystemHeader.h"
#include ".\UserDemo\UserDemoHeader.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

#define BITSTREAM_FILL_BATCH 512
//#define	TempPCM_Buffer_Size	2048	// unit is word
#define	TempPCM_Buffer_Size	4096
//#define	TempPCM_Buffer_Size	8192

//External definition
extern unsigned char *L_PCMFiles;

//Function definition
void FillSoftFIFO(void);
void EnableSoftCh(unsigned int Samplerate);
void read_bs(unsigned short *MP3_bs_buf, int temp_wp, int fill_size);
void read_bitstream(unsigned short *MP3_bs_buf, int *wp);
void Play_MP3(unsigned int MP3_Addr, unsigned int Length);
void Stop_MP3(void);

//Variable definition
unsigned short	*PCMAddress;
unsigned short	*FIFOAddress;
unsigned short *TempAddress;
unsigned short *Address;
unsigned short *MP3_Start_Addr;

unsigned short	FIFOArray[4096];
unsigned short MP3_bs_buf[MP3_BITSTREAM_BUFFER_SIZE/2];
short	PCM_buf[1152*2];
unsigned char decoder_instance[MP3_DECODER_WORK_SPACE];
short 	TempPCM[TempPCM_Buffer_Size];
short	ADC_PCM_Buf_1[MP3_PCM_BUFFER_SIZE*2];
short	ADC_PCM_Buf_2[MP3_PCM_BUFFER_SIZE*2];
short	MP3_Encoded_Data_Buf_1[51200*3/2]={0};	// Initial as '0' to avoid non-zero value be viewed as MP3 data
short	MP3_Encoded_Data_Buf_2[51200*3/2]={0};
short	MP3_Encoded_Data_Buf_Spare[4096/2]={0};
unsigned int MP3_Encoded_Data_Buf_Index=0;
unsigned char *MP3_Encoded_Data_Ptr;

unsigned short	FIFOCounter=0, FIFO_Offset=0;
unsigned short	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, Need_PCM_Flag;
int Fill_count;
unsigned MP3_Status, MP3_Output_Type;
unsigned int MP3_Length;	// added by Bruce, 2006/3/9

#ifdef	EQ_ON
	int EQ_Band_No=5;
	int EQ_Mode=0;
	int custom_gain[7] = {12, 7, -12, -10, 0, 11, -9};
	int MP3_Spectrum[2][7];
#endif

void FillSoftFIFO(void)
{
	unsigned short TempValue;
	unsigned short TempCounter;
	
	if(MP3_Output_Type == Stereo)
	{		
		for(TempCounter=0;TempCounter<2048;TempCounter++)
		{
			TempValue = TempPCM[temp_rp];
			TempValue ^= 0x8000;
			FIFOArray[TempCounter+FIFO_Offset] = TempValue;
			temp_rp++;
			if(temp_rp == TempPCM_Buffer_Size)
				temp_rp = 0;
			if( (MP3_Status&0x50) == 0x50)
			{
				if(temp_rp == temp_wp)
					MP3_Status |= D_MP3_PCM_Empty;
			}
		}
	}
	else if(MP3_Output_Type == Left_Only)
	{
		for(TempCounter=0;TempCounter<1024;TempCounter++)	// for stereo
		{
			TempValue = TempPCM[temp_rp];
			TempValue ^= 0x8000;
			FIFOArray[TempCounter*2+FIFO_Offset] = TempValue;
			FIFOArray[TempCounter*2+1+FIFO_Offset] = TempValue;
			temp_rp += 2;
			if(temp_rp == TempPCM_Buffer_Size)
				temp_rp = 0;
			if( (MP3_Status&0x50) == 0x50)
			{
				if((temp_rp == temp_wp) || (temp_rp-temp_wp == 1) || (temp_wp-temp_rp == TempPCM_Buffer_Size-1))
					MP3_Status |= D_MP3_PCM_Empty;
			}
		}
	}
	else if(MP3_Output_Type == Right_Only)
	{
		for(TempCounter=0;TempCounter<1024;TempCounter++)	// for stereo
		{
			TempValue = TempPCM[temp_rp+1];
			TempValue ^= 0x8000;
			FIFOArray[TempCounter*2+FIFO_Offset] = TempValue;
			FIFOArray[TempCounter*2+1+FIFO_Offset] = TempValue;
			temp_rp += 2;
			if(temp_rp == TempPCM_Buffer_Size)
				temp_rp = 0;
			if( (MP3_Status&0x50) == 0x50)
			{
				if((temp_rp == temp_wp) || (temp_rp-temp_wp == 1) || (temp_wp-temp_rp == TempPCM_Buffer_Size-1))
					MP3_Status |= D_MP3_PCM_Empty;
			}
		}
	}
	
	
	if(FIFOCounter != 0)
	{
		FIFO_Offset = 0;
		FIFOCounter = 0;
	}
	else
	{
		FIFO_Offset += 2048;
		FIFOCounter = 1;
	}
}


void MP3_Service_Loop_ISR(void)
{
	if( (MP3_Status&0xd0) == 0xd0)
	{
		if((MP3_Status&D_MP3_Repeat) != 0)
			Play_MP3(MP3_Start_Addr,MP3_Length);
		else
			Stop_MP3();
		return;
	}
	if( ((MP3_Status&D_MP3_Play) != 0) && ((MP3_Status&D_MP3_Pause) == 0) )
	{
		FillSoftFIFO();
		Need_PCM_Flag = 1;		// Set flag to start MP3 decoder
		*P_DAC_INT_STATUS = 0xC000 | 0x0004 | 0x0003;	// for stereo, 8KBytes
	}
}


void EnableSoftCh(unsigned int Samplerate)
{
	unsigned int TempValue;
	*P_DAC_BUFFER_SA = 0;
	*P_DAC_FIFOBA_LOW = ((unsigned int)FIFOArray);			//Set start address of buffer for SPU soft channel
	*P_DAC_FIFOBA_HIGH = ((unsigned int)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;
	}
//#ifdef stereo
//#ifdef 8KBytes
	*P_DAC_INT_STATUS = 0x4000 | 0x0004 | 0x0003;			//Enable software channel as stereo, 8Kbytes buffer
	*P_DAC_MODE_CTRL2 = (0x0608 | D_VolSel_1 | 0x1003); // for both channel
}

void Init_MP3(void)
{
	*P_DAC_INT_STATUS = 0;			//Stop SPU software channel
	*P_DAC_MODE_CTRL2  = 0;
	MP3_Status = 0;
	Address = 0;
	MP3_Start_Addr = 0;
}

void Play_MP3(unsigned int MP3_Addr, unsigned int Length)
{	
	*P_DAC_INT_STATUS = 0;			//Stop SPU software channel
	*P_DAC_MODE_CTRL2  = 0;
	MP3_Status &= ~(D_MP3_Play | D_MP3_Pause | D_MP3_Data_End | D_MP3_Buf_Empty | D_MP3_PCM_Empty);	//Reset MP3 status
	
	mp3_decoder_init(decoder_instance, MP3_bs_buf, 1);	
	Address = MP3_Addr;
	MP3_Start_Addr = MP3_Addr;
	MP3_Length = Length;
	
	FIFOCounter=0;
	FIFO_Offset=0;
	wp = 0;
	pcm_rp=0;
	pcm_wp=0;
	temp_wp=0;
	temp_rp=0;
	TempPCM_ready=0;
	
	// Fill buffer for playing. Data must be enough at first time.
	read_bs(MP3_bs_buf, wp, MP3_BITSTREAM_BUFFER_SIZE/2-256);
	wp = (MP3_BITSTREAM_BUFFER_SIZE/2 - 256) *2;
	
	Fill_count = 0;
	Need_PCM_Flag = 1;
	MP3_Status |= D_MP3_Play;
	MP3_Output_Type = Stereo;
}


unsigned int Get_MP3_Status(void)
{
	return(MP3_Status);
}

void Stop_MP3(void)
{
	*P_DAC_INT_STATUS = 0;
	*P_DAC_MODE_CTRL2  = 0;
	MP3_Status = 0;
}

void Pause_MP3(void)
{
	*P_DAC_INT_STATUS = 0;
	*P_DAC_MODE_CTRL2  = 0;
	MP3_Status |= D_MP3_Pause;
}

void Resume_MP3(void)
{
	Fill_count = 0;
	Need_PCM_Flag = 1;
	MP3_Status &= ~D_MP3_Pause;
	MP3_Status |= D_MP3_Play;
}

void SpeedUp_MP3(void)
{
	unsigned int TempValue;
	unsigned int Temp1,Temp2;
	
	Temp1 = *P_DAC_INT_STATUS;
	Temp2 = *P_DAC_MODE_CTRL2;
	*P_DAC_INT_STATUS = 0;					//Stop SPU software channel
	*P_DAC_MODE_CTRL2  = 0;
	
	TempValue = *P_SPU_CompControl;
	//TempSR = 27000000/(TempValue+1);		//Get sampling rate of current PCM file
	//TempSR += 100;							//Get new sample rate
	//TempValue = 27000000/TempSR - 1;
	TempValue -= 1;
	
	*P_DAC_SAMPLE_CLK = TempValue;
	*P_DAC_INT_STATUS = Temp1;
	*P_DAC_MODE_CTRL2 = Temp2;
	Fill_count = 0;
	Need_PCM_Flag = 1;
	MP3_Status |= D_MP3_Speed;				//Prevent sampling rate from reset.
}

void SpeedDown_MP3(void)
{
	unsigned int TempValue;
	unsigned int Temp1,Temp2;
	
	Temp1 = *P_DAC_INT_STATUS;
	Temp2 = *P_DAC_MODE_CTRL2;
	*P_DAC_INT_STATUS = 0;					//Stop SPU software channel
	*P_DAC_MODE_CTRL2 = 0;
	
	TempValue = *P_DAC_SAMPLE_CLK;
	//TempSR = 27000000/(TempValue+1);		//Get sampling rate of current PCM file
	//TempSR += 100;							//Get new sample rate
	//TempValue = 27000000/TempSR - 1;
	TempValue += 1;
	
	*P_DAC_SAMPLE_CLK = TempValue;
	*P_DAC_INT_STATUS = Temp1;
	*P_DAC_MODE_CTRL2 = Temp2;
	Fill_count = 0;
	Need_PCM_Flag = 1;
	MP3_Status |= D_MP3_Speed;				//Prevent sampling rate from reset.
}

void Repeat_ON_MP3(void)
{
	MP3_Status |= D_MP3_Repeat;
}

void Repeat_OFF_MP3(void)
{
	MP3_Status &= ~D_MP3_Repeat;
}

void MP3_Output_Stereo(void)
{
	MP3_Output_Type = Stereo;
}

void MP3_Output_Left_Only(void)
{
	MP3_Output_Type = Left_Only;
}

void MP3_Output_Right_Only(void)
{
	MP3_Output_Type = Right_Only;
}


#ifdef	EQ_ON
void MP3_EQ_Mode_Change(int eq_effect_index)
{
	eq_change_effect(eq_effect_index);
}

void MP3_Get_Spectrum(void)
{
	eq_read_band_value(MP3_Spectrum);
}
#endif

void MP3_Service_Loop(void)
{	
	if( ((MP3_Status&D_MP3_Play) != 0) && ((MP3_Status&D_MP3_Pause) == 0) )
	{
		if( (MP3_Status&0x70) == 0x70)
			MP3_Status &= ~D_MP3_Play;
	
		if(Need_PCM_Flag == 1)			//Check whether first or last half of FIFO need data
		{
			//*P_GPIO_TFT_PORT |= 0x02;	// test performance
			if(pcm_wp == pcm_rp)		//Check whether PCM buffer is empty. If yes, decode next frame.
			{
				//*P_GPIO_TFT_PORT |= 0x04;	// test performance
				pcm_cnt = mp3_decoder_run(decoder_instance, wp, PCM_buf+pcm_wp);	//Decode 1 frame and put data from pcm_rp.
				//*P_GPIO_TFT_PORT &= ~0x04;	// test performance
 				if(pcm_cnt == 0)
				{
					if((MP3_Status&D_MP3_Data_End) != 0)
					{
						MP3_Status |= D_MP3_Buf_Empty;
						return;
					}
				} 
				pcm_wp += pcm_cnt*2;
				if(pcm_wp >= 1152*2)
					pcm_wp -= 1152*2;
			}
			
		if(pcm_cnt != 0)
		{
			do
			{
				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 TempPCM buffer, which spares data for SPU FIFO
				if( (temp_rp - temp_wp == 1) || (temp_wp - temp_rp == (TempPCM_Buffer_Size-1)) )
				{
					TempPCM_ready = 1;
					break;
				}
				#ifdef	EQ_ON
					if(temp_wp%2048 == 0)	// Added for EQ
					{
						//*P_TFT_GPIO_OUT |= 0x08;	// test performance
						eq_run_stereo(TempPCM+temp_wp-2048, TempPCM+temp_wp-2048, 2048/2);
						//*P_TFT_GPIO_OUT &= ~0x08;	// test performance
					}
				#endif
				if( (temp_wp%2048) == 0 && Fill_count<3)
				{
					if(temp_wp == TempPCM_Buffer_Size)
						temp_wp = 0;
					TempPCM_ready = 1;
					Fill_count++;
					break;						//Stop filling TempPCM buffer when it is full 
				}
 				else if( (temp_wp%2048) == 0 )
				{
					if(temp_wp == TempPCM_Buffer_Size)
						temp_wp = 0;
					//break;						//Stop filling 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(error_msg == -2)
			{
				*P_DAC_INT_STATUS = 0;			//Stop SPU software channel
				*P_DAC_MODE_CTRL2  = 0;
				MP3_Status = 0;					//Stop playin MP3
				return;
			}
			
			space = get_bs_free_bytes(wp);
			if( (space > BITSTREAM_FILL_BATCH) && ((MP3_Status&D_MP3_Data_End) == 0) )	//Check whether no. of data in MP3 buffer is lower than threshold
				read_bitstream(MP3_bs_buf, &wp);//If yes, fill new data.
			
			if(TempPCM_ready == 1)			//Check whether data in TempPCM buffer is enough to load to SPU FIFO
			{
				TempPCM_ready = 0;
				if(Fill_count < 3)
					MP3_Service_Loop_ISR();	//Fill data in SPU in the beginning. Spare 4K bytes data for 1st SPU IRQ.
				else	
					Need_PCM_Flag = 0;
				if(Fill_count == 3)
				{
					bitrate = mp3_get_bitrate(decoder_instance);
					samplerate = mp3_get_sampling_rate(decoder_instance);
					EnableSoftCh(samplerate);	// Start playing on SPU software channel
					Need_PCM_Flag = 0;
					Fill_count++;
					
					#ifdef	EQ_ON
						eq_init(samplerate, EQ_Band_No);
						eq_change_effect(EQ_Mode);
					#endif
				}
			}
			//*P_GPIO_TFT_PORT &= ~0x02;	// test performance
		}
	}
}


int bs_byte_size(int wp)
{
	int size;
	int rp = mp3_decoder_read_index(decoder_instance);
	size = wp - rp;
	if(size < 0)
		size += MP3_BITSTREAM_BUFFER_SIZE;
	return(size);
}

int get_bs_free_bytes(int wp)
{
	int space;
	int rp = mp3_decoder_read_index(decoder_instance);
	space = rp - wp;
	if(space < 0)
		space += MP3_BITSTREAM_BUFFER_SIZE;
	return(space);
}

void read_bs(unsigned short *MP3_bs_buf, int temp_wp, int fill_size)
{
	int count;
	for(count=0;count<fill_size;count++)
	{
		TempData = *Address;
		Address += 1;
		if( (count+temp_wp) >= (MP3_BITSTREAM_BUFFER_SIZE/2) )
			MP3_bs_buf[count+temp_wp-MP3_BITSTREAM_BUFFER_SIZE/2] = TempData;
		else
			MP3_bs_buf[count+temp_wp] = TempData;
		
		if(Address >= (MP3_Start_Addr+MP3_Length))
			MP3_Status |= D_MP3_Data_End;
	}
}


void read_bitstream(unsigned short *MP3_bs_buf, int *wp)
{
	int space;
	int temp_wp;
	temp_wp = *wp;
	space = get_bs_free_bytes(temp_wp);
	while(space > BITSTREAM_FILL_BATCH)
	{
		read_bs(MP3_bs_buf, temp_wp/2, BITSTREAM_FILL_BATCH/2);	//fill data in MP3_bs_buf
		space -= BITSTREAM_FILL_BATCH;
		temp_wp += BITSTREAM_FILL_BATCH;
		if(temp_wp >= MP3_BITSTREAM_BUFFER_SIZE)
			temp_wp -= MP3_BITSTREAM_BUFFER_SIZE;
	}
	*wp = temp_wp;
}



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -