├── .circleci
└── config.yml
├── .gitignore
├── .npmignore
├── .prettierrc.js
├── LICENSE
├── README.md
├── babel.config.js
├── demos
├── basic
│ ├── README.md
│ ├── app.js
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ └── style.css
├── react-demo
│ ├── .gitignore
│ ├── README.md
│ ├── package.json
│ ├── public
│ │ ├── index.html
│ │ └── score.xml
│ └── src
│ │ ├── App.js
│ │ ├── components
│ │ └── Score.jsx
│ │ └── index.js
├── umd-web
│ ├── app.js
│ ├── index.html
│ ├── readme.md
│ └── style.css
└── vue-player-demo
│ ├── .browserslistrc
│ ├── .gitignore
│ ├── LICENSE
│ ├── README.md
│ ├── babel.config.js
│ ├── package-lock.json
│ ├── package.json
│ ├── postcss.config.js
│ ├── public
│ ├── Rest_Test.xml
│ ├── favicon.ico
│ ├── index.html
│ └── score.xml
│ ├── src
│ ├── App.vue
│ ├── assets
│ │ └── logo.png
│ ├── components
│ │ ├── BpmSlider.vue
│ │ ├── InstrumentControl.vue
│ │ ├── PlaybackControls.vue
│ │ ├── PlaybackSidebar.vue
│ │ ├── Score.vue
│ │ └── VolumeSlider.vue
│ ├── main.js
│ ├── plugins
│ │ └── vuetify.js
│ └── scores.js
│ └── vue.config.js
├── package-lock.json
├── package.json
├── rollup.umd.config.js
├── src
├── PlaybackEngine.test.ts
├── PlaybackEngine.ts
├── PlaybackScheduler.ts
├── index.ts
├── internals
│ ├── EventEmitter.test.ts
│ ├── EventEmitter.ts
│ ├── StepQueue.ts
│ └── noteHelpers.ts
├── midi
│ └── midiInstruments.ts
└── players
│ ├── InstrumentPlayer.ts
│ ├── NotePlaybackOptions.ts
│ ├── SoundfontPlayer.ts
│ └── musyngkiteInstruments.ts
├── tsconfig.build.json
├── tsconfig.json
└── umd
└── OsmdAudioPlayer.min.js
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2.1
2 | orbs:
3 | node: circleci/node@1.1.6
4 | jobs:
5 | build-and-test:
6 | executor:
7 | name: node/default
8 | steps:
9 | - checkout
10 | - node/with-cache:
11 | steps:
12 | - run: npm install
13 | - run: npm test
14 | - run: npm run build
15 | workflows:
16 | build-and-test:
17 | jobs:
18 | - build-and-test
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | dist/
3 | .cache/
4 | coverage/
5 | umd/
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | dist/
3 | .cache/
4 | demos/
5 | coverage/
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | printWidth: 120,
3 | arrowParens: "avoid",
4 | };
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Jimmy Utterström
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ℹ️ This project is no longer in active development. I still keep an eye on it and it's open for contributions/PRs but I am not actively working on new feature implementations. The main reason being that there is an official early access audio player to be found (currently only available for donors): https://github.com/sponsors/opensheetmusicdisplay
2 |
3 | # 🎵 OSMD Audio player
4 |
5 | Unoffical audio playback engine for [OpenSheetMusicDisplay](https://github.com/opensheetmusicdisplay/opensheetmusicdisplay). Successor meant to replace my previous proof of concept player & demo at https://github.com/jimutt/osmd-playback-demo.
6 |
7 | This player is still in a very early state and lots of breaking and non-breaking changes will most likely be introduced before the first major release. Use at your own risk!
8 |
9 | ## Install
10 |
11 | ```
12 | npm install osmd-audio-player
13 | ```
14 |
15 | ## Demos / usage
16 |
17 | ### Basic
18 |
19 | Basic no-framework demo with only play, pause & stop functionality.
20 |
21 | **Live demo:** https://osmd-audio-player-demo-basic.netlify.com/
22 | **Source:** https://github.com/jimutt/osmd-audio-player/tree/master/demos/basic
23 |
24 | ### Vue JS + Vuetify
25 |
26 | A more full-featured demo featuring configurable instruments, level control, switching scores & changing tempo.
27 |
28 | **Live demo:** https://osmd-audio-player-demo-vue.netlify.com/
29 | **Source:** https://github.com/jimutt/osmd-audio-player/tree/master/demos/vue-player-demo
30 |
31 | You might notice that there's currently a quite large delay when switching instruments. It's due to the in-advance scheduling to prevent interruptions & timing issues in the audio playback, and there's currently no clearing/reset of the buffer when an instrument change takes place. Some improvements in that area are planned.
32 |
33 |
34 | ### Basic (React)
35 |
36 | Barebones React example, contribution by [@joshstovall](https://github.com/joshstovall).
37 |
38 | **Source:** https://github.com/jimutt/osmd-audio-player/tree/master/demos/react-demo
39 |
40 |
41 | ### Basic (UMD build)
42 |
43 | Same functionality as the basic demo but without any Node.js requirements. Uses the UMD build of OSMD and the audio player for simple plug and play functionality in any web page.
44 |
45 | **Source:** https://github.com/jimutt/osmd-audio-player/tree/master/demos/umd-web
46 |
47 | The minified UMD build can be referenced from JSDelivr: https://cdn.jsdelivr.net/npm/osmd-audio-player/umd/OsmdAudioPlayer.min.js
48 |
49 | ## Features
50 |
51 | - Framework agnostic, not tied to a specific front end Framework
52 | - Multi-instrument support
53 | - Individual level controls
54 | - Automatic tempo detection from score
55 | - Automatic instrument assignment
56 |
57 | ## Roadmap
58 |
59 | - Repeat support
60 | - Dynamics support
61 | - Grace note support
62 | - Click to set playback position
63 | - Updated & properly structured Vue demo
64 | - Quickstart guide & more extensive Readme
65 | - Custom audio stack for playing soundfonts
66 | - Stricter typing
67 | - Unit tests
68 |
69 | ## Credits
70 |
71 |
72 |
73 | [](http://browserstack.com/)
74 |
75 |
76 |
77 | Thank you Browserstack for offering me your Open Source license for cross browser testing.
78 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | [
4 | "@babel/preset-env",
5 | {
6 | targets: {
7 | node: "current",
8 | },
9 | },
10 | ],
11 | ["@babel/preset-typescript"],
12 | ],
13 | };
14 |
--------------------------------------------------------------------------------
/demos/basic/README.md:
--------------------------------------------------------------------------------
1 | # OSMD Audio Player - Basic demo
2 |
3 | Basic demo with a single score and only play, pause and stop functionality.
4 |
5 | ## Run locally
6 |
7 | ```
8 | npm install
9 | npm run serve
10 | ```
11 |
12 | ## Build for production
13 |
14 | Output can be found in the `/dist` directory.
15 |
16 | ```
17 | npm run build
18 | ```
19 |
--------------------------------------------------------------------------------
/demos/basic/app.js:
--------------------------------------------------------------------------------
1 | import { OpenSheetMusicDisplay } from "opensheetmusicdisplay";
2 | import AudioPlayer from "osmd-audio-player";
3 | import axios from "axios";
4 | import { PlaybackEvent } from "../../dist/PlaybackEngine";
5 |
6 | (async () => {
7 | const osmd = new OpenSheetMusicDisplay(document.getElementById("score"));
8 | const audioPlayer = new AudioPlayer();
9 |
10 | const scoreXml = await axios.get(
11 | "https://opensheetmusicdisplay.github.io/demo/sheets/MuzioClementi_SonatinaOpus36No3_Part1.xml"
12 | );
13 |
14 | await osmd.load(scoreXml.data);
15 | await osmd.render();
16 | await audioPlayer.loadScore(osmd);
17 | audioPlayer.on(PlaybackEvent.ITERATION, notes => {
18 | console.log(notes);
19 | });
20 |
21 | hideLoadingMessage();
22 | registerButtonEvents(audioPlayer);
23 | })();
24 |
25 | function hideLoadingMessage() {
26 | document.getElementById("loading").style.display = "none";
27 | }
28 |
29 | function registerButtonEvents(audioPlayer) {
30 | document.getElementById("btn-play").addEventListener("click", () => {
31 | if (audioPlayer.state === "STOPPED" || audioPlayer.state === "PAUSED") {
32 | audioPlayer.play();
33 | }
34 | });
35 | document.getElementById("btn-pause").addEventListener("click", () => {
36 | if (audioPlayer.state === "PLAYING") {
37 | audioPlayer.pause();
38 | }
39 | });
40 | document.getElementById("btn-stop").addEventListener("click", () => {
41 | if (audioPlayer.state === "PLAYING" || audioPlayer.state === "PAUSED") {
42 | audioPlayer.stop();
43 | }
44 | });
45 | }
46 |
--------------------------------------------------------------------------------
/demos/basic/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | OSMD Audio Player - basic demo
8 |
9 |
10 |
11 |
12 | Play
13 | Pause
14 | Stop
15 |
16 |
17 |
Loading
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/demos/basic/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "osmd-audio-player-demo-basic",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "app.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "serve": "parcel index.html --port 1337",
9 | "build": "parcel build index.html"
10 | },
11 | "author": "Jimmy Utterström",
12 | "license": "MIT",
13 | "dependencies": {
14 | "axios": "^0.21.2",
15 | "opensheetmusicdisplay": "^0.8.4",
16 | "osmd-audio-player": "../../"
17 | },
18 | "devDependencies": {
19 | "parcel-bundler": "^1.12.4"
20 | },
21 | "browserslist": [
22 | "last 3 Chrome versions",
23 | "last 3 Firefox versions"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/demos/basic/style.css:
--------------------------------------------------------------------------------
1 | main {
2 | width: 1400px;
3 | max-width: 90%;
4 | margin: 40px auto 20px auto;
5 | }
--------------------------------------------------------------------------------
/demos/react-demo/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/demos/react-demo/README.md:
--------------------------------------------------------------------------------
1 | # OSMD Audio Player - Basic demo (React build)
2 |
3 | Basic demo with a single score and only play, pause and stop functionality. Built using React.js.
4 |
5 | ## Run locally
6 | ```
7 | npm i
8 | npm start
9 | ```
--------------------------------------------------------------------------------
/demos/react-demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-demo",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "opensheetmusicdisplay": "^1.2.0",
7 | "osmd-audio-player": "^0.6.4",
8 | "react": "^17.0.2",
9 | "react-dom": "^17.0.2",
10 | "react-scripts": "4.0.3"
11 | },
12 | "scripts": {
13 | "start": "react-scripts start",
14 | "build": "react-scripts build",
15 | "test": "react-scripts test",
16 | "eject": "react-scripts eject"
17 | },
18 | "eslintConfig": {
19 | "extends": [
20 | "react-app",
21 | "react-app/jest"
22 | ]
23 | },
24 | "browserslist": {
25 | "production": [
26 | ">0.2%",
27 | "not dead",
28 | "not op_mini all"
29 | ],
30 | "development": [
31 | "last 1 chrome version",
32 | "last 1 firefox version",
33 | "last 1 safari version"
34 | ]
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/demos/react-demo/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 | You need to enable JavaScript to run this app.
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/demos/react-demo/src/App.js:
--------------------------------------------------------------------------------
1 | import Score from './components/Score.jsx'
2 |
3 | function App() {
4 | return (
5 |
6 |
7 |
8 | );
9 | }
10 |
11 | export default App;
--------------------------------------------------------------------------------
/demos/react-demo/src/components/Score.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { OpenSheetMusicDisplay } from "opensheetmusicdisplay";
3 | import AudioPlayer from "osmd-audio-player";
4 |
5 | class Score extends Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = {
9 | file: props.file
10 | };
11 | window.audioPlayer = new AudioPlayer();
12 | this.divRef = React.createRef();
13 | }
14 |
15 | play() {
16 | window.audioPlayer.play();
17 | }
18 |
19 | pause() {
20 | window.audioPlayer.pause();
21 | }
22 |
23 | stop() {
24 | window.audioPlayer.stop();
25 | }
26 |
27 | async componentDidMount() {
28 | this.osmd = new OpenSheetMusicDisplay(this.divRef.current);
29 | await this.osmd.load(this.state.file);
30 | await this.osmd.render();
31 | await window.audioPlayer.loadScore(this.osmd);
32 | }
33 |
34 | render() {
35 | return (
36 |
37 | Play
38 | Pause
39 | Stop
40 |
41 |
42 |
43 | );
44 | }
45 | }
46 |
47 | export default Score;
--------------------------------------------------------------------------------
/demos/react-demo/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | ReactDOM.render(
6 |
7 |
8 | ,
9 | document.getElementById('root')
10 | );
11 |
--------------------------------------------------------------------------------
/demos/umd-web/app.js:
--------------------------------------------------------------------------------
1 | (async () => {
2 | const osmd = new opensheetmusicdisplay.OpenSheetMusicDisplay(document.getElementById("score"));
3 | const audioPlayer = new OsmdAudioPlayer();
4 |
5 | const scoreXml = await fetch(
6 | "https://opensheetmusicdisplay.github.io/demo/sheets/MuzioClementi_SonatinaOpus36No3_Part1.xml"
7 | ).then(r => r.text());
8 |
9 | console.log("Score xml: ", scoreXml);
10 |
11 | await osmd.load(scoreXml);
12 | await osmd.render();
13 | await audioPlayer.loadScore(osmd);
14 | audioPlayer.on("iteration", notes => {
15 | console.log(notes);
16 | });
17 |
18 | hideLoadingMessage();
19 | registerButtonEvents(audioPlayer);
20 | })();
21 |
22 | function hideLoadingMessage() {
23 | document.getElementById("loading").style.display = "none";
24 | }
25 |
26 | function registerButtonEvents(audioPlayer) {
27 | document.getElementById("btn-play").addEventListener("click", () => {
28 | if (audioPlayer.state === "STOPPED" || audioPlayer.state === "PAUSED") {
29 | audioPlayer.play();
30 | }
31 | });
32 | document.getElementById("btn-pause").addEventListener("click", () => {
33 | if (audioPlayer.state === "PLAYING") {
34 | audioPlayer.pause();
35 | }
36 | });
37 | document.getElementById("btn-stop").addEventListener("click", () => {
38 | if (audioPlayer.state === "PLAYING" || audioPlayer.state === "PAUSED") {
39 | audioPlayer.stop();
40 | }
41 | });
42 | }
43 |
--------------------------------------------------------------------------------
/demos/umd-web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | OSMD Audio Player - basic demo
8 |
9 |
10 |
11 |
12 | Play
13 | Pause
14 | Stop
15 |
16 |
17 |
Loading
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/demos/umd-web/readme.md:
--------------------------------------------------------------------------------
1 | # OSMD Audio Player - Basic demo (UMD build)
2 |
3 | Basic demo with a single score and only play, pause and stop functionality. The primary difference from the "basic" demo is that this uses the UMD build of OSMD Audio Player and OSMD. Which means that it does not rely on Node.js and intermediate build steps.
4 |
5 | ## Run locally
6 |
7 | Open index.html in your browser
8 |
--------------------------------------------------------------------------------
/demos/umd-web/style.css:
--------------------------------------------------------------------------------
1 | main {
2 | width: 1400px;
3 | max-width: 90%;
4 | margin: 40px auto 20px auto;
5 | }
6 |
--------------------------------------------------------------------------------
/demos/vue-player-demo/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not ie <= 10
4 |
--------------------------------------------------------------------------------
/demos/vue-player-demo/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw*
--------------------------------------------------------------------------------
/demos/vue-player-demo/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Jimmy Utterström
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/demos/vue-player-demo/README.md:
--------------------------------------------------------------------------------
1 | The demo is built with Vue.js and Vuetify. Run `npm run serve` to build the project and run it on a local dev server.
2 |
--------------------------------------------------------------------------------
/demos/vue-player-demo/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "presets": [
3 | [
4 | "@vue/app",
5 | {
6 | "useBuiltIns": "entry"
7 | }
8 | ]
9 | ]
10 | }
--------------------------------------------------------------------------------
/demos/vue-player-demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "osmd-playback-vue",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build"
8 | },
9 | "dependencies": {
10 | "axios": "^0.21.1",
11 | "opensheetmusicdisplay": "^0.8.4",
12 | "soundfont-player": "^0.12.0",
13 | "vue": "^2.6.11",
14 | "vuetify": "^1.5.22"
15 | },
16 | "devDependencies": {
17 | "@babel/polyfill": "^7.8.3",
18 | "@vue/cli-plugin-babel": "^3.12.1",
19 | "@vue/cli-service": "^3.12.1",
20 | "sass": "^1.25.0",
21 | "sass-loader": "^7.3.1",
22 | "vue-cli-plugin-vuetify": "^0.1.6",
23 | "vue-template-compiler": "^2.6.11"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/demos/vue-player-demo/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {}
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/demos/vue-player-demo/public/Rest_Test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 | Composer
9 |
10 | MuseScore 2.1.0
11 | 2018-09-21
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | 7.05556
22 | 40
23 |
24 |
25 | 1683.36
26 | 1190.88
27 |
28 | 56.6929
29 | 56.6929
30 | 56.6929
31 | 113.386
32 |
33 |
34 | 56.6929
35 | 56.6929
36 | 56.6929
37 | 113.386
38 |
39 |
40 |
41 |
42 |
43 |
44 | Rest Test
45 |
46 |
47 | Jimmy Utterström
48 |
49 |
50 |
51 | Piano
52 | Pno.
53 |
54 | Piano
55 |
56 |
57 |
58 | 1
59 | 1
60 | 78.7402
61 | 0
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | 0.00
71 | -0.00
72 |
73 | 170.00
74 |
75 |
76 |
77 | 2
78 |
79 | 0
80 |
81 |
82 | 4
83 | 4
84 |
85 |
86 | G
87 | 2
88 |
89 |
90 |
91 |
92 | A
93 | 4
94 |
95 | 2
96 | 1
97 | quarter
98 | up
99 |
100 |
101 |
102 | B
103 | 4
104 |
105 | 2
106 | 1
107 | quarter
108 | up
109 |
110 |
111 |
112 | C
113 | 5
114 |
115 | 2
116 | 1
117 | quarter
118 | up
119 |
120 |
121 |
122 | B
123 | 4
124 |
125 | 2
126 | 1
127 | quarter
128 | up
129 |
130 |
131 | 8
132 |
133 |
134 |
135 | E
136 | 4
137 |
138 | 2
139 | 2
140 | quarter
141 | down
142 |
143 |
144 |
145 | F
146 | 1
147 | 4
148 |
149 | 2
150 | 2
151 | quarter
152 | sharp
153 | down
154 |
155 |
156 |
157 | 2
158 | 2
159 | quarter
160 |
161 |
162 |
163 | 1
164 | 2
165 | eighth
166 |
167 |
168 |
169 | D
170 | 4
171 |
172 | 1
173 | 2
174 | eighth
175 | down
176 |
177 |
178 |
179 |
180 |
181 | A
182 | 4
183 |
184 | 4
185 | 1
186 | half
187 | up
188 |
189 |
190 |
191 | A
192 | 4
193 |
194 | 4
195 | 1
196 | half
197 | up
198 |
199 |
200 | 8
201 |
202 |
203 |
204 | E
205 | 4
206 |
207 | 4
208 | 2
209 | half
210 | down
211 |
212 |
213 |
214 | 4
215 | 2
216 | half
217 |
218 |
219 |
220 |
221 |
222 | B
223 | 4
224 |
225 | 8
226 | 1
227 | whole
228 |
229 |
230 |
231 |
232 |
233 | 8
234 | 1
235 |
236 |
237 | light-heavy
238 |
239 |
240 |
241 |
242 |
--------------------------------------------------------------------------------
/demos/vue-player-demo/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jimutt/osmd-audio-player/ec205a6e46ee50002c1fa8f5999389447bba7bbf/demos/vue-player-demo/public/favicon.ico
--------------------------------------------------------------------------------
/demos/vue-player-demo/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | osmd-playback-vue
11 |
12 |
13 |
14 |
15 | We're sorry but osmd-playback-vue doesn't work properly without JavaScript enabled. Please enable it to
16 | continue.
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/demos/vue-player-demo/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Playback settings
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
92 |
93 |
101 |
--------------------------------------------------------------------------------
/demos/vue-player-demo/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jimutt/osmd-audio-player/ec205a6e46ee50002c1fa8f5999389447bba7bbf/demos/vue-player-demo/src/assets/logo.png
--------------------------------------------------------------------------------
/demos/vue-player-demo/src/components/BpmSlider.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | this.$emit('update:bpm', Number(val))"
10 | thumb-label
11 | >
12 |
13 |
14 |
15 |
20 |
--------------------------------------------------------------------------------
/demos/vue-player-demo/src/components/InstrumentControl.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ instrument.Name }}
4 |
5 |
{{ voice.Name }}
6 | setPlaybackInstrument(voice, midiInstrumentId)"
11 | >
12 |
13 |
14 |
15 |
16 |
17 |
41 |
--------------------------------------------------------------------------------
/demos/vue-player-demo/src/components/PlaybackControls.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | this.playbackEngine.jumpToStep(val)"
13 | class="progress-slider"
14 | >
15 |
16 |
17 | {{ scoreTitle }}
18 |
19 |
20 |
21 |
22 |
23 | play_arrow
24 |
25 |
26 | pause
27 |
28 |
29 |
30 |
31 |
32 | stop
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
50 |
51 |
60 |
--------------------------------------------------------------------------------
/demos/vue-player-demo/src/components/PlaybackSidebar.vue:
--------------------------------------------------------------------------------
1 |
2 |
32 |
33 |
34 |
59 |
60 |
65 |
--------------------------------------------------------------------------------
/demos/vue-player-demo/src/components/Score.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
50 |
51 |
63 |
64 |
71 |
--------------------------------------------------------------------------------
/demos/vue-player-demo/src/components/VolumeSlider.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | this.$emit('update:volume', Number(val))"
11 | >
12 |
13 |
14 |
15 |
20 |
--------------------------------------------------------------------------------
/demos/vue-player-demo/src/main.js:
--------------------------------------------------------------------------------
1 | import '@babel/polyfill'
2 | import Vue from 'vue'
3 | import './plugins/vuetify'
4 | import App from './App.vue'
5 |
6 | import Vuetify from 'vuetify'
7 | import 'vuetify/dist/vuetify.min.css'
8 |
9 | Vue.use(Vuetify)
10 | Vue.config.productionTip = false
11 |
12 | new Vue({
13 | render: h => h(App)
14 | }).$mount('#app')
--------------------------------------------------------------------------------
/demos/vue-player-demo/src/plugins/vuetify.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuetify from 'vuetify'
3 | import 'vuetify/dist/vuetify.min.css'
4 |
5 | Vue.use(Vuetify, {
6 | })
7 |
--------------------------------------------------------------------------------
/demos/vue-player-demo/src/scores.js:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | value: "https://opensheetmusicdisplay.github.io/demo/sheets/Beethoven_AnDieFerneGeliebte.xml",
4 | text: "Beethoven, L.v. - An die ferne Geliebte"
5 | },
6 | {
7 | value: "score.xml",
8 | text: "Herren är min herde god"
9 | },
10 | {
11 | value: "https://opensheetmusicdisplay.github.io/demo/sheets/MuzioClementi_SonatinaOpus36No3_Part1.xml",
12 | text: "Clementi, M. - Sonatina Op.36 No.3 Pt.1"
13 | },
14 | {
15 | value: "https://opensheetmusicdisplay.github.io/demo/sheets/MuzioClementi_SonatinaOpus36No3_Part2.xml",
16 | text: "Clementi, M. - Sonatina Op.36 No.3 Pt.2"
17 | },
18 | {
19 | value: "https://opensheetmusicdisplay.github.io/demo/sheets/JohannSebastianBach_PraeludiumInCDur_BWV846_1.xml",
20 | text: "Bach, J.S. - Praeludium in C-Dur BWV846 1"
21 | },
22 | {
23 | value: "https://opensheetmusicdisplay.github.io/demo/sheets/ScottJoplin_EliteSyncopations.xml",
24 | text: "Joplin, S. - Elite Syncopations"
25 | },
26 | {
27 | value: "https://opensheetmusicdisplay.github.io/demo/sheets/ScottJoplin_The_Entertainer.xml",
28 | text: "Joplin, S. - The Entertainer"
29 | },
30 | {
31 | value: "https://opensheetmusicdisplay.github.io/demo/sheets/Land_der_Berge.musicxml",
32 | text: "Mozart/Holzer - Land der Berge (national anthem of Austria)"
33 | },
34 | {
35 | value: "https://opensheetmusicdisplay.github.io/demo/sheets/Schubert_An_die_Musik.xml",
36 | text: "Schubert, F. - An Die Musik"
37 | },
38 | {
39 | value: "https://opensheetmusicdisplay.github.io/demo/sheets/Dichterliebe01.xml",
40 | text: "Schumann, R. - Dichterliebe"
41 | },
42 | {
43 | value: "https://opensheetmusicdisplay.github.io/demo/sheets/TelemannWV40.102_Sonate-Nr.1.1-Dolce.xml",
44 | text: "Telemann, G.P. - Sonate-Nr.1.1-Dolce"
45 | },
46 | {
47 | value: "https://opensheetmusicdisplay.github.io/demo/sheets/TelemannWV40.102_Sonate-Nr.1.2-Allegro-F-Dur.xml",
48 | text: "Telemann, G.P. - Sonate-Nr.1.2-Allegro"
49 | }
50 | ];
51 |
--------------------------------------------------------------------------------
/demos/vue-player-demo/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | productionSourceMap: false
3 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "osmd-audio-player",
3 | "version": "0.7.0",
4 | "description": "OSMD audio player",
5 | "main": "dist/index.js",
6 | "types": "dist/index.d.ts",
7 | "scripts": {
8 | "dev": "tsc -w",
9 | "test": "jest",
10 | "prepare": "npm run build",
11 | "build": "tsc -p tsconfig.build.json",
12 | "build-umd": "rollup -c rollup.umd.config.js",
13 | "install-demo:vue": "npm install --prefix demos/vue-player-demo",
14 | "install-demo:basic": "npm install --prefix demos/basic",
15 | "install-demos": "run-p install-demo:*",
16 | "build-demo:vue": "npm run build --prefix demos/vue-player-demo",
17 | "build-demo:basic": "npm run build --prefix demos/basic",
18 | "build-demos": "run-p build-demo:*",
19 | "build-all": "run-s build build-umd build-demos",
20 | "netlify-build": "run-s build install-demos build-demos"
21 | },
22 | "author": "Jimmy Utterström",
23 | "license": "MIT",
24 | "repository": {
25 | "type": "git",
26 | "url": "https://github.com/jimutt/osmd-audio-player"
27 | },
28 | "keywords": [
29 | "MusicXML",
30 | "Music XML",
31 | "audio player",
32 | "MusicXML audio",
33 | "music notation"
34 | ],
35 | "dependencies": {
36 | "opensheetmusicdisplay": "^0.8.4",
37 | "soundfont-player": "^0.12.0",
38 | "standardized-audio-context": "^24.1.25"
39 | },
40 | "devDependencies": {
41 | "@babel/core": "^7.9.6",
42 | "@babel/preset-env": "^7.9.6",
43 | "@babel/preset-typescript": "^7.9.0",
44 | "@rollup/plugin-commonjs": "^15.0.0",
45 | "@rollup/plugin-node-resolve": "^9.0.0",
46 | "@rollup/plugin-typescript": "^6.0.0",
47 | "@types/jest": "^25.2.1",
48 | "babel-jest": "^26.0.1",
49 | "jest": "^26.0.1",
50 | "npm-run-all": "^4.1.5",
51 | "rollup": "^2.26.11",
52 | "rollup-plugin-terser": "^7.0.2",
53 | "ts-mockito": "^2.5.0",
54 | "tslib": "^2.0.1",
55 | "typescript": "^3.7.5"
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/rollup.umd.config.js:
--------------------------------------------------------------------------------
1 | import typescript from "@rollup/plugin-typescript";
2 | import { nodeResolve } from "@rollup/plugin-node-resolve";
3 | import commonjs from "@rollup/plugin-commonjs";
4 | import { terser } from "rollup-plugin-terser";
5 |
6 | export default {
7 | input: "src/index.ts",
8 | output: [
9 | {
10 | file: "umd/OsmdAudioPlayer.min.js",
11 | format: "umd",
12 | name: "OsmdAudioPlayer",
13 | },
14 | ],
15 | plugins: [
16 | typescript({ declaration: false }),
17 | nodeResolve(),
18 | commonjs({
19 | include: "node_modules/**",
20 | }),
21 | terser(),
22 | ],
23 | };
24 |
--------------------------------------------------------------------------------
/src/PlaybackEngine.test.ts:
--------------------------------------------------------------------------------
1 | import PlaybackEngine from ".";
2 | import { mock, instance, when } from "ts-mockito";
3 | import { OpenSheetMusicDisplay, Cursor, MusicSheet, PlaybackSettings, Fraction } from "opensheetmusicdisplay";
4 | import { PlaybackEvent, PlaybackState } from "./PlaybackEngine";
5 | import { IAudioContext } from "standardized-audio-context";
6 |
7 | jest.mock("./PlaybackScheduler");
8 |
9 | describe("PlaybackEngine", () => {
10 | describe("Events", () => {
11 | test("Playback state event on loadScore()", async () => {
12 | const acMock = createMockedAudioContext();
13 | const osmdMock = createOsmdMock();
14 | const stateCb = jest.fn();
15 |
16 | const pbEngine = new PlaybackEngine(acMock);
17 |
18 | pbEngine.on(PlaybackEvent.STATE_CHANGE, stateCb);
19 | await pbEngine.loadScore(osmdMock);
20 |
21 | expect(stateCb).toHaveBeenCalledTimes(1);
22 | expect(stateCb).toHaveBeenCalledWith(PlaybackState.STOPPED);
23 | });
24 |
25 | test("Playback state event on play()", async () => {
26 | const acMock = createMockedAudioContext();
27 | const osmdMock = createOsmdMock();
28 | const stateCb = jest.fn();
29 |
30 | const pbEngine = new PlaybackEngine(acMock);
31 |
32 | await pbEngine.loadScore(osmdMock);
33 | pbEngine.on(PlaybackEvent.STATE_CHANGE, stateCb);
34 | await pbEngine.play();
35 |
36 | expect(stateCb).toHaveBeenCalledTimes(1);
37 | expect(stateCb).toHaveBeenCalledWith(PlaybackState.PLAYING);
38 | });
39 |
40 | test("Playback state event on stop()", async () => {
41 | const acMock = createMockedAudioContext();
42 | const osmdMock = createOsmdMock();
43 | const stateCb = jest.fn();
44 |
45 | const pbEngine = new PlaybackEngine(acMock);
46 |
47 | await pbEngine.loadScore(osmdMock);
48 | await pbEngine.play();
49 | pbEngine.on(PlaybackEvent.STATE_CHANGE, stateCb);
50 | await pbEngine.stop();
51 |
52 | expect(stateCb).toHaveBeenCalledTimes(1);
53 | expect(stateCb).toHaveBeenCalledWith(PlaybackState.STOPPED);
54 | });
55 |
56 | test("Playback state event on pause()", async () => {
57 | const acMock = createMockedAudioContext();
58 | const osmdMock = createOsmdMock();
59 | const stateCb = jest.fn();
60 |
61 | const pbEngine = new PlaybackEngine(acMock);
62 |
63 | await pbEngine.loadScore(osmdMock);
64 | await pbEngine.play();
65 | pbEngine.on(PlaybackEvent.STATE_CHANGE, stateCb);
66 | await pbEngine.pause();
67 |
68 | expect(stateCb).toHaveBeenCalledTimes(1);
69 | expect(stateCb).toHaveBeenCalledWith(PlaybackState.PAUSED);
70 | });
71 | });
72 | });
73 |
74 | function createMockedAudioContext(): IAudioContext {
75 | return ({
76 | currentTime: 0,
77 | suspend: jest.fn(async () => {}),
78 | resume: jest.fn(async () => {}),
79 | } as unknown) as IAudioContext;
80 | }
81 |
82 | function createOsmdMock(): OpenSheetMusicDisplay {
83 | const mockedOsmd = mock(OpenSheetMusicDisplay);
84 | const mockedSheet = mock(MusicSheet);
85 | const mockedPlaybackSettings = mock(PlaybackSettings);
86 | const mockedFraction = mock(Fraction);
87 | const mockedCursor = mock(Cursor);
88 |
89 | //@ts-ignore
90 | when(mockedCursor.Iterator).thenReturn({ EndReached: true });
91 | when(mockedOsmd.cursor).thenReturn(instance(mockedCursor));
92 | when(mockedSheet.Instruments).thenReturn([]);
93 | when(mockedPlaybackSettings.rhythm).thenReturn(instance(mockedFraction));
94 | when(mockedSheet.SheetPlaybackSetting).thenReturn(instance(mockedPlaybackSettings));
95 | when(mockedOsmd.Sheet).thenReturn(instance(mockedSheet));
96 | return instance(mockedOsmd);
97 | }
98 |
--------------------------------------------------------------------------------
/src/PlaybackEngine.ts:
--------------------------------------------------------------------------------
1 | import PlaybackScheduler from "./PlaybackScheduler";
2 | import { Cursor, OpenSheetMusicDisplay, MusicSheet, Note, Instrument, Voice } from "opensheetmusicdisplay";
3 | import { SoundfontPlayer } from "./players/SoundfontPlayer";
4 | import { InstrumentPlayer, PlaybackInstrument } from "./players/InstrumentPlayer";
5 | import { NotePlaybackInstruction } from "./players/NotePlaybackOptions";
6 | import { getNoteDuration, getNoteVolume, getNoteArticulationStyle } from "./internals/noteHelpers";
7 | import { EventEmitter } from "./internals/EventEmitter";
8 | import { AudioContext, IAudioContext } from "standardized-audio-context";
9 |
10 | export enum PlaybackState {
11 | INIT = "INIT",
12 | PLAYING = "PLAYING",
13 | STOPPED = "STOPPED",
14 | PAUSED = "PAUSED",
15 | }
16 |
17 | export enum PlaybackEvent {
18 | STATE_CHANGE = "state-change",
19 | ITERATION = "iteration",
20 | }
21 |
22 | interface PlaybackSettings {
23 | bpm: number;
24 | masterVolume: number;
25 | }
26 |
27 | export default class PlaybackEngine {
28 | private ac: IAudioContext;
29 | private defaultBpm: number = 100;
30 | private cursor: Cursor;
31 | private sheet: MusicSheet;
32 | private scheduler: PlaybackScheduler;
33 | private instrumentPlayer: InstrumentPlayer;
34 | private events: EventEmitter;
35 |
36 | private iterationSteps: number;
37 | private currentIterationStep: number;
38 |
39 | private timeoutHandles: number[];
40 |
41 | public playbackSettings: PlaybackSettings;
42 | public state: PlaybackState;
43 | public availableInstruments: PlaybackInstrument[];
44 | public scoreInstruments: Instrument[] = [];
45 | public ready: boolean = false;
46 |
47 | constructor(context: IAudioContext = new AudioContext(), instrumentPlayer: InstrumentPlayer = new SoundfontPlayer()) {
48 | this.ac = context;
49 | this.ac.suspend();
50 |
51 | this.instrumentPlayer = instrumentPlayer;
52 | this.instrumentPlayer.init(this.ac);
53 |
54 | this.availableInstruments = this.instrumentPlayer.instruments;
55 |
56 | this.events = new EventEmitter();
57 |
58 | this.cursor = null;
59 | this.sheet = null;
60 |
61 | this.scheduler = null;
62 |
63 | this.iterationSteps = 0;
64 | this.currentIterationStep = 0;
65 |
66 | this.timeoutHandles = [];
67 |
68 | this.playbackSettings = {
69 | bpm: this.defaultBpm,
70 | masterVolume: 1,
71 | };
72 |
73 | this.setState(PlaybackState.INIT);
74 | }
75 |
76 | get wholeNoteLength(): number {
77 | return Math.round((60 / this.playbackSettings.bpm) * 4000);
78 | }
79 |
80 | public getPlaybackInstrument(voiceId: number): PlaybackInstrument {
81 | if (!this.sheet) return null;
82 | const voice = this.sheet.Instruments.flatMap(i => i.Voices).find(v => v.VoiceId === voiceId);
83 | return this.availableInstruments.find(i => i.midiId === (voice as any).midiInstrumentId);
84 | }
85 |
86 | public async setInstrument(voice: Voice, midiInstrumentId: number): Promise {
87 | await this.instrumentPlayer.load(midiInstrumentId);
88 | (voice as any).midiInstrumentId = midiInstrumentId;
89 | }
90 |
91 | async loadScore(osmd: OpenSheetMusicDisplay): Promise {
92 | this.ready = false;
93 | this.sheet = osmd.Sheet;
94 | this.scoreInstruments = this.sheet.Instruments;
95 | this.cursor = osmd.cursor;
96 | if (this.sheet.HasBPMInfo) {
97 | this.setBpm(this.sheet.DefaultStartTempoInBpm);
98 | }
99 |
100 | await this.loadInstruments();
101 | this.initInstruments();
102 |
103 | this.scheduler = new PlaybackScheduler(this.wholeNoteLength, this.ac, (delay, notes) =>
104 | this.notePlaybackCallback(delay, notes)
105 | );
106 |
107 | this.countAndSetIterationSteps();
108 | this.ready = true;
109 | this.setState(PlaybackState.STOPPED);
110 | }
111 |
112 | private initInstruments() {
113 | for (const i of this.sheet.Instruments) {
114 | for (const v of i.Voices) {
115 | (v as any).midiInstrumentId = i.MidiInstrumentId;
116 | }
117 | }
118 | }
119 |
120 | private async loadInstruments() {
121 | let playerPromises: Promise[] = [];
122 | for (const i of this.sheet.Instruments) {
123 | const pbInstrument = this.availableInstruments.find(pbi => pbi.midiId === i.MidiInstrumentId);
124 | if (pbInstrument == null) {
125 | this.fallbackToPiano(i);
126 | }
127 | playerPromises.push(this.instrumentPlayer.load(i.MidiInstrumentId));
128 | }
129 | await Promise.all(playerPromises);
130 | }
131 |
132 | private fallbackToPiano(i: Instrument) {
133 | console.warn(`Can't find playback instrument for midiInstrumentId ${i.MidiInstrumentId}. Falling back to piano`);
134 | i.MidiInstrumentId = 0;
135 |
136 | if (this.availableInstruments.find(i => i.midiId === 0) == null) {
137 | throw new Error("Piano fallback failed, grand piano not supported");
138 | }
139 | }
140 |
141 | async play() {
142 | await this.ac.resume();
143 |
144 | if (this.state === PlaybackState.INIT || this.state === PlaybackState.STOPPED) {
145 | this.cursor.show();
146 | }
147 |
148 | this.setState(PlaybackState.PLAYING);
149 | this.scheduler.start();
150 | }
151 |
152 | async stop() {
153 | this.setState(PlaybackState.STOPPED);
154 | this.stopPlayers();
155 | this.clearTimeouts();
156 | this.scheduler.reset();
157 | this.cursor.reset();
158 | this.currentIterationStep = 0;
159 | this.cursor.hide();
160 | }
161 |
162 | pause() {
163 | this.setState(PlaybackState.PAUSED);
164 | this.ac.suspend();
165 | this.stopPlayers();
166 | this.scheduler.setIterationStep(this.currentIterationStep);
167 | this.scheduler.pause();
168 | this.clearTimeouts();
169 | }
170 |
171 | jumpToStep(step) {
172 | this.pause();
173 | if (this.currentIterationStep > step) {
174 | this.cursor.reset();
175 | this.currentIterationStep = 0;
176 | }
177 | while (this.currentIterationStep < step) {
178 | this.cursor.next();
179 | ++this.currentIterationStep;
180 | }
181 | let schedulerStep = this.currentIterationStep;
182 | if (this.currentIterationStep > 0 && this.currentIterationStep < this.iterationSteps) ++schedulerStep;
183 | this.scheduler.setIterationStep(schedulerStep);
184 | }
185 |
186 | setBpm(bpm: number) {
187 | this.playbackSettings.bpm = bpm;
188 | if (this.scheduler) this.scheduler.wholeNoteLength = this.wholeNoteLength;
189 | }
190 |
191 | public on(event: PlaybackEvent, cb: (...args: any[]) => void) {
192 | this.events.on(event, cb);
193 | }
194 |
195 | private countAndSetIterationSteps() {
196 | this.cursor.reset();
197 | let steps = 0;
198 | while (!this.cursor.Iterator.EndReached) {
199 | if (this.cursor.Iterator.CurrentVoiceEntries) {
200 | this.scheduler.loadNotes(this.cursor.Iterator.CurrentVoiceEntries);
201 | }
202 | this.cursor.next();
203 | ++steps;
204 | }
205 | this.iterationSteps = steps;
206 | this.cursor.reset();
207 | }
208 |
209 | private notePlaybackCallback(audioDelay, notes: Note[]) {
210 | if (this.state !== PlaybackState.PLAYING) return;
211 | let scheduledNotes: Map = new Map();
212 |
213 | for (let note of notes) {
214 | if (note.isRest()) {
215 | continue;
216 | }
217 | const noteDuration = getNoteDuration(note, this.wholeNoteLength);
218 | if (noteDuration === 0) continue;
219 | const noteVolume = getNoteVolume(note);
220 | const noteArticulation = getNoteArticulationStyle(note);
221 |
222 | const midiPlaybackInstrument = (note as any).ParentVoiceEntry.ParentVoice.midiInstrumentId;
223 | const fixedKey = note.ParentVoiceEntry.ParentVoice.Parent.SubInstruments[0].fixedKey || 0;
224 |
225 | if (!scheduledNotes.has(midiPlaybackInstrument)) {
226 | scheduledNotes.set(midiPlaybackInstrument, []);
227 | }
228 |
229 | scheduledNotes.get(midiPlaybackInstrument).push({
230 | note: note.halfTone - fixedKey * 12,
231 | duration: noteDuration / 1000,
232 | gain: noteVolume,
233 | articulation: noteArticulation,
234 | });
235 | }
236 |
237 | for (const [midiId, notes] of scheduledNotes) {
238 | this.instrumentPlayer.schedule(midiId, this.ac.currentTime + audioDelay, notes);
239 | }
240 |
241 | this.timeoutHandles.push(
242 | window.setTimeout(() => this.iterationCallback(), Math.max(0, audioDelay * 1000 - 35)), // Subtracting 35 milliseconds to compensate for update delay
243 | window.setTimeout(() => this.events.emit(PlaybackEvent.ITERATION, notes), audioDelay * 1000)
244 | );
245 | }
246 |
247 | private setState(state: PlaybackState) {
248 | this.state = state;
249 | this.events.emit(PlaybackEvent.STATE_CHANGE, state);
250 | }
251 |
252 | private stopPlayers() {
253 | for (const i of this.sheet.Instruments) {
254 | for (const v of i.Voices) {
255 | this.instrumentPlayer.stop((v as any).midiInstrumentId);
256 | }
257 | }
258 | }
259 |
260 | // Used to avoid duplicate cursor movements after a rapid pause/resume action
261 | private clearTimeouts() {
262 | for (let h of this.timeoutHandles) {
263 | clearTimeout(h);
264 | }
265 | this.timeoutHandles = [];
266 | }
267 |
268 | private iterationCallback() {
269 | if (this.state !== PlaybackState.PLAYING) return;
270 | if (this.currentIterationStep > 0) this.cursor.next();
271 | ++this.currentIterationStep;
272 | }
273 | }
274 |
--------------------------------------------------------------------------------
/src/PlaybackScheduler.ts:
--------------------------------------------------------------------------------
1 | import StepQueue from "./internals/StepQueue";
2 | import { VoiceEntry } from "opensheetmusicdisplay/build/dist/src";
3 | import { IAudioContext } from "standardized-audio-context";
4 |
5 | type NoteSchedulingCallback = (delay: number, notes: any) => void;
6 |
7 | export default class PlaybackScheduler {
8 | public wholeNoteLength: number;
9 |
10 | private stepQueue = new StepQueue();
11 | private stepQueueIndex = 0;
12 | private scheduledTicks = new Set();
13 |
14 | private currentTick = 0;
15 | private currentTickTimestamp = 0;
16 |
17 | private audioContext: IAudioContext;
18 | private audioContextStartTime: number = 0;
19 |
20 | private schedulerIntervalHandle: number = null;
21 | private scheduleInterval: number = 200; // Milliseconds
22 | private schedulePeriod: number = 500;
23 | private tickDenominator: number = 1024;
24 |
25 | private lastTickOffset: number = 300; // Hack to get the initial notes play better
26 | private playing: boolean = false;
27 |
28 | private noteSchedulingCallback: NoteSchedulingCallback;
29 |
30 | constructor(wholeNoteLength: number, audioContext: IAudioContext, noteSchedulingCallback: NoteSchedulingCallback) {
31 | this.noteSchedulingCallback = noteSchedulingCallback;
32 | this.wholeNoteLength = wholeNoteLength;
33 | this.audioContext = audioContext;
34 | }
35 |
36 | get schedulePeriodTicks() {
37 | return this.schedulePeriod / this.tickDuration;
38 | }
39 |
40 | get audioContextTime() {
41 | if (!this.audioContext) return 0;
42 | return (this.audioContext.currentTime - this.audioContextStartTime) * 1000;
43 | }
44 |
45 | get tickDuration() {
46 | return this.wholeNoteLength / this.tickDenominator;
47 | }
48 |
49 | private get calculatedTick() {
50 | return this.currentTick + Math.round((this.audioContextTime - this.currentTickTimestamp) / this.tickDuration);
51 | }
52 |
53 | start() {
54 | this.playing = true;
55 | this.stepQueue.sort();
56 | this.audioContextStartTime = this.audioContext.currentTime;
57 | this.currentTickTimestamp = this.audioContextTime;
58 | if (!this.schedulerIntervalHandle) {
59 | this.schedulerIntervalHandle = window.setInterval(() => this.scheduleIterationStep(), this.scheduleInterval);
60 | }
61 | }
62 |
63 | setIterationStep(step: number) {
64 | step = Math.min(this.stepQueue.steps.length - 1, step);
65 | this.stepQueueIndex = step;
66 | this.currentTick = this.stepQueue.steps[this.stepQueueIndex].tick;
67 | }
68 |
69 | pause() {
70 | this.playing = false;
71 | }
72 |
73 | resume() {
74 | this.playing = true;
75 | this.currentTickTimestamp = this.audioContextTime;
76 | }
77 |
78 | reset() {
79 | this.playing = false;
80 | this.currentTick = 0;
81 | this.currentTickTimestamp = 0;
82 | this.stepQueueIndex = 0;
83 | clearInterval(this.scheduleInterval);
84 | this.schedulerIntervalHandle = null;
85 | }
86 |
87 | loadNotes(currentVoiceEntries: VoiceEntry[]) {
88 | let thisTick = this.lastTickOffset;
89 | if (this.stepQueue.steps.length > 0) {
90 | thisTick = this.stepQueue.getFirstEmptyTick();
91 | }
92 |
93 | for (let entry of currentVoiceEntries) {
94 | if (!entry.IsGrace) {
95 | for (let note of entry.Notes) {
96 | this.stepQueue.addNote(thisTick, note);
97 | this.stepQueue.createStep(thisTick + note.Length.RealValue * this.tickDenominator);
98 | }
99 | }
100 | }
101 | }
102 |
103 | private scheduleIterationStep() {
104 | if (!this.playing) return;
105 | this.currentTick = this.calculatedTick;
106 | this.currentTickTimestamp = this.audioContextTime;
107 |
108 | let nextTick = this.stepQueue.steps[this.stepQueueIndex]?.tick;
109 | while (this.nextTickAvailableAndWithinSchedulePeriod(nextTick)) {
110 | let step = this.stepQueue.steps[this.stepQueueIndex];
111 |
112 | let timeToTick = (step.tick - this.currentTick) * this.tickDuration;
113 | if (timeToTick < 0) timeToTick = 0;
114 |
115 | this.scheduledTicks.add(step.tick);
116 | this.noteSchedulingCallback(timeToTick / 1000, step.notes);
117 |
118 | this.stepQueueIndex++;
119 | nextTick = this.stepQueue.steps[this.stepQueueIndex]?.tick;
120 | }
121 |
122 | for (let tick of this.scheduledTicks) {
123 | if (tick <= this.currentTick) {
124 | this.scheduledTicks.delete(tick);
125 | }
126 | }
127 | }
128 |
129 | private nextTickAvailableAndWithinSchedulePeriod(nextTick: any) {
130 | return (
131 | nextTick &&
132 | this.currentTickTimestamp + (nextTick - this.currentTick) * this.tickDuration <=
133 | this.currentTickTimestamp + this.schedulePeriod
134 | );
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import PlaybackEngine from "./PlaybackEngine";
2 |
3 | export default PlaybackEngine;
4 |
--------------------------------------------------------------------------------
/src/internals/EventEmitter.test.ts:
--------------------------------------------------------------------------------
1 | import { EventEmitter } from "./EventEmitter";
2 |
3 | describe("EventEmitter", () => {
4 | test("Single subscriber", () => {
5 | const emitter = new EventEmitter();
6 | const cb = jest.fn(() => {});
7 |
8 | emitter.on("test-event", cb);
9 | emitter.emit("test-event");
10 |
11 | expect(cb).toHaveBeenCalledTimes(1);
12 | });
13 |
14 | test("Single subscriber, with arguments", () => {
15 | const emitter = new EventEmitter();
16 | const cb = jest.fn(() => {});
17 |
18 | emitter.on("test-event", cb);
19 | emitter.emit("test-event", 1, 2);
20 |
21 | expect(cb).toHaveBeenCalledTimes(1);
22 | expect(cb).toHaveBeenCalledWith(1, 2);
23 | });
24 |
25 | test("Multiple subscribers", () => {
26 | const emitter = new EventEmitter();
27 | const cb1 = jest.fn(() => {});
28 | const cb2 = jest.fn(() => {});
29 |
30 | emitter.on("test-event", cb1);
31 | emitter.on("test-event", cb2);
32 |
33 | emitter.emit("test-event");
34 |
35 | expect(cb1).toHaveBeenCalledTimes(1);
36 | expect(cb2).toHaveBeenCalledTimes(1);
37 | });
38 |
39 | test("Multiple events", () => {
40 | const emitter = new EventEmitter();
41 | const cb1 = jest.fn(() => {});
42 | const cb2 = jest.fn(() => {});
43 | const cb3 = jest.fn(() => {});
44 |
45 | emitter.on("event1", cb1);
46 | emitter.on("event2", cb2);
47 | emitter.on("event3", cb3);
48 |
49 | emitter.emit("event1");
50 | emitter.emit("event2");
51 |
52 | expect(cb1).toHaveBeenCalledTimes(1);
53 | expect(cb2).toHaveBeenCalledTimes(1);
54 | expect(cb3).toHaveBeenCalledTimes(0);
55 | });
56 | });
57 |
--------------------------------------------------------------------------------
/src/internals/EventEmitter.ts:
--------------------------------------------------------------------------------
1 | export class EventEmitter {
2 | private subscribers: Map = new Map();
3 |
4 | public on(event: T, callback: (...args: any[]) => any) {
5 | if (!this.subscribers.get(event)) {
6 | this.subscribers.set(event, []);
7 | }
8 | this.subscribers.get(event).push(callback);
9 | }
10 |
11 | public emit(event: T, ...args: any[]) {
12 | const subscribers = this.subscribers.get(event) || [];
13 | for (const sub of subscribers) {
14 | sub(...args);
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/internals/StepQueue.ts:
--------------------------------------------------------------------------------
1 | import { Note } from "opensheetmusicdisplay/build/dist/src";
2 |
3 | type ScheduledNotes = {
4 | tick: number;
5 | notes: Note[];
6 | };
7 |
8 | export default class StepQueue {
9 | steps: ScheduledNotes[] = [];
10 |
11 | constructor() {}
12 |
13 | [Symbol.iterator]() {
14 | return this.steps.values();
15 | }
16 |
17 | createStep(tick: number): ScheduledNotes {
18 | let step = this.steps.find(s => s.tick === tick);
19 | if (!step) {
20 | step = { tick, notes: [] };
21 | this.steps.push(step);
22 | }
23 |
24 | return step;
25 | }
26 |
27 | addNote(tick: number, note: Note): void {
28 | const step = this.steps.find(s => s.tick === tick) ?? this.createStep(tick);
29 | step.notes.push(note);
30 | }
31 |
32 | delete(value: ScheduledNotes): void {
33 | const index = this.steps.findIndex(v => v.tick === value.tick);
34 | if (index != null) this.steps.splice(index, 1);
35 | }
36 |
37 | sort(): StepQueue {
38 | this.steps.sort((a, b) => a.tick - b.tick);
39 | return this;
40 | }
41 |
42 | getFirstEmptyTick(): number {
43 | return this.sort().steps.filter(s => !s.notes.length)[0].tick;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/internals/noteHelpers.ts:
--------------------------------------------------------------------------------
1 | import { Note } from "opensheetmusicdisplay/build/dist/src";
2 | import { ArticulationStyle } from "../players/NotePlaybackOptions";
3 |
4 | export function getNoteArticulationStyle(note: Note): ArticulationStyle {
5 | if (note.ParentVoiceEntry.isStaccato()) {
6 | return ArticulationStyle.Staccato;
7 | } else {
8 | return ArticulationStyle.None;
9 | }
10 | }
11 |
12 | export function getNoteDuration(note: Note, wholeNoteLength) {
13 | let duration = note.Length.RealValue * wholeNoteLength;
14 | if (note.NoteTie) {
15 | if (Object.is(note.NoteTie.StartNote, note) && note.NoteTie.Notes[1]) {
16 | duration += note.NoteTie.Notes[1].Length.RealValue * wholeNoteLength;
17 | } else {
18 | duration = 0;
19 | }
20 | }
21 | return duration;
22 | }
23 |
24 | export function getNoteVolume(note: Note) {
25 | return note.ParentVoiceEntry.ParentVoice.Volume;
26 | }
27 |
--------------------------------------------------------------------------------
/src/midi/midiInstruments.ts:
--------------------------------------------------------------------------------
1 | export const midiInstruments: [number, string][] = [
2 | [0, "Acoustic Grand Piano"],
3 | [1, "Bright Acoustic Piano"],
4 | [2, "Electric Grand Piano"],
5 | [3, "Honky-tonk Piano"],
6 | [4, "Electric Piano 1"],
7 | [5, "Electric Piano 2"],
8 | [6, "Harpsichord"],
9 | [7, "Clavi"],
10 | [8, "Celesta"],
11 | [9, "Glockenspiel"],
12 | [10, "Music Box"],
13 | [11, "Vibraphone"],
14 | [12, "Marimba"],
15 | [13, "Xylophone"],
16 | [14, "Tubular Bells"],
17 | [15, "Dulcimer"],
18 | [16, "Drawbar Organ"],
19 | [17, "Percussive Organ"],
20 | [18, "Rock Organ"],
21 | [19, "Church Organ"],
22 | [20, "Reed Organ"],
23 | [21, "Accordion"],
24 | [22, "Harmonica"],
25 | [23, "Tango Accordion"],
26 | [24, "Acoustic Guitar (nylon)"],
27 | [25, "Acoustic Guitar (steel)"],
28 | [26, "Electric Guitar (jazz)"],
29 | [27, "Electric Guitar (clean)"],
30 | [28, "Electric Guitar (muted)"],
31 | [29, "Overdriven Guitar"],
32 | [30, "Distortion Guitar"],
33 | [31, "Guitar harmonics"],
34 | [32, "Acoustic Bass"],
35 | [33, "Electric Bass (finger)"],
36 | [34, "Electric Bass (pick)"],
37 | [35, "Fretless Bass"],
38 | [36, "Slap Bass 1"],
39 | [37, "Slap Bass 2"],
40 | [38, "Synth Bass 1"],
41 | [39, "Synth Bass 2"],
42 | [40, "Violin"],
43 | [41, "Viola"],
44 | [42, "Cello"],
45 | [43, "Contrabass"],
46 | [44, "Tremolo Strings"],
47 | [45, "Pizzicato Strings"],
48 | [46, "Orchestral Harp"],
49 | [47, "Timpani"],
50 | [48, "String Ensemble 1"],
51 | [49, "String Ensemble 2"],
52 | [50, "SynthStrings 1"],
53 | [51, "SynthStrings 2"],
54 | [52, "Choir Aahs"],
55 | [53, "Voice Oohs"],
56 | [54, "Synth Choir"],
57 | [55, "Orchestra Hit"],
58 | [56, "Trumpet"],
59 | [57, "Trombone"],
60 | [58, "Tuba"],
61 | [59, "Muted Trumpet"],
62 | [60, "French Horn"],
63 | [61, "Brass Section"],
64 | [62, "SynthBrass 1"],
65 | [63, "SynthBrass 2"],
66 | [64, "Soprano Sax"],
67 | [65, "Alto Sax"],
68 | [66, "Tenor Sax"],
69 | [67, "Baritone Sax"],
70 | [68, "Oboe"],
71 | [69, "English Horn"],
72 | [70, "Bassoon"],
73 | [71, "Clarinet"],
74 | [72, "Piccolo"],
75 | [73, "Flute"],
76 | [74, "Recorder"],
77 | [75, "Pan Flute"],
78 | [76, "Blown Bottle"],
79 | [77, "Shakuhachi"],
80 | [78, "Whistle"],
81 | [79, "Ocarina"],
82 | [80, "Lead 1 (square)"],
83 | [81, "Lead 2 (sawtooth)"],
84 | [82, "Lead 3 (calliope)"],
85 | [83, "Lead 4 (chiff)"],
86 | [84, "Lead 5 (charang)"],
87 | [85, "Lead 6 (voice)"],
88 | [86, "Lead 7 (fifths)"],
89 | [87, "Lead 8 (bass + lead)"],
90 | [88, "Pad 1 (new age)"],
91 | [89, "Pad 2 (warm)"],
92 | [90, "Pad 3 (polysynth)"],
93 | [91, "Pad 4 (choir)"],
94 | [92, "Pad 5 (bowed)"],
95 | [93, "Pad 6 (metallic)"],
96 | [94, "Pad 7 (halo)"],
97 | [95, "Pad 8 (sweep)"],
98 | [96, "FX 1 (rain)"],
99 | [97, "FX 2 (soundtrack)"],
100 | [98, "FX 3 (crystal)"],
101 | [99, "FX 4 (atmosphere)"],
102 | [100, "FX 5 (brightness)"],
103 | [101, "FX 6 (goblins)"],
104 | [102, "FX 7 (echoes)"],
105 | [103, "FX 8 (sci-fi)"],
106 | [104, "Sitar"],
107 | [105, "Banjo"],
108 | [106, "Shamisen"],
109 | [107, "Koto"],
110 | [108, "Kalimba"],
111 | [109, "Bag pipe"],
112 | [110, "Fiddle"],
113 | [111, "Shanai"],
114 | [112, "Tinkle Bell"],
115 | [113, "Agogo"],
116 | [114, "Steel Drums"],
117 | [115, "Woodblock"],
118 | [116, "Taiko Drum"],
119 | [117, "Melodic Tom"],
120 | [118, "Synth Drum"],
121 | [119, "Reverse Cymbal"],
122 | [120, "Guitar Fret Noise"],
123 | [121, "Breath Noise"],
124 | [122, "Seashore"],
125 | [123, "Bird Tweet"],
126 | [124, "Telephone Ring"],
127 | [125, "Helicopter"],
128 | [126, "Applause"],
129 | [127, "Gunshot"],
130 | ];
131 |
--------------------------------------------------------------------------------
/src/players/InstrumentPlayer.ts:
--------------------------------------------------------------------------------
1 | import { NotePlaybackInstruction } from "./NotePlaybackOptions";
2 | import { IAudioContext } from "standardized-audio-context";
3 |
4 | export interface PlaybackInstrument {
5 | midiId: number;
6 | name: string;
7 | loaded: boolean;
8 | }
9 |
10 | export interface InstrumentPlayer {
11 | instruments: PlaybackInstrument[];
12 | init: (audioContext: IAudioContext) => void;
13 | load: (midiId: number) => Promise;
14 | schedule: (midiId: number, time: number, notes: NotePlaybackInstruction[]) => void;
15 | play: (midiId: number, options: NotePlaybackInstruction) => void;
16 | stop: (midiId: number) => void;
17 | }
18 |
--------------------------------------------------------------------------------
/src/players/NotePlaybackOptions.ts:
--------------------------------------------------------------------------------
1 | export enum ArticulationStyle {
2 | None,
3 | Staccato,
4 | Legato
5 | }
6 |
7 | export interface NotePlaybackStyle {
8 | articulation: ArticulationStyle;
9 | }
10 |
11 | export interface NotePlaybackInstruction extends NotePlaybackStyle {
12 | note: number;
13 | gain: number;
14 | duration: number;
15 | }
16 |
--------------------------------------------------------------------------------
/src/players/SoundfontPlayer.ts:
--------------------------------------------------------------------------------
1 | import { InstrumentPlayer, PlaybackInstrument } from "./InstrumentPlayer";
2 | import { NotePlaybackStyle, NotePlaybackInstruction, ArticulationStyle } from "./NotePlaybackOptions";
3 | import { midiInstruments } from "../midi/midiInstruments";
4 | import { IAudioContext } from "standardized-audio-context";
5 | import supportedSoundfontInstruments from "./musyngkiteInstruments";
6 | import * as Soundfont from "soundfont-player";
7 |
8 | export class SoundfontPlayer implements InstrumentPlayer {
9 | public instruments: PlaybackInstrument[];
10 |
11 | private players: Map = new Map();
12 | private audioContext: IAudioContext;
13 |
14 | constructor() {
15 | this.instruments = midiInstruments
16 | .filter(i => supportedSoundfontInstruments.includes(this.getSoundfontInstrumentName(i[1])))
17 | .map(i => ({
18 | midiId: i[0],
19 | name: i[1],
20 | loaded: false,
21 | }));
22 | }
23 |
24 | init(audioContext: IAudioContext) {
25 | this.audioContext = audioContext;
26 | }
27 |
28 | async load(midiId: number) {
29 | const instrument = this.instruments.find(i => i.midiId === midiId);
30 | if (!instrument) {
31 | throw new Error("SoundfontPlayer does not support midi instrument ID " + midiId);
32 | }
33 | if (this.players.has(midiId)) return;
34 |
35 | const player = await Soundfont.instrument(
36 | //@ts-ignore
37 | this.audioContext,
38 | this.getSoundfontInstrumentName(instrument.name) as Soundfont.InstrumentName
39 | );
40 | this.players.set(midiId, player);
41 | }
42 |
43 | play: (midiId: string | number, options: NotePlaybackStyle) => void;
44 |
45 | stop(midiId: number) {
46 | if (!this.players.has(midiId)) return;
47 | this.players.get(midiId).stop();
48 | }
49 |
50 | schedule(midiId: number, time: number, notes: NotePlaybackInstruction[]) {
51 | this.verifyPlayerLoaded(midiId);
52 | this.applyDynamics(notes);
53 | this.players.get(midiId).schedule(time, notes);
54 | }
55 |
56 | private applyDynamics(notes: NotePlaybackInstruction[]): void {
57 | for (const note of notes) {
58 | if (note.articulation === ArticulationStyle.Staccato) {
59 | note.gain = Math.max(note.gain + 0.3, note.gain * 1.3);
60 | note.duration = Math.min(note.duration * 0.4, 0.4);
61 | }
62 | }
63 | }
64 |
65 | private verifyPlayerLoaded(midiId: number) {
66 | if (!this.players.has(midiId)) throw new Error("No soundfont player loaded for midi instrument " + midiId);
67 | }
68 |
69 | private getSoundfontInstrumentName(midiName: string): string {
70 | return midiName.toLowerCase().replace(/\s+/g, "_");
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/players/musyngkiteInstruments.ts:
--------------------------------------------------------------------------------
1 | export default [
2 | "accordion",
3 | "acoustic_bass",
4 | "acoustic_grand_piano",
5 | "acoustic_guitar_nylon",
6 | "acoustic_guitar_steel",
7 | "agogo",
8 | "alto_sax",
9 | "applause",
10 | "bagpipe",
11 | "banjo",
12 | "baritone_sax",
13 | "bassoon",
14 | "bird_tweet",
15 | "blown_bottle",
16 | "brass_section",
17 | "breath_noise",
18 | "bright_acoustic_piano",
19 | "celesta",
20 | "cello",
21 | "choir_aahs",
22 | "church_organ",
23 | "clarinet",
24 | "clavinet",
25 | "contrabass",
26 | "distortion_guitar",
27 | "drawbar_organ",
28 | "dulcimer",
29 | "electric_bass_finger",
30 | "electric_bass_pick",
31 | "electric_grand_piano",
32 | "electric_guitar_clean",
33 | "electric_guitar_jazz",
34 | "electric_guitar_muted",
35 | "electric_piano_1",
36 | "electric_piano_2",
37 | "english_horn",
38 | "fiddle",
39 | "flute",
40 | "french_horn",
41 | "fretless_bass",
42 | "fx_1_rain",
43 | "fx_2_soundtrack",
44 | "fx_3_crystal",
45 | "fx_4_atmosphere",
46 | "fx_5_brightness",
47 | "fx_6_goblins",
48 | "fx_7_echoes",
49 | "fx_8_scifi",
50 | "glockenspiel",
51 | "guitar_fret_noise",
52 | "guitar_harmonics",
53 | "gunshot",
54 | "harmonica",
55 | "harpsichord",
56 | "helicopter",
57 | "honkytonk_piano",
58 | "kalimba",
59 | "koto",
60 | "lead_1_square",
61 | "lead_2_sawtooth",
62 | "lead_3_calliope",
63 | "lead_4_chiff",
64 | "lead_5_charang",
65 | "lead_6_voice",
66 | "lead_7_fifths",
67 | "lead_8_bass__lead",
68 | "marimba",
69 | "melodic_tom",
70 | "music_box",
71 | "muted_trumpet",
72 | "oboe",
73 | "ocarina",
74 | "orchestra_hit",
75 | "orchestral_harp",
76 | "overdriven_guitar",
77 | "pad_1_new_age",
78 | "pad_2_warm",
79 | "pad_3_polysynth",
80 | "pad_4_choir",
81 | "pad_5_bowed",
82 | "pad_6_metallic",
83 | "pad_7_halo",
84 | "pad_8_sweep",
85 | "pan_flute",
86 | "percussive_organ",
87 | "piccolo",
88 | "pizzicato_strings",
89 | "recorder",
90 | "reed_organ",
91 | "reverse_cymbal",
92 | "rock_organ",
93 | "seashore",
94 | "shakuhachi",
95 | "shamisen",
96 | "shanai",
97 | "sitar",
98 | "slap_bass_1",
99 | "slap_bass_2",
100 | "soprano_sax",
101 | "steel_drums",
102 | "string_ensemble_1",
103 | "string_ensemble_2",
104 | "synth_bass_1",
105 | "synth_bass_2",
106 | "synth_brass_1",
107 | "synth_brass_2",
108 | "synth_choir",
109 | "synth_drum",
110 | "synth_strings_1",
111 | "synth_strings_2",
112 | "taiko_drum",
113 | "tango_accordion",
114 | "telephone_ring",
115 | "tenor_sax",
116 | "timpani",
117 | "tinkle_bell",
118 | "tremolo_strings",
119 | "trombone",
120 | "trumpet",
121 | "tuba",
122 | "tubular_bells",
123 | "vibraphone",
124 | "viola",
125 | "violin",
126 | "voice_oohs",
127 | "whistle",
128 | "woodblock",
129 | "xylophone",
130 | ];
131 |
--------------------------------------------------------------------------------
/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./dist"
5 | }
6 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "rootDir": "src",
5 | "lib": ["ES2019", "DOM"],
6 | "target": "ES6",
7 | "moduleResolution": "Node",
8 | "declaration": true
9 | },
10 | "include": ["src/**/*"]
11 | }
12 |
--------------------------------------------------------------------------------
/umd/OsmdAudioPlayer.min.js:
--------------------------------------------------------------------------------
1 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).OsmdAudioPlayer=t()}(this,(function(){"use strict";
2 | /*! *****************************************************************************
3 | Copyright (c) Microsoft Corporation.
4 |
5 | Permission to use, copy, modify, and/or distribute this software for any
6 | purpose with or without fee is hereby granted.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 | PERFORMANCE OF THIS SOFTWARE.
15 | ***************************************************************************** */function e(e,t,n,r){return new(n||(n=Promise))((function(o,a){function i(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,s)}c((r=r.apply(e,t||[])).next())}))}class t{constructor(){this.steps=[]}[Symbol.iterator](){return this.steps.values()}createStep(e){let t=this.steps.find(t=>t.tick===e);return t||(t={tick:e,notes:[]},this.steps.push(t)),t}addNote(e,t){var n;(null!=(n=this.steps.find(t=>t.tick===e))?n:this.createStep(e)).notes.push(t)}delete(e){const t=this.steps.findIndex(t=>t.tick===e.tick);null!=t&&this.steps.splice(t,1)}sort(){return this.steps.sort((e,t)=>e.tick-t.tick),this}getFirstEmptyTick(){return this.sort().steps.filter(e=>!e.notes.length)[0].tick}}class n{constructor(e,n,r,o){this.stepQueue=new t,this.stepQueueIndex=0,this.scheduledTicks=new Set,this.currentTick=0,this.currentTickTimestamp=0,this.audioContextStartTime=0,this.schedulerIntervalHandle=null,this.scheduleInterval=200,this.schedulePeriod=500,this.tickDenominator=1024,this.lastTickOffset=300,this.playing=!1,this.noteSchedulingCallback=o,this.denominator=e,this.wholeNoteLength=n,this.audioContext=r}get schedulePeriodTicks(){return this.schedulePeriod/this.tickDuration}get audioContextTime(){return this.audioContext?1e3*(this.audioContext.currentTime-this.audioContextStartTime):0}get tickDuration(){return this.wholeNoteLength/this.tickDenominator}get calculatedTick(){return this.currentTick+Math.round((this.audioContextTime-this.currentTickTimestamp)/this.tickDuration)}start(){this.playing=!0,this.stepQueue.sort(),this.audioContextStartTime=this.audioContext.currentTime,this.currentTickTimestamp=this.audioContextTime,this.schedulerIntervalHandle||(this.schedulerIntervalHandle=window.setInterval(()=>this.scheduleIterationStep(),this.scheduleInterval))}setIterationStep(e){e=Math.min(this.stepQueue.steps.length-1,e),this.stepQueueIndex=e,this.currentTick=this.stepQueue.steps[this.stepQueueIndex].tick}pause(){this.playing=!1}resume(){this.playing=!0,this.currentTickTimestamp=this.audioContextTime}reset(){this.playing=!1,this.currentTick=0,this.currentTickTimestamp=0,this.stepQueueIndex=0,clearInterval(this.scheduleInterval),this.schedulerIntervalHandle=null}loadNotes(e){let t=this.lastTickOffset;this.stepQueue.steps.length>0&&(t=this.stepQueue.getFirstEmptyTick());for(let n of e)if(!n.IsGrace)for(let e of n.Notes)this.stepQueue.addNote(t,e),this.stepQueue.createStep(t+e.Length.RealValue*this.tickDenominator)}scheduleIterationStep(){var e,t;if(!this.playing)return;this.currentTick=this.calculatedTick,this.currentTickTimestamp=this.audioContextTime;let n=null===(e=this.stepQueue.steps[this.stepQueueIndex])||void 0===e?void 0:e.tick;for(;this.nextTickAvailableAndWithinSchedulePeriod(n);){let e=this.stepQueue.steps[this.stepQueueIndex],r=(e.tick-this.currentTick)*this.tickDuration;r<0&&(r=0),this.scheduledTicks.add(e.tick),this.noteSchedulingCallback(r/1e3,e.notes),this.stepQueueIndex++,n=null===(t=this.stepQueue.steps[this.stepQueueIndex])||void 0===t?void 0:t.tick}for(let e of this.scheduledTicks)e<=this.currentTick&&this.scheduledTicks.delete(e)}nextTickAvailableAndWithinSchedulePeriod(e){return e&&this.currentTickTimestamp+(e-this.currentTick)*this.tickDuration<=this.currentTickTimestamp+this.schedulePeriod}}var r;!function(e){e[e.None=0]="None",e[e.Staccato=1]="Staccato",e[e.Legato=2]="Legato"}(r||(r={}));const o=[[0,"Acoustic Grand Piano"],[1,"Bright Acoustic Piano"],[2,"Electric Grand Piano"],[3,"Honky-tonk Piano"],[4,"Electric Piano 1"],[5,"Electric Piano 2"],[6,"Harpsichord"],[7,"Clavi"],[8,"Celesta"],[9,"Glockenspiel"],[10,"Music Box"],[11,"Vibraphone"],[12,"Marimba"],[13,"Xylophone"],[14,"Tubular Bells"],[15,"Dulcimer"],[16,"Drawbar Organ"],[17,"Percussive Organ"],[18,"Rock Organ"],[19,"Church Organ"],[20,"Reed Organ"],[21,"Accordion"],[22,"Harmonica"],[23,"Tango Accordion"],[24,"Acoustic Guitar (nylon)"],[25,"Acoustic Guitar (steel)"],[26,"Electric Guitar (jazz)"],[27,"Electric Guitar (clean)"],[28,"Electric Guitar (muted)"],[29,"Overdriven Guitar"],[30,"Distortion Guitar"],[31,"Guitar harmonics"],[32,"Acoustic Bass"],[33,"Electric Bass (finger)"],[34,"Electric Bass (pick)"],[35,"Fretless Bass"],[36,"Slap Bass 1"],[37,"Slap Bass 2"],[38,"Synth Bass 1"],[39,"Synth Bass 2"],[40,"Violin"],[41,"Viola"],[42,"Cello"],[43,"Contrabass"],[44,"Tremolo Strings"],[45,"Pizzicato Strings"],[46,"Orchestral Harp"],[47,"Timpani"],[48,"String Ensemble 1"],[49,"String Ensemble 2"],[50,"SynthStrings 1"],[51,"SynthStrings 2"],[52,"Choir Aahs"],[53,"Voice Oohs"],[54,"Synth Choir"],[55,"Orchestra Hit"],[56,"Trumpet"],[57,"Trombone"],[58,"Tuba"],[59,"Muted Trumpet"],[60,"French Horn"],[61,"Brass Section"],[62,"SynthBrass 1"],[63,"SynthBrass 2"],[64,"Soprano Sax"],[65,"Alto Sax"],[66,"Tenor Sax"],[67,"Baritone Sax"],[68,"Oboe"],[69,"English Horn"],[70,"Bassoon"],[71,"Clarinet"],[72,"Piccolo"],[73,"Flute"],[74,"Recorder"],[75,"Pan Flute"],[76,"Blown Bottle"],[77,"Shakuhachi"],[78,"Whistle"],[79,"Ocarina"],[80,"Lead 1 (square)"],[81,"Lead 2 (sawtooth)"],[82,"Lead 3 (calliope)"],[83,"Lead 4 (chiff)"],[84,"Lead 5 (charang)"],[85,"Lead 6 (voice)"],[86,"Lead 7 (fifths)"],[87,"Lead 8 (bass + lead)"],[88,"Pad 1 (new age)"],[89,"Pad 2 (warm)"],[90,"Pad 3 (polysynth)"],[91,"Pad 4 (choir)"],[92,"Pad 5 (bowed)"],[93,"Pad 6 (metallic)"],[94,"Pad 7 (halo)"],[95,"Pad 8 (sweep)"],[96,"FX 1 (rain)"],[97,"FX 2 (soundtrack)"],[98,"FX 3 (crystal)"],[99,"FX 4 (atmosphere)"],[100,"FX 5 (brightness)"],[101,"FX 6 (goblins)"],[102,"FX 7 (echoes)"],[103,"FX 8 (sci-fi)"],[104,"Sitar"],[105,"Banjo"],[106,"Shamisen"],[107,"Koto"],[108,"Kalimba"],[109,"Bag pipe"],[110,"Fiddle"],[111,"Shanai"],[112,"Tinkle Bell"],[113,"Agogo"],[114,"Steel Drums"],[115,"Woodblock"],[116,"Taiko Drum"],[117,"Melodic Tom"],[118,"Synth Drum"],[119,"Reverse Cymbal"],[120,"Guitar Fret Noise"],[121,"Breath Noise"],[122,"Seashore"],[123,"Bird Tweet"],[124,"Telephone Ring"],[125,"Helicopter"],[126,"Applause"],[127,"Gunshot"]];var a=["accordion","acoustic_bass","acoustic_grand_piano","acoustic_guitar_nylon","acoustic_guitar_steel","agogo","alto_sax","applause","bagpipe","banjo","baritone_sax","bassoon","bird_tweet","blown_bottle","brass_section","breath_noise","bright_acoustic_piano","celesta","cello","choir_aahs","church_organ","clarinet","clavinet","contrabass","distortion_guitar","drawbar_organ","dulcimer","electric_bass_finger","electric_bass_pick","electric_grand_piano","electric_guitar_clean","electric_guitar_jazz","electric_guitar_muted","electric_piano_1","electric_piano_2","english_horn","fiddle","flute","french_horn","fretless_bass","fx_1_rain","fx_2_soundtrack","fx_3_crystal","fx_4_atmosphere","fx_5_brightness","fx_6_goblins","fx_7_echoes","fx_8_scifi","glockenspiel","guitar_fret_noise","guitar_harmonics","gunshot","harmonica","harpsichord","helicopter","honkytonk_piano","kalimba","koto","lead_1_square","lead_2_sawtooth","lead_3_calliope","lead_4_chiff","lead_5_charang","lead_6_voice","lead_7_fifths","lead_8_bass__lead","marimba","melodic_tom","music_box","muted_trumpet","oboe","ocarina","orchestra_hit","orchestral_harp","overdriven_guitar","pad_1_new_age","pad_2_warm","pad_3_polysynth","pad_4_choir","pad_5_bowed","pad_6_metallic","pad_7_halo","pad_8_sweep","pan_flute","percussive_organ","piccolo","pizzicato_strings","recorder","reed_organ","reverse_cymbal","rock_organ","seashore","shakuhachi","shamisen","shanai","sitar","slap_bass_1","slap_bass_2","soprano_sax","steel_drums","string_ensemble_1","string_ensemble_2","synth_bass_1","synth_bass_2","synth_brass_1","synth_brass_2","synth_choir","synth_drum","synth_strings_1","synth_strings_2","taiko_drum","tango_accordion","telephone_ring","tenor_sax","timpani","tinkle_bell","tremolo_strings","trombone","trumpet","tuba","tubular_bells","vibraphone","viola","violin","voice_oohs","whistle","woodblock","xylophone"];"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self&&self;function i(e,t,n){return e(n={path:t,exports:{},require:function(e,t){return s(null==t&&n.path)}},n.exports),n.exports}function s(){throw new Error("Dynamic requires are not currently supported by @rollup/plugin-commonjs")}var c={decode:function(e,t){for(var n,r,o,a=e.replace(/[^A-Za-z0-9\+\/]/g,""),i=a.length,s=t?Math.ceil((3*i+1>>2)/t)*t:3*i+1>>2,c=new Uint8Array(s),u=0,l=0,h=0;h64&&o<91?o-65:o>96&&o<123?o-71:o>47&&o<58?o+4:43===o?62:47===o?63:0)<<18-6*r,3===r||i-h==1){for(n=0;n<3&&l>>(16>>>n&24)&255;u=0}return c}},u=function(e,t){return new Promise((function(n,r){var o=new XMLHttpRequest;t&&(o.responseType=t),o.open("GET",e),o.onload=function(){200===o.status?n(o.response):r(Error(o.statusText))},o.onerror=function(){r(Error("Network Error"))},o.send()}))},l=i((function(e){function t(e){return function(t){return"string"==typeof t&&e.test(t)}}function n(e,t){return"string"==typeof e?e+t:"function"==typeof e?e(t):t}function r(e,t,n,r){var c=t instanceof ArrayBuffer?o:a(t)?i:function(e){return e&&"function"==typeof e.then}(t)?s:l(t)?h:function(e){return e&&"object"==typeof e}(t)?d:f(t)?p:m(t)?v:g(t)?y:null;return c?c(e,t,n||{}):r?Promise.resolve(r):Promise.reject("Source not valid ("+t+")")}function o(e,t,n){return new Promise((function(n,r){e.decodeAudioData(t,(function(e){n(e)}),(function(){r("Can't decode audio data ("+t.slice(0,30)+"...)")}))}))}r.fetch=u;var a=t(/\.(mp3|wav|ogg)(\?.*)?$/i);function i(e,t,o){var a=n(o.from,t);return r(e,r.fetch(a,"arraybuffer"),o)}function s(e,t,n){return t.then((function(t){return r(e,t,n)}))}var l=Array.isArray;function h(e,t,n){return Promise.all(t.map((function(t){return r(e,t,n,t)})))}function d(e,t,n){var o={},a=Object.keys(t).map((function(a){if(n.only&&-1===n.only.indexOf(a))return null;var i=t[a];return r(e,i,n,i).then((function(e){o[a]=e}))}));return Promise.all(a).then((function(){return o}))}var f=t(/\.json(\?.*)?$/i);function p(e,t,o){var a=n(o.from,t);return r(e,r.fetch(a,"text").then(JSON.parse),o)}var m=t(/^data:audio/);function v(e,t,n){var o=t.indexOf(",");return r(e,c.decode(t.slice(o+1)).buffer,n)}var g=t(/\.js(\?.*)?$/i);function y(e,t,o){var a=n(o.from,t);return r(e,r.fetch(a,"text").then(w),o)}function w(e){var t=e.indexOf("MIDI.Soundfont.");if(t<0)throw Error("Invalid MIDI.js Soundfont format");t=e.indexOf("=",t)+2;var n=e.lastIndexOf(",");return JSON.parse(e.slice(t,n)+"}")}e.exports&&(e.exports=r),"undefined"!=typeof window&&(window.loadAudio=r)})),h=function(e){var t=e.createGain(),n=t._voltage=function(e){var t=e.createBufferSource(),n=e.createBuffer(1,2,e.sampleRate);return n.getChannelData(0).set(f),t.buffer=n,t.loop=!0,t}(e),r=p(n),o=p(n),a=p(n);return t._startAmount=p(o),t._endAmount=p(a),t._multiplier=p(r),t._multiplier.connect(t),t._startAmount.connect(t),t._endAmount.connect(t),t.value=r.gain,t.startValue=o.gain,t.endValue=a.gain,t.startValue.value=0,t.endValue.value=0,Object.defineProperties(t,d),t};var d={attack:{value:0,writable:!0},decay:{value:0,writable:!0},sustain:{value:1,writable:!0},release:{value:0,writable:!0},getReleaseDuration:{value:function(){return this.release}},start:{value:function(e){var t=this._multiplier.gain,n=this._startAmount.gain,r=this._endAmount.gain;this._voltage.start(e),this._decayFrom=this._decayFrom=e+this.attack,this._startedAt=e;var o=this.sustain;t.cancelScheduledValues(e),n.cancelScheduledValues(e),r.cancelScheduledValues(e),r.setValueAtTime(0,e),this.attack?(t.setValueAtTime(0,e),t.linearRampToValueAtTime(1,e+this.attack),n.setValueAtTime(1,e),n.linearRampToValueAtTime(0,e+this.attack)):(t.setValueAtTime(1,e),n.setValueAtTime(0,e)),this.decay&&t.setTargetAtTime(o,this._decayFrom,m(this.decay))}},stop:{value:function(e,t){t&&(e-=this.release);var n=e+this.release;if(this.release){var r=this._multiplier.gain,o=this._startAmount.gain,a=this._endAmount.gain;r.cancelScheduledValues(e),o.cancelScheduledValues(e),a.cancelScheduledValues(e);var i=m(this.release);if(this.attack&&e=t&&(a=t);return a}(0,1,this._startedAt,this._decayFrom,e);r.linearRampToValueAtTime(s,e),o.linearRampToValueAtTime(1-s,e),o.setTargetAtTime(0,e,i)}a.setTargetAtTime(1,e,i),r.setTargetAtTime(0,e,i)}return this._voltage.stop(n),n}},onended:{get:function(){return this._voltage.onended},set:function(e){this._voltage.onended=e}}},f=new Float32Array([1,1]);function p(e){var t=e.context.createGain();return e.connect(t),t}function m(e){return Math.log(e+1)/Math.log(100)}var v={},g={gain:1,attack:.01,decay:.1,sustain:.9,release:.3,loop:!1,cents:0,loopStart:0,loopEnd:0};function y(e){return"number"==typeof e}var w=["attack","decay","sustain","release"];var _=function(e,t,n){var r=!1,o=0,a={},i=e.createGain();i.gain.value=1;var s=Object.assign({},g,n),c={context:e,out:i,opts:s};return t instanceof AudioBuffer?c.buffer=t:c.buffers=t,c.start=function(t,n,i){if(c.buffer&&null!==t)return c.start(null,t,n);var s=t?c.buffers[t]:c.buffer;if(s){if(r){var l=i||v;n=Math.max(e.currentTime,n||0),c.emit("start",n,t,l);var h=u(t,s,l);return h.id=function(t,n){return n.id=o++,a[n.id]=n,n.source.onended=function(){var t=e.currentTime;n.source.disconnect(),n.env.disconnect(),n.disconnect(),c.emit("ended",t,n.id,n)},n.id}(0,h),h.env.start(n),h.source.start(n),c.emit("started",n,h.id,h),l.duration&&h.stop(n+l.duration),h}console.warn("SamplePlayer not connected to any node.")}else console.warn("Buffer "+t+" not found.")},c.play=function(e,t,n){return c.start(e,t,n)},c.stop=function(e,t){var n;return(t=t||Object.keys(a)).map((function(t){return(n=a[t])?(n.stop(e),n.id):null}))},c.connect=function(e){return r=!0,i.connect(e),c},c.emit=function(e,t,n,r){c.onevent&&c.onevent(e,t,n,r);var o=c["on"+e];o&&o(t,n,r)},c;function u(t,n,r){var o,a=e.createGain();return a.gain.value=0,a.connect(i),a.env=function(e,t,n){var r=h(e),o=t.adsr||n.adsr;return w.forEach((function(e,a){r[e]=o?o[a]:t[e]||n[e]})),r.value.value=y(t.gain)?t.gain:y(n.gain)?n.gain:1,r}(e,r,s),a.env.connect(a.gain),a.source=e.createBufferSource(),a.source.buffer=n,a.source.connect(a),a.source.loop=r.loop||s.loop,a.source.playbackRate.value=(o=r.cents||s.cents)?Math.pow(2,o/1200):1,a.source.loopStart=r.loopStart||s.loopStart,a.source.loopEnd=r.loopEnd||s.loopEnd,a.stop=function(n){var r=n||e.currentTime;c.emit("stop",r,t);var o=a.env.stop(r);a.source.stop(o)},a}};function C(e,t){return function(n,r,o,a){e(n,r,o,a),t(n,r,o,a)}}var b=/^([a-gA-G])(#{1,}|b{1,}|x{1,}|)(-?\d*)\s*(.*)\s*$/;var T=[0,2,4,5,7,9,11];function M(e,t,n){if("string"!=typeof e)return null;var r=b.exec(e);if(!r||!t&&r[4])return null;var o={letter:r[1].toUpperCase(),acc:r[2].replace(/x/g,"##")};return o.pc=o.letter+o.acc,o.step=(o.letter.charCodeAt(0)+3)%7,o.alt="b"===o.acc[0]?-o.acc.length:o.acc.length,o.chroma=T[o.step]+o.alt,r[3]&&(o.oct=+r[3],o.midi=o.chroma+12*(o.oct+1),o.freq=I(o.midi,n)),t&&(o.tonicOf=r[4]),o}function I(e,t){return Math.pow(2,(e-69)/12)*(t||440)}var x={parse:M,regex:function(){return b},midiToFreq:I};["letter","acc","pc","step","alt","chroma","oct","midi","freq"].forEach((function(e){x[e]=function(t){var n=M(t);return n&&void 0!==n[e]?n[e]:null}}));var S=x,A=function(e){return function(e){return null!==e&&e!==[]&&e>=0&&e<129}(e)?+e:S.midi(e)},N=function(e){if(e.buffers){var t=e.opts.map,n="function"==typeof t?t:A,r=function(e){return e?n(e)||e:null};e.buffers=function(e,t){return Object.keys(e).reduce((function(n,r){return n[t(r)]=e[r],n}),{})}(e.buffers,r);var o=e.start;e.start=function(e,t,n){var a=r(e),i=a%1;return i&&(a=Math.floor(a),n=Object.assign(n||{},{cents:Math.floor(100*i)})),o(a,t,n)}}return e};var k=Array.isArray,O={},E=i((function(e,t){e.exports=function e(t,n,r){function o(i,c){if(!n[i]){if(!t[i]){if(!c&&s)return s();if(a)return a(i,!0);var u=new Error("Cannot find module '"+i+"'");throw u.code="MODULE_NOT_FOUND",u}var l=n[i]={exports:{}};t[i][0].call(l.exports,(function(e){var n=t[i][1][e];return o(n||e)}),l,l.exports,e,t,n,r)}return n[i].exports}for(var a=s,i=0;i6?null:b.charAt(e)+c(t)+u(n)}function h(e){if((n(e)||r(e))&&e>=0&&e<128)return+e;var t=s(e);return t&&o(t.midi)?t.midi:null}function d(e,t){var n=h(e);return null===n?null:a(n,t)}function f(e){return(s(e)||{}).letter}function p(e){return(s(e)||{}).acc}function m(e){return(s(e)||{}).pc}function v(e){return(s(e)||{}).step}function g(e){return(s(e)||{}).alt}function y(e){return(s(e)||{}).chroma}function w(e){return(s(e)||{}).oct}var _=/^([a-gA-G])(#{1,}|b{1,}|x{1,}|)(-?\d*)\s*(.*)\s*$/,C=[0,2,4,5,7,9,11],b="CDEFGAB";e.regex=i,e.parse=s,e.build=l,e.midi=h,e.freq=d,e.letter=f,e.acc=p,e.pc=m,e.step=v,e.alt=g,e.chroma=y,e.oct=w}(t)}));function R(e,t){if(console.warn("new Soundfont() is deprected"),console.log("Please use Soundfont.instrument() instead of new Soundfont().instrument()"),!(this instanceof R))return new R(e);this.nameToUrl=t||R.nameToUrl,this.ctx=e,this.instruments={},this.promises=[]}function V(e,t){return t=t||{},function(n,r,o,a){console.warn("The oscillator player is deprecated."),console.log("Starting with version 0.9.0 you will have to wait until the soundfont is loaded to play sounds.");var i=n>0&&n<129?+n:D.midi(n),s=i?D.midiToFreq(i,440):null;if(s){o=o||.2;var c=(a=a||{}).destination||t.destination||e.destination,u=a.vcoType||t.vcoType||"sine",l=a.gain||t.gain||.4,h=e.createOscillator();h.type=u,h.frequency.value=s;var d=e.createGain();return d.gain.value=l,h.connect(d),d.connect(c),h.start(r),o>0&&h.stop(r+o),h}}}R.prototype.onready=function(e){console.warn("deprecated API"),console.log("Please use Promise.all(Soundfont.instrument(), Soundfont.instrument()).then() instead of new Soundfont().onready()"),Promise.all(this.promises).then(e)},R.prototype.instrument=function(e,t){console.warn("new Soundfont().instrument() is deprecated."),console.log("Please use Soundfont.instrument() instead.");var n=this.ctx;if((e=e||"default")in this.instruments)return this.instruments[e];var r={name:e,play:V(n,t)};if(this.instruments[e]=r,"default"!==e){var o=R.instrument(n,e,t).then((function(e){return r.play=e.play,r}));this.promises.push(o),r.onready=function(e){console.warn("onready is deprecated. Use Soundfont.instrument().then()"),o.then(e)}}else r.onready=function(e){console.warn("onready is deprecated. Use Soundfont.instrument().then()"),e()};return r},R.loadBuffers=function(e,t,n){return console.warn("Soundfont.loadBuffers is deprecate."),console.log("Use Soundfont.instrument(..) and get buffers properties from the result."),R.instrument(e,t,n).then((function(e){return e.buffers}))},R.noteToMidi=D.midi;var B=R,F=i((function(e){function t(e){return/\.js(\?.*)?$/i.test(e)}function n(e,t,n){return"https://gleitz.github.io/midi-js-soundfonts/"+(t="FluidR3_GM"===t?t:"MusyngKite")+"/"+e+"-"+(n="ogg"===n?n:"mp3")+".js"}B.instrument=function e(r,o,a){if(1===arguments.length)return function(t,n){return e(r,t,n)};var i=a||{},s=i.isSoundfontURL||t,c=i.nameToUrl||n,u=s(o)?o:c(o,i.soundfont,i.format);return l(r,u,{only:i.only||i.notes}).then((function(e){var t=P(r,e,i).connect(i.destination?i.destination:r.destination);return t.url=u,t.name=o,t}))},B.nameToUrl=n,e.exports&&(e.exports=B),"undefined"!=typeof window&&(window.Soundfont=B)}));class L{constructor(){this.players=new Map,this.instruments=o.filter(e=>a.includes(this.getSoundfontInstrumentName(e[1]))).map(e=>({midiId:e[0],name:e[1],loaded:!1}))}init(e){this.audioContext=e}load(t){return e(this,void 0,void 0,(function*(){const e=this.instruments.find(e=>e.midiId===t);if(!e)throw new Error("SoundfontPlayer does not support midi instrument ID "+t);if(this.players.has(t))return;const n=yield F.instrument(this.audioContext,this.getSoundfontInstrumentName(e.name));this.players.set(t,n)}))}stop(e){this.players.has(e)&&this.players.get(e).stop()}schedule(e,t,n){this.verifyPlayerLoaded(e),this.applyDynamics(n),this.players.get(e).schedule(t,n)}applyDynamics(e){for(const t of e)t.articulation===r.Staccato&&(t.gain=Math.max(t.gain+.3,1.3*t.gain),t.duration=Math.min(.4*t.duration,.4))}verifyPlayerLoaded(e){if(!this.players.has(e))throw new Error("No soundfont player loaded for midi instrument "+e)}getSoundfontInstrumentName(e){return e.toLowerCase().replace(/\s+/g,"_")}}function W(e){return e.ParentVoiceEntry.isStaccato()?r.Staccato:r.None}function j(e,t){let n=e.Length.RealValue*t;return e.NoteTie&&(Object.is(e.NoteTie.StartNote,e)&&e.NoteTie.Notes[1]?n+=e.NoteTie.Notes[1].Length.RealValue*t:n=0),n}function G(e){return e.ParentVoiceEntry.ParentVoice.Volume}class X{constructor(){this.subscribers=new Map}on(e,t){this.subscribers.get(e)||this.subscribers.set(e,[]),this.subscribers.get(e).push(t)}emit(e,...t){const n=this.subscribers.get(e)||[];for(const e of n)e(...t)}}const q=(e,t,n)=>({endTime:t,insertTime:n,type:"exponentialRampToValue",value:e}),z=(e,t,n)=>({endTime:t,insertTime:n,type:"linearRampToValue",value:e}),Y=(e,t)=>({startTime:t,type:"setValue",value:e}),Z=(e,t,n)=>({duration:n,startTime:t,type:"setValueCurve",values:e}),U=(e,t,{startTime:n,target:r,timeConstant:o})=>r+(t-r)*Math.exp((n-e)/o),Q=e=>"exponentialRampToValue"===e.type,H=e=>"linearRampToValue"===e.type,$=e=>Q(e)||H(e),K=e=>"setValue"===e.type,J=e=>"setValueCurve"===e.type,ee=(e,t,n,r)=>{const o=e[t];return void 0===o?r:$(o)||K(o)?o.value:J(o)?o.values[o.values.length-1]:U(n,ee(e,t-1,o.startTime,r),o)},te=(e,t,n,r,o)=>void 0===n?[r.insertTime,o]:$(n)?[n.endTime,n.value]:K(n)?[n.startTime,n.value]:J(n)?[n.startTime+n.duration,n.values[n.values.length-1]]:[n.startTime,ee(e,t-1,n.startTime,o)],ne=e=>"cancelAndHold"===e.type,re=e=>"cancelScheduledValues"===e.type,oe=e=>ne(e)||re(e)?e.cancelTime:Q(e)||H(e)?e.endTime:e.startTime,ae=(e,t,n,{endTime:r,value:o})=>n===o?o:0n+(e-t)/(r-t)*(o-n),se=(e,{duration:t,startTime:n,values:r})=>((e,t)=>{const n=Math.floor(t),r=Math.ceil(t);return n===r?e[n]:(1-(t-n))*e[n]+(1-(r-t))*e[r]})(r,(e-n)/t*(r.length-1)),ce=e=>"setTarget"===e.type;class ue{constructor(e){this._automationEvents=[],this._currenTime=0,this._defaultValue=e}[Symbol.iterator](){return this._automationEvents[Symbol.iterator]()}add(e){const t=oe(e);if(ne(e)||re(e)){const n=this._automationEvents.findIndex(e=>oe(e)>=t),r=this._automationEvents[n];if(-1!==n&&(this._automationEvents=this._automationEvents.slice(0,n)),ne(e)){const e=this._automationEvents[this._automationEvents.length-1];if(void 0!==r&&$(r)){if(ce(e))throw new Error("The internal list is malformed.");const n=J(e)?e.startTime+e.duration:oe(e),o=J(e)?e.values[e.values.length-1]:e.value,a=Q(r)?ae(t,n,o,r):ie(t,n,o,r),i=Q(r)?q(a,t,this._currenTime):z(a,t,this._currenTime);this._automationEvents.push(i)}void 0!==e&&ce(e)&&this._automationEvents.push(Y(this.getValue(t),t)),void 0!==e&&J(e)&&e.startTime+e.duration>t&&(this._automationEvents[this._automationEvents.length-1]=Z(new Float32Array([6,7]),e.startTime,t-e.startTime))}}else{const n=this._automationEvents.findIndex(e=>oe(e)>t),r=-1===n?this._automationEvents[this._automationEvents.length-1]:this._automationEvents[n-1];if(void 0!==r&&J(r)&&oe(r)+r.duration>t)return!1;const o=Q(e)?q(e.value,e.endTime,this._currenTime):H(e)?z(e.value,t,this._currenTime):e;if(-1===n)this._automationEvents.push(o);else{if(J(e)&&t+e.duration>oe(this._automationEvents[n]))return!1;this._automationEvents.splice(n,0,o)}}return!0}flush(e){const t=this._automationEvents.findIndex(t=>oe(t)>e);if(t>1){const e=this._automationEvents.slice(t-1),n=e[0];ce(n)&&e.unshift(Y(ee(this._automationEvents,t-2,n.startTime,this._defaultValue),n.startTime)),this._automationEvents=e}}getValue(e){if(0===this._automationEvents.length)return this._defaultValue;const t=this._automationEvents[this._automationEvents.length-1],n=this._automationEvents.findIndex(t=>oe(t)>e),r=this._automationEvents[n],o=oe(t)<=e?t:this._automationEvents[n-1];if(void 0!==o&&ce(o)&&(void 0===r||!$(r)||r.insertTime>e))return U(e,ee(this._automationEvents,n-2,o.startTime,this._defaultValue),o);if(void 0!==o&&K(o)&&(void 0===r||!$(r)))return o.value;if(void 0!==o&&J(o)&&(void 0===r||!$(r)||o.startTime+o.duration>e))return e_e},Ce=/^import(?:(?:[\s]+[\w]+|(?:[\s]+[\w]+[\s]*,)?[\s]*\{[\s]*[\w]+(?:[\s]+as[\s]+[\w]+)?(?:[\s]*,[\s]*[\w]+(?:[\s]+as[\s]+[\w]+)?)*[\s]*}|(?:[\s]+[\w]+[\s]*,)?[\s]*\*[\s]+as[\s]+[\w]+)[\s]+from)?(?:[\s]*)("([^"\\]|\\.)+"|'([^'\\]|\\.)+')(?:[\s]*);?/,be=(e,t)=>{const n=[];let r=e.replace(/^[\s]+/,""),o=r.match(Ce);for(;null!==o;){const e=o[1].slice(1,-1),a=o[0].replace(/([\s]+)?;?$/,"").replace(e,new URL(e,t).toString());n.push(a),r=r.slice(o[0].length).replace(/^[\s]+/,""),o=r.match(Ce)}return[n.join(";"),r]},Te=e=>{if(void 0!==e&&!Array.isArray(e))throw new TypeError("The parameterDescriptors property of given value for processorCtor is not an array.")},Me=e=>{if(!(e=>{try{new new Proxy(e,_e)}catch{return!1}return!0})(e))throw new TypeError("The given value for processorCtor should be a constructor.");if(null===e.prototype||"object"!=typeof e.prototype)throw new TypeError("The given value for processorCtor should have a prototype.")},Ie={channelCount:2,channelCountMode:"max",channelInterpretation:"speakers",fftSize:2048,maxDecibels:-30,minDecibels:-100,smoothingTimeConstant:.8},xe=(e,t)=>e.context===t,Se=e=>{try{e.copyToChannel(new Float32Array(1),0,-1)}catch{return!1}return!0},Ae=()=>{try{return new DOMException("","IndexSizeError")}catch(e){return e.code=1,e.name="IndexSizeError",e}},Ne=e=>{var t;e.getChannelData=(t=e.getChannelData,n=>{try{return t.call(e,n)}catch(e){if(12===e.code)throw Ae();throw e}})},ke={numberOfChannels:1},Oe=-34028234663852886e22,Ee=-Oe,Pe=(e,t)=>{const n=e.get(t);if(void 0===n)throw new Error("A value with the given key could not be found.");return n},De=e=>Pe(ge,e),Re=e=>{if(le.has(e))throw new Error("The AudioNode is already stored.");le.add(e),De(e).forEach(e=>e(!0))},Ve=e=>{if(!le.has(e))throw new Error("The AudioNode is not stored.");le.delete(e),De(e).forEach(e=>e(!1))},Be={buffer:null,channelCount:2,channelCountMode:"max",channelInterpretation:"speakers",loop:!1,loopEnd:0,loopStart:0,playbackRate:1},Fe=e=>"context"in e,Le=e=>Fe(e[0]),We=e=>"port"in e,je=e=>"inputs"in e,Ge=(e,t,n,r)=>{if(je(t)){const o=t.inputs[r];return e.connect(o,n,0),[o,n,0]}return e.connect(t,n,r),[t,n,r]},Xe=(e,t)=>{if(!De(e).delete(t))throw new Error("Missing the expected event listener.")},qe=(e,t,n,r)=>{je(t)?e.disconnect(t.inputs[r],n,0):e.disconnect(t,n,r)},ze=e=>Pe(he,e),Ye=e=>Pe(fe,e),Ze=e=>Pe(de,e),Ue=e=>Pe(pe,e),Qe=(e,t,n,r)=>{for(const t of e)if(n(t)){if(r)return!1;throw Error("The set contains at least one similar element.")}return e.add(t),!0},He=e=>le.has(e),$e=e=>ye.has(e),Ke=e=>!le.has(e),Je=(e,t)=>{const n=Array.from(e).filter(t);if(n.length>1)throw Error("More than one element was found.");if(0===n.length)throw Error("No element was found.");const[r]=n;return e.delete(r),r},et=(e,t)=>{!We(e)&&t.every(e=>0===e.size)&&Ve(e)},tt=e=>new Promise(t=>{const n=e.createScriptProcessor(256,1,1),r=e.createGain(),o=e.createBuffer(1,2,44100),a=o.getChannelData(0);a[0]=1,a[1]=1;const i=e.createBufferSource();i.buffer=o,i.loop=!0,i.connect(n).connect(e.destination),i.connect(r),i.disconnect(r),n.onaudioprocess=r=>{const o=r.inputBuffer.getChannelData(0);Array.prototype.some.call(o,e=>1===e)?t(!0):t(!1),i.stop(),n.onaudioprocess=null,i.disconnect(n),n.disconnect(e.destination)},i.start()}),nt=(e,t)=>{const n=new Map;for(const t of e)for(const e of t){const t=n.get(e);n.set(e,void 0===t?1:t+1)}n.forEach((e,n)=>t(n,e))},rt=e=>"context"in e,ot=e=>{const t=new Map;var n,r;e.connect=(n=e.connect.bind(e),(e,r=0,o=0)=>{const a=rt(e)?n(e,r,o):n(e,r),i=t.get(e);return void 0===i?t.set(e,[{input:o,output:r}]):i.every(e=>e.input!==o||e.output!==r)&&i.push({input:o,output:r}),a}),e.disconnect=(r=e.disconnect,(n,o,a)=>{if(r.apply(e),void 0===n)t.clear();else if("number"==typeof n)for(const[e,r]of t){const o=r.filter(e=>e.output!==n);0===o.length?t.delete(e):t.set(e,o)}else if(t.has(n))if(void 0===o)t.delete(n);else{const e=t.get(n);if(void 0!==e){const r=e.filter(e=>e.output!==o&&(e.input!==a||void 0===a));0===r.length?t.delete(n):t.set(n,r)}}for(const[n,r]of t)r.forEach(t=>{rt(n)?e.connect(n,t.output,t.input):e.connect(n,t.output)})})},at=(e,t,[n,r,o],a)=>{Qe(e[r],[t,n,o],e=>e[0]===t&&e[1]===n,a)},it=(e,t,[n,r],o)=>{Qe(e,[t,n,r],e=>e[0]===t&&e[1]===n,o)},st=(e,t,[n,r,o],a)=>{const i=e.get(n);void 0===i?e.set(n,new Set([[r,t,o]])):Qe(i,[r,t,o],e=>e[0]===r&&e[1]===t,a)},ct=(e,[t,n,r],o)=>{const a=e.get(t);void 0===a?e.set(t,new Set([[n,r]])):Qe(a,[n,r],e=>e[0]===n,o)},ut=(e,t,n,r)=>{const o=Pe(e,t),a=Je(o,e=>e[0]===n&&e[1]===r);return 0===o.size&&e.delete(t),a},lt=(e,t,n)=>{const r=Pe(e,t),o=Je(r,e=>e[0]===n);return 0===r.size&&e.delete(t),o},ht=(e,t,n,r)=>{const{activeInputs:o,passiveInputs:a}=ze(t),{outputs:i}=ze(e),s=De(e),c=i=>{const s=Ze(t),c=Ze(e);if(i){const i=ut(a,e,n,r);at(o,e,i,!1),$e(e)||Ge(c,s,n,r),Ke(t)&&Re(t)}else{const i=((e,t,n,r)=>Je(e[r],e=>e[0]===t&&e[1]===n))(o,e,n,r);st(a,r,i,!1),$e(e)||qe(c,s,n,r),He(t)&&et(t,o)}};return!!Qe(i,[t,n,r],e=>e[0]===t&&e[1]===n&&e[2]===r,!0)&&(s.add(c),He(e)?at(o,e,[n,r,c],!0):st(a,r,[e,n,c],!0),!0)},dt=(e,t,n)=>{const{activeInputs:r,passiveInputs:o}=Ye(t),{outputs:a}=ze(e),i=De(e),s=a=>{const i=Ze(e),s=Ue(t);if(a){const t=lt(o,e,n);it(r,e,t,!1),$e(e)||i.connect(s,n)}else{const t=((e,t,n)=>Je(e,e=>e[0]===t&&e[1]===n))(r,e,n);ct(o,t,!1),$e(e)||i.disconnect(s,n)}};return!!Qe(a,[t,n],e=>e[0]===t&&e[1]===n,!0)&&(i.add(s),He(e)?it(r,e,[n,s],!0):ct(o,[e,n,s],!0),!0)},ft=(e,t,n)=>{for(const r of e)if(r[0]===t&&r[1]===n)return e.delete(r),r;return null},pt=(e,t,n,r)=>{const[o,a]=((e,t,n,r)=>{const{activeInputs:o,passiveInputs:a}=ze(t),i=ft(o[r],e,n);if(null===i)return[ut(a,e,n,r)[2],!1];return[i[2],!0]})(e,t,n,r);if(null!==o&&(Xe(e,o),a&&!$e(e)&&qe(Ze(e),Ze(t),n,r)),He(t)){const{activeInputs:e}=ze(t);et(t,e)}},mt=(e,t,n)=>{const[r,o]=((e,t,n)=>{const{activeInputs:r,passiveInputs:o}=Ye(t),a=ft(r,e,n);if(null===a)return[lt(o,e,n)[1],!1];return[a[2],!0]})(e,t,n);null!==r&&(Xe(e,r),o&&!$e(e)&&Ze(e).disconnect(Ue(t),n))},vt={Q:1,channelCount:2,channelCountMode:"max",channelInterpretation:"speakers",detune:0,frequency:350,gain:0,type:"lowpass"},gt={channelCount:1,channelCountMode:"explicit",channelInterpretation:"speakers",numberOfInputs:6},yt={channelCount:6,channelCountMode:"explicit",channelInterpretation:"discrete",numberOfOutputs:6},wt={channelCount:2,channelCountMode:"max",channelInterpretation:"speakers",offset:1},_t={buffer:null,channelCount:2,channelCountMode:"clamped-max",channelInterpretation:"speakers",disableNormalization:!1},Ct={channelCount:2,channelCountMode:"max",channelInterpretation:"speakers",delayTime:0,maxDelayTime:1},bt={attack:.003,channelCount:2,channelCountMode:"clamped-max",channelInterpretation:"speakers",knee:30,ratio:12,release:.25,threshold:-24},Tt={channelCount:2,channelCountMode:"max",channelInterpretation:"speakers",gain:1},Mt=()=>{try{return new DOMException("","InvalidStateError")}catch(e){return e.code=11,e.name="InvalidStateError",e}},It=()=>{try{return new DOMException("","InvalidAccessError")}catch(e){return e.code=15,e.name="InvalidAccessError",e}},xt={channelCount:2,channelCountMode:"max",channelInterpretation:"speakers"},St=(e,t,n,r,o,a,i,s,c,u,l)=>{const h=u.length;let d=s;for(let s=0;s{const t=new Uint32Array([1179011410,40,1163280727,544501094,16,131073,44100,176400,1048580,1635017060,4,0]);try{const n=e.decodeAudioData(t.buffer,()=>{});return void 0!==n&&(n.catch(()=>{}),!0)}catch{}return!1},kt=(e,t,n)=>{const r=t[n];void 0!==r&&r!==e[n]&&(e[n]=r)},Ot=(e,t)=>{kt(e,t,"channelCount"),kt(e,t,"channelCountMode"),kt(e,t,"channelInterpretation")},Et=e=>"function"==typeof e.getFloatTimeDomainData,Pt=(e,t,n)=>{const r=t[n];void 0!==r&&r!==e[n].value&&(e[n].value=r)},Dt=e=>{var t;e.start=(t=e.start,(n=0,r=0,o)=>{if("number"==typeof o&&o<0||r<0||n<0)throw new RangeError("The parameters can't be negative.");t.call(e,n,r,o)})},Rt=e=>{var t;e.stop=(t=e.stop,(n=0)=>{if(n<0)throw new RangeError("The parameter can't be negative.");t.call(e,n)})},Vt=(e,t)=>(e.connect=t.connect.bind(t),e.disconnect=t.disconnect.bind(t),e);function Bt(e,t){const n=t[0]*t[0]+t[1]*t[1];return[(e[0]*t[0]+e[1]*t[1])/n,(e[1]*t[0]-e[0]*t[1])/n]}function Ft(e,t){let n=[0,0];for(let a=e.length-1;a>=0;a-=1)o=t,n=[(r=n)[0]*o[0]-r[1]*o[1],r[0]*o[1]+r[1]*o[0]],n[0]+=e[a];var r,o;return n}const Lt=()=>{try{return new DOMException("","NotSupportedError")}catch(e){return e.code=9,e.name="NotSupportedError",e}},Wt={channelCount:2,channelCountMode:"max",channelInterpretation:"speakers",detune:0,frequency:440,type:"sine"},jt={channelCount:2,channelCountMode:"clamped-max",channelInterpretation:"speakers",coneInnerAngle:360,coneOuterAngle:360,coneOuterGain:0,distanceModel:"inverse",maxDistance:1e4,orientationX:1,orientationY:0,orientationZ:0,panningModel:"equalpower",positionX:0,positionY:0,positionZ:0,refDistance:1,rolloffFactor:1},Gt={disableNormalization:!1},Xt={channelCount:2,channelCountMode:"explicit",channelInterpretation:"speakers",pan:0},qt={channelCount:2,channelCountMode:"max",channelInterpretation:"speakers",curve:null,oversample:"none"},zt=e=>{if(null===e)return!1;const t=e.length;return t%2!=0?0!==e[Math.floor(t/2)]:e[t/2-1]+e[t/2]!==0},Yt=(e,t,n,r)=>{let o=Object.getPrototypeOf(e);for(;!o.hasOwnProperty(t);)o=Object.getPrototypeOf(o);const{get:a,set:i}=Object.getOwnPropertyDescriptor(o,t);Object.defineProperty(e,t,{get:n(a),set:r(i)})},Zt=(e,t)=>n=>{const r={value:e};return Object.defineProperties(n,{currentTarget:r,target:r}),"function"==typeof t?t.call(e,n):t.handleEvent.call(e,n)},Ut=(Qt=new Map,Ht=new WeakMap,(e,t)=>{const n=Ht.get(e);if(void 0!==n)return n;const r=Qt.get(e);if(void 0!==r)return r;try{const n=t();return n instanceof Promise?(Qt.set(e,n),n.catch(()=>!1).then(t=>(Qt.delete(e),Ht.set(e,t),t))):(Ht.set(e,n),n)}catch{return Ht.set(e,!1),!1}});var Qt,Ht;const $t="undefined"==typeof window?null:window,Kt=(e=>null===e?null:e.hasOwnProperty("OfflineAudioContext")?e.OfflineAudioContext:e.hasOwnProperty("webkitOfflineAudioContext")?e.webkitOfflineAudioContext:null)($t),Jt=(e=>t=>null!==e&&t instanceof e)(Kt),en=(e=>null===e?null:e.hasOwnProperty("AudioContext")?e.AudioContext:e.hasOwnProperty("webkitAudioContext")?e.webkitAudioContext:null)($t),tn=((e,t,n)=>r=>{if("closed"===r.state&&null!==t&&"webkitAudioContext"!==t.name){if(!e(r)){const e=me.get(r);if(void 0!==e)return e;const n=new t;return me.set(r,n),n}{const e=me.get(r);if(void 0!==e)return e;if(null!==n){const e=new n(1,1,44100);return me.set(r,e),e}}}return null})(Jt,en,Kt),nn=(e=>(t,n)=>{const r=e(t);return n(null!==r?r:t)})(tn),rn=((e,t,n)=>(r,o)=>{const a=n(r,e=>e.createAnalyser());if(Ot(a,o),!(o.maxDecibels>o.minDecibels))throw t();return kt(a,o,"fftSize"),kt(a,o,"maxDecibels"),kt(a,o,"minDecibels"),kt(a,o,"smoothingTimeConstant"),e(Et,()=>Et(a))||(e=>{e.getFloatTimeDomainData=t=>{const n=new Uint8Array(t.length);e.getByteTimeDomainData(n);const r=Math.max(n.length,e.fftSize);for(let e=0;et=>{const n=e(t);if(null===n.renderer)throw new Error("Missing the renderer of the given AudioNode in the audio graph.");return n.renderer})(ze),an=((e,t,n)=>async(r,o,a,i)=>{const s=e(r),c=[...i,r];await Promise.all(s.activeInputs.map((e,i)=>Array.from(e).filter(([e])=>!c.includes(e)).map(async([e,s])=>{const u=t(e),l=await u.render(e,o,c),h=r.context.destination;n(e)||r===h&&n(r)||l.connect(a,s,i)})).reduce((e,t)=>[...e,...t],[]))})(ze,on,$e),sn=((e,t,n)=>()=>{const r=new WeakMap;return{render(o,a,i){const s=r.get(a);return void 0!==s?Promise.resolve(s):(async(o,a,i)=>{let s=t(o);if(!xe(s,a)){const t={channelCount:s.channelCount,channelCountMode:s.channelCountMode,channelInterpretation:s.channelInterpretation,fftSize:s.fftSize,maxDecibels:s.maxDecibels,minDecibels:s.minDecibels,smoothingTimeConstant:s.smoothingTimeConstant};s=e(a,t)}return r.set(a,s),await n(o,a,s,i),s})(o,a,i)}}})(rn,Ze,an),cn=new WeakMap,un=(ln=ve,e=>{const t=ln.get(e);if(void 0===t)throw Mt();return t});var ln;const hn=new WeakMap,dn=(e=>class{constructor(e){this._nativeEventTarget=e,this._listeners=new WeakMap}addEventListener(t,n,r){if(null!==n){let o=this._listeners.get(n);void 0===o&&(o=e(this,n),"function"==typeof n&&this._listeners.set(n,o)),this._nativeEventTarget.addEventListener(t,o,r)}}dispatchEvent(e){return this._nativeEventTarget.dispatchEvent(e)}removeEventListener(e,t,n){const r=null===t?void 0:this._listeners.get(t);this._nativeEventTarget.removeEventListener(e,void 0===r?null:r,n)}})(Zt),fn=(e=>t=>null!==e&&t instanceof e)(en),pn=(e=>t=>null!==e&&"function"==typeof e.AudioNode&&t instanceof e.AudioNode)($t),mn=(e=>t=>null!==e&&"function"==typeof e.AudioParam&&t instanceof e.AudioParam)($t),vn=((e,t,n,r,o,a,i,s,c,u,l,h,d,f,p)=>class extends u{constructor(t,r,o,a){super(o),this._context=t,this._nativeAudioNode=o;const i=l(t);h(i)&&!0!==n(tt,()=>tt(i))&&ot(o),de.set(this,o),ge.set(this,new Set),r&&Re(this),e(this,a,o)}get channelCount(){return this._nativeAudioNode.channelCount}set channelCount(e){this._nativeAudioNode.channelCount=e}get channelCountMode(){return this._nativeAudioNode.channelCountMode}set channelCountMode(e){this._nativeAudioNode.channelCountMode=e}get channelInterpretation(){return this._nativeAudioNode.channelInterpretation}set channelInterpretation(e){this._nativeAudioNode.channelInterpretation=e}get context(){return this._context}get numberOfInputs(){return this._nativeAudioNode.numberOfInputs}get numberOfOutputs(){return this._nativeAudioNode.numberOfOutputs}connect(e,n=0,s=0){if(n<0||n>=this._nativeAudioNode.numberOfOutputs)throw o();const u=l(this._context),h=p(u);if(d(e)||f(e))throw a();if(Fe(e)){const o=Ze(e);try{const r=Ge(this._nativeAudioNode,o,n,s);if(h||Ke(this)?this._nativeAudioNode.disconnect(...r):Ke(e)&&Re(e),We(e)){const e=t.get(o);if(void 0===e){const e=u.createGain();e.connect(r[0],0,r[2]),t.set(o,new Map([[s,e]]))}else if(void 0===e.get(s)){const t=u.createGain();t.connect(r[0],0,r[2]),e.set(s,t)}}}catch(e){if(12===e.code)throw a();throw e}if(h?((e,t,n,r)=>{const{outputs:o}=ze(e);if(Qe(o,[t,n,r],e=>e[0]===t&&e[1]===n&&e[2]===r,!0)){const{activeInputs:o}=ze(t);return at(o,e,[n,r,null],!0),!0}return!1})(this,e,n,s):ht(this,e,n,s)){const t=c([this],e);nt(t,r(h))}return e}const m=Ue(e);if("playbackRate"===m.name)throw i();try{this._nativeAudioNode.connect(m,n),(h||Ke(this))&&this._nativeAudioNode.disconnect(m,n)}catch(e){if(12===e.code)throw a();throw e}if(h?((e,t,n)=>{const{outputs:r}=ze(e);if(Qe(r,[t,n],e=>e[0]===t&&e[1]===n,!0)){const{activeInputs:r}=Ye(t);return it(r,e,[n,null],!0),!0}return!1})(this,e,n):dt(this,e,n)){const t=c([this],e);nt(t,r(h))}}disconnect(e,t,n){let r;if(void 0===e)r=(e=>{const t=ze(e),n=[];for(const r of t.outputs)Le(r)?pt(e,...r):mt(e,...r),n.push(r[0]);return t.outputs.clear(),n})(this);else if("number"==typeof e){if(e<0||e>=this.numberOfOutputs)throw o();r=((e,t)=>{const n=ze(e),r=[];for(const o of n.outputs)o[1]===t&&(Le(o)?pt(e,...o):mt(e,...o),r.push(o[0]),n.outputs.delete(o));return r})(this,e)}else{if(void 0!==t&&(t<0||t>=this.numberOfOutputs))throw o();if(Fe(e)&&void 0!==n&&(n<0||n>=e.numberOfInputs))throw o();if(r=((e,t,n,r)=>{const o=ze(e);return Array.from(o.outputs).filter(e=>!(e[0]!==t||void 0!==n&&e[1]!==n||void 0!==r&&e[2]!==r)).map(t=>(Le(t)?pt(e,...t):mt(e,...t),o.outputs.delete(t),t[0]))})(this,e,t,n),0===r.length)throw a()}for(const e of r){const t=c([this],e);nt(t,s)}}})((gn=he,(e,t,n)=>{const r=[];for(let e=0;ei=>(s,c)=>{const u=e.get(s);if(void 0===u){if(!i&&a(s)){const e=r(s),{outputs:a}=n(s);for(const n of a)if(Le(n)){const o=r(n[0]);t(e,o,n[1],n[2])}else{const t=o(n[0]);e.disconnect(t,n[1])}}e.set(s,c)}else e.set(s,u+c)})(ye,qe,ze,Ze,Ue,He),Ae,It,Lt,((e,t,n,r,o,a,i,s)=>(c,u)=>{const l=t.get(c);if(void 0===l)throw new Error("Missing the expected cycle count.");const h=a(c.context),d=s(h);if(l===u){if(t.delete(c),!d&&i(c)){const t=r(c),{outputs:a}=n(c);for(const n of a)if(Le(n)){const o=r(n[0]);e(t,o,n[1],n[2])}else{const e=o(n[0]);t.connect(e,n[1])}}}else t.set(c,l-u)})(Ge,ye,ze,Ze,Ue,un,He,Jt),((e,t,n)=>function r(o,a){const i=Fe(a)?a:n(e,a);if((e=>"delayTime"in e)(i))return[];if(o[0]===i)return[o];if(o.includes(i))return[];const{outputs:s}=t(i);return Array.from(s).map(e=>r([...o,i],e[0])).reduce((e,t)=>e.concat(t),[])})(hn,ze,Pe),dn,un,fn,pn,mn,Jt);var gn;const yn=((e,t,n,r,o,a)=>class extends e{constructor(e,n=Ie){const i=o(e),s={...Ie,...n},c=r(i,s);super(e,!1,c,a(i)?t():null),this._nativeAnalyserNode=c}get fftSize(){return this._nativeAnalyserNode.fftSize}set fftSize(e){this._nativeAnalyserNode.fftSize=e}get frequencyBinCount(){return this._nativeAnalyserNode.frequencyBinCount}get maxDecibels(){return this._nativeAnalyserNode.maxDecibels}set maxDecibels(e){const t=this._nativeAnalyserNode.maxDecibels;if(this._nativeAnalyserNode.maxDecibels=e,!(e>this._nativeAnalyserNode.minDecibels))throw this._nativeAnalyserNode.maxDecibels=t,n()}get minDecibels(){return this._nativeAnalyserNode.minDecibels}set minDecibels(e){const t=this._nativeAnalyserNode.minDecibels;if(this._nativeAnalyserNode.minDecibels=e,!(this._nativeAnalyserNode.maxDecibels>e))throw this._nativeAnalyserNode.minDecibels=t,n()}get smoothingTimeConstant(){return this._nativeAnalyserNode.smoothingTimeConstant}set smoothingTimeConstant(e){this._nativeAnalyserNode.smoothingTimeConstant=e}getByteFrequencyData(e){this._nativeAnalyserNode.getByteFrequencyData(e)}getByteTimeDomainData(e){this._nativeAnalyserNode.getByteTimeDomainData(e)}getFloatFrequencyData(e){this._nativeAnalyserNode.getFloatFrequencyData(e)}getFloatTimeDomainData(e){this._nativeAnalyserNode.getFloatTimeDomainData(e)}})(vn,sn,Ae,rn,un,Jt),wn=new WeakSet,_n=(e=>null===e?null:e.hasOwnProperty("AudioBuffer")?e.AudioBuffer:null)($t),Cn=(bn=new Uint32Array(1),e=>(bn[0]=e,bn[0]));var bn;const Tn=((e,t)=>n=>{n.copyFromChannel=(r,o,a=0)=>{const i=e(a),s=e(o);if(s>=n.numberOfChannels)throw t();const c=n.length,u=n.getChannelData(s),l=r.length;for(let e=i<0?-i:0;e+i{const i=e(a),s=e(o);if(s>=n.numberOfChannels)throw t();const c=n.length,u=n.getChannelData(s),l=r.length;for(let e=i<0?-i:0;e+it=>{var n,r;t.copyFromChannel=(n=t.copyFromChannel,(r,o,a=0)=>{const i=e(a),s=e(o);if(i{const i=e(a),s=e(o);if(i{let c=null;return class u{constructor(u){if(null===o)throw new Error("Missing the native OfflineAudioContext constructor.");const{length:l,numberOfChannels:h,sampleRate:d}={...ke,...u};null===c&&(c=new o(1,1,44100));const f=null!==r&&t(a,a)?new r({length:l,numberOfChannels:h,sampleRate:d}):c.createBuffer(h,l,d);if(0===f.numberOfChannels)throw n();return"function"!=typeof f.copyFromChannel?(i(f),Ne(f)):t(Se,()=>Se(f))||s(f),e.add(f),f}static[Symbol.hasInstance](t){return null!==t&&"object"==typeof t&&Object.getPrototypeOf(t)===u.prototype||e.has(t)}}})(wn,Ut,Lt,_n,Kt,(e=>()=>{if(null===e)return!1;try{new e({length:1,sampleRate:44100})}catch{return!1}return!0})(_n),Tn,Mn),xn=(e=>(t,n)=>{const r=e(t,e=>e.createGain());return Ot(r,n),Pt(r,n,"gain"),r})(nn),Sn=(e=>(t,n)=>{const r=e(t,{channelCount:1,channelCountMode:"explicit",channelInterpretation:"discrete",gain:0});n.connect(r).connect(r.context.destination);const o=()=>{n.removeEventListener("ended",o),n.disconnect(r),r.disconnect()};n.addEventListener("ended",o)})(xn),An=(e=>t=>{const n=e(t,e=>e.createOscillator());try{n.start(-1)}catch(e){return e instanceof RangeError}return!1})(nn),Nn=(e=>t=>{const n=t.createBuffer(1,1,44100),r=e(t,e=>e.createBufferSource());r.buffer=n,r.start(),r.stop();try{return r.stop(),!0}catch{return!1}})(nn),kn=(e=>t=>{const n=e(t,e=>e.createOscillator());try{n.stop(-1)}catch(e){return e instanceof RangeError}return!1})(nn),On=(e=>(t,n)=>{const r=e(n,e=>e.createGain());t.connect(r);const o=(a=t.disconnect,()=>{a.call(t,r),t.removeEventListener("ended",o)});var a;t.addEventListener("ended",o),Vt(t,r),t.stop=(e=>{let n=!1;return(o=0)=>{if(n)try{e.call(t,o)}catch{r.gain.setValueAtTime(0,o)}else e.call(t,o),n=!0}})(t.stop)})(nn),En=((e,t,n)=>async(r,o,a,i)=>{const s=t(r);await Promise.all(Array.from(s.activeInputs).map(async([t,r])=>{const s=e(t),c=await s.render(t,o,i);n(t)||c.connect(a,r)}))})(on,Ye,$e),Pn=(e=>(t,n,r,o)=>e(n,t,r,o))(En),Dn=((e,t,n,r,o,a,i,s,c,u,l,h,d)=>(f,p)=>{const m=n(f,e=>e.createBufferSource());return Ot(m,p),Pt(m,p,"playbackRate"),kt(m,p,"buffer"),kt(m,p,"loop"),kt(m,p,"loopEnd"),kt(m,p,"loopStart"),t(r,()=>r(f))||(e=>{e.start=(t=>{let n=!1;return(r=0,o=0,a)=>{if(n)throw Mt();t.call(e,r,o,a),n=!0}})(e.start)})(m),t(o,o)||((e,t)=>{let n=Number.POSITIVE_INFINITY,r=Number.POSITIVE_INFINITY;var o,a;e.start=(o=e.start,a=e.stop,(i=0,s=0,c=Number.POSITIVE_INFINITY)=>{if(o.call(e,i,s),c>=0&&c(a=0)=>{r=Math.max(a,t.currentTime),o.call(e,Math.min(n,r))})(e.stop)})(m,f),t(a,()=>a(f))||l(m),t(i,()=>i(f))||h(m,f),t(s,()=>s(f))||Dt(m),t(c,()=>c(f))||d(m,f),t(u,()=>u(f))||Rt(m),e(f,m),m})(Sn,Ut,nn,(e=>t=>{const n=e(t,e=>e.createBufferSource());n.start();try{n.start()}catch{return!0}return!1})(nn),(e=>()=>{if(null===e)return Promise.resolve(!1);const t=new e(1,1,44100),n=t.createBuffer(1,1,t.sampleRate),r=t.createBufferSource();return n.getChannelData(0)[0]=1,r.buffer=n,r.start(0,0,0),r.connect(t.destination),new Promise(e=>{t.oncomplete=({renderedBuffer:t})=>{e(0===t.getChannelData(0)[0])},t.startRendering()})})(Kt),(e=>t=>{const n=e(t,e=>e.createBufferSource()),r=t.createBuffer(1,1,44100);n.buffer=r;try{n.start(0,1)}catch{return!1}return!0})(nn),(e=>t=>{const n=e(t,e=>e.createBufferSource());n.start();try{n.stop()}catch{return!1}return!0})(nn),An,Nn,kn,e=>{var t;e.start=(t=e.start,(n=0,r=0,o)=>{const a=e.buffer,i=null===a?r:Math.min(a.duration,r);null!==a&&i>a.duration-.5/e.context.sampleRate?t.call(e,n,0,0):t.call(e,n,i,o)})},(e=>(t,n)=>{const r=n.createBuffer(1,1,n.sampleRate);null===t.buffer&&(t.buffer=r),e(t,"buffer",e=>()=>{const n=e.call(t);return n===r?null:n},e=>n=>e.call(t,null===n?r:n))})(Yt),On),Rn=((e,t)=>(n,r,o,a)=>(e(r).replay(o),t(r,n,o,a)))((e=>t=>{const n=e(t);if(null===n.renderer)throw new Error("Missing the renderer of the given AudioParam in the audio graph.");return n.renderer})(Ye),En),Vn=((e,t,n,r,o)=>()=>{const a=new WeakMap;let i=null,s=null;return{set start(e){i=e},set stop(e){s=e},render(c,u,l){const h=a.get(u);return void 0!==h?Promise.resolve(h):(async(c,u,l)=>{let h=n(c);const d=xe(h,u);if(!d){const e={buffer:h.buffer,channelCount:h.channelCount,channelCountMode:h.channelCountMode,channelInterpretation:h.channelInterpretation,loop:h.loop,loopEnd:h.loopEnd,loopStart:h.loopStart,playbackRate:h.playbackRate.value};h=t(u,e),null!==i&&h.start(...i),null!==s&&h.stop(s)}return a.set(u,h),d?await e(u,c.playbackRate,h.playbackRate,l):await r(u,c.playbackRate,h.playbackRate,l),await o(c,u,h,l),h})(c,u,l)}}})(Pn,Dn,Ze,Rn,an),Bn=((e,t,n,r,o,a,i,s,c,u,l,h)=>(d,f,p,m=null,v=null)=>{const g=new ue(p.defaultValue),y=f?r(g):null,w={get defaultValue(){return p.defaultValue},get maxValue(){return null===m?p.maxValue:m},get minValue(){return null===v?p.minValue:v},get value(){return p.value},set value(e){p.value=e,w.setValueAtTime(e,d.context.currentTime)},cancelAndHoldAtTime(e){if("function"==typeof p.cancelAndHoldAtTime)null===y&&g.flush(d.context.currentTime),g.add(o(e)),p.cancelAndHoldAtTime(e);else{const t=Array.from(g).pop();null===y&&g.flush(d.context.currentTime),g.add(o(e));const n=Array.from(g).pop();p.cancelScheduledValues(e),t!==n&&void 0!==n&&("exponentialRampToValue"===n.type?p.exponentialRampToValueAtTime(n.value,n.endTime):"linearRampToValue"===n.type?p.linearRampToValueAtTime(n.value,n.endTime):"setValue"===n.type?p.setValueAtTime(n.value,n.startTime):"setValueCurve"===n.type&&p.setValueCurveAtTime(n.values,n.startTime,n.duration))}return w},cancelScheduledValues:e=>(null===y&&g.flush(d.context.currentTime),g.add(a(e)),p.cancelScheduledValues(e),w),exponentialRampToValueAtTime:(e,t)=>(null===y&&g.flush(d.context.currentTime),g.add(i(e,t)),p.exponentialRampToValueAtTime(e,t),w),linearRampToValueAtTime:(e,t)=>(null===y&&g.flush(d.context.currentTime),g.add(s(e,t)),p.linearRampToValueAtTime(e,t),w),setTargetAtTime:(e,t,n)=>(null===y&&g.flush(d.context.currentTime),g.add(c(e,t,n)),p.setTargetAtTime(e,t,n),w),setValueAtTime:(e,t)=>(null===y&&g.flush(d.context.currentTime),g.add(u(e,t)),p.setValueAtTime(e,t),w),setValueCurveAtTime(e,t,n){if(null!==h&&"webkitAudioContext"===h.name){const r=t+n,o=d.context.sampleRate,a=Math.ceil(t*o),i=Math.floor(r*o),s=i-a,c=new Float32Array(s);for(let r=0;r{Fn.set(e,{activeInputs:new Set,passiveInputs:new WeakMap,renderer:t})}),hn,pe,e=>({replay(t){for(const n of e)if("exponentialRampToValue"===n.type){const{endTime:e,value:r}=n;t.exponentialRampToValueAtTime(r,e)}else if("linearRampToValue"===n.type){const{endTime:e,value:r}=n;t.linearRampToValueAtTime(r,e)}else if("setTarget"===n.type){const{startTime:e,target:r,timeConstant:o}=n;t.setTargetAtTime(r,e,o)}else if("setValue"===n.type){const{startTime:e,value:r}=n;t.setValueAtTime(r,e)}else{if("setValueCurve"!==n.type)throw new Error("Can't apply an unknown automation.");{const{duration:e,startTime:r,values:o}=n;t.setValueCurveAtTime(o,r,e)}}}}),e=>({cancelTime:e,type:"cancelAndHold"}),e=>({cancelTime:e,type:"cancelScheduledValues"}),(e,t)=>({endTime:t,type:"exponentialRampToValue",value:e}),(e,t)=>({endTime:t,type:"linearRampToValue",value:e}),(e,t,n)=>({startTime:t,target:e,timeConstant:n,type:"setTarget"}),Y,Z,en);var Fn;const Ln=((e,t,n,r,o,a,i,s)=>class extends e{constructor(e,r=Be){const s=a(e),c={...Be,...r},u=o(s,c),l=i(s),h=l?t():null;super(e,!1,u,h),this._audioBufferSourceNodeRenderer=h,this._isBufferNullified=!1,this._isBufferSet=null!==r.buffer&&void 0!==r.buffer,this._nativeAudioBufferSourceNode=u,this._onended=null,this._playbackRate=n(this,l,u.playbackRate,Ee,Oe)}get buffer(){return this._isBufferNullified?null:this._nativeAudioBufferSourceNode.buffer}set buffer(e){try{this._nativeAudioBufferSourceNode.buffer=e}catch(t){if(null!==e||17!==t.code)throw t;if(null!==this._nativeAudioBufferSourceNode.buffer){const e=this._nativeAudioBufferSourceNode.buffer,t=e.numberOfChannels;for(let n=0;n{this._nativeAudioBufferSourceNode.removeEventListener("ended",e),setTimeout(()=>Ve(this),1e3)};this._nativeAudioBufferSourceNode.addEventListener("ended",e)}}stop(e=0){this._nativeAudioBufferSourceNode.stop(e),null!==this._audioBufferSourceNodeRenderer&&(this._audioBufferSourceNodeRenderer.stop=e)}})(vn,Vn,Bn,Mt,Dn,un,Jt,Zt),Wn=((e,t,n,r,o,a,i,s)=>class extends e{constructor(e,n){const r=a(e),c=i(r),u=o(r,n,c);super(e,!1,u,c?t(s):null),this._isNodeOfNativeOfflineAudioContext=c,this._nativeAudioDestinationNode=u}get channelCount(){return this._nativeAudioDestinationNode.channelCount}set channelCount(e){if(this._isNodeOfNativeOfflineAudioContext)throw r();if(e>this._nativeAudioDestinationNode.maxChannelCount)throw n();this._nativeAudioDestinationNode.channelCount=e}get channelCountMode(){return this._nativeAudioDestinationNode.channelCountMode}set channelCountMode(e){if(this._isNodeOfNativeOfflineAudioContext)throw r();this._nativeAudioDestinationNode.channelCountMode=e}get maxChannelCount(){return this._nativeAudioDestinationNode.maxChannelCount}})(vn,e=>{let t=null;return{render:(n,r,o)=>(null===t&&(t=(async(t,n,r)=>{const o=n.destination;return await e(t,n,o,r),o})(n,r,o)),t)}},Ae,Mt,((e,t)=>(n,r,o)=>{const a=n.destination;if(a.channelCount!==r)try{a.channelCount=r}catch{}o&&"explicit"!==a.channelCountMode&&(a.channelCountMode="explicit"),0===a.maxChannelCount&&Object.defineProperty(a,"maxChannelCount",{value:r});const i=e(n,{channelCount:r,channelCountMode:a.channelCountMode,channelInterpretation:a.channelInterpretation,gain:1});return t(i,"channelCount",e=>()=>e.call(i),e=>t=>{e.call(i,t);try{a.channelCount=t}catch(e){if(t>a.maxChannelCount)throw e}}),t(i,"channelCountMode",e=>()=>e.call(i),e=>t=>{e.call(i,t),a.channelCountMode=t}),t(i,"channelInterpretation",e=>()=>e.call(i),e=>t=>{e.call(i,t),a.channelInterpretation=t}),Object.defineProperty(i,"maxChannelCount",{get:()=>a.maxChannelCount}),i.connect(a),i})(xn,Yt),un,Jt,an),jn=(e=>(t,n)=>{const r=e(t,e=>e.createBiquadFilter());return Ot(r,n),Pt(r,n,"Q"),Pt(r,n,"detune"),Pt(r,n,"frequency"),Pt(r,n,"gain"),kt(r,n,"type"),r})(nn),Gn=((e,t,n,r,o,a,i)=>class extends e{constructor(e,r=vt){const s=a(e),c={...vt,...r},u=o(s,c),l=i(s);super(e,!1,u,l?n():null),this._Q=t(this,l,u.Q,Ee,Oe),this._detune=t(this,l,u.detune,1200*Math.log2(Ee),-1200*Math.log2(Ee)),this._frequency=t(this,l,u.frequency,e.sampleRate/2,0),this._gain=t(this,l,u.gain,40*Math.log10(Ee),Oe),this._nativeBiquadFilterNode=u}get detune(){return this._detune}get frequency(){return this._frequency}get gain(){return this._gain}get Q(){return this._Q}get type(){return this._nativeBiquadFilterNode.type}set type(e){this._nativeBiquadFilterNode.type=e}getFrequencyResponse(e,t,n){if(this._nativeBiquadFilterNode.getFrequencyResponse(e,t,n),e.length!==t.length||t.length!==n.length)throw r()}})(vn,Bn,((e,t,n,r,o)=>()=>{const a=new WeakMap;return{render(i,s,c){const u=a.get(s);return void 0!==u?Promise.resolve(u):(async(i,s,c)=>{let u=n(i);const l=xe(u,s);if(!l){const e={Q:u.Q.value,channelCount:u.channelCount,channelCountMode:u.channelCountMode,channelInterpretation:u.channelInterpretation,detune:u.detune.value,frequency:u.frequency.value,gain:u.gain.value,type:u.type};u=t(s,e)}return a.set(s,u),l?(await e(s,i.Q,u.Q,c),await e(s,i.detune,u.detune,c),await e(s,i.frequency,u.frequency,c),await e(s,i.gain,u.gain,c)):(await r(s,i.Q,u.Q,c),await r(s,i.detune,u.detune,c),await r(s,i.frequency,u.frequency,c),await r(s,i.gain,u.gain,c)),await o(i,s,u,c),u})(i,s,c)}}})(Pn,jn,Ze,Rn,an),It,jn,un,Jt),Xn=((e,t)=>(n,r,o)=>{const a=new Set;var i,s;return n.connect=(i=n.connect,(o,s=0,c=0)=>{const u=0===a.size;if(t(o))return i.call(n,o,s,c),e(a,[o,s,c],e=>e[0]===o&&e[1]===s&&e[2]===c,!0),u&&r(),o;i.call(n,o,s),e(a,[o,s],e=>e[0]===o&&e[1]===s,!0),u&&r()}),n.disconnect=(s=n.disconnect,(e,r,i)=>{const c=a.size>0;if(void 0===e)s.apply(n),a.clear();else if("number"==typeof e){s.call(n,e);for(const t of a)t[1]===e&&a.delete(t)}else{t(e)?s.call(n,e,r,i):s.call(n,e,r);for(const t of a)t[0]!==e||void 0!==r&&t[1]!==r||void 0!==i&&t[2]!==i||a.delete(t)}const u=0===a.size;c&&u&&o()}),n})(Qe,pn),qn=((e,t,n)=>(r,o)=>{o.channelCount=1,o.channelCountMode="explicit",Object.defineProperty(o,"channelCount",{get:()=>1,set:()=>{throw e()}}),Object.defineProperty(o,"channelCountMode",{get:()=>"explicit",set:()=>{throw e()}});const a=t(r,e=>e.createBufferSource());n(o,()=>{const e=o.numberOfInputs;for(let t=0;ta.disconnect(o))})(Mt,nn,Xn),zn=((e,t)=>(n,r)=>{const o=e(n,e=>e.createChannelMerger(r.numberOfInputs));return 1!==o.channelCount&&"explicit"!==o.channelCountMode&&t(n,o),Ot(o,r),o})(nn,qn),Yn=((e,t,n,r,o)=>class extends e{constructor(e,a=gt){const i=r(e),s={...gt,...a};super(e,!1,n(i,s),o(i)?t():null)}})(vn,((e,t,n)=>()=>{const r=new WeakMap;return{render(o,a,i){const s=r.get(a);return void 0!==s?Promise.resolve(s):(async(o,a,i)=>{let s=t(o);if(!xe(s,a)){const t={channelCount:s.channelCount,channelCountMode:s.channelCountMode,channelInterpretation:s.channelInterpretation,numberOfInputs:s.numberOfInputs};s=e(a,t)}return r.set(a,s),await n(o,a,s,i),s})(o,a,i)}}})(zn,Ze,an),zn,un,Jt),Zn=(e=>(t,n)=>{const r=e(t,e=>e.createChannelSplitter(n.numberOfOutputs));return Ot(r,n),(e=>{const t=e.numberOfOutputs;Object.defineProperty(e,"channelCount",{get:()=>t,set:e=>{if(e!==t)throw Mt()}}),Object.defineProperty(e,"channelCountMode",{get:()=>"explicit",set:e=>{if("explicit"!==e)throw Mt()}}),Object.defineProperty(e,"channelInterpretation",{get:()=>"discrete",set:e=>{if("discrete"!==e)throw Mt()}})})(r),r})(nn),Un=((e,t,n,r,o)=>class extends e{constructor(e,a=yt){const i=r(e),s=(e=>({...e,channelCount:e.numberOfOutputs}))({...yt,...a});super(e,!1,n(i,s),o(i)?t():null)}})(vn,((e,t,n)=>()=>{const r=new WeakMap;return{render(o,a,i){const s=r.get(a);return void 0!==s?Promise.resolve(s):(async(o,a,i)=>{let s=t(o);if(!xe(s,a)){const t={channelCount:s.channelCount,channelCountMode:s.channelCountMode,channelInterpretation:s.channelInterpretation,numberOfOutputs:s.numberOfOutputs};s=e(a,t)}return r.set(a,s),await n(o,a,s,i),s})(o,a,i)}}})(Zn,Ze,an),Zn,un,Jt),Qn=((e,t,n,r)=>(o,{offset:a,...i})=>{const s=o.createBuffer(1,2,o.sampleRate),c=t(o,{buffer:null,channelCount:2,channelCountMode:"max",channelInterpretation:"speakers",loop:!1,loopEnd:0,loopStart:0,playbackRate:1}),u=n(o,{...i,gain:a}),l=s.getChannelData(0);l[0]=1,l[1]=1,c.buffer=s,c.loop=!0;const h={get bufferSize(){},get channelCount(){return u.channelCount},set channelCount(e){u.channelCount=e},get channelCountMode(){return u.channelCountMode},set channelCountMode(e){u.channelCountMode=e},get channelInterpretation(){return u.channelInterpretation},set channelInterpretation(e){u.channelInterpretation=e},get context(){return u.context},get inputs(){return[]},get numberOfInputs(){return c.numberOfInputs},get numberOfOutputs(){return u.numberOfOutputs},get offset(){return u.gain},get onended(){return c.onended},set onended(e){c.onended=e},addEventListener:(...e)=>c.addEventListener(e[0],e[1],e[2]),dispatchEvent:(...e)=>c.dispatchEvent(e[0]),removeEventListener:(...e)=>c.removeEventListener(e[0],e[1],e[2]),start(e=0){c.start.call(c,e)},stop(e=0){c.stop.call(c,e)}};return e(o,c),r(Vt(h,u),()=>c.connect(u),()=>c.disconnect(u))})(Sn,Dn,xn,Xn),Hn=((e,t,n,r,o,a)=>(i,s)=>{if(void 0===i.createConstantSource)return r(i,s);const c=n(i,e=>e.createConstantSource());return Ot(c,s),Pt(c,s,"offset"),t(o,()=>o(i))||Dt(c),t(a,()=>a(i))||Rt(c),e(i,c),c})(Sn,Ut,nn,Qn,An,kn),$n=((e,t,n,r,o,a,i)=>class extends e{constructor(e,i=wt){const s=o(e),c={...wt,...i},u=r(s,c),l=a(s),h=l?n():null;super(e,!1,u,h),this._constantSourceNodeRenderer=h,this._nativeConstantSourceNode=u,this._offset=t(this,l,u.offset,Ee,Oe),this._onended=null}get offset(){return this._offset}get onended(){return this._onended}set onended(e){const t="function"==typeof e?i(this,e):null;this._nativeConstantSourceNode.onended=t;const n=this._nativeConstantSourceNode.onended;this._onended=null!==n&&n===t?e:n}start(e=0){if(this._nativeConstantSourceNode.start(e),null!==this._constantSourceNodeRenderer)this._constantSourceNodeRenderer.start=e;else{Re(this);const e=()=>{this._nativeConstantSourceNode.removeEventListener("ended",e),setTimeout(()=>Ve(this),1e3)};this._nativeConstantSourceNode.addEventListener("ended",e)}}stop(e=0){this._nativeConstantSourceNode.stop(e),null!==this._constantSourceNodeRenderer&&(this._constantSourceNodeRenderer.stop=e)}})(vn,Bn,((e,t,n,r,o)=>()=>{const a=new WeakMap;let i=null,s=null;return{set start(e){i=e},set stop(e){s=e},render(c,u,l){const h=a.get(u);return void 0!==h?Promise.resolve(h):(async(c,u,l)=>{let h=n(c);const d=xe(h,u);if(!d){const e={channelCount:h.channelCount,channelCountMode:h.channelCountMode,channelInterpretation:h.channelInterpretation,offset:h.offset.value};h=t(u,e),null!==i&&h.start(i),null!==s&&h.stop(s)}return a.set(u,h),d?await e(u,c.offset,h.offset,l):await r(u,c.offset,h.offset,l),await o(c,u,h,l),h})(c,u,l)}}})(Pn,Hn,Ze,Rn,an),Hn,un,Jt,Zt),Kn=((e,t,n)=>(r,{buffer:o,channelCount:a,channelCountMode:i,channelInterpretation:s,disableNormalization:c})=>{const u=e(r,e=>e.createConvolver());Ot(u,{channelCount:Math.max(a,2),channelCountMode:"max"===i?i:"clamped-max",channelInterpretation:s});const l=t(r,{channelCount:a,channelCountMode:i,channelInterpretation:s,gain:1}),h={get buffer(){return u.buffer},set buffer(e){u.buffer=e},get bufferSize(){},get channelCount(){return l.channelCount},set channelCount(e){e>2&&(u.channelCount=e),l.channelCount=e},get channelCountMode(){return l.channelCountMode},set channelCountMode(e){"max"===e&&(u.channelCountMode=e),l.channelCountMode=e},get channelInterpretation(){return u.channelInterpretation},set channelInterpretation(e){u.channelInterpretation=e,l.channelInterpretation=e},get context(){return u.context},get inputs(){return[u]},get numberOfInputs(){return u.numberOfInputs},get numberOfOutputs(){return u.numberOfOutputs},get normalize(){return u.normalize},set normalize(e){u.normalize=e},addEventListener:(...e)=>u.addEventListener(e[0],e[1],e[2]),dispatchEvent:(...e)=>u.dispatchEvent(e[0]),removeEventListener:(...e)=>u.removeEventListener(e[0],e[1],e[2])};c===h.normalize&&(h.normalize=!c),o!==h.buffer&&(h.buffer=o);return n(Vt(h,l),()=>u.connect(l),()=>u.disconnect(l))})(nn,xn,Xn),Jn=((e,t,n,r)=>(o,a)=>{const i=e(o,e=>e.createConvolver());try{i.channelCount=1}catch(e){return t(o,a)}if(Ot(i,a),a.disableNormalization===i.normalize&&(i.normalize=!a.disableNormalization),kt(i,a,"buffer"),a.channelCount>2)throw n();if(r(i,"channelCount",e=>()=>e.call(i),e=>t=>{if(t>2)throw n();return e.call(i,t)}),"max"===a.channelCountMode)throw n();return r(i,"channelCountMode",e=>()=>e.call(i),e=>t=>{if("max"===t)throw n();return e.call(i,t)}),i})(nn,Kn,Lt,Yt),er=((e,t,n,r,o)=>class extends e{constructor(e,a=_t){const i=r(e),s={..._t,...a},c=n(i,s);super(e,!1,c,o(i)?t():null),this._isBufferNullified=!1,this._nativeConvolverNode=c}get buffer(){return this._isBufferNullified?null:this._nativeConvolverNode.buffer}set buffer(e){if(this._nativeConvolverNode.buffer=e,null===e&&null!==this._nativeConvolverNode.buffer){const e=this._nativeConvolverNode.context;this._nativeConvolverNode.buffer=e.createBuffer(1,1,e.sampleRate),this._isBufferNullified=!0}else this._isBufferNullified=!1}get normalize(){return this._nativeConvolverNode.normalize}set normalize(e){this._nativeConvolverNode.normalize=e}})(vn,((e,t,n)=>()=>{const r=new WeakMap;return{render(o,a,i){const s=r.get(a);return void 0!==s?Promise.resolve(s):(async(o,a,i)=>{let s=t(o);if(!xe(s,a)){const t={buffer:s.buffer,channelCount:s.channelCount,channelCountMode:s.channelCountMode,channelInterpretation:s.channelInterpretation,disableNormalization:!s.normalize};s=e(a,t)}return r.set(a,s),je(s)?await n(o,a,s.inputs[0],i):await n(o,a,s,i),s})(o,a,i)}}})(Jn,Ze,an),Jn,un,Jt),tr=(e=>(t,n)=>{const r=e(t,e=>e.createDelay(n.maxDelayTime));return Ot(r,n),Pt(r,n,"delayTime"),r})(nn),nr=((e,t,n,r,o,a)=>class extends e{constructor(e,i=Ct){const s=o(e),c={...Ct,...i},u=r(s,c),l=a(s);super(e,!1,u,l?n(c.maxDelayTime):null),this._delayTime=t(this,l,u.delayTime,c.maxDelayTime,0)}get delayTime(){return this._delayTime}})(vn,Bn,((e,t,n,r,o)=>a=>{const i=new WeakMap;return{render(s,c,u){const l=i.get(c);return void 0!==l?Promise.resolve(l):(async(s,c,u)=>{let l=n(s);const h=xe(l,c);if(!h){const e={channelCount:l.channelCount,channelCountMode:l.channelCountMode,channelInterpretation:l.channelInterpretation,delayTime:l.delayTime.value,maxDelayTime:a};l=t(c,e)}return i.set(c,l),h?await e(c,s.delayTime,l.delayTime,u):await r(c,s.delayTime,l.delayTime,u),await o(s,c,l,u),l})(s,c,u)}}})(Pn,tr,Ze,Rn,an),tr,un,Jt),rr=((e,t)=>(n,r)=>{const o=e(n,e=>e.createDynamicsCompressor());if(Ot(o,r),r.channelCount>2)throw t();if("max"===r.channelCountMode)throw t();return Pt(o,r,"attack"),Pt(o,r,"knee"),Pt(o,r,"ratio"),Pt(o,r,"release"),Pt(o,r,"threshold"),o})(nn,Lt),or=((e,t,n,r,o,a,i)=>class extends e{constructor(e,o=bt){const s=a(e),c={...bt,...o},u=r(s,c),l=i(s);super(e,!1,u,l?n():null),this._attack=t(this,l,u.attack,1,0),this._knee=t(this,l,u.knee,40,0),this._nativeDynamicsCompressorNode=u,this._ratio=t(this,l,u.ratio,20,1),this._release=t(this,l,u.release,1,0),this._threshold=t(this,l,u.threshold,0,-100)}get attack(){return this._attack}get channelCount(){return this._nativeDynamicsCompressorNode.channelCount}set channelCount(e){const t=this._nativeDynamicsCompressorNode.channelCount;if(this._nativeDynamicsCompressorNode.channelCount=e,e>2)throw this._nativeDynamicsCompressorNode.channelCount=t,o()}get channelCountMode(){return this._nativeDynamicsCompressorNode.channelCountMode}set channelCountMode(e){const t=this._nativeDynamicsCompressorNode.channelCountMode;if(this._nativeDynamicsCompressorNode.channelCountMode=e,"max"===e)throw this._nativeDynamicsCompressorNode.channelCountMode=t,o()}get knee(){return this._knee}get ratio(){return this._ratio}get reduction(){return"number"==typeof this._nativeDynamicsCompressorNode.reduction.value?this._nativeDynamicsCompressorNode.reduction.value:this._nativeDynamicsCompressorNode.reduction}get release(){return this._release}get threshold(){return this._threshold}})(vn,Bn,((e,t,n,r,o)=>()=>{const a=new WeakMap;return{render(i,s,c){const u=a.get(s);return void 0!==u?Promise.resolve(u):(async(i,s,c)=>{let u=n(i);const l=xe(u,s);if(!l){const e={attack:u.attack.value,channelCount:u.channelCount,channelCountMode:u.channelCountMode,channelInterpretation:u.channelInterpretation,knee:u.knee.value,ratio:u.ratio.value,release:u.release.value,threshold:u.threshold.value};u=t(s,e)}return a.set(s,u),l?(await e(s,i.attack,u.attack,c),await e(s,i.knee,u.knee,c),await e(s,i.ratio,u.ratio,c),await e(s,i.release,u.release,c),await e(s,i.threshold,u.threshold,c)):(await r(s,i.attack,u.attack,c),await r(s,i.knee,u.knee,c),await r(s,i.ratio,u.ratio,c),await r(s,i.release,u.release,c),await r(s,i.threshold,u.threshold,c)),await o(i,s,u,c),u})(i,s,c)}}})(Pn,rr,Ze,Rn,an),rr,Lt,un,Jt),ar=((e,t,n,r,o,a)=>class extends e{constructor(e,i=Tt){const s=o(e),c={...Tt,...i},u=r(s,c),l=a(s);super(e,!1,u,l?n():null),this._gain=t(this,l,u.gain,Ee,Oe)}get gain(){return this._gain}})(vn,Bn,((e,t,n,r,o)=>()=>{const a=new WeakMap;return{render(i,s,c){const u=a.get(s);return void 0!==u?Promise.resolve(u):(async(i,s,c)=>{let u=n(i);const l=xe(u,s);if(!l){const e={channelCount:u.channelCount,channelCountMode:u.channelCountMode,channelInterpretation:u.channelInterpretation,gain:u.gain.value};u=t(s,e)}return a.set(s,u),l?await e(s,i.gain,u.gain,c):await r(s,i.gain,u.gain,c),await o(i,s,u,c),u})(i,s,c)}}})(Pn,xn,Ze,Rn,an),xn,un,Jt),ir=(e=>(t,n,r,o)=>e(t,e=>e.createScriptProcessor(n,r,o)))(nn),sr=((e,t,n,r)=>(o,a,{channelCount:i,channelCountMode:s,channelInterpretation:c,feedback:u,feedforward:l})=>{const h=((e,t)=>null===e?512:Math.max(512,Math.min(16384,Math.pow(2,Math.round(Math.log2(e*t))))))(a,o.sampleRate),d=u.length,f=l.length,p=Math.min(d,f);if(0===u.length||u.length>20)throw r();if(0===u[0])throw t();if(0===l.length||l.length>20)throw r();if(0===l[0])throw t();if(1!==u[0]){for(let e=0;e{const t=e.inputBuffer,n=e.outputBuffer,r=t.numberOfChannels;for(let e=0;em.addEventListener(e[0],e[1],e[2]),dispatchEvent:(...e)=>m.dispatchEvent(e[0]),getFrequencyResponse(t,n,r){if(t.length!==n.length||n.length!==r.length)throw e();const o=t.length;for(let e=0;em.removeEventListener(e[0],e[1],e[2])},m)})(It,Mt,ir,Lt),cr=((e,t,n,r)=>o=>e(Nt,()=>Nt(o))?Promise.resolve(e(r,r)).then(e=>{if(!e){const e=n(o,512,0,1);o.oncomplete=()=>{e.onaudioprocess=null,e.disconnect()},e.onaudioprocess=()=>o.currentTime,e.connect(o.destination)}return o.startRendering()}):new Promise(e=>{const n=t(o,{channelCount:1,channelCountMode:"explicit",channelInterpretation:"discrete",gain:0});o.oncomplete=t=>{n.disconnect(),e(t.renderedBuffer)},n.connect(o.destination),o.startRendering()}))(Ut,xn,ir,((e,t)=>()=>{if(null===t)return Promise.resolve(!1);const n=new t(1,1,44100),r=e(n,{channelCount:1,channelCountMode:"explicit",channelInterpretation:"discrete",gain:0});return new Promise(e=>{n.oncomplete=()=>{r.disconnect(),e(0!==n.currentTime)},n.startRendering()})})(xn,Kt)),ur=((e,t,n,r,o,a)=>(i,s)=>{const c=new WeakMap;let u=null;const l=async(l,h,d)=>{let f=null,p=n(l);const m=xe(p,h);if(void 0===h.createIIRFilter?f=e(h,{buffer:null,channelCount:2,channelCountMode:"max",channelInterpretation:"speakers",loop:!1,loopEnd:0,loopStart:0,playbackRate:1}):m||(p=t(h,e=>e.createIIRFilter(s,i))),c.set(h,null===f?p:f),null!==f){if(null===u){if(null===r)throw new Error("Missing the native OfflineAudioContext constructor.");const e=new r(l.context.destination.channelCount,l.context.length,h.sampleRate);u=(async()=>{await o(l,e,e.destination,d);return((e,t,n,r)=>{const o=n.length,a=r.length,i=Math.min(o,a);if(1!==n[0]){for(let e=0;eclass extends e{constructor(e,a){const i=r(e),s=o(i),c={...xt,...a},u=t(i,s?null:e.baseLatency,c);super(e,!1,u,s?n(c.feedback,c.feedforward):null),(e=>{var t;e.getFrequencyResponse=(t=e.getFrequencyResponse,(n,r,o)=>{if(n.length!==r.length||r.length!==o.length)throw It();return t.call(e,n,r,o)})})(u),this._nativeIIRFilterNode=u}getFrequencyResponse(e,t,n){return this._nativeIIRFilterNode.getFrequencyResponse(e,t,n)}})(vn,((e,t)=>(n,r,o)=>{if(void 0===n.createIIRFilter)return t(n,r,o);const a=e(n,e=>e.createIIRFilter(o.feedforward,o.feedback));return Ot(a,o),a})(nn,sr),ur,un,Jt),hr=((e,t,n,r,o,a)=>class extends n{constructor(n,a){super(n),this._nativeContext=n,ve.set(this,n);const i=n.sampleRate;Object.defineProperty(n,"sampleRate",{get:()=>i}),r(n)&&o.set(n,new Set),this._destination=new e(this,a),this._listener=t(this,n),this._onstatechange=null}get currentTime(){return this._nativeContext.currentTime}get destination(){return this._destination}get listener(){return this._listener}get onstatechange(){return this._onstatechange}set onstatechange(e){const t="function"==typeof e?a(this,e):null;this._nativeContext.onstatechange=t;const n=this._nativeContext.onstatechange;this._onstatechange=null!==n&&n===t?e:n}get sampleRate(){return this._nativeContext.sampleRate}get state(){return this._nativeContext.state}})(Wn,((e,t,n,r,o)=>(a,i)=>{const s=i.listener,{forwardX:c,forwardY:u,forwardZ:l,positionX:h,positionY:d,positionZ:f,upX:p,upY:m,upZ:v}=void 0===s.forwardX?(()=>{const c=t(i,{channelCount:1,channelCountMode:"explicit",channelInterpretation:"speakers",numberOfInputs:9}),u=o(i),l=r(i,256,9,0),h=(t,r)=>{const o=n(i,{channelCount:1,channelCountMode:"explicit",channelInterpretation:"discrete",offset:r});return o.connect(c,0,t),o.start(),Object.defineProperty(o.offset,"defaultValue",{get:()=>r}),e({context:a},u,o.offset,Ee,Oe)};let d=[0,0,-1,0,1,0],f=[0,0,0];return l.onaudioprocess=({inputBuffer:e})=>{const t=[e.getChannelData(0)[0],e.getChannelData(1)[0],e.getChannelData(2)[0],e.getChannelData(3)[0],e.getChannelData(4)[0],e.getChannelData(5)[0]];t.some((e,t)=>e!==d[t])&&(s.setOrientation(...t),d=t);const n=[e.getChannelData(6)[0],e.getChannelData(7)[0],e.getChannelData(8)[0]];n.some((e,t)=>e!==f[t])&&(s.setPosition(...n),f=n)},c.connect(l),{forwardX:h(0,0),forwardY:h(1,0),forwardZ:h(2,-1),positionX:h(6,0),positionY:h(7,0),positionZ:h(8,0),upX:h(3,0),upY:h(4,1),upZ:h(5,0)}})():s;return{get forwardX(){return c},get forwardY(){return u},get forwardZ(){return l},get positionX(){return h},get positionY(){return d},get positionZ(){return f},get upX(){return p},get upY(){return m},get upZ(){return v}}})(Bn,zn,Hn,ir,Jt),dn,Jt,new WeakMap,Zt),dr=((e,t,n,r,o,a,i)=>(s,c)=>{const u=n(s,e=>e.createOscillator());return Ot(u,c),Pt(u,c,"detune"),Pt(u,c,"frequency"),void 0!==c.periodicWave?u.setPeriodicWave(c.periodicWave):kt(u,c,"type"),t(r,()=>r(s))||Dt(u),t(o,()=>o(s))||i(u,s),t(a,()=>a(s))||Rt(u),e(s,u),u})(Sn,Ut,nn,An,Nn,kn,On),fr=((e,t,n,r,o)=>()=>{const a=new WeakMap;let i=null,s=null,c=null;return{set periodicWave(e){i=e},set start(e){s=e},set stop(e){c=e},render(u,l,h){const d=a.get(l);return void 0!==d?Promise.resolve(d):(async(u,l,h)=>{let d=n(u);const f=xe(d,l);if(!f){const e={channelCount:d.channelCount,channelCountMode:d.channelCountMode,channelInterpretation:d.channelInterpretation,detune:d.detune.value,frequency:d.frequency.value,periodicWave:null===i?void 0:i,type:d.type};d=t(l,e),null!==s&&d.start(s),null!==c&&d.stop(c)}return a.set(l,d),f?(await e(l,u.detune,d.detune,h),await e(l,u.frequency,d.frequency,h)):(await r(l,u.detune,d.detune,h),await r(l,u.frequency,d.frequency,h)),await o(u,l,d,h),d})(u,l,h)}}})(Pn,dr,Ze,Rn,an),pr=((e,t,n,r,o,a,i,s)=>class extends e{constructor(e,n=Wt){const s=a(e),c={...Wt,...n},u=r(s,c),l=i(s),h=l?o():null,d=e.sampleRate/2;super(e,!1,u,h),this._detune=t(this,l,u.detune,153600,-153600),this._frequency=t(this,l,u.frequency,d,-d),this._nativeOscillatorNode=u,this._onended=null,this._oscillatorNodeRenderer=h,null!==this._oscillatorNodeRenderer&&void 0!==c.periodicWave&&(this._oscillatorNodeRenderer.periodicWave=c.periodicWave)}get detune(){return this._detune}get frequency(){return this._frequency}get onended(){return this._onended}set onended(e){const t="function"==typeof e?s(this,e):null;this._nativeOscillatorNode.onended=t;const n=this._nativeOscillatorNode.onended;this._onended=null!==n&&n===t?e:n}get type(){return this._nativeOscillatorNode.type}set type(e){if(this._nativeOscillatorNode.type=e,"custom"===e)throw n();null!==this._oscillatorNodeRenderer&&(this._oscillatorNodeRenderer.periodicWave=null)}setPeriodicWave(e){this._nativeOscillatorNode.setPeriodicWave(e),null!==this._oscillatorNodeRenderer&&(this._oscillatorNodeRenderer.periodicWave=e)}start(e=0){if(this._nativeOscillatorNode.start(e),null!==this._oscillatorNodeRenderer)this._oscillatorNodeRenderer.start=e;else{Re(this);const e=()=>{this._nativeOscillatorNode.removeEventListener("ended",e),setTimeout(()=>Ve(this),1e3)};this._nativeOscillatorNode.addEventListener("ended",e)}}stop(e=0){this._nativeOscillatorNode.stop(e),null!==this._oscillatorNodeRenderer&&(this._oscillatorNodeRenderer.stop=e)}})(vn,Bn,Mt,dr,fr,un,Jt,Zt),mr=(e=>(t,n)=>{const r=e(t,{buffer:null,channelCount:2,channelCountMode:"max",channelInterpretation:"speakers",loop:!1,loopEnd:0,loopStart:0,playbackRate:1}),o=t.createBuffer(1,2,t.sampleRate);return r.buffer=o,r.loop=!0,r.connect(n),r.start(),()=>{r.stop(),r.disconnect(n)}})(Dn),vr=((e,t,n,r,o,a)=>(i,{curve:s,oversample:c,...u})=>{const l=n(i,e=>e.createWaveShaper()),h=n(i,e=>e.createWaveShaper());Ot(l,u),Ot(h,u);const d=r(i,{...u,gain:1}),f=r(i,{...u,gain:-1}),p=r(i,{...u,gain:1}),m=r(i,{...u,gain:-1});let v=null,g=!1,y=null;const w={get bufferSize(){},get channelCount(){return l.channelCount},set channelCount(e){d.channelCount=e,f.channelCount=e,l.channelCount=e,p.channelCount=e,h.channelCount=e,m.channelCount=e},get channelCountMode(){return l.channelCountMode},set channelCountMode(e){d.channelCountMode=e,f.channelCountMode=e,l.channelCountMode=e,p.channelCountMode=e,h.channelCountMode=e,m.channelCountMode=e},get channelInterpretation(){return l.channelInterpretation},set channelInterpretation(e){d.channelInterpretation=e,f.channelInterpretation=e,l.channelInterpretation=e,p.channelInterpretation=e,h.channelInterpretation=e,m.channelInterpretation=e},get context(){return l.context},get curve(){return y},set curve(n){if(null!==s&&s.length<2)throw t();if(null===n)l.curve=n,h.curve=n;else{const e=n.length,t=new Float32Array(e+2-e%2),r=new Float32Array(e+2-e%2);t[0]=n[0],r[0]=-n[e-1];const o=Math.ceil((e+1)/2),a=(e+1)/2-1;for(let i=1;id.addEventListener(e[0],e[1],e[2]),dispatchEvent:(...e)=>d.dispatchEvent(e[0]),removeEventListener:(...e)=>d.removeEventListener(e[0],e[1],e[2])};s!==w.curve&&(w.curve=s),c!==w.oversample&&(w.oversample=c);return a(Vt(w,p),()=>{d.connect(l).connect(p),d.connect(f).connect(h).connect(m).connect(p),g=!0,o(y)&&(v=e(i,d))},()=>{d.disconnect(l),l.disconnect(p),d.disconnect(f),f.disconnect(h),h.disconnect(m),m.disconnect(p),g=!1,null!==v&&(v(),v=null)})})(mr,Mt,nn,xn,zt,Xn),gr=((e,t,n,r,o,a,i)=>(s,c)=>{const u=n(s,e=>e.createWaveShaper());try{return u.curve=new Float32Array([1]),r(s,c)}catch{}Ot(u,c);const l=c.curve;if(null!==l&&l.length<2)throw t();kt(u,c,"curve"),kt(u,c,"oversample");let h=null,d=!1;i(u,"curve",e=>()=>e.call(u),t=>n=>(t.call(u,n),d&&(o(n)&&null===h?h=e(s,u):o(n)||null===h||(h(),h=null)),n));return a(u,()=>{d=!0,o(u.curve)&&(h=e(s,u))},()=>{d=!1,null!==h&&(h(),h=null)})})(mr,Mt,nn,vr,zt,Xn,Yt),yr=((e,t,n,r,o,a,i,s,c,u)=>(l,{coneInnerAngle:h,coneOuterAngle:d,coneOuterGain:f,distanceModel:p,maxDistance:m,orientationX:v,orientationY:g,orientationZ:y,panningModel:w,positionX:_,positionY:C,positionZ:b,refDistance:T,rolloffFactor:M,...I})=>{const x=n(l,e=>e.createPanner());if(I.channelCount>2)throw s();if("max"===I.channelCountMode)throw s();Ot(x,I);const S={channelCount:1,channelCountMode:"explicit",channelInterpretation:"discrete"},A=r(l,{...S,channelInterpretation:"speakers",numberOfInputs:6}),N=o(l,{...I,gain:1}),k=o(l,{...S,gain:1}),O=o(l,{...S,gain:0}),E=o(l,{...S,gain:0}),P=o(l,{...S,gain:0}),D=o(l,{...S,gain:0}),R=o(l,{...S,gain:0}),V=a(l,256,6,1),B=i(l,{...S,curve:new Float32Array([1,1]),oversample:"none"});let F=[v,g,y],L=[_,C,b];V.onaudioprocess=({inputBuffer:e})=>{const t=[e.getChannelData(0)[0],e.getChannelData(1)[0],e.getChannelData(2)[0]];t.some((e,t)=>e!==F[t])&&(x.setOrientation(...t),F=t);const n=[e.getChannelData(3)[0],e.getChannelData(4)[0],e.getChannelData(5)[0]];n.some((e,t)=>e!==L[t])&&(x.setPosition(...n),L=n)},Object.defineProperty(O.gain,"defaultValue",{get:()=>0}),Object.defineProperty(E.gain,"defaultValue",{get:()=>0}),Object.defineProperty(P.gain,"defaultValue",{get:()=>0}),Object.defineProperty(D.gain,"defaultValue",{get:()=>0}),Object.defineProperty(R.gain,"defaultValue",{get:()=>0});const W={get bufferSize(){},get channelCount(){return x.channelCount},set channelCount(e){if(e>2)throw s();N.channelCount=e,x.channelCount=e},get channelCountMode(){return x.channelCountMode},set channelCountMode(e){if("max"===e)throw s();N.channelCountMode=e,x.channelCountMode=e},get channelInterpretation(){return x.channelInterpretation},set channelInterpretation(e){N.channelInterpretation=e,x.channelInterpretation=e},get coneInnerAngle(){return x.coneInnerAngle},set coneInnerAngle(e){x.coneInnerAngle=e},get coneOuterAngle(){return x.coneOuterAngle},set coneOuterAngle(e){x.coneOuterAngle=e},get coneOuterGain(){return x.coneOuterGain},set coneOuterGain(e){if(e<0||e>1)throw t();x.coneOuterGain=e},get context(){return x.context},get distanceModel(){return x.distanceModel},set distanceModel(e){x.distanceModel=e},get inputs(){return[N]},get maxDistance(){return x.maxDistance},set maxDistance(e){if(e<0)throw new RangeError;x.maxDistance=e},get numberOfInputs(){return x.numberOfInputs},get numberOfOutputs(){return x.numberOfOutputs},get orientationX(){return k.gain},get orientationY(){return O.gain},get orientationZ(){return E.gain},get panningModel(){return x.panningModel},set panningModel(e){if(x.panningModel=e,x.panningModel!==e&&"HRTF"===e)throw s()},get positionX(){return P.gain},get positionY(){return D.gain},get positionZ(){return R.gain},get refDistance(){return x.refDistance},set refDistance(e){if(e<0)throw new RangeError;x.refDistance=e},get rolloffFactor(){return x.rolloffFactor},set rolloffFactor(e){if(e<0)throw new RangeError;x.rolloffFactor=e},addEventListener:(...e)=>N.addEventListener(e[0],e[1],e[2]),dispatchEvent:(...e)=>N.dispatchEvent(e[0]),removeEventListener:(...e)=>N.removeEventListener(e[0],e[1],e[2])};h!==W.coneInnerAngle&&(W.coneInnerAngle=h),d!==W.coneOuterAngle&&(W.coneOuterAngle=d),f!==W.coneOuterGain&&(W.coneOuterGain=f),p!==W.distanceModel&&(W.distanceModel=p),m!==W.maxDistance&&(W.maxDistance=m),v!==W.orientationX.value&&(W.orientationX.value=v),g!==W.orientationY.value&&(W.orientationY.value=g),y!==W.orientationZ.value&&(W.orientationZ.value=y),w!==W.panningModel&&(W.panningModel=w),_!==W.positionX.value&&(W.positionX.value=_),C!==W.positionY.value&&(W.positionY.value=C),b!==W.positionZ.value&&(W.positionZ.value=b),T!==W.refDistance&&(W.refDistance=T),M!==W.rolloffFactor&&(W.rolloffFactor=M),1===F[0]&&0===F[1]&&0===F[2]||x.setOrientation(...F),0===L[0]&&0===L[1]&&0===L[2]||x.setPosition(...L);return u(Vt(W,x),()=>{N.connect(x),e(N,B,0,0),B.connect(k).connect(A,0,0),B.connect(O).connect(A,0,1),B.connect(E).connect(A,0,2),B.connect(P).connect(A,0,3),B.connect(D).connect(A,0,4),B.connect(R).connect(A,0,5),A.connect(V).connect(l.destination)},()=>{N.disconnect(x),c(N,B,0,0),B.disconnect(k),k.disconnect(A),B.disconnect(O),O.disconnect(A),B.disconnect(E),E.disconnect(A),B.disconnect(P),P.disconnect(A),B.disconnect(D),D.disconnect(A),B.disconnect(R),R.disconnect(A),A.disconnect(V),V.disconnect(l.destination)})})(Ge,Mt,nn,zn,xn,ir,gr,Lt,qe,Xn),wr=((e,t)=>(n,r)=>{const o=e(n,e=>e.createPanner());return void 0===o.orientationX?t(n,r):(Ot(o,r),Pt(o,r,"orientationX"),Pt(o,r,"orientationY"),Pt(o,r,"orientationZ"),Pt(o,r,"positionX"),Pt(o,r,"positionY"),Pt(o,r,"positionZ"),kt(o,r,"coneInnerAngle"),kt(o,r,"coneOuterAngle"),kt(o,r,"coneOuterGain"),kt(o,r,"distanceModel"),kt(o,r,"maxDistance"),kt(o,r,"panningModel"),kt(o,r,"refDistance"),kt(o,r,"rolloffFactor"),o)})(nn,yr),_r=((e,t,n,r,o,a,i,s,c,u)=>()=>{const l=new WeakMap;let h=null;return{render(d,f,p){const m=l.get(f);return void 0!==m?Promise.resolve(m):(async(d,f,p)=>{let m=null,v=a(d);const g={channelCount:v.channelCount,channelCountMode:v.channelCountMode,channelInterpretation:v.channelInterpretation},y={...g,coneInnerAngle:v.coneInnerAngle,coneOuterAngle:v.coneOuterAngle,coneOuterGain:v.coneOuterGain,distanceModel:v.distanceModel,maxDistance:v.maxDistance,panningModel:v.panningModel,refDistance:v.refDistance,rolloffFactor:v.rolloffFactor},w=xe(v,f);if("bufferSize"in v)m=r(f,{...g,gain:1});else if(!w){const e={...y,orientationX:v.orientationX.value,orientationY:v.orientationY.value,orientationZ:v.orientationZ.value,positionX:v.positionX.value,positionY:v.positionY.value,positionZ:v.positionZ.value};v=o(f,e)}if(l.set(f,null===m?v:m),null!==m){if(null===h){if(null===i)throw new Error("Missing the native OfflineAudioContext constructor.");const e=new i(6,d.context.length,f.sampleRate),r=t(e,{channelCount:1,channelCountMode:"explicit",channelInterpretation:"speakers",numberOfInputs:6});r.connect(e.destination),h=(async()=>{const t=await Promise.all([d.orientationX,d.orientationY,d.orientationZ,d.positionX,d.positionY,d.positionZ].map(async(t,r)=>{const o=n(e,{channelCount:1,channelCountMode:"explicit",channelInterpretation:"discrete",offset:0===r?1:0});return await s(e,t,o.offset,p),o}));for(let e=0;e<6;e+=1)t[e].connect(r,0,e),t[e].start(0);return u(e)})()}const e=await h,a=r(f,{...g,gain:1});await c(d,f,a,p);const l=[];for(let t=0;te!==v[t])||n.some((e,t)=>e!==w[t])){v=e,w=n;const i=t/f.sampleRate;_.gain.setValueAtTime(0,i),_=r(f,{...g,gain:0}),C=o(f,{...y,orientationX:v[0],orientationY:v[1],orientationZ:v[2],positionX:w[0],positionY:w[1],positionZ:w[2]}),_.gain.setValueAtTime(1,i),a.connect(_).connect(C.inputs[0]),C.connect(m)}}return m}return w?(await e(f,d.orientationX,v.orientationX,p),await e(f,d.orientationY,v.orientationY,p),await e(f,d.orientationZ,v.orientationZ,p),await e(f,d.positionX,v.positionX,p),await e(f,d.positionY,v.positionY,p),await e(f,d.positionZ,v.positionZ,p)):(await s(f,d.orientationX,v.orientationX,p),await s(f,d.orientationY,v.orientationY,p),await s(f,d.orientationZ,v.orientationZ,p),await s(f,d.positionX,v.positionX,p),await s(f,d.positionY,v.positionY,p),await s(f,d.positionZ,v.positionZ,p)),je(v)?await c(d,f,v.inputs[0],p):await c(d,f,v,p),v})(d,f,p)}}})(Pn,zn,Hn,xn,wr,Ze,Kt,Rn,an,cr),Cr=((e,t,n,r,o,a)=>class extends e{constructor(e,i=jt){const s=o(e),c={...jt,...i},u=n(s,c),l=a(s);super(e,!1,u,l?r():null),this._nativePannerNode=u,this._orientationX=t(this,l,u.orientationX,Ee,Oe),this._orientationY=t(this,l,u.orientationY,Ee,Oe),this._orientationZ=t(this,l,u.orientationZ,Ee,Oe),this._positionX=t(this,l,u.positionX,Ee,Oe),this._positionY=t(this,l,u.positionY,Ee,Oe),this._positionZ=t(this,l,u.positionZ,Ee,Oe)}get coneInnerAngle(){return this._nativePannerNode.coneInnerAngle}set coneInnerAngle(e){this._nativePannerNode.coneInnerAngle=e}get coneOuterAngle(){return this._nativePannerNode.coneOuterAngle}set coneOuterAngle(e){this._nativePannerNode.coneOuterAngle=e}get coneOuterGain(){return this._nativePannerNode.coneOuterGain}set coneOuterGain(e){this._nativePannerNode.coneOuterGain=e}get distanceModel(){return this._nativePannerNode.distanceModel}set distanceModel(e){this._nativePannerNode.distanceModel=e}get maxDistance(){return this._nativePannerNode.maxDistance}set maxDistance(e){this._nativePannerNode.maxDistance=e}get orientationX(){return this._orientationX}get orientationY(){return this._orientationY}get orientationZ(){return this._orientationZ}get panningModel(){return this._nativePannerNode.panningModel}set panningModel(e){this._nativePannerNode.panningModel=e}get positionX(){return this._positionX}get positionY(){return this._positionY}get positionZ(){return this._positionZ}get refDistance(){return this._nativePannerNode.refDistance}set refDistance(e){this._nativePannerNode.refDistance=e}get rolloffFactor(){return this._nativePannerNode.rolloffFactor}set rolloffFactor(e){this._nativePannerNode.rolloffFactor=e}})(vn,Bn,wr,_r,un,Jt),br=((e,t,n)=>class r{constructor(r,o){const a=t(r),i={...Gt,...o},s=e(a,i);return n.add(s),s}static[Symbol.hasInstance](e){return null!==e&&"object"==typeof e&&Object.getPrototypeOf(e)===r.prototype||n.has(e)}})((e=>(t,{disableNormalization:n,imag:r,real:o})=>{const a=e(t),i=new Float32Array(r),s=new Float32Array(o);return null!==a?a.createPeriodicWave(s,i,{disableNormalization:n}):t.createPeriodicWave(s,i,{disableNormalization:n})})(tn),un,new WeakSet),Tr=((e,t,n)=>(r,o)=>e(r,e=>{const a=o.channelCountMode;if("clamped-max"===a)throw n();if(void 0===r.createStereoPanner)return t(r,o);const i=e.createStereoPanner();return Ot(i,o),Pt(i,o,"pan"),Object.defineProperty(i,"channelCountMode",{get:()=>a,set:e=>{if(e!==a)throw n()}}),i}))(nn,((e,t,n,r,o,a)=>{const i=16385,s=new Float32Array([1,1]),c=Math.PI/2,u={channelCount:1,channelCountMode:"explicit",channelInterpretation:"discrete"},l={...u,oversample:"none"},h=(e,a,h,d,f)=>{if(1===a)return((e,t,o,a)=>{const h=new Float32Array(i),d=new Float32Array(i);for(let e=0;e{const d=new Float32Array(i),f=new Float32Array(i),p=new Float32Array(i),m=new Float32Array(i),v=Math.floor(8192.5);for(let e=0;ev){const t=(e-v)/(16384-v)*c;d[e]=Math.cos(t),f[e]=Math.sin(t),p[e]=0,m[e]=1}else{const t=e/(16384-v)*c;d[e]=1,f[e]=0,p[e]=Math.cos(t),m[e]=Math.sin(t)}const g=t(e,{channelCount:2,channelCountMode:"explicit",channelInterpretation:"discrete",numberOfOutputs:2}),y=n(e,{...u,gain:0}),w=r(e,{...l,curve:d}),_=n(e,{...u,gain:0}),C=r(e,{...l,curve:f}),b=r(e,{...l,curve:s}),T=n(e,{...u,gain:0}),M=r(e,{...l,curve:p}),I=n(e,{...u,gain:0}),x=r(e,{...l,curve:m});return{connectGraph(){o.connect(g),o.connect(b.inputs[0]),g.connect(y,1),g.connect(_,1),g.connect(T,1),g.connect(I,1),b.connect(a),a.connect(w.inputs[0]),a.connect(C.inputs[0]),a.connect(M.inputs[0]),a.connect(x.inputs[0]),w.connect(y.gain),C.connect(_.gain),M.connect(T.gain),x.connect(I.gain),y.connect(h,0,0),T.connect(h,0,0),_.connect(h,0,1),I.connect(h,0,1)},disconnectGraph(){o.disconnect(g),o.disconnect(b.inputs[0]),g.disconnect(y,1),g.disconnect(_,1),g.disconnect(T,1),g.disconnect(I,1),b.disconnect(a),a.disconnect(w.inputs[0]),a.disconnect(C.inputs[0]),a.disconnect(M.inputs[0]),a.disconnect(x.inputs[0]),w.disconnect(y.gain),C.disconnect(_.gain),M.disconnect(T.gain),x.disconnect(I.gain),y.disconnect(h,0,0),T.disconnect(h,0,0),_.disconnect(h,0,1),I.disconnect(h,0,1)}}})(e,h,d,f);throw o()};return(t,{channelCount:r,channelCountMode:i,pan:s,...c})=>{if("max"===i)throw o();const u=e(t,{...c,channelCount:1,channelCountMode:i,numberOfInputs:2}),l=n(t,{...c,channelCount:r,channelCountMode:i,gain:1}),d=n(t,{channelCount:1,channelCountMode:"explicit",channelInterpretation:"discrete",gain:s});let{connectGraph:f,disconnectGraph:p}=h(t,r,l,d,u);Object.defineProperty(d.gain,"defaultValue",{get:()=>0});const m={get bufferSize(){},get channelCount(){return l.channelCount},set channelCount(e){l.channelCount!==e&&(v&&p(),({connectGraph:f,disconnectGraph:p}=h(t,e,l,d,u)),v&&f()),l.channelCount=e},get channelCountMode(){return l.channelCountMode},set channelCountMode(e){if("clamped-max"===e||"max"===e)throw o();l.channelCountMode=e},get channelInterpretation(){return l.channelInterpretation},set channelInterpretation(e){l.channelInterpretation=e},get context(){return l.context},get inputs(){return[l]},get numberOfInputs(){return l.numberOfInputs},get numberOfOutputs(){return l.numberOfOutputs},get pan(){return d.gain},addEventListener:(...e)=>l.addEventListener(e[0],e[1],e[2]),dispatchEvent:(...e)=>l.dispatchEvent(e[0]),removeEventListener:(...e)=>l.removeEventListener(e[0],e[1],e[2])};let v=!1;return a(Vt(m,u),()=>{f(),v=!0},()=>{p(),v=!1})}})(zn,Zn,xn,gr,Lt,Xn),Lt),Mr=((e,t,n,r,o)=>()=>{const a=new WeakMap;return{render(i,s,c){const u=a.get(s);return void 0!==u?Promise.resolve(u):(async(i,s,c)=>{let u=n(i);const l=xe(u,s);if(!l){const e={channelCount:u.channelCount,channelCountMode:u.channelCountMode,channelInterpretation:u.channelInterpretation,pan:u.pan.value};u=t(s,e)}return a.set(s,u),l?await e(s,i.pan,u.pan,c):await r(s,i.pan,u.pan,c),je(u)?await o(i,s,u.inputs[0],c):await o(i,s,u,c),u})(i,s,c)}}})(Pn,Tr,Ze,Rn,an),Ir=((e,t,n,r,o,a)=>class extends e{constructor(e,i=Xt){const s=o(e),c={...Xt,...i},u=n(s,c),l=a(s);super(e,!1,u,l?r():null),this._pan=t(this,l,u.pan,1,-1)}get pan(){return this._pan}})(vn,Bn,Tr,Mr,un,Jt),xr=((e,t,n)=>()=>{const r=new WeakMap;return{render(o,a,i){const s=r.get(a);return void 0!==s?Promise.resolve(s):(async(o,a,i)=>{let s=t(o);if(!xe(s,a)){const t={channelCount:s.channelCount,channelCountMode:s.channelCountMode,channelInterpretation:s.channelInterpretation,curve:s.curve,oversample:s.oversample};s=e(a,t)}return r.set(a,s),je(s)?await n(o,a,s.inputs[0],i):await n(o,a,s,i),s})(o,a,i)}}})(gr,Ze,an),Sr=((e,t,n,r,o,a)=>class extends e{constructor(e,t=qt){const i=o(e),s={...qt,...t},c=n(i,s);super(e,!0,c,a(i)?r():null),this._isCurveNullified=!1,this._nativeWaveShaperNode=c}get curve(){return this._isCurveNullified?null:this._nativeWaveShaperNode.curve}set curve(e){if(null===e)this._isCurveNullified=!0,this._nativeWaveShaperNode.curve=new Float32Array([0,0]);else{if(e.length<2)throw t();this._isCurveNullified=!1,this._nativeWaveShaperNode.curve=e}}get oversample(){return this._nativeWaveShaperNode.oversample}set oversample(e){this._nativeWaveShaperNode.oversample=e}})(vn,Mt,gr,xr,un,Jt),Ar=(e=>null!==e&&e.isSecureContext)($t),Nr=(e=>(t,n,r)=>{Object.defineProperties(e,{currentFrame:{configurable:!0,get:()=>Math.round(t*n)},currentTime:{configurable:!0,get:()=>t}});try{return r()}finally{null!==e&&(delete e.currentFrame,delete e.currentTime)}})($t),kr=Ar?((e,t,n,r,o,a,i,s,c)=>(u,l,h={credentials:"omit"})=>{const d=a(u),f=new URL(l,c.location.href).toString();if(void 0!==d.audioWorklet)return r(l).then(e=>{const[t,n]=be(e,f),r=new Blob([`${t};(registerProcessor=>{${n}\n})((n,p)=>registerProcessor(n,class extends p{process(i,o,p){return super.process(i.map(j=>j.some(k=>k.length===0)?[]:j),o,p)}}))`],{type:"application/javascript; charset=utf-8"}),a=URL.createObjectURL(r),i=o(d);return(null!==i?i:d).audioWorklet.addModule(a,h).then(()=>URL.revokeObjectURL(a)).catch(e=>{throw URL.revokeObjectURL(a),void 0!==e.code&&"SyntaxError"!==e.name||(e.code=12),e})});const p=s.get(u);if(void 0!==p&&p.has(l))return Promise.resolve();const m=i.get(u);if(void 0!==m){const e=m.get(l);if(void 0!==e)return e}const v=r(l).then(e=>{const[n,r]=be(e,f);return t(`${n};((a,b)=>{(a[b]=a[b]||[]).push((AudioWorkletProcessor,global,registerProcessor,sampleRate,self,window)=>{${r}\n})})(window,'_AWGS')`)}).then(()=>{const t=c._AWGS.pop();if(void 0===t)throw new SyntaxError;n(d.currentTime,d.sampleRate,()=>t(class{},void 0,(t,n)=>{if(""===t.trim())throw e();const r=we.get(d);if(void 0!==r){if(r.has(t))throw e();Me(n),Te(n.parameterDescriptors),r.set(t,n)}else Me(n),Te(n.parameterDescriptors),we.set(d,new Map([[t,n]]))},d.sampleRate,void 0,void 0))}).catch(e=>{throw void 0!==e.code&&"SyntaxError"!==e.name||(e.code=12),e});return void 0===m?i.set(u,new Map([[l,v]])):m.set(l,v),v.then(()=>{const e=s.get(u);void 0===e?s.set(u,new Set([l])):e.add(l)}).catch(()=>{}).then(()=>{const e=i.get(u);void 0!==e&&e.delete(l)}),v})(Lt,(e=>t=>new Promise((n,r)=>{if(null===e)return void r(new SyntaxError);const o=e.document.head;if(null===o)r(new SyntaxError);else{const a=e.document.createElement("script"),i=new Blob([t],{type:"application/javascript"}),s=URL.createObjectURL(i),c=e.onerror,u=()=>{e.onerror=c,URL.revokeObjectURL(s)};e.onerror=(t,n,o,a,i)=>n===s||n===e.location.href&&1===o&&1===a?(u(),r(i),!1):null!==c?c(t,n,o,a,i):void 0,a.onerror=()=>{u(),r(new SyntaxError)},a.onload=()=>{u(),n()},a.src=s,a.type="module",o.appendChild(a)}}))($t),Nr,(e=>async t=>{try{const e=await fetch(t);if(e.ok)return e.text()}catch{}throw e()})(()=>{try{return new DOMException("","AbortError")}catch(e){return e.code=20,e.name="AbortError",e}}),tn,un,new WeakMap,new WeakMap,$t):void 0,Or=((e,t)=>n=>e(n)||t(n))(fn,Jt),Er=((e,t,n,r,o,a,i,s,c,u,l,h,d,f,p,m,v,g,y,w)=>class extends p{constructor(t,n){super(t,n),this._nativeContext=t,this._audioWorklet=void 0===e?void 0:{addModule:(t,n)=>e(this,t,n)}}get audioWorklet(){return this._audioWorklet}createAnalyser(){return new t(this)}createBiquadFilter(){return new o(this)}createBuffer(e,t,r){return new n({length:t,numberOfChannels:e,sampleRate:r})}createBufferSource(){return new r(this)}createChannelMerger(e=6){return new a(this,{numberOfInputs:e})}createChannelSplitter(e=6){return new i(this,{numberOfOutputs:e})}createConstantSource(){return new s(this)}createConvolver(){return new c(this)}createDelay(e=1){return new l(this,{maxDelayTime:e})}createDynamicsCompressor(){return new h(this)}createGain(){return new d(this)}createIIRFilter(e,t){return new f(this,{feedback:t,feedforward:e})}createOscillator(){return new m(this)}createPanner(){return new v(this)}createPeriodicWave(e,t,n={disableNormalization:!1}){return new g(this,{...n,imag:t,real:e})}createStereoPanner(){return new y(this)}createWaveShaper(){return new w(this)}decodeAudioData(e,t,n){return u(this._nativeContext,e).then(e=>("function"==typeof t&&t(e),e)).catch(e=>{throw"function"==typeof n&&n(e),e})}})(kr,yn,In,Ln,Gn,Yn,Un,$n,er,((e,t,n,r,o,a,i,s,c,u,l,h,d)=>(f,p)=>{const m=i(f)?f:a(f);if(o.has(p)){const e=n();return Promise.reject(e)}try{o.add(p)}catch{}if(t(l,()=>l(m))){return("closed"===m.state&&null!==c&&s(m)?new c(1,1,m.sampleRate):m).decodeAudioData(p).catch(e=>{if(e instanceof DOMException&&"NotSupportedError"===e.name)throw new TypeError;throw e}).then(n=>(t(u,()=>u(n))||d(n),e.add(n),n))}return new Promise((t,n)=>{const o=()=>{try{(e=>{const{port1:t}=new MessageChannel;t.postMessage(e,[e])})(p)}catch{}},a=e=>{n(e),o()};try{m.decodeAudioData(p,n=>{"function"!=typeof n.copyFromChannel&&(h(n),Ne(n)),e.add(n),o(),t(n)},e=>{a(null===e?r():e)})}catch(e){a(e)}})})(wn,Ut,()=>{try{return new DOMException("","DataCloneError")}catch(e){return e.code=25,e.name="DataCloneError",e}},()=>{try{return new DOMException("","EncodingError")}catch(e){return e.code=0,e.name="EncodingError",e}},new WeakSet,un,Or,Jt,Kt,Se,Nt,Tn,Mn),nr,or,ar,lr,hr,pr,Cr,br,Ir,Sr),Pr=((e,t,n,r)=>class extends e{constructor(e,o){const a=n(e),i=t(a,o);if(r(a))throw TypeError();super(e,!0,i,null),this._mediaElement=o.mediaElement,this._nativeMediaElementAudioSourceNode=i}get mediaElement(){return void 0===this._nativeMediaElementAudioSourceNode.mediaElement?this._mediaElement:this._nativeMediaElementAudioSourceNode.mediaElement}})(vn,(e=>(t,n)=>e(t,e=>e.createMediaElementSource(n.mediaElement)))(nn),un,Jt),Dr=((e,t,n,r)=>class extends e{constructor(e,o=At){const a=n(e);if(r(a))throw new TypeError;const i={...At,...o},s=t(a,i);super(e,!1,s,null),this._nativeMediaStreamAudioDestinationNode=s}get stream(){return this._nativeMediaStreamAudioDestinationNode.stream}})(vn,((e,t)=>(n,r)=>{if(void 0===n.createMediaStreamDestination)throw t();const o=e(n,e=>e.createMediaStreamDestination());return Ot(o,r),1===o.numberOfOutputs&&Object.defineProperty(o,"numberOfOutputs",{get:()=>0}),o})(nn,Lt),un,Jt),Rr=((e,t,n,r)=>class extends e{constructor(e,o){const a=n(e),i=t(a,o);if(r(a))throw new TypeError;super(e,!0,i,null),this._nativeMediaStreamAudioSourceNode=i}get mediaStream(){return this._nativeMediaStreamAudioSourceNode.mediaStream}})(vn,(e=>(t,{mediaStream:n})=>{const r=n.getAudioTracks(),o=e(t,e=>{r.sort((e,t)=>e.idt.id?1:0);const t=r.slice(0,1);return e.createMediaStreamSource(new MediaStream(t))});return Object.defineProperty(o,"mediaStream",{value:n}),o})(nn),un,Jt),Vr=((e,t,n)=>class extends e{constructor(e,r){const o=n(e);super(e,!0,t(o,r),null)}})(vn,((e,t,n)=>(r,{mediaStreamTrack:o})=>"function"==typeof r.createMediaStreamTrackSource?t(r,e=>e.createMediaStreamTrackSource(o)):t(r,t=>{const r=new MediaStream([o]),a=t.createMediaStreamSource(r);if("audio"!==o.kind)throw e();if(n(t))throw new TypeError;return a}))(Mt,nn,Jt),un),Br=((e,t,n,r,o,a,i,s,c)=>class extends e{constructor(e={}){if(null===c)throw new Error("Missing the native AudioContext constructor.");const t=new c(e);if(null===t)throw r();if(!(e=>void 0===e||"number"==typeof e||"string"==typeof e&&("balanced"===e||"interactive"===e||"playback"===e))(e.latencyHint))throw new TypeError(`The provided value '${e.latencyHint}' is not a valid enum value of type AudioContextLatencyCategory.`);if(void 0!==e.sampleRate&&t.sampleRate!==e.sampleRate)throw n();super(t,2);const{latencyHint:o}=e,{sampleRate:a}=t;if(this._baseLatency="number"==typeof t.baseLatency?t.baseLatency:"balanced"===o?512/a:"interactive"===o||void 0===o?256/a:"playback"===o?1024/a:128*Math.max(2,Math.min(128,Math.round(o*a/128)))/a,this._nativeAudioContext=t,this._state=null,"running"===t.state){this._state="suspended";const e=()=>{"suspended"===this._state&&(this._state=null),t.removeEventListener("statechange",e)};t.addEventListener("statechange",e)}}get baseLatency(){return this._baseLatency}get state(){return null!==this._state?this._state:this._nativeAudioContext.state}close(){return"closed"===this.state?this._nativeAudioContext.close().then(()=>{throw t()}):("suspended"===this._state&&(this._state=null),this._nativeAudioContext.close())}createMediaElementSource(e){return new o(this,{mediaElement:e})}createMediaStreamDestination(){return new a(this)}createMediaStreamSource(e){return new i(this,{mediaStream:e})}createMediaStreamTrackSource(e){return new s(this,{mediaStreamTrack:e})}resume(){return"suspended"===this._state?new Promise((e,t)=>{const n=()=>{this._nativeAudioContext.removeEventListener("statechange",n),"running"===this._nativeAudioContext.state?e():this.resume().then(e,t)};this._nativeAudioContext.addEventListener("statechange",n)}):this._nativeAudioContext.resume().catch(e=>{if(void 0===e||15===e.code)throw t();throw e})}suspend(){return this._nativeAudioContext.suspend().catch(e=>{if(void 0===e)throw t();throw e})}})(Er,Mt,Lt,()=>{try{return new DOMException("","UnknownError")}catch(e){return e.name="UnknownError",e}},Pr,Dr,Rr,Vr,en);(e=>{null===e||e.hasOwnProperty("AudioWorkletNode")&&e.AudioWorkletNode})($t);var Fr,Lr;!function(e){e.INIT="INIT",e.PLAYING="PLAYING",e.STOPPED="STOPPED",e.PAUSED="PAUSED"}(Fr||(Fr={})),function(e){e.STATE_CHANGE="state-change",e.ITERATION="iteration"}(Lr||(Lr={}));return class{constructor(e=new Br,t=new L){this.defaultBpm=100,this.scoreInstruments=[],this.ready=!1,this.ac=e,this.ac.suspend(),this.instrumentPlayer=t,this.instrumentPlayer.init(this.ac),this.availableInstruments=this.instrumentPlayer.instruments,this.events=new X,this.cursor=null,this.sheet=null,this.denominator=null,this.scheduler=null,this.iterationSteps=0,this.currentIterationStep=0,this.timeoutHandles=[],this.playbackSettings={bpm:this.defaultBpm,masterVolume:1},this.setState(Fr.INIT)}get wholeNoteLength(){return Math.round(60/this.playbackSettings.bpm*this.denominator*1e3)}getPlaybackInstrument(e){if(!this.sheet)return null;const t=this.sheet.Instruments.flatMap(e=>e.Voices).find(t=>t.VoiceId===e);return this.availableInstruments.find(e=>e.midiId===t.midiInstrumentId)}setInstrument(t,n){return e(this,void 0,void 0,(function*(){yield this.instrumentPlayer.load(n),t.midiInstrumentId=n}))}loadScore(t){return e(this,void 0,void 0,(function*(){this.ready=!1,this.sheet=t.Sheet,this.scoreInstruments=this.sheet.Instruments,this.cursor=t.cursor,this.denominator=this.sheet.SheetPlaybackSetting.rhythm.Denominator,this.sheet.HasBPMInfo&&this.setBpm(this.sheet.DefaultStartTempoInBpm),yield this.loadInstruments(),this.initInstruments(),this.scheduler=new n(this.denominator,this.wholeNoteLength,this.ac,(e,t)=>this.notePlaybackCallback(e,t)),this.countAndSetIterationSteps(),this.ready=!0,this.setState(Fr.STOPPED)}))}initInstruments(){for(const e of this.sheet.Instruments)for(const t of e.Voices)t.midiInstrumentId=e.MidiInstrumentId}loadInstruments(){return e(this,void 0,void 0,(function*(){let e=[];for(const t of this.sheet.Instruments){null==this.availableInstruments.find(e=>e.midiId===t.MidiInstrumentId)&&this.fallbackToPiano(t),e.push(this.instrumentPlayer.load(t.MidiInstrumentId))}yield Promise.all(e)}))}fallbackToPiano(e){if(console.warn(`Can't find playback instrument for midiInstrumentId ${e.MidiInstrumentId}. Falling back to piano`),e.MidiInstrumentId=0,null==this.availableInstruments.find(e=>0===e.midiId))throw new Error("Piano fallback failed, grand piano not supported")}play(){return e(this,void 0,void 0,(function*(){yield this.ac.resume(),this.state!==Fr.INIT&&this.state!==Fr.STOPPED||this.cursor.show(),this.setState(Fr.PLAYING),this.scheduler.start()}))}stop(){return e(this,void 0,void 0,(function*(){this.setState(Fr.STOPPED),this.stopPlayers(),this.clearTimeouts(),this.scheduler.reset(),this.cursor.reset(),this.currentIterationStep=0,this.cursor.hide()}))}pause(){this.setState(Fr.PAUSED),this.ac.suspend(),this.stopPlayers(),this.scheduler.setIterationStep(this.currentIterationStep),this.scheduler.pause(),this.clearTimeouts()}jumpToStep(e){for(this.pause(),this.currentIterationStep>e&&(this.cursor.reset(),this.currentIterationStep=0);this.currentIterationStep0&&this.currentIterationStepthis.iterationCallback(),Math.max(0,1e3*e-35)),window.setTimeout(()=>this.events.emit(Lr.ITERATION,t),1e3*e))}setState(e){this.state=e,this.events.emit(Lr.STATE_CHANGE,e)}stopPlayers(){for(const e of this.sheet.Instruments)for(const t of e.Voices)this.instrumentPlayer.stop(t.midiInstrumentId)}clearTimeouts(){for(let e of this.timeoutHandles)clearTimeout(e);this.timeoutHandles=[]}iterationCallback(){this.state===Fr.PLAYING&&(this.currentIterationStep>0&&this.cursor.next(),++this.currentIterationStep)}}}));
16 |
--------------------------------------------------------------------------------