如何从.wav声音变成double [] C#

时间:2012-11-15 01:55:25

标签: c# audio

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

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

2 个答案:

答案 0 :(得分:6)

这是一个简单的流操作。

  1. 您必须阅读wav文件标题。
  2. 您必须读取数据字节。
  3. 从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:

    How to convert wave data into Complex numbers

答案 1 :(得分:0)

Kamil的解决方案非常接近,但是不适用于我遇到的某些wav文件。经过研究,这是我发现的。在规范的WAV PCM声音文件格式(http://soundfile.sapp.org/doc/WaveFormat/)的描述中,我在注释中发现了此参考: Wave数据流中可能还有其他子块。如果是这样,则每个将具有char [4] SubChunkID,以及无符号长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 };
            }

        }