Smug logo small@2x

#pragma mark vDSP (ab)use

• Chris Liscio

Have you ever wished you could memset() with a stride parameter? Are you also using floating-point values?

OK, let me frame this a different way. Suppose you're drawing a waveform on the screen. You'll need to set a list of points, where the X values are pretty much constant (increasing from 0 to draw_width) and the Y values contain the waveform values (which you can scale into place using a CGAffineTransform, or other matrix transform).

Well then, you might like this neat trick.

Instead of this:

for ( int i = 0; i < draw_width; i++ ) {
    points[i].x = i;
    points[i].y = waveform[i];

You can do this:

vDSP_vclr( &(points[0].y), 2, draw_width );
vDSP_vadd( &(points[0].y), 2, waveform, 1, &(points[0].y), 2, draw_width );

Basically, the 2nd block of code above clears all the Y values (note the stride value of 2), and then adds the waveform values to set the Y values for the points.

But hey, what about setting the X values?

vDSP_vramp( (float[]){ 0 }, (float[]){ 1 }, &(points[0].x), 2, draw_width );

Boom. There's a vDSP function for (almost) everything…

(Note: You should know that the above won't work on {CG,NS}Points in a 64-bit environment. Use the vDSP_vclrD, vDSP_vaddD, and vDSP_vrampD variants, because CGFloat is a double in 64-bit land.)

But why would you do it this way? In some instances, it might actually be a decent performance win. The vDSP library is vectorized and has been tuned to run as quickly as possible on your specific CPU, while your compiler might not be aiming for that. (By default, clang doesn't enable AVX vector extensions, instead opting for SSE4.2, for instance.)

The more important reason, in my opinion, is that it helps you "think in vectors." I like writing these higher-level operations and trying to batch operations wherever I can. It means that if I ever needed to scale the waveform values, I just have to add a vDSP_vsmul() after the vDSP_vclr() rather than adding a *5 inside the foor loop (and possibly causing some stalls there.)

Similar tricks can be used to interleave mono tracks into a stereo output, easily convert between fixed and floating-point sample formats, etc. There's a huge toolbox of nifty stuff in Accelerate to play with, and we're crazy to not be finding ways to use it in situations like this…