Blitz not suitable for callbacks from APIs?

BlitzMax Forums/BlitzMax Programming/Blitz not suitable for callbacks from APIs?

Who was John Galt?(Posted 2010) [#1]
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?


Rozek(Posted 2010) [#2]
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...


JoshK(Posted 2010) [#3]
Call GCSuspend before calling the function that calls your callbacks, then call GCResume when it is done.


Rozek(Posted 2010) [#4]
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?


Who was John Galt?(Posted 2010) [#5]
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



JoshK(Posted 2010) [#6]
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.


Who was John Galt?(Posted 2010) [#7]
Hey, thanks again, Josh. How do I declare my function as, say, win32?


Azathoth(Posted 2010) [#8]
"win32" is the equivalent to C's stdcall.


Who was John Galt?(Posted 2010) [#9]
How do a declare a blitz function to be "win32" though?


JoshK(Posted 2010) [#10]
function whatever() "win32"

endfunction


Brucey(Posted 2010) [#11]
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.


Who was John Galt?(Posted 2010) [#12]
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.


JoshK(Posted 2010) [#13]
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.


Who was John Galt?(Posted 2010) [#14]
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.



Who was John Galt?(Posted 2010) [#15]
Hmm... word of warning... my callback refuses to see any variables defined outside the callback, whether written in blitz or c.