wav文件1分析


wav文件2分析

注:
00-03 52 49 46 46:RIFF的标志
04-07 24 90 01 00 :文件的长度
08-0B 57 41 56 45 :WAVE的标志
0C-0F 66 6D 74 20 :fmt的标志
10-13 10 00 00 00 :编码的格式类别,10H代表PCM形式。
14-15 01 00 :字块总数
16-17 01 00 : 通道数 1为单声道,2为双声道
18-1B 80 3E 00 00 :采样率:每秒采集二进制的位数。16000Hz
1C-1F 00 7D 00 00 :每秒播放的字节数 = 通道数 x 每秒采集二进制的位数 x 采集数据的位数 / 8. 32000
20-21 02 00 :每个样点的字节数
22-23 01 00 :每个样点的数据位数
24-27 64 61 74 61 :data的标志
28-2b 00 90 01 00 : 文件长度 3200KB

12位dac播放16位音频数据

一般WAV数据开始的第44字节开始就是wav数据,把wav数据取出后直接送到DAC播放。这里的WAV的dac数据是16bit的需要进行转换成12bit(stm32是12bit的DAC,所以整体需要右移4位,损失4bit的精度,保留大头)

//方法1:
buffer[i] = buffer[i]+0x8000;//16bit dac 数据为补码形式的,需要进行处理+0x8000
buffer[i] = buffer[i] >>num; //num 一般为4 右移4位剩下12bit dac数据

//方法二:
(buffer[0]+(buffer[1]-0x80)*256)>>4)//高位用补码形式保存的,转换时需要先减去0x80
//或者
tmpCap = (((u8)(buffer[1] - 0x80) << 4) | (buffer[0] >> 4));

设置time定时器的频率16K的采集率,每秒定时中断1/16000,在中断中填充音频数据到dac接口,即可实现普通dac播放音频文件!

注意:
【1】用二进制补码表示的音频数据(MCU或者计算机数值⼀律⽤补码来表⽰和存储),数据有正负,所以需要转换;
【2】有符号数据的模拟量波形是在0值附近上下波动的,所以需要向上平移0x8000,后再取高12位的数据送到 12位的DAC里面 !

//测试1:
    s16 data1 = 1000;
    s16 data2 = -1000;
    printf("data             = %x,%x\n",data1,data2);
    printf("----------------------------------------------\n\n");
    u8 wav_data1[2] = {0xe8,0x03};//1000
    u8 wav_data2[2] = {0x18,0xfc};//-1000
    u16 dac_data1 =(((u8)(wav_data1[1]+0x80)<<8)|(wav_data1[0]));
    printf("wav_data1          = %d,%x\n",*(s16*)wav_data1,*(s16*)wav_data1);
    printf("dac_data1          = %d,%x\n",dac_data1,dac_data1);
    u16 tmp_data =(((u8)(wav_data1[1])<<8)|(wav_data1[0])) + 0x8000;
    printf("tmp_data           = %d,%x\n",tmp_data,tmp_data);

    u16 dac_data2 = (((u8)(wav_data2[1]+0x80)<<8)|(wav_data2[0]));
    printf("----------------------------------------------\n\n");
    printf("wav_data2          = %d,%x\n",*(s16*)wav_data2,*(s16*)wav_data2);
    printf("dac_data2          = %d,%x\n",dac_data2,dac_data2);
    tmp_data =(((u8)(wav_data2[1])<<8)|(wav_data2[0])) + 0x8000;
    printf("tmp_data           = %d,%x\n",tmp_data,tmp_data);
//测试2:
    s16 data1 = 1000;
    s16 data2 = -1000;
    printf("data             = %x,%x\n",data1,data2);
    printf("----------------------------------------------\n\n");
    u8 wav_data1[2] = {0xe8,0x03};//1000
    u8 wav_data2[2] = {0x18,0xfc};//-1000
    u16 dac_data1 =(((u8)(wav_data1[1]-0x80)<<8)|(wav_data1[0]));
    printf("wav_data1          = %d,%x\n",*(s16*)wav_data1,*(s16*)wav_data1);
    printf("dac_data1          = %d,%x\n",dac_data1,dac_data1);
    u16 tmp_data =(((u8)(wav_data1[1])<<8)|(wav_data1[0])) - 0x8000;
    printf("tmp_data           = %d,%x\n",tmp_data,tmp_data);

    u16 dac_data2 = (((u8)(wav_data2[1]-0x80)<<8)|(wav_data2[0]));
    printf("----------------------------------------------\n\n");
    printf("wav_data2          = %d,%x\n",*(s16*)wav_data2,*(s16*)wav_data2);
    printf("dac_data2          = %d,%x\n",dac_data2,dac_data2);
    tmp_data =(((u8)(wav_data2[1])<<8)|(wav_data2[0])) - 0x8000;
    printf("tmp_data           = %d,%x\n",tmp_data,tmp_data);

测试打印(目的是为了验证( buffer[1]+0x8000))以及 (buffer[1]-0x80)效果都是一样;

有符号减去或者加上0x8000计算的结果都是一样(因为两种情况s16/u16有符号数据都溢出了,所以计算结果一样);

有符号数据的模拟量波形是在0值附近上下波动的,所以需要向上平移0x8000:

测试1打印:

data = 3e8,fffffc18

----------------------------------------------

wav_data1 = 1000,3e8

dac_data1 = 33768,83e8

tmp_data = 33768,83e8

----------------------------------------------

wav_data2 = -1000,fffffc18

dac_data2 = 31768,7c18

tmp_data = 31768,7c18

测试2打印:

data = 3e8,fffffc18

----------------------------------------------

wav_data1 = 1000,3e8

dac_data1 = 33768,83e8

tmp_data = 33768,83e8

----------------------------------------------

wav_data2 = -1000,fffffc18

dac_data2 = 31768,7c18

tmp_data = 31768,7c18

补码和原码之间的换算:

  1. 原码 转 补码:
    正整数的补码是它本身,即 1的原码是0000 0001 ,补码 还是 0000 0001.
    负整数的补码是符号位不变,其余位按位取反 ,再加1 ,例如 -1 的原码 1000 0001,补码 1111 1111 .

  2. 补码 转 原码
    正整数的补码即是原码。例,1 的补码是0000 0001 ,原码还是 0000 0001
    负整数已知补码求原码,只需要再对补码求一次补码即可,即负整数的补码的补码即是原码。
    例 -1 的补码 1111 1111 ,再取一次补码(符号位不变,其余位按位取反,再加1)即是原码 1000 0001.

    mcu数据以补码形式存储:

声音制作

https://tts.waytronic.com/tts


来源:
https://blog.csdn.net/weixin_42107504/article/details/139420370