def save_midi(grid, path, click_track=False, click_track_start=0, accent_downbeat=False, period=0, pulse=1, bpm=240, channel=9, pitch=75, velocity=100): ''' bpm means grid-units per second in this case ''' phase, iois = rhythm_tools.grid_to_iois(grid) track = 0 mf = MIDIFile(1) mf.addTrackName(track, 0, "Sample Track") mf.addTempo(track, 0, bpm) rhythm_start = 0 if click_track: if click_track_start < 0: rhythm_start = -click_track_start click_track_start = 0 click_track_end = ( rhythm_start + len(iois) ) print(rhythm_start, click_track_start) write_click_track(mf, start_time=click_track_start, end_time=click_track_end, period=period, pulse=pulse, velocity=velocity, accent_downbeat=accent_downbeat) write_iois(mf, iois, start_time=rhythm_start, track=track, channel=channel, pitch=pitch, velocity=velocity) with open(path, 'wb') as midi_file: mf.writeFile(midi_file)
class GenerateMelody(object): def __init__(self, file, pitch, length, beat_duration): self.pitch = pitch self.length = abs(length) self.file = file self.midi_melody = MIDIFile(1) self.beat_duration = abs(beat_duration) def get_filename(self): if not self.file.endswith(".mid"): return self.file + ".mid" return self.file def get_random_pitch(self): step = random.randint(-5, 5) return abs(self.pitch + step) @staticmethod def get_random_volume(): return random.randint(70, 127) def generate(self): time = 0 self.midi_melody.addTempo(0, time, 60) while time < self.length: self.midi_melody.addNote(0, 0, self.get_random_pitch(), time, self.beat_duration, self.get_random_volume()) time += self.beat_duration binfile = open(self.get_filename(), 'wb') self.midi_melody.writeFile(binfile) binfile.close()
class Midi: """Musique midi""" def __init__(self,partition,tempo): # Définition des paramètres MIDI. piste = 0 temps = 0 self.sortieMidi = MIDIFile(1) # Nom de la piste. self.sortieMidi.addTrackName(piste,temps,"Gregorien") # Tempo. self.sortieMidi.addTempo(piste,temps, tempo) # Instrument (74 : flûte). self.sortieMidi.addProgramChange(piste,0,temps,74) # À partir des propriétés de la note, création des évènements # MIDI. for note in partition: channel = 0 pitch = note.hauteur duree = note.duree volume = 127 self.sortieMidi.addNote(piste, channel, pitch, temps, duree, volume) temps += duree def ecrire(self,chemin): """Écriture effective du fichier MIDI""" binfile = open(chemin, 'wb') self.sortieMidi.writeFile(binfile) binfile.close()
def createFile(self): MIDI = MIDIFile(1) MIDI.addTrackName(0,0,self.name) MIDI.addTempo(0,0, self.bpm) beat = 0 for chord in self.chords: for degree in chord.degrees: MIDI.addNote(0,0,self.scale.scaleNotes[degree],beat,1,chord.intensity) beat = beat + 1 if not os.path.exists(songFolder): os.makedirs(songFolder) midiFile = open("%s/%d.%d-%s.mid"%(songFolder, self.generation, self.songnum, self.name), 'wb') MIDI.writeFile(midiFile) midiFile.close()
def make(self): with open("output.mid", 'wb') as f: MyMIDI = MIDIFile(1) track = 0 time = 0 channel = 0 volume = 100 MyMIDI.addTrackName(track, self.tempo, "Sample Track") MyMIDI.addTempo(track, time, 120) for part in self.structure: for note in self.riffs[part][0].score: MyMIDI.addNote(track, channel, note.pitch, time, note.duration, volume) time += note.duration MyMIDI.writeFile(f)
def arrayToMidiDouble(aArray, count): MyMIDI = MIDIFile(1) MyMIDI.addTrackName(0,0,"Red") MyMIDI.addTempo(0,0,120) time = 0 for j in range(len(aArray)): # randDur = choice([0.5, 0.25, 1, 2, 4]) randDur = 1 pitch = aArray[j] MyMIDI.addNote(0,0,pitch,time,randDur,100) time += randDur name = str(count) + ".mid" print(name) binfile = open(name, 'wb') MyMIDI.writeFile(binfile) binfile.close() print("finishing producing midi") return (name)
class Midi: """Musique midi""" def __init__(self, partition, titre, tempo): # Définition des paramètres MIDI. piste = 0 temps = 0 self.sortiemidi = MIDIFile(1) # Nom de la piste. self.sortiemidi.addTrackName(piste, temps, sansaccents(titre)) # Tempo. self.sortiemidi.addTempo(piste, temps, tempo) # Instrument (74 : flûte). self.sortiemidi.addProgramChange(piste, 0, temps, 74) self.traiter_partition(partition, piste, temps) def traiter_partition(self, partition, piste, temps): """Création des évènements MIDI""" transposition = partition.transposition for neume in partition.musique: for note in ( notes for notes in neume if isinstance(notes, Note) ): channel = 0 pitch = note.hauteur + transposition duree = note.duree volume = 127 self.sortiemidi.addNote( piste, channel, pitch, temps, duree, volume ) temps += duree def ecrire(self, chemin): """Écriture effective du fichier MIDI""" with ( open(sys.stdout.fileno(), 'wb') if chemin == '-' else open(chemin, 'wb') )as sortie: self.sortiemidi.writeFile(sortie)
def midiSing(sheet, instruments, key, ticktime, filename): offset = NOTES.index(key) + 60 # Middle C is MIDI note #60 midi=MIDIFile(len(sheet)) replaceprint('Creating midi...') for t in range(0,len(sheet)): midi.addTrackName(t, 0, "Track %s"%t) midi.addTempo(t, 0, 60000/(ticktime)) sheet[t]=sheet[t][1:]+[(sheet[t][0],0)] tracklen=len(sheet[t]) for n in range(0,tracklen-1): time, note = sheet[t][n] duration = sheet[t][(n+1)%tracklen][0]-time midi.addNote(t,0,offset+note,time,duration,100)#MyMIDI.addNote(track,channel,pitch,time,duration,volume) replaceprint('Writing to file...') binfile = open(filename+".mid", 'wb') midi.writeFile(binfile) binfile.close() replaceprint('Synth complete!') print("\nMID output to: \"" + filename+ ".mid\"")
def midi(self, path, bpm=240, channel=9, pitch=75, velocity=100): from midiutil.MidiFile3 import MIDIFile track = 0 time = 0 mf = MIDIFile(1) mf.addTrackName(track, time, "Sample Track") mf.addTempo(track, time, bpm) for duration in self.durations: mf.addNote(track, channel, pitch, time, duration, velocity) time += duration # write it to disk with open(path, 'wb') as midi_file: mf.writeFile(midi_file)
def construct_midi(filename, bpm, trackname, beat_intervals): # Create a MIDI with one track MyMIDI = MIDIFile(1) track = 0 time = 0 MyMIDI.addTrackName(track, time, trackname) MyMIDI.addTempo(track, time, bpm) TIME_COUNTER = 0 for beat_interval in beat_intervals: acappella_measure = chord_from_beat(beat_interval) TIME_COUNTER = _add_measure( acappella_measure, TIME_COUNTER, MyMIDI ) binfile = open("../output/" + filename, 'wb') MyMIDI.writeFile(binfile) binfile.close()
precipitation = 1 moonphase = 8 highTempAdjustment = 30 lowTempAdjustment = 30 # Create the MIDIFile Object with 3 tracks plus names of tracks MyMIDI = MIDIFile(3) MyMIDI.addTrackName(track1,time,"Temperature MusicHI") time = time +1 MyMIDI.addTrackName(track2,time,"Temperature MusicLOW") time = time +1 MyMIDI.addTrackName(track3,time,"Temperature MusicPrecip") time = time +1 MyMIDI.addTempo(track1,time, beats) time = time +1 MyMIDI.addTempo(track2,time, beats) time = time +1 MyMIDI.addTempo(track3,time, beats) # set voice (sound) to be played on tracks # we used General Midi sounds ( see General Midi docs ) time = time +1 MyMIDI.addProgramChange(track1,0, time, 47) # voice 1 = 86 fretless bass #time = time +1 MyMIDI.addProgramChange(track2,1, time, 112) # voice 2 = 53 time = time +1 MyMIDI.addProgramChange(track3,2, time, 77) # cymbal = 119 time = time +1
#Import the library from midiutil.MidiFile3 import MIDIFile import csv track1 = 0 track2 = 1 time = 0 MyMIDI = MIDIFile(2) MyMIDI.addTrackName(track1,time,"Temperature MusicHI") time = time +1 MyMIDI.addTrackName(track2,time,"Temperature MusicLOW") time = time +1 MyMIDI.addTempo(track1,time, 540) time = time +1 MyMIDI.addTempo(track2,time, 540) time = time +1 MyMIDI.addProgramChange(track1,0, time, 1) time = time +1 MyMIDI.addProgramChange(track2,1, time, 2) time = time +1 #f = open("climate2010.txt") #for row in csv.reader(f): channel = 0 channel2 = 1
from midiutil.MidiFile3 import MIDIFile MyMIDI = MIDIFile(1) track = 0 time = 0 MyMIDI.addTrackName(track, time, "Sample Track") MyMIDI.addTempo(track, time, 120) track = 0 channel = 0 pitch = 60 time = 4 duration = 1 volume = 100 MyMIDI.addNote(track,channel,pitch,time,duration,volume) track = 0 channel = 1 pitch = 64 time = 8 duration = 1 volume = 100 MyMIDI.addNote(track,channel,pitch,time,duration,volume) track = 0 channel = 2 pitch = 67 time = 12 duration = 1
def create_midi_from_progression(progression): """ Given a chord progression in the form of a list of chord instances, creates a MIDI file as an output. """ MyMIDI = MIDIFile(4) track = 0 time = 0 MyMIDI.addTrackName(track, time, "Soprano") MyMIDI.addTempo(track, time, 60) track += 1 MyMIDI.addTrackName(track, time, "Alto") MyMIDI.addTempo(track, time, 60) track += 1 MyMIDI.addTrackName(track, time, "Tenor") MyMIDI.addTempo(track, time, 60) track += 1 MyMIDI.addTrackName(track, time, "Bass") MyMIDI.addTempo(track, time, 60) channel = 0 duration = 1 volume = 100 for index, chord in enumerate(progression): track = 3 for note in chord.get_notes(): pitch = note.get_midi_number() MyMIDI.addNote(track, channel, pitch, time, duration, volume) track -= 1 time += 1 if index == len(progression) - 2: duration = 2 binfile = open("output_individual_voices.mid", 'wb') MyMIDI.writeFile(binfile) binfile.close() MyMIDI = MIDIFile(2) track = 0 time = 0 MyMIDI.addTrackName(track, time, "Upper Voices") MyMIDI.addTempo(track, time, 60) track += 1 MyMIDI.addTrackName(track, time, "Lower Voices") MyMIDI.addTempo(track, time, 60) duration = 1 for index, chord in enumerate(progression): track = 1 count = 0 for note in chord.get_notes(): pitch = note.get_midi_number() MyMIDI.addNote(track, channel, pitch, time, duration, volume) if count % 2 == 1: track -= 1 count += 1 time += 1 if index == len(progression) - 2: duration = 2 binfile = open("output_two_hands.mid", 'wb') MyMIDI.writeFile(binfile) binfile.close()
def save_midi_file(self): if len(self.messages_captured) == 0: return my_midi = MIDIFile(2) track = 0 my_midi.addTrackName(track, 0, "Tempo track") my_midi.addTempo(track, 0, self.bpm) track += 1 my_midi.addTrackName(track, 0, "Song track") total_time = 0 midi_messages_on = [] midi_messages_off = [] midi_messages_controller = [] for message in self.messages_captured: if len(message) != 3: self.write_message("wrong length: skipping " + str(message)) continue total_time += message.time_stamp # seconds -> beat conversion total_time_adjusted = total_time * float(self.bpm) / float(60) if message.type == MidiEventTypes.NOTE_ON: midi_messages_on.append( {'note': message[1], 'velocity': message[2], 'time': total_time_adjusted, 'channel': message.channel}) elif message.type == MidiEventTypes.NOTE_OFF: midi_messages_off.append( {'note': message[1], 'velocity': message[2], 'time': total_time_adjusted, 'channel': message.channel}) elif message.type == MidiEventTypes.CONTROL_CHANGE: midi_messages_controller.append( {'type': message[1], 'value': message[2], 'time': total_time_adjusted, 'channel': message.channel}) else: self.write_message("unknown message: skipping " + str(message)) continue for m_on in midi_messages_on: for m_off in midi_messages_off: if m_off['note'] == m_on['note'] and m_off['time'] > m_on['time']: m_on['duration'] = m_off['time'] - m_on['time'] m_off['note'] = -1 break else: m_on['duration'] = float( 15) * float(self.bpm) / float(60) # suspended for m in midi_messages_on: my_midi.addNote( track, m['channel'], m['note'], m['time'], m['duration'], m['velocity']) for m in midi_messages_controller: my_midi.addControllerEvent( track, m['channel'], m['time'], m['type'], m['value']) file_name = self.midi_file_name.format( datetime.datetime.now().strftime("%Y%m%d-%H%M%S")) file_path = os.path.join(os.path.dirname(sys.argv[0]), file_name) self.write_message("Saving {0} MIDI messages to {1}...".format( len(self.messages_captured), file_name)) binfile = open(file_path, 'wb') my_midi.writeFile(binfile) binfile.close() self.messages_captured = [] self.write_message("Saved.")
filename = 'mattys-tune.txt' beats_per_minute = 756 with open(filename) as f: for line in f: if len(line) > 3 and (line[1] == '|' or line[2] == '|'): line = line.replace('\n', '') lines.append(line) assert len(lines) % 6 == 0 # Initialize the MIDIFile object (with 1 track) time = 0 duration = 10 volume = 100 song = MIDIFile(1) song.addTrackName(0, time, "pianized_guitar_tab.") song.addTempo(0, time, beats_per_minute) # The root-pitches of the guitar guitar = list(reversed([52, 57, 62, 67, 71, 76])) # Assume EADGBe tuning def add_note(string, fret): song.addNote(0, string, guitar[string] + fret, time, duration, volume) # Process the entire tab for current in range(0, len(lines), 6): # The current base string for i in range(len(lines[current])): # The position in the current string time += 1 for s in range(6): # The number of the string c = lines[current + s][i] try: next_char = lines[current + s][i + 1] except: next_char = '' if c in '-x\\/bhp':
windSpeed = 6 precipitation = 1 highTempAdjustment = 30 lowTempAdjustment = 30 # Create the MIDIFile Object with 3 tracks plus names of tracks MyMIDI = MIDIFile(3) MyMIDI.addTrackName(track1,time,"Temperature MusicHI") time = time +1 MyMIDI.addTrackName(track2,time,"Temperature MusicLOW") time = time +1 MyMIDI.addTrackName(track3,time,"Temperature MusicPrecip") time = time +1 MyMIDI.addTempo(track1,time, beats) time = time +1 MyMIDI.addTempo(track2,time, beats) time = time +1 MyMIDI.addTempo(track3,time, beats) # set voice (sound) to be played on tracks # we used General Midi sounds ( see General Midi docs ) time = time +1 MyMIDI.addProgramChange(track1,0, time, 112) # voice 1 = 86 fretless bass #time = time +1 MyMIDI.addProgramChange(track2,1, time, 112) # voice 2 = 53 time = time +1 MyMIDI.addProgramChange(track3,2, time, 119) # cymbal = 119 time = time +1
class MIDITime(object): def __init__(self, tempo=120, outfile='miditime.mid', seconds_per_year=5, base_octave=5, octave_range=1, custom_epoch=None): self.tempo = tempo self.outfile = outfile self.tracks = [] if custom_epoch: # Only necessary if you have data that starts before 1970 and DO NOT want to start your midi at the first sound. self.epoch = custom_epoch else: self.epoch = datetime.datetime(1970, 1, 1) self.seconds_per_year = seconds_per_year self.base_octave = base_octave self.octave_range = octave_range self.note_chart = [["C"], ["C#", "Db"], ["D"], ["D#", "Eb"], ["E"], ["F"], ["F#", "Gb"], ["G"], ["G#", "Ab"], ["A"], ["A#", "Bb"], ["B"]] def beat(self, numdays): beats_per_second = self.tempo / 60.0 beats_per_datayear = self.seconds_per_year * beats_per_second beats_per_dataday = beats_per_datayear / 365.25 return round(beats_per_dataday * numdays, 2) def check_tz(self, input): if input.tzinfo: return input.tzinfo else: return None # Match the compare date to the timezone of whatever your input date is, if the input datetime is timezone-aware def normalize_datetime(self, input, compare_date): # if input is date, make epoch a date if type(input) is datetime.date: return compare_date.date() # # First, coerce to datetime in case it's a date # if type(input) is datetime.date: # input = datetime.datetime.combine(input, datetime.datetime.min.time()) # If tz data present, make epoch tz-aware tz = self.check_tz(input) if tz: return tz.localize(compare_date) else: return compare_date def days_since_epoch(self, input): normalized_epoch = self.normalize_datetime(input, self.epoch) return (input - normalized_epoch).total_seconds() / 60 / 60 / 24 # How many days, with fractions def map_week_to_day(self, year, week_num, desired_day_num=None): ''' Helper for weekly data, so when you jump to a new year you don't have notes playing too close together. Basically returns the first Sunday, Monday, etc. in 0-indexed integer format that is in that week. Usage: Once without a desired_day_num, then feed it a day_num in the loop Example: first_day = self.map_week_to_day(filtered_data[0]['Year'], filtered_data[0]['Week']) for r in filtered_data: # Convert the week to a date in that week week_start_date = self.map_week_to_day(r['Year'], r['Week'], first_day.weekday()) # To get your date into an integer format, convert that date into the number of days since Jan. 1, 1970 days_since_epoch = self.mymidi.days_since_epoch(week_start_date) ''' year_start = datetime.datetime(int(year), 1, 1).date() year_start_day = year_start.weekday() week_start_date = year_start + datetime.timedelta(weeks=1 * (int(week_num) - 1)) week_start_day = week_start_date.weekday() if desired_day_num and week_start_day < desired_day_num: return week_start_date + datetime.timedelta(days=(desired_day_num - week_start_day)) return week_start_date def get_data_range(self, data_list, attribute_name, ignore_nulls=True): data_list = list(data_list) # If the data is still a CSV object, once you loop through it you'll get rewind issues. So coercing to list. if ignore_nulls: minimum = min([float(d[attribute_name]) for d in data_list if d[attribute_name]]) maximum = max([float(d[attribute_name]) for d in data_list if d[attribute_name]]) else: minimum = min([float(d[attribute_name]) for d in data_list]) maximum = max([float(d[attribute_name]) for d in data_list]) return [minimum, maximum] def scale_to_note_classic(self, scale_pct, mode): # Only works in multi-octave mode if in C Major (i.e. all the notes are used. Should not be used in other keys, unless octave range is 1.) full_mode = [] n = 0 while n < self.octave_range: for m in mode: current_octave = str(self.base_octave + (n * 1)) full_mode.append(m + current_octave) n += 1 index = int(scale_pct * float(len(full_mode))) if index >= len(full_mode): index = len(full_mode) - 1 print(full_mode[index]) return full_mode[index] def scale_to_note(self, scale_pct, mode): # Manually go through notes so it doesn't inaccurately jump an octave sometimes. # First, write out a list of the possible notes for your octave range (i.e. all of the notes on the keyboard) full_c_haystack = [] n = 0 while n < self.octave_range: for note_group in self.note_chart: out_group = [] for note in note_group: current_octave = self.base_octave + (n * 1) out_group.append(note + str(current_octave)) full_c_haystack.append(out_group) n += 1 full_mode = [] n = 0 while n < self.octave_range: for note in mode: note_found = False note_key = None for groupkey, group in enumerate(full_c_haystack): for gnote in group: if gnote[:-1] == note: full_mode.append(gnote) note_found = True note_key = groupkey if note_found: break full_c_haystack = full_c_haystack[note_key:] n += 1 # Now run through your specified mode and pick the exact notes in those octaves index = int(scale_pct * float(len(full_mode))) if index >= len(full_mode): index = len(full_mode) - 1 return full_mode[index] def note_to_midi_pitch(self, notename): midinum = 0 letter = notename[:-1] octave = notename[-1] i = 0 for note in self.note_chart: for form in note: if letter == form: midinum = i break i += 1 midinum += (int(octave)) * 12 return midinum def linear_scale_pct(self, domain_min, domain_max, input, reverse=False): domain_range = float(domain_max) - float(domain_min) domain_pct = (input - domain_min) / domain_range if reverse: domain_pct = 1 - domain_pct return domain_pct def log_scale_pct(self, domain_min, domain_max, input, reverse=False, direction='exponential'): if direction == 'exponential': # E.G. earthquakes min_log_domain = pow(10, domain_min) max_log_domain = pow(10, domain_max) domain_range = max_log_domain - min_log_domain log_input = pow(10, input) elif direction == 'log': # natural log scale if domain_min > 0: min_log_domain = log(domain_min) else: min_log_domain = log(0.1) # Technically this is not a true log scale. Someone smarter than me will have to figure this out. if domain_max > 0: max_log_domain = log(domain_max) else: max_log_domain = log(0.1) # Technically this is not a true log scale. Someone smarter than me will have to figure this out. domain_range = max_log_domain - min_log_domain log_input = log(input) domain_pct = (log_input - min_log_domain) / domain_range if reverse: domain_pct = 1 - domain_pct return domain_pct def scale(self, range_min, range_max, input_pct): scale_range = range_max - range_min return range_min + (input_pct * scale_range) def add_track(self, note_list): self.tracks.append(note_list) def add_note(self, track, channel, note): time = note[0] pitch = note[1] volume = note[2] duration = note[3] print(pitch, time, duration, volume) # Now add the note. self.MIDIFile.addNote(track, channel, pitch, time, duration, volume) def save_midi(self): # Create the MIDIFile Object with 1 track self.MIDIFile = MIDIFile(len(self.tracks)) for i, note_list in enumerate(self.tracks): # Tracks are numbered from zero. Times are measured in beats. track = i time = 0 # Add track name and tempo. self.MIDIFile.addTrackName(track, time, "Track 1") self.MIDIFile.addTempo(track, time, self.tempo) for n in note_list: if len(n) == 2: note = n[0] channel = n[1] else: note = n channel = 0 self.add_note(track, channel, note) # And write it to disk. binfile = open(self.outfile, 'wb') self.MIDIFile.writeFile(binfile) binfile.close()
from midiutil.MidiFile3 import MIDIFile import random # Create the MIDIFile Object MyMIDI = MIDIFile(6) # Add track name and tempo. The first argument to addTrackName and # addTempo is the time to write the event. track = 0 time = 0 channel = 0 program = 0 volume = 100 #Adding instruments MyMIDI.addTrackName(track,time,"Mellow Ambience I") MyMIDI.addTempo(track,time,92) MyMIDI.addProgramChange(track,channel,time,program+53) MyMIDI.addTrackName(track+1,time,"Harpsichord") MyMIDI.addTempo(track+1,time, 92) MyMIDI.addProgramChange(track+1,channel+1,time,program+107) MyMIDI.addTrackName(track+2,time,"Percussion") MyMIDI.addTempo(track+2,time, 92) MyMIDI.addProgramChange(track+2,channel+2,time,program+47) #Saving Randomness state random.seed(1337,2) # Get pitch of note def getPitch(key, pitchOct):
# and write to disk. ############################################################################ #Import the library from midiutil.MidiFile3 import MIDIFile MyMIDI = MIDIFile(1) # Add track name and tempo. The first argument to addTrackName and # addTempo is the time to write the event. track = 0 time = 0 channel = 9 MyMIDI.addTrackName(track,time,"Sample Track") MyMIDI.addTempo(track,time, 120) time = time = 2 MyMIDI.addProgramChange(0,channel, time, 44) # voice 1 = 86 fretless bass # Add a note. addNote expects the following information: pitch = 60 duration = 10 volume = 100 duration2 = 5 # Now add the note. MyMIDI.addNote(track,channel,pitch,time,duration,volume) time = time + 1 MyMIDI.addNote(track,channel,pitch,time,duration,volume) time = time + 1.25
class MidiCreator(object): def __init__(self, config_file_name): """Convert data in a CSV file to a MIDI file.""" # load instrument names and MIDI note ranges from config file self._config = configparser.ConfigParser() self._config.read(config_file_name) # Create the MIDIFile object with 1 track self._midi = MIDIFile(1) # Add track name and tempo. self._midi.addTrackName( 0, # track number 0, # time self._config.get('midi', 'track name', fallback=DEFAULT_TRACK_NAME)) self._midi.addTempo( 0, # track number 0, # time int(self._config.get('midi', 'tempo', fallback=DEFAULT_TEMPO))) def _init_note_makers(self, csv_file_name): """Create a list of NoteMaker objects, one for each csv column that is mapped to an instrument by the config file.""" self._note_makers = [] csv_file = open(csv_file_name) # first line of csv file must have column names columns = csv_file.readline().strip().split(',') # Create one notemaker instance for every csv column that we'll be # using to produce music. Each notemaker is assigned to a separate # channel, since each instrument must have its own channel. channel = 0 for column_index, column_name in enumerate(columns): if NoteMaker.is_musical_column(column_name, self._config): if self._config['columns'][column_name]: self._note_makers.append( NoteMaker(column_name, column_index, self._midi, self._config, channel)) channel += 1 if channel > 15: print("Warning: more than 16 channels, ignoring excess.") break # Now each notemaker object needs to know the maximum value for its # data column, so that it can be scaled to fit the range of the # instrument assigned to that column. for line in csv_file: split_line = line.strip().split(',') for note_maker in self._note_makers: note_maker.test_for_max(split_line) def write_midi_file(self, csv_file_name, midi_file_name): # Create a list of pitchmaker objects, one for each column that will be # used to produce music. self._init_note_makers(csv_file_name) # Write notes to the midi file csv_file = open(csv_file_name) csv_file.readline() # skip header for line in csv_file: split_line = line.strip().split(',') for note_maker in self._note_makers: note_maker.add_note(split_line) # write the midi data to disk with open(midi_file_name, 'wb') as midi_file: self._midi.writeFile(midi_file)
def image_process_2(): image = cv2.imread('temp/src_image.jpg', 0) list_ = image.tolist() if max(map(max, list_)) > 225: thresh_1 = 0.66 * max(map(max, list_)) thresh_2 = 0.70 * max(map(max, list_)) thresh_3 = 0.72 * max(map(max, list_)) elif max(map(max, list_)) < 200: thresh_1 = 0.65 * max(map(max, list_)) thresh_2 = 0.75 * max(map(max, list_)) thresh_3 = 0.84 * max(map(max, list_)) else: thresh_1 = 0.66 * max(map(max, list_)) thresh_2 = 0.72 * max(map(max, list_)) thresh_3 = 0.75 * max(map(max, list_)) ret, img_gray1 = cv2.threshold(dstImg, thresh_1, 255, cv2.THRESH_BINARY) ret, img_gray2 = cv2.threshold(dstImg, thresh_2, 255, cv2.THRESH_BINARY) ret, img_gray3 = cv2.threshold(dstImg, thresh_3, 255, cv2.THRESH_BINARY) img_gray = 255 * np.ones(shape=[780, 551], dtype=np.uint8) # cv2.namedWindow("img_gray", cv2.WINDOW_AUTOSIZE) # cv2.imshow("img_gray", img_gray) for i in range(780): for j in range(551): if img_gray1[i][j] == 0 and img_gray2[i][j] == 0 and img_gray3[i][ j] == 0: img_gray[i][j] = 0 elif img_gray1[i][j] == 0 or img_gray2[i][j] == 0: if img_gray3[i][j] == 0: img_gray[i][j] = 0 elif img_gray1[i][j] == 0 or img_gray3[i][j] == 0: if img_gray2[i][j] == 0: img_gray[i][j] = 0 elif img_gray2[i][j] == 0 or img_gray3[i][j] == 0: if img_gray1[i][j] == 0: img_gray[i][j] = 0 img = img_gray # height, width = img.shape[:2] # img_width, img_height = img_gray.shape[::-1] # <<找五線譜 staff_recs = locate_images(img_gray, staff_imgs, staff_lower, staff_upper, staff_thresh) staff_recs = [j for i in staff_recs for j in i] heights = [r.y for r in staff_recs] + [0] histo = [heights.count(i) for i in range(0, max(heights) + 1)] avg = np.mean(list(set(histo))) staff_recs = [r for r in staff_recs if histo[r.y] > avg] staff_recs = merge_recs(staff_recs, 0.01) # staff_recs_img = img.copy() # for r in staff_recs: # r.draw(staff_recs_img, (0, 0, 255), 2) # >> # <<找五線譜的模板 resul = [] resul.append(staff_recs[0]) for index, item in enumerate(staff_recs): if abs(resul[-1].y - item.y) > 100: resul.append(item) else: continue # print("resul", resul) # >> # <<找五線譜的y座標 staff = [] line_axis = [] for item in resul: # print("item.y", item.y) line_axis.append(item.y) y_project = [] line_ = [] for i in range(int(item.h)): count = 0 for j in range(int(item.w)): if img[item.y + i, item.x + j] == 0: count += 1 else: continue y_project.append(count) # print("y_project(count)", y_project) i = 1 while i < len(y_project): if (y_project[i] == 0): i += 1 continue elif (y_project[i] > 0 and y_project[i + 1] > 0 and y_project[i + 2] > 0): line = (i + i + 1 + i + 2) // 3 line_.append(line + item.y) i += 3 elif (y_project[i] > 0 and y_project[i + 1] > 0): line = (i + i + 1) // 2 line_.append(line + item.y) i += 2 else: line = i line_.append(line + item.y) i += 1 continue staff.append(line_) # print("line_axis", line_axis) #每行譜的五條線的最上面那條 # print("staff", staff) #每行譜的五條線 # >> ##### 第一行對x投影 x_range = [102] * (len(resul)) x_range[0] = 120 # print('ra_list',ra_list) quarter_recs = [] half_recs = [] for x_range_index, x_range_ in enumerate(x_range): x_project1 = [] for x in range(x_range_, 485): count = 0 for y in range(staff[x_range_index][0] - 15, staff[x_range_index][4] + 15): if img[y, x] == 0: count += 1 else: continue x_project1.append(count) # <<音符的x範圍 note_xposition = [] one_note = [] next_to = False for index, item in enumerate(x_project1): if item > 8 and next_to == False: #找到第一個大於9的x one_note.append(index) next_to = True #觸發next_to等於True elif item > 8 and next_to == True: #next_to等於True的情況下如果還是大於九則不做理會 continue elif item < 8 and next_to == True: #next_to等於True的情況下如果小於九則存入one_note one_note.append(index - 1) if one_note[1] - one_note[ 0] > 5: #one_note[0]是起始x,one_note[1]是結束的x,間距要超過5才會把它存入note_xposition # print("index" ,index) note_xposition.append(one_note) one_note = [] next_to = False #next_to等於False # print("note_xposition", note_xposition) # print('xpo', time.time() - start_time) # 音符的x範圍>> # <<音符的y範圍 note_yposition = [] note_xpos_yproject = [] # for index__ in note_xposition: # note_xpos_yproject = [] for r in range(len(note_xposition)): for j in range(staff[x_range_index][0] - 15, staff[x_range_index][4] + 15): count = 0 for i in range(note_xposition[r][0] + x_range_, note_xposition[r][1] + x_range_): if img[j, i] == 0: count += 1 else: continue note_xpos_yproject.append(count) one_note_ = [] next_to_ = False for index_, item in enumerate(note_xpos_yproject): if item > 3 and next_to_ == False: #找到第一個大於3的y one_note_.append(index_) next_to_ = True #觸發next_to_等於True elif item > 3 and next_to_ == True: #next_to_等於True的情況下如果還是大於3則不做理會 continue elif item < 3 and next_to_ == True: #next_to_等於True的情況下如果小於3則存入one_note_ one_note_.append(index_ - 1) if one_note_[1] - one_note_[ 0] > 6: #one_note_[0]是起始y,one_noteY[1]是結束的y,間距要超過6才會把它存入note_xposition note_yposition.append(one_note_) one_note_ = [] next_to_ = False #next_to等於False # print("note_xpos_yproject", note_xpos_yproject) note_xpos_yproject = [] # print("note_yposition", note_yposition) # 音符的y範圍>> # fingers = [] # for i in range(len(note_xposition)): # crop_img = img[staff[x_range_index][4]+15 : staff[x_range_index][4]+30, x_range[x_range_index] + note_xposition[i][0] : x_range[x_range_index] + note_xposition[i][1]] # if i == 1: # print("crop_img", crop_img) # # 找finger1 # finger1_recs = locate_images(crop_img, finger1_imgs, finger1_lower, finger1_upper, finger1_thresh) # # finger1_recs = finger1_recs[0] # finger1_recs = merge_recs([j for i in finger1_recs for j in i], 0.5) # finger1_recs_img = img.copy() # if i == 1: # print("finger1_recs", len(finger1_recs)) # for r in finger1_recs: # r.draw(finger1_recs_img, (0, 0, 255), 2) # cv2.imwrite('finger1_recs_img.png', finger1_recs_img) # open_file('finger1_recs_img.png') global recs recs = [] for r in range(len(note_xposition)): count = 0 for j in range(staff[x_range_index][0] - 15 + note_yposition[r][0], staff[x_range_index][0] - 15 + note_yposition[r][1]): for i in range(note_xposition[r][0] + x_range_, note_xposition[r][1] + x_range_): if img[j, i] == 0: count += 1 else: continue # print(count/((note_xposition[r][1]-note_xposition[r][0])*(note_yposition[r][1]-note_yposition[r][0]))) if (count / ((note_xposition[r][1] - note_xposition[r][0]) * (note_yposition[r][1] - note_yposition[r][0])) > 0.64): rec = Rectangle( note_xposition[r][0] + x_range_, staff[x_range_index][0] - 15 + note_yposition[r][0], note_xposition[r][1] - note_xposition[r][0], note_yposition[r][1] - note_yposition[r][0]) quarter_recs.append(rec) recs.append(rec) elif (count / ((note_xposition[r][1] - note_xposition[r][0]) * (note_yposition[r][1] - note_yposition[r][0])) <= 0.64): rec = Rectangle( note_xposition[r][0] + x_range_, staff[x_range_index][0] - 15 + note_yposition[r][0], note_xposition[r][1] - note_xposition[r][0], note_yposition[r][1] - note_yposition[r][0]) half_recs.append(rec) recs.append(rec) # print("quarter_recs", quarter_recs) # print("half_recs", half_recs) # print("quarter_recs", len(quarter_recs)) # print("half_recs", len(half_recs)) l = recs # print("rec", rec) with open("temp/output.txt", "wb") as fp: #Pickling pickle.dump(l, fp) # with open("test.txt", "rb") as fp: # Unpickling # b = pickle.load(fp) staff_boxes = [ Rectangle(x_range[r], staff[r][2] - 33, 485 - x_range[r], 68) for r in range(len(staff)) ] # staff_boxes_img = img.copy() # for r in staff_boxes: # r.draw(staff_boxes_img, (0, 0, 255), 2) # cv2.imwrite('staff_boxes_img.png', staff_boxes_img) # open_file('staff_boxes_img.png') # objects_img = staff_boxes_img # 畫四分音符 # quarter_recs_img = img.copy() # for r in quarter_recs: # r.draw(quarter_recs_img, (0, 0, 255), 2) # cv2.imwrite('quarter_recs_img.png', quarter_recs_img) # open_file('quarter_recs_img.png') # 畫二分音符 # half_recs_img = img.copy() # for r in half_recs: # r.draw(half_recs_img, (0, 0, 255), 2) # cv2.imwrite('half_recs_img.png', half_recs_img) # open_file('half_recs_img.png') staff_notes = [] note_groups = [] for box in staff_boxes: staff_sharps = [] staff_flats = [] quarter_notes = [ Note(r, "4,8", box, staff_sharps, staff_flats) for r in quarter_recs if abs(r.middle[1] - box.middle[1]) < box.h * 5.0 / 8.0 ] half_notes = [ Note(r, "2", box, staff_sharps, staff_flats) for r in half_recs if abs(r.middle[1] - box.middle[1]) < box.h * 5.0 / 8.0 ] staff_notes = quarter_notes + half_notes staff_notes.sort(key=lambda n: n.rec.x) staffs = [r for r in staff_recs if r.overlap(box) > 0] staffs.sort(key=lambda r: r.x) note_color = (randint(0, 255), randint(0, 255), randint(0, 255)) note_group = [] i = 0 j = 0 while (i < len(staff_notes)): if j < len(staffs): if staff_notes[i].rec.x > staffs[j].x: r = staffs[j] j += 1 if len(note_group) > 0: note_groups.append(note_group) note_group = [] note_color = (randint(0, 255), randint(0, 255), randint(0, 255)) else: note_group.append(staff_notes[i]) # staff_notes[i].rec.draww(img, note_color, 2) i += 1 else: note_group.append(staff_notes[i]) # staff_notes[i].rec.draww(img, note_color, 2) i += 1 note_groups.append(note_group) # for r in staff_boxes: # r.draw(img, (0, 0, 255), 2) # cv2.imwrite('res.png', img) # open_file('res.png') # for note_group in note_groups: # print([ note.note + " " + note.sym for note in note_group]) midi = MIDIFile(1) track = 0 time = 0 channel = 0 volume = 100 midi.addTrackName(track, time, "Track") midi.addTempo(track, time, 60) for note_group in note_groups: duration = None for note in note_group: note_type = note.sym if note_type == "1": duration = 4 elif note_type == "2": duration = 2 elif note_type == "4,8": # duration = 1 if len(note_group) == 1 else 0.5 duration = 1 pitch = note.pitch midi.addNote(track, channel, pitch, time, duration, volume) time += duration # And write it to disk. binfile = open("temp/output.mid", 'wb') midi.writeFile(binfile) binfile.close()
cv2.imwrite('res.png', img) open_file('res.png') for note_group in note_groups: print([ note.note + " " + note.sym for note in note_group]) # note를 미디 파일로 저장 midi = MIDIFile(1) track = 0 time = 0 channel = 0 volume = 100 midi.addTrackName(track, time, "Track") midi.addTempo(track, time, 140) for note_group in note_groups: duration = None for note in note_group: note_type = note.sym if note_type == "1": duration = 4 elif note_type == "2": duration = 2 elif note_type == "4,8": duration = 1 if len(note_group) == 1 else 0.5 pitch = note.pitch midi.addNote(track,channel,pitch,time,duration,volume) time += duration
# A sample program to create a single-track MIDI file, add a note, # and write to disk. ############################################################################ #Import the library from midiutil.MidiFile3 import MIDIFile import random # Create the MIDIFile Object MyMIDI = MIDIFile(2) # Add track name and tempo. The first argument to addTrackName and # addTempo is the time to write the event. track = 0 LHtime = 0 MyMIDI.addTrackName(track, LHtime, "Jazzzzzy Left Hand") MyMIDI.addTempo(track,LHtime, 160) # Creating second track track2 = 1 RHtime = 0 MyMIDI.addTrackName(track2, RHtime, "Jazzzzzy Right Hand") MyMIDI.addTempo(track,RHtime,160) # Add a note 'C'. addNote expects the following information: channel = 0 pitch = 60 duration = 2 volume = 100 # Create Randomness random.seed(1338, 2)
class MIDITime(object): def __init__(self, tempo=120, outfile='miditime.mid', seconds_per_year=5, base_octave=5, octave_range=1, custom_epoch=None): self.tempo = tempo self.outfile = outfile self.tracks = [] if custom_epoch: # Only necessary if you have data that starts before 1970 and DO NOT want to start your midi at the first sound. self.epoch = custom_epoch else: self.epoch = datetime.datetime(1970, 1, 1) self.seconds_per_year = seconds_per_year self.base_octave = base_octave self.octave_range = octave_range self.note_chart = [["C"], ["C#", "Db"], ["D"], ["D#", "Eb"], ["E"], ["F"], ["F#", "Gb"], ["G"], ["G#", "Ab"], ["A"], ["A#", "Bb"], ["B"]] def beat(self, numdays): beats_per_second = self.tempo / 60.0 beats_per_datayear = self.seconds_per_year * beats_per_second beats_per_dataday = beats_per_datayear / 365.25 return round(beats_per_dataday * numdays, 2) def check_tz(self, input): if input.tzinfo: return input.tzinfo else: return None # Match the compare date to the timezone of whatever your input date is, if the input datetime is timezone-aware def normalize_datetime(self, input, compare_date): # if input is date, make epoch a date if type(input) is datetime.date: return compare_date.date() # # First, coerce to datetime in case it's a date # if type(input) is datetime.date: # input = datetime.datetime.combine(input, datetime.datetime.min.time()) # If tz data present, make epoch tz-aware tz = self.check_tz(input) if tz: return tz.localize(compare_date) else: return compare_date def days_since_epoch(self, input): normalized_epoch = self.normalize_datetime(input, self.epoch) return (input - normalized_epoch).total_seconds( ) / 60 / 60 / 24 # How many days, with fractions def map_week_to_day(self, year, week_num, desired_day_num=None): ''' Helper for weekly data, so when you jump to a new year you don't have notes playing too close together. Basically returns the first Sunday, Monday, etc. in 0-indexed integer format that is in that week. Usage: Once without a desired_day_num, then feed it a day_num in the loop Example: first_day = self.map_week_to_day(filtered_data[0]['Year'], filtered_data[0]['Week']) for r in filtered_data: # Convert the week to a date in that week week_start_date = self.map_week_to_day(r['Year'], r['Week'], first_day.weekday()) # To get your date into an integer format, convert that date into the number of days since Jan. 1, 1970 days_since_epoch = self.mymidi.days_since_epoch(week_start_date) ''' year_start = datetime.datetime(int(year), 1, 1).date() year_start_day = year_start.weekday() week_start_date = year_start + datetime.timedelta(weeks=1 * (int(week_num) - 1)) week_start_day = week_start_date.weekday() if desired_day_num and week_start_day < desired_day_num: return week_start_date + datetime.timedelta(days=(desired_day_num - week_start_day)) return week_start_date def get_data_range(self, data_list, attribute_name, ignore_nulls=True): data_list = list( data_list ) # If the data is still a CSV object, once you loop through it you'll get rewind issues. So coercing to list. if ignore_nulls: minimum = min([ float(d[attribute_name]) for d in data_list if d[attribute_name] ]) maximum = max([ float(d[attribute_name]) for d in data_list if d[attribute_name] ]) else: minimum = min([float(d[attribute_name]) for d in data_list]) maximum = max([float(d[attribute_name]) for d in data_list]) return [minimum, maximum] def scale_to_note_classic( self, scale_pct, mode ): # Only works in multi-octave mode if in C Major (i.e. all the notes are used. Should not be used in other keys, unless octave range is 1.) full_mode = [] n = 0 while n < self.octave_range: for m in mode: current_octave = str(self.base_octave + (n * 1)) full_mode.append(m + current_octave) n += 1 index = int(scale_pct * float(len(full_mode))) if index >= len(full_mode): index = len(full_mode) - 1 print(full_mode[index]) return full_mode[index] def scale_to_note( self, scale_pct, mode ): # Manually go through notes so it doesn't inaccurately jump an octave sometimes. # First, write out a list of the possible notes for your octave range (i.e. all of the notes on the keyboard) full_c_haystack = [] n = 0 while n < self.octave_range: for note_group in self.note_chart: out_group = [] for note in note_group: current_octave = self.base_octave + (n * 1) out_group.append(note + str(current_octave)) full_c_haystack.append(out_group) n += 1 full_mode = [] n = 0 while n < self.octave_range: for note in mode: note_found = False note_key = None for groupkey, group in enumerate(full_c_haystack): for gnote in group: if gnote[:-1] == note: full_mode.append(gnote) note_found = True note_key = groupkey if note_found: break full_c_haystack = full_c_haystack[note_key:] n += 1 # Now run through your specified mode and pick the exact notes in those octaves index = int(scale_pct * float(len(full_mode))) if index >= len(full_mode): index = len(full_mode) - 1 return full_mode[index] def note_to_midi_pitch(self, notename): midinum = 0 letter = notename[:-1] octave = notename[-1] i = 0 for note in self.note_chart: for form in note: if letter == form: midinum = i break i += 1 midinum += (int(octave)) * 12 return midinum def linear_scale_pct(self, domain_min, domain_max, input, reverse=False): domain_range = float(domain_max) - float(domain_min) domain_pct = (input - domain_min) / domain_range if reverse: domain_pct = 1 - domain_pct return domain_pct def log_scale_pct(self, domain_min, domain_max, input, reverse=False, direction='exponential'): if direction == 'exponential': # E.G. earthquakes min_log_domain = pow(10, domain_min) max_log_domain = pow(10, domain_max) domain_range = max_log_domain - min_log_domain log_input = pow(10, input) elif direction == 'log': # natural log scale if domain_min > 0: min_log_domain = log(domain_min) else: min_log_domain = log( 0.1 ) # Technically this is not a true log scale. Someone smarter than me will have to figure this out. if domain_max > 0: max_log_domain = log(domain_max) else: max_log_domain = log( 0.1 ) # Technically this is not a true log scale. Someone smarter than me will have to figure this out. domain_range = max_log_domain - min_log_domain log_input = log(input) domain_pct = (log_input - min_log_domain) / domain_range if reverse: domain_pct = 1 - domain_pct return domain_pct def scale(self, range_min, range_max, input_pct): scale_range = range_max - range_min return range_min + (input_pct * scale_range) def add_track(self, note_list): self.tracks.append(note_list) def add_note(self, track, channel, note): time = note[0] pitch = note[1] velocity = note[2] duration = note[3] print(pitch, time, duration, velocity) # Now add the note. self.MIDIFile.addNote(track, channel, pitch, time, duration, velocity) def save_midi(self): # Create the MIDIFile Object with 1 track self.MIDIFile = MIDIFile(len(self.tracks)) for i, note_list in enumerate(self.tracks): # Tracks are numbered from zero. Times are measured in beats. track = i time = 0 # Add track name and tempo. self.MIDIFile.addTrackName(track, time, "Track %s" % i) self.MIDIFile.addTempo(track, time, self.tempo) for n in note_list: if len(n) == 2: note = n[0] channel = n[1] else: note = n channel = 0 self.add_note(track, channel, note) # And write it to disk. binfile = open(self.outfile, 'wb') self.MIDIFile.writeFile(binfile) binfile.close()