【STM32学习笔记】简易音乐播放器+FFT频谱显示,以及一些wav文件data数据块、C语言、声学知识总结
通过FATFS管理SD卡,读取SD卡中的wav文件,根据wav文件的头分析出该音频文件的各项参数(采样率,位深,声道数等)配置外置DAC芯片;将wav数据通过I2S双缓冲区发送给外置DAC芯片播放;同时将PCM格式数据加hanning窗后给到FFT变换到频域,最后将频域信号以对数形式显示在LCD上
简介
通过FATFS管理SD卡,读取SD卡中的wav文件,根据wav文件的头分析出该音频文件的各项参数(采样率,位深,声道数等)配置外置DAC芯片;将wav数据通过I2S双缓冲区发送给外置DAC芯片播放;同时将PCM格式数据加hanning窗后给到FFT变换到频域,最后将频域信号以对数形式显示在LCD上
1 特点与不足
特点:
1、支持44100、48000Hz采样率,16、24bits位深的音频文件
2、FATFS和I2S均采用DMA传输,给FFT提供了充足的CPU资源
3、加入了hanning窗减少频谱泄露
4、频谱显示采用对数方式,视觉效果更好
不足:
1、FFT采用1024点运算,两频点间隔43Hz,部分频段细节有少许缺失
2 分块介绍

2.1 ADC音量调节
cubemx生成代码,固定时间间隔采集ADC数值,若和上次采集有差别则设置DAC芯片
2.2 音乐播放
1、为了保证音乐播放的连续性,I2S需使用双缓冲区传输方式,通过在传输完成中断设置标志位选择需往哪个缓冲区中填入数据
if (wavwitchbuf)
{ fillnum = wav_buffill(g_audiodev.saibuf2, WAV_SAI_TX_DMA_BUFSIZE, wavctrl.bps);
else
{ fillnum = wav_buffill(g_audiodev.saibuf1, WAV_SAI_TX_DMA_BUFSIZE, wavctrl.bps);
2、wav文件解析详解网上有很多资料,这里补充个关于data数据块需注意的点
1)data数据块是以有符号型存储的,注意分辨
2)data数据块存储方式是小端模式
3)16bits几个数据点就占2bytes,24bits占3bytes,依此类推
2.3 音频处理
1、PCM格式转float32格式raw_data_buf以uint8的形式存储data数据,因为上面提到的小端模式,这段代码会先将raw_data_buf[2 * i + 1]转换成uint16型高位为0后左移8位再与raw_data_buf[2 * i]拼接后转成有符号型value;
然后value转成有符号浮点型后归一化到[-1,1]
int16_t value = (uint16_t)raw_data_buf[2 * i] |
((uint16_t)raw_data_buf[2 * i + 1] << 8);
output_buf[2 * i] = (float32_t)value / 32767.0f;
output_buf[2 * i + 1] = 0.0f;
而24位数据因为DAC芯片需要需对数据做些处理
| 地址 | 0x01 | 0x02 | 0x03 | 0x04 |
|---|---|---|---|---|
| 数据 | 数据低位 | 数据中位 | 数据高位 | 无效位(非0) |
int32_t value = ((uint32_t)raw_data_buf[4 * i + 0] << 8 ) |
((uint32_t)raw_data_buf[4 * i + 1] << 16) |
((uint32_t)raw_data_buf[4 * i + 2] << 24);
output_buf[2 * i] = (float32_t)value / 2147483647.0f;
output_buf[2 * i + 1] = 0.0f;
2、hanning窗
没什么特别要注意的,窗函数与数据相乘即可
void arm_hanning_f32(float32_t *pbuf, uint32_t blockSize)
{
float32_t k = 2.0f / ((float32_t)blockSize);
float32_t w;
for (uint32_t i = 0; i < blockSize; i++)
{
w = PI * i * k;
w = 0.5f * (1.0f - cosf(w));
pbuf[i] *= w;
}
}
3、对数显示
线性频率取log以2为底就可以得到对数频率了
static uint16_t display_fft_log(uint16_t sx, uint16_t sy, uint16_t linear_freq, uint16_t width)
{
uint16_t log_current_freq = log2f((float32_t)linear_freq) * 50;
uint16_t log_next_freq = log2f((float32_t)(linear_freq + width)) * 50;
uint8_t i = 0;
for(; i < log_next_freq - log_current_freq; i++)
{
if(sy > 200){sy = 200;}
lcd_fill(sx+i, 300-sy, sx+i+1, 300, RED);
}
return sx+i;
}
因为是柱状图的形式,而且音乐1kHz左右频谱的跃动比较有观赏价值,所以我设置在了3kHz前显示尽可能多的细节,3kHz后细节减少,最后显示就会如图所示
3 资源共享
STM32代码,学习用,留个底
https://gitee.com/creator-len/study_music
成果展示
[STM32学习]简易音乐播放器+FFT频谱显示成功展示
更多推荐



所有评论(0)