Coder Social home page Coder Social logo

mei-friend / mei-friend Goto Github PK

View Code? Open in Web Editor NEW
31.0 3.0 17.0 55.13 MB

The mei-friend Web Application: Editing MEI in the Browser

Home Page: https://mei-friend.mdw.ac.at

License: GNU Affero General Public License v3.0

CSS 0.76% HTML 1.05% JavaScript 97.17% Python 0.05% TypeScript 0.98%
digital-humanities edition editor mei music-encoding music-notation verovio mei-friend

mei-friend's Introduction

mei-friend is a ‘last mile’ editor for MEI music encodings intended to alleviate the common task of cleaning up encodings generated via optical music recognition, or via conversion from other formats, originally implemented as a plugin package for the Atom text editor. The mei-friend Web Application is a reworking of the tool as a full-featured, cross-browser compatible Web application, with optimised performance and an extended set of features. The application is available online at https://mei-friend.mdw.ac.at.

Fundamental functionalities

mei-friend fundamental functionalities

Github workflow

mei-friend github workflow

Components

We use CodeMirror as our text editor, and Verovio as our music engraving engine. GitHub integration is provided using jsgit, jsgit-browser, and the GitHub REST API. XML-DOM manipulations are performed using tXml by Tobias Nickel. The MEI validation and RNG loading code is adapted from the implementation in the Verovio editor, kindly contributed by Laurent Pugin. It makes use of libxml2. Lute tablature formats are converted to MEI using luteconv by Paul Overell, via the luteconv-webui wrapper service developed by Stefan Szepe and hosted at mdw. PDF functionalities are provided by PDFKit by Devon Govett, using SVG-to-PDFKit. MIDI playback is implemented using html-midi-player. This is itself powered by Magenta.js, which also provides the SGM_Plus sound font used to sonify your encoding. Icons are taken from GitHub's Octicons repository.

Features

Editor. The CodeMirror editor implements important coding conveniences including code folding, line numbering, tag- and bracket matching and auto-closing; as well as alternate key mappings (e.g., ‘vim’, ‘emacs’). MEI-schema-informed autocomplete is also available.

File input and output. Files may be opened from the local file system (via a menu option or using drag’n’drop); from the Web via URL; or from GitHub, by specifying a user/organisation and selecting from the available repositories. GitHub integration allows users to log in, fork repositories, view logs, and commit changes. All Verovio-supported encoding formats are supported (MEI, uncompressed and compressed MusicXML, Humdrum, ABC, PAE). The current encoding can be downloaded as MEI, MIDI, and SVG. All interactions occur locally in the browser; nothing is uploaded anywhere, excepting GitHub commits. Editor content is persisted in local storage through page refreshes and browser restarts; support for persisting multiple files simultaneously is envisioned for future development.

Public repertoire. Our codebase includes a CSV file recording publicly licensed music encodings, which are offered through the ‘fork repository’ and ‘open URL’ interfaces, alongside a dedicated ‘public repertoire’ access point. Proposed additions to this repertoire meeting our requirements (publicly licensed files; available via GitHub or hosted on a CORS-enabled Web server) are gladly accepted via Github Issue or Pull Request.

Configurable display. Many aspects of the tool’s interface are user-configurable, including the orientation and size of the notation and editor panes; their scale factor / font-size; and colouring, via a selection of preconfigured themes, with the option of having the notation match the editor theme (or remain black on white); and, optionally setting the interface to follow the local system’s bright / dark mode settings. Crucially, Eulise’s circadian rhythm adjusts accordingly. These configurations are done via a dedicated ‘settings’ menu, which also exposes a large collection of tool-specific options for CodeMirror and Verovio.

Navigation. The interface supports musically meaningful navigation according to encoded sections, pages (first, prev, next, last, specified page number), and within displayed notes/rests. Due to the tightly coupled interaction between encoding (MEI text) and engraving (SVG image), selection and navigation occurs seamlessly across both modalities.

Pedagogy. To smooth the learning curve of users new to MEI, the MEI Guidelines are linked to from the ‘Help’ menu; further, users are able to directly look up documentation for the currently selected element through a keyboard shortcut / help menu item.

Editor functions. In addition to all features of the Atom plugin package, we now offer commands to insert and delete clefs, beam-spans, and spiccato articulation; to insert the vertical group (vgrp) attribute for selected elements supporting this attribute (such as dynam, dir, hairpin), with dynamic number attribution; and, to insert the supplied element around a selection and show all supplied elements in a configurable colour.

Validation against MEI schema. Based on the code of the Verovio editor kindly provided by Laurent Pugin, mei-friend automatically loads the RNG schema specified in the MEI file to validate the encoding. It makes use of Gnome’s libxml2. Validation behaviour is configurable (automatic or on-demand) through the mei-friend settings.

Facsimile support. mei-friend makes the content of the facsimile element accessible by displaying zone elements ontop of the surface images in a dedicated facsimile panel, providing interactive zone editing functionality (resizing, panning, inserting & deleting zones) as well as an automated workflow for ingesting external facsimile content into MEI encodings.

Annotation support. The annotation panel provides tooling for generating in-line elements, as well as for listing, navigating between, and visualising annotations. Support for stand-off Web Annotations is planned for future development.

Installation

