def sample_props(mod, notes): analyze_notes = notes_to_analyze_notes(mod.samples, notes) grouped = sort_groupby(analyze_notes, lambda n: n.sample_idx) return { sample: get_sample_props(mod, sample, list(group)) for (sample, group) in grouped }
def notes_to_midi_file(notes, midi_file, midi_mapping): SP.header('MIDI MAPPING', '%d samples', len(midi_mapping)) SP.print('sample midi base dur vol') fmt = '%6d %4d %4d %3d %3.2f' for sample_idx, midi_def in midi_mapping.items(): SP.print(fmt, (sample_idx,) + tuple(midi_def)) SP.leave() notes_per_channel = sort_groupby(notes, lambda n: n.col_idx) notes_per_channel = [list(grp) for (_, grp) in notes_per_channel] notes_per_channel = [ list(mod_notes_to_midi_notes(notes, midi_mapping)) for notes in notes_per_channel] notes = sorted(flatten(notes_per_channel)) SP.print('Produced %d midi notes (on/offs).' % len(notes)) # Group by column (9 for drums) note_groups = groupby(notes, lambda el: el[0]) tracks = [MidiTrack(list(midi_notes_to_track(channel, note_group))) for (channel, note_group) in note_groups] midi = MidiFile(type = 1) midi.tracks = tracks midi.save(midi_file)
def dissonant_chords(mel_notes): notes_per_row = sort_groupby(mel_notes, lambda n: n.row_idx) n_chords = 0 n_diss_chords = 0 for row, notes in notes_per_row: notes = list(notes) classes = frozenset([n.pitch_idx % 12 for n in notes]) if len(classes) > 1: n_chords += 1 if is_dissonant(classes): n_diss_chords += 1 return n_chords, n_diss_chords
def to_notes(pcode, rel_pitches, row_time): notes = to_notes_without_tempo(pcode, rel_pitches) for n in notes: n.time_ms = row_time fmt = 'Rel pitches: %s, row time: %s.' SP.print(fmt % (rel_pitches, row_time)) # Fix durations cols = sort_groupby(notes, lambda n: n.col_idx) for _, col in cols: fix_durations(list(col)) return notes
def print_encoding_errors(errors): errors_per_type = sort_groupby(errors, lambda x: x[2][0]) for error_type, subsongs in errors_per_type: subsongs = list(subsongs) n_subsongs = len(subsongs) if error_type == ERR_DISSONANCE: header_part = 'WITH DISSONANCE' elif error_type == ERR_FEW_MEL_NOTES: header_part = 'WITH TO FEW MELODIC NOTES' elif error_type == ERR_PARSE_ERROR: header_part = 'WITH PARSE ERRORS' elif error_type == ERR_PITCH_RANGE: header_part = 'WITH TOO WIDE PITCH RANGES' elif error_type == ERR_FEW_NOTES: header_part = 'WITH TO FEW NOTES' elif error_type == ERR_FEW_UNIQUE_PITCHES: header_part = 'WITH TO FEW UNIQUE PITCHES' elif error_type == ERR_EXCESSIVE_PERCUSSION: header_part = 'WITH EXCESSIVE PERCUSSION' else: assert False SP.header('%d SUBSONGS %s' % (n_subsongs, header_part)) for name, idx, err in subsongs: if error_type == ERR_DISSONANCE: args = name, idx, err[1], err[2] fmt = '%-40s %3d %.2f %4d' elif error_type == ERR_FEW_MEL_NOTES: args = name, idx, err[1] fmt = '%-40s %3d %4d' elif error_type == ERR_PARSE_ERROR: args = name, idx, err[1] fmt = '%-40s %3d %s' elif error_type == ERR_PITCH_RANGE: args = name, idx, err[1] fmt = '%-40s %3d %2d' elif error_type == ERR_FEW_NOTES: args = name, idx, err[1] fmt = '%-40s %3d %4d' elif error_type == ERR_FEW_UNIQUE_PITCHES: args = name, idx, err[1] fmt = '%-40s %3d %4d' elif error_type == ERR_EXCESSIVE_PERCUSSION: args = name, idx, err[1], err[2] fmt = '%-40s %3d %4d %4d' else: assert False SP.print(fmt % args) SP.leave()