Example #1
0
/**
  * @brief  I2S_Bus_Init 初始化iis总线
  * @param  none
  * @retval none
  */
void I2S_Bus_Init(void)
{
	/* 配置I2S GPIO用到的引脚 */
	I2S_GPIO_Config(); 

	/* 配置I2S工作模式 */
	I2S_Mode_Config();

	I2S_Cmd(SPI2, ENABLE);

	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	
	DMA_I2S_Configuration(0, 0xFFFE);
}
Example #2
0
/**
  * @brief  wav_player 进行wav文件播放
	*					wav格式存储的就是PCM数据,不需要解码
  * @param  filename:要播放的文件路径
  * @retval none
  */
static void wav_player(const char *filename)
{
	short *p;
	WavHead *wav;	

	//打开音频文件
	fres = f_open (&file, filename, FA_READ );
	
	//打开失败
	if (fres!=FR_OK)
	{
		printf("read file %s error  ! open another file\r\n",filename);
		fres = f_close (&file);
		
		if (++play_index>=file_num)	//索引值加1
		{
				play_index=0;						//归0,所以如果所有文件都打开失败会一直循环
		}				
		return ;										//文件无法打开,终止解码。进入下一次循环,读取下一个文件
	}
	
		//显示播放图标
	Lcd_GramScan(1);
	LCD_Clear(12,88,8,145,BACKGROUND);
	Lcd_show_bmp(320-(103+((play_index-((current_page-1)*8))*18)),240-20,"/mp3player/ui_playing.bmp");	
	
	
	fres = f_read(&file,buffer,512,&rw_num);							//读取文件头
	
	wav = (WavHead *)buffer;															//整理格式
		
	printf("\r\n samprate: %dHz", wav->dwSamplesPerSec);	//采样率

	if(wav->dwSamplesPerSec >= I2S_AudioFreq_Default)
		I2S_Freq_Config(wav->dwSamplesPerSec);							//设置采样率

		//播放循环	
		while(player_state != S_SWITCH)			//循环本过程播放音频,直到切歌
		{
			if (player_state == S_STOP)
				{			
					even_process();
					continue;											//暂停的时候跳出本循环
				}
				
			player_state = S_PLAY;						//状态更新为正在播放
		
				
			//读取wav文件
			p = (short *)(buffer+sizeof(buffer)/2*bufflag);		
			fres = f_read(&file, p, sizeof(buffer)/2, &rw_num);
			if(fres != FR_OK)
			{
				printf("读取%s失败! %d\r\n",filename,fres);
				break;
			}
			
			/* 等待DMA播放完,这段时间我们可以干其他的事,事件处理 */
			while((DMA1_Channel5->CCR & DMA_CCR1_EN) && !(DMA1->ISR&DMA1_IT_TC5))
			{
					even_process();
			}
        DMA_ClearFlag(DMA1_FLAG_TC5 | DMA1_FLAG_TE5);
        DMA_I2S_Configuration((uint32_t)p, rw_num/2);
				bufflag = 1 -bufflag;				//切换buffer																	
							
		
			if(file.fptr==file.fsize) 		//如果指针指向了文件尾,表示数据全部读完
			{
				printf("END\r\n");
				if(play_index<file_num-1)		//自动开始下一首歌曲
				{
					play_index++;
					player_state = S_SWITCH;	
				}
				else
				{
					play_index = 0;
					player_state = S_SWITCH;
				}
						
				break; 									//跳出这首歌的播放状态	while break; 
			}  	
	}
	
	f_close(&file);								//结束播放本歌曲,关闭文件
	I2S_Stop();
}
Example #3
0
/**
  * @brief  mp3_player 进行mp3文件解码、播放
  * @param  filename:要播放的文件路径
  * @retval none
  */
