I only post here when I'm really stuck, so here goes.
I'm creating a program where I can edit the metadata of MP3 files (with all data pulled from a mysql db), using taglib-sharp. If I preview an audio file using naudio, I can hear the audio no problems and I can stop it, so that is all good. For the sake of what is happening in my code, It's a matter of choosing a file from a listbox, and then I push a 'play' button to start, and another button to stop. My error is showing up with a right click context menu when I'm trying to save metadata.
The problem is when I go to edit the metadata of that same file I just played, the error appears - as per this shown in the following example of code. When I try and call the mp3.save() line, I receive the following error:
************** Exception Text **************
System.IO.IOException: The process cannot access the file 'C:\temp\test.mp3' because it is being used by another process. at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share) at TagLib.File.LocalFileAbstraction.get_WriteStream() at TagLib.File.set_Mode(AccessMode value) at TagLib.NonContainer.File.Save() at LinersDB_META.Form1.menuChoice(Object sender, EventArgs e) in C:\Users\smonro\source\repos\WindowsApp1\WindowsApp1\Form1.vb:line 2281 at System.Windows.Forms.ToolStripItem.RaiseEvent(Object key, EventArgs e) at System.Windows.Forms.ToolStripMenuItem.OnClick(EventArgs e) at System.Windows.Forms.ToolStripItem.HandleClick(EventArgs e) at System.Windows.Forms.ToolStripItem.HandleMouseUp(MouseEventArgs e)
at System.Windows.Forms.ToolStrip.OnMouseUp(MouseEventArgs mea) at System.Windows.Forms.ToolStripDropDown.OnMouseUp(MouseEventArgs mea)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks) at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.ToolStrip.WndProc(Message& m) at System.Windows.Forms.ToolStripDropDown.WndProc(Message& m) at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
etc
I know why it's happening, but I'm lost as to how to solve it.
According to this page, (which is in C#) I need to release the "Mp3FileReader".
In my case, it would be "data" - this: Dim data As New NAudio.Wave.Mp3FileReader(file)
The problem is, it's in a private sub, as a private variable.
However, I'm struggling to see how I can make this declaration public, when I need to have file also declared, but it would also need to be known too, and reinitialized every time I choose a different audio file.
Any thoughts?
Should I just try and rearrange my program to work differently? Thanks in advance.
'...
Imports System.IO 'File Operations
Imports TagLib ' Tagging
Imports NAudio
'...
'Wave out device for playing the sound
Public Shared Wave1 As New NAudio.Wave.WaveOut 'Wave out device for playing the sound
Public Sub start_audio()
Dim file As String = "C:\test\test.mp3"
If IO.File.Exists(file) Then
Dim data As New NAudio.Wave.Mp3FileReader(file)
Wave1.Init(data)
Wave1.Play()
End If
End Sub
Public Sub Button5_Click_1(sender As Object, e As EventArgs) Handles Button5.Click
Wave1.Stop()
End Sub
Public Sub menuChoice(ByVal sender As Object, ByVal e As EventArgs)
Dim item = CType(sender, ToolStripMenuItem)
Dim selection = CInt(item.Tag)
Select Case selection
Case 1
' Remove the Artwork
'Insert Album art and save to file and dispose.
If IO.File.Exists(GLOBAL_Full_Path) Then
Wave1.Stop()
Wave1.Dispose()
System.GC.Collect()
System.GC.WaitForPendingFinalizers()
Dim mp3 As TagLib.File = TagLib.File.Create(GLOBAL_Full_Path)
' Clear the artwork from the file.. (It's a big process)
Dim pics As Picture = New Picture()
Dim picsFrame As New TagLib.Id3v2.AttachedPictureFrame(pics)
picsFrame.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg
'set the type of picture (front cover)
picsFrame.Type = TagLib.PictureType.FrontCover
picsFrame.Description = "" ' So the Actual location of the image is not stored in the file. This would otherwise reveal internal systems to the public.
'Id3v2 allows more than one type of image, just one is needed here.
Dim pictFrames() As TagLib.IPicture = {picsFrame}
'set the pictures in the tag
mp3.Tag.Pictures = pictFrames
' ******************************************
' Error occurs here after a file has been played.
mp3.Save()
' Error occurs here
' ******************************************
mp3.Dispose()
End If
Case Else
End Select
End Sub
After @TnTinMn pointed me in the right direction, I solved the issue in the end. While this is not the full example, I've now solved this by adding and changing a couple of minor things.
Imports NAudio
' NEW/required to get the Mp3FileReader, so it can be dynamically populated.
Imports NAudio.Wave
Dim WavePlayOut As New NAudio.Wave.WaveOut 'Wave out device for playing the sound
Dim WaveFile As String = "" ' *** NEW/Declared ***
Dim WaveData As Mp3FileReader ' *** Changed ***
Public Sub start_audio()
If File_ListView.SelectedItems.Count > 0 Then
WaveFile = TxtBx_Path.Text & "\" & File_ListView.FocusedItem.Text
If WavePlayOut IsNot Nothing Then
WavePlayOut = New NAudio.Wave.WaveOut
End If
If WaveData IsNot Nothing Then
WaveData.Dispose()
WaveData = New Mp3FileReader(WaveFile)
If WaveData.Length > 1 Then
If IO.File.Exists(WaveFile) Then
WavePlayOut.Init(WaveData)
WavePlayOut.Play()
End If
End If
Else
WaveData = New Mp3FileReader(WaveFile)
If WaveData.Length > 1 Then
If IO.File.Exists(WaveFile) Then
WavePlayOut.Init(WaveData)
WavePlayOut.Play()
End If
End If
End If
End If
End Sub
To unload the audio file, use the following:
If WaveData IsNot Nothing Then
WaveData.Dispose()
End If
If WavePlayOut IsNot Nothing Then
WavePlayOut.Stop()
WavePlayOut.Dispose()
End If