Blitz not suitable for callbacks from APIs?
BlitzMax Forums/BlitzMax Programming/Blitz not suitable for callbacks from APIs?
| ||
| I'm writing a callback in Blitz to create realtime sound effects with FMOD. All is fine until I try to iterate through a list with EACHIN, and it just will not iterate through the list. I have checked the list is non-null inside the callback, and the same code iterates fine outside the callback. So can I use blitz for these callbacks, and if so, what are the limitations? |
| ||
| John, I am heavily using BlitzMAX callback functions from within Lua - and never had any problems which were related to the fact, that my functions weren't invoked from within BlitzMAX directly. On the other hand: I never used BlitzMAX's built-in lists... |
| ||
| Call GCSuspend before calling the function that calls your callbacks, then call GCResume when it is done. |
| ||
| Josh, is this a general recommendation? What could happen if you don't suspend the GC? Local variables should not be collected, right? How would suspend/resume affect the overall performance? |
| ||
| Nope- it plain refuses to iterate, even with Josh's suggestion. If I replace it with an array, the array reports as zero length within the callback, even though it reports 1 outside. It makes no odds whether the list or array is declared as a type global or plain old global. Function pcmreadcallback:Int(sound:TFMODSound, data:Byte Ptr, dataLen:Int)
'Local f1:Float=1600.0
'Local f2:Float=2400.0
Global floatStream:Float[]=New Float[1]
Local count:Int
'Global f1phase:Float=0.0
'Global f2phase:Float=0.0
Local tonal:Ttonal=Null
Local toneIndex:Int=0
Local stereo16bitbuffer:Short Ptr = Short Ptr (data);
Local samplesPerChannel:Int=dataLen Shr 2 ' shr2 = 16bit stereo (4 bytes per sample)
If floatStream.length<samplesPerChannel
floatStream=New Float[samplesPerChannel]
EndIf
globcount=0
For count=0 Until samplesPerChannel
floatStream[count]=0.0
'listvar=Ttonal._list
Rem
globCount=Ttonal._listArray.length
For toneIndex=0 Until Ttonal._listArray.length
tonal=Ttonal(Ttonal._listArray[toneIndex])
floatStream[count]:+tonal._amp*Sin(tonal._phi)
tonal._phi:+tonal._dphi
globcount:+1
While tonal._phi>=360.0
tonal._phi:-360.0
Wend
Next
EndRem
For tonal=EachIn _list
floatStream[count]:+tonal._amp*Sin(tonal._phi)
tonal._phi:+tonal._dphi
globcount:+1
While tonal._phi>=360.0
tonal._phi:-360.0
Wend
Next
stereo16bitbuffer[count*2] = makeSignedShort(floatStream[count]) 'Left channel
'stereo16bitbuffer[count*2+1] = makeSignedShort( (Sin(f2phase) * 32767.0 ) ) 'Right channel
Rem
f1phase :+ 360.0*f1*(1.0/44100.0);
While f1phase>=360.0
f1phase:-360.0
Wend
f2phase :+ 360.0*f2*(1.0/44100.0);
While f2phase>=360.0
f2phase:-360.0
Wend
EndRem
Next
Return FMOD_OK;
End Function |
| ||
| Also make sure your callback is the right protocol. You have "win32" and "c". I forget what the C equivalent is, something to do with STD's. |
| ||
| Hey, thanks again, Josh. How do I declare my function as, say, win32? |
| ||
| "win32" is the equivalent to C's stdcall. |
| ||
| How do a declare a blitz function to be "win32" though? |
| ||
| function whatever() "win32" endfunction |
| ||
| You can use it fine from callbacks... unless the callback occurs out of the main thread. Specifically, pcmreadcallback() is being called from a different thread. You may want to try enabling multi-threading if you intend to use that. It's basically an issue with BlitzMax's default garbage collector, in that it is not thread-safe. |
| ||
| Thanks, Brucey. Unfortunately it started complaining about Bah.fmod when I tried to build in threaded mode. I tried rebuilding the mods in threaded mode to no avail. After a couple of hours I just decided it was easier to just write the callback in C. |
| ||
| How did you do this? Did you import a function from an imported .c file and send that to fmod? I could use something like this for my collision callbacks. |
| ||
Hi Josh... that is exactly what I'm doing. It's all working fine, and I assume I will be able to make c calls to set variables in my callback so I can change the sound properties, but I haven't implemented that part yet. I actually got the idea from a thread of yours way back.
/*cbit.c*/
#include "/Developer/FMOD Programmers API Mac/api/inc/fmod.h"
#include "/Developer/FMOD Programmers API Mac/api/inc/fmod_errors.h"
#include "/Developer/FMOD Programmers API Mac/examples/common/wincompat.h"
#include <math.h>
FMOD_RESULT F_CALLBACK pcmreadcallback(FMOD_SOUND *sound, void *data, unsigned int datalen)
{
unsigned int count;
static float t1 = 0, t2 = 0; // time
static float v1 = 0, v2 = 0; // velocity
signed short *stereo16bitbuffer = (signed short *)data;
for (count=0; count<datalen>>2; count++) // >>2 = 16bit stereo (4 bytes per sample)
{
*stereo16bitbuffer++ = (signed short)(sin(t1) * 32767.0f); // left channel
*stereo16bitbuffer++ = (signed short)(sin(t2) * 32767.0f); // right channel
t1 += 0.01f + v1;
t2 += 0.0142f + v2;
v1 += (float)(sin(t1) * 0.002f);
v2 += (float)(sin(t2) * 0.002f);
}
return FMOD_OK;
}Part of the main blitz file... Import "cbit.c" Extern Function pcmreadcallback:Int(sound:TFMODSound, data:Byte Ptr, dataLen:Int) 'FMOD_RESULT F_CALLBACK pcmreadcallback(FMOD_SOUND *sound, void *data, unsigned Int datalen) End Extern createsoundexinfo.SetPCMReadCallback (pcmreadcallback) 'User callback For reading. |
| ||
| Hmm... word of warning... my callback refuses to see any variables defined outside the callback, whether written in blitz or c. |