To try out mei-friend, simply navigate to the production instance on https://mei-friend.mdw.ac.at. To run your own instance locally on your system, please follow the installation instructions.

Publications

Goebl, W., & Weigl, D. M. (2023). mei-friend v1.0: Music Encoding in the Browser. Encoding Cultures. Joint MEC and TEI Conference 2023, Paderborn, Germany. https://teimec2023.uni-paderborn.de/contributions/159.html

Goebl, W. & Weigl, D. M. (2023). The mei-friend Web Application: Editing MEI in the Browser. Music Encoding Conference Proceedings 2022 [Late-breaking Reports]. doi:10.17613/dnj6-yy29.

Goebl, W. & Weigl, D. M. (2022). Alleviating the Last Mile of Encoding: The mei-friend Package for the Atom Text Editor. In S. Münnich & D. Rizo (Eds.), Music Encoding Conference Proceedings 2021 (pp. 31–39). University of Alicante. doi:10.17613/fc1c-mx52 (Best Paper Award MEC'21)

Acknowledgements

The mei-friend Web application is developed by Werner Goebl (@wergo) and David M. Weigl (@musicog), Department of Music Acoustics – Wiener Klangstil (IWK), mdw – University of Music and Performing Arts Vienna. Development is undertaken as part of the Signature Sound Vienna Project. This research was funded by the Austrian Science Fund (FWF) P 34664-G. The mei-friend Atom plugin package was developed as part of TROMPA (Towards Richer Online Music Public-domain Archives), with funding from the European Union's Horizon 2020 research and innovation programme H2020-EU.3.6.3.1. under grant agreement No 770376.

License

The mei-friend Web application is published under the GNU AGPL 3.0 license.

mei-friend's People

Contributors

alessiolampis avatar annakijas1 avatar annplaksin avatar dependabot[bot] avatar montspampam avatar musicog avatar sseki27skt avatar sszepe avatar th-we avatar wergo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

mei-friend's Issues

Unexpected facsimile behaviour ("No surface element found for this page")

Reported by @sseki27skt - thanks!

Describe the bug
When loading zone-less encodings linked to facsimiles, with page breaks set to "automatic" and speed mode checked, the "No surface element found for this page (An initial pb element might be missing.)" message appears and the Verovio logo keeps spinning without loading the image. The problem arises whether or not "Full page" is checked in the facsimile control bar. No immediately informative messages on the console. Unchecking speed mode or choosing another page break setting causes the facsimile image to load successfully.

To Reproduce
Go to https://mei-friend.mdw.ac.at/?file=https://raw.githubusercontent.com/sseki27skt/gagaku_encoding/main/etenraku.mei&scale=56&breaks=auto&select=n1vxnhqi&notationOrientation=left&notationProportion=0.5888194613986545&facsimileOrientation=top&facsimileProportion=0.4894650129006186 to see the issue.

Note, when loading another facsimile-aligned encoding with zone information (Beethoven WoO57) the problem does not arise: https://mei-friend.mdw.ac.at/?file=https://raw.githubusercontent.com/trompamusic-encodings/Beethoven_WoO57_BreitkopfHaertel/master/Beethoven_WoO57-Breitkopf.mei&scale=56&breaks=auto&select=n1vxnhqi&notationOrientation=left&notationProportion=0.5888194613986545&facsimileOrientation=top&facsimileProportion=0.4894650129006186

Expected behavior
The facsimile image should load as expected when "Full page" is checked, and should show the "Facsimile without zones only visible in full page mode" message otherwise.

Desktop (please complete the following information):
Reproduced on Mac OS 13.3.1 / Firefox 117 and Chrome 117

Enhance installation docs

There is some information in the INSTALL.md but they are mentioned nowhere and I found them by chance.

Also: Is it really necessary to have a GitHub App registered for developing the core JS functionalities? Maybe there could be different levels of documentation (running locally, running locally + development, optional: Deploying on your own lab server --> links to other tutorials etc.)

Derived from the JOSS review in openjournals/joss-reviews#6002 (comment)

Gracefully handle absence of GH OAuth application

As raised in by the reviews in openjournals/joss-reviews#6002

It should be possible to run an mei-friend instance without having to set up a new GitHub OAuth application. The interface should gracefully detect and handle the absence of a server-side GH configuration by simply not showing the Login / Github menu button. The remainder of the application should otherwise work as normal.

endings spanning pages not rendered in speedmode

Endings are not rendered if they are spanning over multiple pages (so if a ending contains pb - works with sb because the whole ending is still being rendered on 1 page). On a single page they are rendered properly.

page1 NO speedmode:
p1_no_speedmode

page1 WITH speedmode:
p1_with_speedmode

page2 NO speedmode:
p2_no_speedmode

page2 WITH speedmode:
p2_with_speedmode

Test MEI
<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="https://music-encoding.org/schema/dev/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="https://music-encoding.org/schema/dev/mei-all.rng" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>
<mei xmlns="http://www.music-encoding.org/ns/mei" meiversion="5.0.0-dev">
   <meiHead>
      <fileDesc>
         <titleStmt>
            <title>Test endings speedmode</title>
            <respStmt />
         </titleStmt>
         <pubStmt>
            <date isodate="2022-11-07" type="encoding-date">2022-11-07</date>
         </pubStmt>
      </fileDesc>
      <encodingDesc xml:id="encodingdesc-1en8nk">
         <appInfo xml:id="appinfo-1xnh1v7">
            <application xml:id="application-1c1ldr5" isodate="2022-11-07T10:37:51" version="3.13.0-dev-3d3bfaf">
               <name xml:id="name-17au1kd">Verovio</name>
               <p xml:id="p-1ibfh1b">Transcoded from MusicXML</p>
            </application>
         </appInfo>
      </encodingDesc>
   </meiHead>
   <music>
      <body>
         <mdiv>
            <score>
               <scoreDef ending.rend="top">
                  <staffGrp>
                     <staffGrp bar.thru="true">
                        <grpSym symbol="bracket" />
                        <staffDef n="1" lines="5" ppq="1">
                           <label>Flöte</label>
                           <labelAbbr>Fl.</labelAbbr>
                           <instrDef midi.channel="0" midi.instrnum="73" midi.volume="78.00%" />
                           <clef shape="G" line="2" />
                           <keySig sig="0" />
                           <meterSig count="4" unit="4" />
                        </staffDef>
                        <staffDef n="2" lines="5" ppq="1">
                           <label>Oboe</label>
                           <labelAbbr>Ob.</labelAbbr>
                           <instrDef midi.channel="1" midi.instrnum="68" midi.volume="78.00%" />
                           <clef shape="G" line="2" />
                           <keySig sig="0" />
                           <meterSig count="4" unit="4" />
                        </staffDef>
                     </staffGrp>
                     <staffDef n="3" lines="5" ppq="1">
                        <label>Pauken</label>
                        <labelAbbr>Pk.</labelAbbr>
                        <instrDef midi.channel="2" midi.instrnum="47" midi.volume="78.00%" />
                        <clef shape="F" line="4" />
                        <keySig sig="0" />
                        <meterSig count="4" unit="4" />
                     </staffDef>
                     <staffGrp bar.thru="true">
                        <label>Harfe</label>
                        <labelAbbr>Hrf.</labelAbbr>
                        <instrDef midi.channel="3" midi.instrnum="46" midi.volume="78.00%" />
                        <staffDef n="4" lines="5" ppq="1">
                           <clef shape="G" line="2" />
                           <keySig sig="0" />
                           <meterSig count="4" unit="4" />
                        </staffDef>
                        <staffDef n="5" lines="5" ppq="1">
                           <clef shape="F" line="4" />
                           <keySig sig="0" />
                           <meterSig count="4" unit="4" />
                        </staffDef>
                        <grpSym symbol="brace" />
                     </staffGrp>
                     <staffGrp bar.thru="true">
                        <grpSym symbol="bracket" />
                        <staffGrp>
                           <grpSym symbol="bracketsq" />
                           <staffDef n="6" lines="5" ppq="1">
                              <label>Violine 1</label>
                              <labelAbbr>Vl. 1</labelAbbr>
                              <instrDef midi.channel="6" midi.instrnum="40" midi.volume="78.00%" />
                              <clef shape="G" line="2" />
                              <keySig sig="0" />
                              <meterSig count="4" unit="4" />
                           </staffDef>
                           <staffDef n="7" lines="5" ppq="1">
                              <label>Violine 2</label>
                              <labelAbbr>Vl. 2</labelAbbr>
                              <instrDef midi.channel="10" midi.instrnum="40" midi.volume="78.00%" />
                              <clef shape="G" line="2" />
                              <keySig sig="0" />
                              <meterSig count="4" unit="4" />
                           </staffDef>
                        </staffGrp>
                        <staffDef n="8" lines="5" ppq="1">
                           <label>Bratsche</label>
                           <labelAbbr>Bra.</labelAbbr>
                           <instrDef midi.channel="13" midi.instrnum="41" midi.volume="78.00%" />
                           <clef shape="C" line="3" />
                           <keySig sig="0" />
                           <meterSig count="4" unit="4" />
                        </staffDef>
                        <staffDef n="9" lines="5" ppq="1">
                           <label>Violoncello</label>
                           <labelAbbr>Vc.</labelAbbr>
                           <instrDef midi.channel="0" midi.instrnum="42" midi.volume="78.00%" />
                           <clef shape="F" line="4" />
                           <keySig sig="0" />
                           <meterSig count="4" unit="4" />
                        </staffDef>
                        <staffDef n="10" lines="5" ppq="1" trans.diat="-7" trans.semi="-12">
                           <label>Kontrabass</label>
                           <labelAbbr>Kb.</labelAbbr>
                           <instrDef midi.channel="3" midi.instrnum="43" midi.volume="78.00%" />
                           <clef shape="F" line="4" />
                           <keySig sig="0" />
                           <meterSig count="4" unit="4" />
                        </staffDef>
                     </staffGrp>
                  </staffGrp>
               </scoreDef>
               <section>
                  <measure n="1">
                     <staff n="1">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="2">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="3">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="4">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="5">
                        <layer n="5">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="6">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="7">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="8">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="4" pname="c" stem.dir="down" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="9">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="10">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                  </measure>
                  <measure n="4">
                     <staff n="1">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="2">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="3">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="4">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="5">
                        <layer n="5">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="6">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="7">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="8">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="4" pname="c" stem.dir="down" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="9">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="10">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                  </measure>
                  <ending lendsym="angledown" n="1">
                     <measure n="5a">
                        <staff n="1">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="2">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="3">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="4">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="5">
                           <layer n="5">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="6">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="7">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="8">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="4" pname="c" stem.dir="down" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="9">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="10">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                     </measure>
                     <measure n="7a">
                        <staff n="1">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="2">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="3">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="4">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="5">
                           <layer n="5">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="6">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="7">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="8">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="4" pname="c" stem.dir="down" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="9">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="10">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                     </measure>
                     <pb />
                     <measure n="8a">
                        <staff n="1">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="2">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="3">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="4">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="5">
                           <layer n="5">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="6">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="7">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="8">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="4" pname="c" stem.dir="down" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="9">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="10">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                     </measure>
                  </ending>
                  <ending lendsym="angledown" n="2">
                     <measure n="5b">
                        <staff n="1">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="2">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="3">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="4">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="5">
                           <layer n="5">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="6">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="7">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="8">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="4" pname="c" stem.dir="down" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="9">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="10">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                     </measure>
                     <measure n="6b">
                        <staff n="1">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="2">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="3">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="4">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="5">
                           <layer n="5">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="6">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="7">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="8">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="4" pname="c" stem.dir="down" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="9">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="10">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                     </measure>
                  </ending>
                  <pb />
                  <measure n="7">
                     <staff n="1">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="2">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="3">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="4">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="5">
                        <layer n="5">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="6">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="7">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="8">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="4" pname="c" stem.dir="down" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="9">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="10">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                  </measure>
                  <ending lendsym="angledown" n="1">
                     <measure n="8a">
                        <staff n="1">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="2">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="3">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="4">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="5">
                           <layer n="5">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="6">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="7">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="8">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="4" pname="c" stem.dir="down" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="9">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="10">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                     </measure>
                  </ending>
                  <ending lendsym="angledown" n="2">
                     <measure n="8b">
                        <staff n="1">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="2">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="3">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="4">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="5">
                           <layer n="5">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="6">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="7">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="8">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="4" pname="c" stem.dir="down" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="9">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="10">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                     </measure>
                  </ending>
                  <pb />
                  <ending lendsym="angledown" n="3">
                     <measure n="8c">
                        <staff n="1">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="2">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="3">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="4">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="5">
                           <layer n="5">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="6">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="7">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="8">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="4" pname="c" stem.dir="down" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="9">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="10">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                     </measure>
                  </ending>
                  <measure n="9">
                     <staff n="1">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="2">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="3">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="4">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="5">
                        <layer n="5">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="6">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="7">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="8">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="4" pname="c" stem.dir="down" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="9">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="10">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                  </measure>
                  <measure n="10">
                     <staff n="1">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="2">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="3">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="4">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="5">
                        <layer n="5">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="6">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="7">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="8">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="4" pname="c" stem.dir="down" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="9">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="10">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                  </measure>
                  <pb />
                  <measure n="11">
                     <staff n="1">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="2">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="3">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="4">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="5">
                        <layer n="5">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="6">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="7">
                        <layer n="1">
                           <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                        </layer>
                     </staff>
                     <staff n="8">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="4" pname="c" stem.dir="down" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="9">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                     <staff n="10">
                        <layer n="1">
                           <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                           <rest dur.ppq="1" dur="4" />
                           <rest dur.ppq="2" dur="2" />
                        </layer>
                     </staff>
                  </measure>
                  <ending lendsym="angledown" n="1">
                     <measure n="12a">
                        <staff n="1">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="2">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="3">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="4">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="5">
                           <layer n="5">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="6">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="7">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="8">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="4" pname="c" stem.dir="down" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="9">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="10">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                     </measure>
                     <measure n="13a">
                        <staff n="1">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="2">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="3">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="4">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="5">
                           <layer n="5">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="6">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="7">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="8">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="4" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="9">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="3" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="10">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="3" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                     </measure>
                  </ending>
                  <ending lendsym="angledown" n="2">
                     <measure right="end" n="12b">
                        <staff n="1">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="2">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="3">
                           <layer n="1">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="4">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="5">
                           <layer n="5">
                              <note dur.ppq="1" dur="4" oct="3" pname="c" stem.dir="up" />
                              <rest dur.ppq="1" dur="4" />
                              <rest dur.ppq="2" dur="2" />
                           </layer>
                        </staff>
                        <staff n="6">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="7">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="5" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="8">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="4" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="9">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="3" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                        <staff n="10">
                           <layer n="1">
                              <note dur.ppq="4" dur="1" oct="3" pname="c" stem.dir="down" />
                           </layer>
                        </staff>
                     </measure>
                  </ending>
               </section>
            </score>
         </mdiv>
      </body>
   </music>
</mei>


Menu item to turn on/off measure numbers

Problem.
A lot of pieces don't use measure numbers. Currently you have to navigate to and add @mnum.visible="false" by hand. Also it would be nice if turning of measures in musescore would translate, but I'm not sure whether the musescore to musicxml export even manages that (quick testing indicates no)

Potential Solution
Under the Manipulate tab an option to toogle measure numbers which would add (or change) @mnum.visible to "true" or "false". Maybe even a shortcut.

Loading on Safari breaks with undefined variable

Your issue may already be reported!
Please search on the issue tracker before creating a new bug report.

Error Code

image

Describe the bug

Lines 838-841 in main.js check to see if the browser is Safari. However, this check fails because the variable lang is not defined.

https://github.com/mei-friend/mei-friend/blob/main/app/static/lib/main.js#L838-L841

To Reproduce

Load https://mei-friend.mdw.ac.at with Safari.

Desktop (please complete the following information):

  • OS: macOS Ventura 13.3
  • Browser Safari
  • Version 16.4

place="between" for all elements with att.placement

When inserting control elements, mei-friend currently supports only "above" or "below" for @place (using X as keyboard shortcut).

It would be desirable to have @place="between" available through a keyboard shortcut as well.

Request: add CTRL + X to change from @place="above|below" to @place="between" (and back, when pressing it multiple times"). Simultaneously, @staff needs to be adapted as well (to @staff="1 2" for a solo piano score). This should be computed dynamically from the closest staffGrp element of the selected element.

Keyboard shortcut to switch modality focus between notation and encoding

Is your feature request related to a problem? Please describe.
Although many keyboard shortcuts now work in either the encoding or notation modalities, some are still notation only. For example, when entering a new <note> element, I have to either type stem.dir="up" or click on the note in the notation and press "x" (after first pressing ctrl+M to assign an xml:id if required) if I want to set the stem direction. For this kind of situation, it would be convenient to have a keyboard shortcut that switches focus from the notation to the encoding and vice versa.

Describe the solution you'd like
I would propose a function triggered by a keyboard shortcut (proposal: ctrl-space) that:

  1. Assigns an XML:ID to the current element if working in the editor panel and one is required;
  2. Switches focus to the same element in the other modality's panel, where this is possible.

In the example, I could finish typing my new note element (without having to specify xml:id or stem.dir), press the new shortcut to assign an XML:ID and jump to the graphical representation of the new note, and press X to flip the stem direction.

Add contributor guidelines

per JOSS Review openjournals/joss-reviews#6002

You need to provide contributor guidelines:

Are there clear guidelines for third parties wishing to 1) Contribute to the software 2) Report issues or problems with the software 3) Seek support

