Oct 19, 2012 at 6:48 PM
Edited Oct 19, 2012 at 6:49 PM
|
Hi Mark,
I just wanted to say thanks again for sharing NAudio. I'm new to programming, and I'm doing it as a hobby, and to learn some stuff. I really don't know that much about c# yet, but I do see that it's similar to visual basic.
From studying the demo you have, and looking at the tutorials that giawa has, I've managed to put together a test using VB.net
I can open, and play a wav file, and select my asio driver. I'm using a Lynx Studio AES 16 sound card (buffer is set 512).
When I hit stop, it stutters for a few ms. I know I'm missing something, but I can't figure out what. Am I not disposing the asio driver correctly?
Any help would greatly be appreciated.
Many Thanks, Wyatt
Here's my code:
Imports NAudio.Wave
Public Class Form1
Private wave As NAudio.Wave.WaveFileReader = Nothing
Private output As NAudio.Wave.AsioOut = Nothing
Public Sub New()
InitializeComponent()
InitialiseAsioControls()
End Sub
Public ReadOnly Property SelectedDeviceName() As String
Get
Return CStr(comboBoxAsioDriver.SelectedItem)
End Get
End Property
Private Sub InitialiseAsioControls()
' Just fill the comboBox AsioDriver with available driver names
Dim asioDriverNames = AsioOut.GetDriverNames()
For Each driverName As String In asioDriverNames
comboBoxAsioDriver.Items.Add(driverName)
Next driverName
comboBoxAsioDriver.SelectedIndex = 0
End Sub
Private Sub btnOpen_Click(sender As System.Object, e As System.EventArgs) Handles btnOpen.Click
Dim wavFile As String
OpenWavFile.InitialDirectory = ""
wavFile = OpenWavFile.ShowDialog()
wavFile = OpenWavFile.FileName
Label1.Text = wavFile
End Sub
Private Sub btnPlay_Click(sender As System.Object, e As System.EventArgs) Handles btnPlay.Click
If Label1.Text = Nothing Then
Dim wavFile As String
OpenWavFile.InitialDirectory = ""
wavFile = OpenWavFile.ShowDialog()
wavFile = OpenWavFile.FileName
Label1.Text = wavFile
Else
wave = New NAudio.Wave.WaveFileReader(Label1.Text)
output = New AsioOut(comboBoxAsioDriver.Text)
output.Init(New NAudio.Wave.WaveChannel32(wave))
output.Play()
btnPlay.Enabled = False
End If
End Sub
Private Sub DisposeWave()
If output IsNot Nothing Then
If output.PlaybackState = NAudio.Wave.PlaybackState.Playing Then
output.Stop()
End If
output.Dispose()
output = Nothing
End If
If wave IsNot Nothing Then
wave.Dispose()
wave = Nothing
End If
End Sub
Private Sub btnStop_Click(sender As System.Object, e As System.EventArgs) Handles btnStop.Click
DisposeWave()
btnPlay.Enabled = True
End Sub
End Class
|
|
|
Coordinator
Oct 19, 2012 at 7:50 PM
|
don't Dispose straight away after stop. Call output.Stop(), and then in the handler for PlaybackStopped, then you can Dispose the device. Also, please make sure you are using the very latest NAudio (there is a pre-release build up on NuGet)
|
|
|
|
|
Thanks for the quick reply. Sorry for being a noob.
Could you give me an example in the test code I have above, or do you mean where I have btnStop
add output.stop() first? I tried this, and it still stutters. I'm still not understanding something.
Private Sub DisposeWave()
If output IsNot Nothing Then
If output.PlaybackState = NAudio.Wave.PlaybackState.Playing Then
output.Stop()
End If
output.Dispose()
output = Nothing
End If
If wave IsNot Nothing Then
wave.Dispose()
wave = Nothing
End If
End Sub
Private Sub btnStop_Click(sender As System.Object, e As System.EventArgs) Handles btnStop.Click
output.Stop()
DisposeWave()
btnPlay.Enabled = True
End Sub
|
|
|
Coordinator
Oct 19, 2012 at 9:19 PM
|
get rid of the call to output.Dispose(). The ASIO driver is not ready for it yet.
Instead, subscribe to output.PlaybackStopped event. Then in there, call output.Dispose().
Alternatively, only Dispose the device when you press play again or close your form
|
|
|
|
|
Thanks again Mark.
In the code above, I got rid of output.Dispose()
I still don't understand "Instead, subscribe to output.PlaybackStopped event."
|
|
|
|
|
In addition to what Mark said, I think you will need to keep a reference to the WaveChannel32 object, so you can set .PadWithZeros , which enables the PlaybackStopped event.
Something like this:
Private WithEvents output As NAudio.Wave.AsioOut = Nothing
Private mainOutputStream As WaveChannel32
...
mainOutputStream = New WaveChannel32(wave) ' tie the file reader to the output stream
mainOutputStream.PadWithZeroes = False ' need this to detect eof
output.Init(mainOutputStream) ' tie output stream to output device
...
Private Sub PlaybackStopped(sender As Object, e As System.EventArgs) Handles output.PlaybackStopped
' dispose
End Sub
|
|
|
|
|
Thanks again for your help Mark, and eejake52.
Looks like I need to start over, or something. I never did get it to work right. No matter what I've tried, it still stutters when I hit the stop button.
I'll still keep trying.
Thanks, Wyatt
|
|
|
Coordinator
Oct 21, 2012 at 4:21 PM
|
If you use the NAudioDemo application, can you play and stop ASIO without it stuttering?
|
|
|
Oct 22, 2012 at 9:46 PM
Edited Oct 22, 2012 at 9:50 PM
|
Hi Mark.
Yes, when I load the demo "AsioDirectDemo" and stop, there is no stutter. I used the code from that demo in a new test. and converted that into vb.net, but it stutters.
Sorry again for be such a noob at this. Maybe it's something I'm not converting right?
Here's the converted code from that panel. I put the panel controls on a form, and used the converted code:
Imports NAudio.Wave
Public Class Form1
Private reader As WaveFileReader
Private asioOut As AsioOut
Public Sub New()
InitializeComponent()
AddHandler Disposed, AddressOf AsioDirectPanel_Disposed
For Each device In AsioOut.GetDriverNames()
Me.comboBoxAsioDevice.Items.Add(device)
Next device
If Me.comboBoxAsioDevice.Items.Count > 0 Then
Me.comboBoxAsioDevice.SelectedIndex = 0
End If
End Sub
Private Sub AsioDirectPanel_Disposed(ByVal sender As Object, ByVal e As EventArgs)
Cleanup()
End Sub
Private Sub Cleanup()
If Me.asioOut IsNot Nothing Then
Me.asioOut.Dispose()
Me.asioOut = Nothing
End If
If Me.reader IsNot Nothing Then
Me.reader.Dispose()
Me.reader = Nothing
End If
End Sub
Private Sub buttonSelectFile_Click_1(sender As System.Object, e As System.EventArgs) Handles buttonSelectFile.Click
Cleanup()
Dim ofd As New OpenFileDialog()
ofd.Filter = "WAV files|*.wav"
If ofd.ShowDialog() = DialogResult.OK Then
Me.reader = New WaveFileReader(ofd.FileName)
End If
End Sub
Private Sub buttonPlay_Click(ByVal sender As Object, ByVal args As EventArgs) Handles buttonPlay.Click
Try
Play()
Catch e As Exception
MessageBox.Show(e.Message)
End Try
End Sub
Private Function GetUserSpecifiedChannelOffset() As Integer
Dim channelOffset As Integer = 0
Integer.TryParse(textBoxChannelOffset.Text, channelOffset)
Return channelOffset
End Function
Private Sub Play()
' allow change device
If Me.asioOut IsNot Nothing AndAlso (Me.asioOut.DriverName <> comboBoxAsioDevice.Text OrElse Me.asioOut.ChannelOffset <> GetUserSpecifiedChannelOffset()) Then
Me.asioOut.Dispose()
Me.asioOut = Nothing
End If
' create device if necessary
If Me.asioOut Is Nothing Then
Me.asioOut = New AsioOut(comboBoxAsioDevice.Text)
Me.asioOut.ChannelOffset = GetUserSpecifiedChannelOffset()
Me.asioOut.Init(Me.reader)
End If
Me.reader.Position = 0
Me.asioOut.Play()
Me.Timer1.Enabled = True
SetButtonStates()
End Sub
Private Sub SetButtonStates()
buttonPlay.Enabled = asioOut IsNot Nothing AndAlso asioOut.PlaybackState <> PlaybackState.Playing
buttonStop.Enabled = asioOut IsNot Nothing AndAlso asioOut.PlaybackState = PlaybackState.Playing
End Sub
Private Sub buttonStop_Click(ByVal sender As Object, ByVal e As EventArgs) Handles buttonStop.Click
Me.Stop()
End Sub
Private Sub [Stop]()
Me.asioOut.Stop()
Me.Timer1.Enabled = False
SetButtonStates()
End Sub
Private Sub timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles Timer1.Tick
If asioOut IsNot Nothing AndAlso asioOut.PlaybackState = PlaybackState.Playing AndAlso reader.Position >= reader.Length Then
Me.Stop()
End If
End Sub
End Class
|
|
|
Coordinator
Oct 23, 2012 at 6:23 AM
|
that's strange. I'm not a VB.NET developer but I cans see anything obviously wrong there. Could it be the garbage collector kicking in? ASIO works at a very low latency, and so if the garbage collector kicks in at an inopportune moment, it can cause stuttering
and there is nothing much that can be done about it.
|
|
|
|
|
Hi Mark.
Thanks again for your patience on this.
I don't think that's the problem. I wish I had an example of just the Asio Direct Playback on a windows form. I'm having trouble with the panel.
I tried to do this on a windows form in c# (basically I copied and pasted the demo code), and it builds ok, and it works, but still stutters on stop.
This has me thinking that I'm definitely doing something wrong when I can build, and play the demo that you have with no stuttering, but when I use the same code on a form instead of a panel, it does. Hope this make sense.
Anyway, here's a link to my solution file. If you have a chance, could you take a look at it?
Thanks, Wyatt
|
|
|
Coordinator
Oct 24, 2012 at 6:14 AM
|
Hi Wyatt,
I've tried your app and I can hear the "stutter" you refer to. There is also some noise when I start playing again. But the same effect is in the NAudioDemo app for me, so its clearly nothing you are doing wrong. I guess there may be a bug in the way the
ASIO stop code is working and perhaps some uninitialised buffers get to play out. I'll see if I can find some time to investigate.
Mark
|
|
|
|
|
Thanks Mark.
I just checked the new version of NAudio from the source in which you guys were having a discussion on "Noise in playback start" It seems to be working correctly now. There's no stuttering now, and I also tested it out in the VB test project I had started,
and it's working as well.
Thanks, Wyatt
|
|
|
|
|
Edit:
I just checked again. It still stutters when I'm in visual studio, and build, and playback from there. When I close visual studio, and goto my bin debug folder, and open the app from there, it doesn't stutter.
|
|
|
Coordinator
Oct 24, 2012 at 4:33 PM
|
the fix I made shouldn't affect anything to do with stopping. It was fixing a problem where you heard a bit of leftover MP3 from within the decoders buffer when you started playing again. The stutter is a strange one, and might still be related to garbage
collections. The ASIO API is pretty simple - you just call driver.Stop(), so it's hard to think what else could be done to fix the problem.
|
|