C# 频率检索

标签 c# fft frequency naudio

我需要做的是计算麦克风输入的频率。为此,我正在使用 IWaveProvider 及其实现的 Read()。缓冲区的大小始终为 8820 个元素,从字节数组到 float 组的转换似乎也出了问题(FloatBuffer 属性部分)。

这里有一些重要的部分......

这是我开始记录的地方:

private void InitializeSoundRecording()
{
    WaveIn waveIn = new WaveIn();
    waveIn.DeviceNumber = 0;   
    waveIn.DataAvailable += (s, e) => this.waveIn_DataAvailable(s, e); 
    waveIn.RecordingStopped += (s, e) => this.waveIn_RecordingStopped(s, e);
    waveIn.WaveFormat = new WaveFormat(44100, 1);
    waveIn.StartRecording();
}

当调用 DataAvailable 事件处理程序时,将执行以下操作:

private void waveIn_DataAvailable(object sender, WaveInEventArgs e)
{
    WaveBuffer wb = new WaveBuffer(e.Buffer.Length);

    IWaveProvider iWaveProvider = new PitchDetector(new WaveInProvider(sender as WaveIn), new WaveBuffer(e.Buffer));
    iWaveProvider.Read(wb, 0, e.Buffer.Length);

    PitchDetector pd = iWaveProvider as PitchDetector;

    this.ShowPitch(pd.Pitch);
}

最后,这是“实际”重要的一点:

private const int FLOAT_BUFFER_SIZE = 8820;
private IWaveProvider source;
private WaveBuffer waveBuffer;
private int sampleRate;
private float[] fftBuffer;
private float[] prevBuffer;
public float Pitch { get; private set; }

public WaveFormat WaveFormat { get { return this.source.WaveFormat; } }

internal PitchDetector(IWaveProvider waveProvider, WaveBuffer waveBuffer = null)
{
    this.source = waveProvider;
    this.sampleRate = waveProvider.WaveFormat.SampleRate;
    this.waveBuffer = waveBuffer;
}

/// <summary>
/// UNSAFE METHOD! 
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
private unsafe float[] ByteArrayToFloatArray(byte[] input)
{
    float[] fb = new float[FLOAT_BUFFER_SIZE];
    unsafe
    {
        fixed (byte* ptrBuffer = input)
        {
            float* ptrFloatBuffer = (float*)ptrBuffer;
            for (int i = 0; i < FLOAT_BUFFER_SIZE; i++)
            {
                fb[i] = *ptrFloatBuffer;
                ptrFloatBuffer++;
            }
        }
    }
    return fb;
}

public int Read(byte[] buffer, int offset = 0, int count = 0)
{
    if (this.waveBuffer == null || this.waveBuffer.MaxSize < count)
        this.waveBuffer = new WaveBuffer(count);

    int readBytes = this.source.Read(this.waveBuffer, 0, count);

    if (readBytes > 0) readBytes = count;

    int frames = readBytes / sizeof(float);

    this.Pitch = this.DeterminePitch(this.waveBuffer.FloatBuffer, frames);

    return frames * 4;
}

奇怪的是,当它进入构造函数时,waveBuffer 包含一些数据(255、1、0 等),但是当我检查Read() 的“buffer”参数时,它完全是0.每个元素。

同样出于好奇,为什么 Read() 有一个缓冲区参数,但实际上根本没有用在该方法中(我从您的一篇文章中得到了那段代码)?

如果您能帮助解决此问题,我们将不胜感激!我已经在这方面研究了很长一段时间,但无法理解它。

谢谢, 阿兰

最佳答案

不清楚你指的是哪篇文章,我也不熟悉这个库。但是,Read 方法显然正在读取您的“时间序列”/或其他数据。由此,您所说的 buffer 参数很可能是您想要放置在数据集两端的填充长度。

这种填充称为“零填充”,它用零填充您记录的信号(在信号的两端放置 n 个零,其中 n 根据使用的基数设置)。这允许使用更长的 FFT,这将产生更长的 FFT 结果向量。

较长的 FFT 结果具有更多的频率间隔,这些频率间隔在频率上更紧密。但它们本质上将提供与原始数据的较短非零填充 FFT 的高质量 Sinc 插值相同的结果。

在没有进一步插值的情况下绘制时,这可能会导致看起来更平滑的光谱。

更多信息见

https://dsp.stackexchange.com/questions/741/why-should-i-zero-pad-a-signal-before-taking-the-fourier-transform

希望对您有所帮助。

关于C# 频率检索,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15873880/

相关文章:

c# - 强制 ASMX 代理使用 XmlSerializer 而不是 DataContractSerializer

矩阵傅里叶变换。坚持理解频率和结果之间的关系

python - 为什么随后的FFT产生的频率集与生成时使用的频率集不同?

python - 提高 Python 中的 FFT 性能

java - 如何使用 Java Stream API 查找字符串中重复出现的子字符串

c# - 设置列表框虚拟化模式(数据)

c# - 我可以通过 SqlCommand.Dispose 事件处置 SqlConnection 吗?

c# - 对预检请求的响应未通过访问控制检查 : The value of the 'Access-Control-Allow-Credentials' header in the response is ''

vb.net - VB.net直播频率检测

r - 如何计算R中每一行的字符串频率