GitHub has documentation and examples for making a contributing guidelines document, which should help you with getting started: https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/setting-guidelines-for-repository-contributors

Add Unit-Tests for core features

Unit-Tests are currently missing. You could start with testing core functionalities such as importing MusicXML files and checking against an expected MEI-output. These also give devs a good starting point to understand the inner functionalities of your software.

Derived from the JOSS review in openjournals/joss-reviews#6002 (comment)

User should be alerted to local storage use (GDPR compliance)

Since there is persistent local storage being used, even if it isn't sent anywhere else, I believe the site is required to inform/receive consent from the user – even if turning that feature off is impossible.

I'd suggest a simple pop-up the first time the user lands on the editor.

All control elements added with @staff attribute

(Raised by @o-sapov) Currently, control elements (such as slur, tie, dynam) are added only with @startid and @place attributes, but lack a @staff attribute. The guidelines flag @staff as recommended.

Request: add @staff attribute when adding a control element.

Note / rest insertion and conversion

Is your feature request related to a problem? Please describe.
It is not currently possible to insert note or rest elements without manually encoding them. This should be possible to do from the notation panel using menu or keyboard shortcuts.

Describe the solution you'd like
The following new keyboard shortcuts for the notation panel:

"ctrl-alt-n" => insert new note. This should be created immediately after the currently (last-)selected one, or as the new last note on the currently visible notation fragment (e.g., page). It should copy @pname, @oct, @dur from the nearest predecessor note (or otherwise default to 'c', '4', '4').

