From a0f59612a7a43ce84bf7f638d09564ecb8ecfbb7 Mon Sep 17 00:00:00 2001 From: Emma Sawdon Date: Sun, 8 Dec 2024 19:52:57 -0500 Subject: [PATCH 1/2] note_creation.py model_output_to_notes() corrected notes attempt --- basic_pitch/note_creation.py | 49 +++++++++++++++++++++++++----------- tests/test_note_creation.py | 4 ++- 2 files changed, 38 insertions(+), 15 deletions(-) mode change 100644 => 100755 tests/test_note_creation.py diff --git a/basic_pitch/note_creation.py b/basic_pitch/note_creation.py index 0338b6fa..0c3c4592 100644 --- a/basic_pitch/note_creation.py +++ b/basic_pitch/note_creation.py @@ -55,25 +55,34 @@ def model_output_to_notes( multiple_pitch_bends: bool = False, melodia_trick: bool = True, midi_tempo: float = 120, + pitch_offset_correction: float = 1.2, #added parameter to correct pitch offset ) -> Tuple[pretty_midi.PrettyMIDI, List[Tuple[float, float, int, float, Optional[List[int]]]]]: - """Convert model output to MIDI + """Convert model output to MIDI * with corrected pitch mapping * Args: - output: A dictionary with shape - { - 'frame': array of shape (n_times, n_freqs), - 'onset': array of shape (n_times, n_freqs), - 'contour': array of shape (n_times, 3*n_freqs) - } - representing the output of the basic pitch model. + output: A dictionary with shape { + 'frame': array of shape (n_times, n_freqs), + 'onset': array of shape (n_times, n_freqs), + 'contour': array of shape (n_times, 3*n_freqs) + } representing the output of the basic pitch model. + onset_thresh: Minimum amplitude of an onset activation to be considered an onset. + infer_onsets: If True, add additional onsets when there are large differences in frame amplitudes. + min_note_len: The minimum allowed note length in frames. + min_freq: Minimum allowed output frequency, in Hz. If None, all frequencies are used. + max_freq: Maximum allowed output frequency, in Hz. If None, all frequencies are used. + include_pitch_bends: If True, include pitch bends. + multiple_pitch_bends: If True, allow overlapping notes in midi file to have pitch bends. + melodia_trick: Use the melodia post-processing step. + + *pitch_offset_correction: Correction factor to align visualization with MIDI.* Returns: midi : pretty_midi.PrettyMIDI object @@ -83,6 +92,7 @@ def model_output_to_notes( onsets = output["onset"] contours = output["contour"] + #adjust pitch computation to account for the offset! estimated_notes = output_to_notes_polyphonic( frames, onsets, @@ -94,22 +104,33 @@ def model_output_to_notes( max_freq=max_freq, melodia_trick=melodia_trick, ) + + #apply the correction offset to align pitch (created corrected_notes instead of estimated notes) + corrected_notes = [ + (note[0], note[1], int(note[2] - pitch_offset_correction), note[3], note[4]) + for note in estimated_notes + ] + if include_pitch_bends: - estimated_notes_with_pitch_bend = get_pitch_bends(contours, estimated_notes) + corrected_notes_with_pitch_bend = get_pitch_bends(contours, corrected_notes) else: - estimated_notes_with_pitch_bend = [(note[0], note[1], note[2], note[3], None) for note in estimated_notes] + corrected_notes_with_pitch_bend = [ + (note[0], note[1], note[2], note[3], None) for note in corrected_notes + ] times_s = model_frames_to_time(contours.shape[0]) - estimated_notes_time_seconds = [ - (times_s[note[0]], times_s[note[1]], note[2], note[3], note[4]) for note in estimated_notes_with_pitch_bend + corrected_notes_time_seconds = [ + (times_s[note[0]], times_s[note[1]], note[2], note[3], note[4]) + for note in corrected_notes_with_pitch_bend ] return ( - note_events_to_midi(estimated_notes_time_seconds, multiple_pitch_bends, midi_tempo), - estimated_notes_time_seconds, + note_events_to_midi(corrected_notes_time_seconds, multiple_pitch_bends, midi_tempo), + corrected_notes_time_seconds, ) + def sonify_midi(midi: pretty_midi.PrettyMIDI, save_path: Union[pathlib.Path, str], sr: Optional[int] = 44100) -> None: """Sonify a pretty_midi midi object and save to a file. diff --git a/tests/test_note_creation.py b/tests/test_note_creation.py old mode 100644 new mode 100755 index 630bec11..06f59951 --- a/tests/test_note_creation.py +++ b/tests/test_note_creation.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # encoding: utf-8 # # Copyright 2022 Spotify AB @@ -15,6 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. + from basic_pitch.note_creation import drop_overlapping_pitch_bends @@ -47,4 +48,5 @@ def test_drop_overlapping_pitch_bends() -> None: (4.1, 4.2, 77, 1.0, None), # overlaps w prev ] result = drop_overlapping_pitch_bends(note_events_with_pitch_bends) + print("Test Result:", result, " ", expected) assert sorted(result) == sorted(expected) From cd4781acffd0e9c4fb92c8910a40a9ac3d830137 Mon Sep 17 00:00:00 2001 From: Emma Sawdon Date: Mon, 9 Dec 2024 17:16:05 -0500 Subject: [PATCH 2/2] changed back to python from python3, deleted unnecessary comment --- basic_pitch/note_creation.py | 2 +- tests/test_note_creation.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/basic_pitch/note_creation.py b/basic_pitch/note_creation.py index 0c3c4592..37e123bb 100644 --- a/basic_pitch/note_creation.py +++ b/basic_pitch/note_creation.py @@ -55,7 +55,7 @@ def model_output_to_notes( multiple_pitch_bends: bool = False, melodia_trick: bool = True, midi_tempo: float = 120, - pitch_offset_correction: float = 1.2, #added parameter to correct pitch offset + pitch_offset_correction: float = 1.2, ) -> Tuple[pretty_midi.PrettyMIDI, List[Tuple[float, float, int, float, Optional[List[int]]]]]: """Convert model output to MIDI * with corrected pitch mapping * diff --git a/tests/test_note_creation.py b/tests/test_note_creation.py index 06f59951..1be7772b 100755 --- a/tests/test_note_creation.py +++ b/tests/test_note_creation.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python # encoding: utf-8 # # Copyright 2022 Spotify AB @@ -48,5 +48,5 @@ def test_drop_overlapping_pitch_bends() -> None: (4.1, 4.2, 77, 1.0, None), # overlaps w prev ] result = drop_overlapping_pitch_bends(note_events_with_pitch_bends) - print("Test Result:", result, " ", expected) + print("Test Result: /n", result, "/nExpected: /n", expected) assert sorted(result) == sorted(expected)