NAudio - Read and write a Wav file - c#

Before applying any sound modification (using the sample frames), I'm trying to simply read a Wav file, and write out an identical one using the contents:
using (WaveFileReader reader = new WaveFileReader(#"input.wav"))
{
using (WaveFileWriter writer = new WaveFileWriter(#"output.wav", reader.WaveFormat))
{
while (true)
{
var frame = reader.ReadNextSampleFrame();
if (frame == null)
break;
writer.WriteSample(frame[0]);
}
}
}
I'd expect this to write an identical Wav file. But it actually writes a (surprisingly larger file) with a very different sound (as if it's been supressed).
Any ideas?

It's because you are converting to floating point samples, and back to whatever the source format was, and paying no attention to the number of channels. To do what you want you should just use the Read method to read into a byte array and write the same data into the writer.

Related

How to convert audio wav file to Mp3 file Xamarin forms

In my app I am recording voice using AudioRecorder as given in the following site, Audio Recorder it is working but it produce large size WAV file.
For example : If I record audio for 1 minute it takes 4MB to 5MB. So that I want to convert the wave file into MP3 file to reduce the size of the file. Please help me to compress the wav file ,give some example. Thanks in advance.
I never tried converting files before so i looked up on
some threads that might be helpful to you.
One is converting wav to mp3 which require file conversion into a byte[]
public byte[] ConvertToMp3(Uri uri)
{
using (var client = new WebClient())
{
var file = client.DownloadData(uri);
var target = new WaveFormat(8000, 16, 1);
using (var outPutStream = new MemoryStream())
using (var waveStream = new WaveFileReader(new MemoryStream(file)))
using (var conversionStream = new WaveFormatConversionStream(target, waveStream))
using (var writer = new LameMP3FileWriter(outPutStream, conversionStream.WaveFormat, 32, null))
{
conversionStream.CopyTo(writer);
return outPutStream.ToArray();
}
}
}
however on this method he is using a third party service which downloads the
wav file and then to be called on that method but this does not guaranty if the file size will be reduced.
however i have check that you can compress wav files using a library called zlib.
just decompress it whenever u need it.
Please check the link below:
How to convert wav file to mp3 in memory?
Reducing WAV sound file size, without losing quality

Is there any way to convert .mp4 format audio to .wav format just in memory?

I'm developing a WPF application, where I have to play audio. I receive the audio data in .mp4 format (in a byte array) and the only restriction is that I can't write it out to the hard disk.
I found couple of solutions for playing the .mp4 format, for example with WMPLib.WindowsMediaPlayer, but I can't give a byte array, or stream to this library, to play the audio. It just accepts the file path.
Then I found the System.Media.SoundPlayer, which can play audio from a stream, but just in .wav format. I started to search for solutions to convert from mp4 to wav. I found the NAudio library and I could make the conversion the following way:
using (var data = new MediaFoundationReader(filePath)) {
var stream = new MemoryStream();
WaveFileWriter.WriteWavFileToStream(stream, data);
}
The problem with this is that I can instantiate the MediaFoundationReader just with a file path parameter. I didn't find any way to create it without using files. I think this was also a dead end.
So, any suggestion would be helpful about how can I convert audio in memory, or maybe how can I play directly the .mp4 file from a byte array or stream?
You can convert any audio formats witn NAudio
See samples like :How to convert a MP3 file to WAV with NAudio in WinForms C#
with several methods like MediaFoundationReader
Finally I found a solution which converts to an .mp3 format, but it can also convert to .wav. I could use the uwp transcode API the following way:
public static async void ConvertMp4ToMp3(byte[] mp4Data, Action<Stream> doneCallback) {
MediaEncodingProfile profile = MediaEncodingProfile.CreateMp3(AudioEncodingQuality.High);
var inputStream = new MemoryRandomAccessStream(mp4Data);
var outputStream = new InMemoryRandomAccessStream();
MediaTranscoder transcoder = new MediaTranscoder();
PrepareTranscodeResult prepareOperation = await transcoder.PrepareStreamTranscodeAsync(inputStream, outputStream, profile);
if (prepareOperation.CanTranscode) {
//start to convert
var transcodeOperation = prepareOperation.TranscodeAsync();
//registers completed event handler
transcodeOperation.Completed += (IAsyncActionWithProgress<double> asyncInfo, AsyncStatus status) => {
asyncInfo.GetResults();
var stream = outputStream.AsStream();
stream.Position = 0;
doneCallback(stream);
};
} else {
doneCallback(null);
}
}
The imports:
using System;
using System.IO;
using Windows.Foundation;
using Windows.Media.MediaProperties;
using Windows.Media.Transcoding;
using Windows.Storage.Streams;
And the MemoryRandomAccessStream is just an implementation of the IRandomAccesStream interface and can be found here.

Write to S3 using PutObjectRequest while still generating stream

I am converting an application that currently uses the Windows file system to read and store files.
While reading each line of an input file, it modifies the data, and then writes it out to an output file:
using (var writer = new StreamWriter(#"C:\temp\out.txt", false))
{
using (var reader = new StreamReader(#"C:\temp\in.txt", Encoding.UTF8))
{
while ((line = reader.ReadLine()) != null)
{
//Create modifiedLine from line data
...
writer.WriteLine(modifiedLine);
}
}
}
So far, I have been able to write to S3 using a PutObjectRequest, but only with the entire file contents at once:
//Set up stream
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(theEntireModifiedFileContents);
writer.Flush();
stream.Position = 0;
var putRequest = new PutObjectRequest()
{
BucketName = destinationBucket,
Key = destinationKey,
InputStream = stream
};
var response = await s3Client.PutObjectAsync(putRequest);
Given that these are going to be large files, I would prefer to keep the line-by-line approach rather than having to send the entire file contents at once.
Is there any way to maintain a similar behavior to the file system example above with S3?
S3 is an object store and does not support modifications in-place, appending, etc.
However, it is possible to meet your goals if certain criteria is met / understood:
1) Realize that it will take more code to do this than simply modifying your code to buffer the line output and then upload as a single object.
2) You can upload each line as part of the REST API PUT stream. This means that you will need to continuously upload data until complete. Basically you are doing a slow upload of a single S3 object while you process each line.
3) You can use the multi-part API to upload each line as a single part of a multi-part transfer. Then combine parts once complete. Note: I don't remember if each part has to be the same size (except for the last part). The limit to the total number of parts is 1,000. If your number of lines is more than 1,000 than you will need to buffer, so go back to method #1 or add buffering to reduce the number of parts to 1,000.
Unless you are a really motivated developer, realize that method #1 is going to be far easier to implement and test. Methods #2 and #3 will require you to understand how S3 works at a very low level using HTTP PUT requests.

Receiving "Not a WAVE file - no RIFF header" when creating wave stream from mp3 conversion stream

I'm trying to convert a mp3 into a wave stream using NAudio. Unfortunately I receive the error Not a WAVE file - no RIFF header on the third line when creating the wave reader.
var mp3Reader = new Mp3FileReader(mp3FileLocation);
var pcmStream = WaveFormatConversionStream.CreatePcmStream(mp3Reader);
var waveReader = new WaveFileReader(pcmStream)
Shouldn't these streams work together properly? My goal is to combine several mp3s and wavs into a single stream for both playing and saving to disc( as a wav).
I'm going to preface this with a note that I've never used NAudio. Having said that, there's a guide to concatenating audio on their Github site.
Having looked at the API, you can't use Mp3FileReader directly as it doesn't implement ISampleProvider. However, you can use AudioFileReader instead.
Assuming you have an IEnumerable<string> (aka List or array) of the filenames you want to join named files:
var sampleList = new List<ISampleProvider>();
foreach(string file in files)
{
sampleList.add(new AudioFileReader(file));
}
WaveFileWriter.CreateWaveFile16("outfilenamegoeshere.wav", new ConcatenatingSampleProvider(sampleList));
you don't need the second and third lines. Mp3FileReader will convert to PCM for you and you can play it directly with a player like WaveOutEvent. To actually produce a WAV file on disk, pass it into WaveFileWriter.CreateWaveFile
using(var reader = new Mp3FileReader(mp3FileLocation))
{
WaveFileWriter.CreateWaveFile(reader);
}

How can I read and parse very large flat file using thread in C#?

I have to read a large text file and to parse it line by line using C#. It could be done easily with StreamReader for small sized file but it caught out of memory exception while working with large file. How can I adapt it for large files?
Following code catches OutOfMemoryException :
using (StreamReader reader = new StreamReader(FileNameWithPath))
{
while ((line = reader.ReadLine()) != null)
{
// Do something here...
}
}
That is pretty much the standard code for a lazy line reader, and shouldn't cause an OutOfMemoryException unless there are some really big single lines. You could also try:
foreach(var line in File.ReadLines(FileNameWithPath)) {
// Do something here...
}
which just makes it cleaner, but does the same thing. So there are two options:
one or more of the "lines" is simply huge
something in "Do something here" is slowly (or quickly) eating your memory
I expect the latter is more likley.
I am not sure with this but give try to this class of .net framework
MemoryMappedFile Class-A memory-mapped file maps the contents of a file to an application’s logical address space. Memory-mapped files enable programmers to work with extremely large files because memory can be managed concurrently, and they allow complete, random access to a file without the need for seeking. Memory-mapped files can also be shared across multiple processes.
using (var inputFile = new System.IO.StreamReader(sourceFilePath))
{
while (inputFile.Peek() >= 0) {
string lineData = inputFile.ReadLine();
// Do something with lineData
}
}
How about specify the buffer size ?
like this.
using (var reader = new StreamWriter(path,false,Encoding.UTF8, 1000))
{
.....
}

Categories