"r" => convert from a <note> to a <rest>, and vice versa. Retain @dur. Use @ploc and @oloc to retain @pname and @oct where available. When converting from rest to note (without @pname and/or @oct) use the values of the nearest predecessor note or default as above.

Add app/choice functionality

As already mentioned but I almost forgot to write the promised issue, here it is:
One very useful function might be to help users add editorial markup. Especially beginners are struggling with adding editorial markup. mei-friend might be able to help with providing standard templates (reduces accidental typos etc.).

A user might select a certain portion of the MEI file and then ask for surrounding it with an <app> element while the selection will be put into the <lem>, like:

<note pname="a" oct="4" dur="8">
    <refrain>
        <syl wordpos="t">rah!</syl>
    </refrain>
</note>
<note pname="g" oct="4" dur="8">
    <refrain>
        <syl>and</syl>
    </refrain>
</note>

... becomes ...

<app>
    <lem>
        <note pname="a" oct="4" dur="8">
            <refrain>
                <syl wordpos="t">rah!</syl>
            </refrain>
        </note>
        <note pname="g" oct="4" dur="8">
            <refrain>
                <syl>and</syl>
            </refrain>
        </note>
    </lem>
    <rdg>
       <!-- add reading here -->
    </rdg>
</app>

Or ask where the selection should be put...
If useful, that feature might be as well expanded for common cases of <choice> etc.

