Reading and writing WAVE file produces unplayable output - c#

I want to add echo to wave file, in order to do so I need to open it and then save it first. I've written some methods but output file is not correct.
Testing input file size: 731 014
Output file sieze: 730 898
But the "space on disc" is the same for both files, which is 733 184
Error code or whatever it is displayed when opened: 0xc00d36c4
What can be the issue here? This looks pretty simple and yet it's not working. Here's my header, read and write methods:
class WaveFile
{
struct WaveHeader
{
public byte[] RiffID;
public uint fileSize;
public byte[] format;
//Wave format chunk 1
public byte[] fmtID;
public uint fmtSize;
public ushort audioFormat;
public ushort channels;
public uint sampleRate;
public uint byteRate;
public ushort blockAlign;
public int bitsPerSample;
//Wave format chunk 2
public byte[] dataID;
public uint dataSize;
}
uint samples;
public List<short> L;
public List<short> R;
WaveHeader header = new WaveHeader();
//loading file, preparation for modyfying
public bool loadWaveFile(string filePath)
{
using (FileStream fs = File.Open(filePath, FileMode.Open))
using (BinaryReader reader = new BinaryReader(fs))
{
// chunk 0
header.RiffID = reader.ReadBytes(4);
header.fileSize = reader.ReadUInt32();
header.format = reader.ReadBytes(4);
// chunk 1
header.fmtID = reader.ReadBytes(4);
header.fmtSize = reader.ReadUInt32();
header.audioFormat = reader.ReadUInt16();
header.channels = reader.ReadUInt16();
header.sampleRate = reader.ReadUInt32();
header.byteRate = reader.ReadUInt32();
header.blockAlign = reader.ReadUInt16();
header.bitsPerSample = reader.ReadInt16();
// chunk 2
header.dataID = reader.ReadBytes(4);
header.dataSize = reader.ReadUInt32();
// DATA is stereo
L = new List<short>();
R = new List<short>();
samples = header.dataSize / header.blockAlign;
for (int i = 0; i < samples; i++)
{
L.Add((short)reader.ReadUInt16());
R.Add((short)reader.ReadUInt16());
}
reader.Close();
fs.Close();
}
return true;
}
public bool addEcho(int threadsNumber, int echoesNumber, int delay, int attenuation)
{
return true;
}
public bool saveWaveFile(string savingPath)
{
using (FileStream fs = new FileStream(#savingPath + "\\echo.wav", FileMode.Create))
using (BinaryWriter writer = new BinaryWriter(fs))
{
//chunk 0
writer.Write(header.RiffID);
writer.Write(header.fileSize);
writer.Write(header.format);
//chunk 1
writer.Write(header.fmtID);
writer.Write(header.fmtSize);
writer.Write(header.audioFormat);
writer.Write(header.channels);
writer.Write(header.sampleRate);
writer.Write(header.byteRate);
writer.Write(header.blockAlign);
writer.Write(header.bitsPerSample);
//chunk 2
writer.Write(header.dataID);
writer.Write(header.dataSize);
for (int i = 0; i < samples; i++)
{
writer.Write(L[i]);
writer.Write(R[i]);
}
writer.Close();
fs.Close();
return true;
}
}
}

I didn't find out what the issue was, but for echo purposes this class will work:
Class WaveFile
{
byte[] byteArray;
public void loadWaveFile(string filePath)
{
byteArray = File.ReadAllBytes(filePath);
}
public bool addEcho(int threadsNumber, int echoesNumber, int delay, int attenuation)
{
return true;
}
public bool saveWaveFile(string savingPath)
{
using (FileStream fs = new FileStream(#savingPath + "\\echo.wav", FileMode.Create))
using (BinaryWriter writer = new BinaryWriter(fs))
{
writer.Write(byteArray);
writer.Close();
fs.Close();
return true;
}
}
}

Related

streamreader/buffered stream C#

I have a class Value
the output of Value is used as an input to other classes and eventually in Main.
In Main a logic is performed and output is produced for first 512 bits. I want my program to return back to value() to start with next 512 bits of file.txt. How can I do that?
public static byte[] Value()
{
byte[] numbers = new byte[9999];
using (FileStream fs = File.Open(#"C:\Users\file.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (BufferedStream bs = new BufferedStream(fs))
using (StreamReader sr = new StreamReader(bs))
{
string line;
while ((line = sr.ReadLine()) != null)
{
for (int i = 0; i < 512; i++)
{
numbers[i] = Byte.Parse(line[i].ToString());
}
}
}
return numbers;
}
What can be done is to pass Value() an offset and a length parameter.
But there is a problem with your method, you are actually taking the first bytes for each line in the file, which I don't know is what you want to do. So I corrected this to make sure you return only length bytes.
using System.Linq Skip and Take methods, you may find things easier as well
public static byte[] Value(int startOffset, int length)
{
byte allBytes = File.ReadAllBytes(#"C:\Users\file.txt");
return allBytes.Skip(startOffset).Take(length);
}
It seems like what you are trying to do is use a recursive call on Value() this is based on your comment, but it is not clear, so I am going to do that assumption.
there is a problem I see and it's like in your scenario you're returning a byte[], So I modified your code a little bit to make it as closest as your's.
/// <summary>
/// This method will call your `value` methodand return the bytes and it is the entry point for the loci.
/// </summary>
/// <returns></returns>
public static byte[] ByteValueCaller()
{
byte[] numbers = new byte[9999];
Value(0, numbers);
return numbers;
}
public static void Value(int startingByte, byte[] numbers)
{
using (FileStream fs = File.Open(#"C:\Users\file.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (BinaryReader br = new BinaryReader(fs))
{
//64bytes == 512bit
//determines if the last position to use is inside your stream, or if the last position is the end of the stream.
int bytesToRead = startingByte + 64 > br.BaseStream.Length ? (int)br.BaseStream.Length - startingByte : 64;
//move your stream to the given possition
br.BaseStream.Seek(startingByte, SeekOrigin.Begin);
//populates databuffer with the given bytes
byte[] dataBuffer = br.ReadBytes(bytesToRead);
//This method will migrate from our temporal databuffer to the numbers array.
TransformBufferArrayToNumbers(startingByte, dataBuffer, numbers);
//recursive call to the same
if (startingByte + bytesToRead < fs.Length)
Value(startingByte + bytesToRead, numbers);
}
static void TransformBufferArrayToNumbers(int startingByte, byte[] dataBuffer, byte[] numbers)
{
for (var i = 0; i < dataBuffer.Length; i++)
{
numbers[startingByte + i] = dataBuffer[i];
}
}
}
Also, be careful with the byte[9999] as you are limiting the characters you can get, if that's a hardcoded limit, I will add also that information on the if that determines the recursive call.
#TiGreX
public static List<byte> ByteValueCaller()
{
List<byte> numbers = new List<byte>();
GetValue(0, numbers);
return numbers;
}
public static void GetValue(int startingByte, List<byte> numbers)
{
using (FileStream fs = File.Open(#"C:\Users\file1.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (BinaryReader br = new BinaryReader(fs))
{
//64bytes == 512bit
//determines if the last position to use is inside your stream, or if the last position is the end of the stream.
int bytesToRead = startingByte + 64 > br.BaseStream.Length ? (int)br.BaseStream.Length - startingByte : 64;
//move your stream to the given possition
br.BaseStream.Seek(startingByte, SeekOrigin.Begin);
//populates databuffer with the given bytes
byte[] dataBuffer = br.ReadBytes(bytesToRead);
numbers.AddRange(dataBuffer);
//recursive call to the same
if (startingByte + bytesToRead < fs.Length)
GetValue(startingByte + bytesToRead, numbers);
}
}

Zlib Compression differences between zlib.c Adler implemention and Deflate, Ionic Deflate

I have been experiencing some issues with imcompatiabilities between the difference implementations of zlib compression.
As a test case I thought to create test data with 10000 doubles ranging from 0 - 10000.
I created some test code to compress and decompress this data that uses the compress and uncompress in zlib.c
unsigned int Test(char* comparisonFile)
{
unsigned long partsSize = 0x80000;
const int arraySize = 10000;
Bytef doubleArray[sizeof(double) * arraySize];
Bytef outBuffer[sizeof(double) * arraySize];
for (int i = 0; i < arraySize; i++)
{
Bytef doubleBytes[sizeof(double)];
*(double*)(doubleBytes) = (double)i;
for (int x = 0; x < 8; x++)
doubleArray[(8 * i) + x] = doubleBytes[x];
}
compress(outBuffer, &partsSize, doubleArray, sizeof(double) * arraySize);
//create file of compressed data
char * filename = "zlibCompressed";
FILE * file = fopen(filename, "w+b");
int compressResult = et_int64(fwrite((char *)outBuffer, 1, size_t(partsSize), file));
fclose(file);
//load file of compressed data either from zlib or other
if (comparisonFile != NULL)
filename = comparisonFile;
FILE * compressedFile = fopen(filename, "r+b");
if (compressedFile == NULL)
return -1;
unsigned long outBufferSize = sizeof(double) * arraySize;
fseek(compressedFile, 0, SEEK_END);
long fsize = ftell(compressedFile);
fseek(compressedFile, 0, SEEK_SET); /* same as rewind(f); */
partsSize = int(fsize);
double * doubleResult = new double [arraySize];
Bytef* inBuffer = (Bytef*)malloc(sizeof(Bytef)*partsSize);
int readresult = et_int64(fread((char *)inBuffer, 1, partsSize , compressedFile));
if (readresult != partsSize)
return -1;
Bytef * uncompressedOutBuffer = static_cast<Bytef*>((void *)doubleResult);
int result = uncompress(uncompressedOutBuffer, &outBufferSize, inBuffer, partsSize);
for (int i = 0; i < arraySize; i++)
{
// uncompressed data does not match expectation
if ((int)doubleResult[i] != i)
return -2;
}
fclose(compressedFile);
return 0;
}
This allows me to test the internal compression and also substitute compression results from C#.
However, when I use ionic or standard deflate in the following manner I can only recover about 8150 of the expected 10000.
The uncompression returns a:
Z_DATA_ERROR
Given that these seem in theory interoperable, i'm not sure why C# compression results can only be partially unpacked with Adler's zlib? Any help out there?
public void ZlibTest()
{
byte[] buffer;
using (var ms = new MemoryStream())
{
for (int i = 0; i < 10000; i++)
ms.Write(BitConverter.GetBytes((double) i), 0, sizeof(double));
buffer = ms.ToArray();
}
var file = "dummy1";
if (File.Exists(file))
File.Delete(file);
using (Stream fs = new FileStream(file, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
using (var resultStream = new MemoryStream())
{
using (var compressionStream2 = new Ionic.Zlib.ZlibStream(resultStream, Ionic.Zlib.CompressionMode.Compress, CompressionLevel.Default))
{
compressionStream2.Write(buffer, 0, buffer.Length);
var packetLength = (int)resultStream.Length;
fs.Write(resultStream.ToArray(), 0, packetLength);
}
}
}
file = "dummy2";
using (Stream fs = new FileStream(file, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
using (var resultStream = new MemoryStream())
{
using (var compressionStream2 = new System.IO.Compression.DeflateStream(resultStream, System.IO.Compression.CompressionMode.Compress))
{
compressionStream2.Write(buffer, 0, buffer.Length);
var packetLength = (int)resultStream.Length;
fs.Write(BitConverter.GetBytes((ushort)40056), 0, sizeof(ushort));
fs.Write(resultStream.ToArray(), 0, packetLength);
}
}
}
}
They're both using the same zlib. There must be an error in your C# code. It is possible that you are not reading the file in binary mode in C#, which would cause occasional corruption.

The datastream was too long [duplicate]

When I'm trying to write very large amount of data (list with 300 000 rows and more) to memory stream using CsvHelper, it throws the exception "System.IO.IOException: Stream was too long.".
Data class is rather big and has ~30 properties, consequently each record in the file would have ~30 columns.
This is the actual writing code where exception throws (by the way this code is based on that answer of CsvHelper lib's author):
using (var memoryStream = new MemoryStream())
{
using (var streamWriter = new StreamWriter(memoryStream, encoding ?? Encoding.ASCII))
{
var csvWriter = new CsvWriter(streamWriter, GetConfiguration(delimiter, mappingClassType, mappingActions));
csvWriter.WriteRecords(data); //data is IEnumerable<T> and has more than 300k records
streamWriter.Flush();
return memoryStream.ToArray();
}
}
Then I save the resulted bytes array into the file.
File.WriteAllBytes(filePath, resultedBytesArray);
Please note, that the same code works well when I write 100 000 records to the file (in that case the file has size about 1GB). By the way, my goal is to write more then 600 000 data records.
This is the relevant part of the stack trace related to this issue.
Stream was too long.|System.IO.IOException: Stream was too long.
at System.IO.MemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
at System.IO.StreamWriter.Write(Char[] buffer, Int32 index, Int32 count)
at CsvHelper.CsvWriter.NextRecord() in C:\Users\Josh\Projects\CsvHelper\src\CsvHelper\CsvWriter.cs:line 290
at CsvHelper.CsvWriter.WriteRecords(IEnumerable records) in C:\Users\Josh\Projects\CsvHelper\src\CsvHelper\CsvWriter.cs:line 490
at FileExport.Csv.CsvDocument.Create[T](IEnumerable`1 data, String delimiter, Encoding encoding, Type mappingClassType, IDictionary`2 mappingActions) in d:\Dev\DrugDevExport\FileExport\Csv\CsvDocument.cs:line 33
As far as I'm concerned the basic way to achieve my goal and avoid that issue is to split my list of written data up on few parts and concatenate them together then, but may be is there any pretty obvious and easy solution without a significant code refactoring (like increase the default stream/buffer size, etc..)?
Also keep in mind, that I've also applied two possible solutions in order to prevent "Out Of Memory" objects exception.
got rid of 2GB limitation for objects (from here https://stackoverflow.com/a/20912869) Yes, I'm running on x64 OS with 32GB RAM.
set up x64 "Platform target" in the build settings section (from here https://stackoverflow.com/a/22592876)
Thanks in advance.
You can address this limitation of 2GB by writing your own MemoryStream :
class HugeMemoryStream : Stream
{
#region Fields
private const int PAGE_SIZE = 1024000;
private const int ALLOC_STEP = 1024;
private byte[][] _streamBuffers;
private int _pageCount = 0;
private long _allocatedBytes = 0;
private long _position = 0;
private long _length = 0;
#endregion Fields
#region Internals
private int GetPageCount(long length)
{
int pageCount = (int)(length / PAGE_SIZE) + 1;
if ((length % PAGE_SIZE) == 0)
pageCount--;
return pageCount;
}
private void ExtendPages()
{
if (_streamBuffers == null)
{
_streamBuffers = new byte[ALLOC_STEP][];
}
else
{
byte[][] streamBuffers = new byte[_streamBuffers.Length + ALLOC_STEP][];
Array.Copy(_streamBuffers, streamBuffers, _streamBuffers.Length);
_streamBuffers = streamBuffers;
}
_pageCount = _streamBuffers.Length;
}
private void AllocSpaceIfNeeded(long value)
{
if (value < 0)
throw new InvalidOperationException("AllocSpaceIfNeeded < 0");
if (value == 0)
return;
int currentPageCount = GetPageCount(_allocatedBytes);
int neededPageCount = GetPageCount(value);
while (currentPageCount < neededPageCount)
{
if (currentPageCount == _pageCount)
ExtendPages();
_streamBuffers[currentPageCount++] = new byte[PAGE_SIZE];
}
_allocatedBytes = (long)currentPageCount * PAGE_SIZE;
value = Math.Max(value, _length);
if (_position > (_length = value))
_position = _length;
}
#endregion Internals
#region Stream
public override bool CanRead => true;
public override bool CanSeek => true;
public override bool CanWrite => true;
public override long Length => _length;
public override long Position
{
get { return _position; }
set
{
if (value > _length)
throw new InvalidOperationException("Position > Length");
else if (value < 0)
throw new InvalidOperationException("Position < 0");
else
_position = value;
}
}
public override void Flush() { }
public override int Read(byte[] buffer, int offset, int count)
{
int currentPage = (int)(_position / PAGE_SIZE);
int currentOffset = (int)(_position % PAGE_SIZE);
int currentLength = PAGE_SIZE - currentOffset;
long startPosition = _position;
if (startPosition + count > _length)
count = (int)(_length - startPosition);
while (count != 0 && _position < _length)
{
if (currentLength > count)
currentLength = count;
Array.Copy(_streamBuffers[currentPage++], currentOffset, buffer, offset, currentLength);
offset += currentLength;
_position += currentLength;
count -= currentLength;
currentOffset = 0;
currentLength = PAGE_SIZE;
}
return (int)(_position - startPosition);
}
public override long Seek(long offset, SeekOrigin origin)
{
switch (origin)
{
case SeekOrigin.Begin:
break;
case SeekOrigin.Current:
offset += _position;
break;
case SeekOrigin.End:
offset = _length - offset;
break;
default:
throw new ArgumentOutOfRangeException("origin");
}
return Position = offset;
}
public override void SetLength(long value)
{
if (value < 0)
throw new InvalidOperationException("SetLength < 0");
if (value == 0)
{
_streamBuffers = null;
_allocatedBytes = _position = _length = 0;
_pageCount = 0;
return;
}
int currentPageCount = GetPageCount(_allocatedBytes);
int neededPageCount = GetPageCount(value);
// Removes unused buffers if decreasing stream length
while (currentPageCount > neededPageCount)
_streamBuffers[--currentPageCount] = null;
AllocSpaceIfNeeded(value);
if (_position > (_length = value))
_position = _length;
}
public override void Write(byte[] buffer, int offset, int count)
{
int currentPage = (int)(_position / PAGE_SIZE);
int currentOffset = (int)(_position % PAGE_SIZE);
int currentLength = PAGE_SIZE - currentOffset;
long startPosition = _position;
AllocSpaceIfNeeded(_position + count);
while (count != 0)
{
if (currentLength > count)
currentLength = count;
Array.Copy(buffer, offset, _streamBuffers[currentPage++], currentOffset, currentLength);
offset += currentLength;
_position += currentLength;
count -= currentLength;
currentOffset = 0;
currentLength = PAGE_SIZE;
}
}
#endregion Stream
}
using ICSharpCode.SharpZipLib.GZip;
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
// HugeMemoryStrem Test
string filename = #"gzip-filename.gz";
HugeMemoryStream ms = new HugeMemoryStream();
using (StreamWriter sw = new StreamWriter(ms, Encoding.UTF8, 16384, true))
using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
using (GZipInputStream gzipStream = new GZipInputStream(fs))
using (StreamReader sr = new StreamReader(gzipStream, Encoding.UTF8, false, 16384, true))
{
for (string line = sr.ReadLine(); line != null; line = sr.ReadLine())
sw.WriteLine(line);
}
ms.Seek(0, SeekOrigin.Begin);
using (StreamReader srm = new StreamReader(ms, Encoding.UTF8, false, 16384, true))
using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
using (GZipInputStream gzipStream = new GZipInputStream(fs))
using (StreamReader sr = new StreamReader(gzipStream, Encoding.UTF8, false, 16384, true))
{
for (string line1 = sr.ReadLine(), line2 = srm.ReadLine(); line1 != null; line1 = sr.ReadLine(), line2 = srm.ReadLine())
{
if (line1 != line2)
throw new InvalidDataException();
}
}
Many thanks Spender, like he mentioned in the comment below the question, it has been fixed by replacing MemoryStream with FileStream and writing data direct into the file.
It was absolutely useless in my case to write data to MemoryStream and then copy it again into the file without any reason. Thanks him again for opening my eyes on that fact.
My fixed code below.
using (var fileStream = File.Create(path))
{
using (var streamWriter = new StreamWriter(fileStream, encoding ?? Encoding.ASCII))
{
var csvWriter = new CsvWriter(streamWriter, GetConfiguration(delimiter, mappingClassType, mappingActions));
csvWriter.WriteRecords(data);
}
}
Now it works with any amount of input data.

Could read properly the data of WAV file

I am trying to read a wav file as under
class Program
{
struct WavHeader
{
public int riffID;
public int size;
public int wavID;
public int fmtID;
public int fmtSize;
public int format;
public int channels;
public int sampleRate;
public int bytePerSec;
public int blockSize;
public int bit;
public int dataID;
public int dataSize;
}
static void Main(string[] args)
{
WavHeader Header = new WavHeader();
List<short> lDataList = new List<short>();
List<short> rDataList = new List<short>();
using (FileStream fs = new FileStream(#"D:\Test.wav", FileMode.Open, FileAccess.Read))
using (BinaryReader br = new BinaryReader(fs))
{
try
{
Header.riffID = br.ReadInt32();
Header.size = br.ReadInt32();
Header.wavID = br.ReadInt32();
Header.fmtID = br.ReadInt32();
Header.fmtSize = br.ReadInt32();
Header.format = br.ReadUInt16();
Header.channels = br.ReadUInt16();
Header.sampleRate = br.ReadInt32();
Header.bytePerSec = br.ReadInt32();
Header.blockSize = br.ReadInt16();
Header.bit = br.ReadInt16();
if (Header.fmtSize == 18)
{
// Read any extra values
int fmtExtraSize = br.ReadInt16();
br.ReadBytes(fmtExtraSize);
}
Header.dataID = br.ReadInt32();
Header.dataSize = br.ReadInt32();
int bytesForSamp = Header.bit / 8;
int samps = Header.dataSize / bytesForSamp;
for (int i = 0; i < samps; i++)
{
lDataList.Add((short)br.ReadUInt16());
rDataList.Add((short)br.ReadUInt16());
}
}
finally
{
if (br != null)
{
br.Close();
}
if (fs != null)
{
fs.Close();
}
}
}
}
}
But getting runtime error at
lDataList.Add((short)br.ReadUInt16());
rDataList.Add((short)br.ReadUInt16());
{"Unable to read beyond the end of the stream."}
I have seen this SO Q/A and tried to fit as per the requirement but that's returns float.
Here you correctly calculate the bytes per sample and the number of samples:
int bytesForSamp = Header.bit / 8;
int samps = Header.dataSize / bytesForSamp;
But here you assume, that the file has 2 channels and 16-bit samples:
for (int i = 0; i < samps; i++)
{
lDataList.Add((short)br.ReadUInt16());
rDataList.Add((short)br.ReadUInt16());
}
If the file actually has 8-bit samples and/or only 1 channel, then this loop tries to read beyond the input file at some point.
You would either have to assert, that the file is really 16-bit 2ch after reading the header, or handle the file correctly, by reading correctly according to the number of bits per sample and channels specified in the header of the wave-file.

c# objected disposed exception -how can I correct them?

I am beginner c#.
I would like to make program converting from .wav file to .raw file.
I found some source and I would like to use it.
but something happened in the code. the error is related to ObjectDisposedException.
could you give me a some code or idea for me?
the whole code is under
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace WaveTestRead
{
class WaveReader
{
FileInfo m_fInfo;
FileStream m_fStream;
BinaryReader m_binReader;
// RIFF chunk
byte[] chunkID;
UInt32 chunkSize;
byte[] format;
// fmt subchunk
byte[] fmtChunkID;
UInt32 fmtChunkSize;
UInt16 audioFormat;
UInt16 numChannels;
UInt32 sampleRate;
UInt32 byteRate;
UInt16 blockAssign;
UInt16 BitsPerSample;
// data subchunk
byte[] dataChunkID;
UInt32 dataChunkSize;
byte[] data8L; // 8-bit left channel
byte[] data8R; // 8-bit right channel
Int16[] data16L; // 16-bit left channel
Int16[] data16R; // 16-bit right channel
int numSamples;
public WaveReader()
{
}
public bool Open(String filename)
{
string str;
m_fInfo = new FileInfo(filename);
m_fStream = m_fInfo.OpenRead();
m_binReader = new BinaryReader(m_fStream);
chunkID = new byte[4];
format = new byte[4];
chunkID = m_binReader.ReadBytes(4);
chunkSize = m_binReader.ReadUInt32();
format = m_binReader.ReadBytes(4);
str = System.Text.ASCIIEncoding.ASCII.GetString(chunkID, 0, 4);
if (str != "RIFF")
return false;
str = System.Text.ASCIIEncoding.ASCII.GetString(format, 0, 4);
if (str != "WAVE")
return false;
if (ReadFmt() == false)
return false;
if (ReadData() == false)
return false;
m_fStream.Close();
return true;
}
private bool ReadFmt()
{
fmtChunkID = new byte[4];
fmtChunkID = m_binReader.ReadBytes(4);
string str = System.Text.ASCIIEncoding.ASCII.GetString(fmtChunkID, 0, 4);
if (str != "fmt ")
return false;
fmtChunkSize = m_binReader.ReadUInt32();
audioFormat = m_binReader.ReadUInt16();
numChannels = m_binReader.ReadUInt16();
sampleRate = m_binReader.ReadUInt32();
byteRate = m_binReader.ReadUInt32();
blockAssign = m_binReader.ReadUInt16();
BitsPerSample = m_binReader.ReadUInt16();
return true;
}
static void Main(string[] args)
{
p.Open("wavetest.wav");
bool a = p.ReadFmt();
p.ReadData();
}
}
}
The code posted is not very well written.
Anyway you can try with these quick changes:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace WaveTestRead
{
public class Program
{
public static void Main(string[] args)
{
using (var waveReader = new WaveReader())
{
if (!waveReader.Open("wavetest.wav"))
{
Console.WriteLine("Failed to read file.");
return;
}
if (!waveReader.ReadFmt())
{
Console.WriteLine("Failed to read fmt.");
return;
}
// this method is not defined...
//waveReader.ReadData();
}
}
}
class WaveReader : IDisposable
{
FileInfo m_fInfo;
FileStream m_fStream;
BinaryReader m_binReader;
// RIFF chunk
byte[] chunkID;
UInt32 chunkSize;
byte[] format;
// fmt subchunk
byte[] fmtChunkID;
UInt32 fmtChunkSize;
UInt16 audioFormat;
UInt16 numChannels;
UInt32 sampleRate;
UInt32 byteRate;
UInt16 blockAssign;
UInt16 BitsPerSample;
// data subchunk
byte[] dataChunkID;
UInt32 dataChunkSize;
byte[] data8L; // 8-bit left channel
byte[] data8R; // 8-bit right channel
Int16[] data16L; // 16-bit left channel
Int16[] data16R; // 16-bit right channel
int numSamples;
public WaveReader()
{
}
public bool Open(String filename)
{
string str;
m_fInfo = new FileInfo(filename);
m_fStream = m_fInfo.OpenRead();
m_binReader = new BinaryReader(m_fStream);
chunkID = new byte[4];
format = new byte[4];
chunkID = m_binReader.ReadBytes(4);
chunkSize = m_binReader.ReadUInt32();
format = m_binReader.ReadBytes(4);
str = System.Text.ASCIIEncoding.ASCII.GetString(chunkID, 0, 4);
if (str != "RIFF")
return false;
str = System.Text.ASCIIEncoding.ASCII.GetString(format, 0, 4);
if (str != "WAVE")
return false;
//if (ReadFmt() == false)
// return false;
//if (ReadData() == false)
// return false;
return true;
}
public bool ReadFmt()
{
fmtChunkID = new byte[4];
fmtChunkID = m_binReader.ReadBytes(4);
string str = System.Text.ASCIIEncoding.ASCII.GetString(fmtChunkID, 0, 4);
if (str != "fmt ")
return false;
fmtChunkSize = m_binReader.ReadUInt32();
audioFormat = m_binReader.ReadUInt16();
numChannels = m_binReader.ReadUInt16();
sampleRate = m_binReader.ReadUInt32();
byteRate = m_binReader.ReadUInt32();
blockAssign = m_binReader.ReadUInt16();
BitsPerSample = m_binReader.ReadUInt16();
return true;
}
public void Dispose()
{
if (m_fStream != null)
m_fStream.Dispose();
}
}
}
Basically I have created a class WaveReader with your code and removed the internal call to ReadFmt. Then in the Main method I have checked the return code and in case of false I write to the console.
The problem likely exists in Main. The Open method closes the file at the end, and the ReadFmt call in Main reads from m_binReader. Either don't call ReadFmt from your main method after the Open call, or change Open to not close the file when it's done (and make the close explicit).
It looks like Open is doing all the work for you anyway (by calling ReadFmt and ReadData). You don't need to do it again in Main; just access the data from p.

Categories