#申请原创# @21小跑堂
使用沁恒 CH32V103 + VS1003B 制作的 MP3 播放器已经完成了基本功能,剩下的就是添加一些锦上添花的功能,让它有更好的使用体验和更酷的效果
其中音乐频谱由于有动态跳跃的效果,给音乐增加了不少动感
既然酷炫,那就办它
音乐频谱是什么呢?简而言之,就是音乐的各个频率段的强度
音乐频谱怎么获取呢?
第一步:采样喇叭输出,获取音频信号随时间变化的关系,也就是时域波形,例如交流电的正弦波
第二步:对时域波形进行傅里叶变换,可以将时域波形转换为频域波形,例如交流电的频域波形,只有 50Hz 段强度大小,其他频率段强度都是 0
变换的结果就是获取每个频率段信号的强度,傅里叶变换算法在计算机上抽象为离散傅里叶变换(DFT: Discrete Fourier Transform)
离散傅里叶变换计算有限频率点的信号强度大小,例如在 20Hz 到 20000Hz 人耳能分辨的频段,抽取 1024 点计算各个点的频率强度
但离散傅里叶变换需要计算复数、需要进行大量乘法计算,这是单片机所无法完成的
但在前辈们的努力下,提出了快速傅里叶运算(FFT: Fast Fourier Transform),极大的减少了运算量,让单片机也能完成少量点数的时域-频域变换
有现成的算法,那?不客气了就
移植,跑,duang duang duang 卡了
由于需要不断读取内存卡 MP3 数据,传输 MP3 数据到解码器,刷新界面时间进度等,再加入大量计算,导致音频数据和界面卡顿
就。。。
就得换种思路继续了
这里做了23点的频谱效果,先上效果图,再深入讲解
单片机计算比较勉强,但是有 VS1003 解码芯片,可别忘了,它是颗 DSP 芯片,算起来可比单片机快速省事
VS1003 如何获取频谱数据呢?打补丁,写入插件
根据官方手册,VS1003 最多可以完成 23 点频谱计算,每秒可以计算 5 到 20 次,妥了
打补丁
void VS10xx_PatchSpectrum(void)
{
u16 i;
for(i=0; i<943; i++)
{
VS10xx_WriteReg(atab[i], dtab[i]);
}
}
获取频谱数据
void VS10xx_GetSpectrum(u16* buf)
{
u16 i, bands, val;
VS10xx_WriteReg(SCI_WRAMADDR, BASE+2);
/* If VS1011b, one dummy ReadSciReg(SCI_AICTRL3); here*/
bands = VS10xx_ReadReg(SCI_WRAM); /* If VS1011b, use SCI_AICTRL3 */
// printf("bands: %d\r\n", bands);
VS10xx_WriteReg(SCI_WRAMADDR, BASE+4);
/* If VS1011b, one dummy ReadSciReg(SCI_AICTRL3); here*/
for (i=0;i<bands;i++)
{
val = VS10xx_ReadReg(SCI_WRAM); /* If VS1011b, use SCI_AICTRL3 */
/* current value in bits 5..0, normally 0..31
peak value in bits 11..6, normally 0..31 */
*buf++ = val & 0x3F;
// printf("%d\r\n", val & 0x3F);
}
}
获取频谱数据后,进行刷新显示即可,这里采用 200ms 读取刷新一次频谱,效果不错,音频和界面都很流畅
void GUI_MP3_DrawSpectrum(u16 x, u16 y, u16* dat, u16 len)
{
u16 i;
for(i=0;i<len;i++)
{
GUI_SetPen(Color_RGB565(33,33,36));
GUI_Fill_Rectangle(x+(i*4),y-32,3,32-dat[i]);
GUI_SetPen(Cyan);
GUI_Fill_Rectangle(x+(i*4),y-dat[i],3,dat[i]);
}
}
|