2013-06-20 299 views
3

嗨,我对这件事很陌生,请耐心等待。我正试图将WAV文件转换为谱图,但不知道如何开始。我读了一些说要读取PCM数据(我认为是我的WAV文件)并将其存储在WavReader类的数组中,然后对其应用FFT并将其转换为GUI。我目前使用Naudio来实现这一目标,但找不到任何显示如何将WAV文件转换为光谱图的内容。谢谢将WAV文件转换为频谱图

编辑: 我发现有关转换PCM与FFT与Naudio和IM坚持。

 using (var reader = new AudioFileReader("test1.wav")) 
     { 
      // test1.wav is my file to process 
      // test0.wav is my temp file 

      IWaveProvider stream16 = new WaveFloatTo16Provider(reader); 
      using (WaveFileWriter converted = new WaveFileWriter("test0.wav", stream16.WaveFormat)) 
      { 
       // buffer length needs to be a power of 2 for FFT to work nicely 
       // however, make the buffer too long and pitches aren't detected fast enough 
       // successful buffer sizes: 8192, 4096, 2048, 1024 
       // (some pitch detection algorithms need at least 2048) 
       byte[] buffer = new byte[8192]; 
       int bytesRead; 
       do 
       { 
        bytesRead = stream16.Read(buffer, 0, buffer.Length); 
        converted.WriteData(buffer, 0, bytesRead); 
       } while (bytesRead != 0 && converted.Length < reader.Length); 
      } 
     } 

编辑:我也想知道是否有可能以编程方式比较2个谱图的2个不同的文件。

+0

我认为统一游戏引擎提供了一类音频anylisys,但我不确定。 – user2417992

回答

5

您也可以使用BASS.NET库,它本身提供所有这些功能并且是免费的。

Visuals.CreateSpectrum3DVoicePrint Method确实如此。

如果您很难使用它,请随时寻求帮助。

编辑:这里有一个快速和肮脏的样品

enter image description here

public partial class Form1 : Form 
{ 
    private int _handle; 
    private int _pos; 
    private BASSTimer _timer; 
    private Visuals _visuals; 

    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void timer_Tick(object sender, EventArgs e) 
    { 
     bool spectrum3DVoicePrint = _visuals.CreateSpectrum3DVoicePrint(_handle, pictureBox1.CreateGraphics(), 
                     pictureBox1.Bounds, Color.Cyan, Color.Green, 
                     _pos, false, true); 
     _pos++; 
     if (_pos >= pictureBox1.Width) 
     { 
      _pos = 0; 
     } 
    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     string file = "..\\..\\mysong.mp3"; 
     if (Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, Handle)) 
     { 
      _handle = Bass.BASS_StreamCreateFile(file, 0, 0, BASSFlag.BASS_DEFAULT); 

      if (Bass.BASS_ChannelPlay(_handle, false)) 
      { 
       _visuals = new Visuals(); 
       _timer = new BASSTimer((int) (1.0d/10*1000)); 
       _timer.Tick += timer_Tick; 
       _timer.Start(); 
      } 
     } 
    } 
} 

EDIT 2

您可以提供一个文件名,但你也可以使用提供自己的音频数据另一个接受IntPtr的重载或者使用Bass.BASS_StreamCreatePush和Bass.BASS_StreamPutData。

关于比较谱图,你可以做到以下几点:

  • 图像尺寸调整到一个更小的尺寸,通过它抖动至8位(含但是一个好的算法)
  • 降低信息比较两个图像

但是,对于比较音频数据,我强烈建议您使用指纹,它大致这样做,但比我的建议强大得多。

这里有一个指纹库,可免费使用:

http://www.codeproject.com/Articles/206507/Duplicates-detector-via-audio-fingerprinting

不能完全确定它会工作的小样本,虽然。

编辑3

我怕我找不到在哪里我读过的联系,但是这是他们做什么:减少数据和图像比较,如下面的例子中(最后一个图像):

(注意:不要与图像1在所有比较,这是别的东西,但只是为了说明为什么使用较低的分辨率可能会提供更好的收益率)

enter image description here

(从http://blog.echonest.com/post/545323349/the-echo-nest-musical-fingerprint-enmfp

现在的过程中一个非常基本的解释:

比较来源答:

enter image description here

比较来源B:(我刚刚换了一个区域)

enter image description here

比较结果:

(与Paint.Net完成通过添加前的图像作为层和第二层的混合设置为差,而不是正常)

enter image description here

如果指纹均是相同的所产生的图像将是全黑的。

通过将数据减少到8位图像,您正在简化比较过程,但请记住,您需要一个很好的抖动算法。

这是一个相当不错:

http://www.codeproject.com/Articles/66341/A-Simple-Yet-Quite-Powerful-Palette-Quantizer-in-C

那么它不是与Photoshop或HyperSnap中的一个(这IMO是例外)相提并论,但可能是不够的任务。

并不惜一切代价Floyd–Steinberg dithering或者做错误扩散的东西。

这里创建抖动算法的一些尝试:http://bisqwit.iki.fi/story/howto/dither/jy/

拿这个要小心,因为我不是在该领域的专家,但是这就是它大概怎么做。

转到https://dsp.stackexchange.com/并在那里问几个问题,你可能会得到有用的提示,以实现这一点。

+0

只是为了澄清,对于上面的代码,我只需要指定我的文件名来显示频谱图? –

+0

我已经更新了我的答案,看一看。 – Aybe

+0

非常感谢你的回答。真的很感谢你对此的意见。关于你提供的音频指纹,我试图实现它,但不知何故,它只能识别2个类似音乐文件的重复,而不是2个有我声音的音频文件。我会尝试实施比较谱图的ur方法,并希望它能够最好地工作。 –