From 3fdfd39c716975158073da070f283154bd972161 Mon Sep 17 00:00:00 2001 From: sildater Date: Tue, 1 Oct 2024 08:16:29 +0200 Subject: [PATCH 1/4] fix time maps import --- docs/source/Tutorial/notebook.ipynb | 186 ++++++++++++++-------------- 1 file changed, 93 insertions(+), 93 deletions(-) diff --git a/docs/source/Tutorial/notebook.ipynb b/docs/source/Tutorial/notebook.ipynb index 31d98713..b90d44e4 100644 --- a/docs/source/Tutorial/notebook.ipynb +++ b/docs/source/Tutorial/notebook.ipynb @@ -47,11 +47,12 @@ }, "id": "PeabdL1k7YC4", "outputId": "fcb7d1be-27a1-4c79-c5d3-8cbfa54cae44", - "scrolled": true, "pycharm": { "is_executing": true - } + }, + "scrolled": true }, + "outputs": [], "source": [ "# Install partitura\n", "! pip install partitura\n", @@ -64,21 +65,20 @@ "import sys, os\n", "sys.path.insert(0, os.path.join(os.getcwd(), \"partitura_tutorial\", \"content\"))\n", "sys.path.insert(0,'/content/partitura_tutorial/content')\n" - ], - "outputs": [] + ] }, { "cell_type": "code", "execution_count": 2, "id": "impressed-principle", "metadata": {}, + "outputs": [], "source": [ "import glob\n", "import partitura as pt\n", "import numpy as np\n", "import matplotlib.pyplot as plt" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -103,6 +103,7 @@ "execution_count": 3, "id": "photographic-profession", "metadata": {}, + "outputs": [], "source": [ "# setup the dataset\n", "from load_data import init_dataset\n", @@ -110,8 +111,7 @@ "MUSICXML_DIR = os.path.join(DATASET_DIR, 'musicxml')\n", "MIDI_DIR = os.path.join(DATASET_DIR, 'midi')\n", "MATCH_DIR = os.path.join(DATASET_DIR, 'match')" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -220,12 +220,12 @@ "execution_count": 4, "id": "c9179e78", "metadata": {}, + "outputs": [], "source": [ "path_to_musicxml = pt.EXAMPLE_MUSICXML\n", "part = pt.load_musicxml(path_to_musicxml)[0]\n", "print(part.pretty())" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -250,20 +250,20 @@ "execution_count": 5, "id": "423aac6a", "metadata": {}, + "outputs": [], "source": [ "part.notes" - ], - "outputs": [] + ] }, { "cell_type": "code", "execution_count": 6, "id": "0a929369", "metadata": {}, + "outputs": [], "source": [ "dir(part.notes[0])" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -278,23 +278,23 @@ "execution_count": 7, "id": "2a8293c9", "metadata": {}, + "outputs": [], "source": [ "a_new_note = pt.score.Note(id='n04', step='A', octave=4, voice=1)\n", "part.add(a_new_note, start=3, end=15)\n", "# print(part.pretty())" - ], - "outputs": [] + ] }, { "cell_type": "code", "execution_count": 8, "id": "eba2fa93", "metadata": {}, + "outputs": [], "source": [ "part.remove(a_new_note)\n", "# print(part.pretty())" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -313,10 +313,10 @@ "execution_count": 9, "id": "e95eb0f7", "metadata": {}, + "outputs": [], "source": [ "part.beat_map(part.notes[0].end.t)" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -331,10 +331,10 @@ "execution_count": 10, "id": "05346a03", "metadata": {}, + "outputs": [], "source": [ "part.time_signature_map(part.notes[0].end.t)" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -356,22 +356,22 @@ "execution_count": 11, "id": "74943a93", "metadata": {}, + "outputs": [], "source": [ "for measure in part.iter_all(pt.score.Measure):\n", " print(measure)" - ], - "outputs": [] + ] }, { "cell_type": "code", "execution_count": 12, "id": "6cbfd044", "metadata": {}, + "outputs": [], "source": [ "for note in part.iter_all(pt.score.GenericNote, include_subclasses=True, start=0, end=24):\n", " print(note)" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -388,6 +388,7 @@ "execution_count": 13, "id": "fe430921", "metadata": {}, + "outputs": [], "source": [ "# figure out the last measure position, time signature and beat length in divs\n", "measures = [m for m in part.iter_all(pt.score.Measure)]\n", @@ -405,18 +406,17 @@ "# add a note\n", "a_new_note = pt.score.Note(id='n04', step='A', octave=4, voice=1)\n", "part.add(a_new_note, start=append_measure_start, end=append_measure_start+one_beat_in_divs_at_the_end)" - ], - "outputs": [] + ] }, { "cell_type": "code", "execution_count": 14, "id": "f9d738a5", "metadata": {}, + "outputs": [], "source": [ "# print(part.pretty())" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -436,21 +436,21 @@ "execution_count": 15, "id": "5d82a340", "metadata": {}, + "outputs": [], "source": [ "path_to_midifile = pt.EXAMPLE_MIDI\n", "performedpart = pt.load_performance_midi(path_to_midifile)[0]" - ], - "outputs": [] + ] }, { "cell_type": "code", "execution_count": 16, "id": "4e3090d9", "metadata": {}, + "outputs": [], "source": [ "performedpart.notes" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -465,6 +465,7 @@ "execution_count": 17, "id": "d6eb12f2", "metadata": {}, + "outputs": [], "source": [ "import numpy as np \n", "\n", @@ -491,14 +492,14 @@ " part.add(pt.score.Note(id='n{}'.format(idx), step=step, \n", " octave=int(octave), alter=alter, voice=voice, staff=str((voice-1)%2+1)), \n", " start=start, end=end)" - ], - "outputs": [] + ] }, { "cell_type": "code", "execution_count": 18, "id": "572e856c", "metadata": {}, + "outputs": [], "source": [ "l = 200\n", "p = pt.score.Part('CoK', 'Cat on Keyboard', quarter_duration=8)\n", @@ -509,54 +510,53 @@ " np.random.randint(40,60, size=(1,l+1)),\n", " np.random.randint(40,60, size=(1,l+1))\n", " ))" - ], - "outputs": [] + ] }, { "cell_type": "code", "execution_count": 19, "id": "f9f03a50", "metadata": {}, + "outputs": [], "source": [ "for k in range(l):\n", " for j in range(4):\n", " addnote(pitch[j,k], p, j+1, ons[j,k], ons[j,k]+dur[j,k+1], \"v\"+str(j)+\"n\"+str(k))" - ], - "outputs": [] + ] }, { "cell_type": "code", "execution_count": 20, "id": "09fb6b45", "metadata": {}, + "outputs": [], "source": [ "p.add(pt.score.TimeSignature(4, 4), start=0)\n", "p.add(pt.score.Clef(1, \"G\", line = 3, octave_change=0),start=0)\n", "p.add(pt.score.Clef(2, \"G\", line = 3, octave_change=0),start=0)\n", "pt.score.add_measures(p)\n", "pt.score.tie_notes(p)" - ], - "outputs": [] + ] }, { "cell_type": "code", "execution_count": 21, "id": "834582d5", "metadata": {}, + "outputs": [], "source": [ "# pt.save_score_midi(p, \"CatPerformance.mid\", part_voice_assign_mode=2)" - ], - "outputs": [] + ] }, { "cell_type": "code", "execution_count": 22, "id": "006f02ed", "metadata": {}, + "outputs": [], "source": [ "# pt.save_musicxml(p, \"CatScore.xml\")" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -602,6 +602,7 @@ "execution_count": 23, "id": "first-basin", "metadata": {}, + "outputs": [], "source": [ "# Note array from a score\n", "\n", @@ -613,8 +614,7 @@ "\n", "# Get note array.\n", "score_note_array = score_part.note_array()" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -629,11 +629,11 @@ "execution_count": 24, "id": "alternate-coordinate", "metadata": {}, + "outputs": [], "source": [ "# Lets see the first notes in this note array\n", "print(score_note_array[:10])" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -650,10 +650,10 @@ "execution_count": 25, "id": "subtle-millennium", "metadata": {}, + "outputs": [], "source": [ "print(score_note_array.dtype.names)" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -686,6 +686,7 @@ "execution_count": 26, "id": "passing-lending", "metadata": {}, + "outputs": [], "source": [ "# Note array from a performance\n", "\n", @@ -697,8 +698,7 @@ "\n", "# Get note array!\n", "performance_note_array = performance_part.note_array()" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -713,10 +713,10 @@ "execution_count": 27, "id": "pointed-stupid", "metadata": {}, + "outputs": [], "source": [ "print(performance_note_array.dtype.names)" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -737,10 +737,10 @@ "execution_count": 28, "id": "subject-reducing", "metadata": {}, + "outputs": [], "source": [ "print(performance_note_array[:5])" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -755,6 +755,7 @@ "execution_count": 29, "id": "spread-performer", "metadata": {}, + "outputs": [], "source": [ "note_array = np.array(\n", " [(60, 0, 2, 40),\n", @@ -771,8 +772,7 @@ "\n", "# Note array to `PerformedPart`\n", "performed_part = pt.performance.PerformedPart.from_note_array(note_array)" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -787,11 +787,11 @@ "execution_count": 30, "id": "changed-check", "metadata": {}, + "outputs": [], "source": [ "# export as MIDI file\n", "pt.save_performance_midi(performed_part, \"example.mid\")" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -808,6 +808,7 @@ "execution_count": 31, "id": "figured-coordinator", "metadata": {}, + "outputs": [], "source": [ "extended_score_note_array = pt.utils.music.ensure_notearray(\n", " score_part,\n", @@ -817,18 +818,17 @@ " # include_metrical_position=True, # adds 3 fields: is_downbeat, rel_onset_div, tot_measure_div\n", " include_grace_notes=True # adds 2 fields: is_grace, grace_type\n", ")" - ], - "outputs": [] + ] }, { "cell_type": "code", "execution_count": 32, "id": "vietnamese-pathology", "metadata": {}, + "outputs": [], "source": [ "extended_score_note_array.dtype.names" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -837,6 +837,7 @@ "metadata": { "scrolled": true }, + "outputs": [], "source": [ "print(extended_score_note_array[['id', \n", " 'step', \n", @@ -845,8 +846,7 @@ " 'ks_fifths', \n", " 'ks_mode', #'is_downbeat'\n", " ]][:10])" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -879,6 +879,7 @@ "metadata": { "scrolled": true }, + "outputs": [], "source": [ "# Path to the MusicXML file\n", "score_fn = os.path.join(MUSICXML_DIR, 'Chopin_op10_no3.musicxml')\n", @@ -914,8 +915,7 @@ "\n", "accented_note_idxs = np.where(accent_note_array['accent'])\n", "print(accent_note_array[accented_note_idxs][:5])" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -944,6 +944,7 @@ "execution_count": 35, "id": "essential-academy", "metadata": {}, + "outputs": [], "source": [ "# TODO: change the example\n", "# Path to the MusicXML file\n", @@ -953,8 +954,7 @@ "score_part = pt.load_musicxml(score_fn)\n", "# compute piano roll\n", "pianoroll = pt.utils.compute_pianoroll(score_part)" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -969,6 +969,7 @@ "execution_count": 36, "id": "massive-monaco", "metadata": {}, + "outputs": [], "source": [ "piano_range = True\n", "time_unit = 'beat'\n", @@ -979,8 +980,7 @@ " time_div=time_div, # Number of cells per time unit\n", " piano_range=piano_range # Use range of the piano (88 keys)\n", ")" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -1007,14 +1007,14 @@ "execution_count": 37, "id": "mature-dylan", "metadata": {}, + "outputs": [], "source": [ "fig, ax = plt.subplots(1, figsize=(20, 10))\n", "ax.imshow(pianoroll.toarray(), origin=\"lower\", cmap='gray', interpolation='nearest', aspect='auto')\n", "ax.set_xlabel(f'Time ({time_unit}s/{time_div})')\n", "ax.set_ylabel('Piano key' if piano_range else 'MIDI pitch')\n", "plt.show()" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -1031,13 +1031,13 @@ "metadata": { "scrolled": true }, + "outputs": [], "source": [ "pianoroll, note_indices = pt.utils.compute_pianoroll(score_part, return_idxs=True)\n", "\n", "# MIDI pitch, start, end\n", "print(note_indices[:5])" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -1055,6 +1055,7 @@ "execution_count": 39, "id": "parental-links", "metadata": {}, + "outputs": [], "source": [ "pianoroll = pt.utils.compute_pianoroll(score_part)\n", "\n", @@ -1064,8 +1065,7 @@ "ppart = pt.performance.PerformedPart.from_note_array(new_note_array)\n", "\n", "pt.save_performance_midi(ppart, \"newmidi.mid\")" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -1112,13 +1112,13 @@ "execution_count": 40, "id": "rolled-cloud", "metadata": {}, + "outputs": [], "source": [ "# path to the match\n", "match_fn = os.path.join(MATCH_DIR, 'Chopin_op10_no3_p01.match')\n", "# loading a match file\n", "performed_part, alignment, score_part = pt.load_match(match_fn, create_part=True)" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -1140,6 +1140,7 @@ "execution_count": 41, "id": "latest-smell", "metadata": {}, + "outputs": [], "source": [ "# path to the match\n", "match_fn = os.path.join(MATCH_DIR, 'Chopin_op10_no3_p01.match')\n", @@ -1150,8 +1151,7 @@ "\n", "# loading a match file\n", "performed_part, alignment = pt.load_match(match_fn)" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -1175,10 +1175,10 @@ "execution_count": 42, "id": "radio-interim", "metadata": {}, + "outputs": [], "source": [ "alignment[:10]" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -1197,6 +1197,7 @@ "execution_count": 43, "id": "published-understanding", "metadata": {}, + "outputs": [], "source": [ "# note array of the score\n", "snote_array = score_part.note_array()\n", @@ -1209,8 +1210,7 @@ "matched_snote_array = snote_array[matched_note_idxs[:, 0]]\n", "# note array of the matched performed notes\n", "matched_pnote_array = pnote_array[matched_note_idxs[:, 1]]" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -1227,6 +1227,7 @@ "execution_count": 44, "id": "offshore-bridal", "metadata": {}, + "outputs": [], "source": [ "# get all match files\n", "matchfiles = glob.glob(os.path.join(MATCH_DIR, 'Chopin_op10_no3_p*.match'))\n", @@ -1248,13 +1249,12 @@ " performance, alignment = pt.load_match(matchfile)\n", " ppart = performance[0]\n", " # Get score time to performance time map\n", - " _, stime_to_ptime_map = pt.utils.music.get_time_maps_from_alignment(\n", + " _, stime_to_ptime_map = pt.musicanalysis.performance_codec.get_time_maps_from_alignment(\n", " ppart, score_part, alignment)\n", " # Compute naïve tempo curve\n", " performance_time = stime_to_ptime_map(score_time_ending)\n", " tempo_curves[i,:] = 60 * np.diff(score_time_ending) / np.diff(performance_time)" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -1263,6 +1263,7 @@ "metadata": { "scrolled": false }, + "outputs": [], "source": [ "fig, ax = plt.subplots(1, figsize=(15, 8))\n", "color = plt.cm.rainbow(np.linspace(0, 1, len(tempo_curves)))\n", @@ -1284,8 +1285,7 @@ "plt.legend(frameon=False, bbox_to_anchor = (1.15, .9))\n", "plt.grid(axis='x')\n", "plt.show()" - ], - "outputs": [] + ] }, { "cell_type": "markdown", From 69f89459e4c3fd50088261d9079efa9043bfca9b Mon Sep 17 00:00:00 2001 From: sildater Date: Tue, 1 Oct 2024 08:22:34 +0200 Subject: [PATCH 2/4] add warning --- partitura/musicanalysis/performance_codec.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/partitura/musicanalysis/performance_codec.py b/partitura/musicanalysis/performance_codec.py index 54c1b0ac..2064f1b8 100644 --- a/partitura/musicanalysis/performance_codec.py +++ b/partitura/musicanalysis/performance_codec.py @@ -735,6 +735,7 @@ def get_time_maps_from_alignment( # Get indices of the matched notes (notes in the score # for which there is a performance note match_idx = get_matched_notes(score_note_array, perf_note_array, alignment) + print(match_idx) # Get onsets and durations score_onsets = score_note_array[match_idx[:, 0]]["onset_beat"] @@ -824,6 +825,11 @@ def get_matched_notes(spart_note_array, ppart_note_array, alignment): p_idx = int(p_idx) matched_idxs.append((s_idx, p_idx)) + if len(matched_idxs) == 0: + warnings.warn( + "No matched note IDs found." + ) + return np.array(matched_idxs) From 6d24b6a34517b5f8f3fee01c11573e3de99a3560 Mon Sep 17 00:00:00 2001 From: sildater Date: Tue, 1 Oct 2024 08:25:15 +0200 Subject: [PATCH 3/4] explainer in warning --- partitura/musicanalysis/performance_codec.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/partitura/musicanalysis/performance_codec.py b/partitura/musicanalysis/performance_codec.py index 2064f1b8..ea863c5e 100644 --- a/partitura/musicanalysis/performance_codec.py +++ b/partitura/musicanalysis/performance_codec.py @@ -735,7 +735,6 @@ def get_time_maps_from_alignment( # Get indices of the matched notes (notes in the score # for which there is a performance note match_idx = get_matched_notes(score_note_array, perf_note_array, alignment) - print(match_idx) # Get onsets and durations score_onsets = score_note_array[match_idx[:, 0]]["onset_beat"] @@ -828,6 +827,9 @@ def get_matched_notes(spart_note_array, ppart_note_array, alignment): if len(matched_idxs) == 0: warnings.warn( "No matched note IDs found." + "Either the alignment contains no matches" + "or the IDs in score of performance do not correspond to the alignment" + "(repeat unfolding, etc.)" ) return np.array(matched_idxs) From 9754a90da2ca9c6ba46c9081c32e308bbf21d1f8 Mon Sep 17 00:00:00 2001 From: sildater Date: Tue, 1 Oct 2024 08:35:40 +0200 Subject: [PATCH 4/4] correct formatting --- partitura/musicanalysis/performance_codec.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/partitura/musicanalysis/performance_codec.py b/partitura/musicanalysis/performance_codec.py index ea863c5e..434767de 100644 --- a/partitura/musicanalysis/performance_codec.py +++ b/partitura/musicanalysis/performance_codec.py @@ -826,10 +826,10 @@ def get_matched_notes(spart_note_array, ppart_note_array, alignment): if len(matched_idxs) == 0: warnings.warn( - "No matched note IDs found." - "Either the alignment contains no matches" - "or the IDs in score of performance do not correspond to the alignment" - "(repeat unfolding, etc.)" + "No matched note IDs found. " + "Either the alignment contains no matches " + "or the IDs in score of performance do not correspond to the alignment " + "(maybe due to repeat unfolding)." ) return np.array(matched_idxs)