Source code for musif.extract.features.ambitus.handler
from statistics import mean
from typing import List, Optional, Tuple
from music21.chord import Chord
from music21.harmony import ChordSymbol
from music21.note import Note
from musif.config import Configuration
from musif.extract.common import _filter_parts_data
from musif.extract.constants import DATA_PART_ABBREVIATION
from musif.extract.features.core.constants import DATA_NOTES
from musif.cache import isinstance
from ..prefix import get_part_feature
from .constants import *
[docs]def update_part_objects(
score_data: dict, part_data: dict, cfg: Configuration, part_features: dict
):
notes = part_data[DATA_NOTES]
if notes is None or len(notes) == 0:
return
lowest_note, highest_note = _get_notes_ambitus(notes)
lowest_note_text = lowest_note.nameWithOctave.replace("-", "b")
highest_note_text = highest_note.nameWithOctave.replace("-", "b")
lowest_note_index = int(lowest_note.pitch.midi)
highest_note_index = int(highest_note.pitch.midi)
total_ambitus = highest_note_index - lowest_note_index
ambitus_features = {
LOWEST_NOTE: lowest_note_text,
HIGHEST_NOTE: highest_note_text,
LOWEST_NOTE_INDEX: lowest_note_index,
HIGHEST_NOTE_INDEX: highest_note_index,
AMBITUS: total_ambitus,
}
part_features.update(ambitus_features)
[docs]def update_score_objects(
score_data: dict,
parts_data: List[dict],
cfg: Configuration,
parts_features: List[dict],
score_features: dict,
):
parts_data = _filter_parts_data(parts_data, cfg.parts_filter)
if len(parts_data) == 0:
return
for part_data, part_features in zip(parts_data, parts_features):
part = part_data[DATA_PART_ABBREVIATION]
for feature_name in SCORE_FEATURES:
part_feature = get_part_feature(part, feature_name)
if feature_name in score_features:
score_features[part_feature] = mean(
[score_features[part_feature], parts_features[feature_name]]
)
else:
score_features[part_feature] = part_features.get(feature_name)
def _get_notes_ambitus(notes: List[Note]) -> Tuple[Note, Note]:
first_note = notes[0][0] if isinstance(notes[0], (Chord, ChordSymbol)) else notes[0]
lowest_note = first_note
highest_note = first_note
for note in notes[1:]:
current_note = note[0] if isinstance(note, (Chord, ChordSymbol)) else note
if current_note.pitch.midi < lowest_note.pitch.midi:
lowest_note = current_note
if current_note.pitch.midi > highest_note.pitch.midi:
highest_note = current_note
return lowest_note, highest_note