They actually can, in a semi-hack way. dur and time are passed as double-precision floats (or t_CKDUR and t_CKTIME). When defining the prototype, you only need to specify "dur" or "time". The semantic of both is that they both count samples (or fractions thereof). There are ways of converting samples to sample-rate independent time, the most basic of which is to normalize by the system sample rate in Digitalio.
So, what would it look like? Say I want to build a freqtodelay tool that takes a frequency and returns the dur corresponding to the wavelength. (I know, it's silly, but I want to get a hang of it...)
In my foobar_query function (registered in chuck_main, together with the ulib_foo things) I include QUERY->add_export(QUERY, "dur", "freqtodelay", freqtodelay_impl, TRUE); QUERY->add_param(QUERY, "float", "frequency"); .... and where does the time come in? Or is it impossible to -return- durations too?
This should work just fine. (just remember to return a float that is the number of samples (using Digitalio to go from seconds etc to samples))
* The handling of parameter input to ulib functions is severely flawed, including lack of type security across platforms and probably not 64-bit secured:
Um, yes - there are some egregious hacks in that area of the code. We have tried to alleviate the data width with consistent types across the system (t_CKFLOAT, t_CKINT, etc), and hopefully a configure script would be able to resolve that across platforms.
There are already some macros taking care of stepping through arcane arrays (the GET_NEXT_FLOAT et.c. family) - why not make sure there are similar for the argument reading? The hack we finally got working was the following: char* name = GET_CK_STRING(ARGS); (char*)ARGS+=sizeof(char*); t_CKFLOAT foo = GET_CK_FLOAT(ARGS);
with the (foo*)ARGS+=sizeof(foo*) being repeated for every nonfinal argument to be read... All this should be easy to wrap in a macro so that all we really need to do is char* name = GET_CK_STRING(ARGS); t_CKFLOAT foo = GET_CK_FLOAT(ARGS); with the GET_CK_FOO automatically incrementing as we go along...
Yes - foo is out of date for this... the macros you mentioned are made for this purpose: // param conversion #define GET_CK_FLOAT(ptr) (*(t_CKFLOAT *)ptr) #define GET_CK_SINGLE(ptr) (*(float *)ptr) #define GET_CK_DOUBLE(ptr) (*(double *)ptr) #define GET_CK_INT(ptr) (*(t_CKINT *)ptr) #define GET_CK_UINT(ptr) (*(t_CKUINT *)ptr) #define GET_CK_TIME(ptr) (*(t_CKTIME *)ptr) #define GET_CK_DUR(ptr) (*(t_CKDUR *)ptr) #define GET_CK_STRING(ptr) (*(char **)ptr) // param conversion with pointer advance #define GET_NEXT_FLOAT(ptr) (*((t_CKFLOAT *&)ptr)++) #define GET_NEXT_SINGLE(ptr) (*((float *&)ptr)++) #define GET_NEXT_DOUBLE(ptr) (*((double *&)ptr)++) #define GET_NEXT_INT(ptr) (*((t_CKINT *&)ptr)++) #define GET_NEXT_UINT(ptr) (*((t_CKUINT *&)ptr)++) #define GET_NEXT_TIME(ptr) (*((t_CKTIME *&)ptr)++) #define GET_NEXT_DUR(ptr) (*((t_CKDUR *&)ptr)++) #define GET_NEXT_STRING(ptr) (*((char * *&)ptr)++) there are set macros as well. Ge!