|
|
||||
|
vbAccelerator - Contents of code file: WaveStreamReader.vbThis file is part of the download WaveStream VB, which is described in the article WaveStreamReader and WaveStreamWriter. Imports System.IO
Imports System.Runtime.InteropServices
Public Class WaveStreamReader
Inherits Stream
Private waveFile As String
Private hMmio As IntPtr = IntPtr.Zero
Private disposed As Boolean = False
Private format As WinMMInterop.WAVEFORMATEX
Private dataOffset As Integer = 0
Private audioLength As Integer = 0
Public Overloads Sub Dispose()
DisposeResources(True)
GC.SuppressFinalize(Me)
End Sub
''' <summary>
''' Default constructor
''' </summary>
Public Sub New()
MyBase.New()
End Sub
''' <summary>
''' Constructor for a particular wave file.
''' </summary>
''' <param name="file">File name of the wave file to read</param>
Public Sub New(ByVal file As String)
Me.New()
Filename = file
End Sub
''' <summary>
''' Destructor: ensures that the wave file handle is closed.
''' </summary>
Protected Overrides Sub Finalize()
DisposeResources(False)
End Sub
''' <summary>
''' Gets the Multi-media IO handle to the wave file.
''' </summary>
Protected Overridable ReadOnly Property Handle() As IntPtr
Get
Return hMmio
End Get
End Property
''' <summary>
''' Clears up resources associated with this class.
''' </summary>
''' <param name="disposing"><code>true</code> if disposing from the
<c>Dispose</c>
''' method, otherwise <c>false</c>.</param>
Protected Overridable Sub DisposeResources(ByVal disposing As Boolean)
If Not (disposed) Then
If (disposing) Then
'// nothing to do
End If
CloseWaveFile()
disposed = True
End If
End Sub
''' <summary>
''' Gets/sets the wave file name.
''' </summary>
Public Property Filename() As String
Get
Return waveFile
End Get
Set(ByVal Value As String)
If Not (hMmio.Equals(IntPtr.Zero)) Then
CloseWaveFile()
End If
waveFile = Value
OpenWaveFile()
End Set
End Property
''' <summary>
''' Gets the number of audio channels in the file.
''' </summary>
Public ReadOnly Property Channels() As Int16
Get
Return format.nChannels
End Get
End Property
''' <summary>
''' Gets the sample frequency of the file.
''' </summary>
Public ReadOnly Property SamplingFrequency() As Integer
Get
Return format.nSamplesPerSec
End Get
End Property
''' <summary>
''' Gets the number of bits per sample in the wave file.
''' </summary>
Public ReadOnly Property BitsPerSample() As Int16
Get
Return format.wBitsPerSample
End Get
End Property
''' <summary>
''' Gets whether the stream can be read or not (true whenever a wave file
''' is open).
''' </summary>
Public Overrides ReadOnly Property CanRead() As Boolean
Get
Return Not (hMmio.Equals(IntPtr.Zero))
End Get
End Property
''' <summary>
''' Gets whether the stream is seekable or not (true whenever a wave file
''' is open)
''' </summary>
Public Overrides ReadOnly Property CanSeek() As Boolean
Get
Return Not (hMmio.Equals(IntPtr.Zero))
End Get
End Property
''' <summary>
''' Returns false; this is a read-only stream
''' </summary>
Public Overrides ReadOnly Property CanWrite() As Boolean
Get
Return False
End Get
End Property
''' <summary>
''' Throws an exception; this is a read-only stream
''' </summary>
''' <exception cref="InvalidOperationException">Thrown exception</exception>
Public Overrides Sub Flush()
Throw New InvalidOperationException( _
"This class can only read files. Use the WaveStreamWriter class to
write files.")
End Sub
''' <summary>
''' Gets the length of this wave file, in bytes.
''' </summary>
Public Overrides ReadOnly Property Length() As Long
Get
Return audioLength
End Get
End Property
''' <summary>
''' Throws an exception; this is a read-only stream
''' </summary>
''' <exception cref="InvalidOperationException">Thrown exception</exception>
Public Overrides Sub SetLength(ByVal length As Long)
Throw New InvalidOperationException( _
"This class can only read files. Use the WaveStreamWriter class to
write files.")
End Sub
''' <summary>
''' Gets/sets the position within the wave file.
''' </summary>
Public Overrides Property Position() As Long
Get
Return 0
End Get
Set(ByVal Value As Long)
Seek(Value, SeekOrigin.Begin)
End Set
End Property
''' <summary>
''' Reads <c>count</c> bytes into the buffer.
''' </summary>
''' <param name="buffer">Buffer to read into</param>
''' <param name="count">Number of bytes to read</param>
''' <returns>Number of bytes read.</returns>
Public Overridable Overloads Function Read(ByVal buffer As Byte(), ByVal
count As Integer) As Integer
Return Read(buffer, 0, count)
End Function
''' <summary>
''' Reads <c>count</c> bytes into the buffer.
''' </summary>
''' <param name="buffer">Buffer to read into</param>
''' <param name="count">Number of bytes to read</param>
''' <param name="offset">Offset from the current file position to start
reading from</param>
''' <returns>Number of bytes read.</returns>
Public Overloads Overrides Function Read(ByVal buffer As Byte(), ByVal
offset As Integer, ByVal count As Integer) As Integer
If (hMmio.Equals(IntPtr.Zero)) Then
Throw New InvalidOperationException("No wave data is open")
End If
If (offset <> 0) Then
Seek(offset, SeekOrigin.Current)
End If
Dim handle As GCHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned)
Dim ptrBuffer As IntPtr = handle.AddrOfPinnedObject()
Dim dataRemaining As Integer = (dataOffset + audioLength - _
WinMMInterop.mmioSeek(hMmio, 0, WinMMInterop.SEEK_CUR))
Dim amtRead As Integer = 0
If (count < dataRemaining) Then
amtRead = WinMMInterop.mmioRead(hMmio, ptrBuffer, count)
ElseIf (dataRemaining > 0) Then
amtRead = WinMMInterop.mmioRead(hMmio, ptrBuffer, dataRemaining)
End If
If (handle.IsAllocated) Then
handle.Free()
End If
Return amtRead
End Function
''' <summary>
''' Reads <c>count</c> shorts into the buffer.
''' </summary>
''' <param name="buffer">Buffer to read into</param>
''' <param name="count">Number of shorts to read</param>
''' <returns>Number of bytes read.</returns>
Public Overridable Function Read16bit(ByVal buffer As Short(), ByVal count
As Integer) As Integer
Return Read16bit(buffer, 0, count)
End Function
''' <summary>
''' Reads <c>count</c> shorts into the buffer.
''' </summary>
''' <param name="buffer">Buffer to read into</param>
''' <param name="count">Number of shorts to read</param>
''' <param name="offset">Offset in shorts (2 bytes) from the current file
position to start
''' reading from</param>
''' <returns>Number of bytes read.</returns>
Public Overridable Function Read16bit(ByVal buffer As Short(), ByVal offset
As Integer, ByVal count As Integer) As Integer
If (hMmio.Equals(IntPtr.Zero)) Then
Throw New InvalidOperationException("No wave data is open")
End If
If (offset <> 0) Then
Seek((offset / 2), SeekOrigin.Current)
End If
Dim handle As GCHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned)
Dim ptrBuffer As IntPtr = handle.AddrOfPinnedObject()
Dim dataRemaining As Integer = (dataOffset + audioLength - _
WinMMInterop.mmioSeek(hMmio, 0, WinMMInterop.SEEK_CUR)) / 2
Dim read = 0
If (count < dataRemaining) Then
read = WinMMInterop.mmioRead(hMmio, ptrBuffer, count * 2)
ElseIf (dataRemaining > 0) Then
read = WinMMInterop.mmioRead(hMmio, ptrBuffer, dataRemaining * 2)
End If
If (handle.IsAllocated) Then
handle.Free()
End If
Return read / 2
End Function
''' <summary>
''' Throws an exception; this is a read-only stream
''' </summary>
''' <exception cref="InvalidOperationException">Thrown exception</exception>
Public Overrides Sub Write(ByVal buffer As Byte(), ByVal offset As Integer,
ByVal count As Integer)
Throw New InvalidOperationException( _
"This class can only read files. Use the WaveStreamWriter class to
write wave files.")
End Sub
''' <summary>
''' Seeks to the specified position in the stream, in bytes
''' </summary>
''' <param name="position">Position to seek to</param>
''' <param name="origin">Specifies the starting postion of the seek</param>
Public Overrides Function Seek(ByVal position As Long, ByVal origin As
SeekOrigin) As Long
If (hMmio.Equals(IntPtr.Zero)) Then
Throw New InvalidOperationException("No wave data is open")
End If
Dim offset As Integer = position
Dim mmOrigin As Integer = WinMMInterop.SEEK_CUR
If (origin = SeekOrigin.Begin) Then
mmOrigin = WinMMInterop.SEEK_SET
ElseIf (origin = SeekOrigin.End) Then
mmOrigin = WinMMInterop.SEEK_END
End If
Dim result As Integer = WinMMInterop.mmioSeek(hMmio, offset, mmOrigin)
If (result = -1) Then
Throw New WaveStreamException( _
String.Format("Failed to seek to position {0} in file", position))
End If
Return result
End Function
Private Sub OpenWaveFile()
CloseWaveFile()
If Not (File.Exists(waveFile)) Then
Throw New FileNotFoundException( _
String.Format("The file {0} does not exist", waveFile))
End If
hMmio = WinMMInterop.mmioOpen(waveFile, IntPtr.Zero,
WinMMInterop.MMIO_READ)
If (hMmio.Equals(IntPtr.Zero)) Then
Throw New IOException( _
String.Format("Could not open file {0}", waveFile))
End If
GetWaveData()
End Sub
Private Sub GetWaveData()
Dim result As Integer = 0
Dim mmckInfoParent As WinMMInterop.MMCKINFO = New
WinMMInterop.MMCKINFO()
'// Descend into the wave header:
mmckInfoParent.fccType = WinMMInterop.mmioStringToFOURCC("WAVE", 0)
result = WinMMInterop.mmioDescendParent(hMmio, mmckInfoParent, 0, _
WinMMInterop.MMIO_FINDRIFF)
If (result <> WinMMInterop.MMSYSERR_NOERROR) Then
CloseWaveFile()
Throw New WaveStreamException( _
String.Format("The file {0} is not a wave file", waveFile))
End If
'// Descend into the fmt chunk:
Dim mmckSubChunkIn As WinMMInterop.MMCKINFO = New
WinMMInterop.MMCKINFO()
mmckSubChunkIn.ckid = WinMMInterop.mmioStringToFOURCC("fmt", 0)
result = WinMMInterop.mmioDescend(hMmio, mmckSubChunkIn,
mmckInfoParent, _
WinMMInterop.MMIO_FINDCHUNK)
If (result <> WinMMInterop.MMSYSERR_NOERROR) Then
CloseWaveFile()
Throw New WaveStreamException( _
String.Format("Unable to locate the format chunk in file {0}",
waveFile))
End If
format = New WinMMInterop.WAVEFORMATEX()
result = WinMMInterop.mmioReadWaveFormat(hMmio, format,
mmckSubChunkIn.ckSize)
If (result = -1) Then
CloseWaveFile()
Throw New WaveStreamException( _
String.Format("Unable to read the wave format from file {0}",
waveFile))
End If
'// Find the data subchunk
result = WinMMInterop.mmioAscend(hMmio, mmckSubChunkIn, 0)
mmckSubChunkIn.ckid = WinMMInterop.mmioStringToFOURCC("data", 0)
result = WinMMInterop.mmioDescend(hMmio, mmckSubChunkIn,
mmckInfoParent, _
WinMMInterop.MMIO_FINDCHUNK)
If (result <> WinMMInterop.MMSYSERR_NOERROR) Then
CloseWaveFile()
Throw New WaveStreamException( _
String.Format("Unable to locate the data chunk in file {0}",
waveFile))
End If
dataOffset = WinMMInterop.mmioSeek(hMmio, 0, WinMMInterop.SEEK_CUR)
audioLength = mmckSubChunkIn.ckSize
End Sub
Private Sub CloseWaveFile()
If Not (hMmio.Equals(IntPtr.Zero)) Then
WinMMInterop.mmioClose(hMmio, 0)
hMmio = IntPtr.Zero
audioLength = 0
End If
End Sub
End Class
|
|||
|
|
||||