Page 1 of 1
Posted: Mon Feb 03, 2003 11:43 pm
by BackupUser
Restored from previous forum. Originally posted by mindplay.
I've been trying to implement a custom stream in FMOD - that is, I wish to generate my own sound in real time, via a callback buffer, and have FMOD play it back over the soundcard.
For starters, I just want to see that it works, i.e. by filling the buffer with zeroes, but whenever I call FSOUND_Stream_Play, it just crashes.
I suspect I didn't implement the callback with the correct interface? ... I even tried making a callback that does nothing at all, not even zeroing the buffer, but it still crashes.
Any help would be greatly appreciated...
Code: Select all
; FMOD Constants
#FSOUND_16BITS.l = $00000010
#FSOUND_SIGNED.l = $00000100
#FSOUND_MONO.l = $00000020
#FSOUND_FREE.l = -1
; Buffer Structure
#BufferSize.l = 1000*2*2
Structure BufferType
Sample.w[#BufferSize]
EndStructure
; Callback
Procedure.b MyStreamCallback(*Stream, *Buff.BufferType, Len.l, Param.l)
For Index.l = 0 To #BufferSize-1
*Buff\Sample[Index] = 0
Next
ProcedureResult = #true
EndProcedure
; Open a console, and play the stream until ENTER is pressed
OpenConsole()
PrintN("Initializing FMOD...")
FSOUND_Init(44100, 32, 0)
MyStream = FSOUND_Stream_Create(@MyStreamCallback, #BufferSize, #FSOUND_16BITS | #FSOUND_SIGNED | #FSOUND_MONO, 44100, 1)
FSOUND_Stream_Play(#FSOUND_FREE, MyStream)
Print("Press ENTER to quit")
Input()
FSOUND_Stream_Close(MyStream)
FSOUND_Close()
CloseConsole()
Posted: Tue Feb 04, 2003 12:39 am
by BackupUser
Restored from previous forum. Originally posted by Danilo.
Use FMOD DLL with STDCALL callbacks:
http://home.t-online.de/home/ExpressTrack/PureFMOD.zip
> For Index.l = 0 To #BufferSize-1
> *Buff\Sample[Index] = 0
> Next
> ProcedureResult = #true
Should this loop be 'For Index = 0 to Len - 1' ??
cya,
...Danilo
(registered PureBasic user)
Posted: Tue Feb 04, 2003 12:40 am
by BackupUser
Restored from previous forum. Originally posted by J. Baker.
not sure if this helps but when i tried to run the code it said...
Line 31:FSOUND_Init(44100, 32, 0)is not a function, an array or a linked list
Posted: Tue Feb 04, 2003 12:45 am
by BackupUser
Restored from previous forum. Originally posted by Danilo.
ummm... sorry.
>Structure BufferType
> Sample.w[#BufferSize]
>EndStructure
This Structure must be Sample.b for bytes!
cya,
...Danilo
(registered PureBasic user)
Posted: Tue Feb 04, 2003 3:21 pm
by BackupUser
Restored from previous forum. Originally posted by mindplay.
J.Baker: If you don't have FMOD installed, that's the error message you'd get, yes.
Danilo: bytes? but as you can see, when I create the stream, I specify #FSOUND_16BITS and #FSOUND_SIGNED - which should be suitable for the ".w" type in PB, which is a 16-bit signed integer type, or not?
Posted: Tue Feb 04, 2003 3:32 pm
by BackupUser
Restored from previous forum. Originally posted by mindplay.
I see what you meant by the buffersize problem ... should be fixed in the following code - that's not why it crashes though, it never even gets to that point in the code ... as explained, even if you comment out every line inside the callback procedure, it still crashes as soon as FSOUND_Stream_Play is called ... I added code now to check if FSOUND_Stream_Create returns a zero pointer, which would mean that stream creation failed - it does not, however.
You say to use STDCALL, but how can I specicy the calling convention for my callback procedure? ... the FMOD.DLL and the PB library I'm using is the one I donwloaded from the link you provided ... does it work on your machine???
Code: Select all
; FMOD Constants
#FSOUND_16BITS.l = $00000010
#FSOUND_SIGNED.l = $00000100
#FSOUND_MONO.l = $00000020
#FSOUND_FREE.l = -1
; Buffer Structure
#BufferSize.l = 1000 ; 1000 word (2000 bytes)
Structure BufferType
Sample.w[#BufferSize]
EndStructure
; Callback
Procedure.b MyStreamCallback(*Stream, *Buff.BufferType, Len.l, Param.l)
For Index.l = 0 To #BufferSize-1
*Buff\Sample[Index] = 0
Next
ProcedureResult = #true
EndProcedure
; Open a console, and play the stream until ENTER is pressed
OpenConsole()
PrintN("Initializing FMOD...")
FSOUND_Init(44100, 32, 0)
MyStream = FSOUND_Stream_Create(@MyStreamCallback, #BufferSize*2, #FSOUND_16BITS | #FSOUND_SIGNED | #FSOUND_MONO, 44100, 1)
If MyStream=0
PrintN("Stream creation failed!")
Else
FSOUND_Stream_Play(#FSOUND_FREE, MyStream)
EndIf
Print("Press ENTER to quit")
Input()
FSOUND_Stream_Close(MyStream)
FSOUND_Close()
CloseConsole()
Posted: Tue Feb 04, 2003 8:59 pm
by BackupUser
Restored from previous forum. Originally posted by Danilo.
Pointer-problem:
You used @MyStreamCallback instead @MyStreamCallback()
Code: Select all
FSOUND_Init(44100, 32, 0)MyStream = FSOUND_Stream_Create(@MyStreamCallback(), #BufferSize*2, #FSOUND_16BITS | #FSOUND_SIGNED | #FSOUND_MONO, 44100, 1)
If MyStream=0
cya,
...Danilo
(registered PureBasic user)
Posted: Wed Feb 05, 2003 12:06 am
by BackupUser
Restored from previous forum. Originally posted by mindplay.
thanks, Danilo! that solved it!
there were some other problems, but I solved those - here's the final code, which produces a 440 Hz test tone ... this should make a nice example for others to start from? it would have helped me a lot if something like this came with the PB examples for FMOD - who's the author? I'd like to ask him to include this, might save others some trouble
Code: Select all
; FMOD Constants
#FSOUND_16BITS.l = $00000010
#FSOUND_SIGNED.l = $00000100
#FSOUND_MONO.l = $00000020
#FSOUND_FREE.l = -1
; Buffer Structure
#BufferSize.l = 4096*4 ; buffer size (increase if the sound breaks up!)
Structure BufferType
Sample.w[#BufferSize]
EndStructure
; Callback
SinPos.f = 0
Procedure.b MyStreamCallback(*Stream.l, *Buff.BufferType, Len.l, Param.l)
Global SinPos
For Index.l = 0 To (Len/2)-1
SinPos = SinPos + (440/44100)
If SinPos>1
SinPos - 1
EndIf
*Buff\Sample[Index] = Int(Sin(SinPos*3.1415*2)*30000)
Next
ProcedureReturn 1 ; must return 1 to continue playing
EndProcedure
; Open a console, and play the stream until ENTER is pressed
OpenConsole()
PrintN("Initializing FMOD...")
FSOUND_Init(44100, 32, 0)
MyStream = FSOUND_Stream_Create(@MyStreamCallback(), #BufferSize*2, #FSOUND_16BITS | #FSOUND_SIGNED | #FSOUND_MONO, 44100, 1)
If MyStream=0
PrintN("Stream creation failed!")
Else
FSOUND_Stream_Play(#FSOUND_FREE, MyStream)
PrintN("Playing Stream")
EndIf
Print("Press ENTER to quit")
Input()
FSOUND_Stream_Close(MyStream)
FSOUND_Close()
CloseConsole()
Posted: Wed Feb 05, 2003 11:11 am
by BackupUser
Restored from previous forum. Originally posted by Danilo.
> it would have helped me a lot if something like this came with
> the PB examples for FMOD
> I'd like to ask him to include this, might save others some trouble
OK, thanks - i´ll include it
If you have more examples you want included,
just tell me.
cya,
...Danilo
(registered PureBasic user)
Posted: Wed Feb 05, 2003 7:27 pm
by BackupUser
Restored from previous forum. Originally posted by mindplay.
If you'd like to include a slightly more complicated example, here's a tiny bassline synthesizer/sequencer I wrote today - it's just a 1-pol filter on a shaped sinustone with a linear envelope, but it might make some people curious and get them started experimenting with their own synthesizer techniques
Code: Select all
; FMOD Constants
#FSOUND_16BITS.l = $00000010
#FSOUND_SIGNED.l = $00000100
#FSOUND_MONO.l = $00000020
#FSOUND_FREE.l = -1
; Music/math constants and utility functions
#SampleRate = 44100
#Pi.f = 3.14159265
#Pi2.f = 6.2831853
Procedure.f NoteFreq(note.f)
ProcedureReturn Pow(2, (note+11)/12)*8.1757989
EndProcedure
#NumSteps = 8
Structure StepStruct
Freq.f
EndStructure
Dim Seq.StepStruct(#NumSteps)
StepNum.l = 0
NoteDur.l = #SampleRate/(130*4/60) ; 130 BPM, 4 steps per beat
NotePos.l = 0
Seq(0)\Freq = NoteFreq(36)
Seq(1)\Freq = NoteFreq(48)
Seq(2)\Freq = NoteFreq(42)
Seq(3)\Freq = NoteFreq(30)
Seq(4)\Freq = NoteFreq(48)
Seq(5)\Freq = NoteFreq(47)
Seq(6)\Freq = NoteFreq(46)
Seq(7)\Freq = NoteFreq(30)
; Buffer Structure
#BufferSize.l = 4096*4 ; buffer size (increase if the sound breaks up!)
Structure BufferType
Sample.w[#BufferSize]
EndStructure
; Filter Structure
#Filter_HiCutoff = 1200
Structure FilterStruct
rlpf_f.f ; cutoff frequency
rlpf_r.f ; resonance amount
rlpf_c.f
rlpf_pos.f
rlpf_speed.f
EndStructure
DefType.FilterStruct Filter
Filter\rlpf_pos=0
Filter\rlpf_speed=0
Filter\rlpf_r=0.995
Filter\rlpf_f=#Filter_HiCutoff
Filter\rlpf_c=2-2*Cos(2*pi*rlpf_f/#SampleRate)
; Callback
SinPos.f = 0
Procedure.b MyStreamCallback(*Stream.l, *Buff.BufferType, Len.l, Param.l)
Global SinPos, NotePos, NoteDur, StepNum, Seq, Filter
For Index.l = 0 To (Len/2)-1
; Waveform
SinPos = SinPos + ((Seq(StepNum)\Freq)/#SampleRate)
If SinPos>1
SinPos - 1
EndIf
; Oscillator
Smp.f = Sin(SinPos * #Pi2)
; Shaping/distortion (sinus towards square)
Smp = Smp / (Abs(Smp)+0.01)
; Simple envelope
Smp = Smp * ((NoteDur-NotePos)/NoteDur)
; Filter
Filter\rlpf_speed = Filter\rlpf_speed + (Smp - Filter\rlpf_pos) * Filter\rlpf_c
Filter\rlpf_pos = Filter\rlpf_pos + Filter\rlpf_speed
Filter\rlpf_speed = Filter\rlpf_speed * Filter\rlpf_r
Smp = Filter\rlpf_pos * 0.1
Filter\rlpf_f = Filter\rlpf_f - 0.12
Filter\rlpf_c = 2 - 2 * Cos(#Pi2 * Filter\rlpf_f / #SampleRate)
; Clipping
If Smp>1
Smp=1
ElseIf SmpNoteDur
; Next Note
NotePos=0
StepNum+1
SinPos=0
If StepNum=#NumSteps
StepNum=0
EndIf
; Reset Filter Cutoff and recalculate coefficient
Filter\rlpf_f=#Filter_HiCutoff
Filter\rlpf_c = 2 - 2 * Cos(#Pi2 * Filter\rlpf_f / #SampleRate)
EndIf
Next
ProcedureReturn 1 ; must return 1 to continue playing
EndProcedure
; Open a console, and play the stream until ENTER is pressed
OpenConsole()
PrintN("Simple Bassline Synthesizer/Sequencer example")
PrintN("Written by R. Schultz ([url]mailto:mp@mindplay.dk[/url])")
PrintN("Use freely, but give credit, and notify the author of any use!")
PrintN("")
PrintN("Initializing FMOD...")
FSOUND_Init(#SampleRate, 32, 0)
MyStream = FSOUND_Stream_Create(@MyStreamCallback(), #BufferSize*2, #FSOUND_16BITS | #FSOUND_SIGNED | #FSOUND_MONO, #SampleRate, 1)
If MyStream=0
PrintN("Stream creation failed!")
Else
FSOUND_Stream_Play(#FSOUND_FREE, MyStream)
PrintN("Playing Stream")
EndIf
Print("Press ENTER to quit")
Input()
FSOUND_Stream_Close(MyStream)
FSOUND_Close()
CloseConsole()
Posted: Wed Feb 05, 2003 7:43 pm
by BackupUser
Restored from previous forum. Originally posted by mindplay.
And here's a new version with a synthesized bass drum too
Code: Select all
; FMOD Constants
#FSOUND_16BITS.l = $00000010
#FSOUND_SIGNED.l = $00000100
#FSOUND_MONO.l = $00000020
#FSOUND_FREE.l = -1
; Music/math constants and utility functions
#SampleRate = 44100
#Pi.f = 3.14159265
#Pi2.f = 6.2831853
Procedure.f NoteFreq(note.f)
ProcedureReturn Pow(2, (note+11)/12)*8.1757989
EndProcedure
#NumSteps = 8
Structure StepStruct
Freq.f
Drum.l
EndStructure
Dim Seq.StepStruct(#NumSteps)
StepNum.l = 0
NoteDur.l = #SampleRate/(130*4/60) ; 130 BPM, 4 steps per beat
NotePos.l = 0
Seq(0)\Freq = NoteFreq(36)
Seq(1)\Freq = NoteFreq(48)
Seq(2)\Freq = NoteFreq(42)
Seq(3)\Freq = NoteFreq(30)
Seq(4)\Freq = NoteFreq(48)
Seq(5)\Freq = NoteFreq(47)
Seq(6)\Freq = NoteFreq(46)
Seq(7)\Freq = NoteFreq(30)
DrumEnv.f = 1
DrumPos.f = 0.5
Seq(0)\Drum = 1
Seq(1)\Drum = 0
Seq(2)\Drum = 0
Seq(3)\Drum = 0
Seq(4)\Drum = 1
Seq(5)\Drum = 0
Seq(6)\Drum = 0
Seq(7)\Drum = 0
; Buffer Structure
#BufferSize.l = 4096*4 ; buffer size (increase if the sound breaks up!)
Structure BufferType
Sample.w[#BufferSize]
EndStructure
; Filter Structure
#Filter_HiCutoff = 1200
Structure FilterStruct
rlpf_f.f ; cutoff frequency
rlpf_r.f ; resonance amount
rlpf_c.f
rlpf_pos.f
rlpf_speed.f
EndStructure
DefType.FilterStruct Filter
Filter\rlpf_pos=0
Filter\rlpf_speed=0
Filter\rlpf_r=0.995
Filter\rlpf_f=#Filter_HiCutoff
Filter\rlpf_c=2-2*Cos(2*pi*rlpf_f/#SampleRate)
; Callback
SinPos.f = 0
Procedure.b MyStreamCallback(*Stream.l, *Buff.BufferType, Len.l, Param.l)
Global SinPos, NotePos, NoteDur, StepNum, Seq, Filter, DrumPos, DrumEnv
For Index.l = 0 To (Len/2)-1
; Waveform
SinPos = SinPos + ((Seq(StepNum)\Freq)/#SampleRate)
If SinPos>1
SinPos - 1
EndIf
; Oscillator
Smp.f = Sin(SinPos * #Pi2)
; Shaping/distortion (sinus towards square)
Smp = Smp / (Abs(Smp)+0.01)
; Simple envelope
Smp = Smp * ((NoteDur-NotePos)/NoteDur)
; Filter
Filter\rlpf_speed = Filter\rlpf_speed + (Smp - Filter\rlpf_pos) * Filter\rlpf_c
Filter\rlpf_pos = Filter\rlpf_pos + Filter\rlpf_speed
Filter\rlpf_speed = Filter\rlpf_speed * Filter\rlpf_r
Smp = Filter\rlpf_pos * 0.1
Filter\rlpf_f = Filter\rlpf_f - 0.12
Filter\rlpf_c = 2 - 2 * Cos(#Pi2 * Filter\rlpf_f / #SampleRate)
; Drum
If Seq(StepNum)\Drum=1
DrumPos = DrumPos + (130+DrumEnv*1500)/#SampleRate
DrumEnv = DrumEnv * 0.9992
Smp = Smp + ((NoteDur-NotePos)/NoteDur) * Sin(DrumPos)
EndIf
; Volume down
Smp = Smp * 0.7
; Clipping
If Smp>1
Smp=1
ElseIf SmpNoteDur
; Next Note
NotePos=0
StepNum+1
SinPos=0
If StepNum=#NumSteps
StepNum=0
EndIf
; Reset Filter Cutoff and recalculate coefficient
Filter\rlpf_f=#Filter_HiCutoff
Filter\rlpf_c = 2 - 2 * Cos(#Pi2 * Filter\rlpf_f / #SampleRate)
; Reset Drum
If Seq(StepNum)\Drum=1
DrumPos = 0.5
DrumEnv = 1
EndIf
EndIf
Next
ProcedureReturn 1 ; must return 1 to continue playing
EndProcedure
; Open a console, and play the stream until ENTER is pressed
OpenConsole()
PrintN("Simple Bassline Synthesizer/Sequencer example")
PrintN("Written by R. Schultz ([url]mailto:mp@mindplay.dk[/url])")
PrintN("Use freely, but give credit, and notify the author of any use!")
PrintN("")
PrintN("Initializing FMOD...")
FSOUND_Init(#SampleRate, 32, 0)
MyStream = FSOUND_Stream_Create(@MyStreamCallback(), #BufferSize*2, #FSOUND_16BITS | #FSOUND_SIGNED | #FSOUND_MONO, #SampleRate, 1)
If MyStream=0
PrintN("Stream creation failed!")
Else
FSOUND_Stream_Play(#FSOUND_FREE, MyStream)
PrintN("Playing Stream")
EndIf
Print("Press ENTER to quit")
Input()
FSOUND_Stream_Close(MyStream)
FSOUND_Close()
CloseConsole()
this takes me back to the acidhouse days of the 80s - aciiied! woo! okay, enough of this sillyness ...
