Pointers, Functions, Pointers to Functions, Eeek!

Max is wearing his sad face, because he cannot wrap his brain around a problem pertaining to pointers.

A few weeks ago I saw Jack Ganssle's blog about a book called Understanding and Using C Pointers by Richard M. Reese. I'm a hardware design engineer by trade. The best you can say is that I dabble in the software side of things. The subtleties of pointers have long confused me, so I decided to purchase this book.

Personally, I think this book is well worth the price if you want to move beyond the "training wheel" stage of C programming. I learned a lot. Unfortunately, I didn’t learn as much as I thought I'd learned, because I cannot wrap my brain around a programming problem.

Here's the deal. This all pertains to my current BADASS Display project, which -- as you will doubtless recall -- is going to feature a 16x16 array of tri-colored LEDs as illustrated below.

I'm planning on using 16 NeoPixel strips, each containing 16 pixels, and each implementing one of the vertical columns in the array. The idea is to take an audio stream from my iPad, split out its spectral components into sixteen frequency "buckets," and then present the results in spectrum-analyzer-form on my display. (I'm still pondering how to extract the frequency spectrum data from the audio stream, but that's a problem for another day.)

Purely for the sake of discussion, let's assume that my NeoPixel strips are named "strip[0]," "strip[1],"… "strip[15]." Meanwhile, the lowest LED (i.e., the one nearest to the bottom of the array) on each strip is numbered 0, while the highest LED is numbered 15. Let's further assume that whatever is processing my audio stream, it generates a series of sixteen five-bit values called "bucket[0]," "bucket[1],"… "bucket[15]." Each of these five-bit values represents the current amplitude associated with that bucket, from 000002 (no LEDS lit) to 100002 (all LEDs lit).

Actually, my previous statement is not strictly true, because these five-bit values actually represent the number of the highest (vertically speaking) LED being lit. The way in which we subsequently display this information depends on what we wish to do -- we could display a solid bar of LEDs from LED 0 up to and including the LED in question, or we could simply light up this topmost LED, or… the list goes on.

But we are wandering off into the weeds. What I would ideally like to do is to have a function called "lightStrip()" that I can call from the main body of my program. Perhaps something like the following:

But then we come to the way in which the folks at Adafruit have created their libraries and instantiate their NeoPixel strips. I think this is done in C++, but -- thankfully -- the gory details are hidden from me. A stripped-down version of the instantiation might look something like the following:

The first parameter is the number of pixels in your strip (16 in this case), while the second parameter is the number of the digital I/O pin you wish to use to drive this strip (1 in this case).

Later on, in the body of your code, you can use calls like the following:

In the case of the "strip.setPixelColor()" function call, "i" is the number of the pixel (ranging from 0 to 15 in our case) whose color you wish to specify using three eight-bit values for the red, green, and blue channels. The interesting thing is that the "strip.setPixelColor()" function doesn’t actually drive the strip itself. It just stores the new color values in an array in memory. This means you can specify the color values of any and all elements in the strip without actually writing to the strip each time.

Once we have all of our ducks in a row, as it were, we use the "strip.show()" function to upload all of the color values into the strip. Now, we can instantiate multiple strips called "strip0," "strip1," "strip2," and so forth if we wish. But this is where I grind to a halt. How can I pass these different strips into my "lightStrip()" function? I know that in regular C it's possible to pass a pointer to one function as an argument into another function, but how does that relate to what I'm talking about here? All I can say is that any thoughts you care to share will be very gratefully received.

