Share via


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

See also

Please check out my other Technet Wiki articles!