前些日子没事情干,又想到TC那个方波音乐的痛苦与现在新的、不需要方波音乐的灭弧、放音乐的那个效果......顿时觉得有点头大。
1.想法
来看新的灭弧放普通音乐的效果——噗噗噗喀喀喀的。这因为普通音乐的频率里有大量低频成分,而且所送过去的音乐也不是完完全全的主旋律,因而有个简单的想法——提取出音乐的主旋律部分,或许会好些。
按照前面的想法,首先需要去除低频部分。为了做到这一点,我借助了DFT和IDFT来完成,其具体实现也很简单:DFT->删去低频成分->IDFT->结果
其次是主旋律部分的识别,由于主旋律一般是振动幅度较大的那个频率,因此依然可以借助DFT和IDFT来完成:DFT->把振荡幅度低的频率成分调为0->IDFT->结果
为了方便应用程序的处理,我在这里只使用wav文件。原因是这种文件大多存放PCM的线性流数据,方便操作,同样的,为了加快运算速度,我们把DFT和IDFT都用FFT和IFFT代替,那么按照上面的思路,总结就是:
读取wav文件->FFT->删去低频成分->删去振荡幅度低的成分->IFFT->保存wav数据
2.测试
由于上诉过程并不复杂,因此不做代码公开。以FripSide-LateInAutumn.wav这个文件为例,我们先用Au打开它查看它的频谱,可以得到:
然后,进行FFT之后,删去低频部分,得到了下面的结果:
可以看到低频(最底下)的部分都已经几乎没有了,再进行主旋律筛选,得到的结果是:
可以看到,和第一张图做对比,已经改变太多了。但是图中每一段都有一个“竖线”,是为什么呢?其实是因为在上面的操作过程中导致了波形发生了变化,而FFT每次只是处理一小部分,因而每一个部分的波形会存在跳动,从而导致了这个问题。因此,这个需要注意。
3.编写过程中遇到的问题
在刚开始的时候,我依然使用16bit的wav文件来保存——但是随后发现这样比较麻烦,因此我最终是使用IEEE Float的32位的wav文件的。这种文件的保存非常简单,直接写入浮点数据的数组就可以了。下面是一个简单的实现:
#define WRIT_32_LH(dat,val) (dat)[3] = (val) >> 24;(dat)[2] = ((val) >> 16) & 0xff;(dat)[1] = ((val) >> 8) & 0xff;(dat)[0] = (val) & 0xff
#define WRIT_16_LH(dat,val) (dat)[1] = (val) >> 8;(dat)[0] = (val) & 0xff
void writeWavFile(const char* fileName, float *dat, DWORD leng, unsigned short samplerate)
{
FILE *f;
DIGDATA *tmp;
fopen_s(&f, fileName, "wb");
if (f == NULL)
return;
tmp = (DIGDATA*)malloc(100);
if (tmp == nullptr)
{
printf("打开输出文件失败\r\n");
fclose(f);
return;
}
fwrite("RIFF____WA【和谐符号,把它删了才是】VEfmt ", 4, 4, f); // RIFF文件头
WRIT_32_LH(tmp + 0, 0x00000010);
WRIT_16_LH(tmp + 4, WA【和谐符号,把它删了才是】VE_FORMAT_IEEE_FLOAT); // 流类型
WRIT_16_LH(tmp + 6, 1); // 通道数目
WRIT_32_LH(tmp + 8, samplerate); // 采样率
WRIT_32_LH(tmp + 12, samplerate * 4); // 一秒钟的字节数
WRIT_16_LH(tmp + 16, 4); // 数据区块尺寸
WRIT_16_LH(tmp + 18, 32); // 量化精度
fwrite(tmp, 1, 20, f);
fwrite("data____", 1, 8, f); // data段
WRIT_32_LH(tmp + 0, leng * 4);
WRIT_32_LH(tmp + 4, leng * 4 + 44);
fseek(f, 4, 0); // RIFF后面的尺寸
fwrite(tmp + 4, 1, 4, f);
fseek(f, 40, 0); // data后面的尺寸
fwrite(tmp + 0, 1, 4, f);
fwrite(dat, 4, leng, f);
free(tmp);
fclose(f);
}
之后,便是窗函数的问题了。在这里需要提醒一下,如果FFT用了窗函数,最后把IFFT的结果去除以窗函数将会出问题——对于一些窗函数而言,旁瓣衰减不是不为零的。至于其它,便没有什么注意的了。
顺便吐槽一下论坛编辑器,wav文件,然后提示,有敏感词....
最后,不知道您对我这个脑洞的想法有什么建议或者提示没有 |