Visual Basic.Net: Changing the speed of a wave file
Please note that this is not perfect, not all wave files can be modified without first modifying other fileformatsubchunk fields.
- Create a brand new Visual Basic Winforms project
- Replace ALL of Form1's code with the following code:
'Option Strict Is Always Recommended
Option Strict On
Imports System.Text
Public Class Form1
'Add one button to your form(make sure that the handles clause is still at the end of your sub afterwards)=Handles Button1.Click
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
'Create a new instance of the wavefile class(provided in the technet article)
Dim WaveFile As New Wave
'Create a new openfiledialog
Dim OFD As New OpenFileDialog
'Set the filter for the openfiledialog
OFD.Filter = "Wave Files|*.wav"
'make it select single files only
OFD.Multiselect = False
'Show the dialog
If OFD.ShowDialog = DialogResult.OK Then
'If the user didn't cancel then load the wavefile into its wrapper
WaveFile.LoadFromFile(OFD.FileName)
'Modify the sample rate(not all speeds are compatible without adjusting other properties)
WaveFile.FileFormatSubChunk.SampleRate = Wave.WavSampleRate.hz22050
'Create a new memory stream from the bytes of the wavefile
Dim Stream As New IO.MemoryStream(WaveFile.GetBytes)
'Play the wavefile
My.Computer.Audio.Play(Stream, AudioPlayMode.Background)
End If
End Sub
End Class
- Add a new class to your project
- Replace all of that Class's code with the following code:
Option Strict On
Imports System.Text
Public Class Wave
'By Paul Ishak
'WAVE PCM soundfile format
'The Canonical WAVE file format
'As Described Here: https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
'The File's Header
Public FileHeader As Header
'Wave File's Format Sub Chunk
Public FileFormatSubChunk As FormatSubChunk
'Data Subchunk
Public FileDataSubChunk As DataSubChunk
'This structure is an optional parameter for creating a new wave file
Public Structure WaveFileOptions
Public SampleRate As WavSampleRate
Public AudioFormat As Format
Public BitsPerSample As BitsPerSample
Public NumberOfChannels As NumberOfChannels
Public FormatSize As FormatSize
Public NumberOfSamples As UInt32
Public Data As Byte()
End Structure
'These are the various structures in the wave file and their description
'DATATYPE OFFSET Endian Description
Structure Header
Public Property ChunkID As Byte() ' Dword 0 Big Contains the letters "RIFF" in ASCII form(0x52494646 big-endian form).
Public Property ChunkSize As UInt32 ' Dword 4 Little 36 + SubChunk2Size, or more precisely: 4 + (8 + SubChunk1Size) + (8 + SubChunk2Size)
Public Property Format As Byte() ' Dword 8 Big Contains the letters "WAVE" in ASCII form (0x57415645 big-endian form).
End Structure
Structure FormatSubChunk
Public Property Subchunk1ID As Byte() ' Dword 12 Big Contains the letters "fmt "(0x666d7420 big-endian form).
Public Property Subchunk1Size As UInt32 ' Dword 16 little 16 for PCM. This is the size of the rest of the Subchunk which follows this number.
Public Property AudioFormat As UInt16 ' Word 20 little PCM = 1 (i.e. Linear quantization)Values other than 1 indicate some form of compression.
Public Property NumChannels As UInt16 ' Word 22 little Mono = 1, Stereo = 2, etc.
Public Property SampleRate As UInt32 ' Dword 24 little 8000, 44100, etc.
Public Property ByteRate As UInt32 ' Dword 28 little == SampleRate * NumChannels * BitsPerSample/8
Public Property BlockAlign As UInt16 ' Word 32 little == NumChannels * BitsPerSample/8
Public Property BitsPerSample As UInt16 ' Word 34 little 8 bits = 8, 16 bits = 16, etc.
End Structure
Structure DataSubChunk
Public Property Subchunk2ID As Byte() ' Dword 36 Big Contains the letters "data"(0x64617461 big-endian form).
Public Property Subchunk2Size As UInt32 ' Dword 40 little == NumSamples * NumChannels * BitsPerSample/8 This is the number of bytes in the data.
Public Property Data As Byte() ' VariableLength 44 little The actual sound data.
End Structure
Public Sub LoadFromFile(ByVal FileName As String)
If Not My.Computer.FileSystem.FileExists(FileName) Then Exit Sub
Dim FileBytes() As Byte = My.Computer.FileSystem.ReadAllBytes(FileName)
Try
Me.FileHeader.ChunkID = GetDataFromByteArray(FileBytes, 0, 0, 4)
Me.FileHeader.ChunkSize = BitConverter.ToUInt32(FileBytes, 4)
Me.FileHeader.Format = GetDataFromByteArray(FileBytes, 0, 8, 4)
Me.FileFormatSubChunk.Subchunk1ID = GetDataFromByteArray(FileBytes, 0, 12, 4)
Me.FileFormatSubChunk.Subchunk1Size = BitConverter.ToUInt32(FileBytes, 16)
Me.FileFormatSubChunk.AudioFormat = BitConverter.ToUInt16(FileBytes, 20)
Me.FileFormatSubChunk.NumChannels = BitConverter.ToUInt16(FileBytes, 22)
Me.FileFormatSubChunk.SampleRate = BitConverter.ToUInt32(FileBytes, 24)
Me.FileFormatSubChunk.ByteRate = BitConverter.ToUInt32(FileBytes, 28)
Me.FileFormatSubChunk.BlockAlign = BitConverter.ToUInt16(FileBytes, 32)
Me.FileFormatSubChunk.BitsPerSample = BitConverter.ToUInt16(FileBytes, 34)
Me.FileDataSubChunk.Subchunk2ID = GetDataFromByteArray(FileBytes, 0, 36, 4)
Me.FileDataSubChunk.Subchunk2Size = BitConverter.ToUInt32(FileBytes, 40)
Me.FileDataSubChunk.Data = GetDataFromByteArray(FileBytes, 0, 44, Me.FileDataSubChunk.Subchunk2Size)
Catch
Throw New Exception("File Is Invalid or corrupt!")
End Try
End Sub
Public Function GetBytes() As Byte()
Dim Results As Byte() = Nothing
Results = CombineArrays(FileHeader.ChunkID, BitConverter.GetBytes(FileHeader.ChunkSize))
Results = CombineArrays(Results, FileHeader.Format)
Results = CombineArrays(Results, FileFormatSubChunk.Subchunk1ID)
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.Subchunk1Size))
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.AudioFormat))
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.NumChannels))
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.SampleRate))
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.ByteRate))
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.BlockAlign))
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.BitsPerSample))
Results = CombineArrays(Results, FileDataSubChunk.Subchunk2ID)
Results = CombineArrays(Results, BitConverter.GetBytes(FileDataSubChunk.Subchunk2Size))
Results = CombineArrays(Results, FileDataSubChunk.Data)
Return Results
End Function
Function CombineArrays(ByVal Array1() As Byte, ByVal Array2() As Byte) As Byte()
Dim AllResults(Array1.Length + Array2.Length - 1) As Byte
Array1.CopyTo(AllResults, 0)
Array2.CopyTo(AllResults, Array1.Length)
Return AllResults
End Function
Private Function GetDataFromByteArray(ByVal ByteArray As Byte(), ByVal BlockOffset As Long, ByVal RangeStartOffset As Long, ByVal DataLength As Long) As Byte()
On Error Resume Next
Dim AnswerL As New List(Of Byte)
Dim Answer(0 To CInt((DataLength - 1))) As Byte
Dim CurrentOffset As Long
For I = 0 To UBound(ByteArray)
CurrentOffset = BlockOffset + I
If CurrentOffset >= RangeStartOffset Then
If CurrentOffset <= RangeStartOffset + DataLength Then
AnswerL.Add(ByteArray(I))
End If
End If
Next
Dim count As Integer = -1
For Each bt As Byte In AnswerL
count = count + 1
Answer(count) = bt
Next
Return Answer
End Function
Sub New(Optional ByVal Options As WaveFileOptions = Nothing)
Try
FileHeader.ChunkID = Encoding.ASCII.GetBytes("RIFF")
FileFormatSubChunk.Subchunk1Size = Options.FormatSize
FileFormatSubChunk.NumChannels = Options.NumberOfChannels
FileFormatSubChunk.BitsPerSample = Options.BitsPerSample
FileDataSubChunk.Subchunk2Size = CUInt(Options.NumberOfSamples * Options.NumberOfChannels * Options.BitsPerSample / 8)
FileHeader.ChunkSize = CUInt(4 + (8 + FileFormatSubChunk.Subchunk1Size) + (8 + FileDataSubChunk.Subchunk2Size))
FileHeader.Format = Encoding.ASCII.GetBytes("WAVE")
FileFormatSubChunk.Subchunk1ID = Encoding.ASCII.GetBytes("fmt ")
FileFormatSubChunk.AudioFormat = Options.AudioFormat
FileFormatSubChunk.SampleRate = Options.SampleRate
FileFormatSubChunk.ByteRate = CUInt(Options.SampleRate * Options.NumberOfChannels * Options.BitsPerSample / 8)
FileFormatSubChunk.BlockAlign = CUShort(Options.NumberOfChannels * Options.BitsPerSample / 8)
FileDataSubChunk.Subchunk2ID = Encoding.ASCII.GetBytes("data")
FileDataSubChunk.Data = Options.Data
Catch ex As Exception
End Try
End Sub
Public Enum WavSampleRate As UInt32
hz8000 = 8000
hz11025 = 11025
hz16000 = 16000
hz22050 = 22050
hz32000 = 32000
hz44100 = 44100
hz48000 = 48000
hz96000 = 96000
hz192000 = 192000
End Enum
Public Enum Format As UInt16
Standard = 1
End Enum
Public Enum BitsPerSample As UInt16
bps_8 = 8
bps_16 = 16
bps_32 = 32
bps_64 = 64
bps_128 = 128
bps_256 = 256
End Enum
Public Enum NumberOfChannels As UInt16
Mono = 1
Stereo = 2
End Enum
Public Enum FormatSize As UInt32
PCM = 16
End Enum
End Class
References
- https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
- MSDN Forums - http://social.msdn.microsoft.com/Forums/en-US/categories