Page 1 of 1
Get WAV Attributes (length, rate, ...)
Posted: Tue May 03, 2011 5:24 am
by kenmo
I'm surprised that the native PB sound library doesn't have any functions for analyzing a loaded sound...
So for my own purposes, I pulled together bits and pieces of code, and wrote:
CatchWavAttribute(*WAV.i, Attribute.i) and
LoadWavAttribute(File.s, Attribute.i)
(in the style of CatchSound and LoadSound). All constants and return values are described in the code.
Note: this currently works ONLY with files of the most basic PCM format. (No FLAC, OGG, etc.)
Code: Select all
; +-------------------+-------+
; | WavAttributes.pbi | kenmo |
; +-------------------+-------+
; | 5.02.2011 - Version 1.0
; | 6.01. - Version 1.1 (removed a debug, fixed Samples attribute)
;-
;- WAV Constants
; _Attribute _Value _Description _Units
#WAV_BitDepth = $00 ; Sample depth * bits / sample
#WAV_BitRate = $01 ; Total data rate bits / second
#WAV_ByteDepth = $02 ; Sample depth * bytes / sample
#WAV_ByteRate = $03 ; Total data rate bytes / second
#WAV_Channels = $04 ; Number of channels channels
#WAV_ChunkSize = $05 ; Total audio data size bytes
#WAV_Format = $06 ; File format PCM or Unknown
#WAV_Milliseconds = $07 ; Total audio length milliseconds
#WAV_SampleRate = $08 ; Sample rate * samples / second
#WAV_Samples = $09 ; Number of samples * samples
#WAV_Seconds = $0A ; Total audio length seconds
; * refers to one channel only
; Return Values
#WAV_PCM = 0
#WAV_Unknown = -1
#WAV_NoFile = -2
#WAV_ReadFail = -3
#WAV_NoBuffer = -4
;-
;- WAV Procedures
Procedure.i CatchWavAttribute(*WAV.i, Attribute.i)
Protected Value.i = #WAV_Unknown
If (*Wav)
If ((PeekL(*Wav) = 'FFIR') And (PeekL(*Wav + 12) = ' tmf') And (PeekL(*Wav + 36) = 'atad'))
Select (Attribute)
Case #WAV_BitDepth
Value = PeekU(*WAV + 34)
Case #WAV_BitRate
Value = PeekL(*WAV + 28)<<3
Case #WAV_ByteDepth
Value = PeekU(*WAV + 34)>>3
Case #WAV_ByteRate
Value = PeekL(*WAV + 28)
Case #WAV_Channels
Value = PeekU(*WAV + 22)
Case #WAV_ChunkSize
Value = PeekL(*WAV + 40)
Case #WAV_Format
Value = #WAV_PCM
Case #WAV_Milliseconds
Value = PeekL(*WAV + 40) / (PeekL(*Wav + 28) / 100) * 10
Case #WAV_Samples
Value = PeekL(*WAV + 40) / PeekU(*Wav + 32)
Case #WAV_SampleRate
Value = PeekL(*WAV + 24)
Case #WAV_Seconds
Value = PeekL(*WAV + 40) / PeekL(*Wav + 28)
EndSelect
EndIf
EndIf
ProcedureReturn (Value)
EndProcedure
Procedure.i LoadWavAttribute(File.s, Attribute.i)
Protected Value.i = #WAV_NoFile
Protected FID.i = #Null
Protected *Buffer.i = #Null
If (File)
FID = ReadFile(#PB_Any, File)
If (FID)
*Buffer = AllocateMemory(44)
If (*Buffer)
If (ReadData(FID, *Buffer, 44) = 44)
Value = CatchWavAttribute(*Buffer, Attribute)
Else
Value = #WAV_ReadFail
EndIf
FreeMemory(*Buffer)
Else
Value = #WAV_NoBuffer
EndIf
CloseFile(FID)
Else
Value = #WAV_ReadFail
EndIf
EndIf
ProcedureReturn (Value)
EndProcedure
;-
; EOF
and an example:
Code: Select all
XIncludeFile "WavAttributes.pbi"
File.s = OpenFileRequester("Open WAV", "", "WAV Files|*.wav|All Files|*.*", 0)
If (File)
Debug "File: " + GetFilePart(File)
Debug ""
Format.i = LoadWavAttribute(File, #WAV_Format)
If (Format = #WAV_Unknown)
Debug "WAV_Format: Unknown"
ElseIf (Format < 0)
Debug "Load Error: " + Str(Format)
Else
Select (Format)
Case #WAV_PCM
Debug "WAV_Format: PCM"
EndSelect
Debug "WAV_SampleRate: " + Str(LoadWavAttribute(File, #WAV_SampleRate ))
Debug "WAV_BitDepth: " + Str(LoadWavAttribute(File, #WAV_BitDepth ))
Debug "WAV_ByteDepth: " + Str(LoadWavAttribute(File, #WAV_ByteDepth ))
Debug "WAV_Channels: " + Str(LoadWavAttribute(File, #WAV_Channels ))
Debug "WAV_BitRate: " + Str(LoadWavAttribute(File, #WAV_BitRate ))
Debug "WAV_ByteRate: " + Str(LoadWavAttribute(File, #WAV_ByteRate ))
Debug "WAV_ChunkSize: " + Str(LoadWavAttribute(File, #WAV_ChunkSize ))
Debug "WAV_Samples: " + Str(LoadWavAttribute(File, #WAV_Samples ))
Debug "WAV_Milliseconds: " + Str(LoadWavAttribute(File, #WAV_Milliseconds))
Debug "WAV_Seconds: " + Str(LoadWavAttribute(File, #WAV_Seconds ))
EndIf
EndIf
Should come in handy once in a while!
* edit: got rid of a Debug that shouldn't have been left in the procedure
* edit June 1, 2011: (fixed Total # Samples bug)
Re: Get WAV Attributes (length, rate, ...)
Posted: Tue May 03, 2011 8:47 am
by c4s
kenmo wrote:Should come in handy once in a while!
Indeed!
Thank you.
Re: Get WAV Attributes (length, rate, ...)
Posted: Thu Jun 02, 2011 2:04 am
by kenmo
Fixed a (important) bug (in calculating the total number of samples) in case anyone is using this!
Re: Get WAV Attributes (length, rate, ...)
Posted: Thu Jun 02, 2011 10:12 am
by c4s
I'm going to use it soon, thanks!
Edit:
Is
PeekL(*WAV + 40) / PeekU(*Wav + 32) correct or should it be
PeekU(*WAV + 40) / PeekU(*Wav + 32)?
And I think Line 8 ("
;- WAV ConFileants") is wrong...

Re: Get WAV Attributes (length, rate, ...)
Posted: Thu Jun 02, 2011 6:54 pm
by kenmo
Whoops, a rogue find/replace changed that comment.
But the PeekL and PeekU are correct:
- the value at offset 40 is NumSamples * NumChannels * BytesPerSample (32-bit value)
- the value at offset 32 is NumChannels * BytesPerSample (16-bit value)
So the quotient is just NumSamples.
See (
here), one of many useful references.
Also, a hint: For simplicity, the Load procedure opens/reads/closes a .wav file every time you call it. For efficiency (if you are reading many attributes on the same file) it would be better to read the first 44 bytes of the file into your own buffer, then call the Catch procedure on this pointer. The rest of the file (the actual audio data) doesn't need to be included.
Re: Get WAV Attributes (length, rate, ...)
Posted: Sat Jun 11, 2011 7:04 pm
by chris319
Hi Kenmo -
As you will discover, properly analyzing a wav file is not a trivial undertaking. Unfortunately, the format given at stanford.edu is obsolete as it does not take into account files which use the WAVEFORMATEXTENSIBLE format.
A valid wav file will have a WAVEFORMATEX structure but it may or may not have the two-byte cbSize variable; thus, the WAVEFORMATEX structure itself may be 16 or 18 bytes in length. In addition, it may or may not have a WAVEFORMATEXTENSIBLE structure which is cbSize (usually 22) bytes in length, including a 16-byte GUID. This will throw off the location of the "data" string (subchunk2ID). For these reasons, my modified version only looks at the "RIFF" and "fmt " strings. In addition, I convert these strings to lower case as there is no requirement that I'm aware of that they be in a particular case. In a file you could encounter either case.
There is much more to do but this is a start.
Code: Select all
; +-------------------+-------+
; | WavAttributes.pbi | kenmo |
; +-------------------+-------+
; | 5.02.2011 - Version 1.0
; | 6.01. - Version 1.1 (removed a debug, fixed Samples attribute)
; | 6.11.2011 - Version 1.2 (modified by chris319 to accomodate cbSize varaible and
; incorporated case conversion of "RIFF", "fmt " and
; "data" strings - this version is still incomplete)
;-
;- WAV Constants
; _Attribute _Value _Description _Units
#WAV_BitDepth = $00 ; Sample depth * bits / sample
#WAV_BitRate = $01 ; Total data rate bits / second
#WAV_ByteDepth = $02 ; Sample depth * bytes / sample
#WAV_ByteRate = $03 ; Total data rate bytes / second
#WAV_Channels = $04 ; Number of channels channels
#WAV_ChunkSize = $05 ; Total audio data size bytes
#WAV_Format = $06 ; File format PCM or Unknown
#WAV_Milliseconds = $07 ; Total audio length milliseconds
#WAV_SampleRate = $08 ; Sample rate * samples / second
#WAV_Samples = $09 ; Number of samples * samples
#WAV_Seconds = $0A ; Total audio length seconds
; * refers to one channel only
; Return Values
#WAV_PCM = 0
#WAV_Unknown = -1
#WAV_NoFile = -2
#WAV_ReadFail = -3
#WAV_NoBuffer = -4
;-
;- WAV Procedures
Procedure.i CatchWavAttribute(*WAV.i, Attribute.i)
Protected Value.i = #WAV_Unknown
If (*Wav)
riff$ = PeekS(*Wav, 4): fmt$ = PeekS(*Wav + 12, 4) ;: data1$ = PeekS(*Wav + 36, 4): data2$ = PeekS(*Wav + 38, 4)
If LCase(riff$) = "riff" And LCase(fmt$) = "fmt " ;And (LCase(data1$) = "data" Or LCase(data2$) = "data")
Select (Attribute)
Case #WAV_BitDepth
Value = PeekU(*WAV + 34)
Case #WAV_BitRate
Value = PeekL(*WAV + 28)<<3
Case #WAV_ByteDepth
Value = PeekU(*WAV + 34)>>3
Case #WAV_ByteRate
Value = PeekL(*WAV + 28)
Case #WAV_Channels
Value = PeekU(*WAV + 22)
Case #WAV_ChunkSize
Value = PeekL(*WAV + 40)
Case #WAV_Format
Value = #WAV_PCM
Case #WAV_Milliseconds
Value = PeekL(*WAV + 40) / (PeekL(*Wav + 28) / 100) * 10
Case #WAV_Samples
Value = PeekL(*WAV + 40) / PeekU(*Wav + 32)
Case #WAV_SampleRate
Value = PeekL(*WAV + 24)
Case #WAV_Seconds
Value = PeekL(*WAV + 40) / PeekL(*Wav + 28)
EndSelect
EndIf
EndIf
ProcedureReturn (Value)
EndProcedure
Procedure.i LoadWavAttribute(File.s, Attribute.i)
Protected Value.i = #WAV_NoFile
Protected FID.i = #Null
Protected *Buffer.i = #Null
If (File)
FID = ReadFile(#PB_Any, File)
If (FID)
*Buffer = AllocateMemory(44)
If (*Buffer)
If (ReadData(FID, *Buffer, 44) = 44)
Value = CatchWavAttribute(*Buffer, Attribute)
Else
Value = #WAV_ReadFail
EndIf
FreeMemory(*Buffer)
Else
Value = #WAV_NoBuffer
EndIf
CloseFile(FID)
Else
Value = #WAV_ReadFail
EndIf
EndIf
ProcedureReturn (Value)
EndProcedure
;-
; EOF
Code: Select all
XIncludeFile "WavAttributes.pbi"
File.s = OpenFileRequester("Open WAV", "", "WAV Files|*.wav|All Files|*.*", 0)
If (File)
Debug "File: " + GetFilePart(File)
Format.i = LoadWavAttribute(File, #WAV_Format)
If (Format = #WAV_Unknown)
Debug "WAV_Format: Unknown"
ElseIf (Format < 0)
Debug "Load Error: " + Str(Format)
Else
Debug "Valid wav file": Debug ""
Select (Format)
Case #WAV_PCM
Debug "WAV_Format: PCM"
EndSelect
Debug "WAV_SampleRate: " + Str(LoadWavAttribute(File, #WAV_SampleRate ))
Debug "WAV_BitDepth: " + Str(LoadWavAttribute(File, #WAV_BitDepth ))
Debug "WAV_ByteDepth: " + Str(LoadWavAttribute(File, #WAV_ByteDepth ))
Debug "WAV_Channels: " + Str(LoadWavAttribute(File, #WAV_Channels ))
Debug "WAV_BitRate: " + Str(LoadWavAttribute(File, #WAV_BitRate ))
Debug "WAV_ByteRate: " + Str(LoadWavAttribute(File, #WAV_ByteRate ))
Debug "WAV_ChunkSize: " + Str(LoadWavAttribute(File, #WAV_ChunkSize ))
Debug "WAV_Samples: " + Str(LoadWavAttribute(File, #WAV_Samples ))
Debug "WAV_Milliseconds: " + Str(LoadWavAttribute(File, #WAV_Milliseconds))
Debug "WAV_Seconds: " + Str(LoadWavAttribute(File, #WAV_Seconds ))
EndIf
EndIf
Here is some recommended reading on the WAVEFORMATEX and WAVEFORMATEXTENSIBLE structures:
http://msdn.microsoft.com/en-us/library ... 85%29.aspx
http://msdn.microsoft.com/en-us/library ... 85%29.aspx
Re: Get WAV Attributes (length, rate, ...)
Posted: Mon Mar 10, 2014 10:14 am
by doctornash
might I request for this to be extended please to load the actual sample values of the .wav file into an array?
Re: Get WAV Attributes (length, rate, ...)
Posted: Sat Mar 15, 2014 4:50 am
by kenmo
Sure, that is easy as long as you are working with bare-bones WAV files (as chris319 said, the format can get more complicated).
The samples are stored as integers (8 or 16 bit) but it's easy to normalize them to floats from -1 to +1 if you want. I can write an example for you.
Re: Get WAV Attributes (length, rate, ...)
Posted: Sat Mar 15, 2014 10:37 am
by doctornash
Kenmo 'bare bones' is sufficient, so yes please an example would be fabulous!

Re: Get WAV Attributes (length, rate, ...)
Posted: Sun Mar 16, 2014 9:17 pm
by kenmo
This is quick'n'dirty (it's thrown together from some WAV programs I had) and it's not exactly what you asked for (doesn't load the samples into an array, instead they are stored in a memory block as doubles, but you can still step through them).........
It should get you started at loading / analyzing / editing / saving basic 16-bit WAV files.
Code: Select all
;
; Read/Create/Edit/Save WAV files
; by kenmo
; 3/16/2014
;
;-
;- Structures
Structure STDWAV
ChunkID.l
ChunkSize.l
Format.l
;
Subchunk1ID.l
Subchunk1Size.l
AudioFormat.u
NumChannels.u
SampleRate.l
ByteRate.l
BlockAlign.u
BitsPerSample.u
;
Subchunk2ID.l
Subchunk2Size.l
EndStructure
Structure FULLWAVE
NumChannels.u
SampleRate.l
BitsPerSample.u
;
NumSamples.l
MemorySize.l
EndStructure
;-
;- Procedures
Procedure.i ReadFileToMemory(File.s)
Protected *Result = #Null
Protected FN.i = ReadFile(#PB_Any, File)
If (FN)
Protected n.i = Lof(FN)
If (n > 0)
*Result = AllocateMemory(n)
If (*Result)
If (ReadData(FN, *Result, n) <> n)
FreeMemory(*Result)
*Result = #Null
EndIf
EndIf
EndIf
CloseFile(FN)
EndIf
ProcedureReturn (*Result)
EndProcedure
Procedure.i LoadStdWav(File.s)
Protected *SW.STDWAV = #Null
Protected n.i = FileSize(File)
If (n > SizeOf(STDWAV))
*SW = ReadFileToMemory(File)
If (*SW)
Protected Valid.i = #True
Valid = Valid * Bool(*SW\ChunkID = 'FFIR')
Valid = Valid * Bool(*SW\ChunkSize <= n - 8)
Valid = Valid * Bool(*SW\Format = 'EVAW')
Valid = Valid * Bool(*SW\Subchunk1ID = ' tmf')
Valid = Valid * Bool(*SW\Subchunk1Size = 16)
Valid = Valid * Bool(*SW\AudioFormat = 1)
Valid = Valid * Bool(*SW\ByteRate = *SW\SampleRate * *SW\NumChannels * *SW\BitsPerSample / 8)
Valid = Valid * Bool(*SW\BlockAlign = *SW\NumChannels * *SW\BitsPerSample / 8)
Valid = Valid * Bool(*SW\BitsPerSample % 8 = 0)
Valid = Valid * Bool(*SW\Subchunk2ID = 'atad')
Valid = Valid * Bool(*SW\Subchunk2Size <= n - SizeOf(STDWAV))
If (Not Valid)
FreeMemory(*SW)
*SW = #Null
EndIf
EndIf
EndIf
ProcedureReturn (*SW)
EndProcedure
Procedure.i CreateFullWave(NumChannels.i, SampleRate.i, BitsPerSample.i, NumSamples.i)
Protected *FW.FULLWAVE = #Null
If ((NumChannels >= 1) And (SampleRate > 0) And (BitsPerSample % 8 = 0) And (NumSamples > 0))
Protected BlockAlign.i = NumChannels * (BitsPerSample / 8)
Protected n.i = SizeOf(FULLWAVE) + BlockAlign * NumSamples * SizeOf(DOUBLE)
*FW = AllocateMemory(n)
If (*FW)
*FW\NumChannels = NumChannels
*FW\SampleRate = SampleRate
*FW\BitsPerSample = BitsPerSample
*FW\NumSamples = NumSamples
*FW\MemorySize = n
EndIf
EndIf
ProcedureReturn (*FW)
EndProcedure
Procedure.i LoadFullWave(File.s)
Protected *FW.FULLWAVE = #Null
Protected *SW.STDWAV = LoadStdWav(File)
If (*SW)
Protected NumSamples.l = *SW\Subchunk2Size / (*SW\NumChannels * *SW\BitsPerSample / 8)
*FW = CreateFullWave(*SW\NumChannels, *SW\SampleRate, *SW\BitsPerSample, NumSamples)
If (*FW)
Protected Offset.d, Scaling.d
Protected c.i, i.i
Protected *Read, *Write
Select (*SW\BitsPerSample)
Case 16 ; 16-bit, -32768 to +32767
Scaling = 1.0 / 32767.5
Offset = 0.5
For c = 0 To *SW\NumChannels - 1
*Read = *SW + SizeOf(STDWAV) + c * 2
*Write = *FW + SizeOf(FULLWAVE) + c * NumSamples * SizeOf(DOUBLE)
For i = 0 To NumSamples - 1
PokeD(*Write, (PeekW(*Read) + Offset) * Scaling)
*Read + *SW\BlockAlign
*Write + SizeOf(DOUBLE)
Next i
Next c
Case 8 ; 8-bit, 0 to 255
Scaling = 1.0 / 127.5
Offset = -127.5
;
Default
;
EndSelect
EndIf
FreeMemory(*SW)
EndIf
ProcedureReturn (*FW)
EndProcedure
Procedure.i FullWaveSamplePointer(*FW.FULLWAVE, Channel.i)
Protected *Result = #Null
If (*FW And (Channel >= 0) And (Channel < *FW\NumChannels))
*Result = *FW + SizeOf(FULLWAVE) + Channel * (*FW\NumSamples * SizeOf(DOUBLE))
EndIf
ProcedureReturn (*Result)
EndProcedure
Procedure.i SaveWave(*FW.FULLWAVE, File.s)
Protected Result.i = #False
If (*FW And File)
Protected FN.i = CreateFile(#PB_Any, File)
If (FN)
Protected BlockAlign.i = (*FW\NumChannels * *FW\BitsPerSample / 8)
Protected SampleBytes.i = (*FW\NumSamples * BlockAlign)
WriteLong(FN, 'FFIR')
WriteLong(FN, 36 + SampleBytes)
WriteLong(FN, 'EVAW')
;
WriteLong(FN, ' tmf')
WriteLong(FN, 16)
WriteUnicodeCharacter(FN, 1)
WriteUnicodeCharacter(FN, *FW\NumChannels)
WriteLong(FN, *FW\SampleRate)
WriteLong(FN, *FW\SampleRate * BlockAlign)
WriteUnicodeCharacter(FN, BlockAlign)
WriteUnicodeCharacter(FN, *FW\BitsPerSample)
;
WriteLong(FN, 'atad')
WriteLong(FN, SampleBytes)
;
Protected Offset.d, Scaling.d
Protected c.i, i.i
Select (*FW\BitsPerSample)
Case 16
Scaling = 32767.5
Offset = 0.5
For i = 0 To *FW\NumSamples - 1
For c = 0 To *FW\NumChannels - 1
WriteWord(FN, Int(Scaling * PeekD(*FW + SizeOf(DOUBLE) * (i + c * *FW\NumSamples)) - Offset))
Next c
Next i
Case 8
;
Default
;
EndSelect
CloseFile(FN)
Result = #True
EndIf
EndIf
ProcedureReturn (Result)
EndProcedure
Procedure.i DuplicateFullWave(*FWI.FULLWAVE)
Protected *FWO.FULLWAVE = #Null
If (*FWI)
*FWO = AllocateMemory(*FWI\MemorySize)
If (*FWO)
CopyMemory(*FWI, *FWO, *FWI\MemorySize)
EndIf
EndIf
ProcedureReturn (*FWO)
EndProcedure
;-
;- Example Program
Structure DOUBLEBUFFER
d.d[0]
EndStructure
InFile.s = OpenFileRequester("Load WAV", GetHomeDirectory(), "WAV Files|*.wav", 0)
If (InFile)
*Wave.FULLWAVE = LoadFullWave(InFile)
If (*Wave)
*Sample.DOUBLEBUFFER = FullWaveSamplePointer(*Wave, 0)
Delta = *Wave\NumSamples / 1000
i = 0
While (i < *Wave\NumSamples)
Debug "Sample " + Str(i) + ": " + StrD(*Sample\d[i], 5)
i + Delta
Wend
FreeMemory(*Wave)
Else
Debug "WAV could not be loaded!"
EndIf
EndIf
;-
Re: Get WAV Attributes (length, rate, ...)
Posted: Fri Jun 06, 2014 4:32 am
by chris319
The samples are stored as integers (8 or 16 bit)
There can also be 24-bit samples. They are not contained within 32 bits, just three bytes together.
Re: Get WAV Attributes (length, rate, ...)
Posted: Fri Jun 06, 2014 9:32 am
by chris319
Hi Kenmo -
Your code fails on valid wav files.
A wav file checker is a good thing to have, but malformed wav files will not play or cannot be opened, so it is important that a file checker program get it right.
PureBasic already has WAVEFORMATEX and WAVEFORMATEXTENSIBLE structures built into it, so let's use them. Don't confuse the file header with these structures. They are not the same.
This code will get you started. The wav file format has been kludged to accomodate advances in audio. The WAVEFORMATEXTENSIBLE structure is for audio with more than 2 channels or samples larger than 16 bits.
To find the audio data, search for the subchunk2ID string "data", then advance 4 more bytes to get past subchunk2Size.
Code: Select all
; Read WAV files
; original code by kenmo
; fixes started by chris319 ; 6/5/2014
OpenConsole()
Structure FILEHEADER
ChunkID.s{4}
ChunkSize.l
Format.s{4}
Subchunk1ID.s{4}
Subchunk1Size.l
;START OF WAVEFORMATEX or WAVEFORMATEXTENSIBLE STRUCTURE
wFormatTag.w
nChannels.w
nSamplesPerSec.l
nAvgBytesPerSec.l
nBlockAlign.w
wBitsPerSample.w
cbSize.w
EndStructure
myFH.FILEHEADER
InFile.s = OpenFileRequester("Load WAV", GetHomeDirectory(), "WAV Files|*.wav", 0)
If InFile = "": End: EndIf
ReadFile(0,InFile)
ReadData(0, @myFH, SizeOf(myFH))
CloseFile(0)
PrintN(GetFilePart(InFile) + Chr(10))
PrintN("ChunkID: " + myFH\chunkID)
;PrintN("ChunkSize: " + Str(myFH\ChunkSize))
PrintN("Format: " + myFH\Format)
PrintN("SubChunk1ID: " + myFH\Subchunk1ID)
Print("Chunk1Size: " + Str(myFH\Subchunk1Size))
If myFH\Subchunk1Size <> 18
PrintN(" Old file format.")
EndIf
If myFH\cbSize = 22
PrintN("WAVEFORMATEXTENSIBLE")
PrintN("cbSize: " + Str(myFH\cbSize))
EndIf
PrintN("Channels: " + Str(myFH\nChannels))
PrintN("Samples per second: " + Str(myFH\nSamplesPerSec))
PrintN("Average bytes per second: " + Str(myFH\nAvgBytesPerSec))
PrintN("Block align: " + Str(myFH\nBlockAlign))
PrintN("Bits per sample: " + Str(myFH\wBitsPerSample))
If cbSize = 22: PrintN("cbSize: " + Str(myFH\cbSize)): EndIf
If myFH\nChannels > 2 Or myFH\wBitsPerSample > 16: PrintN("WAVEFORMATEXTENSIBLE" + Chr(10)): EndIf
Repeat
Delay(100)
ForEver
Re: Get WAV Attributes (length, rate, ...)
Posted: Sun Jun 08, 2014 7:36 am
by chris319
This code reports an error if a file has > 2 channels or > 16-bit samples and does not contain a proper cbSize field or if subchunk1size is incorrect.
Code: Select all
; Read WAV files
; original code by kenmo
; fixes started by chris319 ; 6/5/2014
OpenConsole()
Structure WAVEFILEHEADER
ChunkID.s{4}
ChunkSize.l
Format.s{4}
Subchunk1ID.s{4}
Subchunk1Size.l
;START OF WAVEFORMATEX or WAVEFORMATEXTENSIBLE STRUCTURE
wFormatTag.w
nChannels.w
nSamplesPerSec.l
nAvgBytesPerSec.l
nBlockAlign.w
wBitsPerSample.w
cbSize.w
EndStructure
myFH.WAVEFILEHEADER
InFile.s = OpenFileRequester("Load WAV", GetHomeDirectory(), "WAV Files|*.wav", 0)
If InFile = "": End: EndIf
ReadFile(0,InFile)
ReadData(0, @myFH, SizeOf(myFH))
CloseFile(0)
PrintN("File name: " + GetFilePart(InFile) + Chr(10))
PrintN("ChunkID: " + myFH\chunkID)
;PrintN("ChunkSize: " + Str(myFH\ChunkSize))
PrintN("Format: " + myFH\Format)
PrintN("SubChunk1ID: " + myFH\Subchunk1ID)
Print("Chunk1Size: " + Str(myFH\Subchunk1Size))
If myFH\Subchunk1Size <> 18
PrintN(" Obsolete wav file format.")
EndIf
If myFH\cbSize = 22
PrintN("WAVEFORMATEXTENSIBLE")
PrintN("cbSize: " + Str(myFH\cbSize))
EndIf
PrintN("Channels: " + Str(myFH\nChannels))
PrintN("Samples per second: " + Str(myFH\nSamplesPerSec))
PrintN("Average bytes per second: " + Str(myFH\nAvgBytesPerSec))
PrintN("Block align: " + Str(myFH\nBlockAlign))
PrintN("Bits per sample: " + Str(myFH\wBitsPerSample))
If cbSize = 22: PrintN("cbSize: " + Str(myFH\cbSize)): EndIf
If myFH\nChannels > 2 Or myFH\wBitsPerSample > 16: PrintN("WAVEFORMATEXTENSIBLE" + Chr(10)): EndIf
If (myFH\nChannels > 2 Or myFH\wBitsPerSample > 16) And (myFH\cbSize <> SizeOf(WAVEFORMATEXTENSIBLE) - SizeOf(WAVEFORMATEX) Or (myFH\Subchunk1Size <> 18))
PrintN("ERROR: This file is not compliant with wav file specifications.")
EndIf
Repeat
Delay(100)
ForEver