Quote Originally Posted by dreammanor View Post
The function that I want to realize now is:
How to use mmioRead to read a piece of wave data into a byte-array.
I guess it should be done with array-pointer.

Edit:
I think of another way, that is, write the file-header to buffer1, then write the wave data to buffer2, and then merge buffer1 and buffer2 into buffer3 (or attach buffer2 to buffer1). But in this case, the speed will be much slower.
A few years ago, I wrote a little WavInfo-Class, which works (RC5-) Stream-Based -
and it parses out all the Info from a *.wav-file without using the mmio-API.

Beside the usual Wav-Format-Fields, it also gives reliable info about the Offset to the real PCM-Data
(which does not necessarily need to start at offset 44).

Here it is (I named it cWavInfo):
Code:
Option Explicit 'RC5-cStream-based Wav-info-reader (Author Olaf Schmidt, 2012)

'precalculated FourCCs
Private Const RIFF As Long = &H46464952, Wave As Long = &H45564157
Private Const data As Long = &H61746164, FMT_ As Long = &H20746D66

Private Type tRiffChunk
  ID As Long
  Size As Long
End Type
Private Type tWaveHeader
  RiffChunk As tRiffChunk
  RiffChunkFormat As Long
  RiffSubChunk As tRiffChunk
  WaveAudioFormat As Integer
  WaveNumChannels As Integer
  WaveSampleRate As Long
  WaveByteRate As Long
  WaveBlockAlign As Integer
  WaveBitsPerSample As Integer
  cbSize   As Integer
  wValidBitsPerSample   As Integer
  dwChannelMask   As Long
  SubFormat(0 To 7) As Integer
End Type

Private Header As tWaveHeader
Private mWaveMSec As Long, mWaveSamples As Long, mWaveDataOffs As Long, mWaveDataLen As Long

Public Sub ReadWaveInfoFromStream(Strm As cStream)
Dim Pos As Long, RiffChunk As tRiffChunk, EmptyHeader As tWaveHeader
  Header = EmptyHeader
  mWaveMSec = 0:     mWaveSamples = 0
  mWaveDataOffs = 0: mWaveDataLen = 0
   Strm.SetPosition 0
   Strm.ReadToPtr VarPtr(Header), Len(Header)
   If Header.RiffChunk.ID <> RIFF Then Err.Raise vbObjectError, , "The file is not in RIFF format."
   If Header.RiffChunkFormat <> Wave Then Err.Raise vbObjectError, , "The file is in RIFF format but is not a WAVE file."

   Do Until Header.RiffSubChunk.ID = FMT_
      Pos = Pos + Len(RiffChunk) + Header.RiffSubChunk.Size
      If Pos <= 0 Or Pos >= Strm.GetSize Then Err.Raise vbObjectError, , "The file is a WAVE file, but the header is corrupt."
      Strm.SetPosition Pos
      Strm.ReadToPtr VarPtr(Header), Len(Header)
   Loop

   Strm.SetPosition Pos + 20 + Header.RiffSubChunk.Size
   Strm.ReadToPtr VarPtr(RiffChunk), Len(RiffChunk)

   Do Until RiffChunk.ID = data
     Strm.SetPosition RiffChunk.Size, STRM_SeekFromCurPos
     If Strm.GetPosition = Strm.GetSize Then Err.Raise vbObjectError, , "The file is in RIFF format but is not a WAVE file."
     Strm.ReadToPtr VarPtr(RiffChunk), Len(RiffChunk)
   Loop
   
   If Header.RiffSubChunk.Size = 40 Then
     Header.WaveAudioFormat = Header.SubFormat(0)
   Else
     Header.wValidBitsPerSample = Header.WaveBitsPerSample
   End If
   
   mWaveDataLen = RiffChunk.Size
   mWaveDataOffs = Strm.GetPosition
    
   mWaveSamples = mWaveDataLen / Header.WaveNumChannels / (Header.WaveBitsPerSample / 8)
   mWaveMSec = (mWaveSamples / Header.WaveSampleRate) * 1000
End Sub
 
Public Property Get AudioFormat() As Long
  AudioFormat = Header.WaveAudioFormat
End Property
Public Property Get AudioFormatString() As String
  AudioFormatString = Choose(AudioFormat + 1, "Unknown", "PCM", "ADPCM", "IEEE_FLOAT")
End Property

Public Property Get Channels() As Integer
  Channels = Header.WaveNumChannels
End Property

Public Property Get SampleRate() As Long
  SampleRate = Header.WaveSampleRate
End Property

Public Property Get ByteRate() As Long
  ByteRate = Header.WaveByteRate
End Property
 
Public Property Get BitsPerSample() As Integer
  BitsPerSample = Header.WaveBitsPerSample
End Property

Public Property Get BlockAlign() As Integer
  BlockAlign = Header.WaveBlockAlign
End Property

