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 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 part_from_matchfile(mf): part = score.Part('P1', mf.info('piece')) # snotes = sorted(mf.snotes, key=attrgetter('OnsetInBeats')) snotes = sort_snotes(mf.snotes) divs = np.lcm.reduce(np.unique([note.Offset.denominator * (note.Offset.tuple_div or 1) for note in snotes])) part.set_quarter_duration(0, divs) min_time = snotes[0].OnsetInBeats # sorted by OnsetInBeats max_time = max(n.OffsetInBeats for n in snotes) ts = mf.time_signatures beats_map, beat_type_map, min_time_q, max_time_q = make_timesig_maps(ts, max_time) bars = np.unique([n.Bar for n in snotes]) t = min_time t = t * 4 / beat_type_map(min_time_q) offset = t # bar map: bar_number-> start in quarters bar_times = {} for b0, b1 in iter_current_next(bars, start=0): bar_times.setdefault(b1, t) if t < 0: t = 0 else: # multiply by diff between consecutive bar numbers n_bars = b1 - b0 if t <= max_time_q: t += (n_bars * 4 * beats_map(t)) / beat_type_map(t) for note in snotes: # start of bar in quarter units bar_start = bar_times[note.Bar] # offset within bar in quarter units bar_offset = (note.Beat - 1) * 4 / beat_type_map(bar_start) # offset within beat in quarter units beat_offset = (4 * note.Offset.numerator / (note.Offset.denominator * (note.Offset.tuple_div or 1))) # # anacrusis if bar_start < 0: # in case of anacrusis we set the bar_start to -bar_duration (in # quarters) so that the below calculation is correct bar_start = - beats_map(bar_start) * 4 / beat_type_map(bar_start) # note onset in divs onset_divs = int(divs * (bar_start + bar_offset + beat_offset - offset)) # print(note.Anchor, onset_divs, bar_start, bar_offset, beat_offset, offset) articulations = set() if 'staccato' in note.ScoreAttributesList: articulations.add('staccato') if 'accent' in note.ScoreAttributesList: articulations.add('accent') # dictionary with keyword args with which the Note (or GraceNote) will be instantiated note_attributes = dict(step=note.NoteName, octave=note.Octave, alter=note.Modifier, id=note.Anchor, articulations=articulations) staff_nr = next((a[-1] for a in note.ScoreAttributesList if a.startswith('staff')), None) try: note_attributes['staff'] = int(staff_nr) except (TypeError, ValueError): # no staff attribute, or staff attribute does not end with a number note_attributes['staff'] = None note_attributes['voice'] = next((int(a) for a in note.ScoreAttributesList if NUMBER_PAT.match(a)), None) # get rid of this if as soon as we have a way to iterate over the # duration components. For now we have to treat the cases simple # and compound durations separately. if note.Duration.add_components: prev_part_note = None for i, (num, den, tuple_div) in enumerate(note.Duration.add_components): # when we add multiple notes that are tied, the first note will # get the original note id, and subsequent notes will get a # derived note id (by appending, 'a', 'b', 'c',...) if i > 0: # tnote_id = 'n{}_{}'.format(note.Anchor, i) note_attributes['id'] = score.make_tied_note_id(note_attributes['id']) part_note = score.Note(**note_attributes) duration_divs = int(divs * 4 * num / (den * (tuple_div or 1))) assert duration_divs > 0 offset_divs = onset_divs + duration_divs part.add(part_note, onset_divs, offset_divs) if prev_part_note: prev_part_note.tie_next = part_note part_note.tie_prev = prev_part_note prev_part_note = part_note onset_divs = offset_divs else: num = note.Duration.numerator den = note.Duration.denominator tuple_div = note.Duration.tuple_div duration_divs = int(divs * 4 * num / (den * (tuple_div or 1))) offset_divs = onset_divs + duration_divs # notes with duration 0, are also treated as grace notes, even if # they do not have a 'grace' score attribute if ('grace' in note.ScoreAttributesList or note.Duration.numerator == 0): part_note = score.GraceNote('appoggiatura', **note_attributes) else: part_note = score.Note(**note_attributes) part.add(part_note, onset_divs, offset_divs) # add time signatures for (ts_beat_time, ts_bar, (ts_beats, ts_beat_type)) in ts: bar_start_divs = int(divs * (bar_times[ts_bar] - offset)) # in quarters part.add(score.TimeSignature(ts_beats, ts_beat_type), bar_start_divs) # add key signatures for (ks_beat_time, ks_bar, keys) in mf.key_signatures: if len(keys) > 1: # there are multple equivalent keys, so we check which one is most # likely according to the key estimator est_keys = estimate_key(notes_to_notearray(part.notes_tied), return_sorted_keys=True) idx = [est_keys.index(key) if key in est_keys else np.inf for key in keys] key_name = keys[np.argmin(idx)] else: key_name = keys[0] fifths, mode = key_name_to_fifths_mode(key_name) part.add(score.KeySignature(fifths, mode), 0) add_staffs(part) # add_clefs(part) # add incomplete measure if necessary if offset < 0: part.add(score.Measure(number=1), 0, int(-offset * divs)) # add the rest of the measures automatically score.add_measures(part) # print(part.pretty()) score.tie_notes(part) score.find_tuplets(part) if not all([n.voice for n in part.notes_tied]): # print('notes without voice detected') add_voices(part) return part