【发布时间】:2017-09-01 08:58:03
【问题描述】:
我想获取字节数组中音频字节的音高(Hz)。 这是我现在的代码:
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 这样的值
【问题讨论】:
-
你是什么意思“音频字节的音高”?该数组是以特定采样率对音频流进行的数字捕获——每个字节代表采样时刻的幅度——因此该字节没有音高。您需要对整个阵列(或其中的一部分)进行某种音频分析,以获得该时间段的音高。
-
您需要阅读和分析标题。
-
@PaulF 我可以分析并得到它的音调的最短时间是多少?我该怎么做?
-
@Eldar:要做到这一点,您需要对音频流的不同时间间隔进行一系列 FFT 变换。对于每个间隔,您可以从频谱中确定音高并进一步处理它们。当然,这里的假设是您的音频流一次只包含一个小频带,而音乐、语音等情况并非如此......
-
您可能想尝试Signal Processing Stack Exchange 来寻求资源 - 但正如 Marko 所说,“对所涉及的数学有基本的了解对于任何类型的音频分析都是必不可少的” - 任何体面的书都会涉及一些非常复杂的数学。我在 35 多年前学习了基础知识,所以我怀疑我用过的任何书仍然可用 - 所以我只能建议谷歌。快速搜索一下这个页面 - dspguru.com/dsp/books/favorites - 我不能保证提到的任何书籍。