Of course, this will lead quickly to some general UI-related questions like: Should empty @source attributes be added automatically or not?
Please, consider it more as a suggestion than a request.

<meiHead> metadata not rendering

Error Code
None.

Describe the bug
I cannot get the Verovio renderer to display metadata from . Changing the value for 'Header' in the Verovio settings does not correct the problem.

To Reproduce
Steps to reproduce the behavior:

  1. Select an MEI file with metadata in (i.e., title, composer, etc.), but make sure it does not have any elements.
  2. Load the file into mei-friend

Expected behavior
In the Verovio editor, basic metadata under shows appropriately and can be edited. The same behaviour would be expected here.

Screenshots
mei-friend-Ps59-xml
Verovio-Editor

Desktop (please complete the following information):

  • OS: Windows 11
  • Browser: Chrome
  • Version: 116

Additional context
None.

Insert control elements with time stamps rather than start/endids

Currently, control elements (such as <dynam>, <dir>, <hairpin>) are inserted by keyboard shortcuts with @startid and @endid pointing to the selected elements.

It would be useful to have an option to insert those control elements with @tstamp and @tstamp2 attributes instead.

importing xml with staff-crossing during beam leads to <beamspan> instead of <beam>

Describe the bug
When some notes that share a beam with others that are on a different staff-line (common i.e. in piano music) in mxl and that gets imported to mei, it will create seperate notes and at the end of the measure a <beamSpan>. The rendered score therefor looks like individual notes in different staffs with a beam just put over them (see screenshots).