Public Property Get ValidBitsPerSample() As Integer
  ValidBitsPerSample = Header.wValidBitsPerSample
End Property

Public Property Get Samples() As Long
  Samples = mWaveSamples
End Property

Public Property Get DataOffs() As Long
  DataOffs = mWaveDataOffs
End Property
Public Property Get DataLen() As Long
  DataLen = mWaveDataLen
End Property
Public Property Get DataLenSec() As Double
  DataLenSec = mWaveMSec / 1000
End Property
Public Property Get DataLen_msec() As Long
  DataLen_msec = mWaveMSec
End Property
And if your intent is, to describe (and later play) shorter "Selection-Snippets" from a larger Wav-File,
you could use a cSelection-Class like the following (which has 4 Read/Write-Props and 2 "calculated ones"):

Code:
Option Explicit

Public StreamTotalLengthSec As Double, StartPerc As Double, EndPerc As Double, Text As String
 
Public Property Get StreamOffsetSeconds() As Double
  StreamOffsetSeconds = StartPerc * StreamTotalLengthSec
End Property

Public Property Get LengthSeconds() As Double
  LengthSeconds = EndPerc * StreamTotalLengthSec - StreamOffsetSeconds
End Property
Well, once you're "armed" with the two little Classes above, the remaining Form-Demo-Code becomes as simple as that:
(define a Wav-File of your choice in Form_Load, and then click the Form).
Code:
Option Explicit
 
Private Declare Function PlaySound& Lib "winmm" (data As Any, Optional ByVal hMod&, Optional ByVal Flags& = 5)

Private Stream As cStream, WavInfo As New cWavInfo

Private Sub Form_Load()
  Set Stream = New_c.FSO.OpenFileStream("c:\temp\SampleLoop.wav")
  WavInfo.ReadWaveInfoFromStream Stream
End Sub
 
Private Sub Form_Click()
  'init a Selection-Object with the Duration from cWavInfo and a Percent-Range
  Dim Sel As New cSelection
      Sel.StreamTotalLengthSec = WavInfo.DataLenSec
      Sel.StartPerc = 0.15
      Sel.EndPerc = 0.35
      
  'now play the selection-snippet
  PlaySelection Sel, WavInfo
End Sub

Public Sub PlaySelection(Sel As cSelection, WavInfo As cWavInfo)
  If Sel Is Nothing Or Stream Is Nothing Then Exit Sub
  With WavInfo
    Dim B() As Byte: B = "" 'init B to an empty Array
    Stream.SetPosition .DataOffs + Int(Sel.StreamOffsetSeconds * .SampleRate) * .BlockAlign
    Stream.ReadToByteArr B, Int(Sel.LengthSeconds * .SampleRate) * .BlockAlign
    PlayWavBuf .SampleRate, .Channels, .BitsPerSample, B
  End With
End Sub

Public Sub PlayWavBuf(ByVal Freq As Long, ByVal Channels As Long, ByVal Bits As Long, WavBuf() As Byte)
  PlaySound ByVal 0& 'cancel any (potentially) still asynchronously playing sounds
  Static B() As Byte
  Dim WavBufLen As Long, Strm As cStream
      WavBufLen = UBound(WavBuf) + 1
  
  Set Strm = New_c.Stream 'let's create an InMemory-Stream
      Strm.WriteFromByteArr StrConv("RIFF    WAVEfmt                     data    ", vbFromUnicode)
      Strm.WriteFromByteArr WavBuf
      Strm.SetPosition 4:  Strm.WriteFromPtr VarPtr(WavBufLen + 36), 4 'FileSize (without the 8 Riff-Hdr-Bytes)
      Strm.SetPosition 16: Strm.WriteFromPtr VarPtr(16&), 4            'Format-Data-Length
      Strm.WriteFromPtr VarPtr(1 + 65536 * Channels), 4                'PCM=1 + Channels
      Strm.WriteFromPtr VarPtr(Freq), 4                                'Samples per second
      Strm.WriteFromPtr VarPtr(Freq * Channels * Bits \ 8), 4          'Bytes per second
      Strm.WriteFromPtr VarPtr(Channels * Bits \ 8 + 65536 * Bits), 4  'Bytes per Sample + Bits
      Strm.SetPosition 40: Strm.WriteFromPtr VarPtr(WavBufLen), 4      'Wav-Data-length
      Strm.SetPosition 0 'prepare for a re-read of the whole stream (now including the header)
   If Strm.ReadToByteArr(B) Then PlaySound B(0) 'read and finally play the (now wav-hdr-prefixed) buffer
End Sub
 
Private Sub Form_Terminate()
  PlaySound ByVal 0& 'cancel any (potentially) still asynchronously playing sounds
  New_c.CleanupRichClientDll
End Sub
The above PlaySelection-Function (which works in conjunction with the WavInfo-Class and the RC5-cStream-Class),
answers a lot of your recent questions I assume.

HTH

Olaf