{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\"FMP\"\n", "\"AudioLabs\"\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\"C1\"\n", "

Symbolic Format: Rendering

\n", "
\n", "\n", "
\n", "\n", "

\n", "In this notebook, we discuss some software tools for rendering sheet music. Furthermore, we explain some functionality of the Python library music21.\n", "

\n", "\n", "
\n", " Important Note: To keep the notebook executable without additional software dependencies, we provide all code cells as comments. To indicate the code cells' output (given a proper installation of the dependencies), we include static images.\n", "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Extra Software\n", "\n", "The process of sheet music rendering refers to the computerized rendition of a symbolic music format into graphical musical symbols, e.g. modern staff notation. There exist several software tools for sheet music rendering, including text-based programs like [LilyPond](http://lilypond.org) and [Verovio](https://www.verovio.org), as well as WYSIWYG sheet music editors like [MuseScore](https://musescore.org) and [Sibelius](https://www.avid.com/de/sibelius).\n", "\n", "For rendering sheet music from Python, we recommend to use the package `music21`.\n", "For a full introduction, we refer to the [documentation of `music21`](https://web.mit.edu/music21/doc/).\n", "It offers various options to feed its internal data structure to a renderer.\n", "One option is to internally convert `music21`'s data structure to the MusicXML format (for more details, see the [MusicXML notebook](../C1/C1S2_MusicXML.html)) and use MuseScore to graphically render the sheet music. With a working Python environment where `music21` is installed, three more steps are needed to get it to work.\n", "\n", "* First, one needs to install MuseScore, which can be [downloaded freely](https://musescore.org/en/download) on its website. Second, one needs to tell `music21` the path to the MuseScore binary.\n", "* Second, we have to set up a `music21` user environment file.\n", "* Third, we have to register the path to MuseScore for `music21`.\n", "\n", "Those three steps only need to be executed one time.\n", "\n", "The following code cell sets up a `music21` user environment file:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "execution": { "iopub.execute_input": "2024-02-15T08:45:52.230046Z", "iopub.status.busy": "2024-02-15T08:45:52.229753Z", "iopub.status.idle": "2024-02-15T08:45:53.569096Z", "shell.execute_reply": "2024-02-15T08:45:53.567732Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Path to music21 environment /Users/zal/.music21rc\n", "{'directoryScratch': None, 'lilypondPath': '/Applications/Lilypond.app/Contents/Resources/bin/lilypond', 'lilypondVersion': None, 'lilypondFormat': 'pdf', 'lilypondBackend': 'ps', 'musicxmlPath': '/Applications/MuseScore 3.app/Contents/MacOS/mscore', 'midiPath': '/Applications/Utilities/QuickTime Player 7.app', 'graphicsPath': '/Applications/Preview.app', 'vectorPath': '/Applications/Preview.app', 'pdfPath': '/Applications/Preview.app', 'braillePath': None, 'musescoreDirectPNGPath': '/Applications/MuseScore 3.app/Contents/MacOS/mscore', 'showFormat': 'musicxml', 'writeFormat': 'musicxml', 'ipythonShowFormat': 'ipython.musicxml.png', 'autoDownload': 'ask', 'debug': '0', 'warnings': '1', 'localCorpusSettings': LocalCorpusSettings([]), 'localCorporaSettings': {}, 'manualCoreCorpusPath': None}\n" ] } ], "source": [ "import os\n", "import music21 as m21\n", "\n", "us = m21.environment.UserSettings()\n", "us_path = us.getSettingsPath()\n", "if not os.path.exists(us_path):\n", " us.create()\n", "print('Path to music21 environment', us_path)\n", "print(us)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, we give the path to the MuseScore binary. The following code cell gives two typical locations for Linux and Windows environments. Note that this could be different on your system and has to be changed, possibly. Both, setting up the user environment file and the specification of the MuseScore path has to be executed only once.\n", "\n", "**Note**: The following example may not work on Windows yet. The reason for this is a bug in `music21`. This was [fixed](https://github.com/cuthbertLab/music21/pull/411) and will be solved in the next version of `music21`. However, currently the fix is not included the the latest version." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2024-02-15T08:45:53.611153Z", "iopub.status.busy": "2024-02-15T08:45:53.610826Z", "iopub.status.idle": "2024-02-15T08:45:53.614001Z", "shell.execute_reply": "2024-02-15T08:45:53.613228Z" } }, "outputs": [], "source": [ "# for linux\n", "# us['musescoreDirectPNGPath'] = '/usr/bin/mscore'\n", "# us['musicxmlPath'] = '/usr/bin/mscore'\n", "\n", "# for windows\n", "# us['musescoreDirectPNGPath'] = r'C:\\Program Files (x86)\\MuseScore 2\\bin\\MuseScore.exe' \n", "# us['musicxmlPath'] = r'C:\\Program Files (x86)\\MuseScore 2\\bin\\MuseScore.exe'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If the setup is correct, the following code cell should create a `music21` Note object and show its graphical rendition via MuseScore:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2024-02-15T08:45:53.617674Z", "iopub.status.busy": "2024-02-15T08:45:53.617311Z", "iopub.status.idle": "2024-02-15T08:45:53.620754Z", "shell.execute_reply": "2024-02-15T08:45:53.619984Z" } }, "outputs": [], "source": [ "# n = m21.note.Note('c')\n", "# n.show('ipython.musicxml.png')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\"Output " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another possibility is to use [LilyPond](http://lilypond.org) for rendering. Again, we need three steps to get it to work.\n", "\n", "* First we need to [install LilyPond](http://lilypond.org/download.html).\n", "* Second, we have to set up the `music21` user environment file (we already did that above).\n", "* Third, we have to register the path to Lilypond for `music21`. The following code cell again gives typical locations for Linux and Windows." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2024-02-15T08:45:53.624788Z", "iopub.status.busy": "2024-02-15T08:45:53.624426Z", "iopub.status.idle": "2024-02-15T08:45:53.628252Z", "shell.execute_reply": "2024-02-15T08:45:53.627564Z" } }, "outputs": [], "source": [ "# for linux\n", "# us['lilypondPath'] = '/usr/local/bin/lilypond'\n", "\n", "# for windows\n", "# us['lilypondPath'] = r'C:\\Program Files (x86)\\LilyPond\\usr\\bin\\lilypond.exe'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, we are able to render our simple note via Lilypond:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2024-02-15T08:45:53.631747Z", "iopub.status.busy": "2024-02-15T08:45:53.631387Z", "iopub.status.idle": "2024-02-15T08:45:53.634911Z", "shell.execute_reply": "2024-02-15T08:45:53.633882Z" } }, "outputs": [], "source": [ "# n.show('ipython.lily.png')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\"Output " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For creating a staff line with multiple notes, we add multiple `music21` objects to a `music21` Stream." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2024-02-15T08:45:53.638682Z", "iopub.status.busy": "2024-02-15T08:45:53.638377Z", "iopub.status.idle": "2024-02-15T08:45:53.642002Z", "shell.execute_reply": "2024-02-15T08:45:53.640796Z" } }, "outputs": [], "source": [ "# s = m21.stream.Stream()\n", "# s.append(m21.key.Key('E-'))\n", "# s.append(m21.meter.TimeSignature('2/4'))\n", "# s.append(m21.note.Rest(quarterLength=0.5))\n", "# s.append(m21.note.Note('g', quarterLength=0.5))\n", "# s.append(m21.note.Note('g', quarterLength=0.5))\n", "# s.append(m21.note.Note('g', quarterLength=0.5))\n", "# s.append(m21.note.Note('e-', quarterLength=2))\n", "\n", "# s.show('ipython.musicxml.png')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\"Output " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Instead of writing Python code to create a `music21` score, we can also read and display a MusicXML file." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2024-02-15T08:45:53.646316Z", "iopub.status.busy": "2024-02-15T08:45:53.646031Z", "iopub.status.idle": "2024-02-15T08:45:53.648767Z", "shell.execute_reply": "2024-02-15T08:45:53.648090Z" } }, "outputs": [], "source": [ "# fn_xml = os.path.join('..', 'data', 'C1', 'FMP_C1_F01_Beethoven_FateMotive_Sibelius.xml')\n", "# s = m21.converter.parse(fn_xml)\n", "# s.show('ipython.musicxml.png')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\"Output " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also read in a full orchestral score. Since such a score cannot be rendered on a single page, we can specify the measures that we want to show:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2024-02-15T08:45:53.652257Z", "iopub.status.busy": "2024-02-15T08:45:53.651958Z", "iopub.status.idle": "2024-02-15T08:45:53.655074Z", "shell.execute_reply": "2024-02-15T08:45:53.654261Z" } }, "outputs": [], "source": [ "# fn_xml = os.path.join('..', 'data', 'C1', 'FMP_C1_F10_Beethoven_Fifth-MM1-21_Sibelius-Orchestra.xml')\n", "# s = m21.converter.parse(fn_xml)\n", "# s.measures(1, 5).show('ipython.musicxml.png')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\"Output " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "Acknowledgment: This notebook was created by Frank Zalkow and Meinard Müller.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "
\"C0\"\"C1\"\"C2\"\"C3\"\"C4\"\"C5\"\"C6\"\"C7\"\"C8\"
" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.16" } }, "nbformat": 4, "nbformat_minor": 1 }