To Reproduce
Steps to reproduce the behavior:

  1. Open Musescore-file with at least two staffs to create mxl-file
  2. Type any notes connected with a beam (eigth or shorter)
  3. use ctr + shift + uparrow/downarrow on some notes to force them to change staff
  4. export mxl and load it into mei-friend

Expected behavior
Mei-friend should create a normal <beam> containing the notes where some of them have @staff="1" and others @staff="2" and the appropriate @stemdir. If you type that in manually it renders correctly.

Screenshots
Wrong:
grafik

Correct (MuseScore):
grafik

Desktop (please complete the following information):

  • OS: Windows 11
  • Browser: Firefox
  • Version: current

Additional context
Attached are the(uncompress musicmxl file and the mei fileas txt. I also tested to reopen the mxl in musescore to see whether that might have been an export issue for musescore but that is not the case - musescore renders the beam correctly.
northertest.mei.txt
nothertest.txt

Check for elements pointing to non-existing target ids

Problem
Whenever an element is removed that can be referenced by spanning elements (like <note> in most cases) the spanning element can not be rendered anymore. This makes it very difficult to find and delete the spanning element manually so there are no dead elements in your file.

Solution
Either the spanning element should be deleted right away when the referenced element is deleted or a function could be implemented that removes all spanning elements that reference non-existent elements.
Because reinserting a spanning element is relatively easy for most of them, just deleting them right away would probably be best for workflow.

Flag when xml:ids are missing for clicked element

In case of a missing xml:id in the encoding, mei-friend currently does not complain to user clicking on the rendered element in the notation. This prevents the notation from interacting with the encoding editor which may confuse users.

Feature request

It would be useful to have a warning indicator in that case saying that the clicked element cannot be found in the encoding (probably due to a missing xml:id).

Inserting within-measure slur without meter.count / unit causes misleading warning message

Describe the bug
When working with an encoding lacking @meter.count / @meter.unit in scoreDef / staffDef, or the equivalent @count / @unit in meterSig, placing a slur between two notes within the same measure currently results in a warning message like:

Attention with slur (slur-xml-id): note1-xml-id and note2-xml-id are on the same beat position -1

Instead of limiting ourselves to these meter attributes, any valid att.meterSigDefault.log / att.meterSig.log attributes should be supported. Particularly, I came across this issue when working with @meter.sym="common".

To Reproduce
Steps to reproduce the behavior:

  1. Go to https://mei-friend.mdw.ac.at?file=https://gist.githubusercontent.com/musicog/e63470e5b6f143829493b5debf11a16c/raw/6b7d1a72429481ab01652edb2224ab08877005c1/gistfile1.txt
  2. Select two notes in the same measure
  3. Press s or Insert->Slur to add a slur
  4. See warning message (slur is placed correctly)

Expected behavior
The warning is misleading in this case and should not be shown.

Desktop (please complete the following information):

  • OS: Fedora Linux
  • Browser: Firefox
  • Version: mei-friend 1.0.0

Facsimile with non-local images

Not sure if this is a bug or just yet missing functionality, but the facsimile viewer/editor doesn't seem to work with external images:

<graphic target="https://api.digitale-sammlungen.de/iiif/image/v2/bsb10527431_00282/full/full/0/default.jpg" />

It would be great if this would work too.

spanning elements over page beginning in speed mode

Spanning elements that end on the following page are not rendered with the correct length in speedmode.

A spanning element be rendered the whole number of bars given in the elements @tstamp2 minus 1, instead of taking the bars of the previous page into account.

Only happens in speedmode!

Encoded @color not shown

Elements with a @color attribute do not appear in that color in mei-friend (occurs under Firefox, Chrome, Safari under MacOS, but probably also under other OS). Problem with CSS hierarchy. (Thanks to @DILewis for telling us.)

Filter selected elements before inserting slurs etc

Problem:
When drag-selecting elements on the notation panel, accidentals or other elements may be included in the array of selected elements. These may hinder inserting control elements such as slurs on that selection.

Solution:
Make sure that inserting control elements works with all sorts of elements selected. Filter them upon inserting control elements so that the control elements successfully appear.

CMD-E for enclosing selection with tag

Add a keyboard shortcut to enclose selected text in the CodeMirror editor with a tag, to be typed in a small modal. Use CMD-E (for Mac) and similar for other OS as in Oxygen.

Allow note, chord, and rests for deletion

Only a limited number of element types are support for a delete operation. As requested by @RichardFreedman, more elements should be supported.

This feature request asks for

  • Deletion support for note, chord, rest, mRest, multiRest.
  • Whenever the selected element is the last inside an enclosing element, such as beam, tuplet, etc. that should be deleted as well.
  • All elements pointing to the deleted element through a @startid and @endid should be deleted as well.

Fail jumping to first note of new page when flip page in a mensural file

Describe the bug
Of course, this report is against the backdrop of limited mensural support...
When the function "Automatical flip page to current cursor position" is active and one tries to manually change the page, when a selection is made, flipping to another page won't work

To Reproduce
Steps to reproduce the behavior:

  1. Load mensural file, e.g. the attached one
  2. Turn off Speedmode (won't work anyway), use automatic breaking and have automatic updated turned on.
  3. Highlight something on the first page; optionally de-select the highlighted note in the rendering by clicking somewhere else
  4. Try to flip a page
  5. Be stuck on the page with the once selected element

Expected behavior
In CMN, the first note of the new page would be selected.
As a quick workaround, a selection could be removed, if no other selection is possible. Then page flipping should still be possible (hopefully)

Desktop (please complete the following information):

  • OS: Windows 11
  • Browser: Firefox
  • Version: 104.0.2 (64-Bit)

Additional context
Here is a short file for testing:
M-AveMarisStella_Jena_resolved.zip

Fail to load responsibility from file at start and add to markup (e.g. <supplied>)

This bug is two-folded:

  1. When adding a new person or cooperation with @xml:id inside a <respStmt> in the header, the list of choices within the settings does not update. Reloading the page is a quick workaround for this one, at least when you're not currently locally debugging something else...
  2. If there is a value chosen within the settings menu, e.g. because there is only one valid person with an id in the file, this value is somehow not loaded into viewer.respId. When adding markup, like <supplied>, v.respId is still empty and no responsibility will be added to the markup.

Regarding 1, I don't have a clue how to solve that. Maybe it's not too important because there is a workaround anyway.

Regarding 2, I am currently struggling to understand the mechanics of how settings are added, applied and modified, but as far as I can see:
When loading mei-friend document.getElementById('respSelect').value is still empty. But when I look into the settings panel, I see a chosen id:
grafik
Using an mei file with two possible responsibilities to choose from, and switching from the first option to the second in the list, it works:
grafik

I am not completely sure, but it seems like the initial attempt of reading the available options into respSelect while loading the file into mei-friend seems to fail.

alt-f for search clashes with forward-word in emacs mode

Reported by @DILewis

Version: mei-friend 0.3.4 (25 Feb 2022)

Systems: Reproduced on Mac (Firefox) and Linux

Problem: emacs META-f key combination (alt-f in CodeMirror) works as expected at https://codemirror.net/demo/emacs.html but instead pulls up the "find in file" interface in mei-friend

Repro:

  1. Go to https://codemirror.net/demo/emacs.html and click into the editor
  2. Press Alt+f
  3. Cursor correctly jumps to the next word (META-f => "forward-word" in emacs)
  4. Go to mei-friend and switch on emacs keybindings in the settings
  5. Click in the editor and press alt+f
  6. Instead of jumping to the next word as expected, the find-in-file mode opens up

Cause: in the defaultCodeMirrorOptions we are setting extraKeys to contain: "Alt-F": "findPersistent"

Proposed solution:: Can we switch to Ctrl-S / Cmd-S for search instead? We would have to preventDefault to circumvent browser "save page"

Allow zones to be added graphically

Currently it is only possible to edit zone boxes graphically, but in the facsimile view it is not possible to add a new one.

A modular system to add facsimiles would be nice:

  • "Add facsimile" would add an empty facsimile tree into the MEI
  • "Add graphic" would let you choose an image (and add the element to the surface)
  • "Create new zone" would add an empty box (somehow)

Error 1649499359728 in Firefox while being logged into GitHub

Is someone else able to reproduce this behaviour or is this only happening on my machine?
It would be very kind if someone could try to reproduce this to see if this needs to be fixed.

Error Code
1649499359728

Describe the bug
While being logged in with GitHub, I receive an error message when clicking this link:
https://mei-friend.mdw.ac.at/?file=https://raw.githubusercontent.com/EarlyMusicTheory/mei-mensural-skeleton/main/MEI-mensural-skeleton.mei&scale=80&breaks=encoded&speed=false&notationOrientation=top

It works fine in Chrome and also with Firefox when not being logged in.

To Reproduce

  1. Use Firefox
  2. Log into your GitHub account with mei-friend
  3. Click; https://mei-friend.mdw.ac.at/?file=https://raw.githubusercontent.com/EarlyMusicTheory/mei-mensural-skeleton/main/MEI-mensural-skeleton.mei&scale=80&breaks=encoded&speed=false&notationOrientation=top
  4. See error message
  5. Everything works fine after the error message is closed.

Screenshots
grafik

Desktop:

  • Windows 11
  • Firefox 115.0.2 (64-Bit)

Selected element(s) vanishes after commit action

After a git commit, mei-friend re-loads first page, irrespective of the current page selected when git commit was exectuted. (And page-flipping ist not working, unless some notation elements are clicked.)

Expected behavior: when committing a change, the same page (and potentially the same selected element) should persist.

Respect key on pitch manipulation

When moving a note up/down it would be good to take the current key signature into consideration.

In a piece in G major:

  • moving up diatonically from an e adds an @acid.ges="s" to the f note
  • moving up chromatically from an e adds an accid child with @accid="n"
  • moving down chromatically from an g adds an @acid.ges="s" to an f note instead of a g with accid f

Make file name in header editable

Is your feature request related to a problem? Please describe.
When editing a file, or esp. copy-paste code into mei-friend for refining, the filename of a downloaded file won't change.

grafik

Describe the solution you'd like
Make the file name editable to download a file with its new file name

Download MEI and SVG not working in Safari

Clicking on Save MEI and Save SVG is doing nothing when using Safari (version 16.5.2 under MacOS Ventura), but works fine, i.e. downloads MEI or SVG respectively, under current Firefox or Chrome browsers. (Thanks to @DILewis for telling us.)

Keyboard shortcut CTRL + S used twice on Windows/Linux

The keybaord shortcut CTRL + S is used for inserting a slur with place="below"; but on Windows/Linux it is also the save MEI command.

Solution: disable inserting slur below on Windows/Linux.

(or @o-sapov: change slur shortcut to R and CTRL + R for below)

Keyboard shortcuts in editor take away useful functionality

Many keyboard shortcuts that used to work only when the notation panel is in focus have been added to also work when the encoding panel is in focus (see #50).

Problem: However, some important common navigation shortcuts in the editor, such as CMD + LEFT/RIGHT (CTRL + LEFT/RIGHT on Win/Linux) to jump to start/end of line are taken by notation to change page etc.

Solution: remove those navigation key bindings from encoding panel.

Adding supplied for @artic and @accid

(Raised by @o-sapov)
Currently, supplied elements may only be added around selected elements (using shortcut U).

Feature request:

  1. Insert – Supplied artic (CTRL + U) on selected note/chord: makes element out of @artic attribute (if existing) and surrounds it with a supplied element.
  2. Insert – Supplied accid (CTRL + SHIFT + U) on selected note: makes element out of @accid attribute (if existing) and surrounds it with a suppliedelement.

Saving locally prevents from using git commits

If after a change the MEI-file is saved locally you can not commit the change to a git repository.
That means if you work using github and load your files from there the change can not be saved in the repository anymore after saving the file locally on your device.

You either should be able to always commit if your file is loaded from github or be able to always commit no matter what.

Versions used:
mei-friend staging-0.9.1
Verovio 3.16.0-6dc700d

Misleading warning when clicking certain notation elements

Through #10 a warning is displayed when any element without a corresponding xml:id is clicked in the notation. This should be restricted to only show for SVG elements where a straightfoward correspondence to identifiable MEI elements can be established.

To Reproduce

  1. Open https://mei-friend.mdw.ac.at and the default encoding (Beethoven WoO70)
  2. Press Ctrl+M, note that 0 new xml:ids are added (that is, every MEI element that needs one has one already)
  3. Click on a note stem (its own element in the SVG, but not an element in the MEI), notice that a warning is now displayed and that it is misleading in this case, since Manipulate->Add IDs won't change anything
  4. Close the warning, click on the word "TEMA."
  5. The warning appears again, and is again misleading since Verovio doesn't persist the ID of the (MEI) <rend> into the (SVG) <tspan> (maybe this is a Verovio bug?)

Expected behavior
The warning message should only appear in cases where following the advice of Manipulate->Add IDs would fix the problem. Additionally, we should consider special heuristics, e.g., where clicking on the note stem could scroll to the respective <note> in the MEI.

Version
mei-friend v1.0.3
Verovio v4.0.1

Map (most) keyboard shortcuts to editor

Many keyboard shortcuts work when the notation panel is activated (such as CMD-M or CMD-SHIFT-M for adding or removing xml.ids from encoding), but not when the CodeMirror editor is activated (thus, when one is directly editing MEI).

Map all keyboard shortcuts with modifier keys in CodeMirror as well.

Add developer documentation

The developer documentation is very sparse to non-existing currently :-).
I know, this is much work but will increase the value of the software tremendously. Start with a documentation of the folder structure and the files. Give pointers to the main files and where developers could find a handle. It could also be a short screen-cast showing people how to implement new features.

Derived from the JOSS review in openjournals/joss-reviews#6002 (comment)

Shift pitch chromatically up/down

Shift pitch chromatically up (with sharps on c, d, f, g, and a) and down (with flats on d, e, g, a, and b) through keyboard shortcuts and menu items. (Keep current diatonic pitch shifting intact.)

Compare to functionality in MuseScore.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.