NAudio - Can not Replay the played sound - c#

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();
}

Related

How do I record single window audio?

Have been searching info about it on Google, but haven't found neither the way to do this, nor why is it impossible. My aim is to make a C# app, which would record the sound of a single window, while another window can make any kind of noise - the app would save only the sound of the first.
Is there any way to record single window loopback in C#? And does Windows allow it?
I have wrotten code using NAudio that is recording all loopback sound on 1 track. Have a look.
private void btnRec_Click(object sender, RoutedEventArgs e)
{
//Setting up dialog to create WAV file
var destFileDialog = new Microsoft.Win32.SaveFileDialog();
destFileDialog.Filter = "Wave files | *.wav";
destFileDialog.ShowDialog();
destFileName = destFileDialog.FileName;
//Creating capturer and file writer to save captured info
capture = new WasapiLoopbackCapture();
var writer = new WaveFileWriter(destFileName, capture.WaveFormat);
//Setting capturer behaviour
capture.DataAvailable += async (s, a) =>
{
if (writer != null)
{
await writer.WriteAsync(a.Buffer, 0, a.BytesRecorded);
await writer.FlushAsync();
}
};
capture.RecordingStopped += (s, a) =>
{
if (writer != null)
{
writer.Dispose();
writer = null;
}
btnRec.IsEnabled = true;
capture.Dispose();
};
//Disabling button to prevent exception
btnRec.IsEnabled = false;
btnStop.IsEnabled = true;
capture.StartRecording();
}

This code will generate a wav file but does not contain any recording

This code will generate a wav file but does not contain any recording
// Define the output wav file of the recorded audio
string outputFilePath = #"C:\Users\system_recorded_audio.wav";
// Redefine the capturer instance with a new instance of the LoopbackCapture class
WasapiCapture CaptureInstance = new WasapiLoopbackCapture();
// Redefine the audio writer instance with the given configuration
WaveFileWriter RecordedAudioWriter = new WaveFileWriter(outputFilePath, CaptureInstance.WaveFormat);
// When the capturer receives audio, start writing the buffer into the mentioned file
CaptureInstance.DataAvailable += (s, a) =>
{
DelaySeconds(5);
// Write buffer into the file of the writer instance
RecordedAudioWriter.Write(a.Buffer, 0, a.BytesRecorded);
};
DelaySeconds(5);
// When the Capturer Stops, dispose instances of the capturer and writer
CaptureInstance.RecordingStopped += (s, a) =>
{
RecordedAudioWriter.Dispose();
RecordedAudioWriter = null;
CaptureInstance.Dispose();
};
// Start audio recording !
CaptureInstance.StartRecording();
}
public static void DelaySeconds(int iTimeSec)
{
TimeSpan delay = TimeSpan.FromSeconds(iTimeSec);
DateTime start = DateTime.Now;
TimeSpan elapsed = TimeSpan.Zero;
// waits in a while loop while checking the abort or cancel flag
while (elapsed < delay)
{
Thread.Sleep(10);
elapsed = DateTime.Now - start;
}
}

C# Recording Device Audio to Stream then processed by Speech Recognition

I'm trying to capture my computer's audio using NAudio.WasapiLoopbackCapture, then save it to a Wavstream then pipe that into a SpeechRecognitionEngine. I can easily save my loopback audio to a wav/mp3 file. I can easily test a simple voice recognition with SRE. Can I simple chain them together using:
using (WasapiCapture capture = new WasapiLoopbackCapture())
{
audioStream = new MemoryStream();
//create a wavewriter to write the data to
//using (var w = new WaveFileWriter("C:\\users\\matth\\documents\\dump.wav", capture.WaveFormat))
using (var w = new WaveFileWriter(audioStream, capture.WaveFormat))
using (var engine = new SpeechRecognitionEngine())
{
//setup an eventhandler to receive the recorded data
capture.DataAvailable += (s, e) =>
{
//save the recorded audio
w.Write(e.Buffer, 0, e.BytesRecorded);
};
engine.SpeechRecognized += (s, e) =>
{
Console.WriteLine(e.Result.Text);
};
engine.SpeechRecognitionRejected += (s, e) =>
{
Console.WriteLine(e.Result.Text);
};
//start recording
capture.StartRecording();
audioStream.Position = 0;
var g = new DictationGrammar();
engine.LoadGrammar(g);
engine.SetInputToWaveStream(audioStream);
engine.RecognizeAsync(RecognizeMode.Multiple);
Console.ReadKey();
//stop recording
capture.StopRecording();
}
}

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;
}

Play .wav files with Naudio lib

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,

Categories

Resources