From 2513a718ccd637c4024921d3db006a01ef4e33c2 Mon Sep 17 00:00:00 2001 From: sildater Date: Tue, 27 Jan 2026 08:53:24 +0100 Subject: [PATCH 1/3] create wrapper (wip) --- matchmaker/par/__init__.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 matchmaker/par/__init__.py diff --git a/matchmaker/par/__init__.py b/matchmaker/par/__init__.py new file mode 100644 index 0000000..42e0175 --- /dev/null +++ b/matchmaker/par/__init__.py @@ -0,0 +1,37 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +""" +Top module for alignment methods imported from the parangonar library: +https://github.com/sildater/parangonar +""" +import parangonar as pa +from matchmaker.base import OnlineAlignment +from typing import Callable, Dict, Generator +from numpy.typing import NDArray + +QUEUE_SENTINEL = object() + +class OnlineParangonarAlignment(OnlineAlignment): + def __init__(self, + parangonar_tracker): + # an instance of + self.parangonar_tracker = parangonar_tracker + + def __call__(self, performance_note): + # process + score_position = self.parangonar_tracker.step(performance_note) + return score_position + + def run(self) -> Generator[int, None, float]: + while self.parangonar_tracker.is_still_following(): + input_feature = self.queue.get(block=True) + if input_feature == QUEUE_SENTINEL: + print("empty queue") + return None + else: + current_state = self(input_feature) + yield current_state + + return None + + From c5dd5b6ffd2c2f391ae118884f6f948a985c61b1 Mon Sep 17 00:00:00 2001 From: sildater Date: Tue, 27 Jan 2026 23:21:31 +0100 Subject: [PATCH 2/3] extend wrapper for four parangonar trackers --- matchmaker/__init__.py | 2 +- matchmaker/external/__init__.py | 84 +++++++++++++++++++++++++++++++++ matchmaker/par/__init__.py | 37 --------------- 3 files changed, 85 insertions(+), 38 deletions(-) create mode 100644 matchmaker/external/__init__.py delete mode 100644 matchmaker/par/__init__.py diff --git a/matchmaker/__init__.py b/matchmaker/__init__.py index 13bc26c..f3d0670 100644 --- a/matchmaker/__init__.py +++ b/matchmaker/__init__.py @@ -6,7 +6,7 @@ import pkg_resources -from . import dp, features, io, prob, utils +from . import dp, features, io, prob, utils, external from .matchmaker import * __all__ = ["dp", "features", "io", "prob", "utils"] diff --git a/matchmaker/external/__init__.py b/matchmaker/external/__init__.py new file mode 100644 index 0000000..b659de2 --- /dev/null +++ b/matchmaker/external/__init__.py @@ -0,0 +1,84 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +""" +Top module for alignment methods imported from the parangonar library: +https://github.com/sildater/parangonar +""" +import parangonar as pa +# from matchmaker.base import OnlineAlignment +from typing import Callable, Dict, Generator +from numpy.typing import NDArray + +QUEUE_SENTINEL = object() + +class OnlineParangonarAlignment():#(OnlineAlignment): + def __init__(self, + queue, + score_note_array, + parangonar_tracker_type: str = "SLT_OLTW"): + # an instance of + self.queue = queue + if parangonar_tracker_type == "SLT_OLTW": + self.parangonar_tracker = pa.TOLTWMatcher(score_note_array, + tracker_type=parangonar_tracker_type) + elif parangonar_tracker_type == "SL_OLTW": + self.parangonar_tracker = pa.OLTWMatcher(score_note_array, + tracker_type=parangonar_tracker_type) + elif parangonar_tracker_type == "OPTM": + self.parangonar_tracker = pa.OnlinePureTransformerMatcher(score_note_array) + elif parangonar_tracker_type == "OTM": + self.parangonar_tracker = pa.OnlineTransformerMatcher(score_note_array) + + def __call__(self, performance_note): + # process + score_position = self.parangonar_tracker(performance_note) + return score_position + + def run(self) -> Generator[int, None, float]: + while self.parangonar_tracker.is_still_following(): + input_feature = self.queue.get(block=True) + if input_feature is QUEUE_SENTINEL: + print("empty queue") + return None + else: + current_state = self(input_feature) + yield current_state + + return None + + def run_offline(self): + self.queue.put(QUEUE_SENTINEL) + for position in self.run(): + print(position, self.parangonar_tracker.unique_onsets[position]) + + return self.parangonar_tracker.warping_path + +if __name__ == "__main__": + import partitura as pt + from queue import Queue + # load the example match file included in the library + perf_match, groundtruth_alignment, score_match = pt.load_match( + filename= pa.EXAMPLE, # + create_score=True + ) + + # compute note arrays from the loaded score and performance + pna_match = perf_match[0].note_array() + sna_match = score_match[0].note_array(include_grace_notes=True) + + # create queue + input_queue = Queue() + for note_row in pna_match: + input_queue.put(note_row) + + # create matchmaker follower + score_follower = OnlineParangonarAlignment( + input_queue, sna_match, "OTM") + + # run the follower offline + warping_path = score_follower.run_offline() + + + + + diff --git a/matchmaker/par/__init__.py b/matchmaker/par/__init__.py deleted file mode 100644 index 42e0175..0000000 --- a/matchmaker/par/__init__.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -""" -Top module for alignment methods imported from the parangonar library: -https://github.com/sildater/parangonar -""" -import parangonar as pa -from matchmaker.base import OnlineAlignment -from typing import Callable, Dict, Generator -from numpy.typing import NDArray - -QUEUE_SENTINEL = object() - -class OnlineParangonarAlignment(OnlineAlignment): - def __init__(self, - parangonar_tracker): - # an instance of - self.parangonar_tracker = parangonar_tracker - - def __call__(self, performance_note): - # process - score_position = self.parangonar_tracker.step(performance_note) - return score_position - - def run(self) -> Generator[int, None, float]: - while self.parangonar_tracker.is_still_following(): - input_feature = self.queue.get(block=True) - if input_feature == QUEUE_SENTINEL: - print("empty queue") - return None - else: - current_state = self(input_feature) - yield current_state - - return None - - From c34452df55a8ea7f8cf206c2673de46c506792cc Mon Sep 17 00:00:00 2001 From: sildater Date: Tue, 17 Feb 2026 07:34:30 +0100 Subject: [PATCH 3/3] parangonar dependency --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 014e5b4..22cb38b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,7 @@ dependencies = [ "pyaudio>=0.2.14", "pyfluidsynth>=1.3.3", "matplotlib>=3.9.4", + "parangonar", ] [project.optional-dependencies]