Using Sox Play to Help Learn Guitar (Shallow Thoughts)

Akkana's Musings on Open Source Computing and Technology, Science, and Nature.

Thu, 18 Apr 2024

Using Sox Play to Help Learn Guitar

I mentioned last month that I'm learning guitar. It's been going well and I'm having fun. But I've gotten to the point where I sometimes get chords confused: a song is listed as using E major and I play D major instead.

Also, it's important to practice transitions between chords, which is easy when you only know three chords; but with eight or so, I had stopped practicing transitions in general and was only practicing the ones that occur in songs I like to play.

I found myself wishing I had something like flash cards for guitar chords.

Someone must have already written that, right? But I couldn't find anything promising with a web search. And besides, it's more fun to write programs than to flail at unhelpful search engines, and you always end up learning something new.

I envisioned something like this: the program displays the name of a chord, like A or Em, I play it, and then after a delay, the computer plays the chord too (so I can see if I'm playing the right one) and displays the fretboard diagram (in case I've forgotten the fingering and need a reminder).

I found a nice python snippet at 101 Computing's Guitar Chords Reader that takes fretboard notation like "xx0232" (the first two strings are muted, the third is open, and the highest three have fingers on the second, third, and second fret), and displays it as a nice diagram like

D
xx____
||||||
|||O|O
||||O|
||||||
So I used that as my starting base (though I spaced out the strings to make it easier to read quickly).

Playing Chords in Python

The first goal was to play a chord from Python. I've played chords before, by adding up wave forms then playing them with PyGame, but that's just basic waveforms like sine or square waves. I'd settle for that if need be, but I'd rather play something that actually sounds like a guitar chord. And weirdly, I couldn't find anything like that already written. (Sound is a known weak point in Python's libraries.) I found a few pages that referenced pygame.midi, but none of them actually produced sound on my machine. I guess you need to do some additional configuration before midi works.

But while reading the sox man page in order to tweak my command-line metronome, I noticed this absolute gem which plays a guitar chord:

play -n synth pl G2 pl B2 pl D3 pl G3 pl D4 pl G4 \
      delay 0 .05 .1 .15 .2 .25 remix - fade 0 4 .1 norm -1
(pl, it turns out, is short for plucked. The man page gives examples of several other interesting sounds built in to sox.)

If I couldn't find an easy way to play a guitar chord directly from Python, I could always do it by calling sox play.

It took longer than I expected, considering how good the man page example is, to generalize the command. The man page, while long and detailed and full of helpful examples, is a bit light on details like what do the numbers in G2 and D4 mean? and how do those delay arguments work? and how do norm and remix work? and what order do arguments have to be in? (which, it turns out, sox is picky about). And how do you turn off all the chatter to standard output? But after most of a day of fiddling, I had a couple of nice general routines to play chords and note sequences.

Sox Arguments

Here are some of the things I learned about sox arguments:

play -nq -t alsa synth pl D3 pl A3 pl D4 pl F#4 delay 0 0.06 0.12 0.18 remix - fade 0 1.75 .1 norm -1 vol 0.25
-n
Use no input file
-q
quiet: suppress (some, but not all) output
-t alsa
quieter: suppress a warning about ALSA output
synth
synthesize sounds rather than using an input file
pl
plucked string waveform
D3, A3, D4 etc.
Numbers reflect a C scale, so it goes F1, G1, A1, B1, C2, D2, ... rather than F1, G1, A2, B2, C2, D2 like I initially guessed. You can specify sharps and flats, e.g. E#2 or Ab2.
delay 0 0.06 0.12 0.18
The second tone will start .06 seconds after the first one; the third will start 0.12 seconds after the first, etc.
remix
mix the different tones together into one channel: needed for norm, below.
fade 0 1.75 .1
fade smoothly out in 1.75 seconds. 0 is the fade-in length, so there's no fade in.
Important note: the stop position is 1.75 seconds after the beginning of the first tone, not the last one. So you need to know the cumulative length of all your delays, or else you'll make the fade too short and the last several tones will be cut off.
I think the third number (.1) is fade-out-length; experiment with this and stop position to get something that sounds okay.
norm -1
normalize volumes of the various channels; otherwise some notes will be too quiet to hear while others are loud. Only works if remix has previously been specified.
vol .25
a quarter of maximum volume

Guitar Chord Flash Cards

Now I had enough to write my guitarflash.py command-line flash-card program. It prints out the chord name, big, using figlet, like this:

    _              
   / \   _ __ ___  
  / _ \ | '_ ` _ \ 
 / ___ \| | | | | |
/_/   \_\_| |_| |_|
                   
waits a bit for me to find the chord and play it; then it plays the chord several times so I can hear if I'm playing the right chord; then finally it prints the string diagram:
  Am
 x _ _ _ _ _
 | | | | O |
 | | O O | |
 | | | | | |
 | | | | | |
so if I've really forgotten the chord, I can see how to play it. Then it switches to the next chord.

I'm finding guitarflash pretty fun to play along with, and helpful in memorizing all the chords I've learned so far.

Tags: , , , ,
[ 20:02 Apr 18, 2024    More linux | permalink to this entry | ]

Comments via Disqus:

blog comments powered by Disqus