Hallo,
ich hab mal wieder ne Frage:
Wenn ich eine Aktion ausführe und sich der GUI-Thread kurz aufhängt, bleibt ebenfalls der Track von NAudio stehen. Bei Bass.Net ist dies nicht so. Gibt es irgendeine Möglichkeit, das zu verhindern? Kann man den Track in einem extra Thread ausführen?
Hier mein Code:
Spoiler anzeigen
Danke für eure Antworten
ich hab mal wieder ne Frage:
Wenn ich eine Aktion ausführe und sich der GUI-Thread kurz aufhängt, bleibt ebenfalls der Track von NAudio stehen. Bei Bass.Net ist dies nicht so. Gibt es irgendeine Möglichkeit, das zu verhindern? Kann man den Track in einem extra Thread ausführen?
Hier mein Code:
VB.NET-Quellcode
- Imports System.Collections.Generic
- Imports System.ComponentModel
- Imports System.Windows.Threading
- Imports NAudio.Wave
- Imports WPFSoundVisualizationLib
- Imports System.Windows.Interop
- Public Class NAudioEngine
- Implements INotifyPropertyChanged
- Implements ISpectrumPlayer
- Implements IWaveformPlayer
- Implements IDisposable
- #Region "Fields"
- Private _NewTrackDelegate As NewTrackPlay
- Private Shared m_instance As NAudioEngine
- Private ReadOnly positionTimer As New DispatcherTimer(DispatcherPriority.ApplicationIdle)
- Private ReadOnly waveformGenerateWorker As New BackgroundWorker()
- Private ReadOnly wavefftDataSize As Integer = CInt(FFTDataSize.FFT2048)
- Private disposed As Boolean
- Private m_canPlay As Boolean
- Private m_canPause As Boolean
- Private m_canStop As Boolean
- Private m_isPlaying As Boolean
- Private inChannelTimerUpdate As Boolean
- Private m_channelLength As Double
- Private m_channelPosition As Double
- Private inChannelSet As Boolean
- Private waveOutDevice As WaveOut = New WaveOut()
- Private m_activeStream As WaveStream
- Private inputStream As WaveChannel32
- Private sampleAggregator As SampleAggregator
- Private waveformAggregator As SampleAggregator
- Private pendingWaveformPath As String
- Private fullLevelData As Single()
- Private m_waveformData As Single()
- Private repeatStart As TimeSpan
- Private repeatStop As TimeSpan
- Private inRepeatSet As Boolean
- Private _currentTrack As Track
- Private _volume As Single
- #End Region
- #Region "Events"
- Public Event ChannelPositionChanged(sender As Object, e As EventArgs)
- Public Event ChannelLengthChange(sender As Object, e As EventArgs)
- Public Event PlayStateChanged(sender As Object, e As EventArgs)
- Public Event TrackEnd(sender As Object, e As EventArgs)
- #End Region
- #Region "Constants"
- Private Const waveformCompressedPointCount As Integer = 2000
- Private Const repeatThreshold As Integer = 200
- #End Region
- #Region "Singleton Pattern"
- Public Shared ReadOnly Property Instance() As NAudioEngine
- Get
- If m_instance Is Nothing Then
- m_instance = New NAudioEngine()
- End If
- Return m_instance
- End Get
- End Property
- #End Region
- #Region "Constructor"
- Private Sub New()
- positionTimer.Interval = TimeSpan.FromMilliseconds(50)
- AddHandler positionTimer.Tick, AddressOf positionTimer_Tick
- AddHandler waveformGenerateWorker.DoWork, AddressOf waveformGenerateWorker_DoWork
- AddHandler waveformGenerateWorker.RunWorkerCompleted, AddressOf waveformGenerateWorker_RunWorkerCompleted
- waveformGenerateWorker.WorkerSupportsCancellation = True
- End Sub
- #End Region
- #Region "IDisposable"
- Public Sub Dispose() Implements IDisposable.Dispose
- Dispose(True)
- GC.SuppressFinalize(Me)
- End Sub
- Protected Overridable Sub Dispose(disposing As Boolean)
- If Not disposed Then
- If disposing Then
- StopAndCloseStream()
- If waveformGenerateWorker.IsBusy Then
- waveformGenerateWorker.CancelAsync()
- End If
- waveformGenerateWorker.Dispose()
- End If
- disposed = True
- End If
- End Sub
- #End Region
- #Region "INotifyPropertyChanged"
- Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
- Private Sub OnPropertyChanged(info As String)
- RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
- End Sub
- #End Region
- #Region "Private Utility Methods"
- Private Sub StopAndCloseStream()
- If waveOutDevice IsNot Nothing Then
- waveOutDevice.[Stop]()
- End If
- If m_activeStream IsNot Nothing Then
- inputStream.Close()
- inputStream = Nothing
- ActiveStream.Close()
- ActiveStream = Nothing
- End If
- If waveOutDevice IsNot Nothing Then
- waveOutDevice.Dispose()
- waveOutDevice = Nothing
- End If
- End Sub
- #End Region
- #Region "Public Methods"
- Public Delegate Sub NewTrackPlay(track As Track)
- Public Sub RegisterNewTrackDelegate(mydelegate As NewTrackPlay)
- _NewTrackDelegate = mydelegate
- End Sub
- Public Sub UpdateTimeStrings()
- OnPropertyChanged("ChannelLengthTimeToString")
- OnPropertyChanged("ChannelPositionTimeToString")
- End Sub
- Public Sub [Stop]()
- If waveOutDevice IsNot Nothing Then
- waveOutDevice.[Stop]()
- End If
- IsPlaying = False
- CanStop = False
- CanPlay = False
- CanPause = False
- StopAndCloseStream()
- Me.CurrentTrack = Nothing
- End Sub
- Public Sub Pause()
- If IsPlaying AndAlso CanPause Then
- waveOutDevice.Pause()
- IsPlaying = False
- CanPlay = True
- CanPause = False
- End If
- End Sub
- Public Sub Play()
- If CanPlay Then
- waveOutDevice.Play()
- IsPlaying = True
- CanPause = True
- CanPlay = False
- CanStop = True
- End If
- End Sub
- Public Overloads Sub OpenFile(t As Track)
- [Stop]()
- If ActiveStream IsNot Nothing Then
- SelectionBegin = TimeSpan.Zero
- SelectionEnd = TimeSpan.Zero
- ChannelPosition = 0
- End If
- StopAndCloseStream()
- If System.IO.File.Exists(t.Path) Then
- Try
- Dim mainWindow As Window = Application.Current.MainWindow
- Dim interopHelper As New WindowInteropHelper(mainWindow)
- waveOutDevice = New WaveOut(interopHelper.Handle) With { _
- .DesiredLatency = 100, _
- .Volume = Volume _
- }
- ActiveStream = New Mp3FileReader(t.Path)
- inputStream = New WaveChannel32(ActiveStream)
- sampleAggregator = New SampleAggregator(wavefftDataSize)
- AddHandler inputStream.Sample, AddressOf inputStream_Sample
- waveOutDevice.Init(inputStream)
- ChannelLength = inputStream.TotalTime.TotalSeconds
- GenerateWaveformData(t.Path)
- CanPlay = True
- If _NewTrackDelegate IsNot Nothing Then
- _NewTrackDelegate.Invoke(t)
- End If
- CurrentTrack = t
- Catch
- ActiveStream = Nothing
- CanPlay = False
- End Try
- End If
- End Sub
- #End Region
- #Region "Public Properties"
- Public Property CurrentTrack As Track
- Get
- Return _currentTrack
- End Get
- Protected Set(value As Track)
- If value IsNot _currentTrack Then
- _currentTrack = value
- OnPropertyChanged("CurrentTrack")
- End If
- End Set
- End Property
- Public Property ActiveStream() As WaveStream
- Get
- Return m_activeStream
- End Get
- Protected Set(value As WaveStream)
- Dim oldValue As WaveStream = m_activeStream
- m_activeStream = value
- If oldValue IsNot m_activeStream Then
- OnPropertyChanged("ActiveStream")
- End If
- End Set
- End Property
- Public Property CanPlay() As Boolean
- Get
- Return m_canPlay
- End Get
- Protected Set(value As Boolean)
- Dim oldValue As Boolean = m_canPlay
- m_canPlay = value
- If oldValue <> m_canPlay Then
- OnPropertyChanged("CanPlay")
- End If
- End Set
- End Property
- Public Property CanPause() As Boolean
- Get
- Return m_canPause
- End Get
- Protected Set(value As Boolean)
- Dim oldValue As Boolean = m_canPause
- m_canPause = value
- If oldValue <> m_canPause Then
- OnPropertyChanged("CanPause")
- End If
- End Set
- End Property
- Public Property CanStop() As Boolean
- Get
- Return m_canStop
- End Get
- Protected Set(value As Boolean)
- Dim oldValue As Boolean = m_canStop
- m_canStop = value
- If oldValue <> m_canStop Then
- OnPropertyChanged("CanStop")
- End If
- End Set
- End Property
- Public Property IsPlaying() As Boolean Implements IWaveformPlayer.IsPlaying
- Get
- Return m_isPlaying
- End Get
- Protected Set(value As Boolean)
- Dim oldValue As Boolean = m_isPlaying
- m_isPlaying = value
- If oldValue <> m_isPlaying Then
- OnPropertyChanged("IsPlaying")
- RaiseEvent PlayStateChanged(Me, EventArgs.Empty)
- End If
- positionTimer.IsEnabled = value
- End Set
- End Property
- Private _ChannelLengthTimeToString As String
- Public ReadOnly Property ChannelLengthTimeToString As String
- Get
- If ActiveStream Is Nothing Then Return "00:00:00"
- Return ActiveStream.TotalTime.ToString("hh\:mm\:ss")
- End Get
- End Property
- Private _ChannelPositionTimeToString As String
- Public ReadOnly Property ChannelPositionTimeToString As String
- Get
- If ActiveStream Is Nothing Then Return "00:00:00"
- Return ActiveStream.CurrentTime.ToString("hh\:mm\:ss")
- End Get
- End Property
- Public Property Volume As Single
- Get
- Return _volume
- End Get
- Set(value As Single)
- _volume = value
- If waveOutDevice IsNot Nothing Then waveOutDevice.Volume = value
- OnPropertyChanged("Volume")
- End Set
- End Property
- #End Region
- #Region "Event Handlers"
- Private Sub inputStream_Sample(sender As Object, e As SampleEventArgs)
- sampleAggregator.Add(e.Left, e.Right)
- Dim repeatStartPosition As Long = CLng((SelectionBegin.TotalSeconds / ActiveStream.TotalTime.TotalSeconds) * ActiveStream.Length)
- Dim repeatStopPosition As Long = CLng((SelectionEnd.TotalSeconds / ActiveStream.TotalTime.TotalSeconds) * ActiveStream.Length)
- If ((SelectionEnd - SelectionBegin) >= TimeSpan.FromMilliseconds(repeatThreshold)) AndAlso ActiveStream.Position >= repeatStopPosition Then
- sampleAggregator.Clear()
- ActiveStream.Position = repeatStartPosition
- End If
- End Sub
- Private Sub waveStream_Sample(sender As Object, e As SampleEventArgs)
- waveformAggregator.Add(e.Left, e.Right)
- End Sub
- Private Sub positionTimer_Tick(sender As Object, e As EventArgs)
- inChannelTimerUpdate = True
- ChannelPosition = (CDbl(ActiveStream.Position) / CDbl(ActiveStream.Length)) * ActiveStream.TotalTime.TotalSeconds
- If _ChannelLengthTimeToString <> ChannelLengthTimeToString Then
- OnPropertyChanged("ChannelLengthTimeToString")
- _ChannelLengthTimeToString = ChannelLengthTimeToString
- End If
- If _ChannelPositionTimeToString <> ChannelPositionTimeToString Then
- OnPropertyChanged("ChannelPositionTimeToString")
- _ChannelPositionTimeToString = ChannelPositionTimeToString
- End If
- If ChannelPosition = ActiveStream.TotalTime.TotalSeconds Then
- IsPlaying = False
- CanPlay = True
- CanPause = False
- CanStop = False
- RaiseEvent TrackEnd(Me, EventArgs.Empty)
- End If
- inChannelTimerUpdate = False
- End Sub
- #End Region
- End Class
Danke für eure Antworten