├── .flake8 ├── .github └── workflows │ ├── linting.yml │ ├── partitura_unittests.yml │ ├── pypi_publish.yml │ └── stale.yml ├── .gitignore ├── .readthedocs.yml ├── CHANGES.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── docs ├── Makefile ├── make.bat ├── requirements.txt └── source │ ├── Tutorial │ └── notebook.ipynb │ ├── conf.py │ ├── genindex.rst │ ├── images │ ├── aknowledge_logo.png │ ├── aknowledge_logo_negative.png │ ├── erc_fwf_logos.jpg │ ├── issue_choosing_label.png │ ├── issue_page.png │ ├── open_pull_request.png │ ├── pull_requests.png │ ├── score_example.png │ ├── score_example_1.png │ ├── score_example_2.png │ ├── unitest_pass.png │ └── writing_issue.png │ ├── index.rst │ ├── introduction.rst │ └── modules │ ├── partitura.musicanalysis.rst │ ├── partitura.performance.rst │ ├── partitura.rst │ ├── partitura.score.rst │ └── partitura.utils.rst ├── partitura ├── __init__.py ├── assets │ ├── mei.rng │ ├── musicxml.xsd │ ├── partitura_logo_black.png │ ├── partitura_logo_white.png │ ├── score_example.krn │ ├── score_example.mei │ ├── score_example.mid │ └── score_example.musicxml ├── directions.py ├── display.py ├── io │ ├── __init__.py │ ├── exportaudio.py │ ├── exportkern.py │ ├── exportmatch.py │ ├── exportmei.py │ ├── exportmidi.py │ ├── exportmusicxml.py │ ├── exportparangonada.py │ ├── importdcml.py │ ├── importkern.py │ ├── importmatch.py │ ├── importmei.py │ ├── importmidi.py │ ├── importmusic21.py │ ├── importmusicxml.py │ ├── importnakamura.py │ ├── importparangonada.py │ ├── matchfile_base.py │ ├── matchfile_utils.py │ ├── matchlines_v0.py │ ├── matchlines_v1.py │ └── musescore.py ├── musicanalysis │ ├── __init__.py │ ├── key_identification.py │ ├── meter.py │ ├── note_array_to_score.py │ ├── note_features.py │ ├── performance_codec.py │ ├── performance_features.py │ ├── pitch_spelling.py │ ├── tonal_tension.py │ └── voice_separation.py ├── performance.py ├── score.py └── utils │ ├── __init__.py │ ├── fluidsynth.py │ ├── generic.py │ ├── globals.py │ ├── misc.py │ ├── music.py │ ├── normalize.py │ └── synth.py ├── requirements.txt ├── setup.py └── tests ├── __init__.py ├── data ├── kern │ ├── chor228.krn │ ├── double_repeat_example.krn │ ├── fine_with_repeat.krn │ ├── long_example.krn │ ├── single_voice_example.krn │ ├── spline_splitting.krn │ ├── tie_mismatch.krn │ ├── tuple_durations.krn │ ├── variable_length_pr_bug.krn │ └── voice_duplication.krn ├── match │ ├── Chopin_op10_no3_p01.match │ ├── mozart_k265_var1.match │ └── test_fuer_elise.match ├── mei │ ├── Bach_Hilf_Herr_Jesu.mei │ ├── Bach_Prelude.mei │ ├── Beethoven_Op119_Nr01-Breitkopf.mei │ ├── Beethoven_Op119_Nr02-Breitkopf.mei │ ├── CRIM_Mass_0030_4.mei │ ├── Mozart_k265_v1.mei │ ├── Schubert_An_die_Sonne_D.439.mei │ ├── mensural.mei │ ├── test_articulation.mei │ ├── test_barline.mei │ ├── test_clefs_tss.mei │ ├── test_cross_staff_voices.mei │ ├── test_divs_tuplet.mei │ ├── test_grace_note.mei │ ├── test_merge_voices2.mei │ ├── test_metrical_position.mei │ ├── test_parts_duration.mei │ ├── test_parts_duration2.mei │ ├── test_ties.mei │ ├── test_tuplets.mei │ ├── test_tuplets_no_ppq.mei │ ├── test_unfold_complex.mei │ └── test_unfold_timeline.mei ├── midi │ ├── bach_midi_score.mid │ ├── mozart_k265_var1.mid │ ├── mozart_k265_var1_quantized.mid │ ├── test_anacrusis.mid │ └── test_basic_midi.mid ├── musescore │ └── 160.03_Pastorale.mscx ├── musicxml │ ├── Three-Part_Invention_No_13_(fragment).xml │ ├── example_octave_shift.musicxml │ ├── mozart_k265_var1.musicxml │ ├── test_anacrusis.xml │ ├── test_articulation.xml │ ├── test_barline.xml │ ├── test_basic_midi.musicxml │ ├── test_beats.xml │ ├── test_chew_vosa_example.xml │ ├── test_chord_duration.musicxml │ ├── test_clef.musicxml │ ├── test_clef_map.musicxml │ ├── test_clefs_tss.xml │ ├── test_cross_staff_beaming.musicxml │ ├── test_cross_staff_voices.musicxml │ ├── test_grace_note.xml │ ├── test_harmony.musicxml │ ├── test_ignore_invisible_objects.musicxml │ ├── test_length_pianoroll.xml │ ├── test_merge_interpolation.xml │ ├── test_merge_voices1.xml │ ├── test_merge_voices2.xml │ ├── test_metrical_position.xml │ ├── test_multi_part.xml │ ├── test_multi_part_change_divs.xml │ ├── test_note_features.xml │ ├── test_note_ties.xml │ ├── test_note_ties_divs.xml │ ├── test_part_group.xml │ ├── test_partial_measures.xml │ ├── test_partial_measures_consecutive.xml │ ├── test_pianoroll_sum.xml │ ├── test_pianoroll_sum_reduced.xml │ ├── test_polyphonic.xml │ ├── test_rest.musicxml │ ├── test_score_object.musicxml │ ├── test_ts_map_ts_starts_not_at_zero.xml │ ├── test_tuplet_attributes.musicxml │ ├── test_unfold_complex.xml │ ├── test_unfold_complex_result.xml │ ├── test_unfold_dacapo.xml │ ├── test_unfold_dacapo_result.xml │ ├── test_unfold_timeline.xml │ ├── test_unfold_timeline_result.xml │ ├── test_unfold_timeline_result_updated_ids.xml │ ├── test_unfold_volta_numbers.xml │ └── test_unfold_volta_numbers_result.xml ├── nakamura │ ├── Shi05_infer_corresp.txt │ ├── Shi05_infer_match.txt │ ├── test_nakamura_performance_corresp.txt │ └── test_nakamura_performance_match.txt ├── parangonada │ └── mozart_k265_var1 │ │ ├── align.csv │ │ ├── feature.csv │ │ ├── part.csv │ │ ├── ppart.csv │ │ └── zalign.csv ├── png │ └── example_score.png ├── tsv │ ├── test_harmonies.tsv │ ├── test_measures.tsv │ └── test_notes.tsv └── wav │ └── example_linear_equal_temperament_sr8000.wav ├── temp_test.py ├── test_clef.py ├── test_cross_staff.py ├── test_dcml_import.py ├── test_deprecations.py ├── test_display.py ├── test_fluidsynth.py ├── test_harmony.py ├── test_kern.py ├── test_key_estimation.py ├── test_load_performance.py ├── test_load_score.py ├── test_m21_import.py ├── test_match_export.py ├── test_match_import.py ├── test_mei.py ├── test_merge_parts.py ├── test_metrical_position.py ├── test_midi_export.py ├── test_midi_import.py ├── test_musescore.py ├── test_nakamura.py ├── test_new_divs.py ├── test_note_array.py ├── test_note_features.py ├── test_octave_shift.py ├── test_parangonada.py ├── test_part_properties.py ├── test_partial_measures.py ├── test_performance.py ├── test_performance_codec.py ├── test_performance_features.py ├── test_pianoroll.py ├── test_pitch_spelling.py ├── test_quarter_adjust.py ├── test_rest_array.py ├── test_synth.py ├── test_time_estimation.py ├── test_times.py ├── test_tonal_tension.py ├── test_transpose.py ├── test_urlload.py ├── test_utils.py ├── test_voice_estimation.py └── test_xml.py /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 88 3 | per-file-ignores = __init__.py:F401 4 | -------------------------------------------------------------------------------- /.github/workflows/linting.yml: -------------------------------------------------------------------------------- 1 | name: Blacken code 2 | 3 | on: 4 | push: 5 | branches: 6 | - develop 7 | jobs: 8 | format: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Format code with black 13 | run: | 14 | pip install black 15 | black ./partitura 16 | - name: Commit changes 17 | uses: EndBug/add-and-commit@v4 18 | with: 19 | author_name: ${{ github.actor }} 20 | author_email: ${{ github.actor }}@users.noreply.github.com 21 | message: "Format code with black (bot)" 22 | add: "." 23 | - name: Notify errors 24 | if: failure() 25 | uses: dawidd6/action-send-mail@v2 26 | with: 27 | server_address: smtp.gmail.com 28 | server_port: 465 29 | username: ${{ secrets.EMAIL_USERNAME }} 30 | password: ${{ secrets.EMAIL_PASSWORD }} 31 | subject: "Format code with black" 32 | body: "Format code with black failed" 33 | to: ${{ secrets.EMAIL_TO }} 34 | from: ${{ secrets.EMAIL_FROM }} 35 | content_type: text/plain 36 | -------------------------------------------------------------------------------- /.github/workflows/partitura_unittests.yml: -------------------------------------------------------------------------------- 1 | name: Partitura Unittests 2 | 3 | on: 4 | push: 5 | branches: [main, develop] 6 | pull_request: 7 | branches: [develop] 8 | 9 | jobs: 10 | test: 11 | strategy: 12 | max-parallel: 5 13 | matrix: 14 | platform: [ubuntu-latest, macos-latest, windows-latest] 15 | 16 | runs-on: ${{ matrix.platform }} 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Set up Python 3.8 20 | uses: actions/setup-python@v2 21 | with: 22 | python-version: 3.8 23 | - name: Install dependencies 24 | run: | 25 | python -m pip install --upgrade pip 26 | pip install -r requirements.txt 27 | pip install . 28 | - name: Install Optional dependencies 29 | run: | 30 | pip install music21==8.3.0 Pillow==9.5.0 musescore==0.0.1 31 | pip install miditok==2.0.6 tokenizers==0.13.3 pandas==2.0.3 32 | - name: Run Tests 33 | run: | 34 | pip install coverage 35 | python -m unittest discover ./tests/ 'test*.py' 36 | coverage run -m unittest discover ./tests/ 'test*.py' 37 | coverage xml 38 | 39 | - name: Check coverage with CodeCov 40 | uses: codecov/codecov-action@v1 41 | with: 42 | file: ./coverage.xml 43 | verbose: true 44 | 45 | -------------------------------------------------------------------------------- /.github/workflows/pypi_publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish to PyPI.org 2 | on: 3 | release: 4 | types: [published] 5 | jobs: 6 | pypi: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout 10 | uses: actions/checkout@v3 11 | with: 12 | fetch-depth: 0 13 | - run: python3 -m pip install --upgrade build && python3 -m build 14 | - name: Publish package 15 | uses: pypa/gh-action-pypi-publish@release/v1 16 | with: 17 | password: ${{ secrets.PYPI_API_TOKEN }} 18 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: "Close stale issues and PRs" 2 | 3 | on: 4 | schedule: 5 | # Every day at 00:00 6 | - cron: "0 0 * * *" 7 | workflow_dispatch: 8 | 9 | jobs: 10 | stale: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/stale@v4.0.0 15 | with: 16 | stale-issue-message: 'This issue had no activity for **6 months**. It will be closed in **2 weeks** unless there is some new activity. Is this issue already resolved?' 17 | stale-issue-label: 'stale' 18 | exempt-issue-labels: 'bug,enhancement,good first issue' 19 | stale-pr-message: 'This pull request had no activity for **6 months**. It will be closed in **2 weeks** unless there is some new activity.' 20 | stale-pr-label: 'stale' 21 | days-before-stale: 180 22 | days-before-close: 14 23 | operations-per-run: 200 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | +.pyc 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | pip-wheel-metadata/ 25 | share/python-wheels/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | MANIFEST 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .nox/ 45 | .coverage 46 | .coverage.* 47 | .cache 48 | nosetests.xml 49 | coverage.xml 50 | *.cover 51 | *.py,cover 52 | .hypothesis/ 53 | .pytest_cache/ 54 | cover/ 55 | 56 | # Translations 57 | *.mo 58 | *.pot 59 | 60 | # Django stuff: 61 | *.log 62 | local_settings.py 63 | db.sqlite3 64 | db.sqlite3-journal 65 | 66 | # Flask stuff: 67 | instance/ 68 | .webassets-cache 69 | 70 | # Scrapy stuff: 71 | .scrapy 72 | 73 | # Sphinx documentation 74 | docs/_build/ 75 | 76 | # PyBuilder 77 | .pybuilder/ 78 | target/ 79 | 80 | # Jupyter Notebook 81 | .ipynb_checkpoints 82 | 83 | # IPython 84 | profile_default/ 85 | ipython_config.py 86 | 87 | # pyenv 88 | # For a library or package, you might want to ignore these files since the code is 89 | # intended to run in multiple environments; otherwise, check them in: 90 | # .python-version 91 | 92 | # pipenv 93 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 94 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 95 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 96 | # install all needed dependencies. 97 | #Pipfile.lock 98 | 99 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 100 | __pypackages__/ 101 | 102 | # Celery stuff 103 | celerybeat-schedule 104 | celerybeat.pid 105 | 106 | # SageMath parsed files 107 | *.sage.py 108 | 109 | # Environments 110 | .env 111 | .venv 112 | env/ 113 | venv/ 114 | ENV/ 115 | env.bak/ 116 | venv.bak/ 117 | 118 | # Spyder project settings 119 | .spyderproject 120 | .spyproject 121 | 122 | # Rope project settings 123 | .ropeproject 124 | 125 | # mkdocs documentation 126 | /site 127 | 128 | # mypy 129 | .mypy_cache/ 130 | .dmypy.json 131 | dmypy.json 132 | 133 | # Pyre type checker 134 | .pyre/ 135 | 136 | # pytype static type analyzer 137 | .pytype/ 138 | 139 | # Cython debug symbols 140 | cython_debug/ 141 | 142 | # static files generated from Django application using `collectstatic` 143 | media 144 | static 145 | 146 | .DS_Store 147 | *# 148 | *~ 149 | 150 | # vscode 151 | .vscode 152 | 153 | # phdocs 154 | phdocs.txt 155 | 156 | # fluidsynth default soundfont 157 | partitura/assets/MuseScore_General.sf* 158 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | 2 | # .readthedocs.yaml 3 | # Read the Docs configuration file 4 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 5 | 6 | # Required 7 | version: 2 8 | 9 | # Set the version of Python and other tools you might need 10 | build: 11 | os: ubuntu-20.04 12 | tools: 13 | python: "3.8" 14 | 15 | #mkdocs: 16 | # configuration: mkdocs.yml 17 | 18 | # Optionally declare the Python requirements required to build your docs 19 | python: 20 | install: 21 | - requirements: docs/requirements.txt -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | You can help the developers of **Partitura** by contributing, requesting features or reporting error. 4 | 5 | ## Opening an Issue 6 | 7 | To open an issue navigate to the partitura github repository: 8 | 9 | [Repository]: https://github.com/CPJKU/partitura/issues "Partitura Issues Link" 10 | 11 | #### Click to **New Issue** 12 | 13 | ![](docs/source/images/issue_page.png) 14 | 15 | #### Write your description 16 | 17 | ![](docs/source/images/writing_issue.png) 18 | 19 | #### Choose the appropriate label 20 | 21 | ![](docs/source/images/issue_choosing_label.png) 22 | 23 | ##### How to choose your issue label: 24 | 25 | - **Question** to ask us a question or **help wanted** if you need a solution to a particular partitura problem. 26 | - **Bug** to report something not working correctly. 27 | - **Enhancement** to request for a feature. 28 | 29 | ## How to contribute 30 | 31 | A step by step guide : 32 | 33 | 1. To contribute is to open a relevant issue. 34 | 2. ***Fork*** the Partitura repo. 35 | 3. *Checkout* or *Pull* the latest stable develop branch. 36 | 4. *Checkout a new branch* from the develop with the name of your develop idea. 37 | 5. When finished coding, open a pull request to the develop branch of partitura. 38 | 39 | ### Open a relevant issue 40 | 41 | Follow section how to open an issue. 42 | 43 | ### **Fork** the Repo 44 | 45 | Fork partitura from 46 | https://github.com/CPJKU/partitura 47 | 48 | Once that you have already forked the repo, you can clone it: 49 | ```shell 50 | git clone https://github.com/YourUsername/partitura.git 51 | cd partitura 52 | ``` 53 | 54 | ### Get latest Develop Branch 55 | 56 | ```shell 57 | git fetch upstream 58 | git checkout develop 59 | git pull 60 | ``` 61 | 62 | ### Create your Branch 63 | 64 | ```shel 65 | git checkout -b mycrazyidea 66 | ``` 67 | 68 | Do your coding magic!!! 69 | 70 | Remember to commit regularly with descriptive messages about your changes. 71 | 72 | **!!! IMPORTANT NOTE !!!** 73 | 74 | Write Unit tests to check the compatibility and assure the evolution of your features. 75 | 76 | *Please follow instruction script found in the Tutorial repository.* 77 | 78 | ### Opening your Pull Request 79 | 80 | ##### Go to your forked Partitura repo and Click New Pull Request 81 | 82 | Open a Pull request from your new branch into the original `https://github.com/CPJKU/partitura` **develop** branch. 83 | 84 | Your pull request should then be visible on: 85 | 86 | [Partitura Pull Requests]: https://github.com/CPJKU/partitura/pulls "Partitura Pull Requests" 87 | 88 | ![](docs/source/images/pull_requests.png) 89 | 90 | ##### Set the base to develop and the compare to your branch 91 | 92 | ![](docs/source/images/open_pull_request.png) 93 | 94 | ##### Then create your Pull Request and add a description. 95 | 96 | When you create your PR then the partitura Unitests including the Unit Tests you wrote are ran. 97 | 98 | If there is no conflict with the develop branch then you will see this on your screen : 99 | 100 | ![](docs/source/images/unitest_pass.png) 101 | 102 | If indeed the tests pass then a person from the development team of Partitura will review your work and accept your Pull Request. 103 | 104 | Your features will then be included to the next release of Partitura or a discussion will kick-start on your pull request thread. 105 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | partitura 2 | sphinx==6.1.3 3 | nbsphinx==0.8.12 4 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # http://www.sphinx-doc.org/en/master/config 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | import pkg_resources 16 | 17 | sys.path.insert(0, os.path.abspath("../../partitura")) 18 | # The master toctree document. 19 | master_doc = "index" 20 | 21 | # -- Project information ----------------------------------------------------- 22 | 23 | project = "partitura" 24 | # copyright = '2019, Maarten Grachten' 25 | author = "Maarten Grachten, Carlos Cancino-Chacón, Silvan Peter, Emmanouil Karystinaios, Francesco Foscarin, Thassilo Gadermaier" 26 | 27 | # The version info for the project you're documenting, acts as replacement for 28 | # |version| and |release|, also used in various other places throughout the 29 | # built documents. 30 | # 31 | # The short X.Y version. 32 | version = "1.6.0" # pkg_resources.get_distribution("partitura").version 33 | # The full version, including alpha/beta/rc tags. 34 | release = "1.6.0" 35 | 36 | # # The full version, including alpha/beta/rc tags 37 | # release = pkg_resources.get_distribution("partitura").version 38 | # # release = '0.1.0-pre' 39 | 40 | # The language for content autogenerated by Sphinx. Refer to documentation 41 | # for a list of supported languages. 42 | # 43 | # This is also used if you do content translation via gettext catalogs. 44 | # Usually you set "language" from the command line for these cases. 45 | language = "python" 46 | 47 | 48 | # -- General configuration --------------------------------------------------- 49 | 50 | # List of patterns, relative to source directory, that match files and 51 | # directories to ignore when looking for source files. 52 | exclude_patterns = ["_build"] 53 | 54 | # The name of the Pygments (syntax highlighting) style to use. 55 | pygments_style = "sphinx" 56 | 57 | # Add any Sphinx extension module names here, as strings. They can be 58 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 59 | # ones. 60 | extensions = [ 61 | "sphinx.ext.autodoc", 62 | "sphinx.ext.autosummary", 63 | "sphinx.ext.doctest", 64 | "sphinx.ext.todo", 65 | "sphinx.ext.coverage", 66 | "sphinx.ext.mathjax", 67 | "sphinx.ext.viewcode", 68 | # 'sphinxcontrib.napoleon', 69 | "sphinx.ext.napoleon", 70 | "nbsphinx", 71 | # 'sphinxcontrib.bibtex', # for bibliographic references 72 | # 'sphinxcontrib.rsvgconverter', # for SVG->PDF conversion in LaTeX output 73 | # 'sphinx_gallery.load_style', # load CSS for gallery (needs SG >= 0.6) 74 | # 'sphinx_last_updated_by_git', #? get "last updated" from Git 75 | # 'sphinx_codeautolink', # automatic links from code to documentation 76 | # 'sphinx.ext.intersphinx', # links to other Sphinx projects (e.g. NumPy) 77 | ] 78 | 79 | # These projects are also used for the sphinx_codeautolink extension: 80 | intersphinx_mapping = { 81 | "IPython": ("https://ipython.readthedocs.io/en/stable/", None), 82 | "matplotlib": ("https://matplotlib.org/", None), 83 | "numpy": ("https://docs.scipy.org/doc/numpy/", None), 84 | "pandas": ("https://pandas.pydata.org/docs/", None), 85 | "python": ("https://docs.python.org/3/", None), 86 | } 87 | 88 | # see http://stackoverflow.com/q/12206334/562769 89 | numpydoc_show_class_members = False 90 | 91 | # Add any paths that contain templates here, relative to this directory. 92 | templates_path = ["_templates"] 93 | 94 | # The suffix(es) of source filenames. 95 | # You can specify multiple suffix as a list of string: 96 | # source_suffix = ['.rst', '.md'] 97 | source_suffix = ".rst" 98 | 99 | # List of patterns, relative to source directory, that match files and 100 | # directories to ignore when looking for source files. 101 | # This pattern also affects html_static_path and html_extra_path. 102 | exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] 103 | 104 | 105 | # -- Options for HTML output ------------------------------------------------- 106 | 107 | # The theme to use for HTML and HTML Help pages. See the documentation for 108 | # a list of builtin themes. 109 | # 110 | # only import and set the theme if we're building docs locally 111 | if os.environ.get("READTHEDOCS") != "True": 112 | import sphinx_rtd_theme 113 | 114 | html_theme = "sphinx_rtd_theme" 115 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] 116 | else: 117 | html_theme = "default" 118 | 119 | # Add any paths that contain custom static files (such as style sheets) here, 120 | # relative to this directory. They are copied after the builtin static files, 121 | # so a file named "default.css" will overwrite the builtin "default.css". 122 | # html_static_path = ['_static'] 123 | 124 | # Output file base name for HTML help builder. 125 | htmlhelp_basename = "partituradoc" 126 | -------------------------------------------------------------------------------- /docs/source/genindex.rst: -------------------------------------------------------------------------------- 1 | Index 2 | ===== 3 | -------------------------------------------------------------------------------- /docs/source/images/aknowledge_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/docs/source/images/aknowledge_logo.png -------------------------------------------------------------------------------- /docs/source/images/aknowledge_logo_negative.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/docs/source/images/aknowledge_logo_negative.png -------------------------------------------------------------------------------- /docs/source/images/erc_fwf_logos.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/docs/source/images/erc_fwf_logos.jpg -------------------------------------------------------------------------------- /docs/source/images/issue_choosing_label.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/docs/source/images/issue_choosing_label.png -------------------------------------------------------------------------------- /docs/source/images/issue_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/docs/source/images/issue_page.png -------------------------------------------------------------------------------- /docs/source/images/open_pull_request.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/docs/source/images/open_pull_request.png -------------------------------------------------------------------------------- /docs/source/images/pull_requests.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/docs/source/images/pull_requests.png -------------------------------------------------------------------------------- /docs/source/images/score_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/docs/source/images/score_example.png -------------------------------------------------------------------------------- /docs/source/images/score_example_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/docs/source/images/score_example_1.png -------------------------------------------------------------------------------- /docs/source/images/score_example_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/docs/source/images/score_example_2.png -------------------------------------------------------------------------------- /docs/source/images/unitest_pass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/docs/source/images/unitest_pass.png -------------------------------------------------------------------------------- /docs/source/images/writing_issue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/docs/source/images/writing_issue.png -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. partitura documentation master file, created by 2 | sphinx-quickstart on Thu Aug 15 18:48:12 2019. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Partitura documentation 7 | ======================= 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | 12 | introduction 13 | Tutorial/notebook.ipynb 14 | genindex 15 | 16 | .. _api_reference: 17 | 18 | .. toctree:: 19 | :maxdepth: 2 20 | :caption: API Reference 21 | 22 | ./modules/partitura 23 | ./modules/partitura.score 24 | ./modules/partitura.performance 25 | ./modules/partitura.musicanalysis 26 | ./modules/partitura.utils 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/source/modules/partitura.musicanalysis.rst: -------------------------------------------------------------------------------- 1 | partitura.musicanalysis 2 | ======================= 3 | .. currentmodule:: partitura.musicanalysis 4 | .. automodule:: partitura.musicanalysis 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. 10 | partitura.musicanalysis.voice\_separation 11 | ----------------------------------------- 12 | 13 | .. toctree:: 14 | 15 | .. automodule:: partitura.musicanalysis.voice_separation 16 | :members: 17 | :undoc-members: 18 | :show-inheritance: 19 | 20 | partitura.musicanalysis.key\_identification 21 | ------------------------------------------- 22 | 23 | .. automodule:: partitura.musicanalysis.key_identification 24 | :members: 25 | :undoc-members: 26 | :show-inheritance: 27 | 28 | partitura.musicanalysis.pitch\_spelling 29 | --------------------------------------- 30 | 31 | .. automodule:: partitura.musicanalysis.pitch_spelling 32 | :members: 33 | :undoc-members: 34 | :show-inheritance: 35 | 36 | -------------------------------------------------------------------------------- /docs/source/modules/partitura.performance.rst: -------------------------------------------------------------------------------- 1 | partitura.performance 2 | --------------------- 3 | 4 | .. automodule:: partitura.performance 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | -------------------------------------------------------------------------------- /docs/source/modules/partitura.rst: -------------------------------------------------------------------------------- 1 | partitura 2 | --------- 3 | 4 | .. automodule:: partitura 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | :member-order: bysource 9 | -------------------------------------------------------------------------------- /docs/source/modules/partitura.score.rst: -------------------------------------------------------------------------------- 1 | partitura.score 2 | --------------- 3 | 4 | .. automodule:: partitura.score 5 | :member-order: bysource 6 | :members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/modules/partitura.utils.rst: -------------------------------------------------------------------------------- 1 | partitura.utils 2 | --------------- 3 | 4 | .. 5 | we need this import for `make doctest` to work. Without it, it will not find 6 | the names of members imported in partitura/utils/__init__.py 7 | 8 | .. testsetup:: * 9 | 10 | from partitura.utils import * 11 | 12 | .. automodule:: partitura.utils 13 | :members: 14 | -------------------------------------------------------------------------------- /partitura/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | The top level of the package contains functions to load and save 5 | data, display rendered scores, and functions to estimate pitch 6 | spelling, voice assignment, and key signature. 7 | """ 8 | 9 | import pkg_resources 10 | 11 | from .io import load_score, load_performance, load_score_as_part, lp 12 | from .io.musescore import load_via_musescore 13 | from .io.importmusicxml import load_musicxml, musicxml_to_notearray 14 | from .io.exportmusicxml import save_musicxml 15 | from .io.importmei import load_mei 16 | from .io.importkern import load_kern 17 | from .io.importmusic21 import load_music21 18 | from .io.importdcml import load_dcml 19 | from .io.importmidi import load_score_midi, load_performance_midi, midi_to_notearray 20 | from .io.exportmidi import save_score_midi, save_performance_midi 21 | from .io.importmatch import load_match 22 | from .io.exportmatch import save_match 23 | from .io.importnakamura import load_nakamuramatch, load_nakamuracorresp 24 | from .io.importparangonada import load_parangonada_csv 25 | from .io.exportparangonada import save_parangonada_csv, save_csv_for_parangonada 26 | from .io.exportaudio import save_wav, save_wav_fluidsynth 27 | from .io.exportmei import save_mei 28 | from .display import render 29 | from . import musicanalysis 30 | from .musicanalysis import make_note_features, compute_note_array, full_note_array 31 | 32 | 33 | # define a version variable 34 | __version__ = pkg_resources.get_distribution("partitura").version 35 | 36 | #: An example MusicXML file for didactic purposes 37 | EXAMPLE_MUSICXML = pkg_resources.resource_filename( 38 | "partitura", "assets/score_example.musicxml" 39 | ) 40 | 41 | EXAMPLE_MIDI = pkg_resources.resource_filename("partitura", "assets/score_example.mid") 42 | EXAMPLE_MEI = pkg_resources.resource_filename("partitura", "assets/score_example.mei") 43 | EXAMPLE_KERN = pkg_resources.resource_filename("partitura", "assets/score_example.krn") 44 | 45 | __all__ = [ 46 | "load_score", 47 | "load_score_as_part", 48 | "load_performance", 49 | "load_musicxml", 50 | "save_musicxml", 51 | "load_mei", 52 | "load_kern", 53 | "musicxml_to_notearray", 54 | "load_score_midi", 55 | "save_score_midi", 56 | "load_via_musescore", 57 | "load_performance_midi", 58 | "save_performance_midi", 59 | "load_match", 60 | "save_match", 61 | "load_dcml", 62 | "load_nakamuramatch", 63 | "load_nakamuracorresp", 64 | "load_parangonada_csv", 65 | "save_parangonada_csv", 66 | "save_wav", 67 | "save_wav_fluidsynth", 68 | "render", 69 | ] 70 | -------------------------------------------------------------------------------- /partitura/assets/partitura_logo_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/partitura/assets/partitura_logo_black.png -------------------------------------------------------------------------------- /partitura/assets/partitura_logo_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/partitura/assets/partitura_logo_white.png -------------------------------------------------------------------------------- /partitura/assets/score_example.krn: -------------------------------------------------------------------------------- 1 | **kern **kern 2 | *staff2 *staff1 3 | *clefG2 *clefG2 4 | *k[] *k[] 5 | *M4/4 *M4/4 6 | =1- =1- 7 | 1a 2r 8 | . 2cc 2ee 9 | =! =! 10 | *- *- 11 | -------------------------------------------------------------------------------- /partitura/assets/score_example.mei: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | <respStmt /> 10 | </titleStmt> 11 | <pubStmt xml:id="p1kxcrok"> 12 | <date isodate="2024-10-30" type="encoding-date">2024-10-30</date> 13 | </pubStmt> 14 | </fileDesc> 15 | <encodingDesc xml:id="e1xr2zpp"> 16 | <appInfo xml:id="a1wyxc5n"> 17 | <application xml:id="a1t43ge2" isodate="2024-10-30T10:56:32" version="4.3.1-3b8cc17"> 18 | <name xml:id="n1cp60l4">Verovio</name> 19 | <p xml:id="p13nndma">Transcoded from MusicXML</p> 20 | </application> 21 | </appInfo> 22 | </encodingDesc> 23 | </meiHead> 24 | <music> 25 | <body> 26 | <mdiv xml:id="muo97v6"> 27 | <score xml:id="suneqlv"> 28 | <scoreDef xml:id="sz00r05"> 29 | <staffGrp xml:id="s1h35kps"> 30 | <staffGrp xml:id="P1" bar.thru="true"> 31 | <grpSym xml:id="g1eji31e" symbol="brace" /> 32 | <label xml:id="l8lirjj">Piano</label> 33 | <instrDef xml:id="iggd40h" midi.channel="0" midi.instrnum="0" midi.volume="78.00%" /> 34 | <staffDef xml:id="sbpks8p" n="1" lines="5" ppq="1"> 35 | <clef xml:id="c1p7nrnw" shape="G" line="2" /> 36 | <keySig xml:id="ki5anqv" sig="0" /> 37 | <meterSig xml:id="m1vpw2w2" count="4" unit="4" /> 38 | </staffDef> 39 | <staffDef xml:id="s1g416nz" n="2" lines="5" ppq="1"> 40 | <clef xml:id="cezkswz" shape="G" line="2" /> 41 | <keySig xml:id="kk41xfz" sig="0" /> 42 | <meterSig xml:id="m7alo7s" count="4" unit="4" /> 43 | </staffDef> 44 | </staffGrp> 45 | </staffGrp> 46 | </scoreDef> 47 | <section xml:id="suu4o7p"> 48 | <measure xml:id="m1e358qx" n="1"> 49 | <staff xml:id="s1ufvigy" n="1"> 50 | <layer xml:id="l1r7cvga" n="1"> 51 | <rest xml:id="ro1o7cb" dur.ppq="2" dur="2" /> 52 | <chord xml:id="c1c1r6b7" dur.ppq="2" dur="2" stem.dir="down"> 53 | <note xml:id="n6dpu2p" oct="5" pname="c" /> 54 | <note xml:id="njfgcwp" oct="5" pname="e" /> 55 | </chord> 56 | </layer> 57 | </staff> 58 | <staff xml:id="s710zw2" n="2"> 59 | <layer xml:id="leffrs2" n="5"> 60 | <note xml:id="n1txt37q" dur.ppq="4" dur="1" oct="4" pname="a" /> 61 | </layer> 62 | </staff> 63 | </measure> 64 | </section> 65 | </score> 66 | </mdiv> 67 | </body> 68 | </music> 69 | </mei> 70 | -------------------------------------------------------------------------------- /partitura/assets/score_example.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/partitura/assets/score_example.mid -------------------------------------------------------------------------------- /partitura/assets/score_example.musicxml: -------------------------------------------------------------------------------- 1 | <?xml version='1.0' encoding='UTF-8'?> 2 | <!DOCTYPE score-partwise PUBLIC 3 | "-//Recordare//DTD MusicXML 3.1 Partwise//EN" 4 | "http://www.musicxml.org/dtds/partwise.dtd"> 5 | <score-partwise> 6 | <part-list> 7 | <score-part id="P1"> 8 | <part-name>Piano</part-name> 9 | </score-part> 10 | </part-list> 11 | <part id="P1"> 12 | <!--=======================================================--> 13 | <measure number="1"> 14 | <attributes> 15 | <divisions>12</divisions> 16 | <time> 17 | <beats>4</beats> 18 | <beat-type>4</beat-type> 19 | </time> 20 | </attributes> 21 | <print new-page="yes" new-system="yes"/> 22 | <note id="n01"> 23 | <pitch> 24 | <step>A</step> 25 | <octave>4</octave> 26 | </pitch> 27 | <duration>48</duration> 28 | <voice>1</voice> 29 | <type>whole</type> 30 | <staff>2</staff> 31 | </note> 32 | <backup> 33 | <duration>48</duration> 34 | </backup> 35 | <note id="r01"> 36 | <rest/> 37 | <duration>24</duration> 38 | <voice>2</voice> 39 | <type>half</type> 40 | <staff>1</staff> 41 | </note> 42 | <note id="n02"> 43 | <pitch> 44 | <step>C</step> 45 | <octave>5</octave> 46 | </pitch> 47 | <duration>24</duration> 48 | <voice>2</voice> 49 | <type>half</type> 50 | <staff>1</staff> 51 | </note> 52 | <note id="n03"> 53 | <chord/> 54 | <pitch> 55 | <step>E</step> 56 | <octave>5</octave> 57 | </pitch> 58 | <duration>24</duration> 59 | <voice>2</voice> 60 | <type>half</type> 61 | <staff>1</staff> 62 | </note> 63 | </measure> 64 | </part> 65 | </score-partwise> 66 | -------------------------------------------------------------------------------- /partitura/musicanalysis/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains tools for estimating key signature, time signature, 5 | pitch spelling, voice information, tonal tension, as well as methods for 6 | deriving note-level features and performance encodings. 7 | """ 8 | 9 | from .voice_separation import estimate_voices 10 | from .key_identification import estimate_key 11 | from .pitch_spelling import estimate_spelling 12 | from .tonal_tension import estimate_tonaltension 13 | from .meter import estimate_time 14 | from .note_features import ( 15 | list_note_feats_functions, 16 | make_note_features, 17 | make_note_feats, 18 | compute_note_array, 19 | full_note_array, 20 | make_rest_feats, 21 | make_rest_features, 22 | ) 23 | from .performance_codec import encode_performance, decode_performance 24 | from .performance_features import make_performance_features 25 | from .note_array_to_score import note_array_to_score 26 | 27 | 28 | __all__ = [ 29 | "estimate_voices", 30 | "estimate_key", 31 | "estimate_spelling", 32 | "estimate_tonaltension", 33 | "estimate_time", 34 | "list_note_feats_functions", 35 | "make_note_features", 36 | "make_rest_features", 37 | "encode_performance", 38 | "decode_performance", 39 | "compute_note_array", 40 | "full_note_array", 41 | "make_performance_features", 42 | "note_array_to_score", 43 | ] 44 | -------------------------------------------------------------------------------- /partitura/utils/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Top level of the utilities module. 5 | """ 6 | 7 | from partitura.utils.generic import ( 8 | ComparableMixin, 9 | ReplaceRefMixin, 10 | partition, 11 | iter_subclasses, 12 | iter_current_next, 13 | sorted_dict_items, 14 | PrettyPrintTree, 15 | find_nearest, 16 | add_field, 17 | show_diff, 18 | search, 19 | _OrderedSet, 20 | ) 21 | from partitura.utils.music import ( 22 | MIDI_BASE_CLASS, 23 | ALTER_SIGNS, 24 | find_tie_split, 25 | fifths_mode_to_key_name, 26 | key_name_to_fifths_mode, 27 | estimate_symbolic_duration, 28 | format_symbolic_duration, 29 | symbolic_to_numeric_duration, 30 | to_quarter_tempo, 31 | pitch_spelling_to_midi_pitch, 32 | estimate_clef_properties, 33 | ensure_pitch_spelling_format, 34 | ensure_notearray, 35 | compute_pianoroll, 36 | compute_pitch_class_pianoroll, 37 | pianoroll_to_notearray, 38 | match_note_arrays, 39 | key_mode_to_int, 40 | clef_sign_to_int, 41 | clef_int_to_sign, 42 | remove_silence_from_performed_part, 43 | note_array_from_part_list, 44 | slice_notearray_by_time, 45 | note_array_from_part, 46 | note_array_from_note_list, 47 | get_time_units_from_note_array, 48 | update_note_ids_after_unfolding, 49 | note_name_to_pitch_spelling, 50 | note_name_to_midi_pitch, 51 | pitch_spelling_to_note_name, 52 | rest_array_from_part, 53 | rest_array_from_rest_list, 54 | ensure_rest_array, 55 | rest_array_from_part_list, 56 | ) 57 | from partitura.utils.synth import synthesize 58 | 59 | from partitura.utils.misc import ( 60 | PathLike, 61 | get_document_name, 62 | deprecated_alias, 63 | deprecated_parameter, 64 | ) 65 | 66 | from partitura.utils.normalize import normalize 67 | 68 | __all__ = [ 69 | "ensure_notearray", 70 | "note_array_from_part", 71 | "ensure_rest_array", 72 | "compute_pianoroll", 73 | "compute_pitch_class_pianoroll", 74 | "pianoroll_to_notearray", 75 | "slice_notearray_by_time", 76 | "key_name_to_fifths_mode", 77 | "fifths_mode_to_key_name", 78 | "key_mode_to_int", 79 | "clef_sign_to_int", 80 | "clef_int_to_sign", 81 | "pitch_spelling_to_midi_pitch", 82 | "pitch_spelling_to_note_name", 83 | "show_diff", 84 | "PrettyPrintTree", 85 | "synthesize", 86 | "normalize", 87 | ] 88 | -------------------------------------------------------------------------------- /partitura/utils/normalize.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains normalization utilities 5 | """ 6 | import numpy as np 7 | from partitura.utils.globals import EPSILON 8 | 9 | 10 | def range_normalize( 11 | array, 12 | min_value=None, 13 | max_value=None, 14 | log=False, 15 | log2=False, 16 | exp=False, 17 | exp2=False, 18 | hard_clip=True, 19 | ): 20 | """ 21 | Linear mapping a vector from range [min_value, max_value] to [0, 1]. 22 | Preprocessing possible with log and exp. 23 | Values exceeding the range [0, 1] are clipped to 0 or 1 if 24 | clip is True, otherwise they are extrapolated. 25 | """ 26 | if min_value is None: 27 | min_value = array.min() 28 | if max_value is None: 29 | max_value = array.max() 30 | if log: 31 | array = np.log(np.abs(array) + EPSILON) 32 | elif log2: 33 | array = np.log2(np.abs(array) + EPSILON) 34 | if exp: 35 | array = np.exp(array) 36 | elif exp2: 37 | array = np.exp2(array) 38 | # handle div by zero 39 | if min_value == max_value: 40 | array = np.clip(array, 0, 1) 41 | else: 42 | array = (array - min_value) / (max_value - min_value) 43 | if hard_clip: 44 | return np.clip(array, 0, 1) 45 | else: 46 | return array 47 | 48 | 49 | def zero_one_normalize( 50 | array, min_value=-3.0, max_value=3.0, log=False, exp=False, clip=True 51 | ): 52 | """ 53 | Compute zero mean and unit variance of a vector. 54 | Preprocessing possible with log and exp. 55 | Values exceeding the range [-min_value, max_value] 56 | are clipped if clip is True. 57 | """ 58 | 59 | if log: 60 | array = np.log(np.abs(array) + EPSILON) 61 | if exp: 62 | array = np.exp(array) 63 | 64 | array = (array - array.mean()) / array.std() 65 | if clip: 66 | return np.clip(array, min_value, max_value) 67 | else: 68 | return array 69 | 70 | 71 | def minmaxrange_normalize(array): 72 | """ 73 | Linear mapping of a vector from range [array.min(), array.max()] to [0, 1]. 74 | Constant vector is clipped to [0, 1]. 75 | """ 76 | return range_normalize(array) 77 | 78 | 79 | DEFAULT_NORM_FUNCS = { 80 | "pitch": { 81 | "func": range_normalize, 82 | "kwargs": {"min_value": 0, "max_value": 127}, 83 | }, 84 | "velocity": { 85 | "func": range_normalize, 86 | "kwargs": {"min_value": 0, "max_value": 127}, 87 | }, 88 | "onset_beat": { 89 | "func": minmaxrange_normalize, 90 | "kwargs": {}, 91 | }, 92 | "duration_beat": { 93 | "func": range_normalize, 94 | "kwargs": {"min_value": -3, "max_value": 3, "log2": True}, 95 | # ref beat = 4th -> -3 = 32nd, 3 = breve 96 | }, 97 | "beat_period": { 98 | "func": range_normalize, 99 | "kwargs": {"min_value": -3, "max_value": 2, "log2": True}, 100 | # ref 1 second / beat -> -3 = 0.125 sec / beat , 2 = 4 sec / beat 101 | }, 102 | "timing": { 103 | "func": range_normalize, 104 | "kwargs": {"min_value": -0.2, "max_value": 0.2}, 105 | # deviation in seconds 106 | }, 107 | "articulation_log": { 108 | "func": range_normalize, 109 | "kwargs": {"min_value": -4, "max_value": 3}, 110 | # thia ia the ratio in base2 log -> just min max clip 111 | }, 112 | # fill up with all note and performance features 113 | } 114 | 115 | 116 | def normalize( 117 | in_array, 118 | norm_funcs=DEFAULT_NORM_FUNCS, 119 | norm_func_fallback=minmaxrange_normalize, 120 | default_value=np.inf, 121 | ): 122 | """ 123 | Normalize a note array. 124 | May include note features as well as performance features. 125 | All input columns must be of numeric types, everything is 126 | cast to single precision float. 127 | 128 | Parameters 129 | ---------- 130 | array : np.ndarray 131 | The performance array to be normalized. 132 | norm_funcs : dict 133 | A dictionary of normalization functions for each feature. 134 | 135 | Returns 136 | ------- 137 | array : np.ndarray 138 | The normalized performance array. 139 | """ 140 | dtype_new = np.dtype( 141 | { 142 | "names": in_array.dtype.names, 143 | "formats": [float for k in range(len(in_array.dtype.names))], 144 | } 145 | ) 146 | array = in_array.copy().astype(dtype_new) 147 | 148 | for feature in array.dtype.names: 149 | # use mask for non-default values and don't change default values 150 | non_default_mask = array[feature] != default_value 151 | 152 | # check whether the feature has non-uniform values 153 | if len(np.unique(array[feature][non_default_mask])) == 1: 154 | array[feature][non_default_mask] = 0.0 155 | else: 156 | # check whether a normalization function is defined for the feature 157 | if feature not in norm_funcs: 158 | array[feature][non_default_mask] = norm_func_fallback( 159 | array[feature][non_default_mask] 160 | ) 161 | else: 162 | array[feature][non_default_mask] = norm_funcs[feature]["func"]( 163 | array[feature][non_default_mask], **norm_funcs[feature]["kwargs"] 164 | ) 165 | 166 | return array 167 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | scipy 3 | xmlschema 4 | lxml 5 | lark-parser 6 | mido 7 | nbsphinx -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import io 5 | import os 6 | import sys 7 | from shutil import rmtree 8 | 9 | from setuptools import find_packages, setup, Command 10 | 11 | # Package meta-data. 12 | NAME = "partitura" 13 | DESCRIPTION = "A package for handling symbolic musical information" 14 | KEYWORDS = "music notation musicxml midi" 15 | URL = "https://github.com/CPJKU/partitura" 16 | EMAIL = "partitura-users@googlegroups.com" 17 | AUTHOR = "Maarten Grachten, Carlos Cancino-Chacón, Silvan Peter, Emmanouil Karystinaios, Francesco Foscarin, Thassilo Gadermaier, Patricia Hu" 18 | REQUIRES_PYTHON = ">=3.7" 19 | VERSION = "1.6.0" 20 | 21 | # What packages are required for this module to be executed? 22 | REQUIRED = ["numpy", "scipy", "lxml", "lark-parser", "xmlschema", "mido"] 23 | 24 | # What packages are optional? 25 | EXTRAS = {} 26 | 27 | here = os.path.abspath(os.path.dirname(__file__)) 28 | 29 | try: 30 | with io.open(os.path.join(here, "README.md"), encoding="utf-8") as f: 31 | long_description = "\n" + f.read() 32 | except FileNotFoundError: 33 | long_description = DESCRIPTION 34 | 35 | # Load the package's __version__.py module as a dictionary. 36 | about = {} 37 | if not VERSION: 38 | with open(os.path.join(here, NAME, "__version__.py")) as f: 39 | exec(f.read(), about) 40 | else: 41 | about["__version__"] = VERSION 42 | 43 | 44 | # Where the magic happens: 45 | setup( 46 | name=NAME, 47 | version=about["__version__"], 48 | description=DESCRIPTION, 49 | long_description=long_description, 50 | long_description_content_type="text/markdown", 51 | keywords=KEYWORDS, 52 | author=AUTHOR, 53 | author_email=EMAIL, 54 | python_requires=REQUIRES_PYTHON, 55 | url=URL, 56 | packages=find_packages(exclude=("tests",)), 57 | package_data={ 58 | "partitura": [ 59 | "assets/musicxml.xsd", 60 | "assets/score_example.mid", 61 | "assets/score_example.musicxml", 62 | "assets/score_example.krn", 63 | "assets/score_example.mei", 64 | ] 65 | }, 66 | install_requires=REQUIRED, 67 | extras_require=EXTRAS, 68 | include_package_data=True, 69 | license="Apache 2.0", 70 | classifiers=[ 71 | # Trove classifiers 72 | # Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers 73 | "License :: OSI Approved :: MIT License", 74 | "Programming Language :: Python", 75 | "Programming Language :: Python :: 3", 76 | "Programming Language :: Python :: Implementation :: CPython", 77 | "Programming Language :: Python :: Implementation :: PyPy", 78 | ], 79 | ) 80 | -------------------------------------------------------------------------------- /tests/data/kern/chor228.krn: -------------------------------------------------------------------------------- 1 | !!!!SEGMENT: chor228.krn 2 | !!!COM: Bach, Johann Sebastian 3 | !!!CDT: 1685/02/21/-1750/07/28/ 4 | !!!OTL@@DE: Danket dem Herren, denn er ist sehr freundlich 5 | !!!SCT: BWV 286 6 | !!!PC#: 228 7 | !!!AGN: chorale 8 | **kern **kern **kern **kern 9 | *ICvox *ICvox *ICvox *ICvox 10 | *IGrand *IGrand *IGrand *IGrand 11 | *Ibass *Itenor *Ialto *Isoprn 12 | *tb *tb *tb *tb 13 | *ITr *ITr *ITr *ITr 14 | *I"Bass *I"Tenor *I"Alto *I"Soprano 15 | *clefF *clefGv2 *clefG2 *clefG 16 | *k[] *k[] *k[] *k[] 17 | *a: *a: *a: *a: 18 | *M4/4 *M4/4 *M4/4 *M4/4 19 | *met(c) *met(c) *met(c) *met(c) 20 | *MM100 *MM100 *MM100 *MM100 21 | 4A 4c 4e 4a 22 | =1 =1 =1 =1 23 | 4.A 4e 4a 4cc 24 | . 4e [8b 4b 25 | 8G# . 8b_ . 26 | 8AL 4e 8bL] 4cc 27 | 8AAJ . [8aJ . 28 | 4BB [4d 8aL] 4dd 29 | . . 8gnXJ . 30 | =2 =2 =2 =2 31 | 8CL 8dL] 4g 4ee 32 | 8D 16cL . . 33 | . 16BJJ . . 34 | 8E 4c 4g 4ee 35 | 8FJ . . . 36 | 4GnX 4.B 8gL 4dd 37 | . . 8fJ . 38 | 4A . 4e 4cc 39 | . [8A . . 40 | =3 =3 =3 =3 41 | 2E 4A] 2e 2b 42 | . 8G#L . . 43 | . 8F#J . . 44 | 4EE; 4G#; 4e; 4b; 45 | 8EL 4G# 4e 4b 46 | 8DJ . . . 47 | =4 =4 =4 =4 48 | 4C 4A 4e 4ee 49 | 4C 4A 4f# 4dd 50 | 4BB 4B 4g# 4dd 51 | 4AA 8cL [4a 4cc 52 | . 8dJ . . 53 | =5 =5 =5 =5 54 | 4E 4e 8aL] 4b 55 | . . 8g#J . 56 | 8AnXL 4e [4a 4cc 57 | 8GnXJ . . . 58 | 4F 4d 8aL] 4dd 59 | . . 8g#J . 60 | 4E 4e 4a 4cc 61 | =6 =6 =6 =6 62 | 4D 4f 4.a 4b 63 | 4E 8.eL . 4b 64 | . . 8g# . 65 | . 16dJk . . 66 | 4AA; 4c#; 4e; 4a; 67 | == == == == 68 | *- *- *- *- 69 | !!!hum2abc: -Q '' 70 | !!!title: @{PC#}. @{OTL@@DE} 71 | !!!YOR1: 371 vierstimmige Choralgesänge von Johann Sebastian Bach, 72 | !!!YOR2: 4th ed. by Alfred Dörffel (Leipzig: Breitkopf und Härtel, 73 | !!!YOR2: c.1875). 178 pp. Plate "V.A.10". reprint: J.S. Bach, 371 Four-Part 74 | !!!YOR4: Chorales (New York: Associated Music Publishers, Inc., c.1940). 75 | !!!SMS: B&H, 4th ed, Alfred Dörffel, c.1875, plate V.A.10 76 | !!!EED: Craig Stuart Sapp 77 | !!!EEV: 2009/05/22 78 | -------------------------------------------------------------------------------- /tests/data/kern/double_repeat_example.krn: -------------------------------------------------------------------------------- 1 | **kern **kern **kern **kern 2 | *staff2 *staff2 *staff1 *staff1 3 | *clefF4 *clefF4 *clefG2 *clefG2 4 | *k[f#c#g#] *k[f#c#g#] *k[f#c#g#] *k[f#c#g#] 5 | *M4/4 *M4/4 *M4/4 *M4/4 6 | 4AA 4c# 4a 4ee 7 | =1 =1 =1 =1 8 | 8AL 4c# 4a 4ee 9 | 8BJ . . . 10 | 8c#L 4c# 4a 4ee 11 | 8AJ . . . 12 | 8DL 4d 4a 4ff# 13 | 8EJ . . . 14 | 8F#L 4d 4a 4ff# 15 | 8DJ . . . 16 | =2 =2 =2 =2 17 | 2A; 2c#; 2a; 2ee; 18 | 4r 4r 4r 4r 19 | 4A 4e 4a 4cc# 20 | =3 =3 =3 =3 21 | 4G# 4e 4b 4dd 22 | 4A 4e 4a 4cc# 23 | 8EL 4e 4g# 4b 24 | 8DJ . . . 25 | 8C#L 4e [4a 8.cc#L 26 | 8AAJ . . . 27 | . . . 16ddJ 28 | =4 =4 =4 =4 29 | 2E 8eL 8a]L 2b 30 | . 16d 8f#J . 31 | . 16c#J . . 32 | . 4d 4g# . 33 | 4AA; 4c#; 4e; 4a; 34 | =:|! =:| =:| =:|! 35 | *- *- *- *- 36 | -------------------------------------------------------------------------------- /tests/data/kern/fine_with_repeat.krn: -------------------------------------------------------------------------------- 1 | **kern **kern **kern 2 | *staff2 *staff2 *staff1 3 | *clefG2 *clefG2 *clefG2 4 | *k[] *k[] *k[] 5 | *M3/4 *M3/4 *M3/4 6 | =1- =1- =1- 7 | 4r 4r [4ee 8 | 4c 4g 8.ee]L 9 | . . 16ffJk 10 | 4f 4g 8.ddL 11 | . . 16eeJk 12 | =2 =2 =2 13 | 4e 4g 4cc 14 | 4r 4r 4gg 15 | 4r 4r 4gg 16 | =3 =3 =3 17 | (2B ([2.g (8ggL 18 | . . 8ff)J 19 | . . (8ffL 20 | . . 8ee)J 21 | 4c . (8eeL 22 | . . 8dd)J 23 | =4 =4 =4 24 | 4G) 4g]) 4dd 25 | 4r 4r 4b 26 | 4r 4r 4g 27 | =5 =5 =5 28 | 4r 4r [4ee 29 | 4c 4g 8.ee]L 30 | . . 16ffJk 31 | 4f 4g 8.ddL 32 | . . 16eeJk 33 | =6 =6 =6 34 | 4e 4g 4cc 35 | 4r 4r 4ccc 36 | 4E 4c 4ccc 37 | =7 =7 =7 38 | 4f 4c 16gg#LL 39 | . . 16aaJJ 40 | . . 8r 41 | 4r 4r 16eeLL 42 | . . 16ffJJ 43 | . . 8r 44 | 4Gn 4f 16ddLL 45 | . . 16bJJ 46 | . . 8r 47 | =8 =8 =8 48 | 4c 4e 4cc 49 | 4r 4r 4r 50 | 4r 4r 4r 51 | =:|! =:|! =:|! 52 | *- *- *- 53 | -------------------------------------------------------------------------------- /tests/data/kern/long_example.krn: -------------------------------------------------------------------------------- 1 | **kern **kern **kern **kern 2 | *staff2 *staff2 *staff1 *staff1 3 | *clefF4 *clefF4 *clefG2 *clefG2 4 | *k[f#c#g#] *k[f#c#g#] *k[f#c#g#] *k[f#c#g#] 5 | *M4/4 *M4/4 *M4/4 *M4/4 6 | 4AA 4c# 4a 4ee 7 | =1 =1 =1 =1 8 | 8AL 4c# 4a 4ee 9 | 8BJ . . . 10 | 8c#L 4c# 4a 4ee 11 | 8AJ . . . 12 | 8DL 4d 4a 4ff# 13 | 8EJ . . . 14 | 8F#L 4d 4a 4ff# 15 | 8DJ . . . 16 | =2 =2 =2 =2 17 | 2A; 2c#; 2a; 2ee; 18 | 4r 4r 4r 4r 19 | 4A 4e 4a 4cc# 20 | =3 =3 =3 =3 21 | 4G# 4e 4b 4dd 22 | 4A 4e 4a 4cc# 23 | 8EL 4e 4g# 4b 24 | 8DJ . . . 25 | 8C#L 4e [4a 8.cc#L 26 | 8AAJ . . . 27 | . . . 16ddJ 28 | =4 =4 =4 =4 29 | 2E 8eL 8a]L 2b 30 | . 16d 8f#J . 31 | . 16c#J . . 32 | . 4d 4g# . 33 | 4AA; 4c#; 4e; 4a; 34 | =:|! =:| =:| =:|! 35 | *- *- *- *- 36 | -------------------------------------------------------------------------------- /tests/data/kern/single_voice_example.krn: -------------------------------------------------------------------------------- 1 | **kern 2 | *clefG2 3 | *k[b-] 4 | *d: 5 | *M2/2 6 | *met(c) 7 | =1- 8 | 2d 9 | 2a 10 | =2 11 | 2f 12 | 2d 13 | =3 14 | 2c# 15 | 4d 16 | 4e 17 | =4 18 | [2f 19 | 8f]L 20 | 8g 21 | 8f 22 | 8eJ 23 | =5 24 | 4d 25 | *- 26 | -------------------------------------------------------------------------------- /tests/data/kern/spline_splitting.krn: -------------------------------------------------------------------------------- 1 | **kern **kern **kern **kern 2 | *staff2 *staff2 *staff1 *staff1 3 | *clefF4 *clefF4 *clefG2 *clefG2 4 | *k[f#c#g#] *k[f#c#g#] *k[f#c#g#] *k[f#c#g#] 5 | *M4/4 *M4/4 *M4/4 *M4/4 6 | 4AA 4c# 4a 4ee 7 | =1 =1 =1 =1 8 | * * * *^ 9 | 8AL 4c# 4a 4ee 8eee 10 | 8BJ . . . 8eee 11 | 8c#L 4c# 4a 4ee 8ee 12 | 8AJ . . . . 13 | 8DL 4d 4a 4ff# 8fff# 14 | 8EJ . . . 8fff# 15 | 8F#L 4d 4a 4ff# 4fff# 16 | 8DJ . . . . 17 | =2 =2 =2 =2 =2 18 | * * * *v *v 19 | 2A; 2c#; 2a; 2ee; 20 | 4r 4r 4r 4r 21 | 4A 4e 4a 4cc# 22 | =3 =3 =3 =3 23 | 4G# 4e 4b 4dd 24 | 4A 4e 4a 4cc# 25 | 8EL 4e 4g# 4b 26 | 8DJ . . . 27 | 8C#L 4e [4a 8.cc#L 28 | 8AAJ . . . 29 | . . . 16ddJ 30 | =4 =4 =4 =4 31 | *^ * * * 32 | 2.EE 2E 8eL 8a]L 2b 33 | . . 16d 8f#J . 34 | . . 16c#J . . 35 | . . 4d 4g# . 36 | . 4AA; 4c#; 4e; 4a; 37 | =:|! =:|! =:| =:| =:|! 38 | *v *v * * * 39 | *- *- *- *- -------------------------------------------------------------------------------- /tests/data/kern/tie_mismatch.krn: -------------------------------------------------------------------------------- 1 | **kern 2 | *clefF4 3 | *k[f#c#g#] 4 | *A: 5 | *M3/4 6 | =1- 7 | [8dd 8 | [8aa 9 | 8aa] 10 | [8dd 11 | 8dd] 12 | [8aa 13 | =2 14 | 4aa 15 | 4aa] 16 | [8aa 17 | 8r 18 | == 19 | -------------------------------------------------------------------------------- /tests/data/kern/tuple_durations.krn: -------------------------------------------------------------------------------- 1 | **kern 2 | *clefG2 3 | *k[f#c#g#d#] 4 | *M3/4 5 | =1 6 | (8f#L 7 | 8e#J 8 | 4en) 9 | (36d#L 10 | 36e# 11 | 36c# 12 | 36a 13 | 36f## 14 | 36g# 15 | 36dd# 16 | 36aa 17 | 36cc#J 18 | =2 19 | 8b~L 20 | 8a#~J 21 | 4an) 22 | (20gg#L 23 | 20ff# 24 | 20dd# 25 | 20cc# 26 | 20aJ 27 | =3 28 | 8g#)L 29 | (40b 30 | 40a# 31 | 40an 32 | 40e 33 | 40dd#J 34 | 8g#)L 35 | (40b 36 | 40a# 37 | 40an 38 | 40e 39 | 40dd#J 40 | 16g#) 41 | =- 42 | *- -------------------------------------------------------------------------------- /tests/data/kern/variable_length_pr_bug.krn: -------------------------------------------------------------------------------- 1 | !!!!SEGMENT: chor057.krn 2 | !!!COM: Bach, Johann Sebastian 3 | !!!CDT: 1685/02/21/-1750/07/28/ 4 | !!!OTL@@DE: O Traurigkeit, o Herzeleid 5 | !!!SCT: BWV 404 6 | !!!PC#: 57 7 | !!!AGN: chorale 8 | **kern **kern **kern **kern 9 | *ICvox *ICvox *ICvox *ICvox 10 | *Ibass *Itenor *Ialto *Isoprn 11 | *I"Bass *I"Tenor *I"Alto *I"Soprano 12 | *clefF4 *clefGv2 *clefG2 *clefG2 13 | *k[] *k[] *k[] *k[] 14 | *a: *a: *a: *a: 15 | *M4/4 *M4/4 *M4/4 *M4/4 16 | *met(c) *met(c) *met(c) *met(c) 17 | *MM100 *MM100 *MM100 *MM100 18 | 4E 4B 4g# 4ee 19 | =1 =1 =1 =1 20 | 4A 8AL 4e 8ccL 21 | . 8G#J . 8bJ 22 | 4AA 4F# 8eL 4cc 23 | . . 8d#J . 24 | 4E; 4G#; 4e; 4b; 25 | 4DnX 4B 4e 4g# 26 | =2 =2 =2 =2 27 | 4C 4c 4e 4a 28 | 4FnX 8BL 4dnX 4a 29 | . 8AJ . . 30 | 4E; 4B; 4e; 4g#; 31 | 4E 4B 4g#X 4ee 32 | =3 =3 =3 =3 33 | 4A 4c 4a 4ee 34 | 4G# 4B 4b 4ee 35 | 8AL 8cL 4a 4ff 36 | 8BJ 8dJ . . 37 | 4c 8eL 4gnX 8eeL 38 | . 8cJ . 8ddJ 39 | =4 =4 =4 =4 40 | 4F# 4c 4a 2dd 41 | 4GnX 4B 8gL . 42 | . . 8fnXJ . 43 | 2C; 2c; 2e; 2cc; 44 | =5 =5 =5 =5 45 | 4G 4d 4g 4b 46 | 4A 4c 8fL 4cc 47 | . . 8eJ . 48 | 4B 4g 8dL 4dd 49 | . . 8ddJ . 50 | 4c 8GL 4cc 4ee 51 | . 8AJ . . 52 | =6 =6 =6 =6 53 | 4G# 8BL 4b 4dd 54 | . 8EJ . . 55 | 4A 4e 4a 4cc 56 | 2E; 2e; 2g#; 2b; 57 | =7 =7 =7 =7 58 | 4F# (8eL 4e 4a 59 | . 8dJ) . . 60 | 4G# (8dL 4e 4b 61 | . 8cJ) . . 62 | 8AL (8cL 4e 4cc 63 | 8GJ 8BJ) . . 64 | 8FL 4A 8aL 8ddL 65 | 8EJ . 8gnXJ 8eeJ 66 | =8 =8 =8 =8 67 | 4D 4A 4f 2b 68 | 4E 4G# 8eL . 69 | . . 8dJ . 70 | 2AA; 2E; 2c; 2a; 71 | == == == == 72 | *- *- *- *- 73 | !!!hum2abc: -Q '' 74 | !!!title: @{PC#}. @{OTL@@DE} 75 | !!!YOR1: 371 vierstimmige Choralgesänge von Johann Sebastian Bach, 76 | !!!YOR2: 4th ed. by Alfred Dörffel (Leipzig: Breitkopf und Härtel, 77 | !!!YOR2: c.1875). 178 pp. Plate "V.A.10". reprint: J.S. Bach, 371 Four-Part 78 | !!!YOR4: Chorales (New York: Associated Music Publishers, Inc., c.1940). 79 | !!!SMS: B&H, 4th ed, Alfred Dörffel, c.1875, plate V.A.10 80 | !!!EED: Craig Stuart Sapp 81 | !!!EEV: 2020/09/05 82 | -------------------------------------------------------------------------------- /tests/data/kern/voice_duplication.krn: -------------------------------------------------------------------------------- 1 | **kern **kern **kern **kern 2 | *staff2 *staff2 *staff1 *staff1 3 | *clefF4 *clefF4 *clefG2 *clefG2 4 | *k[f#c#] *k[f#c#] *k[f#c#] *k[f#c#] 5 | *M4/4 *M4/4 *M4/4 *M4/4 6 | *b: *b: *b: *b: 7 | *MM58 *MM58 *MM58 *MM58 8 | =1- =1- =1- =1- 9 | [1F# 16A#L 8r 2dd 10 | . 16F# . . 11 | . 16G# 8f# . 12 | . 16A#J . . 13 | . 16BL 8dL . 14 | . 16c# . . 15 | . 16d 8BJ . 16 | . [16BJ . . 17 | . 16B]L 8gL [2cc# 18 | . 16B . . 19 | . 16A# 8f#J . 20 | . 16BJ . . 21 | . 16c#L 8bL . 22 | . 16d . . 23 | . 16e 8a#J . 24 | . 16c#J . . 25 | =2 =2 =2 =2 26 | *^ * * * 27 | 2r 16F#]L 8eL 4f# 4cc#] 28 | . 16AA# . . . 29 | . 16BB 8d#J . . 30 | . 16C#J . . . 31 | . 16D#L 8r 8r 16ccnL 32 | . 16E . . 16a# 33 | . 16FF# 8dn 8g# [8bJ 34 | . 16EE#J . . . 35 | 16r 2FF# 2c# 8f#L 4b] 36 | 16BBL . . . . 37 | 16C# . . 8e#J . 38 | 16DnJ . . . . 39 | 16EnL . . 8.f#L 4a# 40 | 16C# . . . . 41 | [8F#J . . . . 42 | . . . 16enJ . 43 | =76 =76 =76 =76 =76 44 | 1F#] 1BB 1B 1d# 1b 45 | *v *v * * * 46 | == == == == 47 | *- *- *- *- -------------------------------------------------------------------------------- /tests/data/mei/test_barline.mei: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <?xml-model href="https://music-encoding.org/schema/dev/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?> 3 | <?xml-model href="https://music-encoding.org/schema/dev/mei-all.rng" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?> 4 | <mei xmlns="http://www.music-encoding.org/ns/mei" meiversion="5.0.0-dev"> 5 | <meiHead> 6 | <fileDesc> 7 | <titleStmt> 8 | <title /> 9 | <respStmt /> 10 | </titleStmt> 11 | <pubStmt><date isodate="2022-03-16" type="encoding-date">2022-03-16</date> 12 | </pubStmt> 13 | </fileDesc> 14 | <encodingDesc xml:id="encodingdesc-nwr474"> 15 | <appInfo xml:id="appinfo-l9fj2o"> 16 | <application xml:id="application-gea1h6" isodate="2022-03-16T15:39:30" version="3.10.0-dev-6906e9c"> 17 | <name xml:id="name-5qas7q">Verovio</name> 18 | <p xml:id="p-xs5c6s">Transcoded from MusicXML</p> 19 | </application> 20 | </appInfo> 21 | </encodingDesc> 22 | </meiHead> 23 | <music> 24 | <body> 25 | <mdiv xml:id="meq4bro"> 26 | <score xml:id="s1ryeev"> 27 | <scoreDef xml:id="smkhiuo"> 28 | <staffGrp xml:id="s8bb54n"> 29 | <staffGrp xml:id="s9out50"> 30 | <grpSym xml:id="gq3hgh3" symbol="brace" /> 31 | <staffDef xml:id="P1" n="1" lines="5" ppq="1"> 32 | <label xml:id="lx844l7">Piano</label> 33 | <labelAbbr xml:id="l1p4bcx">Pno.</labelAbbr> 34 | <instrDef xml:id="igsvdhz" midi.channel="0" midi.instrnum="0" midi.volume="78.00%" /> 35 | <clef xml:id="c9rdcys" shape="G" line="2" /> 36 | <keySig xml:id="kf0sp4k" sig="2s" /> 37 | <meterSig xml:id="mr0t342" count="4" unit="4" /> 38 | </staffDef> 39 | </staffGrp> 40 | </staffGrp> 41 | </scoreDef> 42 | <section xml:id="sx3xhif"> 43 | <measure xml:id="myo1876" left="rptstart" n="1"> 44 | <staff xml:id="szf4d4f" n="1"> 45 | <layer xml:id="lrchciy" n="1"> 46 | <note xml:id="n8s1i0z" dur.ppq="4" dur="1" oct="4" pname="c" accid.ges="s" /> 47 | </layer> 48 | </staff> 49 | </measure> 50 | <measure xml:id="msecoq9" right="rptend" n="2"> 51 | <staff xml:id="sp806wm" n="1"> 52 | <layer xml:id="lrvmhji" n="1"> 53 | <note xml:id="nq4y7gc" dur.ppq="4" dur="1" oct="4" pname="e" /> 54 | </layer> 55 | </staff> 56 | </measure> 57 | <measure xml:id="mz9jm53" left="rptstart" n="3"> 58 | <staff xml:id="shaimxc" n="1"> 59 | <layer xml:id="l5btv7b" n="1"> 60 | <note xml:id="nan14mj" dur.ppq="4" dur="1" oct="4" pname="g" /> 61 | </layer> 62 | </staff> 63 | </measure> 64 | <measure xml:id="moovni5" right="rptend" n="4"> 65 | <staff xml:id="s8qut5v" n="1"> 66 | <layer xml:id="lknp5mm" n="1"> 67 | <note xml:id="nz63t36" dur.ppq="4" dur="1" oct="4" pname="e" /> 68 | </layer> 69 | </staff> 70 | </measure> 71 | <measure xml:id="m8cvcd6" right="dbl" n="5"> 72 | <staff xml:id="smy8bwq" n="1"> 73 | <layer xml:id="l7lhn9j" n="1"> 74 | <note xml:id="nnz9mah" dur.ppq="4" dur="1" oct="4" pname="d" /> 75 | </layer> 76 | </staff> 77 | </measure> 78 | <measure xml:id="myoy5vr" right="dashed" n="6"> 79 | <staff xml:id="sxk3npg" n="1"> 80 | <layer xml:id="ljtxja9" n="1"> 81 | <note xml:id="njxby98" dur.ppq="4" dur="1" oct="3" pname="a" /> 82 | </layer> 83 | </staff> 84 | </measure> 85 | <measure xml:id="mn4q40z" right="end" n="7"> 86 | <staff xml:id="s4baxfy" n="1"> 87 | <layer xml:id="l6p7ppt" n="1"> 88 | <mRest xml:id="m33jahz" /> 89 | </layer> 90 | </staff> 91 | </measure> 92 | </section> 93 | </score> 94 | </mdiv> 95 | </body> 96 | </music> 97 | </mei> 98 | -------------------------------------------------------------------------------- /tests/data/mei/test_divs_tuplet.mei: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <?xml-model href="https://music-encoding.org/schema/dev/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?> 3 | <?xml-model href="https://music-encoding.org/schema/dev/mei-all.rng" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?> 4 | <mei xmlns="http://www.music-encoding.org/ns/mei" meiversion="5.0.0-dev"> 5 | <meiHead xml:id="m51tjwc"> 6 | <fileDesc xml:id="f10kxtxa"> 7 | <titleStmt xml:id="t1tqease"> 8 | <title>Untitled score 9 | 10 | Composer / arranger 11 | 12 | 13 | 14 | 2023-08-02 15 | 16 | 17 | 18 | 19 | 20 | Verovio 21 |

