def parse_nottingham_to_sequence(input_filename, time_step, verbose=False): """ input_filename: a MIDI filename returns a [T x D] matrix representing a sequence with T time steps over D dimensions """ sequence = [] pattern = midi.read_midifile(input_filename) metadata = { "path": input_filename, "name": input_filename.split("/")[-1].split(".")[0] } # Most nottingham midi's have 3 tracks. metadata info, melody, harmony # throw away any tracks that don't fit this if len(pattern) != 3: if verbose: "Skipping track with {} tracks".format(len(pattern)) return (metadata, None) # ticks_per_quarter = -1 for msg in pattern[0]: if isinstance(msg, midi.TimeSignatureEvent): metadata["ticks_per_quarter"] = msg.get_metronome() ticks_per_quarter = msg.get_metronome() if verbose: print("{}".format(input_filename)) print("Track resolution: {}".format(pattern.resolution)) print("Number of tracks: {}".format(len(pattern))) print("Time step: {}".format(time_step)) print("Ticks per quarter: {}".format(ticks_per_quarter)) # Track ingestion stage track_ticks = 0 melody_notes, melody_ticks = midi_util.ingest_notes(pattern[1]) harmony_notes, harmony_ticks = midi_util.ingest_notes(pattern[2]) track_ticks = midi_util.round_tick(max(melody_ticks, harmony_ticks), time_step) if verbose: print("Track ticks (rounded): {} ({} time steps)".format( track_ticks, track_ticks / time_step)) melody_sequence = midi_util.round_notes(melody_notes, track_ticks, time_step, R=NOTTINGHAM_MELODY_RANGE, O=NOTTINGHAM_MELODY_MIN) for i in range(melody_sequence.shape[0]): if np.count_nonzero(melody_sequence[i, :]) > 1: if verbose: print("Double note found: {}: {} ({})".format( i, np.nonzero(melody_sequence[i, :]), input_filename)) return (metadata, None) harmony_sequence = midi_util.round_notes(harmony_notes, track_ticks, time_step) harmonies = [] for i in range(harmony_sequence.shape[0]): notes = np.where(harmony_sequence[i] == 1)[0] if len(notes) > 0: notes_shift = [ mingus.core.notes.int_to_note(h % 12) for h in notes ] chord = mingus.core.chords.determine(notes_shift, shorthand=True) if len(chord) == 0: # try flat combinations notes_shift = [ SHARPS_TO_FLATS[n] if n in SHARPS_TO_FLATS else n for n in notes_shift ] chord = mingus.core.chords.determine(notes_shift, shorthand=True) if len(chord) == 0: if verbose: print("Could not determine chord: {} ({}, {}), defaulting to last steps chord" \ .format(notes_shift, input_filename, i)) if len(harmonies) > 0: harmonies.append(harmonies[-1]) else: harmonies.append(NO_CHORD) else: resolved = resolve_chord(chord[0]) if resolved: harmonies.append(resolved) else: harmonies.append(NO_CHORD) else: harmonies.append(NO_CHORD) return (metadata, (melody_sequence, harmonies))
harmony_notes, harmony_ticks = midi_util.ingest_notes(pattern[2]) track_ticks = midi_util.round_tick(max(melody_ticks, harmony_ticks), time_step) if verbose: print ("Track ticks (rounded): {} ({} time steps)".format(track_ticks, track_ticks/time_step)) melody_sequence = midi_util.round_notes(melody_notes, track_ticks, time_step, R=NOTTINGHAM_MELODY_RANGE, O=NOTTINGHAM_MELODY_MIN) for i in range(melody_sequence.shape[0]): if np.count_nonzero(melody_sequence[i, :]) > 1: if verbose: print ("Double note found: {}: {} ({})".format(i, np.nonzero(melody_sequence[i, :]), input_filename)) return (metadata, None) harmony_sequence = midi_util.round_notes(harmony_notes, track_ticks, time_step) harmonies = [] for i in range(harmony_sequence.shape[0]): notes = np.where(harmony_sequence[i] == 1)[0] if len(notes) > 0: notes_shift = [ mingus.core.notes.int_to_note(h%12) for h in notes] chord = mingus.core.chords.determine(notes_shift, shorthand=True) if len(chord) == 0: # try flat combinations notes_shift = [ SHARPS_TO_FLATS[n] if n in SHARPS_TO_FLATS else n for n in notes_shift] chord = mingus.core.chords.determine(notes_shift, shorthand=True) if len(chord) == 0: if verbose: print ("Could not determine chord: {} ({}, {}), defaulting to last steps chord" \ .format(notes_shift, input_filename, i))
def Data_to_Sequence(midFile, timeStep): unkChord = 'NONE' # for unknown chords harmony = [] # get MIDI evet messages from each file midData = midi.read_midifile(midFile) # store file path and name as meta info meta = {"path": midFile, "name": midFile.split("/")[-1].split(".")[0]} # check for length , 3 tracks for meta , melody and harmony if len(midData) != 3: return (meta, None) for msg in midData[0]: if isinstance(msg, midi.TimeSignatureEvent): # get PPQN (Pulse per Quarter Note)for MIDI resolution meta["ticks_per_quarter_note"] = msg.get_metronome() # get time signature values num = midData[0][2].data[0] dem = 2**(midData[0][2].data[1]) sig = (num, dem) meta["signature"] = sig # Measure time signatur frequency if sig not in sigs: sigs[sig] = 1 else: sigs[sig] += 1 # Filter out sequences with time signature 4/4 based on flag if fourByFour == True: if (num == 3 or num == 6) or (dem != 4): return (meta, None) # Track ingestion nTicks = 0 # get melody and harmony notes and ticks from midi Data melNotes, melTicks = midi_util.ingest_notes(midData[1]) harNotes, harTicks = midi_util.ingest_notes(midData[2]) # round number of ticks with given time step value nTicks = midi_util.round_tick(max(melTicks, harTicks), timeStep) # get melody encodings mapped to defined melody range melSequence = midi_util.round_notes(melNotes, nTicks, timeStep, R=melodyRange, O=melodyMin) # filter out sequences with a double note is found in melody for i in range(melSequence.shape[0]): if np.count_nonzero(melSequence[i, :]) > 1: return (meta, None) # get harmony sequence and process with Mingus harSequence = midi_util.round_notes(harNotes, nTicks, timeStep) # convert sharps to flats to consider compositional considerations flat_note = { "A#": "Bb", "B#": "C", "C#": "Db", "D#": "Eb", "E#": "F", "F#": "Gb", "G#": "Ab", } # use Mingus to identify chords from harmony notes for i in range(harSequence.shape[0]): # get note data notes = np.where(harSequence[i] == 1)[0] if len(notes) > 0: # get note names without octave information noteName = [ mingus.core.notes.int_to_note(note % 12) for note in notes ] chordName = mingus.core.chords.determine(noteName, shorthand=True) if len(chordName) == 0: # convert to flat if chord not identified and try again noteName = [ flat_note[n] if n in flat_note else n for n in noteName ] chordName = mingus.core.chords.determine(noteName, shorthand=True) if len(chordName) == 0: # if chord does not exist, label as NONE if len(harmony) > 0: harmony.append(harmony[-1]) else: harmony.append(unkChord) # resolve chords as major or minor for other types of chord else: resolvedChord = Resolve_Chords(chordName[0]) if resolvedChord: harmony.append(resolvedChord) else: harmony.append(unkChord) else: # label as unresolve after all attempts harmony.append(unkChord) return (meta, (melSequence, harmony))
def parse_nottingham_to_sequence(input_filename, time_step, verbose=False): """ input_filename: a MIDI filename returns a [T x D] matrix representing a sequence with T time steps over D dimensions """ sequence = [] pattern = midi.read_midifile(input_filename) metadata = { "path": input_filename, "name": input_filename.split("/")[-1].split(".")[0] } # Most nottingham midi's have 3 tracks. metadata info, melody, harmony # throw away any tracks that don't fit this if len(pattern) != 3: if verbose: "Skipping track with {} tracks".format(len(pattern)) return (metadata, None) # ticks_per_quarter = -1 for msg in pattern[0]: if isinstance(msg, midi.TimeSignatureEvent): metadata["ticks_per_quarter"] = msg.get_metronome() ticks_per_quarter = msg.get_metronome() if verbose: print "{}".format(input_filename) print "Track resolution: {}".format(pattern.resolution) print "Number of tracks: {}".format(len(pattern)) print "Time step: {}".format(time_step) print "Ticks per quarter: {}".format(ticks_per_quarter) # Track ingestion stage track_ticks = 0 melody_notes, melody_ticks = midi_util.ingest_notes(pattern[1]) harmony_notes, harmony_ticks = midi_util.ingest_notes(pattern[2]) track_ticks = midi_util.round_tick(max(melody_ticks, harmony_ticks), time_step) if verbose: print "Track ticks (rounded): {} ({} time steps)".format(track_ticks, track_ticks/time_step) melody_sequence = midi_util.round_notes(melody_notes, track_ticks, time_step, R=NOTTINGHAM_MELODY_RANGE, O=NOTTINGHAM_MELODY_MIN) for i in range(melody_sequence.shape[0]): if np.count_nonzero(melody_sequence[i, :]) > 1: if verbose: print "Double note found: {}: {} ({})".format(i, np.nonzero(melody_sequence[i, :]), input_filename) return (metadata, None) harmony_sequence = midi_util.round_notes(harmony_notes, track_ticks, time_step) harmonies = [] for i in range(harmony_sequence.shape[0]): notes = np.where(harmony_sequence[i] == 1)[0] if len(notes) > 0: notes_shift = [ mingus.core.notes.int_to_note(h%12) for h in notes] chord = mingus.core.chords.determine(notes_shift, shorthand=True) if len(chord) == 0: # try flat combinations notes_shift = [ SHARPS_TO_FLATS[n] if n in SHARPS_TO_FLATS else n for n in notes_shift] chord = mingus.core.chords.determine(notes_shift, shorthand=True) if len(chord) == 0: if verbose: print "Could not determine chord: {} ({}, {}), defaulting to last steps chord" \ .format(notes_shift, input_filename, i) if len(harmonies) > 0: harmonies.append(harmonies[-1]) else: harmonies.append(NO_CHORD) else: resolved = resolve_chord(chord[0]) if resolved: harmonies.append(resolved) else: harmonies.append(NO_CHORD) else: harmonies.append(NO_CHORD) return (metadata, (melody_sequence, harmonies))
def Data_to_Sequence(input_filename, time_step, verbose=False): pattern = midi.read_midifile(input_filename) metadata = { "path": input_filename, "name": input_filename.split("/")[-1].split(".")[0] } if len(pattern) != 3: return (metadata, None) # ticks_per_quarter = -1 for msg in pattern[0]: if isinstance(msg, midi.TimeSignatureEvent): metadata["ticks_per_quarter"] = msg.get_metronome() num = pattern[0][2].data[0] dem = 2** (pattern[0][2].data[1]) sig = (num, dem) metadata["signature"] = sig if sig not in sigs: sigs[sig] = 1 else: sigs[sig] += 1 if fourByFour == True: if (num == 3 or num == 6) or (dem !=4): return (metadata, None) # Track ingestion stage track_ticks = 0 melody_notes, melody_ticks = midi_util.ingest_notes(pattern[1]) harmony_notes, harmony_ticks = midi_util.ingest_notes(pattern[2]) track_ticks = midi_util.round_tick(max(melody_ticks, harmony_ticks), time_step) if verbose: print "Track ticks (rounded): {} ({} time steps)".format(track_ticks, track_ticks/time_step) melody_sequence = midi_util.round_notes(melody_notes, track_ticks, time_step, R=Melody_Range, O=Melody_Min) for i in range(melody_sequence.shape[0]): if np.count_nonzero(melody_sequence[i, :]) > 1: if verbose: print "Double note found: {}: {} ({})".format(i, np.nonzero(melody_sequence[i, :]), input_filename) return (metadata, None) harmony_sequence = midi_util.round_notes(harmony_notes, track_ticks, time_step) harmonies = [] flat_note = {"A#": "Bb", "B#": "C", "C#": "Db", "D#": "Eb", "E#": "F", "F#": "Gb", "G#": "Ab",} #Identify chords from track 1 notes using mingus library for i in range(harmony_sequence.shape[0]): notes = np.where(harmony_sequence[i] == 1)[0] if len(notes) > 0: notes_shift = [ mingus.core.notes.int_to_note(h%12) for h in notes] chord = mingus.core.chords.determine(notes_shift, shorthand=True) if len(chord) == 0: # try flat combinations notes_shift = [ flat_note[n] if n in flat_note else n for n in notes_shift] chord = mingus.core.chords.determine(notes_shift, shorthand=True) if len(chord) == 0: #print "Could not determine chord: {} ({}, {}), defaulting to last steps chord" \ # .format(notes_shift, input_filename, i) if len(harmonies) > 0: harmonies.append(harmonies[-1]) else: harmonies.append(unkChord) else: resolved = resolve_chord(chord[0]) if resolved: harmonies.append(resolved) else: harmonies.append(unkChord) else: harmonies.append(unkChord) return (metadata, (melody_sequence, harmonies))