def _handle_attributes(e, position, part): """ """ ts_num = get_value_from_tag(e, 'time/beats', int) ts_den = get_value_from_tag(e, 'time/beat-type', int) if ts_num and ts_den: part.add(score.TimeSignature(ts_num, ts_den), position) fifths = get_value_from_tag(e, 'key/fifths', int) mode = get_value_from_tag(e, 'key/mode', str) if fifths is not None or mode is not None: part.add(score.KeySignature(fifths, mode), position) diat = get_value_from_tag(e, 'transpose/diatonic', int) chrom = get_value_from_tag(e, 'transpose/chromatic', int) if diat is not None or chrom is not None: part.add(score.Transposition(diat, chrom), position) divs = get_value_from_tag(e, 'divisions', int) if divs: # part.add(score.Divisions(divs), position) part.set_quarter_duration(position, divs) clefs = get_clefs(e) for clef in clefs: part.add(score.Clef(**clef), position)
def add_staffs(part, split=55, only_missing=True): # assign staffs using a hard limit notes = part.notes_tied for n in notes: if only_missing and n.staff: continue if n.midi_pitch > split: staff = 1 else: staff = 2 n.staff = staff n_tied = n.tie_next while n_tied: n_tied.staff = staff n_tied = n_tied.tie_next part.add(score.Clef(number=1, sign='G', line=2, octave_change=0), 0) part.add(score.Clef(number=2, sign='F', line=4, octave_change=0), 0)
def add_staffs_v1(part): # assign staffs by first estimating voices jointly, then assigning voices to staffs notes = part.notes_tied # estimate voices in strictly monophonic way voices = estimate_voices(notes_to_notearray(notes), monophonic_voices=True) # for v, note in zip(voices, notes): # print(note.start.t, note.midi_pitch, v) # group notes by voice by_voice = partition(itemgetter(0), zip(voices, notes)) clefs = {} for v, vnotes in by_voice.items(): # voice numbers may be recycled throughout the piece, so we split by # time gap t_diffs = np.diff([n.start.t for _, n in vnotes]) t_threshold = np.inf # np.median(t_diffs)+1 note_groups = np.split([note for _, note in vnotes], np.where(t_diffs > t_threshold)[0] + 1) # for each note group estimate the clef for note_group in note_groups: if len(note_group) > 0: pitches = [n.midi_pitch for n in note_group] clef = tuple(estimate_clef_properties(pitches).items()) staff = clefs.setdefault(clef, len(clefs)) # print((note_group[0].start.t, note_group[-1].end.t), # (np.min(pitches), np.max(pitches), np.mean(pitches)), clef) for n in note_group: n.staff = staff n_tied = n.tie_next while n_tied: n_tied.staff = staff n_tied = n_tied.tie_next # re-order the staffs to a fixed order (see CLEF_ORDER), rather than by # first appearance clef_list = list((dict(clef), i) for clef, i in clefs.items()) clef_list.sort(key=lambda x: x[0].get('octave_change', 0)) clef_list.sort(key=lambda x: CLEF_ORDER.index(x[0].get('sign', 'G'))) staff_map = dict((j, i + 1) for i, (_, j) in enumerate(clef_list)) for n in notes: n.staff = staff_map[n.staff] for i, (clef_properties, _) in enumerate(clef_list): part.add(score.Clef(number=i + 1, **clef_properties), 0)
def create_part(ticks, notes, spellings, voices, note_ids, time_sigs, key_sigs, part_id=None, part_name=None): LOGGER.debug('create_part') part = score.Part(part_id, part_name=part_name) part.set_quarter_duration(0, ticks) clef = score.Clef(number=1, **estimate_clef_properties([pitch for _, pitch, _ in notes])) part.add(clef, 0) for t, name in key_sigs: fifths, mode = key_name_to_fifths_mode(name) part.add(score.KeySignature(fifths, mode), t) LOGGER.debug('add notes') for (onset, pitch, duration), (step, alter, octave), voice, note_id in zip(notes, spellings, voices, note_ids): if duration > 0: note = score.Note(step, octave, alter, voice=int(voice or 0), id=note_id, symbolic_duration=estimate_symbolic_duration(duration, ticks)) else: note = score.GraceNote('appoggiatura', step, octave, alter, voice=int(voice or 0), id=note_id, symbolic_duration=dict(type='quarter')) part.add(note, onset, onset+duration) if not time_sigs: warnings.warn('No time signatures found, assuming 4/4') time_sigs = [(0, 4, 4)] time_sigs = np.array(time_sigs, dtype=np.int) # for convenience we add the end times for each time signature ts_end_times = np.r_[time_sigs[1:, 0], np.iinfo(np.int).max] time_sigs = np.column_stack((time_sigs, ts_end_times)) LOGGER.debug('add time sigs and measures') for ts_start, num, den, ts_end in time_sigs: time_sig = score.TimeSignature(num.item(), den.item()) part.add(time_sig, ts_start.item()) score.add_measures(part) # this is the old way to add measures. Since part comes from MIDI we # only have a single global divs value, which makes add it easier to compute # measure durations: # measure_counter = 1 # # we call item() on numpy numbers to get the value in the equivalent python type # for ts_start, num, den, ts_end in time_sigs: # time_sig = score.TimeSignature(num.item(), den.item()) # part.add(time_sig, ts_start.item()) # measure_duration = (num.item() * ticks * 4) // den.item() # measure_start_limit = min(ts_end.item(), part.last_point.t) # for m_start in range(ts_start, measure_start_limit, measure_duration): # measure = score.Measure(number=measure_counter) # m_end = min(m_start+measure_duration, ts_end) # part.add(measure, m_start, m_end) # measure_counter += 1 # if np.isinf(ts_end): # ts_end = m_end LOGGER.debug('tie notes') # tie notes where necessary (across measure boundaries, and within measures # notes with compound duration) score.tie_notes(part) LOGGER.debug('find tuplets') # apply simplistic tuplet finding heuristic score.find_tuplets(part) LOGGER.debug('done create_part') return part
def add_clefs(part): by_staff = partition(attrgetter('staff'), part.notes_tied) for staff, notes in by_staff.items(): part.add(score.Clef(number=staff, **estimate_clef_properties([n.midi_pitch for n in notes])), 0)