我需要执行 FFT,并且我有一个声音样本 .wav 格式。该函数需要 double[] xRe, double[] xIm, REAL PART and imaginary part
如何将声音文件转换为double[]?我从来没有见过这样的事情。在互联网上找不到那种操作。这是这个声音样本:
http ://www.speedyshare.com/fFD8t/e.wav
请帮忙,因为我使用了 Pascal,现在不知道该怎么做。
我需要执行 FFT,并且我有一个声音样本 .wav 格式。该函数需要 double[] xRe, double[] xIm, REAL PART and imaginary part
如何将声音文件转换为double[]?我从来没有见过这样的事情。在互联网上找不到那种操作。这是这个声音样本:
http ://www.speedyshare.com/fFD8t/e.wav
请帮忙,因为我使用了 Pascal,现在不知道该怎么做。
这是一个简单的流操作。
从 MSDN 粘贴:
BinaryReader reader = new BinaryReader(waveFileStream);
//Read the wave file header from the buffer.
int chunkID = reader.ReadInt32();
int fileSize = reader.ReadInt32();
int riffType = reader.ReadInt32();
int fmtID = reader.ReadInt32();
int fmtSize = reader.ReadInt32();
int fmtCode = reader.ReadInt16();
int channels = reader.ReadInt16();
int sampleRate = reader.ReadInt32();
int fmtAvgBPS = reader.ReadInt32();
int fmtBlockAlign = reader.ReadInt16();
int bitDepth = reader.ReadInt16();
if (fmtSize == 18)
{
// Read any extra values
int fmtExtraSize = reader.ReadInt16();
reader.ReadBytes(fmtExtraSize);
}
int dataID = reader.ReadInt32();
int dataSize = reader.ReadInt32();
// Store the audio data of the wave file to a byte array.
byteArray = reader.ReadBytes(dataSize);
// After this you have to split that byte array for each channel (Left,Right)
// Wav supports many channels, so you have to read channel from header
这是更详细的解释:
http://msdn.microsoft.com/en-us/library/ff827591.aspx
在这里您可以阅读有关 WAV 文件格式的信息:
https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
还有一些关于 WAV 作为复数和 FFT:
Kamil 的解决方案非常接近,但不适用于我遇到的一些 wav 文件。经过一番研究,这是我发现的。在规范 WAV PCM 声音文件格式 ( http://soundfile.sapp.org/doc/WaveFormat/ ) 的描述中,我在注释中发现了这个参考:Wave 数据流中可能有额外的子块。如果是这样,每个都会有一个 char[4] SubChunkID,和 unsigned long SubChunkSize,以及 SubChunkSize 的数据量。
在我遇到的几个 wav 文件中,确实有额外的子块,所以我不得不添加一些代码来读取,直到找到“数据”标记。添加后,它普遍适用。我的完整代码如下。
public static bool ReadWavFile(string filename, out float[] L, out float[] R)
{
L = R = null;
try
{
using (FileStream fs = File.Open(filename, FileMode.Open))
{
BinaryReader reader = new BinaryReader(fs);
// chunk 0
int chunkID = reader.ReadInt32();
int fileSize = reader.ReadInt32();
int riffType = reader.ReadInt32();
// chunk 1
int fmtID = reader.ReadInt32();
int fmtSize = reader.ReadInt32(); // bytes for this chunk
int fmtCode = reader.ReadInt16();
int channels = reader.ReadInt16();
int sampleRate = reader.ReadInt32();
int byteRate = reader.ReadInt32();
int fmtBlockAlign = reader.ReadInt16();
int bitDepth = reader.ReadInt16();
if (fmtSize == 18)
{
// Read any extra values
int fmtExtraSize = reader.ReadInt16();
reader.ReadBytes(fmtExtraSize);
}
// chunk 2 -- HERE'S THE NEW STUFF (ignore these subchunks, I don't know what they are!)
int bytes;
while(new string(reader.ReadChars(4)) != "data")
{
bytes = reader.ReadInt32();
reader.ReadBytes(bytes);
}
// DATA!
bytes = reader.ReadInt32();
byte[] byteArray = reader.ReadBytes(bytes);
int bytesForSamp = bitDepth / 8;
int samps = bytes / bytesForSamp;
float[] asFloat = null;
switch (bitDepth)
{
case 64:
double[]
asDouble = new double[samps];
Buffer.BlockCopy(byteArray, 0, asDouble, 0, bytes);
asFloat = Array.ConvertAll(asDouble, e => (float)e);
break;
case 32:
asFloat = new float[samps];
Buffer.BlockCopy(byteArray, 0, asFloat, 0, bytes);
break;
case 16:
Int16[]
asInt16 = new Int16[samps];
Buffer.BlockCopy(byteArray, 0, asInt16, 0, bytes);
asFloat = Array.ConvertAll(asInt16, e => e / (float)Int16.MaxValue);
break;
default:
return false;
}
switch (channels)
{
case 1:
L = asFloat;
R = null;
return true;
case 2:
L = new float[samps];
R = new float[samps];
for (int i = 0, s = 0; i < samps; i++)
{
L[i] = asFloat[s++];
R[i] = asFloat[s++];
}
return true;
default:
return false;
}
}
}
catch
{
Debug.WriteLine("...Failed to load note: " + filename);
return false;
//left = new float[ 1 ]{ 0f };
}
}