NAudio Plot waveform while recording in WaveViewer control - naudio

Can we use waveViever to plot waveform while recording?
private NAudio.Wave.WaveIn wi = null;
int waveInDevices = NAudio.Wave.WaveIn.DeviceCount;
WaveFileWriter waveWriter = null;
SaveFileDialog save;
private void button2_Click(object sender, EventArgs e)
{
save = new SaveFileDialog();
save.Filter = "Wave File (*.wav)|*.wav;";
if (save.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
int deviceNumber = 0;
wi = new WaveIn();
wi.DeviceNumber = deviceNumber;
wi.WaveFormat = new WaveFormat(44100, WaveIn.GetCapabilities(deviceNumber).Channels);
wi.DataAvailable += new EventHandler<WaveInEventArgs>(wi_DataAvailable);
waveWriter = new NAudio.Wave.WaveFileWriter(save.FileName, wi.WaveFormat);
wi.StartRecording();
timer1.Start();
}
private void wi_DataAvailable(object sender, WaveInEventArgs e)
{
if (waveWriter == null) return;
waveWriter.WriteData(e.Buffer, 0, e.BytesRecorded);
waveWriter.Flush();
}
private void timer1_Tick(object sender, EventArgs e)
{
waveViewer1.WaveStream = new WaveFileReader(save.Filename);
}
I am using that code statement to record file and want to read file every tick interval of timer and plot waveform in waveViewer.However it gives an error that "File is in use by another process". Is there anyway to do this. Should i use first overload of WaveFileReader(Stream streamInput)? If yes, please can you give an example about first overload.

I wouldn't recommend trying to use waveViewer, although you could take a copy of the code and use it as a basis. If you look at the WPF demo code in the NAudio repository, it supports drawing the waveform while you are recording.
The basic principle is every time the DataAvailable event fires, calculate the max peaks of the recorded audio and add that to your waveform display.

Related

C# Audio File is played in a loop although it is stopped

I have an older implementation using NAudio 1.6 to play a ring tone signalling an incoming call in an application. As soon as the user acceptes the call, I stop the playback.
Basically the follwing is done:
1. As soon as the I get an event that a call must be signalled, a timer is started
2. Inside this timer Play() on the player
3. When the timer starts again, a check is performed if the file is played by checking the CurrentTime property against the TotalTime propery of the WaveStream
4. When the user accepts the call, Stop() is called on the player and also stop the timer
The point is, that we run sometimes in cases where the playback is still repeated although the timer is stopped and the Stop() was called on the player.
In the following link I read that the classes BufferedWaveProvider and WaveChannel32 which are used in the code are always padding the buffer with zero.
http://mark-dot-net.blogspot.com/2011/05/naudio-and-playbackstopped-problem.html
Is it possible that the non-stopping playback is due to usage of the classes BufferedWaveProvider and WaveChannel32?
In NAudio 1.7 the AudioFileReader class is there. Is this class also padding with zeros? I did not find a property like PadWithZeroes in this class. Does it make to use AudioFileReader in this case of looped playback?
Below the code of the current implementation of the TimerElapsed
void TimerElapsed(object sender, ElapsedEventArgs e)
{
try
{
WaveStream stream = _audioStream as WaveStream;
if (stream != null && stream.CurrentTime >= stream.TotalTime )
{
StartPlayback();
}
}
catch (Exception ex)
{
//do some actions here
}
}
The following code creates the input stream:
private WaveStream CreateWavInputStream(string path)
{
WaveStream readerStream = new WaveFileReader(path);
if (readerStream.WaveFormat.Encoding != WaveFormatEncoding.Pcm)
{
readerStream = WaveFormatConversionStream.CreatePcmStream(readerStream);
readerStream = new BlockAlignReductionStream(readerStream);
}
if (readerStream.WaveFormat.BitsPerSample != 16)
{
var format = new WaveFormat(readerStream.WaveFormat.SampleRate, 16, readerStream.WaveFormat.Channels);
readerStream = new WaveFormatConversionStream(format, readerStream);
}
WaveChannel32 inputStream = new WaveChannel32(readerStream);
return inputStream;
}

Manipulation events of MediaElement not fire when on FullWindows mode

When I set player not in fullscreen (player.IsFullWindows = false), event work normally but when change player to full screen all manipulation event not work. Anyone have solution?
<MediaElement Name="player"
Margin="10,5" ManipulationCompleted="player_ManipulationCompleted"
ManipulationDelta="Grid_ManipulationDelta"
ManipulationMode="TranslateX"
>
I can reproduce this scenario by enabling both the IsFullWindow="True" and the AreTransportControlsEnabled="True". I think it makes sense, because when we are in the Full Window mode, it will go to the new layer named FullWindowMediaRoot instead of the MediaElement. Inside the FullWindowMediaRoot, it is the MediaTransportControls. You can see that clearly by using the Live Visual Tree as following:
So when we are in the Full Window mode, we need to handle the manipulation event of the TransportControls instead of the manipulation event of the MediaElement as following:
public MainPage()
{
this.InitializeComponent();
player.TransportControls.ManipulationMode = ManipulationModes.TranslateX;
player.TransportControls.ManipulationDelta += TransportControls_ManipulationDelta;
player.TransportControls.ManipulationCompleted += TransportControls_ManipulationCompleted;
}
private void TransportControls_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
{
}
private void TransportControls_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
}
Thanks.

