esp32- eps32_snow audio play wav和mp3播放(1)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/iamlvshijie/article/details/79335575

参考

http://blog.sina.com.cn/s/blog_166bd652e0102xcz4.html

http://blog.csdn.net/zhangjikuan/article/details/48978627

http://blog.csdn.net/u012507643/article/details/50432635

https://www.amobbs.com/forum.php?mod=viewthread&tid=4307649

https://www.helixcommunity.org/projects/datatype/mp3dec

https://en.wikipedia.org/wiki/MP3

http://blog.csdn.net/fulinwsuafcie/article/details/8972346

http://www.cnblogs.com/gansc23/archive/2010/11/27/1889537.html

http://blog.csdn.net/sunshine1314/article/details/2514322


未完,请见后需文章


播放aplay_wav文件

需要先解析wav的头文件

typedef struct 
{
    char rld[4];    //riff 标志符号
    int  rLen;      //
    char wld[4];    //格式类型(wave)
    char fld[4];    //"fmt"
 
    int fLen;   //sizeof(wave format matex)
 
    short wFormatTag;   //编码格式
    short wChannels;    //声道数
    int   nSamplesPersec;  //采样频率
    int   nAvgBitsPerSample;//WAVE文件采样大小
    short wBlockAlign; //块对齐
    short wBitsPerSample;   //WAVE文件采样大小

    char dld[4];        //”data“
    int  wSampleLength; //音频数据的大小
 }WAV_HEADER;

来自http://blog.csdn.net/u012507643/article/details/50432635的图片



随后,把data部分读取出来,直接塞给codec就行了


void aplay_wav(char* filename){
	//"/sdcard/test.wav"
	WAV_HEADER wav_head;
	FILE *f= fopen(filename, "r");
	if (f == NULL) {
			ESP_LOGE(TAG,"Failed to open file:%s",filename);
			return;
	}
	//fprintf(f, "Hello %s!\n", card->cid.name);
	int rlen=fread(&wav_head,1,sizeof(wav_head),f);
	if(rlen!=sizeof(wav_head)){
			ESP_LOGE(TAG,"read faliled");
			return;
	}
	int channels = wav_head.wChannels;
	int frequency = wav_head.nSamplesPersec;
	int bit = wav_head.wBitsPerSample;
	int datalen= wav_head.wSampleLength;
	(void)datalen;
	ESP_LOGI(TAG,"channels:%d,frequency:%d,bit:%d\n",channels,frequency,bit);
	char* samples_data = malloc(1024);
	do{
		rlen=fread(samples_data,1,1024,f);
		//datalen-=rlen;
		hal_i2s_write(0,samples_data,rlen,5000);
	}while(rlen>0);
	fclose(f);
	free(samples_data);
	f=NULL;
}


播放mp3

这里使用的helix的解码,helix的流程大致如下

来自http://blog.csdn.net/weixin_39871788/article/details/79330345的图




申请缓存后,先读取10bytes的ID3的头信息,

“在文件的首部顺序记录10 个字节的ID3V2.3 的头部。数据结构如下:

char Header[3]; /*必须为"ID3"否则认为标签不存在*/

char Ver; /*版本号ID3V2.3 就记录3*/

char Revision; /*副版本号此版本记录为0*/

char Flag; /*存放标志的字节,这个版本只定义了三位,稍后详细解说*/

char Size[4]; /*标签大小,包括标签头的10 个字节和所有的标签帧的大小*/”

