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