How to return data from a BackgroundWorker in c++?

I've got a BackgroundWorker continually reading data from a USB device. I want to parse that data, then feed it back to my main GUI thread to update a plot and save it to a file.
I suspect the way to do this is using ReportProgress, but I'm not sure how to pass an object as required.
Here's a snippet of what I'm trying to do:
class Datapacket
{
public:
int Val1;
double Val2;
}
backgroundWorker_DoWork(Object^ sender,DoWorkEventArgs^ e)
{
// readUSB
.........
// create Datapacket with values from usb stream:
Datapacket dp;
dp.Val1 = 5;
dp.Val2 = 34.6;
backgroundWorker->ReportProgress(0, dp); // this bit fails to compile
}
backgroundWorker_ProgressChanged(Object^ sender, ProgressChangedEventArgs^ e)
{
Datapacket dp = e.dp ??????
// update gui, etc
textBox_Data->Text = dp.Val1.ToString();
}
I usually use c#, so diving into this in C++ is a minor headache as it is!
You're near. Datapacket is not a .NET reference type (class) and I'd assume you do not want to dispose it when it's out of scope. Change it to ref class and just add ^ in your backgroundWorker_DoWork (and change . with -> where appropriate):
backgroundWorker_DoWork(Object^ sender,DoWorkEventArgs^ e)
{
Datapacket^ dp = gcnew Datapacket();
dp->Val1 = 5;
dp->Val2 = 34.6;
backgroundWorker->ReportProgress(0, dp);
}
In your event handler you just need to cast UserState property to original type (and change . with -> where appropriate):
backgroundWorker_ProgressChanged(Object^ sender, ProgressChangedEventArgs^ e)
{
Datapacket^ dp = dynamic_cast<Datapacket^>(e->UserState);
// update gui, etc
textBox_Data->Text = dp->Val1.ToString();
}
Do not forget to set WorkerReportsProgress to true.

Auto Repeat a MediaElement

I'm trying to auto repeat a MediaElement. I did that using the following code:
<MediaElement Name="MainMedia" MediaEnded="MainMedia_MediaEnded_1" />
private void MainMedia_MediaEnded_1(object sender, RoutedEventArgs e)
{
MainMedia.Position = TimeSpan.FromSeconds(0);
MainMedia.Play();
}
But I was wondering if there is any better solution.
There is a property called IsLooping. If you set that to true it will auto repeat the media.

Unable to play sound in Windows 8

I want to play sound from a mp3 file in windows 8 metro-style app. I tried two approaches to do so:
Method1:
This is using the code provided by https://stackoverflow.com/a/10961201/147530. It works.
Method 2:
Here I just new a MediaElement and set its Source property like so:
var x = new MediaElement { Source = new Uri("ms-appx:/Assets/MyMp3File.mp3") };
When I do x.Play() nothing happens however. There are no exceptions thrown.
Question: How can I make method 2 work?
EDIT:
Wanted to update that none of the MediaFailed, MediaOpened, MediaEnded event handlers get called using Method 2.
sound = new MediaElement { Source = new Uri("ms-appx:/Assets/Clook.mp3") };
sound.MediaFailed += sound_MediaFailed;
sound.MediaOpened += sound_MediaOpened;
sound.MediaEnded += sound_MediaEnded;
static void sound_MediaEnded(object sender, RoutedEventArgs e)
{
Debugger.Break();
}
static void sound_MediaOpened(object sender, RoutedEventArgs e)
{
Debugger.Break();
}
static void sound_MediaFailed(object sender, ExceptionRoutedEventArgs e)
{
Debugger.Break();
}
A couple of things to try. Try the following code
var music = new MediaElement()
{
AudioCategory = AudioCategory.ForegroundOnlyMedia,
Source = new Uri(this.BaseUri, "Assets/MyMp3File.mp3")
};
// This is really the only difference, adding it to the visual tree
// LayoutRoot is the root of the visual tree, in the case, a grid in my XAML
LayoutRoot.Children.Add(music);
music.Play();
Adding it to the visual tree may be the key. Put a break point on that to make sure your MediaElement has data in it.
Second (and actually happened to me so, that's why I mention it), I was developing on a Samsung device from //Build that has a docking station. The audio jack on the device and the speakers are disabled when it is in the docking station. You have to plug a headset into the docking station directly or remove it from the docking station to hear any sound.
You have to put the MediaElement in the visualTree before to make it play any media :)
Use x.autoplay = true. With autoplay it will wait until it's loaded.