@JeffL: Is the processing just going to send any and all filtered data to the display (more or less "peak-reading") or will there be peak-holding or even sample averaging? (There's a popular type of display that holds and illuminates peaks WHILE the instantaneous values dance beneath them, that actually has some utility as well.)

I was planning with the "any and all" approach to start off with. But then start playing with some more interesting effects like holding and illuminating the peaks -- and then having them gradually fall -- with the instantaneous values "dancing" below. (I wouldn't know "sample averaging" if it crawled up my leg and bit me in an unfortunate place).

Check out my earlier blogs on this BADASS Display tracing my thoughts (including some videos I saw on YouTube) and you will see just how little of a clue I have (Part 1, Part 2, Part3, and Part 4).

@JeffL: I guess this will just be the monophonic combination of left and right?

I'm intending to drive this from my iPad. I plan on feeding the stereo signal in. I plan on having several modes. One will be mono (I was thinking of sampling both channels, adding them together, and dividing by two) -- in which case the entire horizontal axis could be used to display the spectrum data from this mono channel.

I would also like to play with stereo displays. One way would be to split the horizontal axis into two 8-channel bands. Another way would be to keep the 16 bands, but display the left channel "growing up from the bottom" (to a max of 8 pixels tall) and the right channel "growing down from the top)" (to a max of 8 pixels).

@JeffL: If you divide it into 16 bands then I suppose they could be 2/3-octave wide each, of course you CAN do it that way (and digital filters can be created that are just that wide) but it kind of guarantees that the display won't be terribly "relevant" or meaningful (not that it has to be).

I'm not so worried about the display being "relevant" as "looking pretty" -- what I really need is for someone who knows what they are talking about to say something like "OK Max, it's obvious you don't have a clue -- let's say the bottom frequency 'bucket' includes 50Hz and below, the top 'bucket' encompases 16KHz and above, and this is the way you should partition the rest of the spectrum into your remaining 14 'buckets'"

@JeffL: Regarding the general direction of the project, it looks as if you're trying to display the audio frequency spectrum by dividing it into 16 equal bands.

First let me remind you that if you go back to the beginning of this project, I did say that I don't really have a clue what I'm doing on the audio side -- I'm learning (or making it up) as I go along.

One of my early questions was whether the frequency spectrum (think horizontal axis) should be divided in a linear (equal bands) or logarithmic manner.

If you are still pondering about frequency detection you might conceder using the Goertzel algorithm to detect the energy in the 16 bins. The algorithm is more efficient then an FFT when measuring the energy at specific frequencies.

Consider two ways you could get a package delivered to your house. The normal way: you give UPS your address and they send a cheerful driver in a brown truck to plunk the package down on your porch.

To save your poor driver some time, you could instead make a duplicate of your house, hire a house mover to move the house to the local UPS office where they put the package on the porch and have the mover bring the house back to you. The mover demolishes your original house and replaces it with the house that has your package which you open only to discover it's the wrong color and you have to ship it back....

Passing pointers instead of the whole object is more efficient. Of course there are some down sides to this. Giving your address to some hoodlums who come over and have a huge party and trash the place is not good. In that case, making a duplicate of the house that they can do what they want to with is a good option. You could also lock up certain parts of the house and post big signs that say "PRIVATE KEEP OUT" in those critical areas. Let them do what they want in the tornado shelter, just keep them out of the room with all the expensive antiques.

Pointer to a function? Same idea except now the memory pointed to contains code instead of data. It's like the address of your lawn mower. So you tell your son to work on his homework and every time he finishes one assignment to start the mower and mow one section of the lawn. You also tell him where the mower is in case he forgot. You sit in the garage watching the mower and every time you see it start up you know that another assignment was finished.

is making use of an implicitly defined assignment operator, which I believe will only do a shallow copy. (There is a temporary Adafruit_NeoPixel created on the stack, which is then copied into the Adafruit_NeoPixel at strip[i].)

Regarding the general direction of the project, it looks as if you're trying to display the audio frequency spectrum by dividing it into 16 equal bands. Actually that's kind of a bizarre selection, it's typically looked on as 30 or 31 1/3-octave bands, or 10 one-octave bands. If you divide it into 16 bands then I suppose they could be 2/3-octave wide each, of course you CAN do it that way (and digital filters can be created that are just that wide) but it kind of guarantees that the display won't be terribly "relevant" or meaningful (not that it has to be). And I guess this will just be the monophonic combination of left and right? Is the processing just going to send any and all filtered data to the display (more or less "peak-reading") or will there be peak-holding or even sample averaging? (There's a popular type of display that holds and illuminates peaks WHILE the instantaneous values dance beneath them, that actually has some utility as well.) Also I imagine you'll want to make this display logarithmic, with each LED representing 2 or 3 decibels higher level, and maybe even make the lower LEDs represent larger values (so the display comes closer to handling the much larger dynamic range that the ear responds to than just 32 or 48 decibels)? Will there be a provision to "calibrate" this so it can read actual sound levels? How about a "master level" channel to one side to show the unfiltered level? (You ought to think about whether you keep the lowest position always "on" as a kind of visual "anchor", it's commonly done that way anyway.) How is color going to be applied, there's a convention that "acceptable" levels at the bottom are green, levels above that are yellow, even higher are red, will you "go conventional" or do something out of the ordinary? These are all the kind of decisions you ought to think about before taking this to the next stage. (Then again maybe I'm just a LITTLE obsessive about this stuff since I used to design audio gear for sale to pros, back in another lifetime and maybe another universe, I can't really recall right now...)