Code archives/Audio/freeaudio streaming
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
| generate dynamic waveforms and stream them directly to a freeaudio device | |||||
' freestream.bmx ' mono 8 bit streaming example for Strict Import pub.freeaudio Const FRAG=4096 Print "freestream is free streaming..." fa_Init(0) ' brl.freefreeaudio usually does this Local buffer:Byte[FRAG*8] Local writepos Local sound Local channel sound=fa_CreateSound( FRAG*8,8,1,44100,buffer,$80000000) Print "Sound:"+sound channel=fa_PlaySound( sound, FA_CHANNELSTATUS_STREAMING ,0) Print "PlaySound:"+channel Local streaming Local lfo# Local osc1# While True ' Print "Status:"+fa_ChannelStatus( channel ) Local readpos=fa_ChannelPosition( channel ) Local write=readpos+FRAG*4-writepos Local frags=write/FRAG While frags>0 Print "Write to "+writepos Local pos=writepos Mod (FRAG*8) For Local f=0 Until FRAG Local t=writepos+f lfo=Sin(0.001*t) osc1=Sin(t*(lfo+2)) buffer[pos+f]=128+10*lfo*osc1 Next writepos:+FRAG frags:-1 Wend If Not streaming And writepos>=FRAG*4 fa_SetChannelPaused( channel, False ) streaming=True EndIf Print "." Delay 50 Wend |
Comments
| ||
this version uses an int buffer to supply the left and right channels of a stereo 16 bit freeaudio stream ' freestream16.bmx ' stereo 16 bit streaming example Strict Import pub.freeaudio Const FRAG=1024 Print "freestream is free streaming..." fa_Init(0) ' brl.freefreeaudio usually does this Local buffer:Int[FRAG*8] Local writepos Local sound Local channel sound=fa_CreateSound( FRAG*8,16,2,44100,buffer,$80000000) Print "Sound:"+sound channel=fa_PlaySound( sound, FA_CHANNELSTATUS_STREAMING ,0) Print "PlaySound:"+channel Local streaming Local lfo# Local osc1# While True ' Print "Status:"+fa_ChannelStatus( channel ) Local readpos=fa_ChannelPosition( channel ) Local write=readpos+FRAG*4-writepos Local frags=write/FRAG While frags>0 Print "Write to "+writepos Local pos=writepos Mod (FRAG*8) For Local f=0 Until frag Local t=writepos+f lfo=Sin(0.001*t) osc1=Sin(t*(lfo+2)) Local l16=$ffff & Int(1000*lfo*osc1) Local r16=$ffff & Int(2000*Sin(t)) buffer[pos+f]=L16|(R16 Shl 16) Next writepos:+FRAG frags:-1 Wend If Not streaming And writepos>=FRAG*4 fa_SetChannelPaused( channel, False ) streaming=True EndIf Print "." Delay 50 Wend |
| ||
this version streams a stereo 16 bit ogg file
' freestreamogg.bmx
' streaming stereo 16 bit OGG decoder to freeaudio
Strict
Import pub.freeaudio
Import pub.oggvorbis
Type TAudioStream
Const FRAG=8000
Field buffer:Int[FRAG*8]
Field writepos
Field sound
Field channel
Field streaming
Method PlayStereo16(freq)
sound=fa_CreateSound( FRAG*8,16,2,freq,buffer,$80000000)
Print "Sound:"+sound
channel=fa_PlaySound( sound, FA_CHANNELSTATUS_STREAMING ,0)
Print "Channel:"+channel
streaming=False
End Method
Method Poll()
Local readpos=fa_ChannelPosition( channel )
Local write=readpos+FRAG*4-writepos
Local frags=write/FRAG
While frags>0
Print "Write to "+writepos
Local pos=writepos Mod (FRAG*8)
Local res=ReadBuffer(Byte Ptr(buffer)+pos*4,FRAG*4)
Print "ReadBuffer="+res
writepos:+FRAG
frags:-1
Wend
If Not streaming And writepos>=FRAG*4
fa_SetChannelPaused( channel, False )
streaming=True
EndIf
End Method
Method ReadBuffer%(buffer:Byte Ptr,bytes)
End Method
End Type
Type TOggStream Extends TAudioStream
Field source:Object
Field stream:TStream
Field ogg:Byte Ptr
Field samples
Field channels
Field freq
Field size
Method Open( url:Object )
source=url
stream=ReadFile(url)
ogg=Decode_Ogg(stream,readfunc,seekfunc,closefunc,tellfunc,samples,channels,freq)
size=samples*2*channels
PlayStereo16(freq)
End Method
Method ReadBuffer%(buffer:Byte Ptr,bytes)
If Not ogg Return
If bytes>size bytes=size
If bytes=0 Return 0
Local err=Read_Ogg( ogg,buffer,bytes )
If err Return -1
size:-bytes
' If size=0 Open source
Return bytes
End Method
Function readfunc( buf@Ptr,size,nmemb,src:Object )
Local bytes=TStream(src).Read(buf,size*nmemb)
Return bytes/size
End Function
Function seekfunc( src_obj:Object,off0,off1,whence )
Local off
Local src:TStream=TStream(src_obj)
off=off0 'WARNING 32 bit BADNESS
Local res=-1
Select whence
Case 0
res=src.Seek(off) 'SEEK_SET
Case 1
res=src.Seek(src.Pos()+off) 'SEEK_CUR
Case 2
res=src.Seek(src.Size()+off) 'SEEK_END
End Select
If res>=0 Return 0
Return -1
End Function
Function closefunc( src:Object )
End Function
Function tellfunc( src:Object )
Return TStream(src).Pos()
End Function
End Type
fa_Init(0) ' brl.freefreeaudio usually does this
Local ogg:TOggStream
ogg=New TOggStream
ogg.Open("bouncy.ogg")
Print "ogg.size="+ogg.size+" ogg.channels="+ogg.channels+" ogg.freq="+ogg.freq
Print "freestream is free streaming..."
While True
ogg.Poll
Print "."
Delay 50
Wend
|
| ||
| This is cool, but both the 8-bit and the ogg versions have a 'fluttering' sound throughout for me -- the sound plays but has a constant "p-p-p-p-p-p-p" playing through it while doing so. I did find one ogg that played without flutter*, but all three that I tried are 16-bit according to Audacity. The 16-bit demo was also flutter-free. * Actually, on headphones, that has the flutter too, just quieter. Just tried reducing FRAG to 1000 on that quiet flutter track and it was a lot better during a couple of plays, but now after trying the 'noisy tracks' (they stayed noisy) the 'quiet' track is doing it too! They all play fine with this: ogg$ = "xyz.ogg" sound:TSound = LoadSound (ogg$) PlaySound sound Delay 5000 For what it's worth, sound card is "Creative SB Audigy 2 (WDM)". |
| ||
| Oh, and right now the first demo is flutter-free and the 16-bit version is fluttering! |
| ||
| James, you may want to make FRAG bigger not smaller, I have modified the first example to more realistic size. |
| ||
| I used 8k or bigger to make cracklings go away. Reason is: If you eg. only update the streams buffer 30 times a second, this means your buffer must in all cases be longer than 1/33 = 33ms. If your buffer is slightly smaller you have chances to play some milliseconds of "old sound". In the examples using "Delay 50" this means that at least 50 ms are gone till the next buffer refill. Maybe there is one having time and knowledge to write it in a threaded way so some kind of autopolling can be achieved (regardless of delays, or occupation of the mainthread like resource loading). To make it more convertible I wrapped the code in a way so that TChannel/TSound get used. I do not post the code here because it is not PD but zlib/libpng-licenced: https://github.com/GWRon/Dig/blob/3ea47f1e85680dc4403c490751fdd069a2d28047/base.sfx.soundstream.bmx Code contains some simple "Clone"-Method to enable crossfading to the same sound (as you cannot share the buffers but the source bank/stream). |
Code Archives Forum