【问题标题】:Parsing Through Wave File with BinaryReader使用 BinaryReader 解析 Wave 文件
【发布时间】:2011-05-12 19:28:43
【问题描述】:

在 .NET Assembly mscorlib System.IO 命名空间中,我使用 ReadInt16() 方法循环音频数据字节并将有符号整数值转储到文本文件中。如何解释与一个采样率相关的两个值?也就是说,如果我有一秒钟的单声道数据将有 88200 个字节,因此使用 ReadInt16() 返回 88200 个离散整数。这信息太多了,我应该只有 44100 个整数。所以我是否需要使用不同的方法,或者每次迭代将循环提前 1 次。

非常感谢........米奇

【问题讨论】:

    标签: c# file wave audio-processing


    【解决方案1】:
    using System;
    using System.IO;
    
    public struct WaveFormat
    {
    
        private short m_FormatTag;       // most often PCM = 1      
        private short m_nChannels;       // number of channels      
        private int m_SamplesPerSecond;  // samples per second eg 44100     
        private int m_AvgBytesPerSecond; // bytes per second eg 176000      
        private short m_BlockAlign;      // blockalign (byte per sample) eg 4 bytes         
        private short m_BitsPerSample;   // bits per sample, 8, 16, 24
    
        public WaveFormat(byte BPS, int SPS, byte nChn)
        {
            m_FormatTag = 1; //PCM
            m_nChannels = nChn;
            m_SamplesPerSecond = SPS;
            m_BitsPerSample = BPS;
            m_BlockAlign = (short)(m_nChannels * m_BitsPerSample / 8);
            m_AvgBytesPerSecond = (int)(m_BlockAlign * m_SamplesPerSecond);
        }
        public short FormatTag
        {
            get { return m_FormatTag; }
            set { m_FormatTag = value; }
        }
        public short Channels
        {
            get { return m_nChannels; }
        }
        public int SamplesPerSecond
        {
            get { return m_SamplesPerSecond; }
        }
        public int AvgBytesPerSecond
        {
            get { return m_AvgBytesPerSecond; }
        }
        public short BlockAlign
        {
            get { return m_BlockAlign; }
        }
        public short BitsPerSample
        {
            get { return m_BitsPerSample; }
        }
        public void Read(BinaryReader br)
        {
            m_FormatTag = br.ReadInt16();
            m_nChannels = br.ReadInt16();
            m_SamplesPerSecond = br.ReadInt32();
            m_AvgBytesPerSecond = br.ReadInt32();
            m_BlockAlign = br.ReadInt16();
            m_BitsPerSample = br.ReadInt16();
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(m_FormatTag);
            bw.Write(m_nChannels);
            bw.Write(m_SamplesPerSecond);
            bw.Write(m_AvgBytesPerSecond);
            bw.Write(m_BlockAlign);
            bw.Write(m_BitsPerSample);
        }
        public override string ToString()
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            sb.AppendLine("FormatTag:         " + m_FormatTag.ToString());
            sb.AppendLine("nChannels:         " + m_nChannels.ToString());
            sb.AppendLine("SamplesPerSecond:  " + m_SamplesPerSecond.ToString());
            sb.AppendLine("AvgBytesPerSecond: " + m_AvgBytesPerSecond.ToString());
            sb.AppendLine("BlockAlign:        " + m_BlockAlign.ToString());
            sb.AppendLine("BitsPerSample:     " + m_BitsPerSample.ToString());
            return sb.ToString();
        }
    }
    

    【讨论】:

      【解决方案2】:

      通常,当您读取数据数组时,您的代码应如下所示:

      for(int i = 0; i < totalNumberOfEntries; i++)
      {
        // read all data for this entry
        var component1 = reader.ReadXXX();
        var component2 = reader.ReadXXX();
      
        // deal with data for this entry
        someEntryStroage.Add(new Entry(component1, component2);
      }
      

      最有可能(我不知道 Wave 文件格式)在您的情况下,您要么需要读取 Int16 值对(如果样本在一起),要么如果一个通道的数据一个接一个,则单独读取通道。

      【讨论】:

      • wav文件中的通道是“多路复用的”,这意味着:sample1_chnl_1,sample1_chnl_2,sample2_chnl_1,sample2_chnl_2,sample3_chnl_1,sample3_chnl_2,sample4_chnl_1,sample4_chnl_2...
      【解决方案3】:

      你必须阅读chunkinfos。数据块告诉您必须读取多少字节。 WaveFormat 会告诉您平均每秒多少字节,等等。我有一些 VB 代码...

      【讨论】:

        【解决方案4】:

        已经将带有 sharpdevelop 的 VB 代码转换为 C# 可能会有所帮助...

        using System;
        using System.IO;
        
        public class ChunkInfo
        {
            private byte[] m_Header;
            private long m_Length;
            private long m_OffSet;
            public ChunkInfo(string Header)
            {
                m_Header = new byte[Header.Length];
                for (int i = 0; i <= m_Header.GetUpperBound(0); i++)
                {
                    m_Header[i] = (byte)Header[i];
                }
            }
            public ChunkInfo(byte[] Header)
            {
                m_Header = Header;
            }
            public void Read(BinaryReader br)
            {
                m_OffSet = SearchOffset(br);
                if (m_OffSet >= 0)
                {
                    br.BaseStream.Position = m_OffSet + m_Header.Length;
                    m_Length = br.ReadInt32();
                }
            }
            public void Write(BinaryWriter bw)
            {
                bw.Write(m_Header);
                bw.Write(m_Length);
            }
            public long Length
            {
                get { return m_Length; }
            }
            public long OffSet
            {
                get { return m_OffSet; }
            }
            private long SearchOffset(BinaryReader br)
            {
                byte[] haystack = null;
                bool found = false;
                long offset = 0;
                long basepos = 0;
                int hlength = 260;
                long basepos_grow = hlength - m_Header.Length;
                while (!(found || (basepos >= br.BaseStream.Length)))
                {
                    br.BaseStream.Position = basepos;
                    haystack = br.ReadBytes(hlength);
                    offset = BoyerMooreHorspool.find(haystack, m_Header);
                    found = offset >= 0;
                    if (found)
                    {
                        offset += basepos;
                        break; 
                    }
                    else
                    {
                        basepos += basepos_grow;
                    }
                }
                return offset;
            }
        }
        public static class BoyerMooreHorspool
        {
            //detects a needle in the haystack
            const int UBYTE_MAX = 255;
            static int[] bad_char_skip4 = new int[UBYTE_MAX + 3];
            static int[] bad_char_skip8 = new int[UBYTE_MAX + 3];
            static bool IsInitialized = false;
            public static void init()
            {
                //little optimization for needles with length 4 or 8
                for (int i = 0; i <= UBYTE_MAX + 2; i++)
                {
                    bad_char_skip4[i] = 4;
                    bad_char_skip8[i] = 8;
                }
                IsInitialized = true;
            }
            public static int find(byte[] haystack, byte[] needle, int start = 0)
            {
                if (!IsInitialized) init();
                int i_n = 0;
                //needle index
                int n_n = needle.Length;
                int[] bad_char_skip = null;
                switch (n_n)
                {
                    case 4:
                        bad_char_skip = bad_char_skip4;
                        break;
                    case 8:
                        bad_char_skip = bad_char_skip8;
                        break;
                    default:
                        bad_char_skip = new int[UBYTE_MAX + 3];
                        for (i_n = 0; i_n <= UBYTE_MAX + 2; i_n++)
                        {
                            bad_char_skip[i_n] = n_n;
                        }
        
                        break;
                }
                int ifind = -1;
                //if not found then return - 1
                int i_h = start;
                //haystack index
                int n_h = haystack.Length;
                if (n_n > n_h)
                    throw new ArgumentOutOfRangeException("needle", "needle is to long");
                int last = n_n - 1;
                for (i_n = 0; i_n <= last - 1; i_n++)
                {
                    bad_char_skip[needle[i_n]] = last - i_n;
                }
                byte bcs = 0;
                int bhs = 0;
                while ((n_h - start) >= n_n)
                {
                    i_n = last;
                    while (haystack[i_h + i_n] == needle[i_n])
                    {
                        i_n -= 1;
                        if (i_n == 0)
                        {
                            ifind = i_h;
                            break; 
                        }
                    }
                    bhs = haystack[i_h + last];
                    bcs = (byte)(bad_char_skip[bhs]);
                    n_h -= bcs;
                    i_h += bcs;
                }
                return ifind;
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-12-31
          • 1970-01-01
          • 2015-03-24
          • 2021-03-29
          • 2016-03-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多