Пример #1
0
def _handle_note(e, position, part, ongoing, prev_note):

    # prev_note is used when the current note has a <chord/> tag

    # get some common features of element if available
    duration = get_value_from_tag(e, 'duration', int) or 0
    # elements may have an explicit temporal offset
    # offset = get_value_from_tag(e, 'offset', int) or 0
    staff = get_value_from_tag(e, 'staff', int) or None
    voice = get_value_from_tag(e, 'voice', int) or None

    note_id = get_value_from_attribute(e, 'id', str)

    symbolic_duration = {}
    dur_type = get_value_from_tag(e, 'type', str)
    if dur_type:
        symbolic_duration['type'] = dur_type

    dots = len(e.findall('dot'))
    if dots:
        symbolic_duration['dots'] = dots

    actual_notes = get_value_from_tag(e, 'time-modification/actual-notes', int)
    if actual_notes:
        symbolic_duration['actual_notes'] = actual_notes

    normal_notes = get_value_from_tag(e, 'time-modification/normal-notes', int)
    if normal_notes:
        symbolic_duration['normal_notes'] = normal_notes

    chord = e.find('chord')
    if chord is not None:
        # this note starts at the same position as the previous note, and has
        # same duration
        assert prev_note is not None
        position = prev_note.start.t

    articulations_e = e.find('notations/articulations')
    if articulations_e is not None:
        articulations = get_articulations(articulations_e)
    else:
        articulations = {}

    pitch = e.find('pitch')
    if pitch is not None:

        step = get_value_from_tag(pitch, 'step', str)
        alter = get_value_from_tag(pitch, 'alter', int)
        octave = get_value_from_tag(pitch, 'octave', int)

        grace = e.find('grace')

        if grace is not None:
            grace_type, steal_proportion = get_grace_info(grace)
            note = score.GraceNote(grace_type, step, octave, alter,
                                   note_id, voice=voice, staff=staff,
                                   symbolic_duration=symbolic_duration,
                                   articulations=articulations,
                                   steal_proportion=steal_proportion)
            if (isinstance(prev_note, score.GraceNote)
                and prev_note.voice == voice):
                note.grace_prev = prev_note
        else:

            note = score.Note(step, octave, alter, note_id,
                              voice=voice, staff=staff,
                              symbolic_duration=symbolic_duration,
                              articulations=articulations)

        if (isinstance(prev_note, score.GraceNote)
            and prev_note.voice == voice):
            prev_note.grace_next = note
    else:
        # note element is a rest
        note = score.Rest(note_id, voice=voice, staff=staff,
                          symbolic_duration=symbolic_duration,
                          articulations=articulations)

    part.add(note, position, position+duration)

    ties = e.findall('tie')
    if len(ties) > 0:

        tie_key = ('tie', getattr(note, 'midi_pitch', 'rest'))
        tie_types = set(tie.attrib['type'] for tie in ties)

        if 'stop' in tie_types:

            tie_prev = ongoing.get(tie_key, None)

            if tie_prev:

                note.tie_prev = tie_prev
                tie_prev.tie_next = note
                del ongoing[tie_key]

        if 'start' in tie_types:

            ongoing[tie_key] = note

    notations = e.find('notations')

    if notations is not None:

        if notations.find('fermata') is not None:

            fermata = score.Fermata(note)
            part.add(fermata, position)
            note.fermata = fermata

        starting_slurs, stopping_slurs = handle_slurs(notations, ongoing, note, position)

        for slur in starting_slurs:

            part.add(slur, position)

        for slur in stopping_slurs:

            part.add(slur, end=position+duration)

        starting_tups, stopping_tups = handle_tuplets(notations, ongoing, note)

        for tup in starting_tups:

            part.add(tup, position)

        for tup in stopping_tups:

            part.add(tup, end=position+duration)

    new_position = position + duration

    return new_position, note
