Danke für die schnelle Antwort Pluto...
Code: Alles auswählen
Imports System
Imports System.Runtime.InteropServices
Imports System.Text
Imports System.IO
'Simple MP3 player for Pocket PC
'-------------------------------
'using FMOD Sound System http://www.fmod.org" onclick="window.open(this.href);return false; by Brett and the Team, FireLight Technologies
'tricks I used :
'* I did not manage to create a good callback wrapper, so I use a timer set on high rate to check if we have reached the end of a track
'* To pause a track, I first record the actual position and close the stream, as if I stopped playing. To unpause, start playing the same track, starting at recorded position
'* To get a handle on the mp3 file, I used a trick found on fmod's forum, which I implemented in C#: fmod_getStream
'Julien - codeProject - 09/2005
'Contributors : mattias73, lonifasiko
'Credits : MSDN CF faq, FMOD's forums
'Updates
'26.10.2005 - Got rid of external C# fmod wrapper, and implemented it inside main module
'14.11.2005 - AddrOfPinnedObject bug fix for .NET CF 1.0
Public Class frmMain
Inherits System.Windows.Forms.Form
Friend WithEvents lblIntroText As System.Windows.Forms.Label
Friend WithEvents btnBrowse As System.Windows.Forms.Button
Friend WithEvents Label1 As System.Windows.Forms.Label
Friend WithEvents txtSoundTrack As System.Windows.Forms.TextBox
Friend WithEvents Label3 As System.Windows.Forms.Label
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
MyBase.Dispose(disposing)
End Sub
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
Friend WithEvents timSound As System.Windows.Forms.Timer
Friend WithEvents ofdSound As System.Windows.Forms.OpenFileDialog
Friend WithEvents btnPause As System.Windows.Forms.Button
Friend WithEvents btnStop As System.Windows.Forms.Button
Friend WithEvents btnPlay As System.Windows.Forms.Button
Friend WithEvents trackBar As System.Windows.Forms.ProgressBar
Private Sub InitializeComponent()
Dim resources As System.Resources.ResourceManager = New System.Resources.ResourceManager(GetType(frmMain))
Me.timSound = New System.Windows.Forms.Timer
Me.ofdSound = New System.Windows.Forms.OpenFileDialog
Me.lblIntroText = New System.Windows.Forms.Label
Me.btnBrowse = New System.Windows.Forms.Button
Me.Label1 = New System.Windows.Forms.Label
Me.txtSoundTrack = New System.Windows.Forms.TextBox
Me.btnPlay = New System.Windows.Forms.Button
Me.btnPause = New System.Windows.Forms.Button
Me.btnStop = New System.Windows.Forms.Button
Me.Label3 = New System.Windows.Forms.Label
Me.trackBar = New System.Windows.Forms.ProgressBar
'
'timSound
'
Me.timSound.Interval = 500
'
'ofdSound
'
Me.ofdSound.Filter = "MP3 files|*.mp3"
'
'lblIntroText
'
Me.lblIntroText.Location = New System.Drawing.Point(8, 16)
Me.lblIntroText.Size = New System.Drawing.Size(224, 32)
Me.lblIntroText.Text = "Browse to select an mp3 file and click play to listen to it."
'
'btnBrowse
'
Me.btnBrowse.Location = New System.Drawing.Point(8, 56)
Me.btnBrowse.Size = New System.Drawing.Size(224, 24)
Me.btnBrowse.Text = "Browse"
'
'Label1
'
Me.Label1.Location = New System.Drawing.Point(8, 88)
Me.Label1.Size = New System.Drawing.Size(216, 16)
Me.Label1.Text = "Selected sound track :"
'
'txtSoundTrack
'
Me.txtSoundTrack.Location = New System.Drawing.Point(8, 112)
Me.txtSoundTrack.ReadOnly = True
Me.txtSoundTrack.Size = New System.Drawing.Size(224, 21)
Me.txtSoundTrack.Text = "no file selected"
'
'btnPlay
'
Me.btnPlay.Location = New System.Drawing.Point(8, 224)
Me.btnPlay.Size = New System.Drawing.Size(64, 32)
Me.btnPlay.Text = "Play"
'
'btnPause
'
Me.btnPause.Location = New System.Drawing.Point(88, 224)
Me.btnPause.Size = New System.Drawing.Size(64, 32)
Me.btnPause.Text = "Pause"
'
'btnStop
'
Me.btnStop.Location = New System.Drawing.Point(168, 224)
Me.btnStop.Size = New System.Drawing.Size(64, 32)
Me.btnStop.Text = "Stop"
'
'Label3
'
Me.Label3.Location = New System.Drawing.Point(7, 170)
Me.Label3.Size = New System.Drawing.Size(96, 16)
Me.Label3.Text = "Elapsed time :"
'
'trackBar
'
Me.trackBar.Location = New System.Drawing.Point(8, 192)
Me.trackBar.Size = New System.Drawing.Size(224, 21)
'
'frmMain
'
Me.Controls.Add(Me.trackBar)
Me.Controls.Add(Me.Label3)
Me.Controls.Add(Me.btnStop)
Me.Controls.Add(Me.btnPause)
Me.Controls.Add(Me.btnPlay)
Me.Controls.Add(Me.txtSoundTrack)
Me.Controls.Add(Me.Label1)
Me.Controls.Add(Me.btnBrowse)
Me.Controls.Add(Me.lblIntroText)
Me.Font = New System.Drawing.Font("Verdana", 8.25!, System.Drawing.FontStyle.Regular)
Me.Icon = CType(resources.GetObject("$this.Icon"), System.Drawing.Icon)
Me.Text = "MP3 Player"
End Sub
#End Region
'currentSoundTrack - the file name of the currently selected file
Private currentSoundTrack As String = String.Empty
'isOnPause - Boolean which shows if track is paused or not
Private isOnPause As Boolean = False
'currentPosition - used to store current position in the track
Private currentPosition As Integer = 0
'soundHandle - handle to the sound track
Private soundHandle As IntPtr = IntPtr.Zero
'currentSoundLength - the length of the current track
Private currentSoundLength As Integer = 0
'uPausePosition - the current position as uint
Private uPausePosition As UInt32
'frmMain_Load - start point of the application
Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'set the selected file text box to "no file selected"
txtSoundTrack.Text = "no file selected"
'disable play/pause/stop button, as their is no file selected
btnPlay.Enabled = False
btnPause.Enabled = False
btnStop.Enabled = False
'set the progress bar value to 0
trackBar.Value = 0
End Sub
'setEnabled - sub which enables the play button
'used when no sound is playing but a file is selected
Private Sub setEnabled()
btnPlay.Enabled = True
btnPause.Enabled = False
btnStop.Enabled = False
trackBar.Value = 0
End Sub
'btnBrowse_Click - fired when user browses for a MP3 file
'note that the openFileDialog as a *.mp3 filter
Private Sub btnBrowse_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBrowse.Click
If ofdSound.ShowDialog = DialogResult.OK Then
'if the user has selected a file then check if the file really exists
If File.Exists(ofdSound.FileName) Then
'file exists so enable play button
setEnabled()
'update the selected file text box with the file name, without the full path
txtSoundTrack.Text = Path.GetFileName(ofdSound.FileName)
'set global currentSoundTrack to hold the full path+filename
currentSoundTrack = ofdSound.FileName
End If
End If
End Sub
'btnPlay_Click - fired when user clicks on the play button
Private Sub btnPlay_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPlay.Click
'start playing the track
play_track()
'disable play button and enable pause/stop buttons
btnPause.Enabled = True
btnStop.Enabled = True
btnPlay.Enabled = False
'set the progress bar max value to the length of the track divided by 1000
'divide by 1000 to avoid having a max value greater than what it can hold
trackBar.Maximum = currentSoundLength / 1000
trackBar.Minimum = 0
'set the progress bar to 0
trackBar.Value = 0
End Sub
'btnPause_Click - fired when user clicks on the pause button
Private Sub btnPause_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPause.Click
'set the onPause boolean
isOnPause = True
'stop playing
stop_track()
'disable pause button
btnPause.Enabled = False
'other buttons still available
btnStop.Enabled = True
btnPlay.Enabled = True
End Sub
'btnStop_Click - fired when user clicks on the stop button
Private Sub btnStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStop.Click
'stop playing
stop_track()
'enable/disable buttons as if user had just selected a file
setEnabled()
End Sub
'timSound_Tick - fired every 500ms to check current status of file
'this is a workaround for a End_of_track event
'a better solution would be to wrap the End_Callback from FMOD
Private Sub timSound_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles timSound.Tick
'set the uPausePosition to the current position in track
uPausePosition = fmod_GetPosition(soundHandle)
'convert to int [bad conversion ?]
currentPosition = CInt(uPausePosition.ToString)
'set the progress bar to the current position value divided by 1000
trackBar.Value = CInt(currentPosition / 1000)
'if the current position is greater or equal to the total length, then we have reached the end of the track
If currentPosition >= currentSoundLength Then
'disable timer, which means stop waiting for the end of the track
timSound.Enabled = False
'make sure it's really finished by calling stop_sound, just in case
stop_track()
'enable/disable buttons as if user had just selected a file
setEnabled()
End If
End Sub
'play_track - call to fmod functions to start playing
Private Sub play_track()
'initialize fmod with mixrate equal to 44.1kHz
fmod_Init(44100, 16, 0)
'create a handle to hold the track stream - REPLACE HERE fmod_getStream BY fmod_getStream_New TO TRY WITHOUT THE AddrOfPinnedObject BUG FIX !
Dim soundStream As IntPtr = fmod_getStream(currentSoundTrack)
'open the stream in Normal mode, which is combination of Mono sound, 16 bits, Signed
soundHandle = fmod_Open(soundStream, &H10 Or &H20 Or &H100, 0, 0)
'record the current length of track
currentSoundLength = fmod_GetLength(soundHandle)
If isOnPause Then
'if we are on pause, this means the user was previously playing
'thus we have start the track where it has previously stopped
'this position is in uPausePosition
'so set the track's position to that
fmod_SetPosition(soundHandle, uPausePosition)
'and play from there
fmod_Play(0, soundHandle)
'unset the on pause bit
isOnPause = False
Else
'if we are not on pause, this means it's a click on play after a file selection
'so start playing immediately at start position
fmod_Play(0, soundHandle)
End If
'start the timer to check for the end of the stream
timSound.Enabled = True
End Sub
'stop_track - used to stop playing
Private Sub stop_track()
'check if the handle is still valid
'if it's not, the track is probably already finished
If soundHandle.ToInt32 > 0 Then
'record the track's position, in case user has clicked on pause
uPausePosition = fmod_GetPosition(soundHandle)
'stop playing
fmod_Stop(soundHandle)
'release the ressources
fmod_Close()
End If
End Sub
#Region " FMOD DLL calls "
<DllImport("fmodce.dll", EntryPoint:="FSOUND_Init", SetLastError:=True, CharSet:=CharSet.Unicode, CallingConvention:=CallingConvention.Winapi)> _
Public Shared Function fmod_Init(ByVal mixrate As Integer, ByVal maxsoftwarechannels As Integer, ByVal flags As Integer) As Boolean
End Function
<DllImport("fmodce.dll", EntryPoint:="FSOUND_Stream_GetLength", SetLastError:=True, CharSet:=CharSet.Unicode, CallingConvention:=CallingConvention.Winapi)> _
Public Shared Function fmod_GetLength(ByVal fstream As IntPtr) As Integer
End Function
<DllImport("fmodce.dll", EntryPoint:="FSOUND_Stream_GetPosition", SetLastError:=True, CharSet:=CharSet.Unicode, CallingConvention:=CallingConvention.Winapi)> _
Public Shared Function fmod_GetPosition(ByVal fstream As IntPtr) As UInt32
End Function
<DllImport("fmodce.dll", EntryPoint:="FSOUND_Stream_Open", SetLastError:=True, CharSet:=CharSet.Unicode, CallingConvention:=CallingConvention.Winapi)> _
Public Shared Function fmod_Open(ByVal data As IntPtr, ByVal mode As Integer, ByVal offset As Integer, ByVal length As Integer) As IntPtr
End Function
<DllImport("fmodce.dll", EntryPoint:="FSOUND_Stream_Play", SetLastError:=True, CharSet:=CharSet.Unicode, CallingConvention:=CallingConvention.Winapi)> _
Public Shared Function fmod_Play(ByVal channel As Integer, ByVal fstream As IntPtr) As Integer
End Function
<DllImport("fmodce.dll", EntryPoint:="FSOUND_Stream_SetPosition", SetLastError:=True, CharSet:=CharSet.Unicode, CallingConvention:=CallingConvention.Winapi)> _
Public Shared Function fmod_SetPosition(ByVal fstream As IntPtr, ByVal position As UInt32) As Boolean
End Function
<DllImport("fmodce.dll", EntryPoint:="FSOUND_Stream_Stop", SetLastError:=True, CharSet:=CharSet.Unicode, CallingConvention:=CallingConvention.Winapi)> _
Public Shared Function fmod_Stop(ByVal fstream As IntPtr) As Boolean
End Function
<DllImport("fmodce.dll", EntryPoint:="FSOUND_Close", SetLastError:=True, CharSet:=CharSet.Unicode, CallingConvention:=CallingConvention.Winapi)> _
Public Shared Sub fmod_Close()
End Sub
Private Function fmod_getStream(ByVal filename As String) As IntPtr
'thanks to mattias73 and lonifasiko for the help on this !
Dim filenames As Byte() = Encoding.Default.GetBytes(filename & vbNullChar)
Dim hfile As GCHandle = GCHandle.Alloc(filenames, GCHandleType.Pinned)
'if the .NET CF version is 1.x, then we add 4 bytes to the address of the pinned object,
'because AddrOfPinnedObject returns the address of the object shifted of 4 bytes, which corresponds to the storage space of the pointer itself
'the bug is only in CF 1.x so this bug-fix needs to be conditional
If Environment.Version.Major = 1 Then
fmod_getStream = New IntPtr(hfile.AddrOfPinnedObject().ToInt32 + 4)
Else
fmod_getStream = hfile.AddrOfPinnedObject()
End If
If hfile.IsAllocated Then
hfile.Free()
End If
'End note :
'The bug fix above is not a good bug-fix in fact, because although CF 2.0 doesn't have this problem anymore
'it might be solved as well in later releases of CF 1.x (as service packs)
'In this latter case, the code wouldn't work - SEE BELOW
End Function
#Region " Sample from MS "
'The code below is never called - it's only a sample of how to allocate the memory for the stream
'without using the AddrOfPinnedObject
'code from http://msdn.microsoft.com/smartclient/understanding/netcf/FAQ/default.aspx
<DllImport("coredll.dll", SetLastError:=True)> _
Public Shared Function LocalAlloc(ByVal uFlags As UInt32, ByVal uBytes As UInt32) As IntPtr
End Function
<DllImport("coredll.dll", SetLastError:=True)> _
Public Shared Function LocalFree(ByVal hMem As IntPtr) As IntPtr
End Function
<DllImport("coredll.dll", SetLastError:=True)> _
Public Shared Function LocalReAlloc(ByVal hMem As IntPtr, ByVal uBytes As UInt32, ByVal fuFlags As UInt32) As IntPtr
End Function
Public Const LMEM_FIXED As Integer = 0
Public Const LMEM_MOVEABLE As Integer = 2
Public Const LMEM_ZEROINIT As Integer = &H40
Private Function fmod_getStream_New(ByVal filename As String) As IntPtr
Dim filenames As Byte() = Encoding.Default.GetBytes(filename & vbNullChar)
Dim p As IntPtr = LocalAlloc(Convert.ToUInt32(LMEM_FIXED Or LMEM_ZEROINIT), Convert.ToUInt32(filenames.Length))
If Not p.Equals(IntPtr.Zero) Then
Marshal.Copy(filenames, 0, p, filenames.Length)
'else "out of memory" !
End If
fmod_getStream_New = p
End Function
#End Region
#End Region
End Class