Skip to content

Commit

Permalink
Merge pull request #399 from CPJKU/performance_pedal_fix
Browse files Browse the repository at this point in the history
Performance pedal fix
  • Loading branch information
CarlosCancino-Chacon authored Nov 11, 2024
2 parents f72cf19 + b61d8bf commit 3f15113
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 24 deletions.
20 changes: 18 additions & 2 deletions partitura/performance.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,8 @@ def note_array(self, *args, **kwargs) -> np.ndarray:
duration_sec = offset - note_on_sec
duration_tick = (
n.get(
"note_off_tick",
seconds_to_midi_ticks(
n["sound_off"], mpq=self.mpq, ppq=self.ppq),
seconds_to_midi_ticks(n["note_off"], mpq=self.mpq, ppq=self.ppq),
)
- note_on_tick
Expand Down Expand Up @@ -281,7 +282,6 @@ def adjust_offsets_w_sustain(
pedal = pedal[np.argsort(pedal[:, 0]), :]

# reduce the pedal info to just the times where there is a change in pedal state

pedal = np.vstack(
(
(min(pedal[0, 0] - 1, first_off - 1), 0),
Expand All @@ -299,7 +299,23 @@ def adjust_offsets_w_sustain(
next_pedal_time = pedal[last_pedal_change_before_off + 1, 0]

offs[pedal_down_at_off] = next_pedal_time[pedal_down_at_off]

# adjust offset times of notes that have a reonset while the sustain pedal is on
pitches = np.array([n["midi_pitch"] for n in notes])
note_ons = np.array([n["note_on"] for n in notes])

for pitch in np.unique(pitches):
pitch_indices = np.where(pitches == pitch)[0]

sorted_indices = pitch_indices[np.argsort(note_ons[pitch_indices])]
sorted_note_ons = note_ons[sorted_indices]
sorted_sound_offs = offs[sorted_indices]

adjusted_sound_offs = np.minimum(
sorted_sound_offs[:-1], sorted_note_ons[1:])

offs[sorted_indices[:-1]] = adjusted_sound_offs

for offset, note in zip(offs, notes):
note["sound_off"] = offset

Expand Down
48 changes: 26 additions & 22 deletions tests/test_performance_features.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,36 @@
import os



class TestPerformanceFeatures(unittest.TestCase):
def test_performance_features(self):
fields = ['id','pedal_feature.onset_value','pedal_feature.offset_value','pedal_feature.to_prev_release',
'pedal_feature.to_next_release','onset','duration', 'pitch', 'p_onset', 'p_duration','velocity', 'beat_period']
True_array = np.array([('n1', 0.23374297, 89.74999 , 62.000057, 0., 0.16015087, -0.5, 0.5 , 59, 4.9925 , 0.8775 , 44, 1.4700003),
('n4', 0.03011051, 114.25004 , 61.000244, 0., 0.4027142 , 0. , 1. , 40, 5.7025 , 2.4375 , 22, 2.8474998),
('n3', 2.527984 , 87.500046, 61.000244, 0., 0.4027142 , 0. , 0.25, 56, 5.77625, 2.36375, 26, 2.8474998)],
dtype=[('id', '<U256'),
('articulation_feature.kor', '<f4'),
('pedal_feature.onset_value', '<f4'),
('pedal_feature.offset_value', '<f4'),
('pedal_feature.to_prev_release', '<f4'),
('pedal_feature.to_next_release', '<f4'),
('onset', '<f4'),
('duration', '<f4'),
('pitch', '<i4'),
('p_onset', '<f4'),
('p_duration', '<f4'),
('velocity', '<i4'),
('beat_period', '<f4')])
fields = ['id',
'articulation_feature.kor', 'pedal_feature.onset_value', 'pedal_feature.offset_value', 'pedal_feature.to_prev_release',
'pedal_feature.to_next_release', 'onset', 'duration', 'pitch', 'p_onset', 'p_duration', 'velocity', 'beat_period']
True_array = np.array(
[('n1', 0.23374297, 89.74999, 62.000057, 0., 0.16015087, -0.5, 0.5, 59, 4.9925, 0.8775, 44, 1.4700003),
('n4', 0.03011051, 114.25004, 61.000244, 0.,
0.4027142, 0., 1., 40, 5.7025, 2.4375, 22, 2.8474998),
('n3', 0.8451489, 87.500046, 113., 0., 1.5302137, 0., 0.25, 56, 5.77625, 1.23625, 26, 2.8474998)],
dtype=[('id', '<U256'),
('articulation_feature.kor', '<f4'),
('pedal_feature.onset_value', '<f4'),
('pedal_feature.offset_value', '<f4'),
('pedal_feature.to_prev_release', '<f4'),
('pedal_feature.to_next_release', '<f4'),
('onset', '<f4'),
('duration', '<f4'),
('pitch', '<i4'),
('p_onset', '<f4'),
('p_duration', '<f4'),
('velocity', '<i4'),
('beat_period', '<f4')])
fn = MATCH_EXPRESSIVE_FEATURES_TESTFILES[0]
perf, alignment, score = load_match(filename=fn, create_score=True)
features = make_performance_features(score,
perf,
alignment,
feature_functions = "all")

self.assertTrue(np.all(True_array[fields] == features[fields][:3]), f"The expression features don't match the original.")
feature_functions="all")

self.assertTrue(np.all(True_array[fields] == features[fields][:3]),
f"The expression features don't match the original.")

0 comments on commit 3f15113

Please sign in to comment.