我想得到一个字节数组中音频字节的音高。 这是我现在的代码:
byte[] wav = File.ReadAllBytes("test.wav");
for (int i = 44; i<wav.Length; i++)
{
// wav[i] is an audio byte, channel shifts every 2 bytes (I think)
}
起初我认为wav文件是用数百或数千个块构建的,每个块都包含一个采样率,所以我试图扫描整个数组中的另一个字节序列,代表单词“WAVE”,这是一个块的一部分,但采样率仅在数组的开头,而在44位之后,所有数组都只是音频数据本身。
音频字节只是一个十六进制值,我无法理解如何从该值中获取任何信息。
更新:我已经下载了具有FFT算法的Math.NET库。 这是FFT的文档:https://numerics.mathdotnet.com/api/MathNet.Numerics.IntegralTransforms/Fourier.htm 我已经阅读了那里的所有方法,但我不知道什么方法可以做我想要的(给它几个字节的wav文件并获得它们的频率)。
更新2: 现在我使用Accord库进行FFT,我在youtube上找到了一个教程。 这是我将音频字节转换为双数组的代码:
for (int i = 44; i<wav.Length; i+=BufferSize)
{
float currentSec = (float) audioLength / wav.Length * i;
byte[] buffer = new byte[BufferSize];
for (int j = 0; j < buffer.Length; j++)
{
if ((i + j + 1) < wav.Length)
buffer[j] = wav[i + j];
}
int SAMPLE_RESOLUTION = 16;
int BYTES_PER_POINT = SAMPLE_RESOLUTION / 8;
Int32[] vals = new Int32[buffer.Length / BYTES_PER_POINT];
double[] Ys = new double[buffer.Length / BYTES_PER_POINT];
double[] Ys2 = new double[buffer.Length / BYTES_PER_POINT];
for (int k = 0; k < Ys.Length; k++)
{
byte hByte = buffer[k * 2 + 1];
byte lByte = buffer[k * 2 + 0];
vals[k] = (int)(short)((hByte << 8) | lByte);
Ys[k] = vals[k];
}
Ys2 = FFT(Ys);
double avgFrq = AverageFromArray(Ys2);
if(lastSecond < (int) currentSec)
lastSecond = (int) currentSec;
}
FFT功能:
private double[] FFT(double[] data)
{
double[] fft = new double[data.Length];
System.Numerics.Complex[] fftComplex = new System.Numerics.Complex[data.Length];
for (int i = 0; i < data.Length; i++)
{
fftComplex[i] = new System.Numerics.Complex(data[i], 0);
}
Accord.Math.FourierTransform.FFT(fftComplex, Accord.Math.FourierTransform.Direction.Forward);
for (int i = 0; i < data.Length; i++)
{
fft[i] = fftComplex[i].Magnitude;
}
return fft;
}
因此要检查它是否有效我制作的wav文件只是5000Hz频率的白噪声,但这些是我从FFT得到的结果(2048字节数组的值): https://pastebin.com/PUq5bQTn 整个音频文件具有相同的5000Hz频率但我的代码给我的值为605.80502914453746和4401.1090268930584
答案 0 :(得分:6)
我担心你的代码(和问题)过于天真。
Wav文件不仅仅是音频样本的集合。有关文件格式及其结构的说明,请查看(例如)this。
如果您想阅读,处理,编写音频文件,那里有不同的库(例如NAudio)可以提供很多帮助。
从音频流中的1个样本中,您永远无法计算音高。为此,您需要一个(相对较大的)样本数,并使用FFT变换计算频谱。
答案 1 :(得分:4)
iframe.unbind( "load" );
数据只是脉冲编码调制(PCM)。这意味着每个值都代表音频信号的实际点。
Wav文件有标题,您可以找到有关它的一些信息here。它描述了文件的结构。
如果你的意思是&#34; pitch&#34;样本的基本频率,请尝试FFT
幅度是某一点的值,但要注意,您需要考虑这些变量:
答案 2 :(得分:2)
单个FFT幅度峰值是衡量音高的一种较差且通常不准确的方式,因为音调是一种更复杂的心理声学现象。
估算频率时存在时频折衷,通常与sampleRate / blockLength成正比。因此,以44100的采样率使用44个采样块,频率估计误差将在44100/44或大约+ -1000 Hz(可能取决于平稳性和信噪比)。