[bb] .wav samples value by Flanker [ 9 months ago ]

Started by BlitzBot, June 29, 2017, 00:28:42

Previous topic - Next topic

BlitzBot

Title : .wav samples value
Author : Flanker
Posted : 9 months ago

Description : Load a .wav audio file with :
sound = WaveLoad("music.wav")
Then you can access to any sample value with the function :
value = WaveSample(time)
Time is the time in millisecs from the beginning of the wav file. An optional channel parameter let you choose wich channel sample you want.

It only works with 16bits or 8bits stereo or mono PCM .wav files ! Blitz3D doesn't handle 24 and 32 bits audio, and doesn't work well with more than 2 channels. [/i]

Code :
Code (blitzbasic) Select
Graphics 800,600,32,2
SetBuffer BackBuffer()

; variables
Global wavBank
Global wavChannels
Global wavFrequency
Global wavBytePerSec
Global wavBytePerBloc
Global wavBits
Global wavDataSize

Print "Loading .wav...":Flip
Global wavSound = WaveLoad("test16bits.wav") ; ONLY WORKS WITH MONO AND STEREO WAV 8 OR 16 BITS

PlaySound wavSound
wavStartTime = MilliSecs()

;------------------------------------------------------------------------------------;
While Not KeyHit(1)

Cls

; waveform
wavCurrentTime = MilliSecs()-wavStartTime
For channel = 0 To wavChannels-1
For i = 0 To 800
Plot i,75+channel*150+WaveSample(wavCurrentTime+i,channel)/500
Next
Next

Flip 0

Wend
;------------------------------------------------------------------------------------;

FreeSound wavSound
FreeBank wavBank

End

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Function WaveLoad(wavPath$)

If FileType(wavPath) = 1
wavBank = CreateBank(FileSize(wavPath))
wavFile = OpenFile(wavPath)
ReadBytes wavBank,wavFile,0,FileSize(wavPath)
CloseFile wavFile
Else
Return 0
EndIf

If Chr(PeekByte(wavBank,0)) + Chr(PeekByte(wavBank,1)) + Chr(PeekByte(wavBank,2)) + Chr(PeekByte(wavBank,3)) = "RIFF"

If PeekInt(wavBank,4)+8 = FileSize(wavPath) ; file size

If Chr(PeekByte(wavBank,8)) + Chr(PeekByte(wavBank,9)) + Chr(PeekByte(wavBank,10)) + Chr(PeekByte(wavBank,11)) = "WAVE"

If Chr(PeekByte(wavBank,12)) + Chr(PeekByte(wavBank,13)) + Chr(PeekByte(wavBank,14)) + Chr(PeekByte(wavBank,15)) = "fmt "

If PeekInt(wavBank,16) = 16 ; bloc Size

If PeekShort(wavBank,20) = 1 ; PCM

If Chr(PeekByte(wavBank,36)) + Chr(PeekByte(wavBank,37)) + Chr(PeekByte(wavBank,38)) + Chr(PeekByte(wavBank,39)) = "data"

wavChannels = PeekShort(wavBank,22)
wavFrequency = PeekInt(wavBank,24)
wavBytePerSec = PeekInt(wavBank,28)
wavBytePerBloc = PeekShort(wavBank,32)
wavBits = PeekShort(wavBank,34)

wavDataSize = PeekInt(wavBank,40)

If wavBits <= 16 And wavChannels <= 2
wavSound = LoadSound(wavPath)
Return wavSound
Else
Return 0
EndIf

EndIf

EndIf

EndIf

EndIf

EndIf

EndIf

EndIf

End Function

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Function WaveSample(time,channel=0)

offset = time*Float(wavBytePerSec)/1000/wavChannels/(wavBits/8)
If offset > wavDataSize/wavChannels/(wavBits/8) Or offset < 0 Then Return 0

Select wavBits
Case 8
sample = (PeekByte(wavBank,offset*wavChannels+channel)-128)*128
Case 16
sample = PeekShort(wavBank,offset*wavChannels*2+channel*2)
If sample > 32768 Then sample = sample - 65535
End Select

Return sample

End Function


Comments :


Charrua(Posted 9 months ago)

 very nice!, thank's for share, here an example of a filter:for a smoothed oval, define a variable:local alpha#=0.025 ;1=no smooth, 0.025 very!and in the main loop, just after your oval insert
Oval 300-radius,300-radius,radius*2,radius*2,1
;just a smoothed one
smoothRadius# = Float(targetRadius) * alpha# + (smoothRadius# * ( 1.0 - alpha#))
Oval 500-smoothRadius,300-smoothRadius,smoothRadius*2,smoothRadius*2,1
note that i shift your oval to the left somewhat to place my oval somewhat to the right (to not overlap each other)here a test1.wav for playing:<a href="https://dl.dropboxusercontent.com/u/78894295/tmp1/test1.wav" target="_blank">https://dl.dropboxusercontent.com/u/78894295/tmp1/test1.wav</a>and the exe, just in case:<a href="https://dl.dropboxusercontent.com/u/78894295/tmp1/waveload.zip" target="_blank">https://dl.dropboxusercontent.com/u/78894295/tmp1/waveload.zip</a>modified source code:<a href="https://dl.dropboxusercontent.com/u/78894295/tmp1/waveload.bb" target="_blank">https://dl.dropboxusercontent.com/u/78894295/tmp1/waveload.bb</a>Juan


Flanker(Posted 9 months ago)

 Thanks for the addition, I tried to do it at first but it didn't work very well.


Bobysait(Posted 9 months ago)

 Good one Flanker ^^Just a small thing :- A loaded file should not generate runtime errors, it should just return "0" if failedI know it can relevant to generate errors, but to be consistent with blitz3d stuff, you might not want to introduice different behaviors who could lead to headackes to remember which function required to check the file exists before trying to load from the ones who returns a "0" to check.


Flanker(Posted 8 months ago)

 Yes you're right bobysait, it should return 0 instead of generating a runtime error. It's just there because before it was a function the code was in the main program and I forgot to remove that ^^I will update the code when I'm back on my computer, so it can work with both mono and stereo and 8 or 16bits. It seems that wav files with more than 2 channels are not well supported with blitz3d, same with 32bits samples.


Flanker(Posted 8 months ago)

 Code updated so it works with 8 and 16 bits, stereo or mono PCM waves, and no need anymore for an array, it works directly from the bank so it's faster to load and takes less memory.Blitz3D doesn't work with 24 and 32bits wav audio, and when there is more than 2 channels, it needs ChannelPitch to play the audio at the original speed. [/i]