Transcoded from MusicXML

22 |
23 |
24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | Picc. 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 |
63 |
64 |
65 | 66 |
67 |
68 | -------------------------------------------------------------------------------- /tests/data/mei/test_grace_note.mei: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | test grace note 9 | 10 | 11 | 2021-11-04 12 | 13 | 14 | 15 | 16 | 17 | Verovio 18 |

Transcoded from MusicXML

19 |
20 |
21 |
22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 | test grace note 30 | 31 | 32 | 33 | 34 | 35 | 36 | Pno. 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 |
72 |
73 |
74 | 75 |
76 |
77 | -------------------------------------------------------------------------------- /tests/data/mei/test_ties.mei: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | Title 9 | 10 | Composer 11 | 12 | 13 | 2021-11-03 14 | 15 | 16 | 17 | 18 | 19 | Verovio 20 |

Transcoded from MusicXML

21 |
22 |
23 |
24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 | Title 32 | Composer 33 | 34 | 35 | 36 | 37 | Pno. 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 |
77 |
78 |
79 | 80 |
81 |
82 | -------------------------------------------------------------------------------- /tests/data/mei/test_tuplets.mei: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | test tuplets 9 | 10 | 11 | 2021-11-02 12 | 13 | 14 | 15 | 16 | 17 | Verovio 18 |

