Play .wav files with Naudio lib - c#

I try open and play .wav files with NAudio lib.
private OpenFileDialog openFileDialog = null;
private NAudio.Wave.IWavePlayer waveOutDevice;
private NAudio.Wave.BlockAlignReductionStream reductionStream = null;
private NAudio.Wave.BlockAlignReductionStream CreateStream(OpenFileDialog fileDialog)
{
if (fileDialog.FileName.EndsWith(".mp3"))
{
NAudio.Wave.WaveStream pcm = NAudio.Wave.WaveFormatConversionStream.CreatePcmStream(new NAudio.Wave.Mp3FileReader(fileDialog.FileName));
reductionStream = new NAudio.Wave.BlockAlignReductionStream(pcm);
}
else if (fileDialog.FileName.EndsWith(".wav"))
{
NAudio.Wave.WaveStream pcm = new NAudio.Wave.WaveChannel32(new NAudio.Wave.WaveFileReader(openFileDialog.FileName));
reductionStream = new NAudio.Wave.BlockAlignReductionStream(pcm);
}
else
{
throw new InvalidOperationException("Unsupported");
}
return reductionStream;
}
and in play button:
waveOutDevice = new NAudio.Wave.DirectSoundOut();
reductionStream = CreateStream(openFileDialog);
waveOutDevice.Init(reductionStream);
I'm using NAudio 1.5 version. For mp3 files, that play's good. When I select .wav, playing are slowly, and creaking. Maybe something wrong with WaveStream pcm = WaveChannel32?

You don't need to use BlockAlignReductionStream, WaveChannel32 or CreatePcmStream. Just use the Mp3FileReader or WaveFileReader and pass that in to your IWavePlayer,

Related

NAudio - Can not Replay the played sound

Here is my code:
var w = new WaveOut();
var wf = new Mp3FileReader(new MemoryStream(Resources.click));
w.Init(wf);
w.Play();
It will play the audio once, If I Play it again, it will not play it. If I want to make a new Mp3FileReader every time to play the audio, the memory usage of my program will grow more and more.
I just need to use one WaveOut and play the sound in multiple threads as I can. possible?
I have found the solution, we can reset the memory stream position to play the audio again without memory usage:
audio = new Mp3FileReader(new MemoryStream(Resources.click)); // audio is global
player = new WaveOut(); // player is also global
player.Init(audio);
then whenever we need to play the sound we will do this:
audio.Seek(0, SeekOrigin.Begin);
player.Play();
Try wrapping the code in a using block:
using (var stream = new MemoryStream(Resources.click))
{
var wf = new Mp3FileReader(stream);
var w = new WaveOut();
w.Init(wf);
w.Play();
//w.Dispose(); //maybe? maybe not?
}
This will make sure the the object is disposed properly
Edit:
new day new hope!
as described here:
https://csharp.hotexamples.com/de/examples/NAudio.Wave/WaveOut/Play/php-waveout-play-method-examples.html
public void PlaySound(string name, Action done = null)
{
FileStream ms = File.OpenRead(_soundLibrary[name]);
var rdr = new Mp3FileReader(ms);
WaveStream wavStream = WaveFormatConversionStream.CreatePcmStream(rdr);
var baStream = new BlockAlignReductionStream(wavStream);
var waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback());
waveOut.Init(baStream);
waveOut.Play();
var bw = new BackgroundWorker();
bw.DoWork += (s, o) =>
{
while (waveOut.PlaybackState == PlaybackState.Playing)
{
Thread.Sleep(100);
}
waveOut.Dispose();
baStream.Dispose();
wavStream.Dispose();
rdr.Dispose();
ms.Dispose();
if (done != null) done();
};
bw.RunWorkerAsync();
}

WasapiLoopbackCapture.DataAvailable reading silence bytes

