Parsing Through Wave File with BinaryReader
In .NET Assembly mscorlib System.IO namespace, I am using ReadInt16() method to loop through audio data bytes and dumping signed integer values into a text file. How does one interpret the two values associated with one sample rate? That is开发者_如何学C if I have one second of mono data there will be 88200 bytes, hence using ReadInt16() returns 88200 discrete integers. This is too much information, I should only have 44100 integers. So do I need to use a different method or perhaps advance the loop by 1 per each iteration.
Many thanks..........Mickey
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();
}
}
Generally when you read arrays of data your code should look like:
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);
}
Most likely (I don't know Wave file format) in your case you either need to read pairs of Int16 values (if samples are together) or read channels separately if data for one channel is after another.
you must read the chunkinfos. The data-chunk tells you how much bytes you have to read. the WaveFormat tells you ho much Averagebytespersecond you have, and much more. I have some VB-code...
have converted the VB-code with sharpdevelop to C# maybe it helps a little bit...
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;
}
}
精彩评论