Introduction
The idea for LameShell came from my wish to be able to resample MP3 files in VB.NET. The goal was: "Whatever valid file goes in, out comes a 32kbit encoded MP3". I started looking around and I really didn�t like the solutions I found. You either had to deal with Interop or unmanaged code, it would cost, the interfaces where out of date or they where just too much. So I created this wrapper that allows me to have all sorts of status updates while Lame encodes the MP3. All you have to do in the application is supply the source file, the destination file and options you need.
Background
While there are some .NET wrappers around the LAME encoder lame_enc.dll, I decided to go a different route � a simple wrapper around lame.exe. There are so many options in there you could expose easily if you wanted to, or just directly type into your source if you have a simple goal � like I had. You can find out more about LAME here and you will need lame.exe to use this class. (lame.exe is not included with the source code)
Using the code
Using the code is very simple; you supply the filenames and options. Additionally, you can supply the path to lame.exe if it isn't in your application directory.
Dim WithEvents _lameShell As New LameShell
[...]
_lameShell.InFile = Application.StartupPath & "\test.mp3"
_lameShell.OutFile = Application.StartupPath & "\testOut.mp3"
_lameShell.Options = "-b 32"
_lameShell.Start()
Add some event handlers:
Private Sub _lameShell_Done() Handles _lameShell.Done
lblFeedback.Text = "Done"
End Sub
Private Sub _lameShell_Canceled() Handles _lameShell.Canceled
lblFeedback.Text = "Canceled/Error"
pBar.Value = 0
End Sub
Private Sub _lameShell_Progress(ByRef Progress As LameProgress) _
Handles _lameShell.Progress
If pBar.Maximum <> Progress.FrameMax Then
pBar.Value = 0
pBar.Maximum = Progress.FrameMax
Else
pBar.Value = Progress.FrameCurrent
End If
lblFeedback.Text = Progress.PercentDone & "%" & " ETA:" & Progress.ETA
End Sub
That's all there is to it.
How it Works
Essentially, you create a new System.Diagnostics.Process
with the needed ProcessStartInfo
.
Private _startInfo As New ProcessStartInfo
[...]
_startInfo.FileName = "lame.exe"
_startInfo.UseShellExecute = False
_startInfo.RedirectStandardOutput = True
_startInfo.RedirectStandardError = True
_startInfo.CreateNoWindow = True
And you create a Reader in a different thread that keeps reading the output of lame.exe.
Private _lameThread As System.Threading.Thread
[...]
_lameThread = New System.Threading.Thread(AddressOf LameReader)
_lameThread.IsBackground = True
_lameThread.Name = "LameReader"
_lameThread.Start()
[...]
Private Sub LameReader()
Dim oneLine As String
_lameProcess.Start()
oneLine = _lameProcess.StandardError.ReadLine()
While Not oneLine Is Nothing
oneLine = _lameProcess.StandardError.ReadLine()
End While
End Sub
Points of Interest
One thing I haven�t figured out is why the thread that is launched to read the info from lame.exe does not throw a Threading.ThreadAbortException
when the application exits. According to MSDN, it should when IsBackround = true
. For now, you are safe if you make sure to call LameShell.Cancel()
if your application is closing.
Make sure not to depend on the Closing
or Closed
event of a form (like in the example) if you use Application.Exit
anywhere. Those won�t fire if you use Application.Exit
. That's why I would have liked the Threading.ThreadAbortException
to fire to clean up on all circumstances.