I am trying to record the speaker sound to a wave file using NAudio's WasapiLoopbackCapture by writing the stream of bytes available. The WasapiLoopbackCapture.DataAvailable BytesRecorded will be 0 is there is no sound. however in my case i am getting bytecount in BytesRecorded even though the speakers are silent. could you please let me know whats wrong here.
class CallResponse
{
private WaveFileWriter _writer;
private WasapiLoopbackCapture _waveIn;
private string _inFile;
private string _inFileCompressed;
private int _duration;
public bool _isRecording;
public bool _speechDetected;
public CallResponse()
{
_inFile = #"C:\Naresh\test.wav";
_inFileCompressed = #"C:\Naresh\test16Hz.wav";
_waveIn = new WasapiLoopbackCapture();
_waveIn.DataAvailable += (s, e) =>
{
Console.WriteLine(e.BytesRecorded);
_writer.Write(e.Buffer, 0, e.BytesRecorded);
if (_writer.Position > _waveIn.WaveFormat.AverageBytesPerSecond * _duration)
{
Console.Write("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bRecording stopped...");
_waveIn.StopRecording();
}
};
_waveIn.RecordingStopped += (s, e) =>
{
if (_writer != null)
{
_writer.Close();
_writer.Dispose();
_writer = null;
}
Console.Write("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bCompressing Audio...");
using (var reader = new AudioFileReader(_inFile))
{
var resampler = new WdlResamplingSampleProvider(reader, 16000);
WaveFileWriter.CreateWaveFile16(_inFileCompressed, resampler);
}
_isRecording = false;
};
}
public void DisposeObjects()
{
if (_waveIn != null)
{
_waveIn.Dispose();
_waveIn = null;
}
}
public void StartRecording(int duration = 5)
{
_writer = new WaveFileWriter(_inFile, _waveIn.WaveFormat);
this._duration = duration;
_speechDetected = false;
_isRecording = true;
Console.WriteLine("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bRecording....");
_waveIn.StartRecording();
}
}
if something is playing audio, then WasapiLoopbackCapture will capture that audio, even if it contains silence. So there's nothing particularly wrong or surprising that you are getting non-zero BytesRecorded values. In fact, if no applications are sending audio to the device being captured, then what typically happens is that you won't get any DataAvailable callbacks at all.

Convert WasapiLoopbackCapture wav audio stream to MP3 file