(http://blog.csdn.net/fulinwsuafcie/article/details/8972346)



如下,代码注释

void aplay_mp3(char *path)
{
		ESP_LOGI(TAG,"start to decode ...");
		HMP3Decoder hMP3Decoder;
		MP3FrameInfo mp3FrameInfo;
		unsigned char *readBuf=malloc(MAINBUF_SIZE);
		if(readBuf==NULL){
			ESP_LOGE(TAG,"readBuf malloc failed");
			return;
		}
		short *output=malloc(1153*4);
		if(output==NULL){
			free(readBuf);
			ESP_LOGE(TAG,"outBuf malloc failed");
		}
		hMP3Decoder = MP3InitDecoder();
		if (hMP3Decoder == 0){
			free(readBuf);
			free(output);
			ESP_LOGE(TAG,"memory is not enough..");
		}


		int samplerate=0;
		i2s_zero_dma_buffer(0);
		FILE *mp3File=fopen( path,"rb");
		if(mp3File==NULL){
			MP3FreeDecoder(hMP3Decoder);
			free(readBuf);
			free(output);
			ESP_LOGE(TAG,"open file failed");
		}
		char tag[10];
		int tag_len = 0;
		int read_bytes = fread(tag, 1, 10, mp3File);//读取头信息,共10 byte
		if(read_bytes == 10) 
			 {
				if (memcmp(tag,"ID3",3) == 0) //判断是否是id3标签
				 {
				    //计算标签大小,一共四个字节,但每个字节只用7位,最高位不使用恒为0,0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx,计算要去掉0
					tag_len = ((tag[6] & 0x7F)<< 21)|((tag[7] & 0x7F) << 14) | ((tag[8] & 0x7F) << 7) | (tag[9] & 0x7F);
						// ESP_LOGI(TAG,"tag_len: %d %x %x %x %x", tag_len,tag[6],tag[7],tag[8],tag[9]);
					fseek(mp3File, tag_len - 10, SEEK_SET);//指向文件头+tag_len-10的位置??
				 }
				else 
				 {
						fseek(mp3File, 0, SEEK_SET);//指向文件头
				 }
			 }
			 unsigned char* input = &readBuf[0];
			 int bytesLeft = 0;
			 int outOfData = 0;
			 unsigned char* readPtr = readBuf;
			 while (1)
			 {    
	
				 if (bytesLeft < MAINBUF_SIZE)
						{
								memmove(readBuf, readPtr, bytesLeft);
								//读取(MAINBUF_SIZE - bytesLeft)*1个byte到readBuf + bytesLeft中去
								int br = fread(readBuf + bytesLeft, 1, MAINBUF_SIZE - bytesLeft, mp3File);
								if ((br == 0)&&(bytesLeft==0)) break;
 
								bytesLeft = bytesLeft + br;
								readPtr = readBuf;
						}
				int offset = MP3FindSyncWord(readPtr, bytesLeft);
				if (offset < 0)
				{  
						 ESP_LOGE(TAG,"MP3FindSyncWord not find");
						 bytesLeft=0;
						 continue;
				}
				else
				{
					readPtr += offset;                         //data start point
					bytesLeft -= offset;                 //in buffer
					int errs = MP3Decode(hMP3Decoder, &readPtr, &bytesLeft, output, 0);
					if (errs != 0)
					{
							ESP_LOGE(TAG,"MP3Decode failed ,code is %d ",errs);
							break;
					}
					MP3GetLastFrameInfo(hMP3Decoder, &mp3FrameInfo);   
					if(samplerate!=mp3FrameInfo.samprate)
					{
							samplerate=mp3FrameInfo.samprate;
							//hal_i2s_init(0,samplerate,16,mp3FrameInfo.nChans);
							i2s_set_clk(0,samplerate,16,mp3FrameInfo.nChans);
							//wm8978_samplerate_set(samplerate);
							ESP_LOGI(TAG,"mp3file info---bitrate=%d,layer=%d,nChans=%d,samprate=%d,outputSamps=%d",mp3FrameInfo.bitrate,mp3FrameInfo.layer,mp3FrameInfo.nChans,mp3FrameInfo.samprate,mp3FrameInfo.outputSamps);
					}   
					i2s_write_bytes(0,(const char*)output,mp3FrameInfo.outputSamps*2, 1000 / portTICK_RATE_MS);
				}
			
			}
		i2s_zero_dma_buffer(0);
		//i2s_driver_uninstall(0);
		MP3FreeDecoder(hMP3Decoder);
		free(readBuf);
		free(output);  
		fclose(mp3File);
 
		ESP_LOGI(TAG,"end mp3 decode ..");
}




以下来自 https://en.wikipedia.org/wiki/MP3


File structure


An MP3 file is made up of MP3 frames, which consist of a header and a data block. This sequence of frames is called an elementary stream. Due to the "byte reservoir", frames are not independent items and cannot usually be extracted on arbitrary frame boundaries. The MP3 Data blocks contain the (compressed) audio information in terms of frequencies and amplitudes. The diagram shows that the MP3 Header consists of a sync word, which is used to identify the beginning of a valid frame. This is followed by a bit indicating that this is the MPEG standard and two bits that indicate that layer 3 is used; hence MPEG-1 Audio Layer 3 or MP3. After this, the values will differ, depending on the MP3 file. ISO/IEC 11172-3 defines the range of values for each section of the header along with the specification of the header. Most MP3 files today contain ID3 metadata, which precedes or follows the MP3 frames, as noted in the diagram. The data stream can contain an optional checksum.




以下介绍:https://www.helixcommunity.org/projects/datatype/mp3dec

The Helix MP3 Decoder


Key Features
  • Pure 32-bit fixed-point implementation
  • High-quality C reference code for porting to new platforms
  • Optimized for ARM processors
  • Fully reentrant and statically linkable
  • Optional C++ API for compatibility with Helix clients
  • Designed for high performance and low power consumption in handheld and mobile devices
  • Full layer 3 support for
  • MPEG1 layer 3 - sampling frequencies: 48 KHz, 44.1 KHz, 32 KHz
  • MPEG2 layer 3 - sampling frequencies: 24 KHz, 22.05 KHz, 16 KHz
  • MPEG2.5 layer 3 - sampling frequencies: 12 KHz, 11.025 KHz, 8 KHz
  • Supports constant bitrate, variable bitrate, and free bitrate modes
  • Supports mono and all stereo modes (normal stereo, joint stereo, dual-mono)
  • Option to use Intel® IPP performance libraries (if available)
  • Easy to link in either IPP libraries or Helix code

Technical Specifications
Average CPU Usage
Sample Rate
Channels
Bit Rate
Processor Model  (1)
ARM7TDMI
ARM9TDMI-REV2
ARM920T
ARM9E
StrongARM1
XScale
48.0 KHz
2
320 Kbps
30 MHz
24 MHz
27 MHz
20 MHz
20 MHz
20 MHz
44.1 KHz
2
128 Kbps
26 MHz
21 MHz
24 MHz
17 MHz
17 MHz
17 MHz
Memory Usage
  • ROM = 13446 Bytes (const globals)
  • RAM = 23816 Bytes (heap)
  • Total Data Memory = 37262 Bytes
  • Code Size = 21000 Bytes (approximately - depends on compiler)

Frequently Asked Questions
Where is the code in CVS?
  • See the Helix Datatype project page: http://datatype.helixcommunity.org
  • The CVS root is /cvsroot/datatype, and the module name (path) is mp3/codec/fixpt
Where does the build system put the code in my local source tree?
  • datatype/mp3/codec/fixpt
How does the build system decide whether to build the fixed-point or floating-point MP3 decoder?
  • If HELIX_CONFIG_FIXEDPOINT is defined in your profile, it will build the fixed-point decoder. Otherwise it will build the floating-point version.

The Helix MP3 decoder provides MPEG-compliant decoding of MP3 content. Both floating-point and fixed-point decoder implementations are available. The fixed-point decoder is optimized especially for ARM processors but can run on any 32-bit fixed-point processor which can perform a long multiply operation (two 32-bit inputs generating a 64-bit result) and long multiply-accumulate (long multiply with 64-bit accumulator).

(1) Tested with ARMulator, simulated zero-wait-state memory


猜你喜欢

转载自blog.csdn.net/iamlvshijie/article/details/79335575