Skip to content

Instantly share code, notes, and snippets.

@samhann
Created November 24, 2016 10:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save samhann/6485f8be992bdd0b96edf2e6afe7cf79 to your computer and use it in GitHub Desktop.
Save samhann/6485f8be992bdd0b96edf2e6afe7cf79 to your computer and use it in GitHub Desktop.
from midiutil.MidiFile import MIDIFile
from random import randint
from random import randrange
class MIDIGenerator(object):
def __init__(self,fileName):
self.outputFileName = fileName
self.MIDIObject = MIDIFile(1)
self.track = 0
self.MIDIObject.addTrackName(self.track,0,"Sample Track")
self.MIDIObject.addTempo(self.track,0,850)
self.volume = 100
self.channel = 0
self.notes = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','B']
self.basePitchOfC = 50
def addNote(self,note,time,duration,octave):
if note != "S":
self.MIDIObject.addNote(self.track,self.channel,self.notePitch(note,octave),time,duration,self.volume)
else:
self.MIDIObject.addNote(self.track,self.channel,50,time,duration,0)
def addChord(self,notes,time,duration):
for noteInfo in notes:
note = noteInfo[0]
octave = noteInfo[1]
self.MIDIObject.addNote(self.track,self.channel,self.notePitch(note,octave),time,duration,self.volume)
def notePitch(self,note,octave):
return self.notes.index(note) + self.basePitchOfC + (12 * octave)
def addMelody(self,melody):
trackTime = 0
for noteInfo in melody:
note = noteInfo[0]
octave = noteInfo[1]
duration = noteInfo[2]
if(note != ''):
self.addNote(note,trackTime,duration,octave)
trackTime = trackTime + duration
def writeMidiToFile(self):
binfile = open(self.outputFileName, 'wb')
self.MIDIObject.writeFile(binfile)
binfile.close()
class Composer(object):
def compose(self,scaleNotes,rhythmIntervals,duration):
scaleLen = len(scaleNotes)
counter = 0
melody = []
octave = 2
counter = 0
octaveOffset = 0
multiplier = randint(2,1000)
noteCounter = randint(1,5000)
base = randint(1,1000)
cycle_length = 2**randint(2,4)
while counter < duration:
#switch things up every now and then
noteOffset = generateNoteDelta(noteCounter+counter,multiplier,base)
# extend durations by even multiples every now and then
noteDuration = rhythmIntervals[counter % len(rhythmIntervals)] * (2**(noteOffset%2))
if counter % cycle_length == 0:
multiplier = randint(2,1000)
noteCounter = randint(1,5000)
base = randint(1,1000)
cycle_length = 2**randint(2,4)
melody.append(("S",octave + octaveOffset,noteDuration))
counter = counter + 1
continue
# some random silences
if counter % 2**randint(2,4) == 0:
if len(melody) >= 1:
last = melody.pop()
melody.append((last[0],last[1],last[2]+noteDuration + randint(0,1)))
else:
melody.append((scaleNotes[noteOffset % scaleLen],octave + octaveOffset,noteDuration))
counter = counter + 1
return melody
def numberToBase(n, b):
if n == 0:
return [0]
digits = []
while n:
digits.append(int(n % b))
n /= b
return digits[::-1]
def sumOfDigits(num):
result = 0
for digit in num:
result = result + int(digit)
return result
def generateNoteDelta(counter,base,multiplier):
return sumOfDigits(numberToBase((counter * multiplier),base))
def composeAndWriteToFile(scale,intervals,duration,fileName):
mozart = Composer()
testMelody = mozart.compose(scale,intervals,duration)
MIDIGen = MIDIGenerator(fileName)
MIDIGen.addMelody(testMelody)
MIDIGen.writeMidiToFile()
intervals = [1,1,2,1,1,2];
majorScaleNotes = ['C','D','E','F','G','A']
pentatonic = ['C','D','E','G','A']
bluesScaleNotes = ['C','D#','F','F#','A#']
arabScaleNotes = ['C','C#','E','F','G','G#','B']
composeAndWriteToFile(majorScaleNotes,intervals,500,"nyancat.mid")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment