diff --git a/.babelrc b/.babelrc
new file mode 100644
index 0000000000000000000000000000000000000000..6b07a1c2fe70a348a59c7abd935190b98ff2f836
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,5 @@
+{
+ "presets": [
+ "@babel/preset-env"
+ ]
+}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..33cfa6c4ecdfd3cc741d657c4e3213d439e49303
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,11 @@
+.idea/*
+tmp/*
+/node_modules
+/coverage
+to-*.sh
+docs/.vuepress/.cache/*
+docs/.vuepress/.temp/*
+docs/.vuepress/.dist/*
+dist/report.html
+.eslintrc.json
+.DS_Store
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000000000000000000000000000000000000..1465b9d9feff6f76e598fd625ce27f39a0374bc7
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "docs/.vuepress/dist"]
+ path = docs/.vuepress/dist
+ url = https://github.com/paulrosen/abcjs.git
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..324f0a544b61d60a0f462c172690b4476eb05165
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,20 @@
+.idea/
+dist/*.html
+build-utils/
+docs/
+examples/
+font_generator/
+tests/
+tmp/
+
+.babelrc
+.eslintrc
+.gitmodules
+deploy-docs.sh
+docker-start.sh
+docker-build.sh
+docker-compose.yml
+Dockerfile
+start-version.sh
+webpack.config.js
+to-*.sh
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000000000000000000000000000000000000..ba38352b773ef9928394a81473383f5378529925
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,76 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, sex characteristics, gender identity and expression,
+level of experience, education, socio-economic status, nationality, personal
+appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at blog@paulrosen.net. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see
+https://www.contributor-covenant.org/faq
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000000000000000000000000000000000000..2b6ad1244bcd246469b531b648ed0baa8d6ca8dd
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1 @@
+Information about contributions to abcjs is available here: [Developers](https://paulrosen.github.io/abcjs/developers/pull-requests.html)
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..a7754c5e5542aebbedb62d7d23846297da5d8b50
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,9 @@
+FROM node:20.14.0
+
+RUN npm install -g npm@8.19.2
+
+RUN mkdir /srv/app && chown node:node /srv/app
+
+# USER node
+
+WORKDIR /srv/app
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000000000000000000000000000000000000..ad3b93938cfa345f4464caa5606495b5a5693a96
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,21 @@
+Copyright (c) 2009-2024 Paul Rosen and Gregory Dyke
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+**This text is from: http://opensource.org/licenses/MIT**
diff --git a/README0.md b/README0.md
new file mode 100644
index 0000000000000000000000000000000000000000..4014f09eca880a8d15489d150d530448f6fa8091
--- /dev/null
+++ b/README0.md
@@ -0,0 +1,127 @@
+
+
+# Javascript library for rendering standard music notation in a browser.
+
+This library makes it easy to incorporate **sheet music** into your **websites**. You can also turn visible **ABC** text into sheet music on websites that you don't own using a greasemonkey script, or change your own website that contains ABC text with no other changes than the addition of one javascript file. You can also generate **MIDI files** or play them directly in your browser.
+
+[List of Examples](https://cdn.rawgit.com/paulrosen/abcjs/main/examples/toc.html)
+
+Full documentation is here: [abcjs documentation](https://paulrosen.github.io/abcjs/)
+
+There is an organization that has a collection of useful projects related to abcjs called [abcjs-music](https://github.com/abcjs-music). See some examples there. If you have a project that you think would be of general interest and would like to add it to that organization, contact me.
+
+## Announcement: version 6.4.0
+
+The method for creating chord accompaniment has changed. Hopefully there aren't any regressions but if you have an example that doesn't match what it used to be, please open an issue.
+
+## Announcement: version 6.3.0
+
+Most users won't see any difference, but there was some changes to the underlying SVG structure for the top (the title, etc.) and bottom (the notes, etc.) text, so if your code depends on particular classes then this might be a breaking change. Hopefully the new structure will be clearer and will allow css to target particular parts easier.
+
+## Announcement: version 6.2.2
+
+There was a major bug in Firefox 112 that causes some lines to disappear. That is supposed to be fixed in Firefox 113 but in the meantime this update will take care of the problem.
+## Announcement: version 6.1.2
+
+There is a little difference in the generated SVG: Now each line is surrounded with a `` element. This probably won't affect your program unless you are doing very specific manipulation of the SVG.
+
+## Announcement: version 6.1.0
+
+There is a brand new transposing feature. This allows you to input an ABC string and get a new ABC back in a different key. See the documentation for details. I'm sure there are ways to expand this - let me know if your use case is missing.
+
+## Announcement: version 6.0.0
+
+After way too long, abcjs 6.0.0 is now out of beta.
+
+There are only a few bug fixes since the last beta.
+
+The current plan is to continue doing bug fixes and minor features to the 6.x.x branch, but version 7 is already in planning.
+
+There are some minor features that will still be added to the version 6 branch, along with fixing transposition.
+
+## Informal roadmap for version 7.0.0
+
+There will be some architecture changes which will go in a 7.0.0 release:
+
+* Improve the API for controlling the synth. That is, make the parameters less confusing.
+* Create a plugin architecture so that large features that are not widely used can be added without bloating this library.
+* Change the build to use typescript while still maintaining legacy browser capability.
+* Reduce the size of the library by optimizing code.
+* Control the spacing of the elements on the line better: support equal size measures, and support allowing control of the spacing between notes.
+* Improved documentation, particularly for synth.
+* Bug fixes.
+
+I anticipate that for a user that wants the most common functionality, the size of the library might be cut in half.
+
+Thanks, Paul
+
+
+## Major New Feature! 6.0.0-beta.36
+
+String tablature is now available by adding an option to the `renderAbc` parameters. See [tablature documentation](https://paulrosen.github.io/abcjs/visual/tablature.html)
+
+## Fix to audio in octave clefs 6.0.0-beta.31
+
+If you are using an octave clef (for instance `K:C clef=treble-8`) it will now sound an octave different. The octave calculation was happening twice.
+
+## Last version supporting midi.js is 6.0.0-beta.28
+
+The file [abcjs version supporting midi.js](https://github.com/paulrosen/historical-abcjs-versions/blob/main/version-6/abcjs_midi-min.js) is the last version of the old style of sound production that will receive updates.
+
+## Rename the default branch to `main`
+
+The default branch is now named `main`. If you have cloned this repo previously, you can change it with:
+```shell
+git branch -m master main
+git fetch origin
+git branch -u origin/main main
+```
+
+## New css for audio control 6.0.0-beta.27
+
+Be sure to download the latest abcjs-audio.css file if you are using it. If you are styling the audio control with your own css, add the rule:
+```css
+.abcjs-css-warning {
+ display: none;
+}
+```
+
+## Historical abcjs Packages 6.0.0-beta.27
+
+Old versions of abcjs have been removed from this repo. If you are looking for them, you can find them here: [Historical Versions](https://github.com/paulrosen/historical-abcjs-versions)
+
+## Breaking change when using midi.js for 6.0.0-beta.26
+
+The midi.js package is no longer a direct dependency, it is now a peerDependency so it is not included by default. That way, users who aren't using the old style of sound generation won't need to load the package. If you are using the old style that uses midi.js, include this line in your `package.json` file:
+
+```
+"midi": "https://github.com/paulrosen/MIDI.js.git#abcjs"
+```
+Note that if you are using the minified version of the library with a `
+
+
diff --git a/docs/.vuepress/components/CheckBox.vue b/docs/.vuepress/components/CheckBox.vue
new file mode 100644
index 0000000000000000000000000000000000000000..d271704083c001d281310fedf285372345cd4823
--- /dev/null
+++ b/docs/.vuepress/components/CheckBox.vue
@@ -0,0 +1,130 @@
+
+
+
+
+`;
+
diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js
new file mode 100644
index 0000000000000000000000000000000000000000..14a81cce339031804377fb6737754e754b5b5e27
--- /dev/null
+++ b/docs/.vuepress/config.js
@@ -0,0 +1,16 @@
+import { defaultTheme } from '@vuepress/theme-default'
+export default {
+ base: "/abcjs/",
+ title: "abcjs",
+ description: "JavaScript library for displaying sheet music in a browser.",
+ theme: defaultTheme({
+ logo: '/img/abcjs_comp_extended_08.svg',
+ displayAllHeaders: true,
+ sidebar: require("./sidebar")
+ }),
+ head: [
+ ['link', { rel: 'icon', href: '/abcjs/favicon.ico' }],
+ ['link', { rel:"stylesheet", type: "text/css", href: 'https://paulrosen.github.io/abcjs/abcjs-audio.css'}],
+ ['script', { src: "https://paulrosen.github.io/abcjs/dist/abcjs-basic.js", type:"text/javascript" }]
+ ],
+};
diff --git a/docs/.vuepress/public/favicon.ico b/docs/.vuepress/public/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..ac52440052f8c6ac3f5f33d4a1763f72ab332874
Binary files /dev/null and b/docs/.vuepress/public/favicon.ico differ
diff --git a/docs/.vuepress/public/fonts/itim-music.svg b/docs/.vuepress/public/fonts/itim-music.svg
new file mode 100644
index 0000000000000000000000000000000000000000..b1546cc29d1d2f3bee293a783237a3dc9f781487
--- /dev/null
+++ b/docs/.vuepress/public/fonts/itim-music.svg
@@ -0,0 +1,16 @@
+
+
+
\ No newline at end of file
diff --git a/docs/.vuepress/public/fonts/itim-music.ttf b/docs/.vuepress/public/fonts/itim-music.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..892fa95352a79879488661951f9c974e2f41c4af
Binary files /dev/null and b/docs/.vuepress/public/fonts/itim-music.ttf differ
diff --git a/docs/.vuepress/public/fonts/itim-music.woff b/docs/.vuepress/public/fonts/itim-music.woff
new file mode 100644
index 0000000000000000000000000000000000000000..97adfa7f9aa2f656a629e4cf59caabfff8456f43
Binary files /dev/null and b/docs/.vuepress/public/fonts/itim-music.woff differ
diff --git a/docs/.vuepress/public/img/abcjs_comp_extended_08.svg b/docs/.vuepress/public/img/abcjs_comp_extended_08.svg
new file mode 100644
index 0000000000000000000000000000000000000000..3ae7590620583897127bd175566f1c0115320607
--- /dev/null
+++ b/docs/.vuepress/public/img/abcjs_comp_extended_08.svg
@@ -0,0 +1,9 @@
+
diff --git a/docs/.vuepress/public/img/browserstack-logo-600x315.png b/docs/.vuepress/public/img/browserstack-logo-600x315.png
new file mode 100644
index 0000000000000000000000000000000000000000..e9358251e9d32004c4b46d015f76bc4cdbc55534
Binary files /dev/null and b/docs/.vuepress/public/img/browserstack-logo-600x315.png differ
diff --git a/docs/.vuepress/sidebar.json b/docs/.vuepress/sidebar.json
new file mode 100644
index 0000000000000000000000000000000000000000..213fa197086baf7c21b9cf67a25d2aab8a183623
--- /dev/null
+++ b/docs/.vuepress/sidebar.json
@@ -0,0 +1,86 @@
+[
+ {
+ "isGroup": true,
+ "text": "Overview",
+ "children": [
+ "/overview/purpose.md",
+ "/overview/examples.md",
+ "/overview/getting-started.md",
+ "/overview/example-generator.md",
+ "/overview/abc-notation.md",
+ "/overview/faq.md"
+ ]
+ },
+ {
+ "isGroup": true,
+ "text": "Visual",
+ "children": [
+ "/visual/overview.md",
+ "/visual/render-abc-options.md",
+ "/visual/render-abc-result.md",
+ "/visual/classes.md",
+ "/visual/click-listener.md",
+ "/visual/dragging.md",
+ "/visual/tablature.md"
+ ]
+ },
+ {
+ "isGroup": true,
+ "text": "Audio",
+ "children": [
+ "/audio/synthesized-sound.md"
+ ]
+ },
+ {
+ "isGroup": true,
+ "text": "Animation",
+ "children": [
+ "/animation/timing-callbacks.md"
+ ]
+ },
+ {
+ "isGroup": true,
+ "text": "Interactive",
+ "children": [
+ "/interactive/interactive-editor.md"
+ ]
+ },
+ {
+ "isGroup": true,
+ "text": "Transposing",
+ "children": [
+ "/transposing/transposing.md"
+ ]
+ },
+ {
+ "isGroup": true,
+ "text": "Analysis",
+ "children": [
+ "/analysis/tune-book.md"
+ ]
+ },
+ {
+ "isGroup": true,
+ "text": "Deprecated",
+ "children": [
+ "/deprecated/deprecated-api.md"
+ ]
+ },
+ {
+ "isGroup": true,
+ "text": "Developers",
+ "children": [
+ "/developers/pull-requests.md",
+ "/developers/basic-architecture.md",
+ "/developers/releasing.md"
+ ]
+ },
+ {
+ "isGroup": true,
+ "text": "Upgrading",
+ "children": [
+ "/upgrading/release-notes.md",
+ "/upgrading/midijs.md"
+ ]
+ }
+]
diff --git a/docs/.vuepress/store.js b/docs/.vuepress/store.js
new file mode 100644
index 0000000000000000000000000000000000000000..e391116655bb4480c76fd7b5f8e34930872fcae6
--- /dev/null
+++ b/docs/.vuepress/store.js
@@ -0,0 +1,233 @@
+import {audioString, clickListenerHtmlString, dragExplanationHtmlString, dragHtmlString, editorString, middleString, midiString, paperString, postAmbleString, preamble2String, preambleString, setupString, startTimerHtmlString} from "./components/example-strings";
+import {cssString} from "./components/example-strings-css";
+import {clickListenerJsString, editorJsString, renderAbcString, visualOptionsString} from "./components/example-strings-js";
+import {cursorJsString} from "./components/example-strings-js-cursor";
+import {dragJsString} from "./components/example-strings-js-drag";
+import {soundJsString} from "./components/example-strings-js-audio";
+
+const state = {
+ examples: {
+ usingNode: true,
+ soundfont: false,
+
+ sheetMusic: true,
+ cursor: false,
+ hideMeasures: false,
+ jazzChords: false,
+ responsive: false,
+ changes: 'programmatic',
+ hideVoice: false,
+ preload: false,
+ loopMeasures: false,
+ swingFeel: false,
+
+ hasSound: false,
+ playbackWidget: true,
+ large: false,
+ loop: false,
+ restart: true,
+ play: true,
+ progress: true,
+ warp: false,
+ clock: true,
+
+ usingCallbacks: false,
+ metronome: false,
+ tempo: false,
+ stereo: false,
+ instrument: false,
+ transpose: false,
+ noChords: false,
+ noVoice: false,
+
+ tweak: false,
+ midi: false,
+ playImmediate: false,
+ switchTunes: false,
+
+ isDownloading: false,
+ }
+}
+
+const getters = {
+ usingNode(state) { return state.examples.usingNode },
+ soundfont(state) { return state.examples.soundfont },
+ sheetMusic(state) { return state.examples.sheetMusic },
+ cursor(state) { return state.examples.cursor },
+ hideMeasures(state) { return state.examples.hideMeasures },
+ jazzChords(state) { return state.examples.jazzChords },
+ hideVoice(state) { return state.examples.hideVoice },
+ preload(state) { return state.examples.preload },
+ loopMeasures(state) { return state.examples.loopMeasures },
+ swingFeel(state) { return state.examples.swingFeel },
+ responsive(state) { return state.examples.responsive },
+ changes(state) { return state.examples.changes },
+ hasSound(state) { return state.examples.hasSound },
+ playbackWidget(state) { return state.examples.playbackWidget },
+ large(state) { return state.examples.large },
+ loop(state) { return state.examples.loop },
+ restart(state) { return state.examples.restart },
+ play(state) { return state.examples.play },
+ progress(state) { return state.examples.progress },
+ warp(state) { return state.examples.warp },
+ clock(state) { return state.examples.clock },
+ usingCallbacks(state) { return state.examples.usingCallbacks },
+ metronome(state) { return state.examples.metronome },
+ tempo(state) { return state.examples.tempo },
+ stereo(state) { return state.examples.stereo },
+ instrument(state) { return state.examples.instrument },
+ transpose(state) { return state.examples.transpose },
+ noChords(state) { return state.examples.noChords },
+ noVoice(state) { return state.examples.noVoice },
+ tweak(state) { return state.examples.tweak },
+ midi(state) { return state.examples.midi },
+ playImmediate(state) { return state.examples.playImmediate },
+ switchTunes(state) { return state.examples.switchTunes },
+ isDownloading(state) { return state.examples.isDownloading },
+
+ declaration(state, getters) {
+ return setupString(getters.usingNode)
+ },
+ sheetMusicHtml(state, getters) {
+ return `${dragExplanationHtmlString(getters.changes === 'drag')}
+${editorString(getters.hasEditor)}
+${paperString(getters.sheetMusic)}
+${audioString(getters.playbackWidget && getters.hasSound, getters.large)}
+${midiString(getters.midi)}
+${clickListenerHtmlString(getters.sheetMusic && getters.usingCallbacks)}
+${dragHtmlString(getters.changes === 'drag')}
+${startTimerHtmlString(getters.sheetMusic && (getters.cursor || getters.hideMeasures))}
+`;
+ },
+
+ sheetMusicCss(state, getters) {
+ return cssString(
+ getters.playbackWidget && getters.hasSound,
+ getters.sheetMusic && getters.cursor,
+ getters.sheetMusic && getters.hideMeasures,
+ getters.sheetMusic && getters.changes === 'drag',
+ getters.sheetMusic && getters.usingCallbacks
+ );
+ },
+
+ sheetMusicJs(state, getters) {
+ var usingNode = getters.isDownloading ? false : getters.usingNode;
+ return sheetMusicJsBuilder(getters, usingNode);
+ },
+ sheetMusicJsNode(state, getters) {
+ return sheetMusicJsBuilder(getters, true);
+ },
+ hasEditor(state, getters) {
+ return getters.changes === 'editor';
+ },
+ title(state, getters) {
+ let options = [];
+ if (getters.sheetMusic) options.push("visual");
+ if (getters.sheetMusic && getters.responsive) options.push("responsive");
+ if (getters.sheetMusic && getters.cursor) options.push("cursor");
+ if (getters.sheetMusic && getters.hideMeasures) options.push("hide");
+ if (getters.sheetMusic && getters.jazzChords) options.push("jazz");
+ options.push(getters.changes);
+ if (getters.sheetMusic && getters.usingCallbacks) options.push("callback");
+ if (getters.hasSound) options.push("sound");
+ if (getters.hasSound && getters.playbackWidget) options.push("playback");
+ if (getters.hasSound && getters.playbackWidget && getters.large) options.push("large");
+ if (getters.hasSound && getters.playbackWidget && getters.loop) options.push("loop");
+ if (getters.hasSound && getters.playbackWidget && getters.restart) options.push("restart");
+ if (getters.hasSound && getters.playbackWidget && getters.play) options.push("play");
+ if (getters.hasSound && getters.playbackWidget && getters.progress) options.push("progress");
+ if (getters.hasSound && getters.playbackWidget && getters.warp) options.push("warp");
+ if (getters.hasSound && getters.playbackWidget && getters.clock) options.push("clock");
+ if (getters.hasSound && getters.metronome) options.push("metronome");
+ if (getters.hasSound && getters.tempo) options.push("tempo");
+ if (getters.hasSound && getters.stereo) options.push("stereo");
+ if (getters.hasSound && getters.instrument) options.push("instrument");
+ if (getters.hasSound && getters.transpose) options.push("transpose");
+ if (getters.hasSound && getters.noChords) options.push("nochords");
+ if (getters.hasSound && getters.noVoice) options.push("novoice");
+ if (getters.hasSound && getters.tweak) options.push("tweak");
+ if (getters.hasSound && getters.midi) options.push("midi");
+ if (getters.hasSound && getters.playImmediate) options.push("immediate");
+ if (getters.hasSound && getters.switchTunes) options.push("switchtunes");
+ if (getters.hasSound && getters.hideVoice) options.push("hideVoice");
+ if (getters.hasSound && getters.preload) options.push("preload");
+ if (getters.hasSound && getters.loopMeasures) options.push("loopmeasures");
+ if (getters.hasSound && getters.swingFeel) options.push("swing");
+ if (getters.hasSound && getters.soundfont) options.push("soundfont");
+
+ return options.join(' ');
+ },
+ filename(state, getters) {
+ return getters.title.replace(/ /g,'-') + ".html";
+ },
+ fullDemo(state, getters) {
+ return `${preambleString(getters.title)}${getters.sheetMusicCss}${preamble2String(getters.hasEditor)}${getters.sheetMusicJs}${middleString(getters.title)}${getters.sheetMusicHtml}${postAmbleString()}`;
+ }
+
+}
+
+const mutations = {
+ usingNode(state, payload) { state.examples.usingNode = payload },
+ soundfont(state, payload) { state.examples.soundfont = payload },
+ sheetMusic(state, payload) { state.examples.sheetMusic = payload },
+ cursor(state, payload) { state.examples.cursor = payload },
+ hideMeasures(state, payload) { state.examples.hideMeasures = payload },
+ jazzChords(state, payload) { state.examples.jazzChords = payload },
+ hideVoice(state, payload) { state.examples.hideVoice = payload },
+ preload(state, payload) { state.examples.preload = payload },
+ loopMeasures(state, payload) { state.examples.loopMeasures = payload },
+ swingFeel(state, payload) { state.examples.swingFeel = payload },
+ responsive(state, payload) { state.examples.responsive = payload },
+ changes(state, payload) { state.examples.changes = payload },
+ hasSound(state, payload) { state.examples.hasSound = payload },
+ playbackWidget(state, payload) { state.examples.playbackWidget = payload },
+ large(state, payload) { state.examples.large = payload },
+ loop(state, payload) { state.examples.loop = payload },
+ restart(state, payload) { state.examples.restart = payload },
+ play(state, payload) { state.examples.play = payload },
+ progress(state, payload) { state.examples.progress = payload },
+ warp(state, payload) { state.examples.warp = payload },
+ clock(state, payload) { state.examples.clock = payload },
+ usingCallbacks(state, payload) { state.examples.usingCallbacks = payload },
+ metronome(state, payload) { state.examples.metronome = payload },
+ tempo(state, payload) { state.examples.tempo = payload },
+ stereo(state, payload) { state.examples.stereo = payload },
+ instrument(state, payload) { state.examples.instrument = payload },
+ transpose(state, payload) { state.examples.transpose = payload },
+ noChords(state, payload) { state.examples.noChords = payload },
+ noVoice(state, payload) { state.examples.noVoice = payload },
+ tweak(state, payload) { state.examples.tweak = payload },
+ midi(state, payload) { state.examples.midi = payload },
+ playImmediate(state, payload) { state.examples.playImmediate = payload },
+ switchTunes(state, payload) { state.examples.switchTunes = payload },
+ isDownloading(state, payload) { state.examples.isDownloading = payload },
+}
+
+const actions = {
+}
+
+export const store = {
+ state,
+ getters,
+ mutations,
+ actions,
+}
+
+function sheetMusicJsBuilder(getters, usingNode) {
+
+ const visualOptions = visualOptionsString(
+ getters.responsive,
+ getters.sheetMusic && getters.usingCallbacks,
+ getters.hasSound && getters.metronome,
+ getters.hideMeasures,
+ getters.jazzChords,
+ );
+ const str =`${renderAbcString(usingNode, !getters.hasEditor, getters.sheetMusic, visualOptions)}
+${editorJsString(usingNode, getters.hasEditor, getters.sheetMusic)}
+${soundJsString(usingNode, getters)}
+${clickListenerJsString(getters.sheetMusic && getters.usingCallbacks)}
+${cursorJsString(usingNode, getters.sheetMusic && getters.cursor, getters.sheetMusic && getters.hideMeasures)}
+${dragJsString(usingNode, getters.changes === 'drag')}
+`;
+ return str.replace(/\t/g," ");
+}
diff --git a/docs/.vuepress/styles/index.scss b/docs/.vuepress/styles/index.scss
new file mode 100644
index 0000000000000000000000000000000000000000..71d4947327f781db3166c198f13e8db54d3faa4b
--- /dev/null
+++ b/docs/.vuepress/styles/index.scss
@@ -0,0 +1,39 @@
+header.navbar .site-name {
+ display: none;
+}
+
+textarea {
+ width: 100%;
+ height: 200px;
+}
+
+.my-code {
+ color: #fff;
+ padding: 1.25rem 1.5rem;
+ font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
+}
+
+ #paper {
+ max-width: 740px;
+ }
+
+.code-results {
+ display: inline-block;
+ border: 2px outset #fff;
+ padding: 3px 10px;
+ border-radius: 4px;
+ color: #000;
+ background: #a8f5e7;
+ font-weight: bold;
+}
+
+@import url(https://fonts.googleapis.com/css?family=Itim);
+
+@font-face {
+ font-family: 'itim-music';
+ src: url('https://paulrosen.github.io/abcjs/fonts/itim-music.ttf') format('truetype'),
+ url('https://paulrosen.github.io/abcjs/fonts/itim-music.woff') format('woff'),
+ url('https://paulrosen.github.io/abcjs/fonts/itim-music.svg#icomoon') format('svg');
+ font-weight: normal;
+ font-style: normal;
+}
diff --git a/docs/.vuepress/wait-for-abcjs.js b/docs/.vuepress/wait-for-abcjs.js
new file mode 100644
index 0000000000000000000000000000000000000000..6d4433fdc4a6192fe621e26167fdfb951cbb3ad8
--- /dev/null
+++ b/docs/.vuepress/wait-for-abcjs.js
@@ -0,0 +1,10 @@
+export const waitForAbcjs = async function() {
+ while (!window.ABCJS) {
+ await sleep(100)
+ }
+ window.abcjs = ABCJS
+}
+
+export const sleep = (ms) => {
+ return new Promise(resolve => setTimeout(resolve, ms));
+};
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..9ff5e0df55c8075e55383b9edaee1554eda32433
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,33 @@
+# Javascript library for inserting music in the browser.
+
+
+
+**ABC Music Notation** is a format for specifying sheet music using only a string of characters.
+For instance, the following string encodes the music that is shown below it. That music was
+drawn by including this library on this webpage.
+
+```
+X: 1
+T: Cooley's
+M: 4/4
+L: 1/8
+K: Emin
+|:D2|EB{c}BA B2 EB|~B2 AB dBAG|FDAD BDAD|FDAD dAFD|
+EBBA B2 EB|B2 AB defg|afe^c dBAF|DEFD E2:|
+|:gf|eB B2 efge|eB B2 gedB|A2 FA DAFA|A2 FA defg|
+eB B2 eBgB|eB B2 defg|afe^c dBAF|DEFD E2:|
+```
+
+
+
+In addition, the music can also be played by a synthesizer:
+
+
diff --git a/docs/analysis/tune-book.md b/docs/analysis/tune-book.md
new file mode 100644
index 0000000000000000000000000000000000000000..77fbd5f56e7099cbeb76d38cfc0693c1cd9e4d1b
--- /dev/null
+++ b/docs/analysis/tune-book.md
@@ -0,0 +1,70 @@
+# Tune Book
+
+The following analysis is based on the abc string that is in the textarea at the bottom of this page.
+
+## Number of Tunes
+
+It might be useful to know in advance how many tunes are in a tunebook before rendering them:
+
+
+
+## Get Tune Info
+
+The following assumes you've created a `TuneBook` object like this:
+
+```
+var tuneBook = new ABCJS.TuneBook(tunebookString)
+```
+
+### Extract Tune by ID
+
+If you know the ID, then you can use the following to get a particular tune in a tunebook. The id is the value in the `X:` field.
+
+
+
+### Extract Tune by Title
+
+If you know the title, then you can use the following to get a particular tune in a tunebook. The title is the value in the *first* `T:` field.
+
+
+
+### Get all Tune Info
+
+You can directly access the array of tunes in a tune book with:
+
+```javascript
+var arrayOfTunes = tunebook.tunes;
+```
+
+### Get all measures separately
+
+To parse the string and return each measure:
+
+```javascript
+var measureArray = abcjs.extractMeasures(tunebookString);
+```
+
+## Test Data
+
+Paste in any ABC you want here and see how that affects the analysis above:
+
+
+
+
diff --git a/docs/animation/timing-callbacks.md b/docs/animation/timing-callbacks.md
new file mode 100644
index 0000000000000000000000000000000000000000..148f77dae4c673bdc4b2b4de0d416856ee6520c8
--- /dev/null
+++ b/docs/animation/timing-callbacks.md
@@ -0,0 +1,188 @@
+# Timing Callbacks
+
+This runs an animation timer and does callbacks at various intervals. This allows you to do various effects that are timed with beats or playing notes.
+
+## Creation
+
+To use this create an instance of it:
+```javascript
+var timingCallbacks = new abcjs.TimingCallbacks(visualObj, params);
+```
+
+| Parameters | Description |
+| ------------- | ----------- |
+| visualObj | This is the output of the `renderAbc()` call. It is the music that will be timed. |
+| params | This is a object. See below for the possible properties. |
+
+## Parameters
+
+| Name | Default | Description |
+| ------------- | ------- | ----------- |
+| `qpm` | whatever is in the Q: field | Number of beats per minute. |
+| `extraMeasuresAtBeginning` | 0 | Don't start the callbacks right away, but insert this number of measures first. |
+| `beatCallback` | null | Called for each beat passing the beat number (starting at 0). |
+| `eventCallback` | null | Called for each event (either a note, a rest, or a chord, and notes in separate voices are grouped together.) |
+| `lineEndCallback` | null | Called at the end of each line. (This is useful if you want to be sure the music is scrolled into view at the right time.) See `lineEndAnticipation` for more details. |
+| `lineEndAnticipation` | 0 | The number of milliseconds for the `lineEndCallback` to anticipate end of the line. That is, if you want to get the callback half a second before the end of the line, use 500. |
+| `beatSubdivisions` | 1 | How many callbacks should happen for each beat. This allows finer control in the client, for instance, to handle a progress bar. |
+
+## Callbacks
+
+### beatCallback
+
+This is called once for every beat in the tune. It is called one additional time when the tune is finished.
+
+```javascript
+function beatCallback(beatNumber, totalBeats, totalTime, position, debugInfo) {}
+```
+
+|Name|Description|
+|---|---|
+| beatNumber | Zero-based beat number. Usually this will increment sequentially and regularly, but if javascript is paused long enough (for instance, if the browser tab is changed), then there may be a number of these calls at once when it catches up. |
+| totalBeats | The total number of beats (including all repeats) that will be played. |
+| totalTime | The total number of milliseconds of the tune. |
+| position | The interpolated position of the cursor if the beat occurs between notes. This is an object with the attributes { left: , top: , height: } This can be used to smooth out the cursor by moving it on the beat callbacks. The higher the number of `beatSubdivisions` the smoother the cursor will be. |
+| debugInfo | A hash of some extra info that might be useful in figuring out why the callback was triggered. |
+
+### eventCallback
+
+This is called once for every "event" in time - either a note or a rest. If there are multiple notes at the same time, then it is only called once
+for that group of notes.
+
+```javascript
+function eventCallback(ev) {}
+```
+
+The parameter `ev` is an object that looks like this:
+
+```javascript
+ev = {
+ "type": "event", // This is always "event"
+
+ "milliseconds": number, // The number of milliseconds from the beginning of the piece
+ "millisecondsPerMeasure": number, // The number of milliseconds per measure
+
+ "line": number, // The current "line", that is, the staff system.
+ "measureNumber": number, // The measure number. Resets per line, so the first measure number on a line is zero.
+
+ "top": number, // The number of pixels from the top of the svg that the note appears.
+ "height": number, // The height of the note, in pixels.
+ "left": number, // The number of pixels from the left edge of the svg.
+ "width": number, // The width of the note
+
+ "elements": [ ], // Array of the actual elements on the page that are represented by the note or notes.
+ "startCharArray": [ number ], // the character position in the original abc string
+ "endCharArray": [ number ], // the character position in the original abc string
+ "midiPitches": [ // Array of the currently playing pitches
+ {
+ "pitch": number, // The pitch number (based on the midi standard, i.e. middle C is 60)
+ "durationInMeasures": number, // the note value as a fraction. (that is, a quarter note is 0.025)
+ "volume": number, // The volume expressed as a number between 0 and 127
+ "instrument": number // The instrument number (based on the midi standard, i.e. acoustic_grand_piano is 0)
+ }
+ ]
+}
+```
+
+#### Notes:
+
+* The `startCharArray` and `endCharArray` are arrays because there is more than one location in the abc string if there is more than one voice.
+
+* The format of the `elements` array is subject to change in future versions.
+
+* This is called one last time with passing in `null` at the end of the tune. On that call `eventCallback` can return the string "continue" to keep the timer from stopping. This is useful if you want to play on repeat - in theory you would probably have another call to `seek()`.
+
+* This function can be a Promise or not.
+
+### lineEndCallback
+
+This will be called as the cursor is approaching the end of a line of music. This is useful if there is more than a screen's worth of music; it can be used to scroll the page at the right time.
+
+```javascript
+function lineEndCallback(info, event, details) {}
+```
+
+The parameter `info` looks like this:
+
+```javascript
+info = {
+ "milliseconds": number, // current milliseconds from beginning of piece
+ "top": number, // The number of pixels from the top of the svg to the top of the cursor
+ "bottom": number // The number of pixels from the top of the svg to the bottom of the cursor
+}
+```
+The parameter `event` is the standard note event.
+
+The parameter `details` looks like this:
+```javascript
+details = {
+ "line": number, // the current line number (zero-based)
+ "endTimings": array // the array of the timings for each line
+}
+```
+The `endTimings` array elements are of the same type as the `info` parameter.
+
+## Functions
+
+These are the entry points that can be called on the `timingCallbacks` object.
+
+### start(position, units)
+
+This starts the timer that triggers the callbacks. This is called to both start and resume after calling pause. See the `setProgress` method below for explanation of the parameters with one special case:
+
+If `position` is undefined then if the previous call was to `pause()`, then the animation continues from where it left off. If there was no pause, then the animation starts from the beginning.
+
+### pause()
+
+Pauses the animation. Calling `start()` afterwards will resume from where it left off.
+
+### stop()
+
+Stop the animation. After calling this, the next call to `start()` will start at the beginning.
+
+### reset()
+
+Move the timer back to the beginning, so the animation starts over. This can be called either when the animation is currently running or when it is paused.
+
+### setProgress(position, units)
+
+Change the position of the animation. This allows random access to any place in the tune.
+
+If the second parameter is not present, then `units` equals "percent". The possible values are:
+
+* `"percent"`: The percent passed in is a number between 0 and 1. This can be called either when the animation is currently running or when it is paused.
+
+* `"seconds"`: The seconds from the beginning of the tune. If this is passed the end of the tune it is changed to the end.
+
+* `"beats"`: The beats from the beginning of the tune. If this is passed the end of the tune it is changed to the end.
+
+### replaceTarget(visualObj)
+
+If the underlying music changes on the fly, this replaces the current object without having to destroy the object and start over. `visualObj` is the return value from `renderAbc`.
+
+## Example
+
+Paste in any ABC you want here then click "start" to see what is returned by the timing callbacks:
+
+
+
+
+
+
diff --git a/docs/audio/synthesized-sound.md b/docs/audio/synthesized-sound.md
new file mode 100644
index 0000000000000000000000000000000000000000..d6cd29fd704d1fd4ea56d8eca58b1c1494afee14
--- /dev/null
+++ b/docs/audio/synthesized-sound.md
@@ -0,0 +1,671 @@
+# Synthesized Sound
+
+## Browser Compatibility and Requirements
+
+* This works in any browser that supports `AudioContext`, `AudioContext.resume`, and `Promises`. That does NOT include IE, but this will work on any other "modern" browser that is at least the following version: Firefox 40, Safari 9.1, Edge 13, and Chrome 43.
+
+* This requires an internet connection for the "sound fonts". You can supply your own sound fonts, so if you want to deliver them locally you can get by without the network. The default sound fonts come from [this github repo](https://paulrosen.github.io/midi-js-soundfonts/abcjs).
+
+* It is theoretically possible to create complex enough pieces to bog down your browser or eat up memory. The two things that take resources are each unique note in each instrument and the overall length of the music. Music of a few minutes long with a variety of notes in a few different instruments work with no problem on all devices that have been tested.
+
+## Theory
+
+* This creates an audio buffer that is similar to a WAV file and contains the entire piece to play.
+
+* The sounds themselves come from a "sound font": that is, each individual note on each instrument is a separate sound file that is combined into the audio buffer.
+
+* The instrument numbers and the pitch numbers come from the MIDI spec. MIDI is not normally produced, but it is MIDI-like. (There is a function to create a MIDI file for download.)
+
+## Examples
+
+See [Basic Synth](https://raw.githubusercontent.com/paulrosen/abcjs/main/examples/basic-synth.html) for the simplest possible way of making sound.
+
+See [Full Synth](https://raw.githubusercontent.com/paulrosen/abcjs/main/examples/full-synth.html) for an example that incorporates a bouncing-ball type animation and an audio control.
+
+## API
+
+Since there are a number of ways to use the synthesized sound: with or without a visual depiction of the tune, with or without a user-facing audio control, and with or without various timing callbacks, there are a number of different entry points.
+
+## CreateSynth
+
+Creates the object that caches and buffers the audio to be played. All implementations of audio playback will need a CreateSynth.
+
+```javascript
+var synth = new ABCJS.synth.CreateSynth();
+```
+
+### init(synthOptions)
+
+The first call that must be made on the CreateSynth object. This will load all of the needed notes and will return a promise when they are loaded. There might be a considerable delay for this to finish. Because the notes are cached, though, the second time CreateSynth is created with a piece of music with similar notes, it will take much less time. See below for the synthOptions.
+
+This must not be called until the user has made a gesture on the page because this references an `AudioContext`.
+
+This returns a promise after all the notes have been loaded. The promise contains:
+```
+{
+ cached: [], // an array of the notes that were previously loaded.
+ error: [], // an array of the notes that haven't been loaded and the error message that was received
+ loaded: [] // an array of the notes that have been loaded.
+}
+```
+
+#### synthOptions
+
+| Attribute | Default | Description |
+| ------------- | ----------- |----------- |
+| audioContext | undefined | This the value of `new AudioContext()`. It should be passed in instead of created because the calling program might be managing and reusing this. It also MUST be creating in the handler of a user action. It can't be created at any other time. But if you don't pass one in then abcjs will create it. This value is cached for the length of the browser session. |
+| visualObj | undefined | This is the result of `renderAbc()`. Important: `renderAbc()` returns an array, since an ABC string can contain more than one tune. This variable is just one element in that array. Either this must be supplied, or `sequence` must be supplied. |
+| sequence | undefined | This is a manually-created set of instructions for creating the audio. It is built using the `SynthSequence` object. |
+| millisecondsPerMeasure | calculated | This allows control over the tempo. If this is present, then the tempo specified in the ABC string is ignored. |
+| debugCallback | undefined | This will be called with various extra info at different times in the process. |
+| options | undefined | Some options for the sound creation (see list below). |
+
+#### synthOptions.options
+
+In addition to the following option, you can also set the options described in audioParams below.
+
+| Attribute | Default | Description |
+| ------------- | ----------- |----------- |
+| soundFontUrl | "https://paulrosen.github.io/midi-js-soundfonts/abcjs/" | This is the public URL for the sound font. If it isn't present, then the sound fonts come from the github repo. This can be replaced if the new sound font follows the same format. |
+| soundFontVolumeMultiplier | 1.0 | This is the amount to multiply all the volumes to compensate for different volume soundfonts. If you find that either the volume is too low or the output is clipped, you can experiment with this number. |
+| programOffsets | {} | The offset of each voice to the beat. Some voices have a ramp up time so that the beginning of the sound isn't the beat. This is the number of milliseconds that the program should be offset. This is expressed as `{ 'program_name': 100 }` where the program name is one of the standard midi names, like "acoustic_grand_piano". If you use the default soundfont then these values are set automatically. You can still provide this parameter to override the settings if you like. |
+| fadeLength | 200 | The number of milliseconds to fade out each note after its has played for the correct length. The gain will go from 100% to 0% in this number of milliseconds. |
+| sequenceCallback | undefined | This is called after the array of notes is created, and just before it is used to create the audio buffer. The array of tracks is passed in, and this gives a chance to tweak the audio before it is created: you can give it some swing, you can change volumes, or anything else. |
+| callbackContext | undefined | This is passed back when the sequenceCallback function is called. |
+| onEnded | undefined | This function is called after the playback stops. |
+| pan | [0...] | An array of numbers between -1 and 1 for how far to pan each track. -1 is all the way to the left and 1 is all the way to the right. If there are not enough items in the array for all the tracks, then the remaining tracks will be in the middle. |
+
+#### Example
+```javascript
+var myContext = new AudioContext();
+var visualObj = ABCJS.renderAbc(...);
+synth.init({
+ audioContext: myContext,
+ visualObj: visualObj[0],
+ millisecondsPerMeasure: 500,
+ options: {
+ soundFontUrl: "https:/path/to/soundfont/folder",
+ pan: [ -0.3, 0.3 ]
+ }
+}).then(function (results) {
+ // Ready to play. The results are details about what was loaded.
+}).catch(function (reason) {
+ console.log(reason)
+});
+```
+
+The above will:
+1. create audio for the first tune found in the tunebook that is passed to `renderAbc`.
+2. It will play at 1/2 second per measure (180 bpm for 2/4 time).
+3. It will use the URL provided for the soundfont.
+4. It will put the first track a little bit to the left side and the second track a little bit to the right. (Note that if the music is a single line of music with chord diagrams, the melody will be track 0 and the chords will be track 1.)
+
+### prime()
+
+This creates the actual buffer - it doesn't require a network connection since all the notes have now been preloaded. It returns a promise because there might be a little bit of time delay doing the calculations.
+
+After calling this, everything is setup so you can freely call the rest of the functions to control how the audio works.
+
+This returns a promise that is `{ status: audioContextStatus, duration: lengthInSecondsOfAudio }`
+
+Note that normally the status will be "running". On iOS, though, it can sometimes be either "suspended" or "interrupted". It might require user intervention to resolve this.
+
+#### Example
+```javascript
+synth.init(...).then(() => {
+ synth.prime().then((response) => {
+ console.log(response.status)
+ ...
+ });
+});
+```
+
+### start()
+
+This starts the audio.
+
+Call this after `prime()` has returned its promise. This will happen fast and doesn't have any latency, so you can call this right as you are timing other things to be in sync with the audio.
+
+### pause() and resume()
+
+After `start()` has been called, pause and resume can be called to control the playback.
+
+### seek(percent, units)
+
+This changes the playback position. It can be called whether the sound is currently playing or not.
+
+If the second parameter is not present, then `units` equals "percent". The possible values are:
+
+* `"percent"`: The percent passed in is a number between 0 and 1. This can be called either when the animation is currently running or when it is paused.
+
+* `"seconds"`: The seconds from the beginning of the tune. If this is passed the end of the tune it is changed to the end.
+
+* `"beats"`: The beats from the beginning of the tune. If this is passed the end of the tune it is changed to the end.
+
+### stop()
+
+Stops playing the sound and resets the progress to the beginning of the sound file.
+
+### download()
+
+This returns the audio buffer created. (It is in WAV format.)
+
+### getAudioBuffer()
+
+This returns the AudioBuffer that was created in the the `prime()` call.
+
+## SynthController
+
+Creates a visual widget that allows the user to control playback, including play and stop buttons, a progress bar, etc. This is the quickest way to set up a playback widget. See the section below for options.
+
+The constructor can be called at any time, including before much is initialized:
+
+```javascript
+var synthControl = new ABCJS.synth.SynthController();
+```
+
+### load(selector, cursorControl, visualOptions)
+
+After the DOM is loaded, this should be called to initialize the visual widget that contains the "play", etc. buttons.
+
+While this can be called multiple times, it is generally just called once during initialization.
+
+#### selector
+
+This is a CSS-style selector of the element that should be turned into the audio control.
+
+#### cursorControl
+
+This is an optional object that can be passed in that will receive callbacks when events happen that should move the cursor. See the section on "CursorControl" for more info.
+
+#### visualOptions
+
+This is a hash with the following possible properties:
+
+| Option | Default | Description |
+|---|---|---|
+| displayLoop | false | Whether to display a button that the user can press to make the tune loop instead of stopping when it gets to the end. |
+| displayRestart | false | Whether to display a button that the user can press to make the tune go back to the beginning. |
+| displayPlay | true | Whether to display a button that the user can press to make the tune start playing. (Note: this turns into the "pause" button when the tune is playing.) |
+| displayProgress | true | Whether to display the progress slider. The user can click anywhere on this to get the music to jump to that location. |
+| displayWarp | false | Whether to display the tempo and allow the user to change it on the fly. |
+
+### disable(isDisabled)
+
+This is called internally when waiting for the audio to finish loading. It can also be called directly by the client. The most common use for that is to disable the visual control when you are about to load in a new tune.
+
+If you load in a new tune without disabling the control first and the user clicks play while the notes are still being loaded over the network, the old tune will play until the new one is ready.
+
+### setTune(visualObj, userAction, audioParams)
+
+This is called whenever there is a new tune ready to be loaded into the player.
+
+#### visualObj
+
+This is one of the tunes that is returned from the `renderAbc()` call. That is, `renderAbc` will return an array of tunes. Often it is an array of length 1 if there is only one tune in the abc string, but it could be multiple tunes.
+
+#### userAction
+
+True if this is being called inside an event handler from a user gesture. The audio buffer can't be created until then. If this is `true`, then the audio buffer is created immediately. If this is `false` then the audio buffer is not created until the user clicks the `play` button.
+
+### audioParams
+
+Here are the possible properties that can be passed in:
+
+| Property | Default | Description |
+|---|---|---|
+| audioContext | create it. | An AudioContext object so that they can be reused. |
+| debugCallback; | null | A function that is called at various times in the creation of the audio. |
+| soundFontUrl | use the default | The publicly available URL of the soundfont to use. |
+| soundFontVolumeMultiplier | 1.0 | This is the amount to multiply all the volumes to compensate for different volume soundfonts. If you find that either the volume is too low or the output is clipped, you can experiment with this number. |
+| millisecondsPerMeasure | calculated | An override of the tempo in the tune. |
+| visualObj | null | The object returned from `renderAbc`. |
+| options | {} | Options to pass to the low-level buffer creation routines. |
+| sequence | null | An alternate audio specification, if visualObj is not present. |
+| onEnded | null | A callback function when the AudioBuffer finishes playing. |
+
+The `options` element above can have the following properties:
+
+| Property | Default | Description |
+|---|---|---|
+| sequenceCallback | null | A hook to get the instructions that will be passed to the Audio Buffer. This can be used either to debug what audio was generated or to modify the sequence before the audio is created. This can be useful to add "swing" to the beats, or do any other processing that isn't possible in ABC notation. |
+| callbackContext | null | This is passed back with the sequenceCallback. It can be anything you want. |
+| program | 0 | The midi program (aka "instrument") to use, if not specified in ABC string. |
+| midiTranspose | 0 | The number of half-steps to transpose everything, if not specified in ABC string. |
+| channel | 0 | The "midi channel" to use. This isn't particularly useful except that specifying channel 10 means to use the percussion sounds. |
+| drum | null | Whether to add a drum (or metronome) track. A string formatted like the `%%MIDI drum` specification. Using this parameter also implies `%%MIDI drumon` See the section for "Drum Parameter" for an explanation. |
+| drumBars | 1 | How many bars to spread the drum pattern over. See the section for "Drum Parameter" for an explanation. |
+| drumIntro | 0 | The number of measures of count in beats before the music starts. |
+| drumOff | false | If you want a metronome only for the intro measures but not when the tune starts, use this along with the `drumIntro` and `drum` params. This has no effect if either one of those is missing. |
+| qpm | null | The tempo to use. This overrides a tempo that is in the tune. |
+| defaultQpm | null | The tempo to use, only if there is no tempo in the tune. |
+| chordsOff | false | If true, then don't turn the guitar chord symbols into sound. (But do play the metronome if there is one.) |
+| voicesOff | false | If true, play the metronome and accompaniment; do the animation callbacks, but don't play any melody lines. This can also be an array of voices to turn off. The voices are numbered starting at zero. |
+| detuneOctave | 0 | The number of cents to raise the pitch of the top note of an octave that is played at the same time. That is, in multipart music, if the tenor and soprano parts are an octave apart the soprano note gets lost in the overtones. Making the top note slightly sharp brings it out without making it sound out of tune. |
+
+### play(), pause(), toggleLoop(), restart(), setProgress(ev)
+
+These do the same thing as the user pressing these buttons, but can be called programmatically.
+
+### setWarp(percent)
+
+This changes the tempo to the percent passed in. That should be a positive integer. It will change the tempo immediately if the music is already playing.
+
+### download(fileName)
+
+This will download the current audio buffer as a WAV file to the fileName passed in.
+
+### Example
+
+The following creates an audio control that the user can manipulate.
+
+```javascript
+// given that there are two elements in the DOM with the IDs "paper" and "audio"
+var cursorControl = { ... }; // see section on CursorControl
+var abc = "X:1\n etc...";
+var abcOptions = { add_classes: true };
+var audioParams = { chordsOff: true };
+
+if (ABCJS.synth.supportsAudio()) {
+ var synthControl = new ABCJS.synth.SynthController();
+ synthControl.load("#audio",
+ cursorControl,
+ {
+ displayLoop: true,
+ displayRestart: true,
+ displayPlay: true,
+ displayProgress: true,
+ displayWarp: true
+ }
+ );
+
+ var visualObj = ABCJS.renderAbc("paper",
+ abc, abcOptions);
+ var createSynth = new ABCJS.synth.CreateSynth();
+ createSynth.init({ visualObj: visualObj[0] }).then(function () {
+ synthControl.setTune(visualObj[0], false, audioParams).then(function () {
+ console.log("Audio successfully loaded.")
+ }).catch(function (error) {
+ console.warn("Audio problem:", error);
+ });
+ }).catch(function (error) {
+ console.warn("Audio problem:", error);
+ });
+} else {
+ document.querySelector("#audio").innerHTML =
+ "Audio is not supported in this browser.";
+ }
+}
+```
+
+## getMidiFile(source, options)
+
+This is called to get the audio in MIDI format, instead of as a playable audio buffer.
+
+```javascript
+ABCJS.synth.getMidiFile(source, { midiOutputType: 'binary', bpm: 100 })
+```
+
+### source
+
+Either the ABC string to create the MIDI from or the object that is returned from `renderAbc`.
+Note that `renderAbc` returns an array, so to get the first tune, for instance, you need to use `[0]`.
+When using the object many of the options passed in are ignored because the tune is already created.
+
+### options
+
+The same options as are used elsewhere, with the addition of:
+
+```javascript
+options = {
+ midiOutputType: "encoded" | "binary" | "link",
+ // The following OPTIONAL parameters are only used when the type is "link":
+ downloadClass: "class-name-to-add",
+ preTextDownload: "text that appears before the link",
+ downloadLabel: function() | "the text that appears as the body of the anchor tag that is clickable",
+ postTextDownload: "text that appears after the link",
+ fileName: "the name of the file that the midi will be saved as"
+}
+```
+Note that `downloadLabel` can be either a string or a function that is passed the tune object and the tune index.
+The return of that function must be a string. If downloadLabel is text and contains `%T` then that is replaced by the tune's title.
+
+#### midiOutputType
+
+If this is not present or set to `link`, then the return value is a link that can be placed directly on the page for the user to download.
+
+If this is set to `binary`, then the actual contents of the midi file are returned, as a blob.
+
+If this is set to "encoded", then the contents of the midi file are returned, as an encoded ASCII string. That is, bytes are represented by `%xx` where xx is a hexidecimal value.
+
+#### downloadLabel
+
+If this isn't present, then the title is retrieved from the tune and the label is "Download MIDI for $TITLE".
+
+If you'd like to use the title in the label but modify it, use `%T`. That is: `downloadLabel: "the tune %T is ready for download"`
+
+### Examples
+
+#### Complete download link
+
+```html
+
+```
+
+```javascript
+var midi = ABCJS.synth.getMidiFile("X:1\nT:Cooley's\netc...", { chordsOff: true, midiOutputType: "link" });
+document.getElementById("midi-link").innerHTML = midi;
+```
+That results in the following html:
+
+```html
+
+```
+
+#### The midi data for your own download
+
+```html
+MIDI
+```
+
+```javascript
+var midi = ABCJS.synth.getMidiFile("X:1\nT:Cooley's\netc...", { chordsOff: true, midiOutputType: "encoded" });
+document.getElementById("midi-link").setAttribute("html", midi);
+```
+
+#### Actual midi file to pass to another library
+
+```javascript
+var midi = ABCJS.synth.getMidiFile("X:1\nT:Cooley's\netc...", { chordsOff: true, midiOutputType: "binary" });
+otherLibraryMidiPlayer.loadTune(midi);
+```
+
+#### Passing an object
+
+If you already have parsed the tune you can just pass it in:
+```javascript
+var visualObj = ABCJS.renderAbc("paper", "X:1\nT:Cooley's\netc...");
+var midi = ABCJS.synth.getMidiFile(visualObj[0], { midiOutputType: "encoded" });
+```
+
+## CreateSynthControl
+
+Lower level object than `SynthController` if you want the functionality without the visible control.
+
+```javascript
+var control = new ABCJS.synth.CreateSynthControl(element, options);
+```
+
+`element` is either a string representing a selector of an existing element on the page or a DOM element. The contents of that element are replaced with an audio control.
+
+### options parameter
+
+| Option | Description |
+| ------------- | ------------- |
+| loopHandler | Callback function when the loop button is clicked. If this is not present, then the loop button is not displayed. |
+| restartHandler | Callback function when the restart button is clicked. if this is not present, then the restart button is not displayed. |
+| playHandler or playPromiseHandler | Callback function when the play button is clicked. if this is not present, then the play button is not displayed. If the `handler` version is present, then it must return a promise. |
+| progressHandler | Callback function when the progress bar is clicked. if this is not present, then the progress bar is not displayed.|
+| warpHandler | Callback function when the warp percent is changed. if this is not present, then the warp percent is not displayed. |
+| afterResume | Callback function after the AudioContext is set up correctly. |
+| ------------- | ------------- |
+| hasClock | Whether to display a clock on the control. |
+| ac | The AudioContext to use for this control. (Optional - if this is not present, then a button will appear asking the user to click to get an AudioContext.) |
+| ------------- | ------------- |
+| repeatTitle | To override the text of the tooltip for toggling loop mode. |
+| repeatAria | To override the text of the aria for loop mode. (By default, the repeatTitle is used.) |
+| restartTitle | To override the text of the tooltip for the restart button. |
+| restartAria | To override the text of the aria for restart mode. (By default, the restartTitle is used.) |
+| playTitle | To override the text of the tooltip for the play/pause button. |
+| playAria | To override the text of the aria for the play/pause. (By default, the playTitle is used.)|
+| randomTitle | To override the text of the tooltip for the progress slider. |
+| randomAria | To override the text of the aria for progress slider. (By default, the randomTitle is used.)|
+| warpTitle | To override the text of the tooltip for the warp input. |
+| warpAria | To override the text of the aria for warp input. (By default, the warpTitle is used.)|
+| bpm | To override the text "BPM" for beats per minute. |
+
+## SynthSequence
+
+Creates an object that builds data for `CreateSynth`. This is normally done internally if `CreateSynth` is passed a visual object, but this is a way to custom build any sequence.
+
+```javascript
+var sequencer = ABCJS.synth.SynthSequence()
+sequencer.addTrack();
+sequencer.setInstrument(0, 25);
+sequencer.appendNote({ trackNumber: 0, pitch: 60, durationInMeasures: 1, volume: 80 })
+
+var buffer = new ABCJS.synth.CreateSynth();
+return buffer.init({
+ sequence: sequence,
+}).then(function () {
+ return buffer.prime();
+}).then(function () {
+ return buffer.start();
+});
+```
+This is a helper object that will create an object that is consumed by `CreateSynth`. There is nothing special about this that you couldn't create the object by hand, but this provides some convenience functions.
+
+| Method | Parameters |Description |
+| ------------- | ----------- | ----------- |
+| `addTrack` | (none) | Returns the number of the track that was created. This must be called before anything can be added to the track. |
+| `setInstrument` | `trackNumber, instrumentNumber` | `trackNumber` is the value that is returned by `addTrack`. instrumentNumber is the stand MIDI number for the instrument. (See `ABCJS.synth.instrumentIndexToName` for the list of instruments.) This should be called right after `addTrack` and may be called at any time after that to change the instrument midstream. |
+| `appendNote` | `trackNumber, pitch, durationInMeasures, volume` | This adds a note. `trackNumber` is the value returned from `addTrack`. `pitch` is the standard midi pitch number. `durationInMeasures` is a floating point number where "1" is one measure. `volume` is a value from 0 to 255 that is the volume of the note. |
+
+## CursorControl object
+
+If you want notification when events happen, then you can pass in an object that you create yourself. Note that even though this object is called `CursorControl` it can be used for anything that requires knowledge of various events that happen during playback: when a note is played, when a beat is reached, when the end of a music line is near, when a measure starts, and when the music stops.
+
+The following properties are used:
+
+- beatSubdivisions
+
+How often to call the beat callback. If this is not set, then the beat callback is called once per beat. If you want a finer grained control, you can set this to a larger number. Notice that a large number will affect performance.
+
+- extraMeasuresAtBeginning
+
+How many extra measures to have at the beginning before the tune actually starts. This can be used for count in beats.
+
+- lineEndAnticipation
+
+When to call the onLineEnd event. If you want to scroll the music when the end of the line is reached, then you probably want to scroll it a little in advance so the user can read ahead. This is the number of milliseconds, so the value of 500 means to scroll the music one half second before the end of the line.
+
+- onReady(synthController)
+
+Called when the tune has actually been loaded. Because the audio buffer can only be initialized after a user gesture, the tune might not have been loaded when the visual control is created. This might be called when `setTune` is called, or when the user clicks PLAY.
+
+The parameter is the instance of the synthController that called it.
+
+- onStart()
+
+Called when the tune has actually started: that is, after all the set up has been completed.
+
+- onFinished()
+
+Called when the tune has finished.
+
+- onBeat(beatNumber, totalBeats, totalTime)
+
+Called each beat, or each subdivision of a beat.
+
+ - beatNumber
+
+This is the current beat - in a perfect case, this is called regularly. There are various things that can cause JavaScript to stop running, though, so it might get called a bunch of times in a row to catch up. This can be a fraction, if `beatSubdivisions` is present.
+
+- onEvent(event)
+
+This is called every time a note, rest, or bar is encountered.
+
+The `event` parameter has these properties:
+
+| Property | Description |
+|---|---|
+| measureStart | `true` if this is the beginning of a measure. (Note, beware of the case where the only event at the beginning of a measure is a note tied from a previous note. There might not be anything to do.) |
+| elements | The actual SVG elements that represent the note(s) being played. |
+| left | The leftmost point of the current elements. |
+| top | The topmost point of the current elements. |
+| height | The height of the current elements. |
+| width | the width of the current elements. |
+
+- onLineEnd(data)
+
+This is called when the end of the line is approaching. The data is the following properties:
+
+| Property | Description |
+|---|---|
+| milliseconds | The current time. |
+| top | The top of the current line. |
+| bottom | The bottom of the current line. |
+
+Use this to determine if the SVG should be scrolled.
+
+Example:
+```javascript
+var CursorControl = function() {
+ this.beatSubdivisions = 2;
+ this.onStart = function() {
+ console.log("The tune has started playing.");
+ }
+ this.onFinished = function() {
+ console.log("The tune has stopped playing.");
+ }
+ this.onBeat = function(beatNumber) {
+ console.log("Beat " + beatNumber + " is happening.");
+ }
+ this.onEvent = function(event) {
+ console.log("An event is happening", event);
+ }
+}
+var cursorControl = new CursorControl();
+synthControl = new ABCJS.synth.SynthController();
+synthControl.load("#audio", cursorControl, {displayPlay: true, displayProgress: true});
+```
+
+## playEvent(pitches, gracenotes, millisecondsPerMeasure)
+
+This will play a single event that is passed. The event must have the same format as the events that are passed back by the click listener.
+
+### pitches
+
+An array of pitches. If there is more than one item in the array, they are played at the same time. Pitches contain:
+
+| Attribute | Description |
+|---|---|
+| pitch | An integer value of the pitch, where middle C is 60 |
+| durationInMeasures | The length of the note. For instance, a quarter note in 4/4 would be .25 |
+| volume | A number from 0 to 127 for the volume of the note. |
+| instrument | The number of the instrument in the MIDI spec. |
+
+### gracenotes
+
+These are the same format as above, except that these notes are played before the main note for a short time. Also, if there is more than one note in the array, the notes are played sequentially.
+
+### millisecondsPerMeasure
+
+This is used to translate the `durationInMeasures` value into an actual time.
+
+### Example:
+
+```javascript
+ABCJS.synth.playEvent(
+ [ // a C chord
+ {"cmd":"note","pitch":60,"volume":105,"start":0,"duration":0.125,"instrument":0,"gap":0},
+ {"cmd":"note","pitch":64,"volume":105,"start":0,"duration":0.125,"instrument":0,"gap":0},
+ {"cmd":"note","pitch":67,"volume":105,"start":0,"duration":0.125,"instrument":0,"gap":0},
+ ],
+ [ // start with a D as a grace note
+ {"pitch":62,"durationInMeasures":0.125,"volume":70,"instrument":0}
+ ],
+ 1000 // a measure takes one second.
+).then(function (response) {
+ console.log("note played");
+}).catch(function (error) {
+ console.log("error playing note", error);
+});
+
+```
+
+## activeAudioContext()
+
+If there is an AudioContext that is being used then this retrieves it. It allows freely sharing the same one in different parts of your app.
+
+```javascript
+var ac = ABCJS.synth.activeAudioContext();
+```
+
+## instrumentIndexToName[index]
+
+This is an array that converts the standard MIDI instrument indexes to a name. For instance:
+```javascript
+console.log(ABCJS.synth.instrumentIndexToName[9]);
+// "glockenspiel"
+```
+
+## pitchToNoteName[pitchNumber]
+
+This is an array that converts the standard MIDI pitch indexes to a name. For instance:
+```javascript
+console.log(ABCJS.synth.pitchToNoteName[60]);
+// "C4"
+```
+
+## Tempos
+
+If the `qpm` parameter is not supplied, abcjs makes its best guess about what tempo should be used. If there is no tempo indicated at all in the ABC string, then 180 BPM is arbitrarily used. If `defaultQpm` is supplied, then that default will be used only if there is no explicit tempo.
+
+If an exact tempo line is supplied with the `Q:` line, then that tempo is used. If the `Q:` contains a standard tempo string, that string is used to make a guess at an appropriate tempo. Here is a list of the known tempo strings and their associated tempos. If you would like to make suggestions about other strings to support or changes to these tempos, please get in touch:
+
+|Tempo|BPM|
+|---|---|
+|larghissimo|20|
+|adagissimo|24|
+|sostenuto|28|
+|grave|32|
+|largo|40|
+|lento|50|
+|larghetto|60|
+|adagio|68|
+|adagietto|74|
+|andante|80|
+|andantino|88|
+|marcia moderato|84|
+|andante moderato|100|
+|moderato|112|
+|allegretto|116|
+|allegro moderato|120|
+|allegro|126|
+|animato|132|
+|agitato|140|
+|veloce|148|
+|mosso vivo|156|
+|vivace|164|
+|vivacissimo|172|
+|allegrissimo|176|
+|presto|184|
+|prestissimo|210|
+
+## Drum parameter
+
+See the ABC documentation for the correct way to format the string that is passed as the drum parameter. Here is a table that provides a fairly reasonable default for drum, drumIntro, and drumBars when used as a metronome:
+```
+ const drumBeats = {
+ // the array is [0]=drum [1]=drumIntro
+ "2/4": ["dd 76 77 60 30", 2],
+ "3/4": ["ddd 76 77 77 60 30 30", 1],
+ "4/4": ["dddd 76 77 77 77 60 30 30 30", 1],
+ "5/4": ["ddddd 76 77 77 76 77 60 30 30 60 30", 1],
+ "Cut Time": ["dd 76 77 60 30", 2],
+ "6/8": ["dd 76 77 60 30", 2],
+ "9/8": ["ddd 76 77 77 60 30 30", 1],
+ "12/8": ["dddd 76 77 77 77 60 30 30 30", 1]
+ };
+```
+A more complicated example that has the drum pattern fall over two measures of 2/4 time (This is a typical Bulgar pattern):
+```
+{ drum: "d2dd2ddz 76 77 76 77 77 60 30 60 30 30", drumBars: 2, drumIntro: 2 }
+```
+
+Note that the default soundfont that is used by abcjs contains sounds for pitches **27** through **87**. You can experiment with any of them for different effects.
+
+
diff --git a/docs/deprecated/deprecated-api.md b/docs/deprecated/deprecated-api.md
new file mode 100644
index 0000000000000000000000000000000000000000..3872f62df2aa69803462ae50930735804bcae971
--- /dev/null
+++ b/docs/deprecated/deprecated-api.md
@@ -0,0 +1,99 @@
+# Deprecated API Calls
+
+::: warning Deprecation
+The following calls still work, but they have been superseded by other methods. If you are writing a new app, avoid these because they might go away sometime in the future.
+:::
+
+## parseOnly
+
+```javascript
+tuneObjectArray = ABCJS.parseOnly(tunebookString, params)
+```
+
+Parses all the tunes in the tunebookString and returns an array of them parsed structure.
+
+This has turned out to not be that useful since you can do the same effect by passing "*" in as the element and the returned value will have a lot more information.
+
+## Animation
+
+This animation has been replaced by `TimingCallbacks`, which is much more flexible.
+
+### startAnimation
+```javascript
+ABCJS.startAnimation(outputElement, tuneObject, animationParams)
+```
+
+Puts an animated cursor on the rendered music. Note: this is deprecated in favor of `TimingCallbacks`.
+
+### stopAnimation
+```javascript
+ABCJS.stopAnimation()
+```
+
+Stops the animation that was started with `startAnimation`.
+
+### pauseAnimation
+```javascript
+ABCJS.pauseAnimation(pause)
+```
+
+Pauses/resumes the animation that was started with `startAnimation`. Pass `true` or `false` to pause or resume.
+
+## Midi.js
+
+This has been replaced by the new audio interface. Hopefully the new interface will work on more systems, be faster, and require fewer resources.
+
+### deviceSupportsMidi
+```javascript
+ ABCJS.midi.deviceSupportsMidi()
+```
+Returns true if the device and browser is capable of playing MIDI.
+
+### setSoundFont
+```javascript
+ABCJS.midi.setSoundFont(url)
+```
+Sets an alternate location for the soundfont.
+
+### renderMidi
+```javascript
+tuneObjectArray = ABCJS.renderMidi(output, tunebookString, params)
+```
+
+Completely creates midi for the tunebook. Note: this is deprecated in favor of [Synth Documentation](../docs/audio/synthesized-sound.md).
+
+
+### startPlaying
+```javascript
+ABCJS.midi.startPlaying(targetEl)
+```
+
+Starts playing the MIDI for the element passed in. If the element is already playing, this pauses it.
+
+### stopPlaying
+```javascript
+ABCJS.midi.stopPlaying()
+```
+
+Stops playing whatever is currently playing.
+
+### restartPlaying
+```javascript
+ABCJS.midi.restartPlaying()
+```
+
+Moves the progress back to the beginning for whatever is currently playing.
+
+### setRandomProgress
+```javascript
+ABCJS.midi.setRandomProgress(percent)
+```
+
+Moves the progress to whatever percent is passed in for whatever is currently playing.
+
+### setLoop
+```javascript
+ABCJS.midi.setLoop(targetEl, state)
+```
+
+Sets the "loop" mode for the element passed in. State should be true or false.
diff --git a/docs/developers/basic-architecture.md b/docs/developers/basic-architecture.md
new file mode 100644
index 0000000000000000000000000000000000000000..ab38e175dbcebddb2dfbae5018006f83aa3ad2f9
--- /dev/null
+++ b/docs/developers/basic-architecture.md
@@ -0,0 +1,144 @@
+# Basic Architecture
+
+There are two forms of this library: the npm form and a minimized form for non-npm users.
+
+When testing abcjs changes locally, there is no build step required. A handy way to test is to run:
+
+```
+npm link
+```
+
+On this folder, and
+```
+npm link abcjs
+```
+
+in an npm-based test application (like React or Vue). Then any changes made to the abcjs code will automatically be picked up by that test application's webpack.
+
+## Docker
+
+There are docker files included so that npm can be run without installing it. This only applies to someone who wants to keep all their development tools separate on their computer. If you have nodejs installed then you can ignore this.
+
+To run, type:
+```bash
+./docker-start.sh
+```
+That will create a linux virtual machine and give you a command line to run npm.
+
+## Building locally
+
+To build the library so that it can be included with a `
+```
+
+## How do I use the sound fonts I have saved locally in my ABCJS project?
+
+See the [sandbox](../audio/synthesizer-sandbox.md) to see the syntax.
+
+## I’m trying to get the names of notes on click and it doesn’t work. I’ve got a visual rendering of my tune, but no playback widget.
+
+There is some optional extra information that can be added to the music structure. This is added when creating the synth but it isn't added by default so that the code isn't unnecessarily executed for users who don't need it.
+
+To add that information:
+```javascript
+var visualObj = abcjs.renderAbc( ... )
+visualObj[0].setUpAudio()
+```
+
+## Can I use ABCJS in React Native/other mobile development frameworks?
+
+ABJS needs a DOM to 1) calculate how much space the notes will take up once rendered, and 2) render the notes as an SVG. This makes integrating ABCJS with frameworks like React Native that don’t use a DOM less than straightforward.
+
+An approach by Matthew Dorner: His app, react-native-songbook, relies on react-native-svg (via standalone-vexflow-context) to draw to the SVG. You might also try experimenting with rendering the ABCJS elements in a React Native webview component, which supplies the required DOM, as a browser to an external page with ABCJS functionality, rather than as a native rendering engine. Kudos to @rpattcorner for this tip.
+
+## How do I use ABCJS in a server-side rendering app?
+
+If you are using Nuxt or Next or any other framework that builds the pages on the server before sending them to the client, you'll have to delay calling abcjs until you are in the client.
+
+Here's an example:
+```javascript
+const abcjs = process.browser ? require('abcjs') : null;
+
+if (abcjs) {
+ abcjs.renderAbc( ... )
+}
+```
+## Why do I have to wait until the user interacts with the page to create the audio?
+
+Because browsers have placed constraints on AudioContexts to prevent developers from building websites that autoplay sound on page load, you can’t begin to buffer audio until the user makes some gesture on the page.
+
+## How do I get the audio to start right away?
+
+There is some network traffic and construction of the sound buffer that takes some time. This can be done a little bit ahead of time, so, as soon as the user interacts with the page and as soon as you know what music you want to play, you can begin the process. You'll notice that there are `init()` and `prime()` calls that return a promise. After those promises resolve clicking `play()` will be fast.
+
+## How do I prevent this error?: “The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page.”
+
+Don't call any audio-related functionality until the user has interacted with the page.
+
+## I want to replace all the notes with custom glyphs/symbols. How can I do that?
+
+After your call to renderAbc(), search for all items with the class "abcjs-note" and replace the path in them with your picture.
+For this to work, call renderAbc with the parameter { add_classes: true }. Notice there are other things you can search for, like the staff line of the note so you can have different pictures for different notes.
+
+## How can I manipulate the horizontal positioning of the notes — e.g., if I want the notes to be horizontally centered?
+
+You can use `%%staffwidth 400` to pick the number of pixels that the staff will take. You can experiment with that to get it to look right. You can also use `%%stretchlast` to stretch the last line of music out. Also, `staffwidth` can be passed in to the `renderAbc` function. Also, see the wrap.html demo.
+
+## I’m having difficulty transposing my tune.
+Visual and audio transposition are handled separately to suit situations where a musician might want the sheet music transposed but not the audio playback, and vice-versa. For examples of how to handle both forms of transposition, see basic-transpose.html and editor-transpose.html.
diff --git a/docs/overview/getting-started.md b/docs/overview/getting-started.md
new file mode 100644
index 0000000000000000000000000000000000000000..20576af1530e7fc065ba324abbed56e471616c4d
--- /dev/null
+++ b/docs/overview/getting-started.md
@@ -0,0 +1,55 @@
+# Getting Started
+
+## Which flavor should you use?
+
+### node.js
+
+If you are in the node ecosystem, simply install the packaged version with:
+
+ ```
+ npm install --save abcjs
+```
+
+To import, use:
+```
+import abcjs from "abcjs";
+```
+
+To get the styles for the audio control:
+
+```
+import 'abcjs/abcjs-audio.css';
+```
+
+### Old-style minimized download
+
+If you are writing significant JavaScript on your site, and you are generating the music yourself, or you are allowing the user to enter music using ABC notation, whether a whole tune or a fragment, then you probably want to use `abcjs-basic`. This gives you control over the generation in a smaller package.
+
+If you already have ABC notation on your page and don't want to modify the page more than you have to, then you can use `abcjs-plugin`, which will render all ABC that it finds on the page on page load, simply by including one line: the line to include the script. Another use of this is if you have a comment section on a blog, then you can allow users to post ABC tunes and they will appear as sheet music automatically.
+
+If you are looking at someone else's website and see ABC on the page and want to see what it looks like in standard notation, you can install the greasemonkey script in FireFox or Chrome and it will render the ABC for you.
+
+Here are the latest versions. You can just download one of these:
+
+- [Basic](https://raw.githubusercontent.com/paulrosen/abcjs/main/dist/abcjs-basic-min.js)
+
+- [Plugin](https://raw.githubusercontent.com/paulrosen/abcjs/main/dist/abcjs-plugin-min.js)
+
+- [Styles for the Audio control](https://raw.githubusercontent.com/paulrosen/abcjs/main/abcjs-audio.css)
+
+**NOTE: Do NOT link to these files directly! Upload them to your own server! [Here's why.](https://github.com/blog/1482-heads-up-nosniff-header-support-coming-to-chrome-and-firefox)**
+
+You can also use this CDN: `https://cdn.jsdelivr.net/npm/abcjs@VERSION/dist/abcjs-basic-min.js` where `VERSION` is the version of the library you want to use. Note that I don't maintain those files, so I can't guarantee that will still work in the future.
+
+When loading the library directly, you will find the library at `window.ABCJS`.
+
+## Simplest Usage
+
+```html
+
+```
+
+```javascript
+abcjs.renderAbc("paper", "X:1\nK:D\nDD AA|BBA2|\n");
+```
+
\ No newline at end of file
diff --git a/docs/overview/purpose.md b/docs/overview/purpose.md
new file mode 100644
index 0000000000000000000000000000000000000000..0a3c7fda5e3715e9bf6c30a7bdfdd2365754b474
--- /dev/null
+++ b/docs/overview/purpose.md
@@ -0,0 +1,49 @@
+# Purpose
+
+This library makes it easy to incorporate **sheet music** into your **websites**. It is primarily aimed at **javascript developers**. The amount of javascript required for simple uses is very small, though, so one doesn't need to be an expert.
+
+## Uses
+
+* Draw arbitrary sheet music.
+
+* Instantly modify the music.
+
+* Do animation effects with the drawn music.
+
+* Style the music using CSS.
+
+* Create synthesized audio for the music.
+
+* Search for **ABC** formatted strings on a webpage (for instance in post or comments on a blog) and turn them into sheet music.
+
+* Allow the user to modify the music instantly by typing an **ABC** string.
+
+## NOT
+
+* It does not provide a visual editor (although it could be used as a basis if you want to write one.)
+
+## Open Source Apps that require no programming
+
+* If you just want to render your abc but aren't trying to make an entire website, there are a number of openly accessible apps that you can use.
+
+* For working with tunes in the browser, see [the Editor](https://editor.drawthedots.com).
+
+* Also see Michael Eskin's [ABC Tools](https://michaeleskin.com/abctools/abctools.html) for a much more fully-featured editor.
+
+* If you are using VSCode, there is an extension that you install. Get to the extension panel with shift-cmd-X, then search for "abcjs". Once you install that you can see the notation rendered as you type in a file. To use it, open your tune file (ending in `.abc`) and type shift-cmd-P to get the command pallet. Search for "abcjs" to open the preview pane.
+
+## Browser/device support
+
+* The visual part of this library is supported from IE9 and newer, Safari 5.1 and newer, and all modern browsers.
+
+* This synth audio part of this library does not work on IE, but works on any system that supports `AudioContext.resume` and `Promises`. That is, any browser newer than Firefox 40, Safari 9.1, Edge 13, and Chrome 43.
+
+## Supported by BrowserStack
+
+If you aren't using the same browser and machine that I use, you can thank [BrowserStack](https://browserstack.com/) for their support of this open-source project.
+
+
+
+## License
+
+[The MIT License (MIT)](http://opensource.org/licenses/MIT)
diff --git a/docs/overview/resources.md b/docs/overview/resources.md
new file mode 100644
index 0000000000000000000000000000000000000000..0c1f1d5b49b8007f5e223802432597f44df75fd3
--- /dev/null
+++ b/docs/overview/resources.md
@@ -0,0 +1,20 @@
+# Other Resources
+
+[abcjs Home page](https://abcjs.net) (Overview of what this library does)
+
+[Configurator](https://configurator.abcjs.net) (Experiment with all configuration options)
+
+[API Documentation](api.md) (All the details about using abcjs)
+
+[Special Notes](special-notes.md) (Notes from previous versions)
+
+[Old Versions of abcjs](https://github.com/paulrosen/historical-abcjs-versions) (All previous versions of abcjs)
+
+[Info for abcjs contributors](contributing.md) (Info about how abcjs is built and managed)
+
+[Support of the ABC standard](abc-notation.md) (How abcjs varies from the ABC standard)
+
+[Release Notes](RELEASE.md)
+
+License: [The MIT License (MIT)](http://opensource.org/licenses/MIT)
+
diff --git a/docs/plugin/plugin.md b/docs/plugin/plugin.md
new file mode 100644
index 0000000000000000000000000000000000000000..44390f22f8d08a9826fb6b6ff32efea2f8c869e3
--- /dev/null
+++ b/docs/plugin/plugin.md
@@ -0,0 +1,42 @@
+# Plugin
+
+The abcjs plugin renders all the abc in a page (determined as a new line beginning with X:).
+
+::: tip TODO
+This page is currently being enhanced. Check back soon!
+:::
+
+To use, simply include the plugin version in the page:
+
+```javascript
+
+```
+
+Certain options for the plugin can be changed like this, if executed on page load, just after including the plugin file:
+
+```html
+
+```
+
+The options available in abc_plugin are:
+
+| Option | Description |
+| ------------- | ----------- |
+| `show_midi` | NO LONGER SUPPORTED: This option has been removed. |
+| `hide_abc` | Whether the abc text should be hidden or not. (false by default) since 1.0.2 |
+| `render_before` | Whether the rendered score should appear before the abc text. (false by default) since 1.0.2 |
+| `midi_options` | NO LONGER SUPPORTED: This option has been removed. |
+| `auto_render_threshold` | Number of tunes beyond which auto rendering is disabled; instead, each tune is accompanied by a "show" button. (default value is 20) since 1.0.2 |
+| `show_text` | Text to be included on the "show" button before the tune title. (default value is "show score for: ") since 1.0.2 |
+| `render_options` | The options to be used for the `engraverParams` |
+| `render_classname` | The class name to use for the resulting SVG (default value is "abcrendered") |
+| `text_classname` | The class name to use for wrapping the found ABC text (default value is "abctext") |
+
+When abcjs plugin finds an abc tune, it wraps a `div.abctext` around it and renders it into a `div.abcrendered`. The show button is an `a.abcshow`. These hooks can be used for styling. since 1.0.2
+
+
+## abcjs greasemonkey script
+
+Just include the greasemonkey script in either FireFox or Chrome. You will then get a button that will begin the scan of the website.
diff --git a/docs/transposing/transposing.md b/docs/transposing/transposing.md
new file mode 100644
index 0000000000000000000000000000000000000000..b88c4298ae4ae4ec64dba627876bd22ed8571014
--- /dev/null
+++ b/docs/transposing/transposing.md
@@ -0,0 +1,52 @@
+# Transposition
+
+The ABC string can be transposed to another key and output as a string.
+
+Note that there are other forms of transposition using parameters to the `abcRender` call, but they do not output a string that can be used elsewhere. If you want to visually transpose you can use [visualTranspose](/abcjs/visual/render-abc-options.html#visualtranspose). If you want to transpose just the audio, use [midiTranspose](/abcjs/audio/synthesized-sound.html#audioparams)
+
+## Entry Point
+
+```
+var newAbc = ABCJS.strTranspose(originalAbc, visualObj, steps)
+```
+
+## Parameters
+
+All parameters are required
+
+### originalAbc
+Default: none
+
+This is the ABC string that you want to transpose.
+
+### visualObj
+Default: none
+
+This is the result of rendering that string. You must call `renderAbc()` before calling `strTranspose()`.
+
+### steps
+Default: none
+
+This is the number of half steps to transpose. It can be positive to transpose higher in pitch or negative to transpose lower. It can be `12` or `-12` to transpose an octave and can be larger than that to transpose more than an octave.
+
+## Example
+```
+var abc = "K:D\nDEFG|"
+var steps = 2
+var visualObj = abcjs.renderAbc("paper", abc);
+var output = abcjs.strTranspose(abc, visualObj, steps)
+```
+
+For a full example, see the [Transposition Example](https://paulrosen.github.io/abcjs/examples/output-transpose.html).
+
+## Notes
+
+There are some types of ABC that cannot be transposed and because of the wide range of ways to write ABC there are some ABC strings that won't be transposed completely.
+
+For instance, lines that have a clef of "perc" will not be transposed. And some ABC strings contain notes and chords in the lyric line or using the "annotation" syntax. Those will not be transposed.
+
+That said, most input strings use a subset of the full ABC spec and are transposed completely.
+
+::: tip Bugs
+This is a new feature and because of the complexity of the ABC specification there are bound to be bugs! Please let me know if you see an example of something that *should* have been transposed but wasn't.
+:::
diff --git a/docs/upgrading/midijs.md b/docs/upgrading/midijs.md
new file mode 100644
index 0000000000000000000000000000000000000000..5191231549b8b5426bcb6b198c961d77191424e5
--- /dev/null
+++ b/docs/upgrading/midijs.md
@@ -0,0 +1,57 @@
+# MIDI.JS Usage
+
+## Midi.js removed
+
+The last version supporting this interface is 6.0.0-beta.28.
+
+## Notes for Version 5.8.0
+
+This way of creating midi is being deprecated by a new method that is much smaller, less buggy and integrates with the TimingCallbacks object. This will continue to work for the forseeable future, but probably won't change much.
+
+See [Synth Documentation](../audio/synthesized-sound.md) for details.
+
+## Notes for Version 3.0 Beta
+
+There are a number of features described below that are not yet activated. This release is primarily to get the main MIDI functionality working. Here is a list of features you can look forward to in upcoming versions:
+
+* Changing the instrument and channel in the midi file: right now, one channel is used, and the instrument is Grand Piano.
+
+* Changing the tempo is not available.
+
+* The listener doesn't return much information: look for much more to come.
+
+* The "play selection" functionality is not implemented.
+
+* The "bouncing ball" functionality is not implemented.
+
+## MIDI generation in ABCJS
+
+There are two ways to generate MIDI: as a download link, and as an inline control. The download link method is built into ABCJS. The inline control, though, depends on the external library [MIDI.js](https://github.com/mudcube/MIDI.js)
+
+That, in turn, is dependent on a set of sound fonts. A good place to get them is [MIDI.js Soundfonts](https://github.com/paulrosen/midi-js-soundfonts)
+
+## Site Setup
+
+* Use the version of the library that contains midi.js.
+
+* The soundfonts, by default, are served from github. If you would like host them yourself, put them on your server in a publicly accessible place and call:
+
+`window.ABCJS.midi.setSoundFont("/url/to/soundfont/");`
+
+The trailing slash is required.
+
+There is also some CSS required to make the MIDI control look right. You can use the example CSS in this repository and modify it to match your site. The example CSS uses Font Awesome. Include these two lines:
+
+``
+``
+
+## Creating the MIDI
+
+After doing the above steps to load the CSS and the sound fonts, the simplest way to produce the MIDI is:
+
+`window.ABCJS.renderMidi("id-of-div-to-place-midi-controls", abcString, {}, { generateInline: true }, {});`
+
+
+## Example
+
+See the examples in this repository. They contain the prerequisite files. [Editor](/examples/editor-midi.html), [Printable](/examples/printable.html).
diff --git a/docs/upgrading/release-notes.md b/docs/upgrading/release-notes.md
new file mode 100644
index 0000000000000000000000000000000000000000..56abe82a2b44ace2a0736a01a4229ac0d2f86dbe
--- /dev/null
+++ b/docs/upgrading/release-notes.md
@@ -0,0 +1,163 @@
+# Release Notes
+
+Full release notes can be found in the [RELEASE.md](https://github.com/paulrosen/abcjs/blob/main/RELEASE.md) file.
+
+## Notes for Version 6.0.0
+
+There has been a large change in the underlying SVG output. It should look exactly the same, but it will take up much less space. Also a number of inconsistencies in the way classes are applied has been fixed. If you are just using the library to output standard notation, you probably won't notice any difference. However, if you are querying the SVG directly, or setting CSS that targets elements, then you will need to retest.
+
+There has been a change to the data that comes back from the click listener. This includes information if the user has dragged a note.
+
+There are some minor improvements to the spacing of elements. That may slightly change how the music is laid out.
+
+There have been many improvements to the audio quality. More improvements are coming, too!
+
+## Notes for Version 5.9.0
+
+This is a beta version of the new synth method. It is likely there will be some changes to the API in the short run but hopefully not too much.
+
+Please try this out and report any issues that you have.
+
+## **Special note for Version 5.8.0:**
+
+A new method for creating synth sound is included as a **beta** release in this release. See [Synth Documentation](../docs/audio/synthesized-sound.md) for details in how to use it. That means that the current method of creating sound using midi.js will be deprecated at some point in the future. It will be supported in its current form as long as possible. The new synth is much smaller and faster and appears less buggy. It does not work on IE 11 or older browsers, however, so it might not yet be appropriate for your site.
+
+## Special notes for Version 5.0.0:
+
+* The dependency on the Raphael library has been removed! This has made the minimized package 90K smaller, and has increased the speed of generating the SVG image by about 6 times!
+
+For the most common use of creating either the sheet music or the audio, there isn't any change.
+
+However, if you use the animation callback in the audio to manipulate the notes, then be aware that, instead of receiving elements that are wrapped in a Raphael object, you now receive the actual
+SVG element. For the most common example of the animation functionality, the following was recommended to change the color of notes:
+```
+element.attr({ fill: color });
+```
+That should be changed to:
+```
+element.setAttribute("fill", color);
+```
+
+* If you do specific manipulation of the SVG, you will need to retest your code. The generated SVG, while it looks the same on the page, has changed somewhat. The selectors you use may return different results.
+
+## Special notes for Version 4.0.0:
+* **BREAKING CHANGE**: The names of all the classes that are generated are now prefixed with `abcjs-`. Any code that searched for particular class names before will have to be adjusted.
+
+* The parameters have been combined into one set of parameters, instead of three sets like previous versions. The old way of calling the parameters will still work, but you are encouraged to use the new, simplified approach going forward.
+
+## Special notes for Version 3.3.0:
+
+* The build process has switched over to webpack. The minimization is now done with UglifyJS. This shouldn't cause any side effects.
+
+* The "editor" version of the library has been rolled into the "basic" version. There is only the "basic" and "midi" versions now, since the editor code doesn't add much to the size.
+
+* The npm version has a new export called "signature" that gives your javascript code some version information.
+
+* The documentation has all been moved to the `/docs` folder.
+
+* The examples have all been moved to the `/examples` folder.
+
+## Special note for Version 3.2.0:
+
+abcjs is proud to announce that it can now be installed with `npm`. Instead of including the minimized files on your page, you can use the library by doing the following in your project:
+```bash
+npm install --save abcjs
+```
+
+Note that the minimized versions will still be maintained, so you can still copy the minimized file to your project.
+
+## Special notes for Version 3.0:
+
+In-browser [MIDI](/docs/upgrading/midi.md) is now supported. There are some extra dependencies when using that feature. Downloadable MIDI is still supported with no extra dependencies.
+
+## API Changes for Version 3.0
+
+* Added viewPortHorizontal and scrollHorizontal to the renderParams.
+* Add class "slur" to slurs and ties.
+* Add "hint measure"
+* Allow scrolling in the animation.
+* Handle %%titlecaps directive.
+* Add curly brace to indicate piano part (with inspiration from Anthony P. Pancerella).
+* Add invisible marker to the top of each system so that it can be found easily.
+* Add an option to put each line in a separate svg so that browsers will paginate correctly.
+
+## API Changes for Version 3.0 Beta
+
+* The default MIDI program has been changed to "0".
+
+* There are a number of new MIDI parameters.
+
+## API Changes for Version 1.11
+
+"Bouncing Ball" cursor:
+
+ ABCJS.startAnimation(paper, tune, options)
+ paper: the output div that the music is in.
+ tune: the tune object returned by renderAbc.
+ options: a hash containing the following:
+ hideFinishedMeasures: true or false [ false is the default ]
+ showCursor: true or false [ false is the default ]
+ bpm: number of beats per minute [ the default is whatever is in the Q: field ]
+
+`renderABC()` now returns the object that was created by the process. This allows further processing.
+
+`highlight()` and `unhighlight()` now can be passed an optional class name and color.
+
+Descriptive classes to all SVG elements: If you include `{ add_classes: true }` in the rendering params,
+then a set of classes are applied to each SVG element so they can be manipulated with css.
+
+## API Changes for Version 1.3
+
+There is a new public entry point that is designed for those who want some information about what is in a tunebook before processing it.
+
+```JavaScript
+// Tunebook is the contents of the text file containing one or more
+// ABC-formatted tunes, plus global header info, and inter-tune text.
+var book = new ABCJS.TuneBook(tunebook);
+
+var fileHeader = book.header;
+var numberOfTunes = book.tunes.length;
+
+for (var i = 0; i < numberOfTunes; i++) {
+ var title = book.tunes[i].title;
+ var tuneAndHeader = book.tunes[i].abc;
+ var justTheTune = book.tunes[i].pure;
+ var id = book.tunes[i].id;
+}
+
+var tune = book.getTuneById(id);
+tune = book.getTuneByTitle(title);
+```
+
+The variable `book` contains:
+
+| Member | Description |
+| ------------- | ----------- |
+| book.header | This is all of the text that appears before the first tune starts in the file. |
+| book.tunes.length | This is how many tunes are in that file. |
+| book.tunes[i].title | This is the first title found for the particular tune. White space is trimmed from both the beginning and end. |
+| book.tunes[i].abc | This is the particular tune with the global header information added to it. This is what should be passed to the parser in most cases. |
+| book.tunes[i].pure | This is the particular tune without the header. |
+| book.tunes[i].id | This is the id (that is, the text on the X: line). White space is trimmed from both the beginning and end. |
+| book.getTuneById | This will find the FIRST tune in the tune book with the id. |
+| book.getTuneByTitle | This will find the FIRST tune in the tune book with the title. |
+
+
+## API Changes for Version 1.1
+
+IMPORTANT: Version 1.1 has removed all globals and any side effects of ABCJS except for this single global:
+
+```JavaScript
+window.ABCJS
+```
+
+This means that you will have to modify your pages to use the new syntax. All of the old entry points are still available with a slightly different name. Here is a list of all recommended entry points:
+
+|New name|Old name|
+| ------------- | ----------- |
+|ABCJS.numberOfTunes|numberOfTunes|
+|ABCJS.renderAbc|renderABC|
+|ABCJS.renderMidi|renderMidi|
+|ABCJS.Editor|ABCEditor|
+|ABCJS.plugin|abc_plugin|
+
diff --git a/docs/visual/classes.md b/docs/visual/classes.md
new file mode 100644
index 0000000000000000000000000000000000000000..d5e57a30d44af67e440f0fb207838ecffa07fe93
--- /dev/null
+++ b/docs/visual/classes.md
@@ -0,0 +1,112 @@
+# Classes
+
+## Class Names
+
+If you use, `{ add_classes: true }`, then the following classes are attached to various elements:
+
+| class | description |
+| ------------- | ----------- |
+| abcjs-annotation | Text added with the `"^..."` format. |
+| abcjs-author | The author text |
+| abcjs-bar | The bar lines. |
+| abcjs-bar-number | The bar numbers. |
+| abcjs-beam-elem | The beams connecting eighth notes together. |
+| abcjs-brace | The brace on the left side of the staff (like for piano music.) |
+| abcjs-bracket | The bracket on the left side of the staff. |
+| abcjs-chord | The chord symbols, specified in quotes. |
+| abcjs-clef | All clefs |
+| abcjs-composer | The composer text |
+| abcjs-d0-25, etc. | The duration of the note. (Replace the dash with a decimal point. That is, the example is a duration of 0.25, or a quarter note.) |
+| abcjs-decoration | Everything to do with the extra symbols, like crescendo. |
+| abcjs-defined-text | Text that appears between the lines of music, created with `%%text`. |
+| abcjs-dynamics | The dynamics markings: `p` for instance. Also the crescendo mark. |
+| abcjs-end-m0-n0 | Added to slurs to indicate the ending note. |
+| abcjs-ending | The line and decoration for the 1st and 2nd ending. |
+| abcjs-key-signature | All key signatures |
+| abcjs-l0, abcjs-l1, etc. | (lower case L, followed by a number) The staff line number, starting at zero. |
+| abcjs-ledger | ledger line. |
+| abcjs-lyric | The lyric line. |
+| abcjs-m0, abcjs-m1, etc. | The measure count from the START OF THE LINE. |
+| abcjs-mm0, abcjs-mm1, etc. | The measure count from the START OF THE TUNE. |
+| abcjs-meta-bottom | Everything that is printed after all the music. |
+| abcjs-meta-top | Everything that is printed before the first staff line. |
+| abcjs-n0, abcjs-n1, etc. | The note count from the START OF THE MEASURE. |
+| abcjs-note | Everything to do with a note. |
+| abcjs-note_selected | This is the element that the user has clicked on. |
+| abcjs-p-1, abcjs-p1, etc. | The y-position of the note (where middle-C is zero). |
+| abcjs-part | Each part marking in the music itself. |
+| abcjs-part-order | The part order indicator at the top. |
+| abcjs-rest | Everything to do with a rest. |
+| abcjs-rhythm | The rhythm text. |
+| abcjs-slur | Slurs and ties. (backwards compatible) |
+| abcjs-start-m0-n0 | Added to slurs to indicate the beginning note. |
+| abcjs-tie | Tie. |
+| abcjs-legato | Slur. Because "abcjs-slur" was historically used to indicate either a slur or a tie this indicates only a slur. |
+| abcjs-staff | The horizontal lines that make up the staff. |
+| abcjs-staff-extra | Clefs, key signatures, time signatures. |
+| abcjs-stem | |
+| abcjs-subtitle | The subtitle, both on the top and inserted in the middle |
+| abcjs-symbol | Any special symbol, like a trill. |
+| abcjs-tempo | The tempo marking. |
+| abcjs-text | Extra text that is not part of the music. |
+| abcjs-time-signature | All time signatures |
+| abcjs-title | The line specified by T: |
+| abcjs-top-line | This marks the top line of each staff. This is useful if you are trying to find where on the page the music has been drawn. |
+| abcjs-top-of-system | This marks the top of each set of staves. This is useful if you are trying to find where on the page the music has been drawn. |
+| abcjs-triplet | The extra markings that indicate a triplet. (But not the notes themselves.) |
+| abcjs-unaligned-words | Lyrics at the bottom that aren't lined up with notes. |
+| abcjs-v0, abcjs-v1, etc. | the voice number, starting at zero. |
+
+## Test Tune
+
+Paste in any ABC you want here and see how that affects the classes below:
+
+
+
+
+
+## Found Classes
+
+Select the following classes to see what they point to. (They are ANDed together.)
+
+
+
+## CSS Possibilities
+
+### changing colors
+
+If you want to just change everything to one other color, you can do something like:
+```
+
+
+
+
+
+
+
+
+
+
Accompaniment
+
+
+
This shows different options for tweaking the sound of the accompaniment.