I am able to capture system audio which is generated by speaker with the help of WasapiLoopbackCapture (naudio). but the problem is it capture wav file and size of wav file very large (almost 10 to 15 MB/Min). I have to capture 2-3 hour audio and this will be too high.
I m looking for a solution that will convert wav stream which is capture by WasapiLoopbackCapture convert to MP3 and then save this to disk. I try a loat with LAME.exe or other solution but not get success. Any working code.
Here is My Code:
private void button1_Click(object sender, EventArgs e){
LoopbackRecorder obj = new LoopbackRecorder();
string a = textBox1.Text;
obj.StartRecording(#"e:\aman.mp3");
}
public class LoopbackRecorder
{
private IWaveIn _waveIn;
private Mp3WaveFormat _mp3format;
private WaveFormat _wavFormat;
private WaveFileWriter _writer;
private bool _isRecording = false;
/// <summary>
/// Constructor
/// </summary>
public LoopbackRecorder()
{
}
/// <summary>
/// Starts the recording.
/// </summary>
/// <param name="fileName"></param>
public void StartRecording(string fileName)
{
// If we are currently record then go ahead and exit out.
if (_isRecording == true)
{
return;
}
_fileName = fileName;
_waveIn = new WasapiLoopbackCapture();
// _waveIn.WaveFormat = new WaveFormat(16000, 16 , 2);
_writer = new WaveFileWriter(fileName, _waveIn.WaveFormat);
_waveIn.DataAvailable += OnDataAvailable;
// _waveIn.RecordingStopped += OnRecordingStopped;
_waveIn.StartRecording();
_isRecording = true;
}
private void OnDataAvailable(object sender, WaveInEventArgs waveInEventArgs)
{
if (_writer == null)
{
_writer = new WaveFileWriter(#"e:\aman.mp3", _waveIn.WaveFormat);
}
_writer.Write(waveInEventArgs.Buffer, 0, waveInEventArgs.BytesRecorded);
byte[] by= Float32toInt16(waveInEventArgs.Buffer, 0, waveInEventArgs.BytesRecorded);
}
private string _fileName = "";
/// <summary>
/// The name of the file that was set when StartRecording was called. E.g. the current file being written to.
/// </summary>
public string FileName
{
get
{
return _fileName;
}
}
}
Here's an example of using NAudio.Lame (in a console application) to capture data from sound card loopback and write direct to an MP3 file:
using System;
using NAudio.Lame;
using NAudio.Wave;
namespace MP3Rec
{
class Program
{
static LameMP3FileWriter wri;
static bool stopped = false;
static void Main(string[] args)
{
// Start recording from loopback
IWaveIn waveIn = new WasapiLoopbackCapture();
waveIn.DataAvailable += waveIn_DataAvailable;
waveIn.RecordingStopped += waveIn_RecordingStopped;
// Setup MP3 writer to output at 32kbit/sec (~2 minutes per MB)
wri = new LameMP3FileWriter( #"C:\temp\test_output.mp3", waveIn.WaveFormat, 32 );
waveIn.StartRecording();
stopped = false;
// Keep recording until Escape key pressed
while (!stopped)
{
if (Console.KeyAvailable)
{
var key = Console.ReadKey(true);
if (key != null && key.Key == ConsoleKey.Escape)
waveIn.StopRecording();
}
else
System.Threading.Thread.Sleep(50);
}
// flush output to finish MP3 file correctly
wri.Flush();
// Dispose of objects
waveIn.Dispose();
wri.Dispose();
}
static void waveIn_RecordingStopped(object sender, StoppedEventArgs e)
{
// signal that recording has finished
stopped = true;
}
static void waveIn_DataAvailable(object sender, WaveInEventArgs e)
{
// write recorded data to MP3 writer
if (wri != null)
wri.Write(e.Buffer, 0, e.BytesRecorded);
}
}
}
At the moment the NAudio.Lame package on NuGet is compiled for x86 only, so make sure your application is set to target that platform.
To convert the audio to MP3 on the fly, one of the easiest ways is to use the command line options that let you pass audio into LAME.exe via stdin. I describe how to do that in this article.
You may also be interested that Corey Murtagh has created a LAME package for NAudio. I haven't tried it myself, but it looks like it should also do the job. Documentation is here.

AxWindowsMediaPlayer Clip Will Sometimes Not Play

I have a simple one-threaded windows forms .NET 4.5 app where user listens to spoken words (wav files) and then selects the correct picture that represents the word.
The problem is that the clip will sometimes (very rarely - about 1% of the time and completelly at random) not play...
This is the method for playing clips:
public static void PlayWordAudio(Word word, AxWMPLib.AxWindowsMediaPlayer player)
{
string tempFile = Path.GetTempFileName() + ".wav";
MemoryStream stream = new MemoryStream(word.Audio);
using (Stream fileStream = File.OpenWrite(tempFile))
{
stream.WriteTo(fileStream);
}
player.URL = tempFile;
File.Delete(tempFile);
}
Can someone please suggest a solution to this problem? Maybe I shouldn't delete the file at the end of the method? But then temp files would pile up...
I am on Windows 7...
I guess the file is being deleted quicker than it can get played.
Can you try this in stead of File.Delete(tempFile); utilizing the PlayStateChange event
player.PlayStateChange += (snd, psce) => {
switch (psce.newState)
{
case 1: // Stopped (maybe use 12 => Last )
File.Delete(tempFile);
break;
default:
Debug.WriteLine(psce.newState);
break;
}
};
You might have to unsubscribe the event if you keep the player object around a long time.
It seems that I solved the problem... it was in fact the deletion of file that caused this...
solution:
public static void PlayWordAudio(Word word, AxWMPLib.AxWindowsMediaPlayer player)
{
string tempFile = Path.GetTempFileName() + ".wav";
MemoryStream stream = new MemoryStream(word.Audio);
using (Stream fileStream = File.OpenWrite(tempFile))
{
stream.WriteTo(fileStream);
}
player.URL = tempFile;
RunDelayed(5000, File.Delete, tempFile); //if we delete file immediately then clip sometimes would not be played
}
public delegate void DelayedFuncion(string param);
public static void RunDelayed(int delay, DelayedFuncion function, string param = null)
{
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
DelayedArgs args = new DelayedArgs() { delayedFunction = function, param = param };
timer.Tag = args;
timer.Tick += TimerElapsed;
timer.Interval = delay;
timer.Start();
}
private static void TimerElapsed(object sender, EventArgs e)
{
System.Windows.Forms.Timer timer = sender as System.Windows.Forms.Timer;
timer.Stop();
DelayedArgs args = timer.Tag as DelayedArgs;
args.delayedFunction(args.param);
}
class DelayedArgs
{
public Util.DelayedFuncion delayedFunction;
public string param;
}

How to amplify, increase bitrate and Fadin- fadout the recorded audio in Windows Phone 7?

I am facing the following problem regarding to the voice (Audio) recording in windows phone 7.
I am recording the sound using Microphone class available in Microsoft.Xna.Framework.Audio namespace. here is the code -
Variable declaration:
private Microphone mic = Microphone.Default;
private MemoryStream stream;
private const string FILE_NAME = "recording.mp3";
byte[] buffer;
Recording Button click code-
mic.BufferDuration = TimeSpan.FromSeconds(1);
buffer = new byte[mic.GetSampleSizeInBytes(mic.BufferDuration)];
// Create the event handler. I could have done an anonymous
// delegate here if I had so desired.
mic.BufferReady += new EventHandler<EventArgs>(mic_BufferReady);
stream = new MemoryStream();
mic.Start();
Buffer Ready Event code ----------
void mic_BufferReady(object sender, EventArgs e)
{
mic.GetData(buffer);
// Write buffer to stream
stream.Write(buffer, 0, buffer.Length);
}
Button stop code -
private void btnStop_Click(object sender, RoutedEventArgs e)
{
dt.Stop();
btnStop.IsEnabled = false;
btnPlayRecording.IsEnabled = true;
mic.Stop();
//Writing stream into Storage
writeFile(stream);
}
private void writeFile(MemoryStream s, string name)
{
try
{
using (var userStore = IsolatedStorageFile.GetUserStoreForApplication())
{
if (userStore.FileExists(name))
{
userStore.DeleteFile(name);
}
using (var file = userStore.OpenFile(name, FileMode.CreateNew))
{
s.WriteTo(file);
}
}
}
catch (Exception ee)
{
}
}
Once I save the stream into isolated storage and play it back, the volume is very low and the quality is also not good.
So
Can we amplify the Volume ?
can we increase the bitrate ?
Can we do Fadin-Fadout ?
If all these three is not possible in windows phone 7, then is there any third party API available to perform all these operations?
Thanks in advance
Amplification in .NET is not trivial. The best approach I found was to make an external process call to "SoX, the Swiss Army knife of sound processing programs." (http://sox.sourceforge.net/)
I don't have a Windows 7 phone -- so I don't know for sure that SOX runs there.
The format would be SOX -V volume_parameter inputFileName outputFileName for amplification, so:
"sox.exe -v 3.0 myNormalFile.wav myAmpedFile.wav"
would give you an amplification of 300%. Sox also allows for bitrate change... not sure of Fadein/Fadeout.
I don't have anything specifically for Windows 7 phone, but in straight .NET/C# Code:
string finalFileName = "myAmplifiedFile.WAV";
string tmpFileName = "tmpHoldingFile.WAV";
string soxEXE = #"C:\SOX\sox.exe";
string soxArgs = "-v 3.0 ";
/// OTHER STUFF HERE
/*-----------------------------------------------------------
* Call the SOX utility to amplify it so it is 3 times as loud.
*-----------------------------------------------------------*/
try
{
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo = new System.Diagnostics.ProcessStartInfo();
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
process.StartInfo.FileName = soxEXE;
process.StartInfo.Arguments = string.Format("{0} {1} {2}",
soxArgs, tmpFileName, finalFileName);
process.Start();
process.WaitForExit();
int exitCode = process.ExitCode;
}
catch (Exception ex)
{
string err = ex.Message;
return false;
}
/*-------------------------------------------------------------
* OK, now we play it using SoundPlayer
*-------------------------------------------------------------*/
try
{
SoundPlayer simpleSound = new SoundPlayer(#finalFileName);
simpleSound.PlaySync();
FileInfo readFile = new FileInfo(finalFileName);
string finalDestination = finalDirectory + "/" + readFile.Name;
readFile.MoveTo(finalDestination);
}
catch (Exception e)
{
string errmsg = e.Message;
return false;
}
finalFileName = "";
tmpFileName = "";
spVoice = null;

Categories

Resources