Cannot convert Wav to Flac, c#, 1 Error - c#

I'm using this WaveReader class in my code. I'm getting this error:
ERROR: Ensure that samples are integers (e.g. not floating-point numbers)
if (format.wFormatTag != 1) // 1 = PCM 2 = Float
throw new ApplicationException("Format tag " + format.wFormatTag + " is not supported!");
All I'm trying to is convert WAV file to FLAC so I can feed it to GoogleSpeechAPI. I can do the first step, record WAV files. I am stuck on the second step: convert WAV file to FLAC. I can do the 3rd step: convert FLAC to text using GoogleSpeech API.
For the second step, where I'm getting stuck, here is my code:
public void WAV_to_FLAC_converter()
{
string inputFile = "inputFile.wav";
//string outputFile = Path.Combine("flac", Path.ChangeExtension(input, ".flac"));
string outputFile = "outputFile.flac";
if (!File.Exists(inputFile))
throw new ApplicationException("Input file " + inputFile + " cannot be found!");
var stream = File.OpenRead(#"C:\inputFile.wav");
WavReader wav = new WavReader(stream);
using (var flacStream = File.Create(outputFile))
{
FlacWriter flac = new FlacWriter(flacStream, wav.BitDepth, wav.Channels, wav.SampleRate);
// Buffer for 1 second's worth of audio data
byte[] buffer = new byte[wav.Bitrate / 8];
int bytesRead;//**I GET THE ABOVE ERROR HERE.**
do
{
bytesRead = wav.InputStream.Read(buffer, 0, buffer.Length);
flac.Write(buffer, 0, bytesRead);
} while (bytesRead > 0);
flac.Dispose();
flac = null;
}
}
Apparently there is something wrong with the input wav file I am giving the function. I think it says the stream variable that I created is in float-point instead of integer. But what am I supposed to do? I didn't mess with the WAV file. It's just a WAV file. How can I change a WAV file from float-point to Integer?? I don't know how to fix this.

I've tested your code with a random wave file and it worked perfectly.
Then I downloaded a stereo 32-bit float data wave sample from here and I got the same error as you:
ERROR: Ensure that samples are integers (e.g. not floating-point numbers)
Then I debugged the code and following exception was thrown
// Ensure that samples are 16 or 24-bit
if (format.wBitsPerSample != 16 && format.wBitsPerSample != 24)
throw new ApplicationException(format.wBitsPerSample + " bits per sample is not supported by FLAC!");
I'm afraid the WavReader class simply does not support 32 bit float wave samples, nor does the FlacWriter.
UPDATE: I got your project working now. You have to rename your libFlac.dll to LibFlac.dll in your debug folder. There should be no more problems loading the library. What I got then was a PInvokeStackImabalance exception. If you get it too, you could follow the instructions from the post here or simple turn throwing of this type of exception off under Debug->Exceptions->Managed Debugging Assistans->PInvokeStackImbalance.

Related

Convert.ToBase64String throws 'System.OutOfMemoryException' for byte [] (file: large size)

I am trying to convert byte[] to base64 string format so that i can send that information to third party. My code as below:
byte[] ByteArray = System.IO.File.ReadAllBytes(path);
string base64Encoded = System.Convert.ToBase64String(ByteArray);
I am getting below error:
Exception of type 'System.OutOfMemoryException' was thrown. Can you
help me please ?
Update
I just spotted #PanagiotisKanavos' comment pointing to Is there a Base64Stream for .NET?. This does essentially the same thing as my code below attempts to achieve (i.e. allows you to process the file without having to hold the whole thing in memory in one go), but without the overhead/risk of self-rolled code / rather using a standard .Net library method for the job.
Original
The below code will create a new temporary file containing the Base64 encoded version of your input file.
This should have a lower memory footprint, since rather than doing all data at once, we handle it several bytes at a time.
To avoid holding the output in memory, I've pushed that back to a temp file, which is returned. When you later need to use that data for some other process, you'd need to stream it (i.e. so that again you're not consuming all of this data at once).
You'll also notice that I've used WriteLine instead of Write; which will introduce non base64 encoded characters (i.e. the line breaks). That's deliberate, so that if you consume the temp file with a text reader you can easily process it line by line.
However, you can amend per your needs.
void Main()
{
var inputFilePath = #"c:\temp\bigfile.zip";
var convertedDataPath = ConvertToBase64TempFile(inputFilePath);
Console.WriteLine($"Take a look in {convertedDataPath} for your converted data");
}
//inputFilePath = where your source file can be found. This is not impacted by the below code
//bufferSizeInBytesDiv3 = how many bytes to read at a time (divided by 3); the larger this value the more memory is required, but the better you'll find performance. The Div3 part is because we later multiple this by 3 / this ensures we never have to deal with remainders (i.e. since 3 bytes = 4 base64 chars)
public string ConvertToBase64TempFile(string inputFilePath, int bufferSizeInBytesDiv3 = 1024)
{
var tempFilePath = System.IO.Path.GetTempFileName();
using (var fileStream = File.Open(inputFilePath,FileMode.Open))
{
using (var reader = new BinaryReader(fileStream))
{
using (var writer = new StreamWriter(tempFilePath))
{
byte[] data;
while ((data = reader.ReadBytes(bufferSizeInBytesDiv3 * 3)).Length > 0)
{
writer.WriteLine(System.Convert.ToBase64String(data)); //NB: using WriteLine rather than Write; so when consuming this content consider removing line breaks (I've used this instead of write so you can easily stream the data in chunks later)
}
}
}
}
return tempFilePath;
}

.NET SerialPort Write() adding characters and moving bytes

I am developing a firmware upgrade app in C# using VisualStudio 2015. The app uses a XAML-based form and C# code. The target of the firmware upgrade is a custom board running an STM32F417 processor (ARM Cortex M4). The C# code connects with the 417, causes the 417 to jump to its bootloader (factory installed) and uses the bootloader API to load the new firmware.
After every transfer of 256 bytes (max transfer allowed), a checksum of the data and the number of bytes is sent, and an ACK byte is received from the 417 to show that everything checked out for that transfer. The transfer would fail after a couple of blocks of 256 and to test the transfer, I set up the C# code to just transfer the .hex file without any of the other checks.
I set the code to transfer the updated firmware as a .hex file. line by line. It writes data out the a serial line and is captured as text in HyperTerminal.
I implemented it as a write of 256 bytes:
byte[] buffer256 = new byte[256];
// Read the file and process one line at a time
System.IO.StreamReader file = new System.IO.StreamReader(path);
while ((line = file.ReadLine()) != null)
{
line = line.Substring(1, line.Length - 1);
// Create byte array from string
var bytes = GetBytesFromByteString(line).ToArray();
// Assign values to variables from byte array
type = bytes[3];
// BLOCK WRITE TO MEMORY
if (type == 0) // data type
{
length = bytes[0];
if (byteCounter >= 255)
{
_serialPort.Write(buffer256, 0, 256);
Array.Clear(buffer256, 0, buffer256.Length);
byteCounter = 0;
}
for (int i = 0; i < length; i++)
{
buffer256[byteCounter++] = bytes[4 + i];
}
} // end BLOCK WRITE TO MEMORY
counter++;
} // end WHILE loop for loading hex file
file.Close();
And also as a write of single bytes:
byte[] buffer256 = new byte[256];
// Read the file and process one line at a time
System.IO.StreamReader file = new System.IO.StreamReader(path);
while ((line = file.ReadLine()) != null)
{
line = line.Substring(1, line.Length - 1);
// Create byte array from string
var bytes = GetBytesFromByteString(line).ToArray();
// Assign values to variables from byte array
type = bytes[3];
if (type == 0)
{
length = bytes[0];
for (int i = 0; i < length; i++)
{
_serialPort.Write(bytes, 4 + i, 1);
} // end FOR loop
}// end SINGLE BYTE WRITING
counter++;
} // end WHILE loop for loading hex file
file.Close();
In both cases, the hex file is changed by writing it using the SerialPort class. I tried various other methods, even WriteAsync in the BaseStream class on which the SerialPort class is built (overriding Stream methods).
Here is a sample (8 words) of the original .hex file (data only) compared to the received data:
Original:
00F8012B 002AF9D1 18467047 70B50646
2DF0FEFC 04680546 0A220021 304600F0
Received:
00F8012B 002AF9D1 18464670 4770B506
462DF0FE FC046805 460A2200 21304600
These are lines 49 and 50 out of 13391. The checksums for some of the blocks were also checked and were wrong. I'm pretty sure that is why the firmware upgrades are failing — the bootloader is calculating a checksum based on what it is receiving and fails when it compares it to the checksum the C# app is calculating and sending over.
My question is: if the SerialPort (and underlying Stream) is unreliable, what should I replace it with and how? Is it possible to just replace the SerialPort class, maybe with a C++ class? Or would it be better to rewrite the entire app in C++ or something else?
The SerialPort class itself isn't unreliable. I've used it successfully on the desktop and numerous CE devices. The problem could be the hardware on either end, one of the OSes, some fiddly configuration value, or some combination of any of those.
It could also be your code. I'm not sure you're doing anything wrong, but reading binary data into a string using ReadLine seems pretty weird to me. Have you verified bytes[] is correct in a debugger?
PS--If one of the hardware issues is related to timing, switching to C++ can be helpful. Interop is pretty painless for something like this, so I wouldn't bother rewriting the whole app, but I don't know your situation so couldn't say for sure.

How to read the content of file from port

I am in needed to use the text data in to a program when someone prints a file.
I have basic ideas about the TCP/IP client and listener programming.
Already I could send and receive txt files between two machines.
But how to receive the file contents if the files were in docx,xlx,pdf or any other format?
My requirement is,
I wanted to use the contents (texts) of a file in to another program when someone prints a file.
Please suggest me if there is some alternative ways to do it.
Thank in advance.
Since you haven't posted any code I'll write the code part in "my way" but you should have a bit of understanding after reading this.
First on both of the ends ( client and server ) you should apply unified protocol which will describe what data you're sending. Example could be:
[3Bytes - ASCII extension][4Bytes - lengthOfTheFile][XBytes - fileContents]
Then in your sender you can receive data according to the protocol which means first your read 3 bytes to decide what format file has, then you read 4 bytes which will basically inform you how large file is incomming. Lastly you have to read the content and write it directly to the file. Example sender could look like this :
byte[] extensionBuffer = new byte[3];
if( 3 != networkStream.Read(extensionBuffer, 0, 3))
return;
string extension = Encoding.ASCII.GetString(extensionBuffer);
byte[] lengthBuffer = new byte[sizeof(int)];
if(sizeof(int) != networkStream.Read(lengthBuffer, 0, 3))
return;
int length = BitConverter.ToInt32(lengthBuffer, 0);
int recv = 0;
using (FileStream stream = File.Create(nameOfTheFile + "." + extension))
{
byte #byte = 0x00;
while( (#byte = (byte)networkStream.ReadByte() ) != 0x00)
{
stream.WriteByte(#byte);
recv++;
}
stream.Flush();
}
On the sender part you can read the file extension then open up the file stream get the length of the stream then send the stream length to the client and "redirect" each byte from FileStream into a networkStream. This can look something like :
FileInfo meFile = //.. get the file
byte[] extBytes = Encoding.ASCII.GetBytes(meFile.Extension);
using(FileStream stream = meFile.OpenRead())
{
networkStream.Write(extBytes, 0, extBytes.Length);
networkStream.Write(BitConverter.GetBytes(stream.BaseStream.Length));
byte #byte = 0x00;
while ( stream.Position < stream.BaseStream.Length )
{
networkStream.WriteByte((byte)stream.ReadByte());
}
}
This approach is fairly easy to implement and doesn't require big changes if you want to send different file types. It lack some validator but I think you do not require this functionality.

Append WAV Header in NAudio

I am trying to convert audio MP3 files to WAV with a standard rate (48 KHz, 16 bits, 2 channels) by opening with "MediaFoundationReaderRT" and specifying the standard settings in it.
After the file is converted to PCM WAV, when I try to play the WAV file, it gives corrupt output:
Option 1 -
WaveStream activeStream = new MediaFoundationReaderRT([Open "MyFile.mp3"]);
WaveChannel32 waveformInputStream = new WaveChannel32(activeStream);
waveformInputStream.Sample += inputStream_Sample;
I noticed that if I read the audio data into a memory stream (wherein it appends the WAV header via "WaveFileWriter"), then things work fine:
Option 2 -
WaveStream activeStream = new MediaFoundationReaderRT([Open "MyFile.mp3"]);
MemoryStream memStr = new MemoryStream();
byte[] audioData = new byte[activeStream.Length];
int bytesRead = activeStream.Read(audioData, 0, audioData.Length);
memStr.Write(audioData, 0, bytesRead);
WaveFileWriter.CreateWaveFile(memStr, audioData);
RawSourceWaveStream rawSrcWavStr = new RawSourceWaveStream(activeStream,
new WaveFormat(48000, 16, 2));
WaveChannel32 waveformInputStream = new WaveChannel32(rawSrcWavStr);
waveformInputStream.Sample += inputStream_Sample;
However, reading the whole audio into memory is time-consuming. Hence I am looking at "Option 1" as noted above.
I am trying to figure out as to what exactly is the issue. Is it that the WAV header is missing which is causing the problem?
Is there a way in "Option 1" where I can append the WAV header to the "current playing" sample data, instead of converting the whole audio data into memory stream and then appending the header?
I'm not quite sure why you need either of those options. Converting an MP3 file to WAV is quite simple with NAudio:
using(var reader = new MediaFoundationReader("input.mp3"))
{
WaveFileWriter.CreateWaveFile("output.wav", reader);
}
And if you don't need to create a WAV file, then your job is already done - MediaFoundationReader already returns PCM from it's Read method so you can play it directly.

change wav file ( to 16KHz and 8bit ) with using NAudio

I want to change a WAV file to 8KHz and 8bit using NAudio.
WaveFormat format1 = new WaveFormat(8000, 8, 1);
byte[] waveByte = HelperClass.ReadFully(File.OpenRead(wavFile));
Wave
using (WaveFileWriter writer = new WaveFileWriter(outputFile, format1))
{
writer.WriteData(waveByte, 0, waveByte.Length);
}
but when I play the output file, the sound is only sizzle. Is my code is correct or what is wrong?
If I set WaveFormat to WaveFormat(44100, 16, 1), it works fine.
Thanks.
A few pointers:
You need to use a WaveFormatConversionStream to actually convert from one sample rate / bit depth to another - you are just putting the original audio into the new file with the wrong wave format.
You may also need to convert in two steps - first changing the sample rate, then changing the bit depth / channel count. This is because the underlying ACM codecs can't always do the conversion you want in a single step.
You should use WaveFileReader to read your input file - you only want the actual audio data part of the file to get converted, but you are currently copying everything including the RIFF chunks as though they were audio data into the new file.
8 bit PCM audio usually sounds horrible. Use 16 bit, or if you must have 8 bit, use G.711 u-law or a-law
Downsampling audio can result in aliasing. To do it well you need to implement a low-pass filter first. This unfortunately isn't easy, but there are sites that help you generate the coefficients for a Chebyshev low pass filter for the specific downsampling you are doing.
Here's some example code showing how to convert from one format to another. Remember that you might need to do the conversion in multiple steps depending on the format of your input file:
using (var reader = new WaveFileReader("input.wav"))
{
var newFormat = new WaveFormat(8000, 16, 1);
using (var conversionStream = new WaveFormatConversionStream(newFormat, reader))
{
WaveFileWriter.CreateWaveFile("output.wav", conversionStream);
}
}
The following code solved my problem dealing with G.711 Mu-Law with a vox file extension to wav file. I kept getting a "No RIFF Header" error with WaveFileReader otherwise.
FileStream fileStream = new FileStream(fileName, FileMode.Open);
var waveFormat = WaveFormat.CreateMuLawFormat(8000, 1);
var reader = new RawSourceWaveStream(fileStream, waveFormat);
using (WaveStream convertedStream = WaveFormatConversionStream.CreatePcmStream(reader))
{
WaveFileWriter.CreateWaveFile(fileName.Replace("vox", "wav"), convertedStream);
}
fileStream.Close();
openFileDialog openFileDialog = new openFileDialog();
openFileDialog.Filter = "Wave Files (*.wav)|*.wav|All Files (*.*)|*.*";
openFileDialog.FilterIndex = 1;
WaveFileReader reader = new NAudio.Wave.WaveFileReader(dpmFileDestPath);
WaveFormat newFormat = new WaveFormat(8000, 16, 1);
WaveFormatConversionStream str = new WaveFormatConversionStream(newFormat, reader);
try
{
WaveFileWriter.CreateWaveFile("C:\\Konvertierten_Dateien.wav", str);
}
catch (Exception ex)
{
MessageBox.Show(String.Format("{0}", ex.Message));
}
finally
{
str.Close();
}
MessageBox.Show("Konvertieren ist Fertig!");
}

Categories

Resources