static void mp3_player(const char *filename)
{
	int err, i, outputSamps, current_sample_rate = 0;	

	int						read_offset = 0;				/* 读偏移指针				*/
	int						bytes_left = 0;					/* 剩余字节数				*/	
	unsigned long	Frames = 0;							/* mP3帧计数				*/
	unsigned char	*read_ptr = buffer;			/* 缓冲区指针				*/
	HMP3Decoder		Mp3Decoder;						  /* mp3解码器指针		*/
	

	
	//打开音频文件
	fres = f_open (&file, filename, FA_READ );
	
	//打开失败
	if (fres!=FR_OK)
	{
		printf("read file %s error  ! open another file\r\n",filename);
		fres = f_close (&file);
		
		if (++play_index>=file_num)	//索引值加1
		{
				play_index=0;						//归0,所以如果所有文件都打开失败会一直循环
		}				
		return ;										//文件无法打开,终止解码。进入下一次循环,读取下一个文件
	}
		
	//打开成功
	//初始化MP3解码器
	Mp3Decoder = MP3InitDecoder();	
	
	//获取输入数据流,调用helix库解码,输出PCM数据,约20ms完成一次循环
	//开始进入播放状态,期间中断会修改touch_even状态
	while(player_state != S_SWITCH)	//循环1, 如果touch_even不是切歌状态则继续呆在循环体里 
	{
		//有时出现解码错误,错误后继续在本循环体内,继续播放
		
		//显示播放图标
		Lcd_GramScan(1);
		LCD_Clear(12,88,8,145,BACKGROUND);
		Lcd_show_bmp(320-(103+((play_index-((current_page-1)*8))*18)),240-20,"/mp3player/ui_playing.bmp");
		
		//读取mp3文件
		fres = f_read(&file, buffer, sizeof(buffer), &rw_num);
		if(fres != FR_OK)
		{
			printf("读取%s失败! %d\r\n",filename,fres);
			break;
			//return;
		}
		read_ptr = buffer;									//指向mp3输入流
		bytes_left = rw_num;								//实际读到的输入流大小大小

		//按帧处理	
		while(player_state != S_SWITCH)			//循环2,循环本过程播放音频,直到按了下一首、上一首	
		{
			if (player_state == S_STOP)
			{								
				even_process();									//检查是否有事件需要处理
				continue;												//暂停的时候结束本次循环
			}
				
			player_state = S_PLAY;						//状态更新为正在播放
			
			read_offset = MP3FindSyncWord(read_ptr, bytes_left);	//寻找帧同步,返回第一个同步字的位置
			if(read_offset < 0)																		//没有找到同步字
			{
				break;																							//跳出循环2,回到循环1	
			}
			
			read_ptr += read_offset;					//偏移至同步字的位置
			bytes_left -= read_offset;				//同步字之后的数据大小	
			if(bytes_left < 1024)							//补充数据
			{
				/* 注意这个地方因为采用的是DMA读取,所以一定要4字节对齐  */
				i=(uint32_t)(bytes_left)&3;									//判断多余的字节
				if(i) i=4-i;														//需要补充的字节
				memcpy(buffer+i, read_ptr, bytes_left);	//从对齐位置开始复制
				read_ptr = buffer+i;										//指向数据对齐位置
				fres = f_read(&file, buffer+bytes_left+i, sizeof(buffer)-bytes_left-i, &rw_num);//补充数据
				bytes_left += rw_num;										//有效数据流大小
			}
			err = MP3Decode(Mp3Decoder, &read_ptr, &bytes_left, outBuf[bufflag], 0);					//开始解码 参数:mp3解码结构体、输入流指针、输入流大小、输出流指针、数据格式
			Frames++;			
			
			if (err != ERR_MP3_NONE)									//错误处理
			{
				switch (err)
				{
					case ERR_MP3_INDATA_UNDERFLOW:
						printf("ERR_MP3_INDATA_UNDERFLOW\r\n");
						read_ptr = buffer;
						fres = f_read(&file, read_ptr, sizeof(buffer), &rw_num);
						bytes_left = rw_num;
						break;
			
					case ERR_MP3_MAINDATA_UNDERFLOW:
						/* do nothing - next call to decode will provide more mainData */
						printf("ERR_MP3_MAINDATA_UNDERFLOW\r\n");
						break;
			
					default:
						printf("UNKNOWN ERROR:%d\r\n", err);
			
						// 跳过此帧
						if (bytes_left > 0)
						{
							bytes_left --;
							read_ptr ++;
						}	
						break;
				}
			}
			else		//解码无错误,准备把数据输出到PCM
			{
				MP3GetLastFrameInfo(Mp3Decoder, &Mp3FrameInfo);		//获取解码信息				

		    /* 根据解码信息设置采样率 */
				if (Mp3FrameInfo.samprate != current_sample_rate)	//采样率 
				{
					current_sample_rate = Mp3FrameInfo.samprate;

					printf(" \r\n Bitrate       %dKbps", Mp3FrameInfo.bitrate/1000);
				  printf(" \r\n Samprate      %dHz", current_sample_rate);
					printf(" \r\n BitsPerSample %db", Mp3FrameInfo.bitsPerSample);
					printf(" \r\n nChans        %d", Mp3FrameInfo.nChans);
					printf(" \r\n Layer         %d", Mp3FrameInfo.layer);
					printf(" \r\n Version       %d", Mp3FrameInfo.version);
					printf(" \r\n OutputSamps   %d", Mp3FrameInfo.outputSamps);

					if(current_sample_rate >= I2S_AudioFreq_Default)	//I2S_AudioFreq_Default = 2,正常的帧,每次都要改速率
					{
						I2S_Freq_Config(current_sample_rate);						//根据采样率修改iis速率
					}
				}
				
				/* 输出到DAC */
				outputSamps = Mp3FrameInfo.outputSamps;							//PCM数据个数
				
				if (outputSamps > 0)
				{
					if (Mp3FrameInfo.nChans == 1)	//单声道
					{
						//单声道数据需要复制一份到另一个声道
						for (i = outputSamps - 1; i >= 0; i--)
						{
							outBuf[bufflag][i * 2] = outBuf[bufflag][i];
							outBuf[bufflag][i * 2 + 1] = outBuf[bufflag][i];
						}
						outputSamps *= 2;
					}
				
					//非单声道数据可直接由DMA传输到IIS交给DAC
					/* 等待DMA播放完,这段时间我们可以干其他的事,扫描事件进行处理 */
					while((DMA1_Channel5->CCR&DMA_CCR1_EN) && !(DMA1->ISR&DMA1_IT_TC5))
					{
							even_process();							
						}
						
					/*DMA传输完毕*/
			    DMA_ClearFlag(DMA1_FLAG_TC5 | DMA1_FLAG_TE5);
			    DMA_I2S_Configuration((uint32_t)outBuf[bufflag], outputSamps);
					bufflag = 1 -bufflag;																			//切换buffer

				}//if (outputSamps > 0)
			}//else 解码正常
			
		
		if(file.fptr==file.fsize) 		//如果指针指向了文件尾,表示数据全部读完
		{
			printf("END\r\n");
			if(play_index<file_num-1)		//自动开始下一首歌曲
			{
				play_index++;
				player_state = S_SWITCH;	//进入切歌状态,跳出
			}
			else
			{
				play_index = 0;
				player_state = S_SWITCH;
			}
					
			break; 										//跳出这首歌的播放状态	while break; 
		}
  	
	}//循环2		内 while(player_state != S_SWITCH)	
	
 }//循环1  	外 while(player_state != S_SWITCH)

	f_close(&file);							//结束播放本歌曲,关闭文件
	MP3FreeDecoder(Mp3Decoder);
	I2S_Stop();
	
}