4

嗨,我对这件事很陌生,所以请多多包涵。我正在尝试将 WAV 文件转换为频谱图,但不确定如何开始。我阅读了一些内容,上面写着要读取 PCM 数据(我认为这是我的 WAV 文件)并将其存储在 WavReader 类中的数组中,然后再对其应用 FFT 并将其转换为 GUI。我目前使用 Naudio 来实现这一点,但找不到任何显示如何将 WAV 文件转换为频谱图的内容。谢谢

编辑: 我发现了关于使用 Nadio 将 PCM 转换为 FFT 并且我卡住了。

     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 个频谱图。

4

1 回答 1

10

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

Visuals.CreateSpectrum3DVoicePrint方法正是这样做的。

如果您在使用它时遇到困难,请随时寻求帮助。

编辑:这是一个快速而肮脏的样本

在此处输入图像描述

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();
            }
        }
    }
}

编辑 2

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

关于比较频谱图,您可以执行以下操作:

  • 将图像调整为更小的尺寸,通过将其抖动为 8 位来减少信息(但是使用一个好的算法)
  • 比较两个图像

但是,为了比较音频数据,我强烈建议您使用指纹,它大致可以做到这一点,但比我的建议要强大得多。

这是一个免费使用的指纹库:

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

不过,不完全确定它是否适用于小样本。

编辑 3

恐怕我找不到我读过的链接,但这就是他们所做的:减少数据并比较图像,例如下面的示例(最后一张图片):

(注意:根本不与图 1 进行比较,这是另一回事,只是为了说明为什么使用较低的分辨率可能会产生更好的产量)

在此处输入图像描述

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

现在对该过程进行非常基本的解释:

比较来源A:

在此处输入图像描述

比较源B:(我刚刚改变了A的一个区域)

在此处输入图像描述

比较结果:

(使用 Paint.Net 通过将以前的图像添加为图层并将第二层混合设置为差异而不是正常来完成)

在此处输入图像描述

如果指纹相同,则生成的图像将是全黑的。

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

这是一个相当不错的:

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

好吧,它与 Photoshop 或 Hypersnap 的(IMO 是例外的)不相上下,但这对于这项任务可能已经足够了。

并且不惜一切代价避免弗洛伊德-斯坦伯格抖动或导致错误扩散的东西。

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

谨慎对待这一点,因为我不是该领域的专家,但大致就是这样做的。

转到https://dsp.stackexchange.com/并在那里提出一些问题,您可能会得到有关实现此目的的有用提示。

于 2013-06-20T14:32:17.663 回答