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.

My mother works as an IT consultant in the Bay Area (it’s a pretty rad story, she taught me my computing fundamentals as a kid but could never break into the industry due to its biases and such, until ten years ago after my folks relocated to the Bay Area during a tumultuous time for all of us. I stayed in Seattle and broke into tech a few years later).

She just handed-me-down a glorious Dell XPS 13, which I immediately installed my standard Arch Linux + Awesome WM dev environment on.

Hmm. Beautiful screen, but I can’t see anything. I squinted through the Arch install process, but when I got my window manager and favorite dev tools up-and-running, something needed to be done.

Now, it turns out that I really didn’t need to do this and it was just a fun exercise:


This code scales the workspace and window decorations — I need to write a similar function for the menus. It assumes that a theme’s font will be stored in a variable theme.font in the format “fontname 7”, which is what I found to be the case in the Arch theme. I didn’t do any other checking or testing. Without further ado, here’s what I added to my ~/.config/rc.lua:

local theme_name = "arch"

local function scale_theme_font()
  local theme = awful.util.get_themes_dir() .. theme_name .. "/theme.lua"
  local theme_config = gears.protected_call(dofile, theme)
  local fs_start, fs_end = string.find(theme_config.font, "%d+$")
  local scaled_fontsize = tonumber(string.sub(theme_config.font, fs_start, fs_end)) + 5
  local scaled_font = string.sub(theme_config.font, 0, (fs_start-1)) .. tostring(scaled_fontsize)
  theme_config.font = scaled_font
  return theme_config

local theme = scale_theme_font()

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 ))