Function pointer, how?


#1

I'm creating a multi-pole morphing multimode filter which uses some internal non-linearity shapers.
Thing is, after adding a "switch" function to select between the different shaping types, it suddenly asked way more then it should (when using the same "default", previously used shape, it asked 5% more than before.. does the switch-function really adds so much cpu usage??)

So, instead of this, I thought it might be a good idea to use a function-pointer, that's being used within the filter-objects, but to which I can assign a certain function when the selector changes.

I'm trying my best to find out how to do this on the internet, but all the examples I run into are way more complex than I need, containing all kinds of extra code of the threat starters, making it pretty hard to see what is the basic "build up" of a function-pointer. So could someone help me out on this and show me how to make a simple function-pointer?

The basic functions I'm using are build like this:

int32_t SIN( int32_t in ) //just a single input
{
SINE2TINTERP( in , in ) //some kind of math function
return in; //returning the result
}
int32_t COS( int32_t in ) //just a single input
{
SINE2TINTERP( in + (1<<30) , in ) //some kind of math function
return in; //returning the result
}
for a start, I'ld like to have a function pointer that I could embed in a filter like *SHAPE(....)

int32_t *SHAPE() and int32_t FILTER() would be put in the local data and *SHAPE() should be pointed to some function in the krate code along this line (though this seems to be the wrong way..)

if(param_shape==0)
{
SHAPE()=&SIN();
}

int32_t FILTER( int32_t *in, int32_t *val, int32_t f )
{
*val = ___SMMLA( *SHAPE( *in ) - *SHAPE( *val ) <<1 , f, *val ) ;
*in = *val;
}

So can someone tell me the right syntax to do this?? Or point me to an axoloti object that uses int32_t function-pointers, so I can find out myself?


#2

ps, the filter is really nice and creamy and I'll share it once it's done.
It's like a 4-pole ladder filter, but instead of switching filter-types, it's able to morph between LOWPASS-ALLPASS-HIGHPASS while the resonance stays pretty stable and uses seperate cutoff frequencies for each pole, so it almost works like an equaliser all on it's own. Thanks to the non-linearities, you can really push the resonance over the top and make it scream, while at lower resonance settings it sounds really nice and pingy. Formant filtering is a breeze, put a saw into it and you have yourself a didgeridoo!


#3

It's been a while but I believe if you have:
int32_t SIN(int32_t in) { //code }
and
int32_t COS(int32_t in) { //code }
you can do:
int32_t (*SHAPE)(int32_t) { nullptr }; // defer assignment, start with null

if (param_shape == 0)
{
SHAPE = &SIN;
}
else
{
SHAPE = &COS;
}
SHAPE(param_val); // Note: this will be bad is SHAPE is still null

The syntax to declare a function pointer in C++ is ugly:
return_type (*var_name)([arg_type, ...]) { initial_value };

Where return_type is the return type for the functions to be pointed to
var_name is the variable name
[arg_type, ...] is the list of argument types for the functions to be pointed at, which may be empty
initial_value is the initial value for the variable var_name, can be nullptr or an actual function address

You can assign just using the address dereference operator ("&") before the name of the function. Both the return type and the number and types of arguments must match between pointer and function for the assignment to be valid, I think.

More typical than declaring function pointers directly, in my experience anyway, is to use a typedef:

#typedef ShapePtr int32_t (*)(int32_t);

ShapePtr Shape;

Shape = &SIN;

Hope this helps,
John


#4

should the part

#typedef ShapePtr int32_t (*)(int32_t);

already work on it's own without errors? (either with or without the "#")

As it's telling me:

C:\Users\SIRSIC~1\DOCUME~1\axoloti/build/xpatch.cpp:72:9: error: 'ShapePtr' does not name a type
typedef ShapePtr int32_t (*)(int32_t);

or

C:\Users\SIRSIC~1\DOCUME~1\axoloti/build/xpatch.cpp:72:2: error: invalid preprocessing directive #typedef
#typedef ShapePtr int32_t (*)(int32_t);


#5

Sorry - I should definitely not try to remember syntax for stuff I haven't used in years - looking it up is much safer. The syntax should be:

typedef int32_t (*)(int32_t) ShapePtr;

It's not a preprocessor directive (so no leading #) and I got the type and name bits backwards. Sorry about that.
Regards,
John


#6

ok, so this isn't working either...now it gave me these errors:

C:\Users\SIRSIC~1\DOCUME~1\axoloti/build/xpatch.cpp:40:19: error: expected unqualified-id before ')' token
typedef int32_t (*)(int32_t) ShapePtr;
^
C:\Users\SIRSIC~1\DOCUME~1\axoloti/build/xpatch.cpp:40:28: error: expected ';' at end of member declaration
typedef int32_t (*)(int32_t) ShapePtr;
^
C:\Users\SIRSIC~1\DOCUME~1\axoloti/build/xpatch.cpp:40:30: error: 'ShapePtr' does not name a type
typedef int32_t (*)(int32_t) ShapePtr;

when I changed it to this, it didn't give me any errors anymore.

typedef int32_t (*ShapePtr)(int32_t) ;

But when I try to do:
ShapePtr=&sin;
then it gives me the error:

C:\Users\SIRSIC~1\DOCUME~1\axoloti/build/xpatch.cpp:62:4: error: expected unqualified-id before '=' token


#7

Sorry for messing the syntax up YET AGAIN!. Your final version is correct:

typedef int32_t (*ShapePtr)(int32_t);

The issue is that ShapePtr now names a TYPE, not a variable. You need to do:

ShapePtr shape = &sin;

Then "shape" is the actual pointer and can be used:

int32_t rtn = shape(param_val);

Sorry for the goose chase to get here, but I think this is now all correct.

Regards,
John


#8

ah yes of course, it's first setting/creating the type and then I still need to declare something being that type


#9

thanks! I got it working!


#10

hmm, too bad.. not a big change in cpu load for the filter as far as I can see. That's a shame.. it's still on the heavy side (between 17% and 27%) which quite limits it's usage in bigger patches. So I'll need to try to get it down another way..

But it's good to finally understand how to make function-pointers! I ran into that problem several times in previous projects..


#11

Glad to hear you got it working! Sorry again for my issues with getting the ugly c++ function pointer syntax integrated with the typedef syntax. It's been years since I've used this stuff and then the idea was to hide all the ugly function pointer declarations with typedefs and forget about it (which I obviously did!)

Regards,
John