Remove overlap
remove_overlap
¶
Remove overlapping notes with the same pitch from a score.
Sometimes in piano parts, a note participates in two voices and is printed as if two voices play the same note in unison, when of course the pianist only plays the pitch once. After reading a musicXML score, these doubled notes will be represented in the score. You can use this function to remove overlap.
Other cases can arise from reductions or merging of parts, or from rounding errors. This function can be used to clean up these cases.
Caution: Grace notes read from musicXML files are often represented as starting at the same time as the main note they ornament. Depending on pitches, this could cause the grace note to be removed by this function.
When producing MIDI output for playback, there is a risk of
rounding error causing a note-on to be placed immediately before
the note-off of a prceding note of the same pitch. This can cause
a "stuck note." A simple solution is to shorten notes by a small
amount when the same pitch follows immediately. Then, their note-off
event will be sorted before the next note's note-on event. (A
very slightly reduced duration is rarely audible, and separation
must be introduced in a physical piano performance.) The
min_separation parameter can be used to ensure that adjacent
notes with the same pitch are separated by at least that amount.
0.02 is a reasonable choice: no one can play 50 notes per beat,
but 0.02 is certain to quantize to at least one Standard MIDI File
tick at any reasonable tick size. If units are seconds, 0.02 is
just 20 milliseconds.
The score is first flattened (ties merged, notes extracted from
measures and staves). Within each part, notes sharing the same
key_num that overlap in time are resolved:
- If two notes start within
toleranceof each other, the note that starts first (or the first in sorted order when onsets are equal) is kept and extended to the maximum offset of the two; the second note is removed. - If the notes do not start within
tolerancebut the first note extends past the onset of the second, the first note is shortened so that it ends at the onset of the second note. The second note is extended to the offset of the first if necessary.
Each part is processed independently.
Parameters:
-
score(Score) –The score to process. The original score is not modified; a new flat score is returned.
-
tolerance(float, default:0.1) –Maximum onset difference (in seconds or beats depending on the score's time unit) for two notes with the same
key_numto be considered simultaneous. Defaults to0.1. -
min_separation(float, default:0.0) –Minimum separation (in seconds or beats depending on the score's time unit) between adjacent notes with the same
key_num. If0.0, no minimum separation is enforced. Defaults to0.0. Must be less than half oftoleranceto avoid introducing note durations less than min_separation.
Returns:
-
Score–A new flat score with overlapping same-pitch notes resolved.
Examples:
Two notes with the same pitch that start at the same time are merged into a single note whose duration is the maximum of the two:
>>> from amads.core.basics import Note, Part, Score
>>> score = Score(Part(Note(pitch="C4", onset=0.0, duration=2.0),
... Note(pitch="C4", onset=0.0, duration=3.0)))
>>> result = remove_overlap(score)
>>> notes = result.content[0].content
>>> len(notes)
1
>>> notes[0].duration
3.0
A note that overlaps a later note with the same pitch is trimmed so that it ends exactly when the later note begins. The later note is extended if necessary to cover the full duration of the first note:
>>> score = Score(Part(Note(pitch="C4", onset=0.0, duration=4.0),
... Note(pitch="C4", onset=1.0, duration=2.0)))
>>> result = remove_overlap(score)
>>> notes = result.content[0].content
>>> len(notes)
2
>>> notes[0].duration
1.0
>>> notes[1].onset
1.0
>>> notes[1].duration
3.0
Use min_separation to ensure that adjacent notes with the same pitch are separated by at least that amount:
>>> score = Score(Part(Note(pitch="C4", onset=0.0, duration=4.0),
... Note(pitch="C4", onset=4.0, duration=2.0)))
>>> result = remove_overlap(score, min_separation=0.02)
>>> notes = result.content[0].content
>>> len(notes)
2
>>> notes[0].duration
3.98
>>> notes[1].onset
4.0
>>> notes[1].duration
2.0
Source code in amads/algorithms/remove_overlap.py
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | |