class MidiWriter: def __init__(self): # Log frequencies and durations to files. We can then parse these in the autochord class. self.file = MIDIFile(1) self.chord_file = MIDIFile(3) self.rest_length = 0 self.prev_start_time = 0 def add_tempo(self, tempo): self.file.addTempo(0, 0, tempo) self.chord_file.addTempo(0, 0, tempo) def add_midi_note(self, volume, pitch, beat, duration, rest_state, des_len): if(check_rest(rest_state) == True): self.rest_length = duration else: if(self.prev_start_time != beat): if(duration + beat < des_len): self.file.addNote(0, 0, pitch, beat + self.rest_length, duration, volume) self.prev_start_time = beat + self.rest_length self.rest_length = 0 def add_midi_chord(self, c, chord_volume, root_n, third_n, fifth_n, chord_beat, chord_duration, desired_length): if(check_chord(c) == True): if(chord_duration + chord_beat < desired_length): self.chord_file.addNote(0, 0, root_n, chord_beat, chord_duration, chord_volume) self.chord_file.addNote(0, 0, third_n, chord_beat, chord_duration, chord_volume) self.chord_file.addNote(0, 0, fifth_n, chord_beat, chord_duration, chord_volume) def write(self): with open("midi.mid", "wb") as f: self.file.writeFile(f) with open("chord_midi.mid", "wb") as f: self.chord_file.writeFile(f) def close_midi(self): self.file.close() self.chord_file.close()
else: logging.info('accepted proposal') result.append(prop_sp) prev_interval = prop_interval break return result sm = cg.ScaleManager() cp_scale = sm.build_scale() midi_content = MIDIFile(2) midi_content.addTrackName(0, 0, 'cantus firmus') midi_content.addTrackName(1, 0, 'counterpoint') cf_tune = cg.Tune( cp_scale, ['C1', 'D1', 'F1', 'E1', 'F1', 'G1', 'A1', 'G1', 'E1', 'D1', 'C1']) cp_tune = cg.Tune(cp_scale, real_cp2(cp_scale, cf_tune)) for i, v in enumerate(cf_tune.mps): midi_content.addNote(0, 0, v, i, 1, 100) for i, v in enumerate(cp_tune.mps): midi_content.addNote(1, 0, v, i + 0.25, 1, 100) with open('c:/temp/test.mid', "wb+") as f: midi_content.writeFile(f) midi_content.close()
image = Image.fromarray(imagePix) # Preview the image if desired if args.s: image.show() # Start our MIDI file. mFile = MIDIFile(numTracks=1, adjust_origin=True,file_format=1) # Loop through image for y in range(newSize[1]): for x in range(128): pixel = imagePix[y,x] if (args.g): OnPixelGrad(mFile,x,y,pixel,args.y) else: OnPixelThresh(mFile,x,y,pixel,args.y,args.t) # End any notes we had. for x in range(128): if (args.g): OnPixelGrad(mFile,x,newSize[1],0,args.y) else: OnPixelThresh(mFile,x,newSize[1],0, args.y,args.t) # Write out the MIDI file. midiOut = open(args.output_midi, 'wb') mFile.writeFile(midiOut) mFile.close()
class DrumMachine: # set global tempo will effect everything - no # tempo changes between cuts just one global tempo tempo = 0 # holds the cuts which are to be rendered to the midi file allcuts = [] # the print-out version of the cut ids so the user knows which beat is which number cutids = [] # holds unique cuts for use with the buildFromArray method unique = [] # holds unique id for each item of array above uniqueid = [] # counter for number of allcuts - starts at 1 not 0 globalid = 1 # is incremented everytime a unique pattern is pushed and therefore saved in unique cutid = 1 # If a new unique cut is made store it in unique and then set newcut to False # starts at True because first cut is always unique newcut = True # temp for patterns being edited edpad = None # id for pattern being editing editing = None # when editing drum layers # we can overwrite or add to the layers (discontinued) overwrite = True # push copy pushc = False # can copy cancopy = False def __init__(self): self.tempo = 120 # default self.tempcut = None # Create a Midi file def createMidi(self): self.midif = MIDIFile(3) self.midif.addTempo(0, 0, self.tempo) # make it so midi file is in memory so it can play without having to save to disk def createMem(self): self.memFile = BytesIO() # Write the Midi file to memory # and load it into pygame so it can be played def writeMidiMem(self): self.midif.writeFile(self.memFile) self.memFile.seek(0) pygame.mixer.music.load(self.memFile) # free memory and close files def freeMidiMem(self): ## pygame.mixer.music.unload() self.memFile.close() self.midif.close() # create a drum layer of a given type def drumLayer(self, instr, beat, track, prob, pulse=0, barsin=0): bars = 4 if self.overwrite == True or self.edpad == None: drumcut = DrumCutLayer(beat, track) else: if instr == Snare and self.edpad.snaredrumlayer != None: drumcut = self.edpad.snaredrumlayer else: drumcut = DrumCutLayer(beat, track) if instr == BassDrum and self.edpad.bassdrumlayer != None: drumcut = self.edpad.bassdrumlayer else: drumcut = DrumCutLayer(beat, track) if instr == Toms and self.edpad.tomsdrumlayer != None: drumcut = self.edpad.tomsdrumlayer else: drumcut = DrumCutLayer(beat, track) if instr != Snare and instr != BassDrum and instr != Toms: if self.edpad.cymbaldrumlayer != None: drumcut = self.edpad.cymbaldrumlayer else: drumcut = DrumCutLayer(beat, track) c = b = 0 n = 1 mod4hit = 3 dec4hit = [1, 0.50, 0.25][randrange(0, 3)] addtovol = 0 if instr == Snare: addtovol = 20 elif instr == BassDrum: addtovol = 17 while b < bars: hitit = randrange(0, prob) + 1 if (pulse != 0 and n % pulse == 0) or (prob > 0 and hitit == 1): volu = randrange(100 + addtovol, 128) drumcut.ntimesbeat += [n * beat] drumcut.volumes += [volu] drumcut.whathit += [instr[randrange(0, len(instr))]] c += beat if c >= 1: c = 0 b += 1 n += 1 return drumcut # a CompleteCut is made by layering -- calling drumLayer() def drumCut(self): cc = CompleteCut() cc.bassdrumlayer = self.drumLayer(BassDrum, ranbeat(), 0, hitprob(), pulseit(6), 1) cc.snaredrumlayer = self.drumLayer(Snare, snarebeat(), 1, hitprob(), pulseit(17) - 1, 1) if randrange(0, 2) == 1: cc.tomsdrumlayer = self.drumLayer(Toms, tombeat(), 1, hitprob(), pulseit(7) - 1, 1) for pc in range(8): if randrange(0, 8) == 1: cc.cymbaldrumlayer = self.drumLayer(randomcymbal(), cymbeat(), 2, hitprob(), pulseit(7) - 1, 1) self.tempcut = cc # call after creating midi context def CreateDrumLayer(self, drumclayer, offset): if drumclayer == None: return for hit in range(len(drumclayer.whathit)): self.midif.addNote(drumclayer.track, 9, drumclayer.whathit[hit], drumclayer.ntimesbeat[hit] + (offset * 4), 1, drumclayer.volumes[hit]) # create midi and memory for it def createMidiContext(self): self.createMidi() self.createMem() # put midi data into midi file def makeDemo(self, offset=0): ccobj = self.tempcut self.CreateDrumLayer(ccobj.bassdrumlayer, offset) self.CreateDrumLayer(ccobj.snaredrumlayer, offset) self.CreateDrumLayer(ccobj.tomsdrumlayer, offset) self.CreateDrumLayer(ccobj.cymbaldrumlayer, offset) # calls above function but for consecutive drum patterns def buildAllCuts(self): if len(self.allcuts) < 1: return for n, cut in enumerate(self.allcuts): self.tempcut = cut self.makeDemo((n)) def playDemo(self): pygame.mixer.music.play() # stores cut and relevant variables in arrays for later use def storeCut(self): if self.pushc == True and self.cancopy == True: if self.cutid <= len(self.unique): self.cutid += 1 self.allcuts += [self.tempcut] self.cutids += [self.cutid] self.globalid += 1 if self.newcut == True or (self.pushc == True and self.cancopy): self.unique += [deepcopy(self.tempcut)] self.uniqueid += [self.cutid] self.pushc = False self.newcut = False if self.pushc == True and self.cancopy == True: self.newcut = True # deletes last added pattern def killCut(self): if self.globalid > 0: self.globalid -= 1 del self.allcuts[self.globalid - 1] del self.cutids[self.globalid - 1] # saves pattern to disk def save(self): if (self.allcuts == []): return -1 self.buildAllCuts() self.writeMidiMem() ## try: outp = filedialog.asksaveasfile(initialdir="/", mode="wb", defaultextension=".mid") if outp is None: return -1 self.midif.writeFile(outp) ## except: ## return -1 return "" # format pattern string for output def formatfp(self): return "".join([str(x) + ',' for x in self.cutids])[:-1] # print-out for GUI for how many patterns can be used def ntoUse(self): if len(self.unique) < 1: return "0-0" else: return f"1-{len(self.unique)}" # build pattern from array entered by user def buildFromArray(self, temp): if len(self.unique) < 1: return -1 try: temp = [int(x) for x in temp.split(',')] except: return -1 for i in temp: if i not in self.uniqueid: return -1 self.allcuts = [] self.cutids = [] for c in temp: self.allcuts += [self.unique[c - 1]] self.cutids += [self.uniqueid[c - 1]] self.globalid = len(self.allcuts) self.buildAllCuts() return 1 # load a pattern to be edited in the pattern editor def loadForEdit(self, pat): pat = abs(int(pat)) if len(self.unique) < 1: return -1 while (pat not in self.uniqueid): pat -= 1 self.edpad = self.unique[pat - 1] self.editing = pat return 1 def editPattern(self, what): if what == "": return if what == "bass": if self.overwrite == True: self.edpad.bassdrumlayer = None self.edpad.bassdrumlayer = self.drumLayer(BassDrum, ranbeat(), 0, hitprob(), pulseit(4), 1) elif what == "snare": if self.overwrite == True: self.edpad.snaredrumlayer = None self.edpad.snaredrumlayer = self.drumLayer(Snare, snarebeat(), 1, hitprob(), pulseit(3) - 1, 1) elif what == "toms": if self.overwrite == True: self.edpad.tomsdrumlayer = None if randrange(0, 4) != 0: self.edpad.tomsdrumlayer = self.drumLayer( Toms, tombeat(), 1, hitprob(), pulseit(7) - 1, 1) elif what == "cym": if self.overwrite == True: self.edpad.cymbaldrumlayer = None for pc in range(8): if randrange(0, 5) == 1: self.edpad.cymbaldrumlayer = self.drumLayer( randomcymbal(), cymbeat(), 2, hitprob(), pulseit(3) - 1, 1) def updatePattern(self): self.unique[self.editing - 1] self.tempcut = self.unique[self.editing - 1]