My solution to “homework” question 1.1 in Richard Lyons’ Understanding Digital Signal Processing:

\pi \approx 4 * \sum\limits_{n=0}^{100} (-1)^n * \sum\limits_{m=0}^{100} 1/(2m-1)

To complete this problem, I had to do some extra reading on sigma notation, as well as discover some nifty little formulas (inspired by the tricks mentioned in that second link about Partial Sums). For example I did not know off the top of my head that powers of negative one alternate between positive and negative (though that’s intuitive now that I know and can think about it). The equation didn’t make much sense to me until I discovered this fact while playing with code.

Aside from reading up on the formal math syntax, I wrote a little throw-away Python and Clojure code to mess around with the algorithm and make sure I didn’t get any way-off-base ideas about the math. I started with some list comprehensions in a Python shell and once I had understood some things I switched to Clojure. At one point I got approximate pi with:

(* 4.0
     (reduce + (map #(/ 1.0  %) (map #(- (* 4 %) 3) (range 1 9999999))))
     (reduce + (map #(/ -1.0  %) (map #(- (* 4 %) 1) (range 1 9999999))))

This works by finding alternating odd numbers with 4n-3 and 4n-1. I found that trick on Stack Exchange. It was shortly after writing this code that I found the powers of one trick and suddenly the original problem made sense to me.

I’m finding Rich Lyons’ book to be the perfect level of detail; there are just enough breadcrumbs for me to piece together what I remember from high school to inform my web searches to explore the subject. It’s a little slow going, kind of like how I remember my first forays into computing. As I get this basic math theory internalized I’ll bet things will speed up dramatically, just as they did when I got enough contextual knowledge around telling computers what to do. The principles of DSP don’t look too hard to grasp conceptually; the hard part of truly learning anything is walking through it until it’s solid. So here’s me doing that.

Formal math is just another programming language. I will learn it, and then it will teach me things. I’m very excited about this. It’s also deeply gratifying to be teaching myself the formal mathematics armed with years of experience coding. Being able to test my assumptions as I go by translating the formal math into code representing how I understand it is an extremely powerful learning tool.

The harmonizer needs a little tuning, I’ll be playing around with the parameters of the ugens. But it sounds pretty decent as long as you’re within a certain range, and if you push it you can generate some pretty fun-sounding artifacts. Try beatboxing into it while humming your bassline.

I’ve hard-coded the bus my microphone is on, so you’ll need to edit that if you wanna paste this code into your REPL or your cider-connected emacs/vim. But anyway, here’s this:


(definst voice1 []
  (sound-in:ar 1)

(definst harmonize-input
  [note 60 velocity 80 gate 1 bus 1]
  (let [in (sound-in bus)
        pitch (pitch:kr in 
                        :exec-freq 500 
                        :down-sample 0.1)
        amp (/ velocity 127)
        env (env-gen (adsr 0.01 0.1 1 0.3) gate :action FREE)
        orig-midinote (cpsmidi pitch)
        interval (- note orig-midinote)
        ratio (midiratio interval)
        sig (pitch-shift:ar in :pitch-ratio ratio)
      (* env (* amp [sig sig]))
(def harmonizer 
  (midi-poly-player harmonize-input 
                       (first (midi-connected-devices))) 
                     :none ))