How to change .wav format audio file bitrate - c#

In my application I have some .wav format audio files, here I check audio file bit rates by using Naudio dll, if bitrate is below 128kbps then I want to change it to above 128kpbs, so that I wrote below code for check bit rate, if it is less then 128kbps then it convert to above 128kbps.
int bitrate;
using (var reader = new WaveFileReader(textBox1.Text))
{
bitrate = reader.WaveFormat.AverageBytesPerSecond * 8;
reader.Dispose();
}
if (bitrate < 128000)
{
using (var reader = new WaveFileReader(textBox1.Text))
{
var newFormat = new WaveFormat(8000, 16, 1);
using (var conversionStream = new WaveFormatConversionStream(newFormat, reader))
{
WaveFileWriter.CreateWaveFile(#"C:\Docs\Files\", conversionStream);
}
}
}
For some files it is working fine, but for some files I am getting below error,
An unhandled exception of type 'NAudio.MmException' occurred in NAudio.dll
Additional information: AcmNotPossible calling acmStreamOpen
I am attaching error Snap here. Error Error Snap
Here, how can I slove this issue?

I suggest you take a look at FFmpeg. It is what I use for all audio/video conversion tasks.
It is a command-line tool that can convert from pretty much anything to anything, with lots of options. To do what you want, you will probably need to run something like:
$ ffmpeg -i input.wav -ab 128 output.wav
In the above line, we convert the file to a 128 bitrate.
Easiest way to use this in code is to include the FFmpeg executable in your project (or install globally as an environment variable) and invoke it directly with something like:
Process process = new Process();
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.FileName = "ffmpeg";
process.StartInfo.Arguments = $"-i \"{originalFile}\" -ab 128 \"{outputPath}\"";
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = false;
process.Start();
process.WaitForExit();
There are more elegant solutions - wrappers around FFmpeg - but this should do the trick.

WaveFormatConversionStream looks for an ACM codec that can perform the requested transformation. Not every transformation is possible. For example, you can't typically change sample rate, bit depth and channel count in one go. So the possible transformations depend on the exact WaveFormat of the incoming audio. You might need to downsample in one step, and go from stereo to mono in another. The MediaFoundationResampler is more flexible and might be able to do it in one step.

Related

Capture multiline Python output in C#

I am trying to write a piece of C# code which makes use of a small portion of Python code, and then try to output the Python code within my application. The goal is to have a Python RSS, which produces few lines of data and outputs it.
I hoped that a C# code would execute this code and capture all of the lines that are produced, but it captures only first one.
Here is a sample of what python output looks like:
Business Superjumbo jet future secured by Emirates order. A big order from Emirates airline saves the A380 after Airbus threatened to stop making the plane.
Business Banks create funds for firms hit by Carillion collapse. Lloyds and RBS will provide cash for struggling small firms as Nationwide takes on Carillion staff.
Politics Theresa May meets Macron with pledge of extra £44m for border. The UK pledges an extra £44m for channel border security ahead of the Anglo-French summit.
This is a short excerpt of the produced data, but C# ( result variable) only captures first line, sometimes two.
Am I doing something wrong or is not possible to get all prints using this method?
C# code
start.Arguments = "../test/smallWebCrawl.py";
start.UseShellExecute = false;// Do not use OS shell
start.CreateNoWindow = true; // We don't need new window
start.RedirectStandardOutput = true;// Any output, generated by application will be redirected back
start.RedirectStandardError = true; // Any error in standard output will be redirected back (for example exceptions)
try
{
using (Process process = Process.Start(start))
{
using (StreamReader reader = process.StandardOutput)
{
string stderr = process.StandardError.ReadToEnd(); // Here are the exceptions from our Python script
//Console.WriteLine(stderr);
string result = reader.ReadToEnd(); // Here is the result of StdOut(for example: print "test")
Console.WriteLine(result);
}
}
}
catch (Exception)
{
Console.WriteLine("Error. Wrong python path");
}
So I managed to find an alternative solution, which works and which I decided to use, although it is not the best, but I was keen on leaving the overall structure of the code, the way it was.
using (Process process = Process.Start(start))
{
using (StreamReader reader = process.StandardOutput)
{
string stderr = process.StandardError.ReadToEnd();
process.WaitForExit();
string result = reader.ReadToEnd();
string text = File.ReadAllText(start.WorkingDirectory + "\\t.txt");
So basically, I wait for the exit of my Python script to ensure that all data has been written to a file, then read the whole produced text file, which can be later deleted.

Microsoft SpeechSynthesizer crackles when outputting to files and streams

I'm writing a thing that uses the SpeechSynthesizer to generate wave files on request, but I'm having problems with crackling noises. The weird thing is that output directly to the sound card is just fine.
This short powershell script demonstrates the issue, though I'm writing my program in C#.
Add-Type -AssemblyName System.Speech
$speech = New-Object System.Speech.Synthesis.SpeechSynthesizer
$speech.Speak('Guybrush Threepwood, mighty pirate!')
$speech.SetOutputToWaveFile("${PSScriptRoot}\foo.wav")
$speech.Speak('Guybrush Threepwood, mighty pirate!')
What this should do, is output to the speakers, and then save that same sound as "foo.wav" next to the script.
What it does is output to the speakers, and then save a crackling, old record player sounding version as a wave file. I've tested this on three different machines, and though they select different voices by default (all Microsoft provided default ones), they all sound like garbage falling down stairs in the wave file.
Why?
EDIT: I am testing this on Windows 10 Pro, with the latest updates that add that annoying "People" button on the taskbar.
EDIT 2: Here's a link to an example sound generated with the above script. Notice the crackling voice, that's not there when the script outputs directly to the speakers.
EDIT 3: It's even more noticeable with a female voice
EDIT 4: The same voice as above, saved to file with TextAloud 3 - no cracking, no vertical spikes.
I find it hard to believe this is a PoSH issue.
It's not PoSH doing the encoding on the serialization to disk. Its the API/Class that is being used.
'msdn.microsoft.com/en-us/library/system.speech.synthesis.speechsynthesizer(v=vs.110).aspx'
As per the MSDN, there is no option to control the encoding, bit rate, etc.
.wav has never been HQ stuff. So, I'd wonder if you take that .wav through a converter to make it an .mp3 or mp4, if that would correct your quality concerns. But that also means getting the converter on users systems.
Secondly, since Win8, the default player does not even play .wav correctly or at all. Sure, you can still set the default play of .wav to Windows Media Player or call the file via VLC, but it's still a .wav file. Yet, that also means, you having to set the Media Player assignment on every target system.
This is an issue with the SpeechSynthesizer API, which simply provides bad quality, crackling audio as seen in the samples above. The solution is to do what TextAloud does, which is to use the SpeechLib COM objects directly.
This is done by adding a COM reference to "Microsoft Speech Object Library (5.4)". Here is a snippet of the code I ended up with, which produces audio clips of the same quality as TextAloud:
public new static byte[] GetSound(Order o)
{
const SpeechVoiceSpeakFlags speechFlags = SpeechVoiceSpeakFlags.SVSFlagsAsync;
var synth = new SpVoice();
var wave = new SpMemoryStream();
var voices = synth.GetVoices();
try
{
// synth setup
synth.Volume = Math.Max(1, Math.Min(100, o.Volume ?? 100));
synth.Rate = Math.Max(-10, Math.Min(10, o.Rate ?? 0));
foreach (SpObjectToken voice in voices)
{
if (voice.GetAttribute("Name") == o.Voice.Name)
{
synth.Voice = voice;
}
}
wave.Format.Type = SpeechAudioFormatType.SAFT22kHz16BitMono;
synth.AudioOutputStream = wave;
synth.Speak(o.Text, speechFlags);
synth.WaitUntilDone(Timeout.Infinite);
var waveFormat = new WaveFormat(22050, 16, 1);
using (var ms = new MemoryStream((byte[])wave.GetData()))
using (var reader = new RawSourceWaveStream(ms, waveFormat))
using (var outStream = new MemoryStream())
using (var writer = new WaveFileWriter(outStream, waveFormat))
{
reader.CopyTo(writer);
return o.Mp3 ? ConvertToMp3(outStream) : outStream.GetBuffer();
}
}
finally
{
Marshal.ReleaseComObject(voices);
Marshal.ReleaseComObject(wave);
Marshal.ReleaseComObject(synth);
}
}
This is the code to convert a wave file to mp3. It uses NAudio.Lame from nuget.
internal static byte[] ConvertToMp3(Stream wave)
{
wave.Position = 0;
using (var mp3 = new MemoryStream())
using (var reader = new WaveFileReader(wave))
using (var writer = new LameMP3FileWriter(mp3, reader.WaveFormat, 128))
{
reader.CopyTo(writer);
mp3.Position = 0;
return mp3.ToArray();
}
}

PDF or Other "report viewer" options for Asp.net C#

I'm in a bind with my current project. It's a payroll application and I'm developing in ASP.net webforms with C#. My boss said that the ideal function of this site is to click on the pay check date, and a PDF opens and shows the paycheck information. I have done research for a few days to try to find the best solution. So far, I have had no luck. I have found a few different things such as iTextSharp but the license for one year is too expensive right now. I have also seen the tcpdf which is php based. I have also looked into CrystalReports, and Active Reports. To purchase the license is too expensive as well. I have looked into XML to PDF solutions also but I'm not finding anything definite. Since I'm pretty new to the business world of software development and don't have senior developers to rely on, I'm pretty much dead in the water. I know we will be downloading the paychecks into a CSV file from a DOS based application that does our clock-ins and outs. I will then be importing the CSV files into SQL Server 2012 Express. Your ideas are greatly appreciated as I don't know where to go from here! Thank you in advance!
A HTML to PDF converter that I've recently discovered is WKHTMLtoPDF
It's open source and uses WebKit to convert HTML to PDF so it's pretty standards compliant.
An example of how you might use it is
using (var pdfStream = new FileStream(dlg.FileName, FileMode.OpenOrCreate))
{
// pass in the HTML you want to appear in the PDF, and the file stream it writes to
Printer.GeneratePdf(htmlStream, pdfStream);
}
where GeneratePdf is defined as
public static void GeneratePdf(Stream html, Stream pdf)
{
Process process;
StreamWriter stdin;
var psi = new ProcessStartInfo();
psi.FileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + #"\Lib", "wkhtmltopdf.exe");
psi.WorkingDirectory = Path.GetDirectoryName(psi.FileName);
// run the conversion utility
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.Arguments = "-q -n --disable-smart-shrinking - -";
process = Process.Start(psi);
try
{
stdin = process.StandardInput;
stdin.AutoFlush = true;
//stdin.Write(html.ReadToEnd());
stdin.Write(new StreamReader(html).ReadToEnd());
stdin.Dispose();
process.StandardOutput.BaseStream.CopyTo(pdf);
process.StandardOutput.Close();
pdf.Position = 0;
process.WaitForExit(10000);
}
catch (Exception ex)
{
throw ex;
}
finally
{
process.Dispose();
}
}
In your case, instead of writing it to a file stream, you'd write it to the HTTP output stream as a PDF.
Please note however, that this example is more suitable to writing PDF files to disk, rather than the output stream so you'd need to do it differently slightly for it to work for you.
I also agree that html -> pdf is the best option nowadays if you want to render complex report and stay productive.
I have implemented a wrapper for html -> pdf conversion called jsreport.
If you are using asp.net mvc, you can check out my post Rendering pdf from Asp.Net MVC views or more generic post Pdf reports in c#.
Disclaimer: I am the author of jsreport

C# System.Diagnostics.Process redirecting Standard Out for large amounts of data

I running an exe from a .NET app and trying to redirect standard out to a streamreader. The problem is that when I do
myprocess.exe >> out.txt
out.txt is close to 14mb.
When I do the command line version it is very fast but when I run the process from my csharp app it is excruciatingly slow because I believe the default streamreader flushes every 4096 bytes.
Is there a way to change the default stream reader for the Process object?
I haven't tried, but it looks like the asynchronous methods may offer better performance. Instead of using process.StandardOutput, try this method instead:
Process process = Process
.Start(new ProcessStartInfo("a.exe"){RedirectStandardOutput = true});
if (process != null)
{
process.OutputDataReceived += ((sender, e) =>
{
string consoleLine = e.Data;
//handle data
});
process.BeginOutputReadLine();
}
Edit: Just realized I'm answering the wrong question. In my case the stdout buffer was full and WaitForExit() was blocking forever, because nothing was reading from the buffer yet. So if you have THAT problem, then here's a solution. ;)
This is my first day with C# so please understand that this might not be the best solution, and might not always work. But it works in the 2x I've tested it. ;) This is synchronous, just start start writing the redirected stdout/stderr to the file before you WaitForExit(). This way WaitForExit() won't block waiting for the stdout buffer to be emptied.
string str_MyProg = "my.exe";
string str_CommandArgs = " arg1 arg2"'
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo(str_MyProg, str_CommandArgs);
procStartInfo.RedirectStandardError = true;
procStartInfo.RedirectStandardOutput = true; // Set true to redirect the process stdout to the Process.StandardOutput StreamReader
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true; // Do not create the black window
// Create a process, assign its ProcessStartInfo and start it
System.Diagnostics.Process myProcess = new System.Diagnostics.Process();
myProcess.StartInfo = procStartInfo;
myProcess.Start();
// Dump the output to the log file
string stdOut = myProcess.StandardOutput.ReadToEnd();
StreamWriter logFile = new StreamWriter("output.txt" );
logFile.Write(stdOut);
logFile.Close();
myProcess.WaitForExit();
Yes, that's about right. There is a buffer that stores the process output, usually between 1 and 4KB in the common CRT implementations. One small detail: that buffer is located in the process you start, not the .NET program.
Nothing very special needs to happen when you redirect to a file, the CRT directly writes it. But if you redirect to your .NET program then output goes from the buffer into a pipe. Which then takes a thread switch to your program so you can empty the pipe. Back and forth a good 700 times.
Yes, not fast. Easily fixed though, call setvbuf() in the program you are running to increase the stdout and stderr output buffer sizes. Then again, that takes having the source code of that program.
Anticipating a problem with that: maybe you ought to use cmd.exe /c to get the redirection to a file, then read the file.
The Process class exposes the stdout stream directly, so you should be able to read it at whatever pace you like. It's probably best to read it in small chunks and avoid calling ReadToEnd.
For example:
using(StreamReader sr = new StreamReader(myProcess.StandardOutput))
{
string line;
while((line = sr.ReadLine()) != null)
{
// do something with line
}
}
This worked out for me:
var sb = new StringBuilder();
while (!proc.StandardOutput.EndOfStream)
{
sb.Append(proc.StandardOutput.ReadToEnd());
proc.StandardOutput.DiscardBufferedData();
}

How to get the length of a MP3 in C#

Yes this is an exact duplicate of this question, but the link given and accepted as answer is not working for me. It is returning incorrect values (a 2 minutes mp3 will be listed as 1'30, 3 minutes as 2'20) with no obvious pattern.
So here it is again: how can I get the length of a MP3 using C# ?
or
What am I doing wrong with the MP3Header class:
MP3Header mp3hdr = new MP3Header();
bool boolIsMP3 = mp3hdr.ReadMP3Information("1.mp3");
if(boolIsMP3)
Response.Write(mp3hdr.intLength);
Apparently this class computes the duration using fileSize / bitRate. This can only work for constant bitrate, and I assume your MP3 has variable bitRate...
EDIT : have a look at TagLib Sharp, it can give you the duration
How have you ascertained the lengths of the MP3s which are "wrong"? I've often found that the header information can be wrong: there was a particular version of LAME which had this problem, for example.
If you bring the file's properties up in Windows Explorer, what does that show?
I wrapped mp3 decoder library and made it available for .net developers. You can find it here:
http://sourceforge.net/projects/mpg123net/
Included are the samples to convert mp3 file to PCM, and read ID3 tags.
I guess that you can use it to read mp3 file duration. Worst case will be that you read all the frames and compute the duration - VBR file.
To accurately determine mp3 duration, you HAVE TO read all the frames and calculate duration from their summed duration. There are lots of cases when people put various 'metadata' inside mp3 files, so if you estimate from bitrate and file size, you'll guess wrong.
I would consider using an external application to do this. Consider trying Sox and just run the version of the program that's executed by using soxi (no exe) and try parsing that output. Given your options I think you're better off just trusting someone else who has spent the time to work out all the weirdness in mp3 files unless this functionality is core to what you're doing. Good luck!
The second post in the thread might help you: http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/c72033c2-c392-4e0e-9993-1f8991acb2fd
Length of the VBR file CAN'T be estimated at all. Every mp3 frame inside of it could have different bitrate, so from reading any part of the file you can't know what density of the data is at any other part of the file. Only way of determining EXACT length of VBR mp3 is to DECODE it in whole, OR (if you know how) read all the headers of the frames one by one, and collect their decoded DURATION.
You will use later method only if the CPU that you use is a precious resource that you need to save. Otherwise, decode the whole file and you'll have the duration.
You can use my port of mpg123 to do the job: http://sourceforge.net/projects/mpg123net/
More: many mp3 files have "stuff" added to it, as a id3 tags, and if you don't go through all the file you could mistakenly use that tag in duration calculation.
There is my solution for C# with sox sound processing library.
public static double GetAudioDuration(string soxPath, string audioPath)
{
double duration = 0;
var startInfo = new ProcessStartInfo(soxPath,
string.Format("\"{0}\" -n stat", audioPath));
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardOutput = true;
var process = Process.Start(startInfo);
process.WaitForExit();
string str;
using (var outputThread = process.StandardError)
str = outputThread.ReadToEnd();
if (string.IsNullOrEmpty(str))
using (var outputThread = process.StandardOutput)
str = outputThread.ReadToEnd();
try
{
string[] lines = str.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
string lengthLine = lines.First(line => line.Contains("Length (seconds)"));
duration = double.Parse(lengthLine.Split(':')[1]);
}
catch (Exception ex)
{
}
return duration;
}

Categories