Personal tools
You are here: Home development codeSnippets
Views

Useful C-code snippets for PD

This page contains a collection of code snippets, which occur regularly in Pd-code. The intended audience are people interesting in maintaining existing objects or write new ones. The code snippets are not mend to be implemented verbatim, but the may help avoiding some of the common pitfalls. They are collected from pd-list lore and existing code. This page is certainly not intended as a beginners guide. It is assumes you are at least familiar with the Externals Howto by IOhannes? m zmölnig.

Pd API interaction

Sample rate

There is a call to sys_getsr(), but it will report the global sample rate.

int samplerate = sys_getsr();

Better use

int samplerate = sp[0]->s_sr;

from the *_dsp routine. This one respects local settings, like when you changed the block size.

Once per block message

If you want to have an action executed directly after processing the audio buffer, the trick is to specify a clock_delay with value 0 in the perform function. In the object instantiation routine (myObj_new()), a pointer of the function is passed to clock_new(). Don't forget to free the clock with clock_free(), or Pd could crash.

static t_int myObj_perform() {
    ....
    clock_delay(x->x_clock, 0);

static void myObj_tick( t_myObj *x) { ....

static void myObj_free( t_myObj *x) { if (x->x_clock) clock_free(x->x_clock); }

static void myObj_new(void) { .... x->x_clock = clock_new(x, (t_method)myObj_tick); ....

void myObj_tilde_setup(void) { myObj_class = class_new(gensym("myObj~"), (t_newmethod)myObj_new, (t_method)myObj_free, ....

Version of Pd (compile time)

The m_pd.h defines these constants, and defines the version of Pd used during compilation.

#define PD_MAJOR_VERSION 0
#define PD_MINOR_VERSION 47
#define PD_BUGFIX_VERSION 0
#define PD_TEST_VERSION ""

Version of Pd (load time)

The sys_getversion() call retrieves the version of Pd used during loading and instantiating

    int major, minor, bugfix;
    sys_getversion(&major, &minor, &bugfix);
    if (major > 0 || minor > 42)
        return 1;
    else
        return 0;

Logging

logpost is the modern way, but only supported from 0.42. These definitions are not needed, but a text is easier to interpret than a number

#define FATAL_LOGGING  0
#define ERROR_LOGGING  1
#define NORMAL_LOGGING 2
#define DEBUG_LOGGING  3
#define ALL_LOGGING    4

This logs the load-time version of Pd at the lowest level.

if (major > 0 || minor > 42) 
    logpost(NULL, ALL_LOGGING, "this is myObject~ version %d.%d.%d",
    MYOBJ_MAJOR, MYOBJ_MINOR, MYOBJ_BUGFIX);

What are the differences between A_DEFSYM and A_SYMBOL and also A_DEFFLOAT and A_FLOAT?

they fallback to default values if no value is present. e.g. the [float]? object has a single A_DEFFLOAT argument. if you forget to provide it, [float]? will use a default value of 0 instead (you cannot change the default value). otoh, zexy's [repack]? object used a single A_FLOAT argument (iirc). if you forgot to provide it, Pd's object instantiation mechanism would complain about "Bad arguments for message ''repack'' to object 'objectmaker'" and refuse to create the object.

Replace garray_getfloatarray by garray_getfloatwords

With the advent of 64-bit CPUs?, the size of data-types began to differ. On 32-bit systems int, floats, pointers all have a size of 32-bits. On 64-bit systems, the ints and pointers are 64-bit, but the floats are still 32-bits. Because of this, the garray_getfloatarray() function could no longer be misused for integers or floats. The solution is the more generic garray_getfloatwords() which reserves 64-bits per element. Exchange code that uses:

garray_getfloatarray(x->arrayobj, &x->arraysize, &x->array)

to

garray_getfloatwords(x->arrayobj, &x->arraysize, &x->array)

To make sure you get the correct 32-bits from the 64-bit fields, the code has to be changed from:

    double y_1 = x->array[x_1];
    double y_2 = x->array[x_1 + 1];

to

    double y_1 = x->array[x_1].w_float;
    double y_2 = x->array[x_1 + 1].w_float;

Note this applies only to floats in the array, as the other data-types all are 64-bit in size.

Check for denormals

Denormals can occur when a float slowly approaches zero, like in reverb calculation. At one point there are no more significant bits left in the exponent, making the signal essential zero. But because the mantissa still contains data, the CPU still considers it non-zero. This condition is detected, and an exception raised. This means some expensive code (performance-wise) is executed each time a denormal float is used for further calculation. Not all CPUs? are troubled by denormals*, but the currently dominant ones are; Intel and ARM.

Preventing calculations with denormals is done with a check, and the cheapest ones involve bit hacks, which means it not processed as the type it is, but at the bit level. It is currently available for both 32- and 64-bits in m_pd.h as static inline int PD_BIGORSMALL(t_float f).

This function has its cost, but inlined, a check once per signal block is cheaper than processing denormals. A NaN? is the extreme opposite of a denormal, having all exponent bits set to 1. These cause in calculations (NaN? * 0 = NaN?!) and should also be removed. It is unlikely however you can produce NaNs? other than by bit-hacks.

A generic article on denormals is Denormal numbers in floating point signal processing applications.

*Denormals are useful to detect loss of accuracy in calculations where this matters. But for DSP speed is more important than accuracy.

GUI structure

On code for GUI handling a separate page would be best. For now: all GUI interactions are defined via a struct with function pointers "_widgetbehavior" defined in g_canvas.h. Some rudimentary GUI objects can be found here

.

Pointer value as Tk object name and MacOSX? 64-bit

The 64-bit MacOSX? uses addresses in the full 64-bit address range probably as a security measure. GUI-objects use pointer addressea as a run-time object name in injected Tk code. The combination makes that the full 8-byte address has to be presented in this code. Constructions as:

sys_vgui(".x%x.c create line ... 

don't work anymore, %x is a 32-bits formatting character. %lx is for 64-bit.

sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags %lxi%d\n",
         glist_getcanvas(glist),
         x_onset,           y_onset,
         x_onset + IOWIDTH, y_onset + IOHEIGHT,
         x, i);

Make sure you don't cast the pointers to unsigned ints like; (unsigned int)glist_getcanvas(glist) as this messes up the values again (A reason for the cast is to prevent a compiler warning).



Powered by IEM Powered by Plone Section 508 WCAG Valid XHTML Valid CSS Usable in any browser