I wrote a blogpost earlier on harnessing musical grooves with code, and at the end of one fine unproductive day in an epiphanic kill-yourself moment, decided that I’d start off and give it a try. An hour of python hacking later, the result was quite pleasing.
Making sound is pretty easy, but what distinguishes music is the structure and the scales. That’s the consensus, but there’s also the possibility that human ears might just be used to what we called Music today, which is probably why we’re used to songs in 4/4 time signatures and we like the Beatles. Make no mistake, I love the Beatles. Decades of listening to otherwordly cacophony in, say, 25/16, might probably make one a magnificent weirdo.
Ok, so I decided to start off with a note-generator in 4/4 time. Here’s the code.
- First, the basic note-generator. Generates a sine wave of user-specified frequency freq, volume vol and duration dur, and appends the sound to a file with a filename name. I use the extension .au, but .wav is fine too. Anything else isn’t.
from struct import packfrom math import sin, piimport timefrom populate import _listen_
def _play_(name, freq, dur, vol, mode='ab'): """ Generate sound with frequency freq, duration dur, and volume vol """ _dump_ = open(name, mode) _dump_.write('.snd' + pack('>5L', 24, 8*dur, 2, 8000, 1)) _factor_ = 2 * pi * freq/8000 for count in range(8 * dur): _wave_ = sin(count * _factor_) _dump_.write(pack('b', vol * 64 * _wave_)) _dump_.close()
if __name__=="__main__": _play_("foo.au", 50, 1000, 1, 'ab')
- Next, the Scales. Two dictionaries, _freq_ and _midi_, which are populated with note-frequency key-value pairs using the _listen_ function. From this table, A0 has a frequency value of 27.50, and the ascending notes are just part of a geometric progression with a common ratio 1.059463094. So we start off with A0 (Lower notes like C0 have very low frequencies and are barely heard. The discernibility starts at around A0.) and assign note symbols with respective frequencies. When _listen_ is run, the two dicts are populated.
_freq_={}_midi_={}
def _listen_(_firstNoteInRange_, _lastNoteInRange_, _noteInterval_, _midiCounter_): """ Fills dictionaries with note symbols and corresponding frequency values """ notes = ['A0', 'A#0', 'B0', 'C1', 'C#1', 'D1', 'D#1', 'E1', 'F1', 'F#1', 'G1', 'G#1', 'A1', 'A#1', 'B1', 'C2', 'C#2', 'D2', 'D#2', 'E2', 'F2', 'F#2', 'G2', 'G#2', 'A2', 'A#2', 'B2', 'C3', 'C#3', 'D3', 'D#3', 'E3', 'F3', 'F#3', 'G3', 'G#3', 'A3', 'A#3', 'B3', 'C4', 'C#4', 'D4', 'D#4', 'E4', 'F4', 'F#4', 'G4', 'G#4', 'A4', 'A#4', 'B4', 'C5', 'C#5', 'D5', 'D#5', 'E5', 'F5', 'F#5', 'G5', 'G#5', 'A5', 'A#5', 'B5', 'C6', 'C#6', 'D6', 'D#6', 'E6', 'F6', 'F#6', 'G6', 'G#6', 'A6', 'A#6', 'B6', 'C7', 'C#7', 'D7', 'D#7', 'E7', 'F7', 'F#7', 'G7', 'G#7', 'A7', 'A#7', 'B7', 'C8', 'C#8', 'D8', 'D#8']
_bwdf_ = 0 while _firstNoteInRange_ <= _lastNoteInRange_: _freq_[notes[_bwdf_]] = _firstNoteInRange_ _midi_[notes[_bwdf_]] = _midiCounter_ _firstNoteInRange_ *= _noteInterval_ _firstNoteInRange_ = round(_firstNoteInRange_, 4) _bwdf_ += 1 _midiCounter_ += 1
if __name__=="__main__": _listen_(27.5, 5000, 1.059463094, 21)
- So now the notes are ready to be thrown in together in a structure. 4/4 time, hence 4 _beats_, a randomly chosen 1-to-5 second _intervalLength_, which I decided not to use since I’m setting _interval_ to 0, so there will be no silence between the notes. So, one _barLength_ contains _beats_ number of _noteLength_s and _interval_s. Again, this is a bit redundant and for future improv. I chose the C-major Arpeggio arbitrarily to test out the module. To make different riffs every time, I randomized the selection of notes and appended them to an empty list, in the first loop. In the second loop, the innerloop churns out the 4/4 riff, adding a 0-second interval for a snappy effect during the transition from one note to another. The outerloop repeats the riff twice. Now the file is appended with the riff. Running this module n times appends n riffs to the foo.au file.
import populateimport soundimport random
populate._listen_(27.5, 5000, 1.059463094, 21)_beats_ = 4_intervalLength_ = random.choice(range(1,5))*1000_interval_ = 0_noteLength_ = random.choice([500,1000,2000,3000,4000,5000])_barLength_ = _beats_ * (_intervalLength_ + _noteLength_)_CmajorArpeggio_ = ['C3','E3','G3','B3']_note_ = []
for base in range(1, _beats_+1): _note_.append(random.choice(_CmajorArpeggio_))
for repeat in range(1,3): for base in range(1, _beats_+1): sound._play_("foo.au", populate._freq_[_note_[base-1]], _noteLength_, 1, 'ab') sound._play_("foo.au", 0, _interval_, 1, 'ab')
Arpeggio in C Major runs through the first C, the third E and the fifth G. Adding the B was a fuckup, but it added a melancholy minor-key flavor, so I’m not grumbling.
The full code is here.
And here’s one such generated file, converted to mp3 since WordPress doesn’t allow .au files.
Disclaimer: I do not own responsibility for ear damage or nausea.
Audio clip: Adobe Flash Player (version 9 or above) is required to play this audio clip. Download the latest version here. You also need to have JavaScript enabled in your browser.
That didn’t sound really pleasant, so I thought I’d go ahead and improvise on the generated C Major Arpeggio riff with my electric guitar.
Audio clip: Adobe Flash Player (version 9 or above) is required to play this audio clip. Download the latest version here. You also need to have JavaScript enabled in your browser.
And then I got really greedy and added an acoustic touch.
Audio clip: Adobe Flash Player (version 9 or above) is required to play this audio clip. Download the latest version here. You also need to have JavaScript enabled in your browser.
I plan to try out different patterns, styles, algorithms and time-signatures. Since this can be a never-ending venture, I’ve opened a new page here for Music. If you’re interested in collaborating, feel free to shoot me a mail.
Here’s a wanting list of TODOs:
TODOs:Incorporate Karplus-Strong for plucked-string sound.Try different algorithms.Reduce randomizations.Make it choose between different styles (rock, pop, reggae, swing etc), based on different time signatures.Add a database of scales and corresponding notes.Think of more TODOs.
/SignOff