Transcoded from MusicXML

19 |
20 |
21 |
22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 | test tuplets 30 | 31 | 32 | 33 | 34 | 35 | 36 | Pno. 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 |
79 |
80 |
81 | 82 |
83 |
84 | -------------------------------------------------------------------------------- /tests/data/mei/test_tuplets_no_ppq.mei: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | test tuplets 9 | 10 | 11 | 2021-11-02 12 | 13 | 14 | 15 | 16 | 17 | Verovio 18 |

Transcoded from MusicXML

19 |
20 |
21 |
22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 | test tuplets 30 | 31 | 32 | 33 | 34 | 35 | 36 | Pno. 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 |
79 |
80 |
81 | 82 |
83 |
84 | -------------------------------------------------------------------------------- /tests/data/mei/test_unfold_timeline.mei: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | <respStmt /> 10 | </titleStmt> 11 | <pubStmt></pubStmt> 12 | </fileDesc> 13 | <encodingDesc xml:id="encodingdesc-y2c7j"> 14 | <appInfo xml:id="appinfo-wzmtx5"> 15 | <application xml:id="application-z4xw2w" isodate="2022-03-16T12:54:39" version="3.10.0-dev-6906e9c"> 16 | <name xml:id="name-thqlez">Verovio</name> 17 | <p xml:id="p-ufdb4t">Transcoded from MusicXML</p> 18 | </application> 19 | </appInfo> 20 | </encodingDesc> 21 | </meiHead> 22 | <music> 23 | <body> 24 | <mdiv xml:id="mwou5cs"> 25 | <score xml:id="syt006x"> 26 | <scoreDef xml:id="s7nmhte"> 27 | <staffGrp xml:id="suluxoj"> 28 | <staffDef xml:id="P1" n="1" lines="5" ppq="10"> 29 | <label xml:id="l7tehg7">MusicXML Part</label> 30 | <meterSig xml:id="m586s60" count="2" unit="4" /> 31 | </staffDef> 32 | </staffGrp> 33 | </scoreDef> 34 | <sb xml:id="sel67qt" /> 35 | <section xml:id="s99r22y"> 36 | <pb xml:id="pb1wqhm" /> 37 | <measure xml:id="md9oz1h" left="rptstart" right="rptend" n="1"> 38 | <staff xml:id="sjh2lpn" n="1"> 39 | <layer xml:id="lcsnmqx" n="1"> 40 | <rest xml:id="rgto4y" dur.ppq="10" dur="4" /> 41 | <chord xml:id="c5vpint" dur.ppq="10" dur="4"> 42 | <note xml:id="n01" oct="4" pname="a" /> 43 | <note xml:id="n02" oct="3" pname="a" /> 44 | </chord> 45 | </layer> 46 | </staff> 47 | <fermata xml:id="fvi9pcn" staff="1" startid="#c5vpint" /> 48 | <fermata xml:id="fsnizse" staff="1" tstamp="3.000000" /> 49 | </measure> 50 | </section> 51 | </score> 52 | </mdiv> 53 | </body> 54 | </music> 55 | </mei> 56 | -------------------------------------------------------------------------------- /tests/data/midi/bach_midi_score.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/tests/data/midi/bach_midi_score.mid -------------------------------------------------------------------------------- /tests/data/midi/mozart_k265_var1.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/tests/data/midi/mozart_k265_var1.mid -------------------------------------------------------------------------------- /tests/data/midi/mozart_k265_var1_quantized.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/tests/data/midi/mozart_k265_var1_quantized.mid -------------------------------------------------------------------------------- /tests/data/midi/test_anacrusis.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/tests/data/midi/test_anacrusis.mid -------------------------------------------------------------------------------- /tests/data/midi/test_basic_midi.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/tests/data/midi/test_basic_midi.mid -------------------------------------------------------------------------------- /tests/data/musicxml/example_octave_shift.musicxml: -------------------------------------------------------------------------------- 1 | <?xml version='1.0' encoding='UTF-8'?> 2 | <!DOCTYPE score-partwise PUBLIC 3 | "-//Recordare//DTD MusicXML 3.1 Partwise//EN" 4 | "http://www.musicxml.org/dtds/partwise.dtd"> 5 | <score-partwise> 6 | <part-list> 7 | <score-part id="P1"> 8 | <part-name>Piano</part-name> 9 | </score-part> 10 | </part-list> 11 | <part id="P1"> 12 | <!--=======================================================--> 13 | <measure number="1"> 14 | <attributes> 15 | <divisions>12</divisions> 16 | <time> 17 | <beats>4</beats> 18 | <beat-type>4</beat-type> 19 | </time> 20 | </attributes> 21 | <print new-page="yes" new-system="yes"/> 22 | <direction placement="above"> 23 | <direction-type> 24 | <octave-shift type="down" size="8" number="1"/> 25 | </direction-type> 26 | <staff>1</staff> 27 | </direction> 28 | <note id="n01"> 29 | <pitch> 30 | <step>A</step> 31 | <octave>4</octave> 32 | </pitch> 33 | <duration>48</duration> 34 | <voice>1</voice> 35 | <type>whole</type> 36 | <staff>2</staff> 37 | </note> 38 | <backup> 39 | <duration>48</duration> 40 | </backup> 41 | <note id="r01"> 42 | <rest/> 43 | <duration>24</duration> 44 | <voice>2</voice> 45 | <type>half</type> 46 | <staff>1</staff> 47 | </note> 48 | <note id="n02"> 49 | <pitch> 50 | <step>C</step> 51 | <octave>5</octave> 52 | </pitch> 53 | <duration>24</duration> 54 | <voice>2</voice> 55 | <type>half</type> 56 | <staff>1</staff> 57 | </note> 58 | <note id="n03"> 59 | <chord/> 60 | <pitch> 61 | <step>E</step> 62 | <octave>5</octave> 63 | </pitch> 64 | <duration>24</duration> 65 | <voice>2</voice> 66 | <type>half</type> 67 | <staff>1</staff> 68 | </note> 69 | <direction placement="above"> 70 | <direction-type> 71 | <octave-shift type="stop" size="8" number="1"/> 72 | </direction-type> 73 | <staff>1</staff> 74 | </direction> 75 | </measure> 76 | </part> 77 | </score-partwise> 78 | -------------------------------------------------------------------------------- /tests/data/musicxml/test_harmony.musicxml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 4.0 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd"> 3 | <score-partwise version="4.0"> 4 | <work> 5 | <work-title>Untitled score</work-title> 6 | </work> 7 | <identification> 8 | <creator type="composer">Composer / arranger</creator> 9 | <encoding> 10 | <software>MuseScore 4.0.1</software> 11 | <encoding-date>2023-05-10</encoding-date> 12 | <supports element="accidental" type="yes"/> 13 | <supports element="beam" type="yes"/> 14 | <supports element="print" attribute="new-page" type="no"/> 15 | <supports element="print" attribute="new-system" type="no"/> 16 | <supports element="stem" type="yes"/> 17 | </encoding> 18 | </identification> 19 | <part-list> 20 | <score-part id="P1"> 21 | <part-name>Flute</part-name> 22 | <part-abbreviation>Fl.</part-abbreviation> 23 | <score-instrument id="P1-I1"> 24 | <instrument-name>Flute</instrument-name> 25 | </score-instrument> 26 | <midi-device id="P1-I1" port="1"></midi-device> 27 | <midi-instrument id="P1-I1"> 28 | <midi-channel>1</midi-channel> 29 | <midi-program>74</midi-program> 30 | <volume>78.7402</volume> 31 | <pan>0</pan> 32 | </midi-instrument> 33 | </score-part> 34 | </part-list> 35 | <part id="P1"> 36 | <measure number="1"> 37 | <attributes> 38 | <divisions>1</divisions> 39 | <key> 40 | <fifths>0</fifths> 41 | </key> 42 | <time> 43 | <beats>4</beats> 44 | <beat-type>4</beat-type> 45 | </time> 46 | <clef> 47 | <sign>G</sign> 48 | <line>2</line> 49 | </clef> 50 | </attributes> 51 | <harmony print-frame="no"> 52 | <root> 53 | <root-step>C</root-step> 54 | </root> 55 | <kind text="m">minor</kind> 56 | </harmony> 57 | <harmony print-frame="no"> 58 | <function>i</function> 59 | <kind text="">none</kind> 60 | </harmony> 61 | <note> 62 | <pitch> 63 | <step>G</step> 64 | <octave>4</octave> 65 | </pitch> 66 | <duration>2</duration> 67 | <voice>1</voice> 68 | <type>half</type> 69 | <stem>up</stem> 70 | </note> 71 | <harmony print-frame="no"> 72 | <root> 73 | <root-step>G</root-step> 74 | </root> 75 | <kind text="7">dominant</kind> 76 | </harmony> 77 | <harmony print-frame="no"> 78 | <function>V7</function> 79 | <kind text="">none</kind> 80 | </harmony> 81 | <note> 82 | <pitch> 83 | <step>G</step> 84 | <octave>4</octave> 85 | </pitch> 86 | <duration>2</duration> 87 | <voice>1</voice> 88 | <type>half</type> 89 | <stem>up</stem> 90 | </note> 91 | <barline location="right"> 92 | <bar-style>light-heavy</bar-style> 93 | </barline> 94 | </measure> 95 | </part> 96 | </score-partwise> 97 | -------------------------------------------------------------------------------- /tests/data/musicxml/test_note_ties.xml: -------------------------------------------------------------------------------- 1 | <?xml version='1.0' encoding='UTF-8'?> 2 | <!DOCTYPE score-partwise PUBLIC 3 | "-//Recordare//DTD MusicXML 3.1 Partwise//EN" 4 | "http://www.musicxml.org/dtds/partwise.dtd"> 5 | <score-partwise> 6 | <part-list> 7 | <score-part id="P1"> 8 | <part-name>MüsicXML Part</part-name> 9 | </score-part> 10 | </part-list> 11 | <part id="P1"> 12 | <!--=======================================================--> 13 | <measure number="1"> 14 | <attributes> 15 | <divisions>10</divisions> 16 | <time> 17 | <beats>2</beats> 18 | <beat-type>4</beat-type> 19 | </time> 20 | </attributes> 21 | <print new-page="yes" new-system="yes"/> 22 | <note id="n01"> 23 | <pitch> 24 | <step>A</step> 25 | <octave>4</octave> 26 | </pitch> 27 | <duration>15</duration> 28 | <tie type="start"/> 29 | <voice>1</voice> 30 | <stem>up</stem> 31 | <type>quarter</type> 32 | <dot/> 33 | <notations> 34 | <tied type="start"/> 35 | </notations> 36 | </note> 37 | <attributes> 38 | <time> 39 | <beats>4</beats> 40 | <beat-type>4</beat-type> 41 | </time> 42 | </attributes> 43 | <note id="n02"> 44 | <pitch> 45 | <step>A</step> 46 | <octave>4</octave> 47 | </pitch> 48 | <duration>5</duration> 49 | <tie type="stop"/> 50 | <tie type="start"/> 51 | <voice>1</voice> 52 | <type>eighth</type> 53 | <notations> 54 | <tied type="stop"/> 55 | <tied type="start"/> 56 | </notations> 57 | </note> 58 | <backup> 59 | <duration>20</duration> 60 | </backup> 61 | <note id="n03"> 62 | <pitch> 63 | <step>B</step> 64 | <octave>4</octave> 65 | </pitch> 66 | <duration>20</duration> 67 | <voice>2</voice> 68 | <type>half</type> 69 | </note> 70 | </measure> 71 | <!--=======================================================--> 72 | <measure number="2"> 73 | <note id="n04"> 74 | <pitch> 75 | <step>A</step> 76 | <octave>4</octave> 77 | </pitch> 78 | <duration>10</duration> 79 | <tie type="stop"/> 80 | <voice>1</voice> 81 | <type>quarter</type> 82 | <notations> 83 | <tied type="stop"/> 84 | </notations> 85 | </note> 86 | <note id="n05"> 87 | <unpitched> 88 | <display-step>B</display-step> 89 | <display-octave>3</display-octave> 90 | </unpitched> 91 | <notehead filled="no">diamond</notehead> 92 | <duration>10</duration> 93 | <voice>1</voice> 94 | <type>quarter</type> 95 | </note> 96 | </measure> 97 | </part> 98 | </score-partwise> 99 | -------------------------------------------------------------------------------- /tests/data/musicxml/test_note_ties_divs.xml: -------------------------------------------------------------------------------- 1 | <?xml version='1.0' encoding='UTF-8'?> 2 | <!DOCTYPE score-partwise PUBLIC 3 | "-//Recordare//DTD MusicXML 3.1 Partwise//EN" 4 | "http://www.musicxml.org/dtds/partwise.dtd"> 5 | <score-partwise> 6 | <part-list> 7 | <score-part id="P1"> 8 | <part-name>MusicXML Part</part-name> 9 | </score-part> 10 | </part-list> 11 | <part id="P1"> 12 | <!--=======================================================--> 13 | <measure number="1"> 14 | <attributes> 15 | <divisions>10</divisions> 16 | <time> 17 | <beats>2</beats> 18 | <beat-type>4</beat-type> 19 | </time> 20 | </attributes> 21 | <print new-page="yes" new-system="yes"/> 22 | <note id="n01"> 23 | <pitch> 24 | <step>A</step> 25 | <octave>4</octave> 26 | </pitch> 27 | <duration>15</duration> 28 | <tie type="start"/> 29 | <voice>1</voice> 30 | <type>quarter</type> 31 | <dot/> 32 | <notations> 33 | <tied type="start"/> 34 | </notations> 35 | </note> 36 | <backup> 37 | <duration>15</duration> 38 | </backup> 39 | <note id="v01"> 40 | <pitch> 41 | <step>A</step> 42 | <octave>3</octave> 43 | </pitch> 44 | <duration>15</duration> 45 | <voice>2</voice> 46 | <type>quarter</type> 47 | <dot/> 48 | </note> 49 | <attributes> 50 | <divisions>20</divisions> 51 | </attributes> 52 | <note id="n02"> 53 | <pitch> 54 | <step>A</step> 55 | <octave>4</octave> 56 | </pitch> 57 | <duration>10</duration> 58 | <tie type="stop"/> 59 | <tie type="start"/> 60 | <voice>1</voice> 61 | <type>eighth</type> 62 | <notations> 63 | <tied type="stop"/> 64 | <tied type="start"/> 65 | </notations> 66 | </note> 67 | <backup> 68 | <duration>10</duration> 69 | </backup> 70 | <note id="v02"> 71 | <rest/> 72 | <duration>10</duration> 73 | <voice>2</voice> 74 | <type>eighth</type> 75 | </note> 76 | </measure> 77 | <!--=======================================================--> 78 | <measure number="2"> 79 | <note id="n03"> 80 | <pitch> 81 | <step>A</step> 82 | <octave>4</octave> 83 | </pitch> 84 | <duration>20</duration> 85 | <tie type="stop"/> 86 | <voice>1</voice> 87 | <type>quarter</type> 88 | <notations> 89 | <tied type="stop"/> 90 | </notations> 91 | </note> 92 | </measure> 93 | </part> 94 | </score-partwise> 95 | -------------------------------------------------------------------------------- /tests/data/musicxml/test_partial_measures.xml: -------------------------------------------------------------------------------- 1 | <?xml version='1.0' encoding='UTF-8'?> 2 | <!DOCTYPE score-partwise PUBLIC 3 | "-//Recordare//DTD MusicXML 3.1 Partwise//EN" 4 | "http://www.musicxml.org/dtds/partwise.dtd"> 5 | <score-partwise> 6 | <part-list> 7 | <score-part id="P1"> 8 | <part-name>MusicXML Part</part-name> 9 | </score-part> 10 | </part-list> 11 | <part id="P1"> 12 | <!--=======================================================--> 13 | <measure number="1"> 14 | <attributes> 15 | <divisions>1</divisions> 16 | <key> 17 | <fifths>0</fifths> 18 | </key> 19 | <time> 20 | <beats>4</beats> 21 | <beat-type>4</beat-type> 22 | </time> 23 | <staves>1</staves> 24 | <clef> 25 | <sign>G</sign> 26 | <line>2</line> 27 | </clef> 28 | </attributes> 29 | <note id='n1'> 30 | <pitch> 31 | <step>C</step> 32 | <octave>4</octave> 33 | </pitch> 34 | <duration>2</duration> 35 | <voice>1</voice> 36 | <type>half</type> 37 | </note> 38 | <note id='n2'> 39 | <pitch> 40 | <step>C</step> 41 | <octave>4</octave> 42 | </pitch> 43 | <duration>2</duration> 44 | <voice>1</voice> 45 | <type>half</type> 46 | </note> 47 | </measure> 48 | <!--=======================================================--> 49 | <measure number="2"> 50 | <note id='n3'> 51 | <pitch> 52 | <step>D</step> 53 | <octave>4</octave> 54 | </pitch> 55 | <duration>1</duration> 56 | <voice>1</voice> 57 | <type>quarter</type> 58 | </note> 59 | <note id='n4'> 60 | <pitch> 61 | <step>E</step> 62 | <octave>4</octave> 63 | </pitch> 64 | <duration>1</duration> 65 | <voice>1</voice> 66 | <type>quarter</type> 67 | </note> 68 | </measure> 69 | <!--=======================================================--> 70 | <measure number="3"> 71 | <barline location="left"> 72 | <ending number="1" type="start" default-y="116.70"/> 73 | </barline> 74 | <note id='n5'> 75 | <pitch> 76 | <step>F</step> 77 | <octave>4</octave> 78 | </pitch> 79 | <duration>2</duration> 80 | <voice>1</voice> 81 | <type>half</type> 82 | </note> 83 | <barline location="right"> 84 | <bar-style>light-heavy</bar-style> 85 | <ending number="1" type="stop"/> 86 | <repeat direction="backward"/> 87 | </barline> 88 | </measure> 89 | <!--=======================================================--> 90 | <measure number="X1"> 91 | <barline location="left"> 92 | <ending number="2" type="start" default-y="110.10"/> 93 | </barline> 94 | <note id='n6'> 95 | <pitch> 96 | <step>G</step> 97 | <octave>4</octave> 98 | </pitch> 99 | <duration>4</duration> 100 | <voice>1</voice> 101 | <type>whole</type> 102 | </note> 103 | <barline location="right"> 104 | <ending number="2" type="stop"/> 105 | </barline> 106 | </measure> 107 | <!--=======================================================--> 108 | <measure number="4"> 109 | <note id='n7'> 110 | <pitch> 111 | <step>A</step> 112 | <octave>4</octave> 113 | </pitch> 114 | <duration>2</duration> 115 | <voice>1</voice> 116 | <type>half</type> 117 | </note> 118 | </measure> 119 | <!--=======================================================--> 120 | <measure number="X2"> 121 | <note id='n8'> 122 | <pitch> 123 | <step>B</step> 124 | <alter>-1</alter> 125 | <octave>4</octave> 126 | </pitch> 127 | <duration>1</duration> 128 | <voice>1</voice> 129 | <type>quarter</type> 130 | </note> 131 | </measure> 132 | <!--=======================================================--> 133 | <measure number="5"> 134 | <note id='n9'> 135 | <pitch> 136 | <step>F</step> 137 | <octave>4</octave> 138 | </pitch> 139 | <duration>2</duration> 140 | <voice>1</voice> 141 | <type>half</type> 142 | </note> 143 | <barline location="right"> 144 | <bar-style>light-heavy</bar-style> 145 | </barline> 146 | </measure> 147 | </part> 148 | </score-partwise> 149 | -------------------------------------------------------------------------------- /tests/data/musicxml/test_partial_measures_consecutive.xml: -------------------------------------------------------------------------------- 1 | <?xml version='1.0' encoding='UTF-8'?> 2 | <!DOCTYPE score-partwise PUBLIC 3 | "-//Recordare//DTD MusicXML 3.1 Partwise//EN" 4 | "http://www.musicxml.org/dtds/partwise.dtd"> 5 | <score-partwise> 6 | <part-list> 7 | <score-part id="P1"> 8 | <part-name>MusicXML Part</part-name> 9 | </score-part> 10 | </part-list> 11 | <part id="P1"> 12 | <!--=======================================================--> 13 | <measure number="1"> 14 | <attributes> 15 | <divisions>1</divisions> 16 | <key> 17 | <fifths>0</fifths> 18 | </key> 19 | <time> 20 | <beats>4</beats> 21 | <beat-type>4</beat-type> 22 | </time> 23 | <staves>1</staves> 24 | <clef> 25 | <sign>G</sign> 26 | <line>2</line> 27 | </clef> 28 | </attributes> 29 | <note id='n1'> 30 | <pitch> 31 | <step>C</step> 32 | <octave>4</octave> 33 | </pitch> 34 | <duration>2</duration> 35 | <voice>1</voice> 36 | <type>half</type> 37 | </note> 38 | <note id='n2'> 39 | <pitch> 40 | <step>C</step> 41 | <octave>4</octave> 42 | </pitch> 43 | <duration>2</duration> 44 | <voice>1</voice> 45 | <type>half</type> 46 | </note> 47 | </measure> 48 | <!--=======================================================--> 49 | <measure number="2"> 50 | <note id='n3'> 51 | <pitch> 52 | <step>D</step> 53 | <octave>4</octave> 54 | </pitch> 55 | <duration>1</duration> 56 | <voice>1</voice> 57 | <type>half</type> 58 | </note> 59 | <note id='n4'> 60 | <pitch> 61 | <step>E</step> 62 | <octave>4</octave> 63 | </pitch> 64 | <duration>1</duration> 65 | <voice>1</voice> 66 | <type>half</type> 67 | </note> 68 | </measure> 69 | <!--=======================================================--> 70 | <measure number="3"> 71 | <note id='n5'> 72 | <pitch> 73 | <step>F</step> 74 | <octave>4</octave> 75 | </pitch> 76 | <duration>2</duration> 77 | <voice>1</voice> 78 | <type>whole</type> 79 | </note> 80 | </measure> 81 | <!--=======================================================--> 82 | <measure number="X1"> 83 | <note id='n6'> 84 | <pitch> 85 | <step>G</step> 86 | <octave>4</octave> 87 | </pitch> 88 | <duration>4</duration> 89 | <voice>1</voice> 90 | <type>half</type> 91 | </note> 92 | </measure> 93 | <!--=======================================================--> 94 | <measure number="X2"> 95 | <note id='n7'> 96 | <pitch> 97 | <step>A</step> 98 | <octave>4</octave> 99 | </pitch> 100 | <duration>2</duration> 101 | <voice>1</voice> 102 | <type>half</type> 103 | </note> 104 | </measure> 105 | <!--=======================================================--> 106 | <measure number="X3"> 107 | <note id='n8'> 108 | <pitch> 109 | <step>B</step> 110 | <alter>-1</alter> 111 | <octave>4</octave> 112 | </pitch> 113 | <duration>1</duration> 114 | <voice>1</voice> 115 | <type>quarter</type> 116 | </note> 117 | </measure> 118 | <!--=======================================================--> 119 | <measure number="4"> 120 | <note id='n9'> 121 | <pitch> 122 | <step>F</step> 123 | <octave>4</octave> 124 | </pitch> 125 | <duration>2</duration> 126 | <voice>1</voice> 127 | <type>whole</type> 128 | </note> 129 | <barline location="right"> 130 | <bar-style>light-heavy</bar-style> 131 | </barline> 132 | </measure> 133 | </part> 134 | </score-partwise> 135 | -------------------------------------------------------------------------------- /tests/data/musicxml/test_unfold_timeline.xml: -------------------------------------------------------------------------------- 1 | <?xml version='1.0' encoding='UTF-8'?> 2 | <!DOCTYPE score-partwise PUBLIC 3 | "-//Recordare//DTD MusicXML 3.1 Partwise//EN" 4 | "http://www.musicxml.org/dtds/partwise.dtd"> 5 | <score-partwise> 6 | <part-list> 7 | <score-part id="P1"> 8 | <part-name>MusicXML Part</part-name> 9 | </score-part> 10 | </part-list> 11 | <part id="P1"> 12 | <!--=======================================================--> 13 | <measure number="1"> 14 | <barline location="left"> 15 | <repeat direction="forward"/> 16 | </barline> 17 | <attributes> 18 | <divisions>10</divisions> 19 | <time> 20 | <beats>2</beats> 21 | <beat-type>4</beat-type> 22 | </time> 23 | </attributes> 24 | <print new-page="yes" new-system="yes"/> 25 | <note> 26 | <rest/> 27 | <duration>10</duration> 28 | <voice>1</voice> 29 | <type>quarter</type> 30 | </note> 31 | <note id="n01"> 32 | <pitch> 33 | <step>A</step> 34 | <octave>4</octave> 35 | </pitch> 36 | <duration>10</duration> 37 | <voice>1</voice> 38 | <type>quarter</type> 39 | <notations> 40 | <fermata/> 41 | </notations> 42 | </note> 43 | <note id="n02"> 44 | <chord/> 45 | <pitch> 46 | <step>A</step> 47 | <octave>3</octave> 48 | </pitch> 49 | <duration>10</duration> 50 | <voice>1</voice> 51 | <type>quarter</type> 52 | </note> 53 | <barline location="right"> 54 | <fermata/> 55 | <repeat direction="backward"/> 56 | </barline> 57 | </measure> 58 | </part> 59 | </score-partwise> 60 | -------------------------------------------------------------------------------- /tests/data/musicxml/test_unfold_timeline_result.xml: -------------------------------------------------------------------------------- 1 | <?xml version='1.0' encoding='UTF-8'?> 2 | <!DOCTYPE score-partwise PUBLIC 3 | "-//Recordare//DTD MusicXML 3.1 Partwise//EN" 4 | "http://www.musicxml.org/dtds/partwise.dtd"> 5 | <score-partwise> 6 | <part-list> 7 | <score-part id="P1"> 8 | <part-name>MusicXML Part</part-name> 9 | </score-part> 10 | </part-list> 11 | <part id="P1"> 12 | <!--=======================================================--> 13 | <measure number="1"> 14 | <attributes> 15 | <divisions>10</divisions> 16 | <time> 17 | <beats>2</beats> 18 | <beat-type>4</beat-type> 19 | </time> 20 | </attributes> 21 | <note> 22 | <rest/> 23 | <duration>10</duration> 24 | <voice>1</voice> 25 | <type>quarter</type> 26 | </note> 27 | <note id="n01"> 28 | <pitch> 29 | <step>A</step> 30 | <octave>4</octave> 31 | </pitch> 32 | <duration>10</duration> 33 | <voice>1</voice> 34 | <type>quarter</type> 35 | <notations> 36 | <fermata/> 37 | </notations> 38 | </note> 39 | <note id="n02"> 40 | <chord/> 41 | <pitch> 42 | <step>A</step> 43 | <octave>3</octave> 44 | </pitch> 45 | <duration>10</duration> 46 | <voice>1</voice> 47 | <type>quarter</type> 48 | </note> 49 | <barline location="right"> 50 | <fermata/> 51 | </barline> 52 | </measure> 53 | <!--=======================================================--> 54 | <measure number="1"> 55 | <barline location="left"> 56 | <fermata/> 57 | </barline> 58 | <note> 59 | <rest/> 60 | <duration>10</duration> 61 | <voice>1</voice> 62 | <type>quarter</type> 63 | </note> 64 | <note id="n01_2"> 65 | <pitch> 66 | <step>A</step> 67 | <octave>4</octave> 68 | </pitch> 69 | <duration>10</duration> 70 | <voice>1</voice> 71 | <type>quarter</type> 72 | <notations> 73 | <fermata/> 74 | </notations> 75 | </note> 76 | <note id="n02_2"> 77 | <chord/> 78 | <pitch> 79 | <step>A</step> 80 | <octave>3</octave> 81 | </pitch> 82 | <duration>10</duration> 83 | <voice>1</voice> 84 | <type>quarter</type> 85 | </note> 86 | <barline location="right"> 87 | <fermata/> 88 | </barline> 89 | </measure> 90 | </part> 91 | </score-partwise> 92 | -------------------------------------------------------------------------------- /tests/data/musicxml/test_unfold_timeline_result_updated_ids.xml: -------------------------------------------------------------------------------- 1 | <?xml version='1.0' encoding='UTF-8'?> 2 | <!DOCTYPE score-partwise PUBLIC 3 | "-//Recordare//DTD MusicXML 3.1 Partwise//EN" 4 | "http://www.musicxml.org/dtds/partwise.dtd"> 5 | <score-partwise> 6 | <part-list> 7 | <score-part id="P1"> 8 | <part-name>MusicXML Part</part-name> 9 | </score-part> 10 | </part-list> 11 | <part id="P1"> 12 | <!--=======================================================--> 13 | <measure number="1"> 14 | <attributes> 15 | <divisions>10</divisions> 16 | <time> 17 | <beats>2</beats> 18 | <beat-type>4</beat-type> 19 | </time> 20 | </attributes> 21 | <note> 22 | <rest/> 23 | <duration>10</duration> 24 | <voice>1</voice> 25 | <type>quarter</type> 26 | </note> 27 | <note id="n01-1"> 28 | <pitch> 29 | <step>A</step> 30 | <octave>4</octave> 31 | </pitch> 32 | <duration>10</duration> 33 | <voice>1</voice> 34 | <type>quarter</type> 35 | <notations> 36 | <fermata/> 37 | </notations> 38 | </note> 39 | <note id="n02-1"> 40 | <chord/> 41 | <pitch> 42 | <step>A</step> 43 | <octave>3</octave> 44 | </pitch> 45 | <duration>10</duration> 46 | <voice>1</voice> 47 | <type>quarter</type> 48 | </note> 49 | <barline location="right"> 50 | <fermata/> 51 | </barline> 52 | </measure> 53 | <!--=======================================================--> 54 | <measure number="1"> 55 | <barline location="left"> 56 | <fermata/> 57 | </barline> 58 | <note> 59 | <rest/> 60 | <duration>10</duration> 61 | <voice>1</voice> 62 | <type>quarter</type> 63 | </note> 64 | <note id="n01-2"> 65 | <pitch> 66 | <step>A</step> 67 | <octave>4</octave> 68 | </pitch> 69 | <duration>10</duration> 70 | <voice>1</voice> 71 | <type>quarter</type> 72 | <notations> 73 | <fermata/> 74 | </notations> 75 | </note> 76 | <note id="n02-2"> 77 | <chord/> 78 | <pitch> 79 | <step>A</step> 80 | <octave>3</octave> 81 | </pitch> 82 | <duration>10</duration> 83 | <voice>1</voice> 84 | <type>quarter</type> 85 | </note> 86 | <barline location="right"> 87 | <fermata/> 88 | </barline> 89 | </measure> 90 | </part> 91 | </score-partwise> 92 | -------------------------------------------------------------------------------- /tests/data/musicxml/test_unfold_volta_numbers.xml: -------------------------------------------------------------------------------- 1 | <?xml version='1.0' encoding='UTF-8'?> 2 | <!DOCTYPE score-partwise PUBLIC 3 | "-//Recordare//DTD MusicXML 3.1 Partwise//EN" 4 | "http://www.musicxml.org/dtds/partwise.dtd"> 5 | <score-partwise> 6 | <part-list> 7 | <score-part id="P1"> 8 | <part-name>MusicXML Part</part-name> 9 | </score-part> 10 | </part-list> 11 | <part id="P1"> 12 | <measure number="1" width="365.85"> 13 | <attributes> 14 | <divisions>1</divisions> 15 | <key> 16 | <fifths>0</fifths> 17 | </key> 18 | <time> 19 | <beats>4</beats> 20 | <beat-type>4</beat-type> 21 | </time> 22 | <clef> 23 | <sign>G</sign> 24 | <line>2</line> 25 | </clef> 26 | </attributes> 27 | <note default-x="77.22" default-y="-50.00"> 28 | <pitch> 29 | <step>C</step> 30 | <octave>4</octave> 31 | </pitch> 32 | <duration>4</duration> 33 | <voice>1</voice> 34 | <type>whole</type> 35 | </note> 36 | <barline location="right"> 37 | <bar-style>light-heavy</bar-style> 38 | <repeat direction="backward"/> 39 | </barline> 40 | </measure> 41 | <measure number="2" width="176.75"> 42 | <note default-x="13.00" default-y="-45.00"> 43 | <pitch> 44 | <step>D</step> 45 | <octave>4</octave> 46 | </pitch> 47 | <duration>1</duration> 48 | <voice>1</voice> 49 | <type>quarter</type> 50 | <stem>up</stem> 51 | </note> 52 | <note default-x="94.88" default-y="-40.00"> 53 | <pitch> 54 | <step>E</step> 55 | <octave>4</octave> 56 | </pitch> 57 | <duration>1</duration> 58 | <voice>1</voice> 59 | <type>quarter</type> 60 | <stem>up</stem> 61 | </note> 62 | </measure> 63 | <measure number="3" width="180.90"> 64 | <barline location="left"> 65 | <bar-style>heavy-light</bar-style> 66 | <repeat direction="forward"/> 67 | </barline> 68 | <note default-x="31.85" default-y="-35.00"> 69 | <pitch> 70 | <step>F</step> 71 | <octave>4</octave> 72 | </pitch> 73 | <duration>2</duration> 74 | <voice>1</voice> 75 | <type>half</type> 76 | <stem>up</stem> 77 | </note> 78 | </measure> 79 | <measure number="4" width="288.91"> 80 | <note default-x="13.00" default-y="-30.00"> 81 | <pitch> 82 | <step>G</step> 83 | <octave>4</octave> 84 | </pitch> 85 | <duration>4</duration> 86 | <voice>1</voice> 87 | <type>whole</type> 88 | </note> 89 | </measure> 90 | <measure number="5" width="151.15"> 91 | <barline location="left"> 92 | <ending number="1, 4, 5" type="start" default-y="67.41"/> 93 | </barline> 94 | <note default-x="58.59" default-y="-25.00"> 95 | <pitch> 96 | <step>A</step> 97 | <octave>4</octave> 98 | </pitch> 99 | <duration>2</duration> 100 | <voice>1</voice> 101 | <type>half</type> 102 | <stem>up</stem> 103 | </note> 104 | <barline location="right"> 105 | <bar-style>light-heavy</bar-style> 106 | <ending number="1, 4, 5" type="stop"/> 107 | <repeat direction="backward"/> 108 | </barline> 109 | </measure> 110 | <measure number="6" width="152.22"> 111 | <barline location="left"> 112 | <ending number="2" type="start" default-y="67.41"/> 113 | </barline> 114 | <note> 115 | <rest/> 116 | <duration>2</duration> 117 | <voice>1</voice> 118 | <type>half</type> 119 | </note> 120 | <note default-x="81.71" default-y="-20.00"> 121 | <pitch> 122 | <step>B</step> 123 | <octave>4</octave> 124 | </pitch> 125 | <duration>2</duration> 126 | <voice>1</voice> 127 | <type>half</type> 128 | <stem>up</stem> 129 | </note> 130 | </measure> 131 | <measure number="7" width="151.27"> 132 | <note> 133 | <rest measure="yes"/> 134 | <duration>4</duration> 135 | <voice>1</voice> 136 | </note> 137 | <barline location="right"> 138 | <bar-style>light-heavy</bar-style> 139 | <ending number="2" type="stop"/> 140 | <repeat direction="backward"/> 141 | </barline> 142 | </measure> 143 | <measure number="8" width="146.15"> 144 | <barline location="left"> 145 | <ending number="3" type="start" default-y="67.41"/> 146 | </barline> 147 | <note default-x="13.96" default-y="-15.00"> 148 | <pitch> 149 | <step>C</step> 150 | <octave>5</octave> 151 | </pitch> 152 | <duration>4</duration> 153 | <voice>1</voice> 154 | <type>whole</type> 155 | </note> 156 | <barline location="right"> 157 | <bar-style>light-heavy</bar-style> 158 | <ending number="3" type="stop"/> 159 | <repeat direction="backward"/> 160 | </barline> 161 | </measure> 162 | </part> 163 | </score-partwise> -------------------------------------------------------------------------------- /tests/data/nakamura/Shi05_infer_corresp.txt: -------------------------------------------------------------------------------- 1 | 0 2.70299 C4 60 36 0 0.25 C4 60 80 2 | 1 3.29915 D4 62 51 1 0.5 D4 62 80 3 | 2 3.90919 E4 64 54 2 0.75 E4 64 80 4 | 3 4.56838 F4 65 57 3 1 F4 65 80 5 | 4 5.59082 G4 67 44 4 1.375 G4 67 80 6 | 5 5.73077 F4 65 54 5 1.4375 F4 65 80 7 | 6 5.86646 E4 64 53 6 1.5 E4 64 80 8 | 7 6.4936 A4 69 61 7 1.75 A4 69 80 9 | 8 7.12714 D4 62 47 8 2 D4 62 80 10 | 9 7.79274 G4 67 51 9 2.25 G4 67 80 11 | 10 8.85257 A4 69 42 10 2.625 A4 69 80 12 | 11 9.13783 G4 67 41 11 2.75 G4 67 80 13 | 12 9.41774 F4 65 44 12 2.875 F4 65 80 14 | 13 9.70086 E4 64 41 13 3 E4 64 80 15 | 14 9.9733 F4 65 50 14 3.125 F4 65 80 16 | 15 10.2436 G4 67 57 15 3.25 G4 67 80 17 | 16 10.2724 E4 64 36 16 3.25 E4 64 80 18 | 17 10.5716 D4 62 45 17 3.375 D4 62 80 19 | 18 10.828 A4 69 65 18 3.5 A4 69 80 -------------------------------------------------------------------------------- /tests/data/nakamura/Shi05_infer_match.txt: -------------------------------------------------------------------------------- 1 | //Version: ScorePerfmMatch_v170104 2 | // Score: ./score_hmm.txt 3 | // Perfm: ./infer_spr.txt 4 | // fmt3x: ./score_fmt3x.txt 5 | 0 2.70299 3.55129 C4 36 35 0 0 250 P1-1-0 0 0 6 | 1 3.29915 4.03312 D4 51 59 0 0 500 P1-1-1 0 - 7 | 2 3.90919 4.65812 E4 54 46 0 0 750 P1-1-2 0 - 8 | 3 4.56838 5.58013 F4 57 37 0 0 1000 P1-1-3 0 - 9 | 4 5.59082 6.03206 G4 44 38 0 0 1375 P1-1-4 0 - 10 | 5 5.73077 6.06945 F4 54 37 0 0 1437 P1-1-5 0 - 11 | 6 5.86646 6.71902 E4 53 41 0 0 1500 P1-1-6 0 - 12 | 7 6.4936 7.21048 A4 61 56 0 0 1750 P1-1-7 0 - 13 | 8 7.12714 8.01924 D4 47 55 0 0 2000 P1-1-8 0 - 14 | 9 7.79274 8.90279 G4 51 56 0 0 2250 P1-1-9 0 - 15 | 10 8.85257 9.19445 A4 42 46 0 0 2625 P1-1-10 0 - 16 | 11 9.13783 9.50856 G4 41 36 0 0 2750 P1-1-11 0 - 17 | 12 9.41774 9.66881 F4 44 50 0 0 2875 P1-1-12 0 - 18 | 13 9.70086 9.97864 E4 41 61 0 0 3000 P1-1-13 0 - 19 | 14 9.9733 10.4113 F4 50 39 0 0 3125 P1-1-14 0 - 20 | 15 10.2436 10.9626 G4 57 52 0 0 3250 P1-1-15 0 - 21 | 16 10.2724 10.7201 E4 36 30 0 0 3250 P1-1-16 0 - 22 | 17 10.5716 10.8654 D4 45 54 0 0 3375 P1-1-17 0 - 23 | 18 10.828 11.484 A4 65 60 0 0 3500 P1-1-18 0 - -------------------------------------------------------------------------------- /tests/data/nakamura/test_nakamura_performance_corresp.txt: -------------------------------------------------------------------------------- 1 | // alignID alignOntime alignSitch alignPitch alignOnvel refID refOntime refSitch refPitch refOnvel 2 | 0 0.000000 E5 76 64 0 0.000000 E5 76 64 3 | 1 0.000000 G4 67 64 1 0.000000 G4 67 64 4 | 2 0.000000 C4 60 64 2 0.000000 C4 60 64 5 | 3 0.000000 C3 48 64 3 0.000000 C3 48 64 6 | 4 0.500000 F5 77 64 4 0.500000 F5 77 64 7 | 5 1.000000 G5 79 64 5 1.000000 G5 79 64 8 | 6 1.000000 A4 69 64 6 1.000000 A4 69 64 9 | 7 1.000000 C4 60 64 7 1.000000 C4 60 64 10 | 8 1.000000 F3 53 64 8 1.000000 F3 53 64 11 | 9 2.000000 G5 79 64 10 2.000000 G5 79 64 12 | 10 2.000000 G4 67 64 11 2.000000 G4 67 64 13 | 11 2.000000 C4 60 64 12 2.000000 C4 60 64 14 | 12 2.000000 E3 52 64 13 2.000000 E3 52 64 15 | 13 2.500000 E5 76 64 14 2.500000 E5 76 64 16 | 14 3.000000 F5 77 64 15 3.000000 F5 77 64 17 | 15 3.000000 A4 69 64 16 3.000000 A4 69 64 18 | 16 3.000000 D4 62 64 17 3.000000 D4 62 64 19 | 17 3.000000 D3 50 64 18 3.000000 D3 50 64 20 | 18 3.250000 E5 76 64 * -1 * -1 -1 21 | 19 3.500000 D5 74 64 19 3.500000 D5 74 64 22 | 20 4.000000 E5 76 64 20 4.000000 E5 76 64 23 | 21 4.000000 G4 67 64 21 4.000000 G4 67 64 24 | 22 4.000000 C4 60 64 22 4.000000 C4 60 64 25 | 23 4.000000 G3 55 64 23 4.000000 G3 55 64 26 | 24 4.500000 D5 74 64 24 4.500000 D5 74 64 27 | 25 5.000000 C5 72 64 25 5.000000 C5 72 64 28 | 26 5.000000 F4 65 64 26 5.000000 F4 65 64 29 | 27 5.000000 B3 59 64 27 5.000000 B3 59 64 30 | 28 5.000000 G2 43 64 28 5.000000 G2 43 64 31 | 29 5.500000 D5 74 64 29 5.500000 D5 74 64 32 | 30 6.000000 C5 72 64 30 6.000000 C5 72 64 33 | 31 6.000000 E4 64 64 31 6.000000 E4 64 64 34 | 32 6.000000 C4 60 64 32 6.000000 C4 60 64 35 | 33 6.000000 C3 48 64 33 6.000000 C3 48 64 36 | * -1 * -1 -1 9 1.500000 F5 77 64 37 | -------------------------------------------------------------------------------- /tests/data/nakamura/test_nakamura_performance_match.txt: -------------------------------------------------------------------------------- 1 | //Version: ScorePerfmMatch_v170503 2 | // Score: ./test_nakamura_score_hmm.txt 3 | // Perfm: ./test_nakamura_performance_spr.txt 4 | // fmt3x: ./test_nakamura_score_fmt3x.txt 5 | 0 0.000000 0.500000 E5 64 64 1 0 0 P1-1-0 0 0 6 | 1 0.000000 1.000000 G4 64 64 2 0 0 P1-1-1 0 - 7 | 2 0.000000 1.000000 C4 64 64 3 0 0 P1-1-2 0 - 8 | 3 0.000000 1.000000 C3 64 64 4 0 0 P1-1-3 0 - 9 | 4 0.500000 1.000000 F5 64 64 1 0 500 P1-1-4 0 - 10 | 5 1.000000 1.500000 G5 64 64 1 0 1000 P1-1-5 0 - 11 | 6 1.000000 2.000000 A4 64 64 2 0 1000 P1-1-6 0 - 12 | 7 1.000000 2.000000 C4 64 64 3 0 1000 P1-1-7 0 - 13 | 8 1.000000 2.000000 F3 64 64 4 0 1000 P1-1-8 0 - 14 | 9 2.000000 2.500000 G5 64 64 1 0 2000 P1-1-10 0 - 15 | 10 2.000000 3.000000 G4 64 64 2 0 2000 P1-1-11 0 - 16 | 11 2.000000 3.000000 C4 64 64 3 0 2000 P1-1-12 0 - 17 | 12 2.000000 3.000000 E3 64 64 4 0 2000 P1-1-13 0 - 18 | 13 2.500000 3.000000 E5 64 64 1 0 2500 P1-1-14 0 - 19 | 14 3.000000 3.250000 F5 64 64 1 0 3000 P1-1-15 0 - 20 | 15 3.000000 4.000000 A4 64 64 2 0 3000 P1-1-16 0 - 21 | 16 3.000000 4.000000 D4 64 64 3 0 3000 P1-1-17 0 - 22 | 17 3.000000 4.000000 D3 64 64 4 0 3000 P1-1-18 0 - 23 | 18 3.250000 3.500000 E5 64 64 1 0 3500 * 3 - 24 | 19 3.500000 4.000000 D5 64 64 1 0 3500 P1-1-19 0 - 25 | 20 4.000000 4.500000 E5 64 64 1 0 4000 P1-1-20 0 - 26 | 21 4.000000 5.000000 G4 64 64 2 0 4000 P1-1-21 0 - 27 | 22 4.000000 5.000000 C4 64 64 3 0 4000 P1-1-22 0 - 28 | 23 4.000000 5.000000 G3 64 64 4 0 4000 P1-1-23 0 - 29 | 24 4.500000 5.000000 D5 64 64 1 0 4500 P1-1-24 0 - 30 | 25 5.000000 5.500000 C5 64 64 1 0 5000 P1-1-25 0 - 31 | 26 5.000000 6.000000 F4 64 64 2 0 5000 P1-1-26 0 - 32 | 27 5.000000 6.000000 B3 64 64 3 0 5000 P1-1-27 0 - 33 | 28 5.000000 6.000000 G2 64 64 4 0 5000 P1-1-28 0 - 34 | 29 5.500000 6.000000 D5 64 64 1 0 5500 P1-1-29 0 - 35 | 30 6.000000 8.000000 C5 64 64 1 0 6000 P1-1-30 0 - 36 | 31 6.000000 8.000000 E4 64 64 2 0 6000 P1-1-31 0 - 37 | 32 6.000000 8.000000 C4 64 64 3 0 6000 P1-1-32 0 - 38 | 33 6.000000 8.000000 C3 64 64 4 0 6000 P1-1-33 0 - 39 | //Missing 1500 P1-1-9 40 | -------------------------------------------------------------------------------- /tests/data/parangonada/mozart_k265_var1/align.csv: -------------------------------------------------------------------------------- 1 | idx,matchtype,partid,ppartid 2 | 0,0,n9,n0 3 | 1,0,n1,n1 4 | 2,0,n2,n2 5 | 3,0,n3,n3 6 | 4,0,n4,n4 7 | 5,0,n10,n5 8 | 6,0,n5,n6 9 | 7,0,n6,n7 10 | 8,0,n7,n8 11 | 9,0,n8,n9 12 | 10,0,n19,n10 13 | 11,0,n11,n11 14 | 12,0,n12,n12 15 | 13,0,n13,n13 16 | 14,0,n14,n14 17 | 15,0,n15,n15 18 | 16,0,n20,n16 19 | 17,0,n16,n17 20 | 18,0,n17,n18 21 | 19,0,n18,n19 22 | 20,0,n21,n20 23 | 21,0,n29,n21 24 | 22,0,n22,n22 25 | 23,0,n23,n23 26 | 24,0,n24,n24 27 | 25,0,n25,n25 28 | 26,0,n30,n26 29 | 27,0,n26,n27 30 | 28,0,n27,n28 31 | 29,0,n28,n29 32 | 30,0,n39,n30 33 | 31,0,n31,n31 34 | 32,0,n40,n32 35 | 33,0,n32,n33 36 | 34,0,n33,n34 37 | 35,0,n34,n35 38 | 36,0,n35,n36 39 | 37,0,n36,n37 40 | 38,0,n37,n38 41 | 39,0,n42,n39 42 | 40,0,n38,n40 43 | 41,0,n43,n41 44 | 42,0,n51,n42 45 | 43,0,n44,n43 46 | 44,0,n45,n44 47 | 45,0,n46,n45 48 | 46,0,n47,n46 49 | 47,0,n48,n47 50 | 48,0,n49,n48 51 | 49,0,n50,n49 52 | 50,0,n53,n50 53 | 51,0,n54,n51 54 | 52,0,n62,n52 55 | 53,0,n55,n53 56 | 54,0,n56,n54 57 | 55,0,n57,n55 58 | 56,0,n58,n56 59 | 57,0,n59,n57 60 | 58,0,n60,n58 61 | 59,0,n64,n59 62 | 60,0,n61,n60 63 | 61,0,n65,n61 64 | 62,0,n69,n62 65 | 63,0,n66,n63 66 | 64,0,n70,n64 67 | 65,0,n67,n65 68 | 66,0,n68,n66 69 | 67,0,n71,n67 70 | 68,0,n73,n68 71 | 69,0,n74,n69 72 | 70,0,n83,n70 73 | 71,0,n75,n71 74 | 72,0,n76,n72 75 | 73,0,n77,n73 76 | 74,0,n78,n74 77 | 75,0,n79,n75 78 | 76,0,n84,n76 79 | 77,0,n80,n77 80 | 78,0,n81,n78 81 | 79,0,n82,n79 82 | 80,0,n93,n80 83 | 81,0,n85,n81 84 | 82,0,n86,n82 85 | 83,0,n87,n83 86 | 84,0,n88,n84 87 | 85,0,n89,n85 88 | 86,0,n94,n86 89 | 87,0,n90,n87 90 | 88,0,n91,n88 91 | 89,0,n92,n89 92 | 90,0,n95,n90 93 | 91,0,n103,n91 94 | 92,0,n96,n92 95 | 93,0,n97,n93 96 | 94,0,n98,n94 97 | 95,0,n104,n95 98 | 96,0,n99,n96 99 | 97,0,n100,n97 100 | 98,0,n101,n98 101 | 99,0,n102,n99 102 | 100,0,n105,n100 103 | 101,0,n113,n101 104 | 102,0,n106,n102 105 | 103,0,n107,n103 106 | 104,0,n108,n104 107 | 105,0,n109,n105 108 | 106,0,n114,n106 109 | 107,0,n110,n107 110 | 108,0,n111,n108 111 | 109,0,n112,n109 112 | 110,0,n124,n110 113 | 111,0,n123,n111 114 | 112,0,n115,n112 115 | 113,0,n116,n113 116 | 114,0,n117,n114 117 | 115,0,n118,n115 118 | 116,0,n119,n116 119 | 117,0,n120,n117 120 | 118,0,n121,n118 121 | 119,0,n122,n119 122 | 120,0,n133,n120 123 | 121,0,n134,n121 124 | 122,0,n125,n122 125 | 123,0,n126,n123 126 | 124,0,n127,n124 127 | 125,0,n128,n125 128 | 126,0,n129,n126 129 | 127,0,n130,n127 130 | 128,0,n131,n128 131 | 129,0,n132,n129 132 | 130,0,n135,n130 133 | 131,0,n143,n131 134 | 132,0,n144,n132 135 | 133,0,n136,n133 136 | 134,0,n137,n134 137 | 135,0,n138,n135 138 | 136,0,n139,n136 139 | 137,2,undefined,n137 140 | 138,0,n140,n138 141 | 139,0,n141,n139 142 | 140,0,n146,n140 143 | 141,0,n142,n141 144 | 142,0,n153,n142 145 | 143,0,n150,n143 146 | 144,0,n147,n144 147 | 145,0,n151,n145 148 | 146,0,n148,n146 149 | 147,0,n152,n147 150 | 148,0,n149,n148 151 | 149,0,n162,n149 152 | 150,0,n154,n150 153 | 151,0,n155,n151 154 | 152,0,n156,n152 155 | 153,0,n157,n153 156 | 154,0,n163,n154 157 | 155,0,n158,n155 158 | 156,0,n159,n156 159 | 157,0,n160,n157 160 | 158,0,n161,n158 161 | 159,0,n172,n159 162 | 160,0,n164,n160 163 | 161,0,n165,n161 164 | 162,0,n166,n162 165 | 163,0,n167,n163 166 | 164,0,n168,n164 167 | 165,0,n173,n165 168 | 166,0,n169,n166 169 | 167,0,n170,n167 170 | 168,0,n171,n168 171 | 169,0,n174,n169 172 | 170,0,n182,n170 173 | 171,0,n175,n171 174 | 172,0,n176,n172 175 | 173,0,n177,n173 176 | 174,0,n178,n174 177 | 175,0,n183,n175 178 | 176,0,n179,n176 179 | 177,0,n180,n177 180 | 178,0,n181,n178 181 | 179,0,n192,n179 182 | 180,0,n193,n180 183 | 181,0,n184,n181 184 | 182,0,n185,n182 185 | 183,0,n186,n183 186 | 184,0,n187,n184 187 | 185,0,n188,n185 188 | 186,0,n189,n186 189 | 187,0,n190,n187 190 | 188,0,n195,n188 191 | 189,0,n191,n189 192 | 190,0,n196,n190 193 | 191,0,n204,n191 194 | 192,0,n197,n192 195 | 193,0,n198,n193 196 | 194,0,n199,n194 197 | 195,0,n200,n195 198 | 196,0,n201,n196 199 | 197,0,n202,n197 200 | 198,0,n203,n198 201 | 199,0,n206,n199 202 | 200,0,n207,n200 203 | 201,0,n215,n201 204 | 202,0,n208,n202 205 | 203,0,n209,n203 206 | 204,0,n210,n204 207 | 205,0,n211,n205 208 | 206,0,n212,n206 209 | 207,0,n213,n207 210 | 208,0,n214,n208 211 | 209,0,n217,n209 212 | 210,0,n218,n210 213 | 211,0,n222,n211 214 | 212,0,n219,n212 215 | 213,0,n223,n213 216 | 214,0,n220,n214 217 | 215,0,n221,n215 218 | 216,0,n224,n216 219 | 217,0,n226,n217 220 | 218,0,n227,n218 221 | -------------------------------------------------------------------------------- /tests/data/parangonada/mozart_k265_var1/feature.csv: -------------------------------------------------------------------------------- 1 | velocity,timing,articulation,id 2 | 0.0,0.0,0.0,n9 3 | 0.0,0.0,0.0,n1 4 | 0.0,0.0,0.0,n2 5 | 0.0,0.0,0.0,n3 6 | 0.0,0.0,0.0,n4 7 | 0.0,0.0,0.0,n10 8 | 0.0,0.0,0.0,n5 9 | 0.0,0.0,0.0,n6 10 | 0.0,0.0,0.0,n7 11 | 0.0,0.0,0.0,n8 12 | 0.0,0.0,0.0,n19 13 | 0.0,0.0,0.0,n11 14 | 0.0,0.0,0.0,n12 15 | 0.0,0.0,0.0,n13 16 | 0.0,0.0,0.0,n14 17 | 0.0,0.0,0.0,n20 18 | 0.0,0.0,0.0,n15 19 | 0.0,0.0,0.0,n16 20 | 0.0,0.0,0.0,n17 21 | 0.0,0.0,0.0,n18 22 | 0.0,0.0,0.0,n29 23 | 0.0,0.0,0.0,n21 24 | 0.0,0.0,0.0,n22 25 | 0.0,0.0,0.0,n23 26 | 0.0,0.0,0.0,n24 27 | 0.0,0.0,0.0,n30 28 | 0.0,0.0,0.0,n25 29 | 0.0,0.0,0.0,n26 30 | 0.0,0.0,0.0,n27 31 | 0.0,0.0,0.0,n28 32 | 0.0,0.0,0.0,n39 33 | 0.0,0.0,0.0,n40 34 | 0.0,0.0,0.0,n31 35 | 0.0,0.0,0.0,n32 36 | 0.0,0.0,0.0,n33 37 | 0.0,0.0,0.0,n34 38 | 0.0,0.0,0.0,n35 39 | 0.0,0.0,0.0,n36 40 | 0.0,0.0,0.0,n37 41 | 0.0,0.0,0.0,n42 42 | 0.0,0.0,0.0,n38 43 | 0.0,0.0,0.0,n51 44 | 0.0,0.0,0.0,n43 45 | 0.0,0.0,0.0,n44 46 | 0.0,0.0,0.0,n45 47 | 0.0,0.0,0.0,n46 48 | 0.0,0.0,0.0,n47 49 | 0.0,0.0,0.0,n48 50 | 0.0,0.0,0.0,n49 51 | 0.0,0.0,0.0,n53 52 | 0.0,0.0,0.0,n50 53 | 0.0,0.0,0.0,n62 54 | 0.0,0.0,0.0,n54 55 | 0.0,0.0,0.0,n55 56 | 0.0,0.0,0.0,n56 57 | 0.0,0.0,0.0,n57 58 | 0.0,0.0,0.0,n58 59 | 0.0,0.0,0.0,n59 60 | 0.0,0.0,0.0,n60 61 | 0.0,0.0,0.0,n64 62 | 0.0,0.0,0.0,n61 63 | 0.0,0.0,0.0,n69 64 | 0.0,0.0,0.0,n65 65 | 0.0,0.0,0.0,n66 66 | 0.0,0.0,0.0,n70 67 | 0.0,0.0,0.0,n67 68 | 0.0,0.0,0.0,n68 69 | 0.0,0.0,0.0,n73 70 | 0.0,0.0,0.0,n71 71 | 0.0,0.0,0.0,n74 72 | 0.0,0.0,0.0,n83 73 | 0.0,0.0,0.0,n75 74 | 0.0,0.0,0.0,n76 75 | 0.0,0.0,0.0,n77 76 | 0.0,0.0,0.0,n78 77 | 0.0,0.0,0.0,n84 78 | 0.0,0.0,0.0,n79 79 | 0.0,0.0,0.0,n80 80 | 0.0,0.0,0.0,n81 81 | 0.0,0.0,0.0,n82 82 | 0.0,0.0,0.0,n93 83 | 0.0,0.0,0.0,n85 84 | 0.0,0.0,0.0,n86 85 | 0.0,0.0,0.0,n87 86 | 0.0,0.0,0.0,n88 87 | 0.0,0.0,0.0,n94 88 | 0.0,0.0,0.0,n89 89 | 0.0,0.0,0.0,n90 90 | 0.0,0.0,0.0,n91 91 | 0.0,0.0,0.0,n92 92 | 0.0,0.0,0.0,n103 93 | 0.0,0.0,0.0,n95 94 | 0.0,0.0,0.0,n96 95 | 0.0,0.0,0.0,n97 96 | 0.0,0.0,0.0,n98 97 | 0.0,0.0,0.0,n104 98 | 0.0,0.0,0.0,n99 99 | 0.0,0.0,0.0,n100 100 | 0.0,0.0,0.0,n101 101 | 0.0,0.0,0.0,n102 102 | 0.0,0.0,0.0,n113 103 | 0.0,0.0,0.0,n105 104 | 0.0,0.0,0.0,n106 105 | 0.0,0.0,0.0,n107 106 | 0.0,0.0,0.0,n108 107 | 0.0,0.0,0.0,n114 108 | 0.0,0.0,0.0,n109 109 | 0.0,0.0,0.0,n110 110 | 0.0,0.0,0.0,n111 111 | 0.0,0.0,0.0,n112 112 | 0.0,0.0,0.0,n123 113 | 0.0,0.0,0.0,n124 114 | 0.0,0.0,0.0,n115 115 | 0.0,0.0,0.0,n116 116 | 0.0,0.0,0.0,n117 117 | 0.0,0.0,0.0,n118 118 | 0.0,0.0,0.0,n119 119 | 0.0,0.0,0.0,n120 120 | 0.0,0.0,0.0,n121 121 | 0.0,0.0,0.0,n122 122 | 0.0,0.0,0.0,n133 123 | 0.0,0.0,0.0,n134 124 | 0.0,0.0,0.0,n125 125 | 0.0,0.0,0.0,n126 126 | 0.0,0.0,0.0,n127 127 | 0.0,0.0,0.0,n128 128 | 0.0,0.0,0.0,n129 129 | 0.0,0.0,0.0,n130 130 | 0.0,0.0,0.0,n131 131 | 0.0,0.0,0.0,n132 132 | 0.0,0.0,0.0,n143 133 | 0.0,0.0,0.0,n144 134 | 0.0,0.0,0.0,n135 135 | 0.0,0.0,0.0,n136 136 | 0.0,0.0,0.0,n137 137 | 0.0,0.0,0.0,n138 138 | 0.0,0.0,0.0,n139 139 | 0.0,0.0,0.0,n140 140 | 0.0,0.0,0.0,n141 141 | 0.0,0.0,0.0,n146 142 | 0.0,0.0,0.0,n142 143 | 0.0,0.0,0.0,n153 144 | 0.0,0.0,0.0,n150 145 | 0.0,0.0,0.0,n147 146 | 0.0,0.0,0.0,n151 147 | 0.0,0.0,0.0,n148 148 | 0.0,0.0,0.0,n152 149 | 0.0,0.0,0.0,n149 150 | 0.0,0.0,0.0,n162 151 | 0.0,0.0,0.0,n154 152 | 0.0,0.0,0.0,n155 153 | 0.0,0.0,0.0,n156 154 | 0.0,0.0,0.0,n157 155 | 0.0,0.0,0.0,n163 156 | 0.0,0.0,0.0,n158 157 | 0.0,0.0,0.0,n159 158 | 0.0,0.0,0.0,n160 159 | 0.0,0.0,0.0,n161 160 | 0.0,0.0,0.0,n172 161 | 0.0,0.0,0.0,n164 162 | 0.0,0.0,0.0,n165 163 | 0.0,0.0,0.0,n166 164 | 0.0,0.0,0.0,n167 165 | 0.0,0.0,0.0,n173 166 | 0.0,0.0,0.0,n168 167 | 0.0,0.0,0.0,n169 168 | 0.0,0.0,0.0,n170 169 | 0.0,0.0,0.0,n171 170 | 0.0,0.0,0.0,n182 171 | 0.0,0.0,0.0,n174 172 | 0.0,0.0,0.0,n175 173 | 0.0,0.0,0.0,n176 174 | 0.0,0.0,0.0,n177 175 | 0.0,0.0,0.0,n183 176 | 0.0,0.0,0.0,n178 177 | 0.0,0.0,0.0,n179 178 | 0.0,0.0,0.0,n180 179 | 0.0,0.0,0.0,n181 180 | 0.0,0.0,0.0,n192 181 | 0.0,0.0,0.0,n193 182 | 0.0,0.0,0.0,n184 183 | 0.0,0.0,0.0,n185 184 | 0.0,0.0,0.0,n186 185 | 0.0,0.0,0.0,n187 186 | 0.0,0.0,0.0,n188 187 | 0.0,0.0,0.0,n189 188 | 0.0,0.0,0.0,n190 189 | 0.0,0.0,0.0,n195 190 | 0.0,0.0,0.0,n191 191 | 0.0,0.0,0.0,n204 192 | 0.0,0.0,0.0,n196 193 | 0.0,0.0,0.0,n197 194 | 0.0,0.0,0.0,n198 195 | 0.0,0.0,0.0,n199 196 | 0.0,0.0,0.0,n200 197 | 0.0,0.0,0.0,n201 198 | 0.0,0.0,0.0,n202 199 | 0.0,0.0,0.0,n206 200 | 0.0,0.0,0.0,n203 201 | 0.0,0.0,0.0,n215 202 | 0.0,0.0,0.0,n207 203 | 0.0,0.0,0.0,n208 204 | 0.0,0.0,0.0,n209 205 | 0.0,0.0,0.0,n210 206 | 0.0,0.0,0.0,n211 207 | 0.0,0.0,0.0,n212 208 | 0.0,0.0,0.0,n213 209 | 0.0,0.0,0.0,n217 210 | 0.0,0.0,0.0,n214 211 | 0.0,0.0,0.0,n222 212 | 0.0,0.0,0.0,n218 213 | 0.0,0.0,0.0,n219 214 | 0.0,0.0,0.0,n223 215 | 0.0,0.0,0.0,n220 216 | 0.0,0.0,0.0,n221 217 | 0.0,0.0,0.0,n226 218 | 0.0,0.0,0.0,n224 219 | 0.0,0.0,0.0,n227 220 | -------------------------------------------------------------------------------- /tests/data/parangonada/mozart_k265_var1/zalign.csv: -------------------------------------------------------------------------------- 1 | idx,matchtype,partid,ppartid 2 | 0,0,n9,n0 3 | 1,0,n1,n1 4 | 2,0,n2,n2 5 | 3,0,n3,n3 6 | 4,0,n4,n4 7 | 5,0,n10,n5 8 | 6,0,n5,n6 9 | 7,0,n6,n7 10 | 8,0,n7,n8 11 | 9,0,n8,n9 12 | 10,0,n19,n10 13 | 11,0,n11,n11 14 | 12,0,n12,n12 15 | 13,0,n13,n13 16 | 14,0,n14,n14 17 | 15,0,n15,n15 18 | 16,0,n20,n16 19 | 17,0,n16,n17 20 | 18,0,n17,n18 21 | 19,0,n18,n19 22 | 20,0,n21,n20 23 | 21,0,n29,n21 24 | 22,0,n22,n22 25 | 23,0,n23,n23 26 | 24,0,n24,n24 27 | 25,0,n25,n25 28 | 26,0,n30,n26 29 | 27,0,n26,n27 30 | 28,0,n27,n28 31 | 29,0,n28,n29 32 | 30,0,n39,n30 33 | 31,0,n31,n31 34 | 32,0,n40,n32 35 | 33,0,n32,n33 36 | 34,0,n33,n34 37 | 35,0,n34,n35 38 | 36,0,n35,n36 39 | 37,0,n36,n37 40 | 38,0,n37,n38 41 | 39,0,n42,n39 42 | 40,0,n38,n40 43 | 41,0,n43,n41 44 | 42,0,n51,n42 45 | 43,0,n44,n43 46 | 44,0,n45,n44 47 | 45,0,n46,n45 48 | 46,0,n47,n46 49 | 47,0,n48,n47 50 | 48,0,n49,n48 51 | 49,0,n50,n49 52 | 50,0,n53,n50 53 | 51,0,n54,n51 54 | 52,0,n62,n52 55 | 53,0,n55,n53 56 | 54,0,n56,n54 57 | 55,0,n57,n55 58 | 56,0,n58,n56 59 | 57,0,n59,n57 60 | 58,0,n60,n58 61 | 59,0,n64,n59 62 | 60,0,n61,n60 63 | 61,0,n65,n61 64 | 62,0,n69,n62 65 | 63,0,n66,n63 66 | 64,0,n70,n64 67 | 65,0,n67,n65 68 | 66,0,n68,n66 69 | 67,0,n71,n67 70 | 68,0,n73,n68 71 | 69,0,n74,n69 72 | 70,0,n83,n70 73 | 71,0,n75,n71 74 | 72,0,n76,n72 75 | 73,0,n77,n73 76 | 74,0,n78,n74 77 | 75,0,n79,n75 78 | 76,0,n84,n76 79 | 77,0,n80,n77 80 | 78,0,n81,n78 81 | 79,0,n82,n79 82 | 80,0,n93,n80 83 | 81,0,n85,n81 84 | 82,0,n86,n82 85 | 83,0,n87,n83 86 | 84,0,n88,n84 87 | 85,0,n89,n85 88 | 86,0,n94,n86 89 | 87,0,n90,n87 90 | 88,0,n91,n88 91 | 89,0,n92,n89 92 | 90,0,n95,n90 93 | 91,0,n103,n91 94 | 92,0,n96,n92 95 | 93,0,n97,n93 96 | 94,0,n98,n94 97 | 95,0,n104,n95 98 | 96,0,n99,n96 99 | 97,0,n100,n97 100 | 98,0,n101,n98 101 | 99,0,n102,n99 102 | 100,0,n105,n100 103 | 101,0,n113,n101 104 | 102,0,n106,n102 105 | 103,0,n107,n103 106 | 104,0,n108,n104 107 | 105,0,n109,n105 108 | 106,0,n114,n106 109 | 107,0,n110,n107 110 | 108,0,n111,n108 111 | 109,0,n112,n109 112 | 110,0,n124,n110 113 | 111,0,n123,n111 114 | 112,0,n115,n112 115 | 113,0,n116,n113 116 | 114,0,n117,n114 117 | 115,0,n118,n115 118 | 116,0,n119,n116 119 | 117,0,n120,n117 120 | 118,0,n121,n118 121 | 119,0,n122,n119 122 | 120,0,n133,n120 123 | 121,0,n134,n121 124 | 122,0,n125,n122 125 | 123,0,n126,n123 126 | 124,0,n127,n124 127 | 125,0,n128,n125 128 | 126,0,n129,n126 129 | 127,0,n130,n127 130 | 128,0,n131,n128 131 | 129,0,n132,n129 132 | 130,0,n135,n130 133 | 131,0,n143,n131 134 | 132,0,n144,n132 135 | 133,0,n136,n133 136 | 134,0,n137,n134 137 | 135,0,n138,n135 138 | 136,0,n139,n136 139 | 137,2,undefined,n137 140 | 138,0,n140,n138 141 | 139,0,n141,n139 142 | 140,0,n146,n140 143 | 141,0,n142,n141 144 | 142,0,n153,n142 145 | 143,0,n150,n143 146 | 144,0,n147,n144 147 | 145,0,n151,n145 148 | 146,0,n148,n146 149 | 147,0,n152,n147 150 | 148,0,n149,n148 151 | 149,0,n162,n149 152 | 150,0,n154,n150 153 | 151,0,n155,n151 154 | 152,0,n156,n152 155 | 153,0,n157,n153 156 | 154,0,n163,n154 157 | 155,0,n158,n155 158 | 156,0,n159,n156 159 | 157,0,n160,n157 160 | 158,0,n161,n158 161 | 159,0,n172,n159 162 | 160,0,n164,n160 163 | 161,0,n165,n161 164 | 162,0,n166,n162 165 | 163,0,n167,n163 166 | 164,0,n168,n164 167 | 165,0,n173,n165 168 | 166,0,n169,n166 169 | 167,0,n170,n167 170 | 168,0,n171,n168 171 | 169,0,n174,n169 172 | 170,0,n182,n170 173 | 171,0,n175,n171 174 | 172,0,n176,n172 175 | 173,0,n177,n173 176 | 174,0,n178,n174 177 | 175,0,n183,n175 178 | 176,0,n179,n176 179 | 177,0,n180,n177 180 | 178,0,n181,n178 181 | 179,0,n192,n179 182 | 180,0,n193,n180 183 | 181,0,n184,n181 184 | 182,0,n185,n182 185 | 183,0,n186,n183 186 | 184,0,n187,n184 187 | 185,0,n188,n185 188 | 186,0,n189,n186 189 | 187,0,n190,n187 190 | 188,0,n195,n188 191 | 189,0,n191,n189 192 | 190,0,n196,n190 193 | 191,0,n204,n191 194 | 192,0,n197,n192 195 | 193,0,n198,n193 196 | 194,0,n199,n194 197 | 195,0,n200,n195 198 | 196,0,n201,n196 199 | 197,0,n202,n197 200 | 198,0,n203,n198 201 | 199,0,n206,n199 202 | 200,0,n207,n200 203 | 201,0,n215,n201 204 | 202,0,n208,n202 205 | 203,0,n209,n203 206 | 204,0,n210,n204 207 | 205,0,n211,n205 208 | 206,0,n212,n206 209 | 207,0,n213,n207 210 | 208,0,n214,n208 211 | 209,0,n217,n209 212 | 210,0,n218,n210 213 | 211,0,n222,n211 214 | 212,0,n219,n212 215 | 213,0,n223,n213 216 | 214,0,n220,n214 217 | 215,0,n221,n215 218 | 216,0,n224,n216 219 | 217,0,n226,n217 220 | 218,0,n227,n218 221 | -------------------------------------------------------------------------------- /tests/data/png/example_score.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/tests/data/png/example_score.png -------------------------------------------------------------------------------- /tests/data/wav/example_linear_equal_temperament_sr8000.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPJKU/partitura/bfaac43eebb47eaf1aef9841087674c08b22a30e/tests/data/wav/example_linear_equal_temperament_sr8000.wav -------------------------------------------------------------------------------- /tests/temp_test.py: -------------------------------------------------------------------------------- 1 | import partitura as pt 2 | 3 | score = pt.load_mei(r"C:\Users\fosca\Desktop\JKU\partitura\tests\data\mei\example_noMeasures_noBeams.mei") 4 | print(score.parts) 5 | -------------------------------------------------------------------------------- /tests/test_clef.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains tests for clef related methods. 5 | """ 6 | import unittest 7 | from tests import ( 8 | CLEF_TESTFILES, 9 | CLEF_MAP_TESTFILES 10 | ) 11 | import numpy as np 12 | from partitura import load_musicxml 13 | from partitura.musicanalysis import compute_note_array 14 | from partitura.musicanalysis.note_features import clef_feature 15 | from partitura.score import merge_parts 16 | import partitura 17 | 18 | class TestingClefFeatureExtraction(unittest.TestCase): 19 | def test_clef_feature_exctraction(self): 20 | for fn in CLEF_TESTFILES: 21 | score = load_musicxml(fn, force_note_ids = "keep") 22 | sna1 = compute_note_array(score.parts[0], 23 | feature_functions=["clef_feature"]) 24 | sna2 = compute_note_array(score.parts[1], 25 | feature_functions=["clef_feature"]) 26 | mpart = merge_parts(score.parts, reassign="staff") 27 | sna3 = compute_note_array(mpart, 28 | feature_functions=["clef_feature"]) 29 | 30 | sna1test1 = sna1["clef_feature.clef_sign"] == np.array([1., 0., 2., 0., 0., 2., 0., 0., 1., 0.]) 31 | sna1test2 = sna1["clef_feature.clef_line"] == np.array([4., 2., 3., 2., 2., 4., 2., 2., 4., 2.]) 32 | sna1test3 = sna1["clef_feature.clef_octave_change"] == np.array([0., 0., 0., 1., 1., 0., -1., 0., 0., 0.]) 33 | self.assertTrue(np.all(sna1test1), "clef sign does not match") 34 | self.assertTrue(np.all(sna1test2), "clef line does not match") 35 | self.assertTrue(np.all(sna1test3), "clef octave does not match") 36 | 37 | 38 | sna2test1 = sna2["clef_feature.clef_sign"] == np.array([1., 0.]) 39 | sna2test2 = sna2["clef_feature.clef_line"] == np.array([4., 2.]) 40 | sna2test3 = sna2["clef_feature.clef_octave_change"] == np.array([0., 0.]) 41 | self.assertTrue(np.all(sna2test1), "clef sign does not match") 42 | self.assertTrue(np.all(sna2test2), "clef line does not match") 43 | self.assertTrue(np.all(sna2test3), "clef octave does not match") 44 | 45 | sna3test1 = sna3["clef_feature.clef_sign"] == np.array([1., 0., 2., 0., 0., 1., 2., 0., 0., 0., 1., 0.]) 46 | sna3test2 = sna3["clef_feature.clef_line"] == np.array([4., 2., 3., 2., 2., 4., 4., 2., 2., 2., 4., 2.]) 47 | sna3test3 = sna3["clef_feature.clef_octave_change"] == np.array([0., 0., 0., 1., 1., 0., 0., -1., 0., 0., 0., 0.]) 48 | self.assertTrue(np.all(sna3test1), "clef sign does not match") 49 | self.assertTrue(np.all(sna3test2), "clef line does not match") 50 | self.assertTrue(np.all(sna3test3), "clef octave does not match") 51 | 52 | 53 | 54 | 55 | class TestClefMap(unittest.TestCase): 56 | def test_clef_map(self): 57 | score = load_musicxml(CLEF_MAP_TESTFILES[0]) 58 | for part in score: 59 | # clef = (staff_no, sign_shape, line, octave_shift) 60 | map_fn = part.clef_map 61 | self.assertTrue( 62 | np.all(map_fn(part.first_point.t) == np.array([[1, 0, 2, 0], [2, 1, 4, 0]])) # treble / bass 63 | ) 64 | self.assertTrue( 65 | np.all(map_fn(7) == np.array([[1, 0, 2, -2], [2, 0, 2, 0]])) # treble15vb / treble 66 | ) 67 | self.assertTrue( 68 | np.all(map_fn(8) == np.array([[1, 0, 2, 1], [2, 1, 4, 0]])) # treble8va / bass 69 | ) 70 | self.assertTrue( 71 | np.all(map_fn(11) == np.array([[1, 2, 3, 0], [2, 1, 4, 0]])) # ut3 / bass 72 | ) 73 | self.assertTrue( 74 | np.all(map_fn(12) == np.array([[1, 2, 3, 0], [2, 1, 3, 0]])) # ut3 / bass3 75 | ) 76 | self.assertTrue( 77 | np.all(map_fn(13) == np.array([[1, 2, 4, 0], [2, 1, 3, 0]])) # ut4 / bass3 78 | ) 79 | self.assertTrue( 80 | np.all(map_fn(part.last_point.t) == np.array([[1, 2, 4, 0], [2, 1, 3, 0]])) # ut4 / bass3 81 | ) 82 | 83 | 84 | def test_clef_map_multipart(self): 85 | score = load_musicxml(CLEF_TESTFILES[0]) 86 | p1 = score.parts[0] 87 | p2 = score.parts[1] 88 | 89 | t = np.arange(16) 90 | target_p1_octave_change = np.array([ 0, 0, 0, 0, 1, 1, 1, 1, -1, -1, 0, 0, 0, 0, 0, 0]) 91 | target_p1_line = np.array([4, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]) 92 | map_fn = p1.clef_map 93 | self.assertTrue(np.all(map_fn(t)[0,:,3] == target_p1_octave_change)) 94 | self.assertTrue(np.all(map_fn(t)[1,:,2] == target_p1_line)) 95 | 96 | target_p2_sign = np.zeros(16) # 16 stepgs G clef, imputed missing clef in the beginning 97 | map_fn = p2.clef_map 98 | self.assertTrue(np.all(map_fn(t)[1,:,1] == target_p2_sign)) 99 | 100 | 101 | p3 = merge_parts(score.parts, reassign="staff") 102 | map_fn = p3.clef_map 103 | self.assertTrue(np.all(map_fn(t)[0,:,3] == target_p1_octave_change)) 104 | self.assertTrue(np.all(map_fn(t)[1,:,2] == target_p1_line)) 105 | self.assertTrue(np.all(map_fn(t)[3,:,1] == target_p2_sign)) 106 | -------------------------------------------------------------------------------- /tests/test_cross_staff.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from partitura import load_musicxml, load_mei 3 | import numpy as np 4 | from tests import CROSS_STAFF_TESTFILES 5 | 6 | 7 | class CrossStaffBeaming(unittest.TestCase): 8 | def test_cross_staff_single_part_musicxml(self): 9 | score = load_musicxml(CROSS_STAFF_TESTFILES[0]) 10 | note_array = score.note_array(include_staff=True) 11 | expected_staff = np.array([1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 1, 2, 2, 1, 1]) 12 | cross_staff_mask = (note_array["pitch"] > 52) & (note_array["pitch"] < 72) 13 | note_array_staff = note_array[cross_staff_mask]["staff"] 14 | expected_voice = np.ones(len(note_array_staff), dtype=int) 15 | note_array_voice = note_array[cross_staff_mask]["voice"] 16 | self.assertTrue(np.all(note_array_staff == expected_staff)) 17 | self.assertTrue(np.all(note_array_voice == expected_voice)) 18 | 19 | class CrossStaffVoices(unittest.TestCase): 20 | def test_music_xml(self): 21 | score = load_musicxml(CROSS_STAFF_TESTFILES[1]) 22 | note_array = score.note_array(include_staff=True) 23 | expected_staff = [2,1,1,2,1,2,1,1] 24 | expected_voice = [5,2,1,5,5,5,5,5] 25 | self.assertEqual(note_array["staff"].tolist(), expected_staff) 26 | self.assertEqual(note_array["voice"].tolist(), expected_voice) 27 | 28 | def test_mei(self): 29 | score = load_mei(CROSS_STAFF_TESTFILES[2]) 30 | note_array = score.note_array(include_staff=True) 31 | expected_staff = [2,1,1,2,1,2,1,1] 32 | expected_voice = [5,2,1,5,5,5,5,5] 33 | self.assertEqual(note_array["staff"].tolist(), expected_staff) 34 | self.assertEqual(note_array["voice"].tolist(), expected_voice) -------------------------------------------------------------------------------- /tests/test_dcml_import.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from partitura import load_dcml 3 | from tests import TSV_PATH 4 | import os 5 | import pandas as pd 6 | 7 | 8 | class ImportDCMLAnnotations(unittest.TestCase): 9 | def test_tsv_import_from_dcml(self): 10 | note_path = os.path.join(TSV_PATH, "test_notes.tsv") 11 | measure_path = os.path.join(TSV_PATH, "test_measures.tsv") 12 | harmony_path = os.path.join(TSV_PATH, "test_harmonies.tsv") 13 | score = load_dcml(note_path, measure_path, harmony_path) 14 | note_lines = pd.read_csv(note_path, sep="\t", header=None) 15 | self.assertEqual(len(score.parts), 1) 16 | self.assertEqual(len(score[0].notes), len(note_lines)-1, "Number of notes do not match") 17 | 18 | 19 | if __name__ == '__main__': 20 | unittest.main() 21 | -------------------------------------------------------------------------------- /tests/test_deprecations.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module includes tests for deprecation utilities. 5 | """ 6 | import unittest 7 | import warnings 8 | import numpy as np 9 | 10 | from partitura.utils import deprecated_alias, deprecated_parameter 11 | 12 | RNG = np.random.RandomState(1984) 13 | 14 | 15 | class TestDeprecations(unittest.TestCase): 16 | @deprecated_alias(old_p1="new_p1", old_p2="new_p2") 17 | def func_alias(self, new_p1=None, new_p2=None, **kwargs): 18 | 19 | crit = not ("old_p1" in kwargs or "old_p2" in kwargs) 20 | 21 | self.assertTrue(crit) 22 | self.assertTrue(new_p1 is not None) 23 | self.assertTrue(new_p2 is not None) 24 | 25 | @deprecated_parameter(*[f"deprecated{i}" for i in range(10)]) 26 | def func_parameter(self, new_p1=None, new_p2=None, **kwargs): 27 | 28 | crit = not any([f"deprecated{i}" in kwargs for i in range(10)]) 29 | 30 | self.assertTrue(crit) 31 | self.assertTrue(new_p1 is not None) 32 | self.assertTrue(new_p2 is not None) 33 | 34 | def test_deprecated_alias(self): 35 | with warnings.catch_warnings(): 36 | warnings.simplefilter("ignore") 37 | for old_p1, old_p2 in RNG.rand(10, 2): 38 | self.func_alias(old_p1=old_p1, old_p2=old_p2) 39 | 40 | def test_deprecated_parameter(self): 41 | with warnings.catch_warnings(): 42 | warnings.simplefilter("ignore") 43 | for rp in RNG.rand(10, 12): 44 | kwargs = dict( 45 | [("new_p1", rp[0]), ("new_p2", rp[1])] 46 | + [(f"deprecated{i}", rp[i + 2]) for i in range(10)] 47 | ) 48 | self.func_parameter(**kwargs) 49 | -------------------------------------------------------------------------------- /tests/test_display.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module includes tests for display utilities. Since these utilities 5 | rely on externally installed software (e.g., MuseScore, Lilypond), 6 | they cannot be automatically tested by GitHub. 7 | """ 8 | import os 9 | import tempfile 10 | import unittest 11 | 12 | import numpy as np 13 | 14 | from partitura.utils.misc import concatenate_images, PIL_EXISTS, Image 15 | 16 | from tests import PNG_TESTFILES 17 | 18 | 19 | class TestMuseScoreExport(unittest.TestCase): 20 | def test_concat_images(self): 21 | """ 22 | Test `partitura.utils.misc.concatenate_images` 23 | """ 24 | if PIL_EXISTS: 25 | 26 | for fn in PNG_TESTFILES: 27 | filenames = [fn, fn] 28 | 29 | # original image 30 | oimage = Image.open(fn) 31 | 32 | # images concatenated vertically 33 | cimage_vertical = concatenate_images( 34 | filenames=filenames, 35 | out=None, 36 | concat_mode="vertical", 37 | ) 38 | 39 | tmpdir = tempfile.gettempdir() 40 | 41 | ofn = os.path.join(tmpdir, "test_output.png") 42 | concatenate_images( 43 | filenames=filenames, 44 | out=ofn, 45 | concat_mode="vertical", 46 | ) 47 | reloaded_image = Image.open(ofn) 48 | 49 | self.assertTrue( 50 | np.allclose( 51 | np.asarray(reloaded_image), 52 | np.asarray(cimage_vertical), 53 | ) 54 | ) 55 | 56 | cimage_horizontal = concatenate_images( 57 | filenames=filenames, 58 | out=None, 59 | concat_mode="horizontal", 60 | ) 61 | 62 | expected_size_vertical = (oimage.size[0], oimage.size[1] * 2) 63 | expected_size_horizontal = (oimage.size[0] * 2, oimage.size[1]) 64 | self.assertTrue(cimage_vertical.size == expected_size_vertical) 65 | self.assertTrue(cimage_horizontal.size == expected_size_horizontal) 66 | 67 | oimage.close() 68 | reloaded_image.close() 69 | -------------------------------------------------------------------------------- /tests/test_fluidsynth.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains tests for the fluidsynth methods. 5 | """ 6 | import unittest 7 | 8 | import numpy as np 9 | from scipy.io import wavfile 10 | import tempfile 11 | 12 | from partitura.utils.fluidsynth import ( 13 | synthesize_fluidsynth, 14 | HAS_FLUIDSYNTH, 15 | SAMPLE_RATE, 16 | ) 17 | 18 | from partitura import EXAMPLE_MUSICXML, load_score, load_performance_midi 19 | 20 | from partitura.io.exportaudio import save_wav_fluidsynth 21 | 22 | from tests import MOZART_VARIATION_FILES 23 | 24 | RNG = np.random.RandomState(1984) 25 | 26 | if HAS_FLUIDSYNTH: 27 | 28 | class TestSynthesize(unittest.TestCase): 29 | 30 | score = load_score(EXAMPLE_MUSICXML) 31 | 32 | def test_synthesize(self): 33 | 34 | score_na = self.score.note_array() 35 | 36 | duration_beats = ( 37 | score_na["onset_beat"] + score_na["duration_beat"] 38 | ).max() - score_na["onset_beat"].min() 39 | 40 | for bpm in RNG.randint(30, 200, size=10): 41 | 42 | for samplerate in [12000, 16000, 22000, SAMPLE_RATE]: 43 | 44 | duration_sec = duration_beats * 60 / bpm 45 | y = synthesize_fluidsynth( 46 | note_info=self.score, 47 | samplerate=samplerate, 48 | bpm=bpm, 49 | ) 50 | 51 | expected_length = np.round(duration_sec * samplerate) 52 | 53 | self.assertTrue(len(y) == expected_length) 54 | 55 | self.assertTrue(isinstance(y, np.ndarray)) 56 | 57 | class TestSynthExport(unittest.TestCase): 58 | 59 | test_files = [ 60 | load_score(MOZART_VARIATION_FILES["musicxml"]), 61 | load_performance_midi(MOZART_VARIATION_FILES["midi"]), 62 | ] 63 | 64 | def export(self, note_info): 65 | 66 | y = synthesize_fluidsynth( 67 | note_info=note_info, 68 | samplerate=SAMPLE_RATE, 69 | bpm=60, 70 | ) 71 | 72 | with tempfile.TemporaryFile(suffix=".wav") as filename: 73 | 74 | save_wav_fluidsynth( 75 | input_data=note_info, 76 | out=filename, 77 | samplerate=SAMPLE_RATE, 78 | bpm=60, 79 | ) 80 | 81 | sr_rec, rec_audio = wavfile.read(filename) 82 | 83 | self.assertTrue(sr_rec == SAMPLE_RATE) 84 | self.assertTrue(len(rec_audio) == len(y)) 85 | self.assertTrue( 86 | np.allclose( 87 | rec_audio / rec_audio.max(), 88 | y / y.max(), 89 | atol=1e-4, 90 | ) 91 | ) 92 | 93 | def test_export(self): 94 | 95 | for note_info in self.test_files: 96 | 97 | self.export(note_info) 98 | -------------------------------------------------------------------------------- /tests/test_harmony.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains test functions for io of the harmony musicxml tag. 5 | """ 6 | 7 | import unittest 8 | from partitura import load_musicxml 9 | from partitura.score import ChordSymbol, RomanNumeral 10 | from tests import HARMONY_TESTFILES 11 | 12 | 13 | class HarmonyImportTester(unittest.TestCase): 14 | part = load_musicxml(HARMONY_TESTFILES[0])[0] 15 | def test_chordsymbol(self): 16 | roots = list() 17 | kinds = list() 18 | for cs in self.part.iter_all(ChordSymbol): 19 | roots.append(cs.root) 20 | kinds.append(cs.kind) 21 | self.assertEqual(roots, ['C', 'G']) 22 | self.assertEqual(kinds, ['m', '7']) 23 | 24 | def test_romanNumeral(self): 25 | text = list() 26 | for cs in self.part.iter_all(RomanNumeral): 27 | text.append(cs.text) 28 | self.assertEqual(text, ['i', 'V7']) 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /tests/test_kern.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains test functions for KERN import and export. 5 | """ 6 | import unittest 7 | 8 | import partitura 9 | import os 10 | from tests import KERN_TESTFILES, KERN_TIES, KERN_PATH 11 | from tempfile import TemporaryDirectory 12 | from partitura.score import merge_parts 13 | from partitura.utils import ensure_notearray 14 | from partitura.io.importkern import load_kern 15 | from partitura.io.exportkern import save_kern 16 | from partitura import load_musicxml 17 | import numpy as np 18 | 19 | 20 | class TestImportKERN(unittest.TestCase): 21 | def test_example_kern(self): 22 | document_path = partitura.EXAMPLE_KERN 23 | kern_part = merge_parts(load_kern(document_path)) 24 | xml_part = load_musicxml(partitura.EXAMPLE_MUSICXML) 25 | ka = ensure_notearray(kern_part) 26 | xa = ensure_notearray(xml_part) 27 | self.assertTrue( 28 | np.all(ka["onset_beat"] == xa["onset_beat"]), 29 | "Kern onset beats do not match target", 30 | ) 31 | self.assertTrue( 32 | np.all(ka["duration_beat"] == xa["duration_beat"]), 33 | "Kern duration beats do not match target.", 34 | ) 35 | 36 | def test_examples(self): 37 | for fn in KERN_TESTFILES: 38 | score = load_kern(fn) 39 | self.assertTrue(True) 40 | 41 | def test_chorale_import(self): 42 | file_path = os.path.join(KERN_PATH, "chor228.krn") 43 | score = load_kern(file_path) 44 | num_measures = 8 45 | num_parts = 4 46 | num_notes = 102 47 | self.assertTrue(len(score.parts) == num_parts) 48 | self.assertTrue(all([len(part.measures) == num_measures for part in score.parts])) 49 | self.assertTrue(len(score.note_array()) == num_notes) 50 | 51 | def test_tie_mismatch(self): 52 | 53 | fn = KERN_TIES[0] 54 | score = load_kern(fn) 55 | 56 | self.assertTrue(True) 57 | 58 | def test_spline_splitting(self): 59 | file_path = os.path.join(KERN_PATH, "spline_splitting.krn") 60 | score = load_kern(file_path) 61 | num_parts = 4 62 | voices_per_part = [2, 1, 1, 2] 63 | self.assertTrue(num_parts == len(score.parts)) 64 | for i, part in enumerate(score.parts): 65 | vn = part.note_array()["voice"].max() 66 | self.assertTrue(voices_per_part[i] == vn) 67 | 68 | def test_import_export(self): 69 | imported_score = load_kern(partitura.EXAMPLE_KERN) 70 | with TemporaryDirectory() as tmpdir: 71 | out = os.path.join(tmpdir, "test.match") 72 | save_kern(imported_score, out) 73 | exported_score = load_kern(out) 74 | im_na = imported_score.note_array(include_staff=True) 75 | ex_na = exported_score.note_array(include_staff=True) 76 | self.assertTrue(np.all(im_na["onset_beat"] == ex_na["onset_beat"])) 77 | self.assertTrue(np.all(im_na["duration_beat"] == ex_na["duration_beat"])) 78 | self.assertTrue(np.all(im_na["pitch"] == ex_na["pitch"])) 79 | self.assertTrue(np.all(im_na["staff"] == ex_na["staff"])) 80 | # NOTE: Voices are not the same because of the way voices are assigned in merge_parts 81 | 82 | 83 | # if __name__ == "__main__": 84 | # unittest.main() 85 | -------------------------------------------------------------------------------- /tests/test_key_estimation.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains tests for the key estimation methods. 5 | """ 6 | import unittest 7 | 8 | from partitura import EXAMPLE_MUSICXML 9 | from partitura import load_musicxml 10 | from partitura.musicanalysis import estimate_key 11 | from partitura.utils import key_name_to_fifths_mode, fifths_mode_to_key_name 12 | 13 | 14 | class KeyModeComputation(unittest.TestCase): 15 | minor_sharps = ["Em", "Bm", "F#m", "C#m", "G#m", "D#m", "A#m"] 16 | minor_flats = ["Dm", "Gm", "Cm", "Fm", "Bbm", "Ebm", "Abm"] 17 | major_sharps = ["G", "D", "A", "E", "B", "F#", "C#"] 18 | major_flats = ["F", "Bb", "Eb", "Ab", "Db", "Gb", "Cb"] 19 | 20 | def test_key_name_to_fifths_mode(self): 21 | self.assertEqual((0, "minor"), key_name_to_fifths_mode("Am")) 22 | self.assertEqual((0, "major"), key_name_to_fifths_mode("C")) 23 | [ 24 | self.assertEqual((i + 1, "minor"), key_name_to_fifths_mode(a)) 25 | for i, a in enumerate(self.minor_sharps) 26 | ] 27 | [ 28 | self.assertEqual((-(i + 1), "minor"), key_name_to_fifths_mode(a)) 29 | for i, a in enumerate(self.minor_flats) 30 | ] 31 | [ 32 | self.assertEqual((i + 1, "major"), key_name_to_fifths_mode(a)) 33 | for i, a in enumerate(self.major_sharps) 34 | ] 35 | [ 36 | self.assertEqual((-(i + 1), "major"), key_name_to_fifths_mode(a)) 37 | for i, a in enumerate(self.major_flats) 38 | ] 39 | 40 | def test_fifths_modes_to_key_name(self): 41 | self.assertEqual("Am", fifths_mode_to_key_name(0, "minor")) 42 | self.assertEqual("C", fifths_mode_to_key_name(0, "major")) 43 | [ 44 | self.assertEqual(a, fifths_mode_to_key_name(i + 1, "minor")) 45 | for i, a in enumerate(self.minor_sharps) 46 | ] 47 | [ 48 | self.assertEqual(a, fifths_mode_to_key_name(-(i + 1), "minor")) 49 | for i, a in enumerate(self.minor_flats) 50 | ] 51 | [ 52 | self.assertEqual( 53 | a, 54 | fifths_mode_to_key_name(i + 1, "major"), 55 | ) 56 | for i, a in enumerate(self.major_sharps) 57 | ] 58 | [ 59 | self.assertEqual(a, fifths_mode_to_key_name(-(i + 1), "major")) 60 | for i, a in enumerate(self.major_flats) 61 | ] 62 | 63 | 64 | class TestKeyEstimation(unittest.TestCase): 65 | """ 66 | Test key estimation 67 | """ 68 | 69 | score = load_musicxml(EXAMPLE_MUSICXML) 70 | 71 | def test_part(self): 72 | key = estimate_key(self.score) 73 | self.assertTrue(key == "Am", "Incorrect key") 74 | 75 | def test_note_array(self): 76 | key = estimate_key(self.score.note_array()) 77 | self.assertTrue(key == "Am", "Incorrect key") 78 | 79 | 80 | if __name__ == "__main__": 81 | unittest.main() 82 | -------------------------------------------------------------------------------- /tests/test_load_performance.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains test functions for the `load_performance` method 5 | """ 6 | import unittest 7 | import numpy as np 8 | from tests import MOZART_VARIATION_FILES 9 | 10 | 11 | from partitura import load_performance_midi, EXAMPLE_MIDI 12 | from partitura.io import NotSupportedFormatError 13 | from partitura.performance import Performance 14 | 15 | 16 | class TestLoadPerformance(unittest.TestCase): 17 | def test_load_performance(self): 18 | for fn in [MOZART_VARIATION_FILES["midi"]] + [EXAMPLE_MIDI]: 19 | try: 20 | print(fn) 21 | performance = load_performance_midi(fn) 22 | self.assertTrue(isinstance(performance, Performance)) 23 | except NotSupportedFormatError: 24 | self.assertTrue(False) 25 | 26 | def test_array_performance(self): 27 | for fn in [EXAMPLE_MIDI]: 28 | performance = load_performance_midi(fn) 29 | na = performance.note_array() 30 | self.assertTrue(np.all(na["onset_sec"] * 24 == na["onset_tick"])) 31 | 32 | 33 | if __name__ == "__main__": 34 | unittest.main() 35 | -------------------------------------------------------------------------------- /tests/test_load_score.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains test functions for the `load_score` method. 5 | """ 6 | import unittest 7 | 8 | from tests import ( 9 | MUSICXML_IMPORT_EXPORT_TESTFILES, 10 | MEI_TESTFILES, 11 | KERN_TESTFILES, 12 | MATCH_IMPORT_EXPORT_TESTFILES, 13 | ) 14 | 15 | 16 | from partitura import ( 17 | load_score, 18 | EXAMPLE_MIDI, 19 | EXAMPLE_KERN, 20 | EXAMPLE_MEI, 21 | EXAMPLE_MUSICXML, 22 | ) 23 | from partitura.io import NotSupportedFormatError 24 | from partitura.score import Part, PartGroup, Score 25 | 26 | 27 | EXAMPLE_FILES = [EXAMPLE_MIDI, EXAMPLE_KERN, EXAMPLE_MEI, EXAMPLE_MUSICXML] 28 | 29 | 30 | class TestLoadScore(unittest.TestCase): 31 | def test_load_score(self): 32 | 33 | for fn in ( 34 | MUSICXML_IMPORT_EXPORT_TESTFILES 35 | + MEI_TESTFILES 36 | + KERN_TESTFILES 37 | + MATCH_IMPORT_EXPORT_TESTFILES 38 | + EXAMPLE_FILES 39 | ): 40 | self.check_return_type(fn) 41 | 42 | def check_return_type(self, fn): 43 | score = load_score(fn) 44 | self.assertTrue(isinstance(score, Score), f"results of load_score type are not Score for score {fn}.") 45 | for pp in score.part_structure: 46 | self.assertTrue(type(pp) in (Part, PartGroup), f"results of score.part_structure type are neither Part or PartGroup for score {fn}.") 47 | for pp in score.parts: 48 | self.assertTrue(isinstance(pp, Part), f"results of score.parts type are not Part for score {fn}.") 49 | -------------------------------------------------------------------------------- /tests/test_match_export.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains test functions for Matchfile import 5 | """ 6 | import unittest 7 | import numpy as np 8 | import re 9 | import os 10 | from tempfile import TemporaryDirectory 11 | 12 | from tests import MOZART_VARIATION_FILES 13 | 14 | from partitura.io.exportmatch import matchfile_from_alignment, save_match 15 | from partitura.io.importmatch import load_match 16 | from partitura import load_score 17 | 18 | 19 | class TestExportMatch(unittest.TestCase): 20 | def test_matchfile_from_alignment(self): 21 | """ 22 | test `matchfile_from_alignment` 23 | """ 24 | score_fn = MOZART_VARIATION_FILES["musicxml"] 25 | 26 | score = load_score(score_fn) 27 | spart = score[0] 28 | match_fn = MOZART_VARIATION_FILES["match"] 29 | performance, alignment = load_match(match_fn) 30 | 31 | matchfile = matchfile_from_alignment( 32 | alignment=alignment, 33 | ppart=performance[0], 34 | spart=spart, 35 | assume_part_unfolded=True, 36 | ) 37 | 38 | sna = spart.note_array() 39 | pna = performance.note_array() 40 | 41 | # assert that matchfile contains the same number of notes 42 | self.assertTrue(len(sna) == len(matchfile.snotes)) 43 | self.assertTrue(len(pna) == len(matchfile.notes)) 44 | 45 | snote_ids = [n.Anchor for n in matchfile.snotes] 46 | pnote_ids = [n.Id for n in matchfile.notes] 47 | # assert that all snotes in the matchfile are in the note array 48 | self.assertTrue(all([n.Anchor in sna["id"] for n in matchfile.snotes])) 49 | 50 | # assert that all notes in the score are in the matchfile 51 | self.assertTrue(all([nid in snote_ids for nid in sna["id"]])) 52 | 53 | # assert that all notes in the matchfile are in the note array 54 | self.assertTrue(all([n.Id in pna["id"] for n in matchfile.notes])) 55 | 56 | # assert that all notes in the performance are in the matchfile 57 | self.assertTrue(all(nid in pnote_ids for nid in pna["id"])) 58 | 59 | for ml in matchfile.lines: 60 | self.assertTrue(isinstance(ml.matchline, str)) 61 | 62 | def test_save_match(self): 63 | """ 64 | Test save_match 65 | """ 66 | score_fn = MOZART_VARIATION_FILES["musicxml"] 67 | 68 | score = load_score(score_fn) 69 | match_fn = MOZART_VARIATION_FILES["match"] 70 | performance, alignment = load_match(match_fn) 71 | pna1 = performance.note_array() 72 | with TemporaryDirectory() as tmpdir: 73 | 74 | out = os.path.join(tmpdir, "test.match") 75 | save_match( 76 | alignment=alignment, 77 | performance_data=performance, 78 | score_data=score, 79 | out=out, 80 | performer="A Pianist", 81 | composer="W. A. Mozart", 82 | piece="mozart_k265_var1", 83 | score_filename=os.path.basename(score_fn), 84 | performance_filename=os.path.basename(MOZART_VARIATION_FILES["midi"]), 85 | assume_unfolded=True, 86 | ) 87 | 88 | perf_from_saved_match, alignment_from_saved_match = load_match(out) 89 | 90 | pna2 = perf_from_saved_match.note_array() 91 | 92 | # Test that performance data is the same 93 | for field in ( 94 | "onset_sec", 95 | "duration_sec", 96 | "onset_tick", 97 | "duration_tick", 98 | "pitch", 99 | "velocity", 100 | ): 101 | self.assertTrue(np.allclose(pna2[field], pna1[field])) 102 | 103 | # Test that the alignment info is correct 104 | for al in alignment_from_saved_match: 105 | self.assertTrue(al in alignment) 106 | 107 | for al in alignment: 108 | self.assertTrue(al in alignment_from_saved_match) 109 | -------------------------------------------------------------------------------- /tests/test_merge_parts.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains tests for the utilities for merging parts. 5 | """ 6 | import numpy as np 7 | import logging 8 | import unittest 9 | from pathlib import Path 10 | 11 | from partitura import load_musicxml, load_mei 12 | from partitura.score import merge_parts, Part, iter_parts 13 | from partitura.utils.music import ensure_notearray 14 | 15 | from tests import MERGE_PARTS_TESTFILES 16 | 17 | LOGGER = logging.getLogger(__name__) 18 | 19 | 20 | class TestMergeParts(unittest.TestCase): 21 | """ 22 | Test merge parts utility 23 | """ 24 | 25 | def test_list_of_parts_and_partgroup(self): 26 | score = load_musicxml(MERGE_PARTS_TESTFILES[1]) 27 | merged_part = merge_parts(score.parts) 28 | note_array = merged_part.note_array() 29 | expected_onsets = [0, 0, 0, 0, 0, 0, 12, 15, 24, 24, 32, 40, 48] 30 | expected_pitches = [48, 50, 53, 62, 67, 69, 64, 65, 47, 69, 67, 64, 60] 31 | expected_duration = [24, 24, 24, 12, 24, 24, 3, 3, 24, 8, 8, 8, 24] 32 | self.assertTrue(np.array_equal(note_array["onset_div"], expected_onsets)) 33 | self.assertTrue(np.array_equal(note_array["pitch"], expected_pitches)) 34 | self.assertTrue(np.array_equal(note_array["duration_div"], expected_duration)) 35 | 36 | def test_different_divs(self): 37 | score = load_musicxml(MERGE_PARTS_TESTFILES[1]) 38 | merged_part = merge_parts(score.parts) 39 | note_array = merged_part.note_array() 40 | expected_onsets = [0, 0, 0, 0, 0, 0, 12, 15, 24, 24, 32, 40, 48] 41 | expected_pitches = [48, 50, 53, 62, 67, 69, 64, 65, 47, 69, 67, 64, 60] 42 | self.assertTrue(np.array_equal(note_array["onset_div"], expected_onsets)) 43 | self.assertTrue(np.array_equal(note_array["pitch"], expected_pitches)) 44 | 45 | def test_compare_normal_and_different_divs(self): 46 | score_normal = load_musicxml(MERGE_PARTS_TESTFILES[1]) 47 | score_diff = load_musicxml(MERGE_PARTS_TESTFILES[2]) 48 | merged_part_normal = merge_parts(score_normal.parts) 49 | merged_part_diff = merge_parts(score_diff.parts) 50 | note_array_normal = merged_part_normal.note_array() 51 | note_array_diff = merged_part_diff.note_array() 52 | self.assertTrue( 53 | np.array_equal( 54 | note_array_normal["onset_beat"], note_array_diff["onset_beat"] 55 | ) 56 | ) 57 | 58 | def test_merge_single_part(self): 59 | score = load_musicxml(MERGE_PARTS_TESTFILES[3]) 60 | merged_part = merge_parts(score.parts) 61 | self.assertTrue(merged_part == score[0]) 62 | 63 | # def test_merge_interpolation(self): 64 | # parts = load_musicxml(MERGE_PARTS_TESTFILES[4]) 65 | # merged_part = merge_parts(parts) 66 | # self.assertTrue(isinstance(merged_part, Part)) 67 | 68 | def test_reassign_voices(self): 69 | score = load_musicxml(MERGE_PARTS_TESTFILES[6]) 70 | merged_part = merge_parts(score.parts, reassign="voice") 71 | note_array = merged_part.note_array(include_staff=True) 72 | expected_voices = [3, 2, 1, 1] 73 | expected_staves = [1, 1, 1, 1] 74 | self.assertTrue(note_array["voice"].tolist() == expected_voices) 75 | self.assertTrue(note_array["staff"].tolist() == expected_staves) 76 | 77 | def test_reassign_voices2(self): 78 | score = load_musicxml(MERGE_PARTS_TESTFILES[7]) 79 | merged_part = merge_parts(score.parts, reassign="voice") 80 | note_array = merged_part.note_array(include_staff=True) 81 | expected_voices = [4, 4, 3, 2, 1, 1] 82 | expected_staves = [2, 1, 1, 1, 1, 1] 83 | self.assertTrue(note_array["voice"].tolist() == expected_voices) 84 | self.assertTrue(note_array["staff"].tolist() == expected_staves) 85 | 86 | def test_reassign_staves(self): 87 | score = load_musicxml(MERGE_PARTS_TESTFILES[6]) 88 | merged_part = merge_parts(score.parts, reassign="staff") 89 | note_array = merged_part.note_array(include_staff=True) 90 | expected_voices = [1, 2, 1, 1] 91 | expected_staves = [2, 1, 1, 1] 92 | self.assertTrue(note_array["voice"].tolist() == expected_voices) 93 | self.assertTrue(note_array["staff"].tolist() == expected_staves) 94 | 95 | def test_reassign_staves2(self): 96 | score = load_musicxml(MERGE_PARTS_TESTFILES[7]) 97 | merged_part = merge_parts(score.parts, reassign="staff") 98 | note_array = merged_part.note_array(include_staff=True) 99 | expected_voices = [1, 1, 1, 2, 1, 1] 100 | expected_staves = [4, 3, 2, 1, 1, 1] 101 | self.assertTrue(note_array["voice"].tolist() == expected_voices) 102 | self.assertTrue(note_array["staff"].tolist() == expected_staves) 103 | 104 | def test_reassign_auto(self): 105 | score = load_mei(MERGE_PARTS_TESTFILES[8]) 106 | merged_part = merge_parts(score.parts, reassign="auto") 107 | note_array = merged_part.note_array(include_staff=True) 108 | expected_voices = [13, 9, 5, 2, 1, 1] 109 | expected_staves = [4, 3, 2, 1, 1, 1 ] 110 | self.assertEqual(note_array["voice"].tolist(),expected_voices) 111 | self.assertEqual(note_array["staff"].tolist(),expected_staves) 112 | -------------------------------------------------------------------------------- /tests/test_metrical_position.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains test functions for the metrical position computation 5 | """ 6 | 7 | import unittest 8 | from partitura import load_musicxml 9 | from partitura.utils.music import note_array_from_part 10 | from partitura.score import TimeSignature 11 | 12 | import numpy as np 13 | 14 | from tests import ( 15 | METRICAL_POSITION_TESTFILES, 16 | TIME_SIGNATURE_MAP_EDGECASES_TESTFILES, 17 | ) 18 | 19 | 20 | class TestMetricalPosition(unittest.TestCase): 21 | def test_measure_map(self): 22 | score = load_musicxml(METRICAL_POSITION_TESTFILES[0]) 23 | notes = score[0].notes 24 | measures_for_notes = score[0].measure_map([n.start.t for n in notes]) 25 | expected_measures_for_notes = ( 26 | np.array( # the start and end of measures that we expect 27 | [(16 - 48, 16) for i in range(2)] 28 | + [(16, 64) for i in range(6)] 29 | + [(64, 128) for i in range(5)] 30 | + [(128, 200) for i in range(8)] 31 | + [(200, 232) for i in range(2)] 32 | ) 33 | ) 34 | self.assertTrue(np.array_equal(measures_for_notes, expected_measures_for_notes)) 35 | 36 | def test_metrical_position_map(self): 37 | score = load_musicxml(METRICAL_POSITION_TESTFILES[0]) 38 | note_array = note_array_from_part(score[0], include_metrical_position=True) 39 | expected_notes_on_downbeat = [2, 3, 8, 9, 13, 21] 40 | expected_rel_positions = [ 41 | 32, 42 | 40, 43 | 0, 44 | 0, 45 | 24, 46 | 28, 47 | 32, 48 | 40, 49 | 0, 50 | 0, 51 | 24, 52 | 48, 53 | 56, 54 | 0, 55 | 16, 56 | 32, 57 | 33, 58 | 34, 59 | 36, 60 | 40, 61 | 48, 62 | 0, 63 | 16, 64 | ] 65 | expected_measure_duration = ( 66 | [48 for i in range(2)] 67 | + [48 for i in range(6)] 68 | + [64 for i in range(5)] 69 | + [72 for i in range(8)] 70 | + [32 for i in range(2)] 71 | ) 72 | # test if all downbeats are in the right place 73 | self.assertTrue( 74 | np.array_equal( 75 | np.flatnonzero(note_array["is_downbeat"]), expected_notes_on_downbeat 76 | ) 77 | ) 78 | self.assertTrue( 79 | np.array_equal(note_array["rel_onset_div"], expected_rel_positions) 80 | ) 81 | self.assertTrue( 82 | np.array_equal( 83 | note_array["tot_measure_div"], 84 | expected_measure_duration, 85 | ) 86 | ) 87 | 88 | def test_measure_number_map(self): 89 | score = load_musicxml(METRICAL_POSITION_TESTFILES[0]) 90 | notes = score[0].notes 91 | measure_numbers_for_notes = score[0].measure_number_map( 92 | [n.start.t for n in notes] 93 | ) 94 | expected_measure_numbers_for_notes = ( 95 | np.array( # the start and end of measures that we expect 96 | [1 for i in range(2)] 97 | + [2 for i in range(6)] 98 | + [3 for i in range(5)] 99 | + [4 for i in range(8)] 100 | + [5 for i in range(2)] 101 | ) 102 | ) 103 | self.assertTrue( 104 | np.array_equal( 105 | measure_numbers_for_notes, expected_measure_numbers_for_notes 106 | ) 107 | ) 108 | 109 | def test_anacrusis_downbeat(self): 110 | score = load_musicxml(METRICAL_POSITION_TESTFILES[1]) 111 | note_array = note_array_from_part(score[0], include_metrical_position=True) 112 | # first note on the anacrusis is not a downbeat 113 | self.assertTrue(note_array["is_downbeat"][0] == 0) 114 | self.assertTrue(note_array["rel_onset_div"][0] == 3) 115 | 116 | 117 | class TestTimeSignatureMap(unittest.TestCase): 118 | def test_time_signature_map(self): 119 | for fn in TIME_SIGNATURE_MAP_EDGECASES_TESTFILES: 120 | score = load_musicxml(fn) 121 | 122 | for part in score: 123 | 124 | tss = np.array( 125 | [ 126 | (ts.start.t, ts.beats, ts.beat_type, ts.musical_beats) 127 | for ts in part.iter_all(TimeSignature) 128 | ] 129 | ) 130 | 131 | self.assertTrue( 132 | np.all(part.time_signature_map(part.first_point.t) == tss[0, 1:]) 133 | ) 134 | 135 | 136 | 137 | 138 | if __name__ == "__main__": 139 | unittest.main() 140 | -------------------------------------------------------------------------------- /tests/test_musescore.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This file contains test functions for MEI import 5 | """ 6 | 7 | import unittest 8 | 9 | from tests import MUSESCORE_TESTFILES 10 | from partitura import load_musicxml, load_mei, EXAMPLE_MEI 11 | import partitura.score as score 12 | from partitura.io.importmei import MeiParser 13 | from partitura.utils import compute_pianoroll 14 | from lxml import etree 15 | from xmlschema.names import XML_NAMESPACE 16 | from partitura.io import load_score, load_via_musescore 17 | from partitura.io.musescore import find_musescore, MuseScoreNotFoundException 18 | import platform 19 | 20 | import numpy as np 21 | from pathlib import Path 22 | 23 | try: 24 | if find_musescore(): 25 | class TestImportMusescore(unittest.TestCase): 26 | def test_epfl_scores(self): 27 | score = load_via_musescore(MUSESCORE_TESTFILES[0]) 28 | self.assertTrue(len(score.parts) == 1) 29 | # try the generic loading function 30 | score = load_score(MUSESCORE_TESTFILES[0]) 31 | self.assertTrue(len(score.parts) == 1) 32 | except MuseScoreNotFoundException: 33 | pass 34 | -------------------------------------------------------------------------------- /tests/test_nakamura.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains test functions for the import of Nakamura et al.'s match and 5 | corresp file formats. 6 | """ 7 | 8 | import unittest 9 | from partitura.io.importnakamura import load_nakamuracorresp, load_nakamuramatch 10 | 11 | from tests import NAKAMURA_IMPORT_TESTFILES 12 | 13 | 14 | class TestLoadNakamura(unittest.TestCase): 15 | def test_import(self): 16 | for fn in NAKAMURA_IMPORT_TESTFILES: 17 | if "corresp" in fn: 18 | performance, score, align = load_nakamuracorresp(fn) 19 | performance_ids = set( 20 | item["performance_id"] 21 | for item in align 22 | if item["label"] in ("match", "insertion") 23 | ) 24 | score_ids = set( 25 | item["score_id"] 26 | for item in align 27 | if item["label"] in ("match", "deletion") 28 | ) 29 | self.assertTrue(len(performance_ids) == len(performance)) 30 | self.assertTrue(len(score_ids) == len(score)) 31 | else: 32 | performance, score, align = load_nakamuramatch(fn) 33 | performance_ids = set( 34 | item["performance_id"] 35 | for item in align 36 | if item["label"] in ("match", "insertion") 37 | ) 38 | score_ids = set( 39 | item["score_id"] 40 | for item in align 41 | if item["label"] in ("match", "deletion") 42 | ) 43 | self.assertTrue(len(performance_ids) == len(performance)) 44 | self.assertTrue(len(score_ids) == len(score)) 45 | 46 | 47 | if __name__ == "__main__": 48 | 49 | unittest.main() 50 | -------------------------------------------------------------------------------- /tests/test_note_features.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains tests for methods for generating note-level features. 5 | """ 6 | import unittest 7 | from tests import ( 8 | METRICAL_POSITION_TESTFILES, 9 | MUSICXML_IMPORT_EXPORT_TESTFILES, 10 | MEI_TESTFILES, 11 | MUSICXML_NOTE_FEATURES, 12 | ) 13 | from partitura import load_musicxml, load_mei 14 | from partitura.musicanalysis import make_note_feats, compute_note_array 15 | import numpy as np 16 | 17 | 18 | class TestingNoteFeatureExtraction(unittest.TestCase): 19 | def test_metrical_basis(self): 20 | for fn in METRICAL_POSITION_TESTFILES: 21 | score = load_musicxml(fn, force_note_ids = "keep") 22 | make_note_feats(score[0], ["metrical_feature"]) 23 | 24 | def test_grace_basis(self): 25 | fn = [f for f in MEI_TESTFILES if f.endswith("test_grace_note.mei")][0] 26 | part = load_mei(fn) 27 | make_note_feats(part, ["grace_feature"]) 28 | 29 | def test_all_basis(self): 30 | for fn in MUSICXML_IMPORT_EXPORT_TESTFILES: 31 | score = load_musicxml(fn) 32 | make_note_feats(score[0], "all") 33 | 34 | def test_slur_grace_art_dyn_orn(self): 35 | for fn in MUSICXML_NOTE_FEATURES: 36 | score = load_musicxml(fn, force_note_ids=True) 37 | feats = [ 38 | "ornament_feature", 39 | "articulation_feature", 40 | "grace_feature", 41 | "loudness_direction_feature", 42 | "slur_feature", 43 | ] 44 | na = compute_note_array(score[0], feature_functions=feats) 45 | stactest = na["articulation_feature.staccato"] == np.array( 46 | [1, 0, 0, 0, 0, 0] 47 | ) 48 | tentest = na["articulation_feature.tenuto"] == np.array([0, 1, 0, 0, 0, 0]) 49 | trilltest = na["ornament_feature.trill-mark"] == np.array( 50 | [0, 0, 1, 0, 0, 0] 51 | ) 52 | gracetest = na["grace_feature.grace_note"] == np.array([0, 0, 0, 1, 0, 1]) 53 | dyntest = na["loudness_direction_feature.f"] == np.array([0, 0, 0, 1, 1, 1]) 54 | slurtest = na["slur_feature.slur_decr"] == np.array([0, 0, 0, 1, 1, 1]) 55 | self.assertTrue(np.all(stactest), "staccato feature does not match") 56 | self.assertTrue(np.all(tentest), "tenuto feature does not match") 57 | self.assertTrue(np.all(trilltest), "trill feature does not match") 58 | self.assertTrue(np.all(gracetest), "grace feature does not match") 59 | self.assertTrue(np.all(dyntest), "forte feature does not match") 60 | self.assertTrue(np.all(slurtest), "slur feature does not match") 61 | 62 | def test_measure_feature(self): 63 | for fn in MUSICXML_NOTE_FEATURES: 64 | score = load_musicxml(fn, force_note_ids=True) 65 | feats = [ 66 | "measure_feature" 67 | ] 68 | na = compute_note_array(score[0], feature_functions=feats) 69 | 70 | numtest = na["measure_feature.measure_number"] == np.array([1, 1, 1, 2, 2, 2]) 71 | starttest = na["measure_feature.measure_start_beat"] == np.array([0, 0, 0, 4, 4, 4]) 72 | endtest = na["measure_feature.measure_end_beat"] == np.array([4, 4, 4, 8, 8, 8]) 73 | self.assertTrue(np.all(numtest), "measure number feature does not match") 74 | self.assertTrue(np.all(starttest), "measure start feature does not match") 75 | self.assertTrue(np.all(endtest), "measure end feature does not match") 76 | 77 | 78 | 79 | if __name__ == "__main__": 80 | unittest.main() 81 | -------------------------------------------------------------------------------- /tests/test_octave_shift.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from partitura import EXAMPLE_MUSICXML 3 | from partitura import load_score 4 | from partitura.score import OctaveShiftDirection 5 | import numpy as np 6 | from tests import OCTAVE_SHIFT_TESTFILES 7 | 8 | 9 | class OctaveShift(unittest.TestCase): 10 | def test_octave_shift(self): 11 | part = load_score(EXAMPLE_MUSICXML)[0] 12 | na = part.note_array(include_pitch_spelling=True, include_staff=True) 13 | # na["octave"][na["staff"] == 1] += 1 14 | # Octave shift is applied to the 1st staff 15 | shift_part = load_score(OCTAVE_SHIFT_TESTFILES[0])[0] 16 | octave_post_shift = shift_part.note_array(include_pitch_spelling=True)["octave"] 17 | self.assertEqual(np.all(na["octave"] == octave_post_shift), True) 18 | 19 | 20 | if __name__ == '__main__': 21 | unittest.main() 22 | -------------------------------------------------------------------------------- /tests/test_parangonada.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains test functions for Parangonada import and export. 5 | """ 6 | 7 | import logging 8 | import unittest 9 | import tempfile 10 | import os 11 | 12 | from partitura import load_score, load_match 13 | from partitura.io.exportparangonada import ( 14 | save_parangonada_alignment, 15 | save_alignment_for_ASAP, 16 | save_parangonada_csv, 17 | ) 18 | 19 | from partitura.io.importparangonada import ( 20 | load_parangonada_alignment, 21 | load_alignment_from_ASAP, 22 | _load_csv, 23 | load_parangonada_csv, 24 | ) 25 | 26 | 27 | from tests import MOZART_VARIATION_FILES 28 | 29 | LOGGER = logging.getLogger(__name__) 30 | 31 | test_alignment = [ 32 | {"label": "match", "score_id": "n01", "performance_id": "n01"}, 33 | {"label": "insertion", "performance_id": "n02"}, 34 | {"label": "deletion", "score_id": "n02"}, 35 | ] 36 | 37 | 38 | _performance, _alignment = load_match(filename=MOZART_VARIATION_FILES["match"]) 39 | MOZART_VARIATION_DATA = dict( 40 | score=load_score(MOZART_VARIATION_FILES["musicxml"]), 41 | performance=_performance, 42 | alignment=_alignment, 43 | parangonada_align=_load_csv( 44 | MOZART_VARIATION_FILES["parangonada_align"], 45 | ), 46 | parangonada_zalign=_load_csv( 47 | MOZART_VARIATION_FILES["parangonada_zalign"], 48 | ), 49 | parangonada_feature=_load_csv(MOZART_VARIATION_FILES["parangonada_feature"]), 50 | parangonada_ppart=_load_csv(MOZART_VARIATION_FILES["parangonada_ppart"]), 51 | parangonada_spart=_load_csv(MOZART_VARIATION_FILES["parangonada_spart"]), 52 | ) 53 | 54 | 55 | class Ppart: 56 | def __init__(self): 57 | self.notes = [ 58 | { 59 | "id": "n01", 60 | "track": "dummy", 61 | "channel": "dummy", 62 | "midi_pitch": "dummy", 63 | "note_on": "dummy", 64 | }, 65 | { 66 | "id": "n02", 67 | "track": "dummy", 68 | "channel": "dummy", 69 | "midi_pitch": "dummy", 70 | "note_on": "dummy", 71 | }, 72 | ] 73 | 74 | # Make dummy Ppart iterable 75 | def __getitem__(self, index): 76 | return self 77 | 78 | def __iter__(self): 79 | return self 80 | 81 | def __next__(self): 82 | return self 83 | 84 | def __len__(self): 85 | return 1 86 | 87 | 88 | test_ppart = Ppart() 89 | 90 | 91 | class TestIO(unittest.TestCase): 92 | """ 93 | Test if the csv, tsv export and import gives the expected results. 94 | 95 | """ 96 | 97 | def test_csv_import_export(self): 98 | with tempfile.TemporaryDirectory() as tmpdirname: 99 | save_parangonada_alignment( 100 | out=os.path.join(tmpdirname, "align.csv"), alignment=test_alignment 101 | ) 102 | import_alignment = load_parangonada_alignment( 103 | os.path.join(tmpdirname, "align.csv") 104 | ) 105 | equal = test_alignment == import_alignment 106 | self.assertTrue(equal) 107 | 108 | def test_tsv_import_export(self): 109 | with tempfile.TemporaryDirectory() as tmpdirname: 110 | save_alignment_for_ASAP( 111 | out=os.path.join(tmpdirname, "align.tsv"), 112 | performance_data=test_ppart, 113 | alignment=test_alignment, 114 | ) 115 | import_alignment = load_alignment_from_ASAP( 116 | os.path.join(tmpdirname, "align.tsv") 117 | ) 118 | equal = test_alignment == import_alignment 119 | self.assertTrue(equal) 120 | 121 | def test_save_parangonada_csv(self): 122 | 123 | with tempfile.TemporaryDirectory() as tmpdirname: 124 | 125 | save_parangonada_csv( 126 | alignment=MOZART_VARIATION_DATA["alignment"], 127 | performance_data=MOZART_VARIATION_DATA["performance"], 128 | score_data=MOZART_VARIATION_DATA["score"], 129 | outdir=tmpdirname, 130 | ) 131 | 132 | performance, alignment, _, _ = load_parangonada_csv(tmpdirname) 133 | 134 | self.assertTrue(alignment == MOZART_VARIATION_DATA["alignment"]) 135 | 136 | 137 | if __name__ == "__main__": 138 | unittest.main() 139 | -------------------------------------------------------------------------------- /tests/test_part_properties.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains tests for part properties. 5 | """ 6 | import unittest 7 | import partitura 8 | from partitura import score 9 | 10 | 11 | class TestingPartProperties(unittest.TestCase): 12 | def test_props(self): 13 | part = score.Part("P0", "My Part") 14 | part.set_quarter_duration(0, 10) 15 | part.add(score.KeySignature(0, ""), start=0) 16 | part.add(score.TimeSignature(3, 4), start=0) 17 | part.add(score.TimeSignature(4, 4), start=30) 18 | part.add(score.Note(id="n0", step="A", octave=4), start=0, end=10) 19 | part.add(score.Rest(id="r0"), start=10, end=20) 20 | part.add(score.Note(id="n1", step="A", octave=4), start=20, end=70) 21 | part.add(score.ImpulsiveLoudnessDirection("sfz", "sfz"), start=20, end=20) 22 | part.add(score.ArticulationDirection("staccato", "staccato"), start=0, end=0) 23 | score.add_measures(part) 24 | score.tie_notes(part) 25 | 26 | self.assertTrue(len(part.notes) == 3) 27 | self.assertTrue(len(part.notes_tied) == 2) 28 | self.assertTrue(len(part.measures) == 2) 29 | self.assertTrue(len(part.time_sigs) == 2) 30 | self.assertTrue(len(part.key_sigs) == 1) 31 | self.assertTrue(len(part.rests) == 1) 32 | self.assertTrue(len(part.articulations) == 1) 33 | self.assertTrue(len(part.dynamics) == 1) 34 | self.assertTrue(len(part.repeats) == 0) 35 | 36 | 37 | if __name__ == "__main__": 38 | unittest.main() 39 | -------------------------------------------------------------------------------- /tests/test_partial_measures.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | #%% 5 | """ 6 | This module contains tests for measures with non-integer IDs in musicxml. 7 | 8 | Such measure IDs can occur in irregular measures (i.e., pickups in the middle of the piece, i.e. variations pieces, measures with fermata or cadenza ornamentations. 9 | 10 | Fix: added 'name' property to measures to reflect non-integer measures. 11 | """ 12 | import unittest 13 | 14 | import numpy as np 15 | from partitura.io import load_musicxml 16 | from partitura.score import * 17 | 18 | from tests import MUSICXML_PARTIAL_MEASURES_TESTFILES 19 | 20 | 21 | class TestPartialMeasures(unittest.TestCase): 22 | """ 23 | Test parsing of musicxml files with single partial/irregular measures 24 | """ 25 | 26 | def test_measure_number_name_single(self): 27 | sc = load_musicxml(MUSICXML_PARTIAL_MEASURES_TESTFILES[0]) 28 | spart = sc.parts[0] 29 | spart_variants = make_score_variants(spart) 30 | spart_unfolded = spart_variants[0].create_variant_part() 31 | 32 | unfolded_measure_numbers = [m.number for m in spart_unfolded.measures] 33 | unfolded_measure_names = [m.name for m in spart_unfolded.measures] 34 | 35 | expected_unfolded_measure_numbers = [1,2,3,1,2,4,5,6,7] 36 | expected_unfolded_measure_names = ['1','2','3','1','2','X1','4','X2','5'] 37 | 38 | self.assertTrue( 39 | np.array_equal(unfolded_measure_numbers, expected_unfolded_measure_numbers) 40 | ) 41 | self.assertTrue( 42 | np.array_equal(unfolded_measure_names, expected_unfolded_measure_names) 43 | ) 44 | 45 | def test_measure_number_name_consecutive(self): 46 | sc = load_musicxml(MUSICXML_PARTIAL_MEASURES_TESTFILES[1]) 47 | spart = sc.parts[0] 48 | 49 | measure_numbers = [m.number for m in spart.measures] 50 | measure_names = [m.name for m in spart.measures] 51 | 52 | expected_measure_numbers = [1,2,3,4,5,6,7] 53 | expected_measure_names = ['1','2','3','X1','X2','X3','4'] 54 | 55 | self.assertTrue( 56 | np.array_equal(measure_numbers, expected_measure_numbers) 57 | ) 58 | self.assertTrue( 59 | np.array_equal(measure_names, expected_measure_names) 60 | ) 61 | 62 | if __name__ == "__main__": 63 | unittest.main() -------------------------------------------------------------------------------- /tests/test_performance_codec.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains test functions for Performance Array Calculations 5 | """ 6 | import unittest 7 | import numpy as np 8 | import numpy.lib.recfunctions as rfn 9 | from tests import MATCH_IMPORT_EXPORT_TESTFILES 10 | from partitura import load_match 11 | from partitura.musicanalysis import encode_performance, decode_performance 12 | 13 | 14 | class TestPerformanceCoded(unittest.TestCase): 15 | def test_encode_decode(self): 16 | for fn in MATCH_IMPORT_EXPORT_TESTFILES: 17 | ppart, alignment, spart = load_match(filename=fn, create_score=True) 18 | 19 | performance_array, _ = encode_performance(spart[0], ppart[0], alignment) 20 | decoded_ppart, decoded_alignment = decode_performance( 21 | spart[0], performance_array, return_alignment=True 22 | ) 23 | # normalize ppart notearray onset sec starting from 0. 24 | orig_sec_array = ( 25 | ppart[0].note_array()["onset_sec"] 26 | - ppart[0].note_array()["onset_sec"].min() 27 | ) 28 | target = np.all( 29 | np.allclose( 30 | np.sort(decoded_ppart.note_array()["onset_sec"]), 31 | np.sort(orig_sec_array), 32 | ) 33 | ) 34 | self.assertTrue( 35 | target, "The decoded Performed Part doesn't match the original." 36 | ) 37 | 38 | def test_beat_normalization(self): 39 | for fn in MATCH_IMPORT_EXPORT_TESTFILES: 40 | ppart, alignment, spart = load_match(filename=fn, create_score=True) 41 | 42 | for normalization in ["beat_period_log", 43 | "beat_period_ratio", 44 | "beat_period_ratio_log", 45 | "beat_period_standardized"]: 46 | 47 | performance_array, _ = encode_performance(spart[0], ppart[0], alignment, 48 | beat_normalization=normalization) 49 | decoded_ppart, decoded_alignment = decode_performance( 50 | spart[0], performance_array, return_alignment=True, 51 | beat_normalization=normalization 52 | ) 53 | # normalize ppart notearray onset sec starting from 0. 54 | orig_sec_array = ( 55 | ppart[0].note_array()["onset_sec"] 56 | - ppart[0].note_array()["onset_sec"].min() 57 | ) 58 | target = np.all( 59 | np.allclose( 60 | np.sort(decoded_ppart.note_array()["onset_sec"]), 61 | np.sort(orig_sec_array), 62 | ) 63 | ) 64 | self.assertTrue( 65 | target, f"The decoded Performed Part doesn't match the original. (beat_normalization: {normalization})" 66 | ) 67 | 68 | def test_custom_tempo(self): 69 | for fn in MATCH_IMPORT_EXPORT_TESTFILES: 70 | ppart, alignment, spart = load_match(filename=fn, create_score=True) 71 | 72 | # TODO: add more custom tempo function to test. 73 | performance_array, _ = encode_performance(spart[0], ppart[0], alignment, 74 | tempo_smooth='derivative') 75 | decoded_ppart, decoded_alignment = decode_performance( 76 | spart[0], performance_array, return_alignment=True 77 | ) 78 | 79 | orig_sec_array = ( 80 | ppart[0].note_array()["onset_sec"] 81 | - ppart[0].note_array()["onset_sec"].min() 82 | ) 83 | target = np.all( 84 | np.allclose( 85 | np.sort(decoded_ppart.note_array()["onset_sec"]), 86 | np.sort(orig_sec_array), 87 | ) 88 | ) 89 | self.assertTrue( 90 | target, f"The decoded Performed Part doesn't match the original." 91 | ) 92 | 93 | -------------------------------------------------------------------------------- /tests/test_performance_features.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains test functions for Performance Array Calculations 5 | """ 6 | import unittest 7 | import numpy as np 8 | from partitura import load_match 9 | from tests import MATCH_EXPRESSIVE_FEATURES_TESTFILES 10 | from partitura.musicanalysis.performance_features import make_performance_features 11 | import os 12 | 13 | 14 | class TestPerformanceFeatures(unittest.TestCase): 15 | def test_performance_features(self): 16 | fields = ['id', 17 | 'articulation_feature.kor', 'pedal_feature.onset_value', 'pedal_feature.offset_value', 'pedal_feature.to_prev_release', 18 | 'pedal_feature.to_next_release', 'onset', 'duration', 'pitch', 'p_onset', 'p_duration', 'velocity', 'beat_period'] 19 | True_array = np.array( 20 | [('n1', 0.23374297, 89.74999, 62.000057, 0., 0.16015087, -0.5, 0.5, 59, 4.9925, 0.8775, 44, 1.4700003), 21 | ('n4', 0.03011051, 114.25004, 61.000244, 0., 22 | 0.4027142, 0., 1., 40, 5.7025, 2.4375, 22, 2.8474998), 23 | ('n3', 0.8451489, 87.500046, 113., 0., 1.5302137, 0., 0.25, 56, 5.77625, 1.23625, 26, 2.8474998)], 24 | dtype=[('id', '<U256'), 25 | ('articulation_feature.kor', '<f4'), 26 | ('pedal_feature.onset_value', '<f4'), 27 | ('pedal_feature.offset_value', '<f4'), 28 | ('pedal_feature.to_prev_release', '<f4'), 29 | ('pedal_feature.to_next_release', '<f4'), 30 | ('onset', '<f4'), 31 | ('duration', '<f4'), 32 | ('pitch', '<i4'), 33 | ('p_onset', '<f4'), 34 | ('p_duration', '<f4'), 35 | ('velocity', '<i4'), 36 | ('beat_period', '<f4')]) 37 | fn = MATCH_EXPRESSIVE_FEATURES_TESTFILES[0] 38 | perf, alignment, score = load_match(filename=fn, create_score=True) 39 | features = make_performance_features(score, 40 | perf, 41 | alignment, 42 | feature_functions="all") 43 | 44 | self.assertTrue(np.all(True_array[fields] == features[fields][:3]), 45 | f"The expression features don't match the original.") 46 | 47 | -------------------------------------------------------------------------------- /tests/test_pitch_spelling.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains tests for the pitch spelling algorithms. 5 | """ 6 | import numpy as np 7 | import unittest 8 | 9 | from partitura import EXAMPLE_MUSICXML 10 | from partitura import load_musicxml 11 | from partitura.musicanalysis import estimate_spelling 12 | 13 | 14 | def compare_spelling(spelling, notes): 15 | comparisons = np.zeros((len(spelling), 3)) 16 | for i, (n, s) in enumerate(zip(notes, spelling)): 17 | comparisons[i, 0] = int(n.step == s["step"]) 18 | if n.alter is None and s["alter"] == 0: 19 | comparisons[i, 1] = 1 20 | else: 21 | comparisons[i, 1] = int(n.alter == s["alter"]) 22 | comparisons[i, 2] = int(n.octave == s["octave"]) 23 | return comparisons 24 | 25 | 26 | class TestKeyEstimation(unittest.TestCase): 27 | """ 28 | Test key estimation 29 | """ 30 | 31 | score = load_musicxml(EXAMPLE_MUSICXML) 32 | 33 | def test_part(self): 34 | spelling = estimate_spelling(self.score[0]) 35 | comparisons = compare_spelling(spelling, self.score[0].notes) 36 | self.assertTrue(np.all(comparisons), "Incorrect spelling") 37 | 38 | def test_note_array(self): 39 | spelling = estimate_spelling(self.score[0].note_array()) 40 | comparisons = compare_spelling(spelling, self.score[0].notes) 41 | self.assertTrue(np.all(comparisons), "Incorrect spelling") 42 | -------------------------------------------------------------------------------- /tests/test_quarter_adjust.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains tests for adjusting quarter durations 5 | """ 6 | 7 | import logging 8 | import unittest 9 | 10 | import partitura.score as score 11 | 12 | LOGGER = logging.getLogger(__name__) 13 | 14 | import partitura 15 | import partitura.score as score 16 | 17 | # class TestQuarterAdjust(unittest.TestCase): 18 | class TestQuarterAdjust(object): 19 | """ 20 | Test whether timepoints are adjusted correctly when calling 21 | set_quarter_duration with the option adjust_times=True. 22 | """ 23 | 24 | cases = [ 25 | dict( 26 | q_times=[0], 27 | q_durs=[10], 28 | note_ons=[0, 10, 20], 29 | note_offs=[10, 20, 30], 30 | new_q_time=[0], 31 | new_q_dur=[100], 32 | new_note_ons=[0, 100, 200], 33 | new_note_offs=[100, 200, 300], 34 | ), 35 | dict( 36 | q_times=[0, 10], 37 | q_durs=[10, 100], 38 | note_ons=[0, 10, 110], 39 | note_offs=[10, 110, 210], 40 | new_q_time=[5, 10], 41 | new_q_dur=[20, 200], 42 | new_note_ons=[0, 15, 215], 43 | new_note_offs=[15, 215, 415], 44 | ), 45 | dict( 46 | q_times=[0, 10], 47 | q_durs=[10, 100], 48 | note_ons=[0, 10, 110], 49 | note_offs=[10, 110, 210], 50 | new_q_time=[300, 1000], 51 | new_q_dur=[1000, 2000], 52 | new_note_ons=[0, 10, 110], 53 | new_note_offs=[10, 110, 210], 54 | ), 55 | dict( 56 | q_times=[0, 10], 57 | q_durs=[10, 100], 58 | note_ons=[0, 10, 110], 59 | note_offs=[10, 110, 210], 60 | new_q_time=[5, 10], 61 | new_q_dur=[20, 200], 62 | new_note_ons=[0, 15, 215], 63 | new_note_offs=[15, 215, 415], 64 | ), 65 | ] 66 | 67 | def do_test( 68 | self, 69 | q_times, 70 | q_durs, 71 | note_ons, 72 | note_offs, 73 | new_q_time, 74 | new_q_dur, 75 | new_note_ons, 76 | new_note_offs, 77 | ): 78 | 79 | part = score.Part("P0") 80 | 81 | for q_time, q_dur in zip(q_times, q_durs): 82 | part.set_quarter_duration(q_time, q_dur) 83 | 84 | for i, (note_on, note_off) in enumerate(zip(note_ons, note_offs)): 85 | n = score.Note(id="n{}".format(i), step="C", octave=4, voice=1) 86 | part.add(n, note_on, note_off) 87 | 88 | for q_time, q_dur in zip(new_q_time[::-1], new_q_dur[::-1]): 89 | part.set_quarter_duration(q_time, q_dur, adjust_times=True) 90 | 91 | for n, start, end in zip(part.notes, new_note_ons, new_note_offs): 92 | msg = "Note onset {} should be {}".format(n.start.t, start) 93 | self.assertEqual(n.start.t, start, msg) 94 | msg = "Note offset {} should be {}".format(n.end.t, end) 95 | self.assertEqual(n.end.t, end, msg) 96 | 97 | def test_cases(self): 98 | for test_case in self.cases: 99 | self.do_test(**test_case) 100 | 101 | 102 | # class TestQuarterMultiply(unittest.TestCase): 103 | class TestQuarterMultiply(object): 104 | """ 105 | Test whether timepoints are adjusted correctly when calling 106 | set_quarter_duration with the option adjust_times=True. 107 | """ 108 | 109 | cases = [ 110 | dict( 111 | q_times=[0], 112 | q_durs=[10], 113 | note_ons=[0, 10, 20], 114 | note_offs=[10, 20, 30], 115 | factor=100, 116 | new_note_ons=[0, 1000, 2000], 117 | new_note_offs=[1000, 2000, 3000], 118 | ), 119 | dict( 120 | q_times=[0, 10], 121 | q_durs=[10, 100], 122 | note_ons=[0, 10, 110], 123 | note_offs=[10, 110, 210], 124 | factor=200, 125 | new_note_ons=[0, 2000, 22000], 126 | new_note_offs=[2000, 22000, 42000], 127 | ), 128 | ] 129 | 130 | def do_test( 131 | self, q_times, q_durs, note_ons, note_offs, factor, new_note_ons, new_note_offs 132 | ): 133 | 134 | part = score.Part("P0") 135 | 136 | for q_time, q_dur in zip(q_times, q_durs): 137 | part.set_quarter_duration(q_time, q_dur) 138 | 139 | for i, (note_on, note_off) in enumerate(zip(note_ons, note_offs)): 140 | n = score.Note(id="n{}".format(i), step="C", octave=4, voice=1) 141 | part.add(n, note_on, note_off) 142 | 143 | part.multiply_quarter_durations(factor) 144 | 145 | for n, start, end in zip(part.notes, new_note_ons, new_note_offs): 146 | msg = "Note {} onset {} should be {}".format(n.id, n.start.t, start) 147 | self.assertEqual(n.start.t, start, msg) 148 | msg = "Note {} offset {} should be {}".format(n.id, n.end.t, end) 149 | self.assertEqual(n.end.t, end, msg) 150 | 151 | def test_cases(self): 152 | for test_case in self.cases: 153 | self.do_test(**test_case) 154 | 155 | 156 | if __name__ == "__main__": 157 | unittest.main() 158 | -------------------------------------------------------------------------------- /tests/test_rest_array.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains the test cases for testing the note_array attribute of 5 | the Part class. 6 | """ 7 | 8 | import unittest 9 | import partitura.score as score 10 | from partitura import load_musicxml 11 | import numpy as np 12 | from tests import REST_ARRAY_TESTFILES 13 | 14 | 15 | class TestNoteArray(unittest.TestCase): 16 | """ 17 | Test the note_array attribute of the Part class 18 | """ 19 | 20 | def test_restarray_1(self): 21 | part = score.Part("P0", "My Part") 22 | 23 | part.set_quarter_duration(0, 10) 24 | part.add(score.TimeSignature(3, 4), start=0) 25 | part.add(score.Note(id="n0", step="A", octave=4), start=0, end=10) 26 | part.add(score.Rest(id="r0"), start=10, end=20) 27 | 28 | note_array = part.rest_array() 29 | self.assertTrue(len(note_array) == 1) 30 | 31 | def test_rest_array(self): 32 | sc = load_musicxml(REST_ARRAY_TESTFILES[0]) 33 | sc[0].use_musical_beat() 34 | rest_array = sc[0].rest_array( 35 | include_metrical_position=True, include_staff=True 36 | ) 37 | expected_musical_beats = [14, 18] 38 | self.assertTrue( 39 | np.array_equal(rest_array["onset_beat"], expected_musical_beats) 40 | ) 41 | 42 | def test_rest_collapse(self): 43 | sc = load_musicxml(REST_ARRAY_TESTFILES[1]) 44 | rest_array_non_collapsed = sc[0].rest_array() 45 | expected_length_non_collapsed = 7 46 | rest_array = sc[0].rest_array(collapse=True) 47 | expected_length_collapsed = 5 48 | self.assertTrue(len(rest_array_non_collapsed) == expected_length_non_collapsed) 49 | self.assertTrue(len(rest_array) == expected_length_collapsed) 50 | 51 | 52 | if __name__ == "__main__": 53 | unittest.main() 54 | -------------------------------------------------------------------------------- /tests/test_time_estimation.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains tests for the methods for estimating metrical information. 5 | """ 6 | import numpy as np 7 | 8 | import unittest 9 | from tempfile import TemporaryFile 10 | 11 | from tests import VOSA_TESTFILES 12 | 13 | from partitura import load_musicxml 14 | from partitura.musicanalysis import estimate_time 15 | import partitura 16 | 17 | 18 | class TestTempoMeterBeats(unittest.TestCase): 19 | """ 20 | Test tempo, meter numerator, and beat estimation. 21 | """ 22 | 23 | score = load_musicxml(VOSA_TESTFILES[0]) 24 | tempometerbeats = estimate_time(score) 25 | 26 | def testtempo(self): 27 | 28 | some_performance_notes = np.array( 29 | [ 30 | (5.7025, 2.4375, 40, 22, 1, 0, "n1"), 31 | (5.70375, 2.43625, 64, 54, 1, 0, "n2"), 32 | (5.77625, 2.36375, 56, 26, 1, 0, "n3"), 33 | (6.4325, 1.7075, 47, 20, 1, 0, "n4"), 34 | (6.9725, 1.1675, 63, 52, 1, 0, "n6"), 35 | (7.47625, 0.66375, 64, 59, 1, 0, "n8"), 36 | # 37 | (8.03375, 4.20625, 66, 58, 1, 0, "n11"), 38 | (8.06875, 2.04125, 35, 30, 1, 0, "n12"), 39 | (8.06875, 4.17125, 63, 41, 1, 0, "n13"), 40 | (8.09, 0.625, 57, 32, 1, 0, "n14"), 41 | (8.70375, 1.40625, 47, 31, 1, 0, "n15"), 42 | (9.2075, 0.9025, 57, 40, 1, 0, "n17"), 43 | (9.66625, 0.4825, 47, 30, 1, 0, "n18"), 44 | # 45 | (10.1375, 2.1025, 57, 39, 1, 0, "n20"), 46 | (10.14, 2.1, 35, 30, 1, 0, "n21"), 47 | (10.63, 1.61, 68, 57, 1, 0, "n22"), 48 | (11.09625, 1.14375, 68, 63, 1, 0, "n25"), 49 | (11.56, 0.68, 66, 65, 1, 0, "n28"), 50 | # 51 | (12.15875, 4.14125, 68, 61, 1, 0, "n31"), 52 | (12.18125, 1.98875, 40, 29, 1, 0, "n32"), 53 | (12.1875, 2.0675, 64, 48, 1, 0, "n33"), 54 | (12.1975, 1.9725, 56, 33, 1, 0, "n34"), 55 | (12.82, 1.35, 47, 27, 1, 0, "n35"), 56 | (13.30625, 0.86375, 56, 36, 1, 0, "n37"), 57 | (13.8325, 0.47125, 47, 25, 1, 0, "n38"), 58 | ], 59 | dtype=[ 60 | ("onset_sec", "<f4"), 61 | ("duration_sec", "<f4"), 62 | ("pitch", "<i4"), 63 | ("velocity", "<i4"), 64 | ("track", "<i4"), 65 | ("channel", "<i4"), 66 | ("id", "<U256"), 67 | ], 68 | ) 69 | result = estimate_time(some_performance_notes) 70 | 71 | self.assertTrue(np.all(result["meter_numerator"] == 4), "Incorrect meter.") 72 | self.assertTrue(len(result["beats"]) == 16, "Incorrect number of beats.") 73 | self.assertTrue(np.isclose(result["tempo"], 111, atol=1.0), "Incorrect tempo.") 74 | -------------------------------------------------------------------------------- /tests/test_times.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains tests for testing conversions from beats and quarters. 5 | """ 6 | import unittest 7 | 8 | import partitura.score as score 9 | import partitura 10 | 11 | 12 | def test_time_pairs(part, time_pairs): 13 | bm = part.beat_map 14 | ibm = part.inv_beat_map 15 | qm = part.quarter_map 16 | iqm = part.inv_quarter_map 17 | for tb, tq in time_pairs: 18 | assert qm(ibm(tb)) == tq 19 | assert bm(iqm(tq)) == tb 20 | 21 | 22 | class TestBeatVsQuarterTimes(unittest.TestCase): 23 | def test_times_1(self): 24 | # 4/4 anacrusis 25 | part = score.Part("id") 26 | # 1 div is 1 quarter 27 | part.set_quarter_duration(0, 1) 28 | # 4/4 at t=0 29 | part.add(score.TimeSignature(4, 4), 0) 30 | 31 | # ANACRUSIS 32 | # quarter note from t=0 to t=1 33 | part.add(score.Note("c", 4), 0, 1) 34 | # incomplete measure from t=0 to t=1 35 | part.add(score.Measure(), 0, 1) 36 | 37 | # whole note from t=1 to t=5 38 | part.add(score.Note("c", 4), 1, 5) 39 | # add missing measures 40 | score.add_measures(part) 41 | time_pairs = [(-1, -1), (0, 0), (4, 4)] 42 | test_time_pairs(part, time_pairs) 43 | 44 | def test_times_2(self): 45 | # 6/8 anacrusis 46 | part = score.Part("id") 47 | # 2 divs is 1 quarter 48 | part.set_quarter_duration(0, 2) 49 | part.add(score.TimeSignature(6, 8), 0) 50 | 51 | # ANACRUSIS 52 | part.add(score.Note("c", 4), 0, 3) 53 | part.add(score.Measure(), 0, 3) 54 | 55 | part.add(score.Note("c", 4), 3, 9) 56 | 57 | score.add_measures(part) 58 | 59 | time_pairs = [(-3, -1.5), (0, 0), (6, 3)] 60 | test_time_pairs(part, time_pairs) 61 | -------------------------------------------------------------------------------- /tests/test_tonal_tension.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains tests for the methods computing tonal tension. 5 | """ 6 | import unittest 7 | 8 | from partitura import ( 9 | EXAMPLE_MIDI, 10 | EXAMPLE_MUSICXML, 11 | load_performance_midi, 12 | load_musicxml, 13 | ) 14 | 15 | from partitura.musicanalysis.tonal_tension import ( 16 | prepare_note_array, 17 | estimate_tonaltension, 18 | ) 19 | import numpy as np 20 | 21 | 22 | class TestTonalTension(unittest.TestCase): 23 | score = load_musicxml(EXAMPLE_MUSICXML) 24 | performance = load_performance_midi(EXAMPLE_MIDI)[0] 25 | 26 | def test_prepare_notearray(self): 27 | target_note_array = np.array( 28 | [ 29 | (0.0, 2.0, 69, 64, "n0", "A", 0, 4, 0, -1), 30 | (1.0, 1.0, 72, 64, "n1", "C", 0, 5, 0, -1), 31 | (1.0, 1.0, 76, 64, "n2", "E", 0, 5, 0, -1), 32 | ], 33 | dtype=[ 34 | ("onset_sec", "<f4"), 35 | ("duration_sec", "<f4"), 36 | ("pitch", "<i4"), 37 | ("velocity", "<i4"), 38 | ("id", "<U256"), 39 | ("step", "<U1"), 40 | ("alter", "<i8"), 41 | ("octave", "<i8"), 42 | ("ks_fifths", "<i4"), 43 | ("ks_mode", "<i4"), 44 | ], 45 | ) 46 | note_array = prepare_note_array(self.performance) 47 | 48 | for name in target_note_array.dtype.names: 49 | 50 | self.assertTrue( 51 | np.all(note_array[name] == target_note_array[name]), 52 | f"Note arrays are not equal for field {name}", 53 | ) 54 | 55 | def test_estimate_tonaltension(self): 56 | tonal_tension = estimate_tonaltension(self.score) 57 | 58 | target_tension = np.array( 59 | [(0, 0, 0, 0.19651566), (2.0, 0.33333334, 0.07754743, 0.13506594)], 60 | dtype=[ 61 | ("onset_beat", "<f4"), 62 | ("cloud_diameter", "<f4"), 63 | ("cloud_momentum", "<f4"), 64 | ("tensile_strain", "<f4"), 65 | ], 66 | ) 67 | self.assertTrue( 68 | np.all(tonal_tension == target_tension), "estimated tension is incorrect!" 69 | ) 70 | -------------------------------------------------------------------------------- /tests/test_transpose.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains tests for the key estimation methods. 5 | """ 6 | import unittest 7 | 8 | from partitura import EXAMPLE_MUSICXML 9 | from partitura import load_score 10 | from partitura.score import Interval 11 | from partitura.utils.music import transpose 12 | import numpy as np 13 | 14 | 15 | class TransposeScoreByInterval(unittest.TestCase): 16 | def test_transpose(self): 17 | score = load_score(EXAMPLE_MUSICXML) 18 | interval = Interval(number=5, quality="d") 19 | new_score = transpose(score, interval) 20 | note_array = new_score.note_array(include_pitch_spelling=True) 21 | steps = np.array(["E", "G", "B"]) 22 | alters = np.array([-1, -1, -1]) 23 | octaves = np.array([5, 5, 5]) 24 | self.assertEqual(np.all(steps == note_array["step"]), True) 25 | self.assertEqual(np.all(alters == note_array["alter"]), True) 26 | self.assertEqual(np.all(octaves == note_array["octave"]), True) 27 | -------------------------------------------------------------------------------- /tests/test_urlload.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from partitura import load_score 3 | import numpy as np 4 | 5 | 6 | class TestImport(unittest.TestCase): 7 | def test_load_kern(self): 8 | score = load_score("https://raw.githubusercontent.com/CPJKU/partitura/refs/heads/main/partitura/assets/score_example.krn") 9 | note_array = score.note_array() 10 | self.assertTrue(np.all(note_array["pitch"] == [69, 72, 76])) 11 | 12 | def test_load_mei(self): 13 | score = load_score("https://raw.githubusercontent.com/CPJKU/partitura/refs/heads/main/partitura/assets/score_example.mei") 14 | note_array = score.note_array() 15 | self.assertTrue(np.all(note_array["pitch"] == [69, 72, 76])) 16 | 17 | def test_load_midi(self): 18 | score = load_score("https://raw.githubusercontent.com/CPJKU/partitura/refs/heads/main/partitura/assets/score_example.mid") 19 | note_array = score.note_array() 20 | self.assertTrue(np.all(note_array["pitch"] == [69, 72, 76])) 21 | 22 | def test_load_musicxml(self): 23 | score = load_score("https://raw.githubusercontent.com/CPJKU/partitura/refs/heads/main/partitura/assets/score_example.musicxml") 24 | note_array = score.note_array() 25 | self.assertTrue(np.all(note_array["pitch"] == [69, 72, 76])) 26 | 27 | -------------------------------------------------------------------------------- /tests/test_voice_estimation.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | This module contains tests for the voice estimation methods. 5 | """ 6 | import numpy as np 7 | 8 | import unittest 9 | from tempfile import TemporaryFile 10 | 11 | from tests import VOSA_TESTFILES 12 | 13 | from partitura import load_musicxml 14 | from partitura.musicanalysis import estimate_voices 15 | import partitura 16 | 17 | 18 | class TestVoSA(unittest.TestCase): 19 | """ 20 | Test VoSA 21 | """ 22 | 23 | score = load_musicxml(VOSA_TESTFILES[0]) 24 | 25 | def test_vosa_chew(self): 26 | # Example from Chew and Wu. 27 | voices = estimate_voices(self.score, monophonic_voices=True) 28 | # ground_truth_voices = np.array([3, 2, 1, 3, 3, 2, 3, 3, 2, 3, 29 | # 3, 1, 1, 2, 1, 1, 3, 2, 1, 1]) 30 | # ground_truth_voices = np.array( 31 | # [1, 2, 3, 1, 1, 2, 1, 1, 2, 1, 1, 3, 3, 2, 3, 3, 1, 2, 3, 3] 32 | # ) 33 | ground_truth_voices = np.array( 34 | [3, 2, 1, 1, 2, 1, 1, 2, 1, 1, 3, 1, 3, 3, 2, 3, 3, 2, 1, 3] 35 | ) 36 | self.assertTrue( 37 | np.all(voices == ground_truth_voices), "Incorrect voice assignment." 38 | ) 39 | 40 | self.assertTrue(True) 41 | 42 | def test_vosa_chew_chordnotes(self): 43 | # Example from Chew and Wu. 44 | voices = estimate_voices(self.score, monophonic_voices=False) 45 | print(voices) 46 | # ground_truth_voices = np.array( 47 | # [1, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 2, 3, 2, 2, 1, 1, 2, 2] 48 | # ) 49 | ground_truth_voices = np.array( 50 | [3, 3, 2, 2, 3, 2, 2, 3, 2, 2, 3, 2, 3, 3, 1, 3, 3, 2, 2, 3] 51 | ) 52 | self.assertTrue( 53 | np.all(voices == ground_truth_voices), "Incorrect voice assignment." 54 | ) 55 | self.assertTrue(True) 56 | --------------------------------------------------------------------------------