2

我需要执行 FFT,并且我有一个声音样本 .wav 格式。该函数需要 double[] xRe, double[] xIm, REAL PART and imaginary part如何将声音文件转换为double[]?我从来没有见过这样的事情。在互联网上找不到那种操作。这是这个声音样本: http ://www.speedyshare.com/fFD8t/e.wav

请帮忙,因为我使用了 Pascal,现在不知道该怎么做。

4

2 回答 2

6

这是一个简单的流操作。

  1. 您必须阅读 wav 文件头。
  2. 您必须读取数据字节。

从 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:

如何将波形数据转换为复数

于 2012-11-15T02:11:25.673 回答
2

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

        }
于 2018-11-10T00:35:28.450 回答