您的位置:首页 > 其它

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

2018-02-18 21:54 344 查看
参考 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 FeaturesPure 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 RateChannelsBit RateProcessor Model (1)
ARM7TDMIARM9TDMI-REV2ARM920TARM9EStrongARM1XScale
48.0 KHz2320 Kbps30 MHz24 MHz27 MHz20 MHz20 MHz20 MHz
44.1 KHz2128 Kbps26 MHz21 MHz24 MHz17 MHz17 MHz17 MHz
Memory UsageROM = 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: