A phone rings with a little tune. A toy keyboard plays “Happy Birthday” when you press a button. A computer has no strings to pluck and no drum to hit, only numbers. So how does it play a tune?
The answer is short. A note is a number: how many times a second something vibrates. A tune is a list of those numbers. And the most surprising part: to play the same tune higher or lower, the computer multiplies every number by the same amount.
Try it now. Each key is a note of the sargam, Sa Re Ga Ma Pa Dha Ni and the next Sa, with its number under it. Tap a key to hear it.
Sa vibrates 240 times a second. The next Sa up, Sa′, sounds like the same note, only higher. How many times a second do you think Sa′ vibrates?
Pick an answer to see why.
You need: for the blocks, variables from Grade 7 (and how sound is stored as samples, Grade 7). For the Python, lists and functions, from Grade 8.
Try it
Use the keys above, with Sa at 240.
- a.Read the number on each key. Which keys have numbers that are exactly half or twice another key’s?
- b.Tap Pa. In the picture, count Sa’s waves (gray) and Pa’s waves (blue) between two dashed lines. What do you notice?
- c.Now tap Ga, Ma, Dha, Re and Ni in turn. For which notes do the dashed lines come close together, and for which are there none at all?
- d.Press Play the tune with Sa at 240, then with Sa at 360 and 200. Is it the same tune?
How it works
A note is a number
Pluck a string of a guitar or a sarangi, and it moves back and forth, very fast. Each time it moves, it pushes the air, and the pushes reach your ear. How many times it moves back and forth each second is the note’s pitch. Few vibrations a second make a low note; many make a high one. Vibrations a second are counted in hertz (Hz): a note of 240 Hz vibrates 240 times every second.
Two numbers matter most:
- Twice the number sounds like the same note, higher. Sa at 240 Hz and Sa′ at 480 Hz sound so alike that they share a name. The step from a note to the one with twice its number is an octave.
- Pa is 3/2 of Sa. Whatever number a singer picks for Sa, Pa is one and a half times it.
A flute plays Sa at 300 Hz. What is its Pa?
Pick an answer to see why.
The scale’s fractions
The other notes are fractions of Sa too. In one common way of tuning, they are these:
| Note | Sa | Re | Ga | Ma | Pa | Dha | Ni | Sa′ |
|---|---|---|---|---|---|---|---|---|
| Fraction of Sa | 1 | 9/8 | 5/4 | 4/3 | 3/2 | 5/3 | 15/8 | 2 |
| With Sa at 240 Hz | 240 | 270 | 300 | 320 | 360 | 400 | 450 | 480 |
Musicians don’t all tune Re, Ga, Dha and Ni exactly alike, and a raag may raise or lower some of them. But Sa and Pa never move: in Hindustani music they are called the achal notes, the ones that don’t move. Once Sa is chosen, Pa is fixed at 3/2 of it, and Sa′ at twice it.
The dashed lines in the widget show why these fractions are special. When Pa is 3/2 of Sa, every 2 waves of Sa take exactly as long as 3 waves of Pa, so the two waves keep lining up. Notes whose waves line up often, like Sa and Pa, sound smooth when they are played together.
From numbers to sound
You know from Grade 7 Grade 7: Sound as samples that a computer keeps a sound as a list of samples: how far the speaker should be pushed out or pulled in, thousands of times a second. To play a note of 240 Hz, the computer works out samples that rise and fall 240 times a second, and sends them to the speaker. The speaker moves the air back and forth 240 times a second, and you hear Sa.
So a tune is numbers all the way down: a list of notes, each a number of hertz, each turned into thousands of samples.
The computer plays a tune with Sa at 240 Hz. You want the same tune, an octave higher. What does it do to every note’s number?
Pick an answer to see why.
Program it
With blocks
Here is the start of a well-known tune, Twinkle, Twinkle, Little Star, as a block program. Each play block plays one note: its hertz and how many seconds it lasts. The pairs of notes are repeats.
Every number in that program was worked out from Sa = 240. So the next program doesn’t write the numbers at all. It keeps Sa in a variable, sa, and works out each note from it: Pa is sa × 3 ÷ 2, Dha is sa × 5 ÷ 3, and so on.
In Python (from Grade 8)
Now the samples themselves. from sound import play gives you play(samples, rate): a list of numbers from −1 to 1, rate of them a second, played by the page. (sound is this page’s own module; on your own computer you would need a sound library instead.) Press Run, then Play under the output. Nothing plays until you press it.
Step 1: one note
A smooth vibration that goes up and down evenly is a sine wave. math.sin gives it: as its number grows by 2π (about 6.28), it goes up, down and back to the middle once. So math.sin(2 * math.pi * hz * t) goes round hz times every second of t. The program makes one sample every 1/8,000 of a second, and lets each note fade away, like a plucked string.
import mathfrom sound import play RATE = 8000 # samples a second def note(hz, seconds): samples = [] n = int(RATE * seconds) for i in range(n): t = i / RATE # this sample's time, in seconds fade = 1 - i / n # dies away, like a plucked string samples.append(0.5 * fade * math.sin(2 * math.pi * hz * t)) return samples def waves(samples): # count how often the wave crosses the middle going up count = 0 for i in range(1, len(samples)): if samples[i - 1] <= 0 and samples[i] > 0: count = count + 1 return count sa = note(240, 1)print(len(sa), 'samples')print([round(x, 2) for x in sa[:12]])print(waves(sa), 'waves in one second')print(waves(note(480, 1)), 'waves in one second, for Sa an octave up')play(sa, RATE)play(note(480, 1), RATE)Output
8000 samples[0.0, 0.09, 0.18, 0.27, 0.34, 0.4, 0.45, 0.48, 0.5, 0.5, 0.47, 0.44]240 waves in one second480 waves in one second, for Sa an octave upOne second of Sa is 8,000 numbers, and the wave in them goes up and down exactly 240 times. Play both sounds: the same note, the second one higher. (On a phone’s small speaker low notes are quiet; headphones help.)
Step 2: a tune is a list
Now the tune from the blocks, as two lists: each note’s hertz, and how many beats it lasts. A beat here is 0.3 seconds.
import mathfrom sound import play RATE = 8000 def note(hz, seconds): samples = [] n = int(RATE * seconds) for i in range(n): t = i / RATE fade = 1 - i / n samples.append(0.5 * fade * math.sin(2 * math.pi * hz * t)) return samples # Twinkle, Twinkle, Little Star: Sa Sa Pa Pa Dha Dha Pa, Ma Ma Ga Ga Re Re Satune = [240, 240, 360, 360, 400, 400, 360, 320, 320, 300, 300, 270, 270, 240]beats = [1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2] def song(tune, beats): samples = [] for k in range(len(tune)): samples = samples + note(tune[k], 0.3 * beats[k]) return samples twinkle = song(tune, beats)print(len(twinkle), 'samples:', len(twinkle) / RATE, 'seconds')play(twinkle, RATE)Output
38400 samples: 4.8 secondssamples + note(...) joins two lists into one, so the notes come one after another. A tune of 14 numbers became 38,400.
Step 3: a new key, two ways
What happens if you change every number in the tune the same way? The program makes the tune again in two ways: every number times 1.5, and every number plus 120. Both start on 360. Then it looks at each step of the tune: each note as a fraction of the note before it.
import mathfrom sound import play RATE = 8000 def note(hz, seconds): samples = [] n = int(RATE * seconds) for i in range(n): t = i / RATE fade = 1 - i / n samples.append(0.5 * fade * math.sin(2 * math.pi * hz * t)) return samples def song(tune, beats): samples = [] for k in range(len(tune)): samples = samples + note(tune[k], 0.3 * beats[k]) return samples def steps(tune): # each note as a fraction of the note before it out = [] for k in range(1, len(tune)): out.append(round(tune[k] / tune[k - 1], 2)) return out tune = [240, 240, 360, 360, 400, 400, 360, 320, 320, 300, 300, 270, 270, 240]beats = [1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2] times = [] # every number times 1.5plus = [] # every number plus 120for hz in tune: times.append(hz * 1.5) plus.append(hz + 120) print('tune: ', tune[:7])print('× 1.5:', times[:7])print('+ 120:', plus[:7])print()print('steps of the tune: ', steps(tune)[:6])print('steps of × 1.5: ', steps(times)[:6])print('steps of + 120: ', steps(plus)[:6]) play(song(tune, beats), RATE)play(song(times, beats), RATE)play(song(plus, beats), RATE)Output
tune: [240, 240, 360, 360, 400, 400, 360]× 1.5: [360.0, 360.0, 540.0, 540.0, 600.0, 600.0, 540.0]+ 120: [360, 360, 480, 480, 520, 520, 480] steps of the tune: [1.0, 1.5, 1.0, 1.11, 1.0, 0.9]steps of × 1.5: [1.0, 1.5, 1.0, 1.11, 1.0, 0.9]steps of + 120: [1.0, 1.33, 1.0, 1.08, 1.0, 0.92]Play all three. The first two are the same tune; the third sounds wrong from its third note.
What your program shows
- A tune is a list of numbers. Your program turned 14 numbers into 38,400 samples, and the speaker played Twinkle, Twinkle.
- A note is a number of vibrations a second. The wave your program made for Sa went up and down exactly 240 times in a second, and the one for Sa′ 480 times.
- Multiplying keeps the tune; adding breaks it. Times 1.5, every step of the tune stayed the same fraction (1.5, 1.11, 0.9…), and it sounded like the same tune in a new key. Plus 120, the big first jump, Sa up to Pa (× 1.5), shrank to × 1.33, which is Sa up to Ma: the tune’s shape changed.
Your ear doesn’t hear the numbers themselves. It hears how each note compares with the others: the fractions. Keep the fractions, and any Sa gives the same tune. That is why a singer can choose a Sa that suits their voice and the harmonium player can follow, and why one line of a program, set sa to 360, moves a whole song.
Going further still
The harmonium’s twelve equal steps
A harmonium can’t follow the fractions exactly. Its keys play twelve equal steps to the octave: each key’s number is the one before it multiplied by the same amount, 2 to the power 1/12 (about 1.0595), so twelve steps make exactly 2. That way it can play in any key, but most of its notes are slightly off the fractions. How far off?
SA = 240STEP = 2 ** (1 / 12) # one step of the harmonium: 12 of them make 2 # each note: its name, its fraction, and how many harmonium steps above SaNOTES = [['Re', 9 / 8, 2], ['Ga', 5 / 4, 4], ['Ma', 4 / 3, 5], ['Pa', 3 / 2, 7], ['Dha', 5 / 3, 9], ['Ni', 15 / 8, 11], ["Sa'", 2 / 1, 12]] for note in NOTES: tuned = SA * note[1] harmonium = SA * STEP ** note[2] print(note[0], ': fraction', round(tuned, 1), 'Hz, harmonium', round(harmonium, 1), 'Hz, off by', round(harmonium - tuned, 1))Output
Re : fraction 270.0 Hz, harmonium 269.4 Hz, off by -0.6Ga : fraction 300.0 Hz, harmonium 302.4 Hz, off by 2.4Ma : fraction 320.0 Hz, harmonium 320.4 Hz, off by 0.4Pa : fraction 360.0 Hz, harmonium 359.6 Hz, off by -0.4Dha : fraction 400.0 Hz, harmonium 403.6 Hz, off by 3.6Ni : fraction 450.0 Hz, harmonium 453.1 Hz, off by 3.1Sa' : fraction 480.0 Hz, harmonium 480.0 Hz, off by 0.0Pa is less than half a hertz off, but Ga, Dha and Ni are 2 to 4 hertz sharp. Its notes are fixed, and it can’t play the fine shades between them that Indian classical music uses. Partly for that reason, All India Radio kept the harmonium off the air from 1940 to 1971.
Things to try
- Make
notesound richer: add a quieter wave at twice the note’s hertz,0.25 * math.sin(2 * math.pi * 2 * hz * t). The pitch stays the same (the whole pattern still repeatshztimes a second), but the note sounds more like a real instrument. - Write
octave_up(tune)that gives back a new list with every number doubled, and play the tune an octave up.
Challenges
★ Find Pa (blocks)
Finish the program so that, after it asks for Sa’s hertz, it says Pa’s, and nothing else (for 240 it says 360). Then press Test.
★★ A new key (Python, from Grade 8)
Write new_key(tune, old_sa, new_sa): it gives back a new list, the tune moved from a Sa of old_sa to a Sa of new_sa, each number rounded to 1 decimal place with round(x, 1).
def new_key(tune, old_sa, new_sa): # every note moved so that old_sa becomes new_sa return tune print(new_key([240, 240, 360, 360, 400], 240, 300))★★★ Name the notes (Python, from Grade 8)
A program listens to someone sing and measures the hertz of each note, a little off, as singing is. Write sargam(tune, sa): for each number, the name of the nearest note of the scale for that Sa, from the table above. Notes in the octave above get a ' after the name, one for each octave up ("Sa'", "Pa''"), and notes below Sa get a . in front, one for each octave down ('.Pa').
def sargam(tune, sa): # the name of the nearest note for each number return [] print(sargam([240, 360, 400, 480], 240))Questions
What does “a note of 360 Hz” mean?
Pick an answer to see why.
With Sa at 200 Hz, which of these is Sa′, the Sa an octave higher?
Pick an answer to see why.
A tune starts 300, 300, 450, 450. Write the same four notes in the key with Sa at 240 (the tune’s Sa is 300).
Answer
Rina wants her tune higher, so she adds 100 to every note. Explain why it no longer sounds like the same tune, and what she should do instead.
Answer
How many samples does a computer need for a 2-second note, at 8,000 samples a second? And how many times does the wave of a 300 Hz note go up and down in those 2 seconds?
Answer
Why are Sa and Pa called achal, “not moving”, while other notes may be tuned a little differently?
Answer
Where to go next
- Grade 7, Sound as samples: how a sound becomes a list of numbers, and how many bytes it takes.
- Grade 8, Photos, Sound and Video: recording clean sound, and music you may use in your own videos.
- Grade 8, Lists: the lists a tune is kept in.
- How Does a Computer Make a Sitar-like Note out of Noise? A note that sounds like a plucked string, made from random numbers, and Raag Bhupali on it.
- How Does a Tuner Hear Which Note You Play? Finding a note’s hertz from a recording, by comparing the sound with itself (Grades 9–12). (Coming soon.)
Found a mistake? Please tell us.