Пример #2
0
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
Пример #3
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
Пример #4
0
def _handle_note(e, position, part, ongoing, prev_note, doc_order):

    # get some common features of element if available
    duration = get_value_from_tag(e, "duration", int) or 0
    # elements may have an explicit temporal offset
    # offset = get_value_from_tag(e, 'offset', int) or 0
    staff = get_value_from_tag(e, "staff", int) or None
    voice = get_value_from_tag(e, "voice", int) or None

    # add support of uppercase "ID" tags
    note_id = (get_value_from_attribute(e, "id", str)
               if get_value_from_attribute(e, "id", str) else
               get_value_from_attribute(e, "ID", str))

    symbolic_duration = {}
    dur_type = get_value_from_tag(e, "type", str)
    if dur_type:
        symbolic_duration["type"] = dur_type

    dots = len(e.findall("dot"))
    if dots:
        symbolic_duration["dots"] = dots

    actual_notes = get_value_from_tag(e, "time-modification/actual-notes", int)
    if actual_notes:
        symbolic_duration["actual_notes"] = actual_notes

    normal_notes = get_value_from_tag(e, "time-modification/normal-notes", int)
    if normal_notes:
        symbolic_duration["normal_notes"] = normal_notes

    chord = e.find("chord")
    if chord is not None:
        # this note starts at the same position as the previous note, and has
        # same duration
        assert prev_note is not None
        position = prev_note.start.t

    articulations_e = e.find("notations/articulations")
    if articulations_e is not None:
        articulations = get_articulations(articulations_e)
    else:
        articulations = {}

    pitch = e.find("pitch")
    if pitch is not None:

        step = get_value_from_tag(pitch, "step", str)
        alter = get_value_from_tag(pitch, "alter", int)
        octave = get_value_from_tag(pitch, "octave", int)

        grace = e.find("grace")

        if grace is not None:
            grace_type, steal_proportion = get_grace_info(grace)
            note = score.GraceNote(
                grace_type=grace_type,
                step=step,
                octave=octave,
                alter=alter,
                id=note_id,
                voice=voice,
                staff=staff,
                symbolic_duration=symbolic_duration,
                articulations=articulations,
                steal_proportion=steal_proportion,
                doc_order=doc_order,
            )
            if isinstance(prev_note,
                          score.GraceNote) and prev_note.voice == voice:
                note.grace_prev = prev_note
        else:
            note = score.Note(
                step=step,
                octave=octave,
                alter=alter,
                id=note_id,
                voice=voice,
                staff=staff,
                symbolic_duration=symbolic_duration,
                articulations=articulations,
                doc_order=doc_order,
            )

        if isinstance(prev_note, score.GraceNote) and prev_note.voice == voice:
            prev_note.grace_next = note
    else:
        # note element is a rest
        note = score.Rest(
            id=note_id,
            voice=voice,
            staff=staff,
            symbolic_duration=symbolic_duration,
            articulations=articulations,
            doc_order=doc_order,
        )

    part.add(note, position, position + duration)

    ties = e.findall("tie")
    if len(ties) > 0:

        tie_key = ("tie", getattr(note, "midi_pitch", "rest"))
        tie_types = set(tie.attrib["type"] for tie in ties)

        if "stop" in tie_types:

            tie_prev = ongoing.get(tie_key, None)

            if tie_prev:

                note.tie_prev = tie_prev
                tie_prev.tie_next = note
                del ongoing[tie_key]

        if "start" in tie_types:

            ongoing[tie_key] = note

    notations = e.find("notations")

    if notations is not None:

        if notations.find("fermata") is not None:

            fermata = score.Fermata(note)
            part.add(fermata, position)
            note.fermata = fermata

        starting_slurs, stopping_slurs = handle_slurs(notations, ongoing, note,
                                                      position)

        for slur in starting_slurs:

            part.add(slur, position)

        for slur in stopping_slurs:

            part.add(slur, end=position + duration)

        starting_tups, stopping_tups = handle_tuplets(notations, ongoing, note)

        for tup in starting_tups:

            part.add(tup, position)

        for tup in stopping_tups:

            part.add(tup, end=position + duration)

    new_position = position + duration

    return new_position, note