Skip to content

Commit

Permalink
Merge pull request #396 from CPJKU/clef_map_testing
Browse files Browse the repository at this point in the history
Minor refactor of external PR 384
  • Loading branch information
sildater authored Oct 29, 2024
2 parents 65ec4c5 + fc480bf commit bf5355d
Show file tree
Hide file tree
Showing 9 changed files with 464 additions and 13 deletions.
17 changes: 6 additions & 11 deletions partitura/musicanalysis/note_features.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@

import types
from typing import List, Union, Tuple
from partitura.utils import ensure_notearray, ensure_rest_array
from partitura.utils import (
ensure_notearray,
ensure_rest_array,
clef_sign_to_int
)
from partitura.score import ScoreLike
from collections import defaultdict

Expand Down Expand Up @@ -554,15 +558,6 @@ def clef_feature(na, part, **kwargs):
see staff_feature for this information.
"""
notes = {n.id: n for n in part.notes_tied}
numerical_clef_dict = {
"G": 0,
"F": 1,
"C": 2,
"percussion": 3,
"TAB": 4,
"jianpu": 5,
"none": 6,
}
names = ["clef_sign", "clef_line", "clef_octave_change"]
clef_dict = defaultdict(list)
staff_numbers = set()
Expand Down Expand Up @@ -600,7 +595,7 @@ def clef_feature(na, part, **kwargs):
clef_idx = clef_dict[interpolator_key][0](time)
clef = clef_dict[clef_key][int(clef_idx)]
sign = clef.sign or "none"
W[i, 0] = numerical_clef_dict[sign]
W[i, 0] = clef_sign_to_int(sign)
W[i, 1] = clef.line or 0
W[i, 2] = clef.octave_change or 0

Expand Down
72 changes: 71 additions & 1 deletion partitura/score.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
object). This object serves as a timeline at which musical elements
are registered in terms of their start and end times.
"""

from copy import copy, deepcopy
from collections import defaultdict
from collections.abc import Iterable
Expand Down Expand Up @@ -46,6 +45,7 @@
key_mode_to_int,
_OrderedSet,
update_note_ids_after_unfolding,
clef_sign_to_int,
)
from partitura.utils.generic import interp1d
from partitura.utils.music import transpose_note, step2pc
Expand Down Expand Up @@ -229,6 +229,76 @@ def key_signature_map(self):
fill_value="extrapolate",
)

@property
def clef_map(self):
"""A function mapping timeline times to the clef in each
staff at that time. The function can take scalar
values or lists/arrays of values
Returns
-------
function
The mapping function
"""
clefs = np.array(
[
(
c.start.t,
c.staff,
clef_sign_to_int(c.sign),
c.line,
c.octave_change if c.octave_change is not None else 0
)
for c in self.iter_all(Clef)
]
)

interpolators = []
for s in range(1, self.number_of_staves + 1):
staff_clefs = clefs[clefs[:, 1] == s]
if len(staff_clefs) == 0:
# default treble clef
staff, clef, line, octave_change = s, clef_sign_to_int("none"), 0, 0

warnings.warn(
"No clefs found on staff {}, assuming {} clef.".format(s, clef)
)
if self.first_point is None:
t0, tN = 0, 0
else:
t0 = self.first_point.t
tN = self.last_point.t
staff_clefs = np.array(
[
(t0, staff, clef, line, octave_change),
(tN, staff, clef, line, octave_change),
]
)
elif len(staff_clefs) == 1:
# If there is only a single clef
staff_clefs = np.array([staff_clefs[0, :], staff_clefs[0, :]])

if staff_clefs[0, 0] > self.first_point.t:
staff_clefs = np.vstack(
((self.first_point.t, *staff_clefs[0, 1:]), staff_clefs)
)

interpolators.append(
interp1d(
staff_clefs[:, 0],
staff_clefs[:, 1:],
axis=0,
kind="previous",
bounds_error=False,
fill_value="extrapolate",
)
)

def collator(time: Union[int, np.ndarray]) -> np.ndarray:
return np.array([interpolator(time) for interpolator in interpolators], dtype=int)

return collator

@property
def measure_map(self):
"""A function mapping timeline times to the start and end of
Expand Down
4 changes: 4 additions & 0 deletions partitura/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
pianoroll_to_notearray,
match_note_arrays,
key_mode_to_int,
clef_sign_to_int,
clef_int_to_sign,
remove_silence_from_performed_part,
note_array_from_part_list,
slice_notearray_by_time,
Expand Down Expand Up @@ -74,6 +76,8 @@
"key_name_to_fifths_mode",
"fifths_mode_to_key_name",
"key_mode_to_int",
"clef_sign_to_int",
"clef_int_to_sign",
"pitch_spelling_to_midi_pitch",
"pitch_spelling_to_note_name",
"show_diff",
Expand Down
12 changes: 12 additions & 0 deletions partitura/utils/globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -729,3 +729,15 @@
"vii": (7, "M"),
},
}

#["G", "F", "C", "percussion", "TAB", "jianpu", "none"]
CLEF_TO_INT = {
"G": 0,
"F": 1,
"C": 2,
"percussion": 3,
"TAB": 4,
"jianpu": 5,
"none": 6,
}
INT_TO_CLEF = {v: k for k, v in CLEF_TO_INT.items()}
6 changes: 6 additions & 0 deletions partitura/utils/music.py
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,12 @@ def key_int_to_mode(mode):
raise ValueError("Unknown mode {}".format(mode))


def clef_sign_to_int(clef_sign: str) -> int:
return CLEF_TO_INT[clef_sign]

def clef_int_to_sign(clef_int: int) -> str:
return INT_TO_CLEF[clef_int]

def estimate_symbolic_duration(
dur, div, eps=10**-3, return_com_durations=False
) -> Union[Dict[str, Any], Tuple[Dict[str, Any]]]:
Expand Down
5 changes: 5 additions & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@
for fn in ["test_ts_map_ts_starts_not_at_zero.xml"]
]

CLEF_MAP_TESTFILES = [
os.path.join(MUSICXML_PATH, fn)
for fn in ["test_clef_map.musicxml"]
]

REST_ARRAY_TESTFILES = [
os.path.join(MUSICXML_PATH, fn)
for fn in ["test_unfold_complex.xml", "test_rest.musicxml"]
Expand Down
Loading

0 comments on commit bf5355d

Please sign in to comment.