[
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "Bug fixes and contributions are welcome!\n\nIf you're looking for ideas for where to get started, consider jumping in on any of these areas:\n\n### Examples\n\nTo contribute examples, please follow the current style of the examples. Add your example's title and file name to `examples/js/ExampleList.json` for it to appear in the examples list on the index page.\n\n### Docs\n\nThere is always more work that can be done on documentation. Especially adding good examples to methods and members to make the docs more informative and useful for people coming from diverse musical and technical backgrounds.\n\nAll of the docs are written in [TypeDoc](https://typedoc.org/)-style comments in the source code. If you catch a mistake, please send a pull request.\n\nAlong with this, it'd be great to integrate more visuals and references in the docs to help illustrate concepts.\n\n### Forum\n\nIf you are someone who is familiar with Tone.js, consider jumping in on [the forum](https://groups.google.com/forum/#!forum/tonejs) to answer some questions.\n\n### Tutorials\n\nI'd love to see more tutorials for newcomers to Tone.js to help them get up and running or solve a particular issue. If you make a tutorial, please send me a link.\n\n### Tests\n\nTone.js has an extensive [test suite](https://github.com/Tonejs/Tone.js/wiki/Testing) using Mocha and Chai.\n\nAlong with more unit tests, it'd also be great to have more tests which run in the online context and generate music to help find bugs by ear that the automated tests might not illuminate. [Audiokit](http://audiokit.io/tests/), for example, has a great suite of aural tests.\n\nYou can also take a look at Tone.js' [code coverage](https://coveralls.io/github/Tonejs/Tone.js) to get an idea of where more tests might be helpful.\n\n### Synths/Effects\n\nIf you'd like to contribute a cool and expressive synth or effect, I'd love to hear it. Please send me an example that I can play with along with the PR.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Report an issue with Tone.js\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\n\nA description of what the bug is. \n\nFor help questions, check out the [forum](https://groups.google.com/forum/#!forum/tonejs).\n\nNote: Browsers' [Autoplay Policy](https://github.com/Tonejs/Tone.js/wiki/Autoplay) leads to a lot of subtle and inconsistent bugs where Tone.js produces no sound. Check out the link for more information and the solution.\n\nIf you are experiencing loose or inaccurate timing, double check that you are [correctly scheduling events](https://github.com/Tonejs/Tone.js/wiki/Accurate-Timing).\n\n\n**To Reproduce**\n\nPlease include a way to reproduce your issue. If possible, please includes a link to some example code using a platform like jsfiddle or codesandbox where the code can be edited. This makes it much easier to debug the issue and also create a validation test to verify the bug was fixed. \n\n**Expected behavior**\nA description of what you expected to happen.\n\n**What I've tried**\nHow have you tried resolving/debugging this issue? This can be helpful context for getting to the heart of the issue faster and not duplicating effort. \n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: feature request\nassignees: ''\n\n---\n\n**The feature you'd like**\nA description of a module or method which you'd like to be included in Tone.js\n\n**Any alternatives you've considered**\nAre there existing modules or methods within Tone.js which can be combined to do the same thing? Are there other libraries or reference implementations which do a similar thing? \n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n\n**Feature Requests will eventually be closed if inactive**\nConsider submitted a Pull Request for the feature you want. If no one addresses your feature, it will eventually be closed due to inactivity. Though, someone could always implement your feature request after it's closed. Closing issues automatically keeps features requests from piling up.\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "1. Please make all pull requests on the `dev` branch.\n2. Don't commit build files\n2. Try to get all [tests](https://github.com/Tonejs/Tone.js/wiki/Testing) to pass.\n\n\n"
  },
  {
    "path": ".github/codecov.yml",
    "content": "coverage:\n  status:\n    project:\n      default:\n        target: auto\n        threshold: 1%"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "name: \"Close stale issues and PRs\"\non:\n    schedule:\n        - cron: \"30 1 * * *\"\n\njobs:\n    stale:\n        runs-on: ubuntu-latest\n        steps:\n            - uses: actions/stale@v9\n              with:\n                  any-of-labels: \"cant reproduce\"\n                  stale-issue-message: \"Please provide a way to reproduce the issue. Issues without a minimal (Tone.js-only) repro will be closed. A Tone.js-only repro helps ensure that the issue is not caused by another library.\"\n                  days-before-close: 7\n                  days-before-stale: 14\n            - uses: actions/stale@v9\n              with:\n                  any-of-labels: \"feature request\"\n                  stale-issue-message: \"Unfortunately with limited development time, not all feature requests can be tackled. If you are interested in contributing this feature, please open a PR.\"\n                  days-before-close: 30\n                  days-before-stale: 90\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Tests\n\non:\n    pull_request:\n        types: [opened, reopened, synchronize]\n        branches:\n            - dev\n            - main\n    push:\n        branches:\n            - dev\n            - main\n\njobs:\n    test-conventional-commit:\n        name: Validate PR title\n        runs-on: ubuntu-latest\n        permissions:\n            pull-requests: read\n        steps:\n            - uses: amannn/action-semantic-pull-request@v6\n              env:\n                  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n              # only on PRs\n              if: github.event_name == 'pull_request'\n    run-tests:\n        name: All tests\n        permissions:\n            contents: read\n            id-token: write\n        runs-on: ubuntu-latest\n        needs: [test-conventional-commit]\n        env:\n            BROWSER: chrome\n            CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}\n        steps:\n            - name: Check out Git repository\n              uses: actions/checkout@v4\n            - name: Setup Nodejs\n              uses: actions/setup-node@v4\n              with:\n                  node-version: 22.12.0\n                  cache: \"npm\"\n            - name: Install dependencies\n              run: npm install\n            - name: All tests\n              run: npm run test\n            - name: Upload coverage\n              uses: codecov/codecov-action@v5\n              with:\n                  fail_ci_if_error: false\n                  codecov_yml_path: ./.github/codecov.yml\n                  token: ${{ secrets.CODECOV_TOKEN }}\n    test-code-examples:\n        name: Check typedocs\n        permissions:\n            contents: read\n            id-token: write\n        runs-on: ubuntu-latest\n        needs: [test-conventional-commit]\n        steps:\n            - name: Check out Git repository\n              uses: actions/checkout@v4\n            - name: Setup Nodejs\n              uses: actions/setup-node@v4\n              with:\n                  node-version: 22.12.0\n                  cache: \"npm\"\n            - name: Install dependencies\n              run: npm install\n            - name: Build Docs\n              run: npm run build && npm run docs:json\n            - name: tsdoc @example checks\n              run: npm run test:examples\n    test-html-examples:\n        name: Run HTML Examples\n        permissions:\n            contents: read\n            id-token: write\n        runs-on: ubuntu-latest\n        needs: [test-conventional-commit]\n        steps:\n            - name: Check out Git repository\n              uses: actions/checkout@v4\n            - name: Setup Nodejs\n              uses: actions/setup-node@v4\n              with:\n                  node-version: 22.12.0\n                  cache: \"npm\"\n            - name: Install dependencies\n              run: npm install\n            - name: Build\n              run: npm run build\n            - name: Code example tests\n              run: npm run test:html\n    test-lint:\n        name: Linting and environment checks\n        permissions:\n            contents: read\n            id-token: write\n        runs-on: ubuntu-latest\n        needs: [test-conventional-commit]\n        steps:\n            - name: Check out Git repository\n              uses: actions/checkout@v4\n            - name: Setup Nodejs\n              uses: actions/setup-node@v4\n              with:\n                  node-version: 22.12.0\n                  cache: \"npm\"\n            - name: Install dependencies\n              run: npm install\n            - name: Linting\n              run: npm run lint\n            - name: Spell check\n              run: npm run spellcheck\n    test-readme:\n        name: Ensure that examples in the README compile\n        permissions:\n            contents: read\n            id-token: write\n        runs-on: ubuntu-latest\n        needs: [test-conventional-commit]\n        steps:\n            - name: Check out Git repository\n              uses: actions/checkout@v4\n            - name: Setup Nodejs\n              uses: actions/setup-node@v4\n              with:\n                  node-version: 22.12.0\n                  cache: \"npm\"\n            - name: Install dependencies\n              run: npm install\n            - name: Build\n              run: npm run build\n            - name: Test\n              run: npm run test:readme\n    test-integrations:\n        name: Test integrations\n        permissions:\n            contents: read\n            id-token: write\n        runs-on: ubuntu-latest\n        needs: [test-conventional-commit]\n        steps:\n            - name: Check out Git repository\n              uses: actions/checkout@v4\n            - name: Setup Nodejs\n              uses: actions/setup-node@v4\n              with:\n                  node-version: 22.12.0\n                  cache: \"npm\"\n            - name: Install dependencies\n              run: npm install\n            - name: Build\n              run: npm run build\n            - name: Test\n              run: npm run test:integrations\n    publish:\n        runs-on: ubuntu-latest\n        permissions:\n            contents: read\n            id-token: write\n        # make sure all the tests pass first\n        needs:\n            [\n                run-tests,\n                test-code-examples,\n                test-html-examples,\n                test-lint,\n                test-readme,\n                test-integrations,\n            ]\n        # not on PRs\n        if: github.event_name != 'pull_request'\n        env:\n            GITHUB_CI: true\n        steps:\n            - uses: actions/checkout@v5\n            - uses: actions/setup-node@v6\n              with:\n                  node-version: 24\n                  registry-url: \"https://registry.npmjs.org\"\n            # Need to unset this in order to use OICD\n            - name: Unset NODE_AUTH_TOKEN\n              run: unset NODE_AUTH_TOKEN\n            - name: Install dependencies\n              run: npm install\n            - name: Build\n              run: npm run build\n            - name: Increment version\n              run: npm run increment\n            - name: Publish @next\n              # dev branch gets published with @next tag\n              run: npm publish --tag next --provenance --access public\n              if: ${{ github.ref == 'refs/heads/dev' }}\n            - name: Publish @latest\n              # main branch gets published with @latest tag\n              run: npm publish --provenance --access public\n              if: ${{ github.ref == 'refs/heads/main' }}\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n*.asd\n*.scssc\n*.sublime-workspace\n*.sublime-project\n\nnode_modules\n\nTODO.txt\nwiki\n\nexamples/scratch.html\nexamples/deps/FileSaver.js\nexamples/oscilloscope.html\nexamples/graph.html\n\ntest/performance\ntest/mainTest.js\ntest/Main.js\ntest/supports.html\ncoverage/\n\nbuild/*\n**/dist/*\n\nexamples/scratch.js\nexamples/scratch.ts\nTone/version.js\nTone/version.ts\nTone/index.js\ntest/test.js\n\ndocs\n.vscode\ntone.d.ts\nexamples/scratch.ts\ntest/integration/*/package-lock.json\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# 15.0.x\n\n-   `set` in constructor even if AudioBuffer is not from std-audio-context ([0399687](https://github.com/Tonejs/Tone.js/commit/0399687)), closes [#991](https://github.com/Tonejs/Tone.js/issues/991)\n-   ability to mute a sequence ([ac856bc](https://github.com/Tonejs/Tone.js/commit/ac856bc)), closes [#823](https://github.com/Tonejs/Tone.js/issues/823)\n-   Add `\"type\": \"module\"` to `package.json` ([69055ba](https://github.com/Tonejs/Tone.js/commit/69055ba))\n-   Add back `main` as ESM build ([8cc6e8a](https://github.com/Tonejs/Tone.js/commit/8cc6e8a))\n-   Add Pattern.index ([205c438](https://github.com/Tonejs/Tone.js/commit/205c438))\n-   Add test for duplicate events ([d5c8a25](https://github.com/Tonejs/Tone.js/commit/d5c8a25))\n-   adding @category definitions for docs, fixing some typos/mistakes along the way ([0e2b5b9](https://github.com/Tonejs/Tone.js/commit/0e2b5b9))\n-   adding createMediaElementSource ([301f8cd](https://github.com/Tonejs/Tone.js/commit/301f8cd)), closes [#756](https://github.com/Tonejs/Tone.js/issues/756)\n-   Allow instrument and PolySynth to be scheduled to the transport stop/loop events ([954a4fc](https://github.com/Tonejs/Tone.js/commit/954a4fc)), closes [#924](https://github.com/Tonejs/Tone.js/issues/924)\n-   allow worklet-based effects to be used with native contexts (#1131) ([f06ff17](https://github.com/Tonejs/Tone.js/commit/f06ff17)), closes [#1131](https://github.com/Tonejs/Tone.js/issues/1131)\n-   Analyser constructor smoothing option bug fix ([afb5284](https://github.com/Tonejs/Tone.js/commit/afb5284))\n-   bumping standardized-audio-context version ([cbdb596](https://github.com/Tonejs/Tone.js/commit/cbdb596))\n-   Chebyshev order must be an integer ([4f9aece](https://github.com/Tonejs/Tone.js/commit/4f9aece)), closes [#844](https://github.com/Tonejs/Tone.js/issues/844)\n-   correctly offset phase for each oscillator ([0ac1da5](https://github.com/Tonejs/Tone.js/commit/0ac1da5)), closes [#733](https://github.com/Tonejs/Tone.js/issues/733)\n-   custom decay curve #1107 ([d463286](https://github.com/Tonejs/Tone.js/commit/d463286)), closes [#1107](https://github.com/Tonejs/Tone.js/issues/1107)\n-   Don't reschedule source when offset is very small ([444d617](https://github.com/Tonejs/Tone.js/commit/444d617)), closes [#999](https://github.com/Tonejs/Tone.js/issues/999) [#944](https://github.com/Tonejs/Tone.js/issues/944)\n-   Export remaining effect option interfaces (#1293) ([2b8039b](https://github.com/Tonejs/Tone.js/commit/2b8039b)), closes [#1293](https://github.com/Tonejs/Tone.js/issues/1293)\n-   exporting Mono ([8b996bc](https://github.com/Tonejs/Tone.js/commit/8b996bc)), closes [#765](https://github.com/Tonejs/Tone.js/issues/765)\n-   fix the wrong variable name 'event' in Emitter.ts ([46bd717](https://github.com/Tonejs/Tone.js/commit/46bd717))\n-   Garbage collect nodes used for Transport syncing ([a392067](https://github.com/Tonejs/Tone.js/commit/a392067))\n-   increasing attack/release above 0 to avoid distortion ([b39883e](https://github.com/Tonejs/Tone.js/commit/b39883e)), closes [#770](https://github.com/Tonejs/Tone.js/issues/770)\n-   latest std-audio-context ([8915e1b](https://github.com/Tonejs/Tone.js/commit/8915e1b)), closes [#720](https://github.com/Tonejs/Tone.js/issues/720)\n-   Less verbose unit types (#1181) ([9353d33](https://github.com/Tonejs/Tone.js/commit/9353d33)), closes [#1181](https://github.com/Tonejs/Tone.js/issues/1181)\n-   Load only a single AudioWorklet ([75a802c](https://github.com/Tonejs/Tone.js/commit/75a802c))\n-   Memoize getTicksAtTime and getSecondsAtTime ([da73385](https://github.com/Tonejs/Tone.js/commit/da73385))\n-   Parse note strings with three sharps or flats. ([5cd3560](https://github.com/Tonejs/Tone.js/commit/5cd3560))\n-   pass in partials to LFO ([fdc7eb4](https://github.com/Tonejs/Tone.js/commit/fdc7eb4)), closes [#814](https://github.com/Tonejs/Tone.js/issues/814)\n-   polysynth does not reschedule event if disposed ([e3a611f](https://github.com/Tonejs/Tone.js/commit/e3a611f))\n-   Recorder resumes if start() is called in paused state (#1266) ([ead4f21](https://github.com/Tonejs/Tone.js/commit/ead4f21)), closes [#1266](https://github.com/Tonejs/Tone.js/issues/1266)\n-   remove implicit \"stop\" scheduling ([0b7a352](https://github.com/Tonejs/Tone.js/commit/0b7a352)), closes [#778](https://github.com/Tonejs/Tone.js/issues/778)\n-   Reverb input string time (#1313) ([bf3ee91](https://github.com/Tonejs/Tone.js/commit/bf3ee91)), closes [#1313](https://github.com/Tonejs/Tone.js/issues/1313) [#1253](https://github.com/Tonejs/Tone.js/issues/1253)\n-   Reverse Emitter off callback loop for correct removal of duplicate events ([b5f582e](https://github.com/Tonejs/Tone.js/commit/b5f582e))\n-   Revert \"fix for AudioBufferSourceNode stop time miscalculation\" ([e1c6631](https://github.com/Tonejs/Tone.js/commit/e1c6631))\n-   Smooth RMS values per channel in Meter ([45d2009](https://github.com/Tonejs/Tone.js/commit/45d2009)), closes [#882](https://github.com/Tonejs/Tone.js/issues/882)\n-   throws error when polysynth is used with a non monophonic class ([4f5353e](https://github.com/Tonejs/Tone.js/commit/4f5353e)), closes [#939](https://github.com/Tonejs/Tone.js/issues/939)\n-   use now() instead of currentTime ([9e9b3d2](https://github.com/Tonejs/Tone.js/commit/9e9b3d2))\n-   Use reciprocal of tempo when syncing time signals to Transport ([64c8a29](https://github.com/Tonejs/Tone.js/commit/64c8a29)), closes [#879](https://github.com/Tonejs/Tone.js/issues/879)\n-   Using web-test-runner for tests, updating import paths (#1242) ([aaf880c](https://github.com/Tonejs/Tone.js/commit/aaf880c)), closes [#1242](https://github.com/Tonejs/Tone.js/issues/1242)\n-   warn if event is scheduled without using the scheduled time. ([6dd22e7](https://github.com/Tonejs/Tone.js/commit/6dd22e7)), closes [#959](https://github.com/Tonejs/Tone.js/issues/959)\n-   fix: load base64 encoded sounds when baseUrl is not empty ([a771811](https://github.com/Tonejs/Tone.js/commit/a771811)), closes [#898](https://github.com/Tonejs/Tone.js/issues/898)\n-   fix: loading non relative URLs ([f7bdff0](https://github.com/Tonejs/Tone.js/commit/f7bdff0))\n-   feat: sub-tick scheduling ([33e14d0](https://github.com/Tonejs/Tone.js/commit/33e14d0))\n\n### BREAKING CHANGES\n\n-   Deprecating singleton variables, use singleton getter instead (#1233) ([3d42017](https://github.com/Tonejs/Tone.js/commit/3d42017)), closes [#1233](https://github.com/Tonejs/Tone.js/issues/1233)\n-   Removing double-encoding of urls (#1254) ([de086f5](https://github.com/Tonejs/Tone.js/commit/de086f5)), closes [#1254](https://github.com/Tonejs/Tone.js/issues/1254)\n\n# 14.7.x\n\n### Features\n\n-   **Converted to typescript!!!**\n-   adding AudioWorkletNode constructors to Context ([f7bdd75](https://github.com/Tonejs/Tone.js/commit/f7bdd75))\n-   adding ability to get the frequency at the FFT index ([22cecdc](https://github.com/Tonejs/Tone.js/commit/22cecdc281c8076c054affaef9dc422665acda2e))\n-   adding AudioWorkletNode constructors to Context ([f7bdd75](https://github.com/Tonejs/Tone.js/commit/f7bdd7528fa9549740dc514df6308303c060e091))\n-   adding BiquadFilter ([75617d3](https://github.com/Tonejs/Tone.js/commit/75617d341fe44ca5d332ea4e547f07c266a54753)), closes [#686](https://github.com/Tonejs/Tone.js/issues/686)\n-   adding linting to jsdocs ([10ef513](https://github.com/Tonejs/Tone.js/commit/10ef513))\n-   adding send/receive to Channel ([703f27a](https://github.com/Tonejs/Tone.js/commit/703f27a))\n-   Adding triggerRelease to PluckSynth ([04405af](https://github.com/Tonejs/Tone.js/commit/04405af))\n-   Can set the parameter after constructing Param ([23ca0f9](https://github.com/Tonejs/Tone.js/commit/23ca0f9))\n-   adding onerror to Sampler ([7236600](https://github.com/Tonejs/Tone.js/commit/7236600182d336d6598f86d7d7afe8761e733774)), closes [#605](https://github.com/Tonejs/Tone.js/issues/605)\n-   Chorus extends StereoFeedbackEffect ([a28f1af](https://github.com/Tonejs/Tone.js/commit/a28f1af)), closes [#575](https://github.com/Tonejs/Tone.js/issues/575)\n-   Convolver is just a wrapper around the ConvolverNode, no longer an effect ([1668dec](https://github.com/Tonejs/Tone.js/commit/1668dec))\n-   Get an oscillator wave as an array ([9ad519e](https://github.com/Tonejs/Tone.js/commit/9ad519e))\n-   OfflineContext returns a ToneAudioBuffer ([889dafa](https://github.com/Tonejs/Tone.js/commit/889dafa))\n-   OfflineContext yields thread every second of audio rendered ([1154470](https://github.com/Tonejs/Tone.js/commit/1154470)), closes [#436](https://github.com/Tonejs/Tone.js/issues/436)\n-   Renaming TransportTimelineSignal to SyncedSignal ([86853fb](https://github.com/Tonejs/Tone.js/commit/86853fb))\n-   es6 output ([e5d28ba](https://github.com/Tonejs/Tone.js/commit/e5d28baa5f02c19a6f1c8c50c99e98bd1551d15b))\n-   Render a segment of the envelope as an array ([fc5b6f7](https://github.com/Tonejs/Tone.js/commit/fc5b6f7))\n-   testing examples in jsdocs ([e306319](https://github.com/Tonejs/Tone.js/commit/e306319))\n-   Wrapper around the AudioWorkletNode ([2ee8cb1](https://github.com/Tonejs/Tone.js/commit/2ee8cb1))\n-   Input/Outputs are no longer arrays.\n    -   simplifies connect/disconnect logic greatly. Simplifies API to just have clearly named inputs/outputs instead of overloading input/output connect numbers\n-   Using \"Destination\" instead of \"Master\" for output\n    -   More consistent with Web Audio API\n-   FrequencyShifter - thanks @Foaly\n-   PolySynth does not require a polyphony value.\n    -   Voice allocation and disposing is done automatically based on demand.\n-   MetalSynth and MembraneSynth extends Monophonic enabling them to be used in PolySynth\n-   OnePoleFilter is a 6b-per-octave lowpass or highpass filter\n    -   Using OnePoleFilter in PluckSynth and LowpassCombFilter\n-   latencyHint is now set in constructor ([ba8e82b](https://github.com/Tonejs/Tone.js/commit/ba8e82b1ca8a841a23d6e774641916019c37cc92)), closes [#658](https://github.com/Tonejs/Tone.js/issues/658)\n-   meter output can be normalRange in addition to decibels ([2625a13](https://github.com/Tonejs/Tone.js/commit/2625a134b62af117c1c525a4e631e4e52b25ba90))\n-   option to pass in the number of input channels to Panner ([d966735](https://github.com/Tonejs/Tone.js/commit/d966735bd97bddc70039bce5a48f26413054eddc)), closes [#609](https://github.com/Tonejs/Tone.js/issues/609)\n\n### BREAKING CHANGES\n\n-   TransportTimelineSignal renamed SyncedSignal\n-   Master renamed Destination\n-   Buffer renamed ToneAudioBuffer\n-   Buffer.on(\"loaded\") is should now use: `Tone.loaded(): Promise<void>`\n-   Removing bower ([71c8b3b](https://github.com/Tonejs/Tone.js/commit/71c8b3bbb96e45cfc4aa2cce8a2d8c61a092c91e)), closes [#197](https://github.com/Tonejs/Tone.js/issues/197)\n-   Removing Ctrl classes ([51d06bd](https://github.com/Tonejs/Tone.js/commit/51d06bd9873b2f1936a3169930f9696f1ccfb845))\n-   `Players.get(name: string)` is renamed to `Players.player(name: string)`\n\n# 13.8.25\n\n-   Moving to common.js-style code\n\n### BREAKING CHANGES\n\n-   AudioNode.prototype.connect is no longer overwritten. This means that you can no longer connect native nodes to Tone.js Nodes.\n-   Tone.connect(srcNode, destNode, [ouputNum], [inputNum]) is the way to connect native Web Audio nodes with Tone.js nodes.\n\n# 13.4.9\n\n-   Updating semantic versioning to be more in line with other [semvers](https://semver.org/). Now version is 13.x.x\n-   logging full version\n-   Added Object notation for Tone.TimeBase and classes that extend it.\n    -   i.e. Tone.Time({'4n' : 1, '8t' : 2})\n    -   Replacement for deprecated expression strings.\n-   Tone.Meter uses RMS instead of peak (thanks [@Idicious](https://github.com/Idicious))\n-   Tone.Sampler supports polyphonic syntax (thanks [@zfan40](https://github.com/zfan40))\n-   Building files with [webpack](https://webpack.js.org/)\n-   Follower/Gate uses a single \"smoothing\" value instead of separate attacks and releases\n-   Changing references to `window` allowing it to not throw error in node context\n-   Testing examples\n-   Tone.Channel combines Tone.PanVol with Tone.Solo.\n-   Removing require.html example.\n-   adding `partialCount` and `baseType` to Oscillator classes, helps with getting/setting complex types.\n\n# r12\n\n-   Consolidating all shims into [shim folder](https://github.com/Tonejs/Tone.js/tree/dev/Tone/shim)\n-   Using ConstantSourceNode in Signal when available\n-   switching to eslint from jshint\n-   Running [CI tests](https://travis-ci.org/Tonejs/Tone.js/) on Firefox, Chrome (latest and canary) and Safari (latest and version 9).\n-   [Tone.Reverb](https://tonejs.github.io/docs/Reverb) is a convolution-based stereo reverb. [Example](https://tonejs.github.io/examples/#reverb).\n-   Optimizing basic Oscillator types and many Signal use-case\n-   Optimizing basic connection use-case of Tone.Signal where one signal is controlling another signal\n-   Testing rendered output against an existing audio file for continuity and consistency\n-   Optimizing triggerAttack/Release by starting/stopping oscillators when not playing\n-   [TickSource](https://tonejs.github.io/docs/TickSource) (used in Clock and Player) tracks the elapsed ticks\n    -   Improved precision of tracking ticks in Transport and Clock\n-   `Player.position` returns the playback position of the AudioBuffer accounting for any playbackRate changes\n-   Removing `retrigger` option with Tone.Player. Tone.BufferSource should be used if retriggering is desired.\n\n**BREAKING CHANGES:**\n\n-   Tone.TimeBase and all classes that extend it not longer support string expressions.\n    RATIONALE :\n    _ Since all classes implement `valueOf`, expressions can be composed in JS instead of as strings\n    _ e.g. `Time('4n') * 2 + Time('3t')` instead of `Time('4n * 2 + 3t')` \\* this change greatly simplifies the code and is more performant\n\n# r11\n\n-   [Code coverage](https://coveralls.io/github/Tonejs/Tone.js) analysis\n-   [Dev build](https://tonejs.github.io/build/dev/Tone.js) with each successful commit\n-   [Versioned docs](https://tonejs.github.io/docs/Tone) plus a [dev build of the docs](https://tonejs.github.io/docs/dev/Tone) on successful commits\n-   [Tone.AudioNode](https://tonejs.github.io/docs/AudioNode) is base class for all classes which generate or process audio\n-   [Tone.Sampler](https://tonejs.github.io/docs/Sampler) simplifies creating multisampled instruments\n-   [Tone.Solo](https://tonejs.github.io/docs/Solo) makes it easier to mute/solo audio\n-   [Mixer](https://tonejs.github.io/examples/#mixer) and [sampler](https://tonejs.github.io/examples/#sampler) examples\n-   Making type-checking methods static\n-   [Tone.TransportTimelineSignal](https://tonejs.github.io/docs/TransportTimelineSignal) is a signal which can be scheduled along the Transport\n-   [Tone.FFT](https://tonejs.github.io/docs/FFT) and [Tone.Waveform](https://tonejs.github.io/docs/Waveform) abstract Tone.Analyser\n-   [Tone.Meter](https://tonejs.github.io/docs/Meter) returns decibels\n-   [Tone.Envelope](https://tonejs.github.io/docs/Envelope) uses exponential approach instead of exponential curve for decay and release curves\n-   [Tone.BufferSource](https://tonejs.github.io/docs/BufferSource) fadeIn/Out can be either \"linear\" or \"exponential\" curve\n\n# r10\n\n-   Tone.Context wraps AudioContext\n-   Tone.OfflineContext wraps OfflineAudioContext\n-   Tone.Offline: method for rendering audio offline\n-   Rewriting tests with Tone.Offline\n-   Optimizing Tone.Draw to only loop when events are scheduled: [#194](https://github.com/Tonejs/Tone.js/issues/194)\n-   Time.eval->valueOf which takes advantage of build-in primitive evaluation [#205](https://github.com/Tonejs/Tone.js/issues/205)\n-   [Offline example](https://tonejs.github.io/examples/#offline)\n\n# r9\n\n-   Tone.Clock performance and lookAhead updates.\n-   Tone.Transport.lookAhead = seconds|'playback'|'interactive'|'balanced'\n-   Convolver.load and Player.load returns Promise\n-   Tone.ExternalInput -> Tone.UserMedia, simplified API, open() returns Promise.\n-   Tone.Draw for animation-frame synced drawing\n-   Compressor Parameters are now Tone.Params\n-   Bug fixes\n\n# r8\n\n-   Transport.seconds returns the progress in seconds.\n-   Buffer.from/toArray, Float32Array <-> Buffer conversions\n-   Buffer.slice(start, end) slices and returns a subsection of the Buffer\n-   Source.sync now syncs all subsequent calls to `start` and `stop` to the TransportTime instead of the AudioContext time.\n    -   e.g. source.sync().start(0).stop(0.8); //plays source between 0 and 0.8 of the Transport\n-   Transport.on(\"start\" / \"stop\") callbacks are invoked just before the event.\n-   Param can accept an LFO description in the constructor or .value\n    -   e.g. param.value = {min : 10, max : 20, frequency : 0.4}\n-   Time.TimeBase has clone/copy methods.\n-   Tone.Buffer.prototype.load returns Promise\n-   Using Tone.Delay and Tone.Gain everywhere\n-   Patch for Chrome 53+ issue of not correctly scheduling AudioParams with setValueAtTime\n-   Panner3D and Tone.Listener wrap native PannerNode and AudioListener to give 3D panning ability.\n\n# r7\n\n-   MetalSynth creates metallic, cymbal sounds\n-   DrumSynth -> MembraneSynth\n-   FMOscillator, AMOscillator types\n-   FatOscillator creates multiple oscillators and detunes them slightly\n-   FM, AM, Fat Oscillators incorporated into OmniOscillator\n-   Simplified FM and AM Synths and APIs\n-   Panner.pan is between -1,1 like the StereoPannerNode\n-   Pruned away unused (or little used) Signal classes.\n    -   All this functionality will be available when the AudioWorkerNode is introduced.\n-   Clock uses Web Workers instead of requestAnimationFrame which allows it to run in the background.\n-   Removed `startMobile`. Using [StartAudioContext](https://github.com/tambien/StartAudioContext) in examples.\n-   Automated test runner using [Travis CI](https://travis-ci.org/Tonejs/Tone.js/)\n-   Simplified NoiseSynth by removing filter and filter envelope.\n-   Added new timing primitive types: Time, Frequency, TransportTime.\n-   Switching parameter position of type and size in Tone.Analyser\n-   Tone.Meter uses Tone.Analyser instead of ScriptProcessorNode.\n-   Tone.Envelope has 5 new attack/release curves: \"sine\", \"cosine\", \"bounce\", \"ripple\", \"step\"\n-   Renamed Tone.SimpleSynth -> Tone.Synth\n-   Tone.Buffers combines multiple buffers\n-   Tone.BufferSource a low-level wrapper, and Tone.MultiPlayer which is good for multisampled instruments.\n-   Tone.GrainPlayer: granular synthesis buffer player.\n-   Simplified Sampler\n\nDEPRECATED:\n\n-   Removed SimpleFM and SimpleAM\n\n# r6\n\n-   Added PitchShift and Vibrato Effect.\n-   Added Timeline/TimelineState/TimelineSignal which keeps track of all scheduled state changes.\n-   Clock uses requestAnimationFrame instead of ScriptProcessorNode\n-   Removed `onended` event from Tone.Source\n-   Refactored tests into individual files.\n-   Renamed some Signal methods: `exponentialRampToValueNow`->`exponentialRampToValue`, `setCurrentValueNow`->`setRampPoint`\n-   LFO no longer starts at bottom of cycle. Starts at whatever phase it's set at.\n-   Transport is an event emitter. triggers events on \"start\", \"stop\", \"pause\", and \"loop\".\n-   Oscillator accepts a \"partials\" array.\n-   Microphone inherits from ExternalInput which is generalized for different inputs.\n-   New scheduling methods on Transport - `schedule`, `scheduleOnce`, and `scheduleRepeat`.\n-   Tone.Gain and Tone.Delay classes wrap the native Web Audio nodes.\n-   Moved [MidiToScore](https://github.com/Tonejs/MidiConvert) and [TypeScript](https://github.com/Tonejs/TypeScript) definitions to separate repos.\n-   Tone.Param wraps the native AudioParam and allows for unit conversion.\n-   Quantization with Transport.quantize and using \"@\" in any Time. [Read more](https://github.com/Tonejs/Tone.js/wiki/Time).\n-   Control-rate generators for value interpolation, patterns, random numbers, and markov chains.\n-   schedulable musical events: Tone.Event, Tone.Loop, Tone.Part, Tone.Pattern, Tone.Sequence.\n-   Player's playbackRate is now a signal and Noise includes a playbackRate signal.\n-   All filterEnvelopes use new Tone.FrequencyEnvelope with frequency units and `baseFrequency` and `octaves` instead of `min` and `max`.\n-   Phaser uses \"octaves\" instead of \"depth\" to be more consistent across the whole Tone.js API.\n-   Presets now have [their own repo](https://github.com/Tonejs/Presets)\n\nDEPRECATED:\n\n-   `setTimeout`, `setInterval`, `setTimeline` in favor of new `schedule`, `scheduleOnce`, and `scheduleRepeat`.\n-   Tone.Signal no longer takes an AudioParam in the first argument. Use Tone.Param instead.\n-   Tone.Buffer.onload/onprogress/onerror is deprecated. Use `Tone.Buffer.on(\"load\", callback)` instead.\n\n# r5\n\n-   reverse buffer for Player and Sampler.\n-   Tone.Volume for simple volume control in Decibels.\n-   Panner uses StereoPannerNode when available.\n-   AutoFilter and Tremolo effects.\n-   Made many attributes read-only. preventing this common type of error: `oscillator.frequency = 200` when it should be `oscillator.frequency.value = 200`.\n-   Envelope supports \"linear\" and \"exponential\" attack curves.\n-   Renamed Tone.EQ -> Tone.EQ3.\n-   Tone.DrumSynth makes kick and tom sounds.\n-   Tone.MidSideCompressor and Tone.MidSideSplit/Tone.MidSideMerge\n-   Tone.Oscillator - can specify the number of partials in the type: i.e. \"sine10\", \"triangle3\", \"square4\", etc.\n-   mute/unmute the master output: `Tone.Master.mute = true`.\n-   3 new simplified synths: SimpleSynth, SimpleAM and SimpleFM\n-   `harmonicity` is a signal-rate value for all instruments.\n-   expose Q in Phaser.\n-   unit conversions using Tone.Type for signals and LFO.\n-   [new docs](http://tonejs.org/docs)\n-   [updated examples](http://tonejs.org/examples)\n\n# r4\n\n-   `toFrequency` accepts notes by name (i.e. `\"C4\"`)\n-   Envelope no longer accepts exponential scaling, only Tone.ScaledEnvelope\n-   Buffer progress and load events which tracks the progress of all downloads\n-   Buffer only accepts a single url\n-   Sampler accepts multiple samples as an object.\n-   `setPitch` in sampler -> `setNote`\n-   Deprecated MultiSampler - use Sampler with PolySynth instead\n-   Added [cdn](http://cdn.tonejs.org/latest/Tone.min.js) - please don't use for production code\n-   Renamed DryWet to CrossFade\n-   Functions return `this` to allow for chaining. i.e. `player.toMaster().start(2)`.\n-   Added `units` to Signal class which allows signals to be set in terms of Tone.Time, Tone.Frequency, Numbers, or Decibels.\n-   Replaced set/get method with ES5 dot notation. i.e. `player.setVolume(-10)` is now `player.volume.value = -10`.\n    To ramp the volume use either `player.volume.linearRampToValueNow(-10, \"4n\")`, or the new `rampTo` method which automatically selects the ramp (linear|exponential) based on the type of data.\n-   set/get methods for all components\n-   syncSignal and unsyncSignal moved from Signal to Transport\n-   Add/Multiply/Subtract/Min/Max/GreaterThan/LessThan all extend Tone.Signal which allows them to be scheduled and automated just like Tone.Signal.\n-   Deprecated Tone.Divide and Tone.Inverse. They were more complicated than they were useful.\n\nBREAKING CHANGES:\n\nThe API has been changed consistently to use `.attribute` for getting and setting instead of `getAttribute` and `setAttribute` methods. The reasoning for this is twofold: firstly, Tone.Signal attributes were previously limited in their scheduling capabilities when set through a setter function. For exactly, it was not possible to do a setValueAtTime on the `bpm` of the Transport. Secondly, the new EcmaScript 5 getter/setter approach resembles the Web Audio API much more closely, which will make intermixing the two APIs even easier.\n\nIf you're using Sublime Text, one way to transition from the old API to the new one is with a regex find/replace:\nfind `Tone.Transport.setBpm\\((\\d+)\\)` and replace it with `Tone.Transport.bpm.value = $1`.\n\nOr if setBpm was being invoked with a rampTime:\nfind `Tone.Transport.setBpm\\((\\d+)\\, (\\d+)\\)` and replace it with `Tone.Transport.bpm.rampTo($1, $2)`.\n\n# r3\n\nCore Change:\n\n-   Swing parameter on Transport\n-   Player loop positions stay in tempo-relative terms even with tempo changes\n-   Envelope ASDR stay in tempo-relative terms even with tempo changes\n-   Modified build script to accommodate using requirejs with build and minified version\n\nSignal Processing:\n\n-   Tone.Expr: signal processing expression parser for Tone.Signal math\n-   All signal binary operators accept two signals as inputs\n-   Deprecated Tone.Threshold - new class Tone.GreaterThanZero\n-   NOT, OR, AND, and IfThenElse signal logic operators\n-   Additional signal classes: Inverse, Divide, Pow, AudioToGain, Subtract\n-   Scale no longer accepts input min/max. Assumes [0,1] range.\n-   Normalize class if scaling needs to happen from other input ranges\n-   WaveShaper function wraps the WaveShaperNode\n\nEffects:\n\n-   Distortion and Chebyshev distortion effects\n-   Compressor and MultibandCompressor\n-   MidSide effect type and StereoWidener\n-   Convolver effect and example\n\nSynths:\n\n-   Setters on PluckSynth and PulseOscillator\n-   new PWMOscillator\n-   OmniOscillator which combines PWMOscillator, Oscillator, and PulseOscillator into one\n-   NoiseSynth\n\n# r2\n\n-   PluckSynth - Karplus-Strong Plucked String modeling synth\n-   Freeverb\n-   John Chowning Reverb (JCReverb)\n-   LowpassCombFilter and FeedbackCombFilter\n-   Sampler with pitch control\n-   Clock tick callback is out of the audio thread using setTimeout\n-   Optimized Tone.Modulo\n-   Tests run using OfflineRenderingContext\n-   Fixed Transport bug where timeouts/intervals and timelines were on a different tick counter\n-   AmplitudeEnvelope + triggerAttackDecay on Envelope\n-   Instruments inherit from Tone.Instrument base-class\n-   midi<-->note conversions\n\n# r1 - First!\n"
  },
  {
    "path": "LICENSE.md",
    "content": "MIT License\n\nCopyright (c) 2014-2025 Yotam Mann\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Tone.js\n\n[![codecov](https://codecov.io/gh/Tonejs/Tone.js/branch/dev/graph/badge.svg)](https://codecov.io/gh/Tonejs/Tone.js)\n\nTone.js is a Web Audio framework for creating interactive music in the browser. The architecture of Tone.js aims to be familiar to both musicians and audio programmers creating web-based audio applications. On the high-level, Tone offers common DAW (digital audio workstation) features like a global transport for synchronizing and scheduling events as well as prebuilt synths and effects. Additionally, Tone provides high-performance building blocks to create your own synthesizers, effects, and complex control signals.\n\n-   [API](https://tonejs.github.io/docs/)\n-   [Examples](https://tonejs.github.io/examples/)\n\n# Installation\n\nThere are two ways to incorporate Tone.js into a project. First, it can be installed locally into a project using `npm`:\n\n```bash\nnpm install tone      // Install the latest stable version\nnpm install tone@next // Or, alternatively, use the 'next' version\n```\n\nAdd Tone.js to a project using the JavaScript `import` syntax:\n\n```js\nimport * as Tone from \"tone\";\n```\n\nTone.js is also hosted at unpkg.com. It can be added directly within an HTML document, as long as it precedes any project scripts. [See the example here](https://github.com/Tonejs/Tone.js/blob/master/examples/simpleHtml.html) for more details.\n\n```html\n<script src=\"http://unpkg.com/tone\"></script>\n```\n\n# Hello Tone\n\n```javascript\n//create a synth and connect it to the main output (your speakers)\nconst synth = new Tone.Synth().toDestination();\n\n//play a middle 'C' for the duration of an 8th note\nsynth.triggerAttackRelease(\"C4\", \"8n\");\n```\n\n## Tone.Synth\n\n`Tone.Synth` is a basic synthesizer with a single oscillator and an ADSR envelope.\n\n### triggerAttack / triggerRelease\n\n`triggerAttack` starts the note (the amplitude is rising), and `triggerRelease` is when the amplitude is going back to 0 (i.e. **note off**).\n\n```javascript\nconst synth = new Tone.Synth().toDestination();\nconst now = Tone.now();\n// trigger the attack immediately\nsynth.triggerAttack(\"C4\", now);\n// wait one second before triggering the release\nsynth.triggerRelease(now + 1);\n```\n\n### triggerAttackRelease\n\n`triggerAttackRelease` is a combination of `triggerAttack` and `triggerRelease`\n\nThe first argument to the note which can either be a frequency in hertz (like `440`) or as \"pitch-octave\" notation (like `\"D#2\"`).\n\nThe second argument is the duration that the note is held. This value can either be in seconds, or as a [tempo-relative value](https://github.com/Tonejs/Tone.js/wiki/Time).\n\nThe third (optional) argument of `triggerAttackRelease` is _when_ along the AudioContext time the note should play. It can be used to schedule events in the future.\n\n```javascript\nconst synth = new Tone.Synth().toDestination();\nconst now = Tone.now();\nsynth.triggerAttackRelease(\"C4\", \"8n\", now);\nsynth.triggerAttackRelease(\"E4\", \"8n\", now + 0.5);\nsynth.triggerAttackRelease(\"G4\", \"8n\", now + 1);\n```\n\n## Time\n\nWeb Audio has advanced, sample accurate scheduling capabilities. The AudioContext time is what the Web Audio API uses to schedule events, starts at 0 when the page loads and counts up in **seconds**.\n\n`Tone.now()` gets the current time of the AudioContext.\n\n```javascript\nsetInterval(() => console.log(Tone.now()), 100);\n```\n\nTone.js abstracts away the AudioContext time. Instead of defining all values in seconds, any method which takes time as an argument can accept a number or a string. For example `\"4n\"` is a quarter-note, `\"8t\"` is an eighth-note triplet, and `\"1m\"` is one measure.\n\n[Read about Time encodings](https://github.com/Tonejs/Tone.js/wiki/Time).\n\n# Starting Audio\n\n**IMPORTANT**: Browsers will not play _any_ audio until a user clicks something (like a play button). Run your Tone.js code only after calling `Tone.start()` from a event listener which is triggered by a user action such as \"click\" or \"keydown\".\n\n`Tone.start()` returns a promise, the audio will be ready only after that promise is resolved. Scheduling or playing audio before the AudioContext is running will result in silence or incorrect scheduling.\n\n```javascript\n//attach a click listener to a play button\ndocument.querySelector(\"button\")?.addEventListener(\"click\", async () => {\n\tawait Tone.start();\n\tconsole.log(\"audio is ready\");\n});\n```\n\n# Scheduling\n\n## Transport\n\n`Tone.getTransport()` returns the main timekeeper. Unlike the AudioContext clock, it can be started, stopped, looped and adjusted on the fly. You can think of it like the arrangement view in a Digital Audio Workstation.\n\nMultiple events and parts can be arranged and synchronized along the Transport. `Tone.Loop` is a simple way to create a looped callback that can be scheduled to start and stop.\n\n```javascript\n// create two monophonic synths\nconst synthA = new Tone.FMSynth().toDestination();\nconst synthB = new Tone.AMSynth().toDestination();\n//play a note every quarter-note\nconst loopA = new Tone.Loop((time) => {\n\tsynthA.triggerAttackRelease(\"C2\", \"8n\", time);\n}, \"4n\").start(0);\n//play another note every off quarter-note, by starting it \"8n\"\nconst loopB = new Tone.Loop((time) => {\n\tsynthB.triggerAttackRelease(\"C4\", \"8n\", time);\n}, \"4n\").start(\"8n\");\n// all loops start when the Transport is started\nTone.getTransport().start();\n// ramp up to 800 bpm over 10 seconds\nTone.getTransport().bpm.rampTo(800, 10);\n```\n\nSince Javascript callbacks are **not precisely timed**, the sample-accurate time of the event is passed into the callback function. **Use this time value to schedule the events**.\n\n# Instruments\n\nThere are numerous synths to choose from including `Tone.FMSynth`, `Tone.AMSynth` and `Tone.NoiseSynth`.\n\nAll of these instruments are **monophonic** (single voice) which means that they can only play one note at a time.\n\nTo create a **polyphonic** synthesizer, use `Tone.PolySynth`, which accepts a monophonic synth as its first parameter and automatically handles the note allocation so you can pass in multiple notes. The API is similar to the monophonic synths, except `triggerRelease` must be given a note or array of notes.\n\n```javascript\nconst synth = new Tone.PolySynth(Tone.Synth).toDestination();\nconst now = Tone.now();\nsynth.triggerAttack(\"D4\", now);\nsynth.triggerAttack(\"F4\", now + 0.5);\nsynth.triggerAttack(\"A4\", now + 1);\nsynth.triggerAttack(\"C5\", now + 1.5);\nsynth.triggerAttack(\"E5\", now + 2);\nsynth.triggerRelease([\"D4\", \"F4\", \"A4\", \"C5\", \"E5\"], now + 4);\n```\n\n# Samples\n\nSound generation is not limited to synthesized sounds. You can also load a sample and play that back in a number of ways. `Tone.Player` is one way to load and play back an audio file.\n\n```javascript\nconst player = new Tone.Player(\n\t\"https://tonejs.github.io/audio/berklee/gong_1.mp3\"\n).toDestination();\nTone.loaded().then(() => {\n\tplayer.start();\n});\n```\n\n`Tone.loaded()` returns a promise which resolves when _all_ audio files are loaded. It's a helpful shorthand instead of waiting on each individual audio buffer's `onload` event to resolve.\n\n## Tone.Sampler\n\nMultiple samples can also be combined into an instrument. If you have audio files organized by note, `Tone.Sampler` will pitch shift the samples to fill in gaps between notes. So for example, if you only have every 3rd note on a piano sampled, you could turn that into a full piano sample.\n\nUnlike the other synths, Tone.Sampler is polyphonic so doesn't need to be passed into Tone.PolySynth\n\n```javascript\nconst sampler = new Tone.Sampler({\n\turls: {\n\t\tC4: \"C4.mp3\",\n\t\t\"D#4\": \"Ds4.mp3\",\n\t\t\"F#4\": \"Fs4.mp3\",\n\t\tA4: \"A4.mp3\",\n\t},\n\trelease: 1,\n\tbaseUrl: \"https://tonejs.github.io/audio/salamander/\",\n}).toDestination();\n\nTone.loaded().then(() => {\n\tsampler.triggerAttackRelease([\"Eb4\", \"G4\", \"Bb4\"], 4);\n});\n```\n\n# Effects\n\nIn the above examples, the sources were always connected directly to the `Destination`, but the output of the synth could also be routed through one (or more) effects before going to the speakers.\n\n```javascript\nconst player = new Tone.Player({\n\turl: \"https://tonejs.github.io/audio/berklee/gurgling_theremin_1.mp3\",\n\tloop: true,\n\tautostart: true,\n});\n//create a distortion effect\nconst distortion = new Tone.Distortion(0.4).toDestination();\n//connect a player to the distortion\nplayer.connect(distortion);\n```\n\nThe connection routing is flexible, connections can run serially or in parallel.\n\n```javascript\nconst player = new Tone.Player({\n\turl: \"https://tonejs.github.io/audio/drum-samples/loops/ominous.mp3\",\n\tautostart: true,\n});\nconst filter = new Tone.Filter(400, \"lowpass\").toDestination();\nconst feedbackDelay = new Tone.FeedbackDelay(0.125, 0.5).toDestination();\n\n// connect the player to the feedback delay and filter in parallel\nplayer.connect(filter);\nplayer.connect(feedbackDelay);\n```\n\nMultiple nodes can be connected to the same input enabling sources to share effects. `Tone.Gain` is useful utility node for creating complex routing.\n\n# Signals\n\nLike the underlying Web Audio API, Tone.js is built with audio-rate signal control over nearly everything. This is a powerful feature which allows for sample-accurate synchronization and scheduling of parameters.\n\n`Signal` properties have a few built in methods for creating automation curves.\n\nFor example, the `frequency` parameter on `Oscillator` is a Signal so you can create a smooth ramp from one frequency to another.\n\n```javascript\nconst osc = new Tone.Oscillator().toDestination();\n// start at \"C4\"\nosc.frequency.value = \"C4\";\n// ramp to \"C2\" over 2 seconds\nosc.frequency.rampTo(\"C2\", 2);\n// start the oscillator for 2 seconds\nosc.start().stop(\"+3\");\n```\n\n# AudioContext\n\nTone.js creates an AudioContext when it loads and shims it for maximum browser compatibility using [standardized-audio-context](https://github.com/chrisguttandin/standardized-audio-context). The AudioContext can be accessed at `Tone.getContext`. Or set your own AudioContext using `Tone.setContext(audioContext)`.\n\n# MIDI\n\nTo use MIDI files, you'll first need to convert them into a JSON format which Tone.js can understand using [Midi](https://tonejs.github.io/Midi/).\n\n# Performance\n\nTone.js makes extensive use of the native Web Audio Nodes such as the GainNode and WaveShaperNode for all signal processing, which enables Tone.js to work well on both desktop and mobile browsers.\n\n[This wiki](https://github.com/Tonejs/Tone.js/wiki/Performance) article has some suggestions related to performance for best practices.\n\n# Testing\n\nTone.js runs an extensive test suite using [mocha](https://mochajs.org/) and [chai](http://chaijs.com/) with nearly 100% coverage. Passing builds on the 'dev' branch are published on npm as `tone@next`.\n\n# Contributing\n\nThere are many ways to contribute to Tone.js. Check out [this wiki](https://github.com/Tonejs/Tone.js/wiki/Contributing) if you're interested.\n\n# References and Inspiration\n\n-   [Many of Chris Wilson's Repositories](https://github.com/cwilso)\n-   [Many of Mohayonao's Repositories](https://github.com/mohayonao)\n-   [The Spec](http://webaudio.github.io/web-audio-api/)\n-   [Sound on Sound - Synth Secrets](http://www.soundonsound.com/sos/may99/articles/synthsec.htm)\n-   [Miller Puckette - Theory and Techniques of Electronic Music](http://msp.ucsd.edu/techniques.htm)\n-   [standardized-audio-context](https://github.com/chrisguttandin/standardized-audio-context)\n"
  },
  {
    "path": "Tone/classes.ts",
    "content": "export * from \"./component/index.js\";\nexport * from \"./core/index.js\";\nexport * from \"./effect/index.js\";\nexport * from \"./event/index.js\";\nexport * from \"./instrument/index.js\";\nexport * from \"./signal/index.js\";\nexport * from \"./source/index.js\";\n"
  },
  {
    "path": "Tone/component/analysis/Analyser.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { Noise } from \"../../source/Noise.js\";\nimport { Analyser } from \"./Analyser.js\";\n\ndescribe(\"Analyser\", () => {\n\tBasicTests(Analyser);\n\n\tit(\"can get and set properties\", () => {\n\t\tconst anl = new Analyser();\n\t\tanl.set({\n\t\t\tsize: 32,\n\t\t\tsmoothing: 0.2,\n\t\t});\n\t\tconst values = anl.get();\n\t\texpect(values.size).to.equal(32);\n\t\texpect(values.smoothing).to.equal(0.2);\n\t\tanl.dispose();\n\t});\n\n\tit(\"can correctly set the size\", () => {\n\t\tconst anl = new Analyser(\"fft\", 512);\n\t\texpect(anl.size).to.equal(512);\n\t\tanl.size = 1024;\n\t\texpect(anl.size).to.equal(1024);\n\t\tanl.dispose();\n\t});\n\n\tit(\"can run fft analysis\", () => {\n\t\tconst anl = new Analyser(\"fft\", 512);\n\t\tconst analysis = anl.getValue();\n\t\texpect(analysis.length).to.equal(512);\n\t\tanalysis.forEach((val) => {\n\t\t\texpect(val).is.lessThan(0);\n\t\t});\n\t\tanl.dispose();\n\t});\n\n\tit(\"can run waveform analysis\", (done) => {\n\t\tconst noise = new Noise();\n\t\tconst anl = new Analyser(\"waveform\", 256);\n\t\tnoise.connect(anl);\n\t\tnoise.start();\n\n\t\tsetTimeout(() => {\n\t\t\tconst analysis = anl.getValue();\n\t\t\texpect(analysis.length).to.equal(256);\n\t\t\tanalysis.forEach((val) => {\n\t\t\t\texpect(val).is.within(-1, 1);\n\t\t\t});\n\t\t\tanl.dispose();\n\t\t\tnoise.dispose();\n\t\t\tdone();\n\t\t}, 300);\n\t});\n\n\tit(\"throws an error if an invalid type is set\", () => {\n\t\tconst anl = new Analyser(\"fft\", 512);\n\t\texpect(() => {\n\t\t\t// @ts-ignore\n\t\t\tanl.type = \"invalid\";\n\t\t}).to.throw(Error);\n\t\tanl.dispose();\n\t});\n\n\tit(\"can do multichannel analysis\", () => {\n\t\tconst anl = new Analyser({\n\t\t\ttype: \"waveform\",\n\t\t\tchannels: 2,\n\t\t\tsize: 512,\n\t\t});\n\t\texpect(anl.getValue().length).to.equal(2);\n\t\texpect((anl.getValue()[0] as Float32Array).length).to.equal(512);\n\t\tanl.dispose();\n\t});\n});\n"
  },
  {
    "path": "Tone/component/analysis/Analyser.ts",
    "content": "import { Gain } from \"../../core/context/Gain.js\";\nimport {\n\tInputNode,\n\tOutputNode,\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { NormalRange, PowerOfTwo } from \"../../core/type/Units.js\";\nimport { assert, assertRange } from \"../../core/util/Debug.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { Split } from \"../channel/Split.js\";\n\nexport type AnalyserType = \"fft\" | \"waveform\";\n\nexport interface AnalyserOptions extends ToneAudioNodeOptions {\n\tsize: PowerOfTwo;\n\ttype: AnalyserType;\n\tsmoothing: NormalRange;\n\tchannels: number;\n}\n\n/**\n * Wrapper around the native Web Audio's [AnalyserNode](http://webaudio.github.io/web-audio-api/#idl-def-AnalyserNode).\n * Extracts FFT or Waveform data from the incoming signal.\n * @category Component\n */\nexport class Analyser extends ToneAudioNode<AnalyserOptions> {\n\treadonly name: string = \"Analyser\";\n\n\treadonly input: InputNode;\n\treadonly output: OutputNode;\n\n\t/**\n\t * The analyser node.\n\t */\n\tprivate _analyzers: AnalyserNode[] = [];\n\n\t/**\n\t * Input and output are a gain node\n\t */\n\tprivate _gain: Gain;\n\n\t/**\n\t * The channel splitter node\n\t */\n\tprivate _split: Split;\n\n\t/**\n\t * The analysis type\n\t */\n\tprivate _type!: AnalyserType;\n\n\t/**\n\t * The buffer that the FFT data is written to\n\t */\n\tprivate _buffers: Float32Array[] = [];\n\n\t/**\n\t * @param type The return type of the analysis, either \"fft\", or \"waveform\".\n\t * @param size The size of the FFT. This must be a power of two in the range 16 to 16384.\n\t */\n\tconstructor(type?: AnalyserType, size?: number);\n\tconstructor(options?: Partial<AnalyserOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tAnalyser.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"type\", \"size\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.input =\n\t\t\tthis.output =\n\t\t\tthis._gain =\n\t\t\t\tnew Gain({ context: this.context });\n\t\tthis._split = new Split({\n\t\t\tcontext: this.context,\n\t\t\tchannels: options.channels,\n\t\t});\n\t\tthis.input.connect(this._split);\n\n\t\tassertRange(options.channels, 1);\n\n\t\t// create the analyzers\n\t\tfor (let channel = 0; channel < options.channels; channel++) {\n\t\t\tthis._analyzers[channel] = this.context.createAnalyser();\n\t\t\tthis._split.connect(this._analyzers[channel], channel, 0);\n\t\t}\n\n\t\t// set the values initially\n\t\tthis.size = options.size;\n\t\tthis.type = options.type;\n\t\tthis.smoothing = options.smoothing;\n\t}\n\n\tstatic getDefaults(): AnalyserOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tsize: 1024,\n\t\t\tsmoothing: 0.8,\n\t\t\ttype: \"fft\" as AnalyserType,\n\t\t\tchannels: 1,\n\t\t});\n\t}\n\n\t/**\n\t * Run the analysis given the current settings. If {@link channels} = 1,\n\t * it will return a Float32Array. If {@link channels} > 1, it will\n\t * return an array of Float32Arrays where each index in the array\n\t * represents the analysis done on a channel.\n\t */\n\tgetValue(): Float32Array | Float32Array[] {\n\t\tthis._analyzers.forEach((analyser, index) => {\n\t\t\tconst buffer = this._buffers[index];\n\t\t\tif (this._type === \"fft\") {\n\t\t\t\tanalyser.getFloatFrequencyData(buffer);\n\t\t\t} else if (this._type === \"waveform\") {\n\t\t\t\tanalyser.getFloatTimeDomainData(buffer);\n\t\t\t}\n\t\t});\n\t\tif (this.channels === 1) {\n\t\t\treturn this._buffers[0];\n\t\t} else {\n\t\t\treturn this._buffers;\n\t\t}\n\t}\n\n\t/**\n\t * The size of analysis. This must be a power of two in the range 16 to 16384.\n\t */\n\tget size(): PowerOfTwo {\n\t\treturn this._analyzers[0].frequencyBinCount;\n\t}\n\tset size(size: PowerOfTwo) {\n\t\tthis._analyzers.forEach((analyser, index) => {\n\t\t\tanalyser.fftSize = size * 2;\n\t\t\tthis._buffers[index] = new Float32Array(size);\n\t\t});\n\t}\n\n\t/**\n\t * The number of channels the analyser does the analysis on. Channel\n\t * separation is done using {@link Split}\n\t */\n\tget channels(): number {\n\t\treturn this._analyzers.length;\n\t}\n\n\t/**\n\t * The analysis function returned by analyser.getValue(), either \"fft\" or \"waveform\".\n\t */\n\tget type(): AnalyserType {\n\t\treturn this._type;\n\t}\n\tset type(type: AnalyserType) {\n\t\tassert(\n\t\t\ttype === \"waveform\" || type === \"fft\",\n\t\t\t`Analyser: invalid type: ${type}`\n\t\t);\n\t\tthis._type = type;\n\t}\n\n\t/**\n\t * 0 represents no time averaging with the last analysis frame.\n\t */\n\tget smoothing(): NormalRange {\n\t\treturn this._analyzers[0].smoothingTimeConstant;\n\t}\n\tset smoothing(val: NormalRange) {\n\t\tthis._analyzers.forEach((a) => (a.smoothingTimeConstant = val));\n\t}\n\n\t/**\n\t * Clean up.\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._analyzers.forEach((a) => a.disconnect());\n\t\tthis._split.dispose();\n\t\tthis._gain.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/analysis/DCMeter.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { DCMeter } from \"./DCMeter.js\";\n\ndescribe(\"DCMeter\", () => {\n\tBasicTests(DCMeter);\n\n\tcontext(\"DCMetering\", () => {\n\t\tit(\"passes the audio through\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst meter = new DCMeter().toDestination();\n\t\t\t\tinput.connect(meter);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get the rms level of the incoming signal\", (done) => {\n\t\t\tconst meter = new DCMeter();\n\t\t\tconst osc = new Signal(2).connect(meter);\n\t\t\tsetTimeout(() => {\n\t\t\t\texpect(meter.getValue()).to.be.closeTo(2, 0.1);\n\t\t\t\tmeter.dispose();\n\t\t\t\tosc.dispose();\n\t\t\t\tdone();\n\t\t\t}, 400);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/analysis/DCMeter.ts",
    "content": "import { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { MeterBase, MeterBaseOptions } from \"./MeterBase.js\";\n\nexport type DCMeterOptions = MeterBaseOptions;\n\n/**\n * DCMeter gets the raw value of the input signal at the current time.\n * @see {@link Meter}.\n *\n * @example\n * const meter = new Tone.DCMeter();\n * const mic = new Tone.UserMedia();\n * mic.open();\n * // connect mic to the meter\n * mic.connect(meter);\n * // the current level of the mic\n * const level = meter.getValue();\n * @category Component\n */\nexport class DCMeter extends MeterBase<DCMeterOptions> {\n\treadonly name: string = \"DCMeter\";\n\n\tconstructor(options?: Partial<DCMeterOptions>);\n\tconstructor() {\n\t\tsuper(optionsFromArguments(DCMeter.getDefaults(), arguments));\n\n\t\tthis._analyser.type = \"waveform\";\n\t\tthis._analyser.size = 256;\n\t}\n\n\t/**\n\t * Get the signal value of the incoming signal\n\t */\n\tgetValue(): number {\n\t\tconst value = this._analyser.getValue() as Float32Array;\n\t\treturn value[0];\n\t}\n}\n"
  },
  {
    "path": "Tone/component/analysis/FFT.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { Noise } from \"../../source/Noise.js\";\nimport { FFT } from \"./FFT.js\";\n\ndescribe(\"FFT\", () => {\n\tBasicTests(FFT);\n\n\tit(\"can get and set properties\", () => {\n\t\tconst fft = new FFT();\n\t\tfft.set({\n\t\t\tsize: 128,\n\t\t\tsmoothing: 0.4,\n\t\t});\n\t\tconst values = fft.get();\n\t\texpect(values.size).to.equal(128);\n\t\texpect(values.smoothing).to.equal(0.4);\n\t\tfft.dispose();\n\t});\n\n\tit(\"can correctly set the size\", () => {\n\t\tconst fft = new FFT(512);\n\t\texpect(fft.size).to.equal(512);\n\t\tfft.size = 1024;\n\t\texpect(fft.size).to.equal(1024);\n\t\tfft.dispose();\n\t});\n\n\tit(\"can set the smoothing\", () => {\n\t\tconst fft = new FFT(512);\n\t\tfft.smoothing = 0.2;\n\t\texpect(fft.smoothing).to.equal(0.2);\n\t\tfft.dispose();\n\t});\n\n\tit(\"can get the frequency values of each index of the return array\", () => {\n\t\tconst fft = new FFT(32);\n\t\texpect(fft.getFrequencyOfIndex(0)).to.be.closeTo(0, 1);\n\t\texpect(fft.getFrequencyOfIndex(16)).to.be.closeTo(\n\t\t\tfft.context.sampleRate / 4,\n\t\t\t1\n\t\t);\n\t\tfft.dispose();\n\t});\n\n\tit(\"can run waveform analysis\", (done) => {\n\t\tconst noise = new Noise();\n\t\tconst fft = new FFT(256);\n\t\tnoise.connect(fft);\n\t\tnoise.start();\n\n\t\tsetTimeout(() => {\n\t\t\tconst analysis = fft.getValue();\n\t\t\texpect(analysis.length).to.equal(256);\n\t\t\tanalysis.forEach((value) => {\n\t\t\t\texpect(value).is.within(-Infinity, 0);\n\t\t\t});\n\t\t\tfft.dispose();\n\t\t\tnoise.dispose();\n\t\t\tdone();\n\t\t}, 300);\n\t});\n\n\tit(\"outputs a normal range\", (done) => {\n\t\tconst noise = new Noise();\n\t\tconst fft = new FFT({\n\t\t\tnormalRange: true,\n\t\t});\n\t\tnoise.connect(fft);\n\t\tnoise.start();\n\n\t\tsetTimeout(() => {\n\t\t\tconst analysis = fft.getValue();\n\t\t\tanalysis.forEach((value) => {\n\t\t\t\texpect(value).is.within(0, 1);\n\t\t\t});\n\t\t\tfft.dispose();\n\t\t\tnoise.dispose();\n\t\t\tdone();\n\t\t}, 300);\n\t});\n});\n"
  },
  {
    "path": "Tone/component/analysis/FFT.ts",
    "content": "import { ToneAudioNode } from \"../../core/context/ToneAudioNode.js\";\nimport { dbToGain } from \"../../core/type/Conversions.js\";\nimport { Hertz, NormalRange, PowerOfTwo } from \"../../core/type/Units.js\";\nimport { assert } from \"../../core/util/Debug.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { MeterBase, MeterBaseOptions } from \"./MeterBase.js\";\n\nexport interface FFTOptions extends MeterBaseOptions {\n\tsize: PowerOfTwo;\n\tsmoothing: NormalRange;\n\tnormalRange: boolean;\n}\n\n/**\n * Get the current frequency data of the connected audio source using a fast Fourier transform.\n * Read more about FFT algorithms on [Wikipedia] (https://en.wikipedia.org/wiki/Fast_Fourier_transform).\n * @category Component\n */\nexport class FFT extends MeterBase<FFTOptions> {\n\treadonly name: string = \"FFT\";\n\n\t/**\n\t * If the output should be in decibels or normal range between 0-1. If `normalRange` is false,\n\t * the output range will be the measured decibel value, otherwise the decibel value will be converted to\n\t * the range of 0-1\n\t */\n\tnormalRange: boolean;\n\n\t/**\n\t * @param size The size of the FFT. Value must be a power of two in the range 16 to 16384.\n\t */\n\tconstructor(size?: PowerOfTwo);\n\tconstructor(options?: Partial<FFTOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(FFT.getDefaults(), arguments, [\n\t\t\t\"size\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis.normalRange = options.normalRange;\n\t\tthis._analyser.type = \"fft\";\n\t\tthis.size = options.size;\n\t}\n\n\tstatic getDefaults(): FFTOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tnormalRange: false,\n\t\t\tsize: 1024,\n\t\t\tsmoothing: 0.8,\n\t\t});\n\t}\n\n\t/**\n\t * Gets the current frequency data from the connected audio source.\n\t * Returns the frequency data of length {@link size} as a Float32Array of decibel values.\n\t */\n\tgetValue(): Float32Array {\n\t\tconst values = this._analyser.getValue() as Float32Array;\n\t\treturn values.map((v) => (this.normalRange ? dbToGain(v) : v));\n\t}\n\n\t/**\n\t * The size of analysis. This must be a power of two in the range 16 to 16384.\n\t * Determines the size of the array returned by {@link getValue} (i.e. the number of\n\t * frequency bins). Large FFT sizes may be costly to compute.\n\t */\n\tget size(): PowerOfTwo {\n\t\treturn this._analyser.size;\n\t}\n\tset size(size) {\n\t\tthis._analyser.size = size;\n\t}\n\n\t/**\n\t * 0 represents no time averaging with the last analysis frame.\n\t */\n\tget smoothing(): NormalRange {\n\t\treturn this._analyser.smoothing;\n\t}\n\tset smoothing(val) {\n\t\tthis._analyser.smoothing = val;\n\t}\n\n\t/**\n\t * Returns the frequency value in hertz of each of the indices of the FFT's {@link getValue} response.\n\t * @example\n\t * const fft = new Tone.FFT(32);\n\t * console.log([0, 1, 2, 3, 4].map(index => fft.getFrequencyOfIndex(index)));\n\t */\n\tgetFrequencyOfIndex(index: number): Hertz {\n\t\tassert(\n\t\t\t0 <= index && index < this.size,\n\t\t\t`index must be greater than or equal to 0 and less than ${this.size}`\n\t\t);\n\t\treturn (index * this.context.sampleRate) / (this.size * 2);\n\t}\n}\n"
  },
  {
    "path": "Tone/component/analysis/Follower.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { Follower } from \"./Follower.js\";\n\ndescribe(\"Follower\", () => {\n\tBasicTests(Follower);\n\n\tcontext(\"Envelope Following\", () => {\n\t\tit(\"handles getter/setter as Object\", () => {\n\t\t\tconst foll = new Follower();\n\t\t\tconst values = {\n\t\t\t\tsmoothing: 0.2,\n\t\t\t};\n\t\t\tfoll.set(values);\n\t\t\texpect(foll.get()).to.have.keys([\"smoothing\"]);\n\t\t\texpect(foll.get().smoothing).to.be.closeTo(0.2, 0.001);\n\t\t\tfoll.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an object\", () => {\n\t\t\tconst follower = new Follower({\n\t\t\t\tsmoothing: 0.5,\n\t\t\t});\n\t\t\texpect(follower.smoothing).to.be.closeTo(0.5, 0.001);\n\t\t\tfollower.dispose();\n\t\t});\n\n\t\tit(\"smooths the incoming signal at 0.1\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst foll = new Follower(0.1).toDestination();\n\t\t\t\tconst sig = new Signal(0);\n\t\t\t\tsig.connect(foll);\n\t\t\t\tsig.setValueAtTime(1, 0.1);\n\t\t\t\tsig.setValueAtTime(0, 0.3);\n\t\t\t}, 0.41);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.1)).to.be.closeTo(0.0, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.15)).to.be.closeTo(0.95, 0.05);\n\t\t\texpect(buffer.getValueAtTime(0.2)).to.be.closeTo(1, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.3)).to.be.closeTo(1, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.35)).to.be.closeTo(0.05, 0.05);\n\t\t\texpect(buffer.getValueAtTime(0.4)).to.be.closeTo(0, 0.01);\n\t\t});\n\n\t\tit(\"smooths the incoming signal at 0.05\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst foll = new Follower(0.05).toDestination();\n\t\t\t\tconst sig = new Signal(0);\n\t\t\t\tsig.connect(foll);\n\t\t\t\tsig.setValueAtTime(1, 0.1);\n\t\t\t\tsig.setValueAtTime(0, 0.3);\n\t\t\t}, 0.41);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.1)).to.be.closeTo(0.0, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.125)).to.be.closeTo(0.95, 0.05);\n\t\t\texpect(buffer.getValueAtTime(0.15)).to.be.closeTo(1, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.3)).to.be.closeTo(1, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.325)).to.be.closeTo(0.05, 0.05);\n\t\t\texpect(buffer.getValueAtTime(0.35)).to.be.closeTo(0, 0.01);\n\t\t});\n\n\t\tit(\"smooths the incoming signal at 0.2\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst foll = new Follower(0.2).toDestination();\n\t\t\t\tconst sig = new Signal(0);\n\t\t\t\tsig.connect(foll);\n\t\t\t\tsig.setValueAtTime(1, 0.1);\n\t\t\t\tsig.setValueAtTime(0, 0.3);\n\t\t\t}, 0.51);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.1)).to.be.closeTo(0.0, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.2)).to.be.closeTo(0.95, 0.05);\n\t\t\texpect(buffer.getValueAtTime(0.3)).to.be.closeTo(1, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.4)).to.be.closeTo(0.05, 0.05);\n\t\t\texpect(buffer.getValueAtTime(0.5)).to.be.closeTo(0, 0.01);\n\t\t});\n\n\t\tit(\"smooths the incoming signal at 0.5\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst foll = new Follower(0.5).toDestination();\n\t\t\t\tconst sig = new Signal(0);\n\t\t\t\tsig.connect(foll);\n\t\t\t\tsig.setValueAtTime(1, 0.1);\n\t\t\t\tsig.setValueAtTime(0, 0.6);\n\t\t\t}, 1.11);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.1)).to.be.closeTo(0.0, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.35)).to.be.closeTo(0.95, 0.05);\n\t\t\texpect(buffer.getValueAtTime(0.6)).to.be.closeTo(1, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.85)).to.be.closeTo(0.05, 0.05);\n\t\t\texpect(buffer.getValueAtTime(1.1)).to.be.closeTo(0, 0.01);\n\t\t});\n\n\t\tit(\"passes the incoming signal through\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst follower = new Follower().toDestination();\n\t\t\t\tinput.connect(follower);\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/analysis/Follower.ts",
    "content": "import {\n\tInputNode,\n\tOutputNode,\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { Time } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { Abs } from \"../../signal/Abs.js\";\nimport { OnePoleFilter } from \"../filter/OnePoleFilter.js\";\n\nexport interface FollowerOptions extends ToneAudioNodeOptions {\n\tsmoothing: Time;\n}\n\n/**\n * Follower is a simple envelope follower.\n * It's implemented by applying a lowpass filter to the absolute value of the incoming signal.\n * ```\n *          +-----+    +---------------+\n * Input +--> Abs +----> OnePoleFilter +--> Output\n *          +-----+    +---------------+\n * ```\n * @category Component\n */\nexport class Follower extends ToneAudioNode<FollowerOptions> {\n\treadonly name: string = \"Follower\";\n\n\treadonly input: InputNode;\n\treadonly output: OutputNode;\n\n\t/**\n\t * Private reference to the smoothing parameter\n\t */\n\tprivate _smoothing: Time;\n\n\t/**\n\t * The lowpass filter\n\t */\n\tprivate _lowpass: OnePoleFilter;\n\n\t/**\n\t * The absolute value\n\t */\n\tprivate _abs: Abs;\n\n\t/**\n\t * @param smoothing The rate of change of the follower.\n\t */\n\tconstructor(smoothing?: Time);\n\tconstructor(options?: Partial<FollowerOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tFollower.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"smoothing\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._abs = this.input = new Abs({ context: this.context });\n\t\tthis._lowpass = this.output = new OnePoleFilter({\n\t\t\tcontext: this.context,\n\t\t\tfrequency: 1 / this.toSeconds(options.smoothing),\n\t\t\ttype: \"lowpass\",\n\t\t});\n\t\tthis._abs.connect(this._lowpass);\n\t\tthis._smoothing = options.smoothing;\n\t}\n\n\tstatic getDefaults(): FollowerOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tsmoothing: 0.05,\n\t\t});\n\t}\n\n\t/**\n\t * The amount of time it takes a value change to arrive at the updated value.\n\t */\n\tget smoothing(): Time {\n\t\treturn this._smoothing;\n\t}\n\tset smoothing(smoothing) {\n\t\tthis._smoothing = smoothing;\n\t\tthis._lowpass.frequency = 1 / this.toSeconds(this.smoothing);\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._abs.dispose();\n\t\tthis._lowpass.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/analysis/Meter.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests, warns } from \"../../../test/helper/Basic.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { Oscillator } from \"../../source/oscillator/Oscillator.js\";\nimport { Merge } from \"../channel/Merge.js\";\nimport { Meter } from \"./Meter.js\";\n\ndescribe(\"Meter\", () => {\n\tBasicTests(Meter);\n\n\tcontext(\"Metering\", () => {\n\t\tit(\"handles getter/setter as Object\", () => {\n\t\t\tconst meter = new Meter();\n\t\t\tconst values = {\n\t\t\t\tsmoothing: 0.2,\n\t\t\t};\n\t\t\tmeter.set(values);\n\t\t\texpect(meter.get().smoothing).to.equal(0.2);\n\t\t\tmeter.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with the smoothing\", () => {\n\t\t\tconst meter = new Meter(0.5);\n\t\t\texpect(meter.smoothing).to.equal(0.5);\n\t\t\tmeter.dispose();\n\t\t});\n\n\t\tit(\"returns an array of channels if channels > 1\", () => {\n\t\t\tconst meter = new Meter({\n\t\t\t\tchannelCount: 4,\n\t\t\t});\n\t\t\texpect((meter.getValue() as number[]).length).to.equal(4);\n\t\t\tmeter.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an object\", () => {\n\t\t\tconst meter = new Meter({\n\t\t\t\tsmoothing: 0.3,\n\t\t\t});\n\t\t\texpect(meter.smoothing).to.equal(0.3);\n\t\t\tmeter.dispose();\n\t\t});\n\n\t\tit(\"passes the audio through\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst meter = new Meter().toDestination();\n\t\t\t\tinput.connect(meter);\n\t\t\t});\n\t\t});\n\n\t\tit(\"warns of deprecated method\", () => {\n\t\t\twarns(() => {\n\t\t\t\tconst meter = new Meter().toDestination();\n\t\t\t\tmeter.getLevel();\n\t\t\t\tmeter.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get the rms level of the incoming signal\", (done) => {\n\t\t\tconst meter = new Meter();\n\t\t\tconst osc = new Oscillator().connect(meter).start();\n\t\t\tosc.volume.value = -6;\n\t\t\tsetTimeout(() => {\n\t\t\t\texpect(meter.getValue()).to.be.closeTo(-9, 1);\n\t\t\t\tmeter.dispose();\n\t\t\t\tosc.dispose();\n\t\t\t\tdone();\n\t\t\t}, 400);\n\t\t});\n\n\t\tit(\"returns 0 below a threshold\", (done) => {\n\t\t\tconst meter = new Meter({\n\t\t\t\tnormalRange: true,\n\t\t\t});\n\t\t\tconst osc = new Oscillator().connect(meter).start();\n\t\t\tosc.volume.value = -101;\n\t\t\tsetTimeout(() => {\n\t\t\t\texpect(meter.getValue()).to.equal(0);\n\t\t\t\tmeter.dispose();\n\t\t\t\tosc.dispose();\n\t\t\t\tdone();\n\t\t\t}, 400);\n\t\t});\n\n\t\tit(\"can get the values in normal range\", (done) => {\n\t\t\tconst meter = new Meter({\n\t\t\t\tnormalRange: true,\n\t\t\t});\n\t\t\tconst osc = new Oscillator().connect(meter).start();\n\t\t\tosc.volume.value = -6;\n\t\t\tsetTimeout(() => {\n\t\t\t\texpect(meter.getValue()).to.be.closeTo(0.35, 0.15);\n\t\t\t\tmeter.dispose();\n\t\t\t\tosc.dispose();\n\t\t\t\tdone();\n\t\t\t}, 400);\n\t\t});\n\n\t\tit(\"can get the rms levels for multiple channels\", (done) => {\n\t\t\tconst meter = new Meter({\n\t\t\t\tchannelCount: 2,\n\t\t\t\tsmoothing: 0.5,\n\t\t\t});\n\t\t\tconst merge = new Merge().connect(meter);\n\t\t\tconst osc0 = new Oscillator().connect(merge, 0, 0).start();\n\t\t\tconst osc1 = new Oscillator().connect(merge, 0, 1).start();\n\t\t\tosc0.volume.value = -6;\n\t\t\tosc1.volume.value = -18;\n\t\t\tsetTimeout(() => {\n\t\t\t\tconst values = meter.getValue();\n\t\t\t\texpect(values).to.have.lengthOf(2);\n\t\t\t\texpect(values[0]).to.be.closeTo(-9, 1);\n\t\t\t\texpect(values[1]).to.be.closeTo(-21, 1);\n\t\t\t\tmeter.dispose();\n\t\t\t\tmerge.dispose();\n\t\t\t\tosc0.dispose();\n\t\t\t\tosc1.dispose();\n\t\t\t\tdone();\n\t\t\t}, 400);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/analysis/Meter.ts",
    "content": "import { dbToGain, gainToDb } from \"../../core/type/Conversions.js\";\nimport { NormalRange } from \"../../core/type/Units.js\";\nimport { warn } from \"../../core/util/Debug.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { Analyser } from \"./Analyser.js\";\nimport { MeterBase, MeterBaseOptions } from \"./MeterBase.js\";\n\nexport interface MeterOptions extends MeterBaseOptions {\n\tsmoothing: NormalRange;\n\tnormalRange: boolean;\n\tchannelCount: number;\n}\n\n/**\n * Meter gets the [RMS](https://en.wikipedia.org/wiki/Root_mean_square)\n * of an input signal. It can also get the raw value of the input signal.\n * Setting `normalRange` to `true` will covert the output to a range of\n * 0-1. See an example using a graphical display\n * [here](https://tonejs.github.io/examples/meter).\n * @see {@link DCMeter}.\n *\n * @example\n * const meter = new Tone.Meter();\n * const mic = new Tone.UserMedia();\n * mic.open();\n * // connect mic to the meter\n * mic.connect(meter);\n * // the current level of the mic\n * setInterval(() => console.log(meter.getValue()), 100);\n * @category Component\n */\nexport class Meter extends MeterBase<MeterOptions> {\n\treadonly name: string = \"Meter\";\n\n\t/**\n\t * If the output should be in decibels or normal range between 0-1. If `normalRange` is false,\n\t * the output range will be the measured decibel value, otherwise the decibel value will be converted to\n\t * the range of 0-1\n\t */\n\tnormalRange: boolean;\n\n\t/**\n\t * A value from between 0 and 1 where 0 represents no time averaging with the last analysis frame.\n\t */\n\tsmoothing: number;\n\n\t/**\n\t * The previous frame's value for each channel.\n\t */\n\tprivate _rms: number[];\n\n\t/**\n\t * @param smoothing The amount of smoothing applied between frames.\n\t */\n\tconstructor(smoothing?: NormalRange);\n\tconstructor(options?: Partial<MeterOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Meter.getDefaults(), arguments, [\n\t\t\t\"smoothing\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis.input =\n\t\t\tthis.output =\n\t\t\tthis._analyser =\n\t\t\t\tnew Analyser({\n\t\t\t\t\tcontext: this.context,\n\t\t\t\t\tsize: 256,\n\t\t\t\t\ttype: \"waveform\",\n\t\t\t\t\tchannels: options.channelCount,\n\t\t\t\t});\n\n\t\tthis.smoothing = options.smoothing;\n\t\tthis.normalRange = options.normalRange;\n\t\tthis._rms = new Array(options.channelCount);\n\t\tthis._rms.fill(0);\n\t}\n\n\tstatic getDefaults(): MeterOptions {\n\t\treturn Object.assign(MeterBase.getDefaults(), {\n\t\t\tsmoothing: 0.8,\n\t\t\tnormalRange: false,\n\t\t\tchannelCount: 1,\n\t\t});\n\t}\n\n\t/**\n\t * Use {@link getValue} instead. For the previous getValue behavior, use DCMeter.\n\t * @deprecated\n\t */\n\tgetLevel(): number | number[] {\n\t\twarn(\"'getLevel' has been changed to 'getValue'\");\n\t\treturn this.getValue();\n\t}\n\n\t/**\n\t * Below this threshold, stop smoothing.\n\t */\n\tprivate minValue = dbToGain(-100);\n\n\t/**\n\t * Get the current value of the incoming signal.\n\t * Output is in decibels when {@link normalRange} is `false`.\n\t * If {@link channels} = 1, then the output is a single number\n\t * representing the value of the input signal. When {@link channels} > 1,\n\t * then each channel is returned as a value in a number array.\n\t */\n\tgetValue(): number | number[] {\n\t\tconst aValues = this._analyser.getValue();\n\t\tconst channelValues =\n\t\t\tthis.channels === 1\n\t\t\t\t? [aValues as Float32Array]\n\t\t\t\t: (aValues as Float32Array[]);\n\t\tconst vals = channelValues.map((values, channel) => {\n\t\t\tconst totalSquared = values.reduce(\n\t\t\t\t(total, current) => total + current * current,\n\t\t\t\t0\n\t\t\t);\n\t\t\tconst rms = Math.sqrt(totalSquared / values.length);\n\t\t\tif (rms < this.minValue) {\n\t\t\t\tthis._rms[channel] = 0;\n\t\t\t} else {\n\t\t\t\t// the rms can only fall at the rate of the smoothing\n\t\t\t\t// but can jump up instantly\n\t\t\t\tthis._rms[channel] = Math.max(\n\t\t\t\t\trms,\n\t\t\t\t\tthis._rms[channel] * this.smoothing\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn this.normalRange\n\t\t\t\t? this._rms[channel]\n\t\t\t\t: gainToDb(this._rms[channel]);\n\t\t});\n\t\tif (this.channels === 1) {\n\t\t\treturn vals[0];\n\t\t} else {\n\t\t\treturn vals;\n\t\t}\n\t}\n\n\t/**\n\t * The number of channels of analysis.\n\t */\n\tget channels(): number {\n\t\treturn this._analyser.channels;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._analyser.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/analysis/MeterBase.ts",
    "content": "import {\n\tInputNode,\n\tOutputNode,\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { Analyser } from \"./Analyser.js\";\n\nexport type MeterBaseOptions = ToneAudioNodeOptions;\n\n/**\n * The base class for Metering classes.\n */\nexport class MeterBase<\n\tOptions extends MeterBaseOptions,\n> extends ToneAudioNode<Options> {\n\treadonly name: string = \"MeterBase\";\n\n\t/**\n\t * The signal to be analyzed\n\t */\n\tinput: InputNode;\n\n\t/**\n\t * The output is just a pass through of the input\n\t */\n\toutput: OutputNode;\n\n\t/**\n\t * The analyser node for the incoming signal\n\t */\n\tprotected _analyser: Analyser;\n\n\tconstructor(options?: Partial<MeterBaseOptions>);\n\tconstructor() {\n\t\tsuper(optionsFromArguments(MeterBase.getDefaults(), arguments));\n\n\t\tthis.input =\n\t\t\tthis.output =\n\t\t\tthis._analyser =\n\t\t\t\tnew Analyser({\n\t\t\t\t\tcontext: this.context,\n\t\t\t\t\tsize: 256,\n\t\t\t\t\ttype: \"waveform\",\n\t\t\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._analyser.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/analysis/Waveform.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { Noise } from \"../../source/Noise.js\";\nimport { Waveform } from \"./Waveform.js\";\n\ndescribe(\"Waveform\", () => {\n\tBasicTests(Waveform);\n\n\tit(\"can get and set properties\", () => {\n\t\tconst anl = new Waveform();\n\t\tanl.set({\n\t\t\tsize: 128,\n\t\t});\n\t\tconst values = anl.get();\n\t\texpect(values.size).to.equal(128);\n\t\tanl.dispose();\n\t});\n\n\tit(\"can correctly set the size\", () => {\n\t\tconst anl = new Waveform(512);\n\t\texpect(anl.size).to.equal(512);\n\t\tanl.size = 1024;\n\t\texpect(anl.size).to.equal(1024);\n\t\tanl.dispose();\n\t});\n\n\tit(\"can run waveform analysis\", (done) => {\n\t\tconst noise = new Noise();\n\t\tconst anl = new Waveform(256);\n\t\tnoise.connect(anl);\n\t\tnoise.start();\n\n\t\tsetTimeout(() => {\n\t\t\tconst analysis = anl.getValue();\n\t\t\texpect(analysis.length).to.equal(256);\n\t\t\tanalysis.forEach((value) => {\n\t\t\t\texpect(value).is.within(-1, 1);\n\t\t\t});\n\t\t\tanl.dispose();\n\t\t\tnoise.dispose();\n\t\t\tdone();\n\t\t}, 300);\n\t});\n});\n"
  },
  {
    "path": "Tone/component/analysis/Waveform.ts",
    "content": "import { PowerOfTwo } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { MeterBase, MeterBaseOptions } from \"./MeterBase.js\";\n\nexport interface WaveformOptions extends MeterBaseOptions {\n\t/**\n\t * The size of the Waveform. Value must be a power of two in the range 16 to 16384.\n\t */\n\tsize: PowerOfTwo;\n}\n\n/**\n * Get the current waveform data of the connected audio source.\n * @category Component\n */\nexport class Waveform extends MeterBase<WaveformOptions> {\n\treadonly name: string = \"Waveform\";\n\n\t/**\n\t * @param size The size of the Waveform. Value must be a power of two in the range 16 to 16384.\n\t */\n\tconstructor(size?: PowerOfTwo);\n\tconstructor(options?: Partial<WaveformOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tWaveform.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"size\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._analyser.type = \"waveform\";\n\t\tthis.size = options.size;\n\t}\n\n\tstatic getDefaults(): WaveformOptions {\n\t\treturn Object.assign(MeterBase.getDefaults(), {\n\t\t\tsize: 1024,\n\t\t});\n\t}\n\n\t/**\n\t * Return the waveform for the current time as a Float32Array where each value in the array\n\t * represents a sample in the waveform.\n\t */\n\tgetValue(): Float32Array {\n\t\treturn this._analyser.getValue() as Float32Array;\n\t}\n\n\t/**\n\t * The size of analysis. This must be a power of two in the range 16 to 16384.\n\t * Determines the size of the array returned by {@link getValue}.\n\t */\n\tget size(): PowerOfTwo {\n\t\treturn this._analyser.size;\n\t}\n\tset size(size) {\n\t\tthis._analyser.size = size;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/channel/Channel.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { Channel } from \"./Channel.js\";\n\ndescribe(\"Channel\", () => {\n\tBasicTests(Channel);\n\n\tcontext(\"Channel\", () => {\n\t\tit(\"can pass volume and panning into the constructor\", () => {\n\t\t\tconst channel = new Channel(-10, -1);\n\t\t\texpect(channel.pan.value).to.be.closeTo(-1, 0.01);\n\t\t\texpect(channel.volume.value).to.be.closeTo(-10, 0.01);\n\t\t\tchannel.dispose();\n\t\t});\n\n\t\tit(\"can pass in an object into the constructor\", () => {\n\t\t\tconst channel = new Channel({\n\t\t\t\tpan: 1,\n\t\t\t\tvolume: 6,\n\t\t\t\tmute: false,\n\t\t\t\tsolo: true,\n\t\t\t});\n\t\t\texpect(channel.pan.value).to.be.closeTo(1, 0.01);\n\t\t\texpect(channel.volume.value).to.be.closeTo(6, 0.01);\n\t\t\texpect(channel.mute).to.be.false;\n\t\t\texpect(channel.solo).to.be.true;\n\t\t\tchannel.dispose();\n\t\t});\n\n\t\tit(\"passes the incoming signal through\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst channel = new Channel().toDestination();\n\t\t\t\tinput.connect(channel);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can mute the input\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst channel = new Channel(0).toDestination();\n\t\t\t\tnew Signal(1).connect(channel);\n\t\t\t\tchannel.mute = true;\n\t\t\t});\n\t\t\texpect(buffer.isSilent()).to.be.true;\n\t\t});\n\n\t\tit(\"reports itself as muted when either muted or another channel is soloed\", () => {\n\t\t\tconst channelA = new Channel();\n\t\t\tconst channelB = new Channel();\n\t\t\tchannelB.solo = true;\n\t\t\texpect(channelA.muted).to.be.true;\n\t\t\texpect(channelB.muted).to.be.false;\n\t\t\tchannelB.mute = true;\n\t\t\texpect(channelA.muted).to.be.true;\n\t\t\texpect(channelB.muted).to.be.true;\n\t\t\tchannelA.dispose();\n\t\t\tchannelB.dispose();\n\t\t});\n\n\t\tdescribe(\"bus\", () => {\n\t\t\tit(\"can connect two channels together by name\", () => {\n\t\t\t\treturn PassAudio((input) => {\n\t\t\t\t\tconst sendChannel = new Channel();\n\t\t\t\t\tinput.connect(sendChannel);\n\t\t\t\t\tsendChannel.send(\"test\");\n\t\t\t\t\tconst recvChannel = new Channel().toDestination();\n\t\t\t\t\trecvChannel.receive(\"test\");\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/channel/Channel.ts",
    "content": "import { Gain } from \"../../core/context/Gain.js\";\nimport { Param } from \"../../core/context/Param.js\";\nimport {\n\tInputNode,\n\tOutputNode,\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { AudioRange, Decibels } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly } from \"../../core/util/Interface.js\";\nimport { PanVol } from \"./PanVol.js\";\nimport { Solo } from \"./Solo.js\";\n\nexport interface ChannelOptions extends ToneAudioNodeOptions {\n\tpan: AudioRange;\n\tvolume: Decibels;\n\tsolo: boolean;\n\tmute: boolean;\n\tchannelCount: number;\n}\n\n/**\n * Channel provides a channel strip interface with volume, pan, solo and mute controls.\n * @see {@link PanVol} and {@link Solo}\n * @example\n * // pan the incoming signal left and drop the volume 12db\n * const channel = new Tone.Channel(-0.25, -12);\n * @category Component\n */\nexport class Channel extends ToneAudioNode<ChannelOptions> {\n\treadonly name: string = \"Channel\";\n\n\treadonly input: InputNode;\n\treadonly output: OutputNode;\n\n\t/**\n\t * The soloing interface\n\t */\n\tprivate _solo: Solo;\n\n\t/**\n\t * The panning and volume node\n\t */\n\tprivate _panVol: PanVol;\n\n\t/**\n\t * The L/R panning control. -1 = hard left, 1 = hard right.\n\t * @min -1\n\t * @max 1\n\t */\n\treadonly pan: Param<\"audioRange\">;\n\n\t/**\n\t * The volume control in decibels.\n\t */\n\treadonly volume: Param<\"decibels\">;\n\n\t/**\n\t * @param volume The output volume.\n\t * @param pan the initial pan\n\t */\n\tconstructor(volume?: Decibels, pan?: AudioRange);\n\tconstructor(options?: Partial<ChannelOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Channel.getDefaults(), arguments, [\n\t\t\t\"volume\",\n\t\t\t\"pan\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis._solo = this.input = new Solo({\n\t\t\tsolo: options.solo,\n\t\t\tcontext: this.context,\n\t\t});\n\t\tthis._panVol = this.output = new PanVol({\n\t\t\tcontext: this.context,\n\t\t\tpan: options.pan,\n\t\t\tvolume: options.volume,\n\t\t\tmute: options.mute,\n\t\t\tchannelCount: options.channelCount,\n\t\t});\n\t\tthis.pan = this._panVol.pan;\n\t\tthis.volume = this._panVol.volume;\n\n\t\tthis._solo.connect(this._panVol);\n\t\treadOnly(this, [\"pan\", \"volume\"]);\n\t}\n\n\tstatic getDefaults(): ChannelOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tpan: 0,\n\t\t\tvolume: 0,\n\t\t\tmute: false,\n\t\t\tsolo: false,\n\t\t\tchannelCount: 1,\n\t\t});\n\t}\n\n\t/**\n\t * Solo/unsolo the channel. Soloing is only relative to other {@link Channel}s and {@link Solo} instances\n\t */\n\tget solo(): boolean {\n\t\treturn this._solo.solo;\n\t}\n\tset solo(solo) {\n\t\tthis._solo.solo = solo;\n\t}\n\n\t/**\n\t * If the current instance is muted, i.e. another instance is soloed,\n\t * or the channel is muted\n\t */\n\tget muted(): boolean {\n\t\treturn this._solo.muted || this.mute;\n\t}\n\n\t/**\n\t * Mute/unmute the volume\n\t */\n\tget mute(): boolean {\n\t\treturn this._panVol.mute;\n\t}\n\tset mute(mute) {\n\t\tthis._panVol.mute = mute;\n\t}\n\n\t/**\n\t * Store the send/receive channels by name.\n\t */\n\tprivate static buses: Map<string, Gain> = new Map();\n\n\t/**\n\t * Get the gain node belonging to the bus name. Create it if\n\t * it doesn't exist\n\t * @param name The bus name\n\t */\n\tprivate _getBus(name: string): Gain {\n\t\tif (!Channel.buses.has(name)) {\n\t\t\tChannel.buses.set(name, new Gain({ context: this.context }));\n\t\t}\n\t\treturn Channel.buses.get(name) as Gain;\n\t}\n\n\t/**\n\t * Send audio to another channel using a string. `send` is a lot like\n\t * {@link connect}, except it uses a string instead of an object. This can\n\t * be useful in large applications to decouple sections since {@link send}\n\t * and {@link receive} can be invoked separately in order to connect an object\n\t * @param name The channel name to send the audio\n\t * @param volume The amount of the signal to send.\n\t * \tDefaults to 0db, i.e. send the entire signal\n\t * @returns Returns the gain node of this connection.\n\t */\n\tsend(name: string, volume: Decibels = 0): Gain<\"decibels\"> {\n\t\tconst bus = this._getBus(name);\n\t\tconst sendKnob = new Gain({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"decibels\",\n\t\t\tgain: volume,\n\t\t});\n\t\tthis.connect(sendKnob);\n\t\tsendKnob.connect(bus);\n\t\treturn sendKnob;\n\t}\n\n\t/**\n\t * Receive audio from a channel which was connected with {@link send}.\n\t * @param name The channel name to receive audio from.\n\t */\n\treceive(name: string): this {\n\t\tconst bus = this._getBus(name);\n\t\tbus.connect(this);\n\t\treturn this;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._panVol.dispose();\n\t\tthis.pan.dispose();\n\t\tthis.volume.dispose();\n\t\tthis._solo.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/channel/CrossFade.test.ts",
    "content": "import { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { connectFrom, connectTo } from \"../../../test/helper/Connect.js\";\nimport { ConstantOutput } from \"../../../test/helper/ConstantOutput.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { CrossFade } from \"./CrossFade.js\";\n\ndescribe(\"CrossFade\", () => {\n\tBasicTests(CrossFade);\n\n\tcontext(\"Fading\", () => {\n\t\tit(\"handles input and output connections\", () => {\n\t\t\tconst comp = new CrossFade();\n\t\t\tconnectFrom().connect(comp.a);\n\t\t\tconnectFrom().connect(comp.b);\n\t\t\tcomp.connect(connectTo());\n\t\t\tcomp.dispose();\n\t\t});\n\n\t\tit(\"pass 100% of input 0\", () => {\n\t\t\treturn ConstantOutput(\n\t\t\t\t() => {\n\t\t\t\t\tconst crossFade = new CrossFade();\n\t\t\t\t\tconst drySignal = new Signal(10);\n\t\t\t\t\tconst wetSignal = new Signal(20);\n\t\t\t\t\tdrySignal.connect(crossFade.a);\n\t\t\t\t\twetSignal.connect(crossFade.b);\n\t\t\t\t\tcrossFade.fade.value = 0;\n\t\t\t\t\tcrossFade.toDestination();\n\t\t\t\t},\n\t\t\t\t10,\n\t\t\t\t0.05\n\t\t\t);\n\t\t});\n\n\t\tit(\"pass 100% of input 1\", () => {\n\t\t\treturn ConstantOutput(\n\t\t\t\t() => {\n\t\t\t\t\tconst crossFade = new CrossFade();\n\t\t\t\t\tconst drySignal = new Signal(10);\n\t\t\t\t\tconst wetSignal = new Signal(20);\n\t\t\t\t\tdrySignal.connect(crossFade.a);\n\t\t\t\t\twetSignal.connect(crossFade.b);\n\t\t\t\t\tcrossFade.fade.value = 1;\n\t\t\t\t\tcrossFade.toDestination();\n\t\t\t\t},\n\t\t\t\t20,\n\t\t\t\t0.01\n\t\t\t);\n\t\t});\n\n\t\tit(\"can mix two signals\", () => {\n\t\t\treturn ConstantOutput(\n\t\t\t\t() => {\n\t\t\t\t\tconst crossFade = new CrossFade();\n\t\t\t\t\tconst drySignal = new Signal(2);\n\t\t\t\t\tconst wetSignal = new Signal(1);\n\t\t\t\t\tdrySignal.connect(crossFade.a);\n\t\t\t\t\twetSignal.connect(crossFade.b);\n\t\t\t\t\tcrossFade.fade.value = 0.5;\n\t\t\t\t\tcrossFade.toDestination();\n\t\t\t\t},\n\t\t\t\t2.12,\n\t\t\t\t0.01\n\t\t\t);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/channel/CrossFade.ts",
    "content": "import { Gain } from \"../../core/context/Gain.js\";\nimport {\n\tconnect,\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { NormalRange } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly } from \"../../core/util/Interface.js\";\nimport { GainToAudio } from \"../../signal/GainToAudio.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { ToneConstantSource } from \"../../signal/ToneConstantSource.js\";\n\ninterface CrossFadeOptions extends ToneAudioNodeOptions {\n\tfade: NormalRange;\n}\n\n/**\n * Tone.Crossfade provides equal power fading between two inputs.\n * More on crossfading technique [here](https://en.wikipedia.org/wiki/Fade_(audio_engineering)#Crossfading).\n * ```\n *                                             +---------+\n *                                            +> input a +>--+\n * +-----------+   +---------------------+     |         |   |\n * | 1s signal +>--> stereoPannerNode  L +>----> gain    |   |\n * +-----------+   |                     |     +---------+   |\n *               +-> pan               R +>-+                |   +--------+\n *               | +---------------------+  |                +---> output +>\n *  +------+     |                          |  +---------+   |   +--------+\n *  | fade +>----+                          | +> input b +>--+\n *  +------+                                |  |         |\n *                                          +--> gain    |\n *                                             +---------+\n * ```\n * @example\n * const crossFade = new Tone.CrossFade().toDestination();\n * // connect two inputs Tone.to a/b\n * const inputA = new Tone.Oscillator(440, \"square\").connect(crossFade.a).start();\n * const inputB = new Tone.Oscillator(440, \"sine\").connect(crossFade.b).start();\n * // use the fade to control the mix between the two\n * crossFade.fade.value = 0.5;\n * @category Component\n */\nexport class CrossFade extends ToneAudioNode<CrossFadeOptions> {\n\treadonly name: string = \"CrossFade\";\n\n\t/**\n\t * The crossfading is done by a StereoPannerNode\n\t */\n\tprivate _panner: StereoPannerNode = this.context.createStereoPanner();\n\n\t/**\n\t * Split the output of the panner node into two values used to control the gains.\n\t */\n\tprivate _split: ChannelSplitterNode = this.context.createChannelSplitter(2);\n\n\t/**\n\t * Convert the fade value into an audio range value so it can be connected\n\t * to the panner.pan AudioParam\n\t */\n\tprivate _g2a: GainToAudio = new GainToAudio({ context: this.context });\n\n\t/**\n\t * The constant source which is used to control the panner\n\t */\n\tprivate _constant: ToneConstantSource;\n\n\t/**\n\t * The input which is at full level when fade = 0\n\t */\n\treadonly a: Gain = new Gain({\n\t\tcontext: this.context,\n\t\tgain: 0,\n\t});\n\n\t/**\n\t * The input which is at full level when fade = 1\n\t */\n\treadonly b: Gain = new Gain({\n\t\tcontext: this.context,\n\t\tgain: 0,\n\t});\n\n\t/**\n\t * The output is a mix between `a` and `b` at the ratio of `fade`\n\t */\n\treadonly output: Gain = new Gain({ context: this.context });\n\n\t/**\n\t * CrossFade has no input, you must choose either `a` or `b`\n\t */\n\treadonly input: undefined;\n\n\t/**\n\t * The mix between the two inputs. A fade value of 0\n\t * will output 100% crossFade.a and\n\t * a value of 1 will output 100% crossFade.b.\n\t */\n\treadonly fade: Signal<\"normalRange\">;\n\n\tprotected _internalChannels = [this.a, this.b];\n\n\t/**\n\t * @param fade The initial fade value [0, 1].\n\t */\n\tconstructor(fade?: NormalRange);\n\tconstructor(options?: Partial<CrossFadeOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tCrossFade.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"fade\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.fade = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"normalRange\",\n\t\t\tvalue: options.fade,\n\t\t});\n\t\treadOnly(this, \"fade\");\n\n\t\tthis._constant = new ToneConstantSource({\n\t\t\tcontext: this.context,\n\t\t\toffset: 1,\n\t\t}).start();\n\t\tthis._constant.connect(this._panner);\n\t\tthis._panner.connect(this._split);\n\t\t// this is necessary for standardized-audio-context\n\t\t// doesn't make any difference for the native AudioContext\n\t\t// https://github.com/chrisguttandin/standardized-audio-context/issues/647\n\t\tthis._panner.channelCount = 1;\n\t\tthis._panner.channelCountMode = \"explicit\";\n\t\tconnect(this._split, this.a.gain, 0);\n\t\tconnect(this._split, this.b.gain, 1);\n\n\t\tthis.fade.chain(this._g2a, this._panner.pan);\n\n\t\tthis.a.connect(this.output);\n\t\tthis.b.connect(this.output);\n\t}\n\n\tstatic getDefaults(): CrossFadeOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tfade: 0.5,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.a.dispose();\n\t\tthis.b.dispose();\n\t\tthis.output.dispose();\n\t\tthis.fade.dispose();\n\t\tthis._g2a.dispose();\n\t\tthis._panner.disconnect();\n\t\tthis._split.disconnect();\n\t\tthis._constant.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/channel/Merge.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { connectFrom, connectTo } from \"../../../test/helper/Connect.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { Merge } from \"./Merge.js\";\n\ndescribe(\"Merge\", () => {\n\tBasicTests(Merge);\n\n\tcontext(\"Merging\", () => {\n\t\tit(\"handles input and output connections\", () => {\n\t\t\tconst merge = new Merge();\n\t\t\tconnectFrom().connect(merge);\n\t\t\tmerge.connect(connectTo());\n\t\t\tmerge.dispose();\n\t\t});\n\n\t\tit(\"defaults to two channels\", () => {\n\t\t\tconst merge = new Merge();\n\t\t\texpect(merge.numberOfInputs).to.equal(2);\n\t\t\tmerge.dispose();\n\t\t});\n\n\t\tit(\"can pass in more channels\", () => {\n\t\t\tconst merge = new Merge(4);\n\t\t\texpect(merge.numberOfInputs).to.equal(4);\n\t\t\tconnectFrom().connect(merge, 0, 0);\n\t\t\tconnectFrom().connect(merge, 0, 1);\n\t\t\tconnectFrom().connect(merge, 0, 2);\n\t\t\tconnectFrom().connect(merge, 0, 3);\n\t\t\tmerge.dispose();\n\t\t});\n\n\t\tit(\"passes the incoming signal through\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst merge = new Merge().toDestination();\n\t\t\t\tinput.connect(merge);\n\t\t\t});\n\t\t});\n\n\t\tit(\"merge two signal into one stereo signal\", async () => {\n\t\t\tconst buffer = await Offline(\n\t\t\t\t() => {\n\t\t\t\t\tconst sigL = new Signal(1);\n\t\t\t\t\tconst sigR = new Signal(2);\n\t\t\t\t\tconst merger = new Merge();\n\t\t\t\t\tsigL.connect(merger, 0, 0);\n\t\t\t\t\tsigR.connect(merger, 0, 1);\n\t\t\t\t\tmerger.toDestination();\n\t\t\t\t},\n\t\t\t\t0.1,\n\t\t\t\t2\n\t\t\t);\n\t\t\texpect(buffer.toArray()[0][0]).to.be.closeTo(1, 0.001);\n\t\t\texpect(buffer.toArray()[1][0]).to.be.closeTo(2, 0.001);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/channel/Merge.ts",
    "content": "import {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { Positive } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\n\ninterface MergeOptions extends ToneAudioNodeOptions {\n\tchannels: Positive;\n}\n\n/**\n * Merge brings multiple mono input channels into a single multichannel output channel.\n *\n * @example\n * const merge = new Tone.Merge().toDestination();\n * // routing a sine tone in the left channel\n * const osc = new Tone.Oscillator().connect(merge, 0, 0).start();\n * // and noise in the right channel\n * const noise = new Tone.Noise().connect(merge, 0, 1).start();;\n * @category Component\n */\nexport class Merge extends ToneAudioNode<MergeOptions> {\n\treadonly name: string = \"Merge\";\n\n\t/**\n\t * The merger node for the channels.\n\t */\n\tprivate _merger: ChannelMergerNode;\n\n\t/**\n\t * The output is the input channels combined into a single (multichannel) output\n\t */\n\treadonly output: ChannelMergerNode;\n\n\t/**\n\t * Multiple input connections combine into a single output.\n\t */\n\treadonly input: ChannelMergerNode;\n\n\t/**\n\t * @param channels The number of channels to merge.\n\t */\n\tconstructor(channels?: Positive);\n\tconstructor(options?: Partial<MergeOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Merge.getDefaults(), arguments, [\n\t\t\t\"channels\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis._merger =\n\t\t\tthis.output =\n\t\t\tthis.input =\n\t\t\t\tthis.context.createChannelMerger(options.channels);\n\t}\n\n\tstatic getDefaults(): MergeOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tchannels: 2,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._merger.disconnect();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/channel/MidSideMerge.test.ts",
    "content": "import { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { connectFrom, connectTo } from \"../../../test/helper/Connect.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { MidSideMerge } from \"./MidSideMerge.js\";\n\ndescribe(\"MidSideMerge\", () => {\n\tBasicTests(MidSideMerge);\n\n\tcontext(\"Merging\", () => {\n\t\tit(\"handles inputs and outputs\", () => {\n\t\t\tconst merge = new MidSideMerge();\n\t\t\tmerge.connect(connectTo());\n\t\t\tconnectFrom().connect(merge.mid);\n\t\t\tconnectFrom().connect(merge.side);\n\t\t\tmerge.dispose();\n\t\t});\n\n\t\tit(\"passes the mid signal through\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst merge = new MidSideMerge().toDestination();\n\t\t\t\tinput.connect(merge.mid);\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/channel/MidSideMerge.ts",
    "content": "import { Gain } from \"../../core/context/Gain.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { Add } from \"../../signal/Add.js\";\nimport { Multiply } from \"../../signal/Multiply.js\";\nimport { Subtract } from \"../../signal/Subtract.js\";\nimport { Merge } from \"./Merge.js\";\n\nexport type MidSideMergeOptions = ToneAudioNodeOptions;\n\n/**\n * MidSideMerge merges the mid and side signal after they've been separated by {@link MidSideSplit}\n * ```\n * Mid = (Left+Right)/sqrt(2);   // obtain mid-signal from left and right\n * Side = (Left-Right)/sqrt(2);   // obtain side-signal from left and right\n * ```\n * @category Component\n */\nexport class MidSideMerge extends ToneAudioNode<MidSideMergeOptions> {\n\treadonly name: string = \"MidSideMerge\";\n\n\t/**\n\t * There is no input, connect sources to either {@link mid} or {@link side} inputs.\n\t */\n\treadonly input: undefined;\n\n\t/**\n\t * The merged signal\n\t */\n\treadonly output: Merge;\n\n\t/**\n\t * Merge the incoming signal into left and right channels\n\t */\n\tprivate _merge: Merge;\n\n\t/**\n\t * The \"mid\" input.\n\t */\n\treadonly mid: ToneAudioNode;\n\n\t/**\n\t * The \"side\" input.\n\t */\n\treadonly side: ToneAudioNode;\n\n\t/**\n\t * Recombine the mid/side into Left\n\t */\n\tprivate _left: Add;\n\n\t/**\n\t * Recombine the mid/side into Right\n\t */\n\tprivate _right: Subtract;\n\n\t/**\n\t * Multiply the right by sqrt(1/2)\n\t */\n\tprivate _leftMult: Multiply;\n\n\t/**\n\t * Multiply the left by sqrt(1/2)\n\t */\n\tprivate _rightMult: Multiply;\n\n\tconstructor(options?: Partial<MidSideMergeOptions>);\n\tconstructor() {\n\t\tsuper(optionsFromArguments(MidSideMerge.getDefaults(), arguments));\n\t\tthis.mid = new Gain({ context: this.context });\n\t\tthis.side = new Gain({ context: this.context });\n\t\tthis._left = new Add({ context: this.context });\n\t\tthis._leftMult = new Multiply({\n\t\t\tcontext: this.context,\n\t\t\tvalue: Math.SQRT1_2,\n\t\t});\n\t\tthis._right = new Subtract({ context: this.context });\n\t\tthis._rightMult = new Multiply({\n\t\t\tcontext: this.context,\n\t\t\tvalue: Math.SQRT1_2,\n\t\t});\n\t\tthis._merge = this.output = new Merge({ context: this.context });\n\n\t\tthis.mid.fan(this._left);\n\t\tthis.side.connect(this._left.addend);\n\t\tthis.mid.connect(this._right);\n\t\tthis.side.connect(this._right.subtrahend);\n\t\tthis._left.connect(this._leftMult);\n\t\tthis._right.connect(this._rightMult);\n\t\tthis._leftMult.connect(this._merge, 0, 0);\n\t\tthis._rightMult.connect(this._merge, 0, 1);\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.mid.dispose();\n\t\tthis.side.dispose();\n\t\tthis._leftMult.dispose();\n\t\tthis._rightMult.dispose();\n\t\tthis._left.dispose();\n\t\tthis._right.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/channel/MidSideSplit.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { connectFrom, connectTo } from \"../../../test/helper/Connect.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { Merge } from \"./Merge.js\";\nimport { MidSideMerge } from \"./MidSideMerge.js\";\nimport { MidSideSplit } from \"./MidSideSplit.js\";\n\ndescribe(\"MidSideSplit\", () => {\n\tBasicTests(MidSideSplit);\n\n\tcontext(\"Splitting\", () => {\n\t\tit(\"handles inputs and outputs\", () => {\n\t\t\tconst split = new MidSideSplit();\n\t\t\tconnectFrom().connect(split);\n\t\t\tsplit.mid.connect(connectTo());\n\t\t\tsplit.side.connect(connectTo());\n\t\t\tsplit.dispose();\n\t\t});\n\n\t\tit(\"mid is if both L and R are the same\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst split = new MidSideSplit();\n\t\t\t\tsplit.mid.toDestination();\n\t\t\t\tconst merge = new Merge().connect(split);\n\t\t\t\tnew Signal(0.5).connect(merge, 0, 0);\n\t\t\t\tnew Signal(0.5).connect(merge, 0, 1);\n\t\t\t});\n\t\t\texpect(buffer.min()).to.be.closeTo(0.707, 0.01);\n\t\t\texpect(buffer.max()).to.be.closeTo(0.707, 0.01);\n\t\t});\n\n\t\tit(\"side is 0 if both L and R are the same\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst split = new MidSideSplit();\n\t\t\t\tsplit.side.toDestination();\n\t\t\t\tconst merge = new Merge().connect(split);\n\t\t\t\tnew Signal(0.5).connect(merge, 0, 0);\n\t\t\t\tnew Signal(0.5).connect(merge, 0, 1);\n\t\t\t});\n\t\t\texpect(buffer.min()).to.be.closeTo(0, 0.01);\n\t\t\texpect(buffer.max()).to.be.closeTo(0, 0.01);\n\t\t});\n\n\t\tit(\"mid is 0 if both L and R opposites\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst split = new MidSideSplit();\n\t\t\t\tsplit.mid.toDestination();\n\t\t\t\tconst merge = new Merge().connect(split);\n\t\t\t\tnew Signal(-1).connect(merge, 0, 0);\n\t\t\t\tnew Signal(1).connect(merge, 0, 1);\n\t\t\t});\n\t\t\texpect(buffer.min()).to.be.closeTo(0, 0.01);\n\t\t\texpect(buffer.max()).to.be.closeTo(0, 0.01);\n\t\t});\n\n\t\tit(\"can decompose and reconstruct a signal\", async () => {\n\t\t\tconst buffer = await Offline(\n\t\t\t\t() => {\n\t\t\t\t\tconst midSideMerge = new MidSideMerge().toDestination();\n\t\t\t\t\tconst split = new MidSideSplit();\n\t\t\t\t\tsplit.mid.connect(midSideMerge.mid);\n\t\t\t\t\tsplit.side.connect(midSideMerge.side);\n\t\t\t\t\tconst merge = new Merge().connect(split);\n\t\t\t\t\tnew Signal(0.2).connect(merge, 0, 0);\n\t\t\t\t\tnew Signal(0.4).connect(merge, 0, 1);\n\t\t\t\t},\n\t\t\t\t0.1,\n\t\t\t\t2\n\t\t\t);\n\t\t\tbuffer\n\t\t\t\t.toArray()[0]\n\t\t\t\t.forEach((l) => expect(l).to.be.closeTo(0.2, 0.01));\n\t\t\tbuffer\n\t\t\t\t.toArray()[1]\n\t\t\t\t.forEach((r) => expect(r).to.be.closeTo(0.4, 0.01));\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/channel/MidSideSplit.ts",
    "content": "import {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { Add } from \"../../signal/Add.js\";\nimport { Multiply } from \"../../signal/Multiply.js\";\nimport { Subtract } from \"../../signal/Subtract.js\";\nimport { Split } from \"./Split.js\";\n\nexport type MidSideSplitOptions = ToneAudioNodeOptions;\n\n/**\n * Mid/Side processing separates the the 'mid' signal (which comes out of both the left and the right channel)\n * and the 'side' (which only comes out of the the side channels).\n * ```\n * Mid = (Left+Right)/sqrt(2);   // obtain mid-signal from left and right\n * Side = (Left-Right)/sqrt(2);   // obtain side-signal from left and right\n * ```\n * @category Component\n */\nexport class MidSideSplit extends ToneAudioNode<MidSideSplitOptions> {\n\treadonly name: string = \"MidSideSplit\";\n\n\treadonly input: Split;\n\n\t/**\n\t * There is no output node, use either {@link mid} or {@link side} outputs.\n\t */\n\treadonly output: undefined;\n\t/**\n\t * Split the incoming signal into left and right channels\n\t */\n\tprivate _split: Split;\n\n\t/**\n\t * Sums the left and right channels\n\t */\n\tprivate _midAdd: Add;\n\n\t/**\n\t * Subtract left and right channels.\n\t */\n\tprivate _sideSubtract: Subtract;\n\n\t/**\n\t * The \"mid\" output. `(Left+Right)/sqrt(2)`\n\t */\n\treadonly mid: ToneAudioNode;\n\n\t/**\n\t * The \"side\" output. `(Left-Right)/sqrt(2)`\n\t */\n\treadonly side: ToneAudioNode;\n\n\tconstructor(options?: Partial<MidSideSplitOptions>);\n\tconstructor() {\n\t\tsuper(optionsFromArguments(MidSideSplit.getDefaults(), arguments));\n\n\t\tthis._split = this.input = new Split({\n\t\t\tchannels: 2,\n\t\t\tcontext: this.context,\n\t\t});\n\t\tthis._midAdd = new Add({ context: this.context });\n\t\tthis.mid = new Multiply({\n\t\t\tcontext: this.context,\n\t\t\tvalue: Math.SQRT1_2,\n\t\t});\n\t\tthis._sideSubtract = new Subtract({ context: this.context });\n\t\tthis.side = new Multiply({\n\t\t\tcontext: this.context,\n\t\t\tvalue: Math.SQRT1_2,\n\t\t});\n\n\t\tthis._split.connect(this._midAdd, 0);\n\t\tthis._split.connect(this._midAdd.addend, 1);\n\t\tthis._split.connect(this._sideSubtract, 0);\n\t\tthis._split.connect(this._sideSubtract.subtrahend, 1);\n\t\tthis._midAdd.connect(this.mid);\n\t\tthis._sideSubtract.connect(this.side);\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.mid.dispose();\n\t\tthis.side.dispose();\n\t\tthis._midAdd.dispose();\n\t\tthis._sideSubtract.dispose();\n\t\tthis._split.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/channel/Mono.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { StereoSignal } from \"../../../test/helper/StereoSignal.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { Mono } from \"./Mono.js\";\n\ndescribe(\"Mono\", () => {\n\tBasicTests(Mono);\n\n\tcontext(\"Mono\", () => {\n\t\tit(\"Makes a mono signal in both channels\", async () => {\n\t\t\tconst buffer = await Offline(\n\t\t\t\t() => {\n\t\t\t\t\tconst mono = new Mono().toDestination();\n\t\t\t\t\tconst signal = new Signal(2).connect(mono);\n\t\t\t\t},\n\t\t\t\t0.1,\n\t\t\t\t2\n\t\t\t);\n\t\t\texpect(buffer.toArray()[0][0]).to.equal(2);\n\t\t\texpect(buffer.toArray()[1][0]).to.equal(2);\n\t\t\texpect(buffer.toArray()[0][100]).to.equal(2);\n\t\t\texpect(buffer.toArray()[1][100]).to.equal(2);\n\t\t\texpect(buffer.toArray()[0][1000]).to.equal(2);\n\t\t\texpect(buffer.toArray()[1][1000]).to.equal(2);\n\t\t});\n\n\t\tit(\"Sums a stereo signal into a mono signal\", async () => {\n\t\t\tconst buffer = await Offline(\n\t\t\t\t() => {\n\t\t\t\t\tconst mono = new Mono().toDestination();\n\t\t\t\t\tconst signal = StereoSignal(2, 2).connect(mono);\n\t\t\t\t},\n\t\t\t\t0.1,\n\t\t\t\t2\n\t\t\t);\n\t\t\texpect(buffer.toArray()[0][0]).to.equal(2);\n\t\t\texpect(buffer.toArray()[1][0]).to.equal(2);\n\t\t\texpect(buffer.toArray()[0][100]).to.equal(2);\n\t\t\texpect(buffer.toArray()[1][100]).to.equal(2);\n\t\t\texpect(buffer.toArray()[0][1000]).to.equal(2);\n\t\t\texpect(buffer.toArray()[1][1000]).to.equal(2);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/channel/Mono.ts",
    "content": "import { Gain } from \"../../core/context/Gain.js\";\nimport {\n\tOutputNode,\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { Merge } from \"./Merge.js\";\n\nexport type MonoOptions = ToneAudioNodeOptions;\n\n/**\n * Mono coerces the incoming mono or stereo signal into a mono signal\n * where both left and right channels have the same value. This can be useful\n * for [stereo imaging](https://en.wikipedia.org/wiki/Stereo_imaging).\n * @category Component\n */\nexport class Mono extends ToneAudioNode<MonoOptions> {\n\treadonly name: string = \"Mono\";\n\n\t/**\n\t * merge the signal\n\t */\n\tprivate _merge: Merge;\n\n\t/**\n\t * The summed output of the multiple inputs\n\t */\n\treadonly output: OutputNode;\n\n\t/**\n\t * The stereo signal to sum to mono\n\t */\n\treadonly input: Gain;\n\n\tconstructor(options?: Partial<MonoOptions>);\n\tconstructor() {\n\t\tsuper(optionsFromArguments(Mono.getDefaults(), arguments));\n\n\t\tthis.input = new Gain({ context: this.context });\n\n\t\tthis._merge = this.output = new Merge({\n\t\t\tchannels: 2,\n\t\t\tcontext: this.context,\n\t\t});\n\n\t\tthis.input.connect(this._merge, 0, 0);\n\t\tthis.input.connect(this._merge, 0, 1);\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._merge.dispose();\n\t\tthis.input.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/channel/MultibandSplit.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { connectFrom, connectTo } from \"../../../test/helper/Connect.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { MultibandSplit } from \"./MultibandSplit.js\";\n\ndescribe(\"MultibandSplit\", () => {\n\tBasicTests(MultibandSplit);\n\n\tit(\"handles input and output connections\", () => {\n\t\tconst split = new MultibandSplit();\n\t\tconnectFrom().connect(split);\n\t\tsplit.low.connect(connectTo());\n\t\tsplit.mid.connect(connectTo());\n\t\tsplit.high.connect(connectTo());\n\t\tsplit.dispose();\n\t});\n\n\tit(\"can be constructed with an object\", () => {\n\t\tconst split = new MultibandSplit({\n\t\t\tQ: 8,\n\t\t\thighFrequency: 2700,\n\t\t\tlowFrequency: 500,\n\t\t});\n\t\texpect(split.lowFrequency.value).to.be.closeTo(500, 0.01);\n\t\texpect(split.highFrequency.value).to.be.closeTo(2700, 0.01);\n\t\texpect(split.Q.value).to.be.closeTo(8, 0.01);\n\t\tsplit.dispose();\n\t});\n\n\tit(\"can be get and set through object\", () => {\n\t\tconst split = new MultibandSplit();\n\t\tsplit.set({\n\t\t\tQ: 4,\n\t\t\tlowFrequency: 250,\n\t\t});\n\t\texpect(split.get().Q).to.be.closeTo(4, 0.1);\n\t\texpect(split.get().lowFrequency).to.be.closeTo(250, 0.01);\n\t\tsplit.dispose();\n\t});\n\n\tit(\"passes the incoming signal through low\", () => {\n\t\treturn PassAudio((input) => {\n\t\t\tconst split = new MultibandSplit().low.toDestination();\n\t\t\tinput.connect(split);\n\t\t});\n\t});\n\n\tit(\"passes the incoming signal through mid\", () => {\n\t\treturn PassAudio((input) => {\n\t\t\tconst split = new MultibandSplit().mid.toDestination();\n\t\t\tinput.connect(split);\n\t\t});\n\t});\n\n\tit(\"passes the incoming signal through high\", () => {\n\t\treturn PassAudio((input) => {\n\t\t\tconst split = new MultibandSplit({\n\t\t\t\thighFrequency: 10,\n\t\t\t\tlowFrequency: 5,\n\t\t\t}).high.toDestination();\n\t\t\tinput.connect(split);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/channel/MultibandSplit.ts",
    "content": "import { Gain } from \"../../core/context/Gain.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { Frequency, Positive } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly, writable } from \"../../core/util/Interface.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { Filter } from \"../filter/Filter.js\";\n\ninterface MultibandSplitOptions extends ToneAudioNodeOptions {\n\tQ: Positive;\n\tlowFrequency: Frequency;\n\thighFrequency: Frequency;\n}\n\n/**\n * Split the incoming signal into three bands (low, mid, high)\n * with two crossover frequency controls.\n * ```\n *            +----------------------+\n *          +-> input < lowFrequency +------------------> low\n *          | +----------------------+\n *          |\n *          | +--------------------------------------+\n * input ---+-> lowFrequency < input < highFrequency +--> mid\n *          | +--------------------------------------+\n *          |\n *          | +-----------------------+\n *          +-> highFrequency < input +-----------------> high\n *            +-----------------------+\n * ```\n * @category Component\n */\nexport class MultibandSplit extends ToneAudioNode<MultibandSplitOptions> {\n\treadonly name: string = \"MultibandSplit\";\n\n\t/**\n\t * the input\n\t */\n\treadonly input = new Gain({ context: this.context });\n\n\t/**\n\t * no output node, use either low, mid or high outputs\n\t */\n\treadonly output = undefined;\n\n\t/**\n\t * The low band.\n\t */\n\treadonly low = new Filter({\n\t\tcontext: this.context,\n\t\tfrequency: 0,\n\t\ttype: \"lowpass\",\n\t});\n\n\t/**\n\t * the lower filter of the mid band\n\t */\n\tprivate _lowMidFilter = new Filter({\n\t\tcontext: this.context,\n\t\tfrequency: 0,\n\t\ttype: \"highpass\",\n\t});\n\n\t/**\n\t * The mid band output.\n\t */\n\treadonly mid = new Filter({\n\t\tcontext: this.context,\n\t\tfrequency: 0,\n\t\ttype: \"lowpass\",\n\t});\n\n\t/**\n\t * The high band output.\n\t */\n\treadonly high = new Filter({\n\t\tcontext: this.context,\n\t\tfrequency: 0,\n\t\ttype: \"highpass\",\n\t});\n\n\t/**\n\t * The low/mid crossover frequency.\n\t */\n\treadonly lowFrequency: Signal<\"frequency\">;\n\n\t/**\n\t * The mid/high crossover frequency.\n\t */\n\treadonly highFrequency: Signal<\"frequency\">;\n\n\tprotected _internalChannels = [this.low, this.mid, this.high];\n\n\t/**\n\t * The Q or Quality of the filter\n\t */\n\treadonly Q: Signal<\"positive\">;\n\n\t/**\n\t * @param lowFrequency the low/mid crossover frequency\n\t * @param highFrequency the mid/high crossover frequency\n\t */\n\tconstructor(lowFrequency?: Frequency, highFrequency?: Frequency);\n\tconstructor(options?: Partial<MultibandSplitOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tMultibandSplit.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"lowFrequency\", \"highFrequency\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.lowFrequency = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"frequency\",\n\t\t\tvalue: options.lowFrequency,\n\t\t});\n\n\t\tthis.highFrequency = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"frequency\",\n\t\t\tvalue: options.highFrequency,\n\t\t});\n\n\t\tthis.Q = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"positive\",\n\t\t\tvalue: options.Q,\n\t\t});\n\n\t\tthis.input.fan(this.low, this.high);\n\t\tthis.input.chain(this._lowMidFilter, this.mid);\n\t\t// the frequency control signal\n\t\tthis.lowFrequency.fan(this.low.frequency, this._lowMidFilter.frequency);\n\t\tthis.highFrequency.fan(this.mid.frequency, this.high.frequency);\n\t\t// the Q value\n\t\tthis.Q.connect(this.low.Q);\n\t\tthis.Q.connect(this._lowMidFilter.Q);\n\t\tthis.Q.connect(this.mid.Q);\n\t\tthis.Q.connect(this.high.Q);\n\n\t\treadOnly(this, [\"high\", \"mid\", \"low\", \"highFrequency\", \"lowFrequency\"]);\n\t}\n\n\tstatic getDefaults(): MultibandSplitOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tQ: 1,\n\t\t\thighFrequency: 2500,\n\t\t\tlowFrequency: 400,\n\t\t});\n\t}\n\n\t/**\n\t * Clean up.\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\twritable(this, [\"high\", \"mid\", \"low\", \"highFrequency\", \"lowFrequency\"]);\n\t\tthis.low.dispose();\n\t\tthis._lowMidFilter.dispose();\n\t\tthis.mid.dispose();\n\t\tthis.high.dispose();\n\t\tthis.lowFrequency.dispose();\n\t\tthis.highFrequency.dispose();\n\t\tthis.Q.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/channel/PanVol.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { PanVol } from \"./PanVol.js\";\n\ndescribe(\"PanVol\", () => {\n\tBasicTests(PanVol);\n\n\tcontext(\"Pan and Volume\", () => {\n\t\tit(\"can be constructed with the panning and volume value\", () => {\n\t\t\tconst panVol = new PanVol(0.3, -12);\n\t\t\texpect(panVol.pan.value).to.be.closeTo(0.3, 0.001);\n\t\t\texpect(panVol.volume.value).to.be.closeTo(-12, 0.1);\n\t\t\tpanVol.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an options object\", () => {\n\t\t\tconst panVol = new PanVol({\n\t\t\t\tmute: true,\n\t\t\t\tpan: 0.2,\n\t\t\t});\n\t\t\texpect(panVol.pan.value).to.be.closeTo(0.2, 0.001);\n\t\t\texpect(panVol.mute).to.be.true;\n\t\t\tpanVol.dispose();\n\t\t});\n\n\t\tit(\"can set/get with an object\", () => {\n\t\t\tconst panVol = new PanVol();\n\t\t\tpanVol.set({\n\t\t\t\tvolume: -10,\n\t\t\t});\n\t\t\texpect(panVol.get().volume).to.be.closeTo(-10, 0.1);\n\t\t\tpanVol.dispose();\n\t\t});\n\n\t\tit(\"passes the incoming signal through\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst panVol = new PanVol().toDestination();\n\t\t\t\tinput.connect(panVol);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can mute the volume\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst vol = new PanVol(0).toDestination();\n\t\t\t\tnew Signal(1).connect(vol);\n\t\t\t\tvol.mute = true;\n\t\t\t});\n\t\t\texpect(buffer.isSilent()).to.be.true;\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/channel/PanVol.ts",
    "content": "import { Param } from \"../../core/context/Param.js\";\nimport {\n\tInputNode,\n\tOutputNode,\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { AudioRange, Decibels } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly } from \"../../core/util/Interface.js\";\nimport { Panner } from \"./Panner.js\";\nimport { Volume } from \"./Volume.js\";\n\nexport interface PanVolOptions extends ToneAudioNodeOptions {\n\tpan: AudioRange;\n\tvolume: Decibels;\n\tmute: boolean;\n\tchannelCount: number;\n}\n\n/**\n * PanVol is a Tone.Panner and Tone.Volume in one.\n * @example\n * // pan the incoming signal left and drop the volume\n * const panVol = new Tone.PanVol(-0.25, -12).toDestination();\n * const osc = new Tone.Oscillator().connect(panVol).start();\n * @category Component\n */\nexport class PanVol extends ToneAudioNode<PanVolOptions> {\n\treadonly name: string = \"PanVol\";\n\n\treadonly input: InputNode;\n\treadonly output: OutputNode;\n\n\t/**\n\t * The panning node\n\t */\n\tprivate _panner: Panner;\n\n\t/**\n\t * The L/R panning control. -1 = hard left, 1 = hard right.\n\t * @min -1\n\t * @max 1\n\t */\n\treadonly pan: Param<\"audioRange\">;\n\n\t/**\n\t * The volume node\n\t */\n\tprivate _volume: Volume;\n\n\t/**\n\t * The volume control in decibels.\n\t */\n\treadonly volume: Param<\"decibels\">;\n\n\t/**\n\t * @param pan the initial pan\n\t * @param volume The output volume.\n\t */\n\tconstructor(pan?: AudioRange, volume?: Decibels);\n\tconstructor(options?: Partial<PanVolOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(PanVol.getDefaults(), arguments, [\n\t\t\t\"pan\",\n\t\t\t\"volume\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis._panner = this.input = new Panner({\n\t\t\tcontext: this.context,\n\t\t\tpan: options.pan,\n\t\t\tchannelCount: options.channelCount,\n\t\t});\n\t\tthis.pan = this._panner.pan;\n\t\tthis._volume = this.output = new Volume({\n\t\t\tcontext: this.context,\n\t\t\tvolume: options.volume,\n\t\t});\n\t\tthis.volume = this._volume.volume;\n\n\t\t// connections\n\t\tthis._panner.connect(this._volume);\n\t\tthis.mute = options.mute;\n\n\t\treadOnly(this, [\"pan\", \"volume\"]);\n\t}\n\n\tstatic getDefaults(): PanVolOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tmute: false,\n\t\t\tpan: 0,\n\t\t\tvolume: 0,\n\t\t\tchannelCount: 1,\n\t\t});\n\t}\n\n\t/**\n\t * Mute/unmute the volume\n\t */\n\tget mute(): boolean {\n\t\treturn this._volume.mute;\n\t}\n\tset mute(mute) {\n\t\tthis._volume.mute = mute;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._panner.dispose();\n\t\tthis.pan.dispose();\n\t\tthis._volume.dispose();\n\t\tthis.volume.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/channel/Panner.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { Panner } from \"./Panner.js\";\n\ndescribe(\"Panner\", () => {\n\tBasicTests(Panner);\n\n\tcontext(\"Panning\", () => {\n\t\tit(\"can be constructed with the panning value\", () => {\n\t\t\tconst panner = new Panner(0.3);\n\t\t\texpect(panner.pan.value).to.be.closeTo(0.3, 0.001);\n\t\t\tpanner.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an options object\", () => {\n\t\t\tconst panner = new Panner({\n\t\t\t\tpan: 0.5,\n\t\t\t});\n\t\t\texpect(panner.pan.value).to.be.closeTo(0.5, 0.001);\n\t\t\tpanner.dispose();\n\t\t});\n\n\t\tit(\"passes the incoming signal through\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst panner = new Panner().toDestination();\n\t\t\t\tinput.connect(panner);\n\t\t\t});\n\t\t});\n\n\t\tit(\"pans hard left when the pan is set to -1\", async () => {\n\t\t\tconst buffer = await Offline(\n\t\t\t\t() => {\n\t\t\t\t\tconst panner = new Panner(-1).toDestination();\n\t\t\t\t\tnew Signal(1).connect(panner);\n\t\t\t\t},\n\t\t\t\t0.1,\n\t\t\t\t2\n\t\t\t);\n\t\t\tconst l = buffer.toArray()[0];\n\t\t\tconst r = buffer.toArray()[1];\n\t\t\texpect(l[0]).to.be.closeTo(1, 0.01);\n\t\t\texpect(r[0]).to.be.closeTo(0, 0.01);\n\t\t});\n\n\t\tit(\"pans hard right when the pan is set to 1\", async () => {\n\t\t\tconst buffer = await Offline(\n\t\t\t\t() => {\n\t\t\t\t\tconst panner = new Panner(1).toDestination();\n\t\t\t\t\tnew Signal(1).connect(panner);\n\t\t\t\t},\n\t\t\t\t0.1,\n\t\t\t\t2\n\t\t\t);\n\t\t\tconst l = buffer.toArray()[0];\n\t\t\tconst r = buffer.toArray()[1];\n\t\t\texpect(l[0]).to.be.closeTo(0, 0.01);\n\t\t\texpect(r[0]).to.be.closeTo(1, 0.01);\n\t\t});\n\n\t\tit(\"mixes the signal in equal power when panned center\", async () => {\n\t\t\tconst buffer = await Offline(\n\t\t\t\t() => {\n\t\t\t\t\tconst panner = new Panner(0).toDestination();\n\t\t\t\t\tnew Signal(1).connect(panner);\n\t\t\t\t},\n\t\t\t\t0.1,\n\t\t\t\t2\n\t\t\t);\n\t\t\tconst l = buffer.toArray()[0];\n\t\t\tconst r = buffer.toArray()[1];\n\t\t\texpect(l[0]).to.be.closeTo(0.707, 0.01);\n\t\t\texpect(r[0]).to.be.closeTo(0.707, 0.01);\n\t\t});\n\n\t\tit(\"can chain two panners when channelCount is 2\", async () => {\n\t\t\tconst buffer = await Offline(\n\t\t\t\t() => {\n\t\t\t\t\tconst panner1 = new Panner({\n\t\t\t\t\t\tchannelCount: 2,\n\t\t\t\t\t}).toDestination();\n\t\t\t\t\tconst panner0 = new Panner(-1).connect(panner1);\n\t\t\t\t\tnew Signal(1).connect(panner0);\n\t\t\t\t},\n\t\t\t\t0.1,\n\t\t\t\t2\n\t\t\t);\n\t\t\tconst l = buffer.toArray()[0];\n\t\t\tconst r = buffer.toArray()[1];\n\t\t\texpect(l[0]).to.be.closeTo(1, 0.01);\n\t\t\texpect(r[0]).to.be.closeTo(0, 0.01);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/channel/Panner.ts",
    "content": "import { Param } from \"../../core/context/Param.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { AudioRange } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly } from \"../../core/util/Interface.js\";\n\ninterface TonePannerOptions extends ToneAudioNodeOptions {\n\tpan: AudioRange;\n\tchannelCount: number;\n}\n\n/**\n * Panner is an equal power Left/Right Panner. It is a wrapper around the StereoPannerNode.\n * @example\n * return Tone.Offline(() => {\n * // move the input signal from right to left\n * \tconst panner = new Tone.Panner(1).toDestination();\n * \tpanner.pan.rampTo(-1, 0.5);\n * \tconst osc = new Tone.Oscillator(100).connect(panner).start();\n * }, 0.5, 2);\n * @category Component\n */\nexport class Panner extends ToneAudioNode<TonePannerOptions> {\n\treadonly name: string = \"Panner\";\n\n\t/**\n\t * the panner node\n\t */\n\tprivate _panner: StereoPannerNode = this.context.createStereoPanner();\n\treadonly input: StereoPannerNode = this._panner;\n\treadonly output: StereoPannerNode = this._panner;\n\n\t/**\n\t * The pan control. -1 = hard left, 1 = hard right.\n\t * @min -1\n\t * @max 1\n\t * @example\n\t * return Tone.Offline(() => {\n\t * \t// pan hard right\n\t * \tconst panner = new Tone.Panner(1).toDestination();\n\t * \t// pan hard left\n\t * \tpanner.pan.setValueAtTime(-1, 0.25);\n\t * \tconst osc = new Tone.Oscillator(50, \"triangle\").connect(panner).start();\n\t * }, 0.5, 2);\n\t */\n\treadonly pan: Param<\"audioRange\">;\n\n\tconstructor(options?: Partial<TonePannerOptions>);\n\t/**\n\t * @param pan The initial panner value (Defaults to 0 = \"center\").\n\t */\n\tconstructor(pan?: AudioRange);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Panner.getDefaults(), arguments, [\n\t\t\t\"pan\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis.pan = new Param({\n\t\t\tcontext: this.context,\n\t\t\tparam: this._panner.pan,\n\t\t\tvalue: options.pan,\n\t\t\tminValue: -1,\n\t\t\tmaxValue: 1,\n\t\t});\n\n\t\t// this is necessary for standardized-audio-context\n\t\t// doesn't make any difference for the native AudioContext\n\t\t// https://github.com/chrisguttandin/standardized-audio-context/issues/647\n\t\tthis._panner.channelCount = options.channelCount;\n\t\tthis._panner.channelCountMode = \"explicit\";\n\n\t\t// initial value\n\t\treadOnly(this, \"pan\");\n\t}\n\n\tstatic getDefaults(): TonePannerOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tpan: 0,\n\t\t\tchannelCount: 1,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._panner.disconnect();\n\t\tthis.pan.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/channel/Panner3D.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { Panner3D } from \"./Panner3D.js\";\n\ndescribe(\"Panner3D\", () => {\n\tBasicTests(Panner3D);\n\n\tit(\"passes the incoming signal through\", () => {\n\t\treturn PassAudio((input) => {\n\t\t\tconst panner = new Panner3D().toDestination();\n\t\t\tinput.connect(panner);\n\t\t});\n\t});\n\n\tit(\"can get/set the position individually\", () => {\n\t\tconst panner = new Panner3D();\n\t\tpanner.positionX.value = 10;\n\t\texpect(panner.positionX.value).to.equal(10);\n\t\tpanner.positionY.value = 20;\n\t\texpect(panner.positionY.value).to.equal(20);\n\t\tpanner.positionZ.value = -1;\n\t\texpect(panner.positionZ.value).to.equal(-1);\n\t\tpanner.dispose();\n\t});\n\n\tit(\"can get/set the orientation individually\", () => {\n\t\tconst panner = new Panner3D();\n\t\tpanner.orientationX.value = 2;\n\t\texpect(panner.orientationX.value).to.equal(2);\n\t\tpanner.orientationY.value = 4;\n\t\texpect(panner.orientationY.value).to.equal(4);\n\t\tpanner.orientationZ.value = -3;\n\t\texpect(panner.orientationZ.value).to.equal(-3);\n\t\tpanner.dispose();\n\t});\n\n\tit(\"can get/set the position through setPosition\", () => {\n\t\tconst panner = new Panner3D();\n\t\tpanner.setPosition(3, -11, 2);\n\t\texpect(panner.positionX.value).to.equal(3);\n\t\texpect(panner.positionY.value).to.equal(-11);\n\t\texpect(panner.positionZ.value).to.equal(2);\n\t\tpanner.dispose();\n\t});\n\n\tit(\"can get/set the orientation through setOrientation\", () => {\n\t\tconst panner = new Panner3D();\n\t\tpanner.setOrientation(2, -1, 0.5);\n\t\texpect(panner.orientationX.value).to.equal(2);\n\t\texpect(panner.orientationY.value).to.equal(-1);\n\t\texpect(panner.orientationZ.value).to.equal(0.5);\n\t\tpanner.dispose();\n\t});\n\n\tit(\"can get/set all of the other attributes\", () => {\n\t\tconst values = {\n\t\t\tconeInnerAngle: 120,\n\t\t\tconeOuterAngle: 280,\n\t\t\tconeOuterGain: 0.3,\n\t\t\tdistanceModel: \"exponential\",\n\t\t\tmaxDistance: 10002,\n\t\t\tpanningModel: \"HRTF\",\n\t\t\trefDistance: 0.3,\n\t\t\trolloffFactor: 3,\n\t\t};\n\t\tconst panner = new Panner3D();\n\t\tfor (const v in values) {\n\t\t\tif (v in values) {\n\t\t\t\tpanner[v] = values[v];\n\t\t\t\texpect(panner[v]).to.equal(values[v]);\n\t\t\t}\n\t\t}\n\t\tpanner.dispose();\n\t});\n});\n"
  },
  {
    "path": "Tone/component/channel/Panner3D.ts",
    "content": "import \"../../core/context/Listener.js\";\n\nimport { Param } from \"../../core/context/Param.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { Degrees, GainFactor } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\n\nexport interface Panner3DOptions extends ToneAudioNodeOptions {\n\tconeInnerAngle: Degrees;\n\tconeOuterAngle: Degrees;\n\tconeOuterGain: GainFactor;\n\tdistanceModel: DistanceModelType;\n\tmaxDistance: number;\n\torientationX: number;\n\torientationY: number;\n\torientationZ: number;\n\tpanningModel: PanningModelType;\n\tpositionX: number;\n\tpositionY: number;\n\tpositionZ: number;\n\trefDistance: number;\n\trolloffFactor: number;\n}\n\n/**\n * A spatialized panner node which supports equalpower or HRTF panning.\n * @category Component\n */\nexport class Panner3D extends ToneAudioNode<Panner3DOptions> {\n\treadonly name: string = \"Panner3D\";\n\n\t/**\n\t * The panning object\n\t */\n\tprivate _panner: PannerNode;\n\treadonly input: PannerNode;\n\treadonly output: PannerNode;\n\n\treadonly positionX: Param<\"number\">;\n\treadonly positionY: Param<\"number\">;\n\treadonly positionZ: Param<\"number\">;\n\n\treadonly orientationX: Param<\"number\">;\n\treadonly orientationY: Param<\"number\">;\n\treadonly orientationZ: Param<\"number\">;\n\n\t/**\n\t * @param positionX The initial x position.\n\t * @param positionY The initial y position.\n\t * @param positionZ The initial z position.\n\t */\n\tconstructor(positionX: number, positionY: number, positionZ: number);\n\tconstructor(options?: Partial<Panner3DOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tPanner3D.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"positionX\", \"positionY\", \"positionZ\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._panner = this.input = this.output = this.context.createPanner();\n\t\t// set some values\n\t\tthis.panningModel = options.panningModel;\n\t\tthis.maxDistance = options.maxDistance;\n\t\tthis.distanceModel = options.distanceModel;\n\t\tthis.coneOuterGain = options.coneOuterGain;\n\t\tthis.coneOuterAngle = options.coneOuterAngle;\n\t\tthis.coneInnerAngle = options.coneInnerAngle;\n\t\tthis.refDistance = options.refDistance;\n\t\tthis.rolloffFactor = options.rolloffFactor;\n\n\t\tthis.positionX = new Param({\n\t\t\tcontext: this.context,\n\t\t\tparam: this._panner.positionX,\n\t\t\tvalue: options.positionX,\n\t\t});\n\t\tthis.positionY = new Param({\n\t\t\tcontext: this.context,\n\t\t\tparam: this._panner.positionY,\n\t\t\tvalue: options.positionY,\n\t\t});\n\t\tthis.positionZ = new Param({\n\t\t\tcontext: this.context,\n\t\t\tparam: this._panner.positionZ,\n\t\t\tvalue: options.positionZ,\n\t\t});\n\t\tthis.orientationX = new Param({\n\t\t\tcontext: this.context,\n\t\t\tparam: this._panner.orientationX,\n\t\t\tvalue: options.orientationX,\n\t\t});\n\t\tthis.orientationY = new Param({\n\t\t\tcontext: this.context,\n\t\t\tparam: this._panner.orientationY,\n\t\t\tvalue: options.orientationY,\n\t\t});\n\t\tthis.orientationZ = new Param({\n\t\t\tcontext: this.context,\n\t\t\tparam: this._panner.orientationZ,\n\t\t\tvalue: options.orientationZ,\n\t\t});\n\t}\n\n\tstatic getDefaults(): Panner3DOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tconeInnerAngle: 360,\n\t\t\tconeOuterAngle: 360,\n\t\t\tconeOuterGain: 0,\n\t\t\tdistanceModel: \"inverse\" as DistanceModelType,\n\t\t\tmaxDistance: 10000,\n\t\t\torientationX: 0,\n\t\t\torientationY: 0,\n\t\t\torientationZ: 0,\n\t\t\tpanningModel: \"equalpower\" as PanningModelType,\n\t\t\tpositionX: 0,\n\t\t\tpositionY: 0,\n\t\t\tpositionZ: 0,\n\t\t\trefDistance: 1,\n\t\t\trolloffFactor: 1,\n\t\t});\n\t}\n\n\t/**\n\t * Sets the position of the source in 3d space.\n\t */\n\tsetPosition(x: number, y: number, z: number): this {\n\t\tthis.positionX.value = x;\n\t\tthis.positionY.value = y;\n\t\tthis.positionZ.value = z;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the orientation of the source in 3d space.\n\t */\n\tsetOrientation(x: number, y: number, z: number): this {\n\t\tthis.orientationX.value = x;\n\t\tthis.orientationY.value = y;\n\t\tthis.orientationZ.value = z;\n\t\treturn this;\n\t}\n\n\t/**\n\t * The panning model. Either \"equalpower\" or \"HRTF\".\n\t */\n\tget panningModel(): PanningModelType {\n\t\treturn this._panner.panningModel;\n\t}\n\tset panningModel(val) {\n\t\tthis._panner.panningModel = val;\n\t}\n\n\t/**\n\t * A reference distance for reducing volume as source move further from the listener\n\t */\n\tget refDistance(): number {\n\t\treturn this._panner.refDistance;\n\t}\n\tset refDistance(val) {\n\t\tthis._panner.refDistance = val;\n\t}\n\n\t/**\n\t * Describes how quickly the volume is reduced as source moves away from listener.\n\t */\n\tget rolloffFactor(): number {\n\t\treturn this._panner.rolloffFactor;\n\t}\n\tset rolloffFactor(val) {\n\t\tthis._panner.rolloffFactor = val;\n\t}\n\n\t/**\n\t * The distance model used by,  \"linear\", \"inverse\", or \"exponential\".\n\t */\n\tget distanceModel(): DistanceModelType {\n\t\treturn this._panner.distanceModel;\n\t}\n\tset distanceModel(val) {\n\t\tthis._panner.distanceModel = val;\n\t}\n\n\t/**\n\t * The angle, in degrees, inside of which there will be no volume reduction\n\t */\n\tget coneInnerAngle(): Degrees {\n\t\treturn this._panner.coneInnerAngle;\n\t}\n\tset coneInnerAngle(val) {\n\t\tthis._panner.coneInnerAngle = val;\n\t}\n\n\t/**\n\t * The angle, in degrees, outside of which the volume will be reduced\n\t * to a constant value of coneOuterGain\n\t */\n\tget coneOuterAngle(): Degrees {\n\t\treturn this._panner.coneOuterAngle;\n\t}\n\tset coneOuterAngle(val) {\n\t\tthis._panner.coneOuterAngle = val;\n\t}\n\n\t/**\n\t * The gain outside of the coneOuterAngle\n\t */\n\tget coneOuterGain(): GainFactor {\n\t\treturn this._panner.coneOuterGain;\n\t}\n\tset coneOuterGain(val) {\n\t\tthis._panner.coneOuterGain = val;\n\t}\n\n\t/**\n\t * The maximum distance between source and listener,\n\t * after which the volume will not be reduced any further.\n\t */\n\tget maxDistance(): number {\n\t\treturn this._panner.maxDistance;\n\t}\n\tset maxDistance(val) {\n\t\tthis._panner.maxDistance = val;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._panner.disconnect();\n\t\tthis.orientationX.dispose();\n\t\tthis.orientationY.dispose();\n\t\tthis.orientationZ.dispose();\n\t\tthis.positionX.dispose();\n\t\tthis.positionY.dispose();\n\t\tthis.positionZ.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/channel/Recorder.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { connectFrom } from \"../../../test/helper/Connect.js\";\nimport { Context } from \"../../core/context/Context.js\";\nimport { ToneWithContext } from \"../../core/context/ToneWithContext.js\";\nimport { Synth } from \"../../instrument/Synth.js\";\nimport { Recorder } from \"./Recorder.js\";\n\ndescribe(\"Recorder\", () => {\n\tcontext(\"basic\", () => {\n\t\tit(\"can be created and disposed\", () => {\n\t\t\tconst rec = new Recorder();\n\t\t\trec.dispose();\n\t\t});\n\n\t\tit(\"handles input connections\", () => {\n\t\t\tconst rec = new Recorder();\n\t\t\tconnectFrom().connect(rec);\n\t\t\trec.dispose();\n\t\t});\n\n\t\tit(\"reports if it is supported or not\", () => {\n\t\t\texpect(Recorder.supported).to.be.a(\"boolean\");\n\t\t});\n\n\t\tit(\"can get the mime type\", () => {\n\t\t\tconst rec = new Recorder();\n\t\t\texpect(rec.mimeType).to.be.a(\"string\");\n\t\t\trec.dispose();\n\t\t});\n\n\t\tit(\"can set a different context\", () => {\n\t\t\tconst testContext = new Context();\n\t\t\tconst rec = new Recorder({\n\t\t\t\tcontext: testContext,\n\t\t\t});\n\t\t\tfor (const member in rec) {\n\t\t\t\tif (rec[member] instanceof ToneWithContext) {\n\t\t\t\t\texpect(rec[member].context, `member: ${member}`).to.equal(\n\t\t\t\t\t\ttestContext\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\ttestContext.dispose();\n\t\t\trec.dispose();\n\t\t\treturn testContext.close();\n\t\t});\n\t});\n\n\tfunction wait(time) {\n\t\treturn new Promise((done) => setTimeout(done, time));\n\t}\n\n\tcontext(\"start/stop/pause\", () => {\n\t\tit(\"can be started\", () => {\n\t\t\tconst rec = new Recorder();\n\t\t\trec.start();\n\t\t\texpect(rec.state).to.equal(\"started\");\n\t\t\trec.dispose();\n\t\t});\n\n\t\tit(\"can be paused after starting\", async () => {\n\t\t\tconst rec = new Recorder();\n\t\t\trec.start();\n\t\t\texpect(rec.state).to.equal(\"started\");\n\t\t\tawait wait(100);\n\t\t\trec.pause();\n\t\t\texpect(rec.state).to.equal(\"paused\");\n\t\t\trec.dispose();\n\t\t});\n\n\t\tit(\"can be resumed after pausing\", async () => {\n\t\t\tconst rec = new Recorder();\n\t\t\trec.start();\n\t\t\texpect(rec.state).to.equal(\"started\");\n\t\t\tawait wait(100);\n\t\t\trec.pause();\n\t\t\texpect(rec.state).to.equal(\"paused\");\n\t\t\tawait wait(100);\n\t\t\trec.start();\n\t\t\texpect(rec.state).to.equal(\"started\");\n\t\t\trec.dispose();\n\t\t});\n\n\t\tit(\"can be stopped after starting\", async () => {\n\t\t\tconst rec = new Recorder();\n\t\t\trec.start();\n\t\t\texpect(rec.state).to.equal(\"started\");\n\t\t\tawait wait(100);\n\t\t\trec.stop();\n\t\t\texpect(rec.state).to.equal(\"stopped\");\n\t\t\trec.dispose();\n\t\t});\n\n\t\tit(\"throws an error if stopped or paused before starting\", async () => {\n\t\t\tconst rec = new Recorder();\n\t\t\tlet didThrow = false;\n\t\t\ttry {\n\t\t\t\tawait rec.stop();\n\t\t\t} catch (e) {\n\t\t\t\tdidThrow = true;\n\t\t\t}\n\t\t\texpect(didThrow).to.be.true;\n\t\t\texpect(() => {\n\t\t\t\trec.pause();\n\t\t\t}).to.throw(Error);\n\t\t\trec.dispose();\n\t\t});\n\n\t\tit(\"stop returns a blob\", async () => {\n\t\t\tconst rec = new Recorder();\n\t\t\trec.start();\n\t\t\tawait wait(100);\n\t\t\tconst recording = await rec.stop();\n\t\t\texpect(recording).to.be.instanceOf(Blob);\n\t\t\trec.dispose();\n\t\t});\n\n\t\tit(\"can record some sound\", async () => {\n\t\t\tconst rec = new Recorder();\n\t\t\tconst synth = new Synth().connect(rec);\n\t\t\trec.start();\n\t\t\tsynth.triggerAttack(\"C3\");\n\t\t\tawait wait(200);\n\t\t\tconst recording = await rec.stop();\n\t\t\texpect(recording.size).to.be.greaterThan(0);\n\t\t\trec.dispose();\n\t\t\tsynth.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/channel/Recorder.ts",
    "content": "import { theWindow } from \"../../core/context/AudioContext.js\";\nimport { Gain } from \"../../core/context/Gain.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { assert } from \"../../core/util/Debug.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { PlaybackState } from \"../../core/util/StateTimeline.js\";\n\nexport interface RecorderOptions extends ToneAudioNodeOptions {\n\tmimeType?: string;\n}\n\n/**\n * A wrapper around the MediaRecorder API. Unlike the rest of Tone.js, this module does not offer\n * any sample-accurate scheduling because it is not a feature of the MediaRecorder API.\n * This is only natively supported in Chrome and Firefox.\n * For a cross-browser shim, install [audio-recorder-polyfill](https://www.npmjs.com/package/audio-recorder-polyfill).\n * @example\n * const recorder = new Tone.Recorder();\n * const synth = new Tone.Synth().connect(recorder);\n * // start recording\n * recorder.start();\n * // generate a few notes\n * synth.triggerAttackRelease(\"C3\", 0.5);\n * synth.triggerAttackRelease(\"C4\", 0.5, \"+1\");\n * synth.triggerAttackRelease(\"C5\", 0.5, \"+2\");\n * // wait for the notes to end and stop the recording\n * setTimeout(async () => {\n * \t// the recorded audio is returned as a blob\n * \tconst recording = await recorder.stop();\n * \t// download the recording by creating an anchor element and blob url\n * \tconst url = URL.createObjectURL(recording);\n * \tconst anchor = document.createElement(\"a\");\n * \tanchor.download = \"recording.webm\";\n * \tanchor.href = url;\n * \tanchor.click();\n * }, 4000);\n * @category Component\n */\nexport class Recorder extends ToneAudioNode<RecorderOptions> {\n\treadonly name = \"Recorder\";\n\n\t/**\n\t * Recorder uses the Media Recorder API\n\t */\n\tprivate _recorder: MediaRecorder;\n\n\t/**\n\t * MediaRecorder requires\n\t */\n\tprivate _stream: MediaStreamAudioDestinationNode;\n\n\treadonly input: Gain;\n\treadonly output: undefined;\n\n\tconstructor(options?: Partial<RecorderOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Recorder.getDefaults(), arguments);\n\t\tsuper(options);\n\n\t\tthis.input = new Gain({\n\t\t\tcontext: this.context,\n\t\t});\n\n\t\tassert(Recorder.supported, \"Media Recorder API is not available\");\n\n\t\tthis._stream = this.context.createMediaStreamDestination();\n\t\tthis.input.connect(this._stream);\n\t\tthis._recorder = new MediaRecorder(this._stream.stream, {\n\t\t\tmimeType: options.mimeType,\n\t\t});\n\t}\n\n\tstatic getDefaults(): RecorderOptions {\n\t\treturn ToneAudioNode.getDefaults();\n\t}\n\n\t/**\n\t * The mime type is the format that the audio is encoded in. For Chrome\n\t * that is typically webm encoded as \"vorbis\".\n\t */\n\tget mimeType(): string {\n\t\treturn this._recorder.mimeType;\n\t}\n\n\t/**\n\t * Test if your platform supports the Media Recorder API. If it's not available,\n\t * try installing this (polyfill)[https://www.npmjs.com/package/audio-recorder-polyfill].\n\t */\n\tstatic get supported(): boolean {\n\t\treturn theWindow !== null && Reflect.has(theWindow, \"MediaRecorder\");\n\t}\n\n\t/**\n\t * Get the playback state of the Recorder, either \"started\", \"stopped\" or \"paused\"\n\t */\n\tget state(): PlaybackState {\n\t\tif (this._recorder.state === \"inactive\") {\n\t\t\treturn \"stopped\";\n\t\t} else if (this._recorder.state === \"paused\") {\n\t\t\treturn \"paused\";\n\t\t} else {\n\t\t\treturn \"started\";\n\t\t}\n\t}\n\n\t/**\n\t * Start/Resume the Recorder. Returns a promise which resolves\n\t * when the recorder has started.\n\t */\n\tasync start() {\n\t\tassert(this.state !== \"started\", \"Recorder is already started\");\n\t\tconst startPromise = new Promise<void>((done) => {\n\t\t\tconst handleStart = () => {\n\t\t\t\tthis._recorder.removeEventListener(\"start\", handleStart, false);\n\n\t\t\t\tdone();\n\t\t\t};\n\n\t\t\tthis._recorder.addEventListener(\"start\", handleStart, false);\n\t\t});\n\t\tif (this.state === \"stopped\") {\n\t\t\tthis._recorder.start();\n\t\t} else {\n\t\t\tthis._recorder.resume();\n\t\t}\n\t\treturn await startPromise;\n\t}\n\n\t/**\n\t * Stop the recorder. Returns a promise with the recorded content until this point\n\t * encoded as {@link mimeType}\n\t */\n\tasync stop(): Promise<Blob> {\n\t\tassert(this.state !== \"stopped\", \"Recorder is not started\");\n\t\tconst dataPromise: Promise<Blob> = new Promise((done) => {\n\t\t\tconst handleData = (e: BlobEvent) => {\n\t\t\t\tthis._recorder.removeEventListener(\n\t\t\t\t\t\"dataavailable\",\n\t\t\t\t\thandleData,\n\t\t\t\t\tfalse\n\t\t\t\t);\n\n\t\t\t\tdone(e.data);\n\t\t\t};\n\n\t\t\tthis._recorder.addEventListener(\"dataavailable\", handleData, false);\n\t\t});\n\t\tthis._recorder.stop();\n\t\treturn await dataPromise;\n\t}\n\n\t/**\n\t * Pause the recorder\n\t */\n\tpause(): this {\n\t\tassert(this.state === \"started\", \"Recorder must be started\");\n\t\tthis._recorder.pause();\n\t\treturn this;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.input.dispose();\n\t\tthis._stream.disconnect();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/channel/Solo.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { ConstantOutput } from \"../../../test/helper/ConstantOutput.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { Solo } from \"./Solo.js\";\n\ndescribe(\"Solo\", () => {\n\tBasicTests(Solo);\n\n\tcontext(\"Soloing\", () => {\n\t\tit(\"can be soloed an unsoloed\", () => {\n\t\t\tconst sol = new Solo();\n\t\t\tsol.solo = true;\n\t\t\texpect(sol.solo).to.be.true;\n\t\t\tsol.solo = false;\n\t\t\texpect(sol.solo).to.be.false;\n\t\t\tsol.dispose();\n\t\t});\n\n\t\tit(\"can be passed into the constructor\", () => {\n\t\t\tconst sol = new Solo(true);\n\t\t\texpect(sol.solo).to.be.true;\n\t\t\tsol.dispose();\n\t\t});\n\n\t\tit(\"can be passed into the constructor with an object\", () => {\n\t\t\tconst sol = new Solo({ solo: true });\n\t\t\texpect(sol.solo).to.be.true;\n\t\t\tsol.dispose();\n\t\t});\n\n\t\tit(\"other instances are unsoloed when one is soloed\", () => {\n\t\t\tconst solA = new Solo();\n\t\t\tconst solB = new Solo();\n\t\t\tsolA.solo = true;\n\t\t\tsolB.solo = false;\n\t\t\texpect(solA.solo).to.be.true;\n\t\t\texpect(solB.solo).to.be.false;\n\t\t\tsolB.solo = true;\n\t\t\texpect(solA.solo).to.be.true;\n\t\t\texpect(solB.solo).to.be.true;\n\t\t\tsolA.solo = false;\n\t\t\texpect(solA.solo).to.be.false;\n\t\t\texpect(solB.solo).to.be.true;\n\t\t\tsolA.dispose();\n\t\t\tsolB.dispose();\n\t\t});\n\n\t\tit(\"other instances report themselves as muted\", () => {\n\t\t\tconst solA = new Solo();\n\t\t\tconst solB = new Solo();\n\t\t\tsolA.solo = true;\n\t\t\tsolB.solo = false;\n\t\t\texpect(solA.muted).to.be.false;\n\t\t\texpect(solB.muted).to.be.true;\n\t\t\tsolA.dispose();\n\t\t\tsolB.dispose();\n\t\t});\n\n\t\tit(\"all instances are unmuted when there is no solo\", () => {\n\t\t\tconst solA = new Solo();\n\t\t\tconst solB = new Solo();\n\t\t\tsolA.solo = true;\n\t\t\tsolB.solo = false;\n\t\t\tsolA.solo = false;\n\t\t\texpect(solA.muted).to.be.false;\n\t\t\texpect(solB.muted).to.be.false;\n\t\t\tsolA.dispose();\n\t\t\tsolB.dispose();\n\t\t});\n\n\t\tit(\"a newly created instance will be muted if there is already a soloed instance\", () => {\n\t\t\tconst solA = new Solo(true);\n\t\t\tconst solB = new Solo();\n\t\t\texpect(solA.muted).to.be.false;\n\t\t\texpect(solB.muted).to.be.true;\n\t\t\tsolA.dispose();\n\t\t\tsolB.dispose();\n\t\t});\n\n\t\tit(\"passes both signals when nothing is soloed\", () => {\n\t\t\treturn ConstantOutput(\n\t\t\t\t() => {\n\t\t\t\t\tconst soloA = new Solo().toDestination();\n\t\t\t\t\tconst soloB = new Solo().toDestination();\n\t\t\t\t\tnew Signal(10).connect(soloA);\n\t\t\t\t\tnew Signal(20).connect(soloB);\n\t\t\t\t},\n\t\t\t\t30,\n\t\t\t\t0.01\n\t\t\t);\n\t\t});\n\n\t\tit(\"passes one signal when it is soloed\", () => {\n\t\t\treturn ConstantOutput(\n\t\t\t\t() => {\n\t\t\t\t\tconst soloA = new Solo().toDestination();\n\t\t\t\t\tconst soloB = new Solo().toDestination();\n\t\t\t\t\tnew Signal(10).connect(soloA);\n\t\t\t\t\tnew Signal(20).connect(soloB);\n\t\t\t\t\tsoloA.solo = true;\n\t\t\t\t},\n\t\t\t\t10,\n\t\t\t\t0.01\n\t\t\t);\n\t\t});\n\n\t\tit(\"can solo multiple at once\", () => {\n\t\t\treturn ConstantOutput(\n\t\t\t\t() => {\n\t\t\t\t\tconst soloA = new Solo().toDestination();\n\t\t\t\t\tconst soloB = new Solo().toDestination();\n\t\t\t\t\tnew Signal(10).connect(soloA);\n\t\t\t\t\tnew Signal(20).connect(soloB);\n\t\t\t\t\tsoloA.solo = true;\n\t\t\t\t\tsoloB.solo = true;\n\t\t\t\t},\n\t\t\t\t30,\n\t\t\t\t0.01\n\t\t\t);\n\t\t});\n\n\t\tit(\"can unsolo all\", () => {\n\t\t\treturn ConstantOutput(\n\t\t\t\t() => {\n\t\t\t\t\tconst soloA = new Solo().toDestination();\n\t\t\t\t\tconst soloB = new Solo().toDestination();\n\t\t\t\t\tnew Signal(10).connect(soloA);\n\t\t\t\t\tnew Signal(20).connect(soloB);\n\t\t\t\t\tsoloA.solo = true;\n\t\t\t\t\tsoloB.solo = true;\n\t\t\t\t\tsoloA.solo = false;\n\t\t\t\t\tsoloB.solo = false;\n\t\t\t\t},\n\t\t\t\t30,\n\t\t\t\t0.01\n\t\t\t);\n\t\t});\n\n\t\tit(\"can solo and unsolo while keeping previous soloed\", () => {\n\t\t\treturn ConstantOutput(\n\t\t\t\t() => {\n\t\t\t\t\tconst soloA = new Solo().toDestination();\n\t\t\t\t\tconst soloB = new Solo().toDestination();\n\t\t\t\t\tnew Signal(10).connect(soloA);\n\t\t\t\t\tnew Signal(20).connect(soloB);\n\t\t\t\t\tsoloA.solo = true;\n\t\t\t\t\tsoloB.solo = true;\n\t\t\t\t\tsoloB.solo = false;\n\t\t\t\t},\n\t\t\t\t10,\n\t\t\t\t0.01\n\t\t\t);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/channel/Solo.ts",
    "content": "import { BaseContext } from \"../../core/context/BaseContext.js\";\nimport { Gain } from \"../../core/context/Gain.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\n\nexport interface SoloOptions extends ToneAudioNodeOptions {\n\tsolo: boolean;\n}\n\n/**\n * Solo lets you isolate a specific audio stream. When an instance is set to `solo=true`,\n * it will mute all other instances of Solo.\n * @example\n * const soloA = new Tone.Solo().toDestination();\n * const oscA = new Tone.Oscillator(\"C4\", \"sawtooth\").connect(soloA);\n * const soloB = new Tone.Solo().toDestination();\n * const oscB = new Tone.Oscillator(\"E4\", \"square\").connect(soloB);\n * soloA.solo = true;\n * // no audio will pass through soloB\n * @category Component\n */\nexport class Solo extends ToneAudioNode<SoloOptions> {\n\treadonly name: string = \"Solo\";\n\n\treadonly input: Gain;\n\treadonly output: Gain;\n\n\t/**\n\t * @param solo If the connection should be initially solo'ed.\n\t */\n\tconstructor(solo?: boolean);\n\tconstructor(options?: Partial<SoloOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Solo.getDefaults(), arguments, [\n\t\t\t\"solo\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis.input = this.output = new Gain({\n\t\t\tcontext: this.context,\n\t\t});\n\n\t\tif (!Solo._allSolos.has(this.context)) {\n\t\t\tSolo._allSolos.set(this.context, new Set());\n\t\t}\n\t\t(Solo._allSolos.get(this.context) as Set<Solo>).add(this);\n\n\t\t// set initially\n\t\tthis.solo = options.solo;\n\t}\n\n\tstatic getDefaults(): SoloOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tsolo: false,\n\t\t});\n\t}\n\n\t/**\n\t * Hold all of the solo'ed tracks belonging to a specific context\n\t */\n\tprivate static _allSolos: Map<BaseContext, Set<Solo>> = new Map();\n\n\t/**\n\t * Hold the currently solo'ed instance(s)\n\t */\n\tprivate static _soloed: Map<BaseContext, Set<Solo>> = new Map();\n\n\t/**\n\t * Isolates this instance and mutes all other instances of Solo.\n\t * Only one instance can be soloed at a time. A soloed\n\t * instance will report `solo=false` when another instance is soloed.\n\t */\n\tget solo(): boolean {\n\t\treturn this._isSoloed();\n\t}\n\tset solo(solo) {\n\t\tif (solo) {\n\t\t\tthis._addSolo();\n\t\t} else {\n\t\t\tthis._removeSolo();\n\t\t}\n\t\t(Solo._allSolos.get(this.context) as Set<Solo>).forEach((instance) =>\n\t\t\tinstance._updateSolo()\n\t\t);\n\t}\n\n\t/**\n\t * If the current instance is muted, i.e. another instance is soloed\n\t */\n\tget muted(): boolean {\n\t\treturn this.input.gain.value === 0;\n\t}\n\n\t/**\n\t * Add this to the soloed array\n\t */\n\tprivate _addSolo(): void {\n\t\tif (!Solo._soloed.has(this.context)) {\n\t\t\tSolo._soloed.set(this.context, new Set());\n\t\t}\n\t\t(Solo._soloed.get(this.context) as Set<Solo>).add(this);\n\t}\n\n\t/**\n\t * Remove this from the soloed array\n\t */\n\tprivate _removeSolo(): void {\n\t\tif (Solo._soloed.has(this.context)) {\n\t\t\t(Solo._soloed.get(this.context) as Set<Solo>).delete(this);\n\t\t}\n\t}\n\n\t/**\n\t * Is this on the soloed array\n\t */\n\tprivate _isSoloed(): boolean {\n\t\treturn (\n\t\t\tSolo._soloed.has(this.context) &&\n\t\t\t(Solo._soloed.get(this.context) as Set<Solo>).has(this)\n\t\t);\n\t}\n\n\t/**\n\t * Returns true if no one is soloed\n\t */\n\tprivate _noSolos(): boolean {\n\t\t// either does not have any soloed added\n\t\treturn (\n\t\t\t!Solo._soloed.has(this.context) ||\n\t\t\t// or has a solo set but doesn't include any items\n\t\t\t(Solo._soloed.has(this.context) &&\n\t\t\t\t(Solo._soloed.get(this.context) as Set<Solo>).size === 0)\n\t\t);\n\t}\n\n\t/**\n\t * Solo the current instance and unsolo all other instances.\n\t */\n\tprivate _updateSolo(): void {\n\t\tif (this._isSoloed()) {\n\t\t\tthis.input.gain.value = 1;\n\t\t} else if (this._noSolos()) {\n\t\t\t// no one is soloed\n\t\t\tthis.input.gain.value = 1;\n\t\t} else {\n\t\t\tthis.input.gain.value = 0;\n\t\t}\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\t(Solo._allSolos.get(this.context) as Set<Solo>).delete(this);\n\t\tthis._removeSolo();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/channel/Split.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { connectTo } from \"../../../test/helper/Connect.js\";\nimport { ConstantOutput } from \"../../../test/helper/ConstantOutput.js\";\nimport { StereoSignal } from \"../../../test/helper/StereoSignal.js\";\nimport { Split } from \"./Split.js\";\n\ndescribe(\"Split\", () => {\n\tBasicTests(Split);\n\n\tcontext(\"Splitting\", () => {\n\t\tit(\"defaults to two channels\", () => {\n\t\t\tconst split = new Split();\n\t\t\texpect(split.numberOfOutputs).to.equal(2);\n\t\t\tsplit.dispose();\n\t\t});\n\n\t\tit(\"can pass in more channels\", () => {\n\t\t\tconst split = new Split(4);\n\t\t\texpect(split.numberOfOutputs).to.equal(4);\n\t\t\tsplit.connect(connectTo(), 0, 0);\n\t\t\tsplit.connect(connectTo(), 1, 0);\n\t\t\tsplit.connect(connectTo(), 2, 0);\n\t\t\tsplit.connect(connectTo(), 3, 0);\n\t\t\tsplit.dispose();\n\t\t});\n\n\t\tit(\"passes the incoming signal through on the left side\", () => {\n\t\t\treturn ConstantOutput(({ destination }) => {\n\t\t\t\tconst split = new Split();\n\t\t\t\tconst signal = StereoSignal(1, 2).connect(split);\n\t\t\t\tsplit.connect(destination, 0, 0);\n\t\t\t}, 1);\n\t\t});\n\n\t\tit(\"passes the incoming signal through on the right side\", () => {\n\t\t\treturn ConstantOutput(({ destination }) => {\n\t\t\t\tconst split = new Split();\n\t\t\t\tconst signal = StereoSignal(1, 2).connect(split);\n\t\t\t\tsplit.connect(destination, 1, 0);\n\t\t\t}, 2);\n\t\t});\n\n\t\t// it(\"merges two signal into one stereo signal and then split them back into two signals on left side\", () => {\n\t\t// \treturn ConstantOutput(({destination}) => {\n\t\t// \t\tconst split = new Split();\n\t\t// \t\tconst signal = StereoSignal(1, 2).connect(split);\n\t\t// \t\tsplit.connect(destination, 0, 0);\n\t\t// \t}, 1);\n\t\t// });\n\n\t\t// it(\"merges two signal into one stereo signal and then split them back into two signals on right side\", () => {\n\t\t// \treturn ConstantOutput(({destination}) => {\n\t\t// \t\tconst split = new Split();\n\t\t// \t\tconst signal = StereoSignal(1, 2).connect(split);\n\t\t// \t\tsplit.connect(destination, 1, 0);\n\t\t// \t}, 2);\n\t\t// });\n\t});\n});\n"
  },
  {
    "path": "Tone/component/channel/Split.ts",
    "content": "import {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\n\ninterface SplitOptions extends ToneAudioNodeOptions {\n\tchannels: number;\n}\n\n/**\n * Split splits an incoming signal into the number of given channels.\n *\n * @example\n * const split = new Tone.Split();\n * // stereoSignal.connect(split);\n * @category Component\n */\nexport class Split extends ToneAudioNode<SplitOptions> {\n\treadonly name: string = \"Split\";\n\n\t/**\n\t * The splitting node\n\t */\n\tprivate _splitter: ChannelSplitterNode;\n\n\treadonly input: ChannelSplitterNode;\n\treadonly output: ChannelSplitterNode;\n\n\t/**\n\t * @param channels The number of channels to merge.\n\t */\n\tconstructor(channels?: number);\n\tconstructor(options?: Partial<SplitOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Split.getDefaults(), arguments, [\n\t\t\t\"channels\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis._splitter =\n\t\t\tthis.input =\n\t\t\tthis.output =\n\t\t\t\tthis.context.createChannelSplitter(options.channels);\n\t\tthis._internalChannels = [this._splitter];\n\t}\n\n\tstatic getDefaults(): SplitOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tchannels: 2,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._splitter.disconnect();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/channel/Volume.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { connectFrom, connectTo } from \"../../../test/helper/Connect.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { Volume } from \"./Volume.js\";\n\ndescribe(\"Volume\", () => {\n\tBasicTests(Volume);\n\n\tcontext(\"Volume\", () => {\n\t\tit(\"handles input and output connections\", () => {\n\t\t\tconst vol = new Volume();\n\t\t\tvol.connect(connectTo());\n\t\t\tconnectFrom().connect(vol);\n\t\t\tconnectFrom().connect(vol.volume);\n\t\t\tvol.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with volume value\", () => {\n\t\t\tconst vol = new Volume(-12);\n\t\t\texpect(vol.volume.value).to.be.closeTo(-12, 0.1);\n\t\t\tvol.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an options object\", () => {\n\t\t\tconst vol = new Volume({\n\t\t\t\tvolume: 2,\n\t\t\t});\n\t\t\texpect(vol.volume.value).to.be.closeTo(2, 0.1);\n\t\t\tvol.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an options object and muted\", () => {\n\t\t\tconst vol = new Volume({\n\t\t\t\tmute: true,\n\t\t\t});\n\t\t\texpect(vol.mute).to.equal(true);\n\t\t\tvol.dispose();\n\t\t});\n\n\t\tit(\"can set/get with an object\", () => {\n\t\t\tconst vol = new Volume();\n\t\t\tvol.set({\n\t\t\t\tvolume: -10,\n\t\t\t});\n\t\t\texpect(vol.get().volume).to.be.closeTo(-10, 0.1);\n\t\t\tvol.dispose();\n\t\t});\n\n\t\tit(\"unmuting returns to previous volume\", () => {\n\t\t\tconst vol = new Volume(-10);\n\t\t\tvol.mute = true;\n\t\t\texpect(vol.mute).to.equal(true);\n\t\t\texpect(vol.volume.value).to.equal(-Infinity);\n\t\t\tvol.mute = false;\n\t\t\t// returns the volume to what it was\n\t\t\texpect(vol.volume.value).to.be.closeTo(-10, 0.1);\n\t\t\tvol.dispose();\n\t\t});\n\n\t\tit(\"passes the incoming signal through\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst vol = new Volume().toDestination();\n\t\t\t\tinput.connect(vol);\n\t\t\t});\n\t\t});\n\n\t\tit.skip(\"passes the incoming stereo signal through\", () => {\n\t\t\t// return PassAudioStereo(function(input) {\n\t\t\t// \tconst vol = new Volume().toDestination();\n\t\t\t// \tinput.connect(vol);\n\t\t\t// });\n\t\t});\n\n\t\tit(\"can lower the volume\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst vol = new Volume(-10).toDestination();\n\t\t\t\tnew Signal(1).connect(vol);\n\t\t\t});\n\t\t\texpect(buffer.value()).to.be.closeTo(0.315, 0.01);\n\t\t});\n\n\t\tit(\"can mute the volume\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst vol = new Volume(0).toDestination();\n\t\t\t\tnew Signal(1).connect(vol);\n\t\t\t\tvol.mute = true;\n\t\t\t});\n\t\t\texpect(buffer.isSilent()).to.equal(true);\n\t\t});\n\n\t\tit(\"muted when volume is set to -Infinity\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst vol = new Volume(-Infinity).toDestination();\n\t\t\t\tnew Signal(1).connect(vol);\n\t\t\t\texpect(vol.mute).to.equal(true);\n\t\t\t});\n\t\t\texpect(buffer.isSilent()).to.equal(true);\n\t\t});\n\n\t\tit(\"setting the volume unmutes it and reports itself as unmuted\", () => {\n\t\t\tconst vol = new Volume(0).toDestination();\n\t\t\tvol.mute = true;\n\t\t\texpect(vol.mute).to.equal(true);\n\t\t\tvol.volume.value = 0;\n\t\t\texpect(vol.mute).is.equal(false);\n\t\t\tvol.dispose();\n\t\t});\n\n\t\tit(\"multiple calls to mute still return the vol to the original\", () => {\n\t\t\tconst vol = new Volume(-20);\n\t\t\tvol.mute = true;\n\t\t\tvol.mute = true;\n\t\t\texpect(vol.mute).to.equal(true);\n\t\t\texpect(vol.volume.value).to.equal(-Infinity);\n\t\t\tvol.mute = false;\n\t\t\tvol.mute = false;\n\t\t\texpect(vol.volume.value).to.be.closeTo(-20, 0.5);\n\t\t\tvol.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/channel/Volume.ts",
    "content": "import { Gain } from \"../../core/context/Gain.js\";\nimport { Param } from \"../../core/context/Param.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { Decibels } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly } from \"../../core/util/Interface.js\";\n\ninterface VolumeOptions extends ToneAudioNodeOptions {\n\tvolume: Decibels;\n\tmute: boolean;\n}\n\n/**\n * Volume is a simple volume node, useful for creating a volume fader.\n *\n * @example\n * const vol = new Tone.Volume(-12).toDestination();\n * const osc = new Tone.Oscillator().connect(vol).start();\n * @category Component\n */\nexport class Volume extends ToneAudioNode<VolumeOptions> {\n\treadonly name: string = \"Volume\";\n\n\t/**\n\t * the output node\n\t */\n\toutput: Gain<\"decibels\">;\n\n\t/**\n\t * Input and output are the same\n\t */\n\tinput: Gain<\"decibels\">;\n\n\t/**\n\t * The unmuted volume\n\t */\n\tprivate _unmutedVolume: Decibels;\n\n\t/**\n\t * The volume control in decibels.\n\t * @example\n\t * const vol = new Tone.Volume().toDestination();\n\t * const osc = new Tone.Oscillator().connect(vol).start();\n\t * vol.volume.value = -20;\n\t */\n\tvolume: Param<\"decibels\">;\n\n\t/**\n\t * @param volume the initial volume in decibels\n\t */\n\tconstructor(volume?: Decibels);\n\tconstructor(options?: Partial<VolumeOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Volume.getDefaults(), arguments, [\n\t\t\t\"volume\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis.input = this.output = new Gain({\n\t\t\tcontext: this.context,\n\t\t\tgain: options.volume,\n\t\t\tunits: \"decibels\",\n\t\t});\n\t\tthis.volume = this.output.gain;\n\t\treadOnly(this, \"volume\");\n\t\tthis._unmutedVolume = options.volume;\n\n\t\t// set the mute initially\n\t\tthis.mute = options.mute;\n\t}\n\n\tstatic getDefaults(): VolumeOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tmute: false,\n\t\t\tvolume: 0,\n\t\t});\n\t}\n\n\t/**\n\t * Mute the output.\n\t * @example\n\t * const vol = new Tone.Volume(-12).toDestination();\n\t * const osc = new Tone.Oscillator().connect(vol).start();\n\t * // mute the output\n\t * vol.mute = true;\n\t */\n\tget mute(): boolean {\n\t\treturn this.volume.value === -Infinity;\n\t}\n\tset mute(mute: boolean) {\n\t\tif (!this.mute && mute) {\n\t\t\tthis._unmutedVolume = this.volume.value;\n\t\t\t// maybe it should ramp here?\n\t\t\tthis.volume.value = -Infinity;\n\t\t} else if (this.mute && !mute) {\n\t\t\tthis.volume.value = this._unmutedVolume;\n\t\t}\n\t}\n\n\t/**\n\t * clean up\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.input.dispose();\n\t\tthis.volume.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/dynamics/Compressor.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { Compressor } from \"./Compressor.js\";\n\ndescribe(\"Compressor\", () => {\n\tBasicTests(Compressor);\n\n\tcontext(\"Compression\", () => {\n\t\tit(\"passes the incoming signal through\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst comp = new Compressor().toDestination();\n\t\t\t\tinput.connect(comp);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can be get and set through object\", () => {\n\t\t\tconst comp = new Compressor();\n\t\t\tconst values = {\n\t\t\t\tattack: 0.03,\n\t\t\t\tknee: 20,\n\t\t\t\tratio: 12,\n\t\t\t\trelease: 0.5,\n\t\t\t\tthreshold: -30,\n\t\t\t};\n\t\t\tcomp.set(values);\n\t\t\texpect(comp.get()).to.have.keys([\n\t\t\t\t\"ratio\",\n\t\t\t\t\"threshold\",\n\t\t\t\t\"release\",\n\t\t\t\t\"attack\",\n\t\t\t\t\"ratio\",\n\t\t\t]);\n\t\t\tcomp.dispose();\n\t\t});\n\n\t\tit(\"can be get and constructed with an object\", () => {\n\t\t\tconst comp = new Compressor({\n\t\t\t\tattack: 0.03,\n\t\t\t\tknee: 20,\n\t\t\t\tratio: 12,\n\t\t\t\trelease: 0.5,\n\t\t\t\tthreshold: -30,\n\t\t\t});\n\t\t\texpect(comp.threshold.value).to.have.be.closeTo(-30, 1);\n\t\t\tcomp.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with args\", () => {\n\t\t\tconst comp = new Compressor(-10, 4);\n\t\t\texpect(comp.threshold.value).to.have.be.closeTo(-10, 0.1);\n\t\t\texpect(comp.ratio.value).to.have.be.closeTo(4, 0.1);\n\t\t\tcomp.dispose();\n\t\t});\n\n\t\tit(\"params have correct min and max values\", () => {\n\t\t\tconst comp = new Compressor(-10, 4);\n\t\t\texpect(comp.threshold.minValue).to.equal(-100);\n\t\t\texpect(comp.threshold.maxValue).to.equal(0);\n\t\t\texpect(comp.attack.minValue).to.equal(0);\n\t\t\texpect(comp.attack.maxValue).to.equal(1);\n\t\t\texpect(comp.release.minValue).to.equal(0);\n\t\t\texpect(comp.release.maxValue).to.equal(1);\n\t\t\tcomp.dispose();\n\t\t});\n\n\t\tit(\"can get/set all interfaces\", () => {\n\t\t\tconst comp = new Compressor();\n\t\t\tconst values = {\n\t\t\t\tattack: 0.03,\n\t\t\t\tknee: 18,\n\t\t\t\tratio: 12,\n\t\t\t\trelease: 0.5,\n\t\t\t\tthreshold: -30,\n\t\t\t};\n\t\t\tcomp.ratio.value = values.ratio;\n\t\t\tcomp.threshold.value = values.threshold;\n\t\t\tcomp.release.value = values.release;\n\t\t\tcomp.attack.value = values.attack;\n\t\t\tcomp.knee.value = values.knee;\n\t\t\texpect(comp.ratio.value).to.equal(values.ratio);\n\t\t\texpect(comp.threshold.value).to.equal(values.threshold);\n\t\t\texpect(comp.release.value).to.equal(values.release);\n\t\t\texpect(comp.attack.value).to.be.closeTo(values.attack, 0.01);\n\t\t\texpect(comp.knee.value).to.equal(values.knee);\n\t\t\tcomp.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/dynamics/Compressor.ts",
    "content": "import { Param } from \"../../core/context/Param.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { Decibels, Positive, Time } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly } from \"../../core/util/Interface.js\";\n\nexport interface CompressorOptions extends ToneAudioNodeOptions {\n\tattack: Time;\n\tknee: Decibels;\n\tratio: Positive;\n\trelease: Time;\n\tthreshold: Decibels;\n}\n\n/**\n * Compressor is a thin wrapper around the Web Audio\n * [DynamicsCompressorNode](http://webaudio.github.io/web-audio-api/#the-dynamicscompressornode-interface).\n * Compression reduces the volume of loud sounds or amplifies quiet sounds\n * by narrowing or \"compressing\" an audio signal's dynamic range.\n * Read more on [Wikipedia](https://en.wikipedia.org/wiki/Dynamic_range_compression).\n * @example\n * const comp = new Tone.Compressor(-30, 3);\n * @category Component\n */\nexport class Compressor extends ToneAudioNode<CompressorOptions> {\n\treadonly name: string = \"Compressor\";\n\n\t/**\n\t * the compressor node\n\t */\n\tprivate _compressor: DynamicsCompressorNode =\n\t\tthis.context.createDynamicsCompressor();\n\treadonly input = this._compressor;\n\treadonly output = this._compressor;\n\n\t/**\n\t * The decibel value above which the compression will start taking effect.\n\t * @min -100\n\t * @max 0\n\t */\n\treadonly threshold: Param<\"decibels\">;\n\n\t/**\n\t * The amount of time (in seconds) to reduce the gain by 10dB.\n\t * @min 0\n\t * @max 1\n\t */\n\treadonly attack: Param<\"time\">;\n\n\t/**\n\t * The amount of time (in seconds) to increase the gain by 10dB.\n\t * @min 0\n\t * @max 1\n\t */\n\treadonly release: Param<\"time\">;\n\n\t/**\n\t * A decibel value representing the range above the threshold where the\n\t * curve smoothly transitions to the \"ratio\" portion.\n\t * @min 0\n\t * @max 40\n\t */\n\treadonly knee: Param<\"decibels\">;\n\n\t/**\n\t * The amount of dB change in input for a 1 dB change in output.\n\t * @min 1\n\t * @max 20\n\t */\n\treadonly ratio: Param<\"positive\">;\n\n\t/**\n\t * @param threshold The value above which the compression starts to be applied.\n\t * @param ratio The gain reduction ratio.\n\t */\n\tconstructor(threshold?: Decibels, ratio?: Positive);\n\tconstructor(options?: Partial<CompressorOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tCompressor.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"threshold\", \"ratio\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.threshold = new Param({\n\t\t\tminValue: this._compressor.threshold.minValue,\n\t\t\tmaxValue: this._compressor.threshold.maxValue,\n\t\t\tcontext: this.context,\n\t\t\tconvert: false,\n\t\t\tparam: this._compressor.threshold,\n\t\t\tunits: \"decibels\",\n\t\t\tvalue: options.threshold,\n\t\t});\n\n\t\tthis.attack = new Param({\n\t\t\tminValue: this._compressor.attack.minValue,\n\t\t\tmaxValue: this._compressor.attack.maxValue,\n\t\t\tcontext: this.context,\n\t\t\tparam: this._compressor.attack,\n\t\t\tunits: \"time\",\n\t\t\tvalue: options.attack,\n\t\t});\n\n\t\tthis.release = new Param({\n\t\t\tminValue: this._compressor.release.minValue,\n\t\t\tmaxValue: this._compressor.release.maxValue,\n\t\t\tcontext: this.context,\n\t\t\tparam: this._compressor.release,\n\t\t\tunits: \"time\",\n\t\t\tvalue: options.release,\n\t\t});\n\n\t\tthis.knee = new Param({\n\t\t\tminValue: this._compressor.knee.minValue,\n\t\t\tmaxValue: this._compressor.knee.maxValue,\n\t\t\tcontext: this.context,\n\t\t\tconvert: false,\n\t\t\tparam: this._compressor.knee,\n\t\t\tunits: \"decibels\",\n\t\t\tvalue: options.knee,\n\t\t});\n\n\t\tthis.ratio = new Param({\n\t\t\tminValue: this._compressor.ratio.minValue,\n\t\t\tmaxValue: this._compressor.ratio.maxValue,\n\t\t\tcontext: this.context,\n\t\t\tconvert: false,\n\t\t\tparam: this._compressor.ratio,\n\t\t\tunits: \"positive\",\n\t\t\tvalue: options.ratio,\n\t\t});\n\n\t\t// set the defaults\n\t\treadOnly(this, [\"knee\", \"release\", \"attack\", \"ratio\", \"threshold\"]);\n\t}\n\n\tstatic getDefaults(): CompressorOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tattack: 0.003,\n\t\t\tknee: 30,\n\t\t\tratio: 12,\n\t\t\trelease: 0.25,\n\t\t\tthreshold: -24,\n\t\t});\n\t}\n\n\t/**\n\t * A read-only decibel value for metering purposes, representing the current amount of gain\n\t * reduction that the compressor is applying to the signal. If fed no signal the value will be 0 (no gain reduction).\n\t */\n\tget reduction(): Decibels {\n\t\treturn this._compressor.reduction;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._compressor.disconnect();\n\t\tthis.attack.dispose();\n\t\tthis.release.dispose();\n\t\tthis.threshold.dispose();\n\t\tthis.ratio.dispose();\n\t\tthis.knee.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/dynamics/Gate.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../../test/helper/CompareToFile.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { Oscillator } from \"../../source/oscillator/Oscillator.js\";\nimport { Gate } from \"./Gate.js\";\n\ndescribe(\"Gate\", () => {\n\tBasicTests(Gate);\n\n\tit.only(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst gate = new Gate(-10, 0.1).toDestination();\n\t\t\t\tconst osc = new Oscillator().connect(gate);\n\t\t\t\tosc.start(0);\n\t\t\t\tosc.volume.value = -100;\n\t\t\t\tosc.volume.exponentialRampToValueAtTime(0, 0.5);\n\t\t\t},\n\t\t\t\"gate.wav\",\n\t\t\t0.18\n\t\t);\n\t});\n\n\tcontext(\"Signal Gating\", () => {\n\t\tit(\"handles getter/setter as Object\", () => {\n\t\t\tconst gate = new Gate();\n\t\t\tconst values = {\n\t\t\t\tsmoothing: 0.2,\n\t\t\t\tthreshold: -20,\n\t\t\t};\n\t\t\tgate.set(values);\n\t\t\texpect(gate.get().smoothing).to.be.closeTo(0.2, 0.001);\n\t\t\texpect(gate.get().threshold).to.be.closeTo(-20, 0.1);\n\t\t\tgate.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an object\", () => {\n\t\t\tconst gate = new Gate({\n\t\t\t\tsmoothing: 0.3,\n\t\t\t\tthreshold: -5,\n\t\t\t});\n\t\t\texpect(gate.smoothing).to.be.closeTo(0.3, 0.001);\n\t\t\texpect(gate.threshold).to.be.closeTo(-5, 0.1);\n\t\t\tgate.dispose();\n\t\t});\n\n\t\tit(\"gates the incoming signal when below the threshold\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst gate = new Gate(-9);\n\t\t\t\tconst sig = new Signal(-12, \"decibels\");\n\t\t\t\tsig.connect(gate);\n\t\t\t\tgate.toDestination();\n\t\t\t});\n\t\t\texpect(buffer.isSilent()).to.be.true;\n\t\t});\n\n\t\tit(\"passes the incoming signal when above the threshold\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst gate = new Gate(-11);\n\t\t\t\tconst sig = new Signal(-10, \"decibels\");\n\t\t\t\tsig.connect(gate);\n\t\t\t\tgate.toDestination();\n\t\t\t});\n\t\t\texpect(buffer.min()).to.be.above(0);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/dynamics/Gate.ts",
    "content": "import { Gain } from \"../../core/context/Gain.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { dbToGain, gainToDb } from \"../../core/type/Conversions.js\";\nimport { Decibels, Time } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { GreaterThan } from \"../../signal/GreaterThan.js\";\nimport { Follower } from \"../analysis/Follower.js\";\n\nexport interface GateOptions extends ToneAudioNodeOptions {\n\tthreshold: Decibels;\n\tsmoothing: Time;\n}\n\n/**\n * Gate only passes a signal through when the incoming\n * signal exceeds a specified threshold. It uses {@link Follower} to follow the ampltiude\n * of the incoming signal and compares it to the {@link threshold} value using {@link GreaterThan}.\n *\n * @example\n * const gate = new Tone.Gate(-30, 0.2).toDestination();\n * const mic = new Tone.UserMedia().connect(gate);\n * // the gate will only pass through the incoming\n * // signal when it's louder than -30db\n * @category Component\n */\nexport class Gate extends ToneAudioNode<GateOptions> {\n\treadonly name: string = \"Gate\";\n\n\treadonly input: ToneAudioNode;\n\treadonly output: ToneAudioNode;\n\n\t/**\n\t * Follow the incoming signal\n\t */\n\tprivate _follower: Follower;\n\n\t/**\n\t * Test if it's greater than the threshold\n\t */\n\tprivate _gt: GreaterThan;\n\n\t/**\n\t * Gate the incoming signal when it does not exceed the threshold\n\t */\n\tprivate _gate: Gain;\n\n\t/**\n\t * @param threshold The threshold above which the gate will open.\n\t * @param smoothing The follower's smoothing time\n\t */\n\tconstructor(threshold?: Decibels, smoothing?: Time);\n\tconstructor(options?: Partial<GateOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Gate.getDefaults(), arguments, [\n\t\t\t\"threshold\",\n\t\t\t\"smoothing\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis._follower = new Follower({\n\t\t\tcontext: this.context,\n\t\t\tsmoothing: options.smoothing,\n\t\t});\n\t\tthis._gt = new GreaterThan({\n\t\t\tcontext: this.context,\n\t\t\tvalue: dbToGain(options.threshold),\n\t\t});\n\t\tthis.input = new Gain({ context: this.context });\n\t\tthis._gate = this.output = new Gain({ context: this.context });\n\n\t\t// connections\n\t\tthis.input.connect(this._gate);\n\t\t// the control signal\n\t\tthis.input.chain(this._follower, this._gt, this._gate.gain);\n\t}\n\n\tstatic getDefaults(): GateOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tsmoothing: 0.1,\n\t\t\tthreshold: -40,\n\t\t});\n\t}\n\n\t/**\n\t * The threshold of the gate in decibels\n\t */\n\tget threshold(): Decibels {\n\t\treturn gainToDb(this._gt.value);\n\t}\n\tset threshold(thresh) {\n\t\tthis._gt.value = dbToGain(thresh);\n\t}\n\n\t/**\n\t * The attack/decay speed of the gate.\n\t * @see {@link Follower.smoothing}\n\t */\n\tget smoothing(): Time {\n\t\treturn this._follower.smoothing;\n\t}\n\tset smoothing(smoothingTime) {\n\t\tthis._follower.smoothing = smoothingTime;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.input.dispose();\n\t\tthis._follower.dispose();\n\t\tthis._gt.dispose();\n\t\tthis._gate.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/dynamics/Limiter.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { Limiter } from \"./Limiter.js\";\n\ndescribe(\"Limiter\", () => {\n\tBasicTests(Limiter);\n\n\tcontext(\"Limiting\", () => {\n\t\tit(\"passes the incoming signal through\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst limiter = new Limiter().toDestination();\n\t\t\t\tinput.connect(limiter);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can be get and set through object\", () => {\n\t\t\tconst limiter = new Limiter();\n\t\t\tconst values = {\n\t\t\t\tthreshold: -30,\n\t\t\t};\n\t\t\tlimiter.set(values);\n\t\t\texpect(limiter.get().threshold).to.be.closeTo(-30, 0.1);\n\t\t\tlimiter.dispose();\n\t\t});\n\n\t\tit(\"can set the threshold\", () => {\n\t\t\tconst limiter = new Limiter();\n\t\t\tlimiter.threshold.value = -10;\n\t\t\texpect(limiter.threshold.value).to.be.closeTo(-10, 0.1);\n\t\t\tlimiter.dispose();\n\t\t});\n\n\t\tit(\"reduction is 0 when not connected\", () => {\n\t\t\tconst limiter = new Limiter();\n\t\t\texpect(limiter.reduction).to.be.closeTo(0, 0.01);\n\t\t\tlimiter.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/dynamics/Limiter.ts",
    "content": "import { Param } from \"../../core/context/Param.js\";\nimport {\n\tInputNode,\n\tOutputNode,\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { Decibels } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly } from \"../../core/util/Interface.js\";\nimport { Compressor } from \"./Compressor.js\";\n\nexport interface LimiterOptions extends ToneAudioNodeOptions {\n\tthreshold: Decibels;\n}\n\n/**\n * Limiter will limit the loudness of an incoming signal.\n * Under the hood its composed of a {@link Compressor} with a fast attack\n * and release and max compression ratio.\n *\n * @example\n * const limiter = new Tone.Limiter(-20).toDestination();\n * const oscillator = new Tone.Oscillator().connect(limiter);\n * oscillator.start();\n * @category Component\n */\nexport class Limiter extends ToneAudioNode<LimiterOptions> {\n\treadonly name: string = \"Limiter\";\n\n\treadonly input: InputNode;\n\treadonly output: OutputNode;\n\n\t/**\n\t * The compressor which does the limiting\n\t */\n\tprivate _compressor: Compressor;\n\n\treadonly threshold: Param<\"decibels\">;\n\n\t/**\n\t * @param threshold The threshold above which the gain reduction is applied.\n\t */\n\tconstructor(threshold?: Decibels);\n\tconstructor(options?: Partial<LimiterOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Limiter.getDefaults(), arguments, [\n\t\t\t\"threshold\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis._compressor =\n\t\t\tthis.input =\n\t\t\tthis.output =\n\t\t\t\tnew Compressor({\n\t\t\t\t\tcontext: this.context,\n\t\t\t\t\tratio: 20,\n\t\t\t\t\tattack: 0.003,\n\t\t\t\t\trelease: 0.01,\n\t\t\t\t\tthreshold: options.threshold,\n\t\t\t\t});\n\n\t\tthis.threshold = this._compressor.threshold;\n\t\treadOnly(this, \"threshold\");\n\t}\n\n\tstatic getDefaults(): LimiterOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tthreshold: -12,\n\t\t});\n\t}\n\n\t/**\n\t * A read-only decibel value for metering purposes, representing the current amount of gain\n\t * reduction that the compressor is applying to the signal.\n\t */\n\tget reduction(): Decibels {\n\t\treturn this._compressor.reduction;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._compressor.dispose();\n\t\tthis.threshold.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/dynamics/MidSideCompressor.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { MidSideCompressor } from \"./MidSideCompressor.js\";\n\ndescribe(\"MidSideCompressor\", () => {\n\tBasicTests(MidSideCompressor);\n\n\tcontext(\"Compression\", () => {\n\t\tit(\"passes the incoming signal through\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst comp = new MidSideCompressor().toDestination();\n\t\t\t\tinput.connect(comp);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can be get and set through object\", () => {\n\t\t\tconst comp = new MidSideCompressor();\n\t\t\tconst values = {\n\t\t\t\tmid: {\n\t\t\t\t\tratio: 16,\n\t\t\t\t\tthreshold: -30,\n\t\t\t\t},\n\t\t\t\tside: {\n\t\t\t\t\trelease: 0.5,\n\t\t\t\t\tattack: 0.03,\n\t\t\t\t\tknee: 20,\n\t\t\t\t},\n\t\t\t};\n\t\t\tcomp.set(values);\n\t\t\texpect(comp.get()).to.have.keys([\"mid\", \"side\"]);\n\t\t\texpect(comp.get().mid.ratio).be.closeTo(16, 0.01);\n\t\t\texpect(comp.get().side.release).be.closeTo(0.5, 0.01);\n\t\t\tcomp.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an options object\", () => {\n\t\t\tconst comp = new MidSideCompressor({\n\t\t\t\tmid: {\n\t\t\t\t\tratio: 16,\n\t\t\t\t\tthreshold: -30,\n\t\t\t\t},\n\t\t\t\tside: {\n\t\t\t\t\trelease: 0.5,\n\t\t\t\t\tattack: 0.03,\n\t\t\t\t\tknee: 20,\n\t\t\t\t},\n\t\t\t});\n\t\t\texpect(comp.mid.ratio.value).be.closeTo(16, 0.01);\n\t\t\texpect(comp.mid.threshold.value).be.closeTo(-30, 0.01);\n\t\t\texpect(comp.side.release.value).be.closeTo(0.5, 0.01);\n\t\t\texpect(comp.side.attack.value).be.closeTo(0.03, 0.01);\n\t\t\tcomp.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/dynamics/MidSideCompressor.ts",
    "content": "import {\n\tInputNode,\n\tOutputNode,\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly, RecursivePartial } from \"../../core/util/Interface.js\";\nimport { MidSideMerge } from \"../channel/MidSideMerge.js\";\nimport { MidSideSplit } from \"../channel/MidSideSplit.js\";\nimport { Compressor, CompressorOptions } from \"./Compressor.js\";\n\nexport interface MidSideCompressorOptions extends ToneAudioNodeOptions {\n\tmid: Omit<CompressorOptions, keyof ToneAudioNodeOptions>;\n\tside: Omit<CompressorOptions, keyof ToneAudioNodeOptions>;\n}\n\n/**\n * MidSideCompressor applies two different compressors to the {@link mid}\n * and {@link side} signal components of the input.\n * @see {@link MidSideSplit} and {@link MidSideMerge}.\n * @category Component\n */\nexport class MidSideCompressor extends ToneAudioNode<MidSideCompressorOptions> {\n\treadonly name: string = \"MidSideCompressor\";\n\n\treadonly input: InputNode;\n\treadonly output: OutputNode;\n\n\t/**\n\t * Split the incoming signal into Mid/Side\n\t */\n\tprivate _midSideSplit: MidSideSplit;\n\n\t/**\n\t * Merge the compressed signal back into a single stream\n\t */\n\tprivate _midSideMerge: MidSideMerge;\n\n\t/**\n\t * The compression applied to the mid signal\n\t */\n\treadonly mid: Compressor;\n\n\t/**\n\t * The compression applied to the side signal\n\t */\n\treadonly side: Compressor;\n\n\tconstructor(options?: RecursivePartial<MidSideCompressorOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tMidSideCompressor.getDefaults(),\n\t\t\targuments\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._midSideSplit = this.input = new MidSideSplit({\n\t\t\tcontext: this.context,\n\t\t});\n\t\tthis._midSideMerge = this.output = new MidSideMerge({\n\t\t\tcontext: this.context,\n\t\t});\n\t\tthis.mid = new Compressor(\n\t\t\tObject.assign(options.mid, { context: this.context })\n\t\t);\n\t\tthis.side = new Compressor(\n\t\t\tObject.assign(options.side, { context: this.context })\n\t\t);\n\n\t\tthis._midSideSplit.mid.chain(this.mid, this._midSideMerge.mid);\n\t\tthis._midSideSplit.side.chain(this.side, this._midSideMerge.side);\n\t\treadOnly(this, [\"mid\", \"side\"]);\n\t}\n\n\tstatic getDefaults(): MidSideCompressorOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tmid: {\n\t\t\t\tratio: 3,\n\t\t\t\tthreshold: -24,\n\t\t\t\trelease: 0.03,\n\t\t\t\tattack: 0.02,\n\t\t\t\tknee: 16,\n\t\t\t},\n\t\t\tside: {\n\t\t\t\tratio: 6,\n\t\t\t\tthreshold: -30,\n\t\t\t\trelease: 0.25,\n\t\t\t\tattack: 0.03,\n\t\t\t\tknee: 10,\n\t\t\t},\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.mid.dispose();\n\t\tthis.side.dispose();\n\t\tthis._midSideSplit.dispose();\n\t\tthis._midSideMerge.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/dynamics/MultibandCompressor.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { MultibandCompressor } from \"./MultibandCompressor.js\";\n\ndescribe(\"MultibandCompressor\", () => {\n\tBasicTests(MultibandCompressor);\n\n\tcontext(\"Compression\", () => {\n\t\tit(\"passes the incoming signal through\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst comp = new MultibandCompressor().toDestination();\n\t\t\t\tinput.connect(comp);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can be get and set through object\", () => {\n\t\t\tconst comp = new MultibandCompressor();\n\t\t\tconst values = {\n\t\t\t\tmid: {\n\t\t\t\t\tratio: 16,\n\t\t\t\t\tthreshold: -30,\n\t\t\t\t},\n\t\t\t\thigh: {\n\t\t\t\t\trelease: 0.5,\n\t\t\t\t\tattack: 0.03,\n\t\t\t\t\tknee: 20,\n\t\t\t\t},\n\t\t\t};\n\t\t\tcomp.set(values);\n\t\t\texpect(comp.get()).to.have.keys([\n\t\t\t\t\"low\",\n\t\t\t\t\"mid\",\n\t\t\t\t\"high\",\n\t\t\t\t\"lowFrequency\",\n\t\t\t\t\"highFrequency\",\n\t\t\t]);\n\t\t\texpect(comp.get().mid.ratio).be.closeTo(16, 0.01);\n\t\t\texpect(comp.get().high.release).be.closeTo(0.5, 0.01);\n\t\t\tcomp.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an options object\", () => {\n\t\t\tconst comp = new MultibandCompressor({\n\t\t\t\tmid: {\n\t\t\t\t\tratio: 16,\n\t\t\t\t\tthreshold: -30,\n\t\t\t\t},\n\t\t\t\tlowFrequency: 100,\n\t\t\t});\n\t\t\texpect(comp.mid.ratio.value).be.closeTo(16, 0.01);\n\t\t\texpect(comp.mid.threshold.value).be.closeTo(-30, 0.01);\n\t\t\texpect(comp.lowFrequency.value).be.closeTo(100, 0.01);\n\t\t\tcomp.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/dynamics/MultibandCompressor.ts",
    "content": "import { Gain } from \"../../core/context/Gain.js\";\nimport {\n\tInputNode,\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { Frequency } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly, RecursivePartial } from \"../../core/util/Interface.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { MultibandSplit } from \"../channel/MultibandSplit.js\";\nimport { Compressor, CompressorOptions } from \"./Compressor.js\";\n\nexport interface MultibandCompressorOptions extends ToneAudioNodeOptions {\n\tmid: Omit<CompressorOptions, keyof ToneAudioNodeOptions>;\n\tlow: Omit<CompressorOptions, keyof ToneAudioNodeOptions>;\n\thigh: Omit<CompressorOptions, keyof ToneAudioNodeOptions>;\n\tlowFrequency: Frequency;\n\thighFrequency: Frequency;\n}\n\n/**\n * A compressor with separate controls over low/mid/high dynamics.\n * @see {@link Compressor} and {@link MultibandSplit}\n *\n * @example\n * const multiband = new Tone.MultibandCompressor({\n * \tlowFrequency: 200,\n * \thighFrequency: 1300,\n * \tlow: {\n * \t\tthreshold: -12\n * \t}\n * });\n * @category Component\n */\nexport class MultibandCompressor extends ToneAudioNode<MultibandCompressorOptions> {\n\treadonly name: string = \"MultibandCompressor\";\n\n\treadonly input: InputNode;\n\treadonly output: ToneAudioNode;\n\n\t/**\n\t * Split the incoming signal into high/mid/low\n\t */\n\tprivate _splitter: MultibandSplit;\n\n\t/**\n\t * low/mid crossover frequency.\n\t */\n\treadonly lowFrequency: Signal<\"frequency\">;\n\n\t/**\n\t * mid/high crossover frequency.\n\t */\n\treadonly highFrequency: Signal<\"frequency\">;\n\n\t/**\n\t * The compressor applied to the low frequencies\n\t */\n\treadonly low: Compressor;\n\n\t/**\n\t * The compressor applied to the mid frequencies\n\t */\n\treadonly mid: Compressor;\n\n\t/**\n\t * The compressor applied to the high frequencies\n\t */\n\treadonly high: Compressor;\n\n\tconstructor(options?: RecursivePartial<MultibandCompressorOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tMultibandCompressor.getDefaults(),\n\t\t\targuments\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._splitter = this.input = new MultibandSplit({\n\t\t\tcontext: this.context,\n\t\t\tlowFrequency: options.lowFrequency,\n\t\t\thighFrequency: options.highFrequency,\n\t\t});\n\t\tthis.lowFrequency = this._splitter.lowFrequency;\n\t\tthis.highFrequency = this._splitter.highFrequency;\n\t\tthis.output = new Gain({ context: this.context });\n\t\tthis.low = new Compressor(\n\t\t\tObject.assign(options.low, { context: this.context })\n\t\t);\n\t\tthis.mid = new Compressor(\n\t\t\tObject.assign(options.mid, { context: this.context })\n\t\t);\n\t\tthis.high = new Compressor(\n\t\t\tObject.assign(options.high, { context: this.context })\n\t\t);\n\n\t\t// connect the compressor\n\t\tthis._splitter.low.chain(this.low, this.output);\n\t\tthis._splitter.mid.chain(this.mid, this.output);\n\t\tthis._splitter.high.chain(this.high, this.output);\n\n\t\treadOnly(this, [\"high\", \"mid\", \"low\", \"highFrequency\", \"lowFrequency\"]);\n\t}\n\n\tstatic getDefaults(): MultibandCompressorOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tlowFrequency: 250,\n\t\t\thighFrequency: 2000,\n\t\t\tlow: {\n\t\t\t\tratio: 6,\n\t\t\t\tthreshold: -30,\n\t\t\t\trelease: 0.25,\n\t\t\t\tattack: 0.03,\n\t\t\t\tknee: 10,\n\t\t\t},\n\t\t\tmid: {\n\t\t\t\tratio: 3,\n\t\t\t\tthreshold: -24,\n\t\t\t\trelease: 0.03,\n\t\t\t\tattack: 0.02,\n\t\t\t\tknee: 16,\n\t\t\t},\n\t\t\thigh: {\n\t\t\t\tratio: 3,\n\t\t\t\tthreshold: -24,\n\t\t\t\trelease: 0.03,\n\t\t\t\tattack: 0.02,\n\t\t\t\tknee: 16,\n\t\t\t},\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._splitter.dispose();\n\t\tthis.low.dispose();\n\t\tthis.mid.dispose();\n\t\tthis.high.dispose();\n\t\tthis.output.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/envelope/AmplitudeEnvelope.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../../test/helper/CompareToFile.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { Oscillator } from \"../../source/oscillator/Oscillator.js\";\nimport { AmplitudeEnvelope } from \"./AmplitudeEnvelope.js\";\nimport { Envelope } from \"./Envelope.js\";\n\ndescribe(\"AmplitudeEnvelope\", () => {\n\tBasicTests(AmplitudeEnvelope);\n\n\tcontext(\"Comparisons\", () => {\n\t\tit(\"matches a file\", () => {\n\t\t\treturn CompareToFile(() => {\n\t\t\t\tconst ampEnv = new AmplitudeEnvelope({\n\t\t\t\t\tattack: 0.1,\n\t\t\t\t\tdecay: 0.2,\n\t\t\t\t\trelease: 0.2,\n\t\t\t\t\tsustain: 0.1,\n\t\t\t\t}).toDestination();\n\t\t\t\tconst osc = new Oscillator().start(0).connect(ampEnv);\n\t\t\t\tampEnv.triggerAttack(0);\n\t\t\t\tampEnv.triggerRelease(0.3);\n\t\t\t}, \"ampEnvelope.wav\");\n\t\t});\n\n\t\tit(\"matches a file with multiple retriggers\", () => {\n\t\t\treturn CompareToFile(\n\t\t\t\t() => {\n\t\t\t\t\tconst ampEnv = new AmplitudeEnvelope({\n\t\t\t\t\t\tattack: 0.1,\n\t\t\t\t\t\tdecay: 0.2,\n\t\t\t\t\t\trelease: 0.2,\n\t\t\t\t\t\tsustain: 0.1,\n\t\t\t\t\t}).toDestination();\n\t\t\t\t\tconst osc = new Oscillator().start(0).connect(ampEnv);\n\t\t\t\t\tampEnv.triggerAttack(0);\n\t\t\t\t\tampEnv.triggerAttack(0.3);\n\t\t\t\t},\n\t\t\t\t\"ampEnvelope2.wav\",\n\t\t\t\t0.004\n\t\t\t);\n\t\t});\n\n\t\tit(\"matches a file with ripple attack/release\", () => {\n\t\t\treturn CompareToFile(\n\t\t\t\t() => {\n\t\t\t\t\tconst ampEnv = new AmplitudeEnvelope({\n\t\t\t\t\t\tattack: 0.5,\n\t\t\t\t\t\tattackCurve: \"ripple\",\n\t\t\t\t\t\tdecay: 0.2,\n\t\t\t\t\t\trelease: 0.3,\n\t\t\t\t\t\treleaseCurve: \"ripple\",\n\t\t\t\t\t\tsustain: 0.1,\n\t\t\t\t\t}).toDestination();\n\t\t\t\t\tconst osc = new Oscillator().start(0).connect(ampEnv);\n\t\t\t\t\tampEnv.triggerAttack(0);\n\t\t\t\t\tampEnv.triggerRelease(0.7);\n\t\t\t\t\tampEnv.triggerAttack(1);\n\t\t\t\t\tampEnv.triggerRelease(1.6);\n\t\t\t\t},\n\t\t\t\t\"ampEnvelope3.wav\",\n\t\t\t\t0.002\n\t\t\t);\n\t\t});\n\t});\n\n\tcontext(\"Envelope\", () => {\n\t\tit(\"extends envelope\", () => {\n\t\t\tconst ampEnv = new AmplitudeEnvelope();\n\t\t\texpect(ampEnv).to.be.instanceOf(Envelope);\n\t\t\tampEnv.dispose();\n\t\t});\n\n\t\tit(\"passes no signal before being triggered\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst ampEnv = new AmplitudeEnvelope().toDestination();\n\t\t\t\tnew Signal(1).connect(ampEnv);\n\t\t\t});\n\t\t\texpect(buffer.isSilent()).to.be.true;\n\t\t});\n\n\t\tit(\"passes signal once triggered\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst ampEnv = new AmplitudeEnvelope().toDestination();\n\t\t\t\tnew Signal(1).connect(ampEnv);\n\t\t\t\tampEnv.triggerAttack(0.1);\n\t\t\t}, 0.2);\n\t\t\texpect(buffer.getTimeOfFirstSound()).to.be.closeTo(0.1, 0.001);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/envelope/AmplitudeEnvelope.ts",
    "content": "import { Gain } from \"../../core/context/Gain.js\";\nimport { NormalRange, Time } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { Envelope, EnvelopeOptions } from \"./Envelope.js\";\n\n/**\n * AmplitudeEnvelope is a Tone.Envelope connected to a gain node.\n * Unlike Tone.Envelope, which outputs the envelope's value, AmplitudeEnvelope accepts\n * an audio signal as the input and will apply the envelope to the amplitude\n * of the signal.\n * Read more about ADSR Envelopes on [Wikipedia](https://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope).\n *\n * @example\n * return Tone.Offline(() => {\n * \tconst ampEnv = new Tone.AmplitudeEnvelope({\n * \t\tattack: 0.1,\n * \t\tdecay: 0.2,\n * \t\tsustain: 1.0,\n * \t\trelease: 0.8\n * \t}).toDestination();\n * \t// create an oscillator and connect it\n * \tconst osc = new Tone.Oscillator().connect(ampEnv).start();\n * \t// trigger the envelopes attack and release \"8t\" apart\n * \tampEnv.triggerAttackRelease(\"8t\");\n * }, 1.5, 1);\n * @category Component\n */\nexport class AmplitudeEnvelope extends Envelope {\n\treadonly name: string = \"AmplitudeEnvelope\";\n\n\tprivate _gainNode: Gain = new Gain({\n\t\tcontext: this.context,\n\t\tgain: 0,\n\t});\n\toutput: Gain = this._gainNode;\n\tinput: Gain = this._gainNode;\n\n\t/**\n\t * @param attack The amount of time it takes for the envelope to go from 0 to its maximum value.\n\t * @param decay\tThe period of time after the attack that it takes for the envelope\n\t *                      \tto fall to the sustain value. Value must be greater than 0.\n\t * @param sustain\tThe percent of the maximum value that the envelope rests at until\n\t *                               \tthe release is triggered.\n\t * @param release\tThe amount of time after the release is triggered it takes to reach 0.\n\t *                        \tValue must be greater than 0.\n\t */\n\tconstructor(\n\t\tattack?: Time,\n\t\tdecay?: Time,\n\t\tsustain?: NormalRange,\n\t\trelease?: Time\n\t);\n\tconstructor(options?: Partial<EnvelopeOptions>);\n\tconstructor() {\n\t\tsuper(\n\t\t\toptionsFromArguments(AmplitudeEnvelope.getDefaults(), arguments, [\n\t\t\t\t\"attack\",\n\t\t\t\t\"decay\",\n\t\t\t\t\"sustain\",\n\t\t\t\t\"release\",\n\t\t\t])\n\t\t);\n\t\tthis._sig.connect(this._gainNode.gain);\n\t\tthis.output = this._gainNode;\n\t\tthis.input = this._gainNode;\n\t}\n\n\t/**\n\t * Clean up\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._gainNode.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/envelope/Envelope.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { connectTo } from \"../../../test/helper/Connect.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { SignalConnectAndDisconnect } from \"../../../test/helper/SignalTests.js\";\nimport { Envelope, EnvelopeCurve } from \"./Envelope.js\";\n\ndescribe(\"Envelope\", () => {\n\tBasicTests(Envelope);\n\tSignalConnectAndDisconnect(Envelope);\n\n\tcontext(\"Envelope\", () => {\n\t\tit(\"has an output connections\", () => {\n\t\t\tconst env = new Envelope();\n\t\t\tenv.connect(connectTo());\n\t\t\tenv.dispose();\n\t\t});\n\n\t\tit(\"can get and set values an Objects\", () => {\n\t\t\tconst env = new Envelope();\n\t\t\tconst values = {\n\t\t\t\tattack: 0,\n\t\t\t\tdecay: 0.5,\n\t\t\t\trelease: \"4n\",\n\t\t\t\tsustain: 1,\n\t\t\t};\n\t\t\tenv.set(values);\n\t\t\texpect(env.get()).to.contain.keys(Object.keys(values));\n\t\t\tenv.dispose();\n\t\t});\n\n\t\tit(\"passes no signal before being triggered\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tnew Envelope().toDestination();\n\t\t\t});\n\t\t\texpect(buffer.isSilent()).to.equal(true);\n\t\t});\n\n\t\tit(\"passes signal once triggered\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope().toDestination();\n\t\t\t\tenv.triggerAttack(0.05);\n\t\t\t}, 0.1);\n\t\t\texpect(buffer.getTimeOfFirstSound()).to.be.closeTo(0.05, 0.001);\n\t\t});\n\n\t\tit(\"can take parameters as both an object and as arguments\", () => {\n\t\t\tconst env0 = new Envelope({\n\t\t\t\tattack: 0,\n\t\t\t\tdecay: 0.5,\n\t\t\t\tsustain: 1,\n\t\t\t});\n\t\t\texpect(env0.attack).to.equal(0);\n\t\t\texpect(env0.decay).to.equal(0.5);\n\t\t\texpect(env0.sustain).to.equal(1);\n\t\t\tenv0.dispose();\n\t\t\tconst env1 = new Envelope(0.1, 0.2, 0.3);\n\t\t\texpect(env1.attack).to.equal(0.1);\n\t\t\texpect(env1.decay).to.equal(0.2);\n\t\t\texpect(env1.sustain).to.equal(0.3);\n\t\t\tenv1.dispose();\n\t\t});\n\n\t\tit(\"ensures that none of the values go below 0\", () => {\n\t\t\tconst env = new Envelope();\n\t\t\texpect(() => {\n\t\t\t\tenv.attack = -1;\n\t\t\t}).to.throw(RangeError);\n\n\t\t\texpect(() => {\n\t\t\t\tenv.decay = -1;\n\t\t\t}).to.throw(RangeError);\n\n\t\t\texpect(() => {\n\t\t\t\tenv.sustain = 2;\n\t\t\t}).to.throw(RangeError);\n\n\t\t\texpect(() => {\n\t\t\t\tenv.release = -1;\n\t\t\t}).to.throw(RangeError);\n\t\t\tenv.dispose();\n\t\t});\n\n\t\tit(\"can set attack to exponential or linear\", () => {\n\t\t\tconst env = new Envelope(0.01, 0.01, 0.5, 0.3);\n\t\t\tenv.attackCurve = \"exponential\";\n\t\t\texpect(env.attackCurve).to.equal(\"exponential\");\n\t\t\tenv.triggerAttack();\n\t\t\tenv.dispose();\n\t\t\t// and can be linear\n\t\t\tconst env2 = new Envelope(0.01, 0.01, 0.5, 0.3);\n\t\t\tenv2.attackCurve = \"linear\";\n\t\t\texpect(env2.attackCurve).to.equal(\"linear\");\n\t\t\tenv2.triggerAttack();\n\t\t\t// and test a non-curve\n\t\t\texpect(() => {\n\t\t\t\t// @ts-ignore\n\t\t\t\tenv2.attackCurve = \"other\";\n\t\t\t}).to.throw(Error);\n\t\t\tenv2.dispose();\n\t\t});\n\n\t\tit(\"can set decay to exponential or linear\", () => {\n\t\t\tconst env = new Envelope(0.01, 0.01, 0.5, 0.3);\n\t\t\tenv.decayCurve = \"exponential\";\n\t\t\texpect(env.decayCurve).to.equal(\"exponential\");\n\t\t\tenv.triggerAttack();\n\t\t\tenv.dispose();\n\t\t\t// and can be linear\n\t\t\tconst env2 = new Envelope(0.01, 0.01, 0.5, 0.3);\n\t\t\tenv2.decayCurve = \"linear\";\n\t\t\texpect(env2.decayCurve).to.equal(\"linear\");\n\t\t\tenv2.triggerAttack();\n\t\t\t// and test a non-curve\n\t\t\texpect(() => {\n\t\t\t\t// @ts-ignore\n\t\t\t\tenv2.decayCurve = \"other\";\n\t\t\t}).to.throw(Error);\n\t\t\tenv2.dispose();\n\t\t});\n\n\t\tit(\"can set release to exponential or linear\", () => {\n\t\t\tconst env = new Envelope(0.01, 0.01, 0.5, 0.3);\n\t\t\tenv.releaseCurve = \"exponential\";\n\t\t\texpect(env.releaseCurve).to.equal(\"exponential\");\n\t\t\tenv.triggerRelease();\n\t\t\tenv.dispose();\n\t\t\t// and can be linear\n\t\t\tconst env2 = new Envelope(0.01, 0.01, 0.5, 0.3);\n\t\t\tenv2.releaseCurve = \"linear\";\n\t\t\texpect(env2.releaseCurve).to.equal(\"linear\");\n\t\t\tenv2.triggerRelease();\n\t\t\t// and test a non-curve\n\t\t\texpect(() => {\n\t\t\t\t// @ts-ignore\n\t\t\t\tenv2.releaseCurve = \"other\";\n\t\t\t}).to.throw(Error);\n\t\t\tenv2.dispose();\n\t\t});\n\n\t\tit(\"can set release to exponential or linear\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope({\n\t\t\t\t\trelease: 0,\n\t\t\t\t});\n\t\t\t\tenv.toDestination();\n\t\t\t\tenv.triggerAttackRelease(0.4, 0);\n\t\t\t}, 0.7);\n\t\t\texpect(buffer.getValueAtTime(0.3)).to.be.above(0);\n\t\t\texpect(buffer.getValueAtTime(0.401)).to.equal(0);\n\t\t});\n\n\t\tit(\"schedule a release at the moment when the attack portion is done\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope({\n\t\t\t\t\tattack: 0.5,\n\t\t\t\t\tdecay: 0.0,\n\t\t\t\t\tsustain: 1,\n\t\t\t\t\trelease: 0.5,\n\t\t\t\t}).toDestination();\n\t\t\t\tenv.triggerAttackRelease(0.5);\n\t\t\t}, 0.7);\n\t\t\t// make sure that it's got the rising edge\n\t\t\texpect(buffer.getValueAtTime(0.1)).to.be.closeTo(0.2, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.2)).to.be.closeTo(0.4, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.3)).to.be.closeTo(0.6, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.4)).to.be.closeTo(0.8, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.5)).to.be.be.closeTo(1, 0.001);\n\t\t});\n\n\t\tit(\"correctly schedules an exponential attack\", async () => {\n\t\t\tconst e = {\n\t\t\t\tattack: 0.01,\n\t\t\t\tdecay: 0.4,\n\t\t\t\trelease: 0.1,\n\t\t\t\tsustain: 0.5,\n\t\t\t};\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(\n\t\t\t\t\te.attack,\n\t\t\t\t\te.decay,\n\t\t\t\t\te.sustain,\n\t\t\t\t\te.release\n\t\t\t\t);\n\t\t\t\tenv.attackCurve = \"exponential\";\n\t\t\t\tenv.toDestination();\n\t\t\t\tenv.triggerAttack(0);\n\t\t\t}, 0.7);\n\t\t\tbuffer.forEachBetween(\n\t\t\t\t(sample) => {\n\t\t\t\t\texpect(sample).to.be.within(0, 1);\n\t\t\t\t},\n\t\t\t\t0,\n\t\t\t\te.attack\n\t\t\t);\n\t\t\tbuffer.forEachBetween(\n\t\t\t\t(sample) => {\n\t\t\t\t\texpect(sample).to.be.within(e.sustain - 0.001, 1);\n\t\t\t\t},\n\t\t\t\te.attack,\n\t\t\t\te.attack + e.decay\n\t\t\t);\n\t\t\tbuffer.forEachBetween((sample) => {\n\t\t\t\texpect(sample).to.be.closeTo(e.sustain, 0.01);\n\t\t\t}, e.attack + e.decay);\n\t\t});\n\n\t\tit(\"correctly schedules a linear release\", async () => {\n\t\t\tconst e = {\n\t\t\t\tattack: 0.01,\n\t\t\t\tdecay: 0.4,\n\t\t\t\trelease: 0.1,\n\t\t\t\tsustain: 0.5,\n\t\t\t};\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(\n\t\t\t\t\te.attack,\n\t\t\t\t\te.decay,\n\t\t\t\t\te.sustain,\n\t\t\t\t\te.release\n\t\t\t\t);\n\t\t\t\tenv.attackCurve = \"exponential\";\n\t\t\t\tenv.toDestination();\n\t\t\t\tenv.triggerAttack(0);\n\t\t\t}, 0.7);\n\t\t\tbuffer.forEachBetween(\n\t\t\t\t(sample, time) => {\n\t\t\t\t\tconst target = 1 - (time - 0.2) * 10;\n\t\t\t\t\texpect(sample).to.be.closeTo(target, 0.01);\n\t\t\t\t},\n\t\t\t\t0.2,\n\t\t\t\t0.2\n\t\t\t);\n\t\t});\n\n\t\tit(\"correctly schedules a linear decay\", async () => {\n\t\t\tconst e = {\n\t\t\t\tattack: 0.1,\n\t\t\t\tdecay: 0.5,\n\t\t\t\trelease: 0.1,\n\t\t\t\tsustain: 0,\n\t\t\t};\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(\n\t\t\t\t\te.attack,\n\t\t\t\t\te.decay,\n\t\t\t\t\te.sustain,\n\t\t\t\t\te.release\n\t\t\t\t);\n\t\t\t\tenv.decayCurve = \"linear\";\n\t\t\t\tenv.toDestination();\n\t\t\t\tenv.triggerAttack(0);\n\t\t\t}, 0.7);\n\t\t\texpect(buffer.getValueAtTime(0.05)).to.be.closeTo(0.5, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.1)).to.be.closeTo(1, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.2)).to.be.closeTo(0.8, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.3)).to.be.closeTo(0.6, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.4)).to.be.closeTo(0.4, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.5)).to.be.closeTo(0.2, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.6)).to.be.closeTo(0, 0.01);\n\t\t});\n\n\t\tit(\"correctly schedules an exponential decay\", async () => {\n\t\t\tconst e = {\n\t\t\t\tattack: 0.1,\n\t\t\t\tdecay: 0.5,\n\t\t\t\trelease: 0.1,\n\t\t\t\tsustain: 0,\n\t\t\t};\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(\n\t\t\t\t\te.attack,\n\t\t\t\t\te.decay,\n\t\t\t\t\te.sustain,\n\t\t\t\t\te.release\n\t\t\t\t);\n\t\t\t\tenv.decayCurve = \"exponential\";\n\t\t\t\tenv.toDestination();\n\t\t\t\tenv.triggerAttack(0);\n\t\t\t}, 0.7);\n\t\t\texpect(buffer.getValueAtTime(0.1)).to.be.closeTo(1, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.2)).to.be.closeTo(0.27, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.3)).to.be.closeTo(0.07, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.4)).to.be.closeTo(0.02, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.5)).to.be.closeTo(0.005, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.6)).to.be.closeTo(0, 0.01);\n\t\t});\n\n\t\tit(\"can schedule a very short attack\", async () => {\n\t\t\tconst e = {\n\t\t\t\tattack: 0.001,\n\t\t\t\tdecay: 0.01,\n\t\t\t\trelease: 0.1,\n\t\t\t\tsustain: 0.1,\n\t\t\t};\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(\n\t\t\t\t\te.attack,\n\t\t\t\t\te.decay,\n\t\t\t\t\te.sustain,\n\t\t\t\t\te.release\n\t\t\t\t);\n\t\t\t\tenv.attackCurve = \"exponential\";\n\t\t\t\tenv.toDestination();\n\t\t\t\tenv.triggerAttack(0);\n\t\t\t}, 0.2);\n\t\t\tbuffer.forEachBetween(\n\t\t\t\t(sample) => {\n\t\t\t\t\texpect(sample).to.be.within(0, 1);\n\t\t\t\t},\n\t\t\t\t0,\n\t\t\t\te.attack\n\t\t\t);\n\t\t\tbuffer.forEachBetween(\n\t\t\t\t(sample) => {\n\t\t\t\t\texpect(sample).to.be.within(e.sustain - 0.001, 1);\n\t\t\t\t},\n\t\t\t\te.attack,\n\t\t\t\te.attack + e.decay\n\t\t\t);\n\t\t\tbuffer.forEachBetween((sample) => {\n\t\t\t\texpect(sample).to.be.closeTo(e.sustain, 0.01);\n\t\t\t}, e.attack + e.decay);\n\t\t});\n\n\t\tit(\"can schedule an attack of time 0\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(0, 0.1);\n\t\t\t\tenv.toDestination();\n\t\t\t\tenv.triggerAttack(0.1);\n\t\t\t}, 0.2);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.001);\n\t\t\texpect(buffer.getValueAtTime(0.0999)).to.be.closeTo(0, 0.001);\n\t\t\texpect(buffer.getValueAtTime(0.1)).to.be.closeTo(1, 0.001);\n\t\t});\n\n\t\tit(\"correctly schedule a release\", async () => {\n\t\t\tconst e = {\n\t\t\t\tattack: 0.001,\n\t\t\t\tdecay: 0.01,\n\t\t\t\trelease: 0.3,\n\t\t\t\tsustain: 0.5,\n\t\t\t};\n\t\t\tconst releaseTime = 0.2;\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(\n\t\t\t\t\te.attack,\n\t\t\t\t\te.decay,\n\t\t\t\t\te.sustain,\n\t\t\t\t\te.release\n\t\t\t\t);\n\t\t\t\tenv.attackCurve = \"exponential\";\n\t\t\t\tenv.toDestination();\n\t\t\t\tenv.triggerAttackRelease(releaseTime);\n\t\t\t}, 0.6);\n\t\t\tconst sustainStart = e.attack + e.decay;\n\t\t\tconst sustainEnd = sustainStart + releaseTime;\n\t\t\tbuffer.forEachBetween(\n\t\t\t\t(sample) => {\n\t\t\t\t\texpect(sample).to.be.below(e.sustain + 0.01);\n\t\t\t\t},\n\t\t\t\tsustainStart,\n\t\t\t\tsustainEnd\n\t\t\t);\n\t\t\tbuffer.forEachBetween((sample) => {\n\t\t\t\texpect(sample).to.be.closeTo(0, 0.01);\n\t\t\t}, releaseTime + e.release);\n\t\t});\n\n\t\tit(\"can retrigger a short attack at the same time as previous release\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(0.001, 0.1, 0.5);\n\t\t\t\tenv.attackCurve = \"linear\";\n\t\t\t\tenv.toDestination();\n\t\t\t\tenv.triggerAttack(0);\n\t\t\t\tenv.triggerRelease(0.4);\n\t\t\t\tenv.triggerAttack(0.4);\n\t\t\t}, 0.6);\n\t\t\texpect(buffer.getValueAtTime(0.4)).be.closeTo(0.5, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.40025)).be.closeTo(0.75, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.4005)).be.closeTo(1, 0.01);\n\t\t});\n\n\t\tit(\"is silent before and after triggering\", async () => {\n\t\t\tconst e = {\n\t\t\t\tattack: 0.001,\n\t\t\t\tdecay: 0.01,\n\t\t\t\trelease: 0.3,\n\t\t\t\tsustain: 0.5,\n\t\t\t};\n\t\t\tconst releaseTime = 0.2;\n\t\t\tconst attackTime = 0.1;\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(\n\t\t\t\t\te.attack,\n\t\t\t\t\te.decay,\n\t\t\t\t\te.sustain,\n\t\t\t\t\te.release\n\t\t\t\t);\n\t\t\t\tenv.attackCurve = \"exponential\";\n\t\t\t\tenv.toDestination();\n\t\t\t\tenv.triggerAttack(attackTime);\n\t\t\t\tenv.triggerRelease(releaseTime);\n\t\t\t}, 0.6);\n\t\t\texpect(buffer.getValueAtTime(attackTime - 0.001)).to.equal(0);\n\t\t\texpect(\n\t\t\t\tbuffer.getValueAtTime(\n\t\t\t\t\te.attack + e.decay + releaseTime + e.release\n\t\t\t\t)\n\t\t\t).to.be.below(0.01);\n\t\t});\n\n\t\tit(\"is silent after decay if sustain is 0\", async () => {\n\t\t\tconst e = {\n\t\t\t\tattack: 0.01,\n\t\t\t\tdecay: 0.04,\n\t\t\t\tsustain: 0,\n\t\t\t};\n\t\t\tconst attackTime = 0.1;\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(e.attack, e.decay, e.sustain);\n\t\t\t\tenv.toDestination();\n\t\t\t\tenv.triggerAttack(attackTime);\n\t\t\t}, 0.4);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\texpect(buffer.getValueAtTime(attackTime - 0.001)).to.equal(0);\n\t\t\t\texpect(\n\t\t\t\t\tbuffer.getValueAtTime(attackTime + e.attack + e.decay)\n\t\t\t\t).to.be.below(0.01);\n\t\t\t});\n\t\t});\n\n\t\tit(\"correctly schedule an attack release envelope\", async () => {\n\t\t\tconst e = {\n\t\t\t\tattack: 0.08,\n\t\t\t\tdecay: 0.2,\n\t\t\t\trelease: 0.2,\n\t\t\t\tsustain: 0.1,\n\t\t\t};\n\t\t\tconst releaseTime = 0.4;\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(\n\t\t\t\t\te.attack,\n\t\t\t\t\te.decay,\n\t\t\t\t\te.sustain,\n\t\t\t\t\te.release\n\t\t\t\t);\n\t\t\t\tenv.toDestination();\n\t\t\t\tenv.triggerAttack(0);\n\t\t\t\tenv.triggerRelease(releaseTime);\n\t\t\t});\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\tif (time < e.attack) {\n\t\t\t\t\texpect(sample).to.be.within(0, 1);\n\t\t\t\t} else if (time < e.attack + e.decay) {\n\t\t\t\t\texpect(sample).to.be.within(e.sustain, 1);\n\t\t\t\t} else if (time < releaseTime) {\n\t\t\t\t\texpect(sample).to.be.closeTo(e.sustain, 0.1);\n\t\t\t\t} else if (time < releaseTime + e.release) {\n\t\t\t\t\texpect(sample).to.be.within(0, e.sustain + 0.01);\n\t\t\t\t} else {\n\t\t\t\t\texpect(sample).to.be.below(0.0001);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"can schedule a combined AttackRelease\", async () => {\n\t\t\tconst e = {\n\t\t\t\tattack: 0.1,\n\t\t\t\tdecay: 0.2,\n\t\t\t\trelease: 0.1,\n\t\t\t\tsustain: 0.35,\n\t\t\t};\n\t\t\tconst releaseTime = 0.4;\n\t\t\tconst duration = 0.4;\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(\n\t\t\t\t\te.attack,\n\t\t\t\t\te.decay,\n\t\t\t\t\te.sustain,\n\t\t\t\t\te.release\n\t\t\t\t);\n\t\t\t\tenv.toDestination();\n\t\t\t\tenv.triggerAttack(0);\n\t\t\t\tenv.triggerRelease(releaseTime);\n\t\t\t}, 0.7);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\tif (time < e.attack) {\n\t\t\t\t\texpect(sample).to.be.within(0, 1);\n\t\t\t\t} else if (time < e.attack + e.decay) {\n\t\t\t\t\texpect(sample).to.be.within(e.sustain - 0.001, 1);\n\t\t\t\t} else if (time < duration) {\n\t\t\t\t\texpect(sample).to.be.closeTo(e.sustain, 0.1);\n\t\t\t\t} else if (time < duration + e.release) {\n\t\t\t\t\texpect(sample).to.be.within(0, e.sustain + 0.01);\n\t\t\t\t} else {\n\t\t\t\t\texpect(sample).to.be.below(0.0015);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"can schedule a combined AttackRelease with velocity\", async () => {\n\t\t\tconst e = {\n\t\t\t\tattack: 0.1,\n\t\t\t\tdecay: 0.2,\n\t\t\t\trelease: 0.1,\n\t\t\t\tsustain: 0.35,\n\t\t\t};\n\t\t\tconst releaseTime = 0.4;\n\t\t\tconst duration = 0.4;\n\t\t\tconst velocity = 0.4;\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(\n\t\t\t\t\te.attack,\n\t\t\t\t\te.decay,\n\t\t\t\t\te.sustain,\n\t\t\t\t\te.release\n\t\t\t\t);\n\t\t\t\tenv.toDestination();\n\t\t\t\tenv.triggerAttack(0, velocity);\n\t\t\t\tenv.triggerRelease(releaseTime);\n\t\t\t}, 0.7);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\tif (time < e.attack) {\n\t\t\t\t\texpect(sample).to.be.within(0, velocity + 0.01);\n\t\t\t\t} else if (time < e.attack + e.decay) {\n\t\t\t\t\texpect(sample).to.be.within(\n\t\t\t\t\t\te.sustain * velocity - 0.01,\n\t\t\t\t\t\tvelocity + 0.01\n\t\t\t\t\t);\n\t\t\t\t} else if (time < duration) {\n\t\t\t\t\texpect(sample).to.be.closeTo(e.sustain * velocity, 0.1);\n\t\t\t\t} else if (time < duration + e.release) {\n\t\t\t\t\texpect(sample).to.be.within(0, e.sustain * velocity + 0.01);\n\t\t\t\t} else {\n\t\t\t\t\texpect(sample).to.be.below(0.01);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"can schedule multiple envelopes\", async () => {\n\t\t\tconst e = {\n\t\t\t\tattack: 0.1,\n\t\t\t\tdecay: 0.2,\n\t\t\t\trelease: 0.1,\n\t\t\t\tsustain: 0.0,\n\t\t\t};\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(\n\t\t\t\t\te.attack,\n\t\t\t\t\te.decay,\n\t\t\t\t\te.sustain,\n\t\t\t\t\te.release\n\t\t\t\t);\n\t\t\t\tenv.toDestination();\n\t\t\t\tenv.triggerAttack(0);\n\t\t\t\tenv.triggerAttack(0.5);\n\t\t\t}, 0.85);\n\t\t\t// first trigger\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.1)).to.be.closeTo(1, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.3)).to.be.closeTo(0, 0.01);\n\t\t\t// second trigger\n\t\t\texpect(buffer.getValueAtTime(0.5)).to.be.closeTo(0, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.6)).to.be.closeTo(1, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.8)).to.be.closeTo(0, 0.01);\n\t\t});\n\n\t\tit(\"can schedule multiple attack/releases with no discontinuities\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(0.1, 0.2, 0.2, 0.4).toDestination();\n\t\t\t\tenv.triggerAttackRelease(0, 0.4);\n\t\t\t\tenv.triggerAttackRelease(0.4, 0.11);\n\t\t\t\tenv.triggerAttackRelease(0.45, 0.1);\n\t\t\t\tenv.triggerAttackRelease(1.1, 0.09);\n\t\t\t\tenv.triggerAttackRelease(1.5, 0.3);\n\t\t\t\tenv.triggerAttackRelease(1.8, 0.29);\n\t\t\t}, 2);\n\t\t\t// test for discontinuities\n\t\t\tlet lastSample = 0;\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\texpect(sample).to.be.at.most(1);\n\t\t\t\tconst diff = Math.abs(lastSample - sample);\n\t\t\t\texpect(diff).to.be.lessThan(0.001);\n\t\t\t\tlastSample = sample;\n\t\t\t});\n\t\t});\n\n\t\tit(\"can schedule multiple 'linear' attack/releases with no discontinuities\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(0.1, 0.2, 0.2, 0.4).toDestination();\n\t\t\t\tenv.attackCurve = \"linear\";\n\t\t\t\tenv.releaseCurve = \"linear\";\n\t\t\t\tenv.triggerAttackRelease(0, 0.4);\n\t\t\t\tenv.triggerAttackRelease(0.4, 0.11);\n\t\t\t\tenv.triggerAttackRelease(0.45, 0.1);\n\t\t\t\tenv.triggerAttackRelease(1.1, 0.09);\n\t\t\t\tenv.triggerAttackRelease(1.5, 0.3);\n\t\t\t\tenv.triggerAttackRelease(1.8, 0.29);\n\t\t\t}, 2);\n\t\t\t// test for discontinuities\n\t\t\tlet lastSample = 0;\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\texpect(sample).to.be.at.most(1);\n\t\t\t\tconst diff = Math.abs(lastSample - sample);\n\t\t\t\texpect(diff).to.be.lessThan(0.001);\n\t\t\t\tlastSample = sample;\n\t\t\t});\n\t\t});\n\n\t\tit(\"can schedule multiple 'exponential' attack/releases with no discontinuities\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(0.1, 0.2, 0.2, 0.4).toDestination();\n\t\t\t\tenv.attackCurve = \"exponential\";\n\t\t\t\tenv.releaseCurve = \"exponential\";\n\t\t\t\tenv.triggerAttackRelease(0, 0.4);\n\t\t\t\tenv.triggerAttackRelease(0.4, 0.11);\n\t\t\t\tenv.triggerAttackRelease(0.45, 0.1);\n\t\t\t\tenv.triggerAttackRelease(1.1, 0.09);\n\t\t\t\tenv.triggerAttackRelease(1.5, 0.3);\n\t\t\t\tenv.triggerAttackRelease(1.8, 0.29);\n\t\t\t}, 2);\n\t\t\t// test for discontinuities\n\t\t\tlet lastSample = 0;\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\texpect(sample).to.be.at.most(1);\n\t\t\t\tconst diff = Math.abs(lastSample - sample);\n\t\t\t\texpect(diff).to.be.lessThan(0.0035);\n\t\t\t\tlastSample = sample;\n\t\t\t});\n\t\t});\n\n\t\tit(\"can schedule multiple 'sine' attack/releases with no discontinuities\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(0.1, 0.2, 0.2, 0.4).toDestination();\n\t\t\t\tenv.attackCurve = \"sine\";\n\t\t\t\tenv.releaseCurve = \"sine\";\n\t\t\t\tenv.triggerAttackRelease(0, 0.4);\n\t\t\t\tenv.triggerAttackRelease(0.4, 0.11);\n\t\t\t\tenv.triggerAttackRelease(0.45, 0.1);\n\t\t\t\tenv.triggerAttackRelease(1.1, 0.09);\n\t\t\t\tenv.triggerAttackRelease(1.5, 0.3);\n\t\t\t\tenv.triggerAttackRelease(1.8, 0.29);\n\t\t\t}, 2);\n\t\t\t// test for discontinuities\n\t\t\tlet lastSample = 0;\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\texpect(sample).to.be.at.most(1);\n\t\t\t\tconst diff = Math.abs(lastSample - sample);\n\t\t\t\texpect(diff).to.be.lessThan(0.0035);\n\t\t\t\tlastSample = sample;\n\t\t\t});\n\t\t});\n\n\t\tit(\"can schedule multiple 'cosine' attack/releases with no discontinuities\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(0.1, 0.2, 0.2, 0.4).toDestination();\n\t\t\t\tenv.attackCurve = \"cosine\";\n\t\t\t\tenv.releaseCurve = \"cosine\";\n\t\t\t\tenv.triggerAttackRelease(0, 0.4);\n\t\t\t\tenv.triggerAttackRelease(0.4, 0.11);\n\t\t\t\tenv.triggerAttackRelease(0.45, 0.1);\n\t\t\t\tenv.triggerAttackRelease(1.1, 0.09);\n\t\t\t\tenv.triggerAttackRelease(1.5, 0.3);\n\t\t\t\tenv.triggerAttackRelease(1.8, 0.29);\n\t\t\t}, 2);\n\t\t\t// test for discontinuities\n\t\t\tlet lastSample = 0;\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\texpect(sample).to.be.at.most(1);\n\t\t\t\tconst diff = Math.abs(lastSample - sample);\n\t\t\t\texpect(diff).to.be.lessThan(0.002);\n\t\t\t\tlastSample = sample;\n\t\t\t});\n\t\t});\n\n\t\tit(\"reports its current envelope value (.value)\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(1, 0.2, 1).toDestination();\n\t\t\t\texpect(env.value).to.be.closeTo(0, 0.01);\n\t\t\t\tenv.triggerAttack();\n\t\t\t\treturn (time) => {\n\t\t\t\t\texpect(env.value).to.be.closeTo(time, 0.01);\n\t\t\t\t};\n\t\t\t}, 0.5);\n\t\t});\n\n\t\tit(\"can cancel a schedule envelope\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope(0.1, 0.2, 1).toDestination();\n\t\t\t\tenv.triggerAttack(0.2);\n\t\t\t\tenv.cancel(0.2);\n\t\t\t}, 0.3);\n\t\t\texpect(buffer.isSilent()).to.be.true;\n\t\t});\n\t});\n\n\tcontext(\"Attack/Release Curves\", () => {\n\t\tconst envelopeCurves: EnvelopeCurve[] = [\n\t\t\t\"linear\",\n\t\t\t\"exponential\",\n\t\t\t\"bounce\",\n\t\t\t\"cosine\",\n\t\t\t\"ripple\",\n\t\t\t\"sine\",\n\t\t\t\"step\",\n\t\t];\n\n\t\tit(\"can get set all of the types as the attackCurve\", () => {\n\t\t\tconst env = new Envelope();\n\t\t\tenvelopeCurves.forEach((type) => {\n\t\t\t\tenv.attackCurve = type;\n\t\t\t\texpect(env.attackCurve).to.equal(type);\n\t\t\t});\n\t\t\tenv.dispose();\n\t\t});\n\n\t\tit(\"can get set all of the types as the releaseCurve\", () => {\n\t\t\tconst env = new Envelope();\n\t\t\tenvelopeCurves.forEach((type) => {\n\t\t\t\tenv.releaseCurve = type;\n\t\t\t\texpect(env.releaseCurve).to.equal(type);\n\t\t\t});\n\t\t\tenv.dispose();\n\t\t});\n\n\t\tit(\"outputs a signal when the attack/release curves are set to 'bounce'\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope({\n\t\t\t\t\tattack: 0.3,\n\t\t\t\t\tattackCurve: \"bounce\",\n\t\t\t\t\tdecay: 0,\n\t\t\t\t\trelease: 0.3,\n\t\t\t\t\treleaseCurve: \"bounce\",\n\t\t\t\t\tsustain: 1,\n\t\t\t\t}).toDestination();\n\t\t\t\tenv.triggerAttackRelease(0.3, 0.1);\n\t\t\t}, 0.8);\n\t\t\tbuffer.forEachBetween(\n\t\t\t\t(sample) => {\n\t\t\t\t\texpect(sample).to.be.above(0);\n\t\t\t\t},\n\t\t\t\t0.101,\n\t\t\t\t0.7\n\t\t\t);\n\t\t});\n\n\t\tit(\"outputs a signal when the attack/release curves are set to 'ripple'\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope({\n\t\t\t\t\tattack: 0.3,\n\t\t\t\t\tattackCurve: \"ripple\",\n\t\t\t\t\tdecay: 0,\n\t\t\t\t\trelease: 0.3,\n\t\t\t\t\treleaseCurve: \"ripple\",\n\t\t\t\t\tsustain: 1,\n\t\t\t\t}).toDestination();\n\t\t\t\tenv.triggerAttackRelease(0.3, 0.1);\n\t\t\t}, 0.8);\n\t\t\tbuffer.forEachBetween(\n\t\t\t\t(sample) => {\n\t\t\t\t\texpect(sample).to.be.above(0);\n\t\t\t\t},\n\t\t\t\t0.101,\n\t\t\t\t0.7\n\t\t\t);\n\t\t});\n\n\t\tit(\"outputs a signal when the attack/release curves are set to 'sine'\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope({\n\t\t\t\t\tattack: 0.3,\n\t\t\t\t\tattackCurve: \"sine\",\n\t\t\t\t\tdecay: 0,\n\t\t\t\t\trelease: 0.3,\n\t\t\t\t\treleaseCurve: \"sine\",\n\t\t\t\t\tsustain: 1,\n\t\t\t\t}).toDestination();\n\t\t\t\tenv.triggerAttackRelease(0.3, 0.1);\n\t\t\t}, 0.8);\n\t\t\tbuffer.forEachBetween(\n\t\t\t\t(sample) => {\n\t\t\t\t\texpect(sample).to.be.above(0);\n\t\t\t\t},\n\t\t\t\t0.101,\n\t\t\t\t0.7\n\t\t\t);\n\t\t});\n\n\t\tit(\"outputs a signal when the attack/release curves are set to 'cosine'\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope({\n\t\t\t\t\tattack: 0.3,\n\t\t\t\t\tattackCurve: \"cosine\",\n\t\t\t\t\tdecay: 0,\n\t\t\t\t\trelease: 0.3,\n\t\t\t\t\treleaseCurve: \"cosine\",\n\t\t\t\t\tsustain: 1,\n\t\t\t\t}).toDestination();\n\t\t\t\tenv.triggerAttackRelease(0.3, 0.1);\n\t\t\t}, 0.8);\n\t\t\tbuffer.forEachBetween(\n\t\t\t\t(sample) => {\n\t\t\t\t\texpect(sample).to.be.above(0);\n\t\t\t\t},\n\t\t\t\t0.101,\n\t\t\t\t0.7\n\t\t\t);\n\t\t});\n\n\t\tit(\"outputs a signal when the attack/release curves are set to 'step'\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope({\n\t\t\t\t\tattack: 0.3,\n\t\t\t\t\tattackCurve: \"step\",\n\t\t\t\t\tdecay: 0,\n\t\t\t\t\trelease: 0.3,\n\t\t\t\t\treleaseCurve: \"step\",\n\t\t\t\t\tsustain: 1,\n\t\t\t\t}).toDestination();\n\t\t\t\tenv.triggerAttackRelease(0.3, 0.1);\n\t\t\t}, 0.8);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\tif (time > 0.3 && time < 0.5) {\n\t\t\t\t\texpect(sample).to.be.above(0);\n\t\t\t\t} else if (time < 0.1) {\n\t\t\t\t\texpect(sample).to.equal(0);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"outputs a signal when the attack/release curves are set to an array\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope({\n\t\t\t\t\tattack: 0.3,\n\t\t\t\t\tattackCurve: [0, 1, 0, 1],\n\t\t\t\t\tdecay: 0,\n\t\t\t\t\trelease: 0.3,\n\t\t\t\t\treleaseCurve: [1, 0, 1, 0],\n\t\t\t\t\tsustain: 1,\n\t\t\t\t}).toDestination();\n\t\t\t\texpect(env.attackCurve).to.deep.equal([0, 1, 0, 1]);\n\t\t\t\tenv.triggerAttackRelease(0.3, 0.1);\n\t\t\t}, 0.8);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\tif (time > 0.4 && time < 0.5) {\n\t\t\t\t\texpect(sample).to.be.above(0);\n\t\t\t\t} else if (time < 0.1) {\n\t\t\t\t\texpect(sample).to.equal(0);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"can scale a velocity with a custom curve\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope({\n\t\t\t\t\tattack: 0.3,\n\t\t\t\t\tattackCurve: [0, 1, 0, 1],\n\t\t\t\t\tdecay: 0,\n\t\t\t\t\trelease: 0.3,\n\t\t\t\t\treleaseCurve: [1, 0, 1, 0],\n\t\t\t\t\tsustain: 1,\n\t\t\t\t}).toDestination();\n\t\t\t\tenv.triggerAttackRelease(0.4, 0.1, 0.5);\n\t\t\t}, 0.8);\n\t\t\tbuffer.forEach((sample) => {\n\t\t\t\texpect(sample).to.be.at.most(0.51);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can render the envelope to a curve\", async () => {\n\t\t\tconst env = new Envelope();\n\t\t\tconst curve = await env.asArray();\n\t\t\texpect(curve.some((v) => v > 0)).to.be.true;\n\t\t\tcurve.forEach((v) => expect(v).to.be.within(0, 1));\n\t\t\tenv.dispose();\n\t\t});\n\n\t\tit(\"can render the envelope to an array with a given length\", async () => {\n\t\t\tconst env = new Envelope();\n\t\t\tconst curve = await env.asArray(256);\n\t\t\texpect(curve.length).to.equal(256);\n\t\t\tenv.dispose();\n\t\t});\n\n\t\tit(\"can retrigger partial envelope with custom type\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst env = new Envelope({\n\t\t\t\t\tattack: 0.5,\n\t\t\t\t\tattackCurve: \"cosine\",\n\t\t\t\t\tdecay: 0,\n\t\t\t\t\trelease: 0.5,\n\t\t\t\t\treleaseCurve: \"sine\",\n\t\t\t\t\tsustain: 1,\n\t\t\t\t}).toDestination();\n\t\t\t\tenv.triggerAttack(0);\n\t\t\t\tenv.triggerRelease(0.2);\n\t\t\t\tenv.triggerAttack(0.5);\n\t\t\t}, 1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.equal(0);\n\t\t\texpect(buffer.getValueAtTime(0.1)).to.be.closeTo(0.32, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.2)).to.be.closeTo(0.6, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.3)).to.be.closeTo(0.53, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.4)).to.be.closeTo(0.38, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.5)).to.be.closeTo(0.2, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.6)).to.be.closeTo(0.52, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.7)).to.be.closeTo(0.78, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.8)).to.be.closeTo(0.95, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.9)).to.be.closeTo(1, 0.01);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/envelope/Envelope.ts",
    "content": "import { OfflineContext } from \"../../core/context/OfflineContext.js\";\nimport { InputNode, OutputNode } from \"../../core/context/ToneAudioNode.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { NormalRange, Time } from \"../../core/type/Units.js\";\nimport { assert } from \"../../core/util/Debug.js\";\nimport { range, timeRange } from \"../../core/util/Decorator.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { isArray, isObject, isString } from \"../../core/util/TypeCheck.js\";\nimport {\n\tconnectSignal,\n\tdisconnectSignal,\n\tSignal,\n} from \"../../signal/Signal.js\";\n\ntype BasicEnvelopeCurve = \"linear\" | \"exponential\";\ntype InternalEnvelopeCurve = BasicEnvelopeCurve | number[];\nexport type EnvelopeCurve = EnvelopeCurveName | number[];\n\nexport interface EnvelopeOptions extends ToneAudioNodeOptions {\n\tattack: Time;\n\tdecay: Time;\n\tsustain: NormalRange;\n\trelease: Time;\n\tattackCurve: EnvelopeCurve;\n\treleaseCurve: EnvelopeCurve;\n\tdecayCurve: BasicEnvelopeCurve;\n}\n\n/**\n * Envelope is an [ADSR](https://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope)\n * envelope generator. Envelope outputs a signal which\n * can be connected to an AudioParam or Tone.Signal.\n * ```\n *           /\\\n *          /  \\\n *         /    \\\n *        /      \\\n *       /        \\___________\n *      /                     \\\n *     /                       \\\n *    /                         \\\n *   /                           \\\n * ```\n * @example\n * return Tone.Offline(() => {\n * \tconst env = new Tone.Envelope({\n * \t\tattack: 0.1,\n * \t\tdecay: 0.2,\n * \t\tsustain: 0.5,\n * \t\trelease: 0.8,\n * \t}).toDestination();\n * \tenv.triggerAttackRelease(0.5);\n * }, 1.5, 1);\n * @category Component\n */\nexport class Envelope extends ToneAudioNode<EnvelopeOptions> {\n\treadonly name: string = \"Envelope\";\n\n\t/**\n\t * When triggerAttack is called, the attack time is the amount of\n\t * time it takes for the envelope to reach its maximum value.\n\t * ```\n\t *           /\\\n\t *          /X \\\n\t *         /XX  \\\n\t *        /XXX   \\\n\t *       /XXXX    \\___________\n\t *      /XXXXX                \\\n\t *     /XXXXXX                 \\\n\t *    /XXXXXXX                  \\\n\t *   /XXXXXXXX                   \\\n\t * ```\n\t * @min 0\n\t * @max 2\n\t */\n\t@timeRange(0)\n\tattack: Time;\n\n\t/**\n\t * After the attack portion of the envelope, the value will fall\n\t * over the duration of the decay time to its sustain value.\n\t * ```\n\t *           /\\\n\t *          / X\\\n\t *         /  XX\\\n\t *        /   XXX\\\n\t *       /    XXXX\\___________\n\t *      /     XXXXX           \\\n\t *     /      XXXXX            \\\n\t *    /       XXXXX             \\\n\t *   /        XXXXX              \\\n\t * ```\n\t * @min 0\n\t * @max 2\n\t */\n\t@timeRange(0)\n\tdecay: Time;\n\n\t/**\n\t * The sustain value is the value\n\t * which the envelope rests at after triggerAttack is\n\t * called, but before triggerRelease is invoked.\n\t * ```\n\t *           /\\\n\t *          /  \\\n\t *         /    \\\n\t *        /      \\\n\t *       /        \\___________\n\t *      /          XXXXXXXXXXX\\\n\t *     /           XXXXXXXXXXX \\\n\t *    /            XXXXXXXXXXX  \\\n\t *   /             XXXXXXXXXXX   \\\n\t * ```\n\t */\n\t@range(0, 1)\n\tsustain: NormalRange;\n\n\t/**\n\t * After triggerRelease is called, the envelope's\n\t * value will fall to its minimum value over the\n\t * duration of the release time.\n\t * ```\n\t *           /\\\n\t *          /  \\\n\t *         /    \\\n\t *        /      \\\n\t *       /        \\___________\n\t *      /                    X\\\n\t *     /                     XX\\\n\t *    /                      XXX\\\n\t *   /                       XXXX\\\n\t * ```\n\t * @min 0\n\t * @max 5\n\t */\n\t@timeRange(0)\n\trelease: Time;\n\n\t/**\n\t * The automation curve type for the attack\n\t */\n\tprivate _attackCurve!: InternalEnvelopeCurve;\n\n\t/**\n\t * The automation curve type for the decay\n\t */\n\tprivate _decayCurve!: InternalEnvelopeCurve;\n\n\t/**\n\t * The automation curve type for the release\n\t */\n\tprivate _releaseCurve!: InternalEnvelopeCurve;\n\n\t/**\n\t * the signal which is output.\n\t */\n\tprotected _sig: Signal<\"normalRange\"> = new Signal({\n\t\tcontext: this.context,\n\t\tvalue: 0,\n\t});\n\n\t/**\n\t * The output signal of the envelope\n\t */\n\toutput: OutputNode = this._sig;\n\n\t/**\n\t * Envelope has no input\n\t */\n\tinput: InputNode | undefined = undefined;\n\n\t/**\n\t * @param attack The amount of time it takes for the envelope to go from\n\t *                        0 to its maximum value.\n\t * @param decay\tThe period of time after the attack that it takes for the envelope\n\t *                      \tto fall to the sustain value. Value must be greater than 0.\n\t * @param sustain\tThe percent of the maximum value that the envelope rests at until\n\t *                               \tthe release is triggered.\n\t * @param release\tThe amount of time after the release is triggered it takes to reach 0.\n\t *                        \tValue must be greater than 0.\n\t */\n\tconstructor(\n\t\tattack?: Time,\n\t\tdecay?: Time,\n\t\tsustain?: NormalRange,\n\t\trelease?: Time\n\t);\n\tconstructor(options?: Partial<EnvelopeOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tEnvelope.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"attack\", \"decay\", \"sustain\", \"release\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.attack = options.attack;\n\t\tthis.decay = options.decay;\n\t\tthis.sustain = options.sustain;\n\t\tthis.release = options.release;\n\t\tthis.attackCurve = options.attackCurve;\n\t\tthis.releaseCurve = options.releaseCurve;\n\t\tthis.decayCurve = options.decayCurve;\n\t}\n\n\tstatic getDefaults(): EnvelopeOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tattack: 0.01,\n\t\t\tattackCurve: \"linear\" as EnvelopeCurveName,\n\t\t\tdecay: 0.1,\n\t\t\tdecayCurve: \"exponential\" as BasicEnvelopeCurve,\n\t\t\trelease: 1,\n\t\t\treleaseCurve: \"exponential\" as EnvelopeCurveName,\n\t\t\tsustain: 0.5,\n\t\t});\n\t}\n\n\t/**\n\t * Read the current value of the envelope. Useful for\n\t * synchronizing visual output to the envelope.\n\t */\n\tget value(): NormalRange {\n\t\treturn this.getValueAtTime(this.now());\n\t}\n\n\t/**\n\t * Get the curve\n\t * @param  curve\n\t * @param  direction  In/Out\n\t * @return The curve name\n\t */\n\tprivate _getCurve(\n\t\tcurve: InternalEnvelopeCurve,\n\t\tdirection: EnvelopeDirection\n\t): EnvelopeCurve {\n\t\tif (isString(curve)) {\n\t\t\treturn curve;\n\t\t} else {\n\t\t\t// look up the name in the curves array\n\t\t\tlet curveName: EnvelopeCurveName;\n\t\t\tfor (curveName in EnvelopeCurves) {\n\t\t\t\tif (EnvelopeCurves[curveName][direction] === curve) {\n\t\t\t\t\treturn curveName;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// return the custom curve\n\t\t\treturn curve;\n\t\t}\n\t}\n\n\t/**\n\t * Assign a the curve to the given name using the direction\n\t * @param  name\n\t * @param  direction In/Out\n\t * @param  curve\n\t */\n\tprivate _setCurve(\n\t\tname: \"_attackCurve\" | \"_decayCurve\" | \"_releaseCurve\",\n\t\tdirection: EnvelopeDirection,\n\t\tcurve: EnvelopeCurve\n\t): void {\n\t\t// check if it's a valid type\n\t\tif (isString(curve) && Reflect.has(EnvelopeCurves, curve)) {\n\t\t\tconst curveDef = EnvelopeCurves[curve];\n\t\t\tif (isObject(curveDef)) {\n\t\t\t\tif (name !== \"_decayCurve\") {\n\t\t\t\t\tthis[name] = curveDef[direction];\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis[name] = curveDef;\n\t\t\t}\n\t\t} else if (isArray(curve) && name !== \"_decayCurve\") {\n\t\t\tthis[name] = curve;\n\t\t} else {\n\t\t\tthrow new Error(\"Envelope: invalid curve: \" + curve);\n\t\t}\n\t}\n\n\t/**\n\t * The shape of the attack.\n\t * Can be any of these strings:\n\t * * \"linear\"\n\t * * \"exponential\"\n\t * * \"sine\"\n\t * * \"cosine\"\n\t * * \"bounce\"\n\t * * \"ripple\"\n\t * * \"step\"\n\t *\n\t * Can also be an array which describes the curve. Values\n\t * in the array are evenly subdivided and linearly\n\t * interpolated over the duration of the attack.\n\t * @example\n\t * return Tone.Offline(() => {\n\t * \tconst env = new Tone.Envelope(0.4).toDestination();\n\t * \tenv.attackCurve = \"linear\";\n\t * \tenv.triggerAttack();\n\t * }, 1, 1);\n\t */\n\tget attackCurve(): EnvelopeCurve {\n\t\treturn this._getCurve(this._attackCurve, \"In\");\n\t}\n\tset attackCurve(curve) {\n\t\tthis._setCurve(\"_attackCurve\", \"In\", curve);\n\t}\n\n\t/**\n\t * The shape of the release. See the attack curve types.\n\t * @example\n\t * return Tone.Offline(() => {\n\t * \tconst env = new Tone.Envelope({\n\t * \t\trelease: 0.8\n\t * \t}).toDestination();\n\t * \tenv.triggerAttack();\n\t * \t// release curve could also be defined by an array\n\t * \tenv.releaseCurve = [1, 0.3, 0.4, 0.2, 0.7, 0];\n\t * \tenv.triggerRelease(0.2);\n\t * }, 1, 1);\n\t */\n\tget releaseCurve(): EnvelopeCurve {\n\t\treturn this._getCurve(this._releaseCurve, \"Out\");\n\t}\n\tset releaseCurve(curve) {\n\t\tthis._setCurve(\"_releaseCurve\", \"Out\", curve);\n\t}\n\n\t/**\n\t * The shape of the decay either \"linear\" or \"exponential\"\n\t * @example\n\t * return Tone.Offline(() => {\n\t * \tconst env = new Tone.Envelope({\n\t * \t\tsustain: 0.1,\n\t * \t\tdecay: 0.5\n\t * \t}).toDestination();\n\t * \tenv.decayCurve = \"linear\";\n\t * \tenv.triggerAttack();\n\t * }, 1, 1);\n\t */\n\tget decayCurve(): EnvelopeCurve {\n\t\treturn this._getCurve(this._decayCurve, \"Out\");\n\t}\n\tset decayCurve(curve) {\n\t\tthis._setCurve(\"_decayCurve\", \"Out\", curve);\n\t}\n\n\t/**\n\t * Trigger the attack/decay portion of the ADSR envelope.\n\t * @param  time When the attack should start.\n\t * @param velocity The velocity of the envelope scales the vales.\n\t *                             number between 0-1\n\t * @example\n\t * const env = new Tone.AmplitudeEnvelope().toDestination();\n\t * const osc = new Tone.Oscillator().connect(env).start();\n\t * // trigger the attack 0.5 seconds from now with a velocity of 0.2\n\t * env.triggerAttack(\"+0.5\", 0.2);\n\t */\n\ttriggerAttack(time?: Time, velocity: NormalRange = 1): this {\n\t\tthis.log(\"triggerAttack\", time, velocity);\n\t\ttime = this.toSeconds(time);\n\t\tconst originalAttack = this.toSeconds(this.attack);\n\t\tlet attack = originalAttack;\n\t\tconst decay = this.toSeconds(this.decay);\n\t\t// check if it's not a complete attack\n\t\tconst currentValue = this.getValueAtTime(time);\n\t\tif (currentValue > 0) {\n\t\t\t// subtract the current value from the attack time\n\t\t\tconst attackRate = 1 / attack;\n\t\t\tconst remainingDistance = 1 - currentValue;\n\t\t\t// the attack is now the remaining time\n\t\t\tattack = remainingDistance / attackRate;\n\t\t}\n\t\t// attack\n\t\tif (attack < this.sampleTime) {\n\t\t\tthis._sig.cancelScheduledValues(time);\n\t\t\t// case where the attack time is 0 should set instantly\n\t\t\tthis._sig.setValueAtTime(velocity, time);\n\t\t} else if (this._attackCurve === \"linear\") {\n\t\t\tthis._sig.linearRampTo(velocity, attack, time);\n\t\t} else if (this._attackCurve === \"exponential\") {\n\t\t\tthis._sig.targetRampTo(velocity, attack, time);\n\t\t} else {\n\t\t\tthis._sig.cancelAndHoldAtTime(time);\n\t\t\tlet curve = this._attackCurve;\n\t\t\t// find the starting position in the curve\n\t\t\tfor (let i = 1; i < curve.length; i++) {\n\t\t\t\t// the starting index is between the two values\n\t\t\t\tif (curve[i - 1] <= currentValue && currentValue <= curve[i]) {\n\t\t\t\t\tcurve = this._attackCurve.slice(i);\n\t\t\t\t\t// the first index is the current value\n\t\t\t\t\tcurve[0] = currentValue;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._sig.setValueCurveAtTime(curve, time, attack, velocity);\n\t\t}\n\t\t// decay\n\t\tif (decay && this.sustain < 1) {\n\t\t\tconst decayValue = velocity * this.sustain;\n\t\t\tconst decayStart = time + attack;\n\t\t\tthis.log(\"decay\", decayStart);\n\t\t\tif (this._decayCurve === \"linear\") {\n\t\t\t\tthis._sig.linearRampToValueAtTime(\n\t\t\t\t\tdecayValue,\n\t\t\t\t\tdecay + decayStart\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tthis._sig.exponentialApproachValueAtTime(\n\t\t\t\t\tdecayValue,\n\t\t\t\t\tdecayStart,\n\t\t\t\t\tdecay\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Triggers the release of the envelope.\n\t * @param  time When the release portion of the envelope should start.\n\t * @example\n\t * const env = new Tone.AmplitudeEnvelope().toDestination();\n\t * const osc = new Tone.Oscillator({\n\t * \ttype: \"sawtooth\"\n\t * }).connect(env).start();\n\t * env.triggerAttack();\n\t * // trigger the release half a second after the attack\n\t * env.triggerRelease(\"+0.5\");\n\t */\n\ttriggerRelease(time?: Time): this {\n\t\tthis.log(\"triggerRelease\", time);\n\t\ttime = this.toSeconds(time);\n\t\tconst currentValue = this.getValueAtTime(time);\n\t\tif (currentValue > 0) {\n\t\t\tconst release = this.toSeconds(this.release);\n\t\t\tif (release < this.sampleTime) {\n\t\t\t\tthis._sig.setValueAtTime(0, time);\n\t\t\t} else if (this._releaseCurve === \"linear\") {\n\t\t\t\tthis._sig.linearRampTo(0, release, time);\n\t\t\t} else if (this._releaseCurve === \"exponential\") {\n\t\t\t\tthis._sig.targetRampTo(0, release, time);\n\t\t\t} else {\n\t\t\t\tassert(\n\t\t\t\t\tisArray(this._releaseCurve),\n\t\t\t\t\t\"releaseCurve must be either 'linear', 'exponential' or an array\"\n\t\t\t\t);\n\t\t\t\tthis._sig.cancelAndHoldAtTime(time);\n\t\t\t\tthis._sig.setValueCurveAtTime(\n\t\t\t\t\tthis._releaseCurve,\n\t\t\t\t\ttime,\n\t\t\t\t\trelease,\n\t\t\t\t\tcurrentValue\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Get the scheduled value at the given time. This will\n\t * return the unconverted (raw) value.\n\t * @example\n\t * const env = new Tone.Envelope(0.5, 1, 0.4, 2);\n\t * env.triggerAttackRelease(2);\n\t * setInterval(() => console.log(env.getValueAtTime(Tone.now())), 100);\n\t */\n\tgetValueAtTime(time: Time): NormalRange {\n\t\treturn this._sig.getValueAtTime(time);\n\t}\n\n\t/**\n\t * triggerAttackRelease is shorthand for triggerAttack, then waiting\n\t * some duration, then triggerRelease.\n\t * @param duration The duration of the sustain.\n\t * @param time When the attack should be triggered.\n\t * @param velocity The velocity of the envelope.\n\t * @example\n\t * const env = new Tone.AmplitudeEnvelope().toDestination();\n\t * const osc = new Tone.Oscillator().connect(env).start();\n\t * // trigger the release 0.5 seconds after the attack\n\t * env.triggerAttackRelease(0.5);\n\t */\n\ttriggerAttackRelease(\n\t\tduration: Time,\n\t\ttime?: Time,\n\t\tvelocity: NormalRange = 1\n\t): this {\n\t\ttime = this.toSeconds(time);\n\t\tthis.triggerAttack(time, velocity);\n\t\tthis.triggerRelease(time + this.toSeconds(duration));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Cancels all scheduled envelope changes after the given time.\n\t */\n\tcancel(after?: Time): this {\n\t\tthis._sig.cancelScheduledValues(this.toSeconds(after));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Connect the envelope to a destination node.\n\t */\n\tconnect(destination: InputNode, outputNumber = 0, inputNumber = 0): this {\n\t\tconnectSignal(this, destination, outputNumber, inputNumber);\n\t\treturn this;\n\t}\n\n\t/** @inheritdoc */\n\tdisconnect(\n\t\tdestination?: InputNode,\n\t\toutputNumber = 0,\n\t\tinputNumber = 0\n\t): this {\n\t\tdisconnectSignal(this, destination, outputNumber, inputNumber);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Render the envelope curve to an array of the given length.\n\t * Good for visualizing the envelope curve. Rescales the duration of the\n\t * envelope to fit the length.\n\t */\n\tasync asArray(length = 1024): Promise<Float32Array> {\n\t\tconst duration = length / this.context.sampleRate;\n\t\tconst context = new OfflineContext(\n\t\t\t1,\n\t\t\tduration,\n\t\t\tthis.context.sampleRate\n\t\t);\n\t\t// normalize the ADSR for the given duration with 20% sustain time\n\t\tconst attackPortion =\n\t\t\tthis.toSeconds(this.attack) + this.toSeconds(this.decay);\n\t\tconst envelopeDuration = attackPortion + this.toSeconds(this.release);\n\t\tconst sustainTime = envelopeDuration * 0.1;\n\t\tconst totalDuration = envelopeDuration + sustainTime;\n\t\t// @ts-ignore\n\t\tconst clone = new this.constructor(\n\t\t\tObject.assign(this.get(), {\n\t\t\t\tattack:\n\t\t\t\t\t(duration * this.toSeconds(this.attack)) / totalDuration,\n\t\t\t\tdecay: (duration * this.toSeconds(this.decay)) / totalDuration,\n\t\t\t\trelease:\n\t\t\t\t\t(duration * this.toSeconds(this.release)) / totalDuration,\n\t\t\t\tcontext,\n\t\t\t})\n\t\t) as Envelope;\n\t\tclone._sig.toDestination();\n\t\tclone.triggerAttackRelease(\n\t\t\t(duration * (attackPortion + sustainTime)) / totalDuration,\n\t\t\t0\n\t\t);\n\t\tconst buffer = await context.render();\n\t\treturn buffer.getChannelData(0);\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._sig.dispose();\n\t\treturn this;\n\t}\n}\n\ninterface EnvelopeCurveObject {\n\tIn: number[];\n\tOut: number[];\n}\n\ntype EnvelopeDirection = keyof EnvelopeCurveObject;\n\ninterface EnvelopeCurveMap {\n\tlinear: \"linear\";\n\texponential: \"exponential\";\n\tbounce: EnvelopeCurveObject;\n\tcosine: EnvelopeCurveObject;\n\tsine: EnvelopeCurveObject;\n\tripple: EnvelopeCurveObject;\n\tstep: EnvelopeCurveObject;\n}\n\ntype EnvelopeCurveName = keyof EnvelopeCurveMap;\n\n/**\n * Generate some complex envelope curves.\n */\nconst EnvelopeCurves: EnvelopeCurveMap = (() => {\n\tconst curveLen = 128;\n\n\tlet i: number;\n\tlet k: number;\n\n\t// cosine curve\n\tconst cosineCurve: number[] = [];\n\tfor (i = 0; i < curveLen; i++) {\n\t\tcosineCurve[i] = Math.sin((i / (curveLen - 1)) * (Math.PI / 2));\n\t}\n\n\t// ripple curve\n\tconst rippleCurve: number[] = [];\n\tconst rippleCurveFreq = 6.4;\n\tfor (i = 0; i < curveLen - 1; i++) {\n\t\tk = i / (curveLen - 1);\n\t\tconst sineWave =\n\t\t\tMath.sin(k * (Math.PI * 2) * rippleCurveFreq - Math.PI / 2) + 1;\n\t\trippleCurve[i] = sineWave / 10 + k * 0.83;\n\t}\n\trippleCurve[curveLen - 1] = 1;\n\n\t// stairs curve\n\tconst stairsCurve: number[] = [];\n\tconst steps = 5;\n\tfor (i = 0; i < curveLen; i++) {\n\t\tstairsCurve[i] = Math.ceil((i / (curveLen - 1)) * steps) / steps;\n\t}\n\n\t// in-out easing curve\n\tconst sineCurve: number[] = [];\n\tfor (i = 0; i < curveLen; i++) {\n\t\tk = i / (curveLen - 1);\n\t\tsineCurve[i] = 0.5 * (1 - Math.cos(Math.PI * k));\n\t}\n\n\t// a bounce curve\n\tconst bounceCurve: number[] = [];\n\tfor (i = 0; i < curveLen; i++) {\n\t\tk = i / (curveLen - 1);\n\t\tconst freq = Math.pow(k, 3) * 4 + 0.2;\n\t\tconst val = Math.cos(freq * Math.PI * 2 * k);\n\t\tbounceCurve[i] = Math.abs(val * (1 - k));\n\t}\n\n\t/**\n\t * Invert a value curve to make it work for the release\n\t */\n\tfunction invertCurve(curve: number[]): number[] {\n\t\tconst out = new Array(curve.length);\n\t\tfor (let j = 0; j < curve.length; j++) {\n\t\t\tout[j] = 1 - curve[j];\n\t\t}\n\t\treturn out;\n\t}\n\n\t/**\n\t * reverse the curve\n\t */\n\tfunction reverseCurve(curve: number[]): number[] {\n\t\treturn curve.slice(0).reverse();\n\t}\n\n\t/**\n\t * attack and release curve arrays\n\t */\n\treturn {\n\t\tbounce: {\n\t\t\tIn: invertCurve(bounceCurve),\n\t\t\tOut: bounceCurve,\n\t\t},\n\t\tcosine: {\n\t\t\tIn: cosineCurve,\n\t\t\tOut: reverseCurve(cosineCurve),\n\t\t},\n\t\texponential: \"exponential\" as const,\n\t\tlinear: \"linear\" as const,\n\t\tripple: {\n\t\t\tIn: rippleCurve,\n\t\t\tOut: invertCurve(rippleCurve),\n\t\t},\n\t\tsine: {\n\t\t\tIn: sineCurve,\n\t\t\tOut: invertCurve(sineCurve),\n\t\t},\n\t\tstep: {\n\t\t\tIn: stairsCurve,\n\t\t\tOut: invertCurve(stairsCurve),\n\t\t},\n\t};\n})();\n"
  },
  {
    "path": "Tone/component/envelope/FrequencyEnvelope.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { connectFrom, connectTo } from \"../../../test/helper/Connect.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { Envelope } from \"./Envelope.js\";\nimport { FrequencyEnvelope } from \"./FrequencyEnvelope.js\";\n\ndescribe(\"FrequencyEnvelope\", () => {\n\tBasicTests(FrequencyEnvelope);\n\n\tcontext(\"FrequencyEnvelope\", () => {\n\t\tit(\"has an output connections\", () => {\n\t\t\tconst freqEnv = new FrequencyEnvelope();\n\t\t\tfreqEnv.connect(connectTo());\n\t\t\tconnectFrom().connect(freqEnv);\n\t\t\tfreqEnv.dispose();\n\t\t});\n\n\t\tit(\"extends Envelope\", () => {\n\t\t\tconst freqEnv = new FrequencyEnvelope();\n\t\t\texpect(freqEnv).to.be.instanceOf(Envelope);\n\t\t\tfreqEnv.dispose();\n\t\t});\n\n\t\tit(\"can get and set values an Objects\", () => {\n\t\t\tconst freqEnv = new FrequencyEnvelope();\n\t\t\tconst values = {\n\t\t\t\tattack: 0,\n\t\t\t\trelease: \"4n\",\n\t\t\t\tbaseFrequency: 20,\n\t\t\t\toctaves: 4,\n\t\t\t};\n\t\t\tfreqEnv.set(values);\n\t\t\texpect(freqEnv.get()).to.contain.keys(Object.keys(values));\n\t\t\texpect(freqEnv.baseFrequency).to.equal(20);\n\t\t\texpect(freqEnv.octaves).to.equal(4);\n\t\t\tfreqEnv.dispose();\n\t\t});\n\n\t\tit(\"can take parameters as both an object and as arguments\", () => {\n\t\t\tconst env0 = new FrequencyEnvelope({\n\t\t\t\tattack: 0,\n\t\t\t\tdecay: 0.5,\n\t\t\t\tsustain: 1,\n\t\t\t\texponent: 3,\n\t\t\t});\n\t\t\texpect(env0.attack).to.equal(0);\n\t\t\texpect(env0.decay).to.equal(0.5);\n\t\t\texpect(env0.sustain).to.equal(1);\n\t\t\texpect(env0.exponent).to.equal(3);\n\t\t\tenv0.dispose();\n\t\t\tconst env1 = new FrequencyEnvelope(0.1, 0.2, 0.3);\n\t\t\texpect(env1.attack).to.equal(0.1);\n\t\t\texpect(env1.decay).to.equal(0.2);\n\t\t\texpect(env1.sustain).to.equal(0.3);\n\t\t\tenv1.exponent = 2;\n\t\t\texpect(env1.exponent).to.equal(2);\n\t\t\tenv1.dispose();\n\t\t});\n\n\t\tit(\"can set a negative octave\", () => {\n\t\t\tconst freqEnv = new FrequencyEnvelope();\n\t\t\tfreqEnv.octaves = -2;\n\t\t\tfreqEnv.dispose();\n\t\t});\n\n\t\tit(\"goes to the scaled range\", async () => {\n\t\t\tconst e = {\n\t\t\t\tattack: 0.01,\n\t\t\t\tdecay: 0.4,\n\t\t\t\tsustain: 1,\n\t\t\t};\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst freqEnv = new FrequencyEnvelope(\n\t\t\t\t\te.attack,\n\t\t\t\t\te.decay,\n\t\t\t\t\te.sustain\n\t\t\t\t);\n\t\t\t\tfreqEnv.baseFrequency = 200;\n\t\t\t\tfreqEnv.octaves = 3;\n\t\t\t\tfreqEnv.attackCurve = \"exponential\";\n\t\t\t\tfreqEnv.toDestination();\n\t\t\t\tfreqEnv.triggerAttack(0);\n\t\t\t}, 0.3);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\tif (time < e.attack) {\n\t\t\t\t\texpect(sample).to.be.within(200, 1600);\n\t\t\t\t} else if (time < e.attack + e.decay) {\n\t\t\t\t\texpect(sample).to.be.closeTo(1600, 10);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/envelope/FrequencyEnvelope.ts",
    "content": "import { Frequency, Hertz, NormalRange, Time } from \"../../core/type/Units.js\";\nimport { assertRange } from \"../../core/util/Debug.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { Pow } from \"../../signal/Pow.js\";\nimport { Scale } from \"../../signal/Scale.js\";\nimport { Envelope, EnvelopeOptions } from \"./Envelope.js\";\n\nexport interface FrequencyEnvelopeOptions extends EnvelopeOptions {\n\tbaseFrequency: Frequency;\n\toctaves: number;\n\texponent: number;\n}\n/**\n * FrequencyEnvelope is an {@link Envelope} which ramps between {@link baseFrequency}\n * and {@link octaves}. It can also have an optional {@link exponent} to adjust the curve\n * which it ramps.\n * @example\n * const oscillator = new Tone.Oscillator().toDestination().start();\n * const freqEnv = new Tone.FrequencyEnvelope({\n * \tattack: 0.2,\n * \tbaseFrequency: \"C2\",\n * \toctaves: 4\n * });\n * freqEnv.connect(oscillator.frequency);\n * freqEnv.triggerAttack();\n * @category Component\n */\nexport class FrequencyEnvelope extends Envelope {\n\treadonly name: string = \"FrequencyEnvelope\";\n\n\t/**\n\t * Private reference to the base frequency as a number\n\t */\n\tprivate _baseFrequency: Hertz;\n\n\t/**\n\t * The number of octaves\n\t */\n\tprivate _octaves: number;\n\n\t/**\n\t * Internal scaler from 0-1 to the final output range\n\t */\n\tprivate _scale: Scale;\n\n\t/**\n\t * Apply a power curve to the output\n\t */\n\tprivate _exponent: Pow;\n\n\t/**\n\t * @param attack\tthe attack time in seconds\n\t * @param decay\t\tthe decay time in seconds\n\t * @param sustain \ta percentage (0-1) of the full amplitude\n\t * @param release\tthe release time in seconds\n\t */\n\tconstructor(\n\t\tattack?: Time,\n\t\tdecay?: Time,\n\t\tsustain?: NormalRange,\n\t\trelease?: Time\n\t);\n\tconstructor(options?: Partial<FrequencyEnvelopeOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tFrequencyEnvelope.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"attack\", \"decay\", \"sustain\", \"release\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._octaves = options.octaves;\n\t\tthis._baseFrequency = this.toFrequency(options.baseFrequency);\n\n\t\tthis._exponent = this.input = new Pow({\n\t\t\tcontext: this.context,\n\t\t\tvalue: options.exponent,\n\t\t});\n\t\tthis._scale = this.output = new Scale({\n\t\t\tcontext: this.context,\n\t\t\tmin: this._baseFrequency,\n\t\t\tmax: this._baseFrequency * Math.pow(2, this._octaves),\n\t\t});\n\t\tthis._sig.chain(this._exponent, this._scale);\n\t}\n\n\tstatic getDefaults(): FrequencyEnvelopeOptions {\n\t\treturn Object.assign(Envelope.getDefaults(), {\n\t\t\tbaseFrequency: 200,\n\t\t\texponent: 1,\n\t\t\toctaves: 4,\n\t\t});\n\t}\n\n\t/**\n\t * The envelope's minimum output value. This is the value which it\n\t * starts at.\n\t */\n\tget baseFrequency(): Frequency {\n\t\treturn this._baseFrequency;\n\t}\n\tset baseFrequency(min) {\n\t\tconst freq = this.toFrequency(min);\n\t\tassertRange(freq, 0);\n\t\tthis._baseFrequency = freq;\n\t\tthis._scale.min = this._baseFrequency;\n\t\t// update the max value when the min changes\n\t\tthis.octaves = this._octaves;\n\t}\n\n\t/**\n\t * The number of octaves above the baseFrequency that the\n\t * envelope will scale to.\n\t */\n\tget octaves(): number {\n\t\treturn this._octaves;\n\t}\n\tset octaves(octaves: number) {\n\t\tthis._octaves = octaves;\n\t\tthis._scale.max = this._baseFrequency * Math.pow(2, octaves);\n\t}\n\n\t/**\n\t * The envelope's exponent value.\n\t */\n\tget exponent(): number {\n\t\treturn this._exponent.value;\n\t}\n\tset exponent(exponent) {\n\t\tthis._exponent.value = exponent;\n\t}\n\n\t/**\n\t * Clean up\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._exponent.dispose();\n\t\tthis._scale.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/filter/BiquadFilter.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { Oscillator } from \"../../source/oscillator/Oscillator.js\";\nimport { BiquadFilter } from \"./BiquadFilter.js\";\n\ndescribe(\"BiquadFilter\", () => {\n\tBasicTests(BiquadFilter);\n\n\tcontext(\"BiquadFiltering\", () => {\n\t\tit(\"can be constructed with a arguments\", () => {\n\t\t\tconst filter = new BiquadFilter(200, \"highpass\");\n\t\t\texpect(filter.frequency.value).to.be.closeTo(200, 0.001);\n\t\t\texpect(filter.type).to.equal(\"highpass\");\n\t\t\tfilter.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an object\", () => {\n\t\t\tconst filter = new BiquadFilter({\n\t\t\t\tfrequency: 340,\n\t\t\t\ttype: \"bandpass\",\n\t\t\t});\n\t\t\texpect(filter.frequency.value).to.be.closeTo(340, 0.001);\n\t\t\texpect(filter.type).to.equal(\"bandpass\");\n\t\t\tfilter.dispose();\n\t\t});\n\n\t\tit(\"can set/get values as an Object\", () => {\n\t\t\tconst filter = new BiquadFilter();\n\t\t\tconst values = {\n\t\t\t\tQ: 2,\n\t\t\t\tfrequency: 440,\n\t\t\t\tgain: -6,\n\t\t\t\ttype: \"lowshelf\" as const,\n\t\t\t};\n\t\t\tfilter.set(values);\n\t\t\texpect(filter.get()).to.include.keys([\n\t\t\t\t\"type\",\n\t\t\t\t\"frequency\",\n\t\t\t\t\"Q\",\n\t\t\t\t\"gain\",\n\t\t\t]);\n\t\t\texpect(filter.type).to.equal(values.type);\n\t\t\texpect(filter.frequency.value).to.equal(values.frequency);\n\t\t\texpect(filter.Q.value).to.equal(values.Q);\n\t\t\texpect(filter.gain.value).to.be.closeTo(values.gain, 0.04);\n\t\t\tfilter.dispose();\n\t\t});\n\n\t\tit(\"can get the frequency response curve\", () => {\n\t\t\tconst filter = new BiquadFilter();\n\t\t\tconst curve = filter.getFrequencyResponse(32);\n\t\t\texpect(curve.length).to.equal(32);\n\t\t\texpect(curve[0]).be.closeTo(1, 0.01);\n\t\t\texpect(curve[5]).be.closeTo(0.5, 0.1);\n\t\t\texpect(curve[15]).be.closeTo(0, 0.01);\n\t\t\texpect(curve[31]).be.closeTo(0, 0.01);\n\t\t\tfilter.dispose();\n\t\t});\n\n\t\tit(\"passes the incoming signal through\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst filter = new BiquadFilter().toDestination();\n\t\t\t\tinput.connect(filter);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can set the basic filter types\", () => {\n\t\t\tconst filter = new BiquadFilter();\n\t\t\tconst types: BiquadFilterType[] = [\n\t\t\t\t\"lowpass\",\n\t\t\t\t\"highpass\",\n\t\t\t\t\"bandpass\",\n\t\t\t\t\"lowshelf\",\n\t\t\t\t\"highshelf\",\n\t\t\t\t\"notch\",\n\t\t\t\t\"allpass\",\n\t\t\t\t\"peaking\",\n\t\t\t];\n\t\t\tfor (const type of types) {\n\t\t\t\tfilter.type = type;\n\t\t\t\texpect(filter.type).to.equal(type);\n\t\t\t}\n\t\t\texpect(() => {\n\t\t\t\t// @ts-ignore\n\t\t\t\tfilter.type = \"nontype\";\n\t\t\t}).to.throw(Error);\n\t\t\tfilter.dispose();\n\t\t});\n\n\t\tit(\"attenuates the incoming signal\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst filter = new BiquadFilter(700, \"lowpass\").toDestination();\n\t\t\t\tfilter.Q.value = 0;\n\t\t\t\tconst osc = new Oscillator(880).connect(filter);\n\t\t\t\tosc.start(0);\n\t\t\t}, 0.2);\n\t\t\texpect(buffer.getRmsAtTime(0.05)).to.be.within(0.37, 0.53);\n\t\t\texpect(buffer.getRmsAtTime(0.1)).to.be.within(0.37, 0.53);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/filter/BiquadFilter.ts",
    "content": "import { Param } from \"../../core/context/Param.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { Cents, Frequency, GainFactor } from \"../../core/type/Units.js\";\nimport { assert } from \"../../core/util/Debug.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\n\nexport interface BiquadFilterOptions extends ToneAudioNodeOptions {\n\tfrequency: Frequency;\n\tdetune: Cents;\n\tQ: number;\n\ttype: BiquadFilterType;\n\tgain: GainFactor;\n}\n\n/**\n * Thin wrapper around the native Web Audio [BiquadFilterNode](https://webaudio.github.io/web-audio-api/#biquadfilternode).\n * BiquadFilter is similar to {@link Filter} but doesn't have the option to set the \"rolloff\" value.\n * @category Component\n */\nexport class BiquadFilter extends ToneAudioNode<BiquadFilterOptions> {\n\treadonly name: string = \"BiquadFilter\";\n\n\treadonly input: BiquadFilterNode;\n\treadonly output: BiquadFilterNode;\n\n\t/**\n\t * The frequency of the filter\n\t */\n\treadonly frequency: Param<\"frequency\">;\n\n\t/**\n\t * A detune value, in cents, for the frequency.\n\t */\n\treadonly detune: Param<\"cents\">;\n\n\t/**\n\t * The Q factor of the filter.\n\t * For lowpass and highpass filters the Q value is interpreted to be in dB.\n\t * For these filters the nominal range is [−𝑄𝑙𝑖𝑚,𝑄𝑙𝑖𝑚] where 𝑄𝑙𝑖𝑚 is the largest value for which 10𝑄/20 does not overflow. This is approximately 770.63678.\n\t * For the bandpass, notch, allpass, and peaking filters, this value is a linear value.\n\t * The value is related to the bandwidth of the filter and hence should be a positive value. The nominal range is\n\t * [0,3.4028235𝑒38], the upper limit being the most-positive-single-float.\n\t * This is not used for the lowshelf and highshelf filters.\n\t */\n\treadonly Q: Param<\"number\">;\n\n\t/**\n\t * The gain of the filter. Its value is in dB units. The gain is only used for lowshelf, highshelf, and peaking filters.\n\t */\n\treadonly gain: Param<\"decibels\">;\n\n\tprivate readonly _filter: BiquadFilterNode;\n\n\t/**\n\t * @param frequency The cutoff frequency of the filter.\n\t * @param type The type of filter.\n\t */\n\tconstructor(frequency?: Frequency, type?: BiquadFilterType);\n\tconstructor(options?: Partial<BiquadFilterOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tBiquadFilter.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"frequency\", \"type\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._filter = this.context.createBiquadFilter();\n\t\tthis.input = this.output = this._filter;\n\n\t\tthis.Q = new Param({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"number\",\n\t\t\tvalue: options.Q,\n\t\t\tparam: this._filter.Q,\n\t\t});\n\n\t\tthis.frequency = new Param({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"frequency\",\n\t\t\tvalue: options.frequency,\n\t\t\tparam: this._filter.frequency,\n\t\t});\n\n\t\tthis.detune = new Param({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"cents\",\n\t\t\tvalue: options.detune,\n\t\t\tparam: this._filter.detune,\n\t\t});\n\n\t\tthis.gain = new Param({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"decibels\",\n\t\t\tconvert: false,\n\t\t\tvalue: options.gain,\n\t\t\tparam: this._filter.gain,\n\t\t});\n\n\t\tthis.type = options.type;\n\t}\n\n\tstatic getDefaults(): BiquadFilterOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tQ: 1,\n\t\t\ttype: \"lowpass\" as const,\n\t\t\tfrequency: 350,\n\t\t\tdetune: 0,\n\t\t\tgain: 0,\n\t\t});\n\t}\n\n\t/**\n\t * The type of this BiquadFilterNode. For a complete list of types and their attributes, see the\n\t * [Web Audio API](https://webaudio.github.io/web-audio-api/#dom-biquadfiltertype-lowpass)\n\t */\n\tget type(): BiquadFilterType {\n\t\treturn this._filter.type;\n\t}\n\tset type(type) {\n\t\tconst types: BiquadFilterType[] = [\n\t\t\t\"lowpass\",\n\t\t\t\"highpass\",\n\t\t\t\"bandpass\",\n\t\t\t\"lowshelf\",\n\t\t\t\"highshelf\",\n\t\t\t\"notch\",\n\t\t\t\"allpass\",\n\t\t\t\"peaking\",\n\t\t];\n\t\tassert(types.indexOf(type) !== -1, `Invalid filter type: ${type}`);\n\t\tthis._filter.type = type;\n\t}\n\n\t/**\n\t * Get the frequency response curve. This curve represents how the filter\n\t * responses to frequencies between 20hz-20khz.\n\t * @param  len The number of values to return\n\t * @return The frequency response curve between 20-20kHz\n\t */\n\tgetFrequencyResponse(len = 128): Float32Array {\n\t\t// start with all 1s\n\t\tconst freqValues = new Float32Array(len);\n\t\tfor (let i = 0; i < len; i++) {\n\t\t\tconst norm = Math.pow(i / len, 2);\n\t\t\tconst freq = norm * (20000 - 20) + 20;\n\t\t\tfreqValues[i] = freq;\n\t\t}\n\t\tconst magValues = new Float32Array(len);\n\t\tconst phaseValues = new Float32Array(len);\n\t\t// clone the filter to remove any connections which may be changing the value\n\t\tconst filterClone = this.context.createBiquadFilter();\n\t\tfilterClone.type = this.type;\n\t\tfilterClone.Q.value = this.Q.value;\n\t\tfilterClone.frequency.value = this.frequency.value as number;\n\t\tfilterClone.gain.value = this.gain.value as number;\n\t\tfilterClone.getFrequencyResponse(freqValues, magValues, phaseValues);\n\t\treturn magValues;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._filter.disconnect();\n\t\tthis.Q.dispose();\n\t\tthis.frequency.dispose();\n\t\tthis.gain.dispose();\n\t\tthis.detune.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/filter/Convolver.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { ToneAudioBuffer } from \"../../core/context/ToneAudioBuffer.js\";\nimport { Convolver } from \"./Convolver.js\";\n\ndescribe(\"Convolver\", () => {\n\tBasicTests(Convolver);\n\n\tconst ir = new ToneAudioBuffer();\n\n\tconst testFile = \"./test/audio/sineStereo.wav\";\n\n\tbefore(() => {\n\t\treturn ir.load(testFile);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst convolver = new Convolver({\n\t\t\t\tnormalize: false,\n\t\t\t\turl: testFile,\n\t\t\t});\n\t\t\texpect(convolver.normalize).to.be.false;\n\t\t\tconvolver.dispose();\n\t\t});\n\n\t\tit(\"can get set normalize\", () => {\n\t\t\tconst convolver = new Convolver();\n\t\t\tconvolver.normalize = false;\n\t\t\texpect(convolver.normalize).to.be.false;\n\t\t\tconvolver.dispose();\n\t\t});\n\n\t\tit(\"invokes the onload function when loaded\", (done) => {\n\t\t\tconst convolver = new Convolver({\n\t\t\t\turl: testFile,\n\t\t\t\tonload(): void {\n\t\t\t\t\tconvolver.dispose();\n\t\t\t\t\tdone();\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\n\t\tit(\"load returns a Promise\", async () => {\n\t\t\tconst convolver = new Convolver();\n\t\t\tawait convolver.load(testFile);\n\t\t\tconvolver.dispose();\n\t\t});\n\n\t\tit(\"load invokes the second callback\", async () => {\n\t\t\tconst convolver = new Convolver();\n\t\t\tawait convolver.load(testFile);\n\t\t\tconvolver.dispose();\n\t\t});\n\n\t\tit(\"can assign the buffer twice\", () => {\n\t\t\tconst convolver = new Convolver(ir);\n\t\t\tconvolver.buffer = ir;\n\t\t\tconvolver.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with a buffer\", () => {\n\t\t\tconst convolver = new Convolver(ir);\n\t\t\texpect((convolver.buffer as ToneAudioBuffer).get()).to.equal(\n\t\t\t\tir.get()\n\t\t\t);\n\t\t\tconvolver.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with loaded buffer\", (done) => {\n\t\t\tconst buffer = new ToneAudioBuffer({\n\t\t\t\turl: testFile,\n\t\t\t\tonload(): void {\n\t\t\t\t\tconst convolver = new Convolver(buffer);\n\t\t\t\t\texpect(convolver.buffer).is.not.null;\n\t\t\t\t\tbuffer.dispose();\n\t\t\t\t\tconvolver.dispose();\n\t\t\t\t\tdone();\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\n\t\tit(\"can be constructed with unloaded buffer\", (done) => {\n\t\t\tconst convolver = new Convolver({\n\t\t\t\turl: new ToneAudioBuffer({\n\t\t\t\t\turl: testFile,\n\t\t\t\t}),\n\t\t\t\tonload(): void {\n\t\t\t\t\texpect(convolver.buffer).is.not.null;\n\t\t\t\t\tconvolver.dispose();\n\t\t\t\t\tdone();\n\t\t\t\t},\n\t\t\t});\n\t\t\t// is null before then\n\t\t\texpect(convolver.buffer).to.be.null;\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/filter/Convolver.ts",
    "content": "import { Gain } from \"../../core/context/Gain.js\";\nimport { ToneAudioBuffer } from \"../../core/context/ToneAudioBuffer.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { noOp } from \"../../core/util/Interface.js\";\n\nexport interface ConvolverOptions extends ToneAudioNodeOptions {\n\tonload: () => void;\n\tnormalize: boolean;\n\turl?: string | AudioBuffer | ToneAudioBuffer;\n}\n\n/**\n * Convolver is a wrapper around the Native Web Audio\n * [ConvolverNode](http://webaudio.github.io/web-audio-api/#the-convolvernode-interface).\n * Convolution is useful for reverb and filter emulation. Read more about convolution reverb on\n * [Wikipedia](https://en.wikipedia.org/wiki/Convolution_reverb).\n *\n * @example\n * // initializing the convolver with an impulse response\n * const convolver = new Tone.Convolver(\"./path/to/ir.wav\").toDestination();\n * @category Component\n */\nexport class Convolver extends ToneAudioNode<ConvolverOptions> {\n\treadonly name: string = \"Convolver\";\n\n\t/**\n\t * The native ConvolverNode\n\t */\n\tprivate _convolver: ConvolverNode = this.context.createConvolver();\n\n\t/**\n\t * The Buffer belonging to the convolver\n\t */\n\tprivate _buffer: ToneAudioBuffer;\n\n\treadonly input: Gain;\n\treadonly output: Gain;\n\n\t/**\n\t * @param url The URL of the impulse response or the ToneAudioBuffer containing the impulse response.\n\t * @param onload The callback to invoke when the url is loaded.\n\t */\n\tconstructor(\n\t\turl?: string | AudioBuffer | ToneAudioBuffer,\n\t\tonload?: () => void\n\t);\n\tconstructor(options?: Partial<ConvolverOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tConvolver.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"url\", \"onload\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._buffer = new ToneAudioBuffer(options.url, (buffer) => {\n\t\t\tthis.buffer = buffer;\n\t\t\toptions.onload();\n\t\t});\n\n\t\tthis.input = new Gain({ context: this.context });\n\t\tthis.output = new Gain({ context: this.context });\n\n\t\t// set if it's already loaded, set it immediately\n\t\tif (this._buffer.loaded) {\n\t\t\tthis.buffer = this._buffer;\n\t\t}\n\n\t\t// initially set normalization\n\t\tthis.normalize = options.normalize;\n\n\t\t// connect it up\n\t\tthis.input.chain(this._convolver, this.output);\n\t}\n\n\tstatic getDefaults(): ConvolverOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tnormalize: true,\n\t\t\tonload: noOp,\n\t\t});\n\t}\n\n\t/**\n\t * Load an impulse response url as an audio buffer.\n\t * Decodes the audio asynchronously and invokes\n\t * the callback once the audio buffer loads.\n\t * @param url The url of the buffer to load. filetype support depends on the browser.\n\t */\n\tasync load(url: string): Promise<void> {\n\t\tthis.buffer = await this._buffer.load(url);\n\t}\n\n\t/**\n\t * The convolver's buffer\n\t */\n\tget buffer(): ToneAudioBuffer | null {\n\t\tif (this._buffer.length) {\n\t\t\treturn this._buffer;\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\tset buffer(buffer) {\n\t\tif (buffer) {\n\t\t\tthis._buffer.set(buffer);\n\t\t}\n\t\t// if it's already got a buffer, create a new one\n\t\tif (this._convolver.buffer) {\n\t\t\t// disconnect the old one\n\t\t\tthis.input.disconnect();\n\t\t\tthis._convolver.disconnect();\n\t\t\t// create and connect a new one\n\t\t\tthis._convolver = this.context.createConvolver();\n\t\t\tthis.input.chain(this._convolver, this.output);\n\t\t}\n\t\tconst buff = this._buffer.get();\n\t\tthis._convolver.buffer = buff ? buff : null;\n\t}\n\n\t/**\n\t * The normalize property of the ConvolverNode interface is a boolean that\n\t * controls whether the impulse response from the buffer will be scaled by\n\t * an equal-power normalization when the buffer attribute is set, or not.\n\t */\n\tget normalize(): boolean {\n\t\treturn this._convolver.normalize;\n\t}\n\tset normalize(norm) {\n\t\tthis._convolver.normalize = norm;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._buffer.dispose();\n\t\tthis._convolver.disconnect();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/filter/EQ3.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { EQ3 } from \"./EQ3.js\";\n\ndescribe(\"EQ3\", () => {\n\tBasicTests(EQ3);\n\n\tcontext(\"EQing\", () => {\n\t\tit(\"can be constructed with an object\", () => {\n\t\t\tconst eq3 = new EQ3({\n\t\t\t\thigh: -10,\n\t\t\t\thighFrequency: 2700,\n\t\t\t\tlow: -8,\n\t\t\t\tlowFrequency: 500,\n\t\t\t\tmid: -9,\n\t\t\t});\n\t\t\texpect(eq3.low.value).to.be.closeTo(-8, 0.1);\n\t\t\texpect(eq3.mid.value).to.be.closeTo(-9, 0.1);\n\t\t\texpect(eq3.high.value).to.be.closeTo(-10, 0.1);\n\t\t\texpect(eq3.lowFrequency.value).to.be.closeTo(500, 0.01);\n\t\t\texpect(eq3.highFrequency.value).to.be.closeTo(2700, 0.01);\n\t\t\teq3.dispose();\n\t\t});\n\n\t\tit(\"can be get and set through object\", () => {\n\t\t\tconst eq3 = new EQ3();\n\t\t\teq3.set({\n\t\t\t\thigh: -4,\n\t\t\t\tlowFrequency: 250,\n\t\t\t});\n\t\t\texpect(eq3.get().high).to.be.closeTo(-4, 0.1);\n\t\t\texpect(eq3.get().lowFrequency).to.be.closeTo(250, 0.01);\n\t\t\teq3.dispose();\n\t\t});\n\n\t\tit(\"passes the incoming signal through\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst eq3 = new EQ3({\n\t\t\t\t\thigh: 12,\n\t\t\t\t\tlow: -20,\n\t\t\t\t}).toDestination();\n\t\t\t\tinput.connect(eq3);\n\t\t\t});\n\t\t});\n\n\t\tit.skip(\"passes the incoming stereo signal through\", () => {\n\t\t\t// return PassAudioStereo(function(input){\n\t\t\t// \tvar eq3 = new EQ3({\n\t\t\t// \t\t\"mid\" : -2,\n\t\t\t// \t\t\"high\" : 2\n\t\t\t// \t}).toDestination();\n\t\t\t// \tinput.connect(eq3);\n\t\t\t// });\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/filter/EQ3.ts",
    "content": "import { Gain } from \"../../core/context/Gain.js\";\nimport { Param } from \"../../core/context/Param.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { Decibels, Frequency } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly, writable } from \"../../core/util/Interface.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { MultibandSplit } from \"../channel/MultibandSplit.js\";\n\ninterface EQ3Options extends ToneAudioNodeOptions {\n\tlow: Decibels;\n\tmid: Decibels;\n\thigh: Decibels;\n\tlowFrequency: Frequency;\n\thighFrequency: Frequency;\n}\n\n/**\n * EQ3 provides 3 equalizer bins: Low/Mid/High.\n * @category Component\n */\nexport class EQ3 extends ToneAudioNode<EQ3Options> {\n\treadonly name: string = \"EQ3\";\n\n\t/**\n\t * the input\n\t */\n\treadonly input: MultibandSplit;\n\n\t/**\n\t * the output\n\t */\n\treadonly output = new Gain({ context: this.context });\n\n\t/**\n\t * Splits the input into three outputs\n\t */\n\tprivate _multibandSplit: MultibandSplit;\n\n\t/**\n\t * The gain for the lower signals\n\t */\n\tprivate _lowGain: Gain<\"decibels\">;\n\n\t/**\n\t * The gain for the mid signals\n\t */\n\tprivate _midGain: Gain<\"decibels\">;\n\n\t/**\n\t * The gain for the high signals\n\t */\n\tprivate _highGain: Gain<\"decibels\">;\n\n\t/**\n\t * The gain in decibels of the low part\n\t */\n\treadonly low: Param<\"decibels\">;\n\n\t/**\n\t * The gain in decibels of the mid part\n\t */\n\treadonly mid: Param<\"decibels\">;\n\n\t/**\n\t * The gain in decibels of the high part\n\t */\n\treadonly high: Param<\"decibels\">;\n\n\t/**\n\t * The Q value for all of the filters.\n\t */\n\treadonly Q: Signal<\"positive\">;\n\n\t/**\n\t * The low/mid crossover frequency.\n\t */\n\treadonly lowFrequency: Signal<\"frequency\">;\n\n\t/**\n\t * The mid/high crossover frequency.\n\t */\n\treadonly highFrequency: Signal<\"frequency\">;\n\n\tprotected _internalChannels: ToneAudioNode[] = [];\n\n\tconstructor(lowLevel?: Decibels, midLevel?: Decibels, highLevel?: Decibels);\n\tconstructor(options: Partial<EQ3Options>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(EQ3.getDefaults(), arguments, [\n\t\t\t\"low\",\n\t\t\t\"mid\",\n\t\t\t\"high\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis.input = this._multibandSplit = new MultibandSplit({\n\t\t\tcontext: this.context,\n\t\t\thighFrequency: options.highFrequency,\n\t\t\tlowFrequency: options.lowFrequency,\n\t\t});\n\n\t\tthis._lowGain = new Gain({\n\t\t\tcontext: this.context,\n\t\t\tgain: options.low,\n\t\t\tunits: \"decibels\",\n\t\t});\n\n\t\tthis._midGain = new Gain({\n\t\t\tcontext: this.context,\n\t\t\tgain: options.mid,\n\t\t\tunits: \"decibels\",\n\t\t});\n\n\t\tthis._highGain = new Gain({\n\t\t\tcontext: this.context,\n\t\t\tgain: options.high,\n\t\t\tunits: \"decibels\",\n\t\t});\n\n\t\tthis.low = this._lowGain.gain;\n\t\tthis.mid = this._midGain.gain;\n\t\tthis.high = this._highGain.gain;\n\t\tthis.Q = this._multibandSplit.Q;\n\t\tthis.lowFrequency = this._multibandSplit.lowFrequency;\n\t\tthis.highFrequency = this._multibandSplit.highFrequency;\n\n\t\t// the frequency bands\n\t\tthis._multibandSplit.low.chain(this._lowGain, this.output);\n\t\tthis._multibandSplit.mid.chain(this._midGain, this.output);\n\t\tthis._multibandSplit.high.chain(this._highGain, this.output);\n\n\t\treadOnly(this, [\"low\", \"mid\", \"high\", \"lowFrequency\", \"highFrequency\"]);\n\t\tthis._internalChannels = [this._multibandSplit];\n\t}\n\n\tstatic getDefaults(): EQ3Options {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\thigh: 0,\n\t\t\thighFrequency: 2500,\n\t\t\tlow: 0,\n\t\t\tlowFrequency: 400,\n\t\t\tmid: 0,\n\t\t});\n\t}\n\n\t/**\n\t * Clean up.\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\twritable(this, [\"low\", \"mid\", \"high\", \"lowFrequency\", \"highFrequency\"]);\n\t\tthis._multibandSplit.dispose();\n\t\tthis.lowFrequency.dispose();\n\t\tthis.highFrequency.dispose();\n\t\tthis._lowGain.dispose();\n\t\tthis._midGain.dispose();\n\t\tthis._highGain.dispose();\n\t\tthis.low.dispose();\n\t\tthis.mid.dispose();\n\t\tthis.high.dispose();\n\t\tthis.Q.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/filter/FeedbackCombFilter.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { BitCrusher } from \"../../effect/BitCrusher.js\";\nimport { Signal } from \"../../signal/index.js\";\nimport { FeedbackCombFilter } from \"./FeedbackCombFilter.js\";\n\ndescribe(\"FeedbackCombFilter\", () => {\n\tBasicTests(FeedbackCombFilter);\n\n\tcontext(\"Comb Filtering\", () => {\n\t\tit(\"can be constructed with an object\", () => {\n\t\t\tconst fbcf = new FeedbackCombFilter({\n\t\t\t\tdelayTime: 0.2,\n\t\t\t\tresonance: 0.3,\n\t\t\t});\n\t\t\texpect(fbcf.delayTime.value).to.be.closeTo(0.2, 0.001);\n\t\t\texpect(fbcf.resonance.value).to.be.closeTo(0.3, 0.001);\n\t\t\tfbcf.dispose();\n\t\t});\n\n\t\tit(\"can be get and set through object\", () => {\n\t\t\tconst fbcf = new FeedbackCombFilter();\n\t\t\tfbcf.set({\n\t\t\t\tdelayTime: 0.2,\n\t\t\t\tresonance: 0.3,\n\t\t\t});\n\t\t\tconst values = fbcf.get();\n\t\t\texpect(values.delayTime).to.be.closeTo(0.2, 0.001);\n\t\t\texpect(values.resonance).to.be.closeTo(0.3, 0.001);\n\t\t\tfbcf.dispose();\n\t\t});\n\n\t\tit(\"passes the incoming signal through\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst fbcf = new FeedbackCombFilter({\n\t\t\t\t\tdelayTime: 0.0,\n\t\t\t\t\tresonance: 0,\n\t\t\t\t}).toDestination();\n\t\t\t\tinput.connect(fbcf);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can delay by the delayTime\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst fbcf = new FeedbackCombFilter({\n\t\t\t\t\tdelayTime: 0.1,\n\t\t\t\t\tresonance: 0,\n\t\t\t\t}).toDestination();\n\t\t\t\tconst sig = new Signal(0).connect(fbcf);\n\t\t\t\tsig.setValueAtTime(1, 0);\n\t\t\t}, 0.2);\n\t\t\texpect(buffer.getValueAtTime(0)).to.equal(0);\n\t\t\texpect(buffer.getValueAtTime(0.999)).to.equal(0);\n\t\t\texpect(buffer.getValueAtTime(0.101)).to.equal(1);\n\t\t\texpect(buffer.getValueAtTime(0.15)).to.equal(1);\n\t\t});\n\n\t\tit(\"can delay with feedback\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst fbcf = new FeedbackCombFilter({\n\t\t\t\t\tdelayTime: 0.1,\n\t\t\t\t\tresonance: 0.5,\n\t\t\t\t}).toDestination();\n\t\t\t\tconst sig = new Signal(0).connect(fbcf);\n\t\t\t\tsig.setValueAtTime(1, 0);\n\t\t\t\tsig.setValueAtTime(0, 0.1);\n\t\t\t}, 0.4);\n\t\t\texpect(buffer.getValueAtTime(0)).to.equal(0);\n\t\t\texpect(buffer.getValueAtTime(0.101)).to.equal(1);\n\t\t\texpect(buffer.getValueAtTime(0.201)).to.equal(0.5);\n\t\t\texpect(buffer.getValueAtTime(0.301)).to.equal(0.25);\n\t\t});\n\t});\n\n\tit(\"should be usable with the BitCrusher\", (done) => {\n\t\tnew FeedbackCombFilter();\n\t\tnew BitCrusher(4);\n\n\t\tconst handle = setTimeout(() => {\n\t\t\twindow.onunhandledrejection = null;\n\t\t\tdone();\n\t\t}, 100);\n\n\t\twindow.onunhandledrejection = (event) => {\n\t\t\tdone(event.reason);\n\t\t\tclearTimeout(handle);\n\t\t};\n\t});\n});\n"
  },
  {
    "path": "Tone/component/filter/FeedbackCombFilter.ts",
    "content": "import { Gain } from \"../../core/context/Gain.js\";\nimport { Param } from \"../../core/context/Param.js\";\nimport {\n\tconnectSeries,\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { NormalRange, Time } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly, RecursivePartial } from \"../../core/util/Interface.js\";\nimport { ToneAudioWorklet } from \"../../core/worklet/ToneAudioWorklet.js\";\nimport { workletName } from \"./FeedbackCombFilter.worklet.js\";\n\nexport interface FeedbackCombFilterOptions extends ToneAudioNodeOptions {\n\tdelayTime: Time;\n\tresonance: NormalRange;\n}\n\n/**\n * Comb filters are basic building blocks for physical modeling. Read more\n * about comb filters on [CCRMA's website](https://ccrma.stanford.edu/~jos/pasp/Feedback_Comb_Filters.html).\n *\n * This comb filter is implemented with the AudioWorkletNode which allows it to have feedback delays less than the\n * Web Audio processing block of 128 samples. There is a polyfill for browsers that don't yet support the\n * AudioWorkletNode, but it will add some latency and have slower performance than the AudioWorkletNode.\n * @category Component\n */\nexport class FeedbackCombFilter extends ToneAudioWorklet<FeedbackCombFilterOptions> {\n\treadonly name = \"FeedbackCombFilter\";\n\n\t/**\n\t * The amount of delay of the comb filter.\n\t */\n\treadonly delayTime: Param<\"time\">;\n\n\t/**\n\t * The amount of feedback of the delayed signal.\n\t */\n\treadonly resonance: Param<\"normalRange\">;\n\n\treadonly input: Gain;\n\treadonly output: Gain;\n\n\t/**\n\t * @param delayTime The delay time of the filter.\n\t * @param resonance The amount of feedback the filter has.\n\t */\n\tconstructor(delayTime?: Time, resonance?: NormalRange);\n\tconstructor(options?: RecursivePartial<FeedbackCombFilterOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tFeedbackCombFilter.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"delayTime\", \"resonance\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.input = new Gain({ context: this.context });\n\t\tthis.output = new Gain({ context: this.context });\n\n\t\tthis.delayTime = new Param<\"time\">({\n\t\t\tcontext: this.context,\n\t\t\tvalue: options.delayTime,\n\t\t\tunits: \"time\",\n\t\t\tminValue: 0,\n\t\t\tmaxValue: 1,\n\t\t\tparam: this._dummyParam,\n\t\t\tswappable: true,\n\t\t});\n\n\t\tthis.resonance = new Param<\"normalRange\">({\n\t\t\tcontext: this.context,\n\t\t\tvalue: options.resonance,\n\t\t\tunits: \"normalRange\",\n\t\t\tparam: this._dummyParam,\n\t\t\tswappable: true,\n\t\t});\n\n\t\treadOnly(this, [\"resonance\", \"delayTime\"]);\n\t}\n\n\tprotected _audioWorkletName(): string {\n\t\treturn workletName;\n\t}\n\n\t/**\n\t * The default parameters\n\t */\n\tstatic getDefaults(): FeedbackCombFilterOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tdelayTime: 0.1,\n\t\t\tresonance: 0.5,\n\t\t});\n\t}\n\n\tonReady(node: AudioWorkletNode) {\n\t\tconnectSeries(this.input, node, this.output);\n\t\tconst delayTime = node.parameters.get(\"delayTime\") as AudioParam;\n\t\tthis.delayTime.setParam(delayTime);\n\t\tconst feedback = node.parameters.get(\"feedback\") as AudioParam;\n\t\tthis.resonance.setParam(feedback);\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.input.dispose();\n\t\tthis.output.dispose();\n\t\tthis.delayTime.dispose();\n\t\tthis.resonance.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/filter/FeedbackCombFilter.worklet.ts",
    "content": "import \"../../core/worklet/SingleIOProcessor.worklet.js\";\nimport \"../../core/worklet/DelayLine.worklet.js\";\n\nimport { registerProcessor } from \"../../core/worklet/WorkletGlobalScope.js\";\n\nexport const workletName = \"feedback-comb-filter\";\n\nconst feedbackCombFilter = /* javascript */ `\n\tclass FeedbackCombFilterWorklet extends SingleIOProcessor {\n\n\t\tconstructor(options) {\n\t\t\tsuper(options);\n\t\t\tthis.delayLine = new DelayLine(this.sampleRate, options.channelCount || 2);\n\t\t}\n\n\t\tstatic get parameterDescriptors() {\n\t\t\treturn [{\n\t\t\t\tname: \"delayTime\",\n\t\t\t\tdefaultValue: 0.1,\n\t\t\t\tminValue: 0,\n\t\t\t\tmaxValue: 1,\n\t\t\t\tautomationRate: \"k-rate\"\n\t\t\t}, {\n\t\t\t\tname: \"feedback\",\n\t\t\t\tdefaultValue: 0.5,\n\t\t\t\tminValue: 0,\n\t\t\t\tmaxValue: 0.9999,\n\t\t\t\tautomationRate: \"k-rate\"\n\t\t\t}];\n\t\t}\n\n\t\tgenerate(input, channel, parameters) {\n\t\t\tconst delayedSample = this.delayLine.get(channel, parameters.delayTime * this.sampleRate);\n\t\t\tthis.delayLine.push(channel, input + delayedSample * parameters.feedback);\n\t\t\treturn delayedSample;\n\t\t}\n\t}\n`;\n\nregisterProcessor(workletName, feedbackCombFilter);\n"
  },
  {
    "path": "Tone/component/filter/Filter.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { Oscillator } from \"../../source/oscillator/Oscillator.js\";\nimport { Filter, FilterRollOff } from \"./Filter.js\";\n\ndescribe(\"Filter\", () => {\n\tBasicTests(Filter);\n\n\tcontext(\"Filtering\", () => {\n\t\tit(\"can be constructed with a arguments\", () => {\n\t\t\tconst filter = new Filter(200, \"highpass\");\n\t\t\texpect(filter.frequency.value).to.be.closeTo(200, 0.001);\n\t\t\texpect(filter.type).to.equal(\"highpass\");\n\t\t\tfilter.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an object\", () => {\n\t\t\tconst filter = new Filter({\n\t\t\t\tfrequency: 340,\n\t\t\t\ttype: \"bandpass\",\n\t\t\t});\n\t\t\texpect(filter.frequency.value).to.be.closeTo(340, 0.001);\n\t\t\texpect(filter.type).to.equal(\"bandpass\");\n\t\t\tfilter.dispose();\n\t\t});\n\n\t\tit(\"can set/get values as an Object\", () => {\n\t\t\tconst filter = new Filter();\n\t\t\tconst values = {\n\t\t\t\tQ: 2,\n\t\t\t\tfrequency: 440,\n\t\t\t\tgain: -6,\n\t\t\t\trolloff: -24 as FilterRollOff,\n\t\t\t\ttype: \"highpass\" as BiquadFilterType,\n\t\t\t};\n\t\t\tfilter.set(values);\n\t\t\texpect(filter.get()).to.include.keys([\n\t\t\t\t\"type\",\n\t\t\t\t\"frequency\",\n\t\t\t\t\"rolloff\",\n\t\t\t\t\"Q\",\n\t\t\t\t\"gain\",\n\t\t\t]);\n\t\t\texpect(filter.type).to.equal(values.type);\n\t\t\texpect(filter.frequency.value).to.equal(values.frequency);\n\t\t\texpect(filter.rolloff).to.equal(values.rolloff);\n\t\t\texpect(filter.Q.value).to.equal(values.Q);\n\t\t\texpect(filter.gain.value).to.be.closeTo(values.gain, 0.04);\n\t\t\tfilter.dispose();\n\t\t});\n\n\t\tit(\"can get the frequency response curve\", () => {\n\t\t\tconst filter = new Filter();\n\t\t\tconst curve = filter.getFrequencyResponse(32);\n\t\t\texpect(curve.length).to.equal(32);\n\t\t\texpect(curve[0]).be.closeTo(1, 0.01);\n\t\t\texpect(curve[5]).be.closeTo(0.5, 0.1);\n\t\t\texpect(curve[15]).be.closeTo(0, 0.01);\n\t\t\texpect(curve[31]).be.closeTo(0, 0.01);\n\t\t\tfilter.dispose();\n\t\t});\n\n\t\tit(\"passes the incoming signal through\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst filter = new Filter().toDestination();\n\t\t\t\tinput.connect(filter);\n\t\t\t});\n\t\t});\n\n\t\tit(\"only accepts filter values -12, -24, -48 and -96\", () => {\n\t\t\tconst filter = new Filter();\n\t\t\tfilter.rolloff = -12;\n\t\t\texpect(filter.rolloff).to.equal(-12);\n\t\t\t// @ts-ignore\n\t\t\tfilter.rolloff = \"-24\";\n\t\t\texpect(filter.rolloff).to.equal(-24);\n\t\t\tfilter.rolloff = -48;\n\t\t\texpect(filter.rolloff).to.equal(-48);\n\t\t\tfilter.rolloff = -96;\n\t\t\texpect(filter.rolloff).to.equal(-96);\n\t\t\texpect(() => {\n\t\t\t\t// @ts-ignore\n\t\t\t\tfilter.rolloff = -95;\n\t\t\t}).to.throw(Error);\n\t\t\tfilter.dispose();\n\t\t});\n\n\t\tit(\"can set the basic filter types\", () => {\n\t\t\tconst filter = new Filter();\n\t\t\tconst types: BiquadFilterType[] = [\n\t\t\t\t\"lowpass\",\n\t\t\t\t\"highpass\",\n\t\t\t\t\"bandpass\",\n\t\t\t\t\"lowshelf\",\n\t\t\t\t\"highshelf\",\n\t\t\t\t\"notch\",\n\t\t\t\t\"allpass\",\n\t\t\t\t\"peaking\",\n\t\t\t];\n\t\t\tfor (const type of types) {\n\t\t\t\tfilter.type = type;\n\t\t\t\texpect(filter.type).to.equal(type);\n\t\t\t}\n\t\t\texpect(() => {\n\t\t\t\t// @ts-ignore\n\t\t\t\tfilter.type = \"nontype\";\n\t\t\t}).to.throw(Error);\n\t\t\tfilter.dispose();\n\t\t});\n\n\t\tit(\"attenuates the incoming signal\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst filter = new Filter(700, \"lowpass\").toDestination();\n\t\t\t\tfilter.Q.value = 0;\n\t\t\t\tconst osc = new Oscillator(880).connect(filter);\n\t\t\t\tosc.start(0);\n\t\t\t}, 0.2);\n\t\t\texpect(buffer.getRmsAtTime(0.05)).to.be.within(0.37, 0.53);\n\t\t\texpect(buffer.getRmsAtTime(0.1)).to.be.within(0.37, 0.53);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/filter/Filter.ts",
    "content": "import { Gain } from \"../../core/context/Gain.js\";\nimport {\n\tconnectSeries,\n\tToneAudioNode,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { Frequency } from \"../../core/type/Units.js\";\nimport { assert } from \"../../core/util/Debug.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly, writable } from \"../../core/util/Interface.js\";\nimport { isNumber } from \"../../core/util/TypeCheck.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { BiquadFilter, BiquadFilterOptions } from \"./BiquadFilter.js\";\n\nexport type FilterRollOff = -12 | -24 | -48 | -96;\n\nexport type FilterOptions = BiquadFilterOptions & {\n\trolloff: FilterRollOff;\n};\n\n/**\n * Tone.Filter is a filter which allows for all of the same native methods\n * as the [BiquadFilterNode](http://webaudio.github.io/web-audio-api/#the-biquadfilternode-interface).\n * Tone.Filter has the added ability to set the filter rolloff at -12\n * (default), -24 and -48.\n * @example\n * const filter = new Tone.Filter(1500, \"highpass\").toDestination();\n * filter.frequency.rampTo(20000, 10);\n * const noise = new Tone.Noise().connect(filter).start();\n * @category Component\n */\nexport class Filter extends ToneAudioNode<FilterOptions> {\n\treadonly name: string = \"Filter\";\n\n\treadonly input = new Gain({ context: this.context });\n\treadonly output = new Gain({ context: this.context });\n\tprivate _filters: BiquadFilter[] = [];\n\n\t/**\n\t * the rolloff value of the filter\n\t */\n\tprivate _rolloff!: FilterRollOff;\n\tprivate _type: BiquadFilterType;\n\n\t/**\n\t * The Q or Quality of the filter\n\t */\n\treadonly Q: Signal<\"positive\">;\n\n\t/**\n\t * The cutoff frequency of the filter.\n\t */\n\treadonly frequency: Signal<\"frequency\">;\n\n\t/**\n\t * The detune parameter\n\t */\n\treadonly detune: Signal<\"cents\">;\n\n\t/**\n\t * The gain of the filter, only used in certain filter types\n\t */\n\treadonly gain: Signal<\"decibels\">;\n\n\t/**\n\t * @param frequency The cutoff frequency of the filter.\n\t * @param type The type of filter.\n\t * @param rolloff The drop in decibels per octave after the cutoff frequency\n\t */\n\tconstructor(\n\t\tfrequency?: Frequency,\n\t\ttype?: BiquadFilterType,\n\t\trolloff?: FilterRollOff\n\t);\n\tconstructor(options?: Partial<FilterOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Filter.getDefaults(), arguments, [\n\t\t\t\"frequency\",\n\t\t\t\"type\",\n\t\t\t\"rolloff\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis._filters = [];\n\n\t\tthis.Q = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"positive\",\n\t\t\tvalue: options.Q,\n\t\t});\n\t\tthis.frequency = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"frequency\",\n\t\t\tvalue: options.frequency,\n\t\t});\n\t\tthis.detune = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"cents\",\n\t\t\tvalue: options.detune,\n\t\t});\n\t\tthis.gain = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"decibels\",\n\t\t\tconvert: false,\n\t\t\tvalue: options.gain,\n\t\t});\n\t\tthis._type = options.type;\n\t\tthis.rolloff = options.rolloff;\n\t\treadOnly(this, [\"detune\", \"frequency\", \"gain\", \"Q\"]);\n\t}\n\n\tstatic getDefaults(): FilterOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tQ: 1,\n\t\t\tdetune: 0,\n\t\t\tfrequency: 350,\n\t\t\tgain: 0,\n\t\t\trolloff: -12 as FilterRollOff,\n\t\t\ttype: \"lowpass\" as BiquadFilterType,\n\t\t});\n\t}\n\n\t/**\n\t * The type of the filter. Types: \"lowpass\", \"highpass\",\n\t * \"bandpass\", \"lowshelf\", \"highshelf\", \"notch\", \"allpass\", or \"peaking\".\n\t */\n\tget type(): BiquadFilterType {\n\t\treturn this._type;\n\t}\n\tset type(type: BiquadFilterType) {\n\t\tconst types: BiquadFilterType[] = [\n\t\t\t\"lowpass\",\n\t\t\t\"highpass\",\n\t\t\t\"bandpass\",\n\t\t\t\"lowshelf\",\n\t\t\t\"highshelf\",\n\t\t\t\"notch\",\n\t\t\t\"allpass\",\n\t\t\t\"peaking\",\n\t\t];\n\t\tassert(types.indexOf(type) !== -1, `Invalid filter type: ${type}`);\n\t\tthis._type = type;\n\t\tthis._filters.forEach((filter) => (filter.type = type));\n\t}\n\n\t/**\n\t * The rolloff of the filter which is the drop in db\n\t * per octave. Implemented internally by cascading filters.\n\t * Only accepts the values -12, -24, -48 and -96.\n\t */\n\tget rolloff(): FilterRollOff {\n\t\treturn this._rolloff;\n\t}\n\tset rolloff(rolloff) {\n\t\tconst rolloffNum = isNumber(rolloff)\n\t\t\t? rolloff\n\t\t\t: (parseInt(rolloff, 10) as FilterRollOff);\n\t\tconst possibilities = [-12, -24, -48, -96];\n\t\tlet cascadingCount = possibilities.indexOf(rolloffNum);\n\t\t// check the rolloff is valid\n\t\tassert(\n\t\t\tcascadingCount !== -1,\n\t\t\t`rolloff can only be ${possibilities.join(\", \")}`\n\t\t);\n\t\tcascadingCount += 1;\n\n\t\tthis._rolloff = rolloffNum;\n\t\tthis.input.disconnect();\n\t\tthis._filters.forEach((filter) => filter.disconnect());\n\n\t\tthis._filters = new Array(cascadingCount);\n\t\tfor (let count = 0; count < cascadingCount; count++) {\n\t\t\tconst filter = new BiquadFilter({\n\t\t\t\tcontext: this.context,\n\t\t\t});\n\t\t\tfilter.type = this._type;\n\t\t\tthis.frequency.connect(filter.frequency);\n\t\t\tthis.detune.connect(filter.detune);\n\t\t\tthis.Q.connect(filter.Q);\n\t\t\tthis.gain.connect(filter.gain);\n\t\t\tthis._filters[count] = filter;\n\t\t}\n\t\tthis._internalChannels = this._filters;\n\t\tconnectSeries(this.input, ...this._internalChannels, this.output);\n\t}\n\n\t/**\n\t * Get the frequency response curve. This curve represents how the filter\n\t * responses to frequencies between 20hz-20khz.\n\t * @param  len The number of values to return\n\t * @return The frequency response curve between 20-20kHz\n\t */\n\tgetFrequencyResponse(len = 128): Float32Array {\n\t\tconst filterClone = new BiquadFilter({\n\t\t\tcontext: this.context,\n\t\t\tfrequency: this.frequency.value,\n\t\t\tgain: this.gain.value,\n\t\t\tQ: this.Q.value,\n\t\t\ttype: this._type,\n\t\t\tdetune: this.detune.value,\n\t\t});\n\t\t// start with all 1s\n\t\tconst totalResponse = new Float32Array(len).map(() => 1);\n\t\tthis._filters.forEach(() => {\n\t\t\tconst response = filterClone.getFrequencyResponse(len);\n\t\t\tresponse.forEach((val, i) => (totalResponse[i] *= val));\n\t\t});\n\t\tfilterClone.dispose();\n\t\treturn totalResponse;\n\t}\n\n\t/**\n\t * Clean up.\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._filters.forEach((filter) => {\n\t\t\tfilter.dispose();\n\t\t});\n\t\twritable(this, [\"detune\", \"frequency\", \"gain\", \"Q\"]);\n\t\tthis.frequency.dispose();\n\t\tthis.Q.dispose();\n\t\tthis.detune.dispose();\n\t\tthis.gain.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/filter/LowpassCombFilter.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { Oscillator } from \"../../source/oscillator/Oscillator.js\";\nimport { LowpassCombFilter } from \"./LowpassCombFilter.js\";\n\ndescribe(\"LowpassCombFilter\", () => {\n\tBasicTests(LowpassCombFilter);\n\n\tcontext(\"Comb Filtering\", () => {\n\t\tit(\"can be constructed with an object\", () => {\n\t\t\tconst lpcf = new LowpassCombFilter({\n\t\t\t\tdelayTime: 0.2,\n\t\t\t\tresonance: 0.3,\n\t\t\t\tdampening: 2400,\n\t\t\t});\n\t\t\texpect(lpcf.delayTime.value).to.be.closeTo(0.2, 0.001);\n\t\t\texpect(lpcf.resonance.value).to.be.closeTo(0.3, 0.001);\n\t\t\texpect(lpcf.dampening).to.be.closeTo(2400, 0.001);\n\t\t\tlpcf.dispose();\n\t\t});\n\n\t\tit(\"can be get and set through object\", () => {\n\t\t\tconst lpcf = new LowpassCombFilter();\n\t\t\tlpcf.set({\n\t\t\t\tdelayTime: 0.2,\n\t\t\t\tresonance: 0.3,\n\t\t\t\tdampening: 2000,\n\t\t\t});\n\t\t\texpect(lpcf.get().delayTime).to.be.closeTo(0.2, 0.001);\n\t\t\texpect(lpcf.get().resonance).to.be.closeTo(0.3, 0.001);\n\t\t\texpect(lpcf.get().dampening).to.be.closeTo(2000, 0.001);\n\t\t\tlpcf.dispose();\n\t\t});\n\n\t\tit(\"passes the incoming signal through\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst lpcf = new LowpassCombFilter(0).toDestination();\n\t\t\t\tinput.connect(lpcf);\n\t\t\t});\n\t\t});\n\n\t\tit(\"produces a decay signal at high resonance\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst lpcf = new LowpassCombFilter(\n\t\t\t\t\t0.01,\n\t\t\t\t\t0.9,\n\t\t\t\t\t5000\n\t\t\t\t).toDestination();\n\t\t\t\tconst burst = new Oscillator(440).connect(lpcf);\n\t\t\t\tburst.start(0);\n\t\t\t\tburst.stop(0.1);\n\t\t\t}, 0.8);\n\t\t\texpect(buffer.getRmsAtTime(0.05)).to.be.within(0.2, 0.6);\n\t\t\texpect(buffer.getRmsAtTime(0.1)).to.be.within(0.2, 0.6);\n\t\t\texpect(buffer.getRmsAtTime(0.15)).to.be.within(0.15, 0.4);\n\t\t\texpect(buffer.getRmsAtTime(0.3)).to.be.within(0.01, 0.15);\n\t\t\texpect(buffer.getRmsAtTime(0.7)).to.be.below(0.01);\n\t\t});\n\n\t\tit(\"produces a decay signal at moderate resonance\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst lpcf = new LowpassCombFilter(0.05, 0.5).toDestination();\n\t\t\t\tconst burst = new Oscillator(440).connect(lpcf);\n\t\t\t\tburst.start(0);\n\t\t\t\tburst.stop(0.1);\n\t\t\t}, 0.6);\n\t\t\texpect(buffer.getRmsAtTime(0.05)).to.be.closeTo(0.7, 0.1);\n\t\t\texpect(buffer.getRmsAtTime(0.1)).to.be.within(0.7, 1.1);\n\t\t\texpect(buffer.getRmsAtTime(0.2)).to.be.closeTo(0.25, 0.1);\n\t\t\texpect(buffer.getRmsAtTime(0.4)).to.be.closeTo(0.015, 0.01);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/filter/LowpassCombFilter.ts",
    "content": "import { Param } from \"../../core/context/Param.js\";\nimport {\n\tInputNode,\n\tOutputNode,\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { Frequency, NormalRange, Time } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { RecursivePartial } from \"../../core/util/Interface.js\";\nimport { FeedbackCombFilter } from \"./FeedbackCombFilter.js\";\nimport { OnePoleFilter } from \"./OnePoleFilter.js\";\n\ninterface LowpassCombFilterOptions extends ToneAudioNodeOptions {\n\tdelayTime: Time;\n\tresonance: NormalRange;\n\tdampening: Frequency;\n}\n\n/**\n * A lowpass feedback comb filter. It is similar to\n * {@link FeedbackCombFilter}, but includes a lowpass filter.\n * @category Component\n */\nexport class LowpassCombFilter extends ToneAudioNode<LowpassCombFilterOptions> {\n\treadonly name = \"LowpassCombFilter\";\n\n\t/**\n\t * The delay node\n\t */\n\tprivate _combFilter: FeedbackCombFilter;\n\n\t/**\n\t * The lowpass filter\n\t */\n\tprivate _lowpass: OnePoleFilter;\n\n\t/**\n\t * The delayTime of the comb filter.\n\t */\n\treadonly delayTime: Param<\"time\">;\n\n\t/**\n\t * The amount of feedback of the delayed signal.\n\t */\n\treadonly resonance: Param<\"normalRange\">;\n\n\treadonly input: InputNode;\n\treadonly output: OutputNode;\n\n\t/**\n\t * @param delayTime The delay time of the comb filter\n\t * @param resonance The resonance (feedback) of the comb filter\n\t * @param dampening The cutoff of the lowpass filter dampens the signal as it is fed back.\n\t */\n\tconstructor(\n\t\tdelayTime?: Time,\n\t\tresonance?: NormalRange,\n\t\tdampening?: Frequency\n\t);\n\tconstructor(options?: RecursivePartial<LowpassCombFilterOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tLowpassCombFilter.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"delayTime\", \"resonance\", \"dampening\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._combFilter = this.output = new FeedbackCombFilter({\n\t\t\tcontext: this.context,\n\t\t\tdelayTime: options.delayTime,\n\t\t\tresonance: options.resonance,\n\t\t});\n\t\tthis.delayTime = this._combFilter.delayTime;\n\t\tthis.resonance = this._combFilter.resonance;\n\n\t\tthis._lowpass = this.input = new OnePoleFilter({\n\t\t\tcontext: this.context,\n\t\t\tfrequency: options.dampening,\n\t\t\ttype: \"lowpass\",\n\t\t});\n\n\t\t// connections\n\t\tthis._lowpass.connect(this._combFilter);\n\t}\n\n\tstatic getDefaults(): LowpassCombFilterOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tdampening: 3000,\n\t\t\tdelayTime: 0.1,\n\t\t\tresonance: 0.5,\n\t\t});\n\t}\n\n\t/**\n\t * The dampening control of the feedback\n\t */\n\tget dampening(): Frequency {\n\t\treturn this._lowpass.frequency;\n\t}\n\tset dampening(fq) {\n\t\tthis._lowpass.frequency = fq;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._combFilter.dispose();\n\t\tthis._lowpass.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/filter/OnePoleFilter.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../../test/helper/CompareToFile.js\";\nimport { atTime, Offline } from \"../../../test/helper/Offline.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { Oscillator } from \"../../source/oscillator/Oscillator.js\";\nimport { OnePoleFilter } from \"./OnePoleFilter.js\";\n\ndescribe(\"OnePoleFilter\", () => {\n\tBasicTests(OnePoleFilter);\n\n\tit(\"matches a file when set to lowpass\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst filter = new OnePoleFilter(\n\t\t\t\t\t300,\n\t\t\t\t\t\"lowpass\"\n\t\t\t\t).toDestination();\n\t\t\t\tconst osc = new Oscillator().connect(filter);\n\t\t\t\tosc.type = \"square\";\n\t\t\t\tosc.start(0).stop(0.1);\n\t\t\t},\n\t\t\t\"onePoleLowpass.wav\",\n\t\t\t0.05\n\t\t);\n\t});\n\n\tit(\"matches a file when set to highpass\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst filter = new OnePoleFilter(\n\t\t\t\t\t700,\n\t\t\t\t\t\"highpass\"\n\t\t\t\t).toDestination();\n\t\t\t\tconst osc = new Oscillator().connect(filter);\n\t\t\t\tosc.type = \"square\";\n\t\t\t\tosc.start(0).stop(0.1);\n\t\t\t},\n\t\t\t\"onePoleHighpass.wav\",\n\t\t\t0.05\n\t\t);\n\t});\n\n\tcontext(\"Filtering\", () => {\n\t\tit(\"can set the frequency more than once\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst filter = new OnePoleFilter(200);\n\t\t\t\tfilter.frequency = 300;\n\t\t\t\treturn atTime(0.1, () => {\n\t\t\t\t\tfilter.frequency = 400;\n\t\t\t\t});\n\t\t\t}, 1);\n\t\t});\n\n\t\tit(\"can be constructed with an object\", () => {\n\t\t\tconst filter = new OnePoleFilter({\n\t\t\t\tfrequency: 400,\n\t\t\t\ttype: \"lowpass\",\n\t\t\t});\n\t\t\texpect(filter.frequency).to.be.closeTo(400, 0.1);\n\t\t\texpect(filter.type).to.equal(\"lowpass\");\n\t\t\tfilter.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with args\", () => {\n\t\t\tconst filter = new OnePoleFilter(120, \"highpass\");\n\t\t\texpect(filter.frequency).to.be.closeTo(120, 0.1);\n\t\t\texpect(filter.type).to.equal(\"highpass\");\n\t\t\tfilter.dispose();\n\t\t});\n\n\t\tit(\"can be get and set through object\", () => {\n\t\t\tconst filter = new OnePoleFilter();\n\t\t\tfilter.set({\n\t\t\t\tfrequency: 200,\n\t\t\t\ttype: \"highpass\",\n\t\t\t});\n\t\t\texpect(filter.get().type).to.equal(\"highpass\");\n\t\t\texpect(filter.get().frequency).to.be.closeTo(200, 0.1);\n\t\t\tfilter.dispose();\n\t\t});\n\n\t\tit(\"passes the incoming signal through\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst filter = new OnePoleFilter(5000).toDestination();\n\t\t\t\tinput.connect(filter);\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"Response Curve\", () => {\n\t\tit(\"can get the response curve\", () => {\n\t\t\tconst filter = new OnePoleFilter();\n\t\t\tconst response = filter.getFrequencyResponse(128);\n\t\t\texpect(response.length).to.equal(128);\n\t\t\tresponse.forEach((v) => expect(v).to.be.within(0, 1));\n\t\t\tfilter.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/filter/OnePoleFilter.ts",
    "content": "import { Gain } from \"../../core/context/Gain.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\nimport { Frequency } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\n\nexport type OnePoleFilterType = \"highpass\" | \"lowpass\";\n\nexport interface OnePoleFilterOptions extends ToneAudioNodeOptions {\n\tfrequency: Frequency;\n\ttype: OnePoleFilterType;\n}\n\n/**\n * A one pole filter with 6db-per-octave rolloff. Either \"highpass\" or \"lowpass\".\n * Note that changing the type or frequency may result in a discontinuity which\n * can sound like a click or pop.\n * References:\n * * http://www.earlevel.com/main/2012/12/15/a-one-pole-filter/\n * * http://www.dspguide.com/ch19/2.htm\n * * https://github.com/vitaliy-bobrov/js-rocks/blob/master/src/app/audio/effects/one-pole-filters.ts\n * @category Component\n */\nexport class OnePoleFilter extends ToneAudioNode<OnePoleFilterOptions> {\n\treadonly name: string = \"OnePoleFilter\";\n\n\t/**\n\t * Hold the current frequency\n\t */\n\tprivate _frequency: Frequency;\n\n\t/**\n\t * the current one pole type\n\t */\n\tprivate _type: OnePoleFilterType;\n\n\t/**\n\t * the current one pole filter\n\t */\n\tprivate _filter!: IIRFilterNode;\n\n\treadonly input: Gain;\n\treadonly output: Gain;\n\n\t/**\n\t * @param frequency The frequency\n\t * @param type The  filter type, either \"lowpass\" or \"highpass\"\n\t */\n\tconstructor(frequency?: Frequency, type?: OnePoleFilterType);\n\tconstructor(options?: Partial<OnePoleFilterOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tOnePoleFilter.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"frequency\", \"type\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._frequency = options.frequency;\n\t\tthis._type = options.type;\n\t\tthis.input = new Gain({ context: this.context });\n\t\tthis.output = new Gain({ context: this.context });\n\t\tthis._createFilter();\n\t}\n\n\tstatic getDefaults(): OnePoleFilterOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tfrequency: 880,\n\t\t\ttype: \"lowpass\" as OnePoleFilterType,\n\t\t});\n\t}\n\n\t/**\n\t * Create a filter and dispose the old one\n\t */\n\tprivate _createFilter() {\n\t\tconst oldFilter = this._filter;\n\t\tconst freq = this.toFrequency(this._frequency);\n\t\tconst t = 1 / (2 * Math.PI * freq);\n\t\tif (this._type === \"lowpass\") {\n\t\t\tconst a0 = 1 / (t * this.context.sampleRate);\n\t\t\tconst b1 = a0 - 1;\n\t\t\tthis._filter = this.context.createIIRFilter([a0, 0], [1, b1]);\n\t\t} else {\n\t\t\tconst b1 = 1 / (t * this.context.sampleRate) - 1;\n\t\t\tthis._filter = this.context.createIIRFilter([1, -1], [1, b1]);\n\t\t}\n\n\t\tthis.input.chain(this._filter, this.output);\n\t\tif (oldFilter) {\n\t\t\t// dispose it on the next block\n\t\t\tthis.context.setTimeout(() => {\n\t\t\t\tif (!this.disposed) {\n\t\t\t\t\tthis.input.disconnect(oldFilter);\n\t\t\t\t\toldFilter.disconnect();\n\t\t\t\t}\n\t\t\t}, this.blockTime);\n\t\t}\n\t}\n\n\t/**\n\t * The frequency value.\n\t */\n\tget frequency(): Frequency {\n\t\treturn this._frequency;\n\t}\n\tset frequency(fq) {\n\t\tthis._frequency = fq;\n\t\tthis._createFilter();\n\t}\n\n\t/**\n\t * The OnePole Filter type, either \"highpass\" or \"lowpass\"\n\t */\n\tget type(): OnePoleFilterType {\n\t\treturn this._type;\n\t}\n\tset type(t) {\n\t\tthis._type = t;\n\t\tthis._createFilter();\n\t}\n\n\t/**\n\t * Get the frequency response curve. This curve represents how the filter\n\t * responses to frequencies between 20hz-20khz.\n\t * @param  len The number of values to return\n\t * @return The frequency response curve between 20-20kHz\n\t */\n\tgetFrequencyResponse(len = 128): Float32Array {\n\t\tconst freqValues = new Float32Array(len);\n\t\tfor (let i = 0; i < len; i++) {\n\t\t\tconst norm = Math.pow(i / len, 2);\n\t\t\tconst freq = norm * (20000 - 20) + 20;\n\t\t\tfreqValues[i] = freq;\n\t\t}\n\t\tconst magValues = new Float32Array(len);\n\t\tconst phaseValues = new Float32Array(len);\n\t\tthis._filter.getFrequencyResponse(freqValues, magValues, phaseValues);\n\t\treturn magValues;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.input.dispose();\n\t\tthis.output.dispose();\n\t\tthis._filter.disconnect();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/filter/PhaseShiftAllpass.test.ts",
    "content": "import { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../../test/helper/CompareToFile.js\";\nimport { connectTo } from \"../../../test/helper/Connect.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { connect } from \"../../core/context/ToneAudioNode.js\";\nimport { Subtract } from \"../../signal/Subtract.js\";\nimport { PhaseShiftAllpass } from \"./PhaseShiftAllpass.js\";\n\ndescribe(\"PhaseShiftAllpass\", () => {\n\tBasicTests(PhaseShiftAllpass);\n\n\tcontext(\"PhaseShiftAllpass\", () => {\n\t\tit(\"handles output connections\", () => {\n\t\t\tconst phaseShifter = new PhaseShiftAllpass();\n\t\t\tphaseShifter.connect(connectTo());\n\t\t\tphaseShifter.offset90.connect(connectTo());\n\t\t\tphaseShifter.dispose();\n\t\t});\n\n\t\tit(\"passes the incoming signal through\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst phaseShifter = new PhaseShiftAllpass().toDestination();\n\t\t\t\tinput.connect(phaseShifter);\n\t\t\t});\n\t\t});\n\n\t\tit(\"generates correct values with the phase shifted channel\", () => {\n\t\t\treturn CompareToFile(\n\t\t\t\t(context) => {\n\t\t\t\t\t// create impulse with 5 samples offset\n\t\t\t\t\tconst constantNode = context.createConstantSource();\n\t\t\t\t\tconstantNode.start(0);\n\t\t\t\t\tconst oneSampleDelay = context.createIIRFilter(\n\t\t\t\t\t\t[0.0, 1.0],\n\t\t\t\t\t\t[1.0, 0.0]\n\t\t\t\t\t);\n\t\t\t\t\tconst fiveSampleDelay = context.createIIRFilter(\n\t\t\t\t\t\t[0.0, 0.0, 0.0, 0.0, 0.0, 1.0],\n\t\t\t\t\t\t[1.0, 0.0, 0.0, 0.0, 0.0, 0.0]\n\t\t\t\t\t);\n\t\t\t\t\tconst sub = new Subtract();\n\n\t\t\t\t\tconnect(constantNode, oneSampleDelay);\n\t\t\t\t\tconnect(constantNode, sub);\n\t\t\t\t\tconnect(oneSampleDelay, sub.subtrahend);\n\t\t\t\t\tconnect(sub, fiveSampleDelay);\n\n\t\t\t\t\tconst phaseShifter = new PhaseShiftAllpass();\n\t\t\t\t\tconnect(fiveSampleDelay, phaseShifter);\n\t\t\t\t\tphaseShifter.toDestination();\n\t\t\t\t},\n\t\t\t\t\"phaseShiftAllpass.wav\",\n\t\t\t\t0.001\n\t\t\t);\n\t\t});\n\n\t\tit(\"generates correct values with the offset90 channel\", () => {\n\t\t\treturn CompareToFile(\n\t\t\t\t(context) => {\n\t\t\t\t\t// create impulse with 5 samples offset\n\t\t\t\t\tconst constantNode = context.createConstantSource();\n\t\t\t\t\tconstantNode.start(0);\n\t\t\t\t\tconst oneSampleDelay = context.createIIRFilter(\n\t\t\t\t\t\t[0.0, 1.0],\n\t\t\t\t\t\t[1.0, 0.0]\n\t\t\t\t\t);\n\t\t\t\t\tconst fiveSampleDelay = context.createIIRFilter(\n\t\t\t\t\t\t[0.0, 0.0, 0.0, 0.0, 0.0, 1.0],\n\t\t\t\t\t\t[1.0, 0.0, 0.0, 0.0, 0.0, 0.0]\n\t\t\t\t\t);\n\t\t\t\t\tconst sub = new Subtract();\n\n\t\t\t\t\tconnect(constantNode, oneSampleDelay);\n\t\t\t\t\tconnect(constantNode, sub);\n\t\t\t\t\tconnect(oneSampleDelay, sub.subtrahend);\n\t\t\t\t\tconnect(sub, fiveSampleDelay);\n\n\t\t\t\t\tconst phaseShifter = new PhaseShiftAllpass();\n\t\t\t\t\tconnect(fiveSampleDelay, phaseShifter);\n\t\t\t\t\tphaseShifter.offset90.toDestination();\n\t\t\t\t},\n\t\t\t\t\"phaseShiftAllpass1.wav\",\n\t\t\t\t0.001\n\t\t\t);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/component/filter/PhaseShiftAllpass.ts",
    "content": "import { Gain } from \"../../core/context/Gain.js\";\nimport {\n\tconnectSeries,\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../../core/context/ToneAudioNode.js\";\n\n/**\n * PhaseShiftAllpass is an very efficient implementation of a Hilbert Transform\n * using two Allpass filter banks whose outputs have a phase difference of 90°.\n * Here the `offset90` phase is offset by +90° in relation to `output`.\n * Coefficients and structure was developed by Olli Niemitalo.\n * For more details see: http://yehar.com/blog/?p=368\n * @category Component\n */\nexport class PhaseShiftAllpass extends ToneAudioNode<ToneAudioNodeOptions> {\n\treadonly name: string = \"PhaseShiftAllpass\";\n\n\treadonly input = new Gain({ context: this.context });\n\n\t/**\n\t * The Allpass filter in the first bank\n\t */\n\tprivate _bank0: IIRFilterNode[];\n\n\t/**\n\t * The Allpass filter in the seconds bank\n\t */\n\tprivate _bank1: IIRFilterNode[];\n\n\t/**\n\t * A IIR filter implementing a delay by one sample used by the first bank\n\t */\n\tprivate _oneSampleDelay: IIRFilterNode;\n\n\t/**\n\t * The phase shifted output\n\t */\n\treadonly output = new Gain({ context: this.context });\n\n\t/**\n\t * The PhaseShifted allpass output\n\t */\n\treadonly offset90 = new Gain({ context: this.context });\n\n\tconstructor(options?: Partial<ToneAudioNodeOptions>) {\n\t\tsuper(options);\n\n\t\tconst allpassBank1Values = [\n\t\t\t0.6923878, 0.9360654322959, 0.988229522686, 0.9987488452737,\n\t\t];\n\t\tconst allpassBank2Values = [\n\t\t\t0.4021921162426, 0.856171088242, 0.9722909545651, 0.9952884791278,\n\t\t];\n\n\t\tthis._bank0 = this._createAllPassFilterBank(allpassBank1Values);\n\t\tthis._bank1 = this._createAllPassFilterBank(allpassBank2Values);\n\t\tthis._oneSampleDelay = this.context.createIIRFilter(\n\t\t\t[0.0, 1.0],\n\t\t\t[1.0, 0.0]\n\t\t);\n\n\t\t// connect Allpass filter banks\n\t\tconnectSeries(\n\t\t\tthis.input,\n\t\t\t...this._bank0,\n\t\t\tthis._oneSampleDelay,\n\t\t\tthis.output\n\t\t);\n\t\tconnectSeries(this.input, ...this._bank1, this.offset90);\n\t}\n\n\t/**\n\t * Create all of the IIR filters from an array of values using the coefficient calculation.\n\t */\n\tprivate _createAllPassFilterBank(bankValues: number[]): IIRFilterNode[] {\n\t\tconst nodes: IIRFilterNode[] = bankValues.map((value) => {\n\t\t\tconst coefficients = [\n\t\t\t\t[value * value, 0, -1],\n\t\t\t\t[1, 0, -(value * value)],\n\t\t\t];\n\t\t\treturn this.context.createIIRFilter(\n\t\t\t\tcoefficients[0],\n\t\t\t\tcoefficients[1]\n\t\t\t);\n\t\t});\n\n\t\treturn nodes;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.input.dispose();\n\t\tthis.output.dispose();\n\t\tthis.offset90.dispose();\n\t\tthis._bank0.forEach((f) => f.disconnect());\n\t\tthis._bank1.forEach((f) => f.disconnect());\n\t\tthis._oneSampleDelay.disconnect();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/component/index.ts",
    "content": "export * from \"./analysis/Analyser.js\";\nexport * from \"./analysis/DCMeter.js\";\nexport * from \"./analysis/FFT.js\";\nexport * from \"./analysis/Follower.js\";\nexport * from \"./analysis/Meter.js\";\nexport * from \"./analysis/Waveform.js\";\nexport * from \"./channel/Channel.js\";\nexport * from \"./channel/CrossFade.js\";\nexport * from \"./channel/Merge.js\";\nexport * from \"./channel/MidSideMerge.js\";\nexport * from \"./channel/MidSideSplit.js\";\nexport * from \"./channel/Mono.js\";\nexport * from \"./channel/MultibandSplit.js\";\nexport * from \"./channel/Panner.js\";\nexport * from \"./channel/Panner3D.js\";\nexport * from \"./channel/PanVol.js\";\nexport * from \"./channel/Recorder.js\";\nexport * from \"./channel/Solo.js\";\nexport * from \"./channel/Split.js\";\nexport * from \"./channel/Volume.js\";\nexport * from \"./dynamics/Compressor.js\";\nexport * from \"./dynamics/Gate.js\";\nexport * from \"./dynamics/Limiter.js\";\nexport * from \"./dynamics/MidSideCompressor.js\";\nexport * from \"./dynamics/MultibandCompressor.js\";\nexport * from \"./envelope/AmplitudeEnvelope.js\";\nexport * from \"./envelope/Envelope.js\";\nexport * from \"./envelope/FrequencyEnvelope.js\";\nexport * from \"./filter/BiquadFilter.js\";\nexport * from \"./filter/Convolver.js\";\nexport * from \"./filter/EQ3.js\";\nexport * from \"./filter/FeedbackCombFilter.js\";\nexport * from \"./filter/Filter.js\";\nexport * from \"./filter/LowpassCombFilter.js\";\nexport * from \"./filter/OnePoleFilter.js\";\n"
  },
  {
    "path": "Tone/core/Global.ts",
    "content": "import { version } from \"../version.js\";\nimport {\n\tAnyAudioContext,\n\thasAudioContext,\n\ttheWindow,\n} from \"./context/AudioContext.js\";\nimport { BaseContext } from \"./context/BaseContext.js\";\nimport { Context } from \"./context/Context.js\";\nimport { DummyContext } from \"./context/DummyContext.js\";\nimport { OfflineContext } from \"./context/OfflineContext.js\";\nimport {\n\tisAudioContext,\n\tisOfflineAudioContext,\n} from \"./util/AdvancedTypeCheck.js\";\n\n/**\n * This dummy context is used to avoid throwing immediate errors when importing in Node.js\n */\nconst dummyContext = new DummyContext();\n\n/**\n * The global audio context which is getable and assignable through\n * getContext and setContext\n */\nlet globalContext: BaseContext = dummyContext;\n\n/**\n * Returns the default system-wide {@link Context}\n * @category Core\n */\nexport function getContext(): BaseContext {\n\tif (globalContext === dummyContext && hasAudioContext) {\n\t\tsetContext(new Context());\n\t}\n\treturn globalContext;\n}\n\n/**\n * Set the default audio context\n * @param context\n * @param disposeOld Pass `true` if you don't need the old context to dispose it.\n * @category Core\n */\nexport function setContext(\n\tcontext: BaseContext | AnyAudioContext,\n\tdisposeOld = false\n): void {\n\tif (disposeOld) {\n\t\tglobalContext.dispose();\n\t}\n\n\tif (isAudioContext(context)) {\n\t\tglobalContext = new Context(context);\n\t} else if (isOfflineAudioContext(context)) {\n\t\tglobalContext = new OfflineContext(context);\n\t} else {\n\t\tglobalContext = context;\n\t}\n}\n\n/**\n * Most browsers will not play _any_ audio until a user\n * clicks something (like a play button). Invoke this method\n * on a click or keypress event handler to start the audio context.\n * More about the Autoplay policy\n * [here](https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#webaudio)\n * @example\n * document.querySelector(\"button\").addEventListener(\"click\", async () => {\n * \tawait Tone.start();\n * \tconsole.log(\"context started\");\n * });\n * @category Core\n */\nexport function start(): Promise<void> {\n\treturn globalContext.resume();\n}\n\n/**\n * Log Tone.js + version in the console.\n */\nif (theWindow && !theWindow.TONE_SILENCE_LOGGING) {\n\tlet prefix = \"v\";\n\tif (version === \"dev\") {\n\t\tprefix = \"\";\n\t}\n\tconst printString = ` * Tone.js ${prefix}${version} * `;\n\t// eslint-disable-next-line no-console\n\tconsole.log(`%c${printString}`, \"background: #000; color: #fff\");\n}\n"
  },
  {
    "path": "Tone/core/Tone.ts",
    "content": "/**\n * Tone.js\n * @author Yotam Mann\n * @license http://opensource.org/licenses/MIT MIT License\n * @copyright 2014-2024 Yotam Mann\n */\nimport { version } from \"../version.js\";\nimport { theWindow } from \"./context/AudioContext.js\";\nimport { log } from \"./util/Debug.js\";\n\n//-------------------------------------\n// \tTONE\n//-------------------------------------\n\nexport interface BaseToneOptions {}\n\n/**\n * Tone is the base class of all other classes.\n *\n * @category Core\n * @constructor\n */\nexport abstract class Tone {\n\t/**\n\t * The version number semver\n\t */\n\tstatic version: string = version;\n\n\t/**\n\t * The name of the class\n\t */\n\tprotected abstract name: string;\n\n\t/**\n\t * Returns all of the default options belonging to the class.\n\t */\n\tstatic getDefaults(): BaseToneOptions {\n\t\treturn {};\n\t}\n\n\t//-------------------------------------\n\t// \tDEBUGGING\n\t//-------------------------------------\n\n\t/**\n\t * Set this debug flag to log all events that happen in this class.\n\t */\n\tdebug = false;\n\n\t/**\n\t * Prints the outputs to the console log for debugging purposes.\n\t * Prints the contents only if either the object has a property\n\t * called `debug` set to true, or a variable called TONE_DEBUG_CLASS\n\t * is set to the name of the class.\n\t * @example\n\t * const osc = new Tone.Oscillator();\n\t * // prints all logs originating from this oscillator\n\t * osc.debug = true;\n\t * // calls to start/stop will print in the console\n\t * osc.start();\n\t */\n\tprotected log(...args: any[]): void {\n\t\t// if the object is either set to debug = true\n\t\t// or if there is a string on the Tone.global.with the class name\n\t\tif (\n\t\t\tthis.debug ||\n\t\t\t(theWindow && this.toString() === theWindow.TONE_DEBUG_CLASS)\n\t\t) {\n\t\t\tlog(this, ...args);\n\t\t}\n\t}\n\n\t//-------------------------------------\n\t// \tDISPOSING\n\t//-------------------------------------\n\n\t/**\n\t * Indicates if the instance was disposed\n\t */\n\tprivate _wasDisposed = false;\n\n\t/**\n\t * disconnect and dispose.\n\t */\n\tdispose(): this {\n\t\tthis._wasDisposed = true;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Indicates if the instance was disposed. 'Disposing' an\n\t * instance means that all of the Web Audio nodes that were\n\t * created for the instance are disconnected and freed for garbage collection.\n\t */\n\tget disposed(): boolean {\n\t\treturn this._wasDisposed;\n\t}\n\n\t/**\n\t * Convert the class to a string\n\t * @example\n\t * const osc = new Tone.Oscillator();\n\t * console.log(osc.toString());\n\t */\n\ttoString(): string {\n\t\treturn this.name;\n\t}\n}\n"
  },
  {
    "path": "Tone/core/clock/Clock.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { atTime, Offline, whenBetween } from \"../../../test/helper/Offline.js\";\nimport { noOp } from \"../util/Interface.js\";\nimport { Clock } from \"./Clock.js\";\n\ndescribe(\"Clock\", () => {\n\tBasicTests(Clock);\n\n\tcontext(\"Get/Set values\", () => {\n\t\tit(\"can get and set the frequency\", () => {\n\t\t\tconst clock = new Clock(noOp, 2);\n\t\t\texpect(clock.frequency.value).to.equal(2);\n\t\t\tclock.frequency.value = 0.2;\n\t\t\texpect(clock.frequency.value).to.be.closeTo(0.2, 0.001);\n\t\t\tclock.dispose();\n\t\t});\n\n\t\tit(\"invokes the callback when started\", (done) => {\n\t\t\tconst clock = new Clock((time) => {\n\t\t\t\tclock.dispose();\n\t\t\t\tdone();\n\t\t\t}, 10).start();\n\t\t});\n\n\t\tit(\"can be constructed with an options object\", (done) => {\n\t\t\tconst clock = new Clock({\n\t\t\t\tcallback(): void {\n\t\t\t\t\tclock.dispose();\n\t\t\t\t\tdone();\n\t\t\t\t},\n\t\t\t\tfrequency: 8,\n\t\t\t}).start();\n\t\t\texpect(clock.frequency.value).to.equal(8);\n\t\t});\n\n\t\tit(\"can get and set its values with the set/get\", () => {\n\t\t\tconst clock = new Clock();\n\t\t\tclock.set({\n\t\t\t\tfrequency: 2,\n\t\t\t});\n\t\t\tconst gotValues = clock.get();\n\t\t\texpect(gotValues.frequency).to.equal(2);\n\t\t\tclock.dispose();\n\t\t});\n\t});\n\n\tcontext(\"State\", () => {\n\t\tit(\"correctly returns the scheduled play state\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock();\n\t\t\t\texpect(clock.state).to.equal(\"stopped\");\n\t\t\t\tclock.start(0).stop(0.2);\n\t\t\t\texpect(clock.state).to.equal(\"started\");\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, 0.2, () => {\n\t\t\t\t\t\texpect(clock.state).to.equal(\"started\");\n\t\t\t\t\t});\n\n\t\t\t\t\twhenBetween(time, 0.2, Infinity, () => {\n\t\t\t\t\t\texpect(clock.state).to.equal(\"stopped\");\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.3);\n\t\t});\n\n\t\tit(\"can start, pause, and stop\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock();\n\t\t\t\texpect(clock.state).to.equal(\"stopped\");\n\t\t\t\tclock.start(0).pause(0.2).stop(0.4);\n\t\t\t\texpect(clock.state).to.equal(\"started\");\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, 0.2, () => {\n\t\t\t\t\t\texpect(clock.state).to.equal(\"started\");\n\t\t\t\t\t});\n\n\t\t\t\t\twhenBetween(time, 0.2, 0.4, () => {\n\t\t\t\t\t\texpect(clock.state).to.equal(\"paused\");\n\t\t\t\t\t});\n\n\t\t\t\t\twhenBetween(time, 0.4, Infinity, () => {\n\t\t\t\t\t\texpect(clock.state).to.equal(\"stopped\");\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.5);\n\t\t});\n\n\t\tit(\"can schedule multiple start and stops\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock();\n\t\t\t\texpect(clock.state).to.equal(\"stopped\");\n\t\t\t\tclock.start(0).pause(0.1).stop(0.2).start(0.3).stop(0.4);\n\t\t\t\texpect(clock.state).to.equal(\"started\");\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0.1, 0.2, () => {\n\t\t\t\t\t\texpect(clock.state).to.equal(\"paused\");\n\t\t\t\t\t\texpect(clock.ticks).to.be.greaterThan(0);\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.2, 0.3, () => {\n\t\t\t\t\t\texpect(clock.state).to.equal(\"stopped\");\n\t\t\t\t\t\texpect(clock.ticks).to.equal(0);\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.3, 0.4, () => {\n\t\t\t\t\t\texpect(clock.state).to.equal(\"started\");\n\t\t\t\t\t\texpect(clock.ticks).to.be.greaterThan(0);\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.5);\n\t\t});\n\n\t\tit(\"stop and immediately start\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock();\n\t\t\t\texpect(clock.state).to.equal(\"stopped\");\n\t\t\t\tclock.start(0).stop(0.1).start(0.1);\n\t\t\t\texpect(clock.state).to.equal(\"started\");\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, 0.1, () => {\n\t\t\t\t\t\texpect(clock.state).to.equal(\"started\");\n\t\t\t\t\t});\n\n\t\t\t\t\twhenBetween(time, 0.1, 0.5, () => {\n\t\t\t\t\t\texpect(clock.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.5);\n\t\t});\n\t});\n\n\tcontext(\"Scheduling\", () => {\n\t\tit(\"passes a time to the callback\", (done) => {\n\t\t\tconst clock = new Clock((time) => {\n\t\t\t\texpect(time).to.be.a(\"number\");\n\t\t\t\tclock.dispose();\n\t\t\t\tdone();\n\t\t\t}, 10).start();\n\t\t});\n\n\t\tit(\"invokes the callback with a time great than now\", (done) => {\n\t\t\tconst clock = new Clock((time) => {\n\t\t\t\tclock.dispose();\n\t\t\t\texpect(time).to.be.greaterThan(now);\n\t\t\t\tdone();\n\t\t\t}, 10);\n\t\t\tconst now = clock.now();\n\t\t\tconst startTime = now + 0.1;\n\t\t\tclock.start(startTime);\n\t\t});\n\n\t\tit(\"invokes the first callback at the given start time\", (done) => {\n\t\t\tconst clock = new Clock((time) => {\n\t\t\t\tclock.dispose();\n\t\t\t\texpect(time).to.be.closeTo(startTime, 0.01);\n\t\t\t\tdone();\n\t\t\t}, 10);\n\t\t\tconst startTime = clock.now() + 0.1;\n\t\t\tclock.start(startTime);\n\t\t});\n\n\t\tit(\"can be scheduled to start in the future\", async () => {\n\t\t\tlet invocations = 0;\n\t\t\tawait Offline(() => {\n\t\t\t\tconst clock = new Clock((time) => {\n\t\t\t\t\tinvocations++;\n\t\t\t\t}, 2).start(0.1);\n\t\t\t}, 0.4);\n\t\t\texpect(invocations).to.equal(1);\n\t\t});\n\n\t\tit(\"invokes the right number of callbacks given the duration\", async () => {\n\t\t\tlet invocations = 0;\n\t\t\tawait Offline(() => {\n\t\t\t\tnew Clock((time) => {\n\t\t\t\t\tinvocations++;\n\t\t\t\t}, 10)\n\t\t\t\t\t.start(0)\n\t\t\t\t\t.stop(0.45);\n\t\t\t}, 0.6);\n\t\t\texpect(invocations).to.equal(5);\n\t\t});\n\n\t\tit(\"can schedule the frequency of the clock\", async () => {\n\t\t\tlet invocations = 0;\n\t\t\tawait Offline(() => {\n\t\t\t\tconst clock = new Clock((time, ticks) => {\n\t\t\t\t\tinvocations++;\n\t\t\t\t}, 2);\n\t\t\t\tclock.start(0).stop(1.01);\n\t\t\t\tclock.frequency.setValueAtTime(4, 0.5);\n\t\t\t}, 2);\n\t\t\texpect(invocations).to.equal(4);\n\t\t});\n\t});\n\n\tcontext(\"Seconds\", () => {\n\t\tit(\"can set the current seconds\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 10);\n\t\t\t\texpect(clock.seconds).to.be.closeTo(0, 0.001);\n\t\t\t\tclock.seconds = 3;\n\t\t\t\texpect(clock.seconds).to.be.closeTo(3, 0.01);\n\t\t\t\tclock.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get the seconds\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 10);\n\t\t\t\texpect(clock.seconds).to.be.closeTo(0, 0.001);\n\t\t\t\tclock.start(0.05);\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time > 0.05) {\n\t\t\t\t\t\texpect(clock.seconds).to.be.closeTo(time - 0.05, 0.01);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.1);\n\t\t});\n\n\t\tit(\"can get the seconds during a bpm ramp\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 10);\n\t\t\t\texpect(clock.seconds).to.be.closeTo(0, 0.001);\n\t\t\t\tclock.start(0.05);\n\t\t\t\tclock.frequency.linearRampTo(60, 0.5, 0.5);\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time > 0.05) {\n\t\t\t\t\t\texpect(clock.seconds).to.be.closeTo(time - 0.05, 0.01);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.7);\n\t\t});\n\n\t\tit(\"can set seconds during a bpm ramp\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 10);\n\t\t\t\texpect(clock.seconds).to.be.closeTo(0, 0.001);\n\t\t\t\tclock.start(0.05);\n\t\t\t\tclock.frequency.linearRampTo(60, 0.5, 0.5);\n\t\t\t\tconst changeSeconds = atTime(0.4, () => {\n\t\t\t\t\tclock.seconds = 0;\n\t\t\t\t});\n\t\t\t\treturn (time) => {\n\t\t\t\t\tchangeSeconds(time);\n\t\t\t\t\tif (time > 0.05 && time < 0.4) {\n\t\t\t\t\t\texpect(clock.seconds).to.be.closeTo(time - 0.05, 0.01);\n\t\t\t\t\t} else if (time > 0.4) {\n\t\t\t\t\t\texpect(clock.seconds).to.be.closeTo(time - 0.4, 0.01);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.7);\n\t\t});\n\t});\n\n\tcontext(\"Ticks\", () => {\n\t\tit(\"has 0 ticks when first created\", () => {\n\t\t\tconst clock = new Clock();\n\t\t\texpect(clock.ticks).to.equal(0);\n\t\t\tclock.dispose();\n\t\t});\n\n\t\tit(\"can set the ticks\", () => {\n\t\t\tconst clock = new Clock();\n\t\t\texpect(clock.ticks).to.equal(0);\n\t\t\tclock.ticks = 10;\n\t\t\texpect(clock.ticks).to.equal(10);\n\t\t\tclock.dispose();\n\t\t});\n\n\t\tit(\"increments 1 tick per callback\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tlet ticks = 0;\n\t\t\t\tconst clock = new Clock(() => {\n\t\t\t\t\tticks++;\n\t\t\t\t}, 2).start();\n\t\t\t\treturn atTime(0.59, () => {\n\t\t\t\t\texpect(ticks).to.equal(clock.ticks);\n\t\t\t\t});\n\t\t\t}, 0.6);\n\t\t});\n\n\t\tit(\"resets ticks on stop\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 20).start(0).stop(0.1);\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0.01, 0.09, () => {\n\t\t\t\t\t\texpect(clock.ticks).to.be.greaterThan(0);\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.1, Infinity, () => {\n\t\t\t\t\t\texpect(clock.ticks).to.equal(0);\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.2);\n\t\t});\n\n\t\tit(\"does not reset ticks on pause but stops incrementing\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 20).start(0).pause(0.1);\n\t\t\t\tlet pausedTicks = 0;\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0.01, 0.1, () => {\n\t\t\t\t\t\texpect(clock.ticks).to.be.greaterThan(0);\n\t\t\t\t\t\tpausedTicks = clock.ticks;\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.1, Infinity, () => {\n\t\t\t\t\t\texpect(clock.ticks).to.equal(pausedTicks);\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.2);\n\t\t});\n\n\t\tit(\"starts incrementing where it left off after pause\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 20)\n\t\t\t\t\t.start(0)\n\t\t\t\t\t.pause(0.1)\n\t\t\t\t\t.start(0.2);\n\n\t\t\t\tlet pausedTicks = 0;\n\t\t\t\tlet tested = false;\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0.01, 0.1, () => {\n\t\t\t\t\t\texpect(clock.ticks).to.be.greaterThan(0);\n\t\t\t\t\t\tpausedTicks = clock.ticks;\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.1, 0.19, () => {\n\t\t\t\t\t\texpect(clock.ticks).to.equal(pausedTicks);\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.21, Infinity, () => {\n\t\t\t\t\t\tif (!tested) {\n\t\t\t\t\t\t\ttested = true;\n\t\t\t\t\t\t\texpect(clock.ticks).to.equal(pausedTicks + 1);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.3);\n\t\t});\n\n\t\tit(\"can start with a tick offset\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tlet tested = false;\n\t\t\t\tconst clock = new Clock((time, ticks) => {\n\t\t\t\t\tif (!tested) {\n\t\t\t\t\t\ttested = true;\n\t\t\t\t\t\texpect(ticks).to.equal(4);\n\t\t\t\t\t}\n\t\t\t\t}, 10);\n\t\t\t\texpect(clock.ticks).to.equal(0);\n\t\t\t\tclock.start(0, 4);\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"Events\", () => {\n\t\tit(\"triggers the start event on start\", (done) => {\n\t\t\tOffline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 20);\n\t\t\t\tconst startTime = 0.3;\n\t\t\t\tclock.on(\"start\", (time, offset) => {\n\t\t\t\t\texpect(time).to.be.closeTo(startTime, 0.05);\n\t\t\t\t\texpect(offset).to.equal(0);\n\t\t\t\t\tdone();\n\t\t\t\t});\n\t\t\t\tclock.start(startTime);\n\t\t\t}, 0.4);\n\t\t});\n\n\t\tit(\"triggers the start event with an offset\", (done) => {\n\t\t\tOffline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 20);\n\t\t\t\tconst startTime = 0.3;\n\t\t\t\tclock.on(\"start\", (time, offset) => {\n\t\t\t\t\texpect(time).to.be.closeTo(startTime, 0.05);\n\t\t\t\t\texpect(offset).to.equal(2);\n\t\t\t\t\tdone();\n\t\t\t\t});\n\t\t\t\tclock.start(startTime, 2);\n\t\t\t}, 0.4);\n\t\t});\n\n\t\tit(\"triggers stop event\", (done) => {\n\t\t\tOffline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 20);\n\t\t\t\tconst stopTime = 0.3;\n\t\t\t\tclock.on(\"stop\", (time) => {\n\t\t\t\t\texpect(time).to.be.closeTo(stopTime, 0.05);\n\t\t\t\t\tdone();\n\t\t\t\t});\n\t\t\t\tclock.start().stop(stopTime);\n\t\t\t}, 0.4);\n\t\t});\n\n\t\tit(\"triggers pause stop event\", (done) => {\n\t\t\tOffline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 20);\n\t\t\t\tclock\n\t\t\t\t\t.on(\"pause\", (time) => {\n\t\t\t\t\t\texpect(time).to.be.closeTo(0.1, 0.05);\n\t\t\t\t\t})\n\t\t\t\t\t.on(\"stop\", (time) => {\n\t\t\t\t\t\texpect(time).to.be.closeTo(0.2, 0.05);\n\t\t\t\t\t\tdone();\n\t\t\t\t\t});\n\t\t\t\tclock.start().pause(0.1).stop(0.2);\n\t\t\t}, 0.4);\n\t\t});\n\n\t\tit(\"triggers events even in close proximity\", (done) => {\n\t\t\tOffline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 20);\n\t\t\t\tlet invokedStartEvent = false;\n\t\t\t\tclock.on(\"start\", () => {\n\t\t\t\t\tinvokedStartEvent = true;\n\t\t\t\t});\n\t\t\t\tclock.on(\"stop\", () => {\n\t\t\t\t\texpect(invokedStartEvent).to.equal(true);\n\t\t\t\t\tdone();\n\t\t\t\t});\n\t\t\t\tclock.start(0.09999).stop(0.1);\n\t\t\t}, 0.4);\n\t\t});\n\n\t\tit(\"triggers 'start' event when time is in the past\", (done) => {\n\t\t\tconst clock = new Clock(noOp, 20);\n\t\t\tclock.on(\"start\", () => {\n\t\t\t\tdone();\n\t\t\t\tclock.dispose();\n\t\t\t});\n\t\t\tsetTimeout(() => {\n\t\t\t\tclock.start(0);\n\t\t\t}, 100);\n\t\t});\n\n\t\tit(\"triggers 'stop' event when time is in the past\", (done) => {\n\t\t\tconst clock = new Clock(noOp, 20);\n\t\t\tclock.on(\"stop\", () => {\n\t\t\t\tdone();\n\t\t\t\tclock.dispose();\n\t\t\t});\n\t\t\tsetTimeout(() => {\n\t\t\t\tclock.start(0);\n\t\t\t}, 100);\n\t\t\tsetTimeout(() => {\n\t\t\t\tclock.stop(0);\n\t\t\t}, 200);\n\t\t});\n\n\t\tit(\"triggers 'pause' event when time is in the past\", (done) => {\n\t\t\tconst clock = new Clock(noOp, 20);\n\t\t\tclock.on(\"pause\", () => {\n\t\t\t\tdone();\n\t\t\t\tclock.dispose();\n\t\t\t});\n\t\t\tsetTimeout(() => {\n\t\t\t\tclock.start(0);\n\t\t\t}, 100);\n\t\t\tsetTimeout(() => {\n\t\t\t\tclock.pause(0);\n\t\t\t}, 200);\n\t\t});\n\t});\n\n\tcontext(\"[get/set]Ticks\", () => {\n\t\tit(\"always reports 0 if not started\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 20);\n\t\t\t\texpect(clock.getTicksAtTime(0)).to.equal(0);\n\t\t\t\texpect(clock.getTicksAtTime(1)).to.equal(0);\n\t\t\t\texpect(clock.getTicksAtTime(2)).to.equal(0);\n\t\t\t\tclock.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get ticks in the future\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 20);\n\t\t\t\tclock.start(1);\n\t\t\t\texpect(clock.getTicksAtTime(1)).to.be.closeTo(0, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(1.5)).to.be.closeTo(10, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(2)).to.be.closeTo(20, 0.01);\n\t\t\t\tclock.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"pauses on last ticks\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 20);\n\t\t\t\tclock.start(0).pause(1);\n\t\t\t\texpect(clock.getTicksAtTime(0.5)).to.be.closeTo(10, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(1)).to.be.closeTo(20, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(2)).to.be.closeTo(20, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(3)).to.be.closeTo(20, 0.01);\n\t\t\t\tclock.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"resumes from paused position\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 20);\n\t\t\t\tclock.start(0).pause(1).start(2);\n\t\t\t\texpect(clock.getTicksAtTime(0.5)).to.be.closeTo(10, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(1)).to.be.closeTo(20, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(2)).to.be.closeTo(20, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(3)).to.be.closeTo(40, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(3.5)).to.be.closeTo(50, 0.01);\n\t\t\t\tclock.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get tick position after multiple pauses\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 10);\n\t\t\t\tclock.start(0).pause(1).start(2).pause(3).start(4);\n\t\t\t\texpect(clock.getTicksAtTime(0.5)).to.be.closeTo(5, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(1)).to.be.closeTo(10, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(2)).to.be.closeTo(10, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(3)).to.be.closeTo(20, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(4)).to.be.closeTo(20, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(5)).to.be.closeTo(30, 0.01);\n\t\t\t\tclock.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get tick position after multiple pauses and tempo scheduling\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 10);\n\t\t\t\tclock.frequency.setValueAtTime(100, 3.5);\n\t\t\t\tclock.start(0).pause(1).start(2).pause(3).start(4);\n\t\t\t\texpect(clock.getTicksAtTime(0.5)).to.be.closeTo(5, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(1)).to.be.closeTo(10, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(2)).to.be.closeTo(10, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(3)).to.be.closeTo(20, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(4)).to.be.closeTo(20, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(5)).to.be.closeTo(120, 0.01);\n\t\t\t\tclock.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get tick position after multiple pauses and setting ticks\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 10);\n\t\t\t\tclock.start(0).pause(1).start(2).pause(3).start(4);\n\t\t\t\tclock.setTicksAtTime(10, 2.5);\n\t\t\t\texpect(clock.getTicksAtTime(0.5)).to.be.closeTo(5, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(1)).to.be.closeTo(10, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(2)).to.be.closeTo(10, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(3)).to.be.closeTo(15, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(4)).to.be.closeTo(15, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(5)).to.be.closeTo(25, 0.01);\n\t\t\t\tclock.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"resumes from paused position with tempo scheduling\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 20);\n\t\t\t\tclock.start(0).pause(1).start(2);\n\t\t\t\tclock.frequency.setValueAtTime(20, 0);\n\t\t\t\tclock.frequency.setValueAtTime(10, 0.5);\n\t\t\t\texpect(clock.getTicksAtTime(0.5)).to.be.closeTo(10, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(1)).to.be.closeTo(15, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(2)).to.be.closeTo(15, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(3)).to.be.closeTo(25, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(3.5)).to.be.closeTo(30, 0.01);\n\t\t\t\tclock.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can set a tick value at the given time\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 20);\n\t\t\t\tclock.start(0);\n\t\t\t\tclock.setTicksAtTime(0, 1);\n\t\t\t\tclock.setTicksAtTime(0, 2);\n\t\t\t\texpect(clock.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(0.5)).to.be.closeTo(10, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(1)).to.be.closeTo(0, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(1.5)).to.be.closeTo(10, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(2)).to.be.closeTo(0, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(2.5)).to.be.closeTo(10, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(3)).to.be.closeTo(20, 0.01);\n\t\t\t\tclock.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get a tick position while the frequency is scheduled with setValueAtTime\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 20);\n\t\t\t\tclock.start(0);\n\t\t\t\tclock.frequency.setValueAtTime(2, 1);\n\t\t\t\tclock.setTicksAtTime(0, 1);\n\t\t\t\tclock.setTicksAtTime(0, 2);\n\t\t\t\texpect(clock.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(0.5)).to.be.closeTo(10, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(1)).to.be.closeTo(0, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(1.5)).to.be.closeTo(1, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(2)).to.be.closeTo(0, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(2.5)).to.be.closeTo(1, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(3)).to.be.closeTo(2, 0.01);\n\t\t\t\tclock.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get a tick position while the frequency is scheduled with linearRampTo\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 20);\n\t\t\t\tclock.start(0);\n\t\t\t\tclock.frequency.linearRampTo(2, 1, 1);\n\t\t\t\tclock.setTicksAtTime(0, 1);\n\t\t\t\tclock.setTicksAtTime(10, 2);\n\t\t\t\texpect(clock.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(0.5)).to.be.closeTo(10, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(1)).to.be.closeTo(0, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(1.5)).to.be.closeTo(7.75, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(2)).to.be.closeTo(10, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(2.5)).to.be.closeTo(11, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(3)).to.be.closeTo(12, 0.01);\n\t\t\t\tclock.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get a tick position while the frequency is scheduled with exponentialRampTo\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst clock = new Clock(noOp, 20);\n\t\t\t\tclock.start(0);\n\t\t\t\tclock.frequency.exponentialRampTo(2, 1, 1);\n\t\t\t\tclock.setTicksAtTime(0, 1);\n\t\t\t\tclock.setTicksAtTime(10, 2);\n\t\t\t\texpect(clock.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(0.5)).to.be.closeTo(10, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(1)).to.be.closeTo(0, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(1.5)).to.be.closeTo(5.96, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(2)).to.be.closeTo(10, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(2.5)).to.be.closeTo(11, 0.01);\n\t\t\t\texpect(clock.getTicksAtTime(3)).to.be.closeTo(12, 0.01);\n\t\t\t\tclock.dispose();\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/clock/Clock.ts",
    "content": "import {\n\tToneWithContext,\n\tToneWithContextOptions,\n} from \"../context/ToneWithContext.js\";\nimport { Frequency, Hertz, Seconds, Ticks, Time } from \"../type/Units.js\";\nimport { assertContextRunning } from \"../util/Debug.js\";\nimport { optionsFromArguments } from \"../util/Defaults.js\";\nimport { Emitter } from \"../util/Emitter.js\";\nimport { noOp, readOnly } from \"../util/Interface.js\";\nimport { PlaybackState, StateTimeline } from \"../util/StateTimeline.js\";\nimport { TickSignal } from \"./TickSignal.js\";\nimport { TickSource } from \"./TickSource.js\";\n\ntype ClockCallback = (time: Seconds, ticks?: Ticks) => void;\n\ninterface ClockOptions extends ToneWithContextOptions {\n\tfrequency: Hertz;\n\tcallback: ClockCallback;\n\tunits: \"hertz\" | \"bpm\";\n}\n\ntype ClockEvent = \"start\" | \"stop\" | \"pause\";\n\n/**\n * A sample-accurate clock that provides a callback at a given rate.\n *\n * While the callback is not sample-accurate (it is susceptible to\n * loose JavaScript timing), the time passed to the callback is precise.\n *\n * For most applications, it is better to use {@link Transport} instead of the\n * Clock by itself, since you can synchronize multiple callbacks.\n *\n * @example\n * // The callback will be invoked approximately once a second,\n * // and it will print the time exactly one second apart.\n * const clock = new Tone.Clock(time => {\n * \tconsole.log(time);\n * }, 1);\n * clock.start();\n * @category Core\n */\nexport class Clock<TypeName extends \"bpm\" | \"hertz\" = \"hertz\">\n\textends ToneWithContext<ClockOptions>\n\timplements Emitter<ClockEvent>\n{\n\treadonly name: string = \"Clock\";\n\n\t/**\n\t * The callback function to invoke at the scheduled tick.\n\t */\n\tcallback: ClockCallback = noOp;\n\n\t/**\n\t * The tick counter\n\t */\n\tprivate _tickSource: TickSource<TypeName>;\n\n\t/**\n\t * The last time the loop callback was invoked\n\t */\n\tprivate _lastUpdate = 0;\n\n\t/**\n\t * Keep track of the playback state\n\t */\n\tprivate _state: StateTimeline = new StateTimeline(\"stopped\");\n\n\t/**\n\t * Context bound reference to the _loop method\n\t * This is necessary to remove the event in the end.\n\t */\n\tprivate _boundLoop: () => void = this._loop.bind(this);\n\n\t/**\n\t * The rate the callback function should be invoked.\n\t */\n\tfrequency: TickSignal<TypeName>;\n\n\t/**\n\t * @param callback The callback to be invoked with the time of the audio event\n\t * @param frequency The rate of the callback\n\t */\n\tconstructor(callback?: ClockCallback, frequency?: Frequency);\n\tconstructor(options: Partial<ClockOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Clock.getDefaults(), arguments, [\n\t\t\t\"callback\",\n\t\t\t\"frequency\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis.callback = options.callback;\n\t\tthis._tickSource = new TickSource({\n\t\t\tcontext: this.context,\n\t\t\tfrequency: options.frequency,\n\t\t\tunits: options.units,\n\t\t});\n\t\tthis._lastUpdate = 0;\n\t\tthis.frequency = this._tickSource.frequency;\n\t\treadOnly(this, \"frequency\");\n\n\t\t// add an initial state\n\t\tthis._state.setStateAtTime(\"stopped\", 0);\n\n\t\t// bind a callback to the worker thread\n\t\tthis.context.on(\"tick\", this._boundLoop);\n\t}\n\n\tstatic getDefaults(): ClockOptions {\n\t\treturn Object.assign(ToneWithContext.getDefaults(), {\n\t\t\tcallback: noOp as ClockCallback,\n\t\t\tfrequency: 1,\n\t\t\tunits: \"hertz\",\n\t\t}) as ClockOptions;\n\t}\n\n\t/**\n\t * The playback state of the clock, either \"started\", \"stopped\", or \"paused\".\n\t */\n\tget state(): PlaybackState {\n\t\treturn this._state.getValueAtTime(this.now());\n\t}\n\n\t/**\n\t * Start the clock at the given time.\n\t * @param time The time the clock should start.\n\t * @param offset The number of ticks to start the clock from.\n\t */\n\tstart(time?: Time, offset?: Ticks): this {\n\t\t// make sure the context is running\n\t\tassertContextRunning(this.context);\n\t\t// start the loop\n\t\tconst computedTime = this.toSeconds(time);\n\t\tthis.log(\"start\", computedTime);\n\t\tif (this._state.getValueAtTime(computedTime) !== \"started\") {\n\t\t\tthis._state.setStateAtTime(\"started\", computedTime);\n\t\t\tthis._tickSource.start(computedTime, offset);\n\t\t\tif (computedTime < this._lastUpdate) {\n\t\t\t\tthis.emit(\"start\", computedTime, offset);\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop the clock. Stopping the clock resets the tick counter to 0.\n\t * @param time The time when the clock should stop.\n\t * @example\n\t * const clock = new Tone.Clock(time => {\n\t * \tconsole.log(time);\n\t * }, 1);\n\t * clock.start();\n\t * // Stop the clock after 10 seconds.\n\t * clock.stop(\"+10\");\n\t */\n\tstop(time?: Time): this {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tthis.log(\"stop\", computedTime);\n\t\tthis._state.cancel(computedTime);\n\t\tthis._state.setStateAtTime(\"stopped\", computedTime);\n\t\tthis._tickSource.stop(computedTime);\n\t\tif (computedTime < this._lastUpdate) {\n\t\t\tthis.emit(\"stop\", computedTime);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Pause the clock. Pausing does not reset the tick counter.\n\t * @param time The time when the clock should pause.\n\t */\n\tpause(time?: Time): this {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tif (this._state.getValueAtTime(computedTime) === \"started\") {\n\t\t\tthis._state.setStateAtTime(\"paused\", computedTime);\n\t\t\tthis._tickSource.pause(computedTime);\n\t\t\tif (computedTime < this._lastUpdate) {\n\t\t\t\tthis.emit(\"pause\", computedTime);\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * The number of times the callback has been invoked.\n\t *\n\t * Starts counting at 0 and increments after the callback is invoked.\n\t */\n\tget ticks(): Ticks {\n\t\treturn Math.ceil(this.getTicksAtTime(this.now()));\n\t}\n\tset ticks(t: Ticks) {\n\t\tthis._tickSource.ticks = t;\n\t}\n\n\t/**\n\t * The time since ticks=0 that the clock has been running.\n\t *\n\t * Accounts for tempo curves.\n\t */\n\tget seconds(): Seconds {\n\t\treturn this._tickSource.seconds;\n\t}\n\tset seconds(s: Seconds) {\n\t\tthis._tickSource.seconds = s;\n\t}\n\n\t/**\n\t * Return the elapsed seconds at the given time.\n\t * @param time When to get the elapsed seconds.\n\t * @return The number of elapsed seconds.\n\t */\n\tgetSecondsAtTime(time: Time): Seconds {\n\t\treturn this._tickSource.getSecondsAtTime(time);\n\t}\n\n\t/**\n\t * Set the clock's ticks at the given time.\n\t * @param ticks The tick value to set.\n\t * @param time When to set the tick value.\n\t */\n\tsetTicksAtTime(ticks: Ticks, time: Time): this {\n\t\tthis._tickSource.setTicksAtTime(ticks, time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Get the time of the given tick.\n\t *\n\t * The second argument is when to test before. Since ticks can be set\n\t * (with {@link setTicksAtTime}), there may be multiple times for a given\n\t * tick value.\n\t *\n\t * @param tick The tick number.\n\t * @param before When to measure the tick value from.\n\t * @return The time of the tick\n\t */\n\tgetTimeOfTick(tick: Ticks, before = this.now()): Seconds {\n\t\treturn this._tickSource.getTimeOfTick(tick, before);\n\t}\n\n\t/**\n\t * Get the clock's ticks at the given time.\n\t * @param time When to get the tick value.\n\t * @return The tick value at the given time.\n\t */\n\tgetTicksAtTime(time?: Time): Ticks {\n\t\treturn this._tickSource.getTicksAtTime(time);\n\t}\n\n\t/**\n\t * Get the time of the next tick.\n\t * @param offset The tick number.\n\t */\n\tnextTickTime(offset: Ticks, when: Time): Seconds {\n\t\tconst computedTime = this.toSeconds(when);\n\t\tconst currentTick = this.getTicksAtTime(computedTime);\n\t\treturn this._tickSource.getTimeOfTick(\n\t\t\tcurrentTick + offset,\n\t\t\tcomputedTime\n\t\t);\n\t}\n\n\t/**\n\t * The scheduling loop.\n\t */\n\tprivate _loop(): void {\n\t\tconst startTime = this._lastUpdate;\n\t\tconst endTime = this.now();\n\t\tthis._lastUpdate = endTime;\n\t\tthis.log(\"loop\", startTime, endTime);\n\n\t\tif (startTime !== endTime) {\n\t\t\t// the state change events\n\t\t\tthis._state.forEachBetween(startTime, endTime, (e) => {\n\t\t\t\tswitch (e.state) {\n\t\t\t\t\tcase \"started\":\n\t\t\t\t\t\tconst offset = this._tickSource.getTicksAtTime(e.time);\n\t\t\t\t\t\tthis.emit(\"start\", e.time, offset);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"stopped\":\n\t\t\t\t\t\tif (e.time !== 0) {\n\t\t\t\t\t\t\tthis.emit(\"stop\", e.time);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"paused\":\n\t\t\t\t\t\tthis.emit(\"pause\", e.time);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t});\n\t\t\t// the tick callbacks\n\t\t\tthis._tickSource.forEachTickBetween(\n\t\t\t\tstartTime,\n\t\t\t\tendTime,\n\t\t\t\t(time, ticks) => {\n\t\t\t\t\tthis.callback(time, ticks);\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Returns the scheduled state at the given time.\n\t * @param  time  The time to query.\n\t * @return  The name of the state input in setStateAtTime.\n\t * @example\n\t * const clock = new Tone.Clock();\n\t * clock.start(\"+0.1\");\n\t * clock.getStateAtTime(\"+0.1\"); // returns \"started\"\n\t */\n\tgetStateAtTime(time: Time): PlaybackState {\n\t\tconst computedTime = this.toSeconds(time);\n\t\treturn this._state.getValueAtTime(computedTime);\n\t}\n\n\t/**\n\t * Clean up\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.context.off(\"tick\", this._boundLoop);\n\t\tthis._tickSource.dispose();\n\t\tthis._state.dispose();\n\t\treturn this;\n\t}\n\n\t//-------------------------------------\n\t// EMITTER MIXIN TO SATISFY COMPILER\n\t//-------------------------------------\n\n\ton!: (event: ClockEvent, callback: (...args: any[]) => void) => this;\n\tonce!: (event: ClockEvent, callback: (...args: any[]) => void) => this;\n\toff!: (\n\t\tevent: ClockEvent,\n\t\tcallback?: ((...args: any[]) => void) | undefined\n\t) => this;\n\temit!: (event: any, ...args: any[]) => this;\n}\n\nEmitter.mixin(Clock);\n"
  },
  {
    "path": "Tone/core/clock/TickParam.test.ts",
    "content": "import { BasicTests, testAudioContext } from \"../../../test/helper/Basic.js\";\n// import { atTime, Offline } from \"../../../test/helper/Offline\";\nimport { TickParam } from \"./TickParam.js\";\n\ndescribe(\"TickParam\", () => {\n\t// sanity checks\n\tBasicTests(TickParam, {\n\t\tcontext: testAudioContext,\n\t\tparam: testAudioContext.createOscillator().frequency,\n\t});\n});\n"
  },
  {
    "path": "Tone/core/clock/TickParam.ts",
    "content": "import { AutomationEvent, Param, ParamOptions } from \"../context/Param.js\";\nimport { Seconds, Ticks, Time, UnitMap, UnitName } from \"../type/Units.js\";\nimport { optionsFromArguments } from \"../util/Defaults.js\";\nimport { Timeline } from \"../util/Timeline.js\";\nimport { isUndef } from \"../util/TypeCheck.js\";\n\ntype TickAutomationEvent = AutomationEvent & {\n\tticks: number;\n};\n\ninterface TickParamOptions<TypeName extends UnitName>\n\textends ParamOptions<TypeName> {\n\tmultiplier: number;\n}\n\n/**\n * A Param class just for computing ticks. Similar to the {@link Param} class,\n * but offers conversion to BPM values as well as ability to compute tick\n * duration and elapsed ticks\n */\nexport class TickParam<\n\tTypeName extends \"hertz\" | \"bpm\",\n> extends Param<TypeName> {\n\treadonly name: string = \"TickParam\";\n\n\t/**\n\t * The timeline which tracks all of the automations.\n\t */\n\tprotected _events: Timeline<TickAutomationEvent> = new Timeline(Infinity);\n\n\t/**\n\t * The internal holder for the multiplier value\n\t */\n\tprivate _multiplier = 1;\n\n\t/**\n\t * @param param The AudioParam to wrap\n\t * @param units The unit name\n\t * @param convert Whether or not to convert the value to the target units\n\t */\n\t/**\n\t * @param value The initial value of the signal\n\t */\n\tconstructor(value?: number);\n\tconstructor(options: Partial<TickParamOptions<TypeName>>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tTickParam.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"value\"]\n\t\t);\n\t\tsuper(options);\n\n\t\t// set the multiplier\n\t\tthis._multiplier = options.multiplier;\n\n\t\t// clear the ticks from the beginning\n\t\tthis._events.cancel(0);\n\t\t// set an initial event\n\t\tthis._events.add({\n\t\t\tticks: 0,\n\t\t\ttime: 0,\n\t\t\ttype: \"setValueAtTime\",\n\t\t\tvalue: this._fromType(options.value),\n\t\t});\n\t\tthis.setValueAtTime(options.value, 0);\n\t}\n\n\tstatic getDefaults(): TickParamOptions<any> {\n\t\treturn Object.assign(Param.getDefaults(), {\n\t\t\tmultiplier: 1,\n\t\t\tunits: \"hertz\",\n\t\t\tvalue: 1,\n\t\t});\n\t}\n\n\tsetTargetAtTime(\n\t\tvalue: UnitMap[TypeName],\n\t\ttime: Time,\n\t\tconstant: number\n\t): this {\n\t\t// approximate it with multiple linear ramps\n\t\ttime = this.toSeconds(time);\n\t\tthis.setRampPoint(time);\n\t\tconst computedValue = this._fromType(value);\n\n\t\t// start from previously scheduled value\n\t\tconst prevEvent = this._events.get(time) as TickAutomationEvent;\n\t\tconst segments = Math.round(Math.max(1 / constant, 1));\n\t\tfor (let i = 0; i <= segments; i++) {\n\t\t\tconst segTime = constant * i + time;\n\t\t\tconst rampVal = this._exponentialApproach(\n\t\t\t\tprevEvent.time,\n\t\t\t\tprevEvent.value,\n\t\t\t\tcomputedValue,\n\t\t\t\tconstant,\n\t\t\t\tsegTime\n\t\t\t);\n\t\t\tthis.linearRampToValueAtTime(this._toType(rampVal), segTime);\n\t\t}\n\t\treturn this;\n\t}\n\n\tsetValueAtTime(value: UnitMap[TypeName], time: Time): this {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tsuper.setValueAtTime(value, time);\n\t\tconst event = this._events.get(computedTime) as TickAutomationEvent;\n\t\tconst previousEvent = this._events.previousEvent(event);\n\t\tconst ticksUntilTime = this._getTicksUntilEvent(\n\t\t\tpreviousEvent,\n\t\t\tcomputedTime\n\t\t);\n\t\tevent.ticks = Math.max(ticksUntilTime, 0);\n\t\treturn this;\n\t}\n\n\tlinearRampToValueAtTime(value: UnitMap[TypeName], time: Time): this {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tsuper.linearRampToValueAtTime(value, time);\n\t\tconst event = this._events.get(computedTime) as TickAutomationEvent;\n\t\tconst previousEvent = this._events.previousEvent(event);\n\t\tconst ticksUntilTime = this._getTicksUntilEvent(\n\t\t\tpreviousEvent,\n\t\t\tcomputedTime\n\t\t);\n\t\tevent.ticks = Math.max(ticksUntilTime, 0);\n\t\treturn this;\n\t}\n\n\texponentialRampToValueAtTime(value: UnitMap[TypeName], time: Time): this {\n\t\t// approximate it with multiple linear ramps\n\t\ttime = this.toSeconds(time);\n\t\tconst computedVal = this._fromType(value);\n\n\t\t// start from previously scheduled value\n\t\tconst prevEvent = this._events.get(time) as TickAutomationEvent;\n\t\t// approx 10 segments per second\n\t\tconst segments = Math.round(Math.max((time - prevEvent.time) * 10, 1));\n\t\tconst segmentDur = (time - prevEvent.time) / segments;\n\t\tfor (let i = 0; i <= segments; i++) {\n\t\t\tconst segTime = segmentDur * i + prevEvent.time;\n\t\t\tconst rampVal = this._exponentialInterpolate(\n\t\t\t\tprevEvent.time,\n\t\t\t\tprevEvent.value,\n\t\t\t\ttime,\n\t\t\t\tcomputedVal,\n\t\t\t\tsegTime\n\t\t\t);\n\t\t\tthis.linearRampToValueAtTime(this._toType(rampVal), segTime);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Returns the tick value at the time. Takes into account\n\t * any automation curves scheduled on the signal.\n\t * @param  event The time to get the tick count at\n\t * @return The number of ticks which have elapsed at the time given any automations.\n\t */\n\tprivate _getTicksUntilEvent(\n\t\tevent: TickAutomationEvent | null,\n\t\ttime: number\n\t): Ticks {\n\t\tif (event === null) {\n\t\t\tevent = {\n\t\t\t\tticks: 0,\n\t\t\t\ttime: 0,\n\t\t\t\ttype: \"setValueAtTime\",\n\t\t\t\tvalue: 0,\n\t\t\t};\n\t\t} else if (isUndef(event.ticks)) {\n\t\t\tconst previousEvent = this._events.previousEvent(event);\n\t\t\tevent.ticks = this._getTicksUntilEvent(previousEvent, event.time);\n\t\t}\n\t\tconst val0 = this._fromType(this.getValueAtTime(event.time));\n\t\tlet val1 = this._fromType(this.getValueAtTime(time));\n\t\t// if it's right on the line, take the previous value\n\t\tconst onTheLineEvent = this._events.get(time);\n\t\tif (\n\t\t\tonTheLineEvent &&\n\t\t\tonTheLineEvent.time === time &&\n\t\t\tonTheLineEvent.type === \"setValueAtTime\"\n\t\t) {\n\t\t\tval1 = this._fromType(this.getValueAtTime(time - this.sampleTime));\n\t\t}\n\t\treturn 0.5 * (time - event.time) * (val0 + val1) + event.ticks;\n\t}\n\n\t/**\n\t * Returns the tick value at the time. Takes into account\n\t * any automation curves scheduled on the signal.\n\t * @param  time The time to get the tick count at\n\t * @return The number of ticks which have elapsed at the time given any automations.\n\t */\n\tgetTicksAtTime(time: Time): Ticks {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tconst event = this._events.get(computedTime);\n\t\treturn Math.max(this._getTicksUntilEvent(event, computedTime), 0);\n\t}\n\n\t/**\n\t * Return the elapsed time of the number of ticks from the given time\n\t * @param ticks The number of ticks to calculate\n\t * @param  time The time to get the next tick from\n\t * @return The duration of the number of ticks from the given time in seconds\n\t */\n\tgetDurationOfTicks(ticks: Ticks, time: Time): Seconds {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tconst currentTick = this.getTicksAtTime(time);\n\t\treturn this.getTimeOfTick(currentTick + ticks) - computedTime;\n\t}\n\n\t/**\n\t * Given a tick, returns the time that tick occurs at.\n\t * @return The time that the tick occurs.\n\t */\n\tgetTimeOfTick(tick: Ticks): Seconds {\n\t\tconst before = this._events.get(tick, \"ticks\");\n\t\tconst after = this._events.getAfter(tick, \"ticks\");\n\t\tif (before && before.ticks === tick) {\n\t\t\treturn before.time;\n\t\t} else if (\n\t\t\tbefore &&\n\t\t\tafter &&\n\t\t\tafter.type === \"linearRampToValueAtTime\" &&\n\t\t\tbefore.value !== after.value\n\t\t) {\n\t\t\tconst val0 = this._fromType(this.getValueAtTime(before.time));\n\t\t\tconst val1 = this._fromType(this.getValueAtTime(after.time));\n\t\t\tconst delta = (val1 - val0) / (after.time - before.time);\n\t\t\tconst k = Math.sqrt(\n\t\t\t\tMath.pow(val0, 2) - 2 * delta * (before.ticks - tick)\n\t\t\t);\n\t\t\tconst sol1 = (-val0 + k) / delta;\n\t\t\tconst sol2 = (-val0 - k) / delta;\n\t\t\treturn (sol1 > 0 ? sol1 : sol2) + before.time;\n\t\t} else if (before) {\n\t\t\tif (before.value === 0) {\n\t\t\t\treturn Infinity;\n\t\t\t} else {\n\t\t\t\treturn before.time + (tick - before.ticks) / before.value;\n\t\t\t}\n\t\t} else {\n\t\t\treturn tick / this._initialValue;\n\t\t}\n\t}\n\n\t/**\n\t * Convert some number of ticks their the duration in seconds accounting\n\t * for any automation curves starting at the given time.\n\t * @param  ticks The number of ticks to convert to seconds.\n\t * @param  when  When along the automation timeline to convert the ticks.\n\t * @return The duration in seconds of the ticks.\n\t */\n\tticksToTime(ticks: Ticks, when: Time): Seconds {\n\t\treturn this.getDurationOfTicks(ticks, when);\n\t}\n\n\t/**\n\t * The inverse of {@link ticksToTime}. Convert a duration in\n\t * seconds to the corresponding number of ticks accounting for any\n\t * automation curves starting at the given time.\n\t * @param  duration The time interval to convert to ticks.\n\t * @param  when When along the automation timeline to convert the ticks.\n\t * @return The duration in ticks.\n\t */\n\ttimeToTicks(duration: Time, when: Time): Ticks {\n\t\tconst computedTime = this.toSeconds(when);\n\t\tconst computedDuration = this.toSeconds(duration);\n\t\tconst startTicks = this.getTicksAtTime(computedTime);\n\t\tconst endTicks = this.getTicksAtTime(computedTime + computedDuration);\n\t\treturn endTicks - startTicks;\n\t}\n\n\t/**\n\t * Convert from the type when the unit value is BPM\n\t */\n\tprotected _fromType(val: UnitMap[TypeName]): number {\n\t\tif (this.units === \"bpm\" && this.multiplier) {\n\t\t\treturn 1 / (60 / val / this.multiplier);\n\t\t} else {\n\t\t\treturn super._fromType(val);\n\t\t}\n\t}\n\n\t/**\n\t * Special case of type conversion where the units === \"bpm\"\n\t */\n\tprotected _toType(val: number): UnitMap[TypeName] {\n\t\tif (this.units === \"bpm\" && this.multiplier) {\n\t\t\treturn ((val / this.multiplier) * 60) as UnitMap[TypeName];\n\t\t} else {\n\t\t\treturn super._toType(val);\n\t\t}\n\t}\n\t/**\n\t * A multiplier on the bpm value. Useful for setting a PPQ relative to the base frequency value.\n\t */\n\tget multiplier(): number {\n\t\treturn this._multiplier;\n\t}\n\tset multiplier(m: number) {\n\t\t// get and reset the current value with the new multiplier\n\t\t// might be necessary to clear all the previous values\n\t\tconst currentVal = this.value;\n\t\tthis._multiplier = m;\n\t\tthis.cancelScheduledValues(0);\n\t\tthis.setValueAtTime(currentVal, 0);\n\t}\n}\n"
  },
  {
    "path": "Tone/core/clock/TickSignal.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { TickSignal } from \"./TickSignal.js\";\n\ndescribe(\"TickSignal\", () => {\n\tBasicTests(TickSignal);\n\n\tit(\"can be created and disposed\", () => {\n\t\tconst tickSignal = new TickSignal();\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"can schedule a change in the future\", () => {\n\t\tconst tickSignal = new TickSignal(1);\n\t\ttickSignal.setValueAtTime(2, 0.2);\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"can schedule a ramp in the future\", () => {\n\t\tconst tickSignal = new TickSignal(1);\n\t\ttickSignal.setValueAtTime(2, 0);\n\t\ttickSignal.linearRampToValueAtTime(0.1, 0.2);\n\t\ttickSignal.exponentialRampToValueAtTime(1, 0.4);\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"calculates the ticks when no changes are scheduled\", () => {\n\t\tconst tickSignal0 = new TickSignal(2);\n\t\texpect(tickSignal0.getTicksAtTime(1)).to.be.closeTo(2, 0.01);\n\t\texpect(tickSignal0.getTicksAtTime(2)).to.be.closeTo(4, 0.01);\n\t\texpect(tickSignal0.getTimeOfTick(4)).to.be.closeTo(2, 0.01);\n\t\ttickSignal0.dispose();\n\n\t\tconst tickSignal1 = new TickSignal(1);\n\t\texpect(tickSignal1.getTicksAtTime(1)).to.be.closeTo(1, 0.01);\n\t\texpect(tickSignal1.getTicksAtTime(2)).to.be.closeTo(2, 0.01);\n\t\texpect(tickSignal1.getTimeOfTick(2)).to.be.closeTo(2, 0.01);\n\t\ttickSignal1.dispose();\n\t});\n\n\tit(\"calculates the ticks in the future when a setValueAtTime is scheduled\", () => {\n\t\tconst tickSignal = new TickSignal(1);\n\t\ttickSignal.setValueAtTime(2, 0.5);\n\t\texpect(tickSignal.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\texpect(tickSignal.getTicksAtTime(0.5)).to.be.closeTo(0.5, 0.01);\n\t\texpect(tickSignal.getTicksAtTime(0.75)).to.be.closeTo(1, 0.01);\n\t\texpect(tickSignal.getTicksAtTime(1)).to.be.closeTo(1.5, 0.01);\n\t\texpect(tickSignal.getTimeOfTick(1.5)).to.be.closeTo(1, 0.01);\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"calculates the ticks in the future when multiple setValueAtTime are scheduled\", () => {\n\t\tconst tickSignal = new TickSignal(1);\n\t\ttickSignal.setValueAtTime(2, 1);\n\t\ttickSignal.setValueAtTime(4, 2);\n\t\texpect(tickSignal.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\texpect(tickSignal.getTicksAtTime(0.5)).to.be.closeTo(0.5, 0.01);\n\t\texpect(tickSignal.getTicksAtTime(1)).to.be.closeTo(1, 0.01);\n\t\texpect(tickSignal.getTicksAtTime(1.5)).to.be.closeTo(2, 0.01);\n\t\texpect(tickSignal.getTicksAtTime(2)).to.be.closeTo(3, 0.01);\n\t\texpect(tickSignal.getTicksAtTime(2.5)).to.be.closeTo(5, 0.01);\n\t\texpect(tickSignal.getTicksAtTime(3)).to.be.closeTo(7, 0.01);\n\t\texpect(tickSignal.getTimeOfTick(7)).to.be.closeTo(3, 0.01);\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"if ticks are 0, getTicksAtTime will return 0\", () => {\n\t\tconst tickSignal = new TickSignal(0);\n\t\ttickSignal.setValueAtTime(0, 1);\n\t\ttickSignal.linearRampToValueAtTime(0, 2);\n\t\texpect(tickSignal.getTicksAtTime(0)).to.equal(0);\n\t\texpect(tickSignal.getTicksAtTime(1)).to.equal(0);\n\t\texpect(tickSignal.getTicksAtTime(2)).to.equal(0);\n\t\texpect(tickSignal.getTicksAtTime(3)).to.equal(0);\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"calculates the ticks in the future when a linearRampToValueAtTime is scheduled\", () => {\n\t\tconst tickSignal = new TickSignal(1);\n\t\ttickSignal.setValueAtTime(1, 0);\n\t\ttickSignal.linearRampToValueAtTime(2, 1);\n\t\texpect(tickSignal.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\texpect(tickSignal.getTicksAtTime(0.5)).to.be.closeTo(0.62, 0.01);\n\t\texpect(tickSignal.getTicksAtTime(1)).to.be.closeTo(1.5, 0.01);\n\t\texpect(tickSignal.getTicksAtTime(2)).to.be.closeTo(3.5, 0.01);\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"calculates the ticks in the future when multiple linearRampToValueAtTime are scheduled\", () => {\n\t\tconst tickSignal = new TickSignal(1);\n\t\ttickSignal.setValueAtTime(1, 0);\n\t\ttickSignal.linearRampToValueAtTime(2, 1);\n\t\ttickSignal.linearRampToValueAtTime(0, 2);\n\t\texpect(tickSignal.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\texpect(tickSignal.getTicksAtTime(0.5)).to.be.closeTo(0.62, 0.01);\n\t\texpect(tickSignal.getTicksAtTime(1)).to.be.closeTo(1.5, 0.01);\n\t\texpect(tickSignal.getTicksAtTime(2)).to.be.closeTo(2.5, 0.01);\n\t\texpect(tickSignal.getTicksAtTime(3)).to.be.closeTo(2.5, 0.01);\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"calculates the ticks in the future when a exponentialRampToValueAtTime is scheduled\", () => {\n\t\tconst tickSignal = new TickSignal(1);\n\t\ttickSignal.setValueAtTime(1, 0);\n\t\ttickSignal.exponentialRampToValueAtTime(2, 1);\n\t\texpect(tickSignal.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\texpect(tickSignal.getTicksAtTime(0.5)).to.be.closeTo(0.6, 0.01);\n\t\texpect(tickSignal.getTicksAtTime(1)).to.be.closeTo(1.5, 0.1);\n\t\texpect(tickSignal.getTicksAtTime(2)).to.be.closeTo(3.5, 0.1);\n\t\texpect(tickSignal.getTicksAtTime(3)).to.be.closeTo(5.5, 0.1);\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"calculates the ticks in the future when multiple exponentialRampToValueAtTime are scheduled\", () => {\n\t\tconst tickSignal = new TickSignal(1);\n\t\ttickSignal.setValueAtTime(1, 0);\n\t\ttickSignal.exponentialRampToValueAtTime(2, 1);\n\t\ttickSignal.exponentialRampToValueAtTime(0, 2);\n\t\texpect(tickSignal.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\texpect(tickSignal.getTicksAtTime(0.5)).to.be.closeTo(0.6, 0.01);\n\t\texpect(tickSignal.getTicksAtTime(1)).to.be.closeTo(1.5, 0.1);\n\t\texpect(tickSignal.getTicksAtTime(2)).to.be.closeTo(1.54, 0.1);\n\t\texpect(tickSignal.getTicksAtTime(3)).to.be.closeTo(1.54, 0.1);\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"computes the time of a given tick when setTargetAtTime is scheduled\", () => {\n\t\tconst tickSignal = new TickSignal(1);\n\t\ttickSignal.setTargetAtTime(0.5, 0, 0.1);\n\t\texpect(tickSignal.getTimeOfTick(0)).to.be.closeTo(0, 0.01);\n\t\texpect(tickSignal.getTimeOfTick(1)).to.be.closeTo(1.89, 0.01);\n\t\texpect(tickSignal.getTimeOfTick(2)).to.be.closeTo(3.89, 0.01);\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"computes the time of a given tick when multiple setTargetAtTime are scheduled\", () => {\n\t\tconst tickSignal = new TickSignal(1);\n\t\ttickSignal.setTargetAtTime(0.5, 0, 0.1);\n\t\ttickSignal.setTargetAtTime(2, 1, 1);\n\t\texpect(tickSignal.getTimeOfTick(0)).to.be.closeTo(0, 0.01);\n\t\texpect(tickSignal.getTimeOfTick(1)).to.be.closeTo(1.5, 0.1);\n\t\texpect(tickSignal.getTimeOfTick(2)).to.be.closeTo(2.28, 0.1);\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"computes the time of a given tick when nothing is scheduled\", () => {\n\t\tconst tickSignal0 = new TickSignal(1);\n\t\texpect(tickSignal0.getTimeOfTick(0)).to.be.closeTo(0, 0.01);\n\t\texpect(tickSignal0.getTimeOfTick(1)).to.be.closeTo(1, 0.01);\n\t\texpect(tickSignal0.getTimeOfTick(2)).to.be.closeTo(2, 0.01);\n\t\texpect(tickSignal0.getTimeOfTick(3)).to.be.closeTo(3, 0.01);\n\t\ttickSignal0.dispose();\n\n\t\tconst tickSignal = new TickSignal(2);\n\t\texpect(tickSignal.getTimeOfTick(0)).to.be.closeTo(0, 0.01);\n\t\texpect(tickSignal.getTimeOfTick(1)).to.be.closeTo(0.5, 0.01);\n\t\texpect(tickSignal.getTimeOfTick(2)).to.be.closeTo(1, 0.01);\n\t\texpect(tickSignal.getTimeOfTick(3)).to.be.closeTo(1.5, 0.01);\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"computes the time of a given tick when setValueAtTime is scheduled\", () => {\n\t\tconst tickSignal = new TickSignal(1);\n\t\ttickSignal.setValueAtTime(0.5, 1);\n\t\texpect(tickSignal.getTimeOfTick(0)).to.be.closeTo(0, 0.01);\n\t\texpect(tickSignal.getTimeOfTick(1)).to.be.closeTo(1, 0.01);\n\t\texpect(tickSignal.getTimeOfTick(2)).to.be.closeTo(3, 0.01);\n\t\texpect(tickSignal.getTimeOfTick(3)).to.be.closeTo(5, 0.01);\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"returns Infinity if the tick interval is 0\", () => {\n\t\tconst tickSignal = new TickSignal(0);\n\t\texpect(tickSignal.getTimeOfTick(1)).to.equal(Infinity);\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"computes the time of a given tick when multiple setValueAtTime are scheduled\", () => {\n\t\tconst tickSignal = new TickSignal(1);\n\t\ttickSignal.setValueAtTime(0.5, 1);\n\t\ttickSignal.setValueAtTime(0, 2);\n\t\texpect(tickSignal.getTimeOfTick(0)).to.be.closeTo(0, 0.01);\n\t\texpect(tickSignal.getTimeOfTick(1)).to.be.closeTo(1, 0.01);\n\t\texpect(tickSignal.getTimeOfTick(1.499)).to.be.closeTo(2, 0.01);\n\t\texpect(tickSignal.getTimeOfTick(2)).to.equal(Infinity);\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"computes the time of a given tick when a linearRampToValueAtTime is scheduled\", () => {\n\t\tconst tickSignal = new TickSignal(1);\n\t\ttickSignal.setValueAtTime(1, 0);\n\t\ttickSignal.linearRampToValueAtTime(2, 1);\n\t\texpect(tickSignal.getTimeOfTick(0)).to.be.closeTo(0, 0.01);\n\t\texpect(tickSignal.getTimeOfTick(1)).to.be.closeTo(0.75, 0.1);\n\t\texpect(tickSignal.getTimeOfTick(2)).to.be.closeTo(1.25, 0.1);\n\t\texpect(tickSignal.getTimeOfTick(3)).to.be.closeTo(1.75, 0.1);\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"computes the time of a given tick when multiple linearRampToValueAtTime are scheduled\", () => {\n\t\tconst tickSignal = new TickSignal(1);\n\t\ttickSignal.setValueAtTime(1, 0);\n\t\ttickSignal.linearRampToValueAtTime(2, 1);\n\t\ttickSignal.linearRampToValueAtTime(0, 2);\n\t\texpect(tickSignal.getTimeOfTick(0)).to.be.closeTo(0, 0.1);\n\t\texpect(tickSignal.getTimeOfTick(1)).to.be.closeTo(0.75, 0.1);\n\t\texpect(tickSignal.getTimeOfTick(2)).to.be.closeTo(1.25, 0.1);\n\t\texpect(tickSignal.getTimeOfTick(3)).to.equal(Infinity);\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"computes the time of a given tick when a exponentialRampToValueAtTime is scheduled\", () => {\n\t\tconst tickSignal = new TickSignal(1);\n\t\ttickSignal.exponentialRampToValueAtTime(2, 1);\n\t\texpect(tickSignal.getTimeOfTick(0)).to.be.closeTo(0, 0.01);\n\t\texpect(tickSignal.getTimeOfTick(2)).to.be.closeTo(1.25, 0.1);\n\t\texpect(tickSignal.getTimeOfTick(3)).to.be.closeTo(1.75, 0.1);\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"computes the time of a given tick when multiple exponentialRampToValueAtTime are scheduled\", () => {\n\t\tconst tickSignal = new TickSignal(1);\n\t\ttickSignal.setValueAtTime(1, 0);\n\t\ttickSignal.exponentialRampToValueAtTime(2, 1);\n\t\ttickSignal.exponentialRampToValueAtTime(0, 2);\n\t\texpect(tickSignal.getTimeOfTick(0)).to.be.closeTo(0, 0.01);\n\t\texpect(tickSignal.getTimeOfTick(0.5)).to.be.closeTo(0.5, 0.1);\n\t\texpect(tickSignal.getTimeOfTick(1.5)).to.be.closeTo(1, 0.1);\n\t\texpect(tickSignal.getTimeOfTick(3)).to.equal(Infinity);\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"can schedule multiple types of curves\", () => {\n\t\tconst tickSignal = new TickSignal(1);\n\t\ttickSignal.setValueAtTime(1, 0);\n\t\ttickSignal.exponentialRampToValueAtTime(4, 1);\n\t\ttickSignal.linearRampToValueAtTime(0.2, 2);\n\t\ttickSignal.setValueAtTime(2, 3);\n\t\ttickSignal.linearRampToValueAtTime(2, 4);\n\t\ttickSignal.setTargetAtTime(8, 5, 0.2);\n\n\t\tfor (let time = 0; time < 5; time += 0.2) {\n\t\t\tconst tick = tickSignal.getTicksAtTime(time);\n\t\t\texpect(tickSignal.getTimeOfTick(tick)).to.be.closeTo(time, 0.1);\n\t\t}\n\n\t\ttickSignal.dispose();\n\t});\n\n\tit(\"can get the duration of a tick at any point in time\", () => {\n\t\tconst tickSignal = new TickSignal(1);\n\t\ttickSignal.setValueAtTime(2, 1);\n\t\ttickSignal.setValueAtTime(10, 2);\n\t\texpect(tickSignal.getDurationOfTicks(1, 0)).to.be.closeTo(1, 0.01);\n\t\texpect(tickSignal.getDurationOfTicks(1, 1)).to.be.closeTo(0.5, 0.01);\n\t\texpect(tickSignal.getDurationOfTicks(1, 2)).to.be.closeTo(0.1, 0.01);\n\t\texpect(tickSignal.getDurationOfTicks(2, 1.5)).to.be.closeTo(0.6, 0.01);\n\t});\n\n\tcontext(\"BPM / PPQ\", () => {\n\t\tit(\"can be set as PPQ\", () => {\n\t\t\tconst tickSignal = new TickSignal({\n\t\t\t\tmultiplier: 10,\n\t\t\t\tunits: \"bpm\",\n\t\t\t\tvalue: 120,\n\t\t\t});\n\t\t\texpect(tickSignal.multiplier).to.equal(10);\n\t\t\texpect(tickSignal.getTicksAtTime(1)).to.be.closeTo(20, 0.01);\n\t\t\texpect(tickSignal.getTicksAtTime(2)).to.be.closeTo(40, 0.01);\n\t\t\texpect(tickSignal.getTimeOfTick(40)).to.be.closeTo(2, 0.01);\n\t\t\ttickSignal.dispose();\n\t\t});\n\n\t\tit(\"calculates the ticks in the future when multiple setValueAtTime are scheduled\", () => {\n\t\t\tconst tickSignal = new TickSignal({\n\t\t\t\tmultiplier: 20,\n\t\t\t\tunits: \"bpm\",\n\t\t\t\tvalue: 60,\n\t\t\t});\n\t\t\ttickSignal.setValueAtTime(120, 1);\n\t\t\ttickSignal.setValueAtTime(180, 2);\n\t\t\texpect(tickSignal.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(tickSignal.getTicksAtTime(0.5)).to.be.closeTo(10, 0.01);\n\t\t\texpect(tickSignal.getTicksAtTime(1)).to.be.closeTo(20, 0.01);\n\t\t\texpect(tickSignal.getTicksAtTime(1.5)).to.be.closeTo(40, 0.01);\n\t\t\texpect(tickSignal.getTicksAtTime(2)).to.be.closeTo(60, 0.01);\n\t\t\texpect(tickSignal.getTicksAtTime(2.5)).to.be.closeTo(90, 0.01);\n\t\t\texpect(tickSignal.getTicksAtTime(3)).to.be.closeTo(120, 0.01);\n\t\t\texpect(tickSignal.getTimeOfTick(120)).to.be.closeTo(3, 0.01);\n\t\t\ttickSignal.dispose();\n\t\t});\n\t});\n\n\tit(\"outputs a signal\", async () => {\n\t\tconst buffer = await Offline((context) => {\n\t\t\tconst sched = new TickSignal(1).connect(context.destination);\n\t\t\tsched.linearRampTo(3, 1, 0);\n\t\t}, 1.01);\n\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(1, 0.01);\n\t\texpect(buffer.getValueAtTime(0.5)).to.be.closeTo(2, 0.01);\n\t\texpect(buffer.getValueAtTime(1)).to.be.closeTo(3, 0.01);\n\t});\n\n\tit(\"outputs a signal with bpm units\", async () => {\n\t\tconst buffer = await Offline((context) => {\n\t\t\tconst sched = new TickSignal({\n\t\t\t\tunits: \"bpm\",\n\t\t\t\tvalue: 120,\n\t\t\t}).connect(context.destination);\n\t\t\tsched.linearRampTo(60, 1, 0);\n\t\t}, 1.01);\n\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(2, 0.01);\n\t\texpect(buffer.getValueAtTime(0.5)).to.be.closeTo(1.5, 0.01);\n\t\texpect(buffer.getValueAtTime(1)).to.be.closeTo(1, 0.01);\n\t});\n\n\tit(\"outputs a signal with bpm units and a multiplier\", async () => {\n\t\tconst buffer = await Offline((context) => {\n\t\t\tconst sched = new TickSignal({\n\t\t\t\tmultiplier: 10,\n\t\t\t\tunits: \"bpm\",\n\t\t\t\tvalue: 60,\n\t\t\t}).connect(context.destination);\n\t\t\tsched.linearRampTo(120, 1, 0);\n\t\t}, 1.01);\n\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(10, 0.01);\n\t\texpect(buffer.getValueAtTime(0.5)).to.be.closeTo(15, 0.01);\n\t\texpect(buffer.getValueAtTime(1)).to.be.closeTo(20, 0.01);\n\t});\n\n\tcontext(\"Ticks <-> Time\", () => {\n\t\tit(\"converts from time to ticks\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst tickSignal = new TickSignal(20);\n\t\t\t\texpect(tickSignal.ticksToTime(20, 0).valueOf()).to.be.closeTo(\n\t\t\t\t\t1,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.ticksToTime(10, 0).valueOf()).to.be.closeTo(\n\t\t\t\t\t0.5,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.ticksToTime(10, 10).valueOf()).to.be.closeTo(\n\t\t\t\t\t0.5,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\ttickSignal.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"converts from time to ticks with a linear ramp on the tempo\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst tickSignal = new TickSignal(1);\n\t\t\t\ttickSignal.linearRampTo(2, 2, 1);\n\t\t\t\texpect(tickSignal.ticksToTime(1, 0).valueOf()).to.be.closeTo(\n\t\t\t\t\t1,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.ticksToTime(1, 1).valueOf()).to.be.closeTo(\n\t\t\t\t\t0.82,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.ticksToTime(2, 0).valueOf()).to.be.closeTo(\n\t\t\t\t\t1.82,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.ticksToTime(1, 3).valueOf()).to.be.closeTo(\n\t\t\t\t\t0.5,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\ttickSignal.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"converts from time to ticks with a setValueAtTime\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst tickSignal = new TickSignal(1);\n\t\t\t\ttickSignal.setValueAtTime(2, 1);\n\t\t\t\texpect(tickSignal.ticksToTime(1, 0).valueOf()).to.be.closeTo(\n\t\t\t\t\t1,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.ticksToTime(1, 1).valueOf()).to.be.closeTo(\n\t\t\t\t\t0.5,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.ticksToTime(2, 0).valueOf()).to.be.closeTo(\n\t\t\t\t\t1.5,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.ticksToTime(1, 3).valueOf()).to.be.closeTo(\n\t\t\t\t\t0.5,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.ticksToTime(1, 0.5).valueOf()).to.be.closeTo(\n\t\t\t\t\t0.75,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\ttickSignal.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"converts from time to ticks with an exponential ramp\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst tickSignal = new TickSignal(1);\n\t\t\t\ttickSignal.exponentialRampTo(2, 1, 1);\n\t\t\t\texpect(tickSignal.ticksToTime(1, 0).valueOf()).to.be.closeTo(\n\t\t\t\t\t1,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.ticksToTime(1, 1).valueOf()).to.be.closeTo(\n\t\t\t\t\t0.75,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.ticksToTime(2, 0).valueOf()).to.be.closeTo(\n\t\t\t\t\t1.75,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.ticksToTime(1, 3).valueOf()).to.be.closeTo(\n\t\t\t\t\t0.5,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\ttickSignal.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"converts from time to ticks with a setTargetAtTime\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst tickSignal = new TickSignal(1);\n\t\t\t\ttickSignal.setTargetAtTime(2, 1, 1);\n\t\t\t\texpect(tickSignal.ticksToTime(1, 0).valueOf()).to.be.closeTo(\n\t\t\t\t\t1,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.ticksToTime(1, 1).valueOf()).to.be.closeTo(\n\t\t\t\t\t0.79,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.ticksToTime(2, 0).valueOf()).to.be.closeTo(\n\t\t\t\t\t1.79,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.ticksToTime(1, 3).valueOf()).to.be.closeTo(\n\t\t\t\t\t0.61,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\ttickSignal.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"converts from ticks to time\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst tickSignal = new TickSignal(20);\n\t\t\t\texpect(tickSignal.timeToTicks(1, 0).valueOf()).to.be.closeTo(\n\t\t\t\t\t20,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.timeToTicks(0.5, 0).valueOf()).to.be.closeTo(\n\t\t\t\t\t10,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.timeToTicks(0.5, 2).valueOf()).to.be.closeTo(\n\t\t\t\t\t10,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\ttickSignal.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"converts from ticks to time with a setValueAtTime\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst tickSignal = new TickSignal(1);\n\t\t\t\ttickSignal.setValueAtTime(2, 1);\n\t\t\t\texpect(tickSignal.timeToTicks(1, 0).valueOf()).to.be.closeTo(\n\t\t\t\t\t1,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.timeToTicks(1, 1).valueOf()).to.be.closeTo(\n\t\t\t\t\t2,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.timeToTicks(1, 2).valueOf()).to.be.closeTo(\n\t\t\t\t\t2,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.timeToTicks(1, 0.5).valueOf()).to.be.closeTo(\n\t\t\t\t\t1.5,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\ttickSignal.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"converts from ticks to time with a linear ramp\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst tickSignal = new TickSignal(1);\n\t\t\t\ttickSignal.linearRampTo(2, 1, 1);\n\t\t\t\texpect(tickSignal.timeToTicks(1, 0).valueOf()).to.be.closeTo(\n\t\t\t\t\t1,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.timeToTicks(1, 1).valueOf()).to.be.closeTo(\n\t\t\t\t\t1.5,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.timeToTicks(1, 2).valueOf()).to.be.closeTo(\n\t\t\t\t\t2,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.timeToTicks(1, 0.5).valueOf()).to.be.closeTo(\n\t\t\t\t\t1.12,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\ttickSignal.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"converts from ticks to time with an exponential ramp\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst tickSignal = new TickSignal(1);\n\t\t\t\ttickSignal.exponentialRampTo(2, 1, 1);\n\t\t\t\texpect(tickSignal.timeToTicks(1, 0).valueOf()).to.be.closeTo(\n\t\t\t\t\t1,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.timeToTicks(1, 1).valueOf()).to.be.closeTo(\n\t\t\t\t\t1.44,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.timeToTicks(1, 2).valueOf()).to.be.closeTo(\n\t\t\t\t\t2,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.timeToTicks(1, 0.5).valueOf()).to.be.closeTo(\n\t\t\t\t\t1.09,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\ttickSignal.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"converts from ticks to time with a setTargetAtTime\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst tickSignal = new TickSignal(1);\n\t\t\t\ttickSignal.setTargetAtTime(2, 1, 1);\n\t\t\t\texpect(tickSignal.timeToTicks(1, 0).valueOf()).to.be.closeTo(\n\t\t\t\t\t1,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.timeToTicks(1, 1).valueOf()).to.be.closeTo(\n\t\t\t\t\t1.31,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.timeToTicks(1, 2).valueOf()).to.be.closeTo(\n\t\t\t\t\t1.63,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(tickSignal.timeToTicks(1, 0.5).valueOf()).to.be.closeTo(\n\t\t\t\t\t1.07,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\ttickSignal.dispose();\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/clock/TickSignal.ts",
    "content": "import { Signal, SignalOptions } from \"../../signal/Signal.js\";\nimport { InputNode } from \"../context/ToneAudioNode.js\";\nimport { Seconds, Ticks, Time, UnitMap, UnitName } from \"../type/Units.js\";\nimport { optionsFromArguments } from \"../util/Defaults.js\";\nimport { TickParam } from \"./TickParam.js\";\n\ninterface TickSignalOptions<TypeName extends UnitName>\n\textends SignalOptions<TypeName> {\n\tvalue: UnitMap[TypeName];\n\tmultiplier: number;\n}\n\n/**\n * TickSignal extends Tone.Signal, but adds the capability\n * to calculate the number of elapsed ticks. exponential and target curves\n * are approximated with multiple linear ramps.\n *\n * Thank you Bruno Dias, H. Sofia Pinto, and David M. Matos,\n * for your [WAC paper](https://smartech.gatech.edu/bitstream/handle/1853/54588/WAC2016-49.pdf)\n * describing integrating timing functions for tempo calculations.\n */\nexport class TickSignal<\n\tTypeName extends \"hertz\" | \"bpm\",\n> extends Signal<TypeName> {\n\treadonly name: string = \"TickSignal\";\n\n\t/**\n\t * The param which controls the output signal value\n\t */\n\tprotected _param: TickParam<TypeName>;\n\treadonly input: InputNode;\n\n\t/**\n\t * @param value The initial value of the signal\n\t */\n\tconstructor(value?: UnitMap[TypeName]);\n\tconstructor(options: Partial<TickSignalOptions<TypeName>>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tTickSignal.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"value\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.input = this._param = new TickParam({\n\t\t\tcontext: this.context,\n\t\t\tconvert: options.convert,\n\t\t\tmultiplier: options.multiplier,\n\t\t\tparam: this._constantSource.offset,\n\t\t\tunits: options.units,\n\t\t\tvalue: options.value,\n\t\t});\n\t}\n\n\tstatic getDefaults(): TickSignalOptions<any> {\n\t\treturn Object.assign(Signal.getDefaults(), {\n\t\t\tmultiplier: 1,\n\t\t\tunits: \"hertz\",\n\t\t\tvalue: 1,\n\t\t});\n\t}\n\n\tticksToTime(ticks: Ticks, when: Time): Seconds {\n\t\treturn this._param.ticksToTime(ticks, when);\n\t}\n\n\ttimeToTicks(duration: Time, when: Time): Ticks {\n\t\treturn this._param.timeToTicks(duration, when);\n\t}\n\n\tgetTimeOfTick(tick: Ticks): Seconds {\n\t\treturn this._param.getTimeOfTick(tick);\n\t}\n\n\tgetDurationOfTicks(ticks: Ticks, time: Time): Seconds {\n\t\treturn this._param.getDurationOfTicks(ticks, time);\n\t}\n\n\tgetTicksAtTime(time: Time): Ticks {\n\t\treturn this._param.getTicksAtTime(time);\n\t}\n\n\t/**\n\t * A multiplier on the bpm value. Useful for setting a PPQ relative to the base frequency value.\n\t */\n\tget multiplier(): number {\n\t\treturn this._param.multiplier;\n\t}\n\tset multiplier(m: number) {\n\t\tthis._param.multiplier = m;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._param.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/core/clock/TickSource.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { TickSource } from \"./TickSource.js\";\n\ndescribe(\"TickSource\", () => {\n\tBasicTests(TickSource);\n\n\tcontext(\"Constructor\", () => {\n\t\tit(\"can pass in the frequency\", () => {\n\t\t\tconst source = new TickSource(2);\n\t\t\texpect(source.frequency.value).to.equal(2);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"initially returns stop\", () => {\n\t\t\tconst source = new TickSource(2);\n\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\tsource.dispose();\n\t\t});\n\t});\n\n\tcontext(\"Ticks\", () => {\n\t\tit(\"ticks are 0 before started\", () => {\n\t\t\tconst source = new TickSource();\n\t\t\texpect(source.ticks).to.equal(0);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can set ticks\", () => {\n\t\t\tconst source = new TickSource();\n\t\t\texpect(source.ticks).to.equal(0);\n\t\t\tsource.ticks = 10;\n\t\t\texpect(source.ticks).to.equal(10);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"ticks increment at the rate of the frequency after started\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst source = new TickSource();\n\t\t\t\tsource.start(0);\n\t\t\t\treturn (time) => {\n\t\t\t\t\texpect(source.ticks).to.be.closeTo(time, 0.1);\n\t\t\t\t};\n\t\t\t}, 0.5);\n\t\t});\n\n\t\tit(\"ticks return to 0 after stopped\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst source = new TickSource(2);\n\t\t\t\tsource.start(0).stop(0.4);\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time < 0.399) {\n\t\t\t\t\t\texpect(source.ticks).to.be.closeTo(2 * time, 0.01);\n\t\t\t\t\t} else if (time > 0.4) {\n\t\t\t\t\t\texpect(source.ticks).to.be.equal(0);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.5);\n\t\t});\n\n\t\tit(\"returns the paused ticks when paused\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst source = new TickSource(2);\n\t\t\t\tsource.start(0).pause(0.4);\n\t\t\t\tlet pausedTicks = -1;\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time < 0.4) {\n\t\t\t\t\t\tpausedTicks = source.ticks;\n\t\t\t\t\t\texpect(source.ticks).to.be.closeTo(2 * time, 0.01);\n\t\t\t\t\t} else {\n\t\t\t\t\t\texpect(source.ticks).to.be.closeTo(pausedTicks, 0.01);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.5);\n\t\t});\n\n\t\tit(\"ticks restart at 0 when started after stop\", () => {\n\t\t\tconst source = new TickSource(3);\n\t\t\tsource.start(0).stop(1).start(2);\n\t\t\texpect(source.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.5)).to.be.closeTo(1.5, 0.01);\n\t\t\texpect(source.getTicksAtTime(1)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(2)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(3)).to.be.closeTo(3, 0.01);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"ticks remain the same after paused\", () => {\n\t\t\tconst source = new TickSource(3);\n\t\t\tsource.start(0).pause(1);\n\t\t\texpect(source.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.5)).to.be.closeTo(1.5, 0.01);\n\t\t\texpect(source.getTicksAtTime(1)).to.be.closeTo(3, 0.01);\n\t\t\texpect(source.getTicksAtTime(2)).to.be.closeTo(3, 0.01);\n\t\t\texpect(source.getTicksAtTime(3)).to.be.closeTo(3, 0.01);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"ticks resume where they were paused\", () => {\n\t\t\tconst source = new TickSource(2);\n\t\t\tsource.start(0).pause(1).start(2);\n\t\t\texpect(source.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.5)).to.be.closeTo(1, 0.01);\n\t\t\texpect(source.getTicksAtTime(1)).to.be.closeTo(2, 0.01);\n\t\t\texpect(source.getTicksAtTime(2)).to.be.closeTo(2, 0.01);\n\t\t\texpect(source.getTicksAtTime(3)).to.be.closeTo(4, 0.01);\n\t\t\texpect(source.getTicksAtTime(4)).to.be.closeTo(6, 0.01);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"ticks return to 0 after pause then stopped\", () => {\n\t\t\tconst source = new TickSource(2);\n\t\t\tsource.start(0).pause(1).start(2).stop(3);\n\t\t\texpect(source.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.5)).to.be.closeTo(1, 0.01);\n\t\t\texpect(source.getTicksAtTime(1)).to.be.closeTo(2, 0.01);\n\t\t\texpect(source.getTicksAtTime(2)).to.be.closeTo(2, 0.01);\n\t\t\texpect(source.getTicksAtTime(3)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(4)).to.be.closeTo(0, 0.01);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"handles multiple starts/stops\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0).stop(0.3).start(0.4).stop(0.5).start(0.6);\n\t\t\texpect(source.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.1)).to.be.closeTo(0.1, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.2)).to.be.closeTo(0.2, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.3)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.4)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.5)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.6)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.7)).to.be.closeTo(0.1, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.8)).to.be.closeTo(0.2, 0.01);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can get ticks when started with an offset\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0, 2).stop(3).start(5, 1);\n\t\t\texpect(source.getTicksAtTime(0)).to.be.closeTo(2, 0.01);\n\t\t\texpect(source.getTicksAtTime(1)).to.be.closeTo(3, 0.01);\n\t\t\texpect(source.getTicksAtTime(2)).to.be.closeTo(4, 0.01);\n\t\t\texpect(source.getTicksAtTime(3)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(4)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(5)).to.be.closeTo(1, 0.01);\n\t\t\texpect(source.getTicksAtTime(6)).to.be.closeTo(2, 0.01);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can invoke stop multiple times, takes the last invocation\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0).stop(3).stop(2).stop(4);\n\t\t\texpect(source.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(1)).to.be.closeTo(1, 0.01);\n\t\t\texpect(source.getTicksAtTime(2)).to.be.closeTo(2, 0.01);\n\t\t\texpect(source.getTicksAtTime(3)).to.be.closeTo(3, 0.01);\n\t\t\texpect(source.getTicksAtTime(4)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(5)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(6)).to.be.closeTo(0, 0.01);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can set multiple setTicksAtTime\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0, 1).pause(3);\n\t\t\tsource.setTicksAtTime(1, 4);\n\t\t\tsource.stop(5).start(6);\n\t\t\tsource.setTicksAtTime(2, 7);\n\t\t\texpect(source.getTicksAtTime(0)).to.be.closeTo(1, 0.01);\n\t\t\texpect(source.getTicksAtTime(1)).to.be.closeTo(2, 0.01);\n\t\t\texpect(source.getTicksAtTime(2)).to.be.closeTo(3, 0.01);\n\t\t\texpect(source.getTicksAtTime(3)).to.be.closeTo(4, 0.01);\n\t\t\texpect(source.getTicksAtTime(3.5)).to.be.closeTo(4, 0.01);\n\t\t\texpect(source.getTicksAtTime(4)).to.be.closeTo(1, 0.01);\n\t\t\texpect(source.getTicksAtTime(5)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(6)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(6.5)).to.be.closeTo(0.5, 0.01);\n\t\t\texpect(source.getTicksAtTime(7)).to.be.closeTo(2, 0.01);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can pass start offset\", () => {\n\t\t\tconst source = new TickSource(2);\n\t\t\tsource.start(0, 2).pause(1).start(2, 1);\n\t\t\texpect(source.getTicksAtTime(0)).to.be.closeTo(2, 0.01);\n\t\t\texpect(source.getTicksAtTime(1)).to.be.closeTo(4, 0.01);\n\t\t\texpect(source.getTicksAtTime(2)).to.be.closeTo(1, 0.01);\n\t\t\texpect(source.getTicksAtTime(3)).to.be.closeTo(3, 0.01);\n\t\t\texpect(source.getTicksAtTime(4)).to.be.closeTo(5, 0.01);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can set ticks at any point\", () => {\n\t\t\tconst source = new TickSource(2);\n\t\t\tsource.start(0, 2).pause(1).start(2);\n\t\t\tsource.setTicksAtTime(10, 1.5);\n\t\t\tsource.setTicksAtTime(2, 3.5);\n\t\t\texpect(source.getTicksAtTime(0)).to.be.closeTo(2, 0.01);\n\t\t\texpect(source.getTicksAtTime(1)).to.be.closeTo(4, 0.01);\n\t\t\texpect(source.getTicksAtTime(2)).to.be.closeTo(10, 0.01);\n\t\t\texpect(source.getTicksAtTime(3)).to.be.closeTo(12, 0.01);\n\t\t\texpect(source.getTicksAtTime(4)).to.be.closeTo(3, 0.01);\n\t\t\texpect(source.getTicksAtTime(5)).to.be.closeTo(5, 0.01);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"get the time of the ticks\", () => {\n\t\t\tconst source = new TickSource(2);\n\t\t\tsource.start(0, 2).pause(1).start(2);\n\t\t\tsource.setTicksAtTime(10, 1.5);\n\t\t\tsource.setTicksAtTime(2, 3.5);\n\t\t\texpect(source.getTimeOfTick(2, 0.9)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTimeOfTick(4, 0.9)).to.be.closeTo(1, 0.01);\n\t\t\texpect(source.getTimeOfTick(10, 3)).to.be.closeTo(2, 0.01);\n\t\t\texpect(source.getTimeOfTick(12, 3)).to.be.closeTo(3, 0.01);\n\t\t\texpect(source.getTimeOfTick(3, 4)).to.be.closeTo(4, 0.01);\n\t\t\texpect(source.getTimeOfTick(5, 4)).to.be.closeTo(5, 0.01);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can cancel scheduled events\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0).stop(3);\n\t\t\tsource.setTicksAtTime(10, 2);\n\t\t\tsource.cancel(1);\n\t\t\texpect(source.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(1)).to.be.closeTo(1, 0.01);\n\t\t\texpect(source.getTicksAtTime(2)).to.be.closeTo(2, 0.01);\n\t\t\texpect(source.getTicksAtTime(3)).to.be.closeTo(3, 0.01);\n\t\t\texpect(source.getTicksAtTime(4)).to.be.closeTo(4, 0.01);\n\t\t\texpect(source.getTicksAtTime(5)).to.be.closeTo(5, 0.01);\n\t\t\texpect(source.getTicksAtTime(6)).to.be.closeTo(6, 0.01);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"will recompute memoized values when events are modified\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(3).pause(4);\n\t\t\texpect(source.getTicksAtTime(1)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(2)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(3)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(4)).to.be.closeTo(1, 0.01);\n\t\t\texpect(source.getTicksAtTime(5)).to.be.closeTo(1, 0.01);\n\t\t\tsource.start(1).pause(2);\n\t\t\texpect(source.getTicksAtTime(1)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(2)).to.be.closeTo(1, 0.01);\n\t\t\texpect(source.getTicksAtTime(3)).to.be.closeTo(1, 0.01);\n\t\t\texpect(source.getTicksAtTime(4)).to.be.closeTo(2, 0.01);\n\t\t\texpect(source.getTicksAtTime(5)).to.be.closeTo(2, 0.01);\n\t\t\tsource.setTicksAtTime(3, 1);\n\t\t\texpect(source.getTicksAtTime(1)).to.be.closeTo(3, 0.01);\n\t\t\texpect(source.getTicksAtTime(2)).to.be.closeTo(4, 0.01);\n\t\t\texpect(source.getTicksAtTime(3)).to.be.closeTo(4, 0.01);\n\t\t\texpect(source.getTicksAtTime(4)).to.be.closeTo(5, 0.01);\n\t\t\texpect(source.getTicksAtTime(5)).to.be.closeTo(5, 0.01);\n\t\t\tsource.cancel(4);\n\t\t\texpect(source.getTicksAtTime(1)).to.be.closeTo(3, 0.01);\n\t\t\texpect(source.getTicksAtTime(2)).to.be.closeTo(4, 0.01);\n\t\t\texpect(source.getTicksAtTime(3)).to.be.closeTo(4, 0.01);\n\t\t\texpect(source.getTicksAtTime(4)).to.be.closeTo(5, 0.01);\n\t\t\texpect(source.getTicksAtTime(5)).to.be.closeTo(6, 0.01);\n\t\t\tsource.dispose();\n\t\t});\n\t});\n\n\tcontext(\"forEachTickBetween\", () => {\n\t\tit(\"invokes a callback function when started\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0);\n\t\t\tlet wasCalled = false;\n\t\t\tsource.forEachTickBetween(0, 2, () => {\n\t\t\t\twasCalled = true;\n\t\t\t});\n\t\t\texpect(wasCalled).to.equal(true);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"does not invoke callback when not overlapping with tick\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0);\n\t\t\tlet wasCalled = false;\n\t\t\tsource.forEachTickBetween(1.1, 2, () => {\n\t\t\t\twasCalled = true;\n\t\t\t});\n\t\t\texpect(wasCalled).to.equal(false);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"iterates only at times when the state is 'started'\", () => {\n\t\t\tconst source = new TickSource(4);\n\t\t\tsource.start(0.2).pause(2).start(3.5).stop(5);\n\t\t\tlet iterations = 0;\n\t\t\tconst expectedTimes = [\n\t\t\t\t1.2, 1.45, 1.7, 1.95, 3.5, 3.75, 4, 4.25, 4.5, 4.75,\n\t\t\t];\n\t\t\tconst expectedTicks = [4, 5, 6, 7, 7, 8, 9, 10, 11, 12];\n\t\t\tsource.forEachTickBetween(1, 7, (time, ticks) => {\n\t\t\t\texpect(time).to.be.closeTo(expectedTimes[iterations], 0.001);\n\t\t\t\texpect(ticks).to.equal(expectedTicks[iterations]);\n\t\t\t\titerations++;\n\t\t\t});\n\t\t\texpect(iterations).to.equal(expectedTimes.length);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can start at time = 0\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0);\n\t\t\tlet iterations = 0;\n\t\t\tsource.forEachTickBetween(0, 0.1, () => {\n\t\t\t\titerations++;\n\t\t\t});\n\t\t\texpect(iterations).to.equal(1);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can throw an error in the callback but still invokes all loops\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0);\n\t\t\texpect(() => {\n\t\t\t\tsource.forEachTickBetween(0, 3, () => {\n\t\t\t\t\tthrow new Error(\"should throw\");\n\t\t\t\t});\n\t\t\t}).throws(Error);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"iterates once per tick\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0.5);\n\t\t\tlet iterations = 0;\n\t\t\tsource.forEachTickBetween(0, 2, () => {\n\t\t\t\titerations++;\n\t\t\t});\n\t\t\texpect(iterations).to.equal(2);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"passes time and tick into the callback\", () => {\n\t\t\tconst source = new TickSource(2);\n\t\t\tsource.start(0.5);\n\t\t\tlet iterations = 0;\n\t\t\tconst times = [0.5, 1.0, 1.5];\n\t\t\tsource.forEachTickBetween(0, 2, (time, ticks) => {\n\t\t\t\texpect(times[ticks]).to.be.closeTo(time, 0.001);\n\t\t\t\titerations++;\n\t\t\t});\n\t\t\texpect(iterations).to.equal(3);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"ticks = 0 when restarted\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0.5).stop(1).start(2);\n\t\t\tlet iterations = 0;\n\t\t\tconst expectedTicks = [0, 0, 1];\n\t\t\tconst expectedTimes = [0.5, 2, 3];\n\t\t\tsource.forEachTickBetween(0, 3.1, (time, ticks) => {\n\t\t\t\texpect(time).to.be.closeTo(expectedTimes[iterations], 0.001);\n\t\t\t\texpect(ticks).to.equal(expectedTicks[iterations]);\n\t\t\t\titerations++;\n\t\t\t});\n\t\t\texpect(iterations).to.equal(expectedTicks.length);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"ticks resume after pause when restarted\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0.5).pause(2).start(3);\n\t\t\tlet iterations = 0;\n\t\t\tconst expectedTicks = [0, 1, 2];\n\t\t\tconst expectedTimes = [0.5, 1.5, 3];\n\t\t\tsource.forEachTickBetween(0, 3.1, (time, ticks) => {\n\t\t\t\texpect(time).to.be.closeTo(expectedTimes[iterations], 0.001);\n\t\t\t\texpect(ticks).to.equal(expectedTicks[iterations]);\n\t\t\t\titerations++;\n\t\t\t});\n\t\t\texpect(iterations).to.equal(expectedTicks.length);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"handles start and stop\", () => {\n\t\t\tconst source = new TickSource(2);\n\t\t\tsource.start(0.5).stop(2);\n\t\t\tlet iterations = 0;\n\t\t\tconst times = [0.5, 1.0, 1.5];\n\t\t\tsource.forEachTickBetween(0, 3, (time, ticks) => {\n\t\t\t\texpect(times[ticks]).to.be.closeTo(time, 0.001);\n\t\t\t\titerations++;\n\t\t\t});\n\t\t\texpect(iterations).to.equal(3);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"handles multiple start and stop\", () => {\n\t\t\tconst source = new TickSource(2);\n\t\t\tsource.start(0.5).stop(2).start(2.5).stop(4.1);\n\t\t\tlet iterations = 0;\n\t\t\tconst times = [0.5, 1.0, 1.5, 2.5, 3, 3.5, 4];\n\t\t\tsource.forEachTickBetween(0, 10, (time) => {\n\t\t\t\texpect(times[iterations]).to.be.closeTo(time, 0.001);\n\t\t\t\titerations++;\n\t\t\t});\n\t\t\texpect(iterations).to.equal(times.length);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"works with a frequency ramp\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.frequency.setValueAtTime(1, 0);\n\t\t\tsource.frequency.linearRampToValueAtTime(4, 1);\n\t\t\tsource.start(0.5);\n\t\t\tlet iterations = 0;\n\t\t\tconst times = [0.5, 0.833, 1.094, 1.344, 1.594, 1.844];\n\t\t\tsource.forEachTickBetween(0, 2, (time, ticks) => {\n\t\t\t\texpect(time).to.be.closeTo(times[ticks], 0.001);\n\t\t\t\titerations++;\n\t\t\t});\n\t\t\texpect(iterations).to.equal(times.length);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can start with a tick offset\", () => {\n\t\t\tconst source = new TickSource(10);\n\t\t\tsource.start(0.5, 5);\n\t\t\tlet iterations = 0;\n\t\t\tsource.forEachTickBetween(0, 2, (time, ticks) => {\n\t\t\t\texpect(ticks).to.be.gte(5);\n\t\t\t\titerations++;\n\t\t\t});\n\t\t\texpect(iterations).to.equal(15);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can handle multiple starts with tick offsets\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0.5, 10).stop(2).start(3, 1);\n\t\t\tlet iterations = 0;\n\t\t\tconst expectedTimes = [0.5, 1.5, 3];\n\t\t\tconst expectedTicks = [10, 11, 1];\n\t\t\tsource.forEachTickBetween(0, 4, (time, ticks) => {\n\t\t\t\texpect(time).to.be.closeTo(expectedTimes[iterations], 0.001);\n\t\t\t\texpect(ticks).to.equal(expectedTicks[iterations]);\n\t\t\t\titerations++;\n\t\t\t});\n\t\t\texpect(iterations).to.equal(expectedTicks.length);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can set ticks after start\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0.4, 3);\n\t\t\tsource.setTicksAtTime(1, 1.4);\n\t\t\tsource.setTicksAtTime(10, 3);\n\t\t\tlet iterations = 0;\n\t\t\tconst expectedTicks = [3, 1, 2, 10];\n\t\t\tsource.forEachTickBetween(0, 4, (time, ticks) => {\n\t\t\t\texpect(ticks).to.equal(expectedTicks[iterations]);\n\t\t\t\titerations++;\n\t\t\t});\n\t\t\texpect(iterations).to.equal(expectedTicks.length);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can pass in the frequency\", () => {\n\t\t\tconst source = new TickSource(20);\n\t\t\tsource.start(0.5);\n\t\t\tlet iterations = 0;\n\t\t\tlet lastTime = 0.5;\n\t\t\tsource.forEachTickBetween(0.51, 2.01, (time) => {\n\t\t\t\texpect(time - lastTime).to.be.closeTo(0.05, 0.001);\n\t\t\t\tlastTime = time;\n\t\t\t\titerations++;\n\t\t\t});\n\t\t\texpect(iterations).to.equal(30);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can iterate from later in the timeline\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0.2);\n\t\t\tlet iterations = 0;\n\t\t\tsource.forEachTickBetween(100, 101, (time, ticks) => {\n\t\t\t\texpect(ticks).to.equal(100);\n\t\t\t\texpect(time).to.be.closeTo(100.2, 0.001);\n\t\t\t\titerations++;\n\t\t\t});\n\t\t\texpect(iterations).to.equal(1);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"always increments by 1 at a fixed rate\", () => {\n\t\t\tconst source = new TickSource(960);\n\t\t\tsource.start(0);\n\t\t\tlet previousTick = -1;\n\t\t\tlet previousTime = -1;\n\t\t\tsource.forEachTickBetween(1000, 1010, (time, ticks) => {\n\t\t\t\texpect(time).to.be.gt(previousTime);\n\t\t\t\tif (previousTick !== -1) {\n\t\t\t\t\texpect(ticks - previousTick).to.equal(1);\n\t\t\t\t}\n\t\t\t\tpreviousTick = ticks;\n\t\t\t\tpreviousTime = time;\n\t\t\t});\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"always increments by 1 when linearly changing rate\", () => {\n\t\t\tconst source = new TickSource(200);\n\t\t\tsource.frequency.setValueAtTime(200, 0);\n\t\t\tsource.frequency.linearRampToValueAtTime(1000, 100);\n\t\t\tsource.start(10);\n\t\t\tlet previousTick = -1;\n\t\t\tlet previousTime = -1;\n\t\t\tsource.forEachTickBetween(10, 30, (time, ticks) => {\n\t\t\t\texpect(time).to.be.gt(previousTime);\n\t\t\t\texpect(ticks - previousTick).to.equal(1);\n\t\t\t\tpreviousTick = ticks;\n\t\t\t\tpreviousTime = time;\n\t\t\t});\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"always increments by 1 when setting values\", () => {\n\t\t\tconst source = new TickSource(200);\n\t\t\tsource.frequency.setValueAtTime(300, 0);\n\t\t\tsource.frequency.setValueAtTime(3, 0.1);\n\t\t\tsource.frequency.setValueAtTime(100, 0.2);\n\t\t\tsource.frequency.setValueAtTime(10, 0.3);\n\t\t\tsource.frequency.setValueAtTime(1000, 0.4);\n\t\t\tsource.frequency.setValueAtTime(1, 0.5);\n\t\t\tsource.frequency.setValueAtTime(50, 0.6);\n\t\t\tsource.start(0);\n\t\t\tlet previousTick = -1;\n\t\t\tlet previousTime = -1;\n\t\t\tsource.forEachTickBetween(0, 10, (time, ticks) => {\n\t\t\t\texpect(time).to.be.gt(previousTime);\n\t\t\t\texpect(ticks - previousTick).to.equal(1);\n\t\t\t\tpreviousTick = ticks;\n\t\t\t\tpreviousTime = time;\n\t\t\t});\n\t\t\tsource.dispose();\n\t\t});\n\t});\n\n\tcontext(\"Seconds\", () => {\n\t\tit(\"get the elapsed time in seconds\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst source = new TickSource(1).start(0);\n\t\t\t\treturn (time) => {\n\t\t\t\t\texpect(source.seconds).to.be.closeTo(time, 0.01);\n\t\t\t\t};\n\t\t\t}, 2);\n\t\t});\n\n\t\tit(\"seconds is 0 before starting\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\texpect(source.seconds).to.be.closeTo(0, 0.001);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can set the seconds\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\texpect(source.seconds).to.be.closeTo(0, 0.001);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"seconds pauses at last second count\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0).pause(1);\n\t\t\texpect(source.getSecondsAtTime(0)).to.be.closeTo(0, 0.001);\n\t\t\texpect(source.getSecondsAtTime(1)).to.be.closeTo(1, 0.001);\n\t\t\texpect(source.getSecondsAtTime(2)).to.be.closeTo(1, 0.001);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can handle multiple pauses\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0).pause(1).start(2).pause(3).start(4).stop(6);\n\t\t\texpect(source.getSecondsAtTime(0)).to.be.closeTo(0, 0.001);\n\t\t\texpect(source.getSecondsAtTime(1)).to.be.closeTo(1, 0.001);\n\t\t\texpect(source.getSecondsAtTime(2)).to.be.closeTo(1, 0.001);\n\t\t\texpect(source.getSecondsAtTime(2.5)).to.be.closeTo(1.5, 0.001);\n\t\t\texpect(source.getSecondsAtTime(3)).to.be.closeTo(2, 0.001);\n\t\t\texpect(source.getSecondsAtTime(4.5)).to.be.closeTo(2.5, 0.001);\n\t\t\texpect(source.getSecondsAtTime(5)).to.be.closeTo(3, 0.001);\n\t\t\texpect(source.getSecondsAtTime(6)).to.be.closeTo(0, 0.001);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"get the elapsed time in seconds when starting in the future\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst source = new TickSource(1).start(0.1);\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time < 0.1) {\n\t\t\t\t\t\texpect(source.seconds).to.be.closeTo(0, 0.001);\n\t\t\t\t\t} else {\n\t\t\t\t\t\texpect(source.seconds).to.be.closeTo(time - 0.1, 0.01);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 2);\n\t\t});\n\n\t\tit(\"handles multiple starts and stops\", () => {\n\t\t\tconst source = new TickSource(1)\n\t\t\t\t.start(0)\n\t\t\t\t.stop(0.5)\n\t\t\t\t.start(1)\n\t\t\t\t.stop(1.5);\n\t\t\texpect(source.getSecondsAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getSecondsAtTime(0.4)).to.be.closeTo(0.4, 0.01);\n\t\t\texpect(source.getSecondsAtTime(0.5)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getSecondsAtTime(0.9)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getSecondsAtTime(1)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getSecondsAtTime(1.4)).to.be.closeTo(0.4, 0.01);\n\t\t\texpect(source.getSecondsAtTime(1.5)).to.be.closeTo(0, 0.01);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"will recompute memoized values when events are modified\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(3).pause(4);\n\t\t\texpect(source.getSecondsAtTime(1)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getSecondsAtTime(2)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getSecondsAtTime(3)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getSecondsAtTime(4)).to.be.closeTo(1, 0.01);\n\t\t\texpect(source.getSecondsAtTime(5)).to.be.closeTo(1, 0.01);\n\t\t\tsource.start(1).pause(2);\n\t\t\texpect(source.getSecondsAtTime(1)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getSecondsAtTime(2)).to.be.closeTo(1, 0.01);\n\t\t\texpect(source.getSecondsAtTime(3)).to.be.closeTo(1, 0.01);\n\t\t\texpect(source.getSecondsAtTime(4)).to.be.closeTo(2, 0.01);\n\t\t\texpect(source.getSecondsAtTime(5)).to.be.closeTo(2, 0.01);\n\t\t\tsource.cancel(4);\n\t\t\texpect(source.getSecondsAtTime(1)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getSecondsAtTime(2)).to.be.closeTo(1, 0.01);\n\t\t\texpect(source.getSecondsAtTime(3)).to.be.closeTo(1, 0.01);\n\t\t\texpect(source.getSecondsAtTime(4)).to.be.closeTo(2, 0.01);\n\t\t\texpect(source.getSecondsAtTime(5)).to.be.closeTo(3, 0.01);\n\t\t\tsource.dispose();\n\t\t});\n\t});\n\n\tcontext(\"Frequency\", () => {\n\t\tit(\"can automate frequency with setValueAtTime\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0).stop(0.3).start(0.4).stop(0.5).start(0.6);\n\t\t\tsource.frequency.setValueAtTime(2, 0.3);\n\t\t\texpect(source.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.1)).to.be.closeTo(0.1, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.2)).to.be.closeTo(0.2, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.3)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.4)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.45)).to.be.closeTo(0.1, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.5)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.6)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.7)).to.be.closeTo(0.2, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.8)).to.be.closeTo(0.4, 0.01);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can automate frequency with linearRampToValueAtTime\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0).stop(1).start(2);\n\t\t\tsource.frequency.linearRampToValueAtTime(2, 2);\n\t\t\texpect(source.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.5)).to.be.closeTo(0.56, 0.01);\n\t\t\texpect(source.getTicksAtTime(1)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(2)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(3)).to.be.closeTo(2, 0.01);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can automate frequency with exponentialRampToValueAtTime\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0).stop(1).start(2).stop(5);\n\t\t\tsource.frequency.exponentialRampToValueAtTime(4, 2);\n\t\t\texpect(source.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.5)).to.be.closeTo(0.6, 0.01);\n\t\t\texpect(source.getTicksAtTime(1)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(2)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(3)).to.be.closeTo(4, 0.01);\n\t\t\texpect(source.getTicksAtTime(4)).to.be.closeTo(8, 0.01);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can automate frequency with setTargetAtTime\", () => {\n\t\t\tconst source = new TickSource(1);\n\t\t\tsource.start(0).stop(1).start(2).stop(5);\n\t\t\tsource.frequency.setTargetAtTime(2, 1, 0.5);\n\t\t\texpect(source.getTicksAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(0.5)).to.be.closeTo(0.5, 0.01);\n\t\t\texpect(source.getTicksAtTime(1)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(2)).to.be.closeTo(0, 0.01);\n\t\t\texpect(source.getTicksAtTime(3)).to.be.closeTo(1.86, 0.01);\n\t\t\texpect(source.getTicksAtTime(4)).to.be.closeTo(3.73, 0.01);\n\t\t\texpect(source.getTicksAtTime(5)).to.be.closeTo(0, 0.01);\n\t\t\tsource.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/clock/TickSource.ts",
    "content": "import {\n\tToneWithContext,\n\tToneWithContextOptions,\n} from \"../context/ToneWithContext.js\";\nimport { Seconds, Ticks, Time } from \"../type/Units.js\";\nimport { optionsFromArguments } from \"../util/Defaults.js\";\nimport { readOnly } from \"../util/Interface.js\";\nimport { EQ } from \"../util/Math.js\";\nimport {\n\tPlaybackState,\n\tStateTimeline,\n\tStateTimelineEvent,\n} from \"../util/StateTimeline.js\";\nimport { Timeline, TimelineEvent } from \"../util/Timeline.js\";\nimport { isDefined } from \"../util/TypeCheck.js\";\nimport { TickSignal } from \"./TickSignal.js\";\n\ninterface TickSourceOptions extends ToneWithContextOptions {\n\tfrequency: number;\n\tunits: \"bpm\" | \"hertz\";\n}\n\ninterface TickSourceOffsetEvent extends TimelineEvent {\n\tticks: number;\n\ttime: number;\n\tseconds: number;\n}\n\ninterface TickSourceTicksAtTimeEvent extends TimelineEvent {\n\tstate: PlaybackState;\n\ttime: number;\n\tticks: number;\n}\n\ninterface TickSourceSecondsAtTimeEvent extends TimelineEvent {\n\tstate: PlaybackState;\n\ttime: number;\n\tseconds: number;\n}\n\n/**\n * Uses [TickSignal](TickSignal) to track elapsed ticks with complex automation curves.\n */\nexport class TickSource<\n\tTypeName extends \"bpm\" | \"hertz\",\n> extends ToneWithContext<TickSourceOptions> {\n\treadonly name: string = \"TickSource\";\n\n\t/**\n\t * The frequency the callback function should be invoked.\n\t */\n\treadonly frequency: TickSignal<TypeName>;\n\n\t/**\n\t * The state timeline\n\t */\n\tprivate _state: StateTimeline = new StateTimeline();\n\n\t/**\n\t * The offset values of the ticks\n\t */\n\tprivate _tickOffset: Timeline<TickSourceOffsetEvent> = new Timeline();\n\n\t/**\n\t * Memoized values of getTicksAtTime at events with state other than \"started\"\n\t */\n\tprivate _ticksAtTime: Timeline<TickSourceTicksAtTimeEvent> =\n\t\tnew Timeline<TickSourceTicksAtTimeEvent>();\n\n\t/**\n\t * Memoized values of getSecondsAtTime at events with state other than \"started\"\n\t */\n\tprivate _secondsAtTime: Timeline<TickSourceSecondsAtTimeEvent> =\n\t\tnew Timeline<TickSourceSecondsAtTimeEvent>();\n\n\t/**\n\t * @param frequency The initial frequency that the signal ticks at\n\t */\n\tconstructor(frequency?: number);\n\tconstructor(options?: Partial<TickSourceOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tTickSource.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"frequency\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.frequency = new TickSignal({\n\t\t\tcontext: this.context,\n\t\t\tunits: options.units as TypeName,\n\t\t\tvalue: options.frequency,\n\t\t});\n\t\treadOnly(this, \"frequency\");\n\n\t\t// set the initial state\n\t\tthis._state.setStateAtTime(\"stopped\", 0);\n\t\t// add the first event\n\t\tthis.setTicksAtTime(0, 0);\n\t}\n\n\tstatic getDefaults(): TickSourceOptions {\n\t\treturn Object.assign(\n\t\t\t{\n\t\t\t\tfrequency: 1,\n\t\t\t\tunits: \"hertz\" as const,\n\t\t\t},\n\t\t\tToneWithContext.getDefaults()\n\t\t);\n\t}\n\n\t/**\n\t * Returns the playback state of the source, either \"started\", \"stopped\" or \"paused\".\n\t */\n\tget state(): PlaybackState {\n\t\treturn this.getStateAtTime(this.now());\n\t}\n\n\t/**\n\t * Start the clock at the given time. Optionally pass in an offset\n\t * of where to start the tick counter from.\n\t * @param  time    The time the clock should start\n\t * @param offset The number of ticks to start the source at\n\t */\n\tstart(time: Time, offset?: Ticks): this {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tif (this._state.getValueAtTime(computedTime) !== \"started\") {\n\t\t\tthis._state.setStateAtTime(\"started\", computedTime);\n\t\t\tif (isDefined(offset)) {\n\t\t\t\tthis.setTicksAtTime(offset, computedTime);\n\t\t\t}\n\t\t\tthis._ticksAtTime.cancel(computedTime);\n\t\t\tthis._secondsAtTime.cancel(computedTime);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop the clock. Stopping the clock resets the tick counter to 0.\n\t * @param time The time when the clock should stop.\n\t */\n\tstop(time: Time): this {\n\t\tconst computedTime = this.toSeconds(time);\n\t\t// cancel the previous stop\n\t\tif (this._state.getValueAtTime(computedTime) === \"stopped\") {\n\t\t\tconst event = this._state.get(computedTime);\n\t\t\tif (event && event.time > 0) {\n\t\t\t\tthis._tickOffset.cancel(event.time);\n\t\t\t\tthis._state.cancel(event.time);\n\t\t\t}\n\t\t}\n\t\tthis._state.cancel(computedTime);\n\t\tthis._state.setStateAtTime(\"stopped\", computedTime);\n\t\tthis.setTicksAtTime(0, computedTime);\n\t\tthis._ticksAtTime.cancel(computedTime);\n\t\tthis._secondsAtTime.cancel(computedTime);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Pause the clock. Pausing does not reset the tick counter.\n\t * @param time The time when the clock should stop.\n\t */\n\tpause(time: Time): this {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tif (this._state.getValueAtTime(computedTime) === \"started\") {\n\t\t\tthis._state.setStateAtTime(\"paused\", computedTime);\n\t\t\tthis._ticksAtTime.cancel(computedTime);\n\t\t\tthis._secondsAtTime.cancel(computedTime);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Cancel start/stop/pause and setTickAtTime events scheduled after the given time.\n\t * @param time When to clear the events after\n\t */\n\tcancel(time: Time): this {\n\t\ttime = this.toSeconds(time);\n\t\tthis._state.cancel(time);\n\t\tthis._tickOffset.cancel(time);\n\t\tthis._ticksAtTime.cancel(time);\n\t\tthis._secondsAtTime.cancel(time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Get the elapsed ticks at the given time\n\t * @param  time  When to get the tick value\n\t * @return The number of ticks\n\t */\n\tgetTicksAtTime(time?: Time): Ticks {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tconst stopEvent = this._state.getLastState(\n\t\t\t\"stopped\",\n\t\t\tcomputedTime\n\t\t) as StateTimelineEvent;\n\n\t\t// get previously memoized ticks if available\n\t\tconst memoizedEvent = this._ticksAtTime.get(computedTime);\n\n\t\t// this event allows forEachBetween to iterate until the current time\n\t\tconst tmpEvent: StateTimelineEvent = {\n\t\t\tstate: \"paused\",\n\t\t\ttime: computedTime,\n\t\t};\n\t\tthis._state.add(tmpEvent);\n\n\t\t// keep track of the previous offset event\n\t\tlet lastState = memoizedEvent ? memoizedEvent : stopEvent;\n\t\tlet elapsedTicks = memoizedEvent ? memoizedEvent.ticks : 0;\n\t\tlet eventToMemoize: TickSourceTicksAtTimeEvent | null = null;\n\n\t\t// iterate through all the events since the last stop\n\t\tthis._state.forEachBetween(\n\t\t\tlastState.time,\n\t\t\tcomputedTime + this.sampleTime,\n\t\t\t(e) => {\n\t\t\t\tlet periodStartTime = lastState.time;\n\t\t\t\t// if there is an offset event in this period use that\n\t\t\t\tconst offsetEvent = this._tickOffset.get(e.time);\n\t\t\t\tif (offsetEvent && offsetEvent.time >= lastState.time) {\n\t\t\t\t\telapsedTicks = offsetEvent.ticks;\n\t\t\t\t\tperiodStartTime = offsetEvent.time;\n\t\t\t\t}\n\t\t\t\tif (lastState.state === \"started\" && e.state !== \"started\") {\n\t\t\t\t\telapsedTicks +=\n\t\t\t\t\t\tthis.frequency.getTicksAtTime(e.time) -\n\t\t\t\t\t\tthis.frequency.getTicksAtTime(periodStartTime);\n\t\t\t\t\t// do not memoize the temporary event\n\t\t\t\t\tif (e.time !== tmpEvent.time) {\n\t\t\t\t\t\teventToMemoize = {\n\t\t\t\t\t\t\tstate: e.state,\n\t\t\t\t\t\t\ttime: e.time,\n\t\t\t\t\t\t\tticks: elapsedTicks,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlastState = e;\n\t\t\t}\n\t\t);\n\n\t\t// remove the temporary event\n\t\tthis._state.remove(tmpEvent);\n\n\t\t// memoize the ticks at the most recent event with state other than \"started\"\n\t\tif (eventToMemoize) {\n\t\t\tthis._ticksAtTime.add(eventToMemoize);\n\t\t}\n\n\t\t// return the ticks\n\t\treturn elapsedTicks;\n\t}\n\n\t/**\n\t * The number of times the callback was invoked. Starts counting at 0\n\t * and increments after the callback was invoked. Returns -1 when stopped.\n\t */\n\tget ticks(): Ticks {\n\t\treturn this.getTicksAtTime(this.now());\n\t}\n\tset ticks(t: Ticks) {\n\t\tthis.setTicksAtTime(t, this.now());\n\t}\n\n\t/**\n\t * The time since ticks=0 that the TickSource has been running. Accounts\n\t * for tempo curves\n\t */\n\tget seconds(): Seconds {\n\t\treturn this.getSecondsAtTime(this.now());\n\t}\n\tset seconds(s: Seconds) {\n\t\tconst now = this.now();\n\t\tconst ticks = this.frequency.timeToTicks(s, now);\n\t\tthis.setTicksAtTime(ticks, now);\n\t}\n\n\t/**\n\t * Return the elapsed seconds at the given time.\n\t * @param  time  When to get the elapsed seconds\n\t * @return  The number of elapsed seconds\n\t */\n\tgetSecondsAtTime(time: Time): Seconds {\n\t\ttime = this.toSeconds(time);\n\t\tconst stopEvent = this._state.getLastState(\n\t\t\t\"stopped\",\n\t\t\ttime\n\t\t) as StateTimelineEvent;\n\t\t// this event allows forEachBetween to iterate until the current time\n\t\tconst tmpEvent: StateTimelineEvent = { state: \"paused\", time };\n\t\tthis._state.add(tmpEvent);\n\n\t\t// get previously memoized seconds if available\n\t\tconst memoizedEvent = this._secondsAtTime.get(time);\n\n\t\t// keep track of the previous offset event\n\t\tlet lastState = memoizedEvent ? memoizedEvent : stopEvent;\n\t\tlet elapsedSeconds = memoizedEvent ? memoizedEvent.seconds : 0;\n\t\tlet eventToMemoize: TickSourceSecondsAtTimeEvent | null = null;\n\n\t\t// iterate through all the events since the last stop\n\t\tthis._state.forEachBetween(\n\t\t\tlastState.time,\n\t\t\ttime + this.sampleTime,\n\t\t\t(e) => {\n\t\t\t\tlet periodStartTime = lastState.time;\n\t\t\t\t// if there is an offset event in this period use that\n\t\t\t\tconst offsetEvent = this._tickOffset.get(e.time);\n\t\t\t\tif (offsetEvent && offsetEvent.time >= lastState.time) {\n\t\t\t\t\telapsedSeconds = offsetEvent.seconds;\n\t\t\t\t\tperiodStartTime = offsetEvent.time;\n\t\t\t\t}\n\t\t\t\tif (lastState.state === \"started\" && e.state !== \"started\") {\n\t\t\t\t\telapsedSeconds += e.time - periodStartTime;\n\t\t\t\t\t// do not memoize the temporary event\n\t\t\t\t\tif (e.time !== tmpEvent.time) {\n\t\t\t\t\t\teventToMemoize = {\n\t\t\t\t\t\t\tstate: e.state,\n\t\t\t\t\t\t\ttime: e.time,\n\t\t\t\t\t\t\tseconds: elapsedSeconds,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlastState = e;\n\t\t\t}\n\t\t);\n\n\t\t// remove the temporary event\n\t\tthis._state.remove(tmpEvent);\n\n\t\t// memoize the seconds at the most recent event with state other than \"started\"\n\t\tif (eventToMemoize) {\n\t\t\tthis._secondsAtTime.add(eventToMemoize);\n\t\t}\n\n\t\t// return the seconds\n\t\treturn elapsedSeconds;\n\t}\n\n\t/**\n\t * Set the clock's ticks at the given time.\n\t * @param  ticks The tick value to set\n\t * @param  time  When to set the tick value\n\t */\n\tsetTicksAtTime(ticks: Ticks, time: Time): this {\n\t\ttime = this.toSeconds(time);\n\t\tthis._tickOffset.cancel(time);\n\t\tthis._tickOffset.add({\n\t\t\tseconds: this.frequency.getDurationOfTicks(ticks, time),\n\t\t\tticks,\n\t\t\ttime,\n\t\t});\n\t\tthis._ticksAtTime.cancel(time);\n\t\tthis._secondsAtTime.cancel(time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Returns the scheduled state at the given time.\n\t * @param  time  The time to query.\n\t */\n\tgetStateAtTime(time: Time): PlaybackState {\n\t\ttime = this.toSeconds(time);\n\t\treturn this._state.getValueAtTime(time);\n\t}\n\n\t/**\n\t * Get the time of the given tick. The second argument\n\t * is when to test before. Since ticks can be set (with setTicksAtTime)\n\t * there may be multiple times for a given tick value.\n\t * @param  tick The tick number.\n\t * @param  before When to measure the tick value from.\n\t * @return The time of the tick\n\t */\n\tgetTimeOfTick(tick: Ticks, before = this.now()): Seconds {\n\t\tconst offset = this._tickOffset.get(before) as TickSourceOffsetEvent;\n\t\tconst event = this._state.get(before) as StateTimelineEvent;\n\t\tconst startTime = Math.max(offset.time, event.time);\n\t\tconst absoluteTicks =\n\t\t\tthis.frequency.getTicksAtTime(startTime) + tick - offset.ticks;\n\t\treturn this.frequency.getTimeOfTick(absoluteTicks);\n\t}\n\n\t/**\n\t * Invoke the callback event at all scheduled ticks between the\n\t * start time and the end time\n\t * @param  startTime  The beginning of the search range\n\t * @param  endTime    The end of the search range\n\t * @param  callback   The callback to invoke with each tick\n\t */\n\tforEachTickBetween(\n\t\tstartTime: number,\n\t\tendTime: number,\n\t\tcallback: (when: Seconds, ticks: Ticks) => void\n\t): this {\n\t\t// only iterate through the sections where it is \"started\"\n\t\tlet lastStateEvent = this._state.get(startTime);\n\t\tthis._state.forEachBetween(startTime, endTime, (event) => {\n\t\t\tif (\n\t\t\t\tlastStateEvent &&\n\t\t\t\tlastStateEvent.state === \"started\" &&\n\t\t\t\tevent.state !== \"started\"\n\t\t\t) {\n\t\t\t\tthis.forEachTickBetween(\n\t\t\t\t\tMath.max(lastStateEvent.time, startTime),\n\t\t\t\t\tevent.time - this.sampleTime,\n\t\t\t\t\tcallback\n\t\t\t\t);\n\t\t\t}\n\t\t\tlastStateEvent = event;\n\t\t});\n\n\t\tlet error: Error | null = null;\n\n\t\tif (lastStateEvent && lastStateEvent.state === \"started\") {\n\t\t\tconst maxStartTime = Math.max(lastStateEvent.time, startTime);\n\t\t\t// figure out the difference between the frequency ticks and the\n\t\t\tconst startTicks = this.frequency.getTicksAtTime(maxStartTime);\n\t\t\tconst ticksAtStart = this.frequency.getTicksAtTime(\n\t\t\t\tlastStateEvent.time\n\t\t\t);\n\t\t\tconst diff = startTicks - ticksAtStart;\n\t\t\tlet offset = Math.ceil(diff) - diff;\n\t\t\t// guard against floating point issues\n\t\t\toffset = EQ(offset, 1) ? 0 : offset;\n\t\t\tlet nextTickTime = this.frequency.getTimeOfTick(\n\t\t\t\tstartTicks + offset\n\t\t\t);\n\t\t\twhile (nextTickTime < endTime) {\n\t\t\t\ttry {\n\t\t\t\t\tcallback(\n\t\t\t\t\t\tnextTickTime,\n\t\t\t\t\t\tMath.round(this.getTicksAtTime(nextTickTime))\n\t\t\t\t\t);\n\t\t\t\t} catch (e) {\n\t\t\t\t\terror = e;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tnextTickTime += this.frequency.getDurationOfTicks(\n\t\t\t\t\t1,\n\t\t\t\t\tnextTickTime\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (error) {\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clean up\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._state.dispose();\n\t\tthis._tickOffset.dispose();\n\t\tthis._ticksAtTime.dispose();\n\t\tthis._secondsAtTime.dispose();\n\t\tthis.frequency.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/core/clock/Ticker.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { Ticker } from \"./Ticker.js\";\n\ndescribe(\"Ticker\", () => {\n\tfunction empty(): void {\n\t\t// do nothing\n\t}\n\n\tit(\"can be created and disposed\", () => {\n\t\tconst ticker = new Ticker(empty, \"offline\", 1);\n\t\tticker.dispose();\n\t});\n\n\tit(\"can adjust the type\", () => {\n\t\tconst ticker = new Ticker(empty, \"worker\", 0.1);\n\t\texpect(ticker.type).to.equal(\"worker\");\n\t\tticker.type = \"timeout\";\n\t\texpect(ticker.type).to.equal(\"timeout\");\n\t\tticker.type = \"offline\";\n\t\texpect(ticker.type).to.equal(\"offline\");\n\t\tticker.dispose();\n\t});\n\n\tit(\"can get/set the updateInterval\", () => {\n\t\tconst ticker = new Ticker(empty, \"worker\", 0.1);\n\t\texpect(ticker.updateInterval).to.equal(0.1);\n\t\tticker.updateInterval = 0.5;\n\t\texpect(ticker.updateInterval).to.equal(0.5);\n\t\tticker.dispose();\n\t});\n\n\tcontext(\"timeout\", () => {\n\t\tit(\"provides a callback when set to timeout\", (done) => {\n\t\t\tconst ticker = new Ticker(\n\t\t\t\t() => {\n\t\t\t\t\tticker.dispose();\n\t\t\t\t\tdone();\n\t\t\t\t},\n\t\t\t\t\"timeout\",\n\t\t\t\t0.01\n\t\t\t);\n\t\t});\n\n\t\tit(\"can adjust the interval when set to timeout\", (done) => {\n\t\t\tconst ticker = new Ticker(\n\t\t\t\t() => {\n\t\t\t\t\tticker.dispose();\n\t\t\t\t\tdone();\n\t\t\t\t},\n\t\t\t\t\"timeout\",\n\t\t\t\t0.01\n\t\t\t);\n\t\t\tticker.updateInterval = 0.1;\n\t\t});\n\t});\n\n\tcontext(\"worker\", () => {\n\t\tit(\"provides a callback when set to worker\", (done) => {\n\t\t\tconst ticker = new Ticker(\n\t\t\t\t() => {\n\t\t\t\t\tticker.dispose();\n\t\t\t\t\tdone();\n\t\t\t\t},\n\t\t\t\t\"worker\",\n\t\t\t\t0.01\n\t\t\t);\n\t\t});\n\n\t\tit(\"falls back to timeout if the constructor throws an error\", (done) => {\n\t\t\tconst URL = window.URL;\n\t\t\t// @ts-ignore\n\t\t\twindow.URL = null;\n\t\t\tconst ticker = new Ticker(\n\t\t\t\t() => {\n\t\t\t\t\texpect(ticker.type).to.equal(\"timeout\");\n\t\t\t\t\tticker.dispose();\n\t\t\t\t\twindow.URL = URL;\n\t\t\t\t\tdone();\n\t\t\t\t},\n\t\t\t\t\"worker\",\n\t\t\t\t0.01\n\t\t\t);\n\t\t});\n\n\t\tit(\"can adjust the interval when set to worker\", (done) => {\n\t\t\tconst ticker = new Ticker(\n\t\t\t\t() => {\n\t\t\t\t\tticker.dispose();\n\t\t\t\t\tdone();\n\t\t\t\t},\n\t\t\t\t\"worker\",\n\t\t\t\t0.01\n\t\t\t);\n\t\t\tticker.updateInterval = 0.1;\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/clock/Ticker.ts",
    "content": "import { Seconds } from \"../type/Units.js\";\n\nexport type TickerClockSource = \"worker\" | \"timeout\" | \"offline\";\n\n/**\n * A class which provides a reliable callback using either\n * a Web Worker, or if that isn't supported, falls back to setTimeout.\n */\nexport class Ticker {\n\t/**\n\t * Either \"worker\" or \"timeout\" or \"offline\"\n\t */\n\tprivate _type: TickerClockSource;\n\n\t/**\n\t * The update interval of the worker\n\t */\n\tprivate _updateInterval!: Seconds;\n\n\t/**\n\t * The lowest allowable interval, preferably calculated from context sampleRate\n\t */\n\tprivate _minimumUpdateInterval: Seconds;\n\n\t/**\n\t * The callback to invoke at regular intervals\n\t */\n\tprivate _callback: () => void;\n\n\t/**\n\t * track the callback interval\n\t */\n\tprivate _timeout!: ReturnType<typeof setTimeout>;\n\n\t/**\n\t * private reference to the worker\n\t */\n\tprivate _worker!: Worker;\n\n\tconstructor(\n\t\tcallback: () => void,\n\t\ttype: TickerClockSource,\n\t\tupdateInterval: Seconds,\n\t\tcontextSampleRate?: number\n\t) {\n\t\tthis._callback = callback;\n\t\tthis._type = type;\n\t\tthis._minimumUpdateInterval = Math.max(\n\t\t\t128 / (contextSampleRate || 44100),\n\t\t\t0.001\n\t\t);\n\t\tthis.updateInterval = updateInterval;\n\n\t\t// create the clock source for the first time\n\t\tthis._createClock();\n\t}\n\n\t/**\n\t * Generate a web worker\n\t */\n\tprivate _createWorker(): void {\n\t\tconst blob = new Blob(\n\t\t\t[\n\t\t\t\t/* javascript */ `\n\t\t\t// the initial timeout time\n\t\t\tlet timeoutTime =  ${(this._updateInterval * 1000).toFixed(1)};\n\t\t\t// onmessage callback\n\t\t\tself.onmessage = function(msg){\n\t\t\t\ttimeoutTime = parseInt(msg.data);\n\t\t\t};\n\t\t\t// the tick function which posts a message\n\t\t\t// and schedules a new tick\n\t\t\tfunction tick(){\n\t\t\t\tsetTimeout(tick, timeoutTime);\n\t\t\t\tself.postMessage('tick');\n\t\t\t}\n\t\t\t// call tick initially\n\t\t\ttick();\n\t\t\t`,\n\t\t\t],\n\t\t\t{ type: \"text/javascript\" }\n\t\t);\n\t\tconst blobUrl = URL.createObjectURL(blob);\n\t\tconst worker = new Worker(blobUrl);\n\n\t\tworker.onmessage = this._callback.bind(this);\n\n\t\tthis._worker = worker;\n\t}\n\n\t/**\n\t * Create a timeout loop\n\t */\n\tprivate _createTimeout(): void {\n\t\tthis._timeout = setTimeout(() => {\n\t\t\tthis._createTimeout();\n\t\t\tthis._callback();\n\t\t}, this._updateInterval * 1000);\n\t}\n\n\t/**\n\t * Create the clock source.\n\t */\n\tprivate _createClock(): void {\n\t\tif (this._type === \"worker\") {\n\t\t\ttry {\n\t\t\t\tthis._createWorker();\n\t\t\t\t// eslint-disable-next-line unused-imports/no-unused-vars\n\t\t\t} catch (e) {\n\t\t\t\t// workers not supported, fallback to timeout\n\t\t\t\tthis._type = \"timeout\";\n\t\t\t\tthis._createClock();\n\t\t\t}\n\t\t} else if (this._type === \"timeout\") {\n\t\t\tthis._createTimeout();\n\t\t}\n\t}\n\n\t/**\n\t * Clean up the current clock source\n\t */\n\tprivate _disposeClock(): void {\n\t\tif (this._timeout) {\n\t\t\tclearTimeout(this._timeout);\n\t\t}\n\t\tif (this._worker) {\n\t\t\tthis._worker.terminate();\n\t\t\tthis._worker.onmessage = null;\n\t\t}\n\t}\n\n\t/**\n\t * The rate in seconds the ticker will update\n\t */\n\tget updateInterval(): Seconds {\n\t\treturn this._updateInterval;\n\t}\n\tset updateInterval(interval: Seconds) {\n\t\tthis._updateInterval = Math.max(interval, this._minimumUpdateInterval);\n\t\tif (this._type === \"worker\") {\n\t\t\tthis._worker?.postMessage(this._updateInterval * 1000);\n\t\t}\n\t}\n\n\t/**\n\t * The type of the ticker, either a worker or a timeout\n\t */\n\tget type(): TickerClockSource {\n\t\treturn this._type;\n\t}\n\tset type(type: TickerClockSource) {\n\t\tthis._disposeClock();\n\t\tthis._type = type;\n\t\tthis._createClock();\n\t}\n\n\t/**\n\t * Clean up\n\t */\n\tdispose(): void {\n\t\tthis._disposeClock();\n\t}\n}\n"
  },
  {
    "path": "Tone/core/clock/Transport.test.ts",
    "content": "// importing for side affects\nimport \"../context/Destination.js\";\n\nimport { expect } from \"chai\";\n\nimport { warns } from \"../../../test/helper/Basic.js\";\nimport { atTime, Offline, whenBetween } from \"../../../test/helper/Offline.js\";\nimport { Synth } from \"../../instrument/Synth.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { Time } from \"../type/Time.js\";\nimport { TransportTime } from \"../type/TransportTime.js\";\nimport { noOp } from \"../util/Interface.js\";\nimport { TransportInstance } from \"./Transport.js\";\n\ndescribe(\"Transport\", () => {\n\tcontext(\"BPM and timeSignature\", () => {\n\t\tit(\"can get and set bpm\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.bpm.value = 125;\n\t\t\t\texpect(transport.bpm.value).to.be.closeTo(125, 0.001);\n\t\t\t\ttransport.bpm.value = 120;\n\t\t\t\texpect(transport.bpm.value).to.equal(120);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get and set timeSignature as both an array or number\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.timeSignature = [6, 8];\n\t\t\t\texpect(transport.timeSignature).to.equal(3);\n\t\t\t\ttransport.timeSignature = 5;\n\t\t\t\texpect(transport.timeSignature).to.equal(5);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get and set timeSignature as both an array or number\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.timeSignature = [6, 8];\n\t\t\t\texpect(transport.timeSignature).to.equal(3);\n\t\t\t\ttransport.timeSignature = 5;\n\t\t\t\texpect(transport.timeSignature).to.equal(5);\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"looping\", () => {\n\t\tit(\"can get and set loop points\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.loopStart = 0.2;\n\t\t\t\ttransport.loopEnd = 0.4;\n\t\t\t\texpect(transport.loopStart).to.be.closeTo(0.2, 0.01);\n\t\t\t\texpect(transport.loopEnd).to.be.closeTo(0.4, 0.01);\n\t\t\t\ttransport.setLoopPoints(0, \"1m\");\n\t\t\t\texpect(transport.loopStart).to.be.closeTo(0, 0.01);\n\t\t\t\texpect(transport.loopEnd).to.be.closeTo(\n\t\t\t\t\ttransport.toSeconds(\"1m\"),\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can loop events scheduled on the transport\", async () => {\n\t\t\tlet invocations = 0;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.schedule((time) => {\n\t\t\t\t\tinvocations++;\n\t\t\t\t}, 0);\n\t\t\t\ttransport.setLoopPoints(0, 0.1).start(0);\n\t\t\t\ttransport.loop = true;\n\t\t\t}, 0.41);\n\t\t\texpect(invocations).to.equal(5);\n\t\t});\n\n\t\tit(\"jumps to the loopStart after the loopEnd point\", async () => {\n\t\t\tlet looped = false;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.on(\"loop\", () => {\n\t\t\t\t\tlooped = true;\n\t\t\t\t});\n\t\t\t\ttransport.loop = true;\n\t\t\t\ttransport.loopEnd = 1;\n\t\t\t\ttransport.seconds = 2;\n\t\t\t\ttransport.start();\n\t\t\t}, 0.4);\n\t\t\texpect(looped).to.equal(true);\n\t\t});\n\t});\n\n\tcontext(\"nextSubdivision\", () => {\n\t\tit(\"returns 0 if the transports not started\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\texpect(transport.nextSubdivision()).to.equal(0);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get the next subdivision of the transport\", async () => {\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.start(0);\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0.05, 0.07, () => {\n\t\t\t\t\t\texpect(transport.nextSubdivision(0.5)).to.be.closeTo(\n\t\t\t\t\t\t\t0.5,\n\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t);\n\t\t\t\t\t\texpect(transport.nextSubdivision(0.04)).to.be.closeTo(\n\t\t\t\t\t\t\t0.08,\n\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t);\n\t\t\t\t\t\texpect(transport.nextSubdivision(2)).to.be.closeTo(\n\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.09, 0.1, () => {\n\t\t\t\t\t\texpect(transport.nextSubdivision(0.04)).to.be.closeTo(\n\t\t\t\t\t\t\t0.12,\n\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t);\n\t\t\t\t\t\texpect(transport.nextSubdivision(\"8n\")).to.be.closeTo(\n\t\t\t\t\t\t\t0.25,\n\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.1);\n\t\t});\n\t});\n\n\tcontext(\"PPQ\", () => {\n\t\tit(\"can get and set pulses per quarter\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.PPQ = 96;\n\t\t\t\texpect(transport.PPQ).to.equal(96);\n\t\t\t});\n\t\t});\n\n\t\tit(\"schedules a quarter note at the same time with a different PPQ\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.PPQ = 1;\n\t\t\t\tconst id = transport.schedule((time) => {\n\t\t\t\t\texpect(time).to.be.closeTo(transport.toSeconds(\"4n\"), 0.1);\n\t\t\t\t\ttransport.clear(id);\n\t\t\t\t}, \"4n\");\n\t\t\t\ttransport.start();\n\t\t\t});\n\t\t});\n\n\t\tit(\"invokes the right number of ticks with a different PPQ\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.bpm.value = 120;\n\t\t\t\tconst ppq = 20;\n\t\t\t\ttransport.PPQ = ppq;\n\t\t\t\ttransport.start();\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time > 0.5) {\n\t\t\t\t\t\texpect(transport.ticks).to.be.within(ppq, ppq * 1.2);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.55);\n\t\t});\n\t});\n\n\tcontext(\"position\", () => {\n\t\tit(\"can jump to a specific tick number\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.ticks = 200;\n\t\t\t\texpect(transport.ticks).to.equal(200);\n\t\t\t\ttransport.start(0);\n\t\t\t\tlet tested = false;\n\t\t\t\treturn () => {\n\t\t\t\t\tif (!tested) {\n\t\t\t\t\t\texpect(transport.ticks).to.at.least(200);\n\t\t\t\t\t\ttested = true;\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.1);\n\t\t});\n\n\t\tit(\"can get the current position in BarsBeatsSixteenths\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\texpect(transport.position).to.equal(\"0:0:0\");\n\t\t\t\ttransport.start(0);\n\t\t\t\treturn atTime(0.05, () => {\n\t\t\t\t\texpect(transport.position).to.not.equal(\"0:0:0\");\n\t\t\t\t});\n\t\t\t}, 0.1);\n\t\t});\n\n\t\tit(\"can get the current position in seconds\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\texpect(transport.seconds).to.equal(0);\n\t\t\t\ttransport.start(0.05);\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time > 0.05) {\n\t\t\t\t\t\texpect(transport.seconds).to.be.closeTo(\n\t\t\t\t\t\t\ttime - 0.05,\n\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.1);\n\t\t});\n\n\t\tit(\"can get the current position in seconds during a bpm ramp\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\texpect(transport.seconds).to.equal(0);\n\t\t\t\ttransport.start(0.05);\n\t\t\t\ttransport.bpm.linearRampTo(60, 0.5, 0.5);\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time > 0.05) {\n\t\t\t\t\t\texpect(transport.seconds).to.be.closeTo(\n\t\t\t\t\t\t\ttime - 0.05,\n\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.7);\n\t\t});\n\n\t\tit(\"can set the current position in seconds\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\texpect(transport.seconds).to.equal(0);\n\t\t\t\ttransport.seconds = 3;\n\t\t\t\texpect(transport.seconds).to.be.closeTo(3, 0.01);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can schedule the current seconds position\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.start();\n\n\t\t\t\tlet scheduled = false;\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time > 0.5 && !scheduled) {\n\t\t\t\t\t\tscheduled = true;\n\t\t\t\t\t\ttransport.setSecondsAtTime(3, 0.5);\n\t\t\t\t\t}\n\n\t\t\t\t\twhenBetween(time, 0, 0.5, () => {\n\t\t\t\t\t\texpect(transport.seconds).to.be.closeTo(time, 0.01);\n\t\t\t\t\t});\n\n\t\t\t\t\twhenBetween(time, 0.5, 1, () => {\n\t\t\t\t\t\texpect(transport.seconds).to.be.closeTo(\n\t\t\t\t\t\t\t2.5 + time,\n\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 1);\n\t\t});\n\n\t\tit(\"can set the current position in BarsBeatsSixteenths\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\texpect(transport.position).to.equal(\"0:0:0\");\n\t\t\t\ttransport.position = \"3:0\";\n\t\t\t\texpect(transport.position).to.equal(\"3:0:0\");\n\t\t\t\ttransport.position = \"0:0\";\n\t\t\t\texpect(transport.position).to.equal(\"0:0:0\");\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get the progress of the loop\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.setLoopPoints(0, \"1m\").start();\n\t\t\t\ttransport.loop = true;\n\t\t\t\texpect(transport.progress).to.be.equal(0);\n\t\t\t\ttransport.position = \"2n\";\n\t\t\t\texpect(transport.progress).to.be.closeTo(0.5, 0.001);\n\t\t\t\ttransport.position =\n\t\t\t\t\tTime(\"2n\").valueOf() + Time(\"4n\").valueOf();\n\t\t\t\texpect(transport.progress).to.be.closeTo(0.75, 0.001);\n\t\t\t});\n\t\t});\n\n\t\tit(\"progress is always 0 when not looping\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\ttransport.loop = false;\n\t\t\t\ttransport.start();\n\t\t\t\treturn atTime(0.1, () => {\n\t\t\t\t\texpect(transport.progress).to.be.equal(0);\n\t\t\t\t});\n\t\t\t}, 0.2);\n\t\t});\n\n\t\tit(\"invokes the first callback time when the scheduled time is a non-integer tick time\", async () => {\n\t\t\tlet wasCalled = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\t// choose a value which is not cleanly representable as ticks\n\t\t\t\tconst problemValue = Time(100, \"i\").toSeconds() + 0.01;\n\t\t\t\ttransport.seconds = problemValue;\n\t\t\t\ttransport.schedule(() => {\n\t\t\t\t\twasCalled = true;\n\t\t\t\t}, problemValue);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.2);\n\t\t\texpect(wasCalled).to.be.true;\n\t\t});\n\n\t\tit(\"setting the same ticks value twice does not emit twice\", async () => {\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tlet callCount = 0;\n\t\t\t\ttransport.on(\"ticks\", () => {\n\t\t\t\t\tcallCount++;\n\t\t\t\t});\n\t\t\t\ttransport.ticks = 100;\n\t\t\t\texpect(transport.ticks).to.equal(100);\n\t\t\t\texpect(callCount).to.equal(1);\n\n\t\t\t\t// set it to the same value again has no change\n\t\t\t\ttransport.ticks = 100;\n\t\t\t\texpect(callCount).to.equal(1);\n\t\t\t}, 0.1);\n\t\t});\n\t});\n\n\tcontext(\"state\", () => {\n\t\tit(\"can start, pause, and restart\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\ttransport.start(0).pause(0.2).start(0.4);\n\n\t\t\t\tconst pulse = new Signal(0).toDestination();\n\n\t\t\t\ttransport.schedule((time) => {\n\t\t\t\t\tpulse.setValueAtTime(1, time);\n\t\t\t\t\tpulse.setValueAtTime(0, time + 0.1);\n\t\t\t\t}, 0);\n\n\t\t\t\ttransport.schedule((time) => {\n\t\t\t\t\tpulse.setValueAtTime(1, time);\n\t\t\t\t\tpulse.setValueAtTime(0, time + 0.1);\n\t\t\t\t}, 0.3);\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, 0.2, () => {\n\t\t\t\t\t\texpect(transport.state).to.equal(\"started\");\n\t\t\t\t\t});\n\n\t\t\t\t\twhenBetween(time, 0.2, 0.4, () => {\n\t\t\t\t\t\texpect(transport.state).to.equal(\"paused\");\n\t\t\t\t\t});\n\n\t\t\t\t\twhenBetween(time, 0.4, Infinity, () => {\n\t\t\t\t\t\texpect(transport.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.6);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\twhenBetween(time, 0, 0.01, () => {\n\t\t\t\t\texpect(sample).to.equal(1);\n\t\t\t\t});\n\t\t\t\twhenBetween(time, 0.1, 0.11, () => {\n\t\t\t\t\texpect(sample).to.equal(0);\n\t\t\t\t});\n\t\t\t\twhenBetween(time, 0.502, 0.51, () => {\n\t\t\t\t\texpect(sample).to.equal(1);\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"ticks\", () => {\n\t\tit(\"resets ticks on stop but not on pause\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.start(0).pause(0.1).stop(0.2);\n\t\t\t\texpect(transport.getTicksAtTime(0)).to.be.equal(\n\t\t\t\t\tMath.floor(transport.PPQ * 0)\n\t\t\t\t);\n\t\t\t\texpect(transport.getTicksAtTime(0.05)).to.be.closeTo(\n\t\t\t\t\tMath.floor(transport.PPQ * 0.1),\n\t\t\t\t\t0.5\n\t\t\t\t);\n\t\t\t\texpect(transport.getTicksAtTime(0.1)).to.be.closeTo(\n\t\t\t\t\tMath.floor(transport.PPQ * 0.2),\n\t\t\t\t\t0.5\n\t\t\t\t);\n\t\t\t\texpect(transport.getTicksAtTime(0.15)).to.be.closeTo(\n\t\t\t\t\tMath.floor(transport.PPQ * 0.2),\n\t\t\t\t\t0.5\n\t\t\t\t);\n\t\t\t\texpect(transport.getTicksAtTime(0.2)).to.be.equal(0);\n\t\t\t}, 0.3);\n\t\t});\n\n\t\tit(\"tracks ticks after start\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.bpm.value = 120;\n\t\t\t\tconst ppq = transport.PPQ;\n\t\t\t\ttransport.start();\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time > 0.5) {\n\t\t\t\t\t\texpect(transport.ticks).to.at.least(ppq);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.6);\n\t\t});\n\n\t\tit(\"can start with a tick offset\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.start(0, \"200i\");\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time < 0.01) {\n\t\t\t\t\t\texpect(transport.ticks).to.at.least(200);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.1);\n\t\t});\n\n\t\tit(\"can toggle the state of the transport\", async () => {\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.toggle(0);\n\t\t\t\ttransport.toggle(0.2);\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, 0.2, () => {\n\t\t\t\t\t\texpect(transport.state).to.equal(\"started\");\n\t\t\t\t\t});\n\n\t\t\t\t\twhenBetween(time, 0.2, Infinity, () => {\n\t\t\t\t\t\texpect(transport.state).to.equal(\"stopped\");\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.1);\n\t\t});\n\n\t\tit(\"tracks ticks correctly with a different PPQ and BPM\", async () => {\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.PPQ = 96;\n\t\t\t\ttransport.bpm.value = 90;\n\t\t\t\ttransport.start();\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time > 0.5) {\n\t\t\t\t\t\texpect(transport.ticks).to.at.least(72);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.6);\n\t\t});\n\n\t\tit(\"can set the ticks while started\", async () => {\n\t\t\tlet invocations = 0;\n\t\t\tconst times = [0, 1.5];\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\ttransport.PPQ = 1;\n\t\t\t\ttransport.schedule((time) => {\n\t\t\t\t\texpect(time).to.be.closeTo(times[invocations], 0.01);\n\t\t\t\t\tinvocations++;\n\t\t\t\t}, 0);\n\t\t\t\ttransport.start(0);\n\t\t\t\treturn atTime(1.1, () => {\n\t\t\t\t\ttransport.ticks = 0;\n\t\t\t\t});\n\t\t\t}, 2.5);\n\t\t\texpect(invocations).to.equal(2);\n\t\t});\n\n\t\tit(\"can schedule the ticks\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.start();\n\n\t\t\t\tlet scheduled = false;\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time > 0.5 && !scheduled) {\n\t\t\t\t\t\tscheduled = true;\n\t\t\t\t\t\ttransport.setTicksAtTime(0, 0.5);\n\t\t\t\t\t}\n\n\t\t\t\t\twhenBetween(time, 0, 0.5, () => {\n\t\t\t\t\t\texpect(transport.ticks).to.be.closeTo(\n\t\t\t\t\t\t\ttransport.toTicks(time),\n\t\t\t\t\t\t\t1\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\n\t\t\t\t\twhenBetween(time, 0.5, 1, () => {\n\t\t\t\t\t\texpect(transport.ticks).to.be.closeTo(\n\t\t\t\t\t\t\ttransport.toTicks(time - 0.5),\n\t\t\t\t\t\t\t1\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 1);\n\t\t});\n\t});\n\n\tcontext(\"schedule\", () => {\n\t\tit(\"can schedule an event on the timeline\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\tconst eventID = transport.schedule(() => {}, 0);\n\t\t\t\texpect(eventID).to.be.a(\"number\");\n\t\t\t});\n\t\t});\n\n\t\tit(\"scheduled event gets invoked with the time of the event\", async () => {\n\t\t\tlet wasCalled = false;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\tconst startTime = 0.1;\n\t\t\t\ttransport.schedule((time) => {\n\t\t\t\t\texpect(time).to.be.closeTo(startTime, 0.01);\n\t\t\t\t\twasCalled = true;\n\t\t\t\t}, 0);\n\t\t\t\ttransport.start(startTime);\n\t\t\t}, 0.2);\n\t\t\texpect(wasCalled).to.equal(true);\n\t\t});\n\n\t\tit(\"can schedule events with TransportTime\", async () => {\n\t\t\tlet wasCalled = false;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\tconst startTime = 0.1;\n\t\t\t\tconst eighth = transport.toSeconds(\"8n\");\n\t\t\t\ttransport.schedule((time) => {\n\t\t\t\t\texpect(time).to.be.closeTo(startTime + eighth, 0.01);\n\t\t\t\t\twasCalled = true;\n\t\t\t\t}, TransportTime(\"8n\"));\n\t\t\t\ttransport.start(startTime);\n\t\t\t}, 0.5);\n\t\t\texpect(wasCalled).to.be.true;\n\t\t});\n\n\t\tit(\"can clear a scheduled event\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\tconst eventID = transport.schedule(() => {\n\t\t\t\t\tthrow new Error(\"should not call this function\");\n\t\t\t\t}, 0);\n\t\t\t\ttransport.clear(eventID);\n\t\t\t\ttransport.start();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can cancel the timeline of scheduled object\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.schedule(() => {\n\t\t\t\t\tthrow new Error(\"should not call this\");\n\t\t\t\t}, 0);\n\t\t\t\ttransport.cancel(0);\n\t\t\t\ttransport.start(0);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can cancel the timeline of scheduleOnce object\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.scheduleOnce(() => {\n\t\t\t\t\tthrow new Error(\"should not call this\");\n\t\t\t\t}, 0);\n\t\t\t\ttransport.cancel(0);\n\t\t\t\ttransport.start(0);\n\t\t\t});\n\t\t});\n\n\t\tit(\"scheduled event anywhere along the timeline\", async () => {\n\t\t\tlet wasCalled = false;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\tconst startTime = transport.now();\n\t\t\t\ttransport.schedule((time) => {\n\t\t\t\t\texpect(time).to.be.closeTo(startTime + 0.5, 0.001);\n\t\t\t\t\twasCalled = true;\n\t\t\t\t}, 0.5);\n\t\t\t\ttransport.start(startTime);\n\t\t\t}, 0.6);\n\t\t\texpect(wasCalled).to.equal(true);\n\t\t});\n\n\t\tit(\"can schedule multiple events and invoke them in the right order\", async () => {\n\t\t\tlet wasCalled = false;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\tlet first = false;\n\t\t\t\ttransport.schedule(() => {\n\t\t\t\t\tfirst = true;\n\t\t\t\t}, 0.1);\n\t\t\t\ttransport.schedule(() => {\n\t\t\t\t\texpect(first).to.equal(true);\n\t\t\t\t\twasCalled = true;\n\t\t\t\t}, 0.11);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.2);\n\t\t\texpect(wasCalled).to.equal(true);\n\t\t});\n\n\t\tit(\"invokes the event again if the timeline is restarted\", async () => {\n\t\t\tlet iterations = 0;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.schedule(() => {\n\t\t\t\t\titerations++;\n\t\t\t\t}, 0.05);\n\t\t\t\ttransport.start(0).stop(0.1).start(0.2);\n\t\t\t}, 0.3);\n\t\t\texpect(iterations).to.be.equal(2);\n\t\t});\n\n\t\tit(\"can add an event after the Transport is started\", async () => {\n\t\t\tlet wasCalled = false;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.start(0);\n\t\t\t\tlet wasScheduled = false;\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time > 0.1 && !wasScheduled) {\n\t\t\t\t\t\twasScheduled = true;\n\t\t\t\t\t\ttransport.schedule(() => {\n\t\t\t\t\t\t\twasCalled = true;\n\t\t\t\t\t\t}, 0.15);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.3);\n\t\t\texpect(wasCalled).to.equal(true);\n\t\t});\n\n\t\tit(\"warns if the scheduled time was not used in the callback\", async () => {\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst synth = new Synth();\n\t\t\t\ttransport.schedule(() => {\n\t\t\t\t\twarns(() => {\n\t\t\t\t\t\tsynth.triggerAttackRelease(\"C2\", 0.1);\n\t\t\t\t\t});\n\t\t\t\t}, 0);\n\t\t\t\ttransport.start(0);\n\t\t\t}, 0.3);\n\t\t});\n\t});\n\n\tcontext(\"scheduleRepeat\", () => {\n\t\tit(\"can schedule a repeated event\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\tconst eventID = transport.scheduleRepeat(noOp, 1);\n\t\t\t\texpect(eventID).to.be.a(\"number\");\n\t\t\t});\n\t\t});\n\n\t\tit(\"scheduled event gets invoked with the time of the event\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\tconst startTime = 0.1;\n\t\t\t\tconst eventID = transport.scheduleRepeat(\n\t\t\t\t\t(time) => {\n\t\t\t\t\t\texpect(time).to.be.closeTo(startTime, 0.01);\n\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t\ttransport.clear(eventID);\n\t\t\t\t\t},\n\t\t\t\t\t1,\n\t\t\t\t\t0\n\t\t\t\t);\n\t\t\t\ttransport.start(startTime);\n\t\t\t}, 0.3);\n\t\t\texpect(invoked).to.equal(true);\n\t\t});\n\n\t\tit(\"can cancel the timeline of scheduleRepeat\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.scheduleRepeat(\n\t\t\t\t\t() => {\n\t\t\t\t\t\tthrow new Error(\"should not call this\");\n\t\t\t\t\t},\n\t\t\t\t\t0.01,\n\t\t\t\t\t0\n\t\t\t\t);\n\t\t\t\ttransport.cancel(0);\n\t\t\t\ttransport.start(0);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can schedule events with TransportTime\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\tconst startTime = 0.1;\n\t\t\t\tconst eighth = transport.toSeconds(\"8n\");\n\t\t\t\ttransport.scheduleRepeat(\n\t\t\t\t\t(time) => {\n\t\t\t\t\t\texpect(time).to.be.closeTo(startTime + eighth, 0.01);\n\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t},\n\t\t\t\t\t\"1n\",\n\t\t\t\t\tTransportTime(\"8n\")\n\t\t\t\t);\n\t\t\t\ttransport.start(startTime);\n\t\t\t}, 0.4);\n\t\t\texpect(invoked).to.equal(true);\n\t\t});\n\n\t\tit(\"can clear a scheduled event\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\tconst eventID = transport.scheduleRepeat(\n\t\t\t\t\t() => {\n\t\t\t\t\t\tthrow new Error(\"should not call this function\");\n\t\t\t\t\t},\n\t\t\t\t\t1,\n\t\t\t\t\t0\n\t\t\t\t);\n\t\t\t\ttransport.clear(eventID);\n\t\t\t\ttransport.stop();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can be scheduled in the future\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\tconst startTime = 0.1;\n\t\t\t\tconst eventID = transport.scheduleRepeat(\n\t\t\t\t\t(time) => {\n\t\t\t\t\t\ttransport.clear(eventID);\n\t\t\t\t\t\texpect(time).to.be.closeTo(startTime + 0.2, 0.01);\n\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t},\n\t\t\t\t\t1,\n\t\t\t\t\t0.2\n\t\t\t\t);\n\t\t\t\ttransport.start(startTime);\n\t\t\t}, 0.5);\n\t\t\texpect(invoked).to.equal(true);\n\t\t});\n\n\t\tit(\"repeats a repeat event\", async () => {\n\t\t\tlet invocations = 0;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.scheduleRepeat(\n\t\t\t\t\t() => {\n\t\t\t\t\t\tinvocations++;\n\t\t\t\t\t},\n\t\t\t\t\t0.1,\n\t\t\t\t\t0\n\t\t\t\t);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.51);\n\t\t\texpect(invocations).to.equal(6);\n\t\t});\n\n\t\tit(\"repeats at the repeat interval\", async () => {\n\t\t\tlet wasCalled = false;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\tlet repeatTime = -1;\n\t\t\t\ttransport.scheduleRepeat(\n\t\t\t\t\t(time) => {\n\t\t\t\t\t\tif (repeatTime !== -1) {\n\t\t\t\t\t\t\texpect(time - repeatTime).to.be.closeTo(0.1, 0.01);\n\t\t\t\t\t\t}\n\t\t\t\t\t\trepeatTime = time;\n\t\t\t\t\t\twasCalled = true;\n\t\t\t\t\t},\n\t\t\t\t\t0.1,\n\t\t\t\t\t0\n\t\t\t\t);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.5);\n\t\t\texpect(wasCalled).to.equal(true);\n\t\t});\n\n\t\tit(\"can schedule multiple events and invoke them in the right order\", async () => {\n\t\t\tlet first = false;\n\t\t\tlet second = false;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\tconst firstID = transport.scheduleRepeat(\n\t\t\t\t\t() => {\n\t\t\t\t\t\tfirst = true;\n\t\t\t\t\t\ttransport.clear(firstID);\n\t\t\t\t\t},\n\t\t\t\t\t1,\n\t\t\t\t\t0.1\n\t\t\t\t);\n\t\t\t\tconst secondID = transport.scheduleRepeat(\n\t\t\t\t\t() => {\n\t\t\t\t\t\ttransport.clear(secondID);\n\t\t\t\t\t\texpect(first).to.equal(true);\n\t\t\t\t\t\tsecond = true;\n\t\t\t\t\t},\n\t\t\t\t\t1,\n\t\t\t\t\t0.11\n\t\t\t\t);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.3);\n\t\t\texpect(first);\n\t\t\texpect(second);\n\t\t});\n\n\t\tit(\"repeats for the given interval\", async () => {\n\t\t\tlet repeatCount = 0;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.scheduleRepeat(\n\t\t\t\t\t(time) => {\n\t\t\t\t\t\trepeatCount++;\n\t\t\t\t\t},\n\t\t\t\t\t0.1,\n\t\t\t\t\t0,\n\t\t\t\t\t0.5\n\t\t\t\t);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.61);\n\t\t\texpect(repeatCount).to.equal(5);\n\t\t});\n\n\t\tit(\"can add an event after the Transport is started\", async () => {\n\t\t\tlet invocations = 0;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.start(0);\n\t\t\t\tlet wasScheduled = false;\n\t\t\t\tconst times = [0.15, 0.3];\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time > 0.1 && !wasScheduled) {\n\t\t\t\t\t\twasScheduled = true;\n\t\t\t\t\t\ttransport.scheduleRepeat(\n\t\t\t\t\t\t\t(repeatedTime) => {\n\t\t\t\t\t\t\t\texpect(repeatedTime).to.be.closeTo(\n\t\t\t\t\t\t\t\t\ttimes[invocations],\n\t\t\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tinvocations++;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t0.15,\n\t\t\t\t\t\t\t0.15\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.31);\n\t\t\texpect(invocations).to.equal(2);\n\t\t});\n\n\t\tit(\"can add an event to the past after the Transport is started\", async () => {\n\t\t\tlet invocations = 0;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.start(0);\n\t\t\t\tlet wasScheduled = false;\n\t\t\t\tconst times = [0.15, 0.25];\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time >= 0.12 && !wasScheduled) {\n\t\t\t\t\t\twasScheduled = true;\n\t\t\t\t\t\ttransport.scheduleRepeat(\n\t\t\t\t\t\t\t(repeatedTime) => {\n\t\t\t\t\t\t\t\texpect(repeatedTime).to.be.closeTo(\n\t\t\t\t\t\t\t\t\ttimes[invocations],\n\t\t\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tinvocations++;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t0.1,\n\t\t\t\t\t\t\t0.05\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.3);\n\t\t\texpect(invocations).to.equal(2);\n\t\t});\n\t});\n\n\tcontext(\"scheduleOnce\", () => {\n\t\tit(\"can schedule a single event on the timeline\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\tconst eventID = transport.scheduleOnce(() => {}, 0);\n\t\t\t\texpect(eventID).to.be.a(\"number\");\n\t\t\t});\n\t\t});\n\n\t\tit(\"scheduled event gets invoked with the time of the event\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\tconst startTime = 0.1;\n\t\t\t\tconst eventID = transport.scheduleOnce((time) => {\n\t\t\t\t\tinvoked = true;\n\t\t\t\t\ttransport.clear(eventID);\n\t\t\t\t\texpect(time).to.be.closeTo(startTime, 0.01);\n\t\t\t\t}, 0);\n\t\t\t\ttransport.start(startTime);\n\t\t\t}, 0.2);\n\t\t\texpect(invoked).to.equal(true);\n\t\t});\n\n\t\tit(\"can schedule events with TransportTime\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\tconst startTime = 0.1;\n\t\t\t\tconst eighth = transport.toSeconds(\"8n\");\n\t\t\t\ttransport.scheduleOnce((time) => {\n\t\t\t\t\texpect(time).to.be.closeTo(startTime + eighth, 0.01);\n\t\t\t\t\tinvoked = true;\n\t\t\t\t}, TransportTime(\"8n\"));\n\t\t\t\ttransport.start(startTime);\n\t\t\t}, 0.5);\n\t\t\texpect(invoked).to.equal(true);\n\t\t});\n\n\t\tit(\"can clear a scheduled event\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\tconst eventID = transport.scheduleOnce(() => {\n\t\t\t\t\tthrow new Error(\"should not call this function\");\n\t\t\t\t}, 0);\n\t\t\t\ttransport.clear(eventID);\n\t\t\t\ttransport.start();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can be scheduled in the future\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\tconst startTime = transport.now() + 0.1;\n\t\t\t\tconst eventID = transport.scheduleOnce((time) => {\n\t\t\t\t\ttransport.clear(eventID);\n\t\t\t\t\texpect(time).to.be.closeTo(startTime + 0.3, 0.01);\n\t\t\t\t\tinvoked = true;\n\t\t\t\t}, 0.3);\n\t\t\t\ttransport.start(startTime);\n\t\t\t}, 0.5);\n\t\t\texpect(invoked).to.equal(true);\n\t\t});\n\n\t\tit(\"the event is removed after is is invoked\", async () => {\n\t\t\tlet iterations = 0;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.scheduleOnce(() => {\n\t\t\t\t\titerations++;\n\t\t\t\t}, 0);\n\t\t\t\ttransport.start().stop(\"+0.1\").start(\"+0.2\");\n\t\t\t}, 0.5);\n\t\t\texpect(iterations).to.be.lessThan(2);\n\t\t});\n\t});\n\n\tcontext(\"events\", () => {\n\t\tit(\"invokes start/stop/pause events\", async () => {\n\t\t\tlet invocations = 0;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.on(\"start\", () => {\n\t\t\t\t\tinvocations++;\n\t\t\t\t});\n\t\t\t\ttransport.on(\"stop\", () => {\n\t\t\t\t\tinvocations++;\n\t\t\t\t});\n\t\t\t\ttransport.on(\"pause\", () => {\n\t\t\t\t\tinvocations++;\n\t\t\t\t});\n\t\t\t\ttransport.start().stop(0.1).start(0.2);\n\t\t\t}, 0.5);\n\t\t\texpect(invocations).to.equal(3);\n\t\t});\n\n\t\tit(\"invokes start event with correct offset\", async () => {\n\t\t\tlet wasCalled = false;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.on(\"start\", (time, offset) => {\n\t\t\t\t\texpect(time).to.be.closeTo(0.2, 0.01);\n\t\t\t\t\texpect(offset).to.be.closeTo(0.5, 0.001);\n\t\t\t\t\twasCalled = true;\n\t\t\t\t});\n\t\t\t\ttransport.start(0.2, \"4n\");\n\t\t\t}, 0.3);\n\t\t\texpect(wasCalled).to.equal(true);\n\t\t});\n\n\t\tit(\"invokes the event just before the scheduled time\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.on(\"start\", (time, offset) => {\n\t\t\t\t\texpect(time - transport.context.currentTime).to.be.closeTo(\n\t\t\t\t\t\t0,\n\t\t\t\t\t\t0.01\n\t\t\t\t\t);\n\t\t\t\t\texpect(offset).to.equal(0);\n\t\t\t\t\tinvoked = true;\n\t\t\t\t});\n\t\t\t\ttransport.start(0.2);\n\t\t\t}, 0.3);\n\t\t\texpect(invoked).to.equal(true);\n\t\t});\n\n\t\tit(\"passes in the time argument to the events\", async () => {\n\t\t\tlet invocations = 0;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\tconst now = transport.now();\n\t\t\t\ttransport.on(\"start\", (time) => {\n\t\t\t\t\tinvocations++;\n\t\t\t\t\texpect(time).to.be.closeTo(now + 0.1, 0.01);\n\t\t\t\t});\n\t\t\t\ttransport.on(\"stop\", (time) => {\n\t\t\t\t\tinvocations++;\n\t\t\t\t\texpect(time).to.be.closeTo(now + 0.2, 0.01);\n\t\t\t\t});\n\t\t\t\ttransport.start(\"+0.1\").stop(\"+0.2\");\n\t\t\t}, 0.3);\n\t\t\texpect(invocations).to.equal(2);\n\t\t});\n\n\t\tit(\"invokes the 'loop' method on loop\", async () => {\n\t\t\tlet loops = 0;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\tconst sixteenth = transport.toSeconds(\"16n\");\n\t\t\t\ttransport.setLoopPoints(0, sixteenth);\n\t\t\t\ttransport.loop = true;\n\t\t\t\tlet lastLoop = -1;\n\t\t\t\ttransport.on(\"loop\", (time) => {\n\t\t\t\t\tloops++;\n\t\t\t\t\tif (lastLoop !== -1) {\n\t\t\t\t\t\texpect(time - lastLoop).to.be.closeTo(sixteenth, 0.001);\n\t\t\t\t\t}\n\t\t\t\t\tlastLoop = time;\n\t\t\t\t});\n\t\t\t\ttransport.start(0).stop(sixteenth * 5.1);\n\t\t\t}, 0.7);\n\t\t\texpect(loops).to.equal(5);\n\t\t});\n\t});\n\n\tcontext(\"swing\", () => {\n\t\tit(\"can get/set the swing subdivision\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.swingSubdivision = \"8n\";\n\t\t\t\texpect(transport.swingSubdivision).to.equal(\"8n\");\n\t\t\t\ttransport.swingSubdivision = \"4n\";\n\t\t\t\texpect(transport.swingSubdivision).to.equal(\"4n\");\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get/set the swing amount\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.swing = 0.5;\n\t\t\t\texpect(transport.swing).to.equal(0.5);\n\t\t\t\ttransport.swing = 0;\n\t\t\t\texpect(transport.swing).to.equal(0);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can swing\", async () => {\n\t\t\tlet invocations = 0;\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.swing = 1;\n\t\t\t\ttransport.swingSubdivision = \"8n\";\n\t\t\t\tconst eightNote = transport.toSeconds(\"8n\");\n\t\t\t\t// downbeat, no swing\n\t\t\t\ttransport.schedule((time) => {\n\t\t\t\t\tinvocations++;\n\t\t\t\t\texpect(time).is.closeTo(0, 0.001);\n\t\t\t\t}, 0);\n\t\t\t\t// eighth note has swing\n\t\t\t\ttransport.schedule((time) => {\n\t\t\t\t\tinvocations++;\n\t\t\t\t\texpect(time).is.closeTo((eightNote * 5) / 3, 0.001);\n\t\t\t\t}, \"8n\");\n\t\t\t\t// sixteenth note is also swung\n\t\t\t\ttransport.schedule((time) => {\n\t\t\t\t\tinvocations++;\n\t\t\t\t\texpect(time).is.closeTo(eightNote, 0.05);\n\t\t\t\t}, \"16n\");\n\t\t\t\t// no swing on the quarter\n\t\t\t\ttransport.schedule((time) => {\n\t\t\t\t\tinvocations++;\n\t\t\t\t\texpect(time).is.closeTo(eightNote * 2, 0.001);\n\t\t\t\t}, \"4n\");\n\t\t\t\ttransport.start(0).stop(0.7);\n\t\t\t}, 0.7);\n\t\t\texpect(invocations).to.equal(4);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/clock/Transport.ts",
    "content": "import { ToneAudioNode } from \"../../core/context/ToneAudioNode.js\";\nimport { TimeClass } from \"../../core/type/Time.js\";\nimport { PlaybackState } from \"../../core/util/StateTimeline.js\";\nimport { TimelineValue } from \"../../core/util/TimelineValue.js\";\nimport { Pow } from \"../../signal/Pow.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport {\n\tonContextClose,\n\tonContextInit,\n} from \"../context/ContextInitialization.js\";\nimport { Gain } from \"../context/Gain.js\";\nimport {\n\tToneWithContext,\n\tToneWithContextOptions,\n} from \"../context/ToneWithContext.js\";\nimport { TicksClass } from \"../type/Ticks.js\";\nimport { TransportTimeClass } from \"../type/TransportTime.js\";\nimport {\n\tBarsBeatsSixteenths,\n\tBPM,\n\tNormalRange,\n\tSeconds,\n\tSubdivision,\n\tTicks,\n\tTime,\n\tTimeSignature,\n\tTransportTime,\n} from \"../type/Units.js\";\nimport { enterScheduledCallback } from \"../util/Debug.js\";\nimport { assertUsedScheduleTime } from \"../util/Debug.js\";\nimport { optionsFromArguments } from \"../util/Defaults.js\";\nimport { Emitter } from \"../util/Emitter.js\";\nimport { readOnly, writable } from \"../util/Interface.js\";\nimport { IntervalTimeline } from \"../util/IntervalTimeline.js\";\nimport { Timeline } from \"../util/Timeline.js\";\nimport { isArray, isDefined } from \"../util/TypeCheck.js\";\nimport { Clock } from \"./Clock.js\";\nimport { TickParam } from \"./TickParam.js\";\nimport { TransportEvent } from \"./TransportEvent.js\";\nimport { TransportRepeatEvent } from \"./TransportRepeatEvent.js\";\n\ninterface TransportOptions extends ToneWithContextOptions {\n\tbpm: BPM;\n\tswing: NormalRange;\n\tswingSubdivision: Subdivision;\n\ttimeSignature: number;\n\tloopStart: Time;\n\tloopEnd: Time;\n\tppq: number;\n}\n\ntype TransportEventNames =\n\t| \"start\"\n\t| \"stop\"\n\t| \"pause\"\n\t| \"loop\"\n\t| \"loopEnd\"\n\t| \"loopStart\"\n\t| \"ticks\";\n\ninterface SyncedSignalEvent {\n\tsignal: Signal;\n\tinitial: number;\n\tnodes: ToneAudioNode<any>[];\n}\n\ntype TransportCallback = (time: Seconds) => void;\n\n/**\n * Transport for timing musical events.\n *\n * Supports tempo curves and time changes.\n *\n * Unlike browser-based timing (setInterval, requestAnimationFrame),\n * Transport timing events pass in the exact time of the scheduled event\n * in the argument of the callback function.\n *\n * A single transport is created for you when the library is initialized.\n *\n * The transport emits \"start\", \"stop\", \"pause\", and \"loop\" events.\n *\n * @example\n * const osc = new Tone.Oscillator().toDestination();\n * // Repeated event every 8th note.\n * Tone.getTransport().scheduleRepeat((time) => {\n * \t// Use the callback time to schedule events.\n * \tosc.start(time).stop(time + 0.1);\n * }, \"8n\");\n * // Transport must be started before it starts invoking events.\n * Tone.getTransport().start();\n * @category Core\n */\nexport class TransportInstance\n\textends ToneWithContext<TransportOptions>\n\timplements Emitter<TransportEventNames>\n{\n\treadonly name: string = \"Transport\";\n\n\t//-------------------------------------\n\t// \tLOOPING\n\t//-------------------------------------\n\n\t/**\n\t * If the transport loops or not.\n\t */\n\tprivate _loop: TimelineValue<boolean> = new TimelineValue(false);\n\n\t/**\n\t * The loop start position in ticks\n\t */\n\tprivate _loopStart: Ticks = 0;\n\n\t/**\n\t * The loop end position in ticks\n\t */\n\tprivate _loopEnd: Ticks = 0;\n\n\t//-------------------------------------\n\t// \tCLOCK/TEMPO\n\t//-------------------------------------\n\n\t/**\n\t * Pulses per quarter is the number of ticks per quarter note.\n\t */\n\tprivate _ppq: number;\n\n\t/**\n\t * watches the main oscillator for timing ticks\n\t * initially starts at 120bpm\n\t */\n\tprivate _clock: Clock<\"bpm\">;\n\n\t/**\n\t * The Beats Per Minute of the Transport.\n\t * @example\n\t * const osc = new Tone.Oscillator().toDestination();\n\t * Tone.getTransport().bpm.value = 80;\n\t * // start/stop the oscillator every quarter note\n\t * Tone.getTransport().scheduleRepeat(time => {\n\t * \tosc.start(time).stop(time + 0.1);\n\t * }, \"4n\");\n\t * Tone.getTransport().start();\n\t * // ramp the bpm to 120 over 10 seconds\n\t * Tone.getTransport().bpm.rampTo(120, 10);\n\t */\n\tbpm: TickParam<\"bpm\">;\n\n\t/**\n\t * The time signature, or more accurately the numerator\n\t * of the time signature over a denominator of 4.\n\t */\n\tprivate _timeSignature: number;\n\n\t//-------------------------------------\n\t// \tTIMELINE EVENTS\n\t//-------------------------------------\n\n\t/**\n\t * All the events in an object to keep track by ID\n\t */\n\tprivate _scheduledEvents = {};\n\n\t/**\n\t * The scheduled events.\n\t */\n\tprivate _timeline: Timeline<TransportEvent> = new Timeline();\n\n\t/**\n\t * Repeated events\n\t */\n\tprivate _repeatedEvents: IntervalTimeline = new IntervalTimeline();\n\n\t/**\n\t * All of the synced Signals\n\t */\n\tprivate _syncedSignals: SyncedSignalEvent[] = [];\n\n\t//-------------------------------------\n\t// \tSWING\n\t//-------------------------------------\n\n\t/**\n\t * The subdivision of the swing\n\t */\n\tprivate _swingTicks: Ticks;\n\n\t/**\n\t * The swing amount\n\t */\n\tprivate _swingAmount: NormalRange = 0;\n\n\tconstructor(options?: Partial<TransportOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tTransportInstance.getDefaults(),\n\t\t\targuments\n\t\t);\n\t\tsuper(options);\n\n\t\t// CLOCK/TEMPO\n\t\tthis._ppq = options.ppq;\n\t\tthis._clock = new Clock({\n\t\t\tcallback: this._processTick.bind(this),\n\t\t\tcontext: this.context,\n\t\t\tfrequency: 0,\n\t\t\tunits: \"bpm\",\n\t\t});\n\t\tthis._bindClockEvents();\n\t\tthis.bpm = this._clock.frequency as unknown as TickParam<\"bpm\">;\n\t\tthis._clock.frequency.multiplier = options.ppq;\n\t\tthis.bpm.setValueAtTime(options.bpm, 0);\n\t\treadOnly(this, \"bpm\");\n\t\tthis._timeSignature = options.timeSignature;\n\n\t\t// SWING\n\t\tthis._swingTicks = options.ppq / 2; // 8n\n\t}\n\n\tstatic getDefaults(): TransportOptions {\n\t\treturn Object.assign(ToneWithContext.getDefaults(), {\n\t\t\tbpm: 120,\n\t\t\tloopEnd: \"4m\" as Subdivision,\n\t\t\tloopStart: 0,\n\t\t\tppq: 192,\n\t\t\tswing: 0,\n\t\t\tswingSubdivision: \"8n\" as Subdivision,\n\t\t\ttimeSignature: 4,\n\t\t});\n\t}\n\n\t//-------------------------------------\n\t// \tTICKS\n\t//-------------------------------------\n\n\t/**\n\t * called on every tick\n\t * @param  tickTime clock relative tick time\n\t */\n\tprivate _processTick(tickTime: Seconds, ticks: Ticks): void {\n\t\t// do the loop test\n\t\tif (this._loop.get(tickTime)) {\n\t\t\tif (ticks >= this._loopEnd) {\n\t\t\t\tthis.emit(\"loopEnd\", tickTime);\n\t\t\t\tthis._clock.setTicksAtTime(this._loopStart, tickTime);\n\t\t\t\tticks = this._loopStart;\n\t\t\t\tthis.emit(\n\t\t\t\t\t\"loopStart\",\n\t\t\t\t\ttickTime,\n\t\t\t\t\tthis._clock.getSecondsAtTime(tickTime)\n\t\t\t\t);\n\t\t\t\tthis.emit(\"loop\", tickTime);\n\t\t\t}\n\t\t}\n\t\t// handle swing\n\t\tif (\n\t\t\tthis._swingAmount > 0 &&\n\t\t\tticks % this._ppq !== 0 && // not on a downbeat\n\t\t\tticks % (this._swingTicks * 2) !== 0\n\t\t) {\n\t\t\t// add some swing\n\t\t\tconst progress =\n\t\t\t\t(ticks % (this._swingTicks * 2)) / (this._swingTicks * 2);\n\t\t\tconst amount = Math.sin(progress * Math.PI) * this._swingAmount;\n\t\t\ttickTime +=\n\t\t\t\tnew TicksClass(\n\t\t\t\t\tthis.context,\n\t\t\t\t\t(this._swingTicks * 2) / 3\n\t\t\t\t).toSeconds() * amount;\n\t\t}\n\t\t// invoke the timeline events scheduled on this tick\n\t\tenterScheduledCallback(true);\n\t\tthis._timeline.forEachAtTime(ticks, (event) => event.invoke(tickTime));\n\t\tenterScheduledCallback(false);\n\t}\n\n\t//-------------------------------------\n\t// \tSCHEDULABLE EVENTS\n\t//-------------------------------------\n\n\t/**\n\t * Schedule an event to be invoked at a specific time.\n\t * @param callback The callback to invoke at the given time.\n\t * @param time The time to invoke the callback at.\n\t * @return The ID of the event, which can be used to cancel the event.\n\t * @example\n\t * // Schedule an event on the 16th measure.\n\t * Tone.getTransport().schedule((time) => {\n\t * \t// Invoked on measure 16.\n\t * \tconsole.log(\"measure 16!\");\n\t * }, \"16:0:0\");\n\t */\n\tschedule(\n\t\tcallback: TransportCallback,\n\t\ttime: TransportTime | TransportTimeClass\n\t): number {\n\t\tconst event = new TransportEvent(this, {\n\t\t\tcallback,\n\t\t\ttime: new TransportTimeClass(this.context, time).toTicks(),\n\t\t});\n\t\treturn this._addEvent(event, this._timeline);\n\t}\n\n\t/**\n\t * Schedule a repeated event.\n\t *\n\t * The event will fire at the `interval` starting at the `startTime` and for the specified `duration`.\n\t *\n\t * @param callback The callback to invoke.\n\t * @param interval The duration between successive callbacks.\n\t * @param startTime When the event should start.\n\t * @param duration How long the event should repeat.\n\t * @return The ID of the scheduled event. Use this to cancel the event.\n\t * @example\n\t * const osc = new Tone.Oscillator().toDestination().start();\n\t * // A callback invoked every eighth note after the first measure.\n\t * Tone.getTransport().scheduleRepeat((time) => {\n\t * \tosc.start(time).stop(time + 0.1);\n\t * }, \"8n\", \"1m\");\n\t */\n\tscheduleRepeat(\n\t\tcallback: TransportCallback,\n\t\tinterval: Time | TimeClass,\n\t\tstartTime?: TransportTime | TransportTimeClass,\n\t\tduration: Time = Infinity\n\t): number {\n\t\tconst event = new TransportRepeatEvent(this, {\n\t\t\tcallback,\n\t\t\tduration: new TimeClass(this.context, duration).toTicks(),\n\t\t\tinterval: new TimeClass(this.context, interval).toTicks(),\n\t\t\ttime: new TransportTimeClass(this.context, startTime).toTicks(),\n\t\t});\n\t\t// kick it off if the Transport is started\n\t\t// @ts-ignore\n\t\treturn this._addEvent(event, this._repeatedEvents);\n\t}\n\n\t/**\n\t * Schedule an event that will be removed after it is invoked.\n\t * @param callback The callback to invoke once.\n\t * @param time The time the callback should be invoked.\n\t * @returns The ID of the scheduled event.\n\t */\n\tscheduleOnce(\n\t\tcallback: TransportCallback,\n\t\ttime: TransportTime | TransportTimeClass\n\t): number {\n\t\tconst event = new TransportEvent(this, {\n\t\t\tcallback,\n\t\t\tonce: true,\n\t\t\ttime: new TransportTimeClass(this.context, time).toTicks(),\n\t\t});\n\t\treturn this._addEvent(event, this._timeline);\n\t}\n\n\t/**\n\t * Clear the passed in event id from the timeline\n\t * @param eventId The id of the event.\n\t */\n\tclear(eventId: number): this {\n\t\tif (this._scheduledEvents.hasOwnProperty(eventId)) {\n\t\t\tconst item = this._scheduledEvents[eventId.toString()];\n\t\t\titem.timeline.remove(item.event);\n\t\t\titem.event.dispose();\n\t\t\tdelete this._scheduledEvents[eventId.toString()];\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Add an event to the correct timeline. Keep track of the\n\t * timeline it was added to.\n\t * @returns the event id which was just added\n\t */\n\tprivate _addEvent(\n\t\tevent: TransportEvent,\n\t\ttimeline: Timeline<TransportEvent>\n\t): number {\n\t\tthis._scheduledEvents[event.id.toString()] = {\n\t\t\tevent,\n\t\t\ttimeline,\n\t\t};\n\t\ttimeline.add(event);\n\t\treturn event.id;\n\t}\n\n\t/**\n\t * Remove scheduled events from the timeline after\n\t * the given time. Repeated events will be removed\n\t * if their startTime is after the given time\n\t * @param after Clear all events after this time.\n\t */\n\tcancel(after: TransportTime = 0): this {\n\t\tconst computedAfter = this.toTicks(after);\n\t\tthis._timeline.forEachFrom(computedAfter, (event) =>\n\t\t\tthis.clear(event.id)\n\t\t);\n\t\tthis._repeatedEvents.forEachFrom(computedAfter, (event) =>\n\t\t\tthis.clear(event.id)\n\t\t);\n\t\treturn this;\n\t}\n\n\t//-------------------------------------\n\t// \tSTART/STOP/PAUSE\n\t//-------------------------------------\n\n\t/**\n\t * Bind start/stop/pause events from the clock and emit them.\n\t */\n\tprivate _bindClockEvents(): void {\n\t\tthis._clock.on(\"start\", (time, offset) => {\n\t\t\toffset = new TicksClass(this.context, offset).toSeconds();\n\t\t\tthis.emit(\"start\", time, offset);\n\t\t});\n\n\t\tthis._clock.on(\"stop\", (time) => {\n\t\t\tthis.emit(\"stop\", time);\n\t\t});\n\n\t\tthis._clock.on(\"pause\", (time) => {\n\t\t\tthis.emit(\"pause\", time);\n\t\t});\n\t}\n\n\t/**\n\t * The playback state of the transport, either \"started\", \"stopped\", or \"paused\".\n\t */\n\tget state(): PlaybackState {\n\t\treturn this._clock.getStateAtTime(this.now());\n\t}\n\n\t/**\n\t * Start the transport and all sources synced to the transport.\n\t * @param time The time when the transport should start.\n\t * @param offset The timeline offset to start the transport from.\n\t * @example\n\t * // Start the transport in one second, beginning at the start of the 5th measure.\n\t * Tone.getTransport().start(\"+1\", \"4:0:0\");\n\t */\n\tstart(time?: Time, offset?: TransportTime): this {\n\t\t// start the context\n\t\tthis.context.resume();\n\t\tlet offsetTicks;\n\t\tif (isDefined(offset)) {\n\t\t\toffsetTicks = this.toTicks(offset);\n\t\t}\n\t\t// start the clock\n\t\tthis._clock.start(time, offsetTicks);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop the transport and all sources synced to the transport.\n\t * @param time The time when the transport should stop.\n\t * @example\n\t * Tone.getTransport().stop();\n\t */\n\tstop(time?: Time): this {\n\t\tthis._clock.stop(time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Pause the transport and all sources synced to the transport.\n\t */\n\tpause(time?: Time): this {\n\t\tthis._clock.pause(time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Toggle the current state of the transport.\n\t *\n\t * If it is started, it will stop it. If it is stopped, it will start it.\n\t *\n\t * @param time The time of the event.\n\t */\n\ttoggle(time?: Time): this {\n\t\ttime = this.toSeconds(time);\n\t\tif (this._clock.getStateAtTime(time) !== \"started\") {\n\t\t\tthis.start(time);\n\t\t} else {\n\t\t\tthis.stop(time);\n\t\t}\n\t\treturn this;\n\t}\n\n\t//-------------------------------------\n\t// \tSETTERS/GETTERS\n\t//-------------------------------------\n\n\t/**\n\t * The time signature as just the numerator over 4.\n\t * For example 4/4 would be just 4 and 6/8 would be 3.\n\t * @example\n\t * // common time\n\t * Tone.getTransport().timeSignature = 4;\n\t * // 7/8\n\t * Tone.getTransport().timeSignature = [7, 8];\n\t * // this will be reduced to a single number\n\t * Tone.getTransport().timeSignature; // returns 3.5\n\t */\n\tget timeSignature(): TimeSignature {\n\t\treturn this._timeSignature;\n\t}\n\tset timeSignature(timeSig: TimeSignature) {\n\t\tif (isArray(timeSig)) {\n\t\t\ttimeSig = (timeSig[0] / timeSig[1]) * 4;\n\t\t}\n\t\tthis._timeSignature = timeSig;\n\t}\n\n\t/**\n\t * When the Transport.loop = true, this is the starting position of the loop.\n\t */\n\tget loopStart(): Time {\n\t\treturn new TimeClass(this.context, this._loopStart, \"i\").toSeconds();\n\t}\n\tset loopStart(startPosition: Time) {\n\t\tthis._loopStart = this.toTicks(startPosition);\n\t}\n\n\t/**\n\t * When the Transport.loop = true, this is the ending position of the loop.\n\t */\n\tget loopEnd(): Time {\n\t\treturn new TimeClass(this.context, this._loopEnd, \"i\").toSeconds();\n\t}\n\tset loopEnd(endPosition: Time) {\n\t\tthis._loopEnd = this.toTicks(endPosition);\n\t}\n\n\t/**\n\t * If the transport loops or not.\n\t */\n\tget loop(): boolean {\n\t\treturn this._loop.get(this.now());\n\t}\n\tset loop(loop) {\n\t\tthis._loop.set(loop, this.now());\n\t}\n\n\t/**\n\t * Set the loop start and stop at the same time.\n\t * @example\n\t * // loop over the first measure\n\t * Tone.getTransport().setLoopPoints(0, \"1m\");\n\t * Tone.getTransport().loop = true;\n\t */\n\tsetLoopPoints(\n\t\tstartPosition: TransportTime,\n\t\tendPosition: TransportTime\n\t): this {\n\t\tthis.loopStart = startPosition;\n\t\tthis.loopEnd = endPosition;\n\t\treturn this;\n\t}\n\n\t/**\n\t * The swing value. Between 0-1 where 1 equal to the note + half the subdivision.\n\t */\n\tget swing(): NormalRange {\n\t\treturn this._swingAmount;\n\t}\n\tset swing(amount: NormalRange) {\n\t\t// scale the values to a normal range\n\t\tthis._swingAmount = amount;\n\t}\n\n\t/**\n\t * Set the subdivision which the swing will be applied to.\n\t * The default value is an 8th note. Value must be less\n\t * than a quarter note.\n\t */\n\tget swingSubdivision(): Subdivision {\n\t\treturn new TicksClass(this.context, this._swingTicks).toNotation();\n\t}\n\tset swingSubdivision(subdivision: Subdivision) {\n\t\tthis._swingTicks = this.toTicks(subdivision);\n\t}\n\n\t/**\n\t * The Transport's position in Bars:Beats:Sixteenths.\n\t * Setting the value will jump to that position right away.\n\t */\n\tget position(): BarsBeatsSixteenths | Time {\n\t\tconst now = this.now();\n\t\tconst ticks = this._clock.getTicksAtTime(now);\n\t\treturn new TicksClass(this.context, ticks).toBarsBeatsSixteenths();\n\t}\n\tset position(progress: Time) {\n\t\tconst ticks = this.toTicks(progress);\n\t\tthis.ticks = ticks;\n\t}\n\n\t/**\n\t * The Transport's position in seconds.\n\t * Setting the value will jump to that position right away.\n\t */\n\tget seconds(): Seconds {\n\t\treturn this._clock.seconds;\n\t}\n\tset seconds(s: Seconds) {\n\t\tconst now = this.now();\n\t\tconst ticks = this._clock.frequency.timeToTicks(s, now);\n\t\tthis.ticks = ticks;\n\t}\n\n\t/**\n\t * The Transport's loop position as a normalized value. Always\n\t * returns 0 if the Transport.loop = false.\n\t */\n\tget progress(): NormalRange {\n\t\tif (this.loop) {\n\t\t\tconst now = this.now();\n\t\t\tconst ticks = this._clock.getTicksAtTime(now);\n\t\t\treturn (\n\t\t\t\t(ticks - this._loopStart) / (this._loopEnd - this._loopStart)\n\t\t\t);\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t/**\n\t * The Transport's current tick position.\n\t */\n\tget ticks(): Ticks {\n\t\treturn this._clock.ticks;\n\t}\n\tset ticks(t: Ticks) {\n\t\tassertUsedScheduleTime();\n\n\t\t// \"floor\" ensures that any events scheduled on this tick will be called.\n\t\tt = Math.floor(t);\n\n\t\tif (this._clock.ticks === t) {\n\t\t\treturn;\n\t\t}\n\t\tconst now = this.now();\n\t\t// stop everything synced to the transport\n\t\tif (this.state === \"started\") {\n\t\t\tconst ticks = this._clock.getTicksAtTime(now);\n\t\t\t// schedule to start on the next tick, #573\n\t\t\tconst remainingTick = this._clock.frequency.getDurationOfTicks(\n\t\t\t\tMath.ceil(ticks) - ticks,\n\t\t\t\tnow\n\t\t\t);\n\t\t\tconst time = now + remainingTick;\n\t\t\tthis.emit(\"stop\", time);\n\t\t\tthis._clock.setTicksAtTime(t, time);\n\t\t\t// restart it with the new time\n\t\t\tthis.emit(\"start\", time, this._clock.getSecondsAtTime(time));\n\t\t} else {\n\t\t\tthis.emit(\"ticks\", now);\n\t\t\tthis._clock.setTicksAtTime(t, now);\n\t\t}\n\t}\n\n\t/**\n\t * Get the clock's ticks at the given time.\n\t * @param  time  When to get the tick value\n\t * @return The tick value at the given time.\n\t */\n\tgetTicksAtTime(time?: Time): Ticks {\n\t\treturn this._clock.getTicksAtTime(time);\n\t}\n\n\t/**\n\t * Set the Transport's {@link ticks} value at the given time\n\t * @param  ticks  The tick value to set\n\t * @param  time   The Context time at which to set the seconds value\n\t */\n\tsetTicksAtTime(ticks: Ticks, time: Time): this {\n\t\tthis._clock.setTicksAtTime(ticks, time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Return the elapsed seconds at the given time.\n\t * @param  time  When to get the elapsed seconds\n\t * @return  The number of elapsed seconds\n\t */\n\tgetSecondsAtTime(time: Time): Seconds {\n\t\treturn this._clock.getSecondsAtTime(time);\n\t}\n\n\t/**\n\t * Set the Transport's {@link seconds} value at the given time.\n\t * @param seconds The seconds value to set\n\t * @param time The Context time at which to set the seconds value\n\t */\n\tsetSecondsAtTime(seconds: Seconds, time: Time): this {\n\t\tthis.setTicksAtTime(this.toTicks(seconds), time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Pulses Per Quarter note. This is the smallest resolution\n\t * the Transport timing supports. This should be set once\n\t * on initialization and not set again. Changing this value\n\t * after other objects have been created can cause problems.\n\t */\n\tget PPQ(): number {\n\t\treturn this._clock.frequency.multiplier;\n\t}\n\tset PPQ(ppq: number) {\n\t\tthis._clock.frequency.multiplier = ppq;\n\t}\n\n\t//-------------------------------------\n\t// \tSYNCING\n\t//-------------------------------------\n\n\t/**\n\t * Returns the time aligned to the next subdivision\n\t * of the Transport. If the Transport is not started,\n\t * it will return 0.\n\t * Note: this will not work precisely during tempo ramps.\n\t * @param  subdivision  The subdivision to quantize to\n\t * @return  The context time of the next subdivision.\n\t * @example\n\t * // the transport must be started, otherwise returns 0\n\t * Tone.getTransport().start();\n\t * Tone.getTransport().nextSubdivision(\"4n\");\n\t */\n\tnextSubdivision(subdivision?: Time): Seconds {\n\t\tsubdivision = this.toTicks(subdivision);\n\t\tif (this.state !== \"started\") {\n\t\t\t// if the transport's not started, return 0\n\t\t\treturn 0;\n\t\t} else {\n\t\t\tconst now = this.now();\n\t\t\t// the remainder of the current ticks and the subdivision\n\t\t\tconst transportPos = this.getTicksAtTime(now);\n\t\t\tconst remainingTicks = subdivision - (transportPos % subdivision);\n\t\t\treturn this._clock.nextTickTime(remainingTicks, now);\n\t\t}\n\t}\n\n\t/**\n\t * Attaches the signal to the tempo control signal so that\n\t * any changes in the tempo will change the signal in the same\n\t * ratio.\n\t *\n\t * @param signal\n\t * @param ratio Optionally pass in the ratio between the two signals.\n\t * \t\t\tOtherwise it will be computed based on their current values.\n\t */\n\tsyncSignal(signal: Signal<any>, ratio?: number): this {\n\t\tconst now = this.now();\n\t\tlet source: TickParam<\"bpm\"> | ToneAudioNode<any> = this.bpm;\n\t\tlet sourceValue = 1 / (60 / source.getValueAtTime(now) / this.PPQ);\n\t\tlet nodes: ToneAudioNode<any>[] = [];\n\t\t// If the signal is in the time domain, sync it to the reciprocal of\n\t\t// the tempo instead of the tempo.\n\t\tif (signal.units === \"time\") {\n\t\t\t// The input to Pow should be in the range [1 / 4096, 1], where\n\t\t\t// where 4096 is half of the buffer size of Pow's waveshaper.\n\t\t\t// Pick a scaling factor based on the initial tempo that ensures\n\t\t\t// that the initial input is in this range, while leaving room for\n\t\t\t// tempo changes.\n\t\t\tconst scaleFactor = 1 / 64 / sourceValue;\n\t\t\tconst scaleBefore = new Gain(scaleFactor);\n\t\t\tconst reciprocal = new Pow(-1);\n\t\t\tconst scaleAfter = new Gain(scaleFactor);\n\t\t\t// @ts-ignore\n\t\t\tsource.chain(scaleBefore, reciprocal, scaleAfter);\n\t\t\tsource = scaleAfter;\n\t\t\tsourceValue = 1 / sourceValue;\n\t\t\tnodes = [scaleBefore, reciprocal, scaleAfter];\n\t\t}\n\t\tif (!ratio) {\n\t\t\t// get the sync ratio\n\t\t\tif (signal.getValueAtTime(now) !== 0) {\n\t\t\t\tratio = signal.getValueAtTime(now) / sourceValue;\n\t\t\t} else {\n\t\t\t\tratio = 0;\n\t\t\t}\n\t\t}\n\t\tconst ratioSignal = new Gain(ratio);\n\t\t// @ts-ignore\n\t\tsource.connect(ratioSignal);\n\t\t// @ts-ignore\n\t\tratioSignal.connect(signal._param);\n\t\tnodes.push(ratioSignal);\n\t\tthis._syncedSignals.push({\n\t\t\tinitial: signal.value,\n\t\t\tnodes: nodes,\n\t\t\tsignal,\n\t\t});\n\t\tsignal.value = 0;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Unsyncs a previously synced signal from the transport's control.\n\t * @see {@link syncSignal}.\n\t */\n\tunsyncSignal(signal: Signal<any>): this {\n\t\tfor (let i = this._syncedSignals.length - 1; i >= 0; i--) {\n\t\t\tconst syncedSignal = this._syncedSignals[i];\n\t\t\tif (syncedSignal.signal === signal) {\n\t\t\t\tsyncedSignal.nodes.forEach((node) => node.dispose());\n\t\t\t\tsyncedSignal.signal.value = syncedSignal.initial;\n\t\t\t\tthis._syncedSignals.splice(i, 1);\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clean up.\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._clock.dispose();\n\t\twritable(this, \"bpm\");\n\t\tthis._timeline.dispose();\n\t\tthis._repeatedEvents.dispose();\n\t\treturn this;\n\t}\n\n\t//-------------------------------------\n\t// EMITTER MIXIN TO SATISFY COMPILER\n\t//-------------------------------------\n\n\ton!: (\n\t\tevent: TransportEventNames,\n\t\tcallback: (...args: any[]) => void\n\t) => this;\n\tonce!: (\n\t\tevent: TransportEventNames,\n\t\tcallback: (...args: any[]) => void\n\t) => this;\n\toff!: (\n\t\tevent: TransportEventNames,\n\t\tcallback?: ((...args: any[]) => void) | undefined\n\t) => this;\n\temit!: (event: any, ...args: any[]) => this;\n}\n\nEmitter.mixin(TransportInstance);\n\n//-------------------------------------\n// \tINITIALIZATION\n//-------------------------------------\n\nonContextInit((context) => {\n\tcontext.transport = new TransportInstance({ context });\n});\n\nonContextClose((context) => {\n\tcontext.transport.dispose();\n});\n"
  },
  {
    "path": "Tone/core/clock/TransportEvent.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { TransportInstance } from \"./Transport.js\";\nimport { TransportEvent } from \"./TransportEvent.js\";\n\ndescribe(\"TransportEvent\", () => {\n\tit(\"can be created and disposed\", () => {\n\t\treturn Offline((context) => {\n\t\t\tconst transport = new TransportInstance({ context });\n\t\t\tconst event = new TransportEvent(transport, {\n\t\t\t\ttime: 0,\n\t\t\t});\n\t\t\tevent.dispose();\n\t\t});\n\t});\n\n\tit(\"has a unique id\", () => {\n\t\treturn Offline((context) => {\n\t\t\tconst transport = new TransportInstance({ context });\n\t\t\tconst event = new TransportEvent(transport, {\n\t\t\t\ttime: 0,\n\t\t\t});\n\t\t\texpect(event.id).to.be.a(\"number\");\n\t\t\tevent.dispose();\n\t\t});\n\t});\n\n\tit(\"can invoke the callback\", async () => {\n\t\tlet wasInvoked = false;\n\t\tawait Offline((context) => {\n\t\t\tconst transport = new TransportInstance({ context });\n\t\t\tconst event = new TransportEvent(transport, {\n\t\t\t\tcallback: (time) => {\n\t\t\t\t\texpect(time).to.equal(100);\n\t\t\t\t\twasInvoked = true;\n\t\t\t\t},\n\t\t\t\ttime: 0,\n\t\t\t});\n\t\t\tevent.invoke(100);\n\t\t});\n\t\texpect(wasInvoked).to.equal(true);\n\t});\n});\n"
  },
  {
    "path": "Tone/core/clock/TransportEvent.ts",
    "content": "import { Seconds, Ticks } from \"../type/Units.js\";\nimport { noOp } from \"../util/Interface.js\";\nimport type { TransportInstance as Transport } from \"./Transport.js\";\n\nexport interface TransportEventOptions {\n\tcallback: (time: number) => void;\n\tonce: boolean;\n\ttime: Ticks;\n}\n\n/**\n * TransportEvent is an internal class used by {@link TransportInstance}\n * to schedule events. Do no invoke this class directly, it is\n * handled from within Tone.Transport.\n */\nexport class TransportEvent {\n\t/**\n\t * Reference to the Transport that created it\n\t */\n\tprotected transport: Transport;\n\n\t/**\n\t * The unique id of the event\n\t */\n\tid: number = TransportEvent._eventId++;\n\n\t/**\n\t * The time the event starts\n\t */\n\ttime: Ticks;\n\n\t/**\n\t * The callback to invoke\n\t */\n\tprivate callback?: (time: Seconds) => void;\n\n\t/**\n\t * If the event should be removed after being invoked.\n\t */\n\tprivate _once: boolean;\n\n\t/**\n\t * The remaining value between the passed in time, and Math.floor(time).\n\t * This value is later added back when scheduling to get sub-tick precision.\n\t */\n\tprotected _remainderTime = 0;\n\n\t/**\n\t * @param transport The transport object which the event belongs to\n\t */\n\tconstructor(transport: Transport, opts: Partial<TransportEventOptions>) {\n\t\tconst options: TransportEventOptions = Object.assign(\n\t\t\tTransportEvent.getDefaults(),\n\t\t\topts\n\t\t);\n\n\t\tthis.transport = transport;\n\t\tthis.callback = options.callback;\n\t\tthis._once = options.once;\n\t\tthis.time = Math.floor(options.time);\n\t\tthis._remainderTime = options.time - this.time;\n\t}\n\n\tstatic getDefaults(): TransportEventOptions {\n\t\treturn {\n\t\t\tcallback: noOp,\n\t\t\tonce: false,\n\t\t\ttime: 0,\n\t\t};\n\t}\n\n\t/**\n\t * Current ID counter\n\t */\n\tprivate static _eventId = 0;\n\n\t/**\n\t * Get the time and remainder time.\n\t */\n\tprotected get floatTime(): number {\n\t\treturn this.time + this._remainderTime;\n\t}\n\n\t/**\n\t * Invoke the event callback.\n\t * @param  time  The AudioContext time in seconds of the event\n\t */\n\tinvoke(time: Seconds): void {\n\t\tif (this.callback) {\n\t\t\tconst tickDuration = this.transport.bpm.getDurationOfTicks(1, time);\n\t\t\tthis.callback(time + this._remainderTime * tickDuration);\n\t\t\tif (this._once) {\n\t\t\t\tthis.transport.clear(this.id);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Clean up\n\t */\n\tdispose(): this {\n\t\tthis.callback = undefined;\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/core/clock/TransportRepeatEvent.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { TransportInstance } from \"./Transport.js\";\nimport { TransportRepeatEvent } from \"./TransportRepeatEvent.js\";\n\ndescribe(\"TransportRepeatEvent\", () => {\n\tit(\"can be created and disposed\", async () => {\n\t\tawait Offline((context) => {\n\t\t\tconst transport = new TransportInstance({ context });\n\t\t\tconst event = new TransportRepeatEvent(transport, {\n\t\t\t\tduration: 100,\n\t\t\t\tinterval: 4,\n\t\t\t\ttime: 0,\n\t\t\t});\n\t\t\tevent.dispose();\n\t\t});\n\t});\n\n\tit(\"generates a unique event ID\", async () => {\n\t\tawait Offline((context) => {\n\t\t\tconst transport = new TransportInstance({ context });\n\t\t\tconst event = new TransportRepeatEvent(transport, {\n\t\t\t\ttime: 0,\n\t\t\t});\n\t\t\texpect(event.id).to.be.a(\"number\");\n\t\t\tevent.dispose();\n\t\t});\n\t});\n\n\tit(\"is removed from the Transport when disposed\", async () => {\n\t\tawait Offline((context) => {\n\t\t\tconst transport = new TransportInstance({ context });\n\t\t\tconst event = new TransportRepeatEvent(transport, {\n\t\t\t\ttime: 0,\n\t\t\t});\n\t\t\tevent.dispose();\n\t\t\t// @ts-ignore\n\t\t\texpect(transport._timeline.length).to.equal(0);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/clock/TransportRepeatEvent.ts",
    "content": "import { BaseContext } from \"../context/BaseContext.js\";\nimport { TicksClass } from \"../type/Ticks.js\";\nimport { Seconds, Ticks, Time } from \"../type/Units.js\";\nimport { GT, LT } from \"../util/Math.js\";\nimport type { TransportInstance as Transport } from \"./Transport.js\";\nimport { TransportEvent, TransportEventOptions } from \"./TransportEvent.js\";\n\ninterface TransportRepeatEventOptions extends TransportEventOptions {\n\tinterval: Ticks;\n\tduration: Ticks;\n}\n\n/**\n * TransportRepeatEvent is an internal class used by Tone.Transport\n * to schedule repeat events. This class should not be instantiated directly.\n */\nexport class TransportRepeatEvent extends TransportEvent {\n\t/**\n\t * When the event should stop repeating\n\t */\n\tprivate duration: Ticks;\n\n\t/**\n\t * The interval of the repeated event\n\t */\n\tprivate _interval: Ticks;\n\n\t/**\n\t * The ID of the current timeline event\n\t */\n\tprivate _currentId = -1;\n\n\t/**\n\t * The ID of the next timeline event\n\t */\n\tprivate _nextId = -1;\n\n\t/**\n\t * The time of the next event\n\t */\n\tprivate _nextTick = this.time;\n\n\t/**\n\t * a reference to the bound start method\n\t */\n\tprivate _boundRestart = this._restart.bind(this);\n\n\t/**\n\t * The audio context belonging to this event\n\t */\n\tprotected context: BaseContext;\n\n\t/**\n\t * @param transport The transport object which the event belongs to\n\t */\n\tconstructor(\n\t\ttransport: Transport,\n\t\topts: Partial<TransportRepeatEventOptions>\n\t) {\n\t\tsuper(transport, opts);\n\n\t\tconst options = Object.assign(TransportRepeatEvent.getDefaults(), opts);\n\n\t\tthis.duration = options.duration;\n\t\tthis._interval = options.interval;\n\t\tthis._nextTick = options.time;\n\t\tthis.transport.on(\"start\", this._boundRestart);\n\t\tthis.transport.on(\"loopStart\", this._boundRestart);\n\t\tthis.transport.on(\"ticks\", this._boundRestart);\n\t\tthis.context = this.transport.context;\n\t\tthis._restart();\n\t}\n\n\tstatic getDefaults(): TransportRepeatEventOptions {\n\t\treturn Object.assign({}, TransportEvent.getDefaults(), {\n\t\t\tduration: Infinity,\n\t\t\tinterval: 1,\n\t\t\tonce: false,\n\t\t});\n\t}\n\n\t/**\n\t * Invoke the callback. Returns the tick time which\n\t * the next event should be scheduled at.\n\t * @param  time  The AudioContext time in seconds of the event\n\t */\n\tinvoke(time: Seconds): void {\n\t\t// create more events if necessary\n\t\tthis._createEvents();\n\t\t// call the super class\n\t\tsuper.invoke(time);\n\t}\n\n\t/**\n\t * Create an event on the transport on the nextTick\n\t */\n\tprivate _createEvent(): number {\n\t\tif (LT(this._nextTick, this.floatTime + this.duration)) {\n\t\t\treturn this.transport.scheduleOnce(\n\t\t\t\tthis.invoke.bind(this),\n\t\t\t\tnew TicksClass(this.context, this._nextTick).toSeconds()\n\t\t\t);\n\t\t}\n\t\treturn -1;\n\t}\n\n\t/**\n\t * Push more events onto the timeline to keep up with the position of the timeline\n\t */\n\tprivate _createEvents(): void {\n\t\t// if the next tick is within the bounds set by \"duration\"\n\t\tif (\n\t\t\tLT(this._nextTick + this._interval, this.floatTime + this.duration)\n\t\t) {\n\t\t\tthis._nextTick += this._interval;\n\t\t\tthis._currentId = this._nextId;\n\t\t\tthis._nextId = this.transport.scheduleOnce(\n\t\t\t\tthis.invoke.bind(this),\n\t\t\t\tnew TicksClass(this.context, this._nextTick).toSeconds()\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Re-compute the events when the transport time has changed from a start/ticks/loopStart event\n\t */\n\tprivate _restart(time?: Time): void {\n\t\tthis.transport.clear(this._currentId);\n\t\tthis.transport.clear(this._nextId);\n\t\t// start at the first event\n\t\tthis._nextTick = this.floatTime;\n\t\tconst ticks = this.transport.getTicksAtTime(time);\n\t\tif (GT(ticks, this.time)) {\n\t\t\t// the event is not being scheduled from the beginning and should be offset\n\t\t\tthis._nextTick =\n\t\t\t\tthis.floatTime +\n\t\t\t\tMath.ceil((ticks - this.floatTime) / this._interval) *\n\t\t\t\t\tthis._interval;\n\t\t}\n\t\tthis._currentId = this._createEvent();\n\t\tthis._nextTick += this._interval;\n\t\tthis._nextId = this._createEvent();\n\t}\n\n\t/**\n\t * Clean up\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.transport.clear(this._currentId);\n\t\tthis.transport.clear(this._nextId);\n\t\tthis.transport.off(\"start\", this._boundRestart);\n\t\tthis.transport.off(\"loopStart\", this._boundRestart);\n\t\tthis.transport.off(\"ticks\", this._boundRestart);\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/core/context/AbstractParam.ts",
    "content": "import { Time, UnitMap, UnitName } from \"../type/Units.js\";\n\n/**\n * Abstract base class for {@link Param} and {@link Signal}\n */\nexport abstract class AbstractParam<TypeName extends UnitName> {\n\t/**\n\t * Schedules a parameter value change at the given time.\n\t * @param value The value to set the signal.\n\t * @param time The time when the change should occur.\n\t * @example\n\t * return Tone.Offline(() => {\n\t * \tconst osc = new Tone.Oscillator(20).toDestination().start();\n\t * \t// set the frequency to 40 at exactly 0.25 seconds\n\t * \tosc.frequency.setValueAtTime(40, 0.25);\n\t * }, 0.5, 1);\n\t */\n\tabstract setValueAtTime(value: UnitMap[TypeName], time: Time): this;\n\n\t/**\n\t * Get the signals value at the given time. Subsequent scheduling\n\t * may invalidate the returned value.\n\t * @param time When to get the value\n\t * @example\n\t * const signal = new Tone.Signal().toDestination();\n\t * // ramp up to '8' over 3 seconds\n\t * signal.rampTo(8, 3);\n\t * // ramp back down to '0' over 3 seconds\n\t * signal.rampTo(0, 3, \"+3\");\n\t * setInterval(() => {\n\t * \t// check the value every 100 ms\n\t * \tconsole.log(signal.getValueAtTime(Tone.now()));\n\t * }, 100);\n\t */\n\tabstract getValueAtTime(time: Time): UnitMap[TypeName];\n\n\t/**\n\t * Creates a schedule point with the current value at the current time.\n\t * Automation methods like {@link linearRampToValueAtTime} and {@link exponentialRampToValueAtTime}\n\t * require a starting automation value usually set by {@link setValueAtTime}. This method\n\t * is useful since it will do a `setValueAtTime` with whatever the currently computed\n\t * value at the given time is.\n\t * @param time When to add a ramp point.\n\t * @example\n\t * const osc = new Tone.Oscillator().toDestination().start();\n\t * // set the frequency to \"G4\" in exactly 1 second from now.\n\t * osc.frequency.setRampPoint(\"+1\");\n\t * osc.frequency.linearRampToValueAtTime(\"C1\", \"+2\");\n\t */\n\tabstract setRampPoint(time: Time): this;\n\n\t/**\n\t * Schedules a linear continuous change in parameter value from the\n\t * previous scheduled parameter value to the given value.\n\t * @example\n\t * return Tone.Offline(() => {\n\t * \tconst signal = new Tone.Signal(0).toDestination();\n\t * \t// the ramp starts from the previously scheduled value\n\t * \tsignal.setValueAtTime(0, 0.1);\n\t * \tsignal.linearRampToValueAtTime(1, 0.4);\n\t * }, 0.5, 1);\n\t */\n\tabstract linearRampToValueAtTime(\n\t\tvalue: UnitMap[TypeName],\n\t\ttime: Time\n\t): this;\n\n\t/**\n\t * Schedules an exponential continuous change in parameter value from\n\t * the previous scheduled parameter value to the given value.\n\t * @example\n\t * return Tone.Offline(() => {\n\t * \tconst signal = new Tone.Signal(1).toDestination();\n\t * \t// the ramp starts from the previously scheduled value, which must be positive\n\t * \tsignal.setValueAtTime(1, 0.1);\n\t * \tsignal.exponentialRampToValueAtTime(0, 0.4);\n\t * }, 0.5, 1);\n\t */\n\tabstract exponentialRampToValueAtTime(\n\t\tvalue: UnitMap[TypeName],\n\t\ttime: Time\n\t): this;\n\n\t/**\n\t * Schedules an exponential continuous change in parameter value from\n\t * the current time and current value to the given value over the\n\t * duration of the rampTime.\n\t * @param value   The value to ramp to.\n\t * @param rampTime the time that it takes the\n\t *                             value to ramp from its current value\n\t * @param startTime When the ramp should start.\n\t * @example\n\t * const delay = new Tone.FeedbackDelay(0.5, 0.98).toDestination();\n\t * // a short burst of noise through the feedback delay\n\t * const noise = new Tone.Noise().connect(delay).start().stop(\"+0.1\");\n\t * // making the delay time shorter over time will also make the pitch rise\n\t * delay.delayTime.exponentialRampTo(0.01, 20);\n\t * @example\n\t * return Tone.Offline(() => {\n\t * \tconst signal = new Tone.Signal(.1).toDestination();\n\t * \tsignal.exponentialRampTo(5, 0.3, 0.1);\n\t * }, 0.5, 1);\n\t */\n\tabstract exponentialRampTo(\n\t\tvalue: UnitMap[TypeName],\n\t\trampTime: Time,\n\t\tstartTime?: Time\n\t): this;\n\n\t/**\n\t * Schedules an linear continuous change in parameter value from\n\t * the current time and current value to the given value over the\n\t * duration of the rampTime.\n\t *\n\t * @param  value   The value to ramp to.\n\t * @param  rampTime the time that it takes the\n\t *                              value to ramp from its current value\n\t * @param startTime \tWhen the ramp should start.\n\t * @returns {Param} this\n\t * @example\n\t * const delay = new Tone.FeedbackDelay(0.5, 0.98).toDestination();\n\t * // a short burst of noise through the feedback delay\n\t * const noise = new Tone.Noise().connect(delay).start().stop(\"+0.1\");\n\t * // making the delay time shorter over time will also make the pitch rise\n\t * delay.delayTime.linearRampTo(0.01, 20);\n\t * @example\n\t * return Tone.Offline(() => {\n\t * \tconst signal = new Tone.Signal(1).toDestination();\n\t * \tsignal.linearRampTo(0, 0.3, 0.1);\n\t * }, 0.5, 1);\n\t */\n\tabstract linearRampTo(\n\t\tvalue: UnitMap[TypeName],\n\t\trampTime: Time,\n\t\tstartTime?: Time\n\t): this;\n\n\t/**\n\t * Start exponentially approaching the target value at the given time. Since it\n\t * is an exponential approach it will continue approaching after the ramp duration. The\n\t * rampTime is the time that it takes to reach over 99% of the way towards the value.\n\t * @param  value   The value to ramp to.\n\t * @param  rampTime the time that it takes the\n\t *                              value to ramp from its current value\n\t * @param startTime \tWhen the ramp should start.\n\t * @example\n\t * @example\n\t * return Tone.Offline(() => {\n\t * \tconst signal = new Tone.Signal(1).toDestination();\n\t * \tsignal.targetRampTo(0, 0.3, 0.1);\n\t * }, 0.5, 1);\n\t */\n\tabstract targetRampTo(\n\t\tvalue: UnitMap[TypeName],\n\t\trampTime: Time,\n\t\tstartTime?: Time\n\t): this;\n\n\t/**\n\t * Start exponentially approaching the target value at the given time. Since it\n\t * is an exponential approach it will continue approaching after the ramp duration. The\n\t * rampTime is the time that it takes to reach over 99% of the way towards the value. This methods\n\t * is similar to setTargetAtTime except the third argument is a time instead of a 'timeConstant'\n\t * @param  value   The value to ramp to.\n\t * @param time \tWhen the ramp should start.\n\t * @param  rampTime the time that it takes the value to ramp from its current value\n\t * @example\n\t * const osc = new Tone.Oscillator().toDestination().start();\n\t * // exponential approach over 4 seconds starting in 1 second\n\t * osc.frequency.exponentialApproachValueAtTime(\"C4\", \"+1\", 4);\n\t */\n\tabstract exponentialApproachValueAtTime(\n\t\tvalue: UnitMap[TypeName],\n\t\ttime: Time,\n\t\trampTime: Time\n\t): this;\n\n\t/**\n\t * Start exponentially approaching the target value at the given time with\n\t * a rate having the given time constant.\n\t * @param value\n\t * @param startTime\n\t * @param timeConstant\n\t */\n\tabstract setTargetAtTime(\n\t\tvalue: UnitMap[TypeName],\n\t\tstartTime: Time,\n\t\ttimeConstant: number\n\t): this;\n\n\t/**\n\t * Sets an array of arbitrary parameter values starting at the given time\n\t * for the given duration.\n\t *\n\t * @param values\n\t * @param startTime\n\t * @param duration\n\t * @param scaling If the values in the curve should be scaled by some value\n\t * @example\n\t * return Tone.Offline(() => {\n\t * \tconst signal = new Tone.Signal(1).toDestination();\n\t * \tsignal.setValueCurveAtTime([1, 0.2, 0.8, 0.1, 0], 0.2, 0.3);\n\t * }, 0.5, 1);\n\t */\n\tabstract setValueCurveAtTime(\n\t\tvalues: UnitMap[TypeName][],\n\t\tstartTime: Time,\n\t\tduration: Time,\n\t\tscaling?: number\n\t): this;\n\n\t/**\n\t * Cancels all scheduled parameter changes with times greater than or\n\t * equal to startTime.\n\t * @example\n\t * return Tone.Offline(() => {\n\t * \tconst signal = new Tone.Signal(0).toDestination();\n\t * \tsignal.setValueAtTime(0.1, 0.1);\n\t * \tsignal.setValueAtTime(0.2, 0.2);\n\t * \tsignal.setValueAtTime(0.3, 0.3);\n\t * \tsignal.setValueAtTime(0.4, 0.4);\n\t * \t// cancels the last two scheduled changes\n\t * \tsignal.cancelScheduledValues(0.3);\n\t * }, 0.5, 1);\n\t */\n\tabstract cancelScheduledValues(time: Time): this;\n\n\t/**\n\t * This is similar to {@link cancelScheduledValues} except\n\t * it holds the automated value at time until the next automated event.\n\t * @example\n\t * return Tone.Offline(() => {\n\t * \tconst signal = new Tone.Signal(0).toDestination();\n\t * \tsignal.linearRampTo(1, 0.5, 0);\n\t * \tsignal.cancelAndHoldAtTime(0.3);\n\t * }, 0.5, 1);\n\t */\n\tabstract cancelAndHoldAtTime(time: Time): this;\n\n\t/**\n\t * Ramps to the given value over the duration of the rampTime.\n\t * Automatically selects the best ramp type (exponential or linear)\n\t * depending on the `units` of the signal\n\t *\n\t * @param  value\n\t * @param  rampTime The time that it takes the value to ramp from its current value\n\t * @param startTime When the ramp should start.\n\t * @example\n\t * const osc = new Tone.Oscillator().toDestination().start();\n\t * // schedule it to ramp either linearly or exponentially depending on the units\n\t * osc.frequency.rampTo(\"A2\", 10);\n\t * @example\n\t * const osc = new Tone.Oscillator().toDestination().start();\n\t * // schedule it to ramp starting at a specific time\n\t * osc.frequency.rampTo(\"A2\", 10, \"+2\");\n\t */\n\tabstract rampTo(\n\t\tvalue: UnitMap[TypeName],\n\t\trampTime: Time,\n\t\tstartTime?: Time\n\t): this;\n\n\t/**\n\t * The current value of the parameter. Setting this value\n\t * is equivalent to setValueAtTime(value, context.currentTime)\n\t */\n\tabstract value: UnitMap[TypeName];\n\n\t/**\n\t * If the value should be converted or not\n\t */\n\tabstract convert: boolean;\n\n\t/**\n\t * The unit type\n\t */\n\tabstract readonly units: UnitName;\n\n\t/**\n\t * True if the signal value is being overridden by\n\t * a connected signal. Internal use only.\n\t */\n\tabstract overridden: boolean;\n\n\t/**\n\t * The minimum value of the output given the units\n\t */\n\tabstract readonly minValue: number;\n\n\t/**\n\t * The maximum value of the output given the units\n\t */\n\tabstract readonly maxValue: number;\n}\n"
  },
  {
    "path": "Tone/core/context/AudioContext.ts",
    "content": "import {\n\tAudioContext as stdAudioContext,\n\tAudioWorkletNode as stdAudioWorkletNode,\n\tOfflineAudioContext as stdOfflineAudioContext,\n} from \"standardized-audio-context\";\n\nimport { assert } from \"../util/Debug.js\";\nimport { isDefined } from \"../util/TypeCheck.js\";\n\n/**\n * Create a new AudioContext\n */\nexport function createAudioContext(\n\toptions?: AudioContextOptions\n): AudioContext {\n\treturn new stdAudioContext(options) as unknown as AudioContext;\n}\n\n/**\n * Create a new OfflineAudioContext\n */\nexport function createOfflineAudioContext(\n\tchannels: number,\n\tlength: number,\n\tsampleRate: number\n): OfflineAudioContext {\n\treturn new stdOfflineAudioContext(\n\t\tchannels,\n\t\tlength,\n\t\tsampleRate\n\t) as unknown as OfflineAudioContext;\n}\n\n/**\n * Either the online or offline audio context\n */\nexport type AnyAudioContext = AudioContext | OfflineAudioContext;\n\n/**\n * Interface for things that Tone.js adds to the window\n */\ninterface ToneWindow extends Window {\n\tTONE_SILENCE_LOGGING?: boolean;\n\tTONE_DEBUG_CLASS?: string;\n\tBaseAudioContext: any;\n\tAudioWorkletNode: any;\n}\n\n/**\n * A reference to the window object\n * @hidden\n */\nexport const theWindow: ToneWindow | null =\n\ttypeof self === \"object\" ? self : null;\n\n/**\n * If the browser has a window object which has an AudioContext\n * @hidden\n */\nexport const hasAudioContext =\n\ttheWindow &&\n\t(theWindow.hasOwnProperty(\"AudioContext\") ||\n\t\ttheWindow.hasOwnProperty(\"webkitAudioContext\"));\n\nexport function createAudioWorkletNode(\n\tcontext: AnyAudioContext,\n\tname: string,\n\toptions?: Partial<AudioWorkletNodeOptions>\n): AudioWorkletNode {\n\tassert(\n\t\tisDefined(stdAudioWorkletNode),\n\t\t\"AudioWorkletNode only works in a secure context (https or localhost)\"\n\t);\n\treturn new (\n\t\tcontext instanceof theWindow?.BaseAudioContext\n\t\t\t? theWindow?.AudioWorkletNode\n\t\t\t: stdAudioWorkletNode\n\t)(context, name, options);\n}\n\n/**\n * This promise resolves to a boolean which indicates if the\n * functionality is supported within the currently used browse.\n * Taken from [standardized-audio-context](https://github.com/chrisguttandin/standardized-audio-context#issupported)\n */\nexport { isSupported as supported } from \"standardized-audio-context\";\n"
  },
  {
    "path": "Tone/core/context/BaseContext.ts",
    "content": "import type { TransportInstance as Transport } from \"../clock/Transport.js\";\nimport { Seconds } from \"../type/Units.js\";\nimport type { DrawInstance as Draw } from \"../util/Draw.js\";\nimport { Emitter } from \"../util/Emitter.js\";\nimport { AnyAudioContext } from \"./AudioContext.js\";\nimport type { DestinationInstance as Destination } from \"./Destination.js\";\nimport type { ListenerInstance as Listener } from \"./Listener.js\";\n\n// these are either not used in Tone.js or deprecated and not implemented.\nexport type ExcludedFromBaseAudioContext =\n\t| \"onstatechange\"\n\t| \"addEventListener\"\n\t| \"removeEventListener\"\n\t| \"listener\"\n\t| \"dispatchEvent\"\n\t| \"audioWorklet\"\n\t| \"destination\"\n\t| \"createScriptProcessor\";\n\n// the subset of the BaseAudioContext which Tone.Context implements.\nexport type BaseAudioContextSubset = Omit<\n\tBaseAudioContext,\n\tExcludedFromBaseAudioContext\n>;\n\nexport type ContextLatencyHint = AudioContextLatencyCategory;\n\n/**\n * Shared class for both Offline and Online Audio Context's\n */\nexport abstract class BaseContext\n\textends Emitter<\"statechange\" | \"tick\">\n\timplements BaseAudioContextSubset\n{\n\t//---------------------------\n\t// BASE AUDIO CONTEXT METHODS\n\t//---------------------------\n\tabstract createAnalyser(): AnalyserNode;\n\n\tabstract createOscillator(): OscillatorNode;\n\n\tabstract createBufferSource(): AudioBufferSourceNode;\n\n\tabstract createBiquadFilter(): BiquadFilterNode;\n\n\tabstract createBuffer(\n\t\t_numberOfChannels: number,\n\t\t_length: number,\n\t\t_sampleRate: number\n\t): AudioBuffer;\n\n\tabstract createChannelMerger(\n\t\t_numberOfInputs?: number | undefined\n\t): ChannelMergerNode;\n\n\tabstract createChannelSplitter(\n\t\t_numberOfOutputs?: number | undefined\n\t): ChannelSplitterNode;\n\n\tabstract createConstantSource(): ConstantSourceNode;\n\n\tabstract createConvolver(): ConvolverNode;\n\n\tabstract createDelay(_maxDelayTime?: number | undefined): DelayNode;\n\n\tabstract createDynamicsCompressor(): DynamicsCompressorNode;\n\n\tabstract createGain(): GainNode;\n\n\tabstract createIIRFilter(\n\t\t_feedForward: number[] | Float32Array,\n\t\t_feedback: number[] | Float32Array\n\t): IIRFilterNode;\n\n\tabstract createPanner(): PannerNode;\n\n\tabstract createPeriodicWave(\n\t\t_real: number[] | Float32Array,\n\t\t_imag: number[] | Float32Array,\n\t\t_constraints?: PeriodicWaveConstraints | undefined\n\t): PeriodicWave;\n\n\tabstract createStereoPanner(): StereoPannerNode;\n\n\tabstract createWaveShaper(): WaveShaperNode;\n\n\tabstract createMediaStreamSource(\n\t\t_stream: MediaStream\n\t): MediaStreamAudioSourceNode;\n\n\tabstract createMediaElementSource(\n\t\t_element: HTMLMediaElement\n\t): MediaElementAudioSourceNode;\n\n\tabstract createMediaStreamDestination(): MediaStreamAudioDestinationNode;\n\n\tabstract decodeAudioData(_audioData: ArrayBuffer): Promise<AudioBuffer>;\n\n\t//---------------------------\n\t// TONE AUDIO CONTEXT METHODS\n\t//---------------------------\n\n\tabstract createAudioWorkletNode(\n\t\t_name: string,\n\t\t_options?: Partial<AudioWorkletNodeOptions>\n\t): AudioWorkletNode;\n\n\tabstract get rawContext(): AnyAudioContext;\n\n\tabstract addAudioWorkletModule(_url: string): Promise<void>;\n\n\tabstract lookAhead: number;\n\n\tabstract latencyHint: ContextLatencyHint | Seconds;\n\n\tabstract resume(): Promise<void>;\n\n\tabstract setTimeout(\n\t\t_fn: (...args: any[]) => void,\n\t\t_timeout: Seconds\n\t): number;\n\n\tabstract clearTimeout(_id: number): this;\n\n\tabstract setInterval(\n\t\t_fn: (...args: any[]) => void,\n\t\t_interval: Seconds\n\t): number;\n\n\tabstract clearInterval(_id: number): this;\n\n\t/**\n\t * @deprecated use ToneConstantSource instead\n\t */\n\tabstract getConstant(_val: number): AudioBufferSourceNode;\n\n\tabstract get currentTime(): Seconds;\n\n\tabstract get state(): AudioContextState;\n\n\tabstract get sampleRate(): number;\n\n\tabstract get listener(): Listener;\n\n\tabstract get transport(): Transport;\n\n\tabstract get draw(): Draw;\n\n\tabstract get destination(): Destination;\n\n\tabstract now(): Seconds;\n\n\tabstract immediate(): Seconds;\n\n\t/*\n\t * This is a placeholder so that JSON.stringify does not throw an error\n\t * This matches what JSON.stringify(audioContext) returns on a native\n\t * audioContext instance.\n\t */\n\ttoJSON(): Record<string, any> {\n\t\treturn {};\n\t}\n\n\treadonly isOffline: boolean = false;\n}\n"
  },
  {
    "path": "Tone/core/context/Context.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { ConstantOutput } from \"../../../test/helper/ConstantOutput.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { TransportInstance } from \"../clock/Transport.js\";\nimport { getContext } from \"../Global.js\";\nimport { DrawInstance } from \"../util/Draw.js\";\nimport { createAudioContext } from \"./AudioContext.js\";\nimport { Context } from \"./Context.js\";\nimport { DestinationInstance } from \"./Destination.js\";\nimport { ListenerInstance } from \"./Listener.js\";\nimport { connect } from \"./ToneAudioNode.js\";\n\ndescribe(\"Context\", () => {\n\tit(\"creates and disposes the classes attached to the context\", async () => {\n\t\tconst ac = createAudioContext();\n\t\tconst context = new Context(ac);\n\t\tconst ctxDest = context.destination;\n\t\tconst ctxDraw = context.draw;\n\t\tconst ctxTransport = context.transport;\n\t\tconst ctxListener = context.listener;\n\t\texpect(context.destination).is.instanceOf(DestinationInstance);\n\t\texpect(context.draw).is.instanceOf(DrawInstance);\n\t\texpect(context.listener).is.instanceOf(ListenerInstance);\n\t\tawait context.close();\n\t\texpect(ctxDest.disposed).to.be.true;\n\t\texpect(ctxDraw.disposed).to.be.true;\n\t\texpect(ctxTransport.disposed).to.be.true;\n\t\texpect(ctxListener.disposed).to.be.true;\n\t\tcontext.dispose();\n\t});\n\n\tcontext(\"AudioContext\", () => {\n\t\tit(\"extends the AudioContext methods\", () => {\n\t\t\tconst ctx = new Context(createAudioContext());\n\t\t\texpect(ctx).to.have.property(\"createGain\");\n\t\t\texpect(ctx.createGain()).to.have.property(\"gain\");\n\t\t\texpect(ctx).to.have.property(\"createOscillator\");\n\t\t\texpect(ctx.createOscillator()).to.be.have.property(\"frequency\");\n\t\t\texpect(ctx).to.have.property(\"createDelay\");\n\t\t\texpect(ctx.createDelay()).to.be.have.property(\"delayTime\");\n\t\t\texpect(ctx).to.have.property(\"createConstantSource\");\n\t\t\tctx.dispose();\n\t\t\treturn ctx.close();\n\t\t});\n\n\t\tit(\"can be stringified\", () => {\n\t\t\tconst ctx = new Context(createAudioContext());\n\t\t\texpect(JSON.stringify(ctx)).to.equal(\"{}\");\n\t\t\tctx.dispose();\n\t\t\treturn ctx.close();\n\t\t});\n\n\t\tit(\"clock is running\", (done) => {\n\t\t\tconst interval = setInterval(() => {\n\t\t\t\tif (getContext().currentTime > 0.5) {\n\t\t\t\t\tclearInterval(interval);\n\t\t\t\t\tdone();\n\t\t\t\t}\n\t\t\t}, 20);\n\t\t});\n\n\t\tit(\"has a rawContext\", () => {\n\t\t\tconst ctx = new Context(createAudioContext());\n\t\t\texpect(ctx.rawContext).has.property(\"destination\");\n\t\t\texpect(ctx.rawContext).has.property(\"sampleRate\");\n\t\t\tctx.dispose();\n\t\t\treturn ctx.close();\n\t\t});\n\n\t\tit(\"can be constructed with an options object\", () => {\n\t\t\tconst ctx = new Context({\n\t\t\t\tclockSource: \"timeout\",\n\t\t\t\tlatencyHint: \"playback\",\n\t\t\t\tlookAhead: 0.2,\n\t\t\t\tupdateInterval: 0.1,\n\t\t\t\tsampleRate: 32000,\n\t\t\t});\n\t\t\texpect(ctx.lookAhead).to.equal(0.2);\n\t\t\texpect(ctx.updateInterval).to.equal(0.1);\n\t\t\texpect(ctx.latencyHint).to.equal(\"playback\");\n\t\t\texpect(ctx.clockSource).to.equal(\"timeout\");\n\t\t\texpect(ctx.sampleRate).to.equal(32000);\n\t\t\tctx.dispose();\n\t\t\treturn ctx.close();\n\t\t});\n\n\t\tit(\"returns 'now' and 'immediate' time\", () => {\n\t\t\tconst ctx = new Context();\n\t\t\texpect(ctx.now()).to.be.a(\"number\");\n\t\t\texpect(ctx.immediate()).to.be.a(\"number\");\n\t\t\tctx.dispose();\n\t\t\treturn ctx.close();\n\t\t});\n\t});\n\n\tcontext(\"state\", () => {\n\t\tit(\"can suspend and resume the state\", async () => {\n\t\t\tconst ac = createAudioContext();\n\t\t\tconst context = new Context(ac);\n\t\t\texpect(context.rawContext).to.equal(ac);\n\t\t\tawait ac.suspend();\n\t\t\texpect(context.state).to.equal(\"suspended\");\n\t\t\tawait context.resume();\n\t\t\texpect(context.state).to.equal(\"running\");\n\t\t\tcontext.dispose();\n\t\t\treturn context.close();\n\t\t});\n\n\t\tit(\"invokes the statechange event\", async () => {\n\t\t\tconst ac = createAudioContext();\n\t\t\tconst context = new Context(ac);\n\t\t\tlet triggerChange = false;\n\t\t\tcontext.on(\"statechange\", (state) => {\n\t\t\t\tif (!triggerChange) {\n\t\t\t\t\ttriggerChange = true;\n\t\t\t\t\texpect(state).to.equal(\"running\");\n\t\t\t\t}\n\t\t\t});\n\t\t\tawait context.resume();\n\t\t\tawait new Promise<void>((done) => setTimeout(() => done(), 10));\n\t\t\texpect(triggerChange).to.equal(true);\n\t\t\treturn context.dispose();\n\t\t});\n\t});\n\n\tcontext(\"clockSource\", () => {\n\t\tlet ctx;\n\t\tbeforeEach(() => {\n\t\t\tctx = new Context();\n\t\t\treturn ctx.resume();\n\t\t});\n\n\t\tafterEach(() => {\n\t\t\tctx.dispose();\n\t\t\treturn ctx.close();\n\t\t});\n\n\t\tit(\"defaults to 'worker'\", () => {\n\t\t\texpect(ctx.clockSource).to.equal(\"worker\");\n\t\t});\n\n\t\tit(\"provides callback\", (done) => {\n\t\t\texpect(ctx.clockSource).to.equal(\"worker\");\n\t\t\tctx.setTimeout(() => {\n\t\t\t\tdone();\n\t\t\t}, 0.1);\n\t\t});\n\n\t\tit(\"can be set to 'timeout'\", (done) => {\n\t\t\tctx.clockSource = \"timeout\";\n\t\t\texpect(ctx.clockSource).to.equal(\"timeout\");\n\t\t\tctx.setTimeout(() => {\n\t\t\t\tdone();\n\t\t\t}, 0.1);\n\t\t});\n\n\t\tit(\"can be set to 'offline'\", (done) => {\n\t\t\tctx.clockSource = \"offline\";\n\t\t\texpect(ctx.clockSource).to.equal(\"offline\");\n\t\t\t// provides no callback\n\t\t\tctx.setTimeout(() => {\n\t\t\t\tthrow new Error(\"shouldn't be called\");\n\t\t\t}, 0.1);\n\t\t\tsetTimeout(() => {\n\t\t\t\tdone();\n\t\t\t}, 200);\n\t\t});\n\t});\n\tcontext(\"setTimeout\", () => {\n\t\tlet ctx;\n\t\tbeforeEach(() => {\n\t\t\tctx = new Context();\n\t\t\treturn ctx.resume();\n\t\t});\n\n\t\tafterEach(() => {\n\t\t\tctx.dispose();\n\t\t\treturn ctx.close();\n\t\t});\n\n\t\tit(\"can set a timeout\", (done) => {\n\t\t\tctx.setTimeout(() => {\n\t\t\t\tdone();\n\t\t\t}, 0.1);\n\t\t});\n\n\t\tit(\"returns an id\", () => {\n\t\t\texpect(ctx.setTimeout(() => {}, 0.1)).to.be.a(\"number\");\n\t\t\t// try clearing a random ID, shouldn't cause any errors\n\t\t\tctx.clearTimeout(-2);\n\t\t});\n\n\t\tit(\"timeout is not invoked when cancelled\", (done) => {\n\t\t\tconst id = ctx.setTimeout(() => {\n\t\t\t\tthrow new Error(\"shouldn't be invoked\");\n\t\t\t}, 0.01);\n\t\t\tctx.clearTimeout(id);\n\t\t\tctx.setTimeout(() => {\n\t\t\t\tdone();\n\t\t\t}, 0.02);\n\t\t});\n\n\t\tit(\"order is maintained\", (done) => {\n\t\t\tlet wasInvoked = false;\n\t\t\tctx.setTimeout(() => {\n\t\t\t\texpect(wasInvoked).to.equal(true);\n\t\t\t\tdone();\n\t\t\t}, 0.02);\n\t\t\tctx.setTimeout(() => {\n\t\t\t\twasInvoked = true;\n\t\t\t}, 0.01);\n\t\t});\n\n\t\tit(\"is invoked in the offline context\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = new TransportInstance({ context });\n\t\t\t\ttransport.context.setTimeout(() => {\n\t\t\t\t\texpect(transport.now()).to.be.closeTo(0.01, 0.005);\n\t\t\t\t}, 0.01);\n\t\t\t}, 0.05);\n\t\t});\n\n\t\tit(\"is robust against altering the timeline within the callback fn\", (done) => {\n\t\t\tlet invokeCount = 0;\n\t\t\tfunction checkDone(id: number) {\n\t\t\t\t// clearing the current event alters the timeline and should not cause an issue\n\t\t\t\tctx.clearTimeout(id);\n\t\t\t\tinvokeCount++;\n\t\t\t\tif (invokeCount === 3) {\n\t\t\t\t\tdone();\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst id0 = ctx.setTimeout(() => checkDone(id0), 0.01);\n\t\t\tconst id1 = ctx.setTimeout(() => checkDone(id1), 0.01);\n\t\t\tconst id2 = ctx.setTimeout(() => checkDone(id2), 0.01);\n\t\t});\n\t});\n\n\tcontext(\"setInterval\", () => {\n\t\tlet ctx;\n\t\tbeforeEach(() => {\n\t\t\tctx = new Context();\n\t\t\treturn ctx.resume();\n\t\t});\n\n\t\tafterEach(() => {\n\t\t\tctx.dispose();\n\t\t\treturn ctx.close();\n\t\t});\n\n\t\tit(\"can set an interval\", (done) => {\n\t\t\tctx.setInterval(() => {\n\t\t\t\tdone();\n\t\t\t}, 0.1);\n\t\t});\n\n\t\tit(\"returns an id\", () => {\n\t\t\texpect(ctx.setInterval(() => {}, 0.1)).to.be.a(\"number\");\n\t\t\t// try clearing a random ID, shouldn't cause any errors\n\t\t\tctx.clearInterval(-2);\n\t\t});\n\n\t\tit(\"timeout is not invoked when cancelled\", (done) => {\n\t\t\tconst id = ctx.setInterval(() => {\n\t\t\t\tthrow new Error(\"shouldn't be invoked\");\n\t\t\t}, 0.01);\n\t\t\tctx.clearInterval(id);\n\t\t\tctx.setInterval(() => {\n\t\t\t\tdone();\n\t\t\t}, 0.02);\n\t\t});\n\n\t\tit(\"order is maintained\", (done) => {\n\t\t\tlet wasInvoked = false;\n\t\t\tctx.setInterval(() => {\n\t\t\t\texpect(wasInvoked).to.equal(true);\n\t\t\t\tdone();\n\t\t\t}, 0.02);\n\t\t\tctx.setInterval(() => {\n\t\t\t\twasInvoked = true;\n\t\t\t}, 0.01);\n\t\t});\n\n\t\tit(\"is invoked in the offline context\", async () => {\n\t\t\tlet invocationCount = 0;\n\t\t\tawait Offline((context) => {\n\t\t\t\tcontext.setInterval(() => {\n\t\t\t\t\tinvocationCount++;\n\t\t\t\t}, 0.01);\n\t\t\t}, 0.051);\n\t\t\texpect(invocationCount).to.equal(4);\n\t\t});\n\n\t\tit(\"is invoked with the right interval\", async () => {\n\t\t\tlet numberOfInvocations = 0;\n\t\t\tawait Offline((context) => {\n\t\t\t\tlet intervalTime = context.now();\n\t\t\t\tcontext.setInterval(() => {\n\t\t\t\t\texpect(context.now() - intervalTime).to.be.closeTo(\n\t\t\t\t\t\t0.01,\n\t\t\t\t\t\t0.005\n\t\t\t\t\t);\n\t\t\t\t\tintervalTime = context.now();\n\t\t\t\t\tnumberOfInvocations++;\n\t\t\t\t}, 0.01);\n\t\t\t}, 0.051);\n\t\t\texpect(numberOfInvocations).to.equal(4);\n\t\t});\n\t});\n\n\tcontext(\"get/set\", () => {\n\t\tlet ctx;\n\t\tbeforeEach(() => {\n\t\t\tctx = new Context();\n\t\t\treturn ctx.resume();\n\t\t});\n\n\t\tafterEach(() => {\n\t\t\tctx.dispose();\n\t\t\treturn ctx.close();\n\t\t});\n\n\t\tit(\"can set the lookAhead\", () => {\n\t\t\tctx.lookAhead = 0.05;\n\t\t\texpect(ctx.lookAhead).to.equal(0.05);\n\t\t});\n\n\t\tit(\"can set the updateInterval\", () => {\n\t\t\tctx.updateInterval = 0.05;\n\t\t\texpect(ctx.updateInterval).to.equal(0.05);\n\t\t});\n\n\t\tit(\"gets a constant signal\", () => {\n\t\t\treturn ConstantOutput((context) => {\n\t\t\t\tconst bufferSrc = context.getConstant(1);\n\t\t\t\tconnect(bufferSrc, context.destination);\n\t\t\t}, 1);\n\t\t});\n\n\t\tit(\"multiple calls return the same buffer source\", () => {\n\t\t\tconst bufferA = ctx.getConstant(2);\n\t\t\tconst bufferB = ctx.getConstant(2);\n\t\t\texpect(bufferA).to.equal(bufferB);\n\t\t});\n\t});\n\n\tcontext(\"Methods\", () => {\n\t\tlet ctx;\n\t\tbeforeEach(() => {\n\t\t\tctx = new Context();\n\t\t\treturn ctx.resume();\n\t\t});\n\n\t\tafterEach(() => {\n\t\t\tctx.dispose();\n\t\t\treturn ctx.close();\n\t\t});\n\n\t\tit(\"can create a MediaElementAudioSourceNode\", () => {\n\t\t\tconst audioNode = document.createElement(\"audio\");\n\t\t\tconst node = ctx.createMediaElementSource(audioNode);\n\t\t\texpect(node).is.not.undefined;\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/context/Context.ts",
    "content": "import { Ticker, TickerClockSource } from \"../clock/Ticker.js\";\nimport type { TransportInstance as Transport } from \"../clock/Transport.js\";\nimport { Seconds } from \"../type/Units.js\";\nimport { isAudioContext } from \"../util/AdvancedTypeCheck.js\";\nimport { assert } from \"../util/Debug.js\";\nimport { optionsFromArguments } from \"../util/Defaults.js\";\nimport type { DrawInstance as Draw } from \"../util/Draw.js\";\nimport { Timeline } from \"../util/Timeline.js\";\nimport { isDefined } from \"../util/TypeCheck.js\";\nimport {\n\tAnyAudioContext,\n\tcreateAudioContext,\n\tcreateAudioWorkletNode,\n} from \"./AudioContext.js\";\nimport { BaseContext, ContextLatencyHint } from \"./BaseContext.js\";\nimport { closeContext, initializeContext } from \"./ContextInitialization.js\";\nimport type { DestinationInstance as Destination } from \"./Destination.js\";\nimport type { ListenerInstance as Listener } from \"./Listener.js\";\n\nexport interface ContextOptions {\n\tclockSource: TickerClockSource;\n\tlatencyHint: ContextLatencyHint;\n\tlookAhead: Seconds;\n\tupdateInterval: Seconds;\n\tcontext: AnyAudioContext;\n\tsampleRate: number;\n}\n\nexport interface ContextTimeoutEvent {\n\tcallback: (...args: any[]) => void;\n\tid: number;\n\ttime: Seconds;\n}\n\n/**\n * Wraps the native AudioContext.\n * @category Core\n */\nexport class Context extends BaseContext {\n\treadonly name: string = \"Context\";\n\n\t/**\n\t * A private reference to the BaseAudioContext.\n\t */\n\tprotected readonly _context: AnyAudioContext;\n\n\t/**\n\t * A reliable callback method.\n\t */\n\tprivate readonly _ticker: Ticker;\n\n\t/**\n\t * The default latency hint.\n\t */\n\tprivate _latencyHint!: ContextLatencyHint | Seconds;\n\n\t/**\n\t * An object containing all of the AudioBufferSourceNodes with constant values.\n\t */\n\tprivate _constants = new Map<number, AudioBufferSourceNode>();\n\n\t/**\n\t * All of the setTimeout events.\n\t */\n\tprivate _timeouts: Timeline<ContextTimeoutEvent> = new Timeline();\n\n\t/**\n\t * The timeout id counter\n\t */\n\tprivate _timeoutIds = 0;\n\n\t/**\n\t * A reference the Transport singleton belonging to this context\n\t */\n\tprivate _transport!: Transport;\n\n\t/**\n\t * A reference the Listener singleton belonging to this context\n\t */\n\tprivate _listener!: Listener;\n\n\t/**\n\t * A reference the Destination singleton belonging to this context\n\t */\n\tprivate _destination!: Destination;\n\n\t/**\n\t * A reference the Transport singleton belonging to this context\n\t */\n\tprivate _draw!: Draw;\n\n\t/**\n\t * Private indicator if the context has been initialized\n\t */\n\tprivate _initialized = false;\n\n\t/**\n\t * Private indicator if a close() has been called on the context, since close is async\n\t */\n\tprivate _closeStarted = false;\n\n\t/**\n\t * Indicates if the context is an OfflineAudioContext or an AudioContext\n\t */\n\treadonly isOffline: boolean = false;\n\n\tconstructor(context?: AnyAudioContext);\n\tconstructor(options?: Partial<ContextOptions>);\n\tconstructor() {\n\t\tsuper();\n\t\tconst options = optionsFromArguments(Context.getDefaults(), arguments, [\n\t\t\t\"context\",\n\t\t]);\n\n\t\tif (options.context) {\n\t\t\tthis._context = options.context;\n\t\t\t// custom context provided, latencyHint unknown (unless explicitly provided in options)\n\t\t\tthis._latencyHint = arguments[0]?.latencyHint || \"\";\n\t\t} else {\n\t\t\tthis._context = createAudioContext(\n\t\t\t\toptions.sampleRate\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tlatencyHint: options.latencyHint,\n\t\t\t\t\t\t\tsampleRate: options.sampleRate,\n\t\t\t\t\t\t}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\tlatencyHint: options.latencyHint,\n\t\t\t\t\t\t}\n\t\t\t);\n\t\t\tthis._latencyHint = options.latencyHint;\n\t\t}\n\n\t\tthis._ticker = new Ticker(\n\t\t\tthis.emit.bind(this, \"tick\"),\n\t\t\toptions.clockSource,\n\t\t\toptions.updateInterval,\n\t\t\tthis._context.sampleRate\n\t\t);\n\t\tthis.on(\"tick\", this._timeoutLoop.bind(this));\n\n\t\t// fwd events from the context\n\t\tthis._context.onstatechange = () => {\n\t\t\tthis.emit(\"statechange\", this.state);\n\t\t};\n\n\t\t// if no custom updateInterval provided, updateInterval will be derived by lookAhead setter\n\t\tthis[\n\t\t\targuments[0]?.hasOwnProperty(\"updateInterval\")\n\t\t\t\t? \"_lookAhead\"\n\t\t\t\t: \"lookAhead\"\n\t\t] = options.lookAhead;\n\t}\n\n\tstatic getDefaults(): ContextOptions {\n\t\treturn {\n\t\t\tclockSource: \"worker\",\n\t\t\tlatencyHint: \"interactive\",\n\t\t\tlookAhead: 0.1,\n\t\t\tupdateInterval: 0.05,\n\t\t} as ContextOptions;\n\t}\n\n\t/**\n\t * Finish setting up the context. **You usually do not need to do this manually.**\n\t */\n\tprivate initialize(): this {\n\t\tif (!this._initialized) {\n\t\t\t// add any additional modules\n\t\t\tinitializeContext(this);\n\t\t\tthis._initialized = true;\n\t\t}\n\t\treturn this;\n\t}\n\n\t//---------------------------\n\t// BASE AUDIO CONTEXT METHODS\n\t//---------------------------\n\n\tcreateAnalyser(): AnalyserNode {\n\t\treturn this._context.createAnalyser();\n\t}\n\tcreateOscillator(): OscillatorNode {\n\t\treturn this._context.createOscillator();\n\t}\n\tcreateBufferSource(): AudioBufferSourceNode {\n\t\treturn this._context.createBufferSource();\n\t}\n\tcreateBiquadFilter(): BiquadFilterNode {\n\t\treturn this._context.createBiquadFilter();\n\t}\n\tcreateBuffer(\n\t\tnumberOfChannels: number,\n\t\tlength: number,\n\t\tsampleRate: number\n\t): AudioBuffer {\n\t\treturn this._context.createBuffer(numberOfChannels, length, sampleRate);\n\t}\n\tcreateChannelMerger(\n\t\tnumberOfInputs?: number | undefined\n\t): ChannelMergerNode {\n\t\treturn this._context.createChannelMerger(numberOfInputs);\n\t}\n\tcreateChannelSplitter(\n\t\tnumberOfOutputs?: number | undefined\n\t): ChannelSplitterNode {\n\t\treturn this._context.createChannelSplitter(numberOfOutputs);\n\t}\n\tcreateConstantSource(): ConstantSourceNode {\n\t\treturn this._context.createConstantSource();\n\t}\n\tcreateConvolver(): ConvolverNode {\n\t\treturn this._context.createConvolver();\n\t}\n\tcreateDelay(maxDelayTime?: number | undefined): DelayNode {\n\t\treturn this._context.createDelay(maxDelayTime);\n\t}\n\tcreateDynamicsCompressor(): DynamicsCompressorNode {\n\t\treturn this._context.createDynamicsCompressor();\n\t}\n\tcreateGain(): GainNode {\n\t\treturn this._context.createGain();\n\t}\n\tcreateIIRFilter(\n\t\tfeedForward: number[] | Float32Array,\n\t\tfeedback: number[] | Float32Array\n\t): IIRFilterNode {\n\t\t// @ts-ignore\n\t\treturn this._context.createIIRFilter(feedForward, feedback);\n\t}\n\tcreatePanner(): PannerNode {\n\t\treturn this._context.createPanner();\n\t}\n\tcreatePeriodicWave(\n\t\treal: number[] | Float32Array,\n\t\timag: number[] | Float32Array,\n\t\tconstraints?: PeriodicWaveConstraints | undefined\n\t): PeriodicWave {\n\t\treturn this._context.createPeriodicWave(real, imag, constraints);\n\t}\n\tcreateStereoPanner(): StereoPannerNode {\n\t\treturn this._context.createStereoPanner();\n\t}\n\tcreateWaveShaper(): WaveShaperNode {\n\t\treturn this._context.createWaveShaper();\n\t}\n\tcreateMediaStreamSource(stream: MediaStream): MediaStreamAudioSourceNode {\n\t\tassert(\n\t\t\tisAudioContext(this._context),\n\t\t\t\"Not available if OfflineAudioContext\"\n\t\t);\n\t\tconst context = this._context as AudioContext;\n\t\treturn context.createMediaStreamSource(stream);\n\t}\n\tcreateMediaElementSource(\n\t\telement: HTMLMediaElement\n\t): MediaElementAudioSourceNode {\n\t\tassert(\n\t\t\tisAudioContext(this._context),\n\t\t\t\"Not available if OfflineAudioContext\"\n\t\t);\n\t\tconst context = this._context as AudioContext;\n\t\treturn context.createMediaElementSource(element);\n\t}\n\tcreateMediaStreamDestination(): MediaStreamAudioDestinationNode {\n\t\tassert(\n\t\t\tisAudioContext(this._context),\n\t\t\t\"Not available if OfflineAudioContext\"\n\t\t);\n\t\tconst context = this._context as AudioContext;\n\t\treturn context.createMediaStreamDestination();\n\t}\n\tdecodeAudioData(audioData: ArrayBuffer): Promise<AudioBuffer> {\n\t\treturn this._context.decodeAudioData(audioData);\n\t}\n\n\t/**\n\t * The current time in seconds of the AudioContext.\n\t */\n\tget currentTime(): Seconds {\n\t\treturn this._context.currentTime;\n\t}\n\t/**\n\t * The current time in seconds of the AudioContext.\n\t */\n\tget state(): AudioContextState {\n\t\treturn this._context.state;\n\t}\n\t/**\n\t * The current time in seconds of the AudioContext.\n\t */\n\tget sampleRate(): number {\n\t\treturn this._context.sampleRate;\n\t}\n\n\t/**\n\t * The listener\n\t */\n\tget listener(): Listener {\n\t\tthis.initialize();\n\t\treturn this._listener;\n\t}\n\tset listener(l) {\n\t\tassert(\n\t\t\t!this._initialized,\n\t\t\t\"The listener cannot be set after initialization.\"\n\t\t);\n\t\tthis._listener = l;\n\t}\n\n\t/**\n\t * There is only one Transport per Context. It is created on initialization.\n\t */\n\tget transport(): Transport {\n\t\tthis.initialize();\n\t\treturn this._transport;\n\t}\n\tset transport(t: Transport) {\n\t\tassert(\n\t\t\t!this._initialized,\n\t\t\t\"The transport cannot be set after initialization.\"\n\t\t);\n\t\tthis._transport = t;\n\t}\n\n\t/**\n\t * This is the Draw object for the context which is useful for synchronizing the draw frame with the Tone.js clock.\n\t */\n\tget draw(): Draw {\n\t\tthis.initialize();\n\t\treturn this._draw;\n\t}\n\tset draw(d) {\n\t\tassert(!this._initialized, \"Draw cannot be set after initialization.\");\n\t\tthis._draw = d;\n\t}\n\n\t/**\n\t * A reference to the Context's destination node.\n\t */\n\tget destination(): Destination {\n\t\tthis.initialize();\n\t\treturn this._destination;\n\t}\n\tset destination(d: Destination) {\n\t\tassert(\n\t\t\t!this._initialized,\n\t\t\t\"The destination cannot be set after initialization.\"\n\t\t);\n\t\tthis._destination = d;\n\t}\n\n\t//--------------------------------------------\n\t// AUDIO WORKLET\n\t//--------------------------------------------\n\n\t/**\n\t * A set of unsettled promises returned by the addModule method\n\t */\n\tprivate _workletPromises = new Set<Promise<void>>();\n\n\t/**\n\t * Create an audio worklet node from a name and options. The module\n\t * must first be loaded using {@link addAudioWorkletModule}.\n\t */\n\tcreateAudioWorkletNode(\n\t\tname: string,\n\t\toptions?: Partial<AudioWorkletNodeOptions>\n\t): AudioWorkletNode {\n\t\treturn createAudioWorkletNode(this.rawContext, name, options);\n\t}\n\n\t/**\n\t * Add an AudioWorkletProcessor module\n\t * @param url The url of the module\n\t */\n\tasync addAudioWorkletModule(url: string): Promise<void> {\n\t\tassert(\n\t\t\tisDefined(this.rawContext.audioWorklet),\n\t\t\t\"AudioWorkletNode is only available in a secure context (https or localhost)\"\n\t\t);\n\t\tconst workletPromise = this.rawContext.audioWorklet.addModule(url);\n\n\t\tthis._workletPromises.add(workletPromise);\n\t\tworkletPromise.finally(() =>\n\t\t\tthis._workletPromises.delete(workletPromise)\n\t\t);\n\n\t\treturn workletPromise;\n\t}\n\n\t/**\n\t * Returns a promise which resolves when all of the worklets have been loaded on this context\n\t */\n\tprotected async workletsAreReady(): Promise<void> {\n\t\tawait Promise.all(this._workletPromises);\n\t}\n\n\t//---------------------------\n\t// TICKER\n\t//---------------------------\n\n\t/**\n\t * How often the interval callback is invoked.\n\t * This number corresponds to how responsive the scheduling\n\t * can be. Setting to 0 will result in the lowest practical interval\n\t * based on context properties. context.updateInterval + context.lookAhead\n\t * gives you the total latency between scheduling an event and hearing it.\n\t */\n\tget updateInterval(): Seconds {\n\t\treturn this._ticker.updateInterval;\n\t}\n\tset updateInterval(interval: Seconds) {\n\t\tthis._ticker.updateInterval = interval;\n\t}\n\n\t/**\n\t * What the source of the clock is, either \"worker\" (default),\n\t * \"timeout\", or \"offline\" (none).\n\t */\n\tget clockSource(): TickerClockSource {\n\t\treturn this._ticker.type;\n\t}\n\tset clockSource(type: TickerClockSource) {\n\t\tthis._ticker.type = type;\n\t}\n\n\t/**\n\t * The amount of time into the future events are scheduled. Giving Web Audio\n\t * a short amount of time into the future to schedule events can reduce clicks and\n\t * improve performance. This value can be set to 0 to get the lowest latency.\n\t * Adjusting this value also affects the {@link updateInterval}.\n\t */\n\tget lookAhead(): Seconds {\n\t\treturn this._lookAhead;\n\t}\n\tset lookAhead(time: Seconds) {\n\t\tthis._lookAhead = time;\n\t\t// if lookAhead is 0, default to .01 updateInterval\n\t\tthis.updateInterval = time ? time / 2 : 0.01;\n\t}\n\tprivate _lookAhead!: Seconds;\n\n\t/**\n\t * The type of playback, which affects tradeoffs between audio\n\t * output latency and responsiveness.\n\t * In addition to setting the value in seconds, the latencyHint also\n\t * accepts the strings \"interactive\" (prioritizes low latency),\n\t * \"playback\" (prioritizes sustained playback), \"balanced\" (balances\n\t * latency and performance).\n\t * @example\n\t * // prioritize sustained playback\n\t * const context = new Tone.Context({ latencyHint: \"playback\" });\n\t * // set this context as the global Context\n\t * Tone.setContext(context);\n\t * // the global context is gettable with Tone.getContext()\n\t * console.log(Tone.getContext().latencyHint);\n\t */\n\tget latencyHint(): ContextLatencyHint | Seconds {\n\t\treturn this._latencyHint;\n\t}\n\n\t/**\n\t * The unwrapped AudioContext or OfflineAudioContext\n\t */\n\tget rawContext(): AnyAudioContext {\n\t\treturn this._context;\n\t}\n\n\t/**\n\t * The current audio context time plus a short {@link lookAhead}.\n\t * @example\n\t * setInterval(() => {\n\t * \tconsole.log(\"now\", Tone.now());\n\t * }, 100);\n\t */\n\tnow(): Seconds {\n\t\treturn this._context.currentTime + this._lookAhead;\n\t}\n\n\t/**\n\t * The current audio context time without the {@link lookAhead}.\n\t * In most cases it is better to use {@link now} instead of {@link immediate} since\n\t * with {@link now} the {@link lookAhead} is applied equally to _all_ components including internal components,\n\t * to making sure that everything is scheduled in sync. Mixing {@link now} and {@link immediate}\n\t * can cause some timing issues. If no lookAhead is desired, you can set the {@link lookAhead} to `0`.\n\t */\n\timmediate(): Seconds {\n\t\treturn this._context.currentTime;\n\t}\n\n\t/**\n\t * Starts the audio context from a suspended state. This is required\n\t * to initially start the AudioContext.\n\t * @see {@link start}\n\t */\n\tresume(): Promise<void> {\n\t\tif (isAudioContext(this._context)) {\n\t\t\treturn this._context.resume();\n\t\t} else {\n\t\t\treturn Promise.resolve();\n\t\t}\n\t}\n\n\t/**\n\t * Close the context. Once closed, the context can no longer be used and\n\t * any AudioNodes created from the context will be silent.\n\t */\n\tasync close(): Promise<void> {\n\t\tif (\n\t\t\tisAudioContext(this._context) &&\n\t\t\tthis.state !== \"closed\" &&\n\t\t\t!this._closeStarted\n\t\t) {\n\t\t\tthis._closeStarted = true;\n\t\t\tawait this._context.close();\n\t\t}\n\t\tif (this._initialized) {\n\t\t\tcloseContext(this);\n\t\t}\n\t}\n\n\t/**\n\t * **Internal** Generate a looped buffer at some constant value.\n\t * @deprecated\n\t */\n\tgetConstant(val: number): AudioBufferSourceNode {\n\t\tif (this._constants.has(val)) {\n\t\t\treturn this._constants.get(val) as AudioBufferSourceNode;\n\t\t} else {\n\t\t\tconst buffer = this._context.createBuffer(\n\t\t\t\t1,\n\t\t\t\t128,\n\t\t\t\tthis._context.sampleRate\n\t\t\t);\n\t\t\tconst arr = buffer.getChannelData(0);\n\t\t\tfor (let i = 0; i < arr.length; i++) {\n\t\t\t\tarr[i] = val;\n\t\t\t}\n\t\t\tconst constant = this._context.createBufferSource();\n\t\t\tconstant.channelCount = 1;\n\t\t\tconstant.channelCountMode = \"explicit\";\n\t\t\tconstant.buffer = buffer;\n\t\t\tconstant.loop = true;\n\t\t\tconstant.start(0);\n\t\t\tthis._constants.set(val, constant);\n\t\t\treturn constant;\n\t\t}\n\t}\n\n\t/**\n\t * Clean up. Also closes the audio context.\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._ticker.dispose();\n\t\tthis._timeouts.dispose();\n\t\tObject.keys(this._constants).map((val) =>\n\t\t\tthis._constants[val].disconnect()\n\t\t);\n\t\tthis.close();\n\t\treturn this;\n\t}\n\n\t//---------------------------\n\t// TIMEOUTS\n\t//---------------------------\n\n\t/**\n\t * The private loop which keeps track of the context scheduled timeouts\n\t * Is invoked from the clock source\n\t */\n\tprivate _timeoutLoop(): void {\n\t\tconst now = this.now();\n\t\tthis._timeouts.forEachBefore(now, (event) => {\n\t\t\ttry {\n\t\t\t\tevent.callback();\n\t\t\t} finally {\n\t\t\t\tthis._timeouts.remove(event);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * A `setTimeout` which is guaranteed by the clock source.\n\t *\n\t * Also runs in the offline context.\n\t *\n\t * @param fn The callback to invoke.\n\t * @param timeout The timeout in seconds.\n\t * @returns ID to use when invoking {@link clearTimeout}.\n\t */\n\tsetTimeout(fn: (...args: any[]) => void, timeout: Seconds): number {\n\t\tthis._timeoutIds++;\n\t\tconst now = this.now();\n\t\tthis._timeouts.add({\n\t\t\tcallback: fn,\n\t\t\tid: this._timeoutIds,\n\t\t\ttime: now + timeout,\n\t\t});\n\t\treturn this._timeoutIds;\n\t}\n\n\t/**\n\t * Clears a previously scheduled timeout with {@link setTimeout}.\n\t * @param id The ID returned from {@link setTimeout}.\n\t */\n\tclearTimeout(id: number): this {\n\t\tthis._timeouts.forEach((event) => {\n\t\t\tif (event.id === id) {\n\t\t\t\tthis._timeouts.remove(event);\n\t\t\t}\n\t\t});\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clear the function scheduled by {@link setInterval}.\n\t * @param id The ID returned from {@link setInterval}.\n\t */\n\tclearInterval(id: number): this {\n\t\treturn this.clearTimeout(id);\n\t}\n\n\t/**\n\t * Adds a repeating event to the context's callback clock.\n\t * @param fn The callback to invoke.\n\t * @param interval The timeout in seconds.\n\t * @returns ID to use when invoking {@link clearInterval}.\n\t */\n\tsetInterval(fn: (...args: any[]) => void, interval: Seconds): number {\n\t\tconst id = ++this._timeoutIds;\n\t\tconst intervalFn = () => {\n\t\t\tconst now = this.now();\n\t\t\tthis._timeouts.add({\n\t\t\t\tcallback: () => {\n\t\t\t\t\t// invoke the callback\n\t\t\t\t\tfn();\n\t\t\t\t\t// invoke the event to repeat it\n\t\t\t\t\tintervalFn();\n\t\t\t\t},\n\t\t\t\tid,\n\t\t\t\ttime: now + interval,\n\t\t\t});\n\t\t};\n\t\t// kick it off\n\t\tintervalFn();\n\t\treturn id;\n\t}\n}\n"
  },
  {
    "path": "Tone/core/context/ContextInitialization.ts",
    "content": "//-------------------------------------\n// INITIALIZING NEW CONTEXT\n//-------------------------------------\nimport type { Context } from \"./Context.js\";\n\n/**\n * Array of callbacks to invoke when a new context is created\n */\nconst notifyNewContext: Array<(ctx: Context) => void> = [];\n\n/**\n * Used internally to setup a new Context\n */\nexport function onContextInit(cb: (ctx: Context) => void): void {\n\tnotifyNewContext.push(cb);\n}\n\n/**\n * Invoke any classes which need to also be initialized when a new context is created.\n */\nexport function initializeContext(ctx: Context): void {\n\t// add any additional modules\n\tnotifyNewContext.forEach((cb) => cb(ctx));\n}\n\n/**\n * Array of callbacks to invoke when a new context is closed\n */\nconst notifyCloseContext: Array<(ctx: Context) => void> = [];\n\n/**\n * Used internally to tear down a Context\n */\nexport function onContextClose(cb: (ctx: Context) => void): void {\n\tnotifyCloseContext.push(cb);\n}\n\nexport function closeContext(ctx: Context): void {\n\t// remove any additional modules\n\tnotifyCloseContext.forEach((cb) => cb(ctx));\n}\n"
  },
  {
    "path": "Tone/core/context/Delay.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { connectFrom, connectTo } from \"../../../test/helper/Connect.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { connect } from \"../context/ToneAudioNode.js\";\nimport { Delay } from \"./Delay.js\";\n\ndescribe(\"Delay\", () => {\n\tBasicTests(Delay);\n\n\tit(\"can be created and disposed\", () => {\n\t\tconst delay = new Delay();\n\t\tdelay.dispose();\n\t});\n\n\tit(\"handles input and output connections\", () => {\n\t\tconst delay = new Delay();\n\t\tdelay.connect(connectTo());\n\t\tconnectFrom().connect(delay);\n\t\tconnectFrom().connect(delay.delayTime);\n\t\tdelay.dispose();\n\t});\n\n\tit(\"can be constructed with an options object\", () => {\n\t\tconst delay = new Delay({\n\t\t\tdelayTime: 0.3,\n\t\t\tmaxDelay: 2,\n\t\t});\n\t\texpect(delay.delayTime.value).to.be.closeTo(0.3, 0.001);\n\t\texpect(delay.maxDelay).to.equal(2);\n\t\tdelay.dispose();\n\t});\n\n\tit(\"if the constructor delay time is greater than maxDelay, use that as the maxDelay time\", () => {\n\t\tconst delay = new Delay(3);\n\t\texpect(delay.delayTime.value).to.be.closeTo(3, 0.001);\n\t\tdelay.dispose();\n\t});\n\n\tit(\"clamps the delayTime range between 0 and maxDelay\", () => {\n\t\tconst delay = new Delay({\n\t\t\tmaxDelay: 1,\n\t\t});\n\t\texpect(() => {\n\t\t\tdelay.delayTime.value = 2;\n\t\t}).to.throw(RangeError);\n\t\texpect(() => {\n\t\t\tdelay.delayTime.value = -1;\n\t\t}).to.throw(RangeError);\n\t\texpect(delay.delayTime.value).to.be.closeTo(0, 0.001);\n\t\tdelay.dispose();\n\t});\n\n\tit(\"can set the delayTime value\", () => {\n\t\tconst delay = new Delay();\n\t\texpect(delay.delayTime.value).to.be.closeTo(0, 0.001);\n\t\tdelay.delayTime.value = 0.2;\n\t\texpect(delay.delayTime.value).to.be.closeTo(0.2, 0.001);\n\t\tdelay.dispose();\n\t});\n\n\tit(\"can be constructed with options object\", () => {\n\t\tconst delay = new Delay({\n\t\t\tdelayTime: 0.4,\n\t\t});\n\t\texpect(delay.delayTime.value).to.be.closeTo(0.4, 0.001);\n\t\tdelay.dispose();\n\t});\n\n\tit(\"can be constructed with an initial value\", () => {\n\t\tconst delay = new Delay(0.3);\n\t\texpect(delay.delayTime.value).to.be.closeTo(0.3, 0.001);\n\t\tdelay.dispose();\n\t});\n\n\tit(\"can set the units\", () => {\n\t\tconst delay = new Delay(0);\n\t\texpect(delay.delayTime.value).to.be.closeTo(0, 0.001);\n\t\tdelay.dispose();\n\t});\n\n\tit(\"can get the value using 'get'\", () => {\n\t\tconst delay = new Delay(2);\n\t\tconst value = delay.get();\n\t\texpect(value.delayTime).to.be.closeTo(2, 0.001);\n\t\tdelay.dispose();\n\t});\n\n\tit(\"can set the value using 'set'\", () => {\n\t\tconst delay = new Delay(5);\n\t\tdelay.set({\n\t\t\tdelayTime: 4,\n\t\t});\n\t\texpect(delay.delayTime.value).to.be.closeTo(4, 0.001);\n\t\tdelay.dispose();\n\t});\n\n\tit(\"passes audio through\", () => {\n\t\treturn PassAudio((input) => {\n\t\t\tconst delay = new Delay().toDestination();\n\t\t\tconnect(input, delay);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/context/Delay.ts",
    "content": "import { Param } from \"../context/Param.js\";\nimport { Seconds, Time } from \"../type/Units.js\";\nimport { optionsFromArguments } from \"../util/Defaults.js\";\nimport { readOnly } from \"../util/Interface.js\";\nimport { ToneAudioNode, ToneAudioNodeOptions } from \"./ToneAudioNode.js\";\n\nexport interface DelayOptions extends ToneAudioNodeOptions {\n\tdelayTime: Time;\n\tmaxDelay: Time;\n}\n\n/**\n * Wrapper around Web Audio's native [DelayNode](http://webaudio.github.io/web-audio-api/#the-delaynode-interface).\n * @category Core\n * @example\n * return Tone.Offline(() => {\n * \tconst delay = new Tone.Delay(0.1).toDestination();\n * \t// connect the signal to both the delay and the destination\n * \tconst pulse = new Tone.PulseOscillator().connect(delay).toDestination();\n * \t// start and stop the pulse\n * \tpulse.start(0).stop(0.01);\n * }, 0.5, 1);\n */\nexport class Delay extends ToneAudioNode<DelayOptions> {\n\treadonly name: string = \"Delay\";\n\n\t/**\n\t * Private holder of the max delay time\n\t */\n\tprivate _maxDelay: Seconds;\n\n\t/**\n\t * The amount of time the incoming signal is delayed.\n\t * @example\n\t * const delay = new Tone.Delay().toDestination();\n\t * // modulate the delayTime between 0.1 and 1 seconds\n\t * const delayLFO = new Tone.LFO(0.5, 0.1, 1).start().connect(delay.delayTime);\n\t * const pulse = new Tone.PulseOscillator().connect(delay).start();\n\t * // the change in delayTime causes the pitch to go up and down\n\t */\n\treadonly delayTime: Param<\"time\">;\n\n\t/**\n\t * Private reference to the internal DelayNode\n\t */\n\tprivate _delayNode: DelayNode;\n\treadonly input: DelayNode;\n\treadonly output: DelayNode;\n\n\t/**\n\t * @param delayTime The delay applied to the incoming signal.\n\t * @param maxDelay The maximum delay time.\n\t */\n\tconstructor(delayTime?: Time, maxDelay?: Time);\n\tconstructor(options?: Partial<DelayOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Delay.getDefaults(), arguments, [\n\t\t\t\"delayTime\",\n\t\t\t\"maxDelay\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tconst maxDelayInSeconds = this.toSeconds(options.maxDelay);\n\t\tthis._maxDelay = Math.max(\n\t\t\tmaxDelayInSeconds,\n\t\t\tthis.toSeconds(options.delayTime)\n\t\t);\n\n\t\tthis._delayNode =\n\t\t\tthis.input =\n\t\t\tthis.output =\n\t\t\t\tthis.context.createDelay(maxDelayInSeconds);\n\n\t\tthis.delayTime = new Param({\n\t\t\tcontext: this.context,\n\t\t\tparam: this._delayNode.delayTime,\n\t\t\tunits: \"time\",\n\t\t\tvalue: options.delayTime,\n\t\t\tminValue: 0,\n\t\t\tmaxValue: this.maxDelay,\n\t\t});\n\n\t\treadOnly(this, \"delayTime\");\n\t}\n\n\tstatic getDefaults(): DelayOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tdelayTime: 0,\n\t\t\tmaxDelay: 1,\n\t\t});\n\t}\n\n\t/**\n\t * The maximum delay time. This cannot be changed after\n\t * the value is passed into the constructor.\n\t */\n\tget maxDelay(): Seconds {\n\t\treturn this._maxDelay;\n\t}\n\n\t/**\n\t * Clean up.\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._delayNode.disconnect();\n\t\tthis.delayTime.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/core/context/Destination.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { warns } from \"../../../test/helper/Basic.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { Oscillator } from \"../../source/oscillator/Oscillator.js\";\nimport { getContext } from \"../Global.js\";\nimport { DestinationInstance } from \"./Destination.js\";\n\ndescribe(\"Destination\", () => {\n\tit(\"creates itself on the context\", () => {\n\t\texpect(getContext().destination).instanceOf(DestinationInstance);\n\t});\n\n\tit(\"can be muted and unmuted\", () => {\n\t\treturn Offline((context) => {\n\t\t\tcontext.destination.mute = false;\n\t\t\texpect(context.destination.mute).to.equal(false);\n\t\t\tcontext.destination.mute = true;\n\t\t\texpect(context.destination.mute).to.equal(true);\n\t\t});\n\t});\n\n\tit(\"passes audio through\", () => {\n\t\treturn PassAudio((input) => {\n\t\t\tinput.toDestination();\n\t\t});\n\t});\n\n\tit(\"passes no audio when muted\", async () => {\n\t\tconst buffer = await Offline((context) => {\n\t\t\tnew Oscillator().toDestination().start(0);\n\t\t\tcontext.destination.mute = true;\n\t\t});\n\t\texpect(buffer.isSilent()).to.equal(true);\n\t});\n\n\tit(\"has a master volume control\", () => {\n\t\treturn Offline((context) => {\n\t\t\tcontext.destination.volume.value = -20;\n\t\t\texpect(context.destination.volume.value).to.be.closeTo(-20, 0.1);\n\t\t});\n\t});\n\n\tit(\"warns when toMaster is called\", () => {\n\t\twarns(() => {\n\t\t\tconst osc = new Oscillator().toMaster();\n\t\t\tosc.dispose();\n\t\t});\n\t});\n\n\tit(\"can get the maxChannelCount\", () => {\n\t\treturn Offline(\n\t\t\t(context) => {\n\t\t\t\texpect(context.destination.maxChannelCount).to.equal(4);\n\t\t\t},\n\t\t\t0.1,\n\t\t\t4\n\t\t);\n\t});\n\n\tit.skip(\"can set the audio channel configuration\", () => {\n\t\treturn Offline(\n\t\t\t(context) => {\n\t\t\t\texpect(context.destination.channelCount).to.equal(4);\n\t\t\t\tcontext.destination.channelCountMode = \"explicit\";\n\t\t\t\tcontext.destination.channelInterpretation = \"discrete\";\n\t\t\t\texpect(context.destination.channelCountMode).to.equal(\n\t\t\t\t\t\"explicit\"\n\t\t\t\t);\n\t\t\t\texpect(context.destination.channelInterpretation).to.equal(\n\t\t\t\t\t\"discrete\"\n\t\t\t\t);\n\t\t\t},\n\t\t\t0.1,\n\t\t\t4\n\t\t);\n\t});\n\n\tit(\"can pass audio through chained nodes\", () => {\n\t\treturn PassAudio((input) => {\n\t\t\tconst gain = input.context.createGain();\n\t\t\tinput.connect(gain);\n\t\t\tinput.context.destination.chain(gain);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/context/Destination.ts",
    "content": "import { Volume } from \"../../component/channel/Volume.js\";\nimport { Decibels } from \"../type/Units.js\";\nimport { optionsFromArguments } from \"../util/Defaults.js\";\nimport { onContextClose, onContextInit } from \"./ContextInitialization.js\";\nimport { Gain } from \"./Gain.js\";\nimport { Param } from \"./Param.js\";\nimport {\n\tconnectSeries,\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"./ToneAudioNode.js\";\n\ninterface DestinationOptions extends ToneAudioNodeOptions {\n\tvolume: Decibels;\n\tmute: boolean;\n}\n\n/**\n * A single master output that is connected to the\n * AudioDestinationNode (i.e. your speakers).\n *\n * It provides useful conveniences, such as the ability\n * to set the volume and mute the entire application.\n *\n * It also gives you the ability to apply master effects to your application.\n *\n * @example\n * const oscillator = new Tone.Oscillator().start();\n * // The audio will go from the oscillator to the speakers.\n * oscillator.connect(Tone.getDestination());\n * // A convenience for connecting to the master output is also provided:\n * oscillator.toDestination();\n * @category Core\n */\nexport class DestinationInstance extends ToneAudioNode<DestinationOptions> {\n\treadonly name: string = \"Destination\";\n\n\tinput: Volume = new Volume({ context: this.context });\n\toutput: Gain = new Gain({ context: this.context });\n\n\t/**\n\t * The volume of the master output in decibels.\n\t *\n\t * -Infinity is silent, and 0 is no change.\n\t *\n\t * @example\n\t * const osc = new Tone.Oscillator().toDestination();\n\t * osc.start();\n\t * // Ramp the volume down to silent over 10 seconds.\n\t * Tone.getDestination().volume.rampTo(-Infinity, 10);\n\t */\n\tvolume: Param<\"decibels\"> = this.input.volume;\n\n\tconstructor(options: Partial<DestinationOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tDestinationInstance.getDefaults(),\n\t\t\targuments\n\t\t);\n\t\tsuper(options);\n\n\t\tconnectSeries(\n\t\t\tthis.input,\n\t\t\tthis.output,\n\t\t\tthis.context.rawContext.destination\n\t\t);\n\n\t\tthis.mute = options.mute;\n\t\tthis._internalChannels = [\n\t\t\tthis.input,\n\t\t\tthis.context.rawContext.destination,\n\t\t\tthis.output,\n\t\t];\n\t}\n\n\tstatic getDefaults(): DestinationOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tmute: false,\n\t\t\tvolume: 0,\n\t\t});\n\t}\n\n\t/**\n\t * Mute the output.\n\t * @example\n\t * const oscillator = new Tone.Oscillator().start().toDestination();\n\t * setTimeout(() => {\n\t * \t// Mute the output.\n\t * \tTone.Destination.mute = true;\n\t * }, 1000);\n\t */\n\tget mute(): boolean {\n\t\treturn this.input.mute;\n\t}\n\tset mute(mute: boolean) {\n\t\tthis.input.mute = mute;\n\t}\n\n\t/**\n\t * Add a master effects chain.\n\t *\n\t * NOTE: This will disconnect any nodes that were previously chained in the master effects chain.\n\t *\n\t * @param args All arguments will be connected in a row, and the master output will be routed through it.\n\t * @example\n\t * // Route all audio through a filter and compressor.\n\t * const lowpass = new Tone.Filter(800, \"lowpass\");\n\t * const compressor = new Tone.Compressor(-18);\n\t * Tone.Destination.chain(lowpass, compressor);\n\t */\n\tchain(...args: Array<AudioNode | ToneAudioNode>): this {\n\t\tthis.input.disconnect();\n\t\targs.unshift(this.input);\n\t\targs.push(this.output);\n\t\tconnectSeries(...args);\n\t\treturn this;\n\t}\n\n\t/**\n\t * The maximum number of channels the system can output.\n\t * @example\n\t * console.log(Tone.Destination.maxChannelCount);\n\t */\n\tget maxChannelCount(): number {\n\t\treturn this.context.rawContext.destination.maxChannelCount;\n\t}\n\n\t/**\n\t * Clean up\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.volume.dispose();\n\t\treturn this;\n\t}\n}\n\n//-------------------------------------\n// \tINITIALIZATION\n//-------------------------------------\n\nonContextInit((context) => {\n\tcontext.destination = new DestinationInstance({ context });\n});\n\nonContextClose((context) => {\n\tcontext.destination.dispose();\n});\n"
  },
  {
    "path": "Tone/core/context/DummyContext.test.ts",
    "content": "import { DummyContext } from \"./DummyContext.js\";\n\ndescribe(\"DummyContext\", () => {\n\tit(\"has all the methods and members\", () => {\n\t\tconst context = new DummyContext();\n\t\tcontext.createAnalyser();\n\t\tcontext.createOscillator();\n\t\tcontext.createBufferSource();\n\t\tcontext.createBiquadFilter();\n\t\tcontext.createBuffer(2, 1024, 44100);\n\t\tcontext.createChannelMerger();\n\t\tcontext.createChannelSplitter();\n\t\tcontext.createConstantSource();\n\t\tcontext.createConvolver();\n\t\tcontext.createDelay();\n\t\tcontext.createDynamicsCompressor();\n\t\tcontext.createGain();\n\t\tcontext.createIIRFilter([1, 1, 1], [1, 1, 1]);\n\t\tcontext.createPanner();\n\t\tcontext.createPeriodicWave([1, 1, 1], [1, 1, 1]);\n\t\tcontext.createStereoPanner();\n\t\tcontext.createWaveShaper();\n\t\t// @ts-ignore\n\t\tcontext.createMediaStreamSource();\n\t\tcontext.decodeAudioData(new Float32Array(100));\n\t\tcontext.createAudioWorkletNode(\"test.js\");\n\t\tcontext.rawContext;\n\t\tcontext.addAudioWorkletModule(\"test.js\");\n\t\tcontext.resume();\n\t\tcontext.setTimeout(() => {}, 1);\n\t\tcontext.clearTimeout(1);\n\t\tcontext.setInterval(() => {}, 1);\n\t\tcontext.clearInterval(1);\n\t\tcontext.getConstant(1);\n\t\tcontext.currentTime;\n\t\tcontext.state;\n\t\tcontext.sampleRate;\n\t\tcontext.listener;\n\t\tcontext.transport;\n\t\tcontext.draw;\n\t\tcontext.draw;\n\t\tcontext.destination;\n\t\tcontext.now();\n\t\tcontext.immediate();\n\t});\n});\n"
  },
  {
    "path": "Tone/core/context/DummyContext.ts",
    "content": "import type { TransportInstance as Transport } from \"../clock/Transport.js\";\nimport { Seconds } from \"../type/Units.js\";\nimport type { DrawInstance as Draw } from \"../util/Draw.js\";\nimport { AnyAudioContext } from \"./AudioContext.js\";\nimport { BaseContext } from \"./BaseContext.js\";\nimport type { DestinationInstance as Destination } from \"./Destination.js\";\nimport type { ListenerInstance as Listener } from \"./Listener.js\";\n\nexport class DummyContext extends BaseContext {\n\t//---------------------------\n\t// BASE AUDIO CONTEXT METHODS\n\t//---------------------------\n\tcreateAnalyser(): AnalyserNode {\n\t\treturn {} as AnalyserNode;\n\t}\n\n\tcreateOscillator(): OscillatorNode {\n\t\treturn {} as OscillatorNode;\n\t}\n\n\tcreateBufferSource() {\n\t\treturn {} as AudioBufferSourceNode;\n\t}\n\n\tcreateBiquadFilter(): BiquadFilterNode {\n\t\treturn {} as BiquadFilterNode;\n\t}\n\n\tcreateBuffer(\n\t\t_numberOfChannels: number,\n\t\t_length: number,\n\t\t_sampleRate: number\n\t): AudioBuffer {\n\t\treturn {} as AudioBuffer;\n\t}\n\n\tcreateChannelMerger(\n\t\t_numberOfInputs?: number | undefined\n\t): ChannelMergerNode {\n\t\treturn {} as ChannelMergerNode;\n\t}\n\n\tcreateChannelSplitter(\n\t\t_numberOfOutputs?: number | undefined\n\t): ChannelSplitterNode {\n\t\treturn {} as ChannelSplitterNode;\n\t}\n\n\tcreateConstantSource(): ConstantSourceNode {\n\t\treturn {} as ConstantSourceNode;\n\t}\n\n\tcreateConvolver(): ConvolverNode {\n\t\treturn {} as ConvolverNode;\n\t}\n\n\tcreateDelay(_maxDelayTime?: number | undefined): DelayNode {\n\t\treturn {} as DelayNode;\n\t}\n\n\tcreateDynamicsCompressor(): DynamicsCompressorNode {\n\t\treturn {} as DynamicsCompressorNode;\n\t}\n\n\tcreateGain(): GainNode {\n\t\treturn {} as GainNode;\n\t}\n\n\tcreateIIRFilter(\n\t\t_feedForward: number[] | Float32Array,\n\t\t_feedback: number[] | Float32Array\n\t): IIRFilterNode {\n\t\treturn {} as IIRFilterNode;\n\t}\n\n\tcreatePanner(): PannerNode {\n\t\treturn {} as PannerNode;\n\t}\n\n\tcreatePeriodicWave(\n\t\t_real: number[] | Float32Array,\n\t\t_imag: number[] | Float32Array,\n\t\t_constraints?: PeriodicWaveConstraints | undefined\n\t): PeriodicWave {\n\t\treturn {} as PeriodicWave;\n\t}\n\n\tcreateStereoPanner(): StereoPannerNode {\n\t\treturn {} as StereoPannerNode;\n\t}\n\n\tcreateWaveShaper(): WaveShaperNode {\n\t\treturn {} as WaveShaperNode;\n\t}\n\n\tcreateMediaStreamSource(_stream: MediaStream): MediaStreamAudioSourceNode {\n\t\treturn {} as MediaStreamAudioSourceNode;\n\t}\n\n\tcreateMediaElementSource(\n\t\t_element: HTMLMediaElement\n\t): MediaElementAudioSourceNode {\n\t\treturn {} as MediaElementAudioSourceNode;\n\t}\n\n\tcreateMediaStreamDestination(): MediaStreamAudioDestinationNode {\n\t\treturn {} as MediaStreamAudioDestinationNode;\n\t}\n\n\tdecodeAudioData(_audioData: ArrayBuffer): Promise<AudioBuffer> {\n\t\treturn Promise.resolve({} as AudioBuffer);\n\t}\n\n\t//---------------------------\n\t// TONE AUDIO CONTEXT METHODS\n\t//---------------------------\n\n\tcreateAudioWorkletNode(\n\t\t_name: string,\n\t\t_options?: Partial<AudioWorkletNodeOptions>\n\t): AudioWorkletNode {\n\t\treturn {} as AudioWorkletNode;\n\t}\n\n\tget rawContext(): AnyAudioContext {\n\t\treturn {} as AnyAudioContext;\n\t}\n\n\tasync addAudioWorkletModule(_url: string): Promise<void> {\n\t\treturn Promise.resolve();\n\t}\n\n\tlookAhead = 0;\n\n\tlatencyHint = 0;\n\n\tresume(): Promise<void> {\n\t\treturn Promise.resolve();\n\t}\n\n\tsetTimeout(_fn: (...args: any[]) => void, _timeout: Seconds): number {\n\t\treturn 0;\n\t}\n\n\tclearTimeout(_id: number): this {\n\t\treturn this;\n\t}\n\n\tsetInterval(_fn: (...args: any[]) => void, _interval: Seconds): number {\n\t\treturn 0;\n\t}\n\n\tclearInterval(_id: number): this {\n\t\treturn this;\n\t}\n\n\tgetConstant(_val: number): AudioBufferSourceNode {\n\t\treturn {} as AudioBufferSourceNode;\n\t}\n\n\tget currentTime(): Seconds {\n\t\treturn 0;\n\t}\n\n\tget state(): AudioContextState {\n\t\treturn {} as AudioContextState;\n\t}\n\n\tget sampleRate(): number {\n\t\treturn 0;\n\t}\n\n\tget listener(): Listener {\n\t\treturn {} as Listener;\n\t}\n\n\tget transport(): Transport {\n\t\treturn {} as Transport;\n\t}\n\n\tget draw(): Draw {\n\t\treturn {} as Draw;\n\t}\n\tset draw(_d) {}\n\n\tget destination(): Destination {\n\t\treturn {} as Destination;\n\t}\n\tset destination(_d: Destination) {}\n\n\tnow() {\n\t\treturn 0;\n\t}\n\n\timmediate() {\n\t\treturn 0;\n\t}\n\n\treadonly isOffline: boolean = false;\n}\n"
  },
  {
    "path": "Tone/core/context/Gain.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { connectFrom, connectTo } from \"../../../test/helper/Connect.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { Gain } from \"./Gain.js\";\n\ndescribe(\"Gain\", () => {\n\tBasicTests(Gain);\n\n\tit(\"can be created and disposed\", () => {\n\t\tconst gainNode = new Gain();\n\t\tgainNode.dispose();\n\t});\n\n\tit(\"handles input and output connections\", () => {\n\t\tconst gainNode = new Gain();\n\t\tgainNode.connect(connectTo());\n\t\tconnectFrom().connect(gainNode);\n\t\tconnectFrom().connect(gainNode.gain);\n\t\tgainNode.dispose();\n\t});\n\n\tit(\"can set the gain value\", () => {\n\t\tconst gainNode = new Gain();\n\t\texpect(gainNode.gain.value).to.be.closeTo(1, 0.001);\n\t\tgainNode.gain.value = 0.2;\n\t\texpect(gainNode.gain.value).to.be.closeTo(0.2, 0.001);\n\t\tgainNode.dispose();\n\t});\n\n\tit(\"can be constructed with options object\", () => {\n\t\tconst gainNode = new Gain({\n\t\t\tgain: 0.4,\n\t\t});\n\t\texpect(gainNode.gain.value).to.be.closeTo(0.4, 0.001);\n\t\tgainNode.dispose();\n\t});\n\n\tit(\"can be constructed with an initial value\", () => {\n\t\tconst gainNode = new Gain(3);\n\t\texpect(gainNode.gain.value).to.be.closeTo(3, 0.001);\n\t\tgainNode.dispose();\n\t});\n\n\tit(\"can set the units\", () => {\n\t\tconst gainNode = new Gain(0, \"decibels\");\n\t\texpect(gainNode.gain.value).to.be.closeTo(0, 0.001);\n\t\texpect(gainNode.gain.units).to.equal(\"decibels\");\n\t\tgainNode.dispose();\n\t});\n\n\tit(\"can get the value using 'get'\", () => {\n\t\tconst gainNode = new Gain(5);\n\t\tconst value = gainNode.get();\n\t\texpect(value.gain).to.be.closeTo(5, 0.001);\n\t\tgainNode.dispose();\n\t});\n\n\tit(\"can set the value using 'set'\", () => {\n\t\tconst gainNode = new Gain(5);\n\t\tgainNode.set({\n\t\t\tgain: 4,\n\t\t});\n\t\texpect(gainNode.gain.value).to.be.closeTo(4, 0.001);\n\t\tgainNode.dispose();\n\t});\n\n\tit(\"passes audio through\", () => {\n\t\treturn PassAudio((input) => {\n\t\t\tconst gainNode = new Gain().toDestination();\n\t\t\tinput.connect(gainNode);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/context/Gain.ts",
    "content": "import { Param } from \"../context/Param.js\";\nimport { UnitMap, UnitName } from \"../type/Units.js\";\nimport { optionsFromArguments } from \"../util/Defaults.js\";\nimport { readOnly } from \"../util/Interface.js\";\nimport { ToneAudioNode, ToneAudioNodeOptions } from \"./ToneAudioNode.js\";\n\ninterface GainOptions<TypeName extends UnitName> extends ToneAudioNodeOptions {\n\tgain: UnitMap[TypeName];\n\tunits: TypeName;\n\tconvert: boolean;\n\tminValue?: number;\n\tmaxValue?: number;\n}\n\n/**\n * A thin wrapper around the Native Web Audio GainNode.\n * The GainNode is a basic building block of the Web Audio\n * API and is useful for routing audio and adjusting gains.\n * @category Core\n * @example\n * return Tone.Offline(() => {\n * \tconst gainNode = new Tone.Gain(0).toDestination();\n * \tconst osc = new Tone.Oscillator(30).connect(gainNode).start();\n * \tgainNode.gain.rampTo(1, 0.1);\n * \tgainNode.gain.rampTo(0, 0.4, 0.2);\n * }, 0.7, 1);\n */\nexport class Gain<\n\tTypeName extends \"gain\" | \"decibels\" | \"normalRange\" = \"gain\",\n> extends ToneAudioNode<GainOptions<TypeName>> {\n\treadonly name: string = \"Gain\";\n\n\t/**\n\t * The gain parameter of the gain node.\n\t * @example\n\t * const gainNode = new Tone.Gain(0).toDestination();\n\t * const osc = new Tone.Oscillator().connect(gainNode).start();\n\t * gainNode.gain.rampTo(1, 0.1);\n\t * gainNode.gain.rampTo(0, 2, \"+0.5\");\n\t */\n\treadonly gain: Param<TypeName>;\n\n\t/**\n\t * The wrapped GainNode.\n\t */\n\tprivate _gainNode: GainNode = this.context.createGain();\n\n\t// input = output\n\treadonly input: GainNode = this._gainNode;\n\treadonly output: GainNode = this._gainNode;\n\n\t/**\n\t * @param  gain The initial gain of the GainNode\n\t * @param units The units of the gain parameter.\n\t */\n\tconstructor(gain?: UnitMap[TypeName], units?: TypeName);\n\tconstructor(options?: Partial<GainOptions<TypeName>>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Gain.getDefaults(), arguments, [\n\t\t\t\"gain\",\n\t\t\t\"units\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis.gain = new Param({\n\t\t\tcontext: this.context,\n\t\t\tconvert: options.convert,\n\t\t\tparam: this._gainNode.gain,\n\t\t\tunits: options.units,\n\t\t\tvalue: options.gain,\n\t\t\tminValue: options.minValue,\n\t\t\tmaxValue: options.maxValue,\n\t\t});\n\t\treadOnly(this, \"gain\");\n\t}\n\n\tstatic getDefaults(): GainOptions<any> {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tconvert: true,\n\t\t\tgain: 1,\n\t\t\tunits: \"gain\",\n\t\t});\n\t}\n\n\t/**\n\t * Clean up.\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._gainNode.disconnect();\n\t\tthis.gain.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/core/context/Listener.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { getContext } from \"../Global.js\";\nimport { ListenerInstance } from \"./Listener.js\";\n\ndescribe(\"Listener\", () => {\n\tit(\"creates itself on the context\", () => {\n\t\texpect(getContext().listener).instanceOf(ListenerInstance);\n\t});\n\n\tit(\"can get and set values as an object\", () => {\n\t\t// can get and set some values\n\t\tOffline(({ listener }) => {\n\t\t\texpect(listener.get()).to.have.property(\"positionX\");\n\t\t\texpect(listener.get()).to.have.property(\"positionY\");\n\t\t\texpect(listener.get()).to.have.property(\"positionZ\");\n\t\t\texpect(listener.get()).to.have.property(\"forwardZ\");\n\t\t\texpect(listener.get()).to.have.property(\"upY\");\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/context/Listener.ts",
    "content": "import { onContextClose, onContextInit } from \"./ContextInitialization.js\";\nimport { Param } from \"./Param.js\";\nimport { ToneAudioNode, ToneAudioNodeOptions } from \"./ToneAudioNode.js\";\n\nexport interface ListenerOptions extends ToneAudioNodeOptions {\n\tpositionX: number;\n\tpositionY: number;\n\tpositionZ: number;\n\tforwardX: number;\n\tforwardY: number;\n\tforwardZ: number;\n\tupX: number;\n\tupY: number;\n\tupZ: number;\n}\n\n/**\n * Tone.Listener is a thin wrapper around the AudioListener. Listener combined\n * with {@link Panner3D} makes up the Web Audio API's 3D panning system. Panner3D allows you\n * to place sounds in 3D and Listener allows you to navigate the 3D sound environment from\n * a first-person perspective. There is only one listener per audio context.\n * @category Core\n */\nexport class ListenerInstance extends ToneAudioNode<ListenerOptions> {\n\treadonly name: string = \"Listener\";\n\n\t/**\n\t * The listener has no inputs or outputs.\n\t */\n\toutput: undefined;\n\tinput: undefined;\n\n\treadonly positionX: Param = new Param({\n\t\tcontext: this.context,\n\t\tparam: this.context.rawContext.listener.positionX,\n\t});\n\n\treadonly positionY: Param = new Param({\n\t\tcontext: this.context,\n\t\tparam: this.context.rawContext.listener.positionY,\n\t});\n\n\treadonly positionZ: Param = new Param({\n\t\tcontext: this.context,\n\t\tparam: this.context.rawContext.listener.positionZ,\n\t});\n\n\treadonly forwardX: Param = new Param({\n\t\tcontext: this.context,\n\t\tparam: this.context.rawContext.listener.forwardX,\n\t});\n\n\treadonly forwardY: Param = new Param({\n\t\tcontext: this.context,\n\t\tparam: this.context.rawContext.listener.forwardY,\n\t});\n\n\treadonly forwardZ: Param = new Param({\n\t\tcontext: this.context,\n\t\tparam: this.context.rawContext.listener.forwardZ,\n\t});\n\n\treadonly upX: Param = new Param({\n\t\tcontext: this.context,\n\t\tparam: this.context.rawContext.listener.upX,\n\t});\n\n\treadonly upY: Param = new Param({\n\t\tcontext: this.context,\n\t\tparam: this.context.rawContext.listener.upY,\n\t});\n\n\treadonly upZ: Param = new Param({\n\t\tcontext: this.context,\n\t\tparam: this.context.rawContext.listener.upZ,\n\t});\n\n\tstatic getDefaults(): ListenerOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tpositionX: 0,\n\t\t\tpositionY: 0,\n\t\t\tpositionZ: 0,\n\t\t\tforwardX: 0,\n\t\t\tforwardY: 0,\n\t\t\tforwardZ: -1,\n\t\t\tupX: 0,\n\t\t\tupY: 1,\n\t\t\tupZ: 0,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.positionX.dispose();\n\t\tthis.positionY.dispose();\n\t\tthis.positionZ.dispose();\n\t\tthis.forwardX.dispose();\n\t\tthis.forwardY.dispose();\n\t\tthis.forwardZ.dispose();\n\t\tthis.upX.dispose();\n\t\tthis.upY.dispose();\n\t\tthis.upZ.dispose();\n\t\treturn this;\n\t}\n}\n\n//-------------------------------------\n// \tINITIALIZATION\n//-------------------------------------\n\nonContextInit((context) => {\n\tcontext.listener = new ListenerInstance({ context });\n});\n\nonContextClose((context) => {\n\tcontext.listener.dispose();\n});\n"
  },
  {
    "path": "Tone/core/context/Offline.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { TestAudioBuffer } from \"../../../test/helper/compare/TestAudioBuffer.js\";\nimport { ToneOscillatorNode } from \"../../source/oscillator/ToneOscillatorNode.js\";\nimport { noOp } from \"../util/Interface.js\";\nimport { Offline } from \"./Offline.js\";\nimport { ToneAudioBuffer } from \"./ToneAudioBuffer.js\";\n\ndescribe(\"Offline\", () => {\n\tit(\"accepts a callback and a duration\", () => {\n\t\treturn Offline(noOp, 0.01);\n\t});\n\n\tit(\"returns a promise\", () => {\n\t\tconst ret = Offline(noOp, 0.01);\n\t\texpect(ret).to.have.property(\"then\");\n\t\treturn ret;\n\t});\n\n\tit(\"generates a buffer\", async () => {\n\t\tconst buffer = await Offline(noOp, 0.01);\n\t\texpect(buffer).to.be.instanceOf(ToneAudioBuffer);\n\t});\n\n\tit(\"silent by default\", async () => {\n\t\tconst buffer = await Offline(noOp, 0.01, 1);\n\t\tconst isSilent = buffer.toArray().every((sample) => sample === 0);\n\t\texpect(isSilent).to.equal(true);\n\t});\n\n\tit(\"records the master output\", async () => {\n\t\tconst buffer = await Offline(() => {\n\t\t\tnew ToneOscillatorNode().toDestination().start();\n\t\t}, 0.01);\n\t\tconst testBuff = new TestAudioBuffer(buffer.get() as AudioBuffer);\n\t\texpect(testBuff.isSilent()).is.equal(false);\n\t});\n\n\tit(\"returning a promise defers the rendering till the promise resolves\", async () => {\n\t\tlet wasInvoked = false;\n\t\tconst buffer = await Offline(() => {\n\t\t\tnew ToneOscillatorNode().toDestination().start();\n\t\t\treturn new Promise((done) => {\n\t\t\t\tsetTimeout(done, 100);\n\t\t\t}).then(() => {\n\t\t\t\twasInvoked = true;\n\t\t\t});\n\t\t}, 0.01);\n\t\tconst testBuff = new TestAudioBuffer(buffer.get() as AudioBuffer);\n\t\texpect(wasInvoked).is.equal(true);\n\t\texpect(testBuff.isSilent()).to.equal(false);\n\t});\n\n\tit(\"can schedule specific timing outputs\", async () => {\n\t\tconst buffer = await Offline(() => {\n\t\t\tnew ToneOscillatorNode().toDestination().start(0.05);\n\t\t}, 0.1);\n\t\tconst testBuff = new TestAudioBuffer(buffer.get() as AudioBuffer);\n\t\texpect(testBuff.getTimeOfFirstSound()).to.be.closeTo(0.05, 0.0001);\n\t});\n});\n"
  },
  {
    "path": "Tone/core/context/Offline.ts",
    "content": "import \"./Destination.js\";\nimport \"./Listener.js\";\n\nimport { getContext, setContext } from \"../Global.js\";\nimport { Seconds } from \"../type/Units.js\";\nimport { OfflineContext } from \"./OfflineContext.js\";\nimport { ToneAudioBuffer } from \"./ToneAudioBuffer.js\";\n\n/**\n * Generate a buffer by rendering all of the Tone.js code within the callback using the OfflineAudioContext.\n * The OfflineAudioContext is capable of rendering much faster than real time in many cases.\n * The callback function also passes in an offline instance of {@link Context} which can be used\n * to schedule events along the Transport.\n * @param  callback  All Tone.js nodes which are created and scheduled within this callback are recorded into the output Buffer.\n * @param  duration     the amount of time to record for.\n * @return  The promise which is invoked with the ToneAudioBuffer of the recorded output.\n * @example\n * // render 2 seconds of the oscillator\n * Tone.Offline(() => {\n * \t// only nodes created in this callback will be recorded\n * \tconst oscillator = new Tone.Oscillator().toDestination().start(0);\n * }, 2).then((buffer) => {\n * \t// do something with the output buffer\n * \tconsole.log(buffer);\n * });\n * @example\n * // can also schedule events along the Transport\n * // using the passed in Offline Transport\n * Tone.Offline(({ transport }) => {\n * \tconst osc = new Tone.Oscillator().toDestination();\n * \ttransport.schedule(time => {\n * \t\tosc.start(time).stop(time + 0.1);\n * \t}, 1);\n * \t// make sure to start the transport\n * \ttransport.start(0.2);\n * }, 4).then((buffer) => {\n * \t// do something with the output buffer\n * \tconsole.log(buffer);\n * });\n * @category Core\n */\nexport async function Offline(\n\tcallback: (context: OfflineContext) => Promise<void> | void,\n\tduration: Seconds,\n\tchannels = 2,\n\tsampleRate: number = getContext().sampleRate\n): Promise<ToneAudioBuffer> {\n\t// set the OfflineAudioContext based on the current context\n\tconst originalContext = getContext();\n\n\tconst context = new OfflineContext(channels, duration, sampleRate);\n\tsetContext(context);\n\n\t// invoke the callback/scheduling\n\tawait callback(context);\n\n\t// then render the audio\n\tconst bufferPromise = context.render();\n\n\t// return the original AudioContext\n\tsetContext(originalContext);\n\n\t// await the rendering\n\tconst buffer = await bufferPromise;\n\n\t// return the audio\n\treturn new ToneAudioBuffer(buffer);\n}\n"
  },
  {
    "path": "Tone/core/context/OfflineContext.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { OfflineContext } from \"./OfflineContext.js\";\n\ncontext(\"OfflineContext\", () => {\n\tit(\"can be created an disposed\", () => {\n\t\tconst ctx = new OfflineContext(1, 0.1, 44100);\n\t\tctx.dispose();\n\t});\n\n\tit(\"is setup with 0 lookAhead and offline clockSource\", () => {\n\t\tconst ctx = new OfflineContext(1, 0.1, 44100);\n\t\texpect(ctx.lookAhead).to.equal(0);\n\t\texpect(ctx.clockSource).to.equal(\"offline\");\n\t\treturn ctx.dispose();\n\t});\n\n\tit(\"now = currentTime\", () => {\n\t\tconst ctx = new OfflineContext(1, 0.1, 44100);\n\t\texpect(ctx.currentTime).to.equal(ctx.now());\n\t\treturn ctx.dispose();\n\t});\n\n\tit(\"closing shouldn't do anything\", () => {\n\t\tconst ctx = new OfflineContext(1, 0.1, 44100);\n\t\treturn ctx.close();\n\t});\n\n\tit(\"can render audio\", async () => {\n\t\tconst ctx = new OfflineContext(1, 0.2, 44100);\n\t\tconst osc = ctx.createOscillator();\n\t\tosc.connect(ctx.rawContext.destination);\n\t\tosc.start(0.1);\n\t\tconst buffer = await ctx.render();\n\t\texpect(buffer).to.have.property(\"length\");\n\t\texpect(buffer).to.have.property(\"sampleRate\");\n\t\tconst array = buffer.getChannelData(0);\n\t\tfor (let i = 0; i < array.length; i++) {\n\t\t\tif (array[i] !== 0) {\n\t\t\t\texpect(i / array.length).to.be.closeTo(0.5, 0.01);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t});\n\n\tit(\"can render audio not async\", async () => {\n\t\tconst ctx = new OfflineContext(1, 0.2, 44100);\n\t\tconst osc = ctx.createOscillator();\n\t\tosc.connect(ctx.rawContext.destination);\n\t\tosc.start(0.1);\n\t\tconst buffer = await ctx.render(false);\n\t\texpect(buffer).to.have.property(\"length\");\n\t\texpect(buffer).to.have.property(\"sampleRate\");\n\t\tconst array = buffer.getChannelData(0);\n\t\tfor (let i = 0; i < array.length; i++) {\n\t\t\tif (array[i] !== 0) {\n\t\t\t\texpect(i / array.length).to.be.closeTo(0.5, 0.01);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t});\n});\n"
  },
  {
    "path": "Tone/core/context/OfflineContext.ts",
    "content": "import { createOfflineAudioContext } from \"../context/AudioContext.js\";\nimport { Context } from \"../context/Context.js\";\nimport { Seconds } from \"../type/Units.js\";\nimport { isOfflineAudioContext } from \"../util/AdvancedTypeCheck.js\";\nimport { ToneAudioBuffer } from \"./ToneAudioBuffer.js\";\n\n/**\n * Wrapper around the OfflineAudioContext\n * @category Core\n * @example\n * // generate a single channel, 0.5 second buffer\n * const context = new Tone.OfflineContext(1, 0.5, 44100);\n * const osc = new Tone.Oscillator({ context });\n * context.render().then(buffer => {\n * \tconsole.log(buffer.numberOfChannels, buffer.duration);\n * });\n */\nexport class OfflineContext extends Context {\n\treadonly name: string = \"OfflineContext\";\n\n\t/**\n\t * A private reference to the duration\n\t */\n\tprivate readonly _duration: Seconds;\n\n\t/**\n\t * An artificial clock source\n\t */\n\tprivate _currentTime: Seconds = 0;\n\n\t/**\n\t * Private reference to the OfflineAudioContext.\n\t */\n\tprotected _context!: OfflineAudioContext;\n\n\treadonly isOffline: boolean = true;\n\n\t/**\n\t * @param  channels  The number of channels to render\n\t * @param  duration  The duration to render in seconds\n\t * @param sampleRate the sample rate to render at\n\t */\n\tconstructor(channels: number, duration: Seconds, sampleRate: number);\n\tconstructor(context: OfflineAudioContext);\n\tconstructor() {\n\t\tsuper({\n\t\t\tclockSource: \"offline\",\n\t\t\tcontext: isOfflineAudioContext(arguments[0])\n\t\t\t\t? arguments[0]\n\t\t\t\t: createOfflineAudioContext(\n\t\t\t\t\t\targuments[0],\n\t\t\t\t\t\targuments[1] * arguments[2],\n\t\t\t\t\t\targuments[2]\n\t\t\t\t\t),\n\t\t\tlookAhead: 0,\n\t\t\tupdateInterval: isOfflineAudioContext(arguments[0])\n\t\t\t\t? 128 / arguments[0].sampleRate\n\t\t\t\t: 128 / arguments[2],\n\t\t});\n\n\t\tthis._duration = isOfflineAudioContext(arguments[0])\n\t\t\t? arguments[0].length / arguments[0].sampleRate\n\t\t\t: arguments[1];\n\t}\n\n\t/**\n\t * Override the now method to point to the internal clock time\n\t */\n\tnow(): Seconds {\n\t\treturn this._currentTime;\n\t}\n\n\t/**\n\t * Same as this.now()\n\t */\n\tget currentTime(): Seconds {\n\t\treturn this._currentTime;\n\t}\n\n\t/**\n\t * Render just the clock portion of the audio context.\n\t */\n\tprivate async _renderClock(asynchronous: boolean): Promise<void> {\n\t\tlet index = 0;\n\t\twhile (this._duration - this._currentTime >= 0) {\n\t\t\t// invoke all the callbacks on that time\n\t\t\tthis.emit(\"tick\");\n\n\t\t\t// increment the clock in block-sized chunks\n\t\t\tthis._currentTime += 128 / this.sampleRate;\n\n\t\t\t// yield once a second of audio\n\t\t\tindex++;\n\t\t\tconst yieldEvery = Math.floor(this.sampleRate / 128);\n\t\t\tif (asynchronous && index % yieldEvery === 0) {\n\t\t\t\tawait new Promise((done) => setTimeout(done, 1));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Render the output of the OfflineContext\n\t * @param asynchronous If the clock should be rendered asynchronously, which will not block the main thread, but be slightly slower.\n\t */\n\tasync render(asynchronous = true): Promise<ToneAudioBuffer> {\n\t\tawait this.workletsAreReady();\n\t\tawait this._renderClock(asynchronous);\n\t\tconst buffer = await this._context.startRendering();\n\t\treturn new ToneAudioBuffer(buffer);\n\t}\n\n\t/**\n\t * Close the context\n\t */\n\tclose(): Promise<void> {\n\t\treturn Promise.resolve();\n\t}\n}\n"
  },
  {
    "path": "Tone/core/context/OnRunning.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { Context } from \"./Context.js\";\nimport { OfflineContext } from \"./OfflineContext.js\";\nimport { onContextRunning } from \"./OnRunning.js\";\n\ncontext(\"onContextRunning\", () => {\n\tit(\"callback is invoked immediately when offline context is used\", () => {\n\t\tconst ctx = new OfflineContext(1, 0.1, 44100);\n\t\tlet wasInvoked = false;\n\n\t\tonContextRunning(ctx, () => {\n\t\t\twasInvoked = true;\n\t\t});\n\n\t\texpect(wasInvoked).to.be.true;\n\t\tctx.dispose();\n\t});\n\n\tit(\"callback is invoked immediately when context is already running\", async () => {\n\t\tconst ctx = new Context();\n\t\tawait ctx.resume();\n\t\tlet wasInvoked = false;\n\n\t\tonContextRunning(ctx, () => {\n\t\t\twasInvoked = true;\n\t\t});\n\n\t\texpect(wasInvoked).to.be.true;\n\t\tctx.dispose();\n\t});\n\n\tit(\"callback is invoked when the context starts running\", async () => {\n\t\tconst ctx = new Context();\n\t\tlet wasInvoked = false;\n\n\t\tonContextRunning(ctx, () => {\n\t\t\twasInvoked = true;\n\t\t});\n\n\t\texpect(wasInvoked).to.be.false;\n\n\t\tawait ctx.resume();\n\t\texpect(wasInvoked).to.be.true;\n\n\t\tctx.dispose();\n\t});\n\n\tit(\"can remove the callback with the returned function\", async () => {\n\t\tconst ctx = new Context();\n\t\tlet wasInvoked = false;\n\t\tconst remove = onContextRunning(ctx, () => {\n\t\t\twasInvoked = true;\n\t\t});\n\t\texpect(wasInvoked).to.be.false;\n\t\tremove();\n\n\t\tawait ctx.resume();\n\n\t\texpect(wasInvoked).to.be.false;\n\t\tctx.dispose();\n\t});\n});\n"
  },
  {
    "path": "Tone/core/context/OnRunning.ts",
    "content": "import { BaseContext } from \"./BaseContext.js\";\n\n/**\n * Invoked when the context is started. The callback is invoked immediately\n * if the context is already started or when the context is an OfflineContext.\n * Returns a function which can be called to remove the listener.\n * @internal Used to trigger certain events when the context has been started.\n */\nexport function onContextRunning(\n\tcontext: BaseContext,\n\tcallback: () => void\n): () => void {\n\tconst listener = (state: AudioContextState) => {\n\t\tif (state === \"running\") {\n\t\t\tcallback();\n\t\t\tcontext.off(\"statechange\", listener);\n\t\t}\n\t};\n\tif (context.isOffline || context.state === \"running\") {\n\t\tcallback();\n\t\treturn () => {};\n\t}\n\n\tcontext.on(\"statechange\", listener);\n\treturn () => context.off(\"statechange\", listener);\n}\n"
  },
  {
    "path": "Tone/core/context/Param.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests, testAudioContext } from \"../../../test/helper/Basic.js\";\nimport { Plot } from \"../../../test/helper/compare/index.js\";\nimport { atTime, Offline } from \"../../../test/helper/Offline.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { getContext } from \"../Global.js\";\nimport { UnitName } from \"../type/Units.js\";\nimport { Gain } from \"./Gain.js\";\nimport { Param } from \"./Param.js\";\nimport { connect } from \"./ToneAudioNode.js\";\n\nconst audioContext = getContext();\n\ndescribe(\"Param\", () => {\n\tBasicTests(Param, {\n\t\tcontext: testAudioContext,\n\t\tparam: testAudioContext.createOscillator().frequency,\n\t});\n\n\tcontext(\"constructor\", () => {\n\t\tit(\"can be created and disposed\", async () => {\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst param = new Param<\"time\">({\n\t\t\t\t\tcontext,\n\t\t\t\t\tparam: context.createConstantSource().offset,\n\t\t\t\t\tunits: \"time\",\n\t\t\t\t});\n\t\t\t\texpect(param.getValueAtTime(0)).to.equal(1);\n\t\t\t\tparam.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can pass in a value\", async () => {\n\t\t\tawait Offline((context) => {\n\t\t\t\tconst param = new Param({\n\t\t\t\t\tcontext,\n\t\t\t\t\tparam: context.createConstantSource().offset,\n\t\t\t\t\tvalue: 1.1,\n\t\t\t\t});\n\t\t\t\texpect(param.getValueAtTime(0)).to.equal(1.1);\n\t\t\t\tparam.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"requires a param in the constructor\", () => {\n\t\t\texpect(() => {\n\t\t\t\tconst param = new Param({\n\t\t\t\t\tvalue: 1.1,\n\t\t\t\t});\n\t\t\t}).throws(Error);\n\t\t});\n\t});\n\n\tcontext(\"Scheduling Curves\", () => {\n\t\tconst sampleRate = 11025;\n\t\tfunction matchesOutputCurve(param, outBuffer): void {\n\t\t\toutBuffer.toArray()[0].forEach((sample, index) => {\n\t\t\t\ttry {\n\t\t\t\t\texpect(\n\t\t\t\t\t\tparam.getValueAtTime(index / sampleRate)\n\t\t\t\t\t).to.be.closeTo(sample, 0.1);\n\t\t\t\t} catch (e) {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tit(\"correctly handles setTargetAtTime followed by a ramp\", async () => {\n\t\t\tlet param;\n\t\t\t// this fails on FF\n\t\t\tconst testBuffer = await Offline(\n\t\t\t\t(context) => {\n\t\t\t\t\tconst source = context.createConstantSource();\n\t\t\t\t\tsource.connect(context.rawContext.destination);\n\t\t\t\t\tsource.start(0);\n\t\t\t\t\tparam = new Param({\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\tparam: source.offset,\n\t\t\t\t\t});\n\t\t\t\t\tparam.setTargetAtTime(2, 0.5, 0.1);\n\t\t\t\t\texpect(param.getValueAtTime(0.6)).to.be.closeTo(1.6, 0.1);\n\t\t\t\t\tparam.linearRampToValueAtTime(0.5, 0.7);\n\t\t\t\t\texpect(param.getValueAtTime(0.6)).to.be.closeTo(0.75, 0.1);\n\t\t\t\t},\n\t\t\t\t1.5,\n\t\t\t\t1,\n\t\t\t\tsampleRate\n\t\t\t);\n\t\t\tdocument.body.appendChild(await Plot.signal(testBuffer));\n\t\t\tmatchesOutputCurve(param, testBuffer);\n\t\t});\n\n\t\tit(\"schedules a value curve\", async () => {\n\t\t\tlet param;\n\t\t\tconst testBuffer = await Offline(\n\t\t\t\t(context) => {\n\t\t\t\t\tconst source = context.createConstantSource();\n\t\t\t\t\tsource.connect(context.rawContext.destination);\n\t\t\t\t\tsource.start(0);\n\t\t\t\t\tparam = new Param({\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\tparam: source.offset,\n\t\t\t\t\t\tunits: \"number\",\n\t\t\t\t\t\tvalue: 0,\n\t\t\t\t\t});\n\t\t\t\t\tparam.setValueCurveAtTime(\n\t\t\t\t\t\t[0, 0.5, 0, 1, 1.5],\n\t\t\t\t\t\t0.1,\n\t\t\t\t\t\t0.8,\n\t\t\t\t\t\t0.5\n\t\t\t\t\t);\n\t\t\t\t\texpect(param.getValueAtTime(0.91)).to.be.closeTo(\n\t\t\t\t\t\t0.75,\n\t\t\t\t\t\t0.01\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\t1,\n\t\t\t\t1,\n\t\t\t\tsampleRate\n\t\t\t);\n\t\t\tmatchesOutputCurve(param, testBuffer);\n\t\t});\n\n\t\tit(\"a mixture of scheduling curves\", async () => {\n\t\t\tlet param;\n\t\t\tconst testBuffer = await Offline(\n\t\t\t\t(context) => {\n\t\t\t\t\tconst source = context.createConstantSource();\n\t\t\t\t\tsource.connect(context.rawContext.destination);\n\t\t\t\t\tsource.start(0);\n\t\t\t\t\tparam = new Param({\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\tparam: source.offset,\n\t\t\t\t\t\tvalue: 0.1,\n\t\t\t\t\t});\n\t\t\t\t\tparam.setValueAtTime(0, 0);\n\t\t\t\t\tparam.setValueAtTime(1, 0.1);\n\t\t\t\t\tparam.linearRampToValueAtTime(3, 0.2);\n\t\t\t\t\tparam.exponentialRampToValueAtTime(0.01, 0.3);\n\t\t\t\t\tparam.setTargetAtTime(-1, 0.35, 0.2);\n\t\t\t\t\tparam.cancelAndHoldAtTime(0.6);\n\t\t\t\t\tparam.rampTo(1.1, 0.2, 0.7);\n\t\t\t\t\tparam.exponentialRampTo(0, 0.1, 0.85);\n\t\t\t\t\tparam.setValueAtTime(0, 1);\n\t\t\t\t\tparam.linearRampTo(1, 0.2, 1);\n\t\t\t\t\tparam.targetRampTo(0, 0.1, 1.1);\n\t\t\t\t\tparam.setValueAtTime(4, 1.2);\n\t\t\t\t\tparam.cancelScheduledValues(1.2);\n\t\t\t\t\tparam.linearRampToValueAtTime(1, 1.3);\n\t\t\t\t},\n\t\t\t\t1.5,\n\t\t\t\t1,\n\t\t\t\tsampleRate\n\t\t\t);\n\t\t\tmatchesOutputCurve(param, testBuffer);\n\t\t});\n\n\t\tit.skip(\"can cancel and hold\", async () => {\n\t\t\tlet param;\n\t\t\tconst testBuffer = await Offline(\n\t\t\t\t(context) => {\n\t\t\t\t\tconst source = context.createConstantSource();\n\t\t\t\t\tsource.connect(context.rawContext.destination);\n\t\t\t\t\tsource.start(0);\n\t\t\t\t\tparam = new Param({\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\tparam: source.offset,\n\t\t\t\t\t\tvalue: 0.1,\n\t\t\t\t\t});\n\t\t\t\t\tparam.setValueAtTime(0, 0);\n\t\t\t\t\tparam.setValueAtTime(1, 0.2);\n\t\t\t\t\tparam.cancelAndHoldAtTime(0.1);\n\t\t\t\t\tparam.linearRampToValueAtTime(1, 0.3);\n\t\t\t\t\tparam.cancelAndHoldAtTime(0.2);\n\t\t\t\t\texpect(param.getValueAtTime(0.2)).to.be.closeTo(0.5, 0.001);\n\t\t\t\t\tparam.exponentialRampToValueAtTime(0, 0.4);\n\t\t\t\t\tparam.cancelAndHoldAtTime(0.25);\n\t\t\t\t\texpect(param.getValueAtTime(0.25)).to.be.closeTo(\n\t\t\t\t\t\t0.033,\n\t\t\t\t\t\t0.001\n\t\t\t\t\t);\n\t\t\t\t\tparam.setTargetAtTime(1, 0.3, 0.1);\n\t\t\t\t\tparam.cancelAndHoldAtTime(0.4);\n\t\t\t\t\texpect(param.getValueAtTime(0.4)).to.be.closeTo(\n\t\t\t\t\t\t0.644,\n\t\t\t\t\t\t0.001\n\t\t\t\t\t);\n\t\t\t\t\tparam.setValueAtTime(0, 0.45);\n\t\t\t\t\tparam.setValueAtTime(1, 0.48);\n\t\t\t\t\tparam.cancelAndHoldAtTime(0.45);\n\t\t\t\t\texpect(param.getValueAtTime(0.45)).to.be.closeTo(0, 0.001);\n\t\t\t\t},\n\t\t\t\t0.5,\n\t\t\t\t1,\n\t\t\t\tsampleRate\n\t\t\t);\n\t\t\tmatchesOutputCurve(param, testBuffer);\n\t\t});\n\t});\n\n\tcontext(\"Units\", () => {\n\t\tit(\"throws an error with invalid values\", () => {\n\t\t\tconst osc = audioContext.createOscillator();\n\t\t\tconst param = new Param<\"frequency\">({\n\t\t\t\tcontext: audioContext,\n\t\t\t\tparam: osc.frequency,\n\t\t\t\tunits: \"frequency\",\n\t\t\t});\n\t\t\texpect(() => {\n\t\t\t\t// @ts-ignore\n\t\t\t\texpect(param.setValueAtTime(\"bad\", \"bad\"));\n\t\t\t}).to.throw(Error);\n\t\t\texpect(() => {\n\t\t\t\t// @ts-ignore\n\t\t\t\texpect(param.linearRampToValueAtTime(\"bad\", \"bad\"));\n\t\t\t}).to.throw(Error);\n\t\t\texpect(() => {\n\t\t\t\t// @ts-ignore\n\t\t\t\texpect(param.exponentialRampToValueAtTime(\"bad\", \"bad\"));\n\t\t\t}).to.throw(Error);\n\t\t\texpect(() => {\n\t\t\t\t// @ts-ignore\n\t\t\t\texpect(param.setTargetAtTime(\"bad\", \"bad\", 0.1));\n\t\t\t}).to.throw(Error);\n\t\t\texpect(() => {\n\t\t\t\t// @ts-ignore\n\t\t\t\texpect(param.cancelScheduledValues(\"bad\"));\n\t\t\t}).to.throw(Error);\n\t\t\tparam.dispose();\n\t\t});\n\n\t\tit(\"can be created with specific units\", () => {\n\t\t\tconst gain = audioContext.createGain();\n\t\t\tconst param = new Param<\"bpm\">({\n\t\t\t\tcontext: audioContext,\n\t\t\t\tparam: gain.gain,\n\t\t\t\tunits: \"bpm\",\n\t\t\t});\n\t\t\texpect(param.units).to.equal(\"bpm\");\n\t\t\tparam.dispose();\n\t\t});\n\n\t\tit(\"can evaluate the given units\", () => {\n\t\t\tconst gain = audioContext.createGain();\n\t\t\tconst param = new Param<\"decibels\">({\n\t\t\t\tcontext: audioContext,\n\t\t\t\tparam: gain.gain,\n\t\t\t\tunits: \"decibels\",\n\t\t\t});\n\t\t\tparam.value = 0.5;\n\t\t\texpect(param.value).to.be.closeTo(0.5, 0.001);\n\t\t\tparam.dispose();\n\t\t});\n\n\t\tit(\"can be forced to not convert\", async () => {\n\t\t\tconst testBuffer = await Offline(\n\t\t\t\t(context) => {\n\t\t\t\t\tconst source = context.createConstantSource();\n\t\t\t\t\tsource.connect(context.rawContext.destination);\n\t\t\t\t\tsource.start(0);\n\t\t\t\t\tconst param = new Param({\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\tconvert: false,\n\t\t\t\t\t\tparam: source.offset,\n\t\t\t\t\t\tunits: \"decibels\",\n\t\t\t\t\t});\n\t\t\t\t\tparam.value = -10;\n\t\t\t\t\texpect(param.value).to.be.closeTo(-10, 0.01);\n\t\t\t\t},\n\t\t\t\t0.001,\n\t\t\t\t1\n\t\t\t);\n\t\t\texpect(testBuffer.getValueAtTime(0)).to.be.closeTo(-10, 0.01);\n\t\t});\n\t});\n\n\tcontext(\"apply\", () => {\n\t\tit(\"can apply a scheduled curve\", async () => {\n\t\t\tlet sig;\n\t\t\tconst buffer = await Offline((context) => {\n\t\t\t\tconst signal = new Signal();\n\t\t\t\tsig = signal;\n\t\t\t\tsignal.setValueAtTime(0, 0);\n\t\t\t\tsignal.linearRampToValueAtTime(0.5, 0.1);\n\t\t\t\tsignal.exponentialRampToValueAtTime(0.2, 0.5);\n\t\t\t\tsignal.linearRampToValueAtTime(4, 2);\n\t\t\t\tsignal.cancelScheduledValues(1);\n\t\t\t\tsignal.setTargetAtTime(4, 1, 0.1);\n\t\t\t\tconst source = context.createConstantSource();\n\t\t\t\tsource.start(0);\n\t\t\t\tconnect(source, context.destination);\n\t\t\t\treturn atTime(0.4, () => {\n\t\t\t\t\tsignal.apply(source.offset);\n\t\t\t\t});\n\t\t\t}, 2);\n\t\t\tfor (let time = 0.41; time < 2; time += 0.1) {\n\t\t\t\texpect(buffer.getValueAtTime(time)).to.be.closeTo(\n\t\t\t\t\tsig.getValueAtTime(time),\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\n\t\tit(\"can apply a scheduled curve that starts with a setTargetAtTime\", async () => {\n\t\t\tlet sig;\n\t\t\tconst buffer = await Offline((context) => {\n\t\t\t\tconst signal = new Signal();\n\t\t\t\tsig = signal;\n\t\t\t\tsignal.setTargetAtTime(2, 0, 0.2);\n\t\t\t\tconst source = context.createConstantSource();\n\t\t\t\tsource.start(0);\n\t\t\t\tconnect(source, context.destination);\n\t\t\t\treturn atTime(0.4, () => {\n\t\t\t\t\tsignal.apply(source.offset);\n\t\t\t\t});\n\t\t\t}, 2);\n\t\t\tfor (let time = 0.41; time < 2; time += 0.1) {\n\t\t\t\texpect(buffer.getValueAtTime(time)).to.be.closeTo(\n\t\t\t\t\tsig.getValueAtTime(time),\n\t\t\t\t\t0.05\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\n\t\tit(\"can apply a scheduled curve that starts with a setTargetAtTime and then schedules other things\", async () => {\n\t\t\tlet sig;\n\t\t\tconst buffer = await Offline((context) => {\n\t\t\t\tconst signal = new Signal();\n\t\t\t\tsig = signal;\n\t\t\t\tsignal.setTargetAtTime(2, 0, 0.2);\n\t\t\t\tsignal.setValueAtTime(1, 0.8);\n\t\t\t\tsignal.linearRampToValueAtTime(0, 2);\n\t\t\t\tconst source = context.createConstantSource();\n\t\t\t\tsource.start(0);\n\t\t\t\tconnect(source, context.destination);\n\t\t\t\treturn atTime(0.4, () => {\n\t\t\t\t\tsignal.apply(source.offset);\n\t\t\t\t});\n\t\t\t}, 2);\n\t\t\tfor (let time = 0.41; time < 2; time += 0.1) {\n\t\t\t\texpect(buffer.getValueAtTime(time)).to.be.closeTo(\n\t\t\t\t\tsig.getValueAtTime(time),\n\t\t\t\t\t0.05\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\n\t\tit(\"can set the param if the Param is marked as swappable\", async () => {\n\t\t\tconst buffer = await Offline((context) => {\n\t\t\t\tconst constSource = context.createConstantSource();\n\t\t\t\tconst param = new Param({\n\t\t\t\t\tswappable: true,\n\t\t\t\t\tparam: constSource.offset,\n\t\t\t\t});\n\t\t\t\tparam.setValueAtTime(0.1, 0.1);\n\t\t\t\tparam.setValueAtTime(0.2, 0.2);\n\t\t\t\tparam.setValueAtTime(0.3, 0.3);\n\t\t\t\tconst constSource2 = context.createConstantSource();\n\t\t\t\tconstSource2.start(0);\n\t\t\t\tparam.setParam(constSource2.offset);\n\t\t\t\tconnect(constSource2, context.destination);\n\t\t\t}, 0.5);\n\t\t\texpect(buffer.getValueAtTime(0.1)).to.be.closeTo(0.1, 0.001);\n\t\t\texpect(buffer.getValueAtTime(0.2)).to.be.closeTo(0.2, 0.001);\n\t\t\texpect(buffer.getValueAtTime(0.3)).to.be.closeTo(0.3, 0.001);\n\t\t});\n\n\t\tit(\"throws an error if the param is not set to swappable\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst constSource = context.createConstantSource();\n\t\t\t\tconst param = new Param({\n\t\t\t\t\tparam: constSource.offset,\n\t\t\t\t});\n\t\t\t\tconst constSource2 = context.createConstantSource();\n\t\t\t\texpect(() => {\n\t\t\t\t\tparam.setParam(constSource2.offset);\n\t\t\t\t}).to.throw(Error);\n\t\t\t}, 0.5);\n\t\t});\n\t});\n\n\tcontext(\"Unit Conversions\", () => {\n\t\tfunction testUnitConversion(\n\t\t\tunits: UnitName,\n\t\t\tinputValue: any,\n\t\t\tinputVerification: number,\n\t\t\toutputValue: number\n\t\t): void {\n\t\t\tit(`converts to ${units}`, async () => {\n\t\t\t\tconst testBuffer = await Offline(\n\t\t\t\t\t(context) => {\n\t\t\t\t\t\tconst source = context.createConstantSource();\n\t\t\t\t\t\tsource.connect(context.rawContext.destination);\n\t\t\t\t\t\tsource.start(0);\n\t\t\t\t\t\tconst param = new Param({\n\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\tparam: source.offset,\n\t\t\t\t\t\t\tunits,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tparam.value = inputValue;\n\t\t\t\t\t\texpect(param.value).to.be.closeTo(\n\t\t\t\t\t\t\tinputVerification,\n\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t\t0.001,\n\t\t\t\t\t1\n\t\t\t\t);\n\t\t\t\texpect(testBuffer.getValueAtTime(0)).to.be.closeTo(\n\t\t\t\t\toutputValue,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\n\t\ttestUnitConversion(\"number\", 3, 3, 3);\n\t\ttestUnitConversion(\"decibels\", -10, -10, 0.31);\n\t\ttestUnitConversion(\"decibels\", -20, -20, 0.1);\n\t\ttestUnitConversion(\"decibels\", -100, -100, 0);\n\t\ttestUnitConversion(\"gain\", 1.2, 1.2, 1.2);\n\t\ttestUnitConversion(\"positive\", 1.5, 1.5, 1.5);\n\t\ttestUnitConversion(\"positive\", 0, 0, 0);\n\t\ttestUnitConversion(\"time\", 2, 2, 2);\n\t\ttestUnitConversion(\"time\", 0, 0, 0);\n\t\ttestUnitConversion(\"frequency\", 20, 20, 20);\n\t\ttestUnitConversion(\"frequency\", 0.1, 0.1, 0.1);\n\t\ttestUnitConversion(\"normalRange\", 0, 0, 0);\n\t\ttestUnitConversion(\"normalRange\", 0.5, 0.5, 0.5);\n\t\ttestUnitConversion(\"audioRange\", -1, -1, -1);\n\t\ttestUnitConversion(\"audioRange\", 0.5, 0.5, 0.5);\n\t\ttestUnitConversion(\"audioRange\", 1, 1, 1);\n\t});\n\n\tcontext(\"min/maxValue\", () => {\n\t\tfunction testMinMaxValue(units: UnitName, min, max): void {\n\t\t\tit(`has proper min/max for ${units}`, () => {\n\t\t\t\tconst source = audioContext.createConstantSource();\n\t\t\t\tsource.connect(audioContext.rawContext.destination);\n\t\t\t\tconst param = new Param({\n\t\t\t\t\tcontext: audioContext,\n\t\t\t\t\tparam: source.offset,\n\t\t\t\t\tunits,\n\t\t\t\t});\n\t\t\t\texpect(param.minValue).to.be.equal(min);\n\t\t\t\texpect(param.maxValue).to.be.equal(max);\n\t\t\t});\n\t\t}\n\t\t// number, decibels, normalRange, audioRange, gain\n\t\t// positive, time, frequency, transportTime, ticks, bpm, degrees, samples, hertz\n\t\tconst rangeMax = 3.4028234663852886e38;\n\t\ttestMinMaxValue(\"number\", -rangeMax, rangeMax);\n\t\ttestMinMaxValue(\"decibels\", -Infinity, rangeMax);\n\t\ttestMinMaxValue(\"normalRange\", 0, 1);\n\t\ttestMinMaxValue(\"audioRange\", -1, 1);\n\t\ttestMinMaxValue(\"gain\", -rangeMax, rangeMax);\n\t\ttestMinMaxValue(\"positive\", 0, rangeMax);\n\t\ttestMinMaxValue(\"time\", 0, rangeMax);\n\t\ttestMinMaxValue(\"frequency\", 0, rangeMax);\n\t\ttestMinMaxValue(\"transportTime\", 0, rangeMax);\n\t\ttestMinMaxValue(\"ticks\", 0, rangeMax);\n\t\ttestMinMaxValue(\"bpm\", 0, rangeMax);\n\t\ttestMinMaxValue(\"degrees\", -rangeMax, rangeMax);\n\t\ttestMinMaxValue(\"samples\", 0, rangeMax);\n\t\ttestMinMaxValue(\"hertz\", 0, rangeMax);\n\n\t\tit(\"can pass in a min and max value\", () => {\n\t\t\tconst source = audioContext.createConstantSource();\n\t\t\tsource.connect(audioContext.rawContext.destination);\n\t\t\tconst param = new Param({\n\t\t\t\tcontext: audioContext,\n\t\t\t\tparam: source.offset,\n\t\t\t\tminValue: 0.3,\n\t\t\t\tmaxValue: 0.5,\n\t\t\t});\n\t\t\texpect(param.minValue).to.be.equal(0.3);\n\t\t\texpect(param.maxValue).to.be.equal(0.5);\n\t\t});\n\t});\n\n\tcontext(\"defaultValue\", () => {\n\t\tit(\"has the right default value for default units\", () => {\n\t\t\tconst source = audioContext.createConstantSource();\n\t\t\tsource.connect(audioContext.rawContext.destination);\n\t\t\tconst param = new Param({\n\t\t\t\tcontext: audioContext,\n\t\t\t\tparam: source.offset,\n\t\t\t});\n\t\t\texpect(param.defaultValue).to.be.equal(1);\n\t\t});\n\n\t\tit(\"has the right default value for default decibels\", () => {\n\t\t\tconst source = audioContext.createConstantSource();\n\t\t\tsource.connect(audioContext.rawContext.destination);\n\t\t\tconst param = new Param({\n\t\t\t\tcontext: audioContext,\n\t\t\t\tparam: source.offset,\n\t\t\t\tunits: \"decibels\",\n\t\t\t});\n\t\t\texpect(param.defaultValue).to.be.equal(0);\n\t\t});\n\t});\n\n\t// const allSchedulingMethods = ['setValueAtTime', 'linearRampToValueAtTime', 'exponentialRampToValueAtTime']\n\n\tcontext(\"setValueAtTime\", () => {\n\t\tfunction testSetValueAtTime(\n\t\t\tunits: UnitName,\n\t\t\tvalue0: number,\n\t\t\tvalue1: number,\n\t\t\tvalue2: number\n\t\t): void {\n\t\t\tit(`can schedule value with units ${units}`, async () => {\n\t\t\t\tconst testBuffer = await Offline(\n\t\t\t\t\t(context) => {\n\t\t\t\t\t\tconst source = context.createConstantSource();\n\t\t\t\t\t\tsource.connect(context.rawContext.destination);\n\t\t\t\t\t\tsource.start(0);\n\t\t\t\t\t\tconst param = new Param({\n\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\tparam: source.offset,\n\t\t\t\t\t\t\tunits,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tparam.setValueAtTime(value0, 0);\n\t\t\t\t\t\tparam.setValueAtTime(value1, 0.01);\n\t\t\t\t\t\tparam.setValueAtTime(value2, 0.02);\n\n\t\t\t\t\t\texpect(param.getValueAtTime(0)).to.be.closeTo(\n\t\t\t\t\t\t\tvalue0,\n\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t);\n\t\t\t\t\t\texpect(param.getValueAtTime(0.01)).to.be.closeTo(\n\t\t\t\t\t\t\tvalue1,\n\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t);\n\t\t\t\t\t\texpect(param.getValueAtTime(0.02)).to.be.closeTo(\n\t\t\t\t\t\t\tvalue2,\n\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t\t0.022,\n\t\t\t\t\t1\n\t\t\t\t);\n\t\t\t\texpect(testBuffer.getValueAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\t\texpect(testBuffer.getValueAtTime(0.011)).to.be.closeTo(1, 0.01);\n\t\t\t\texpect(testBuffer.getValueAtTime(0.021)).to.be.closeTo(\n\t\t\t\t\t0.5,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\n\t\tconst allUnits: UnitName[] = [\n\t\t\t\"number\",\n\t\t\t\"decibels\",\n\t\t\t\"normalRange\",\n\t\t\t\"audioRange\",\n\t\t\t\"gain\",\n\t\t\t\"positive\",\n\t\t\t\"time\",\n\t\t\t\"frequency\",\n\t\t\t\"transportTime\",\n\t\t\t\"ticks\",\n\t\t\t\"bpm\",\n\t\t\t\"degrees\",\n\t\t\t\"samples\",\n\t\t\t\"hertz\",\n\t\t];\n\n\t\tallUnits.forEach((unit) => {\n\t\t\tif (unit === \"decibels\") {\n\t\t\t\ttestSetValueAtTime(unit, -100, 0, -6);\n\t\t\t} else {\n\t\t\t\ttestSetValueAtTime(unit, 0, 1, 0.5);\n\t\t\t}\n\t\t});\n\n\t\tit(\"asserts a value range\", async () => {\n\t\t\tlet errored = false;\n\t\t\ttry {\n\t\t\t\tconst source = new Gain();\n\t\t\t\tconst param = new Param({\n\t\t\t\t\tparam: source.gain,\n\t\t\t\t\tunits: \"normalRange\",\n\t\t\t\t});\n\t\t\t\tparam.setValueAtTime(2, 0);\n\t\t\t} catch (e) {\n\t\t\t\terrored = true;\n\t\t\t}\n\t\t});\n\t});\n\n\t[\"linearRampToValueAtTime\", \"exponentialRampToValueAtTime\"].forEach(\n\t\t(method) => {\n\t\t\tcontext(method, () => {\n\t\t\t\tfunction testRampToValueAtTime(\n\t\t\t\t\tunits: UnitName,\n\t\t\t\t\tvalue0: number,\n\t\t\t\t\tvalue1: number,\n\t\t\t\t\tvalue2: number\n\t\t\t\t): void {\n\t\t\t\t\tit(`can schedule value with units ${units}`, async () => {\n\t\t\t\t\t\tconst testBuffer = await Offline(\n\t\t\t\t\t\t\t(context) => {\n\t\t\t\t\t\t\t\tconst source = context.createConstantSource();\n\t\t\t\t\t\t\t\tsource.connect(context.rawContext.destination);\n\t\t\t\t\t\t\t\tsource.start(0);\n\t\t\t\t\t\t\t\tconst param = new Param({\n\t\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t\t\tparam: source.offset,\n\t\t\t\t\t\t\t\t\tunits,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tparam.setValueAtTime(value0, 0);\n\t\t\t\t\t\t\t\tparam[method](value1, 0.01);\n\t\t\t\t\t\t\t\tparam[method](value2, 0.02);\n\n\t\t\t\t\t\t\t\texpect(param.getValueAtTime(0)).to.be.closeTo(\n\t\t\t\t\t\t\t\t\tvalue0,\n\t\t\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\texpect(\n\t\t\t\t\t\t\t\t\tparam.getValueAtTime(0.01)\n\t\t\t\t\t\t\t\t).to.be.closeTo(value1, 0.01);\n\t\t\t\t\t\t\t\texpect(\n\t\t\t\t\t\t\t\t\tparam.getValueAtTime(0.02)\n\t\t\t\t\t\t\t\t).to.be.closeTo(value2, 0.01);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t0.022,\n\t\t\t\t\t\t\t1\n\t\t\t\t\t\t);\n\t\t\t\t\t\texpect(testBuffer.getValueAtTime(0)).to.be.closeTo(\n\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t);\n\t\t\t\t\t\texpect(testBuffer.getValueAtTime(0.01)).to.be.closeTo(\n\t\t\t\t\t\t\t0.7,\n\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t);\n\t\t\t\t\t\texpect(testBuffer.getValueAtTime(0.02)).to.be.closeTo(\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst allUnits: UnitName[] = [\n\t\t\t\t\t\"number\",\n\t\t\t\t\t\"decibels\",\n\t\t\t\t\t\"normalRange\",\n\t\t\t\t\t\"audioRange\",\n\t\t\t\t\t\"gain\",\n\t\t\t\t\t\"positive\",\n\t\t\t\t\t\"time\",\n\t\t\t\t\t\"frequency\",\n\t\t\t\t\t\"transportTime\",\n\t\t\t\t\t\"ticks\",\n\t\t\t\t\t\"bpm\",\n\t\t\t\t\t\"degrees\",\n\t\t\t\t\t\"samples\",\n\t\t\t\t\t\"hertz\",\n\t\t\t\t];\n\n\t\t\t\tallUnits.forEach((unit) => {\n\t\t\t\t\tif (unit === \"decibels\") {\n\t\t\t\t\t\ttestRampToValueAtTime(unit, 0, -3, -100);\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttestRampToValueAtTime(unit, 1, 0.7, 0);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t);\n\n\t[\"linearRampTo\", \"exponentialRampTo\", \"rampTo\", \"targetRampTo\"].forEach(\n\t\t(method) => {\n\t\t\tcontext(method, () => {\n\t\t\t\tfunction testRampToValueAtTime(\n\t\t\t\t\tunits: UnitName,\n\t\t\t\t\tvalue0: number,\n\t\t\t\t\tvalue1: number,\n\t\t\t\t\tvalue2: number\n\t\t\t\t): void {\n\t\t\t\t\tit(`can schedule value with units ${units}`, async () => {\n\t\t\t\t\t\tconst testBuffer = await Offline(\n\t\t\t\t\t\t\t(context) => {\n\t\t\t\t\t\t\t\tconst source = context.createConstantSource();\n\t\t\t\t\t\t\t\tsource.connect(context.rawContext.destination);\n\t\t\t\t\t\t\t\tsource.start(0);\n\t\t\t\t\t\t\t\tconst param = new Param({\n\t\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t\t\tparam: source.offset,\n\t\t\t\t\t\t\t\t\tunits,\n\t\t\t\t\t\t\t\t\tvalue: value0,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tparam[method](value1, 0.009, 0);\n\t\t\t\t\t\t\t\tparam[method](value2, 0.01, 0.01);\n\n\t\t\t\t\t\t\t\texpect(param.getValueAtTime(0)).to.be.closeTo(\n\t\t\t\t\t\t\t\t\tvalue0,\n\t\t\t\t\t\t\t\t\t0.02\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\texpect(\n\t\t\t\t\t\t\t\t\tparam.getValueAtTime(0.01)\n\t\t\t\t\t\t\t\t).to.be.closeTo(value1, 0.02);\n\t\t\t\t\t\t\t\tif (units !== \"decibels\") {\n\t\t\t\t\t\t\t\t\texpect(\n\t\t\t\t\t\t\t\t\t\tparam.getValueAtTime(0.025)\n\t\t\t\t\t\t\t\t\t).to.be.closeTo(value2, 0.01);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t0.021,\n\t\t\t\t\t\t\t1\n\t\t\t\t\t\t);\n\t\t\t\t\t\t// document.body.appendChild(await Plot.signal(testBuffer));\n\t\t\t\t\t\texpect(testBuffer.getValueAtTime(0)).to.be.closeTo(\n\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t);\n\t\t\t\t\t\texpect(testBuffer.getValueAtTime(0.01)).to.be.closeTo(\n\t\t\t\t\t\t\t0.7,\n\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t);\n\t\t\t\t\t\texpect(testBuffer.getValueAtTime(0.02)).to.be.closeTo(\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst allUnits: UnitName[] = [\n\t\t\t\t\t\"number\",\n\t\t\t\t\t\"decibels\",\n\t\t\t\t\t\"normalRange\",\n\t\t\t\t\t\"audioRange\",\n\t\t\t\t\t\"gain\",\n\t\t\t\t\t\"positive\",\n\t\t\t\t\t\"time\",\n\t\t\t\t\t\"frequency\",\n\t\t\t\t\t\"transportTime\",\n\t\t\t\t\t\"ticks\",\n\t\t\t\t\t\"bpm\",\n\t\t\t\t\t\"degrees\",\n\t\t\t\t\t\"samples\",\n\t\t\t\t\t\"hertz\",\n\t\t\t\t];\n\n\t\t\t\tallUnits.forEach((unit) => {\n\t\t\t\t\tif (unit === \"decibels\") {\n\t\t\t\t\t\ttestRampToValueAtTime(unit, 0, -3, -100);\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttestRampToValueAtTime(unit, 1, 0.7, 0);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t);\n});\n"
  },
  {
    "path": "Tone/core/context/Param.ts",
    "content": "import { AbstractParam } from \"../context/AbstractParam.js\";\nimport { dbToGain, gainToDb } from \"../type/Conversions.js\";\nimport {\n\tDecibels,\n\tFrequency,\n\tPositive,\n\tTime,\n\tUnitMap,\n\tUnitName,\n} from \"../type/Units.js\";\nimport { isAudioParam } from \"../util/AdvancedTypeCheck.js\";\nimport { assert, assertRange } from \"../util/Debug.js\";\nimport { optionsFromArguments } from \"../util/Defaults.js\";\nimport { EQ } from \"../util/Math.js\";\nimport { Timeline } from \"../util/Timeline.js\";\nimport { isDefined } from \"../util/TypeCheck.js\";\nimport { ToneWithContext, ToneWithContextOptions } from \"./ToneWithContext.js\";\n\nexport interface ParamOptions<TypeName extends UnitName>\n\textends ToneWithContextOptions {\n\tunits: TypeName;\n\tvalue?: UnitMap[TypeName];\n\tparam: AudioParam | Param<TypeName>;\n\tconvert: boolean;\n\tminValue?: number;\n\tmaxValue?: number;\n\tswappable?: boolean;\n}\n\n/**\n * the possible automation types\n */\ntype AutomationType =\n\t| \"linearRampToValueAtTime\"\n\t| \"exponentialRampToValueAtTime\"\n\t| \"setValueAtTime\"\n\t| \"setTargetAtTime\"\n\t| \"cancelScheduledValues\";\n\ninterface TargetAutomationEvent {\n\ttype: \"setTargetAtTime\";\n\ttime: number;\n\tvalue: number;\n\tconstant: number;\n}\n\ninterface NormalAutomationEvent {\n\ttype: Exclude<AutomationType, \"setTargetAtTime\">;\n\ttime: number;\n\tvalue: number;\n}\n/**\n * The events on the automation\n */\nexport type AutomationEvent = NormalAutomationEvent | TargetAutomationEvent;\n\n/**\n * Param wraps the native Web Audio's AudioParam to provide\n * additional unit conversion functionality. It also\n * serves as a base-class for classes which have a single,\n * automatable parameter.\n * @category Core\n */\nexport class Param<TypeName extends UnitName = \"number\">\n\textends ToneWithContext<ParamOptions<TypeName>>\n\timplements AbstractParam<TypeName>\n{\n\treadonly name: string = \"Param\";\n\n\treadonly input: GainNode | AudioParam;\n\n\treadonly units: UnitName;\n\tconvert: boolean;\n\toverridden = false;\n\n\t/**\n\t * The timeline which tracks all of the automations.\n\t */\n\tprotected _events: Timeline<AutomationEvent>;\n\n\t/**\n\t * The native parameter to control\n\t */\n\tprotected _param: AudioParam;\n\n\t/**\n\t * The default value before anything is assigned\n\t */\n\tprotected _initialValue: number;\n\n\t/**\n\t * The minimum output value\n\t */\n\tprivate _minOutput = 1e-7;\n\n\t/**\n\t * Private reference to the min and max values if passed into the constructor\n\t */\n\tprivate readonly _minValue?: number;\n\tprivate readonly _maxValue?: number;\n\n\t/**\n\t * If the underlying AudioParam can be swapped out\n\t * using the setParam method.\n\t */\n\tprotected readonly _swappable: boolean;\n\n\t/**\n\t * @param param The AudioParam to wrap\n\t * @param units The unit name\n\t * @param convert Whether or not to convert the value to the target units\n\t */\n\tconstructor(param: AudioParam, units?: TypeName, convert?: boolean);\n\tconstructor(options: Partial<ParamOptions<TypeName>>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Param.getDefaults(), arguments, [\n\t\t\t\"param\",\n\t\t\t\"units\",\n\t\t\t\"convert\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tassert(\n\t\t\tisDefined(options.param) &&\n\t\t\t\t(isAudioParam(options.param) || options.param instanceof Param),\n\t\t\t\"param must be an AudioParam\"\n\t\t);\n\n\t\twhile (!isAudioParam(options.param)) {\n\t\t\toptions.param = options.param._param;\n\t\t}\n\n\t\tthis._swappable = isDefined(options.swappable)\n\t\t\t? options.swappable\n\t\t\t: false;\n\t\tif (this._swappable) {\n\t\t\tthis.input = this.context.createGain();\n\t\t\t// initialize\n\t\t\tthis._param = options.param;\n\t\t\tthis.input.connect(this._param);\n\t\t} else {\n\t\t\tthis._param = this.input = options.param;\n\t\t}\n\t\tthis._events = new Timeline<AutomationEvent>(1000);\n\t\tthis._initialValue = this._param.defaultValue;\n\t\tthis.units = options.units;\n\t\tthis.convert = options.convert;\n\t\tthis._minValue = options.minValue;\n\t\tthis._maxValue = options.maxValue;\n\n\t\t// if the value is defined, set it immediately\n\t\tif (\n\t\t\tisDefined(options.value) &&\n\t\t\toptions.value !== this._toType(this._initialValue)\n\t\t) {\n\t\t\tthis.setValueAtTime(options.value, 0);\n\t\t}\n\t}\n\n\tstatic getDefaults(): ParamOptions<any> {\n\t\treturn Object.assign(ToneWithContext.getDefaults(), {\n\t\t\tconvert: true,\n\t\t\tunits: \"number\" as UnitName,\n\t\t} as ParamOptions<any>);\n\t}\n\n\tget value(): UnitMap[TypeName] {\n\t\tconst now = this.now();\n\t\treturn this.getValueAtTime(now);\n\t}\n\tset value(value) {\n\t\tthis.cancelScheduledValues(this.now());\n\t\tthis.setValueAtTime(value, this.now());\n\t}\n\n\tget minValue(): number {\n\t\t// if it's not the default minValue, return it\n\t\tif (isDefined(this._minValue)) {\n\t\t\treturn this._minValue;\n\t\t} else if (\n\t\t\tthis.units === \"time\" ||\n\t\t\tthis.units === \"frequency\" ||\n\t\t\tthis.units === \"normalRange\" ||\n\t\t\tthis.units === \"positive\" ||\n\t\t\tthis.units === \"transportTime\" ||\n\t\t\tthis.units === \"ticks\" ||\n\t\t\tthis.units === \"bpm\" ||\n\t\t\tthis.units === \"hertz\" ||\n\t\t\tthis.units === \"samples\"\n\t\t) {\n\t\t\treturn 0;\n\t\t} else if (this.units === \"audioRange\") {\n\t\t\treturn -1;\n\t\t} else if (this.units === \"decibels\") {\n\t\t\treturn -Infinity;\n\t\t} else {\n\t\t\treturn this._param.minValue;\n\t\t}\n\t}\n\n\tget maxValue(): number {\n\t\tif (isDefined(this._maxValue)) {\n\t\t\treturn this._maxValue;\n\t\t} else if (\n\t\t\tthis.units === \"normalRange\" ||\n\t\t\tthis.units === \"audioRange\"\n\t\t) {\n\t\t\treturn 1;\n\t\t} else {\n\t\t\treturn this._param.maxValue;\n\t\t}\n\t}\n\n\t/**\n\t * Type guard based on the unit name\n\t */\n\tprivate _is<T>(arg: any, type: UnitName): arg is T {\n\t\treturn this.units === type;\n\t}\n\n\t/**\n\t * Make sure the value is always in the defined range\n\t */\n\tprivate _assertRange(value: number): number {\n\t\tif (isDefined(this.maxValue) && isDefined(this.minValue)) {\n\t\t\tassertRange(\n\t\t\t\tvalue,\n\t\t\t\tthis._fromType(this.minValue),\n\t\t\t\tthis._fromType(this.maxValue)\n\t\t\t);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Convert the given value from the type specified by Param.units\n\t * into the destination value (such as Gain or Frequency).\n\t */\n\tprotected _fromType(val: UnitMap[TypeName]): number {\n\t\tif (this.convert && !this.overridden) {\n\t\t\tif (this._is<Time>(val, \"time\")) {\n\t\t\t\treturn this.toSeconds(val);\n\t\t\t} else if (this._is<Decibels>(val, \"decibels\")) {\n\t\t\t\treturn dbToGain(val);\n\t\t\t} else if (this._is<Frequency>(val, \"frequency\")) {\n\t\t\t\treturn this.toFrequency(val);\n\t\t\t} else {\n\t\t\t\treturn val as number;\n\t\t\t}\n\t\t} else if (this.overridden) {\n\t\t\t// if it's overridden, should only schedule 0s\n\t\t\treturn 0;\n\t\t} else {\n\t\t\treturn val as number;\n\t\t}\n\t}\n\n\t/**\n\t * Convert the parameters value into the units specified by Param.units.\n\t */\n\tprotected _toType(val: number): UnitMap[TypeName] {\n\t\tif (this.convert && this.units === \"decibels\") {\n\t\t\treturn gainToDb(val) as UnitMap[TypeName];\n\t\t} else {\n\t\t\treturn val as UnitMap[TypeName];\n\t\t}\n\t}\n\n\t//-------------------------------------\n\t// ABSTRACT PARAM INTERFACE\n\t// all docs are generated from ParamInterface.ts\n\t//-------------------------------------\n\n\tsetValueAtTime(value: UnitMap[TypeName], time: Time): this {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tconst numericValue = this._fromType(value);\n\t\tassert(\n\t\t\tisFinite(numericValue) && isFinite(computedTime),\n\t\t\t`Invalid argument(s) to setValueAtTime: ${JSON.stringify(value)}, ${JSON.stringify(time)}`\n\t\t);\n\t\tthis._assertRange(numericValue);\n\t\tthis.log(this.units, \"setValueAtTime\", value, computedTime);\n\t\tthis._events.add({\n\t\t\ttime: computedTime,\n\t\t\ttype: \"setValueAtTime\",\n\t\t\tvalue: numericValue,\n\t\t});\n\t\tthis._param.setValueAtTime(numericValue, computedTime);\n\t\treturn this;\n\t}\n\n\tgetValueAtTime(time: Time): UnitMap[TypeName] {\n\t\tconst computedTime = Math.max(this.toSeconds(time), 0);\n\t\tconst after = this._events.getAfter(computedTime);\n\t\tconst before = this._events.get(computedTime);\n\t\tlet value = this._initialValue;\n\t\t// if it was set by\n\t\tif (before === null) {\n\t\t\tvalue = this._initialValue;\n\t\t} else if (\n\t\t\tbefore.type === \"setTargetAtTime\" &&\n\t\t\t(after === null || after.type === \"setValueAtTime\")\n\t\t) {\n\t\t\tconst previous = this._events.getBefore(before.time);\n\t\t\tlet previousVal;\n\t\t\tif (previous === null) {\n\t\t\t\tpreviousVal = this._initialValue;\n\t\t\t} else {\n\t\t\t\tpreviousVal = previous.value;\n\t\t\t}\n\t\t\tif (before.type === \"setTargetAtTime\") {\n\t\t\t\tvalue = this._exponentialApproach(\n\t\t\t\t\tbefore.time,\n\t\t\t\t\tpreviousVal,\n\t\t\t\t\tbefore.value,\n\t\t\t\t\tbefore.constant,\n\t\t\t\t\tcomputedTime\n\t\t\t\t);\n\t\t\t}\n\t\t} else if (after === null) {\n\t\t\tvalue = before.value;\n\t\t} else if (\n\t\t\tafter.type === \"linearRampToValueAtTime\" ||\n\t\t\tafter.type === \"exponentialRampToValueAtTime\"\n\t\t) {\n\t\t\tlet beforeValue = before.value;\n\t\t\tif (before.type === \"setTargetAtTime\") {\n\t\t\t\tconst previous = this._events.getBefore(before.time);\n\t\t\t\tif (previous === null) {\n\t\t\t\t\tbeforeValue = this._initialValue;\n\t\t\t\t} else {\n\t\t\t\t\tbeforeValue = previous.value;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (after.type === \"linearRampToValueAtTime\") {\n\t\t\t\tvalue = this._linearInterpolate(\n\t\t\t\t\tbefore.time,\n\t\t\t\t\tbeforeValue,\n\t\t\t\t\tafter.time,\n\t\t\t\t\tafter.value,\n\t\t\t\t\tcomputedTime\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tvalue = this._exponentialInterpolate(\n\t\t\t\t\tbefore.time,\n\t\t\t\t\tbeforeValue,\n\t\t\t\t\tafter.time,\n\t\t\t\t\tafter.value,\n\t\t\t\t\tcomputedTime\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\tvalue = before.value;\n\t\t}\n\t\treturn this._toType(value);\n\t}\n\n\tsetRampPoint(time: Time): this {\n\t\ttime = this.toSeconds(time);\n\t\tlet currentVal = this.getValueAtTime(time);\n\t\tthis.cancelAndHoldAtTime(time);\n\t\tif (this._fromType(currentVal) === 0) {\n\t\t\tcurrentVal = this._toType(this._minOutput);\n\t\t}\n\t\tthis.setValueAtTime(currentVal, time);\n\t\treturn this;\n\t}\n\n\tlinearRampToValueAtTime(value: UnitMap[TypeName], endTime: Time): this {\n\t\tconst numericValue = this._fromType(value);\n\t\tconst computedTime = this.toSeconds(endTime);\n\t\tassert(\n\t\t\tisFinite(numericValue) && isFinite(computedTime),\n\t\t\t`Invalid argument(s) to linearRampToValueAtTime: ${JSON.stringify(value)}, ${JSON.stringify(endTime)}`\n\t\t);\n\t\tthis._assertRange(numericValue);\n\t\tthis._events.add({\n\t\t\ttime: computedTime,\n\t\t\ttype: \"linearRampToValueAtTime\",\n\t\t\tvalue: numericValue,\n\t\t});\n\t\tthis.log(this.units, \"linearRampToValueAtTime\", value, computedTime);\n\t\tthis._param.linearRampToValueAtTime(numericValue, computedTime);\n\t\treturn this;\n\t}\n\n\texponentialRampToValueAtTime(\n\t\tvalue: UnitMap[TypeName],\n\t\tendTime: Time\n\t): this {\n\t\tlet numericValue = this._fromType(value);\n\t\t// the value can't be 0\n\t\tnumericValue = EQ(numericValue, 0) ? this._minOutput : numericValue;\n\t\tthis._assertRange(numericValue);\n\t\tconst computedTime = this.toSeconds(endTime);\n\t\tassert(\n\t\t\tisFinite(numericValue) && isFinite(computedTime),\n\t\t\t`Invalid argument(s) to exponentialRampToValueAtTime: ${JSON.stringify(value)}, ${JSON.stringify(endTime)}`\n\t\t);\n\t\t// store the event\n\t\tthis._events.add({\n\t\t\ttime: computedTime,\n\t\t\ttype: \"exponentialRampToValueAtTime\",\n\t\t\tvalue: numericValue,\n\t\t});\n\t\tthis.log(\n\t\t\tthis.units,\n\t\t\t\"exponentialRampToValueAtTime\",\n\t\t\tvalue,\n\t\t\tcomputedTime\n\t\t);\n\t\tthis._param.exponentialRampToValueAtTime(numericValue, computedTime);\n\t\treturn this;\n\t}\n\n\texponentialRampTo(\n\t\tvalue: UnitMap[TypeName],\n\t\trampTime: Time,\n\t\tstartTime?: Time\n\t): this {\n\t\tstartTime = this.toSeconds(startTime);\n\t\tthis.setRampPoint(startTime);\n\t\tthis.exponentialRampToValueAtTime(\n\t\t\tvalue,\n\t\t\tstartTime + this.toSeconds(rampTime)\n\t\t);\n\t\treturn this;\n\t}\n\n\tlinearRampTo(\n\t\tvalue: UnitMap[TypeName],\n\t\trampTime: Time,\n\t\tstartTime?: Time\n\t): this {\n\t\tstartTime = this.toSeconds(startTime);\n\t\tthis.setRampPoint(startTime);\n\t\tthis.linearRampToValueAtTime(\n\t\t\tvalue,\n\t\t\tstartTime + this.toSeconds(rampTime)\n\t\t);\n\t\treturn this;\n\t}\n\n\ttargetRampTo(\n\t\tvalue: UnitMap[TypeName],\n\t\trampTime: Time,\n\t\tstartTime?: Time\n\t): this {\n\t\tstartTime = this.toSeconds(startTime);\n\t\tthis.setRampPoint(startTime);\n\t\tthis.exponentialApproachValueAtTime(value, startTime, rampTime);\n\t\treturn this;\n\t}\n\n\texponentialApproachValueAtTime(\n\t\tvalue: UnitMap[TypeName],\n\t\ttime: Time,\n\t\trampTime: Time\n\t): this {\n\t\ttime = this.toSeconds(time);\n\t\trampTime = this.toSeconds(rampTime);\n\t\tconst timeConstant = Math.log(rampTime + 1) / Math.log(200);\n\t\tthis.setTargetAtTime(value, time, timeConstant);\n\t\t// at 90% start a linear ramp to the final value\n\t\tthis.cancelAndHoldAtTime(time + rampTime * 0.9);\n\t\tthis.linearRampToValueAtTime(value, time + rampTime);\n\t\treturn this;\n\t}\n\n\tsetTargetAtTime(\n\t\tvalue: UnitMap[TypeName],\n\t\tstartTime: Time,\n\t\ttimeConstant: Positive\n\t): this {\n\t\tconst numericValue = this._fromType(value);\n\t\t// The value will never be able to approach without timeConstant > 0.\n\t\tassert(\n\t\t\tisFinite(timeConstant) && timeConstant > 0,\n\t\t\t\"timeConstant must be a number greater than 0\"\n\t\t);\n\t\tconst computedTime = this.toSeconds(startTime);\n\t\tthis._assertRange(numericValue);\n\t\tassert(\n\t\t\tisFinite(numericValue) && isFinite(computedTime),\n\t\t\t`Invalid argument(s) to setTargetAtTime: ${JSON.stringify(value)}, ${JSON.stringify(startTime)}`\n\t\t);\n\t\tthis._events.add({\n\t\t\tconstant: timeConstant,\n\t\t\ttime: computedTime,\n\t\t\ttype: \"setTargetAtTime\",\n\t\t\tvalue: numericValue,\n\t\t});\n\t\tthis.log(\n\t\t\tthis.units,\n\t\t\t\"setTargetAtTime\",\n\t\t\tvalue,\n\t\t\tcomputedTime,\n\t\t\ttimeConstant\n\t\t);\n\t\tthis._param.setTargetAtTime(numericValue, computedTime, timeConstant);\n\t\treturn this;\n\t}\n\n\tsetValueCurveAtTime(\n\t\tvalues: UnitMap[TypeName][],\n\t\tstartTime: Time,\n\t\tduration: Time,\n\t\tscaling = 1\n\t): this {\n\t\tduration = this.toSeconds(duration);\n\t\tstartTime = this.toSeconds(startTime);\n\t\tconst startingValue = this._fromType(values[0]) * scaling;\n\t\tthis.setValueAtTime(this._toType(startingValue), startTime);\n\t\tconst segTime = duration / (values.length - 1);\n\t\tfor (let i = 1; i < values.length; i++) {\n\t\t\tconst numericValue = this._fromType(values[i]) * scaling;\n\t\t\tthis.linearRampToValueAtTime(\n\t\t\t\tthis._toType(numericValue),\n\t\t\t\tstartTime + i * segTime\n\t\t\t);\n\t\t}\n\t\treturn this;\n\t}\n\n\tcancelScheduledValues(time: Time): this {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tassert(\n\t\t\tisFinite(computedTime),\n\t\t\t`Invalid argument to cancelScheduledValues: ${JSON.stringify(time)}`\n\t\t);\n\t\tthis._events.cancel(computedTime);\n\t\tthis._param.cancelScheduledValues(computedTime);\n\t\tthis.log(this.units, \"cancelScheduledValues\", computedTime);\n\t\treturn this;\n\t}\n\n\tcancelAndHoldAtTime(time: Time): this {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tconst valueAtTime = this._fromType(this.getValueAtTime(computedTime));\n\t\t// remove the schedule events\n\t\tassert(\n\t\t\tisFinite(computedTime),\n\t\t\t`Invalid argument to cancelAndHoldAtTime: ${JSON.stringify(time)}`\n\t\t);\n\n\t\tthis.log(\n\t\t\tthis.units,\n\t\t\t\"cancelAndHoldAtTime\",\n\t\t\tcomputedTime,\n\t\t\t\"value=\" + valueAtTime\n\t\t);\n\n\t\t// if there is an event at the given computedTime\n\t\t// and that even is not a \"set\"\n\t\tconst before = this._events.get(computedTime);\n\t\tconst after = this._events.getAfter(computedTime);\n\t\tif (before && EQ(before.time, computedTime)) {\n\t\t\t// remove everything after\n\t\t\tif (after) {\n\t\t\t\tthis._param.cancelScheduledValues(after.time);\n\t\t\t\tthis._events.cancel(after.time);\n\t\t\t} else {\n\t\t\t\tthis._param.cancelAndHoldAtTime(computedTime);\n\t\t\t\tthis._events.cancel(computedTime + this.sampleTime);\n\t\t\t}\n\t\t} else if (after) {\n\t\t\tthis._param.cancelScheduledValues(after.time);\n\t\t\t// cancel the next event(s)\n\t\t\tthis._events.cancel(after.time);\n\t\t\tif (after.type === \"linearRampToValueAtTime\") {\n\t\t\t\tthis.linearRampToValueAtTime(\n\t\t\t\t\tthis._toType(valueAtTime),\n\t\t\t\t\tcomputedTime\n\t\t\t\t);\n\t\t\t} else if (after.type === \"exponentialRampToValueAtTime\") {\n\t\t\t\tthis.exponentialRampToValueAtTime(\n\t\t\t\t\tthis._toType(valueAtTime),\n\t\t\t\t\tcomputedTime\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// set the value at the given time\n\t\tthis._events.add({\n\t\t\ttime: computedTime,\n\t\t\ttype: \"setValueAtTime\",\n\t\t\tvalue: valueAtTime,\n\t\t});\n\t\tthis._param.setValueAtTime(valueAtTime, computedTime);\n\t\treturn this;\n\t}\n\n\trampTo(\n\t\tvalue: UnitMap[TypeName],\n\t\trampTime: Time = 0.1,\n\t\tstartTime?: Time\n\t): this {\n\t\tif (\n\t\t\tthis.units === \"frequency\" ||\n\t\t\tthis.units === \"bpm\" ||\n\t\t\tthis.units === \"decibels\"\n\t\t) {\n\t\t\tthis.exponentialRampTo(value, rampTime, startTime);\n\t\t} else {\n\t\t\tthis.linearRampTo(value, rampTime, startTime);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Apply all of the previously scheduled events to the passed in Param or AudioParam.\n\t * The applied values will start at the context's current time and schedule\n\t * all of the events which are scheduled on this Param onto the passed in param.\n\t */\n\tapply(param: Param | AudioParam): this {\n\t\tconst now = this.context.currentTime;\n\t\t// set the param's value at the current time and schedule everything else\n\t\tparam.setValueAtTime(this.getValueAtTime(now) as number, now);\n\t\t// if the previous event was a curve, then set the rest of it\n\t\tconst previousEvent = this._events.get(now);\n\t\tif (previousEvent && previousEvent.type === \"setTargetAtTime\") {\n\t\t\t// approx it until the next event with linear ramps\n\t\t\tconst nextEvent = this._events.getAfter(previousEvent.time);\n\t\t\t// or for 2 seconds if there is no event\n\t\t\tconst endTime = nextEvent ? nextEvent.time : now + 2;\n\t\t\tconst subdivisions = (endTime - now) / 10;\n\t\t\tfor (let i = now; i < endTime; i += subdivisions) {\n\t\t\t\tparam.linearRampToValueAtTime(\n\t\t\t\t\tthis.getValueAtTime(i) as number,\n\t\t\t\t\ti\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tthis._events.forEachAfter(this.context.currentTime, (event) => {\n\t\t\tif (event.type === \"cancelScheduledValues\") {\n\t\t\t\tparam.cancelScheduledValues(event.time);\n\t\t\t} else if (event.type === \"setTargetAtTime\") {\n\t\t\t\tparam.setTargetAtTime(event.value, event.time, event.constant);\n\t\t\t} else {\n\t\t\t\tparam[event.type](event.value, event.time);\n\t\t\t}\n\t\t});\n\t\treturn this;\n\t}\n\n\t/**\n\t * Replace the Param's internal AudioParam. Will apply scheduled curves\n\t * onto the parameter and replace the connections.\n\t */\n\tsetParam(param: AudioParam): this {\n\t\tassert(\n\t\t\tthis._swappable,\n\t\t\t\"The Param must be assigned as 'swappable' in the constructor\"\n\t\t);\n\t\tconst input = this.input as GainNode;\n\t\tinput.disconnect(this._param);\n\t\tthis.apply(param);\n\t\tthis._param = param;\n\t\tinput.connect(this._param);\n\t\treturn this;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._events.dispose();\n\t\treturn this;\n\t}\n\n\tget defaultValue(): UnitMap[TypeName] {\n\t\treturn this._toType(this._param.defaultValue);\n\t}\n\n\t//-------------------------------------\n\t// \tAUTOMATION CURVE CALCULATIONS\n\t// \tMIT License, copyright (c) 2014 Jordan Santell\n\t//-------------------------------------\n\n\t// Calculates the the value along the curve produced by setTargetAtTime\n\tprotected _exponentialApproach(\n\t\tt0: number,\n\t\tv0: number,\n\t\tv1: number,\n\t\ttimeConstant: number,\n\t\tt: number\n\t): number {\n\t\treturn v1 + (v0 - v1) * Math.exp(-(t - t0) / timeConstant);\n\t}\n\n\t// Calculates the the value along the curve produced by linearRampToValueAtTime\n\tprotected _linearInterpolate(\n\t\tt0: number,\n\t\tv0: number,\n\t\tt1: number,\n\t\tv1: number,\n\t\tt: number\n\t): number {\n\t\treturn v0 + (v1 - v0) * ((t - t0) / (t1 - t0));\n\t}\n\n\t// Calculates the the value along the curve produced by exponentialRampToValueAtTime\n\tprotected _exponentialInterpolate(\n\t\tt0: number,\n\t\tv0: number,\n\t\tt1: number,\n\t\tv1: number,\n\t\tt: number\n\t): number {\n\t\treturn v0 * Math.pow(v1 / v0, (t - t0) / (t1 - t0));\n\t}\n}\n"
  },
  {
    "path": "Tone/core/context/ToneAudioBuffer.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { getContext } from \"../Global.js\";\nimport { ToneAudioBuffer } from \"./ToneAudioBuffer.js\";\n\nconst testFile = \"./test/audio/sine.wav\";\n\ndescribe(\"ToneAudioBuffer\", () => {\n\tcontext(\"basic\", () => {\n\t\tit(\"can be created and disposed\", () => {\n\t\t\tconst buff = new ToneAudioBuffer(testFile);\n\t\t\tbuff.dispose();\n\t\t});\n\n\t\tit(\"loads a file from a url string\", (done) => {\n\t\t\tconst buffer = new ToneAudioBuffer(testFile, (buff) => {\n\t\t\t\texpect(buff).to.be.instanceof(ToneAudioBuffer);\n\t\t\t\tbuffer.dispose();\n\t\t\t\tdone();\n\t\t\t});\n\t\t});\n\n\t\tit(\"has a duration\", (done) => {\n\t\t\tconst buffer = new ToneAudioBuffer(testFile, () => {\n\t\t\t\texpect(buffer.duration).to.be.closeTo(3, 0.01);\n\t\t\t\tbuffer.dispose();\n\t\t\t\tdone();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can be constructed with no arguments\", () => {\n\t\t\tconst buffer = new ToneAudioBuffer();\n\t\t\texpect(buffer.length).to.equal(0);\n\t\t\texpect(buffer.duration).to.equal(0);\n\t\t\texpect(buffer.numberOfChannels).to.equal(0);\n\t\t\tbuffer.dispose();\n\t\t});\n\n\t\tit(\"can get the number of channels\", (done) => {\n\t\t\tconst buffer = new ToneAudioBuffer(testFile, () => {\n\t\t\t\texpect(buffer.numberOfChannels).to.be.equal(1);\n\t\t\t\tbuffer.dispose();\n\t\t\t\tdone();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get the length of the buffer\", (done) => {\n\t\t\tconst buffer = new ToneAudioBuffer(testFile, () => {\n\t\t\t\texpect(buffer.length).to.be.a(\"number\");\n\t\t\t\texpect(buffer.length).to.be.above(130000);\n\t\t\t\tbuffer.dispose();\n\t\t\t\tdone();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can be constructed with an options object\", (done) => {\n\t\t\tconst buffer = new ToneAudioBuffer({\n\t\t\t\tonload: () => {\n\t\t\t\t\tbuffer.dispose();\n\t\t\t\t\tdone();\n\t\t\t\t},\n\t\t\t\treverse: true,\n\t\t\t\turl: testFile,\n\t\t\t});\n\t\t\texpect(buffer.reverse).to.equal(true);\n\t\t});\n\n\t\tit(\"takes an AudioBuffer in the constructor method\", async () => {\n\t\t\tconst audioBuffer = await ToneAudioBuffer.load(testFile);\n\t\t\tconst buffer = new ToneAudioBuffer({\n\t\t\t\turl: audioBuffer,\n\t\t\t});\n\t\t\tconst testOne = new ToneAudioBuffer(buffer.get());\n\t\t\texpect(testOne.get()).to.equal(buffer.get());\n\t\t\ttestOne.dispose();\n\t\t\tbuffer.dispose();\n\t\t});\n\n\t\tit(\"takes a loaded ToneAudioBuffer in the constructor method\", async () => {\n\t\t\tconst audioBuffer = await ToneAudioBuffer.fromUrl(testFile);\n\t\t\tconst buffer = new ToneAudioBuffer({\n\t\t\t\turl: audioBuffer,\n\t\t\t});\n\t\t\tconst testOne = new ToneAudioBuffer(buffer);\n\t\t\texpect(testOne.get()).to.equal(buffer.get());\n\t\t\ttestOne.dispose();\n\t\t\tbuffer.dispose();\n\t\t});\n\n\t\tit(\"takes an unloaded Tone.ToneAudioBuffer in the constructor method\", (done) => {\n\t\t\tconst unloadedToneAudioBuffer = new ToneAudioBuffer(testFile);\n\t\t\tconst buffer = new ToneAudioBuffer({\n\t\t\t\tonload(): void {\n\t\t\t\t\tconst testOne = new ToneAudioBuffer(buffer);\n\t\t\t\t\texpect(unloadedToneAudioBuffer.get()).to.equal(\n\t\t\t\t\t\tbuffer.get()\n\t\t\t\t\t);\n\t\t\t\t\tunloadedToneAudioBuffer.dispose();\n\t\t\t\t\tbuffer.dispose();\n\t\t\t\t\tdone();\n\t\t\t\t},\n\t\t\t\turl: unloadedToneAudioBuffer,\n\t\t\t});\n\t\t});\n\n\t\tit(\"takes Tone.ToneAudioBuffer in the set method\", (done) => {\n\t\t\tconst buffer = new ToneAudioBuffer({\n\t\t\t\turl: testFile,\n\t\t\t\tonload(): void {\n\t\t\t\t\tconst testOne = new ToneAudioBuffer(testFile);\n\t\t\t\t\ttestOne.set(buffer);\n\t\t\t\t\texpect(testOne.get()).to.equal(buffer.get());\n\t\t\t\t\ttestOne.dispose();\n\t\t\t\t\tbuffer.dispose();\n\t\t\t\t\tdone();\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\n\t\tit(\"can load an audio file with a space in the name\", async () => {\n\t\t\tconst buffer = new ToneAudioBuffer(\n\t\t\t\t\"./test/audio/name with space.wav\"\n\t\t\t);\n\t\t\texpect(buffer.loaded).to.be.false;\n\t\t\tawait ToneAudioBuffer.loaded();\n\t\t\texpect(buffer.loaded).to.be.true;\n\t\t});\n\n\t\tit(\"can load an encoded audio file with a space in the name\", async () => {\n\t\t\tconst buffer = new ToneAudioBuffer(\n\t\t\t\t\"./test/audio/\" + encodeURIComponent(\"name with space.wav\")\n\t\t\t);\n\t\t\texpect(buffer.loaded).to.be.false;\n\t\t\tawait ToneAudioBuffer.loaded();\n\t\t\texpect(buffer.loaded).to.be.true;\n\t\t});\n\t});\n\n\tcontext(\"baseUrl\", () => {\n\t\tafterEach(() => {\n\t\t\t// reset baseUrl\n\t\t\tToneAudioBuffer.baseUrl = \"\";\n\t\t});\n\n\t\tit(\"can resolve a url without a baseUrl\", async () => {\n\t\t\tconst buffer = new ToneAudioBuffer(\"./test/audio/sine.wav\");\n\t\t\texpect(buffer.loaded).to.be.false;\n\t\t\tawait ToneAudioBuffer.loaded();\n\t\t\texpect(buffer.loaded).to.be.true;\n\t\t\texpect(buffer.duration).to.be.closeTo(3, 0.01);\n\t\t});\n\n\t\tit(\"can resolve a url with a baseUrl\", async () => {\n\t\t\tToneAudioBuffer.baseUrl = \"./test/audio\";\n\t\t\tconst buffer = new ToneAudioBuffer(\"sine.wav\");\n\t\t\texpect(buffer.loaded).to.be.false;\n\t\t\tawait ToneAudioBuffer.loaded();\n\t\t\texpect(buffer.loaded).to.be.true;\n\t\t\texpect(buffer.duration).to.be.closeTo(3, 0.01);\n\t\t});\n\n\t\tit(\"can resolve a url with a baseUrl that has a trailing slash\", async () => {\n\t\t\tToneAudioBuffer.baseUrl = \"./test/audio/\";\n\t\t\tconst buffer = new ToneAudioBuffer(\"sine.wav\");\n\t\t\texpect(buffer.loaded).to.be.false;\n\t\t\tawait ToneAudioBuffer.loaded();\n\t\t\texpect(buffer.loaded).to.be.true;\n\t\t\texpect(buffer.duration).to.be.closeTo(3, 0.01);\n\t\t});\n\t});\n\n\tcontext(\"loading\", () => {\n\t\tit(\"invokes the error callback if there is a problem with the file\", (done) => {\n\t\t\tconst buffer = new ToneAudioBuffer(\n\t\t\t\t\"nosuchfile.wav\",\n\t\t\t\t() => {\n\t\t\t\t\tthrow new Error(\"shouldn't invoke this function\");\n\t\t\t\t},\n\t\t\t\t(e) => {\n\t\t\t\t\tbuffer.dispose();\n\t\t\t\t\tdone();\n\t\t\t\t}\n\t\t\t);\n\t\t});\n\n\t\tit(\"invokes the error callback on static .load method\", async () => {\n\t\t\tlet hadError = false;\n\t\t\ttry {\n\t\t\t\tawait ToneAudioBuffer.load(\"nosuchfile.wav\");\n\t\t\t} catch (e) {\n\t\t\t\thadError = true;\n\t\t\t}\n\t\t\texpect(hadError).to.equal(true);\n\t\t});\n\n\t\tit(\"instance .load method returns Promise\", async () => {\n\t\t\tconst buffer = await new ToneAudioBuffer().load(testFile);\n\t\t\texpect(buffer).to.be.instanceOf(ToneAudioBuffer);\n\t\t});\n\n\t\tit(\"invokes the error callback if the file is corrupt\", (done) => {\n\t\t\tconst buffer = new ToneAudioBuffer(\n\t\t\t\t\"./test/audio/corrupt.wav\",\n\t\t\t\t() => {\n\t\t\t\t\tthrow new Error(\"shouldn't invoke this function\");\n\t\t\t\t},\n\t\t\t\t(e) => {\n\t\t\t\t\tbuffer.dispose();\n\t\t\t\t\tdone();\n\t\t\t\t}\n\t\t\t);\n\t\t});\n\t});\n\n\tcontext(\"buffer manipulation\", () => {\n\t\tit(\"returns an empty array if there is no channel data\", () => {\n\t\t\tconst buffer = new ToneAudioBuffer();\n\t\t\texpect(buffer.getChannelData(0).length).to.equal(0);\n\t\t\tbuffer.dispose();\n\t\t});\n\n\t\tit(\"can get the channel data as an array\", (done) => {\n\t\t\tconst buffer = new ToneAudioBuffer(testFile, () => {\n\t\t\t\texpect(buffer.getChannelData(0)).to.be.an.instanceOf(\n\t\t\t\t\tFloat32Array\n\t\t\t\t);\n\t\t\t\texpect(buffer.getChannelData(0).length).to.be.above(130000);\n\t\t\t\tbuffer.dispose();\n\t\t\t\tdone();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can reverse a buffer\", (done) => {\n\t\t\tconst buffer = new ToneAudioBuffer(testFile, () => {\n\t\t\t\tconst buffArray = buffer.get() as AudioBuffer;\n\t\t\t\tconst lastSample = buffArray[buffArray.length - 1];\n\t\t\t\tbuffer.reverse = true;\n\t\t\t\texpect((buffer.get() as AudioBuffer)[0]).to.equal(lastSample);\n\t\t\t\t// setting reverse again has no effect\n\t\t\t\tbuffer.reverse = true;\n\t\t\t\texpect((buffer.get() as AudioBuffer)[0]).to.equal(lastSample);\n\t\t\t\tbuffer.dispose();\n\t\t\t\tdone();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can convert from an array\", () => {\n\t\t\tconst buffer = new ToneAudioBuffer();\n\t\t\tconst arr = new Float32Array(0.5 * buffer.sampleRate);\n\t\t\tarr[0] = 0.5;\n\t\t\tbuffer.fromArray(arr);\n\t\t\texpect(buffer.duration).to.equal(0.5);\n\t\t\texpect(buffer.numberOfChannels).to.equal(1);\n\t\t\t// test the first sample of the first channel to see if it's the same\n\t\t\texpect(buffer.toArray(0)[0]).to.equal(0.5);\n\t\t\tbuffer.dispose();\n\t\t});\n\n\t\tit(\"can create a buffer from an array using the static method\", () => {\n\t\t\tconst arr = new Float32Array(0.5 * getContext().sampleRate);\n\t\t\tarr[0] = 0.5;\n\t\t\tconst buffer = ToneAudioBuffer.fromArray(arr);\n\t\t\texpect(buffer.duration).to.equal(0.5);\n\t\t\texpect(buffer.numberOfChannels).to.equal(1);\n\t\t\t// test the first sample of the first channel to see if it's the same\n\t\t\texpect(buffer.toArray(0)[0]).to.equal(0.5);\n\t\t\t// should return the same thing without the channel argument as well\n\t\t\texpect(buffer.toArray()[0]).to.equal(0.5);\n\t\t\tbuffer.dispose();\n\t\t});\n\n\t\tit(\"can convert from a multidimensional array\", () => {\n\t\t\tconst buffer = new ToneAudioBuffer();\n\t\t\tconst arr = [\n\t\t\t\tnew Float32Array(0.5 * buffer.sampleRate),\n\t\t\t\tnew Float32Array(0.5 * buffer.sampleRate),\n\t\t\t];\n\t\t\tarr[0][0] = 0.5;\n\t\t\tbuffer.fromArray(arr);\n\t\t\texpect(buffer.duration).to.equal(0.5);\n\t\t\texpect(buffer.numberOfChannels).to.equal(2);\n\t\t\texpect(buffer.toArray(0)[0]).to.equal(0.5);\n\t\t\tbuffer.dispose();\n\t\t});\n\n\t\tit(\"can convert to and from an array\", () => {\n\t\t\tconst buffer = new ToneAudioBuffer();\n\t\t\tconst arr = [\n\t\t\t\tnew Float32Array(0.5 * buffer.sampleRate),\n\t\t\t\tnew Float32Array(0.5 * buffer.sampleRate),\n\t\t\t];\n\t\t\tarr[0][0] = 0.5;\n\t\t\tbuffer.fromArray(arr);\n\t\t\texpect(buffer.toArray(0)[0]).to.equal(0.5);\n\t\t\texpect(buffer.toArray()[0][0]).to.equal(0.5);\n\t\t\t// with a selected channel\n\t\t\texpect(buffer.toArray(0)[0]).to.equal(0.5);\n\t\t\tbuffer.dispose();\n\t\t});\n\n\t\tit(\"can slice a portion of the array\", async () => {\n\t\t\tconst buffer = await ToneAudioBuffer.fromUrl(testFile);\n\t\t\t// original duration\n\t\t\texpect(buffer.duration).to.be.closeTo(3, 0.01);\n\t\t\tconst sliced1 = buffer.slice(0, 1);\n\t\t\t// confirm they have the same values\n\t\t\tconst offset = Math.floor(buffer.sampleRate * 0.9);\n\t\t\t// does not modify the original\n\t\t\texpect(buffer.duration).to.be.closeTo(3, 0.01);\n\t\t\texpect(sliced1.duration).to.be.closeTo(1, 0.01);\n\t\t\tconst sliced2 = sliced1.slice(0.5);\n\t\t\texpect(sliced2.duration).to.be.closeTo(0.5, 0.01);\n\t\t\tconst sliced3 = buffer.slice(2);\n\t\t\texpect(\n\t\t\t\tsliced3.toArray(0)[Math.floor(0.5 * buffer.sampleRate) + 1]\n\t\t\t).to.equal(\n\t\t\t\tbuffer.toArray(0)[Math.floor(2.5 * buffer.sampleRate) + 1]\n\t\t\t);\n\t\t\tbuffer.dispose();\n\t\t\tsliced1.dispose();\n\t\t\tsliced2.dispose();\n\t\t\tsliced3.dispose();\n\t\t});\n\n\t\tit(\"slice can extend the buffer also\", async () => {\n\t\t\tconst buffer = await ToneAudioBuffer.fromUrl(testFile);\n\t\t\t// original duration\n\t\t\texpect(buffer.duration).to.be.closeTo(3, 0.01);\n\t\t\tconst sliced = buffer.slice(0, 4);\n\t\t\texpect(sliced.duration).to.be.closeTo(4, 0.01);\n\t\t\tbuffer.dispose();\n\t\t\tsliced.dispose();\n\t\t});\n\n\t\tit(\"can convert a buffer to mono\", () => {\n\t\t\tconst buffer = new ToneAudioBuffer();\n\t\t\tconst arr = [\n\t\t\t\tnew Float32Array(0.5 * buffer.sampleRate),\n\t\t\t\tnew Float32Array(0.5 * buffer.sampleRate),\n\t\t\t];\n\t\t\tarr[0][0] = 0.5;\n\t\t\tbuffer.fromArray(arr);\n\t\t\texpect(buffer.duration).to.equal(0.5);\n\t\t\texpect(buffer.numberOfChannels).to.equal(2);\n\t\t\tbuffer.toMono();\n\t\t\texpect(buffer.numberOfChannels).to.equal(1);\n\t\t\t// should have averaged the two first samples\n\t\t\texpect(buffer.toArray()[0]).to.equal(0.25);\n\t\t\tbuffer.dispose();\n\t\t});\n\n\t\tit(\"can use just the second channel of a buffer when making mono\", () => {\n\t\t\tconst buffer = new ToneAudioBuffer();\n\t\t\tconst arr = [\n\t\t\t\tnew Float32Array(0.5 * buffer.sampleRate),\n\t\t\t\tnew Float32Array(0.5 * buffer.sampleRate),\n\t\t\t];\n\t\t\tarr[0][0] = 0.5;\n\t\t\tbuffer.fromArray(arr);\n\t\t\texpect(buffer.duration).to.equal(0.5);\n\t\t\texpect(buffer.numberOfChannels).to.equal(2);\n\t\t\tbuffer.toMono(1);\n\t\t\texpect(buffer.numberOfChannels).to.equal(1);\n\t\t\t// should have averaged the two first samples\n\t\t\texpect(buffer.toArray()[0]).to.equal(0);\n\t\t\tbuffer.dispose();\n\t\t});\n\t});\n\n\tcontext(\"static methods\", () => {\n\t\tit(\"Test if the browser supports the given type\", () => {\n\t\t\texpect(ToneAudioBuffer.supportsType(\"test.wav\")).to.equal(true);\n\t\t\texpect(ToneAudioBuffer.supportsType(\"wav\")).to.equal(true);\n\t\t\texpect(ToneAudioBuffer.supportsType(\"path/to/test.wav\")).to.equal(\n\t\t\t\ttrue\n\t\t\t);\n\t\t\texpect(ToneAudioBuffer.supportsType(\"path/to/test.nope\")).to.equal(\n\t\t\t\tfalse\n\t\t\t);\n\t\t});\n\n\t\tit(\"can be constructed with ToneAudioBuffer.fromUrl\", (done) => {\n\t\t\tToneAudioBuffer.fromUrl(\"nosuchfile.wav\")\n\t\t\t\t.then(() => {\n\t\t\t\t\tthrow new Error(\"shouldn't invoke this function\");\n\t\t\t\t})\n\t\t\t\t.catch(() => {\n\t\t\t\t\tdone();\n\t\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"ToneAudioBuffer.loaded()\", () => {\n\t\tit(\"returns a promise\", () => {\n\t\t\texpect(ToneAudioBuffer.loaded()).to.have.property(\"then\");\n\t\t});\n\n\t\tit(\"is invoked when all the buffers are loaded\", async () => {\n\t\t\tconst buff0 = new ToneAudioBuffer(testFile);\n\t\t\tconst buff1 = new ToneAudioBuffer(testFile);\n\t\t\tawait ToneAudioBuffer.loaded();\n\t\t\texpect(buff0.loaded).to.equal(true);\n\t\t\texpect(buff1.loaded).to.equal(true);\n\t\t});\n\n\t\tit(\"can be setup before the urls\", async () => {\n\t\t\tconst loadedPromise = ToneAudioBuffer.loaded();\n\t\t\tconst buff0 = new ToneAudioBuffer(testFile);\n\t\t\tconst buff1 = new ToneAudioBuffer(testFile);\n\t\t\tawait loadedPromise;\n\t\t\texpect(buff0.loaded).to.equal(true);\n\t\t\texpect(buff1.loaded).to.equal(true);\n\t\t});\n\n\t\tit(\"invokes loaded even if there is an error\", () => {\n\t\t\tToneAudioBuffer.fromUrl(testFile);\n\t\t\tToneAudioBuffer.fromUrl(\"nosuchfile.wav\");\n\t\t\treturn ToneAudioBuffer.loaded();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/context/ToneAudioBuffer.ts",
    "content": "import { getContext } from \"../Global.js\";\nimport { Tone } from \"../Tone.js\";\nimport { Samples, Seconds } from \"../type/Units.js\";\nimport { assert } from \"../util/Debug.js\";\nimport { optionsFromArguments } from \"../util/Defaults.js\";\nimport { noOp } from \"../util/Interface.js\";\nimport { isArray, isNumber, isString } from \"../util/TypeCheck.js\";\n\ninterface ToneAudioBufferOptions {\n\turl?: string | AudioBuffer | ToneAudioBuffer;\n\treverse: boolean;\n\tonload: (buffer?: ToneAudioBuffer) => void;\n\tonerror: (error: Error) => void;\n}\n\n/**\n * AudioBuffer loading and storage. ToneAudioBuffer is used internally by all\n * classes that make requests for audio files such as Tone.Player,\n * Tone.Sampler and Tone.Convolver.\n * @example\n * const buffer = new Tone.ToneAudioBuffer(\"https://tonejs.github.io/audio/casio/A1.mp3\", () => {\n * \tconsole.log(\"loaded\");\n * });\n * @category Core\n */\nexport class ToneAudioBuffer extends Tone {\n\treadonly name: string = \"ToneAudioBuffer\";\n\n\t/**\n\t * stores the loaded AudioBuffer\n\t */\n\tprivate _buffer?: AudioBuffer;\n\n\t/**\n\t * indicates if the buffer should be reversed or not\n\t */\n\tprivate _reversed!: boolean;\n\n\t/**\n\t * Callback when the buffer is loaded.\n\t */\n\tonload: (buffer: ToneAudioBuffer) => void = noOp;\n\n\t/**\n\t *\n\t * @param url The url to load, or the audio buffer to set.\n\t * @param onload A callback which is invoked after the buffer is loaded.\n\t *                           It's recommended to use `ToneAudioBuffer.on('load', callback)` instead\n\t *                           since it will give you a callback when _all_ buffers are loaded.\n\t * @param onerror The callback to invoke if there is an error\n\t */\n\tconstructor(\n\t\turl?: string | ToneAudioBuffer | AudioBuffer,\n\t\tonload?: (buffer: ToneAudioBuffer) => void,\n\t\tonerror?: (error: Error) => void\n\t);\n\tconstructor(options?: Partial<ToneAudioBufferOptions>);\n\tconstructor() {\n\t\tsuper();\n\n\t\tconst options = optionsFromArguments(\n\t\t\tToneAudioBuffer.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"url\", \"onload\", \"onerror\"]\n\t\t);\n\n\t\tthis.reverse = options.reverse;\n\t\tthis.onload = options.onload;\n\n\t\tif (isString(options.url)) {\n\t\t\t// initiate the download\n\t\t\tthis.load(options.url).catch(options.onerror);\n\t\t} else if (options.url) {\n\t\t\tthis.set(options.url);\n\t\t}\n\t}\n\n\tstatic getDefaults(): ToneAudioBufferOptions {\n\t\treturn {\n\t\t\tonerror: noOp,\n\t\t\tonload: noOp,\n\t\t\treverse: false,\n\t\t};\n\t}\n\n\t/**\n\t * The sample rate of the AudioBuffer\n\t */\n\tget sampleRate(): number {\n\t\tif (this._buffer) {\n\t\t\treturn this._buffer.sampleRate;\n\t\t} else {\n\t\t\treturn getContext().sampleRate;\n\t\t}\n\t}\n\n\t/**\n\t * Pass in an AudioBuffer or ToneAudioBuffer to set the value of this buffer.\n\t */\n\tset(buffer: AudioBuffer | ToneAudioBuffer): this {\n\t\tif (buffer instanceof ToneAudioBuffer) {\n\t\t\t// if it's loaded, set it\n\t\t\tif (buffer.loaded) {\n\t\t\t\tthis._buffer = buffer.get();\n\t\t\t} else {\n\t\t\t\t// otherwise when its loaded, invoke it's callback\n\t\t\t\tbuffer.onload = () => {\n\t\t\t\t\tthis.set(buffer);\n\t\t\t\t\tthis.onload(this);\n\t\t\t\t};\n\t\t\t}\n\t\t} else {\n\t\t\tthis._buffer = buffer;\n\t\t}\n\t\t// reverse it initially\n\t\tif (this._reversed) {\n\t\t\tthis._reverse();\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * The audio buffer stored in the object.\n\t */\n\tget(): AudioBuffer | undefined {\n\t\treturn this._buffer;\n\t}\n\n\t/**\n\t * Makes an fetch request for the selected url then decodes the file as an audio buffer.\n\t * Invokes the callback once the audio buffer loads.\n\t * @param url The url of the buffer to load. filetype support depends on the browser.\n\t * @returns A Promise which resolves with this ToneAudioBuffer\n\t */\n\tasync load(url: string): Promise<this> {\n\t\tconst doneLoading: Promise<void> = ToneAudioBuffer.load(url).then(\n\t\t\t(audioBuffer) => {\n\t\t\t\tthis.set(audioBuffer);\n\t\t\t\t// invoke the onload method\n\t\t\t\tthis.onload(this);\n\t\t\t}\n\t\t);\n\t\tToneAudioBuffer.downloads.push(doneLoading);\n\t\ttry {\n\t\t\tawait doneLoading;\n\t\t} finally {\n\t\t\t// remove the downloaded file\n\t\t\tconst index = ToneAudioBuffer.downloads.indexOf(doneLoading);\n\t\t\tToneAudioBuffer.downloads.splice(index, 1);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * clean up\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._buffer = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set the audio buffer from the array.\n\t * To create a multichannel AudioBuffer, pass in a multidimensional array.\n\t * @param array The array to fill the audio buffer\n\t */\n\tfromArray(array: Float32Array | Float32Array[]): this {\n\t\tconst isMultidimensional = isArray(array) && array[0].length > 0;\n\t\tconst channels = isMultidimensional ? array.length : 1;\n\t\tconst len = isMultidimensional\n\t\t\t? (array[0] as Float32Array).length\n\t\t\t: array.length;\n\t\tconst context = getContext();\n\t\tconst buffer = context.createBuffer(channels, len, context.sampleRate);\n\t\tconst multiChannelArray: Float32Array[] =\n\t\t\t!isMultidimensional && channels === 1\n\t\t\t\t? [array as Float32Array]\n\t\t\t\t: (array as Float32Array[]);\n\n\t\tfor (let c = 0; c < channels; c++) {\n\t\t\tbuffer.copyToChannel(multiChannelArray[c], c);\n\t\t}\n\t\tthis._buffer = buffer;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sums multiple channels into 1 channel\n\t * @param chanNum Optionally only copy a single channel from the array.\n\t */\n\ttoMono(chanNum?: number): this {\n\t\tif (isNumber(chanNum)) {\n\t\t\tthis.fromArray(this.toArray(chanNum));\n\t\t} else {\n\t\t\tlet outputArray = new Float32Array(this.length as number);\n\t\t\tconst numChannels = this.numberOfChannels;\n\t\t\tfor (let channel = 0; channel < numChannels; channel++) {\n\t\t\t\tconst channelArray = this.toArray(channel) as Float32Array;\n\t\t\t\tfor (let i = 0; i < channelArray.length; i++) {\n\t\t\t\t\toutputArray[i] += channelArray[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\t// divide by the number of channels\n\t\t\toutputArray = outputArray.map((sample) => sample / numChannels);\n\t\t\tthis.fromArray(outputArray);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Get the buffer as an array. Single channel buffers will return a 1-dimensional\n\t * Float32Array, and multichannel buffers will return multidimensional arrays.\n\t * @param channel Optionally only copy a single channel from the array.\n\t */\n\ttoArray(channel?: number): Float32Array | Float32Array[] {\n\t\tif (isNumber(channel)) {\n\t\t\treturn this.getChannelData(channel);\n\t\t} else if (this.numberOfChannels === 1) {\n\t\t\treturn this.toArray(0);\n\t\t} else {\n\t\t\tconst ret: Float32Array[] = [];\n\t\t\tfor (let c = 0; c < this.numberOfChannels; c++) {\n\t\t\t\tret[c] = this.getChannelData(c);\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t}\n\n\t/**\n\t * Returns the Float32Array representing the PCM audio data for the specific channel.\n\t * @param  channel  The channel number to return\n\t * @return The audio as a TypedArray\n\t */\n\tgetChannelData(channel: number): Float32Array {\n\t\tif (this._buffer) {\n\t\t\treturn this._buffer.getChannelData(channel);\n\t\t} else {\n\t\t\treturn new Float32Array(0);\n\t\t}\n\t}\n\n\t/**\n\t * Cut a subsection of the array and return a buffer of the\n\t * subsection. Does not modify the original buffer\n\t * @param start The time to start the slice\n\t * @param end The end time to slice. If none is given will default to the end of the buffer\n\t */\n\tslice(start: Seconds, end: Seconds = this.duration): ToneAudioBuffer {\n\t\tassert(this.loaded, \"Buffer is not loaded\");\n\t\tconst startSamples = Math.floor(start * this.sampleRate);\n\t\tconst endSamples = Math.floor(end * this.sampleRate);\n\t\tassert(\n\t\t\tstartSamples < endSamples,\n\t\t\t\"The start time must be less than the end time\"\n\t\t);\n\t\tconst length = endSamples - startSamples;\n\t\tconst retBuffer = getContext().createBuffer(\n\t\t\tthis.numberOfChannels,\n\t\t\tlength,\n\t\t\tthis.sampleRate\n\t\t);\n\t\tfor (let channel = 0; channel < this.numberOfChannels; channel++) {\n\t\t\tretBuffer.copyToChannel(\n\t\t\t\tthis.getChannelData(channel).subarray(startSamples, endSamples),\n\t\t\t\tchannel\n\t\t\t);\n\t\t}\n\t\treturn new ToneAudioBuffer(retBuffer);\n\t}\n\n\t/**\n\t * Reverse the buffer.\n\t */\n\tprivate _reverse(): this {\n\t\tif (this.loaded) {\n\t\t\tfor (let i = 0; i < this.numberOfChannels; i++) {\n\t\t\t\tthis.getChannelData(i).reverse();\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * If the buffer is loaded or not\n\t */\n\tget loaded(): boolean {\n\t\treturn this.length > 0;\n\t}\n\n\t/**\n\t * The duration of the buffer in seconds.\n\t */\n\tget duration(): Seconds {\n\t\tif (this._buffer) {\n\t\t\treturn this._buffer.duration;\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t/**\n\t * The length of the buffer in samples\n\t */\n\tget length(): Samples {\n\t\tif (this._buffer) {\n\t\t\treturn this._buffer.length;\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t/**\n\t * The number of discrete audio channels. Returns 0 if no buffer is loaded.\n\t */\n\tget numberOfChannels(): number {\n\t\tif (this._buffer) {\n\t\t\treturn this._buffer.numberOfChannels;\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t/**\n\t * Reverse the buffer.\n\t */\n\tget reverse(): boolean {\n\t\treturn this._reversed;\n\t}\n\tset reverse(rev: boolean) {\n\t\tif (this._reversed !== rev) {\n\t\t\tthis._reversed = rev;\n\t\t\tthis._reverse();\n\t\t}\n\t}\n\n\t//-------------------------------------\n\t// STATIC METHODS\n\t//-------------------------------------\n\n\t/**\n\t * A path which is prefixed before every url.\n\t */\n\tstatic baseUrl = \"\";\n\n\t/**\n\t * Create a ToneAudioBuffer from the array. To create a multichannel AudioBuffer,\n\t * pass in a multidimensional array.\n\t * @param array The array to fill the audio buffer\n\t * @return A ToneAudioBuffer created from the array\n\t */\n\tstatic fromArray(array: Float32Array | Float32Array[]): ToneAudioBuffer {\n\t\treturn new ToneAudioBuffer().fromArray(array);\n\t}\n\n\t/**\n\t * Creates a ToneAudioBuffer from a URL, returns a promise which resolves to a ToneAudioBuffer\n\t * @param  url The url to load.\n\t * @return A promise which resolves to a ToneAudioBuffer\n\t */\n\tstatic async fromUrl(url: string): Promise<ToneAudioBuffer> {\n\t\tconst buffer = new ToneAudioBuffer();\n\t\treturn await buffer.load(url);\n\t}\n\n\t/**\n\t * All of the downloads\n\t */\n\tstatic downloads: Array<Promise<void>> = [];\n\n\t/**\n\t * Loads a url using fetch and returns the AudioBuffer.\n\t */\n\tstatic async load(url: string): Promise<AudioBuffer> {\n\t\t// make sure there is a slash between the baseUrl and the url\n\t\tconst baseUrl =\n\t\t\tToneAudioBuffer.baseUrl === \"\" ||\n\t\t\tToneAudioBuffer.baseUrl.endsWith(\"/\")\n\t\t\t\t? ToneAudioBuffer.baseUrl\n\t\t\t\t: ToneAudioBuffer.baseUrl + \"/\";\n\n\t\tconst response = await fetch(baseUrl + url);\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`could not load url: ${url}`);\n\t\t}\n\t\tconst arrayBuffer = await response.arrayBuffer();\n\n\t\tconst audioBuffer = await getContext().decodeAudioData(arrayBuffer);\n\n\t\treturn audioBuffer;\n\t}\n\n\t/**\n\t * Checks a url's extension to see if the current browser can play that file type.\n\t * @param url The url/extension to test\n\t * @return If the file extension can be played\n\t * @static\n\t * @example\n\t * Tone.ToneAudioBuffer.supportsType(\"wav\"); // returns true\n\t * Tone.ToneAudioBuffer.supportsType(\"path/to/file.wav\"); // returns true\n\t */\n\tstatic supportsType(url: string): boolean {\n\t\tconst extensions = url.split(\".\");\n\t\tconst extension = extensions[extensions.length - 1];\n\t\tconst response = document\n\t\t\t.createElement(\"audio\")\n\t\t\t.canPlayType(\"audio/\" + extension);\n\t\treturn response !== \"\";\n\t}\n\n\t/**\n\t * Returns a Promise which resolves when all of the buffers have loaded\n\t */\n\tstatic async loaded(): Promise<void> {\n\t\t// this makes sure that the function is always async\n\t\tawait Promise.resolve();\n\t\twhile (ToneAudioBuffer.downloads.length) {\n\t\t\tawait ToneAudioBuffer.downloads[0];\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Tone/core/context/ToneAudioBuffers.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { ToneAudioBuffer } from \"./ToneAudioBuffer.js\";\nimport { ToneAudioBuffers } from \"./ToneAudioBuffers.js\";\n\nconst testFile = \"./test/audio/sine.wav\";\nconst testFile2 = \"./test/audio/hh.wav\";\n\ndescribe(\"ToneAudioBuffers\", () => {\n\tit(\"can be created and disposed\", () => {\n\t\tconst buff = new ToneAudioBuffers();\n\t\tbuff.dispose();\n\t});\n\n\tit(\"loads a file from an object string\", (done) => {\n\t\tconst buffer = new ToneAudioBuffers(\n\t\t\t{\n\t\t\t\tsine: testFile,\n\t\t\t},\n\t\t\t() => {\n\t\t\t\texpect(buffer).to.be.instanceof(ToneAudioBuffers);\n\t\t\t\tbuffer.dispose();\n\t\t\t\tdone();\n\t\t\t}\n\t\t);\n\t});\n\n\tit(\"can get a buffer loaded from an object\", (done) => {\n\t\tconst buffer = new ToneAudioBuffers(\n\t\t\t{\n\t\t\t\tkick: testFile2,\n\t\t\t\tsine: testFile,\n\t\t\t},\n\t\t\t() => {\n\t\t\t\texpect(buffer.get(\"kick\")).to.be.instanceof(ToneAudioBuffer);\n\t\t\t\tbuffer.dispose();\n\t\t\t\tdone();\n\t\t\t}\n\t\t);\n\t});\n\n\tit(\"throws an error when it tries to get an object that doesn't exist\", (done) => {\n\t\tconst buffer = new ToneAudioBuffers(\n\t\t\t{\n\t\t\t\tsine: testFile,\n\t\t\t},\n\t\t\t() => {\n\t\t\t\texpect(() => {\n\t\t\t\t\tbuffer.get(\"nope\");\n\t\t\t\t}).throws(Error);\n\t\t\t\tbuffer.dispose();\n\t\t\t\tdone();\n\t\t\t}\n\t\t);\n\t});\n\n\tit(\"tests if it has a buffer\", (done) => {\n\t\tconst buffer = new ToneAudioBuffers(\n\t\t\t{\n\t\t\t\tkick: testFile2,\n\t\t\t\tsine: testFile,\n\t\t\t},\n\t\t\t() => {\n\t\t\t\texpect(buffer.has(\"kick\")).to.be.true;\n\t\t\t\texpect(buffer.has(\"sine\")).to.be.true;\n\t\t\t\texpect(buffer.has(\"nope\")).to.be.false;\n\t\t\t\tbuffer.dispose();\n\t\t\t\tdone();\n\t\t\t}\n\t\t);\n\t});\n\n\tit(\"can pass in buffers as object and options object in second arg\", (done) => {\n\t\tconst buffer = new ToneAudioBuffers({\n\t\t\tbaseUrl: \"./test/audio/\",\n\t\t\tonload(): void {\n\t\t\t\texpect(buffer.has(\"sine\")).to.be.true;\n\t\t\t\tbuffer.dispose();\n\t\t\t\tdone();\n\t\t\t},\n\t\t\turls: {\n\t\t\t\tsine: \"sine.wav\",\n\t\t\t},\n\t\t});\n\t});\n\n\tit(\"invokes onerror if it cant load the url\", (done) => {\n\t\tconst buffer = new ToneAudioBuffers({\n\t\t\tonerror(): void {\n\t\t\t\tbuffer.dispose();\n\t\t\t\tdone();\n\t\t\t},\n\t\t\turls: {\n\t\t\t\ttest: \"nosuchfile.wav\",\n\t\t\t},\n\t\t});\n\t});\n\n\tit(\"reports itself as loaded\", (done) => {\n\t\tconst buffer = new ToneAudioBuffers(\n\t\t\t{\n\t\t\t\tkick: testFile2,\n\t\t\t\tsine: testFile,\n\t\t\t},\n\t\t\t() => {\n\t\t\t\texpect(buffer.loaded).to.be.true;\n\t\t\t\tbuffer.dispose();\n\t\t\t\tdone();\n\t\t\t}\n\t\t);\n\t\texpect(buffer.loaded).to.be.false;\n\t});\n\n\tit(\"can load from a base url\", async () => {\n\t\tconst buffer = new ToneAudioBuffers(\n\t\t\t{\n\t\t\t\that: \"hh.wav\",\n\t\t\t},\n\t\t\t() => {},\n\t\t\t\"./test/audio/\"\n\t\t);\n\t\tawait ToneAudioBuffer.loaded();\n\t\texpect(buffer.get(\"hat\")).to.be.instanceof(ToneAudioBuffer);\n\t});\n\n\tit(\"can add a buffer\", (done) => {\n\t\tconst buffer = new ToneAudioBuffers();\n\t\tbuffer.add(\"name\", testFile, () => {\n\t\t\texpect(buffer.get(\"name\")).to.be.instanceof(ToneAudioBuffer);\n\t\t\tbuffer.dispose();\n\t\t\tdone();\n\t\t});\n\t});\n\n\tit(\"can add a buffer url\", (done) => {\n\t\tconst buffer = new ToneAudioBuffers();\n\t\tbuffer.add(\"name\", testFile, () => {\n\t\t\texpect(buffer.get(\"name\")).to.be.instanceof(ToneAudioBuffer);\n\t\t\tbuffer.dispose();\n\t\t\tdone();\n\t\t});\n\t});\n\n\tit(\"throws an error if no buffer exists with that name or index\", () => {\n\t\tconst buffer = new ToneAudioBuffers();\n\t\texpect(() => {\n\t\t\tbuffer.get(\"nope\");\n\t\t}).to.throw(Error);\n\t\tbuffer.dispose();\n\t});\n\n\tit(\"can add a ToneAudioBuffer\", () => {\n\t\tconst buff = new ToneAudioBuffer();\n\t\tconst buffer = new ToneAudioBuffers();\n\t\tbuffer.add(\"name\", buff);\n\t\texpect(buffer.get(\"name\").get()).to.equal(buff.get());\n\t});\n\n\tit(\"can add an AudioBuffer\", async () => {\n\t\tconst audioBuffer = await ToneAudioBuffer.load(testFile);\n\t\tconst buffer = new ToneAudioBuffers();\n\t\tbuffer.add(\"name\", audioBuffer);\n\t\texpect(buffer.get(\"name\").get()).to.equal(audioBuffer);\n\t});\n\n\tit(\"can be constructed with ToneAudioBuffers\", () => {\n\t\tconst buff = new ToneAudioBuffer();\n\t\tconst buffer = new ToneAudioBuffers({\n\t\t\tbuff,\n\t\t});\n\t\texpect(buffer.get(\"buff\").get()).to.equal(buff.get());\n\t});\n});\n"
  },
  {
    "path": "Tone/core/context/ToneAudioBuffers.ts",
    "content": "import { Tone } from \"../Tone.js\";\nimport { assert } from \"../util/Debug.js\";\nimport { optionsFromArguments } from \"../util/Defaults.js\";\nimport { noOp } from \"../util/Interface.js\";\nimport { isString } from \"../util/TypeCheck.js\";\nimport { ToneAudioBuffer } from \"./ToneAudioBuffer.js\";\n\nexport interface ToneAudioBuffersUrlMap {\n\t[name: string]: string | AudioBuffer | ToneAudioBuffer;\n\t[name: number]: string | AudioBuffer | ToneAudioBuffer;\n}\n\ninterface ToneAudioBuffersOptions {\n\turls: ToneAudioBuffersUrlMap;\n\tonload: () => void;\n\tonerror?: (error: Error) => void;\n\tbaseUrl: string;\n}\n\n/**\n * A data structure for holding multiple buffers in a Map-like data structure.\n *\n * @example\n * const pianoSamples = new Tone.ToneAudioBuffers({\n * \tA1: \"https://tonejs.github.io/audio/casio/A1.mp3\",\n * \tA2: \"https://tonejs.github.io/audio/casio/A2.mp3\",\n * }, () => {\n * \tconst player = new Tone.Player().toDestination();\n * \t// play one of the samples when they all load\n * \tplayer.buffer = pianoSamples.get(\"A2\");\n * \tplayer.start();\n * });\n * @example\n * // To pass in additional parameters in the second parameter\n * const buffers = new Tone.ToneAudioBuffers({\n * \t urls: {\n * \t\t A1: \"A1.mp3\",\n * \t\t A2: \"A2.mp3\",\n * \t },\n * \t onload: () => console.log(\"loaded\"),\n * \t baseUrl: \"https://tonejs.github.io/audio/casio/\"\n * });\n * @category Core\n */\nexport class ToneAudioBuffers extends Tone {\n\treadonly name: string = \"ToneAudioBuffers\";\n\n\t/**\n\t * All of the buffers\n\t */\n\tprivate _buffers: Map<string, ToneAudioBuffer> = new Map();\n\n\t/**\n\t * A path which is prefixed before every url.\n\t */\n\tbaseUrl: string;\n\n\t/**\n\t * Keep track of the number of loaded buffers\n\t */\n\tprivate _loadingCount = 0;\n\n\t/**\n\t * @param  urls  An object literal or array of urls to load.\n\t * @param onload  The callback to invoke when the buffers are loaded.\n\t * @param baseUrl A prefix url to add before all the urls\n\t */\n\tconstructor(\n\t\turls?: ToneAudioBuffersUrlMap,\n\t\tonload?: () => void,\n\t\tbaseUrl?: string\n\t);\n\tconstructor(options?: Partial<ToneAudioBuffersOptions>);\n\tconstructor() {\n\t\tsuper();\n\t\tconst options = optionsFromArguments(\n\t\t\tToneAudioBuffers.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"urls\", \"onload\", \"baseUrl\"],\n\t\t\t\"urls\"\n\t\t);\n\n\t\tthis.baseUrl = options.baseUrl;\n\t\t// add each one\n\t\tObject.keys(options.urls).forEach((name) => {\n\t\t\tthis._loadingCount++;\n\t\t\tconst url = options.urls[name];\n\t\t\tthis.add(\n\t\t\t\tname,\n\t\t\t\turl,\n\t\t\t\tthis._bufferLoaded.bind(this, options.onload),\n\t\t\t\toptions.onerror\n\t\t\t);\n\t\t});\n\t}\n\n\tstatic getDefaults(): ToneAudioBuffersOptions {\n\t\treturn {\n\t\t\tbaseUrl: \"\",\n\t\t\tonerror: noOp,\n\t\t\tonload: noOp,\n\t\t\turls: {},\n\t\t};\n\t}\n\n\t/**\n\t * True if the buffers object has a buffer by that name.\n\t * @param  name  The key or index of the buffer.\n\t */\n\thas(name: string | number): boolean {\n\t\treturn this._buffers.has(name.toString());\n\t}\n\n\t/**\n\t * Get a buffer by name. If an array was loaded,\n\t * then use the array index.\n\t * @param  name  The key or index of the buffer.\n\t */\n\tget(name: string | number): ToneAudioBuffer {\n\t\tassert(this.has(name), `ToneAudioBuffers has no buffer named: ${name}`);\n\t\treturn this._buffers.get(name.toString()) as ToneAudioBuffer;\n\t}\n\n\t/**\n\t * A buffer was loaded. decrement the counter.\n\t */\n\tprivate _bufferLoaded(callback: () => void): void {\n\t\tthis._loadingCount--;\n\t\tif (this._loadingCount === 0 && callback) {\n\t\t\tcallback();\n\t\t}\n\t}\n\n\t/**\n\t * If the buffers are loaded or not\n\t */\n\tget loaded(): boolean {\n\t\treturn Array.from(this._buffers).every(([_, buffer]) => buffer.loaded);\n\t}\n\n\t/**\n\t * Add a buffer by name and url to the Buffers\n\t * @param  name      A unique name to give the buffer\n\t * @param  url  Either the url of the buffer, or a buffer which will be added with the given name.\n\t * @param  callback  The callback to invoke when the url is loaded.\n\t * @param  onerror  Invoked if the buffer can't be loaded\n\t */\n\tadd(\n\t\tname: string | number,\n\t\turl: string | AudioBuffer | ToneAudioBuffer,\n\t\tcallback: () => void = noOp,\n\t\tonerror: (e: Error) => void = noOp\n\t): this {\n\t\tif (isString(url)) {\n\t\t\t// don't include the baseUrl if the url is a base64 encoded sound\n\t\t\tif (\n\t\t\t\tthis.baseUrl &&\n\t\t\t\turl.trim().substring(0, 11).toLowerCase() === \"data:audio/\"\n\t\t\t) {\n\t\t\t\tthis.baseUrl = \"\";\n\t\t\t}\n\t\t\tthis._buffers.set(\n\t\t\t\tname.toString(),\n\t\t\t\tnew ToneAudioBuffer(this.baseUrl + url, callback, onerror)\n\t\t\t);\n\t\t} else {\n\t\t\tthis._buffers.set(\n\t\t\t\tname.toString(),\n\t\t\t\tnew ToneAudioBuffer(url, callback, onerror)\n\t\t\t);\n\t\t}\n\t\treturn this;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._buffers.forEach((buffer) => buffer.dispose());\n\t\tthis._buffers.clear();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/core/context/ToneAudioNode.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { PassAudio } from \"../../../test/helper/PassAudio.js\";\nimport { Split } from \"../../component/channel/Split.js\";\nimport { Merge } from \"../../component/index.js\";\nimport { Oscillator } from \"../../source/index.js\";\nimport { Gain } from \"./Gain.js\";\nimport { connect, disconnect, fanIn } from \"./ToneAudioNode.js\";\n\ndescribe(\"ToneAudioNode\", () => {\n\tcontext(\"constructor\", () => {\n\t\tit(\"can be created and disposed\", () => {\n\t\t\tconst node = new Gain();\n\t\t\tnode.dispose();\n\t\t});\n\t});\n\n\tcontext(\"properties\", () => {\n\t\tit(\"reports its inputs and outputs\", () => {\n\t\t\tconst node = new Gain();\n\t\t\texpect(node.numberOfInputs).to.equal(1);\n\t\t\texpect(node.numberOfOutputs).to.equal(1);\n\t\t\tnode.dispose();\n\t\t});\n\n\t\tit(\"get/set channelCount\", () => {\n\t\t\tconst node = new Gain();\n\t\t\texpect(node.channelCount).to.equal(2);\n\t\t\tnode.channelCount = 1;\n\t\t\texpect(node.channelCount).to.equal(1);\n\t\t\tnode.dispose();\n\t\t});\n\n\t\tit(\"get/set channelCountMode\", () => {\n\t\t\tconst node = new Gain();\n\t\t\texpect(node.channelCountMode).to.equal(\"max\");\n\t\t\tnode.channelCountMode = \"explicit\";\n\t\t\texpect(node.channelCountMode).to.equal(\"explicit\");\n\t\t\tnode.dispose();\n\t\t});\n\n\t\tit(\"get/set channelInterpretation\", () => {\n\t\t\tconst node = new Gain();\n\t\t\texpect(node.channelInterpretation).to.equal(\"speakers\");\n\t\t\tnode.channelInterpretation = \"discrete\";\n\t\t\texpect(node.channelInterpretation).to.equal(\"discrete\");\n\t\t\tnode.dispose();\n\t\t});\n\n\t\tit(\"reports its inputs and outputs\", () => {\n\t\t\tconst node0 = new Merge({\n\t\t\t\tchannels: 4,\n\t\t\t});\n\t\t\texpect(node0.numberOfInputs).to.equal(4);\n\t\t\texpect(node0.numberOfOutputs).to.equal(1);\n\t\t\tnode0.dispose();\n\n\t\t\tconst node1 = new Split(4);\n\t\t\texpect(node1.numberOfInputs).to.equal(1);\n\t\t\texpect(node1.numberOfOutputs).to.equal(4);\n\t\t\tnode1.dispose();\n\n\t\t\tconst node2 = new Oscillator();\n\t\t\texpect(node2.numberOfInputs).to.equal(0);\n\t\t\texpect(node2.numberOfOutputs).to.equal(1);\n\t\t\tnode2.dispose();\n\t\t});\n\n\t\tit(\"is able to get and set the channelCount, channelCountMode and channelInterpretation\", () => {\n\t\t\tconst gainNode = new Gain();\n\n\t\t\texpect(gainNode.channelCount).to.equal(2);\n\t\t\tgainNode.channelCount = 1;\n\t\t\texpect(gainNode.channelCount).to.equal(1);\n\n\t\t\texpect(gainNode.channelInterpretation).to.equal(\"speakers\");\n\t\t\tgainNode.channelInterpretation = \"discrete\";\n\t\t\texpect(gainNode.channelInterpretation).to.equal(\"discrete\");\n\n\t\t\texpect(gainNode.channelCountMode).to.equal(\"max\");\n\t\t\tgainNode.channelCountMode = \"clamped-max\";\n\t\t\texpect(gainNode.channelCountMode).to.equal(\"clamped-max\");\n\t\t\tgainNode.dispose();\n\t\t});\n\t});\n\n\tcontext(\"methods\", () => {\n\t\tit(\"toDestination()\", () => {\n\t\t\tconst node = new Gain();\n\t\t\tnode.toDestination();\n\t\t\tnode.dispose();\n\t\t});\n\n\t\tit(\"connect()\", () => {\n\t\t\tconst nodeA = new Gain();\n\t\t\tconst nodeB = new Gain();\n\t\t\tnodeA.connect(nodeB);\n\t\t\tnodeA.dispose();\n\t\t\tnodeB.dispose();\n\t\t});\n\n\t\tit(\"disconnect()\", () => {\n\t\t\tconst nodeA = new Gain();\n\t\t\tconst nodeB = new Gain();\n\t\t\tnodeA.connect(nodeB);\n\t\t\tnodeA.disconnect(nodeB);\n\t\t\tnodeA.dispose();\n\t\t\tnodeB.dispose();\n\t\t});\n\n\t\tit(\"fan()\", () => {\n\t\t\tconst nodeA = new Gain();\n\t\t\tconst nodeB = new Gain();\n\t\t\tconst nodeC = new Gain();\n\t\t\tnodeA.fan(nodeB, nodeC);\n\t\t\tnodeA.dispose();\n\t\t\tnodeB.dispose();\n\t\t\tnodeC.dispose();\n\t\t});\n\n\t\tit(\"chain()\", () => {\n\t\t\tconst nodeA = new Gain();\n\t\t\tconst nodeB = new Gain();\n\t\t\tconst nodeC = new Gain();\n\t\t\tnodeA.chain(nodeB, nodeC);\n\t\t\tnodeA.dispose();\n\t\t\tnodeB.dispose();\n\t\t\tnodeC.dispose();\n\t\t});\n\t});\n\n\tcontext(\"connections\", () => {\n\t\tit(\"can connect with args\", () => {\n\t\t\tconst nodeA = new Gain();\n\t\t\tconst nodeB = new Gain();\n\t\t\tnodeA.connect(nodeB, 0, 0);\n\t\t\tnodeA.dispose();\n\t\t\tnodeB.dispose();\n\t\t});\n\n\t\tit(\"can connect with no args\", () => {\n\t\t\tconst nodeA = new Gain();\n\t\t\tconst nodeB = new Gain();\n\t\t\tnodeA.connect(nodeB);\n\t\t\tnodeA.dispose();\n\t\t\tnodeB.dispose();\n\t\t});\n\n\t\tit(\"can connect with one arg\", () => {\n\t\t\tconst nodeA = new Split(2);\n\t\t\tconst nodeB = new Gain();\n\t\t\tnodeA.connect(nodeB, 1);\n\t\t\tnodeA.dispose();\n\t\t\tnodeB.dispose();\n\t\t});\n\n\t\tit(\"Tone nodes can disconnect from everything with no args\", () => {\n\t\t\tconst nodeA = new Gain();\n\t\t\tconst nodeB = new Gain();\n\t\t\tnodeA.connect(nodeB);\n\t\t\tnodeA.disconnect();\n\t\t\tnodeA.dispose();\n\t\t\tnodeB.dispose();\n\t\t});\n\n\t\tit(\"Tone nodes can disconnect from a specific node\", () => {\n\t\t\tconst nodeA = new Gain();\n\t\t\tconst nodeB = new Gain();\n\t\t\tnodeA.connect(nodeB);\n\t\t\tnodeA.disconnect(nodeB);\n\t\t\tnodeA.dispose();\n\t\t\tnodeB.dispose();\n\t\t});\n\n\t\tit(\"Tone nodes can disconnect from a specific node and input/output\", () => {\n\t\t\tconst nodeA = new Gain();\n\t\t\tconst nodeB = new Merge();\n\t\t\tnodeA.connect(nodeB, 0, 1);\n\t\t\tnodeA.disconnect(nodeB, 0, 1);\n\t\t\tnodeA.dispose();\n\t\t\tnodeB.dispose();\n\t\t});\n\n\t\tit(\"throws an error if they are not connected\", () => {\n\t\t\tconst nodeA = new Gain();\n\t\t\tconst nodeB = new Gain();\n\t\t\texpect(() => {\n\t\t\t\tnodeA.disconnect(nodeB);\n\t\t\t}).throws(Error);\n\t\t\tnodeA.dispose();\n\t\t\tnodeB.dispose();\n\t\t});\n\t});\n\n\tcontext(\"connect native node\", () => {\n\t\tit(\"can create a connection\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst output = input.context.destination;\n\t\t\t\tconnect(input, output);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can disconnect two nodes\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst output = input.context.destination;\n\t\t\t\tconnect(input, output);\n\t\t\t\tdisconnect(input, output);\n\t\t\t}, false);\n\t\t});\n\n\t\tit(\"can disconnect a node\", () => {\n\t\t\tPassAudio((input) => {\n\t\t\t\tconst output = input.context.destination;\n\t\t\t\tconnect(input, output);\n\t\t\t\tdisconnect(input);\n\t\t\t}, false);\n\t\t});\n\n\t\tit(\"can fan in multiple nodes to a destination\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst context = input.context;\n\t\t\t\tconst gain0 = context.createGain();\n\t\t\t\tconst gain1 = context.createGain();\n\t\t\t\tconst output = context.destination;\n\t\t\t\tfanIn(gain0, gain1, input, output);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can connect one channel to another\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst context = input.context;\n\t\t\t\tconst output = input.context.destination;\n\t\t\t\tconst merge = context.createChannelMerger(2);\n\t\t\t\tconst split = context.createChannelSplitter(2);\n\t\t\t\tconnect(input, merge, 0, 1);\n\t\t\t\tconnect(merge, split, 0, 0);\n\t\t\t\tconnect(split, output, 1, 0);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can disconnect from an explicit channel\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst context = input.context;\n\t\t\t\tconst output = input.context.destination;\n\t\t\t\tconst merge = context.createChannelMerger(2);\n\t\t\t\tconst split = context.createChannelSplitter(2);\n\t\t\t\tconnect(input, merge, 0, 1);\n\t\t\t\tconnect(merge, split, 0, 0);\n\t\t\t\tconnect(split, output, 1, 0);\n\t\t\t\tdisconnect(split, output, 1, 0);\n\t\t\t}, false);\n\t\t});\n\n\t\tit(\"can disconnect from an audio param\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst osc = context.createOscillator();\n\t\t\t\tconst gain = context.createGain();\n\t\t\t\tconnect(gain, osc.frequency);\n\t\t\t\tdisconnect(gain, osc.frequency);\n\t\t\t});\n\t\t});\n\n\t\tit(\"throws an error if things aren't connected\", async () => {\n\t\t\tlet threwError = false;\n\t\t\tawait PassAudio((input) => {\n\t\t\t\tconst output = input.context.destination;\n\t\t\t\tdisconnect(input, output);\n\t\t\t}).catch(() => (threwError = true));\n\t\t\texpect(threwError).to.equal(true);\n\t\t});\n\n\t\tit(\"throws an error if the destination has no input\", () => {\n\t\t\tconst source = new Oscillator();\n\t\t\tconst gain = new Gain();\n\t\t\texpect(() => {\n\t\t\t\tgain.connect(source);\n\t\t\t}).to.throw(Error);\n\t\t\tgain.dispose();\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"throws an error if things aren't connected to a specific channel\", async () => {\n\t\t\tlet threwError = false;\n\t\t\tawait PassAudio((input) => {\n\t\t\t\tconst context = input.context;\n\t\t\t\tconst output = input.context.destination;\n\t\t\t\tconst merge = context.createChannelMerger(2);\n\t\t\t\tconst split = context.createChannelSplitter(2);\n\t\t\t\tconnect(input, merge, 0, 1);\n\t\t\t\tconnect(merge, split, 0, 0);\n\t\t\t\tconnect(split, output, 1, 0);\n\t\t\t\tdisconnect(split, output, 0, 0);\n\t\t\t}).catch(() => (threwError = true));\n\t\t\texpect(threwError).to.equal(true);\n\t\t});\n\t});\n\n\tcontext(\"ToneAudioNode\", () => {\n\t\tit(\"can create a connection\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst input = new Gain();\n\t\t\t\tconst output = new Gain();\n\t\t\t\tconst gain = new Gain();\n\t\t\t\tconnect(input, gain);\n\t\t\t\tconnect(gain, output);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can disconnect a node\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst input = new Gain();\n\t\t\t\tconst output = new Gain();\n\t\t\t\tconst gain = new Gain();\n\t\t\t\tconnect(input, gain);\n\t\t\t\tconnect(gain, output);\n\t\t\t\tdisconnect(gain);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can disconnect a node explicitly\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst input = new Gain();\n\t\t\t\tconst output = new Gain();\n\t\t\t\tconst gain = new Gain();\n\t\t\t\tconnect(input, gain);\n\t\t\t\tconnect(gain, output);\n\t\t\t\tdisconnect(gain, output);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can fan in multiple nodes to a destination\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst output = new Gain();\n\t\t\t\tconst input0 = new Gain();\n\t\t\t\tconst input1 = new Gain();\n\t\t\t\tconst input2 = new Gain();\n\t\t\t\tfanIn(input0, input1, input2, output);\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/context/ToneAudioNode.ts",
    "content": "import { isAudioNode, isAudioParam } from \"../util/AdvancedTypeCheck.js\";\nimport { assert, warn } from \"../util/Debug.js\";\nimport { isDefined } from \"../util/TypeCheck.js\";\nimport { Param } from \"./Param.js\";\nimport { ToneWithContext, ToneWithContextOptions } from \"./ToneWithContext.js\";\n\nexport type InputNode = ToneAudioNode | AudioNode | Param<any> | AudioParam;\nexport type OutputNode = ToneAudioNode | AudioNode;\n\ninterface ChannelProperties {\n\tchannelCount: number;\n\tchannelCountMode: ChannelCountMode;\n\tchannelInterpretation: ChannelInterpretation;\n}\n\n/**\n * The possible options for this node\n */\nexport type ToneAudioNodeOptions = ToneWithContextOptions;\n\n/**\n * ToneAudioNode is the base class for classes which process audio.\n * @category Core\n */\nexport abstract class ToneAudioNode<\n\tOptions extends ToneAudioNodeOptions = ToneAudioNodeOptions,\n> extends ToneWithContext<Options> {\n\t/**\n\t * The name of the class\n\t */\n\tabstract readonly name: string;\n\n\t/**\n\t * The input node or nodes. If the object is a source,\n\t * it does not have any input and this.input is undefined.\n\t */\n\tabstract input: InputNode | undefined;\n\n\t/**\n\t * The output nodes. If the object is a sink,\n\t * it does not have any output and this.output is undefined.\n\t */\n\tabstract output: OutputNode | undefined;\n\n\t/**\n\t * The number of inputs feeding into the AudioNode.\n\t * For source nodes, this will be 0.\n\t * @example\n\t * const node = new Tone.Gain();\n\t * console.log(node.numberOfInputs);\n\t */\n\tget numberOfInputs(): number {\n\t\tif (isDefined(this.input)) {\n\t\t\tif (isAudioParam(this.input) || this.input instanceof Param) {\n\t\t\t\treturn 1;\n\t\t\t} else {\n\t\t\t\treturn this.input.numberOfInputs;\n\t\t\t}\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t/**\n\t * The number of outputs of the AudioNode.\n\t * @example\n\t * const node = new Tone.Gain();\n\t * console.log(node.numberOfOutputs);\n\t */\n\tget numberOfOutputs(): number {\n\t\tif (isDefined(this.output)) {\n\t\t\treturn this.output.numberOfOutputs;\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t/**\n\t * List all of the node that must be set to match the ChannelProperties\n\t */\n\tprotected _internalChannels: OutputNode[] = [];\n\n\t//-------------------------------------\n\t// AUDIO PROPERTIES\n\t//-------------------------------------\n\n\t/**\n\t * Used to decide which nodes to get/set properties on\n\t */\n\tprivate _isAudioNode(node: any): node is AudioNode | ToneAudioNode {\n\t\treturn (\n\t\t\tisDefined(node) &&\n\t\t\t(node instanceof ToneAudioNode || isAudioNode(node))\n\t\t);\n\t}\n\n\t/**\n\t * Get all of the audio nodes (either internal or input/output) which together\n\t * make up how the class node responds to channel input/output\n\t */\n\tprivate _getInternalNodes(): OutputNode[] {\n\t\tconst nodeList = this._internalChannels.slice(0);\n\t\tif (this._isAudioNode(this.input)) {\n\t\t\tnodeList.push(this.input);\n\t\t}\n\t\tif (this._isAudioNode(this.output)) {\n\t\t\tif (this.input !== this.output) {\n\t\t\t\tnodeList.push(this.output);\n\t\t\t}\n\t\t}\n\t\treturn nodeList;\n\t}\n\n\t/**\n\t * Set the audio options for this node such as channelInterpretation\n\t * channelCount, etc.\n\t * @param options\n\t */\n\tprivate _setChannelProperties(options: ChannelProperties): void {\n\t\tconst nodeList = this._getInternalNodes();\n\t\tnodeList.forEach((node) => {\n\t\t\tnode.channelCount = options.channelCount;\n\t\t\tnode.channelCountMode = options.channelCountMode;\n\t\t\tnode.channelInterpretation = options.channelInterpretation;\n\t\t});\n\t}\n\n\t/**\n\t * Get the current audio options for this node such as channelInterpretation\n\t * channelCount, etc.\n\t */\n\tprivate _getChannelProperties(): ChannelProperties {\n\t\tconst nodeList = this._getInternalNodes();\n\t\tassert(\n\t\t\tnodeList.length > 0,\n\t\t\t\"ToneAudioNode does not have any internal nodes\"\n\t\t);\n\t\t// use the first node to get properties\n\t\t// they should all be the same\n\t\tconst node = nodeList[0];\n\t\treturn {\n\t\t\tchannelCount: node.channelCount,\n\t\t\tchannelCountMode: node.channelCountMode,\n\t\t\tchannelInterpretation: node.channelInterpretation,\n\t\t};\n\t}\n\n\t/**\n\t * channelCount is the number of channels used when up-mixing and down-mixing\n\t * connections to any inputs to the node. The default value is 2 except for\n\t * specific nodes where its value is specially determined.\n\t */\n\tget channelCount(): number {\n\t\treturn this._getChannelProperties().channelCount;\n\t}\n\tset channelCount(channelCount) {\n\t\tconst props = this._getChannelProperties();\n\t\t// merge it with the other properties\n\t\tthis._setChannelProperties(Object.assign(props, { channelCount }));\n\t}\n\n\t/**\n\t * channelCountMode determines how channels will be counted when up-mixing and\n\t * down-mixing connections to any inputs to the node.\n\t * The default value is \"max\". This attribute has no effect for nodes with no inputs.\n\t * * \"max\" - computedNumberOfChannels is the maximum of the number of channels of all connections to an input. In this mode channelCount is ignored.\n\t * * \"clamped-max\" - computedNumberOfChannels is determined as for \"max\" and then clamped to a maximum value of the given channelCount.\n\t * * \"explicit\" - computedNumberOfChannels is the exact value as specified by the channelCount.\n\t */\n\tget channelCountMode(): ChannelCountMode {\n\t\treturn this._getChannelProperties().channelCountMode;\n\t}\n\tset channelCountMode(channelCountMode) {\n\t\tconst props = this._getChannelProperties();\n\t\t// merge it with the other properties\n\t\tthis._setChannelProperties(Object.assign(props, { channelCountMode }));\n\t}\n\n\t/**\n\t * channelInterpretation determines how individual channels will be treated\n\t * when up-mixing and down-mixing connections to any inputs to the node.\n\t * The default value is \"speakers\".\n\t */\n\tget channelInterpretation(): ChannelInterpretation {\n\t\treturn this._getChannelProperties().channelInterpretation;\n\t}\n\tset channelInterpretation(channelInterpretation) {\n\t\tconst props = this._getChannelProperties();\n\t\t// merge it with the other properties\n\t\tthis._setChannelProperties(\n\t\t\tObject.assign(props, { channelInterpretation })\n\t\t);\n\t}\n\n\t//-------------------------------------\n\t// CONNECTIONS\n\t//-------------------------------------\n\n\t/**\n\t * connect the output of a ToneAudioNode to an AudioParam, AudioNode, or ToneAudioNode\n\t * @param destination The output to connect to\n\t * @param outputNum The output to connect from\n\t * @param inputNum The input to connect to\n\t */\n\tconnect(destination: InputNode, outputNum = 0, inputNum = 0): this {\n\t\tconnect(this, destination, outputNum, inputNum);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Connect the output to the context's destination node.\n\t * @example\n\t * const osc = new Tone.Oscillator(\"C2\").start();\n\t * osc.toDestination();\n\t */\n\ttoDestination(): this {\n\t\tthis.connect(this.context.destination);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Connect the output to the context's destination node.\n\t * @see {@link toDestination}\n\t * @deprecated\n\t */\n\ttoMaster(): this {\n\t\twarn(\"toMaster() has been renamed toDestination()\");\n\t\treturn this.toDestination();\n\t}\n\n\t/**\n\t * disconnect the output\n\t */\n\tdisconnect(destination?: InputNode, outputNum = 0, inputNum = 0): this {\n\t\tdisconnect(this, destination, outputNum, inputNum);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Connect the output of this node to the rest of the nodes in series.\n\t * @example\n\t * const player = new Tone.Player(\"https://tonejs.github.io/audio/drum-samples/handdrum-loop.mp3\");\n\t * player.autostart = true;\n\t * const filter = new Tone.AutoFilter(4).start();\n\t * const distortion = new Tone.Distortion(0.5);\n\t * // connect the player to the filter, distortion and then to the master output\n\t * player.chain(filter, distortion, Tone.Destination);\n\t */\n\tchain(...nodes: InputNode[]): this {\n\t\tconnectSeries(this, ...nodes);\n\t\treturn this;\n\t}\n\n\t/**\n\t * connect the output of this node to the rest of the nodes in parallel.\n\t * @example\n\t * const player = new Tone.Player(\"https://tonejs.github.io/audio/drum-samples/conga-rhythm.mp3\");\n\t * player.autostart = true;\n\t * const pitchShift = new Tone.PitchShift(4).toDestination();\n\t * const filter = new Tone.Filter(\"G5\").toDestination();\n\t * // connect a node to the pitch shift and filter in parallel\n\t * player.fan(pitchShift, filter);\n\t */\n\tfan(...nodes: InputNode[]): this {\n\t\tnodes.forEach((node) => this.connect(node));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Dispose and disconnect\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tif (isDefined(this.input)) {\n\t\t\tif (this.input instanceof ToneAudioNode) {\n\t\t\t\tthis.input.dispose();\n\t\t\t} else if (isAudioNode(this.input)) {\n\t\t\t\tthis.input.disconnect();\n\t\t\t}\n\t\t}\n\t\tif (isDefined(this.output)) {\n\t\t\tif (this.output instanceof ToneAudioNode) {\n\t\t\t\tthis.output.dispose();\n\t\t\t} else if (isAudioNode(this.output)) {\n\t\t\t\tthis.output.disconnect();\n\t\t\t}\n\t\t}\n\t\tthis._internalChannels = [];\n\t\treturn this;\n\t}\n}\n\n//-------------------------------------\n// CONNECTIONS\n//-------------------------------------\n\n/**\n * connect together all of the arguments in series\n * @param nodes\n */\nexport function connectSeries(...nodes: InputNode[]): void {\n\tconst first = nodes.shift();\n\tnodes.reduce((prev, current) => {\n\t\tif (prev instanceof ToneAudioNode) {\n\t\t\tprev.connect(current);\n\t\t} else if (isAudioNode(prev)) {\n\t\t\tconnect(prev, current);\n\t\t}\n\t\treturn current;\n\t}, first);\n}\n\n/**\n * Connect two nodes together so that signal flows from the\n * first node to the second. Optionally specify the input and output channels.\n * @param srcNode The source node\n * @param dstNode The destination node\n * @param outputNumber The output channel of the srcNode\n * @param inputNumber The input channel of the dstNode\n */\nexport function connect(\n\tsrcNode: OutputNode,\n\tdstNode: InputNode,\n\toutputNumber = 0,\n\tinputNumber = 0\n): void {\n\tassert(isDefined(srcNode), \"Cannot connect from undefined node\");\n\tassert(isDefined(dstNode), \"Cannot connect to undefined node\");\n\n\tif (dstNode instanceof ToneAudioNode || isAudioNode(dstNode)) {\n\t\tassert(\n\t\t\tdstNode.numberOfInputs > 0,\n\t\t\t\"Cannot connect to node with no inputs\"\n\t\t);\n\t}\n\tassert(\n\t\tsrcNode.numberOfOutputs > 0,\n\t\t\"Cannot connect from node with no outputs\"\n\t);\n\n\t// resolve the input of the dstNode\n\twhile (dstNode instanceof ToneAudioNode || dstNode instanceof Param) {\n\t\tif (isDefined(dstNode.input)) {\n\t\t\tdstNode = dstNode.input;\n\t\t}\n\t}\n\n\twhile (srcNode instanceof ToneAudioNode) {\n\t\tif (isDefined(srcNode.output)) {\n\t\t\tsrcNode = srcNode.output;\n\t\t}\n\t}\n\n\t// make the connection\n\tif (isAudioParam(dstNode)) {\n\t\tsrcNode.connect(dstNode as AudioParam, outputNumber);\n\t} else {\n\t\tsrcNode.connect(dstNode, outputNumber, inputNumber);\n\t}\n}\n\n/**\n * Disconnect a node from all nodes or optionally include a destination node and input/output channels.\n * @param srcNode The source node\n * @param dstNode The destination node\n * @param outputNumber The output channel of the srcNode\n * @param inputNumber The input channel of the dstNode\n */\nexport function disconnect(\n\tsrcNode: OutputNode,\n\tdstNode?: InputNode,\n\toutputNumber = 0,\n\tinputNumber = 0\n): void {\n\t// resolve the destination node\n\tif (isDefined(dstNode)) {\n\t\twhile (dstNode instanceof ToneAudioNode || dstNode instanceof Param) {\n\t\t\tdstNode = dstNode.input;\n\t\t}\n\t}\n\n\t// resolve the src node\n\twhile (!isAudioNode(srcNode)) {\n\t\tif (isDefined(srcNode.output)) {\n\t\t\tsrcNode = srcNode.output;\n\t\t}\n\t}\n\n\tif (isAudioParam(dstNode)) {\n\t\tsrcNode.disconnect(dstNode, outputNumber);\n\t} else if (isAudioNode(dstNode)) {\n\t\tsrcNode.disconnect(dstNode, outputNumber, inputNumber);\n\t} else {\n\t\tsrcNode.disconnect();\n\t}\n}\n\n/**\n * Connect the output of one or more source nodes to a single destination node\n * @param nodes One or more source nodes followed by one destination node\n * @example\n * const player = new Tone.Player(\"https://tonejs.github.io/audio/drum-samples/conga-rhythm.mp3\");\n * const player1 = new Tone.Player(\"https://tonejs.github.io/audio/drum-samples/conga-rhythm.mp3\");\n * const filter = new Tone.Filter(\"G5\").toDestination();\n * // connect nodes to a common destination\n * Tone.fanIn(player, player1, filter);\n */\nexport function fanIn(...nodes: OutputNode[]): void {\n\tconst dstNode = nodes.pop();\n\n\tif (isDefined(dstNode)) {\n\t\tnodes.forEach((node) => connect(node, dstNode));\n\t}\n}\n"
  },
  {
    "path": "Tone/core/context/ToneWithContext.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { getContext } from \"../Global.js\";\nimport { Gain } from \"./Gain.js\";\nimport { ToneWithContext } from \"./ToneWithContext.js\";\n\ndescribe(\"ToneWithContext\", () => {\n\tcontext(\"get\", () => {\n\t\tit(\"returns an object with all the default properties\", () => {\n\t\t\tconst gain = new Gain();\n\t\t\tconst values = gain.get();\n\t\t\texpect(values).to.be.an(\"object\");\n\t\t\texpect(values).to.have.property(\"gain\");\n\t\t\tgain.dispose();\n\t\t});\n\n\t\tit(\"reflects the current value of properties\", () => {\n\t\t\tconst gain = new Gain(0.3);\n\t\t\tconst values = gain.get();\n\t\t\texpect(values.gain).to.be.closeTo(0.3, 0.001);\n\t\t\tgain.dispose();\n\t\t});\n\t});\n\n\tcontext(\"set\", () => {\n\t\tit(\"sets properties with an object\", () => {\n\t\t\tconst gain = new Gain();\n\t\t\tgain.set({ gain: 0.5 });\n\t\t\texpect(gain.gain.value).to.be.closeTo(0.5, 0.001);\n\t\t\tgain.dispose();\n\t\t});\n\n\t\tit(\"returns the instance for chaining\", () => {\n\t\t\tconst gain = new Gain();\n\t\t\tconst returned = gain.set({ gain: 0.5 });\n\t\t\texpect(returned).to.equal(gain);\n\t\t\tgain.dispose();\n\t\t});\n\n\t\tit(\"does not set a value if it is the same\", () => {\n\t\t\tconst gain = new Gain(0.7);\n\t\t\tgain.set({ gain: 0.7 });\n\t\t\texpect(gain.gain.value).to.be.closeTo(0.7, 0.001);\n\t\t\tgain.dispose();\n\t\t});\n\t});\n\n\tcontext(\"getDefaults\", () => {\n\t\tit(\"returns defaults with a context\", () => {\n\t\t\tconst defaults = ToneWithContext.getDefaults();\n\t\t\texpect(defaults).to.have.property(\"context\");\n\t\t\texpect(defaults.context).to.equal(getContext());\n\t\t});\n\t});\n\n\tcontext(\"_onContextRunning\", () => {\n\t\tit(\"invokes the callback immediately for an offline context\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tlet callbackInvoked = false;\n\t\t\t\tconst gain = new Gain();\n\t\t\t\t// Access protected method via subclass trick\n\t\t\t\t(gain as any)._onContextRunning(() => {\n\t\t\t\t\tcallbackInvoked = true;\n\t\t\t\t});\n\t\t\t\texpect(callbackInvoked).to.equal(true);\n\t\t\t\tgain.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"cleans up the listener on dispose\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst gain = new Gain();\n\t\t\t\t(gain as any)._onContextRunning(() => {\n\t\t\t\t\t// no-op\n\t\t\t\t});\n\t\t\t\t// Should not throw when disposing\n\t\t\t\tgain.dispose();\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/context/ToneWithContext.ts",
    "content": "import { getContext } from \"../Global.js\";\nimport { Tone } from \"../Tone.js\";\nimport { FrequencyClass } from \"../type/Frequency.js\";\nimport { TimeClass } from \"../type/Time.js\";\nimport { TransportTimeClass } from \"../type/TransportTime.js\";\nimport { Frequency, Hertz, Seconds, Ticks, Time } from \"../type/Units.js\";\nimport { assertUsedScheduleTime } from \"../util/Debug.js\";\nimport {\n\tgetDefaultsFromInstance,\n\toptionsFromArguments,\n} from \"../util/Defaults.js\";\nimport { RecursivePartial } from \"../util/Interface.js\";\nimport {\n\tisArray,\n\tisBoolean,\n\tisDefined,\n\tisNumber,\n\tisString,\n\tisUndef,\n} from \"../util/TypeCheck.js\";\nimport { BaseContext } from \"./BaseContext.js\";\nimport { onContextRunning } from \"./OnRunning.js\";\n\n/**\n * A unit which process audio\n */\nexport interface ToneWithContextOptions {\n\tcontext: BaseContext;\n}\n\n/**\n * The Base class for all nodes that have an AudioContext.\n */\nexport abstract class ToneWithContext<\n\tOptions extends ToneWithContextOptions,\n> extends Tone {\n\t/**\n\t * The context belonging to the node.\n\t */\n\treadonly context: BaseContext;\n\n\t/**\n\t * The default context to use if no AudioContext is passed in to the constructor.\n\t * Probably should not be set manually. Used internally.\n\t * @hidden\n\t */\n\treadonly defaultContext?: BaseContext;\n\n\t/**\n\t * Pass in a constructor as the first argument\n\t */\n\tconstructor(context?: BaseContext);\n\tconstructor(options?: Partial<ToneWithContextOptions>);\n\tconstructor() {\n\t\tsuper();\n\t\tconst options = optionsFromArguments(\n\t\t\tToneWithContext.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"context\"]\n\t\t);\n\t\tif (this.defaultContext) {\n\t\t\tthis.context = this.defaultContext;\n\t\t} else {\n\t\t\tthis.context = options.context;\n\t\t}\n\t}\n\n\tstatic getDefaults(): ToneWithContextOptions {\n\t\treturn {\n\t\t\tcontext: getContext(),\n\t\t};\n\t}\n\n\t/**\n\t * Return the current time of the Context clock plus the lookAhead.\n\t * @example\n\t * setInterval(() => {\n\t * \tconsole.log(Tone.now());\n\t * }, 100);\n\t */\n\tnow(): Seconds {\n\t\treturn this.context.currentTime + this.context.lookAhead;\n\t}\n\n\t/**\n\t * Return the current time of the Context clock without any lookAhead.\n\t * @example\n\t * setInterval(() => {\n\t * \tconsole.log(Tone.immediate());\n\t * }, 100);\n\t */\n\timmediate(): Seconds {\n\t\treturn this.context.currentTime;\n\t}\n\n\t/**\n\t * The duration in seconds of one sample.\n\t */\n\tget sampleTime(): Seconds {\n\t\treturn 1 / this.context.sampleRate;\n\t}\n\n\t/**\n\t * The number of seconds of 1 processing block (128 samples)\n\t * @example\n\t * console.log(Tone.Destination.blockTime);\n\t */\n\tget blockTime(): Seconds {\n\t\treturn 128 / this.context.sampleRate;\n\t}\n\n\t/**\n\t * Convert the incoming time to seconds.\n\t * This is calculated against the current {@link TransportInstance} bpm\n\t * @example\n\t * const gain = new Tone.Gain();\n\t * setInterval(() => console.log(gain.toSeconds(\"4n\")), 100);\n\t * // ramp the tempo to 60 bpm over 30 seconds\n\t * Tone.getTransport().bpm.rampTo(60, 30);\n\t */\n\ttoSeconds(time?: Time): Seconds {\n\t\tassertUsedScheduleTime(time);\n\t\treturn new TimeClass(this.context, time).toSeconds();\n\t}\n\n\t/**\n\t * Convert the input to a frequency number\n\t * @example\n\t * const gain = new Tone.Gain();\n\t * console.log(gain.toFrequency(\"4n\"));\n\t */\n\ttoFrequency(freq: Frequency): Hertz {\n\t\treturn new FrequencyClass(this.context, freq).toFrequency();\n\t}\n\n\t/**\n\t * Convert the input time into ticks\n\t * @example\n\t * const gain = new Tone.Gain();\n\t * console.log(gain.toTicks(\"4n\"));\n\t */\n\ttoTicks(time?: Time | TimeClass): Ticks {\n\t\treturn new TransportTimeClass(this.context, time).toTicks();\n\t}\n\n\t//-------------------------------------\n\t// \tGET/SET\n\t//-------------------------------------\n\n\t/**\n\t * Get a subset of the properties which are in the partial props\n\t */\n\tprotected _getPartialProperties(props: Options): Partial<Options> {\n\t\tconst options = this.get();\n\t\t// remove attributes from the prop that are not in the partial\n\t\tObject.keys(options).forEach((name) => {\n\t\t\tif (isUndef(props[name])) {\n\t\t\t\tdelete options[name];\n\t\t\t}\n\t\t});\n\t\treturn options;\n\t}\n\n\t/**\n\t * Get the object's attributes.\n\t * @example\n\t * const osc = new Tone.Oscillator();\n\t * console.log(osc.get());\n\t */\n\tget(): Options {\n\t\tconst defaults = getDefaultsFromInstance(this) as Options;\n\t\tObject.keys(defaults).forEach((attribute) => {\n\t\t\tif (Reflect.has(this, attribute)) {\n\t\t\t\tconst member = this[attribute];\n\t\t\t\tif (\n\t\t\t\t\tisDefined(member) &&\n\t\t\t\t\tisDefined(member.value) &&\n\t\t\t\t\tisDefined(member.setValueAtTime)\n\t\t\t\t) {\n\t\t\t\t\tdefaults[attribute] = member.value;\n\t\t\t\t} else if (member instanceof ToneWithContext) {\n\t\t\t\t\tdefaults[attribute] = member._getPartialProperties(\n\t\t\t\t\t\tdefaults[attribute]\n\t\t\t\t\t);\n\t\t\t\t\t// otherwise make sure it's a serializable type\n\t\t\t\t} else if (\n\t\t\t\t\tisArray(member) ||\n\t\t\t\t\tisNumber(member) ||\n\t\t\t\t\tisString(member) ||\n\t\t\t\t\tisBoolean(member)\n\t\t\t\t) {\n\t\t\t\t\tdefaults[attribute] = member;\n\t\t\t\t} else {\n\t\t\t\t\t// remove all undefined and unserializable attributes\n\t\t\t\t\tdelete defaults[attribute];\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\treturn defaults;\n\t}\n\n\t/**\n\t * Set multiple properties at once with an object.\n\t * @example\n\t * const filter = new Tone.Filter().toDestination();\n\t * // set values using an object\n\t * filter.set({\n\t * \tfrequency: \"C6\",\n\t * \ttype: \"highpass\"\n\t * });\n\t * const player = new Tone.Player(\"https://tonejs.github.io/audio/berklee/Analogsynth_octaves_highmid.mp3\").connect(filter);\n\t * player.autostart = true;\n\t */\n\tset(props: RecursivePartial<Options>): this {\n\t\tObject.keys(props).forEach((attribute) => {\n\t\t\tif (Reflect.has(this, attribute) && isDefined(this[attribute])) {\n\t\t\t\tif (\n\t\t\t\t\tthis[attribute] &&\n\t\t\t\t\tisDefined(this[attribute].value) &&\n\t\t\t\t\tisDefined(this[attribute].setValueAtTime)\n\t\t\t\t) {\n\t\t\t\t\t// small optimization\n\t\t\t\t\tif (this[attribute].value !== props[attribute]) {\n\t\t\t\t\t\tthis[attribute].value = props[attribute];\n\t\t\t\t\t}\n\t\t\t\t} else if (this[attribute] instanceof ToneWithContext) {\n\t\t\t\t\tthis[attribute].set(props[attribute]);\n\t\t\t\t} else {\n\t\t\t\t\tthis[attribute] = props[attribute];\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\treturn this;\n\t}\n\n\t/**\n\t * Internal method which removes the onContextRunning callback.\n\t */\n\tprivate _removeOnContextRunning?: () => void;\n\n\t/**\n\t * Internal method which is called the first time the context is resumed.\n\t * Useful for setting up AudioNodes which should be running as soon\n\t * as the context is running, but should not be started until then.\n\t */\n\tprotected _onContextRunning(callback: () => void): void {\n\t\tthis._removeOnContextRunning = onContextRunning(this.context, callback);\n\t}\n\n\t/**\n\t * Dispose and disconnect\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._removeOnContextRunning?.();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/core/index.ts",
    "content": "export * from \"./clock/Clock.js\";\nexport * from \"./context/BaseContext.js\";\nexport * from \"./context/Context.js\";\nexport * from \"./context/Delay.js\";\nexport * from \"./context/Gain.js\";\nexport * from \"./context/Offline.js\";\nexport * from \"./context/OfflineContext.js\";\nexport * from \"./context/Param.js\";\nexport * from \"./context/ToneAudioBuffer.js\";\nexport * from \"./context/ToneAudioBuffers.js\";\nexport * from \"./context/ToneAudioNode.js\";\nexport * from \"./type/Frequency.js\";\nexport * from \"./type/Midi.js\";\nexport * from \"./type/Ticks.js\";\nexport * from \"./type/Time.js\";\nexport * from \"./type/TransportTime.js\";\n\nimport \"./util/Draw.js\";\nexport {\n\tdbToGain,\n\tftom,\n\tgainToDb,\n\tintervalToFrequencyRatio,\n\tmtof,\n} from \"./type/Conversions.js\";\nexport { defaultArg, optionsFromArguments } from \"./util/Defaults.js\";\nexport * from \"./util/Emitter.js\";\nexport * from \"./util/IntervalTimeline.js\";\nexport * from \"./util/StateTimeline.js\";\nexport * from \"./util/Timeline.js\";\nexport * from \"./util/TypeCheck.js\";\n\n// get the units and export them under the \"Unit\" namespace\nimport * as Unit from \"./type/Units.js\";\nexport { Unit };\n\n// export the debug stuff as Debug\nimport * as debug from \"./util/Debug.js\";\n/** @internal */\nexport { debug };\n"
  },
  {
    "path": "Tone/core/type/Conversions.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport {\n\tdbToGain,\n\tequalPowerScale,\n\tgainToDb,\n\tintervalToFrequencyRatio,\n} from \"./Conversions.js\";\n\ndescribe(\"Conversions\", () => {\n\tit(\"can convert equalPowerScale\", () => {\n\t\texpect(equalPowerScale(0.5)).to.be.closeTo(0.707, 0.001);\n\t\texpect(equalPowerScale(0.75)).to.be.closeTo(0.923, 0.001);\n\t});\n\n\tit(\"can convert gain to db\", () => {\n\t\texpect(gainToDb(0)).to.equal(-Infinity);\n\t\texpect(gainToDb(1)).is.closeTo(0, 0.1);\n\t\texpect(gainToDb(0.5)).is.closeTo(-6, 0.1);\n\t});\n\n\tit(\"can convert db to gain\", () => {\n\t\texpect(dbToGain(0)).is.closeTo(1, 0.1);\n\t\texpect(dbToGain(-12)).is.closeTo(0.25, 0.1);\n\t\texpect(dbToGain(-24)).is.closeTo(0.125, 0.1);\n\t});\n\n\tit(\"can convert back and forth between db and gain representations\", () => {\n\t\texpect(dbToGain(gainToDb(0))).is.closeTo(0, 0.01);\n\t\texpect(dbToGain(gainToDb(0.5))).is.closeTo(0.5, 0.01);\n\t\texpect(gainToDb(dbToGain(1))).is.closeTo(1, 0.01);\n\t});\n\n\tit(\"can convert semitone intervals to frequency ratios\", () => {\n\t\texpect(intervalToFrequencyRatio(0)).to.equal(1);\n\t\texpect(intervalToFrequencyRatio(12)).to.equal(2);\n\t\texpect(intervalToFrequencyRatio(7)).to.be.closeTo(1.5, 0.01);\n\t});\n});\n"
  },
  {
    "path": "Tone/core/type/Conversions.ts",
    "content": "import {\n\tDecibels,\n\tGainFactor,\n\tHertz,\n\tInterval,\n\tMidiNote,\n\tNormalRange,\n} from \"./Units.js\";\n\n/**\n * Equal power gain scale. Good for cross-fading.\n * @param  percent (0-1)\n */\nexport function equalPowerScale(percent: NormalRange): number {\n\tconst piFactor = 0.5 * Math.PI;\n\treturn Math.sin(percent * piFactor);\n}\n\n/**\n * Convert decibels into gain.\n */\nexport function dbToGain(db: Decibels): GainFactor {\n\treturn Math.pow(10, db / 20);\n}\n\n/**\n * Convert gain to decibels.\n */\nexport function gainToDb(gain: GainFactor): Decibels {\n\treturn 20 * (Math.log(gain) / Math.LN10);\n}\n\n/**\n * Convert an interval (in semitones) to a frequency ratio.\n * @param interval the number of semitones above the base note\n * @example\n * Tone.intervalToFrequencyRatio(0); // 1\n * Tone.intervalToFrequencyRatio(12); // 2\n * Tone.intervalToFrequencyRatio(-12); // 0.5\n */\nexport function intervalToFrequencyRatio(interval: Interval): number {\n\treturn Math.pow(2, interval / 12);\n}\n\n/**\n * The Global [concert tuning pitch](https://en.wikipedia.org/wiki/Concert_pitch) which is used\n * to generate all the other pitch values from notes. A4's values in Hertz.\n */\nlet A4: Hertz = 440;\n\nexport function getA4(): Hertz {\n\treturn A4;\n}\n\nexport function setA4(freq: Hertz): void {\n\tA4 = freq;\n}\n\n/**\n * Convert a frequency value to a MIDI note.\n * @param frequency The value to frequency value to convert.\n * @example\n * Tone.ftom(440); // returns 69\n */\nexport function ftom(frequency: Hertz): MidiNote {\n\treturn Math.round(ftomf(frequency)) as MidiNote;\n}\n\n/**\n * Convert a frequency to a floating point midi value\n */\nexport function ftomf(frequency: Hertz): number {\n\treturn 69 + 12 * Math.log2(frequency / A4);\n}\n\n/**\n * Convert a MIDI note to frequency value.\n * @param  midi The midi number to convert.\n * @return The corresponding frequency value\n * @example\n * Tone.mtof(69); // 440\n */\nexport function mtof(midi: MidiNote): Hertz {\n\treturn A4 * Math.pow(2, (midi - 69) / 12);\n}\n"
  },
  {
    "path": "Tone/core/type/Frequency.test.ts",
    "content": "import { expect } from \"chai\";\nimport { Midi as TonalMidi, Note } from \"tonal\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { getContext } from \"../Global.js\";\nimport { Frequency, FrequencyClass } from \"./Frequency.js\";\nimport { Midi } from \"./Midi.js\";\nimport { Ticks } from \"./Ticks.js\";\nimport { Time } from \"./Time.js\";\nimport { TransportTime } from \"./TransportTime.js\";\n\ndescribe(\"FrequencyClass\", () => {\n\tBasicTests(Frequency);\n\n\tcontext(\"Constructor\", () => {\n\t\tit(\"can be made with or without 'new'\", () => {\n\t\t\tconst f0 = Frequency();\n\t\t\texpect(f0).to.be.instanceOf(FrequencyClass);\n\t\t\tf0.dispose();\n\t\t\tconst f1 = new FrequencyClass(getContext());\n\t\t\texpect(f1).to.be.instanceOf(FrequencyClass);\n\t\t\tf1.dispose();\n\t\t});\n\n\t\tit(\"can pass in a number in the constructor\", () => {\n\t\t\tconst frequency = Frequency(1);\n\t\t\texpect(frequency).to.be.instanceOf(FrequencyClass);\n\t\t\tfrequency.dispose();\n\t\t});\n\n\t\tit(\"can pass in a string in the constructor\", () => {\n\t\t\tconst frequency = Frequency(\"1\");\n\t\t\texpect(frequency).to.be.instanceOf(FrequencyClass);\n\t\t\tfrequency.dispose();\n\t\t});\n\n\t\tit(\"can pass in a value and a type\", () => {\n\t\t\texpect(Frequency(4, \"n\").valueOf()).to.equal(2);\n\t\t});\n\n\t\tit(\"with no arguments evaluates to 0\", () => {\n\t\t\texpect(Frequency().valueOf()).to.equal(0);\n\t\t});\n\n\t\tit(\"is evaluated in equations and comparisons using valueOf\", () => {\n\t\t\t// @ts-ignore\n\t\t\texpect(Frequency(1) + 1).to.equal(2);\n\t\t\t// @ts-ignore\n\t\t\texpect(Frequency(1) + Frequency(1)).to.equal(2);\n\t\t\t// @ts-ignore\n\t\t\texpect(Frequency(1) > Frequency(0)).to.be.true;\n\t\t\t// @ts-ignore\n\t\t\texpect(+Frequency(1)).to.equal(1);\n\t\t});\n\n\t\tit(\"can convert from Time\", () => {\n\t\t\texpect(Frequency(Time(2)).valueOf()).to.equal(0.5);\n\t\t\texpect(Frequency(Time(\"4n\")).valueOf()).to.equal(2);\n\t\t\texpect(Frequency(Time(4, \"n\")).valueOf()).to.equal(2);\n\t\t});\n\n\t\tit(\"can convert from Frequency\", () => {\n\t\t\texpect(Frequency(Frequency(2)).valueOf()).to.equal(2);\n\t\t\texpect(Frequency(Frequency(\"4n\")).valueOf()).to.equal(2);\n\t\t\texpect(Frequency(Frequency(4, \"n\")).valueOf()).to.equal(2);\n\t\t});\n\n\t\tit(\"can convert from TransportTime\", () => {\n\t\t\texpect(Frequency(TransportTime(2)).valueOf()).to.equal(0.5);\n\t\t\texpect(Frequency(TransportTime(\"4n\")).valueOf()).to.equal(2);\n\t\t});\n\n\t\tit(\"can convert from Midi\", () => {\n\t\t\texpect(Frequency(Midi(\"C4\")).valueOf()).to.equal(\n\t\t\t\tFrequency(\"C4\").valueOf()\n\t\t\t);\n\t\t\texpect(Frequency(Midi(60)).valueOf()).to.equal(\n\t\t\t\tFrequency(\"C4\").valueOf()\n\t\t\t);\n\t\t\texpect(Frequency(Midi(61)).valueOf()).to.equal(\n\t\t\t\tFrequency(\"C#4\").valueOf()\n\t\t\t);\n\t\t});\n\n\t\tit(\"can convert from Ticks\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\texpect(Frequency(Ticks(transport.PPQ)).valueOf()).to.equal(2);\n\t\t\t\texpect(Frequency(Ticks(\"4n\")).valueOf()).to.equal(2);\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"Eval Types\", () => {\n\t\tit(\"evaluates numbers as frequency\", () => {\n\t\t\texpect(Frequency(\"1\").valueOf()).to.equal(1);\n\t\t\texpect(Frequency(\"123\").valueOf()).to.equal(123);\n\t\t\texpect(Frequency(3.2).valueOf()).to.equal(3.2);\n\t\t});\n\n\t\tit(\"evaluates notation\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\ttransport.bpm.value = 120;\n\t\t\t\ttransport.timeSignature = 4;\n\t\t\t\texpect(Frequency(\"4n\").valueOf()).to.equal(2);\n\t\t\t\texpect(Frequency(\"8n\").valueOf()).to.equal(4);\n\t\t\t\texpect(Frequency(16, \"n\").valueOf()).to.equal(8);\n\t\t\t\ttransport.bpm.value = 60;\n\t\t\t\ttransport.timeSignature = [5, 4];\n\t\t\t\texpect(Frequency(\"1m\").valueOf()).to.equal(1 / 5);\n\t\t\t\ttransport.bpm.value = 120;\n\t\t\t\ttransport.timeSignature = 4;\n\t\t\t});\n\t\t});\n\n\t\tit(\"evaluates hertz\", () => {\n\t\t\texpect(Frequency(\"1hz\").valueOf()).to.equal(1);\n\t\t\texpect(Frequency(\"2hz\").valueOf()).to.equal(2);\n\t\t\texpect(Frequency(4, \"hz\").valueOf()).to.equal(4);\n\t\t\texpect(Frequency(\"0.25hz\").valueOf()).to.equal(0.25);\n\t\t});\n\n\t\tit(\"evaluates ticks\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\texpect(Frequency(transport.PPQ, \"i\").valueOf()).to.equal(2);\n\t\t\t\texpect(Frequency(1, \"i\").valueOf()).to.equal(transport.PPQ * 2);\n\t\t\t});\n\t\t});\n\n\t\tit(\"evaluates transport time\", () => {\n\t\t\texpect(Frequency(\"1:0\").valueOf()).to.equal(0.5);\n\t\t\texpect(Frequency(\"1:4:0\").valueOf()).to.equal(0.25);\n\t\t\t// expect(Frequency(\"2:1:0\").valueOf()).to.equal(0.25);\n\t\t});\n\n\t\tit(\"evaluates midi\", () => {\n\t\t\texpect(Frequency(48, \"midi\").valueOf()).to.be.closeTo(\n\t\t\t\tTonalMidi.midiToFreq(48),\n\t\t\t\t0.0001\n\t\t\t);\n\t\t\texpect(Frequency(69, \"midi\").valueOf()).to.be.closeTo(\n\t\t\t\tTonalMidi.midiToFreq(69),\n\t\t\t\t0.0001\n\t\t\t);\n\t\t});\n\n\t\tit(\"evaluates hz\", () => {\n\t\t\texpect(Frequency(48, \"hz\").valueOf()).to.equal(48);\n\t\t\texpect(Frequency(480, \"hz\").valueOf()).to.equal(480);\n\t\t});\n\n\t\tit(\"can convert notes into frequencies\", () => {\n\t\t\texpect(Frequency(\"C4\").valueOf()).to.be.closeTo(\n\t\t\t\tNote.freq(\"C4\") as number,\n\t\t\t\t0.0001\n\t\t\t);\n\t\t\texpect(Frequency(\"D4\").valueOf()).to.be.closeTo(\n\t\t\t\tNote.freq(\"D4\") as number,\n\t\t\t\t0.0001\n\t\t\t);\n\t\t\texpect(Frequency(\"Db4\").valueOf()).to.be.closeTo(\n\t\t\t\tNote.freq(\"Db4\") as number,\n\t\t\t\t0.0001\n\t\t\t);\n\t\t\texpect(Frequency(\"E4\").valueOf()).to.be.closeTo(\n\t\t\t\tNote.freq(\"E4\") as number,\n\t\t\t\t0.0001\n\t\t\t);\n\t\t\texpect(Frequency(\"F2\").valueOf()).to.be.closeTo(\n\t\t\t\tNote.freq(\"F2\") as number,\n\t\t\t\t0.0001\n\t\t\t);\n\t\t\texpect(Frequency(\"Gb-1\").valueOf()).to.be.closeTo(\n\t\t\t\tNote.freq(\"Gb-1\") as number,\n\t\t\t\t0.0001\n\t\t\t);\n\t\t\texpect(Frequency(\"A#10\").valueOf()).to.be.closeTo(\n\t\t\t\tNote.freq(\"A#10\") as number,\n\t\t\t\t0.0001\n\t\t\t);\n\t\t\texpect(Frequency(\"Bb2\").valueOf()).to.be.closeTo(\n\t\t\t\tNote.freq(\"Bb2\") as number,\n\t\t\t\t0.0001\n\t\t\t);\n\t\t});\n\n\t\tit(\"handles double accidentals\", () => {\n\t\t\texpect(Frequency(\"Cbb4\").valueOf()).to.be.closeTo(\n\t\t\t\tNote.freq(\"Cbb4\") as number,\n\t\t\t\t0.0001\n\t\t\t);\n\t\t\texpect(Frequency(\"Dx4\").valueOf()).to.be.closeTo(\n\t\t\t\tNote.freq(\"Dx4\") as number,\n\t\t\t\t0.0001\n\t\t\t);\n\t\t\texpect(Frequency(\"Dbb4\").valueOf()).to.be.closeTo(\n\t\t\t\tNote.freq(\"Dbb4\") as number,\n\t\t\t\t0.0001\n\t\t\t);\n\t\t\texpect(Frequency(\"Ex4\").valueOf()).to.be.closeTo(\n\t\t\t\tNote.freq(\"Ex4\") as number,\n\t\t\t\t0.0001\n\t\t\t);\n\t\t\texpect(Frequency(\"Fx2\").valueOf()).to.be.closeTo(\n\t\t\t\tNote.freq(\"Fx2\") as number,\n\t\t\t\t0.0001\n\t\t\t);\n\t\t\texpect(Frequency(\"Gbb-1\").valueOf()).to.be.closeTo(\n\t\t\t\tNote.freq(\"Gbb-1\") as number,\n\t\t\t\t0.0001\n\t\t\t);\n\t\t\texpect(Frequency(\"Ax10\").valueOf()).to.be.closeTo(\n\t\t\t\tNote.freq(\"Ax10\") as number,\n\t\t\t\t0.0001\n\t\t\t);\n\t\t\texpect(Frequency(\"Bbb2\").valueOf()).to.be.closeTo(\n\t\t\t\tNote.freq(\"Bbb2\") as number,\n\t\t\t\t0.0001\n\t\t\t);\n\t\t});\n\n\t\tit(\"can accommodate different concert tuning\", () => {\n\t\t\tFrequencyClass.A4 = 444;\n\t\t\texpect(Frequency(\"C4\").valueOf()).to.be.closeTo(\n\t\t\t\tTonalMidi.midiToFreq(\n\t\t\t\t\tTonalMidi.toMidi(\"C4\") as number,\n\t\t\t\t\tFrequencyClass.A4\n\t\t\t\t),\n\t\t\t\t0.0001\n\t\t\t);\n\t\t\texpect(Frequency(\"D1\").valueOf()).to.be.closeTo(\n\t\t\t\tTonalMidi.midiToFreq(\n\t\t\t\t\tTonalMidi.toMidi(\"D1\") as number,\n\t\t\t\t\tFrequencyClass.A4\n\t\t\t\t),\n\t\t\t\t0.0001\n\t\t\t);\n\t\t\tFrequencyClass.A4 = 100;\n\t\t\texpect(Frequency(\"C4\").valueOf()).to.be.closeTo(\n\t\t\t\tTonalMidi.midiToFreq(\n\t\t\t\t\tTonalMidi.toMidi(\"C4\") as number,\n\t\t\t\t\tFrequencyClass.A4\n\t\t\t\t),\n\t\t\t\t0.0001\n\t\t\t);\n\t\t\t// return it to normal\n\t\t\tFrequencyClass.A4 = 440;\n\t\t});\n\t});\n\n\tcontext(\"transpose/harmonize\", () => {\n\t\tit(\"can transpose a value\", () => {\n\t\t\texpect(Frequency(\"A4\").transpose(3).toMidi()).to.equal(72);\n\t\t\texpect(Frequency(\"A4\").transpose(-3).toMidi()).to.equal(66);\n\t\t\texpect(Frequency(440).transpose(-12).valueOf()).to.equal(220);\n\t\t});\n\n\t\tit(\"can harmonize a value\", () => {\n\t\t\texpect(Frequency(\"A4\").harmonize([0, 3])).to.be.an(\"array\");\n\t\t\texpect(Frequency(\"A4\").harmonize([0, 3]).length).to.equal(2);\n\t\t\texpect(Frequency(\"A4\").harmonize([0, 3])[0].toNote()).to.equal(\n\t\t\t\t\"A4\"\n\t\t\t);\n\t\t\texpect(Frequency(\"A4\").harmonize([0, 3])[1].toNote()).to.equal(\n\t\t\t\t\"C5\"\n\t\t\t);\n\n\t\t\texpect(Frequency(\"A4\").harmonize([-12, 0, 12])).to.be.an(\"array\");\n\t\t\texpect(Frequency(\"A4\").harmonize([-12, 0, 12]).length).to.equal(3);\n\t\t\texpect(\n\t\t\t\tFrequency(\"A4\").harmonize([-12, 0, 12])[0].toNote()\n\t\t\t).to.equal(\"A3\");\n\t\t\texpect(\n\t\t\t\tFrequency(\"A4\").harmonize([-12, 0, 12])[1].toNote()\n\t\t\t).to.equal(\"A4\");\n\t\t\texpect(\n\t\t\t\tFrequency(\"A4\").harmonize([-12, 0, 12])[2].toNote()\n\t\t\t).to.equal(\"A5\");\n\t\t});\n\t});\n\n\tcontext(\"Conversions\", () => {\n\t\tit(\"can convert frequencies into notes\", () => {\n\t\t\texpect(Frequency(261.625).toNote()).to.equal(\n\t\t\t\tNote.fromFreq(261.625)\n\t\t\t);\n\t\t\texpect(Frequency(440).toNote()).to.equal(Note.fromFreq(440));\n\t\t\texpect(Frequency(220).toNote()).to.equal(Note.fromFreq(220));\n\t\t\texpect(Frequency(13.75).toNote()).to.equal(Note.fromFreq(13.75));\n\t\t\texpect(Frequency(4979).toNote()).to.equal(\"D#8\");\n\t\t});\n\n\t\tit(\"can convert note to midi values\", () => {\n\t\t\texpect(Frequency(\"C4\").toMidi()).to.equal(\n\t\t\t\tTonalMidi.toMidi(\"C4\") as number\n\t\t\t);\n\t\t\texpect(Frequency(\"C#0\").toMidi()).to.equal(\n\t\t\t\tTonalMidi.toMidi(\"C#0\") as number\n\t\t\t);\n\t\t\texpect(Frequency(\"A-1\").toMidi()).to.equal(\n\t\t\t\tTonalMidi.toMidi(\"A-1\") as number\n\t\t\t);\n\t\t});\n\n\t\tit(\"can convert hertz to seconds\", () => {\n\t\t\texpect(Frequency(4).toSeconds()).to.equal(0.25);\n\t\t\texpect(Frequency(\"2hz\").toSeconds()).to.equal(0.5);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/type/Frequency.ts",
    "content": "import { getContext } from \"../Global.js\";\nimport { intervalToFrequencyRatio, mtof } from \"./Conversions.js\";\nimport { ftom, getA4, setA4 } from \"./Conversions.js\";\nimport { TimeClass } from \"./Time.js\";\nimport { TimeBaseUnit, TimeExpression, TimeValue } from \"./TimeBase.js\";\nimport {\n\tFrequency,\n\tHertz,\n\tInterval,\n\tMidiNote,\n\tNote,\n\tSeconds,\n\tTicks,\n} from \"./Units.js\";\n\nexport type FrequencyUnit = TimeBaseUnit | \"midi\";\n\n/**\n * Frequency is a primitive type for encoding Frequency values.\n * Eventually all time values are evaluated to hertz using the `valueOf` method.\n * @example\n * Tone.Frequency(\"C3\"); // 261\n * Tone.Frequency(38, \"midi\");\n * Tone.Frequency(\"C3\").transpose(4);\n * @category Unit\n */\nexport class FrequencyClass<Type extends number = Hertz> extends TimeClass<\n\tType,\n\tFrequencyUnit\n> {\n\treadonly name: string = \"Frequency\";\n\n\treadonly defaultUnits: FrequencyUnit = \"hz\";\n\n\t/**\n\t * The [concert tuning pitch](https://en.wikipedia.org/wiki/Concert_pitch) which is used\n\t * to generate all the other pitch values from notes. A4's values in Hertz.\n\t */\n\tstatic get A4(): Hertz {\n\t\treturn getA4();\n\t}\n\tstatic set A4(freq: Hertz) {\n\t\tsetA4(freq);\n\t}\n\n\t//-------------------------------------\n\t// \tAUGMENT BASE EXPRESSIONS\n\t//-------------------------------------\n\n\tprotected _getExpressions(): TimeExpression<Type> {\n\t\treturn Object.assign({}, super._getExpressions(), {\n\t\t\tmidi: {\n\t\t\t\tregexp: /^(\\d+(?:\\.\\d+)?midi)/,\n\t\t\t\tmethod(value): number {\n\t\t\t\t\tif (this.defaultUnits === \"midi\") {\n\t\t\t\t\t\treturn value;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn FrequencyClass.mtof(value);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t\tnote: {\n\t\t\t\tregexp: /^([a-g]{1}(?:b|#|##|x|bb|###|#x|x#|bbb)?)(-?[0-9]+)/i,\n\t\t\t\tmethod(pitch, octave): number {\n\t\t\t\t\tconst index = noteToScaleIndex[pitch.toLowerCase()];\n\t\t\t\t\tconst noteNumber = index + (parseInt(octave, 10) + 1) * 12;\n\t\t\t\t\tif (this.defaultUnits === \"midi\") {\n\t\t\t\t\t\treturn noteNumber;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn FrequencyClass.mtof(noteNumber);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t\ttr: {\n\t\t\t\tregexp: /^(\\d+(?:\\.\\d+)?):(\\d+(?:\\.\\d+)?):?(\\d+(?:\\.\\d+)?)?/,\n\t\t\t\tmethod(m, q, s): number {\n\t\t\t\t\tlet total = 1;\n\t\t\t\t\tif (m && m !== \"0\") {\n\t\t\t\t\t\ttotal *= this._beatsToUnits(\n\t\t\t\t\t\t\tthis._getTimeSignature() * parseFloat(m)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (q && q !== \"0\") {\n\t\t\t\t\t\ttotal *= this._beatsToUnits(parseFloat(q));\n\t\t\t\t\t}\n\t\t\t\t\tif (s && s !== \"0\") {\n\t\t\t\t\t\ttotal *= this._beatsToUnits(parseFloat(s) / 4);\n\t\t\t\t\t}\n\t\t\t\t\treturn total;\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\t}\n\n\t//-------------------------------------\n\t// \tEXPRESSIONS\n\t//-------------------------------------\n\n\t/**\n\t * Transposes the frequency by the given number of semitones.\n\t * @return  A new transposed frequency\n\t * @example\n\t * Tone.Frequency(\"A4\").transpose(3); // \"C5\"\n\t */\n\ttranspose(interval: Interval): FrequencyClass {\n\t\treturn new FrequencyClass(\n\t\t\tthis.context,\n\t\t\tthis.valueOf() * intervalToFrequencyRatio(interval)\n\t\t);\n\t}\n\n\t/**\n\t * Takes an array of semitone intervals and returns\n\t * an array of frequencies transposed by those intervals.\n\t * @return  Returns an array of Frequencies\n\t * @example\n\t * Tone.Frequency(\"A4\").harmonize([0, 3, 7]); // [\"A4\", \"C5\", \"E5\"]\n\t */\n\tharmonize(intervals: Interval[]): FrequencyClass[] {\n\t\treturn intervals.map((interval) => {\n\t\t\treturn this.transpose(interval);\n\t\t});\n\t}\n\n\t//-------------------------------------\n\t// \tUNIT CONVERSIONS\n\t//-------------------------------------\n\n\t/**\n\t * Return the value of the frequency as a MIDI note\n\t * @example\n\t * Tone.Frequency(\"C4\").toMidi(); // 60\n\t */\n\ttoMidi(): MidiNote {\n\t\treturn ftom(this.valueOf());\n\t}\n\n\t/**\n\t * Return the value of the frequency in Scientific Pitch Notation\n\t * @example\n\t * Tone.Frequency(69, \"midi\").toNote(); // \"A4\"\n\t */\n\ttoNote(): Note {\n\t\tconst freq = this.toFrequency();\n\t\tconst log = Math.log2(freq / FrequencyClass.A4);\n\t\tlet noteNumber = Math.round(12 * log) + 57;\n\t\tconst octave = Math.floor(noteNumber / 12);\n\t\tif (octave < 0) {\n\t\t\tnoteNumber += -12 * octave;\n\t\t}\n\t\tconst noteName = scaleIndexToNote[noteNumber % 12];\n\t\treturn (noteName + octave.toString()) as Note;\n\t}\n\n\t/**\n\t * Return the duration of one cycle in seconds.\n\t */\n\ttoSeconds(): Seconds {\n\t\treturn 1 / super.toSeconds();\n\t}\n\n\t/**\n\t * Return the duration of one cycle in ticks\n\t */\n\ttoTicks(): Ticks {\n\t\tconst quarterTime = this._beatsToUnits(1);\n\t\tconst quarters = this.valueOf() / quarterTime;\n\t\treturn Math.floor(quarters * this._getPPQ());\n\t}\n\n\t//-------------------------------------\n\t// \tUNIT CONVERSIONS HELPERS\n\t//-------------------------------------\n\n\t/**\n\t * With no arguments, return 0\n\t */\n\tprotected _noArg(): Type {\n\t\treturn 0 as Type;\n\t}\n\n\t/**\n\t * Returns the value of a frequency in the current units\n\t */\n\tprotected _frequencyToUnits(freq: Hertz): Type {\n\t\treturn freq as Type;\n\t}\n\n\t/**\n\t * Returns the value of a tick in the current time units\n\t */\n\tprotected _ticksToUnits(ticks: Ticks): Type {\n\t\treturn (1 / ((ticks * 60) / (this._getBpm() * this._getPPQ()))) as Type;\n\t}\n\n\t/**\n\t * Return the value of the beats in the current units\n\t */\n\tprotected _beatsToUnits(beats: number): Type {\n\t\treturn (1 / super._beatsToUnits(beats)) as Type;\n\t}\n\n\t/**\n\t * Returns the value of a second in the current units\n\t */\n\tprotected _secondsToUnits(seconds: Seconds): Type {\n\t\treturn (1 / seconds) as Type;\n\t}\n\n\t/**\n\t * Convert a MIDI note to frequency value.\n\t * @param  midi The midi number to convert.\n\t * @return The corresponding frequency value\n\t */\n\tstatic mtof(midi: MidiNote): Hertz {\n\t\treturn mtof(midi);\n\t}\n\n\t/**\n\t * Convert a frequency value to a MIDI note.\n\t * @param frequency The value to frequency value to convert.\n\t */\n\tstatic ftom(frequency: Hertz): MidiNote {\n\t\treturn ftom(frequency);\n\t}\n}\n\n//-------------------------------------\n// \tFREQUENCY CONVERSIONS\n//-------------------------------------\n\n/**\n * Note to scale index.\n * @hidden\n */\nconst noteToScaleIndex = {\n\tcbbb: -3,\n\tcbb: -2,\n\tcb: -1,\n\tc: 0,\n\t\"c#\": 1,\n\tcx: 2,\n\t\"c##\": 2,\n\t\"c###\": 3,\n\t\"cx#\": 3,\n\t\"c#x\": 3,\n\tdbbb: -1,\n\tdbb: 0,\n\tdb: 1,\n\td: 2,\n\t\"d#\": 3,\n\tdx: 4,\n\t\"d##\": 4,\n\t\"d###\": 5,\n\t\"dx#\": 5,\n\t\"d#x\": 5,\n\tebbb: 1,\n\tebb: 2,\n\teb: 3,\n\te: 4,\n\t\"e#\": 5,\n\tex: 6,\n\t\"e##\": 6,\n\t\"e###\": 7,\n\t\"ex#\": 7,\n\t\"e#x\": 7,\n\tfbbb: 2,\n\tfbb: 3,\n\tfb: 4,\n\tf: 5,\n\t\"f#\": 6,\n\tfx: 7,\n\t\"f##\": 7,\n\t\"f###\": 8,\n\t\"fx#\": 8,\n\t\"f#x\": 8,\n\tgbbb: 4,\n\tgbb: 5,\n\tgb: 6,\n\tg: 7,\n\t\"g#\": 8,\n\tgx: 9,\n\t\"g##\": 9,\n\t\"g###\": 10,\n\t\"gx#\": 10,\n\t\"g#x\": 10,\n\tabbb: 6,\n\tabb: 7,\n\tab: 8,\n\ta: 9,\n\t\"a#\": 10,\n\tax: 11,\n\t\"a##\": 11,\n\t\"a###\": 12,\n\t\"ax#\": 12,\n\t\"a#x\": 12,\n\tbbbb: 8,\n\tbbb: 9,\n\tbb: 10,\n\tb: 11,\n\t\"b#\": 12,\n\tbx: 13,\n\t\"b##\": 13,\n\t\"b###\": 14,\n\t\"bx#\": 14,\n\t\"b#x\": 14,\n};\n\n/**\n * scale index to note (sharps)\n * @hidden\n */\nconst scaleIndexToNote = [\n\t\"C\",\n\t\"C#\",\n\t\"D\",\n\t\"D#\",\n\t\"E\",\n\t\"F\",\n\t\"F#\",\n\t\"G\",\n\t\"G#\",\n\t\"A\",\n\t\"A#\",\n\t\"B\",\n];\n\n/**\n * Convert a value into a FrequencyClass object.\n * @category Unit\n * @example\n * const midi = Tone.Frequency(\"C3\").toMidi();\n * console.log(midi);\n * @example\n * const hertz = Tone.Frequency(38, \"midi\").toFrequency();\n * console.log(hertz);\n */\nexport function Frequency(\n\tvalue?: TimeValue | Frequency,\n\tunits?: FrequencyUnit\n): FrequencyClass {\n\treturn new FrequencyClass(getContext(), value, units);\n}\n"
  },
  {
    "path": "Tone/core/type/Midi.test.ts",
    "content": "import { expect } from \"chai\";\nimport { Midi as TonalMidi } from \"tonal\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { Frequency } from \"./Frequency.js\";\nimport { Midi, MidiClass } from \"./Midi.js\";\nimport { Ticks } from \"./Ticks.js\";\nimport { Time } from \"./Time.js\";\nimport { TransportTime } from \"./TransportTime.js\";\n\ndescribe(\"MidiClass\", () => {\n\tBasicTests(MidiClass);\n\n\tcontext(\"Constructor\", () => {\n\t\tit(\"can pass in a number in the constructor\", () => {\n\t\t\tconst midi = Midi(1);\n\t\t\texpect(midi).to.be.instanceOf(MidiClass);\n\t\t\tmidi.dispose();\n\t\t});\n\n\t\tit(\"can pass in a string in the constructor\", () => {\n\t\t\tconst midi = Midi(\"1\");\n\t\t\texpect(midi).to.be.instanceOf(MidiClass);\n\t\t\tmidi.dispose();\n\t\t});\n\n\t\tit(\"can pass in a value and a type\", () => {\n\t\t\texpect(Midi(128, \"n\").valueOf()).to.equal(36);\n\t\t});\n\n\t\tit(\"with no arguments evaluates to 0\", () => {\n\t\t\texpect(Midi().valueOf()).to.equal(0);\n\t\t});\n\n\t\tit(\"is evaluated in equations and comparisons using valueOf\", () => {\n\t\t\t// @ts-ignore\n\t\t\texpect(Midi(1) + 1).to.equal(2);\n\t\t\t// @ts-ignore\n\t\t\texpect(Midi(1) + Midi(1)).to.equal(2);\n\t\t\t// @ts-ignore\n\t\t\texpect(Midi(1) > Midi(0)).to.be.true;\n\t\t\t// @ts-ignore\n\t\t\texpect(+Midi(1)).to.equal(1);\n\t\t});\n\n\t\tit(\"can convert from seconds\", () => {\n\t\t\texpect(Midi(\"0.1s\").valueOf()).to.equal(3);\n\t\t\texpect(Midi(\"0.05s\").valueOf()).to.equal(15);\n\t\t\texpect(Midi(0.05, \"s\").valueOf()).to.equal(15);\n\t\t});\n\n\t\tit(\"can convert from hertz\", () => {\n\t\t\texpect(Midi(\"440hz\").valueOf()).to.equal(69);\n\t\t\texpect(Midi(220, \"hz\").valueOf()).to.equal(57);\n\t\t});\n\n\t\tit(\"can convert from ticks\", () => {\n\t\t\texpect(Midi(\"1i\").valueOf()).to.equal(67);\n\t\t\texpect(Midi(2, \"i\").valueOf()).to.equal(55);\n\t\t});\n\n\t\tit(\"can convert from Time\", () => {\n\t\t\texpect(Midi(Time(0.01)).valueOf()).to.equal(43);\n\t\t\texpect(Midi(Time(\"128n\")).valueOf()).to.equal(36);\n\t\t\texpect(Midi(Time(128, \"n\")).valueOf()).to.equal(36);\n\t\t});\n\n\t\tit(\"can convert from Midi\", () => {\n\t\t\texpect(Midi(Midi(2)).valueOf()).to.equal(2);\n\t\t\texpect(Midi(Midi(\"64n\")).valueOf()).to.equal(24);\n\t\t\texpect(Midi(Midi(64, \"n\")).valueOf()).to.equal(24);\n\t\t});\n\n\t\tit(\"can convert from Frequency\", () => {\n\t\t\texpect(Midi(Frequency(\"C4\")).valueOf()).to.equal(60);\n\t\t\texpect(Midi(Frequency(\"64n\")).valueOf()).to.equal(24);\n\t\t\texpect(Midi(Frequency(64, \"n\")).valueOf()).to.equal(24);\n\t\t});\n\n\t\tit(\"can convert from TransportTime\", () => {\n\t\t\texpect(Midi(TransportTime(0.01)).valueOf()).to.equal(43);\n\t\t\texpect(Midi(TransportTime(\"256n\")).valueOf()).to.equal(48);\n\t\t});\n\n\t\tit(\"can convert from Ticks\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\texpect(Midi(Ticks(transport.PPQ)).valueOf()).to.equal(-24);\n\t\t\t\texpect(Midi(Ticks(\"4n\")).valueOf()).to.equal(-24);\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"Conversions\", () => {\n\t\tit(\"can convert frequencies into notes\", () => {\n\t\t\texpect(Midi(48).toNote()).to.equal(TonalMidi.midiToNoteName(48));\n\t\t\texpect(Midi(90).toNote()).to.equal(\n\t\t\t\tTonalMidi.midiToNoteName(90, { sharps: true })\n\t\t\t);\n\t\t\texpect(Midi(\"C#4\").toNote()).to.equal(\"C#4\");\n\t\t});\n\n\t\tit(\"can convert note to midi values\", () => {\n\t\t\texpect(Midi(\"C4\").toMidi()).to.equal(TonalMidi.toMidi(\"C4\"));\n\t\t\texpect(Midi(\"C#0\").toMidi()).to.equal(TonalMidi.toMidi(\"C#0\"));\n\t\t\texpect(Midi(\"A-1\").toMidi()).to.equal(TonalMidi.toMidi(\"A-1\"));\n\t\t});\n\n\t\tit(\"can convert midi to frequency\", () => {\n\t\t\texpect(Midi(60).toFrequency()).to.equal(TonalMidi.midiToFreq(60));\n\t\t\texpect(Midi(25).toFrequency()).to.equal(TonalMidi.midiToFreq(25));\n\t\t\texpect(Midi(108).toFrequency()).to.equal(TonalMidi.midiToFreq(108));\n\t\t});\n\t});\n\n\tcontext(\"transpose/harmonize\", () => {\n\t\tit(\"can transpose a value\", () => {\n\t\t\texpect(Midi(\"A4\").transpose(3).toMidi()).to.equal(72);\n\t\t\texpect(Midi(\"A4\").transpose(-3).toMidi()).to.equal(66);\n\t\t\texpect(Midi(69).transpose(-12).valueOf()).to.equal(57);\n\t\t});\n\n\t\tit(\"can harmonize a value\", () => {\n\t\t\texpect(Midi(\"A4\").harmonize([0, 3])).to.be.an(\"array\");\n\t\t\texpect(Midi(\"A4\").harmonize([0, 3]).length).to.equal(2);\n\t\t\texpect(Midi(\"A4\").harmonize([0, 3])[0].toNote()).to.equal(\"A4\");\n\t\t\texpect(Midi(\"A4\").harmonize([0, 3])[1].toNote()).to.equal(\"C5\");\n\n\t\t\texpect(Midi(\"A4\").harmonize([-12, 0, 12])).to.be.an(\"array\");\n\t\t\texpect(Midi(\"A4\").harmonize([-12, 0, 12]).length).to.equal(3);\n\t\t\texpect(Midi(\"A4\").harmonize([-12, 0, 12])[0].toNote()).to.equal(\n\t\t\t\t\"A3\"\n\t\t\t);\n\t\t\texpect(Midi(\"A4\").harmonize([-12, 0, 12])[1].toNote()).to.equal(\n\t\t\t\t\"A4\"\n\t\t\t);\n\t\t\texpect(Midi(\"A4\").harmonize([-12, 0, 12])[2].toNote()).to.equal(\n\t\t\t\t\"A5\"\n\t\t\t);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/type/Midi.ts",
    "content": "import { getContext } from \"../Global.js\";\nimport { ftom, mtof } from \"./Conversions.js\";\nimport { FrequencyClass, FrequencyUnit } from \"./Frequency.js\";\nimport { TimeValue } from \"./TimeBase.js\";\nimport { Hertz, Interval, MidiNote, Seconds, Ticks } from \"./Units.js\";\n\n/**\n * Midi is a primitive type for encoding Time values.\n * Midi can be constructed with or without the `new` keyword. Midi can be passed\n * into the parameter of any method which takes time as an argument.\n * @category Unit\n */\nexport class MidiClass extends FrequencyClass<MidiNote> {\n\treadonly name: string = \"MidiClass\";\n\n\treadonly defaultUnits = \"midi\";\n\n\t/**\n\t * Returns the value of a frequency in the current units\n\t */\n\tprotected _frequencyToUnits(freq: Hertz): MidiNote {\n\t\treturn ftom(super._frequencyToUnits(freq));\n\t}\n\n\t/**\n\t * Returns the value of a tick in the current time units\n\t */\n\tprotected _ticksToUnits(ticks: Ticks): MidiNote {\n\t\treturn ftom(super._ticksToUnits(ticks));\n\t}\n\n\t/**\n\t * Return the value of the beats in the current units\n\t */\n\tprotected _beatsToUnits(beats: number): MidiNote {\n\t\treturn ftom(super._beatsToUnits(beats));\n\t}\n\n\t/**\n\t * Returns the value of a second in the current units\n\t */\n\tprotected _secondsToUnits(seconds: Seconds): MidiNote {\n\t\treturn ftom(super._secondsToUnits(seconds));\n\t}\n\n\t/**\n\t * Return the value of the frequency as a MIDI note\n\t * @example\n\t * Tone.Midi(60).toMidi(); // 60\n\t */\n\ttoMidi(): MidiNote {\n\t\treturn this.valueOf();\n\t}\n\n\t/**\n\t * Return the value of the frequency as a MIDI note\n\t * @example\n\t * Tone.Midi(60).toFrequency(); // 261.6255653005986\n\t */\n\ttoFrequency(): Hertz {\n\t\treturn mtof(this.toMidi());\n\t}\n\n\t/**\n\t * Transposes the frequency by the given number of semitones.\n\t * @return A new transposed MidiClass\n\t * @example\n\t * Tone.Midi(\"A4\").transpose(3); // \"C5\"\n\t */\n\ttranspose(interval: Interval): MidiClass {\n\t\treturn new MidiClass(this.context, this.toMidi() + interval);\n\t}\n}\n\n/**\n * Convert a value into a FrequencyClass object.\n * @category Unit\n */\nexport function Midi(value?: TimeValue, units?: FrequencyUnit): MidiClass {\n\treturn new MidiClass(getContext(), value, units);\n}\n"
  },
  {
    "path": "Tone/core/type/NoteUnits.ts",
    "content": "// This file contains all of the valid note names for all pitches between C-4 and C11\n\ntype Letter = \"C\" | \"D\" | \"E\" | \"F\" | \"G\" | \"A\" | \"B\";\ntype Accidental = \"bb\" | \"b\" | \"\" | \"#\" | \"x\";\ntype Octave =\n\t| -4\n\t| -3\n\t| -2\n\t| -1\n\t| 0\n\t| 1\n\t| 2\n\t| 3\n\t| 4\n\t| 5\n\t| 6\n\t| 7\n\t| 8\n\t| 9\n\t| 10\n\t| 11;\n\n/**\n * A note in Scientific pitch notation.\n * The pitch class + octave number\n * e.g. \"C4\", \"D#3\", \"G-1\"\n * @category Unit\n */\nexport type Note = `${Letter}${Accidental}${Octave}`;\n\ntype IntegerRange<\n\tN extends number,\n\tA extends any[] = [],\n> = A[\"length\"] extends N ? A[number] : IntegerRange<N, [...A, A[\"length\"]]>;\n\n/**\n * A number representing a midi note. Integers between 0-127\n * @category Unit\n */\nexport type MidiNote = IntegerRange<128>;\n"
  },
  {
    "path": "Tone/core/type/Ticks.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { atTime, Offline } from \"../../../test/helper/Offline.js\";\nimport { getContext } from \"../Global.js\";\nimport { Frequency } from \"./Frequency.js\";\nimport { Ticks, TicksClass } from \"./Ticks.js\";\nimport { Time } from \"./Time.js\";\nimport { TransportTime } from \"./TransportTime.js\";\n\ndescribe(\"TicksClass\", () => {\n\tBasicTests(Ticks);\n\n\tcontext(\"Constructor\", () => {\n\t\tit(\"can be made with or without 'new'\", () => {\n\t\t\tconst t0 = Ticks();\n\t\t\texpect(t0).to.be.instanceOf(TicksClass);\n\t\t\tt0.dispose();\n\t\t\tconst t1 = new TicksClass(getContext());\n\t\t\texpect(t1).to.be.instanceOf(TicksClass);\n\t\t\tt1.dispose();\n\t\t});\n\n\t\tit(\"can pass in a number in the constructor\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst time = Ticks(1);\n\t\t\t\texpect(time).to.be.instanceOf(TicksClass);\n\t\t\t\texpect(time.valueOf()).to.equal(1);\n\t\t\t\ttime.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can pass in a string in the constructor\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst time = Ticks(\"1\");\n\t\t\t\texpect(time).to.be.instanceOf(TicksClass);\n\t\t\t\texpect(time.valueOf()).to.equal(1);\n\t\t\t\ttime.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can pass in a value and a type\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\texpect(Ticks(4, \"m\").valueOf()).to.equal(transport.PPQ * 16);\n\t\t\t});\n\t\t});\n\n\t\tit(\"with no arguments evaluates to 0 when the transport is stopped\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\texpect(Ticks().valueOf()).to.equal(0);\n\t\t\t});\n\t\t});\n\n\t\tit(\"with no arguments evaluates to the current ticks when the transport is started\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tcontext.transport.start();\n\t\t\t\treturn atTime(0.29, () => {\n\t\t\t\t\texpect(new TicksClass(context).valueOf()).to.equal(\n\t\t\t\t\t\tcontext.transport.ticks\n\t\t\t\t\t);\n\t\t\t\t\tcontext.transport.stop();\n\t\t\t\t});\n\t\t\t}, 0.3);\n\t\t});\n\n\t\tit(\"is evaluated in equations and comparisons using valueOf\", () => {\n\t\t\t// @ts-ignore\n\t\t\texpect(Ticks(\"1i\") + 1).to.equal(2);\n\t\t\t// @ts-ignore\n\t\t\texpect(Ticks(\"1i\") + Ticks(\"1i\")).to.equal(2);\n\t\t\texpect(Ticks(\"1i\") > Ticks(0)).to.be.true;\n\t\t\texpect(+Ticks(\"1i\")).to.equal(1);\n\t\t});\n\n\t\tit(\"can convert from Time\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\texpect(Ticks(Time(2)).valueOf()).to.equal(transport.PPQ * 4);\n\t\t\t\texpect(Ticks(Time(\"4n\")).valueOf()).to.equal(transport.PPQ);\n\t\t\t\texpect(Ticks(Time(4, \"n\")).valueOf()).to.equal(transport.PPQ);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can convert from Frequency\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\texpect(Ticks(Frequency(2)).valueOf()).to.equal(transport.PPQ);\n\t\t\t\texpect(Ticks(Frequency(\"4n\")).valueOf()).to.equal(\n\t\t\t\t\ttransport.PPQ\n\t\t\t\t);\n\t\t\t\texpect(Ticks(Frequency(4, \"n\")).valueOf()).to.equal(\n\t\t\t\t\ttransport.PPQ\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can convert from TransportTime\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\texpect(Ticks(TransportTime(2)).valueOf()).to.equal(\n\t\t\t\t\ttransport.PPQ * 4\n\t\t\t\t);\n\t\t\t\texpect(Ticks(TransportTime(\"4n\")).valueOf()).to.equal(\n\t\t\t\t\ttransport.PPQ\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can convert from Ticks\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\texpect(Ticks(Ticks(transport.PPQ)).valueOf()).to.equal(\n\t\t\t\t\ttransport.PPQ\n\t\t\t\t);\n\t\t\t\texpect(Ticks(Ticks(\"4n\")).valueOf()).to.equal(transport.PPQ);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can convert from an Object\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\texpect(Ticks({ \"4n\": 2 }).valueOf()).to.equal(\n\t\t\t\t\ttransport.PPQ * 2\n\t\t\t\t);\n\t\t\t\texpect(Ticks({ \"1n\": 1, \"8t\": 2 }).valueOf()).to.equal(\n\t\t\t\t\ttransport.PPQ * 4 + transport.PPQ * (2 / 3)\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"Quantizes values\", () => {\n\t\tit(\"can quantize values\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\texpect(Ticks(\"4t\").quantize(\"4n\").valueOf()).to.be.closeTo(\n\t\t\t\t\ttransport.PPQ,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get the next subdivision when the transport is started\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = context.transport;\n\t\t\t\ttransport.start();\n\t\t\t\treturn atTime(0.59, () => {\n\t\t\t\t\texpect(\n\t\t\t\t\t\tnew TicksClass(context, \"@1m\").valueOf()\n\t\t\t\t\t).to.be.closeTo(4 * transport.PPQ, 1);\n\t\t\t\t\texpect(\n\t\t\t\t\t\tnew TicksClass(context, \"@4n\").valueOf()\n\t\t\t\t\t).to.be.closeTo(transport.PPQ * 2, 1);\n\t\t\t\t});\n\t\t\t}, 0.6);\n\t\t});\n\t});\n\n\tcontext(\"Operators\", () => {\n\t\tit(\"can add the current time\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tcontext.transport.start();\n\t\t\t\treturn atTime(0.59, () => {\n\t\t\t\t\tconst now = context.transport.ticks;\n\t\t\t\t\texpect(\n\t\t\t\t\t\tnew TicksClass(context, \"+4i\").valueOf()\n\t\t\t\t\t).to.be.closeTo(4 + now, 0.01);\n\t\t\t\t\texpect(\n\t\t\t\t\t\tnew TicksClass(context, \"+2n\").valueOf()\n\t\t\t\t\t).to.be.closeTo(context.transport.PPQ * 2 + now, 0.01);\n\t\t\t\t\texpect(\n\t\t\t\t\t\tnew TicksClass(context, \"+2n\").valueOf()\n\t\t\t\t\t).to.be.closeTo(context.transport.PPQ * 2 + now, 0.01);\n\t\t\t\t\tcontext.transport.stop();\n\t\t\t\t});\n\t\t\t}, 0.6);\n\t\t});\n\t});\n\n\tcontext(\"Conversions\", () => {\n\t\tit(\"converts time into notation\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\ttransport.bpm.value = 120;\n\t\t\t\ttransport.timeSignature = 4;\n\t\t\t\texpect(Ticks(\"4n\").toNotation()).to.equal(\"4n\");\n\t\t\t\t// expect(Ticks(1.5 * transport.PPQ).toNotation()).to.equal(\"2n + 4n\");\n\t\t\t\texpect(Ticks(0).toNotation()).to.equal(\"0\");\n\t\t\t\t// expect(Ticks(\"1:2:3\").toNotation()).to.equal(\"1m + 2n + 8n + 16n\");\n\t\t\t});\n\t\t});\n\n\t\tit(\"converts time into samples\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\texpect(Ticks(transport.PPQ).toSamples()).to.equal(\n\t\t\t\t\t0.5 * getContext().sampleRate\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\n\t\tit(\"converts time into frequency\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\texpect(Ticks(transport.PPQ * 4).toFrequency()).to.equal(0.5);\n\t\t\t\texpect(Ticks(\"2n\").toFrequency()).to.equal(1);\n\t\t\t});\n\t\t});\n\n\t\tit(\"converts time into seconds\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\texpect(Ticks(\"2n\").toSeconds()).to.equal(1);\n\t\t\t});\n\t\t});\n\n\t\tit(\"converts time into BarsBeatsSixteenths\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\texpect(Ticks(\"3:1:3\").toBarsBeatsSixteenths()).to.equal(\n\t\t\t\t\t\"3:1:3\"\n\t\t\t\t);\n\t\t\t\texpect(\n\t\t\t\t\tTicks(4 * transport.PPQ).toBarsBeatsSixteenths()\n\t\t\t\t).to.equal(\"1:0:0\");\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/type/Ticks.ts",
    "content": "import { getContext } from \"../Global.js\";\nimport { TimeBaseUnit, TimeValue } from \"./TimeBase.js\";\nimport { TransportTimeClass } from \"./TransportTime.js\";\nimport { Seconds, Ticks } from \"./Units.js\";\n\n/**\n * Ticks is a primitive type for encoding Time values.\n * Ticks can be constructed with or without the `new` keyword. Ticks can be passed\n * into the parameter of any method which takes time as an argument.\n * @example\n * const t = Tone.Ticks(\"4n\"); // a quarter note as ticks\n * @category Unit\n */\nexport class TicksClass extends TransportTimeClass<Ticks> {\n\treadonly name: string = \"Ticks\";\n\n\treadonly defaultUnits: TimeBaseUnit = \"i\";\n\n\t/**\n\t * Get the current time in the given units\n\t */\n\tprotected _now(): Ticks {\n\t\treturn this.context.transport.ticks;\n\t}\n\n\t/**\n\t * Return the value of the beats in the current units\n\t */\n\tprotected _beatsToUnits(beats: number): Ticks {\n\t\treturn this._getPPQ() * beats;\n\t}\n\n\t/**\n\t * Returns the value of a second in the current units\n\t */\n\tprotected _secondsToUnits(seconds: Seconds): Ticks {\n\t\treturn Math.floor((seconds / (60 / this._getBpm())) * this._getPPQ());\n\t}\n\n\t/**\n\t * Returns the value of a tick in the current time units\n\t */\n\tprotected _ticksToUnits(ticks: Ticks): Ticks {\n\t\treturn ticks;\n\t}\n\n\t/**\n\t * Return the time in ticks\n\t */\n\ttoTicks(): Ticks {\n\t\treturn this.valueOf() as Ticks;\n\t}\n\n\t/**\n\t * Return the time in seconds\n\t */\n\ttoSeconds(): Seconds {\n\t\treturn (this.valueOf() / this._getPPQ()) * (60 / this._getBpm());\n\t}\n}\n\n/**\n * Convert a time representation to ticks\n * @category Unit\n */\nexport function Ticks(value?: TimeValue, units?: TimeBaseUnit): TicksClass {\n\treturn new TicksClass(getContext(), value, units);\n}\n"
  },
  {
    "path": "Tone/core/type/Time.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { atTime, Offline } from \"../../../test/helper/Offline.js\";\nimport { getContext } from \"../Global.js\";\nimport { Frequency } from \"./Frequency.js\";\nimport { Ticks } from \"./Ticks.js\";\nimport { Time, TimeClass } from \"./Time.js\";\nimport { TransportTime } from \"./TransportTime.js\";\n\ndescribe(\"TimeClass\", () => {\n\tBasicTests(TimeClass);\n\n\tcontext(\"Constructor\", () => {\n\t\tit(\"can be used as a function or instantiated\", () => {\n\t\t\tconst t0 = Time();\n\t\t\texpect(t0).to.be.instanceOf(TimeClass);\n\t\t\tt0.dispose();\n\t\t\tconst t1 = new TimeClass(getContext());\n\t\t\texpect(t1).to.be.instanceOf(TimeClass);\n\t\t\tt1.dispose();\n\t\t});\n\n\t\tit(\"can pass in a number in the constructor\", () => {\n\t\t\tconst time = Time(1);\n\t\t\texpect(time.valueOf()).to.equal(1);\n\t\t\texpect(time).to.be.instanceOf(TimeClass);\n\t\t\ttime.dispose();\n\t\t});\n\n\t\tit(\"can pass in a string in the constructor\", () => {\n\t\t\tconst time = Time(\"1\");\n\t\t\texpect(time.valueOf()).to.equal(1);\n\t\t\texpect(time).to.be.instanceOf(TimeClass);\n\t\t\ttime.dispose();\n\t\t});\n\n\t\tit(\"can pass in a value and a type\", () => {\n\t\t\texpect(Time(4, \"m\").valueOf()).to.equal(8);\n\t\t});\n\n\t\tit(\"with no arguments evaluates to 'now'\", () => {\n\t\t\tconst now = getContext().now();\n\t\t\texpect(Time().valueOf()).to.be.closeTo(now, 0.01);\n\t\t});\n\n\t\tit(\"is evaluated in equations and comparisons using valueOf\", () => {\n\t\t\texpect(Time(1).valueOf() + 1).to.equal(2);\n\t\t\texpect(Time(1).valueOf() + Time(1).valueOf()).to.equal(2);\n\t\t\texpect(Time(1) > Time(0)).to.equal(true);\n\t\t\texpect(+Time(1)).to.equal(1);\n\t\t});\n\n\t\tit(\"can convert from Time\", () => {\n\t\t\texpect(Time(Time(2)).valueOf()).to.equal(2);\n\t\t\texpect(Time(\"4n\").valueOf()).to.equal(0.5);\n\t\t});\n\n\t\tit(\"can convert from Frequency\", () => {\n\t\t\texpect(Time(Frequency(2)).valueOf()).to.equal(0.5);\n\t\t\texpect(Time(Frequency(\"4n\")).valueOf()).to.equal(0.5);\n\t\t});\n\n\t\tit(\"can convert from TransportTime\", () => {\n\t\t\texpect(Time(TransportTime(2)).valueOf()).to.equal(2);\n\t\t\texpect(Time(TransportTime(\"4n\")).valueOf()).to.equal(0.5);\n\t\t});\n\n\t\tit(\"can convert from Ticks\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\texpect(Time(Ticks(transport.PPQ)).valueOf()).to.equal(0.5);\n\t\t\t\texpect(Time(Ticks(\"4n\")).valueOf()).to.equal(0.5);\n\t\t\t});\n\t\t});\n\n\t\tit(\"evaluates objects\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\texpect(Time({ \"4n\": 3 }).valueOf()).to.equal(1.5);\n\t\t\t\texpect(Time({ \"8t\": 2, \"1m\": 3 }).valueOf()).to.be.closeTo(\n\t\t\t\t\t6.33,\n\t\t\t\t\t0.01\n\t\t\t\t);\n\t\t\t\texpect(Time({ \"2n\": 1, \"8n\": 1.5 }).valueOf()).to.equal(1.375);\n\t\t\t\texpect(Time({ \"2n\": 1, \"8n\": -1 }).valueOf()).to.equal(0.75);\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"Quantizes values\", () => {\n\t\tit(\"returns the time quantized to the a subdivision\", () => {\n\t\t\texpect(Time(1.1).quantize(0.5).valueOf()).to.be.closeTo(1, 0.01);\n\t\t\texpect(Time(2.3).quantize(0.5).valueOf()).to.be.closeTo(2.5, 0.01);\n\t\t\texpect(Time(0).quantize(4).valueOf()).to.be.closeTo(0, 0.01);\n\t\t});\n\n\t\tit(\"can quantize with a percentage\", () => {\n\t\t\texpect(Time(4).quantize(8, 0.5).valueOf()).to.equal(6);\n\t\t\texpect(Time(10).quantize(8, 0.5).valueOf()).to.equal(9);\n\t\t\texpect(Time(2).quantize(8, 0.75).valueOf()).to.equal(0.5);\n\t\t});\n\n\t\tit(\"can get the next subdivision when the transport is started\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = context.transport;\n\t\t\t\ttransport.start(0.1);\n\t\t\t\treturn atTime(0.69, () => {\n\t\t\t\t\texpect(\n\t\t\t\t\t\tnew TimeClass(context, \"@1m\").valueOf()\n\t\t\t\t\t).to.be.closeTo(2.1, 0.01);\n\t\t\t\t\texpect(\n\t\t\t\t\t\tnew TimeClass(context, \"@4n\").valueOf()\n\t\t\t\t\t).to.be.closeTo(1.1, 0.01);\n\t\t\t\t\texpect(\n\t\t\t\t\t\tnew TimeClass(context, \"@8n\").valueOf()\n\t\t\t\t\t).to.be.closeTo(0.85, 0.01);\n\t\t\t\t});\n\t\t\t}, 0.7);\n\t\t});\n\t});\n\n\tcontext(\"Operators\", () => {\n\t\tit(\"can add the current time\", () => {\n\t\t\tconst now = getContext().now();\n\t\t\texpect(Time(\"+4\").valueOf()).to.be.closeTo(4 + now, 0.02);\n\t\t\texpect(Time(\"+2n\").valueOf()).to.be.closeTo(1 + now, 0.02);\n\t\t});\n\n\t\tit(\"can quantize the value\", () => {\n\t\t\texpect(Time(4).quantize(3)).to.equal(3);\n\t\t\texpect(Time(5).quantize(3)).to.equal(6);\n\t\t});\n\t});\n\n\tcontext(\"Conversions\", () => {\n\t\tit(\"converts time into notation\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\texpect(Time(\"4n\").toNotation()).to.equal(\"4n\");\n\t\t\t\texpect(Time(1.5).toNotation()).to.equal(\"2n.\");\n\t\t\t\texpect(Time(0).toNotation()).to.equal(\"0\");\n\t\t\t\texpect(Time(\"1:2:3\").toNotation()).to.equal(\"1m\");\n\t\t\t\texpect(\n\t\t\t\t\tTime(\n\t\t\t\t\t\tTime(\"2n\").valueOf() + Time(\"4n\").valueOf()\n\t\t\t\t\t).toNotation()\n\t\t\t\t).to.equal(\"2n.\");\n\t\t\t});\n\t\t});\n\n\t\tit(\"converts time into milliseconds\", () => {\n\t\t\texpect(Time(2).toMilliseconds()).to.equal(2000);\n\t\t\texpect(Time(\"4n\").toMilliseconds()).to.equal(500);\n\t\t});\n\n\t\tit(\"converts time into samples\", () => {\n\t\t\texpect(Time(2).toSamples()).to.equal(2 * getContext().sampleRate);\n\t\t});\n\n\t\tit(\"converts time into frequency\", () => {\n\t\t\texpect(Time(2).toFrequency()).to.equal(0.5);\n\t\t});\n\n\t\tit(\"converts time into ticks\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\texpect(Time(\"2n\").toTicks()).to.closeTo(2 * transport.PPQ, 0.1);\n\t\t\t\t// floating point checks\n\t\t\t\tconst bpmOrig = transport.bpm.value;\n\t\t\t\ttransport.bpm.value = 100;\n\t\t\t\texpect(Time(\"0:1:3\").toTicks()).to.closeTo(\n\t\t\t\t\t1.75 * transport.PPQ,\n\t\t\t\t\t0.1\n\t\t\t\t);\n\t\t\t\ttransport.bpm.value = bpmOrig;\n\t\t\t});\n\t\t});\n\n\t\tit(\"converts time into BarsBeatsSixteenths\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\texpect(Time(\"3:1:3\").toBarsBeatsSixteenths()).to.equal(\"3:1:3\");\n\t\t\t\texpect(Time(2).toBarsBeatsSixteenths()).to.equal(\"1:0:0\");\n\t\t\t\t// trailing zero removal test\n\t\t\t\ttransport.bpm.value = 100;\n\t\t\t\texpect(Time(\"0:1:3\").toBarsBeatsSixteenths()).to.equal(\"0:1:3\");\n\t\t\t\texpect(Time(\"14:0:0\").toBarsBeatsSixteenths()).to.equal(\n\t\t\t\t\t\"14:0:0\"\n\t\t\t\t);\n\t\t\t\texpect(Time(\"15:0:0\").toBarsBeatsSixteenths()).to.equal(\n\t\t\t\t\t\"15:0:0\"\n\t\t\t\t);\n\t\t\t\ttransport.bpm.value = 90;\n\t\t\t\texpect(Time(\"100:0:0\").toBarsBeatsSixteenths()).to.equal(\n\t\t\t\t\t\"100:0:0\"\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/type/Time.ts",
    "content": "import { getContext } from \"../Global.js\";\nimport { ftom } from \"./Conversions.js\";\nimport {\n\tTimeBaseClass,\n\tTimeBaseUnit,\n\tTimeExpression,\n\tTimeValue,\n} from \"./TimeBase.js\";\nimport {\n\tBarsBeatsSixteenths,\n\tMidiNote,\n\tSeconds,\n\tSubdivision,\n\tTicks,\n\tTime,\n} from \"./Units.js\";\n\n/**\n * TimeClass is a primitive type for encoding and decoding Time values.\n * TimeClass can be passed into the parameter of any method which takes time as an argument.\n * @param  val    The time value.\n * @param  units  The units of the value.\n * @example\n * const time = Tone.Time(\"4n\"); // a quarter note\n * @category Unit\n */\nexport class TimeClass<\n\tType extends Seconds | Ticks = Seconds,\n\tUnit extends string = TimeBaseUnit,\n> extends TimeBaseClass<Type, Unit> {\n\treadonly name: string = \"TimeClass\";\n\n\tprotected _getExpressions(): TimeExpression<Type> {\n\t\treturn Object.assign(super._getExpressions(), {\n\t\t\tnow: {\n\t\t\t\tmethod: (capture: string): Type => {\n\t\t\t\t\treturn (this._now() +\n\t\t\t\t\t\tnew (this.constructor as typeof TimeClass)(\n\t\t\t\t\t\t\tthis.context,\n\t\t\t\t\t\t\tcapture\n\t\t\t\t\t\t).valueOf()) as Type;\n\t\t\t\t},\n\t\t\t\tregexp: /^\\+(.+)/,\n\t\t\t},\n\t\t\tquantize: {\n\t\t\t\tmethod: (capture: string): Type => {\n\t\t\t\t\tconst quantTo = new TimeClass(\n\t\t\t\t\t\tthis.context,\n\t\t\t\t\t\tcapture\n\t\t\t\t\t).valueOf();\n\t\t\t\t\treturn this._secondsToUnits(\n\t\t\t\t\t\tthis.context.transport.nextSubdivision(quantTo)\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\tregexp: /^@(.+)/,\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Quantize the time by the given subdivision. Optionally add a\n\t * percentage which will move the time value towards the ideal\n\t * quantized value by that percentage.\n\t * @param  subdiv    The subdivision to quantize to\n\t * @param  percent  Move the time value towards the quantized value by a percentage.\n\t * @example\n\t * Tone.Time(21).quantize(2); // returns 22\n\t * Tone.Time(0.6).quantize(\"4n\", 0.5); // returns 0.55\n\t */\n\tquantize(subdiv: Time, percent = 1): Type {\n\t\tconst subdivision = new (this.constructor as typeof TimeClass)(\n\t\t\tthis.context,\n\t\t\tsubdiv\n\t\t).valueOf();\n\t\tconst value = this.valueOf();\n\t\tconst multiple = Math.round(value / subdivision);\n\t\tconst ideal = multiple * subdivision;\n\t\tconst diff = ideal - value;\n\t\treturn (value + diff * percent) as Type;\n\t}\n\n\t//-------------------------------------\n\t// CONVERSIONS\n\t//-------------------------------------\n\t/**\n\t * Convert a Time to Notation. The notation values are will be the\n\t * closest representation between 1m to 128th note.\n\t * @return {Notation}\n\t * @example\n\t * // if the Transport is at 120bpm:\n\t * Tone.Time(2).toNotation(); // returns \"1m\"\n\t */\n\ttoNotation(): Subdivision {\n\t\tconst time = this.toSeconds();\n\t\tconst testNotations: Subdivision[] = [\"1m\"];\n\t\tfor (let power = 1; power < 9; power++) {\n\t\t\tconst subdiv = Math.pow(2, power);\n\t\t\ttestNotations.push((subdiv + \"n.\") as Subdivision);\n\t\t\ttestNotations.push((subdiv + \"n\") as Subdivision);\n\t\t\ttestNotations.push((subdiv + \"t\") as Subdivision);\n\t\t}\n\t\ttestNotations.push(\"0\");\n\t\t// find the closets notation representation\n\t\tlet closest = testNotations[0];\n\t\tlet closestSeconds = new TimeClass(\n\t\t\tthis.context,\n\t\t\ttestNotations[0]\n\t\t).toSeconds();\n\t\ttestNotations.forEach((notation) => {\n\t\t\tconst notationSeconds = new TimeClass(\n\t\t\t\tthis.context,\n\t\t\t\tnotation\n\t\t\t).toSeconds();\n\t\t\tif (\n\t\t\t\tMath.abs(notationSeconds - time) <\n\t\t\t\tMath.abs(closestSeconds - time)\n\t\t\t) {\n\t\t\t\tclosest = notation;\n\t\t\t\tclosestSeconds = notationSeconds;\n\t\t\t}\n\t\t});\n\t\treturn closest;\n\t}\n\n\t/**\n\t * Return the time encoded as Bars:Beats:Sixteenths.\n\t */\n\ttoBarsBeatsSixteenths(): BarsBeatsSixteenths {\n\t\tconst quarterTime = this._beatsToUnits(1);\n\t\tlet quarters = this.valueOf() / quarterTime;\n\t\tquarters = parseFloat(quarters.toFixed(4));\n\t\tconst measures = Math.floor(quarters / this._getTimeSignature());\n\t\tlet sixteenths = (quarters % 1) * 4;\n\t\tquarters = Math.floor(quarters) % this._getTimeSignature();\n\t\tconst sixteenthString = sixteenths.toString();\n\t\tif (sixteenthString.length > 3) {\n\t\t\t// the additional parseFloat removes insignificant trailing zeroes\n\t\t\tsixteenths = parseFloat(parseFloat(sixteenthString).toFixed(3));\n\t\t}\n\t\tconst progress = [measures, quarters, sixteenths];\n\t\treturn progress.join(\":\") as BarsBeatsSixteenths;\n\t}\n\n\t/**\n\t * Return the time in ticks.\n\t */\n\ttoTicks(): Ticks {\n\t\tconst quarterTime = this._beatsToUnits(1);\n\t\tconst quarters = this.valueOf() / quarterTime;\n\t\treturn quarters * this._getPPQ();\n\t}\n\n\t/**\n\t * Return the time in seconds.\n\t */\n\ttoSeconds(): Seconds {\n\t\treturn this.valueOf();\n\t}\n\n\t/**\n\t * Return the value as a midi note.\n\t */\n\ttoMidi(): MidiNote {\n\t\treturn ftom(this.toFrequency());\n\t}\n\n\tprotected _now(): Type {\n\t\treturn this.context.now() as Type;\n\t}\n}\n\n/**\n * Create a TimeClass from a time string or number. The time is computed against the\n * global Tone.Context. To use a specific context, use {@link TimeClass}\n * @param value A value which represents time\n * @param units The value's units if they can't be inferred by the value.\n * @category Unit\n * @example\n * const time = Tone.Time(\"4n\").toSeconds();\n * console.log(time);\n * @example\n * const note = Tone.Time(1).toNotation();\n * console.log(note);\n * @example\n * const freq = Tone.Time(0.5).toFrequency();\n * console.log(freq);\n */\nexport function Time(\n\tvalue?: TimeValue,\n\tunits?: TimeBaseUnit\n): TimeClass<Seconds> {\n\treturn new TimeClass(getContext(), value, units);\n}\n"
  },
  {
    "path": "Tone/core/type/TimeBase.ts",
    "content": "import { BaseContext } from \"../context/BaseContext.js\";\nimport { Tone } from \"../Tone.js\";\nimport { isDefined, isObject, isString, isUndef } from \"../util/TypeCheck.js\";\nimport {\n\tBPM,\n\tHertz,\n\tMidiNote,\n\tMilliseconds,\n\tSamples,\n\tSeconds,\n\tTicks,\n\tTime,\n} from \"./Units.js\";\n\nexport type TimeValue = Time | TimeBaseClass<any, any>;\n\n/**\n * The units that the TimeBase can accept. extended by other classes\n */\nexport type TimeBaseUnit =\n\t| \"s\"\n\t| \"n\"\n\t| \"t\"\n\t| \"m\"\n\t| \"i\"\n\t| \"hz\"\n\t| \"tr\"\n\t| \"samples\"\n\t| \"number\";\n\nexport interface TypeFunction {\n\tregexp: RegExp;\n\tmethod: (value: string, ...args: string[]) => number;\n}\n\nexport interface TimeExpression<Type extends number> {\n\t[key: string]: {\n\t\tregexp: RegExp;\n\t\tmethod: (value: string, ...args: string[]) => Type;\n\t};\n}\n\n/**\n * TimeBase is a flexible encoding of time which can be evaluated to and from a string.\n */\nexport abstract class TimeBaseClass<\n\tType extends number,\n\tUnit extends string,\n> extends Tone {\n\treadonly context: BaseContext;\n\n\t/**\n\t * The value of the units\n\t */\n\tprotected _val?: TimeValue;\n\n\t/**\n\t * The units of time\n\t */\n\tprotected _units?: Unit;\n\n\t/**\n\t * All of the conversion expressions\n\t */\n\tprotected _expressions: TimeExpression<Type>;\n\n\t/**\n\t * The default units\n\t */\n\treadonly defaultUnits: Unit = \"s\" as Unit;\n\n\t/**\n\t * @param context The context associated with the time value. Used to compute\n\t * Transport and context-relative timing.\n\t * @param  value  The time value as a number, string or object\n\t * @param  units  Unit values\n\t */\n\tconstructor(context: BaseContext, value?: TimeValue, units?: Unit) {\n\t\tsuper();\n\n\t\tthis._val = value;\n\t\tthis._units = units;\n\t\tthis.context = context;\n\t\tthis._expressions = this._getExpressions();\n\t}\n\n\t/**\n\t * All of the time encoding expressions\n\t */\n\tprotected _getExpressions(): TimeExpression<Type> {\n\t\treturn {\n\t\t\thz: {\n\t\t\t\tmethod: (value) => {\n\t\t\t\t\treturn this._frequencyToUnits(parseFloat(value));\n\t\t\t\t},\n\t\t\t\tregexp: /^(\\d+(?:\\.\\d+)?)hz$/i,\n\t\t\t},\n\t\t\ti: {\n\t\t\t\tmethod: (value) => {\n\t\t\t\t\treturn this._ticksToUnits(parseInt(value, 10));\n\t\t\t\t},\n\t\t\t\tregexp: /^(\\d+)i$/i,\n\t\t\t},\n\t\t\tm: {\n\t\t\t\tmethod: (value) => {\n\t\t\t\t\treturn this._beatsToUnits(\n\t\t\t\t\t\tparseInt(value, 10) * this._getTimeSignature()\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\tregexp: /^(\\d+)m$/i,\n\t\t\t},\n\t\t\tn: {\n\t\t\t\tmethod: (value, dot) => {\n\t\t\t\t\tconst numericValue = parseInt(value, 10);\n\t\t\t\t\tconst scalar = dot === \".\" ? 1.5 : 1;\n\t\t\t\t\tif (numericValue === 1) {\n\t\t\t\t\t\treturn (this._beatsToUnits(this._getTimeSignature()) *\n\t\t\t\t\t\t\tscalar) as Type;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn (this._beatsToUnits(4 / numericValue) *\n\t\t\t\t\t\t\tscalar) as Type;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tregexp: /^(\\d+)n(\\.?)$/i,\n\t\t\t},\n\t\t\tnumber: {\n\t\t\t\tmethod: (value) => {\n\t\t\t\t\treturn this._expressions[this.defaultUnits].method.call(\n\t\t\t\t\t\tthis,\n\t\t\t\t\t\tvalue\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\tregexp: /^(\\d+(?:\\.\\d+)?)$/,\n\t\t\t},\n\t\t\ts: {\n\t\t\t\tmethod: (value): Type => {\n\t\t\t\t\treturn this._secondsToUnits(parseFloat(value));\n\t\t\t\t},\n\t\t\t\tregexp: /^(\\d+(?:\\.\\d+)?)s$/,\n\t\t\t},\n\t\t\tsamples: {\n\t\t\t\tmethod: (value) => {\n\t\t\t\t\treturn (parseInt(value, 10) /\n\t\t\t\t\t\tthis.context.sampleRate) as Type;\n\t\t\t\t},\n\t\t\t\tregexp: /^(\\d+)samples$/,\n\t\t\t},\n\t\t\tt: {\n\t\t\t\tmethod: (value) => {\n\t\t\t\t\tconst numericValue = parseInt(value, 10);\n\t\t\t\t\treturn this._beatsToUnits(\n\t\t\t\t\t\t8 / (Math.floor(numericValue) * 3)\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\tregexp: /^(\\d+)t$/i,\n\t\t\t},\n\t\t\ttr: {\n\t\t\t\tmethod: (m, q, s) => {\n\t\t\t\t\tlet total = 0;\n\t\t\t\t\tif (m && m !== \"0\") {\n\t\t\t\t\t\ttotal += this._beatsToUnits(\n\t\t\t\t\t\t\tthis._getTimeSignature() * parseFloat(m)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (q && q !== \"0\") {\n\t\t\t\t\t\ttotal += this._beatsToUnits(parseFloat(q));\n\t\t\t\t\t}\n\t\t\t\t\tif (s && s !== \"0\") {\n\t\t\t\t\t\ttotal += this._beatsToUnits(parseFloat(s) / 4);\n\t\t\t\t\t}\n\t\t\t\t\treturn total as Type;\n\t\t\t\t},\n\t\t\t\tregexp: /^(\\d+(?:\\.\\d+)?):(\\d+(?:\\.\\d+)?):?(\\d+(?:\\.\\d+)?)?$/,\n\t\t\t},\n\t\t};\n\t}\n\n\t//-------------------------------------\n\t// \tVALUE OF\n\t//-------------------------------------\n\n\t/**\n\t * Evaluate the time value. Returns the time in seconds.\n\t */\n\tvalueOf(): Type {\n\t\tif (this._val instanceof TimeBaseClass) {\n\t\t\tthis.fromType(this._val);\n\t\t}\n\t\tif (isUndef(this._val)) {\n\t\t\treturn this._noArg();\n\t\t} else if (isString(this._val) && isUndef(this._units)) {\n\t\t\tfor (const units in this._expressions) {\n\t\t\t\tif (this._expressions[units].regexp.test(this._val.trim())) {\n\t\t\t\t\tthis._units = units as Unit;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (isObject(this._val)) {\n\t\t\tlet total = 0;\n\t\t\tfor (const typeName in this._val) {\n\t\t\t\tif (isDefined(this._val[typeName])) {\n\t\t\t\t\tconst quantity = this._val[typeName];\n\t\t\t\t\tconst time =\n\t\t\t\t\t\t// @ts-ignore\n\t\t\t\t\t\tnew this.constructor(this.context, typeName).valueOf() *\n\t\t\t\t\t\tquantity;\n\t\t\t\t\ttotal += time;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn total as Type;\n\t\t}\n\t\tif (isDefined(this._units)) {\n\t\t\tconst expr = this._expressions[this._units];\n\t\t\tconst matching = this._val.toString().trim().match(expr.regexp);\n\t\t\tif (matching) {\n\t\t\t\treturn expr.method.apply(this, matching.slice(1));\n\t\t\t} else {\n\t\t\t\treturn expr.method.call(this, this._val);\n\t\t\t}\n\t\t} else if (isString(this._val)) {\n\t\t\treturn parseFloat(this._val) as Type;\n\t\t} else {\n\t\t\treturn this._val as Type;\n\t\t}\n\t}\n\n\t//-------------------------------------\n\t// \tUNIT CONVERSIONS\n\t//-------------------------------------\n\n\t/**\n\t * Returns the value of a frequency in the current units\n\t */\n\tprotected _frequencyToUnits(freq: Hertz): Type {\n\t\treturn (1 / freq) as Type;\n\t}\n\n\t/**\n\t * Return the value of the beats in the current units\n\t */\n\tprotected _beatsToUnits(beats: number): Type {\n\t\treturn ((60 / this._getBpm()) * beats) as Type;\n\t}\n\n\t/**\n\t * Returns the value of a second in the current units\n\t */\n\tprotected _secondsToUnits(seconds: Seconds): Type {\n\t\treturn seconds as Type;\n\t}\n\n\t/**\n\t * Returns the value of a tick in the current time units\n\t */\n\tprotected _ticksToUnits(ticks: Ticks): Type {\n\t\treturn ((ticks * this._beatsToUnits(1)) / this._getPPQ()) as Type;\n\t}\n\n\t/**\n\t * With no arguments, return 'now'\n\t */\n\tprotected _noArg(): Type {\n\t\treturn this._now();\n\t}\n\n\t//-------------------------------------\n\t// \tTEMPO CONVERSIONS\n\t//-------------------------------------\n\n\t/**\n\t * Return the bpm\n\t */\n\tprotected _getBpm(): BPM {\n\t\treturn this.context.transport.bpm.value;\n\t}\n\n\t/**\n\t * Return the timeSignature\n\t */\n\tprotected _getTimeSignature(): number {\n\t\treturn this.context.transport.timeSignature as number;\n\t}\n\n\t/**\n\t * Return the PPQ or 192 if Transport is not available\n\t */\n\tprotected _getPPQ(): number {\n\t\treturn this.context.transport.PPQ;\n\t}\n\n\t/**\n\t * Return the current time in whichever context is relevant\n\t */\n\tprotected abstract _now(): Type;\n\n\t//-------------------------------------\n\t// \tCONVERSION INTERFACE\n\t//-------------------------------------\n\n\t/**\n\t * Coerce a time type into this units type.\n\t * @param type Any time type units\n\t */\n\tfromType(type: TimeBaseClass<any, any>): this {\n\t\tthis._units = undefined;\n\t\tswitch (this.defaultUnits) {\n\t\t\tcase \"s\":\n\t\t\t\tthis._val = type.toSeconds();\n\t\t\t\tbreak;\n\t\t\tcase \"i\":\n\t\t\t\tthis._val = type.toTicks();\n\t\t\t\tbreak;\n\t\t\tcase \"hz\":\n\t\t\t\tthis._val = type.toFrequency();\n\t\t\t\tbreak;\n\t\t\tcase \"midi\":\n\t\t\t\tthis._val = type.toMidi();\n\t\t\t\tbreak;\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Return the value in seconds\n\t */\n\tabstract toSeconds(): Seconds;\n\n\t/**\n\t * Return the value as a Midi note\n\t */\n\tabstract toMidi(): MidiNote;\n\n\t/**\n\t * Convert the value into ticks\n\t */\n\tabstract toTicks(): Ticks;\n\n\t/**\n\t * Return the value in hertz\n\t */\n\ttoFrequency(): Hertz {\n\t\treturn 1 / this.toSeconds();\n\t}\n\n\t/**\n\t * Return the time in samples\n\t */\n\ttoSamples(): Samples {\n\t\treturn this.toSeconds() * this.context.sampleRate;\n\t}\n\n\t/**\n\t * Return the time in milliseconds.\n\t */\n\ttoMilliseconds(): Milliseconds {\n\t\treturn this.toSeconds() * 1000;\n\t}\n}\n"
  },
  {
    "path": "Tone/core/type/TransportTime.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { atTime, Offline } from \"../../../test/helper/Offline.js\";\nimport { getContext } from \"../Global.js\";\nimport { Frequency } from \"./Frequency.js\";\nimport { Ticks } from \"./Ticks.js\";\nimport { Time } from \"./Time.js\";\nimport { TransportTime, TransportTimeClass } from \"./TransportTime.js\";\n\ndescribe(\"TransportTimeClass\", () => {\n\tBasicTests(TransportTime);\n\n\tcontext(\"Constructor\", () => {\n\t\tit(\"can be made with or without 'new'\", () => {\n\t\t\tconst t0 = TransportTime();\n\t\t\texpect(t0).to.be.instanceOf(TransportTimeClass);\n\t\t\tt0.dispose();\n\t\t\tconst t1 = new TransportTimeClass(getContext());\n\t\t\texpect(t1).to.be.instanceOf(TransportTimeClass);\n\t\t\tt1.dispose();\n\t\t});\n\n\t\tit(\"can pass in a number in the constructor\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst time = TransportTime(1);\n\t\t\t\texpect(time).to.be.instanceOf(TransportTimeClass);\n\t\t\t\texpect(time.valueOf()).to.equal(1);\n\t\t\t\ttime.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can pass in a string in the constructor\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst time = TransportTime(\"1\");\n\t\t\t\texpect(time).to.be.instanceOf(TransportTimeClass);\n\t\t\t\texpect(time.valueOf()).to.equal(1);\n\t\t\t\ttime.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can pass in a value and a type\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\texpect(TransportTime(4, \"m\").valueOf()).to.equal(8);\n\t\t\t});\n\t\t});\n\n\t\tit(\"with no arguments evaluates to 0 when the transport is stopped\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\texpect(TransportTime().valueOf()).to.equal(0);\n\t\t\t});\n\t\t});\n\n\t\tit(\"with no arguments evaluates to the current ticks when the transport is started\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = context.transport;\n\t\t\t\ttransport.start();\n\t\t\t\treturn atTime(0.29, () => {\n\t\t\t\t\texpect(new TransportTimeClass(context).valueOf()).to.equal(\n\t\t\t\t\t\ttransport.seconds\n\t\t\t\t\t);\n\t\t\t\t\ttransport.stop();\n\t\t\t\t});\n\t\t\t}, 0.3);\n\t\t});\n\n\t\tit(\"is evaluated in equations and comparisons using valueOf\", () => {\n\t\t\t// @ts-ignore\n\t\t\texpect(TransportTime(\"1\") + 1).to.equal(2);\n\t\t\t// @ts-ignore\n\t\t\texpect(TransportTime(\"1\") + TransportTime(\"1\")).to.equal(2);\n\t\t\texpect(TransportTime(\"1\") > TransportTime(0)).to.be.true;\n\t\t\texpect(+TransportTime(\"1\")).to.equal(1);\n\t\t});\n\n\t\tit(\"can convert from Time\", () => {\n\t\t\texpect(TransportTime(Time(2)).valueOf()).to.equal(2);\n\t\t\texpect(TransportTime(Time(\"4n\")).valueOf()).to.equal(0.5);\n\t\t});\n\n\t\tit(\"can convert from Frequency\", () => {\n\t\t\texpect(TransportTime(Frequency(2)).valueOf()).to.equal(0.5);\n\t\t\texpect(TransportTime(Frequency(\"4n\")).valueOf()).to.equal(0.5);\n\t\t});\n\n\t\tit(\"can convert from TransportTime\", () => {\n\t\t\texpect(TransportTime(TransportTime(2)).valueOf()).to.equal(2);\n\t\t\texpect(TransportTime(TransportTime(\"4n\")).valueOf()).to.equal(0.5);\n\t\t});\n\n\t\tit(\"can convert from Ticks\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = context.transport;\n\t\t\t\texpect(TransportTime(Ticks(transport.PPQ)).valueOf()).to.equal(\n\t\t\t\t\t0.5\n\t\t\t\t);\n\t\t\t\texpect(TransportTime(Ticks(\"4n\")).valueOf()).to.equal(0.5);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can convert from an Object\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\texpect(TransportTime({ \"4n\": 2 }).valueOf()).to.equal(1);\n\t\t\t\texpect(\n\t\t\t\t\tTransportTime({ \"1n\": 1, \"8t\": 2 }).valueOf()\n\t\t\t\t).to.be.closeTo(2.333, 0.01);\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"Quantizes values\", () => {\n\t\tit(\"can quantize values\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\texpect(\n\t\t\t\t\tTransportTime(\"4t\").quantize(\"4n\").valueOf()\n\t\t\t\t).to.be.closeTo(0.5, 0.01);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get the next subdivision when the transport is started\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = context.transport;\n\t\t\t\ttransport.start();\n\t\t\t\treturn atTime(0.59, () => {\n\t\t\t\t\texpect(\n\t\t\t\t\t\tnew TransportTimeClass(context, \"@1m\").valueOf()\n\t\t\t\t\t).to.be.closeTo(2, 0.01);\n\t\t\t\t\texpect(\n\t\t\t\t\t\tnew TransportTimeClass(context, \"@4n\").valueOf()\n\t\t\t\t\t).to.be.closeTo(1, 0.01);\n\t\t\t\t});\n\t\t\t}, 0.6);\n\t\t});\n\t});\n\n\tcontext(\"Operators\", () => {\n\t\tit(\"can add the current time\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = context.transport;\n\t\t\t\ttransport.start();\n\t\t\t\treturn atTime(0.59, () => {\n\t\t\t\t\tconst now = transport.seconds;\n\t\t\t\t\tconst quarterNote = 60 / transport.bpm.value;\n\t\t\t\t\texpect(\n\t\t\t\t\t\tnew TransportTimeClass(context, \"+4i\").valueOf()\n\t\t\t\t\t).to.be.closeTo(4 / transport.PPQ + now, 0.1);\n\t\t\t\t\texpect(\n\t\t\t\t\t\tnew TransportTimeClass(context, \"+2n\").valueOf()\n\t\t\t\t\t).to.be.closeTo(quarterNote * 2 + now, 0.1);\n\t\t\t\t\ttransport.stop();\n\t\t\t\t});\n\t\t\t}, 0.6);\n\t\t});\n\t});\n\n\tcontext(\"Conversions\", () => {\n\t\tit(\"converts time into notation\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\tconst transport = context.transport;\n\t\t\t\ttransport.bpm.value = 120;\n\t\t\t\ttransport.timeSignature = 4;\n\t\t\t\texpect(TransportTime(\"4n\").toNotation()).to.equal(\"4n\");\n\t\t\t\texpect(TransportTime(1.5).toNotation()).to.equal(\"2n.\");\n\t\t\t\texpect(TransportTime(0).toNotation()).to.equal(\"0\");\n\t\t\t\texpect(TransportTime(\"1:0:0\").toNotation()).to.equal(\"1m\");\n\t\t\t});\n\t\t});\n\n\t\tit(\"converts time into samples\", () => {\n\t\t\treturn Offline((context) => {\n\t\t\t\texpect(TransportTime(2).toSamples()).to.equal(\n\t\t\t\t\t2 * context.sampleRate\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\n\t\tit(\"converts time into frequency\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\texpect(TransportTime(2).toFrequency()).to.equal(0.5);\n\t\t\t});\n\t\t});\n\n\t\tit(\"converts time into seconds\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\texpect(TransportTime(\"2n\").toSeconds()).to.equal(1);\n\t\t\t});\n\t\t});\n\n\t\tit(\"converts time into BarsBeatsSixteenths\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\texpect(TransportTime(\"3:1:3\").toBarsBeatsSixteenths()).to.equal(\n\t\t\t\t\t\"3:1:3\"\n\t\t\t\t);\n\t\t\t\texpect(TransportTime(2).toBarsBeatsSixteenths()).to.equal(\n\t\t\t\t\t\"1:0:0\"\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/type/TransportTime.ts",
    "content": "import { getContext } from \"../Global.js\";\nimport { Seconds, Ticks } from \"../type/Units.js\";\nimport { TimeClass } from \"./Time.js\";\nimport { TimeBaseUnit, TimeValue } from \"./TimeBase.js\";\n\n/**\n * TransportTime is a time along the Transport's\n * timeline. It is similar to Tone.Time, but instead of evaluating\n * against the AudioContext's clock, it is evaluated against\n * the Transport's position. See [TransportTime wiki](https://github.com/Tonejs/Tone.js/wiki/TransportTime).\n * @category Unit\n */\nexport class TransportTimeClass<\n\tType extends Seconds | Ticks = Seconds,\n> extends TimeClass<Type> {\n\treadonly name: string = \"TransportTime\";\n\n\t/**\n\t * Return the current time in whichever context is relevant\n\t */\n\tprotected _now(): Type {\n\t\treturn this.context.transport.seconds as Type;\n\t}\n}\n\n/**\n * TransportTime is a time along the Transport's\n * timeline. It is similar to Tone.Time, but instead of evaluating\n * against the AudioContext's clock, it is evaluated against\n * the Transport's position. See [TransportTime wiki](https://github.com/Tonejs/Tone.js/wiki/TransportTime).\n * @category Unit\n */\nexport function TransportTime(\n\tvalue?: TimeValue,\n\tunits?: TimeBaseUnit\n): TransportTimeClass {\n\treturn new TransportTimeClass(getContext(), value, units);\n}\n"
  },
  {
    "path": "Tone/core/type/Units.ts",
    "content": "export * from \"./NoteUnits.js\";\n\nimport { Note } from \"./NoteUnits.js\";\n\n/**\n * A number representing a time in seconds\n * @category Unit\n */\nexport type Seconds = number;\n\n/**\n * A number used to measure the intensity of a sound on a logarithmic scale.\n * @category Unit\n */\nexport type Decibels = number;\n\n/**\n * A number that is between [0, 1]\n * @category Unit\n */\nexport type NormalRange = number;\n\n/**\n * A number that is between [-1, 1]\n * @category Unit\n */\nexport type AudioRange = number;\n\n/**\n * Half-step note increments, i.e. 12 is an octave above the root. and 1 is a half-step up.\n * @category Unit\n */\nexport type Interval = number;\n\n/**\n * A number representing the multiplication factor applied to a signal\n * @category Unit\n */\nexport type GainFactor = number;\n\n/**\n * A number greater than or equal to 0.\n * @category Unit\n */\nexport type Positive = number;\n\n/**\n * Represents a subdivision of a measure.\n * The number represents the subdivision. \"t\" represents a triplet. A \".\" add a half.\n * e.g. \"4n\" is a quarter note, \"4t\" is a quarter note triplet, and \"4n.\" is a dotted quarter note.\n * @category Unit\n */\nexport type Subdivision =\n\t| \"1m\"\n\t| \"1n\"\n\t| \"1n.\"\n\t| `${2 | 4 | 8 | 16 | 32 | 64 | 128 | 256}${\"n\" | \"n.\" | \"t\"}`\n\t| \"0\";\n/**\n * A time object has a subdivision as the keys and a number as the values.\n * @example\n * Tone.Time({\n * \t\"2n\": 1,\n * \t\"8n\": 3\n * }).valueOf(); // 2n + 8n * 3\n * @category Unit\n */\nexport type TimeObject = {\n\t[sub in Subdivision]?: number;\n};\n\n/**\n * Time can be described in a number of ways. Read more [Time](https://github.com/Tonejs/Tone.js/wiki/Time).\n * * Numbers, which will be taken literally as the time (in seconds).\n * * Notation, (\"4n\", \"8t\") describes time in BPM and time signature relative values.\n * * TransportTime, (\"4:3:2\") will also provide tempo and time signature relative times in the form BARS:QUARTERS:SIXTEENTHS.\n * * Frequency, (\"8hz\") is converted to the length of the cycle in seconds.\n * * Now-Relative, (\"+1\") prefix any of the above with \"+\" and it will be interpreted as \"the current time plus whatever expression follows\".\n * * Object, ({\"4n\" : 3, \"8t\" : -1}). The resulting time is equal to the sum of all of the keys multiplied by the values in the object.\n * * No Argument, for methods which accept time, no argument will be interpreted as \"now\" (i.e. the currentTime).\n * @category Unit\n */\nexport type Time = string | Seconds | TimeObject | Subdivision;\n\n/**\n * Frequency can be described similar to time, except ultimately the\n * values are converted to frequency instead of seconds. A number\n * is taken literally as the value in hertz. Additionally any of the\n * Time encodings can be used. Note names in the form\n * of NOTE OCTAVE (i.e. C4) are also accepted and converted to their\n * frequency value.\n * @category Unit\n */\nexport type Frequency = Subdivision | Note | string | Hertz;\n\n/**\n *\n * @category Unit\n */\nexport type TimeSignature = number | number[];\n\n/**\n * TransportTime describes a position along the Transport's timeline. It is\n * similar to Time in that it uses all the same encodings, but TransportTime specifically\n * pertains to the Transport's timeline, which is startable, stoppable, loopable, and seekable.\n * [Read more](https://github.com/Tonejs/Tone.js/wiki/TransportTime)\n * @category Unit\n */\nexport type TransportTime = Time;\n\n/**\n * Ticks are the basic subunit of the Transport. They are\n * the smallest unit of time that the Transport supports.\n * @category Unit\n */\nexport type Ticks = number;\n\n/**\n * Beats per minute\n * @category Unit\n */\nexport type BPM = number;\n\n/**\n * Angle between 0 and 360.\n * @category Unit\n */\nexport type Degrees = number;\n\n/**\n * Angle between 0 and 2 * PI.\n * @category Unit\n */\nexport type Radians = number;\n\n/**\n * A colon-separated representation of time in the form of\n * Bars:Beats:Sixteenths.\n * @category Unit\n */\nexport type BarsBeatsSixteenths = `${number}:${number}:${number}`;\n/**\n * Sampling is the reduction of a continuous signal to a discrete signal.\n * Audio is typically sampled 44100 times per second.\n * @category Unit\n */\nexport type Samples = number;\n\n/**\n * Hertz are a frequency representation defined as one cycle per second.\n * @category Unit\n */\nexport type Hertz = number;\n\n/**\n * A Cent is 1/100th of a semitone.\n * e.g. a value of 50 cents would be halfway between two intervals.\n * @category Unit\n */\nexport type Cents = number;\n\n/**\n * One millisecond is a thousandth of a second.\n * @category Unit\n */\nexport type Milliseconds = number;\n\n/**\n * A value which is a power of 2\n * @category Unit\n */\nexport type PowerOfTwo = number;\n\n/**\n * Map the unit name to a unit value\n */\nexport interface UnitMap {\n\tnumber: number;\n\tdecibels: Decibels;\n\tnormalRange: NormalRange;\n\taudioRange: AudioRange;\n\tgain: GainFactor;\n\tpositive: Positive;\n\ttime: Time;\n\tfrequency: Frequency;\n\ttransportTime: TransportTime;\n\tticks: Ticks;\n\tbpm: BPM;\n\tdegrees: Degrees;\n\tradians: Radians;\n\tsamples: Samples;\n\thertz: Hertz;\n\tcents: Cents;\n}\n\n/**\n * All of the unit types\n * @category Unit\n */\nexport type Unit = UnitMap[keyof UnitMap];\n\n/**\n * All of the unit names\n * @category Unit\n */\nexport type UnitName = keyof UnitMap;\n"
  },
  {
    "path": "Tone/core/util/AdvancedTypeCheck.ts",
    "content": "import {\n\tAudioBuffer,\n\tisAnyAudioContext,\n\tisAnyAudioNode,\n\tisAnyAudioParam,\n\tisAnyOfflineAudioContext,\n} from \"standardized-audio-context\";\n\n/**\n * Test if the given value is an instanceof AudioParam\n */\nexport function isAudioParam(arg: any): arg is AudioParam {\n\treturn isAnyAudioParam(arg);\n}\n\n/**\n * Test if the given value is an instanceof AudioNode\n */\nexport function isAudioNode(arg: any): arg is AudioNode {\n\treturn isAnyAudioNode(arg);\n}\n\n/**\n * Test if the arg is instanceof an OfflineAudioContext\n */\nexport function isOfflineAudioContext(arg: any): arg is OfflineAudioContext {\n\treturn isAnyOfflineAudioContext(arg);\n}\n\n/**\n * Test if the arg is an instanceof AudioContext\n */\nexport function isAudioContext(arg: any): arg is AudioContext {\n\treturn isAnyAudioContext(arg);\n}\n\n/**\n * Test if the arg is instanceof an AudioBuffer\n */\nexport function isAudioBuffer(arg: any): arg is AudioBuffer {\n\treturn arg instanceof AudioBuffer;\n}\n"
  },
  {
    "path": "Tone/core/util/Debug.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { Oscillator } from \"../../source/index.js\";\nimport { ToneOscillatorNode } from \"../../source/oscillator/ToneOscillatorNode.js\";\nimport { theWindow } from \"../context/AudioContext.js\";\nimport { Context } from \"../context/Context.js\";\nimport { assertRange, setLogger } from \"./Debug.js\";\n\ndescribe(\"Debug\", () => {\n\tit(\"can log a class when that class is set to 'debug'\", () => {\n\t\tconst osc = new ToneOscillatorNode();\n\t\tosc.debug = true;\n\t\tlet loggerInvoked = false;\n\t\tlet warnInvoked = false;\n\t\tsetLogger({\n\t\t\tlog: () => (loggerInvoked = true),\n\t\t\twarn: () => (warnInvoked = true),\n\t\t});\n\t\tosc.start();\n\t\texpect(loggerInvoked).to.be.true;\n\t\texpect(warnInvoked).to.be.false;\n\t\tosc.dispose();\n\t\tsetLogger(console);\n\t});\n\n\tit(\"can log a class when the window is set with that class name\", () => {\n\t\t// @ts-ignore\n\t\ttheWindow.TONE_DEBUG_CLASS = \"ToneOscillatorNode\";\n\t\tconst osc = new ToneOscillatorNode();\n\t\tlet loggerInvoked = false;\n\t\tlet warnInvoked = false;\n\t\tsetLogger({\n\t\t\tlog: () => (loggerInvoked = true),\n\t\t\twarn: () => (warnInvoked = true),\n\t\t});\n\t\tosc.start();\n\t\texpect(loggerInvoked).to.be.true;\n\t\texpect(warnInvoked).to.be.false;\n\t\tsetLogger(console);\n\t\t// @ts-ignore\n\t\ttheWindow.TONE_DEBUG_CLASS = undefined;\n\t\tosc.dispose();\n\t});\n\n\tit(\"can assert a range\", () => {\n\t\texpect(() => {\n\t\t\tassertRange(-1, 0, 1);\n\t\t}).to.throw(RangeError);\n\n\t\texpect(() => {\n\t\t\tassertRange(2, 0, 1);\n\t\t}).to.throw(RangeError);\n\n\t\texpect(() => {\n\t\t\tassertRange(0, 0);\n\t\t}).to.not.throw(RangeError);\n\t});\n\n\tit(\"warns if console is not running\", async () => {\n\t\tconst context = new Context();\n\t\tawait context.rawContext.suspend(0);\n\t\tconst osc = new Oscillator({ context });\n\t\tlet warnInvoked = false;\n\t\tsetLogger({\n\t\t\tlog: () => {},\n\t\t\twarn: () => (warnInvoked = true),\n\t\t});\n\t\tosc.start();\n\t\texpect(warnInvoked).to.be.true;\n\t\tosc.dispose();\n\t\tsetLogger(console);\n\t\tawait context.close();\n\t});\n});\n"
  },
  {
    "path": "Tone/core/util/Debug.ts",
    "content": "import type { BaseContext } from \"../context/BaseContext.js\";\nimport type { Time } from \"../type/Units.js\";\nimport { isUndef } from \"./TypeCheck.js\";\n\n/**\n * Assert that the statement is true, otherwise invoke the error.\n * @param statement\n * @param error The message which is passed into an Error\n */\nexport function assert(statement: boolean, error: string): asserts statement {\n\tif (!statement) {\n\t\tthrow new Error(error);\n\t}\n}\n\n/**\n * Make sure that the given value is within the range\n */\nexport function assertRange(value: number, gte: number, lte = Infinity): void {\n\tif (!(gte <= value && value <= lte)) {\n\t\tthrow new RangeError(\n\t\t\t`Value must be within [${gte}, ${lte}], got: ${value}`\n\t\t);\n\t}\n}\n\n/**\n * Warn if the context is not running.\n */\nexport function assertContextRunning(context: BaseContext): void {\n\t// add a warning if the context is not started\n\tif (!context.isOffline && context.state !== \"running\") {\n\t\twarn(\n\t\t\t'The AudioContext is \"suspended\". Invoke Tone.start() from a user action to start the audio.'\n\t\t);\n\t}\n}\n\n/**\n * If it is currently inside a scheduled callback\n */\nlet isInsideScheduledCallback = false;\nlet printedScheduledWarning = false;\n\n/**\n * Notify that the following block of code is occurring inside a Transport callback.\n */\nexport function enterScheduledCallback(insideCallback: boolean): void {\n\tisInsideScheduledCallback = insideCallback;\n}\n\n/**\n * Make sure that a time was passed into\n */\nexport function assertUsedScheduleTime(time?: Time): void {\n\tif (\n\t\tisUndef(time) &&\n\t\tisInsideScheduledCallback &&\n\t\t!printedScheduledWarning\n\t) {\n\t\tprintedScheduledWarning = true;\n\t\twarn(\n\t\t\t\"Schedulable methods should include the provided time argument to ensure accurate timing. See https://github.com/Tonejs/Tone.js/wiki/Accurate-Timing\"\n\t\t);\n\t}\n}\n\n/**\n * A basic logging interface\n */\ninterface Logger {\n\tlog: (args?: any[]) => void;\n\twarn: (args?: any[]) => void;\n}\n\n/**\n * The default logger is the console\n */\nlet defaultLogger: Logger = console;\n\n/**\n * Set the logging interface\n */\nexport function setLogger(logger: Logger): void {\n\tdefaultLogger = logger;\n}\n\n/**\n * Log anything\n */\nexport function log(...args: any[]): void {\n\tdefaultLogger.log(...args);\n}\n\n/**\n * Warn anything\n */\nexport function warn(...args: any[]): void {\n\tdefaultLogger.warn(...args);\n}\n"
  },
  {
    "path": "Tone/core/util/Decorator.ts",
    "content": "import { Time } from \"../type/Units.js\";\nimport { assertRange } from \"./Debug.js\";\n\n/**\n * Assert that the number is in the given range.\n */\nexport function range(min: number, max = Infinity) {\n\tconst valueMap: WeakMap<any, number> = new WeakMap();\n\treturn function (target: any, propertyKey: string | symbol) {\n\t\tReflect.defineProperty(target, propertyKey, {\n\t\t\tconfigurable: true,\n\t\t\tenumerable: true,\n\t\t\tget: function () {\n\t\t\t\treturn valueMap.get(this);\n\t\t\t},\n\t\t\tset: function (newValue: number) {\n\t\t\t\tassertRange(newValue, min, max);\n\t\t\t\tvalueMap.set(this, newValue);\n\t\t\t},\n\t\t});\n\t};\n}\n\n/**\n * Convert the time to seconds and assert that the time is in between the two\n * values when being set.\n */\nexport function timeRange(min: number, max = Infinity) {\n\tconst valueMap: WeakMap<any, Time> = new WeakMap();\n\treturn function (target: any, propertyKey: string) {\n\t\tReflect.defineProperty(target, propertyKey, {\n\t\t\tconfigurable: true,\n\t\t\tenumerable: true,\n\t\t\tget: function () {\n\t\t\t\treturn valueMap.get(this);\n\t\t\t},\n\t\t\tset: function (newValue: Time) {\n\t\t\t\tassertRange(this.toSeconds(newValue), min, max);\n\t\t\t\tvalueMap.set(this, newValue);\n\t\t\t},\n\t\t});\n\t};\n}\n"
  },
  {
    "path": "Tone/core/util/Defaults.ts",
    "content": "import type { BaseToneOptions } from \"../Tone.js\";\nimport {\n\tisAudioBuffer,\n\tisAudioNode,\n\tisAudioParam,\n} from \"./AdvancedTypeCheck.js\";\nimport { isDefined, isObject, isUndef } from \"./TypeCheck.js\";\n\n/**\n * Some objects should not be merged\n */\nfunction noCopy(key: string, arg: any): boolean {\n\treturn (\n\t\tkey === \"value\" ||\n\t\tisAudioParam(arg) ||\n\t\tisAudioNode(arg) ||\n\t\tisAudioBuffer(arg)\n\t);\n}\n\nexport function deepMerge<T>(target: T): T;\nexport function deepMerge<T, U>(target: T, source1: U): T & U;\nexport function deepMerge<T, U, V>(\n\ttarget: T,\n\tsource1: U,\n\tsource2: V\n): T & U & V;\nexport function deepMerge<T, U, V, W>(\n\ttarget: T,\n\tsource1: U,\n\tsource2: V,\n\tsource3: W\n): T & U & V & W;\n/**\n * Recursively merge an object\n * @param target the object to merge into\n * @param sources the source objects to merge\n */\nexport function deepMerge(target: any, ...sources: any[]): any {\n\tif (!sources.length) {\n\t\treturn target;\n\t}\n\tconst source = sources.shift();\n\n\tif (isObject(target) && isObject(source)) {\n\t\tfor (const key in source) {\n\t\t\tif (noCopy(key, source[key])) {\n\t\t\t\ttarget[key] = source[key];\n\t\t\t} else if (isObject(source[key])) {\n\t\t\t\tif (!target[key]) {\n\t\t\t\t\tObject.assign(target, { [key]: {} });\n\t\t\t\t}\n\t\t\t\tdeepMerge(target[key], source[key] as any);\n\t\t\t} else {\n\t\t\t\tObject.assign(target, { [key]: source[key] as any });\n\t\t\t}\n\t\t}\n\t}\n\t// @ts-ignore\n\treturn deepMerge(target, ...sources);\n}\n\n/**\n * Returns true if the two arrays have the same value for each of the elements\n */\nexport function deepEquals<T>(arrayA: T[], arrayB: T[]): boolean {\n\treturn (\n\t\tarrayA.length === arrayB.length &&\n\t\tarrayA.every((element, index) => arrayB[index] === element)\n\t);\n}\n\n/**\n * Convert an args array into an object.\n * @internal\n */\nexport function optionsFromArguments<T extends object>(\n\tdefaults: T,\n\targsArray: IArguments,\n\tkeys: Array<keyof T> = [],\n\tobjKey?: keyof T\n): T {\n\tconst opts: Partial<T> = {};\n\tconst args = Array.from(argsArray);\n\t// if the first argument is an object and has an object key\n\tif (isObject(args[0]) && objKey && !Reflect.has(args[0], objKey)) {\n\t\t// if it's not part of the defaults\n\t\tconst partOfDefaults = Object.keys(args[0]).some((key) =>\n\t\t\tReflect.has(defaults, key)\n\t\t);\n\t\tif (!partOfDefaults) {\n\t\t\t// merge that key\n\t\t\tdeepMerge(opts, { [objKey]: args[0] });\n\t\t\t// remove the obj key from the keys\n\t\t\tkeys.splice(keys.indexOf(objKey), 1);\n\t\t\t// shift the first argument off\n\t\t\targs.shift();\n\t\t}\n\t}\n\tif (args.length === 1 && isObject(args[0])) {\n\t\tdeepMerge(opts, args[0]);\n\t} else {\n\t\tfor (let i = 0; i < keys.length; i++) {\n\t\t\tif (isDefined(args[i])) {\n\t\t\t\topts[keys[i]] = args[i];\n\t\t\t}\n\t\t}\n\t}\n\treturn deepMerge(defaults, opts);\n}\n\n/**\n * Return this instances default values by calling Constructor.getDefaults()\n */\nexport function getDefaultsFromInstance<T>(instance: T): BaseToneOptions {\n\ttype ToneClass = {\n\t\tconstructor: ToneClass;\n\t\tgetDefaults: () => BaseToneOptions;\n\t} & T;\n\n\treturn (instance as ToneClass).constructor.getDefaults();\n}\n\n/**\n * Returns the fallback if the given object is undefined.\n * Take an array of arguments and return a formatted options object.\n * @internal\n */\nexport function defaultArg<T>(given: T, fallback: T): T {\n\tif (isUndef(given)) {\n\t\treturn fallback;\n\t} else {\n\t\treturn given;\n\t}\n}\n\n/**\n * Remove all of the properties belonging to omit from obj.\n */\nexport function omitFromObject<T extends object, O extends string[]>(\n\tobj: T,\n\tomit: O\n): Omit<T, keyof O> {\n\tomit.forEach((prop) => {\n\t\tif (Reflect.has(obj, prop)) {\n\t\t\tdelete obj[prop];\n\t\t}\n\t});\n\treturn obj;\n}\n"
  },
  {
    "path": "Tone/core/util/Draw.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { DrawInstance } from \"./Draw.js\";\n\ndescribe(\"Draw\", () => {\n\tconst originalRAF = window.requestAnimationFrame;\n\tbefore(async () => {\n\t\twindow.requestAnimationFrame = (callback) => {\n\t\t\treturn setTimeout(callback, 10);\n\t\t};\n\t});\n\n\tafter(() => {\n\t\twindow.requestAnimationFrame = originalRAF;\n\t});\n\n\tit(\"can schedule a callback at a AudioContext time\", (done) => {\n\t\tconst draw = new DrawInstance();\n\t\tconst scheduledTime = draw.now() + 0.2;\n\t\tdraw.schedule(() => {\n\t\t\texpect(draw.context.currentTime).to.be.closeTo(scheduledTime, 0.05);\n\t\t\tdraw.dispose();\n\t\t\tdone();\n\t\t}, scheduledTime);\n\t});\n\n\tit(\"can schedule multiple callbacks\", (done) => {\n\t\tconst draw = new DrawInstance();\n\t\tlet callbackCount = 0;\n\t\tconst firstEvent = draw.now() + 0.1;\n\t\tdraw.schedule(() => {\n\t\t\tcallbackCount++;\n\t\t\texpect(draw.context.currentTime).to.be.closeTo(firstEvent, 0.05);\n\t\t}, firstEvent);\n\n\t\tconst thirdEvent = draw.now() + 0.3;\n\t\tdraw.schedule(() => {\n\t\t\tcallbackCount++;\n\t\t\texpect(draw.context.currentTime).to.be.closeTo(thirdEvent, 0.05);\n\t\t\texpect(callbackCount).to.equal(3);\n\t\t\tdone();\n\t\t\tdraw.dispose();\n\t\t}, thirdEvent);\n\n\t\tconst secondEvent = draw.now() + 0.2;\n\t\tdraw.schedule(() => {\n\t\t\tcallbackCount++;\n\t\t\texpect(draw.context.currentTime).to.be.closeTo(secondEvent, 0.05);\n\t\t}, secondEvent);\n\t});\n\n\tit(\"can cancel scheduled events\", (done) => {\n\t\tconst draw = new DrawInstance();\n\t\tlet callbackCount = 0;\n\t\tdraw.schedule(() => {\n\t\t\tcallbackCount++;\n\t\t}, draw.now() + 0.1);\n\n\t\tdraw.schedule(() => {\n\t\t\tthrow new Error(\"should not call this method\");\n\t\t}, draw.now() + 0.2);\n\n\t\tdraw.schedule(() => {\n\t\t\tthrow new Error(\"should not call this method\");\n\t\t}, draw.now() + 0.25);\n\n\t\t// cancel the second and third events\n\t\tdraw.cancel(draw.now() + 0.15);\n\n\t\t// schedule another one after\n\t\tdraw.schedule(() => {\n\t\t\tcallbackCount++;\n\t\t\texpect(callbackCount).to.equal(2);\n\t\t\tdone();\n\t\t\tdraw.dispose();\n\t\t}, draw.now() + 0.3);\n\t});\n});\n"
  },
  {
    "path": "Tone/core/util/Draw.ts",
    "content": "import {\n\tonContextClose,\n\tonContextInit,\n} from \"../context/ContextInitialization.js\";\nimport {\n\tToneWithContext,\n\tToneWithContextOptions,\n} from \"../context/ToneWithContext.js\";\nimport { Seconds, Time } from \"../type/Units.js\";\nimport { Timeline, TimelineEvent } from \"./Timeline.js\";\n\ninterface DrawEvent extends TimelineEvent {\n\tcallback: () => void;\n}\n\n/**\n * Draw is useful for synchronizing visuals and audio events.\n * Callbacks from Tone.Transport or any of the Tone.Event classes\n * always happen _before_ the scheduled time and are not synchronized\n * to the animation frame so they are not good for triggering tightly\n * synchronized visuals and sound. Draw makes it easy to schedule\n * callbacks using the AudioContext time and uses requestAnimationFrame.\n * @example\n * Tone.Transport.schedule((time) => {\n * \t// use the time argument to schedule a callback with Draw\n * \tTone.Draw.schedule(() => {\n * \t\t// do drawing or DOM manipulation here\n * \t\tconsole.log(time);\n * \t}, time);\n * }, \"+0.5\");\n * Tone.Transport.start();\n * @category Core\n */\nexport class DrawInstance extends ToneWithContext<ToneWithContextOptions> {\n\treadonly name: string = \"Draw\";\n\n\t/**\n\t * The duration after which events are not invoked.\n\t */\n\texpiration: Seconds = 0.25;\n\n\t/**\n\t * The amount of time before the scheduled time\n\t * that the callback can be invoked. Default is\n\t * half the time of an animation frame (0.008 seconds).\n\t */\n\tanticipation: Seconds = 0.008;\n\n\t/**\n\t * All of the events.\n\t */\n\tprivate _events: Timeline<DrawEvent> = new Timeline();\n\n\t/**\n\t * The draw loop\n\t */\n\tprivate _boundDrawLoop = this._drawLoop.bind(this);\n\n\t/**\n\t * The animation frame id\n\t */\n\tprivate _animationFrame = -1;\n\n\t/**\n\t * Schedule a function at the given time to be invoked\n\t * on the nearest animation frame.\n\t * @param  callback  Callback is invoked at the given time.\n\t * @param  time      The time relative to the AudioContext time to invoke the callback.\n\t * @example\n\t * Tone.Transport.scheduleRepeat(time => {\n\t * \tTone.Draw.schedule(() => console.log(time), time);\n\t * }, 1);\n\t * Tone.Transport.start();\n\t */\n\tschedule(callback: () => void, time: Time): this {\n\t\tthis._events.add({\n\t\t\tcallback,\n\t\t\ttime: this.toSeconds(time),\n\t\t});\n\t\t// start the draw loop on the first event\n\t\tif (this._events.length === 1) {\n\t\t\tthis._animationFrame = requestAnimationFrame(this._boundDrawLoop);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Cancel events scheduled after the given time\n\t * @param  after  Time after which scheduled events will be removed from the scheduling timeline.\n\t */\n\tcancel(after?: Time): this {\n\t\tthis._events.cancel(this.toSeconds(after));\n\t\treturn this;\n\t}\n\n\t/**\n\t * The draw loop\n\t */\n\tprivate _drawLoop(): void {\n\t\tconst now = this.context.currentTime;\n\t\tthis._events.forEachBefore(now + this.anticipation, (event) => {\n\t\t\tif (now - event.time <= this.expiration) {\n\t\t\t\tevent.callback();\n\t\t\t}\n\t\t\tthis._events.remove(event);\n\t\t});\n\t\tif (this._events.length > 0) {\n\t\t\tthis._animationFrame = requestAnimationFrame(this._boundDrawLoop);\n\t\t}\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._events.dispose();\n\t\tcancelAnimationFrame(this._animationFrame);\n\t\treturn this;\n\t}\n}\n\n//-------------------------------------\n// \tINITIALIZATION\n//-------------------------------------\n\nonContextInit((context) => {\n\tcontext.draw = new DrawInstance({ context });\n});\n\nonContextClose((context) => {\n\tcontext.draw.dispose();\n});\n"
  },
  {
    "path": "Tone/core/util/Emitter.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { Emitter } from \"./Emitter.js\";\n\ndescribe(\"Emitter\", () => {\n\tit(\"can be created and disposed\", () => {\n\t\tconst emitter = new Emitter();\n\t\temitter.dispose();\n\t});\n\n\tit(\"can bind events\", (done) => {\n\t\tconst emitter = new Emitter();\n\t\temitter.on(\"something\", () => {\n\t\t\tdone();\n\t\t\temitter.dispose();\n\t\t});\n\t\temitter.emit(\"something\");\n\t\temitter.dispose();\n\t});\n\n\tit(\"can unbind events\", () => {\n\t\tconst emitter = new Emitter();\n\t\tconst callback = () => {\n\t\t\tthrow new Error(\"should call this\");\n\t\t};\n\t\temitter.on(\"something\", callback);\n\t\temitter.off(\"something\", callback);\n\t\temitter.emit(\"something\");\n\t\temitter.dispose();\n\t});\n\n\tit(\"can unbind duplicate events\", () => {\n\t\tconst emitter = new Emitter();\n\t\tconst callback = () => {\n\t\t\tthrow new Error(\"should call this\");\n\t\t};\n\t\temitter.on(\"something\", callback);\n\t\temitter.on(\"something\", callback);\n\t\temitter.on(\"something\", callback);\n\t\temitter.off(\"something\", callback);\n\t\temitter.emit(\"something\");\n\t\temitter.dispose();\n\t});\n\n\tit(\"'off' does nothing if there is no event scheduled\", () => {\n\t\tconst emitter = new Emitter();\n\t\tconst callback = () => {\n\t\t\tthrow new Error(\"should call this\");\n\t\t};\n\t\temitter.off(\"something\", callback);\n\t\temitter.emit(\"something\");\n\t\temitter.dispose();\n\t});\n\n\tit(\"removes all events when no callback is given\", () => {\n\t\tconst emitter = new Emitter();\n\t\temitter.on(\"something\", () => {\n\t\t\tthrow new Error(\"should call this\");\n\t\t});\n\t\temitter.on(\"something\", () => {\n\t\t\tthrow new Error(\"should call this\");\n\t\t});\n\t\temitter.off(\"something\");\n\t\temitter.emit(\"something\");\n\t\temitter.off(\"something-else\");\n\t\temitter.dispose();\n\t});\n\n\tit(\"can remove an event while emitting\", (done) => {\n\t\tconst emitter = new Emitter();\n\t\temitter.on(\"something\", () => {\n\t\t\temitter.off(\"something\");\n\t\t});\n\t\temitter.on(\"something-else\", () => {\n\t\t\temitter.dispose();\n\t\t\tdone();\n\t\t});\n\t\temitter.emit(\"something\");\n\t\temitter.emit(\"something-else\");\n\t});\n\n\tit(\"can invoke an event once\", () => {\n\t\tconst emitter = new Emitter();\n\t\temitter.once(\"something\", (val) => {\n\t\t\texpect(val).to.equal(1);\n\t\t});\n\t\temitter.emit(\"something\", 1);\n\t\temitter.emit(\"something\", 2);\n\t\temitter.dispose();\n\t});\n\n\tit(\"can pass arguments to the callback\", (done) => {\n\t\tconst emitter = new Emitter();\n\t\temitter.on(\"something\", (arg0, arg1) => {\n\t\t\texpect(arg0).to.equal(\"A\");\n\t\t\texpect(arg1).to.equal(\"B\");\n\t\t\temitter.dispose();\n\t\t\tdone();\n\t\t});\n\t\temitter.emit(\"something\", \"A\", \"B\");\n\t});\n\n\t// it(\"can mixin its methods to another object\", done => {\n\t// \tconst emitter = {};\n\t// \tEmitter.mixin(emitter);\n\t// \temitter.on(\"test\", done);\n\t// \temitter.emit(\"test\");\n\t// });\n});\n"
  },
  {
    "path": "Tone/core/util/Emitter.ts",
    "content": "import { Tone } from \"../Tone.js\";\nimport { isUndef } from \"./TypeCheck.js\";\n\nexport interface EmitterEventObject {\n\t[event: string]: Array<(...args: any[]) => void>;\n}\n\n/**\n * Emitter gives classes which extend it\n * the ability to listen for and emit events.\n * Inspiration and reference from Jerome Etienne's [MicroEvent](https://github.com/jeromeetienne/microevent.js).\n * MIT (c) 2011 Jerome Etienne.\n */\nexport class Emitter<EventType extends string = string> extends Tone {\n\treadonly name: string = \"Emitter\";\n\n\t/**\n\t * Private container for the events\n\t */\n\tprivate _events?: EmitterEventObject;\n\n\t/**\n\t * Bind a callback to a specific event.\n\t * @param  event     The name of the event to listen for.\n\t * @param  callback  The callback to invoke when the event is emitted\n\t */\n\ton(event: EventType, callback: (...args: any[]) => void): this {\n\t\t// split the event\n\t\tconst events = event.split(/\\W+/);\n\t\tevents.forEach((eventName) => {\n\t\t\tif (isUndef(this._events)) {\n\t\t\t\tthis._events = {};\n\t\t\t}\n\t\t\tif (!this._events.hasOwnProperty(eventName)) {\n\t\t\t\tthis._events[eventName] = [];\n\t\t\t}\n\t\t\tthis._events[eventName].push(callback);\n\t\t});\n\t\treturn this;\n\t}\n\n\t/**\n\t * Bind a callback which is only invoked once\n\t * @param  event     The name of the event to listen for.\n\t * @param  callback  The callback to invoke when the event is emitted\n\t */\n\tonce(event: EventType, callback: (...args: any[]) => void): this {\n\t\tconst boundCallback = (...args: any[]) => {\n\t\t\t// invoke the callback\n\t\t\tcallback(...args);\n\t\t\t// remove the event\n\t\t\tthis.off(event, boundCallback);\n\t\t};\n\t\tthis.on(event, boundCallback);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove the event listener.\n\t * @param  event     The event to stop listening to.\n\t * @param  callback  The callback which was bound to the event with Emitter.on.\n\t *                   If no callback is given, all callbacks events are removed.\n\t */\n\toff(event: EventType, callback?: (...args: any[]) => void): this {\n\t\tconst events = event.split(/\\W+/);\n\t\tevents.forEach((eventName) => {\n\t\t\tif (isUndef(this._events)) {\n\t\t\t\tthis._events = {};\n\t\t\t}\n\t\t\tif (this._events.hasOwnProperty(eventName)) {\n\t\t\t\tif (isUndef(callback)) {\n\t\t\t\t\tthis._events[eventName] = [];\n\t\t\t\t} else {\n\t\t\t\t\tconst eventList = this._events[eventName];\n\t\t\t\t\tfor (let i = eventList.length - 1; i >= 0; i--) {\n\t\t\t\t\t\tif (eventList[i] === callback) {\n\t\t\t\t\t\t\teventList.splice(i, 1);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\treturn this;\n\t}\n\n\t/**\n\t * Invoke all of the callbacks bound to the event\n\t * with any arguments passed in.\n\t * @param  event  The name of the event.\n\t * @param args The arguments to pass to the functions listening.\n\t */\n\temit(event: EventType, ...args: any[]): this {\n\t\tif (this._events) {\n\t\t\tif (this._events.hasOwnProperty(event)) {\n\t\t\t\tconst eventList = this._events[event].slice(0);\n\t\t\t\tfor (let i = 0, len = eventList.length; i < len; i++) {\n\t\t\t\t\teventList[i].apply(this, args);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Add Emitter functions (on/off/emit) to the object\n\t */\n\tstatic mixin(constr: any): void {\n\t\t// instance._events = {};\n\t\t[\"on\", \"once\", \"off\", \"emit\"].forEach((name) => {\n\t\t\tconst property = Object.getOwnPropertyDescriptor(\n\t\t\t\tEmitter.prototype,\n\t\t\t\tname\n\t\t\t) as PropertyDescriptor;\n\t\t\tObject.defineProperty(constr.prototype, name, property);\n\t\t});\n\t}\n\n\t/**\n\t * Clean up\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._events = undefined;\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/core/util/Interface.ts",
    "content": "import { isArray } from \"./TypeCheck.js\";\n\n// return an interface which excludes certain keys\nexport type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;\n\n/**\n * Make the property not writable using `defineProperty`. Internal use only.\n */\nexport function readOnly<T extends object>(\n\ttarget: T,\n\tproperty: keyof T | (keyof T)[]\n): void {\n\tif (isArray(property)) {\n\t\tproperty.forEach((str) => readOnly(target, str));\n\t} else {\n\t\tObject.defineProperty(target, property, {\n\t\t\tenumerable: true,\n\t\t\twritable: false,\n\t\t});\n\t}\n}\n\n/**\n * Make an attribute writeable. Internal use only.\n */\nexport function writable<T extends object>(\n\ttarget: T,\n\tproperty: keyof T | (keyof T)[]\n): void {\n\tif (isArray(property)) {\n\t\tproperty.forEach((str) => writable(target, str));\n\t} else {\n\t\tObject.defineProperty(target, property, {\n\t\t\twritable: true,\n\t\t});\n\t}\n}\n\nexport const noOp: (...args: any[]) => any = () => {\n\t// no operation here!\n};\n\n/**\n * Recursive Partial taken from here: https://stackoverflow.com/a/51365037\n */\nexport type RecursivePartial<T> = {\n\t[P in keyof T]?: T[P] extends Array<infer U>\n\t\t? Array<RecursivePartial<U>>\n\t\t: T[P] extends object\n\t\t\t? RecursivePartial<T[P]>\n\t\t\t: T[P];\n};\n"
  },
  {
    "path": "Tone/core/util/IntervalTimeline.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { IntervalTimeline, IntervalTimelineEvent } from \"./IntervalTimeline.js\";\n\ndescribe(\"IntervalTimeline\", () => {\n\tBasicTests(IntervalTimeline);\n\n\tcontext(\"inserting/deleting events\", () => {\n\t\tit(\"accepts events into the timeline\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tsched.add({\n\t\t\t\tduration: 0.2,\n\t\t\t\tstate: \"A\",\n\t\t\t\ttime: 0,\n\t\t\t});\n\t\t\tsched.add({\n\t\t\t\tduration: 0.4,\n\t\t\t\tstate: \"B\",\n\t\t\t\ttime: 1,\n\t\t\t});\n\t\t\tsched.add({\n\t\t\t\tduration: 12,\n\t\t\t\tstate: \"C\",\n\t\t\t\ttime: 2,\n\t\t\t});\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"computes the length of the timeline correctly after adding events\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tsched.add({\n\t\t\t\tduration: 0.2,\n\t\t\t\tstate: \"A\",\n\t\t\t\ttime: 0,\n\t\t\t});\n\t\t\tsched.add({\n\t\t\t\tduration: 0.4,\n\t\t\t\tstate: \"B\",\n\t\t\t\ttime: 1,\n\t\t\t});\n\t\t\tsched.add({\n\t\t\t\tduration: 12,\n\t\t\t\tstate: \"C\",\n\t\t\t\ttime: 2,\n\t\t\t});\n\t\t\texpect(sched.length).to.equal(3);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"can remove events from the timeline\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\n\t\t\tconst ev0 = {\n\t\t\t\tduration: 0.2,\n\t\t\t\ttime: 0,\n\t\t\t};\n\t\t\tconst ev1 = {\n\t\t\t\tduration: 0.2,\n\t\t\t\ttime: 0.2,\n\t\t\t};\n\t\t\tconst ev2 = {\n\t\t\t\tduration: 0.2,\n\t\t\t\ttime: 0.1,\n\t\t\t};\n\t\t\tsched.add(ev0);\n\t\t\tsched.add(ev1);\n\t\t\tsched.add(ev2);\n\t\t\texpect(sched.length).to.equal(3);\n\t\t\tsched.remove(ev0);\n\t\t\tsched.remove(ev1);\n\t\t\texpect(sched.length).to.equal(1);\n\t\t\tsched.remove(ev2);\n\t\t\texpect(sched.length).to.equal(0);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"removing on a null set does nothing\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\texpect(sched.length).to.equal(0);\n\t\t\t// @ts-ignore\n\t\t\tsched.remove({});\n\t\t\texpect(sched.length).to.equal(0);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"can add and remove and add again events from the timeline\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\n\t\t\tconst ev0 = {\n\t\t\t\tduration: 0.2,\n\t\t\t\ttime: 0,\n\t\t\t};\n\t\t\tconst ev1 = {\n\t\t\t\tduration: 0.2,\n\t\t\t\ttime: 0.2,\n\t\t\t};\n\t\t\tconst ev2 = {\n\t\t\t\tduration: 0.2,\n\t\t\t\ttime: 0.1,\n\t\t\t};\n\t\t\tsched.add(ev0);\n\t\t\tsched.add(ev1);\n\t\t\tsched.add(ev2);\n\t\t\texpect(sched.length).to.equal(3);\n\t\t\tsched.remove(ev0);\n\t\t\tsched.remove(ev1);\n\t\t\texpect(sched.length).to.equal(1);\n\t\t\tsched.add(ev0);\n\t\t\tsched.add(ev1);\n\t\t\texpect(sched.length).to.equal(3);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"throws an error if events do not have both time and duration attributes\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\texpect(() => {\n\t\t\t\t// @ts-ignore\n\t\t\t\tsched.add({\n\t\t\t\t\ttime: 0,\n\t\t\t\t});\n\t\t\t}).to.throw(Error);\n\t\t\texpect(() => {\n\t\t\t\t// @ts-ignore\n\t\t\t\tsched.add({\n\t\t\t\t\tduration: 0,\n\t\t\t\t});\n\t\t\t}).to.throw(Error);\n\t\t\tsched.dispose();\n\t\t});\n\t});\n\n\tcontext(\"getting events\", () => {\n\t\tit(\"returns null when no events are in the timeline\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\texpect(sched.get(3)).to.equal(null);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"returns the event which overlaps the given time\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tsched.add({\n\t\t\t\tduration: Infinity,\n\t\t\t\tstate: \"A\",\n\t\t\t\ttime: 0,\n\t\t\t});\n\t\t\tsched.add({\n\t\t\t\tduration: 0.4,\n\t\t\t\tstate: \"B\",\n\t\t\t\ttime: 1,\n\t\t\t});\n\t\t\tsched.add({\n\t\t\t\tduration: 12,\n\t\t\t\tstate: \"C\",\n\t\t\t\ttime: 2,\n\t\t\t});\n\t\t\texpect(sched.get(0.2)?.state).to.equal(\"A\");\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"returns events exclusive of the end time\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tsched.add({\n\t\t\t\tduration: 1,\n\t\t\t\tstate: \"A\",\n\t\t\t\ttime: 0,\n\t\t\t});\n\t\t\texpect(sched.get(0.99)?.state).to.equal(\"A\");\n\t\t\texpect(sched.get(1)).to.equal(null);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"factors in start position and duration when checking for overlaps\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tsched.add({\n\t\t\t\tduration: 0.4,\n\t\t\t\ttime: 0,\n\t\t\t});\n\t\t\texpect(sched.get(0.5)).to.equal(null);\n\t\t\texpect(sched.get(-1)).to.equal(null);\n\t\t\texpect(sched.get(0)).to.not.equal(null);\n\t\t\texpect(sched.get(0.39)).to.not.equal(null);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"returns the event whose start is closest to the given time\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tsched.add({\n\t\t\t\tduration: Infinity,\n\t\t\t\tstate: \"A\",\n\t\t\t\ttime: 0,\n\t\t\t});\n\t\t\tsched.add({\n\t\t\t\tduration: 0.4,\n\t\t\t\tstate: \"B\",\n\t\t\t\ttime: 0.2,\n\t\t\t});\n\t\t\tsched.add({\n\t\t\t\tduration: 12,\n\t\t\t\tstate: \"C\",\n\t\t\t\ttime: 2,\n\t\t\t});\n\t\t\texpect(sched.get(0.2)?.state).to.equal(\"B\");\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"returns the events correctly after some events are removed\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tconst ev0 = {\n\t\t\t\tduration: 0.2,\n\t\t\t\tstate: \"A\",\n\t\t\t\ttime: 0.1,\n\t\t\t};\n\t\t\tconst ev1 = {\n\t\t\t\tduration: 0.3,\n\t\t\t\tstate: \"B\",\n\t\t\t\ttime: 0.2,\n\t\t\t};\n\t\t\tconst ev2 = {\n\t\t\t\tduration: Infinity,\n\t\t\t\tstate: \"C\",\n\t\t\t\ttime: 0,\n\t\t\t};\n\t\t\tsched.add(ev0);\n\t\t\tsched.add(ev1);\n\t\t\tsched.add(ev2);\n\t\t\tsched.remove(ev0);\n\t\t\tsched.remove(ev1);\n\t\t\texpect(sched.get(0.2)).to.not.equal(null);\n\t\t\texpect(sched.get(0.2)?.state).to.equal(\"C\");\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"can handle many items\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tconst len = 5000;\n\t\t\tconst events: IntervalTimelineEvent[] = [];\n\t\t\tlet duration = 1;\n\t\t\tlet time = 0;\n\t\t\tfor (let i = 0; i < len; i++) {\n\t\t\t\tconst event = {\n\t\t\t\t\tduration,\n\t\t\t\t\ttime,\n\t\t\t\t};\n\t\t\t\ttime = (time + 3.1) % 109;\n\t\t\t\tduration = (duration + 5.7) % 19;\n\t\t\t\tsched.add(event);\n\t\t\t\tevents.push(event);\n\t\t\t}\n\t\t\tfor (let j = 0; j < events.length; j++) {\n\t\t\t\tconst event = events[j];\n\t\t\t\tconst eventVal = sched.get(event.time);\n\t\t\t\tif (eventVal) {\n\t\t\t\t\texpect(eventVal.time).to.equal(event.time);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (let k = 0; k < events.length; k++) {\n\t\t\t\tsched.remove(events[k]);\n\t\t\t\texpect(sched.length).to.equal(events.length - k - 1);\n\t\t\t}\n\t\t\tsched.dispose();\n\t\t});\n\t});\n\n\tcontext(\"cancelling\", () => {\n\t\tit(\"can cancel items after the given time\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tfor (let i = 5; i < 100; i++) {\n\t\t\t\tsched.add({\n\t\t\t\t\tduration: 10,\n\t\t\t\t\ttime: i,\n\t\t\t\t});\n\t\t\t}\n\t\t\tsched.cancel(10);\n\t\t\texpect(sched.length).to.equal(5);\n\t\t\tsched.cancel(0);\n\t\t\texpect(sched.length).to.equal(0);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"can cancel items at the given time\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tsched.add({\n\t\t\t\tduration: 10,\n\t\t\t\ttime: 0,\n\t\t\t});\n\t\t\tsched.cancel(1);\n\t\t\texpect(sched.length).to.equal(1);\n\t\t\tsched.cancel(0);\n\t\t\texpect(sched.length).to.equal(0);\n\t\t\tsched.dispose();\n\t\t});\n\t});\n\n\tcontext(\"Iterators\", () => {\n\t\tit(\"iterates over all items and returns and item\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tsched.add({ time: 0, duration: 5 });\n\t\t\tsched.add({ time: 0.1, duration: 5 });\n\t\t\tsched.add({ time: 0.2, duration: 5 });\n\t\t\tsched.add({ time: 0.3, duration: 5 });\n\t\t\tsched.add({ time: 0.4, duration: 5 });\n\t\t\tlet count = 0;\n\t\t\tsched.forEach((event) => {\n\t\t\t\texpect(event).to.be.an(\"object\");\n\t\t\t\tcount++;\n\t\t\t});\n\t\t\texpect(count).to.equal(5);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"iterate over null set\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tlet count = 0;\n\t\t\tsched.forEach(() => {\n\t\t\t\tcount++;\n\t\t\t});\n\t\t\texpect(count).to.equal(0);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"iterates over all items overlapping the given time\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tsched.add({ time: 0, duration: 5 });\n\t\t\tsched.add({ time: 0.1, duration: 5 });\n\t\t\tsched.add({ time: 0.2, duration: 5 });\n\t\t\tsched.add({ time: 0.3, duration: 5 });\n\t\t\tsched.add({ time: 0.4, duration: 5 });\n\t\t\tlet count = 0;\n\t\t\tsched.forEachAtTime(0.3, (event) => {\n\t\t\t\texpect(event).to.be.an(\"object\");\n\t\t\t\texpect(event.time).to.be.at.most(0.3);\n\t\t\t\tcount++;\n\t\t\t});\n\t\t\texpect(count).to.equal(4);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"handles time ranges before the available objects\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tsched.add({ time: 0.1, duration: 5 });\n\t\t\tsched.add({ time: 0.2, duration: 5 });\n\t\t\tsched.add({ time: 0.3, duration: 5 });\n\t\t\tsched.add({ time: 0.4, duration: 5 });\n\t\t\tlet count = 0;\n\t\t\tsched.forEachAtTime(0, () => {\n\t\t\t\tcount++;\n\t\t\t});\n\t\t\texpect(count).to.equal(0);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"handles time ranges after the available objects\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tsched.add({ time: 0.1, duration: 5 });\n\t\t\tsched.add({ time: 0.2, duration: 5 });\n\t\t\tsched.add({ time: 0.3, duration: 5 });\n\t\t\tsched.add({ time: 0.4, duration: 5 });\n\t\t\tlet count = 0;\n\t\t\tsched.forEachAtTime(5.5, () => {\n\t\t\t\tcount++;\n\t\t\t});\n\t\t\texpect(count).to.equal(0);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"iterates over all items after the given time\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tsched.add({ time: 0.1, duration: 5 });\n\t\t\tsched.add({ time: 0.2, duration: 5 });\n\t\t\tsched.add({ time: 0.3, duration: 5 });\n\t\t\tsched.add({ time: 0.4, duration: 5 });\n\t\t\tlet count = 0;\n\t\t\tsched.forEachFrom(0.2, (event) => {\n\t\t\t\texpect(event).to.be.an(\"object\");\n\t\t\t\texpect(event.time).to.be.gte(0.2);\n\t\t\t\tcount++;\n\t\t\t});\n\t\t\texpect(count).to.equal(3);\n\t\t\tcount = 0;\n\t\t\tsched.forEachFrom(0.35, (event) => {\n\t\t\t\texpect(event.time).to.be.gte(0.35);\n\t\t\t\tcount++;\n\t\t\t});\n\t\t\texpect(count).to.equal(1);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"handles time ranges after the available objects\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tsched.add({ time: 0.1, duration: 5 });\n\t\t\tsched.add({ time: 0.2, duration: 5 });\n\t\t\tsched.add({ time: 0.3, duration: 5 });\n\t\t\tsched.add({ time: 0.4, duration: 5 });\n\t\t\tlet count = 0;\n\t\t\tsched.forEachFrom(0.5, () => {\n\t\t\t\tcount++;\n\t\t\t});\n\t\t\texpect(count).to.equal(0);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"iterates over all items\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tsched.add({ time: 0.1, duration: 5 });\n\t\t\tsched.add({ time: 0.2, duration: 5 });\n\t\t\tsched.add({ time: 0.3, duration: 5 });\n\t\t\tsched.add({ time: 0.4, duration: 5 });\n\t\t\tlet count = 0;\n\t\t\tsched.forEach(() => {\n\t\t\t\tcount++;\n\t\t\t});\n\t\t\texpect(count).to.equal(4);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"can remove items during forEach iterations\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tfor (let i = 0; i < 1000; i++) {\n\t\t\t\tsched.add({ time: i, duration: 0.01 });\n\t\t\t}\n\t\t\tsched.forEach((event) => {\n\t\t\t\tsched.cancel(event.time);\n\t\t\t});\n\t\t\texpect(sched.length).to.equal(0);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"can remove items during forEachAtTime iterations\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tfor (let i = 0; i < 1000; i++) {\n\t\t\t\tsched.add({ time: i, duration: Infinity });\n\t\t\t}\n\t\t\tsched.forEachAtTime(1000, (event) => {\n\t\t\t\tsched.cancel(event.time);\n\t\t\t});\n\t\t\texpect(sched.length).to.equal(0);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"can remove items during forEachFrom iterations\", () => {\n\t\t\tconst sched = new IntervalTimeline();\n\t\t\tfor (let i = 0; i < 1000; i++) {\n\t\t\t\tsched.add({ time: i, duration: Infinity });\n\t\t\t}\n\t\t\tsched.forEachFrom(0, (event) => {\n\t\t\t\tsched.remove(event);\n\t\t\t});\n\t\t\texpect(sched.length).to.equal(0);\n\t\t\tsched.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/util/IntervalTimeline.ts",
    "content": "import { Tone } from \"../Tone.js\";\nimport { assert } from \"./Debug.js\";\nimport { isDefined } from \"./TypeCheck.js\";\n\n/**\n * An IntervalTimeline event must have a time and duration\n */\nexport interface IntervalTimelineEvent {\n\ttime: number;\n\tduration: number;\n\t[propName: string]: any;\n}\n\ntype IteratorCallback = (event: IntervalTimelineEvent) => void;\n\n/**\n * Similar to Tone.Timeline, but all events represent\n * intervals with both \"time\" and \"duration\" times. The\n * events are placed in a tree structure optimized\n * for querying an intersection point with the timeline\n * events. Internally uses an [Interval Tree](https://en.wikipedia.org/wiki/Interval_tree)\n * to represent the data.\n * @internal\n */\nexport class IntervalTimeline extends Tone {\n\treadonly name: string = \"IntervalTimeline\";\n\n\t/**\n\t * The root node of the interval tree\n\t */\n\tprivate _root: IntervalNode | null = null;\n\n\t/**\n\t * Keep track of the length of the timeline.\n\t */\n\tprivate _length = 0;\n\n\t/**\n\t * The event to add to the timeline. All events must\n\t * have a time and duration value\n\t * @param  event  The event to add to the timeline\n\t */\n\tadd(event: IntervalTimelineEvent): this {\n\t\tassert(isDefined(event.time), \"Events must have a time property\");\n\t\tassert(\n\t\t\tisDefined(event.duration),\n\t\t\t\"Events must have a duration parameter\"\n\t\t);\n\n\t\tevent.time = event.time.valueOf();\n\t\tlet node: IntervalNode | null = new IntervalNode(\n\t\t\tevent.time,\n\t\t\tevent.time + event.duration,\n\t\t\tevent\n\t\t);\n\t\tif (this._root === null) {\n\t\t\tthis._root = node;\n\t\t} else {\n\t\t\tthis._root.insert(node);\n\t\t}\n\t\tthis._length++;\n\t\t// Restructure tree to be balanced\n\t\twhile (node !== null) {\n\t\t\tnode.updateHeight();\n\t\t\tnode.updateMax();\n\t\t\tthis._rebalance(node);\n\t\t\tnode = node.parent;\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove an event from the timeline.\n\t * @param  event  The event to remove from the timeline\n\t */\n\tremove(event: IntervalTimelineEvent): this {\n\t\tif (this._root !== null) {\n\t\t\tconst results: IntervalNode[] = [];\n\t\t\tthis._root.search(event.time, results);\n\t\t\tfor (const node of results) {\n\t\t\t\tif (node.event === event) {\n\t\t\t\t\tthis._removeNode(node);\n\t\t\t\t\tthis._length--;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * The number of items in the timeline.\n\t * @readOnly\n\t */\n\tget length(): number {\n\t\treturn this._length;\n\t}\n\n\t/**\n\t * Remove events whose time time is after the given time\n\t * @param  after  The time to query.\n\t */\n\tcancel(after: number): this {\n\t\tthis.forEachFrom(after, (event) => this.remove(event));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set the root node as the given node\n\t */\n\tprivate _setRoot(node: IntervalNode | null): void {\n\t\tthis._root = node;\n\t\tif (this._root !== null) {\n\t\t\tthis._root.parent = null;\n\t\t}\n\t}\n\n\t/**\n\t * Replace the references to the node in the node's parent\n\t * with the replacement node.\n\t */\n\tprivate _replaceNodeInParent(\n\t\tnode: IntervalNode,\n\t\treplacement: IntervalNode | null\n\t): void {\n\t\tif (node.parent !== null) {\n\t\t\tif (node.isLeftChild()) {\n\t\t\t\tnode.parent.left = replacement;\n\t\t\t} else {\n\t\t\t\tnode.parent.right = replacement;\n\t\t\t}\n\t\t\tthis._rebalance(node.parent);\n\t\t} else {\n\t\t\tthis._setRoot(replacement);\n\t\t}\n\t}\n\n\t/**\n\t * Remove the node from the tree and replace it with\n\t * a successor which follows the schema.\n\t */\n\tprivate _removeNode(node: IntervalNode): void {\n\t\tif (node.left === null && node.right === null) {\n\t\t\tthis._replaceNodeInParent(node, null);\n\t\t} else if (node.right === null) {\n\t\t\tthis._replaceNodeInParent(node, node.left);\n\t\t} else if (node.left === null) {\n\t\t\tthis._replaceNodeInParent(node, node.right);\n\t\t} else {\n\t\t\tconst balance = node.getBalance();\n\t\t\tlet replacement: IntervalNode;\n\t\t\tlet temp: IntervalNode | null = null;\n\t\t\tif (balance > 0) {\n\t\t\t\tif (node.left.right === null) {\n\t\t\t\t\treplacement = node.left;\n\t\t\t\t\treplacement.right = node.right;\n\t\t\t\t\ttemp = replacement;\n\t\t\t\t} else {\n\t\t\t\t\treplacement = node.left.right;\n\t\t\t\t\twhile (replacement.right !== null) {\n\t\t\t\t\t\treplacement = replacement.right;\n\t\t\t\t\t}\n\t\t\t\t\tif (replacement.parent) {\n\t\t\t\t\t\treplacement.parent.right = replacement.left;\n\t\t\t\t\t\ttemp = replacement.parent;\n\t\t\t\t\t\treplacement.left = node.left;\n\t\t\t\t\t\treplacement.right = node.right;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (node.right.left === null) {\n\t\t\t\treplacement = node.right;\n\t\t\t\treplacement.left = node.left;\n\t\t\t\ttemp = replacement;\n\t\t\t} else {\n\t\t\t\treplacement = node.right.left;\n\t\t\t\twhile (replacement.left !== null) {\n\t\t\t\t\treplacement = replacement.left;\n\t\t\t\t}\n\t\t\t\tif (replacement.parent) {\n\t\t\t\t\treplacement.parent.left = replacement.right;\n\t\t\t\t\ttemp = replacement.parent;\n\t\t\t\t\treplacement.left = node.left;\n\t\t\t\t\treplacement.right = node.right;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (node.parent !== null) {\n\t\t\t\tif (node.isLeftChild()) {\n\t\t\t\t\tnode.parent.left = replacement;\n\t\t\t\t} else {\n\t\t\t\t\tnode.parent.right = replacement;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis._setRoot(replacement);\n\t\t\t}\n\t\t\tif (temp) {\n\t\t\t\tthis._rebalance(temp);\n\t\t\t}\n\t\t}\n\t\tnode.dispose();\n\t}\n\n\t/**\n\t * Rotate the tree to the left\n\t */\n\tprivate _rotateLeft(node: IntervalNode): void {\n\t\tconst parent = node.parent;\n\t\tconst isLeftChild = node.isLeftChild();\n\n\t\t// Make node.right the new root of this sub tree (instead of node)\n\t\tconst pivotNode = node.right;\n\t\tif (pivotNode) {\n\t\t\tnode.right = pivotNode.left;\n\t\t\tpivotNode.left = node;\n\t\t}\n\n\t\tif (parent !== null) {\n\t\t\tif (isLeftChild) {\n\t\t\t\tparent.left = pivotNode;\n\t\t\t} else {\n\t\t\t\tparent.right = pivotNode;\n\t\t\t}\n\t\t} else {\n\t\t\tthis._setRoot(pivotNode);\n\t\t}\n\t}\n\n\t/**\n\t * Rotate the tree to the right\n\t */\n\tprivate _rotateRight(node: IntervalNode): void {\n\t\tconst parent = node.parent;\n\t\tconst isLeftChild = node.isLeftChild();\n\n\t\t// Make node.left the new root of this sub tree (instead of node)\n\t\tconst pivotNode = node.left;\n\t\tif (pivotNode) {\n\t\t\tnode.left = pivotNode.right;\n\t\t\tpivotNode.right = node;\n\t\t}\n\n\t\tif (parent !== null) {\n\t\t\tif (isLeftChild) {\n\t\t\t\tparent.left = pivotNode;\n\t\t\t} else {\n\t\t\t\tparent.right = pivotNode;\n\t\t\t}\n\t\t} else {\n\t\t\tthis._setRoot(pivotNode);\n\t\t}\n\t}\n\n\t/**\n\t * Balance the BST\n\t */\n\tprivate _rebalance(node: IntervalNode): void {\n\t\tconst balance = node.getBalance();\n\t\tif (balance > 1 && node.left) {\n\t\t\tif (node.left.getBalance() < 0) {\n\t\t\t\tthis._rotateLeft(node.left);\n\t\t\t} else {\n\t\t\t\tthis._rotateRight(node);\n\t\t\t}\n\t\t} else if (balance < -1 && node.right) {\n\t\t\tif (node.right.getBalance() > 0) {\n\t\t\t\tthis._rotateRight(node.right);\n\t\t\t} else {\n\t\t\t\tthis._rotateLeft(node);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Get an event whose time and duration span the give time. Will\n\t * return the match whose \"time\" value is closest to the given time.\n\t * @return  The event which spans the desired time\n\t */\n\tget(time: number): IntervalTimelineEvent | null {\n\t\tif (this._root !== null) {\n\t\t\tconst results: IntervalNode[] = [];\n\t\t\tthis._root.search(time, results);\n\t\t\tif (results.length > 0) {\n\t\t\t\tlet max = results[0];\n\t\t\t\tfor (let i = 1; i < results.length; i++) {\n\t\t\t\t\tif (results[i].low > max.low) {\n\t\t\t\t\t\tmax = results[i];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn max.event;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Iterate over everything in the timeline.\n\t * @param  callback The callback to invoke with every item\n\t */\n\tforEach(callback: IteratorCallback): this {\n\t\tif (this._root !== null) {\n\t\t\tconst allNodes: IntervalNode[] = [];\n\t\t\tthis._root.traverse((node) => allNodes.push(node));\n\t\t\tallNodes.forEach((node) => {\n\t\t\t\tif (node.event) {\n\t\t\t\t\tcallback(node.event);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Iterate over everything in the array in which the given time\n\t * overlaps with the time and duration time of the event.\n\t * @param  time The time to check if items are overlapping\n\t * @param  callback The callback to invoke with every item\n\t */\n\tforEachAtTime(time: number, callback: IteratorCallback): this {\n\t\tif (this._root !== null) {\n\t\t\tconst results: IntervalNode[] = [];\n\t\t\tthis._root.search(time, results);\n\t\t\tresults.forEach((node) => {\n\t\t\t\tif (node.event) {\n\t\t\t\t\tcallback(node.event);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Iterate over everything in the array in which the time is greater\n\t * than or equal to the given time.\n\t * @param  time The time to check if items are before\n\t * @param  callback The callback to invoke with every item\n\t */\n\tforEachFrom(time: number, callback: IteratorCallback): this {\n\t\tif (this._root !== null) {\n\t\t\tconst results: IntervalNode[] = [];\n\t\t\tthis._root.searchAfter(time, results);\n\t\t\tresults.forEach((node) => {\n\t\t\t\tif (node.event) {\n\t\t\t\t\tcallback(node.event);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clean up\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tif (this._root !== null) {\n\t\t\tthis._root.traverse((node) => node.dispose());\n\t\t}\n\t\tthis._root = null;\n\t\treturn this;\n\t}\n}\n\n//-------------------------------------\n// \tINTERVAL NODE HELPER\n//-------------------------------------\n\n/**\n * Represents a node in the binary search tree, with the addition\n * of a \"high\" value which keeps track of the highest value of\n * its children.\n * References:\n * https://brooknovak.wordpress.com/2013/12/07/augmented-interval-tree-in-c/\n * http://www.mif.vu.lt/~valdas/ALGORITMAI/LITERATURA/Cormen/Cormen.pdf\n * @param low\n * @param high\n */\nclass IntervalNode {\n\t// the event container\n\tevent: IntervalTimelineEvent | null;\n\t// the low value\n\tlow: number;\n\t// the high value\n\thigh: number;\n\t// the high value for this and all child nodes\n\tmax: number;\n\t// the nodes to the left\n\tprivate _left: IntervalNode | null = null;\n\t// the nodes to the right\n\tprivate _right: IntervalNode | null = null;\n\t// the parent node\n\tparent: IntervalNode | null = null;\n\t// the number of child nodes\n\theight = 0;\n\n\tconstructor(low: number, high: number, event: IntervalTimelineEvent) {\n\t\tthis.event = event;\n\t\t// the low value\n\t\tthis.low = low;\n\t\t// the high value\n\t\tthis.high = high;\n\t\t// the high value for this and all child nodes\n\t\tthis.max = this.high;\n\t}\n\n\t/**\n\t * Insert a node into the correct spot in the tree\n\t */\n\tinsert(node: IntervalNode): void {\n\t\tif (node.low <= this.low) {\n\t\t\tif (this.left === null) {\n\t\t\t\tthis.left = node;\n\t\t\t} else {\n\t\t\t\tthis.left.insert(node);\n\t\t\t}\n\t\t} else if (this.right === null) {\n\t\t\tthis.right = node;\n\t\t} else {\n\t\t\tthis.right.insert(node);\n\t\t}\n\t}\n\n\t/**\n\t * Search the tree for nodes which overlap\n\t * with the given point\n\t * @param  point  The point to query\n\t * @param  results  The array to put the results\n\t */\n\tsearch(point: number, results: IntervalNode[]): void {\n\t\t// If p is to the right of the rightmost point of any interval\n\t\t// in this node and all children, there won't be any matches.\n\t\tif (point > this.max) {\n\t\t\treturn;\n\t\t}\n\t\t// Search left children\n\t\tif (this.left !== null) {\n\t\t\tthis.left.search(point, results);\n\t\t}\n\t\t// Check this node\n\t\tif (this.low <= point && this.high > point) {\n\t\t\tresults.push(this);\n\t\t}\n\t\t// If p is to the left of the time of this interval,\n\t\t// then it can't be in any child to the right.\n\t\tif (this.low > point) {\n\t\t\treturn;\n\t\t}\n\t\t// Search right children\n\t\tif (this.right !== null) {\n\t\t\tthis.right.search(point, results);\n\t\t}\n\t}\n\n\t/**\n\t * Search the tree for nodes which are less\n\t * than the given point\n\t * @param  point  The point to query\n\t * @param  results  The array to put the results\n\t */\n\tsearchAfter(point: number, results: IntervalNode[]): void {\n\t\t// Check this node\n\t\tif (this.low >= point) {\n\t\t\tresults.push(this);\n\t\t\tif (this.left !== null) {\n\t\t\t\tthis.left.searchAfter(point, results);\n\t\t\t}\n\t\t}\n\t\t// search the right side\n\t\tif (this.right !== null) {\n\t\t\tthis.right.searchAfter(point, results);\n\t\t}\n\t}\n\n\t/**\n\t * Invoke the callback on this element and both its branches\n\t * @param  {Function}  callback\n\t */\n\ttraverse(callback: (self: IntervalNode) => void): void {\n\t\tcallback(this);\n\t\tif (this.left !== null) {\n\t\t\tthis.left.traverse(callback);\n\t\t}\n\t\tif (this.right !== null) {\n\t\t\tthis.right.traverse(callback);\n\t\t}\n\t}\n\n\t/**\n\t * Update the height of the node\n\t */\n\tupdateHeight(): void {\n\t\tif (this.left !== null && this.right !== null) {\n\t\t\tthis.height = Math.max(this.left.height, this.right.height) + 1;\n\t\t} else if (this.right !== null) {\n\t\t\tthis.height = this.right.height + 1;\n\t\t} else if (this.left !== null) {\n\t\t\tthis.height = this.left.height + 1;\n\t\t} else {\n\t\t\tthis.height = 0;\n\t\t}\n\t}\n\n\t/**\n\t * Update the height of the node\n\t */\n\tupdateMax(): void {\n\t\tthis.max = this.high;\n\t\tif (this.left !== null) {\n\t\t\tthis.max = Math.max(this.max, this.left.max);\n\t\t}\n\t\tif (this.right !== null) {\n\t\t\tthis.max = Math.max(this.max, this.right.max);\n\t\t}\n\t}\n\n\t/**\n\t * The balance is how the leafs are distributed on the node\n\t * @return  Negative numbers are balanced to the right\n\t */\n\tgetBalance(): number {\n\t\tlet balance = 0;\n\t\tif (this.left !== null && this.right !== null) {\n\t\t\tbalance = this.left.height - this.right.height;\n\t\t} else if (this.left !== null) {\n\t\t\tbalance = this.left.height + 1;\n\t\t} else if (this.right !== null) {\n\t\t\tbalance = -(this.right.height + 1);\n\t\t}\n\t\treturn balance;\n\t}\n\n\t/**\n\t * @returns true if this node is the left child of its parent\n\t */\n\tisLeftChild(): boolean {\n\t\treturn this.parent !== null && this.parent.left === this;\n\t}\n\n\t/**\n\t * get/set the left node\n\t */\n\tget left(): IntervalNode | null {\n\t\treturn this._left;\n\t}\n\n\tset left(node: IntervalNode | null) {\n\t\tthis._left = node;\n\t\tif (node !== null) {\n\t\t\tnode.parent = this;\n\t\t}\n\t\tthis.updateHeight();\n\t\tthis.updateMax();\n\t}\n\n\t/**\n\t * get/set the right node\n\t */\n\tget right(): IntervalNode | null {\n\t\treturn this._right;\n\t}\n\n\tset right(node: IntervalNode | null) {\n\t\tthis._right = node;\n\t\tif (node !== null) {\n\t\t\tnode.parent = this;\n\t\t}\n\t\tthis.updateHeight();\n\t\tthis.updateMax();\n\t}\n\n\t/**\n\t * null out references.\n\t */\n\tdispose(): void {\n\t\tthis.parent = null;\n\t\tthis._left = null;\n\t\tthis._right = null;\n\t\tthis.event = null;\n\t}\n}\n"
  },
  {
    "path": "Tone/core/util/Math.ts",
    "content": "/**\n * The threshold for correctness for operators. Less than one sample even\n * at very high sampling rates (e.g. `1e-6 < 1 / 192000`).\n */\nconst EPSILON = 1e-6;\n\n/**\n * Test if A is greater than B\n */\nexport function GT(a: number, b: number): boolean {\n\treturn a > b + EPSILON;\n}\n\n/**\n * Test if A is greater than or equal to B\n */\nexport function GTE(a: number, b: number): boolean {\n\treturn GT(a, b) || EQ(a, b);\n}\n\n/**\n * Test if A is less than B\n */\nexport function LT(a: number, b: number): boolean {\n\treturn a + EPSILON < b;\n}\n\n/**\n * Test if A is less than B\n */\nexport function EQ(a: number, b: number): boolean {\n\treturn Math.abs(a - b) < EPSILON;\n}\n\n/**\n * Clamp the value within the given range\n */\nexport function clamp(value: number, min: number, max: number): number {\n\treturn Math.max(Math.min(value, max), min);\n}\n"
  },
  {
    "path": "Tone/core/util/StateTimeline.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { StateTimeline } from \"./StateTimeline.js\";\n\ndescribe(\"StateTimeline\", () => {\n\tit(\"can be created and disposed\", () => {\n\t\tconst sched = new StateTimeline();\n\t\tsched.dispose();\n\t});\n\n\tit(\"can schedule a state at a given time\", () => {\n\t\tconst sched = new StateTimeline();\n\t\tsched.setStateAtTime(\"started\", 0);\n\t\tsched.setStateAtTime(\"stopped\", 1);\n\t\tsched.setStateAtTime(\"started\", 1);\n\t\tsched.dispose();\n\t});\n\n\tit(\"can get a state at a given time\", () => {\n\t\tconst sched = new StateTimeline();\n\t\tsched.setStateAtTime(\"started\", 0);\n\t\tsched.setStateAtTime(\"stopped\", 1);\n\t\tsched.setStateAtTime(\"started\", 2);\n\t\texpect(sched.getValueAtTime(1)).to.equal(\"stopped\");\n\t\texpect(sched.getValueAtTime(0.999)).to.equal(\"started\");\n\t\tsched.dispose();\n\t});\n\n\tit(\"returns initial state if it's before any scheduled states\", () => {\n\t\tconst sched = new StateTimeline();\n\t\tsched.setStateAtTime(\"started\", 0);\n\t\tsched.setStateAtTime(\"stopped\", 1);\n\t\tsched.setStateAtTime(\"started\", 2);\n\t\texpect(sched.getValueAtTime(-11)).to.equal(\"stopped\");\n\t\tsched.dispose();\n\t});\n\n\tit(\"returns the last event inserted if the timing is very close\", () => {\n\t\tconst sched = new StateTimeline();\n\t\tsched.setStateAtTime(\"stopped\", 1 + 1e-7);\n\t\tsched.setStateAtTime(\"started\", 1 - 1e-7);\n\t\texpect(sched.getValueAtTime(1 - 1e-7)).to.equal(\"started\");\n\t\tsched.dispose();\n\t});\n\n\tit(\"returns initial state if defined and query time is before any scheduled states\", () => {\n\t\tconst sched = new StateTimeline(\"started\");\n\t\tsched.setStateAtTime(\"started\", 20);\n\t\tsched.setStateAtTime(\"stopped\", 21);\n\t\tsched.setStateAtTime(\"started\", 22);\n\t\texpect(sched.getValueAtTime(0)).is.equal(\"started\");\n\t\tsched.dispose();\n\t});\n\n\tit(\"gets the last occurrence of the state at or before the given time\", () => {\n\t\tconst sched = new StateTimeline();\n\t\tsched.setStateAtTime(\"started\", 0);\n\t\tsched.setStateAtTime(\"stopped\", 1);\n\t\tsched.setStateAtTime(\"started\", 2);\n\t\tsched.setStateAtTime(\"stopped\", 3);\n\t\texpect(sched.getLastState(\"stopped\", 1)).to.exist;\n\t\texpect(sched.getLastState(\"stopped\", 1)?.state).is.equal(\"stopped\");\n\t\texpect(sched.getLastState(\"stopped\", 2)).to.exist;\n\t\texpect(sched.getLastState(\"stopped\", 2)?.state).is.equal(\"stopped\");\n\t\texpect(sched.getLastState(\"stopped\", 2)?.time).is.equal(1);\n\t\texpect(sched.getLastState(\"stopped\", 0.9)?.time).to.equal(0);\n\t\texpect(sched.getLastState(\"stopped\", 4)?.state).is.equal(\"stopped\");\n\t\texpect(sched.getLastState(\"stopped\", 4)?.time).is.equal(3);\n\t\tsched.dispose();\n\t});\n\n\tit(\"gets the next occurrence of the state at or before the given time\", () => {\n\t\tconst sched = new StateTimeline();\n\t\tsched.setStateAtTime(\"started\", 0);\n\t\tsched.setStateAtTime(\"stopped\", 1);\n\t\tsched.setStateAtTime(\"started\", 2);\n\t\tsched.setStateAtTime(\"stopped\", 3);\n\t\texpect(sched.getNextState(\"stopped\", 1)).to.exist;\n\t\texpect(sched.getNextState(\"stopped\", 1)?.state).is.equal(\"stopped\");\n\t\texpect(sched.getNextState(\"stopped\", 2)).to.exist;\n\t\texpect(sched.getNextState(\"stopped\", 2)?.state).is.equal(\"stopped\");\n\t\texpect(sched.getNextState(\"stopped\", 2)?.time).is.equal(3);\n\t\texpect(sched.getNextState(\"stopped\", 0.9)).to.exist;\n\t\texpect(sched.getNextState(\"stopped\", 0.9)?.state).is.equal(\"stopped\");\n\t\texpect(sched.getNextState(\"stopped\", 0.9)?.time).is.equal(1);\n\t\tsched.dispose();\n\t});\n});\n"
  },
  {
    "path": "Tone/core/util/StateTimeline.ts",
    "content": "import { Seconds } from \"../type/Units.js\";\nimport { assertRange } from \"./Debug.js\";\nimport { Timeline, TimelineEvent } from \"./Timeline.js\";\n\nexport type BasicPlaybackState = \"started\" | \"stopped\";\nexport type PlaybackState = BasicPlaybackState | \"paused\";\n\nexport interface StateTimelineEvent extends TimelineEvent {\n\tstate: PlaybackState;\n}\n\n/**\n * A Timeline State. Provides the methods: `setStateAtTime(\"state\", time)` and `getValueAtTime(time)`\n * @param initial The initial state of the StateTimeline.  Defaults to `undefined`\n * @internal\n */\nexport class StateTimeline<\n\tAdditionalOptions extends Record<string, any> = Record<string, any>,\n> extends Timeline<StateTimelineEvent & AdditionalOptions> {\n\treadonly name: string = \"StateTimeline\";\n\n\t/**\n\t * The initial state\n\t */\n\tprivate _initial: PlaybackState;\n\n\tconstructor(initial: PlaybackState = \"stopped\") {\n\t\tsuper();\n\t\tthis._initial = initial;\n\t\tthis.setStateAtTime(this._initial, 0);\n\t}\n\n\t/**\n\t * Returns the scheduled state scheduled before or at\n\t * the given time.\n\t * @param  time  The time to query.\n\t * @return  The name of the state input in setStateAtTime.\n\t */\n\tgetValueAtTime(time: Seconds): PlaybackState {\n\t\tconst event = this.get(time);\n\t\tif (event !== null) {\n\t\t\treturn event.state;\n\t\t} else {\n\t\t\treturn this._initial;\n\t\t}\n\t}\n\n\t/**\n\t * Add a state to the timeline.\n\t * @param  state The name of the state to set.\n\t * @param  time  The time to query.\n\t * @param options Any additional options that are needed in the timeline.\n\t */\n\tsetStateAtTime(\n\t\tstate: PlaybackState,\n\t\ttime: Seconds,\n\t\toptions?: AdditionalOptions\n\t): this {\n\t\tassertRange(time, 0);\n\t\tthis.add(\n\t\t\tObject.assign({}, options, {\n\t\t\t\tstate,\n\t\t\t\ttime,\n\t\t\t})\n\t\t);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Return the event before the time with the given state\n\t * @param  state The state to look for\n\t * @param  time  When to check before\n\t * @return  The event with the given state before the time\n\t */\n\tgetLastState(\n\t\tstate: PlaybackState,\n\t\ttime: number\n\t): (StateTimelineEvent & AdditionalOptions) | undefined {\n\t\t// time = this.toSeconds(time);\n\t\tconst index = this._search(time);\n\t\tfor (let i = index; i >= 0; i--) {\n\t\t\tconst event = this._timeline[i];\n\t\t\tif (event.state === state) {\n\t\t\t\treturn event;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Return the event after the time with the given state\n\t * @param  state The state to look for\n\t * @param  time  When to check from\n\t * @return  The event with the given state after the time\n\t */\n\tgetNextState(\n\t\tstate: PlaybackState,\n\t\ttime: number\n\t): (StateTimelineEvent & AdditionalOptions) | undefined {\n\t\t// time = this.toSeconds(time);\n\t\tconst index = this._search(time);\n\t\tif (index !== -1) {\n\t\t\tfor (let i = index; i < this._timeline.length; i++) {\n\t\t\t\tconst event = this._timeline[i];\n\t\t\t\tif (event.state === state) {\n\t\t\t\t\treturn event;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Tone/core/util/Timeline.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { Timeline } from \"./Timeline.js\";\n\ninterface StateTimelineEvent {\n\tstate: string;\n\ttime: number;\n}\n\ninterface TimelineNameEvent {\n\tname: string;\n\ttime: number;\n}\n\ninterface TimelineValueEvent {\n\ttime: number;\n\tvalue: any;\n}\n\ndescribe(\"Timeline\", () => {\n\tit(\"can be created and disposed\", () => {\n\t\tconst sched = new Timeline();\n\t\tsched.dispose();\n\t});\n\n\tit(\"accepts events into the timeline\", () => {\n\t\tconst sched = new Timeline<StateTimelineEvent>();\n\t\tsched.add({\n\t\t\tstate: \"A\",\n\t\t\ttime: 0,\n\t\t});\n\t\tsched.add({\n\t\t\tstate: \"B\",\n\t\t\ttime: 1,\n\t\t});\n\t\tsched.add({\n\t\t\tstate: \"C\",\n\t\t\ttime: 2,\n\t\t});\n\t\tsched.dispose();\n\t});\n\n\tit(\"can insert events in the timeline in the right order\", () => {\n\t\tconst sched = new Timeline();\n\t\tsched.add({\n\t\t\ttime: 0,\n\t\t});\n\t\tsched.add({\n\t\t\ttime: 2,\n\t\t});\n\t\tsched.add({\n\t\t\ttime: 1,\n\t\t});\n\t\tlet index = 0;\n\t\tconst eventTimes = [0, 1, 2];\n\t\tsched.forEach((event) => {\n\t\t\texpect(event.time).to.equal(eventTimes[index++]);\n\t\t});\n\t\tsched.dispose();\n\t});\n\n\tit(\"can get the length of the timeline\", () => {\n\t\tconst sched = new Timeline();\n\t\texpect(sched.length).to.equal(0);\n\t\tsched.add({\n\t\t\ttime: 0,\n\t\t});\n\t\texpect(sched.length).to.equal(1);\n\t\tsched.dispose();\n\t});\n\n\tit(\"can remove items from the timeline\", () => {\n\t\tconst sched = new Timeline();\n\t\tconst obj = { time: 0 };\n\t\tsched.add(obj);\n\t\tsched.add({\n\t\t\ttime: 2,\n\t\t});\n\t\texpect(sched.length).to.equal(2);\n\t\tsched.remove(obj);\n\t\texpect(sched.length).to.equal(1);\n\t\tsched.dispose();\n\t});\n\n\tit(\"has no effect to remove an object which is not there\", () => {\n\t\tconst sched = new Timeline();\n\t\tsched.add({\n\t\t\ttime: 2,\n\t\t});\n\t\tsched.remove({ time: 1 });\n\t\texpect(sched.length).to.equal(1);\n\t\tsched.forEach((event) => {\n\t\t\tsched.remove({ time: 4 });\n\t\t});\n\t\texpect(sched.length).to.equal(1);\n\t\tsched.dispose();\n\t});\n\n\tit(\"can search for events in the timeline by time\", () => {\n\t\tconst sched = new Timeline();\n\t\tsched.add({\n\t\t\ttime: 0,\n\t\t});\n\t\tsched.add({\n\t\t\ttime: 2,\n\t\t});\n\t\tsched.add({\n\t\t\ttime: 1,\n\t\t});\n\t\t// expect(sched._search(0)).to.equal(0);\n\t\t// expect(sched._search(0.01)).to.equal(0);\n\t\t// expect(sched._search(1)).to.equal(1);\n\t\t// expect(sched._search(1.01)).to.equal(1);\n\t\t// expect(sched._search(2)).to.equal(2);\n\t\t// expect(sched._search(20000)).to.equal(2);\n\t\t// expect(sched._search(-1)).to.equal(-1);\n\t\tsched.dispose();\n\t});\n\n\tit(\"can get a previous event\", () => {\n\t\tconst sched = new Timeline();\n\t\tconst event0 = {\n\t\t\ttime: 0,\n\t\t};\n\t\tconst event1 = {\n\t\t\ttime: 1,\n\t\t};\n\t\tsched.add(event0);\n\t\tsched.add(event1);\n\t\texpect(sched.previousEvent(event1)).to.equal(event0);\n\t\texpect(sched.previousEvent(event0)).to.equal(null);\n\t\tsched.dispose();\n\t});\n\n\tit(\"can get the scheduled event at the given time\", () => {\n\t\tconst sched = new Timeline<StateTimelineEvent>();\n\t\tsched.add({\n\t\t\tstate: \"A\",\n\t\t\ttime: 2,\n\t\t});\n\t\tsched.add({\n\t\t\tstate: \"C\",\n\t\t\ttime: 9.4,\n\t\t});\n\t\tsched.add({\n\t\t\tstate: \"B\",\n\t\t\ttime: 6,\n\t\t});\n\t\texpect(sched.get(0)).is.null;\n\t\tconst e1 = sched.get(2);\n\t\tconst e2 = sched.get(5.9);\n\t\tconst e3 = sched.get(6.1);\n\t\tconst e4 = sched.get(12);\n\t\tif (e1 && e2 && e3 && e4) {\n\t\t\texpect(e1.state).is.equal(\"A\");\n\t\t\texpect(e2.state).is.equal(\"A\");\n\t\t\texpect(e3.state).is.equal(\"B\");\n\t\t\texpect(e4.state).is.equal(\"C\");\n\t\t} else {\n\t\t\tthrow new Error(\"expected 4 events\");\n\t\t}\n\t\tsched.dispose();\n\t});\n\n\tit(\"puts the second scheduled event after if two events are scheduled at the same time\", () => {\n\t\tconst sched = new Timeline<TimelineNameEvent>();\n\t\tsched.add({\n\t\t\tname: \"A\",\n\t\t\ttime: 0,\n\t\t});\n\t\tsched.add({\n\t\t\tname: \"B\",\n\t\t\ttime: 0,\n\t\t});\n\t\tconst firstEvent0 = sched.get(0);\n\t\tif (firstEvent0) {\n\t\t\texpect(firstEvent0.name).is.equal(\"B\");\n\t\t}\n\t\tsched.add({\n\t\t\tname: \"C\",\n\t\t\ttime: 0,\n\t\t});\n\t\tconst firstEvent1 = sched.get(0);\n\t\tif (firstEvent1) {\n\t\t\texpect(firstEvent1.name).is.equal(\"C\");\n\t\t}\n\t\tsched.dispose();\n\t});\n\n\tit(\"can the next event after the given time\", () => {\n\t\tconst sched = new Timeline<StateTimelineEvent>();\n\t\texpect(sched.getAfter(0)).is.null;\n\t\tsched.add({\n\t\t\tstate: \"A\",\n\t\t\ttime: 0.1,\n\t\t});\n\t\tsched.add({\n\t\t\tstate: \"B\",\n\t\t\ttime: 1.1,\n\t\t});\n\t\tsched.add({\n\t\t\tstate: \"C\",\n\t\t\ttime: 2.1,\n\t\t});\n\t\tconst firstEvent = sched.getAfter(0);\n\t\tconst secondEvent = sched.getAfter(1);\n\t\tif (firstEvent && secondEvent) {\n\t\t\texpect(firstEvent.state).is.equal(\"A\");\n\t\t\texpect(secondEvent.state).is.equal(\"B\");\n\t\t} else {\n\t\t\tthrow new Error(\"should have 2 events\");\n\t\t}\n\t\texpect(sched.getAfter(3)).is.null;\n\t\tsched.dispose();\n\t});\n\n\tit(\"can the event before the event before the given time\", () => {\n\t\tconst sched = new Timeline<StateTimelineEvent>();\n\t\texpect(sched.getBefore(0)).is.null;\n\t\tsched.add({\n\t\t\tstate: \"A\",\n\t\t\ttime: 0.1,\n\t\t});\n\t\tsched.add({\n\t\t\tstate: \"B\",\n\t\t\ttime: 1.1,\n\t\t});\n\t\tsched.add({\n\t\t\tstate: \"C\",\n\t\t\ttime: 2.1,\n\t\t});\n\t\texpect(sched.getBefore(0)).is.null;\n\t\tconst firstEvent = sched.getBefore(1.1);\n\t\tconst secondEvent = sched.getBefore(2.1);\n\t\tconst thirdEvent = sched.getBefore(3);\n\t\tif (firstEvent && secondEvent && thirdEvent) {\n\t\t\texpect(firstEvent.state).is.equal(\"A\");\n\t\t\texpect(secondEvent.state).is.equal(\"B\");\n\t\t\texpect(thirdEvent.state).is.equal(\"C\");\n\t\t} else {\n\t\t\tthrow new Error(\"should have 3 events\");\n\t\t}\n\t\tsched.dispose();\n\t});\n\n\tit(\"can cancel an item\", () => {\n\t\tconst sched = new Timeline();\n\t\tsched.add({ time: 3 });\n\t\tsched.add({ time: 5 });\n\t\tsched.add({ time: 4 });\n\t\tsched.add({ time: 8 });\n\t\tsched.add({ time: 5 });\n\t\texpect(sched.length).to.equal(5);\n\t\tsched.cancel(10);\n\t\texpect(sched.length).to.equal(5);\n\t\tsched.cancel(5);\n\t\texpect(sched.length).to.equal(2);\n\t\tsched.cancel(3);\n\t\texpect(sched.length).to.equal(0);\n\t\tsched.dispose();\n\t});\n\n\tit(\"can cancel items after the given time\", () => {\n\t\tconst sched = new Timeline();\n\t\tfor (let i = 0; i < 100; i++) {\n\t\t\tsched.add({ time: 100 - i });\n\t\t}\n\t\tsched.cancel(10);\n\t\texpect(sched.length).to.equal(9);\n\t\tsched.cancel(5);\n\t\texpect(sched.length).to.equal(4);\n\t\tsched.cancel(0);\n\t\texpect(sched.length).to.equal(0);\n\t\tsched.dispose();\n\t});\n\n\tit(\"can cancel items before the given time\", () => {\n\t\tconst sched = new Timeline();\n\t\tfor (let i = 0; i < 100; i++) {\n\t\t\tsched.add({ time: i });\n\t\t}\n\t\tsched.cancelBefore(9);\n\t\texpect(sched.length).to.equal(90);\n\t\tsched.cancelBefore(10.1);\n\t\texpect(sched.length).to.equal(89);\n\t\tsched.cancelBefore(100);\n\t\texpect(sched.length).to.equal(0);\n\t\tsched.dispose();\n\t});\n\n\tit(\"has no problem with many items\", () => {\n\t\tconst sched = new Timeline();\n\t\tfor (let i = 0; i < 10000; i++) {\n\t\t\tsched.add({\n\t\t\t\ttime: i,\n\t\t\t});\n\t\t}\n\t\tfor (let j = 0; j < 1000; j++) {\n\t\t\tconst val = sched.get(j);\n\t\t\tif (val) {\n\t\t\t\texpect(val.time).to.equal(j);\n\t\t\t}\n\t\t}\n\t\tsched.dispose();\n\t});\n\n\tit(\"enforces increasing time\", () => {\n\t\tconst sched = new Timeline({\n\t\t\tincreasing: true,\n\t\t});\n\t\texpect(() => {\n\t\t\tsched.add({ time: 1 });\n\t\t\tsched.add({ time: 0 });\n\t\t}).to.throw(Error);\n\t\tsched.dispose();\n\t});\n\n\tit(\"the same time value is allowed to be added\", () => {\n\t\tconst sched = new Timeline({\n\t\t\tincreasing: true,\n\t\t});\n\t\tsched.add({ time: 1 });\n\t\tsched.add({ time: 1 });\n\t\tsched.add({ time: 1 });\n\t\tsched.dispose();\n\t});\n\n\tit(\"can constrain the length of the timeline\", () => {\n\t\tconst sched = new Timeline(4);\n\t\tfor (let i = 0; i < 10000; i++) {\n\t\t\tsched.add({\n\t\t\t\ttime: i,\n\t\t\t});\n\t\t}\n\t\texpect(sched.length).to.equal(4);\n\t\tsched.dispose();\n\t});\n\n\tit(\"can peek and shift off the first element\", () => {\n\t\tconst timeline = new Timeline<TimelineValueEvent>();\n\t\ttimeline.add({\n\t\t\ttime: 0,\n\t\t\tvalue: \"a\",\n\t\t});\n\t\ttimeline.add({\n\t\t\ttime: 1,\n\t\t\tvalue: \"b\",\n\t\t});\n\t\ttimeline.add({\n\t\t\ttime: 2,\n\t\t\tvalue: \"c\",\n\t\t});\n\t\texpect(timeline.length).to.equal(3);\n\t\tconst peekValue = timeline.peek();\n\t\tif (peekValue) {\n\t\t\texpect(peekValue.value).to.equal(\"a\");\n\t\t} else {\n\t\t\tthrow new Error(\"should have value\");\n\t\t}\n\t\texpect(timeline.length).to.equal(3);\n\n\t\tconst shiftValue = timeline.shift();\n\t\tif (shiftValue) {\n\t\t\texpect(shiftValue.value).to.equal(\"a\");\n\t\t} else {\n\t\t\tthrow new Error(\"should have value\");\n\t\t}\n\t\texpect(timeline.length).to.equal(2);\n\t\tconst peekValue2 = timeline.peek();\n\t\tif (peekValue2) {\n\t\t\texpect(peekValue2.value).to.equal(\"b\");\n\t\t} else {\n\t\t\tthrow new Error(\"should have value\");\n\t\t}\n\t\tconst shiftValue2 = timeline.shift();\n\t\tif (shiftValue2) {\n\t\t\texpect(shiftValue2.value).to.equal(\"b\");\n\t\t} else {\n\t\t\tthrow new Error(\"should have value\");\n\t\t}\n\t\texpect(timeline.length).to.equal(1);\n\t\ttimeline.dispose();\n\t});\n\n\tcontext(\"Iterators\", () => {\n\t\tit(\"iterates over all items and returns and item\", () => {\n\t\t\tconst sched = new Timeline();\n\t\t\tsched.add({ time: 0 });\n\t\t\tsched.add({ time: 0.1 });\n\t\t\tsched.add({ time: 0.2 });\n\t\t\tsched.add({ time: 0.3 });\n\t\t\tsched.add({ time: 0.4 });\n\t\t\tlet count = 0;\n\t\t\tsched.forEach((event) => {\n\t\t\t\texpect(event).to.be.an(\"object\");\n\t\t\t\tcount++;\n\t\t\t});\n\t\t\texpect(count).to.equal(5);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"iterates over all items before the given time\", () => {\n\t\t\tconst sched = new Timeline();\n\t\t\tsched.add({ time: 0 });\n\t\t\tsched.add({ time: 0.1 });\n\t\t\tsched.add({ time: 0.2 });\n\t\t\tsched.add({ time: 0.3 });\n\t\t\tsched.add({ time: 0.4 });\n\t\t\tlet count = 0;\n\t\t\tsched.forEachBefore(0.3, (event) => {\n\t\t\t\texpect(event).to.be.an(\"object\");\n\t\t\t\texpect(event.time).to.be.at.most(0.3);\n\t\t\t\tcount++;\n\t\t\t});\n\t\t\texpect(count).to.equal(4);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"handles time ranges before the available objects\", () => {\n\t\t\tconst sched = new Timeline();\n\t\t\tsched.add({ time: 0.1 });\n\t\t\tsched.add({ time: 0.2 });\n\t\t\tsched.add({ time: 0.3 });\n\t\t\tsched.add({ time: 0.4 });\n\t\t\tlet count = 0;\n\t\t\tsched.forEachBefore(0, () => {\n\t\t\t\tcount++;\n\t\t\t});\n\t\t\texpect(count).to.equal(0);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"iterates over all items after the given time\", () => {\n\t\t\tconst sched = new Timeline();\n\t\t\tsched.add({ time: 0 });\n\t\t\tsched.add({ time: 0.1 });\n\t\t\tsched.add({ time: 0.2 });\n\t\t\tsched.add({ time: 0.3 });\n\t\t\tsched.add({ time: 0.4 });\n\t\t\tlet count = 0;\n\t\t\tsched.forEachAfter(0.1, (event) => {\n\t\t\t\texpect(event).to.be.an(\"object\");\n\t\t\t\texpect(event.time).to.be.above(0.1);\n\t\t\t\tcount++;\n\t\t\t});\n\t\t\texpect(count).to.equal(3);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"handles time ranges after the available objects\", () => {\n\t\t\tconst sched = new Timeline();\n\t\t\tsched.add({ time: 0.1 });\n\t\t\tsched.add({ time: 0.2 });\n\t\t\tsched.add({ time: 0.3 });\n\t\t\tsched.add({ time: 0.4 });\n\t\t\tlet count = 0;\n\t\t\tsched.forEachAfter(0.5, () => {\n\t\t\t\tcount++;\n\t\t\t});\n\t\t\texpect(count).to.equal(0);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"handles time ranges before the first object\", () => {\n\t\t\tconst sched = new Timeline();\n\t\t\tsched.add({ time: 0.1 });\n\t\t\tsched.add({ time: 0.2 });\n\t\t\tsched.add({ time: 0.3 });\n\t\t\tsched.add({ time: 0.4 });\n\t\t\tlet count = 0;\n\t\t\tsched.forEachAfter(-Infinity, () => {\n\t\t\t\tcount++;\n\t\t\t});\n\t\t\texpect(count).to.equal(4);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"can iterate after inclusive of the item at the given time\", () => {\n\t\t\tconst sched = new Timeline();\n\t\t\tsched.add({ time: 0.1 });\n\t\t\tsched.add({ time: 0.2 });\n\t\t\tsched.add({ time: 0.2 });\n\t\t\tsched.add({ time: 0.3 });\n\t\t\tsched.add({ time: 0.4 });\n\t\t\tlet count = 0;\n\t\t\tsched.forEachFrom(0.2, () => {\n\t\t\t\tcount++;\n\t\t\t});\n\t\t\texpect(count).to.equal(4);\n\t\t\tcount = 0;\n\t\t\tsched.forEachFrom(0.21, () => {\n\t\t\t\tcount++;\n\t\t\t});\n\t\t\texpect(count).to.equal(2);\n\t\t\tcount = 0;\n\t\t\tsched.forEachFrom(0, () => {\n\t\t\t\tcount++;\n\t\t\t});\n\t\t\texpect(count).to.equal(5);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"iterates over all items at the given time\", () => {\n\t\t\tconst sched = new Timeline();\n\t\t\tsched.add({ time: 0 });\n\t\t\tsched.add({ time: 0 });\n\t\t\tsched.add({ time: 0.2 });\n\t\t\tsched.add({ time: 0.2 });\n\t\t\tsched.add({ time: 0.4 });\n\t\t\tlet count = 0;\n\t\t\tsched.forEachAtTime(0.1, (event) => {\n\t\t\t\tcount++;\n\t\t\t});\n\t\t\texpect(count).to.equal(0);\n\t\t\t// and with an actual time\n\t\t\tsched.forEachAtTime(0.2, (event) => {\n\t\t\t\texpect(event.time).to.equal(0.2);\n\t\t\t\tcount++;\n\t\t\t});\n\t\t\texpect(count).to.equal(2);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"can remove items during iterations\", () => {\n\t\t\tconst sched = new Timeline();\n\t\t\tfor (let i = 0; i < 1000; i++) {\n\t\t\t\tsched.add({ time: i });\n\t\t\t}\n\t\t\tsched.forEach((event) => {\n\t\t\t\tsched.remove(event);\n\t\t\t});\n\t\t\texpect(sched.length).to.equal(0);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"can add items during iteration\", () => {\n\t\t\tinterface AddedInterface {\n\t\t\t\ttime: number;\n\t\t\t\tadded?: boolean;\n\t\t\t}\n\t\t\tconst sched = new Timeline<AddedInterface>();\n\t\t\tfor (let i = 0; i < 1000; i++) {\n\t\t\t\tsched.add({ time: i });\n\t\t\t}\n\t\t\tlet added = false;\n\t\t\tsched.forEach((event) => {\n\t\t\t\tif (!added) {\n\t\t\t\t\tadded = true;\n\t\t\t\t\tsched.add({\n\t\t\t\t\t\tadded: true,\n\t\t\t\t\t\ttime: 10,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t\texpect(sched.length).to.equal(1001);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"can iterate between a time range\", () => {\n\t\t\tconst sched = new Timeline();\n\t\t\tsched.add({ time: 0.1 });\n\t\t\tsched.add({ time: 0.2 });\n\t\t\tsched.add({ time: 0.3 });\n\t\t\tsched.add({ time: 0.4 });\n\t\t\tlet count = 0;\n\t\t\tsched.forEachBetween(0.2, 0.4, (event) => {\n\t\t\t\tcount++;\n\t\t\t\texpect(event.time).to.be.within(0.2, 0.3);\n\t\t\t});\n\t\t\texpect(count).to.equal(2);\n\t\t\tcount = 0;\n\t\t\tsched.forEachBetween(0.21, 0.4, (event) => {\n\t\t\t\tcount++;\n\t\t\t\texpect(event.time).to.be.within(0.21, 0.3);\n\t\t\t});\n\t\t\texpect(count).to.equal(1);\n\t\t\tcount = 0;\n\t\t\tsched.forEachBetween(0.21, 0.39, (event) => {\n\t\t\t\tcount++;\n\t\t\t\texpect(event.time).to.be.within(0.21, 0.39);\n\t\t\t});\n\t\t\texpect(count).to.equal(1);\n\t\t\tcount = 0;\n\t\t\tsched.forEachBetween(0, 0.11, (event) => {\n\t\t\t\tcount++;\n\t\t\t\texpect(event.time).to.be.within(0, 0.11);\n\t\t\t});\n\t\t\texpect(count).to.equal(1);\n\t\t\tcount = 0;\n\t\t\tsched.forEachBetween(0, 0.09, (event) => {\n\t\t\t\tcount++;\n\t\t\t\texpect(event.time).to.be.within(0, 0.09);\n\t\t\t});\n\t\t\texpect(count).to.equal(0);\n\t\t\tcount = 0;\n\t\t\tsched.forEachBetween(0.41, 0.5, (event) => {\n\t\t\t\tcount++;\n\t\t\t\texpect(event.time).to.be.within(0.41, 0.5);\n\t\t\t});\n\t\t\texpect(count).to.equal(0);\n\t\t\tsched.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/core/util/Timeline.ts",
    "content": "import { Tone } from \"../Tone.js\";\nimport { Seconds } from \"../type/Units.js\";\nimport { assert } from \"./Debug.js\";\nimport { optionsFromArguments } from \"./Defaults.js\";\nimport { EQ, GT, GTE, LT } from \"./Math.js\";\n\ntype TimelineSearchParam = \"ticks\" | \"time\";\n\n/**\n * The options object for Timeline\n */\ninterface TimelineOptions {\n\tmemory: number;\n\tincreasing: boolean;\n}\n\n/**\n * An event must have a time number\n */\nexport interface TimelineEvent {\n\ttime: number;\n}\n\n/**\n * A Timeline class for scheduling and maintaining state\n * along a timeline. All events must have a \"time\" property.\n * Internally, events are stored in time order for fast\n * retrieval.\n * @internal\n */\nexport class Timeline<GenericEvent extends TimelineEvent> extends Tone {\n\treadonly name: string = \"Timeline\";\n\n\t/**\n\t * The memory of the timeline, i.e.\n\t * how many events in the past it will retain\n\t */\n\tmemory: number;\n\n\t/**\n\t * The array of scheduled timeline events\n\t */\n\tprotected _timeline: GenericEvent[] = [];\n\n\t/**\n\t * If the time value must always be greater than or equal to the last\n\t * element on the list.\n\t */\n\tincreasing: boolean;\n\n\t/**\n\t * @param memory The number of previous events that are retained.\n\t */\n\tconstructor(memory?: number);\n\tconstructor(options?: Partial<TimelineOptions>);\n\tconstructor() {\n\t\tsuper();\n\t\tconst options = optionsFromArguments(\n\t\t\tTimeline.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"memory\"]\n\t\t);\n\n\t\tthis.memory = options.memory;\n\t\tthis.increasing = options.increasing;\n\t}\n\n\tstatic getDefaults(): TimelineOptions {\n\t\treturn {\n\t\t\tmemory: Infinity,\n\t\t\tincreasing: false,\n\t\t};\n\t}\n\n\t/**\n\t * The number of items in the timeline.\n\t */\n\tget length(): number {\n\t\treturn this._timeline.length;\n\t}\n\n\t/**\n\t * Insert an event object onto the timeline. Events must have a \"time\" attribute.\n\t * @param event  The event object to insert into the timeline.\n\t */\n\tadd(event: GenericEvent): this {\n\t\t// the event needs to have a time attribute\n\t\tassert(\n\t\t\tReflect.has(event, \"time\"),\n\t\t\t\"Timeline: events must have a time attribute\"\n\t\t);\n\t\tevent.time = event.time.valueOf();\n\t\tif (this.increasing && this.length) {\n\t\t\tconst lastValue = this._timeline[this.length - 1] as GenericEvent;\n\t\t\tassert(\n\t\t\t\tGTE(event.time, lastValue.time),\n\t\t\t\t\"The time must be greater than or equal to the last scheduled time\"\n\t\t\t);\n\t\t\tthis._timeline.push(event);\n\t\t} else {\n\t\t\tconst index = this._search(event.time);\n\t\t\tthis._timeline.splice(index + 1, 0, event);\n\t\t}\n\t\t// if the length is more than the memory, remove the previous ones\n\t\tif (this.length > this.memory) {\n\t\t\tconst diff = this.length - this.memory;\n\t\t\tthis._timeline.splice(0, diff);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove an event from the timeline.\n\t * @param  {Object}  event  The event object to remove from the list.\n\t * @returns {Timeline} this\n\t */\n\tremove(event: GenericEvent): this {\n\t\tconst index = this._timeline.indexOf(event);\n\t\tif (index !== -1) {\n\t\t\tthis._timeline.splice(index, 1);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Get the nearest event whose time is less than or equal to the given time.\n\t * @param  time  The time to query.\n\t */\n\tget(\n\t\ttime: number,\n\t\tparam: TimelineSearchParam = \"time\"\n\t): GenericEvent | null {\n\t\tconst index = this._search(time, param);\n\t\tif (index !== -1) {\n\t\t\treturn this._timeline[index];\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Return the first event in the timeline without removing it\n\t * @returns {Object} The first event object\n\t * @deprecated\n\t */\n\tpeek(): GenericEvent | undefined {\n\t\treturn this._timeline[0];\n\t}\n\n\t/**\n\t * Return the first event in the timeline and remove it\n\t * @deprecated\n\t */\n\tshift(): GenericEvent | undefined {\n\t\treturn this._timeline.shift();\n\t}\n\n\t/**\n\t * Get the event which is scheduled after the given time.\n\t * @param  time  The time to query.\n\t */\n\tgetAfter(\n\t\ttime: number,\n\t\tparam: TimelineSearchParam = \"time\"\n\t): GenericEvent | null {\n\t\tconst index = this._search(time, param);\n\t\tif (index + 1 < this._timeline.length) {\n\t\t\treturn this._timeline[index + 1];\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Get the event before the event at the given time.\n\t * @param  time  The time to query.\n\t */\n\tgetBefore(time: number): GenericEvent | null {\n\t\tconst len = this._timeline.length;\n\t\t// if it's after the last item, return the last item\n\t\tif (len > 0 && this._timeline[len - 1].time < time) {\n\t\t\treturn this._timeline[len - 1];\n\t\t}\n\t\tconst index = this._search(time);\n\t\tif (index - 1 >= 0) {\n\t\t\treturn this._timeline[index - 1];\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Cancel events at and after the given time\n\t * @param  after  The time to query.\n\t */\n\tcancel(after: number): this {\n\t\tif (this._timeline.length > 1) {\n\t\t\tlet index = this._search(after);\n\t\t\tif (index >= 0) {\n\t\t\t\tif (EQ(this._timeline[index].time, after)) {\n\t\t\t\t\t// get the first item with that time\n\t\t\t\t\tfor (let i = index; i >= 0; i--) {\n\t\t\t\t\t\tif (EQ(this._timeline[i].time, after)) {\n\t\t\t\t\t\t\tindex = i;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthis._timeline = this._timeline.slice(0, index);\n\t\t\t\t} else {\n\t\t\t\t\tthis._timeline = this._timeline.slice(0, index + 1);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis._timeline = [];\n\t\t\t}\n\t\t} else if (this._timeline.length === 1) {\n\t\t\t// the first item's time\n\t\t\tif (GTE(this._timeline[0].time, after)) {\n\t\t\t\tthis._timeline = [];\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Cancel events before or equal to the given time.\n\t * @param  time  The time to cancel before.\n\t */\n\tcancelBefore(time: number): this {\n\t\tconst index = this._search(time);\n\t\tif (index >= 0) {\n\t\t\tthis._timeline = this._timeline.slice(index + 1);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Returns the previous event if there is one. null otherwise\n\t * @param  event The event to find the previous one of\n\t * @return The event right before the given event\n\t */\n\tpreviousEvent(event: GenericEvent): GenericEvent | null {\n\t\tconst index = this._timeline.indexOf(event);\n\t\tif (index > 0) {\n\t\t\treturn this._timeline[index - 1];\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Does a binary search on the timeline array and returns the\n\t * nearest event index whose time is after or equal to the given time.\n\t * If a time is searched before the first index in the timeline, -1 is returned.\n\t * If the time is after the end, the index of the last item is returned.\n\t */\n\tprotected _search(\n\t\ttime: number,\n\t\tparam: TimelineSearchParam = \"time\"\n\t): number {\n\t\tif (this._timeline.length === 0) {\n\t\t\treturn -1;\n\t\t}\n\t\tlet beginning = 0;\n\t\tconst len = this._timeline.length;\n\t\tlet end = len;\n\t\tif (len > 0 && this._timeline[len - 1][param] <= time) {\n\t\t\treturn len - 1;\n\t\t}\n\t\twhile (beginning < end) {\n\t\t\t// calculate the midpoint for roughly equal partition\n\t\t\tlet midPoint = Math.floor(beginning + (end - beginning) / 2);\n\t\t\tconst event = this._timeline[midPoint];\n\t\t\tconst nextEvent = this._timeline[midPoint + 1];\n\t\t\tif (EQ(event[param], time)) {\n\t\t\t\t// choose the last one that has the same time\n\t\t\t\tfor (let i = midPoint; i < this._timeline.length; i++) {\n\t\t\t\t\tconst testEvent = this._timeline[i];\n\t\t\t\t\tif (EQ(testEvent[param], time)) {\n\t\t\t\t\t\tmidPoint = i;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn midPoint;\n\t\t\t} else if (LT(event[param], time) && GT(nextEvent[param], time)) {\n\t\t\t\treturn midPoint;\n\t\t\t} else if (GT(event[param], time)) {\n\t\t\t\t// search lower\n\t\t\t\tend = midPoint;\n\t\t\t} else {\n\t\t\t\t// search upper\n\t\t\t\tbeginning = midPoint + 1;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t}\n\n\t/**\n\t * Internal iterator. Applies extra safety checks for\n\t * removing items from the array.\n\t */\n\tprivate _iterate(\n\t\tcallback: (event: GenericEvent) => void,\n\t\tlowerBound = 0,\n\t\tupperBound = this._timeline.length - 1\n\t): void {\n\t\tthis._timeline.slice(lowerBound, upperBound + 1).forEach(callback);\n\t}\n\n\t/**\n\t * Iterate over everything in the array\n\t * @param  callback The callback to invoke with every item\n\t */\n\tforEach(callback: (event: GenericEvent) => void): this {\n\t\tthis._iterate(callback);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Iterate over everything in the array at or before the given time.\n\t * @param  time The time to check if items are before\n\t * @param  callback The callback to invoke with every item\n\t */\n\tforEachBefore(\n\t\ttime: Seconds,\n\t\tcallback: (event: GenericEvent) => void\n\t): this {\n\t\t// iterate over the items in reverse so that removing an item doesn't break things\n\t\tconst upperBound = this._search(time);\n\t\tif (upperBound !== -1) {\n\t\t\tthis._iterate(callback, 0, upperBound);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Iterate over everything in the array after the given time.\n\t * @param  time The time to check if items are before\n\t * @param  callback The callback to invoke with every item\n\t */\n\tforEachAfter(time: Seconds, callback: (event: GenericEvent) => void): this {\n\t\t// iterate over the items in reverse so that removing an item doesn't break things\n\t\tconst lowerBound = this._search(time);\n\t\tthis._iterate(callback, lowerBound + 1);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Iterate over everything in the array between the startTime and endTime.\n\t * The time range is inclusive of the startTime, but exclusive of the endTime.\n\t * range = [startTime, endTime).\n\t * @param  startTime The time to check if items are before\n\t * @param  endTime The end of the test interval.\n\t * @param  callback The callback to invoke with every item\n\t */\n\tforEachBetween(\n\t\tstartTime: number,\n\t\tendTime: number,\n\t\tcallback: (event: GenericEvent) => void\n\t): this {\n\t\tlet lowerBound = this._search(startTime);\n\t\tlet upperBound = this._search(endTime);\n\t\tif (lowerBound !== -1 && upperBound !== -1) {\n\t\t\tif (this._timeline[lowerBound].time !== startTime) {\n\t\t\t\tlowerBound += 1;\n\t\t\t}\n\t\t\t// exclusive of the end time\n\t\t\tif (this._timeline[upperBound].time === endTime) {\n\t\t\t\tupperBound -= 1;\n\t\t\t}\n\t\t\tthis._iterate(callback, lowerBound, upperBound);\n\t\t} else if (lowerBound === -1) {\n\t\t\tthis._iterate(callback, 0, upperBound);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Iterate over everything in the array at or after the given time. Similar to\n\t * forEachAfter, but includes the item(s) at the given time.\n\t * @param  time The time to check if items are before\n\t * @param  callback The callback to invoke with every item\n\t */\n\tforEachFrom(time: number, callback: (event: GenericEvent) => void): this {\n\t\t// iterate over the items in reverse so that removing an item doesn't break things\n\t\tlet lowerBound = this._search(time);\n\t\t// work backwards until the event time is less than time\n\t\twhile (lowerBound >= 0 && this._timeline[lowerBound].time >= time) {\n\t\t\tlowerBound--;\n\t\t}\n\t\tthis._iterate(callback, lowerBound + 1);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Iterate over everything in the array at the given time\n\t * @param  time The time to check if items are before\n\t * @param  callback The callback to invoke with every item\n\t */\n\tforEachAtTime(time: number, callback: (event: GenericEvent) => void): this {\n\t\t// iterate over the items in reverse so that removing an item doesn't break things\n\t\tconst upperBound = this._search(time);\n\t\tif (upperBound !== -1 && EQ(this._timeline[upperBound].time, time)) {\n\t\t\tlet lowerBound = upperBound;\n\t\t\tfor (let i = upperBound; i >= 0; i--) {\n\t\t\t\tif (EQ(this._timeline[i].time, time)) {\n\t\t\t\t\tlowerBound = i;\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._iterate(\n\t\t\t\t(event) => {\n\t\t\t\t\tcallback(event);\n\t\t\t\t},\n\t\t\t\tlowerBound,\n\t\t\t\tupperBound\n\t\t\t);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clean up.\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._timeline = [];\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/core/util/TimelineValue.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { TimelineValue } from \"./TimelineValue.js\";\n\ndescribe(\"TimelineValue\", () => {\n\tit(\"can be created and disposed\", () => {\n\t\tconst sched = new TimelineValue(0);\n\t\tsched.dispose();\n\t});\n\n\tit(\"can add events to the timeline\", () => {\n\t\tconst sched = new TimelineValue(10);\n\t\tsched.set(11, 1);\n\t\tsched.set(1, 12);\n\t\tsched.set(3, 4);\n\t\texpect(sched.get(0)).to.equal(10);\n\t\texpect(sched.get(1)).to.equal(11);\n\t\texpect(sched.get(2)).to.equal(11);\n\t\texpect(sched.get(4)).to.equal(3);\n\t\texpect(sched.get(12)).to.equal(1);\n\t\tsched.dispose();\n\t});\n\n\tit(\"returns the initial value if there is nothing scheduled\", () => {\n\t\tconst sched = new TimelineValue(10);\n\t\texpect(sched.get(0)).to.equal(10);\n\t\tsched.dispose();\n\t});\n});\n"
  },
  {
    "path": "Tone/core/util/TimelineValue.ts",
    "content": "import { Tone } from \"../Tone.js\";\nimport { Seconds } from \"../type/Units.js\";\nimport { Timeline, TimelineEvent } from \"./Timeline.js\";\n\ninterface TimelineValueEvent<T> extends TimelineEvent {\n\tvalue: T;\n}\n\n/**\n * Represents a single value which is gettable and settable in a timed way\n */\nexport class TimelineValue<Type> extends Tone {\n\treadonly name: string = \"TimelineValue\";\n\n\t/**\n\t * The timeline which stores the values\n\t */\n\tprivate _timeline: Timeline<TimelineValueEvent<Type>> = new Timeline({\n\t\tmemory: 10,\n\t});\n\n\t/**\n\t * Hold the value to return if there is no scheduled values\n\t */\n\tprivate _initialValue: Type;\n\n\t/**\n\t * @param initialValue The value to return if there is no scheduled values\n\t */\n\tconstructor(initialValue: Type) {\n\t\tsuper();\n\t\tthis._initialValue = initialValue;\n\t}\n\n\t/**\n\t * Set the value at the given time\n\t */\n\tset(value: Type, time: Seconds): this {\n\t\tthis._timeline.add({\n\t\t\tvalue,\n\t\t\ttime,\n\t\t});\n\t\treturn this;\n\t}\n\n\t/**\n\t * Get the value at the given time\n\t */\n\tget(time: Seconds): Type {\n\t\tconst event = this._timeline.get(time);\n\t\tif (event) {\n\t\t\treturn event.value;\n\t\t} else {\n\t\t\treturn this._initialValue;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Tone/core/util/TypeCheck.ts",
    "content": "import { Note } from \"../type/Units.js\";\n\n/**\n * Test if the arg is undefined\n */\nexport function isUndef(arg: unknown): arg is undefined {\n\treturn arg === undefined;\n}\n\n/**\n * Test if the arg is not undefined\n */\nexport function isDefined<T>(arg: T | undefined): arg is T {\n\treturn arg !== undefined;\n}\n\n/**\n * Test if the arg is a function\n */\nexport function isFunction(arg: unknown): arg is (a: any) => any {\n\treturn typeof arg === \"function\";\n}\n\n/**\n * Test if the argument is a number.\n */\nexport function isNumber(arg: unknown): arg is number {\n\treturn typeof arg === \"number\";\n}\n\n/**\n * Test if the given argument is an object literal (i.e. `{}`);\n */\nexport function isObject(arg: unknown): arg is object {\n\treturn (\n\t\tObject.prototype.toString.call(arg) === \"[object Object]\" &&\n\t\t(arg as object).constructor === Object\n\t);\n}\n\n/**\n * Test if the argument is a boolean.\n */\nexport function isBoolean(arg: unknown): arg is boolean {\n\treturn typeof arg === \"boolean\";\n}\n\n/**\n * Test if the argument is an Array\n */\nexport function isArray(arg: unknown): arg is any[] {\n\treturn Array.isArray(arg);\n}\n\n/**\n * Test if the argument is a string.\n */\nexport function isString(arg: unknown): arg is string {\n\treturn typeof arg === \"string\";\n}\n\n/**\n * Test if the argument is in the form of a note in scientific pitch notation.\n * e.g. \"C4\"\n */\nexport function isNote(arg: unknown): arg is Note {\n\treturn isString(arg) && /^([a-g]{1}(?:b|#|x|bb)?)(-?[0-9]+)/i.test(arg);\n}\n"
  },
  {
    "path": "Tone/core/util/global.d.ts",
    "content": "/**\n * Replace the default lib.dom.d.ts interface to reflect the fact\n * that the AudioParamMap extends Map\n */\ninterface AudioParamMap extends Map<string, AudioParam> {\n\tforEach(\n\t\tcallbackfn: (\n\t\t\tvalue: AudioParam,\n\t\t\tkey: string,\n\t\t\tparent: AudioParamMap\n\t\t) => void,\n\t\tthisArg?: any\n\t): void;\n}\n"
  },
  {
    "path": "Tone/core/worklet/DelayLine.worklet.ts",
    "content": "import { addToWorklet } from \"./WorkletGlobalScope.js\";\n\nconst delayLine = /* javascript */ `\n\t/**\n\t * A multichannel buffer for use within an AudioWorkletProcessor as a delay line\n\t */\n\tclass DelayLine {\n\n\t\tconstructor(size, channels) {\n\t\t\tthis.buffer = [];\n\t\t\tthis.writeHead = []\n\t\t\tthis.size = size;\n\n\t\t\t// create the empty channels\n\t\t\tfor (let i = 0; i < channels; i++) {\n\t\t\t\tthis.buffer[i] = new Float32Array(this.size);\n\t\t\t\tthis.writeHead[i] = 0;\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Push a value onto the end\n\t\t * @param channel number\n\t\t * @param value number\n\t\t */\n\t\tpush(channel, value) {\n\t\t\tthis.writeHead[channel] += 1;\n\t\t\tif (this.writeHead[channel] >= this.size) {\n\t\t\t\tthis.writeHead[channel] = 0;\n\t\t\t}\n\t\t\tthis.buffer[channel][this.writeHead[channel]] = value;\n\t\t}\n\n\t\t/**\n\t\t * Get the recorded value of the channel given the delay\n\t\t * @param channel number\n\t\t * @param delay number delay samples\n\t\t */\n\t\tget(channel, delay) {\n\t\t\tlet readHead = this.writeHead[channel] - Math.floor(delay);\n\t\t\tif (readHead < 0) {\n\t\t\t\treadHead += this.size;\n\t\t\t}\n\t\t\treturn this.buffer[channel][readHead];\n\t\t}\n\n\t\t/**\n\t\t * Get the reverse recorded value of the channel given the delay\n\t\t * @param channel number\n\t\t * @param delay number delay samples\n\t\t */\n\t\tgetReverse(channel, delay) {\n\t\t\tif (!this.size || !delay) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tconst readHead = delay * 2 - this.writeHead[channel] - 1;\n\n\t\t\t// Gain function to reduce clicking when read is too close to write\n\t\t\tlet readWriteDifference = this.writeHead[channel] - readHead;\n\t\t\tif (readWriteDifference < 0) {\n\t\t\t\treadWriteDifference += this.size\n\t\t\t}\n\t\t\tconst delayPct = readWriteDifference / this.size;\n\t\t\tconst gainFunction = 4 * delayPct * (1 - delayPct);\n\n\t\t\treturn this.buffer[channel][readHead] * gainFunction;\n\t\t}\n\t}\n`;\n\naddToWorklet(delayLine);\n"
  },
  {
    "path": "Tone/core/worklet/SingleIOProcessor.worklet.ts",
    "content": "import \"./ToneAudioWorkletProcessor.worklet.js\";\n\nimport { addToWorklet } from \"./WorkletGlobalScope.js\";\n\nexport const singleIOProcess = /* javascript */ `\n\t/**\n\t * Abstract class for a single input/output processor. \n\t * has a 'generate' function which processes one sample at a time\n\t */\n\tclass SingleIOProcessor extends ToneAudioWorkletProcessor {\n\n\t\tconstructor(options) {\n\t\t\tsuper(Object.assign(options, {\n\t\t\t\tnumberOfInputs: 1,\n\t\t\t\tnumberOfOutputs: 1\n\t\t\t}));\n\t\t\t/**\n\t\t\t * Holds the name of the parameter and a single value of that\n\t\t\t * parameter at the current sample\n\t\t\t * @type { [name: string]: number }\n\t\t\t */\n\t\t\tthis.params = {}\n\t\t}\n\n\t\t/**\n\t\t * Generate an output sample from the input sample and parameters\n\t\t * @abstract\n\t\t * @param input number\n\t\t * @param channel number\n\t\t * @param parameters { [name: string]: number }\n\t\t * @returns number\n\t\t */\n\t\tgenerate(){}\n\n\t\t/**\n\t\t * Update the private params object with the \n\t\t * values of the parameters at the given index\n\t\t * @param parameters { [name: string]: Float32Array },\n\t\t * @param index number\n\t\t */\n\t\tupdateParams(parameters, index) {\n\t\t\tfor (const paramName in parameters) {\n\t\t\t\tconst param = parameters[paramName];\n\t\t\t\tif (param.length > 1) {\n\t\t\t\t\tthis.params[paramName] = parameters[paramName][index];\n\t\t\t\t} else {\n\t\t\t\t\tthis.params[paramName] = parameters[paramName][0];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Process a single frame of the audio\n\t\t * @param inputs Float32Array[][]\n\t\t * @param outputs Float32Array[][]\n\t\t */\n\t\tprocess(inputs, outputs, parameters) {\n\t\t\tconst input = inputs[0];\n\t\t\tconst output = outputs[0];\n\t\t\t// get the parameter values\n\t\t\tconst channelCount = Math.max(input && input.length || 0, output.length);\n\t\t\tfor (let sample = 0; sample < this.blockSize; sample++) {\n\t\t\t\tthis.updateParams(parameters, sample);\n\t\t\t\tfor (let channel = 0; channel < channelCount; channel++) {\n\t\t\t\t\tconst inputSample = input && input.length ? input[channel][sample] : 0;\n\t\t\t\t\toutput[channel][sample] = this.generate(inputSample, channel, this.params);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn !this.disposed;\n\t\t}\n\t};\n`;\n\naddToWorklet(singleIOProcess);\n"
  },
  {
    "path": "Tone/core/worklet/ToneAudioWorklet.ts",
    "content": "import {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../context/ToneAudioNode.js\";\nimport { noOp } from \"../util/Interface.js\";\nimport { getWorkletGlobalScope } from \"./WorkletGlobalScope.js\";\n\nexport interface ToneAudioWorkletOptions extends ToneAudioNodeOptions {\n\tworkletOptions?: Partial<AudioWorkletNodeOptions>\n};\nexport abstract class ToneAudioWorklet<\n\tOptions extends ToneAudioWorkletOptions,\n> extends ToneAudioNode<Options> {\n\treadonly name: string = \"ToneAudioWorklet\";\n\n\t/**\n\t * The processing node\n\t */\n\tprotected _worklet!: AudioWorkletNode;\n\n\t/**\n\t * A dummy gain node to create a dummy audio param from\n\t */\n\tprivate _dummyGain: GainNode;\n\n\t/**\n\t * A dummy audio param to use when creating Params\n\t */\n\tprotected _dummyParam: AudioParam;\n\n\t/**\n\t * The constructor options for the node\n\t */\n\tprotected workletOptions: Partial<AudioWorkletNodeOptions> = {};\n\n\t/**\n\t * Get the name of the audio worklet\n\t */\n\tprotected abstract _audioWorkletName(): string;\n\n\t/**\n\t * Invoked when the module is loaded and the node is created\n\t */\n\tprotected abstract onReady(node: AudioWorkletNode): void;\n\n\t/**\n\t * Callback which is invoked when there is an error in the processing\n\t */\n\tonprocessorerror: (e: string) => void = noOp;\n\n\tconstructor(options: Options) {\n\t\tsuper(options);\n\n\t\tconst blobUrl = URL.createObjectURL(\n\t\t\tnew Blob([getWorkletGlobalScope()], { type: \"text/javascript\" })\n\t\t);\n\t\tconst name = this._audioWorkletName();\n\n\t\tthis._dummyGain = this.context.createGain();\n\t\tthis._dummyParam = this._dummyGain.gain;\n\n\t\t// Register the processor\n\t\tlet workletPromise = ToneAudioWorklet._workletPromises.get(\n\t\t\tthis.context\n\t\t);\n\n\t\tif (options.workletOptions) {\n\t\t\tthis.workletOptions = Object.assign({},\n\t\t\t\tthis.workletOptions,\n\t\t\t\toptions.workletOptions\n\t\t\t);\n\t\t}\n\n\t\tif (workletPromise === undefined) {\n\t\t\tworkletPromise = this.context.addAudioWorkletModule(blobUrl);\n\n\t\t\tToneAudioWorklet._workletPromises.set(this.context, workletPromise);\n\t\t}\n\n\t\tworkletPromise.then(() => {\n\t\t\t// create the worklet when it's read\n\t\t\tif (!this.disposed) {\n\t\t\t\tthis._worklet = this.context.createAudioWorkletNode(\n\t\t\t\t\tname,\n\t\t\t\t\tthis.workletOptions\n\t\t\t\t);\n\t\t\t\tthis._worklet.onprocessorerror =\n\t\t\t\t\tthis.onprocessorerror.bind(this);\n\t\t\t\tthis.onReady(this._worklet);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate static _workletPromises = new WeakMap<any, Promise<void>>();\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._dummyGain.disconnect();\n\t\tif (this._worklet) {\n\t\t\tthis._worklet.port.postMessage(\"dispose\");\n\t\t\tthis._worklet.disconnect();\n\t\t}\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/core/worklet/ToneAudioWorkletProcessor.worklet.ts",
    "content": "import { addToWorklet } from \"./WorkletGlobalScope.js\";\n\nconst toneAudioWorkletProcessor = /* javascript */ `\n\t/**\n\t * The base AudioWorkletProcessor for use in Tone.js. Works with the {@link ToneAudioWorklet}. \n\t */\n\tclass ToneAudioWorkletProcessor extends AudioWorkletProcessor {\n\n\t\tconstructor(options) {\n\t\t\t\n\t\t\tsuper(options);\n\t\t\t/**\n\t\t\t * If the processor was disposed or not. Keep alive until its disposed.\n\t\t\t */\n\t\t\tthis.disposed = false;\n\t\t   \t/** \n\t\t\t * The number of samples in the processing block\n\t\t\t */\n\t\t\tthis.blockSize = 128;\n\t\t\t/**\n\t\t\t * the sample rate\n\t\t\t */\n\t\t\tthis.sampleRate = sampleRate;\n\n\t\t\tthis.port.onmessage = (event) => {\n\t\t\t\t// when it receives a dispose \n\t\t\t\tif (event.data === \"dispose\") {\n\t\t\t\t\tthis.disposed = true;\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t}\n`;\n\naddToWorklet(toneAudioWorkletProcessor);\n"
  },
  {
    "path": "Tone/core/worklet/WorkletGlobalScope.ts",
    "content": "/**\n * All of the classes or functions which are loaded into the AudioWorkletGlobalScope\n */\nconst workletContext: Set<string> = new Set();\n\n/**\n * Add a class to the AudioWorkletGlobalScope\n */\nexport function addToWorklet(classOrFunction: string) {\n\tworkletContext.add(classOrFunction);\n}\n\n/**\n * Register a processor in the AudioWorkletGlobalScope with the given name\n */\nexport function registerProcessor(name: string, classDesc: string) {\n\tconst processor = /* javascript */ `registerProcessor(\"${name}\", ${classDesc})`;\n\tworkletContext.add(processor);\n}\n\n/**\n * Get all of the modules which have been registered to the AudioWorkletGlobalScope\n */\nexport function getWorkletGlobalScope(): string {\n\treturn Array.from(workletContext).join(\"\\n\");\n}\n"
  },
  {
    "path": "Tone/effect/AutoFilter.test.ts",
    "content": "import { expect } from \"chai\";\nimport { Note } from \"tonal\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { EffectTests } from \"../../test/helper/EffectTests.js\";\nimport { Offline } from \"../../test/helper/Offline.js\";\nimport { Noise } from \"../source/index.js\";\nimport { AutoFilter } from \"./AutoFilter.js\";\n\ndescribe(\"AutoFilter\", () => {\n\tBasicTests(AutoFilter);\n\tEffectTests(AutoFilter);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst autoFilter = new AutoFilter({\n\t\t\t\t\tbaseFrequency: 200,\n\t\t\t\t\toctaves: 4,\n\t\t\t\t\tfrequency: 4,\n\t\t\t\t\ttype: \"sine\",\n\t\t\t\t}).toDestination();\n\t\t\t\tnew Noise().connect(autoFilter).start();\n\t\t\t\tautoFilter.start(0.2);\n\t\t\t},\n\t\t\t\"autoFilter.wav\",\n\t\t\t0.1\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst autoFilter = new AutoFilter({\n\t\t\t\tbaseFrequency: 2000,\n\t\t\t\toctaves: 2,\n\t\t\t\ttype: \"sawtooth\",\n\t\t\t});\n\t\t\texpect(autoFilter.baseFrequency).to.be.closeTo(2000, 0.1);\n\t\t\texpect(autoFilter.octaves).to.equal(2);\n\t\t\texpect(autoFilter.type).to.equal(\"sawtooth\");\n\t\t\tautoFilter.dispose();\n\t\t});\n\n\t\tit(\"can be started and stopped\", () => {\n\t\t\tconst autoFilter = new AutoFilter();\n\t\t\tautoFilter.start().stop(\"+0.2\");\n\t\t\tautoFilter.dispose();\n\t\t});\n\n\t\tit(\"can get/set the options\", () => {\n\t\t\tconst autoFilter = new AutoFilter();\n\t\t\tautoFilter.set({\n\t\t\t\tbaseFrequency: 1200,\n\t\t\t\tfrequency: 2.4,\n\t\t\t\ttype: \"triangle\",\n\t\t\t});\n\t\t\texpect(autoFilter.get().baseFrequency).to.be.closeTo(1200, 0.01);\n\t\t\texpect(autoFilter.get().frequency).to.be.closeTo(2.4, 0.01);\n\t\t\texpect(autoFilter.get().type).to.equal(\"triangle\");\n\t\t\tautoFilter.dispose();\n\t\t});\n\n\t\tit(\"can set the frequency and depth\", () => {\n\t\t\tconst autoFilter = new AutoFilter();\n\t\t\tautoFilter.depth.value = 0.4;\n\t\t\tautoFilter.frequency.value = 0.4;\n\t\t\texpect(autoFilter.depth.value).to.be.closeTo(0.4, 0.01);\n\t\t\texpect(autoFilter.frequency.value).to.be.closeTo(0.4, 0.01);\n\t\t\tautoFilter.dispose();\n\t\t});\n\n\t\tit(\"can set the filter options\", () => {\n\t\t\tconst autoFilter = new AutoFilter();\n\t\t\tautoFilter.filter.Q.value = 2;\n\t\t\texpect(autoFilter.filter.Q.value).to.be.closeTo(2, 0.01);\n\t\t\tautoFilter.dispose();\n\t\t});\n\n\t\tit(\"accepts baseFrequency and octaves as frequency values\", () => {\n\t\t\tconst autoFilter = new AutoFilter(\"2n\", \"C2\", 4);\n\t\t\texpect(autoFilter.baseFrequency).to.be.closeTo(\n\t\t\t\tNote.freq(\"C2\") as number,\n\t\t\t\t0.01\n\t\t\t);\n\t\t\texpect(autoFilter.octaves).to.equal(4);\n\t\t\tautoFilter.dispose();\n\t\t});\n\n\t\tit(\"can sync the frequency to the transport\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst autoFilter = new AutoFilter(2);\n\t\t\t\tautoFilter.sync();\n\t\t\t\tautoFilter.frequency.toDestination();\n\t\t\t\ttransport.bpm.setValueAtTime(transport.bpm.value * 2, 0.05);\n\t\t\t\t// transport.start(0)\n\t\t\t}, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(2, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.05)).to.be.closeTo(4, 0.1);\n\t\t});\n\n\t\tit(\"can unsync the frequency to the transport\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst autoFilter = new AutoFilter(2);\n\t\t\t\tautoFilter.sync();\n\t\t\t\tautoFilter.frequency.toDestination();\n\t\t\t\ttransport.bpm.setValueAtTime(transport.bpm.value * 2, 0.05);\n\t\t\t\tautoFilter.unsync();\n\t\t\t}, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(2, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.05)).to.be.closeTo(2, 0.1);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/effect/AutoFilter.ts",
    "content": "import { Filter, FilterOptions } from \"../component/filter/Filter.js\";\nimport { Frequency, Positive } from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { SourceOptions } from \"../source/Source.js\";\nimport { LFOEffect, LFOEffectOptions } from \"./LFOEffect.js\";\n\nexport interface AutoFilterOptions extends LFOEffectOptions {\n\tbaseFrequency: Frequency;\n\toctaves: Positive;\n\tfilter: Omit<\n\t\tFilterOptions,\n\t\tkeyof SourceOptions | \"frequency\" | \"detune\" | \"gain\"\n\t>;\n}\n\n/**\n * AutoFilter is a Tone.Filter with a Tone.LFO connected to the filter cutoff frequency.\n * Setting the LFO rate and depth allows for control over the filter modulation rate\n * and depth.\n *\n * @example\n * // create an autofilter and start its LFO\n * const autoFilter = new Tone.AutoFilter(\"4n\").toDestination().start();\n * // route an oscillator through the filter and start it\n * const oscillator = new Tone.Oscillator().connect(autoFilter).start();\n * @category Effect\n */\nexport class AutoFilter extends LFOEffect<AutoFilterOptions> {\n\treadonly name: string = \"AutoFilter\";\n\n\t/**\n\t * The filter node\n\t */\n\treadonly filter: Filter;\n\n\t/**\n\t * The octaves placeholder\n\t */\n\tprivate _octaves!: Positive;\n\n\t/**\n\t * @param frequency The rate of the LFO.\n\t * @param baseFrequency The lower value of the LFOs oscillation\n\t * @param octaves The number of octaves above the baseFrequency\n\t */\n\tconstructor(\n\t\tfrequency?: Frequency,\n\t\tbaseFrequency?: Frequency,\n\t\toctaves?: Positive\n\t);\n\tconstructor(options?: Partial<AutoFilterOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tAutoFilter.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"frequency\", \"baseFrequency\", \"octaves\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.filter = new Filter(\n\t\t\tObject.assign(options.filter, {\n\t\t\t\tcontext: this.context,\n\t\t\t})\n\t\t);\n\n\t\t// connections\n\t\tthis.connectEffect(this.filter);\n\t\tthis._lfo.connect(this.filter.frequency);\n\t\tthis.octaves = options.octaves;\n\t\tthis.baseFrequency = options.baseFrequency;\n\t}\n\n\tstatic getDefaults(): AutoFilterOptions {\n\t\treturn Object.assign(LFOEffect.getDefaults(), {\n\t\t\tbaseFrequency: 200,\n\t\t\toctaves: 2.6,\n\t\t\tfilter: {\n\t\t\t\ttype: \"lowpass\" as const,\n\t\t\t\trolloff: -12 as -12,\n\t\t\t\tQ: 1,\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * The minimum value of the filter's cutoff frequency.\n\t */\n\tget baseFrequency(): Frequency {\n\t\treturn this._lfo.min;\n\t}\n\tset baseFrequency(freq) {\n\t\tthis._lfo.min = this.toFrequency(freq);\n\t\t// and set the max\n\t\tthis.octaves = this._octaves;\n\t}\n\n\t/**\n\t * The maximum value of the filter's cutoff frequency.\n\t */\n\tget octaves(): Positive {\n\t\treturn this._octaves;\n\t}\n\tset octaves(oct) {\n\t\tthis._octaves = oct;\n\t\tthis._lfo.max = this._lfo.min * Math.pow(2, oct);\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.filter.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/AutoPanner.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { EffectTests } from \"../../test/helper/EffectTests.js\";\nimport { Offline } from \"../../test/helper/Offline.js\";\nimport { Oscillator } from \"../source/oscillator/Oscillator.js\";\nimport { AutoPanner } from \"./AutoPanner.js\";\n\ndescribe(\"AutoPanner\", () => {\n\tBasicTests(AutoPanner);\n\tEffectTests(AutoPanner);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst autoFilter = new AutoPanner({\n\t\t\t\t\ttype: \"sine\",\n\t\t\t\t\tfrequency: 3,\n\t\t\t\t}).toDestination();\n\t\t\t\tnew Oscillator().connect(autoFilter).start();\n\t\t\t\tautoFilter.start(0.2);\n\t\t\t},\n\t\t\t\"autoPanner.wav\",\n\t\t\t0.01\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst autoPanner = new AutoPanner({\n\t\t\t\ttype: \"sawtooth\",\n\t\t\t\tdepth: 0.2,\n\t\t\t});\n\t\t\texpect(autoPanner.depth.value).to.be.closeTo(0.2, 0.01);\n\t\t\texpect(autoPanner.type).to.equal(\"sawtooth\");\n\t\t\tautoPanner.dispose();\n\t\t});\n\n\t\tit(\"can be started and stopped\", () => {\n\t\t\tconst autoPanner = new AutoPanner();\n\t\t\tautoPanner.start().stop(\"+0.2\");\n\t\t\tautoPanner.dispose();\n\t\t});\n\n\t\tit(\"can get/set the options\", () => {\n\t\t\tconst autoPanner = new AutoPanner();\n\t\t\tautoPanner.set({\n\t\t\t\tfrequency: 2.4,\n\t\t\t\ttype: \"triangle\",\n\t\t\t});\n\t\t\texpect(autoPanner.get().frequency).to.be.closeTo(2.4, 0.01);\n\t\t\texpect(autoPanner.get().type).to.equal(\"triangle\");\n\t\t\tautoPanner.dispose();\n\t\t});\n\n\t\tit(\"can set the frequency and depth\", () => {\n\t\t\tconst autoPanner = new AutoPanner();\n\t\t\tautoPanner.depth.value = 0.4;\n\t\t\tautoPanner.frequency.value = 0.4;\n\t\t\texpect(autoPanner.depth.value).to.be.closeTo(0.4, 0.01);\n\t\t\texpect(autoPanner.frequency.value).to.be.closeTo(0.4, 0.01);\n\t\t\tautoPanner.dispose();\n\t\t});\n\n\t\tit(\"can sync the frequency to the transport\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst panner = new AutoPanner(2);\n\t\t\t\tpanner.sync();\n\t\t\t\tpanner.frequency.toDestination();\n\t\t\t\ttransport.bpm.setValueAtTime(transport.bpm.value * 2, 0.05);\n\t\t\t\t// transport.start(0)\n\t\t\t}, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(2, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.05)).to.be.closeTo(4, 0.1);\n\t\t});\n\n\t\tit(\"can unsync the frequency to the transport\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst panner = new AutoPanner(2);\n\t\t\t\tpanner.sync();\n\t\t\t\tpanner.frequency.toDestination();\n\t\t\t\ttransport.bpm.setValueAtTime(transport.bpm.value * 2, 0.05);\n\t\t\t\tpanner.unsync();\n\t\t\t\t// transport.start(0)\n\t\t\t}, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(2, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.05)).to.be.closeTo(2, 0.1);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/effect/AutoPanner.ts",
    "content": "import { Panner } from \"../component/channel/Panner.js\";\nimport { Frequency } from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { LFOEffect, LFOEffectOptions } from \"./LFOEffect.js\";\n\nexport interface AutoPannerOptions extends LFOEffectOptions {\n\tchannelCount: number;\n}\n\n/**\n * AutoPanner is a {@link Panner} with an {@link LFO} connected to the pan amount.\n * [Related Reading](https://www.ableton.com/en/blog/autopan-chopper-effect-and-more-liveschool/).\n *\n * @example\n * // create an autopanner and start it\n * const autoPanner = new Tone.AutoPanner(\"4n\").toDestination().start();\n * // route an oscillator through the panner and start it\n * const oscillator = new Tone.Oscillator().connect(autoPanner).start();\n * @category Effect\n */\nexport class AutoPanner extends LFOEffect<AutoPannerOptions> {\n\treadonly name: string = \"AutoPanner\";\n\n\t/**\n\t * The filter node\n\t */\n\treadonly _panner: Panner;\n\n\t/**\n\t * @param frequency Rate of left-right oscillation.\n\t */\n\tconstructor(frequency?: Frequency);\n\tconstructor(options?: Partial<AutoPannerOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tAutoPanner.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"frequency\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._panner = new Panner({\n\t\t\tcontext: this.context,\n\t\t\tchannelCount: options.channelCount,\n\t\t});\n\t\t// connections\n\t\tthis.connectEffect(this._panner);\n\t\tthis._lfo.connect(this._panner.pan);\n\t\tthis._lfo.min = -1;\n\t\tthis._lfo.max = 1;\n\t}\n\n\tstatic getDefaults(): AutoPannerOptions {\n\t\treturn Object.assign(LFOEffect.getDefaults(), {\n\t\t\tchannelCount: 1,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._panner.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/AutoWah.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { EffectTests } from \"../../test/helper/EffectTests.js\";\nimport { Synth } from \"../instrument/Synth.js\";\nimport { AutoWah } from \"./AutoWah.js\";\n\ndescribe(\"AutoWah\", () => {\n\tBasicTests(AutoWah);\n\tEffectTests(AutoWah);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst wah = new AutoWah().toDestination();\n\t\t\t\twah.follower = 0.4;\n\t\t\t\tconst synth = new Synth().connect(wah);\n\t\t\t\tsynth.triggerAttackRelease(\"C4\", 0.5);\n\t\t\t},\n\t\t\t\"autoWah.wav\",\n\t\t\t0.01\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst autoWah = new AutoWah({\n\t\t\t\tbaseFrequency: 150,\n\t\t\t\toctaves: 3,\n\t\t\t\tsensitivity: -10,\n\t\t\t});\n\t\t\texpect(autoWah.baseFrequency).to.be.closeTo(150, 0.01);\n\t\t\tautoWah.baseFrequency = 250;\n\t\t\texpect(autoWah.baseFrequency).to.be.closeTo(250, 0.01);\n\t\t\texpect(autoWah.octaves).to.be.closeTo(3, 0.01);\n\t\t\tautoWah.octaves = 2;\n\t\t\texpect(autoWah.octaves).to.be.closeTo(2, 0.01);\n\t\t\texpect(autoWah.sensitivity).to.be.closeTo(-10, 0.1);\n\t\t\tautoWah.sensitivity = -20;\n\t\t\texpect(autoWah.sensitivity).to.be.closeTo(-20, 0.1);\n\t\t\tautoWah.dispose();\n\t\t});\n\n\t\tit(\"can get/set the options\", () => {\n\t\t\tconst autoWah = new AutoWah();\n\t\t\tautoWah.set({\n\t\t\t\tQ: 2.4,\n\t\t\t});\n\t\t\texpect(autoWah.get().Q).to.be.closeTo(2.4, 0.01);\n\t\t\tautoWah.dispose();\n\t\t});\n\n\t\tit(\"can set the gain and follower values\", () => {\n\t\t\tconst autoWah = new AutoWah();\n\t\t\tautoWah.gain.value = 1.2;\n\t\t\tautoWah.follower = 0.4;\n\t\t\texpect(autoWah.gain.value).to.be.closeTo(1.2, 0.01);\n\t\t\texpect(autoWah.follower).to.be.closeTo(0.4, 0.01);\n\t\t\tautoWah.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/effect/AutoWah.ts",
    "content": "import { Follower } from \"../component/analysis/Follower.js\";\nimport { Filter } from \"../component/filter/Filter.js\";\nimport { Gain } from \"../core/context/Gain.js\";\nimport { dbToGain, gainToDb } from \"../core/type/Conversions.js\";\nimport {\n\tDecibels,\n\tFrequency,\n\tGainFactor,\n\tHertz,\n\tPositive,\n\tTime,\n} from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport { ScaleExp } from \"../signal/ScaleExp.js\";\nimport { Signal } from \"../signal/Signal.js\";\nimport { Effect, EffectOptions } from \"./Effect.js\";\n\nexport interface AutoWahOptions extends EffectOptions {\n\tbaseFrequency: Frequency;\n\toctaves: Positive;\n\tsensitivity: Decibels;\n\tQ: Positive;\n\tgain: GainFactor;\n\tfollower: Time;\n}\n\n/**\n * AutoWah connects a {@link Follower} to a {@link Filter}.\n * The frequency of the filter, follows the input amplitude curve.\n * Inspiration from [Tuna.js](https://github.com/Dinahmoe/tuna).\n *\n * @example\n * const autoWah = new Tone.AutoWah(50, 6, -30).toDestination();\n * // initialize the synth and connect to autowah\n * const synth = new Tone.Synth().connect(autoWah);\n * // Q value influences the effect of the wah - default is 2\n * autoWah.Q.value = 6;\n * // more audible on higher notes\n * synth.triggerAttackRelease(\"C4\", \"8n\");\n * @category Effect\n */\nexport class AutoWah extends Effect<AutoWahOptions> {\n\treadonly name: string = \"AutoWah\";\n\n\t/**\n\t * The envelope follower. Set the attack/release\n\t * timing to adjust how the envelope is followed.\n\t */\n\tprivate _follower: Follower;\n\n\t/**\n\t * scales the follower value to the frequency domain\n\t */\n\tprivate _sweepRange: ScaleExp;\n\n\t/**\n\t * Hold the base frequency value\n\t */\n\tprivate _baseFrequency: Hertz;\n\n\t/**\n\t * Private holder for the octave count\n\t */\n\tprivate _octaves: Positive;\n\n\t/**\n\t * the input gain to adjust the sensitivity\n\t */\n\tprivate _inputBoost: Gain;\n\n\t/**\n\t * Private holder for the filter\n\t */\n\tprivate _bandpass: Filter;\n\n\t/**\n\t * The peaking filter\n\t */\n\tprivate _peaking: Filter;\n\n\t/**\n\t * The gain of the filter.\n\t */\n\treadonly gain: Signal<\"decibels\">;\n\n\t/**\n\t * The quality of the filter.\n\t */\n\treadonly Q: Signal<\"positive\">;\n\n\t/**\n\t * @param baseFrequency The frequency the filter is set to at the low point of the wah\n\t * @param octaves The number of octaves above the baseFrequency the filter will sweep to when fully open.\n\t * @param sensitivity The decibel threshold sensitivity for the incoming signal. Normal range of -40 to 0.\n\t */\n\tconstructor(\n\t\tbaseFrequency?: Frequency,\n\t\toctaves?: Positive,\n\t\tsensitivity?: Decibels\n\t);\n\tconstructor(options?: Partial<AutoWahOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(AutoWah.getDefaults(), arguments, [\n\t\t\t\"baseFrequency\",\n\t\t\t\"octaves\",\n\t\t\t\"sensitivity\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis._follower = new Follower({\n\t\t\tcontext: this.context,\n\t\t\tsmoothing: options.follower,\n\t\t});\n\t\tthis._sweepRange = new ScaleExp({\n\t\t\tcontext: this.context,\n\t\t\tmin: 0,\n\t\t\tmax: 1,\n\t\t\texponent: 0.5,\n\t\t});\n\t\tthis._baseFrequency = this.toFrequency(options.baseFrequency);\n\t\tthis._octaves = options.octaves;\n\t\tthis._inputBoost = new Gain({ context: this.context });\n\t\tthis._bandpass = new Filter({\n\t\t\tcontext: this.context,\n\t\t\trolloff: -48,\n\t\t\tfrequency: 0,\n\t\t\tQ: options.Q,\n\t\t});\n\t\tthis._peaking = new Filter({\n\t\t\tcontext: this.context,\n\t\t\ttype: \"peaking\",\n\t\t});\n\t\tthis._peaking.gain.value = options.gain;\n\t\tthis.gain = this._peaking.gain;\n\t\tthis.Q = this._bandpass.Q;\n\n\t\t// the control signal path\n\t\tthis.effectSend.chain(\n\t\t\tthis._inputBoost,\n\t\t\tthis._follower,\n\t\t\tthis._sweepRange\n\t\t);\n\t\tthis._sweepRange.connect(this._bandpass.frequency);\n\t\tthis._sweepRange.connect(this._peaking.frequency);\n\t\t// the filtered path\n\t\tthis.effectSend.chain(this._bandpass, this._peaking, this.effectReturn);\n\t\t// set the initial value\n\t\tthis._setSweepRange();\n\t\tthis.sensitivity = options.sensitivity;\n\n\t\treadOnly(this, [\"gain\", \"Q\"]);\n\t}\n\n\tstatic getDefaults(): AutoWahOptions {\n\t\treturn Object.assign(Effect.getDefaults(), {\n\t\t\tbaseFrequency: 100,\n\t\t\toctaves: 6,\n\t\t\tsensitivity: 0,\n\t\t\tQ: 2,\n\t\t\tgain: 2,\n\t\t\tfollower: 0.2,\n\t\t});\n\t}\n\n\t/**\n\t * The number of octaves that the filter will sweep above the baseFrequency.\n\t */\n\tget octaves() {\n\t\treturn this._octaves;\n\t}\n\tset octaves(octaves) {\n\t\tthis._octaves = octaves;\n\t\tthis._setSweepRange();\n\t}\n\n\t/**\n\t * The follower's smoothing time\n\t */\n\tget follower(): Time {\n\t\treturn this._follower.smoothing;\n\t}\n\tset follower(follower) {\n\t\tthis._follower.smoothing = follower;\n\t}\n\n\t/**\n\t * The base frequency from which the sweep will start from.\n\t */\n\tget baseFrequency(): Frequency {\n\t\treturn this._baseFrequency;\n\t}\n\tset baseFrequency(baseFreq) {\n\t\tthis._baseFrequency = this.toFrequency(baseFreq);\n\t\tthis._setSweepRange();\n\t}\n\n\t/**\n\t * The sensitivity to control how responsive to the input signal the filter is.\n\t */\n\tget sensitivity(): Decibels {\n\t\treturn gainToDb(1 / this._inputBoost.gain.value);\n\t}\n\tset sensitivity(sensitivity) {\n\t\tthis._inputBoost.gain.value = 1 / dbToGain(sensitivity);\n\t}\n\n\t/**\n\t * sets the sweep range of the scaler\n\t */\n\tprivate _setSweepRange() {\n\t\tthis._sweepRange.min = this._baseFrequency;\n\t\tthis._sweepRange.max = Math.min(\n\t\t\tthis._baseFrequency * Math.pow(2, this._octaves),\n\t\t\tthis.context.sampleRate / 2\n\t\t);\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._follower.dispose();\n\t\tthis._sweepRange.dispose();\n\t\tthis._bandpass.dispose();\n\t\tthis._peaking.dispose();\n\t\tthis._inputBoost.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/BitCrusher.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { EffectTests } from \"../../test/helper/EffectTests.js\";\nimport { FeedbackCombFilter } from \"../component/filter/FeedbackCombFilter.js\";\nimport { Oscillator } from \"../source/oscillator/Oscillator.js\";\nimport { BitCrusher } from \"./BitCrusher.js\";\n\ndescribe(\"BitCrusher\", () => {\n\tBasicTests(BitCrusher);\n\tEffectTests(BitCrusher);\n\n\tcontext(\"API\", () => {\n\t\tit(\"matches a file\", () => {\n\t\t\treturn CompareToFile(\n\t\t\t\t() => {\n\t\t\t\t\tconst crusher = new BitCrusher({ bits: 4 }).toDestination();\n\t\t\t\t\tconst osc = new Oscillator(110).connect(crusher);\n\t\t\t\t\tosc.start(0);\n\t\t\t\t},\n\t\t\t\t\"bitCrusher.wav\",\n\t\t\t\t0.01\n\t\t\t);\n\t\t});\n\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst crusher = new BitCrusher({\n\t\t\t\tbits: 3,\n\t\t\t});\n\t\t\texpect(crusher.bits.value).to.equal(3);\n\t\t\tcrusher.dispose();\n\t\t});\n\n\t\tit(\"can get/set the options\", () => {\n\t\t\tconst crusher = new BitCrusher(4);\n\t\t\texpect(crusher.bits.value).to.equal(4);\n\t\t\tcrusher.set({\n\t\t\t\tbits: 5,\n\t\t\t});\n\t\t\texpect(crusher.get().bits).to.equal(5);\n\t\t\tcrusher.dispose();\n\t\t});\n\t});\n\n\tit(\"should be usable with the FeedbackCombFilter\", (done) => {\n\t\tnew BitCrusher(4);\n\t\tnew FeedbackCombFilter();\n\n\t\tconst handle = setTimeout(() => {\n\t\t\twindow.onunhandledrejection = null;\n\t\t\tdone();\n\t\t}, 100);\n\n\t\twindow.onunhandledrejection = (event) => {\n\t\t\tdone(event.reason);\n\t\t\tclearTimeout(handle);\n\t\t};\n\t});\n});\n"
  },
  {
    "path": "Tone/effect/BitCrusher.ts",
    "content": "import { Gain } from \"../core/context/Gain.js\";\nimport { Param } from \"../core/context/Param.js\";\nimport { connectSeries } from \"../core/context/ToneAudioNode.js\";\nimport { Positive } from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport {\n\tToneAudioWorklet,\n\tToneAudioWorkletOptions,\n} from \"../core/worklet/ToneAudioWorklet.js\";\nimport { workletName } from \"./BitCrusher.worklet.js\";\nimport { Effect, EffectOptions } from \"./Effect.js\";\n\nexport interface BitCrusherOptions extends EffectOptions {\n\tbits: Positive;\n}\n\n/**\n * BitCrusher down-samples the incoming signal to a different bit depth.\n * Lowering the bit depth of the signal creates distortion. Read more about BitCrushing\n * on [Wikipedia](https://en.wikipedia.org/wiki/Bitcrusher).\n * @example\n * // initialize crusher and route a synth through it\n * const crusher = new Tone.BitCrusher(4).toDestination();\n * const synth = new Tone.Synth().connect(crusher);\n * synth.triggerAttackRelease(\"C2\", 2);\n *\n * @category Effect\n */\nexport class BitCrusher extends Effect<BitCrusherOptions> {\n\treadonly name: string = \"BitCrusher\";\n\n\t/**\n\t * The bit depth of the effect\n\t * @min 1\n\t * @max 16\n\t */\n\treadonly bits: Param<\"positive\">;\n\n\t/**\n\t * The node which does the bit crushing effect. Runs in an AudioWorklet when possible.\n\t */\n\tprivate _bitCrusherWorklet: BitCrusherWorklet;\n\n\tconstructor(bits?: Positive);\n\tconstructor(options?: Partial<BitCrusherWorkletOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tBitCrusher.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"bits\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._bitCrusherWorklet = new BitCrusherWorklet({\n\t\t\tcontext: this.context,\n\t\t\tbits: options.bits,\n\t\t});\n\t\t// connect it up\n\t\tthis.connectEffect(this._bitCrusherWorklet);\n\n\t\tthis.bits = this._bitCrusherWorklet.bits;\n\t}\n\n\tstatic getDefaults(): BitCrusherOptions {\n\t\treturn Object.assign(Effect.getDefaults(), {\n\t\t\tbits: 4,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._bitCrusherWorklet.dispose();\n\t\treturn this;\n\t}\n}\n\ninterface BitCrusherWorkletOptions extends ToneAudioWorkletOptions {\n\tbits: number;\n}\n\n/**\n * Internal class which creates an AudioWorklet to do the bit crushing\n */\nclass BitCrusherWorklet extends ToneAudioWorklet<BitCrusherWorkletOptions> {\n\treadonly name: string = \"BitCrusherWorklet\";\n\n\treadonly input: Gain;\n\treadonly output: Gain;\n\n\treadonly bits: Param<\"positive\">;\n\n\tconstructor(options?: Partial<BitCrusherWorkletOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tBitCrusherWorklet.getDefaults(),\n\t\t\targuments\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.input = new Gain({ context: this.context });\n\t\tthis.output = new Gain({ context: this.context });\n\n\t\tthis.bits = new Param<\"positive\">({\n\t\t\tcontext: this.context,\n\t\t\tvalue: options.bits,\n\t\t\tunits: \"positive\",\n\t\t\tminValue: 1,\n\t\t\tmaxValue: 16,\n\t\t\tparam: this._dummyParam,\n\t\t\tswappable: true,\n\t\t});\n\t}\n\n\tstatic getDefaults(): BitCrusherWorkletOptions {\n\t\treturn Object.assign(ToneAudioWorklet.getDefaults(), {\n\t\t\tbits: 12,\n\t\t});\n\t}\n\n\tprotected _audioWorkletName(): string {\n\t\treturn workletName;\n\t}\n\n\tonReady(node: AudioWorkletNode) {\n\t\tconnectSeries(this.input, node, this.output);\n\t\tconst bits = node.parameters.get(\"bits\") as AudioParam;\n\t\tthis.bits.setParam(bits);\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.input.dispose();\n\t\tthis.output.dispose();\n\t\tthis.bits.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/BitCrusher.worklet.ts",
    "content": "import \"../core/worklet/SingleIOProcessor.worklet.js\";\n\nimport { registerProcessor } from \"../core/worklet/WorkletGlobalScope.js\";\n\nexport const workletName = \"bit-crusher\";\n\nexport const bitCrusherWorklet = /* javascript */ `\n\tclass BitCrusherWorklet extends SingleIOProcessor {\n\n\t\tstatic get parameterDescriptors() {\n\t\t\treturn [{\n\t\t\t\tname: \"bits\",\n\t\t\t\tdefaultValue: 12,\n\t\t\t\tminValue: 1,\n\t\t\t\tmaxValue: 16,\n\t\t\t\tautomationRate: 'k-rate'\n\t\t\t}];\n\t\t}\n\n\t\tgenerate(input, _channel, parameters) {\n\t\t\tconst step = Math.pow(0.5, parameters.bits - 1);\n\t\t\tconst val = step * Math.floor(input / step + 0.5);\n\t\t\treturn val;\n\t\t}\n\t}\n`;\n\nregisterProcessor(workletName, bitCrusherWorklet);\n"
  },
  {
    "path": "Tone/effect/Chebyshev.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { EffectTests } from \"../../test/helper/EffectTests.js\";\nimport { Synth } from \"../instrument/index.js\";\nimport { Chebyshev } from \"./Chebyshev.js\";\n\ndescribe(\"Chebyshev\", () => {\n\tBasicTests(Chebyshev);\n\tEffectTests(Chebyshev, 51);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst cheby = new Chebyshev(100).toDestination();\n\t\t\t\tconst synth = new Synth().connect(cheby);\n\t\t\t\tsynth.triggerAttackRelease(\"C2\", 0.2);\n\t\t\t},\n\t\t\t\"chebyshev.wav\",\n\t\t\t0.01\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst cheby = new Chebyshev({\n\t\t\t\torder: 2,\n\t\t\t});\n\t\t\texpect(cheby.order).to.equal(2);\n\t\t\tcheby.dispose();\n\t\t});\n\n\t\tit(\"can get/set the options\", () => {\n\t\t\tconst cheby = new Chebyshev();\n\t\t\tcheby.set({\n\t\t\t\torder: 40,\n\t\t\t});\n\t\t\texpect(cheby.get().order).to.equal(40);\n\t\t\tcheby.dispose();\n\t\t});\n\n\t\tit(\"throws an error if order is not an integer\", () => {\n\t\t\tconst cheby = new Chebyshev();\n\t\t\texpect(() => {\n\t\t\t\tcheby.order = 0.2;\n\t\t\t}).to.throw(Error);\n\t\t\tcheby.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/effect/Chebyshev.ts",
    "content": "import { Positive } from \"../core/type/Units.js\";\nimport { assert } from \"../core/util/Debug.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { WaveShaper } from \"../signal/WaveShaper.js\";\nimport { Effect, EffectOptions } from \"./Effect.js\";\n\nexport interface ChebyshevOptions extends EffectOptions {\n\torder: Positive;\n\toversample: OverSampleType;\n}\n\n/**\n * Chebyshev is a waveshaper which is good\n * for making different types of distortion sounds.\n * Note that odd orders sound very different from even ones,\n * and order = 1 is no change.\n * Read more at [music.columbia.edu](http://music.columbia.edu/cmc/musicandcomputers/chapter4/04_06.php).\n * @example\n * // create a new cheby\n * const cheby = new Tone.Chebyshev(50).toDestination();\n * // create a monosynth connected to our cheby\n * const synth = new Tone.MonoSynth().connect(cheby);\n * synth.triggerAttackRelease(\"C2\", 0.4);\n * @category Effect\n */\nexport class Chebyshev extends Effect<ChebyshevOptions> {\n\treadonly name: string = \"Chebyshev\";\n\n\t/**\n\t * The private waveshaper node\n\t */\n\tprivate _shaper: WaveShaper;\n\n\t/**\n\t * holds onto the order of the filter\n\t */\n\tprivate _order: number;\n\n\t/**\n\t * @param order The order of the chebyshev polynomial. Normal range between 1-100.\n\t */\n\tconstructor(order?: Positive);\n\tconstructor(options?: Partial<ChebyshevOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tChebyshev.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"order\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._shaper = new WaveShaper({\n\t\t\tcontext: this.context,\n\t\t\tlength: 4096,\n\t\t});\n\t\tthis._order = options.order;\n\n\t\tthis.connectEffect(this._shaper);\n\t\tthis.order = options.order;\n\t\tthis.oversample = options.oversample;\n\t}\n\n\tstatic getDefaults(): ChebyshevOptions {\n\t\treturn Object.assign(Effect.getDefaults(), {\n\t\t\torder: 1,\n\t\t\toversample: \"none\" as const,\n\t\t});\n\t}\n\n\t/**\n\t * get the coefficient for that degree\n\t * @param  x the x value\n\t * @param  degree\n\t * @param  memo memoize the computed value. this speeds up computation greatly.\n\t */\n\tprivate _getCoefficient(\n\t\tx: number,\n\t\tdegree: number,\n\t\tmemo: Map<number, number>\n\t): number {\n\t\tif (memo.has(degree)) {\n\t\t\treturn memo.get(degree) as number;\n\t\t} else if (degree === 0) {\n\t\t\tmemo.set(degree, 0);\n\t\t} else if (degree === 1) {\n\t\t\tmemo.set(degree, x);\n\t\t} else {\n\t\t\tmemo.set(\n\t\t\t\tdegree,\n\t\t\t\t2 * x * this._getCoefficient(x, degree - 1, memo) -\n\t\t\t\t\tthis._getCoefficient(x, degree - 2, memo)\n\t\t\t);\n\t\t}\n\t\treturn memo.get(degree) as number;\n\t}\n\n\t/**\n\t * The order of the Chebyshev polynomial which creates the equation which is applied to the incoming\n\t * signal through a Tone.WaveShaper. Must be an integer. The equations are in the form:\n\t * ```\n\t * order 2: 2x^2 + 1\n\t * order 3: 4x^3 + 3x\n\t * ```\n\t * @min 1\n\t * @max 100\n\t */\n\tget order(): Positive {\n\t\treturn this._order;\n\t}\n\tset order(order) {\n\t\tassert(Number.isInteger(order), \"'order' must be an integer\");\n\t\tthis._order = order;\n\t\tthis._shaper.setMap((x) => {\n\t\t\treturn this._getCoefficient(x, order, new Map());\n\t\t});\n\t}\n\n\t/**\n\t * The oversampling of the effect. Can either be \"none\", \"2x\" or \"4x\".\n\t */\n\tget oversample(): OverSampleType {\n\t\treturn this._shaper.oversample;\n\t}\n\tset oversample(oversampling) {\n\t\tthis._shaper.oversample = oversampling;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._shaper.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/Chorus.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { EffectTests } from \"../../test/helper/EffectTests.js\";\nimport { Offline } from \"../../test/helper/Offline.js\";\nimport { Oscillator } from \"../source/index.js\";\nimport { Chorus } from \"./Chorus.js\";\n\ndescribe(\"Chorus\", () => {\n\tBasicTests(Chorus);\n\tEffectTests(Chorus);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst chorus = new Chorus().toDestination().start();\n\t\t\t\tconst osc = new Oscillator(220, \"sawtooth\")\n\t\t\t\t\t.connect(chorus)\n\t\t\t\t\t.start();\n\t\t\t},\n\t\t\t\"chorus.wav\",\n\t\t\t0.25\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst chorus = new Chorus({\n\t\t\t\tfrequency: 2,\n\t\t\t\tdelayTime: 1,\n\t\t\t\tdepth: 0.4,\n\t\t\t\tspread: 90,\n\t\t\t});\n\t\t\texpect(chorus.frequency.value).to.be.closeTo(2, 0.01);\n\t\t\texpect(chorus.delayTime).to.be.closeTo(1, 0.01);\n\t\t\texpect(chorus.depth).to.be.closeTo(0.4, 0.01);\n\t\t\texpect(chorus.spread).to.be.equal(90);\n\t\t\tchorus.dispose();\n\t\t});\n\n\t\tit(\"can get/set the options\", () => {\n\t\t\tconst chorus = new Chorus();\n\t\t\tchorus.set({\n\t\t\t\ttype: \"square\",\n\t\t\t});\n\t\t\texpect(chorus.get().type).to.equal(\"square\");\n\t\t\tchorus.dispose();\n\t\t});\n\n\t\tit(\"can get/set the delayTime\", () => {\n\t\t\tconst chorus = new Chorus();\n\t\t\tchorus.delayTime = 3;\n\t\t\texpect(chorus.delayTime).to.equal(3);\n\t\t\tchorus.dispose();\n\t\t});\n\n\t\tit(\"can be started and stopped\", () => {\n\t\t\tconst chorus = new Chorus();\n\t\t\tchorus.start().stop(\"+0.2\");\n\t\t\tchorus.dispose();\n\t\t});\n\n\t\tit(\"can sync the frequency to the transport\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst chorus = new Chorus(2);\n\t\t\t\tchorus.sync();\n\t\t\t\tchorus.frequency.toDestination();\n\t\t\t\ttransport.bpm.setValueAtTime(transport.bpm.value * 2, 0.05);\n\t\t\t}, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(2, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.05)).to.be.closeTo(4, 0.1);\n\t\t});\n\n\t\tit(\"can unsync the frequency to the transport\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst chorus = new Chorus(2);\n\t\t\t\tchorus.sync();\n\t\t\t\tchorus.frequency.toDestination();\n\t\t\t\ttransport.bpm.setValueAtTime(transport.bpm.value * 2, 0.05);\n\t\t\t\tchorus.unsync();\n\t\t\t}, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(2, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.05)).to.be.closeTo(2, 0.1);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/effect/Chorus.ts",
    "content": "import { Delay } from \"../core/context/Delay.js\";\nimport {\n\tDegrees,\n\tFrequency,\n\tMilliseconds,\n\tNormalRange,\n\tSeconds,\n\tTime,\n} from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport {\n\tStereoFeedbackEffect,\n\tStereoFeedbackEffectOptions,\n} from \"../effect/StereoFeedbackEffect.js\";\nimport { Signal } from \"../signal/Signal.js\";\nimport { LFO } from \"../source/oscillator/LFO.js\";\nimport { ToneOscillatorType } from \"../source/oscillator/OscillatorInterface.js\";\n\nexport interface ChorusOptions extends StereoFeedbackEffectOptions {\n\tfrequency: Frequency;\n\tdelayTime: Milliseconds;\n\tdepth: NormalRange;\n\ttype: ToneOscillatorType;\n\tspread: Degrees;\n}\n\n/**\n * Chorus is a stereo chorus effect composed of a left and right delay with an {@link LFO} applied to the delayTime of each channel.\n * When {@link feedback} is set to a value larger than 0, you also get Flanger-type effects.\n * Inspiration from [Tuna.js](https://github.com/Dinahmoe/tuna/blob/master/tuna.js).\n * Read more on the chorus effect on [Sound On Sound](http://www.soundonsound.com/sos/jun04/articles/synthsecrets.htm).\n *\n * @example\n * const chorus = new Tone.Chorus(4, 2.5, 0.5).toDestination().start();\n * const synth = new Tone.PolySynth().connect(chorus);\n * synth.triggerAttackRelease([\"C3\", \"E3\", \"G3\"], \"8n\");\n *\n * @category Effect\n */\nexport class Chorus extends StereoFeedbackEffect<ChorusOptions> {\n\treadonly name: string = \"Chorus\";\n\n\t/**\n\t * the depth of the chorus\n\t */\n\tprivate _depth: NormalRange;\n\n\t/**\n\t * the delayTime in seconds.\n\t */\n\tprivate _delayTime: Seconds;\n\n\t/**\n\t * the lfo which controls the delayTime\n\t */\n\tprivate _lfoL: LFO;\n\n\t/**\n\t * another LFO for the right side with a 180 degree phase diff\n\t */\n\tprivate _lfoR: LFO;\n\n\t/**\n\t * delay for left\n\t */\n\tprivate _delayNodeL: Delay;\n\n\t/**\n\t * delay for right\n\t */\n\tprivate _delayNodeR: Delay;\n\n\t/**\n\t * The frequency of the LFO which modulates the delayTime.\n\t */\n\treadonly frequency: Signal<\"frequency\">;\n\n\t/**\n\t * @param frequency The frequency of the LFO.\n\t * @param delayTime The delay of the chorus effect in ms.\n\t * @param depth The depth of the chorus.\n\t */\n\tconstructor(\n\t\tfrequency?: Frequency,\n\t\tdelayTime?: Milliseconds,\n\t\tdepth?: NormalRange\n\t);\n\tconstructor(options?: Partial<ChorusOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Chorus.getDefaults(), arguments, [\n\t\t\t\"frequency\",\n\t\t\t\"delayTime\",\n\t\t\t\"depth\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis._depth = options.depth;\n\t\tthis._delayTime = options.delayTime / 1000;\n\t\tthis._lfoL = new LFO({\n\t\t\tcontext: this.context,\n\t\t\tfrequency: options.frequency,\n\t\t\tmin: 0,\n\t\t\tmax: 1,\n\t\t});\n\t\tthis._lfoR = new LFO({\n\t\t\tcontext: this.context,\n\t\t\tfrequency: options.frequency,\n\t\t\tmin: 0,\n\t\t\tmax: 1,\n\t\t\tphase: 180,\n\t\t});\n\t\tthis._delayNodeL = new Delay({ context: this.context });\n\t\tthis._delayNodeR = new Delay({ context: this.context });\n\t\tthis.frequency = this._lfoL.frequency;\n\t\treadOnly(this, [\"frequency\"]);\n\t\t// have one LFO frequency control the other\n\t\tthis._lfoL.frequency.connect(this._lfoR.frequency);\n\n\t\t// connections\n\t\tthis.connectEffectLeft(this._delayNodeL);\n\t\tthis.connectEffectRight(this._delayNodeR);\n\t\t// lfo setup\n\t\tthis._lfoL.connect(this._delayNodeL.delayTime);\n\t\tthis._lfoR.connect(this._delayNodeR.delayTime);\n\t\t// set the initial values\n\t\tthis.depth = this._depth;\n\t\tthis.type = options.type;\n\t\tthis.spread = options.spread;\n\t}\n\n\tstatic getDefaults(): ChorusOptions {\n\t\treturn Object.assign(StereoFeedbackEffect.getDefaults(), {\n\t\t\tfrequency: 1.5,\n\t\t\tdelayTime: 3.5,\n\t\t\tdepth: 0.7,\n\t\t\ttype: \"sine\" as const,\n\t\t\tspread: 180,\n\t\t\tfeedback: 0,\n\t\t\twet: 0.5,\n\t\t});\n\t}\n\n\t/**\n\t * The depth of the effect. A depth of 1 makes the delayTime\n\t * modulate between 0 and 2*delayTime (centered around the delayTime).\n\t */\n\tget depth(): NormalRange {\n\t\treturn this._depth;\n\t}\n\tset depth(depth) {\n\t\tthis._depth = depth;\n\t\tconst deviation = this._delayTime * depth;\n\t\tthis._lfoL.min = Math.max(this._delayTime - deviation, 0);\n\t\tthis._lfoL.max = this._delayTime + deviation;\n\t\tthis._lfoR.min = Math.max(this._delayTime - deviation, 0);\n\t\tthis._lfoR.max = this._delayTime + deviation;\n\t}\n\n\t/**\n\t * The delayTime in milliseconds of the chorus. A larger delayTime\n\t * will give a more pronounced effect. Nominal range a delayTime\n\t * is between 2 and 20ms.\n\t */\n\tget delayTime(): Milliseconds {\n\t\treturn this._delayTime * 1000;\n\t}\n\tset delayTime(delayTime) {\n\t\tthis._delayTime = delayTime / 1000;\n\t\tthis.depth = this._depth;\n\t}\n\n\t/**\n\t * The oscillator type of the LFO.\n\t */\n\tget type(): ToneOscillatorType {\n\t\treturn this._lfoL.type;\n\t}\n\tset type(type) {\n\t\tthis._lfoL.type = type;\n\t\tthis._lfoR.type = type;\n\t}\n\n\t/**\n\t * Amount of stereo spread. When set to 0, both LFO's will be panned centrally.\n\t * When set to 180, LFO's will be panned hard left and right respectively.\n\t */\n\tget spread(): Degrees {\n\t\treturn this._lfoR.phase - this._lfoL.phase;\n\t}\n\tset spread(spread) {\n\t\tthis._lfoL.phase = 90 - spread / 2;\n\t\tthis._lfoR.phase = spread / 2 + 90;\n\t}\n\n\t/**\n\t * Start the effect.\n\t */\n\tstart(time?: Time): this {\n\t\tthis._lfoL.start(time);\n\t\tthis._lfoR.start(time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop the lfo\n\t */\n\tstop(time?: Time): this {\n\t\tthis._lfoL.stop(time);\n\t\tthis._lfoR.stop(time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sync the filter to the transport.\n\t * @see {@link LFO.sync}\n\t */\n\tsync(): this {\n\t\tthis._lfoL.sync();\n\t\tthis._lfoR.sync();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Unsync the filter from the transport.\n\t */\n\tunsync(): this {\n\t\tthis._lfoL.unsync();\n\t\tthis._lfoR.unsync();\n\t\treturn this;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._lfoL.dispose();\n\t\tthis._lfoR.dispose();\n\t\tthis._delayNodeL.dispose();\n\t\tthis._delayNodeR.dispose();\n\t\tthis.frequency.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/Distortion.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { EffectTests } from \"../../test/helper/EffectTests.js\";\nimport { Oscillator } from \"../source/oscillator/Oscillator.js\";\nimport { Distortion } from \"./Distortion.js\";\n\ndescribe(\"Distortion\", () => {\n\tBasicTests(Distortion);\n\tEffectTests(Distortion);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst dist = new Distortion(0.8).toDestination();\n\t\t\t\tconst osc = new Oscillator().connect(dist);\n\t\t\t\tosc.type = \"square\";\n\t\t\t\tosc.start(0).stop(0.4);\n\t\t\t},\n\t\t\t\"distortion.wav\",\n\t\t\t0.02\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst dist = new Distortion({\n\t\t\t\tdistortion: 0.2,\n\t\t\t});\n\t\t\texpect(dist.distortion).to.be.closeTo(0.2, 0.01);\n\t\t\tdist.dispose();\n\t\t});\n\n\t\tit(\"can get/set the options\", () => {\n\t\t\tconst dist = new Distortion();\n\t\t\tdist.set({\n\t\t\t\toversample: \"4x\",\n\t\t\t});\n\t\t\texpect(dist.get().oversample).to.equal(\"4x\");\n\t\t\tdist.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/effect/Distortion.ts",
    "content": "import { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { WaveShaper } from \"../signal/WaveShaper.js\";\nimport { Effect, EffectOptions } from \"./Effect.js\";\n\nexport interface DistortionOptions extends EffectOptions {\n\tdistortion: number;\n\toversample: OverSampleType;\n}\n\n/**\n * A simple distortion effect using Tone.WaveShaper.\n * Algorithm from [this stackoverflow answer](http://stackoverflow.com/a/22313408).\n * Read more about distortion on [Wikipedia](https://en.wikipedia.org/wiki/Distortion_(music).\n * @example\n * const dist = new Tone.Distortion(0.8).toDestination();\n * const fm = new Tone.FMSynth().connect(dist);\n * fm.triggerAttackRelease(\"A1\", \"8n\");\n * @category Effect\n */\nexport class Distortion extends Effect<DistortionOptions> {\n\treadonly name: string = \"Distortion\";\n\n\t/**\n\t * The waveshaper which does the distortion\n\t */\n\tprivate _shaper: WaveShaper;\n\n\t/**\n\t * Stores the distortion value\n\t */\n\tprivate _distortion: number;\n\n\t/**\n\t * @param distortion The amount of distortion (nominal range of 0-1)\n\t */\n\tconstructor(distortion?: number);\n\tconstructor(options?: Partial<DistortionOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tDistortion.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"distortion\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._shaper = new WaveShaper({\n\t\t\tcontext: this.context,\n\t\t\tlength: 4096,\n\t\t});\n\n\t\tthis._distortion = options.distortion;\n\n\t\tthis.connectEffect(this._shaper);\n\t\tthis.distortion = options.distortion;\n\t\tthis.oversample = options.oversample;\n\t}\n\n\tstatic getDefaults(): DistortionOptions {\n\t\treturn Object.assign(Effect.getDefaults(), {\n\t\t\tdistortion: 0.4,\n\t\t\toversample: \"none\" as OverSampleType,\n\t\t});\n\t}\n\n\t/**\n\t * The amount of distortion. Nominal range is between 0 and 1.\n\t */\n\tget distortion(): number {\n\t\treturn this._distortion;\n\t}\n\tset distortion(amount) {\n\t\tthis._distortion = amount;\n\t\tconst k = amount * 100;\n\t\tconst deg = Math.PI / 180;\n\t\tthis._shaper.setMap((x) => {\n\t\t\tif (Math.abs(x) < 0.001) {\n\t\t\t\t// should output 0 when input is 0\n\t\t\t\treturn 0;\n\t\t\t} else {\n\t\t\t\treturn ((3 + k) * x * 20 * deg) / (Math.PI + k * Math.abs(x));\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * The oversampling of the effect. Can either be \"none\", \"2x\" or \"4x\".\n\t */\n\tget oversample(): OverSampleType {\n\t\treturn this._shaper.oversample;\n\t}\n\tset oversample(oversampling) {\n\t\tthis._shaper.oversample = oversampling;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._shaper.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/Effect.ts",
    "content": "import { CrossFade } from \"../component/channel/CrossFade.js\";\nimport { Gain } from \"../core/context/Gain.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../core/context/ToneAudioNode.js\";\nimport { NormalRange } from \"../core/type/Units.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport { Signal } from \"../signal/Signal.js\";\n\nexport interface EffectOptions extends ToneAudioNodeOptions {\n\twet: NormalRange;\n}\n/**\n * Effect is the base class for effects. Connect the effect between\n * the effectSend and effectReturn GainNodes, then control the amount of\n * effect which goes to the output using the wet control.\n */\nexport abstract class Effect<\n\tOptions extends EffectOptions,\n> extends ToneAudioNode<Options> {\n\treadonly name: string = \"Effect\";\n\n\t/**\n\t * the drywet knob to control the amount of effect\n\t */\n\tprivate _dryWet: CrossFade = new CrossFade({ context: this.context });\n\n\t/**\n\t * The wet control is how much of the effected\n\t * will pass through to the output. 1 = 100% effected\n\t * signal, 0 = 100% dry signal.\n\t */\n\twet: Signal<\"normalRange\"> = this._dryWet.fade;\n\n\t/**\n\t * connect the effectSend to the input of the effect\n\t */\n\tprotected effectSend: Gain = new Gain({ context: this.context });\n\n\t/**\n\t * connect the output of the effect to the effectReturn\n\t */\n\tprotected effectReturn: Gain = new Gain({ context: this.context });\n\n\t/**\n\t * The effect input node\n\t */\n\tinput: Gain = new Gain({ context: this.context });\n\n\t/**\n\t * The effect output\n\t */\n\toutput = this._dryWet;\n\n\tconstructor(options: EffectOptions) {\n\t\tsuper(options);\n\n\t\t// connections\n\t\tthis.input.fan(this._dryWet.a, this.effectSend);\n\t\tthis.effectReturn.connect(this._dryWet.b);\n\t\tthis.wet.setValueAtTime(options.wet, 0);\n\t\tthis._internalChannels = [this.effectReturn, this.effectSend];\n\t\treadOnly(this, \"wet\");\n\t}\n\n\tstatic getDefaults(): EffectOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\twet: 1,\n\t\t});\n\t}\n\n\t/**\n\t * chains the effect in between the effectSend and effectReturn\n\t */\n\tprotected connectEffect(effect: ToneAudioNode | AudioNode): this {\n\t\t// add it to the internal channels\n\t\tthis._internalChannels.push(effect);\n\t\tthis.effectSend.chain(effect, this.effectReturn);\n\t\treturn this;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._dryWet.dispose();\n\t\tthis.effectSend.dispose();\n\t\tthis.effectReturn.dispose();\n\t\tthis.wet.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/FeedbackDelay.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { EffectTests } from \"../../test/helper/EffectTests.js\";\nimport { Oscillator } from \"../source/oscillator/Oscillator.js\";\nimport { FeedbackDelay } from \"./FeedbackDelay.js\";\nimport { FeedbackEffect } from \"./FeedbackEffect.js\";\n\ndescribe(\"FeedbackDelay\", () => {\n\tBasicTests(FeedbackDelay);\n\tEffectTests(FeedbackDelay, 0.01);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst delay = new FeedbackDelay(0.1, 0.6).toDestination();\n\t\t\t\tconst osc = new Oscillator().connect(delay);\n\t\t\t\tosc.type = \"square\";\n\t\t\t\tosc.start(0).stop(0.01);\n\t\t\t},\n\t\t\t\"feedbackDelay.wav\",\n\t\t\t0.05\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"extends FeedbackEffect\", () => {\n\t\t\tconst feedbackDelay = new FeedbackDelay(0.2, 0.3);\n\t\t\texpect(feedbackDelay).to.be.instanceOf(FeedbackEffect);\n\t\t\tfeedbackDelay.dispose();\n\t\t});\n\n\t\tit(\"parses constructor arguments correctly\", () => {\n\t\t\tconst feedbackDelay = new FeedbackDelay(0.1, 0.4);\n\t\t\texpect(feedbackDelay.delayTime.value).to.be.closeTo(0.1, 0.01);\n\t\t\texpect(feedbackDelay.feedback.value).to.be.closeTo(0.4, 0.01);\n\t\t\tfeedbackDelay.dispose();\n\t\t});\n\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst feedbackDelay = new FeedbackDelay({\n\t\t\t\tdelayTime: 0.2,\n\t\t\t\tfeedback: 0.3,\n\t\t\t});\n\t\t\texpect(feedbackDelay.delayTime.value).to.be.closeTo(0.2, 0.01);\n\t\t\texpect(feedbackDelay.feedback.value).to.be.closeTo(0.3, 0.01);\n\t\t\tfeedbackDelay.dispose();\n\t\t});\n\n\t\tit(\"can get/set the options\", () => {\n\t\t\tconst feedbackDelay = new FeedbackDelay();\n\t\t\tfeedbackDelay.set({\n\t\t\t\tfeedback: 0.4,\n\t\t\t});\n\t\t\texpect(feedbackDelay.get().feedback).to.be.closeTo(0.4, 0.01);\n\t\t\tfeedbackDelay.dispose();\n\t\t});\n\n\t\tit(\"can set the delayTime\", () => {\n\t\t\tconst feedbackDelay = new FeedbackDelay();\n\t\t\tfeedbackDelay.delayTime.value = \"4n\";\n\t\t\texpect(feedbackDelay.delayTime.value).to.be.closeTo(0.5, 0.001);\n\t\t\tfeedbackDelay.delayTime.value = 0.22;\n\t\t\texpect(feedbackDelay.delayTime.value).to.be.closeTo(0.22, 0.001);\n\t\t\tfeedbackDelay.dispose();\n\t\t});\n\n\t\tit(\"can set the feedback amount\", () => {\n\t\t\tconst feedbackDelay = new FeedbackDelay();\n\t\t\tfeedbackDelay.feedback.value = 1;\n\t\t\texpect(feedbackDelay.feedback.value).to.be.closeTo(1, 0.001);\n\t\t\tfeedbackDelay.feedback.value = 0.22;\n\t\t\texpect(feedbackDelay.feedback.value).to.be.closeTo(0.22, 0.001);\n\t\t\tfeedbackDelay.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/effect/FeedbackDelay.ts",
    "content": "import { Delay } from \"../core/context/Delay.js\";\nimport { Param } from \"../core/context/Param.js\";\nimport { NormalRange, Time } from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport { FeedbackEffect, FeedbackEffectOptions } from \"./FeedbackEffect.js\";\n\nexport interface FeedbackDelayOptions extends FeedbackEffectOptions {\n\tdelayTime: Time;\n\tmaxDelay: Time;\n}\n\n/**\n * FeedbackDelay is a DelayNode in which part of output signal is fed back into the delay.\n *\n * @param delayTime The delay applied to the incoming signal.\n * @param feedback The amount of the effected signal which is fed back through the delay.\n * @example\n * const feedbackDelay = new Tone.FeedbackDelay(\"8n\", 0.5).toDestination();\n * const tom = new Tone.MembraneSynth({\n * \toctaves: 4,\n * \tpitchDecay: 0.1\n * }).connect(feedbackDelay);\n * tom.triggerAttackRelease(\"A2\", \"32n\");\n * @category Effect\n */\nexport class FeedbackDelay extends FeedbackEffect<FeedbackDelayOptions> {\n\treadonly name: string = \"FeedbackDelay\";\n\n\t/**\n\t * the delay node\n\t */\n\tprivate _delayNode: Delay;\n\n\t/**\n\t * The delayTime of the FeedbackDelay.\n\t */\n\treadonly delayTime: Param<\"time\">;\n\n\tconstructor(delayTime?: Time, feedback?: NormalRange);\n\tconstructor(options?: Partial<FeedbackDelayOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tFeedbackDelay.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"delayTime\", \"feedback\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._delayNode = new Delay({\n\t\t\tcontext: this.context,\n\t\t\tdelayTime: options.delayTime,\n\t\t\tmaxDelay: options.maxDelay,\n\t\t});\n\t\tthis.delayTime = this._delayNode.delayTime;\n\n\t\t// connect it up\n\t\tthis.connectEffect(this._delayNode);\n\t\treadOnly(this, \"delayTime\");\n\t}\n\n\tstatic getDefaults(): FeedbackDelayOptions {\n\t\treturn Object.assign(FeedbackEffect.getDefaults(), {\n\t\t\tdelayTime: 0.25,\n\t\t\tmaxDelay: 1,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._delayNode.dispose();\n\t\tthis.delayTime.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/FeedbackEffect.ts",
    "content": "import { Gain } from \"../core/context/Gain.js\";\nimport { Param } from \"../core/context/Param.js\";\nimport { NormalRange } from \"../core/type/Units.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport { Effect, EffectOptions } from \"./Effect.js\";\n\nexport interface FeedbackEffectOptions extends EffectOptions {\n\t/**\n\t * The feedback from the output back to the input\n\t * ```\n\t * +---<--------<---+\n\t * |                |\n\t * |  +----------+  |\n\t * +--> feedback +>-+\n\t *    +----------+\n\t * ```\n\t */\n\tfeedback: NormalRange;\n}\n\n/**\n * FeedbackEffect provides a loop between an audio source and its own output.\n * This is a base-class for feedback effects.\n *\n * NOTE: Feedback effects require at least one DelayNode to be in the feedback cycle.\n */\nexport abstract class FeedbackEffect<\n\tOptions extends FeedbackEffectOptions,\n> extends Effect<Options> {\n\treadonly name: string = \"FeedbackEffect\";\n\n\t/**\n\t * the gain which controls the feedback\n\t */\n\tprivate _feedbackGain: Gain<\"normalRange\">;\n\n\t/**\n\t * The amount of signal which is fed back into the effect input.\n\t */\n\tfeedback: Param<\"normalRange\">;\n\n\tconstructor(options: FeedbackEffectOptions) {\n\t\tsuper(options);\n\n\t\tthis._feedbackGain = new Gain({\n\t\t\tcontext: this.context,\n\t\t\tgain: options.feedback,\n\t\t\tunits: \"normalRange\",\n\t\t});\n\n\t\tthis.feedback = this._feedbackGain.gain;\n\t\treadOnly(this, \"feedback\");\n\n\t\t// the feedback loop\n\t\tthis.effectReturn.chain(this._feedbackGain, this.effectSend);\n\t}\n\n\tstatic getDefaults(): FeedbackEffectOptions {\n\t\treturn Object.assign(Effect.getDefaults(), {\n\t\t\tfeedback: 0.125,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._feedbackGain.dispose();\n\t\tthis.feedback.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/Freeverb.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { EffectTests } from \"../../test/helper/EffectTests.js\";\nimport { Oscillator } from \"../source/oscillator/Oscillator.js\";\nimport { Freeverb } from \"./Freeverb.js\";\n\ndescribe(\"Freeverb\", () => {\n\tBasicTests(Freeverb);\n\tEffectTests(Freeverb);\n\n\tit(\"matches a file basic\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst reverb = new Freeverb(0.9).toDestination();\n\t\t\t\treverb.dampening = 7000;\n\t\t\t\tconst osc = new Oscillator().connect(reverb);\n\t\t\t\tosc.start(0).stop(0.01);\n\t\t\t},\n\t\t\t\"freeverb.wav\",\n\t\t\t0.3\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst reverb = new Freeverb({\n\t\t\t\tdampening: 2000,\n\t\t\t\troomSize: 0.2,\n\t\t\t});\n\t\t\texpect(reverb.dampening).to.be.closeTo(2000, 0.01);\n\t\t\texpect(reverb.roomSize.value).to.be.closeTo(0.2, 0.01);\n\t\t\treverb.dispose();\n\t\t});\n\n\t\tit(\"can get/set the options\", () => {\n\t\t\tconst reverb = new Freeverb(0.2, 2300);\n\t\t\treverb.set({\n\t\t\t\troomSize: 0.23,\n\t\t\t});\n\t\t\texpect(reverb.get().dampening).to.be.closeTo(2300, 0.01);\n\t\t\texpect(reverb.get().roomSize).to.be.closeTo(0.23, 0.01);\n\t\t\treverb.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/effect/Freeverb.ts",
    "content": "import { LowpassCombFilter } from \"../component/filter/LowpassCombFilter.js\";\nimport { Frequency, NormalRange } from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport { Signal } from \"../signal/Signal.js\";\nimport { StereoEffect, StereoEffectOptions } from \"./StereoEffect.js\";\n\nexport interface FreeverbOptions extends StereoEffectOptions {\n\tdampening: Frequency;\n\troomSize: NormalRange;\n}\n\n/**\n * An array of comb filter delay values from Freeverb implementation\n */\nconst combFilterTunings = [\n\t1557 / 44100,\n\t1617 / 44100,\n\t1491 / 44100,\n\t1422 / 44100,\n\t1277 / 44100,\n\t1356 / 44100,\n\t1188 / 44100,\n\t1116 / 44100,\n];\n\n/**\n * An array of allpass filter frequency values from Freeverb implementation\n */\nconst allpassFilterFrequencies = [225, 556, 441, 341];\n\n/**\n * Freeverb is a reverb based on [Freeverb](https://ccrma.stanford.edu/~jos/pasp/Freeverb.html).\n * Read more on reverb on [Sound On Sound](https://web.archive.org/web/20160404083902/http://www.soundonsound.com:80/sos/feb01/articles/synthsecrets.asp).\n * Freeverb is now implemented with an AudioWorkletNode which may result on performance degradation on some platforms. Consider using {@link Reverb}.\n * @example\n * const freeverb = new Tone.Freeverb().toDestination();\n * freeverb.dampening = 1000;\n * // routing synth through the reverb\n * const synth = new Tone.NoiseSynth().connect(freeverb);\n * synth.triggerAttackRelease(0.05);\n * @category Effect\n */\nexport class Freeverb extends StereoEffect<FreeverbOptions> {\n\treadonly name: string = \"Freeverb\";\n\n\t/**\n\t * The roomSize value between 0 and 1. A larger roomSize will result in a longer decay.\n\t */\n\treadonly roomSize: Signal<\"normalRange\">;\n\n\t/**\n\t * the comb filters\n\t */\n\tprivate _combFilters: LowpassCombFilter[] = [];\n\n\t/**\n\t * the allpass filters on the left\n\t */\n\tprivate _allpassFiltersL: BiquadFilterNode[] = [];\n\n\t/**\n\t * the allpass filters on the right\n\t */\n\tprivate _allpassFiltersR: BiquadFilterNode[] = [];\n\n\t/**\n\t * @param roomSize Correlated to the decay time.\n\t * @param dampening The cutoff frequency of a lowpass filter as part of the reverb.\n\t */\n\tconstructor(roomSize?: NormalRange, dampening?: Frequency);\n\tconstructor(options?: Partial<FreeverbOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tFreeverb.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"roomSize\", \"dampening\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.roomSize = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tvalue: options.roomSize,\n\t\t\tunits: \"normalRange\",\n\t\t});\n\n\t\t// make the allpass filters on the right\n\t\tthis._allpassFiltersL = allpassFilterFrequencies.map((freq) => {\n\t\t\tconst allpassL = this.context.createBiquadFilter();\n\t\t\tallpassL.type = \"allpass\";\n\t\t\tallpassL.frequency.value = freq;\n\t\t\treturn allpassL;\n\t\t});\n\n\t\t// make the allpass filters on the left\n\t\tthis._allpassFiltersR = allpassFilterFrequencies.map((freq) => {\n\t\t\tconst allpassR = this.context.createBiquadFilter();\n\t\t\tallpassR.type = \"allpass\";\n\t\t\tallpassR.frequency.value = freq;\n\t\t\treturn allpassR;\n\t\t});\n\n\t\t// make the comb filters\n\t\tthis._combFilters = combFilterTunings.map((delayTime, index) => {\n\t\t\tconst lfpf = new LowpassCombFilter({\n\t\t\t\tcontext: this.context,\n\t\t\t\tdampening: options.dampening,\n\t\t\t\tdelayTime,\n\t\t\t});\n\t\t\tif (index < combFilterTunings.length / 2) {\n\t\t\t\tthis.connectEffectLeft(lfpf, ...this._allpassFiltersL);\n\t\t\t} else {\n\t\t\t\tthis.connectEffectRight(lfpf, ...this._allpassFiltersR);\n\t\t\t}\n\t\t\tthis.roomSize.connect(lfpf.resonance);\n\t\t\treturn lfpf;\n\t\t});\n\n\t\treadOnly(this, [\"roomSize\"]);\n\t}\n\n\tstatic getDefaults(): FreeverbOptions {\n\t\treturn Object.assign(StereoEffect.getDefaults(), {\n\t\t\troomSize: 0.7,\n\t\t\tdampening: 3000,\n\t\t});\n\t}\n\n\t/**\n\t * The amount of dampening of the reverberant signal.\n\t */\n\n\tget dampening(): Frequency {\n\t\treturn this._combFilters[0].dampening;\n\t}\n\tset dampening(d) {\n\t\tthis._combFilters.forEach((c) => (c.dampening = d));\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._allpassFiltersL.forEach((al) => al.disconnect());\n\t\tthis._allpassFiltersR.forEach((ar) => ar.disconnect());\n\t\tthis._combFilters.forEach((cf) => cf.dispose());\n\t\tthis.roomSize.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/FrequencyShifter.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { EffectTests } from \"../../test/helper/EffectTests.js\";\nimport { Offline } from \"../../test/helper/Offline.js\";\nimport { Oscillator } from \"../source/oscillator/Oscillator.js\";\nimport { FrequencyShifter } from \"./FrequencyShifter.js\";\n\ndescribe(\"FrequencyShifter\", () => {\n\tBasicTests(FrequencyShifter);\n\tEffectTests(FrequencyShifter);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst shifter = new FrequencyShifter().toDestination();\n\t\t\t\tshifter.frequency.value = -60;\n\t\t\t\tconst osc = new Oscillator().connect(shifter);\n\t\t\t\tosc.start(0);\n\t\t\t},\n\t\t\t\"frequencyShifter.wav\",\n\t\t\t0.1\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst shifter = new FrequencyShifter({\n\t\t\t\tfrequency: -20,\n\t\t\t});\n\t\t\texpect(shifter.frequency.value).to.be.closeTo(-20, 0.001);\n\t\t\tshifter.dispose();\n\t\t});\n\n\t\tit(\"can get/set the options\", () => {\n\t\t\tconst shifter = new FrequencyShifter();\n\t\t\tshifter.set({\n\t\t\t\tfrequency: 40,\n\t\t\t});\n\t\t\texpect(shifter.get().frequency).to.be.closeTo(40, 0.001);\n\t\t\tshifter.dispose();\n\t\t});\n\n\t\tit(\"passes audio from input to output\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst osc = new Oscillator();\n\t\t\t\tosc.start(0).stop(0.1);\n\t\t\t\tconst shifter = new FrequencyShifter(0.2).toDestination();\n\t\t\t\tosc.connect(shifter);\n\t\t\t}, 0.3);\n\t\t\texpect(buffer.getRmsAtTime(0.05)).to.be.greaterThan(0);\n\t\t\texpect(buffer.getRmsAtTime(0.1)).to.be.greaterThan(0);\n\t\t\texpect(buffer.getRmsAtTime(0.2)).to.be.greaterThan(0);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/effect/FrequencyShifter.ts",
    "content": "import { PhaseShiftAllpass } from \"../component/filter/PhaseShiftAllpass.js\";\nimport { Frequency } from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { Effect, EffectOptions } from \"../effect/Effect.js\";\nimport { Add } from \"../signal/Add.js\";\nimport { Multiply } from \"../signal/Multiply.js\";\nimport { Negate } from \"../signal/Negate.js\";\nimport { Signal } from \"../signal/Signal.js\";\nimport { Oscillator } from \"../source/oscillator/Oscillator.js\";\nimport { ToneOscillatorNode } from \"../source/oscillator/ToneOscillatorNode.js\";\n\nexport interface FrequencyShifterOptions extends EffectOptions {\n\tfrequency: Frequency;\n}\n\n/**\n * FrequencyShifter can be used to shift all frequencies of a signal by a fixed amount.\n * The amount can be changed at audio rate and the effect is applied in real time.\n * The frequency shifting is implemented with a technique called single side band modulation using a ring modulator.\n * Note: Contrary to pitch shifting, all frequencies are shifted by the same amount,\n * destroying the harmonic relationship between them. This leads to the classic ring modulator timbre distortion.\n * The algorithm will produces some aliasing towards the high end, especially if your source material\n * contains a lot of high frequencies. Unfortunately the Web Audio API does not support resampling\n * buffers in real time, so it is not possible to fix it properly. Depending on the use case it might\n * be an option to low pass filter your input before frequency shifting it to get ride of the aliasing.\n * You can find a very detailed description of the algorithm here: https://larzeitlin.github.io/RMFS/\n *\n * @example\n * const input = new Tone.Oscillator(230, \"sawtooth\").start();\n * const shift = new Tone.FrequencyShifter(42).toDestination();\n * input.connect(shift);\n * @category Effect\n */\nexport class FrequencyShifter extends Effect<FrequencyShifterOptions> {\n\treadonly name: string = \"FrequencyShifter\";\n\n\t/**\n\t * The ring modulators carrier frequency. This frequency determines\n\t * by how many Hertz the input signal will be shifted up or down. Default is 0.\n\t */\n\treadonly frequency: Signal<\"frequency\">;\n\n\t/**\n\t * The ring modulators sine carrier\n\t */\n\tprivate _sine: ToneOscillatorNode;\n\n\t/**\n\t * The ring modulators cosine carrier\n\t */\n\tprivate _cosine: Oscillator;\n\n\t/**\n\t * The sine multiply operator\n\t */\n\tprivate _sineMultiply: Multiply;\n\n\t/**\n\t * The cosine multiply operator\n\t */\n\tprivate _cosineMultiply: Multiply;\n\n\t/**\n\t * The negate operator\n\t */\n\tprivate _negate: Negate;\n\n\t/**\n\t * The final add operator\n\t */\n\tprivate _add: Add;\n\n\t/**\n\t * The phase shifter to create the initial 90° phase offset\n\t */\n\tprivate _phaseShifter: PhaseShiftAllpass;\n\n\t/**\n\t * @param frequency The incoming signal is shifted by this frequency value.\n\t */\n\tconstructor(frequency?: Frequency);\n\tconstructor(options?: Partial<FrequencyShifterOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tFrequencyShifter.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"frequency\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.frequency = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"frequency\",\n\t\t\tvalue: options.frequency,\n\t\t\tminValue: -this.context.sampleRate / 2,\n\t\t\tmaxValue: this.context.sampleRate / 2,\n\t\t});\n\n\t\tthis._sine = new ToneOscillatorNode({\n\t\t\tcontext: this.context,\n\t\t\ttype: \"sine\",\n\t\t});\n\n\t\tthis._cosine = new Oscillator({\n\t\t\tcontext: this.context,\n\t\t\tphase: -90,\n\t\t\ttype: \"sine\",\n\t\t});\n\n\t\tthis._sineMultiply = new Multiply({ context: this.context });\n\t\tthis._cosineMultiply = new Multiply({ context: this.context });\n\t\tthis._negate = new Negate({ context: this.context });\n\t\tthis._add = new Add({ context: this.context });\n\n\t\tthis._phaseShifter = new PhaseShiftAllpass({ context: this.context });\n\t\tthis.effectSend.connect(this._phaseShifter);\n\n\t\t// connect the carrier frequency signal to the two oscillators\n\t\tthis.frequency.fan(this._sine.frequency, this._cosine.frequency);\n\n\t\tthis._phaseShifter.offset90.connect(this._cosineMultiply);\n\t\tthis._cosine.connect(this._cosineMultiply.factor);\n\n\t\tthis._phaseShifter.connect(this._sineMultiply);\n\t\tthis._sine.connect(this._sineMultiply.factor);\n\t\tthis._sineMultiply.connect(this._negate);\n\n\t\tthis._cosineMultiply.connect(this._add);\n\t\tthis._negate.connect(this._add.addend);\n\n\t\tthis._add.connect(this.effectReturn);\n\n\t\t// start the oscillators at the same time\n\t\tthis._onContextRunning(() => {\n\t\t\tconst now = this.immediate();\n\t\t\tthis._sine.start(now);\n\t\t\tthis._cosine.start(now);\n\t\t});\n\t}\n\n\tstatic getDefaults(): FrequencyShifterOptions {\n\t\treturn Object.assign(Effect.getDefaults(), {\n\t\t\tfrequency: 0,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.frequency.dispose();\n\t\tthis._add.dispose();\n\t\tthis._cosine.dispose();\n\t\tthis._cosineMultiply.dispose();\n\t\tthis._negate.dispose();\n\t\tthis._phaseShifter.dispose();\n\t\tthis._sine.dispose();\n\t\tthis._sineMultiply.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/JCReverb.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { EffectTests } from \"../../test/helper/EffectTests.js\";\nimport { Noise } from \"../source/Noise.js\";\nimport { JCReverb } from \"./JCReverb.js\";\n\ndescribe(\"JCReverb\", () => {\n\tBasicTests(JCReverb);\n\tEffectTests(JCReverb);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst reverb = new JCReverb().toDestination();\n\t\t\t\tconst noise = new Noise().connect(reverb);\n\t\t\t\tnoise.start(0).stop(0.1);\n\t\t\t},\n\t\t\t\"jcReverb.wav\",\n\t\t\t0.2\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst reverb = new JCReverb({\n\t\t\t\troomSize: 0.2,\n\t\t\t});\n\t\t\texpect(reverb.roomSize.value).to.be.closeTo(0.2, 0.01);\n\t\t\treverb.dispose();\n\t\t});\n\n\t\tit(\"can get/set the options\", () => {\n\t\t\tconst reverb = new JCReverb();\n\t\t\treverb.set({\n\t\t\t\troomSize: 0.23,\n\t\t\t});\n\t\t\texpect(reverb.get().roomSize).to.be.closeTo(0.23, 0.01);\n\t\t\treverb.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/effect/JCReverb.ts",
    "content": "import { FeedbackCombFilter } from \"../component/filter/FeedbackCombFilter.js\";\nimport { NormalRange } from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport { Scale } from \"../signal/Scale.js\";\nimport { Signal } from \"../signal/Signal.js\";\nimport { StereoEffect, StereoEffectOptions } from \"./StereoEffect.js\";\n\nexport interface JCReverbOptions extends StereoEffectOptions {\n\troomSize: NormalRange;\n}\n\n/**\n * an array of the comb filter delay time values\n */\nconst combFilterDelayTimes = [\n\t1687 / 25000,\n\t1601 / 25000,\n\t2053 / 25000,\n\t2251 / 25000,\n];\n\n/**\n * the resonances of each of the comb filters\n */\nconst combFilterResonances = [0.773, 0.802, 0.753, 0.733];\n\n/**\n * the allpass filter frequencies\n */\nconst allpassFilterFreqs = [347, 113, 37];\n\n/**\n * JCReverb is a simple [Schroeder Reverberator](https://ccrma.stanford.edu/~jos/pasp/Schroeder_Reverberators.html)\n * tuned by John Chowning in 1970.\n * It is made up of three allpass filters and four {@link FeedbackCombFilter}.\n * JCReverb is now implemented with an AudioWorkletNode which may result on performance degradation on some platforms. Consider using {@link Reverb}.\n * @example\n * const reverb = new Tone.JCReverb(0.4).toDestination();\n * const delay = new Tone.FeedbackDelay(0.5);\n * // connecting the synth to reverb through delay\n * const synth = new Tone.DuoSynth().chain(delay, reverb);\n * synth.triggerAttackRelease(\"A4\", \"8n\");\n *\n * @category Effect\n */\nexport class JCReverb extends StereoEffect<JCReverbOptions> {\n\treadonly name: string = \"JCReverb\";\n\n\t/**\n\t * Room size control values.\n\t */\n\treadonly roomSize: Signal<\"normalRange\">;\n\n\t/**\n\t * Scale the room size\n\t */\n\tprivate _scaleRoomSize: Scale;\n\n\t/**\n\t * a series of allpass filters\n\t */\n\tprivate _allpassFilters: BiquadFilterNode[] = [];\n\n\t/**\n\t * parallel feedback comb filters\n\t */\n\tprivate _feedbackCombFilters: FeedbackCombFilter[] = [];\n\n\t/**\n\t * @param roomSize Correlated to the decay time.\n\t */\n\tconstructor(roomSize?: NormalRange);\n\tconstructor(options?: Partial<JCReverbOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tJCReverb.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"roomSize\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.roomSize = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tvalue: options.roomSize,\n\t\t\tunits: \"normalRange\",\n\t\t});\n\t\tthis._scaleRoomSize = new Scale({\n\t\t\tcontext: this.context,\n\t\t\tmin: -0.733,\n\t\t\tmax: 0.197,\n\t\t});\n\n\t\t// make the allpass filters\n\t\tthis._allpassFilters = allpassFilterFreqs.map((freq) => {\n\t\t\tconst allpass = this.context.createBiquadFilter();\n\t\t\tallpass.type = \"allpass\";\n\t\t\tallpass.frequency.value = freq;\n\t\t\treturn allpass;\n\t\t});\n\n\t\t// and the comb filters\n\t\tthis._feedbackCombFilters = combFilterDelayTimes.map(\n\t\t\t(delayTime, index) => {\n\t\t\t\tconst fbcf = new FeedbackCombFilter({\n\t\t\t\t\tcontext: this.context,\n\t\t\t\t\tdelayTime,\n\t\t\t\t});\n\t\t\t\tthis._scaleRoomSize.connect(fbcf.resonance);\n\t\t\t\tfbcf.resonance.value = combFilterResonances[index];\n\t\t\t\tif (index < combFilterDelayTimes.length / 2) {\n\t\t\t\t\tthis.connectEffectLeft(...this._allpassFilters, fbcf);\n\t\t\t\t} else {\n\t\t\t\t\tthis.connectEffectRight(...this._allpassFilters, fbcf);\n\t\t\t\t}\n\t\t\t\treturn fbcf;\n\t\t\t}\n\t\t);\n\n\t\t// chain the allpass filters together\n\t\tthis.roomSize.connect(this._scaleRoomSize);\n\t\treadOnly(this, [\"roomSize\"]);\n\t}\n\n\tstatic getDefaults(): JCReverbOptions {\n\t\treturn Object.assign(StereoEffect.getDefaults(), {\n\t\t\troomSize: 0.5,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._allpassFilters.forEach((apf) => apf.disconnect());\n\t\tthis._feedbackCombFilters.forEach((fbcf) => fbcf.dispose());\n\t\tthis.roomSize.dispose();\n\t\tthis._scaleRoomSize.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/LFOEffect.ts",
    "content": "import { Param } from \"../core/context/Param.js\";\nimport { Frequency, NormalRange, Time } from \"../core/type/Units.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport { Effect, EffectOptions } from \"../effect/Effect.js\";\nimport { Signal } from \"../signal/Signal.js\";\nimport { LFO } from \"../source/oscillator/LFO.js\";\nimport { ToneOscillatorType } from \"../source/oscillator/OscillatorInterface.js\";\n\nexport interface LFOEffectOptions extends EffectOptions {\n\tfrequency: Frequency;\n\ttype: ToneOscillatorType;\n\tdepth: NormalRange;\n}\n\n/**\n * Base class for LFO-based effects.\n */\nexport abstract class LFOEffect<\n\tOptions extends LFOEffectOptions,\n> extends Effect<Options> {\n\treadonly name: string = \"LFOEffect\";\n\n\t/**\n\t * the lfo which drives the filter cutoff\n\t */\n\tprotected _lfo: LFO;\n\n\t/**\n\t * The range of the filter modulating between the min and max frequency.\n\t * 0 = no modulation. 1 = full modulation.\n\t */\n\treadonly depth: Param<\"normalRange\">;\n\n\t/**\n\t * How fast the filter modulates between min and max.\n\t */\n\treadonly frequency: Signal<\"frequency\">;\n\n\tconstructor(options: LFOEffectOptions) {\n\t\tsuper(options);\n\n\t\tthis._lfo = new LFO({\n\t\t\tcontext: this.context,\n\t\t\tfrequency: options.frequency,\n\t\t\tamplitude: options.depth,\n\t\t});\n\t\tthis.depth = this._lfo.amplitude;\n\t\tthis.frequency = this._lfo.frequency;\n\n\t\tthis.type = options.type;\n\t\treadOnly(this, [\"frequency\", \"depth\"]);\n\t}\n\n\tstatic getDefaults(): LFOEffectOptions {\n\t\treturn Object.assign(Effect.getDefaults(), {\n\t\t\tfrequency: 1,\n\t\t\ttype: \"sine\" as ToneOscillatorType,\n\t\t\tdepth: 1,\n\t\t});\n\t}\n\n\t/**\n\t * Start the effect.\n\t */\n\tstart(time?: Time): this {\n\t\tthis._lfo.start(time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop the lfo\n\t */\n\tstop(time?: Time): this {\n\t\tthis._lfo.stop(time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sync the filter to the transport.\n\t * @see {@link LFO.sync}\n\t */\n\tsync(): this {\n\t\tthis._lfo.sync();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Unsync the filter from the transport.\n\t */\n\tunsync(): this {\n\t\tthis._lfo.unsync();\n\t\treturn this;\n\t}\n\n\t/**\n\t * The type of the LFO's oscillator.\n\t * @see {@link Oscillator.type}\n\t * @example\n\t * const autoFilter = new Tone.AutoFilter().start().toDestination();\n\t * const noise = new Tone.Noise().start().connect(autoFilter);\n\t * autoFilter.type = \"square\";\n\t */\n\tget type() {\n\t\treturn this._lfo.type;\n\t}\n\tset type(type) {\n\t\tthis._lfo.type = type;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._lfo.dispose();\n\t\tthis.frequency.dispose();\n\t\tthis.depth.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/LFOStereoEffect.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { Offline } from \"../../test/helper/Offline.js\";\nimport { LFOStereoEffect, LFOStereoEffectOptions } from \"./LFOStereoEffect.js\";\n\ndescribe(\"LFOStereoEffect\", () => {\n\tclass LFOStereoEffectTest extends LFOStereoEffect<LFOStereoEffectOptions> {\n\t\tgetLfoState() {\n\t\t\treturn this._lfoL.state;\n\t\t}\n\t}\n\n\tBasicTests(LFOStereoEffectTest);\n\n\tcontext(\"API\", () => {\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst stereoEffect = new LFOStereoEffectTest({\n\t\t\t\tfrequency: 0.2,\n\t\t\t});\n\t\t\texpect(stereoEffect.frequency.value).to.be.closeTo(0.2, 0.01);\n\t\t\tstereoEffect.dispose();\n\t\t});\n\n\t\tit(\"can be started and stopped\", () => {\n\t\t\tconst stereoEffect = new LFOStereoEffectTest();\n\t\t\tstereoEffect.start().stop(\"+0.2\");\n\t\t\tstereoEffect.dispose();\n\t\t});\n\n\t\tit(\"can get/set the options\", () => {\n\t\t\tconst stereoEffect = new LFOStereoEffectTest();\n\t\t\tstereoEffect.set({\n\t\t\t\tfrequency: 2.4,\n\t\t\t});\n\t\t\texpect(stereoEffect.get().frequency).to.be.closeTo(2.4, 0.01);\n\t\t\tstereoEffect.dispose();\n\t\t});\n\n\t\tit(\"can set the frequency and depth\", () => {\n\t\t\tconst stereoEffect = new LFOStereoEffectTest();\n\t\t\tstereoEffect.frequency.value = 0.4;\n\t\t\texpect(stereoEffect.frequency.value).to.be.closeTo(0.4, 0.01);\n\t\t\tstereoEffect.dispose();\n\t\t});\n\n\t\tit(\"can sync the frequency to the transport\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst stereoEffect = new LFOStereoEffectTest({\n\t\t\t\t\tfrequency: 2,\n\t\t\t\t});\n\t\t\t\tstereoEffect.sync();\n\t\t\t\tstereoEffect.frequency.toDestination();\n\t\t\t\ttransport.bpm.setValueAtTime(transport.bpm.value * 2, 0.05);\n\t\t\t}, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(2, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.05)).to.be.closeTo(4, 0.1);\n\t\t});\n\n\t\tit(\"can unsync the frequency to the transport\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst stereoEffect = new LFOStereoEffectTest({\n\t\t\t\t\tfrequency: 2,\n\t\t\t\t});\n\t\t\t\tstereoEffect.sync();\n\t\t\t\tstereoEffect.frequency.toDestination();\n\t\t\t\ttransport.bpm.setValueAtTime(transport.bpm.value * 2, 0.05);\n\t\t\t\tstereoEffect.unsync();\n\t\t\t}, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(2, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.05)).to.be.closeTo(2, 0.1);\n\t\t});\n\n\t\tit(\"autostart the LFO\", () => {\n\t\t\tconst stereoEffect = new LFOStereoEffectTest({\n\t\t\t\tfrequency: 0.2,\n\t\t\t\tautostart: true,\n\t\t\t});\n\t\t\texpect(stereoEffect.frequency.value).to.be.closeTo(0.2, 0.01);\n\n\t\t\texpect(stereoEffect.getLfoState()).to.equal(\"started\");\n\t\t\tstereoEffect.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/effect/LFOStereoEffect.ts",
    "content": "import { Frequency, Time } from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport { Signal } from \"../signal/Signal.js\";\nimport { LFO } from \"../source/oscillator/LFO.js\";\nimport { ToneOscillatorType } from \"../source/oscillator/OscillatorInterface.js\";\nimport { StereoEffect, StereoEffectOptions } from \"./StereoEffect.js\";\n\nexport interface LFOStereoEffectOptions extends StereoEffectOptions {\n\tfrequency: Frequency;\n\tautostart: boolean;\n}\n\n/**\n * Base class for stereo effects which modulate the incoming signal with an LFO.\n *\n * @category Effect\n */\nexport abstract class LFOStereoEffect<\n\tOptions extends LFOStereoEffectOptions,\n> extends StereoEffect<Options> {\n\treadonly name: string = \"LFOStereoEffect\";\n\n\t/**\n\t * The LFO in the left channel\n\t */\n\tprotected _lfoL: LFO;\n\n\t/**\n\t * The LFO in the right channel\n\t */\n\tprotected _lfoR: LFO;\n\n\t/**\n\t * The frequency of the tremolo.\n\t */\n\treadonly frequency: Signal<\"frequency\">;\n\n\tconstructor(options?: Partial<LFOStereoEffectOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tLFOStereoEffect.getDefaults(),\n\t\t\targuments\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._lfoL = new LFO({\n\t\t\tcontext: this.context,\n\t\t\tmin: 0,\n\t\t\tmax: 1,\n\t\t});\n\t\tthis._lfoR = new LFO({\n\t\t\tcontext: this.context,\n\t\t\tmin: 0,\n\t\t\tmax: 1,\n\t\t});\n\n\t\t// control the frequency with a single signal\n\t\tthis.frequency = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tvalue: options.frequency,\n\t\t\tunits: \"frequency\",\n\t\t});\n\t\tthis.frequency.fan(this._lfoL.frequency, this._lfoR.frequency);\n\n\t\treadOnly(this, [\"frequency\"]);\n\n\t\tif (options.autostart) {\n\t\t\tthis._onContextRunning(() => this.start(this.immediate()));\n\t\t}\n\t}\n\n\tstatic getDefaults(): LFOStereoEffectOptions {\n\t\treturn Object.assign(StereoEffect.getDefaults(), {\n\t\t\tfrequency: 10,\n\t\t\tautostart: false,\n\t\t});\n\t}\n\n\t/**\n\t * Start the tremolo.\n\t */\n\tstart(time?: Time): this {\n\t\tthis._lfoL.start(time);\n\t\tthis._lfoR.start(time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop the tremolo.\n\t */\n\tstop(time?: Time): this {\n\t\tthis._lfoL.stop(time);\n\t\tthis._lfoR.stop(time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sync the effect to the transport.\n\t */\n\tsync(): this {\n\t\tthis._lfoL.sync();\n\t\tthis._lfoR.sync();\n\t\tthis.context.transport.syncSignal(this.frequency);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Unsync the filter from the transport\n\t */\n\tunsync(): this {\n\t\tthis._lfoL.unsync();\n\t\tthis._lfoR.unsync();\n\t\tthis.context.transport.unsyncSignal(this.frequency);\n\t\treturn this;\n\t}\n\n\t/**\n\t * The oscillator type.\n\t */\n\tget type(): ToneOscillatorType {\n\t\treturn this._lfoL.type;\n\t}\n\tset type(type) {\n\t\tthis._lfoL.type = type;\n\t\tthis._lfoR.type = type;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._lfoL.dispose();\n\t\tthis._lfoR.dispose();\n\t\tthis.frequency.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/MidSideEffect.ts",
    "content": "import { MidSideMerge } from \"../component/channel/MidSideMerge.js\";\nimport { MidSideSplit } from \"../component/channel/MidSideSplit.js\";\nimport { OutputNode, ToneAudioNode } from \"../core/context/ToneAudioNode.js\";\nimport { Effect, EffectOptions } from \"./Effect.js\";\n\nexport type MidSideEffectOptions = EffectOptions;\n\n/**\n * Mid/Side processing separates the the 'mid' signal\n * (which comes out of both the left and the right channel)\n * and the 'side' (which only comes out of the the side channels)\n * and effects them separately before being recombined.\n * Applies a Mid/Side separation and recombination.\n * Algorithm found in [kvraudio forums](http://www.kvraudio.com/forum/viewtopic.php?t=212587).\n * This is a base-class for Mid/Side Effects.\n * @category Effect\n */\nexport abstract class MidSideEffect<\n\tOptions extends MidSideEffectOptions,\n> extends Effect<Options> {\n\treadonly name: string = \"MidSideEffect\";\n\n\t/**\n\t * The mid/side split\n\t */\n\tprivate _midSideSplit: MidSideSplit;\n\n\t/**\n\t * The mid/side merge\n\t */\n\tprivate _midSideMerge: MidSideMerge;\n\n\t/**\n\t * The mid send. Connect to mid processing\n\t */\n\tprotected _midSend: ToneAudioNode;\n\n\t/**\n\t * The side send. Connect to side processing\n\t */\n\tprotected _sideSend: ToneAudioNode;\n\n\t/**\n\t * The mid return connection\n\t */\n\tprotected _midReturn: ToneAudioNode;\n\n\t/**\n\t * The side return connection\n\t */\n\tprotected _sideReturn: ToneAudioNode;\n\n\tconstructor(options: MidSideEffectOptions) {\n\t\tsuper(options);\n\n\t\tthis._midSideMerge = new MidSideMerge({ context: this.context });\n\t\tthis._midSideSplit = new MidSideSplit({ context: this.context });\n\t\tthis._midSend = this._midSideSplit.mid;\n\t\tthis._sideSend = this._midSideSplit.side;\n\t\tthis._midReturn = this._midSideMerge.mid;\n\t\tthis._sideReturn = this._midSideMerge.side;\n\n\t\t// the connections\n\t\tthis.effectSend.connect(this._midSideSplit);\n\t\tthis._midSideMerge.connect(this.effectReturn);\n\t}\n\n\t/**\n\t * Connect the mid chain of the effect\n\t */\n\tprotected connectEffectMid(...nodes: OutputNode[]): void {\n\t\tthis._midSend.chain(...nodes, this._midReturn);\n\t}\n\n\t/**\n\t * Connect the side chain of the effect\n\t */\n\tprotected connectEffectSide(...nodes: OutputNode[]): void {\n\t\tthis._sideSend.chain(...nodes, this._sideReturn);\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._midSideSplit.dispose();\n\t\tthis._midSideMerge.dispose();\n\t\tthis._midSend.dispose();\n\t\tthis._sideSend.dispose();\n\t\tthis._midReturn.dispose();\n\t\tthis._sideReturn.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/Phaser.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { EffectTests } from \"../../test/helper/EffectTests.js\";\nimport { ToneAudioBuffer } from \"../core/index.js\";\nimport { Player } from \"../source/buffer/Player.js\";\nimport { Phaser } from \"./Phaser.js\";\n\ndescribe(\"Phaser\", () => {\n\tBasicTests(Phaser);\n\tEffectTests(Phaser);\n\n\tit(\"matches a file basic\", async () => {\n\t\tconst buffer = await ToneAudioBuffer.fromUrl(\"./test/audio/FWDL.wav\");\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst phaser = new Phaser(2, 6, 200).toDestination();\n\t\t\t\tconst player = new Player(buffer).connect(phaser).start();\n\t\t\t},\n\t\t\t\"phaser.wav\",\n\t\t\t0.1\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst phaser = new Phaser({\n\t\t\t\tfrequency: 0.2,\n\t\t\t});\n\t\t\texpect(phaser.frequency.value).to.be.closeTo(0.2, 0.01);\n\t\t\tphaser.dispose();\n\t\t});\n\n\t\tit(\"can get/set the options\", () => {\n\t\t\tconst phaser = new Phaser();\n\t\t\tphaser.set({\n\t\t\t\toctaves: 0.21,\n\t\t\t\tbaseFrequency: 300,\n\t\t\t});\n\t\t\texpect(phaser.get().baseFrequency).to.be.closeTo(300, 0.01);\n\t\t\texpect(phaser.get().octaves).to.be.closeTo(0.21, 0.01);\n\t\t\tphaser.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/effect/Phaser.ts",
    "content": "import { Frequency, Hertz, Positive } from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport { Signal } from \"../signal/Signal.js\";\nimport { LFO } from \"../source/oscillator/LFO.js\";\nimport { LFOStereoEffect, LFOStereoEffectOptions } from \"./LFOStereoEffect.js\";\n\nexport interface PhaserOptions extends LFOStereoEffectOptions {\n\toctaves: Positive;\n\tstages: Positive;\n\tQ: Positive;\n\tbaseFrequency: Frequency;\n}\n\n/**\n * Phaser is a phaser effect. Phasers work by changing the phase\n * of different frequency components of an incoming signal. Read more on\n * [Wikipedia](https://en.wikipedia.org/wiki/Phaser_(effect)).\n * Inspiration for this phaser comes from [Tuna.js](https://github.com/Dinahmoe/tuna/).\n * @example\n * const phaser = new Tone.Phaser({\n * \tfrequency: 15,\n * \toctaves: 5,\n * \tbaseFrequency: 1000\n * }).toDestination();\n * const synth = new Tone.FMSynth().connect(phaser);\n * synth.triggerAttackRelease(\"E3\", \"2n\");\n * @category Effect\n */\nexport class Phaser extends LFOStereoEffect<PhaserOptions> {\n\treadonly name: string = \"Phaser\";\n\n\t/**\n\t * the base modulation frequency\n\t */\n\tprivate _baseFrequency: Hertz;\n\n\t/**\n\t * the octaves of the phasing\n\t */\n\tprivate _octaves: Positive;\n\n\t/**\n\t * The quality factor of the filters\n\t */\n\treadonly Q: Signal<\"positive\">;\n\n\t/**\n\t * the array of filters for the left side\n\t */\n\tprivate _filtersL: BiquadFilterNode[];\n\n\t/**\n\t * the array of filters for the left side\n\t */\n\tprivate _filtersR: BiquadFilterNode[];\n\n\t/**\n\t * @param frequency The speed of the phasing.\n\t * @param octaves The octaves of the effect.\n\t * @param baseFrequency The base frequency of the filters.\n\t */\n\tconstructor(\n\t\tfrequency?: Frequency,\n\t\toctaves?: Positive,\n\t\tbaseFrequency?: Frequency\n\t);\n\tconstructor(options?: Partial<PhaserOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Phaser.getDefaults(), arguments, [\n\t\t\t\"frequency\",\n\t\t\t\"octaves\",\n\t\t\t\"baseFrequency\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis._lfoR.phase = 180;\n\n\t\tthis._baseFrequency = this.toFrequency(options.baseFrequency);\n\t\tthis._octaves = options.octaves;\n\t\tthis.Q = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tvalue: options.Q,\n\t\t\tunits: \"positive\",\n\t\t});\n\t\tthis._filtersL = this._makeFilters(options.stages, this._lfoL);\n\t\tthis._filtersR = this._makeFilters(options.stages, this._lfoR);\n\n\t\t// connect them up\n\t\tthis.connectEffectLeft(...this._filtersL);\n\t\tthis.connectEffectRight(...this._filtersR);\n\n\t\t// set the options\n\t\tthis.baseFrequency = options.baseFrequency;\n\t\tthis.octaves = options.octaves;\n\t\treadOnly(this, [\"Q\"]);\n\t}\n\n\tstatic getDefaults(): PhaserOptions {\n\t\treturn Object.assign(LFOStereoEffect.getDefaults(), {\n\t\t\tfrequency: 0.5,\n\t\t\toctaves: 3,\n\t\t\tstages: 10,\n\t\t\tQ: 10,\n\t\t\tbaseFrequency: 350,\n\t\t\tautostart: true,\n\t\t});\n\t}\n\n\tprivate _makeFilters(\n\t\tstages: number,\n\t\tconnectToFreq: LFO\n\t): BiquadFilterNode[] {\n\t\tconst filters: BiquadFilterNode[] = [];\n\t\t// make all the filters\n\t\tfor (let i = 0; i < stages; i++) {\n\t\t\tconst filter = this.context.createBiquadFilter();\n\t\t\tfilter.type = \"allpass\";\n\t\t\tthis.Q.connect(filter.Q);\n\t\t\tconnectToFreq.connect(filter.frequency);\n\t\t\tfilters.push(filter);\n\t\t}\n\t\treturn filters;\n\t}\n\n\t/**\n\t * The number of octaves the phase goes above the baseFrequency\n\t */\n\tget octaves() {\n\t\treturn this._octaves;\n\t}\n\tset octaves(octaves) {\n\t\tthis._octaves = octaves;\n\t\tconst max = this._baseFrequency * Math.pow(2, octaves);\n\t\tthis._lfoL.max = max;\n\t\tthis._lfoR.max = max;\n\t}\n\n\t/**\n\t * The the base frequency of the filters.\n\t */\n\tget baseFrequency(): Frequency {\n\t\treturn this._baseFrequency;\n\t}\n\tset baseFrequency(freq) {\n\t\tthis._baseFrequency = this.toFrequency(freq);\n\t\tthis._lfoL.min = this._baseFrequency;\n\t\tthis._lfoR.min = this._baseFrequency;\n\t\tthis.octaves = this._octaves;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.Q.dispose();\n\t\tthis._filtersL.forEach((f) => f.disconnect());\n\t\tthis._filtersR.forEach((f) => f.disconnect());\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/PingPongDelay.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { EffectTests } from \"../../test/helper/EffectTests.js\";\nimport { Oscillator } from \"../source/oscillator/Oscillator.js\";\nimport { PingPongDelay } from \"./PingPongDelay.js\";\n\ndescribe(\"PingPongDelay\", () => {\n\tBasicTests(PingPongDelay);\n\tEffectTests(PingPongDelay, 0.01);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst delay = new PingPongDelay(0.2, 0.8).toDestination();\n\t\t\t\tconst pulse = new Oscillator().connect(delay);\n\t\t\t\tpulse.start(0).stop(0.1);\n\t\t\t},\n\t\t\t\"pingPongDelay.wav\",\n\t\t\t0.2\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst pingPong = new PingPongDelay({\n\t\t\t\tdelayTime: 0.2,\n\t\t\t});\n\t\t\texpect(pingPong.delayTime.value).to.be.closeTo(0.2, 0.01);\n\t\t\tpingPong.dispose();\n\t\t});\n\n\t\tit(\"can get/set the options\", () => {\n\t\t\tconst pingPong = new PingPongDelay();\n\t\t\tpingPong.set({\n\t\t\t\tdelayTime: 0.21,\n\t\t\t});\n\t\t\texpect(pingPong.get().delayTime).to.be.closeTo(0.21, 0.01);\n\t\t\tpingPong.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/effect/PingPongDelay.ts",
    "content": "import { Delay } from \"../core/context/Delay.js\";\nimport { NormalRange, Seconds, Time } from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport { Signal } from \"../signal/Signal.js\";\nimport {\n\tStereoXFeedbackEffect,\n\tStereoXFeedbackEffectOptions,\n} from \"./StereoXFeedbackEffect.js\";\n\nexport interface PingPongDelayOptions extends StereoXFeedbackEffectOptions {\n\tdelayTime: Time;\n\tmaxDelay: Seconds;\n}\n\n/**\n * PingPongDelay is a feedback delay effect where the echo is heard\n * first in one channel and next in the opposite channel. In a stereo\n * system these are the right and left channels.\n * PingPongDelay in more simplified terms is two Tone.FeedbackDelays\n * with independent delay values. Each delay is routed to one channel\n * (left or right), and the channel triggered second will always\n * trigger at the same interval after the first.\n * @example\n * const pingPong = new Tone.PingPongDelay(\"4n\", 0.2).toDestination();\n * const drum = new Tone.MembraneSynth().connect(pingPong);\n * drum.triggerAttackRelease(\"C4\", \"32n\");\n * @category Effect\n */\nexport class PingPongDelay extends StereoXFeedbackEffect<PingPongDelayOptions> {\n\treadonly name: string = \"PingPongDelay\";\n\n\t/**\n\t * the delay node on the left side\n\t */\n\tprivate _leftDelay: Delay;\n\n\t/**\n\t * the delay node on the right side\n\t */\n\tprivate _rightDelay: Delay;\n\n\t/**\n\t * the predelay on the right side\n\t */\n\tprivate _rightPreDelay: Delay;\n\n\t/**\n\t * the delay time signal\n\t */\n\treadonly delayTime: Signal<\"time\">;\n\n\t/**\n\t * @param delayTime The delayTime between consecutive echos.\n\t * @param feedback The amount of the effected signal which is fed back through the delay.\n\t */\n\tconstructor(delayTime?: Time, feedback?: NormalRange);\n\tconstructor(options?: Partial<PingPongDelayOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tPingPongDelay.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"delayTime\", \"feedback\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._leftDelay = new Delay({\n\t\t\tcontext: this.context,\n\t\t\tmaxDelay: options.maxDelay,\n\t\t});\n\t\tthis._rightDelay = new Delay({\n\t\t\tcontext: this.context,\n\t\t\tmaxDelay: options.maxDelay,\n\t\t});\n\t\tthis._rightPreDelay = new Delay({\n\t\t\tcontext: this.context,\n\t\t\tmaxDelay: options.maxDelay,\n\t\t});\n\t\tthis.delayTime = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"time\",\n\t\t\tvalue: options.delayTime,\n\t\t});\n\n\t\t// connect it up\n\t\tthis.connectEffectLeft(this._leftDelay);\n\t\tthis.connectEffectRight(this._rightPreDelay, this._rightDelay);\n\t\tthis.delayTime.fan(\n\t\t\tthis._leftDelay.delayTime,\n\t\t\tthis._rightDelay.delayTime,\n\t\t\tthis._rightPreDelay.delayTime\n\t\t);\n\t\t// rearranged the feedback to be after the rightPreDelay\n\t\tthis._feedbackL.disconnect();\n\t\tthis._feedbackL.connect(this._rightDelay);\n\t\treadOnly(this, [\"delayTime\"]);\n\t}\n\n\tstatic getDefaults(): PingPongDelayOptions {\n\t\treturn Object.assign(StereoXFeedbackEffect.getDefaults(), {\n\t\t\tdelayTime: 0.25,\n\t\t\tmaxDelay: 1,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._leftDelay.dispose();\n\t\tthis._rightDelay.dispose();\n\t\tthis._rightPreDelay.dispose();\n\t\tthis.delayTime.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/PitchShift.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { EffectTests } from \"../../test/helper/EffectTests.js\";\nimport { Oscillator } from \"../source/oscillator/Oscillator.js\";\nimport { PitchShift } from \"./PitchShift.js\";\n\ndescribe(\"PitchShift\", () => {\n\tBasicTests(PitchShift);\n\tEffectTests(PitchShift);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst pitchShift = new PitchShift(4).toDestination();\n\t\t\t\tconst osc = new Oscillator()\n\t\t\t\t\t.toDestination()\n\t\t\t\t\t.connect(pitchShift);\n\t\t\t\tosc.start(0);\n\t\t\t},\n\t\t\t\"pitchShift.wav\",\n\t\t\t0.3\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst pitchShift = new PitchShift({\n\t\t\t\twindowSize: 0.2,\n\t\t\t\tpitch: 2,\n\t\t\t});\n\t\t\texpect(pitchShift.windowSize).to.be.closeTo(0.2, 0.01);\n\t\t\texpect(pitchShift.pitch).to.be.closeTo(2, 0.01);\n\t\t\tpitchShift.dispose();\n\t\t});\n\n\t\tit(\"can set positive and negative pitches\", () => {\n\t\t\tconst pitchShift = new PitchShift();\n\t\t\tpitchShift.pitch = 2;\n\t\t\texpect(pitchShift.pitch).to.be.equal(2);\n\t\t\tpitchShift.pitch = -2;\n\t\t\texpect(pitchShift.pitch).to.be.equal(-2);\n\t\t\tpitchShift.pitch = -4.5;\n\t\t\texpect(pitchShift.pitch).to.be.equal(-4.5);\n\t\t\tpitchShift.dispose();\n\t\t});\n\n\t\tit(\"can get/set the options\", () => {\n\t\t\tconst pitchShift = new PitchShift();\n\t\t\tpitchShift.set({\n\t\t\t\twindowSize: 0.4,\n\t\t\t});\n\t\t\texpect(pitchShift.get().windowSize).to.be.closeTo(0.4, 0.01);\n\t\t\tpitchShift.dispose();\n\t\t});\n\n\t\tit(\"can set set the feedback and delay times\", () => {\n\t\t\tconst pitchShift = new PitchShift({\n\t\t\t\tdelayTime: \"4n\",\n\t\t\t\tfeedback: 0.3,\n\t\t\t});\n\t\t\texpect(pitchShift.delayTime.value).to.be.closeTo(\n\t\t\t\tpitchShift.toSeconds(\"4n\"),\n\t\t\t\t0.01\n\t\t\t);\n\t\t\texpect(pitchShift.feedback.value).to.be.closeTo(0.3, 0.01);\n\t\t\tpitchShift.delayTime.value = 0.2;\n\t\t\texpect(pitchShift.delayTime.value).to.be.closeTo(0.2, 0.01);\n\t\t\tpitchShift.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/effect/PitchShift.ts",
    "content": "import { CrossFade } from \"../component/channel/CrossFade.js\";\nimport { Delay } from \"../core/context/Delay.js\";\nimport { Param } from \"../core/context/Param.js\";\nimport { intervalToFrequencyRatio } from \"../core/type/Conversions.js\";\nimport { Interval, Seconds, Time } from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport { Signal } from \"../signal/Signal.js\";\nimport { LFO } from \"../source/oscillator/LFO.js\";\nimport { FeedbackEffect, FeedbackEffectOptions } from \"./FeedbackEffect.js\";\n\nexport interface PitchShiftOptions extends FeedbackEffectOptions {\n\tpitch: Interval;\n\twindowSize: Seconds;\n\tdelayTime: Time;\n}\n\n/**\n * PitchShift does near-realtime pitch shifting to the incoming signal.\n * The effect is achieved by speeding up or slowing down the delayTime\n * of a DelayNode using a sawtooth wave.\n * Algorithm found in [this pdf](http://dsp-book.narod.ru/soundproc.pdf).\n * Additional reference by [Miller Pucket](http://msp.ucsd.edu/techniques/v0.11/book-html/node115.html).\n * @category Effect\n */\nexport class PitchShift extends FeedbackEffect<PitchShiftOptions> {\n\treadonly name: string = \"PitchShift\";\n\n\t/**\n\t * The pitch signal\n\t */\n\tprivate _frequency: Signal<\"frequency\">;\n\n\t/**\n\t * Uses two DelayNodes to cover up the jump in the sawtooth wave.\n\t */\n\tprivate _delayA: Delay;\n\n\t/**\n\t * The first LFO.\n\t */\n\tprivate _lfoA: LFO;\n\n\t/**\n\t * The second DelayNode\n\t */\n\tprivate _delayB: Delay;\n\n\t/**\n\t * The second LFO.\n\t */\n\tprivate _lfoB: LFO;\n\n\t/**\n\t * Cross fade quickly between the two delay lines to cover up the jump in the sawtooth wave\n\t */\n\tprivate _crossFade: CrossFade;\n\n\t/**\n\t * LFO which alternates between the two delay lines to cover up the disparity in the\n\t * sawtooth wave.\n\t */\n\tprivate _crossFadeLFO: LFO;\n\n\t/**\n\t * The delay node\n\t */\n\tprivate _feedbackDelay: Delay;\n\n\t/**\n\t * The amount of delay on the input signal\n\t */\n\treadonly delayTime: Param<\"time\">;\n\n\t/**\n\t * Hold the current pitch\n\t */\n\tprivate _pitch: Interval;\n\n\t/**\n\t * Hold the current windowSize\n\t */\n\tprivate _windowSize;\n\n\t/**\n\t * @param pitch The interval to transpose the incoming signal by.\n\t */\n\tconstructor(pitch?: Interval);\n\tconstructor(options?: Partial<PitchShiftOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tPitchShift.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"pitch\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._frequency = new Signal({ context: this.context });\n\t\tthis._delayA = new Delay({\n\t\t\tmaxDelay: 1,\n\t\t\tcontext: this.context,\n\t\t});\n\t\tthis._lfoA = new LFO({\n\t\t\tcontext: this.context,\n\t\t\tmin: 0,\n\t\t\tmax: 0.1,\n\t\t\ttype: \"sawtooth\",\n\t\t}).connect(this._delayA.delayTime);\n\t\tthis._delayB = new Delay({\n\t\t\tmaxDelay: 1,\n\t\t\tcontext: this.context,\n\t\t});\n\t\tthis._lfoB = new LFO({\n\t\t\tcontext: this.context,\n\t\t\tmin: 0,\n\t\t\tmax: 0.1,\n\t\t\ttype: \"sawtooth\",\n\t\t\tphase: 180,\n\t\t}).connect(this._delayB.delayTime);\n\t\tthis._crossFade = new CrossFade({ context: this.context });\n\t\tthis._crossFadeLFO = new LFO({\n\t\t\tcontext: this.context,\n\t\t\tmin: 0,\n\t\t\tmax: 1,\n\t\t\ttype: \"triangle\",\n\t\t\tphase: 90,\n\t\t}).connect(this._crossFade.fade);\n\t\tthis._feedbackDelay = new Delay({\n\t\t\tdelayTime: options.delayTime,\n\t\t\tcontext: this.context,\n\t\t});\n\t\tthis.delayTime = this._feedbackDelay.delayTime;\n\t\treadOnly(this, \"delayTime\");\n\t\tthis._pitch = options.pitch;\n\n\t\tthis._windowSize = options.windowSize;\n\n\t\t// connect the two delay lines up\n\t\tthis._delayA.connect(this._crossFade.a);\n\t\tthis._delayB.connect(this._crossFade.b);\n\t\t// connect the frequency\n\t\tthis._frequency.fan(\n\t\t\tthis._lfoA.frequency,\n\t\t\tthis._lfoB.frequency,\n\t\t\tthis._crossFadeLFO.frequency\n\t\t);\n\t\t// route the input\n\t\tthis.effectSend.fan(this._delayA, this._delayB);\n\t\tthis._crossFade.chain(this._feedbackDelay, this.effectReturn);\n\t\t// set the initial value\n\t\tthis.windowSize = this._windowSize;\n\n\t\t// start the LFOs at the same time\n\t\tthis._onContextRunning(() => {\n\t\t\tconst now = this.immediate();\n\t\t\tthis._lfoA.start(now);\n\t\t\tthis._lfoB.start(now);\n\t\t\tthis._crossFadeLFO.start(now);\n\t\t});\n\t}\n\n\tstatic getDefaults(): PitchShiftOptions {\n\t\treturn Object.assign(FeedbackEffect.getDefaults(), {\n\t\t\tpitch: 0,\n\t\t\twindowSize: 0.1,\n\t\t\tdelayTime: 0,\n\t\t\tfeedback: 0,\n\t\t});\n\t}\n\n\t/**\n\t * Repitch the incoming signal by some interval (measured in semi-tones).\n\t * @example\n\t * const pitchShift = new Tone.PitchShift().toDestination();\n\t * const osc = new Tone.Oscillator().connect(pitchShift).start().toDestination();\n\t * pitchShift.pitch = -12; // down one octave\n\t * pitchShift.pitch = 7; // up a fifth\n\t */\n\tget pitch() {\n\t\treturn this._pitch;\n\t}\n\tset pitch(interval) {\n\t\tthis._pitch = interval;\n\t\tlet factor = 0;\n\t\tif (interval < 0) {\n\t\t\tthis._lfoA.min = 0;\n\t\t\tthis._lfoA.max = this._windowSize;\n\t\t\tthis._lfoB.min = 0;\n\t\t\tthis._lfoB.max = this._windowSize;\n\t\t\tfactor = intervalToFrequencyRatio(interval - 1) + 1;\n\t\t} else {\n\t\t\tthis._lfoA.min = this._windowSize;\n\t\t\tthis._lfoA.max = 0;\n\t\t\tthis._lfoB.min = this._windowSize;\n\t\t\tthis._lfoB.max = 0;\n\t\t\tfactor = intervalToFrequencyRatio(interval) - 1;\n\t\t}\n\t\tthis._frequency.value = factor * (1.2 / this._windowSize);\n\t}\n\n\t/**\n\t * The window size corresponds roughly to the sample length in a looping sampler.\n\t * Smaller values are desirable for a less noticeable delay time of the pitch shifted\n\t * signal, but larger values will result in smoother pitch shifting for larger intervals.\n\t * A nominal range of 0.03 to 0.1 is recommended.\n\t */\n\tget windowSize(): Seconds {\n\t\treturn this._windowSize;\n\t}\n\tset windowSize(size) {\n\t\tthis._windowSize = this.toSeconds(size);\n\t\tthis.pitch = this._pitch;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._frequency.dispose();\n\t\tthis._delayA.dispose();\n\t\tthis._delayB.dispose();\n\t\tthis._lfoA.dispose();\n\t\tthis._lfoB.dispose();\n\t\tthis._crossFade.dispose();\n\t\tthis._crossFadeLFO.dispose();\n\t\tthis._feedbackDelay.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/Reverb.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { Offline } from \"../../test/helper/Offline.js\";\nimport { Oscillator } from \"../source/oscillator/Oscillator.js\";\nimport { Reverb } from \"./Reverb.js\";\n\ndescribe(\"Reverb\", () => {\n\tBasicTests(Reverb);\n\n\tcontext(\"API\", () => {\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst reverb = new Reverb({\n\t\t\t\tdecay: 2,\n\t\t\t\tpreDelay: 0.1,\n\t\t\t});\n\t\t\texpect(reverb.decay).to.be.closeTo(2, 0.001);\n\t\t\texpect(reverb.preDelay).to.be.closeTo(0.1, 0.001);\n\t\t\treverb.dispose();\n\t\t});\n\n\t\tit(\"can get/set values\", () => {\n\t\t\tconst reverb = new Reverb();\n\t\t\treverb.decay = 0.5;\n\t\t\texpect(reverb.decay).to.be.closeTo(0.5, 0.001);\n\t\t\treverb.preDelay = 0.05;\n\t\t\texpect(reverb.preDelay).to.be.closeTo(0.05, 0.001);\n\t\t\treverb.dispose();\n\t\t});\n\n\t\tit(\"can get/set the options\", () => {\n\t\t\tconst reverb = new Reverb();\n\t\t\treverb.set({\n\t\t\t\tdecay: 0.4,\n\t\t\t});\n\t\t\texpect(reverb.get().decay).to.be.closeTo(0.4, 0.001);\n\t\t\treverb.dispose();\n\t\t});\n\n\t\tit(\"can generate an IR\", async () => {\n\t\t\tconst reverb = new Reverb();\n\t\t\tconst promise = reverb.generate();\n\t\t\texpect(promise).to.have.property(\"then\");\n\t\t\tawait promise;\n\t\t\treverb.dispose();\n\t\t});\n\n\t\tit.skip(\"is silent before the reverb is generated\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst osc = new Oscillator();\n\t\t\t\tosc.start(0).stop(0.1);\n\t\t\t\tconst reverb = new Reverb(0.2).toDestination();\n\t\t\t\tosc.connect(reverb);\n\t\t\t});\n\t\t\texpect(buffer.isSilent()).to.be.true;\n\t\t});\n\n\t\tit(\"passes audio from input to output\", async () => {\n\t\t\tconst buffer = await Offline(async () => {\n\t\t\t\tconst osc = new Oscillator();\n\t\t\t\tosc.start(0).stop(0.1);\n\t\t\t\tconst reverb = new Reverb(0.2).toDestination();\n\t\t\t\tosc.connect(reverb);\n\t\t\t\tawait reverb.ready;\n\t\t\t}, 0.3);\n\t\t\texpect(buffer.getRmsAtTime(0.05)).to.be.greaterThan(0);\n\t\t\texpect(buffer.getRmsAtTime(0.1)).to.be.greaterThan(0);\n\t\t\texpect(buffer.getRmsAtTime(0.2)).to.be.greaterThan(0);\n\t\t});\n\n\t\tit(\"parses number from string in input\", () => {\n\t\t\t// @ts-ignore\n\t\t\tconst reverb = new Reverb(\"1\");\n\t\t\texpect(reverb.decay).to.equal(1);\n\t\t\treverb.dispose();\n\t\t});\n\n\t\tit(\"throws an error with invalid input\", () => {\n\t\t\texpect(\n\t\t\t\t() =>\n\t\t\t\t\tnew Reverb({\n\t\t\t\t\t\tdecay: 0,\n\t\t\t\t\t\tpreDelay: -1,\n\t\t\t\t\t})\n\t\t\t).to.throw(Error);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/effect/Reverb.ts",
    "content": "import { Merge } from \"../component/channel/Merge.js\";\nimport { Gain } from \"../core/context/Gain.js\";\nimport { OfflineContext } from \"../core/context/OfflineContext.js\";\nimport { Seconds, Time } from \"../core/type/Units.js\";\nimport { assertRange } from \"../core/util/Debug.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { noOp } from \"../core/util/Interface.js\";\nimport { Noise } from \"../source/Noise.js\";\nimport { Effect, EffectOptions } from \"./Effect.js\";\n\nexport interface ReverbOptions extends EffectOptions {\n\tdecay: Seconds;\n\tpreDelay: Seconds;\n}\n\n/**\n * Simple convolution created with decaying noise.\n * Generates an Impulse Response Buffer\n * with Tone.Offline then feeds the IR into ConvolverNode.\n * The impulse response generation is async, so you have\n * to wait until {@link ready} resolves before it will make a sound.\n *\n * Inspiration from [ReverbGen](https://github.com/adelespinasse/reverbGen).\n * Copyright (c) 2014 Alan deLespinasse Apache 2.0 License.\n *\n * @category Effect\n */\nexport class Reverb extends Effect<ReverbOptions> {\n\treadonly name: string = \"Reverb\";\n\n\t/**\n\t * Convolver node\n\t */\n\tprivate _convolver: ConvolverNode = this.context.createConvolver();\n\n\t/**\n\t * The duration of the reverb.\n\t */\n\tprivate _decay: Seconds;\n\n\t/**\n\t * The amount of time before the reverb is fully ramped in.\n\t */\n\tprivate _preDelay: Seconds;\n\n\t/**\n\t * Resolves when the reverb buffer is generated. Whenever either {@link decay}\n\t * or {@link preDelay} are set, you have to wait until {@link ready} resolves\n\t * before the IR is generated with the latest values.\n\t */\n\tready: Promise<void> = Promise.resolve();\n\n\t/**\n\t * @param decay The amount of time it will reverberate for.\n\t */\n\tconstructor(decay?: Seconds);\n\tconstructor(options?: Partial<ReverbOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Reverb.getDefaults(), arguments, [\n\t\t\t\"decay\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tconst decayTime = this.toSeconds(options.decay);\n\t\tassertRange(decayTime, 0.001);\n\t\tthis._decay = decayTime;\n\n\t\tconst preDelayTime = this.toSeconds(options.preDelay);\n\t\tassertRange(preDelayTime, 0);\n\t\tthis._preDelay = preDelayTime;\n\n\t\tthis.generate();\n\n\t\tthis.connectEffect(this._convolver);\n\t}\n\n\tstatic getDefaults(): ReverbOptions {\n\t\treturn Object.assign(Effect.getDefaults(), {\n\t\t\tdecay: 1.5,\n\t\t\tpreDelay: 0.01,\n\t\t});\n\t}\n\n\t/**\n\t * The duration of the reverb.\n\t */\n\tget decay(): Time {\n\t\treturn this._decay;\n\t}\n\tset decay(time) {\n\t\ttime = this.toSeconds(time);\n\t\tassertRange(time, 0.001);\n\t\tthis._decay = time;\n\t\tthis.generate();\n\t}\n\n\t/**\n\t * The amount of time before the reverb is fully ramped in.\n\t */\n\tget preDelay(): Time {\n\t\treturn this._preDelay;\n\t}\n\tset preDelay(time) {\n\t\ttime = this.toSeconds(time);\n\t\tassertRange(time, 0);\n\t\tthis._preDelay = time;\n\t\tthis.generate();\n\t}\n\n\t/**\n\t * Generate the Impulse Response. Returns a promise while the IR is being generated.\n\t * @return Promise which returns this object.\n\t */\n\tasync generate(): Promise<this> {\n\t\tconst previousReady = this.ready;\n\n\t\t// create a noise burst which decays over the duration in each channel\n\t\tconst context = new OfflineContext(\n\t\t\t2,\n\t\t\tthis._decay + this._preDelay,\n\t\t\tthis.context.sampleRate\n\t\t);\n\t\tconst noiseL = new Noise({ context });\n\t\tconst noiseR = new Noise({ context });\n\t\tconst merge = new Merge({ context });\n\t\tnoiseL.connect(merge, 0, 0);\n\t\tnoiseR.connect(merge, 0, 1);\n\t\tconst gainNode = new Gain({ context }).toDestination();\n\t\tmerge.connect(gainNode);\n\t\tnoiseL.start(0);\n\t\tnoiseR.start(0);\n\t\t// predelay\n\t\tgainNode.gain.setValueAtTime(0, 0);\n\t\tgainNode.gain.setValueAtTime(1, this._preDelay);\n\t\t// decay\n\t\tgainNode.gain.exponentialApproachValueAtTime(\n\t\t\t0,\n\t\t\tthis._preDelay,\n\t\t\tthis.decay\n\t\t);\n\n\t\t// render the buffer\n\t\tconst renderPromise = context.render();\n\t\tthis.ready = renderPromise.then(noOp);\n\n\t\t// wait for the previous `ready` to resolve\n\t\tawait previousReady;\n\t\t// set the buffer\n\t\tthis._convolver.buffer = (await renderPromise).get() as AudioBuffer;\n\n\t\treturn this;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._convolver.disconnect();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/ReverseDelay.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { EffectTests } from \"../../test/helper/EffectTests.js\";\nimport { Oscillator } from \"../source/oscillator/Oscillator.js\";\nimport { ReverseDelay } from \"./ReverseDelay.js\";\n\ndescribe(\"ReverseDelay\", () => {\n\tBasicTests(ReverseDelay);\n\tEffectTests(ReverseDelay, 0.01);\n\n\tcontext(\"API\", () => {\n\t\tit(\"matches a file\", () => {\n\t\t\treturn CompareToFile(() => {\n\t\t\t\tconst delay = new ReverseDelay({\n\t\t\t\t\tdelayTime: 0.2,\n\t\t\t\t\tfeedback: 0.5,\n\t\t\t\t\twet: 0.5,\n\t\t\t\t}).toDestination();\n\t\t\t\tconst osc = new Oscillator().connect(delay);\n\t\t\t\tosc.start(0);\n\t\t\t\tosc.volume.linearRampToValueAtTime(0, 0.1);\n\t\t\t\tosc.volume.exponentialRampToValueAtTime(-Infinity, 0.2);\n\t\t\t}, \"reverseDelay.wav\");\n\t\t});\n\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst reverse = new ReverseDelay({\n\t\t\t\tdelayTime: 1.25,\n\t\t\t\tfeedback: 0.75,\n\t\t\t});\n\t\t\texpect(reverse.delayTime).to.equal(1.25);\n\t\t\texpect(reverse.feedback).to.equal(0.75);\n\t\t\treverse.dispose();\n\t\t});\n\n\t\tit(\"can get/set the options\", () => {\n\t\t\tconst reverse = new ReverseDelay(1.25, 0.75);\n\t\t\texpect(reverse.delayTime).to.equal(1.25);\n\t\t\texpect(reverse.feedback).to.equal(0.75);\n\t\t\treverse.set({\n\t\t\t\tdelayTime: \"2n\",\n\t\t\t\tfeedback: 0.5,\n\t\t\t});\n\n\t\t\texpect(reverse.get().delayTime).to.be.closeTo(1, 0.01);\n\t\t\texpect(reverse.get().feedback).to.be.closeTo(0.5, 0.01);\n\t\t\treverse.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/effect/ReverseDelay.ts",
    "content": "import { Gain } from \"../core/context/Gain.js\";\nimport { Param } from \"../core/context/Param.js\";\nimport { connectSeries } from \"../core/context/ToneAudioNode.js\";\nimport { NormalRange, Seconds, Time } from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport {\n\tToneAudioWorklet,\n\tToneAudioWorkletOptions,\n} from \"../core/worklet/ToneAudioWorklet.js\";\nimport { EffectOptions } from \"./Effect.js\";\nimport { Effect } from \"./Effect.js\";\nimport { workletName } from \"./ReverseDelay.worklet.js\";\n\nexport interface ReverseDelayOptions extends EffectOptions {\n\tdelayTime: Time;\n\tfeedback: NormalRange;\n}\n\n/**\n * A feedback delay effect that plays the echos in reverse.\n * Algorithm and gain function found in [this pdf](https://ccrma.stanford.edu/~jingjiez/portfolio/echoing-harmonics/pdfs/A%20Pitch%20Shifting%20Reverse%20Echo%20Audio%20Effect.pdf)\n *\n * @example\n * const reverse = new Tone.ReverseDelay(1.5, 0.75).toDestination();\n * const synth = new Tone.Synth().connect(reverse);\n * synth.triggerAttackRelease(\"C4\", \"2n\");\n * @category Effect\n */\nexport class ReverseDelay extends Effect<ReverseDelayOptions> {\n\treadonly name: string = \"ReverseDelay\";\n\n\t/**\n\t * The node that does the reverse delay effect.\n\t */\n\tprivate _reverseDelayWorklet: ReverseDelayWorklet;\n\n\t/**\n\t * @param delayTime The amount of time the incoming signal will be delayed and reversed.\n\t * @param feedback The amount of signal which is fed back through the delay.\n\t */\n\tconstructor(delayTime?: Time, feedback?: NormalRange);\n\tconstructor(options?: Partial<ReverseDelayOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tReverseDelay.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"delayTime\", \"feedback\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._reverseDelayWorklet = this._connectWorklet(\n\t\t\toptions.delayTime,\n\t\t\toptions.feedback\n\t\t);\n\t}\n\n\tprivate _connectWorklet(\n\t\tdelayTime: Time,\n\t\tfeedback: NormalRange\n\t): ReverseDelayWorklet {\n\t\tconst worklet = new ReverseDelayWorklet({\n\t\t\tcontext: this.context,\n\t\t\tdelayTime: this.toSeconds(delayTime),\n\t\t\tfeedback,\n\t\t});\n\t\tthis.connectEffect(worklet);\n\n\t\treturn worklet;\n\t}\n\n\t/**\n\t * The amount of time the incoming signal is delayed and reversed\n\t */\n\tget delayTime(): Time {\n\t\treturn this._reverseDelayWorklet.delayTime;\n\t}\n\n\tset delayTime(delayTime) {\n\t\tconst prev = this._reverseDelayWorklet;\n\t\tthis._reverseDelayWorklet = this._connectWorklet(\n\t\t\tdelayTime,\n\t\t\tthis.feedback\n\t\t);\n\n\t\t// Prevent sudden stop when disposing previous worklet\n\t\tprev.output.gain.linearRampTo(0, this.toSeconds(this.delayTime));\n\t\tthis.context.setTimeout(\n\t\t\t() => prev.dispose(),\n\t\t\tthis.toSeconds(this.delayTime)\n\t\t);\n\t}\n\n\t/**\n\t * The amount of signal which is fed back through the delay.\n\t */\n\tget feedback(): NormalRange {\n\t\treturn this._reverseDelayWorklet.feedback.value;\n\t}\n\n\tset feedback(feedback) {\n\t\tthis._reverseDelayWorklet.set({ feedback });\n\t}\n\n\tstatic getDefaults(): ReverseDelayOptions {\n\t\treturn Object.assign(Effect.getDefaults(), {\n\t\t\twet: 0.5,\n\t\t\tdelayTime: 1,\n\t\t\tfeedback: 0.5,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._reverseDelayWorklet.dispose();\n\t\treturn this;\n\t}\n}\n\nexport interface ReverseDelayWorkletOptions extends ToneAudioWorkletOptions {\n\tdelayTime: Seconds;\n\tfeedback: NormalRange;\n}\n\n/**\n * Internal class which creates an AudioWorklet to reverse the delay signal\n */\nclass ReverseDelayWorklet extends ToneAudioWorklet<ReverseDelayWorkletOptions> {\n\treadonly name: string = \"ReverseDelayWorklet\";\n\n\treadonly input: Gain;\n\treadonly output: Gain;\n\n\treadonly delayTime: Seconds;\n\treadonly feedback: Param<\"normalRange\">;\n\n\tconstructor(options?: Partial<ReverseDelayOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tReverseDelayWorklet.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"delayTime\", \"feedback\"]\n\t\t);\n\n\t\tsuper({\n\t\t\t...options,\n\t\t\tworkletOptions: {\n\t\t\t\tprocessorOptions: {\n\t\t\t\t\tdelayTime: options.delayTime,\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\n\t\tthis.input = new Gain({ context: this.context });\n\t\tthis.output = new Gain({ context: this.context });\n\n\t\tthis.delayTime = options.delayTime;\n\t\tthis.feedback = new Param<\"normalRange\">({\n\t\t\tcontext: this.context,\n\t\t\tvalue: options.feedback,\n\t\t\tunits: \"normalRange\",\n\t\t\tparam: this._dummyParam,\n\t\t\tswappable: true,\n\t\t\tminValue: 0,\n\t\t\tmaxValue: 0.9999,\n\t\t});\n\t}\n\n\tstatic getDefaults(): ReverseDelayWorkletOptions {\n\t\treturn Object.assign(ToneAudioWorklet.getDefaults(), {\n\t\t\tdelayTime: 1,\n\t\t\tfeedback: 0.5,\n\t\t});\n\t}\n\n\tprotected _audioWorkletName(): string {\n\t\treturn workletName;\n\t}\n\n\tonReady(node: AudioWorkletNode): void {\n\t\tconnectSeries(this.input, node, this.output);\n\t\tconst feedback = node.parameters.get(\"feedback\") as AudioParam;\n\t\tthis.feedback.setParam(feedback);\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.input.dispose();\n\t\tthis.output.dispose();\n\t\tthis.feedback.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/ReverseDelay.worklet.ts",
    "content": "import \"../core/worklet/SingleIOProcessor.worklet.js\";\nimport \"../core/worklet/DelayLine.worklet.js\";\n\nimport { registerProcessor } from \"../core/worklet/WorkletGlobalScope.js\";\n\nexport const workletName = \"reverse-delay\";\n\nexport const reverseDelayWorklet = /* javascript */ `\n\tclass ReverseDelayWorklet extends SingleIOProcessor {\n\n\t\tconstructor(options) {\n\t\t\tsuper(options);\n\t\t\tthis.delayTime = Math.floor(this.sampleRate * options.processorOptions.delayTime);\n\t\t\tconst channels = options.channelCount || 2;\n\t\t\tthis.delayLine = new DelayLine(this.delayTime * 2, channels);\n\t\t}\n\n\t\tstatic get parameterDescriptors() {\n\t\t\treturn [{\n\t\t\t\tname: \"feedback\",\n\t\t\t\tdefaultValue: 0.5,\n\t\t\t\tminValue: 0,\n\t\t\t\tmaxValue: 0.9999,\n\t\t\t\tautomationRate: \"k-rate\"\n\t\t\t}];\n\t\t}\n\n\t\tgenerate(input, channel, parameters) {\n\t\t\tconst reversedSample = this.delayLine.getReverse(channel, this.delayTime);\n\t\t\tconst delayedSample = this.delayLine.get(channel, this.delayTime);\n\n\t\t\t// Push the forward sample back on the line\n\t\t\tthis.delayLine.push(channel, input + delayedSample * parameters.feedback);\n\n\t\t\t// Play the reversed sample\n\t\t\treturn reversedSample;\n\t\t}\n\t}\n`;\n\nregisterProcessor(workletName, reverseDelayWorklet);\n"
  },
  {
    "path": "Tone/effect/StereoEffect.ts",
    "content": "import { CrossFade } from \"../component/channel/CrossFade.js\";\nimport { Merge } from \"../component/channel/Merge.js\";\nimport { Split } from \"../component/channel/Split.js\";\nimport { Gain } from \"../core/context/Gain.js\";\nimport {\n\tconnect,\n\tconnectSeries,\n\tOutputNode,\n\tToneAudioNode,\n} from \"../core/context/ToneAudioNode.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport { Signal } from \"../signal/Signal.js\";\nimport { EffectOptions } from \"./Effect.js\";\n\nexport type StereoEffectOptions = EffectOptions;\n\n/**\n * Base class for Stereo effects.\n */\nexport class StereoEffect<\n\tOptions extends StereoEffectOptions,\n> extends ToneAudioNode<Options> {\n\treadonly name: string = \"StereoEffect\";\n\n\treadonly input: Gain;\n\treadonly output: CrossFade;\n\n\t/**\n\t * the drywet knob to control the amount of effect\n\t */\n\tprivate _dryWet: CrossFade;\n\n\t/**\n\t * The wet control, i.e. how much of the effected\n\t * will pass through to the output.\n\t */\n\treadonly wet: Signal<\"normalRange\">;\n\n\t/**\n\t * Split it\n\t */\n\tprotected _split: Split;\n\n\t/**\n\t * the stereo effect merger\n\t */\n\tprotected _merge: Merge;\n\n\tconstructor(options: StereoEffectOptions) {\n\t\tsuper(options);\n\n\t\tthis.input = new Gain({ context: this.context });\n\t\t// force mono sources to be stereo\n\t\tthis.input.channelCount = 2;\n\t\tthis.input.channelCountMode = \"explicit\";\n\n\t\tthis._dryWet = this.output = new CrossFade({\n\t\t\tcontext: this.context,\n\t\t\tfade: options.wet,\n\t\t});\n\t\tthis.wet = this._dryWet.fade;\n\t\tthis._split = new Split({ context: this.context, channels: 2 });\n\t\tthis._merge = new Merge({ context: this.context, channels: 2 });\n\n\t\t// connections\n\t\tthis.input.connect(this._split);\n\t\t// dry wet connections\n\t\tthis.input.connect(this._dryWet.a);\n\t\tthis._merge.connect(this._dryWet.b);\n\t\treadOnly(this, [\"wet\"]);\n\t}\n\n\t/**\n\t * Connect the left part of the effect\n\t */\n\tprotected connectEffectLeft(...nodes: OutputNode[]): void {\n\t\tthis._split.connect(nodes[0], 0, 0);\n\t\tconnectSeries(...nodes);\n\t\tconnect(nodes[nodes.length - 1], this._merge, 0, 0);\n\t}\n\n\t/**\n\t * Connect the right part of the effect\n\t */\n\tprotected connectEffectRight(...nodes: OutputNode[]): void {\n\t\tthis._split.connect(nodes[0], 1, 0);\n\t\tconnectSeries(...nodes);\n\t\tconnect(nodes[nodes.length - 1], this._merge, 0, 1);\n\t}\n\n\tstatic getDefaults(): StereoEffectOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\twet: 1,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._dryWet.dispose();\n\t\tthis._split.dispose();\n\t\tthis._merge.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/StereoFeedbackEffect.ts",
    "content": "import { Merge } from \"../component/channel/Merge.js\";\nimport { Split } from \"../component/channel/Split.js\";\nimport { Gain } from \"../core/context/Gain.js\";\nimport { NormalRange } from \"../core/type/Units.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport { Signal } from \"../signal/Signal.js\";\nimport { StereoEffect, StereoEffectOptions } from \"./StereoEffect.js\";\n\nexport interface StereoFeedbackEffectOptions extends StereoEffectOptions {\n\tfeedback: NormalRange;\n}\n\n/**\n * Base class for stereo feedback effects where the effectReturn is fed back into the same channel.\n */\nexport class StereoFeedbackEffect<\n\tOptions extends StereoFeedbackEffectOptions,\n> extends StereoEffect<Options> {\n\t/**\n\t * The amount of feedback from the output\n\t * back into the input of the effect (routed\n\t * across left and right channels).\n\t */\n\treadonly feedback: Signal<\"normalRange\">;\n\n\t/**\n\t * the left side feedback\n\t */\n\tprotected _feedbackL: Gain;\n\n\t/**\n\t * the right side feedback\n\t */\n\tprotected _feedbackR: Gain;\n\n\t/**\n\t * Split the channels for feedback\n\t */\n\tprotected _feedbackSplit: Split;\n\n\t/**\n\t * Merge the channels for feedback\n\t */\n\tprotected _feedbackMerge: Merge;\n\n\tconstructor(options: StereoFeedbackEffectOptions) {\n\t\tsuper(options);\n\n\t\tthis.feedback = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tvalue: options.feedback,\n\t\t\tunits: \"normalRange\",\n\t\t});\n\t\tthis._feedbackL = new Gain({ context: this.context });\n\t\tthis._feedbackR = new Gain({ context: this.context });\n\n\t\tthis._feedbackSplit = new Split({ context: this.context, channels: 2 });\n\t\tthis._feedbackMerge = new Merge({ context: this.context, channels: 2 });\n\n\t\tthis._merge.connect(this._feedbackSplit);\n\t\tthis._feedbackMerge.connect(this._split);\n\n\t\t// the left output connected to the left input\n\t\tthis._feedbackSplit.connect(this._feedbackL, 0, 0);\n\t\tthis._feedbackL.connect(this._feedbackMerge, 0, 0);\n\n\t\t// the right output connected to the right input\n\t\tthis._feedbackSplit.connect(this._feedbackR, 1, 0);\n\t\tthis._feedbackR.connect(this._feedbackMerge, 0, 1);\n\n\t\t// the feedback control\n\t\tthis.feedback.fan(this._feedbackL.gain, this._feedbackR.gain);\n\t\treadOnly(this, [\"feedback\"]);\n\t}\n\n\tstatic getDefaults(): StereoFeedbackEffectOptions {\n\t\treturn Object.assign(StereoEffect.getDefaults(), {\n\t\t\tfeedback: 0.5,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.feedback.dispose();\n\t\tthis._feedbackL.dispose();\n\t\tthis._feedbackR.dispose();\n\t\tthis._feedbackSplit.dispose();\n\t\tthis._feedbackMerge.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/StereoWidener.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { EffectTests } from \"../../test/helper/EffectTests.js\";\nimport { ToneAudioBuffer } from \"../core/context/ToneAudioBuffer.js\";\nimport { Player } from \"../source/buffer/Player.js\";\nimport { StereoWidener } from \"./StereoWidener.js\";\n\ndescribe(\"StereoWidener\", () => {\n\tBasicTests(StereoWidener);\n\tEffectTests(StereoWidener, 0);\n\n\tit(\"matches a file basic\", async () => {\n\t\tconst buffer = await ToneAudioBuffer.fromUrl(\"./test/audio/FWDL.wav\");\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst phaser = new StereoWidener(0.1).toDestination();\n\t\t\t\tconst player = new Player(buffer).connect(phaser).start();\n\t\t\t},\n\t\t\t\"stereoWidener.wav\",\n\t\t\t0.3\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst widener = new StereoWidener(0.2);\n\t\t\texpect(widener.width.value).to.be.closeTo(0.2, 0.001);\n\t\t\twidener.dispose();\n\t\t});\n\n\t\tit(\"can get/set the options\", () => {\n\t\t\tconst widener = new StereoWidener();\n\t\t\twidener.set({\n\t\t\t\twidth: 0.4,\n\t\t\t});\n\t\t\texpect(widener.width.value).to.be.closeTo(0.4, 0.001);\n\t\t\twidener.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/effect/StereoWidener.ts",
    "content": "import { NormalRange } from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport {\n\tMidSideEffect,\n\tMidSideEffectOptions,\n} from \"../effect/MidSideEffect.js\";\nimport { Multiply } from \"../signal/Multiply.js\";\nimport { Signal } from \"../signal/Signal.js\";\nimport { Subtract } from \"../signal/Subtract.js\";\nimport { ToneConstantSource } from \"../signal/ToneConstantSource.js\";\n\nexport interface StereoWidenerOptions extends MidSideEffectOptions {\n\twidth: NormalRange;\n}\n\n/**\n * Applies a width factor to the mid/side separation.\n * 0 is all mid and 1 is all side.\n * Algorithm found in [kvraudio forums](http://www.kvraudio.com/forum/viewtopic.php?t=212587).\n * ```\n * Mid *= 2*(1-width)<br>\n * Side *= 2*width\n * ```\n * @category Effect\n */\nexport class StereoWidener extends MidSideEffect<StereoWidenerOptions> {\n\treadonly name: string = \"StereoWidener\";\n\n\t/**\n\t * The width control. 0 = 100% mid. 1 = 100% side. 0.5 = no change.\n\t */\n\treadonly width: Signal<\"normalRange\">;\n\n\t/**\n\t * Two times the (1-width) for the mid channel\n\t */\n\tprivate _twoTimesWidthMid: Multiply;\n\n\t/**\n\t * Two times the width for the side channel\n\t */\n\tprivate _twoTimesWidthSide: Multiply;\n\n\t/**\n\t * Mid multiplier\n\t */\n\tprivate _midMult: Multiply;\n\n\t/**\n\t * 1 - width\n\t */\n\tprivate _oneMinusWidth: Subtract;\n\n\t/**\n\t * Side multiplier\n\t */\n\tprivate _sideMult: Multiply;\n\n\t/**\n\t * A constant source to get the value of 1 for the subtract node\n\t */\n\tprivate _constant: ToneConstantSource;\n\n\t/**\n\t * @param width The stereo width. A width of 0 is mono and 1 is stereo. 0.5 is no change.\n\t */\n\tconstructor(width?: NormalRange);\n\tconstructor(options?: Partial<StereoWidenerOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tStereoWidener.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"width\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.width = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tvalue: options.width,\n\t\t\tunits: \"normalRange\",\n\t\t});\n\t\treadOnly(this, [\"width\"]);\n\t\tthis._twoTimesWidthMid = new Multiply({\n\t\t\tcontext: this.context,\n\t\t\tvalue: 2,\n\t\t});\n\t\tthis._twoTimesWidthSide = new Multiply({\n\t\t\tcontext: this.context,\n\t\t\tvalue: 2,\n\t\t});\n\t\tthis._midMult = new Multiply({ context: this.context });\n\t\tthis._twoTimesWidthMid.connect(this._midMult.factor);\n\t\tthis.connectEffectMid(this._midMult);\n\n\t\tthis._oneMinusWidth = new Subtract({ context: this.context });\n\t\tthis._oneMinusWidth.connect(this._twoTimesWidthMid);\n\t\tthis._constant = new ToneConstantSource({\n\t\t\tcontext: this.context,\n\t\t\toffset: 1,\n\t\t}).start();\n\t\tthis._constant.connect(this._oneMinusWidth);\n\t\tthis.width.connect(this._oneMinusWidth.subtrahend);\n\n\t\tthis._sideMult = new Multiply({ context: this.context });\n\t\tthis.width.connect(this._twoTimesWidthSide);\n\t\tthis._twoTimesWidthSide.connect(this._sideMult.factor);\n\t\tthis.connectEffectSide(this._sideMult);\n\t}\n\n\tstatic getDefaults(): StereoWidenerOptions {\n\t\treturn Object.assign(MidSideEffect.getDefaults(), {\n\t\t\twidth: 0.5,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.width.dispose();\n\t\tthis._midMult.dispose();\n\t\tthis._sideMult.dispose();\n\t\tthis._twoTimesWidthMid.dispose();\n\t\tthis._twoTimesWidthSide.dispose();\n\t\tthis._oneMinusWidth.dispose();\n\t\tthis._constant.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/StereoXFeedbackEffect.ts",
    "content": "import { NormalRange } from \"../core/type/Units.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport {\n\tStereoFeedbackEffect,\n\tStereoFeedbackEffectOptions,\n} from \"./StereoFeedbackEffect.js\";\n\nexport interface StereoXFeedbackEffectOptions\n\textends StereoFeedbackEffectOptions {\n\tfeedback: NormalRange;\n}\n\n/**\n * Just like a {@link StereoFeedbackEffect}, but the feedback is routed from left to right\n * and right to left instead of on the same channel.\n * ```\n * +--------------------------------+ feedbackL <-----------------------------------+\n * |                                                                                |\n * +-->                          +----->        +---->                          +-----+\n *      feedbackMerge +--> split        (EFFECT)       merge +--> feedbackSplit     | |\n * +-->                          +----->        +---->                          +---+ |\n * |                                                                                  |\n * +--------------------------------+ feedbackR <-------------------------------------+\n * ```\n */\nexport class StereoXFeedbackEffect<\n\tOptions extends StereoXFeedbackEffectOptions,\n> extends StereoFeedbackEffect<Options> {\n\tconstructor(options: StereoXFeedbackEffectOptions) {\n\t\tsuper(options);\n\t\t// the left output connected to the right input\n\t\tthis._feedbackL.disconnect();\n\t\tthis._feedbackL.connect(this._feedbackMerge, 0, 1);\n\n\t\t// the left output connected to the right input\n\t\tthis._feedbackR.disconnect();\n\t\tthis._feedbackR.connect(this._feedbackMerge, 0, 0);\n\n\t\treadOnly(this, [\"feedback\"]);\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/Tremolo.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { EffectTests } from \"../../test/helper/EffectTests.js\";\nimport { Oscillator } from \"../source/index.js\";\nimport { Tremolo } from \"./Tremolo.js\";\n\ndescribe(\"Tremolo\", () => {\n\tBasicTests(Tremolo);\n\tEffectTests(Tremolo);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst tremolo = new Tremolo().toDestination().start(0.2);\n\t\t\t\tconst osc = new Oscillator().connect(tremolo).start();\n\t\t\t},\n\t\t\t\"tremolo.wav\",\n\t\t\t0.05\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst tremolo = new Tremolo({\n\t\t\t\tdepth: 0.2,\n\t\t\t\ttype: \"sawtooth\",\n\t\t\t\tspread: 160,\n\t\t\t});\n\t\t\texpect(tremolo.depth.value).to.be.closeTo(0.2, 0.001);\n\t\t\texpect(tremolo.type).to.equal(\"sawtooth\");\n\t\t\texpect(tremolo.spread).to.equal(160);\n\t\t\ttremolo.dispose();\n\t\t});\n\n\t\tit(\"can be started and stopped\", () => {\n\t\t\tconst tremolo = new Tremolo();\n\t\t\ttremolo.start().stop(\"+0.2\");\n\t\t\ttremolo.dispose();\n\t\t});\n\n\t\tit(\"can get/set the options\", () => {\n\t\t\tconst tremolo = new Tremolo();\n\t\t\ttremolo.set({\n\t\t\t\tfrequency: 2.4,\n\t\t\t\ttype: \"triangle\",\n\t\t\t});\n\t\t\texpect(tremolo.get().frequency).to.be.closeTo(2.4, 0.01);\n\t\t\texpect(tremolo.get().type).to.equal(\"triangle\");\n\t\t\ttremolo.dispose();\n\t\t});\n\n\t\tit(\"can set the frequency and depth\", () => {\n\t\t\tconst tremolo = new Tremolo();\n\t\t\ttremolo.depth.value = 0.4;\n\t\t\ttremolo.frequency.value = 0.4;\n\t\t\texpect(tremolo.depth.value).to.be.closeTo(0.4, 0.01);\n\t\t\texpect(tremolo.frequency.value).to.be.closeTo(0.4, 0.01);\n\t\t\ttremolo.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/effect/Tremolo.ts",
    "content": "import { Gain } from \"../core/context/Gain.js\";\nimport { Degrees, Frequency, NormalRange } from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport { Signal } from \"../signal/Signal.js\";\nimport { ToneOscillatorType } from \"../source/oscillator/OscillatorInterface.js\";\nimport { LFOStereoEffect, LFOStereoEffectOptions } from \"./LFOStereoEffect.js\";\n\nexport interface TremoloOptions extends LFOStereoEffectOptions {\n\tfrequency: Frequency;\n\ttype: ToneOscillatorType;\n\tdepth: NormalRange;\n\tspread: Degrees;\n}\n\n/**\n * Tremolo modulates the amplitude of an incoming signal using an {@link LFO}.\n * The effect is a stereo effect where the modulation phase is inverted in each channel.\n *\n * @example\n * // create a tremolo and start its LFO\n * const tremolo = new Tone.Tremolo(9, 0.75).toDestination().start();\n * // route an oscillator through the tremolo and start it\n * const oscillator = new Tone.Oscillator().connect(tremolo).start();\n *\n * @category Effect\n */\nexport class Tremolo extends LFOStereoEffect<TremoloOptions> {\n\treadonly name: string = \"Tremolo\";\n\n\t/**\n\t * Where the gain is multiplied\n\t */\n\tprivate _amplitudeL: Gain;\n\n\t/**\n\t * Where the gain is multiplied\n\t */\n\tprivate _amplitudeR: Gain;\n\n\t/**\n\t * The depth of the effect. A depth of 0, has no effect\n\t * on the amplitude, and a depth of 1 makes the amplitude\n\t * modulate fully between 0 and 1.\n\t */\n\treadonly depth: Signal<\"normalRange\">;\n\n\t/**\n\t * @param frequency The rate of the effect.\n\t * @param depth The depth of the effect.\n\t */\n\tconstructor(frequency?: Frequency, depth?: NormalRange);\n\tconstructor(options?: Partial<TremoloOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Tremolo.getDefaults(), arguments, [\n\t\t\t\"frequency\",\n\t\t\t\"depth\",\n\t\t]);\n\t\tsuper(options);\n\n\t\t// invert the lfo min/max so it moves from full gain to 0 gain\n\t\tthis._lfoL.min = 1;\n\t\tthis._lfoL.max = 0;\n\t\tthis._lfoR.min = 1;\n\t\tthis._lfoR.max = 0;\n\t\tthis.type = options.type;\n\n\t\tthis._amplitudeL = new Gain({ context: this.context });\n\t\tthis._amplitudeR = new Gain({ context: this.context });\n\n\t\tthis.depth = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tvalue: options.depth,\n\t\t\tunits: \"normalRange\",\n\t\t});\n\n\t\treadOnly(this, [\"frequency\", \"depth\"]);\n\t\tthis.connectEffectLeft(this._amplitudeL);\n\t\tthis.connectEffectRight(this._amplitudeR);\n\t\tthis._lfoL.connect(this._amplitudeL.gain);\n\t\tthis._lfoR.connect(this._amplitudeR.gain);\n\t\tthis.depth.fan(this._lfoR.amplitude, this._lfoL.amplitude);\n\t\tthis.spread = options.spread;\n\t}\n\n\tstatic getDefaults(): TremoloOptions {\n\t\treturn Object.assign(LFOStereoEffect.getDefaults(), {\n\t\t\tfrequency: 10,\n\t\t\ttype: \"sine\" as const,\n\t\t\tdepth: 0.5,\n\t\t\tspread: 180,\n\t\t});\n\t}\n\n\t/**\n\t * The oscillator type.\n\t */\n\tget type(): ToneOscillatorType {\n\t\treturn this._lfoL.type;\n\t}\n\tset type(type) {\n\t\tthis._lfoL.type = type;\n\t\tthis._lfoR.type = type;\n\t}\n\n\t/**\n\t * Amount of stereo spread. When set to 0, both LFO's will be panned centrally.\n\t * When set to 180, LFO's will be panned hard left and right respectively.\n\t */\n\tget spread(): Degrees {\n\t\treturn this._lfoR.phase - this._lfoL.phase; // 180\n\t}\n\tset spread(spread) {\n\t\tthis._lfoL.phase = 90 - spread / 2;\n\t\tthis._lfoR.phase = spread / 2 + 90;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._amplitudeL.dispose();\n\t\tthis._amplitudeR.dispose();\n\t\tthis.depth.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/Vibrato.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { EffectTests } from \"../../test/helper/EffectTests.js\";\nimport { Oscillator } from \"../source/oscillator/Oscillator.js\";\nimport { Vibrato } from \"./Vibrato.js\";\n\ndescribe(\"Vibrato\", () => {\n\tBasicTests(Vibrato);\n\tEffectTests(Vibrato);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst vibrato = new Vibrato(4, 1).toDestination();\n\t\t\t\tconst osc = new Oscillator().connect(vibrato).start();\n\t\t\t},\n\t\t\t\"vibrato.wav\",\n\t\t\t0.02\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can pass in options in the constructor\", () => {\n\t\t\tconst vibrato = new Vibrato({\n\t\t\t\tmaxDelay: 0.02,\n\t\t\t\tdepth: 0.25,\n\t\t\t\ttype: \"sawtooth\",\n\t\t\t});\n\t\t\texpect(vibrato.depth.value).to.be.closeTo(0.25, 0.001);\n\t\t\texpect(vibrato.type).to.equal(\"sawtooth\");\n\t\t\tvibrato.dispose();\n\t\t});\n\n\t\tit(\"can get/set the options\", () => {\n\t\t\tconst vibrato = new Vibrato();\n\t\t\tvibrato.set({\n\t\t\t\tfrequency: 2.4,\n\t\t\t\ttype: \"triangle\",\n\t\t\t});\n\t\t\texpect(vibrato.get().frequency).to.be.closeTo(2.4, 0.01);\n\t\t\texpect(vibrato.get().type).to.equal(\"triangle\");\n\t\t\tvibrato.dispose();\n\t\t});\n\n\t\tit(\"can set the frequency and depth\", () => {\n\t\t\tconst vibrato = new Vibrato();\n\t\t\tvibrato.depth.value = 0.4;\n\t\t\tvibrato.frequency.value = 0.4;\n\t\t\texpect(vibrato.depth.value).to.be.closeTo(0.4, 0.01);\n\t\t\texpect(vibrato.frequency.value).to.be.closeTo(0.4, 0.01);\n\t\t\tvibrato.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/effect/Vibrato.ts",
    "content": "import { Delay } from \"../core/context/Delay.js\";\nimport { Param } from \"../core/context/Param.js\";\nimport { Frequency, NormalRange, Seconds } from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport { Signal } from \"../signal/Signal.js\";\nimport { LFO } from \"../source/oscillator/LFO.js\";\nimport { ToneOscillatorType } from \"../source/oscillator/OscillatorInterface.js\";\nimport { Effect, EffectOptions } from \"./Effect.js\";\n\nexport interface VibratoOptions extends EffectOptions {\n\tmaxDelay: Seconds;\n\tfrequency: Frequency;\n\tdepth: NormalRange;\n\ttype: ToneOscillatorType;\n}\n/**\n * A Vibrato effect composed of a Tone.Delay and a Tone.LFO. The LFO\n * modulates the delayTime of the delay, causing the pitch to rise and fall.\n * @category Effect\n */\nexport class Vibrato extends Effect<VibratoOptions> {\n\treadonly name: string = \"Vibrato\";\n\t/**\n\t * The delay node used for the vibrato effect\n\t */\n\tprivate _delayNode: Delay;\n\n\t/**\n\t * The LFO used to control the vibrato\n\t */\n\tprivate _lfo: LFO;\n\n\t/**\n\t * The frequency of the vibrato\n\t */\n\treadonly frequency: Signal<\"frequency\">;\n\n\t/**\n\t * The depth of the vibrato.\n\t */\n\treadonly depth: Param<\"normalRange\">;\n\n\t/**\n\t * @param frequency The frequency of the vibrato.\n\t * @param depth The amount the pitch is modulated.\n\t */\n\tconstructor(frequency?: Frequency, depth?: NormalRange);\n\tconstructor(options?: Partial<VibratoOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Vibrato.getDefaults(), arguments, [\n\t\t\t\"frequency\",\n\t\t\t\"depth\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis._delayNode = new Delay({\n\t\t\tcontext: this.context,\n\t\t\tdelayTime: 0,\n\t\t\tmaxDelay: options.maxDelay,\n\t\t});\n\t\tthis._lfo = new LFO({\n\t\t\tcontext: this.context,\n\t\t\ttype: options.type,\n\t\t\tmin: 0,\n\t\t\tmax: options.maxDelay,\n\t\t\tfrequency: options.frequency,\n\t\t\tphase: -90, // offset the phase so the resting position is in the center\n\t\t}).connect(this._delayNode.delayTime);\n\t\tthis.frequency = this._lfo.frequency;\n\t\tthis.depth = this._lfo.amplitude;\n\n\t\tthis.depth.value = options.depth;\n\t\treadOnly(this, [\"frequency\", \"depth\"]);\n\t\tthis.effectSend.chain(this._delayNode, this.effectReturn);\n\n\t\tthis._onContextRunning(() => {\n\t\t\tthis._lfo.start();\n\t\t});\n\t}\n\n\tstatic getDefaults(): VibratoOptions {\n\t\treturn Object.assign(Effect.getDefaults(), {\n\t\t\tmaxDelay: 0.005,\n\t\t\tfrequency: 5,\n\t\t\tdepth: 0.1,\n\t\t\ttype: \"sine\" as const,\n\t\t});\n\t}\n\n\t/**\n\t * Type of oscillator attached to the Vibrato.\n\t */\n\tget type(): ToneOscillatorType {\n\t\treturn this._lfo.type;\n\t}\n\tset type(type) {\n\t\tthis._lfo.type = type;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._delayNode.dispose();\n\t\tthis._lfo.dispose();\n\t\tthis.frequency.dispose();\n\t\tthis.depth.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/effect/index.ts",
    "content": "export * from \"./AutoFilter.js\";\nexport * from \"./AutoPanner.js\";\nexport * from \"./AutoWah.js\";\nexport * from \"./BitCrusher.js\";\nexport * from \"./Chebyshev.js\";\nexport * from \"./Chorus.js\";\nexport * from \"./Distortion.js\";\nexport * from \"./FeedbackDelay.js\";\nexport * from \"./Freeverb.js\";\nexport * from \"./FrequencyShifter.js\";\nexport * from \"./JCReverb.js\";\nexport * from \"./Phaser.js\";\nexport * from \"./PingPongDelay.js\";\nexport * from \"./PitchShift.js\";\nexport * from \"./Reverb.js\";\nexport * from \"./ReverseDelay.js\";\nexport * from \"./StereoWidener.js\";\nexport * from \"./Tremolo.js\";\nexport * from \"./Vibrato.js\";\n"
  },
  {
    "path": "Tone/event/Loop.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { Offline, whenBetween } from \"../../test/helper/Offline.js\";\nimport { Time } from \"../core/type/Time.js\";\nimport { noOp } from \"../core/util/Interface.js\";\nimport { Loop } from \"./Loop.js\";\n\ndescribe(\"Loop\", () => {\n\tBasicTests(Loop);\n\n\tcontext(\"Constructor\", () => {\n\t\tit(\"takes a callback and an interval\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst callback = noOp;\n\t\t\t\tconst loop = new Loop(callback, \"8n\");\n\t\t\t\texpect(loop.callback).to.equal(callback);\n\t\t\t\texpect(loop.interval).to.equal(Time(\"8n\").valueOf());\n\t\t\t\tloop.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can be constructed with no arguments\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst loop = new Loop();\n\t\t\t\texpect(loop.iterations).to.equal(Infinity);\n\t\t\t\tloop.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can pass in arguments in options object\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst callback = noOp;\n\t\t\t\tconst loop = new Loop({\n\t\t\t\t\tcallback: callback,\n\t\t\t\t\titerations: 4,\n\t\t\t\t\tprobability: 0.3,\n\t\t\t\t\tinterval: \"8t\",\n\t\t\t\t});\n\t\t\t\texpect(loop.callback).to.equal(callback);\n\t\t\t\texpect(loop.interval.valueOf()).to.equal(Time(\"8t\").valueOf());\n\t\t\t\texpect(loop.iterations).to.equal(4);\n\t\t\t\texpect(loop.probability).to.equal(0.3);\n\t\t\t\tloop.dispose();\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"Get/Set\", () => {\n\t\tit(\"can set values with object\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst callback = noOp;\n\t\t\t\tconst loop = new Loop();\n\t\t\t\tloop.set({\n\t\t\t\t\tcallback: callback,\n\t\t\t\t\titerations: 8,\n\t\t\t\t});\n\t\t\t\texpect(loop.callback).to.equal(callback);\n\t\t\t\texpect(loop.iterations).to.equal(8);\n\t\t\t\tloop.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get/set the humanize and interval values\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst loop = new Loop();\n\t\t\t\tloop.humanize = true;\n\t\t\t\tloop.interval = 0.4;\n\t\t\t\texpect(loop.humanize).to.be.true;\n\t\t\t\texpect(loop.interval).to.be.closeTo(0.4, 0.002);\n\t\t\t\tloop.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can set get a the values as an object\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst callback = noOp;\n\t\t\t\tconst loop = new Loop({\n\t\t\t\t\tcallback: callback,\n\t\t\t\t\titerations: 4,\n\t\t\t\t\tprobability: 0.3,\n\t\t\t\t});\n\t\t\t\tconst values = loop.get();\n\t\t\t\texpect(values.iterations).to.equal(4);\n\t\t\t\texpect(values.probability).to.equal(0.3);\n\t\t\t\tloop.dispose();\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"Callback\", () => {\n\t\tit(\"does not invoke get invoked until started\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tnew Loop(() => {\n\t\t\t\t\tthrow new Error(\"shouldn't call this callback\");\n\t\t\t\t}, \"8n\");\n\t\t\t\ttransport.start();\n\t\t\t}, 0.3);\n\t\t});\n\n\t\tit(\"is invoked after it's started\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst loop = new Loop(() => {\n\t\t\t\t\tinvoked = true;\n\t\t\t\t\tloop.dispose();\n\t\t\t\t}, 0.05).start(0);\n\t\t\t\ttransport.start();\n\t\t\t});\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"passes in the scheduled time to the callback\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst now = transport.now() + 0.1;\n\t\t\t\tconst loop = new Loop((time) => {\n\t\t\t\t\texpect(time).to.be.a(\"number\");\n\t\t\t\t\texpect(time - now).to.be.closeTo(0.3, 0.01);\n\t\t\t\t\tloop.dispose();\n\t\t\t\t\tinvoked = true;\n\t\t\t\t});\n\t\t\t\ttransport.start(now);\n\t\t\t\tloop.start(0.3);\n\t\t\t}, 0.5);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"can mute the callback\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst loop = new Loop(() => {\n\t\t\t\t\tthrow new Error(\"shouldn't call this callback\");\n\t\t\t\t}, \"4n\").start();\n\t\t\t\tloop.mute = true;\n\t\t\t\texpect(loop.mute).to.be.true;\n\t\t\t\ttransport.start();\n\t\t\t}, 0.4);\n\t\t});\n\n\t\tit(\"can trigger with some probability\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst loop = new Loop(() => {\n\t\t\t\t\tthrow new Error(\"shouldn't call this callback\");\n\t\t\t\t}, \"4n\").start();\n\t\t\t\tloop.probability = 0;\n\t\t\t\texpect(loop.probability).to.equal(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.4);\n\t\t});\n\t});\n\n\tcontext(\"Scheduling\", () => {\n\t\tit(\"can be started and stopped multiple times\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst loop = new Loop().start().stop(0.2).start(0.4);\n\t\t\t\ttransport.start(0);\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, 0.19, () => {\n\t\t\t\t\t\texpect(loop.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.2, 0.39, () => {\n\t\t\t\t\t\texpect(loop.state).to.equal(\"stopped\");\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.4, Infinity, () => {\n\t\t\t\t\t\texpect(loop.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.6);\n\t\t});\n\n\t\tit(\"restarts when transport is restarted\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst note = new Loop().start(0).stop(0.4);\n\t\t\t\ttransport.start(0).stop(0.5).start(0.55);\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, 0.39, () => {\n\t\t\t\t\t\texpect(note.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.4, 0.5, () => {\n\t\t\t\t\t\texpect(note.state).to.equal(\"stopped\");\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.55, 0.8, () => {\n\t\t\t\t\t\texpect(note.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 1);\n\t\t});\n\n\t\tit(\"can be cancelled\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst note = new Loop().start(0);\n\t\t\t\texpect(note.state).to.equal(\"started\");\n\t\t\t\ttransport.start();\n\n\t\t\t\tlet firstStop = false;\n\t\t\t\tlet restarted = false;\n\t\t\t\tconst tested = false;\n\t\t\t\treturn (time) => {\n\t\t\t\t\t// stop the transport\n\t\t\t\t\tif (time > 0.2 && !firstStop) {\n\t\t\t\t\t\tfirstStop = true;\n\t\t\t\t\t\ttransport.stop();\n\t\t\t\t\t\tnote.cancel();\n\t\t\t\t\t}\n\t\t\t\t\tif (time > 0.3 && !restarted) {\n\t\t\t\t\t\trestarted = true;\n\t\t\t\t\t\ttransport.start();\n\t\t\t\t\t}\n\t\t\t\t\tif (time > 0.4 && !tested) {\n\t\t\t\t\t\trestarted = true;\n\t\t\t\t\t\ttransport.start();\n\t\t\t\t\t\texpect(note.state).to.equal(\"stopped\");\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.5);\n\t\t});\n\t});\n\n\tcontext(\"Looping\", () => {\n\t\tit(\"loops\", async () => {\n\t\t\tlet callCount = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tnew Loop({\n\t\t\t\t\tinterval: 0.1,\n\t\t\t\t\tcallback: () => {\n\t\t\t\t\t\tcallCount++;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.81);\n\t\t\texpect(callCount).to.equal(9);\n\t\t});\n\n\t\tit(\"loops for the specified interval\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tlet lastCall;\n\t\t\t\tnew Loop({\n\t\t\t\t\tinterval: \"8n\",\n\t\t\t\t\tcallback: (time) => {\n\t\t\t\t\t\tif (lastCall) {\n\t\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t\t\texpect(time - lastCall).to.be.closeTo(0.25, 0.01);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlastCall = time;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 1);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"can loop a specific number of iterations\", async () => {\n\t\t\tlet callCount = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tnew Loop({\n\t\t\t\t\tinterval: 0.1,\n\t\t\t\t\titerations: 2,\n\t\t\t\t\tcallback: () => {\n\t\t\t\t\t\tcallCount++;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.4);\n\t\t\texpect(callCount).to.equal(2);\n\t\t});\n\n\t\tit(\"reports the progress of the loop\", async () => {\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst loop = new Loop({\n\t\t\t\t\tinterval: 1,\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t\treturn (time) => {\n\t\t\t\t\texpect(loop.progress).to.be.closeTo(time, 0.05);\n\t\t\t\t};\n\t\t\t}, 0.8);\n\t\t});\n\t});\n\n\tcontext(\"playbackRate\", () => {\n\t\tit(\"can adjust the playbackRate\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tlet lastCall;\n\t\t\t\tconst loop = new Loop({\n\t\t\t\t\tplaybackRate: 2,\n\t\t\t\t\tinterval: 0.5,\n\t\t\t\t\tcallback: (time) => {\n\t\t\t\t\t\tif (lastCall) {\n\t\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t\t\texpect(time - lastCall).to.be.closeTo(0.25, 0.01);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlastCall = time;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\texpect(loop.playbackRate).to.equal(2);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.7);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"can playback at a faster rate\", async () => {\n\t\t\tlet callCount = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst loop = new Loop({\n\t\t\t\t\tinterval: 0.1,\n\t\t\t\t\tcallback: () => {\n\t\t\t\t\t\tcallCount++;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\tloop.playbackRate = 1.5;\n\t\t\t\texpect(loop.playbackRate).to.equal(1.5);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.81);\n\t\t\texpect(callCount).to.equal(13);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/event/Loop.ts",
    "content": "import {\n\tToneWithContext,\n\tToneWithContextOptions,\n} from \"../core/context/ToneWithContext.js\";\nimport {\n\tNormalRange,\n\tPositive,\n\tSeconds,\n\tTime,\n\tTransportTime,\n} from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { noOp } from \"../core/util/Interface.js\";\nimport { BasicPlaybackState } from \"../core/util/StateTimeline.js\";\nimport { ToneEvent } from \"./ToneEvent.js\";\n\nexport interface LoopOptions extends ToneWithContextOptions {\n\tcallback: (time: Seconds) => void;\n\tinterval: Time;\n\tplaybackRate: Positive;\n\titerations: number;\n\tprobability: NormalRange;\n\tmute: boolean;\n\thumanize: boolean | Time;\n}\n\n/**\n * Loop creates a looped callback at the\n * specified interval. The callback can be\n * started, stopped and scheduled along\n * the Transport's timeline.\n * @example\n * const loop = new Tone.Loop((time) => {\n * \t// triggered every eighth note.\n * \tconsole.log(time);\n * }, \"8n\").start(0);\n * Tone.Transport.start();\n * @category Event\n */\nexport class Loop<\n\tOptions extends LoopOptions = LoopOptions,\n> extends ToneWithContext<Options> {\n\treadonly name: string = \"Loop\";\n\n\t/**\n\t * The event which produces the callbacks\n\t */\n\tprivate _event: ToneEvent;\n\n\t/**\n\t * The callback to invoke with the next event in the pattern\n\t */\n\tcallback: (time: Seconds) => void;\n\n\t/**\n\t * @param callback The callback to invoke at the time.\n\t * @param interval The time between successive callback calls.\n\t */\n\tconstructor(callback?: (time: Seconds) => void, interval?: Time);\n\tconstructor(options?: Partial<LoopOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Loop.getDefaults(), arguments, [\n\t\t\t\"callback\",\n\t\t\t\"interval\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis._event = new ToneEvent({\n\t\t\tcontext: this.context,\n\t\t\tcallback: this._tick.bind(this),\n\t\t\tloop: true,\n\t\t\tloopEnd: options.interval,\n\t\t\tplaybackRate: options.playbackRate,\n\t\t\tprobability: options.probability,\n\t\t\thumanize: options.humanize,\n\t\t});\n\n\t\tthis.callback = options.callback;\n\t\t// set the iterations\n\t\tthis.iterations = options.iterations;\n\t}\n\n\tstatic getDefaults(): LoopOptions {\n\t\treturn Object.assign(ToneWithContext.getDefaults(), {\n\t\t\tinterval: \"4n\",\n\t\t\tcallback: noOp,\n\t\t\tplaybackRate: 1,\n\t\t\titerations: Infinity,\n\t\t\tprobability: 1,\n\t\t\tmute: false,\n\t\t\thumanize: false,\n\t\t});\n\t}\n\n\t/**\n\t * Start the loop at the specified time along the Transport's timeline.\n\t * @param  time  When to start the Loop.\n\t */\n\tstart(time?: TransportTime): this {\n\t\tthis._event.start(time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop the loop at the given time.\n\t * @param  time  When to stop the Loop.\n\t */\n\tstop(time?: TransportTime): this {\n\t\tthis._event.stop(time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Cancel all scheduled events greater than or equal to the given time\n\t * @param  time  The time after which events will be cancel.\n\t */\n\tcancel(time?: TransportTime): this {\n\t\tthis._event.cancel(time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Internal function called when the notes should be called\n\t * @param time  The time the event occurs\n\t */\n\tprotected _tick(time: Seconds): void {\n\t\tthis.callback(time);\n\t}\n\n\t/**\n\t * The state of the Loop, either started or stopped.\n\t */\n\tget state(): BasicPlaybackState {\n\t\treturn this._event.state;\n\t}\n\n\t/**\n\t * The progress of the loop as a value between 0-1. 0, when the loop is stopped or done iterating.\n\t */\n\tget progress(): NormalRange {\n\t\treturn this._event.progress;\n\t}\n\n\t/**\n\t * The time between successive callbacks.\n\t * @example\n\t * const loop = new Tone.Loop();\n\t * loop.interval = \"8n\"; // loop every 8n\n\t */\n\tget interval(): Time {\n\t\treturn this._event.loopEnd;\n\t}\n\tset interval(interval) {\n\t\tthis._event.loopEnd = interval;\n\t}\n\n\t/**\n\t * The playback rate of the loop. The normal playback rate is 1 (no change).\n\t * A `playbackRate` of 2 would be twice as fast.\n\t */\n\tget playbackRate(): Positive {\n\t\treturn this._event.playbackRate;\n\t}\n\tset playbackRate(rate) {\n\t\tthis._event.playbackRate = rate;\n\t}\n\n\t/**\n\t * Random variation +/-0.01s to the scheduled time.\n\t * Or give it a time value which it will randomize by.\n\t */\n\tget humanize(): boolean | Time {\n\t\treturn this._event.humanize;\n\t}\n\tset humanize(variation) {\n\t\tthis._event.humanize = variation;\n\t}\n\n\t/**\n\t * The probably of the callback being invoked.\n\t */\n\tget probability(): NormalRange {\n\t\treturn this._event.probability;\n\t}\n\n\tset probability(prob) {\n\t\tthis._event.probability = prob;\n\t}\n\n\t/**\n\t * Muting the Loop means that no callbacks are invoked.\n\t */\n\tget mute(): boolean {\n\t\treturn this._event.mute;\n\t}\n\n\tset mute(mute) {\n\t\tthis._event.mute = mute;\n\t}\n\n\t/**\n\t * The number of iterations of the loop. The default value is `Infinity` (loop forever).\n\t */\n\tget iterations(): number {\n\t\tif (this._event.loop === true) {\n\t\t\treturn Infinity;\n\t\t} else {\n\t\t\treturn this._event.loop as number;\n\t\t}\n\t}\n\tset iterations(iters) {\n\t\tif (iters === Infinity) {\n\t\t\tthis._event.loop = true;\n\t\t} else {\n\t\t\tthis._event.loop = iters;\n\t\t}\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._event.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/event/Part.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { atTime, Offline } from \"../../test/helper/Offline.js\";\nimport { Time } from \"../core/type/Time.js\";\nimport { noOp } from \"../core/util/Interface.js\";\nimport { Part } from \"./Part.js\";\nimport { Sequence } from \"./Sequence.js\";\nimport { ToneEvent } from \"./ToneEvent.js\";\n\ndescribe(\"Part\", () => {\n\tBasicTests(Part);\n\n\tcontext(\"Constructor\", () => {\n\t\tit(\"takes a callback and an array of values\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst callback = noOp;\n\t\t\t\tconst part = new Part(callback, [0, 1, 2]);\n\t\t\t\texpect(part.callback).to.equal(callback);\n\t\t\t\texpect(part.length).to.equal(3);\n\t\t\t\tpart.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can be constructed with no arguments\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst part = new Part();\n\t\t\t\texpect(part.length).to.equal(0);\n\t\t\t\tpart.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can pass in arguments in options object\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst callback = noOp;\n\t\t\t\tconst part = new Part({\n\t\t\t\t\tcallback,\n\t\t\t\t\tevents: [0, 1, 2],\n\t\t\t\t\thumanize: true,\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: \"4n\",\n\t\t\t\t\tprobability: 0.3,\n\t\t\t\t});\n\t\t\t\texpect(part.callback).to.equal(callback);\n\t\t\t\texpect(part.length).to.equal(3);\n\t\t\t\texpect(part.loop).to.be.true;\n\t\t\t\texpect(part.loopEnd).to.equal(Time(\"4n\").valueOf());\n\t\t\t\texpect(part.probability).to.equal(0.3);\n\t\t\t\texpect(part.humanize).to.be.true;\n\t\t\t\tpart.dispose();\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"Adding / Removing / Getting Events\", () => {\n\t\tit(\"can take events in the constructor as an array of times\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst part = new Part(noOp, [\"0\", \"8n\", \"4n\"]);\n\t\t\t\texpect(part.length).to.equal(3);\n\t\t\t\tpart.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can take events in the constructor as an array of times and values\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst part = new Part(noOp, [\n\t\t\t\t\t[\"0\", \"C4\"],\n\t\t\t\t\t[\"8n\", \"D3\"],\n\t\t\t\t\t[\"4n\", \"E4\"],\n\t\t\t\t]);\n\t\t\t\texpect(part.length).to.equal(3);\n\t\t\t\tpart.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can retrieve an event using 'at'\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst part = new Part(noOp, [\n\t\t\t\t\t[\"0\", 0],\n\t\t\t\t\t[\"8n\", \"C2\"],\n\t\t\t\t\t[\"4n\", 2],\n\t\t\t\t]);\n\t\t\t\texpect(part.length).to.equal(3);\n\t\t\t\texpect(part.at(0)).to.be.instanceof(ToneEvent);\n\t\t\t\texpect((part.at(0) as ToneEvent).value).to.equal(0);\n\t\t\t\texpect((part.at(\"8n\") as ToneEvent).value).to.equal(\"C2\");\n\t\t\t\texpect((part.at(\"4n\") as ToneEvent).value).to.equal(2);\n\t\t\t\texpect(part.at(\"2n\")).to.be.null;\n\t\t\t\tpart.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can set the value of an existing event with 'at'\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst part = new Part({\n\t\t\t\t\tevents: [[0, \"C3\"]],\n\t\t\t\t});\n\t\t\t\texpect(part.length).to.equal(1);\n\t\t\t\texpect((part.at(0) as ToneEvent).value).to.equal(\"C3\");\n\t\t\t\tpart.at(0, \"C4\");\n\t\t\t\texpect((part.at(0) as ToneEvent).value).to.equal(\"C4\");\n\t\t\t\tpart.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can take events in the constructor as an array of objects\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst part = new Part(noOp, [\n\t\t\t\t\t{\n\t\t\t\t\t\tnote: \"C3\",\n\t\t\t\t\t\ttime: 0.3,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tnote: \"D3\",\n\t\t\t\t\t\ttime: 1,\n\t\t\t\t\t},\n\t\t\t\t]);\n\t\t\t\texpect(part.length).to.equal(2);\n\t\t\t\texpect((part.at(0.3) as ToneEvent).value).to.be.an(\"object\");\n\t\t\t\texpect((part.at(0.3) as ToneEvent).value.note).to.equal(\"C3\");\n\t\t\t\tpart.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can cancel event changes\", async () => {\n\t\t\tlet count = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst part = new Part(\n\t\t\t\t\t(time) => {\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t},\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnote: \"C3\",\n\t\t\t\t\t\t\ttime: 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnote: \"D3\",\n\t\t\t\t\t\t\ttime: 0.2,\n\t\t\t\t\t\t},\n\t\t\t\t\t]\n\t\t\t\t)\n\t\t\t\t\t.start(0)\n\t\t\t\t\t.stop(0.1);\n\t\t\t\tpart.cancel(0.1);\n\t\t\t\ttransport.start(0);\n\t\t\t}, 0.3);\n\t\t\texpect(count).to.equal(2);\n\t\t});\n\n\t\tit(\"can add an event as a time and value\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst part = new Part();\n\t\t\t\texpect(part.length).to.equal(0);\n\t\t\t\tpart.add(1, \"D3\");\n\t\t\t\texpect(part.length).to.equal(1);\n\t\t\t\texpect((part.at(1) as ToneEvent).value).to.equal(\"D3\");\n\t\t\t\tpart.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can add an event as an object\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst part = new Part();\n\t\t\t\texpect(part.length).to.equal(0);\n\t\t\t\tpart.add({\n\t\t\t\t\tduration: \"8n\",\n\t\t\t\t\tnote: \"D4\",\n\t\t\t\t\ttime: 0.5,\n\t\t\t\t});\n\t\t\t\texpect(part.length).to.equal(1);\n\t\t\t\texpect((part.at(0.5) as ToneEvent).value).to.be.an(\"object\");\n\t\t\t\texpect(\n\t\t\t\t\t(part.at(0.5) as ToneEvent).value.duration\n\t\t\t\t).to.deep.equal(\"8n\");\n\t\t\t\texpect((part.at(0.5) as ToneEvent).value.note).to.deep.equal(\n\t\t\t\t\t\"D4\"\n\t\t\t\t);\n\t\t\t\tpart.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can add another part\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst part = new Part();\n\t\t\t\texpect(part.length).to.equal(0);\n\t\t\t\tconst subPart = new Part({\n\t\t\t\t\tevents: [0, 0.5],\n\t\t\t\t});\n\t\t\t\tpart.add(0.2, subPart);\n\t\t\t\texpect(part.length).to.equal(1);\n\t\t\t\texpect(part.at(0.2)).to.equal(subPart);\n\t\t\t\tpart.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can add a sequence\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst part = new Part();\n\t\t\t\texpect(part.length).to.equal(0);\n\t\t\t\tconst subPart = new Sequence({\n\t\t\t\t\tevents: [0, 1, 2, 3],\n\t\t\t\t});\n\t\t\t\tpart.add(0.2, subPart);\n\t\t\t\texpect(part.length).to.equal(1);\n\t\t\t\texpect(part.at(0.2)).to.equal(subPart);\n\t\t\t\tpart.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can remove an event by time\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst part = new Part({\n\t\t\t\t\tevents: [\n\t\t\t\t\t\t[0.2, \"C3\"],\n\t\t\t\t\t\t[0.2, \"C4\"],\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t\texpect(part.length).to.equal(2);\n\t\t\t\tpart.remove(0.2);\n\t\t\t\texpect(part.length).to.equal(0);\n\t\t\t\tpart.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can remove an event by time and value\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst secondEvent = {\n\t\t\t\t\tnote: \"C4\",\n\t\t\t\t\ttime: 0.2,\n\t\t\t\t};\n\t\t\t\tconst part = new Part({\n\t\t\t\t\tevents: [[0.2, \"C2\"], secondEvent],\n\t\t\t\t});\n\t\t\t\texpect(part.length).to.equal(2);\n\t\t\t\tpart.remove(0.2, \"C2\");\n\t\t\t\texpect(part.length).to.equal(1);\n\t\t\t\tpart.remove(secondEvent);\n\t\t\t\texpect(part.length).to.equal(0);\n\t\t\t\tpart.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"added events have the same settings as the parent\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst part = new Part({\n\t\t\t\t\tevents: [\n\t\t\t\t\t\t[0.2, \"C3\"],\n\t\t\t\t\t\t[0.3, \"C4\"],\n\t\t\t\t\t],\n\t\t\t\t\tloopEnd: \"1m\",\n\t\t\t\t\tloopStart: \"4n\",\n\t\t\t\t\tprobability: 0.2,\n\t\t\t\t});\n\t\t\t\tpart.humanize = 0.1;\n\t\t\t\tconst firstEvent = part.at(0.2) as ToneEvent;\n\t\t\t\texpect(firstEvent.humanize).to.equal(0.1);\n\t\t\t\texpect(firstEvent.probability).to.equal(0.2);\n\t\t\t\t// loop duration is the same\n\t\t\t\texpect(firstEvent.loopEnd).to.equal(Time(\"1m\").valueOf());\n\t\t\t\texpect(firstEvent.loopStart).to.equal(Time(\"4n\").valueOf());\n\n\t\t\t\tconst secondEvent = part.at(0.3) as ToneEvent;\n\t\t\t\texpect(secondEvent.humanize).to.equal(0.1);\n\t\t\t\texpect(secondEvent.probability).to.equal(0.2);\n\t\t\t\t// loop duration is the same\n\t\t\t\texpect(secondEvent.loopEnd).to.equal(Time(\"1m\").valueOf());\n\t\t\t\texpect(secondEvent.loopStart).to.equal(Time(\"4n\").valueOf());\n\t\t\t\tpart.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"will create an event using at if one wasn't there at that time\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst part = new Part();\n\t\t\t\texpect(part.length).to.equal(0);\n\t\t\t\texpect((part.at(0.1, \"C4\") as ToneEvent).value).to.equal(\"C4\");\n\t\t\t\texpect(part.length).to.equal(1);\n\t\t\t\tpart.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can remove all of the events\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst part = new Part(noOp, [0, 1, 2, 3, 4, 5]);\n\t\t\t\texpect(part.length).to.equal(6);\n\t\t\t\tpart.clear();\n\t\t\t\texpect(part.length).to.equal(0);\n\t\t\t\tpart.dispose();\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"Part callback\", () => {\n\t\tit(\"does not invoke get invoked until started\", async () => {\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst part = new Part(() => {\n\t\t\t\t\tthrow new Error(\"shouldn't call this callback\");\n\t\t\t\t}, [0, 0.4]);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.5);\n\t\t});\n\n\t\tit(\"is invoked after it's started\", async () => {\n\t\t\tlet invocations = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst part = new Part(() => {\n\t\t\t\t\tinvocations++;\n\t\t\t\t}, [0, 0.1]).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.2);\n\t\t\texpect(invocations).to.equal(2);\n\t\t});\n\n\t\tit(\"passes in the scheduled time to the callback\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst startTime = 0.1;\n\t\t\t\tconst part = new Part(\n\t\t\t\t\t(time) => {\n\t\t\t\t\t\texpect(time).to.be.a(\"number\");\n\t\t\t\t\t\texpect(time - startTime).to.be.closeTo(0.5, 0.01);\n\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t},\n\t\t\t\t\t[0.3]\n\t\t\t\t);\n\t\t\t\tpart.start(0.2);\n\t\t\t\ttransport.start(startTime);\n\t\t\t}, 0.62);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"passes in the value to the callback\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst part = new Part(\n\t\t\t\t\t(time, thing) => {\n\t\t\t\t\t\texpect(time).to.be.a(\"number\");\n\t\t\t\t\t\texpect(thing).to.equal(\"thing\");\n\t\t\t\t\t\tpart.dispose();\n\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t},\n\t\t\t\t\t[[0, \"thing\"]]\n\t\t\t\t).start();\n\t\t\t\ttransport.start();\n\t\t\t}, 0.6);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"can mute the callback\", async () => {\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst part = new Part(() => {\n\t\t\t\t\tthrow new Error(\"shouldn't call this callback\");\n\t\t\t\t}, [0, 0.1, 0.2, 0.3]).start();\n\t\t\t\tpart.mute = true;\n\t\t\t\texpect(part.mute).to.be.true;\n\t\t\t\ttransport.start();\n\t\t\t}, 0.5);\n\t\t});\n\n\t\tit(\"can trigger with some probability\", async () => {\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst part = new Part(() => {\n\t\t\t\t\tthrow new Error(\"shouldn't call this callback\");\n\t\t\t\t}, [0, 0.1, 0.2, 0.3]).start();\n\t\t\t\tpart.probability = 0;\n\t\t\t\texpect(part.probability).to.equal(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.4);\n\t\t});\n\n\t\tit(\"invokes all of the scheduled events\", async () => {\n\t\t\tlet count = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tnew Part(() => {\n\t\t\t\t\tcount++;\n\t\t\t\t}, [0, 0.1, 0.2, 0.3]).start();\n\t\t\t\ttransport.start();\n\t\t\t}, 0.4);\n\t\t\texpect(count).to.equal(4);\n\t\t});\n\n\t\tit(\"invokes all of the scheduled events at the correct times\", async () => {\n\t\t\tlet count = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst now = transport.now() + 0.1;\n\t\t\t\tnew Part(\n\t\t\t\t\t(time, value) => {\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t\texpect(time - now).to.be.closeTo(value, 0.01);\n\t\t\t\t\t},\n\t\t\t\t\t[\n\t\t\t\t\t\t[0, 0],\n\t\t\t\t\t\t[0.1, 0.1],\n\t\t\t\t\t\t[0.2, 0.2],\n\t\t\t\t\t]\n\t\t\t\t).start();\n\t\t\t\ttransport.start(now);\n\t\t\t}, 0.4);\n\t\t\texpect(count).to.equal(3);\n\t\t});\n\n\t\tit(\"starts an event added after the part was started\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst part = new Part({\n\t\t\t\t\tevents: [[0, 0]],\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 0.2,\n\t\t\t\t\tcallback(time, value): void {\n\t\t\t\t\t\tif (value === 1) {\n\t\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t\treturn atTime(0.1, () => {\n\t\t\t\t\tpart.add(0.1, 1);\n\t\t\t\t});\n\t\t\t}, 0.6);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"can schedule a subpart\", async () => {\n\t\t\tlet invocations = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst startTime = 0.1;\n\t\t\t\tconst subPart = new Part({\n\t\t\t\t\tevents: [\n\t\t\t\t\t\t[0, 1],\n\t\t\t\t\t\t[0.3, 2],\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t\tconst part = new Part((time, value) => {\n\t\t\t\t\tinvocations++;\n\t\t\t\t\tif (value === 0) {\n\t\t\t\t\t\texpect(time - startTime).to.be.closeTo(0, 0.01);\n\t\t\t\t\t} else if (value === 1) {\n\t\t\t\t\t\texpect(time - startTime).to.be.closeTo(0.2, 0.01);\n\t\t\t\t\t} else if (value === 2) {\n\t\t\t\t\t\texpect(time - startTime).to.be.closeTo(0.5, 0.01);\n\t\t\t\t\t\tpart.dispose();\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t\t.add(0.2, subPart)\n\t\t\t\t\t.add(0, 0)\n\t\t\t\t\t.start(0);\n\t\t\t\ttransport.start(startTime);\n\t\t\t}, 0.7);\n\t\t\texpect(invocations).to.equal(3);\n\t\t});\n\n\t\tit(\"can start with an offset\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst startTime = 0.1;\n\t\t\t\tconst part = new Part(\n\t\t\t\t\t(time, number) => {\n\t\t\t\t\t\texpect(time - startTime).to.be.closeTo(0.1, 0.01);\n\t\t\t\t\t\texpect(number).to.equal(1);\n\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t},\n\t\t\t\t\t[\n\t\t\t\t\t\t[0, 0],\n\t\t\t\t\t\t[1, 1],\n\t\t\t\t\t]\n\t\t\t\t).start(0, 0.9);\n\t\t\t\ttransport.start(startTime);\n\t\t\t}, 0.3);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\t});\n\n\tcontext(\"Looping\", () => {\n\t\tit(\"can be set using a boolean as an argument when created\", async () => {\n\t\t\tlet callCount = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tnew Part({\n\t\t\t\t\tevents: [\n\t\t\t\t\t\t[0, 1],\n\t\t\t\t\t\t[0.1, 2],\n\t\t\t\t\t],\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 0.2,\n\t\t\t\t\tcallback(): void {\n\t\t\t\t\t\tcallCount++;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.55);\n\t\t\texpect(callCount).to.equal(6);\n\t\t});\n\n\t\tit(\"can be toggled off using a boolean\", async () => {\n\t\t\tlet callCount = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst part = new Part({\n\t\t\t\t\tevents: [\n\t\t\t\t\t\t[0, 1],\n\t\t\t\t\t\t[0.1, 2],\n\t\t\t\t\t],\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 0.2,\n\t\t\t\t\tcallback(): void {\n\t\t\t\t\t\tcallCount++;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\tpart.loop = false;\n\t\t\t\ttransport.start();\n\t\t\t}, 0.55);\n\t\t\texpect(callCount).to.equal(2);\n\t\t});\n\n\t\tit(\"can be toggled on using a boolean\", async () => {\n\t\t\tlet callCount = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst part = new Part({\n\t\t\t\t\tevents: [\n\t\t\t\t\t\t[0, 1],\n\t\t\t\t\t\t[0.1, 2],\n\t\t\t\t\t],\n\t\t\t\t\tloop: false,\n\t\t\t\t\tloopEnd: 0.2,\n\t\t\t\t\tcallback(): void {\n\t\t\t\t\t\tcallCount++;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\tpart.loop = true;\n\t\t\t\ttransport.start();\n\t\t\t}, 0.55);\n\t\t\texpect(callCount).to.equal(6);\n\t\t});\n\n\t\tit(\"can be set to loop at a specific interval\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tlet lastCall;\n\t\t\t\tconst part = new Part({\n\t\t\t\t\tevents: [0],\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 0.25,\n\t\t\t\t\tcallback(time): void {\n\t\t\t\t\t\tif (lastCall) {\n\t\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t\t\texpect(time - lastCall).to.be.closeTo(0.25, 0.01);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlastCall = time;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.7);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"a started part will be stopped if it is after the loopEnd\", async () => {\n\t\t\tlet invoked = true;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tlet switched = false;\n\t\t\t\tconst part = new Part({\n\t\t\t\t\tevents: [\n\t\t\t\t\t\t[0, 0],\n\t\t\t\t\t\t[0.25, 1],\n\t\t\t\t\t],\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 0.5,\n\t\t\t\t\tcallback(time, value): void {\n\t\t\t\t\t\tif (value === 1 && !switched) {\n\t\t\t\t\t\t\tswitched = true;\n\t\t\t\t\t\t\tpart.loopEnd = 0.2;\n\t\t\t\t\t\t} else if (switched) {\n\t\t\t\t\t\t\texpect(value).to.equal(0);\n\t\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.7);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"a started part will be stopped if it is before the loopStart\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tlet switched = false;\n\t\t\t\tconst part = new Part({\n\t\t\t\t\tevents: [\n\t\t\t\t\t\t[0, 0],\n\t\t\t\t\t\t[0.25, 1],\n\t\t\t\t\t],\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 0.5,\n\t\t\t\t\tcallback(time, value): void {\n\t\t\t\t\t\tif (value === 1 && !switched) {\n\t\t\t\t\t\t\tswitched = true;\n\t\t\t\t\t\t\tpart.loopStart = 0.2;\n\t\t\t\t\t\t} else if (switched) {\n\t\t\t\t\t\t\texpect(value).to.equal(1);\n\t\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.7);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"can loop a specific number of times\", async () => {\n\t\t\tlet callCount = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tnew Part({\n\t\t\t\t\tevents: [0, 0.1],\n\t\t\t\t\tloop: 3,\n\t\t\t\t\tloopEnd: 0.125,\n\t\t\t\t\tcallback(): void {\n\t\t\t\t\t\tcallCount++;\n\t\t\t\t\t},\n\t\t\t\t}).start(0.1);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.8);\n\t\t\texpect(callCount).to.equal(6);\n\t\t});\n\n\t\tit(\"can loop a specific number of times (different set order)\", async () => {\n\t\t\tlet callCount = 0;\n\t\t\tconst times = [0.1, 0.2, 0.4, 0.5];\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst part = new Part({\n\t\t\t\t\tevents: [0, 0.1],\n\t\t\t\t\tcallback(time): void {\n\t\t\t\t\t\texpect(times[callCount]).to.be.closeTo(time, 0.01);\n\t\t\t\t\t\tcallCount++;\n\t\t\t\t\t},\n\t\t\t\t}).start(0.1);\n\t\t\t\tpart.loop = 2;\n\t\t\t\tpart.loopEnd = 0.3;\n\t\t\t\ttransport.start();\n\t\t\t}, 0.8);\n\t\t\texpect(callCount).to.equal(4);\n\t\t});\n\n\t\tit(\"plays once when loop is 1\", async () => {\n\t\t\tlet callCount = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tnew Part({\n\t\t\t\t\tevents: [0, 0.1],\n\t\t\t\t\tloop: 1,\n\t\t\t\t\tloopEnd: 0.125,\n\t\t\t\t\tcallback(): void {\n\t\t\t\t\t\tcallCount++;\n\t\t\t\t\t},\n\t\t\t\t}).start(0.1);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.8);\n\t\t\texpect(callCount).to.equal(2);\n\t\t});\n\n\t\tit(\"plays once when loop is 0\", async () => {\n\t\t\tlet callCount = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tnew Part({\n\t\t\t\t\tevents: [0, 0.1],\n\t\t\t\t\tloop: 0,\n\t\t\t\t\tloopEnd: 0.125,\n\t\t\t\t\tcallback(): void {\n\t\t\t\t\t\tcallCount++;\n\t\t\t\t\t},\n\t\t\t\t}).start(0.1);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.8);\n\t\t\texpect(callCount).to.equal(2);\n\t\t});\n\n\t\tit(\"plays once when loop is false\", async () => {\n\t\t\tlet callCount = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tnew Part({\n\t\t\t\t\tevents: [0, 0.1],\n\t\t\t\t\tloop: false,\n\t\t\t\t\tloopEnd: 0.125,\n\t\t\t\t\tcallback(): void {\n\t\t\t\t\t\tcallCount++;\n\t\t\t\t\t},\n\t\t\t\t}).start(0.1);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.8);\n\t\t\texpect(callCount).to.equal(2);\n\t\t});\n\n\t\tit(\"can loop between loopStart and loopEnd\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tnew Part({\n\t\t\t\t\tevents: [\n\t\t\t\t\t\t[0, 0],\n\t\t\t\t\t\t[\"8n\", 1],\n\t\t\t\t\t\t[\"8n + 16n\", 2],\n\t\t\t\t\t\t[\"4n\", 3],\n\t\t\t\t\t],\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: \"4n\",\n\t\t\t\t\tloopStart: \"8n\",\n\t\t\t\t\tcallback(time, value): void {\n\t\t\t\t\t\texpect(value).to.be.at.least(1);\n\t\t\t\t\t\texpect(value).to.be.at.most(2);\n\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.8);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"can be started and stopped multiple times\", async () => {\n\t\t\tlet eventTimeIndex = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst eventTimes = [\n\t\t\t\t\t[0.5, 0],\n\t\t\t\t\t[0.6, 1],\n\t\t\t\t\t[1.1, 0],\n\t\t\t\t\t[1.2, 1],\n\t\t\t\t\t[1.3, 2],\n\t\t\t\t\t[1.4, 0],\n\t\t\t\t\t[1.5, 1],\n\t\t\t\t\t[1.6, 2],\n\t\t\t\t];\n\t\t\t\tnew Part({\n\t\t\t\t\tevents: [\n\t\t\t\t\t\t[0, 0],\n\t\t\t\t\t\t[0.1, 1],\n\t\t\t\t\t\t[0.2, 2],\n\t\t\t\t\t],\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 0.3,\n\t\t\t\t\tloopStart: 0,\n\t\t\t\t\tcallback(time, value): void {\n\t\t\t\t\t\texpect(eventTimes.length).to.be.gt(eventTimeIndex);\n\t\t\t\t\t\texpect(eventTimes[eventTimeIndex][0]).to.be.closeTo(\n\t\t\t\t\t\t\ttime,\n\t\t\t\t\t\t\t0.05\n\t\t\t\t\t\t);\n\t\t\t\t\t\texpect(eventTimes[eventTimeIndex][1]).to.equal(value);\n\t\t\t\t\t\teventTimeIndex++;\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\t\t.start(0.3)\n\t\t\t\t\t.stop(0.81);\n\t\t\t\ttransport.start(0.2).stop(0.61).start(0.8);\n\t\t\t}, 2);\n\t\t\texpect(eventTimeIndex).to.equal(8);\n\t\t});\n\n\t\tit(\"can adjust the loopEnd times\", async () => {\n\t\t\tlet eventTimeIndex = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst eventTimes = [\n\t\t\t\t\t[0.5, 0],\n\t\t\t\t\t[0.6, 1],\n\t\t\t\t\t[1.1, 0],\n\t\t\t\t\t[1.2, 1],\n\t\t\t\t\t[1.3, 2],\n\t\t\t\t\t[1.4, 0],\n\t\t\t\t\t[1.5, 1],\n\t\t\t\t\t[1.6, 2],\n\t\t\t\t];\n\t\t\t\tconst part = new Part({\n\t\t\t\t\tevents: [\n\t\t\t\t\t\t[0, 0],\n\t\t\t\t\t\t[0.1, 1],\n\t\t\t\t\t\t[0.2, 2],\n\t\t\t\t\t],\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 0.2,\n\t\t\t\t\tloopStart: 0,\n\t\t\t\t\tcallback(time, value): void {\n\t\t\t\t\t\texpect(eventTimes.length).to.be.gt(eventTimeIndex);\n\t\t\t\t\t\texpect(eventTimes[eventTimeIndex][0]).to.be.closeTo(\n\t\t\t\t\t\t\ttime,\n\t\t\t\t\t\t\t0.05\n\t\t\t\t\t\t);\n\t\t\t\t\t\texpect(eventTimes[eventTimeIndex][1]).to.equal(value);\n\t\t\t\t\t\teventTimeIndex++;\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\t\t.start(0.3)\n\t\t\t\t\t.stop(0.81);\n\t\t\t\tpart.loopEnd = 0.4;\n\t\t\t\tpart.loopEnd = 0.3;\n\t\t\t\ttransport.start(0.2).stop(0.61).start(0.8);\n\t\t\t}, 2);\n\t\t\texpect(eventTimeIndex).to.equal(8);\n\t\t});\n\n\t\tit(\"reports the progress of the loop\", async () => {\n\t\t\tlet callCount = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst part = new Part({\n\t\t\t\t\tevents: [0],\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 1,\n\t\t\t\t\tloopStart: 0,\n\t\t\t\t\tcallback(): void {\n\t\t\t\t\t\tcallCount++;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start(0);\n\t\t\t\treturn (time) => {\n\t\t\t\t\texpect(part.progress).to.be.closeTo(time, 0.01);\n\t\t\t\t};\n\t\t\t}, 0.8);\n\t\t\texpect(callCount).to.equal(1);\n\t\t});\n\n\t\tit(\"can start a loop with an offset\", async () => {\n\t\t\tlet iteration = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst now = transport.now();\n\t\t\t\tconst part = new Part(\n\t\t\t\t\t(time, number) => {\n\t\t\t\t\t\tif (iteration === 0) {\n\t\t\t\t\t\t\texpect(number).to.equal(1);\n\t\t\t\t\t\t\texpect(time - now).to.be.closeTo(0.2, 0.05);\n\t\t\t\t\t\t} else if (iteration === 1) {\n\t\t\t\t\t\t\texpect(number).to.equal(0);\n\t\t\t\t\t\t}\n\t\t\t\t\t\titeration++;\n\t\t\t\t\t},\n\t\t\t\t\t[\n\t\t\t\t\t\t[0, 0],\n\t\t\t\t\t\t[0.25, 1],\n\t\t\t\t\t]\n\t\t\t\t);\n\t\t\t\tpart.loop = true;\n\t\t\t\tpart.loopEnd = 0.5;\n\t\t\t\tpart.start(0, 1.05);\n\t\t\t\ttransport.start(0);\n\t\t\t}, 0.6);\n\t\t\texpect(iteration).to.equal(2);\n\t\t});\n\n\t\tit(\"can start a loop with an offset before loop start\", async () => {\n\t\t\tlet iteration = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst part = new Part(\n\t\t\t\t\t(time, number) => {\n\t\t\t\t\t\tif (iteration === 0) {\n\t\t\t\t\t\t\texpect(number).to.equal(0);\n\t\t\t\t\t\t} else if (iteration === 1) {\n\t\t\t\t\t\t\texpect(number).to.equal(1);\n\t\t\t\t\t\t} else if (iteration === 2) {\n\t\t\t\t\t\t\texpect(number).to.equal(2);\n\t\t\t\t\t\t} else if (iteration === 3) {\n\t\t\t\t\t\t\texpect(number).to.equal(1);\n\t\t\t\t\t\t} else if (iteration === 4) {\n\t\t\t\t\t\t\texpect(number).to.equal(2);\n\t\t\t\t\t\t}\n\t\t\t\t\t\titeration++;\n\t\t\t\t\t},\n\t\t\t\t\t[\n\t\t\t\t\t\t[0, 0],\n\t\t\t\t\t\t[0.25, 1],\n\t\t\t\t\t\t[0.3, 2],\n\t\t\t\t\t]\n\t\t\t\t);\n\t\t\t\tpart.loop = true;\n\t\t\t\tpart.loopStart = 0.25;\n\t\t\t\tpart.loopEnd = 0.5;\n\t\t\t\tpart.start(0, 0);\n\t\t\t\ttransport.start(part.now());\n\t\t\t}, 0.7);\n\t\t\texpect(iteration).to.equal(5);\n\t\t});\n\t});\n\n\tcontext(\"playbackRate\", () => {\n\t\tit(\"can adjust the playbackRate\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tlet lastCall;\n\t\t\t\tnew Part({\n\t\t\t\t\tevents: [0, 0.5],\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 1,\n\t\t\t\t\tplaybackRate: 2,\n\t\t\t\t\tcallback(time): void {\n\t\t\t\t\t\tif (lastCall) {\n\t\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t\t\texpect(time - lastCall).to.be.closeTo(0.25, 0.01);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlastCall = time;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start(0);\n\t\t\t}, 0.7);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"can adjust the playbackRate after starting\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tlet lastCall;\n\t\t\t\tconst part = new Part({\n\t\t\t\t\tevents: [0, 0.25],\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 0.5,\n\t\t\t\t\tplaybackRate: 1,\n\t\t\t\t\tcallback(time): void {\n\t\t\t\t\t\tif (lastCall) {\n\t\t\t\t\t\t\texpect(time - lastCall).to.be.closeTo(0.5, 0.01);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t\t\tpart.playbackRate = 0.5;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlastCall = time;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start(0);\n\t\t\t}, 0.8);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\t});\n\n\tcontext(\"scheduling\", () => {\n\t\tit(\"throws an error if events are scheduling in the wrong order\", () => {\n\t\t\tconst part = new Part();\n\t\t\tpart.start(1);\n\t\t\texpect(() => {\n\t\t\t\tpart.start(0);\n\t\t\t}).to.throw(Error);\n\t\t\tpart.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/event/Part.ts",
    "content": "import { TicksClass } from \"../core/type/Ticks.js\";\nimport { TransportTimeClass } from \"../core/type/TransportTime.js\";\nimport {\n\tNormalRange,\n\tPositive,\n\tSeconds,\n\tTicks,\n\tTime,\n\tTransportTime,\n} from \"../core/type/Units.js\";\nimport { defaultArg, optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { StateTimeline } from \"../core/util/StateTimeline.js\";\nimport {\n\tisArray,\n\tisDefined,\n\tisObject,\n\tisUndef,\n} from \"../core/util/TypeCheck.js\";\nimport { ToneEvent, ToneEventCallback, ToneEventOptions } from \"./ToneEvent.js\";\n\ntype CallbackType<T> = T extends {\n\ttime: Time;\n\t[key: string]: any;\n}\n\t? T\n\t: T extends ArrayLike<any>\n\t\t? T[1]\n\t\t: T extends Time\n\t\t\t? null\n\t\t\t: never;\n\ninterface PartOptions<T>\n\textends Omit<ToneEventOptions<CallbackType<T>>, \"value\"> {\n\tevents: T[];\n}\n\n/**\n * Part is a collection ToneEvents which can be started/stopped and looped as a single unit.\n *\n * @example\n * const synth = new Tone.Synth().toDestination();\n * const part = new Tone.Part(((time, note) => {\n * \t// the notes given as the second element in the array\n * \t// will be passed in as the second argument\n * \tsynth.triggerAttackRelease(note, \"8n\", time);\n * }), [[0, \"C2\"], [\"0:2\", \"C3\"], [\"0:3:2\", \"G2\"]]).start(0);\n * Tone.Transport.start();\n * @example\n * const synth = new Tone.Synth().toDestination();\n * // use an array of objects as long as the object has a \"time\" attribute\n * const part = new Tone.Part(((time, value) => {\n * \t// the value is an object which contains both the note and the velocity\n * \tsynth.triggerAttackRelease(value.note, \"8n\", time, value.velocity);\n * }), [{ time: 0, note: \"C3\", velocity: 0.9 },\n * \t{ time: \"0:2\", note: \"C4\", velocity: 0.5 }\n * ]).start(0);\n * Tone.Transport.start();\n * @category Event\n */\nexport class Part<ValueType = any> extends ToneEvent<ValueType> {\n\treadonly name: string = \"Part\";\n\n\t/**\n\t * Tracks the scheduled events\n\t */\n\tprotected _state: StateTimeline<{\n\t\tid: number;\n\t\toffset: number;\n\t}> = new StateTimeline(\"stopped\");\n\n\t/**\n\t * The events that belong to this part\n\t */\n\tprivate _events: Set<ToneEvent> = new Set();\n\n\t/**\n\t * @param callback The callback to invoke on each event\n\t * @param value the array of events\n\t */\n\tconstructor(\n\t\tcallback?: ToneEventCallback<CallbackType<ValueType>>,\n\t\tvalue?: ValueType[]\n\t);\n\tconstructor(options?: Partial<PartOptions<ValueType>>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Part.getDefaults(), arguments, [\n\t\t\t\"callback\",\n\t\t\t\"events\",\n\t\t]);\n\t\tsuper(options);\n\n\t\t// make sure things are assigned in the right order\n\t\tthis._state.increasing = true;\n\n\t\t// add the events\n\t\toptions.events.forEach((event) => {\n\t\t\tif (isArray(event)) {\n\t\t\t\tthis.add(event[0], event[1]);\n\t\t\t} else {\n\t\t\t\tthis.add(event);\n\t\t\t}\n\t\t});\n\t}\n\n\tstatic getDefaults(): PartOptions<any> {\n\t\treturn Object.assign(ToneEvent.getDefaults(), {\n\t\t\tevents: [],\n\t\t});\n\t}\n\n\t/**\n\t * Start the part at the given time.\n\t * @param  time    When to start the part.\n\t * @param  offset  The offset from the start of the part to begin playing at.\n\t */\n\tstart(time?: TransportTime, offset?: Time): this {\n\t\tconst ticks = this.toTicks(time);\n\t\tif (this._state.getValueAtTime(ticks) !== \"started\") {\n\t\t\toffset = defaultArg(offset, this._loop ? this._loopStart : 0);\n\t\t\tif (this._loop) {\n\t\t\t\toffset = defaultArg(offset, this._loopStart);\n\t\t\t} else {\n\t\t\t\toffset = defaultArg(offset, 0);\n\t\t\t}\n\t\t\tconst computedOffset = this.toTicks(offset);\n\t\t\tthis._state.add({\n\t\t\t\tid: -1,\n\t\t\t\toffset: computedOffset,\n\t\t\t\tstate: \"started\",\n\t\t\t\ttime: ticks,\n\t\t\t});\n\t\t\tthis._forEach((event) => {\n\t\t\t\tthis._startNote(event, ticks, computedOffset);\n\t\t\t});\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Start the event in the given event at the correct time given\n\t * the ticks and offset and looping.\n\t * @param  event\n\t * @param  ticks\n\t * @param  offset\n\t */\n\tprivate _startNote(event: ToneEvent, ticks: Ticks, offset: Ticks): void {\n\t\tticks -= offset;\n\t\tif (this._loop) {\n\t\t\tif (\n\t\t\t\tevent.startOffset >= this._loopStart &&\n\t\t\t\tevent.startOffset < this._loopEnd\n\t\t\t) {\n\t\t\t\tif (event.startOffset < offset) {\n\t\t\t\t\t// start it on the next loop\n\t\t\t\t\tticks += this._getLoopDuration();\n\t\t\t\t}\n\t\t\t\tevent.start(new TicksClass(this.context, ticks));\n\t\t\t} else if (\n\t\t\t\tevent.startOffset < this._loopStart &&\n\t\t\t\tevent.startOffset >= offset\n\t\t\t) {\n\t\t\t\tevent.loop = false;\n\t\t\t\tevent.start(new TicksClass(this.context, ticks));\n\t\t\t}\n\t\t} else if (event.startOffset >= offset) {\n\t\t\tevent.start(new TicksClass(this.context, ticks));\n\t\t}\n\t}\n\n\tget startOffset(): Ticks {\n\t\treturn this._startOffset;\n\t}\n\tset startOffset(offset) {\n\t\tthis._startOffset = offset;\n\t\tthis._forEach((event) => {\n\t\t\tevent.startOffset += this._startOffset;\n\t\t});\n\t}\n\n\t/**\n\t * Stop the part at the given time.\n\t * @param  time  When to stop the part.\n\t */\n\tstop(time?: TransportTime): this {\n\t\tconst ticks = this.toTicks(time);\n\t\tthis._state.cancel(ticks);\n\t\tthis._state.setStateAtTime(\"stopped\", ticks);\n\t\tthis._forEach((event) => {\n\t\t\tevent.stop(time);\n\t\t});\n\t\treturn this;\n\t}\n\n\t/**\n\t * Get/Set an Event's value at the given time.\n\t * If a value is passed in and no event exists at\n\t * the given time, one will be created with that value.\n\t * If two events are at the same time, the first one will\n\t * be returned.\n\t * @example\n\t * const part = new Tone.Part();\n\t * part.at(\"1m\"); // returns the part at the first measure\n\t * part.at(\"2m\", \"C2\"); // set the value at \"2m\" to C2.\n\t * // if an event didn't exist at that time, it will be created.\n\t * @param time The time of the event to get or set.\n\t * @param value If a value is passed in, the value of the event at the given time will be set to it.\n\t */\n\tat(time: Time, value?: any): ToneEvent | null {\n\t\tconst timeInTicks = new TransportTimeClass(\n\t\t\tthis.context,\n\t\t\ttime\n\t\t).toTicks();\n\t\tconst tickTime = new TicksClass(this.context, 1).toSeconds();\n\n\t\tconst iterator = this._events.values();\n\t\tlet result = iterator.next();\n\t\twhile (!result.done) {\n\t\t\tconst event = result.value;\n\t\t\tif (Math.abs(timeInTicks - event.startOffset) < tickTime) {\n\t\t\t\tif (isDefined(value)) {\n\t\t\t\t\tevent.value = value;\n\t\t\t\t}\n\t\t\t\treturn event;\n\t\t\t}\n\t\t\tresult = iterator.next();\n\t\t}\n\t\t// if there was no event at that time, create one\n\t\tif (isDefined(value)) {\n\t\t\tthis.add(time, value);\n\t\t\t// return the new event\n\t\t\treturn this.at(time);\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Add a an event to the part.\n\t * @param time The time the note should start. If an object is passed in, it should\n\t * \t\thave a 'time' attribute and the rest of the object will be used as the 'value'.\n\t * @param  value Any value to add to the timeline\n\t * @example\n\t * const part = new Tone.Part();\n\t * part.add(\"1m\", \"C#+11\");\n\t */\n\tadd(obj: { time: Time; [key: string]: any }): this;\n\tadd(time: Time, value?: any): this;\n\tadd(time: Time | object, value?: any): this {\n\t\t// extract the parameters\n\t\tif (time instanceof Object && Reflect.has(time, \"time\")) {\n\t\t\tvalue = time;\n\t\t\ttime = value.time;\n\t\t}\n\t\tconst ticks = this.toTicks(time);\n\t\tlet event: ToneEvent;\n\t\tif (value instanceof ToneEvent) {\n\t\t\tevent = value;\n\t\t\tevent.callback = this._tick.bind(this);\n\t\t} else {\n\t\t\tevent = new ToneEvent({\n\t\t\t\tcallback: this._tick.bind(this),\n\t\t\t\tcontext: this.context,\n\t\t\t\tvalue,\n\t\t\t});\n\t\t}\n\t\t// the start offset\n\t\tevent.startOffset = ticks;\n\n\t\t// initialize the values\n\t\tevent.set({\n\t\t\thumanize: this.humanize,\n\t\t\tloop: this.loop,\n\t\t\tloopEnd: this.loopEnd,\n\t\t\tloopStart: this.loopStart,\n\t\t\tplaybackRate: this.playbackRate,\n\t\t\tprobability: this.probability,\n\t\t});\n\n\t\tthis._events.add(event);\n\n\t\t// start the note if it should be played right now\n\t\tthis._restartEvent(event);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Restart the given event\n\t */\n\tprivate _restartEvent(event: ToneEvent): void {\n\t\tthis._state.forEach((stateEvent) => {\n\t\t\tif (stateEvent.state === \"started\") {\n\t\t\t\tthis._startNote(event, stateEvent.time, stateEvent.offset);\n\t\t\t} else {\n\t\t\t\t// stop the note\n\t\t\t\tevent.stop(new TicksClass(this.context, stateEvent.time));\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Remove an event from the part. If the event at that time is a Part,\n\t * it will remove the entire part.\n\t * @param time The time of the event\n\t * @param value Optionally select only a specific event value\n\t */\n\tremove(obj: { time: Time; [key: string]: any }): this;\n\tremove(time: Time, value?: any): this;\n\tremove(time: Time | object, value?: any): this {\n\t\t// extract the parameters\n\t\tif (isObject(time) && time.hasOwnProperty(\"time\")) {\n\t\t\tvalue = time;\n\t\t\ttime = value.time;\n\t\t}\n\t\ttime = this.toTicks(time);\n\t\tthis._events.forEach((event) => {\n\t\t\tif (event.startOffset === time) {\n\t\t\t\tif (\n\t\t\t\t\tisUndef(value) ||\n\t\t\t\t\t(isDefined(value) && event.value === value)\n\t\t\t\t) {\n\t\t\t\t\tthis._events.delete(event);\n\t\t\t\t\tevent.dispose();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove all of the notes from the group.\n\t */\n\tclear(): this {\n\t\tthis._forEach((event) => event.dispose());\n\t\tthis._events.clear();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Cancel scheduled state change events: i.e. \"start\" and \"stop\".\n\t * @param after The time after which to cancel the scheduled events.\n\t */\n\tcancel(after?: TransportTime | TransportTimeClass): this {\n\t\tthis._forEach((event) => event.cancel(after));\n\t\tthis._state.cancel(this.toTicks(after));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Iterate over all of the events\n\t */\n\tprivate _forEach(callback: (event: ToneEvent) => void): this {\n\t\tif (this._events) {\n\t\t\tthis._events.forEach((event) => {\n\t\t\t\tif (event instanceof Part) {\n\t\t\t\t\tevent._forEach(callback);\n\t\t\t\t} else {\n\t\t\t\t\tcallback(event);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set the attribute of all of the events\n\t * @param  attr  the attribute to set\n\t * @param  value      The value to set it to\n\t */\n\tprivate _setAll(attr: string, value: any): void {\n\t\tthis._forEach((event) => {\n\t\t\tevent[attr] = value;\n\t\t});\n\t}\n\n\t/**\n\t * Internal tick method\n\t * @param  time  The time of the event in seconds\n\t */\n\tprotected _tick(time: Seconds, value?: any): void {\n\t\tif (!this.mute) {\n\t\t\tthis.callback(time, value);\n\t\t}\n\t}\n\n\t/**\n\t * Determine if the event should be currently looping\n\t * given the loop boundaries of this Part.\n\t * @param  event  The event to test\n\t */\n\tprivate _testLoopBoundaries(event: ToneEvent): void {\n\t\tif (\n\t\t\tthis._loop &&\n\t\t\t(event.startOffset < this._loopStart ||\n\t\t\t\tevent.startOffset >= this._loopEnd)\n\t\t) {\n\t\t\tevent.cancel(0);\n\t\t} else if (event.state === \"stopped\") {\n\t\t\t// reschedule it if it's stopped\n\t\t\tthis._restartEvent(event);\n\t\t}\n\t}\n\n\tget probability(): NormalRange {\n\t\treturn this._probability;\n\t}\n\tset probability(prob) {\n\t\tthis._probability = prob;\n\t\tthis._setAll(\"probability\", prob);\n\t}\n\n\tget humanize(): boolean | Time {\n\t\treturn this._humanize;\n\t}\n\tset humanize(variation) {\n\t\tthis._humanize = variation;\n\t\tthis._setAll(\"humanize\", variation);\n\t}\n\n\t/**\n\t * If the part should loop or not\n\t * between Part.loopStart and\n\t * Part.loopEnd. If set to true,\n\t * the part will loop indefinitely,\n\t * if set to a number greater than 1\n\t * it will play a specific number of\n\t * times, if set to false, 0 or 1, the\n\t * part will only play once.\n\t * @example\n\t * const part = new Tone.Part();\n\t * // loop the part 8 times\n\t * part.loop = 8;\n\t */\n\tget loop(): boolean | number {\n\t\treturn this._loop;\n\t}\n\tset loop(loop) {\n\t\tthis._loop = loop;\n\t\tthis._forEach((event) => {\n\t\t\tevent.loopStart = this.loopStart;\n\t\t\tevent.loopEnd = this.loopEnd;\n\t\t\tevent.loop = loop;\n\t\t\tthis._testLoopBoundaries(event);\n\t\t});\n\t}\n\n\t/**\n\t * The loopEnd point determines when it will\n\t * loop if Part.loop is true.\n\t */\n\tget loopEnd(): Time {\n\t\treturn new TicksClass(this.context, this._loopEnd).toSeconds();\n\t}\n\tset loopEnd(loopEnd) {\n\t\tthis._loopEnd = this.toTicks(loopEnd);\n\t\tif (this._loop) {\n\t\t\tthis._forEach((event) => {\n\t\t\t\tevent.loopEnd = loopEnd;\n\t\t\t\tthis._testLoopBoundaries(event);\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * The loopStart point determines when it will\n\t * loop if Part.loop is true.\n\t */\n\tget loopStart(): Time {\n\t\treturn new TicksClass(this.context, this._loopStart).toSeconds();\n\t}\n\tset loopStart(loopStart) {\n\t\tthis._loopStart = this.toTicks(loopStart);\n\t\tif (this._loop) {\n\t\t\tthis._forEach((event) => {\n\t\t\t\tevent.loopStart = this.loopStart;\n\t\t\t\tthis._testLoopBoundaries(event);\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * The playback rate of the part\n\t */\n\tget playbackRate(): Positive {\n\t\treturn this._playbackRate;\n\t}\n\tset playbackRate(rate) {\n\t\tthis._playbackRate = rate;\n\t\tthis._setAll(\"playbackRate\", rate);\n\t}\n\n\t/**\n\t * The number of scheduled notes in the part.\n\t */\n\tget length(): number {\n\t\treturn this._events.size;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.clear();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/event/Pattern.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { Offline } from \"../../test/helper/Offline.js\";\nimport { Time } from \"../core/type/Time.js\";\nimport { Pattern } from \"./Pattern.js\";\n\ndescribe(\"Pattern\", () => {\n\tBasicTests(Pattern);\n\n\tcontext(\"Constructor\", () => {\n\t\tit(\"takes a callback, an array of values and a pattern name\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst callback = function () {};\n\t\t\t\tconst pattern = new Pattern(callback, [0, 1, 2, 3], \"down\");\n\t\t\t\texpect(pattern.callback).to.equal(callback);\n\t\t\t\texpect(pattern.values).to.deep.equal([0, 1, 2, 3]);\n\t\t\t\texpect(pattern.pattern).to.equal(\"down\");\n\t\t\t\tpattern.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can be constructed with no arguments\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst pattern = new Pattern();\n\t\t\t\tpattern.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can pass in arguments in options object\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst callback = function () {};\n\t\t\t\tconst pattern = new Pattern({\n\t\t\t\t\tcallback: callback,\n\t\t\t\t\titerations: 4,\n\t\t\t\t\tprobability: 0.3,\n\t\t\t\t\tinterval: \"8t\",\n\t\t\t\t\tvalues: [1, 2, 3],\n\t\t\t\t\tpattern: \"upDown\",\n\t\t\t\t});\n\t\t\t\texpect(pattern.callback).to.equal(callback);\n\t\t\t\texpect(pattern.interval.valueOf()).to.equal(\n\t\t\t\t\tTime(\"8t\").valueOf()\n\t\t\t\t);\n\t\t\t\texpect(pattern.iterations).to.equal(4);\n\t\t\t\texpect(pattern.values).to.deep.equal([1, 2, 3]);\n\t\t\t\texpect(pattern.probability).to.equal(0.3);\n\t\t\t\texpect(pattern.pattern).to.equal(\"upDown\");\n\t\t\t\tpattern.dispose();\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"Get/Set\", () => {\n\t\tit(\"can set values with object\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst callback = function () {};\n\t\t\t\tconst pattern = new Pattern();\n\t\t\t\tpattern.set({\n\t\t\t\t\tcallback: callback,\n\t\t\t\t\tvalues: [\"a\", \"b\", \"c\"],\n\t\t\t\t});\n\t\t\t\texpect(pattern.callback).to.equal(callback);\n\t\t\t\texpect(pattern.values).to.deep.equal([\"a\", \"b\", \"c\"]);\n\t\t\t\tpattern.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can set get a the values as an object\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst callback = function () {};\n\t\t\t\tconst pattern = new Pattern({\n\t\t\t\t\tcallback: callback,\n\t\t\t\t\tpattern: \"random\",\n\t\t\t\t\tprobability: 0.3,\n\t\t\t\t});\n\t\t\t\tconst values = pattern.get();\n\t\t\t\texpect(values.pattern).to.equal(\"random\");\n\t\t\t\tvalues.pattern = \"upDown\";\n\t\t\t\texpect(values.pattern).to.equal(\"upDown\");\n\t\t\t\texpect(values.probability).to.equal(0.3);\n\t\t\t\tpattern.dispose();\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"Callback\", () => {\n\t\tit(\"is invoked after it's started\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst values = [\"a\", \"b\", \"c\"];\n\t\t\t\tlet index = 0;\n\t\t\t\tconst pattern = new Pattern(() => {\n\t\t\t\t\tinvoked = true;\n\t\t\t\t\texpect(pattern.value).to.equal(values[index]);\n\t\t\t\t\texpect(pattern.index).to.equal(index);\n\t\t\t\t\tindex++;\n\t\t\t\t}, values).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.2);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"passes in the scheduled time and pattern note to the callback\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst startTime = 0.05;\n\t\t\t\tconst pattern = new Pattern(\n\t\t\t\t\t(time, note) => {\n\t\t\t\t\t\texpect(time).to.be.a(\"number\");\n\t\t\t\t\t\texpect(time - startTime).to.be.closeTo(0.3, 0.01);\n\t\t\t\t\t\texpect(note).to.be.equal(\"a\");\n\t\t\t\t\t\texpect(pattern.value).to.equal(\"a\");\n\t\t\t\t\t\texpect(pattern.index).to.be.equal(0);\n\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t},\n\t\t\t\t\t[\"a\"],\n\t\t\t\t\t\"up\"\n\t\t\t\t);\n\t\t\t\ttransport.start(startTime);\n\t\t\t\tpattern.start(0.3);\n\t\t\t}, 0.4);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"passes in the next note of the pattern\", async () => {\n\t\t\tlet counter = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst values = [\"a\", \"b\", \"c\"];\n\t\t\t\tconst pattern = new Pattern(\n\t\t\t\t\t(time, note) => {\n\t\t\t\t\t\texpect(note).to.equal(values[counter % 3]);\n\t\t\t\t\t\texpect(pattern.value).to.equal(values[counter % 3]);\n\t\t\t\t\t\texpect(pattern.index).to.be.equal(counter % 3);\n\t\t\t\t\t\tcounter++;\n\t\t\t\t\t},\n\t\t\t\t\tvalues,\n\t\t\t\t\t\"up\"\n\t\t\t\t).start(0);\n\t\t\t\tpattern.interval = \"16n\";\n\t\t\t\ttransport.start(0);\n\t\t\t}, 0.7);\n\t\t\texpect(counter).to.equal(6);\n\t\t});\n\n\t\tit(\"can modify the pattern type and values\", async () => {\n\t\t\tlet counter = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst values = [\"a\", \"b\", \"c\"];\n\t\t\t\tconst pattern = new Pattern(\n\t\t\t\t\t(time, note) => {\n\t\t\t\t\t\texpect(note).to.equal(values[counter % 3]);\n\t\t\t\t\t\texpect(pattern.value).to.equal(values[counter % 3]);\n\t\t\t\t\t\texpect(pattern.index).to.be.equal(counter % 3);\n\t\t\t\t\t\tcounter++;\n\t\t\t\t\t},\n\t\t\t\t\t[\"a\"],\n\t\t\t\t\t\"down\"\n\t\t\t\t).start(0);\n\t\t\t\tpattern.interval = \"16n\";\n\t\t\t\tpattern.pattern = \"up\";\n\t\t\t\tpattern.values = values;\n\t\t\t\ttransport.start(0);\n\t\t\t}, 0.7);\n\t\t\texpect(counter).to.equal(6);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/event/Pattern.ts",
    "content": "import { Seconds } from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { noOp } from \"../core/util/Interface.js\";\nimport { Loop, LoopOptions } from \"./Loop.js\";\nimport { PatternGenerator, PatternName } from \"./PatternGenerator.js\";\nimport { ToneEventCallback } from \"./ToneEvent.js\";\n\nexport interface PatternOptions<ValueType> extends LoopOptions {\n\tpattern: PatternName;\n\tvalues: ValueType[];\n\tcallback: (time: Seconds, value?: ValueType) => void;\n}\n\n/**\n * Pattern arpeggiates between the given notes\n * in a number of patterns.\n * @example\n * const pattern = new Tone.Pattern((time, note) => {\n * \t// the order of the notes passed in depends on the pattern\n * }, [\"C2\", \"D4\", \"E5\", \"A6\"], \"upDown\");\n * @category Event\n */\nexport class Pattern<ValueType> extends Loop<PatternOptions<ValueType>> {\n\treadonly name: string = \"Pattern\";\n\n\t/**\n\t * The pattern generator function\n\t */\n\tprivate _pattern: Iterator<number>;\n\n\t/**\n\t * The current index\n\t */\n\tprivate _index?: number;\n\n\t/**\n\t * The current value\n\t */\n\tprivate _value?: ValueType;\n\n\t/**\n\t * Hold the pattern type\n\t */\n\tprivate _type: PatternName;\n\n\t/**\n\t * Hold the values\n\t */\n\tprivate _values: ValueType[];\n\n\t/**\n\t * The callback to be invoked at a regular interval\n\t */\n\tcallback: (time: Seconds, value?: ValueType) => void;\n\n\t/**\n\t * @param  callback The callback to invoke with the event.\n\t * @param  values The values to arpeggiate over.\n\t * @param  pattern  The name of the pattern\n\t */\n\tconstructor(\n\t\tcallback?: ToneEventCallback<ValueType>,\n\t\tvalues?: ValueType[],\n\t\tpattern?: PatternName\n\t);\n\tconstructor(options?: Partial<PatternOptions<ValueType>>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Pattern.getDefaults(), arguments, [\n\t\t\t\"callback\",\n\t\t\t\"values\",\n\t\t\t\"pattern\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis.callback = options.callback;\n\t\tthis._values = options.values;\n\t\tthis._pattern = PatternGenerator(\n\t\t\toptions.values.length,\n\t\t\toptions.pattern\n\t\t);\n\t\tthis._type = options.pattern;\n\t}\n\n\tstatic getDefaults(): PatternOptions<any> {\n\t\treturn Object.assign(Loop.getDefaults(), {\n\t\t\tpattern: \"up\" as const,\n\t\t\tvalues: [],\n\t\t\tcallback: noOp,\n\t\t});\n\t}\n\n\t/**\n\t * Internal function called when the notes should be called\n\t */\n\tprotected _tick(time: Seconds): void {\n\t\tconst index = this._pattern.next() as IteratorResult<ValueType>;\n\t\tthis._index = index.value;\n\t\tthis._value = this._values[index.value];\n\t\tthis.callback(time, this._value);\n\t}\n\n\t/**\n\t * The array of events.\n\t */\n\tget values(): ValueType[] {\n\t\treturn this._values;\n\t}\n\tset values(val) {\n\t\tthis._values = val;\n\t\t// reset the pattern\n\t\tthis.pattern = this._type;\n\t}\n\n\t/**\n\t * The current value of the pattern.\n\t */\n\tget value(): ValueType | undefined {\n\t\treturn this._value;\n\t}\n\n\t/**\n\t * The current index of the pattern.\n\t */\n\tget index(): number | undefined {\n\t\treturn this._index;\n\t}\n\n\t/**\n\t * The pattern type.\n\t */\n\tget pattern(): PatternName {\n\t\treturn this._type;\n\t}\n\tset pattern(pattern) {\n\t\tthis._type = pattern;\n\t\tthis._pattern = PatternGenerator(this._values.length, this._type);\n\t}\n}\n"
  },
  {
    "path": "Tone/event/PatternGenerator.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { PatternGenerator } from \"./PatternGenerator.js\";\n\ndescribe(\"PatternGenerator\", () => {\n\tfunction getArrayValues(gen: Iterator<any>, length: number): any[] {\n\t\tconst ret: any[] = [];\n\t\tfor (let i = 0; i < length; i++) {\n\t\t\tret.push(gen.next().value);\n\t\t}\n\t\treturn ret;\n\t}\n\n\tcontext(\"API\", () => {\n\t\tit(\"can be constructed with an number and type\", () => {\n\t\t\tconst pattern = PatternGenerator(4, \"down\");\n\t\t\texpect(getArrayValues(pattern, 10)).to.deep.equal([\n\t\t\t\t3, 2, 1, 0, 3, 2, 1, 0, 3, 2,\n\t\t\t]);\n\t\t});\n\n\t\tit(\"throws an error with a number less than 1\", () => {\n\t\t\texpect(() => {\n\t\t\t\tconst pattern = PatternGenerator(0);\n\t\t\t\tpattern.next();\n\t\t\t}).to.throw(Error);\n\t\t});\n\t});\n\n\tcontext(\"Patterns\", () => {\n\t\tit(\"does the up pattern\", () => {\n\t\t\tconst pattern = PatternGenerator(4, \"up\");\n\t\t\texpect(getArrayValues(pattern, 6)).to.deep.equal([\n\t\t\t\t0, 1, 2, 3, 0, 1,\n\t\t\t]);\n\t\t});\n\n\t\tit(\"does the down pattern\", () => {\n\t\t\tconst pattern = PatternGenerator(4, \"down\");\n\t\t\texpect(getArrayValues(pattern, 6)).to.deep.equal([\n\t\t\t\t3, 2, 1, 0, 3, 2,\n\t\t\t]);\n\t\t});\n\n\t\tit(\"does the upDown pattern\", () => {\n\t\t\tconst pattern = PatternGenerator(4, \"upDown\");\n\t\t\texpect(getArrayValues(pattern, 10)).to.deep.equal([\n\t\t\t\t0, 1, 2, 3, 2, 1, 0, 1, 2, 3,\n\t\t\t]);\n\t\t});\n\n\t\tit(\"does the downUp pattern\", () => {\n\t\t\tconst pattern = PatternGenerator(4, \"downUp\");\n\t\t\texpect(getArrayValues(pattern, 10)).to.deep.equal([\n\t\t\t\t3, 2, 1, 0, 1, 2, 3, 2, 1, 0,\n\t\t\t]);\n\t\t});\n\n\t\tit(\"does the alternateUp pattern\", () => {\n\t\t\tconst pattern = PatternGenerator(5, \"alternateUp\");\n\t\t\texpect(getArrayValues(pattern, 10)).to.deep.equal([\n\t\t\t\t0, 2, 1, 3, 2, 4, 3, 0, 2, 1,\n\t\t\t]);\n\t\t});\n\n\t\tit(\"does the alternateDown pattern\", () => {\n\t\t\tconst pattern = PatternGenerator(5, \"alternateDown\");\n\t\t\texpect(getArrayValues(pattern, 10)).to.deep.equal([\n\t\t\t\t4, 2, 3, 1, 2, 0, 1, 4, 2, 3,\n\t\t\t]);\n\t\t});\n\n\t\tit(\"outputs random elements from the values\", () => {\n\t\t\tconst numValues = 5;\n\t\t\tconst pattern = PatternGenerator(numValues, \"random\");\n\t\t\tfor (let i = 0; i < 10; i++) {\n\t\t\t\texpect(pattern.next().value)\n\t\t\t\t\t.to.be.at.least(0)\n\t\t\t\t\t.and.at.most(numValues - 1);\n\t\t\t}\n\t\t});\n\n\t\tit(\"does randomOnce pattern\", () => {\n\t\t\tconst pattern = PatternGenerator(5, \"randomOnce\");\n\t\t\texpect(getArrayValues(pattern, 10).sort()).to.deep.equal([\n\t\t\t\t0, 0, 1, 1, 2, 2, 3, 3, 4, 4,\n\t\t\t]);\n\t\t});\n\n\t\tit(\"randomly walks up or down 1 step without repeating\", () => {\n\t\t\tconst values = [0, 1, 2, 3, 4];\n\t\t\tconst pattern = PatternGenerator(5, \"randomWalk\");\n\t\t\tlet currentIndex = pattern.next().value;\n\t\t\tfor (let i = 0; i < 10; i++) {\n\t\t\t\tconst nextIndex = pattern.next().value;\n\t\t\t\texpect(currentIndex).to.not.equal(nextIndex);\n\t\t\t\t// change always equals 1\n\t\t\t\texpect(Math.abs(currentIndex - nextIndex)).to.equal(1);\n\t\t\t\tcurrentIndex = nextIndex;\n\t\t\t}\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/event/PatternGenerator.ts",
    "content": "import { assert } from \"../core/util/Debug.js\";\nimport { clamp } from \"../core/util/Math.js\";\n\n/**\n * The name of the patterns\n */\nexport type PatternName =\n\t| \"up\"\n\t| \"down\"\n\t| \"upDown\"\n\t| \"downUp\"\n\t| \"alternateUp\"\n\t| \"alternateDown\"\n\t| \"random\"\n\t| \"randomOnce\"\n\t| \"randomWalk\";\n\n/**\n * Start at the first value and go up to the last\n */\nfunction* upPatternGen(numValues: number): IterableIterator<number> {\n\tlet index = 0;\n\twhile (index < numValues) {\n\t\tindex = clamp(index, 0, numValues - 1);\n\t\tyield index;\n\t\tindex++;\n\t}\n}\n\n/**\n * Start at the last value and go down to 0\n */\nfunction* downPatternGen(numValues: number): IterableIterator<number> {\n\tlet index = numValues - 1;\n\twhile (index >= 0) {\n\t\tindex = clamp(index, 0, numValues - 1);\n\t\tyield index;\n\t\tindex--;\n\t}\n}\n\n/**\n * Infinitely yield the generator\n */\nfunction* infiniteGen(\n\tnumValues: number,\n\tgen: typeof upPatternGen\n): IterableIterator<number> {\n\twhile (true) {\n\t\tyield* gen(numValues);\n\t}\n}\n\n/**\n * Alternate between two generators\n */\nfunction* alternatingGenerator(\n\tnumValues: number,\n\tdirectionUp: boolean\n): IterableIterator<number> {\n\tlet index = directionUp ? 0 : numValues - 1;\n\twhile (true) {\n\t\tindex = clamp(index, 0, numValues - 1);\n\t\tyield index;\n\t\tif (directionUp) {\n\t\t\tindex++;\n\t\t\tif (index >= numValues - 1) {\n\t\t\t\tdirectionUp = false;\n\t\t\t}\n\t\t} else {\n\t\t\tindex--;\n\t\t\tif (index <= 0) {\n\t\t\t\tdirectionUp = true;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Starting from the bottom move up 2, down 1\n */\nfunction* jumpUp(numValues: number): IterableIterator<number> {\n\tlet index = 0;\n\tlet stepIndex = 0;\n\twhile (index < numValues) {\n\t\tindex = clamp(index, 0, numValues - 1);\n\t\tyield index;\n\t\tstepIndex++;\n\t\tindex += stepIndex % 2 ? 2 : -1;\n\t}\n}\n\n/**\n * Starting from the top move down 2, up 1\n */\nfunction* jumpDown(numValues: number): IterableIterator<number> {\n\tlet index = numValues - 1;\n\tlet stepIndex = 0;\n\twhile (index >= 0) {\n\t\tindex = clamp(index, 0, numValues - 1);\n\t\tyield index;\n\t\tstepIndex++;\n\t\tindex += stepIndex % 2 ? -2 : 1;\n\t}\n}\n\n/**\n * Choose a random index each time\n */\nfunction* randomGen(numValues: number): IterableIterator<number> {\n\twhile (true) {\n\t\tconst randomIndex = Math.floor(Math.random() * numValues);\n\t\tyield randomIndex;\n\t}\n}\n\n/**\n * Randomly go through all of the values once before choosing a new random order\n */\nfunction* randomOnce(numValues: number): IterableIterator<number> {\n\t// create an array of indices\n\tconst copy: number[] = [];\n\tfor (let i = 0; i < numValues; i++) {\n\t\tcopy.push(i);\n\t}\n\twhile (copy.length > 0) {\n\t\t// random choose an index, and then remove it so it's not chosen again\n\t\tconst randVal = copy.splice(Math.floor(copy.length * Math.random()), 1);\n\t\tconst index = clamp(randVal[0], 0, numValues - 1);\n\t\tyield index;\n\t}\n}\n\n/**\n * Randomly choose to walk up or down 1 index\n */\nfunction* randomWalk(numValues: number): IterableIterator<number> {\n\t// randomly choose a starting index\n\tlet index = Math.floor(Math.random() * numValues);\n\twhile (true) {\n\t\tif (index === 0) {\n\t\t\tindex++; // at bottom, so force upward step\n\t\t} else if (index === numValues - 1) {\n\t\t\tindex--; // at top, so force downward step\n\t\t} else if (Math.random() < 0.5) {\n\t\t\t// else choose random downward or upward step\n\t\t\tindex--;\n\t\t} else {\n\t\t\tindex++;\n\t\t}\n\t\tyield index;\n\t}\n}\n\n/**\n * PatternGenerator returns a generator which will yield numbers between 0 and numValues\n * according to the passed in pattern that can be used as indexes into an array of size numValues.\n * @param numValues The size of the array to emit indexes for\n * @param pattern The name of the pattern use when iterating over\n */\nexport function* PatternGenerator(\n\tnumValues: number,\n\tpattern: PatternName = \"up\"\n): Iterator<number> {\n\t// safeguards\n\tassert(numValues >= 1, \"The number of values must be at least one\");\n\tswitch (pattern) {\n\t\tcase \"up\":\n\t\t\tyield* infiniteGen(numValues, upPatternGen);\n\t\tcase \"down\":\n\t\t\tyield* infiniteGen(numValues, downPatternGen);\n\t\tcase \"upDown\":\n\t\t\tyield* alternatingGenerator(numValues, true);\n\t\tcase \"downUp\":\n\t\t\tyield* alternatingGenerator(numValues, false);\n\t\tcase \"alternateUp\":\n\t\t\tyield* infiniteGen(numValues, jumpUp);\n\t\tcase \"alternateDown\":\n\t\t\tyield* infiniteGen(numValues, jumpDown);\n\t\tcase \"random\":\n\t\t\tyield* randomGen(numValues);\n\t\tcase \"randomOnce\":\n\t\t\tyield* infiniteGen(numValues, randomOnce);\n\t\tcase \"randomWalk\":\n\t\t\tyield* randomWalk(numValues);\n\t}\n}\n"
  },
  {
    "path": "Tone/event/Sequence.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { atTime, Offline } from \"../../test/helper/Offline.js\";\nimport { Time } from \"../core/type/Time.js\";\nimport { noOp } from \"../core/util/Interface.js\";\nimport { Sequence } from \"./Sequence.js\";\n\ndescribe(\"Sequence\", () => {\n\tBasicTests(Sequence);\n\n\tcontext(\"Constructor\", () => {\n\t\tit(\"takes a callback and a sequence of values\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst callback = noOp;\n\t\t\t\tconst seq = new Sequence(callback, [0, 1, 2]);\n\t\t\t\texpect(seq.callback).to.equal(callback);\n\t\t\t\texpect(seq.length).to.equal(3);\n\t\t\t\tseq.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"takes a callback and a sequence of values and a subdivision\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst callback = noOp;\n\t\t\t\tconst seq = new Sequence(callback, [0, 1, 2], \"2n\");\n\t\t\t\texpect(seq.callback).to.equal(callback);\n\t\t\t\texpect(seq.subdivision).to.equal(Time(\"2n\").valueOf());\n\t\t\t\texpect(seq.length).to.equal(3);\n\t\t\t\tseq.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can be constructed with no arguments\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst seq = new Sequence();\n\t\t\t\texpect(seq.length).to.equal(0);\n\t\t\t\tseq.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can pass in arguments in options object\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst callback = noOp;\n\t\t\t\tconst seq = new Sequence({\n\t\t\t\t\tcallback,\n\t\t\t\t\tevents: [0, 1, 2],\n\t\t\t\t\thumanize: true,\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 2,\n\t\t\t\t\tprobability: 0.3,\n\t\t\t\t});\n\t\t\t\texpect(seq.callback).to.equal(callback);\n\t\t\t\texpect(seq.length).to.equal(3);\n\t\t\t\texpect(seq.loop).to.be.true;\n\t\t\t\texpect(seq.loopEnd).to.equal(2);\n\t\t\t\texpect(seq.probability).to.equal(0.3);\n\t\t\t\texpect(seq.humanize).to.be.true;\n\t\t\t\tseq.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"loops by default with the loopEnd as the duration of the loop\", async () => {\n\t\t\tconst values: number[] = [];\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst seq = new Sequence(\n\t\t\t\t\t(_, value) => {\n\t\t\t\t\t\tvalues.push(value);\n\t\t\t\t\t},\n\t\t\t\t\t[0, 1, 2, 3],\n\t\t\t\t\t\"8n\"\n\t\t\t\t).start(0);\n\t\t\t\texpect(seq.loop).to.be.true;\n\t\t\t\texpect(seq.length).to.equal(4);\n\t\t\t\ttransport.start(0);\n\t\t\t}, 2);\n\t\t\texpect(values).to.deep.equal([0, 1, 2, 3, 0, 1, 2, 3]);\n\t\t});\n\t});\n\n\tcontext(\"Adding / Removing / Getting Events\", () => {\n\t\tit(\"can add an event using the index\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst seq = new Sequence();\n\t\t\t\tseq.events[0] = 0;\n\t\t\t\texpect(seq.length).to.equal(1);\n\t\t\t\tseq.events[1] = 1;\n\t\t\t\texpect(seq.length).to.equal(2);\n\t\t\t\tseq.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can add a subsequence\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst seq = new Sequence();\n\t\t\t\tseq.events = [[0, 1, 2]];\n\t\t\t\texpect(seq.length).to.equal(3);\n\t\t\t\tseq.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can retrieve an event using the index\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst seq = new Sequence(noOp, [0, 1, 2]);\n\t\t\t\texpect(seq.length).to.equal(3);\n\t\t\t\texpect(seq.events[0]).to.equal(0);\n\t\t\t\texpect(seq.events[1]).to.equal(1);\n\t\t\t\texpect(seq.events[2]).to.equal(2);\n\t\t\t\texpect(seq.events[3]).to.be.undefined;\n\t\t\t\tseq.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can set the value of an existing event with an index\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst seq = new Sequence(noOp, [0, 1, 2]);\n\t\t\t\texpect(seq.length).to.equal(3);\n\t\t\t\texpect(seq.events[0]).to.equal(0);\n\t\t\t\tseq.events[0] = 1;\n\t\t\t\texpect(seq.events[0]).to.equal(1);\n\t\t\t\tseq.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can remove an event by index\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst seq = new Sequence(noOp, [0, 1, 2]);\n\t\t\t\texpect(seq.length).to.equal(3);\n\t\t\t\tseq.events.splice(0, 1);\n\t\t\t\texpect(seq.length).to.equal(2);\n\t\t\t\tseq.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can add a subsequence and remove the entire subsequence\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst seq = new Sequence(noOp, [0, 1, 2]);\n\t\t\t\texpect(seq.length).to.equal(3);\n\t\t\t\tseq.events.shift();\n\t\t\t\tseq.events[0] = [1, 2];\n\t\t\t\texpect(seq.length).to.equal(3);\n\t\t\t\texpect(seq.events[0][0]).to.equal(1);\n\t\t\t\texpect(seq.events[0][1]).to.equal(2);\n\t\t\t\tseq.events.shift();\n\t\t\t\texpect(seq.length).to.equal(1);\n\t\t\t\texpect(seq.events[0]).to.equal(2);\n\t\t\t\tseq.events[0] = 4;\n\t\t\t\texpect(seq.events[0]).to.equal(4);\n\t\t\t\tseq.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can remove all of the events\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst seq = new Sequence(noOp, [0, 1, 2, 3, 4, 5]);\n\t\t\t\texpect(seq.length).to.equal(6);\n\t\t\t\tseq.clear();\n\t\t\t\texpect(seq.length).to.equal(0);\n\t\t\t\tseq.dispose();\n\t\t\t});\n\t\t});\n\t});\n\tcontext(\"Sequence callback\", () => {\n\t\tit(\"invokes the callback after it's started\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst seq = new Sequence(() => {\n\t\t\t\t\tseq.dispose();\n\t\t\t\t\tinvoked = true;\n\t\t\t\t}, [0, 1]).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.1);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"can be scheduled to stop\", async () => {\n\t\t\tlet invoked = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst seq = new Sequence(\n\t\t\t\t\t() => {\n\t\t\t\t\t\tinvoked++;\n\t\t\t\t\t},\n\t\t\t\t\t[0, 1],\n\t\t\t\t\t0.1\n\t\t\t\t)\n\t\t\t\t\t.start(0)\n\t\t\t\t\t.stop(0.5);\n\t\t\t\ttransport.start();\n\t\t\t}, 1);\n\t\t\texpect(invoked).to.equal(6);\n\t\t});\n\n\t\tit(\"passes in the scheduled time to the callback\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst now = 0.1;\n\t\t\t\tconst seq = new Sequence(\n\t\t\t\t\t(time) => {\n\t\t\t\t\t\texpect(time).to.be.a(\"number\");\n\t\t\t\t\t\texpect(time - now).to.be.closeTo(0.3, 0.01);\n\t\t\t\t\t\tseq.dispose();\n\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t},\n\t\t\t\t\t[0.5]\n\t\t\t\t);\n\t\t\t\tseq.start(0.3);\n\t\t\t\ttransport.start(now);\n\t\t\t}, 0.5);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"passes in the value to the callback\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst seq = new Sequence(\n\t\t\t\t\t(time, thing) => {\n\t\t\t\t\t\texpect(time).to.be.a(\"number\");\n\t\t\t\t\t\texpect(thing).to.equal(\"thing\");\n\t\t\t\t\t\tseq.dispose();\n\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t},\n\t\t\t\t\t[\"thing\"]\n\t\t\t\t).start();\n\t\t\t\ttransport.start();\n\t\t\t}, 0.1);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"invokes the scheduled events in the right order\", async () => {\n\t\t\tlet count = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst seq = new Sequence(\n\t\t\t\t\t(time, value) => {\n\t\t\t\t\t\texpect(value).to.equal(count);\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t},\n\t\t\t\t\t[0, [1, 2], [3, 4]],\n\t\t\t\t\t\"16n\"\n\t\t\t\t).start();\n\t\t\t\tseq.loop = false;\n\t\t\t\ttransport.start(0);\n\t\t\t}, 0.5);\n\t\t\texpect(count).to.equal(5);\n\t\t});\n\n\t\tit(\"invokes the scheduled events at the correct times\", async () => {\n\t\t\tlet count = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst eighth = transport.toSeconds(\"8n\");\n\t\t\t\tconst times = [\n\t\t\t\t\t0,\n\t\t\t\t\teighth,\n\t\t\t\t\teighth * 1.5,\n\t\t\t\t\teighth * 2,\n\t\t\t\t\teighth * (2 + 1 / 3),\n\t\t\t\t\teighth * (2 + 2 / 3),\n\t\t\t\t];\n\t\t\t\tconst seq = new Sequence(\n\t\t\t\t\t(time) => {\n\t\t\t\t\t\texpect(time).to.be.closeTo(times[count], 0.01);\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t},\n\t\t\t\t\t[0, [1, 2], [3, 4, 5]],\n\t\t\t\t\t\"8n\"\n\t\t\t\t).start(0);\n\t\t\t\tseq.loop = false;\n\t\t\t\ttransport.start(0);\n\t\t\t}, 0.8);\n\t\t\texpect(count).to.equal(6);\n\t\t});\n\n\t\tit(\"can schedule rests using 'null'\", async () => {\n\t\t\tlet count = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst eighth = transport.toSeconds(\"8n\");\n\t\t\t\tconst times = [0, eighth * 2.5];\n\t\t\t\tconst seq = new Sequence(\n\t\t\t\t\t(time, value) => {\n\t\t\t\t\t\texpect(time).to.be.closeTo(times[count], 0.01);\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t},\n\t\t\t\t\t[0, null, [null, 1]],\n\t\t\t\t\t\"8n\"\n\t\t\t\t).start(0);\n\t\t\t\tseq.loop = false;\n\t\t\t\ttransport.start(0);\n\t\t\t}, 0.8);\n\t\t\texpect(count).to.equal(2);\n\t\t});\n\n\t\tit(\"can schedule triple nested arrays\", async () => {\n\t\t\tlet count = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst eighth = transport.toSeconds(\"8n\");\n\t\t\t\tconst times = [0, eighth, eighth * 1.5, eighth * 1.75];\n\t\t\t\tconst seq = new Sequence(\n\t\t\t\t\t(time) => {\n\t\t\t\t\t\texpect(time).to.be.closeTo(times[count], 0.01);\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t},\n\t\t\t\t\t[0, [1, [2, 3]]],\n\t\t\t\t\t\"8n\"\n\t\t\t\t).start(0);\n\t\t\t\tseq.loop = false;\n\t\t\t\ttransport.start(0);\n\t\t\t}, 0.7);\n\t\t\texpect(count).to.equal(4);\n\t\t});\n\n\t\tit(\"starts an event added after the seq was started\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst seq = new Sequence({\n\t\t\t\t\tcallback(time, value): void {\n\t\t\t\t\t\tif (value === 1) {\n\t\t\t\t\t\t\tseq.dispose();\n\t\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tevents: [[0, 2]],\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\n\t\t\t\treturn atTime(0.1, () => {\n\t\t\t\t\tseq.events[1] = 1;\n\t\t\t\t});\n\t\t\t}, 0.5);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"can mute the callback\", async () => {\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst seq = new Sequence(() => {\n\t\t\t\t\tthrow new Error(\"shouldn't call this callback\");\n\t\t\t\t}, [0, 0.1, 0.2, 0.3]).start();\n\t\t\t\tseq.mute = true;\n\t\t\t\texpect(seq.mute).to.be.true;\n\t\t\t\ttransport.start();\n\t\t\t}, 0.5);\n\t\t});\n\t});\n\n\tcontext(\"Looping\", () => {\n\t\tit(\"can be set to loop\", async () => {\n\t\t\tlet callCount = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst seq = new Sequence({\n\t\t\t\t\tevents: [0, 1],\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 0.2,\n\t\t\t\t\tcallback(): void {\n\t\t\t\t\t\tcallCount++;\n\t\t\t\t\t\tif (callCount > 2) {\n\t\t\t\t\t\t\tseq.dispose();\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.5);\n\t\t\texpect(callCount).to.equal(3);\n\t\t});\n\n\t\tit(\"can loop between loopStart and loopEnd\", async () => {\n\t\t\tlet invocations = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst seq = new Sequence({\n\t\t\t\t\tevents: [0, [1, 2, 3], [4, 5]],\n\t\t\t\t\tloopEnd: 2,\n\t\t\t\t\tloopStart: 1,\n\t\t\t\t\tsubdivision: \"8n\",\n\t\t\t\t\tcallback(time, value): void {\n\t\t\t\t\t\texpect(value).to.be.at.least(1);\n\t\t\t\t\t\texpect(value).to.be.at.most(3);\n\t\t\t\t\t\tinvocations++;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.7);\n\t\t\texpect(invocations).to.equal(9);\n\t\t});\n\n\t\tit(\"can set the loop points after starting\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tlet switched = false;\n\t\t\t\tconst seq = new Sequence({\n\t\t\t\t\tcallback(time, value): void {\n\t\t\t\t\t\tif (value === 4) {\n\t\t\t\t\t\t\tseq.loopStart = 2;\n\t\t\t\t\t\t\tswitched = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (switched) {\n\t\t\t\t\t\t\texpect(value).to.be.at.least(4);\n\t\t\t\t\t\t\texpect(value).to.be.at.most(5);\n\t\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tevents: [0, [1, 2, 3], [4, 5]],\n\t\t\t\t\tsubdivision: \"16n\",\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.7);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\t});\n\n\tcontext(\"playbackRate\", () => {\n\t\tit(\"can adjust the playbackRate\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tlet lastCall;\n\t\t\t\tnew Sequence({\n\t\t\t\t\tevents: [0, 1],\n\t\t\t\t\tplaybackRate: 2,\n\t\t\t\t\tsubdivision: \"4n\",\n\t\t\t\t\tcallback(time): void {\n\t\t\t\t\t\tif (lastCall) {\n\t\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t\t\texpect(time - lastCall).to.be.closeTo(0.25, 0.01);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlastCall = time;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.7);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"adjusts speed of subsequences\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tlet lastCall;\n\t\t\t\tnew Sequence({\n\t\t\t\t\tevents: [\n\t\t\t\t\t\t[0, 1],\n\t\t\t\t\t\t[2, 3],\n\t\t\t\t\t],\n\t\t\t\t\tplaybackRate: 0.5,\n\t\t\t\t\tsubdivision: \"8n\",\n\t\t\t\t\tcallback(time): void {\n\t\t\t\t\t\tif (lastCall) {\n\t\t\t\t\t\t\texpect(time - lastCall).to.be.closeTo(0.25, 0.01);\n\t\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlastCall = time;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.7);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"can adjust the playbackRate after starting\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tlet lastCall;\n\t\t\t\tconst seq = new Sequence({\n\t\t\t\t\tevents: [0, 1],\n\t\t\t\t\tplaybackRate: 1,\n\t\t\t\t\tsubdivision: \"8n\",\n\t\t\t\t\tcallback(time): void {\n\t\t\t\t\t\tif (lastCall) {\n\t\t\t\t\t\t\texpect(time - lastCall).to.be.closeTo(0.5, 0.01);\n\t\t\t\t\t\t\tinvoked = true;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tseq.playbackRate = 0.5;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlastCall = time;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 2);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/event/Sequence.ts",
    "content": "import { TicksClass } from \"../core/type/Ticks.js\";\nimport {\n\tNormalRange,\n\tPositive,\n\tSeconds,\n\tTicks,\n\tTime,\n\tTransportTime,\n} from \"../core/type/Units.js\";\nimport { omitFromObject, optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { isArray, isString } from \"../core/util/TypeCheck.js\";\nimport { Part } from \"./Part.js\";\nimport { ToneEvent, ToneEventCallback, ToneEventOptions } from \"./ToneEvent.js\";\n\ntype SequenceEventDescription<T> = Array<T | SequenceEventDescription<T>>;\n\ninterface SequenceOptions<T> extends Omit<ToneEventOptions<T>, \"value\"> {\n\tloopStart: number;\n\tloopEnd: number;\n\tsubdivision: Time;\n\tevents: SequenceEventDescription<T>;\n}\n\n/**\n * A sequence is an alternate notation of a part. Instead\n * of passing in an array of [time, event] pairs, pass\n * in an array of events which will be spaced at the\n * given subdivision. Sub-arrays will subdivide that beat\n * by the number of items are in the array.\n * Sequence notation inspiration from [Tidal Cycles](http://tidalcycles.org/)\n * @example\n * const synth = new Tone.Synth().toDestination();\n * const seq = new Tone.Sequence((time, note) => {\n * \tsynth.triggerAttackRelease(note, 0.1, time);\n * \t// subdivisions are given as subarrays\n * }, [\"C4\", [\"E4\", \"D4\", \"E4\"], \"G4\", [\"A4\", \"G4\"]]).start(0);\n * Tone.Transport.start();\n * @category Event\n */\nexport class Sequence<ValueType = any> extends ToneEvent<ValueType> {\n\treadonly name: string = \"Sequence\";\n\n\t/**\n\t * The subdivision of each note\n\t */\n\tprivate _subdivision: Ticks;\n\n\t/**\n\t * The object responsible for scheduling all of the events\n\t */\n\tprivate _part: Part = new Part({\n\t\tcallback: this._seqCallback.bind(this),\n\t\tcontext: this.context,\n\t});\n\n\t/**\n\t * private reference to all of the sequence proxies\n\t */\n\tprivate _events: SequenceEventDescription<ValueType> = [];\n\n\t/**\n\t * The proxied array\n\t */\n\tprivate _eventsArray: SequenceEventDescription<ValueType> = [];\n\n\t/**\n\t * @param  callback  The callback to invoke with every note\n\t * @param  events  The sequence of events\n\t * @param  subdivision  The subdivision between which events are placed.\n\t */\n\tconstructor(\n\t\tcallback?: ToneEventCallback<ValueType>,\n\t\tevents?: SequenceEventDescription<ValueType>,\n\t\tsubdivision?: Time\n\t);\n\tconstructor(options?: Partial<SequenceOptions<ValueType>>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tSequence.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"callback\", \"events\", \"subdivision\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._subdivision = this.toTicks(options.subdivision);\n\n\t\tthis.events = options.events;\n\n\t\t// set all of the values\n\t\tthis.loop = options.loop;\n\t\tthis.loopStart = options.loopStart;\n\t\tthis.loopEnd = options.loopEnd;\n\t\tthis.playbackRate = options.playbackRate;\n\t\tthis.probability = options.probability;\n\t\tthis.humanize = options.humanize;\n\t\tthis.mute = options.mute;\n\t\tthis.playbackRate = options.playbackRate;\n\t}\n\n\tstatic getDefaults(): SequenceOptions<any> {\n\t\treturn Object.assign(\n\t\t\tomitFromObject(ToneEvent.getDefaults(), [\"value\"]),\n\t\t\t{\n\t\t\t\tevents: [],\n\t\t\t\tloop: true,\n\t\t\t\tloopEnd: 0,\n\t\t\t\tloopStart: 0,\n\t\t\t\tsubdivision: \"8n\",\n\t\t\t}\n\t\t);\n\t}\n\n\t/**\n\t * The internal callback for when an event is invoked\n\t */\n\tprivate _seqCallback(time: Seconds, value: any): void {\n\t\tif (value !== null && !this.mute) {\n\t\t\tthis.callback(time, value);\n\t\t}\n\t}\n\n\t/**\n\t * The sequence\n\t */\n\tget events(): any[] {\n\t\treturn this._events;\n\t}\n\tset events(s) {\n\t\tthis.clear();\n\t\tthis._eventsArray = s;\n\t\tthis._events = this._createSequence(this._eventsArray);\n\t\tthis._eventsUpdated();\n\t}\n\n\t/**\n\t * Start the part at the given time.\n\t * @param  time    When to start the part.\n\t * @param  offset  The offset index to start at\n\t */\n\tstart(time?: TransportTime, offset?: number): this {\n\t\tthis._part.start(time, offset ? this._indexTime(offset) : offset);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop the part at the given time.\n\t * @param  time  When to stop the part.\n\t */\n\tstop(time?: TransportTime): this {\n\t\tthis._part.stop(time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * The subdivision of the sequence. This can only be\n\t * set in the constructor. The subdivision is the\n\t * interval between successive steps.\n\t */\n\tget subdivision(): Seconds {\n\t\treturn new TicksClass(this.context, this._subdivision).toSeconds();\n\t}\n\n\t/**\n\t * Create a sequence proxy which can be monitored to create subsequences\n\t */\n\tprivate _createSequence(array: any[]): any[] {\n\t\treturn new Proxy(array, {\n\t\t\tget: (target: any[], property: PropertyKey): any => {\n\t\t\t\t// property is index in this case\n\t\t\t\treturn target[property];\n\t\t\t},\n\t\t\tset: (\n\t\t\t\ttarget: any[],\n\t\t\t\tproperty: PropertyKey,\n\t\t\t\tvalue: any\n\t\t\t): boolean => {\n\t\t\t\tif (isString(property) && isFinite(parseInt(property, 10))) {\n\t\t\t\t\tif (isArray(value)) {\n\t\t\t\t\t\ttarget[property] = this._createSequence(value);\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttarget[property] = value;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttarget[property] = value;\n\t\t\t\t}\n\t\t\t\tthis._eventsUpdated();\n\t\t\t\t// return true to accept the changes\n\t\t\t\treturn true;\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * When the sequence has changed, all of the events need to be recreated\n\t */\n\tprivate _eventsUpdated(): void {\n\t\tthis._part.clear();\n\t\tthis._rescheduleSequence(\n\t\t\tthis._eventsArray,\n\t\t\tthis._subdivision,\n\t\t\tthis.startOffset\n\t\t);\n\t\t// update the loopEnd\n\t\tthis.loopEnd = this.loopEnd;\n\t}\n\n\t/**\n\t * reschedule all of the events that need to be rescheduled\n\t */\n\tprivate _rescheduleSequence(\n\t\tsequence: any[],\n\t\tsubdivision: Ticks,\n\t\tstartOffset: Ticks\n\t): void {\n\t\tsequence.forEach((value, index) => {\n\t\t\tconst eventOffset = index * subdivision + startOffset;\n\t\t\tif (isArray(value)) {\n\t\t\t\tthis._rescheduleSequence(\n\t\t\t\t\tvalue,\n\t\t\t\t\tsubdivision / value.length,\n\t\t\t\t\teventOffset\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tconst startTime = new TicksClass(\n\t\t\t\t\tthis.context,\n\t\t\t\t\teventOffset,\n\t\t\t\t\t\"i\"\n\t\t\t\t).toSeconds();\n\t\t\t\tthis._part.add(startTime, value);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Get the time of the index given the Sequence's subdivision\n\t * @param  index\n\t * @return The time of that index\n\t */\n\tprivate _indexTime(index: number): Seconds {\n\t\treturn new TicksClass(\n\t\t\tthis.context,\n\t\t\tindex * this._subdivision + this.startOffset\n\t\t).toSeconds();\n\t}\n\n\t/**\n\t * Clear all of the events\n\t */\n\tclear(): this {\n\t\tthis._part.clear();\n\t\treturn this;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._part.dispose();\n\t\treturn this;\n\t}\n\n\t//-------------------------------------\n\t// PROXY CALLS\n\t//-------------------------------------\n\n\tget loop(): boolean | number {\n\t\treturn this._part.loop;\n\t}\n\tset loop(l) {\n\t\tthis._part.loop = l;\n\t}\n\n\t/**\n\t * The index at which the sequence should start looping\n\t */\n\tget loopStart(): number {\n\t\treturn this._loopStart;\n\t}\n\tset loopStart(index) {\n\t\tthis._loopStart = index;\n\t\tthis._part.loopStart = this._indexTime(index);\n\t}\n\n\t/**\n\t * The index at which the sequence should end looping\n\t */\n\tget loopEnd(): number {\n\t\treturn this._loopEnd;\n\t}\n\tset loopEnd(index) {\n\t\tthis._loopEnd = index;\n\t\tif (index === 0) {\n\t\t\tthis._part.loopEnd = this._indexTime(this._eventsArray.length);\n\t\t} else {\n\t\t\tthis._part.loopEnd = this._indexTime(index);\n\t\t}\n\t}\n\n\tget startOffset(): Ticks {\n\t\treturn this._part.startOffset;\n\t}\n\tset startOffset(start) {\n\t\tthis._part.startOffset = start;\n\t}\n\n\tget playbackRate(): Positive {\n\t\treturn this._part.playbackRate;\n\t}\n\tset playbackRate(rate) {\n\t\tthis._part.playbackRate = rate;\n\t}\n\n\tget probability(): NormalRange {\n\t\treturn this._part.probability;\n\t}\n\tset probability(prob) {\n\t\tthis._part.probability = prob;\n\t}\n\n\tget progress(): NormalRange {\n\t\treturn this._part.progress;\n\t}\n\n\tget humanize(): boolean | Time {\n\t\treturn this._part.humanize;\n\t}\n\tset humanize(variation) {\n\t\tthis._part.humanize = variation;\n\t}\n\n\t/**\n\t * The number of scheduled events\n\t */\n\tget length(): number {\n\t\treturn this._part.length;\n\t}\n}\n"
  },
  {
    "path": "Tone/event/ToneEvent.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { Offline, whenBetween } from \"../../test/helper/Offline.js\";\nimport { Time } from \"../core/type/Time.js\";\nimport { noOp } from \"../core/util/Interface.js\";\nimport { ToneEvent } from \"./ToneEvent.js\";\n\ndescribe(\"ToneEvent\", () => {\n\tBasicTests(ToneEvent);\n\n\tcontext(\"Constructor\", () => {\n\t\tit(\"takes a callback and a value\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst callback = noOp;\n\t\t\t\tconst note = new ToneEvent(callback, \"C4\");\n\t\t\t\texpect(note.callback).to.equal(callback);\n\t\t\t\texpect(note.value).to.equal(\"C4\");\n\t\t\t\tnote.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can be constructed with no arguments\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst note = new ToneEvent();\n\t\t\t\texpect(note.value).to.be.null;\n\t\t\t\tnote.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can pass in arguments in options object\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst callback = noOp;\n\t\t\t\tconst value = { a: 1 };\n\t\t\t\tconst note = new ToneEvent({\n\t\t\t\t\tcallback,\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: \"4n\",\n\t\t\t\t\tprobability: 0.3,\n\t\t\t\t\tvalue,\n\t\t\t\t});\n\t\t\t\texpect(note.callback).to.equal(callback);\n\t\t\t\texpect(note.value).to.equal(value);\n\t\t\t\texpect(note.loop).to.be.true;\n\t\t\t\texpect(note.loopEnd).to.equal(Time(\"4n\").valueOf());\n\t\t\t\texpect(note.probability).to.equal(0.3);\n\t\t\t\tnote.dispose();\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"Get/Set\", () => {\n\t\tit(\"can set values with object\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst callback = noOp;\n\t\t\t\tconst note = new ToneEvent();\n\t\t\t\tnote.set({\n\t\t\t\t\tcallback,\n\t\t\t\t\tloop: 8,\n\t\t\t\t\tvalue: \"D4\",\n\t\t\t\t});\n\t\t\t\texpect(note.callback).to.equal(callback);\n\t\t\t\texpect(note.value).to.equal(\"D4\");\n\t\t\t\texpect(note.loop).to.equal(8);\n\t\t\t\tnote.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can set get a the values as an object\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst callback = noOp;\n\t\t\t\tconst note = new ToneEvent({\n\t\t\t\t\tcallback,\n\t\t\t\t\tloop: 4,\n\t\t\t\t\tvalue: \"D3\",\n\t\t\t\t});\n\t\t\t\tconst values = note.get();\n\t\t\t\texpect(values.value).to.equal(\"D3\");\n\t\t\t\texpect(values.loop).to.equal(4);\n\t\t\t\tnote.dispose();\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"ToneEvent callback\", () => {\n\t\tit(\"does not invoke get invoked until started\", async () => {\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst event = new ToneEvent(() => {\n\t\t\t\t\tthrow new Error(\"shouldn't call this callback\");\n\t\t\t\t}, \"C4\");\n\t\t\t\ttransport.start();\n\t\t\t}, 0.3);\n\t\t});\n\n\t\tit(\"is invoked after it's started\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst note = new ToneEvent(() => {\n\t\t\t\t\tnote.dispose();\n\t\t\t\t\tinvoked = true;\n\t\t\t\t}, \"C4\").start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.3);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"passes in the scheduled time to the callback\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst now = 0.1;\n\t\t\t\tconst note = new ToneEvent((time) => {\n\t\t\t\t\texpect(time).to.be.a(\"number\");\n\t\t\t\t\texpect(time - now).to.be.closeTo(0.3, 0.01);\n\t\t\t\t\tnote.dispose();\n\t\t\t\t\tinvoked = true;\n\t\t\t\t});\n\t\t\t\tnote.start(0.3);\n\t\t\t\ttransport.start(now);\n\t\t\t}, 0.5);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"passes in the value to the callback\", async () => {\n\t\t\tlet invoked = false;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst note = new ToneEvent((time, thing) => {\n\t\t\t\t\texpect(time).to.be.a(\"number\");\n\t\t\t\t\texpect(thing).to.equal(\"thing\");\n\t\t\t\t\tnote.dispose();\n\t\t\t\t\tinvoked = true;\n\t\t\t\t}, \"thing\").start();\n\t\t\t\ttransport.start();\n\t\t\t}, 0.3);\n\t\t\texpect(invoked).to.be.true;\n\t\t});\n\n\t\tit(\"can mute the callback\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst note = new ToneEvent(() => {\n\t\t\t\t\tthrow new Error(\"shouldn't call this callback\");\n\t\t\t\t}, \"C4\").start();\n\t\t\t\tnote.mute = true;\n\t\t\t\texpect(note.mute).to.be.true;\n\t\t\t\ttransport.start();\n\t\t\t}, 0.3);\n\t\t});\n\n\t\tit(\"can trigger with some probability\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst note = new ToneEvent(() => {\n\t\t\t\t\tthrow new Error(\"shouldn't call this callback\");\n\t\t\t\t}, \"C4\").start();\n\t\t\t\tnote.probability = 0;\n\t\t\t\texpect(note.probability).to.equal(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.3);\n\t\t});\n\t});\n\n\tcontext(\"Scheduling\", () => {\n\t\tit(\"can be started and stopped multiple times\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst note = new ToneEvent().start(0).stop(0.2).start(0.4);\n\t\t\t\ttransport.start(0);\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, 0.19, () => {\n\t\t\t\t\t\texpect(note.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.2, 0.39, () => {\n\t\t\t\t\t\texpect(note.state).to.equal(\"stopped\");\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.4, Infinity, () => {\n\t\t\t\t\t\texpect(note.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.5);\n\t\t});\n\n\t\tit(\"restarts when transport is restarted\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst note = new ToneEvent().start(0).stop(0.4);\n\t\t\t\ttransport.start(0).stop(0.5).start(0.55);\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, 0.39, () => {\n\t\t\t\t\t\texpect(note.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.4, 0.5, () => {\n\t\t\t\t\t\texpect(note.state).to.equal(\"stopped\");\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.55, 0.8, () => {\n\t\t\t\t\t\texpect(note.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 1);\n\t\t});\n\n\t\tit(\"can be cancelled\", async () => {\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst note = new ToneEvent().start(0);\n\t\t\t\texpect(note.state).to.equal(\"started\");\n\t\t\t\ttransport.start();\n\n\t\t\t\tlet firstStop = false;\n\t\t\t\tlet restarted = false;\n\t\t\t\tconst tested = false;\n\t\t\t\treturn (time) => {\n\t\t\t\t\t// stop the transport\n\t\t\t\t\tif (time > 0.2 && !firstStop) {\n\t\t\t\t\t\tfirstStop = true;\n\t\t\t\t\t\ttransport.stop();\n\t\t\t\t\t\tnote.cancel();\n\t\t\t\t\t}\n\t\t\t\t\tif (time > 0.3 && !restarted) {\n\t\t\t\t\t\trestarted = true;\n\t\t\t\t\t\ttransport.start();\n\t\t\t\t\t}\n\t\t\t\t\tif (time > 0.4 && !tested) {\n\t\t\t\t\t\trestarted = true;\n\t\t\t\t\t\ttransport.start();\n\t\t\t\t\t\texpect(note.state).to.equal(\"stopped\");\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.5);\n\t\t});\n\t});\n\n\tcontext(\"Looping\", () => {\n\t\tit(\"can be set to loop\", async () => {\n\t\t\tlet callCount = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tnew ToneEvent({\n\t\t\t\t\tcallback(): void {\n\t\t\t\t\t\tcallCount++;\n\t\t\t\t\t},\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 0.25,\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start(0);\n\t\t\t}, 0.8);\n\t\t\texpect(callCount).to.equal(4);\n\t\t});\n\n\t\tit(\"can be set to loop at a specific interval\", async () => {\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tlet lastCall;\n\t\t\t\tnew ToneEvent({\n\t\t\t\t\tcallback(time): void {\n\t\t\t\t\t\tif (lastCall) {\n\t\t\t\t\t\t\texpect(time - lastCall).to.be.closeTo(0.25, 0.01);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlastCall = time;\n\t\t\t\t\t},\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 0.25,\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 1);\n\t\t});\n\n\t\tit(\"can adjust the loop duration after starting\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tlet lastCall;\n\t\t\t\tconst note = new ToneEvent({\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 0.5,\n\t\t\t\t\tcallback(time): void {\n\t\t\t\t\t\tif (lastCall) {\n\t\t\t\t\t\t\texpect(time - lastCall).to.be.closeTo(0.25, 0.01);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tnote.loopEnd = 0.25;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlastCall = time;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.8);\n\t\t});\n\n\t\tit(\"can loop a specific number of times\", async () => {\n\t\t\tlet callCount = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tnew ToneEvent({\n\t\t\t\t\tloop: 3,\n\t\t\t\t\tloopEnd: 0.125,\n\t\t\t\t\tcallback(): void {\n\t\t\t\t\t\tcallCount++;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.8);\n\t\t\texpect(callCount).to.equal(3);\n\t\t});\n\n\t\tit(\"plays once when loop is 1\", async () => {\n\t\t\tlet callCount = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tnew ToneEvent({\n\t\t\t\t\tloop: 1,\n\t\t\t\t\tloopEnd: 0.125,\n\t\t\t\t\tcallback(): void {\n\t\t\t\t\t\tcallCount++;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.8);\n\t\t\texpect(callCount).to.equal(1);\n\t\t});\n\n\t\tit(\"plays once when loop is 0\", async () => {\n\t\t\tlet callCount = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tnew ToneEvent({\n\t\t\t\t\tloop: 0,\n\t\t\t\t\tloopEnd: 0.125,\n\t\t\t\t\tcallback(): void {\n\t\t\t\t\t\tcallCount++;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.8);\n\t\t\texpect(callCount).to.equal(1);\n\t\t});\n\n\t\tit(\"plays once when loop is false\", async () => {\n\t\t\tlet callCount = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tnew ToneEvent({\n\t\t\t\t\tloop: false,\n\t\t\t\t\tloopEnd: 0.125,\n\t\t\t\t\tcallback(): void {\n\t\t\t\t\t\tcallCount++;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.8);\n\t\t\texpect(callCount).to.equal(1);\n\t\t});\n\n\t\tit(\"can be started and stopped multiple times\", async () => {\n\t\t\tconst eventTimes = [\n\t\t\t\t0.3, 0.39, 0.9, 0.99, 1.3, 1.39, 1.48, 1.57, 1.66, 1.75, 1.84,\n\t\t\t];\n\t\t\tlet eventTimeIndex = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tnew ToneEvent({\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 0.09,\n\t\t\t\t\tcallback(time): void {\n\t\t\t\t\t\texpect(eventTimes.length).to.be.gt(eventTimeIndex);\n\t\t\t\t\t\texpect(eventTimes[eventTimeIndex]).to.be.closeTo(\n\t\t\t\t\t\t\ttime,\n\t\t\t\t\t\t\t0.05\n\t\t\t\t\t\t);\n\t\t\t\t\t\teventTimeIndex++;\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\t\t.start(0.1)\n\t\t\t\t\t.stop(0.2)\n\t\t\t\t\t.start(0.5)\n\t\t\t\t\t.stop(1.1);\n\t\t\t\ttransport.start(0.2).stop(0.5).start(0.8);\n\t\t\t}, 2);\n\t\t});\n\n\t\tit(\"loops the correct amount of times when the event is started in the transport's past\", async () => {\n\t\t\tlet callCount = 0;\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst note = new ToneEvent({\n\t\t\t\t\tloop: 3,\n\t\t\t\t\tloopEnd: 0.2,\n\t\t\t\t\tcallback(): void {\n\t\t\t\t\t\tcallCount++;\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\ttransport.start();\n\t\t\t\tlet wasCalled = false;\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time > 0.1 && !wasCalled) {\n\t\t\t\t\t\twasCalled = true;\n\t\t\t\t\t\tnote.start(0);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 1);\n\t\t\texpect(callCount).to.equal(2);\n\t\t});\n\n\t\tit(\"reports the progress of the loop\", async () => {\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst note = new ToneEvent({\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 1,\n\t\t\t\t});\n\t\t\t\texpect(note.progress).to.equal(0);\n\t\t\t\tnote.start(0);\n\t\t\t\ttransport.start();\n\t\t\t\treturn (time) => {\n\t\t\t\t\texpect(note.progress).to.be.closeTo(time, 0.05);\n\t\t\t\t};\n\t\t\t}, 0.8);\n\t\t});\n\n\t\tit(\"progress is 0 when not looping\", async () => {\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tconst note = new ToneEvent({\n\t\t\t\t\tloop: false,\n\t\t\t\t\tloopEnd: 0.25,\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t\treturn () => {\n\t\t\t\t\texpect(note.progress).to.equal(0);\n\t\t\t\t};\n\t\t\t}, 0.2);\n\t\t});\n\t});\n\n\tcontext(\"playbackRate and humanize\", () => {\n\t\tit(\"can adjust the playbackRate\", async () => {\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tlet lastCall;\n\t\t\t\tnew ToneEvent({\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 0.5,\n\t\t\t\t\tplaybackRate: 2,\n\t\t\t\t\tcallback(time): void {\n\t\t\t\t\t\tif (lastCall) {\n\t\t\t\t\t\t\texpect(time - lastCall).to.be.closeTo(0.25, 0.01);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlastCall = time;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.7);\n\t\t});\n\n\t\tit(\"can adjust the playbackRate after starting\", async () => {\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tlet lastCall;\n\t\t\t\tconst note = new ToneEvent({\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 0.25,\n\t\t\t\t\tplaybackRate: 1,\n\t\t\t\t\tcallback(time): void {\n\t\t\t\t\t\tif (lastCall) {\n\t\t\t\t\t\t\texpect(time - lastCall).to.be.closeTo(0.5, 0.01);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tnote.playbackRate = 0.5;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlastCall = time;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 1.2);\n\t\t});\n\n\t\tit(\"can humanize the callback by some amount\", async () => {\n\t\t\tawait Offline(({ transport }) => {\n\t\t\t\tlet lastCall;\n\t\t\t\tconst note = new ToneEvent({\n\t\t\t\t\thumanize: 0.05,\n\t\t\t\t\tloop: true,\n\t\t\t\t\tloopEnd: 0.25,\n\t\t\t\t\tcallback(time): void {\n\t\t\t\t\t\tif (lastCall) {\n\t\t\t\t\t\t\texpect(time - lastCall).to.be.within(0.2, 0.3);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlastCall += 0.25;\n\t\t\t\t\t},\n\t\t\t\t}).start(0);\n\t\t\t\ttransport.start();\n\t\t\t}, 0.6);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/event/ToneEvent.ts",
    "content": "import \"../core/clock/Transport.js\";\n\nimport {\n\tToneWithContext,\n\tToneWithContextOptions,\n} from \"../core/context/ToneWithContext.js\";\nimport { TicksClass } from \"../core/type/Ticks.js\";\nimport { TransportTimeClass } from \"../core/type/TransportTime.js\";\nimport {\n\tNormalRange,\n\tPositive,\n\tSeconds,\n\tTicks,\n\tTime,\n\tTransportTime,\n} from \"../core/type/Units.js\";\nimport { defaultArg, optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { noOp } from \"../core/util/Interface.js\";\nimport {\n\tBasicPlaybackState,\n\tStateTimeline,\n} from \"../core/util/StateTimeline.js\";\nimport { isBoolean, isNumber } from \"../core/util/TypeCheck.js\";\n\nexport type ToneEventCallback<T> = (time: Seconds, value: T) => void;\n\nexport interface ToneEventOptions<T> extends ToneWithContextOptions {\n\tcallback: ToneEventCallback<T>;\n\tloop: boolean | number;\n\tloopEnd: Time;\n\tloopStart: Time;\n\tplaybackRate: Positive;\n\tvalue?: T;\n\tprobability: NormalRange;\n\tmute: boolean;\n\thumanize: boolean | Time;\n}\n\n/**\n * ToneEvent abstracts away this.context.transport.schedule and provides a schedulable\n * callback for a single or repeatable events along the timeline.\n *\n * @example\n * const synth = new Tone.PolySynth().toDestination();\n * const chordEvent = new Tone.ToneEvent(((time, chord) => {\n * \t// the chord as well as the exact time of the event\n * \t// are passed in as arguments to the callback function\n * \tsynth.triggerAttackRelease(chord, 0.5, time);\n * }), [\"D4\", \"E4\", \"F4\"]);\n * // start the chord at the beginning of the transport timeline\n * chordEvent.start();\n * // loop it every measure for 8 measures\n * chordEvent.loop = 8;\n * chordEvent.loopEnd = \"1m\";\n * @category Event\n */\nexport class ToneEvent<ValueType = any> extends ToneWithContext<\n\tToneEventOptions<ValueType>\n> {\n\treadonly name: string = \"ToneEvent\";\n\n\t/**\n\t * Loop value\n\t */\n\tprotected _loop: boolean | number;\n\n\t/**\n\t * The callback to invoke.\n\t */\n\tcallback: ToneEventCallback<ValueType>;\n\n\t/**\n\t * The value which is passed to the\n\t * callback function.\n\t */\n\tvalue: ValueType;\n\n\t/**\n\t * When the note is scheduled to start.\n\t */\n\tprotected _loopStart: Ticks;\n\n\t/**\n\t * When the note is scheduled to start.\n\t */\n\tprotected _loopEnd: Ticks;\n\n\t/**\n\t * Tracks the scheduled events\n\t */\n\tprotected _state: StateTimeline<{\n\t\tid: number;\n\t}> = new StateTimeline(\"stopped\");\n\n\t/**\n\t * The playback speed of the note. A speed of 1\n\t * is no change.\n\t */\n\tprotected _playbackRate: Positive;\n\n\t/**\n\t * A delay time from when the event is scheduled to start\n\t */\n\tprotected _startOffset: Ticks = 0;\n\n\t/**\n\t * private holder of probability value\n\t */\n\tprotected _probability: NormalRange;\n\n\t/**\n\t * the amount of variation from the given time.\n\t */\n\tprotected _humanize: boolean | Time;\n\n\t/**\n\t * If mute is true, the callback won't be invoked.\n\t */\n\tmute: boolean;\n\n\t/**\n\t * @param callback The callback to invoke at the time.\n\t * @param value The value or values which should be passed to the callback function on invocation.\n\t */\n\tconstructor(callback?: ToneEventCallback<ValueType>, value?: ValueType);\n\tconstructor(options?: Partial<ToneEventOptions<ValueType>>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tToneEvent.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"callback\", \"value\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._loop = options.loop;\n\t\tthis.callback = options.callback;\n\t\tthis.value = options.value;\n\t\tthis._loopStart = this.toTicks(options.loopStart);\n\t\tthis._loopEnd = this.toTicks(options.loopEnd);\n\t\tthis._playbackRate = options.playbackRate;\n\t\tthis._probability = options.probability;\n\t\tthis._humanize = options.humanize;\n\t\tthis.mute = options.mute;\n\t\tthis._playbackRate = options.playbackRate;\n\t\tthis._state.increasing = true;\n\t\t// schedule the events for the first time\n\t\tthis._rescheduleEvents();\n\t}\n\n\tstatic getDefaults(): ToneEventOptions<any> {\n\t\treturn Object.assign(ToneWithContext.getDefaults(), {\n\t\t\tcallback: noOp,\n\t\t\thumanize: false,\n\t\t\tloop: false,\n\t\t\tloopEnd: \"1m\",\n\t\t\tloopStart: 0,\n\t\t\tmute: false,\n\t\t\tplaybackRate: 1,\n\t\t\tprobability: 1,\n\t\t\tvalue: null,\n\t\t});\n\t}\n\n\t/**\n\t * Reschedule all of the events along the timeline\n\t * with the updated values.\n\t * @param after Only reschedules events after the given time.\n\t */\n\tprivate _rescheduleEvents(after: Ticks = -1): void {\n\t\t// if no argument is given, schedules all of the events\n\t\tthis._state.forEachFrom(after, (event) => {\n\t\t\tlet duration;\n\t\t\tif (event.state === \"started\") {\n\t\t\t\tif (event.id !== -1) {\n\t\t\t\t\tthis.context.transport.clear(event.id);\n\t\t\t\t}\n\t\t\t\tconst startTick =\n\t\t\t\t\tevent.time +\n\t\t\t\t\tMath.round(this.startOffset / this._playbackRate);\n\t\t\t\tif (\n\t\t\t\t\tthis._loop === true ||\n\t\t\t\t\t(isNumber(this._loop) && this._loop > 1)\n\t\t\t\t) {\n\t\t\t\t\tduration = Infinity;\n\t\t\t\t\tif (isNumber(this._loop)) {\n\t\t\t\t\t\tduration = this._loop * this._getLoopDuration();\n\t\t\t\t\t}\n\t\t\t\t\tconst nextEvent = this._state.getAfter(startTick);\n\t\t\t\t\tif (nextEvent !== null) {\n\t\t\t\t\t\tduration = Math.min(\n\t\t\t\t\t\t\tduration,\n\t\t\t\t\t\t\tnextEvent.time - startTick\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (duration !== Infinity) {\n\t\t\t\t\t\tduration = new TicksClass(this.context, duration);\n\t\t\t\t\t}\n\t\t\t\t\tconst interval = new TicksClass(\n\t\t\t\t\t\tthis.context,\n\t\t\t\t\t\tthis._getLoopDuration()\n\t\t\t\t\t);\n\t\t\t\t\tevent.id = this.context.transport.scheduleRepeat(\n\t\t\t\t\t\tthis._tick.bind(this),\n\t\t\t\t\t\tinterval,\n\t\t\t\t\t\tnew TicksClass(this.context, startTick),\n\t\t\t\t\t\tduration\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tevent.id = this.context.transport.schedule(\n\t\t\t\t\t\tthis._tick.bind(this),\n\t\t\t\t\t\tnew TicksClass(this.context, startTick)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Returns the playback state of the note, either \"started\" or \"stopped\".\n\t */\n\tget state(): BasicPlaybackState {\n\t\treturn this._state.getValueAtTime(\n\t\t\tthis.context.transport.ticks\n\t\t) as BasicPlaybackState;\n\t}\n\n\t/**\n\t * The start from the scheduled start time.\n\t */\n\tget startOffset(): Ticks {\n\t\treturn this._startOffset;\n\t}\n\tset startOffset(offset) {\n\t\tthis._startOffset = offset;\n\t}\n\n\t/**\n\t * The probability of the notes being triggered.\n\t */\n\tget probability(): NormalRange {\n\t\treturn this._probability;\n\t}\n\tset probability(prob) {\n\t\tthis._probability = prob;\n\t}\n\n\t/**\n\t * If set to true, will apply small random variation\n\t * to the callback time. If the value is given as a time, it will randomize\n\t * by that amount.\n\t * @example\n\t * const event = new Tone.ToneEvent();\n\t * event.humanize = true;\n\t */\n\tget humanize(): Time | boolean {\n\t\treturn this._humanize;\n\t}\n\n\tset humanize(variation) {\n\t\tthis._humanize = variation;\n\t}\n\n\t/**\n\t * Start the note at the given time.\n\t * @param  time  When the event should start.\n\t */\n\tstart(time?: TransportTime | TransportTimeClass): this {\n\t\tconst ticks = this.toTicks(time);\n\t\tif (this._state.getValueAtTime(ticks) === \"stopped\") {\n\t\t\tthis._state.add({\n\t\t\t\tid: -1,\n\t\t\t\tstate: \"started\",\n\t\t\t\ttime: ticks,\n\t\t\t});\n\t\t\tthis._rescheduleEvents(ticks);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop the Event at the given time.\n\t * @param  time  When the event should stop.\n\t */\n\tstop(time?: TransportTime | TransportTimeClass): this {\n\t\tthis.cancel(time);\n\t\tconst ticks = this.toTicks(time);\n\t\tif (this._state.getValueAtTime(ticks) === \"started\") {\n\t\t\tthis._state.setStateAtTime(\"stopped\", ticks, { id: -1 });\n\t\t\tconst previousEvent = this._state.getBefore(ticks);\n\t\t\tlet rescheduleTime = ticks;\n\t\t\tif (previousEvent !== null) {\n\t\t\t\trescheduleTime = previousEvent.time;\n\t\t\t}\n\t\t\tthis._rescheduleEvents(rescheduleTime);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Cancel all scheduled events greater than or equal to the given time\n\t * @param  time  The time after which events will be cancel.\n\t */\n\tcancel(time?: TransportTime | TransportTimeClass): this {\n\t\ttime = defaultArg(time, -Infinity);\n\t\tconst ticks = this.toTicks(time);\n\t\tthis._state.forEachFrom(ticks, (event) => {\n\t\t\tthis.context.transport.clear(event.id);\n\t\t});\n\t\tthis._state.cancel(ticks);\n\t\treturn this;\n\t}\n\n\t/**\n\t * The callback function invoker. Also\n\t * checks if the Event is done playing\n\t * @param  time  The time of the event in seconds\n\t */\n\tprotected _tick(time: Seconds): void {\n\t\tconst ticks = this.context.transport.getTicksAtTime(time);\n\t\tif (!this.mute && this._state.getValueAtTime(ticks) === \"started\") {\n\t\t\tif (this.probability < 1 && Math.random() > this.probability) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (this.humanize) {\n\t\t\t\tlet variation = 0.02;\n\t\t\t\tif (!isBoolean(this.humanize)) {\n\t\t\t\t\tvariation = this.toSeconds(this.humanize);\n\t\t\t\t}\n\t\t\t\ttime += (Math.random() * 2 - 1) * variation;\n\t\t\t}\n\t\t\tthis.callback(time, this.value);\n\t\t}\n\t}\n\n\t/**\n\t * Get the duration of the loop.\n\t */\n\tprotected _getLoopDuration(): Ticks {\n\t\treturn (this._loopEnd - this._loopStart) / this._playbackRate;\n\t}\n\n\t/**\n\t * If the note should loop or not\n\t * between ToneEvent.loopStart and\n\t * ToneEvent.loopEnd. If set to true,\n\t * the event will loop indefinitely,\n\t * if set to a number greater than 1\n\t * it will play a specific number of\n\t * times, if set to false, 0 or 1, the\n\t * part will only play once.\n\t */\n\tget loop(): boolean | number {\n\t\treturn this._loop;\n\t}\n\tset loop(loop) {\n\t\tthis._loop = loop;\n\t\tthis._rescheduleEvents();\n\t}\n\n\t/**\n\t * The playback rate of the event. Defaults to 1.\n\t * @example\n\t * const note = new Tone.ToneEvent();\n\t * note.loop = true;\n\t * // repeat the note twice as fast\n\t * note.playbackRate = 2;\n\t */\n\tget playbackRate(): Positive {\n\t\treturn this._playbackRate;\n\t}\n\tset playbackRate(rate) {\n\t\tthis._playbackRate = rate;\n\t\tthis._rescheduleEvents();\n\t}\n\n\t/**\n\t * The loopEnd point is the time the event will loop\n\t * if ToneEvent.loop is true.\n\t */\n\tget loopEnd(): Time {\n\t\treturn new TicksClass(this.context, this._loopEnd).toSeconds();\n\t}\n\tset loopEnd(loopEnd) {\n\t\tthis._loopEnd = this.toTicks(loopEnd);\n\t\tif (this._loop) {\n\t\t\tthis._rescheduleEvents();\n\t\t}\n\t}\n\n\t/**\n\t * The time when the loop should start.\n\t */\n\tget loopStart(): Time {\n\t\treturn new TicksClass(this.context, this._loopStart).toSeconds();\n\t}\n\tset loopStart(loopStart) {\n\t\tthis._loopStart = this.toTicks(loopStart);\n\t\tif (this._loop) {\n\t\t\tthis._rescheduleEvents();\n\t\t}\n\t}\n\n\t/**\n\t * The current progress of the loop interval.\n\t * Returns 0 if the event is not started yet or\n\t * it is not set to loop.\n\t */\n\tget progress(): NormalRange {\n\t\tif (this._loop) {\n\t\t\tconst ticks = this.context.transport.ticks;\n\t\t\tconst lastEvent = this._state.get(ticks);\n\t\t\tif (lastEvent !== null && lastEvent.state === \"started\") {\n\t\t\t\tconst loopDuration = this._getLoopDuration();\n\t\t\t\tconst progress = (ticks - lastEvent.time) % loopDuration;\n\t\t\t\treturn progress / loopDuration;\n\t\t\t} else {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.cancel();\n\t\tthis._state.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/event/index.ts",
    "content": "export * from \"./Loop.js\";\nexport * from \"./Part.js\";\nexport * from \"./Pattern.js\";\nexport * from \"./Sequence.js\";\nexport * from \"./ToneEvent.js\";\n"
  },
  {
    "path": "Tone/fromContext.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { OfflineContext } from \"./core/context/OfflineContext.js\";\nimport { fromContext } from \"./fromContext.js\";\n\ndescribe(\"fromContext\", () => {\n\tlet context: OfflineContext;\n\n\tbefore(() => {\n\t\tcontext = new OfflineContext(1, 1, 44100);\n\t});\n\n\tafter(() => {\n\t\tcontext.dispose();\n\t});\n\n\tit(\"creates an object from a context\", () => {\n\t\tconst tone = fromContext(context);\n\t\tconst osc = new tone.Oscillator();\n\t\texpect(osc.context).to.equal(context);\n\t\tosc.dispose();\n\t});\n\n\tit(\"units are relative to the passed in context's timing\", () => {\n\t\tconst tone = fromContext(context);\n\t\texpect(tone.Time(\"+0.5\").valueOf()).to.equal(0.5);\n\t});\n});\n"
  },
  {
    "path": "Tone/fromContext.ts",
    "content": "import * as Classes from \"./classes.js\";\nimport { TransportInstance } from \"./core/clock/Transport.js\";\nimport { Context } from \"./core/context/Context.js\";\nimport { DestinationInstance } from \"./core/context/Destination.js\";\nimport { ListenerInstance } from \"./core/context/Listener.js\";\nimport { FrequencyClass } from \"./core/type/Frequency.js\";\nimport { MidiClass } from \"./core/type/Midi.js\";\nimport { TicksClass } from \"./core/type/Ticks.js\";\nimport { TimeClass } from \"./core/type/Time.js\";\nimport { TransportTimeClass } from \"./core/type/TransportTime.js\";\nimport { omitFromObject } from \"./core/util/Defaults.js\";\nimport { DrawInstance } from \"./core/util/Draw.js\";\nimport { isDefined, isFunction } from \"./core/util/TypeCheck.js\";\n\ntype ClassesWithoutSingletons = Omit<\n\ttypeof Classes,\n\t\"Transport\" | \"Destination\" | \"Draw\"\n>;\n\n/**\n * The exported Tone object. Contains all of the classes that default\n * to the same context and contains a singleton Transport and Destination node.\n */\ntype ToneObject = {\n\tTransport: TransportInstance;\n\tDestination: DestinationInstance;\n\tListener: ListenerInstance;\n\tDraw: DrawInstance;\n\tcontext: Context;\n\tnow: () => number;\n\timmediate: () => number;\n} & ClassesWithoutSingletons;\n\n/**\n * Bind the TimeBaseClass to the context\n */\nfunction bindTypeClass(context: Context, type) {\n\treturn (...args: unknown[]) => new type(context, ...args);\n}\n\n/**\n * Return an object with all of the classes bound to the passed in context\n * @param context The context to bind all of the nodes to\n */\nexport function fromContext(context: Context): ToneObject {\n\tconst classesWithContext: Partial<ClassesWithoutSingletons> = {};\n\tObject.keys(\n\t\tomitFromObject(Classes, [\"Transport\", \"Destination\", \"Draw\"])\n\t).map((key) => {\n\t\tconst cls = Classes[key];\n\t\tif (isDefined(cls) && isFunction(cls.getDefaults)) {\n\t\t\tclassesWithContext[key] = class ToneFromContextNode extends cls {\n\t\t\t\tget defaultContext(): Context {\n\t\t\t\t\treturn context;\n\t\t\t\t}\n\t\t\t};\n\t\t} else {\n\t\t\t// otherwise just copy it over\n\t\t\tclassesWithContext[key] = Classes[key];\n\t\t}\n\t});\n\n\tconst toneFromContext: ToneObject = {\n\t\t...(classesWithContext as ClassesWithoutSingletons),\n\t\tnow: context.now.bind(context),\n\t\timmediate: context.immediate.bind(context),\n\t\tTransport: context.transport,\n\t\tDestination: context.destination,\n\t\tListener: context.listener,\n\t\tDraw: context.draw,\n\t\tcontext,\n\t\t// the type functions\n\t\tMidi: bindTypeClass(context, MidiClass),\n\t\tTime: bindTypeClass(context, TimeClass),\n\t\tFrequency: bindTypeClass(context, FrequencyClass),\n\t\tTicks: bindTypeClass(context, TicksClass),\n\t\tTransportTime: bindTypeClass(context, TransportTimeClass),\n\t};\n\t// return the object\n\treturn toneFromContext;\n}\n"
  },
  {
    "path": "Tone/index.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { TransportInstance } from \"./core/clock/Transport.js\";\nimport { Context } from \"./core/context/Context.js\";\nimport { DestinationInstance } from \"./core/context/Destination.js\";\nimport { DrawInstance } from \"./core/util/Draw.js\";\nimport * as Tone from \"./index.js\";\n\ndescribe(\"Tone\", () => {\n\tit(\"has 'now' and 'immediate' methods\", () => {\n\t\texpect(Tone.now).to.be.a(\"function\");\n\t\texpect(Tone.now()).to.be.a(\"number\");\n\t\texpect(Tone.immediate).to.be.a(\"function\");\n\t\texpect(Tone.immediate()).to.be.a(\"number\");\n\t});\n\n\tit(\"exports the global singletons\", () => {\n\t\texpect(Tone.Destination).to.be.an.instanceOf(DestinationInstance);\n\t\texpect(Tone.Draw).to.be.an.instanceOf(DrawInstance);\n\t\texpect(Tone.Transport).to.be.an.instanceOf(TransportInstance);\n\t\texpect(Tone.context).to.be.an.instanceOf(Context);\n\t});\n\n\tit(\"exports the global singleton getters\", () => {\n\t\texpect(Tone.getDestination()).to.be.an.instanceOf(DestinationInstance);\n\t\texpect(Tone.getDraw()).to.be.an.instanceOf(DrawInstance);\n\t\texpect(Tone.getTransport()).to.be.an.instanceOf(TransportInstance);\n\t});\n\n\tit(\"can start the global context\", () => {\n\t\treturn Tone.start();\n\t});\n\n\tit(\"resolves the promise when everything is loaded\", () => {\n\t\treturn Tone.loaded();\n\t});\n\n\tit(\"can set the global context from a raw online context\", async () => {\n\t\tconst ctx = new AudioContext();\n\t\tconst origContext = Tone.getContext();\n\t\tTone.setContext(ctx);\n\t\texpect(Tone.getContext().rawContext).to.equal(ctx);\n\t\tawait ctx.close();\n\t\tTone.setContext(origContext);\n\t});\n\n\tit(\"can set the global context from a raw offline context\", async () => {\n\t\tconst ctx = new OfflineAudioContext(2, 44100, 44100);\n\t\tconst origContext = Tone.getContext();\n\t\tTone.setContext(ctx);\n\t\texpect(Tone.getContext().rawContext).to.equal(ctx);\n\t\tTone.setContext(origContext);\n\t});\n});\n"
  },
  {
    "path": "Tone/index.ts",
    "content": "export * from \"./classes.js\";\nexport { getContext, setContext } from \"./core/Global.js\";\nexport * from \"./version.js\";\nimport { ToneAudioBuffer } from \"./core/context/ToneAudioBuffer.js\";\nimport { getContext } from \"./core/Global.js\";\nexport { start } from \"./core/Global.js\";\nimport { Seconds } from \"./core/type/Units.js\";\nexport { supported } from \"./core/context/AudioContext.js\";\nimport type { TransportInstance } from \"./core/clock/Transport.js\";\nexport type { TransportInstance } from \"./core/clock/Transport.js\";\nimport type { DestinationInstance } from \"./core/context/Destination.js\";\nexport type { DestinationInstance } from \"./core/context/Destination.js\";\nimport type { ListenerInstance } from \"./core/context/Listener.js\";\nexport type { ListenerInstance } from \"./core/context/Listener.js\";\nimport type { DrawInstance } from \"./core/util/Draw.js\";\nexport type { DrawInstance } from \"./core/util/Draw.js\";\n\n/**\n * The current audio context time of the global {@link BaseContext}.\n * @see {@link Context.now}\n * @category Core\n */\nexport function now(): Seconds {\n\treturn getContext().now();\n}\n\n/**\n * The current audio context time of the global {@link Context} without the {@link Context.lookAhead}\n * @see {@link Context.immediate}\n * @category Core\n */\nexport function immediate(): Seconds {\n\treturn getContext().immediate();\n}\n\n/**\n * The Transport object belonging to the global Tone.js Context.\n * @see {@link TransportInstance}\n * @category Core\n * @deprecated Use {@link getTransport} instead\n */\nexport const Transport = getContext().transport;\n\n/**\n * The Transport object belonging to the global Tone.js Context.\n * @see {@link TransportInstance}\n * @category Core\n */\nexport function getTransport(): TransportInstance {\n\treturn getContext().transport;\n}\n\n/**\n * The Destination (output) belonging to the global Tone.js Context.\n * @see {@link DestinationInstance}\n * @category Core\n * @deprecated Use {@link getDestination} instead\n */\nexport const Destination = getContext().destination;\n\n/**\n * @deprecated Use {@link getDestination} instead\n */\nexport const Master = getContext().destination;\n\n/**\n * The Destination (output) belonging to the global Tone.js Context.\n * @see {@link DestinationInstance}\n * @category Core\n */\nexport function getDestination(): DestinationInstance {\n\treturn getContext().destination;\n}\n\n/**\n * The {@link ListenerInstance} belonging to the global Tone.js Context.\n * @category Core\n * @deprecated Use {@link getListener} instead\n */\nexport const Listener = getContext().listener;\n\n/**\n * The {@link ListenerInstance} belonging to the global Tone.js Context.\n * @category Core\n */\nexport function getListener(): ListenerInstance {\n\treturn getContext().listener;\n}\n\n/**\n * Draw is used to synchronize the draw frame with the Transport's callbacks.\n * @see {@link DrawInstance}\n * @category Core\n * @deprecated Use {@link getDraw} instead\n */\nexport const Draw = getContext().draw;\n\n/**\n * Get the singleton attached to the global context.\n * Draw is used to synchronize the draw frame with the Transport's callbacks.\n * @see {@link DrawInstance}\n * @category Core\n */\nexport function getDraw(): DrawInstance {\n\treturn getContext().draw;\n}\n\n/**\n * A reference to the global context\n * @see {@link Context}\n * @deprecated Use {@link getContext} instead\n */\nexport const context = getContext();\n\n/**\n * Promise which resolves when all of the loading promises are resolved.\n * Alias for static {@link ToneAudioBuffer.loaded} method.\n * @category Core\n */\nexport function loaded() {\n\treturn ToneAudioBuffer.loaded();\n}\n\n// this fills in name changes from 13.x to 14.x\nimport { ToneAudioBuffers } from \"./core/context/ToneAudioBuffers.js\";\nimport { ToneBufferSource } from \"./source/buffer/ToneBufferSource.js\";\n/** @deprecated Use {@link ToneAudioBuffer} */\nexport const Buffer: typeof ToneAudioBuffer = ToneAudioBuffer;\n/** @deprecated Use {@link ToneAudioBuffers} */\nexport const Buffers: typeof ToneAudioBuffers = ToneAudioBuffers;\n/** @deprecated Use {@link ToneBufferSource} */\nexport const BufferSource: typeof ToneBufferSource = ToneBufferSource;\n"
  },
  {
    "path": "Tone/instrument/AMSynth.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { InstrumentTest } from \"../../test/helper/InstrumentTests.js\";\nimport { Offline } from \"../../test/helper/Offline.js\";\nimport { AMSynth } from \"./AMSynth.js\";\n\ndescribe(\"AMSynth\", () => {\n\tBasicTests(AMSynth);\n\tInstrumentTest(AMSynth, \"C4\");\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst synth = new AMSynth().toDestination();\n\t\t\t\tsynth.triggerAttackRelease(\"C5\", 0.1, 0.1);\n\t\t\t},\n\t\t\t\"amSynth.wav\",\n\t\t\t0.15\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"invokes the onsilence callback\", (done) => {\n\t\t\tOffline(() => {\n\t\t\t\tconst amSynth = new AMSynth({\n\t\t\t\t\tonsilence: () => done(),\n\t\t\t\t});\n\t\t\t\tamSynth.triggerAttackRelease(\"C3\", 0.2, 0);\n\t\t\t}, 2);\n\t\t});\n\n\t\tit(\"can get and set carrier attributes\", () => {\n\t\t\tconst amSynth = new AMSynth();\n\t\t\tamSynth.oscillator.type = \"triangle\";\n\t\t\texpect(amSynth.oscillator.type).to.equal(\"triangle\");\n\t\t\tamSynth.dispose();\n\t\t});\n\n\t\tit(\"can get and set modulator attributes\", () => {\n\t\t\tconst amSynth = new AMSynth();\n\t\t\tamSynth.envelope.attack = 0.24;\n\t\t\texpect(amSynth.envelope.attack).to.equal(0.24);\n\t\t\tamSynth.dispose();\n\t\t});\n\n\t\tit(\"can get and set harmonicity\", () => {\n\t\t\tconst amSynth = new AMSynth();\n\t\t\tamSynth.harmonicity.value = 2;\n\t\t\texpect(amSynth.harmonicity.value).to.equal(2);\n\t\t\tamSynth.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an options object\", () => {\n\t\t\tconst amSynth = new AMSynth({\n\t\t\t\toscillator: {\n\t\t\t\t\ttype: \"square\",\n\t\t\t\t},\n\t\t\t\tmodulationEnvelope: {\n\t\t\t\t\tattack: 0.3,\n\t\t\t\t},\n\t\t\t});\n\t\t\texpect(amSynth.modulationEnvelope.attack).to.equal(0.3);\n\t\t\texpect(amSynth.oscillator.type).to.equal(\"square\");\n\t\t\tamSynth.dispose();\n\t\t});\n\n\t\tit(\"can get/set attributes\", () => {\n\t\t\tconst amSynth = new AMSynth();\n\t\t\tamSynth.set({\n\t\t\t\tharmonicity: 1.5,\n\t\t\t\tdetune: 1200,\n\t\t\t});\n\t\t\texpect(amSynth.get().harmonicity).to.equal(1.5);\n\t\t\texpect(amSynth.get().detune).to.be.closeTo(1200, 1);\n\t\t\tamSynth.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/instrument/AMSynth.ts",
    "content": "import { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { RecursivePartial } from \"../core/util/Interface.js\";\nimport { AudioToGain } from \"../signal/AudioToGain.js\";\nimport { ModulationSynth, ModulationSynthOptions } from \"./ModulationSynth.js\";\n\nexport type AMSynthOptions = ModulationSynthOptions;\n\n/**\n * AMSynth uses the output of one Tone.Synth to modulate the\n * amplitude of another Tone.Synth. The harmonicity (the ratio between\n * the two signals) affects the timbre of the output signal greatly.\n * Read more about Amplitude Modulation Synthesis on\n * [SoundOnSound](https://web.archive.org/web/20160404103653/http://www.soundonsound.com:80/sos/mar00/articles/synthsecrets.htm).\n *\n * @example\n * const synth = new Tone.AMSynth().toDestination();\n * synth.triggerAttackRelease(\"C4\", \"4n\");\n *\n * @category Instrument\n */\nexport class AMSynth extends ModulationSynth<AMSynthOptions> {\n\treadonly name: string = \"AMSynth\";\n\n\t/**\n\t * Scale the oscillator from -1,1 to 0-1\n\t */\n\tprivate _modulationScale: AudioToGain;\n\n\tconstructor(options?: RecursivePartial<AMSynthOptions>);\n\tconstructor() {\n\t\tsuper(optionsFromArguments(AMSynth.getDefaults(), arguments));\n\n\t\tthis._modulationScale = new AudioToGain({\n\t\t\tcontext: this.context,\n\t\t});\n\n\t\t// control the two voices frequency\n\t\tthis.frequency.connect(this._carrier.frequency);\n\t\tthis.frequency.chain(this.harmonicity, this._modulator.frequency);\n\t\tthis.detune.fan(this._carrier.detune, this._modulator.detune);\n\t\tthis._modulator.chain(this._modulationScale, this._modulationNode.gain);\n\t\tthis._carrier.chain(this._modulationNode, this.output);\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._modulationScale.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/instrument/DuoSynth.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { InstrumentTest } from \"../../test/helper/InstrumentTests.js\";\nimport { MonophonicTest } from \"../../test/helper/MonophonicTests.js\";\nimport { DuoSynth } from \"./DuoSynth.js\";\n\ndescribe(\"DuoSynth\", () => {\n\tBasicTests(DuoSynth);\n\tMonophonicTest(DuoSynth, \"C4\");\n\tInstrumentTest(DuoSynth, \"C4\", {\n\t\tvoice0: {\n\t\t\toscillator: {\n\t\t\t\ttype: \"square\",\n\t\t\t},\n\t\t\tenvelope: {\n\t\t\t\tdecay: 0.1,\n\t\t\t\tsustain: 0.5,\n\t\t\t\trelease: 0.2,\n\t\t\t},\n\t\t},\n\t\tvoice1: {\n\t\t\toscillator: {\n\t\t\t\ttype: \"square\",\n\t\t\t},\n\t\t\tenvelope: {\n\t\t\t\tdecay: 0.1,\n\t\t\t\tsustain: 0.5,\n\t\t\t\trelease: 0.3,\n\t\t\t},\n\t\t},\n\t});\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst synth = new DuoSynth().toDestination();\n\t\t\t\tsynth.triggerAttackRelease(\"C5\", 0.1, 0.1);\n\t\t\t},\n\t\t\t\"duoSynth.wav\",\n\t\t\t0.07\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can get and set voice0 attributes\", () => {\n\t\t\tconst duoSynth = new DuoSynth();\n\t\t\tduoSynth.voice0.oscillator.type = \"triangle\";\n\t\t\texpect(duoSynth.voice0.oscillator.type).to.equal(\"triangle\");\n\t\t\tduoSynth.dispose();\n\t\t});\n\n\t\tit(\"can get and set voice1 attributes\", () => {\n\t\t\tconst duoSynth = new DuoSynth();\n\t\t\tduoSynth.voice1.envelope.attack = 0.24;\n\t\t\texpect(duoSynth.voice1.envelope.attack).to.equal(0.24);\n\t\t\tduoSynth.dispose();\n\t\t});\n\n\t\tit(\"can get and set harmonicity\", () => {\n\t\t\tconst duoSynth = new DuoSynth();\n\t\t\tduoSynth.harmonicity.value = 2;\n\t\t\texpect(duoSynth.harmonicity.value).to.equal(2);\n\t\t\tduoSynth.dispose();\n\t\t});\n\n\t\tit(\"can get and set vibratoRate\", () => {\n\t\t\tconst duoSynth = new DuoSynth();\n\t\t\tduoSynth.vibratoRate.value = 2;\n\t\t\texpect(duoSynth.vibratoRate.value).to.equal(2);\n\t\t\tduoSynth.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an options object\", () => {\n\t\t\tconst duoSynth = new DuoSynth({\n\t\t\t\tvoice0: {\n\t\t\t\t\tfilter: {\n\t\t\t\t\t\trolloff: -24,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t});\n\t\t\texpect(duoSynth.voice0.filter.rolloff).to.equal(-24);\n\t\t\tduoSynth.dispose();\n\t\t});\n\n\t\tit(\"can get/set attributes\", () => {\n\t\t\tconst duoSynth = new DuoSynth();\n\t\t\tduoSynth.set({\n\t\t\t\tharmonicity: 1.5,\n\t\t\t});\n\t\t\texpect(duoSynth.get().harmonicity).to.equal(1.5);\n\t\t\tduoSynth.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/instrument/DuoSynth.ts",
    "content": "import { Gain } from \"../core/context/Gain.js\";\nimport { Param } from \"../core/context/Param.js\";\nimport {\n\tFrequency,\n\tNormalRange,\n\tPositive,\n\tSeconds,\n\tTime,\n} from \"../core/type/Units.js\";\nimport {\n\tdeepMerge,\n\tomitFromObject,\n\toptionsFromArguments,\n} from \"../core/util/Defaults.js\";\nimport { readOnly, RecursivePartial } from \"../core/util/Interface.js\";\nimport { Multiply } from \"../signal/Multiply.js\";\nimport { Signal } from \"../signal/Signal.js\";\nimport { LFO } from \"../source/oscillator/LFO.js\";\nimport { Monophonic, MonophonicOptions } from \"./Monophonic.js\";\nimport { MonoSynth, MonoSynthOptions } from \"./MonoSynth.js\";\n\nexport interface DuoSynthOptions extends MonophonicOptions {\n\tvoice0: Omit<MonoSynthOptions, keyof MonophonicOptions>;\n\tvoice1: Omit<MonoSynthOptions, keyof MonophonicOptions>;\n\tharmonicity: Positive;\n\tvibratoRate: Frequency;\n\tvibratoAmount: Positive;\n}\n\n/**\n * DuoSynth is a monophonic synth composed of two {@link MonoSynth}s run in parallel with control over the\n * frequency ratio between the two voices and vibrato effect.\n * @example\n * const duoSynth = new Tone.DuoSynth().toDestination();\n * duoSynth.triggerAttackRelease(\"C4\", \"2n\");\n * @category Instrument\n */\nexport class DuoSynth extends Monophonic<DuoSynthOptions> {\n\treadonly name: string = \"DuoSynth\";\n\n\treadonly frequency: Signal<\"frequency\">;\n\treadonly detune: Signal<\"cents\">;\n\n\t/**\n\t * the first voice\n\t */\n\treadonly voice0: MonoSynth;\n\n\t/**\n\t * the second voice\n\t */\n\treadonly voice1: MonoSynth;\n\n\t/**\n\t * The amount of vibrato\n\t */\n\tpublic vibratoAmount: Param<\"normalRange\">;\n\n\t/**\n\t * the vibrato frequency\n\t */\n\tpublic vibratoRate: Signal<\"frequency\">;\n\n\t/**\n\t * Harmonicity is the ratio between the two voices. A harmonicity of\n\t * 1 is no change. Harmonicity = 2 means a change of an octave.\n\t * @example\n\t * const duoSynth = new Tone.DuoSynth().toDestination();\n\t * duoSynth.triggerAttackRelease(\"C4\", \"2n\");\n\t * // pitch voice1 an octave below voice0\n\t * duoSynth.harmonicity.value = 0.5;\n\t */\n\tpublic harmonicity: Signal<\"positive\">;\n\n\t/**\n\t * The vibrato LFO.\n\t */\n\tprivate _vibrato: LFO;\n\n\t/**\n\t * the vibrato gain\n\t */\n\tprivate _vibratoGain: Gain<\"normalRange\">;\n\n\tconstructor(options?: RecursivePartial<DuoSynthOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(DuoSynth.getDefaults(), arguments);\n\t\tsuper(options);\n\n\t\tthis.voice0 = new MonoSynth(\n\t\t\tObject.assign(options.voice0, {\n\t\t\t\tcontext: this.context,\n\t\t\t\tonsilence: () => this.onsilence(this),\n\t\t\t})\n\t\t);\n\t\tthis.voice1 = new MonoSynth(\n\t\t\tObject.assign(options.voice1, {\n\t\t\t\tcontext: this.context,\n\t\t\t})\n\t\t);\n\n\t\tthis.harmonicity = new Multiply({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"positive\",\n\t\t\tvalue: options.harmonicity,\n\t\t});\n\n\t\tthis._vibrato = new LFO({\n\t\t\tfrequency: options.vibratoRate,\n\t\t\tcontext: this.context,\n\t\t\tmin: -50,\n\t\t\tmax: 50,\n\t\t});\n\t\t// start the vibrato immediately\n\t\tthis._vibrato.start();\n\t\tthis.vibratoRate = this._vibrato.frequency;\n\t\tthis._vibratoGain = new Gain({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"normalRange\",\n\t\t\tgain: options.vibratoAmount,\n\t\t});\n\t\tthis.vibratoAmount = this._vibratoGain.gain;\n\n\t\tthis.frequency = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"frequency\",\n\t\t\tvalue: 440,\n\t\t});\n\t\tthis.detune = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"cents\",\n\t\t\tvalue: options.detune,\n\t\t});\n\n\t\t// control the two voices frequency\n\t\tthis.frequency.connect(this.voice0.frequency);\n\t\tthis.frequency.chain(this.harmonicity, this.voice1.frequency);\n\n\t\tthis._vibrato.connect(this._vibratoGain);\n\t\tthis._vibratoGain.fan(this.voice0.detune, this.voice1.detune);\n\n\t\tthis.detune.fan(this.voice0.detune, this.voice1.detune);\n\n\t\tthis.voice0.connect(this.output);\n\t\tthis.voice1.connect(this.output);\n\n\t\treadOnly(this, [\n\t\t\t\"voice0\",\n\t\t\t\"voice1\",\n\t\t\t\"frequency\",\n\t\t\t\"vibratoAmount\",\n\t\t\t\"vibratoRate\",\n\t\t]);\n\t}\n\n\tgetLevelAtTime(time: Time): NormalRange {\n\t\ttime = this.toSeconds(time);\n\t\treturn (\n\t\t\tthis.voice0.envelope.getValueAtTime(time) +\n\t\t\tthis.voice1.envelope.getValueAtTime(time)\n\t\t);\n\t}\n\n\tstatic getDefaults(): DuoSynthOptions {\n\t\treturn deepMerge(Monophonic.getDefaults(), {\n\t\t\tvibratoAmount: 0.5,\n\t\t\tvibratoRate: 5,\n\t\t\tharmonicity: 1.5,\n\t\t\tvoice0: deepMerge(\n\t\t\t\tomitFromObject(\n\t\t\t\t\tMonoSynth.getDefaults(),\n\t\t\t\t\tObject.keys(Monophonic.getDefaults())\n\t\t\t\t),\n\t\t\t\t{\n\t\t\t\t\tfilterEnvelope: {\n\t\t\t\t\t\tattack: 0.01,\n\t\t\t\t\t\tdecay: 0.0,\n\t\t\t\t\t\tsustain: 1,\n\t\t\t\t\t\trelease: 0.5,\n\t\t\t\t\t},\n\t\t\t\t\tenvelope: {\n\t\t\t\t\t\tattack: 0.01,\n\t\t\t\t\t\tdecay: 0.0,\n\t\t\t\t\t\tsustain: 1,\n\t\t\t\t\t\trelease: 0.5,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t),\n\t\t\tvoice1: deepMerge(\n\t\t\t\tomitFromObject(\n\t\t\t\t\tMonoSynth.getDefaults(),\n\t\t\t\t\tObject.keys(Monophonic.getDefaults())\n\t\t\t\t),\n\t\t\t\t{\n\t\t\t\t\tfilterEnvelope: {\n\t\t\t\t\t\tattack: 0.01,\n\t\t\t\t\t\tdecay: 0.0,\n\t\t\t\t\t\tsustain: 1,\n\t\t\t\t\t\trelease: 0.5,\n\t\t\t\t\t},\n\t\t\t\t\tenvelope: {\n\t\t\t\t\t\tattack: 0.01,\n\t\t\t\t\t\tdecay: 0.0,\n\t\t\t\t\t\tsustain: 1,\n\t\t\t\t\t\trelease: 0.5,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t),\n\t\t}) as unknown as DuoSynthOptions;\n\t}\n\t/**\n\t * Trigger the attack portion of the note\n\t */\n\tprotected _triggerEnvelopeAttack(time: Seconds, velocity: number): void {\n\t\t// @ts-ignore\n\t\tthis.voice0._triggerEnvelopeAttack(time, velocity);\n\t\t// @ts-ignore\n\t\tthis.voice1._triggerEnvelopeAttack(time, velocity);\n\t}\n\n\t/**\n\t * Trigger the release portion of the note\n\t */\n\tprotected _triggerEnvelopeRelease(time: Seconds) {\n\t\t// @ts-ignore\n\t\tthis.voice0._triggerEnvelopeRelease(time);\n\t\t// @ts-ignore\n\t\tthis.voice1._triggerEnvelopeRelease(time);\n\t\treturn this;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.voice0.dispose();\n\t\tthis.voice1.dispose();\n\t\tthis.frequency.dispose();\n\t\tthis.detune.dispose();\n\t\tthis._vibrato.dispose();\n\t\tthis.vibratoRate.dispose();\n\t\tthis._vibratoGain.dispose();\n\t\tthis.harmonicity.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/instrument/FMSynth.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { InstrumentTest } from \"../../test/helper/InstrumentTests.js\";\nimport { Offline } from \"../../test/helper/Offline.js\";\nimport { FMSynth } from \"./FMSynth.js\";\n\ndescribe(\"FMSynth\", () => {\n\tBasicTests(FMSynth);\n\tInstrumentTest(FMSynth, \"C4\");\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst synth = new FMSynth().toDestination();\n\t\t\t\tsynth.triggerAttackRelease(\"G4\", 0.1, 0.05);\n\t\t\t},\n\t\t\t\"fmSynth.wav\",\n\t\t\t0.08\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can get and set carrier attributes\", () => {\n\t\t\tconst fmSynth = new FMSynth();\n\t\t\tfmSynth.oscillator.type = \"triangle\";\n\t\t\texpect(fmSynth.oscillator.type).to.equal(\"triangle\");\n\t\t\tfmSynth.dispose();\n\t\t});\n\n\t\tit(\"invokes the onsilence callback\", (done) => {\n\t\t\tOffline(() => {\n\t\t\t\tconst synth = new FMSynth({\n\t\t\t\t\tonsilence: () => done(),\n\t\t\t\t});\n\t\t\t\tsynth.triggerAttackRelease(\"C3\", 0.2, 0);\n\t\t\t}, 2);\n\t\t});\n\n\t\tit(\"can get and set modulator attributes\", () => {\n\t\t\tconst fmSynth = new FMSynth();\n\t\t\tfmSynth.modulationEnvelope.attack = 0.24;\n\t\t\texpect(fmSynth.modulationEnvelope.attack).to.equal(0.24);\n\t\t\tfmSynth.dispose();\n\t\t});\n\n\t\tit(\"can get and set harmonicity\", () => {\n\t\t\tconst fmSynth = new FMSynth();\n\t\t\tfmSynth.harmonicity.value = 2;\n\t\t\texpect(fmSynth.harmonicity.value).to.equal(2);\n\t\t\tfmSynth.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an options object\", () => {\n\t\t\tconst fmSynth = new FMSynth({\n\t\t\t\tenvelope: {\n\t\t\t\t\trelease: 0.3,\n\t\t\t\t},\n\t\t\t});\n\t\t\texpect(fmSynth.envelope.release).to.equal(0.3);\n\t\t\tfmSynth.dispose();\n\t\t});\n\n\t\tit(\"can get/set attributes\", () => {\n\t\t\tconst fmSynth = new FMSynth();\n\t\t\tfmSynth.set({\n\t\t\t\tharmonicity: 1.5,\n\t\t\t\tdetune: 1200,\n\t\t\t});\n\t\t\texpect(fmSynth.get().harmonicity).to.equal(1.5);\n\t\t\texpect(fmSynth.get().detune).to.be.closeTo(1200, 1);\n\t\t\tfmSynth.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/instrument/FMSynth.ts",
    "content": "import { Positive } from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { RecursivePartial } from \"../core/util/Interface.js\";\nimport { Multiply } from \"../signal/Multiply.js\";\nimport { ModulationSynth, ModulationSynthOptions } from \"./ModulationSynth.js\";\n\nexport interface FMSynthOptions extends ModulationSynthOptions {\n\tmodulationIndex: Positive;\n}\n\n/**\n * FMSynth is composed of two Tone.Synths where one Tone.Synth modulates\n * the frequency of a second Tone.Synth. A lot of spectral content\n * can be explored using the modulationIndex parameter. Read more about\n * frequency modulation synthesis on Sound On Sound: [Part 1](https://web.archive.org/web/20160403123704/http://www.soundonsound.com/sos/apr00/articles/synthsecrets.htm), [Part 2](https://web.archive.org/web/20160403115835/http://www.soundonsound.com/sos/may00/articles/synth.htm).\n *\n * @example\n * const fmSynth = new Tone.FMSynth().toDestination();\n * fmSynth.triggerAttackRelease(\"C5\", \"4n\");\n *\n * @category Instrument\n */\n\nexport class FMSynth extends ModulationSynth<FMSynthOptions> {\n\treadonly name: string = \"FMSynth\";\n\n\t/**\n\t * The modulation index which essentially the depth or amount of the modulation. It is the\n\t * ratio of the frequency of the modulating signal (mf) to the amplitude of the\n\t * modulating signal (ma) -- as in ma/mf.\n\t */\n\treadonly modulationIndex: Multiply;\n\n\tconstructor(options?: RecursivePartial<FMSynthOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(FMSynth.getDefaults(), arguments);\n\t\tsuper(options);\n\n\t\tthis.modulationIndex = new Multiply({\n\t\t\tcontext: this.context,\n\t\t\tvalue: options.modulationIndex,\n\t\t});\n\n\t\t// control the two voices frequency\n\t\tthis.frequency.connect(this._carrier.frequency);\n\t\tthis.frequency.chain(this.harmonicity, this._modulator.frequency);\n\t\tthis.frequency.chain(this.modulationIndex, this._modulationNode);\n\t\tthis.detune.fan(this._carrier.detune, this._modulator.detune);\n\t\tthis._modulator.connect(this._modulationNode.gain);\n\t\tthis._modulationNode.connect(this._carrier.frequency);\n\t\tthis._carrier.connect(this.output);\n\t}\n\n\tstatic getDefaults(): FMSynthOptions {\n\t\treturn Object.assign(ModulationSynth.getDefaults(), {\n\t\t\tmodulationIndex: 10,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.modulationIndex.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/instrument/Instrument.ts",
    "content": "import { Volume } from \"../component/channel/Volume.js\";\nimport { Param } from \"../core/context/Param.js\";\nimport {\n\tOutputNode,\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../core/context/ToneAudioNode.js\";\nimport { Decibels, Frequency, NormalRange, Time } from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\n\nexport interface InstrumentOptions extends ToneAudioNodeOptions {\n\tvolume: Decibels;\n}\n\n/**\n * Base-class for all instruments\n */\nexport abstract class Instrument<\n\tOptions extends InstrumentOptions,\n> extends ToneAudioNode<Options> {\n\t/**\n\t * The output and volume trimming node\n\t */\n\tprivate _volume: Volume;\n\toutput: OutputNode;\n\n\t/**\n\t * The instrument only has an output\n\t */\n\tinput: undefined;\n\n\t/**\n\t * The volume of the output in decibels.\n\t * @example\n\t * const amSynth = new Tone.AMSynth().toDestination();\n\t * amSynth.volume.value = -6;\n\t * amSynth.triggerAttackRelease(\"G#3\", 0.2);\n\t */\n\tvolume: Param<\"decibels\">;\n\n\t/**\n\t * Keep track of all events scheduled to the transport\n\t * when the instrument is 'synced'\n\t */\n\tprivate _scheduledEvents: number[] = [];\n\n\t/**\n\t * If the instrument is currently synced\n\t */\n\tprivate _synced = false;\n\n\tconstructor(options?: Partial<InstrumentOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tInstrument.getDefaults(),\n\t\t\targuments\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._volume = this.output = new Volume({\n\t\t\tcontext: this.context,\n\t\t\tvolume: options.volume,\n\t\t});\n\t\tthis.volume = this._volume.volume;\n\t\treadOnly(this, \"volume\");\n\t}\n\n\tstatic getDefaults(): InstrumentOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tvolume: 0,\n\t\t});\n\t}\n\n\t/**\n\t * Sync the instrument to the Transport. All subsequent calls of\n\t * {@link triggerAttack} and {@link triggerRelease} will be scheduled along the transport.\n\t * @example\n\t * const fmSynth = new Tone.FMSynth().toDestination();\n\t * fmSynth.volume.value = -6;\n\t * fmSynth.sync();\n\t * // schedule 3 notes when the transport first starts\n\t * fmSynth.triggerAttackRelease(\"C4\", \"8n\", 0);\n\t * fmSynth.triggerAttackRelease(\"E4\", \"8n\", \"8n\");\n\t * fmSynth.triggerAttackRelease(\"G4\", \"8n\", \"4n\");\n\t * // start the transport to hear the notes\n\t * Tone.Transport.start();\n\t */\n\tsync(): this {\n\t\tif (this._syncState()) {\n\t\t\tthis._syncMethod(\"triggerAttack\", 1);\n\t\t\tthis._syncMethod(\"triggerRelease\", 0);\n\n\t\t\tthis.context.transport.on(\"stop\", this._syncedRelease);\n\t\t\tthis.context.transport.on(\"pause\", this._syncedRelease);\n\t\t\tthis.context.transport.on(\"loopEnd\", this._syncedRelease);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * set _sync\n\t */\n\tprotected _syncState(): boolean {\n\t\tlet changed = false;\n\t\tif (!this._synced) {\n\t\t\tthis._synced = true;\n\t\t\tchanged = true;\n\t\t}\n\t\treturn changed;\n\t}\n\n\t/**\n\t * Wrap the given method so that it can be synchronized\n\t * @param method Which method to wrap and sync\n\t * @param  timePosition What position the time argument appears in\n\t */\n\tprotected _syncMethod(method: string, timePosition: number): void {\n\t\tconst originalMethod = (this[\"_original_\" + method] = this[method]);\n\t\tthis[method] = (...args: any[]) => {\n\t\t\tconst time = args[timePosition];\n\t\t\tconst id = this.context.transport.schedule((t) => {\n\t\t\t\targs[timePosition] = t;\n\t\t\t\toriginalMethod.apply(this, args);\n\t\t\t}, time);\n\t\t\tthis._scheduledEvents.push(id);\n\t\t};\n\t}\n\n\t/**\n\t * Unsync the instrument from the Transport\n\t */\n\tunsync(): this {\n\t\tthis._scheduledEvents.forEach((id) => this.context.transport.clear(id));\n\t\tthis._scheduledEvents = [];\n\t\tif (this._synced) {\n\t\t\tthis._synced = false;\n\t\t\tthis.triggerAttack = this._original_triggerAttack;\n\t\t\tthis.triggerRelease = this._original_triggerRelease;\n\n\t\t\tthis.context.transport.off(\"stop\", this._syncedRelease);\n\t\t\tthis.context.transport.off(\"pause\", this._syncedRelease);\n\t\t\tthis.context.transport.off(\"loopEnd\", this._syncedRelease);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Trigger the attack and then the release after the duration.\n\t * @param  note     The note to trigger.\n\t * @param  duration How long the note should be held for before\n\t *                         triggering the release. This value must be greater than 0.\n\t * @param time  When the note should be triggered.\n\t * @param  velocity The velocity the note should be triggered at.\n\t * @example\n\t * const synth = new Tone.Synth().toDestination();\n\t * // trigger \"C4\" for the duration of an 8th note\n\t * synth.triggerAttackRelease(\"C4\", \"8n\");\n\t */\n\ttriggerAttackRelease(\n\t\tnote: Frequency,\n\t\tduration: Time,\n\t\ttime?: Time,\n\t\tvelocity?: NormalRange\n\t): this {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tconst computedDuration = this.toSeconds(duration);\n\t\tthis.triggerAttack(note, computedTime, velocity);\n\t\tthis.triggerRelease(computedTime + computedDuration);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Start the instrument's note.\n\t * @param note the note to trigger\n\t * @param time the time to trigger the note\n\t * @param velocity the velocity to trigger the note (between 0-1)\n\t */\n\tabstract triggerAttack(\n\t\tnote: Frequency,\n\t\ttime?: Time,\n\t\tvelocity?: NormalRange\n\t): this;\n\tprivate _original_triggerAttack = this.triggerAttack;\n\n\t/**\n\t * Trigger the release phase of the current note.\n\t * @param time when to trigger the release\n\t */\n\tabstract triggerRelease(...args: any[]): this;\n\tprivate _original_triggerRelease = this.triggerRelease;\n\n\t/**\n\t * The release which is scheduled to the timeline.\n\t */\n\tprotected _syncedRelease = (time: number) =>\n\t\tthis._original_triggerRelease(time);\n\n\t/**\n\t * clean up\n\t * @returns {Instrument} this\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._volume.dispose();\n\t\tthis.unsync();\n\t\tthis._scheduledEvents = [];\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/instrument/MembraneSynth.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { InstrumentTest } from \"../../test/helper/InstrumentTests.js\";\nimport { MembraneSynth } from \"./MembraneSynth.js\";\n\ndescribe(\"MembraneSynth\", () => {\n\tBasicTests(MembraneSynth);\n\tInstrumentTest(MembraneSynth, \"C2\");\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst synth = new MembraneSynth().toDestination();\n\t\t\t\tsynth.triggerAttackRelease(\"F#2\", 0.1, 0.05);\n\t\t\t},\n\t\t\t\"membraneSynth.wav\",\n\t\t\t0.5\n\t\t);\n\t});\n\n\tit(\"matches another file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst synth = new MembraneSynth({\n\t\t\t\t\tenvelope: {\n\t\t\t\t\t\tsustain: 0,\n\t\t\t\t\t},\n\t\t\t\t}).toDestination();\n\t\t\t\tsynth.triggerAttackRelease(\"C2\", 0.1);\n\t\t\t},\n\t\t\t\"membraneSynth2.wav\",\n\t\t\t0.5\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can get and set oscillator attributes\", () => {\n\t\t\tconst drumSynth = new MembraneSynth();\n\t\t\tdrumSynth.oscillator.type = \"triangle\";\n\t\t\texpect(drumSynth.oscillator.type).to.equal(\"triangle\");\n\t\t\tdrumSynth.dispose();\n\t\t});\n\n\t\tit(\"can get and set envelope attributes\", () => {\n\t\t\tconst drumSynth = new MembraneSynth();\n\t\t\tdrumSynth.envelope.attack = 0.24;\n\t\t\texpect(drumSynth.envelope.attack).to.equal(0.24);\n\t\t\tdrumSynth.dispose();\n\t\t});\n\n\t\tit(\"can get and set the octaves and pitch decay\", () => {\n\t\t\tconst drumSynth = new MembraneSynth();\n\t\t\tdrumSynth.octaves = 8;\n\t\t\tdrumSynth.pitchDecay = 0.2;\n\t\t\texpect(drumSynth.pitchDecay).to.equal(0.2);\n\t\t\texpect(drumSynth.octaves).to.equal(8);\n\t\t\tdrumSynth.dispose();\n\t\t});\n\n\t\tit(\"validates octaves range\", () => {\n\t\t\tconst drumSynth = new MembraneSynth();\n\t\t\t// Test minimum boundary\n\t\t\tdrumSynth.octaves = 0.5;\n\t\t\texpect(drumSynth.octaves).to.equal(0.5);\n\t\t\t// Test maximum boundary\n\t\t\tdrumSynth.octaves = 8;\n\t\t\texpect(drumSynth.octaves).to.equal(8);\n\t\t\tdrumSynth.dispose();\n\t\t});\n\n\t\tit(\"validates pitchDecay range\", () => {\n\t\t\tconst drumSynth = new MembraneSynth();\n\t\t\tdrumSynth.pitchDecay = 0;\n\t\t\texpect(drumSynth.pitchDecay).to.equal(0);\n\t\t\tdrumSynth.pitchDecay = 0.5;\n\t\t\texpect(drumSynth.pitchDecay).to.equal(0.5);\n\t\t\tdrumSynth.dispose();\n\t\t});\n\n\t\tit(\"Finds correct maximum note frequency\", () => {\n\t\t\tconst drumSynth = new MembraneSynth();\n\t\t\tconst hertz = 65.4; // C2 \n\t\t\tdrumSynth.octaves = 8;\n\t\t\tconst maxNote = hertz * Math.pow(2, drumSynth.octaves); \n\t\t\texpect(maxNote).to.equal(16742.4); // C2 + 8 octaves \n\t\t\tdrumSynth.dispose();\n\t\t});\n\n\n\t\tit(\"can be constructed with an options object\", () => {\n\t\t\tconst drumSynth = new MembraneSynth({\n\t\t\t\tenvelope: {\n\t\t\t\t\tsustain: 0.3,\n\t\t\t\t},\n\t\t\t});\n\t\t\texpect(drumSynth.envelope.sustain).to.equal(0.3);\n\t\t\tdrumSynth.dispose();\n\t\t});\n\n\t\tit(\"can get/set attributes\", () => {\n\t\t\tconst drumSynth = new MembraneSynth();\n\t\t\tdrumSynth.set({\n\t\t\t\tenvelope: { decay: 0.24 },\n\t\t\t});\n\t\t\texpect(drumSynth.get().envelope.decay).to.equal(0.24);\n\t\t\tdrumSynth.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/instrument/MembraneSynth.ts",
    "content": "import { FrequencyClass } from \"../core/type/Frequency.js\";\nimport { Frequency, Positive, Time } from \"../core/type/Units.js\";\nimport { range, timeRange } from \"../core/util/Decorator.js\";\nimport { deepMerge, optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { readOnly, RecursivePartial } from \"../core/util/Interface.js\";\nimport { Monophonic } from \"./Monophonic.js\";\nimport { Synth, SynthOptions } from \"./Synth.js\";\n\nexport interface MembraneSynthOptions extends SynthOptions {\n\tpitchDecay: Time;\n\toctaves: Positive;\n}\n\n/**\n * MembraneSynth makes kick and tom sounds using a single oscillator\n * with an amplitude envelope and frequency ramp. A Tone.OmniOscillator\n * is routed through a Tone.AmplitudeEnvelope to the output. The drum\n * quality of the sound comes from the frequency envelope applied\n * during MembraneSynth.triggerAttack(note). The frequency envelope\n * starts at <code>note * .octaves</code> and ramps to <code>note</code>\n * over the duration of <code>.pitchDecay</code>.\n * @example\n * const synth = new Tone.MembraneSynth().toDestination();\n * synth.triggerAttackRelease(\"C2\", \"8n\");\n * @category Instrument\n */\nexport class MembraneSynth extends Synth<MembraneSynthOptions> {\n\treadonly name: string = \"MembraneSynth\";\n\n\t/**\n\t * The number of octaves the pitch envelope ramps.\n\t * @min 0.5\n\t * @max 8\n\t */\n\t@range(0.5, 8)\n\toctaves: Positive;\n\n\t/**\n\t * The amount of time the frequency envelope takes.\n\t * @min 0\n\t * @max 0.5\n\t */\n\t@timeRange(0, 0.5)\n\tpitchDecay: Time;\n\n\t/**\n\t * Portamento is ignored in this synth. use pitch decay instead.\n\t */\n\treadonly portamento = 0;\n\n\t/**\n\t * @param options the options available for the synth see defaults\n\t */\n\tconstructor(options?: RecursivePartial<MembraneSynthOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tMembraneSynth.getDefaults(),\n\t\t\targuments\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.pitchDecay = options.pitchDecay;\n\t\tthis.octaves = options.octaves;\n\t\treadOnly(this, [\"oscillator\", \"envelope\"]);\n\t}\n\n\tstatic getDefaults(): MembraneSynthOptions {\n\t\treturn deepMerge(Monophonic.getDefaults(), Synth.getDefaults(), {\n\t\t\tenvelope: {\n\t\t\t\tattack: 0.001,\n\t\t\t\tattackCurve: \"exponential\",\n\t\t\t\tdecay: 0.4,\n\t\t\t\trelease: 1.4,\n\t\t\t\tsustain: 0.01,\n\t\t\t},\n\t\t\toctaves: 8,\n\t\t\toscillator: {\n\t\t\t\ttype: \"sine\",\n\t\t\t},\n\t\t\tpitchDecay: 0.05,\n\t\t});\n\t}\n\n\tsetNote(note: Frequency | FrequencyClass, time?: Time): this {\n\t\tconst seconds = this.toSeconds(time);\n\t\tconst hertz = this.toFrequency(\n\t\t\tnote instanceof FrequencyClass ? note.toFrequency() : note\n\t\t);\n\t\tconst maxNote = hertz * Math.pow(2, this.octaves);\n\t\tthis.oscillator.frequency.setValueAtTime(maxNote, seconds);\n\t\tthis.oscillator.frequency.exponentialRampToValueAtTime(\n\t\t\thertz,\n\t\t\tseconds + this.toSeconds(this.pitchDecay)\n\t\t);\n\t\treturn this;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/instrument/MetalSynth.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { InstrumentTest } from \"../../test/helper/InstrumentTests.js\";\nimport { MonophonicTest } from \"../../test/helper/MonophonicTests.js\";\nimport { MetalSynth } from \"./MetalSynth.js\";\n\ndescribe(\"MetalSynth\", () => {\n\tBasicTests(MetalSynth);\n\n\tInstrumentTest(MetalSynth, \"C2\", undefined, undefined, true);\n\tMonophonicTest(MetalSynth, \"C4\");\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst synth = new MetalSynth().toDestination();\n\t\t\t\tsynth.triggerAttackRelease(200, 0.1, 0.05);\n\t\t\t},\n\t\t\t\"metalSynth.wav\",\n\t\t\t2\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can be constructed with octave and harmonicity values\", () => {\n\t\t\tconst cymbal = new MetalSynth({\n\t\t\t\tharmonicity: 3.1,\n\t\t\t\toctaves: 0.4,\n\t\t\t\tresonance: 2300,\n\t\t\t});\n\t\t\texpect(cymbal.harmonicity).to.be.closeTo(3.1, 0.01);\n\t\t\texpect(cymbal.octaves).to.be.closeTo(0.4, 0.01);\n\t\t\texpect(cymbal.resonance).to.be.closeTo(2300, 0.01);\n\t\t\tcymbal.dispose();\n\t\t});\n\n\t\tit(\"can get and set envelope attributes\", () => {\n\t\t\tconst cymbal = new MetalSynth();\n\t\t\tcymbal.envelope.attack = 0.024;\n\t\t\tcymbal.envelope.decay = 0.9;\n\t\t\texpect(cymbal.envelope.attack).to.equal(0.024);\n\t\t\texpect(cymbal.envelope.decay).to.equal(0.9);\n\t\t\tcymbal.dispose();\n\t\t});\n\n\t\tit(\"can set the modulationIndex\", () => {\n\t\t\tconst cymbal = new MetalSynth();\n\t\t\tcymbal.modulationIndex = 82;\n\t\t\texpect(cymbal.modulationIndex).to.be.closeTo(82, 0.01);\n\t\t\tcymbal.dispose();\n\t\t});\n\n\t\tit(\"can get/set attributes\", () => {\n\t\t\tconst cymbal = new MetalSynth();\n\t\t\tcymbal.set({\n\t\t\t\tmodulationIndex: 5,\n\t\t\t});\n\t\t\texpect(cymbal.get().modulationIndex).to.be.closeTo(5, 0.01);\n\t\t\tcymbal.harmonicity = 2;\n\t\t\texpect(cymbal.harmonicity).to.be.closeTo(2, 0.01);\n\t\t\tcymbal.resonance = 2222;\n\t\t\texpect(cymbal.resonance).to.be.closeTo(2222, 1);\n\t\t\tcymbal.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/instrument/MetalSynth.ts",
    "content": "import { Envelope, EnvelopeOptions } from \"../component/envelope/Envelope.js\";\nimport { Filter } from \"../component/filter/Filter.js\";\nimport { Gain } from \"../core/context/Gain.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../core/context/ToneAudioNode.js\";\nimport {\n\tFrequency,\n\tNormalRange,\n\tPositive,\n\tSeconds,\n\tTime,\n} from \"../core/type/Units.js\";\nimport {\n\tdeepMerge,\n\tomitFromObject,\n\toptionsFromArguments,\n} from \"../core/util/Defaults.js\";\nimport { noOp, RecursivePartial } from \"../core/util/Interface.js\";\nimport { Multiply } from \"../signal/Multiply.js\";\nimport { Scale } from \"../signal/Scale.js\";\nimport { Signal } from \"../signal/Signal.js\";\nimport { FMOscillator } from \"../source/oscillator/FMOscillator.js\";\nimport { Monophonic, MonophonicOptions } from \"./Monophonic.js\";\n\nexport interface MetalSynthOptions extends MonophonicOptions {\n\tharmonicity: Positive;\n\tmodulationIndex: Positive;\n\toctaves: number;\n\tresonance: Frequency;\n\tenvelope: Omit<EnvelopeOptions, keyof ToneAudioNodeOptions>;\n}\n\n/**\n * Inharmonic ratio of frequencies based on the Roland TR-808\n * Taken from https://ccrma.stanford.edu/papers/tr-808-cymbal-physically-informed-circuit-bendable-digital-model\n */\nconst inharmRatios: number[] = [1.0, 1.483, 1.932, 2.546, 2.63, 3.897];\n\n/**\n * A highly inharmonic and spectrally complex source with a highpass filter\n * and amplitude envelope which is good for making metallophone sounds.\n * Based on CymbalSynth by [@polyrhythmatic](https://github.com/polyrhythmatic).\n * @category Instrument\n */\nexport class MetalSynth extends Monophonic<MetalSynthOptions> {\n\treadonly name: string = \"MetalSynth\";\n\n\t/**\n\t * The frequency of the cymbal\n\t */\n\treadonly frequency: Signal<\"frequency\">;\n\n\t/**\n\t * The detune applied to the oscillators\n\t */\n\treadonly detune: Signal<\"cents\">;\n\n\t/**\n\t * The array of FMOscillators\n\t */\n\tprivate _oscillators: FMOscillator[] = [];\n\n\t/**\n\t * The frequency multipliers\n\t */\n\tprivate _freqMultipliers: Multiply[] = [];\n\n\t/**\n\t * The gain node for the envelope.\n\t */\n\tprivate _amplitude: Gain;\n\n\t/**\n\t * Highpass the output\n\t */\n\tprivate _highpass: Filter;\n\n\t/**\n\t * The number of octaves the highpass\n\t * filter frequency ramps\n\t */\n\tprivate _octaves: number;\n\n\t/**\n\t * Scale the body envelope for the highpass filter\n\t */\n\tprivate _filterFreqScaler: Scale;\n\n\t/**\n\t * The envelope which is connected both to the\n\t * amplitude and a highpass filter's cutoff frequency.\n\t * The lower-limit of the filter is controlled by the {@link resonance}\n\t */\n\treadonly envelope: Envelope;\n\n\tconstructor(options?: RecursivePartial<MetalSynthOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tMetalSynth.getDefaults(),\n\t\t\targuments\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.detune = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"cents\",\n\t\t\tvalue: options.detune,\n\t\t});\n\n\t\tthis.frequency = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"frequency\",\n\t\t});\n\n\t\tthis._amplitude = new Gain({\n\t\t\tcontext: this.context,\n\t\t\tgain: 0,\n\t\t}).connect(this.output);\n\n\t\tthis._highpass = new Filter({\n\t\t\t// Q: -3.0102999566398125,\n\t\t\tQ: 0,\n\t\t\tcontext: this.context,\n\t\t\ttype: \"highpass\",\n\t\t}).connect(this._amplitude);\n\n\t\tfor (let i = 0; i < inharmRatios.length; i++) {\n\t\t\tconst osc = new FMOscillator({\n\t\t\t\tcontext: this.context,\n\t\t\t\tharmonicity: options.harmonicity,\n\t\t\t\tmodulationIndex: options.modulationIndex,\n\t\t\t\tmodulationType: \"square\",\n\t\t\t\tonstop: i === 0 ? () => this.onsilence(this) : noOp,\n\t\t\t\ttype: \"square\",\n\t\t\t});\n\t\t\tosc.connect(this._highpass);\n\t\t\tthis._oscillators[i] = osc;\n\n\t\t\tconst mult = new Multiply({\n\t\t\t\tcontext: this.context,\n\t\t\t\tvalue: inharmRatios[i],\n\t\t\t});\n\t\t\tthis._freqMultipliers[i] = mult;\n\t\t\tthis.frequency.chain(mult, osc.frequency);\n\t\t\tthis.detune.connect(osc.detune);\n\t\t}\n\n\t\tthis._filterFreqScaler = new Scale({\n\t\t\tcontext: this.context,\n\t\t\tmax: 7000,\n\t\t\tmin: this.toFrequency(options.resonance),\n\t\t});\n\n\t\tthis.envelope = new Envelope({\n\t\t\tattack: options.envelope.attack,\n\t\t\tattackCurve: \"linear\",\n\t\t\tcontext: this.context,\n\t\t\tdecay: options.envelope.decay,\n\t\t\trelease: options.envelope.release,\n\t\t\tsustain: 0,\n\t\t});\n\n\t\tthis.envelope.chain(this._filterFreqScaler, this._highpass.frequency);\n\t\tthis.envelope.connect(this._amplitude.gain);\n\t\t// set the octaves\n\t\tthis._octaves = options.octaves;\n\t\tthis.octaves = options.octaves;\n\t}\n\n\tstatic getDefaults(): MetalSynthOptions {\n\t\treturn deepMerge(Monophonic.getDefaults(), {\n\t\t\tenvelope: Object.assign(\n\t\t\t\tomitFromObject(\n\t\t\t\t\tEnvelope.getDefaults(),\n\t\t\t\t\tObject.keys(ToneAudioNode.getDefaults())\n\t\t\t\t),\n\t\t\t\t{\n\t\t\t\t\tattack: 0.001,\n\t\t\t\t\tdecay: 1.4,\n\t\t\t\t\trelease: 0.2,\n\t\t\t\t}\n\t\t\t),\n\t\t\tharmonicity: 5.1,\n\t\t\tmodulationIndex: 32,\n\t\t\toctaves: 1.5,\n\t\t\tresonance: 4000,\n\t\t});\n\t}\n\n\t/**\n\t * Trigger the attack.\n\t * @param time When the attack should be triggered.\n\t * @param velocity The velocity that the envelope should be triggered at.\n\t */\n\tprotected _triggerEnvelopeAttack(\n\t\ttime: Seconds,\n\t\tvelocity: NormalRange = 1\n\t): this {\n\t\tthis.envelope.triggerAttack(time, velocity);\n\t\tthis._oscillators.forEach((osc) => osc.start(time));\n\t\tif (this.envelope.sustain === 0) {\n\t\t\tthis._oscillators.forEach((osc) => {\n\t\t\t\tosc.stop(\n\t\t\t\t\ttime +\n\t\t\t\t\t\tthis.toSeconds(this.envelope.attack) +\n\t\t\t\t\t\tthis.toSeconds(this.envelope.decay)\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Trigger the release of the envelope.\n\t * @param time When the release should be triggered.\n\t */\n\tprotected _triggerEnvelopeRelease(time: Seconds): this {\n\t\tthis.envelope.triggerRelease(time);\n\t\tthis._oscillators.forEach((osc) =>\n\t\t\tosc.stop(time + this.toSeconds(this.envelope.release))\n\t\t);\n\t\treturn this;\n\t}\n\n\tgetLevelAtTime(time: Time): NormalRange {\n\t\ttime = this.toSeconds(time);\n\t\treturn this.envelope.getValueAtTime(time);\n\t}\n\n\t/**\n\t * The modulationIndex of the oscillators which make up the source.\n\t * see {@link FMOscillator.modulationIndex}\n\t * @min 1\n\t * @max 100\n\t */\n\tget modulationIndex(): number {\n\t\treturn this._oscillators[0].modulationIndex.value;\n\t}\n\tset modulationIndex(val) {\n\t\tthis._oscillators.forEach((osc) => (osc.modulationIndex.value = val));\n\t}\n\n\t/**\n\t * The harmonicity of the oscillators which make up the source.\n\t * see Tone.FMOscillator.harmonicity\n\t * @min 0.1\n\t * @max 10\n\t */\n\tget harmonicity(): number {\n\t\treturn this._oscillators[0].harmonicity.value;\n\t}\n\tset harmonicity(val) {\n\t\tthis._oscillators.forEach((osc) => (osc.harmonicity.value = val));\n\t}\n\n\t/**\n\t * The lower level of the highpass filter which is attached to the envelope.\n\t * This value should be between [0, 7000]\n\t * @min 0\n\t * @max 7000\n\t */\n\tget resonance(): Frequency {\n\t\treturn this._filterFreqScaler.min;\n\t}\n\tset resonance(val) {\n\t\tthis._filterFreqScaler.min = this.toFrequency(val);\n\t\tthis.octaves = this._octaves;\n\t}\n\n\t/**\n\t * The number of octaves above the \"resonance\" frequency\n\t * that the filter ramps during the attack/decay envelope\n\t * @min 0\n\t * @max 8\n\t */\n\tget octaves(): number {\n\t\treturn this._octaves;\n\t}\n\tset octaves(val) {\n\t\tthis._octaves = val;\n\t\tthis._filterFreqScaler.max =\n\t\t\tthis._filterFreqScaler.min * Math.pow(2, val);\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._oscillators.forEach((osc) => osc.dispose());\n\t\tthis._freqMultipliers.forEach((freqMult) => freqMult.dispose());\n\t\tthis.frequency.dispose();\n\t\tthis.detune.dispose();\n\t\tthis._filterFreqScaler.dispose();\n\t\tthis._amplitude.dispose();\n\t\tthis.envelope.dispose();\n\t\tthis._highpass.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/instrument/ModulationSynth.ts",
    "content": "import { AmplitudeEnvelope } from \"../component/envelope/AmplitudeEnvelope.js\";\nimport { Envelope, EnvelopeOptions } from \"../component/envelope/Envelope.js\";\nimport { Gain } from \"../core/context/Gain.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../core/context/ToneAudioNode.js\";\nimport { NormalRange, Positive, Seconds, Time } from \"../core/type/Units.js\";\nimport { omitFromObject, optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { readOnly, RecursivePartial } from \"../core/util/Interface.js\";\nimport { Multiply } from \"../signal/Multiply.js\";\nimport { Signal } from \"../signal/Signal.js\";\nimport { OmniOscillator } from \"../source/oscillator/OmniOscillator.js\";\nimport { OmniOscillatorSynthOptions } from \"../source/oscillator/OscillatorInterface.js\";\nimport { Source } from \"../source/Source.js\";\nimport { Monophonic } from \"./Monophonic.js\";\nimport { Synth, SynthOptions } from \"./Synth.js\";\n\nexport interface ModulationSynthOptions extends SynthOptions {\n\tharmonicity: Positive;\n\tmodulationEnvelope: Omit<EnvelopeOptions, keyof ToneAudioNodeOptions>;\n\tmodulation: OmniOscillatorSynthOptions;\n}\n/**\n * Base class for both AM and FM synths\n */\nexport abstract class ModulationSynth<\n\tOptions extends ModulationSynthOptions,\n> extends Monophonic<Options> {\n\treadonly name: string = \"ModulationSynth\";\n\n\t/**\n\t * The carrier voice.\n\t */\n\tprotected _carrier: Synth;\n\n\t/**\n\t * The modulator voice.\n\t */\n\n\tprotected _modulator: Synth;\n\n\t/**\n\t * The carrier's oscillator\n\t */\n\treadonly oscillator: OmniOscillator<any>;\n\n\t/**\n\t * The carrier's envelope\n\t */\n\treadonly envelope: AmplitudeEnvelope;\n\n\t/**\n\t * The modulator's oscillator which is applied to the amplitude of the oscillator\n\t */\n\treadonly modulation: OmniOscillator<any>;\n\n\t/**\n\t * The modulator's envelope\n\t */\n\treadonly modulationEnvelope: AmplitudeEnvelope;\n\n\t/**\n\t * The frequency control\n\t */\n\treadonly frequency: Signal<\"frequency\">;\n\n\t/**\n\t * The detune in cents\n\t */\n\treadonly detune: Signal<\"cents\">;\n\n\t/**\n\t * Harmonicity is the ratio between the two voices. A harmonicity of\n\t * 1 is no change. Harmonicity = 2 means a change of an octave.\n\t * @example\n\t * const amSynth = new Tone.AMSynth().toDestination();\n\t * // pitch the modulator an octave below oscillator\n\t * amSynth.harmonicity.value = 0.5;\n\t * amSynth.triggerAttackRelease(\"C5\", \"4n\");\n\t */\n\treadonly harmonicity: Multiply;\n\n\t/**\n\t * The node where the modulation happens\n\t */\n\tprotected _modulationNode: Gain;\n\n\tconstructor(options?: RecursivePartial<ModulationSynthOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tModulationSynth.getDefaults(),\n\t\t\targuments\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._carrier = new Synth({\n\t\t\tcontext: this.context,\n\t\t\toscillator: options.oscillator,\n\t\t\tenvelope: options.envelope,\n\t\t\tonsilence: () => this.onsilence(this),\n\t\t\tvolume: -10,\n\t\t});\n\t\tthis._modulator = new Synth({\n\t\t\tcontext: this.context,\n\t\t\toscillator: options.modulation,\n\t\t\tenvelope: options.modulationEnvelope,\n\t\t\tvolume: -10,\n\t\t});\n\n\t\tthis.oscillator = this._carrier.oscillator;\n\t\tthis.envelope = this._carrier.envelope;\n\t\tthis.modulation = this._modulator.oscillator;\n\t\tthis.modulationEnvelope = this._modulator.envelope;\n\n\t\tthis.frequency = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"frequency\",\n\t\t});\n\t\tthis.detune = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tvalue: options.detune,\n\t\t\tunits: \"cents\",\n\t\t});\n\t\tthis.harmonicity = new Multiply({\n\t\t\tcontext: this.context,\n\t\t\tvalue: options.harmonicity,\n\t\t\tminValue: 0,\n\t\t});\n\t\tthis._modulationNode = new Gain({\n\t\t\tcontext: this.context,\n\t\t\tgain: 0,\n\t\t});\n\n\t\treadOnly(this, [\n\t\t\t\"frequency\",\n\t\t\t\"harmonicity\",\n\t\t\t\"oscillator\",\n\t\t\t\"envelope\",\n\t\t\t\"modulation\",\n\t\t\t\"modulationEnvelope\",\n\t\t\t\"detune\",\n\t\t]);\n\t}\n\n\tstatic getDefaults(): ModulationSynthOptions {\n\t\treturn Object.assign(Monophonic.getDefaults(), {\n\t\t\tharmonicity: 3,\n\t\t\toscillator: Object.assign(\n\t\t\t\tomitFromObject(OmniOscillator.getDefaults(), [\n\t\t\t\t\t...Object.keys(Source.getDefaults()),\n\t\t\t\t\t\"frequency\",\n\t\t\t\t\t\"detune\",\n\t\t\t\t]),\n\t\t\t\t{\n\t\t\t\t\ttype: \"sine\",\n\t\t\t\t}\n\t\t\t) as OmniOscillatorSynthOptions,\n\t\t\tenvelope: Object.assign(\n\t\t\t\tomitFromObject(\n\t\t\t\t\tEnvelope.getDefaults(),\n\t\t\t\t\tObject.keys(ToneAudioNode.getDefaults())\n\t\t\t\t),\n\t\t\t\t{\n\t\t\t\t\tattack: 0.01,\n\t\t\t\t\tdecay: 0.01,\n\t\t\t\t\tsustain: 1,\n\t\t\t\t\trelease: 0.5,\n\t\t\t\t}\n\t\t\t),\n\t\t\tmodulation: Object.assign(\n\t\t\t\tomitFromObject(OmniOscillator.getDefaults(), [\n\t\t\t\t\t...Object.keys(Source.getDefaults()),\n\t\t\t\t\t\"frequency\",\n\t\t\t\t\t\"detune\",\n\t\t\t\t]),\n\t\t\t\t{\n\t\t\t\t\ttype: \"square\",\n\t\t\t\t}\n\t\t\t) as OmniOscillatorSynthOptions,\n\t\t\tmodulationEnvelope: Object.assign(\n\t\t\t\tomitFromObject(\n\t\t\t\t\tEnvelope.getDefaults(),\n\t\t\t\t\tObject.keys(ToneAudioNode.getDefaults())\n\t\t\t\t),\n\t\t\t\t{\n\t\t\t\t\tattack: 0.5,\n\t\t\t\t\tdecay: 0.0,\n\t\t\t\t\tsustain: 1,\n\t\t\t\t\trelease: 0.5,\n\t\t\t\t}\n\t\t\t),\n\t\t});\n\t}\n\n\t/**\n\t * Trigger the attack portion of the note\n\t */\n\tprotected _triggerEnvelopeAttack(time: Seconds, velocity: number): void {\n\t\t// @ts-ignore\n\t\tthis._carrier._triggerEnvelopeAttack(time, velocity);\n\t\t// @ts-ignore\n\t\tthis._modulator._triggerEnvelopeAttack(time, velocity);\n\t}\n\n\t/**\n\t * Trigger the release portion of the note\n\t */\n\tprotected _triggerEnvelopeRelease(time: Seconds) {\n\t\t// @ts-ignore\n\t\tthis._carrier._triggerEnvelopeRelease(time);\n\t\t// @ts-ignore\n\t\tthis._modulator._triggerEnvelopeRelease(time);\n\t\treturn this;\n\t}\n\n\tgetLevelAtTime(time: Time): NormalRange {\n\t\ttime = this.toSeconds(time);\n\t\treturn this.envelope.getValueAtTime(time);\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._carrier.dispose();\n\t\tthis._modulator.dispose();\n\t\tthis.frequency.dispose();\n\t\tthis.detune.dispose();\n\t\tthis.harmonicity.dispose();\n\t\tthis._modulationNode.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/instrument/MonoSynth.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { InstrumentTest } from \"../../test/helper/InstrumentTests.js\";\nimport { Offline } from \"../../test/helper/Offline.js\";\nimport { MonoSynth } from \"./MonoSynth.js\";\n\ndescribe(\"MonoSynth\", () => {\n\tBasicTests(MonoSynth);\n\tInstrumentTest(MonoSynth, \"C4\");\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst synth = new MonoSynth().toDestination();\n\t\t\t\tsynth.triggerAttackRelease(\"C4\", 0.1, 0.05);\n\t\t\t},\n\t\t\t\"monoSynth.wav\",\n\t\t\t0.01\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can get and set oscillator attributes\", () => {\n\t\t\tconst monoSynth = new MonoSynth();\n\t\t\tmonoSynth.oscillator.type = \"triangle\";\n\t\t\texpect(monoSynth.oscillator.type).to.equal(\"triangle\");\n\t\t\tmonoSynth.dispose();\n\t\t});\n\n\t\tit(\"can get and set envelope attributes\", () => {\n\t\t\tconst monoSynth = new MonoSynth();\n\t\t\tmonoSynth.envelope.attack = 0.24;\n\t\t\texpect(monoSynth.envelope.attack).to.equal(0.24);\n\t\t\tmonoSynth.dispose();\n\t\t});\n\n\t\tit(\"can get and set filter attributes\", () => {\n\t\t\tconst monoSynth = new MonoSynth();\n\t\t\tmonoSynth.filter.Q.value = 0.4;\n\t\t\texpect(monoSynth.filter.Q.value).to.be.closeTo(0.4, 0.001);\n\t\t\tmonoSynth.dispose();\n\t\t});\n\n\t\tit(\"can get and set filterEnvelope attributes\", () => {\n\t\t\tconst monoSynth = new MonoSynth();\n\t\t\tmonoSynth.filterEnvelope.baseFrequency = 400;\n\t\t\texpect(monoSynth.filterEnvelope.baseFrequency).to.equal(400);\n\t\t\tmonoSynth.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an options object\", () => {\n\t\t\tconst monoSynth = new MonoSynth({\n\t\t\t\tenvelope: {\n\t\t\t\t\tsustain: 0.3,\n\t\t\t\t},\n\t\t\t});\n\t\t\texpect(monoSynth.envelope.sustain).to.equal(0.3);\n\t\t\tmonoSynth.dispose();\n\t\t});\n\n\t\tit(\"can get/set attributes\", () => {\n\t\t\tconst monoSynth = new MonoSynth();\n\t\t\tmonoSynth.set({\n\t\t\t\tenvelope: {\n\t\t\t\t\tdecay: 0.24,\n\t\t\t\t},\n\t\t\t});\n\t\t\texpect(monoSynth.get().envelope.decay).to.equal(0.24);\n\t\t\tmonoSynth.dispose();\n\t\t});\n\n\t\tit(\"is silent after triggerAttack if sustain is 0\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst synth = new MonoSynth({\n\t\t\t\t\tenvelope: {\n\t\t\t\t\t\tattack: 0.1,\n\t\t\t\t\t\tdecay: 0.1,\n\t\t\t\t\t\tsustain: 0,\n\t\t\t\t\t},\n\t\t\t\t}).toDestination();\n\t\t\t\tsynth.triggerAttack(\"C4\", 0);\n\t\t\t}, 0.5);\n\t\t\texpect(buffer.getTimeOfLastSound()).to.be.closeTo(0.2, 0.01);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/instrument/MonoSynth.ts",
    "content": "import { AmplitudeEnvelope } from \"../component/envelope/AmplitudeEnvelope.js\";\nimport { Envelope, EnvelopeOptions } from \"../component/envelope/Envelope.js\";\nimport {\n\tFrequencyEnvelope,\n\tFrequencyEnvelopeOptions,\n} from \"../component/envelope/FrequencyEnvelope.js\";\nimport { Filter, FilterOptions } from \"../component/filter/Filter.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../core/context/ToneAudioNode.js\";\nimport { NormalRange, Seconds, Time } from \"../core/type/Units.js\";\nimport { omitFromObject, optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { readOnly, RecursivePartial } from \"../core/util/Interface.js\";\nimport { Monophonic, MonophonicOptions } from \"../instrument/Monophonic.js\";\nimport { Signal } from \"../signal/Signal.js\";\nimport { OmniOscillator } from \"../source/oscillator/OmniOscillator.js\";\nimport { OmniOscillatorSynthOptions } from \"../source/oscillator/OscillatorInterface.js\";\nimport { Source } from \"../source/Source.js\";\n\nexport interface MonoSynthOptions extends MonophonicOptions {\n\toscillator: OmniOscillatorSynthOptions;\n\tenvelope: Omit<EnvelopeOptions, keyof ToneAudioNodeOptions>;\n\tfilterEnvelope: Omit<FrequencyEnvelopeOptions, keyof ToneAudioNodeOptions>;\n\tfilter: Omit<FilterOptions, keyof ToneAudioNodeOptions>;\n}\n\n/**\n * MonoSynth is composed of one `oscillator`, one `filter`, and two `envelopes`.\n * The amplitude of the Oscillator and the cutoff frequency of the\n * Filter are controlled by Envelopes.\n * <img src=\"https://docs.google.com/drawings/d/1gaY1DF9_Hzkodqf8JI1Cg2VZfwSElpFQfI94IQwad38/pub?w=924&h=240\">\n * @example\n * const synth = new Tone.MonoSynth({\n * \toscillator: {\n * \t\ttype: \"square\"\n * \t},\n * \tenvelope: {\n * \t\tattack: 0.1\n * \t}\n * }).toDestination();\n * synth.triggerAttackRelease(\"C4\", \"8n\");\n * @category Instrument\n */\nexport class MonoSynth extends Monophonic<MonoSynthOptions> {\n\treadonly name = \"MonoSynth\";\n\n\t/**\n\t * The oscillator.\n\t */\n\treadonly oscillator: OmniOscillator<any>;\n\n\t/**\n\t * The frequency control.\n\t */\n\treadonly frequency: Signal<\"frequency\">;\n\n\t/**\n\t * The detune control.\n\t */\n\treadonly detune: Signal<\"cents\">;\n\n\t/**\n\t * The filter.\n\t */\n\treadonly filter: Filter;\n\n\t/**\n\t * The filter envelope.\n\t */\n\treadonly filterEnvelope: FrequencyEnvelope;\n\n\t/**\n\t * The amplitude envelope.\n\t */\n\treadonly envelope: AmplitudeEnvelope;\n\n\tconstructor(options?: RecursivePartial<MonoSynthOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tMonoSynth.getDefaults(),\n\t\t\targuments\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.oscillator = new OmniOscillator(\n\t\t\tObject.assign(options.oscillator, {\n\t\t\t\tcontext: this.context,\n\t\t\t\tdetune: options.detune,\n\t\t\t\tonstop: () => this.onsilence(this),\n\t\t\t})\n\t\t);\n\t\tthis.frequency = this.oscillator.frequency;\n\t\tthis.detune = this.oscillator.detune;\n\t\tthis.filter = new Filter(\n\t\t\tObject.assign(options.filter, { context: this.context })\n\t\t);\n\t\tthis.filterEnvelope = new FrequencyEnvelope(\n\t\t\tObject.assign(options.filterEnvelope, { context: this.context })\n\t\t);\n\t\tthis.envelope = new AmplitudeEnvelope(\n\t\t\tObject.assign(options.envelope, { context: this.context })\n\t\t);\n\n\t\t// connect the oscillators to the output\n\t\tthis.oscillator.chain(this.filter, this.envelope, this.output);\n\n\t\t// connect the filter envelope\n\t\tthis.filterEnvelope.connect(this.filter.frequency);\n\n\t\treadOnly(this, [\n\t\t\t\"oscillator\",\n\t\t\t\"frequency\",\n\t\t\t\"detune\",\n\t\t\t\"filter\",\n\t\t\t\"filterEnvelope\",\n\t\t\t\"envelope\",\n\t\t]);\n\t}\n\n\tstatic getDefaults(): MonoSynthOptions {\n\t\treturn Object.assign(Monophonic.getDefaults(), {\n\t\t\tenvelope: Object.assign(\n\t\t\t\tomitFromObject(\n\t\t\t\t\tEnvelope.getDefaults(),\n\t\t\t\t\tObject.keys(ToneAudioNode.getDefaults())\n\t\t\t\t),\n\t\t\t\t{\n\t\t\t\t\tattack: 0.005,\n\t\t\t\t\tdecay: 0.1,\n\t\t\t\t\trelease: 1,\n\t\t\t\t\tsustain: 0.9,\n\t\t\t\t}\n\t\t\t),\n\t\t\tfilter: Object.assign(\n\t\t\t\tomitFromObject(\n\t\t\t\t\tFilter.getDefaults(),\n\t\t\t\t\tObject.keys(ToneAudioNode.getDefaults())\n\t\t\t\t),\n\t\t\t\t{\n\t\t\t\t\tQ: 1,\n\t\t\t\t\trolloff: -12,\n\t\t\t\t\ttype: \"lowpass\",\n\t\t\t\t}\n\t\t\t),\n\t\t\tfilterEnvelope: Object.assign(\n\t\t\t\tomitFromObject(\n\t\t\t\t\tFrequencyEnvelope.getDefaults(),\n\t\t\t\t\tObject.keys(ToneAudioNode.getDefaults())\n\t\t\t\t),\n\t\t\t\t{\n\t\t\t\t\tattack: 0.6,\n\t\t\t\t\tbaseFrequency: 200,\n\t\t\t\t\tdecay: 0.2,\n\t\t\t\t\texponent: 2,\n\t\t\t\t\toctaves: 3,\n\t\t\t\t\trelease: 2,\n\t\t\t\t\tsustain: 0.5,\n\t\t\t\t}\n\t\t\t),\n\t\t\toscillator: Object.assign(\n\t\t\t\tomitFromObject(\n\t\t\t\t\tOmniOscillator.getDefaults(),\n\t\t\t\t\tObject.keys(Source.getDefaults())\n\t\t\t\t),\n\t\t\t\t{\n\t\t\t\t\ttype: \"sawtooth\",\n\t\t\t\t}\n\t\t\t) as OmniOscillatorSynthOptions,\n\t\t});\n\t}\n\n\t/**\n\t * start the attack portion of the envelope\n\t * @param time the time the attack should start\n\t * @param velocity the velocity of the note (0-1)\n\t */\n\tprotected _triggerEnvelopeAttack(time: Seconds, velocity = 1): void {\n\t\tthis.envelope.triggerAttack(time, velocity);\n\t\tthis.filterEnvelope.triggerAttack(time);\n\t\tthis.oscillator.start(time);\n\t\tif (this.envelope.sustain === 0) {\n\t\t\tconst computedAttack = this.toSeconds(this.envelope.attack);\n\t\t\tconst computedDecay = this.toSeconds(this.envelope.decay);\n\t\t\tthis.oscillator.stop(time + computedAttack + computedDecay);\n\t\t}\n\t}\n\n\t/**\n\t * start the release portion of the envelope\n\t * @param time the time the release should start\n\t */\n\tprotected _triggerEnvelopeRelease(time: Seconds): void {\n\t\tthis.envelope.triggerRelease(time);\n\t\tthis.filterEnvelope.triggerRelease(time);\n\t\tthis.oscillator.stop(time + this.toSeconds(this.envelope.release));\n\t}\n\n\tgetLevelAtTime(time: Time): NormalRange {\n\t\ttime = this.toSeconds(time);\n\t\treturn this.envelope.getValueAtTime(time);\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.oscillator.dispose();\n\t\tthis.envelope.dispose();\n\t\tthis.filterEnvelope.dispose();\n\t\tthis.filter.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/instrument/Monophonic.ts",
    "content": "import { FrequencyClass } from \"../core/type/Frequency.js\";\nimport {\n\tCents,\n\tFrequency,\n\tNormalRange,\n\tSeconds,\n\tTime,\n} from \"../core/type/Units.js\";\nimport { timeRange } from \"../core/util/Decorator.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { noOp } from \"../core/util/Interface.js\";\nimport { Instrument, InstrumentOptions } from \"../instrument/Instrument.js\";\nimport { Signal } from \"../signal/Signal.js\";\n\ntype onSilenceCallback = (instrument: Monophonic<any>) => void;\n\nexport interface MonophonicOptions extends InstrumentOptions {\n\tportamento: Seconds;\n\tonsilence: onSilenceCallback;\n\tdetune: Cents;\n}\n\n/**\n * Abstract base class for other monophonic instruments to extend.\n */\nexport abstract class Monophonic<\n\tOptions extends MonophonicOptions,\n> extends Instrument<Options> {\n\t/**\n\t * The glide time between notes.\n\t */\n\t@timeRange(0)\n\tportamento: Seconds;\n\n\t/**\n\t * Invoked when the release has finished and the output is silent.\n\t */\n\tonsilence: onSilenceCallback;\n\n\t/**\n\t * The instrument's frequency signal.\n\t */\n\tabstract readonly frequency: Signal<\"frequency\">;\n\n\t/**\n\t * The instrument's detune control signal.\n\t */\n\tabstract readonly detune: Signal<\"cents\">;\n\n\tconstructor(options?: Partial<MonophonicOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tMonophonic.getDefaults(),\n\t\t\targuments\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.portamento = options.portamento;\n\t\tthis.onsilence = options.onsilence;\n\t}\n\n\tstatic getDefaults(): MonophonicOptions {\n\t\treturn Object.assign(Instrument.getDefaults(), {\n\t\t\tdetune: 0,\n\t\t\tonsilence: noOp,\n\t\t\tportamento: 0,\n\t\t});\n\t}\n\n\t/**\n\t * Trigger the attack of the note optionally with a given velocity.\n\t * @param  note The note to trigger.\n\t * @param  time When the note should start.\n\t * @param  velocity The velocity determines how \"loud\" the note will be.\n\t * @example\n\t * const synth = new Tone.Synth().toDestination();\n\t * // trigger the note a half second from now at half velocity\n\t * synth.triggerAttack(\"C4\", \"+0.5\", 0.5);\n\t */\n\ttriggerAttack(\n\t\tnote: Frequency | FrequencyClass,\n\t\ttime?: Time,\n\t\tvelocity: NormalRange = 1\n\t): this {\n\t\tthis.log(\"triggerAttack\", note, time, velocity);\n\t\tconst seconds = this.toSeconds(time);\n\t\tthis._triggerEnvelopeAttack(seconds, velocity);\n\t\tthis.setNote(note, seconds);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Trigger the release portion of the envelope.\n\t * @param  time If no time is given, the release happens immediately.\n\t * @example\n\t * const synth = new Tone.Synth().toDestination();\n\t * synth.triggerAttack(\"C4\");\n\t * // trigger the release a second from now\n\t * synth.triggerRelease(\"+1\");\n\t */\n\ttriggerRelease(time?: Time): this {\n\t\tthis.log(\"triggerRelease\", time);\n\t\tconst seconds = this.toSeconds(time);\n\t\tthis._triggerEnvelopeRelease(seconds);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Internal method which starts the envelope attack\n\t */\n\tprotected abstract _triggerEnvelopeAttack(\n\t\ttime: Seconds,\n\t\tvelocity: NormalRange\n\t): void;\n\n\t/**\n\t * Internal method which starts the envelope release\n\t */\n\tprotected abstract _triggerEnvelopeRelease(time: Seconds): void;\n\n\t/**\n\t * Get the level of the output at the given time. Measures\n\t * the envelope(s) value at the time.\n\t * @param time The time to query the envelope value\n\t * @return The output level between 0-1\n\t */\n\tabstract getLevelAtTime(time: Time): NormalRange;\n\n\t/**\n\t * Set the note at the given time. If no time is given, the note\n\t * will set immediately.\n\t * @param note The note to change to.\n\t * @param  time The time when the note should be set.\n\t * @example\n\t * const synth = new Tone.Synth().toDestination();\n\t * synth.triggerAttack(\"C4\");\n\t * // change to F#6 in one quarter note from now.\n\t * synth.setNote(\"F#6\", \"+4n\");\n\t */\n\tsetNote(note: Frequency | FrequencyClass, time?: Time): this {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tconst computedFrequency =\n\t\t\tnote instanceof FrequencyClass ? note.toFrequency() : note;\n\t\tif (this.portamento > 0 && this.getLevelAtTime(computedTime) > 0.05) {\n\t\t\tconst portTime = this.toSeconds(this.portamento);\n\t\t\tthis.frequency.exponentialRampTo(\n\t\t\t\tcomputedFrequency,\n\t\t\t\tportTime,\n\t\t\t\tcomputedTime\n\t\t\t);\n\t\t} else {\n\t\t\tthis.frequency.setValueAtTime(computedFrequency, computedTime);\n\t\t}\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/instrument/NoiseSynth.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { InstrumentTest } from \"../../test/helper/InstrumentTests.js\";\nimport { NoiseSynth } from \"./NoiseSynth.js\";\n\ndescribe(\"NoiseSynth\", () => {\n\tBasicTests(NoiseSynth);\n\n\tInstrumentTest(NoiseSynth, undefined, {\n\t\tenvelope: {\n\t\t\tdecay: 0.1,\n\t\t\trelease: 0.2,\n\t\t\tsustain: 0.5,\n\t\t},\n\t});\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst synth = new NoiseSynth({\n\t\t\t\t\tenvelope: {\n\t\t\t\t\t\tattack: 0.01,\n\t\t\t\t\t\tdecay: 0.4,\n\t\t\t\t\t},\n\t\t\t\t}).toDestination();\n\t\t\t\tsynth.triggerAttack(0);\n\t\t\t\tsynth.triggerAttack(0.3);\n\t\t\t},\n\t\t\t\"noiseSynth.wav\",\n\t\t\t4\n\t\t);\n\t});\n\n\tit(\"matches another file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst synth = new NoiseSynth({\n\t\t\t\t\tenvelope: {\n\t\t\t\t\t\tattack: 0.01,\n\t\t\t\t\t\tdecay: 0.4,\n\t\t\t\t\t},\n\t\t\t\t}).toDestination();\n\t\t\t\tsynth.triggerAttackRelease(0.1, 0);\n\t\t\t},\n\t\t\t\"noiseSynthRelease.wav\",\n\t\t\t4\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can get and set noise type\", () => {\n\t\t\tconst noiseSynth = new NoiseSynth();\n\t\t\tnoiseSynth.noise.type = \"pink\";\n\t\t\texpect(noiseSynth.noise.type).to.equal(\"pink\");\n\t\t\tnoiseSynth.dispose();\n\t\t});\n\n\t\tit(\"can get and set envelope attributes\", () => {\n\t\t\tconst noiseSynth = new NoiseSynth();\n\t\t\tnoiseSynth.envelope.attack = 0.24;\n\t\t\texpect(noiseSynth.envelope.attack).to.equal(0.24);\n\t\t\tnoiseSynth.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an options object\", () => {\n\t\t\tconst noiseSynth = new NoiseSynth({\n\t\t\t\tenvelope: {\n\t\t\t\t\tsustain: 0.3,\n\t\t\t\t},\n\t\t\t});\n\t\t\texpect(noiseSynth.envelope.sustain).to.equal(0.3);\n\t\t\tnoiseSynth.dispose();\n\t\t});\n\n\t\tit(\"can get/set attributes\", () => {\n\t\t\tconst noiseSynth = new NoiseSynth();\n\t\t\tnoiseSynth.set({\n\t\t\t\tenvelope: {\n\t\t\t\t\tdecay: 0.24,\n\t\t\t\t},\n\t\t\t});\n\t\t\texpect(noiseSynth.get().envelope.decay).to.equal(0.24);\n\t\t\tnoiseSynth.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/instrument/NoiseSynth.ts",
    "content": "import { AmplitudeEnvelope } from \"../component/envelope/AmplitudeEnvelope.js\";\nimport { Envelope, EnvelopeOptions } from \"../component/envelope/Envelope.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../core/context/ToneAudioNode.js\";\nimport { NormalRange, Time } from \"../core/type/Units.js\";\nimport { omitFromObject, optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { RecursivePartial } from \"../core/util/Interface.js\";\nimport { Noise, NoiseOptions } from \"../source/Noise.js\";\nimport { Source } from \"../source/Source.js\";\nimport { Instrument, InstrumentOptions } from \"./Instrument.js\";\n\nexport interface NoiseSynthOptions extends InstrumentOptions {\n\tenvelope: Omit<EnvelopeOptions, keyof ToneAudioNodeOptions>;\n\tnoise: Omit<NoiseOptions, keyof ToneAudioNodeOptions>;\n}\n\n/**\n * Tone.NoiseSynth is composed of {@link Noise} through an {@link AmplitudeEnvelope}.\n * ```\n * +-------+   +-------------------+\n * | Noise +>--> AmplitudeEnvelope +>--> Output\n * +-------+   +-------------------+\n * ```\n * @example\n * const noiseSynth = new Tone.NoiseSynth().toDestination();\n * noiseSynth.triggerAttackRelease(\"8n\", 0.05);\n * @category Instrument\n */\nexport class NoiseSynth extends Instrument<NoiseSynthOptions> {\n\treadonly name = \"NoiseSynth\";\n\n\t/**\n\t * The noise source.\n\t */\n\treadonly noise: Noise;\n\n\t/**\n\t * The amplitude envelope.\n\t */\n\treadonly envelope: AmplitudeEnvelope;\n\n\tconstructor(options?: RecursivePartial<NoiseSynthOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tNoiseSynth.getDefaults(),\n\t\t\targuments\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.noise = new Noise(\n\t\t\tObject.assign(\n\t\t\t\t{\n\t\t\t\t\tcontext: this.context,\n\t\t\t\t},\n\t\t\t\toptions.noise\n\t\t\t)\n\t\t);\n\n\t\tthis.envelope = new AmplitudeEnvelope(\n\t\t\tObject.assign(\n\t\t\t\t{\n\t\t\t\t\tcontext: this.context,\n\t\t\t\t},\n\t\t\t\toptions.envelope\n\t\t\t)\n\t\t);\n\n\t\t// connect the noise to the output\n\t\tthis.noise.chain(this.envelope, this.output);\n\t}\n\n\tstatic getDefaults(): NoiseSynthOptions {\n\t\treturn Object.assign(Instrument.getDefaults(), {\n\t\t\tenvelope: Object.assign(\n\t\t\t\tomitFromObject(\n\t\t\t\t\tEnvelope.getDefaults(),\n\t\t\t\t\tObject.keys(ToneAudioNode.getDefaults())\n\t\t\t\t),\n\t\t\t\t{\n\t\t\t\t\tdecay: 0.1,\n\t\t\t\t\tsustain: 0.0,\n\t\t\t\t}\n\t\t\t),\n\t\t\tnoise: Object.assign(\n\t\t\t\tomitFromObject(\n\t\t\t\t\tNoise.getDefaults(),\n\t\t\t\t\tObject.keys(Source.getDefaults())\n\t\t\t\t),\n\t\t\t\t{\n\t\t\t\t\ttype: \"white\",\n\t\t\t\t}\n\t\t\t),\n\t\t});\n\t}\n\n\t/**\n\t * Start the attack portion of the envelopes. Unlike other\n\t * instruments, Tone.NoiseSynth doesn't have a note.\n\t * @example\n\t * const noiseSynth = new Tone.NoiseSynth().toDestination();\n\t * noiseSynth.triggerAttack();\n\t */\n\ttriggerAttack(time?: Time, velocity: NormalRange = 1): this {\n\t\ttime = this.toSeconds(time);\n\t\t// the envelopes\n\t\tthis.envelope.triggerAttack(time, velocity);\n\t\t// start the noise\n\t\tthis.noise.start(time);\n\t\tif (this.envelope.sustain === 0) {\n\t\t\tthis.noise.stop(\n\t\t\t\ttime +\n\t\t\t\t\tthis.toSeconds(this.envelope.attack) +\n\t\t\t\t\tthis.toSeconds(this.envelope.decay)\n\t\t\t);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Start the release portion of the envelopes.\n\t */\n\ttriggerRelease(time?: Time): this {\n\t\ttime = this.toSeconds(time);\n\t\tthis.envelope.triggerRelease(time);\n\t\tthis.noise.stop(time + this.toSeconds(this.envelope.release));\n\t\treturn this;\n\t}\n\n\tsync(): this {\n\t\tif (this._syncState()) {\n\t\t\tthis._syncMethod(\"triggerAttack\", 0);\n\t\t\tthis._syncMethod(\"triggerRelease\", 0);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Trigger the attack and then the release after the duration.\n\t * @param duration The amount of time to hold the note for\n\t * @param time The time the note should start\n\t * @param velocity The volume of the note (0-1)\n\t * @example\n\t * const noiseSynth = new Tone.NoiseSynth().toDestination();\n\t * // hold the note for 0.5 seconds\n\t * noiseSynth.triggerAttackRelease(0.5);\n\t */\n\ttriggerAttackRelease(\n\t\tduration: Time,\n\t\ttime?: Time,\n\t\tvelocity: NormalRange = 1\n\t): this {\n\t\ttime = this.toSeconds(time);\n\t\tduration = this.toSeconds(duration);\n\t\tthis.triggerAttack(time, velocity);\n\t\tthis.triggerRelease(time + duration);\n\t\treturn this;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.noise.dispose();\n\t\tthis.envelope.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/instrument/PluckSynth.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { InstrumentTest } from \"../../test/helper/InstrumentTests.js\";\nimport { PluckSynth } from \"./PluckSynth.js\";\n\ndescribe(\"PluckSynth\", () => {\n\tBasicTests(PluckSynth);\n\tInstrumentTest(PluckSynth, \"C3\");\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst synth = new PluckSynth().toDestination();\n\t\t\t\tsynth.triggerAttack(\"C4\");\n\t\t\t},\n\t\t\t\"pluckSynth.wav\",\n\t\t\t0.02\n\t\t);\n\t});\n\n\tit(\"matches a file with release\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst synth = new PluckSynth({\n\t\t\t\t\tresonance: 0.97,\n\t\t\t\t\trelease: 0.2,\n\t\t\t\t}).toDestination();\n\t\t\t\tsynth.triggerAttackRelease(\"C4\", 0.6);\n\t\t\t},\n\t\t\t\"pluckSynth2.wav\",\n\t\t\t0.06\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can get and set resonance\", () => {\n\t\t\tconst pluck = new PluckSynth();\n\t\t\tpluck.resonance = 0.4;\n\t\t\texpect(pluck.resonance).to.be.closeTo(0.4, 0.001);\n\t\t\tpluck.dispose();\n\t\t});\n\n\t\tit(\"can get and set dampening\", () => {\n\t\t\tconst pluck = new PluckSynth();\n\t\t\tpluck.dampening = 2000;\n\t\t\texpect(pluck.dampening).to.be.closeTo(2000, 0.1);\n\t\t\tpluck.dispose();\n\t\t});\n\n\t\tit(\"can get and set the attackNoise\", () => {\n\t\t\tconst pluck = new PluckSynth();\n\t\t\tpluck.attackNoise = 0.2;\n\t\t\texpect(pluck.attackNoise).to.be.closeTo(0.2, 0.1);\n\t\t\tpluck.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an options object\", () => {\n\t\t\tconst pluck = new PluckSynth({\n\t\t\t\tdampening: 300,\n\t\t\t\tresonance: 0.5,\n\t\t\t});\n\t\t\texpect(pluck.dampening).to.be.closeTo(300, 0.1);\n\t\t\texpect(pluck.resonance).to.be.closeTo(0.5, 0.001);\n\t\t\tpluck.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/instrument/PluckSynth.ts",
    "content": "import { LowpassCombFilter } from \"../component/filter/LowpassCombFilter.js\";\nimport { Frequency, NormalRange, Time } from \"../core/type/Units.js\";\nimport { deepMerge } from \"../core/util/Defaults.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { RecursivePartial } from \"../core/util/Interface.js\";\nimport { Noise } from \"../source/Noise.js\";\nimport { Instrument, InstrumentOptions } from \"./Instrument.js\";\n\nexport interface PluckSynthOptions extends InstrumentOptions {\n\tattackNoise: number;\n\tdampening: Frequency;\n\tresonance: NormalRange;\n\trelease: Time;\n}\n\n/**\n * Karplus-Strong string synthesis.\n * @example\n * const plucky = new Tone.PluckSynth().toDestination();\n * plucky.triggerAttack(\"C4\", \"+0.5\");\n * plucky.triggerAttack(\"C3\", \"+1\");\n * plucky.triggerAttack(\"C2\", \"+1.5\");\n * plucky.triggerAttack(\"C1\", \"+2\");\n * @category Instrument\n */\nexport class PluckSynth extends Instrument<PluckSynthOptions> {\n\treadonly name = \"PluckSynth\";\n\n\t/**\n\t * Noise burst at the beginning\n\t */\n\tprivate _noise: Noise;\n\tprivate _lfcf: LowpassCombFilter;\n\n\t/**\n\t * The amount of noise at the attack.\n\t * Nominal range of [0.1, 20]\n\t * @min 0.1\n\t * @max 20\n\t */\n\tattackNoise: number;\n\n\t/**\n\t * The amount of resonance of the pluck. Also correlates to the sustain duration.\n\t */\n\tresonance: NormalRange;\n\n\t/**\n\t * The release time which corresponds to a resonance ramp down to 0\n\t */\n\trelease: Time;\n\n\tconstructor(options?: RecursivePartial<PluckSynthOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tPluckSynth.getDefaults(),\n\t\t\targuments\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._noise = new Noise({\n\t\t\tcontext: this.context,\n\t\t\ttype: \"pink\",\n\t\t});\n\n\t\tthis.attackNoise = options.attackNoise;\n\n\t\tthis._lfcf = new LowpassCombFilter({\n\t\t\tcontext: this.context,\n\t\t\tdampening: options.dampening,\n\t\t\tresonance: options.resonance,\n\t\t});\n\n\t\tthis.resonance = options.resonance;\n\t\tthis.release = options.release;\n\n\t\tthis._noise.connect(this._lfcf);\n\t\tthis._lfcf.connect(this.output);\n\t}\n\n\tstatic getDefaults(): PluckSynthOptions {\n\t\treturn deepMerge(Instrument.getDefaults(), {\n\t\t\tattackNoise: 1,\n\t\t\tdampening: 4000,\n\t\t\tresonance: 0.7,\n\t\t\trelease: 1,\n\t\t});\n\t}\n\n\t/**\n\t * The dampening control. i.e. the lowpass filter frequency of the comb filter\n\t * @min 0\n\t * @max 7000\n\t */\n\tget dampening(): Frequency {\n\t\treturn this._lfcf.dampening;\n\t}\n\tset dampening(fq) {\n\t\tthis._lfcf.dampening = fq;\n\t}\n\n\ttriggerAttack(note: Frequency, time?: Time): this {\n\t\tconst freq = this.toFrequency(note);\n\t\ttime = this.toSeconds(time);\n\t\tconst delayAmount = 1 / freq;\n\t\tthis._lfcf.delayTime.setValueAtTime(delayAmount, time);\n\t\tthis._noise.start(time);\n\t\tthis._noise.stop(time + delayAmount * this.attackNoise);\n\t\tthis._lfcf.resonance.cancelScheduledValues(time);\n\t\tthis._lfcf.resonance.setValueAtTime(this.resonance, time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Ramp down the {@link resonance} to 0 over the duration of the release time.\n\t */\n\ttriggerRelease(time?: Time): this {\n\t\tthis._lfcf.resonance.linearRampTo(0, this.release, time);\n\t\treturn this;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._noise.dispose();\n\t\tthis._lfcf.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/instrument/PolySynth.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests, warns } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { atTime, Offline } from \"../../test/helper/Offline.js\";\nimport { OutputAudio } from \"../../test/helper/OutputAudio.js\";\nimport { FMSynth } from \"./FMSynth.js\";\nimport { MembraneSynth } from \"./MembraneSynth.js\";\nimport { MetalSynth } from \"./MetalSynth.js\";\nimport { PluckSynth } from \"./PluckSynth.js\";\nimport { PolySynth } from \"./PolySynth.js\";\nimport { Synth } from \"./Synth.js\";\n\ndescribe(\"PolySynth\", () => {\n\tBasicTests(PolySynth);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst synth = new PolySynth().toDestination();\n\t\t\t\tsynth.triggerAttackRelease(\"C4\", 0.2, 0);\n\t\t\t\tsynth.triggerAttackRelease(\"C4\", 0.1, 0.1);\n\t\t\t\tsynth.triggerAttackRelease(\"E4\", 0.1, 0.2);\n\t\t\t\tsynth.triggerAttackRelease(\"E4\", 0.1, 0.3);\n\t\t\t\tsynth.triggerAttackRelease(\"G4\", 0.1, 0.4);\n\t\t\t\tsynth.triggerAttackRelease(\"B4\", 0.1, 0.4);\n\t\t\t\tsynth.triggerAttackRelease(\"C4\", 0.2, 0.5);\n\t\t\t},\n\t\t\t\"polySynth.wav\",\n\t\t\t0.6\n\t\t);\n\t});\n\n\tit(\"matches another file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst synth = new PolySynth().toDestination();\n\t\t\t\tsynth.triggerAttackRelease([\"C4\", \"E4\", \"G4\", \"B4\"], 0.2, 0);\n\t\t\t\tsynth.triggerAttackRelease([\"C4\", \"E4\", \"G4\", \"B4\"], 0.2, 0.3);\n\t\t\t},\n\t\t\t\"polySynth2.wav\",\n\t\t\t0.6\n\t\t);\n\t});\n\n\tit(\"matches a file and chooses the right voice\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst synth = new PolySynth().toDestination();\n\t\t\t\tsynth.triggerAttackRelease([\"C4\", \"E4\"], 1, 0);\n\t\t\t\tsynth.triggerAttackRelease(\"G4\", 0.1, 0.2);\n\t\t\t\tsynth.triggerAttackRelease(\"B4\", 0.1, 0.4);\n\t\t\t\tsynth.triggerAttackRelease(\"G4\", 0.1, 0.6);\n\t\t\t},\n\t\t\t\"polySynth3.wav\",\n\t\t\t0.5\n\t\t);\n\t});\n\n\tit(\"can be constructed with monophonic synths\", () => {\n\t\texpect(() => {\n\t\t\tconst polySynth = new PolySynth(Synth);\n\t\t\tpolySynth.dispose();\n\t\t}).to.not.throw(Error);\n\t\texpect(() => {\n\t\t\tconst polySynth = new PolySynth(FMSynth);\n\t\t\tpolySynth.dispose();\n\t\t}).to.not.throw(Error);\n\t\texpect(() => {\n\t\t\tconst polySynth = new PolySynth(MetalSynth);\n\t\t\tpolySynth.dispose();\n\t\t}).to.not.throw(Error);\n\t\texpect(() => {\n\t\t\tconst polySynth = new PolySynth(MembraneSynth);\n\t\t\tpolySynth.dispose();\n\t\t}).to.not.throw(Error);\n\t});\n\n\tcontext(\"Playing Notes\", () => {\n\t\tit(\"triggerAttackRelease can take an array of durations\", async () => {\n\t\t\tawait OutputAudio(() => {\n\t\t\t\tconst polySynth = new PolySynth();\n\t\t\t\tpolySynth.toDestination();\n\t\t\t\tpolySynth.triggerAttackRelease([\"C4\", \"D4\"], [0.1, 0.2]);\n\t\t\t});\n\t\t});\n\n\t\tit(\"triggerAttack and triggerRelease can be invoked without arrays\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst polySynth = new PolySynth();\n\t\t\t\tpolySynth.set({ envelope: { release: 0.1 } });\n\t\t\t\tpolySynth.toDestination();\n\t\t\t\tpolySynth.triggerAttack(\"C4\", 0);\n\t\t\t\tpolySynth.triggerRelease(\"C4\", 0.1);\n\t\t\t}, 0.3);\n\t\t\texpect(buffer.getTimeOfFirstSound()).to.be.closeTo(0, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.2)).to.be.closeTo(0, 0.01);\n\t\t});\n\n\t\tit(\"can stop all of the currently playing sounds\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst polySynth = new PolySynth();\n\t\t\t\tpolySynth.set({ envelope: { release: 0.1 } });\n\t\t\t\tpolySynth.toDestination();\n\t\t\t\tpolySynth.triggerAttack([\"C4\", \"E4\", \"G4\", \"B4\"], 0);\n\t\t\t\treturn atTime(0.1, () => {\n\t\t\t\t\tpolySynth.releaseAll();\n\t\t\t\t});\n\t\t\t}, 0.3);\n\t\t\texpect(buffer.getTimeOfFirstSound()).to.be.closeTo(0, 0.01);\n\t\t\texpect(buffer.getTimeOfLastSound()).to.be.closeTo(0.2, 0.01);\n\t\t});\n\n\t\tit(\"is silent before being triggered\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst polySynth = new PolySynth();\n\t\t\t\tpolySynth.toDestination();\n\t\t\t});\n\t\t\texpect(buffer.isSilent()).to.be.true;\n\t\t});\n\n\t\tit(\"can be scheduled to start in the future\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst polySynth = new PolySynth();\n\t\t\t\tpolySynth.toDestination();\n\t\t\t\tpolySynth.triggerAttack(\"C4\", 0.1);\n\t\t\t}, 0.3);\n\t\t\texpect(buffer.getTimeOfFirstSound()).to.be.closeTo(0.1, 0.01);\n\t\t});\n\n\t\tit(\"can stop all sounds scheduled to start in the future when disposed\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst polySynth = new PolySynth();\n\t\t\t\tpolySynth.set({ envelope: { release: 0.1 } });\n\t\t\t\tpolySynth.toDestination();\n\t\t\t\tpolySynth.triggerAttackRelease([\"C4\", \"E4\", \"G4\", \"B4\"], 0.2);\n\t\t\t\treturn atTime(0.1, () => {\n\t\t\t\t\tpolySynth.dispose();\n\t\t\t\t});\n\t\t\t}, 0.3);\n\t\t\texpect(buffer.isSilent()).to.be.true;\n\t\t});\n\n\t\tit(\"disposes voices when they are no longer used\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst polySynth = new PolySynth(Synth, {\n\t\t\t\t\tenvelope: {\n\t\t\t\t\t\trelease: 0.1,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tpolySynth.toDestination();\n\t\t\t\tpolySynth.triggerAttackRelease(\n\t\t\t\t\t[\"C4\", \"E4\", \"G4\", \"B4\", \"D5\"],\n\t\t\t\t\t0.1,\n\t\t\t\t\t0\n\t\t\t\t);\n\t\t\t\treturn [\n\t\t\t\t\tatTime(0, () => {\n\t\t\t\t\t\texpect(polySynth.activeVoices).to.equal(5);\n\t\t\t\t\t}),\n\t\t\t\t\tatTime(0.3, () => {\n\t\t\t\t\t\texpect(polySynth.activeVoices).to.equal(0);\n\t\t\t\t\t}),\n\t\t\t\t];\n\t\t\t}, 10);\n\t\t});\n\n\t\tit(\"warns when too much polyphony is attempted and notes are dropped\", () => {\n\t\t\twarns(() => {\n\t\t\t\treturn Offline(() => {\n\t\t\t\t\tconst polySynth = new PolySynth({\n\t\t\t\t\t\tmaxPolyphony: 2,\n\t\t\t\t\t});\n\t\t\t\t\tpolySynth.toDestination();\n\t\t\t\t\tpolySynth.triggerAttack([\"C4\", \"D4\", \"G4\"], 0.1);\n\t\t\t\t}, 0.3);\n\t\t\t});\n\t\t});\n\n\t\tit(\"reports the active notes\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst polySynth = new PolySynth();\n\t\t\t\tpolySynth.set({ envelope: { release: 0.1 } });\n\t\t\t\tpolySynth.toDestination();\n\t\t\t\tpolySynth.triggerAttackRelease(\"C4\", 0.1, 0.1);\n\t\t\t\tpolySynth.triggerAttackRelease(\"D4\", 0.1, 0.2);\n\t\t\t\tpolySynth.triggerAttackRelease(\"C4\", 0.1, 0.5);\n\t\t\t\tpolySynth.triggerAttackRelease(\"C4\", 0.1, 0.6);\n\t\t\t\treturn [\n\t\t\t\t\tatTime(0, () => {\n\t\t\t\t\t\texpect(polySynth.activeVoices).to.equal(0);\n\t\t\t\t\t}),\n\t\t\t\t\tatTime(0.1, () => {\n\t\t\t\t\t\texpect(polySynth.activeVoices).to.equal(1);\n\t\t\t\t\t}),\n\t\t\t\t\tatTime(0.2, () => {\n\t\t\t\t\t\texpect(polySynth.activeVoices).to.equal(2);\n\t\t\t\t\t}),\n\t\t\t\t\tatTime(0.3, () => {\n\t\t\t\t\t\texpect(polySynth.activeVoices).to.equal(1);\n\t\t\t\t\t}),\n\t\t\t\t\tatTime(0.4, () => {\n\t\t\t\t\t\texpect(polySynth.activeVoices).to.equal(0);\n\t\t\t\t\t}),\n\t\t\t\t\tatTime(0.5, () => {\n\t\t\t\t\t\texpect(polySynth.activeVoices).to.equal(1);\n\t\t\t\t\t}),\n\t\t\t\t\tatTime(0.6, () => {\n\t\t\t\t\t\texpect(polySynth.activeVoices).to.equal(2);\n\t\t\t\t\t}),\n\t\t\t\t\tatTime(0.7, () => {\n\t\t\t\t\t\texpect(polySynth.activeVoices).to.equal(1);\n\t\t\t\t\t}),\n\t\t\t\t\tatTime(0.8, () => {\n\t\t\t\t\t\texpect(polySynth.activeVoices).to.equal(0);\n\t\t\t\t\t}),\n\t\t\t\t];\n\t\t\t}, 1);\n\t\t});\n\n\t\tit(\"can trigger another attack before the release has ended\", async () => {\n\t\t\t// compute the end time\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst synth = new PolySynth(Synth, {\n\t\t\t\t\tenvelope: {\n\t\t\t\t\t\trelease: 0.1,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tsynth.toDestination();\n\t\t\t\tsynth.triggerAttack(\"C4\", 0.05);\n\t\t\t\tsynth.triggerRelease(\"C4\", 0.1);\n\t\t\t\tsynth.triggerAttack(\"C4\", 0.15);\n\t\t\t\tsynth.triggerRelease(\"C4\", 0.2);\n\t\t\t}, 1);\n\t\t\texpect(buffer.getTimeOfLastSound()).to.be.closeTo(0.3, 0.01);\n\t\t});\n\n\t\tit(\"can trigger another attack right after the release has ended\", async () => {\n\t\t\t// compute the end time\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst synth = new PolySynth(Synth, {\n\t\t\t\t\tenvelope: {\n\t\t\t\t\t\trelease: 0.1,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tsynth.toDestination();\n\t\t\t\tsynth.triggerAttack(\"C4\", 0.05);\n\t\t\t\tsynth.triggerRelease(\"C4\", 0.1);\n\t\t\t\tsynth.triggerAttack(\"C4\", 0.2);\n\t\t\t\tsynth.triggerRelease(\"C4\", 0.3);\n\t\t\t\treturn atTime(0.41, () => {\n\t\t\t\t\texpect(synth.activeVoices).to.equal(0);\n\t\t\t\t});\n\t\t\t}, 1);\n\t\t\texpect(buffer.getTimeOfLastSound()).to.be.closeTo(0.4, 0.01);\n\t\t});\n\t});\n\n\tcontext(\"Transport sync\", () => {\n\t\tit(\"can be synced to the transport\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst polySynth = new PolySynth(Synth, {\n\t\t\t\t\tenvelope: {\n\t\t\t\t\t\trelease: 0.1,\n\t\t\t\t\t},\n\t\t\t\t}).sync();\n\t\t\t\tpolySynth.toDestination();\n\t\t\t\tpolySynth.triggerAttackRelease(\"C4\", 0.1, 0.1);\n\t\t\t\tpolySynth.triggerAttackRelease(\"E4\", 0.1, 0.3);\n\t\t\t\ttransport.start(0.1);\n\t\t\t}, 0.8);\n\t\t\texpect(buffer.getTimeOfFirstSound()).to.be.closeTo(0.2, 0.01);\n\t\t\texpect(buffer.getTimeOfLastSound()).to.be.closeTo(0.6, 0.01);\n\t\t});\n\n\t\tit(\"is silent until the transport is started\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst synth = new PolySynth(Synth).sync().toDestination();\n\t\t\t\tsynth.triggerAttackRelease(\"C4\", 0.5);\n\t\t\t\ttransport.start(0.5);\n\t\t\t}, 1);\n\t\t\texpect(buffer.getTimeOfFirstSound()).is.closeTo(0.5, 0.1);\n\t\t});\n\n\t\tit(\"stops when the transport is stopped\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst synth = new PolySynth(Synth, {\n\t\t\t\t\tenvelope: {\n\t\t\t\t\t\trelease: 0,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\t\t.sync()\n\t\t\t\t\t.toDestination();\n\t\t\t\tsynth.triggerAttackRelease(\"C4\", 0.5);\n\t\t\t\ttransport.start(0.5).stop(1);\n\t\t\t}, 1.5);\n\t\t\texpect(buffer.getTimeOfLastSound()).is.closeTo(1, 0.1);\n\t\t});\n\n\t\tit(\"goes silent at the loop boundary\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst synth = new PolySynth(Synth, {\n\t\t\t\t\tenvelope: {\n\t\t\t\t\t\trelease: 0,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\t\t.sync()\n\t\t\t\t\t.toDestination();\n\t\t\t\tsynth.triggerAttackRelease(\"C4\", 0.8, 0.5);\n\t\t\t\ttransport.loopEnd = 1;\n\t\t\t\ttransport.loop = true;\n\t\t\t\ttransport.start();\n\t\t\t}, 2);\n\t\t\texpect(buffer.getRmsAtTime(0)).to.be.closeTo(0, 0.05);\n\t\t\texpect(buffer.getRmsAtTime(0.6)).to.be.closeTo(0.2, 0.05);\n\t\t\texpect(buffer.getRmsAtTime(1.1)).to.be.closeTo(0, 0.05);\n\t\t\texpect(buffer.getRmsAtTime(1.6)).to.be.closeTo(0.2, 0.05);\n\t\t});\n\n\t\tit(\"can unsync\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst synth = new PolySynth(Synth, {\n\t\t\t\t\tenvelope: {\n\t\t\t\t\t\tsustain: 1,\n\t\t\t\t\t\trelease: 0,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\t\t.sync()\n\t\t\t\t\t.toDestination()\n\t\t\t\t\t.unsync();\n\t\t\t\tsynth.triggerAttackRelease(\"C4\", 1, 0.5);\n\t\t\t\ttransport.start().stop(1);\n\t\t\t}, 2);\n\t\t\texpect(buffer.getRmsAtTime(0)).to.be.closeTo(0, 0.05);\n\t\t\texpect(buffer.getRmsAtTime(0.6)).to.be.closeTo(0.6, 0.05);\n\t\t\texpect(buffer.getRmsAtTime(1.4)).to.be.closeTo(0.6, 0.05);\n\t\t\texpect(buffer.getRmsAtTime(1.6)).to.be.closeTo(0, 0.05);\n\t\t});\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can be constructed with an options object\", () => {\n\t\t\tconst polySynth = new PolySynth(Synth, {\n\t\t\t\tenvelope: {\n\t\t\t\t\tsustain: 0.3,\n\t\t\t\t},\n\t\t\t});\n\t\t\texpect(polySynth.get().envelope.sustain).to.equal(0.3);\n\t\t\tpolySynth.dispose();\n\t\t});\n\n\t\tit(\"throws an error when used without a monophonic synth\", () => {\n\t\t\texpect(() => {\n\t\t\t\t// @ts-ignore\n\t\t\t\tnew PolySynth(PluckSynth);\n\t\t\t}).throws(Error);\n\t\t});\n\n\t\tit(\"can pass in the volume\", () => {\n\t\t\tconst polySynth = new PolySynth({\n\t\t\t\tvolume: -12,\n\t\t\t});\n\t\t\texpect(polySynth.volume.value).to.be.closeTo(-12, 0.1);\n\t\t\tpolySynth.dispose();\n\t\t});\n\n\t\tit(\"can get/set attributes\", () => {\n\t\t\tconst polySynth = new PolySynth();\n\t\t\tpolySynth.set({\n\t\t\t\tenvelope: { decay: 3 },\n\t\t\t});\n\t\t\texpect(polySynth.get().envelope.decay).to.equal(3);\n\t\t\tpolySynth.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/instrument/PolySynth.ts",
    "content": "import { MidiClass } from \"../core/type/Midi.js\";\nimport {\n\tFrequency,\n\tMidiNote,\n\tNormalRange,\n\tSeconds,\n\tTime,\n} from \"../core/type/Units.js\";\nimport { assert, warn } from \"../core/util/Debug.js\";\nimport {\n\tdeepMerge,\n\tomitFromObject,\n\toptionsFromArguments,\n} from \"../core/util/Defaults.js\";\nimport { RecursivePartial } from \"../core/util/Interface.js\";\nimport { isArray, isNumber } from \"../core/util/TypeCheck.js\";\nimport { AMSynth, AMSynthOptions } from \"./AMSynth.js\";\nimport { FMSynth, FMSynthOptions } from \"./FMSynth.js\";\nimport { Instrument, InstrumentOptions } from \"./Instrument.js\";\nimport { MembraneSynth, MembraneSynthOptions } from \"./MembraneSynth.js\";\nimport { MetalSynth, MetalSynthOptions } from \"./MetalSynth.js\";\nimport { Monophonic } from \"./Monophonic.js\";\nimport { MonoSynth, MonoSynthOptions } from \"./MonoSynth.js\";\nimport { Synth, SynthOptions } from \"./Synth.js\";\n\ntype VoiceConstructor<V> = {\n\tgetDefaults: () => VoiceOptions<V>;\n} & (new (...args: any[]) => V);\n\ntype OmitMonophonicOptions<T> = Omit<T, \"context\" | \"onsilence\">;\n\ntype VoiceOptions<T> = T extends MembraneSynth\n\t? MembraneSynthOptions\n\t: T extends MetalSynth\n\t\t? MetalSynthOptions\n\t\t: T extends FMSynth\n\t\t\t? FMSynthOptions\n\t\t\t: T extends MonoSynth\n\t\t\t\t? MonoSynthOptions\n\t\t\t\t: T extends AMSynth\n\t\t\t\t\t? AMSynthOptions\n\t\t\t\t\t: T extends Synth\n\t\t\t\t\t\t? SynthOptions\n\t\t\t\t\t\t: T extends Monophonic<infer U>\n\t\t\t\t\t\t\t? U\n\t\t\t\t\t\t\t: never;\n\n/**\n * The settable synth options. excludes monophonic options.\n */\ntype PartialVoiceOptions<T> = RecursivePartial<\n\tOmitMonophonicOptions<VoiceOptions<T>>\n>;\n\nexport interface PolySynthOptions<Voice> extends InstrumentOptions {\n\tmaxPolyphony: number;\n\tvoice: VoiceConstructor<Voice>;\n\toptions: PartialVoiceOptions<Voice>;\n}\n\n/**\n * PolySynth handles voice creation and allocation for any\n * instruments passed in as the second parameter. PolySynth is\n * not a synthesizer by itself, it merely manages voices of\n * one of the other types of synths, allowing any of the\n * monophonic synthesizers to be polyphonic.\n *\n * @example\n * const synth = new Tone.PolySynth().toDestination();\n * // set the attributes across all the voices using 'set'\n * synth.set({ detune: -1200 });\n * // play a chord\n * synth.triggerAttackRelease([\"C4\", \"E4\", \"A4\"], 1);\n * @category Instrument\n */\nexport class PolySynth<\n\tVoice extends Monophonic<any> = Synth,\n> extends Instrument<VoiceOptions<Voice>> {\n\treadonly name: string = \"PolySynth\";\n\n\t/**\n\t * The voices which are not currently in use\n\t */\n\tprivate _availableVoices: Voice[] = [];\n\n\t/**\n\t * The currently active voices\n\t */\n\tprivate _activeVoices: Array<{\n\t\tmidi: MidiNote;\n\t\tvoice: Voice;\n\t\treleased: boolean;\n\t}> = [];\n\n\t/**\n\t * All of the allocated voices for this synth.\n\t */\n\tprivate _voices: Voice[] = [];\n\n\t/**\n\t * The options that are set on the synth.\n\t */\n\tprivate options: VoiceOptions<Voice>;\n\n\t/**\n\t * The polyphony limit.\n\t */\n\tmaxPolyphony: number;\n\n\t/**\n\t * The voice constructor\n\t */\n\tprivate readonly voice: VoiceConstructor<Voice>;\n\n\t/**\n\t * A voice used for holding the get/set values\n\t */\n\tprivate _dummyVoice: Voice;\n\n\t/**\n\t * The GC timeout. Held so that it could be cancelled when the node is disposed.\n\t */\n\tprivate _gcTimeout = -1;\n\n\t/**\n\t * A moving average of the number of active voices\n\t */\n\tprivate _averageActiveVoices = 0;\n\n\t/**\n\t * @param voice The constructor of the voices\n\t * @param options\tThe options object to set the synth voice\n\t */\n\tconstructor(\n\t\tvoice?: VoiceConstructor<Voice>,\n\t\toptions?: PartialVoiceOptions<Voice>\n\t);\n\tconstructor(options?: Partial<PolySynthOptions<Voice>>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tPolySynth.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"voice\", \"options\"]\n\t\t);\n\t\tsuper(options);\n\n\t\t// check against the old API (pre 14.3.0)\n\t\tassert(\n\t\t\t!isNumber(options.voice),\n\t\t\t\"DEPRECATED: The polyphony count is no longer the first argument.\"\n\t\t);\n\n\t\tconst defaults = options.voice.getDefaults();\n\t\tthis.options = Object.assign(\n\t\t\tdefaults,\n\t\t\toptions.options\n\t\t) as VoiceOptions<Voice>;\n\t\tthis.voice = options.voice as unknown as VoiceConstructor<Voice>;\n\t\tthis.maxPolyphony = options.maxPolyphony;\n\n\t\t// create the first voice\n\t\tthis._dummyVoice = this._getNextAvailableVoice() as Voice;\n\t\t// remove it from the voices list\n\t\tconst index = this._voices.indexOf(this._dummyVoice);\n\t\tthis._voices.splice(index, 1);\n\t\t// kick off the GC interval\n\t\tthis._gcTimeout = this.context.setInterval(\n\t\t\tthis._collectGarbage.bind(this),\n\t\t\t1\n\t\t);\n\t}\n\n\tstatic getDefaults(): PolySynthOptions<Synth> {\n\t\treturn Object.assign(Instrument.getDefaults(), {\n\t\t\tmaxPolyphony: 32,\n\t\t\toptions: {},\n\t\t\tvoice: Synth,\n\t\t});\n\t}\n\n\t/**\n\t * The number of active voices.\n\t */\n\tget activeVoices(): number {\n\t\treturn this._activeVoices.length;\n\t}\n\n\t/**\n\t * Invoked when the source is done making sound, so that it can be\n\t * re-added to the pool of available voices\n\t */\n\tprivate _makeVoiceAvailable(voice: Voice): void {\n\t\tthis._availableVoices.push(voice);\n\t\t// remove the midi note from 'active voices'\n\t\tconst activeVoiceIndex = this._activeVoices.findIndex(\n\t\t\t(e) => e.voice === voice\n\t\t);\n\t\tthis._activeVoices.splice(activeVoiceIndex, 1);\n\t}\n\n\t/**\n\t * Get an available voice from the pool of available voices.\n\t * If one is not available and the maxPolyphony limit is reached,\n\t * steal a voice, otherwise return null.\n\t */\n\tprivate _getNextAvailableVoice(): Voice | undefined {\n\t\t// if there are available voices, return the first one\n\t\tif (this._availableVoices.length) {\n\t\t\treturn this._availableVoices.shift();\n\t\t} else if (this._voices.length < this.maxPolyphony) {\n\t\t\t// otherwise if there is still more maxPolyphony, make a new voice\n\t\t\tconst voice = new this.voice(\n\t\t\t\tObject.assign(this.options, {\n\t\t\t\t\tcontext: this.context,\n\t\t\t\t\tonsilence: this._makeVoiceAvailable.bind(this),\n\t\t\t\t})\n\t\t\t);\n\t\t\tassert(\n\t\t\t\tvoice instanceof Monophonic,\n\t\t\t\t\"Voice must extend Monophonic class\"\n\t\t\t);\n\t\t\tvoice.connect(this.output);\n\t\t\tthis._voices.push(voice);\n\t\t\treturn voice;\n\t\t} else {\n\t\t\twarn(\"Max polyphony exceeded. Note dropped.\");\n\t\t}\n\t}\n\n\t/**\n\t * Occasionally check if there are any allocated voices which can be cleaned up.\n\t */\n\tprivate _collectGarbage(): void {\n\t\tthis._averageActiveVoices = Math.max(\n\t\t\tthis._averageActiveVoices * 0.95,\n\t\t\tthis.activeVoices\n\t\t);\n\t\tif (\n\t\t\tthis._availableVoices.length &&\n\t\t\tthis._voices.length > Math.ceil(this._averageActiveVoices + 1)\n\t\t) {\n\t\t\t// take off an available note\n\t\t\tconst firstAvail = this._availableVoices.shift() as Voice;\n\t\t\tconst index = this._voices.indexOf(firstAvail);\n\t\t\tthis._voices.splice(index, 1);\n\t\t\tif (!this.context.isOffline) {\n\t\t\t\tfirstAvail.dispose();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Internal method which triggers the attack\n\t */\n\tprivate _triggerAttack(\n\t\tnotes: Frequency[],\n\t\ttime: Seconds,\n\t\tvelocity?: NormalRange\n\t): void {\n\t\tnotes.forEach((note) => {\n\t\t\tconst midiNote = new MidiClass(this.context, note).toMidi();\n\t\t\tconst voice = this._getNextAvailableVoice();\n\t\t\tif (voice) {\n\t\t\t\tvoice.triggerAttack(note, time, velocity);\n\t\t\t\tthis._activeVoices.push({\n\t\t\t\t\tmidi: midiNote,\n\t\t\t\t\tvoice,\n\t\t\t\t\treleased: false,\n\t\t\t\t});\n\t\t\t\tthis.log(\"triggerAttack\", note, time);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Internal method which triggers the release\n\t */\n\tprivate _triggerRelease(notes: Frequency[], time: Seconds): void {\n\t\tnotes.forEach((note) => {\n\t\t\tconst midiNote = new MidiClass(this.context, note).toMidi();\n\t\t\tconst event = this._activeVoices.find(\n\t\t\t\t({ midi, released }) => midi === midiNote && !released\n\t\t\t);\n\t\t\tif (event) {\n\t\t\t\t// trigger release on that note\n\t\t\t\tevent.voice.triggerRelease(time);\n\t\t\t\t// mark it as released\n\t\t\t\tevent.released = true;\n\t\t\t\tthis.log(\"triggerRelease\", note, time);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Schedule the attack/release events. If the time is in the future, then it should set a timeout\n\t * to wait for just-in-time scheduling\n\t */\n\tprivate _scheduleEvent(\n\t\ttype: \"attack\" | \"release\",\n\t\tnotes: Frequency[],\n\t\ttime: Seconds,\n\t\tvelocity?: NormalRange\n\t): void {\n\t\tassert(!this.disposed, \"Synth was already disposed\");\n\t\t// if the notes are greater than this amount of time in the future, they should be scheduled with setTimeout\n\t\tif (time <= this.now()) {\n\t\t\t// do it immediately\n\t\t\tif (type === \"attack\") {\n\t\t\t\tthis._triggerAttack(notes, time, velocity);\n\t\t\t} else {\n\t\t\t\tthis._triggerRelease(notes, time);\n\t\t\t}\n\t\t} else {\n\t\t\t// schedule it to start in the future\n\t\t\tthis.context.setTimeout(() => {\n\t\t\t\tif (!this.disposed) {\n\t\t\t\t\tthis._scheduleEvent(type, notes, time, velocity);\n\t\t\t\t}\n\t\t\t}, time - this.now());\n\t\t}\n\t}\n\n\t/**\n\t * Trigger the attack portion of the note\n\t * @param  notes The notes to play. Accepts a single Frequency or an array of frequencies.\n\t * @param  time  The start time of the note.\n\t * @param velocity The velocity of the note.\n\t * @example\n\t * const synth = new Tone.PolySynth(Tone.FMSynth).toDestination();\n\t * // trigger a chord immediately with a velocity of 0.2\n\t * synth.triggerAttack([\"Ab3\", \"C4\", \"F5\"], Tone.now(), 0.2);\n\t */\n\ttriggerAttack(\n\t\tnotes: Frequency | Frequency[],\n\t\ttime?: Time,\n\t\tvelocity?: NormalRange\n\t): this {\n\t\tif (!Array.isArray(notes)) {\n\t\t\tnotes = [notes];\n\t\t}\n\t\tconst computedTime = this.toSeconds(time);\n\t\tthis._scheduleEvent(\"attack\", notes, computedTime, velocity);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Trigger the release of the note. Unlike monophonic instruments,\n\t * a note (or array of notes) needs to be passed in as the first argument.\n\t * @param  notes The notes to play. Accepts a single Frequency or an array of frequencies.\n\t * @param  time  When the release will be triggered.\n\t * @example\n\t * const poly = new Tone.PolySynth(Tone.AMSynth).toDestination();\n\t * poly.triggerAttack([\"Ab3\", \"C4\", \"F5\"]);\n\t * // trigger the release of the given notes.\n\t * poly.triggerRelease([\"Ab3\", \"C4\"], \"+1\");\n\t * poly.triggerRelease(\"F5\", \"+3\");\n\t */\n\ttriggerRelease(notes: Frequency | Frequency[], time?: Time): this {\n\t\tif (!Array.isArray(notes)) {\n\t\t\tnotes = [notes];\n\t\t}\n\t\tconst computedTime = this.toSeconds(time);\n\t\tthis._scheduleEvent(\"release\", notes, computedTime);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Trigger the attack and release after the specified duration\n\t * @param  notes The notes to play. Accepts a single  Frequency or an array of frequencies.\n\t * @param  duration the duration of the note\n\t * @param  time  if no time is given, defaults to now\n\t * @param  velocity the velocity of the attack (0-1)\n\t * @example\n\t * const poly = new Tone.PolySynth(Tone.AMSynth).toDestination();\n\t * // can pass in an array of durations as well\n\t * poly.triggerAttackRelease([\"Eb3\", \"G4\", \"Bb4\", \"D5\"], [4, 3, 2, 1]);\n\t */\n\ttriggerAttackRelease(\n\t\tnotes: Frequency | Frequency[],\n\t\tduration: Time | Time[],\n\t\ttime?: Time,\n\t\tvelocity?: NormalRange\n\t): this {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tthis.triggerAttack(notes, computedTime, velocity);\n\t\tif (isArray(duration)) {\n\t\t\tassert(\n\t\t\t\tisArray(notes),\n\t\t\t\t\"If the duration is an array, the notes must also be an array\"\n\t\t\t);\n\t\t\tnotes = notes as Frequency[];\n\t\t\tfor (let i = 0; i < notes.length; i++) {\n\t\t\t\tconst d = duration[Math.min(i, duration.length - 1)];\n\t\t\t\tconst durationSeconds = this.toSeconds(d);\n\t\t\t\tassert(\n\t\t\t\t\tdurationSeconds > 0,\n\t\t\t\t\t\"The duration must be greater than 0\"\n\t\t\t\t);\n\t\t\t\tthis.triggerRelease(notes[i], computedTime + durationSeconds);\n\t\t\t}\n\t\t} else {\n\t\t\tconst durationSeconds = this.toSeconds(duration);\n\t\t\tassert(durationSeconds > 0, \"The duration must be greater than 0\");\n\t\t\tthis.triggerRelease(notes, computedTime + durationSeconds);\n\t\t}\n\t\treturn this;\n\t}\n\n\tsync(): this {\n\t\tif (this._syncState()) {\n\t\t\tthis._syncMethod(\"triggerAttack\", 1);\n\t\t\tthis._syncMethod(\"triggerRelease\", 1);\n\n\t\t\t// make sure that the sound doesn't play after its been stopped\n\t\t\tthis.context.transport.on(\"stop\", this._syncedRelease);\n\t\t\tthis.context.transport.on(\"pause\", this._syncedRelease);\n\t\t\tthis.context.transport.on(\"loopEnd\", this._syncedRelease);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * The release which is scheduled to the timeline.\n\t */\n\tprotected _syncedRelease = (time: number) => this.releaseAll(time);\n\n\t/**\n\t * Set a member/attribute of the voices\n\t * @example\n\t * const poly = new Tone.PolySynth().toDestination();\n\t * // set all of the voices using an options object for the synth type\n\t * poly.set({\n\t * \tenvelope: {\n\t * \t\tattack: 0.25\n\t * \t}\n\t * });\n\t * poly.triggerAttackRelease(\"Bb3\", 0.2);\n\t */\n\tset(options: RecursivePartial<VoiceOptions<Voice>>): this {\n\t\t// remove options which are controlled by the PolySynth\n\t\tconst sanitizedOptions = omitFromObject(options, [\n\t\t\t\"onsilence\",\n\t\t\t\"context\",\n\t\t]);\n\t\t// store all of the options\n\t\tthis.options = deepMerge(this.options, sanitizedOptions);\n\t\tthis._voices.forEach((voice) => voice.set(sanitizedOptions));\n\t\tthis._dummyVoice.set(sanitizedOptions);\n\t\treturn this;\n\t}\n\n\tget(): VoiceOptions<Voice> {\n\t\treturn this._dummyVoice.get();\n\t}\n\n\t/**\n\t * Trigger the release portion of all the currently active voices immediately.\n\t * Useful for silencing the synth.\n\t */\n\treleaseAll(time?: Time): this {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tthis._activeVoices.forEach(({ voice }) => {\n\t\t\tvoice.triggerRelease(computedTime);\n\t\t});\n\t\treturn this;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._dummyVoice.dispose();\n\t\tthis._voices.forEach((v) => v.dispose());\n\t\tthis._activeVoices = [];\n\t\tthis._availableVoices = [];\n\t\tthis.context.clearInterval(this._gcTimeout);\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/instrument/Sampler.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { InstrumentTest } from \"../../test/helper/InstrumentTests.js\";\nimport { atTime, Offline } from \"../../test/helper/Offline.js\";\nimport { ToneAudioBuffer } from \"../core/context/ToneAudioBuffer.js\";\nimport { getContext } from \"../core/Global.js\";\nimport { Sampler } from \"./Sampler.js\";\n\ndescribe(\"Sampler\", () => {\n\tconst A4_buffer = new ToneAudioBuffer();\n\n\tbeforeEach(() => {\n\t\treturn A4_buffer.load(\"./test/audio/sine.wav\");\n\t});\n\n\tBasicTests(Sampler);\n\n\tInstrumentTest(\n\t\tSampler,\n\t\t\"A4\",\n\t\t{\n\t\t\t69: A4_buffer,\n\t\t},\n\t\t1\n\t);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst sampler = new Sampler(\n\t\t\t\t\t{\n\t\t\t\t\t\t69: A4_buffer,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\trelease: 0.4,\n\t\t\t\t\t}\n\t\t\t\t).toDestination();\n\t\t\t\tsampler.triggerAttackRelease(\"C4\", 0.1, 0, 0.2);\n\t\t\t\tsampler.triggerAttackRelease(\"E4\", 0.1, 0.2, 0.4);\n\t\t\t\tsampler.triggerAttackRelease(\"G4\", 0.1, 0.4, 0.6);\n\t\t\t\tsampler.triggerAttackRelease(\"B4\", 0.1, 0.6, 0.8);\n\t\t\t\tsampler.triggerAttackRelease(\"C4\", 0.1, 0.8);\n\t\t\t},\n\t\t\t\"sampler.wav\",\n\t\t\t0.01\n\t\t);\n\t});\n\n\tcontext(\"Constructor\", () => {\n\t\tit(\"can be constructed with an options object\", () => {\n\t\t\tconst sampler = new Sampler(\n\t\t\t\t{\n\t\t\t\t\t69: A4_buffer,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tattack: 0.2,\n\t\t\t\t\trelease: 0.3,\n                    loop: true\n\t\t\t\t}\n\t\t\t);\n\t\t\texpect(sampler.attack).to.equal(0.2);\n\t\t\texpect(sampler.release).to.equal(0.3);\n\t\t\tsampler.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an options object with urls object\", () => {\n\t\t\tconst sampler = new Sampler({\n\t\t\t\tattack: 0.4,\n\t\t\t\trelease: 0.5,\n\t\t\t\turls: {\n\t\t\t\t\t69: A4_buffer,\n\t\t\t\t},\n\t\t\t});\n\t\t\texpect(sampler.attack).to.equal(0.4);\n\t\t\texpect(sampler.release).to.equal(0.5);\n\t\t\tsampler.dispose();\n\t\t});\n\n\t\tit(\"urls can be described as either midi or notes\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sampler = new Sampler({\n\t\t\t\t\tA4: A4_buffer,\n\t\t\t\t}).toDestination();\n\t\t\t\tsampler.triggerAttack(\"A4\");\n\t\t\t});\n\t\t\texpect(buffer.isSilent()).to.be.false;\n\t\t});\n\n\t\tit(\"throws an error if there are no available notes to play\", () => {\n\t\t\texpect(() => {\n\t\t\t\tconst sampler = new Sampler();\n\t\t\t\tsampler.triggerAttack(\"C4\");\n\t\t\t}).throws(Error);\n\t\t});\n\n\t\tit(\"throws an error if the url key is not midi or pitch notation\", () => {\n\t\t\texpect(() => {\n\t\t\t\tconst sampler = new Sampler({\n\t\t\t\t\turls: {\n\t\t\t\t\t\tnote: A4_buffer,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}).throws(Error);\n\t\t});\n\n\t\tit(\"invokes onerror if the \", async () => {\n\t\t\tconst sampler = new Sampler({\n\t\t\t\turls: {\n\t\t\t\t\t40: \"./nosuchfile.wav\",\n\t\t\t\t},\n\t\t\t\tonerror(e) {\n\t\t\t\t\texpect(e).to.be.instanceOf(Error);\n\t\t\t\t\tsampler.dispose();\n\t\t\t\t},\n\t\t\t});\n\t\t\tawait Offline(() => {});\n\t\t});\n\n\t\tit(\"can get and set envelope attributes\", () => {\n\t\t\tconst sampler = new Sampler();\n\t\t\tsampler.attack = 0.1;\n\t\t\tsampler.release = 0.1;\n\t\t\texpect(sampler.attack).to.equal(0.1);\n\t\t\texpect(sampler.release).to.equal(0.1);\n\t\t\tsampler.dispose();\n\t\t});\n\n\t\tit(\"invokes the callback when loaded\", (done) => {\n\t\t\tconst sampler = new Sampler(\n\t\t\t\t{\n\t\t\t\t\tA4: \"./test/audio/sine.wav\",\n\t\t\t\t},\n\t\t\t\t() => {\n\t\t\t\t\texpect(sampler.loaded).to.be.true;\n\t\t\t\t\tdone();\n\t\t\t\t}\n\t\t\t);\n\t\t});\n\n\t\tit(\"can pass in a callback and baseUrl\", (done) => {\n\t\t\tconst sampler = new Sampler(\n\t\t\t\t{\n\t\t\t\t\tA4: A4_buffer,\n\t\t\t\t},\n\t\t\t\t() => {\n\t\t\t\t\texpect(sampler.loaded).to.be.true;\n\t\t\t\t\tdone();\n\t\t\t\t},\n\t\t\t\t\"./baseUrl\"\n\t\t\t);\n\t\t});\n\n\t\tit(\"can dispose while playing sounds\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst sampler = new Sampler(\n\t\t\t\t\t{\n\t\t\t\t\t\tA4: A4_buffer,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\trelease: 0,\n\t\t\t\t\t}\n\t\t\t\t).toDestination();\n\t\t\t\tsampler.triggerAttack(\"A4\", 0);\n\t\t\t\tsampler.triggerRelease(\"A4\", 0.2);\n\t\t\t\tsampler.dispose();\n\t\t\t}, 0.3);\n\t\t});\n\t});\n\n\tcontext(\"Makes sound\", () => {\n\t\tit(\"repitches the note\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sampler = new Sampler({\n\t\t\t\t\tA4: A4_buffer,\n\t\t\t\t}).toDestination();\n\t\t\t\tsampler.triggerAttack(\"G4\");\n\t\t\t});\n\t\t\texpect(buffer.isSilent()).to.be.false;\n\t\t});\n\n\t\tit(\"is silent after the release\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sampler = new Sampler(\n\t\t\t\t\t{\n\t\t\t\t\t\tA4: A4_buffer,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\trelease: 0,\n\t\t\t\t\t}\n\t\t\t\t).toDestination();\n\t\t\t\tsampler.triggerAttack(\"A4\", 0);\n\t\t\t\tsampler.triggerRelease(\"A4\", 0.2);\n\t\t\t}, 0.3);\n\t\t\texpect(buffer.getTimeOfLastSound()).to.be.closeTo(0.2, 0.01);\n\t\t});\n\n\t\tit(\"can triggerRelease after the buffer has already stopped\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sampler = new Sampler(\n\t\t\t\t\t{\n\t\t\t\t\t\tA4: A4_buffer,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\trelease: 0,\n\t\t\t\t\t}\n\t\t\t\t).toDestination();\n\t\t\t\tsampler.triggerAttack(\"A4\", 0);\n\t\t\t\treturn atTime(A4_buffer.duration + 0.01, () => {\n\t\t\t\t\tsampler.triggerRelease(\"A4\");\n\t\t\t\t});\n\t\t\t}, A4_buffer.duration + 0.1);\n\t\t\texpect(buffer.getTimeOfLastSound()).to.be.closeTo(\n\t\t\t\tA4_buffer.duration,\n\t\t\t\t0.01\n\t\t\t);\n\t\t});\n\n\t\tit(\"can release multiple notes\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sampler = new Sampler(\n\t\t\t\t\t{\n\t\t\t\t\t\tA4: A4_buffer,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\trelease: 0,\n\t\t\t\t\t}\n\t\t\t\t).toDestination();\n\t\t\t\tsampler.triggerAttack(\"A4\", 0);\n\t\t\t\tsampler.triggerAttack(\"C4\", 0);\n\t\t\t\tsampler.triggerAttack(\"A4\", 0.1);\n\t\t\t\tsampler.triggerAttack(\"G4\", 0.1);\n\t\t\t\tsampler.releaseAll(0.2);\n\t\t\t}, 0.3);\n\t\t\texpect(buffer.getTimeOfLastSound()).to.be.closeTo(0.2, 0.01);\n\t\t});\n\n\t\tit(\"can trigger the attack and release\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sampler = new Sampler(\n\t\t\t\t\t{\n\t\t\t\t\t\tA4: A4_buffer,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\trelease: 0,\n\t\t\t\t\t}\n\t\t\t\t).toDestination();\n\t\t\t\tsampler.triggerAttackRelease(\"A4\", 0.2, 0.1);\n\t\t\t}, 0.4);\n\t\t\texpect(buffer.getTimeOfFirstSound()).to.be.closeTo(0.1, 0.01);\n\t\t\texpect(buffer.getTimeOfLastSound()).to.be.closeTo(0.3, 0.01);\n\t\t});\n\n\t\tit(\"can trigger polyphonic attack release\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sampler = new Sampler(\n\t\t\t\t\t{\n\t\t\t\t\t\tA4: A4_buffer,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\trelease: 0,\n\t\t\t\t\t}\n\t\t\t\t).toDestination();\n\t\t\t\tsampler.triggerAttackRelease([\"A4\", \"C4\"], [0.2, 0.3], 0.1);\n\t\t\t}, 0.5);\n\t\t\texpect(buffer.getTimeOfFirstSound()).to.be.closeTo(0.1, 0.01);\n\t\t\texpect(buffer.getTimeOfLastSound()).to.be.closeTo(0.4, 0.01);\n\t\t});\n\t});\n\n    context(\"Looping\", () => {\n\n        it(\"can be set to loop\", () => {\n            const sampler = new Sampler();\n            sampler.loop = true;\n            expect(sampler.loop).to.be.true;\n            sampler.dispose();\n        });\n\n        it(\"can set the loop points\", () => {\n            const sampler = new Sampler();\n            sampler.loopStart = 0.2;\n            expect(sampler.loopStart).to.equal(0.2);\n            sampler.loopEnd = 0.7;\n            expect(sampler.loopEnd).to.equal(0.7);\n            sampler.setLoopPoints(0, 0.5);\n            expect(sampler.loopStart).to.equal(0);\n            expect(sampler.loopEnd).to.equal(0.5);\n            sampler.dispose();\n        });\n\n        it(\"loops the audio\", async () => {\n            const buff = await Offline(() => {\n                const sampler = new Sampler({\n                    urls: {\n                        A4: A4_buffer\n                    }\n                });\n                sampler.loop = true;\n                sampler.toDestination();\n                sampler.triggerAttack(\"A4\");\n            }, A4_buffer.duration * 1.5);\n            expect(buff.getRmsAtTime(0)).to.be.above(0);\n            expect(buff.getRmsAtTime(A4_buffer.duration * 0.5)).to.be.above(0);\n            expect(buff.getRmsAtTime(A4_buffer.duration)).to.be.above(0);\n            expect(buff.getRmsAtTime(A4_buffer.duration * 1.2)).to.be.above(0);\n        });\n\n        it(\"setting the loop multiple times has no affect\", async () => {\n            const buff = await Offline(() => {\n                const sampler = new Sampler({\n                    urls: {\n                        A4: A4_buffer\n                    }\n                });\n                sampler.loop = true;\n                sampler.loop = true;\n                sampler.toDestination();\n                sampler.triggerAttack(\"A4\");\n            }, A4_buffer.duration * 1.5);\n            expect(buff.getRmsAtTime(0)).to.be.above(0);\n            expect(buff.getRmsAtTime(A4_buffer.duration * 0.5)).to.be.above(0);\n            expect(buff.getRmsAtTime(A4_buffer.duration)).to.be.above(0);\n            expect(buff.getRmsAtTime(A4_buffer.duration * 1.2)).to.be.above(0);\n        });\n\n        it(\"loops the audio when loop is set after start\", async () => {\n            const buff = await Offline(() => {\n                const sampler = new Sampler({\n                    urls: {\n                        A4: A4_buffer\n                    }\n                });\n                sampler.toDestination();\n                sampler.triggerAttack(\"A4\");\n                sampler.loop = true;\n            }, A4_buffer.duration * 1.5);\n            expect(buff.getRmsAtTime(0)).to.be.above(0);\n            expect(buff.getRmsAtTime(A4_buffer.duration * 0.5)).to.be.above(0);\n            expect(buff.getRmsAtTime(A4_buffer.duration)).to.be.above(0);\n            expect(buff.getRmsAtTime(A4_buffer.duration * 1.2)).to.be.above(0);\n        });\n\n        it(\"starts buffers at loopStart when set to loop\", async () => {\n            const testSample =\n                A4_buffer.toArray(0)[Math.floor(0.1 * getContext().sampleRate)];\n            const buff = await Offline(() => {\n                const sampler = new Sampler({\n                    urls: {\n                        A4: A4_buffer\n                    }\n                });\n                sampler.loopStart = 0.1;\n                sampler.loop = true;\n                sampler.toDestination();\n                sampler.triggerAttack(\"A4\");\n            }, 0.05);\n            expect(buff.toArray()[0][0]).to.equal(testSample);\n        });\n    });\n\n\tcontext(\"add samples\", () => {\n\t\tit(\"can add a note with its midi value\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sampler = new Sampler().toDestination();\n\t\t\t\tsampler.add(69, A4_buffer);\n\t\t\t\tsampler.triggerAttack(\"B4\");\n\t\t\t});\n\t\t\texpect(buffer.isSilent()).to.be.false;\n\t\t});\n\n\t\tit(\"can add a note with its note name\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sampler = new Sampler().toDestination();\n\t\t\t\tsampler.add(\"A4\", A4_buffer);\n\t\t\t\tsampler.triggerAttack(\"G4\");\n\t\t\t});\n\t\t\texpect(buffer.isSilent()).to.be.false;\n\t\t});\n\n\t\tit(\"can pass in a url and invokes the callback\", (done) => {\n\t\t\tconst sampler = new Sampler();\n\t\t\tsampler.add(\"A4\", \"./test/audio/sine.wav\", () => {\n\t\t\t\tdone();\n\t\t\t});\n\t\t});\n\n\t\tit(\"throws an error if added note key is not midi or note name\", () => {\n\t\t\texpect(() => {\n\t\t\t\tconst sampler = new Sampler().toDestination();\n\t\t\t\t// @ts-ignore\n\t\t\t\tsampler.add(\"nope\", A4_buffer);\n\t\t\t}).throws(Error);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/instrument/Sampler.ts",
    "content": "import { ToneAudioBuffer } from \"../core/context/ToneAudioBuffer.js\";\nimport { ToneAudioBuffers } from \"../core/context/ToneAudioBuffers.js\";\nimport { ftomf, intervalToFrequencyRatio } from \"../core/type/Conversions.js\";\nimport { FrequencyClass } from \"../core/type/Frequency.js\";\nimport {\n\tFrequency,\n\tInterval,\n\tMidiNote,\n\tNormalRange,\n\tNote,\n\tTime,\n} from \"../core/type/Units.js\";\nimport { assert, assertRange } from \"../core/util/Debug.js\";\nimport { timeRange } from \"../core/util/Decorator.js\";\nimport { defaultArg, optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { noOp } from \"../core/util/Interface.js\";\nimport { isArray, isNote, isNumber } from \"../core/util/TypeCheck.js\";\nimport { Instrument, InstrumentOptions } from \"../instrument/Instrument.js\";\nimport {\n\tToneBufferSource,\n\tToneBufferSourceCurve,\n} from \"../source/buffer/ToneBufferSource.js\";\n\ninterface SamplesMap {\n\t[note: string]: ToneAudioBuffer | AudioBuffer | string;\n\t[midi: number]: ToneAudioBuffer | AudioBuffer | string;\n}\n\nexport interface SamplerOptions extends InstrumentOptions {\n\tattack: Time;\n\trelease: Time;\n\tonload: () => void;\n\tonerror: (error: Error) => void;\n\tbaseUrl: string;\n\tcurve: ToneBufferSourceCurve;\n\turls: SamplesMap;\n    loop: boolean;\n    loopEnd: number;\n    loopStart: number;\n}\n\n/**\n * Pass in an object which maps the note's pitch or midi value to the url,\n * then you can trigger the attack and release of that note like other instruments.\n * By automatically repitching the samples, it is possible to play pitches which\n * were not explicitly included which can save loading time.\n *\n * For sample or buffer playback where repitching is not necessary,\n * use {@link Player}.\n * @example\n * const sampler = new Tone.Sampler({\n * \turls: {\n * \t\tA1: \"A1.mp3\",\n * \t\tA2: \"A2.mp3\",\n * \t},\n * \tbaseUrl: \"https://tonejs.github.io/audio/casio/\",\n * \tonload: () => {\n * \t\tsampler.triggerAttackRelease([\"C1\", \"E1\", \"G1\", \"B1\"], 0.5);\n * \t}\n * }).toDestination();\n * @category Instrument\n */\nexport class Sampler extends Instrument<SamplerOptions> {\n\treadonly name: string = \"Sampler\";\n\n\t/**\n\t * The stored and loaded buffers\n\t */\n\tprivate _buffers: ToneAudioBuffers;\n\n\t/**\n\t * The object of all currently playing BufferSources\n\t */\n\tprivate _activeSources: Map<MidiNote, ToneBufferSource[]> = new Map();\n\n    /** \n     * The list of all provided midi notes\n     */\n    private _providedMidiNotes: MidiNote[] = [];\n\n    /**\n     * if the buffer should loop once its over\n     */\n\tprivate _loop: boolean;\n\n\t/**\n\t * if 'loop' is true, the loop will start at this position\n\t */\n\tprivate _loopStart: Time;\n\n\t/**\n\t * if 'loop' is true, the loop will end at this position\n\t */\n\tprivate _loopEnd: Time;\n\n\t/**\n\t * The envelope applied to the beginning of the sample.\n\t * @min 0\n\t * @max 1\n\t */\n\t@timeRange(0)\n\tattack: Time;\n\n\t/**\n\t * The envelope applied to the end of the envelope.\n\t * @min 0\n\t * @max 1\n\t */\n\t@timeRange(0)\n\trelease: Time;\n\n\t/**\n\t * The shape of the attack/release curve.\n\t * Either \"linear\" or \"exponential\"\n\t */\n\tcurve: ToneBufferSourceCurve;\n\n\t/**\n\t * @param samples An object of samples mapping either Midi Note Numbers or\n\t * \t\t\tScientific Pitch Notation to the url of that sample.\n\t * @param onload The callback to invoke when all of the samples are loaded.\n\t * @param baseUrl The root URL of all of the samples, which is prepended to all the URLs.\n\t */\n\tconstructor(samples?: SamplesMap, onload?: () => void, baseUrl?: string);\n\t/**\n\t * @param samples An object of samples mapping either Midi Note Numbers or\n\t * \t\t\tScientific Pitch Notation to the url of that sample.\n\t * @param options The remaining options associated with the sampler\n\t */\n\tconstructor(\n\t\tsamples?: SamplesMap,\n\t\toptions?: Partial<Omit<SamplerOptions, \"urls\">>\n\t);\n\tconstructor(options?: Partial<SamplerOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tSampler.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"urls\", \"onload\", \"baseUrl\"],\n\t\t\t\"urls\"\n\t\t);\n\t\tsuper(options);\n\n\t\tconst urlMap = {};\n\t\tObject.keys(options.urls).forEach((note) => {\n\t\t\tconst noteNumber = parseInt(note, 10);\n\t\t\tassert(\n\t\t\t\tisNote(note) || (isNumber(noteNumber) && isFinite(noteNumber)),\n\t\t\t\t`url key is neither a note or midi pitch: ${note}`\n\t\t\t);\n\t\t\tif (isNote(note)) {\n\t\t\t\t// convert the note name to MIDI\n\t\t\t\tconst mid = new FrequencyClass(this.context, note).toMidi();\n\t\t\t\turlMap[mid] = options.urls[note];\n\t\t\t} else if (isNumber(noteNumber) && isFinite(noteNumber)) {\n\t\t\t\t// otherwise if it's numbers assume it's midi\n\t\t\t\turlMap[noteNumber] = options.urls[noteNumber];\n\t\t\t}\n\t\t});\n\n\t\tthis._buffers = new ToneAudioBuffers({\n\t\t\turls: urlMap,\n\t\t\tonload: options.onload,\n\t\t\tbaseUrl: options.baseUrl,\n\t\t\tonerror: options.onerror,\n\t\t});\n\t\tthis.attack = options.attack;\n\t\tthis.release = options.release;\n\t\tthis.curve = options.curve;\n        this._loop = options.loop;\n        this._loopStart = options.loopStart;\n        this._loopEnd = options.loopEnd;\n\n\t\t// invoke the callback if it's already loaded\n\t\tif (this._buffers.loaded) {\n\t\t\t// invoke onload deferred\n\t\t\tPromise.resolve().then(options.onload);\n\t\t}\n\t}\n\n\tstatic getDefaults(): SamplerOptions {\n\t\treturn Object.assign(Instrument.getDefaults(), {\n\t\t\tattack: 0,\n\t\t\tbaseUrl: \"\",\n\t\t\tcurve: \"exponential\" as const,\n\t\t\tonload: noOp,\n\t\t\tonerror: noOp,\n\t\t\trelease: 0.1,\n\t\t\turls: {},\n            loop: false,\n            loopEnd: 0,\n            loopStart: 0,\n\t\t});\n\t}\n\n\t/**\n\t * Returns the difference in steps between the given midi note at the closets sample.\n\t */\n\tprivate _findClosest(midi: MidiNote): Interval {\n\t\t// searches within 8 octaves of the given midi note\n\t\tconst MAX_INTERVAL = 96;\n\t\tlet interval = 0;\n\t\twhile (interval < MAX_INTERVAL) {\n\t\t\t// check above and below\n\t\t\tif (this._buffers.has(midi + interval)) {\n\t\t\t\treturn -interval;\n\t\t\t} else if (this._buffers.has(midi - interval)) {\n\t\t\t\treturn interval;\n\t\t\t}\n\t\t\tinterval++;\n\t\t}\n\t\tthrow new Error(`No available buffers for note: ${midi}`);\n\t}\n\n\t/**\n\t * @param  notes\tThe note to play, or an array of notes.\n\t * @param  time     When to play the note\n\t * @param  velocity The velocity to play the sample back.\n\t */\n\ttriggerAttack(\n\t\tnotes: Frequency | Frequency[],\n\t\ttime?: Time,\n\t\tvelocity: NormalRange = 1\n\t): this {\n\t\tthis.log(\"triggerAttack\", notes, time, velocity);\n\t\tif (!Array.isArray(notes)) {\n\t\t\tnotes = [notes];\n\t\t}\n        const offset = defaultArg(this._loopStart, 0);\n\t\tnotes.forEach((note) => {\n\t\t\tconst midiFloat = ftomf(\n\t\t\t\tnew FrequencyClass(this.context, note).toFrequency()\n\t\t\t);\n\t\t\tconst midi = Math.round(midiFloat) as MidiNote;\n\t\t\tconst remainder = midiFloat - midi;\n\t\t\t// find the closest note pitch\n\t\t\tconst difference = this._findClosest(midi);\n\t\t\tconst closestNote = midi - difference;\n\t\t\tconst buffer = this._buffers.get(closestNote);\n\t\t\tconst playbackRate = intervalToFrequencyRatio(\n\t\t\t\tdifference + remainder\n\t\t\t);\n            const duration = this._loop \n                ? undefined\n                : buffer.duration / playbackRate;\n\t\t\t// play that note\n\t\t\tconst source = new ToneBufferSource({\n\t\t\t\turl: buffer,\n\t\t\t\tcontext: this.context,\n\t\t\t\tcurve: this.curve,\n\t\t\t\tfadeIn: this.attack,\n\t\t\t\tfadeOut: this.release,\n                loop: this._loop,\n                loopStart: this._loopStart,\n                loopEnd: this._loopEnd,\n\t\t\t\tplaybackRate,\n\t\t\t}).connect(this.output);\n\t\t\tsource.start(time, offset, duration, velocity);\n\t\t\t// add it to the active sources\n\t\t\tif (!isArray(this._activeSources.get(midi))) {\n\t\t\t\tthis._activeSources.set(midi, []);\n\t\t\t}\n\t\t\t(this._activeSources.get(midi) as ToneBufferSource[]).push(source);\n\n\t\t\t// remove it when it's done\n\t\t\tsource.onended = () => {\n\t\t\t\tif (this._activeSources && this._activeSources.has(midi)) {\n\t\t\t\t\tconst sources = this._activeSources.get(\n\t\t\t\t\t\tmidi\n\t\t\t\t\t) as ToneBufferSource[];\n\t\t\t\t\tconst index = sources.indexOf(source);\n\t\t\t\t\tif (index !== -1) {\n\t\t\t\t\t\tsources.splice(index, 1);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t});\n\t\treturn this;\n\t}\n\n\t/**\n\t * @param  notes\tThe note to release, or an array of notes.\n\t * @param  time     \tWhen to release the note.\n\t */\n\ttriggerRelease(notes: Frequency | Frequency[], time?: Time): this {\n\t\tthis.log(\"triggerRelease\", notes, time);\n\t\tif (!Array.isArray(notes)) {\n\t\t\tnotes = [notes];\n\t\t}\n\t\tnotes.forEach((note) => {\n\t\t\tconst midi = new FrequencyClass(this.context, note).toMidi();\n\t\t\t// find the note\n\t\t\tif (\n\t\t\t\tthis._activeSources.has(midi) &&\n\t\t\t\t(this._activeSources.get(midi) as ToneBufferSource[]).length\n\t\t\t) {\n\t\t\t\tconst sources = this._activeSources.get(\n\t\t\t\t\tmidi\n\t\t\t\t) as ToneBufferSource[];\n\t\t\t\ttime = this.toSeconds(time);\n\t\t\t\tsources.forEach((source) => {\n\t\t\t\t\tsource.stop(time);\n\t\t\t\t});\n\t\t\t\tthis._activeSources.set(midi, []);\n\t\t\t}\n\t\t});\n\t\treturn this;\n\t}\n\n\t/**\n\t * Release all currently active notes.\n\t * @param  time     \tWhen to release the notes.\n\t */\n\treleaseAll(time?: Time): this {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tthis._activeSources.forEach((sources) => {\n\t\t\twhile (sources.length) {\n\t\t\t\tconst source = sources.shift() as ToneBufferSource;\n\t\t\t\tsource.stop(computedTime);\n\t\t\t}\n\t\t});\n\t\treturn this;\n\t}\n\n\tsync(): this {\n\t\tif (this._syncState()) {\n\t\t\tthis._syncMethod(\"triggerAttack\", 1);\n\t\t\tthis._syncMethod(\"triggerRelease\", 1);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Invoke the attack phase, then after the duration, invoke the release.\n\t * @param  notes\tThe note to play and release, or an array of notes.\n\t * @param  duration The time the note should be held\n\t * @param  time     When to start the attack\n\t * @param  velocity The velocity of the attack\n\t */\n\ttriggerAttackRelease(\n\t\tnotes: Frequency[] | Frequency,\n\t\tduration: Time | Time[],\n\t\ttime?: Time,\n\t\tvelocity: NormalRange = 1\n\t): this {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tthis.triggerAttack(notes, computedTime, velocity);\n\t\tif (isArray(duration)) {\n\t\t\tassert(\n\t\t\t\tisArray(notes),\n\t\t\t\t\"notes must be an array when duration is array\"\n\t\t\t);\n\t\t\t(notes as Frequency[]).forEach((note, index) => {\n\t\t\t\tconst d = duration[Math.min(index, duration.length - 1)];\n\t\t\t\tthis.triggerRelease(note, computedTime + this.toSeconds(d));\n\t\t\t});\n\t\t} else {\n\t\t\tthis.triggerRelease(notes, computedTime + this.toSeconds(duration));\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Add a note to the sampler.\n\t * @param  note      The buffer's pitch.\n\t * @param  url  Either the url of the buffer, or a buffer which will be added with the given name.\n\t * @param  callback  The callback to invoke when the url is loaded.\n\t */\n\tadd(\n\t\tnote: Note | MidiNote,\n\t\turl: string | ToneAudioBuffer | AudioBuffer,\n\t\tcallback?: () => void\n\t): this {\n\t\tassert(\n\t\t\tisNote(note) || isFinite(note),\n\t\t\t`note must be a pitch or midi: ${note}`\n\t\t);\n\t\tif (isNote(note)) {\n\t\t\t// convert the note name to MIDI\n\t\t\tconst mid = new FrequencyClass(this.context, note).toMidi();\n\t\t\tthis._buffers.add(mid, url, callback);\n\t\t} else {\n\t\t\t// otherwise if it's numbers assume it's midi\n\t\t\tthis._buffers.add(note, url, callback);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * If the buffers are loaded or not\n\t */\n\tget loaded(): boolean {\n\t\treturn this._buffers.loaded;\n\t}\n\n    /**\n     * Set the loop start and end. Will only loop if loop is set to true.\n     * @param loopStart The loop start time\n     * @param loopEnd The loop end time\n     * @example\n     * const sampler = new Tone.Sampler({\n     *      urls: {  \n     *           A1: \"https://tonejs.github.io/audio/berklee/guitar_chord4.mp3\",  \n     *      },\n     * }).toDestination();\n     * // loop between the given points\n     * sampler.setLoopPoints(0.2, 0.3);\n     * sampler.loop = true;\n     */\n    setLoopPoints(loopStart: Time, loopEnd: Time): this {\n        this.loopStart = loopStart;\n        this.loopEnd = loopEnd;\n        return this;\n    }\n\n    /**\n     * If loop is true, the loop will start at this position.\n     */\n    get loopStart(): Time {\n        return this._loopStart;\n    }\n    set loopStart(loopStart) {\n        this._loopStart = loopStart;\n        this._providedMidiNotes.forEach((midiNote) => {\n            const buffer = this._buffers.get(midiNote);\n            if (buffer.loaded) {\n                assertRange(this.toSeconds(loopStart), 0, buffer.duration);\n            }\n        });\n        // get the current sources\n        this._activeSources.forEach((sourceList) => {\n            sourceList.forEach((source) => {\n                source.loopStart = loopStart;\n            });\n        });\n    }\n\n    /**\n     * If loop is true, the loop will end at this position.\n     */\n    get loopEnd(): Time {\n        return this._loopEnd;\n    }\n    set loopEnd(loopEnd) {\n        this._loopEnd = loopEnd;\n        this._providedMidiNotes.forEach((midiNote) => {\n            const buffer = this._buffers.get(midiNote);\n            if (buffer.loaded) {\n                assertRange(this.toSeconds(loopEnd), 0, buffer.duration);\n            }\n        });\n        // get the current sources\n        this._activeSources.forEach((sourceList) => {\n            sourceList.forEach((source) => {\n                source.loopEnd = loopEnd;\n            });\n        });\n    }\n\n\n    /**\n     * If the buffers should loop once they are over.\n     * @example\n     * const sampler = new Tone.Sampler({\n     *      urls: {  \n     *           A4: \"https://tonejs.github.io/audio/berklee/femalevoice_aa_A4.mp3\",  \n     *      },\n     * }).toDestination();\n     * sampler.loop = true;\n     */\n    get loop(): boolean {\n        return this._loop;\n    }\n    set loop(loop) {\n        // if no change, do nothing\n        if (this._loop === loop) {\n            return;\n        }\n        this._loop = loop;\n        // set the loop of all of the sources\n        this._activeSources.forEach((sourceList) => {\n            sourceList.forEach((source) => {\n                source.loop = loop;\n            });\n        });\n    }\n    \n\t/**\n\t * Clean up\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._buffers.dispose();\n\t\tthis._activeSources.forEach((sources) => {\n\t\t\tsources.forEach((source) => source.dispose());\n\t\t});\n\t\tthis._activeSources.clear();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/instrument/Synth.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { InstrumentTest } from \"../../test/helper/InstrumentTests.js\";\nimport { MonophonicTest } from \"../../test/helper/MonophonicTests.js\";\nimport { Offline } from \"../../test/helper/Offline.js\";\nimport { Frequency } from \"../core/type/Frequency.js\";\nimport { Synth } from \"./Synth.js\";\n\ndescribe(\"Synth\", () => {\n\tBasicTests(Synth);\n\tInstrumentTest(Synth, \"C4\");\n\tMonophonicTest(Synth, \"C4\");\n\n\tit(\"matches a file basic\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst synth = new Synth().toDestination();\n\t\t\t\tsynth.triggerAttackRelease(\"C4\", 0.1, 0.05);\n\t\t\t},\n\t\t\t\"synth_basic.wav\",\n\t\t\t0.3\n\t\t);\n\t});\n\n\tit(\"matches a file melody\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst synth = new Synth().toDestination();\n\t\t\t\tsynth.triggerAttack(\"C4\", 0);\n\t\t\t\tsynth.triggerAttack(\"E4\", 0.1, 0.5);\n\t\t\t\tsynth.triggerAttackRelease(\"G4\", 0.5, 0.3);\n\t\t\t\tsynth.triggerAttackRelease(\"B4\", 0.5, 0.5, 0.2);\n\t\t\t},\n\t\t\t\"synth_melody.wav\",\n\t\t\t0.3\n\t\t);\n\t});\n\n\tcontext(\"API\", () => {\n\t\tit(\"can get and set oscillator attributes\", () => {\n\t\t\tconst simple = new Synth();\n\t\t\tsimple.oscillator.type = \"triangle\";\n\t\t\texpect(simple.oscillator.type).to.equal(\"triangle\");\n\t\t\tsimple.dispose();\n\t\t});\n\n\t\tit(\"can get and set envelope attributes\", () => {\n\t\t\tconst simple = new Synth();\n\t\t\tsimple.envelope.attack = 0.24;\n\t\t\texpect(simple.envelope.attack).to.equal(0.24);\n\t\t\tsimple.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an options object\", () => {\n\t\t\tconst simple = new Synth({\n\t\t\t\tenvelope: {\n\t\t\t\t\tsustain: 0.3,\n\t\t\t\t},\n\t\t\t\toscillator: {\n\t\t\t\t\ttype: \"sine\",\n\t\t\t\t},\n\t\t\t\tvolume: -5,\n\t\t\t});\n\t\t\texpect(simple.envelope.sustain).to.equal(0.3);\n\t\t\texpect(simple.oscillator.type).to.equal(\"sine\");\n\t\t\texpect(simple.volume.value).to.be.closeTo(-5, 0.1);\n\t\t\tsimple.dispose();\n\t\t});\n\n\t\tit(\"can get/set attributes\", () => {\n\t\t\tconst simple = new Synth();\n\t\t\tsimple.set({\n\t\t\t\tenvelope: {\n\t\t\t\t\tdecay: 0.24,\n\t\t\t\t},\n\t\t\t});\n\t\t\texpect(simple.get().envelope.decay).to.equal(0.24);\n\t\t\tsimple.dispose();\n\t\t});\n\n\t\tit(\"can get does not include omitted oscillator attributes\", () => {\n\t\t\tconst simple = new Synth();\n\t\t\texpect(simple.get().oscillator).to.not.have.key(\"frequency\");\n\t\t\texpect(simple.get().oscillator).to.not.have.key(\"detune\");\n\t\t\texpect(Object.keys(simple.get().oscillator)).to.include(\"type\");\n\t\t\tsimple.dispose();\n\t\t});\n\n\t\tit(\"can be trigged with a Tone.Frequency\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst synth = new Synth().toDestination();\n\t\t\t\tsynth.triggerAttack(Frequency(\"C4\"), 0);\n\t\t\t});\n\t\t\texpect(buffer.isSilent()).to.be.false;\n\t\t});\n\n\t\tit(\"is silent after triggerAttack if sustain is 0\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst synth = new Synth({\n\t\t\t\t\tenvelope: {\n\t\t\t\t\t\tattack: 0.1,\n\t\t\t\t\t\tdecay: 0.1,\n\t\t\t\t\t\tsustain: 0,\n\t\t\t\t\t},\n\t\t\t\t}).toDestination();\n\t\t\t\tsynth.triggerAttack(\"C4\", 0);\n\t\t\t}, 0.5);\n\t\t\texpect(buffer.getTimeOfLastSound()).to.be.closeTo(0.2, 0.01);\n\t\t});\n\t});\n\n\tcontext(\"Transport sync\", () => {\n\t\tit(\"is silent until the transport is started\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst synth = new Synth().sync().toDestination();\n\t\t\t\tsynth.triggerAttackRelease(\"C4\", 0.5);\n\t\t\t\ttransport.start(0.5);\n\t\t\t}, 1);\n\t\t\texpect(buffer.getTimeOfFirstSound()).is.closeTo(0.5, 0.1);\n\t\t});\n\n\t\tit(\"stops when the transport is stopped\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst synth = new Synth({\n\t\t\t\t\tenvelope: {\n\t\t\t\t\t\trelease: 0,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\t\t.sync()\n\t\t\t\t\t.toDestination();\n\t\t\t\tsynth.triggerAttackRelease(\"C4\", 0.5);\n\t\t\t\ttransport.start(0.5).stop(1);\n\t\t\t}, 1.5);\n\t\t\texpect(buffer.getTimeOfLastSound()).is.closeTo(1, 0.1);\n\t\t});\n\n\t\tit(\"goes silent at the loop boundary\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst synth = new Synth({\n\t\t\t\t\tenvelope: {\n\t\t\t\t\t\trelease: 0,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\t\t.sync()\n\t\t\t\t\t.toDestination();\n\t\t\t\tsynth.triggerAttackRelease(\"C4\", 0.8, 0.5);\n\t\t\t\ttransport.loopEnd = 1;\n\t\t\t\ttransport.loop = true;\n\t\t\t\ttransport.start();\n\t\t\t}, 2);\n\t\t\texpect(buffer.getRmsAtTime(0)).to.be.closeTo(0, 0.05);\n\t\t\texpect(buffer.getRmsAtTime(0.6)).to.be.closeTo(0.2, 0.05);\n\t\t\texpect(buffer.getRmsAtTime(1.1)).to.be.closeTo(0, 0.05);\n\t\t\texpect(buffer.getRmsAtTime(1.6)).to.be.closeTo(0.2, 0.05);\n\t\t});\n\n\t\tit(\"can unsync\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst synth = new Synth({\n\t\t\t\t\tenvelope: {\n\t\t\t\t\t\tsustain: 1,\n\t\t\t\t\t\trelease: 0,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\t\t.sync()\n\t\t\t\t\t.toDestination()\n\t\t\t\t\t.unsync();\n\t\t\t\tsynth.triggerAttackRelease(\"C4\", 1, 0.5);\n\t\t\t\ttransport.start().stop(1);\n\t\t\t}, 2);\n\t\t\texpect(buffer.getRmsAtTime(0)).to.be.closeTo(0, 0.05);\n\t\t\texpect(buffer.getRmsAtTime(0.6)).to.be.closeTo(0.6, 0.05);\n\t\t\texpect(buffer.getRmsAtTime(1.4)).to.be.closeTo(0.6, 0.05);\n\t\t\texpect(buffer.getRmsAtTime(1.6)).to.be.closeTo(0, 0.05);\n\t\t});\n\t});\n\n\tcontext(\"Portamento\", () => {\n\t\tit(\"can play notes with a portamento\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst synth = new Synth({\n\t\t\t\t\tportamento: 0.1,\n\t\t\t\t});\n\t\t\t\texpect(synth.portamento).to.equal(0.1);\n\t\t\t\tsynth.frequency.toDestination();\n\t\t\t\tsynth.triggerAttack(440, 0);\n\t\t\t\tsynth.triggerAttack(880, 0.1);\n\t\t\t}, 0.2);\n\t\t\tbuffer.forEach((val, time) => {\n\t\t\t\tif (time < 0.1) {\n\t\t\t\t\texpect(val).to.be.closeTo(440, 1);\n\t\t\t\t} else if (time < 0.2) {\n\t\t\t\t\texpect(val).to.within(440, 880);\n\t\t\t\t} else {\n\t\t\t\t\texpect(val).to.be.closeTo(880, 1);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/instrument/Synth.ts",
    "content": "import { AmplitudeEnvelope } from \"../component/envelope/AmplitudeEnvelope.js\";\nimport { Envelope, EnvelopeOptions } from \"../component/envelope/Envelope.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../core/context/ToneAudioNode.js\";\nimport { NormalRange, Seconds, Time } from \"../core/type/Units.js\";\nimport { omitFromObject, optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport { RecursivePartial } from \"../core/util/Interface.js\";\nimport { Signal } from \"../signal/Signal.js\";\nimport { OmniOscillator } from \"../source/oscillator/OmniOscillator.js\";\nimport {\n\tOmniOscillatorOptions,\n\tOmniOscillatorSynthOptions,\n} from \"../source/oscillator/OscillatorInterface.js\";\nimport { Source } from \"../source/Source.js\";\nimport { Monophonic, MonophonicOptions } from \"./Monophonic.js\";\n\nexport interface SynthOptions extends MonophonicOptions {\n\toscillator: OmniOscillatorSynthOptions;\n\tenvelope: Omit<EnvelopeOptions, keyof ToneAudioNodeOptions>;\n}\n\n/**\n * Synth is composed simply of a {@link OmniOscillator} routed through an {@link AmplitudeEnvelope}.\n * ```\n * +----------------+   +-------------------+\n * | OmniOscillator +>--> AmplitudeEnvelope +>--> Output\n * +----------------+   +-------------------+\n * ```\n * @example\n * const synth = new Tone.Synth().toDestination();\n * synth.triggerAttackRelease(\"C4\", \"8n\");\n * @category Instrument\n */\nexport class Synth<\n\tOptions extends SynthOptions = SynthOptions,\n> extends Monophonic<Options> {\n\treadonly name: string = \"Synth\";\n\n\t/**\n\t * The oscillator.\n\t */\n\treadonly oscillator: OmniOscillator<any>;\n\n\t/**\n\t * The frequency signal\n\t */\n\treadonly frequency: Signal<\"frequency\">;\n\n\t/**\n\t * The detune signal\n\t */\n\treadonly detune: Signal<\"cents\">;\n\n\t/**\n\t * The envelope\n\t */\n\treadonly envelope: AmplitudeEnvelope;\n\n\t/**\n\t * @param options the options available for the synth.\n\t */\n\tconstructor(options?: RecursivePartial<SynthOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Synth.getDefaults(), arguments);\n\t\tsuper(options);\n\n\t\tthis.oscillator = new OmniOscillator(\n\t\t\tObject.assign(\n\t\t\t\t{\n\t\t\t\t\tcontext: this.context,\n\t\t\t\t\tdetune: options.detune,\n\t\t\t\t\tonstop: () => this.onsilence(this),\n\t\t\t\t},\n\t\t\t\toptions.oscillator\n\t\t\t)\n\t\t);\n\n\t\tthis.frequency = this.oscillator.frequency;\n\t\tthis.detune = this.oscillator.detune;\n\n\t\tthis.envelope = new AmplitudeEnvelope(\n\t\t\tObject.assign(\n\t\t\t\t{\n\t\t\t\t\tcontext: this.context,\n\t\t\t\t},\n\t\t\t\toptions.envelope\n\t\t\t)\n\t\t);\n\n\t\t// connect the oscillators to the output\n\t\tthis.oscillator.chain(this.envelope, this.output);\n\t\treadOnly(this, [\"oscillator\", \"frequency\", \"detune\", \"envelope\"]);\n\t}\n\n\tstatic getDefaults(): SynthOptions {\n\t\treturn Object.assign(Monophonic.getDefaults(), {\n\t\t\tenvelope: Object.assign(\n\t\t\t\tomitFromObject(\n\t\t\t\t\tEnvelope.getDefaults(),\n\t\t\t\t\tObject.keys(ToneAudioNode.getDefaults())\n\t\t\t\t),\n\t\t\t\t{\n\t\t\t\t\tattack: 0.005,\n\t\t\t\t\tdecay: 0.1,\n\t\t\t\t\trelease: 1,\n\t\t\t\t\tsustain: 0.3,\n\t\t\t\t}\n\t\t\t),\n\t\t\toscillator: Object.assign(\n\t\t\t\tomitFromObject(OmniOscillator.getDefaults(), [\n\t\t\t\t\t...Object.keys(Source.getDefaults()),\n\t\t\t\t\t\"frequency\",\n\t\t\t\t\t\"detune\",\n\t\t\t\t]),\n\t\t\t\t{\n\t\t\t\t\ttype: \"triangle\",\n\t\t\t\t}\n\t\t\t) as OmniOscillatorOptions,\n\t\t});\n\t}\n\n\t/**\n\t * start the attack portion of the envelope\n\t * @param time the time the attack should start\n\t * @param velocity the velocity of the note (0-1)\n\t */\n\tprotected _triggerEnvelopeAttack(time: Seconds, velocity: number): void {\n\t\t// the envelopes\n\t\tthis.envelope.triggerAttack(time, velocity);\n\t\tthis.oscillator.start(time);\n\t\t// if there is no release portion, stop the oscillator\n\t\tif (this.envelope.sustain === 0) {\n\t\t\tconst computedAttack = this.toSeconds(this.envelope.attack);\n\t\t\tconst computedDecay = this.toSeconds(this.envelope.decay);\n\t\t\tthis.oscillator.stop(time + computedAttack + computedDecay);\n\t\t}\n\t}\n\n\t/**\n\t * start the release portion of the envelope\n\t * @param time the time the release should start\n\t */\n\tprotected _triggerEnvelopeRelease(time: Seconds): void {\n\t\tthis.envelope.triggerRelease(time);\n\t\tthis.oscillator.stop(time + this.toSeconds(this.envelope.release));\n\t}\n\n\tgetLevelAtTime(time: Time): NormalRange {\n\t\ttime = this.toSeconds(time);\n\t\treturn this.envelope.getValueAtTime(time);\n\t}\n\n\t/**\n\t * clean up\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.oscillator.dispose();\n\t\tthis.envelope.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/instrument/index.ts",
    "content": "export * from \"./AMSynth.js\";\nexport * from \"./DuoSynth.js\";\nexport * from \"./FMSynth.js\";\nexport * from \"./MembraneSynth.js\";\nexport * from \"./MetalSynth.js\";\nexport * from \"./MonoSynth.js\";\nexport * from \"./NoiseSynth.js\";\nexport * from \"./PluckSynth.js\";\nexport * from \"./PolySynth.js\";\nexport * from \"./Sampler.js\";\nexport * from \"./Synth.js\";\n"
  },
  {
    "path": "Tone/signal/Abs.test.ts",
    "content": "import { BasicTests } from \"../../test/helper/Basic.js\";\nimport { ConstantOutput } from \"../../test/helper/ConstantOutput.js\";\nimport { Abs } from \"./Abs.js\";\nimport { Signal } from \"./Signal.js\";\n\ndescribe(\"Abs\", () => {\n\tBasicTests(Abs);\n\n\tcontext(\"Absolute Value\", () => {\n\t\tit(\"outputs the same value for positive values\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(0.4);\n\t\t\t\tconst abs = new Abs();\n\t\t\t\tsignal.connect(abs);\n\t\t\t\tabs.toDestination();\n\t\t\t}, 0.4);\n\t\t});\n\n\t\tit(\"outputs 0 when the input is 0\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(0);\n\t\t\t\tconst abs = new Abs();\n\t\t\t\tsignal.connect(abs);\n\t\t\t\tabs.toDestination();\n\t\t\t}, 0);\n\t\t});\n\n\t\tit(\"outputs the absolute value for negative numbers\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(-0.3);\n\t\t\t\tconst abs = new Abs();\n\t\t\t\tsignal.connect(abs);\n\t\t\t\tabs.toDestination();\n\t\t\t}, 0.3);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/signal/Abs.ts",
    "content": "import { ToneAudioNodeOptions } from \"../core/context/ToneAudioNode.js\";\nimport { SignalOperator } from \"./SignalOperator.js\";\nimport { WaveShaper } from \"./WaveShaper.js\";\n\n/**\n * Return the absolute value of an incoming signal.\n *\n * @example\n * return Tone.Offline(() => {\n * \tconst abs = new Tone.Abs().toDestination();\n * \tconst signal = new Tone.Signal(1);\n * \tsignal.rampTo(-1, 0.5);\n * \tsignal.connect(abs);\n * }, 0.5, 1);\n * @category Signal\n */\nexport class Abs extends SignalOperator<ToneAudioNodeOptions> {\n\treadonly name: string = \"Abs\";\n\n\t/**\n\t * The node which converts the audio ranges\n\t */\n\tprivate _abs = new WaveShaper({\n\t\tcontext: this.context,\n\t\tmapping: (val) => {\n\t\t\tif (Math.abs(val) < 0.001) {\n\t\t\t\treturn 0;\n\t\t\t} else {\n\t\t\t\treturn Math.abs(val);\n\t\t\t}\n\t\t},\n\t});\n\n\t/**\n\t * The AudioRange input [-1, 1]\n\t */\n\tinput = this._abs;\n\n\t/**\n\t * The output range [0, 1]\n\t */\n\toutput = this._abs;\n\n\t/**\n\t * clean up\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._abs.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/signal/Add.test.ts",
    "content": "import { BasicTests } from \"../../test/helper/Basic.js\";\nimport { connectFrom, connectTo } from \"../../test/helper/Connect.js\";\nimport { ConstantOutput } from \"../../test/helper/ConstantOutput.js\";\nimport { Add } from \"./Add.js\";\nimport { Signal } from \"./Signal.js\";\n\ndescribe(\"Add\", () => {\n\tBasicTests(Add);\n\n\tcontext(\"Addition\", () => {\n\t\tit(\"handles input and output connections\", () => {\n\t\t\tconst add = new Add();\n\t\t\tconnectFrom().connect(add);\n\t\t\tconnectFrom().connect(add.addend);\n\t\t\tadd.connect(connectTo());\n\t\t\tadd.dispose();\n\t\t});\n\n\t\tit(\"correctly sums a signal and a number\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(0);\n\t\t\t\tconst adder = new Add(3);\n\t\t\t\tsignal.connect(adder);\n\t\t\t\tadder.toDestination();\n\t\t\t}, 3);\n\t\t});\n\n\t\tit(\"can handle negative values\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(10);\n\t\t\t\tconst adder = new Add(-1);\n\t\t\t\tsignal.connect(adder);\n\t\t\t\tadder.toDestination();\n\t\t\t}, 9);\n\t\t});\n\n\t\tit(\"can sum two signals\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst sigA = new Signal(1);\n\t\t\t\tconst sigB = new Signal(4);\n\t\t\t\tconst adder = new Add();\n\t\t\t\tsigA.connect(adder);\n\t\t\t\tsigB.connect(adder.addend);\n\t\t\t\tadder.toDestination();\n\t\t\t}, 5);\n\t\t});\n\n\t\tit(\"can set addend\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(10);\n\t\t\t\tconst adder = new Add(-1);\n\t\t\t\tadder.addend.value = 2;\n\t\t\t\tsignal.connect(adder);\n\t\t\t\tadder.toDestination();\n\t\t\t}, 12);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/signal/Add.ts",
    "content": "import { Gain } from \"../core/context/Gain.js\";\nimport { Param } from \"../core/context/Param.js\";\nimport { connectSeries } from \"../core/context/ToneAudioNode.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { Signal, SignalOptions } from \"./Signal.js\";\n\n/**\n * Add a signal and a number or two signals. When no value is\n * passed into the constructor, Tone.Add will sum input and `addend`\n * If a value is passed into the constructor, the it will be added to the input.\n *\n * @example\n * return Tone.Offline(() => {\n * \tconst add = new Tone.Add(2).toDestination();\n * \tadd.addend.setValueAtTime(1, 0.2);\n * \tconst signal = new Tone.Signal(2);\n * \t// add a signal and a scalar\n * \tsignal.connect(add);\n * \tsignal.setValueAtTime(1, 0.1);\n * }, 0.5, 1);\n * @category Signal\n */\nexport class Add extends Signal {\n\toverride = false;\n\n\treadonly name: string = \"Add\";\n\n\t/**\n\t * the summing node\n\t */\n\tprivate _sum: Gain = new Gain({ context: this.context });\n\treadonly input = this._sum;\n\treadonly output = this._sum;\n\n\t/**\n\t * The value which is added to the input signal\n\t */\n\treadonly addend: Param<\"number\"> = this._param;\n\n\t/**\n\t * @param value If no value is provided, will sum the input and {@link addend}.\n\t */\n\tconstructor(value?: number);\n\tconstructor(options?: Partial<SignalOptions<\"number\">>);\n\tconstructor() {\n\t\tsuper(optionsFromArguments(Add.getDefaults(), arguments, [\"value\"]));\n\n\t\tconnectSeries(this._constantSource, this._sum);\n\t}\n\n\tstatic getDefaults(): SignalOptions<\"number\"> {\n\t\treturn Object.assign(Signal.getDefaults(), {\n\t\t\tvalue: 0,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._sum.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/signal/AudioToGain.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { ConstantOutput } from \"../../test/helper/ConstantOutput.js\";\nimport { Offline } from \"../../test/helper/Offline.js\";\nimport { Oscillator } from \"../source/oscillator/Oscillator.js\";\nimport { AudioToGain } from \"./AudioToGain.js\";\nimport { Signal } from \"./Signal.js\";\nimport { Zero } from \"./Zero.js\";\n\ndescribe(\"AudioToGain\", () => {\n\tBasicTests(AudioToGain);\n\n\tit(\"normalizes an oscillator to 0,1\", async () => {\n\t\tconst buffer = await Offline(() => {\n\t\t\tconst osc = new Oscillator(1000).start();\n\t\t\tconst a2g = new AudioToGain();\n\t\t\tosc.connect(a2g);\n\t\t\ta2g.toDestination();\n\t\t});\n\t\texpect(buffer.min()).to.be.closeTo(0, 0.01);\n\t\texpect(buffer.max()).to.be.closeTo(1, 0.01);\n\t});\n\n\tit(\"outputs 0.5 for an input value of 0\", () => {\n\t\treturn ConstantOutput(() => {\n\t\t\tconst sig = new Zero();\n\t\t\tconst a2g = new AudioToGain();\n\t\t\tsig.connect(a2g);\n\t\t\ta2g.toDestination();\n\t\t}, 0.5);\n\t});\n\n\tit(\"outputs 1 for an input value of 1\", () => {\n\t\treturn ConstantOutput(() => {\n\t\t\tconst sig = new Signal(1);\n\t\t\tconst a2g = new AudioToGain();\n\t\t\tsig.connect(a2g);\n\t\t\ta2g.toDestination();\n\t\t}, 1);\n\t});\n\n\tit(\"outputs 0 for an input value of -1\", () => {\n\t\treturn ConstantOutput(() => {\n\t\t\tconst sig = new Signal(-1);\n\t\t\tconst a2g = new AudioToGain();\n\t\t\tsig.connect(a2g);\n\t\t\ta2g.toDestination();\n\t\t}, 0);\n\t});\n});\n"
  },
  {
    "path": "Tone/signal/AudioToGain.ts",
    "content": "import { ToneAudioNodeOptions } from \"../core/context/ToneAudioNode.js\";\nimport { SignalOperator } from \"./SignalOperator.js\";\nimport { WaveShaper } from \"./WaveShaper.js\";\n\n/**\n * AudioToGain converts an input in AudioRange [-1,1] to NormalRange [0,1].\n * @see {@link GainToAudio}.\n * @category Signal\n */\nexport class AudioToGain extends SignalOperator<ToneAudioNodeOptions> {\n\treadonly name: string = \"AudioToGain\";\n\n\t/**\n\t * The node which converts the audio ranges\n\t */\n\tprivate _norm = new WaveShaper({\n\t\tcontext: this.context,\n\t\tmapping: (x) => (x + 1) / 2,\n\t});\n\n\t/**\n\t * The AudioRange input [-1, 1]\n\t */\n\tinput = this._norm;\n\n\t/**\n\t * The GainRange output [0, 1]\n\t */\n\toutput = this._norm;\n\n\t/**\n\t * clean up\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._norm.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/signal/GainToAudio.test.ts",
    "content": "import { BasicTests } from \"../../test/helper/Basic.js\";\nimport { ConstantOutput } from \"../../test/helper/ConstantOutput.js\";\nimport { GainToAudio } from \"./GainToAudio.js\";\nimport { Signal } from \"./Signal.js\";\nimport { Zero } from \"./Zero.js\";\n\ndescribe(\"GainToAudio\", () => {\n\tBasicTests(GainToAudio);\n\n\tcontext(\"Gain To Audio\", () => {\n\t\tit(\"outputs 0 for an input value of 0.5\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst sig = new Signal(0.5);\n\t\t\t\tconst g2a = new GainToAudio();\n\t\t\t\tsig.connect(g2a);\n\t\t\t\tg2a.toDestination();\n\t\t\t}, 0);\n\t\t});\n\n\t\tit(\"outputs 1 for an input value of 1\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst sig = new Signal(1);\n\t\t\t\tconst g2a = new GainToAudio();\n\t\t\t\tsig.connect(g2a);\n\t\t\t\tg2a.toDestination();\n\t\t\t}, 1);\n\t\t});\n\n\t\tit(\"outputs -1 for an input value of 0\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst sig = new Zero();\n\t\t\t\tconst g2a = new GainToAudio();\n\t\t\t\tsig.connect(g2a);\n\t\t\t\tg2a.toDestination();\n\t\t\t}, -1);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/signal/GainToAudio.ts",
    "content": "import { ToneAudioNodeOptions } from \"../core/context/ToneAudioNode.js\";\nimport { SignalOperator } from \"./SignalOperator.js\";\nimport { WaveShaper } from \"./WaveShaper.js\";\n\n/**\n * GainToAudio converts an input in NormalRange [0,1] to AudioRange [-1,1].\n * @see {@link AudioToGain}.\n * @category Signal\n */\nexport class GainToAudio extends SignalOperator<ToneAudioNodeOptions> {\n\treadonly name: string = \"GainToAudio\";\n\n\t/**\n\t * The node which converts the audio ranges\n\t */\n\tprivate _norm = new WaveShaper({\n\t\tcontext: this.context,\n\t\tmapping: (x) => Math.abs(x) * 2 - 1,\n\t});\n\n\t/**\n\t * The NormalRange input [0, 1]\n\t */\n\tinput = this._norm;\n\n\t/**\n\t * The AudioRange output [-1, 1]\n\t */\n\toutput = this._norm;\n\n\t/**\n\t * clean up\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._norm.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/signal/GreaterThan.test.ts",
    "content": "import { BasicTests } from \"../../test/helper/Basic.js\";\nimport { ConstantOutput } from \"../../test/helper/ConstantOutput.js\";\nimport { GreaterThan } from \"./GreaterThan.js\";\nimport { Signal } from \"./Signal.js\";\n\ndescribe(\"GreaterThan\", () => {\n\tBasicTests(GreaterThan);\n\n\tcontext(\"Comparison\", () => {\n\t\tit(\"outputs 0 when signal is less than value\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(1);\n\t\t\t\tconst gt = new GreaterThan(20);\n\t\t\t\tsignal.connect(gt);\n\t\t\t\tgt.toDestination();\n\t\t\t}, 0);\n\t\t});\n\n\t\tit(\"outputs 0 when signal is equal to the value\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(10);\n\t\t\t\tconst gt = new GreaterThan(10);\n\t\t\t\tsignal.connect(gt);\n\t\t\t\tgt.toDestination();\n\t\t\t}, 0);\n\t\t});\n\n\t\tit(\"outputs 1 value is greater than\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(0.8);\n\t\t\t\tconst gt = new GreaterThan(0.4);\n\t\t\t\tsignal.connect(gt);\n\t\t\t\tgt.toDestination();\n\t\t\t}, 1);\n\t\t});\n\n\t\tit(\"can handle negative values\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(-2);\n\t\t\t\tconst gt = new GreaterThan(-4);\n\t\t\t\tsignal.connect(gt);\n\t\t\t\tgt.toDestination();\n\t\t\t}, 1);\n\t\t});\n\n\t\tit(\"can set a new value\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(2);\n\t\t\t\tconst gt = new GreaterThan(-100);\n\t\t\t\tgt.value = 1;\n\t\t\t\tsignal.connect(gt);\n\t\t\t\tgt.toDestination();\n\t\t\t}, 1);\n\t\t});\n\n\t\tit(\"outputs 0 when first signal is less than second\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst sigA = new Signal(1);\n\t\t\t\tconst sigB = new Signal(4);\n\t\t\t\tconst gt = new GreaterThan();\n\t\t\t\tsigA.connect(gt);\n\t\t\t\tsigB.connect(gt.comparator);\n\t\t\t\tgt.toDestination();\n\t\t\t}, 0);\n\t\t});\n\n\t\tit(\"outputs 1 when first signal is greater than second\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst sigA = new Signal(2.01);\n\t\t\t\tconst sigB = new Signal(2);\n\t\t\t\tconst gt = new GreaterThan();\n\t\t\t\tsigA.connect(gt);\n\t\t\t\tsigB.connect(gt.comparator);\n\t\t\t\tgt.toDestination();\n\t\t\t}, 1);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/signal/GreaterThan.ts",
    "content": "import { Param } from \"../core/context/Param.js\";\nimport { ToneAudioNode } from \"../core/context/ToneAudioNode.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport { GreaterThanZero } from \"./GreaterThanZero.js\";\nimport { Signal, SignalOptions } from \"./Signal.js\";\nimport { Subtract } from \"./Subtract.js\";\n\nexport type GreaterThanOptions = SignalOptions<\"number\">;\n\n/**\n * Output 1 if the signal is greater than the value, otherwise outputs 0.\n * can compare two signals or a signal and a number.\n *\n * @example\n * return Tone.Offline(() => {\n * \tconst gt = new Tone.GreaterThan(2).toDestination();\n * \tconst sig = new Tone.Signal(4).connect(gt);\n * }, 0.1, 1);\n * @category Signal\n */\nexport class GreaterThan extends Signal<\"number\"> {\n\treadonly name: string = \"GreaterThan\";\n\n\treadonly override: boolean = false;\n\n\treadonly input: ToneAudioNode;\n\treadonly output: ToneAudioNode;\n\n\t/**\n\t * compare that amount to zero after subtracting\n\t */\n\tprivate _gtz: GreaterThanZero;\n\n\t/**\n\t * Subtract the value from the input node\n\t */\n\tprivate _subtract: Subtract;\n\n\t/**\n\t * The signal to compare to the incoming signal against.\n\t * @example\n\t * return Tone.Offline(() => {\n\t * \t// change the comparison value\n\t * \tconst gt = new Tone.GreaterThan(1.5).toDestination();\n\t * \tconst signal = new Tone.Signal(1).connect(gt);\n\t * \tgt.comparator.setValueAtTime(0.5, 0.1);\n\t * }, 0.5, 1);\n\t */\n\treadonly comparator: Param<\"number\">;\n\n\t/**\n\t * @param value The value to compare to\n\t */\n\tconstructor(value?: number);\n\tconstructor(options?: Partial<GreaterThanOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tGreaterThan.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"value\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._subtract = this.input = new Subtract({\n\t\t\tcontext: this.context,\n\t\t\tvalue: options.value,\n\t\t});\n\t\tthis._gtz = this.output = new GreaterThanZero({\n\t\t\tcontext: this.context,\n\t\t});\n\n\t\tthis.comparator = this._param = this._subtract.subtrahend;\n\t\treadOnly(this, \"comparator\");\n\n\t\t// connect\n\t\tthis._subtract.connect(this._gtz);\n\t}\n\n\tstatic getDefaults(): GreaterThanOptions {\n\t\treturn Object.assign(Signal.getDefaults(), {\n\t\t\tvalue: 0,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._gtz.dispose();\n\t\tthis._subtract.dispose();\n\t\tthis.comparator.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/signal/GreaterThanZero.test.ts",
    "content": "import { BasicTests } from \"../../test/helper/Basic.js\";\nimport { ConstantOutput } from \"../../test/helper/ConstantOutput.js\";\nimport { GreaterThanZero } from \"./GreaterThanZero.js\";\nimport { Signal } from \"./Signal.js\";\n\ndescribe(\"GreaterThanZero\", () => {\n\tBasicTests(GreaterThanZero);\n\n\tdescribe(\"Comparison\", () => {\n\t\tit(\"Outputs 0 when the value is less than 0\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(-1);\n\t\t\t\tconst gtz = new GreaterThanZero();\n\t\t\t\tsignal.connect(gtz);\n\t\t\t\tgtz.toDestination();\n\t\t\t}, 0);\n\t\t});\n\n\t\tit(\"Outputs 1 when the value is greater than 0\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(1);\n\t\t\t\tconst gtz = new GreaterThanZero();\n\t\t\t\tsignal.connect(gtz);\n\t\t\t\tgtz.toDestination();\n\t\t\t}, 1);\n\t\t});\n\n\t\tit(\"Outputs 0 when the value is equal to 0\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(0);\n\t\t\t\tconst gtz = new GreaterThanZero();\n\t\t\t\tsignal.connect(gtz);\n\t\t\t\tgtz.toDestination();\n\t\t\t}, 0);\n\t\t});\n\n\t\tit(\"Outputs 1 when the value is slightly above 0\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(0.001);\n\t\t\t\tconst gtz = new GreaterThanZero();\n\t\t\t\tsignal.connect(gtz);\n\t\t\t\tgtz.toDestination();\n\t\t\t}, 1);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/signal/GreaterThanZero.ts",
    "content": "import { ToneAudioNode } from \"../core/context/ToneAudioNode.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { Multiply } from \"./Multiply.js\";\nimport { SignalOperator, SignalOperatorOptions } from \"./SignalOperator.js\";\nimport { WaveShaper } from \"./WaveShaper.js\";\n\nexport type GreaterThanZeroOptions = SignalOperatorOptions;\n\n/**\n * GreaterThanZero outputs 1 when the input is strictly greater than zero\n * @example\n * return Tone.Offline(() => {\n * \tconst gt0 = new Tone.GreaterThanZero().toDestination();\n * \tconst sig = new Tone.Signal(0.5).connect(gt0);\n * \tsig.setValueAtTime(-1, 0.05);\n * }, 0.1, 1);\n * @category Signal\n */\nexport class GreaterThanZero extends SignalOperator<GreaterThanZeroOptions> {\n\treadonly name: string = \"GreaterThanZero\";\n\n\t/**\n\t * The waveshaper\n\t */\n\tprivate _thresh: WaveShaper;\n\n\t/**\n\t * Scale the first thresholded signal by a large value.\n\t * this will help with values which are very close to 0\n\t */\n\tprivate _scale: Multiply;\n\n\treadonly output: ToneAudioNode;\n\treadonly input: ToneAudioNode;\n\n\tconstructor(options?: Partial<GreaterThanZeroOptions>);\n\tconstructor() {\n\t\tsuper(optionsFromArguments(GreaterThanZero.getDefaults(), arguments));\n\n\t\tthis._thresh = this.output = new WaveShaper({\n\t\t\tcontext: this.context,\n\t\t\tlength: 127,\n\t\t\tmapping: (val) => {\n\t\t\t\tif (val <= 0) {\n\t\t\t\t\treturn 0;\n\t\t\t\t} else {\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t\tthis._scale = this.input = new Multiply({\n\t\t\tcontext: this.context,\n\t\t\tvalue: 10000,\n\t\t});\n\n\t\t// connections\n\t\tthis._scale.connect(this._thresh);\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._scale.dispose();\n\t\tthis._thresh.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/signal/Multiply.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { connectFrom, connectTo } from \"../../test/helper/Connect.js\";\n// import Test from \"../../test/helper/Test\";\nimport { ConstantOutput } from \"../../test/helper/ConstantOutput.js\";\nimport { Multiply } from \"./Multiply.js\";\n// import Multiply from \"Multiply\";\nimport { Signal } from \"./Signal.js\";\n// import Oscillator from \"../source/Oscillator\";\n\ndescribe(\"Multiply\", () => {\n\tBasicTests(Multiply);\n\n\tdescribe(\"Multiplication\", () => {\n\t\tit(\"handles input and output connections\", () => {\n\t\t\tconst mult = new Multiply();\n\t\t\tconnectFrom().connect(mult, 0);\n\t\t\tconnectFrom().connect(mult.factor);\n\t\t\tmult.connect(connectTo());\n\t\t\tmult.dispose();\n\t\t});\n\n\t\tit(\"correctly multiplies a signal and a scalar\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(2);\n\t\t\t\tconst mult = new Multiply(10);\n\t\t\t\texpect(mult.value).to.equal(10);\n\t\t\t\tsignal.connect(mult);\n\t\t\t\tmult.toDestination();\n\t\t\t}, 20);\n\t\t});\n\n\t\tit(\"can multiply two signals\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst sigA = new Signal(3);\n\t\t\t\tconst sigB = new Signal(5);\n\t\t\t\tconst mult = new Multiply();\n\t\t\t\tsigA.connect(mult);\n\t\t\t\tsigB.connect(mult.factor);\n\t\t\t\tmult.toDestination();\n\t\t\t}, 15);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/signal/Multiply.ts",
    "content": "import { Gain } from \"../core/context/Gain.js\";\nimport { Param } from \"../core/context/Param.js\";\nimport { InputNode, OutputNode } from \"../core/context/ToneAudioNode.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { Signal, SignalOptions } from \"./Signal.js\";\n\n/**\n * Multiply two incoming signals. Or, if a number is given in the constructor,\n * multiplies the incoming signal by that value.\n *\n * @example\n * // multiply two signals\n * const mult = new Tone.Multiply();\n * const sigA = new Tone.Signal(3);\n * const sigB = new Tone.Signal(4);\n * sigA.connect(mult);\n * sigB.connect(mult.factor);\n * // output of mult is 12.\n * @example\n * // multiply a signal and a number\n * const mult = new Tone.Multiply(10);\n * const sig = new Tone.Signal(2).connect(mult);\n * // the output of mult is 20.\n * @category Signal\n */\nexport class Multiply<\n\tTypeName extends \"number\" | \"positive\" = \"number\",\n> extends Signal<TypeName> {\n\treadonly name: string = \"Multiply\";\n\n\t/**\n\t * Indicates if the value should be overridden on connection\n\t */\n\treadonly override = false;\n\n\t/**\n\t * the input gain node\n\t */\n\tprivate _mult: Gain;\n\n\t/**\n\t * The multiplicand input.\n\t */\n\tinput: InputNode;\n\n\t/**\n\t * The product of the input and {@link factor}\n\t */\n\toutput: OutputNode;\n\n\t/**\n\t * The multiplication factor. Can be set directly or a signal can be connected to it.\n\t */\n\tfactor: Param<TypeName>;\n\n\t/**\n\t * @param value Constant value to multiple\n\t */\n\tconstructor(value?: number);\n\tconstructor(options?: Partial<SignalOptions<TypeName>>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tMultiply.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"value\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._mult =\n\t\t\tthis.input =\n\t\t\tthis.output =\n\t\t\t\tnew Gain({\n\t\t\t\t\tcontext: this.context,\n\t\t\t\t\tminValue: options.minValue,\n\t\t\t\t\tmaxValue: options.maxValue,\n\t\t\t\t});\n\n\t\tthis.factor = this._param = this._mult\n\t\t\t.gain as unknown as Param<TypeName>;\n\t\tthis.factor.setValueAtTime(options.value, 0);\n\t}\n\n\tstatic getDefaults(): SignalOptions<any> {\n\t\treturn Object.assign(Signal.getDefaults(), {\n\t\t\tvalue: 0,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._mult.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/signal/Negate.test.ts",
    "content": "import { BasicTests } from \"../../test/helper/Basic.js\";\nimport { ConstantOutput } from \"../../test/helper/ConstantOutput.js\";\nimport { Negate } from \"./Negate.js\";\nimport { Signal } from \"./Signal.js\";\n\ndescribe(\"Negate\", () => {\n\tBasicTests(Negate);\n\n\tcontext(\"Negating\", () => {\n\t\tit(\"negates a positive value\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(1);\n\t\t\t\tconst negate = new Negate();\n\t\t\t\tsignal.connect(negate);\n\t\t\t\tnegate.toDestination();\n\t\t\t}, -1);\n\t\t});\n\n\t\tit(\"makes a negative value positive\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(-10);\n\t\t\t\tconst negate = new Negate();\n\t\t\t\tsignal.connect(negate);\n\t\t\t\tnegate.toDestination();\n\t\t\t}, 10);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/signal/Negate.ts",
    "content": "import { ToneAudioNodeOptions } from \"../core/context/ToneAudioNode.js\";\nimport { Multiply } from \"./Multiply.js\";\nimport { SignalOperator } from \"./SignalOperator.js\";\n\n/**\n * Negate the incoming signal. i.e. an input signal of 10 will output -10\n *\n * @example\n * const neg = new Tone.Negate();\n * const sig = new Tone.Signal(-2).connect(neg);\n * // output of neg is positive 2.\n * @category Signal\n */\nexport class Negate extends SignalOperator<ToneAudioNodeOptions> {\n\treadonly name: string = \"Negate\";\n\n\t/**\n\t * negation is done by multiplying by -1\n\t */\n\tprivate _multiply: Multiply = new Multiply({\n\t\tcontext: this.context,\n\t\tvalue: -1,\n\t});\n\n\t/**\n\t * The input and output are equal to the multiply node\n\t */\n\tinput = this._multiply;\n\toutput = this._multiply;\n\n\t/**\n\t * clean up\n\t * @returns {Negate} this\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._multiply.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/signal/Pow.test.ts",
    "content": "import { BasicTests } from \"../../test/helper/Basic.js\";\nimport { ConstantOutput } from \"../../test/helper/ConstantOutput.js\";\nimport { Pow } from \"./Pow.js\";\nimport { Signal } from \"./Signal.js\";\n\ndescribe(\"Pow\", () => {\n\tBasicTests(Pow);\n\n\tcontext(\"Exponential Scaling\", () => {\n\t\tit(\"can do powers of 2\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(0.3);\n\t\t\t\tconst pow = new Pow(2);\n\t\t\t\tsignal.connect(pow);\n\t\t\t\tpow.toDestination();\n\t\t\t}, 0.09);\n\t\t});\n\n\t\tit(\"can compute negative values and powers less than 1\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(-0.49);\n\t\t\t\tconst pow = new Pow(0.5);\n\t\t\t\tsignal.connect(pow);\n\t\t\t\tpow.toDestination();\n\t\t\t}, 0.7);\n\t\t});\n\n\t\tit(\"can set a new exponent\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(0.5);\n\t\t\t\tconst pow = new Pow(1);\n\t\t\t\tpow.value = 3;\n\t\t\t\tsignal.connect(pow);\n\t\t\t\tpow.toDestination();\n\t\t\t}, 0.125);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/signal/Pow.ts",
    "content": "import { ToneAudioNodeOptions } from \"../core/context/ToneAudioNode.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { SignalOperator } from \"./SignalOperator.js\";\nimport { WaveShaper, WaveShaperMappingFn } from \"./WaveShaper.js\";\n\nexport interface PowOptions extends ToneAudioNodeOptions {\n\tvalue: number;\n}\n\n/**\n * Pow applies an exponent to the incoming signal. The incoming signal must be AudioRange [-1, 1]\n *\n * @example\n * const pow = new Tone.Pow(2);\n * const sig = new Tone.Signal(0.5).connect(pow);\n * // output of pow is 0.25.\n * @category Signal\n */\nexport class Pow extends SignalOperator<PowOptions> {\n\treadonly name: string = \"Pow\";\n\n\tprivate _exponent: number;\n\n\tprivate _exponentScaler: WaveShaper;\n\n\tinput: WaveShaper;\n\n\toutput: WaveShaper;\n\n\t/**\n\t * @param value Constant exponent value to use\n\t */\n\tconstructor(value?: number);\n\tconstructor(options?: Partial<PowOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Pow.getDefaults(), arguments, [\n\t\t\t\"value\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis._exponentScaler =\n\t\t\tthis.input =\n\t\t\tthis.output =\n\t\t\t\tnew WaveShaper({\n\t\t\t\t\tcontext: this.context,\n\t\t\t\t\tmapping: this._expFunc(options.value),\n\t\t\t\t\tlength: 8192,\n\t\t\t\t});\n\n\t\tthis._exponent = options.value;\n\t}\n\n\tstatic getDefaults(): PowOptions {\n\t\treturn Object.assign(SignalOperator.getDefaults(), {\n\t\t\tvalue: 1,\n\t\t});\n\t}\n\n\t/**\n\t * the function which maps the waveshaper\n\t * @param exponent exponent value\n\t */\n\tprivate _expFunc(exponent: number): WaveShaperMappingFn {\n\t\treturn (val: number) => {\n\t\t\treturn Math.pow(Math.abs(val), exponent);\n\t\t};\n\t}\n\n\t/**\n\t * The value of the exponent.\n\t */\n\tget value(): number {\n\t\treturn this._exponent;\n\t}\n\tset value(exponent: number) {\n\t\tthis._exponent = exponent;\n\t\tthis._exponentScaler.setMap(this._expFunc(this._exponent));\n\t}\n\n\t/**\n\t * Clean up.\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._exponentScaler.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/signal/Scale.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { connectFrom, connectTo } from \"../../test/helper/Connect.js\";\nimport { ConstantOutput } from \"../../test/helper/ConstantOutput.js\";\nimport { Scale } from \"./Scale.js\";\nimport { Signal } from \"./Signal.js\";\n\ndescribe(\"Scale\", () => {\n\tBasicTests(Scale);\n\n\tcontext(\"Scaling\", () => {\n\t\tit(\"handles input and output connections\", () => {\n\t\t\tconst scale = new Scale({ min: 0, max: 100 });\n\t\t\tconnectFrom().connect(scale);\n\t\t\tscale.connect(connectTo());\n\t\t\tscale.dispose();\n\t\t});\n\n\t\tit(\"can set the min and max values\", () => {\n\t\t\tconst scale = new Scale({ min: 0, max: 100 });\n\t\t\tscale.min = -0.01;\n\t\t\texpect(scale.min).to.be.closeTo(-0.01, 0.001);\n\t\t\tscale.max = 1000;\n\t\t\texpect(scale.max).to.be.closeTo(1000, 0.001);\n\t\t\tscale.dispose();\n\t\t});\n\n\t\tit(\"scales to the min when the input is 0\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(0);\n\t\t\t\tconst scale = new Scale({ min: -10, max: 8 });\n\t\t\t\tsignal.connect(scale);\n\t\t\t\tscale.toDestination();\n\t\t\t}, -10);\n\t\t});\n\n\t\tit(\"scales to the max when the input is 1\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(1);\n\t\t\t\tconst scale = new Scale(-10, 0);\n\t\t\t\tscale.max = 8;\n\t\t\t\tsignal.connect(scale);\n\t\t\t\tscale.toDestination();\n\t\t\t}, 8);\n\t\t});\n\n\t\tit(\"scales an input of 0.5 to 15 (10, 20)\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(0.5);\n\t\t\t\tconst scale = new Scale({ min: 10, max: 20 });\n\t\t\t\tsignal.connect(scale);\n\t\t\t\tscale.toDestination();\n\t\t\t}, 15);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/signal/Scale.ts",
    "content": "import {\n\tInputNode,\n\tOutputNode,\n\tToneAudioNodeOptions,\n} from \"../core/context/ToneAudioNode.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { Add } from \"./Add.js\";\nimport { Multiply } from \"./Multiply.js\";\nimport { SignalOperator } from \"./SignalOperator.js\";\n\nexport interface ScaleOptions extends ToneAudioNodeOptions {\n\tmin: number;\n\tmax: number;\n}\n\n/**\n * Performs a linear scaling on an input signal.\n * Scales a NormalRange input to between\n * outputMin and outputMax.\n *\n * @example\n * const scale = new Tone.Scale(50, 100);\n * const signal = new Tone.Signal(0.5).connect(scale);\n * // the output of scale equals 75\n * @category Signal\n */\nexport class Scale<\n\tOptions extends ScaleOptions = ScaleOptions,\n> extends SignalOperator<Options> {\n\treadonly name: string = \"Scale\";\n\n\tinput: InputNode;\n\toutput: OutputNode;\n\n\t/**\n\t * Hold the multiple\n\t */\n\tprotected _mult: Multiply;\n\n\t/**\n\t * Hold the adder\n\t */\n\tprotected _add: Add;\n\n\t/**\n\t * Private reference to the min value\n\t */\n\tprivate _min: number;\n\n\t/**\n\t * Private reference to the max value\n\t */\n\tprivate _max: number;\n\n\t/**\n\t * @param min The output value when the input is 0.\n\t * @param max The output value when the input is 1.\n\t */\n\tconstructor(min?: number, max?: number);\n\tconstructor(options?: Partial<ScaleOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Scale.getDefaults(), arguments, [\n\t\t\t\"min\",\n\t\t\t\"max\",\n\t\t]);\n\t\tsuper(options as Options);\n\n\t\tthis._mult = this.input = new Multiply({\n\t\t\tcontext: this.context,\n\t\t\tvalue: options.max - options.min,\n\t\t});\n\n\t\tthis._add = this.output = new Add({\n\t\t\tcontext: this.context,\n\t\t\tvalue: options.min,\n\t\t});\n\n\t\tthis._min = options.min;\n\t\tthis._max = options.max;\n\n\t\tthis.input.connect(this.output);\n\t}\n\n\tstatic getDefaults(): ScaleOptions {\n\t\treturn Object.assign(SignalOperator.getDefaults(), {\n\t\t\tmax: 1,\n\t\t\tmin: 0,\n\t\t});\n\t}\n\n\t/**\n\t * The minimum output value. This number is output when the value input value is 0.\n\t */\n\tget min(): number {\n\t\treturn this._min;\n\t}\n\tset min(min) {\n\t\tthis._min = min;\n\t\tthis._setRange();\n\t}\n\n\t/**\n\t * The maximum output value. This number is output when the value input value is 1.\n\t */\n\tget max(): number {\n\t\treturn this._max;\n\t}\n\tset max(max) {\n\t\tthis._max = max;\n\t\tthis._setRange();\n\t}\n\n\t/**\n\t * set the values\n\t */\n\tprivate _setRange(): void {\n\t\tthis._add.value = this._min;\n\t\tthis._mult.value = this._max - this._min;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._add.dispose();\n\t\tthis._mult.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/signal/ScaleExp.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { ConstantOutput } from \"../../test/helper/ConstantOutput.js\";\nimport { ScaleExp } from \"./ScaleExp.js\";\nimport { Signal } from \"./Signal.js\";\n\ndescribe(\"ScaleExp\", () => {\n\tBasicTests(ScaleExp);\n\n\tcontext(\"Scaling\", () => {\n\t\tit(\"can set the min and max values\", () => {\n\t\t\tconst scale = new ScaleExp(-20, 10, 2);\n\t\t\tscale.min = -0.01;\n\t\t\texpect(scale.min).to.be.closeTo(-0.01, 0.001);\n\t\t\tscale.max = 1000;\n\t\t\texpect(scale.max).to.be.closeTo(1000, 0.001);\n\t\t\tscale.dispose();\n\t\t});\n\n\t\tit(\"can set the exponent value\", () => {\n\t\t\tconst scale = new ScaleExp(0, 100, 2);\n\t\t\texpect(scale.exponent).to.be.closeTo(2, 0.001);\n\t\t\tscale.exponent = 3;\n\t\t\texpect(scale.exponent).to.be.closeTo(3, 0.001);\n\t\t\tscale.dispose();\n\t\t});\n\n\t\tit(\"scales a signal between two values exponentially\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(0.5);\n\t\t\t\tconst scale = new ScaleExp(0, 1, 3);\n\t\t\t\tsignal.connect(scale);\n\t\t\t\tscale.toDestination();\n\t\t\t}, 0.125);\n\t\t});\n\n\t\tit(\"scale a signal between 1 and 3 exponentially\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(0.5);\n\t\t\t\tconst scale = new ScaleExp(1, 3, 2);\n\t\t\t\tsignal.connect(scale);\n\t\t\t\tscale.toDestination();\n\t\t\t}, 1.5);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/signal/ScaleExp.ts",
    "content": "import { Positive } from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { Pow } from \"./Pow.js\";\nimport { Scale, ScaleOptions } from \"./Scale.js\";\n\nexport interface ScaleExpOptions extends ScaleOptions {\n\texponent: Positive;\n}\n\n/**\n * Performs an exponential scaling on an input signal.\n * Scales a NormalRange value [0,1] exponentially\n * to the output range of outputMin to outputMax.\n * @example\n * const scaleExp = new Tone.ScaleExp(0, 100, 2);\n * const signal = new Tone.Signal(0.5).connect(scaleExp);\n * @category Signal\n */\nexport class ScaleExp extends Scale<ScaleExpOptions> {\n\treadonly name: string = \"ScaleExp\";\n\n\t/**\n\t * The exponent scaler\n\t */\n\tprivate _exp: Pow;\n\n\t/**\n\t * @param min The output value when the input is 0.\n\t * @param max The output value when the input is 1.\n\t * @param exponent The exponent which scales the incoming signal.\n\t */\n\tconstructor(min?: number, max?: number, exponent?: number);\n\tconstructor(options?: Partial<ScaleExpOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tScaleExp.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"min\", \"max\", \"exponent\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.input = this._exp = new Pow({\n\t\t\tcontext: this.context,\n\t\t\tvalue: options.exponent,\n\t\t});\n\t\tthis._exp.connect(this._mult);\n\t}\n\n\tstatic getDefaults(): ScaleExpOptions {\n\t\treturn Object.assign(Scale.getDefaults(), {\n\t\t\texponent: 1,\n\t\t});\n\t}\n\n\t/**\n\t * Instead of interpolating linearly between the {@link min} and\n\t * {@link max} values, setting the exponent will interpolate between\n\t * the two values with an exponential curve.\n\t */\n\tget exponent(): Positive {\n\t\treturn this._exp.value;\n\t}\n\tset exponent(exp) {\n\t\tthis._exp.value = exp;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._exp.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/signal/Signal.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { ConstantOutput } from \"../../test/helper/ConstantOutput.js\";\nimport { Offline } from \"../../test/helper/Offline.js\";\nimport { SignalConnectAndDisconnect } from \"../../test/helper/SignalTests.js\";\nimport { Gain } from \"../core/context/Gain.js\";\nimport { connectSignal, disconnectSignal, Signal } from \"./Signal.js\";\n\ndescribe(\"Signal\", () => {\n\tBasicTests(Signal);\n\tSignalConnectAndDisconnect(Signal);\n\n\tcontext(\"Signal Rate Value\", () => {\n\t\tit(\"has 1 input and 1 output\", () => {\n\t\t\tconst signal = new Signal();\n\t\t\texpect(signal.numberOfInputs).to.equal(1);\n\t\t\texpect(signal.numberOfOutputs).to.equal(1);\n\t\t\tsignal.dispose();\n\t\t});\n\n\t\tit(\"can be created with an options object\", () => {\n\t\t\tconst signal = new Signal({\n\t\t\t\tunits: \"positive\",\n\t\t\t\tvalue: 0.2,\n\t\t\t});\n\t\t\texpect(signal.value).to.be.closeTo(0.2, 0.001);\n\t\t\texpect(signal.units).to.equal(\"positive\");\n\t\t\tsignal.dispose();\n\t\t});\n\n\t\tit(\"can start with a value initially\", () => {\n\t\t\tconst signal = new Signal(2);\n\t\t\texpect(signal.value).to.equal(2);\n\t\t\tsignal.dispose();\n\t\t});\n\n\t\tit(\"can set a value\", () => {\n\t\t\tconst signal = new Signal(0);\n\t\t\tsignal.value = 10;\n\t\t\texpect(signal.value).to.equal(10);\n\t\t\tsignal.dispose();\n\t\t});\n\n\t\tit(\"outputs a constant signal\", () => {\n\t\t\treturn ConstantOutput((context) => {\n\t\t\t\tconst sig = new Signal(2.5).toDestination();\n\t\t\t}, 2.5);\n\t\t});\n\n\t\tit(\"takes on another signal's value when connected\", () => {\n\t\t\treturn ConstantOutput((context) => {\n\t\t\t\tconst sigA = new Signal(1).toDestination();\n\t\t\t\tconst sigB = new Signal(3);\n\t\t\t\tsigB.connect(sigA);\n\t\t\t}, 3);\n\t\t});\n\n\t\tit(\"scheduling anything on the connected signal doesn't change the output\", () => {\n\t\t\treturn ConstantOutput((context) => {\n\t\t\t\tconst sigA = new Signal(1).toDestination();\n\t\t\t\tsigA.setValueAtTime(10, 0);\n\t\t\t\tconst sigB = new Signal(3);\n\t\t\t\tsigB.setValueAtTime(4, 0);\n\t\t\t\tsigB.connect(sigA);\n\t\t\t}, 4);\n\t\t});\n\n\t\tit(\"takes the first signals value when many values are chained\", () => {\n\t\t\treturn ConstantOutput((context) => {\n\t\t\t\tconst sigA = new Signal(3).toDestination();\n\t\t\t\tconst sigB = new Signal(1).connect(sigA);\n\t\t\t\tconst sigC = new Signal(2).connect(sigB);\n\t\t\t}, 2);\n\t\t});\n\t});\n\n\tcontext(\"Scheduling\", () => {\n\t\tafterEach((done) => {\n\t\t\tsetTimeout(() => done(), 100);\n\t\t});\n\n\t\tit(\"can be scheduled to set a value in the future\", async () => {\n\t\t\tconst buffer = await Offline((context) => {\n\t\t\t\tconst sig = new Signal(0).toDestination();\n\t\t\t\tsig.setValueAtTime(2, 0.2);\n\t\t\t}, 0.25);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.001);\n\t\t\texpect(buffer.getValueAtTime(0.19)).to.be.closeTo(0, 0.001);\n\t\t\texpect(buffer.getValueAtTime(0.2)).to.be.closeTo(2, 0.001);\n\t\t\texpect(buffer.getValueAtTime(0.24)).to.be.closeTo(2, 0.001);\n\t\t});\n\n\t\tit(\"can linear ramp from the current value to another value in the future\", async () => {\n\t\t\tconst buffer = await Offline((context) => {\n\t\t\t\tconst sig = new Signal(0).toDestination();\n\t\t\t\tsig.setValueAtTime(0, 0);\n\t\t\t\tsig.linearRampToValueAtTime(1, 0.1);\n\t\t\t}, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.001);\n\t\t\texpect(buffer.getValueAtTime(0.05)).to.be.closeTo(0.5, 0.001);\n\t\t\texpect(buffer.getValueAtTime(0.1)).to.be.closeTo(1, 0.001);\n\t\t});\n\n\t\tit(\"can set a ramp point and then ramp from there\", async () => {\n\t\t\tconst buffer = await Offline((context) => {\n\t\t\t\tconst sig = new Signal(0).toDestination();\n\t\t\t\tsig.setRampPoint(0);\n\t\t\t\tsig.linearRampToValueAtTime(1, 1);\n\t\t\t\tsig.setRampPoint(0.5);\n\t\t\t\tsig.linearRampToValueAtTime(0, 1);\n\t\t\t}, 1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.001);\n\t\t\texpect(buffer.getValueAtTime(0.5)).to.be.closeTo(0.5, 0.001);\n\t\t\texpect(buffer.getValueAtTime(1)).to.be.closeTo(0, 0.001);\n\t\t});\n\n\t\tit(\"can schedule multiple automations\", async () => {\n\t\t\tconst buffer = await Offline((context) => {\n\t\t\t\tconst sig = new Signal(0).toDestination();\n\t\t\t\tsig.setValueAtTime(0, 0);\n\t\t\t\tsig.linearRampToValueAtTime(0.5, 0.5);\n\t\t\t\tsig.linearRampToValueAtTime(0, 1);\n\t\t\t}, 1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.001);\n\t\t\texpect(buffer.getValueAtTime(0.25)).to.be.closeTo(0.25, 0.001);\n\t\t\texpect(buffer.getValueAtTime(0.5)).to.be.closeTo(0.5, 0.001);\n\t\t\texpect(buffer.getValueAtTime(0.75)).to.be.closeTo(0.25, 0.001);\n\t\t\texpect(buffer.getValueAtTime(1)).to.be.closeTo(0, 0.001);\n\t\t});\n\n\t\tit(\"can schedule multiple automations from a connected signal\", async () => {\n\t\t\tconst buffer = await Offline((context) => {\n\t\t\t\tconst output = new Signal(1).toDestination();\n\t\t\t\tconst sig = new Signal(0).connect(output);\n\t\t\t\tsig.setValueAtTime(0, 0);\n\t\t\t\tsig.linearRampToValueAtTime(0.5, 0.5);\n\t\t\t\tsig.linearRampToValueAtTime(0, 1);\n\t\t\t}, 1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.001);\n\t\t\texpect(buffer.getValueAtTime(0.25)).to.be.closeTo(0.25, 0.001);\n\t\t\texpect(buffer.getValueAtTime(0.5)).to.be.closeTo(0.5, 0.001);\n\t\t\texpect(buffer.getValueAtTime(0.75)).to.be.closeTo(0.25, 0.001);\n\t\t\texpect(buffer.getValueAtTime(1)).to.be.closeTo(0, 0.001);\n\t\t});\n\n\t\tit(\"can schedule multiple automations from a connected signal through a multiple nodes\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst output = new Signal(0).toDestination();\n\t\t\t\tconst proxy = new Signal(0).connect(output);\n\t\t\t\tconst gain = new Gain(1).connect(proxy);\n\t\t\t\tconst sig = new Signal(0).connect(gain);\n\t\t\t\tsig.setValueAtTime(0, 0);\n\t\t\t\tsig.linearRampToValueAtTime(0.5, 0.5);\n\t\t\t\tsig.linearRampToValueAtTime(0, 1);\n\t\t\t}, 1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.1)).to.be.closeTo(0.1, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.25)).to.be.closeTo(0.25, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.5)).to.be.closeTo(0.5, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.75)).to.be.closeTo(0.25, 0.01);\n\t\t\texpect(buffer.getValueAtTime(1)).to.be.closeTo(0, 0.01);\n\t\t});\n\n\t\tit(\"can cancel an automation\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst sig = new Signal(1).toDestination();\n\t\t\t\tsig.setValueAtTime(4, 0.1);\n\t\t\t\tsig.exponentialRampToValueAtTime(3, 0.2);\n\t\t\t\tsig.cancelScheduledValues(0);\n\t\t\t}, 1);\n\t\t});\n\n\t\tit(\"can cancel and hold a linear automation curve\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sig = new Signal(0).toDestination();\n\t\t\t\tsig.linearRampTo(2, 1);\n\t\t\t\tsig.cancelAndHoldAtTime(0.5);\n\t\t\t}, 1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.25)).to.be.closeTo(0.5, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.5)).to.be.closeTo(1, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.75)).to.be.closeTo(1, 0.1);\n\t\t});\n\n\t\tit(\"can cancel and hold an exponential automation curve\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sig = new Signal(1).toDestination();\n\t\t\t\tsig.exponentialRampTo(2, 1);\n\t\t\t\tsig.cancelAndHoldAtTime(0.5);\n\t\t\t}, 1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(1, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.25)).to.be.closeTo(1.2, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.5)).to.be.closeTo(1.4, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.75)).to.be.closeTo(1.4, 0.1);\n\t\t});\n\n\t\tit(\"can set a linear ramp from the current time\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sig = new Signal(0).toDestination();\n\t\t\t\tsig.linearRampTo(2, 0.3);\n\t\t\t}, 0.5);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\tif (time > 0.3) {\n\t\t\t\t\texpect(sample).to.be.closeTo(2, 0.02);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"can set an linear ramp in the future\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sig = new Signal(1).toDestination();\n\t\t\t\tsig.linearRampTo(50, 0.3, 0.2);\n\t\t\t}, 0.7);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\tif (time >= 0.6) {\n\t\t\t\t\texpect(sample).to.be.closeTo(50, 0.5);\n\t\t\t\t} else if (time < 0.2) {\n\t\t\t\t\texpect(sample).to.closeTo(1, 0.01);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"can set a exponential approach ramp from the current time\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sig = new Signal(0).toDestination();\n\t\t\t\tsig.targetRampTo(1, 0.3);\n\t\t\t}, 0.5);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.below(0.0001);\n\t\t\texpect(buffer.getValueAtTime(0.3)).to.be.closeTo(1, 0.02);\n\t\t});\n\n\t\tit(\"can set an exponential approach ramp in the future\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sig = new Signal(1).toDestination();\n\t\t\t\tsig.targetRampTo(50, 0.3, 0.2);\n\t\t\t}, 0.7);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(1, 0.0001);\n\t\t\texpect(buffer.getValueAtTime(0.2)).to.be.closeTo(1, 0.0001);\n\t\t\texpect(buffer.getValueAtTime(0.6)).to.be.closeTo(50, 0.5);\n\t\t});\n\n\t\tit(\"can set an exponential ramp from the current time\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sig = new Signal(1).toDestination();\n\t\t\t\tsig.exponentialRampTo(50, 0.4);\n\t\t\t}, 0.6);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\tif (time >= 0.4) {\n\t\t\t\t\texpect(sample).to.be.closeTo(50, 0.5);\n\t\t\t\t} else if (time < 0.39) {\n\t\t\t\t\texpect(sample).to.be.lessThan(50);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"can set an exponential ramp in the future\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sig = new Signal(1).toDestination();\n\t\t\t\tsig.exponentialRampTo(50, 0.3, 0.2);\n\t\t\t}, 0.8);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\tif (time >= 0.6) {\n\t\t\t\t\texpect(sample).to.be.closeTo(50, 0.5);\n\t\t\t\t} else if (time < 0.2) {\n\t\t\t\t\texpect(sample).to.equal(1);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"rampTo ramps from the current value\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sig = new Signal(3).toDestination();\n\t\t\t\tsig.rampTo(0.2, 0.1);\n\t\t\t}, 0.4);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\tif (time >= 0.1) {\n\t\t\t\t\texpect(sample).to.be.closeTo(0.2, 0.1);\n\t\t\t\t} else {\n\t\t\t\t\texpect(sample).to.be.greaterThan(0.2);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"rampTo ramps from the current value at a specific time\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sig = new Signal(0).toDestination();\n\t\t\t\tsig.rampTo(2, 0.1, 0.4);\n\t\t\t}, 0.6);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\tif (time < 0.4) {\n\t\t\t\t\texpect(sample).to.be.closeTo(0, 0.1);\n\t\t\t\t} else if (time > 0.5) {\n\t\t\t\t\texpect(sample).to.be.closeTo(2, 0.1);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"can set a value curve\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sig = new Signal(0).toDestination();\n\t\t\t\tsig.setValueCurveAtTime([0, 1, 0.5, 0.2], 0, 1);\n\t\t\t}, 1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.33 / 2)).to.be.closeTo(0.5, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.33)).to.be.closeTo(1, 0.02);\n\t\t\texpect(buffer.getValueAtTime(0.66)).to.be.closeTo(0.5, 0.02);\n\t\t\texpect(buffer.getValueAtTime(0.99)).to.be.closeTo(0.2, 0.02);\n\t\t});\n\n\t\tit(\"can set a value curve in the future\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sig = new Signal(0).toDestination();\n\t\t\t\tsig.setValueCurveAtTime([0, 1, 0.5, 0.2], 0.5, 1);\n\t\t\t}, 1.5);\n\t\t\texpect(buffer.getValueAtTime(0 + 0.5)).to.be.closeTo(0, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.33 / 2 + 0.5)).to.be.closeTo(\n\t\t\t\t0.5,\n\t\t\t\t0.01\n\t\t\t);\n\t\t\texpect(buffer.getValueAtTime(0.33 + 0.5)).to.be.closeTo(1, 0.02);\n\t\t\texpect(buffer.getValueAtTime(0.66 + 0.5)).to.be.closeTo(0.5, 0.02);\n\t\t\texpect(buffer.getValueAtTime(0.99 + 0.5)).to.be.closeTo(0.2, 0.02);\n\t\t});\n\n\t\tit(\"can set an exponential approach\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sig = new Signal(0).toDestination();\n\t\t\t\tsig.exponentialApproachValueAtTime(2, 0.1, 0.5);\n\t\t\t}, 1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.1)).to.be.closeTo(0, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.4)).to.be.closeTo(1.9, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.6)).to.be.closeTo(2, 0.01);\n\t\t});\n\n\t\tit(\"can set a target at time\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst sig = new Signal(0).toDestination();\n\t\t\t\tsig.setTargetAtTime(2, 0.1, 0.1);\n\t\t\t}, 1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.6)).to.be.closeTo(2, 0.1);\n\t\t});\n\t});\n\n\tcontext(\"Units\", () => {\n\t\tit(\"can be created with specific units\", () => {\n\t\t\tconst signal = new Signal(0, \"bpm\");\n\t\t\texpect(signal.units).to.equal(\"bpm\");\n\t\t\tsignal.dispose();\n\t\t});\n\n\t\tit(\"can evaluate the given units\", () => {\n\t\t\tconst signal = new Signal(2, \"time\");\n\t\t\tsignal.value = 0.5;\n\t\t\texpect(signal.value).to.be.closeTo(0.5, 0.001);\n\t\t\tsignal.dispose();\n\t\t});\n\n\t\tit(\"converts the given units when passed in the constructor\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal({\n\t\t\t\t\tunits: \"decibels\",\n\t\t\t\t\tvalue: -10,\n\t\t\t\t}).toDestination();\n\t\t\t}, 0.315);\n\t\t});\n\n\t\tit(\"can be set to not convert the given units in constructor\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal({\n\t\t\t\t\tconvert: false,\n\t\t\t\t\tunits: \"decibels\",\n\t\t\t\t\tvalue: -10,\n\t\t\t\t}).toDestination();\n\t\t\t}, -10);\n\t\t});\n\n\t\tit(\"can be set to not convert the given units in member\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal({\n\t\t\t\t\tunits: \"decibels\",\n\t\t\t\t}).toDestination();\n\t\t\t\tsignal.convert = false;\n\t\t\t\tsignal.value = -10;\n\t\t\t}, -10);\n\t\t});\n\n\t\tit(\"converts Frequency units\", () => {\n\t\t\tconst signal = new Signal(\"50hz\", \"frequency\");\n\t\t\texpect(signal.value).to.be.closeTo(50, 0.01);\n\t\t\tsignal.dispose();\n\t\t});\n\n\t\tit(\"converts Time units\", () => {\n\t\t\tconst signal = new Signal(\"4n\", \"time\");\n\t\t\texpect(signal.value).to.be.closeTo(0.5, 0.01);\n\t\t\tsignal.dispose();\n\t\t});\n\n\t\tit(\"converts NormalRange units\", () => {\n\t\t\texpect(() => {\n\t\t\t\tnew Signal(2, \"normalRange\");\n\t\t\t}).to.throw(RangeError);\n\t\t\tconst signal = new Signal(1, \"normalRange\");\n\t\t\texpect(signal.value).to.be.closeTo(1, 0.01);\n\t\t\texpect(signal.minValue).to.be.equal(0);\n\t\t\texpect(signal.maxValue).to.be.equal(1);\n\t\t\tsignal.dispose();\n\t\t});\n\n\t\tit(\"converts AudioRange units\", () => {\n\t\t\texpect(() => {\n\t\t\t\tnew Signal(-2, \"audioRange\");\n\t\t\t}).to.throw(RangeError);\n\t\t\tconst signal = new Signal(-1, \"audioRange\");\n\t\t\texpect(signal.value).to.be.closeTo(-1, 0.01);\n\t\t\texpect(signal.minValue).to.be.equal(-1);\n\t\t\texpect(signal.maxValue).to.be.equal(1);\n\t\t\tsignal.dispose();\n\t\t});\n\n\t\tit(\"converts Positive units\", () => {\n\t\t\texpect(() => {\n\t\t\t\tnew Signal(-2, \"positive\");\n\t\t\t}).to.throw(RangeError);\n\t\t\tconst signal = new Signal(100, \"positive\");\n\t\t\texpect(signal.value).to.be.closeTo(100, 0.01);\n\t\t\texpect(signal.minValue).to.be.equal(0);\n\t\t\tsignal.dispose();\n\t\t});\n\t});\n\n\tcontext(\"Transport Syncing\", () => {\n\t\tit(\"maintains its original value after being synced to the transport\", () => {\n\t\t\treturn ConstantOutput(({ transport }) => {\n\t\t\t\tconst sig = new Signal(3).toDestination();\n\t\t\t\ttransport.syncSignal(sig);\n\t\t\t}, 3);\n\t\t});\n\n\t\tit(\"keeps the ratio when the bpm changes\", () => {\n\t\t\treturn ConstantOutput(({ transport }) => {\n\t\t\t\ttransport.bpm.value = 120;\n\t\t\t\tconst sig = new Signal(5).toDestination();\n\t\t\t\ttransport.syncSignal(sig);\n\t\t\t\ttransport.bpm.value = 240;\n\t\t\t}, 10);\n\t\t});\n\n\t\tit(\"keeps the ratio of a time signal when the bpm changes\", () => {\n\t\t\treturn ConstantOutput(({ transport }) => {\n\t\t\t\ttransport.bpm.value = 120;\n\t\t\t\tconst sig = new Signal(\"4n\", \"time\").toDestination();\n\t\t\t\ttransport.syncSignal(sig);\n\t\t\t\ttransport.bpm.value = 240;\n\t\t\t}, 0.25);\n\t\t});\n\n\t\tit(\"outputs 0 when the signal is 0\", () => {\n\t\t\treturn ConstantOutput(({ transport }) => {\n\t\t\t\ttransport.bpm.value = 120;\n\t\t\t\tconst sig = new Signal(0).toDestination();\n\t\t\t\ttransport.syncSignal(sig);\n\t\t\t\ttransport.bpm.value = 240;\n\t\t\t}, 0);\n\t\t});\n\n\t\tit(\"can ramp along with the bpm\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\ttransport.bpm.value = 120;\n\t\t\t\tconst sig = new Signal(2).toDestination();\n\t\t\t\ttransport.syncSignal(sig);\n\t\t\t\ttransport.bpm.rampTo(240, 0.5);\n\t\t\t});\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\tif (time >= 0.5) {\n\t\t\t\t\texpect(sample).to.be.closeTo(4, 0.04);\n\t\t\t\t} else if (time < 0.4) {\n\t\t\t\t\texpect(sample).to.be.within(1.95, 3);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"returns to the original value when unsynced\", () => {\n\t\t\treturn ConstantOutput(({ transport }) => {\n\t\t\t\ttransport.bpm.value = 120;\n\t\t\t\tconst sig = new Signal(5).toDestination();\n\t\t\t\ttransport.syncSignal(sig);\n\t\t\t\ttransport.bpm.value = 240;\n\t\t\t\ttransport.unsyncSignal(sig);\n\t\t\t}, 5);\n\t\t});\n\t});\n\n\tcontext(\"connectSignal/disconnectSignal\", () => {\n\t\tit(\"can connect a Signal to an AudioNode\", () => {\n\t\t\treturn ConstantOutput((context) => {\n\t\t\t\tconst sig = new Signal({\n\t\t\t\t\tvalue: 3,\n\t\t\t\t\tcontext,\n\t\t\t\t});\n\t\t\t\tconst gain = new Gain({\n\t\t\t\t\tgain: 0.5,\n\t\t\t\t\tcontext,\n\t\t\t\t}).toDestination();\n\t\t\t\tconnectSignal(sig, gain);\n\t\t\t}, 1.5);\n\t\t});\n\n\t\tit(\"can connect a Signal to a Param\", () => {\n\t\t\treturn ConstantOutput((context) => {\n\t\t\t\tconst sig = new Signal({\n\t\t\t\t\tvalue: 3,\n\t\t\t\t\tcontext,\n\t\t\t\t});\n\t\t\t\tconst scalar = new Signal({\n\t\t\t\t\tvalue: 2,\n\t\t\t\t\tcontext,\n\t\t\t\t});\n\t\t\t\tconst gain = new Gain({\n\t\t\t\t\tgain: 0.5,\n\t\t\t\t\tcontext,\n\t\t\t\t}).toDestination();\n\t\t\t\tconnectSignal(sig, gain);\n\t\t\t\tconnectSignal(scalar, gain.gain);\n\t\t\t\t// gain of 0.5 is overridden\n\t\t\t\texpect(gain.gain.value).to.equal(0);\n\t\t\t}, 6);\n\t\t});\n\n\t\tit(\"can connect a Signal to a Signal\", () => {\n\t\t\treturn ConstantOutput((context) => {\n\t\t\t\tconst sig = new Signal({\n\t\t\t\t\tvalue: 3,\n\t\t\t\t\tcontext,\n\t\t\t\t});\n\t\t\t\tconst output = new Signal({\n\t\t\t\t\tvalue: 0.5,\n\t\t\t\t\tcontext,\n\t\t\t\t}).toDestination();\n\n\t\t\t\tconnectSignal(sig, output);\n\t\t\t\texpect(output.overridden).to.be.true;\n\t\t\t}, 3);\n\t\t});\n\n\t\tit(\"can disconnect a Signal from an AudioNode\", () => {\n\t\t\treturn ConstantOutput((context) => {\n\t\t\t\tconst sig = new Signal({\n\t\t\t\t\tvalue: 3,\n\t\t\t\t\tcontext,\n\t\t\t\t});\n\t\t\t\tconst gain = new Gain({\n\t\t\t\t\tgain: 0.5,\n\t\t\t\t\tcontext,\n\t\t\t\t}).toDestination();\n\t\t\t\tconnectSignal(sig, gain);\n\t\t\t\tdisconnectSignal(sig, gain);\n\t\t\t}, 0);\n\t\t});\n\n\t\tit(\"can disconnect a Signal from a Param\", () => {\n\t\t\treturn ConstantOutput((context) => {\n\t\t\t\tconst sig = new Signal({\n\t\t\t\t\tvalue: 3,\n\t\t\t\t\tcontext,\n\t\t\t\t});\n\t\t\t\tconst scalar = new Signal({\n\t\t\t\t\tvalue: 2,\n\t\t\t\t\tcontext,\n\t\t\t\t});\n\t\t\t\tconst gain = new Gain({\n\t\t\t\t\tgain: 0.5,\n\t\t\t\t\tcontext,\n\t\t\t\t}).toDestination();\n\t\t\t\tconnectSignal(sig, gain);\n\t\t\t\tconnectSignal(scalar, gain.gain);\n\t\t\t\t// gain of 0.5 is overridden\n\t\t\t\texpect(gain.gain.value).to.equal(0);\n\n\t\t\t\tdisconnectSignal(scalar, gain.gain);\n\t\t\t\t// the original value is restored\n\t\t\t\texpect(gain.gain.value).to.equal(0.5);\n\t\t\t}, 1.5);\n\t\t});\n\n\t\tit(\"can disconnect a Signal from a Signal\", () => {\n\t\t\treturn ConstantOutput((context) => {\n\t\t\t\tconst sig = new Signal({\n\t\t\t\t\tvalue: 3,\n\t\t\t\t\tcontext,\n\t\t\t\t});\n\t\t\t\tconst output = new Signal({\n\t\t\t\t\tvalue: 2,\n\t\t\t\t\tcontext,\n\t\t\t\t}).toDestination();\n\n\t\t\t\tconnectSignal(sig, output);\n\t\t\t\texpect(output.overridden).to.be.true;\n\t\t\t\texpect(output.value).to.equal(0);\n\n\t\t\t\tdisconnectSignal(sig, output);\n\t\t\t\texpect(output.value).to.equal(2);\n\t\t\t\texpect(output.overridden).to.be.false;\n\t\t\t}, 2);\n\t\t});\n\n\t\tit(\"can disconnect from all the connected nodes\", async () => {\n\t\t\tawait ConstantOutput(async (context) => {\n\t\t\t\t// initially destination is 2\n\t\t\t\tconst output0 = new Signal(1).toDestination();\n\t\t\t\tconst output1 = new Signal(1).toDestination();\n\n\t\t\t\t// both should now equal 0\n\t\t\t\tconst sig = new Signal(0).connect(output0).connect(output1);\n\n\t\t\t\t// disconnect from both\n\t\t\t\tsig.disconnect();\n\t\t\t}, 2);\n\t\t});\n\n\t\tit(\"can disconnect from a specific node\", async () => {\n\t\t\tawait ConstantOutput(() => {\n\t\t\t\t// initially destination is 3\n\t\t\t\tconst output0 = new Signal(1).toDestination();\n\t\t\t\tconst output1 = new Signal(2).toDestination();\n\n\t\t\t\tconst sig = new Signal(3);\n\t\t\t\tsig.connect(output0);\n\t\t\t\tsig.connect(output1);\n\n\t\t\t\t// output0 goes back to 1 after disconnecting\n\t\t\t\tsig.disconnect(output0);\n\t\t\t}, 4); // 1 + 3\n\t\t});\n\n\t\tit(\"disconnects every input when no input is passed in\", async () => {\n\t\t\tawait ConstantOutput(() => {\n\t\t\t\t// initially destination is 1\n\t\t\t\tconst output = new Signal(1).toDestination();\n\n\t\t\t\t// overwrites it with 0\n\t\t\t\tconst sig = new Signal(0).connect(output, 0);\n\n\t\t\t\t// disconnects the signal and goes back to 1\n\t\t\t\tsig.disconnect(output);\n\t\t\t}, 1);\n\t\t});\n\n\t\tit(\"disconnects every output when no output is passed in\", async () => {\n\t\t\tawait ConstantOutput(() => {\n\t\t\t\t// initially destination is 1\n\t\t\t\tconst output = new Signal(1).toDestination();\n\n\t\t\t\t// overwrites it with 0\n\t\t\t\tconst sig = new Signal(0).connect(output, undefined, 0);\n\n\t\t\t\t// disconnects the signal and goes back to 1\n\t\t\t\tsig.disconnect(output);\n\t\t\t}, 1);\n\t\t});\n\n\t\tit(\"disconnects everything if no destination is passed in\", () => {\n\t\t\treturn ConstantOutput((context) => {\n\t\t\t\tconst sig = new Signal({\n\t\t\t\t\tvalue: 3,\n\t\t\t\t\tcontext,\n\t\t\t\t});\n\t\t\t\tconst output = new Signal({\n\t\t\t\t\tvalue: 2,\n\t\t\t\t\tcontext,\n\t\t\t\t}).toDestination();\n\n\t\t\t\t// overridden with value of 3\n\t\t\t\tconnectSignal(sig, output);\n\t\t\t\texpect(output.overridden).to.be.true;\n\n\t\t\t\t// disconnect goes back to 2\n\t\t\t\tsig.disconnect();\n\t\t\t\texpect(output.overridden).to.be.false;\n\t\t\t}, 2);\n\t\t});\n\n\t\tit(\"can connect multiple times with no affect\", () => {\n\t\t\treturn ConstantOutput((context) => {\n\t\t\t\tconst sig = new Signal({\n\t\t\t\t\tvalue: 3,\n\t\t\t\t\tcontext,\n\t\t\t\t});\n\t\t\t\tconst output = new Signal({\n\t\t\t\t\tvalue: 2,\n\t\t\t\t\tcontext,\n\t\t\t\t}).toDestination();\n\n\t\t\t\tconnectSignal(sig, output);\n\t\t\t\texpect(output.overridden).to.be.true;\n\n\t\t\t\t// no affect when called again\n\t\t\t\tconnectSignal(sig, output);\n\t\t\t}, 3);\n\t\t});\n\n\t\tit(\"disconnecting multiple times throws an error\", () => {\n\t\t\treturn ConstantOutput((context) => {\n\t\t\t\tconst sig = new Signal({\n\t\t\t\t\tvalue: 3,\n\t\t\t\t\tcontext,\n\t\t\t\t});\n\t\t\t\tconst output = new Signal({\n\t\t\t\t\tvalue: 2,\n\t\t\t\t\tcontext,\n\t\t\t\t}).toDestination();\n\n\t\t\t\tconnectSignal(sig, output);\n\n\t\t\t\tdisconnectSignal(sig, output);\n\t\t\t\texpect(() => disconnectSignal(sig, output)).to.throw(Error);\n\t\t\t}, 2);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/signal/Signal.ts",
    "content": "import { AbstractParam } from \"../core/context/AbstractParam.js\";\nimport { Param } from \"../core/context/Param.js\";\nimport {\n\tdisconnect,\n\tInputNode,\n\tOutputNode,\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../core/context/ToneAudioNode.js\";\nimport { connect } from \"../core/context/ToneAudioNode.js\";\nimport { Time, UnitMap, UnitName } from \"../core/type/Units.js\";\nimport { isAudioParam } from \"../core/util/AdvancedTypeCheck.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { isUndef } from \"../core/util/TypeCheck.js\";\nimport { ToneConstantSource } from \"./ToneConstantSource.js\";\n\nexport interface SignalOptions<TypeName extends UnitName>\n\textends ToneAudioNodeOptions {\n\tvalue: UnitMap[TypeName];\n\tunits: TypeName;\n\tconvert: boolean;\n\tminValue?: number;\n\tmaxValue?: number;\n}\n\n/**\n * A signal is an audio-rate value. Tone.Signal is a core component of the library.\n * Unlike a number, Signals can be scheduled with sample-level accuracy. Tone.Signal\n * has all of the methods available to native Web Audio\n * [AudioParam](http://webaudio.github.io/web-audio-api/#the-audioparam-interface)\n * as well as additional conveniences. Read more about working with signals\n * [here](https://github.com/Tonejs/Tone.js/wiki/Signals).\n *\n * @example\n * const osc = new Tone.Oscillator().toDestination().start();\n * // a schedulable signal which can be connected to control an AudioParam or another Signal\n * const signal = new Tone.Signal({\n * \tvalue: \"C4\",\n * \tunits: \"frequency\"\n * }).connect(osc.frequency);\n * // the scheduled ramp controls the connected signal\n * signal.rampTo(\"C2\", 4, \"+0.5\");\n * @category Signal\n */\nexport class Signal<TypeName extends UnitName = \"number\">\n\textends ToneAudioNode<SignalOptions<any>>\n\timplements AbstractParam<TypeName>\n{\n\treadonly name: string = \"Signal\";\n\n\t/**\n\t * Indicates if the value should be overridden on connection.\n\t */\n\treadonly override: boolean = true;\n\n\t/**\n\t * The constant source node which generates the signal\n\t */\n\tprotected _constantSource: ToneConstantSource<TypeName>;\n\treadonly output: OutputNode;\n\tprotected _param: Param<TypeName>;\n\treadonly input: InputNode;\n\n\t/**\n\t * @param value Initial value of the signal\n\t * @param units The unit name, e.g. \"frequency\"\n\t */\n\tconstructor(value?: UnitMap[TypeName], units?: TypeName);\n\tconstructor(options?: Partial<SignalOptions<TypeName>>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Signal.getDefaults(), arguments, [\n\t\t\t\"value\",\n\t\t\t\"units\",\n\t\t]) as SignalOptions<TypeName>;\n\t\tsuper(options);\n\n\t\tthis.output = this._constantSource = new ToneConstantSource({\n\t\t\tcontext: this.context,\n\t\t\tconvert: options.convert,\n\t\t\toffset: options.value,\n\t\t\tunits: options.units,\n\t\t\tminValue: options.minValue,\n\t\t\tmaxValue: options.maxValue,\n\t\t});\n\t\tthis._constantSource.start(0);\n\t\tthis.input = this._param = this._constantSource.offset;\n\t}\n\t/** @inheritdoc */\n\tstatic getDefaults(): SignalOptions<any> {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tconvert: true,\n\t\t\tunits: \"number\" as UnitName,\n\t\t\tvalue: 0,\n\t\t});\n\t}\n\t/** @inheritdoc */\n\tconnect(destination: InputNode, outputNum = 0, inputNum = 0): this {\n\t\t// start it only when connected to something\n\t\tconnectSignal(this, destination, outputNum, inputNum);\n\t\treturn this;\n\t}\n\t/** @inheritdoc */\n\tdisconnect(\n\t\tdestination?: InputNode,\n\t\toutputNum?: number,\n\t\tinputNum?: number\n\t): this {\n\t\t// disconnect the signal\n\t\tdisconnectSignal(this, destination, outputNum, inputNum);\n\t\treturn this;\n\t}\n\t/** @inheritdoc */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._param.dispose();\n\t\tthis._constantSource.dispose();\n\t\treturn this;\n\t}\n\n\t//-------------------------------------\n\t// ABSTRACT PARAM INTERFACE\n\t// just a proxy for the ConstantSourceNode's offset AudioParam\n\t// all docs are generated from AbstractParam.ts\n\t//-------------------------------------\n\n\t/** @inheritdoc */\n\tsetValueAtTime(value: UnitMap[TypeName], time: Time): this {\n\t\tthis._param.setValueAtTime(value, time);\n\t\treturn this;\n\t}\n\t/** @inheritdoc */\n\tgetValueAtTime(time: Time): UnitMap[TypeName] {\n\t\treturn this._param.getValueAtTime(time);\n\t}\n\t/** @inheritdoc */\n\tsetRampPoint(time: Time): this {\n\t\tthis._param.setRampPoint(time);\n\t\treturn this;\n\t}\n\t/** @inheritdoc */\n\tlinearRampToValueAtTime(value: UnitMap[TypeName], time: Time): this {\n\t\tthis._param.linearRampToValueAtTime(value, time);\n\t\treturn this;\n\t}\n\t/** @inheritdoc */\n\texponentialRampToValueAtTime(value: UnitMap[TypeName], time: Time): this {\n\t\tthis._param.exponentialRampToValueAtTime(value, time);\n\t\treturn this;\n\t}\n\t/** @inheritdoc */\n\texponentialRampTo(\n\t\tvalue: UnitMap[TypeName],\n\t\trampTime: Time,\n\t\tstartTime?: Time\n\t): this {\n\t\tthis._param.exponentialRampTo(value, rampTime, startTime);\n\t\treturn this;\n\t}\n\t/** @inheritdoc */\n\tlinearRampTo(\n\t\tvalue: UnitMap[TypeName],\n\t\trampTime: Time,\n\t\tstartTime?: Time\n\t): this {\n\t\tthis._param.linearRampTo(value, rampTime, startTime);\n\t\treturn this;\n\t}\n\t/** @inheritdoc */\n\ttargetRampTo(\n\t\tvalue: UnitMap[TypeName],\n\t\trampTime: Time,\n\t\tstartTime?: Time\n\t): this {\n\t\tthis._param.targetRampTo(value, rampTime, startTime);\n\t\treturn this;\n\t}\n\t/** @inheritdoc */\n\texponentialApproachValueAtTime(\n\t\tvalue: UnitMap[TypeName],\n\t\ttime: Time,\n\t\trampTime: Time\n\t): this {\n\t\tthis._param.exponentialApproachValueAtTime(value, time, rampTime);\n\t\treturn this;\n\t}\n\t/** @inheritdoc */\n\tsetTargetAtTime(\n\t\tvalue: UnitMap[TypeName],\n\t\tstartTime: Time,\n\t\ttimeConstant: number\n\t): this {\n\t\tthis._param.setTargetAtTime(value, startTime, timeConstant);\n\t\treturn this;\n\t}\n\t/** @inheritdoc */\n\tsetValueCurveAtTime(\n\t\tvalues: UnitMap[TypeName][],\n\t\tstartTime: Time,\n\t\tduration: Time,\n\t\tscaling?: number\n\t): this {\n\t\tthis._param.setValueCurveAtTime(values, startTime, duration, scaling);\n\t\treturn this;\n\t}\n\t/** @inheritdoc */\n\tcancelScheduledValues(time: Time): this {\n\t\tthis._param.cancelScheduledValues(time);\n\t\treturn this;\n\t}\n\t/** @inheritdoc */\n\tcancelAndHoldAtTime(time: Time): this {\n\t\tthis._param.cancelAndHoldAtTime(time);\n\t\treturn this;\n\t}\n\t/** @inheritdoc */\n\trampTo(value: UnitMap[TypeName], rampTime: Time, startTime?: Time): this {\n\t\tthis._param.rampTo(value, rampTime, startTime);\n\t\treturn this;\n\t}\n\t/** @inheritdoc */\n\tget value(): UnitMap[TypeName] {\n\t\treturn this._param.value;\n\t}\n\tset value(value: UnitMap[TypeName]) {\n\t\tthis._param.value = value;\n\t}\n\t/** @inheritdoc */\n\tget convert(): boolean {\n\t\treturn this._param.convert;\n\t}\n\tset convert(convert: boolean) {\n\t\tthis._param.convert = convert;\n\t}\n\t/** @inheritdoc */\n\tget units(): UnitName {\n\t\treturn this._param.units;\n\t}\n\t/** @inheritdoc */\n\tget overridden(): boolean {\n\t\treturn this._param.overridden;\n\t}\n\tset overridden(overridden: boolean) {\n\t\tthis._param.overridden = overridden;\n\t}\n\t/** @inheritdoc */\n\tget maxValue(): number {\n\t\treturn this._param.maxValue;\n\t}\n\tget minValue(): number {\n\t\treturn this._param.minValue;\n\t}\n\n\t/**\n\t * @see {@link Param.apply}.\n\t */\n\tapply(param: Param | AudioParam): this {\n\t\tthis._param.apply(param);\n\t\treturn this;\n\t}\n}\n\n/**\n * Keep track of connected signals so they can be disconnected and restored to their previous value\n */\nconst connectedSignals = new WeakMap<\n\tOutputNode,\n\tArray<{\n\t\tdestination: Param | AudioParam | Signal;\n\t\toutputNum: number;\n\t\tinputNum: number;\n\t\t/**\n\t\t * The value before overriding\n\t\t */\n\t\tpreviousValue: number;\n\t}>\n>();\n\n/**\n * When connecting from a signal, it's necessary to zero out the node destination\n * node if that node is also a signal. If the destination is not 0, then the values\n * will be summed. This method insures that the output of the destination signal will\n * be the same as the source signal, making the destination signal a pass through node.\n * @param signal The output signal to connect from\n * @param destination the destination to connect to\n * @param outputNum the optional output number\n * @param inputNum the input number\n */\nexport function connectSignal(\n\tsignal: OutputNode,\n\tdestination: InputNode,\n\toutputNum?: number,\n\tinputNum?: number\n): void {\n\tif (\n\t\tdestination instanceof Param ||\n\t\tisAudioParam(destination) ||\n\t\t(destination instanceof Signal && destination.override)\n\t) {\n\t\tconst previousValue = destination.value;\n\t\t// cancel changes\n\t\tdestination.cancelScheduledValues(0);\n\t\t// reset the value\n\t\tdestination.setValueAtTime(0, 0);\n\t\t// mark the value as overridden\n\t\tif (destination instanceof Signal || destination instanceof Param) {\n\t\t\tdestination.overridden = true;\n\t\t}\n\t\t// store the connection\n\t\tif (!connectedSignals.has(signal)) {\n\t\t\tconnectedSignals.set(signal, []);\n\t\t}\n\t\tconnectedSignals.get(signal)?.push({\n\t\t\tdestination,\n\t\t\toutputNum: outputNum || 0,\n\t\t\tinputNum: inputNum || 0,\n\t\t\tpreviousValue,\n\t\t});\n\t}\n\tconnect(signal, destination, outputNum, inputNum);\n}\n\n/**\n * Disconnect a signal connection and restore the value of the destination if\n * it was a signal that was overridden by the connection.\n * @param signal\n * @param destination\n * @param outputNum\n * @param inputNum\n */\nexport function disconnectSignal(\n\tsignal: OutputNode,\n\tdestination?: InputNode,\n\toutputNum?: number,\n\tinputNum?: number\n): void {\n\tif (\n\t\tdestination instanceof Param ||\n\t\tisAudioParam(destination) ||\n\t\t(destination instanceof Signal && destination.override) ||\n\t\tdestination === undefined\n\t) {\n\t\tif (connectedSignals.has(signal)) {\n\t\t\tlet connections = connectedSignals.get(signal)!;\n\n\t\t\tif (destination) {\n\t\t\t\tconnections = connections.filter((conn) => {\n\t\t\t\t\treturn (\n\t\t\t\t\t\tconn.destination === destination &&\n\t\t\t\t\t\t(isUndef(outputNum) || conn.outputNum === outputNum) &&\n\t\t\t\t\t\t(isUndef(inputNum) || conn.inputNum === inputNum)\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (!connections.length) {\n\t\t\t\tthrow new Error(\"Not connected to destination node\");\n\t\t\t}\n\n\t\t\t// restore the value\n\t\t\tconnections.forEach((connection) => {\n\t\t\t\tif (\n\t\t\t\t\tconnection.destination instanceof Signal ||\n\t\t\t\t\tconnection.destination instanceof Param\n\t\t\t\t) {\n\t\t\t\t\tconnection.destination.overridden = false;\n\t\t\t\t}\n\t\t\t\tconnection.destination.setValueAtTime(\n\t\t\t\t\tconnection.previousValue,\n\t\t\t\t\t0\n\t\t\t\t);\n\t\t\t});\n\t\t\t// remove the connection from the stored array\n\t\t\tconnectedSignals.set(\n\t\t\t\tsignal,\n\t\t\t\tconnectedSignals\n\t\t\t\t\t.get(signal)!\n\t\t\t\t\t.filter((conn) => !connections.includes(conn))\n\t\t\t);\n\t\t}\n\t}\n\tdisconnect(signal, destination, outputNum, inputNum);\n}\n"
  },
  {
    "path": "Tone/signal/SignalOperator.test.ts",
    "content": "import { BasicTests } from \"../../test/helper/Basic.js\";\nimport { SignalConnectAndDisconnect } from \"../../test/helper/SignalTests.js\";\nimport { Signal } from \"./Signal.js\";\nimport { SignalOperator, SignalOperatorOptions } from \"./SignalOperator.js\";\n\ndescribe(\"SignalOperator\", () => {\n\tclass TestSignalOperator extends SignalOperator<SignalOperatorOptions> {\n\t\tname = \"TestSignalOperator\";\n\n\t\tinput: Signal;\n\t\toutput: Signal;\n\n\t\tconstructor(options: SignalOperatorOptions) {\n\t\t\tsuper(options);\n\t\t\tthis.input = this.output = new Signal({\n\t\t\t\tcontext: this.context,\n\t\t\t});\n\t\t}\n\t}\n\n\tBasicTests(TestSignalOperator);\n\tSignalConnectAndDisconnect(TestSignalOperator);\n});\n"
  },
  {
    "path": "Tone/signal/SignalOperator.ts",
    "content": "import {\n\tInputNode,\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../core/context/ToneAudioNode.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { connectSignal, disconnectSignal } from \"./Signal.js\";\n\nexport type SignalOperatorOptions = ToneAudioNodeOptions;\n\n/**\n * A signal operator has an input and output and modifies the signal.\n */\nexport abstract class SignalOperator<\n\tOptions extends SignalOperatorOptions,\n> extends ToneAudioNode<Options> {\n\tconstructor(options?: Partial<Options>);\n\tconstructor() {\n\t\tsuper(\n\t\t\toptionsFromArguments(SignalOperator.getDefaults(), arguments, [\n\t\t\t\t\"context\",\n\t\t\t])\n\t\t);\n\t}\n\n\t/** @inheritdoc */\n\tconnect(destination: InputNode, outputNum = 0, inputNum = 0): this {\n\t\tconnectSignal(this, destination, outputNum, inputNum);\n\t\treturn this;\n\t}\n\n\t/** @inheritdoc */\n\tdisconnect(destination: InputNode, outputNum = 0, inputNum = 0): this {\n\t\tdisconnectSignal(this, destination, outputNum, inputNum);\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/signal/Subtract.test.ts",
    "content": "import { BasicTests } from \"../../test/helper/Basic.js\";\nimport { connectFrom, connectTo } from \"../../test/helper/Connect.js\";\nimport { ConstantOutput } from \"../../test/helper/ConstantOutput.js\";\nimport { Signal } from \"./Signal.js\";\nimport { Subtract } from \"./Subtract.js\";\n\ndescribe(\"Subtract\", () => {\n\tBasicTests(Subtract);\n\n\tcontext(\"Subtraction\", () => {\n\t\tit(\"handles input and output connections\", () => {\n\t\t\tconst subtract = new Subtract();\n\t\t\tconnectFrom().connect(subtract);\n\t\t\tconnectFrom().connect(subtract.subtrahend);\n\t\t\tsubtract.connect(connectTo());\n\t\t\tsubtract.dispose();\n\t\t});\n\n\t\tit(\"correctly subtracts a signal and a number\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(0);\n\t\t\t\tconst sub = new Subtract(3);\n\t\t\t\tsignal.connect(sub);\n\t\t\t\tsub.toDestination();\n\t\t\t}, -3);\n\t\t});\n\n\t\tit(\"can set the scalar value after construction\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(-2);\n\t\t\t\tconst sub = new Subtract(0);\n\t\t\t\tsub.value = 4;\n\t\t\t\tsignal.connect(sub);\n\t\t\t\tsub.toDestination();\n\t\t\t}, -6);\n\t\t});\n\n\t\tit(\"can handle negative values\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(4);\n\t\t\t\tconst sub = new Subtract(-2);\n\t\t\t\tsignal.connect(sub);\n\t\t\t\tsub.toDestination();\n\t\t\t}, 6);\n\t\t});\n\n\t\tit(\"can subtract two signals\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst sigA = new Signal(1);\n\t\t\t\tconst sigB = new Signal(4);\n\t\t\t\tconst sub = new Subtract();\n\t\t\t\tsigA.connect(sub);\n\t\t\t\tsigB.connect(sub.subtrahend);\n\t\t\t\tsub.toDestination();\n\t\t\t}, -3);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/signal/Subtract.ts",
    "content": "import { Gain } from \"../core/context/Gain.js\";\nimport { Param } from \"../core/context/Param.js\";\nimport { connectSeries } from \"../core/context/ToneAudioNode.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { Negate } from \"../signal/Negate.js\";\nimport { Signal, SignalOptions } from \"../signal/Signal.js\";\n\n/**\n * Subtract the signal connected to the input is subtracted from the signal connected\n * The subtrahend.\n *\n * @example\n * // subtract a scalar from a signal\n * const sub = new Tone.Subtract(1);\n * const sig = new Tone.Signal(4).connect(sub);\n * // the output of sub is 3.\n * @example\n * // subtract two signals\n * const sub = new Tone.Subtract();\n * const sigA = new Tone.Signal(10);\n * const sigB = new Tone.Signal(2.5);\n * sigA.connect(sub);\n * sigB.connect(sub.subtrahend);\n * // output of sub is 7.5\n * @category Signal\n */\nexport class Subtract extends Signal {\n\toverride = false;\n\n\treadonly name: string = \"Subtract\";\n\n\t/**\n\t * the summing node\n\t */\n\tprivate _sum: Gain = new Gain({ context: this.context });\n\treadonly input: Gain = this._sum;\n\treadonly output: Gain = this._sum;\n\n\t/**\n\t * Negate the input of the second input before connecting it to the summing node.\n\t */\n\tprivate _neg: Negate = new Negate({ context: this.context });\n\n\t/**\n\t * The value which is subtracted from the main signal\n\t */\n\tsubtrahend: Param<\"number\"> = this._param;\n\n\t/**\n\t * @param value The value to subtract from the incoming signal. If the value\n\t *             is omitted, it will subtract the second signal from the first.\n\t */\n\tconstructor(value?: number);\n\tconstructor(options?: Partial<SignalOptions<\"number\">>);\n\tconstructor() {\n\t\tsuper(\n\t\t\toptionsFromArguments(Subtract.getDefaults(), arguments, [\"value\"])\n\t\t);\n\n\t\tconnectSeries(this._constantSource, this._neg, this._sum);\n\t}\n\n\tstatic getDefaults(): SignalOptions<\"number\"> {\n\t\treturn Object.assign(Signal.getDefaults(), {\n\t\t\tvalue: 0,\n\t\t});\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._neg.dispose();\n\t\tthis._sum.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/signal/SyncedSignal.test.ts",
    "content": "import \"../core/clock/Transport.js\";\nimport \"../core/context/Destination.js\";\n\nimport { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { Offline } from \"../../test/helper/Offline.js\";\nimport { dbToGain } from \"../core/type/Conversions.js\";\nimport { SyncedSignal } from \"./SyncedSignal.js\";\n\ndescribe(\"SyncedSignal\", () => {\n\tBasicTests(SyncedSignal);\n\n\tcontext(\"Scheduling Events\", () => {\n\t\tit(\"can schedule a change in the future\", () => {\n\t\t\tconst sched = new SyncedSignal(1);\n\t\t\tsched.setValueAtTime(2, 0.2);\n\t\t\tsched.dispose();\n\t\t});\n\n\t\tit(\"can schedule setValueAtTime relative to the Transport\", async () => {\n\t\t\tconst buffer = await Offline(\n\t\t\t\t({ transport }) => {\n\t\t\t\t\tconst sched = new SyncedSignal(1).toDestination();\n\t\t\t\t\tsched.setValueAtTime(2, 0.1);\n\t\t\t\t\tsched.setValueAtTime(3, 0.2);\n\t\t\t\t\ttransport.start(0.1);\n\t\t\t\t},\n\t\t\t\t0.4,\n\t\t\t\t1\n\t\t\t);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(1, 0.07);\n\t\t\texpect(buffer.getValueAtTime(0.1)).to.be.closeTo(1, 0.07);\n\t\t\texpect(buffer.getValueAtTime(0.201)).to.be.closeTo(2, 0.07);\n\t\t\texpect(buffer.getValueAtTime(0.301)).to.be.closeTo(3, 0.07);\n\t\t});\n\n\t\tit(\"can schedule linearRampToValueAtTime relative to the Transport\", async () => {\n\t\t\tconst buffer = await Offline(\n\t\t\t\t({ transport }) => {\n\t\t\t\t\tconst sched = new SyncedSignal(1).toDestination();\n\t\t\t\t\tsched.setValueAtTime(1, 0.1);\n\t\t\t\t\tsched.linearRampToValueAtTime(2, 0.2);\n\t\t\t\t\ttransport.start(0.1);\n\t\t\t\t},\n\t\t\t\t0.4,\n\t\t\t\t1\n\t\t\t);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(1, 0.07);\n\t\t\texpect(buffer.getValueAtTime(0.1)).to.be.closeTo(1, 0.07);\n\t\t\texpect(buffer.getValueAtTime(0.2)).to.be.closeTo(1, 0.07);\n\t\t\texpect(buffer.getValueAtTime(0.25)).to.be.closeTo(1.5, 0.07);\n\t\t\texpect(buffer.getValueAtTime(0.301)).to.be.closeTo(2, 0.07);\n\t\t});\n\n\t\tit(\"can schedule exponentialRampToValueAtTime relative to the Transport\", async () => {\n\t\t\tconst buffer = await Offline(\n\t\t\t\t({ transport }) => {\n\t\t\t\t\tconst sched = new SyncedSignal(1).toDestination();\n\t\t\t\t\tsched.setValueAtTime(1, 0.1);\n\t\t\t\t\tsched.exponentialRampToValueAtTime(2, 0.2);\n\t\t\t\t\ttransport.start(0.1);\n\t\t\t\t},\n\t\t\t\t0.4,\n\t\t\t\t1\n\t\t\t);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(1, 0.07);\n\t\t\texpect(buffer.getValueAtTime(0.1)).to.be.closeTo(1, 0.07);\n\t\t\texpect(buffer.getValueAtTime(0.2)).to.be.closeTo(1, 0.07);\n\t\t\texpect(buffer.getValueAtTime(0.25)).to.be.closeTo(1.4, 0.07);\n\t\t\texpect(buffer.getValueAtTime(0.301)).to.be.closeTo(2, 0.07);\n\t\t});\n\n\t\tit(\"can get exponential ramp value in the future\", async () => {\n\t\t\tlet sched;\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tsched = new SyncedSignal(0.5).toDestination();\n\t\t\t\tsched.setValueAtTime(0.5, 0);\n\t\t\t\tsched.exponentialRampToValueAtTime(1, 0.2);\n\t\t\t\tsched.exponentialRampToValueAtTime(0.5, 0.4);\n\t\t\t\ttransport.start(0.1);\n\t\t\t}, 0.6);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\texpect(sample).to.be.closeTo(\n\t\t\t\t\tsched.getValueAtTime(time - 0.1),\n\t\t\t\t\t0.07\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get exponential approach in the future\", async () => {\n\t\t\tlet sched;\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tsched = new SyncedSignal(0.5).toDestination();\n\t\t\t\tsched.setValueAtTime(0.5, 0);\n\t\t\t\tsched.setTargetAtTime(1, 0.2, 0.2);\n\t\t\t\ttransport.start(0.1);\n\t\t\t}, 0.6);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\texpect(sample).to.be.closeTo(\n\t\t\t\t\tsched.getValueAtTime(time - 0.1),\n\t\t\t\t\t0.07\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can loop the signal when the Transport loops\", async () => {\n\t\t\tlet sched;\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tsched = new SyncedSignal(1).toDestination();\n\t\t\t\ttransport.setLoopPoints(0, 1);\n\t\t\t\ttransport.loop = true;\n\t\t\t\tsched.setValueAtTime(1, 0);\n\t\t\t\tsched.setValueAtTime(2, 0.5);\n\t\t\t\ttransport.start(0);\n\t\t\t}, 2);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(1, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0.5)).to.be.closeTo(2, 0.01);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(1, 0.01);\n\t\t\texpect(buffer.getValueAtTime(1.5)).to.be.closeTo(2, 0.01);\n\t\t});\n\n\t\tit(\"can get set a curve in the future\", async () => {\n\t\t\tlet sched;\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tsched = new SyncedSignal(0).toDestination();\n\t\t\t\tsched.setValueCurveAtTime([0, 1, 0.2, 0.8, 0], 0, 1);\n\t\t\t\ttransport.start(0.2);\n\t\t\t}, 1);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\texpect(sample).to.be.closeTo(\n\t\t\t\t\tsched.getValueAtTime(time - 0.2),\n\t\t\t\t\t0.07\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can scale a curve value\", async () => {\n\t\t\tlet sched;\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tsched = new SyncedSignal(1).toDestination();\n\t\t\t\tsched.setValueCurveAtTime([0, 1, 0], 0, 1, 0.5);\n\t\t\t\ttransport.start(0);\n\t\t\t}, 1);\n\t\t\tbuffer.forEach((sample) => {\n\t\t\t\texpect(sample).to.be.at.most(0.51);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can schedule a linear ramp between two times\", async () => {\n\t\t\tlet sched;\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tsched = new SyncedSignal(0).toDestination();\n\t\t\t\tsched.linearRampTo(1, 1, 1);\n\t\t\t\ttransport.start(0);\n\t\t\t}, 3);\n\t\t\texpect(buffer.getValueAtTime(0)).to.closeTo(0, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.5)).to.closeTo(0, 0.1);\n\t\t\texpect(buffer.getValueAtTime(1)).to.closeTo(0, 0.1);\n\t\t\texpect(buffer.getValueAtTime(1.5)).to.closeTo(0.5, 0.1);\n\t\t\texpect(buffer.getValueAtTime(2)).to.closeTo(1, 0.1);\n\t\t});\n\n\t\tit(\"can get exponential ramp value between two times\", async () => {\n\t\t\tlet sched;\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tsched = new SyncedSignal(1).toDestination();\n\t\t\t\tsched.exponentialRampTo(3, 1, 1);\n\t\t\t\ttransport.start(0);\n\t\t\t}, 3);\n\t\t\texpect(buffer.getValueAtTime(0)).to.closeTo(1, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.5)).to.closeTo(1, 0.1);\n\t\t\texpect(buffer.getValueAtTime(1)).to.closeTo(1, 0.1);\n\t\t\texpect(buffer.getValueAtTime(1.5)).to.closeTo(1.75, 0.1);\n\t\t\texpect(buffer.getValueAtTime(2)).to.closeTo(3, 0.1);\n\t\t});\n\n\t\tit(\"can cancel and hold a scheduled value\", async () => {\n\t\t\tlet sched;\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tsched = new SyncedSignal(0).toDestination();\n\t\t\t\tsched.setValueAtTime(0, 0);\n\t\t\t\tsched.linearRampToValueAtTime(1, 1);\n\t\t\t\tsched.cancelAndHoldAtTime(0.5);\n\t\t\t\ttransport.start(0);\n\t\t\t}, 1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.25)).to.be.closeTo(0.25, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.5)).to.be.closeTo(0.5, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.75)).to.be.closeTo(0.5, 0.1);\n\t\t});\n\n\t\tit(\"can cancel a scheduled value\", async () => {\n\t\t\tlet sched;\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tsched = new SyncedSignal(0).toDestination();\n\t\t\t\tsched.setValueAtTime(0, 0);\n\t\t\t\tsched.linearRampToValueAtTime(1, 0.5);\n\t\t\t\tsched.linearRampToValueAtTime(0, 1);\n\t\t\t\tsched.cancelScheduledValues(0.6);\n\t\t\t\ttransport.start(0);\n\t\t\t}, 1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.25)).to.be.closeTo(0.5, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.5)).to.be.closeTo(1, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.75)).to.be.closeTo(1, 0.1);\n\t\t});\n\n\t\tit(\"can automate values with different units\", async () => {\n\t\t\tlet sched;\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tsched = new SyncedSignal(-10, \"decibels\").toDestination();\n\t\t\t\tsched.setValueAtTime(-5, 0);\n\t\t\t\tsched.linearRampToValueAtTime(-12, 0.5);\n\t\t\t\tsched.exponentialRampTo(-6, 0.1, 1);\n\t\t\t\ttransport.start(0);\n\t\t\t}, 1.2);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\tif (time < 0.5) {\n\t\t\t\t\texpect(sample).to.be.within(\n\t\t\t\t\t\tdbToGain(-12.01),\n\t\t\t\t\t\tdbToGain(-4.99)\n\t\t\t\t\t);\n\t\t\t\t} else if (time < 1) {\n\t\t\t\t\texpect(sample).to.be.closeTo(dbToGain(-12), 0.1);\n\t\t\t\t} else if (time > 1.1) {\n\t\t\t\t\texpect(sample).to.be.closeTo(dbToGain(-6), 0.1);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"can set a ramp point and then ramp from there\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst sig = new SyncedSignal(0).toDestination();\n\t\t\t\tsig.setRampPoint(0);\n\t\t\t\tsig.linearRampToValueAtTime(1, 1);\n\t\t\t\tsig.setRampPoint(0.5);\n\t\t\t\tsig.linearRampToValueAtTime(0, 1);\n\t\t\t\ttransport.start(0);\n\t\t\t}, 1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.5)).to.be.closeTo(0.5, 0.1);\n\t\t\texpect(buffer.getValueAtTime(1)).to.be.closeTo(0, 0.1);\n\t\t});\n\n\t\tit(\"can set a exponential approach ramp from the current time\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst sig = new SyncedSignal(0).toDestination();\n\t\t\t\tsig.targetRampTo(1, 0.3);\n\t\t\t\ttransport.start(0);\n\t\t\t}, 0.5);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.below(0.07);\n\t\t\texpect(buffer.getValueAtTime(0.3)).to.be.closeTo(1, 0.1);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/signal/SyncedSignal.ts",
    "content": "import \"../core/clock/Transport.js\";\n\nimport { OutputNode } from \"../core/context/ToneAudioNode.js\";\nimport { TransportTimeClass } from \"../core/type/TransportTime.js\";\nimport {\n\tNormalRange,\n\tSeconds,\n\tTime,\n\tTransportTime,\n\tUnitMap,\n\tUnitName,\n} from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { Signal, SignalOptions } from \"./Signal.js\";\nimport { ToneConstantSource } from \"./ToneConstantSource.js\";\n\n/**\n * Adds the ability to synchronize the signal to the {@link TransportInstance}\n * @category Signal\n */\nexport class SyncedSignal<\n\tTypeName extends UnitName = \"number\",\n> extends Signal<TypeName> {\n\treadonly name: string = \"SyncedSignal\";\n\n\t/**\n\t * Don't override when something is connected to the input\n\t */\n\treadonly override = false;\n\n\treadonly output: OutputNode;\n\n\t/**\n\t * Keep track of the last value as an optimization.\n\t */\n\tprivate _lastVal: UnitMap[TypeName];\n\n\t/**\n\t * The ID returned from scheduleRepeat\n\t */\n\tprivate _synced: number;\n\n\t/**\n\t * Remember the callback value\n\t */\n\tprivate _syncedCallback: () => void;\n\n\t/**\n\t * @param value Initial value of the signal\n\t * @param units The unit name, e.g. \"frequency\"\n\t */\n\tconstructor(value?: UnitMap[TypeName], units?: TypeName);\n\tconstructor(options?: Partial<SignalOptions<TypeName>>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Signal.getDefaults(), arguments, [\n\t\t\t\"value\",\n\t\t\t\"units\",\n\t\t]) as SignalOptions<TypeName>;\n\t\tsuper(options);\n\n\t\tthis._lastVal = options.value;\n\t\tthis._synced = this.context.transport.scheduleRepeat(\n\t\t\tthis._onTick.bind(this),\n\t\t\t\"1i\"\n\t\t);\n\n\t\tthis._syncedCallback = this._anchorValue.bind(this);\n\t\tthis.context.transport.on(\"start\", this._syncedCallback);\n\t\tthis.context.transport.on(\"pause\", this._syncedCallback);\n\t\tthis.context.transport.on(\"stop\", this._syncedCallback);\n\n\t\t// disconnect the constant source from the output and replace it with another one\n\t\tthis._constantSource.disconnect();\n\t\tthis._constantSource.stop(0);\n\n\t\t// create a new one\n\t\tthis._constantSource = this.output = new ToneConstantSource<TypeName>({\n\t\t\tcontext: this.context,\n\t\t\toffset: options.value,\n\t\t\tunits: options.units,\n\t\t}).start(0);\n\t\tthis.setValueAtTime(options.value, 0);\n\t}\n\n\t/**\n\t * Callback which is invoked every tick.\n\t */\n\tprivate _onTick(time: Seconds): void {\n\t\tconst val = super.getValueAtTime(this.context.transport.seconds);\n\t\t// approximate ramp curves with linear ramps\n\t\tif (this._lastVal !== val) {\n\t\t\tthis._lastVal = val;\n\t\t\tthis._constantSource.offset.setValueAtTime(val, time);\n\t\t}\n\t}\n\n\t/**\n\t * Anchor the value at the start and stop of the Transport\n\t */\n\tprivate _anchorValue(time: Seconds): void {\n\t\tconst val = super.getValueAtTime(this.context.transport.seconds);\n\t\tthis._lastVal = val;\n\t\tthis._constantSource.offset.cancelAndHoldAtTime(time);\n\t\tthis._constantSource.offset.setValueAtTime(val, time);\n\t}\n\n\tgetValueAtTime(time: TransportTime): UnitMap[TypeName] {\n\t\tconst computedTime = new TransportTimeClass(\n\t\t\tthis.context,\n\t\t\ttime\n\t\t).toSeconds();\n\t\treturn super.getValueAtTime(computedTime);\n\t}\n\n\tsetValueAtTime(value: UnitMap[TypeName], time: TransportTime) {\n\t\tconst computedTime = new TransportTimeClass(\n\t\t\tthis.context,\n\t\t\ttime\n\t\t).toSeconds();\n\t\tsuper.setValueAtTime(value, computedTime);\n\t\treturn this;\n\t}\n\n\tlinearRampToValueAtTime(value: UnitMap[TypeName], time: TransportTime) {\n\t\tconst computedTime = new TransportTimeClass(\n\t\t\tthis.context,\n\t\t\ttime\n\t\t).toSeconds();\n\t\tsuper.linearRampToValueAtTime(value, computedTime);\n\t\treturn this;\n\t}\n\n\texponentialRampToValueAtTime(\n\t\tvalue: UnitMap[TypeName],\n\t\ttime: TransportTime\n\t) {\n\t\tconst computedTime = new TransportTimeClass(\n\t\t\tthis.context,\n\t\t\ttime\n\t\t).toSeconds();\n\t\tsuper.exponentialRampToValueAtTime(value, computedTime);\n\t\treturn this;\n\t}\n\n\tsetTargetAtTime(\n\t\tvalue,\n\t\tstartTime: TransportTime,\n\t\ttimeConstant: number\n\t): this {\n\t\tconst computedTime = new TransportTimeClass(\n\t\t\tthis.context,\n\t\t\tstartTime\n\t\t).toSeconds();\n\t\tsuper.setTargetAtTime(value, computedTime, timeConstant);\n\t\treturn this;\n\t}\n\n\tcancelScheduledValues(startTime: TransportTime): this {\n\t\tconst computedTime = new TransportTimeClass(\n\t\t\tthis.context,\n\t\t\tstartTime\n\t\t).toSeconds();\n\t\tsuper.cancelScheduledValues(computedTime);\n\t\treturn this;\n\t}\n\n\tsetValueCurveAtTime(\n\t\tvalues: UnitMap[TypeName][],\n\t\tstartTime: TransportTime,\n\t\tduration: Time,\n\t\tscaling: NormalRange\n\t): this {\n\t\tconst computedTime = new TransportTimeClass(\n\t\t\tthis.context,\n\t\t\tstartTime\n\t\t).toSeconds();\n\t\tduration = this.toSeconds(duration);\n\t\tsuper.setValueCurveAtTime(values, computedTime, duration, scaling);\n\t\treturn this;\n\t}\n\n\tcancelAndHoldAtTime(time: TransportTime): this {\n\t\tconst computedTime = new TransportTimeClass(\n\t\t\tthis.context,\n\t\t\ttime\n\t\t).toSeconds();\n\t\tsuper.cancelAndHoldAtTime(computedTime);\n\t\treturn this;\n\t}\n\n\tsetRampPoint(time: TransportTime): this {\n\t\tconst computedTime = new TransportTimeClass(\n\t\t\tthis.context,\n\t\t\ttime\n\t\t).toSeconds();\n\t\tsuper.setRampPoint(computedTime);\n\t\treturn this;\n\t}\n\n\texponentialRampTo(\n\t\tvalue: UnitMap[TypeName],\n\t\trampTime: Time,\n\t\tstartTime?: TransportTime\n\t): this {\n\t\tconst computedTime = new TransportTimeClass(\n\t\t\tthis.context,\n\t\t\tstartTime\n\t\t).toSeconds();\n\t\tsuper.exponentialRampTo(value, rampTime, computedTime);\n\t\treturn this;\n\t}\n\n\tlinearRampTo(\n\t\tvalue: UnitMap[TypeName],\n\t\trampTime: Time,\n\t\tstartTime?: TransportTime\n\t): this {\n\t\tconst computedTime = new TransportTimeClass(\n\t\t\tthis.context,\n\t\t\tstartTime\n\t\t).toSeconds();\n\t\tsuper.linearRampTo(value, rampTime, computedTime);\n\t\treturn this;\n\t}\n\n\ttargetRampTo(\n\t\tvalue: UnitMap[TypeName],\n\t\trampTime: Time,\n\t\tstartTime?: TransportTime\n\t): this {\n\t\tconst computedTime = new TransportTimeClass(\n\t\t\tthis.context,\n\t\t\tstartTime\n\t\t).toSeconds();\n\t\tsuper.targetRampTo(value, rampTime, computedTime);\n\t\treturn this;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.context.transport.clear(this._synced);\n\t\tthis.context.transport.off(\"start\", this._syncedCallback);\n\t\tthis.context.transport.off(\"pause\", this._syncedCallback);\n\t\tthis.context.transport.off(\"stop\", this._syncedCallback);\n\t\tthis._constantSource.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/signal/ToneConstantSource.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { Offline, whenBetween } from \"../../test/helper/Offline.js\";\nimport { Context } from \"../core/context/Context.js\";\nimport { ToneConstantSource } from \"./ToneConstantSource.js\";\n\ndescribe(\"ToneConstantSource\", () => {\n\tBasicTests(ToneConstantSource);\n\n\tcontext(\"Constructor\", () => {\n\t\tit(\"can be constructed with an offset\", () => {\n\t\t\tconst source = new ToneConstantSource(330);\n\t\t\texpect(source.offset.value).to.equal(330);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with no arguments\", () => {\n\t\t\tconst source = new ToneConstantSource();\n\t\t\texpect(source.offset.value).to.equal(1);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an options object\", () => {\n\t\t\tconst source = new ToneConstantSource({\n\t\t\t\toffset: 2,\n\t\t\t});\n\t\t\texpect(source.offset.value).to.be.closeTo(2, 0.01);\n\t\t\tsource.dispose();\n\t\t});\n\t});\n\n\tcontext(\"onended\", () => {\n\t\tit(\"invokes the onended callback in the online context\", (done) => {\n\t\t\tconst source = new ToneConstantSource();\n\t\t\tsource.start();\n\t\t\tsource.stop(\"+0.3\");\n\t\t\tconst now = source.now();\n\t\t\tsource.onended = () => {\n\t\t\t\texpect(source.now() - now).to.be.closeTo(0.3, 0.15);\n\t\t\t\tsource.dispose();\n\t\t\t\tdone();\n\t\t\t};\n\t\t});\n\n\t\tit(\"invokes the onended callback only once in the online context\", (done) => {\n\t\t\tconst source = new ToneConstantSource();\n\t\t\tsource.start();\n\t\t\tsource.stop(\"+0.1\");\n\t\t\tsource.stop(\"+0.2\");\n\t\t\tsource.stop(\"+0.3\");\n\t\t\tconst now = source.now();\n\t\t\tsource.onended = () => {\n\t\t\t\texpect(source.now() - now).to.be.within(0.25, 0.5);\n\t\t\t\tsource.dispose();\n\t\t\t\tdone();\n\t\t\t};\n\t\t});\n\n\t\tit(\"invokes the onended callback in the offline context\", async () => {\n\t\t\tlet wasInvoked = false;\n\t\t\tawait Offline(() => {\n\t\t\t\tconst source = new ToneConstantSource();\n\t\t\t\tsource.start(0);\n\t\t\t\tsource.stop(0.2);\n\t\t\t\tsource.onended = () => {\n\t\t\t\t\texpect(source.now() - 0.2).to.be.closeTo(0, 0.05);\n\t\t\t\t\tsource.dispose();\n\t\t\t\t\twasInvoked = true;\n\t\t\t\t};\n\t\t\t}, 0.3);\n\t\t\texpect(wasInvoked).to.equal(true);\n\t\t});\n\n\t\tit(\"invokes the onended callback only once in offline context\", async () => {\n\t\t\tlet wasInvoked = false;\n\t\t\tawait Offline(() => {\n\t\t\t\tconst source = new ToneConstantSource();\n\t\t\t\tsource.start(0);\n\t\t\t\tsource.stop(0.1);\n\t\t\t\tsource.stop(0.2);\n\t\t\t\tsource.stop(0.3);\n\t\t\t\tsource.onended = () => {\n\t\t\t\t\texpect(source.now() - 0.3).to.be.closeTo(0, 0.05);\n\t\t\t\t\tsource.dispose();\n\t\t\t\t\texpect(wasInvoked).to.equal(false);\n\t\t\t\t\twasInvoked = true;\n\t\t\t\t};\n\t\t\t}, 0.4);\n\t\t\texpect(wasInvoked).to.equal(true);\n\t\t});\n\t});\n\n\tcontext(\"Scheduling\", () => {\n\t\tit(\"throw an error if start is called multiple time\", () => {\n\t\t\tconst source = new ToneConstantSource();\n\t\t\tsource.start();\n\t\t\texpect(() => {\n\t\t\t\tsource.start();\n\t\t\t}).to.throw();\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can play for a specific duration\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst source = new ToneConstantSource().toDestination();\n\t\t\t\tsource.start(0).stop(0.1);\n\t\t\t}, 0.4);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.above(0);\n\t\t\texpect(buffer.getValueAtTime(0.09)).to.be.above(0);\n\t\t\texpect(buffer.getValueAtTime(0.1)).to.equal(0);\n\t\t});\n\n\t\tit(\"can call stop multiple times and takes the last value\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst source = new ToneConstantSource().toDestination();\n\t\t\t\tsource.start(0).stop(0.1).stop(0.2);\n\t\t\t}, 0.4);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.above(0);\n\t\t\texpect(buffer.getValueAtTime(0.1)).to.be.above(0);\n\t\t\texpect(buffer.getValueAtTime(0.19)).to.be.above(0);\n\t\t\texpect(buffer.getValueAtTime(0.2)).to.equal(0);\n\t\t});\n\n\t\tit(\"clamps start time to the currentTime\", () => {\n\t\t\tconst source = new ToneConstantSource();\n\t\t\tsource.start(0);\n\t\t\tconst currentTime = source.context.currentTime;\n\t\t\texpect(source.getStateAtTime(0)).to.equal(\"stopped\");\n\t\t\texpect(source.getStateAtTime(currentTime)).to.equal(\"started\");\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"clamps stop time to the currentTime\", (done) => {\n\t\t\tconst source = new ToneConstantSource();\n\t\t\tsource.start(0);\n\t\t\tlet currentTime = source.context.currentTime;\n\t\t\texpect(source.getStateAtTime(0)).to.equal(\"stopped\");\n\t\t\texpect(source.getStateAtTime(currentTime)).to.equal(\"started\");\n\t\t\tsetTimeout(() => {\n\t\t\t\tcurrentTime = source.now();\n\t\t\t\tsource.stop(0);\n\t\t\t\texpect(source.getStateAtTime(currentTime + 0.01)).to.equal(\n\t\t\t\t\t\"stopped\"\n\t\t\t\t);\n\t\t\t\tsource.dispose();\n\t\t\t\tdone();\n\t\t\t}, 100);\n\t\t});\n\t});\n\n\tcontext(\"State\", () => {\n\t\tit(\"reports the right state\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst source = new ToneConstantSource();\n\t\t\t\tsource.start(0);\n\t\t\t\tsource.stop(0.05);\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, 0.05, () => {\n\t\t\t\t\t\texpect(source.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.05, 0.1, () => {\n\t\t\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.1);\n\t\t});\n\n\t\tit(\"can call stop multiple times, takes the last value\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst source = new ToneConstantSource();\n\t\t\t\tsource.start(0);\n\t\t\t\tsource.stop(0.05);\n\t\t\t\tsource.stop(0.1);\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, 0.1, () => {\n\t\t\t\t\t\texpect(source.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.1, 0.2, () => {\n\t\t\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.2);\n\t\t});\n\t});\n\n\tcontext.only(\"Suspended AudioContext\", () => {\n\t\tit(\"does nothing when AudioContext returns to suspended\", () => {\n\t\t\tconst context = new Context();\n\t\t\texpect(context.state).to.equal(\"suspended\");\n\n\t\t\tconst source = new ToneConstantSource({\n\t\t\t\tcontext,\n\t\t\t});\n\n\t\t\tsource.start(0);\n\n\t\t\tcontext.dispose();\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"starts when the audio context is resumed\", async () => {\n\t\t\tconst context = new Context();\n\t\t\texpect(context.state).to.equal(\"suspended\");\n\n\t\t\tconst source = new ToneConstantSource({\n\t\t\t\tcontext,\n\t\t\t});\n\n\t\t\tsource.start(0);\n\n\t\t\tawait context.resume();\n\n\t\t\tcontext.dispose();\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"context can be suspended again\", async () => {\n\t\t\tconst context = new Context();\n\t\t\texpect(context.state).to.equal(\"suspended\");\n\n\t\t\tconst source = new ToneConstantSource({\n\t\t\t\tcontext,\n\t\t\t});\n\n\t\t\tsource.start(0);\n\n\t\t\tawait context.resume();\n\n\t\t\tsource.stop(0.1);\n\n\t\t\tawait context.rawContext.suspend(0);\n\n\t\t\t// wait for the context to be suspended\n\t\t\tawait new Promise<void>((resolve) =>\n\t\t\t\tcontext.on(\"statechange\", () => {\n\t\t\t\t\tif (context.state === \"suspended\") {\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t);\n\n\t\t\tcontext.dispose();\n\t\t\tsource.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/signal/ToneConstantSource.ts",
    "content": "import { Param } from \"../core/context/Param.js\";\nimport { connect } from \"../core/context/ToneAudioNode.js\";\nimport { Seconds, Time, UnitMap, UnitName } from \"../core/type/Units.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport {\n\tOneShotSource,\n\tOneShotSourceOptions,\n} from \"../source/OneShotSource.js\";\n\nexport interface ToneConstantSourceOptions<TypeName extends UnitName>\n\textends OneShotSourceOptions {\n\tconvert: boolean;\n\toffset: UnitMap[TypeName];\n\tunits: TypeName;\n\tminValue?: number;\n\tmaxValue?: number;\n}\n\n/**\n * Wrapper around the native fire-and-forget ConstantSource.\n * Adds the ability to reschedule the stop method.\n * @category Signal\n */\nexport class ToneConstantSource<\n\tTypeName extends UnitName = \"number\",\n> extends OneShotSource<ToneConstantSourceOptions<TypeName>> {\n\treadonly name: string = \"ToneConstantSource\";\n\n\t/**\n\t * The signal generator\n\t */\n\tprivate _source?: ConstantSourceNode;\n\n\t/**\n\t * The offset of the signal generator\n\t */\n\treadonly offset: Param<TypeName>;\n\n\t/**\n\t * @param  offset   The offset value\n\t */\n\tconstructor(offset: UnitMap[TypeName]);\n\tconstructor(options?: Partial<ToneConstantSourceOptions<TypeName>>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tToneConstantSource.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"offset\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._onContextRunning(() => this._contextStarted());\n\n\t\tthis.offset = new Param({\n\t\t\tcontext: this.context,\n\t\t\tconvert: options.convert,\n\t\t\tparam: !this._source\n\t\t\t\t? // placeholder param until the context is started\n\t\t\t\t\tthis.context.createGain().gain\n\t\t\t\t: this._source.offset,\n\t\t\tswappable: !this._source,\n\t\t\tunits: options.units,\n\t\t\tvalue: options.offset,\n\t\t\tminValue: options.minValue,\n\t\t\tmaxValue: options.maxValue,\n\t\t});\n\t}\n\n\tstatic getDefaults(): ToneConstantSourceOptions<any> {\n\t\treturn Object.assign(OneShotSource.getDefaults(), {\n\t\t\tconvert: true,\n\t\t\toffset: 1,\n\t\t\tunits: \"number\" as UnitName,\n\t\t});\n\t}\n\n\t/**\n\t * Once the context is started, kick off source.\n\t */\n\tprivate _contextStarted() {\n\t\tthis._source = this.context.createConstantSource();\n\t\tconnect(this._source, this._gainNode);\n\t\tthis.offset?.setParam(this._source.offset);\n\t\tif (this.state === \"started\") {\n\t\t\tthis._source.start(0);\n\t\t}\n\t}\n\n\t/**\n\t * Start the source node at the given time\n\t * @param  time When to start the source\n\t */\n\tstart(time?: Time): this {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tthis.log(\"start\", computedTime);\n\t\tthis._startGain(computedTime);\n\t\tthis._source?.start(computedTime);\n\t\treturn this;\n\t}\n\n\tprotected _stopSource(time?: Seconds): void {\n\t\tif (this.state === \"stopped\") {\n\t\t\treturn;\n\t\t}\n\t\tthis._source?.stop(time);\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tif (this.state === \"started\") {\n\t\t\tthis.stop();\n\t\t}\n\t\tthis._source?.disconnect();\n\t\tthis.offset.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/signal/WaveShaper.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { ConstantOutput } from \"../../test/helper/ConstantOutput.js\";\nimport { Offline } from \"../../test/helper/Offline.js\";\nimport { Signal } from \"./Signal.js\";\nimport { WaveShaper } from \"./WaveShaper.js\";\n\ndescribe(\"WaveShaper\", () => {\n\tBasicTests(WaveShaper);\n\n\tdescribe(\"Construction Options\", () => {\n\t\tit(\"can be constructed with an array\", () => {\n\t\t\tconst waveshaper = new WaveShaper([1, 2, 3, 4, 5, 6]);\n\t\t\texpect(waveshaper.curve && waveshaper.curve[0]).to.equal(1);\n\t\t\texpect(waveshaper.curve && waveshaper.curve[2]).to.equal(3);\n\t\t});\n\n\t\tit(\"can be constructed with a mapping function\", () => {\n\t\t\tconst waveshaper = new WaveShaper(() => {\n\t\t\t\treturn -2;\n\t\t\t});\n\t\t\texpect(waveshaper.curve && waveshaper.curve[0]).to.equal(-2);\n\t\t\texpect(waveshaper.curve && waveshaper.curve[1]).to.equal(-2);\n\t\t});\n\n\t\tit(\"can be constructed with a length and then set with a map\", () => {\n\t\t\tconst waveshaper = new WaveShaper(() => 10, 2048);\n\t\t\texpect(waveshaper.curve && waveshaper.curve.length).to.equal(2048);\n\t\t\texpect(waveshaper.curve && waveshaper.curve[0]).to.equal(10);\n\t\t\texpect(waveshaper.curve && waveshaper.curve[1]).to.equal(10);\n\t\t});\n\n\t\tit(\"can be set to oversample\", () => {\n\t\t\tconst waveshaper = new WaveShaper();\n\t\t\texpect(waveshaper.oversample).to.equal(\"none\");\n\t\t\twaveshaper.oversample = \"2x\";\n\t\t\texpect(waveshaper.oversample).to.equal(\"2x\");\n\t\t\texpect(() => {\n\t\t\t\t// @ts-ignore\n\t\t\t\twaveshaper.oversample = \"3x\";\n\t\t\t}).to.throw(Error);\n\t\t});\n\t});\n\n\tdescribe(\"Logic\", () => {\n\t\tit(\"shapes the output of the incoming signal\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(1);\n\t\t\t\tconst waveshaper = new WaveShaper([-10, -10, -10]);\n\t\t\t\tsignal.connect(waveshaper);\n\t\t\t\twaveshaper.toDestination();\n\t\t\t}, -10);\n\t\t});\n\n\t\tit(\"outputs the last curve value when the input is above 1\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(10);\n\t\t\t\tconst waveshaper = new WaveShaper([-20, 20]);\n\t\t\t\tsignal.connect(waveshaper);\n\t\t\t\twaveshaper.toDestination();\n\t\t\t}, 20);\n\t\t});\n\n\t\tit(\"outputs the first curve value when the input is below -1\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(-1);\n\t\t\t\tconst waveshaper = new WaveShaper([-20, 20]);\n\t\t\t\tsignal.connect(waveshaper);\n\t\t\t\twaveshaper.toDestination();\n\t\t\t}, -20);\n\t\t});\n\n\t\tit(\"maps the input through the waveshaping curve\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst signal = new Signal(-1);\n\t\t\t\tconst waveshaper = new WaveShaper((input) => {\n\t\t\t\t\treturn input * 2;\n\t\t\t\t});\n\t\t\t\tsignal.connect(waveshaper);\n\t\t\t\twaveshaper.toDestination();\n\t\t\t\tsignal.setValueAtTime(-1, 0);\n\t\t\t\tsignal.linearRampToValueAtTime(1, 1);\n\t\t\t}, 1);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\texpect(sample).to.be.closeTo(2 * (time * 2 - 1), 0.005);\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/signal/WaveShaper.ts",
    "content": "import { ToneAudioNodeOptions } from \"../core/context/ToneAudioNode.js\";\nimport { assert } from \"../core/util/Debug.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { isArray, isFunction } from \"../core/util/TypeCheck.js\";\nimport { Signal } from \"./Signal.js\";\nimport { SignalOperator } from \"./SignalOperator.js\";\n\nexport type WaveShaperMappingFn = (value: number, index?: number) => number;\n\ntype WaveShaperMapping = WaveShaperMappingFn | number[] | Float32Array;\n\ninterface WaveShaperOptions extends ToneAudioNodeOptions {\n\tmapping?: WaveShaperMapping;\n\tlength: number;\n\tcurve?: number[] | Float32Array;\n}\n\n/**\n * Wraps the native Web Audio API\n * [WaveShaperNode](http://webaudio.github.io/web-audio-api/#the-waveshapernode-interface).\n *\n * @example\n * const osc = new Tone.Oscillator().toDestination().start();\n * // multiply the output of the signal by 2 using the waveshaper's function\n * const timesTwo = new Tone.WaveShaper((val) => val * 2, 2048).connect(osc.frequency);\n * const signal = new Tone.Signal(440).connect(timesTwo);\n * @category Signal\n */\nexport class WaveShaper extends SignalOperator<WaveShaperOptions> {\n\treadonly name: string = \"WaveShaper\";\n\n\t/**\n\t * the waveshaper node\n\t */\n\tprivate _shaper: WaveShaperNode = this.context.createWaveShaper();\n\n\t/**\n\t * The input to the waveshaper node.\n\t */\n\tinput = this._shaper;\n\n\t/**\n\t * The output from the waveshaper node\n\t */\n\toutput = this._shaper;\n\n\t/**\n\t * @param mapping The function used to define the values.\n\t *                The mapping function should take two arguments:\n\t *                the first is the value at the current position\n\t *                and the second is the array position.\n\t *                If the argument is an array, that array will be\n\t *                set as the wave shaping function. The input\n\t *                signal is an AudioRange [-1, 1] value and the output\n\t *                signal can take on any numerical values.\n\t *\n\t * @param length The length of the WaveShaperNode buffer.\n\t */\n\tconstructor(mapping?: WaveShaperMapping, length?: number);\n\tconstructor(options?: Partial<WaveShaperOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tWaveShaper.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"mapping\", \"length\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._onContextRunning(() => {\n\t\t\tthis.initCurve(options.mapping, options.length);\n\t\t});\n\t}\n\n\tstatic getDefaults(): WaveShaperOptions {\n\t\treturn Object.assign(Signal.getDefaults(), {\n\t\t\tlength: 1024,\n\t\t});\n\t}\n\n\t/**\n\t * Set the curve for the first time. This is run only after the audio context is\n\t * running to avoid any context warnings.\n\t */\n\tprivate initCurve(mapping?: WaveShaperMapping, length?: number): void {\n\t\tif (isArray(mapping) || mapping instanceof Float32Array) {\n\t\t\tthis.curve = Float32Array.from(mapping);\n\t\t} else if (isFunction(mapping)) {\n\t\t\tthis.setMap(mapping, length);\n\t\t}\n\t}\n\n\t/**\n\t * Uses a mapping function to set the value of the curve.\n\t * @param mapping The function used to define the values.\n\t *                The mapping function take two arguments:\n\t *                the first is the value at the current position\n\t *                which goes from -1 to 1 over the number of elements\n\t *                in the curve array. The second argument is the array position.\n\t * @example\n\t * const shaper = new Tone.WaveShaper();\n\t * // map the input signal from [-1, 1] to [0, 10]\n\t * shaper.setMap((val, index) => (val + 1) * 5);\n\t */\n\tsetMap(mapping: WaveShaperMappingFn, length = 1024): this {\n\t\tconst array = new Float32Array(length);\n\t\tfor (let i = 0, len = length; i < len; i++) {\n\t\t\tconst normalized = (i / (len - 1)) * 2 - 1;\n\t\t\tarray[i] = mapping(normalized, i);\n\t\t}\n\t\tthis.curve = array;\n\t\treturn this;\n\t}\n\n\t/**\n\t * The array to set as the waveshaper curve. For linear curves\n\t * array length does not make much difference, but for complex curves\n\t * longer arrays will provide smoother interpolation.\n\t */\n\tget curve(): Float32Array | null {\n\t\treturn this._shaper.curve;\n\t}\n\n\tset curve(mapping: Float32Array | null) {\n\t\tthis._shaper.curve = mapping;\n\t}\n\n\t/**\n\t * Specifies what type of oversampling (if any) should be used when\n\t * applying the shaping curve. Can either be \"none\", \"2x\" or \"4x\".\n\t */\n\tget oversample(): OverSampleType {\n\t\treturn this._shaper.oversample;\n\t}\n\n\tset oversample(oversampling: OverSampleType) {\n\t\tconst isOverSampleType = [\"none\", \"2x\", \"4x\"].some((str) =>\n\t\t\tstr.includes(oversampling)\n\t\t);\n\t\tassert(\n\t\t\tisOverSampleType,\n\t\t\t\"oversampling must be either 'none', '2x', or '4x'\"\n\t\t);\n\t\tthis._shaper.oversample = oversampling;\n\t}\n\n\t/**\n\t * Clean up.\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._shaper.disconnect();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/signal/Zero.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { ConstantOutput } from \"../../test/helper/ConstantOutput.js\";\nimport { Zero } from \"./Zero.js\";\n\ndescribe(\"Zero\", () => {\n\tBasicTests(Zero);\n\n\tcontext(\"Zero\", () => {\n\t\tit(\"has 0 inputs and 1 output\", () => {\n\t\t\tconst zero = new Zero();\n\t\t\texpect(zero.numberOfInputs).to.equal(0);\n\t\t\texpect(zero.numberOfOutputs).to.equal(1);\n\t\t\tzero.dispose();\n\t\t});\n\n\t\tit(\"always outputs 0\", () => {\n\t\t\treturn ConstantOutput(\n\t\t\t\t() => {\n\t\t\t\t\tnew Zero().toDestination();\n\t\t\t\t},\n\t\t\t\t0,\n\t\t\t\t0\n\t\t\t);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/signal/Zero.ts",
    "content": "import {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../core/context/ToneAudioNode.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { SignalOperator } from \"./SignalOperator.js\";\nimport { ToneConstantSource } from \"./ToneConstantSource.js\";\n\n/**\n * Tone.Zero outputs 0's at audio-rate. The reason this has to be\n * its own class is that many browsers optimize out Tone.Signal\n * with a value of 0 and will not process nodes further down the graph.\n * @category Signal\n */\nexport class Zero extends SignalOperator<ToneAudioNodeOptions> {\n\treadonly name: string = \"Zero\";\n\n\t/**\n\t * A constant source which outputs 0\n\t */\n\tprivate _constant: ToneConstantSource;\n\n\t/**\n\t * Only outputs 0\n\t */\n\toutput: ToneAudioNode;\n\n\t/**\n\t * no input node\n\t */\n\tinput = undefined;\n\n\tconstructor(options?: Partial<ToneAudioNodeOptions>);\n\tconstructor() {\n\t\tsuper(optionsFromArguments(Zero.getDefaults(), arguments));\n\t\tthis._constant = this.output = new ToneConstantSource({\n\t\t\tcontext: this.context,\n\t\t\toffset: 0,\n\t\t}).start();\n\t}\n\n\t/**\n\t * clean up\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._constant.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/signal/index.ts",
    "content": "export * from \"./Abs.js\";\nexport * from \"./Add.js\";\nexport * from \"./AudioToGain.js\";\nexport * from \"./GainToAudio.js\";\nexport * from \"./GreaterThan.js\";\nexport * from \"./GreaterThanZero.js\";\nexport * from \"./Multiply.js\";\nexport * from \"./Negate.js\";\nexport * from \"./Pow.js\";\nexport * from \"./Scale.js\";\nexport * from \"./ScaleExp.js\";\nexport * from \"./Signal.js\";\nexport * from \"./Subtract.js\";\nexport * from \"./SyncedSignal.js\";\nexport * from \"./WaveShaper.js\";\nexport * from \"./Zero.js\";\n"
  },
  {
    "path": "Tone/source/Noise.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../test/helper/CompareToFile.js\";\nimport { OutputAudio } from \"../../test/helper/OutputAudio.js\";\nimport { SourceTests } from \"../../test/helper/SourceTests.js\";\nimport { Noise } from \"./Noise.js\";\n\ndescribe(\"Noise\", () => {\n\t// run the common tests\n\tBasicTests(Noise);\n\tSourceTests(Noise);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst noise = new Noise().toDestination();\n\t\t\t\tnoise.start(0.1).stop(0.2);\n\t\t\t},\n\t\t\t\"noise.wav\",\n\t\t\t9\n\t\t);\n\t});\n\n\tcontext(\"Get/Set\", () => {\n\t\tit(\"can be constructed with an options object\", () => {\n\t\t\tconst noise = new Noise({\n\t\t\t\ttype: \"brown\",\n\t\t\t});\n\t\t\texpect(noise.type).to.equal(\"brown\");\n\t\t\tnoise.dispose();\n\t\t});\n\n\t\tit(\"can set the playbackRate in the constructor\", () => {\n\t\t\tconst noise = new Noise({\n\t\t\t\tplaybackRate: 2,\n\t\t\t});\n\t\t\texpect(noise.playbackRate).to.equal(2);\n\t\t\tnoise.dispose();\n\t\t});\n\n\t\tit(\"can set the playbackRate after the noise is started\", () => {\n\t\t\treturn OutputAudio(() => {\n\t\t\t\tconst noise = new Noise().toDestination();\n\t\t\t\tnoise.start();\n\t\t\t\tnoise.playbackRate = 3;\n\t\t\t\texpect(noise.playbackRate).to.equal(3);\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"Fades\", () => {\n\t\tit(\"can set the fade in/out\", () => {\n\t\t\tconst noise = new Noise({\n\t\t\t\tfadeIn: 0.1,\n\t\t\t});\n\t\t\texpect(noise.fadeIn).to.equal(0.1);\n\t\t\texpect(noise.fadeOut).to.equal(0);\n\t\t\tnoise.start();\n\t\t\tnoise.fadeIn = 0.2;\n\t\t\tnoise.fadeOut = 0.1;\n\t\t\texpect(noise.fadeIn).to.equal(0.2);\n\t\t\texpect(noise.fadeOut).to.equal(0.1);\n\t\t\tnoise.dispose();\n\t\t});\n\t});\n\n\tcontext(\"Type\", () => {\n\t\tit(\"can be set to 3 noise types\", () => {\n\t\t\tconst noise = new Noise();\n\t\t\tconst types = [\"white\", \"brown\", \"pink\"];\n\t\t\ttypes.forEach((type) => {\n\t\t\t\t// @ts-ignore\n\t\t\t\tnoise.type = type;\n\t\t\t\texpect(noise.type).to.equal(type);\n\t\t\t});\n\t\t\tnoise.dispose();\n\t\t});\n\n\t\tit(\"cant set invalid type\", () => {\n\t\t\tconst noise = new Noise();\n\t\t\texpect(() => {\n\t\t\t\t// @ts-ignore\n\t\t\t\tnoise.type = \"else\";\n\t\t\t}).to.throw(Error);\n\t\t\tnoise.dispose();\n\t\t});\n\n\t\tit(\"outputs white noise\", () => {\n\t\t\treturn OutputAudio(() => {\n\t\t\t\tconst noise = new Noise(\"white\");\n\t\t\t\tnoise.toDestination();\n\t\t\t\tnoise.start();\n\t\t\t});\n\t\t});\n\n\t\tit(\"outputs pink noise\", () => {\n\t\t\treturn OutputAudio(() => {\n\t\t\t\tconst noise = new Noise(\"pink\");\n\t\t\t\tnoise.toDestination();\n\t\t\t\tnoise.start();\n\t\t\t});\n\t\t});\n\n\t\tit(\"outputs brown noise\", () => {\n\t\t\treturn OutputAudio(() => {\n\t\t\t\tconst noise = new Noise(\"brown\");\n\t\t\t\tnoise.toDestination();\n\t\t\t\tnoise.start();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can set the type after the noise is started\", () => {\n\t\t\treturn OutputAudio(() => {\n\t\t\t\tconst noise = new Noise();\n\t\t\t\tnoise.toDestination();\n\t\t\t\tnoise.start();\n\t\t\t\tnoise.type = \"brown\";\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/source/Noise.ts",
    "content": "import { ToneAudioBuffer } from \"../core/context/ToneAudioBuffer.js\";\nimport { Positive, Time } from \"../core/type/Units.js\";\nimport { assert } from \"../core/util/Debug.js\";\nimport { optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { Source, SourceOptions } from \"../source/Source.js\";\nimport { ToneBufferSource } from \"./buffer/ToneBufferSource.js\";\n\nexport type NoiseType = \"white\" | \"brown\" | \"pink\";\n\nexport interface NoiseOptions extends SourceOptions {\n\ttype: NoiseType;\n\tplaybackRate: Positive;\n\tfadeIn: Time;\n\tfadeOut: Time;\n}\n\n/**\n * Noise is a noise generator. It uses looped noise buffers to save on performance.\n * Noise supports the noise types: \"pink\", \"white\", and \"brown\". Read more about\n * colors of noise on [Wikipedia](https://en.wikipedia.org/wiki/Colors_of_noise).\n *\n * @example\n * // initialize the noise and start\n * const noise = new Tone.Noise(\"pink\").start();\n * // make an autofilter to shape the noise\n * const autoFilter = new Tone.AutoFilter({\n * \tfrequency: \"8n\",\n * \tbaseFrequency: 200,\n * \toctaves: 8\n * }).toDestination().start();\n * // connect the noise\n * noise.connect(autoFilter);\n * // start the autofilter LFO\n * autoFilter.start();\n * @category Source\n */\nexport class Noise extends Source<NoiseOptions> {\n\treadonly name: string = \"Noise\";\n\n\t/**\n\t * Private reference to the source\n\t */\n\tprivate _source: ToneBufferSource | null = null;\n\n\t/**\n\t * private reference to the type\n\t */\n\tprivate _type!: NoiseType;\n\n\t/**\n\t * The playback rate of the noise. Affects\n\t * the \"frequency\" of the noise.\n\t */\n\tprivate _playbackRate: Positive;\n\n\t/**\n\t * The fadeIn time of the amplitude envelope.\n\t */\n\tprotected _fadeIn: Time;\n\n\t/**\n\t * The fadeOut time of the amplitude envelope.\n\t */\n\tprotected _fadeOut: Time;\n\n\t/**\n\t * @param type the noise type (white|pink|brown)\n\t */\n\tconstructor(type?: NoiseType);\n\tconstructor(options?: Partial<NoiseOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Noise.getDefaults(), arguments, [\n\t\t\t\"type\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis._playbackRate = options.playbackRate;\n\t\tthis.type = options.type;\n\t\tthis._fadeIn = options.fadeIn;\n\t\tthis._fadeOut = options.fadeOut;\n\t}\n\n\tstatic getDefaults(): NoiseOptions {\n\t\treturn Object.assign(Source.getDefaults(), {\n\t\t\tfadeIn: 0,\n\t\t\tfadeOut: 0,\n\t\t\tplaybackRate: 1,\n\t\t\ttype: \"white\" as NoiseType,\n\t\t});\n\t}\n\n\t/**\n\t * The type of the noise. Can be \"white\", \"brown\", or \"pink\".\n\t * @example\n\t * const noise = new Tone.Noise().toDestination().start();\n\t * noise.type = \"brown\";\n\t */\n\tget type(): NoiseType {\n\t\treturn this._type;\n\t}\n\tset type(type: NoiseType) {\n\t\tassert(type in _noiseBuffers, \"Noise: invalid type: \" + type);\n\t\tif (this._type !== type) {\n\t\t\tthis._type = type;\n\t\t\t// if it's playing, stop and restart it\n\t\t\tif (this.state === \"started\") {\n\t\t\t\tconst now = this.now();\n\t\t\t\tthis._stop(now);\n\t\t\t\tthis._start(now);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * The playback rate of the noise. Affects\n\t * the \"frequency\" of the noise.\n\t */\n\tget playbackRate(): Positive {\n\t\treturn this._playbackRate;\n\t}\n\tset playbackRate(rate: Positive) {\n\t\tthis._playbackRate = rate;\n\t\tif (this._source) {\n\t\t\tthis._source.playbackRate.value = rate;\n\t\t}\n\t}\n\n\t/**\n\t * internal start method\n\t */\n\tprotected _start(time?: Time): void {\n\t\tconst buffer = _noiseBuffers[this._type];\n\t\tthis._source = new ToneBufferSource({\n\t\t\turl: buffer,\n\t\t\tcontext: this.context,\n\t\t\tfadeIn: this._fadeIn,\n\t\t\tfadeOut: this._fadeOut,\n\t\t\tloop: true,\n\t\t\tonended: () => this.onstop(this),\n\t\t\tplaybackRate: this._playbackRate,\n\t\t}).connect(this.output);\n\t\tthis._source.start(\n\t\t\tthis.toSeconds(time),\n\t\t\tMath.random() * (buffer.duration - 0.001)\n\t\t);\n\t}\n\n\t/**\n\t * internal stop method\n\t */\n\tprotected _stop(time?: Time): void {\n\t\tif (this._source) {\n\t\t\tthis._source.stop(this.toSeconds(time));\n\t\t\tthis._source = null;\n\t\t}\n\t}\n\n\t/**\n\t * The fadeIn time of the amplitude envelope.\n\t */\n\tget fadeIn(): Time {\n\t\treturn this._fadeIn;\n\t}\n\tset fadeIn(time) {\n\t\tthis._fadeIn = time;\n\t\tif (this._source) {\n\t\t\tthis._source.fadeIn = this._fadeIn;\n\t\t}\n\t}\n\n\t/**\n\t * The fadeOut time of the amplitude envelope.\n\t */\n\tget fadeOut(): Time {\n\t\treturn this._fadeOut;\n\t}\n\tset fadeOut(time) {\n\t\tthis._fadeOut = time;\n\t\tif (this._source) {\n\t\t\tthis._source.fadeOut = this._fadeOut;\n\t\t}\n\t}\n\n\tprotected _restart(time?: Time): void {\n\t\t// TODO could be optimized by cancelling the buffer source 'stop'\n\t\tthis._stop(time);\n\t\tthis._start(time);\n\t}\n\n\t/**\n\t * Clean up.\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tif (this._source) {\n\t\t\tthis._source.disconnect();\n\t\t}\n\t\treturn this;\n\t}\n}\n\n//--------------------\n// THE NOISE BUFFERS\n//--------------------\n\n// Noise buffer stats\nconst BUFFER_LENGTH = 44100 * 5;\nconst NUM_CHANNELS = 2;\n\n/**\n * The cached noise buffers\n */\ninterface NoiseCache {\n\t[key: string]: ToneAudioBuffer | null;\n}\n\n/**\n * Cache the noise buffers\n */\nconst _noiseCache: NoiseCache = {\n\tbrown: null,\n\tpink: null,\n\twhite: null,\n};\n\n/**\n * The noise arrays. Generated on initialization.\n * borrowed heavily from https://github.com/zacharydenton/noise.js\n * (c) 2013 Zach Denton (MIT)\n */\nconst _noiseBuffers = {\n\tget brown(): ToneAudioBuffer {\n\t\tif (!_noiseCache.brown) {\n\t\t\tconst buffer: Float32Array[] = [];\n\t\t\tfor (let channelNum = 0; channelNum < NUM_CHANNELS; channelNum++) {\n\t\t\t\tconst channel = new Float32Array(BUFFER_LENGTH);\n\t\t\t\tbuffer[channelNum] = channel;\n\t\t\t\tlet lastOut = 0.0;\n\t\t\t\tfor (let i = 0; i < BUFFER_LENGTH; i++) {\n\t\t\t\t\tconst white = Math.random() * 2 - 1;\n\t\t\t\t\tchannel[i] = (lastOut + 0.02 * white) / 1.02;\n\t\t\t\t\tlastOut = channel[i];\n\t\t\t\t\tchannel[i] *= 3.5; // (roughly) compensate for gain\n\t\t\t\t}\n\t\t\t}\n\t\t\t_noiseCache.brown = new ToneAudioBuffer().fromArray(buffer);\n\t\t}\n\t\treturn _noiseCache.brown;\n\t},\n\n\tget pink(): ToneAudioBuffer {\n\t\tif (!_noiseCache.pink) {\n\t\t\tconst buffer: Float32Array[] = [];\n\t\t\tfor (let channelNum = 0; channelNum < NUM_CHANNELS; channelNum++) {\n\t\t\t\tconst channel = new Float32Array(BUFFER_LENGTH);\n\t\t\t\tbuffer[channelNum] = channel;\n\t\t\t\tlet b0, b1, b2, b3, b4, b5, b6;\n\t\t\t\tb0 = b1 = b2 = b3 = b4 = b5 = b6 = 0.0;\n\t\t\t\tfor (let i = 0; i < BUFFER_LENGTH; i++) {\n\t\t\t\t\tconst white = Math.random() * 2 - 1;\n\t\t\t\t\tb0 = 0.99886 * b0 + white * 0.0555179;\n\t\t\t\t\tb1 = 0.99332 * b1 + white * 0.0750759;\n\t\t\t\t\tb2 = 0.969 * b2 + white * 0.153852;\n\t\t\t\t\tb3 = 0.8665 * b3 + white * 0.3104856;\n\t\t\t\t\tb4 = 0.55 * b4 + white * 0.5329522;\n\t\t\t\t\tb5 = -0.7616 * b5 - white * 0.016898;\n\t\t\t\t\tchannel[i] =\n\t\t\t\t\t\tb0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362;\n\t\t\t\t\tchannel[i] *= 0.11; // (roughly) compensate for gain\n\t\t\t\t\tb6 = white * 0.115926;\n\t\t\t\t}\n\t\t\t}\n\t\t\t_noiseCache.pink = new ToneAudioBuffer().fromArray(buffer);\n\t\t}\n\t\treturn _noiseCache.pink;\n\t},\n\n\tget white(): ToneAudioBuffer {\n\t\tif (!_noiseCache.white) {\n\t\t\tconst buffer: Float32Array[] = [];\n\t\t\tfor (let channelNum = 0; channelNum < NUM_CHANNELS; channelNum++) {\n\t\t\t\tconst channel = new Float32Array(BUFFER_LENGTH);\n\t\t\t\tbuffer[channelNum] = channel;\n\t\t\t\tfor (let i = 0; i < BUFFER_LENGTH; i++) {\n\t\t\t\t\tchannel[i] = Math.random() * 2 - 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\t_noiseCache.white = new ToneAudioBuffer().fromArray(buffer);\n\t\t}\n\t\treturn _noiseCache.white;\n\t},\n};\n"
  },
  {
    "path": "Tone/source/OneShotSource.ts",
    "content": "import { Gain } from \"../core/context/Gain.js\";\nimport {\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../core/context/ToneAudioNode.js\";\nimport { GainFactor, Seconds, Time } from \"../core/type/Units.js\";\nimport { assert } from \"../core/util/Debug.js\";\nimport { noOp } from \"../core/util/Interface.js\";\nimport { BasicPlaybackState } from \"../core/util/StateTimeline.js\";\n\nexport type OneShotSourceCurve = \"linear\" | \"exponential\";\n\ntype onEndedCallback = (source: OneShotSource<any>) => void;\n\nexport interface OneShotSourceOptions extends ToneAudioNodeOptions {\n\tonended: onEndedCallback;\n\tfadeIn: Time;\n\tfadeOut: Time;\n\tcurve: OneShotSourceCurve;\n}\n\n/**\n * Base class for fire-and-forget nodes\n */\nexport abstract class OneShotSource<\n\tOptions extends ToneAudioNodeOptions,\n> extends ToneAudioNode<Options> {\n\t/**\n\t * The callback to invoke after the\n\t * source is done playing.\n\t */\n\tonended: onEndedCallback = noOp;\n\n\t/**\n\t * Sources do not have input nodes\n\t */\n\tinput: undefined;\n\n\t/**\n\t * The start time\n\t */\n\tprotected _startTime = -1;\n\n\t/**\n\t * The stop time\n\t */\n\tprotected _stopTime = -1;\n\n\t/**\n\t * The id of the timeout\n\t */\n\tprivate _timeout = -1;\n\n\t/**\n\t * The public output node\n\t */\n\toutput: Gain = new Gain({\n\t\tcontext: this.context,\n\t\tgain: 0,\n\t});\n\n\t/**\n\t * The output gain node.\n\t */\n\tprotected _gainNode = this.output;\n\n\t/**\n\t * The fadeIn time of the amplitude envelope.\n\t */\n\tprotected _fadeIn: Time;\n\n\t/**\n\t * The fadeOut time of the amplitude envelope.\n\t */\n\tprotected _fadeOut: Time;\n\n\t/**\n\t * The curve applied to the fades, either \"linear\" or \"exponential\"\n\t */\n\tprotected _curve: OneShotSourceCurve;\n\n\tconstructor(options: OneShotSourceOptions) {\n\t\tsuper(options);\n\n\t\tthis._fadeIn = options.fadeIn;\n\t\tthis._fadeOut = options.fadeOut;\n\t\tthis._curve = options.curve;\n\t\tthis.onended = options.onended;\n\t}\n\n\tstatic getDefaults(): OneShotSourceOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tcurve: \"linear\" as OneShotSourceCurve,\n\t\t\tfadeIn: 0,\n\t\t\tfadeOut: 0,\n\t\t\tonended: noOp,\n\t\t});\n\t}\n\n\t/**\n\t * Stop the source node\n\t */\n\tprotected abstract _stopSource(time: Seconds): void;\n\n\t/**\n\t * Start the source node at the given time\n\t * @param  time When to start the node\n\t */\n\tprotected abstract start(time?: Time): this;\n\t/**\n\t * Start the source at the given time\n\t * @param  time When to start the source\n\t */\n\tprotected _startGain(time: Seconds, gain: GainFactor = 1): this {\n\t\tassert(\n\t\t\tthis._startTime === -1,\n\t\t\t\"Source cannot be started more than once\"\n\t\t);\n\t\t// apply a fade in envelope\n\t\tconst fadeInTime = this.toSeconds(this._fadeIn);\n\n\t\t// record the start time\n\t\tthis._startTime = time + fadeInTime;\n\t\tthis._startTime = Math.max(this._startTime, this.context.currentTime);\n\n\t\t// schedule the envelope\n\t\tif (fadeInTime > 0) {\n\t\t\tthis._gainNode.gain.setValueAtTime(0, time);\n\t\t\tif (this._curve === \"linear\") {\n\t\t\t\tthis._gainNode.gain.linearRampToValueAtTime(\n\t\t\t\t\tgain,\n\t\t\t\t\ttime + fadeInTime\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tthis._gainNode.gain.exponentialApproachValueAtTime(\n\t\t\t\t\tgain,\n\t\t\t\t\ttime,\n\t\t\t\t\tfadeInTime\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\tthis._gainNode.gain.setValueAtTime(gain, time);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop the source node at the given time.\n\t * @param time When to stop the source\n\t */\n\tstop(time?: Time): this {\n\t\tthis.log(\"stop\", time);\n\t\tthis._stopGain(this.toSeconds(time));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop the source at the given time\n\t * @param  time When to stop the source\n\t */\n\tprotected _stopGain(time: Seconds): this {\n\t\tassert(this._startTime !== -1, \"'start' must be called before 'stop'\");\n\t\t// cancel the previous stop\n\t\tthis.cancelStop();\n\n\t\t// the fadeOut time\n\t\tconst fadeOutTime = this.toSeconds(this._fadeOut);\n\n\t\t// schedule the stop callback\n\t\tthis._stopTime = this.toSeconds(time) + fadeOutTime;\n\t\tthis._stopTime = Math.max(this._stopTime, this.now());\n\t\tif (fadeOutTime > 0) {\n\t\t\t// start the fade out curve at the given time\n\t\t\tif (this._curve === \"linear\") {\n\t\t\t\tthis._gainNode.gain.linearRampTo(0, fadeOutTime, time);\n\t\t\t} else {\n\t\t\t\tthis._gainNode.gain.targetRampTo(0, fadeOutTime, time);\n\t\t\t}\n\t\t} else {\n\t\t\t// stop any ongoing ramps, and set the value to 0\n\t\t\tthis._gainNode.gain.cancelAndHoldAtTime(time);\n\t\t\tthis._gainNode.gain.setValueAtTime(0, time);\n\t\t}\n\t\tthis.context.clearTimeout(this._timeout);\n\t\tthis._timeout = this.context.setTimeout(() => {\n\t\t\t// allow additional time for the exponential curve to fully decay\n\t\t\tconst additionalTail =\n\t\t\t\tthis._curve === \"exponential\" ? fadeOutTime * 2 : 0;\n\t\t\tthis._stopSource(this.now() + additionalTail);\n\t\t\tthis._onended();\n\t\t}, this._stopTime - this.context.currentTime);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Invoke the onended callback\n\t */\n\tprotected _onended(): void {\n\t\tif (this.onended === noOp) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.onended(this);\n\t\t// overwrite onended to make sure it only is called once\n\t\tthis.onended = noOp;\n\t\t// dispose when it's ended to free up for garbage collection only in the online context\n\t\tif (!this.context.isOffline) {\n\t\t\tconst disposeCallback = () => this.dispose();\n\t\t\tif (typeof requestIdleCallback !== \"undefined\") {\n\t\t\t\trequestIdleCallback(disposeCallback);\n\t\t\t} else {\n\t\t\t\tsetTimeout(disposeCallback, 10);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Get the playback state at the given time\n\t */\n\tgetStateAtTime = function (time: Time): BasicPlaybackState {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tif (\n\t\t\tthis._startTime !== -1 &&\n\t\t\tcomputedTime >= this._startTime &&\n\t\t\t(this._stopTime === -1 || computedTime <= this._stopTime)\n\t\t) {\n\t\t\treturn \"started\";\n\t\t} else {\n\t\t\treturn \"stopped\";\n\t\t}\n\t};\n\n\t/**\n\t * Get the playback state at the current time\n\t */\n\tget state(): BasicPlaybackState {\n\t\treturn this.getStateAtTime(this.now());\n\t}\n\n\t/**\n\t * Cancel a scheduled stop event\n\t */\n\tcancelStop(): this {\n\t\tthis.log(\"cancelStop\");\n\t\tassert(this._startTime !== -1, \"Source is not started\");\n\t\t// cancel the stop envelope\n\t\tthis._gainNode.gain.cancelScheduledValues(\n\t\t\tthis._startTime + this.sampleTime\n\t\t);\n\t\tthis.context.clearTimeout(this._timeout);\n\t\tthis._stopTime = -1;\n\t\treturn this;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._gainNode.dispose();\n\t\tthis.onended = noOp;\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/source/Source.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { atTime, Offline } from \"../../test/helper/Offline.js\";\nimport { ToneAudioBuffer } from \"../core/context/ToneAudioBuffer.js\";\nimport { getContext } from \"../core/Global.js\";\nimport { Player } from \"./buffer/Player.js\";\nimport { Oscillator } from \"./oscillator/Oscillator.js\";\n\ndescribe(\"Source\", () => {\n\tit(\"can be started and stopped\", () => {\n\t\tconst source = new Oscillator();\n\t\tsource.start(0);\n\t\tsource.stop(1);\n\t\tsource.dispose();\n\t});\n\n\tit(\"can be constructed with an options object\", () => {\n\t\tconst source = new Oscillator({\n\t\t\tvolume: -20,\n\t\t});\n\t\texpect(source.volume.value).to.be.closeTo(-20, 0.1);\n\t\tsource.dispose();\n\t});\n\n\tit(\"can be muted in the constructor options\", () => {\n\t\tconst source = new Oscillator({\n\t\t\tmute: true,\n\t\t});\n\t\texpect(source.mute).to.be.true;\n\t\tsource.dispose();\n\t});\n\n\tit(\"can set the volume\", () => {\n\t\tconst source = new Oscillator();\n\t\tsource.volume.value = -8;\n\t\texpect(source.volume.value).to.be.closeTo(-8, 0.1);\n\t\tsource.dispose();\n\t});\n\n\tit(\"can mute and unmute the source\", () => {\n\t\tconst source = new Oscillator();\n\t\tsource.volume.value = -8;\n\t\tsource.mute = true;\n\t\texpect(source.mute).to.be.true;\n\t\texpect(source.volume.value).to.equal(-Infinity);\n\t\tsource.mute = false;\n\t\t// returns the volume to what it was\n\t\texpect(source.volume.value).to.be.closeTo(-8, 0.1);\n\t\tsource.dispose();\n\t});\n\n\tit(\"can get and set values with an object\", () => {\n\t\tconst source = new Oscillator();\n\t\tsource.set({ volume: -10 });\n\t\texpect(source.get().volume).to.be.closeTo(-10, 0.1);\n\t\tsource.dispose();\n\t});\n\n\tit(\"is initially stopped\", () => {\n\t\tconst source = new Oscillator();\n\t\texpect(source.state).to.equal(\"stopped\");\n\t\tsource.dispose();\n\t});\n\n\tit(\"cannot be scheduled to stop/start twice in a row\", () => {\n\t\treturn Offline(() => {\n\t\t\tconst source = new Oscillator();\n\t\t\tsource.start(0).start(1);\n\t\t\tsource.stop(2).stop(3);\n\t\t\tsource.dispose();\n\t\t});\n\t});\n\n\tit(\"can be scheduled with multiple starts/stops\", () => {\n\t\treturn Offline(() => {\n\t\t\tconst source = new Oscillator();\n\t\t\tsource.start(0).stop(0.5).start(0.75).stop(1).start(1.25).stop(1.5);\n\t\t\treturn [\n\t\t\t\tatTime(0.1, () => {\n\t\t\t\t\texpect(source.state).to.equal(\"started\");\n\t\t\t\t}),\n\t\t\t\tatTime(0.5, () => {\n\t\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\t\t}),\n\t\t\t\tatTime(0.8, () => {\n\t\t\t\t\texpect(source.state).to.equal(\"started\");\n\t\t\t\t}),\n\t\t\t\tatTime(1, () => {\n\t\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\t\t}),\n\t\t\t\tatTime(1.25, () => {\n\t\t\t\t\texpect(source.state).to.equal(\"started\");\n\t\t\t\t}),\n\t\t\t\tatTime(1.6, () => {\n\t\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\t\t}),\n\t\t\t];\n\t\t}, 2);\n\t});\n\n\tit(\"clamps start time to the currentTime\", (done) => {\n\t\tconst source = new Oscillator();\n\t\texpect(source.state).to.equal(\"stopped\");\n\t\tsource.start(0);\n\t\tsetTimeout(() => {\n\t\t\texpect(source.state).to.equal(\"started\");\n\t\t\tsource.dispose();\n\t\t\tdone();\n\t\t}, 10);\n\t});\n\n\tit(\"clamps stop time to the currentTime\", (done) => {\n\t\tconst source = new Oscillator();\n\t\texpect(source.state).to.equal(\"stopped\");\n\t\tsource.start(0);\n\t\tsetTimeout(() => {\n\t\t\texpect(source.state).to.equal(\"started\");\n\t\t\tsource.stop(0);\n\t\t\tsetTimeout(() => {\n\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\t\tsource.dispose();\n\t\t\t\tdone();\n\t\t\t}, 10);\n\t\t}, 10);\n\t});\n\n\tit(\"correctly returns the scheduled play state\", () => {\n\t\treturn Offline(() => {\n\t\t\tconst source = new Oscillator();\n\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\tsource.start(0).stop(0.5);\n\n\t\t\treturn (time) => {\n\t\t\t\tif (time >= 0 && time < 0.5) {\n\t\t\t\t\texpect(source.state).to.equal(\"started\");\n\t\t\t\t} else if (time > 0.5) {\n\t\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\t\t}\n\t\t\t};\n\t\t}, 0.6);\n\t});\n\n\tit(\"start needs to be greater than the previous start time\", () => {\n\t\treturn Offline(() => {\n\t\t\tconst source = new Oscillator();\n\t\t\tsource.start(0);\n\t\t\texpect(() => {\n\t\t\t\tsource.start(0);\n\t\t\t}).to.throw(Error);\n\t\t\tsource.dispose();\n\t\t});\n\t});\n\n\tcontext(\"sync\", () => {\n\t\tconst ramp = new Float32Array(getContext().sampleRate);\n\t\tramp.forEach((val, index) => {\n\t\t\tramp[index] = index / getContext().sampleRate;\n\t\t});\n\t\tconst rampBuffer = ToneAudioBuffer.fromArray(ramp);\n\n\t\tit(\"can sync its start to the transport\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst source = new Oscillator();\n\t\t\t\tsource.sync().start(0);\n\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\t\ttransport.start(source.now());\n\t\t\t\texpect(source.state).to.equal(\"started\");\n\t\t\t\tsource.dispose();\n\t\t\t\ttransport.stop();\n\t\t\t});\n\t\t});\n\n\t\tit(\"calling sync multiple times has no affect\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst source = new Oscillator();\n\t\t\t\tsource.sync().sync().start(0);\n\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\t\ttransport.start(source.now());\n\t\t\t\texpect(source.state).to.equal(\"started\");\n\t\t\t\tsource.dispose();\n\t\t\t\ttransport.stop();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can unsync after it was synced\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst source = new Oscillator();\n\t\t\t\tsource.sync().start(0);\n\t\t\t\tsource.unsync();\n\t\t\t\ttransport.start();\n\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\t});\n\t\t});\n\n\t\tit(\"calling unsync multiple times has no affect\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst source = new Oscillator();\n\t\t\t\tsource.sync().start(0);\n\t\t\t\tsource.unsync().unsync();\n\t\t\t\ttransport.start();\n\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\t});\n\t\t});\n\n\t\tit(\"can sync its stop to the transport\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst source = new Oscillator();\n\t\t\t\tsource.sync().start(0);\n\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\t\ttransport.start(0).stop(0.4);\n\t\t\t\texpect(source.state).to.equal(\"started\");\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time > 0.4) {\n\t\t\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.5);\n\t\t});\n\n\t\tit(\"can schedule multiple starts/stops\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst source = new Oscillator();\n\t\t\t\tsource.sync().start(0.1).stop(0.2).start(0.3);\n\t\t\t\ttransport.start(0).stop(0.4);\n\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time > 0.1 && time < 0.19) {\n\t\t\t\t\t\texpect(source.state).to.equal(\"started\");\n\t\t\t\t\t} else if (time > 0.2 && time < 0.29) {\n\t\t\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\t\t\t} else if (time > 0.3 && time < 0.39) {\n\t\t\t\t\t\texpect(source.state).to.equal(\"started\");\n\t\t\t\t\t} else if (time > 0.4) {\n\t\t\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.6);\n\t\t});\n\n\t\tit.skip(\"can sync schedule multiple starts\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst buff = ToneAudioBuffer.fromArray(\n\t\t\t\t\tnew Float32Array(1024).map((v) => 1)\n\t\t\t\t);\n\t\t\t\tconst source = new Player(buff);\n\t\t\t\tsource.sync().start(0.1).start(0.3);\n\t\t\t\ttransport.start(0);\n\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\n\t\t\t\treturn [\n\t\t\t\t\tatTime(0.11, () => {\n\t\t\t\t\t\texpect(source.state).to.equal(\"started\");\n\t\t\t\t\t}),\n\t\t\t\t\tatTime(0.31, () => {\n\t\t\t\t\t\texpect(source.state).to.equal(\"started\");\n\t\t\t\t\t}),\n\t\t\t\t];\n\t\t\t}, 0.6);\n\t\t});\n\n\t\tit(\"has correct offset when the transport is started with an offset\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst source = new Oscillator();\n\t\t\t\tsource.sync().start(0.3).stop(0.4);\n\t\t\t\ttransport.start(0, 0.1);\n\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time > 0.21 && time < 0.29) {\n\t\t\t\t\t\texpect(source.state).to.equal(\"started\");\n\t\t\t\t\t} else if (time > 0.31) {\n\t\t\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.5);\n\t\t});\n\n\t\tit(\"can start with an offset after the start time of the source\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst source = new Oscillator();\n\t\t\t\tsource.sync().start(0);\n\t\t\t\ttransport.start(0, 0.1);\n\t\t\t\texpect(source.state).to.equal(\"started\");\n\t\t\t\tsource.dispose();\n\t\t\t}, 0.1);\n\t\t});\n\n\t\tit(\"can sync its start to the transport after a delay\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst source = new Oscillator();\n\t\t\t\tsource.sync().start(0.3);\n\t\t\t\ttransport.start(0).stop(0.4);\n\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time > 0.3 && time < 0.39) {\n\t\t\t\t\t\texpect(source.state).to.equal(\"started\");\n\t\t\t\t\t} else if (time > 0.4) {\n\t\t\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.6);\n\t\t});\n\n\t\tit(\"correct state when the transport position is changed\", () => {\n\t\t\treturn Offline(({ transport }) => {\n\t\t\t\tconst source = new Oscillator();\n\t\t\t\tsource.sync().start(0.3).stop(0.4);\n\t\t\t\ttransport.start(0).stop(0.4);\n\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\t\ttransport.seconds = 0.305;\n\t\t\t\texpect(source.state).to.equal(\"started\");\n\t\t\t\ttransport.seconds = 0.405;\n\t\t\t\treturn atTime(0.01, () => {\n\t\t\t\t\texpect(source.state).to.equal(\"stopped\");\n\t\t\t\t});\n\t\t\t}, 0.1);\n\t\t});\n\n\t\tit(\"gives the correct offset on time on start/stop events\", async () => {\n\t\t\tconst output = await Offline(({ transport }) => {\n\t\t\t\tconst source = new Player(rampBuffer).toDestination();\n\t\t\t\tsource.sync().start(0.2, 0.1).stop(0.3);\n\t\t\t\ttransport.start(0.2);\n\t\t\t}, 0.7);\n\t\t\texpect(output.getValueAtTime(0.41)).to.be.closeTo(0.1, 0.01);\n\t\t\texpect(output.getValueAtTime(0.45)).to.be.closeTo(0.15, 0.001);\n\t\t\texpect(output.getValueAtTime(0.5)).to.be.equal(0);\n\t\t});\n\n\t\tit(\"gives the correct offset on time on start/stop events when started with an offset\", async () => {\n\t\t\tconst output = await Offline(({ transport }) => {\n\t\t\t\tconst source = new Player(rampBuffer).toDestination();\n\t\t\t\tsource.sync().start(0.2, 0.1).stop(0.4);\n\t\t\t\ttransport.start(0.2, 0.1);\n\t\t\t}, 0.7);\n\t\t\texpect(output.getValueAtTime(0.21)).to.be.closeTo(0.0, 0.01);\n\t\t\texpect(output.getValueAtTime(0.31)).to.be.closeTo(0.1, 0.01);\n\t\t\texpect(output.getValueAtTime(0.41)).to.be.closeTo(0.2, 0.01);\n\t\t\texpect(output.getValueAtTime(0.45)).to.be.closeTo(0.25, 0.01);\n\t\t\texpect(output.getValueAtTime(0.51)).to.be.equal(0);\n\t\t});\n\n\t\tit(\"gives the correct offset on time on start/stop events invoked with a transport offset that's in the middle of the event\", async () => {\n\t\t\tconst output = await Offline(({ transport }) => {\n\t\t\t\tconst source = new Player(rampBuffer).toDestination();\n\t\t\t\tsource.sync().start(0.2, 0.1).stop(0.4);\n\t\t\t\ttransport.start(0, 0.3);\n\t\t\t}, 0.7);\n\t\t\texpect(output.getValueAtTime(0.01)).to.be.closeTo(0.2, 0.01);\n\t\t\texpect(output.getValueAtTime(0.05)).to.be.closeTo(0.25, 0.01);\n\t\t\texpect(output.getValueAtTime(0.11)).to.be.equal(0);\n\t\t});\n\n\t\tit(\"gives the correct duration when invoked with a transport offset that's in the middle of the event\", async () => {\n\t\t\tconst output = await Offline(({ transport }) => {\n\t\t\t\tconst source = new Player(rampBuffer).toDestination();\n\t\t\t\tsource.sync().start(0.2, 0.1, 0.3);\n\t\t\t\ttransport.start(0, 0.3);\n\t\t\t}, 0.7);\n\t\t\texpect(output.getValueAtTime(0.01)).to.be.closeTo(0.2, 0.01);\n\t\t\texpect(output.getValueAtTime(0.1)).to.be.closeTo(0.3, 0.01);\n\t\t\texpect(output.getValueAtTime(0.199)).to.be.closeTo(0.4, 0.01);\n\t\t\texpect(output.getValueAtTime(0.31)).to.be.equal(0);\n\t\t});\n\n\t\tit(\"stops at the right time when transport.stop is invoked before the scheduled stop\", async () => {\n\t\t\tconst output = await Offline(({ transport }) => {\n\t\t\t\tconst source = new Player(rampBuffer).toDestination();\n\t\t\t\tsource.sync().start(0.2).stop(0.4);\n\t\t\t\ttransport.start(0).stop(0.3);\n\t\t\t}, 0.7);\n\t\t\texpect(output.getValueAtTime(0.2)).to.be.closeTo(0.0, 0.01);\n\t\t\texpect(output.getValueAtTime(0.25)).to.be.closeTo(0.05, 0.01);\n\t\t\texpect(output.getValueAtTime(0.31)).to.be.equal(0);\n\t\t});\n\n\t\tit(\"invokes the right methods and offsets when the transport is seeked\", async () => {\n\t\t\tconst output = await Offline(({ transport }) => {\n\t\t\t\tconst source = new Player(rampBuffer).toDestination();\n\t\t\t\tsource.sync().start(0.2);\n\t\t\t\ttransport.start(0, 0.3);\n\n\t\t\t\treturn atTime(0.1, () => {\n\t\t\t\t\t// seek forward in time\n\t\t\t\t\ttransport.seconds = 0.1;\n\t\t\t\t});\n\t\t\t}, 0.7);\n\t\t\texpect(output.getValueAtTime(0.01)).to.be.closeTo(0.1, 0.01);\n\t\t\texpect(output.getValueAtTime(0.05)).to.be.closeTo(0.15, 0.01);\n\t\t\texpect(output.getValueAtTime(0.11)).to.be.closeTo(0.0, 0.01);\n\t\t\texpect(output.getValueAtTime(0.21)).to.be.closeTo(0.0, 0.01);\n\t\t\texpect(output.getValueAtTime(0.25)).to.be.closeTo(0.05, 0.01);\n\t\t\texpect(output.getValueAtTime(0.3)).to.be.closeTo(0.1, 0.01);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/source/Source.ts",
    "content": "import \"../core/context/Destination.js\";\nimport \"../core/clock/Transport.js\";\n\nimport { Volume } from \"../component/channel/Volume.js\";\nimport { Param } from \"../core/context/Param.js\";\nimport {\n\tOutputNode,\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../core/context/ToneAudioNode.js\";\nimport { Decibels, Seconds, Time } from \"../core/type/Units.js\";\nimport { assert, assertContextRunning } from \"../core/util/Debug.js\";\nimport { defaultArg } from \"../core/util/Defaults.js\";\nimport { noOp, readOnly } from \"../core/util/Interface.js\";\nimport { GT } from \"../core/util/Math.js\";\nimport {\n\tBasicPlaybackState,\n\tStateTimeline,\n\tStateTimelineEvent,\n} from \"../core/util/StateTimeline.js\";\nimport { isDefined, isUndef } from \"../core/util/TypeCheck.js\";\n\ntype onStopCallback = (source: Source<any>) => void;\n\nexport interface SourceOptions extends ToneAudioNodeOptions {\n\tvolume: Decibels;\n\tmute: boolean;\n\tonstop: onStopCallback;\n}\n\n/**\n * Base class for sources.\n * start/stop of this.context.transport.\n *\n * ```\n * // Multiple state change events can be chained together,\n * // but must be set in the correct order and with ascending times\n * // OK\n * state.start().stop(\"+0.2\");\n * // OK\n * state.start().stop(\"+0.2\").start(\"+0.4\").stop(\"+0.7\")\n * // BAD\n * state.stop(\"+0.2\").start();\n * // BAD\n * state.start(\"+0.3\").stop(\"+0.2\");\n * ```\n */\nexport abstract class Source<\n\tOptions extends SourceOptions,\n> extends ToneAudioNode<Options> {\n\t/**\n\t * The output volume node\n\t */\n\tprivate _volume: Volume;\n\n\t/**\n\t * The output node\n\t */\n\toutput: OutputNode;\n\n\t/**\n\t * Sources have no inputs\n\t */\n\tinput = undefined;\n\n\t/**\n\t * The volume of the output in decibels.\n\t * @example\n\t * const source = new Tone.PWMOscillator().toDestination();\n\t * source.volume.value = -6;\n\t */\n\tvolume: Param<\"decibels\">;\n\n\t/**\n\t * The callback to invoke when the source is stopped.\n\t */\n\tonstop: onStopCallback;\n\n\t/**\n\t * Keep track of the scheduled state.\n\t */\n\tprotected _state: StateTimeline<{\n\t\tduration?: Seconds;\n\t\toffset?: Seconds;\n\t\t/**\n\t\t * Either the buffer is explicitly scheduled to end using the stop method,\n\t\t * or its implicitly ended when the buffer is over.\n\t\t */\n\t\timplicitEnd?: boolean;\n\t}> = new StateTimeline(\"stopped\");\n\n\t/**\n\t * The synced `start` callback function from the transport\n\t */\n\tprotected _synced = false;\n\n\t/**\n\t * Keep track of all of the scheduled event ids\n\t */\n\tprivate _scheduled: number[] = [];\n\n\t/**\n\t * Placeholder functions for syncing/unsyncing to transport\n\t */\n\tprivate _syncedStart: (time: Seconds, offset: Seconds) => void = noOp;\n\tprivate _syncedStop: (time: Seconds) => void = noOp;\n\n\tconstructor(options: SourceOptions) {\n\t\tsuper(options);\n\t\tthis._state.memory = 100;\n\t\tthis._state.increasing = true;\n\n\t\tthis._volume = this.output = new Volume({\n\t\t\tcontext: this.context,\n\t\t\tmute: options.mute,\n\t\t\tvolume: options.volume,\n\t\t});\n\t\tthis.volume = this._volume.volume;\n\t\treadOnly(this, \"volume\");\n\t\tthis.onstop = options.onstop;\n\t}\n\n\tstatic getDefaults(): SourceOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tmute: false,\n\t\t\tonstop: noOp,\n\t\t\tvolume: 0,\n\t\t});\n\t}\n\n\t/**\n\t * Returns the playback state of the source, either \"started\" or \"stopped\".\n\t * @example\n\t * const player = new Tone.Player(\"https://tonejs.github.io/audio/berklee/ahntone_c3.mp3\", () => {\n\t * \tplayer.start();\n\t * \tconsole.log(player.state);\n\t * }).toDestination();\n\t */\n\tget state(): BasicPlaybackState {\n\t\tif (this._synced) {\n\t\t\tif (this.context.transport.state === \"started\") {\n\t\t\t\treturn this._state.getValueAtTime(\n\t\t\t\t\tthis.context.transport.seconds\n\t\t\t\t) as BasicPlaybackState;\n\t\t\t} else {\n\t\t\t\treturn \"stopped\";\n\t\t\t}\n\t\t} else {\n\t\t\treturn this._state.getValueAtTime(this.now()) as BasicPlaybackState;\n\t\t}\n\t}\n\n\t/**\n\t * Mute the output.\n\t * @example\n\t * const osc = new Tone.Oscillator().toDestination().start();\n\t * // mute the output\n\t * osc.mute = true;\n\t */\n\tget mute(): boolean {\n\t\treturn this._volume.mute;\n\t}\n\tset mute(mute: boolean) {\n\t\tthis._volume.mute = mute;\n\t}\n\n\t// overwrite these functions\n\tprotected abstract _start(time: Time, offset?: Time, duration?: Time): void;\n\tprotected abstract _stop(time: Time): void;\n\tprotected abstract _restart(\n\t\ttime: Seconds,\n\t\toffset?: Time,\n\t\tduration?: Time\n\t): void;\n\n\t/**\n\t * Ensure that the scheduled time is not before the current time.\n\t * Should only be used when scheduled unsynced.\n\t */\n\tprivate _clampToCurrentTime(time: Seconds): Seconds {\n\t\tif (this._synced) {\n\t\t\treturn time;\n\t\t} else {\n\t\t\treturn Math.max(time, this.context.currentTime);\n\t\t}\n\t}\n\n\t/**\n\t * Start the source at the specified time. If no time is given,\n\t * start the source now.\n\t * @param  time When the source should be started.\n\t * @example\n\t * const source = new Tone.Oscillator().toDestination();\n\t * source.start(\"+0.5\"); // starts the source 0.5 seconds from now\n\t */\n\tstart(time?: Time, offset?: Time, duration?: Time): this {\n\t\tlet computedTime =\n\t\t\tisUndef(time) && this._synced\n\t\t\t\t? this.context.transport.seconds\n\t\t\t\t: this.toSeconds(time);\n\t\tcomputedTime = this._clampToCurrentTime(computedTime);\n\t\t// if it's started, stop it and restart it\n\t\tif (\n\t\t\t!this._synced &&\n\t\t\tthis._state.getValueAtTime(computedTime) === \"started\"\n\t\t) {\n\t\t\t// time should be strictly greater than the previous start time\n\t\t\tassert(\n\t\t\t\tGT(\n\t\t\t\t\tcomputedTime,\n\t\t\t\t\t(this._state.get(computedTime) as StateTimelineEvent).time\n\t\t\t\t),\n\t\t\t\t\"Start time must be strictly greater than previous start time\"\n\t\t\t);\n\t\t\tthis._state.cancel(computedTime);\n\t\t\tthis._state.setStateAtTime(\"started\", computedTime);\n\t\t\tthis.log(\"restart\", computedTime);\n\t\t\tthis.restart(computedTime, offset, duration);\n\t\t} else {\n\t\t\tthis._state.setStateAtTime(\"started\", computedTime);\n\t\t\tif (this._synced) {\n\t\t\t\t// add the offset time to the event\n\t\t\t\tconst event = this._state.get(computedTime);\n\t\t\t\tif (event) {\n\t\t\t\t\tevent.offset = this.toSeconds(defaultArg(offset, 0));\n\t\t\t\t\tevent.duration = duration\n\t\t\t\t\t\t? this.toSeconds(duration)\n\t\t\t\t\t\t: undefined;\n\t\t\t\t}\n\t\t\t\tconst sched = this.context.transport.schedule((t) => {\n\t\t\t\t\tthis._start(t, offset, duration);\n\t\t\t\t}, computedTime);\n\t\t\t\tthis._scheduled.push(sched);\n\n\t\t\t\t// if the transport is already started\n\t\t\t\t// and the time is greater than where the transport is\n\t\t\t\tif (\n\t\t\t\t\tthis.context.transport.state === \"started\" &&\n\t\t\t\t\tthis.context.transport.getSecondsAtTime(this.immediate()) >\n\t\t\t\t\t\tcomputedTime\n\t\t\t\t) {\n\t\t\t\t\tthis._syncedStart(\n\t\t\t\t\t\tthis.now(),\n\t\t\t\t\t\tthis.context.transport.seconds\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tassertContextRunning(this.context);\n\t\t\t\tthis._start(computedTime, offset, duration);\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop the source at the specified time. If no time is given,\n\t * stop the source now.\n\t * @param  time When the source should be stopped.\n\t * @example\n\t * const source = new Tone.Oscillator().toDestination();\n\t * source.start();\n\t * source.stop(\"+0.5\"); // stops the source 0.5 seconds from now\n\t */\n\tstop(time?: Time): this {\n\t\tlet computedTime =\n\t\t\tisUndef(time) && this._synced\n\t\t\t\t? this.context.transport.seconds\n\t\t\t\t: this.toSeconds(time);\n\t\tcomputedTime = this._clampToCurrentTime(computedTime);\n\t\tif (\n\t\t\tthis._state.getValueAtTime(computedTime) === \"started\" ||\n\t\t\tisDefined(this._state.getNextState(\"started\", computedTime))\n\t\t) {\n\t\t\tthis.log(\"stop\", computedTime);\n\t\t\tif (!this._synced) {\n\t\t\t\tthis._stop(computedTime);\n\t\t\t} else {\n\t\t\t\tconst sched = this.context.transport.schedule(\n\t\t\t\t\tthis._stop.bind(this),\n\t\t\t\t\tcomputedTime\n\t\t\t\t);\n\t\t\t\tthis._scheduled.push(sched);\n\t\t\t}\n\t\t\tthis._state.cancel(computedTime);\n\t\t\tthis._state.setStateAtTime(\"stopped\", computedTime);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Restart the source.\n\t */\n\trestart(time?: Time, offset?: Time, duration?: Time): this {\n\t\ttime = this.toSeconds(time);\n\t\tif (this._state.getValueAtTime(time) === \"started\") {\n\t\t\tthis._state.cancel(time);\n\t\t\tthis._restart(time, offset, duration);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sync the source to the Transport so that all subsequent\n\t * calls to `start` and `stop` are synced to the TransportTime\n\t * instead of the AudioContext time.\n\t *\n\t * @example\n\t * const osc = new Tone.Oscillator().toDestination();\n\t * // sync the source so that it plays between 0 and 0.3 on the Transport's timeline\n\t * osc.sync().start(0).stop(0.3);\n\t * // start the transport.\n\t * Tone.Transport.start();\n\t * // set it to loop once a second\n\t * Tone.Transport.loop = true;\n\t * Tone.Transport.loopEnd = 1;\n\t */\n\tsync(): this {\n\t\tif (!this._synced) {\n\t\t\tthis._synced = true;\n\t\t\tthis._syncedStart = (time, offset) => {\n\t\t\t\tif (GT(offset, 0)) {\n\t\t\t\t\t// get the playback state at that time\n\t\t\t\t\tconst stateEvent = this._state.get(offset);\n\t\t\t\t\t// listen for start events which may occur in the middle of the sync'ed time\n\t\t\t\t\tif (\n\t\t\t\t\t\tstateEvent &&\n\t\t\t\t\t\tstateEvent.state === \"started\" &&\n\t\t\t\t\t\tstateEvent.time !== offset\n\t\t\t\t\t) {\n\t\t\t\t\t\t// get the offset\n\t\t\t\t\t\tconst startOffset =\n\t\t\t\t\t\t\toffset - this.toSeconds(stateEvent.time);\n\t\t\t\t\t\tlet duration: number | undefined;\n\t\t\t\t\t\tif (stateEvent.duration) {\n\t\t\t\t\t\t\tduration =\n\t\t\t\t\t\t\t\tthis.toSeconds(stateEvent.duration) -\n\t\t\t\t\t\t\t\tstartOffset;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis._start(\n\t\t\t\t\t\t\ttime,\n\t\t\t\t\t\t\tthis.toSeconds(stateEvent.offset) + startOffset,\n\t\t\t\t\t\t\tduration\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t\tthis._syncedStop = (time) => {\n\t\t\t\tconst seconds = this.context.transport.getSecondsAtTime(\n\t\t\t\t\tMath.max(time - this.sampleTime, 0)\n\t\t\t\t);\n\t\t\t\tif (this._state.getValueAtTime(seconds) === \"started\") {\n\t\t\t\t\tthis._stop(time);\n\t\t\t\t}\n\t\t\t};\n\t\t\tthis.context.transport.on(\"start\", this._syncedStart);\n\t\t\tthis.context.transport.on(\"loopStart\", this._syncedStart);\n\t\t\tthis.context.transport.on(\"stop\", this._syncedStop);\n\t\t\tthis.context.transport.on(\"pause\", this._syncedStop);\n\t\t\tthis.context.transport.on(\"loopEnd\", this._syncedStop);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Unsync the source to the Transport.\n\t * @see {@link sync}\n\t */\n\tunsync(): this {\n\t\tif (this._synced) {\n\t\t\tthis.context.transport.off(\"stop\", this._syncedStop);\n\t\t\tthis.context.transport.off(\"pause\", this._syncedStop);\n\t\t\tthis.context.transport.off(\"loopEnd\", this._syncedStop);\n\t\t\tthis.context.transport.off(\"start\", this._syncedStart);\n\t\t\tthis.context.transport.off(\"loopStart\", this._syncedStart);\n\t\t}\n\t\tthis._synced = false;\n\t\t// clear all of the scheduled ids\n\t\tthis._scheduled.forEach((id) => this.context.transport.clear(id));\n\t\tthis._scheduled = [];\n\t\tthis._state.cancel(0);\n\t\t// stop it also\n\t\tthis._stop(0);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clean up.\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.onstop = noOp;\n\t\tthis.unsync();\n\t\tthis._volume.dispose();\n\t\tthis._state.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/source/UserMedia.test.ts",
    "content": "import { expect, use } from \"chai\";\nimport sinon from \"sinon\";\nimport sinonChai from \"sinon-chai\";\nuse(sinonChai);\n\nimport { BasicTests } from \"../../test/helper/Basic.js\";\nimport { Context } from \"../core/context/Context.js\";\nimport { OfflineContext } from \"../core/context/OfflineContext.js\";\nimport { UserMedia } from \"./UserMedia.js\";\n\ndescribe(\"UserMedia\", () => {\n\t// run the common tests\n\tBasicTests(UserMedia);\n\n\tcontext(\"Source Tests\", () => {\n\t\tit(\"can be constructed with the input number\", () => {\n\t\t\tconst extIn = new UserMedia();\n\t\t\textIn.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an options object\", () => {\n\t\t\tconst extIn = new UserMedia({\n\t\t\t\tvolume: -10,\n\t\t\t\tmute: false,\n\t\t\t});\n\t\t\texpect(extIn.volume.value).to.be.closeTo(-10, 0.1);\n\t\t\texpect(extIn.mute).to.be.false;\n\t\t\textIn.dispose();\n\t\t});\n\n\t\tit(\"properties return undefined before open\", () => {\n\t\t\tconst extIn = new UserMedia();\n\t\t\texpect(extIn.deviceId).to.be.undefined;\n\t\t\texpect(extIn.groupId).to.be.undefined;\n\t\t\texpect(extIn.label).to.be.undefined;\n\t\t\textIn.dispose();\n\t\t});\n\n\t\tit(\"indicates if the browser has UserMedia support\", () => {\n\t\t\texpect(UserMedia.supported).to.be.a(\"boolean\");\n\t\t});\n\t});\n\n\tcontext(\"Opening and closing\", () => {\n\t\tbeforeEach(() => {\n\t\t\tconst mockTrack = { stop: sinon.stub() };\n\t\t\tconst mockStream = {\n\t\t\t\tactive: true,\n\t\t\t\tgetAudioTracks: () => [mockTrack],\n\t\t\t} as unknown as MediaStream;\n\t\t\tconst mockMediaStreamSource = {\n\t\t\t\tconnect: sinon.stub(),\n\t\t\t\tdisconnect: sinon.stub(),\n\t\t\t\tnumberOfOutputs: 1,\n\t\t\t} as unknown as MediaStreamAudioSourceNode;\n\t\t\tsinon.stub(UserMedia, \"enumerateDevices\").resolves([\n\t\t\t\t{\n\t\t\t\t\tdeviceId: \"default\",\n\t\t\t\t\tgroupId: \"default\",\n\t\t\t\t\tlabel: \"Default Device\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdeviceId: \"other\",\n\t\t\t\t\tgroupId: \"default\",\n\t\t\t\t\tlabel: \"Other Device\",\n\t\t\t\t},\n\t\t\t] as MediaDeviceInfo[]);\n\t\t\tsinon\n\t\t\t\t.stub(navigator.mediaDevices, \"getUserMedia\")\n\t\t\t\t.resolves(mockStream);\n\t\t\tsinon\n\t\t\t\t.stub(Context.prototype, \"createMediaStreamSource\")\n\t\t\t\t.returns(mockMediaStreamSource);\n\t\t});\n\n\t\tafterEach(() => {\n\t\t\tsinon.restore();\n\t\t});\n\n\t\tit(\"open returns a promise\", async () => {\n\t\t\tconst extIn = new UserMedia();\n\t\t\tconst promise = extIn.open();\n\t\t\texpect(promise).to.be.instanceOf(Promise);\n\t\t\tawait promise;\n\t\t\textIn.dispose();\n\t\t});\n\n\t\tit(\"can open an input\", async () => {\n\t\t\tconst extIn = new UserMedia();\n\t\t\tawait extIn.open();\n\t\t\textIn.dispose();\n\t\t});\n\n\t\tit(\"can open an input by name\", async () => {\n\t\t\tconst extIn = new UserMedia();\n\t\t\tconst devices = await UserMedia.enumerateDevices();\n\t\t\tconst name = devices[0].deviceId;\n\n\t\t\tawait extIn.open(name);\n\n\t\t\texpect(extIn.deviceId).to.equal(name);\n\t\t\texpect(navigator.mediaDevices.getUserMedia).to.have.been.calledWith(\n\t\t\t\tsinon.match.hasNested(\"audio.deviceId\", name)\n\t\t\t);\n\t\t\textIn.dispose();\n\t\t});\n\n\t\tit(\"can open an input by index\", async () => {\n\t\t\tconst extIn = new UserMedia();\n\n\t\t\tawait extIn.open(0);\n\n\t\t\texpect(navigator.mediaDevices.getUserMedia).to.have.been.calledWith(\n\t\t\t\tsinon.match.hasNested(\"audio.deviceId\", \"default\")\n\t\t\t);\n\t\t\textIn.dispose();\n\t\t});\n\n\t\tit(\"can pass in additional constraints\", async () => {\n\t\t\tconst extIn = new UserMedia();\n\t\t\tawait extIn.open({\n\t\t\t\tpreferCurrentTab: true,\n\t\t\t});\n\t\t\texpect(navigator.mediaDevices.getUserMedia).to.have.been.calledWith(\n\t\t\t\tsinon.match.hasNested(\"preferCurrentTab\", true)\n\t\t\t);\n\t\t\textIn.dispose();\n\t\t});\n\n\t\tit(\"throws an error if it cant find the device name\", async () => {\n\t\t\tconst extIn = new UserMedia();\n\t\t\ttry {\n\t\t\t\tawait extIn.open(\"doesn't exist\");\n\t\t\t\tthrow new Error(\"shouldn't reach here\");\n\t\t\t} catch {\n\t\t\t\textIn.dispose();\n\t\t\t}\n\t\t});\n\n\t\tit(\"is 'started' after media is open and 'stopped' otherwise\", async () => {\n\t\t\tconst extIn = new UserMedia();\n\t\t\texpect(extIn.state).to.equal(\"stopped\");\n\n\t\t\tawait extIn.open();\n\n\t\t\texpect(extIn.state).to.equal(\"started\");\n\t\t\textIn.dispose();\n\t\t});\n\n\t\tit(\"has a label, group and device id when open\", async () => {\n\t\t\tconst extIn = new UserMedia();\n\t\t\texpect(extIn.deviceId).to.be.undefined;\n\t\t\texpect(extIn.groupId).to.be.undefined;\n\t\t\texpect(extIn.label).to.be.undefined;\n\n\t\t\tawait extIn.open();\n\n\t\t\texpect(extIn.deviceId).to.be.a(\"string\");\n\t\t\texpect(extIn.groupId).to.be.a(\"string\");\n\t\t\texpect(extIn.label).to.be.a(\"string\");\n\t\t\textIn.dispose();\n\t\t});\n\n\t\tit(\"can reopen an input\", async () => {\n\t\t\tconst extIn = new UserMedia();\n\t\t\tawait extIn.open();\n\t\t\textIn.close();\n\t\t\tawait extIn.open();\n\t\t\textIn.dispose();\n\t\t});\n\n\t\tit(\"can close an input\", async () => {\n\t\t\tconst extIn = new UserMedia();\n\t\t\tawait extIn.open();\n\t\t\textIn.close();\n\t\t\textIn.dispose();\n\t\t});\n\n\t\tit(\"can enumerate devices\", async () => {\n\t\t\tconst devices = await UserMedia.enumerateDevices();\n\t\t\texpect(devices).to.be.instanceOf(Array);\n\t\t});\n\n\t\tit(\"doesn't work in OfflineContext\", async () => {\n\t\t\tconst context = new OfflineContext(2, 2, 44100);\n\t\t\tconst extIn = new UserMedia({ context });\n\t\t\ttry {\n\t\t\t\tawait extIn.open();\n\t\t\t\tthrow new Error(\"shouldn't reach here\");\n\t\t\t} catch {\n\t\t\t\t// expected to throw in OfflineContext\n\t\t\t}\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/source/UserMedia.ts",
    "content": "import { Volume } from \"../component/channel/Volume.js\";\nimport { Param } from \"../core/context/Param.js\";\nimport {\n\tconnect,\n\tOutputNode,\n\tToneAudioNode,\n\tToneAudioNodeOptions,\n} from \"../core/context/ToneAudioNode.js\";\nimport { Decibels } from \"../core/type/Units.js\";\nimport { assert } from \"../core/util/Debug.js\";\nimport { deepMerge, optionsFromArguments } from \"../core/util/Defaults.js\";\nimport { readOnly } from \"../core/util/Interface.js\";\nimport { isDefined, isNumber, isObject } from \"../core/util/TypeCheck.js\";\n\nexport interface UserMediaOptions extends ToneAudioNodeOptions {\n\tvolume: Decibels;\n\tmute: boolean;\n}\n/**\n * UserMedia uses MediaDevices.getUserMedia to open up and external microphone or audio input.\n * Check [MediaDevices API Support](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia)\n * to see which browsers are supported. Access to an external input\n * is limited to secure (HTTPS) connections.\n * @example\n * const meter = new Tone.Meter();\n * const mic = new Tone.UserMedia().connect(meter);\n * mic.open().then(() => {\n * \t// promise resolves when input is available\n * \tconsole.log(\"mic open\");\n * \t// print the incoming mic levels in decibels\n * \tsetInterval(() => console.log(meter.getValue()), 100);\n * }).catch(e => {\n * \t// promise is rejected when the user doesn't have or allow mic access\n * \tconsole.log(\"mic not open\");\n * });\n * @category Source\n */\n\nexport class UserMedia extends ToneAudioNode<UserMediaOptions> {\n\treadonly name: string = \"UserMedia\";\n\n\treadonly input: undefined;\n\treadonly output: OutputNode;\n\n\t/**\n\t * The MediaStreamNode\n\t */\n\tprivate _mediaStream?: MediaStreamAudioSourceNode;\n\n\t/**\n\t * The media stream created by getUserMedia.\n\t */\n\tprivate _stream?: MediaStream;\n\n\t/**\n\t * The open device\n\t */\n\tprivate _device?: MediaDeviceInfo;\n\n\t/**\n\t * The output volume node\n\t */\n\tprivate _volume: Volume;\n\n\t/**\n\t * The volume of the output in decibels.\n\t */\n\treadonly volume: Param<\"decibels\">;\n\n\t/**\n\t * @param volume The level of the input in decibels\n\t */\n\tconstructor(volume?: Decibels);\n\tconstructor(options?: Partial<UserMediaOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tUserMedia.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"volume\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._volume = this.output = new Volume({\n\t\t\tcontext: this.context,\n\t\t\tvolume: options.volume,\n\t\t});\n\t\tthis.volume = this._volume.volume;\n\t\treadOnly(this, \"volume\");\n\t\tthis.mute = options.mute;\n\t}\n\n\tstatic getDefaults(): UserMediaOptions {\n\t\treturn Object.assign(ToneAudioNode.getDefaults(), {\n\t\t\tmute: false,\n\t\t\tvolume: 0,\n\t\t});\n\t}\n\n\t/**\n\t * Open the media stream. If a string is passed in, it is assumed\n\t * to be the label or id of the stream, if a number is passed in,\n\t * it is the input number of the stream.\n\t * @param  labelOrIdOrConstraints The label or id of the audio input media device, or a getUserMedia constraints object.\n\t *                   \t\t\t  With no argument, the default stream is opened.\n\t * @return The promise is resolved when the stream is open.\n\t */\n\tasync open(\n\t\tlabelOrIdOrConstraints?: string | number | MediaStreamConstraints\n\t): Promise<this> {\n\t\tassert(UserMedia.supported, \"UserMedia is not supported\");\n\t\t// close the previous stream\n\t\tif (this.state === \"started\") {\n\t\t\tthis.close();\n\t\t}\n\t\tlet constraints: MediaStreamConstraints = {\n\t\t\taudio: {\n\t\t\t\techoCancellation: false,\n\t\t\t\tsampleRate: this.context.sampleRate,\n\t\t\t\tnoiseSuppression: false,\n\t\t\t},\n\t\t};\n\t\tif (isObject(labelOrIdOrConstraints)) {\n\t\t\t// if the user passed in a constraints object\n\t\t\tconstraints = deepMerge(constraints, labelOrIdOrConstraints);\n\t\t} else {\n\t\t\t// if the user passed in a label or id\n\t\t\tconst devices = await UserMedia.enumerateDevices();\n\t\t\tif (isNumber(labelOrIdOrConstraints)) {\n\t\t\t\tthis._device = devices[labelOrIdOrConstraints];\n\t\t\t} else {\n\t\t\t\tthis._device = devices.find((device) => {\n\t\t\t\t\treturn (\n\t\t\t\t\t\tdevice.label === labelOrIdOrConstraints ||\n\t\t\t\t\t\tdevice.deviceId === labelOrIdOrConstraints\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t\t// didn't find a matching device\n\t\t\t\tif (!this._device && devices.length > 0) {\n\t\t\t\t\tthis._device = devices[0];\n\t\t\t\t}\n\t\t\t\tassert(\n\t\t\t\t\tisDefined(this._device),\n\t\t\t\t\t`No matching device ${labelOrIdOrConstraints}`\n\t\t\t\t);\n\t\t\t}\n\t\t\t// if there is a device, set the deviceId\n\t\t\tif (this._device) {\n\t\t\t\t// @ts-ignore\n\t\t\t\tconstraints.audio.deviceId = this._device.deviceId;\n\t\t\t}\n\t\t}\n\t\tconst stream = await navigator.mediaDevices.getUserMedia(constraints);\n\t\t// start a new source only if the previous one is closed\n\t\tif (!this._stream) {\n\t\t\tthis._stream = stream;\n\t\t\t// Wrap a MediaStreamSourceNode around the live input stream.\n\t\t\tconst mediaStreamNode =\n\t\t\t\tthis.context.createMediaStreamSource(stream);\n\t\t\t// Connect the MediaStreamSourceNode to a gate gain node\n\t\t\tconnect(mediaStreamNode, this.output);\n\t\t\tthis._mediaStream = mediaStreamNode;\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Close the media stream\n\t */\n\tclose(): this {\n\t\tif (this._stream && this._mediaStream) {\n\t\t\tthis._stream.getAudioTracks().forEach((track) => {\n\t\t\t\ttrack.stop();\n\t\t\t});\n\t\t\tthis._stream = undefined;\n\t\t\t// remove the old media stream\n\t\t\tthis._mediaStream.disconnect();\n\t\t\tthis._mediaStream = undefined;\n\t\t}\n\t\tthis._device = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Returns a promise which resolves with the list of audio input devices available.\n\t * @return The promise that is resolved with the devices\n\t * @example\n\t * Tone.UserMedia.enumerateDevices().then((devices) => {\n\t * \t// print the device labels\n\t * \tconsole.log(devices.map(device => device.label));\n\t * });\n\t */\n\tstatic async enumerateDevices(): Promise<MediaDeviceInfo[]> {\n\t\tconst allDevices = await navigator.mediaDevices.enumerateDevices();\n\t\treturn allDevices.filter((device) => {\n\t\t\treturn device.kind === \"audioinput\";\n\t\t});\n\t}\n\n\t/**\n\t * Returns the playback state of the source, \"started\" when the microphone is open\n\t * and \"stopped\" when the mic is closed.\n\t */\n\tget state() {\n\t\treturn this._stream && this._stream.active ? \"started\" : \"stopped\";\n\t}\n\n\t/**\n\t * Returns an identifier for the represented device that is\n\t * persisted across sessions. It is un-guessable by other applications and\n\t * unique to the origin of the calling application. It is reset when the\n\t * user clears cookies (for Private Browsing, a different identifier is\n\t * used that is not persisted across sessions). Returns undefined when the\n\t * device is not open.\n\t */\n\tget deviceId(): string | undefined {\n\t\tif (this._device) {\n\t\t\treturn this._device.deviceId;\n\t\t} else {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Returns a group identifier. Two devices have the\n\t * same group identifier if they belong to the same physical device.\n\t * Returns null  when the device is not open.\n\t */\n\tget groupId(): string | undefined {\n\t\tif (this._device) {\n\t\t\treturn this._device.groupId;\n\t\t} else {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Returns a label describing this device (for example \"Built-in Microphone\").\n\t * Returns undefined when the device is not open or label is not available\n\t * because of permissions.\n\t */\n\tget label(): string | undefined {\n\t\tif (this._device) {\n\t\t\treturn this._device.label;\n\t\t} else {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Mute the output.\n\t * @example\n\t * const mic = new Tone.UserMedia();\n\t * mic.open().then(() => {\n\t * \t// promise resolves when input is available\n\t * });\n\t * // mute the output\n\t * mic.mute = true;\n\t */\n\tget mute(): boolean {\n\t\treturn this._volume.mute;\n\t}\n\tset mute(mute) {\n\t\tthis._volume.mute = mute;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.close();\n\t\tthis._volume.dispose();\n\t\tthis.volume.dispose();\n\t\treturn this;\n\t}\n\n\t/**\n\t * If getUserMedia is supported by the browser.\n\t */\n\tstatic get supported(): boolean {\n\t\treturn (\n\t\t\tisDefined(navigator.mediaDevices) &&\n\t\t\tisDefined(navigator.mediaDevices.getUserMedia)\n\t\t);\n\t}\n}\n"
  },
  {
    "path": "Tone/source/buffer/GrainPlayer.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../../test/helper/CompareToFile.js\";\nimport { Offline, whenBetween } from \"../../../test/helper/Offline.js\";\nimport { SourceTests } from \"../../../test/helper/SourceTests.js\";\nimport { ToneAudioBuffer } from \"../../core/context/ToneAudioBuffer.js\";\nimport { GrainPlayer } from \"./GrainPlayer.js\";\n\ndescribe(\"GrainPlayer\", () => {\n\tconst buffer = new ToneAudioBuffer();\n\n\tbeforeEach(() => {\n\t\treturn buffer.load(\"./test/audio/sine.wav\");\n\t});\n\n\t// run the common tests\n\tBasicTests(GrainPlayer, buffer);\n\tSourceTests(GrainPlayer, buffer);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst player = new GrainPlayer(buffer).toDestination();\n\t\t\t\tplayer.start(0.1).stop(0.2);\n\t\t\t\t(player.detune = -100), (player.playbackRate = 2);\n\t\t\t},\n\t\t\t\"grainPlayer.wav\",\n\t\t\t0.16\n\t\t);\n\t});\n\n\tit(\"matches another file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst player = new GrainPlayer(buffer).toDestination();\n\t\t\t\tplayer.start(0.1, 0.2);\n\t\t\t\tplayer.loop = true;\n\t\t\t\tplayer.overlap = 0.005;\n\t\t\t\tplayer.grainSize = 0.05;\n\t\t\t\t(player.detune = 1200), (player.playbackRate = 0.5);\n\t\t\t},\n\t\t\t\"grainPlayer2.wav\",\n\t\t\t0.2\n\t\t);\n\t});\n\n\tcontext(\"Constructor\", () => {\n\t\tit(\"can be constructed with a Tone.Buffer\", (done) => {\n\t\t\tconst player = new GrainPlayer(buffer);\n\t\t\texpect(player.buffer.get()).to.equal(buffer.get());\n\t\t\tplayer.dispose();\n\t\t\tdone();\n\t\t});\n\n\t\tit(\"can be constructed with an AudioBuffer\", (done) => {\n\t\t\tconst player = new GrainPlayer(buffer.get());\n\t\t\texpect(player.buffer.get()).to.equal(buffer.get());\n\t\t\tplayer.dispose();\n\t\t\tdone();\n\t\t});\n\n\t\tit(\"makes a sound\", async () => {\n\t\t\tconst output = await Offline(() => {\n\t\t\t\tconst player = new GrainPlayer(buffer).toDestination();\n\t\t\t\tplayer.start();\n\t\t\t});\n\t\t\texpect(output.isSilent()).to.be.false;\n\t\t});\n\t});\n\n\tcontext(\"Loading\", () => {\n\t\tit(\"loads a url which was passed in\", (done) => {\n\t\t\tconst player = new GrainPlayer(\"./test/audio/sine.wav\", () => {\n\t\t\t\texpect(player.loaded).to.be.true;\n\t\t\t\tplayer.dispose();\n\t\t\t\tdone();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can be created with an options object\", (done) => {\n\t\t\tconst player = new GrainPlayer({\n\t\t\t\turl: \"./test/audio/sine.wav\",\n\t\t\t\tloop: true,\n\t\t\t\tonload: function () {\n\t\t\t\t\texpect(player.loop).to.be.true;\n\t\t\t\t\tplayer.dispose();\n\t\t\t\t\tdone();\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\n\t\tit(\"invokes onerror if no url\", (done) => {\n\t\t\tconst source = new GrainPlayer({\n\t\t\t\turl: \"./nosuchfile.wav\",\n\t\t\t\tonerror() {\n\t\t\t\t\tsource.dispose();\n\t\t\t\t\tdone();\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"Looping\", () => {\n\t\tbeforeEach(() => {\n\t\t\tbuffer.load(\"./test/audio/short_sine.wav\");\n\t\t});\n\n\t\tit(\"can be set to loop\", () => {\n\t\t\tconst player = new GrainPlayer();\n\t\t\tplayer.loop = true;\n\t\t\texpect(player.loop).to.be.true;\n\t\t\tplayer.dispose();\n\t\t});\n\t});\n\n\tcontext(\"start/stop\", () => {\n\t\tbeforeEach(() => {\n\t\t\tbuffer.load(\"./test/audio/short_sine.wav\");\n\t\t});\n\n\t\tit(\"can be play for a specific duration\", async () => {\n\t\t\tconst output = await Offline(() => {\n\t\t\t\tconst player = new GrainPlayer(buffer);\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer.start(0).stop(0.1);\n\t\t\t\treturn function (time) {\n\t\t\t\t\twhenBetween(time, 0.1, Infinity, () => {\n\t\t\t\t\t\texpect(player.state).to.equal(\"stopped\");\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0, 0.1, () => {\n\t\t\t\t\t\texpect(player.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.3);\n\t\t\texpect(output.getTimeOfLastSound()).to.be.closeTo(0.1, 0.02);\n\t\t});\n\n\t\tit(\"can be play for a specific duration passed in the 'start' method\", async () => {\n\t\t\tconst output = await Offline(() => {\n\t\t\t\tconst player = new GrainPlayer(buffer);\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer.start(0, 0, 0.1);\n\t\t\t\treturn function (time) {\n\t\t\t\t\twhenBetween(time, 0.1, Infinity, () => {\n\t\t\t\t\t\texpect(player.state).to.equal(\"stopped\");\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0, 0.1, () => {\n\t\t\t\t\t\texpect(player.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.3);\n\t\t\texpect(output.getTimeOfLastSound()).to.be.closeTo(0.1, 0.02);\n\t\t});\n\n\t\tit(\"invokes the onstop method on restart\", async () => {\n\t\t\tlet wasInvoked = 0;\n\t\t\tawait Offline(() => {\n\t\t\t\tconst player = new GrainPlayer(buffer);\n\t\t\t\tplayer.start(0).restart(0.1).stop(0.2);\n\t\t\t\tplayer.onstop = () => {\n\t\t\t\t\twasInvoked++;\n\t\t\t\t};\n\t\t\t}, 0.3);\n\t\t\texpect(wasInvoked).to.equal(2);\n\t\t});\n\n\t\tit(\"can play to the end of the file\", async () => {\n\t\t\tconst bufferDuration = buffer.duration;\n\t\t\tconst output = await Offline(() => {\n\t\t\t\tconst player = new GrainPlayer(buffer).toDestination();\n\t\t\t\tplayer.grainSize = 0.1;\n\t\t\t\tplayer.start(0);\n\t\t\t}, bufferDuration * 1.2);\n\t\t\texpect(output.getTimeOfLastSound()).to.be.closeTo(\n\t\t\t\tbufferDuration,\n\t\t\t\t0.1\n\t\t\t);\n\t\t});\n\n\t\tit(\"plays for the right time when playbackRate = 2\", async () => {\n\t\t\tconst bufferDuration = buffer.duration;\n\t\t\tconst output = await Offline(() => {\n\t\t\t\tconst player = new GrainPlayer(buffer).toDestination();\n\t\t\t\tplayer.playbackRate = 2;\n\t\t\t\tplayer.start(0);\n\t\t\t}, bufferDuration);\n\t\t\texpect(output.getTimeOfLastSound()).to.be.closeTo(\n\t\t\t\tbufferDuration * 0.5,\n\t\t\t\t0.1\n\t\t\t);\n\t\t});\n\t});\n\n\tcontext(\"Get/Set\", () => {\n\t\tit(\"can be set with an options object\", () => {\n\t\t\tconst player = new GrainPlayer();\n\t\t\texpect(player.loop).to.be.false;\n\t\t\tplayer.set({\n\t\t\t\tloop: true,\n\t\t\t\tloopStart: 0.4,\n\t\t\t});\n\t\t\texpect(player.loop).to.be.true;\n\t\t\texpect(player.loopStart).to.equal(0.4);\n\t\t\tplayer.dispose();\n\t\t});\n\n\t\tit(\"can get an options object\", () => {\n\t\t\tconst player = new GrainPlayer({\n\t\t\t\turl: \"./test/audio/sine.wav\",\n\t\t\t\tloopStart: 0.2,\n\t\t\t\tloopEnd: 0.3,\n\t\t\t\tloop: true,\n\t\t\t\treverse: true,\n\t\t\t});\n\t\t\texpect(player.get().loopStart).to.equal(0.2);\n\t\t\texpect(player.get().loopEnd).to.equal(0.3);\n\t\t\texpect(player.get().loop).to.be.true;\n\t\t\texpect(player.get().reverse).to.be.true;\n\t\t\tplayer.dispose();\n\t\t});\n\n\t\tit(\"can get/set the playbackRate\", () => {\n\t\t\tconst player = new GrainPlayer();\n\t\t\tplayer.playbackRate = 0.5;\n\t\t\texpect(player.playbackRate).to.equal(0.5);\n\t\t\tplayer.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/source/buffer/GrainPlayer.ts",
    "content": "import { Clock } from \"../../core/clock/Clock.js\";\nimport { ToneAudioBuffer } from \"../../core/context/ToneAudioBuffer.js\";\nimport { intervalToFrequencyRatio } from \"../../core/type/Conversions.js\";\nimport { Cents, Positive, Seconds, Time } from \"../../core/type/Units.js\";\nimport { assertRange } from \"../../core/util/Debug.js\";\nimport { defaultArg, optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { noOp } from \"../../core/util/Interface.js\";\nimport { Source, SourceOptions } from \"../Source.js\";\nimport { ToneBufferSource } from \"./ToneBufferSource.js\";\n\ninterface GrainPlayerOptions extends SourceOptions {\n\tonload: () => void;\n\tonerror: (error: Error) => void;\n\treverse: boolean;\n\turl?: ToneAudioBuffer | string | AudioBuffer;\n\toverlap: Seconds;\n\tgrainSize: Seconds;\n\tplaybackRate: Positive;\n\tdetune: Cents;\n\tloop: boolean;\n\tloopStart: Time;\n\tloopEnd: Time;\n}\n\n/**\n * GrainPlayer implements [granular synthesis](https://en.wikipedia.org/wiki/Granular_synthesis).\n * Granular Synthesis enables you to adjust pitch and playback rate independently. The grainSize is the\n * amount of time each small chunk of audio is played for and the overlap is the\n * amount of crossfading transition time between successive grains.\n * @category Source\n */\nexport class GrainPlayer extends Source<GrainPlayerOptions> {\n\treadonly name: string = \"GrainPlayer\";\n\n\t/**\n\t * The audio buffer belonging to the player.\n\t */\n\tbuffer: ToneAudioBuffer;\n\n\t/**\n\t * Create a repeating tick to schedule the grains.\n\t */\n\tprivate _clock: Clock;\n\n\t/**\n\t * Internal loopStart value\n\t */\n\tprivate _loopStart = 0;\n\n\t/**\n\t * Internal loopStart value\n\t */\n\tprivate _loopEnd = 0;\n\n\t/**\n\t * All of the currently playing BufferSources\n\t */\n\tprivate _activeSources: ToneBufferSource[] = [];\n\n\t/**\n\t * Internal reference to the playback rate\n\t */\n\tprivate _playbackRate: Positive;\n\n\t/**\n\t * Internal grain size reference;\n\t */\n\tprivate _grainSize: Seconds;\n\n\t/**\n\t * Internal overlap reference;\n\t */\n\tprivate _overlap: Seconds;\n\n\t/**\n\t * Adjust the pitch independently of the playbackRate.\n\t */\n\tdetune: Cents;\n\n\t/**\n\t * If the buffer should loop back to the loopStart when completed\n\t */\n\tloop: boolean;\n\n\t/**\n\t * @param url Either the AudioBuffer or the url from which to load the AudioBuffer\n\t * @param onload The function to invoke when the buffer is loaded.\n\t */\n\tconstructor(\n\t\turl?: string | AudioBuffer | ToneAudioBuffer,\n\t\tonload?: () => void\n\t);\n\tconstructor(options?: Partial<GrainPlayerOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tGrainPlayer.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"url\", \"onload\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.buffer = new ToneAudioBuffer({\n\t\t\tonload: options.onload,\n\t\t\tonerror: options.onerror,\n\t\t\treverse: options.reverse,\n\t\t\turl: options.url,\n\t\t});\n\t\tthis._clock = new Clock({\n\t\t\tcontext: this.context,\n\t\t\tcallback: this._tick.bind(this),\n\t\t\tfrequency: 1 / options.grainSize,\n\t\t});\n\t\tthis._playbackRate = options.playbackRate;\n\t\tthis._grainSize = options.grainSize;\n\t\tthis._overlap = options.overlap;\n\t\tthis.detune = options.detune;\n\n\t\t// setup\n\t\tthis.overlap = options.overlap;\n\t\tthis.loop = options.loop;\n\t\tthis.playbackRate = options.playbackRate;\n\t\tthis.grainSize = options.grainSize;\n\t\tthis.loopStart = options.loopStart;\n\t\tthis.loopEnd = options.loopEnd;\n\t\tthis.reverse = options.reverse;\n\t\tthis._clock.on(\"stop\", this._onstop.bind(this));\n\t}\n\n\tstatic getDefaults(): GrainPlayerOptions {\n\t\treturn Object.assign(Source.getDefaults(), {\n\t\t\tonload: noOp,\n\t\t\tonerror: noOp,\n\t\t\toverlap: 0.1,\n\t\t\tgrainSize: 0.2,\n\t\t\tplaybackRate: 1,\n\t\t\tdetune: 0,\n\t\t\tloop: false,\n\t\t\tloopStart: 0,\n\t\t\tloopEnd: 0,\n\t\t\treverse: false,\n\t\t});\n\t}\n\n\t/**\n\t * Internal start method\n\t */\n\tprotected _start(time?: Time, offset?: Time, duration?: Time): void {\n\t\toffset = defaultArg(offset, 0);\n\t\toffset = this.toSeconds(offset);\n\t\ttime = this.toSeconds(time);\n\n\t\tconst grainSize = 1 / this._clock.frequency.getValueAtTime(time);\n\t\tthis._clock.start(time, offset / grainSize);\n\n\t\tif (duration) {\n\t\t\tthis.stop(time + this.toSeconds(duration));\n\t\t}\n\t}\n\n\t/**\n\t * Stop and then restart the player from the beginning (or offset)\n\t * @param  time When the player should start.\n\t * @param  offset The offset from the beginning of the sample to start at.\n\t * @param  duration How long the sample should play. If no duration is given,\n\t * \t\t\t\t\tit will default to the full length of the sample (minus any offset)\n\t */\n\trestart(time?: Seconds, offset?: Time, duration?: Time): this {\n\t\tsuper.restart(time, offset, duration);\n\t\treturn this;\n\t}\n\n\tprotected _restart(time?: Seconds, offset?: Time, duration?: Time): void {\n\t\tthis._stop(time);\n\t\tthis._start(time, offset, duration);\n\t}\n\n\t/**\n\t * Internal stop method\n\t */\n\tprotected _stop(time?: Time): void {\n\t\tthis._clock.stop(time);\n\t}\n\n\t/**\n\t * Invoked when the clock is stopped\n\t */\n\tprivate _onstop(time: Seconds): void {\n\t\t// stop the players\n\t\tthis._activeSources.forEach((source) => {\n\t\t\tsource.fadeOut = 0;\n\t\t\tsource.stop(time);\n\t\t});\n\t\tthis.onstop(this);\n\t}\n\n\t/**\n\t * Invoked on each clock tick. scheduled a new grain at this time.\n\t */\n\tprivate _tick(time: Seconds): void {\n\t\t// check if it should stop looping\n\t\tconst ticks = this._clock.getTicksAtTime(time);\n\t\tconst offset = ticks * this._grainSize;\n\t\tthis.log(\"offset\", offset);\n\n\t\tif (!this.loop && offset > this.buffer.duration) {\n\t\t\tthis.stop(time);\n\t\t\treturn;\n\t\t}\n\n\t\t// at the beginning of the file, the fade in should be 0\n\t\tconst fadeIn = offset < this._overlap ? 0 : this._overlap;\n\n\t\t// create a buffer source\n\t\tconst source = new ToneBufferSource({\n\t\t\tcontext: this.context,\n\t\t\turl: this.buffer,\n\t\t\tfadeIn: fadeIn,\n\t\t\tfadeOut: this._overlap,\n\t\t\tloop: this.loop,\n\t\t\tloopStart: this._loopStart,\n\t\t\tloopEnd: this._loopEnd,\n\t\t\t// compute the playbackRate based on the detune\n\t\t\tplaybackRate: intervalToFrequencyRatio(this.detune / 100),\n\t\t}).connect(this.output);\n\n\t\tsource.start(time, this._grainSize * ticks);\n\t\tsource.stop(time + this._grainSize / this.playbackRate);\n\n\t\t// add it to the active sources\n\t\tthis._activeSources.push(source);\n\t\t// remove it when it's done\n\t\tsource.onended = () => {\n\t\t\tconst index = this._activeSources.indexOf(source);\n\t\t\tif (index !== -1) {\n\t\t\t\tthis._activeSources.splice(index, 1);\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * The playback rate of the sample\n\t */\n\tget playbackRate(): Positive {\n\t\treturn this._playbackRate;\n\t}\n\tset playbackRate(rate) {\n\t\tassertRange(rate, 0.001);\n\t\tthis._playbackRate = rate;\n\t\tthis.grainSize = this._grainSize;\n\t}\n\n\t/**\n\t * The loop start time.\n\t */\n\tget loopStart(): Time {\n\t\treturn this._loopStart;\n\t}\n\tset loopStart(time) {\n\t\tif (this.buffer.loaded) {\n\t\t\tassertRange(this.toSeconds(time), 0, this.buffer.duration);\n\t\t}\n\t\tthis._loopStart = this.toSeconds(time);\n\t}\n\n\t/**\n\t * The loop end time.\n\t */\n\tget loopEnd(): Time {\n\t\treturn this._loopEnd;\n\t}\n\tset loopEnd(time) {\n\t\tif (this.buffer.loaded) {\n\t\t\tassertRange(this.toSeconds(time), 0, this.buffer.duration);\n\t\t}\n\t\tthis._loopEnd = this.toSeconds(time);\n\t}\n\n\t/**\n\t * The direction the buffer should play in\n\t */\n\tget reverse() {\n\t\treturn this.buffer.reverse;\n\t}\n\n\tset reverse(rev) {\n\t\tthis.buffer.reverse = rev;\n\t}\n\n\t/**\n\t * The size of each chunk of audio that the\n\t * buffer is chopped into and played back at.\n\t */\n\tget grainSize(): Time {\n\t\treturn this._grainSize;\n\t}\n\tset grainSize(size) {\n\t\tthis._grainSize = this.toSeconds(size);\n\t\tthis._clock.frequency.setValueAtTime(\n\t\t\tthis._playbackRate / this._grainSize,\n\t\t\tthis.now()\n\t\t);\n\t}\n\n\t/**\n\t * The duration of the cross-fade between successive grains.\n\t */\n\tget overlap(): Time {\n\t\treturn this._overlap;\n\t}\n\tset overlap(time) {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tassertRange(computedTime, 0);\n\t\tthis._overlap = computedTime;\n\t}\n\n\t/**\n\t * If all the buffer is loaded\n\t */\n\tget loaded(): boolean {\n\t\treturn this.buffer.loaded;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.buffer.dispose();\n\t\tthis._clock.dispose();\n\t\tthis._activeSources.forEach((source) => source.dispose());\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/source/buffer/Player.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../../test/helper/CompareToFile.js\";\nimport { atTime, Offline, whenBetween } from \"../../../test/helper/Offline.js\";\nimport { SourceTests } from \"../../../test/helper/SourceTests.js\";\nimport { ToneAudioBuffer } from \"../../core/context/ToneAudioBuffer.js\";\nimport { getContext } from \"../../core/Global.js\";\nimport { Player } from \"./Player.js\";\n\ndescribe(\"Player\", () => {\n\tconst buffer = new ToneAudioBuffer();\n\n\tbeforeEach(() => {\n\t\treturn buffer.load(\"./test/audio/sine.wav\");\n\t});\n\n\t// run the common tests\n\tBasicTests(Player, buffer);\n\tSourceTests(Player, buffer);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst player = new Player(buffer).toDestination();\n\t\t\t\tplayer.start(0.1).stop(0.2);\n\t\t\t\tplayer.playbackRate = 2;\n\t\t\t},\n\t\t\t\"player.wav\",\n\t\t\t0.005\n\t\t);\n\t});\n\n\tcontext(\"Constructor\", () => {\n\t\tit(\"can be constructed with a Tone.Buffer\", () => {\n\t\t\tconst player = new Player(buffer);\n\t\t\texpect(player.buffer.get()).to.equal(buffer.get());\n\t\t\tplayer.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an AudioBuffer\", () => {\n\t\t\tconst player = new Player(buffer.get());\n\t\t\texpect(player.buffer.get()).to.equal(buffer.get());\n\t\t\tplayer.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an unloaded Tone.Buffer\", (done) => {\n\t\t\tconst playerBuffer = new ToneAudioBuffer(\"./test/audio/sine.wav\");\n\t\t\tconst player = new Player(playerBuffer, () => {\n\t\t\t\texpect(player.buffer.get()).to.equal(playerBuffer.get());\n\t\t\t\tplayer.dispose();\n\t\t\t\tdone();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can be constructed with no arguments\", () => {\n\t\t\tconst player = new Player();\n\t\t\t// set the buffer\n\t\t\tplayer.buffer = buffer;\n\t\t\texpect(player.buffer.get()).to.equal(buffer.get());\n\t\t\tplayer.dispose();\n\t\t});\n\t});\n\n\tcontext(\"onstop\", () => {\n\t\tit(\"invokes the onstop method when the player is explicitly stopped\", async () => {\n\t\t\tlet wasInvoked = false;\n\t\t\tawait Offline(() => {\n\t\t\t\tconst player = new Player({\n\t\t\t\t\tonstop: () => {\n\t\t\t\t\t\twasInvoked = true;\n\t\t\t\t\t},\n\t\t\t\t\turl: buffer,\n\t\t\t\t});\n\t\t\t\tplayer.start(0).stop(0.1);\n\t\t\t}, 0.2);\n\t\t\texpect(wasInvoked).to.equal(true);\n\t\t});\n\n\t\tit(\"invokes the onstop method when the file is naturally over\", async () => {\n\t\t\tlet wasInvoked = false;\n\t\t\tawait Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.start(0);\n\t\t\t\tplayer.onstop = () => {\n\t\t\t\t\twasInvoked = true;\n\t\t\t\t\texpect(player.state).to.equal(\"stopped\");\n\t\t\t\t};\n\t\t\t}, buffer.duration * 1.1);\n\t\t\texpect(wasInvoked).to.equal(true);\n\t\t});\n\n\t\tit(\"invokes the onstop method on restart\", async () => {\n\t\t\tlet wasInvoked = 0;\n\t\t\tawait Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.start(0).restart(0.1).stop(0.2);\n\t\t\t\tplayer.onstop = () => {\n\t\t\t\t\twasInvoked++;\n\t\t\t\t};\n\t\t\t}, 0.3);\n\t\t\texpect(wasInvoked).to.equal(2);\n\t\t});\n\t});\n\n\tcontext(\"Loading\", () => {\n\t\tit(\"loads a url which was passed in\", (done) => {\n\t\t\tconst player = new Player(\"./test/audio/sine.wav\", () => {\n\t\t\t\texpect(player.loaded).to.be.true;\n\t\t\t\tplayer.dispose();\n\t\t\t\tdone();\n\t\t\t});\n\t\t});\n\n\t\tit(\"loads a url using the load method\", async () => {\n\t\t\tconst player = new Player();\n\t\t\tawait player.load(\"./test/audio/sine.wav\");\n\t\t\texpect(player.buffer).to.be.instanceof(ToneAudioBuffer);\n\t\t});\n\n\t\tit(\"can be created with an options object\", () => {\n\t\t\tconst player = new Player({\n\t\t\t\tloop: true,\n\t\t\t\turl: \"./test/audio/sine.wav\",\n\t\t\t});\n\t\t\tplayer.dispose();\n\t\t});\n\n\t\tit(\"invokes onerror if no url\", (done) => {\n\t\t\tconst source = new Player({\n\t\t\t\turl: \"./nosuchfile.wav\",\n\t\t\t\tonerror(e) {\n\t\t\t\t\texpect(e).to.be.instanceOf(Error);\n\t\t\t\t\tsource.dispose();\n\t\t\t\t\tdone();\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\n\t\tit(\"can autostart after loading\", (done) => {\n\t\t\tconst player = new Player({\n\t\t\t\tautostart: true,\n\t\t\t\tonload(): void {\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\texpect(player.state).to.be.equal(\"started\");\n\t\t\t\t\t\tdone();\n\t\t\t\t\t}, 10);\n\t\t\t\t},\n\t\t\t\turl: \"./test/audio/sine.wav\",\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"Reverse\", () => {\n\t\tit(\"can get/set reverse\", () => {\n\t\t\tconst player = new Player();\n\t\t\tplayer.reverse = true;\n\t\t\texpect(player.reverse).to.equal(true);\n\t\t\tplayer.dispose();\n\t\t});\n\n\t\tit(\"can be played in reverse\", async () => {\n\t\t\tconst shorterBuffer = buffer.slice(0, buffer.duration / 2);\n\t\t\tconst audioBuffer = (\n\t\t\t\tshorterBuffer.get() as AudioBuffer\n\t\t\t).getChannelData(0);\n\t\t\tconst lastSample = audioBuffer[audioBuffer.length - 1];\n\t\t\texpect(lastSample).to.not.equal(0);\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new Player({\n\t\t\t\t\treverse: true,\n\t\t\t\t\turl: shorterBuffer.get(),\n\t\t\t\t}).toDestination();\n\t\t\t\tplayer.start(0);\n\t\t\t});\n\t\t\tconst firstSample = buff.toArray()[0][0];\n\t\t\texpect(firstSample).to.equal(lastSample);\n\t\t});\n\t});\n\n\tcontext(\"Looping\", () => {\n\t\tbeforeEach(() => {\n\t\t\treturn buffer.load(\"./test/audio/short_sine.wav\");\n\t\t});\n\n\t\tit(\"can be set to loop\", () => {\n\t\t\tconst player = new Player();\n\t\t\tplayer.loop = true;\n\t\t\texpect(player.loop).to.be.true;\n\t\t\tplayer.dispose();\n\t\t});\n\n\t\tit(\"can set the loop points\", () => {\n\t\t\tconst player = new Player();\n\t\t\tplayer.loopStart = 0.4;\n\t\t\texpect(player.loopStart).to.equal(0.4);\n\t\t\tplayer.loopEnd = 0.5;\n\t\t\texpect(player.loopEnd).to.equal(0.5);\n\t\t\tplayer.setLoopPoints(0, 0.2);\n\t\t\texpect(player.loopStart).to.equal(0);\n\t\t\texpect(player.loopEnd).to.equal(0.2);\n\t\t\tplayer.dispose();\n\t\t});\n\n\t\tit(\"loops the audio\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.loop = true;\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer.start(0);\n\t\t\t}, buffer.duration * 1.5);\n\t\t\texpect(buff.getRmsAtTime(0)).to.be.above(0);\n\t\t\texpect(buff.getRmsAtTime(buffer.duration * 0.5)).to.be.above(0);\n\t\t\texpect(buff.getRmsAtTime(buffer.duration)).to.be.above(0);\n\t\t\texpect(buff.getRmsAtTime(buffer.duration * 1.2)).to.be.above(0);\n\t\t});\n\n\t\tit(\"setting the loop multiple times has no affect\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.loop = true;\n\t\t\t\tplayer.loop = true;\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer.start(0);\n\t\t\t}, buffer.duration * 1.5);\n\t\t\texpect(buff.getRmsAtTime(0)).to.be.above(0);\n\t\t\texpect(buff.getRmsAtTime(buffer.duration * 0.5)).to.be.above(0);\n\t\t\texpect(buff.getRmsAtTime(buffer.duration)).to.be.above(0);\n\t\t\texpect(buff.getRmsAtTime(buffer.duration * 1.2)).to.be.above(0);\n\t\t});\n\n\t\tit(\"loops the audio when loop is set after start\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer.start(0);\n\t\t\t\tplayer.loop = true;\n\t\t\t}, buffer.duration * 1.5);\n\t\t\texpect(buff.getRmsAtTime(0)).to.be.above(0);\n\t\t\texpect(buff.getRmsAtTime(buffer.duration * 0.5)).to.be.above(0);\n\t\t\texpect(buff.getRmsAtTime(buffer.duration)).to.be.above(0);\n\t\t\texpect(buff.getRmsAtTime(buffer.duration * 1.2)).to.be.above(0);\n\t\t});\n\n\t\tit(\"offset is the loopStart when set to loop\", async () => {\n\t\t\tconst testSample =\n\t\t\t\tbuffer.toArray(0)[Math.floor(0.1 * getContext().sampleRate)];\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.loopStart = 0.1;\n\t\t\t\tplayer.loop = true;\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer.start(0);\n\t\t\t}, 0.05);\n\t\t\texpect(buff.toArray()[0][0]).to.equal(testSample);\n\t\t});\n\n\t\tit(\"loops the audio for the specific duration\", async () => {\n\t\t\tconst playDur = buffer.duration * 1.5;\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.loop = true;\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer.start(0, 0, playDur);\n\t\t\t}, buffer.duration * 2);\n\t\t\tfor (let time = 0; time < buffer.duration * 2; time += 0.1) {\n\t\t\t\tconst val = buff.getRmsAtTime(time);\n\t\t\t\tif (time < playDur - 0.01) {\n\t\t\t\t\texpect(val).to.be.greaterThan(0);\n\t\t\t\t} else if (time > playDur) {\n\t\t\t\t\texpect(val).to.equal(0);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tit(\"correctly compensates if the offset is greater than the loopEnd\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\t// make a ramp between 0-1\n\t\t\t\tconst ramp = new Float32Array(\n\t\t\t\t\tMath.floor(getContext().sampleRate * 0.3)\n\t\t\t\t);\n\t\t\t\tfor (let i = 0; i < ramp.length; i++) {\n\t\t\t\t\tramp[i] = (i / ramp.length) * 0.3;\n\t\t\t\t}\n\t\t\t\tconst playerBuff = ToneAudioBuffer.fromArray(ramp);\n\t\t\t\tconst player = new Player(playerBuff).toDestination();\n\t\t\t\tplayer.loopStart = 0.1;\n\t\t\t\tplayer.loopEnd = 0.2;\n\t\t\t\tplayer.loop = true;\n\t\t\t\tplayer.start(0, 0.35);\n\t\t\t}, 0.05);\n\t\t\tbuff.forEach((sample, time) => {\n\t\t\t\tif (time < 0.04) {\n\t\t\t\t\texpect(sample).to.be.within(0.15, 0.2);\n\t\t\t\t} else if (time > 0.05 && time < 0.09) {\n\t\t\t\t\texpect(sample).to.be.within(0.1, 0.15);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"PlaybackRate\", () => {\n\t\tit(\"reports itself as completed after the stop time when playbackRate = 1\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.start(0);\n\t\t\t\treturn atTime(buffer.duration + 0.1, () => {\n\t\t\t\t\texpect(player.state).to.equal(\"stopped\");\n\t\t\t\t});\n\t\t\t}, buffer.duration * 1.1);\n\t\t});\n\n\t\tit(\"no longer reports itself as stopped when playback rate is changed to < 1\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.start(0);\n\t\t\t\tplayer.playbackRate = 0.5;\n\t\t\t\treturn atTime(buffer.duration + 0.1, () => {\n\t\t\t\t\texpect(player.state).to.equal(\"started\");\n\t\t\t\t});\n\t\t\t}, buffer.duration * 1.1);\n\t\t});\n\n\t\tit(\"when end is explicitly scheduled, it does not matter if playbackRate is changed\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.start(0).stop(0.1);\n\t\t\t\tplayer.playbackRate = 0.5;\n\t\t\t\treturn atTime(0.11, () => {\n\t\t\t\t\texpect(player.state).to.equal(\"stopped\");\n\t\t\t\t});\n\t\t\t}, buffer.duration);\n\t\t});\n\t});\n\n\tcontext(\"Get/Set\", () => {\n\t\tit(\"can be set with an options object\", () => {\n\t\t\tconst player = new Player();\n\t\t\texpect(player.loop).to.be.false;\n\t\t\tplayer.set({\n\t\t\t\tfadeIn: 0.1,\n\t\t\t\tfadeOut: 0.2,\n\t\t\t\tloop: true,\n\t\t\t\tloopStart: 0.4,\n\t\t\t});\n\t\t\texpect(player.loop).to.be.true;\n\t\t\texpect(player.loopStart).to.equal(0.4);\n\t\t\texpect(player.fadeIn).to.equal(0.1);\n\t\t\texpect(player.fadeOut).to.equal(0.2);\n\t\t\tplayer.dispose();\n\t\t});\n\n\t\tit(\"can set attributes after player is started\", () => {\n\t\t\tconst player = new Player(buffer);\n\t\t\texpect(player.loop).to.be.false;\n\t\t\tplayer.start();\n\t\t\tplayer.set({\n\t\t\t\tloop: true,\n\t\t\t\tloopEnd: 0.3,\n\t\t\t\tloopStart: 0.2,\n\t\t\t\tplaybackRate: 0.9,\n\t\t\t});\n\t\t\texpect(player.loop).to.be.true;\n\t\t\texpect(player.loopStart).to.equal(0.2);\n\t\t\texpect(player.loopEnd).to.equal(0.3);\n\t\t\texpect(player.playbackRate).to.equal(0.9);\n\t\t\tplayer.dispose();\n\t\t});\n\n\t\tit(\"can get an options object\", () => {\n\t\t\tconst player = new Player({\n\t\t\t\tloop: true,\n\t\t\t\tloopEnd: 0.3,\n\t\t\t\tloopStart: 0.2,\n\t\t\t\treverse: true,\n\t\t\t\turl: \"./test/audio/sine.wav\",\n\t\t\t});\n\t\t\texpect(player.get().loopStart).to.equal(0.2);\n\t\t\texpect(player.get().loopEnd).to.equal(0.3);\n\t\t\texpect(player.get().loop).to.be.true;\n\t\t\texpect(player.get().reverse).to.be.true;\n\t\t\tplayer.dispose();\n\t\t});\n\n\t\tit(\"can get/set the playbackRate\", () => {\n\t\t\tconst player = new Player();\n\t\t\tplayer.playbackRate = 0.5;\n\t\t\texpect(player.playbackRate).to.equal(0.5);\n\t\t\tplayer.dispose();\n\t\t});\n\t});\n\n\tcontext(\"Start Scheduling\", () => {\n\t\tit(\"can be start with an offset\", async () => {\n\t\t\tconst testSample =\n\t\t\t\tbuffer.toArray(0)[Math.floor(0.1 * getContext().sampleRate)];\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new Player(buffer.get());\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer.start(0, 0.1);\n\t\t\t});\n\t\t\texpect(buff.toArray()[0][0]).to.equal(testSample);\n\t\t});\n\n\t\tit(\"is stopped and restarted when start is called twice\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\t// make a ramp between 0-1\n\t\t\t\tconst ramp = new Float32Array(\n\t\t\t\t\tMath.floor(getContext().sampleRate * 0.3)\n\t\t\t\t);\n\t\t\t\tfor (let i = 0; i < ramp.length; i++) {\n\t\t\t\t\tramp[i] = i / (ramp.length - 1);\n\t\t\t\t}\n\t\t\t\tconst playerBuff = new ToneAudioBuffer().fromArray(ramp);\n\t\t\t\tconst player = new Player(playerBuff).toDestination();\n\t\t\t\tplayer.start(0);\n\t\t\t\tplayer.start(0.1);\n\t\t\t}, 0.31);\n\t\t\texpect(buff.max()).to.be.lessThan(1);\n\t\t});\n\n\t\tit(\"only seeks if player is started\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new Player(buffer).toDestination();\n\t\t\t\tplayer.seek(0.2, 0.01);\n\t\t\t}, 0.05);\n\t\t\texpect(buff.isSilent()).to.be.true;\n\t\t});\n\n\t\tit(\"seeking updates stopped state\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst player = new Player(buffer).toDestination();\n\t\t\t\tplayer.start(0);\n\t\t\t\tplayer.seek(buffer.duration * 0.75, 0.5);\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, 0.5, () => {\n\t\t\t\t\t\texpect(player.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.5, 0.5 + buffer.duration * 0.25, () => {\n\t\t\t\t\t\texpect(player.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(\n\t\t\t\t\t\ttime,\n\t\t\t\t\t\t0.5 + buffer.duration * 0.25,\n\t\t\t\t\t\tInfinity,\n\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\texpect(player.state).to.equal(\"stopped\");\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t\t};\n\t\t\t}, buffer.duration);\n\t\t});\n\n\t\tit(\"can seek to a position at the given time\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst ramp = new Float32Array(\n\t\t\t\t\tMath.floor(getContext().sampleRate * 0.3)\n\t\t\t\t);\n\t\t\t\tfor (let i = 0; i < ramp.length; i++) {\n\t\t\t\t\tramp[i] = (i / ramp.length) * 0.3;\n\t\t\t\t}\n\t\t\t\tconst playerBuff = new ToneAudioBuffer().fromArray(ramp);\n\t\t\t\tconst player = new Player(playerBuff).toDestination();\n\t\t\t\tplayer.start(0);\n\t\t\t\tplayer.seek(0.2, 0.1);\n\t\t\t}, 0.3);\n\t\t\tbuff.forEach((sample, time) => {\n\t\t\t\tif (time < 0.09) {\n\t\t\t\t\texpect(sample).to.be.within(0, 0.1);\n\t\t\t\t} else if (time > 0.1 && time < 0.19) {\n\t\t\t\t\texpect(sample).to.be.within(0.2, 0.3);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"can be play for a specific duration\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer.start(0).stop(0.1);\n\t\t\t\treturn (time_2) => {\n\t\t\t\t\twhenBetween(time_2, 0.1, Infinity, () => {\n\t\t\t\t\t\texpect(player.state).to.equal(\"stopped\");\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time_2, 0, 0.1, () => {\n\t\t\t\t\t\texpect(player.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.3);\n\t\t\tbuff.forEachBetween(\n\t\t\t\t(sample) => {\n\t\t\t\t\texpect(sample).to.equal(0);\n\t\t\t\t},\n\t\t\t\t0.11,\n\t\t\t\t0.15\n\t\t\t);\n\t\t});\n\n\t\tit(\"stops playing if invoked with 'stop' at a sooner time\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer.start(0).stop(0.1).stop(0.05);\n\t\t\t}, 0.3);\n\t\t\texpect(buff.getTimeOfLastSound()).to.be.closeTo(0.05, 0.02);\n\t\t});\n\n\t\tit(\"stops playing if at the last scheduled 'stop' time\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer\n\t\t\t\t\t.start(0, 0, 0.05)\n\t\t\t\t\t.start(0.1, 0, 0.05)\n\t\t\t\t\t.start(0.2, 0, 0.05);\n\t\t\t\tplayer.stop(0.1);\n\t\t\t}, 0.3);\n\t\t\texpect(buff.getTimeOfLastSound()).to.be.closeTo(0.1, 0.02);\n\t\t});\n\n\t\tit(\"can retrigger multiple sources which all stop at the stop time\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer.loop = true;\n\t\t\t\tplayer.start(0).start(0.1).start(0.2).stop(0.25);\n\t\t\t}, 0.4);\n\t\t\texpect(buff.getTimeOfLastSound()).to.be.closeTo(0.25, 0.02);\n\t\t});\n\n\t\tit(\"can be play for a specific duration passed in the 'start' method\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer.start(0, 0, 0.1);\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0.1, Infinity, () => {\n\t\t\t\t\t\texpect(player.state).to.equal(\"stopped\");\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0, 0.1, () => {\n\t\t\t\t\t\texpect(player.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.3);\n\t\t\texpect(buff.getTimeOfLastSound()).to.be.closeTo(0.1, 0.02);\n\t\t});\n\n\t\tit(\"reports itself as stopped after a single iterations of the buffer\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst player = new Player(buffer).toDestination();\n\t\t\t\tplayer.start();\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, buffer.duration, Infinity, () => {\n\t\t\t\t\t\texpect(player.state).to.equal(\"stopped\");\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0, buffer.duration, () => {\n\t\t\t\t\t\texpect(player.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, buffer.duration * 1.1);\n\t\t});\n\n\t\tit(\"plays synced to the Transport\", async () => {\n\t\t\tconst buff = await Offline(({ transport }) => {\n\t\t\t\tconst player = new Player(buffer)\n\t\t\t\t\t.sync()\n\t\t\t\t\t.start(0)\n\t\t\t\t\t.toDestination();\n\t\t\t\ttransport.start(0);\n\t\t\t}, 0.05);\n\t\t\texpect(buff.isSilent()).to.be.false;\n\t\t});\n\n\t\tit(\"does not play twice when the offset is very small\", () => {\n\t\t\t// addresses #999 and #944\n\t\t\treturn CompareToFile(\n\t\t\t\t() => {\n\t\t\t\t\tconst player = new Player(buffer).toDestination();\n\t\t\t\t\tplayer.sync().start(0);\n\t\t\t\t\tgetContext().transport.bpm.value = 125;\n\t\t\t\t\tgetContext().transport.setLoopPoints(0, \"1:0:0\");\n\t\t\t\t\tgetContext().transport.loop = true;\n\t\t\t\t\tgetContext().transport.start(0);\n\t\t\t\t},\n\t\t\t\t\"playerSyncLoop.wav\",\n\t\t\t\t0.01\n\t\t\t);\n\t\t});\n\n\t\tit(\"offsets correctly when started by the Transport\", async () => {\n\t\t\tconst testSample =\n\t\t\t\tbuffer.toArray(0)[\n\t\t\t\t\tMath.floor(0.13125 * getContext().sampleRate)\n\t\t\t\t];\n\t\t\tconst buff = await Offline(({ transport }) => {\n\t\t\t\tconst player = new Player(buffer)\n\t\t\t\t\t.sync()\n\t\t\t\t\t.start(0, 0.1)\n\t\t\t\t\t.toDestination();\n\t\t\t\ttransport.start(0, 0.03125);\n\t\t\t}, 0.05);\n\t\t\texpect(buff.toArray()[0][0]).to.equal(testSample);\n\t\t});\n\n\t\tit(\"starts at the correct position when Transport is offset and playbackRate is not 1\", async () => {\n\t\t\tconst buff = await Offline(({ transport }) => {\n\t\t\t\t// make a ramp between 0-1\n\t\t\t\tconst ramp = new Float32Array(\n\t\t\t\t\tMath.floor(getContext().sampleRate * 0.3)\n\t\t\t\t);\n\t\t\t\tfor (let i = 0; i < ramp.length; i++) {\n\t\t\t\t\tramp[i] = i / ramp.length;\n\t\t\t\t}\n\t\t\t\tconst playerBuff = ToneAudioBuffer.fromArray(ramp);\n\t\t\t\tconst player = new Player(playerBuff).toDestination();\n\t\t\t\tplayer.playbackRate = 0.5;\n\t\t\t\tplayer.sync().start(0);\n\t\t\t\t// start halfway through\n\t\t\t\ttransport.start(0, 0.15);\n\t\t\t}, 0.05);\n\t\t\texpect(buff.getValueAtTime(0)).to.be.closeTo(0.5, 0.05);\n\t\t});\n\n\t\tit(\"starts with an offset when synced and started after Transport is running\", async () => {\n\t\t\tconst buff = await Offline(({ transport }) => {\n\t\t\t\tconst ramp = new Float32Array(\n\t\t\t\t\tMath.floor(getContext().sampleRate * 0.3)\n\t\t\t\t);\n\t\t\t\tfor (let i = 0; i < ramp.length; i++) {\n\t\t\t\t\tramp[i] = (i / ramp.length) * 0.3;\n\t\t\t\t}\n\t\t\t\tconst playerBuff = new ToneAudioBuffer().fromArray(ramp);\n\t\t\t\tconst player = new Player(playerBuff).toDestination();\n\t\t\t\ttransport.start(0);\n\t\t\t\treturn atTime(0.1, () => {\n\t\t\t\t\tplayer.sync().start(0);\n\t\t\t\t});\n\t\t\t}, 0.3);\n\t\t\texpect(buff.getValueAtTime(0)).to.equal(0);\n\t\t\texpect(buff.getValueAtTime(0.05)).to.equal(0);\n\t\t\texpect(buff.getValueAtTime(0.11)).to.be.closeTo(0.11, 0.01);\n\t\t\texpect(buff.getValueAtTime(0.2)).to.be.closeTo(0.2, 0.01);\n\t\t});\n\n\t\tit(\"can pass in an offset when synced and started after Transport is running\", async () => {\n\t\t\tconst buff = await Offline(({ transport }) => {\n\t\t\t\tconst ramp = new Float32Array(\n\t\t\t\t\tMath.floor(getContext().sampleRate * 0.3)\n\t\t\t\t);\n\t\t\t\tfor (let i = 0; i < ramp.length; i++) {\n\t\t\t\t\tramp[i] = (i / ramp.length) * 0.3;\n\t\t\t\t}\n\t\t\t\tconst playerBuff = new ToneAudioBuffer().fromArray(ramp);\n\t\t\t\tconst player = new Player(playerBuff).toDestination();\n\t\t\t\tplayer.loop = true;\n\t\t\t\ttransport.start(0);\n\t\t\t\treturn atTime(0.1, () => {\n\t\t\t\t\tplayer.sync().start(0, 0.1);\n\t\t\t\t});\n\t\t\t}, 0.3);\n\t\t\texpect(buff.getValueAtTime(0)).to.equal(0);\n\t\t\texpect(buff.getValueAtTime(0.05)).to.equal(0);\n\t\t\texpect(buff.getValueAtTime(0.11)).to.be.closeTo(0.21, 0.01);\n\t\t\texpect(buff.getValueAtTime(0.15)).to.be.closeTo(0.25, 0.01);\n\t\t\texpect(buff.getValueAtTime(0.2)).to.be.closeTo(0.0, 0.01);\n\t\t\texpect(buff.getValueAtTime(0.25)).to.be.closeTo(0.05, 0.01);\n\t\t});\n\n\t\tit(\"fades in and out correctly\", async () => {\n\t\t\tlet duration = 0.5;\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst onesArray = new Float32Array(\n\t\t\t\t\tgetContext().sampleRate * duration\n\t\t\t\t);\n\t\t\t\tonesArray.forEach((sample, index) => {\n\t\t\t\t\tonesArray[index] = 1;\n\t\t\t\t});\n\t\t\t\tconst onesBuffer = ToneAudioBuffer.fromArray(onesArray);\n\t\t\t\tconst player = new Player({\n\t\t\t\t\turl: onesBuffer,\n\t\t\t\t\tfadeOut: 0.1,\n\t\t\t\t\tfadeIn: 0.1,\n\t\t\t\t}).toDestination();\n\t\t\t\tplayer.start(0);\n\t\t\t}, 0.6);\n\t\t\texpect(buff.getRmsAtTime(0)).to.be.closeTo(0, 0.1);\n\t\t\texpect(buff.getRmsAtTime(0.05)).to.be.closeTo(0.5, 0.1);\n\t\t\texpect(buff.getRmsAtTime(0.1)).to.be.closeTo(1, 0.1);\n\t\t\tduration -= 0.1;\n\t\t\texpect(buff.getRmsAtTime(duration)).to.be.closeTo(1, 0.1);\n\t\t\texpect(buff.getRmsAtTime(duration + 0.05)).to.be.closeTo(0.5, 0.1);\n\t\t\texpect(buff.getRmsAtTime(duration + 0.1)).to.be.closeTo(0, 0.1);\n\t\t});\n\n\t\tit(\"stops only last activeSource when restarting at intervals < latencyHint\", (done) => {\n\t\t\tconst originalLookAhead = getContext().lookAhead;\n\t\t\tgetContext().lookAhead = 0.3;\n\t\t\tconst player = new Player({\n\t\t\t\tonload(): void {\n\t\t\t\t\tplayer.start(undefined, undefined, 1);\n\t\t\t\t\tsetTimeout(\n\t\t\t\t\t\t() => player.restart(undefined, undefined, 1),\n\t\t\t\t\t\t50\n\t\t\t\t\t);\n\t\t\t\t\tsetTimeout(\n\t\t\t\t\t\t() => player.restart(undefined, undefined, 1),\n\t\t\t\t\t\t100\n\t\t\t\t\t);\n\t\t\t\t\tsetTimeout(\n\t\t\t\t\t\t() => player.restart(undefined, undefined, 1),\n\t\t\t\t\t\t150\n\t\t\t\t\t);\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tplayer.restart(undefined, undefined, 1);\n\t\t\t\t\t\tconst checkStopTimes = new Set();\n\t\t\t\t\t\t// @ts-ignore\n\t\t\t\t\t\tplayer._activeSources.forEach((source) => {\n\t\t\t\t\t\t\t// @ts-ignore\n\t\t\t\t\t\t\tcheckStopTimes.add(source._stopTime);\n\t\t\t\t\t\t});\n\t\t\t\t\t\tgetContext().lookAhead = originalLookAhead;\n\t\t\t\t\t\t// ensure each source has a different stopTime\n\t\t\t\t\t\texpect(checkStopTimes.size).to.equal(\n\t\t\t\t\t\t\t// @ts-ignore\n\t\t\t\t\t\t\tplayer._activeSources.size\n\t\t\t\t\t\t);\n\t\t\t\t\t\tdone();\n\t\t\t\t\t}, 250);\n\t\t\t\t},\n\t\t\t\turl: \"./test/audio/sine.wav\",\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"progress\", () => {\n\t\tit(\"can get the progress of the player\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.start(0);\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, buffer.duration, () => {\n\t\t\t\t\t\texpect(player.progress).to.be.closeTo(time, 0.01);\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, buffer.duration, Infinity, () => {\n\t\t\t\t\t\texpect(player.progress).to.equal(0);\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, buffer.duration * 1.1);\n\t\t});\n\n\t\tit(\"progress goes back to 0 when the player loops\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.loop = true;\n\t\t\t\tplayer.start(0);\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, buffer.duration, () => {\n\t\t\t\t\t\texpect(player.progress).to.be.closeTo(time, 0.01);\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(\n\t\t\t\t\t\ttime,\n\t\t\t\t\t\tbuffer.duration,\n\t\t\t\t\t\tbuffer.duration * 2,\n\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\texpect(player.progress).to.be.closeTo(\n\t\t\t\t\t\t\t\ttime - buffer.duration,\n\t\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t\t};\n\t\t\t}, buffer.duration * 2);\n\t\t});\n\n\t\tit(\"loops between loopStart and loopEnd\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.loop = true;\n\t\t\t\tplayer.loopStart = 0.1;\n\t\t\t\tplayer.loopEnd = 0.9;\n\t\t\t\tplayer.start(0);\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, 0.8, () => {\n\t\t\t\t\t\texpect(player.progress).to.be.closeTo(time + 0.1, 0.01);\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.8, 1.6, () => {\n\t\t\t\t\t\texpect(player.progress).to.be.closeTo(time - 0.7, 0.01);\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 1.6, 2.4, () => {\n\t\t\t\t\t\texpect(player.progress).to.be.closeTo(time - 1.5, 0.01);\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 2.4);\n\t\t});\n\n\t\tit(\"progress updates at the rate of the playbackRate\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.playbackRate = 2;\n\t\t\t\tplayer.start(0);\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, buffer.duration / 2, () => {\n\t\t\t\t\t\texpect(player.progress).to.be.closeTo(time * 2, 0.01);\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, buffer.duration / 2, Infinity, () => {\n\t\t\t\t\t\texpect(player.progress).to.be.equal(0);\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, buffer.duration);\n\t\t});\n\n\t\tit(\"playbackRate can be changed after start\", async () => {\n\t\t\tlet playbackRateChanged = false;\n\t\t\tawait Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.start(0);\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, buffer.duration * 0.5, () => {\n\t\t\t\t\t\texpect(player.progress).to.be.closeTo(time, 0.01);\n\t\t\t\t\t});\n\t\t\t\t\tif (!playbackRateChanged && time > buffer.duration * 0.5) {\n\t\t\t\t\t\tplaybackRateChanged = true;\n\t\t\t\t\t\tplayer.playbackRate = 2;\n\t\t\t\t\t}\n\t\t\t\t\t// after the playbackRate is changed, the progress should move half as fast\n\t\t\t\t\twhenBetween(\n\t\t\t\t\t\ttime,\n\t\t\t\t\t\tbuffer.duration * 0.5,\n\t\t\t\t\t\tbuffer.duration * 0.75,\n\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\tconst timeAfterHalf = time - buffer.duration * 0.5;\n\t\t\t\t\t\t\texpect(player.progress).to.be.closeTo(\n\t\t\t\t\t\t\t\tbuffer.duration * 0.5 + timeAfterHalf * 2,\n\t\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\n\t\t\t\t\twhenBetween(time, buffer.duration * 0.75, Infinity, () => {\n\t\t\t\t\t\texpect(player.progress).to.be.equal(0);\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, buffer.duration);\n\t\t});\n\n\t\tit(\"can start at an offset\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.start(0, buffer.duration / 2);\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0.01, buffer.duration / 2, () => {\n\t\t\t\t\t\texpect(player.progress).to.be.closeTo(\n\t\t\t\t\t\t\ttime + buffer.duration / 2,\n\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, buffer.duration / 2, Infinity, () => {\n\t\t\t\t\t\texpect(player.progress).to.be.equal(0);\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, buffer.duration);\n\t\t});\n\n\t\tit(\"can seek to a new position\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.start(0);\n\t\t\t\tplayer.seek(0, buffer.duration / 2);\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, buffer.duration * 0.5, () => {\n\t\t\t\t\t\texpect(player.progress).to.be.closeTo(time, 0.01);\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(\n\t\t\t\t\t\ttime,\n\t\t\t\t\t\tbuffer.duration * 0.5,\n\t\t\t\t\t\tbuffer.duration * 1.5,\n\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\texpect(player.progress).to.be.closeTo(\n\t\t\t\t\t\t\t\ttime - buffer.duration * 0.5,\n\t\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t\t\twhenBetween(time, buffer.duration * 1.5, Infinity, () => {\n\t\t\t\t\t\texpect(player.progress).to.be.equal(0);\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, buffer.duration * 2);\n\t\t});\n\n\t\tit(\"can start and stop multiple times\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.start(0);\n\t\t\t\tplayer.stop(0.1);\n\t\t\t\tplayer.start(0.2, buffer.duration / 2);\n\t\t\t\tplayer.stop(0.3);\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, 0.1, () => {\n\t\t\t\t\t\texpect(player.progress).to.be.closeTo(time, 0.01);\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.1, 0.2, () => {\n\t\t\t\t\t\texpect(player.progress).to.equal(0);\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.2, 0.3, () => {\n\t\t\t\t\t\texpect(player.progress).to.be.closeTo(\n\t\t\t\t\t\t\ttime - 0.2 + buffer.duration / 2,\n\t\t\t\t\t\t\t0.01\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.3, 0.4, () => {\n\t\t\t\t\t\texpect(player.progress).to.equal(0);\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.4);\n\t\t});\n\n\t\tit(\"can seek multiple times\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst player = new Player(buffer);\n\t\t\t\tplayer.start(0);\n\t\t\t\tplayer.seek(1, 0.5);\n\t\t\t\tplayer.seek(0, 1);\n\t\t\t\tplayer.seek(1.5, 1.5);\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, 0.5, () => {\n\t\t\t\t\t\texpect(player.progress).to.be.closeTo(time, 0.01);\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.5, 1, () => {\n\t\t\t\t\t\texpect(player.progress).to.be.closeTo(time + 0.5, 0.01);\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 1, 1.5, () => {\n\t\t\t\t\t\texpect(player.progress).to.be.closeTo(time - 1, 0.01);\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 1.5, buffer.duration, () => {\n\t\t\t\t\t\texpect(player.progress).to.be.closeTo(time, 0.01);\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, buffer.duration, Infinity, () => {\n\t\t\t\t\t\texpect(player.progress).to.equal(0);\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 3);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/source/buffer/Player.ts",
    "content": "import { TickParam } from \"../../core/clock/TickParam.js\";\nimport { ToneAudioBuffer } from \"../../core/context/ToneAudioBuffer.js\";\nimport { Positive, Seconds, Time } from \"../../core/type/Units.js\";\nimport { assertRange } from \"../../core/util/Debug.js\";\nimport { timeRange } from \"../../core/util/Decorator.js\";\nimport { defaultArg, optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { noOp } from \"../../core/util/Interface.js\";\nimport { Timeline } from \"../../core/util/Timeline.js\";\nimport { isUndef } from \"../../core/util/TypeCheck.js\";\nimport { ToneConstantSource } from \"../../signal/ToneConstantSource.js\";\nimport { Source, SourceOptions } from \"../Source.js\";\nimport { ToneBufferSource } from \"./ToneBufferSource.js\";\n\nexport interface PlayerOptions extends SourceOptions {\n\tonload: () => void;\n\tonerror: (error: Error) => void;\n\tplaybackRate: Positive;\n\tloop: boolean;\n\tautostart: boolean;\n\tloopStart: Time;\n\tloopEnd: Time;\n\treverse: boolean;\n\tfadeIn: Time;\n\tfadeOut: Time;\n\turl?: ToneAudioBuffer | string | AudioBuffer;\n}\n\n/**\n * Player is an audio file player with start, loop, and stop functions.\n * @example\n * const player = new Tone.Player(\"https://tonejs.github.io/audio/berklee/gong_1.mp3\").toDestination();\n * // play as soon as the buffer is loaded\n * player.autostart = true;\n * @category Source\n */\nexport class Player extends Source<PlayerOptions> {\n\treadonly name: string = \"Player\";\n\n\t/**\n\t * If the file should play as soon\n\t * as the buffer is loaded.\n\t */\n\tautostart: boolean;\n\n\t/**\n\t * The buffer\n\t */\n\tprivate _buffer: ToneAudioBuffer;\n\n\t/**\n\t * if the buffer should loop once its over\n\t */\n\tprivate _loop: boolean;\n\n\t/**\n\t * if 'loop' is true, the loop will start at this position\n\t */\n\tprivate _loopStart: Time;\n\n\t/**\n\t * if 'loop' is true, the loop will end at this position\n\t */\n\tprivate _loopEnd: Time;\n\n\t/**\n\t * the playback rate\n\t */\n\tprivate _playbackRate: Positive;\n\n\t/**\n\t * All of the active buffer source nodes\n\t */\n\tprivate _activeSources: Set<ToneBufferSource> = new Set();\n\n\t/**\n\t * Used as the source of the TickParam, but not started or used for anything else.\n\t */\n\tprivate _constantSource = new ToneConstantSource({\n\t\tcontext: this.context,\n\t\tunits: \"hertz\",\n\t\toffset: 0,\n\t});\n\n\t/**\n\t * Used to track the progress of the player.\n\t */\n\tprivate _progressTracker = new TickParam({\n\t\tcontext: this.context,\n\t\tunits: \"hertz\",\n\t\tvalue: 0,\n\t\tparam: this._constantSource.offset,\n\t});\n\n\t/**\n\t * Combined with the _progressTracker param to track the progress of the player in seconds.\n\t */\n\tprivate _progressOffset = new Timeline<{\n\t\ttime: Seconds;\n\t\tseek: Seconds;\n\t}>(Infinity);\n\n\t/**\n\t * The fadeIn time of the amplitude envelope.\n\t */\n\t@timeRange(0)\n\tfadeIn: Time;\n\n\t/**\n\t * The fadeOut time of the amplitude envelope.\n\t */\n\t@timeRange(0)\n\tfadeOut: Time;\n\n\t/**\n\t * @param url Either the AudioBuffer or the url from which to load the AudioBuffer\n\t * @param onload The function to invoke when the buffer is loaded.\n\t */\n\tconstructor(\n\t\turl?: string | AudioBuffer | ToneAudioBuffer,\n\t\tonload?: () => void\n\t);\n\tconstructor(options?: Partial<PlayerOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(Player.getDefaults(), arguments, [\n\t\t\t\"url\",\n\t\t\t\"onload\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis._buffer = new ToneAudioBuffer({\n\t\t\tonload: this._onload.bind(this, options.onload),\n\t\t\tonerror: options.onerror,\n\t\t\treverse: options.reverse,\n\t\t\turl: options.url,\n\t\t});\n\t\tthis.autostart = options.autostart;\n\t\tthis._loop = options.loop;\n\t\tthis._loopStart = options.loopStart;\n\t\tthis._loopEnd = options.loopEnd;\n\t\tthis._playbackRate = options.playbackRate;\n\t\tthis.fadeIn = options.fadeIn;\n\t\tthis.fadeOut = options.fadeOut;\n\t}\n\n\tstatic getDefaults(): PlayerOptions {\n\t\treturn Object.assign(Source.getDefaults(), {\n\t\t\tautostart: false,\n\t\t\tfadeIn: 0,\n\t\t\tfadeOut: 0,\n\t\t\tloop: false,\n\t\t\tloopEnd: 0,\n\t\t\tloopStart: 0,\n\t\t\tonload: noOp,\n\t\t\tonerror: noOp,\n\t\t\tplaybackRate: 1,\n\t\t\treverse: false,\n\t\t});\n\t}\n\n\t/**\n\t * Load the audio file as an audio buffer.\n\t * Decodes the audio asynchronously and invokes\n\t * the callback once the audio buffer loads.\n\t * Note: this does not need to be called if a url\n\t * was passed in to the constructor. Only use this\n\t * if you want to manually load a new url.\n\t * @param url The url of the buffer to load. Filetype support depends on the browser.\n\t */\n\tasync load(url: string): Promise<this> {\n\t\tawait this._buffer.load(url);\n\t\tthis._onload();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Internal method to get the progress at a specific time.\n\t * @param time The time to evaluate the progress at.\n\t */\n\tprivate _getProgressAtTime(time: Seconds): Seconds {\n\t\tconst state = this._state.getValueAtTime(time);\n\t\tif (state === \"stopped\") {\n\t\t\treturn 0;\n\t\t}\n\t\tconst startTime = this._state.getLastState(\"started\", time)!;\n\n\t\t// sum all of the offsets between the start time and the time\n\t\tlet seeksSinceStart = 0;\n\t\tthis._progressOffset.forEachBetween(startTime.time, time, (event) => {\n\t\t\tseeksSinceStart += event.seek;\n\t\t});\n\t\tconst progress =\n\t\t\tthis._progressTracker.getTicksAtTime(time) + seeksSinceStart;\n\t\tif (this._loop) {\n\t\t\tconst loopEnd =\n\t\t\t\tthis.loopEnd === 0\n\t\t\t\t\t? this.buffer.duration\n\t\t\t\t\t: this.toSeconds(this.loopEnd);\n\t\t\tconst loopStart = this.toSeconds(this.loopStart);\n\t\t\tconst duration = loopEnd - loopStart;\n\t\t\treturn (progress % duration) + loopStart;\n\t\t}\n\n\t\treturn progress;\n\t}\n\n\t/**\n\t * Displays the elapsed seconds since the player was started, taking into account playbackRate changes.\n\t * @example\n\t * const player = new Tone.Player(\"https://tonejs.github.io/audio/berklee/gong_1.mp3\", () => {\n\t * \tplayer.start();\n\t * \tsetInterval(() => {\n\t * \t\tconsole.log(player.progress);\n\t * \t}, 100);\n\t * }).toDestination();\n\t */\n\tget progress(): Seconds {\n\t\tconst now = this.now();\n\t\treturn this._getProgressAtTime(now);\n\t}\n\n\t/**\n\t * Internal callback when the buffer is loaded.\n\t */\n\tprivate _onload(callback: () => void = noOp): void {\n\t\tcallback();\n\t\tif (this.autostart) {\n\t\t\tthis.start();\n\t\t}\n\t}\n\n\t/**\n\t * Internal callback when the buffer is done playing.\n\t */\n\tprivate _onSourceEnd(source: ToneBufferSource): void {\n\t\t// invoke the onstop function\n\t\tthis.onstop(this);\n\n\t\t// delete the source from the active sources\n\t\tthis._activeSources.delete(source);\n\t\tif (\n\t\t\tthis._activeSources.size === 0 &&\n\t\t\t!this._synced &&\n\t\t\tthis._state.getValueAtTime(this.now()) === \"started\"\n\t\t) {\n\t\t\t// remove the 'implicitEnd' event and replace with an explicit end\n\t\t\tthis._state.cancel(this.now());\n\t\t\tthis._state.setStateAtTime(\"stopped\", this.now());\n\t\t}\n\t}\n\n\t/**\n\t * Play the buffer at the given startTime. Optionally add an offset\n\t * and/or duration which will play the buffer from a position\n\t * within the buffer for the given duration.\n\t *\n\t * @param  time When the player should start.\n\t * @param  offset The offset from the beginning of the sample to start at.\n\t * @param  duration How long the sample should play. If no duration is given, it will default to the full length of the sample (minus any offset)\n\t */\n\tstart(time?: Time, offset?: Time, duration?: Time): this {\n\t\tsuper.start(time, offset, duration);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Internal start method\n\t */\n\tprotected _start(startTime?: Time, offset?: Time, duration?: Time): void {\n\t\t// if it's a loop the default offset is the loopStart point\n\t\tif (this._loop) {\n\t\t\toffset = defaultArg(offset, this._loopStart);\n\t\t} else {\n\t\t\t// otherwise the default offset is 0\n\t\t\toffset = defaultArg(offset, 0);\n\t\t}\n\n\t\t// compute the values in seconds\n\t\tconst computedOffset = this.toSeconds(offset);\n\n\t\t// compute the duration which is either the passed in duration of the buffer.duration - offset\n\t\tconst origDuration = duration;\n\t\tduration = defaultArg(\n\t\t\tduration,\n\t\t\tMath.max(this._buffer.duration - computedOffset, 0)\n\t\t);\n\t\tlet computedDuration = this.toSeconds(duration);\n\n\t\t// scale it by the playback rate\n\t\tcomputedDuration = computedDuration / this._playbackRate;\n\n\t\t// get the start time\n\t\tstartTime = this.toSeconds(startTime);\n\n\t\t// make the source\n\t\tconst source = new ToneBufferSource({\n\t\t\turl: this._buffer,\n\t\t\tcontext: this.context,\n\t\t\tfadeIn: this.fadeIn,\n\t\t\tfadeOut: this.fadeOut,\n\t\t\tloop: this._loop,\n\t\t\tloopEnd: this._loopEnd,\n\t\t\tloopStart: this._loopStart,\n\t\t\tonended: this._onSourceEnd.bind(this),\n\t\t\tplaybackRate: this._playbackRate,\n\t\t}).connect(this.output);\n\n\t\t// schedule the \"stopped\" state\n\t\tif (!this._loop && !this._synced) {\n\t\t\t// cancel the previous stop\n\t\t\tthis._state.cancel(startTime + computedDuration);\n\t\t\t// if it's not looping, set the state change at the end of the sample\n\t\t\tthis._state.setStateAtTime(\n\t\t\t\t\"stopped\",\n\t\t\t\tstartTime + computedDuration,\n\t\t\t\t{\n\t\t\t\t\timplicitEnd: true,\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\t// add it to the array of active sources\n\t\tthis._activeSources.add(source);\n\n\t\t// used to track the progress of the player\n\t\tconst seekDelta = computedOffset - this._getProgressAtTime(startTime);\n\t\tthis._progressOffset.add({\n\t\t\ttime: startTime,\n\t\t\tseek: seekDelta,\n\t\t});\n\t\tthis._progressTracker.setValueAtTime(this._playbackRate, startTime);\n\n\t\t// start it\n\t\tif (this._loop && isUndef(origDuration)) {\n\t\t\tsource.start(startTime, computedOffset);\n\t\t} else {\n\t\t\t// subtract the fade out time\n\t\t\tsource.start(\n\t\t\t\tstartTime,\n\t\t\t\tcomputedOffset,\n\t\t\t\tcomputedDuration - this.toSeconds(this.fadeOut)\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Stop playback.\n\t */\n\tprotected _stop(time?: Time): void {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tthis._activeSources.forEach((source) => source.stop(computedTime));\n\t\tthis._progressTracker.setValueAtTime(0, computedTime);\n\t}\n\n\t/**\n\t * Stop and then restart the player from the beginning (or offset)\n\t * @param  time When the player should start.\n\t * @param  offset The offset from the beginning of the sample to start at.\n\t * @param  duration How long the sample should play. If no duration is given,\n\t * \t\t\t\t\tit will default to the full length of the sample (minus any offset)\n\t */\n\trestart(time?: Seconds, offset?: Time, duration?: Time): this {\n\t\tsuper.restart(time, offset, duration);\n\t\treturn this;\n\t}\n\n\tprotected _restart(time?: Seconds, offset?: Time, duration?: Time): void {\n\t\t[...this._activeSources].pop()?.stop(time); // explicitly stop only the most recently created source, to avoid edge case when > 1 source exists and _stop() erroneously sets all stop times past original end offset\n\t\tthis._start(time, offset, duration);\n\t}\n\n\t/**\n\t * Seek to a specific time in the player's buffer. If the\n\t * source is no longer playing at that time, it will stop.\n\t * @param offset The time to seek to.\n\t * @param when The time for the seek event to occur.\n\t * @example\n\t * const player = new Tone.Player(\"https://tonejs.github.io/audio/berklee/gurgling_theremin_1.mp3\", () => {\n\t * \tplayer.start();\n\t * \t// seek to the offset in 1 second from now\n\t * \tplayer.seek(0.4, \"+1\");\n\t * }).toDestination();\n\t */\n\tseek(offset: Time, when?: Time): this {\n\t\tconst computedTime = this.toSeconds(when);\n\t\tif (this._state.getValueAtTime(computedTime) === \"started\") {\n\t\t\tconst computedOffset = this.toSeconds(offset);\n\t\t\t// if it's currently playing, stop it\n\t\t\tthis._stop(computedTime);\n\t\t\t// remove the stop event\n\t\t\tthis._state.cancel(computedTime);\n\t\t\t// restart it at the given time\n\t\t\tthis._start(computedTime, computedOffset);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set the loop start and end. Will only loop if loop is set to true.\n\t * @param loopStart The loop start time\n\t * @param loopEnd The loop end time\n\t * @example\n\t * const player = new Tone.Player(\"https://tonejs.github.io/audio/berklee/malevoices_aa2_F3.mp3\").toDestination();\n\t * // loop between the given points\n\t * player.setLoopPoints(0.2, 0.3);\n\t * player.loop = true;\n\t * player.autostart = true;\n\t */\n\tsetLoopPoints(loopStart: Time, loopEnd: Time): this {\n\t\tthis.loopStart = loopStart;\n\t\tthis.loopEnd = loopEnd;\n\t\treturn this;\n\t}\n\n\t/**\n\t * If loop is true, the loop will start at this position.\n\t */\n\tget loopStart(): Time {\n\t\treturn this._loopStart;\n\t}\n\tset loopStart(loopStart) {\n\t\tthis._loopStart = loopStart;\n\t\tif (this.buffer.loaded) {\n\t\t\tassertRange(this.toSeconds(loopStart), 0, this.buffer.duration);\n\t\t}\n\t\t// get the current source\n\t\tthis._activeSources.forEach((source) => {\n\t\t\tsource.loopStart = loopStart;\n\t\t});\n\t}\n\n\t/**\n\t * If loop is true, the loop will end at this position.\n\t */\n\tget loopEnd(): Time {\n\t\treturn this._loopEnd;\n\t}\n\tset loopEnd(loopEnd) {\n\t\tthis._loopEnd = loopEnd;\n\t\tif (this.buffer.loaded) {\n\t\t\tassertRange(this.toSeconds(loopEnd), 0, this.buffer.duration);\n\t\t}\n\t\t// get the current source\n\t\tthis._activeSources.forEach((source) => {\n\t\t\tsource.loopEnd = loopEnd;\n\t\t});\n\t}\n\n\t/**\n\t * The audio buffer belonging to the player.\n\t */\n\tget buffer(): ToneAudioBuffer {\n\t\treturn this._buffer;\n\t}\n\tset buffer(buffer) {\n\t\tthis._buffer.set(buffer);\n\t}\n\n\t/**\n\t * If the buffer should loop once its over.\n\t * @example\n\t * const player = new Tone.Player(\"https://tonejs.github.io/audio/drum-samples/breakbeat.mp3\").toDestination();\n\t * player.loop = true;\n\t * player.autostart = true;\n\t */\n\tget loop(): boolean {\n\t\treturn this._loop;\n\t}\n\tset loop(loop) {\n\t\t// if no change, do nothing\n\t\tif (this._loop === loop) {\n\t\t\treturn;\n\t\t}\n\t\tthis._loop = loop;\n\t\t// set the loop of all of the sources\n\t\tthis._activeSources.forEach((source) => {\n\t\t\tsource.loop = loop;\n\t\t});\n\t\tif (loop) {\n\t\t\t// remove the next stopEvent\n\t\t\tconst stopEvent = this._state.getNextState(\"stopped\", this.now());\n\t\t\tif (stopEvent) {\n\t\t\t\tthis._state.cancel(stopEvent.time);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Normal speed is 1. The pitch will change with the playback rate.\n\t * @example\n\t * const player = new Tone.Player(\"https://tonejs.github.io/audio/berklee/femalevoices_aa2_A5.mp3\").toDestination();\n\t * // play at 1/4 speed\n\t * player.playbackRate = 0.25;\n\t * // play as soon as the buffer is loaded\n\t * player.autostart = true;\n\t */\n\tget playbackRate(): Positive {\n\t\treturn this._playbackRate;\n\t}\n\tset playbackRate(rate) {\n\t\tthis._playbackRate = rate;\n\t\tconst now = this.now();\n\t\tthis._progressTracker.setValueAtTime(rate, now);\n\n\t\t// cancel the stop event since it's at a different time now\n\t\tconst stopEvent = this._state.getNextState(\"stopped\", now);\n\t\tif (stopEvent && stopEvent.implicitEnd) {\n\t\t\tthis._state.cancel(stopEvent.time);\n\t\t\tthis._activeSources.forEach((source) => source.cancelStop());\n\n\t\t\tconst progress = this._getProgressAtTime(now);\n\t\t\tconst remainingTime = this._buffer.duration - progress;\n\t\t\tconst newStopTime = now + remainingTime / rate;\n\t\t\t// reschedule the implicit stop event\n\t\t\tthis._state.setStateAtTime(\"stopped\", newStopTime, {\n\t\t\t\timplicitEnd: true,\n\t\t\t});\n\t\t}\n\n\t\t// set all the sources\n\t\tthis._activeSources.forEach((source) => {\n\t\t\tsource.playbackRate.setValueAtTime(rate, now);\n\t\t});\n\t}\n\n\t/**\n\t * If the buffer should be reversed. Note that this sets the underlying {@link ToneAudioBuffer.reverse}, so\n\t * if multiple players are pointing at the same ToneAudioBuffer, they will all be reversed.\n\t * @example\n\t * const player = new Tone.Player(\"https://tonejs.github.io/audio/berklee/chime_1.mp3\").toDestination();\n\t * player.autostart = true;\n\t * player.reverse = true;\n\t */\n\tget reverse(): boolean {\n\t\treturn this._buffer.reverse;\n\t}\n\tset reverse(rev) {\n\t\tthis._buffer.reverse = rev;\n\t}\n\n\t/**\n\t * If the buffer is loaded\n\t */\n\tget loaded(): boolean {\n\t\treturn this._buffer.loaded;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\t// disconnect all of the players\n\t\tthis._activeSources.forEach((source) => source.dispose());\n\t\tthis._activeSources.clear();\n\t\tthis._buffer.dispose();\n\t\tthis._constantSource.dispose();\n\t\tthis._progressTracker.dispose();\n\t\tthis._progressOffset.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/source/buffer/Players.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { OutputAudio } from \"../../../test/helper/OutputAudio.js\";\nimport { ToneAudioBuffer } from \"../../core/context/ToneAudioBuffer.js\";\nimport { getContext } from \"../../core/Global.js\";\nimport { Player } from \"./Player.js\";\nimport { Players } from \"./Players.js\";\n\ndescribe(\"Players\", () => {\n\tconst buffer = new ToneAudioBuffer();\n\n\tbeforeEach(() => {\n\t\treturn buffer.load(\"./test/audio/sine.wav\");\n\t});\n\n\tBasicTests(Players, { test: buffer });\n\n\tcontext(\"Constructor\", () => {\n\t\tit(\"can be constructed with an object containing a ToneAudioBuffer\", () => {\n\t\t\tconst players = new Players({\n\t\t\t\ttest: buffer,\n\t\t\t});\n\t\t\texpect(players.player(\"test\").buffer.get()).to.equal(buffer.get());\n\t\t\tplayers.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an AudioBuffer\", () => {\n\t\t\tconst players = new Players({\n\t\t\t\ttest: buffer.get() as AudioBuffer,\n\t\t\t});\n\t\t\texpect(players.player(\"test\").buffer.get()).to.equal(buffer.get());\n\t\t\tplayers.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with a url\", (done) => {\n\t\t\tconst players = new Players(\n\t\t\t\t{\n\t\t\t\t\ttest0: \"./test/audio/sine.wav\",\n\t\t\t\t\ttest1: \"./test/audio/sine.wav\",\n\t\t\t\t},\n\t\t\t\t() => {\n\t\t\t\t\texpect(players.player(\"test0\")).to.be.instanceOf(Player);\n\t\t\t\t\texpect(players.player(\"test0\").buffer.loaded).to.be.true;\n\t\t\t\t\texpect(players.player(\"test1\")).to.be.instanceOf(Player);\n\t\t\t\t\texpect(players.player(\"test1\").buffer.loaded).to.be.true;\n\t\t\t\t\texpect(players.loaded).to.be.true;\n\t\t\t\t\tplayers.dispose();\n\t\t\t\t\tdone();\n\t\t\t\t}\n\t\t\t);\n\t\t});\n\n\t\tit(\"can pass in additional args in the second parameters\", (done) => {\n\t\t\tconst players = new Players(\n\t\t\t\t{\n\t\t\t\t\ttest: \"./test/audio/sine.wav\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tonload: () => {\n\t\t\t\t\t\texpect(players.player(\"test\").buffer.loaded).to.be.true;\n\t\t\t\t\t\texpect(players.volume.value).to.be.closeTo(-12, 0.1);\n\t\t\t\t\t\tplayers.dispose();\n\t\t\t\t\t\tdone();\n\t\t\t\t\t},\n\t\t\t\t\tvolume: -12,\n\t\t\t\t}\n\t\t\t);\n\t\t});\n\n\t\tit(\"invokes onerror if no url\", (done) => {\n\t\t\tconst source = new Players({\n\t\t\t\turls: {\n\t\t\t\t\ttest: \"./nosuchfile.wav\",\n\t\t\t\t},\n\t\t\t\tonerror() {\n\t\t\t\t\tsource.dispose();\n\t\t\t\t\tdone();\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\n\t\tit(\"can get and set fadeIn/Out\", () => {\n\t\t\tconst players = new Players(\n\t\t\t\t{\n\t\t\t\t\ttest: \"./test/audio/sine.wav\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfadeIn: 0.1,\n\t\t\t\t\tfadeOut: 0.2,\n\t\t\t\t}\n\t\t\t);\n\t\t\texpect(players.fadeIn).to.equal(0.1);\n\t\t\texpect(players.fadeOut).to.equal(0.2);\n\t\t\texpect(players.player(\"test\").fadeIn).to.equal(0.1);\n\t\t\tplayers.fadeIn = 0.2;\n\t\t\tplayers.fadeOut = 0.3;\n\t\t\texpect(players.fadeIn).to.equal(0.2);\n\t\t\texpect(players.fadeOut).to.equal(0.3);\n\t\t\texpect(players.player(\"test\").fadeOut).to.equal(0.3);\n\t\t\tplayers.dispose();\n\t\t});\n\t});\n\n\tcontext(\"get/has/add buffers\", () => {\n\t\tit(\"says it 'has' a sample\", () => {\n\t\t\tconst players = new Players({\n\t\t\t\ttest: buffer,\n\t\t\t});\n\t\t\texpect(players.has(\"test\")).to.be.true;\n\t\t\texpect(players.has(\"nope\")).to.be.false;\n\t\t\tplayers.dispose();\n\t\t});\n\n\t\tit(\"can get a sample\", () => {\n\t\t\tconst players = new Players({\n\t\t\t\ttest: buffer,\n\t\t\t});\n\t\t\texpect(players.player(\"test\")).to.be.instanceOf(Player);\n\t\t\tplayers.dispose();\n\t\t});\n\n\t\tit(\"throws an error if it tries to get a sample which is not there\", () => {\n\t\t\tconst players = new Players({\n\t\t\t\ttest: buffer,\n\t\t\t});\n\t\t\texpect(() => {\n\t\t\t\tplayers.player(\"nope\");\n\t\t\t}).to.throw(Error);\n\t\t\tplayers.dispose();\n\t\t});\n\n\t\tit(\"can add a player with a buffer\", () => {\n\t\t\tconst players = new Players();\n\t\t\texpect(players.has(\"test\")).to.be.false;\n\t\t\tplayers.add(\"test\", buffer);\n\t\t\texpect(players.has(\"test\")).to.be.true;\n\t\t\tplayers.dispose();\n\t\t});\n\n\t\tit(\"can add a player with a url\", (done) => {\n\t\t\tconst players = new Players();\n\t\t\texpect(players.has(\"test\")).to.be.false;\n\t\t\tplayers.add(\"test\", \"./test/audio/sine.wav\", () => {\n\t\t\t\texpect(players.has(\"test\")).to.be.true;\n\t\t\t\tplayers.dispose();\n\t\t\t\tdone();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can add a player with an unloaded ToneAudioBuffer\", (done) => {\n\t\t\tconst players = new Players();\n\t\t\tconst output = new ToneAudioBuffer(\"./test/audio/sine.wav\");\n\t\t\tplayers.add(\"test\", output, () => {\n\t\t\t\texpect(players.has(\"test\")).to.be.true;\n\t\t\t\texpect(players.player(\"test\").loaded).to.be.true;\n\t\t\t\tplayers.dispose();\n\t\t\t\tdone();\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"start/stop players\", () => {\n\t\tit(\"makes a sound\", () => {\n\t\t\treturn OutputAudio(() => {\n\t\t\t\tconst players = new Players({\n\t\t\t\t\ttest: buffer,\n\t\t\t\t}).toDestination();\n\t\t\t\tplayers.player(\"test\").start(0);\n\t\t\t});\n\t\t});\n\t\tit(\"can be muted\", async () => {\n\t\t\tconst output = await Offline(() => {\n\t\t\t\tconst players = new Players({\n\t\t\t\t\ttest: buffer,\n\t\t\t\t}).toDestination();\n\t\t\t\tplayers.player(\"test\").start(0);\n\t\t\t\tplayers.mute = true;\n\t\t\t\texpect(players.mute).to.be.true;\n\t\t\t}, 0.3);\n\t\t\texpect(output.isSilent()).to.be.true;\n\t\t});\n\n\t\tit(\"be scheduled to start in the future\", async () => {\n\t\t\tconst output = await Offline(() => {\n\t\t\t\tconst players = new Players({\n\t\t\t\t\ttest: buffer,\n\t\t\t\t}).toDestination();\n\t\t\t\tplayers.player(\"test\").start(0.1);\n\t\t\t}, 0.3);\n\t\t\toutput.forEach((sample, time) => {\n\t\t\t\tif (sample > 0) {\n\t\t\t\t\texpect(time).to.be.at.least(0.099);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"be scheduled to stop in the future\", async () => {\n\t\t\tconst output = await Offline(() => {\n\t\t\t\tconst players = new Players({\n\t\t\t\t\ttest: buffer,\n\t\t\t\t}).toDestination();\n\t\t\t\tplayers.player(\"test\").start(0).stop(0.2);\n\t\t\t}, 0.3);\n\t\t\toutput.forEach((sample, time) => {\n\t\t\t\tif (time > 0.2) {\n\t\t\t\t\texpect(sample).to.equal(0);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"if any of the players are playing, reports state as 'started'\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst players = new Players({\n\t\t\t\t\ttest0: buffer,\n\t\t\t\t\ttest1: buffer,\n\t\t\t\t}).toDestination();\n\t\t\t\tplayers.player(\"test0\").start(0).stop(0.05);\n\t\t\t\tplayers.player(\"test1\").start(0).stop(0.1);\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time <= 0.1) {\n\t\t\t\t\t\texpect(players.state).to.equal(\"started\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\texpect(players.state).to.equal(\"stopped\");\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.2);\n\t\t});\n\n\t\tit(\"can start multiple samples\", async () => {\n\t\t\tawait OutputAudio(() => {\n\t\t\t\tconst players = new Players({\n\t\t\t\t\ttest0: buffer,\n\t\t\t\t\ttest1: buffer,\n\t\t\t\t}).toDestination();\n\t\t\t\tplayers.player(\"test0\").start(0).stop(0.01);\n\t\t\t\tplayers.player(\"test1\").start(0);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can stop all of the samples in the future\", async () => {\n\t\t\tconst output = await Offline(() => {\n\t\t\t\tconst players = new Players({\n\t\t\t\t\ttest0: buffer,\n\t\t\t\t\ttest1: buffer,\n\t\t\t\t}).toDestination();\n\t\t\t\tplayers.player(\"test0\").start(0);\n\t\t\t\tplayers.player(\"test1\").start(0);\n\t\t\t\tplayers.stopAll(0.2);\n\t\t\t}, 0.3);\n\t\t\toutput.forEach((sample, time) => {\n\t\t\t\tif (time > 0.2) {\n\t\t\t\t\texpect(sample).to.equal(0);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"fades in and out correctly\", async () => {\n\t\t\tconst output = await Offline(() => {\n\t\t\t\tconst onesArray = new Float32Array(\n\t\t\t\t\tgetContext().sampleRate * 0.5\n\t\t\t\t);\n\t\t\t\tonesArray.forEach((sample, index) => {\n\t\t\t\t\tonesArray[index] = 1;\n\t\t\t\t});\n\t\t\t\tconst onesBuffer = ToneAudioBuffer.fromArray(onesArray);\n\t\t\t\tconst players = new Players(\n\t\t\t\t\t{\n\t\t\t\t\t\ttest: onesBuffer,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tfadeIn: 0.1,\n\t\t\t\t\t\tfadeOut: 0.1,\n\t\t\t\t\t}\n\t\t\t\t).toDestination();\n\t\t\t\tplayers.player(\"test\").start(0);\n\t\t\t}, 0.6);\n\t\t\toutput.forEach((sample, time) => {\n\t\t\t\tif (time < 0.1) {\n\t\t\t\t\texpect(sample).to.be.within(0, 1);\n\t\t\t\t} else if (time < 0.4) {\n\t\t\t\t\texpect(sample).to.equal(1);\n\t\t\t\t} else if (time < 0.5) {\n\t\t\t\t\texpect(sample).to.be.within(0, 1);\n\t\t\t\t} else {\n\t\t\t\t\texpect(sample).to.equal(0);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/source/buffer/Players.ts",
    "content": "import { Volume } from \"../../component/channel/Volume.js\";\nimport { Param } from \"../../core/context/Param.js\";\nimport { ToneAudioBuffer } from \"../../core/context/ToneAudioBuffer.js\";\nimport {\n\tToneAudioBuffers,\n\tToneAudioBuffersUrlMap,\n} from \"../../core/context/ToneAudioBuffers.js\";\nimport { OutputNode, ToneAudioNode } from \"../../core/context/ToneAudioNode.js\";\nimport { Decibels, Time } from \"../../core/type/Units.js\";\nimport { assert } from \"../../core/util/Debug.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { noOp, readOnly } from \"../../core/util/Interface.js\";\nimport { BasicPlaybackState } from \"../../core/util/StateTimeline.js\";\nimport { Source, SourceOptions } from \"../Source.js\";\nimport { Player } from \"./Player.js\";\n\nexport interface PlayersOptions extends SourceOptions {\n\turls: ToneAudioBuffersUrlMap;\n\tvolume: Decibels;\n\tmute: boolean;\n\tonload: () => void;\n\tonerror: (error: Error) => void;\n\tbaseUrl: string;\n\tfadeIn: Time;\n\tfadeOut: Time;\n}\n\n/**\n * Players combines multiple {@link Player} objects.\n * @category Source\n */\nexport class Players extends ToneAudioNode<PlayersOptions> {\n\treadonly name: string = \"Players\";\n\n\t/**\n\t * The output volume node\n\t */\n\tprivate _volume: Volume;\n\n\t/**\n\t * The volume of the output in decibels.\n\t */\n\treadonly volume: Param<\"decibels\">;\n\n\t/**\n\t * The combined output of all of the players\n\t */\n\treadonly output: OutputNode;\n\n\t/**\n\t * Players has no input.\n\t */\n\treadonly input = undefined;\n\n\t/**\n\t * The container of all of the players\n\t */\n\tprivate _players: Map<string, Player> = new Map();\n\n\t/**\n\t * The container of all the buffers\n\t */\n\tprivate _buffers: ToneAudioBuffers;\n\n\t/**\n\t * private holder of the fadeIn time\n\t */\n\tprivate _fadeIn: Time;\n\n\t/**\n\t * private holder of the fadeOut time\n\t */\n\tprivate _fadeOut: Time;\n\n\t/**\n\t * @param urls An object mapping a name to a url.\n\t * @param onload The function to invoke when all buffers are loaded.\n\t */\n\tconstructor(urls?: ToneAudioBuffersUrlMap, onload?: () => void);\n\t/**\n\t * @param urls An object mapping a name to a url.\n\t * @param options The remaining options associated with the players\n\t */\n\tconstructor(\n\t\turls?: ToneAudioBuffersUrlMap,\n\t\toptions?: Partial<Omit<PlayersOptions, \"urls\">>\n\t);\n\tconstructor(options?: Partial<PlayersOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tPlayers.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"urls\", \"onload\"],\n\t\t\t\"urls\"\n\t\t);\n\t\tsuper(options);\n\n\t\t/**\n\t\t * The output volume node\n\t\t */\n\t\tthis._volume = this.output = new Volume({\n\t\t\tcontext: this.context,\n\t\t\tvolume: options.volume,\n\t\t});\n\n\t\tthis.volume = this._volume.volume;\n\t\treadOnly(this, \"volume\");\n\t\tthis._buffers = new ToneAudioBuffers({\n\t\t\turls: options.urls,\n\t\t\tonload: options.onload,\n\t\t\tbaseUrl: options.baseUrl,\n\t\t\tonerror: options.onerror,\n\t\t});\n\t\t// mute initially\n\t\tthis.mute = options.mute;\n\t\tthis._fadeIn = options.fadeIn;\n\t\tthis._fadeOut = options.fadeOut;\n\t}\n\n\tstatic getDefaults(): PlayersOptions {\n\t\treturn Object.assign(Source.getDefaults(), {\n\t\t\tbaseUrl: \"\",\n\t\t\tfadeIn: 0,\n\t\t\tfadeOut: 0,\n\t\t\tmute: false,\n\t\t\tonload: noOp,\n\t\t\tonerror: noOp,\n\t\t\turls: {},\n\t\t\tvolume: 0,\n\t\t});\n\t}\n\n\t/**\n\t * Mute the output.\n\t */\n\tget mute(): boolean {\n\t\treturn this._volume.mute;\n\t}\n\tset mute(mute) {\n\t\tthis._volume.mute = mute;\n\t}\n\n\t/**\n\t * The fadeIn time of the envelope applied to the source.\n\t */\n\tget fadeIn(): Time {\n\t\treturn this._fadeIn;\n\t}\n\tset fadeIn(fadeIn) {\n\t\tthis._fadeIn = fadeIn;\n\t\tthis._players.forEach((player) => {\n\t\t\tplayer.fadeIn = fadeIn;\n\t\t});\n\t}\n\n\t/**\n\t * The fadeOut time of the each of the sources.\n\t */\n\tget fadeOut(): Time {\n\t\treturn this._fadeOut;\n\t}\n\tset fadeOut(fadeOut) {\n\t\tthis._fadeOut = fadeOut;\n\t\tthis._players.forEach((player) => {\n\t\t\tplayer.fadeOut = fadeOut;\n\t\t});\n\t}\n\n\t/**\n\t * The state of the players object. Returns \"started\" if any of the players are playing.\n\t */\n\tget state(): BasicPlaybackState {\n\t\tconst playing = Array.from(this._players).some(\n\t\t\t([_, player]) => player.state === \"started\"\n\t\t);\n\t\treturn playing ? \"started\" : \"stopped\";\n\t}\n\n\t/**\n\t * True if the buffers object has a buffer by that name.\n\t * @param name  The key or index of the buffer.\n\t */\n\thas(name: string): boolean {\n\t\treturn this._buffers.has(name);\n\t}\n\n\t/**\n\t * Get a player by name.\n\t * @param  name  The players name as defined in the constructor object or `add` method.\n\t */\n\tplayer(name: string): Player {\n\t\tassert(\n\t\t\tthis.has(name),\n\t\t\t`No Player with the name ${name} exists on this object`\n\t\t);\n\t\tif (!this._players.has(name)) {\n\t\t\tconst player = new Player({\n\t\t\t\tcontext: this.context,\n\t\t\t\tfadeIn: this._fadeIn,\n\t\t\t\tfadeOut: this._fadeOut,\n\t\t\t\turl: this._buffers.get(name),\n\t\t\t}).connect(this.output);\n\t\t\tthis._players.set(name, player);\n\t\t}\n\t\treturn this._players.get(name) as Player;\n\t}\n\n\t/**\n\t * If all the buffers are loaded or not\n\t */\n\tget loaded(): boolean {\n\t\treturn this._buffers.loaded;\n\t}\n\n\t/**\n\t * Add a player by name and url to the Players\n\t * @param  name A unique name to give the player\n\t * @param  url  Either the url of the buffer or a buffer which will be added with the given name.\n\t * @param callback  The callback to invoke when the url is loaded.\n\t * @example\n\t * const players = new Tone.Players();\n\t * players.add(\"gong\", \"https://tonejs.github.io/audio/berklee/gong_1.mp3\", () => {\n\t * \tconsole.log(\"gong loaded\");\n\t * \tplayers.player(\"gong\").start();\n\t * });\n\t */\n\tadd(\n\t\tname: string,\n\t\turl: string | ToneAudioBuffer | AudioBuffer,\n\t\tcallback?: () => void\n\t): this {\n\t\tassert(\n\t\t\t!this._buffers.has(name),\n\t\t\t\"A buffer with that name already exists on this object\"\n\t\t);\n\t\tthis._buffers.add(name, url, callback);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop all of the players at the given time\n\t * @param time The time to stop all of the players.\n\t */\n\tstopAll(time?: Time): this {\n\t\tthis._players.forEach((player) => player.stop(time));\n\t\treturn this;\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._volume.dispose();\n\t\tthis.volume.dispose();\n\t\tthis._players.forEach((player) => player.dispose());\n\t\tthis._buffers.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/source/buffer/ToneBufferSource.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../../test/helper/CompareToFile.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { ToneAudioBuffer } from \"../../core/context/ToneAudioBuffer.js\";\nimport { getContext } from \"../../core/Global.js\";\nimport { ToneBufferSource } from \"./ToneBufferSource.js\";\n\nconst sampleRate = getContext().sampleRate;\n\ndescribe(\"ToneBufferSource\", () => {\n\tconst buffer = new ToneAudioBuffer();\n\n\tconst ones = new Float32Array(sampleRate * 0.5);\n\tones.forEach((sample, index) => (ones[index] = 1));\n\tconst onesBuffer = ToneAudioBuffer.fromArray(ones);\n\n\tbeforeEach(() => {\n\t\treturn buffer.load(\"./test/audio/sine.wav\");\n\t});\n\n\t// run the common tests\n\tBasicTests(ToneBufferSource, buffer);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(() => {\n\t\t\tconst source = new ToneBufferSource(buffer).toDestination();\n\t\t\tsource.start(0).stop(0.2);\n\t\t}, \"bufferSource.wav\");\n\t});\n\n\tcontext(\"Constructor\", () => {\n\t\tit(\"can be constructed with a Tone.Buffer\", () => {\n\t\t\tconst source = new ToneBufferSource(buffer);\n\t\t\texpect(source.buffer.get()).to.equal(buffer.get());\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an AudioBuffer\", () => {\n\t\t\tconst source = new ToneBufferSource(buffer.get());\n\t\t\texpect(source.buffer.get()).to.equal(buffer.get());\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can be created with an options object\", () => {\n\t\t\tconst source = new ToneBufferSource({\n\t\t\t\turl: buffer,\n\t\t\t\tloop: true,\n\t\t\t\tloopEnd: 0.2,\n\t\t\t\tloopStart: 0.1,\n\t\t\t\tplaybackRate: 0.5,\n\t\t\t});\n\t\t\texpect(source.loop).to.equal(true);\n\t\t\texpect(source.loopEnd).to.equal(0.2);\n\t\t\texpect(source.loopStart).to.equal(0.1);\n\t\t\texpect(source.playbackRate.value).to.equal(0.5);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with no arguments\", () => {\n\t\t\tconst source = new ToneBufferSource();\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can set the buffer after construction\", () => {\n\t\t\tconst source = new ToneBufferSource();\n\t\t\texpect(source.buffer.loaded).is.equal(false);\n\t\t\tsource.buffer = buffer;\n\t\t\texpect(source.buffer.loaded).is.equal(true);\n\t\t\tsource.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with a url and onload\", (done) => {\n\t\t\tconst source = new ToneBufferSource(\n\t\t\t\t\"./test/audio/short_sine.wav\",\n\t\t\t\t() => {\n\t\t\t\t\texpect(source.buffer.loaded).is.equal(true);\n\t\t\t\t\tsource.dispose();\n\t\t\t\t\tdone();\n\t\t\t\t}\n\t\t\t);\n\t\t});\n\n\t\tit(\"invokes onerror if no url\", (done) => {\n\t\t\tconst source = new ToneBufferSource({\n\t\t\t\turl: \"./nosuchfile.wav\",\n\t\t\t\tonerror() {\n\t\t\t\t\tsource.dispose();\n\t\t\t\t\tdone();\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\n\t\tit(\"won't start or stop if there is no buffer\", () => {\n\t\t\tconst source = new ToneBufferSource();\n\t\t\texpect(() => {\n\t\t\t\tsource.start();\n\t\t\t}).to.throw(Error);\n\t\t\texpect(() => {\n\t\t\t\tsource.stop();\n\t\t\t}).to.throw(Error);\n\t\t\tsource.dispose();\n\t\t});\n\t});\n\n\tcontext(\"Looping\", () => {\n\t\tbeforeEach(() => {\n\t\t\treturn buffer.load(\"./test/audio/short_sine.wav\");\n\t\t});\n\n\t\tit(\"can be set to loop\", () => {\n\t\t\tconst player = new ToneBufferSource();\n\t\t\tplayer.loop = true;\n\t\t\texpect(player.loop).is.equal(true);\n\t\t\tplayer.dispose();\n\t\t});\n\n\t\tit(\"loops the audio\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer);\n\t\t\t\tplayer.loop = true;\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer.start(0);\n\t\t\t}, buffer.duration * 2);\n\t\t\texpect(buff.getRmsAtTime(0)).to.be.above(0);\n\t\t\texpect(buff.getRmsAtTime(buffer.duration * 0.5)).to.be.above(0);\n\t\t\texpect(buff.getRmsAtTime(buffer.duration)).to.be.above(0);\n\t\t\texpect(buff.getRmsAtTime(buffer.duration * 1.5)).to.be.above(0);\n\t\t});\n\n\t\tit(\"loops the audio when loop is set after 'start'\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer);\n\t\t\t\tplayer.start(0);\n\t\t\t\tplayer.loop = true;\n\t\t\t\tplayer.toDestination();\n\t\t\t}, buffer.duration * 2);\n\t\t\texpect(buff.getRmsAtTime(0)).to.be.above(0);\n\t\t\texpect(buff.getRmsAtTime(buffer.duration * 0.5)).to.be.above(0);\n\t\t\texpect(buff.getRmsAtTime(buffer.duration)).to.be.above(0);\n\t\t\texpect(buff.getRmsAtTime(buffer.duration * 1.5)).to.be.above(0);\n\t\t});\n\n\t\tit(\"unloops the audio when loop is set after 'start'\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer);\n\t\t\t\tplayer.loop = true;\n\t\t\t\tplayer.start(0);\n\t\t\t\tplayer.loop = false;\n\t\t\t\tplayer.toDestination();\n\t\t\t}, buffer.duration * 2);\n\t\t\texpect(buff.getRmsAtTime(0)).to.be.above(0);\n\t\t\texpect(buff.getRmsAtTime(buffer.duration * 0.5)).to.be.above(0);\n\t\t\texpect(buff.getRmsAtTime(buffer.duration)).to.be.closeTo(0, 0.001);\n\t\t\texpect(buff.getRmsAtTime(buffer.duration * 1.5)).to.be.closeTo(\n\t\t\t\t0,\n\t\t\t\t0.001\n\t\t\t);\n\t\t});\n\n\t\tit(\"loops the audio for the specific duration\", async () => {\n\t\t\tconst playDur = buffer.duration * 1.5;\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer);\n\t\t\t\tplayer.loop = true;\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer.start(0, 0, playDur);\n\t\t\t}, buffer.duration * 2);\n\t\t\texpect(buff.getRmsAtTime(0)).to.be.above(0);\n\t\t\texpect(buff.getRmsAtTime(buffer.duration)).to.be.above(0);\n\t\t\texpect(buff.getRmsAtTime(playDur - 0.01)).to.be.above(0);\n\t\t\texpect(buff.getRmsAtTime(playDur + 0.01)).to.equal(0);\n\t\t});\n\n\t\tit(\"starts at the loop start offset if looping\", async () => {\n\t\t\tconst offsetTime = 0.05;\n\t\t\tconst offsetSample =\n\t\t\t\tbuffer.toArray()[Math.floor(offsetTime * sampleRate)];\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer).toDestination();\n\t\t\t\tplayer.loop = true;\n\t\t\t\tplayer.loopStart = offsetTime;\n\t\t\t\tplayer.start(0);\n\t\t\t}, 0.1);\n\t\t\texpect(buff.getValueAtTime(0)).to.equal(offsetSample);\n\t\t});\n\n\t\tit(\"the offset is modulo the loopDuration\", async () => {\n\t\t\tconst testSample = buffer.toArray()[\n\t\t\t\tMath.floor(0.051 * sampleRate)\n\t\t\t] as number;\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer).toDestination();\n\t\t\t\tplayer.loop = true;\n\t\t\t\tplayer.loopStart = 0;\n\t\t\t\tplayer.loopEnd = 0.1;\n\t\t\t\tplayer.start(0, 0.351);\n\t\t\t}, 0.1);\n\t\t\texpect(buff.getValueAtTime(0)).to.be.closeTo(testSample, 1e-4);\n\t\t});\n\t});\n\n\tcontext(\"Get/Set\", () => {\n\t\tit(\"can be set with an options object\", () => {\n\t\t\tconst player = new ToneBufferSource();\n\t\t\texpect(player.loop).is.equal(false);\n\t\t\tplayer.set({\n\t\t\t\tloop: true,\n\t\t\t\tloopEnd: 0.5,\n\t\t\t\tloopStart: 0.4,\n\t\t\t});\n\t\t\texpect(player.loop).is.equal(true);\n\t\t\texpect(player.loopStart).to.equal(0.4);\n\t\t\texpect(player.loopEnd).to.equal(0.5);\n\t\t\tplayer.dispose();\n\t\t});\n\n\t\tit(\"can get/set the playbackRate\", () => {\n\t\t\tconst player = new ToneBufferSource();\n\t\t\tplayer.playbackRate.value = 0.5;\n\t\t\texpect(player.playbackRate.value).to.equal(0.5);\n\t\t\tplayer.dispose();\n\t\t});\n\t});\n\n\tcontext(\"onended\", () => {\n\t\tbeforeEach(() => {\n\t\t\treturn buffer.load(\"./test/audio/sine.wav\");\n\t\t});\n\n\t\tit.skip(\"schedules the onended callback in online context\", (done) => {\n\t\t\tconst player = new ToneBufferSource(buffer);\n\t\t\tplayer.start().stop(\"+0.1\");\n\t\t\tplayer.onended = () => {\n\t\t\t\texpect(player.state).to.equal(\"stopped\");\n\t\t\t\tplayer.dispose();\n\t\t\t\tdone();\n\t\t\t};\n\t\t});\n\n\t\tit(\"schedules the onended callback when offline\", async () => {\n\t\t\tlet wasInvoked = false;\n\t\t\tawait Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer).toDestination();\n\t\t\t\tplayer.start(0.2).stop(0.4);\n\t\t\t\tplayer.onended = () => (wasInvoked = true);\n\t\t\t}, 0.5);\n\t\t\texpect(wasInvoked).to.equal(true);\n\t\t});\n\n\t\tit(\"invokes the onended callback when a looped buffer is scheduled to stop\", async () => {\n\t\t\tlet wasInvoked = false;\n\t\t\tawait Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer).toDestination();\n\t\t\t\tplayer.loop = true;\n\t\t\t\tplayer.start().stop(0.4);\n\t\t\t\tplayer.onended = () => {\n\t\t\t\t\twasInvoked = true;\n\t\t\t\t};\n\t\t\t}, 0.5);\n\t\t\texpect(wasInvoked).to.equal(true);\n\t\t});\n\n\t\tit(\"schedules the onended callback when the buffer is done without scheduling stop\", async () => {\n\t\t\tlet wasInvoked = false;\n\t\t\tawait Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer).toDestination();\n\t\t\t\tplayer.start(0);\n\t\t\t\tplayer.onended = () => {\n\t\t\t\t\twasInvoked = true;\n\t\t\t\t};\n\t\t\t}, buffer.duration * 1.1);\n\t\t\texpect(wasInvoked).to.equal(true);\n\t\t});\n\t});\n\n\tcontext(\"state\", () => {\n\t\tbeforeEach(() => {\n\t\t\treturn buffer.load(\"./test/audio/sine.wav\");\n\t\t});\n\n\t\tit(\"reports the right state when scheduled to stop\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer).toDestination();\n\t\t\t\tplayer.start(0.2).stop(0.4);\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time >= 0.2 && time < 0.4) {\n\t\t\t\t\t\texpect(player.state).to.equal(\"started\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\texpect(player.state).to.equal(\"stopped\");\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.5);\n\t\t});\n\n\t\tit(\"reports the right state when duration is passed into start method\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer).toDestination();\n\t\t\t\tplayer.start(0, 0, 0.1);\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time >= 0 && time < 0.1) {\n\t\t\t\t\t\texpect(player.state).to.equal(\"started\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\texpect(player.state).to.equal(\"stopped\");\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.2);\n\t\t});\n\t});\n\n\tcontext(\"Start/Stop Scheduling\", () => {\n\t\tbeforeEach(() => {\n\t\t\treturn buffer.load(\"./test/audio/sine.wav\");\n\t\t});\n\n\t\tit(\"can play for a specific duration\", async () => {\n\t\t\tconst rms = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer).toDestination();\n\t\t\t\tplayer.start(0).stop(0.1);\n\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time > 0.1) {\n\t\t\t\t\t\texpect(player.state).to.equal(\"stopped\");\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.4);\n\t\t\texpect(rms.getRmsAtTime(0)).to.be.gt(0);\n\t\t\texpect(rms.getRmsAtTime(0.09)).to.be.gt(0);\n\t\t\texpect(rms.getRmsAtTime(0.11)).to.equal(0);\n\t\t\texpect(rms.getRmsAtTime(0.3)).to.equal(0);\n\t\t});\n\n\t\tit(\"can be scheduled to stop\", async () => {\n\t\t\tconst rms = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer).toDestination();\n\t\t\t\tplayer.start(0).stop(0.1);\n\t\t\t}, 0.6);\n\t\t\texpect(rms.getRmsAtTime(0.01)).to.be.gt(0);\n\t\t\texpect(rms.getRmsAtTime(0.08)).to.be.gt(0);\n\t\t\texpect(rms.getRmsAtTime(0.11)).to.equal(0);\n\t\t});\n\n\t\tit(\"plays correctly when playbackRate is < 1\", async () => {\n\t\t\tconst rms = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer).toDestination();\n\t\t\t\tplayer.start(0);\n\t\t\t\tplayer.playbackRate.value = 0.75;\n\t\t\t}, buffer.duration * 1.3);\n\t\t\texpect(rms.getRmsAtTime(0.01)).to.be.gt(0);\n\t\t\texpect(rms.getRmsAtTime(0.1)).to.be.gt(0);\n\t\t\texpect(rms.getRmsAtTime(0.2)).to.be.gt(0);\n\t\t\texpect(rms.getRmsAtTime(buffer.duration)).to.be.gt(0);\n\t\t});\n\n\t\tit(\"plays correctly when playbackRate is > 1\", async () => {\n\t\t\tconst rms = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer).toDestination();\n\t\t\t\tplayer.start(0);\n\t\t\t\tplayer.playbackRate.value = 2;\n\t\t\t}, buffer.duration);\n\t\t\texpect(rms.getRmsAtTime(0.03)).to.be.gt(0);\n\t\t\texpect(rms.getRmsAtTime(buffer.duration * 0.45)).to.be.gt(0);\n\t\t\texpect(rms.getRmsAtTime(buffer.duration * 0.5)).to.closeTo(0, 0.01);\n\t\t\texpect(rms.getRmsAtTime(buffer.duration * 0.7)).to.closeTo(0, 0.01);\n\t\t});\n\n\t\tit(\"can play for a specific duration passed in the 'start' method\", async () => {\n\t\t\tconst rms = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer).toDestination();\n\t\t\t\tplayer.start(0, 0, 0.1);\n\n\t\t\t\treturn (time_1) => {\n\t\t\t\t\tif (time_1 > 0.1) {\n\t\t\t\t\t\texpect(player.state).to.equal(\"stopped\");\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.4);\n\t\t\texpect(rms.getRmsAtTime(0)).to.be.gt(0);\n\t\t\texpect(rms.getRmsAtTime(0.09)).to.be.gt(0);\n\t\t\t// after stop is scheduled\n\t\t\texpect(rms.getRmsAtTime(0.11)).to.equal(0);\n\t\t\texpect(rms.getRmsAtTime(0.3)).to.equal(0);\n\t\t});\n\n\t\tit(\"can start at an offset\", async () => {\n\t\t\tconst offsetTime = 0.1;\n\t\t\tconst offsetSample =\n\t\t\t\tbuffer.toArray()[Math.floor(offsetTime * sampleRate)];\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer).toDestination();\n\t\t\t\tplayer.start(0, offsetTime);\n\t\t\t}, 0.05);\n\t\t\texpect(buff.getValueAtTime(0)).to.equal(offsetSample);\n\t\t});\n\n\t\tit(\"can end start ramp early\", async () => {\n\t\t\tconst rms = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer);\n\t\t\t\tplayer.fadeIn = 0.2;\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer.start(0).stop(0.1);\n\t\t\t}, 0.2);\n\t\t\texpect(rms.getRmsAtTime(0.0)).to.be.gt(0);\n\t\t\texpect(rms.getRmsAtTime(0.05)).to.be.gt(0);\n\t\t\texpect(rms.getRmsAtTime(0.09)).to.be.gt(0);\n\t\t\texpect(rms.getRmsAtTime(0.1)).to.equal(0);\n\t\t\texpect(rms.getRmsAtTime(0.15)).to.equal(0);\n\t\t});\n\n\t\tit(\"can end start ramp with a ramp\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(onesBuffer);\n\t\t\t\tplayer.fadeIn = 0.2;\n\t\t\t\tplayer.fadeOut = 0.1;\n\t\t\t\tplayer.loop = true;\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer.start(0).stop(0.1);\n\t\t\t}, 0.3);\n\t\t\t// fade in\n\t\t\texpect(buff.getRmsAtTime(0.01)).to.be.gt(0);\n\t\t\texpect(buff.getRmsAtTime(0.05)).to.be.gt(0);\n\t\t\t// fade out\n\t\t\texpect(buff.getRmsAtTime(0.1)).to.be.gt(0);\n\t\t\texpect(buff.getRmsAtTime(0.15)).to.be.gt(0);\n\t\t\texpect(buff.getRmsAtTime(0.19)).to.be.gt(0);\n\t\t\t// end of ramp\n\t\t\texpect(buff.getRmsAtTime(0.21)).to.equal(0);\n\t\t});\n\n\t\tit(\"can be scheduled to stop with a ramp\", async () => {\n\t\t\tconst rms = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer).toDestination();\n\t\t\t\tplayer.fadeOut = 0.05;\n\t\t\t\tplayer.start(0).stop(0.1);\n\t\t\t}, 0.6);\n\t\t\texpect(rms.getRmsAtTime(0.01)).to.be.gt(0);\n\t\t\texpect(rms.getRmsAtTime(0.05)).to.be.gt(0);\n\t\t\texpect(rms.getRmsAtTime(0.08)).to.be.gt(0);\n\t\t\texpect(rms.getRmsAtTime(0.1)).to.be.gt(0);\n\t\t\texpect(rms.getRmsAtTime(0.14)).to.be.gt(0);\n\t\t\texpect(rms.getRmsAtTime(0.16)).to.equal(0);\n\t\t\texpect(rms.getRmsAtTime(0.2)).to.equal(0);\n\t\t\texpect(rms.getRmsAtTime(0.3)).to.equal(0);\n\t\t\texpect(rms.getRmsAtTime(0.4)).to.equal(0);\n\t\t\texpect(rms.getRmsAtTime(0.5)).to.equal(0);\n\t\t});\n\n\t\tit(\"fade is applied after the stop time\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(onesBuffer).toDestination();\n\t\t\t\tplayer.fadeOut = 0.1;\n\t\t\t\tplayer.start(0).stop(0.2);\n\t\t\t}, 0.32);\n\t\t\texpect(buff.getValueAtTime(0)).to.equal(1);\n\t\t\texpect(buff.getValueAtTime(0.1)).to.equal(1);\n\t\t\texpect(buff.getValueAtTime(0.2)).to.equal(1);\n\t\t\texpect(buff.getValueAtTime(0.25)).to.be.closeTo(0.5, 0.01);\n\t\t\texpect(buff.getValueAtTime(0.29)).to.be.closeTo(0.1, 0.01);\n\t\t\texpect(buff.getValueAtTime(0.3)).to.be.closeTo(0, 0.01);\n\t\t\texpect(buff.getValueAtTime(0.31)).to.equal(0);\n\t\t});\n\n\t\tit(\"can fade with an exponential curve\", () => {\n\t\t\tconst player = new ToneBufferSource(onesBuffer).toDestination();\n\t\t\tplayer.curve = \"exponential\";\n\t\t\texpect(player.curve).to.equal(\"exponential\");\n\t\t\tplayer.dispose();\n\t\t});\n\n\t\tit(\"fades in and out exponentially\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(onesBuffer).toDestination();\n\t\t\t\tplayer.curve = \"exponential\";\n\t\t\t\tplayer.fadeIn = 0.1;\n\t\t\t\tplayer.fadeOut = 0.1;\n\t\t\t\tplayer.start(0).stop(0.4);\n\t\t\t}, 0.51);\n\t\t\texpect(buff.getValueAtTime(0)).to.equal(0);\n\t\t\texpect(buff.getValueAtTime(0.05)).to.be.closeTo(0.93, 0.01);\n\t\t\texpect(buff.getValueAtTime(0.1)).to.be.closeTo(1, 0.01);\n\t\t\texpect(buff.getValueAtTime(0.4)).to.be.closeTo(1, 0.01);\n\t\t\texpect(buff.getValueAtTime(0.45)).to.be.closeTo(0.06, 0.01);\n\t\t\texpect(buff.getValueAtTime(0.5)).to.closeTo(0, 0.01);\n\t\t});\n\n\t\tit(\"can be scheduled to start at a lower gain\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer).toDestination();\n\t\t\t\tplayer.start(0, 0, undefined, 0.5);\n\t\t\t}, 0.5);\n\t\t\texpect(buff.getValueAtTime(0)).to.be.lte(0.5);\n\t\t\texpect(buff.getValueAtTime(0.1)).to.be.lte(0.5);\n\t\t\texpect(buff.getValueAtTime(0.2)).to.be.lte(0.5);\n\t\t\texpect(buff.getValueAtTime(0.3)).to.be.lte(0.5);\n\t\t\texpect(buff.getValueAtTime(0.4)).to.be.lte(0.5);\n\t\t});\n\n\t\tit(\"cannot be started more than once\", () => {\n\t\t\tconst player = new ToneBufferSource(buffer);\n\t\t\tplayer.start();\n\t\t\texpect(() => {\n\t\t\t\tplayer.start();\n\t\t\t}).to.throw(Error);\n\t\t\tplayer.dispose();\n\t\t});\n\n\t\tit(\"stops playing if invoked with 'stop' at a sooner time\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer);\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer.start(0).stop(0.1).stop(0.05);\n\t\t\t}, 0.3);\n\t\t\texpect(buff.getTimeOfLastSound()).to.be.closeTo(0.05, 0.02);\n\t\t});\n\n\t\tit(\"does not play if the stop time is at the start time\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer);\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer.start(0).stop(0);\n\t\t\t}, 0.3);\n\t\t\texpect(buff.isSilent()).is.equal(true);\n\t\t});\n\n\t\tit(\"does not play if the stop time is at before start time\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer);\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer.start(0.1).stop(0);\n\t\t\t}, 0.3);\n\t\t\texpect(buff.isSilent()).is.equal(true);\n\t\t});\n\n\t\tit(\"stops playing at the last scheduled stop time\", async () => {\n\t\t\tconst buff = await Offline(() => {\n\t\t\t\tconst player = new ToneBufferSource(buffer);\n\t\t\t\tplayer.toDestination();\n\t\t\t\tplayer.start(0).stop(0.1).stop(0.2);\n\t\t\t}, 0.3);\n\t\t\texpect(buff.getTimeOfLastSound()).to.be.closeTo(0.2, 0.02);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/source/buffer/ToneBufferSource.ts",
    "content": "import { Param } from \"../../core/context/Param.js\";\nimport { ToneAudioBuffer } from \"../../core/context/ToneAudioBuffer.js\";\nimport { connect } from \"../../core/context/ToneAudioNode.js\";\nimport { GainFactor, Positive, Seconds, Time } from \"../../core/type/Units.js\";\nimport { assert } from \"../../core/util/Debug.js\";\nimport { defaultArg, optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { noOp } from \"../../core/util/Interface.js\";\nimport { EQ, GTE, LT } from \"../../core/util/Math.js\";\nimport { isDefined } from \"../../core/util/TypeCheck.js\";\nimport {\n\tOneShotSource,\n\tOneShotSourceCurve,\n\tOneShotSourceOptions,\n} from \"../OneShotSource.js\";\n\nexport type ToneBufferSourceCurve = OneShotSourceCurve;\n\nexport interface ToneBufferSourceOptions extends OneShotSourceOptions {\n\turl: string | AudioBuffer | ToneAudioBuffer;\n\tcurve: ToneBufferSourceCurve;\n\tplaybackRate: Positive;\n\tfadeIn: Time;\n\tfadeOut: Time;\n\tloopStart: Time;\n\tloopEnd: Time;\n\tloop: boolean;\n\tonload: () => void;\n\tonerror: (error: Error) => void;\n}\n\n/**\n * Wrapper around the native BufferSourceNode.\n * @category Source\n */\nexport class ToneBufferSource extends OneShotSource<ToneBufferSourceOptions> {\n\treadonly name: string = \"ToneBufferSource\";\n\n\t/**\n\t * The oscillator\n\t */\n\tprivate _source = this.context.createBufferSource();\n\tprotected _internalChannels = [this._source];\n\n\t/**\n\t * The frequency of the oscillator\n\t */\n\treadonly playbackRate: Param<\"positive\">;\n\n\t/**\n\t * The private instance of the buffer object\n\t */\n\tprivate _buffer: ToneAudioBuffer;\n\n\t/**\n\t * indicators if the source has started/stopped\n\t */\n\tprivate _sourceStarted = false;\n\tprivate _sourceStopped = false;\n\n\t/**\n\t * @param url The buffer to play or url to load\n\t * @param onload The callback to invoke when the buffer is done playing.\n\t */\n\tconstructor(\n\t\turl?: ToneAudioBuffer | AudioBuffer | string,\n\t\tonload?: () => void\n\t);\n\tconstructor(options?: Partial<ToneBufferSourceOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tToneBufferSource.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"url\", \"onload\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tconnect(this._source, this._gainNode);\n\t\tthis._source.onended = () => this._stopSource();\n\n\t\t/**\n\t\t * The playbackRate of the buffer\n\t\t */\n\t\tthis.playbackRate = new Param({\n\t\t\tcontext: this.context,\n\t\t\tparam: this._source.playbackRate,\n\t\t\tunits: \"positive\",\n\t\t\tvalue: options.playbackRate,\n\t\t});\n\n\t\t// set some values initially\n\t\tthis.loop = options.loop;\n\t\tthis.loopStart = options.loopStart;\n\t\tthis.loopEnd = options.loopEnd;\n\t\tthis._buffer = new ToneAudioBuffer(\n\t\t\toptions.url,\n\t\t\toptions.onload,\n\t\t\toptions.onerror\n\t\t);\n\n\t\tthis._internalChannels.push(this._source);\n\t}\n\n\tstatic getDefaults(): ToneBufferSourceOptions {\n\t\treturn Object.assign(OneShotSource.getDefaults(), {\n\t\t\turl: new ToneAudioBuffer(),\n\t\t\tloop: false,\n\t\t\tloopEnd: 0,\n\t\t\tloopStart: 0,\n\t\t\tonload: noOp,\n\t\t\tonerror: noOp,\n\t\t\tplaybackRate: 1,\n\t\t});\n\t}\n\n\t/**\n\t * The fadeIn time of the amplitude envelope.\n\t */\n\tget fadeIn(): Time {\n\t\treturn this._fadeIn;\n\t}\n\tset fadeIn(t: Time) {\n\t\tthis._fadeIn = t;\n\t}\n\n\t/**\n\t * The fadeOut time of the amplitude envelope.\n\t */\n\tget fadeOut(): Time {\n\t\treturn this._fadeOut;\n\t}\n\tset fadeOut(t: Time) {\n\t\tthis._fadeOut = t;\n\t}\n\n\t/**\n\t * The curve applied to the fades, either \"linear\" or \"exponential\"\n\t */\n\tget curve(): ToneBufferSourceCurve {\n\t\treturn this._curve;\n\t}\n\tset curve(t) {\n\t\tthis._curve = t;\n\t}\n\n\t/**\n\t * Start the buffer\n\t * @param  time When the player should start.\n\t * @param  offset The offset from the beginning of the sample to start at.\n\t * @param  duration How long the sample should play. If no duration is given, it will default to the full length of the sample (minus any offset)\n\t * @param  gain  The gain to play the buffer back at.\n\t */\n\tstart(\n\t\ttime?: Time,\n\t\toffset?: Time,\n\t\tduration?: Time,\n\t\tgain: GainFactor = 1\n\t): this {\n\t\tassert(this.buffer.loaded, \"buffer is either not set or not loaded\");\n\t\tconst computedTime = this.toSeconds(time);\n\n\t\t// apply the gain envelope\n\t\tthis._startGain(computedTime, gain);\n\n\t\t// if it's a loop the default offset is the loopstart point\n\t\tif (this.loop) {\n\t\t\toffset = defaultArg(offset, this.loopStart);\n\t\t} else {\n\t\t\t// otherwise the default offset is 0\n\t\t\toffset = defaultArg(offset, 0);\n\t\t}\n\t\t// make sure the offset is not less than 0\n\t\tlet computedOffset = Math.max(this.toSeconds(offset), 0);\n\n\t\t// start the buffer source\n\t\tif (this.loop) {\n\t\t\t// modify the offset if it's greater than the loop time\n\t\t\tconst loopEnd =\n\t\t\t\tthis.toSeconds(this.loopEnd) || this.buffer.duration;\n\t\t\tconst loopStart = this.toSeconds(this.loopStart);\n\t\t\tconst loopDuration = loopEnd - loopStart;\n\t\t\t// move the offset back\n\t\t\tif (GTE(computedOffset, loopEnd)) {\n\t\t\t\tcomputedOffset =\n\t\t\t\t\t((computedOffset - loopStart) % loopDuration) + loopStart;\n\t\t\t}\n\t\t\t// when the offset is very close to the duration, set it to 0\n\t\t\tif (EQ(computedOffset, this.buffer.duration)) {\n\t\t\t\tcomputedOffset = 0;\n\t\t\t}\n\t\t}\n\n\t\t// this.buffer.loaded would have return false if the AudioBuffer was undefined\n\t\tthis._source.buffer = this.buffer.get() as AudioBuffer;\n\t\tthis._source.loopEnd =\n\t\t\tthis.toSeconds(this.loopEnd) || this.buffer.duration;\n\t\tif (LT(computedOffset, this.buffer.duration)) {\n\t\t\tthis._sourceStarted = true;\n\t\t\tthis._source.start(computedTime, computedOffset);\n\t\t}\n\n\t\t// if a duration is given, schedule a stop\n\t\tif (isDefined(duration)) {\n\t\t\tlet computedDur = this.toSeconds(duration);\n\t\t\t// make sure it's never negative\n\t\t\tcomputedDur = Math.max(computedDur, 0);\n\t\t\tthis.stop(computedTime + computedDur);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tprotected _stopSource(time?: Seconds): void {\n\t\tif (!this._sourceStopped && this._sourceStarted) {\n\t\t\tthis._sourceStopped = true;\n\t\t\tthis._source.stop(this.toSeconds(time));\n\t\t\tthis._onended();\n\t\t}\n\t}\n\n\t/**\n\t * If loop is true, the loop will start at this position.\n\t */\n\tget loopStart(): Time {\n\t\treturn this._source.loopStart;\n\t}\n\tset loopStart(loopStart: Time) {\n\t\tthis._source.loopStart = this.toSeconds(loopStart);\n\t}\n\n\t/**\n\t * If loop is true, the loop will end at this position.\n\t */\n\tget loopEnd(): Time {\n\t\treturn this._source.loopEnd;\n\t}\n\tset loopEnd(loopEnd: Time) {\n\t\tthis._source.loopEnd = this.toSeconds(loopEnd);\n\t}\n\n\t/**\n\t * The audio buffer belonging to the player.\n\t */\n\tget buffer(): ToneAudioBuffer {\n\t\treturn this._buffer;\n\t}\n\tset buffer(buffer: ToneAudioBuffer) {\n\t\tthis._buffer.set(buffer);\n\t}\n\n\t/**\n\t * If the buffer should loop once its over.\n\t */\n\tget loop(): boolean {\n\t\treturn this._source.loop;\n\t}\n\tset loop(loop: boolean) {\n\t\tthis._source.loop = loop;\n\t\tif (this._sourceStarted) {\n\t\t\tthis.cancelStop();\n\t\t}\n\t}\n\n\t/**\n\t * Clean up.\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._source.onended = null;\n\t\tthis._source.disconnect();\n\t\tthis._buffer.dispose();\n\t\tthis.playbackRate.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/source/index.ts",
    "content": "export * from \"./buffer/GrainPlayer.js\";\nexport * from \"./buffer/Player.js\";\nexport * from \"./buffer/Players.js\";\nexport * from \"./buffer/ToneBufferSource.js\";\nexport * from \"./Noise.js\";\nexport * from \"./oscillator/AMOscillator.js\";\nexport * from \"./oscillator/FatOscillator.js\";\nexport * from \"./oscillator/FMOscillator.js\";\nexport * from \"./oscillator/LFO.js\";\nexport * from \"./oscillator/OmniOscillator.js\";\nexport * from \"./oscillator/Oscillator.js\";\nexport * from \"./oscillator/PulseOscillator.js\";\nexport * from \"./oscillator/PWMOscillator.js\";\nexport * from \"./oscillator/ToneOscillatorNode.js\";\nexport * from \"./UserMedia.js\";\n"
  },
  {
    "path": "Tone/source/oscillator/AMOscillator.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../../test/helper/CompareToFile.js\";\nimport { OscillatorTests } from \"../../../test/helper/OscillatorTests.js\";\nimport { SourceTests } from \"../../../test/helper/SourceTests.js\";\nimport { AMOscillator } from \"./AMOscillator.js\";\n\ndescribe(\"AMOscillator\", () => {\n\t// run the common tests\n\tBasicTests(AMOscillator);\n\tSourceTests(AMOscillator);\n\tOscillatorTests(AMOscillator);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst osc = new AMOscillator().toDestination();\n\t\t\t\tosc.start(0.1).stop(0.4);\n\t\t\t},\n\t\t\t\"amOscillator.wav\",\n\t\t\t0.03\n\t\t);\n\t});\n\n\tcontext(\"Amplitude Modulation\", () => {\n\t\tit(\"can pass in parameters in the constructor\", () => {\n\t\t\tconst amOsc = new AMOscillator({\n\t\t\t\tharmonicity: 3,\n\t\t\t\tmodulationType: \"square3\",\n\t\t\t\ttype: \"triangle2\",\n\t\t\t});\n\t\t\texpect(amOsc.type).to.equal(\"triangle2\");\n\t\t\texpect(amOsc.harmonicity.value).to.be.closeTo(3, 0.001);\n\t\t\texpect(amOsc.modulationType).to.equal(\"square3\");\n\t\t\tamOsc.dispose();\n\t\t});\n\n\t\tit(\"can set the harmonicity\", () => {\n\t\t\tconst amOsc = new AMOscillator();\n\t\t\tamOsc.harmonicity.value = 0.2;\n\t\t\texpect(amOsc.harmonicity.value).to.be.closeTo(0.2, 0.001);\n\t\t\tamOsc.dispose();\n\t\t});\n\n\t\tit(\"can set the modulationType\", () => {\n\t\t\tconst amOsc = new AMOscillator();\n\t\t\tamOsc.modulationType = \"triangle5\";\n\t\t\texpect(amOsc.modulationType).to.equal(\"triangle5\");\n\t\t\tamOsc.dispose();\n\t\t});\n\n\t\tit(\"can get/set the baseType\", () => {\n\t\t\tconst osc = new AMOscillator();\n\t\t\tosc.type = \"sine5\";\n\t\t\texpect(osc.baseType).to.equal(\"sine\");\n\t\t\tosc.baseType = \"triangle\";\n\t\t\texpect(osc.type).to.equal(\"triangle5\");\n\t\t\texpect(osc.partialCount).to.equal(5);\n\t\t\tosc.partialCount = 2;\n\t\t\texpect(osc.type).to.equal(\"triangle2\");\n\t\t\tosc.baseType = \"custom\";\n\t\t\texpect(osc.type).to.equal(\"custom\");\n\t\t\tosc.partials = [1, 2, 3];\n\t\t\texpect(osc.baseType).to.equal(\"custom\");\n\t\t\texpect(osc.partials).to.deep.equal([1, 2, 3]);\n\t\t\tosc.baseType = \"square\";\n\t\t\texpect(osc.type).to.equal(\"square\");\n\t\t\tosc.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/source/oscillator/AMOscillator.ts",
    "content": "import { Gain } from \"../../core/context/Gain.js\";\nimport { Degrees, Frequency, Seconds } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly } from \"../../core/util/Interface.js\";\nimport { AudioToGain } from \"../../signal/AudioToGain.js\";\nimport { Multiply } from \"../../signal/Multiply.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { Source } from \"../Source.js\";\nimport { Oscillator } from \"./Oscillator.js\";\nimport {\n\tAMConstructorOptions,\n\tAMOscillatorOptions,\n\tgenerateWaveform,\n\tNonCustomOscillatorType,\n\tToneOscillatorInterface,\n\tToneOscillatorType,\n} from \"./OscillatorInterface.js\";\n\nexport { AMOscillatorOptions } from \"./OscillatorInterface.js\";\n\n/**\n * An amplitude modulated oscillator node. It is implemented with\n * two oscillators, one which modulators the other's amplitude\n * through a gain node.\n * ```\n *    +-------------+       +----------+\n *    | Carrier Osc +>------> GainNode |\n *    +-------------+       |          +--->Output\n *                      +---> gain     |\n * +---------------+    |   +----------+\n * | Modulator Osc +>---+\n * +---------------+\n * ```\n * @example\n * return Tone.Offline(() => {\n * \tconst amOsc = new Tone.AMOscillator(30, \"sine\", \"square\").toDestination().start();\n * }, 0.2, 1);\n * @category Source\n */\nexport class AMOscillator\n\textends Source<AMOscillatorOptions>\n\timplements ToneOscillatorInterface\n{\n\treadonly name: string = \"AMOscillator\";\n\n\t/**\n\t * The carrier oscillator\n\t */\n\tprivate _carrier: Oscillator;\n\n\treadonly frequency: Signal<\"frequency\">;\n\treadonly detune: Signal<\"cents\">;\n\n\t/**\n\t * The modulating oscillator\n\t */\n\tprivate _modulator: Oscillator;\n\n\t/**\n\t * convert the -1,1 output to 0,1\n\t */\n\tprivate _modulationScale = new AudioToGain({ context: this.context });\n\n\t/**\n\t * Harmonicity is the frequency ratio between the carrier and the modulator oscillators.\n\t * A harmonicity of 1 gives both oscillators the same frequency.\n\t * Harmonicity = 2 means a change of an octave.\n\t * @example\n\t * const amOsc = new Tone.AMOscillator(\"D2\").toDestination().start();\n\t * Tone.Transport.scheduleRepeat(time => {\n\t * \tamOsc.harmonicity.setValueAtTime(1, time);\n\t * \tamOsc.harmonicity.setValueAtTime(0.5, time + 0.5);\n\t * \tamOsc.harmonicity.setValueAtTime(1.5, time + 1);\n\t * \tamOsc.harmonicity.setValueAtTime(1, time + 2);\n\t * \tamOsc.harmonicity.linearRampToValueAtTime(2, time + 4);\n\t * }, 4);\n\t * Tone.Transport.start();\n\t */\n\treadonly harmonicity: Signal<\"positive\">;\n\n\t/**\n\t * the node where the modulation happens\n\t */\n\tprivate _modulationNode = new Gain({\n\t\tcontext: this.context,\n\t});\n\n\t/**\n\t * @param frequency The starting frequency of the oscillator.\n\t * @param type The type of the carrier oscillator.\n\t * @param modulationType The type of the modulator oscillator.\n\t */\n\tconstructor(\n\t\tfrequency?: Frequency,\n\t\ttype?: ToneOscillatorType,\n\t\tmodulationType?: ToneOscillatorType\n\t);\n\tconstructor(options?: Partial<AMConstructorOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tAMOscillator.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"frequency\", \"type\", \"modulationType\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._carrier = new Oscillator({\n\t\t\tcontext: this.context,\n\t\t\tdetune: options.detune,\n\t\t\tfrequency: options.frequency,\n\t\t\tonstop: () => this.onstop(this),\n\t\t\tphase: options.phase,\n\t\t\ttype: options.type,\n\t\t} as OscillatorOptions);\n\t\tthis.frequency = this._carrier.frequency;\n\t\tthis.detune = this._carrier.detune;\n\n\t\tthis._modulator = new Oscillator({\n\t\t\tcontext: this.context,\n\t\t\tphase: options.phase,\n\t\t\ttype: options.modulationType,\n\t\t} as OscillatorOptions);\n\n\t\tthis.harmonicity = new Multiply({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"positive\",\n\t\t\tvalue: options.harmonicity,\n\t\t});\n\n\t\t// connections\n\t\tthis.frequency.chain(this.harmonicity, this._modulator.frequency);\n\t\tthis._modulator.chain(this._modulationScale, this._modulationNode.gain);\n\t\tthis._carrier.chain(this._modulationNode, this.output);\n\n\t\treadOnly(this, [\"frequency\", \"detune\", \"harmonicity\"]);\n\t}\n\n\tstatic getDefaults(): AMOscillatorOptions {\n\t\treturn Object.assign(Oscillator.getDefaults(), {\n\t\t\tharmonicity: 1,\n\t\t\tmodulationType: \"square\" as NonCustomOscillatorType,\n\t\t});\n\t}\n\n\t/**\n\t * start the oscillator\n\t */\n\tprotected _start(time: Seconds): void {\n\t\tthis._modulator.start(time);\n\t\tthis._carrier.start(time);\n\t}\n\n\t/**\n\t * stop the oscillator\n\t */\n\tprotected _stop(time: Seconds): void {\n\t\tthis._modulator.stop(time);\n\t\tthis._carrier.stop(time);\n\t}\n\n\tprotected _restart(time: Seconds): void {\n\t\tthis._modulator.restart(time);\n\t\tthis._carrier.restart(time);\n\t}\n\n\t/**\n\t * The type of the carrier oscillator\n\t */\n\tget type(): ToneOscillatorType {\n\t\treturn this._carrier.type;\n\t}\n\tset type(type: ToneOscillatorType) {\n\t\tthis._carrier.type = type;\n\t}\n\n\tget baseType(): OscillatorType {\n\t\treturn this._carrier.baseType;\n\t}\n\tset baseType(baseType: OscillatorType) {\n\t\tthis._carrier.baseType = baseType;\n\t}\n\n\tget partialCount(): number {\n\t\treturn this._carrier.partialCount;\n\t}\n\tset partialCount(partialCount: number) {\n\t\tthis._carrier.partialCount = partialCount;\n\t}\n\n\t/**\n\t * The type of the modulator oscillator\n\t */\n\tget modulationType(): ToneOscillatorType {\n\t\treturn this._modulator.type;\n\t}\n\tset modulationType(type: ToneOscillatorType) {\n\t\tthis._modulator.type = type;\n\t}\n\n\tget phase(): Degrees {\n\t\treturn this._carrier.phase;\n\t}\n\tset phase(phase: Degrees) {\n\t\tthis._carrier.phase = phase;\n\t\tthis._modulator.phase = phase;\n\t}\n\n\tget partials(): number[] {\n\t\treturn this._carrier.partials;\n\t}\n\tset partials(partials: number[]) {\n\t\tthis._carrier.partials = partials;\n\t}\n\n\tasync asArray(length = 1024): Promise<Float32Array> {\n\t\treturn generateWaveform(this, length);\n\t}\n\n\t/**\n\t * Clean up.\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.frequency.dispose();\n\t\tthis.detune.dispose();\n\t\tthis.harmonicity.dispose();\n\t\tthis._carrier.dispose();\n\t\tthis._modulator.dispose();\n\t\tthis._modulationNode.dispose();\n\t\tthis._modulationScale.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/source/oscillator/FMOscillator.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../../test/helper/CompareToFile.js\";\nimport { connectFrom } from \"../../../test/helper/Connect.js\";\nimport { OscillatorTests } from \"../../../test/helper/OscillatorTests.js\";\nimport { SourceTests } from \"../../../test/helper/SourceTests.js\";\nimport { FMOscillator } from \"./FMOscillator.js\";\n\ndescribe(\"FMOscillator\", () => {\n\t// run the common tests\n\tBasicTests(FMOscillator);\n\tSourceTests(FMOscillator);\n\tOscillatorTests(FMOscillator);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst osc = new FMOscillator().toDestination();\n\t\t\t\tosc.start(0);\n\t\t\t},\n\t\t\t\"fmOscillator.wav\",\n\t\t\t0.01\n\t\t);\n\t});\n\n\tcontext(\"Frequency Modulation\", () => {\n\t\tit(\"can pass in parameters in the constructor\", () => {\n\t\t\tconst fmOsc = new FMOscillator({\n\t\t\t\tharmonicity: 3,\n\t\t\t\tmodulationType: \"square3\",\n\t\t\t\ttype: \"triangle2\",\n\t\t\t});\n\t\t\texpect(fmOsc.type).to.equal(\"triangle2\");\n\t\t\texpect(fmOsc.harmonicity.value).to.be.closeTo(3, 0.001);\n\t\t\texpect(fmOsc.modulationType).to.equal(\"square3\");\n\t\t\tfmOsc.dispose();\n\t\t});\n\n\t\tit(\"can set the harmonicity\", () => {\n\t\t\tconst fmOsc = new FMOscillator();\n\t\t\tfmOsc.harmonicity.value = 0.2;\n\t\t\texpect(fmOsc.harmonicity.value).to.be.closeTo(0.2, 0.001);\n\t\t\tfmOsc.dispose();\n\t\t});\n\n\t\tit(\"can set the modulationIndex\", () => {\n\t\t\tconst fmOsc = new FMOscillator({\n\t\t\t\tmodulationIndex: 3,\n\t\t\t});\n\t\t\texpect(fmOsc.modulationIndex.value).to.be.closeTo(3, 0.001);\n\t\t\tfmOsc.modulationIndex.value = 0.2;\n\t\t\texpect(fmOsc.modulationIndex.value).to.be.closeTo(0.2, 0.001);\n\t\t\tfmOsc.dispose();\n\t\t});\n\n\t\tit(\"can connect a signal to the harmonicity\", () => {\n\t\t\tconst fmOsc = new FMOscillator();\n\t\t\tconnectFrom().connect(fmOsc.harmonicity);\n\t\t\tfmOsc.dispose();\n\t\t});\n\n\t\tit(\"can set the modulationType\", () => {\n\t\t\tconst fmOsc = new FMOscillator();\n\t\t\tfmOsc.modulationType = \"triangle5\";\n\t\t\texpect(fmOsc.modulationType).to.equal(\"triangle5\");\n\t\t\tfmOsc.dispose();\n\t\t});\n\n\t\tit(\"can get/set the baseType\", () => {\n\t\t\tconst osc = new FMOscillator();\n\t\t\tosc.type = \"sine5\";\n\t\t\texpect(osc.baseType).to.equal(\"sine\");\n\t\t\tosc.baseType = \"triangle\";\n\t\t\texpect(osc.type).to.equal(\"triangle5\");\n\t\t\texpect(osc.partialCount).to.equal(5);\n\t\t\tosc.partialCount = 2;\n\t\t\texpect(osc.type).to.equal(\"triangle2\");\n\t\t\tosc.baseType = \"custom\";\n\t\t\texpect(osc.type).to.equal(\"custom\");\n\t\t\tosc.partials = [1, 2, 3];\n\t\t\texpect(osc.baseType).to.equal(\"custom\");\n\t\t\tosc.baseType = \"square\";\n\t\t\texpect(osc.type).to.equal(\"square\");\n\t\t\tosc.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/source/oscillator/FMOscillator.ts",
    "content": "import { Gain } from \"../../core/context/Gain.js\";\nimport { Degrees, Frequency, Seconds, Time } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly } from \"../../core/util/Interface.js\";\nimport { Multiply } from \"../../signal/Multiply.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { Source } from \"../Source.js\";\nimport { Oscillator } from \"./Oscillator.js\";\nimport {\n\tFMConstructorOptions,\n\tFMOscillatorOptions,\n\tgenerateWaveform,\n\tNonCustomOscillatorType,\n\tToneOscillatorInterface,\n\tToneOscillatorType,\n} from \"./OscillatorInterface.js\";\n\nexport { FMOscillatorOptions } from \"./OscillatorInterface.js\";\n/**\n * FMOscillator implements a frequency modulation synthesis\n * ```\n *                                              +-------------+\n * +---------------+        +-------------+     | Carrier Osc |\n * | Modulator Osc +>-------> GainNode    |     |             +--->Output\n * +---------------+        |             +>----> frequency   |\n *                       +--> gain        |     +-------------+\n *                       |  +-------------+\n * +-----------------+   |\n * | modulationIndex +>--+\n * +-----------------+\n * ```\n *\n * @example\n * return Tone.Offline(() => {\n * \tconst fmOsc = new Tone.FMOscillator({\n * \t\tfrequency: 200,\n * \t\ttype: \"square\",\n * \t\tmodulationType: \"triangle\",\n * \t\tharmonicity: 0.2,\n * \t\tmodulationIndex: 3\n * \t}).toDestination().start();\n * }, 0.1, 1);\n * @category Source\n */\nexport class FMOscillator\n\textends Source<FMOscillatorOptions>\n\timplements ToneOscillatorInterface\n{\n\treadonly name: string = \"FMOscillator\";\n\n\t/**\n\t * The carrier oscillator\n\t */\n\tprivate _carrier: Oscillator;\n\n\treadonly frequency: Signal<\"frequency\">;\n\treadonly detune: Signal<\"cents\">;\n\n\t/**\n\t * The modulating oscillator\n\t */\n\tprivate _modulator: Oscillator;\n\n\t/**\n\t * Harmonicity is the frequency ratio between the carrier and the modulator oscillators.\n\t * A harmonicity of 1 gives both oscillators the same frequency.\n\t * Harmonicity = 2 means a change of an octave.\n\t * @example\n\t * const fmOsc = new Tone.FMOscillator(\"D2\").toDestination().start();\n\t * // pitch the modulator an octave below carrier\n\t * fmOsc.harmonicity.value = 0.5;\n\t */\n\treadonly harmonicity: Signal<\"positive\">;\n\n\t/**\n\t * The modulation index which is in essence the depth or amount of the modulation. In other terms it is the\n\t * ratio of the frequency of the modulating signal (mf) to the amplitude of the\n\t * modulating signal (ma) -- as in ma/mf.\n\t */\n\treadonly modulationIndex: Signal<\"positive\">;\n\n\t/**\n\t * the node where the modulation happens\n\t */\n\tprivate _modulationNode: Gain = new Gain({\n\t\tcontext: this.context,\n\t\tgain: 0,\n\t});\n\n\t/**\n\t * @param frequency The starting frequency of the oscillator.\n\t * @param type The type of the carrier oscillator.\n\t * @param modulationType The type of the modulator oscillator.\n\t */\n\tconstructor(\n\t\tfrequency?: Frequency,\n\t\ttype?: ToneOscillatorType,\n\t\tmodulationType?: ToneOscillatorType\n\t);\n\tconstructor(options?: Partial<FMConstructorOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tFMOscillator.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"frequency\", \"type\", \"modulationType\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._carrier = new Oscillator({\n\t\t\tcontext: this.context,\n\t\t\tdetune: options.detune,\n\t\t\tfrequency: 0,\n\t\t\tonstop: () => this.onstop(this),\n\t\t\tphase: options.phase,\n\t\t\ttype: options.type,\n\t\t} as OscillatorOptions);\n\n\t\tthis.detune = this._carrier.detune;\n\n\t\tthis.frequency = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"frequency\",\n\t\t\tvalue: options.frequency,\n\t\t});\n\n\t\tthis._modulator = new Oscillator({\n\t\t\tcontext: this.context,\n\t\t\tphase: options.phase,\n\t\t\ttype: options.modulationType,\n\t\t} as OscillatorOptions);\n\n\t\tthis.harmonicity = new Multiply({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"positive\",\n\t\t\tvalue: options.harmonicity,\n\t\t});\n\n\t\tthis.modulationIndex = new Multiply({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"positive\",\n\t\t\tvalue: options.modulationIndex,\n\t\t});\n\n\t\t// connections\n\t\tthis.frequency.connect(this._carrier.frequency);\n\t\tthis.frequency.chain(this.harmonicity, this._modulator.frequency);\n\t\tthis.frequency.chain(this.modulationIndex, this._modulationNode);\n\t\tthis._modulator.connect(this._modulationNode.gain);\n\t\tthis._modulationNode.connect(this._carrier.frequency);\n\t\tthis._carrier.connect(this.output);\n\t\tthis.detune.connect(this._modulator.detune);\n\n\t\treadOnly(this, [\n\t\t\t\"modulationIndex\",\n\t\t\t\"frequency\",\n\t\t\t\"detune\",\n\t\t\t\"harmonicity\",\n\t\t]);\n\t}\n\n\tstatic getDefaults(): FMOscillatorOptions {\n\t\treturn Object.assign(Oscillator.getDefaults(), {\n\t\t\tharmonicity: 1,\n\t\t\tmodulationIndex: 2,\n\t\t\tmodulationType: \"square\" as NonCustomOscillatorType,\n\t\t});\n\t}\n\n\t/**\n\t * start the oscillator\n\t */\n\tprotected _start(time: Time): void {\n\t\tthis._modulator.start(time);\n\t\tthis._carrier.start(time);\n\t}\n\n\t/**\n\t * stop the oscillator\n\t */\n\tprotected _stop(time: Time): void {\n\t\tthis._modulator.stop(time);\n\t\tthis._carrier.stop(time);\n\t}\n\n\tprotected _restart(time: Seconds): this {\n\t\tthis._modulator.restart(time);\n\t\tthis._carrier.restart(time);\n\t\treturn this;\n\t}\n\n\tget type(): ToneOscillatorType {\n\t\treturn this._carrier.type;\n\t}\n\tset type(type: ToneOscillatorType) {\n\t\tthis._carrier.type = type;\n\t}\n\n\tget baseType(): OscillatorType {\n\t\treturn this._carrier.baseType;\n\t}\n\tset baseType(baseType: OscillatorType) {\n\t\tthis._carrier.baseType = baseType;\n\t}\n\n\tget partialCount(): number {\n\t\treturn this._carrier.partialCount;\n\t}\n\tset partialCount(partialCount: number) {\n\t\tthis._carrier.partialCount = partialCount;\n\t}\n\n\t/**\n\t * The type of the modulator oscillator\n\t */\n\tget modulationType(): ToneOscillatorType {\n\t\treturn this._modulator.type;\n\t}\n\tset modulationType(type: ToneOscillatorType) {\n\t\tthis._modulator.type = type;\n\t}\n\n\tget phase(): Degrees {\n\t\treturn this._carrier.phase;\n\t}\n\tset phase(phase: Degrees) {\n\t\tthis._carrier.phase = phase;\n\t\tthis._modulator.phase = phase;\n\t}\n\n\tget partials(): number[] {\n\t\treturn this._carrier.partials;\n\t}\n\tset partials(partials: number[]) {\n\t\tthis._carrier.partials = partials;\n\t}\n\n\tasync asArray(length = 1024): Promise<Float32Array> {\n\t\treturn generateWaveform(this, length);\n\t}\n\n\t/**\n\t * Clean up.\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.frequency.dispose();\n\t\tthis.harmonicity.dispose();\n\t\tthis._carrier.dispose();\n\t\tthis._modulator.dispose();\n\t\tthis._modulationNode.dispose();\n\t\tthis.modulationIndex.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/source/oscillator/FatOscillator.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../../test/helper/CompareToFile.js\";\nimport { OscillatorTests } from \"../../../test/helper/OscillatorTests.js\";\nimport { SourceTests } from \"../../../test/helper/SourceTests.js\";\nimport { FatOscillator } from \"./FatOscillator.js\";\n\ndescribe(\"FatOscillator\", () => {\n\t// run the common tests\n\tBasicTests(FatOscillator);\n\tSourceTests(FatOscillator);\n\tOscillatorTests(FatOscillator);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst osc = new FatOscillator().toDestination();\n\t\t\t\tosc.start(0);\n\t\t\t},\n\t\t\t\"fatOscillator.wav\",\n\t\t\t0.2\n\t\t);\n\t});\n\n\tcontext(\"Detuned Oscillators\", () => {\n\t\tit(\"can pass in parameters in the constructor\", () => {\n\t\t\tconst fatOsc = new FatOscillator({\n\t\t\t\tcount: 4,\n\t\t\t\tspread: 25,\n\t\t\t});\n\t\t\texpect(fatOsc.spread).to.be.equal(25);\n\t\t\texpect(fatOsc.count).to.equal(4);\n\t\t\tfatOsc.dispose();\n\t\t});\n\n\t\tit(\"can set the partials and the count\", () => {\n\t\t\tconst fatOsc = new FatOscillator({\n\t\t\t\tcount: 3,\n\t\t\t});\n\t\t\tfatOsc.partials = [0, 2, 3, 4];\n\t\t\texpect(fatOsc.partials).to.deep.equal([0, 2, 3, 4]);\n\t\t\texpect(fatOsc.partialCount).to.equal(4);\n\t\t\texpect(fatOsc.type).to.equal(\"custom\");\n\t\t\tfatOsc.count = 4;\n\t\t\texpect(fatOsc.partials).to.deep.equal([0, 2, 3, 4]);\n\t\t\texpect(fatOsc.type).to.equal(\"custom\");\n\t\t\tfatOsc.dispose();\n\t\t});\n\n\t\tit(\"can set the count after starting\", () => {\n\t\t\tconst fatOsc = new FatOscillator({\n\t\t\t\tcount: 3,\n\t\t\t});\n\t\t\tfatOsc.start();\n\t\t\tfatOsc.count = 4;\n\t\t\texpect(fatOsc.count).to.equal(4);\n\t\t\tfatOsc.dispose();\n\t\t});\n\n\t\tit(\"correctly distributes the detune spread\", () => {\n\t\t\tconst fatOsc = new FatOscillator({\n\t\t\t\tcount: 2,\n\t\t\t\tspread: 20,\n\t\t\t});\n\t\t\t// @ts-ignore\n\t\t\texpect(fatOsc._oscillators.length).to.equal(2);\n\t\t\t// @ts-ignore\n\t\t\texpect(fatOsc._oscillators[0].detune.value).to.equal(-10);\n\t\t\t// @ts-ignore\n\t\t\texpect(fatOsc._oscillators[1].detune.value).to.equal(10);\n\t\t\tfatOsc.dispose();\n\t\t});\n\n\t\tit(\"can get/set the baseType\", () => {\n\t\t\tconst osc = new FatOscillator();\n\t\t\tosc.type = \"sine5\";\n\t\t\texpect(osc.baseType).to.equal(\"sine\");\n\t\t\tosc.baseType = \"triangle\";\n\t\t\texpect(osc.type).to.equal(\"triangle5\");\n\t\t\texpect(osc.partialCount).to.equal(5);\n\t\t\tosc.partialCount = 2;\n\t\t\texpect(osc.type).to.equal(\"triangle2\");\n\t\t\tosc.baseType = \"custom\";\n\t\t\texpect(osc.type).to.equal(\"custom\");\n\t\t\tosc.partials = [1, 2, 3];\n\t\t\texpect(osc.baseType).to.equal(\"custom\");\n\t\t\tosc.baseType = \"square\";\n\t\t\texpect(osc.type).to.equal(\"square\");\n\t\t\tosc.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/source/oscillator/FatOscillator.ts",
    "content": "import {\n\tCents,\n\tDegrees,\n\tFrequency,\n\tSeconds,\n\tTime,\n} from \"../../core/type/Units.js\";\nimport { assertRange } from \"../../core/util/Debug.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { noOp, readOnly } from \"../../core/util/Interface.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { Source } from \"../Source.js\";\nimport { Oscillator } from \"./Oscillator.js\";\nimport {\n\tFatConstructorOptions,\n\tFatOscillatorOptions,\n\tgenerateWaveform,\n\tNonCustomOscillatorType,\n\tToneOscillatorInterface,\n\tToneOscillatorType,\n} from \"./OscillatorInterface.js\";\n\nexport { FatOscillatorOptions } from \"./OscillatorInterface.js\";\n\n/**\n * FatOscillator is an array of oscillators with detune spread between the oscillators\n * @example\n * const fatOsc = new Tone.FatOscillator(\"Ab3\", \"sawtooth\", 40).toDestination().start();\n * @category Source\n */\nexport class FatOscillator\n\textends Source<FatOscillatorOptions>\n\timplements ToneOscillatorInterface\n{\n\treadonly name: string = \"FatOscillator\";\n\n\treadonly frequency: Signal<\"frequency\">;\n\treadonly detune: Signal<\"cents\">;\n\n\t/**\n\t * The array of oscillators\n\t */\n\tprivate _oscillators: Oscillator[] = [];\n\n\t/**\n\t * The total spread of the oscillators\n\t */\n\tprivate _spread: Cents;\n\n\t/**\n\t * The type of the oscillator\n\t */\n\tprivate _type: ToneOscillatorType;\n\n\t/**\n\t * The phase of the oscillators\n\t */\n\tprivate _phase: Degrees;\n\n\t/**\n\t * The partials array\n\t */\n\tprivate _partials: number[];\n\n\t/**\n\t * The number of partials to use\n\t */\n\tprivate _partialCount: number;\n\n\t/**\n\t * @param frequency The oscillator's frequency.\n\t * @param type The type of the oscillator.\n\t * @param spread The detune spread between the oscillators.\n\t */\n\tconstructor(\n\t\tfrequency?: Frequency,\n\t\ttype?: ToneOscillatorType,\n\t\tspread?: Cents\n\t);\n\tconstructor(options?: Partial<FatConstructorOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tFatOscillator.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"frequency\", \"type\", \"spread\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.frequency = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"frequency\",\n\t\t\tvalue: options.frequency,\n\t\t});\n\t\tthis.detune = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"cents\",\n\t\t\tvalue: options.detune,\n\t\t});\n\n\t\tthis._spread = options.spread;\n\t\tthis._type = options.type;\n\t\tthis._phase = options.phase;\n\t\tthis._partials = options.partials;\n\t\tthis._partialCount = options.partialCount;\n\n\t\t// set the count initially\n\t\tthis.count = options.count;\n\n\t\treadOnly(this, [\"frequency\", \"detune\"]);\n\t}\n\n\tstatic getDefaults(): FatOscillatorOptions {\n\t\treturn Object.assign(Oscillator.getDefaults(), {\n\t\t\tcount: 3,\n\t\t\tspread: 20,\n\t\t\ttype: \"sawtooth\",\n\t\t});\n\t}\n\n\t/**\n\t * start the oscillator\n\t */\n\tprotected _start(time: Time): void {\n\t\ttime = this.toSeconds(time);\n\t\tthis._forEach((osc) => osc.start(time));\n\t}\n\n\t/**\n\t * stop the oscillator\n\t */\n\tprotected _stop(time: Time): void {\n\t\ttime = this.toSeconds(time);\n\t\tthis._forEach((osc) => osc.stop(time));\n\t}\n\n\tprotected _restart(time: Seconds): void {\n\t\tthis._forEach((osc) => osc.restart(time));\n\t}\n\n\t/**\n\t * Iterate over all of the oscillators\n\t */\n\tprivate _forEach(iterator: (osc: Oscillator, index: number) => void): void {\n\t\tfor (let i = 0; i < this._oscillators.length; i++) {\n\t\t\titerator(this._oscillators[i], i);\n\t\t}\n\t}\n\n\t/**\n\t * The type of the oscillator\n\t */\n\tget type(): ToneOscillatorType {\n\t\treturn this._type;\n\t}\n\tset type(type: ToneOscillatorType) {\n\t\tthis._type = type;\n\t\tthis._forEach((osc) => (osc.type = type));\n\t}\n\n\t/**\n\t * The detune spread between the oscillators. If \"count\" is\n\t * set to 3 oscillators and the \"spread\" is set to 40,\n\t * the three oscillators would be detuned like this: [-20, 0, 20]\n\t * for a total detune spread of 40 cents.\n\t * @example\n\t * const fatOsc = new Tone.FatOscillator().toDestination().start();\n\t * fatOsc.spread = 70;\n\t */\n\tget spread(): Cents {\n\t\treturn this._spread;\n\t}\n\tset spread(spread: Cents) {\n\t\tthis._spread = spread;\n\t\tif (this._oscillators.length > 1) {\n\t\t\tconst start = -spread / 2;\n\t\t\tconst step = spread / (this._oscillators.length - 1);\n\t\t\tthis._forEach((osc, i) => (osc.detune.value = start + step * i));\n\t\t}\n\t}\n\n\t/**\n\t * The number of detuned oscillators. Must be an integer greater than 1.\n\t * @example\n\t * const fatOsc = new Tone.FatOscillator(\"C#3\", \"sawtooth\").toDestination().start();\n\t * // use 4 sawtooth oscillators\n\t * fatOsc.count = 4;\n\t */\n\tget count(): number {\n\t\treturn this._oscillators.length;\n\t}\n\tset count(count: number) {\n\t\tassertRange(count, 1);\n\t\tif (this._oscillators.length !== count) {\n\t\t\t// dispose the previous oscillators\n\t\t\tthis._forEach((osc) => osc.dispose());\n\t\t\tthis._oscillators = [];\n\t\t\tfor (let i = 0; i < count; i++) {\n\t\t\t\tconst osc = new Oscillator({\n\t\t\t\t\tcontext: this.context,\n\t\t\t\t\tvolume: -6 - count * 1.1,\n\t\t\t\t\ttype: this._type as NonCustomOscillatorType,\n\t\t\t\t\tphase: this._phase + (i / count) * 360,\n\t\t\t\t\tpartialCount: this._partialCount,\n\t\t\t\t\tonstop: i === 0 ? () => this.onstop(this) : noOp,\n\t\t\t\t});\n\t\t\t\tif (this.type === \"custom\") {\n\t\t\t\t\tosc.partials = this._partials;\n\t\t\t\t}\n\t\t\t\tthis.frequency.connect(osc.frequency);\n\t\t\t\tthis.detune.connect(osc.detune);\n\t\t\t\tosc.detune.overridden = false;\n\t\t\t\tosc.connect(this.output);\n\t\t\t\tthis._oscillators[i] = osc;\n\t\t\t}\n\t\t\t// set the spread\n\t\t\tthis.spread = this._spread;\n\t\t\tif (this.state === \"started\") {\n\t\t\t\tthis._forEach((osc) => osc.start());\n\t\t\t}\n\t\t}\n\t}\n\n\tget phase(): Degrees {\n\t\treturn this._phase;\n\t}\n\tset phase(phase: Degrees) {\n\t\tthis._phase = phase;\n\t\tthis._forEach(\n\t\t\t(osc, i) => (osc.phase = this._phase + (i / this.count) * 360)\n\t\t);\n\t}\n\n\tget baseType(): OscillatorType {\n\t\treturn this._oscillators[0].baseType;\n\t}\n\tset baseType(baseType: OscillatorType) {\n\t\tthis._forEach((osc) => (osc.baseType = baseType));\n\t\tthis._type = this._oscillators[0].type;\n\t}\n\n\tget partials(): number[] {\n\t\treturn this._oscillators[0].partials;\n\t}\n\tset partials(partials: number[]) {\n\t\tthis._partials = partials;\n\t\tthis._partialCount = this._partials.length;\n\t\tif (partials.length) {\n\t\t\tthis._type = \"custom\";\n\t\t\tthis._forEach((osc) => (osc.partials = partials));\n\t\t}\n\t}\n\n\tget partialCount(): number {\n\t\treturn this._oscillators[0].partialCount;\n\t}\n\tset partialCount(partialCount: number) {\n\t\tthis._partialCount = partialCount;\n\t\tthis._forEach((osc) => (osc.partialCount = partialCount));\n\t\tthis._type = this._oscillators[0].type;\n\t}\n\n\tasync asArray(length = 1024): Promise<Float32Array> {\n\t\treturn generateWaveform(this, length);\n\t}\n\n\t/**\n\t * Clean up.\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.frequency.dispose();\n\t\tthis.detune.dispose();\n\t\tthis._forEach((osc) => osc.dispose());\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/source/oscillator/LFO.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { OutputAudio } from \"../../../test/helper/OutputAudio.js\";\nimport { SignalConnectAndDisconnect } from \"../../../test/helper/SignalTests.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { LFO, LFOOptions } from \"./LFO.js\";\n\ndescribe(\"LFO\", () => {\n\tBasicTests(LFO);\n\tSignalConnectAndDisconnect(LFO);\n\n\tcontext(\"API\", () => {\n\t\tit(\"can get the current state\", () => {\n\t\t\tconst lfo = new LFO();\n\t\t\texpect(lfo.state).to.equal(\"stopped\");\n\t\t\tlfo.start();\n\t\t\texpect(lfo.state).to.equal(\"started\");\n\t\t\tlfo.dispose();\n\t\t});\n\t});\n\n\tcontext(\"Low Oscillations\", () => {\n\t\tit(\"can be started and stopped\", () => {\n\t\t\tconst lfo = new LFO();\n\t\t\tlfo.start();\n\t\t\tlfo.stop();\n\t\t\tlfo.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an object\", () => {\n\t\t\tconst lfo = new LFO({\n\t\t\t\tfrequency: 0.3,\n\t\t\t\ttype: \"triangle2\",\n\t\t\t});\n\t\t\texpect(lfo.type).to.equal(\"triangle2\");\n\t\t\texpect(lfo.frequency.value).to.be.closeTo(0.3, 0.001);\n\t\t\tlfo.dispose();\n\t\t});\n\n\t\tit(\"handles getters/setters as objects\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst lfo = new LFO();\n\t\t\t\tconst values = {\n\t\t\t\t\tfrequency: \"8n\",\n\t\t\t\t\tmax: 2,\n\t\t\t\t\tmin: -1,\n\t\t\t\t\tphase: 180,\n\t\t\t\t\ttype: \"square\",\n\t\t\t\t} as Partial<LFOOptions>;\n\t\t\t\tlfo.set(values);\n\t\t\t\texpect(lfo.get()).to.contain.keys(Object.keys(values));\n\t\t\t\texpect(lfo.type).to.equal(values.type);\n\t\t\t\texpect(lfo.min).to.equal(values.min);\n\t\t\t\texpect(lfo.max).to.equal(values.max);\n\t\t\t\texpect(lfo.phase).to.equal(values.phase);\n\t\t\t\texpect(lfo.frequency.value).to.be.closeTo(4, 0.1);\n\t\t\t\tlfo.dispose();\n\t\t\t});\n\t\t});\n\n\t\tit(\"outputs a signal\", () => {\n\t\t\treturn OutputAudio(() => {\n\t\t\t\tconst lfo = new LFO(100, 10, 20);\n\t\t\t\tlfo.toDestination();\n\t\t\t\tlfo.start();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can be creates an oscillation in a specific range\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst lfo = new LFO(100, 10, 20).toDestination();\n\t\t\t\tlfo.start();\n\t\t\t});\n\t\t\texpect(buffer.min()).to.be.gte(10);\n\t\t\texpect(buffer.max()).to.be.lte(20);\n\t\t});\n\n\t\tit(\"can change the oscillation range\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst lfo = new LFO(100, 10, 20).toDestination();\n\t\t\t\tlfo.start();\n\t\t\t\tlfo.min = 15;\n\t\t\t\tlfo.max = 18;\n\t\t\t});\n\t\t\texpect(buffer.min()).to.be.gte(15);\n\t\t\texpect(buffer.max()).to.be.lte(18);\n\t\t});\n\n\t\tit(\"initially outputs a signal at the center of its phase\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tnew LFO(100, 10, 20).toDestination();\n\t\t\t});\n\t\t\texpect(buffer.value()).to.be.closeTo(15, 0.1);\n\t\t});\n\n\t\tit(\"outputs a signal at the correct phase angle\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tnew LFO({\n\t\t\t\t\tmin: 0,\n\t\t\t\t\tphase: 90,\n\t\t\t\t}).toDestination();\n\t\t\t});\n\t\t\texpect(buffer.value()).to.be.closeTo(0, 0.1);\n\t\t});\n\n\t\tit(\"outputs the right phase when setting a new phase\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst lfo = new LFO({\n\t\t\t\t\tmax: 1,\n\t\t\t\t\tmin: -1,\n\t\t\t\t\tphase: 0,\n\t\t\t\t}).toDestination();\n\t\t\t\tlfo.phase = 270;\n\t\t\t});\n\t\t\texpect(buffer.value()).to.be.closeTo(1, 0.1);\n\t\t});\n\n\t\tit(\"can convert to other units\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst lfo = new LFO({\n\t\t\t\t\tfrequency: 20,\n\t\t\t\t\tmax: 5,\n\t\t\t\t\tmin: -20,\n\t\t\t\t\tunits: \"decibels\",\n\t\t\t\t}).toDestination();\n\t\t\t\tlfo.start();\n\t\t\t});\n\t\t\texpect(buffer.min()).to.be.closeTo(0.099, 0.01);\n\t\t\texpect(buffer.max()).to.be.closeTo(1.78, 0.01);\n\t\t});\n\n\t\tit(\"can converts to the units of the connecting node\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst lfo = new LFO(20, -35, -10);\n\t\t\t\tconst signal = new Signal(0, \"decibels\");\n\t\t\t\texpect(lfo.units).to.equal(\"number\");\n\t\t\t\tlfo.toDestination();\n\t\t\t\tlfo.connect(signal);\n\t\t\t\texpect(lfo.units).to.equal(\"decibels\");\n\t\t\t\tlfo.start();\n\t\t\t});\n\t\t\texpect(buffer.min()).to.be.closeTo(0.017, 0.01);\n\t\t\texpect(buffer.max()).to.be.closeTo(0.31, 0.01);\n\t\t});\n\n\t\tit(\"does not convert to the connected value if that is not set to convert\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst lfo = new LFO(20, -35, -10);\n\t\t\t\tconst signal = new Signal({\n\t\t\t\t\tconvert: false,\n\t\t\t\t\tunits: \"decibels\",\n\t\t\t\t\tvalue: 0,\n\t\t\t\t});\n\t\t\t\texpect(lfo.units).to.equal(\"number\");\n\t\t\t\tlfo.toDestination();\n\t\t\t\tlfo.connect(signal);\n\t\t\t\texpect(lfo.units).to.equal(\"decibels\");\n\t\t\t\tlfo.start();\n\t\t\t});\n\t\t\texpect(buffer.min()).to.be.closeTo(-35, 0.01);\n\t\t\texpect(buffer.max()).to.be.closeTo(-10, 0.01);\n\t\t});\n\n\t\tit(\"can sync the frequency to the Transport\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst lfo = new LFO(2);\n\t\t\t\tlfo.sync();\n\t\t\t\tlfo.frequency.toDestination();\n\t\t\t\ttransport.bpm.setValueAtTime(transport.bpm.value * 2, 0.05);\n\t\t\t\t// transport.start(0)\n\t\t\t}, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(2, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.05)).to.be.closeTo(4, 0.1);\n\t\t});\n\n\t\tit(\"can unsync the frequency to the transport\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst lfo = new LFO(2);\n\t\t\t\tlfo.sync();\n\t\t\t\tlfo.frequency.toDestination();\n\t\t\t\ttransport.bpm.setValueAtTime(transport.bpm.value * 2, 0.05);\n\t\t\t\tlfo.unsync();\n\t\t\t\ttransport.start(0);\n\t\t\t}, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(2, 0.1);\n\t\t\texpect(buffer.getValueAtTime(0.05)).to.be.closeTo(2, 0.1);\n\t\t});\n\n\t\tit(\"can adjust the amplitude\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst lfo = new LFO(10, -10, 10);\n\t\t\t\tlfo.amplitude.value = 0.5;\n\t\t\t\tlfo.toDestination();\n\t\t\t\tlfo.start();\n\t\t\t}, 0.1);\n\t\t\texpect(buffer.min()).to.be.closeTo(-5, 0.1);\n\t\t\texpect(buffer.max()).to.be.closeTo(5, 0.1);\n\t\t});\n\n\t\tit(\"can adjust the amplitude not centered at 0\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst lfo = new LFO(10, 400, 4000);\n\t\t\t\tlfo.amplitude.value = 0.5;\n\t\t\t\tlfo.toDestination();\n\t\t\t\tlfo.start();\n\t\t\t}, 0.1);\n\t\t\texpect(buffer.min()).to.be.closeTo(1300, 1);\n\t\t\texpect(buffer.max()).to.be.closeTo(3100, 1);\n\t\t});\n\n\t\tit(\"can pass in partials to the constructor\", () => {\n\t\t\tconst lfo = new LFO({\n\t\t\t\ttype: \"custom\",\n\t\t\t\tpartials: [0, 2, 3],\n\t\t\t});\n\t\t\texpect(lfo.partials).to.deep.equal([0, 2, 3]);\n\t\t\tlfo.partials = [1, 2, 3];\n\t\t\texpect(lfo.partials).to.deep.equal([1, 2, 3]);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/source/oscillator/LFO.ts",
    "content": "import { Gain } from \"../../core/context/Gain.js\";\nimport { Param } from \"../../core/context/Param.js\";\nimport {\n\tInputNode,\n\tOutputNode,\n\tToneAudioNode,\n} from \"../../core/context/ToneAudioNode.js\";\nimport {\n\tDegrees,\n\tFrequency,\n\tNormalRange,\n\tTime,\n\tUnitName,\n} from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly } from \"../../core/util/Interface.js\";\nimport { BasicPlaybackState } from \"../../core/util/StateTimeline.js\";\nimport { AudioToGain } from \"../../signal/AudioToGain.js\";\nimport { Scale } from \"../../signal/Scale.js\";\nimport {\n\tconnectSignal,\n\tdisconnectSignal,\n\tSignal,\n} from \"../../signal/Signal.js\";\nimport { Zero } from \"../../signal/Zero.js\";\nimport { Oscillator, ToneOscillatorType } from \"./Oscillator.js\";\nimport {\n\tToneOscillatorConstructorOptions,\n\tToneOscillatorOptions,\n} from \"./OscillatorInterface.js\";\n\nexport type LFOOptions = {\n\tmin: number;\n\tmax: number;\n\tamplitude: NormalRange;\n\tunits: UnitName;\n} & ToneOscillatorOptions;\n\n/**\n * LFO stands for low frequency oscillator. LFO produces an output signal\n * which can be attached to an AudioParam or Tone.Signal\n * in order to modulate that parameter with an oscillator. The LFO can\n * also be synced to the transport to start/stop and change when the tempo changes.\n * @example\n * return Tone.Offline(() => {\n * \tconst lfo = new Tone.LFO(\"4n\", 400, 4000).start().toDestination();\n * }, 0.5, 1);\n * @category Source\n */\nexport class LFO extends ToneAudioNode<LFOOptions> {\n\treadonly name: string = \"LFO\";\n\n\t/**\n\t * The oscillator.\n\t */\n\tprivate _oscillator: Oscillator;\n\n\t/**\n\t * The gain of the output\n\t */\n\tprivate _amplitudeGain: Gain<\"normalRange\">;\n\n\t/**\n\t * The amplitude of the LFO, which controls the output range between\n\t * the min and max output. For example if the min is -10 and the max\n\t * is 10, setting the amplitude to 0.5 would make the LFO modulate\n\t * between -5 and 5.\n\t */\n\treadonly amplitude: Param<\"normalRange\">;\n\n\t/**\n\t * The signal which is output when the LFO is stopped\n\t */\n\tprivate _stoppedSignal: Signal<\"audioRange\">;\n\n\t/**\n\t * Just outputs zeros. This is used so that scaled signal is not\n\t * optimized to silence.\n\t */\n\tprivate _zeros: Zero;\n\n\t/**\n\t * The value that the LFO outputs when its stopped\n\t */\n\tprivate _stoppedValue = 0;\n\n\t/**\n\t * Convert the oscillators audio range to an output between 0-1 so it can be scaled\n\t */\n\tprivate _a2g: AudioToGain;\n\n\t/**\n\t * Scales the final output to the min and max value\n\t */\n\tprivate _scaler: Scale;\n\n\t/**\n\t * The output of the LFO\n\t */\n\treadonly output: OutputNode;\n\n\t/**\n\t * There is no input node\n\t */\n\treadonly input: undefined;\n\n\t/**\n\t * A private placeholder for the units\n\t */\n\tprivate _units: UnitName = \"number\";\n\n\t/**\n\t * If the input value is converted using the {@link units}\n\t */\n\tconvert = true;\n\n\t/**\n\t * The frequency value of the LFO\n\t */\n\treadonly frequency: Signal<\"frequency\">;\n\n\t/**\n\t * @param frequency The frequency of the oscillation.\n\t * Typically, LFOs will be in the frequency range of 0.1 to 10 hertz.\n\t * @param min The minimum output value of the LFO.\n\t * @param max The maximum value of the LFO.\n\t */\n\tconstructor(frequency?: Frequency, min?: number, max?: number);\n\tconstructor(options?: Partial<LFOOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(LFO.getDefaults(), arguments, [\n\t\t\t\"frequency\",\n\t\t\t\"min\",\n\t\t\t\"max\",\n\t\t]);\n\t\tsuper(options);\n\n\t\tthis._oscillator = new Oscillator(\n\t\t\toptions as ToneOscillatorConstructorOptions\n\t\t);\n\n\t\tthis.frequency = this._oscillator.frequency;\n\n\t\tthis._amplitudeGain = new Gain({\n\t\t\tcontext: this.context,\n\t\t\tgain: options.amplitude,\n\t\t\tunits: \"normalRange\",\n\t\t});\n\t\tthis.amplitude = this._amplitudeGain.gain;\n\t\tthis._stoppedSignal = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"audioRange\",\n\t\t\tvalue: 0,\n\t\t});\n\t\tthis._zeros = new Zero({ context: this.context });\n\t\tthis._a2g = new AudioToGain({ context: this.context });\n\t\tthis._scaler = this.output = new Scale({\n\t\t\tcontext: this.context,\n\t\t\tmax: options.max,\n\t\t\tmin: options.min,\n\t\t});\n\n\t\tthis.units = options.units;\n\t\tthis.min = options.min;\n\t\tthis.max = options.max;\n\n\t\t// connect it up\n\t\tthis._oscillator.chain(this._amplitudeGain, this._a2g, this._scaler);\n\t\tthis._zeros.connect(this._a2g);\n\t\tthis._stoppedSignal.connect(this._a2g);\n\t\treadOnly(this, [\"amplitude\", \"frequency\"]);\n\t\tthis.phase = options.phase;\n\t}\n\n\tstatic getDefaults(): LFOOptions {\n\t\treturn Object.assign(Oscillator.getDefaults(), {\n\t\t\tamplitude: 1,\n\t\t\tfrequency: \"4n\",\n\t\t\tmax: 1,\n\t\t\tmin: 0,\n\t\t\ttype: \"sine\",\n\t\t\tunits: \"number\" as UnitName,\n\t\t});\n\t}\n\n\t/**\n\t * Start the LFO.\n\t * @param time The time the LFO will start\n\t */\n\tstart(time?: Time): this {\n\t\ttime = this.toSeconds(time);\n\t\tthis._stoppedSignal.setValueAtTime(0, time);\n\t\tthis._oscillator.start(time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop the LFO.\n\t * @param  time The time the LFO will stop\n\t */\n\tstop(time?: Time): this {\n\t\ttime = this.toSeconds(time);\n\t\tthis._stoppedSignal.setValueAtTime(this._stoppedValue, time);\n\t\tthis._oscillator.stop(time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sync the start/stop/pause to the transport\n\t * and the frequency to the bpm of the transport\n\t * @example\n\t * const lfo = new Tone.LFO(\"8n\");\n\t * lfo.sync().start(0);\n\t * // the rate of the LFO will always be an eighth note, even as the tempo changes\n\t */\n\tsync(): this {\n\t\tthis._oscillator.sync();\n\t\tthis._oscillator.syncFrequency();\n\t\treturn this;\n\t}\n\n\t/**\n\t * unsync the LFO from transport control\n\t */\n\tunsync(): this {\n\t\tthis._oscillator.unsync();\n\t\tthis._oscillator.unsyncFrequency();\n\t\treturn this;\n\t}\n\n\t/**\n\t * After the oscillator waveform is updated, reset the `_stoppedSignal` value to match the updated waveform\n\t */\n\tprivate _setStoppedValue() {\n\t\tthis._stoppedValue = this._oscillator.getInitialValue();\n\t\tthis._stoppedSignal.value = this._stoppedValue;\n\t}\n\n\t/**\n\t * The minimum output of the LFO.\n\t */\n\tget min(): number {\n\t\treturn this._toType(this._scaler.min);\n\t}\n\tset min(min) {\n\t\tmin = this._fromType(min);\n\t\tthis._scaler.min = min;\n\t}\n\n\t/**\n\t * The maximum output of the LFO.\n\t */\n\tget max(): number {\n\t\treturn this._toType(this._scaler.max);\n\t}\n\tset max(max) {\n\t\tmax = this._fromType(max);\n\t\tthis._scaler.max = max;\n\t}\n\n\t/**\n\t * The type of the oscillator.\n\t * @see {@link Oscillator.type}\n\t */\n\tget type(): ToneOscillatorType {\n\t\treturn this._oscillator.type;\n\t}\n\tset type(type) {\n\t\tthis._oscillator.type = type;\n\t\tthis._setStoppedValue();\n\t}\n\n\t/**\n\t * The oscillator's partials array.\n\t * @see {@link Oscillator.partials}\n\t */\n\tget partials(): number[] {\n\t\treturn this._oscillator.partials;\n\t}\n\tset partials(partials) {\n\t\tthis._oscillator.partials = partials;\n\t\tthis._setStoppedValue();\n\t}\n\n\t/**\n\t * The phase of the LFO.\n\t */\n\tget phase(): Degrees {\n\t\treturn this._oscillator.phase;\n\t}\n\tset phase(phase) {\n\t\tthis._oscillator.phase = phase;\n\t\tthis._setStoppedValue();\n\t}\n\n\t/**\n\t * The output units of the LFO.\n\t */\n\tget units(): UnitName {\n\t\treturn this._units;\n\t}\n\tset units(val) {\n\t\tconst currentMin = this.min;\n\t\tconst currentMax = this.max;\n\t\t// convert the min and the max\n\t\tthis._units = val;\n\t\tthis.min = currentMin;\n\t\tthis.max = currentMax;\n\t}\n\n\t/**\n\t * Returns the playback state of the source, either \"started\" or \"stopped\".\n\t */\n\tget state(): BasicPlaybackState {\n\t\treturn this._oscillator.state;\n\t}\n\n\t/**\n\t * @param node the destination to connect to\n\t * @param outputNum the optional output number\n\t * @param inputNum the input number\n\t */\n\tconnect(node: InputNode, outputNum?: number, inputNum?: number): this {\n\t\tif (node instanceof Param || node instanceof Signal) {\n\t\t\tthis.convert = node.convert;\n\t\t\tthis.units = node.units;\n\t\t}\n\t\tconnectSignal(this, node, outputNum, inputNum);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Disconnect the LFO.\n\t */\n\tdisconnect(destination?: InputNode, outputNum = 0, inputNum = 0): this {\n\t\tdisconnectSignal(this, destination, outputNum, inputNum);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Private methods borrowed from Param\n\t */\n\t// @ts-ignore\n\tprivate _fromType = Param.prototype._fromType;\n\t// @ts-ignore\n\tprivate _toType = Param.prototype._toType;\n\t// @ts-ignore\n\tprivate _is = Param.prototype._is;\n\t// @ts-ignore\n\tprivate _clampValue = Param.prototype._clampValue;\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._oscillator.dispose();\n\t\tthis._stoppedSignal.dispose();\n\t\tthis._zeros.dispose();\n\t\tthis._scaler.dispose();\n\t\tthis._a2g.dispose();\n\t\tthis._amplitudeGain.dispose();\n\t\tthis.amplitude.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/source/oscillator/OmniOscillator.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../../test/helper/CompareToFile.js\";\nimport { OscillatorTests } from \"../../../test/helper/OscillatorTests.js\";\nimport { OutputAudio } from \"../../../test/helper/OutputAudio.js\";\nimport { SourceTests } from \"../../../test/helper/SourceTests.js\";\nimport { FMOscillator } from \"./FMOscillator.js\";\nimport { OmniOscillator } from \"./OmniOscillator.js\";\nimport { OmniOscillatorType } from \"./OscillatorInterface.js\";\nimport { PulseOscillator } from \"./PulseOscillator.js\";\nimport { PWMOscillator } from \"./PWMOscillator.js\";\n\ndescribe(\"OmniOscillator\", () => {\n\t// run the common tests\n\tBasicTests(OmniOscillator);\n\tSourceTests(OmniOscillator);\n\tOscillatorTests(OmniOscillator);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst osc = new OmniOscillator(220, \"fmsquare\").toDestination();\n\t\t\t\tosc.start(0.1).stop(0.2);\n\t\t\t},\n\t\t\t\"omniOscillator.wav\",\n\t\t\t1.6\n\t\t);\n\t});\n\n\tcontext(\"Sound\", () => {\n\t\tit(\"makes a sound\", () => {\n\t\t\treturn OutputAudio(() => {\n\t\t\t\tconst osc = new OmniOscillator();\n\t\t\t\tosc.toDestination();\n\t\t\t\tosc.start(0);\n\t\t\t});\n\t\t});\n\n\t\tit(\"makes a sound when set to square\", () => {\n\t\t\treturn OutputAudio(() => {\n\t\t\t\tconst osc = new OmniOscillator(440, \"square\");\n\t\t\t\tosc.toDestination();\n\t\t\t\tosc.start();\n\t\t\t});\n\t\t});\n\n\t\tit(\"makes a sound when set to pulse\", () => {\n\t\t\treturn OutputAudio(() => {\n\t\t\t\tconst osc = new OmniOscillator(440, \"pulse\");\n\t\t\t\tosc.toDestination();\n\t\t\t\tosc.start();\n\t\t\t});\n\t\t});\n\n\t\tit(\"makes a sound when set to pwm\", () => {\n\t\t\treturn OutputAudio(() => {\n\t\t\t\tconst osc = new OmniOscillator(440, \"pwm\");\n\t\t\t\tosc.toDestination();\n\t\t\t\tosc.start();\n\t\t\t});\n\t\t});\n\n\t\tit(\"makes a sound when set to fm\", () => {\n\t\t\treturn OutputAudio(() => {\n\t\t\t\tconst osc = new OmniOscillator(440, \"fmsquare\");\n\t\t\t\tosc.toDestination();\n\t\t\t\tosc.start();\n\t\t\t});\n\t\t});\n\n\t\tit(\"makes a sound when set to am\", () => {\n\t\t\treturn OutputAudio(() => {\n\t\t\t\tconst osc = new OmniOscillator(440, \"amsine\");\n\t\t\t\tosc.toDestination();\n\t\t\t\tosc.start();\n\t\t\t});\n\t\t});\n\n\t\tit(\"makes a sound when set to fat\", () => {\n\t\t\treturn OutputAudio(() => {\n\t\t\t\tconst osc = new OmniOscillator(440, \"fatsawtooth\");\n\t\t\t\tosc.toDestination();\n\t\t\t\tosc.start();\n\t\t\t});\n\t\t});\n\n\t\tit(\"can switch type after playing\", () => {\n\t\t\treturn OutputAudio(() => {\n\t\t\t\tconst osc = new OmniOscillator(440, \"amsine\");\n\t\t\t\tosc.toDestination();\n\t\t\t\tosc.start();\n\t\t\t\tosc.type = \"fmsine\";\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"Type\", () => {\n\t\tit(\"can get and set the type\", () => {\n\t\t\tconst osc = new OmniOscillator({\n\t\t\t\ttype: \"sawtooth\",\n\t\t\t});\n\t\t\texpect(osc.type).to.equal(\"sawtooth\");\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"handles various types\", () => {\n\t\t\tconst osc = new OmniOscillator();\n\t\t\tconst types: OmniOscillatorType[] = [\n\t\t\t\t\"triangle3\",\n\t\t\t\t\"sine\",\n\t\t\t\t\"pulse\",\n\t\t\t\t\"pwm\",\n\t\t\t\t\"amsine4\",\n\t\t\t\t\"fatsquare2\",\n\t\t\t\t\"fmsawtooth\",\n\t\t\t];\n\t\t\ttypes.forEach((type) => {\n\t\t\t\tosc.type = type;\n\t\t\t\texpect(osc.type).to.equal(type);\n\t\t\t});\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"throws an error if invalid type is set\", () => {\n\t\t\tconst osc = new OmniOscillator();\n\t\t\texpect(() => {\n\t\t\t\t// @ts-ignore\n\t\t\t\tosc.type = \"invalid\";\n\t\t\t}).to.throw(Error);\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"can set extended types\", () => {\n\t\t\tconst osc = new OmniOscillator();\n\t\t\tosc.type = \"sine5\";\n\t\t\texpect(osc.type).to.equal(\"sine5\");\n\t\t\tosc.type = \"triangle2\";\n\t\t\texpect(osc.type).to.equal(\"triangle2\");\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"can set the modulation frequency only when type is pwm\", () => {\n\t\t\tconst omni = new OmniOscillator<PWMOscillator>();\n\t\t\tomni.type = \"pwm\";\n\t\t\texpect(() => {\n\t\t\t\tomni.modulationFrequency.value = 0.2;\n\t\t\t}).to.not.throw(Error);\n\t\t\tomni.type = \"pulse\";\n\t\t\texpect(() => {\n\t\t\t\tomni.modulationFrequency.value = 0.2;\n\t\t\t}).to.throw(Error);\n\t\t\tomni.dispose();\n\t\t});\n\n\t\tit(\"can set the modulation width only when type is pulse\", () => {\n\t\t\tconst omni = new OmniOscillator<PulseOscillator>();\n\t\t\tomni.type = \"pulse\";\n\t\t\texpect(() => {\n\t\t\t\tomni.width.value = 0.2;\n\t\t\t}).to.not.throw(Error);\n\t\t\tomni.type = \"sine\";\n\t\t\texpect(() => {\n\t\t\t\tomni.width.value = 0.2;\n\t\t\t}).to.throw(Error);\n\t\t\tomni.dispose();\n\t\t});\n\n\t\tit(\"can be set to an FM oscillator\", () => {\n\t\t\tconst omni = new OmniOscillator<FMOscillator>();\n\t\t\tomni.set({\n\t\t\t\tmodulationIndex: 2,\n\t\t\t\ttype: \"fmsquare2\",\n\t\t\t});\n\t\t\texpect(omni.type).to.equal(\"fmsquare2\");\n\t\t\texpect(omni.modulationIndex.value).to.equal(2);\n\t\t\tomni.dispose();\n\t\t});\n\n\t\tit(\"can be set to an AM oscillator\", () => {\n\t\t\tconst omni = new OmniOscillator();\n\t\t\tomni.set({\n\t\t\t\ttype: \"amsquare\",\n\t\t\t});\n\t\t\tomni.modulationType = \"sawtooth2\";\n\t\t\texpect(omni.type).to.equal(\"amsquare\");\n\t\t\texpect(omni.modulationType).to.equal(\"sawtooth2\");\n\t\t\tomni.dispose();\n\t\t});\n\n\t\tit(\"can be set to an FatOscillator\", () => {\n\t\t\tconst omni = new OmniOscillator({\n\t\t\t\tcount: 4,\n\t\t\t\tspread: 25,\n\t\t\t\ttype: \"fatsquare2\",\n\t\t\t});\n\t\t\texpect(omni.type).to.equal(\"fatsquare2\");\n\t\t\texpect(omni.count).to.equal(4);\n\t\t\texpect(omni.spread).to.equal(25);\n\t\t\tomni.dispose();\n\t\t});\n\n\t\tit(\"can get/set the partialCount\", () => {\n\t\t\tconst omni = new OmniOscillator({\n\t\t\t\ttype: \"square2\",\n\t\t\t});\n\t\t\texpect(omni.partialCount).to.equal(2);\n\t\t\tomni.partialCount = 3;\n\t\t\texpect(omni.partialCount).to.equal(3);\n\t\t\texpect(omni.type).to.equal(\"square3\");\n\t\t\tomni.dispose();\n\t\t});\n\n\t\tit(\"can get/set the basic parameters\", () => {\n\t\t\tconst omni = new OmniOscillator({\n\t\t\t\ttype: \"square\",\n\t\t\t\tdetune: 20,\n\t\t\t\tvolume: -20,\n\t\t\t\tfrequency: 200,\n\t\t\t});\n\t\t\texpect(omni.get().detune).to.be.closeTo(20, 0.1);\n\t\t\texpect(omni.get().volume).to.be.closeTo(-20, 0.1);\n\t\t\texpect(omni.get().type).to.equal(\"square\");\n\t\t\texpect(omni.get().frequency).to.be.closeTo(200, 1);\n\t\t\tomni.dispose();\n\t\t});\n\n\t\tit(\"can get/set the sourceType\", () => {\n\t\t\tconst omni = new OmniOscillator({\n\t\t\t\ttype: \"fatsquare3\",\n\t\t\t});\n\t\t\texpect(omni.type).to.equal(\"fatsquare3\");\n\t\t\texpect(omni.sourceType).to.equal(\"fat\");\n\t\t\tomni.sourceType = \"oscillator\";\n\t\t\texpect(omni.sourceType).to.equal(\"oscillator\");\n\t\t\texpect(omni.type).to.equal(\"square3\");\n\t\t\tomni.sourceType = \"pulse\";\n\t\t\texpect(omni.sourceType).to.equal(\"pulse\");\n\t\t\texpect(omni.type).to.equal(\"pulse\");\n\t\t\tomni.sourceType = \"fm\";\n\t\t\texpect(omni.sourceType).to.equal(\"fm\");\n\t\t\texpect(omni.type).to.equal(\"fmsine\");\n\t\t\tomni.sourceType = \"pwm\";\n\t\t\texpect(omni.sourceType).to.equal(\"pwm\");\n\t\t\texpect(omni.type).to.equal(\"pwm\");\n\t\t\tomni.sourceType = \"am\";\n\t\t\texpect(omni.sourceType).to.equal(\"am\");\n\t\t\texpect(omni.type).to.equal(\"amsine\");\n\t\t\tomni.sourceType = \"fat\";\n\t\t\texpect(omni.type).to.equal(\"fatsine\");\n\t\t\tomni.dispose();\n\t\t});\n\n\t\tit(\"can get/set the baseType\", () => {\n\t\t\tconst omni = new OmniOscillator({\n\t\t\t\ttype: \"fatsquare3\",\n\t\t\t});\n\t\t\texpect(omni.type).to.equal(\"fatsquare3\");\n\t\t\texpect(omni.sourceType).to.equal(\"fat\");\n\t\t\texpect(omni.baseType).to.equal(\"square\");\n\t\t\texpect(omni.partialCount).to.equal(3);\n\t\t\tomni.partialCount = 2;\n\t\t\texpect(omni.type).to.equal(\"fatsquare2\");\n\t\t\tomni.type = \"amsine\";\n\t\t\texpect(omni.baseType).to.equal(\"sine\");\n\t\t\tomni.baseType = \"square\";\n\t\t\texpect(omni.type).to.equal(\"amsquare\");\n\t\t\tomni.type = \"pwm\";\n\t\t\texpect(omni.baseType).to.equal(\"pwm\");\n\t\t\tomni.type = \"triangle4\";\n\t\t\texpect(omni.baseType).to.equal(\"triangle\");\n\t\t\tomni.baseType = \"square\";\n\t\t\texpect(omni.type).to.equal(\"square4\");\n\t\t\tomni.dispose();\n\t\t});\n\n\t\tit(\"can set a FM oscillator with partials\", () => {\n\t\t\tconst omni = new OmniOscillator<FMOscillator>({\n\t\t\t\tdetune: 4,\n\t\t\t\tharmonicity: 2,\n\t\t\t\tpartials: [2, 1, 2, 2],\n\t\t\t\tphase: 120,\n\t\t\t\ttype: \"fmcustom\",\n\t\t\t\tvolume: -2,\n\t\t\t});\n\t\t\texpect(omni.volume.value).to.be.closeTo(-2, 0.01);\n\t\t\texpect(omni.detune.value).to.be.closeTo(4, 0.01);\n\t\t\texpect(omni.phase).to.be.closeTo(120, 0.01);\n\t\t\texpect(omni.type).to.be.equal(\"fmcustom\");\n\t\t\texpect(omni.partials).to.deep.equal([2, 1, 2, 2]);\n\t\t\texpect(omni.harmonicity.value).be.closeTo(2, 0.01);\n\t\t\tomni.dispose();\n\t\t});\n\n\t\tit(\"setting/getting values when the wrong type is set has no effect\", () => {\n\t\t\tconst omni = new OmniOscillator(440, \"sine\");\n\t\t\tomni.set({\n\t\t\t\tharmonicity: 3,\n\t\t\t\tmodulationIndex: 4,\n\t\t\t});\n\t\t\tomni.spread = 40;\n\t\t\texpect(omni.spread).to.be.undefined;\n\t\t\tomni.count = 5;\n\t\t\texpect(omni.count).to.be.undefined;\n\t\t\tomni.modulationType = \"sine\";\n\t\t\texpect(omni.modulationType).to.be.undefined;\n\t\t\texpect(omni.modulationIndex).to.be.undefined;\n\t\t\texpect(omni.harmonicity).to.be.undefined;\n\t\t\tomni.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/source/oscillator/OmniOscillator.ts",
    "content": "import {\n\tCents,\n\tDegrees,\n\tFrequency,\n\tSeconds,\n\tTime,\n} from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly } from \"../../core/util/Interface.js\";\nimport { isNumber, isString } from \"../../core/util/TypeCheck.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { Source } from \"../Source.js\";\nimport { AMOscillator } from \"./AMOscillator.js\";\nimport { FatOscillator } from \"./FatOscillator.js\";\nimport { FMOscillator } from \"./FMOscillator.js\";\nimport { Oscillator } from \"./Oscillator.js\";\nimport {\n\tgenerateWaveform,\n\tOmniOscillatorOptions,\n\tOmniOscillatorType,\n\tToneOscillatorInterface,\n\tToneOscillatorType,\n} from \"./OscillatorInterface.js\";\nimport { PulseOscillator } from \"./PulseOscillator.js\";\nimport { PWMOscillator } from \"./PWMOscillator.js\";\n\nexport { OmniOscillatorOptions } from \"./OscillatorInterface.js\";\n\n/**\n * All of the oscillator types that OmniOscillator can take on\n */\ntype AnyOscillator =\n\t| Oscillator\n\t| PWMOscillator\n\t| PulseOscillator\n\t| FatOscillator\n\t| AMOscillator\n\t| FMOscillator;\n\n/**\n * All of the Oscillator constructor types mapped to their name.\n */\ninterface OmniOscillatorSource {\n\tfm: FMOscillator;\n\tam: AMOscillator;\n\tpwm: PWMOscillator;\n\tpulse: PulseOscillator;\n\toscillator: Oscillator;\n\tfat: FatOscillator;\n}\n\n/**\n * The available oscillator types.\n */\nexport type OmniOscSourceType = keyof OmniOscillatorSource;\n\n// Conditional Types\ntype IsAmOrFmOscillator<Osc, Ret> = Osc extends AMOscillator\n\t? Ret\n\t: Osc extends FMOscillator\n\t\t? Ret\n\t\t: undefined;\ntype IsFatOscillator<Osc, Ret> = Osc extends FatOscillator ? Ret : undefined;\ntype IsPWMOscillator<Osc, Ret> = Osc extends PWMOscillator ? Ret : undefined;\ntype IsPulseOscillator<Osc, Ret> = Osc extends PulseOscillator\n\t? Ret\n\t: undefined;\ntype IsFMOscillator<Osc, Ret> = Osc extends FMOscillator ? Ret : undefined;\n\ntype AnyOscillatorConstructor = new (...args: any[]) => AnyOscillator;\n\nconst OmniOscillatorSourceMap: {\n\t[key in OmniOscSourceType]: AnyOscillatorConstructor;\n} = {\n\tam: AMOscillator,\n\tfat: FatOscillator,\n\tfm: FMOscillator,\n\toscillator: Oscillator,\n\tpulse: PulseOscillator,\n\tpwm: PWMOscillator,\n};\n\n/**\n * OmniOscillator aggregates all of the oscillator types into one.\n * @example\n * return Tone.Offline(() => {\n * \tconst omniOsc = new Tone.OmniOscillator(\"C#4\", \"pwm\").toDestination().start();\n * }, 0.1, 1);\n * @category Source\n */\nexport class OmniOscillator<OscType extends AnyOscillator>\n\textends Source<OmniOscillatorOptions>\n\timplements Omit<ToneOscillatorInterface, \"type\">\n{\n\treadonly name: string = \"OmniOscillator\";\n\n\treadonly frequency: Signal<\"frequency\">;\n\treadonly detune: Signal<\"cents\">;\n\n\t/**\n\t * The oscillator that can switch types\n\t */\n\tprivate _oscillator!: AnyOscillator;\n\n\t/**\n\t * the type of the oscillator source\n\t */\n\tprivate _sourceType!: OmniOscSourceType;\n\n\t/**\n\t * @param frequency The initial frequency of the oscillator.\n\t * @param type The type of the oscillator.\n\t */\n\tconstructor(frequency?: Frequency, type?: OmniOscillatorType);\n\tconstructor(options?: Partial<OmniOscillatorOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tOmniOscillator.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"frequency\", \"type\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.frequency = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"frequency\",\n\t\t\tvalue: options.frequency,\n\t\t});\n\t\tthis.detune = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"cents\",\n\t\t\tvalue: options.detune,\n\t\t});\n\t\treadOnly(this, [\"frequency\", \"detune\"]);\n\n\t\t// set the options\n\t\tthis.set(options);\n\t}\n\n\tstatic getDefaults(): OmniOscillatorOptions {\n\t\treturn Object.assign(\n\t\t\tOscillator.getDefaults(),\n\t\t\tFMOscillator.getDefaults(),\n\t\t\tAMOscillator.getDefaults(),\n\t\t\tFatOscillator.getDefaults(),\n\t\t\tPulseOscillator.getDefaults(),\n\t\t\tPWMOscillator.getDefaults()\n\t\t);\n\t}\n\n\t/**\n\t * start the oscillator\n\t */\n\tprotected _start(time: Time): void {\n\t\tthis._oscillator.start(time);\n\t}\n\n\t/**\n\t * start the oscillator\n\t */\n\tprotected _stop(time: Time): void {\n\t\tthis._oscillator.stop(time);\n\t}\n\n\tprotected _restart(time: Seconds): this {\n\t\tthis._oscillator.restart(time);\n\t\treturn this;\n\t}\n\n\t/**\n\t * The type of the oscillator. Can be any of the basic types: sine, square, triangle, sawtooth. Or\n\t * prefix the basic types with \"fm\", \"am\", or \"fat\" to use the FMOscillator, AMOscillator or FatOscillator\n\t * types. The oscillator could also be set to \"pwm\" or \"pulse\". All of the parameters of the\n\t * oscillator's class are accessible when the oscillator is set to that type, but throws an error\n\t * when it's not.\n\t * @example\n\t * const omniOsc = new Tone.OmniOscillator().toDestination().start();\n\t * omniOsc.type = \"pwm\";\n\t * // modulationFrequency is parameter which is available\n\t * // only when the type is \"pwm\".\n\t * omniOsc.modulationFrequency.value = 0.5;\n\t */\n\tget type(): OmniOscillatorType {\n\t\tlet prefix = \"\";\n\t\tif ([\"am\", \"fm\", \"fat\"].some((p) => this._sourceType === p)) {\n\t\t\tprefix = this._sourceType;\n\t\t}\n\t\treturn (prefix + this._oscillator.type) as OmniOscillatorType;\n\t}\n\tset type(type) {\n\t\tif (type.substr(0, 2) === \"fm\") {\n\t\t\tthis._createNewOscillator(\"fm\");\n\t\t\tthis._oscillator = this._oscillator as FMOscillator;\n\t\t\tthis._oscillator.type = type.substr(2) as ToneOscillatorType;\n\t\t} else if (type.substr(0, 2) === \"am\") {\n\t\t\tthis._createNewOscillator(\"am\");\n\t\t\tthis._oscillator = this._oscillator as AMOscillator;\n\t\t\tthis._oscillator.type = type.substr(2) as ToneOscillatorType;\n\t\t} else if (type.substr(0, 3) === \"fat\") {\n\t\t\tthis._createNewOscillator(\"fat\");\n\t\t\tthis._oscillator = this._oscillator as FatOscillator;\n\t\t\tthis._oscillator.type = type.substr(3) as ToneOscillatorType;\n\t\t} else if (type === \"pwm\") {\n\t\t\tthis._createNewOscillator(\"pwm\");\n\t\t\tthis._oscillator = this._oscillator as PWMOscillator;\n\t\t} else if (type === \"pulse\") {\n\t\t\tthis._createNewOscillator(\"pulse\");\n\t\t} else {\n\t\t\tthis._createNewOscillator(\"oscillator\");\n\t\t\tthis._oscillator = this._oscillator as Oscillator;\n\t\t\tthis._oscillator.type = type as ToneOscillatorType;\n\t\t}\n\t}\n\n\t/**\n\t * The value is an empty array when the type is not \"custom\".\n\t * This is not available on \"pwm\" and \"pulse\" oscillator types.\n\t * @see {@link Oscillator.partials}\n\t */\n\tget partials(): number[] {\n\t\treturn this._oscillator.partials;\n\t}\n\tset partials(partials) {\n\t\tif (\n\t\t\t!this._getOscType(this._oscillator, \"pulse\") &&\n\t\t\t!this._getOscType(this._oscillator, \"pwm\")\n\t\t) {\n\t\t\tthis._oscillator.partials = partials;\n\t\t}\n\t}\n\n\tget partialCount(): number {\n\t\treturn this._oscillator.partialCount;\n\t}\n\tset partialCount(partialCount) {\n\t\tif (\n\t\t\t!this._getOscType(this._oscillator, \"pulse\") &&\n\t\t\t!this._getOscType(this._oscillator, \"pwm\")\n\t\t) {\n\t\t\tthis._oscillator.partialCount = partialCount;\n\t\t}\n\t}\n\n\tset(props: Partial<OmniOscillatorOptions>): this {\n\t\t// make sure the type is set first\n\t\tif (Reflect.has(props, \"type\") && props.type) {\n\t\t\tthis.type = props.type;\n\t\t}\n\t\t// then set the rest\n\t\tsuper.set(props);\n\t\treturn this;\n\t}\n\n\t/**\n\t * connect the oscillator to the frequency and detune signals\n\t */\n\tprivate _createNewOscillator(oscType: OmniOscSourceType): void {\n\t\tif (oscType !== this._sourceType) {\n\t\t\tthis._sourceType = oscType;\n\t\t\tconst OscConstructor = OmniOscillatorSourceMap[oscType];\n\t\t\t// short delay to avoid clicks on the change\n\t\t\tconst now = this.now();\n\t\t\tif (this._oscillator) {\n\t\t\t\tconst oldOsc = this._oscillator;\n\t\t\t\toldOsc.stop(now);\n\t\t\t\t// dispose the old one\n\t\t\t\tthis.context.setTimeout(() => oldOsc.dispose(), this.blockTime);\n\t\t\t}\n\t\t\tthis._oscillator = new OscConstructor({\n\t\t\t\tcontext: this.context,\n\t\t\t});\n\t\t\tthis.frequency.connect(this._oscillator.frequency);\n\t\t\tthis.detune.connect(this._oscillator.detune);\n\t\t\tthis._oscillator.connect(this.output);\n\t\t\tthis._oscillator.onstop = () => this.onstop(this);\n\t\t\tif (this.state === \"started\") {\n\t\t\t\tthis._oscillator.start(now);\n\t\t\t}\n\t\t}\n\t}\n\n\tget phase(): Degrees {\n\t\treturn this._oscillator.phase;\n\t}\n\tset phase(phase) {\n\t\tthis._oscillator.phase = phase;\n\t}\n\n\t/**\n\t * The source type of the oscillator.\n\t * @example\n\t * const omniOsc = new Tone.OmniOscillator(440, \"fmsquare\");\n\t * console.log(omniOsc.sourceType); // 'fm'\n\t */\n\tget sourceType(): OmniOscSourceType {\n\t\treturn this._sourceType;\n\t}\n\tset sourceType(sType) {\n\t\tlet baseType = \"sine\";\n\t\tif (\n\t\t\tthis._oscillator.type !== \"pwm\" &&\n\t\t\tthis._oscillator.type !== \"pulse\"\n\t\t) {\n\t\t\tbaseType = this._oscillator.type;\n\t\t}\n\n\t\t// set the type\n\t\tif (sType === \"fm\") {\n\t\t\tthis.type = (\"fm\" + baseType) as OmniOscillatorType;\n\t\t} else if (sType === \"am\") {\n\t\t\tthis.type = (\"am\" + baseType) as OmniOscillatorType;\n\t\t} else if (sType === \"fat\") {\n\t\t\tthis.type = (\"fat\" + baseType) as OmniOscillatorType;\n\t\t} else if (sType === \"oscillator\") {\n\t\t\tthis.type = baseType as OmniOscillatorType;\n\t\t} else if (sType === \"pulse\") {\n\t\t\tthis.type = \"pulse\";\n\t\t} else if (sType === \"pwm\") {\n\t\t\tthis.type = \"pwm\";\n\t\t}\n\t}\n\n\tprivate _getOscType<SourceType extends OmniOscSourceType>(\n\t\tosc: AnyOscillator,\n\t\tsourceType: SourceType\n\t): osc is OmniOscillatorSource[SourceType] {\n\t\treturn osc instanceof OmniOscillatorSourceMap[sourceType];\n\t}\n\n\t/**\n\t * The base type of the oscillator.\n\t * @see {@link Oscillator.baseType}\n\t * @example\n\t * const omniOsc = new Tone.OmniOscillator(440, \"fmsquare4\");\n\t * console.log(omniOsc.sourceType, omniOsc.baseType, omniOsc.partialCount);\n\t */\n\tget baseType(): OscillatorType | \"pwm\" | \"pulse\" {\n\t\treturn this._oscillator.baseType;\n\t}\n\tset baseType(baseType) {\n\t\tif (\n\t\t\t!this._getOscType(this._oscillator, \"pulse\") &&\n\t\t\t!this._getOscType(this._oscillator, \"pwm\") &&\n\t\t\tbaseType !== \"pulse\" &&\n\t\t\tbaseType !== \"pwm\"\n\t\t) {\n\t\t\tthis._oscillator.baseType = baseType;\n\t\t}\n\t}\n\n\t/**\n\t * The width of the oscillator when sourceType === \"pulse\".\n\t * @see {@link PWMOscillator}\n\t */\n\tget width(): IsPulseOscillator<OscType, Signal<\"audioRange\">> {\n\t\tif (this._getOscType(this._oscillator, \"pulse\")) {\n\t\t\treturn this._oscillator.width as IsPulseOscillator<\n\t\t\t\tOscType,\n\t\t\t\tSignal<\"audioRange\">\n\t\t\t>;\n\t\t} else {\n\t\t\treturn undefined as IsPulseOscillator<\n\t\t\t\tOscType,\n\t\t\t\tSignal<\"audioRange\">\n\t\t\t>;\n\t\t}\n\t}\n\n\t/**\n\t * The number of detuned oscillators when sourceType === \"fat\".\n\t * @see {@link FatOscillator.count}\n\t */\n\tget count(): IsFatOscillator<OscType, number> {\n\t\tif (this._getOscType(this._oscillator, \"fat\")) {\n\t\t\treturn this._oscillator.count as IsFatOscillator<OscType, number>;\n\t\t} else {\n\t\t\treturn undefined as IsFatOscillator<OscType, number>;\n\t\t}\n\t}\n\tset count(count) {\n\t\tif (this._getOscType(this._oscillator, \"fat\") && isNumber(count)) {\n\t\t\tthis._oscillator.count = count;\n\t\t}\n\t}\n\n\t/**\n\t * The detune spread between the oscillators when sourceType === \"fat\".\n\t * @see {@link FatOscillator.count}\n\t */\n\tget spread(): IsFatOscillator<OscType, Cents> {\n\t\tif (this._getOscType(this._oscillator, \"fat\")) {\n\t\t\treturn this._oscillator.spread as IsFatOscillator<OscType, Cents>;\n\t\t} else {\n\t\t\treturn undefined as IsFatOscillator<OscType, Cents>;\n\t\t}\n\t}\n\tset spread(spread) {\n\t\tif (this._getOscType(this._oscillator, \"fat\") && isNumber(spread)) {\n\t\t\tthis._oscillator.spread = spread;\n\t\t}\n\t}\n\n\t/**\n\t * The type of the modulator oscillator. Only if the oscillator is set to \"am\" or \"fm\" types.\n\t * @see {@link AMOscillator} or {@link FMOscillator}\n\t */\n\tget modulationType(): IsAmOrFmOscillator<OscType, ToneOscillatorType> {\n\t\tif (\n\t\t\tthis._getOscType(this._oscillator, \"fm\") ||\n\t\t\tthis._getOscType(this._oscillator, \"am\")\n\t\t) {\n\t\t\treturn this._oscillator.modulationType as IsAmOrFmOscillator<\n\t\t\t\tOscType,\n\t\t\t\tToneOscillatorType\n\t\t\t>;\n\t\t} else {\n\t\t\treturn undefined as IsAmOrFmOscillator<OscType, ToneOscillatorType>;\n\t\t}\n\t}\n\tset modulationType(mType) {\n\t\tif (\n\t\t\t(this._getOscType(this._oscillator, \"fm\") ||\n\t\t\t\tthis._getOscType(this._oscillator, \"am\")) &&\n\t\t\tisString(mType)\n\t\t) {\n\t\t\tthis._oscillator.modulationType = mType;\n\t\t}\n\t}\n\n\t/**\n\t * The modulation index when the sourceType === \"fm\"\n\t * @see {@link FMOscillator}.\n\t */\n\tget modulationIndex(): IsFMOscillator<OscType, Signal<\"positive\">> {\n\t\tif (this._getOscType(this._oscillator, \"fm\")) {\n\t\t\treturn this._oscillator.modulationIndex as IsFMOscillator<\n\t\t\t\tOscType,\n\t\t\t\tSignal<\"positive\">\n\t\t\t>;\n\t\t} else {\n\t\t\treturn undefined as IsFMOscillator<OscType, Signal<\"positive\">>;\n\t\t}\n\t}\n\n\t/**\n\t * Harmonicity is the frequency ratio between the carrier and the modulator oscillators.\n\t * @see {@link AMOscillator} or {@link FMOscillator}\n\t */\n\tget harmonicity(): IsAmOrFmOscillator<OscType, Signal<\"positive\">> {\n\t\tif (\n\t\t\tthis._getOscType(this._oscillator, \"fm\") ||\n\t\t\tthis._getOscType(this._oscillator, \"am\")\n\t\t) {\n\t\t\treturn this._oscillator.harmonicity as IsAmOrFmOscillator<\n\t\t\t\tOscType,\n\t\t\t\tSignal<\"positive\">\n\t\t\t>;\n\t\t} else {\n\t\t\treturn undefined as IsAmOrFmOscillator<OscType, Signal<\"positive\">>;\n\t\t}\n\t}\n\n\t/**\n\t * The modulationFrequency Signal of the oscillator when sourceType === \"pwm\"\n\t * see {@link PWMOscillator}\n\t * @min 0.1\n\t * @max 5\n\t */\n\tget modulationFrequency(): IsPWMOscillator<OscType, Signal<\"frequency\">> {\n\t\tif (this._getOscType(this._oscillator, \"pwm\")) {\n\t\t\treturn this._oscillator.modulationFrequency as IsPWMOscillator<\n\t\t\t\tOscType,\n\t\t\t\tSignal<\"frequency\">\n\t\t\t>;\n\t\t} else {\n\t\t\treturn undefined as IsPWMOscillator<OscType, Signal<\"frequency\">>;\n\t\t}\n\t}\n\n\tasync asArray(length = 1024): Promise<Float32Array> {\n\t\treturn generateWaveform(this, length);\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis.detune.dispose();\n\t\tthis.frequency.dispose();\n\t\tthis._oscillator.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/source/oscillator/Oscillator.test.ts",
    "content": "import { expect, use } from \"chai\";\nimport sinon from \"sinon\";\nimport sinonChai from \"sinon-chai\";\nuse(sinonChai);\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../../test/helper/CompareToFile.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { OscillatorTests } from \"../../../test/helper/OscillatorTests.js\";\nimport { OutputAudio } from \"../../../test/helper/OutputAudio.js\";\nimport { SourceTests } from \"../../../test/helper/SourceTests.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { Oscillator } from \"./Oscillator.js\";\nimport { ToneOscillatorType } from \"./OscillatorInterface.js\";\n\ndescribe(\"Oscillator\", () => {\n\t// run the common tests\n\tBasicTests(Oscillator);\n\tSourceTests(Oscillator);\n\tOscillatorTests(Oscillator);\n\n\tafterEach(() => {\n\t\tsinon.restore();\n\t});\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst osc = new Oscillator().toDestination();\n\t\t\t\tosc.type = \"square\";\n\t\t\t\tosc.start(0).stop(0.2);\n\t\t\t},\n\t\t\t\"oscillator.wav\",\n\t\t\t0.1\n\t\t);\n\t});\n\n\tit(\"cleans up connections after stopping\", async () => {\n\t\tconst SignalPrototype = Signal.prototype;\n\t\tconst connectSpy = sinon.spy(SignalPrototype, \"connect\");\n\t\tconst disconnectSpy = sinon.spy(SignalPrototype, \"disconnect\");\n\t\tawait new Promise<void>((done) => {\n\t\t\tconst osc = new Oscillator({\n\t\t\t\tonstop: () => done(),\n\t\t\t}).toDestination();\n\t\t\tosc.start().stop(\"+0.05\");\n\n\t\t\t// called with two connections: frequency and detune\n\t\t\texpect(connectSpy).to.have.been.callCount(2);\n\t\t});\n\n\t\t// called with two disconnections: frequency and detune\n\t\texpect(disconnectSpy).to.have.been.callCount(2);\n\t});\n\n\tcontext(\"Get/Set\", () => {\n\t\tit(\"can be set with an options object\", () => {\n\t\t\tconst osc = new Oscillator();\n\t\t\tosc.set({\n\t\t\t\tdetune: -21,\n\t\t\t\tfrequency: 231,\n\t\t\t\ttype: \"square\",\n\t\t\t});\n\t\t\texpect(osc.frequency.value).to.equal(231);\n\t\t\texpect(osc.detune.value).to.equal(-21);\n\t\t\texpect(osc.type).to.equal(\"square\");\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"can be get the values as an object\", () => {\n\t\t\tconst osc = new Oscillator(450, \"square\");\n\t\t\texpect(osc.get().frequency).to.equal(450);\n\t\t\texpect(osc.get().type).to.equal(\"square\");\n\t\t\tosc.dispose();\n\t\t});\n\t});\n\n\tcontext(\"Phase Rotation\", () => {\n\t\tit(\"can change the phase to 90\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst instance = new Oscillator({\n\t\t\t\t\tfrequency: 1,\n\t\t\t\t\tphase: 90,\n\t\t\t\t});\n\t\t\t\tinstance.toDestination();\n\t\t\t\tinstance.start(0);\n\t\t\t}, 1);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\tif (time < 0.25) {\n\t\t\t\t\texpect(sample).to.be.within(-1, 0);\n\t\t\t\t} else if (time > 0.25 && time < 0.5) {\n\t\t\t\t\texpect(sample).to.be.within(0, 1);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"can change the phase to -90\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst instance = new Oscillator({\n\t\t\t\t\tfrequency: 1,\n\t\t\t\t\tphase: 270,\n\t\t\t\t});\n\t\t\t\tinstance.toDestination();\n\t\t\t\tinstance.start(0);\n\t\t\t}, 1);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\tif (time < 0.25) {\n\t\t\t\t\texpect(sample).to.be.within(0, 1);\n\t\t\t\t} else if (time > 0.25 && time < 0.5) {\n\t\t\t\t\texpect(sample).to.be.within(-1, 0);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"can go past the cache max size of 100\", () => {\n\t\t\tconst osc = new Oscillator();\n\t\t\tfor (let i = 0; i < 110; i++) {\n\t\t\t\tosc.phase = i;\n\t\t\t}\n\t\t\tosc.dispose();\n\t\t});\n\t});\n\n\tcontext(\"Type\", () => {\n\t\tit(\"can get and set the type\", () => {\n\t\t\tconst osc = new Oscillator({\n\t\t\t\ttype: \"sawtooth\",\n\t\t\t});\n\t\t\texpect(osc.type).to.equal(\"sawtooth\");\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"can set the type after starting\", () => {\n\t\t\tconst osc = new Oscillator(110, \"sawtooth10\").start();\n\t\t\texpect(osc.type).to.equal(\"sawtooth10\");\n\t\t\tosc.type = \"sawtooth20\";\n\t\t\texpect(osc.type).to.equal(\"sawtooth20\");\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"handles 4 basic types\", () => {\n\t\t\tconst osc = new Oscillator();\n\t\t\tconst types: ToneOscillatorType[] = [\n\t\t\t\t\"triangle\",\n\t\t\t\t\"sawtooth\",\n\t\t\t\t\"sine\",\n\t\t\t\t\"square\",\n\t\t\t];\n\t\t\tfor (const type of types) {\n\t\t\t\tosc.type = type;\n\t\t\t\texpect(osc.type).to.equal(type);\n\t\t\t}\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"throws an error if invalid type is set\", () => {\n\t\t\tconst osc = new Oscillator();\n\t\t\texpect(() => {\n\t\t\t\t// @ts-ignore\n\t\t\t\tosc.type = \"invalid\";\n\t\t\t}).to.throw(Error);\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"can set extended types\", () => {\n\t\t\tconst osc = new Oscillator();\n\t\t\tosc.type = \"sine5\";\n\t\t\texpect(osc.type).to.equal(\"sine5\");\n\t\t\tosc.type = \"triangle2\";\n\t\t\texpect(osc.type).to.equal(\"triangle2\");\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"can get/set the baseType\", () => {\n\t\t\tconst osc = new Oscillator();\n\t\t\tosc.type = \"sine5\";\n\t\t\texpect(osc.baseType).to.equal(\"sine\");\n\t\t\tosc.baseType = \"triangle\";\n\t\t\texpect(osc.type).to.equal(\"triangle5\");\n\t\t\texpect(osc.partialCount).to.equal(5);\n\t\t\tosc.partialCount = 2;\n\t\t\texpect(osc.type).to.equal(\"triangle2\");\n\t\t\tosc.baseType = \"custom\";\n\t\t\texpect(osc.type).to.equal(\"custom\");\n\t\t\tosc.partials = [1, 2, 3];\n\t\t\texpect(osc.baseType).to.equal(\"custom\");\n\t\t\tosc.baseType = \"square\";\n\t\t\texpect(osc.type).to.equal(\"square\");\n\t\t\tosc.dispose();\n\t\t});\n\t});\n\n\tcontext(\"Partials\", () => {\n\t\tit(\"can pass partials in the constructor\", () => {\n\t\t\tconst osc = new Oscillator({\n\t\t\t\tpartials: [1, 0.3, 0.3],\n\t\t\t\ttype: \"custom\",\n\t\t\t});\n\t\t\texpect(osc.type).to.equal(\"custom\");\n\t\t\texpect(osc.partials[1]).to.equal(0.3);\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"can set partials\", () => {\n\t\t\tconst osc = new Oscillator();\n\t\t\tosc.partials = [1, 0.2, 0.2, 0.2];\n\t\t\texpect(osc.type).to.equal(\"custom\");\n\t\t\texpect(osc.partials[1]).to.equal(0.2);\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"makes a sound with custom partials\", () => {\n\t\t\treturn OutputAudio(() => {\n\t\t\t\tconst osc = new Oscillator().toDestination().start();\n\t\t\t\tosc.partials = [1, 0.2, 0.2, 0.2];\n\t\t\t});\n\t\t});\n\n\t\tit(\"outputs the partials of the given waveform\", () => {\n\t\t\tconst osc = new Oscillator();\n\t\t\tosc.type = \"sine2\";\n\t\t\texpect(osc.type).to.equal(\"sine2\");\n\t\t\texpect(osc.partials.length).to.equal(2);\n\t\t\texpect(osc.partials).to.deep.equal([1, 1]);\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"partialCount is 0 when set to max\", () => {\n\t\t\tconst osc = new Oscillator();\n\t\t\texpect(osc.partialCount).to.equal(0);\n\t\t\tosc.type = \"square32\";\n\t\t\texpect(osc.partialCount).to.equal(32);\n\t\t\tosc.type = \"square\";\n\t\t\texpect(osc.partialCount).to.equal(0);\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"can pass in number of partials into constructor\", () => {\n\t\t\tconst osc = new Oscillator({\n\t\t\t\tpartialCount: 3,\n\t\t\t\ttype: \"sine\",\n\t\t\t});\n\t\t\texpect(osc.type).to.equal(\"sine3\");\n\t\t\texpect(osc.partialCount).to.equal(3);\n\t\t\tosc.partialCount = 4;\n\t\t\texpect(osc.partialCount).to.equal(4);\n\t\t\texpect(osc.type).to.equal(\"sine4\");\n\t\t\tosc.dispose();\n\t\t});\n\t});\n\n\tcontext(\"Synchronization\", () => {\n\t\tit(\"can unsync the frequency from the Transport\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\ttransport.bpm.value = 120;\n\t\t\t\tconst osc = new Oscillator(2);\n\t\t\t\tosc.frequency.toDestination();\n\t\t\t\tosc.syncFrequency();\n\t\t\t\ttransport.bpm.value = 240;\n\t\t\t});\n\t\t\texpect(buffer.value()).to.be.closeTo(4, 0.001);\n\t\t});\n\n\t\tit(\"can sync the frequency to the Transport\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\ttransport.bpm.value = 120;\n\t\t\t\tconst osc = new Oscillator(2);\n\t\t\t\tosc.frequency.toDestination();\n\t\t\t\tosc.syncFrequency();\n\t\t\t\ttransport.bpm.value = 240;\n\t\t\t\tosc.unsyncFrequency();\n\t\t\t});\n\t\t\texpect(buffer.value()).to.be.closeTo(2, 0.001);\n\t\t});\n\t});\n\n\tcontext(\"initialValue\", () => {\n\t\tit(\"can get the initial value of a basic oscillator type\", () => {\n\t\t\tconst osc = new Oscillator(10, \"sine\");\n\t\t\texpect(osc.getInitialValue()).to.be.closeTo(0, 0.01);\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"can get the initial value when the phase is rotated\", () => {\n\t\t\tconst osc = new Oscillator({\n\t\t\t\tphase: 90,\n\t\t\t\ttype: \"sine\",\n\t\t\t});\n\t\t\texpect(osc.getInitialValue()).to.be.closeTo(-1, 0.01);\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"can get the initial value of more complex types\", () => {\n\t\t\tconst osc = new Oscillator({\n\t\t\t\tpartials: [0, 2, 4, 1, 3],\n\t\t\t\tphase: 145,\n\t\t\t\ttype: \"custom\",\n\t\t\t});\n\t\t\texpect(osc.getInitialValue()).to.be.closeTo(-0.2, 0.05);\n\t\t\tosc.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/source/oscillator/Oscillator.ts",
    "content": "import {\n\tAudioRange,\n\tDegrees,\n\tFrequency,\n\tRadians,\n\tTime,\n} from \"../../core/type/Units.js\";\nimport { assertRange } from \"../../core/util/Debug.js\";\nimport { deepEquals, optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly } from \"../../core/util/Interface.js\";\nimport { clamp } from \"../../core/util/Math.js\";\nimport { isDefined } from \"../../core/util/TypeCheck.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { Source } from \"../Source.js\";\nimport {\n\tgenerateWaveform,\n\tToneOscillatorConstructorOptions,\n\tToneOscillatorInterface,\n\tToneOscillatorOptions,\n\tToneOscillatorType,\n} from \"./OscillatorInterface.js\";\nimport { ToneOscillatorNode } from \"./ToneOscillatorNode.js\";\nexport {\n\tToneOscillatorOptions,\n\tToneOscillatorType,\n} from \"./OscillatorInterface.js\";\n/**\n * Oscillator supports a number of features including\n * phase rotation, multiple oscillator types (see Oscillator.type),\n * and Transport syncing (see Oscillator.syncFrequency).\n *\n * @example\n * // make and start a 440hz sine tone\n * const osc = new Tone.Oscillator(440, \"sine\").toDestination().start();\n * @category Source\n */\nexport class Oscillator\n\textends Source<ToneOscillatorOptions>\n\timplements ToneOscillatorInterface\n{\n\treadonly name: string = \"Oscillator\";\n\n\t/**\n\t * the main oscillator\n\t */\n\tprivate _oscillator: ToneOscillatorNode | null = null;\n\n\t/**\n\t * The frequency control.\n\t */\n\tfrequency: Signal<\"frequency\">;\n\n\t/**\n\t * The detune control signal.\n\t */\n\tdetune: Signal<\"cents\">;\n\n\t/**\n\t * the periodic wave\n\t */\n\tprivate _wave?: PeriodicWave;\n\n\t/**\n\t * The partials of the oscillator\n\t */\n\tprivate _partials: number[];\n\n\t/**\n\t * The number of partials to limit or extend the periodic wave by\n\t */\n\tprivate _partialCount: number;\n\n\t/**\n\t * the phase of the oscillator between 0 - 360\n\t */\n\tprivate _phase!: Radians;\n\n\t/**\n\t * the type of the oscillator\n\t */\n\tprivate _type: ToneOscillatorType;\n\n\t/**\n\t * @param frequency Starting frequency\n\t * @param type The oscillator type. Read more about type below.\n\t */\n\tconstructor(frequency?: Frequency, type?: ToneOscillatorType);\n\tconstructor(options?: Partial<ToneOscillatorConstructorOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tOscillator.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"frequency\", \"type\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.frequency = new Signal<\"frequency\">({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"frequency\",\n\t\t\tvalue: options.frequency,\n\t\t});\n\t\treadOnly(this, \"frequency\");\n\n\t\tthis.detune = new Signal<\"cents\">({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"cents\",\n\t\t\tvalue: options.detune,\n\t\t});\n\t\treadOnly(this, \"detune\");\n\n\t\tthis._partials = options.partials;\n\t\tthis._partialCount = options.partialCount;\n\t\tthis._type = options.type;\n\n\t\tif (options.partialCount && options.type !== \"custom\") {\n\t\t\tthis._type = (this.baseType +\n\t\t\t\toptions.partialCount.toString()) as ToneOscillatorType;\n\t\t}\n\t\tthis.phase = options.phase;\n\t}\n\n\tstatic getDefaults(): ToneOscillatorOptions {\n\t\treturn Object.assign(Source.getDefaults(), {\n\t\t\tdetune: 0,\n\t\t\tfrequency: 440,\n\t\t\tpartialCount: 0,\n\t\t\tpartials: [],\n\t\t\tphase: 0,\n\t\t\ttype: \"sine\" as const,\n\t\t});\n\t}\n\n\t/**\n\t * start the oscillator\n\t */\n\tprotected _start(time?: Time): void {\n\t\tconst computedTime = this.toSeconds(time);\n\t\t// new oscillator with previous values\n\t\tconst oscillator = new ToneOscillatorNode({\n\t\t\tcontext: this.context,\n\t\t\tonended: () => {\n\t\t\t\tthis._cleanUpConnections(oscillator);\n\t\t\t\tthis.onstop(this);\n\t\t\t},\n\t\t});\n\t\tthis._oscillator = oscillator;\n\t\tif (this._wave) {\n\t\t\tthis._oscillator.setPeriodicWave(this._wave);\n\t\t} else {\n\t\t\tthis._oscillator.type = this._type as OscillatorType;\n\t\t}\n\t\t// connect the control signal to the oscillator frequency & detune\n\t\tthis._oscillator.connect(this.output);\n\t\tthis.frequency.connect(this._oscillator.frequency);\n\t\tthis.detune.connect(this._oscillator.detune);\n\n\t\t// start the oscillator\n\t\tthis._oscillator.start(computedTime);\n\t}\n\n\t/**\n\t * Cleans up the connections to the oscillator for online contexts once it\n\t * has stopped.\n\t */\n\tprivate _cleanUpConnections(oscillator: ToneOscillatorNode): void {\n\t\tif (this.context.isOffline) {\n\t\t\treturn;\n\t\t}\n\t\t// Clean up connections fixes #1379\n\t\tthis.frequency.disconnect(oscillator.frequency);\n\t\tthis.detune.disconnect(oscillator.detune);\n\t\toscillator.disconnect();\n\t}\n\n\t/**\n\t * stop the oscillator\n\t */\n\tprotected _stop(time?: Time): void {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tif (this._oscillator) {\n\t\t\tthis._oscillator.stop(computedTime);\n\t\t}\n\t}\n\n\t/**\n\t * Restart the oscillator. Does not stop the oscillator, but instead\n\t * just cancels any scheduled 'stop' from being invoked.\n\t */\n\tprotected _restart(time?: Time): this {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tthis.log(\"restart\", computedTime);\n\t\tif (this._oscillator) {\n\t\t\tthis._oscillator.cancelStop();\n\t\t}\n\t\tthis._state.cancel(computedTime);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sync the signal to the Transport's bpm. Any changes to the transports bpm,\n\t * will also affect the oscillators frequency.\n\t * @example\n\t * const osc = new Tone.Oscillator().toDestination().start();\n\t * osc.frequency.value = 440;\n\t * // the ratio between the bpm and the frequency will be maintained\n\t * osc.syncFrequency();\n\t * // double the tempo\n\t * Tone.Transport.bpm.value *= 2;\n\t * // the frequency of the oscillator is doubled to 880\n\t */\n\tsyncFrequency(): this {\n\t\tthis.context.transport.syncSignal(this.frequency);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Unsync the oscillator's frequency from the Transport.\n\t * @see {@link syncFrequency}\n\t */\n\tunsyncFrequency(): this {\n\t\tthis.context.transport.unsyncSignal(this.frequency);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Cache the periodic waves to avoid having to redo computations\n\t */\n\tprivate static _periodicWaveCache: Array<{\n\t\tpartials: number[];\n\t\tphase: number;\n\t\ttype: string;\n\t\tpartialCount: number;\n\t\treal: Float32Array;\n\t\timag: Float32Array;\n\t\twave: PeriodicWave;\n\t}> = [];\n\n\t/**\n\t * Get a cached periodic wave. Avoids having to recompute\n\t * the oscillator values when they have already been computed\n\t * with the same values.\n\t */\n\tprivate _getCachedPeriodicWave():\n\t\t| {\n\t\t\t\treal: Float32Array;\n\t\t\t\timag: Float32Array;\n\t\t\t\tpartials: number[];\n\t\t\t\twave: PeriodicWave;\n\t\t  }\n\t\t| undefined {\n\t\tif (this._type === \"custom\") {\n\t\t\tconst oscProps = Oscillator._periodicWaveCache.find(\n\t\t\t\t(description) => {\n\t\t\t\t\treturn (\n\t\t\t\t\t\tdescription.phase === this._phase &&\n\t\t\t\t\t\tdeepEquals(description.partials, this._partials)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t);\n\t\t\treturn oscProps;\n\t\t} else {\n\t\t\tconst oscProps = Oscillator._periodicWaveCache.find(\n\t\t\t\t(description) => {\n\t\t\t\t\treturn (\n\t\t\t\t\t\tdescription.type === this._type &&\n\t\t\t\t\t\tdescription.phase === this._phase\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t);\n\t\t\tthis._partialCount = oscProps\n\t\t\t\t? oscProps.partialCount\n\t\t\t\t: this._partialCount;\n\t\t\treturn oscProps;\n\t\t}\n\t}\n\n\tget type(): ToneOscillatorType {\n\t\treturn this._type;\n\t}\n\tset type(type) {\n\t\tthis._type = type;\n\t\tconst isBasicType =\n\t\t\t[\"sine\", \"square\", \"sawtooth\", \"triangle\"].indexOf(type) !== -1;\n\t\tif (this._phase === 0 && isBasicType) {\n\t\t\tthis._wave = undefined;\n\t\t\tthis._partialCount = 0;\n\t\t\t// just go with the basic approach\n\t\t\tif (this._oscillator !== null) {\n\t\t\t\t// already tested that it's a basic type\n\t\t\t\tthis._oscillator.type = type as OscillatorType;\n\t\t\t}\n\t\t} else {\n\t\t\t// first check if the value is cached\n\t\t\tconst cache = this._getCachedPeriodicWave();\n\t\t\tif (isDefined(cache)) {\n\t\t\t\tconst { partials, wave } = cache;\n\t\t\t\tthis._wave = wave;\n\t\t\t\tthis._partials = partials;\n\t\t\t\tif (this._oscillator !== null) {\n\t\t\t\t\tthis._oscillator.setPeriodicWave(this._wave);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst [real, imag] = this._getRealImaginary(type, this._phase);\n\t\t\t\tconst periodicWave = this.context.createPeriodicWave(\n\t\t\t\t\treal,\n\t\t\t\t\timag\n\t\t\t\t);\n\t\t\t\tthis._wave = periodicWave;\n\t\t\t\tif (this._oscillator !== null) {\n\t\t\t\t\tthis._oscillator.setPeriodicWave(this._wave);\n\t\t\t\t}\n\t\t\t\t// set the cache\n\t\t\t\tOscillator._periodicWaveCache.push({\n\t\t\t\t\timag,\n\t\t\t\t\tpartialCount: this._partialCount,\n\t\t\t\t\tpartials: this._partials,\n\t\t\t\t\tphase: this._phase,\n\t\t\t\t\treal,\n\t\t\t\t\ttype: this._type,\n\t\t\t\t\twave: this._wave,\n\t\t\t\t});\n\t\t\t\tif (Oscillator._periodicWaveCache.length > 100) {\n\t\t\t\t\tOscillator._periodicWaveCache.shift();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tget baseType(): OscillatorType {\n\t\treturn (this._type as string).replace(\n\t\t\tthis.partialCount.toString(),\n\t\t\t\"\"\n\t\t) as OscillatorType;\n\t}\n\tset baseType(baseType) {\n\t\tif (\n\t\t\tthis.partialCount &&\n\t\t\tthis._type !== \"custom\" &&\n\t\t\tbaseType !== \"custom\"\n\t\t) {\n\t\t\tthis.type = (baseType + this.partialCount) as ToneOscillatorType;\n\t\t} else {\n\t\t\tthis.type = baseType;\n\t\t}\n\t}\n\n\tget partialCount(): number {\n\t\treturn this._partialCount;\n\t}\n\tset partialCount(p) {\n\t\tassertRange(p, 0);\n\t\tlet type = this._type;\n\t\tconst partial = /^(sine|triangle|square|sawtooth)(\\d+)$/.exec(\n\t\t\tthis._type\n\t\t);\n\t\tif (partial) {\n\t\t\ttype = partial[1] as OscillatorType;\n\t\t}\n\t\tif (this._type !== \"custom\") {\n\t\t\tif (p === 0) {\n\t\t\t\tthis.type = type;\n\t\t\t} else {\n\t\t\t\tthis.type = (type + p.toString()) as ToneOscillatorType;\n\t\t\t}\n\t\t} else {\n\t\t\t// extend or shorten the partials array\n\t\t\tconst fullPartials = new Float32Array(p);\n\t\t\t// copy over the partials array\n\t\t\tthis._partials.forEach((v, i) => (fullPartials[i] = v));\n\t\t\tthis._partials = Array.from(fullPartials);\n\t\t\tthis.type = this._type;\n\t\t}\n\t}\n\n\t/**\n\t * Returns the real and imaginary components based\n\t * on the oscillator type.\n\t * @returns [real: Float32Array, imaginary: Float32Array]\n\t */\n\tprivate _getRealImaginary(\n\t\ttype: ToneOscillatorType,\n\t\tphase: Radians\n\t): Float32Array[] {\n\t\tconst fftSize = 4096;\n\t\tlet periodicWaveSize = fftSize / 2;\n\n\t\tconst real = new Float32Array(periodicWaveSize);\n\t\tconst imag = new Float32Array(periodicWaveSize);\n\n\t\tlet partialCount = 1;\n\t\tif (type === \"custom\") {\n\t\t\tpartialCount = this._partials.length + 1;\n\t\t\tthis._partialCount = this._partials.length;\n\t\t\tperiodicWaveSize = partialCount;\n\t\t\t// if the partial count is 0, don't bother doing any computation\n\t\t\tif (this._partials.length === 0) {\n\t\t\t\treturn [real, imag];\n\t\t\t}\n\t\t} else {\n\t\t\tconst partial = /^(sine|triangle|square|sawtooth)(\\d+)$/.exec(type);\n\t\t\tif (partial) {\n\t\t\t\tpartialCount = parseInt(partial[2], 10) + 1;\n\t\t\t\tthis._partialCount = parseInt(partial[2], 10);\n\t\t\t\ttype = partial[1] as ToneOscillatorType;\n\t\t\t\tpartialCount = Math.max(partialCount, 2);\n\t\t\t\tperiodicWaveSize = partialCount;\n\t\t\t} else {\n\t\t\t\tthis._partialCount = 0;\n\t\t\t}\n\t\t\tthis._partials = [];\n\t\t}\n\n\t\tfor (let n = 1; n < periodicWaveSize; ++n) {\n\t\t\tconst piFactor = 2 / (n * Math.PI);\n\t\t\tlet b;\n\t\t\tswitch (type) {\n\t\t\t\tcase \"sine\":\n\t\t\t\t\tb = n <= partialCount ? 1 : 0;\n\t\t\t\t\tthis._partials[n - 1] = b;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"square\":\n\t\t\t\t\tb = n & 1 ? 2 * piFactor : 0;\n\t\t\t\t\tthis._partials[n - 1] = b;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"sawtooth\":\n\t\t\t\t\tb = piFactor * (n & 1 ? 1 : -1);\n\t\t\t\t\tthis._partials[n - 1] = b;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"triangle\":\n\t\t\t\t\tif (n & 1) {\n\t\t\t\t\t\tb =\n\t\t\t\t\t\t\t2 *\n\t\t\t\t\t\t\t(piFactor * piFactor) *\n\t\t\t\t\t\t\t(((n - 1) >> 1) & 1 ? -1 : 1);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tb = 0;\n\t\t\t\t\t}\n\t\t\t\t\tthis._partials[n - 1] = b;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"custom\":\n\t\t\t\t\tb = this._partials[n - 1];\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new TypeError(\"Oscillator: invalid type: \" + type);\n\t\t\t}\n\t\t\tif (b !== 0) {\n\t\t\t\treal[n] = -b * Math.sin(phase * n);\n\t\t\t\timag[n] = b * Math.cos(phase * n);\n\t\t\t} else {\n\t\t\t\treal[n] = 0;\n\t\t\t\timag[n] = 0;\n\t\t\t}\n\t\t}\n\t\treturn [real, imag];\n\t}\n\n\t/**\n\t * Compute the inverse FFT for a given phase.\n\t */\n\tprivate _inverseFFT(\n\t\treal: Float32Array,\n\t\timag: Float32Array,\n\t\tphase: Radians\n\t): number {\n\t\tlet sum = 0;\n\t\tconst len = real.length;\n\t\tfor (let i = 0; i < len; i++) {\n\t\t\tsum +=\n\t\t\t\treal[i] * Math.cos(i * phase) + imag[i] * Math.sin(i * phase);\n\t\t}\n\t\treturn sum;\n\t}\n\n\t/**\n\t * Returns the initial value of the oscillator when stopped.\n\t * E.g. a \"sine\" oscillator with phase = 90 would return an initial value of -1.\n\t */\n\tgetInitialValue(): AudioRange {\n\t\tconst [real, imag] = this._getRealImaginary(this._type, 0);\n\t\tlet maxValue = 0;\n\t\tconst twoPi = Math.PI * 2;\n\t\tconst testPositions = 32;\n\t\t// check for peaks in 16 places\n\t\tfor (let i = 0; i < testPositions; i++) {\n\t\t\tmaxValue = Math.max(\n\t\t\t\tthis._inverseFFT(real, imag, (i / testPositions) * twoPi),\n\t\t\t\tmaxValue\n\t\t\t);\n\t\t}\n\t\treturn clamp(\n\t\t\t-this._inverseFFT(real, imag, this._phase) / maxValue,\n\t\t\t-1,\n\t\t\t1\n\t\t);\n\t}\n\n\tget partials(): number[] {\n\t\treturn this._partials.slice(0, this.partialCount);\n\t}\n\tset partials(partials) {\n\t\tthis._partials = partials;\n\t\tthis._partialCount = this._partials.length;\n\t\tif (partials.length) {\n\t\t\tthis.type = \"custom\";\n\t\t}\n\t}\n\n\tget phase(): Degrees {\n\t\treturn this._phase * (180 / Math.PI);\n\t}\n\tset phase(phase) {\n\t\tthis._phase = (phase * Math.PI) / 180;\n\t\t// reset the type\n\t\tthis.type = this._type;\n\t}\n\n\tasync asArray(length = 1024): Promise<Float32Array> {\n\t\treturn generateWaveform(this, length);\n\t}\n\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tif (this._oscillator !== null) {\n\t\t\tthis._oscillator.dispose();\n\t\t}\n\t\tthis._wave = undefined;\n\t\tthis.frequency.dispose();\n\t\tthis.detune.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/source/oscillator/OscillatorInterface.ts",
    "content": "import { OfflineContext } from \"../../core/context/OfflineContext.js\";\nimport {\n\tAudioRange,\n\tCents,\n\tDegrees,\n\tFrequency,\n\tPositive,\n} from \"../../core/type/Units.js\";\nimport { Omit } from \"../../core/util/Interface.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { SourceOptions } from \"../Source.js\";\n\n/**\n * The common interface of all Oscillators\n */\nexport interface ToneOscillatorInterface {\n\t/**\n\t * The oscillator type without the partialsCount appended to the end\n\t * @example\n\t * const osc = new Tone.Oscillator();\n\t * osc.type = \"sine2\";\n\t * console.log(osc.baseType); // \"sine\"\n\t */\n\tbaseType: OscillatorType | \"pulse\" | \"pwm\";\n\n\t/**\n\t * The oscillator's type. Also capable of setting the first x number of partials of the oscillator.\n\t * For example: \"sine4\" would set be the first 4 partials of the sine wave and \"triangle8\" would\n\t * set the first 8 partials of the triangle wave.\n\t * @example\n\t * return Tone.Offline(() => {\n\t * \tconst osc = new Tone.Oscillator().toDestination().start();\n\t * \tosc.type = \"sine2\";\n\t * }, 0.1, 1);\n\t */\n\ttype: ExtendedToneOscillatorType;\n\n\t/**\n\t * The frequency value of the oscillator\n\t * @example\n\t * const osc = new Tone.FMOscillator(\"Bb4\").toDestination().start();\n\t * osc.frequency.rampTo(\"D2\", 3);\n\t */\n\treadonly frequency: Signal<\"frequency\">;\n\n\t/**\n\t * The detune value in cents (100th of a semitone).\n\t * @example\n\t * const osc = new Tone.PulseOscillator(\"F3\").toDestination().start();\n\t * // pitch it 1 octave = 12 semitones = 1200 cents\n\t * osc.detune.setValueAtTime(-1200, Tone.now());\n\t * osc.detune.setValueAtTime(1200, Tone.now() + 0.5);\n\t * osc.detune.linearRampToValueAtTime(0, Tone.now() + 1);\n\t * osc.stop(Tone.now() + 1.5);\n\t */\n\treadonly detune: Signal<\"cents\">;\n\n\t/**\n\t * The phase is the starting position within the oscillator's cycle. For example\n\t * a phase of 180 would start halfway through the oscillator's cycle.\n\t * @example\n\t * return Tone.Offline(() => {\n\t * \tconst osc = new Tone.Oscillator({\n\t * \t\tfrequency: 20,\n\t * \t\tphase: 90\n\t * \t}).toDestination().start();\n\t * }, 0.1, 1);\n\t */\n\tphase: Degrees;\n\n\t/**\n\t * The partials describes the relative amplitude of each of the harmonics of the oscillator.\n\t * The first value in the array is the first harmonic (i.e. the fundamental frequency), the\n\t * second harmonic is an octave up, the third harmonic is an octave and a fifth, etc. The resulting\n\t * oscillator output is composed of a sine tone at the relative amplitude at each of the harmonic intervals.\n\t *\n\t * Setting this value will automatically set the type to \"custom\".\n\t * The value is an empty array when the type is not \"custom\".\n\t * @example\n\t * const osc = new Tone.Oscillator(\"F3\").toDestination().start();\n\t * setInterval(() => {\n\t * \t// generate 8 random partials\n\t * \tosc.partials = new Array(8).fill(0).map(() => Math.random());\n\t * }, 1000);\n\t */\n\tpartials: number[];\n\n\t/**\n\t * 'partialCount' offers an alternative way to set the number of used partials.\n\t * When partialCount is 0, the maximum number of partials are used when representing\n\t * the waveform using the periodicWave. When 'partials' is set, this value is\n\t * not settable, but equals the length of the partials array. A square wave wave\n\t * is composed of only odd harmonics up through the harmonic series. Partial count\n\t * can limit the number of harmonics which are used to generate the waveform.\n\t * @example\n\t * const osc = new Tone.Oscillator(\"C3\", \"square\").toDestination().start();\n\t * osc.partialCount = 1;\n\t * setInterval(() => {\n\t * \tosc.partialCount++;\n\t * \tconsole.log(osc.partialCount);\n\t * }, 500);\n\t */\n\tpartialCount?: number;\n\n\t/**\n\t * Returns an array of values which represents the waveform.\n\t * @param length The length of the waveform to return\n\t */\n\tasArray(length: number): Promise<Float32Array>;\n}\n\n/**\n * Render a segment of the oscillator to an offline context and return the results as an array\n */\nexport async function generateWaveform(\n\tinstance: any,\n\tlength: number\n): Promise<Float32Array> {\n\tconst duration = length / instance.context.sampleRate;\n\tconst context = new OfflineContext(\n\t\t1,\n\t\tduration,\n\t\tinstance.context.sampleRate\n\t);\n\tconst clone = new instance.constructor(\n\t\tObject.assign(instance.get(), {\n\t\t\t// should do 2 iterations\n\t\t\tfrequency: 2 / duration,\n\t\t\t// zero out the detune\n\t\t\tdetune: 0,\n\t\t\tcontext,\n\t\t})\n\t).toDestination();\n\tclone.start(0);\n\tconst buffer = await context.render();\n\treturn buffer.getChannelData(0);\n}\n\n/**\n * The supported number of partials\n */\ntype PartialsRange =\n\t| 1\n\t| 2\n\t| 3\n\t| 4\n\t| 5\n\t| 6\n\t| 7\n\t| 8\n\t| 9\n\t| 10\n\t| 11\n\t| 12\n\t| 13\n\t| 14\n\t| 15\n\t| 16\n\t| 17\n\t| 18\n\t| 19\n\t| 20\n\t| 21\n\t| 22\n\t| 23\n\t| 24\n\t| 25\n\t| 26\n\t| 27\n\t| 28\n\t| 29\n\t| 30\n\t| 31\n\t| 32;\n\n/**\n * Oscillators with partials\n */\ntype SineWithPartials = `sine${PartialsRange}`;\n\ntype SquareWithPartials = `square${PartialsRange}`;\n\ntype SawtoothWithPartials = `sawtooth${PartialsRange}`;\n\ntype TriangleWithPartials = `triangle${PartialsRange}`;\n\ntype TypeWithPartials =\n\t| SineWithPartials\n\t| SquareWithPartials\n\t| TriangleWithPartials\n\t| SawtoothWithPartials;\n\ninterface BaseOscillatorOptions extends SourceOptions {\n\tfrequency: Frequency;\n\tdetune: Cents;\n\tphase: Degrees;\n}\n\nexport type NonCustomOscillatorType = Exclude<OscillatorType, \"custom\">;\n\ntype AllNonCustomOscillatorType = NonCustomOscillatorType | TypeWithPartials;\n\nexport type ToneOscillatorType = AllNonCustomOscillatorType | \"custom\";\n\nexport type ExtendedToneOscillatorType = ToneOscillatorType | \"pwm\" | \"pulse\";\n\n/**\n * Oscillator Interfaces\n */\ninterface ToneCustomOscillatorOptions extends BaseOscillatorOptions {\n\ttype: \"custom\";\n\tpartials: number[];\n}\n\ninterface ToneTypeOscillatorOptions extends BaseOscillatorOptions {\n\ttype: NonCustomOscillatorType;\n\tpartialCount?: number;\n}\n\ninterface TonePartialOscillatorOptions extends BaseOscillatorOptions {\n\ttype: TypeWithPartials;\n}\n\nexport type ToneOscillatorConstructorOptions =\n\t| ToneCustomOscillatorOptions\n\t| ToneTypeOscillatorOptions\n\t| TonePartialOscillatorOptions;\n\nexport interface ToneOscillatorOptions extends BaseOscillatorOptions {\n\ttype: ToneOscillatorType;\n\tpartialCount: number;\n\tpartials: number[];\n}\n\n/**\n * FMOscillator Interface\n */\ninterface FMBaseOscillatorOptions extends BaseOscillatorOptions {\n\tharmonicity: Positive;\n\tmodulationIndex: Positive;\n\tmodulationType: AllNonCustomOscillatorType;\n}\n\ninterface FMCustomOscillatorOptions extends FMBaseOscillatorOptions {\n\ttype: \"custom\";\n\tpartials: number[];\n}\n\ninterface FMTypeOscillatorOptions extends FMBaseOscillatorOptions {\n\ttype: NonCustomOscillatorType;\n\tpartialsCount?: number;\n}\n\ninterface FMPartialsOscillatorOptions extends FMBaseOscillatorOptions {\n\ttype: TypeWithPartials;\n}\n\nexport type FMConstructorOptions =\n\t| FMTypeOscillatorOptions\n\t| FMCustomOscillatorOptions\n\t| FMPartialsOscillatorOptions;\n\nexport interface FMOscillatorOptions extends ToneOscillatorOptions {\n\tharmonicity: Positive;\n\tmodulationIndex: Positive;\n\tmodulationType: AllNonCustomOscillatorType;\n}\n\n/**\n * AMOscillator Interface\n */\ninterface AMBaseOscillatorOptions extends BaseOscillatorOptions {\n\tharmonicity: Positive;\n\tmodulationType: AllNonCustomOscillatorType;\n}\n\ninterface AMCustomOscillatorOptions extends AMBaseOscillatorOptions {\n\ttype: \"custom\";\n\tpartials: number[];\n}\n\ninterface AMTypeOscillatorOptions extends AMBaseOscillatorOptions {\n\ttype: NonCustomOscillatorType;\n\tpartialsCount?: number;\n}\n\ninterface AMPartialsOscillatorOptions extends AMBaseOscillatorOptions {\n\ttype: TypeWithPartials;\n}\n\nexport type AMConstructorOptions =\n\t| AMCustomOscillatorOptions\n\t| AMTypeOscillatorOptions\n\t| AMPartialsOscillatorOptions;\n\nexport interface AMOscillatorOptions extends ToneOscillatorOptions {\n\tharmonicity: Positive;\n\tmodulationType: AllNonCustomOscillatorType;\n}\n/**\n * FatOscillator\n */\ninterface FatBaseOscillatorOptions extends BaseOscillatorOptions {\n\tspread: Cents;\n\tcount: Positive;\n}\n\ninterface FatCustomOscillatorOptions extends FatBaseOscillatorOptions {\n\ttype: \"custom\";\n\tpartials: number[];\n}\n\ninterface FatTypeOscillatorOptions extends FatBaseOscillatorOptions {\n\ttype: NonCustomOscillatorType;\n\tpartialCount?: number;\n}\n\ninterface FatPartialsOscillatorOptions extends FatBaseOscillatorOptions {\n\ttype: TypeWithPartials;\n}\n\nexport type FatConstructorOptions =\n\t| FatCustomOscillatorOptions\n\t| FatTypeOscillatorOptions\n\t| FatPartialsOscillatorOptions;\n\nexport interface FatOscillatorOptions extends ToneOscillatorOptions {\n\tspread: Cents;\n\tcount: Positive;\n}\n\n/**\n * Pulse Oscillator\n */\nexport interface PulseOscillatorOptions extends BaseOscillatorOptions {\n\ttype: \"pulse\";\n\twidth: AudioRange;\n}\n\n/**\n * PWM Oscillator\n */\nexport interface PWMOscillatorOptions extends BaseOscillatorOptions {\n\ttype: \"pwm\";\n\tmodulationFrequency: Frequency;\n}\n\n/**\n * OMNI OSCILLATOR\n */\n\n/**\n * FM Oscillators with partials\n */\ntype FMSineWithPartials = `fmsine${PartialsRange}`;\n\ntype FMSquareWithPartials = `fmsquare${PartialsRange}`;\n\ntype FMSawtoothWithPartials = `fmsawtooth${PartialsRange}`;\n\ntype FMTriangleWithPartials = `fmtriangle${PartialsRange}`;\n\ntype FMTypeWithPartials =\n\t| FMSineWithPartials\n\t| FMSquareWithPartials\n\t| FMSawtoothWithPartials\n\t| FMTriangleWithPartials;\n\n/**\n * AM Oscillators with partials\n */\ntype AMSineWithPartials = `amsine${PartialsRange}`;\n\ntype AMSquareWithPartials = `amsquare${PartialsRange}`;\n\ntype AMSawtoothWithPartials = `amsawtooth${PartialsRange}`;\n\ntype AMTriangleWithPartials = `amtriangle${PartialsRange}`;\n\ntype AMTypeWithPartials =\n\t| AMSineWithPartials\n\t| AMSquareWithPartials\n\t| AMSawtoothWithPartials\n\t| AMTriangleWithPartials;\n\n/**\n * Fat Oscillators with partials\n */\ntype FatSineWithPartials = `fatsine${PartialsRange}`;\n\ntype FatSquareWithPartials = `fatsquare${PartialsRange}`;\n\ntype FatSawtoothWithPartials = `fatsawtooth${PartialsRange}`;\n\ntype FatTriangleWithPartials = `fattriangle${PartialsRange}`;\n\ntype FatTypeWithPartials =\n\t| FatSineWithPartials\n\t| FatSquareWithPartials\n\t| FatSawtoothWithPartials\n\t| FatTriangleWithPartials;\n\n/**\n * Omni FM\n */\ninterface OmniFMCustomOscillatorOptions extends FMBaseOscillatorOptions {\n\ttype: \"fmcustom\";\n\tpartials: number[];\n}\n\ninterface OmniFMTypeOscillatorOptions extends FMBaseOscillatorOptions {\n\ttype: \"fmsine\" | \"fmsquare\" | \"fmsawtooth\" | \"fmtriangle\";\n\tpartialsCount?: number;\n}\n\ninterface OmniFMPartialsOscillatorOptions extends FMBaseOscillatorOptions {\n\ttype: FMTypeWithPartials;\n}\n\n/**\n * Omni AM\n */\ninterface OmniAMCustomOscillatorOptions extends AMBaseOscillatorOptions {\n\ttype: \"amcustom\";\n\tpartials: number[];\n}\n\ninterface OmniAMTypeOscillatorOptions extends AMBaseOscillatorOptions {\n\ttype: \"amsine\" | \"amsquare\" | \"amsawtooth\" | \"amtriangle\";\n\tpartialsCount?: number;\n}\n\ninterface OmniAMPartialsOscillatorOptions extends AMBaseOscillatorOptions {\n\ttype: AMTypeWithPartials;\n}\n\n/**\n * Omni Fat\n */\ninterface OmniFatCustomOscillatorOptions extends FatBaseOscillatorOptions {\n\ttype: \"fatcustom\";\n\tpartials: number[];\n}\n\ninterface OmniFatTypeOscillatorOptions extends FatBaseOscillatorOptions {\n\ttype: \"fatsine\" | \"fatsquare\" | \"fatsawtooth\" | \"fattriangle\";\n\tpartialsCount?: number;\n}\n\ninterface OmniFatPartialsOscillatorOptions extends FatBaseOscillatorOptions {\n\ttype: FatTypeWithPartials;\n}\n\nexport type OmniOscillatorType =\n\t| \"fatsine\"\n\t| \"fatsquare\"\n\t| \"fatsawtooth\"\n\t| \"fattriangle\"\n\t| \"fatcustom\"\n\t| FatTypeWithPartials\n\t| \"fmsine\"\n\t| \"fmsquare\"\n\t| \"fmsawtooth\"\n\t| \"fmtriangle\"\n\t| \"fmcustom\"\n\t| FMTypeWithPartials\n\t| \"amsine\"\n\t| \"amsquare\"\n\t| \"amsawtooth\"\n\t| \"amtriangle\"\n\t| \"amcustom\"\n\t| AMTypeWithPartials\n\t| TypeWithPartials\n\t| OscillatorType\n\t| \"pulse\"\n\t| \"pwm\";\n\nexport type OmniOscillatorOptions =\n\t| PulseOscillatorOptions\n\t| PWMOscillatorOptions\n\t| OmniFatCustomOscillatorOptions\n\t| OmniFatTypeOscillatorOptions\n\t| OmniFatPartialsOscillatorOptions\n\t| OmniFMCustomOscillatorOptions\n\t| OmniFMTypeOscillatorOptions\n\t| OmniFMPartialsOscillatorOptions\n\t| OmniAMCustomOscillatorOptions\n\t| OmniAMTypeOscillatorOptions\n\t| OmniAMPartialsOscillatorOptions\n\t| ToneOscillatorConstructorOptions;\n\ntype OmitSourceOptions<T extends BaseOscillatorOptions> = Omit<\n\tT,\n\t\"frequency\" | \"detune\" | \"context\"\n>;\n\n/**\n * The settable options for the omni oscillator inside of the source which excludes certain attributes that are defined by the parent class\n */\nexport type OmniOscillatorSynthOptions =\n\t| OmitSourceOptions<PulseOscillatorOptions>\n\t| OmitSourceOptions<PWMOscillatorOptions>\n\t| OmitSourceOptions<OmniFatCustomOscillatorOptions>\n\t| OmitSourceOptions<OmniFatTypeOscillatorOptions>\n\t| OmitSourceOptions<OmniFatPartialsOscillatorOptions>\n\t| OmitSourceOptions<OmniFMCustomOscillatorOptions>\n\t| OmitSourceOptions<OmniFMTypeOscillatorOptions>\n\t| OmitSourceOptions<OmniFMPartialsOscillatorOptions>\n\t| OmitSourceOptions<OmniAMCustomOscillatorOptions>\n\t| OmitSourceOptions<OmniAMTypeOscillatorOptions>\n\t| OmitSourceOptions<OmniAMPartialsOscillatorOptions>\n\t| OmitSourceOptions<ToneCustomOscillatorOptions>\n\t| OmitSourceOptions<ToneTypeOscillatorOptions>\n\t| OmitSourceOptions<TonePartialOscillatorOptions>;\n"
  },
  {
    "path": "Tone/source/oscillator/PWMOscillator.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../../test/helper/CompareToFile.js\";\nimport { connectFrom } from \"../../../test/helper/Connect.js\";\nimport { OscillatorTests } from \"../../../test/helper/OscillatorTests.js\";\nimport { SourceTests } from \"../../../test/helper/SourceTests.js\";\nimport { PWMOscillator } from \"./PWMOscillator.js\";\n\ndescribe(\"PWMOscillator\", () => {\n\t// run the common tests\n\tBasicTests(PWMOscillator);\n\tSourceTests(PWMOscillator);\n\tOscillatorTests(PWMOscillator);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst osc = new PWMOscillator().toDestination();\n\t\t\t\tosc.start(0.1);\n\t\t\t},\n\t\t\t\"pwmOscillator.wav\",\n\t\t\t0.01\n\t\t);\n\t});\n\n\tcontext(\"Modulation Frequency\", () => {\n\t\tit(\"can set the modulation frequency\", () => {\n\t\t\tconst pwm = new PWMOscillator();\n\t\t\tpwm.modulationFrequency.value = 0.2;\n\t\t\texpect(pwm.modulationFrequency.value).to.be.closeTo(0.2, 0.001);\n\t\t\tpwm.dispose();\n\t\t});\n\n\t\tit(\"can connect a signal to the modulationFrequency\", () => {\n\t\t\tconst pwm = new PWMOscillator();\n\t\t\tconnectFrom().connect(pwm.modulationFrequency);\n\t\t\tpwm.dispose();\n\t\t});\n\t});\n\n\tcontext(\"Types\", () => {\n\t\tit(\"reports its type\", () => {\n\t\t\tconst osc = new PWMOscillator();\n\t\t\texpect(osc.type).to.equal(\"pwm\");\n\t\t\texpect(osc.baseType).to.equal(\"pwm\");\n\t\t\texpect(osc.partials).to.deep.equal([]);\n\t\t\tosc.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/source/oscillator/PWMOscillator.ts",
    "content": "import { Degrees, Frequency, Seconds, Time } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly } from \"../../core/util/Interface.js\";\nimport { Multiply } from \"../../signal/Multiply.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { Source } from \"../Source.js\";\nimport { Oscillator } from \"./Oscillator.js\";\nimport {\n\tgenerateWaveform,\n\tPWMOscillatorOptions,\n\tToneOscillatorInterface,\n} from \"./OscillatorInterface.js\";\nimport { PulseOscillator } from \"./PulseOscillator.js\";\n\nexport { PWMOscillatorOptions } from \"./OscillatorInterface.js\";\n\n/**\n * PWMOscillator modulates the width of a Tone.PulseOscillator\n * at the modulationFrequency. This has the effect of continuously\n * changing the timbre of the oscillator by altering the harmonics\n * generated.\n * @example\n * return Tone.Offline(() => {\n * \tconst pwm = new Tone.PWMOscillator(60, 0.3).toDestination().start();\n * }, 0.1, 1);\n * @category Source\n */\nexport class PWMOscillator\n\textends Source<PWMOscillatorOptions>\n\timplements ToneOscillatorInterface\n{\n\treadonly name: string = \"PWMOscillator\";\n\n\treadonly sourceType = \"pwm\";\n\n\t/**\n\t * the pulse oscillator\n\t */\n\tprivate _pulse: PulseOscillator;\n\t/**\n\t * the modulator\n\t */\n\tprivate _modulator: Oscillator;\n\n\t/**\n\t * Scale the oscillator so it doesn't go silent\n\t * at the extreme values.\n\t */\n\tprivate _scale: Multiply = new Multiply({\n\t\tcontext: this.context,\n\t\tvalue: 2,\n\t});\n\n\t/**\n\t * The frequency control.\n\t */\n\treadonly frequency: Signal<\"frequency\">;\n\n\t/**\n\t * The detune of the oscillator.\n\t */\n\treadonly detune: Signal<\"cents\">;\n\n\t/**\n\t * The width modulation rate of the oscillator.\n\t * @example\n\t * return Tone.Offline(() => {\n\t * \tconst osc = new Tone.PWMOscillator(20, 2).toDestination().start();\n\t * }, 0.1, 1);\n\t */\n\treadonly modulationFrequency: Signal<\"frequency\">;\n\n\t/**\n\t * @param {Frequency} frequency The starting frequency of the oscillator.\n\t * @param {Frequency} modulationFrequency The modulation frequency of the width of the pulse.\n\t */\n\tconstructor(frequency?: Frequency, modulationFrequency?: Frequency);\n\tconstructor(options?: Partial<PWMOscillatorOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tPWMOscillator.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"frequency\", \"modulationFrequency\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis._pulse = new PulseOscillator({\n\t\t\tcontext: this.context,\n\t\t\tfrequency: options.modulationFrequency,\n\t\t});\n\t\t// change the pulse oscillator type\n\t\tthis._pulse.carrierType = \"sine\";\n\n\t\tthis.modulationFrequency = this._pulse.frequency;\n\n\t\tthis._modulator = new Oscillator({\n\t\t\tcontext: this.context,\n\t\t\tdetune: options.detune,\n\t\t\tfrequency: options.frequency,\n\t\t\tonstop: () => this.onstop(this),\n\t\t\tphase: options.phase,\n\t\t});\n\n\t\tthis.frequency = this._modulator.frequency;\n\t\tthis.detune = this._modulator.detune;\n\n\t\t// connections\n\t\tthis._modulator.chain(this._scale, this._pulse.width);\n\t\tthis._pulse.connect(this.output);\n\t\treadOnly(this, [\"modulationFrequency\", \"frequency\", \"detune\"]);\n\t}\n\n\tstatic getDefaults(): PWMOscillatorOptions {\n\t\treturn Object.assign(Source.getDefaults(), {\n\t\t\tdetune: 0,\n\t\t\tfrequency: 440,\n\t\t\tmodulationFrequency: 0.4,\n\t\t\tphase: 0,\n\t\t\ttype: \"pwm\" as const,\n\t\t});\n\t}\n\t/**\n\t * start the oscillator\n\t */\n\tprotected _start(time: Time): void {\n\t\ttime = this.toSeconds(time);\n\t\tthis._modulator.start(time);\n\t\tthis._pulse.start(time);\n\t}\n\n\t/**\n\t * stop the oscillator\n\t */\n\tprotected _stop(time: Time): void {\n\t\ttime = this.toSeconds(time);\n\t\tthis._modulator.stop(time);\n\t\tthis._pulse.stop(time);\n\t}\n\n\t/**\n\t * restart the oscillator\n\t */\n\tprotected _restart(time: Seconds): void {\n\t\tthis._modulator.restart(time);\n\t\tthis._pulse.restart(time);\n\t}\n\n\t/**\n\t * The type of the oscillator. Always returns \"pwm\".\n\t */\n\tget type(): \"pwm\" {\n\t\treturn \"pwm\";\n\t}\n\n\t/**\n\t * The baseType of the oscillator. Always returns \"pwm\".\n\t */\n\tget baseType(): \"pwm\" {\n\t\treturn \"pwm\";\n\t}\n\n\t/**\n\t * The partials of the waveform. Cannot set partials for this waveform type\n\t */\n\tget partials(): number[] {\n\t\treturn [];\n\t}\n\n\t/**\n\t * No partials for this waveform type.\n\t */\n\tget partialCount(): number {\n\t\treturn 0;\n\t}\n\n\t/**\n\t * The phase of the oscillator in degrees.\n\t */\n\tget phase(): Degrees {\n\t\treturn this._modulator.phase;\n\t}\n\tset phase(phase: Degrees) {\n\t\tthis._modulator.phase = phase;\n\t}\n\n\tasync asArray(length = 1024): Promise<Float32Array> {\n\t\treturn generateWaveform(this, length);\n\t}\n\n\t/**\n\t * Clean up.\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._pulse.dispose();\n\t\tthis._scale.dispose();\n\t\tthis._modulator.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/source/oscillator/PulseOscillator.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../../test/helper/CompareToFile.js\";\nimport { Offline } from \"../../../test/helper/Offline.js\";\nimport { OscillatorTests } from \"../../../test/helper/OscillatorTests.js\";\nimport { SourceTests } from \"../../../test/helper/SourceTests.js\";\nimport { PulseOscillator } from \"./PulseOscillator.js\";\n\ndescribe(\"PulseOscillator\", () => {\n\t// run the common tests\n\tBasicTests(PulseOscillator);\n\tSourceTests(PulseOscillator);\n\tOscillatorTests(PulseOscillator);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(\n\t\t\t() => {\n\t\t\t\tconst osc = new PulseOscillator({\n\t\t\t\t\twidth: 0.2,\n\t\t\t\t}).toDestination();\n\t\t\t\tosc.start(0);\n\t\t\t},\n\t\t\t\"pulseOscillator.wav\",\n\t\t\t0.03\n\t\t);\n\t});\n\n\tcontext(\"Phase Rotation\", () => {\n\t\tit(\"can change the phase to 90\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst osc = new PulseOscillator({\n\t\t\t\t\tfrequency: 1,\n\t\t\t\t\tphase: 90,\n\t\t\t\t\twidth: 0,\n\t\t\t\t});\n\t\t\t\tosc.toDestination();\n\t\t\t\tosc.start(0);\n\t\t\t}, 1);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\tif (time < 0.25) {\n\t\t\t\t\texpect(sample).to.be.within(-1, 0);\n\t\t\t\t} else if (time > 0.25 && time < 0.5) {\n\t\t\t\t\texpect(sample).to.be.within(0, 1);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"can change the phase to -90\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst osc = new PulseOscillator({\n\t\t\t\t\tfrequency: 1,\n\t\t\t\t\tphase: 270,\n\t\t\t\t\twidth: 0,\n\t\t\t\t});\n\t\t\t\tosc.toDestination();\n\t\t\t\tosc.start(0);\n\t\t\t}, 1);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\tif (time < 0.25) {\n\t\t\t\t\texpect(sample).to.be.within(0, 1);\n\t\t\t\t} else if (time > 0.25 && time < 0.5) {\n\t\t\t\t\texpect(sample).to.be.within(-1, 0);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"Width\", () => {\n\t\tit(\"can set the width\", () => {\n\t\t\tconst osc = new PulseOscillator({\n\t\t\t\twidth: 0.2,\n\t\t\t});\n\t\t\texpect(osc.width.value).to.be.closeTo(0.2, 0.001);\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"outputs correctly with a width of 0\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst osc = new PulseOscillator({\n\t\t\t\t\tfrequency: 1,\n\t\t\t\t\twidth: 0,\n\t\t\t\t});\n\t\t\t\tosc.toDestination();\n\t\t\t\tosc.start(0);\n\t\t\t}, 0.9);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\tif (time > 0.51) {\n\t\t\t\t\texpect(sample).to.be.within(-1, 0);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tit(\"outputs correctly with a width of 0.5\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst osc = new PulseOscillator({\n\t\t\t\t\tfrequency: 1,\n\t\t\t\t\twidth: 0.5,\n\t\t\t\t});\n\t\t\t\tosc.toDestination();\n\t\t\t\tosc.start(0);\n\t\t\t}, 1);\n\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\tif (time <= 0.6) {\n\t\t\t\t\texpect(sample).to.be.within(0, 1);\n\t\t\t\t} else if (time >= 0.63 && time <= 0.87) {\n\t\t\t\t\texpect(sample).to.be.within(-1, 0);\n\t\t\t\t} else if (time > 0.9) {\n\t\t\t\t\texpect(sample).to.be.within(0, 1);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t});\n\n\tcontext(\"Types\", () => {\n\t\tit(\"reports its type\", () => {\n\t\t\tconst osc = new PulseOscillator();\n\t\t\texpect(osc.type).to.equal(\"pulse\");\n\t\t\texpect(osc.baseType).to.equal(\"pulse\");\n\t\t\texpect(osc.partials).to.deep.equal([]);\n\t\t\tosc.dispose();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/source/oscillator/PulseOscillator.ts",
    "content": "import { Gain } from \"../../core/context/Gain.js\";\nimport {\n\tAudioRange,\n\tDegrees,\n\tFrequency,\n\tSeconds,\n\tTime,\n} from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly } from \"../../core/util/Interface.js\";\nimport { Signal } from \"../../signal/Signal.js\";\nimport { WaveShaper } from \"../../signal/WaveShaper.js\";\nimport { Source } from \"../Source.js\";\nimport { Oscillator } from \"./Oscillator.js\";\nimport {\n\tgenerateWaveform,\n\tPulseOscillatorOptions,\n\tToneOscillatorInterface,\n} from \"./OscillatorInterface.js\";\n\nexport { PulseOscillatorOptions } from \"./OscillatorInterface.js\";\n\n/**\n * PulseOscillator is an oscillator with control over pulse width,\n * also known as the duty cycle. At 50% duty cycle (width = 0) the wave is\n * a square wave.\n * [Read more](https://wigglewave.wordpress.com/2014/08/16/pulse-waveforms-and-harmonics/).\n * ```\n *    width = -0.25        width = 0.0          width = 0.25\n *\n *   +-----+            +-------+       +    +-------+     +-+\n *   |     |            |       |       |            |     |\n *   |     |            |       |       |            |     |\n * +-+     +-------+    +       +-------+            +-----+\n *\n *\n *    width = -0.5                              width = 0.5\n *\n *     +---+                                 +-------+   +---+\n *     |   |                                         |   |\n *     |   |                                         |   |\n * +---+   +-------+                                 +---+\n *\n *\n *    width = -0.75                             width = 0.75\n *\n *       +-+                                 +-------+ +-----+\n *       | |                                         | |\n *       | |                                         | |\n * +-----+ +-------+                                 +-+\n * ```\n * @example\n * return Tone.Offline(() => {\n * \tconst pulse = new Tone.PulseOscillator(50, 0.4).toDestination().start();\n * }, 0.1, 1);\n * @category Source\n */\nexport class PulseOscillator\n\textends Source<PulseOscillatorOptions>\n\timplements ToneOscillatorInterface\n{\n\treadonly name: string = \"PulseOscillator\";\n\n\t/**\n\t * The width of the pulse.\n\t * @example\n\t * return Tone.Offline(() => {\n\t * \tconst pulse = new Tone.PulseOscillator(20, 0.8).toDestination().start();\n\t * }, 0.1, 1);\n\t */\n\treadonly width: Signal<\"audioRange\">;\n\n\t/**\n\t * gate the width amount\n\t */\n\tprivate _widthGate: Gain = new Gain({\n\t\tcontext: this.context,\n\t\tgain: 0,\n\t});\n\n\t/**\n\t * the sawtooth oscillator\n\t */\n\tprivate _triangle: Oscillator;\n\n\t/**\n\t * The frequency control.\n\t */\n\treadonly frequency: Signal<\"frequency\">;\n\n\t/**\n\t * The detune in cents.\n\t */\n\treadonly detune: Signal<\"cents\">;\n\n\t/**\n\t * Threshold the signal to turn it into a square\n\t */\n\tprivate _thresh = new WaveShaper({\n\t\tcontext: this.context,\n\t\tmapping: (val) => (val <= 0 ? -1 : 1),\n\t});\n\n\t/**\n\t * @param frequency The frequency of the oscillator\n\t * @param width The width of the pulse\n\t */\n\tconstructor(frequency?: Frequency, width?: AudioRange);\n\tconstructor(options?: Partial<PulseOscillatorOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tPulseOscillator.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"frequency\", \"width\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tthis.width = new Signal({\n\t\t\tcontext: this.context,\n\t\t\tunits: \"audioRange\",\n\t\t\tvalue: options.width,\n\t\t});\n\n\t\tthis._triangle = new Oscillator({\n\t\t\tcontext: this.context,\n\t\t\tdetune: options.detune,\n\t\t\tfrequency: options.frequency,\n\t\t\tonstop: () => this.onstop(this),\n\t\t\tphase: options.phase,\n\t\t\ttype: \"triangle\",\n\t\t});\n\t\tthis.frequency = this._triangle.frequency;\n\t\tthis.detune = this._triangle.detune;\n\n\t\t// connections\n\t\tthis._triangle.chain(this._thresh, this.output);\n\t\tthis.width.chain(this._widthGate, this._thresh);\n\t\treadOnly(this, [\"width\", \"frequency\", \"detune\"]);\n\t}\n\n\tstatic getDefaults(): PulseOscillatorOptions {\n\t\treturn Object.assign(Source.getDefaults(), {\n\t\t\tdetune: 0,\n\t\t\tfrequency: 440,\n\t\t\tphase: 0,\n\t\t\ttype: \"pulse\" as const,\n\t\t\twidth: 0.2,\n\t\t});\n\t}\n\n\t/**\n\t * start the oscillator\n\t */\n\tprotected _start(time: Time): void {\n\t\ttime = this.toSeconds(time);\n\t\tthis._triangle.start(time);\n\t\tthis._widthGate.gain.setValueAtTime(1, time);\n\t}\n\n\t/**\n\t * stop the oscillator\n\t */\n\tprotected _stop(time: Time): void {\n\t\ttime = this.toSeconds(time);\n\t\tthis._triangle.stop(time);\n\t\t// the width is still connected to the output.\n\t\t// that needs to be stopped also\n\t\tthis._widthGate.gain.cancelScheduledValues(time);\n\t\tthis._widthGate.gain.setValueAtTime(0, time);\n\t}\n\n\tprotected _restart(time: Seconds): void {\n\t\tthis._triangle.restart(time);\n\t\tthis._widthGate.gain.cancelScheduledValues(time);\n\t\tthis._widthGate.gain.setValueAtTime(1, time);\n\t}\n\n\t/**\n\t * The phase of the oscillator in degrees.\n\t */\n\tget phase(): Degrees {\n\t\treturn this._triangle.phase;\n\t}\n\tset phase(phase: Degrees) {\n\t\tthis._triangle.phase = phase;\n\t}\n\n\t/**\n\t * The type of the oscillator. Always returns \"pulse\".\n\t */\n\tget type(): \"pulse\" {\n\t\treturn \"pulse\";\n\t}\n\n\t/**\n\t * The baseType of the oscillator. Always returns \"pulse\".\n\t */\n\tget baseType(): \"pulse\" {\n\t\treturn \"pulse\";\n\t}\n\n\t/**\n\t * The partials of the waveform. Cannot set partials for this waveform type\n\t */\n\tget partials(): number[] {\n\t\treturn [];\n\t}\n\n\t/**\n\t * No partials for this waveform type.\n\t */\n\tget partialCount(): number {\n\t\treturn 0;\n\t}\n\n\t/**\n\t * *Internal use* The carrier oscillator type is fed through the\n\t * waveshaper node to create the pulse. Using different carrier oscillators\n\t * changes oscillator's behavior.\n\t */\n\tset carrierType(type: \"triangle\" | \"sine\") {\n\t\tthis._triangle.type = type;\n\t}\n\n\tasync asArray(length = 1024): Promise<Float32Array> {\n\t\treturn generateWaveform(this, length);\n\t}\n\n\t/**\n\t * Clean up method.\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tthis._triangle.dispose();\n\t\tthis.width.dispose();\n\t\tthis._widthGate.dispose();\n\t\tthis._thresh.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "Tone/source/oscillator/ToneOscillatorNode.test.ts",
    "content": "import { expect } from \"chai\";\n\nimport { BasicTests } from \"../../../test/helper/Basic.js\";\nimport { CompareToFile } from \"../../../test/helper/CompareToFile.js\";\nimport { Offline, whenBetween } from \"../../../test/helper/Offline.js\";\nimport { Frequency } from \"../../core/type/Frequency.js\";\nimport { ToneOscillatorNode } from \"./ToneOscillatorNode.js\";\n\ndescribe(\"ToneOscillatorNode\", () => {\n\tBasicTests(ToneOscillatorNode);\n\n\tit(\"matches a file\", () => {\n\t\treturn CompareToFile(() => {\n\t\t\tconst osc = new ToneOscillatorNode().toDestination();\n\t\t\tosc.start(0.5);\n\t\t}, \"oscillatorNode.wav\");\n\t});\n\n\tcontext(\"Constructor\", () => {\n\t\tit(\"can be constructed with a frequency and type\", () => {\n\t\t\tconst osc0 = new ToneOscillatorNode(330, \"square\");\n\t\t\texpect(osc0.frequency.value).to.equal(330);\n\t\t\tosc0.dispose();\n\t\t\tconst osc1 = new ToneOscillatorNode(\n\t\t\t\tFrequency(550).valueOf(),\n\t\t\t\t\"sawtooth\"\n\t\t\t);\n\t\t\texpect(osc1.frequency.value).to.equal(550);\n\t\t\tosc1.dispose();\n\t\t\tconst osc2 = new ToneOscillatorNode(\"A3\", \"triangle\");\n\t\t\texpect(osc2.frequency.value).to.equal(220);\n\t\t\tosc2.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with no arguments\", () => {\n\t\t\tconst osc = new ToneOscillatorNode();\n\t\t\texpect(osc.frequency.value).to.equal(440);\n\t\t\texpect(osc.detune.value).to.equal(0);\n\t\t\texpect(osc.type).to.equal(\"sine\");\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an options object\", () => {\n\t\t\tconst osc = new ToneOscillatorNode({\n\t\t\t\tdetune: -20,\n\t\t\t\tfrequency: 123,\n\t\t\t\ttype: \"square\",\n\t\t\t});\n\t\t\texpect(osc.frequency.value).to.be.closeTo(123, 0.01);\n\t\t\texpect(osc.detune.value).to.equal(-20);\n\t\t\texpect(osc.type).to.equal(\"square\");\n\t\t\tosc.dispose();\n\t\t});\n\t});\n\n\tcontext(\"Type\", () => {\n\t\tit(\"can get and set the type\", () => {\n\t\t\tconst osc = new ToneOscillatorNode();\n\t\t\tosc.type = \"triangle\";\n\t\t\texpect(osc.type).to.equal(\"triangle\");\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"can set a periodic wave\", () => {\n\t\t\tconst osc = new ToneOscillatorNode();\n\t\t\tconst periodicWave = osc.context.createPeriodicWave(\n\t\t\t\tFloat32Array.from([1, 0]),\n\t\t\t\tFloat32Array.from([1, 0])\n\t\t\t);\n\t\t\tosc.setPeriodicWave(periodicWave);\n\t\t\texpect(osc.type).to.equal(\"custom\");\n\t\t\tosc.dispose();\n\t\t});\n\t});\n\n\tcontext(\"onended\", () => {\n\t\tit(\"invokes the onended callback in the online context\", (done) => {\n\t\t\tconst osc = new ToneOscillatorNode();\n\t\t\tosc.start();\n\t\t\tosc.stop(\"+0.3\");\n\t\t\tconst now = osc.now();\n\t\t\tosc.onended = () => {\n\t\t\t\texpect(osc.now() - now).to.be.within(0.25, 0.5);\n\t\t\t\tosc.dispose();\n\t\t\t\tdone();\n\t\t\t};\n\t\t});\n\n\t\tit(\"invokes the onended callback only once in the online context\", (done) => {\n\t\t\tconst osc = new ToneOscillatorNode();\n\t\t\tosc.start();\n\t\t\tosc.stop(\"+0.1\");\n\t\t\tosc.stop(\"+0.2\");\n\t\t\tosc.stop(\"+0.3\");\n\t\t\tconst now = osc.now();\n\t\t\tosc.onended = () => {\n\t\t\t\texpect(osc.now() - now).to.be.within(0.25, 0.5);\n\t\t\t\tosc.dispose();\n\t\t\t\tdone();\n\t\t\t};\n\t\t});\n\n\t\tit(\"invokes the onended callback in the offline context\", async () => {\n\t\t\tlet wasInvoked = false;\n\t\t\tawait Offline(() => {\n\t\t\t\tconst osc = new ToneOscillatorNode();\n\t\t\t\tosc.start(0);\n\t\t\t\tosc.stop(0.2);\n\t\t\t\tosc.onended = () => {\n\t\t\t\t\texpect(osc.now() - 0.2).to.be.closeTo(0, 0.05);\n\t\t\t\t\tosc.dispose();\n\t\t\t\t\twasInvoked = true;\n\t\t\t\t};\n\t\t\t}, 0.3);\n\t\t\texpect(wasInvoked).to.equal(true);\n\t\t});\n\n\t\tit(\"invokes the onended callback only once in offline context\", async () => {\n\t\t\tlet wasInvoked = false;\n\t\t\tawait Offline(() => {\n\t\t\t\tconst osc = new ToneOscillatorNode();\n\t\t\t\tosc.start(0);\n\t\t\t\tosc.stop(0.1);\n\t\t\t\tosc.stop(0.2);\n\t\t\t\tosc.stop(0.3);\n\t\t\t\tosc.onended = () => {\n\t\t\t\t\texpect(osc.now() - 0.3).to.be.closeTo(0, 0.05);\n\t\t\t\t\tosc.dispose();\n\t\t\t\t\texpect(wasInvoked).to.equal(false);\n\t\t\t\t\twasInvoked = true;\n\t\t\t\t};\n\t\t\t}, 0.4);\n\t\t\texpect(wasInvoked).to.equal(true);\n\t\t});\n\t});\n\n\tcontext(\"Scheduling\", () => {\n\t\tit(\"throw an error if start is called multiple time\", () => {\n\t\t\tconst osc = new ToneOscillatorNode();\n\t\t\tosc.start();\n\t\t\texpect(() => {\n\t\t\t\tosc.start();\n\t\t\t}).to.throw();\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"can play for a specific duration\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst osc = new ToneOscillatorNode().toDestination();\n\t\t\t\tosc.start(0).stop(0.1);\n\t\t\t}, 0.4);\n\t\t\texpect(buffer.getRmsAtTime(0)).to.be.above(0);\n\t\t\texpect(buffer.getRmsAtTime(0.09)).to.be.above(0);\n\t\t\texpect(buffer.getRmsAtTime(0.1)).to.equal(0);\n\t\t});\n\n\t\tit(\"can call stop multiple times and takes the last value\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst osc = new ToneOscillatorNode().toDestination();\n\t\t\t\tosc.start(0).stop(0.1).stop(0.2);\n\t\t\t}, 0.4);\n\t\t\texpect(buffer.getRmsAtTime(0)).to.be.above(0);\n\t\t\texpect(buffer.getRmsAtTime(0.1)).to.be.above(0);\n\t\t\texpect(buffer.getRmsAtTime(0.19)).to.be.above(0);\n\t\t\texpect(buffer.getRmsAtTime(0.2)).to.equal(0);\n\t\t});\n\n\t\tit(\"clamps start time to the currentTime\", () => {\n\t\t\tconst osc = new ToneOscillatorNode();\n\t\t\tosc.start(0);\n\t\t\tconst currentTime = osc.context.currentTime;\n\t\t\texpect(osc.getStateAtTime(0)).to.equal(\"stopped\");\n\t\t\texpect(osc.getStateAtTime(currentTime)).to.equal(\"started\");\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"clamps stop time to the currentTime\", (done) => {\n\t\t\tconst osc = new ToneOscillatorNode();\n\t\t\tosc.start(0);\n\t\t\tlet currentTime = osc.context.currentTime;\n\t\t\texpect(osc.getStateAtTime(0)).to.equal(\"stopped\");\n\t\t\texpect(osc.getStateAtTime(currentTime)).to.equal(\"started\");\n\t\t\tsetTimeout(() => {\n\t\t\t\tcurrentTime = osc.now();\n\t\t\t\tosc.stop(0);\n\t\t\t\texpect(osc.getStateAtTime(currentTime + 0.01)).to.equal(\n\t\t\t\t\t\"stopped\"\n\t\t\t\t);\n\t\t\t\tosc.dispose();\n\t\t\t\tdone();\n\t\t\t}, 100);\n\t\t});\n\t});\n\n\tcontext(\"State\", () => {\n\t\tit(\"reports the right state\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst osc = new ToneOscillatorNode();\n\t\t\t\tosc.start(0);\n\t\t\t\tosc.stop(0.05);\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, 0.05, () => {\n\t\t\t\t\t\texpect(osc.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.05, 0.1, () => {\n\t\t\t\t\t\texpect(osc.state).to.equal(\"stopped\");\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.1);\n\t\t});\n\n\t\tit(\"can call stop multiple times, takes the last value\", async () => {\n\t\t\tawait Offline(() => {\n\t\t\t\tconst osc = new ToneOscillatorNode();\n\t\t\t\tosc.start(0);\n\t\t\t\tosc.stop(0.05);\n\t\t\t\tosc.stop(0.1);\n\t\t\t\treturn (time) => {\n\t\t\t\t\twhenBetween(time, 0, 0.1, () => {\n\t\t\t\t\t\texpect(osc.state).to.equal(\"started\");\n\t\t\t\t\t});\n\t\t\t\t\twhenBetween(time, 0.1, 0.2, () => {\n\t\t\t\t\t\texpect(osc.state).to.equal(\"stopped\");\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}, 0.2);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "Tone/source/oscillator/ToneOscillatorNode.ts",
    "content": "import { Param } from \"../../core/context/Param.js\";\nimport { connect } from \"../../core/context/ToneAudioNode.js\";\nimport { Cents, Frequency, Seconds, Time } from \"../../core/type/Units.js\";\nimport { optionsFromArguments } from \"../../core/util/Defaults.js\";\nimport { readOnly } from \"../../core/util/Interface.js\";\nimport { OneShotSource, OneShotSourceOptions } from \"../OneShotSource.js\";\n\nexport interface ToneOscillatorNodeOptions extends OneShotSourceOptions {\n\tfrequency: Frequency;\n\tdetune: Cents;\n\ttype: OscillatorType;\n}\n\n/**\n * Wrapper around the native fire-and-forget OscillatorNode.\n * Adds the ability to reschedule the stop method.\n * ***{@link Oscillator} is better for most use-cases***\n * @category Source\n */\nexport class ToneOscillatorNode extends OneShotSource<ToneOscillatorNodeOptions> {\n\treadonly name: string = \"ToneOscillatorNode\";\n\n\t/**\n\t * The oscillator\n\t */\n\tprivate _oscillator = this.context.createOscillator();\n\tprotected _internalChannels = [this._oscillator];\n\n\t/**\n\t * The frequency of the oscillator\n\t */\n\treadonly frequency: Param<\"frequency\">;\n\n\t/**\n\t * The detune of the oscillator\n\t */\n\treadonly detune: Param<\"cents\">;\n\n\t/**\n\t * @param  frequency   The frequency value\n\t * @param  type  The basic oscillator type\n\t */\n\tconstructor(frequency: Frequency, type: OscillatorType);\n\tconstructor(options?: Partial<ToneOscillatorNodeOptions>);\n\tconstructor() {\n\t\tconst options = optionsFromArguments(\n\t\t\tToneOscillatorNode.getDefaults(),\n\t\t\targuments,\n\t\t\t[\"frequency\", \"type\"]\n\t\t);\n\t\tsuper(options);\n\n\t\tconnect(this._oscillator, this._gainNode);\n\n\t\tthis.type = options.type;\n\n\t\tthis.frequency = new Param({\n\t\t\tcontext: this.context,\n\t\t\tparam: this._oscillator.frequency,\n\t\t\tunits: \"frequency\",\n\t\t\tvalue: options.frequency,\n\t\t});\n\n\t\tthis.detune = new Param({\n\t\t\tcontext: this.context,\n\t\t\tparam: this._oscillator.detune,\n\t\t\tunits: \"cents\",\n\t\t\tvalue: options.detune,\n\t\t});\n\n\t\treadOnly(this, [\"frequency\", \"detune\"]);\n\t}\n\n\tstatic getDefaults(): ToneOscillatorNodeOptions {\n\t\treturn Object.assign(OneShotSource.getDefaults(), {\n\t\t\tdetune: 0,\n\t\t\tfrequency: 440,\n\t\t\ttype: \"sine\" as OscillatorType,\n\t\t});\n\t}\n\n\t/**\n\t * Start the oscillator node at the given time\n\t * @param  time When to start the oscillator\n\t */\n\tstart(time?: Time): this {\n\t\tconst computedTime = this.toSeconds(time);\n\t\tthis.log(\"start\", computedTime);\n\t\tthis._startGain(computedTime);\n\t\tthis._oscillator.start(computedTime);\n\t\treturn this;\n\t}\n\n\tprotected _stopSource(time?: Seconds): void {\n\t\tthis._oscillator.stop(time);\n\t}\n\n\t/**\n\t * Sets an arbitrary custom periodic waveform given a PeriodicWave.\n\t * @param  periodicWave PeriodicWave should be created with context.createPeriodicWave\n\t */\n\tsetPeriodicWave(periodicWave: PeriodicWave): this {\n\t\tthis._oscillator.setPeriodicWave(periodicWave);\n\t\treturn this;\n\t}\n\n\t/**\n\t * The oscillator type. Either 'sine', 'sawtooth', 'square', or 'triangle'\n\t */\n\tget type(): OscillatorType {\n\t\treturn this._oscillator.type;\n\t}\n\tset type(type: OscillatorType) {\n\t\tthis._oscillator.type = type;\n\t}\n\n\t/**\n\t * Clean up.\n\t */\n\tdispose(): this {\n\t\tsuper.dispose();\n\t\tif (this.state === \"started\") {\n\t\t\tthis.stop();\n\t\t}\n\t\tthis._oscillator.disconnect();\n\t\tthis.frequency.dispose();\n\t\tthis.detune.dispose();\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "eslint.config.mjs",
    "content": "// @ts-check\nimport stylisticJs from \"@stylistic/eslint-plugin-js\";\nimport stylisticTs from \"@stylistic/eslint-plugin-ts\";\nimport html from \"eslint-plugin-html\";\nimport jsdoc from \"eslint-plugin-jsdoc\";\nimport simpleImportSort from \"eslint-plugin-simple-import-sort\";\nimport unusedImports from \"eslint-plugin-unused-imports\";\nimport tseslint from \"typescript-eslint\";\n\n/** @type {import(\"typescript-eslint\").ConfigWithExtends} */\nconst customConfig = {\n\tfiles: [\"**/*.js\", \"**/*.cjs\", \"**/*.mjs\", \"**/*.ts\", \"**/*.html\"],\n\tplugins: {\n\t\t\"@stylistic/js\": stylisticJs,\n\t\t\"@stylistic/ts\": stylisticTs,\n\t\tjsdoc,\n\t\thtml,\n\t\t\"simple-import-sort\": simpleImportSort,\n\t\t\"unused-imports\": unusedImports,\n\t},\n\trules: {\n\t\t\"@typescript-eslint/array-type\": \"off\",\n\t\t\"@typescript-eslint/ban-ts-comment\": \"off\",\n\t\t\"@typescript-eslint/ban-ts-ignore\": \"off\",\n\t\t\"jsdoc/check-alignment\": 1,\n\t\t\"jsdoc/check-indentation\": [\n\t\t\t\"error\",\n\t\t\t{\n\t\t\t\texcludeTags: [\"example\", \"param\"],\n\t\t\t},\n\t\t],\n\t\t\"jsdoc/check-param-names\": [\"error\"],\n\t\tcurly: [\"error\", \"all\"],\n\t\t\"@stylistic/js/dot-location\": [\"error\", \"property\"],\n\t\t\"dot-notation\": [\"error\"],\n\t\t\"@stylistic/js/eol-last\": [\"error\", \"always\"],\n\t\teqeqeq: [\"error\"],\n\t\t\"@typescript-eslint/explicit-function-return-type\": \"off\",\n\t\t\"@typescript-eslint/explicit-member-accessibility\": \"off\",\n\t\t\"@stylistic/js/linebreak-style\": [\"error\", \"unix\"],\n\t\t\"no-cond-assign\": [\"error\", \"always\"],\n\t\t\"no-console\": [\n\t\t\t\"error\",\n\t\t\t{\n\t\t\t\tallow: [\"warn\"],\n\t\t\t},\n\t\t],\n\t\t\"@typescript-eslint/no-empty-function\": \"off\",\n\t\t\"@typescript-eslint/no-empty-object-type\": [\n\t\t\t\"error\",\n\t\t\t{\n\t\t\t\tallowInterfaces: \"always\",\n\t\t\t},\n\t\t],\n\t\t\"@typescript-eslint/no-explicit-any\": \"off\",\n\t\t\"no-lonely-if\": [\"error\"],\n\t\t\"@typescript-eslint/no-object-literal-type-assertion\": \"off\",\n\t\t\"no-shadow\": \"error\",\n\t\t\"no-throw-literal\": [\"error\"],\n\t\t\"no-unmodified-loop-condition\": [\"error\"],\n\t\t\"no-unneeded-ternary\": [\"error\"],\n\t\t\"@typescript-eslint/no-unused-vars\": \"off\",\n\t\t\"@typescript-eslint/no-use-before-define\": \"off\",\n\t\t\"no-useless-call\": [\"error\"],\n\t\t\"no-var\": \"error\",\n\t\t\"prefer-arrow-callback\": \"error\",\n\t\t\"prefer-rest-params\": \"off\",\n\t\t\"@stylistic/ts/quote-props\": [\"error\", \"as-needed\"],\n\t\t\"@stylistic/ts/quotes\": [\n\t\t\t\"error\",\n\t\t\t\"double\",\n\t\t\t{\n\t\t\t\tavoidEscape: true,\n\t\t\t},\n\t\t],\n\t\t\"sort-imports\": \"off\",\n\t\t\"simple-import-sort/imports\": \"error\",\n\t\t\"simple-import-sort/exports\": \"error\",\n\t\t\"@stylistic/js/spaced-comment\": [\n\t\t\t\"error\",\n\t\t\t\"always\",\n\t\t\t{\n\t\t\t\tline: {\n\t\t\t\t\texceptions: [\"-\"],\n\t\t\t\t},\n\t\t\t\tblock: {\n\t\t\t\t\tbalanced: true,\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t\"unused-imports/no-unused-imports\": \"error\",\n\t\t\"unused-imports/no-unused-vars\": [\n\t\t\t\"warn\",\n\t\t\t{\n\t\t\t\tvars: \"all\",\n\t\t\t\tvarsIgnorePattern: \"^_\",\n\t\t\t\targs: \"after-used\",\n\t\t\t\targsIgnorePattern: \"^_\",\n\t\t\t},\n\t\t],\n\t},\n};\n\nexport default tseslint.config(\n\ttseslint.configs.recommended,\n\tcustomConfig,\n\t{\n\t\tfiles: [\"**/*.test.ts\", \"./test/**/*.ts\"],\n\t\trules: {\n\t\t\t\"@typescript-eslint/no-unused-expressions\": \"off\",\n\t\t\t\"unused-imports/no-unused-vars\": \"off\",\n\t\t},\n\t},\n\t{\n\t\tfiles: [\"**/*.cjs\", \"**/*.mjs\"],\n\t\trules: {\n\t\t\t\"no-console\": \"off\",\n\t\t\t\"@typescript-eslint/no-require-imports\": \"off\",\n\t\t\t\"@typescript-eslint/no-unused-expressions\": \"off\",\n\t\t},\n\t},\n\t{\n\t\tname: \"globally-ignored-files\",\n\t\tignores: [\n\t\t\t\"**/node_modules\",\n\t\t\t\"build/**\",\n\t\t\t\"coverage/**\",\n\t\t\t\"**/dist/**\",\n\t\t\t\"docs/**\",\n\t\t\t\"examples/**/*.js\",\n\t\t],\n\t}\n);\n"
  },
  {
    "path": "examples/README.md",
    "content": "These examples use web components (e.g. `<tone-example>`) which are defined in the [Tonejs/ui](https://github.com/Tonejs/ui) repository.\n\n### Running examples locally\n\nCheck out the repository, and from the root run:\n\n```\n$ npm install\n...\n$ npm run build\n```\n\nOnce this is done, you can start a local server with Python:\n\n```\n$ python -m SimpleHTTPServer 8000\n```\n\nThen, from a browser visit http://localhost:8000/examples. (See also: [installation instructions on the wiki](https://github.com/Tonejs/Tone.js/wiki/Installation#newbie-macos-quickstart-to-get-examples-running))\n\n### Adding examples\n\nTo contribute examples, please follow the current style of the examples. Add your example's title and file name to `js/ExampleList.json` file for it to appear in the examples list on the index page. (cf. [CONTRIBUTING.md](https://github.com/Tonejs/Tone.js/blob/dev/.github/CONTRIBUTING.md))\n"
  },
  {
    "path": "examples/amSynth.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>AMSynth</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<tone-example label=\"AMSynth\">\n\t\t\t<div slot=\"explanation\">\n\t\t\t\t<a href=\"https://tonejs.github.io/docs/latest/classes/AMSynth\"\n\t\t\t\t\t>Tone.AMSynth</a\n\t\t\t\t>\n\t\t\t\tis composed of two\n\t\t\t\t<a href=\"https://tonejs.github.io/docs/latest/classes/Synth\"\n\t\t\t\t\t>Tone.Synths</a\n\t\t\t\t>\n\t\t\t\twhere one Tone.Synth modulates the amplitude of a second\n\t\t\t\tTone.Synth.\n\t\t\t</div>\n\n\t\t\t<div id=\"content\"></div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\tconst synth = new Tone.AMSynth({\n\t\t\t\tharmonicity: 2.5,\n\t\t\t\toscillator: {\n\t\t\t\t\ttype: \"fatsawtooth\",\n\t\t\t\t},\n\t\t\t\tenvelope: {\n\t\t\t\t\tattack: 0.1,\n\t\t\t\t\tdecay: 0.2,\n\t\t\t\t\tsustain: 0.2,\n\t\t\t\t\trelease: 0.3,\n\t\t\t\t},\n\t\t\t\tmodulation: {\n\t\t\t\t\ttype: \"square\",\n\t\t\t\t},\n\t\t\t\tmodulationEnvelope: {\n\t\t\t\t\tattack: 0.5,\n\t\t\t\t\tdecay: 0.01,\n\t\t\t\t},\n\t\t\t}).toDestination();\n\n\t\t\tpiano({\n\t\t\t\ttone: synth,\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t\tnoteon: (note) => synth.triggerAttack(note.name),\n\t\t\t\tnoteoff: (note) => synth.triggerRelease(),\n\t\t\t});\n\n\t\t\tui({\n\t\t\t\ttone: synth,\n\t\t\t\tname: \"AMSynth\",\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t});\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/analysis.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Analyser</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<tone-example label=\"Analyser\">\n\t\t\t<tone-loader></tone-loader>\n\n\t\t\t<div slot=\"explanation\">\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/FFT\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t>Tone.FFT</a\n\t\t\t\t>\n\t\t\t\treturns the amplitude of the incoming signal at different\n\t\t\t\tfrequencies.\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/Waveform\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t>Tone.Waveform</a\n\t\t\t\t>\n\t\t\t\treturns the signal value between 0-1.\n\t\t\t</div>\n\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\tconst player = new Tone.Player({\n\t\t\t\turl: \"https://tonejs.github.io/audio/berklee/arpeggio2.mp3\",\n\t\t\t\tloop: true,\n\t\t\t}).toDestination();\n\n\t\t\tconst toneMeter = new Tone.Meter();\n\t\t\tplayer.connect(toneMeter);\n\n\t\t\tconst toneFFT = new Tone.FFT();\n\t\t\tplayer.connect(toneFFT);\n\n\t\t\tconst toneWaveform = new Tone.Waveform();\n\t\t\tplayer.connect(toneWaveform);\n\n\t\t\t// bind the GUI\n\t\t\tdrawer().add({\n\t\t\t\ttone: player,\n\t\t\t\ttitle: \"Player\",\n\t\t\t});\n\t\t\tmeter({\n\t\t\t\ttone: toneMeter,\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t});\n\t\t\tfft({\n\t\t\t\ttone: toneFFT,\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t});\n\t\t\twaveform({\n\t\t\t\ttone: toneWaveform,\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t});\n\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"start\", () => player.start());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"stop\", () => player.stop());\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/animationSync.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n\t<title>Analyser</title>\n\n\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\">\n\t<link rel=\"icon\" type=\"image/png\" sizes=\"174x174\" href=\"./favicon.png\">\n\n\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t<link href=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\" rel=\"stylesheet\"/>\n\t<script src=\"../build/Tone.js\"></script>\n\t<script src=\"./js/tone-ui.js\"></script>\n\t<script src=\"./js/components.js\"></script>\n\n</head>\n<body>\t\n\t<style type=\"text/css\">\n\t\t#Notes{\n\t\t\twidth: 100%;\n\t\t\theight: 20px;\n\t\t\tposition: relative;\n\t\t\tmargin-bottom: 10px;\n\t\t}\n\t\t.Note {\n\t\t\twidth: 20%;\n\t\t\theight: 100%;\n\t\t\tposition: relative;\n\t\t\tfloat: left;\n\t\t\tbackground-color: black;\n\t\t\topacity: 0;\n\t\t\ttransition: opacity 0.5s;\n\t\t}\n\t\t.Note.active {\n\t\t\topacity: 1;\n\t\t\ttransition-duration: 0.1s;\n\t\t}\n\t</style>\n\t<tone-example label=\"Synchronizing Visuals\">\n\t\t<div slot=\"explanation\">\n\t\t\t Audio scheduling and rendering visuals should always be kept separate. Instead of triggering visuals from within a scheduled event callback, schedule a 'deferred' callback using Tone.Draw which will be invoked on an animation frame at the exact moment of the scheduled event.\n\t\t\t <br><br>\n\t\t\t For more information see <a href=\"https://github.com/Tonejs/Tone.js/wiki/Performance\">this wiki article</a>. \n\t\t</div>\n\t\t<div id=\"content\">\n\t\t\t<div id=\"Notes\">\n\t\t\t\t<div id=\"C4\" class=\"Note\"></div>\n\t\t\t\t<div id=\"E4\" class=\"Note\"></div>\n\t\t\t\t<div id=\"G4\" class=\"Note\"></div>\n\t\t\t\t<div id=\"B4\" class=\"Note\"></div>\n\t\t\t\t<div id=\"D5\" class=\"Note\"></div>\n\t\t\t</div>\n\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t</div>\n\t</tone-example>\n\t\n\t<script type=\"text/javascript\">\n\t\tconst synth = new Tone.Synth({\n\t\t\toscillator: {\n\t\t\t\ttype: \"fmsine4\",\n\t\t\t\tmodulationType: \"square\"\n\t\t\t}\n\t\t}).toDestination();\n\n\t\tconst loop = new Tone.Pattern(((time, note) => {\n\t\t\tsynth.triggerAttackRelease(note, \"16n\", time);\n\n\t\t\t// Draw.schedule takes a callback and a time to invoke the callback\n\t\t\tTone.Draw.schedule(() => {\n\t\t\t\t// the callback synced to the animation frame at the given time\n\t\t\t\tconst noteElement = document.querySelector(\"#\"+note);\n\t\t\t\tnoteElement.classList.add(\"active\");\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tnoteElement.classList.remove(\"active\");\n\t\t\t\t}, 100);\n\t\t\t}, time);\n\t\t}), [\"C4\", \"E4\", \"G4\", \"B4\", \"D5\"]).start(0);\n\n\t\tloop.interval = \"16n\";\n\n\t\tdrawer().add({\n\t\t\ttone: synth,\n\t\t\ttitle: \"Piano\",\n\t\t});\n\n\t\t// connect the UI with the components\n\t\tdocument.querySelector(\"tone-play-toggle\").addEventListener(\"start\", () => Tone.Transport.start());\n\t\tdocument.querySelector(\"tone-play-toggle\").addEventListener(\"stop\", () => Tone.Transport.stop());\n\n\t</script>\n</body>\n</html>\n"
  },
  {
    "path": "examples/bembe.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>MetalSynth</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<tone-example label=\"Bembe\">\n\t\t\t<div slot=\"explanation\">\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/MetalSynth\"\n\t\t\t\t\t>Tone.MetalSynth</a\n\t\t\t\t>\n\t\t\t\tcreates metallic, inharmonic sounds using 6\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/FMOscillator\"\n\t\t\t\t\t>Tone.FMOscillators</a\n\t\t\t\t>\n\t\t\t\twith a tuning based on the TR-808 Cymbal.\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/MembraneSynth\"\n\t\t\t\t\t>Tone.MembraneSynth</a\n\t\t\t\t>\n\t\t\t\tmakes kick and tom-like sounds using a frequency envelope which\n\t\t\t\tis triggered on notes attack.\n\t\t\t</div>\n\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\tconst bell = new Tone.MetalSynth({\n\t\t\t\tharmonicity: 12,\n\t\t\t\tresonance: 800,\n\t\t\t\tmodulationIndex: 20,\n\t\t\t\tenvelope: {\n\t\t\t\t\tdecay: 0.4,\n\t\t\t\t},\n\t\t\t\tvolume: -15,\n\t\t\t}).toDestination();\n\n\t\t\tconst bellPart = new Tone.Sequence(\n\t\t\t\t(time, freq) => {\n\t\t\t\t\tbell.triggerAttack(freq, time, Math.random() * 0.5 + 0.5);\n\t\t\t\t},\n\t\t\t\t[\n\t\t\t\t\t[300, null, 200],\n\t\t\t\t\t[null, 200, 200],\n\t\t\t\t\t[null, 200, null],\n\t\t\t\t\t[200, null, 200],\n\t\t\t\t],\n\t\t\t\t\"4n\"\n\t\t\t).start(0);\n\n\t\t\tconst conga = new Tone.MembraneSynth({\n\t\t\t\tpitchDecay: 0.008,\n\t\t\t\toctaves: 2,\n\t\t\t\tenvelope: {\n\t\t\t\t\tattack: 0.0006,\n\t\t\t\t\tdecay: 0.5,\n\t\t\t\t\tsustain: 0,\n\t\t\t\t},\n\t\t\t}).toDestination();\n\n\t\t\tconst congaPart = new Tone.Sequence(\n\t\t\t\t(time, pitch) => {\n\t\t\t\t\tconga.triggerAttack(pitch, time, Math.random() * 0.5 + 0.5);\n\t\t\t\t},\n\t\t\t\t[\"G3\", \"C4\", \"C4\", \"C4\"],\n\t\t\t\t\"4n\"\n\t\t\t).start(0);\n\n\t\t\tTone.Transport.bpm.value = 115;\n\n\t\t\tdrawer()\n\t\t\t\t.add({\n\t\t\t\t\ttone: conga,\n\t\t\t\t\ttitle: \"Conga\",\n\t\t\t\t})\n\t\t\t\t.add({\n\t\t\t\t\ttone: bell,\n\t\t\t\t\ttitle: \"Bell\",\n\t\t\t\t});\n\n\t\t\t// connect the UI with the components\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"start\", () => Tone.Transport.start());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"stop\", () => Tone.Transport.stop());\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/buses.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Buses</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<tone-example label=\"Buses\">\n\t\t\t<div slot=\"explanation\">\n\t\t\t\tBuses make it easy to share effects across many instruments.\n\t\t\t\t<code>send</code> audio to a named bus from an instrument and\n\t\t\t\tthen <code>receive</code> that channel on your effect. The gain\n\t\t\t\tvalues are all in decibels. <br /><br />\n\t\t\t\tDocs on\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/Channel.html#send\"\n\t\t\t\t\t>send</a\n\t\t\t\t>\n\t\t\t\tand\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/Channel.html#receive\"\n\t\t\t\t\t>receive</a\n\t\t\t\t>.\n\t\t\t</div>\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t\t\t<tone-slider\n\t\t\t\t\tlabel=\"Chorus Send\"\n\t\t\t\t\tmin=\"-60\"\n\t\t\t\t\tmax=\"6\"\n\t\t\t\t\tvalue=\"-60\"\n\t\t\t\t\tunits=\"db\"\n\t\t\t\t></tone-slider>\n\t\t\t\t<tone-slider\n\t\t\t\t\tlabel=\"Chebyshev Send\"\n\t\t\t\t\tmin=\"-60\"\n\t\t\t\t\tmax=\"6\"\n\t\t\t\t\tvalue=\"-60\"\n\t\t\t\t\tunits=\"db\"\n\t\t\t\t></tone-slider>\n\t\t\t\t<tone-slider\n\t\t\t\t\tlabel=\"Reverb Send\"\n\t\t\t\t\tmin=\"-60\"\n\t\t\t\t\tmax=\"6\"\n\t\t\t\t\tvalue=\"-60\"\n\t\t\t\t\tunits=\"db\"\n\t\t\t\t></tone-slider>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\t// the source\n\t\t\tconst player = new Tone.Player({\n\t\t\t\turl: \"https://tonejs.github.io/audio/berklee/femalevoice_oo_A4.mp3\",\n\t\t\t\tloop: true,\n\t\t\t});\n\n\t\t\t// make some effects\n\t\t\tconst chorus = new Tone.Chorus({\n\t\t\t\twet: 1,\n\t\t\t})\n\t\t\t\t.toDestination()\n\t\t\t\t.start();\n\t\t\tconst chorusChannel = new Tone.Channel({ volume: -60 }).connect(\n\t\t\t\tchorus\n\t\t\t);\n\t\t\tchorusChannel.receive(\"chorus\");\n\n\t\t\tconst cheby = new Tone.Chebyshev(50).toDestination();\n\t\t\tconst chebyChannel = new Tone.Channel({ volume: -60 }).connect(\n\t\t\t\tcheby\n\t\t\t);\n\t\t\tchebyChannel.receive(\"cheby\");\n\n\t\t\tconst reverb = new Tone.Reverb(3).toDestination();\n\t\t\tconst reverbChannel = new Tone.Channel({ volume: -60 }).connect(\n\t\t\t\treverb\n\t\t\t);\n\t\t\treverbChannel.receive(\"reverb\");\n\n\t\t\t// send the player to all of the channels\n\t\t\tconst playerChannel = new Tone.Channel().toDestination();\n\t\t\tplayerChannel.send(\"chorus\");\n\t\t\tplayerChannel.send(\"cheby\");\n\t\t\tplayerChannel.send(\"reverb\");\n\t\t\tplayer.connect(playerChannel);\n\n\t\t\tdrawer()\n\t\t\t\t.add({\n\t\t\t\t\ttone: chorus,\n\t\t\t\t})\n\t\t\t\t.add({\n\t\t\t\t\ttone: reverb,\n\t\t\t\t})\n\t\t\t\t.add({\n\t\t\t\t\ttone: cheby,\n\t\t\t\t});\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"start\", () => player.start());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"stop\", () => player.stop());\n\t\t\t// bind the interface\n\t\t\tdocument\n\t\t\t\t.querySelector('[label=\"Chorus Send\"]')\n\t\t\t\t.addEventListener(\"input\", (e) => {\n\t\t\t\t\tchorusChannel.volume.value = parseFloat(e.target.value);\n\t\t\t\t});\n\t\t\tdocument\n\t\t\t\t.querySelector('[label=\"Chebyshev Send\"]')\n\t\t\t\t.addEventListener(\"input\", (e) => {\n\t\t\t\t\tchebyChannel.volume.value = parseFloat(e.target.value);\n\t\t\t\t});\n\t\t\tdocument\n\t\t\t\t.querySelector('[label=\"Reverb Send\"]')\n\t\t\t\t.addEventListener(\"input\", (e) => {\n\t\t\t\t\treverbChannel.volume.value = parseFloat(e.target.value);\n\t\t\t\t});\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/daw.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>DAW</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t\t<style type=\"text/css\">\n\t\t\ttone-play-toggle {\n\t\t\t\tmargin-bottom: 10px;\n\t\t\t}\n\t\t\t#tracks {\n\t\t\t\tposition: relative;\n\t\t\t\twidth: calc(100% - 10px);\n\t\t\t\tmargin-left: 10px;\n\t\t\t}\n\n\t\t\t#progress {\n\t\t\t\twidth: 1px;\n\t\t\t\theight: 100%;\n\t\t\t\tleft: 0%;\n\t\t\t\tposition: absolute;\n\t\t\t\tbackground-color: black;\n\t\t\t}\n\t\t\timg {\n\t\t\t\twidth: 100%;\n\t\t\t\theight: 200px;\n\t\t\t}\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<tone-example label=\"DAW\">\n\t\t\t<tone-loader></tone-loader>\n\t\t\t<div slot=\"explanation\">\n\t\t\t\tThis beat is composed of 3 independent Players each with a\n\t\t\t\tdifferent loop length, synced to the Transport to start at\n\t\t\t\tdifferent times and different offsets. The players stay\n\t\t\t\tsynchronized to the position and offset of the Transport.\n\t\t\t</div>\n\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t\t\t<div id=\"tracks\">\n\t\t\t\t\t<div id=\"progress\"></div>\n\t\t\t\t\t<img\n\t\t\t\t\t\tsrc=\"https://tonejs.github.io/audio/loop/drum_loop.png\"\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\t// set the transport\n\t\t\tTone.Transport.bpm.value = 108;\n\t\t\tTone.Transport.loop = true;\n\t\t\tTone.Transport.loopStart = \"4m\";\n\t\t\tTone.Transport.loopEnd = \"8m\";\n\n\t\t\tconst kick = new Tone.Player({\n\t\t\t\turl: \"https://tonejs.github.io/audio/loop/kick.mp3\",\n\t\t\t\tloop: true,\n\t\t\t})\n\t\t\t\t.toDestination()\n\t\t\t\t.sync()\n\t\t\t\t.start(0);\n\n\t\t\tconst snare = new Tone.Player({\n\t\t\t\turl: \"https://tonejs.github.io/audio/loop/snare.mp3\",\n\t\t\t\tloop: true,\n\t\t\t})\n\t\t\t\t.toDestination()\n\t\t\t\t.sync()\n\t\t\t\t.start(\"2n\");\n\n\t\t\tconst hh = new Tone.Player({\n\t\t\t\turl: \"https://tonejs.github.io/audio/loop/hh.mp3\",\n\t\t\t\tloop: true,\n\t\t\t})\n\t\t\t\t.toDestination()\n\t\t\t\t.sync()\n\t\t\t\t.start(\"3:3\", \"4n\"); // start with an offset\n\n\t\t\t// connect the UI with the components\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"start\", () => Tone.Transport.start());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"stop\", () => Tone.Transport.stop());\n\n\t\t\t// keep the play head on track\n\t\t\tsetInterval(() => {\n\t\t\t\t// scale it between 0-1\n\t\t\t\tconst progress = (Tone.Transport.progress + 1) / 2;\n\t\t\t\tdocument.querySelector(\"#progress\").style =\n\t\t\t\t\t`left: ${progress * 100}%`;\n\t\t\t}, 16);\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/envelope.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Envelope</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<style type=\"text/css\">\n\t\t\timg {\n\t\t\t\tdisplay: block;\n\t\t\t\tmargin: 5px auto;\n\t\t\t\twidth: 300px !important;\n\t\t\t}\n\n\t\t\ttone-trigger {\n\t\t\t\tmargin-bottom: 10px;\n\t\t\t}\n\t\t</style>\n\t\t<tone-example label=\"Envelope\">\n\t\t\t<div slot=\"explanation\">\n\t\t\t\tEnvelopes ramp amplitude, frequency or any other parameter over\n\t\t\t\ttime.\n\t\t\t\t<a href=\"https://tonejs.github.io/docs/latest/classes/Envelope\"\n\t\t\t\t\t>Tone.Envelope</a\n\t\t\t\t>\n\t\t\t\tand the classes that extend it implement an\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t>ADSR</a\n\t\t\t\t>\n\t\t\t\tenvelope type which splits its ramp into four distinct phases:\n\t\t\t\tAttack, Decay, Sustain, Release.\n\t\t\t\t<img\n\t\t\t\t\tsrc=\"https://upload.wikimedia.org/wikipedia/commons/e/ea/ADSR_parameter.svg\"\n\t\t\t\t/>\n\t\t\t</div>\n\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-momentary-button></tone-momentary-button>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\tconst env = new Tone.AmplitudeEnvelope({\n\t\t\t\tattack: 0.11,\n\t\t\t\tdecay: 0.21,\n\t\t\t\tsustain: 0.5,\n\t\t\t\trelease: 1.2,\n\t\t\t}).toDestination();\n\n\t\t\t// create an oscillator and connect it to the envelope\n\t\t\tconst osc = new Tone.Oscillator({\n\t\t\t\tpartials: [3, 2, 1],\n\t\t\t\ttype: \"custom\",\n\t\t\t\tfrequency: \"C#4\",\n\t\t\t\tvolume: -8,\n\t\t\t})\n\t\t\t\t.connect(env)\n\t\t\t\t.start();\n\n\t\t\t// bind the interface\n\t\t\tdrawer()\n\t\t\t\t.add({\n\t\t\t\t\ttone: env,\n\t\t\t\t\tname: \"Envelope\",\n\t\t\t\t})\n\t\t\t\t.add({\n\t\t\t\t\ttone: osc,\n\t\t\t\t});\n\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-momentary-button\")\n\t\t\t\t.addEventListener(\"down\", (e) => env.triggerAttack());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-momentary-button\")\n\t\t\t\t.addEventListener(\"up\", (e) => env.triggerRelease());\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/events.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Events</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<tone-example label=\"Events\">\n\t\t\t<div slot=\"explanation\">\n\t\t\t\tTone's Event classes (<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/ToneEvent\"\n\t\t\t\t\t>Tone.ToneEvent</a\n\t\t\t\t>,\n\t\t\t\t<a href=\"https://tonejs.github.io/docs/latest/classes/Loop\"\n\t\t\t\t\t>Tone.Loop</a\n\t\t\t\t>,\n\t\t\t\t<a href=\"https://tonejs.github.io/docs/latest/classes/Part\"\n\t\t\t\t\t>Tone.Part</a\n\t\t\t\t>\n\t\t\t\tand\n\t\t\t\t<a href=\"https://tonejs.github.io/docs/latest/classes/Sequence\"\n\t\t\t\t\t>Tone.Sequence</a\n\t\t\t\t>) simplify scheduling events along the Transport. Each class\n\t\t\t\tabstracts away calls to\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/Transport.schedule\"\n\t\t\t\t\t>Transport.schedule</a\n\t\t\t\t>\n\t\t\t\tor\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/Transport.scheduleRepeat\"\n\t\t\t\t\t>scheduleRepeat</a\n\t\t\t\t>\n\t\t\t\tand lets you create precise, rhythmic events which are\n\t\t\t\tstartable, stoppable and loopable. (note that ToneEvent was\n\t\t\t\tcalled\n\t\t\t\t<a href=\"https://tonejs.github.io/docs/latest/classes/Event\"\n\t\t\t\t\t>Event</a\n\t\t\t\t>\n\t\t\t\tbefore Tone.js 14.x)\n\t\t\t</div>\n\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\t/**\n\t\t\t * KICK\n\t\t\t */\n\t\t\tconst kick = new Tone.MembraneSynth({\n\t\t\t\tenvelope: {\n\t\t\t\t\tsustain: 0,\n\t\t\t\t\tattack: 0.02,\n\t\t\t\t\tdecay: 0.8,\n\t\t\t\t},\n\t\t\t\toctaves: 10,\n\t\t\t\tpitchDecay: 0.01,\n\t\t\t}).toDestination();\n\n\t\t\tconst kickPart = new Tone.Loop((time) => {\n\t\t\t\tkick.triggerAttackRelease(\"C2\", \"8n\", time);\n\t\t\t}, \"2n\").start(0);\n\n\t\t\t/**\n\t\t\t * SNARE\n\t\t\t */\n\t\t\tconst snare = new Tone.NoiseSynth({\n\t\t\t\tvolume: -10,\n\t\t\t\tenvelope: {\n\t\t\t\t\tattack: 0.001,\n\t\t\t\t\tdecay: 0.2,\n\t\t\t\t\tsustain: 0,\n\t\t\t\t},\n\t\t\t}).toDestination();\n\n\t\t\tconst snarePart = new Tone.Loop((time) => {\n\t\t\t\tsnare.triggerAttack(time);\n\t\t\t}, \"2n\").start(\"4n\");\n\n\t\t\t/**\n\t\t\t * PIANO\n\t\t\t */\n\t\t\tconst keys = new Tone.PolySynth(Tone.Synth, {\n\t\t\t\tvolume: -8,\n\t\t\t\toscillator: {\n\t\t\t\t\tpartials: [1, 2, 1],\n\t\t\t\t},\n\t\t\t}).toDestination();\n\n\t\t\tconst cChord = [\"C4\", \"E4\", \"G4\", \"B4\"];\n\t\t\tconst dChord = [\"D4\", \"F4\", \"A4\", \"C5\"];\n\t\t\tconst gChord = [\"B3\", \"D4\", \"E4\", \"A4\"];\n\n\t\t\tconst pianoPart = new Tone.Part(\n\t\t\t\t(time, chord) => {\n\t\t\t\t\tkeys.triggerAttackRelease(chord, \"8n\", time);\n\t\t\t\t},\n\t\t\t\t[\n\t\t\t\t\t[\"0:0:2\", cChord],\n\t\t\t\t\t[\"0:1\", cChord],\n\t\t\t\t\t[\"0:1:3\", dChord],\n\t\t\t\t\t[\"0:2:2\", cChord],\n\t\t\t\t\t[\"0:3\", cChord],\n\t\t\t\t\t[\"0:3:2\", gChord],\n\t\t\t\t]\n\t\t\t).start(\"2m\");\n\n\t\t\tpianoPart.loop = true;\n\t\t\tpianoPart.loopEnd = \"1m\";\n\t\t\tpianoPart.humanize = true;\n\n\t\t\t/**\n\t\t\t * BASS\n\t\t\t */\n\t\t\tconst bass = new Tone.MonoSynth({\n\t\t\t\tvolume: -10,\n\t\t\t\tenvelope: {\n\t\t\t\t\tattack: 0.1,\n\t\t\t\t\tdecay: 0.3,\n\t\t\t\t\trelease: 2,\n\t\t\t\t},\n\t\t\t\tfilterEnvelope: {\n\t\t\t\t\tattack: 0.001,\n\t\t\t\t\tdecay: 0.01,\n\t\t\t\t\tsustain: 0.5,\n\t\t\t\t\tbaseFrequency: 200,\n\t\t\t\t\toctaves: 2.6,\n\t\t\t\t},\n\t\t\t}).toDestination();\n\n\t\t\tconst bassPart = new Tone.Sequence(\n\t\t\t\t(time, note) => {\n\t\t\t\t\tbass.triggerAttackRelease(note, \"16n\", time);\n\t\t\t\t},\n\t\t\t\t[\"C2\", [\"C3\", [\"C3\", \"D2\"]], \"E2\", [\"D2\", \"A1\"]],\n\t\t\t\t\"4n\"\n\t\t\t).start(0);\n\n\t\t\tbassPart.probability = 0.9;\n\n\t\t\t// set the transport\n\t\t\tTone.Transport.bpm.value = 90;\n\n\t\t\tdrawer()\n\t\t\t\t.add({\n\t\t\t\t\tname: \"Kick\",\n\t\t\t\t\ttone: kick,\n\t\t\t\t\topen: false,\n\t\t\t\t})\n\t\t\t\t.add({\n\t\t\t\t\tname: \"Snare\",\n\t\t\t\t\ttone: snare,\n\t\t\t\t\topen: false,\n\t\t\t\t})\n\t\t\t\t.add({\n\t\t\t\t\tname: \"Bass\",\n\t\t\t\t\ttone: bass,\n\t\t\t\t\topen: false,\n\t\t\t\t})\n\t\t\t\t.add({\n\t\t\t\t\tname: \"Keys\",\n\t\t\t\t\ttone: keys,\n\t\t\t\t\topen: false,\n\t\t\t\t});\n\n\t\t\t// bind the interface\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"start\", (e) => Tone.Transport.start());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"stop\", (e) => Tone.Transport.stop());\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/fmSynth.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>FMSynth</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<tone-example label=\"FMSynth\">\n\t\t\t<div slot=\"explanation\">\n\t\t\t\t<a href=\"https://tonejs.github.io/docs/latest/classes/FMSynth\"\n\t\t\t\t\t>Tone.FMSynth</a\n\t\t\t\t>\n\t\t\t\tis composed of two\n\t\t\t\t<a href=\"https://tonejs.github.io/docs/latest/classes/Synth\"\n\t\t\t\t\t>Tone.Synths</a\n\t\t\t\t>\n\t\t\t\twhere one Tone.Synth modulates the frequency of a second\n\t\t\t\tTone.Synth.\n\t\t\t</div>\n\n\t\t\t<div id=\"content\"></div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\tconst synth = new Tone.FMSynth({\n\t\t\t\tmodulationIndex: 12.22,\n\t\t\t\tenvelope: {\n\t\t\t\t\tattack: 0.01,\n\t\t\t\t\tdecay: 0.2,\n\t\t\t\t},\n\t\t\t\tmodulation: {\n\t\t\t\t\ttype: \"square\",\n\t\t\t\t},\n\t\t\t\tmodulationEnvelope: {\n\t\t\t\t\tattack: 0.2,\n\t\t\t\t\tdecay: 0.01,\n\t\t\t\t},\n\t\t\t}).toDestination();\n\n\t\t\tpiano({\n\t\t\t\ttone: synth,\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t\tnoteon: (note) => synth.triggerAttack(note.name),\n\t\t\t\tnoteoff: (note) => synth.triggerRelease(),\n\t\t\t});\n\n\t\t\tui({\n\t\t\t\ttone: synth,\n\t\t\t\tname: \"FMSynth\",\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t});\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/funkyShape.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n\t<title>VISUALIZING ENVELOPES</title>\n\n\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\">\n\t<link rel=\"icon\" type=\"image/png\" sizes=\"174x174\" href=\"./favicon.png\">\n\n\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.js\"></script>\n\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t<link href=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\" rel=\"stylesheet\"/>\n\t<script src=\"../build/Tone.js\"></script>\n\t<script src=\"./js/tone-ui.js\"></script>\n\t<script src=\"./js/components.js\"></script>\n</head>\n<body>\n\t<tone-example label=\"Tone with p5.js\">\n\t\t<div slot=\"explanation\">\n\t\t\tAccess the envelopes current value to synchronize visuals. This sketch uses <a href=\"https://p5js.org\" target=\"_blank\">p5.js</a> for canvas rendering.\n\t\t\t<br><br>\n\t\t\tExample by <a href=\"https://github.com/polyrhythmatic\">polyrhythmatic</a>\n\t\t</div>\n\n\t\t<div id=\"content\">\n\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t</div>\n\t</tone-example>\n\n\t<script type=\"text/javascript\">\n\t\tnew p5((p5) => {\n\t\t\t\n\t\t\tp5.setup = () => {\n\t\t\t\t// create a canvas width and height of the screen\n\t\t\t\t// document.querySelector('canvas')\n\t\t\t\tp5.createCanvas(300, 300);\n\t\t\t\t// no fill\n\t\t\t\tp5.fill(255);\n\t\t\t\tp5.strokeWeight(1);\n\t\t\t\tp5.rectMode(p5.CENTER);\n\t\t\t};\n\n\t\t\tlet phase = 0;\n\n\t\t\tp5.draw = () => {\n\t\t\t\tp5.background(255);\n\t\t\t\tp5.stroke(0);\n\t\t\t\t// drawing the kick wave at the bottom\n\t\t\t\t// it is composed of a simple sine wave that\n\t\t\t\t// changes in height with the kick envelope\n\t\t\t\tfor (let i = 0; i < p5.width; i++) {\n\t\t\t\t\t// scaling kickEnvelope value by 200 \n\t\t\t\t\t// since default is 0-1\n\t\t\t\t\tconst kickValue = kickEnvelope.value * 200;\n\t\t\t\t\t// multiplying this value to scale the sine wave \n\t\t\t\t\t// depending on x position\n\t\t\t\t\tconst yDot = Math.sin((i / 60) + phase) * kickValue;\n\t\t\t\t\tp5.point(i, p5.height -150 + yDot);\n\t\t\t\t}\n\t\t\t\t// increasing phase means that the kick wave will \n\t\t\t\t// not be standing and looks more dynamic\n\t\t\t\tphase += 1;\n\t\t\t\t// updating circle and square positions with \n\t\t\t\t// bass envelop visualizer\n\t\t\t\tconst bassRadius = p5.height * bassEnvelope.value;\n\t\t\t\tp5.stroke(\"red\");\n\t\t\t\tconst bassX = p5.noise(p5.millis() / 1000) * p5.width;\n\t\t\t\tconst bassY = p5.noise(phase / 100) * p5.height;\n\t\t\t\tp5.ellipse(bassX, bassY, bassRadius, bassRadius);\n\t\t\t\t\n\t\t\t\t// beep envelope viz\n\t\t\t\tconst beepX = p5.noise(p5.millis() / 500) * p5.width;\n\t\t\t\tconst beepY = p5.noise(phase / 50) * p5.height;\n\t\t\t\tconst beepSize = p5.height * bleepEnvelope.value;\n\t\t\t\tp5.stroke(\"green\");\n\t\t\t\tp5.rect(beepX, beepY, beepSize, beepSize);\n\t\t\t};\n\t\t}, document.querySelector(\"#content\"));\n\n\t\t// filtering the hi-hats a bit\n\t\t// to make them sound nicer\n\t\tconst lowPass = new Tone.Filter({\n\t\t\tfrequency: 14000,\n\t\t}).toDestination();\n\n\t\t// we can make our own hi hats with \n\t\t// the noise synth and a sharp filter envelope\n\t\tconst openHiHat = new Tone.NoiseSynth({\n\t\t\tvolume: -10,\n\t\t\tenvelope: {\n\t\t\t\tattack: 0.01,\n\t\t\t\tdecay: 0.3\n\t\t\t},\n\t\t}).connect(lowPass);\n\n\t\tconst openHiHatPart = new Tone.Part(((time) => {\n\t\t\topenHiHat.triggerAttack(time);\n\t\t}), [{ \"8n\": 2 }, { \"8n\": 6 }]).start(0);\n\n\t\tconst closedHiHat = new Tone.NoiseSynth({\n\t\t\tvolume: -10,\n\t\t\tenvelope: {\n\t\t\t\tattack: 0.01,\n\t\t\t\tdecay: 0.15\n\t\t\t},\n\t\t}).connect(lowPass);\n\n\t\tconst closedHatPart = new Tone.Part(((time) => {\n\t\t\tclosedHiHat.triggerAttack(time);\n\t\t}), [0, { \"16n\": 1 }, { \"8n\": 1 }, { \"8n\": 3 }, { \"8n\": 4 }, { \"8n\": 5 }, { \"8n\": 7 }, { \"8n\": 8 }]).start(0);\n\n\t\t// BASS\n\t\tconst bassEnvelope = new Tone.AmplitudeEnvelope({\n\t\t\tattack: 0.01,\n\t\t\tdecay: 0.2,\n\t\t\tsustain: 0,\n\t\t}).toDestination();\n\n\t\tconst bassFilter = new Tone.Filter({\n\t\t\tfrequency: 600,\n\t\t\tQ: 8\n\t\t});\n\n\t\tconst bass = new Tone.PulseOscillator(\"A2\", 0.4).chain(bassFilter, bassEnvelope);\n\t\tbass.start();\n\n\t\tconst bassPart = new Tone.Part(((time, note) => {\n\t\t\tbass.frequency.setValueAtTime(note, time);\n\t\t\tbassEnvelope.triggerAttack(time);\n\t\t}), [[\"0:0\", \"A1\"],\n\t\t\t[\"0:2\", \"G1\"],\n\t\t\t[\"0:2:2\", \"C2\"],\n\t\t\t[\"0:3:2\", \"A1\"]]).start(0);\n\n\t\t// BLEEP\n\t\tconst bleepEnvelope = new Tone.AmplitudeEnvelope({\n\t\t\tattack: 0.01,\n\t\t\tdecay: 0.4,\n\t\t\tsustain: 0,\n\t\t}).toDestination();\n\n\t\tconst bleep = new Tone.Oscillator(\"A4\").connect(bleepEnvelope);\n\t\tbleep.start();\n\n\t\tconst bleepLoop = new Tone.Loop(((time) => {\n\t\t\tbleepEnvelope.triggerAttack(time);\n\t\t}), \"2n\").start(0);\n\n\t\t// KICK\n\t\tconst kickEnvelope = new Tone.AmplitudeEnvelope({\n\t\t\tattack: 0.01,\n\t\t\tdecay: 0.2,\n\t\t\tsustain: 0,\n\t\t}).toDestination();\n\n\t\tconst kick = new Tone.Oscillator(\"A2\").connect(kickEnvelope).start();\n\n\t\tconst kickSnapEnv = new Tone.FrequencyEnvelope({\n\t\t\tattack: 0.005,\n\t\t\tdecay: 0.01,\n\t\t\tsustain: 0,\n\t\t\tbaseFrequency: \"A2\",\n\t\t\toctaves: 2.7\n\t\t}).connect(kick.frequency);\n\n\t\tconst kickPart = new Tone.Part(((time) => {\n\t\t\tkickEnvelope.triggerAttack(time);\n\t\t\tkickSnapEnv.triggerAttack(time);\n\t\t}), [\"0\", \"0:0:3\", \"0:2:0\", \"0:3:1\"]).start(0);\n\n\t\t// TRANSPORT\n\t\tTone.Transport.loopStart = 0;\n\t\tTone.Transport.loopEnd = \"1:0\";\n\t\tTone.Transport.loop = true;\n\n\t\t// bind the interface\n\t\tdocument.querySelector(\"tone-play-toggle\").addEventListener(\"start\", e => Tone.Transport.start());\n\t\tdocument.querySelector(\"tone-play-toggle\").addEventListener(\"stop\", e => Tone.Transport.stop());\n\n\t\tconst controls = drawer({\n\t\t\tparent: document.body,\n\t\t\topen: false,\n\t\t});\n\n\t\tcontrols.folder({\n\t\t\tname: \"Hihat\"\n\t\t}).add({\n\t\t\ttone: lowPass,\n\t\t}).add({\n\t\t\tname: \"Open Hihat\",\n\t\t\ttone: openHiHat,\n\t\t}).add({\n\t\t\tname: \"Closed Hihat\",\n\t\t\ttone: closedHiHat\n\t\t});\n\n\t\tcontrols.folder({\n\t\t\tname: \"Bass\"\n\t\t}).add({\n\t\t\ttone: bassFilter,\n\t\t}).add({\n\t\t\ttone: bass,\n\t\t}).add({\n\t\t\ttone: bassEnvelope\n\t\t});\n\n\t\tcontrols.folder({\n\t\t\tname: \"Bleep\"\n\t\t}).add({\n\t\t\ttone: bleep,\n\t\t}).add({\n\t\t\ttone: bleepEnvelope,\n\t\t});\n\n\t\tcontrols.folder({\n\t\t\tname: \"Kick\"\n\t\t}).add({\n\t\t\ttone: kick,\n\t\t}).add({\n\t\t\ttone: kickEnvelope,\n\t\t}).add({\n\t\t\ttone: kickSnapEnv,\n\t\t});\n\t</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "examples/grainPlayer.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Grain Player</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<style type=\"text/css\">\n\t\t\ttone-play-toggle,\n\t\t\ttone-fft {\n\t\t\t\tmargin-bottom: 10px;\n\t\t\t}\n\n\t\t\ttone-fft {\n\t\t\t\tbackground-color: black;\n\t\t\t\theight: 40px;\n\t\t\t\twidth: 100%;\n\t\t\t\tborder-radius: 20px;\n\t\t\t}\n\t\t</style>\n\t\t<tone-example label=\"Granular Synthesis\">\n\t\t\t<div slot=\"explanation\">\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/GrainPlayer\"\n\t\t\t\t\t>Tone.GrainPlayer</a\n\t\t\t\t>\n\t\t\t\tuses\n\t\t\t\t<a href=\"https://en.wikipedia.org/wiki/Granular_synthesis\"\n\t\t\t\t\t>granular synthesis</a\n\t\t\t\t>\n\t\t\t\tto enable you to adjust pitch and playback rate independently.\n\t\t\t\tThe grainSize is the amount of time each small chunk of audio is\n\t\t\t\tplayed for and the overlap is the amount of crossfading\n\t\t\t\ttransition time between successive grains.\n\t\t\t</div>\n\n\t\t\t<tone-loader></tone-loader>\n\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\t// the player\n\t\t\tconst player = new Tone.GrainPlayer({\n\t\t\t\turl: \"https://tonejs.github.io/audio/berklee/arpeggio3crazy.mp3\",\n\t\t\t\tloop: true,\n\t\t\t\tgrainSize: 0.1,\n\t\t\t\toverlap: 0.05,\n\t\t\t}).toDestination();\n\n\t\t\tui({\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t\ttone: player,\n\t\t\t});\n\n\t\t\t// bind the interface\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"start\", () => player.start());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"stop\", () => player.stop());\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n\t<title>Tone.js Examples</title>\n\n\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\">\n\t<link rel=\"icon\" type=\"image/png\" sizes=\"174x174\" href=\"./favicon.png\">\n\n\t<script type=\"text/javascript\">\n\t\t// forward links with hashes\n\t\tif (window.location.hash !== \"\") {\n\t\t\tconst hash = window.location.hash.substring(1);\n\t\t\twindow.location.href = window.location.pathname+hash;\n\t\t}\n\t</script>\n\n\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t<link href=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\" rel=\"stylesheet\"/>\n\t<script src=\"../build/Tone.js\"></script>\n\t<script src=\"./js/tone-ui.js\"></script>\n\t<script src=\"./js/components.js\"></script>\n</head>\n<body>\n\t<tone-example label=\"Examples\" open>\n\t\t<div slot=\"explanation\">\n\t\t\tChoose an example from the side panel.\n\t\t</div>\n\t</tone-example>\n\n</body>\n</html>\n"
  },
  {
    "path": "examples/js/ExampleList.json",
    "content": "{\n\t\"Basic\" : {\n\t\t\"Oscillators\" : \"oscillator\",\n\t\t\"Envelope\" : \"envelope\",\n\t\t\"Noise\" : \"noises\",\n\t\t\"Player\" : \"player\",\n\t\t\"Microphone\" : \"mic\",\n\t\t\"Mixer\" : \"mixer\"\n\t},\n\t\"Instruments\" : {\n\t\t\"Synth\" : \"simpleSynth\",\n\t\t\"MonoSynth\" : \"monoSynth\",\n\t\t\"FMSynth\" : \"fmSynth\",\n\t\t\"AMSynth\" : \"amSynth\",\n\t\t\"PolySynth\" : \"polySynth\",\n\t\t\"FatOscillator\" : \"jump\",\n\t\t\"MetalSynth\" : \"bembe\",\n\t\t\"Granular Synthesis\" : \"grainPlayer\",\n\t\t\"Sampler\" : \"sampler\"\n\t},\n\t\"Effects\" : {\n\t\t\"LFO Effects\" : \"lfoEffects\",\n\t\t\"PingPongDelay\" : \"pingPongDelay\",\n\t\t\"Buses\" : \"buses\",\n\t\t\"Reverb\" : \"reverb\",\n\t\t\"Spatialization\" : \"spatialPanner\",\n\t\t\"PitchShift\" : \"pitchShift\",\n\t\t\"ReverseDelay\" : \"reverseDelay\"\n\t},\n\t\"Sequencing / Timing\" : {\n\t\t\"Step Sequencer\" : \"stepSequencer\",\n\t\t\"Events\" : \"events\",\n\t\t\"Play Along\" : \"shiny\",\n\t\t\"Quantization\" : \"quantization\",\n\t\t\"Playback Rate\" : \"pianoPhase\",\n\t\t\"Transport Sync\" : \"daw\"\n\t},\n\t\"Signals\" : {\n\t\t\"Control Voltage\" : \"signal\",\n\t\t\"Ramping Values\" : \"rampTo\"\n\t},\n\t\"Visualization\" : {\n\t\t\"Animation Sync\" : \"animationSync\",\n\t\t\"Envelopes\" : \"funkyShape\",\n\t\t\"Analysis\" : \"analysis\",\n\t\t\"Meter\" : \"meter\"\n\t},\n\t\"Misc\" : {\n\t\t\"Offline Rendering\" : \"offline\"\n\t}\n}\n"
  },
  {
    "path": "examples/js/components.js",
    "content": "/******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// define __esModule on exports\n/******/ \t__webpack_require__.r = function(exports) {\n/******/ \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n/******/ \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n/******/ \t\t}\n/******/ \t\tObject.defineProperty(exports, '__esModule', { value: true });\n/******/ \t};\n/******/\n/******/ \t// create a fake namespace object\n/******/ \t// mode & 1: value is a module id, require it\n/******/ \t// mode & 2: merge all properties of value into the ns\n/******/ \t// mode & 4: return value when already ns object\n/******/ \t// mode & 8|1: behave like require\n/******/ \t__webpack_require__.t = function(value, mode) {\n/******/ \t\tif(mode & 1) value = __webpack_require__(value);\n/******/ \t\tif(mode & 8) return value;\n/******/ \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n/******/ \t\tvar ns = Object.create(null);\n/******/ \t\t__webpack_require__.r(ns);\n/******/ \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n/******/ \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n/******/ \t\treturn ns;\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = \"./src/components/index.ts\");\n/******/ })\n/************************************************************************/\n/******/ ({\n\n/***/ \"./node_modules/@material/animation/util.js\":\n/*!**************************************************!*\\\n  !*** ./node_modules/@material/animation/util.js ***!\n  \\**************************************************/\n/*! exports provided: getCorrectPropertyName, getCorrectEventName */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"getCorrectPropertyName\\\", function() { return getCorrectPropertyName; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"getCorrectEventName\\\", function() { return getCorrectEventName; });\\n/**\\n * @license\\n * Copyright 2016 Google Inc.\\n *\\n * Permission is hereby granted, free of charge, to any person obtaining a copy\\n * of this software and associated documentation files (the \\\"Software\\\"), to deal\\n * in the Software without restriction, including without limitation the rights\\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\\n * copies of the Software, and to permit persons to whom the Software is\\n * furnished to do so, subject to the following conditions:\\n *\\n * The above copyright notice and this permission notice shall be included in\\n * all copies or substantial portions of the Software.\\n *\\n * THE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\\n * THE SOFTWARE.\\n */\\nvar cssPropertyNameMap = {\\n    animation: {\\n        prefixed: '-webkit-animation',\\n        standard: 'animation',\\n    },\\n    transform: {\\n        prefixed: '-webkit-transform',\\n        standard: 'transform',\\n    },\\n    transition: {\\n        prefixed: '-webkit-transition',\\n        standard: 'transition',\\n    },\\n};\\nvar jsEventTypeMap = {\\n    animationend: {\\n        cssProperty: 'animation',\\n        prefixed: 'webkitAnimationEnd',\\n        standard: 'animationend',\\n    },\\n    animationiteration: {\\n        cssProperty: 'animation',\\n        prefixed: 'webkitAnimationIteration',\\n        standard: 'animationiteration',\\n    },\\n    animationstart: {\\n        cssProperty: 'animation',\\n        prefixed: 'webkitAnimationStart',\\n        standard: 'animationstart',\\n    },\\n    transitionend: {\\n        cssProperty: 'transition',\\n        prefixed: 'webkitTransitionEnd',\\n        standard: 'transitionend',\\n    },\\n};\\nfunction isWindow(windowObj) {\\n    return Boolean(windowObj.document) && typeof windowObj.document.createElement === 'function';\\n}\\nfunction getCorrectPropertyName(windowObj, cssProperty) {\\n    if (isWindow(windowObj) && cssProperty in cssPropertyNameMap) {\\n        var el = windowObj.document.createElement('div');\\n        var _a = cssPropertyNameMap[cssProperty], standard = _a.standard, prefixed = _a.prefixed;\\n        var isStandard = standard in el.style;\\n        return isStandard ? standard : prefixed;\\n    }\\n    return cssProperty;\\n}\\nfunction getCorrectEventName(windowObj, eventType) {\\n    if (isWindow(windowObj) && eventType in jsEventTypeMap) {\\n        var el = windowObj.document.createElement('div');\\n        var _a = jsEventTypeMap[eventType], standard = _a.standard, prefixed = _a.prefixed, cssProperty = _a.cssProperty;\\n        var isStandard = cssProperty in el.style;\\n        return isStandard ? standard : prefixed;\\n    }\\n    return eventType;\\n}\\n//# sourceMappingURL=util.js.map\\n\\n//# sourceURL=webpack:///./node_modules/@material/animation/util.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/@material/base/foundation.js\":\n/*!***************************************************!*\\\n  !*** ./node_modules/@material/base/foundation.js ***!\n  \\***************************************************/\n/*! exports provided: MDCFoundation, default */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"MDCFoundation\\\", function() { return MDCFoundation; });\\n/**\\n * @license\\n * Copyright 2016 Google Inc.\\n *\\n * Permission is hereby granted, free of charge, to any person obtaining a copy\\n * of this software and associated documentation files (the \\\"Software\\\"), to deal\\n * in the Software without restriction, including without limitation the rights\\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\\n * copies of the Software, and to permit persons to whom the Software is\\n * furnished to do so, subject to the following conditions:\\n *\\n * The above copyright notice and this permission notice shall be included in\\n * all copies or substantial portions of the Software.\\n *\\n * THE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\\n * THE SOFTWARE.\\n */\\nvar MDCFoundation = /** @class */ (function () {\\n    function MDCFoundation(adapter) {\\n        if (adapter === void 0) { adapter = {}; }\\n        this.adapter = adapter;\\n    }\\n    Object.defineProperty(MDCFoundation, \\\"cssClasses\\\", {\\n        get: function () {\\n            // Classes extending MDCFoundation should implement this method to return an object which exports every\\n            // CSS class the foundation class needs as a property. e.g. {ACTIVE: 'mdc-component--active'}\\n            return {};\\n        },\\n        enumerable: true,\\n        configurable: true\\n    });\\n    Object.defineProperty(MDCFoundation, \\\"strings\\\", {\\n        get: function () {\\n            // Classes extending MDCFoundation should implement this method to return an object which exports all\\n            // semantic strings as constants. e.g. {ARIA_ROLE: 'tablist'}\\n            return {};\\n        },\\n        enumerable: true,\\n        configurable: true\\n    });\\n    Object.defineProperty(MDCFoundation, \\\"numbers\\\", {\\n        get: function () {\\n            // Classes extending MDCFoundation should implement this method to return an object which exports all\\n            // of its semantic numbers as constants. e.g. {ANIMATION_DELAY_MS: 350}\\n            return {};\\n        },\\n        enumerable: true,\\n        configurable: true\\n    });\\n    Object.defineProperty(MDCFoundation, \\\"defaultAdapter\\\", {\\n        get: function () {\\n            // Classes extending MDCFoundation may choose to implement this getter in order to provide a convenient\\n            // way of viewing the necessary methods of an adapter. In the future, this could also be used for adapter\\n            // validation.\\n            return {};\\n        },\\n        enumerable: true,\\n        configurable: true\\n    });\\n    MDCFoundation.prototype.init = function () {\\n        // Subclasses should override this method to perform initialization routines (registering events, etc.)\\n    };\\n    MDCFoundation.prototype.destroy = function () {\\n        // Subclasses should override this method to perform de-initialization routines (de-registering events, etc.)\\n    };\\n    return MDCFoundation;\\n}());\\n\\n// tslint:disable-next-line:no-default-export Needed for backward compatibility with MDC Web v0.44.0 and earlier.\\n/* harmony default export */ __webpack_exports__[\\\"default\\\"] = (MDCFoundation);\\n//# sourceMappingURL=foundation.js.map\\n\\n//# sourceURL=webpack:///./node_modules/@material/base/foundation.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/@material/dom/events.js\":\n/*!**********************************************!*\\\n  !*** ./node_modules/@material/dom/events.js ***!\n  \\**********************************************/\n/*! exports provided: applyPassive */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"applyPassive\\\", function() { return applyPassive; });\\n/**\\n * @license\\n * Copyright 2019 Google Inc.\\n *\\n * Permission is hereby granted, free of charge, to any person obtaining a copy\\n * of this software and associated documentation files (the \\\"Software\\\"), to deal\\n * in the Software without restriction, including without limitation the rights\\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\\n * copies of the Software, and to permit persons to whom the Software is\\n * furnished to do so, subject to the following conditions:\\n *\\n * The above copyright notice and this permission notice shall be included in\\n * all copies or substantial portions of the Software.\\n *\\n * THE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\\n * THE SOFTWARE.\\n */\\n/**\\n * Determine whether the current browser supports passive event listeners, and\\n * if so, use them.\\n */\\nfunction applyPassive(globalObj) {\\n    if (globalObj === void 0) { globalObj = window; }\\n    return supportsPassiveOption(globalObj) ?\\n        { passive: true } :\\n        false;\\n}\\nfunction supportsPassiveOption(globalObj) {\\n    if (globalObj === void 0) { globalObj = window; }\\n    // See\\n    // https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener\\n    var passiveSupported = false;\\n    try {\\n        var options = {\\n            // This function will be called when the browser\\n            // attempts to access the passive property.\\n            get passive() {\\n                passiveSupported = true;\\n                return false;\\n            }\\n        };\\n        var handler = function () { };\\n        globalObj.document.addEventListener('test', handler, options);\\n        globalObj.document.removeEventListener('test', handler, options);\\n    }\\n    catch (err) {\\n        passiveSupported = false;\\n    }\\n    return passiveSupported;\\n}\\n//# sourceMappingURL=events.js.map\\n\\n//# sourceURL=webpack:///./node_modules/@material/dom/events.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/@material/dom/ponyfill.js\":\n/*!************************************************!*\\\n  !*** ./node_modules/@material/dom/ponyfill.js ***!\n  \\************************************************/\n/*! exports provided: closest, matches, estimateScrollWidth */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"closest\\\", function() { return closest; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"matches\\\", function() { return matches; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"estimateScrollWidth\\\", function() { return estimateScrollWidth; });\\n/**\\n * @license\\n * Copyright 2018 Google Inc.\\n *\\n * Permission is hereby granted, free of charge, to any person obtaining a copy\\n * of this software and associated documentation files (the \\\"Software\\\"), to deal\\n * in the Software without restriction, including without limitation the rights\\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\\n * copies of the Software, and to permit persons to whom the Software is\\n * furnished to do so, subject to the following conditions:\\n *\\n * The above copyright notice and this permission notice shall be included in\\n * all copies or substantial portions of the Software.\\n *\\n * THE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\\n * THE SOFTWARE.\\n */\\n/**\\n * @fileoverview A \\\"ponyfill\\\" is a polyfill that doesn't modify the global prototype chain.\\n * This makes ponyfills safer than traditional polyfills, especially for libraries like MDC.\\n */\\nfunction closest(element, selector) {\\n    if (element.closest) {\\n        return element.closest(selector);\\n    }\\n    var el = element;\\n    while (el) {\\n        if (matches(el, selector)) {\\n            return el;\\n        }\\n        el = el.parentElement;\\n    }\\n    return null;\\n}\\nfunction matches(element, selector) {\\n    var nativeMatches = element.matches\\n        || element.webkitMatchesSelector\\n        || element.msMatchesSelector;\\n    return nativeMatches.call(element, selector);\\n}\\n/**\\n * Used to compute the estimated scroll width of elements. When an element is\\n * hidden due to display: none; being applied to a parent element, the width is\\n * returned as 0. However, the element will have a true width once no longer\\n * inside a display: none context. This method computes an estimated width when\\n * the element is hidden or returns the true width when the element is visble.\\n * @param {Element} element the element whose width to estimate\\n */\\nfunction estimateScrollWidth(element) {\\n    // Check the offsetParent. If the element inherits display: none from any\\n    // parent, the offsetParent property will be null (see\\n    // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent).\\n    // This check ensures we only clone the node when necessary.\\n    var htmlEl = element;\\n    if (htmlEl.offsetParent !== null) {\\n        return htmlEl.scrollWidth;\\n    }\\n    var clone = htmlEl.cloneNode(true);\\n    clone.style.setProperty('position', 'absolute');\\n    clone.style.setProperty('transform', 'translate(-9999px, -9999px)');\\n    document.documentElement.appendChild(clone);\\n    var scrollWidth = clone.scrollWidth;\\n    document.documentElement.removeChild(clone);\\n    return scrollWidth;\\n}\\n//# sourceMappingURL=ponyfill.js.map\\n\\n//# sourceURL=webpack:///./node_modules/@material/dom/ponyfill.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/@material/mwc-base/base-element.js\":\n/*!*********************************************************!*\\\n  !*** ./node_modules/@material/mwc-base/base-element.js ***!\n  \\*********************************************************/\n/*! exports provided: addHasRemoveClass, BaseElement */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"BaseElement\\\", function() { return BaseElement; });\\n/* harmony import */ var lit_element__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\n/* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./utils.js */ \\\"./node_modules/@material/mwc-base/utils.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"addHasRemoveClass\\\", function() { return _utils_js__WEBPACK_IMPORTED_MODULE_1__[\\\"addHasRemoveClass\\\"]; });\\n\\n/**\\n@license\\nCopyright 2018 Google Inc. All Rights Reserved.\\n\\nLicensed under the Apache License, Version 2.0 (the \\\"License\\\");\\nyou may not use this file except in compliance with the License.\\nYou may obtain a copy of the License at\\n\\n    http://www.apache.org/licenses/LICENSE-2.0\\n\\nUnless required by applicable law or agreed to in writing, software\\ndistributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\nSee the License for the specific language governing permissions and\\nlimitations under the License.\\n*/\\n\\n\\n/** @soyCompatible */\\nclass BaseElement extends lit_element__WEBPACK_IMPORTED_MODULE_0__[\\\"LitElement\\\"] {\\n    /**\\n     * Create and attach the MDC Foundation to the instance\\n     */\\n    createFoundation() {\\n        if (this.mdcFoundation !== undefined) {\\n            this.mdcFoundation.destroy();\\n        }\\n        if (this.mdcFoundationClass) {\\n            this.mdcFoundation = new this.mdcFoundationClass(this.createAdapter());\\n            this.mdcFoundation.init();\\n        }\\n    }\\n    firstUpdated() {\\n        this.createFoundation();\\n    }\\n}\\n//# sourceMappingURL=base-element.js.map\\n\\n//# sourceURL=webpack:///./node_modules/@material/mwc-base/base-element.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/@material/mwc-base/form-element.js\":\n/*!*********************************************************!*\\\n  !*** ./node_modules/@material/mwc-base/form-element.js ***!\n  \\*********************************************************/\n/*! exports provided: addHasRemoveClass, BaseElement, FormElement */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"FormElement\\\", function() { return FormElement; });\\n/* harmony import */ var _base_element_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./base-element.js */ \\\"./node_modules/@material/mwc-base/base-element.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"addHasRemoveClass\\\", function() { return _base_element_js__WEBPACK_IMPORTED_MODULE_0__[\\\"addHasRemoveClass\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"BaseElement\\\", function() { return _base_element_js__WEBPACK_IMPORTED_MODULE_0__[\\\"BaseElement\\\"]; });\\n\\n/**\\n@license\\nCopyright 2018 Google Inc. All Rights Reserved.\\n\\nLicensed under the Apache License, Version 2.0 (the \\\"License\\\");\\nyou may not use this file except in compliance with the License.\\nYou may obtain a copy of the License at\\n\\n    http://www.apache.org/licenses/LICENSE-2.0\\n\\nUnless required by applicable law or agreed to in writing, software\\ndistributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\nSee the License for the specific language governing permissions and\\nlimitations under the License.\\n*/\\n\\n\\n/** @soyCompatible */\\nclass FormElement extends _base_element_js__WEBPACK_IMPORTED_MODULE_0__[\\\"BaseElement\\\"] {\\n    createRenderRoot() {\\n        return this.attachShadow({ mode: 'open', delegatesFocus: true });\\n    }\\n    click() {\\n        if (this.formElement) {\\n            this.formElement.focus();\\n            this.formElement.click();\\n        }\\n    }\\n    setAriaLabel(label) {\\n        if (this.formElement) {\\n            this.formElement.setAttribute('aria-label', label);\\n        }\\n    }\\n    firstUpdated() {\\n        super.firstUpdated();\\n        this.mdcRoot.addEventListener('change', (e) => {\\n            this.dispatchEvent(new Event('change', e));\\n        });\\n    }\\n}\\n//# sourceMappingURL=form-element.js.map\\n\\n//# sourceURL=webpack:///./node_modules/@material/mwc-base/form-element.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/@material/mwc-base/observer.js\":\n/*!*****************************************************!*\\\n  !*** ./node_modules/@material/mwc-base/observer.js ***!\n  \\*****************************************************/\n/*! exports provided: observer */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"observer\\\", function() { return observer; });\\nconst observer = (observer) => \\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\\n(proto, propName) => {\\n    // if we haven't wrapped `updated` in this class, do so\\n    if (!proto.constructor._observers) {\\n        proto.constructor._observers = new Map();\\n        const userUpdated = proto.updated;\\n        proto.updated = function (changedProperties) {\\n            userUpdated.call(this, changedProperties);\\n            changedProperties.forEach((v, k) => {\\n                const observer = this.constructor._observers.get(k);\\n                if (observer !== undefined) {\\n                    observer.call(this, this[k], v);\\n                }\\n            });\\n        };\\n        // clone any existing observers (superclasses)\\n    }\\n    else if (!proto.constructor.hasOwnProperty('_observers')) {\\n        const observers = proto.constructor._observers;\\n        proto.constructor._observers = new Map();\\n        observers.forEach(\\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n        (v, k) => proto.constructor._observers.set(k, v));\\n    }\\n    // set this method\\n    proto.constructor._observers.set(propName, observer);\\n};\\n//# sourceMappingURL=observer.js.map\\n\\n//# sourceURL=webpack:///./node_modules/@material/mwc-base/observer.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/@material/mwc-base/utils.js\":\n/*!**************************************************!*\\\n  !*** ./node_modules/@material/mwc-base/utils.js ***!\n  \\**************************************************/\n/*! exports provided: isNodeElement, findAssignedElement, addHasRemoveClass, supportsPassiveEventListener, deepActiveElementPath, doesElementContainFocus */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"isNodeElement\\\", function() { return isNodeElement; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"findAssignedElement\\\", function() { return findAssignedElement; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"addHasRemoveClass\\\", function() { return addHasRemoveClass; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"supportsPassiveEventListener\\\", function() { return supportsPassiveEventListener; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"deepActiveElementPath\\\", function() { return deepActiveElementPath; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"doesElementContainFocus\\\", function() { return doesElementContainFocus; });\\n/* harmony import */ var _material_dom_ponyfill__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @material/dom/ponyfill */ \\\"./node_modules/@material/dom/ponyfill.js\\\");\\n/**\\n@license\\nCopyright 2018 Google Inc. All Rights Reserved.\\n\\nLicensed under the Apache License, Version 2.0 (the \\\"License\\\");\\nyou may not use this file except in compliance with the License.\\nYou may obtain a copy of the License at\\n\\n    http://www.apache.org/licenses/LICENSE-2.0\\n\\nUnless required by applicable law or agreed to in writing, software\\ndistributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\nSee the License for the specific language governing permissions and\\nlimitations under the License.\\n*/\\n/**\\n * Return an element assigned to a given slot that matches the given selector\\n */\\n\\n/**\\n * Determines whether a node is an element.\\n *\\n * @param node Node to check\\n */\\nconst isNodeElement = (node) => {\\n    return node.nodeType === Node.ELEMENT_NODE;\\n};\\nfunction findAssignedElement(slot, selector) {\\n    for (const node of slot.assignedNodes({ flatten: true })) {\\n        if (isNodeElement(node)) {\\n            const el = node;\\n            if (Object(_material_dom_ponyfill__WEBPACK_IMPORTED_MODULE_0__[\\\"matches\\\"])(el, selector)) {\\n                return el;\\n            }\\n        }\\n    }\\n    return null;\\n}\\nfunction addHasRemoveClass(element) {\\n    return {\\n        addClass: (className) => {\\n            element.classList.add(className);\\n        },\\n        removeClass: (className) => {\\n            element.classList.remove(className);\\n        },\\n        hasClass: (className) => element.classList.contains(className),\\n    };\\n}\\nlet supportsPassive = false;\\nconst fn = () => { };\\nconst optionsBlock = {\\n    get passive() {\\n        supportsPassive = true;\\n        return false;\\n    }\\n};\\ndocument.addEventListener('x', fn, optionsBlock);\\ndocument.removeEventListener('x', fn);\\n/**\\n * Do event listeners suport the `passive` option?\\n */\\nconst supportsPassiveEventListener = supportsPassive;\\nconst deepActiveElementPath = (doc = window.document) => {\\n    let activeElement = doc.activeElement;\\n    const path = [];\\n    if (!activeElement) {\\n        return path;\\n    }\\n    while (activeElement) {\\n        path.push(activeElement);\\n        if (activeElement.shadowRoot) {\\n            activeElement = activeElement.shadowRoot.activeElement;\\n        }\\n        else {\\n            break;\\n        }\\n    }\\n    return path;\\n};\\nconst doesElementContainFocus = (element) => {\\n    const activePath = deepActiveElementPath();\\n    if (!activePath.length) {\\n        return false;\\n    }\\n    const deepActiveElement = activePath[activePath.length - 1];\\n    const focusEv = new Event('check-if-focused', { bubbles: true, composed: true });\\n    let composedPath = [];\\n    const listener = (ev) => {\\n        composedPath = ev.composedPath();\\n    };\\n    document.body.addEventListener('check-if-focused', listener);\\n    deepActiveElement.dispatchEvent(focusEv);\\n    document.body.removeEventListener('check-if-focused', listener);\\n    return composedPath.indexOf(element) !== -1;\\n};\\n//# sourceMappingURL=utils.js.map\\n\\n//# sourceURL=webpack:///./node_modules/@material/mwc-base/utils.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/@material/mwc-slider/mwc-slider-base.js\":\n/*!**************************************************************!*\\\n  !*** ./node_modules/@material/mwc-slider/mwc-slider-base.js ***!\n  \\**************************************************************/\n/*! exports provided: SliderBase */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"SliderBase\\\", function() { return SliderBase; });\\n/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ \\\"./node_modules/tslib/tslib.es6.js\\\");\\n/* harmony import */ var _material_dom_events_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @material/dom/events.js */ \\\"./node_modules/@material/dom/events.js\\\");\\n/* harmony import */ var _material_mwc_base_form_element_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @material/mwc-base/form-element.js */ \\\"./node_modules/@material/mwc-base/form-element.js\\\");\\n/* harmony import */ var _material_mwc_base_observer_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @material/mwc-base/observer.js */ \\\"./node_modules/@material/mwc-base/observer.js\\\");\\n/* harmony import */ var _material_slider_foundation_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @material/slider/foundation.js */ \\\"./node_modules/@material/slider/foundation.js\\\");\\n/* harmony import */ var lit_element__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\n/* harmony import */ var lit_html_directives_class_map_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! lit-html/directives/class-map.js */ \\\"./node_modules/lit-html/directives/class-map.js\\\");\\n/* harmony import */ var lit_html_directives_style_map_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! lit-html/directives/style-map.js */ \\\"./node_modules/lit-html/directives/style-map.js\\\");\\n\\n/**\\n@license\\nCopyright 2018 Google Inc. All Rights Reserved.\\n\\nLicensed under the Apache License, Version 2.0 (the \\\"License\\\");\\nyou may not use this file except in compliance with the License.\\nYou may obtain a copy of the License at\\n\\n    http://www.apache.org/licenses/LICENSE-2.0\\n\\nUnless required by applicable law or agreed to in writing, software\\ndistributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\nSee the License for the specific language governing permissions and\\nlimitations under the License.\\n*/\\n\\n\\n\\n\\n\\n\\n\\nconst INPUT_EVENT = 'input';\\nconst CHANGE_EVENT = 'change';\\nclass SliderBase extends _material_mwc_base_form_element_js__WEBPACK_IMPORTED_MODULE_2__[\\\"FormElement\\\"] {\\n    constructor() {\\n        super(...arguments);\\n        this.mdcFoundationClass = _material_slider_foundation_js__WEBPACK_IMPORTED_MODULE_4__[\\\"default\\\"];\\n        this.min = 0;\\n        this.max = 100;\\n        this._value = 0;\\n        this.step = 0;\\n        this.disabled = false;\\n        this.pin = false;\\n        this.markers = false;\\n        this.pinMarkerText = '';\\n        this.trackMarkerContainerStyles = {};\\n        this.thumbContainerStyles = {};\\n        this.trackStyles = {};\\n        this.isFoundationDestroyed = false;\\n    }\\n    set value(value) {\\n        if (this.mdcFoundation) {\\n            this.mdcFoundation.setValue(value);\\n        }\\n        this._value = value;\\n        this.requestUpdate('value', value);\\n    }\\n    get value() {\\n        if (this.mdcFoundation) {\\n            return this.mdcFoundation.getValue();\\n        }\\n        else {\\n            return this._value;\\n        }\\n    }\\n    // TODO(sorvell) #css: needs a default width\\n    render() {\\n        const isDiscrete = this.step !== 0;\\n        const hostClassInfo = {\\n            'mdc-slider--discrete': isDiscrete,\\n            'mdc-slider--display-markers': this.markers && isDiscrete,\\n        };\\n        let markersTemplate = '';\\n        if (isDiscrete && this.markers) {\\n            markersTemplate = lit_element__WEBPACK_IMPORTED_MODULE_5__[\\\"html\\\"] `\\n        <div\\n            class=\\\"mdc-slider__track-marker-container\\\"\\n            style=\\\"${Object(lit_html_directives_style_map_js__WEBPACK_IMPORTED_MODULE_7__[\\\"styleMap\\\"])(this.trackMarkerContainerStyles)}\\\">\\n        </div>`;\\n        }\\n        let pin = '';\\n        if (this.pin) {\\n            pin = lit_element__WEBPACK_IMPORTED_MODULE_5__[\\\"html\\\"] `\\n      <div class=\\\"mdc-slider__pin\\\">\\n        <span class=\\\"mdc-slider__pin-value-marker\\\">${this.pinMarkerText}</span>\\n      </div>`;\\n        }\\n        return lit_element__WEBPACK_IMPORTED_MODULE_5__[\\\"html\\\"] `\\n      <div class=\\\"mdc-slider ${Object(lit_html_directives_class_map_js__WEBPACK_IMPORTED_MODULE_6__[\\\"classMap\\\"])(hostClassInfo)}\\\"\\n           tabindex=\\\"0\\\" role=\\\"slider\\\"\\n           aria-valuemin=\\\"${this.min}\\\" aria-valuemax=\\\"${this.max}\\\"\\n           aria-valuenow=\\\"${this.value}\\\"\\n           aria-disabled=\\\"${this.disabled.toString()}\\\"\\n           data-step=\\\"${this.step}\\\"\\n           @mousedown=${this.layout}\\n           @touchstart=${this.layout}>\\n        <div class=\\\"mdc-slider__track-container\\\">\\n          <div\\n              class=\\\"mdc-slider__track\\\"\\n              style=\\\"${Object(lit_html_directives_style_map_js__WEBPACK_IMPORTED_MODULE_7__[\\\"styleMap\\\"])(this.trackStyles)}\\\">\\n          </div>\\n          ${markersTemplate}\\n        </div>\\n        <div\\n            class=\\\"mdc-slider__thumb-container\\\"\\n            style=\\\"${Object(lit_html_directives_style_map_js__WEBPACK_IMPORTED_MODULE_7__[\\\"styleMap\\\"])(this.thumbContainerStyles)}\\\">\\n          <!-- TODO: use cache() directive -->\\n          ${pin}\\n          <svg class=\\\"mdc-slider__thumb\\\" width=\\\"21\\\" height=\\\"21\\\">\\n            <circle cx=\\\"10.5\\\" cy=\\\"10.5\\\" r=\\\"7.875\\\"></circle>\\n          </svg>\\n        <div class=\\\"mdc-slider__focus-ring\\\"></div>\\n      </div>\\n    </div>`;\\n    }\\n    connectedCallback() {\\n        super.connectedCallback();\\n        if (this.mdcRoot && this.isFoundationDestroyed) {\\n            this.isFoundationDestroyed = false;\\n            this.mdcFoundation.init();\\n        }\\n    }\\n    updated(changed) {\\n        const minChanged = changed.has('min');\\n        const maxChanged = changed.has('max');\\n        if (minChanged && maxChanged) {\\n            if (this.max < this.mdcFoundation.getMin()) {\\n                // for when min is above previous max\\n                this.mdcFoundation.setMin(this.min);\\n                this.mdcFoundation.setMax(this.max);\\n            }\\n            else {\\n                // for when max is below previous min\\n                this.mdcFoundation.setMax(this.max);\\n                this.mdcFoundation.setMin(this.min);\\n            }\\n        }\\n        else if (minChanged) {\\n            this.mdcFoundation.setMin(this.min);\\n        }\\n        else if (maxChanged) {\\n            this.mdcFoundation.setMax(this.max);\\n        }\\n        super.updated(changed);\\n    }\\n    disconnectedCallback() {\\n        super.disconnectedCallback();\\n        this.isFoundationDestroyed = true;\\n        this.mdcFoundation.destroy();\\n    }\\n    createAdapter() {\\n        return Object.assign(Object.assign({}, Object(_material_mwc_base_form_element_js__WEBPACK_IMPORTED_MODULE_2__[\\\"addHasRemoveClass\\\"])(this.mdcRoot)), { getAttribute: (name) => this.mdcRoot.getAttribute(name), setAttribute: (name, value) => this.mdcRoot.setAttribute(name, value), removeAttribute: (name) => this.mdcRoot.removeAttribute(name), computeBoundingRect: () => {\\n                const rect = this.mdcRoot.getBoundingClientRect();\\n                const myRect = {\\n                    bottom: rect.bottom,\\n                    height: rect.height,\\n                    left: rect.left + window.pageXOffset,\\n                    right: rect.right,\\n                    top: rect.top,\\n                    width: rect.width,\\n                };\\n                return myRect;\\n            }, getTabIndex: () => this.mdcRoot.tabIndex, registerInteractionHandler: (type, handler) => {\\n                const init = type === 'touchstart' ? Object(_material_dom_events_js__WEBPACK_IMPORTED_MODULE_1__[\\\"applyPassive\\\"])() : undefined;\\n                this.mdcRoot.addEventListener(type, handler, init);\\n            }, deregisterInteractionHandler: (type, handler) => this.mdcRoot.removeEventListener(type, handler), registerThumbContainerInteractionHandler: (type, handler) => {\\n                const init = type === 'touchstart' ? Object(_material_dom_events_js__WEBPACK_IMPORTED_MODULE_1__[\\\"applyPassive\\\"])() : undefined;\\n                this.thumbContainer.addEventListener(type, handler, init);\\n            }, deregisterThumbContainerInteractionHandler: (type, handler) => this.thumbContainer.removeEventListener(type, handler), registerBodyInteractionHandler: (type, handler) => document.body.addEventListener(type, handler), deregisterBodyInteractionHandler: (type, handler) => document.body.removeEventListener(type, handler), registerResizeHandler: (handler) => window.addEventListener('resize', handler, Object(_material_dom_events_js__WEBPACK_IMPORTED_MODULE_1__[\\\"applyPassive\\\"])()), deregisterResizeHandler: (handler) => window.removeEventListener('resize', handler), notifyInput: () => {\\n                const value = this.mdcFoundation.getValue();\\n                if (value !== this._value) {\\n                    this.value = value;\\n                    this.dispatchEvent(new CustomEvent(INPUT_EVENT, { detail: this, composed: true, bubbles: true, cancelable: true }));\\n                }\\n            }, notifyChange: () => {\\n                this.dispatchEvent(new CustomEvent(CHANGE_EVENT, { detail: this, composed: true, bubbles: true, cancelable: true }));\\n            }, setThumbContainerStyleProperty: (propertyName, value) => {\\n                this.thumbContainerStyles[propertyName] = value;\\n                this.requestUpdate();\\n            }, setTrackStyleProperty: (propertyName, value) => {\\n                this.trackStyles[propertyName] = value;\\n                this.requestUpdate();\\n            }, setMarkerValue: (value) => this.pinMarkerText =\\n                value.toLocaleString(), setTrackMarkers: (step, max, min) => {\\n                // calculates the CSS for the notches on the slider. Taken from\\n                // https://github.com/material-components/material-components-web/blob/8f851d9ed2f75dc8b8956d15b3bb2619e59fa8a9/packages/mdc-slider/component.ts#L122\\n                const stepStr = step.toLocaleString();\\n                const maxStr = max.toLocaleString();\\n                const minStr = min.toLocaleString();\\n                // keep calculation in css for better rounding/subpixel behavior\\n                const markerAmount = `((${maxStr} - ${minStr}) / ${stepStr})`;\\n                const markerWidth = '2px';\\n                const markerBkgdImage = `linear-gradient(to right, currentColor ${markerWidth}, transparent 0)`;\\n                const markerBkgdLayout = `0 center / calc((100% - ${markerWidth}) / ${markerAmount}) 100% repeat-x`;\\n                const markerBkgdShorthand = `${markerBkgdImage} ${markerBkgdLayout}`;\\n                this.trackMarkerContainerStyles['background'] = markerBkgdShorthand;\\n                this.requestUpdate();\\n            }, isRTL: () => getComputedStyle(this.mdcRoot).direction === 'rtl' });\\n    }\\n    resetFoundation() {\\n        if (this.mdcFoundation) {\\n            this.mdcFoundation.destroy();\\n            this.mdcFoundation.init();\\n        }\\n    }\\n    async firstUpdated() {\\n        await super.firstUpdated();\\n        this.mdcFoundation.setValue(this._value);\\n    }\\n    /**\\n     * Layout is called on mousedown / touchstart as the dragging animations of\\n     * slider are calculated based off of the bounding rect which can change\\n     * between interactions with this component, and this is the only location\\n     * in the foundation that udpates the rects. e.g. scrolling horizontally\\n     * causes adverse effects on the bounding rect vs mouse drag / touchmove\\n     * location.\\n     */\\n    layout() {\\n        this.mdcFoundation.layout();\\n    }\\n}\\nObject(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__decorate\\\"])([\\n    Object(lit_element__WEBPACK_IMPORTED_MODULE_5__[\\\"query\\\"])('.mdc-slider')\\n], SliderBase.prototype, \\\"mdcRoot\\\", void 0);\\nObject(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__decorate\\\"])([\\n    Object(lit_element__WEBPACK_IMPORTED_MODULE_5__[\\\"query\\\"])('.mdc-slider')\\n], SliderBase.prototype, \\\"formElement\\\", void 0);\\nObject(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__decorate\\\"])([\\n    Object(lit_element__WEBPACK_IMPORTED_MODULE_5__[\\\"query\\\"])('.mdc-slider__thumb-container')\\n], SliderBase.prototype, \\\"thumbContainer\\\", void 0);\\nObject(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__decorate\\\"])([\\n    Object(lit_element__WEBPACK_IMPORTED_MODULE_5__[\\\"query\\\"])('.mdc-slider__pin-value-marker')\\n], SliderBase.prototype, \\\"pinMarker\\\", void 0);\\nObject(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__decorate\\\"])([\\n    Object(lit_element__WEBPACK_IMPORTED_MODULE_5__[\\\"property\\\"])({ type: Number })\\n], SliderBase.prototype, \\\"min\\\", void 0);\\nObject(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__decorate\\\"])([\\n    Object(lit_element__WEBPACK_IMPORTED_MODULE_5__[\\\"property\\\"])({ type: Number })\\n], SliderBase.prototype, \\\"max\\\", void 0);\\nObject(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__decorate\\\"])([\\n    Object(lit_element__WEBPACK_IMPORTED_MODULE_5__[\\\"property\\\"])({ type: Number })\\n], SliderBase.prototype, \\\"value\\\", null);\\nObject(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__decorate\\\"])([\\n    Object(lit_element__WEBPACK_IMPORTED_MODULE_5__[\\\"property\\\"])({ type: Number }),\\n    Object(_material_mwc_base_observer_js__WEBPACK_IMPORTED_MODULE_3__[\\\"observer\\\"])(function (value, old) {\\n        const oldWasDiscrete = old !== 0;\\n        const newIsDiscrete = value !== 0;\\n        if (oldWasDiscrete !== newIsDiscrete) {\\n            this.resetFoundation();\\n        }\\n        this.mdcFoundation.setStep(value);\\n    })\\n], SliderBase.prototype, \\\"step\\\", void 0);\\nObject(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__decorate\\\"])([\\n    Object(lit_element__WEBPACK_IMPORTED_MODULE_5__[\\\"property\\\"])({ type: Boolean, reflect: true }),\\n    Object(_material_mwc_base_observer_js__WEBPACK_IMPORTED_MODULE_3__[\\\"observer\\\"])(function (value) {\\n        this.mdcFoundation.setDisabled(value);\\n    })\\n], SliderBase.prototype, \\\"disabled\\\", void 0);\\nObject(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__decorate\\\"])([\\n    Object(lit_element__WEBPACK_IMPORTED_MODULE_5__[\\\"property\\\"])({ type: Boolean, reflect: true })\\n], SliderBase.prototype, \\\"pin\\\", void 0);\\nObject(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__decorate\\\"])([\\n    Object(lit_element__WEBPACK_IMPORTED_MODULE_5__[\\\"property\\\"])({ type: Boolean, reflect: true }),\\n    Object(_material_mwc_base_observer_js__WEBPACK_IMPORTED_MODULE_3__[\\\"observer\\\"])(function () {\\n        this.mdcFoundation.setupTrackMarker();\\n    })\\n], SliderBase.prototype, \\\"markers\\\", void 0);\\nObject(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__decorate\\\"])([\\n    Object(lit_element__WEBPACK_IMPORTED_MODULE_5__[\\\"property\\\"])({ type: String })\\n], SliderBase.prototype, \\\"pinMarkerText\\\", void 0);\\nObject(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__decorate\\\"])([\\n    Object(lit_element__WEBPACK_IMPORTED_MODULE_5__[\\\"property\\\"])({ type: Object })\\n], SliderBase.prototype, \\\"trackMarkerContainerStyles\\\", void 0);\\nObject(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__decorate\\\"])([\\n    Object(lit_element__WEBPACK_IMPORTED_MODULE_5__[\\\"property\\\"])({ type: Object })\\n], SliderBase.prototype, \\\"thumbContainerStyles\\\", void 0);\\nObject(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__decorate\\\"])([\\n    Object(lit_element__WEBPACK_IMPORTED_MODULE_5__[\\\"property\\\"])({ type: Object })\\n], SliderBase.prototype, \\\"trackStyles\\\", void 0);\\nObject(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__decorate\\\"])([\\n    Object(lit_element__WEBPACK_IMPORTED_MODULE_5__[\\\"eventOptions\\\"])({ capture: true, passive: true })\\n], SliderBase.prototype, \\\"layout\\\", null);\\n//# sourceMappingURL=mwc-slider-base.js.map\\n\\n//# sourceURL=webpack:///./node_modules/@material/mwc-slider/mwc-slider-base.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/@material/mwc-slider/mwc-slider-css.js\":\n/*!*************************************************************!*\\\n  !*** ./node_modules/@material/mwc-slider/mwc-slider-css.js ***!\n  \\*************************************************************/\n/*! exports provided: style */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"style\\\", function() { return style; });\\n/* harmony import */ var lit_element__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\n/**\\n@license\\nCopyright 2018 Google Inc. All Rights Reserved.\\n\\nLicensed under the Apache License, Version 2.0 (the \\\"License\\\");\\nyou may not use this file except in compliance with the License.\\nYou may obtain a copy of the License at\\n\\n    http://www.apache.org/licenses/LICENSE-2.0\\n\\nUnless required by applicable law or agreed to in writing, software\\ndistributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\nSee the License for the specific language governing permissions and\\nlimitations under the License.\\n*/\\n\\nconst style = lit_element__WEBPACK_IMPORTED_MODULE_0__[\\\"css\\\"] `@keyframes mdc-slider-emphasize{0%{animation-timing-function:ease-out}50%{animation-timing-function:ease-in;transform:scale(0.85)}100%{transform:scale(0.571)}}.mdc-slider{position:relative;width:100%;height:48px;cursor:pointer;touch-action:pan-x;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mdc-slider:not(.mdc-slider--disabled) .mdc-slider__track{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}.mdc-slider:not(.mdc-slider--disabled) .mdc-slider__track-container::after{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786);opacity:.26}.mdc-slider:not(.mdc-slider--disabled) .mdc-slider__track-marker-container{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}.mdc-slider:not(.mdc-slider--disabled) .mdc-slider__thumb{fill:#018786;fill:var(--mdc-theme-secondary, #018786);stroke:#018786;stroke:var(--mdc-theme-secondary, #018786)}.mdc-slider:not(.mdc-slider--disabled) .mdc-slider__focus-ring{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}.mdc-slider:not(.mdc-slider--disabled) .mdc-slider__pin{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}.mdc-slider:not(.mdc-slider--disabled) .mdc-slider__pin{color:#fff;color:var(--mdc-theme-text-primary-on-dark, white)}.mdc-slider--disable-touch-action{touch-action:none}.mdc-slider--disabled{cursor:auto}.mdc-slider--disabled .mdc-slider__track{background-color:#9a9a9a}.mdc-slider--disabled .mdc-slider__track-container::after{background-color:#9a9a9a;opacity:.26}.mdc-slider--disabled .mdc-slider__track-marker-container{background-color:#9a9a9a}.mdc-slider--disabled .mdc-slider__thumb{fill:#9a9a9a;stroke:#9a9a9a}.mdc-slider--disabled .mdc-slider__thumb{stroke:#fff;stroke:var(--mdc-slider-bg-color-behind-component, white)}.mdc-slider:focus{outline:none}.mdc-slider__track-container{position:absolute;top:50%;width:100%;height:2px;overflow:hidden}.mdc-slider__track-container::after{position:absolute;top:0;left:0;display:block;width:100%;height:100%;content:\\\"\\\"}.mdc-slider__track{position:absolute;width:100%;height:100%;transform-origin:left top;will-change:transform}.mdc-slider[dir=rtl] .mdc-slider__track,[dir=rtl] .mdc-slider .mdc-slider__track{transform-origin:right top}.mdc-slider__track-marker-container{display:flex;margin-right:0;margin-left:-1px;visibility:hidden}.mdc-slider[dir=rtl] .mdc-slider__track-marker-container,[dir=rtl] .mdc-slider .mdc-slider__track-marker-container{margin-right:-1px;margin-left:0}.mdc-slider__track-marker-container::after{display:block;width:2px;height:2px;content:\\\"\\\"}.mdc-slider__track-marker{flex:1}.mdc-slider__track-marker::after{display:block;width:2px;height:2px;content:\\\"\\\"}.mdc-slider__track-marker:first-child::after{width:3px}.mdc-slider__thumb-container{position:absolute;top:15px;left:0;width:21px;height:100%;user-select:none;will-change:transform}.mdc-slider__thumb{position:absolute;top:0;left:0;transform:scale(0.571);stroke-width:3.5;transition:transform 100ms ease-out,fill 100ms ease-out,stroke 100ms ease-out}.mdc-slider__focus-ring{width:21px;height:21px;border-radius:50%;opacity:0;transition:transform 266.67ms ease-out,opacity 266.67ms ease-out,background-color 266.67ms ease-out}.mdc-slider__pin{display:flex;position:absolute;top:0;left:0;align-items:center;justify-content:center;width:26px;height:26px;margin-top:-2px;margin-left:-2px;transform:rotate(-45deg) scale(0) translate(0, 0);border-radius:50% 50% 50% 0%;z-index:1;transition:transform 100ms ease-out}.mdc-slider__pin-value-marker{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:0.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);transform:rotate(45deg)}.mdc-slider--active .mdc-slider__thumb{transform:scale3d(1, 1, 1)}.mdc-slider--focus .mdc-slider__thumb{animation:mdc-slider-emphasize 266.67ms linear}.mdc-slider--focus .mdc-slider__focus-ring{transform:scale3d(1.55, 1.55, 1.55);opacity:.25}.mdc-slider--in-transit .mdc-slider__thumb{transition-delay:140ms}.mdc-slider--in-transit .mdc-slider__thumb-container,.mdc-slider--in-transit .mdc-slider__track,.mdc-slider:focus:not(.mdc-slider--active) .mdc-slider__thumb-container,.mdc-slider:focus:not(.mdc-slider--active) .mdc-slider__track{transition:transform 80ms ease}.mdc-slider--discrete.mdc-slider--active .mdc-slider__thumb{transform:scale(calc(12 / 21))}.mdc-slider--discrete.mdc-slider--active .mdc-slider__pin{transform:rotate(-45deg) scale(1) translate(19px, -20px)}.mdc-slider--discrete.mdc-slider--focus .mdc-slider__thumb{animation:none}.mdc-slider--discrete.mdc-slider--display-markers .mdc-slider__track-marker-container{visibility:visible}:host{display:inline-block;min-width:120px;outline:none}`;\\n//# sourceMappingURL=mwc-slider-css.js.map\\n\\n//# sourceURL=webpack:///./node_modules/@material/mwc-slider/mwc-slider-css.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/@material/mwc-slider/mwc-slider.js\":\n/*!*********************************************************!*\\\n  !*** ./node_modules/@material/mwc-slider/mwc-slider.js ***!\n  \\*********************************************************/\n/*! exports provided: Slider */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"Slider\\\", function() { return Slider; });\\n/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ \\\"./node_modules/tslib/tslib.es6.js\\\");\\n/* harmony import */ var lit_element__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\n/* harmony import */ var _mwc_slider_base_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./mwc-slider-base.js */ \\\"./node_modules/@material/mwc-slider/mwc-slider-base.js\\\");\\n/* harmony import */ var _mwc_slider_css_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./mwc-slider-css.js */ \\\"./node_modules/@material/mwc-slider/mwc-slider-css.js\\\");\\n\\n/**\\n@license\\nCopyright 2018 Google Inc. All Rights Reserved.\\n\\nLicensed under the Apache License, Version 2.0 (the \\\"License\\\");\\nyou may not use this file except in compliance with the License.\\nYou may obtain a copy of the License at\\n\\n    http://www.apache.org/licenses/LICENSE-2.0\\n\\nUnless required by applicable law or agreed to in writing, software\\ndistributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\nSee the License for the specific language governing permissions and\\nlimitations under the License.\\n*/\\n\\n\\n\\nlet Slider = class Slider extends _mwc_slider_base_js__WEBPACK_IMPORTED_MODULE_2__[\\\"SliderBase\\\"] {\\n};\\nSlider.styles = _mwc_slider_css_js__WEBPACK_IMPORTED_MODULE_3__[\\\"style\\\"];\\nSlider = Object(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__decorate\\\"])([\\n    Object(lit_element__WEBPACK_IMPORTED_MODULE_1__[\\\"customElement\\\"])('mwc-slider')\\n], Slider);\\n\\n//# sourceMappingURL=mwc-slider.js.map\\n\\n//# sourceURL=webpack:///./node_modules/@material/mwc-slider/mwc-slider.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/@material/slider/constants.js\":\n/*!****************************************************!*\\\n  !*** ./node_modules/@material/slider/constants.js ***!\n  \\****************************************************/\n/*! exports provided: cssClasses, strings, numbers */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"cssClasses\\\", function() { return cssClasses; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"strings\\\", function() { return strings; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"numbers\\\", function() { return numbers; });\\n/**\\n * @license\\n * Copyright 2017 Google Inc.\\n *\\n * Permission is hereby granted, free of charge, to any person obtaining a copy\\n * of this software and associated documentation files (the \\\"Software\\\"), to deal\\n * in the Software without restriction, including without limitation the rights\\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\\n * copies of the Software, and to permit persons to whom the Software is\\n * furnished to do so, subject to the following conditions:\\n *\\n * The above copyright notice and this permission notice shall be included in\\n * all copies or substantial portions of the Software.\\n *\\n * THE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\\n * THE SOFTWARE.\\n */\\nvar cssClasses = {\\n    ACTIVE: 'mdc-slider--active',\\n    DISABLED: 'mdc-slider--disabled',\\n    DISCRETE: 'mdc-slider--discrete',\\n    FOCUS: 'mdc-slider--focus',\\n    HAS_TRACK_MARKER: 'mdc-slider--display-markers',\\n    IN_TRANSIT: 'mdc-slider--in-transit',\\n    IS_DISCRETE: 'mdc-slider--discrete',\\n    DISABLE_TOUCH_ACTION: 'mdc-slider--disable-touch-action',\\n};\\nvar strings = {\\n    ARIA_DISABLED: 'aria-disabled',\\n    ARIA_VALUEMAX: 'aria-valuemax',\\n    ARIA_VALUEMIN: 'aria-valuemin',\\n    ARIA_VALUENOW: 'aria-valuenow',\\n    CHANGE_EVENT: 'MDCSlider:change',\\n    INPUT_EVENT: 'MDCSlider:input',\\n    PIN_VALUE_MARKER_SELECTOR: '.mdc-slider__pin-value-marker',\\n    STEP_DATA_ATTR: 'data-step',\\n    THUMB_CONTAINER_SELECTOR: '.mdc-slider__thumb-container',\\n    TRACK_MARKER_CONTAINER_SELECTOR: '.mdc-slider__track-marker-container',\\n    TRACK_SELECTOR: '.mdc-slider__track',\\n};\\nvar numbers = {\\n    PAGE_FACTOR: 4,\\n};\\n\\n//# sourceMappingURL=constants.js.map\\n\\n//# sourceURL=webpack:///./node_modules/@material/slider/constants.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/@material/slider/foundation.js\":\n/*!*****************************************************!*\\\n  !*** ./node_modules/@material/slider/foundation.js ***!\n  \\*****************************************************/\n/*! exports provided: MDCSliderFoundation, default */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"MDCSliderFoundation\\\", function() { return MDCSliderFoundation; });\\n/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ \\\"./node_modules/tslib/tslib.es6.js\\\");\\n/* harmony import */ var _material_animation_util__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @material/animation/util */ \\\"./node_modules/@material/animation/util.js\\\");\\n/* harmony import */ var _material_base_foundation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @material/base/foundation */ \\\"./node_modules/@material/base/foundation.js\\\");\\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./constants */ \\\"./node_modules/@material/slider/constants.js\\\");\\n/**\\n * @license\\n * Copyright 2017 Google Inc.\\n *\\n * Permission is hereby granted, free of charge, to any person obtaining a copy\\n * of this software and associated documentation files (the \\\"Software\\\"), to deal\\n * in the Software without restriction, including without limitation the rights\\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\\n * copies of the Software, and to permit persons to whom the Software is\\n * furnished to do so, subject to the following conditions:\\n *\\n * The above copyright notice and this permission notice shall be included in\\n * all copies or substantial portions of the Software.\\n *\\n * THE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\\n * THE SOFTWARE.\\n */\\n\\n\\n\\n\\n// Accessing `window` without a `typeof` check will throw on Node environments.\\nvar hasWindow = typeof window !== 'undefined';\\nvar hasPointerEventSupport = hasWindow && !!window.PointerEvent;\\nvar DOWN_EVENTS = hasPointerEventSupport ? ['pointerdown'] : ['mousedown', 'touchstart'];\\nvar UP_EVENTS = hasPointerEventSupport ? ['pointerup'] : ['mouseup', 'touchend'];\\nvar MOVE_EVENT_MAP = {\\n    mousedown: 'mousemove',\\n    pointerdown: 'pointermove',\\n    touchstart: 'touchmove',\\n};\\nvar KEY_IDS = {\\n    ARROW_DOWN: 'ArrowDown',\\n    ARROW_LEFT: 'ArrowLeft',\\n    ARROW_RIGHT: 'ArrowRight',\\n    ARROW_UP: 'ArrowUp',\\n    END: 'End',\\n    HOME: 'Home',\\n    PAGE_DOWN: 'PageDown',\\n    PAGE_UP: 'PageUp',\\n};\\nvar MDCSliderFoundation = /** @class */ (function (_super) {\\n    Object(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__extends\\\"])(MDCSliderFoundation, _super);\\n    function MDCSliderFoundation(adapter) {\\n        var _this = _super.call(this, Object(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__assign\\\"])(Object(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__assign\\\"])({}, MDCSliderFoundation.defaultAdapter), adapter)) || this;\\n        /**\\n         * We set this to NaN since we want it to be a number, but we can't use '0' or\\n         * '-1' because those could be valid tabindices set by the client code.\\n         */\\n        _this.savedTabIndex_ = NaN;\\n        _this.active_ = false;\\n        _this.inTransit_ = false;\\n        _this.isDiscrete_ = false;\\n        _this.hasTrackMarker_ = false;\\n        _this.handlingThumbTargetEvt_ = false;\\n        _this.min_ = 0;\\n        _this.max_ = 100;\\n        _this.step_ = 0;\\n        _this.value_ = 0;\\n        _this.disabled_ = false;\\n        _this.preventFocusState_ = false;\\n        _this.thumbContainerPointerHandler_ = function () { return _this.handlingThumbTargetEvt_ =\\n            true; };\\n        _this.interactionStartHandler_ = function (evt) {\\n            return _this.handleDown_(evt);\\n        };\\n        _this.keydownHandler_ = function (evt) { return _this.handleKeydown_(evt); };\\n        _this.focusHandler_ = function () { return _this.handleFocus_(); };\\n        _this.blurHandler_ = function () { return _this.handleBlur_(); };\\n        _this.resizeHandler_ = function () { return _this.layout(); };\\n        return _this;\\n    }\\n    Object.defineProperty(MDCSliderFoundation, \\\"cssClasses\\\", {\\n        get: function () {\\n            return _constants__WEBPACK_IMPORTED_MODULE_3__[\\\"cssClasses\\\"];\\n        },\\n        enumerable: true,\\n        configurable: true\\n    });\\n    Object.defineProperty(MDCSliderFoundation, \\\"strings\\\", {\\n        get: function () {\\n            return _constants__WEBPACK_IMPORTED_MODULE_3__[\\\"strings\\\"];\\n        },\\n        enumerable: true,\\n        configurable: true\\n    });\\n    Object.defineProperty(MDCSliderFoundation, \\\"numbers\\\", {\\n        get: function () {\\n            return _constants__WEBPACK_IMPORTED_MODULE_3__[\\\"numbers\\\"];\\n        },\\n        enumerable: true,\\n        configurable: true\\n    });\\n    Object.defineProperty(MDCSliderFoundation, \\\"defaultAdapter\\\", {\\n        get: function () {\\n            // tslint:disable:object-literal-sort-keys Methods should be in the same\\n            // order as the adapter interface.\\n            return {\\n                hasClass: function () { return false; },\\n                addClass: function () { return undefined; },\\n                removeClass: function () { return undefined; },\\n                getAttribute: function () { return null; },\\n                setAttribute: function () { return undefined; },\\n                removeAttribute: function () { return undefined; },\\n                computeBoundingRect: function () {\\n                    return ({ top: 0, right: 0, bottom: 0, left: 0, width: 0, height: 0 });\\n                },\\n                getTabIndex: function () { return 0; },\\n                registerInteractionHandler: function () { return undefined; },\\n                deregisterInteractionHandler: function () { return undefined; },\\n                registerThumbContainerInteractionHandler: function () { return undefined; },\\n                deregisterThumbContainerInteractionHandler: function () { return undefined; },\\n                registerBodyInteractionHandler: function () { return undefined; },\\n                deregisterBodyInteractionHandler: function () { return undefined; },\\n                registerResizeHandler: function () { return undefined; },\\n                deregisterResizeHandler: function () { return undefined; },\\n                notifyInput: function () { return undefined; },\\n                notifyChange: function () { return undefined; },\\n                setThumbContainerStyleProperty: function () { return undefined; },\\n                setTrackStyleProperty: function () { return undefined; },\\n                setMarkerValue: function () { return undefined; },\\n                setTrackMarkers: function () { return undefined; },\\n                isRTL: function () { return false; },\\n            };\\n            // tslint:enable:object-literal-sort-keys\\n        },\\n        enumerable: true,\\n        configurable: true\\n    });\\n    MDCSliderFoundation.prototype.init = function () {\\n        var _this = this;\\n        this.isDiscrete_ = this.adapter.hasClass(_constants__WEBPACK_IMPORTED_MODULE_3__[\\\"cssClasses\\\"].IS_DISCRETE);\\n        this.hasTrackMarker_ = this.adapter.hasClass(_constants__WEBPACK_IMPORTED_MODULE_3__[\\\"cssClasses\\\"].HAS_TRACK_MARKER);\\n        DOWN_EVENTS.forEach(function (evtName) {\\n            _this.adapter.registerInteractionHandler(evtName, _this.interactionStartHandler_);\\n            _this.adapter.registerThumbContainerInteractionHandler(evtName, _this.thumbContainerPointerHandler_);\\n        });\\n        if (hasPointerEventSupport) {\\n            /*\\n             * When pointermove happens, if too much sliding happens, the browser\\n             * believes you are panning in the x direction and stops firing\\n             * pointermove events and supplies its own gestures. (similar to\\n             * preventing default on touchmove)\\n             */\\n            this.adapter.addClass(_constants__WEBPACK_IMPORTED_MODULE_3__[\\\"cssClasses\\\"].DISABLE_TOUCH_ACTION);\\n        }\\n        this.adapter.registerInteractionHandler('keydown', this.keydownHandler_);\\n        this.adapter.registerInteractionHandler('focus', this.focusHandler_);\\n        this.adapter.registerInteractionHandler('blur', this.blurHandler_);\\n        this.adapter.registerResizeHandler(this.resizeHandler_);\\n        this.layout();\\n        // At last step, provide a reasonable default value to discrete slider\\n        if (this.isDiscrete_ && this.getStep() === 0) {\\n            this.step_ = 1;\\n        }\\n    };\\n    MDCSliderFoundation.prototype.destroy = function () {\\n        var _this = this;\\n        DOWN_EVENTS.forEach(function (evtName) {\\n            _this.adapter.deregisterInteractionHandler(evtName, _this.interactionStartHandler_);\\n            _this.adapter.deregisterThumbContainerInteractionHandler(evtName, _this.thumbContainerPointerHandler_);\\n        });\\n        this.adapter.deregisterInteractionHandler('keydown', this.keydownHandler_);\\n        this.adapter.deregisterInteractionHandler('focus', this.focusHandler_);\\n        this.adapter.deregisterInteractionHandler('blur', this.blurHandler_);\\n        this.adapter.deregisterResizeHandler(this.resizeHandler_);\\n    };\\n    MDCSliderFoundation.prototype.setupTrackMarker = function () {\\n        if (this.isDiscrete_ && this.hasTrackMarker_ && this.getStep() !== 0) {\\n            this.adapter.setTrackMarkers(this.getStep(), this.getMax(), this.getMin());\\n        }\\n    };\\n    MDCSliderFoundation.prototype.layout = function () {\\n        this.rect_ = this.adapter.computeBoundingRect();\\n        this.updateUIForCurrentValue_();\\n    };\\n    MDCSliderFoundation.prototype.getValue = function () {\\n        return this.value_;\\n    };\\n    MDCSliderFoundation.prototype.setValue = function (value) {\\n        this.setValue_(value, false);\\n    };\\n    MDCSliderFoundation.prototype.getMax = function () {\\n        return this.max_;\\n    };\\n    MDCSliderFoundation.prototype.setMax = function (max) {\\n        if (max < this.min_) {\\n            throw new Error('Cannot set max to be less than the slider\\\\'s minimum value');\\n        }\\n        this.max_ = max;\\n        this.setValue_(this.value_, false, true);\\n        this.adapter.setAttribute(_constants__WEBPACK_IMPORTED_MODULE_3__[\\\"strings\\\"].ARIA_VALUEMAX, String(this.max_));\\n        this.setupTrackMarker();\\n    };\\n    MDCSliderFoundation.prototype.getMin = function () {\\n        return this.min_;\\n    };\\n    MDCSliderFoundation.prototype.setMin = function (min) {\\n        if (min > this.max_) {\\n            throw new Error('Cannot set min to be greater than the slider\\\\'s maximum value');\\n        }\\n        this.min_ = min;\\n        this.setValue_(this.value_, false, true);\\n        this.adapter.setAttribute(_constants__WEBPACK_IMPORTED_MODULE_3__[\\\"strings\\\"].ARIA_VALUEMIN, String(this.min_));\\n        this.setupTrackMarker();\\n    };\\n    MDCSliderFoundation.prototype.getStep = function () {\\n        return this.step_;\\n    };\\n    MDCSliderFoundation.prototype.setStep = function (step) {\\n        if (step < 0) {\\n            throw new Error('Step cannot be set to a negative number');\\n        }\\n        if (this.isDiscrete_ && (typeof (step) !== 'number' || step < 1)) {\\n            step = 1;\\n        }\\n        this.step_ = step;\\n        this.setValue_(this.value_, false, true);\\n        this.setupTrackMarker();\\n    };\\n    MDCSliderFoundation.prototype.isDisabled = function () {\\n        return this.disabled_;\\n    };\\n    MDCSliderFoundation.prototype.setDisabled = function (disabled) {\\n        this.disabled_ = disabled;\\n        this.toggleClass_(_constants__WEBPACK_IMPORTED_MODULE_3__[\\\"cssClasses\\\"].DISABLED, this.disabled_);\\n        if (this.disabled_) {\\n            this.savedTabIndex_ = this.adapter.getTabIndex();\\n            this.adapter.setAttribute(_constants__WEBPACK_IMPORTED_MODULE_3__[\\\"strings\\\"].ARIA_DISABLED, 'true');\\n            this.adapter.removeAttribute('tabindex');\\n        }\\n        else {\\n            this.adapter.removeAttribute(_constants__WEBPACK_IMPORTED_MODULE_3__[\\\"strings\\\"].ARIA_DISABLED);\\n            if (!isNaN(this.savedTabIndex_)) {\\n                this.adapter.setAttribute('tabindex', String(this.savedTabIndex_));\\n            }\\n        }\\n    };\\n    /**\\n     * Called when the user starts interacting with the slider\\n     */\\n    MDCSliderFoundation.prototype.handleDown_ = function (downEvent) {\\n        var _this = this;\\n        if (this.disabled_) {\\n            return;\\n        }\\n        this.preventFocusState_ = true;\\n        this.setInTransit_(!this.handlingThumbTargetEvt_);\\n        this.handlingThumbTargetEvt_ = false;\\n        this.setActive_(true);\\n        var moveHandler = function (moveEvent) {\\n            _this.handleMove_(moveEvent);\\n        };\\n        var moveEventType = MOVE_EVENT_MAP[downEvent.type];\\n        // Note: upHandler is [de]registered on ALL potential pointer-related\\n        // release event types, since some browsers do not always fire these\\n        // consistently in pairs. (See\\n        // https://github.com/material-components/material-components-web/issues/1192)\\n        var upHandler = function () {\\n            _this.handleUp_();\\n            _this.adapter.deregisterBodyInteractionHandler(moveEventType, moveHandler);\\n            UP_EVENTS.forEach(function (evtName) { return _this.adapter.deregisterBodyInteractionHandler(evtName, upHandler); });\\n        };\\n        this.adapter.registerBodyInteractionHandler(moveEventType, moveHandler);\\n        UP_EVENTS.forEach(function (evtName) {\\n            return _this.adapter.registerBodyInteractionHandler(evtName, upHandler);\\n        });\\n        this.setValueFromEvt_(downEvent);\\n    };\\n    /**\\n     * Called when the user moves the slider\\n     */\\n    MDCSliderFoundation.prototype.handleMove_ = function (evt) {\\n        evt.preventDefault();\\n        this.setValueFromEvt_(evt);\\n    };\\n    /**\\n     * Called when the user's interaction with the slider ends\\n     */\\n    MDCSliderFoundation.prototype.handleUp_ = function () {\\n        this.setActive_(false);\\n        this.adapter.notifyChange();\\n    };\\n    /**\\n     * Returns the clientX of the event\\n     */\\n    MDCSliderFoundation.prototype.getClientX_ = function (evt) {\\n        if (evt.targetTouches &&\\n            evt.targetTouches.length > 0) {\\n            return evt.targetTouches[0].clientX;\\n        }\\n        return evt.clientX;\\n    };\\n    /**\\n     * Sets the slider value from an event\\n     */\\n    MDCSliderFoundation.prototype.setValueFromEvt_ = function (evt) {\\n        var clientX = this.getClientX_(evt);\\n        var value = this.computeValueFromClientX_(clientX);\\n        this.setValue_(value, true);\\n    };\\n    /**\\n     * Computes the new value from the clientX position\\n     */\\n    MDCSliderFoundation.prototype.computeValueFromClientX_ = function (clientX) {\\n        var _a = this, max = _a.max_, min = _a.min_;\\n        var xPos = clientX - this.rect_.left;\\n        var pctComplete = xPos / this.rect_.width;\\n        if (this.adapter.isRTL()) {\\n            pctComplete = 1 - pctComplete;\\n        }\\n        // Fit the percentage complete between the range [min,max]\\n        // by remapping from [0, 1] to [min, min+(max-min)].\\n        return min + pctComplete * (max - min);\\n    };\\n    /**\\n     * Handles keydown events\\n     */\\n    MDCSliderFoundation.prototype.handleKeydown_ = function (evt) {\\n        var keyId = this.getKeyId_(evt);\\n        var value = this.getValueForKeyId_(keyId);\\n        if (isNaN(value)) {\\n            return;\\n        }\\n        // Prevent page from scrolling due to key presses that would normally scroll\\n        // the page\\n        evt.preventDefault();\\n        this.adapter.addClass(_constants__WEBPACK_IMPORTED_MODULE_3__[\\\"cssClasses\\\"].FOCUS);\\n        this.setValue_(value, true);\\n        this.adapter.notifyChange();\\n    };\\n    /**\\n     * Returns the computed name of the event\\n     */\\n    MDCSliderFoundation.prototype.getKeyId_ = function (kbdEvt) {\\n        if (kbdEvt.key === KEY_IDS.ARROW_LEFT || kbdEvt.keyCode === 37) {\\n            return KEY_IDS.ARROW_LEFT;\\n        }\\n        if (kbdEvt.key === KEY_IDS.ARROW_RIGHT || kbdEvt.keyCode === 39) {\\n            return KEY_IDS.ARROW_RIGHT;\\n        }\\n        if (kbdEvt.key === KEY_IDS.ARROW_UP || kbdEvt.keyCode === 38) {\\n            return KEY_IDS.ARROW_UP;\\n        }\\n        if (kbdEvt.key === KEY_IDS.ARROW_DOWN || kbdEvt.keyCode === 40) {\\n            return KEY_IDS.ARROW_DOWN;\\n        }\\n        if (kbdEvt.key === KEY_IDS.HOME || kbdEvt.keyCode === 36) {\\n            return KEY_IDS.HOME;\\n        }\\n        if (kbdEvt.key === KEY_IDS.END || kbdEvt.keyCode === 35) {\\n            return KEY_IDS.END;\\n        }\\n        if (kbdEvt.key === KEY_IDS.PAGE_UP || kbdEvt.keyCode === 33) {\\n            return KEY_IDS.PAGE_UP;\\n        }\\n        if (kbdEvt.key === KEY_IDS.PAGE_DOWN || kbdEvt.keyCode === 34) {\\n            return KEY_IDS.PAGE_DOWN;\\n        }\\n        return '';\\n    };\\n    /**\\n     * Computes the value given a keyboard key ID\\n     */\\n    MDCSliderFoundation.prototype.getValueForKeyId_ = function (keyId) {\\n        var _a = this, max = _a.max_, min = _a.min_, step = _a.step_;\\n        var delta = step || (max - min) / 100;\\n        var valueNeedsToBeFlipped = this.adapter.isRTL() &&\\n            (keyId === KEY_IDS.ARROW_LEFT || keyId === KEY_IDS.ARROW_RIGHT);\\n        if (valueNeedsToBeFlipped) {\\n            delta = -delta;\\n        }\\n        switch (keyId) {\\n            case KEY_IDS.ARROW_LEFT:\\n            case KEY_IDS.ARROW_DOWN:\\n                return this.value_ - delta;\\n            case KEY_IDS.ARROW_RIGHT:\\n            case KEY_IDS.ARROW_UP:\\n                return this.value_ + delta;\\n            case KEY_IDS.HOME:\\n                return this.min_;\\n            case KEY_IDS.END:\\n                return this.max_;\\n            case KEY_IDS.PAGE_UP:\\n                return this.value_ + delta * _constants__WEBPACK_IMPORTED_MODULE_3__[\\\"numbers\\\"].PAGE_FACTOR;\\n            case KEY_IDS.PAGE_DOWN:\\n                return this.value_ - delta * _constants__WEBPACK_IMPORTED_MODULE_3__[\\\"numbers\\\"].PAGE_FACTOR;\\n            default:\\n                return NaN;\\n        }\\n    };\\n    MDCSliderFoundation.prototype.handleFocus_ = function () {\\n        if (this.preventFocusState_) {\\n            return;\\n        }\\n        this.adapter.addClass(_constants__WEBPACK_IMPORTED_MODULE_3__[\\\"cssClasses\\\"].FOCUS);\\n    };\\n    MDCSliderFoundation.prototype.handleBlur_ = function () {\\n        this.preventFocusState_ = false;\\n        this.adapter.removeClass(_constants__WEBPACK_IMPORTED_MODULE_3__[\\\"cssClasses\\\"].FOCUS);\\n    };\\n    /**\\n     * Sets the value of the slider\\n     */\\n    MDCSliderFoundation.prototype.setValue_ = function (value, shouldFireInput, force) {\\n        if (force === void 0) { force = false; }\\n        if (value === this.value_ && !force) {\\n            return;\\n        }\\n        var _a = this, min = _a.min_, max = _a.max_;\\n        var valueSetToBoundary = value === min || value === max;\\n        if (this.step_ && !valueSetToBoundary) {\\n            value = this.quantize_(value);\\n        }\\n        if (value < min) {\\n            value = min;\\n        }\\n        else if (value > max) {\\n            value = max;\\n        }\\n        value = value || 0; // coerce -0 to 0\\n        this.value_ = value;\\n        this.adapter.setAttribute(_constants__WEBPACK_IMPORTED_MODULE_3__[\\\"strings\\\"].ARIA_VALUENOW, String(this.value_));\\n        this.updateUIForCurrentValue_();\\n        if (shouldFireInput) {\\n            this.adapter.notifyInput();\\n            if (this.isDiscrete_) {\\n                this.adapter.setMarkerValue(value);\\n            }\\n        }\\n    };\\n    /**\\n     * Calculates the quantized value\\n     */\\n    MDCSliderFoundation.prototype.quantize_ = function (value) {\\n        var numSteps = Math.round(value / this.step_);\\n        return numSteps * this.step_;\\n    };\\n    MDCSliderFoundation.prototype.updateUIForCurrentValue_ = function () {\\n        var _this = this;\\n        var _a = this, max = _a.max_, min = _a.min_, value = _a.value_;\\n        var pctComplete = (value - min) / (max - min);\\n        var translatePx = pctComplete * this.rect_.width;\\n        if (this.adapter.isRTL()) {\\n            translatePx = this.rect_.width - translatePx;\\n        }\\n        var transformProp = hasWindow ? Object(_material_animation_util__WEBPACK_IMPORTED_MODULE_1__[\\\"getCorrectPropertyName\\\"])(window, 'transform') : 'transform';\\n        var transitionendEvtName = hasWindow ? Object(_material_animation_util__WEBPACK_IMPORTED_MODULE_1__[\\\"getCorrectEventName\\\"])(window, 'transitionend') : 'transitionend';\\n        if (this.inTransit_) {\\n            var onTransitionEnd_1 = function () {\\n                _this.setInTransit_(false);\\n                _this.adapter.deregisterThumbContainerInteractionHandler(transitionendEvtName, onTransitionEnd_1);\\n            };\\n            this.adapter.registerThumbContainerInteractionHandler(transitionendEvtName, onTransitionEnd_1);\\n        }\\n        requestAnimationFrame(function () {\\n            // NOTE(traviskaufman): It would be nice to use calc() here,\\n            // but IE cannot handle calcs in transforms correctly.\\n            // See: https://goo.gl/NC2itk\\n            // Also note that the -50% offset is used to center the slider thumb.\\n            _this.adapter.setThumbContainerStyleProperty(transformProp, \\\"translateX(\\\" + translatePx + \\\"px) translateX(-50%)\\\");\\n            _this.adapter.setTrackStyleProperty(transformProp, \\\"scaleX(\\\" + pctComplete + \\\")\\\");\\n        });\\n    };\\n    /**\\n     * Toggles the active state of the slider\\n     */\\n    MDCSliderFoundation.prototype.setActive_ = function (active) {\\n        this.active_ = active;\\n        this.toggleClass_(_constants__WEBPACK_IMPORTED_MODULE_3__[\\\"cssClasses\\\"].ACTIVE, this.active_);\\n    };\\n    /**\\n     * Toggles the inTransit state of the slider\\n     */\\n    MDCSliderFoundation.prototype.setInTransit_ = function (inTransit) {\\n        this.inTransit_ = inTransit;\\n        this.toggleClass_(_constants__WEBPACK_IMPORTED_MODULE_3__[\\\"cssClasses\\\"].IN_TRANSIT, this.inTransit_);\\n    };\\n    /**\\n     * Conditionally adds or removes a class based on shouldBePresent\\n     */\\n    MDCSliderFoundation.prototype.toggleClass_ = function (className, shouldBePresent) {\\n        if (shouldBePresent) {\\n            this.adapter.addClass(className);\\n        }\\n        else {\\n            this.adapter.removeClass(className);\\n        }\\n    };\\n    return MDCSliderFoundation;\\n}(_material_base_foundation__WEBPACK_IMPORTED_MODULE_2__[\\\"MDCFoundation\\\"]));\\n\\n// tslint:disable-next-line:no-default-export Needed for backward compatibility\\n// with MDC Web v0.44.0 and earlier.\\n/* harmony default export */ __webpack_exports__[\\\"default\\\"] = (MDCSliderFoundation);\\n//# sourceMappingURL=foundation.js.map\\n\\n//# sourceURL=webpack:///./node_modules/@material/slider/foundation.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/components/input/button.scss\":\n/*!*********************************************************************************************************************************!*\\\n  !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2!./src/components/input/button.scss ***!\n  \\*********************************************************************************************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"// Imports\\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \\\"./node_modules/css-loader/dist/runtime/api.js\\\");\\nexports = ___CSS_LOADER_API_IMPORT___(false);\\n// Module\\nexports.push([module.i, \\\"button {\\\\n  display: block;\\\\n  width: 100%;\\\\n  cursor: pointer;\\\\n  appearance: none;\\\\n  -webkit-appearance: none;\\\\n  height: 30px;\\\\n  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);\\\\n  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\\\\n  border: none;\\\\n  font-size: 1em;\\\\n  overflow: hidden;\\\\n  background-color: #ddd;\\\\n  margin-bottom: 10px;\\\\n  outline: 0px solid #fcd5b1; }\\\\n  button:focus {\\\\n    outline-width: 3px; }\\\\n  button:hover {\\\\n    background-color: #f0f;\\\\n    box-shadow: 0 3px 6px rgba(255, 0, 255, 0.16), 0 3px 6px rgba(255, 0, 255, 0.23);\\\\n    color: white; }\\\\n  button:active {\\\\n    background-color: #f0f;\\\\n    color: white; }\\\\n  button:disabled {\\\\n    opacity: 0.5;\\\\n    pointer-events: none !important;\\\\n    color: #777; }\\\\n  button::slotted(svg) {\\\\n    height: 30px;\\\\n    display: inline-block;\\\\n    transition: fill 0.1s; }\\\\n  button::slotted(*) {\\\\n    pointer-events: none; }\\\\n  button:hover ::slotted(svg) {\\\\n    fill: white; }\\\\n\\\", \\\"\\\"]);\\n// Exports\\nmodule.exports = exports;\\n\\n\\n//# sourceURL=webpack:///./src/components/input/button.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2\");\n\n/***/ }),\n\n/***/ \"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/components/input/mic-button.scss\":\n/*!*************************************************************************************************************************************!*\\\n  !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2!./src/components/input/mic-button.scss ***!\n  \\*************************************************************************************************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"// Imports\\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \\\"./node_modules/css-loader/dist/runtime/api.js\\\");\\nexports = ___CSS_LOADER_API_IMPORT___(false);\\n// Module\\nexports.push([module.i, \\\"tone-button mwc-icon {\\\\n  height: 80%;\\\\n  margin-top: 4px; }\\\\n\\\", \\\"\\\"]);\\n// Exports\\nmodule.exports = exports;\\n\\n\\n//# sourceURL=webpack:///./src/components/input/mic-button.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2\");\n\n/***/ }),\n\n/***/ \"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/components/input/momentary-button.scss\":\n/*!*******************************************************************************************************************************************!*\\\n  !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2!./src/components/input/momentary-button.scss ***!\n  \\*******************************************************************************************************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"// Imports\\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \\\"./node_modules/css-loader/dist/runtime/api.js\\\");\\nexports = ___CSS_LOADER_API_IMPORT___(false);\\n// Module\\nexports.push([module.i, \\\"button {\\\\n  display: block;\\\\n  width: 100%;\\\\n  cursor: pointer;\\\\n  appearance: none;\\\\n  -webkit-appearance: none;\\\\n  height: 30px;\\\\n  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);\\\\n  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\\\\n  border: none;\\\\n  font-size: 1em;\\\\n  overflow: hidden;\\\\n  background-color: #ddd;\\\\n  margin-bottom: 10px;\\\\n  outline: 0px solid #fcd5b1; }\\\\n  button:focus {\\\\n    outline-width: 3px; }\\\\n  button:hover {\\\\n    background-color: #f0f;\\\\n    box-shadow: 0 3px 6px rgba(255, 0, 255, 0.16), 0 3px 6px rgba(255, 0, 255, 0.23);\\\\n    color: white; }\\\\n  button:active {\\\\n    background-color: #f0f;\\\\n    color: white; }\\\\n  button:disabled {\\\\n    opacity: 0.5;\\\\n    pointer-events: none !important;\\\\n    color: #777; }\\\\n  button::slotted(svg) {\\\\n    height: 30px;\\\\n    display: inline-block;\\\\n    transition: fill 0.1s; }\\\\n  button::slotted(*) {\\\\n    pointer-events: none; }\\\\n  button:hover ::slotted(svg) {\\\\n    fill: white; }\\\\n\\\\ntone-button {\\\\n  position: relative;\\\\n  display: block; }\\\\n  tone-button #ring {\\\\n    width: 18px;\\\\n    height: 18px;\\\\n    position: absolute;\\\\n    border-radius: 50%;\\\\n    left: 50%;\\\\n    top: 50%;\\\\n    transform: translate(-50%, -50%);\\\\n    border: 2px solid black;\\\\n    box-sizing: border-box;\\\\n    transition: all 0.1s; }\\\\n    tone-button #ring #circle {\\\\n      position: absolute;\\\\n      left: 50%;\\\\n      top: 50%;\\\\n      transform: translate(-50%, -50%) scale(1.1);\\\\n      width: 100%;\\\\n      height: 100%;\\\\n      border-radius: 50%;\\\\n      transition: all 0.1s;\\\\n      background-color: black; }\\\\n  tone-button[triggered] #ring {\\\\n    width: 25px;\\\\n    height: 25px; }\\\\n    tone-button[triggered] #ring #circle {\\\\n      width: 0px;\\\\n      height: 0px; }\\\\n  tone-button:hover #ring {\\\\n    border-color: white; }\\\\n    tone-button:hover #ring #circle {\\\\n      background-color: white; }\\\\n\\\", \\\"\\\"]);\\n// Exports\\nmodule.exports = exports;\\n\\n\\n//# sourceURL=webpack:///./src/components/input/momentary-button.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2\");\n\n/***/ }),\n\n/***/ \"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/components/input/play-toggle.scss\":\n/*!**************************************************************************************************************************************!*\\\n  !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2!./src/components/input/play-toggle.scss ***!\n  \\**************************************************************************************************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"// Imports\\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \\\"./node_modules/css-loader/dist/runtime/api.js\\\");\\nexports = ___CSS_LOADER_API_IMPORT___(false);\\n// Module\\nexports.push([module.i, \\\"button {\\\\n  display: block;\\\\n  width: 100%;\\\\n  cursor: pointer;\\\\n  appearance: none;\\\\n  -webkit-appearance: none;\\\\n  height: 30px;\\\\n  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);\\\\n  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\\\\n  border: none;\\\\n  font-size: 1em;\\\\n  overflow: hidden;\\\\n  background-color: #ddd;\\\\n  margin-bottom: 10px;\\\\n  outline: 0px solid #fcd5b1; }\\\\n  button:focus {\\\\n    outline-width: 3px; }\\\\n  button:hover {\\\\n    background-color: #f0f;\\\\n    box-shadow: 0 3px 6px rgba(255, 0, 255, 0.16), 0 3px 6px rgba(255, 0, 255, 0.23);\\\\n    color: white; }\\\\n  button:active {\\\\n    background-color: #f0f;\\\\n    color: white; }\\\\n  button:disabled {\\\\n    opacity: 0.5;\\\\n    pointer-events: none !important;\\\\n    color: #777; }\\\\n  button::slotted(svg) {\\\\n    height: 30px;\\\\n    display: inline-block;\\\\n    transition: fill 0.1s; }\\\\n  button::slotted(*) {\\\\n    pointer-events: none; }\\\\n  button:hover ::slotted(svg) {\\\\n    fill: white; }\\\\n\\\\ntone-button {\\\\n  display: block; }\\\\n  tone-button mwc-icon {\\\\n    height: 30px;\\\\n    --mdc-icon-size: 30px;\\\\n    display: inline-block;\\\\n    transition: color 0.1s; }\\\\n  tone-button:hover mwc-icon {\\\\n    color: white; }\\\\n\\\", \\\"\\\"]);\\n// Exports\\nmodule.exports = exports;\\n\\n\\n//# sourceURL=webpack:///./src/components/input/play-toggle.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2\");\n\n/***/ }),\n\n/***/ \"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/components/input/slider-pad.scss\":\n/*!*************************************************************************************************************************************!*\\\n  !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2!./src/components/input/slider-pad.scss ***!\n  \\*************************************************************************************************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"// Imports\\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \\\"./node_modules/css-loader/dist/runtime/api.js\\\");\\nexports = ___CSS_LOADER_API_IMPORT___(false);\\n// Module\\nexports.push([module.i, \\\":host {\\\\n  width: 100%; }\\\\n\\\\n#container .square {\\\\n  position: relative;\\\\n  width: 60%;\\\\n  margin: 20px auto;\\\\n  background-color: rgba(170, 170, 170, 0.5);\\\\n  border-radius: 10px;\\\\n  overflow: hidden;\\\\n  cursor: pointer; }\\\\n  #container .square:after {\\\\n    content: \\\\\\\"\\\\\\\";\\\\n    display: block;\\\\n    padding-bottom: 100%; }\\\\n  #container .square:hover {\\\\n    background-color: rgba(30, 223, 62, 0.3); }\\\\n    #container .square:hover #puck {\\\\n      background-color: #3833ed;\\\\n      width: 40px;\\\\n      height: 40px; }\\\\n  #container .square #puck {\\\\n    position: absolute;\\\\n    transform: translate(-50%, -50%);\\\\n    transition: width 0.2s, height 0.2s;\\\\n    background-color: black;\\\\n    width: 30px;\\\\n    height: 30px;\\\\n    border-radius: 50%;\\\\n    pointer-events: none; }\\\\n\\\", \\\"\\\"]);\\n// Exports\\nmodule.exports = exports;\\n\\n\\n//# sourceURL=webpack:///./src/components/input/slider-pad.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2\");\n\n/***/ }),\n\n/***/ \"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/components/input/slider.scss\":\n/*!*********************************************************************************************************************************!*\\\n  !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2!./src/components/input/slider.scss ***!\n  \\*********************************************************************************************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"// Imports\\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \\\"./node_modules/css-loader/dist/runtime/api.js\\\");\\nexports = ___CSS_LOADER_API_IMPORT___(false);\\n// Module\\nexports.push([module.i, \\\":host {\\\\n  width: 100%; }\\\\n\\\\n#container {\\\\n  display: block;\\\\n  width: 100%; }\\\\n  #container #label {\\\\n    display: block;\\\\n    width: 100%; }\\\\n    #container #label .value {\\\\n      margin-left: 10px;\\\\n      font-weight: bold;\\\\n      float: right; }\\\\n      #container #label .value .units {\\\\n        font-weight: normal; }\\\\n  #container mwc-slider {\\\\n    display: block;\\\\n    width: 100%;\\\\n    --mdc-theme-secondary: black; }\\\\n\\\", \\\"\\\"]);\\n// Exports\\nmodule.exports = exports;\\n\\n\\n//# sourceURL=webpack:///./src/components/input/slider.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2\");\n\n/***/ }),\n\n/***/ \"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/components/input/step-sequencer.scss\":\n/*!*****************************************************************************************************************************************!*\\\n  !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2!./src/components/input/step-sequencer.scss ***!\n  \\*****************************************************************************************************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"// Imports\\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \\\"./node_modules/css-loader/dist/runtime/api.js\\\");\\nexports = ___CSS_LOADER_API_IMPORT___(false);\\n// Module\\nexports.push([module.i, \\\":host {\\\\n  width: 100%; }\\\\n\\\\n#container {\\\\n  display: flex;\\\\n  height: 40px; }\\\\n  #container .column {\\\\n    flex: 1;\\\\n    display: flex;\\\\n    flex-direction: column; }\\\\n    #container .column[highlighted] {\\\\n      background-color: rgba(245, 135, 31, 0.5); }\\\\n      #container .column[highlighted] .cell:not([filled]) {\\\\n        background-color: #f9bb81; }\\\\n      #container .column[highlighted] .cell[filled] {\\\\n        transform: scale(1.2); }\\\\n    #container .column .cell {\\\\n      outline: 0px solid #fcd5b1;\\\\n      margin: 2px;\\\\n      flex: 1;\\\\n      background-color: #aaa;\\\\n      border: none; }\\\\n      #container .column .cell:focus {\\\\n        outline-width: 3px; }\\\\n      #container .column .cell[filled] {\\\\n        background-color: black; }\\\\n\\\", \\\"\\\"]);\\n// Exports\\nmodule.exports = exports;\\n\\n\\n//# sourceURL=webpack:///./src/components/input/step-sequencer.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2\");\n\n/***/ }),\n\n/***/ \"./node_modules/css-loader/dist/runtime/api.js\":\n/*!*****************************************************!*\\\n  !*** ./node_modules/css-loader/dist/runtime/api.js ***!\n  \\*****************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\n/*\\n  MIT License http://www.opensource.org/licenses/mit-license.php\\n  Author Tobias Koppers @sokra\\n*/\\n// css base code, injected by the css-loader\\n// eslint-disable-next-line func-names\\nmodule.exports = function (useSourceMap) {\\n  var list = []; // return the list of modules as css string\\n\\n  list.toString = function toString() {\\n    return this.map(function (item) {\\n      var content = cssWithMappingToString(item, useSourceMap);\\n\\n      if (item[2]) {\\n        return \\\"@media \\\".concat(item[2], \\\" {\\\").concat(content, \\\"}\\\");\\n      }\\n\\n      return content;\\n    }).join('');\\n  }; // import a list of modules into the list\\n  // eslint-disable-next-line func-names\\n\\n\\n  list.i = function (modules, mediaQuery, dedupe) {\\n    if (typeof modules === 'string') {\\n      // eslint-disable-next-line no-param-reassign\\n      modules = [[null, modules, '']];\\n    }\\n\\n    var alreadyImportedModules = {};\\n\\n    if (dedupe) {\\n      for (var i = 0; i < this.length; i++) {\\n        // eslint-disable-next-line prefer-destructuring\\n        var id = this[i][0];\\n\\n        if (id != null) {\\n          alreadyImportedModules[id] = true;\\n        }\\n      }\\n    }\\n\\n    for (var _i = 0; _i < modules.length; _i++) {\\n      var item = [].concat(modules[_i]);\\n\\n      if (dedupe && alreadyImportedModules[item[0]]) {\\n        // eslint-disable-next-line no-continue\\n        continue;\\n      }\\n\\n      if (mediaQuery) {\\n        if (!item[2]) {\\n          item[2] = mediaQuery;\\n        } else {\\n          item[2] = \\\"\\\".concat(mediaQuery, \\\" and \\\").concat(item[2]);\\n        }\\n      }\\n\\n      list.push(item);\\n    }\\n  };\\n\\n  return list;\\n};\\n\\nfunction cssWithMappingToString(item, useSourceMap) {\\n  var content = item[1] || ''; // eslint-disable-next-line prefer-destructuring\\n\\n  var cssMapping = item[3];\\n\\n  if (!cssMapping) {\\n    return content;\\n  }\\n\\n  if (useSourceMap && typeof btoa === 'function') {\\n    var sourceMapping = toComment(cssMapping);\\n    var sourceURLs = cssMapping.sources.map(function (source) {\\n      return \\\"/*# sourceURL=\\\".concat(cssMapping.sourceRoot || '').concat(source, \\\" */\\\");\\n    });\\n    return [content].concat(sourceURLs).concat([sourceMapping]).join('\\\\n');\\n  }\\n\\n  return [content].join('\\\\n');\\n} // Adapted from convert-source-map (MIT)\\n\\n\\nfunction toComment(sourceMap) {\\n  // eslint-disable-next-line no-undef\\n  var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))));\\n  var data = \\\"sourceMappingURL=data:application/json;charset=utf-8;base64,\\\".concat(base64);\\n  return \\\"/*# \\\".concat(data, \\\" */\\\");\\n}\\n\\n//# sourceURL=webpack:///./node_modules/css-loader/dist/runtime/api.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-element/lib/css-tag.js\":\n/*!*************************************************!*\\\n  !*** ./node_modules/lit-element/lib/css-tag.js ***!\n  \\*************************************************/\n/*! exports provided: supportsAdoptingStyleSheets, CSSResult, unsafeCSS, css */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"supportsAdoptingStyleSheets\\\", function() { return supportsAdoptingStyleSheets; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"CSSResult\\\", function() { return CSSResult; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"unsafeCSS\\\", function() { return unsafeCSS; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"css\\\", function() { return css; });\\n/**\\n@license\\nCopyright (c) 2019 The Polymer Project Authors. All rights reserved.\\nThis code may only be used under the BSD style license found at\\nhttp://polymer.github.io/LICENSE.txt The complete set of authors may be found at\\nhttp://polymer.github.io/AUTHORS.txt The complete set of contributors may be\\nfound at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as\\npart of the polymer project is also subject to an additional IP rights grant\\nfound at http://polymer.github.io/PATENTS.txt\\n*/\\nconst supportsAdoptingStyleSheets = ('adoptedStyleSheets' in Document.prototype) &&\\n    ('replace' in CSSStyleSheet.prototype);\\nconst constructionToken = Symbol();\\nclass CSSResult {\\n    constructor(cssText, safeToken) {\\n        if (safeToken !== constructionToken) {\\n            throw new Error('CSSResult is not constructable. Use `unsafeCSS` or `css` instead.');\\n        }\\n        this.cssText = cssText;\\n    }\\n    // Note, this is a getter so that it's lazy. In practice, this means\\n    // stylesheets are not created until the first element instance is made.\\n    get styleSheet() {\\n        if (this._styleSheet === undefined) {\\n            // Note, if `adoptedStyleSheets` is supported then we assume CSSStyleSheet\\n            // is constructable.\\n            if (supportsAdoptingStyleSheets) {\\n                this._styleSheet = new CSSStyleSheet();\\n                this._styleSheet.replaceSync(this.cssText);\\n            }\\n            else {\\n                this._styleSheet = null;\\n            }\\n        }\\n        return this._styleSheet;\\n    }\\n    toString() {\\n        return this.cssText;\\n    }\\n}\\n/**\\n * Wrap a value for interpolation in a css tagged template literal.\\n *\\n * This is unsafe because untrusted CSS text can be used to phone home\\n * or exfiltrate data to an attacker controlled site. Take care to only use\\n * this with trusted input.\\n */\\nconst unsafeCSS = (value) => {\\n    return new CSSResult(String(value), constructionToken);\\n};\\nconst textFromCSSResult = (value) => {\\n    if (value instanceof CSSResult) {\\n        return value.cssText;\\n    }\\n    else if (typeof value === 'number') {\\n        return value;\\n    }\\n    else {\\n        throw new Error(`Value passed to 'css' function must be a 'css' function result: ${value}. Use 'unsafeCSS' to pass non-literal values, but\\n            take care to ensure page security.`);\\n    }\\n};\\n/**\\n * Template tag which which can be used with LitElement's `style` property to\\n * set element styles. For security reasons, only literal string values may be\\n * used. To incorporate non-literal values `unsafeCSS` may be used inside a\\n * template string part.\\n */\\nconst css = (strings, ...values) => {\\n    const cssText = values.reduce((acc, v, idx) => acc + textFromCSSResult(v) + strings[idx + 1], strings[0]);\\n    return new CSSResult(cssText, constructionToken);\\n};\\n//# sourceMappingURL=css-tag.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-element/lib/css-tag.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-element/lib/decorators.js\":\n/*!****************************************************!*\\\n  !*** ./node_modules/lit-element/lib/decorators.js ***!\n  \\****************************************************/\n/*! exports provided: customElement, property, internalProperty, query, queryAsync, queryAll, eventOptions, queryAssignedNodes */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"customElement\\\", function() { return customElement; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"property\\\", function() { return property; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"internalProperty\\\", function() { return internalProperty; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"query\\\", function() { return query; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"queryAsync\\\", function() { return queryAsync; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"queryAll\\\", function() { return queryAll; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"eventOptions\\\", function() { return eventOptions; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"queryAssignedNodes\\\", function() { return queryAssignedNodes; });\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\nconst legacyCustomElement = (tagName, clazz) => {\\n    window.customElements.define(tagName, clazz);\\n    // Cast as any because TS doesn't recognize the return type as being a\\n    // subtype of the decorated class when clazz is typed as\\n    // `Constructor<HTMLElement>` for some reason.\\n    // `Constructor<HTMLElement>` is helpful to make sure the decorator is\\n    // applied to elements however.\\n    // tslint:disable-next-line:no-any\\n    return clazz;\\n};\\nconst standardCustomElement = (tagName, descriptor) => {\\n    const { kind, elements } = descriptor;\\n    return {\\n        kind,\\n        elements,\\n        // This callback is called once the class is otherwise fully defined\\n        finisher(clazz) {\\n            window.customElements.define(tagName, clazz);\\n        }\\n    };\\n};\\n/**\\n * Class decorator factory that defines the decorated class as a custom element.\\n *\\n * ```\\n * @customElement('my-element')\\n * class MyElement {\\n *   render() {\\n *     return html``;\\n *   }\\n * }\\n * ```\\n *\\n * @param tagName The name of the custom element to define.\\n */\\nconst customElement = (tagName) => (classOrDescriptor) => (typeof classOrDescriptor === 'function') ?\\n    legacyCustomElement(tagName, classOrDescriptor) :\\n    standardCustomElement(tagName, classOrDescriptor);\\nconst standardProperty = (options, element) => {\\n    // When decorating an accessor, pass it through and add property metadata.\\n    // Note, the `hasOwnProperty` check in `createProperty` ensures we don't\\n    // stomp over the user's accessor.\\n    if (element.kind === 'method' && element.descriptor &&\\n        !('value' in element.descriptor)) {\\n        return Object.assign(Object.assign({}, element), { finisher(clazz) {\\n                clazz.createProperty(element.key, options);\\n            } });\\n    }\\n    else {\\n        // createProperty() takes care of defining the property, but we still\\n        // must return some kind of descriptor, so return a descriptor for an\\n        // unused prototype field. The finisher calls createProperty().\\n        return {\\n            kind: 'field',\\n            key: Symbol(),\\n            placement: 'own',\\n            descriptor: {},\\n            // When @babel/plugin-proposal-decorators implements initializers,\\n            // do this instead of the initializer below. See:\\n            // https://github.com/babel/babel/issues/9260 extras: [\\n            //   {\\n            //     kind: 'initializer',\\n            //     placement: 'own',\\n            //     initializer: descriptor.initializer,\\n            //   }\\n            // ],\\n            initializer() {\\n                if (typeof element.initializer === 'function') {\\n                    this[element.key] = element.initializer.call(this);\\n                }\\n            },\\n            finisher(clazz) {\\n                clazz.createProperty(element.key, options);\\n            }\\n        };\\n    }\\n};\\nconst legacyProperty = (options, proto, name) => {\\n    proto.constructor\\n        .createProperty(name, options);\\n};\\n/**\\n * A property decorator which creates a LitElement property which reflects a\\n * corresponding attribute value. A `PropertyDeclaration` may optionally be\\n * supplied to configure property features.\\n *\\n * This decorator should only be used for public fields. Private or protected\\n * fields should use the internalProperty decorator.\\n *\\n * @example\\n *\\n *     class MyElement {\\n *       @property({ type: Boolean })\\n *       clicked = false;\\n *     }\\n *\\n * @ExportDecoratedItems\\n */\\nfunction property(options) {\\n    // tslint:disable-next-line:no-any decorator\\n    return (protoOrDescriptor, name) => (name !== undefined) ?\\n        legacyProperty(options, protoOrDescriptor, name) :\\n        standardProperty(options, protoOrDescriptor);\\n}\\n/**\\n * Declares a private or protected property that still triggers updates to the\\n * element when it changes.\\n *\\n * Properties declared this way must not be used from HTML or HTML templating\\n * systems, they're solely for properties internal to the element. These\\n * properties may be renamed by optimization tools like closure compiler.\\n */\\nfunction internalProperty(options) {\\n    return property({ attribute: false, hasChanged: options === null || options === void 0 ? void 0 : options.hasChanged });\\n}\\n/**\\n * A property decorator that converts a class property into a getter that\\n * executes a querySelector on the element's renderRoot.\\n *\\n * @param selector A DOMString containing one or more selectors to match.\\n *\\n * See: https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector\\n *\\n * @example\\n *\\n *     class MyElement {\\n *       @query('#first')\\n *       first;\\n *\\n *       render() {\\n *         return html`\\n *           <div id=\\\"first\\\"></div>\\n *           <div id=\\\"second\\\"></div>\\n *         `;\\n *       }\\n *     }\\n *\\n */\\nfunction query(selector) {\\n    return (protoOrDescriptor, \\n    // tslint:disable-next-line:no-any decorator\\n    name) => {\\n        const descriptor = {\\n            get() {\\n                return this.renderRoot.querySelector(selector);\\n            },\\n            enumerable: true,\\n            configurable: true,\\n        };\\n        return (name !== undefined) ?\\n            legacyQuery(descriptor, protoOrDescriptor, name) :\\n            standardQuery(descriptor, protoOrDescriptor);\\n    };\\n}\\n// Note, in the future, we may extend this decorator to support the use case\\n// where the queried element may need to do work to become ready to interact\\n// with (e.g. load some implementation code). If so, we might elect to\\n// add a second argument defining a function that can be run to make the\\n// queried element loaded/updated/ready.\\n/**\\n * A property decorator that converts a class property into a getter that\\n * returns a promise that resolves to the result of a querySelector on the\\n * element's renderRoot done after the element's `updateComplete` promise\\n * resolves. When the queried property may change with element state, this\\n * decorator can be used instead of requiring users to await the\\n * `updateComplete` before accessing the property.\\n *\\n * @param selector A DOMString containing one or more selectors to match.\\n *\\n * See: https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector\\n *\\n * @example\\n *\\n *     class MyElement {\\n *       @queryAsync('#first')\\n *       first;\\n *\\n *       render() {\\n *         return html`\\n *           <div id=\\\"first\\\"></div>\\n *           <div id=\\\"second\\\"></div>\\n *         `;\\n *       }\\n *     }\\n *\\n *     // external usage\\n *     async doSomethingWithFirst() {\\n *      (await aMyElement.first).doSomething();\\n *     }\\n */\\nfunction queryAsync(selector) {\\n    return (protoOrDescriptor, \\n    // tslint:disable-next-line:no-any decorator\\n    name) => {\\n        const descriptor = {\\n            async get() {\\n                await this.updateComplete;\\n                return this.renderRoot.querySelector(selector);\\n            },\\n            enumerable: true,\\n            configurable: true,\\n        };\\n        return (name !== undefined) ?\\n            legacyQuery(descriptor, protoOrDescriptor, name) :\\n            standardQuery(descriptor, protoOrDescriptor);\\n    };\\n}\\n/**\\n * A property decorator that converts a class property into a getter\\n * that executes a querySelectorAll on the element's renderRoot.\\n *\\n * @param selector A DOMString containing one or more selectors to match.\\n *\\n * See:\\n * https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll\\n *\\n * @example\\n *\\n *     class MyElement {\\n *       @queryAll('div')\\n *       divs;\\n *\\n *       render() {\\n *         return html`\\n *           <div id=\\\"first\\\"></div>\\n *           <div id=\\\"second\\\"></div>\\n *         `;\\n *       }\\n *     }\\n */\\nfunction queryAll(selector) {\\n    return (protoOrDescriptor, \\n    // tslint:disable-next-line:no-any decorator\\n    name) => {\\n        const descriptor = {\\n            get() {\\n                return this.renderRoot.querySelectorAll(selector);\\n            },\\n            enumerable: true,\\n            configurable: true,\\n        };\\n        return (name !== undefined) ?\\n            legacyQuery(descriptor, protoOrDescriptor, name) :\\n            standardQuery(descriptor, protoOrDescriptor);\\n    };\\n}\\nconst legacyQuery = (descriptor, proto, name) => {\\n    Object.defineProperty(proto, name, descriptor);\\n};\\nconst standardQuery = (descriptor, element) => ({\\n    kind: 'method',\\n    placement: 'prototype',\\n    key: element.key,\\n    descriptor,\\n});\\nconst standardEventOptions = (options, element) => {\\n    return Object.assign(Object.assign({}, element), { finisher(clazz) {\\n            Object.assign(clazz.prototype[element.key], options);\\n        } });\\n};\\nconst legacyEventOptions = \\n// tslint:disable-next-line:no-any legacy decorator\\n(options, proto, name) => {\\n    Object.assign(proto[name], options);\\n};\\n/**\\n * Adds event listener options to a method used as an event listener in a\\n * lit-html template.\\n *\\n * @param options An object that specifies event listener options as accepted by\\n * `EventTarget#addEventListener` and `EventTarget#removeEventListener`.\\n *\\n * Current browsers support the `capture`, `passive`, and `once` options. See:\\n * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Parameters\\n *\\n * @example\\n *\\n *     class MyElement {\\n *       clicked = false;\\n *\\n *       render() {\\n *         return html`\\n *           <div @click=${this._onClick}`>\\n *             <button></button>\\n *           </div>\\n *         `;\\n *       }\\n *\\n *       @eventOptions({capture: true})\\n *       _onClick(e) {\\n *         this.clicked = true;\\n *       }\\n *     }\\n */\\nfunction eventOptions(options) {\\n    // Return value typed as any to prevent TypeScript from complaining that\\n    // standard decorator function signature does not match TypeScript decorator\\n    // signature\\n    // TODO(kschaaf): unclear why it was only failing on this decorator and not\\n    // the others\\n    return ((protoOrDescriptor, name) => (name !== undefined) ?\\n        legacyEventOptions(options, protoOrDescriptor, name) :\\n        standardEventOptions(options, protoOrDescriptor));\\n}\\n/**\\n * A property decorator that converts a class property into a getter that\\n * returns the `assignedNodes` of the given named `slot`. Note, the type of\\n * this property should be annotated as `NodeListOf<HTMLElement>`.\\n *\\n */\\nfunction queryAssignedNodes(slotName = '', flatten = false) {\\n    return (protoOrDescriptor, \\n    // tslint:disable-next-line:no-any decorator\\n    name) => {\\n        const descriptor = {\\n            get() {\\n                const selector = `slot${slotName ? `[name=${slotName}]` : ''}`;\\n                const slot = this.renderRoot.querySelector(selector);\\n                return slot && slot.assignedNodes({ flatten });\\n            },\\n            enumerable: true,\\n            configurable: true,\\n        };\\n        return (name !== undefined) ?\\n            legacyQuery(descriptor, protoOrDescriptor, name) :\\n            standardQuery(descriptor, protoOrDescriptor);\\n    };\\n}\\n//# sourceMappingURL=decorators.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-element/lib/decorators.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-element/lib/updating-element.js\":\n/*!**********************************************************!*\\\n  !*** ./node_modules/lit-element/lib/updating-element.js ***!\n  \\**********************************************************/\n/*! exports provided: defaultConverter, notEqual, UpdatingElement */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"defaultConverter\\\", function() { return defaultConverter; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"notEqual\\\", function() { return notEqual; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"UpdatingElement\\\", function() { return UpdatingElement; });\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\nvar _a;\\n/**\\n * When using Closure Compiler, JSCompiler_renameProperty(property, object) is\\n * replaced at compile time by the munged name for object[property]. We cannot\\n * alias this function, so we have to use a small shim that has the same\\n * behavior when not compiling.\\n */\\nwindow.JSCompiler_renameProperty =\\n    (prop, _obj) => prop;\\nconst defaultConverter = {\\n    toAttribute(value, type) {\\n        switch (type) {\\n            case Boolean:\\n                return value ? '' : null;\\n            case Object:\\n            case Array:\\n                // if the value is `null` or `undefined` pass this through\\n                // to allow removing/no change behavior.\\n                return value == null ? value : JSON.stringify(value);\\n        }\\n        return value;\\n    },\\n    fromAttribute(value, type) {\\n        switch (type) {\\n            case Boolean:\\n                return value !== null;\\n            case Number:\\n                return value === null ? null : Number(value);\\n            case Object:\\n            case Array:\\n                return JSON.parse(value);\\n        }\\n        return value;\\n    }\\n};\\n/**\\n * Change function that returns true if `value` is different from `oldValue`.\\n * This method is used as the default for a property's `hasChanged` function.\\n */\\nconst notEqual = (value, old) => {\\n    // This ensures (old==NaN, value==NaN) always returns false\\n    return old !== value && (old === old || value === value);\\n};\\nconst defaultPropertyDeclaration = {\\n    attribute: true,\\n    type: String,\\n    converter: defaultConverter,\\n    reflect: false,\\n    hasChanged: notEqual\\n};\\nconst STATE_HAS_UPDATED = 1;\\nconst STATE_UPDATE_REQUESTED = 1 << 2;\\nconst STATE_IS_REFLECTING_TO_ATTRIBUTE = 1 << 3;\\nconst STATE_IS_REFLECTING_TO_PROPERTY = 1 << 4;\\n/**\\n * The Closure JS Compiler doesn't currently have good support for static\\n * property semantics where \\\"this\\\" is dynamic (e.g.\\n * https://github.com/google/closure-compiler/issues/3177 and others) so we use\\n * this hack to bypass any rewriting by the compiler.\\n */\\nconst finalized = 'finalized';\\n/**\\n * Base element class which manages element properties and attributes. When\\n * properties change, the `update` method is asynchronously called. This method\\n * should be supplied by subclassers to render updates as desired.\\n */\\nclass UpdatingElement extends HTMLElement {\\n    constructor() {\\n        super();\\n        this._updateState = 0;\\n        this._instanceProperties = undefined;\\n        // Initialize to an unresolved Promise so we can make sure the element has\\n        // connected before first update.\\n        this._updatePromise = new Promise((res) => this._enableUpdatingResolver = res);\\n        /**\\n         * Map with keys for any properties that have changed since the last\\n         * update cycle with previous values.\\n         */\\n        this._changedProperties = new Map();\\n        /**\\n         * Map with keys of properties that should be reflected when updated.\\n         */\\n        this._reflectingProperties = undefined;\\n        this.initialize();\\n    }\\n    /**\\n     * Returns a list of attributes corresponding to the registered properties.\\n     * @nocollapse\\n     */\\n    static get observedAttributes() {\\n        // note: piggy backing on this to ensure we're finalized.\\n        this.finalize();\\n        const attributes = [];\\n        // Use forEach so this works even if for/of loops are compiled to for loops\\n        // expecting arrays\\n        this._classProperties.forEach((v, p) => {\\n            const attr = this._attributeNameForProperty(p, v);\\n            if (attr !== undefined) {\\n                this._attributeToPropertyMap.set(attr, p);\\n                attributes.push(attr);\\n            }\\n        });\\n        return attributes;\\n    }\\n    /**\\n     * Ensures the private `_classProperties` property metadata is created.\\n     * In addition to `finalize` this is also called in `createProperty` to\\n     * ensure the `@property` decorator can add property metadata.\\n     */\\n    /** @nocollapse */\\n    static _ensureClassProperties() {\\n        // ensure private storage for property declarations.\\n        if (!this.hasOwnProperty(JSCompiler_renameProperty('_classProperties', this))) {\\n            this._classProperties = new Map();\\n            // NOTE: Workaround IE11 not supporting Map constructor argument.\\n            const superProperties = Object.getPrototypeOf(this)._classProperties;\\n            if (superProperties !== undefined) {\\n                superProperties.forEach((v, k) => this._classProperties.set(k, v));\\n            }\\n        }\\n    }\\n    /**\\n     * Creates a property accessor on the element prototype if one does not exist\\n     * and stores a PropertyDeclaration for the property with the given options.\\n     * The property setter calls the property's `hasChanged` property option\\n     * or uses a strict identity check to determine whether or not to request\\n     * an update.\\n     *\\n     * This method may be overridden to customize properties; however,\\n     * when doing so, it's important to call `super.createProperty` to ensure\\n     * the property is setup correctly. This method calls\\n     * `getPropertyDescriptor` internally to get a descriptor to install.\\n     * To customize what properties do when they are get or set, override\\n     * `getPropertyDescriptor`. To customize the options for a property,\\n     * implement `createProperty` like this:\\n     *\\n     * static createProperty(name, options) {\\n     *   options = Object.assign(options, {myOption: true});\\n     *   super.createProperty(name, options);\\n     * }\\n     *\\n     * @nocollapse\\n     */\\n    static createProperty(name, options = defaultPropertyDeclaration) {\\n        // Note, since this can be called by the `@property` decorator which\\n        // is called before `finalize`, we ensure storage exists for property\\n        // metadata.\\n        this._ensureClassProperties();\\n        this._classProperties.set(name, options);\\n        // Do not generate an accessor if the prototype already has one, since\\n        // it would be lost otherwise and that would never be the user's intention;\\n        // Instead, we expect users to call `requestUpdate` themselves from\\n        // user-defined accessors. Note that if the super has an accessor we will\\n        // still overwrite it\\n        if (options.noAccessor || this.prototype.hasOwnProperty(name)) {\\n            return;\\n        }\\n        const key = typeof name === 'symbol' ? Symbol() : `__${name}`;\\n        const descriptor = this.getPropertyDescriptor(name, key, options);\\n        if (descriptor !== undefined) {\\n            Object.defineProperty(this.prototype, name, descriptor);\\n        }\\n    }\\n    /**\\n     * Returns a property descriptor to be defined on the given named property.\\n     * If no descriptor is returned, the property will not become an accessor.\\n     * For example,\\n     *\\n     *   class MyElement extends LitElement {\\n     *     static getPropertyDescriptor(name, key, options) {\\n     *       const defaultDescriptor =\\n     *           super.getPropertyDescriptor(name, key, options);\\n     *       const setter = defaultDescriptor.set;\\n     *       return {\\n     *         get: defaultDescriptor.get,\\n     *         set(value) {\\n     *           setter.call(this, value);\\n     *           // custom action.\\n     *         },\\n     *         configurable: true,\\n     *         enumerable: true\\n     *       }\\n     *     }\\n     *   }\\n     *\\n     * @nocollapse\\n     */\\n    static getPropertyDescriptor(name, key, _options) {\\n        return {\\n            // tslint:disable-next-line:no-any no symbol in index\\n            get() {\\n                return this[key];\\n            },\\n            set(value) {\\n                const oldValue = this[name];\\n                this[key] = value;\\n                this._requestUpdate(name, oldValue);\\n            },\\n            configurable: true,\\n            enumerable: true\\n        };\\n    }\\n    /**\\n     * Returns the property options associated with the given property.\\n     * These options are defined with a PropertyDeclaration via the `properties`\\n     * object or the `@property` decorator and are registered in\\n     * `createProperty(...)`.\\n     *\\n     * Note, this method should be considered \\\"final\\\" and not overridden. To\\n     * customize the options for a given property, override `createProperty`.\\n     *\\n     * @nocollapse\\n     * @final\\n     */\\n    static getPropertyOptions(name) {\\n        return this._classProperties && this._classProperties.get(name) ||\\n            defaultPropertyDeclaration;\\n    }\\n    /**\\n     * Creates property accessors for registered properties and ensures\\n     * any superclasses are also finalized.\\n     * @nocollapse\\n     */\\n    static finalize() {\\n        // finalize any superclasses\\n        const superCtor = Object.getPrototypeOf(this);\\n        if (!superCtor.hasOwnProperty(finalized)) {\\n            superCtor.finalize();\\n        }\\n        this[finalized] = true;\\n        this._ensureClassProperties();\\n        // initialize Map populated in observedAttributes\\n        this._attributeToPropertyMap = new Map();\\n        // make any properties\\n        // Note, only process \\\"own\\\" properties since this element will inherit\\n        // any properties defined on the superClass, and finalization ensures\\n        // the entire prototype chain is finalized.\\n        if (this.hasOwnProperty(JSCompiler_renameProperty('properties', this))) {\\n            const props = this.properties;\\n            // support symbols in properties (IE11 does not support this)\\n            const propKeys = [\\n                ...Object.getOwnPropertyNames(props),\\n                ...(typeof Object.getOwnPropertySymbols === 'function') ?\\n                    Object.getOwnPropertySymbols(props) :\\n                    []\\n            ];\\n            // This for/of is ok because propKeys is an array\\n            for (const p of propKeys) {\\n                // note, use of `any` is due to TypeSript lack of support for symbol in\\n                // index types\\n                // tslint:disable-next-line:no-any no symbol in index\\n                this.createProperty(p, props[p]);\\n            }\\n        }\\n    }\\n    /**\\n     * Returns the property name for the given attribute `name`.\\n     * @nocollapse\\n     */\\n    static _attributeNameForProperty(name, options) {\\n        const attribute = options.attribute;\\n        return attribute === false ?\\n            undefined :\\n            (typeof attribute === 'string' ?\\n                attribute :\\n                (typeof name === 'string' ? name.toLowerCase() : undefined));\\n    }\\n    /**\\n     * Returns true if a property should request an update.\\n     * Called when a property value is set and uses the `hasChanged`\\n     * option for the property if present or a strict identity check.\\n     * @nocollapse\\n     */\\n    static _valueHasChanged(value, old, hasChanged = notEqual) {\\n        return hasChanged(value, old);\\n    }\\n    /**\\n     * Returns the property value for the given attribute value.\\n     * Called via the `attributeChangedCallback` and uses the property's\\n     * `converter` or `converter.fromAttribute` property option.\\n     * @nocollapse\\n     */\\n    static _propertyValueFromAttribute(value, options) {\\n        const type = options.type;\\n        const converter = options.converter || defaultConverter;\\n        const fromAttribute = (typeof converter === 'function' ? converter : converter.fromAttribute);\\n        return fromAttribute ? fromAttribute(value, type) : value;\\n    }\\n    /**\\n     * Returns the attribute value for the given property value. If this\\n     * returns undefined, the property will *not* be reflected to an attribute.\\n     * If this returns null, the attribute will be removed, otherwise the\\n     * attribute will be set to the value.\\n     * This uses the property's `reflect` and `type.toAttribute` property options.\\n     * @nocollapse\\n     */\\n    static _propertyValueToAttribute(value, options) {\\n        if (options.reflect === undefined) {\\n            return;\\n        }\\n        const type = options.type;\\n        const converter = options.converter;\\n        const toAttribute = converter && converter.toAttribute ||\\n            defaultConverter.toAttribute;\\n        return toAttribute(value, type);\\n    }\\n    /**\\n     * Performs element initialization. By default captures any pre-set values for\\n     * registered properties.\\n     */\\n    initialize() {\\n        this._saveInstanceProperties();\\n        // ensures first update will be caught by an early access of\\n        // `updateComplete`\\n        this._requestUpdate();\\n    }\\n    /**\\n     * Fixes any properties set on the instance before upgrade time.\\n     * Otherwise these would shadow the accessor and break these properties.\\n     * The properties are stored in a Map which is played back after the\\n     * constructor runs. Note, on very old versions of Safari (<=9) or Chrome\\n     * (<=41), properties created for native platform properties like (`id` or\\n     * `name`) may not have default values set in the element constructor. On\\n     * these browsers native properties appear on instances and therefore their\\n     * default value will overwrite any element default (e.g. if the element sets\\n     * this.id = 'id' in the constructor, the 'id' will become '' since this is\\n     * the native platform default).\\n     */\\n    _saveInstanceProperties() {\\n        // Use forEach so this works even if for/of loops are compiled to for loops\\n        // expecting arrays\\n        this.constructor\\n            ._classProperties.forEach((_v, p) => {\\n            if (this.hasOwnProperty(p)) {\\n                const value = this[p];\\n                delete this[p];\\n                if (!this._instanceProperties) {\\n                    this._instanceProperties = new Map();\\n                }\\n                this._instanceProperties.set(p, value);\\n            }\\n        });\\n    }\\n    /**\\n     * Applies previously saved instance properties.\\n     */\\n    _applyInstanceProperties() {\\n        // Use forEach so this works even if for/of loops are compiled to for loops\\n        // expecting arrays\\n        // tslint:disable-next-line:no-any\\n        this._instanceProperties.forEach((v, p) => this[p] = v);\\n        this._instanceProperties = undefined;\\n    }\\n    connectedCallback() {\\n        // Ensure first connection completes an update. Updates cannot complete\\n        // before connection.\\n        this.enableUpdating();\\n    }\\n    enableUpdating() {\\n        if (this._enableUpdatingResolver !== undefined) {\\n            this._enableUpdatingResolver();\\n            this._enableUpdatingResolver = undefined;\\n        }\\n    }\\n    /**\\n     * Allows for `super.disconnectedCallback()` in extensions while\\n     * reserving the possibility of making non-breaking feature additions\\n     * when disconnecting at some point in the future.\\n     */\\n    disconnectedCallback() {\\n    }\\n    /**\\n     * Synchronizes property values when attributes change.\\n     */\\n    attributeChangedCallback(name, old, value) {\\n        if (old !== value) {\\n            this._attributeToProperty(name, value);\\n        }\\n    }\\n    _propertyToAttribute(name, value, options = defaultPropertyDeclaration) {\\n        const ctor = this.constructor;\\n        const attr = ctor._attributeNameForProperty(name, options);\\n        if (attr !== undefined) {\\n            const attrValue = ctor._propertyValueToAttribute(value, options);\\n            // an undefined value does not change the attribute.\\n            if (attrValue === undefined) {\\n                return;\\n            }\\n            // Track if the property is being reflected to avoid\\n            // setting the property again via `attributeChangedCallback`. Note:\\n            // 1. this takes advantage of the fact that the callback is synchronous.\\n            // 2. will behave incorrectly if multiple attributes are in the reaction\\n            // stack at time of calling. However, since we process attributes\\n            // in `update` this should not be possible (or an extreme corner case\\n            // that we'd like to discover).\\n            // mark state reflecting\\n            this._updateState = this._updateState | STATE_IS_REFLECTING_TO_ATTRIBUTE;\\n            if (attrValue == null) {\\n                this.removeAttribute(attr);\\n            }\\n            else {\\n                this.setAttribute(attr, attrValue);\\n            }\\n            // mark state not reflecting\\n            this._updateState = this._updateState & ~STATE_IS_REFLECTING_TO_ATTRIBUTE;\\n        }\\n    }\\n    _attributeToProperty(name, value) {\\n        // Use tracking info to avoid deserializing attribute value if it was\\n        // just set from a property setter.\\n        if (this._updateState & STATE_IS_REFLECTING_TO_ATTRIBUTE) {\\n            return;\\n        }\\n        const ctor = this.constructor;\\n        // Note, hint this as an `AttributeMap` so closure clearly understands\\n        // the type; it has issues with tracking types through statics\\n        // tslint:disable-next-line:no-unnecessary-type-assertion\\n        const propName = ctor._attributeToPropertyMap.get(name);\\n        if (propName !== undefined) {\\n            const options = ctor.getPropertyOptions(propName);\\n            // mark state reflecting\\n            this._updateState = this._updateState | STATE_IS_REFLECTING_TO_PROPERTY;\\n            this[propName] =\\n                // tslint:disable-next-line:no-any\\n                ctor._propertyValueFromAttribute(value, options);\\n            // mark state not reflecting\\n            this._updateState = this._updateState & ~STATE_IS_REFLECTING_TO_PROPERTY;\\n        }\\n    }\\n    /**\\n     * This private version of `requestUpdate` does not access or return the\\n     * `updateComplete` promise. This promise can be overridden and is therefore\\n     * not free to access.\\n     */\\n    _requestUpdate(name, oldValue) {\\n        let shouldRequestUpdate = true;\\n        // If we have a property key, perform property update steps.\\n        if (name !== undefined) {\\n            const ctor = this.constructor;\\n            const options = ctor.getPropertyOptions(name);\\n            if (ctor._valueHasChanged(this[name], oldValue, options.hasChanged)) {\\n                if (!this._changedProperties.has(name)) {\\n                    this._changedProperties.set(name, oldValue);\\n                }\\n                // Add to reflecting properties set.\\n                // Note, it's important that every change has a chance to add the\\n                // property to `_reflectingProperties`. This ensures setting\\n                // attribute + property reflects correctly.\\n                if (options.reflect === true &&\\n                    !(this._updateState & STATE_IS_REFLECTING_TO_PROPERTY)) {\\n                    if (this._reflectingProperties === undefined) {\\n                        this._reflectingProperties = new Map();\\n                    }\\n                    this._reflectingProperties.set(name, options);\\n                }\\n            }\\n            else {\\n                // Abort the request if the property should not be considered changed.\\n                shouldRequestUpdate = false;\\n            }\\n        }\\n        if (!this._hasRequestedUpdate && shouldRequestUpdate) {\\n            this._updatePromise = this._enqueueUpdate();\\n        }\\n    }\\n    /**\\n     * Requests an update which is processed asynchronously. This should\\n     * be called when an element should update based on some state not triggered\\n     * by setting a property. In this case, pass no arguments. It should also be\\n     * called when manually implementing a property setter. In this case, pass the\\n     * property `name` and `oldValue` to ensure that any configured property\\n     * options are honored. Returns the `updateComplete` Promise which is resolved\\n     * when the update completes.\\n     *\\n     * @param name {PropertyKey} (optional) name of requesting property\\n     * @param oldValue {any} (optional) old value of requesting property\\n     * @returns {Promise} A Promise that is resolved when the update completes.\\n     */\\n    requestUpdate(name, oldValue) {\\n        this._requestUpdate(name, oldValue);\\n        return this.updateComplete;\\n    }\\n    /**\\n     * Sets up the element to asynchronously update.\\n     */\\n    async _enqueueUpdate() {\\n        this._updateState = this._updateState | STATE_UPDATE_REQUESTED;\\n        try {\\n            // Ensure any previous update has resolved before updating.\\n            // This `await` also ensures that property changes are batched.\\n            await this._updatePromise;\\n        }\\n        catch (e) {\\n            // Ignore any previous errors. We only care that the previous cycle is\\n            // done. Any error should have been handled in the previous update.\\n        }\\n        const result = this.performUpdate();\\n        // If `performUpdate` returns a Promise, we await it. This is done to\\n        // enable coordinating updates with a scheduler. Note, the result is\\n        // checked to avoid delaying an additional microtask unless we need to.\\n        if (result != null) {\\n            await result;\\n        }\\n        return !this._hasRequestedUpdate;\\n    }\\n    get _hasRequestedUpdate() {\\n        return (this._updateState & STATE_UPDATE_REQUESTED);\\n    }\\n    get hasUpdated() {\\n        return (this._updateState & STATE_HAS_UPDATED);\\n    }\\n    /**\\n     * Performs an element update. Note, if an exception is thrown during the\\n     * update, `firstUpdated` and `updated` will not be called.\\n     *\\n     * You can override this method to change the timing of updates. If this\\n     * method is overridden, `super.performUpdate()` must be called.\\n     *\\n     * For instance, to schedule updates to occur just before the next frame:\\n     *\\n     * ```\\n     * protected async performUpdate(): Promise<unknown> {\\n     *   await new Promise((resolve) => requestAnimationFrame(() => resolve()));\\n     *   super.performUpdate();\\n     * }\\n     * ```\\n     */\\n    performUpdate() {\\n        // Mixin instance properties once, if they exist.\\n        if (this._instanceProperties) {\\n            this._applyInstanceProperties();\\n        }\\n        let shouldUpdate = false;\\n        const changedProperties = this._changedProperties;\\n        try {\\n            shouldUpdate = this.shouldUpdate(changedProperties);\\n            if (shouldUpdate) {\\n                this.update(changedProperties);\\n            }\\n            else {\\n                this._markUpdated();\\n            }\\n        }\\n        catch (e) {\\n            // Prevent `firstUpdated` and `updated` from running when there's an\\n            // update exception.\\n            shouldUpdate = false;\\n            // Ensure element can accept additional updates after an exception.\\n            this._markUpdated();\\n            throw e;\\n        }\\n        if (shouldUpdate) {\\n            if (!(this._updateState & STATE_HAS_UPDATED)) {\\n                this._updateState = this._updateState | STATE_HAS_UPDATED;\\n                this.firstUpdated(changedProperties);\\n            }\\n            this.updated(changedProperties);\\n        }\\n    }\\n    _markUpdated() {\\n        this._changedProperties = new Map();\\n        this._updateState = this._updateState & ~STATE_UPDATE_REQUESTED;\\n    }\\n    /**\\n     * Returns a Promise that resolves when the element has completed updating.\\n     * The Promise value is a boolean that is `true` if the element completed the\\n     * update without triggering another update. The Promise result is `false` if\\n     * a property was set inside `updated()`. If the Promise is rejected, an\\n     * exception was thrown during the update.\\n     *\\n     * To await additional asynchronous work, override the `_getUpdateComplete`\\n     * method. For example, it is sometimes useful to await a rendered element\\n     * before fulfilling this Promise. To do this, first await\\n     * `super._getUpdateComplete()`, then any subsequent state.\\n     *\\n     * @returns {Promise} The Promise returns a boolean that indicates if the\\n     * update resolved without triggering another update.\\n     */\\n    get updateComplete() {\\n        return this._getUpdateComplete();\\n    }\\n    /**\\n     * Override point for the `updateComplete` promise.\\n     *\\n     * It is not safe to override the `updateComplete` getter directly due to a\\n     * limitation in TypeScript which means it is not possible to call a\\n     * superclass getter (e.g. `super.updateComplete.then(...)`) when the target\\n     * language is ES5 (https://github.com/microsoft/TypeScript/issues/338).\\n     * This method should be overridden instead. For example:\\n     *\\n     *   class MyElement extends LitElement {\\n     *     async _getUpdateComplete() {\\n     *       await super._getUpdateComplete();\\n     *       await this._myChild.updateComplete;\\n     *     }\\n     *   }\\n     */\\n    _getUpdateComplete() {\\n        return this._updatePromise;\\n    }\\n    /**\\n     * Controls whether or not `update` should be called when the element requests\\n     * an update. By default, this method always returns `true`, but this can be\\n     * customized to control when to update.\\n     *\\n     * @param _changedProperties Map of changed properties with old values\\n     */\\n    shouldUpdate(_changedProperties) {\\n        return true;\\n    }\\n    /**\\n     * Updates the element. This method reflects property values to attributes.\\n     * It can be overridden to render and keep updated element DOM.\\n     * Setting properties inside this method will *not* trigger\\n     * another update.\\n     *\\n     * @param _changedProperties Map of changed properties with old values\\n     */\\n    update(_changedProperties) {\\n        if (this._reflectingProperties !== undefined &&\\n            this._reflectingProperties.size > 0) {\\n            // Use forEach so this works even if for/of loops are compiled to for\\n            // loops expecting arrays\\n            this._reflectingProperties.forEach((v, k) => this._propertyToAttribute(k, this[k], v));\\n            this._reflectingProperties = undefined;\\n        }\\n        this._markUpdated();\\n    }\\n    /**\\n     * Invoked whenever the element is updated. Implement to perform\\n     * post-updating tasks via DOM APIs, for example, focusing an element.\\n     *\\n     * Setting properties inside this method will trigger the element to update\\n     * again after this update cycle completes.\\n     *\\n     * @param _changedProperties Map of changed properties with old values\\n     */\\n    updated(_changedProperties) {\\n    }\\n    /**\\n     * Invoked when the element is first updated. Implement to perform one time\\n     * work on the element after update.\\n     *\\n     * Setting properties inside this method will trigger the element to update\\n     * again after this update cycle completes.\\n     *\\n     * @param _changedProperties Map of changed properties with old values\\n     */\\n    firstUpdated(_changedProperties) {\\n    }\\n}\\n_a = finalized;\\n/**\\n * Marks class as having finished creating properties.\\n */\\nUpdatingElement[_a] = true;\\n//# sourceMappingURL=updating-element.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-element/lib/updating-element.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-element/lit-element.js\":\n/*!*************************************************!*\\\n  !*** ./node_modules/lit-element/lit-element.js ***!\n  \\*************************************************/\n/*! exports provided: defaultConverter, notEqual, UpdatingElement, customElement, property, internalProperty, query, queryAsync, queryAll, eventOptions, queryAssignedNodes, html, svg, TemplateResult, SVGTemplateResult, supportsAdoptingStyleSheets, CSSResult, unsafeCSS, css, LitElement */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"LitElement\\\", function() { return LitElement; });\\n/* harmony import */ var lit_html_lib_shady_render_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lit-html/lib/shady-render.js */ \\\"./node_modules/lit-html/lib/shady-render.js\\\");\\n/* harmony import */ var _lib_updating_element_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./lib/updating-element.js */ \\\"./node_modules/lit-element/lib/updating-element.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"defaultConverter\\\", function() { return _lib_updating_element_js__WEBPACK_IMPORTED_MODULE_1__[\\\"defaultConverter\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"notEqual\\\", function() { return _lib_updating_element_js__WEBPACK_IMPORTED_MODULE_1__[\\\"notEqual\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"UpdatingElement\\\", function() { return _lib_updating_element_js__WEBPACK_IMPORTED_MODULE_1__[\\\"UpdatingElement\\\"]; });\\n\\n/* harmony import */ var _lib_decorators_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./lib/decorators.js */ \\\"./node_modules/lit-element/lib/decorators.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"customElement\\\", function() { return _lib_decorators_js__WEBPACK_IMPORTED_MODULE_2__[\\\"customElement\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"property\\\", function() { return _lib_decorators_js__WEBPACK_IMPORTED_MODULE_2__[\\\"property\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"internalProperty\\\", function() { return _lib_decorators_js__WEBPACK_IMPORTED_MODULE_2__[\\\"internalProperty\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"query\\\", function() { return _lib_decorators_js__WEBPACK_IMPORTED_MODULE_2__[\\\"query\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"queryAsync\\\", function() { return _lib_decorators_js__WEBPACK_IMPORTED_MODULE_2__[\\\"queryAsync\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"queryAll\\\", function() { return _lib_decorators_js__WEBPACK_IMPORTED_MODULE_2__[\\\"queryAll\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"eventOptions\\\", function() { return _lib_decorators_js__WEBPACK_IMPORTED_MODULE_2__[\\\"eventOptions\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"queryAssignedNodes\\\", function() { return _lib_decorators_js__WEBPACK_IMPORTED_MODULE_2__[\\\"queryAssignedNodes\\\"]; });\\n\\n/* harmony import */ var lit_html_lit_html_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! lit-html/lit-html.js */ \\\"./node_modules/lit-html/lit-html.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"html\\\", function() { return lit_html_lit_html_js__WEBPACK_IMPORTED_MODULE_3__[\\\"html\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"svg\\\", function() { return lit_html_lit_html_js__WEBPACK_IMPORTED_MODULE_3__[\\\"svg\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"TemplateResult\\\", function() { return lit_html_lit_html_js__WEBPACK_IMPORTED_MODULE_3__[\\\"TemplateResult\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"SVGTemplateResult\\\", function() { return lit_html_lit_html_js__WEBPACK_IMPORTED_MODULE_3__[\\\"SVGTemplateResult\\\"]; });\\n\\n/* harmony import */ var _lib_css_tag_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./lib/css-tag.js */ \\\"./node_modules/lit-element/lib/css-tag.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"supportsAdoptingStyleSheets\\\", function() { return _lib_css_tag_js__WEBPACK_IMPORTED_MODULE_4__[\\\"supportsAdoptingStyleSheets\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"CSSResult\\\", function() { return _lib_css_tag_js__WEBPACK_IMPORTED_MODULE_4__[\\\"CSSResult\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"unsafeCSS\\\", function() { return _lib_css_tag_js__WEBPACK_IMPORTED_MODULE_4__[\\\"unsafeCSS\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"css\\\", function() { return _lib_css_tag_js__WEBPACK_IMPORTED_MODULE_4__[\\\"css\\\"]; });\\n\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n\\n\\n\\n\\n\\n\\n\\n// IMPORTANT: do not change the property name or the assignment expression.\\n// This line will be used in regexes to search for LitElement usage.\\n// TODO(justinfagnani): inject version number at build time\\n(window['litElementVersions'] || (window['litElementVersions'] = []))\\n    .push('2.3.1');\\n/**\\n * Sentinal value used to avoid calling lit-html's render function when\\n * subclasses do not implement `render`\\n */\\nconst renderNotImplemented = {};\\nclass LitElement extends _lib_updating_element_js__WEBPACK_IMPORTED_MODULE_1__[\\\"UpdatingElement\\\"] {\\n    /**\\n     * Return the array of styles to apply to the element.\\n     * Override this method to integrate into a style management system.\\n     *\\n     * @nocollapse\\n     */\\n    static getStyles() {\\n        return this.styles;\\n    }\\n    /** @nocollapse */\\n    static _getUniqueStyles() {\\n        // Only gather styles once per class\\n        if (this.hasOwnProperty(JSCompiler_renameProperty('_styles', this))) {\\n            return;\\n        }\\n        // Take care not to call `this.getStyles()` multiple times since this\\n        // generates new CSSResults each time.\\n        // TODO(sorvell): Since we do not cache CSSResults by input, any\\n        // shared styles will generate new stylesheet objects, which is wasteful.\\n        // This should be addressed when a browser ships constructable\\n        // stylesheets.\\n        const userStyles = this.getStyles();\\n        if (userStyles === undefined) {\\n            this._styles = [];\\n        }\\n        else if (Array.isArray(userStyles)) {\\n            // De-duplicate styles preserving the _last_ instance in the set.\\n            // This is a performance optimization to avoid duplicated styles that can\\n            // occur especially when composing via subclassing.\\n            // The last item is kept to try to preserve the cascade order with the\\n            // assumption that it's most important that last added styles override\\n            // previous styles.\\n            const addStyles = (styles, set) => styles.reduceRight((set, s) => \\n            // Note: On IE set.add() does not return the set\\n            Array.isArray(s) ? addStyles(s, set) : (set.add(s), set), set);\\n            // Array.from does not work on Set in IE, otherwise return\\n            // Array.from(addStyles(userStyles, new Set<CSSResult>())).reverse()\\n            const set = addStyles(userStyles, new Set());\\n            const styles = [];\\n            set.forEach((v) => styles.unshift(v));\\n            this._styles = styles;\\n        }\\n        else {\\n            this._styles = [userStyles];\\n        }\\n    }\\n    /**\\n     * Performs element initialization. By default this calls `createRenderRoot`\\n     * to create the element `renderRoot` node and captures any pre-set values for\\n     * registered properties.\\n     */\\n    initialize() {\\n        super.initialize();\\n        this.constructor._getUniqueStyles();\\n        this.renderRoot =\\n            this.createRenderRoot();\\n        // Note, if renderRoot is not a shadowRoot, styles would/could apply to the\\n        // element's getRootNode(). While this could be done, we're choosing not to\\n        // support this now since it would require different logic around de-duping.\\n        if (window.ShadowRoot && this.renderRoot instanceof window.ShadowRoot) {\\n            this.adoptStyles();\\n        }\\n    }\\n    /**\\n     * Returns the node into which the element should render and by default\\n     * creates and returns an open shadowRoot. Implement to customize where the\\n     * element's DOM is rendered. For example, to render into the element's\\n     * childNodes, return `this`.\\n     * @returns {Element|DocumentFragment} Returns a node into which to render.\\n     */\\n    createRenderRoot() {\\n        return this.attachShadow({ mode: 'open' });\\n    }\\n    /**\\n     * Applies styling to the element shadowRoot using the `static get styles`\\n     * property. Styling will apply using `shadowRoot.adoptedStyleSheets` where\\n     * available and will fallback otherwise. When Shadow DOM is polyfilled,\\n     * ShadyCSS scopes styles and adds them to the document. When Shadow DOM\\n     * is available but `adoptedStyleSheets` is not, styles are appended to the\\n     * end of the `shadowRoot` to [mimic spec\\n     * behavior](https://wicg.github.io/construct-stylesheets/#using-constructed-stylesheets).\\n     */\\n    adoptStyles() {\\n        const styles = this.constructor._styles;\\n        if (styles.length === 0) {\\n            return;\\n        }\\n        // There are three separate cases here based on Shadow DOM support.\\n        // (1) shadowRoot polyfilled: use ShadyCSS\\n        // (2) shadowRoot.adoptedStyleSheets available: use it.\\n        // (3) shadowRoot.adoptedStyleSheets polyfilled: append styles after\\n        // rendering\\n        if (window.ShadyCSS !== undefined && !window.ShadyCSS.nativeShadow) {\\n            window.ShadyCSS.ScopingShim.prepareAdoptedCssText(styles.map((s) => s.cssText), this.localName);\\n        }\\n        else if (_lib_css_tag_js__WEBPACK_IMPORTED_MODULE_4__[\\\"supportsAdoptingStyleSheets\\\"]) {\\n            this.renderRoot.adoptedStyleSheets =\\n                styles.map((s) => s.styleSheet);\\n        }\\n        else {\\n            // This must be done after rendering so the actual style insertion is done\\n            // in `update`.\\n            this._needsShimAdoptedStyleSheets = true;\\n        }\\n    }\\n    connectedCallback() {\\n        super.connectedCallback();\\n        // Note, first update/render handles styleElement so we only call this if\\n        // connected after first update.\\n        if (this.hasUpdated && window.ShadyCSS !== undefined) {\\n            window.ShadyCSS.styleElement(this);\\n        }\\n    }\\n    /**\\n     * Updates the element. This method reflects property values to attributes\\n     * and calls `render` to render DOM via lit-html. Setting properties inside\\n     * this method will *not* trigger another update.\\n     * @param _changedProperties Map of changed properties with old values\\n     */\\n    update(changedProperties) {\\n        // Setting properties in `render` should not trigger an update. Since\\n        // updates are allowed after super.update, it's important to call `render`\\n        // before that.\\n        const templateResult = this.render();\\n        super.update(changedProperties);\\n        // If render is not implemented by the component, don't call lit-html render\\n        if (templateResult !== renderNotImplemented) {\\n            this.constructor\\n                .render(templateResult, this.renderRoot, { scopeName: this.localName, eventContext: this });\\n        }\\n        // When native Shadow DOM is used but adoptedStyles are not supported,\\n        // insert styling after rendering to ensure adoptedStyles have highest\\n        // priority.\\n        if (this._needsShimAdoptedStyleSheets) {\\n            this._needsShimAdoptedStyleSheets = false;\\n            this.constructor._styles.forEach((s) => {\\n                const style = document.createElement('style');\\n                style.textContent = s.cssText;\\n                this.renderRoot.appendChild(style);\\n            });\\n        }\\n    }\\n    /**\\n     * Invoked on each update to perform rendering tasks. This method may return\\n     * any value renderable by lit-html's NodePart - typically a TemplateResult.\\n     * Setting properties inside this method will *not* trigger the element to\\n     * update.\\n     */\\n    render() {\\n        return renderNotImplemented;\\n    }\\n}\\n/**\\n * Ensure this class is marked as `finalized` as an optimization ensuring\\n * it will not needlessly try to `finalize`.\\n *\\n * Note this property name is a string to prevent breaking Closure JS Compiler\\n * optimizations. See updating-element.ts for more information.\\n */\\nLitElement['finalized'] = true;\\n/**\\n * Render method used to render the value to the element's DOM.\\n * @param result The value to render.\\n * @param container Node into which to render.\\n * @param options Element name.\\n * @nocollapse\\n */\\nLitElement.render = lit_html_lib_shady_render_js__WEBPACK_IMPORTED_MODULE_0__[\\\"render\\\"];\\n//# sourceMappingURL=lit-element.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-element/lit-element.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/directives/class-map.js\":\n/*!*******************************************************!*\\\n  !*** ./node_modules/lit-html/directives/class-map.js ***!\n  \\*******************************************************/\n/*! exports provided: classMap */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"classMap\\\", function() { return classMap; });\\n/* harmony import */ var _lit_html_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../lit-html.js */ \\\"./node_modules/lit-html/lit-html.js\\\");\\n/**\\n * @license\\n * Copyright (c) 2018 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n\\n// IE11 doesn't support classList on SVG elements, so we emulate it with a Set\\nclass ClassList {\\n    constructor(element) {\\n        this.classes = new Set();\\n        this.changed = false;\\n        this.element = element;\\n        const classList = (element.getAttribute('class') || '').split(/\\\\s+/);\\n        for (const cls of classList) {\\n            this.classes.add(cls);\\n        }\\n    }\\n    add(cls) {\\n        this.classes.add(cls);\\n        this.changed = true;\\n    }\\n    remove(cls) {\\n        this.classes.delete(cls);\\n        this.changed = true;\\n    }\\n    commit() {\\n        if (this.changed) {\\n            let classString = '';\\n            this.classes.forEach((cls) => classString += cls + ' ');\\n            this.element.setAttribute('class', classString);\\n        }\\n    }\\n}\\n/**\\n * Stores the ClassInfo object applied to a given AttributePart.\\n * Used to unset existing values when a new ClassInfo object is applied.\\n */\\nconst previousClassesCache = new WeakMap();\\n/**\\n * A directive that applies CSS classes. This must be used in the `class`\\n * attribute and must be the only part used in the attribute. It takes each\\n * property in the `classInfo` argument and adds the property name to the\\n * element's `class` if the property value is truthy; if the property value is\\n * falsey, the property name is removed from the element's `class`. For example\\n * `{foo: bar}` applies the class `foo` if the value of `bar` is truthy.\\n * @param classInfo {ClassInfo}\\n */\\nconst classMap = Object(_lit_html_js__WEBPACK_IMPORTED_MODULE_0__[\\\"directive\\\"])((classInfo) => (part) => {\\n    if (!(part instanceof _lit_html_js__WEBPACK_IMPORTED_MODULE_0__[\\\"AttributePart\\\"]) || (part instanceof _lit_html_js__WEBPACK_IMPORTED_MODULE_0__[\\\"PropertyPart\\\"]) ||\\n        part.committer.name !== 'class' || part.committer.parts.length > 1) {\\n        throw new Error('The `classMap` directive must be used in the `class` attribute ' +\\n            'and must be the only part in the attribute.');\\n    }\\n    const { committer } = part;\\n    const { element } = committer;\\n    let previousClasses = previousClassesCache.get(part);\\n    if (previousClasses === undefined) {\\n        // Write static classes once\\n        // Use setAttribute() because className isn't a string on SVG elements\\n        element.setAttribute('class', committer.strings.join(' '));\\n        previousClassesCache.set(part, previousClasses = new Set());\\n    }\\n    const classList = (element.classList || new ClassList(element));\\n    // Remove old classes that no longer apply\\n    // We use forEach() instead of for-of so that re don't require down-level\\n    // iteration.\\n    previousClasses.forEach((name) => {\\n        if (!(name in classInfo)) {\\n            classList.remove(name);\\n            previousClasses.delete(name);\\n        }\\n    });\\n    // Add or remove classes based on their classMap value\\n    for (const name in classInfo) {\\n        const value = classInfo[name];\\n        if (value != previousClasses.has(name)) {\\n            // We explicitly want a loose truthy check of `value` because it seems\\n            // more convenient that '' and 0 are skipped.\\n            if (value) {\\n                classList.add(name);\\n                previousClasses.add(name);\\n            }\\n            else {\\n                classList.remove(name);\\n                previousClasses.delete(name);\\n            }\\n        }\\n    }\\n    if (typeof classList.commit === 'function') {\\n        classList.commit();\\n    }\\n});\\n//# sourceMappingURL=class-map.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/directives/class-map.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/directives/style-map.js\":\n/*!*******************************************************!*\\\n  !*** ./node_modules/lit-html/directives/style-map.js ***!\n  \\*******************************************************/\n/*! exports provided: styleMap */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"styleMap\\\", function() { return styleMap; });\\n/* harmony import */ var _lit_html_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../lit-html.js */ \\\"./node_modules/lit-html/lit-html.js\\\");\\n/**\\n * @license\\n * Copyright (c) 2018 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n\\n/**\\n * Stores the StyleInfo object applied to a given AttributePart.\\n * Used to unset existing values when a new StyleInfo object is applied.\\n */\\nconst previousStylePropertyCache = new WeakMap();\\n/**\\n * A directive that applies CSS properties to an element.\\n *\\n * `styleMap` can only be used in the `style` attribute and must be the only\\n * expression in the attribute. It takes the property names in the `styleInfo`\\n * object and adds the property values as CSS properties. Property names with\\n * dashes (`-`) are assumed to be valid CSS property names and set on the\\n * element's style object using `setProperty()`. Names without dashes are\\n * assumed to be camelCased JavaScript property names and set on the element's\\n * style object using property assignment, allowing the style object to\\n * translate JavaScript-style names to CSS property names.\\n *\\n * For example `styleMap({backgroundColor: 'red', 'border-top': '5px', '--size':\\n * '0'})` sets the `background-color`, `border-top` and `--size` properties.\\n *\\n * @param styleInfo {StyleInfo}\\n */\\nconst styleMap = Object(_lit_html_js__WEBPACK_IMPORTED_MODULE_0__[\\\"directive\\\"])((styleInfo) => (part) => {\\n    if (!(part instanceof _lit_html_js__WEBPACK_IMPORTED_MODULE_0__[\\\"AttributePart\\\"]) || (part instanceof _lit_html_js__WEBPACK_IMPORTED_MODULE_0__[\\\"PropertyPart\\\"]) ||\\n        part.committer.name !== 'style' || part.committer.parts.length > 1) {\\n        throw new Error('The `styleMap` directive must be used in the style attribute ' +\\n            'and must be the only part in the attribute.');\\n    }\\n    const { committer } = part;\\n    const { style } = committer.element;\\n    let previousStyleProperties = previousStylePropertyCache.get(part);\\n    if (previousStyleProperties === undefined) {\\n        // Write static styles once\\n        style.cssText = committer.strings.join(' ');\\n        previousStylePropertyCache.set(part, previousStyleProperties = new Set());\\n    }\\n    // Remove old properties that no longer exist in styleInfo\\n    // We use forEach() instead of for-of so that re don't require down-level\\n    // iteration.\\n    previousStyleProperties.forEach((name) => {\\n        if (!(name in styleInfo)) {\\n            previousStyleProperties.delete(name);\\n            if (name.indexOf('-') === -1) {\\n                // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n                style[name] = null;\\n            }\\n            else {\\n                style.removeProperty(name);\\n            }\\n        }\\n    });\\n    // Add or update properties\\n    for (const name in styleInfo) {\\n        previousStyleProperties.add(name);\\n        if (name.indexOf('-') === -1) {\\n            // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n            style[name] = styleInfo[name];\\n        }\\n        else {\\n            style.setProperty(name, styleInfo[name]);\\n        }\\n    }\\n});\\n//# sourceMappingURL=style-map.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/directives/style-map.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/default-template-processor.js\":\n/*!*****************************************************************!*\\\n  !*** ./node_modules/lit-html/lib/default-template-processor.js ***!\n  \\*****************************************************************/\n/*! exports provided: DefaultTemplateProcessor, defaultTemplateProcessor */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"DefaultTemplateProcessor\\\", function() { return DefaultTemplateProcessor; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"defaultTemplateProcessor\\\", function() { return defaultTemplateProcessor; });\\n/* harmony import */ var _parts_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./parts.js */ \\\"./node_modules/lit-html/lib/parts.js\\\");\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n\\n/**\\n * Creates Parts when a template is instantiated.\\n */\\nclass DefaultTemplateProcessor {\\n    /**\\n     * Create parts for an attribute-position binding, given the event, attribute\\n     * name, and string literals.\\n     *\\n     * @param element The element containing the binding\\n     * @param name  The attribute name\\n     * @param strings The string literals. There are always at least two strings,\\n     *   event for fully-controlled bindings with a single expression.\\n     */\\n    handleAttributeExpressions(element, name, strings, options) {\\n        const prefix = name[0];\\n        if (prefix === '.') {\\n            const committer = new _parts_js__WEBPACK_IMPORTED_MODULE_0__[\\\"PropertyCommitter\\\"](element, name.slice(1), strings);\\n            return committer.parts;\\n        }\\n        if (prefix === '@') {\\n            return [new _parts_js__WEBPACK_IMPORTED_MODULE_0__[\\\"EventPart\\\"](element, name.slice(1), options.eventContext)];\\n        }\\n        if (prefix === '?') {\\n            return [new _parts_js__WEBPACK_IMPORTED_MODULE_0__[\\\"BooleanAttributePart\\\"](element, name.slice(1), strings)];\\n        }\\n        const committer = new _parts_js__WEBPACK_IMPORTED_MODULE_0__[\\\"AttributeCommitter\\\"](element, name, strings);\\n        return committer.parts;\\n    }\\n    /**\\n     * Create parts for a text-position binding.\\n     * @param templateFactory\\n     */\\n    handleTextExpression(options) {\\n        return new _parts_js__WEBPACK_IMPORTED_MODULE_0__[\\\"NodePart\\\"](options);\\n    }\\n}\\nconst defaultTemplateProcessor = new DefaultTemplateProcessor();\\n//# sourceMappingURL=default-template-processor.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/default-template-processor.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/directive.js\":\n/*!************************************************!*\\\n  !*** ./node_modules/lit-html/lib/directive.js ***!\n  \\************************************************/\n/*! exports provided: directive, isDirective */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"directive\\\", function() { return directive; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"isDirective\\\", function() { return isDirective; });\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\nconst directives = new WeakMap();\\n/**\\n * Brands a function as a directive factory function so that lit-html will call\\n * the function during template rendering, rather than passing as a value.\\n *\\n * A _directive_ is a function that takes a Part as an argument. It has the\\n * signature: `(part: Part) => void`.\\n *\\n * A directive _factory_ is a function that takes arguments for data and\\n * configuration and returns a directive. Users of directive usually refer to\\n * the directive factory as the directive. For example, \\\"The repeat directive\\\".\\n *\\n * Usually a template author will invoke a directive factory in their template\\n * with relevant arguments, which will then return a directive function.\\n *\\n * Here's an example of using the `repeat()` directive factory that takes an\\n * array and a function to render an item:\\n *\\n * ```js\\n * html`<ul><${repeat(items, (item) => html`<li>${item}</li>`)}</ul>`\\n * ```\\n *\\n * When `repeat` is invoked, it returns a directive function that closes over\\n * `items` and the template function. When the outer template is rendered, the\\n * return directive function is called with the Part for the expression.\\n * `repeat` then performs it's custom logic to render multiple items.\\n *\\n * @param f The directive factory function. Must be a function that returns a\\n * function of the signature `(part: Part) => void`. The returned function will\\n * be called with the part object.\\n *\\n * @example\\n *\\n * import {directive, html} from 'lit-html';\\n *\\n * const immutable = directive((v) => (part) => {\\n *   if (part.value !== v) {\\n *     part.setValue(v)\\n *   }\\n * });\\n */\\nconst directive = (f) => ((...args) => {\\n    const d = f(...args);\\n    directives.set(d, true);\\n    return d;\\n});\\nconst isDirective = (o) => {\\n    return typeof o === 'function' && directives.has(o);\\n};\\n//# sourceMappingURL=directive.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/directive.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/dom.js\":\n/*!******************************************!*\\\n  !*** ./node_modules/lit-html/lib/dom.js ***!\n  \\******************************************/\n/*! exports provided: isCEPolyfill, reparentNodes, removeNodes */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"isCEPolyfill\\\", function() { return isCEPolyfill; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"reparentNodes\\\", function() { return reparentNodes; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"removeNodes\\\", function() { return removeNodes; });\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n/**\\n * True if the custom elements polyfill is in use.\\n */\\nconst isCEPolyfill = typeof window !== 'undefined' &&\\n    window.customElements != null &&\\n    window.customElements.polyfillWrapFlushCallback !==\\n        undefined;\\n/**\\n * Reparents nodes, starting from `start` (inclusive) to `end` (exclusive),\\n * into another container (could be the same container), before `before`. If\\n * `before` is null, it appends the nodes to the container.\\n */\\nconst reparentNodes = (container, start, end = null, before = null) => {\\n    while (start !== end) {\\n        const n = start.nextSibling;\\n        container.insertBefore(start, before);\\n        start = n;\\n    }\\n};\\n/**\\n * Removes nodes, starting from `start` (inclusive) to `end` (exclusive), from\\n * `container`.\\n */\\nconst removeNodes = (container, start, end = null) => {\\n    while (start !== end) {\\n        const n = start.nextSibling;\\n        container.removeChild(start);\\n        start = n;\\n    }\\n};\\n//# sourceMappingURL=dom.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/dom.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/modify-template.js\":\n/*!******************************************************!*\\\n  !*** ./node_modules/lit-html/lib/modify-template.js ***!\n  \\******************************************************/\n/*! exports provided: removeNodesFromTemplate, insertNodeIntoTemplate */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"removeNodesFromTemplate\\\", function() { return removeNodesFromTemplate; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"insertNodeIntoTemplate\\\", function() { return insertNodeIntoTemplate; });\\n/* harmony import */ var _template_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./template.js */ \\\"./node_modules/lit-html/lib/template.js\\\");\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n/**\\n * @module shady-render\\n */\\n\\nconst walkerNodeFilter = 133 /* NodeFilter.SHOW_{ELEMENT|COMMENT|TEXT} */;\\n/**\\n * Removes the list of nodes from a Template safely. In addition to removing\\n * nodes from the Template, the Template part indices are updated to match\\n * the mutated Template DOM.\\n *\\n * As the template is walked the removal state is tracked and\\n * part indices are adjusted as needed.\\n *\\n * div\\n *   div#1 (remove) <-- start removing (removing node is div#1)\\n *     div\\n *       div#2 (remove)  <-- continue removing (removing node is still div#1)\\n *         div\\n * div <-- stop removing since previous sibling is the removing node (div#1,\\n * removed 4 nodes)\\n */\\nfunction removeNodesFromTemplate(template, nodesToRemove) {\\n    const { element: { content }, parts } = template;\\n    const walker = document.createTreeWalker(content, walkerNodeFilter, null, false);\\n    let partIndex = nextActiveIndexInTemplateParts(parts);\\n    let part = parts[partIndex];\\n    let nodeIndex = -1;\\n    let removeCount = 0;\\n    const nodesToRemoveInTemplate = [];\\n    let currentRemovingNode = null;\\n    while (walker.nextNode()) {\\n        nodeIndex++;\\n        const node = walker.currentNode;\\n        // End removal if stepped past the removing node\\n        if (node.previousSibling === currentRemovingNode) {\\n            currentRemovingNode = null;\\n        }\\n        // A node to remove was found in the template\\n        if (nodesToRemove.has(node)) {\\n            nodesToRemoveInTemplate.push(node);\\n            // Track node we're removing\\n            if (currentRemovingNode === null) {\\n                currentRemovingNode = node;\\n            }\\n        }\\n        // When removing, increment count by which to adjust subsequent part indices\\n        if (currentRemovingNode !== null) {\\n            removeCount++;\\n        }\\n        while (part !== undefined && part.index === nodeIndex) {\\n            // If part is in a removed node deactivate it by setting index to -1 or\\n            // adjust the index as needed.\\n            part.index = currentRemovingNode !== null ? -1 : part.index - removeCount;\\n            // go to the next active part.\\n            partIndex = nextActiveIndexInTemplateParts(parts, partIndex);\\n            part = parts[partIndex];\\n        }\\n    }\\n    nodesToRemoveInTemplate.forEach((n) => n.parentNode.removeChild(n));\\n}\\nconst countNodes = (node) => {\\n    let count = (node.nodeType === 11 /* Node.DOCUMENT_FRAGMENT_NODE */) ? 0 : 1;\\n    const walker = document.createTreeWalker(node, walkerNodeFilter, null, false);\\n    while (walker.nextNode()) {\\n        count++;\\n    }\\n    return count;\\n};\\nconst nextActiveIndexInTemplateParts = (parts, startIndex = -1) => {\\n    for (let i = startIndex + 1; i < parts.length; i++) {\\n        const part = parts[i];\\n        if (Object(_template_js__WEBPACK_IMPORTED_MODULE_0__[\\\"isTemplatePartActive\\\"])(part)) {\\n            return i;\\n        }\\n    }\\n    return -1;\\n};\\n/**\\n * Inserts the given node into the Template, optionally before the given\\n * refNode. In addition to inserting the node into the Template, the Template\\n * part indices are updated to match the mutated Template DOM.\\n */\\nfunction insertNodeIntoTemplate(template, node, refNode = null) {\\n    const { element: { content }, parts } = template;\\n    // If there's no refNode, then put node at end of template.\\n    // No part indices need to be shifted in this case.\\n    if (refNode === null || refNode === undefined) {\\n        content.appendChild(node);\\n        return;\\n    }\\n    const walker = document.createTreeWalker(content, walkerNodeFilter, null, false);\\n    let partIndex = nextActiveIndexInTemplateParts(parts);\\n    let insertCount = 0;\\n    let walkerIndex = -1;\\n    while (walker.nextNode()) {\\n        walkerIndex++;\\n        const walkerNode = walker.currentNode;\\n        if (walkerNode === refNode) {\\n            insertCount = countNodes(node);\\n            refNode.parentNode.insertBefore(node, refNode);\\n        }\\n        while (partIndex !== -1 && parts[partIndex].index === walkerIndex) {\\n            // If we've inserted the node, simply adjust all subsequent parts\\n            if (insertCount > 0) {\\n                while (partIndex !== -1) {\\n                    parts[partIndex].index += insertCount;\\n                    partIndex = nextActiveIndexInTemplateParts(parts, partIndex);\\n                }\\n                return;\\n            }\\n            partIndex = nextActiveIndexInTemplateParts(parts, partIndex);\\n        }\\n    }\\n}\\n//# sourceMappingURL=modify-template.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/modify-template.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/part.js\":\n/*!*******************************************!*\\\n  !*** ./node_modules/lit-html/lib/part.js ***!\n  \\*******************************************/\n/*! exports provided: noChange, nothing */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"noChange\\\", function() { return noChange; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"nothing\\\", function() { return nothing; });\\n/**\\n * @license\\n * Copyright (c) 2018 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n/**\\n * A sentinel value that signals that a value was handled by a directive and\\n * should not be written to the DOM.\\n */\\nconst noChange = {};\\n/**\\n * A sentinel value that signals a NodePart to fully clear its content.\\n */\\nconst nothing = {};\\n//# sourceMappingURL=part.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/part.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/parts.js\":\n/*!********************************************!*\\\n  !*** ./node_modules/lit-html/lib/parts.js ***!\n  \\********************************************/\n/*! exports provided: isPrimitive, isIterable, AttributeCommitter, AttributePart, NodePart, BooleanAttributePart, PropertyCommitter, PropertyPart, EventPart */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"isPrimitive\\\", function() { return isPrimitive; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"isIterable\\\", function() { return isIterable; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"AttributeCommitter\\\", function() { return AttributeCommitter; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"AttributePart\\\", function() { return AttributePart; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"NodePart\\\", function() { return NodePart; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"BooleanAttributePart\\\", function() { return BooleanAttributePart; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"PropertyCommitter\\\", function() { return PropertyCommitter; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"PropertyPart\\\", function() { return PropertyPart; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"EventPart\\\", function() { return EventPart; });\\n/* harmony import */ var _directive_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./directive.js */ \\\"./node_modules/lit-html/lib/directive.js\\\");\\n/* harmony import */ var _dom_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./dom.js */ \\\"./node_modules/lit-html/lib/dom.js\\\");\\n/* harmony import */ var _part_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./part.js */ \\\"./node_modules/lit-html/lib/part.js\\\");\\n/* harmony import */ var _template_instance_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./template-instance.js */ \\\"./node_modules/lit-html/lib/template-instance.js\\\");\\n/* harmony import */ var _template_result_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./template-result.js */ \\\"./node_modules/lit-html/lib/template-result.js\\\");\\n/* harmony import */ var _template_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./template.js */ \\\"./node_modules/lit-html/lib/template.js\\\");\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n/**\\n * @module lit-html\\n */\\n\\n\\n\\n\\n\\n\\nconst isPrimitive = (value) => {\\n    return (value === null ||\\n        !(typeof value === 'object' || typeof value === 'function'));\\n};\\nconst isIterable = (value) => {\\n    return Array.isArray(value) ||\\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n        !!(value && value[Symbol.iterator]);\\n};\\n/**\\n * Writes attribute values to the DOM for a group of AttributeParts bound to a\\n * single attribute. The value is only set once even if there are multiple parts\\n * for an attribute.\\n */\\nclass AttributeCommitter {\\n    constructor(element, name, strings) {\\n        this.dirty = true;\\n        this.element = element;\\n        this.name = name;\\n        this.strings = strings;\\n        this.parts = [];\\n        for (let i = 0; i < strings.length - 1; i++) {\\n            this.parts[i] = this._createPart();\\n        }\\n    }\\n    /**\\n     * Creates a single part. Override this to create a differnt type of part.\\n     */\\n    _createPart() {\\n        return new AttributePart(this);\\n    }\\n    _getValue() {\\n        const strings = this.strings;\\n        const l = strings.length - 1;\\n        let text = '';\\n        for (let i = 0; i < l; i++) {\\n            text += strings[i];\\n            const part = this.parts[i];\\n            if (part !== undefined) {\\n                const v = part.value;\\n                if (isPrimitive(v) || !isIterable(v)) {\\n                    text += typeof v === 'string' ? v : String(v);\\n                }\\n                else {\\n                    for (const t of v) {\\n                        text += typeof t === 'string' ? t : String(t);\\n                    }\\n                }\\n            }\\n        }\\n        text += strings[l];\\n        return text;\\n    }\\n    commit() {\\n        if (this.dirty) {\\n            this.dirty = false;\\n            this.element.setAttribute(this.name, this._getValue());\\n        }\\n    }\\n}\\n/**\\n * A Part that controls all or part of an attribute value.\\n */\\nclass AttributePart {\\n    constructor(committer) {\\n        this.value = undefined;\\n        this.committer = committer;\\n    }\\n    setValue(value) {\\n        if (value !== _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"] && (!isPrimitive(value) || value !== this.value)) {\\n            this.value = value;\\n            // If the value is a not a directive, dirty the committer so that it'll\\n            // call setAttribute. If the value is a directive, it'll dirty the\\n            // committer if it calls setValue().\\n            if (!Object(_directive_js__WEBPACK_IMPORTED_MODULE_0__[\\\"isDirective\\\"])(value)) {\\n                this.committer.dirty = true;\\n            }\\n        }\\n    }\\n    commit() {\\n        while (Object(_directive_js__WEBPACK_IMPORTED_MODULE_0__[\\\"isDirective\\\"])(this.value)) {\\n            const directive = this.value;\\n            this.value = _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"];\\n            directive(this);\\n        }\\n        if (this.value === _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"]) {\\n            return;\\n        }\\n        this.committer.commit();\\n    }\\n}\\n/**\\n * A Part that controls a location within a Node tree. Like a Range, NodePart\\n * has start and end locations and can set and update the Nodes between those\\n * locations.\\n *\\n * NodeParts support several value types: primitives, Nodes, TemplateResults,\\n * as well as arrays and iterables of those types.\\n */\\nclass NodePart {\\n    constructor(options) {\\n        this.value = undefined;\\n        this.__pendingValue = undefined;\\n        this.options = options;\\n    }\\n    /**\\n     * Appends this part into a container.\\n     *\\n     * This part must be empty, as its contents are not automatically moved.\\n     */\\n    appendInto(container) {\\n        this.startNode = container.appendChild(Object(_template_js__WEBPACK_IMPORTED_MODULE_5__[\\\"createMarker\\\"])());\\n        this.endNode = container.appendChild(Object(_template_js__WEBPACK_IMPORTED_MODULE_5__[\\\"createMarker\\\"])());\\n    }\\n    /**\\n     * Inserts this part after the `ref` node (between `ref` and `ref`'s next\\n     * sibling). Both `ref` and its next sibling must be static, unchanging nodes\\n     * such as those that appear in a literal section of a template.\\n     *\\n     * This part must be empty, as its contents are not automatically moved.\\n     */\\n    insertAfterNode(ref) {\\n        this.startNode = ref;\\n        this.endNode = ref.nextSibling;\\n    }\\n    /**\\n     * Appends this part into a parent part.\\n     *\\n     * This part must be empty, as its contents are not automatically moved.\\n     */\\n    appendIntoPart(part) {\\n        part.__insert(this.startNode = Object(_template_js__WEBPACK_IMPORTED_MODULE_5__[\\\"createMarker\\\"])());\\n        part.__insert(this.endNode = Object(_template_js__WEBPACK_IMPORTED_MODULE_5__[\\\"createMarker\\\"])());\\n    }\\n    /**\\n     * Inserts this part after the `ref` part.\\n     *\\n     * This part must be empty, as its contents are not automatically moved.\\n     */\\n    insertAfterPart(ref) {\\n        ref.__insert(this.startNode = Object(_template_js__WEBPACK_IMPORTED_MODULE_5__[\\\"createMarker\\\"])());\\n        this.endNode = ref.endNode;\\n        ref.endNode = this.startNode;\\n    }\\n    setValue(value) {\\n        this.__pendingValue = value;\\n    }\\n    commit() {\\n        if (this.startNode.parentNode === null) {\\n            return;\\n        }\\n        while (Object(_directive_js__WEBPACK_IMPORTED_MODULE_0__[\\\"isDirective\\\"])(this.__pendingValue)) {\\n            const directive = this.__pendingValue;\\n            this.__pendingValue = _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"];\\n            directive(this);\\n        }\\n        const value = this.__pendingValue;\\n        if (value === _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"]) {\\n            return;\\n        }\\n        if (isPrimitive(value)) {\\n            if (value !== this.value) {\\n                this.__commitText(value);\\n            }\\n        }\\n        else if (value instanceof _template_result_js__WEBPACK_IMPORTED_MODULE_4__[\\\"TemplateResult\\\"]) {\\n            this.__commitTemplateResult(value);\\n        }\\n        else if (value instanceof Node) {\\n            this.__commitNode(value);\\n        }\\n        else if (isIterable(value)) {\\n            this.__commitIterable(value);\\n        }\\n        else if (value === _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"nothing\\\"]) {\\n            this.value = _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"nothing\\\"];\\n            this.clear();\\n        }\\n        else {\\n            // Fallback, will render the string representation\\n            this.__commitText(value);\\n        }\\n    }\\n    __insert(node) {\\n        this.endNode.parentNode.insertBefore(node, this.endNode);\\n    }\\n    __commitNode(value) {\\n        if (this.value === value) {\\n            return;\\n        }\\n        this.clear();\\n        this.__insert(value);\\n        this.value = value;\\n    }\\n    __commitText(value) {\\n        const node = this.startNode.nextSibling;\\n        value = value == null ? '' : value;\\n        // If `value` isn't already a string, we explicitly convert it here in case\\n        // it can't be implicitly converted - i.e. it's a symbol.\\n        const valueAsString = typeof value === 'string' ? value : String(value);\\n        if (node === this.endNode.previousSibling &&\\n            node.nodeType === 3 /* Node.TEXT_NODE */) {\\n            // If we only have a single text node between the markers, we can just\\n            // set its value, rather than replacing it.\\n            // TODO(justinfagnani): Can we just check if this.value is primitive?\\n            node.data = valueAsString;\\n        }\\n        else {\\n            this.__commitNode(document.createTextNode(valueAsString));\\n        }\\n        this.value = value;\\n    }\\n    __commitTemplateResult(value) {\\n        const template = this.options.templateFactory(value);\\n        if (this.value instanceof _template_instance_js__WEBPACK_IMPORTED_MODULE_3__[\\\"TemplateInstance\\\"] &&\\n            this.value.template === template) {\\n            this.value.update(value.values);\\n        }\\n        else {\\n            // Make sure we propagate the template processor from the TemplateResult\\n            // so that we use its syntax extension, etc. The template factory comes\\n            // from the render function options so that it can control template\\n            // caching and preprocessing.\\n            const instance = new _template_instance_js__WEBPACK_IMPORTED_MODULE_3__[\\\"TemplateInstance\\\"](template, value.processor, this.options);\\n            const fragment = instance._clone();\\n            instance.update(value.values);\\n            this.__commitNode(fragment);\\n            this.value = instance;\\n        }\\n    }\\n    __commitIterable(value) {\\n        // For an Iterable, we create a new InstancePart per item, then set its\\n        // value to the item. This is a little bit of overhead for every item in\\n        // an Iterable, but it lets us recurse easily and efficiently update Arrays\\n        // of TemplateResults that will be commonly returned from expressions like:\\n        // array.map((i) => html`${i}`), by reusing existing TemplateInstances.\\n        // If _value is an array, then the previous render was of an\\n        // iterable and _value will contain the NodeParts from the previous\\n        // render. If _value is not an array, clear this part and make a new\\n        // array for NodeParts.\\n        if (!Array.isArray(this.value)) {\\n            this.value = [];\\n            this.clear();\\n        }\\n        // Lets us keep track of how many items we stamped so we can clear leftover\\n        // items from a previous render\\n        const itemParts = this.value;\\n        let partIndex = 0;\\n        let itemPart;\\n        for (const item of value) {\\n            // Try to reuse an existing part\\n            itemPart = itemParts[partIndex];\\n            // If no existing part, create a new one\\n            if (itemPart === undefined) {\\n                itemPart = new NodePart(this.options);\\n                itemParts.push(itemPart);\\n                if (partIndex === 0) {\\n                    itemPart.appendIntoPart(this);\\n                }\\n                else {\\n                    itemPart.insertAfterPart(itemParts[partIndex - 1]);\\n                }\\n            }\\n            itemPart.setValue(item);\\n            itemPart.commit();\\n            partIndex++;\\n        }\\n        if (partIndex < itemParts.length) {\\n            // Truncate the parts array so _value reflects the current state\\n            itemParts.length = partIndex;\\n            this.clear(itemPart && itemPart.endNode);\\n        }\\n    }\\n    clear(startNode = this.startNode) {\\n        Object(_dom_js__WEBPACK_IMPORTED_MODULE_1__[\\\"removeNodes\\\"])(this.startNode.parentNode, startNode.nextSibling, this.endNode);\\n    }\\n}\\n/**\\n * Implements a boolean attribute, roughly as defined in the HTML\\n * specification.\\n *\\n * If the value is truthy, then the attribute is present with a value of\\n * ''. If the value is falsey, the attribute is removed.\\n */\\nclass BooleanAttributePart {\\n    constructor(element, name, strings) {\\n        this.value = undefined;\\n        this.__pendingValue = undefined;\\n        if (strings.length !== 2 || strings[0] !== '' || strings[1] !== '') {\\n            throw new Error('Boolean attributes can only contain a single expression');\\n        }\\n        this.element = element;\\n        this.name = name;\\n        this.strings = strings;\\n    }\\n    setValue(value) {\\n        this.__pendingValue = value;\\n    }\\n    commit() {\\n        while (Object(_directive_js__WEBPACK_IMPORTED_MODULE_0__[\\\"isDirective\\\"])(this.__pendingValue)) {\\n            const directive = this.__pendingValue;\\n            this.__pendingValue = _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"];\\n            directive(this);\\n        }\\n        if (this.__pendingValue === _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"]) {\\n            return;\\n        }\\n        const value = !!this.__pendingValue;\\n        if (this.value !== value) {\\n            if (value) {\\n                this.element.setAttribute(this.name, '');\\n            }\\n            else {\\n                this.element.removeAttribute(this.name);\\n            }\\n            this.value = value;\\n        }\\n        this.__pendingValue = _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"];\\n    }\\n}\\n/**\\n * Sets attribute values for PropertyParts, so that the value is only set once\\n * even if there are multiple parts for a property.\\n *\\n * If an expression controls the whole property value, then the value is simply\\n * assigned to the property under control. If there are string literals or\\n * multiple expressions, then the strings are expressions are interpolated into\\n * a string first.\\n */\\nclass PropertyCommitter extends AttributeCommitter {\\n    constructor(element, name, strings) {\\n        super(element, name, strings);\\n        this.single =\\n            (strings.length === 2 && strings[0] === '' && strings[1] === '');\\n    }\\n    _createPart() {\\n        return new PropertyPart(this);\\n    }\\n    _getValue() {\\n        if (this.single) {\\n            return this.parts[0].value;\\n        }\\n        return super._getValue();\\n    }\\n    commit() {\\n        if (this.dirty) {\\n            this.dirty = false;\\n            // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n            this.element[this.name] = this._getValue();\\n        }\\n    }\\n}\\nclass PropertyPart extends AttributePart {\\n}\\n// Detect event listener options support. If the `capture` property is read\\n// from the options object, then options are supported. If not, then the third\\n// argument to add/removeEventListener is interpreted as the boolean capture\\n// value so we should only pass the `capture` property.\\nlet eventOptionsSupported = false;\\n// Wrap into an IIFE because MS Edge <= v41 does not support having try/catch\\n// blocks right into the body of a module\\n(() => {\\n    try {\\n        const options = {\\n            get capture() {\\n                eventOptionsSupported = true;\\n                return false;\\n            }\\n        };\\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n        window.addEventListener('test', options, options);\\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n        window.removeEventListener('test', options, options);\\n    }\\n    catch (_e) {\\n        // event options not supported\\n    }\\n})();\\nclass EventPart {\\n    constructor(element, eventName, eventContext) {\\n        this.value = undefined;\\n        this.__pendingValue = undefined;\\n        this.element = element;\\n        this.eventName = eventName;\\n        this.eventContext = eventContext;\\n        this.__boundHandleEvent = (e) => this.handleEvent(e);\\n    }\\n    setValue(value) {\\n        this.__pendingValue = value;\\n    }\\n    commit() {\\n        while (Object(_directive_js__WEBPACK_IMPORTED_MODULE_0__[\\\"isDirective\\\"])(this.__pendingValue)) {\\n            const directive = this.__pendingValue;\\n            this.__pendingValue = _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"];\\n            directive(this);\\n        }\\n        if (this.__pendingValue === _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"]) {\\n            return;\\n        }\\n        const newListener = this.__pendingValue;\\n        const oldListener = this.value;\\n        const shouldRemoveListener = newListener == null ||\\n            oldListener != null &&\\n                (newListener.capture !== oldListener.capture ||\\n                    newListener.once !== oldListener.once ||\\n                    newListener.passive !== oldListener.passive);\\n        const shouldAddListener = newListener != null && (oldListener == null || shouldRemoveListener);\\n        if (shouldRemoveListener) {\\n            this.element.removeEventListener(this.eventName, this.__boundHandleEvent, this.__options);\\n        }\\n        if (shouldAddListener) {\\n            this.__options = getOptions(newListener);\\n            this.element.addEventListener(this.eventName, this.__boundHandleEvent, this.__options);\\n        }\\n        this.value = newListener;\\n        this.__pendingValue = _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"];\\n    }\\n    handleEvent(event) {\\n        if (typeof this.value === 'function') {\\n            this.value.call(this.eventContext || this.element, event);\\n        }\\n        else {\\n            this.value.handleEvent(event);\\n        }\\n    }\\n}\\n// We copy options because of the inconsistent behavior of browsers when reading\\n// the third argument of add/removeEventListener. IE11 doesn't support options\\n// at all. Chrome 41 only reads `capture` if the argument is an object.\\nconst getOptions = (o) => o &&\\n    (eventOptionsSupported ?\\n        { capture: o.capture, passive: o.passive, once: o.once } :\\n        o.capture);\\n//# sourceMappingURL=parts.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/parts.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/render.js\":\n/*!*********************************************!*\\\n  !*** ./node_modules/lit-html/lib/render.js ***!\n  \\*********************************************/\n/*! exports provided: parts, render */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"parts\\\", function() { return parts; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"render\\\", function() { return render; });\\n/* harmony import */ var _dom_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./dom.js */ \\\"./node_modules/lit-html/lib/dom.js\\\");\\n/* harmony import */ var _parts_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./parts.js */ \\\"./node_modules/lit-html/lib/parts.js\\\");\\n/* harmony import */ var _template_factory_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./template-factory.js */ \\\"./node_modules/lit-html/lib/template-factory.js\\\");\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n/**\\n * @module lit-html\\n */\\n\\n\\n\\nconst parts = new WeakMap();\\n/**\\n * Renders a template result or other value to a container.\\n *\\n * To update a container with new values, reevaluate the template literal and\\n * call `render` with the new result.\\n *\\n * @param result Any value renderable by NodePart - typically a TemplateResult\\n *     created by evaluating a template tag like `html` or `svg`.\\n * @param container A DOM parent to render to. The entire contents are either\\n *     replaced, or efficiently updated if the same result type was previous\\n *     rendered there.\\n * @param options RenderOptions for the entire render tree rendered to this\\n *     container. Render options must *not* change between renders to the same\\n *     container, as those changes will not effect previously rendered DOM.\\n */\\nconst render = (result, container, options) => {\\n    let part = parts.get(container);\\n    if (part === undefined) {\\n        Object(_dom_js__WEBPACK_IMPORTED_MODULE_0__[\\\"removeNodes\\\"])(container, container.firstChild);\\n        parts.set(container, part = new _parts_js__WEBPACK_IMPORTED_MODULE_1__[\\\"NodePart\\\"](Object.assign({ templateFactory: _template_factory_js__WEBPACK_IMPORTED_MODULE_2__[\\\"templateFactory\\\"] }, options)));\\n        part.appendInto(container);\\n    }\\n    part.setValue(result);\\n    part.commit();\\n};\\n//# sourceMappingURL=render.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/render.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/shady-render.js\":\n/*!***************************************************!*\\\n  !*** ./node_modules/lit-html/lib/shady-render.js ***!\n  \\***************************************************/\n/*! exports provided: html, svg, TemplateResult, render */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"render\\\", function() { return render; });\\n/* harmony import */ var _dom_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./dom.js */ \\\"./node_modules/lit-html/lib/dom.js\\\");\\n/* harmony import */ var _modify_template_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./modify-template.js */ \\\"./node_modules/lit-html/lib/modify-template.js\\\");\\n/* harmony import */ var _render_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./render.js */ \\\"./node_modules/lit-html/lib/render.js\\\");\\n/* harmony import */ var _template_factory_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./template-factory.js */ \\\"./node_modules/lit-html/lib/template-factory.js\\\");\\n/* harmony import */ var _template_instance_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./template-instance.js */ \\\"./node_modules/lit-html/lib/template-instance.js\\\");\\n/* harmony import */ var _template_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./template.js */ \\\"./node_modules/lit-html/lib/template.js\\\");\\n/* harmony import */ var _lit_html_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lit-html.js */ \\\"./node_modules/lit-html/lit-html.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"html\\\", function() { return _lit_html_js__WEBPACK_IMPORTED_MODULE_6__[\\\"html\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"svg\\\", function() { return _lit_html_js__WEBPACK_IMPORTED_MODULE_6__[\\\"svg\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"TemplateResult\\\", function() { return _lit_html_js__WEBPACK_IMPORTED_MODULE_6__[\\\"TemplateResult\\\"]; });\\n\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n/**\\n * Module to add shady DOM/shady CSS polyfill support to lit-html template\\n * rendering. See the [[render]] method for details.\\n *\\n * @module shady-render\\n * @preferred\\n */\\n/**\\n * Do not remove this comment; it keeps typedoc from misplacing the module\\n * docs.\\n */\\n\\n\\n\\n\\n\\n\\n\\n// Get a key to lookup in `templateCaches`.\\nconst getTemplateCacheKey = (type, scopeName) => `${type}--${scopeName}`;\\nlet compatibleShadyCSSVersion = true;\\nif (typeof window.ShadyCSS === 'undefined') {\\n    compatibleShadyCSSVersion = false;\\n}\\nelse if (typeof window.ShadyCSS.prepareTemplateDom === 'undefined') {\\n    console.warn(`Incompatible ShadyCSS version detected. ` +\\n        `Please update to at least @webcomponents/webcomponentsjs@2.0.2 and ` +\\n        `@webcomponents/shadycss@1.3.1.`);\\n    compatibleShadyCSSVersion = false;\\n}\\n/**\\n * Template factory which scopes template DOM using ShadyCSS.\\n * @param scopeName {string}\\n */\\nconst shadyTemplateFactory = (scopeName) => (result) => {\\n    const cacheKey = getTemplateCacheKey(result.type, scopeName);\\n    let templateCache = _template_factory_js__WEBPACK_IMPORTED_MODULE_3__[\\\"templateCaches\\\"].get(cacheKey);\\n    if (templateCache === undefined) {\\n        templateCache = {\\n            stringsArray: new WeakMap(),\\n            keyString: new Map()\\n        };\\n        _template_factory_js__WEBPACK_IMPORTED_MODULE_3__[\\\"templateCaches\\\"].set(cacheKey, templateCache);\\n    }\\n    let template = templateCache.stringsArray.get(result.strings);\\n    if (template !== undefined) {\\n        return template;\\n    }\\n    const key = result.strings.join(_template_js__WEBPACK_IMPORTED_MODULE_5__[\\\"marker\\\"]);\\n    template = templateCache.keyString.get(key);\\n    if (template === undefined) {\\n        const element = result.getTemplateElement();\\n        if (compatibleShadyCSSVersion) {\\n            window.ShadyCSS.prepareTemplateDom(element, scopeName);\\n        }\\n        template = new _template_js__WEBPACK_IMPORTED_MODULE_5__[\\\"Template\\\"](result, element);\\n        templateCache.keyString.set(key, template);\\n    }\\n    templateCache.stringsArray.set(result.strings, template);\\n    return template;\\n};\\nconst TEMPLATE_TYPES = ['html', 'svg'];\\n/**\\n * Removes all style elements from Templates for the given scopeName.\\n */\\nconst removeStylesFromLitTemplates = (scopeName) => {\\n    TEMPLATE_TYPES.forEach((type) => {\\n        const templates = _template_factory_js__WEBPACK_IMPORTED_MODULE_3__[\\\"templateCaches\\\"].get(getTemplateCacheKey(type, scopeName));\\n        if (templates !== undefined) {\\n            templates.keyString.forEach((template) => {\\n                const { element: { content } } = template;\\n                // IE 11 doesn't support the iterable param Set constructor\\n                const styles = new Set();\\n                Array.from(content.querySelectorAll('style')).forEach((s) => {\\n                    styles.add(s);\\n                });\\n                Object(_modify_template_js__WEBPACK_IMPORTED_MODULE_1__[\\\"removeNodesFromTemplate\\\"])(template, styles);\\n            });\\n        }\\n    });\\n};\\nconst shadyRenderSet = new Set();\\n/**\\n * For the given scope name, ensures that ShadyCSS style scoping is performed.\\n * This is done just once per scope name so the fragment and template cannot\\n * be modified.\\n * (1) extracts styles from the rendered fragment and hands them to ShadyCSS\\n * to be scoped and appended to the document\\n * (2) removes style elements from all lit-html Templates for this scope name.\\n *\\n * Note, <style> elements can only be placed into templates for the\\n * initial rendering of the scope. If <style> elements are included in templates\\n * dynamically rendered to the scope (after the first scope render), they will\\n * not be scoped and the <style> will be left in the template and rendered\\n * output.\\n */\\nconst prepareTemplateStyles = (scopeName, renderedDOM, template) => {\\n    shadyRenderSet.add(scopeName);\\n    // If `renderedDOM` is stamped from a Template, then we need to edit that\\n    // Template's underlying template element. Otherwise, we create one here\\n    // to give to ShadyCSS, which still requires one while scoping.\\n    const templateElement = !!template ? template.element : document.createElement('template');\\n    // Move styles out of rendered DOM and store.\\n    const styles = renderedDOM.querySelectorAll('style');\\n    const { length } = styles;\\n    // If there are no styles, skip unnecessary work\\n    if (length === 0) {\\n        // Ensure prepareTemplateStyles is called to support adding\\n        // styles via `prepareAdoptedCssText` since that requires that\\n        // `prepareTemplateStyles` is called.\\n        //\\n        // ShadyCSS will only update styles containing @apply in the template\\n        // given to `prepareTemplateStyles`. If no lit Template was given,\\n        // ShadyCSS will not be able to update uses of @apply in any relevant\\n        // template. However, this is not a problem because we only create the\\n        // template for the purpose of supporting `prepareAdoptedCssText`,\\n        // which doesn't support @apply at all.\\n        window.ShadyCSS.prepareTemplateStyles(templateElement, scopeName);\\n        return;\\n    }\\n    const condensedStyle = document.createElement('style');\\n    // Collect styles into a single style. This helps us make sure ShadyCSS\\n    // manipulations will not prevent us from being able to fix up template\\n    // part indices.\\n    // NOTE: collecting styles is inefficient for browsers but ShadyCSS\\n    // currently does this anyway. When it does not, this should be changed.\\n    for (let i = 0; i < length; i++) {\\n        const style = styles[i];\\n        style.parentNode.removeChild(style);\\n        condensedStyle.textContent += style.textContent;\\n    }\\n    // Remove styles from nested templates in this scope.\\n    removeStylesFromLitTemplates(scopeName);\\n    // And then put the condensed style into the \\\"root\\\" template passed in as\\n    // `template`.\\n    const content = templateElement.content;\\n    if (!!template) {\\n        Object(_modify_template_js__WEBPACK_IMPORTED_MODULE_1__[\\\"insertNodeIntoTemplate\\\"])(template, condensedStyle, content.firstChild);\\n    }\\n    else {\\n        content.insertBefore(condensedStyle, content.firstChild);\\n    }\\n    // Note, it's important that ShadyCSS gets the template that `lit-html`\\n    // will actually render so that it can update the style inside when\\n    // needed (e.g. @apply native Shadow DOM case).\\n    window.ShadyCSS.prepareTemplateStyles(templateElement, scopeName);\\n    const style = content.querySelector('style');\\n    if (window.ShadyCSS.nativeShadow && style !== null) {\\n        // When in native Shadow DOM, ensure the style created by ShadyCSS is\\n        // included in initially rendered output (`renderedDOM`).\\n        renderedDOM.insertBefore(style.cloneNode(true), renderedDOM.firstChild);\\n    }\\n    else if (!!template) {\\n        // When no style is left in the template, parts will be broken as a\\n        // result. To fix this, we put back the style node ShadyCSS removed\\n        // and then tell lit to remove that node from the template.\\n        // There can be no style in the template in 2 cases (1) when Shady DOM\\n        // is in use, ShadyCSS removes all styles, (2) when native Shadow DOM\\n        // is in use ShadyCSS removes the style if it contains no content.\\n        // NOTE, ShadyCSS creates its own style so we can safely add/remove\\n        // `condensedStyle` here.\\n        content.insertBefore(condensedStyle, content.firstChild);\\n        const removes = new Set();\\n        removes.add(condensedStyle);\\n        Object(_modify_template_js__WEBPACK_IMPORTED_MODULE_1__[\\\"removeNodesFromTemplate\\\"])(template, removes);\\n    }\\n};\\n/**\\n * Extension to the standard `render` method which supports rendering\\n * to ShadowRoots when the ShadyDOM (https://github.com/webcomponents/shadydom)\\n * and ShadyCSS (https://github.com/webcomponents/shadycss) polyfills are used\\n * or when the webcomponentsjs\\n * (https://github.com/webcomponents/webcomponentsjs) polyfill is used.\\n *\\n * Adds a `scopeName` option which is used to scope element DOM and stylesheets\\n * when native ShadowDOM is unavailable. The `scopeName` will be added to\\n * the class attribute of all rendered DOM. In addition, any style elements will\\n * be automatically re-written with this `scopeName` selector and moved out\\n * of the rendered DOM and into the document `<head>`.\\n *\\n * It is common to use this render method in conjunction with a custom element\\n * which renders a shadowRoot. When this is done, typically the element's\\n * `localName` should be used as the `scopeName`.\\n *\\n * In addition to DOM scoping, ShadyCSS also supports a basic shim for css\\n * custom properties (needed only on older browsers like IE11) and a shim for\\n * a deprecated feature called `@apply` that supports applying a set of css\\n * custom properties to a given location.\\n *\\n * Usage considerations:\\n *\\n * * Part values in `<style>` elements are only applied the first time a given\\n * `scopeName` renders. Subsequent changes to parts in style elements will have\\n * no effect. Because of this, parts in style elements should only be used for\\n * values that will never change, for example parts that set scope-wide theme\\n * values or parts which render shared style elements.\\n *\\n * * Note, due to a limitation of the ShadyDOM polyfill, rendering in a\\n * custom element's `constructor` is not supported. Instead rendering should\\n * either done asynchronously, for example at microtask timing (for example\\n * `Promise.resolve()`), or be deferred until the first time the element's\\n * `connectedCallback` runs.\\n *\\n * Usage considerations when using shimmed custom properties or `@apply`:\\n *\\n * * Whenever any dynamic changes are made which affect\\n * css custom properties, `ShadyCSS.styleElement(element)` must be called\\n * to update the element. There are two cases when this is needed:\\n * (1) the element is connected to a new parent, (2) a class is added to the\\n * element that causes it to match different custom properties.\\n * To address the first case when rendering a custom element, `styleElement`\\n * should be called in the element's `connectedCallback`.\\n *\\n * * Shimmed custom properties may only be defined either for an entire\\n * shadowRoot (for example, in a `:host` rule) or via a rule that directly\\n * matches an element with a shadowRoot. In other words, instead of flowing from\\n * parent to child as do native css custom properties, shimmed custom properties\\n * flow only from shadowRoots to nested shadowRoots.\\n *\\n * * When using `@apply` mixing css shorthand property names with\\n * non-shorthand names (for example `border` and `border-width`) is not\\n * supported.\\n */\\nconst render = (result, container, options) => {\\n    if (!options || typeof options !== 'object' || !options.scopeName) {\\n        throw new Error('The `scopeName` option is required.');\\n    }\\n    const scopeName = options.scopeName;\\n    const hasRendered = _render_js__WEBPACK_IMPORTED_MODULE_2__[\\\"parts\\\"].has(container);\\n    const needsScoping = compatibleShadyCSSVersion &&\\n        container.nodeType === 11 /* Node.DOCUMENT_FRAGMENT_NODE */ &&\\n        !!container.host;\\n    // Handle first render to a scope specially...\\n    const firstScopeRender = needsScoping && !shadyRenderSet.has(scopeName);\\n    // On first scope render, render into a fragment; this cannot be a single\\n    // fragment that is reused since nested renders can occur synchronously.\\n    const renderContainer = firstScopeRender ? document.createDocumentFragment() : container;\\n    Object(_render_js__WEBPACK_IMPORTED_MODULE_2__[\\\"render\\\"])(result, renderContainer, Object.assign({ templateFactory: shadyTemplateFactory(scopeName) }, options));\\n    // When performing first scope render,\\n    // (1) We've rendered into a fragment so that there's a chance to\\n    // `prepareTemplateStyles` before sub-elements hit the DOM\\n    // (which might cause them to render based on a common pattern of\\n    // rendering in a custom element's `connectedCallback`);\\n    // (2) Scope the template with ShadyCSS one time only for this scope.\\n    // (3) Render the fragment into the container and make sure the\\n    // container knows its `part` is the one we just rendered. This ensures\\n    // DOM will be re-used on subsequent renders.\\n    if (firstScopeRender) {\\n        const part = _render_js__WEBPACK_IMPORTED_MODULE_2__[\\\"parts\\\"].get(renderContainer);\\n        _render_js__WEBPACK_IMPORTED_MODULE_2__[\\\"parts\\\"].delete(renderContainer);\\n        // ShadyCSS might have style sheets (e.g. from `prepareAdoptedCssText`)\\n        // that should apply to `renderContainer` even if the rendered value is\\n        // not a TemplateInstance. However, it will only insert scoped styles\\n        // into the document if `prepareTemplateStyles` has already been called\\n        // for the given scope name.\\n        const template = part.value instanceof _template_instance_js__WEBPACK_IMPORTED_MODULE_4__[\\\"TemplateInstance\\\"] ?\\n            part.value.template :\\n            undefined;\\n        prepareTemplateStyles(scopeName, renderContainer, template);\\n        Object(_dom_js__WEBPACK_IMPORTED_MODULE_0__[\\\"removeNodes\\\"])(container, container.firstChild);\\n        container.appendChild(renderContainer);\\n        _render_js__WEBPACK_IMPORTED_MODULE_2__[\\\"parts\\\"].set(container, part);\\n    }\\n    // After elements have hit the DOM, update styling if this is the\\n    // initial render to this container.\\n    // This is needed whenever dynamic changes are made so it would be\\n    // safest to do every render; however, this would regress performance\\n    // so we leave it up to the user to call `ShadyCSS.styleElement`\\n    // for dynamic changes.\\n    if (!hasRendered && needsScoping) {\\n        window.ShadyCSS.styleElement(container.host);\\n    }\\n};\\n//# sourceMappingURL=shady-render.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/shady-render.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/template-factory.js\":\n/*!*******************************************************!*\\\n  !*** ./node_modules/lit-html/lib/template-factory.js ***!\n  \\*******************************************************/\n/*! exports provided: templateFactory, templateCaches */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"templateFactory\\\", function() { return templateFactory; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"templateCaches\\\", function() { return templateCaches; });\\n/* harmony import */ var _template_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./template.js */ \\\"./node_modules/lit-html/lib/template.js\\\");\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n\\n/**\\n * The default TemplateFactory which caches Templates keyed on\\n * result.type and result.strings.\\n */\\nfunction templateFactory(result) {\\n    let templateCache = templateCaches.get(result.type);\\n    if (templateCache === undefined) {\\n        templateCache = {\\n            stringsArray: new WeakMap(),\\n            keyString: new Map()\\n        };\\n        templateCaches.set(result.type, templateCache);\\n    }\\n    let template = templateCache.stringsArray.get(result.strings);\\n    if (template !== undefined) {\\n        return template;\\n    }\\n    // If the TemplateStringsArray is new, generate a key from the strings\\n    // This key is shared between all templates with identical content\\n    const key = result.strings.join(_template_js__WEBPACK_IMPORTED_MODULE_0__[\\\"marker\\\"]);\\n    // Check if we already have a Template for this key\\n    template = templateCache.keyString.get(key);\\n    if (template === undefined) {\\n        // If we have not seen this key before, create a new Template\\n        template = new _template_js__WEBPACK_IMPORTED_MODULE_0__[\\\"Template\\\"](result, result.getTemplateElement());\\n        // Cache the Template for this key\\n        templateCache.keyString.set(key, template);\\n    }\\n    // Cache all future queries for this TemplateStringsArray\\n    templateCache.stringsArray.set(result.strings, template);\\n    return template;\\n}\\nconst templateCaches = new Map();\\n//# sourceMappingURL=template-factory.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/template-factory.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/template-instance.js\":\n/*!********************************************************!*\\\n  !*** ./node_modules/lit-html/lib/template-instance.js ***!\n  \\********************************************************/\n/*! exports provided: TemplateInstance */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"TemplateInstance\\\", function() { return TemplateInstance; });\\n/* harmony import */ var _dom_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./dom.js */ \\\"./node_modules/lit-html/lib/dom.js\\\");\\n/* harmony import */ var _template_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./template.js */ \\\"./node_modules/lit-html/lib/template.js\\\");\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n/**\\n * @module lit-html\\n */\\n\\n\\n/**\\n * An instance of a `Template` that can be attached to the DOM and updated\\n * with new values.\\n */\\nclass TemplateInstance {\\n    constructor(template, processor, options) {\\n        this.__parts = [];\\n        this.template = template;\\n        this.processor = processor;\\n        this.options = options;\\n    }\\n    update(values) {\\n        let i = 0;\\n        for (const part of this.__parts) {\\n            if (part !== undefined) {\\n                part.setValue(values[i]);\\n            }\\n            i++;\\n        }\\n        for (const part of this.__parts) {\\n            if (part !== undefined) {\\n                part.commit();\\n            }\\n        }\\n    }\\n    _clone() {\\n        // There are a number of steps in the lifecycle of a template instance's\\n        // DOM fragment:\\n        //  1. Clone - create the instance fragment\\n        //  2. Adopt - adopt into the main document\\n        //  3. Process - find part markers and create parts\\n        //  4. Upgrade - upgrade custom elements\\n        //  5. Update - set node, attribute, property, etc., values\\n        //  6. Connect - connect to the document. Optional and outside of this\\n        //     method.\\n        //\\n        // We have a few constraints on the ordering of these steps:\\n        //  * We need to upgrade before updating, so that property values will pass\\n        //    through any property setters.\\n        //  * We would like to process before upgrading so that we're sure that the\\n        //    cloned fragment is inert and not disturbed by self-modifying DOM.\\n        //  * We want custom elements to upgrade even in disconnected fragments.\\n        //\\n        // Given these constraints, with full custom elements support we would\\n        // prefer the order: Clone, Process, Adopt, Upgrade, Update, Connect\\n        //\\n        // But Safari does not implement CustomElementRegistry#upgrade, so we\\n        // can not implement that order and still have upgrade-before-update and\\n        // upgrade disconnected fragments. So we instead sacrifice the\\n        // process-before-upgrade constraint, since in Custom Elements v1 elements\\n        // must not modify their light DOM in the constructor. We still have issues\\n        // when co-existing with CEv0 elements like Polymer 1, and with polyfills\\n        // that don't strictly adhere to the no-modification rule because shadow\\n        // DOM, which may be created in the constructor, is emulated by being placed\\n        // in the light DOM.\\n        //\\n        // The resulting order is on native is: Clone, Adopt, Upgrade, Process,\\n        // Update, Connect. document.importNode() performs Clone, Adopt, and Upgrade\\n        // in one step.\\n        //\\n        // The Custom Elements v1 polyfill supports upgrade(), so the order when\\n        // polyfilled is the more ideal: Clone, Process, Adopt, Upgrade, Update,\\n        // Connect.\\n        const fragment = _dom_js__WEBPACK_IMPORTED_MODULE_0__[\\\"isCEPolyfill\\\"] ?\\n            this.template.element.content.cloneNode(true) :\\n            document.importNode(this.template.element.content, true);\\n        const stack = [];\\n        const parts = this.template.parts;\\n        // Edge needs all 4 parameters present; IE11 needs 3rd parameter to be null\\n        const walker = document.createTreeWalker(fragment, 133 /* NodeFilter.SHOW_{ELEMENT|COMMENT|TEXT} */, null, false);\\n        let partIndex = 0;\\n        let nodeIndex = 0;\\n        let part;\\n        let node = walker.nextNode();\\n        // Loop through all the nodes and parts of a template\\n        while (partIndex < parts.length) {\\n            part = parts[partIndex];\\n            if (!Object(_template_js__WEBPACK_IMPORTED_MODULE_1__[\\\"isTemplatePartActive\\\"])(part)) {\\n                this.__parts.push(undefined);\\n                partIndex++;\\n                continue;\\n            }\\n            // Progress the tree walker until we find our next part's node.\\n            // Note that multiple parts may share the same node (attribute parts\\n            // on a single element), so this loop may not run at all.\\n            while (nodeIndex < part.index) {\\n                nodeIndex++;\\n                if (node.nodeName === 'TEMPLATE') {\\n                    stack.push(node);\\n                    walker.currentNode = node.content;\\n                }\\n                if ((node = walker.nextNode()) === null) {\\n                    // We've exhausted the content inside a nested template element.\\n                    // Because we still have parts (the outer for-loop), we know:\\n                    // - There is a template in the stack\\n                    // - The walker will find a nextNode outside the template\\n                    walker.currentNode = stack.pop();\\n                    node = walker.nextNode();\\n                }\\n            }\\n            // We've arrived at our part's node.\\n            if (part.type === 'node') {\\n                const part = this.processor.handleTextExpression(this.options);\\n                part.insertAfterNode(node.previousSibling);\\n                this.__parts.push(part);\\n            }\\n            else {\\n                this.__parts.push(...this.processor.handleAttributeExpressions(node, part.name, part.strings, this.options));\\n            }\\n            partIndex++;\\n        }\\n        if (_dom_js__WEBPACK_IMPORTED_MODULE_0__[\\\"isCEPolyfill\\\"]) {\\n            document.adoptNode(fragment);\\n            customElements.upgrade(fragment);\\n        }\\n        return fragment;\\n    }\\n}\\n//# sourceMappingURL=template-instance.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/template-instance.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/template-result.js\":\n/*!******************************************************!*\\\n  !*** ./node_modules/lit-html/lib/template-result.js ***!\n  \\******************************************************/\n/*! exports provided: TemplateResult, SVGTemplateResult */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"TemplateResult\\\", function() { return TemplateResult; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"SVGTemplateResult\\\", function() { return SVGTemplateResult; });\\n/* harmony import */ var _dom_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./dom.js */ \\\"./node_modules/lit-html/lib/dom.js\\\");\\n/* harmony import */ var _template_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./template.js */ \\\"./node_modules/lit-html/lib/template.js\\\");\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n/**\\n * @module lit-html\\n */\\n\\n\\nconst commentMarker = ` ${_template_js__WEBPACK_IMPORTED_MODULE_1__[\\\"marker\\\"]} `;\\n/**\\n * The return type of `html`, which holds a Template and the values from\\n * interpolated expressions.\\n */\\nclass TemplateResult {\\n    constructor(strings, values, type, processor) {\\n        this.strings = strings;\\n        this.values = values;\\n        this.type = type;\\n        this.processor = processor;\\n    }\\n    /**\\n     * Returns a string of HTML used to create a `<template>` element.\\n     */\\n    getHTML() {\\n        const l = this.strings.length - 1;\\n        let html = '';\\n        let isCommentBinding = false;\\n        for (let i = 0; i < l; i++) {\\n            const s = this.strings[i];\\n            // For each binding we want to determine the kind of marker to insert\\n            // into the template source before it's parsed by the browser's HTML\\n            // parser. The marker type is based on whether the expression is in an\\n            // attribute, text, or comment position.\\n            //   * For node-position bindings we insert a comment with the marker\\n            //     sentinel as its text content, like <!--{{lit-guid}}-->.\\n            //   * For attribute bindings we insert just the marker sentinel for the\\n            //     first binding, so that we support unquoted attribute bindings.\\n            //     Subsequent bindings can use a comment marker because multi-binding\\n            //     attributes must be quoted.\\n            //   * For comment bindings we insert just the marker sentinel so we don't\\n            //     close the comment.\\n            //\\n            // The following code scans the template source, but is *not* an HTML\\n            // parser. We don't need to track the tree structure of the HTML, only\\n            // whether a binding is inside a comment, and if not, if it appears to be\\n            // the first binding in an attribute.\\n            const commentOpen = s.lastIndexOf('<!--');\\n            // We're in comment position if we have a comment open with no following\\n            // comment close. Because <-- can appear in an attribute value there can\\n            // be false positives.\\n            isCommentBinding = (commentOpen > -1 || isCommentBinding) &&\\n                s.indexOf('-->', commentOpen + 1) === -1;\\n            // Check to see if we have an attribute-like sequence preceding the\\n            // expression. This can match \\\"name=value\\\" like structures in text,\\n            // comments, and attribute values, so there can be false-positives.\\n            const attributeMatch = _template_js__WEBPACK_IMPORTED_MODULE_1__[\\\"lastAttributeNameRegex\\\"].exec(s);\\n            if (attributeMatch === null) {\\n                // We're only in this branch if we don't have a attribute-like\\n                // preceding sequence. For comments, this guards against unusual\\n                // attribute values like <div foo=\\\"<!--${'bar'}\\\">. Cases like\\n                // <!-- foo=${'bar'}--> are handled correctly in the attribute branch\\n                // below.\\n                html += s + (isCommentBinding ? commentMarker : _template_js__WEBPACK_IMPORTED_MODULE_1__[\\\"nodeMarker\\\"]);\\n            }\\n            else {\\n                // For attributes we use just a marker sentinel, and also append a\\n                // $lit$ suffix to the name to opt-out of attribute-specific parsing\\n                // that IE and Edge do for style and certain SVG attributes.\\n                html += s.substr(0, attributeMatch.index) + attributeMatch[1] +\\n                    attributeMatch[2] + _template_js__WEBPACK_IMPORTED_MODULE_1__[\\\"boundAttributeSuffix\\\"] + attributeMatch[3] +\\n                    _template_js__WEBPACK_IMPORTED_MODULE_1__[\\\"marker\\\"];\\n            }\\n        }\\n        html += this.strings[l];\\n        return html;\\n    }\\n    getTemplateElement() {\\n        const template = document.createElement('template');\\n        template.innerHTML = this.getHTML();\\n        return template;\\n    }\\n}\\n/**\\n * A TemplateResult for SVG fragments.\\n *\\n * This class wraps HTML in an `<svg>` tag in order to parse its contents in the\\n * SVG namespace, then modifies the template to remove the `<svg>` tag so that\\n * clones only container the original fragment.\\n */\\nclass SVGTemplateResult extends TemplateResult {\\n    getHTML() {\\n        return `<svg>${super.getHTML()}</svg>`;\\n    }\\n    getTemplateElement() {\\n        const template = super.getTemplateElement();\\n        const content = template.content;\\n        const svgElement = content.firstChild;\\n        content.removeChild(svgElement);\\n        Object(_dom_js__WEBPACK_IMPORTED_MODULE_0__[\\\"reparentNodes\\\"])(content, svgElement.firstChild);\\n        return template;\\n    }\\n}\\n//# sourceMappingURL=template-result.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/template-result.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/template.js\":\n/*!***********************************************!*\\\n  !*** ./node_modules/lit-html/lib/template.js ***!\n  \\***********************************************/\n/*! exports provided: marker, nodeMarker, markerRegex, boundAttributeSuffix, Template, isTemplatePartActive, createMarker, lastAttributeNameRegex */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"marker\\\", function() { return marker; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"nodeMarker\\\", function() { return nodeMarker; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"markerRegex\\\", function() { return markerRegex; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"boundAttributeSuffix\\\", function() { return boundAttributeSuffix; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"Template\\\", function() { return Template; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"isTemplatePartActive\\\", function() { return isTemplatePartActive; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"createMarker\\\", function() { return createMarker; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"lastAttributeNameRegex\\\", function() { return lastAttributeNameRegex; });\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n/**\\n * An expression marker with embedded unique key to avoid collision with\\n * possible text in templates.\\n */\\nconst marker = `{{lit-${String(Math.random()).slice(2)}}}`;\\n/**\\n * An expression marker used text-positions, multi-binding attributes, and\\n * attributes with markup-like text values.\\n */\\nconst nodeMarker = `<!--${marker}-->`;\\nconst markerRegex = new RegExp(`${marker}|${nodeMarker}`);\\n/**\\n * Suffix appended to all bound attribute names.\\n */\\nconst boundAttributeSuffix = '$lit$';\\n/**\\n * An updatable Template that tracks the location of dynamic parts.\\n */\\nclass Template {\\n    constructor(result, element) {\\n        this.parts = [];\\n        this.element = element;\\n        const nodesToRemove = [];\\n        const stack = [];\\n        // Edge needs all 4 parameters present; IE11 needs 3rd parameter to be null\\n        const walker = document.createTreeWalker(element.content, 133 /* NodeFilter.SHOW_{ELEMENT|COMMENT|TEXT} */, null, false);\\n        // Keeps track of the last index associated with a part. We try to delete\\n        // unnecessary nodes, but we never want to associate two different parts\\n        // to the same index. They must have a constant node between.\\n        let lastPartIndex = 0;\\n        let index = -1;\\n        let partIndex = 0;\\n        const { strings, values: { length } } = result;\\n        while (partIndex < length) {\\n            const node = walker.nextNode();\\n            if (node === null) {\\n                // We've exhausted the content inside a nested template element.\\n                // Because we still have parts (the outer for-loop), we know:\\n                // - There is a template in the stack\\n                // - The walker will find a nextNode outside the template\\n                walker.currentNode = stack.pop();\\n                continue;\\n            }\\n            index++;\\n            if (node.nodeType === 1 /* Node.ELEMENT_NODE */) {\\n                if (node.hasAttributes()) {\\n                    const attributes = node.attributes;\\n                    const { length } = attributes;\\n                    // Per\\n                    // https://developer.mozilla.org/en-US/docs/Web/API/NamedNodeMap,\\n                    // attributes are not guaranteed to be returned in document order.\\n                    // In particular, Edge/IE can return them out of order, so we cannot\\n                    // assume a correspondence between part index and attribute index.\\n                    let count = 0;\\n                    for (let i = 0; i < length; i++) {\\n                        if (endsWith(attributes[i].name, boundAttributeSuffix)) {\\n                            count++;\\n                        }\\n                    }\\n                    while (count-- > 0) {\\n                        // Get the template literal section leading up to the first\\n                        // expression in this attribute\\n                        const stringForPart = strings[partIndex];\\n                        // Find the attribute name\\n                        const name = lastAttributeNameRegex.exec(stringForPart)[2];\\n                        // Find the corresponding attribute\\n                        // All bound attributes have had a suffix added in\\n                        // TemplateResult#getHTML to opt out of special attribute\\n                        // handling. To look up the attribute value we also need to add\\n                        // the suffix.\\n                        const attributeLookupName = name.toLowerCase() + boundAttributeSuffix;\\n                        const attributeValue = node.getAttribute(attributeLookupName);\\n                        node.removeAttribute(attributeLookupName);\\n                        const statics = attributeValue.split(markerRegex);\\n                        this.parts.push({ type: 'attribute', index, name, strings: statics });\\n                        partIndex += statics.length - 1;\\n                    }\\n                }\\n                if (node.tagName === 'TEMPLATE') {\\n                    stack.push(node);\\n                    walker.currentNode = node.content;\\n                }\\n            }\\n            else if (node.nodeType === 3 /* Node.TEXT_NODE */) {\\n                const data = node.data;\\n                if (data.indexOf(marker) >= 0) {\\n                    const parent = node.parentNode;\\n                    const strings = data.split(markerRegex);\\n                    const lastIndex = strings.length - 1;\\n                    // Generate a new text node for each literal section\\n                    // These nodes are also used as the markers for node parts\\n                    for (let i = 0; i < lastIndex; i++) {\\n                        let insert;\\n                        let s = strings[i];\\n                        if (s === '') {\\n                            insert = createMarker();\\n                        }\\n                        else {\\n                            const match = lastAttributeNameRegex.exec(s);\\n                            if (match !== null && endsWith(match[2], boundAttributeSuffix)) {\\n                                s = s.slice(0, match.index) + match[1] +\\n                                    match[2].slice(0, -boundAttributeSuffix.length) + match[3];\\n                            }\\n                            insert = document.createTextNode(s);\\n                        }\\n                        parent.insertBefore(insert, node);\\n                        this.parts.push({ type: 'node', index: ++index });\\n                    }\\n                    // If there's no text, we must insert a comment to mark our place.\\n                    // Else, we can trust it will stick around after cloning.\\n                    if (strings[lastIndex] === '') {\\n                        parent.insertBefore(createMarker(), node);\\n                        nodesToRemove.push(node);\\n                    }\\n                    else {\\n                        node.data = strings[lastIndex];\\n                    }\\n                    // We have a part for each match found\\n                    partIndex += lastIndex;\\n                }\\n            }\\n            else if (node.nodeType === 8 /* Node.COMMENT_NODE */) {\\n                if (node.data === marker) {\\n                    const parent = node.parentNode;\\n                    // Add a new marker node to be the startNode of the Part if any of\\n                    // the following are true:\\n                    //  * We don't have a previousSibling\\n                    //  * The previousSibling is already the start of a previous part\\n                    if (node.previousSibling === null || index === lastPartIndex) {\\n                        index++;\\n                        parent.insertBefore(createMarker(), node);\\n                    }\\n                    lastPartIndex = index;\\n                    this.parts.push({ type: 'node', index });\\n                    // If we don't have a nextSibling, keep this node so we have an end.\\n                    // Else, we can remove it to save future costs.\\n                    if (node.nextSibling === null) {\\n                        node.data = '';\\n                    }\\n                    else {\\n                        nodesToRemove.push(node);\\n                        index--;\\n                    }\\n                    partIndex++;\\n                }\\n                else {\\n                    let i = -1;\\n                    while ((i = node.data.indexOf(marker, i + 1)) !== -1) {\\n                        // Comment node has a binding marker inside, make an inactive part\\n                        // The binding won't work, but subsequent bindings will\\n                        // TODO (justinfagnani): consider whether it's even worth it to\\n                        // make bindings in comments work\\n                        this.parts.push({ type: 'node', index: -1 });\\n                        partIndex++;\\n                    }\\n                }\\n            }\\n        }\\n        // Remove text binding nodes after the walk to not disturb the TreeWalker\\n        for (const n of nodesToRemove) {\\n            n.parentNode.removeChild(n);\\n        }\\n    }\\n}\\nconst endsWith = (str, suffix) => {\\n    const index = str.length - suffix.length;\\n    return index >= 0 && str.slice(index) === suffix;\\n};\\nconst isTemplatePartActive = (part) => part.index !== -1;\\n// Allows `document.createComment('')` to be renamed for a\\n// small manual size-savings.\\nconst createMarker = () => document.createComment('');\\n/**\\n * This regex extracts the attribute name preceding an attribute-position\\n * expression. It does this by matching the syntax allowed for attributes\\n * against the string literal directly preceding the expression, assuming that\\n * the expression is in an attribute-value position.\\n *\\n * See attributes in the HTML spec:\\n * https://www.w3.org/TR/html5/syntax.html#elements-attributes\\n *\\n * \\\" \\\\x09\\\\x0a\\\\x0c\\\\x0d\\\" are HTML space characters:\\n * https://www.w3.org/TR/html5/infrastructure.html#space-characters\\n *\\n * \\\"\\\\0-\\\\x1F\\\\x7F-\\\\x9F\\\" are Unicode control characters, which includes every\\n * space character except \\\" \\\".\\n *\\n * So an attribute is:\\n *  * The name: any character except a control character, space character, ('),\\n *    (\\\"), \\\">\\\", \\\"=\\\", or \\\"/\\\"\\n *  * Followed by zero or more space characters\\n *  * Followed by \\\"=\\\"\\n *  * Followed by zero or more space characters\\n *  * Followed by:\\n *    * Any character except space, ('), (\\\"), \\\"<\\\", \\\">\\\", \\\"=\\\", (`), or\\n *    * (\\\") then any non-(\\\"), or\\n *    * (') then any non-(')\\n */\\nconst lastAttributeNameRegex = \\n// eslint-disable-next-line no-control-regex\\n/([ \\\\x09\\\\x0a\\\\x0c\\\\x0d])([^\\\\0-\\\\x1F\\\\x7F-\\\\x9F \\\"'>=/]+)([ \\\\x09\\\\x0a\\\\x0c\\\\x0d]*=[ \\\\x09\\\\x0a\\\\x0c\\\\x0d]*(?:[^ \\\\x09\\\\x0a\\\\x0c\\\\x0d\\\"'`<>=]*|\\\"[^\\\"]*|'[^']*))$/;\\n//# sourceMappingURL=template.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/template.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lit-html.js\":\n/*!*******************************************!*\\\n  !*** ./node_modules/lit-html/lit-html.js ***!\n  \\*******************************************/\n/*! exports provided: DefaultTemplateProcessor, defaultTemplateProcessor, directive, isDirective, removeNodes, reparentNodes, noChange, nothing, AttributeCommitter, AttributePart, BooleanAttributePart, EventPart, isIterable, isPrimitive, NodePart, PropertyCommitter, PropertyPart, parts, render, templateCaches, templateFactory, TemplateInstance, SVGTemplateResult, TemplateResult, createMarker, isTemplatePartActive, Template, html, svg */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"html\\\", function() { return html; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"svg\\\", function() { return svg; });\\n/* harmony import */ var _lib_default_template_processor_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./lib/default-template-processor.js */ \\\"./node_modules/lit-html/lib/default-template-processor.js\\\");\\n/* harmony import */ var _lib_template_result_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./lib/template-result.js */ \\\"./node_modules/lit-html/lib/template-result.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"DefaultTemplateProcessor\\\", function() { return _lib_default_template_processor_js__WEBPACK_IMPORTED_MODULE_0__[\\\"DefaultTemplateProcessor\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"defaultTemplateProcessor\\\", function() { return _lib_default_template_processor_js__WEBPACK_IMPORTED_MODULE_0__[\\\"defaultTemplateProcessor\\\"]; });\\n\\n/* harmony import */ var _lib_directive_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./lib/directive.js */ \\\"./node_modules/lit-html/lib/directive.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"directive\\\", function() { return _lib_directive_js__WEBPACK_IMPORTED_MODULE_2__[\\\"directive\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"isDirective\\\", function() { return _lib_directive_js__WEBPACK_IMPORTED_MODULE_2__[\\\"isDirective\\\"]; });\\n\\n/* harmony import */ var _lib_dom_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./lib/dom.js */ \\\"./node_modules/lit-html/lib/dom.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"removeNodes\\\", function() { return _lib_dom_js__WEBPACK_IMPORTED_MODULE_3__[\\\"removeNodes\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"reparentNodes\\\", function() { return _lib_dom_js__WEBPACK_IMPORTED_MODULE_3__[\\\"reparentNodes\\\"]; });\\n\\n/* harmony import */ var _lib_part_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./lib/part.js */ \\\"./node_modules/lit-html/lib/part.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"noChange\\\", function() { return _lib_part_js__WEBPACK_IMPORTED_MODULE_4__[\\\"noChange\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"nothing\\\", function() { return _lib_part_js__WEBPACK_IMPORTED_MODULE_4__[\\\"nothing\\\"]; });\\n\\n/* harmony import */ var _lib_parts_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./lib/parts.js */ \\\"./node_modules/lit-html/lib/parts.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"AttributeCommitter\\\", function() { return _lib_parts_js__WEBPACK_IMPORTED_MODULE_5__[\\\"AttributeCommitter\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"AttributePart\\\", function() { return _lib_parts_js__WEBPACK_IMPORTED_MODULE_5__[\\\"AttributePart\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"BooleanAttributePart\\\", function() { return _lib_parts_js__WEBPACK_IMPORTED_MODULE_5__[\\\"BooleanAttributePart\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"EventPart\\\", function() { return _lib_parts_js__WEBPACK_IMPORTED_MODULE_5__[\\\"EventPart\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"isIterable\\\", function() { return _lib_parts_js__WEBPACK_IMPORTED_MODULE_5__[\\\"isIterable\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"isPrimitive\\\", function() { return _lib_parts_js__WEBPACK_IMPORTED_MODULE_5__[\\\"isPrimitive\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"NodePart\\\", function() { return _lib_parts_js__WEBPACK_IMPORTED_MODULE_5__[\\\"NodePart\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"PropertyCommitter\\\", function() { return _lib_parts_js__WEBPACK_IMPORTED_MODULE_5__[\\\"PropertyCommitter\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"PropertyPart\\\", function() { return _lib_parts_js__WEBPACK_IMPORTED_MODULE_5__[\\\"PropertyPart\\\"]; });\\n\\n/* harmony import */ var _lib_render_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./lib/render.js */ \\\"./node_modules/lit-html/lib/render.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"parts\\\", function() { return _lib_render_js__WEBPACK_IMPORTED_MODULE_6__[\\\"parts\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"render\\\", function() { return _lib_render_js__WEBPACK_IMPORTED_MODULE_6__[\\\"render\\\"]; });\\n\\n/* harmony import */ var _lib_template_factory_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./lib/template-factory.js */ \\\"./node_modules/lit-html/lib/template-factory.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"templateCaches\\\", function() { return _lib_template_factory_js__WEBPACK_IMPORTED_MODULE_7__[\\\"templateCaches\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"templateFactory\\\", function() { return _lib_template_factory_js__WEBPACK_IMPORTED_MODULE_7__[\\\"templateFactory\\\"]; });\\n\\n/* harmony import */ var _lib_template_instance_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./lib/template-instance.js */ \\\"./node_modules/lit-html/lib/template-instance.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"TemplateInstance\\\", function() { return _lib_template_instance_js__WEBPACK_IMPORTED_MODULE_8__[\\\"TemplateInstance\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"SVGTemplateResult\\\", function() { return _lib_template_result_js__WEBPACK_IMPORTED_MODULE_1__[\\\"SVGTemplateResult\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"TemplateResult\\\", function() { return _lib_template_result_js__WEBPACK_IMPORTED_MODULE_1__[\\\"TemplateResult\\\"]; });\\n\\n/* harmony import */ var _lib_template_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./lib/template.js */ \\\"./node_modules/lit-html/lib/template.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"createMarker\\\", function() { return _lib_template_js__WEBPACK_IMPORTED_MODULE_9__[\\\"createMarker\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"isTemplatePartActive\\\", function() { return _lib_template_js__WEBPACK_IMPORTED_MODULE_9__[\\\"isTemplatePartActive\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"Template\\\", function() { return _lib_template_js__WEBPACK_IMPORTED_MODULE_9__[\\\"Template\\\"]; });\\n\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n/**\\n *\\n * Main lit-html module.\\n *\\n * Main exports:\\n *\\n * -  [[html]]\\n * -  [[svg]]\\n * -  [[render]]\\n *\\n * @module lit-html\\n * @preferred\\n */\\n/**\\n * Do not remove this comment; it keeps typedoc from misplacing the module\\n * docs.\\n */\\n\\n\\n\\n\\n// TODO(justinfagnani): remove line when we get NodePart moving methods\\n\\n\\n\\n\\n\\n\\n\\n\\n// IMPORTANT: do not change the property name or the assignment expression.\\n// This line will be used in regexes to search for lit-html usage.\\n// TODO(justinfagnani): inject version number at build time\\nif (typeof window !== 'undefined') {\\n    (window['litHtmlVersions'] || (window['litHtmlVersions'] = [])).push('1.2.1');\\n}\\n/**\\n * Interprets a template literal as an HTML template that can efficiently\\n * render to and update a container.\\n */\\nconst html = (strings, ...values) => new _lib_template_result_js__WEBPACK_IMPORTED_MODULE_1__[\\\"TemplateResult\\\"](strings, values, 'html', _lib_default_template_processor_js__WEBPACK_IMPORTED_MODULE_0__[\\\"defaultTemplateProcessor\\\"]);\\n/**\\n * Interprets a template literal as an SVG template that can efficiently\\n * render to and update a container.\\n */\\nconst svg = (strings, ...values) => new _lib_template_result_js__WEBPACK_IMPORTED_MODULE_1__[\\\"SVGTemplateResult\\\"](strings, values, 'svg', _lib_default_template_processor_js__WEBPACK_IMPORTED_MODULE_0__[\\\"defaultTemplateProcessor\\\"]);\\n//# sourceMappingURL=lit-html.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lit-html.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/tslib/tslib.es6.js\":\n/*!*****************************************!*\\\n  !*** ./node_modules/tslib/tslib.es6.js ***!\n  \\*****************************************/\n/*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __createBinding, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault, __classPrivateFieldGet, __classPrivateFieldSet */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__extends\\\", function() { return __extends; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__assign\\\", function() { return __assign; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__rest\\\", function() { return __rest; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__decorate\\\", function() { return __decorate; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__param\\\", function() { return __param; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__metadata\\\", function() { return __metadata; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__awaiter\\\", function() { return __awaiter; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__generator\\\", function() { return __generator; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__createBinding\\\", function() { return __createBinding; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__exportStar\\\", function() { return __exportStar; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__values\\\", function() { return __values; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__read\\\", function() { return __read; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__spread\\\", function() { return __spread; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__spreadArrays\\\", function() { return __spreadArrays; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__await\\\", function() { return __await; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__asyncGenerator\\\", function() { return __asyncGenerator; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__asyncDelegator\\\", function() { return __asyncDelegator; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__asyncValues\\\", function() { return __asyncValues; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__makeTemplateObject\\\", function() { return __makeTemplateObject; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__importStar\\\", function() { return __importStar; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__importDefault\\\", function() { return __importDefault; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__classPrivateFieldGet\\\", function() { return __classPrivateFieldGet; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__classPrivateFieldSet\\\", function() { return __classPrivateFieldSet; });\\n/*! *****************************************************************************\\r\\nCopyright (c) Microsoft Corporation.\\r\\n\\r\\nPermission to use, copy, modify, and/or distribute this software for any\\r\\npurpose with or without fee is hereby granted.\\r\\n\\r\\nTHE SOFTWARE IS PROVIDED \\\"AS IS\\\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\\r\\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\\r\\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\\r\\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\\r\\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\\r\\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\\r\\nPERFORMANCE OF THIS SOFTWARE.\\r\\n***************************************************************************** */\\r\\n/* global Reflect, Promise */\\r\\n\\r\\nvar extendStatics = function(d, b) {\\r\\n    extendStatics = Object.setPrototypeOf ||\\r\\n        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\\r\\n        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\\r\\n    return extendStatics(d, b);\\r\\n};\\r\\n\\r\\nfunction __extends(d, b) {\\r\\n    extendStatics(d, b);\\r\\n    function __() { this.constructor = d; }\\r\\n    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\\r\\n}\\r\\n\\r\\nvar __assign = function() {\\r\\n    __assign = Object.assign || function __assign(t) {\\r\\n        for (var s, i = 1, n = arguments.length; i < n; i++) {\\r\\n            s = arguments[i];\\r\\n            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\\r\\n        }\\r\\n        return t;\\r\\n    }\\r\\n    return __assign.apply(this, arguments);\\r\\n}\\r\\n\\r\\nfunction __rest(s, e) {\\r\\n    var t = {};\\r\\n    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\\r\\n        t[p] = s[p];\\r\\n    if (s != null && typeof Object.getOwnPropertySymbols === \\\"function\\\")\\r\\n        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\\r\\n            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\\r\\n                t[p[i]] = s[p[i]];\\r\\n        }\\r\\n    return t;\\r\\n}\\r\\n\\r\\nfunction __decorate(decorators, target, key, desc) {\\r\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\r\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\r\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\r\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\r\\n}\\r\\n\\r\\nfunction __param(paramIndex, decorator) {\\r\\n    return function (target, key) { decorator(target, key, paramIndex); }\\r\\n}\\r\\n\\r\\nfunction __metadata(metadataKey, metadataValue) {\\r\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.metadata === \\\"function\\\") return Reflect.metadata(metadataKey, metadataValue);\\r\\n}\\r\\n\\r\\nfunction __awaiter(thisArg, _arguments, P, generator) {\\r\\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\\r\\n    return new (P || (P = Promise))(function (resolve, reject) {\\r\\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\\r\\n        function rejected(value) { try { step(generator[\\\"throw\\\"](value)); } catch (e) { reject(e); } }\\r\\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\\r\\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\\r\\n    });\\r\\n}\\r\\n\\r\\nfunction __generator(thisArg, body) {\\r\\n    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\\r\\n    return g = { next: verb(0), \\\"throw\\\": verb(1), \\\"return\\\": verb(2) }, typeof Symbol === \\\"function\\\" && (g[Symbol.iterator] = function() { return this; }), g;\\r\\n    function verb(n) { return function (v) { return step([n, v]); }; }\\r\\n    function step(op) {\\r\\n        if (f) throw new TypeError(\\\"Generator is already executing.\\\");\\r\\n        while (_) try {\\r\\n            if (f = 1, y && (t = op[0] & 2 ? y[\\\"return\\\"] : op[0] ? y[\\\"throw\\\"] || ((t = y[\\\"return\\\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\\r\\n            if (y = 0, t) op = [op[0] & 2, t.value];\\r\\n            switch (op[0]) {\\r\\n                case 0: case 1: t = op; break;\\r\\n                case 4: _.label++; return { value: op[1], done: false };\\r\\n                case 5: _.label++; y = op[1]; op = [0]; continue;\\r\\n                case 7: op = _.ops.pop(); _.trys.pop(); continue;\\r\\n                default:\\r\\n                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\\r\\n                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\\r\\n                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\\r\\n                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\\r\\n                    if (t[2]) _.ops.pop();\\r\\n                    _.trys.pop(); continue;\\r\\n            }\\r\\n            op = body.call(thisArg, _);\\r\\n        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\\r\\n        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\\r\\n    }\\r\\n}\\r\\n\\r\\nfunction __createBinding(o, m, k, k2) {\\r\\n    if (k2 === undefined) k2 = k;\\r\\n    o[k2] = m[k];\\r\\n}\\r\\n\\r\\nfunction __exportStar(m, exports) {\\r\\n    for (var p in m) if (p !== \\\"default\\\" && !exports.hasOwnProperty(p)) exports[p] = m[p];\\r\\n}\\r\\n\\r\\nfunction __values(o) {\\r\\n    var s = typeof Symbol === \\\"function\\\" && Symbol.iterator, m = s && o[s], i = 0;\\r\\n    if (m) return m.call(o);\\r\\n    if (o && typeof o.length === \\\"number\\\") return {\\r\\n        next: function () {\\r\\n            if (o && i >= o.length) o = void 0;\\r\\n            return { value: o && o[i++], done: !o };\\r\\n        }\\r\\n    };\\r\\n    throw new TypeError(s ? \\\"Object is not iterable.\\\" : \\\"Symbol.iterator is not defined.\\\");\\r\\n}\\r\\n\\r\\nfunction __read(o, n) {\\r\\n    var m = typeof Symbol === \\\"function\\\" && o[Symbol.iterator];\\r\\n    if (!m) return o;\\r\\n    var i = m.call(o), r, ar = [], e;\\r\\n    try {\\r\\n        while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\\r\\n    }\\r\\n    catch (error) { e = { error: error }; }\\r\\n    finally {\\r\\n        try {\\r\\n            if (r && !r.done && (m = i[\\\"return\\\"])) m.call(i);\\r\\n        }\\r\\n        finally { if (e) throw e.error; }\\r\\n    }\\r\\n    return ar;\\r\\n}\\r\\n\\r\\nfunction __spread() {\\r\\n    for (var ar = [], i = 0; i < arguments.length; i++)\\r\\n        ar = ar.concat(__read(arguments[i]));\\r\\n    return ar;\\r\\n}\\r\\n\\r\\nfunction __spreadArrays() {\\r\\n    for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\\r\\n    for (var r = Array(s), k = 0, i = 0; i < il; i++)\\r\\n        for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\\r\\n            r[k] = a[j];\\r\\n    return r;\\r\\n};\\r\\n\\r\\nfunction __await(v) {\\r\\n    return this instanceof __await ? (this.v = v, this) : new __await(v);\\r\\n}\\r\\n\\r\\nfunction __asyncGenerator(thisArg, _arguments, generator) {\\r\\n    if (!Symbol.asyncIterator) throw new TypeError(\\\"Symbol.asyncIterator is not defined.\\\");\\r\\n    var g = generator.apply(thisArg, _arguments || []), i, q = [];\\r\\n    return i = {}, verb(\\\"next\\\"), verb(\\\"throw\\\"), verb(\\\"return\\\"), i[Symbol.asyncIterator] = function () { return this; }, i;\\r\\n    function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\\r\\n    function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\\r\\n    function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\\r\\n    function fulfill(value) { resume(\\\"next\\\", value); }\\r\\n    function reject(value) { resume(\\\"throw\\\", value); }\\r\\n    function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\\r\\n}\\r\\n\\r\\nfunction __asyncDelegator(o) {\\r\\n    var i, p;\\r\\n    return i = {}, verb(\\\"next\\\"), verb(\\\"throw\\\", function (e) { throw e; }), verb(\\\"return\\\"), i[Symbol.iterator] = function () { return this; }, i;\\r\\n    function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \\\"return\\\" } : f ? f(v) : v; } : f; }\\r\\n}\\r\\n\\r\\nfunction __asyncValues(o) {\\r\\n    if (!Symbol.asyncIterator) throw new TypeError(\\\"Symbol.asyncIterator is not defined.\\\");\\r\\n    var m = o[Symbol.asyncIterator], i;\\r\\n    return m ? m.call(o) : (o = typeof __values === \\\"function\\\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\\\"next\\\"), verb(\\\"throw\\\"), verb(\\\"return\\\"), i[Symbol.asyncIterator] = function () { return this; }, i);\\r\\n    function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\\r\\n    function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\\r\\n}\\r\\n\\r\\nfunction __makeTemplateObject(cooked, raw) {\\r\\n    if (Object.defineProperty) { Object.defineProperty(cooked, \\\"raw\\\", { value: raw }); } else { cooked.raw = raw; }\\r\\n    return cooked;\\r\\n};\\r\\n\\r\\nfunction __importStar(mod) {\\r\\n    if (mod && mod.__esModule) return mod;\\r\\n    var result = {};\\r\\n    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];\\r\\n    result.default = mod;\\r\\n    return result;\\r\\n}\\r\\n\\r\\nfunction __importDefault(mod) {\\r\\n    return (mod && mod.__esModule) ? mod : { default: mod };\\r\\n}\\r\\n\\r\\nfunction __classPrivateFieldGet(receiver, privateMap) {\\r\\n    if (!privateMap.has(receiver)) {\\r\\n        throw new TypeError(\\\"attempted to get private field on non-instance\\\");\\r\\n    }\\r\\n    return privateMap.get(receiver);\\r\\n}\\r\\n\\r\\nfunction __classPrivateFieldSet(receiver, privateMap, value) {\\r\\n    if (!privateMap.has(receiver)) {\\r\\n        throw new TypeError(\\\"attempted to set private field on non-instance\\\");\\r\\n    }\\r\\n    privateMap.set(receiver, value);\\r\\n    return value;\\r\\n}\\r\\n\\n\\n//# sourceURL=webpack:///./node_modules/tslib/tslib.es6.js?\");\n\n/***/ }),\n\n/***/ \"./src/components/index.ts\":\n/*!*********************************!*\\\n  !*** ./src/components/index.ts ***!\n  \\*********************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\n__webpack_require__(/*! ./input/play-toggle */ \\\"./src/components/input/play-toggle.ts\\\");\\nvar play_toggle_1 = __webpack_require__(/*! ./input/play-toggle */ \\\"./src/components/input/play-toggle.ts\\\");\\nObject.defineProperty(exports, \\\"TonePlayToggle\\\", { enumerable: true, get: function () { return play_toggle_1.TonePlayToggle; } });\\n__webpack_require__(/*! ./input/slider */ \\\"./src/components/input/slider.ts\\\");\\nvar slider_1 = __webpack_require__(/*! ./input/slider */ \\\"./src/components/input/slider.ts\\\");\\nObject.defineProperty(exports, \\\"ToneSlider\\\", { enumerable: true, get: function () { return slider_1.ToneSlider; } });\\n__webpack_require__(/*! ./input/momentary-button */ \\\"./src/components/input/momentary-button.ts\\\");\\nvar momentary_button_1 = __webpack_require__(/*! ./input/momentary-button */ \\\"./src/components/input/momentary-button.ts\\\");\\nObject.defineProperty(exports, \\\"ToneMomentaryButton\\\", { enumerable: true, get: function () { return momentary_button_1.ToneMomentaryButton; } });\\n__webpack_require__(/*! ./interface/mute */ \\\"./src/components/interface/mute.ts\\\");\\nvar mute_1 = __webpack_require__(/*! ./interface/mute */ \\\"./src/components/interface/mute.ts\\\");\\nObject.defineProperty(exports, \\\"ToneMuteButton\\\", { enumerable: true, get: function () { return mute_1.ToneMuteButton; } });\\n__webpack_require__(/*! ./input/mic-button */ \\\"./src/components/input/mic-button.ts\\\");\\nvar mic_button_1 = __webpack_require__(/*! ./input/mic-button */ \\\"./src/components/input/mic-button.ts\\\");\\nObject.defineProperty(exports, \\\"ToneMicButton\\\", { enumerable: true, get: function () { return mic_button_1.ToneMicButton; } });\\n__webpack_require__(/*! ./interface/loader */ \\\"./src/components/interface/loader.ts\\\");\\nvar loader_1 = __webpack_require__(/*! ./interface/loader */ \\\"./src/components/interface/loader.ts\\\");\\nObject.defineProperty(exports, \\\"ToneLoader\\\", { enumerable: true, get: function () { return loader_1.ToneLoader; } });\\n__webpack_require__(/*! ./input/step-sequencer */ \\\"./src/components/input/step-sequencer.ts\\\");\\nvar step_sequencer_1 = __webpack_require__(/*! ./input/step-sequencer */ \\\"./src/components/input/step-sequencer.ts\\\");\\nObject.defineProperty(exports, \\\"ToneStepSequencer\\\", { enumerable: true, get: function () { return step_sequencer_1.ToneStepSequencer; } });\\n__webpack_require__(/*! ./input/slider-pad */ \\\"./src/components/input/slider-pad.ts\\\");\\nvar slider_pad_1 = __webpack_require__(/*! ./input/slider-pad */ \\\"./src/components/input/slider-pad.ts\\\");\\nObject.defineProperty(exports, \\\"ToneSliderPad\\\", { enumerable: true, get: function () { return slider_pad_1.ToneSliderPad; } });\\n__webpack_require__(/*! ./interface/example */ \\\"./src/components/interface/example.ts\\\");\\n\\n\\n//# sourceURL=webpack:///./src/components/index.ts?\");\n\n/***/ }),\n\n/***/ \"./src/components/input/button.scss\":\n/*!******************************************!*\\\n  !*** ./src/components/input/button.scss ***!\n  \\******************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"\\n        var result = __webpack_require__(/*! !../../../node_modules/css-loader/dist/cjs.js!../../../node_modules/sass-loader/dist/cjs.js??ref--5-2!./button.scss */ \\\"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/components/input/button.scss\\\");\\n\\n        if (typeof result === \\\"string\\\") {\\n            module.exports = result;\\n        } else {\\n            module.exports = result.toString();\\n        }\\n    \\n\\n//# sourceURL=webpack:///./src/components/input/button.scss?\");\n\n/***/ }),\n\n/***/ \"./src/components/input/button.ts\":\n/*!****************************************!*\\\n  !*** ./src/components/input/button.ts ***!\n  \\****************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneButton = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst start_1 = __webpack_require__(/*! ../util/start */ \\\"./src/components/util/start.ts\\\");\\nconst style = __webpack_require__(/*! ./button.scss */ \\\"./src/components/input/button.scss\\\");\\nclass ToneButton extends lit_element_1.LitElement {\\n    constructor() {\\n        super(...arguments);\\n        this.pressed = false;\\n        this.disabled = false;\\n    }\\n    updated(changed) {\\n        if (changed.has(\\\"pressed\\\")) {\\n            this.dispatchEvent(new CustomEvent(this.pressed ? \\\"down\\\" : \\\"up\\\", {\\n                composed: true,\\n            }));\\n        }\\n    }\\n    static get styles() {\\n        return lit_element_1.css `\\n\\t\\t\\t${lit_element_1.unsafeCSS(style)}\\n\\t\\t`;\\n    }\\n    _mousedown(e) {\\n        start_1.startContext();\\n        if (e.type === \\\"touchstart\\\") {\\n            e.preventDefault();\\n        }\\n        this.pressed = true;\\n    }\\n    _keydown(e) {\\n        start_1.startContext();\\n        if (e.key === \\\" \\\" || e.key === \\\"Enter\\\") {\\n            this.pressed = true;\\n        }\\n    }\\n    _keyup(e) {\\n        if (e.key === \\\" \\\" || e.key === \\\"Enter\\\") {\\n            this.pressed = false;\\n        }\\n    }\\n    render() {\\n        return lit_element_1.html `\\n\\t\\t\\t<button\\n\\t\\t\\t\\t?disabled=${this.disabled}\\n\\t\\t\\t\\t?pressed=${this.pressed}\\n\\t\\t\\t\\t@keydown=${this._keydown.bind(this)}\\n\\t\\t\\t\\t@keyup=${this._keyup.bind(this)}\\n\\t\\t\\t\\t@mousedown=${this._mousedown.bind(this)}\\n\\t\\t\\t\\t@touchstart=${this._mousedown.bind(this)}\\n\\t\\t\\t\\t@mouseup=${() => (this.pressed = false)}\\n\\t\\t\\t\\t@touchend=${() => (this.pressed = false)}\\n\\t\\t\\t\\taria-label=\\\"Trigger\\\"\\n\\t\\t\\t\\t.aria-checked=${this.pressed}\\n\\t\\t\\t>\\n\\t\\t\\t\\t<slot></slot>\\n\\t\\t\\t</button>\\n\\t\\t`;\\n    }\\n}\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], ToneButton.prototype, \\\"pressed\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], ToneButton.prototype, \\\"disabled\\\", void 0);\\nexports.ToneButton = ToneButton;\\ncustomElements.define(\\\"tone-button\\\", ToneButton);\\n\\n\\n//# sourceURL=webpack:///./src/components/input/button.ts?\");\n\n/***/ }),\n\n/***/ \"./src/components/input/mic-button.scss\":\n/*!**********************************************!*\\\n  !*** ./src/components/input/mic-button.scss ***!\n  \\**********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"\\n        var result = __webpack_require__(/*! !../../../node_modules/css-loader/dist/cjs.js!../../../node_modules/sass-loader/dist/cjs.js??ref--5-2!./mic-button.scss */ \\\"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/components/input/mic-button.scss\\\");\\n\\n        if (typeof result === \\\"string\\\") {\\n            module.exports = result;\\n        } else {\\n            module.exports = result.toString();\\n        }\\n    \\n\\n//# sourceURL=webpack:///./src/components/input/mic-button.scss?\");\n\n/***/ }),\n\n/***/ \"./src/components/input/mic-button.ts\":\n/*!********************************************!*\\\n  !*** ./src/components/input/mic-button.ts ***!\n  \\********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\\n    return new (P || (P = Promise))(function (resolve, reject) {\\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\\n        function rejected(value) { try { step(generator[\\\"throw\\\"](value)); } catch (e) { reject(e); } }\\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\\n    });\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneMicButton = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\n__webpack_require__(/*! ./button */ \\\"./src/components/input/button.ts\\\");\\nconst style = __webpack_require__(/*! ./mic-button.scss */ \\\"./src/components/input/mic-button.scss\\\");\\n// import \\\"@material/mwc-icon\\\";\\nlet ToneMicButton = class ToneMicButton extends lit_element_1.LitElement {\\n    constructor() {\\n        super(...arguments);\\n        this.open = false;\\n        this.supported = false;\\n    }\\n    updated(changed) {\\n        if (changed.has(\\\"open\\\")) {\\n            this.dispatchEvent(new CustomEvent(this.open ? \\\"open\\\" : \\\"close\\\"));\\n        }\\n    }\\n    _clicked() {\\n        return __awaiter(this, void 0, void 0, function* () {\\n            this.open = !this.open;\\n        });\\n    }\\n    static get styles() {\\n        return lit_element_1.css `\\n\\t\\t\\t${lit_element_1.unsafeCSS(style)}\\n\\t\\t`;\\n    }\\n    render() {\\n        return lit_element_1.html `\\n\\t\\t\\t<tone-button\\n\\t\\t\\t\\t?disabled=${!this.supported}\\n\\t\\t\\t\\t@click=${this._clicked.bind(this)}\\n\\t\\t\\t\\ttitle=${this.open ? \\\"Stop\\\" : \\\"Start\\\"}\\n\\t\\t\\t\\taria-label=${this.open ? \\\"Stop\\\" : \\\"Start\\\"}\\n\\t\\t\\t>\\n\\t\\t\\t\\t<mwc-icon>\\n\\t\\t\\t\\t\\t${!this.open ? \\\"mic\\\" : \\\"mic_off\\\"}\\n\\t\\t\\t\\t</mwc-icon>\\n\\t\\t\\t</tone-button>\\n\\t\\t`;\\n    }\\n};\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], ToneMicButton.prototype, \\\"open\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], ToneMicButton.prototype, \\\"supported\\\", void 0);\\nToneMicButton = __decorate([\\n    lit_element_1.customElement(\\\"tone-mic-button\\\")\\n], ToneMicButton);\\nexports.ToneMicButton = ToneMicButton;\\n\\n\\n//# sourceURL=webpack:///./src/components/input/mic-button.ts?\");\n\n/***/ }),\n\n/***/ \"./src/components/input/momentary-button.scss\":\n/*!****************************************************!*\\\n  !*** ./src/components/input/momentary-button.scss ***!\n  \\****************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"\\n        var result = __webpack_require__(/*! !../../../node_modules/css-loader/dist/cjs.js!../../../node_modules/sass-loader/dist/cjs.js??ref--5-2!./momentary-button.scss */ \\\"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/components/input/momentary-button.scss\\\");\\n\\n        if (typeof result === \\\"string\\\") {\\n            module.exports = result;\\n        } else {\\n            module.exports = result.toString();\\n        }\\n    \\n\\n//# sourceURL=webpack:///./src/components/input/momentary-button.scss?\");\n\n/***/ }),\n\n/***/ \"./src/components/input/momentary-button.ts\":\n/*!**************************************************!*\\\n  !*** ./src/components/input/momentary-button.ts ***!\n  \\**************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneMomentaryButton = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst style = __webpack_require__(/*! ./momentary-button.scss */ \\\"./src/components/input/momentary-button.scss\\\");\\n__webpack_require__(/*! ./button */ \\\"./src/components/input/button.ts\\\");\\nlet ToneMomentaryButton = class ToneMomentaryButton extends lit_element_1.LitElement {\\n    constructor() {\\n        super(...arguments);\\n        this.triggered = false;\\n    }\\n    static get styles() {\\n        return lit_element_1.css `\\n\\t\\t\\t${lit_element_1.unsafeCSS(style)}\\n\\t\\t`;\\n    }\\n    render() {\\n        return lit_element_1.html `\\n\\t\\t\\t<tone-button\\n\\t\\t\\t\\t?triggered=${this.triggered}\\n\\t\\t\\t\\t@down=${() => (this.triggered = true)}\\n\\t\\t\\t\\t@up=${() => (this.triggered = false)}\\n\\t\\t\\t>\\n\\t\\t\\t\\t<div id=\\\"ring\\\">\\n\\t\\t\\t\\t\\t<div id=\\\"circle\\\"></div>\\n\\t\\t\\t\\t</div>\\n\\t\\t\\t</tone-button>\\n\\t\\t`;\\n    }\\n};\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], ToneMomentaryButton.prototype, \\\"triggered\\\", void 0);\\nToneMomentaryButton = __decorate([\\n    lit_element_1.customElement(\\\"tone-momentary-button\\\")\\n], ToneMomentaryButton);\\nexports.ToneMomentaryButton = ToneMomentaryButton;\\n\\n\\n//# sourceURL=webpack:///./src/components/input/momentary-button.ts?\");\n\n/***/ }),\n\n/***/ \"./src/components/input/play-toggle.scss\":\n/*!***********************************************!*\\\n  !*** ./src/components/input/play-toggle.scss ***!\n  \\***********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"\\n        var result = __webpack_require__(/*! !../../../node_modules/css-loader/dist/cjs.js!../../../node_modules/sass-loader/dist/cjs.js??ref--5-2!./play-toggle.scss */ \\\"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/components/input/play-toggle.scss\\\");\\n\\n        if (typeof result === \\\"string\\\") {\\n            module.exports = result;\\n        } else {\\n            module.exports = result.toString();\\n        }\\n    \\n\\n//# sourceURL=webpack:///./src/components/input/play-toggle.scss?\");\n\n/***/ }),\n\n/***/ \"./src/components/input/play-toggle.ts\":\n/*!*********************************************!*\\\n  !*** ./src/components/input/play-toggle.ts ***!\n  \\*********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\\n    return new (P || (P = Promise))(function (resolve, reject) {\\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\\n        function rejected(value) { try { step(generator[\\\"throw\\\"](value)); } catch (e) { reject(e); } }\\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\\n    });\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.TonePlayToggle = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\n__webpack_require__(/*! ./button */ \\\"./src/components/input/button.ts\\\");\\nconst style = __webpack_require__(/*! ./play-toggle.scss */ \\\"./src/components/input/play-toggle.scss\\\");\\nlet TonePlayToggle = class TonePlayToggle extends lit_element_1.LitElement {\\n    constructor() {\\n        super(...arguments);\\n        this.started = false;\\n        this.disabled = false;\\n    }\\n    // updated(changed) {\\n    // \\tif (changed.has(\\\"started\\\")) {\\n    // \\t\\tthis.dispatchEvent(\\n    // \\t\\t\\tnew CustomEvent(this.started ? \\\"start\\\" : \\\"stop\\\")\\n    // \\t\\t);\\n    // \\t}\\n    // }\\n    _clicked(e) {\\n        return __awaiter(this, void 0, void 0, function* () {\\n            this.started = !this.started;\\n            e.stopPropagation();\\n            this.dispatchEvent(new CustomEvent(this.started ? \\\"start\\\" : \\\"stop\\\", {\\n                composed: true,\\n            }));\\n        });\\n    }\\n    static get styles() {\\n        return lit_element_1.css `\\n\\t\\t\\t${lit_element_1.unsafeCSS(style)}\\n\\t\\t`;\\n    }\\n    render() {\\n        return lit_element_1.html `\\n\\t\\t\\t<tone-button\\n\\t\\t\\t\\t?disabled=${this.disabled}\\n\\t\\t\\t\\t@click=${!this.disabled ? this._clicked.bind(this) : () => { }}\\n\\t\\t\\t\\ttitle=${this.started ? \\\"Stop\\\" : \\\"Start\\\"}\\n\\t\\t\\t\\taria-label=${this.started ? \\\"Stop\\\" : \\\"Start\\\"}\\n\\t\\t\\t>\\n\\t\\t\\t\\t<mwc-icon>${!this.started ? \\\"play_arrow\\\" : \\\"stop\\\"}</mwc-icon>\\n\\t\\t\\t</tone-button>\\n\\t\\t`;\\n    }\\n};\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], TonePlayToggle.prototype, \\\"started\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], TonePlayToggle.prototype, \\\"disabled\\\", void 0);\\nTonePlayToggle = __decorate([\\n    lit_element_1.customElement(\\\"tone-play-toggle\\\")\\n], TonePlayToggle);\\nexports.TonePlayToggle = TonePlayToggle;\\n\\n\\n//# sourceURL=webpack:///./src/components/input/play-toggle.ts?\");\n\n/***/ }),\n\n/***/ \"./src/components/input/slider-pad.scss\":\n/*!**********************************************!*\\\n  !*** ./src/components/input/slider-pad.scss ***!\n  \\**********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"\\n        var result = __webpack_require__(/*! !../../../node_modules/css-loader/dist/cjs.js!../../../node_modules/sass-loader/dist/cjs.js??ref--5-2!./slider-pad.scss */ \\\"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/components/input/slider-pad.scss\\\");\\n\\n        if (typeof result === \\\"string\\\") {\\n            module.exports = result;\\n        } else {\\n            module.exports = result.toString();\\n        }\\n    \\n\\n//# sourceURL=webpack:///./src/components/input/slider-pad.scss?\");\n\n/***/ }),\n\n/***/ \"./src/components/input/slider-pad.ts\":\n/*!********************************************!*\\\n  !*** ./src/components/input/slider-pad.ts ***!\n  \\********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneSliderPad = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst style = __webpack_require__(/*! ./slider-pad.scss */ \\\"./src/components/input/slider-pad.scss\\\");\\nlet ToneSliderPad = class ToneSliderPad extends lit_element_1.LitElement {\\n    constructor() {\\n        super(...arguments);\\n        this.xPosition = 0.5;\\n        this.yPosition = 0.5;\\n        this.pressed = false;\\n    }\\n    static get styles() {\\n        return lit_element_1.css `${lit_element_1.unsafeCSS(style)}`;\\n    }\\n    _updatePosition(e) {\\n        this.xPosition = this._clamp(e.offsetX / this._container.offsetWidth);\\n        this.yPosition = this._clamp(e.offsetY / this._container.offsetHeight);\\n        this.dispatchEvent(new CustomEvent(\\\"move\\\", {\\n            composed: true,\\n            detail: {\\n                x: this.xPosition,\\n                y: this.yPosition,\\n            }\\n        }));\\n    }\\n    updated(changed) {\\n        if (changed.has(\\\"pressed\\\")) {\\n            this.dispatchEvent(new CustomEvent(this.pressed ? \\\"down\\\" : \\\"up\\\", {\\n                composed: true,\\n                detail: {\\n                    x: this.xPosition,\\n                    y: this.yPosition,\\n                }\\n            }));\\n        }\\n    }\\n    _mousemove(e) {\\n        if (e.buttons) {\\n            this._updatePosition(e);\\n        }\\n    }\\n    _mousedown(e) {\\n        this._updatePosition(e);\\n        this.pressed = true;\\n    }\\n    _mouseup(e) {\\n        this._updatePosition(e);\\n        this.pressed = false;\\n    }\\n    _clamp(value) {\\n        return Math.min(Math.max(value, 0), 1);\\n    }\\n    puckStyle() {\\n        const leftPercent = `${(this.xPosition * 100).toFixed(2)}%`;\\n        const topPercent = `${(this.yPosition * 100).toFixed(2)}%`;\\n        return `left: ${leftPercent}; top: ${topPercent};`;\\n    }\\n    render() {\\n        return lit_element_1.html `\\n\\t\\t\\t<div id=\\\"container\\\">\\n\\t\\t\\t\\t<div class=\\\"square\\\" \\n\\t\\t\\t\\t\\t@mousemove=${this._mousemove.bind(this)}\\n\\t\\t\\t\\t\\t@mousedown=${this._mousedown.bind(this)}\\n\\t\\t\\t\\t\\t@mouseup=${this._mouseup.bind(this)}\\n\\t\\t\\t\\t\\t@mouseleave=${() => this.pressed = false}\\n\\t\\t\\t\\t>\\n\\t\\t\\t\\t\\t<div id=\\\"puck\\\" \\n\\t\\t\\t\\t\\t\\tstyle=\\\"${this.puckStyle()}\\\">\\n\\t\\t\\t\\t\\t</div>\\n\\t\\t\\t\\t</div>\\n\\t\\t\\t</div>\\n\\t\\t`;\\n    }\\n};\\n__decorate([\\n    lit_element_1.property({ type: Number })\\n], ToneSliderPad.prototype, \\\"xPosition\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Number })\\n], ToneSliderPad.prototype, \\\"yPosition\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], ToneSliderPad.prototype, \\\"pressed\\\", void 0);\\n__decorate([\\n    lit_element_1.query(\\\".square\\\")\\n], ToneSliderPad.prototype, \\\"_container\\\", void 0);\\n__decorate([\\n    lit_element_1.query(\\\"#puck\\\")\\n], ToneSliderPad.prototype, \\\"_puck\\\", void 0);\\nToneSliderPad = __decorate([\\n    lit_element_1.customElement(\\\"tone-slider-pad\\\")\\n], ToneSliderPad);\\nexports.ToneSliderPad = ToneSliderPad;\\n\\n\\n//# sourceURL=webpack:///./src/components/input/slider-pad.ts?\");\n\n/***/ }),\n\n/***/ \"./src/components/input/slider.scss\":\n/*!******************************************!*\\\n  !*** ./src/components/input/slider.scss ***!\n  \\******************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"\\n        var result = __webpack_require__(/*! !../../../node_modules/css-loader/dist/cjs.js!../../../node_modules/sass-loader/dist/cjs.js??ref--5-2!./slider.scss */ \\\"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/components/input/slider.scss\\\");\\n\\n        if (typeof result === \\\"string\\\") {\\n            module.exports = result;\\n        } else {\\n            module.exports = result.toString();\\n        }\\n    \\n\\n//# sourceURL=webpack:///./src/components/input/slider.scss?\");\n\n/***/ }),\n\n/***/ \"./src/components/input/slider.ts\":\n/*!****************************************!*\\\n  !*** ./src/components/input/slider.ts ***!\n  \\****************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneSlider = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst style = __webpack_require__(/*! ./slider.scss */ \\\"./src/components/input/slider.scss\\\");\\n__webpack_require__(/*! @material/mwc-slider */ \\\"./node_modules/@material/mwc-slider/mwc-slider.js\\\");\\nclass ToneSlider extends lit_element_1.LitElement {\\n    constructor() {\\n        super(...arguments);\\n        this.min = 0;\\n        this.max = 100;\\n        this.value = 50;\\n        this.step = 1;\\n        this.label = \\\"\\\";\\n        this.units = \\\"\\\";\\n    }\\n    static get styles() {\\n        return lit_element_1.css `\\n\\t\\t\\t${lit_element_1.unsafeCSS(style)}\\n\\t\\t`;\\n    }\\n    onInput(e) {\\n        this.value = parseFloat(e.target.value);\\n        e.stopImmediatePropagation();\\n        e.stopPropagation();\\n        this.dispatchEvent(new CustomEvent(\\\"input\\\", {\\n            composed: true,\\n            detail: this.value,\\n        }));\\n    }\\n    beautifyValue(value) {\\n        if (Number.isInteger(value)) {\\n            return value.toString();\\n        }\\n        else {\\n            return value.toFixed(2);\\n        }\\n    }\\n    render() {\\n        return lit_element_1.html `\\n\\t\\t\\t<div id=\\\"container\\\">\\n\\t\\t\\t\\t<div id=\\\"label\\\">\\n\\t\\t\\t\\t\\t<label for=\\\"slider\\\">${this.label}</label>\\n\\t\\t\\t\\t\\t<span class=\\\"value\\\"\\n\\t\\t\\t\\t\\t\\t>${this.beautifyValue(this.value)}\\n\\t\\t\\t\\t\\t\\t<span class=\\\"units\\\">${this.units}</span></span\\n\\t\\t\\t\\t\\t>\\n\\t\\t\\t\\t</div>\\n\\t\\t\\t\\t<mwc-slider\\n\\t\\t\\t\\t\\tname=\\\"slider\\\"\\n\\t\\t\\t\\t\\t.min=${this.min}\\n\\t\\t\\t\\t\\t.max=${this.max}\\n\\t\\t\\t\\t\\t.value=${this.value}\\n\\t\\t\\t\\t\\t.step=\\\"0\\\"\\n\\t\\t\\t\\t\\t@input=${(e) => (this.value = parseFloat(e.target.value))}\\n\\t\\t\\t\\t></mwc-slider>\\n\\t\\t\\t</div>\\n\\t\\t`;\\n    }\\n}\\n__decorate([\\n    lit_element_1.property({ type: Number })\\n], ToneSlider.prototype, \\\"min\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Number })\\n], ToneSlider.prototype, \\\"max\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Number, reflect: true })\\n], ToneSlider.prototype, \\\"value\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Number })\\n], ToneSlider.prototype, \\\"step\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: String })\\n], ToneSlider.prototype, \\\"label\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: String })\\n], ToneSlider.prototype, \\\"units\\\", void 0);\\nexports.ToneSlider = ToneSlider;\\ncustomElements.define(\\\"tone-slider\\\", ToneSlider);\\n\\n\\n//# sourceURL=webpack:///./src/components/input/slider.ts?\");\n\n/***/ }),\n\n/***/ \"./src/components/input/step-sequencer.scss\":\n/*!**************************************************!*\\\n  !*** ./src/components/input/step-sequencer.scss ***!\n  \\**************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"\\n        var result = __webpack_require__(/*! !../../../node_modules/css-loader/dist/cjs.js!../../../node_modules/sass-loader/dist/cjs.js??ref--5-2!./step-sequencer.scss */ \\\"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/components/input/step-sequencer.scss\\\");\\n\\n        if (typeof result === \\\"string\\\") {\\n            module.exports = result;\\n        } else {\\n            module.exports = result.toString();\\n        }\\n    \\n\\n//# sourceURL=webpack:///./src/components/input/step-sequencer.scss?\");\n\n/***/ }),\n\n/***/ \"./src/components/input/step-sequencer.ts\":\n/*!************************************************!*\\\n  !*** ./src/components/input/step-sequencer.ts ***!\n  \\************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneStepSequencer = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst Tone = __webpack_require__(/*! tone */ \\\"tone\\\");\\nconst style = __webpack_require__(/*! ./step-sequencer.scss */ \\\"./src/components/input/step-sequencer.scss\\\");\\nlet ToneStepSequencer = class ToneStepSequencer extends lit_element_1.LitElement {\\n    constructor() {\\n        super(...arguments);\\n        this.columns = 16;\\n        this.rows = 4;\\n        this.subdivision = \\\"8n\\\";\\n        this._matrix = [];\\n        this.highlighted = -1;\\n        this.started = false;\\n    }\\n    update(changed) {\\n        if (changed.has(\\\"columns\\\") || changed.has(\\\"subdivision\\\")) {\\n            if (this._sequencer) {\\n                this._sequencer.dispose();\\n            }\\n            this._sequencer = new Tone.Sequence(this._tick.bind(this), this._indexArray(this.columns), this.subdivision).start(0);\\n        }\\n        if (changed.has(\\\"columns\\\") || changed.has(\\\"rows\\\")) {\\n            this._matrix = this._indexArray(this.columns).map(() => {\\n                return this._indexArray(this.rows).map(() => false);\\n            });\\n        }\\n        super.update(changed);\\n    }\\n    firstUpdated(props) {\\n        super.firstUpdated(props);\\n        Tone.Transport.on(\\\"start\\\", () => this.started = true);\\n        Tone.Transport.on(\\\"stop\\\", () => {\\n            this.highlighted = -1;\\n            this.started = false;\\n        });\\n    }\\n    updated(changed) {\\n        super.updated(changed);\\n        if (changed.has(\\\"rows\\\")) {\\n            const width = this._container.offsetWidth;\\n            const cellWidth = width / this.columns;\\n            this._container.style.height = `${cellWidth * this.rows}px`;\\n        }\\n    }\\n    _indexArray(count) {\\n        const indices = [];\\n        for (let i = 0; i < count; i++) {\\n            indices.push(i);\\n        }\\n        return indices;\\n    }\\n    _tick(time, index) {\\n        Tone.Draw.schedule(() => {\\n            if (this.started) {\\n                this.highlighted = index;\\n            }\\n        }, time);\\n        this._matrix[index].forEach((value, row) => {\\n            if (value) {\\n                row = this.rows - row - 1;\\n                this.dispatchEvent(new CustomEvent(\\\"trigger\\\", {\\n                    detail: {\\n                        time,\\n                        row,\\n                    },\\n                    composed: true,\\n                }));\\n            }\\n        });\\n    }\\n    static get styles() {\\n        return lit_element_1.css `${lit_element_1.unsafeCSS(style)}`;\\n    }\\n    _updateCell(column, row) {\\n        this._matrix[column][row] = !this._matrix[column][row];\\n        this.requestUpdate();\\n    }\\n    _mouseover(e, column, row) {\\n        if (e.buttons) {\\n            this._updateCell(column, row);\\n        }\\n    }\\n    render() {\\n        return lit_element_1.html `\\n\\t\\t\\t<div id=\\\"container\\\">${this._matrix.map((column, x) => lit_element_1.html `\\n\\t\\t\\t\\t<div class=\\\"column\\\" ?highlighted=${x === this.highlighted}>\\n\\t\\t\\t\\t\\t${column.map((cell, y) => lit_element_1.html `\\n\\t\\t\\t\\t\\t\\t<button \\n\\t\\t\\t\\t\\t\\t\\t@mouseover=${e => this._mouseover(e, x, y)}\\n\\t\\t\\t\\t\\t\\t\\t@mousedown=${e => this._mouseover(e, x, y)}\\n\\t\\t\\t\\t\\t\\t\\tclass=\\\"cell\\\" ?filled=${cell}></button>\\n\\t\\t\\t\\t\\t`)}\\n\\t\\t\\t\\t</div>\\n\\t\\t\\t`)}</div>\\n\\t\\t`;\\n    }\\n};\\n__decorate([\\n    lit_element_1.property({ type: Number })\\n], ToneStepSequencer.prototype, \\\"columns\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Number })\\n], ToneStepSequencer.prototype, \\\"rows\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: String })\\n], ToneStepSequencer.prototype, \\\"subdivision\\\", void 0);\\n__decorate([\\n    lit_element_1.query(\\\"#container\\\")\\n], ToneStepSequencer.prototype, \\\"_container\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Number })\\n], ToneStepSequencer.prototype, \\\"highlighted\\\", void 0);\\nToneStepSequencer = __decorate([\\n    lit_element_1.customElement(\\\"tone-step-sequencer\\\")\\n], ToneStepSequencer);\\nexports.ToneStepSequencer = ToneStepSequencer;\\n\\n\\n//# sourceURL=webpack:///./src/components/input/step-sequencer.ts?\");\n\n/***/ }),\n\n/***/ \"./src/components/interface/example.ts\":\n/*!*********************************************!*\\\n  !*** ./src/components/interface/example.ts ***!\n  \\*********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneExample = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\n__webpack_require__(/*! ./sidebar */ \\\"./src/components/interface/sidebar.ts\\\");\\n__webpack_require__(/*! ./mute */ \\\"./src/components/interface/mute.ts\\\");\\nlet ToneExample = class ToneExample extends lit_element_1.LitElement {\\n    constructor() {\\n        super(...arguments);\\n        this.label = \\\"\\\";\\n        this.open = false;\\n    }\\n    firstUpdated() {\\n        document.querySelector(\\\"body\\\").style.margin = \\\"0px\\\";\\n    }\\n    static get styles() {\\n        return lit_element_1.css `\\n\\t\\t\\t:host {\\n\\t\\t\\t\\twidth: 100%;\\n\\t\\t\\t\\theight: 100%;\\n\\t\\t\\t\\tfont-family: sans-serif;\\n\\t\\t\\t}\\n\\t\\t\\t#explanation {\\n\\t\\t\\t\\tbackground-color: var(--color-light-purple);\\n\\t\\t\\t\\tfont-family: sans-serif;\\n\\t\\t\\t\\tmargin: 20px 0;\\n\\t\\t\\t}\\n\\n\\t\\t\\t::slotted(a) {\\n\\t\\t\\t\\ttext-decoration: none;\\n\\t\\t\\t\\tcolor: #7f33ed;\\n\\t\\t\\t}\\n\\n\\t\\t\\t#container {\\n\\t\\t\\t\\tdisplay: flex;\\n\\t\\t\\t}\\n\\n\\t\\t\\ttone-sidebar,\\n\\t\\t\\t#inner-container {\\n\\t\\t\\t\\tflex: 1;\\n\\t\\t\\t\\ttransition: flex 0.1s;\\n\\t\\t\\t}\\n\\n\\t\\t\\t#inner-container {\\n\\t\\t\\t\\theight: 100vh;\\n\\t\\t\\t\\twidth: 100%;\\n\\t\\t\\t\\toverflow-y: auto;\\n\\t\\t\\t}\\n\\n\\t\\t\\t#body {\\n\\t\\t\\t\\tpadding: 40px;\\n\\t\\t\\t\\tposition: relative;\\n\\t\\t\\t}\\n\\n\\t\\t\\ttone-sidebar {\\n\\t\\t\\t\\tflex: 0 0 240px;\\n\\t\\t\\t\\tz-index: 1;\\n\\t\\t\\t}\\n\\n\\t\\t\\ttone-sidebar:not([open]) {\\n\\t\\t\\t\\tflex: 0 0 0px;\\n\\t\\t\\t\\twidth: 0px;\\n\\t\\t\\t}\\n\\n\\t\\t\\t#content {\\n\\t\\t\\t\\tmax-width: 600px;\\n\\t\\t\\t\\tmargin: 0px auto;\\n\\t\\t\\t}\\n\\n\\t\\t\\t#title {\\n\\t\\t\\t\\tfont-size: 1.1em;\\n\\t\\t\\t\\tcolor: #616161;\\n\\t\\t\\t}\\n\\t\\t`;\\n    }\\n    render() {\\n        return lit_element_1.html `\\n\\t\\t\\t<div id=\\\"container\\\">\\n\\t\\t\\t\\t<tone-sidebar\\n\\t\\t\\t\\t\\t?open=${this.open}\\n\\t\\t\\t\\t\\t@open=${(e) => (this.open = e.detail)}\\n\\t\\t\\t\\t></tone-sidebar>\\n\\t\\t\\t\\t<div id=\\\"inner-container\\\">\\n\\t\\t\\t\\t\\t<div id=\\\"body\\\">\\n\\t\\t\\t\\t\\t\\t<tone-mute></tone-mute>\\n\\t\\t\\t\\t\\t\\t<div id=\\\"title\\\">${this.title}</div>\\n\\t\\t\\t\\t\\t\\t<div id=\\\"explanation\\\">\\n\\t\\t\\t\\t\\t\\t\\t<slot name=\\\"explanation\\\"></slot>\\n\\t\\t\\t\\t\\t\\t</div>\\n\\t\\t\\t\\t\\t\\t<div id=\\\"content\\\">\\n\\t\\t\\t\\t\\t\\t\\t<slot></slot>\\n\\t\\t\\t\\t\\t\\t</div>\\n\\t\\t\\t\\t\\t</div>\\n\\t\\t\\t\\t</div>\\n\\t\\t\\t</div>\\n\\t\\t`;\\n    }\\n};\\n__decorate([\\n    lit_element_1.property({ type: String })\\n], ToneExample.prototype, \\\"label\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], ToneExample.prototype, \\\"open\\\", void 0);\\nToneExample = __decorate([\\n    lit_element_1.customElement(\\\"tone-example\\\")\\n], ToneExample);\\nexports.ToneExample = ToneExample;\\n\\n\\n//# sourceURL=webpack:///./src/components/interface/example.ts?\");\n\n/***/ }),\n\n/***/ \"./src/components/interface/loader.ts\":\n/*!********************************************!*\\\n  !*** ./src/components/interface/loader.ts ***!\n  \\********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneLoader = void 0;\\nconst tone_1 = __webpack_require__(/*! tone */ \\\"tone\\\");\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nclass ToneLoader extends lit_element_1.LitElement {\\n    constructor() {\\n        super(...arguments);\\n        this.loading = false;\\n        this.dots = 0;\\n    }\\n    static get styles() {\\n        return lit_element_1.css `\\n\\t\\t\\t#container {\\n\\t\\t\\t\\tposition: fixed;\\n\\t\\t\\t\\twidth: 100%;\\n\\t\\t\\t\\theight: 100%;\\n\\t\\t\\t\\tbackground-color: rgba(55, 55, 55, 0.5);\\n\\t\\t\\t\\tz-index: 10000000;\\n\\t\\t\\t\\ttop: 0px;\\n\\t\\t\\t\\tleft: 0px;\\n\\t\\t\\t\\tright: 0px;\\n\\t\\t\\t\\tbottom: 0px;\\n\\t\\t\\t\\tpointer-events: none;\\n\\t\\t\\t\\ttransition: opacity 0.2s;\\n\\t\\t\\t\\topacity: 0;\\n\\t\\t\\t}\\n\\t\\t\\t#container[loading] {\\n\\t\\t\\t\\topacity: 1;\\n\\t\\t\\t}\\n\\n\\t\\t\\t#text {\\n\\t\\t\\t\\tposition: absolute;\\n\\t\\t\\t\\ttop: 50%;\\n\\t\\t\\t\\tleft: 50%;\\n\\t\\t\\t\\tfont-family: $titleFont;\\n\\t\\t\\t\\tcolor: white;\\n\\t\\t\\t\\tfont-size: 2em;\\n\\t\\t\\t\\twidth: 100px;\\n\\t\\t\\t\\ttransform: translate(-50%, -50%);\\n\\t\\t\\t}\\n\\t\\t`;\\n    }\\n    firstUpdated(props) {\\n        super.firstUpdated(props);\\n        window.onload = () => {\\n            this.loading = tone_1.ToneAudioBuffer.downloads.length > 0;\\n            if (this.loading) {\\n                tone_1.loaded().then(() => {\\n                    this.loading = false;\\n                });\\n                this._dotLoop();\\n            }\\n        };\\n    }\\n    _dotLoop() {\\n        if (this.loading) {\\n            this.dots = (this.dots + 1) % 4;\\n            setTimeout(() => {\\n                this._dotLoop();\\n            }, 500);\\n        }\\n    }\\n    render() {\\n        let dots = \\\"\\\";\\n        for (let i = 0; i < this.dots; i++) {\\n            dots += \\\".\\\";\\n        }\\n        return lit_element_1.html `\\n\\t\\t\\t<div id=\\\"container\\\" ?loading=${this.loading}>\\n\\t\\t\\t\\t<div id=\\\"text\\\">loading${dots}</div>\\n\\t\\t\\t</div>\\n\\t\\t`;\\n    }\\n}\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], ToneLoader.prototype, \\\"loading\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Number })\\n], ToneLoader.prototype, \\\"dots\\\", void 0);\\nexports.ToneLoader = ToneLoader;\\ncustomElements.define(\\\"tone-loader\\\", ToneLoader);\\n\\n\\n//# sourceURL=webpack:///./src/components/interface/loader.ts?\");\n\n/***/ }),\n\n/***/ \"./src/components/interface/mute.ts\":\n/*!******************************************!*\\\n  !*** ./src/components/interface/mute.ts ***!\n  \\******************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\\n    return new (P || (P = Promise))(function (resolve, reject) {\\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\\n        function rejected(value) { try { step(generator[\\\"throw\\\"](value)); } catch (e) { reject(e); } }\\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\\n    });\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneMuteButton = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst start_1 = __webpack_require__(/*! ../util/start */ \\\"./src/components/util/start.ts\\\");\\nconst tone_1 = __webpack_require__(/*! tone */ \\\"tone\\\");\\nconst class_map_1 = __webpack_require__(/*! lit-html/directives/class-map */ \\\"./node_modules/lit-html/directives/class-map.js\\\");\\n// import { html } from \\\"lit-html\\\";\\n// import \\\"@material/mwc-icon\\\";\\nlet ToneMuteButton = class ToneMuteButton extends lit_element_1.LitElement {\\n    constructor() {\\n        super(...arguments);\\n        this.muted = false;\\n        this.suspended = true;\\n    }\\n    static get styles() {\\n        return lit_element_1.css `\\n\\t\\t\\t:host {\\n\\t\\t\\t\\tposition: absolute;\\n\\t\\t\\t\\ttop: 5px;\\n\\t\\t\\t\\tright: 5px;\\n\\t\\t\\t}\\n\\n\\t\\t\\tbutton {\\n\\t\\t\\t\\t--webkit-appearance: none;\\n\\t\\t\\t\\tappearance: none;\\n\\t\\t\\t\\tborder: none;\\n\\t\\t\\t\\tbackground-color: transparent;\\n\\t\\t\\t}\\n\\t\\t\\tmwc-icon {\\n\\t\\t\\t\\tcursor: pointer;\\n\\t\\t\\t\\tcolor: black;\\n\\t\\t\\t\\tz-index: 100000;\\n\\t\\t\\t}\\n\\t\\t\\tmwc-icon.muted {\\n\\t\\t\\t\\tcolor: #ff4800;\\n\\t\\t\\t}\\n\\t\\t`;\\n    }\\n    firstUpdated(props) {\\n        super.firstUpdated(props);\\n        setInterval(() => {\\n            this.suspended = tone_1.context.state === \\\"suspended\\\";\\n        }, 100);\\n    }\\n    updated(changed) {\\n        if (changed.has(\\\"muted\\\")) {\\n            tone_1.getDestination().mute = this.muted;\\n        }\\n    }\\n    _clicked() {\\n        return __awaiter(this, void 0, void 0, function* () {\\n            if (this.suspended) {\\n                yield start_1.startContext();\\n            }\\n            else {\\n                this.muted = !this.muted;\\n            }\\n        });\\n    }\\n    render() {\\n        return lit_element_1.html `\\n\\t\\t\\t<button aria-label=\\\"mute\\\" @click=${this._clicked}>\\n\\t\\t\\t\\t<mwc-icon\\n\\t\\t\\t\\t\\tclass=${class_map_1.classMap({\\n            muted: this.muted || this.suspended,\\n        })}\\n\\t\\t\\t\\t>\\n\\t\\t\\t\\t\\t${this.muted || this.suspended ? \\\"volume_off\\\" : \\\"volume_up\\\"}\\n\\t\\t\\t\\t</mwc-icon>\\n\\t\\t\\t</button>\\n\\t\\t`;\\n    }\\n};\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], ToneMuteButton.prototype, \\\"muted\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], ToneMuteButton.prototype, \\\"suspended\\\", void 0);\\nToneMuteButton = __decorate([\\n    lit_element_1.customElement(\\\"tone-mute\\\")\\n], ToneMuteButton);\\nexports.ToneMuteButton = ToneMuteButton;\\n\\n\\n//# sourceURL=webpack:///./src/components/interface/mute.ts?\");\n\n/***/ }),\n\n/***/ \"./src/components/interface/sidebar.ts\":\n/*!*********************************************!*\\\n  !*** ./src/components/interface/sidebar.ts ***!\n  \\*********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\\n    return new (P || (P = Promise))(function (resolve, reject) {\\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\\n        function rejected(value) { try { step(generator[\\\"throw\\\"](value)); } catch (e) { reject(e); } }\\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\\n    });\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneSidebar = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst tone_1 = __webpack_require__(/*! tone */ \\\"tone\\\");\\nlet ToneSidebar = class ToneSidebar extends lit_element_1.LitElement {\\n    constructor() {\\n        super(...arguments);\\n        this.open = false;\\n        this.loading = true;\\n        this.examples = {};\\n    }\\n    firstUpdated() {\\n        return __awaiter(this, void 0, void 0, function* () {\\n            const response = yield fetch(\\\"./js/ExampleList.json\\\");\\n            if (response.ok) {\\n                this.examples = yield response.json();\\n                this.loading = false;\\n            }\\n        });\\n    }\\n    updated(changed) {\\n        if (changed.has(\\\"open\\\")) {\\n            this.dispatchEvent(new CustomEvent(\\\"open\\\", {\\n                detail: this.open,\\n            }));\\n        }\\n    }\\n    static get styles() {\\n        return lit_element_1.css `\\n\\t\\t\\t:host {\\n\\t\\t\\t\\tposition: relative;\\n\\t\\t\\t\\theight: 100%;\\n\\t\\t\\t\\twidth: 100%;\\n\\t\\t\\t}\\n\\t\\t\\t#title a {\\n\\t\\t\\t\\tfont-size: 1.2em;\\n\\t\\t\\t\\ttext-decoration: none;\\n\\t\\t\\t\\tcolor: black;\\n\\t\\t\\t\\tfont-family: sans-serif;\\n\\t\\t\\t}\\n\\t\\t\\t#title {\\n\\t\\t\\t\\tmargin: 10px 15px;\\n\\t\\t\\t}\\n\\t\\t\\t#content {\\n\\t\\t\\t\\toverflow: hidden;\\n\\t\\t\\t\\twidth: 100%;\\n\\t\\t\\t\\theight: 100vh;\\n\\t\\t\\t\\toverflow-y: scroll;\\n\\t\\t\\t\\tbackground-color: var(--light-gray, #ececec);\\n\\t\\t\\t}\\n\\t\\t\\t#content:not([open]) {\\n\\t\\t\\t\\twidth: 0px;\\n\\t\\t\\t}\\n\\n\\t\\t\\t#expand {\\n\\t\\t\\t\\tposition: absolute;\\n\\t\\t\\t\\ttop: 0px;\\n\\t\\t\\t\\tright: -35px;\\n\\t\\t\\t\\tappearance: none;\\n\\t\\t\\t\\tbackground-color: transparent;\\n\\t\\t\\t\\tborder: none;\\n\\t\\t\\t}\\n\\n\\t\\t\\tul,\\n\\t\\t\\tli {\\n\\t\\t\\t\\tpadding: 5px 10px;\\n\\t\\t\\t\\ttext-align: left;\\n\\t\\t\\t\\tlist-style-type: none;\\n\\t\\t\\t\\tfont-family: sans-serif;\\n\\t\\t\\t\\twidth: 100%;\\n\\t\\t\\t}\\n\\t\\t\\tul:last-child {\\n\\t\\t\\t\\tpadding-bottom: 20px;\\n\\t\\t\\t}\\n\\t\\t\\tul span {\\n\\t\\t\\t\\ttext-transform: uppercase;\\n\\t\\t\\t\\tborder-bottom: 1px solid #616161;\\n\\t\\t\\t\\tmargin-bottom: 10px;\\n\\t\\t\\t\\twidth: 100%;\\n\\t\\t\\t\\tdisplay: block;\\n\\t\\t\\t\\tcolor: #616161;\\n\\t\\t\\t}\\n\\n\\t\\t\\tli a {\\n\\t\\t\\t\\ttext-decoration: none;\\n\\t\\t\\t\\tcolor: black;\\n\\t\\t\\t\\twidth: 100%;\\n\\t\\t\\t\\tdisplay: block;\\n\\t\\t\\t}\\n\\n\\t\\t\\tli[selected] {\\n\\t\\t\\t\\tborder-top-left-radius: 4px;\\n\\t\\t\\t\\tborder-bottom-left-radius: 4px;\\n\\t\\t\\t\\tbackground-color: white;\\n\\t\\t\\t}\\n\\t\\t`;\\n    }\\n    render() {\\n        const splitPath = window.location.pathname.split(\\\"/\\\");\\n        const exampleName = splitPath[splitPath.length - 1];\\n        return lit_element_1.html `\\n\\t\\t\\t<div id=\\\"content\\\" ?open=${this.open}>\\n\\t\\t\\t\\t<div id=\\\"title\\\">\\n\\t\\t\\t\\t\\t<a href=\\\"https://tonejs.github.io\\\">Tone.js v${tone_1.version}</a>\\n\\t\\t\\t\\t</div>\\n\\t\\t\\t\\t${this.loading\\n            ? \\\"loading\\\"\\n            : Object.keys(this.examples).map((group) => lit_element_1.html `\\n\\t\\t\\t\\t\\t\\t\\t\\t<ul id=\\\"group\\\">\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t<span>${group}</span>\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t${Object.keys(this.examples[group]).map((subgroup) => lit_element_1.html `\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t<li\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t?selected=${exampleName ===\\n                this.examples[group][subgroup]}\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t>\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t<a\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\thref=${this.examples[group][subgroup]}\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t>\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t${subgroup}\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t</a>\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t</li>\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t`)}\\n\\t\\t\\t\\t\\t\\t\\t\\t</ul>\\n\\t\\t\\t\\t\\t\\t\\t`)}\\n\\t\\t\\t</div>\\n\\t\\t\\t<button id=\\\"expand\\\" @click=${() => (this.open = !this.open)}>\\n\\t\\t\\t\\t<mwc-icon>${!this.open ? \\\"menu\\\" : \\\"menu_open\\\"}</mwc-icon>\\n\\t\\t\\t</button>\\n\\t\\t`;\\n    }\\n};\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], ToneSidebar.prototype, \\\"open\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], ToneSidebar.prototype, \\\"loading\\\", void 0);\\nToneSidebar = __decorate([\\n    lit_element_1.customElement(\\\"tone-sidebar\\\")\\n], ToneSidebar);\\nexports.ToneSidebar = ToneSidebar;\\n\\n\\n//# sourceURL=webpack:///./src/components/interface/sidebar.ts?\");\n\n/***/ }),\n\n/***/ \"./src/components/util/start.ts\":\n/*!**************************************!*\\\n  !*** ./src/components/util/start.ts ***!\n  \\**************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.startContext = void 0;\\n// start the audio context\\nconst tone_1 = __webpack_require__(/*! tone */ \\\"tone\\\");\\nfunction startContext() {\\n    tone_1.start();\\n}\\nexports.startContext = startContext;\\n\\n\\n//# sourceURL=webpack:///./src/components/util/start.ts?\");\n\n/***/ }),\n\n/***/ \"tone\":\n/*!***********************!*\\\n  !*** external \"Tone\" ***!\n  \\***********************/\n/*! no static exports found */\n/***/ (function(module, exports) {\n\neval(\"module.exports = Tone;\\n\\n//# sourceURL=webpack:///external_%22Tone%22?\");\n\n/***/ })\n\n/******/ });"
  },
  {
    "path": "examples/js/tone-ui.js",
    "content": "(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"Tone\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"Tone\"], factory);\n\telse {\n\t\tvar a = typeof exports === 'object' ? factory(require(\"Tone\")) : factory(root[\"Tone\"]);\n\t\tfor(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\n\t}\n})(window, function(__WEBPACK_EXTERNAL_MODULE_tone__) {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// define __esModule on exports\n/******/ \t__webpack_require__.r = function(exports) {\n/******/ \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n/******/ \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n/******/ \t\t}\n/******/ \t\tObject.defineProperty(exports, '__esModule', { value: true });\n/******/ \t};\n/******/\n/******/ \t// create a fake namespace object\n/******/ \t// mode & 1: value is a module id, require it\n/******/ \t// mode & 2: merge all properties of value into the ns\n/******/ \t// mode & 4: return value when already ns object\n/******/ \t// mode & 8|1: behave like require\n/******/ \t__webpack_require__.t = function(value, mode) {\n/******/ \t\tif(mode & 1) value = __webpack_require__(value);\n/******/ \t\tif(mode & 8) return value;\n/******/ \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n/******/ \t\tvar ns = Object.create(null);\n/******/ \t\t__webpack_require__.r(ns);\n/******/ \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n/******/ \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n/******/ \t\treturn ns;\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = \"./src/gui/index.ts\");\n/******/ })\n/************************************************************************/\n/******/ ({\n\n/***/ \"./node_modules/@material/mwc-icon/mwc-icon-host-css.js\":\n/*!**************************************************************!*\\\n  !*** ./node_modules/@material/mwc-icon/mwc-icon-host-css.js ***!\n  \\**************************************************************/\n/*! exports provided: style */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"style\\\", function() { return style; });\\n/* harmony import */ var lit_element__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\n/**\\n@license\\nCopyright 2018 Google Inc. All Rights Reserved.\\n\\nLicensed under the Apache License, Version 2.0 (the \\\"License\\\");\\nyou may not use this file except in compliance with the License.\\nYou may obtain a copy of the License at\\n\\n    http://www.apache.org/licenses/LICENSE-2.0\\n\\nUnless required by applicable law or agreed to in writing, software\\ndistributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\nSee the License for the specific language governing permissions and\\nlimitations under the License.\\n*/\\n\\nconst style = lit_element__WEBPACK_IMPORTED_MODULE_0__[\\\"css\\\"] `:host{font-family:var(--mdc-icon-font, \\\"Material Icons\\\");font-weight:normal;font-style:normal;font-size:var(--mdc-icon-size, 24px);line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;font-feature-settings:\\\"liga\\\"}`;\\n//# sourceMappingURL=mwc-icon-host-css.js.map\\n\\n//# sourceURL=webpack:///./node_modules/@material/mwc-icon/mwc-icon-host-css.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/@material/mwc-icon/mwc-icon.js\":\n/*!*****************************************************!*\\\n  !*** ./node_modules/@material/mwc-icon/mwc-icon.js ***!\n  \\*****************************************************/\n/*! exports provided: Icon */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"Icon\\\", function() { return Icon; });\\n/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ \\\"./node_modules/tslib/tslib.es6.js\\\");\\n/* harmony import */ var lit_element__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\n/* harmony import */ var _mwc_icon_host_css_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./mwc-icon-host-css.js */ \\\"./node_modules/@material/mwc-icon/mwc-icon-host-css.js\\\");\\n\\n/**\\n@license\\nCopyright 2018 Google Inc. All Rights Reserved.\\n\\nLicensed under the Apache License, Version 2.0 (the \\\"License\\\");\\nyou may not use this file except in compliance with the License.\\nYou may obtain a copy of the License at\\n\\n    http://www.apache.org/licenses/LICENSE-2.0\\n\\nUnless required by applicable law or agreed to in writing, software\\ndistributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\nSee the License for the specific language governing permissions and\\nlimitations under the License.\\n*/\\n\\n\\n/** @soyCompatible */\\nlet Icon = class Icon extends lit_element__WEBPACK_IMPORTED_MODULE_1__[\\\"LitElement\\\"] {\\n    /** @soyCompatible */\\n    render() {\\n        return lit_element__WEBPACK_IMPORTED_MODULE_1__[\\\"html\\\"] `<slot></slot>`;\\n    }\\n};\\nIcon.styles = _mwc_icon_host_css_js__WEBPACK_IMPORTED_MODULE_2__[\\\"style\\\"];\\nIcon = Object(tslib__WEBPACK_IMPORTED_MODULE_0__[\\\"__decorate\\\"])([\\n    Object(lit_element__WEBPACK_IMPORTED_MODULE_1__[\\\"customElement\\\"])('mwc-icon')\\n], Icon);\\n\\n//# sourceMappingURL=mwc-icon.js.map\\n\\n//# sourceURL=webpack:///./node_modules/@material/mwc-icon/mwc-icon.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/array-filter/index.js\":\n/*!********************************************!*\\\n  !*** ./node_modules/array-filter/index.js ***!\n  \\********************************************/\n/*! no static exports found */\n/***/ (function(module, exports) {\n\neval(\"\\n/**\\n * Array#filter.\\n *\\n * @param {Array} arr\\n * @param {Function} fn\\n * @param {Object=} self\\n * @return {Array}\\n * @throw TypeError\\n */\\n\\nmodule.exports = function (arr, fn, self) {\\n  if (arr.filter) return arr.filter(fn, self);\\n  if (void 0 === arr || null === arr) throw new TypeError;\\n  if ('function' != typeof fn) throw new TypeError;\\n  var ret = [];\\n  for (var i = 0; i < arr.length; i++) {\\n    if (!hasOwn.call(arr, i)) continue;\\n    var val = arr[i];\\n    if (fn.call(self, val, i, arr)) ret.push(val);\\n  }\\n  return ret;\\n};\\n\\nvar hasOwn = Object.prototype.hasOwnProperty;\\n\\n\\n//# sourceURL=webpack:///./node_modules/array-filter/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/audiokeys/src/AudioKeys.buffer.js\":\n/*!********************************************************!*\\\n  !*** ./node_modules/audiokeys/src/AudioKeys.buffer.js ***!\n  \\********************************************************/\n/*! no static exports found */\n/***/ (function(module, exports) {\n\neval(\"// ================================================================\\n// KEY BUFFER\\n// ================================================================\\n\\n// The process is:\\n\\n// key press\\n//   add to self._state.keys\\n//   (an accurate representation of keys currently pressed)\\n// resolve self.buffer\\n//   based on polyphony and priority, determine the notes\\n//   that get triggered for the user\\n\\nmodule.exports = {\\n  _addKey: function(e) {\\n    var self = this;\\n    // if the keyCode is one that can be mapped and isn't\\n    // already pressed, add it to the key object.\\n    if(self._isNote(e.keyCode) && !self._isPressed(e.keyCode)) {\\n      var newKey = self._makeNote(e.keyCode);\\n      // add the newKey to the list of keys\\n      self._state.keys = (self._state.keys || []).concat(newKey);\\n      // reevaluate the active notes based on our priority rules.\\n      // give it the new note to use if there is an event to trigger.\\n      self._update();\\n    } else if(self._isSpecialKey(e.keyCode)) {\\n      self._specialKey(e.keyCode);\\n    }\\n  },\\n\\n  _removeKey: function(e) {\\n    var self = this;\\n    // if the keyCode is active, remove it from the key object.\\n    if(self._isPressed(e.keyCode)) {\\n      var keyToRemove;\\n      for(var i = 0; i < self._state.keys.length; i++) {\\n        if(self._state.keys[i].keyCode === e.keyCode) {\\n          keyToRemove = self._state.keys[i];\\n          break;\\n        }\\n      }\\n\\n      // remove the key from _keys\\n      self._state.keys.splice(self._state.keys.indexOf(keyToRemove), 1);\\n      self._update();\\n    }\\n  },\\n\\n  _isPressed: function(keyCode) {\\n    var self = this;\\n\\n    if(!self._state.keys || !self._state.keys.length) {\\n      return false;\\n    }\\n\\n    for(var i = 0; i < self._state.keys.length; i++) {\\n      if(self._state.keys[i].keyCode === keyCode) {\\n        return true;\\n      }\\n    }\\n    return false;\\n  },\\n\\n  // turn a key object into a note object for the event listeners.\\n  _makeNote: function(keyCode) {\\n    var self = this;\\n    return {\\n      keyCode: keyCode,\\n      note: self._map(keyCode),\\n      frequency: self._toFrequency( self._map(keyCode) ),\\n      velocity: self._state.velocity\\n    };\\n  },\\n\\n  // clear any active notes\\n  clear: function() {\\n    var self = this;\\n    // trigger note off for the notes in the buffer before\\n    // removing them.\\n    self._state.buffer.forEach( function(key) {\\n      // note up events should have a velocity of 0\\n      key.velocity = 0;\\n      self._trigger('up', key);\\n    });\\n    self._state.keys = [];\\n    self._state.buffer = [];\\n  },\\n\\n  // ================================================================\\n  // NOTE BUFFER\\n  // ================================================================\\n\\n  // every time a change is made to _keys due to a key on or key off\\n  // we need to call `_update`. It compares the `_keys` array to the\\n  // `buffer` array, which is the array of notes that are really\\n  // being played, makes the necessary changes to `buffer` and\\n  // triggers any events that need triggering.\\n\\n  _update: function() {\\n    var self = this;\\n\\n    // a key has been added to self._state.keys.\\n    // stash the old buffer\\n    var oldBuffer = self._state.buffer;\\n    // set the new priority in self.state._keys\\n    self._prioritize();\\n    // compare the buffers and trigger events based on\\n    // the differences.\\n    self._diff(oldBuffer);\\n  },\\n\\n  _diff: function(oldBuffer) {\\n    var self = this;\\n\\n    // if it's not in the OLD buffer, it's a note ON.\\n    // if it's not in the NEW buffer, it's a note OFF.\\n\\n    var oldNotes = oldBuffer.map( function(key) {\\n      return key.keyCode;\\n    });\\n\\n    var newNotes = self._state.buffer.map( function(key) {\\n      return key.keyCode;\\n    });\\n\\n    // check for old (removed) notes\\n    var notesToRemove = [];\\n    oldNotes.forEach( function(key) {\\n      if(newNotes.indexOf(key) === -1) {\\n        notesToRemove.push(key);\\n      }\\n    });\\n\\n    // check for new notes\\n    var notesToAdd = [];\\n    newNotes.forEach( function(key) {\\n      if(oldNotes.indexOf(key) === -1) {\\n        notesToAdd.push(key);\\n      }\\n    });\\n\\n    notesToAdd.forEach( function(key) {\\n      for(var i = 0; i < self._state.buffer.length; i++) {\\n        if(self._state.buffer[i].keyCode === key) {\\n          self._trigger('down', self._state.buffer[i]);\\n          break;\\n        }\\n      }\\n    });\\n\\n    notesToRemove.forEach( function(key) {\\n      // these need to fire the entire object\\n      for(var i = 0; i < oldBuffer.length; i++) {\\n        if(oldBuffer[i].keyCode === key) {\\n          // note up events should have a velocity of 0\\n          oldBuffer[i].velocity = 0;\\n          self._trigger('up', oldBuffer[i]);\\n          break;\\n        }\\n      }\\n    });\\n  },\\n\\n};\\n\\n\\n\\n//# sourceURL=webpack:///./node_modules/audiokeys/src/AudioKeys.buffer.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/audiokeys/src/AudioKeys.events.js\":\n/*!********************************************************!*\\\n  !*** ./node_modules/audiokeys/src/AudioKeys.events.js ***!\n  \\********************************************************/\n/*! no static exports found */\n/***/ (function(module, exports) {\n\neval(\"// ================================================================\\n// Event Listeners\\n// ================================================================\\n\\n// AudioKeys has a very simple event handling system. Internally\\n// we'll call self._trigger('down', argument) when we want to fire\\n// an event for the user.\\n\\nmodule.exports = {\\n  down: function(fn) {\\n    var self = this;\\n\\n    // add the function to our list of listeners\\n    self._listeners.down = (self._listeners.down || []).concat(fn);\\n  },\\n\\n  up: function(fn) {\\n    var self = this;\\n\\n    // add the function to our list of listeners\\n    self._listeners.up = (self._listeners.up || []).concat(fn);\\n  },\\n\\n  _trigger: function(action /* args */) {\\n    var self = this;\\n\\n    // if we have any listeners by this name ...\\n    if(self._listeners[action] && self._listeners[action].length) {\\n      // grab the arguments to pass to the listeners ...\\n      var args = Array.prototype.slice.call(arguments);\\n      args.splice(0, 1);\\n      // and call them!\\n      self._listeners[action].forEach( function(fn) {\\n        fn.apply(self, args);\\n      });\\n    }\\n  },\\n\\n  // ================================================================\\n  // DOM Bindings\\n  // ================================================================\\n\\n  _bind: function() {\\n    var self = this;\\n\\n    if(typeof window !== 'undefined' && window.document) {\\n      window.document.addEventListener('keydown', function(e) {\\n        self._addKey(e);\\n      });\\n      window.document.addEventListener('keyup', function(e) {\\n        self._removeKey(e);\\n      });\\n\\n      var lastFocus = true;\\n      setInterval( function() {\\n        if(window.document.hasFocus() === lastFocus) {\\n          return;\\n        }\\n        lastFocus = !lastFocus;\\n        if(!lastFocus) {\\n          self.clear();\\n        }\\n      }, 100);\\n    }\\n  },\\n\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/audiokeys/src/AudioKeys.events.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/audiokeys/src/AudioKeys.js\":\n/*!*************************************************!*\\\n  !*** ./node_modules/audiokeys/src/AudioKeys.js ***!\n  \\*************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"// Each file contains methods of the prototype.\\n// We'll compose them all together here.\\n\\nvar state = __webpack_require__(/*! ./AudioKeys.state */ \\\"./node_modules/audiokeys/src/AudioKeys.state.js\\\");\\nvar events = __webpack_require__(/*! ./AudioKeys.events */ \\\"./node_modules/audiokeys/src/AudioKeys.events.js\\\");\\nvar mapping = __webpack_require__(/*! ./AudioKeys.mapping */ \\\"./node_modules/audiokeys/src/AudioKeys.mapping.js\\\");\\nvar buffer = __webpack_require__(/*! ./AudioKeys.buffer */ \\\"./node_modules/audiokeys/src/AudioKeys.buffer.js\\\");\\nvar priority = __webpack_require__(/*! ./AudioKeys.priority */ \\\"./node_modules/audiokeys/src/AudioKeys.priority.js\\\");\\nvar special = __webpack_require__(/*! ./AudioKeys.special */ \\\"./node_modules/audiokeys/src/AudioKeys.special.js\\\");\\n\\nfunction AudioKeys(options) {\\n  var self = this;\\n\\n  self._setState(options);\\n\\n  // all listeners are stored in arrays in their respective properties.\\n  // e.g. self._listeners.down = [fn1, fn2, ... ]\\n  self._listeners = {};\\n\\n  // bind DOM events\\n  self._bind();\\n}\\n\\n// state\\nAudioKeys.prototype._setState = state._setState;\\nAudioKeys.prototype._extendState = state._extendState;\\nAudioKeys.prototype.set = state.set;\\nAudioKeys.prototype.get = state.get;\\n\\n// events\\nAudioKeys.prototype.down = events.down;\\nAudioKeys.prototype.up = events.up;\\nAudioKeys.prototype._trigger = events._trigger;\\nAudioKeys.prototype._bind = events._bind;\\n\\n// mapping\\nAudioKeys.prototype._map = mapping._map;\\nAudioKeys.prototype._offset = mapping._offset;\\nAudioKeys.prototype._isNote = mapping._isNote;\\nAudioKeys.prototype._toFrequency = mapping._toFrequency;\\nAudioKeys.prototype._keyMap = mapping._keyMap;\\n\\n// buffer\\nAudioKeys.prototype._addKey = buffer._addKey;\\nAudioKeys.prototype._removeKey = buffer._removeKey;\\nAudioKeys.prototype._isPressed = buffer._isPressed;\\nAudioKeys.prototype._makeNote = buffer._makeNote;\\nAudioKeys.prototype.clear = buffer.clear;\\nAudioKeys.prototype._update = buffer._update;\\nAudioKeys.prototype._diff = buffer._diff;\\n\\n// priority\\nAudioKeys.prototype._prioritize = priority._prioritize;\\nAudioKeys.prototype._last = priority._last;\\nAudioKeys.prototype._first = priority._first;\\nAudioKeys.prototype._highest = priority._highest;\\nAudioKeys.prototype._lowest = priority._lowest;\\n\\n// special\\nAudioKeys.prototype._isSpecialKey = special._isSpecialKey;\\nAudioKeys.prototype._specialKey = special._specialKey;\\nAudioKeys.prototype._specialKeyMap = special._specialKeyMap;\\n\\n// Browserify will take care of making this a global\\n// in a browser environment without a build system.\\nmodule.exports = AudioKeys;\\n\\n//# sourceURL=webpack:///./node_modules/audiokeys/src/AudioKeys.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/audiokeys/src/AudioKeys.mapping.js\":\n/*!*********************************************************!*\\\n  !*** ./node_modules/audiokeys/src/AudioKeys.mapping.js ***!\n  \\*********************************************************/\n/*! no static exports found */\n/***/ (function(module, exports) {\n\neval(\"module.exports = {\\n    // _map returns the midi note for a given keyCode.\\n    _map: function(keyCode) {\\n      return this._keyMap[this._state.rows][keyCode] + this._offset();\\n    },\\n\\n    _offset: function() {\\n      return this._state.rootNote - this._keyMap[this._state.rows].root + (this._state.octave * 12);\\n    },\\n\\n    // _isNote determines whether a keyCode is a note or not.\\n    _isNote: function(keyCode) {\\n      return !!this._keyMap[this._state.rows][keyCode];\\n    },\\n\\n    // convert a midi note to a frequency. we assume here that _map has\\n    // already been called (to account for a potential rootNote offset)\\n    _toFrequency: function(note) {\\n      return ( Math.pow(2, ( note-69 ) / 12) ) * 440.0;\\n    },\\n\\n    // the object keys correspond to `rows`, so `_keyMap[rows]` should\\n    // retrieve that particular mapping.\\n    _keyMap: {\\n      1: {\\n        root: 60,\\n        // starting with the 'a' key\\n        65:  60,\\n        87:  61,\\n        83:  62,\\n        69:  63,\\n        68:  64,\\n        70:  65,\\n        84:  66,\\n        71:  67,\\n        89:  68,\\n        72:  69,\\n        85:  70,\\n        74:  71,\\n        75:  72,\\n        79:  73,\\n        76:  74,\\n        80:  75,\\n        186: 76,\\n        222: 77\\n      },\\n      2: {\\n        root: 60,\\n        // bottom row\\n        90:  60,\\n        83:  61,\\n        88:  62,\\n        68:  63,\\n        67:  64,\\n        86:  65,\\n        71:  66,\\n        66:  67,\\n        72:  68,\\n        78:  69,\\n        74:  70,\\n        77:  71,\\n        188: 72,\\n        76:  73,\\n        190: 74,\\n        186: 75,\\n        191: 76,\\n        // top row\\n        81:  72,\\n        50:  73,\\n        87:  74,\\n        51:  75,\\n        69:  76,\\n        82:  77,\\n        53:  78,\\n        84:  79,\\n        54:  80,\\n        89:  81,\\n        55:  82,\\n        85:  83,\\n        73:  84,\\n        57:  85,\\n        79:  86,\\n        48:  87,\\n        80:  88,\\n        219: 89,\\n        187: 90,\\n        221: 91\\n      }\\n    },\\n\\n};\\n\\n\\n\\n//# sourceURL=webpack:///./node_modules/audiokeys/src/AudioKeys.mapping.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/audiokeys/src/AudioKeys.priority.js\":\n/*!**********************************************************!*\\\n  !*** ./node_modules/audiokeys/src/AudioKeys.priority.js ***!\n  \\**********************************************************/\n/*! no static exports found */\n/***/ (function(module, exports) {\n\neval(\"module.exports = {\\n  _prioritize: function() {\\n    var self = this;\\n\\n    // if all the keys have been turned off, no need\\n    // to do anything here.\\n    if(!self._state.keys.length) {\\n      self._state.buffer = [];\\n      return;\\n    }\\n\\n\\n    if(self._state.polyphony >= self._state.keys.length) {\\n      // every note is active\\n      self._state.keys = self._state.keys.map( function(key) {\\n        key.isActive = true;\\n        return key;\\n      });\\n    } else {\\n      // set all keys to inactive.\\n      self._state.keys = self._state.keys.map( function(key) {\\n        key.isActive = false;\\n        return key;\\n      });\\n\\n      self['_' + self._state.priority]();\\n    }\\n\\n    // now take the isActive keys and set the new buffer.\\n    self._state.buffer = [];\\n\\n    self._state.keys.forEach( function(key) {\\n      if(key.isActive) {\\n        self._state.buffer.push(key);\\n      }\\n    });\\n\\n    // done.\\n  },\\n\\n  _last: function() {\\n    var self = this;\\n    // set the last bunch to active based on the polyphony.\\n    for(var i = self._state.keys.length - self._state.polyphony; i < self._state.keys.length; i++) {\\n      self._state.keys[i].isActive = true;\\n    }\\n  },\\n\\n  _first: function() {\\n    var self = this;\\n    // set the last bunch to active based on the polyphony.\\n    for(var i = 0; i < self._state.polyphony; i++) {\\n      self._state.keys[i].isActive = true;\\n    }\\n  },\\n\\n  _highest: function() {\\n    var self = this;\\n    // get the highest notes and set them to active\\n    var notes = self._state.keys.map( function(key) {\\n      return key.note;\\n    });\\n\\n    notes.sort( function(b,a) {\\n      if(a === b) {\\n        return 0;\\n      }\\n      return a < b ? -1 : 1;\\n    });\\n\\n    notes.splice(self._state.polyphony, Number.MAX_VALUE);\\n\\n    self._state.keys.forEach( function(key) {\\n      if(notes.indexOf(key.note) !== -1) {\\n        key.isActive = true;\\n      }\\n    });\\n  },\\n\\n  _lowest: function() {\\n    var self = this;\\n    // get the lowest notes and set them to active\\n    var notes = self._state.keys.map( function(key) {\\n      return key.note;\\n    });\\n\\n    notes.sort( function(a,b) {\\n      if(a === b) {\\n        return 0;\\n      }\\n      return a < b ? -1 : 1;\\n    });\\n\\n    notes.splice(self._state.polyphony, Number.MAX_VALUE);\\n\\n    self._state.keys.forEach( function(key) {\\n      if(notes.indexOf(key.note) !== -1) {\\n        key.isActive = true;\\n      }\\n    });\\n  },\\n\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/audiokeys/src/AudioKeys.priority.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/audiokeys/src/AudioKeys.special.js\":\n/*!*********************************************************!*\\\n  !*** ./node_modules/audiokeys/src/AudioKeys.special.js ***!\n  \\*********************************************************/\n/*! no static exports found */\n/***/ (function(module, exports) {\n\neval(\"// This file maps special keys to the state— octave shifting and\\n// velocity selection, both available when `rows` = 1.\\nmodule.exports = {\\n  _isSpecialKey: function(keyCode) {\\n    return (this._state.rows === 1 && this._specialKeyMap[keyCode]);\\n  },\\n\\n  _specialKey: function(keyCode) {\\n    var self = this;\\n    if(self._specialKeyMap[keyCode].type === 'octave' && self._state.octaveControls) {\\n      // shift the state of the `octave`\\n      self._state.octave += self._specialKeyMap[keyCode].value;\\n    } else if(self._specialKeyMap[keyCode].type === 'velocity' && self._state.velocityControls) {\\n      // set the `velocity` to a new value\\n      self._state.velocity = self._specialKeyMap[keyCode].value;\\n    }\\n  },\\n\\n  _specialKeyMap: {\\n    // octaves\\n    90: {\\n      type: 'octave',\\n      value: -1\\n    },\\n    88: {\\n      type: 'octave',\\n      value: 1\\n    },\\n    // velocity\\n    49: {\\n      type: 'velocity',\\n      value: 1\\n    },\\n    50: {\\n      type: 'velocity',\\n      value: 14\\n    },\\n    51: {\\n      type: 'velocity',\\n      value: 28\\n    },\\n    52: {\\n      type: 'velocity',\\n      value: 42\\n    },\\n    53: {\\n      type: 'velocity',\\n      value: 56\\n    },\\n    54: {\\n      type: 'velocity',\\n      value: 70\\n    },\\n    55: {\\n      type: 'velocity',\\n      value: 84\\n    },\\n    56: {\\n      type: 'velocity',\\n      value: 98\\n    },\\n    57: {\\n      type: 'velocity',\\n      value: 112\\n    },\\n    48: {\\n      type: 'velocity',\\n      value: 127\\n    },\\n  },\\n\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/audiokeys/src/AudioKeys.special.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/audiokeys/src/AudioKeys.state.js\":\n/*!*******************************************************!*\\\n  !*** ./node_modules/audiokeys/src/AudioKeys.state.js ***!\n  \\*******************************************************/\n/*! no static exports found */\n/***/ (function(module, exports) {\n\neval(\"module.exports = {\\n  _setState: function(options) {\\n    var self = this;\\n\\n    if(!options) {\\n      options = {};\\n    }\\n\\n    // the state is kept in this object\\n    self._state = {};\\n\\n    // set some defaults ...\\n    self._extendState({\\n      polyphony: 4,\\n      rows: 1,\\n      priority: 'last',\\n      rootNote: 60,\\n      octaveControls: true,\\n      octave: 0,\\n      velocityControls: true,\\n      velocity: 127,\\n      keys: [],\\n      buffer: []\\n    });\\n\\n    // ... and override them with options.\\n    self._extendState(options);\\n  },\\n\\n  _extendState: function(options) {\\n    var self = this;\\n\\n    for(var o in options) {\\n      self._state[o] = options[o];\\n    }\\n  },\\n\\n  set: function(/* options || property, value */) {\\n    var self = this;\\n\\n    if(arguments.length === 1) {\\n      self._extendState(arguments[0]);\\n    } else {\\n      self._state[arguments[0]] = arguments[1];\\n    }\\n\\n    return this;\\n  },\\n\\n  get: function(property) {\\n    var self = this;\\n\\n    return self._state[property];\\n  },\\n\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/audiokeys/src/AudioKeys.state.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/available-typed-arrays/index.js\":\n/*!******************************************************!*\\\n  !*** ./node_modules/available-typed-arrays/index.js ***!\n  \\******************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"/* WEBPACK VAR INJECTION */(function(global) {\\n\\nvar filter = __webpack_require__(/*! array-filter */ \\\"./node_modules/array-filter/index.js\\\");\\n\\nmodule.exports = function availableTypedArrays() {\\n\\treturn filter([\\n\\t\\t'BigInt64Array',\\n\\t\\t'BigUint64Array',\\n\\t\\t'Float32Array',\\n\\t\\t'Float64Array',\\n\\t\\t'Int16Array',\\n\\t\\t'Int32Array',\\n\\t\\t'Int8Array',\\n\\t\\t'Uint16Array',\\n\\t\\t'Uint32Array',\\n\\t\\t'Uint8Array',\\n\\t\\t'Uint8ClampedArray'\\n\\t], function (typedArray) {\\n\\t\\treturn typeof global[typedArray] === 'function';\\n\\t});\\n};\\n\\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../webpack/buildin/global.js */ \\\"./node_modules/webpack/buildin/global.js\\\")))\\n\\n//# sourceURL=webpack:///./node_modules/available-typed-arrays/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/color-convert/conversions.js\":\n/*!***************************************************!*\\\n  !*** ./node_modules/color-convert/conversions.js ***!\n  \\***************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"/* MIT license */\\nvar cssKeywords = __webpack_require__(/*! color-name */ \\\"./node_modules/color-name/index.js\\\");\\n\\n// NOTE: conversions should only return primitive values (i.e. arrays, or\\n//       values that give correct `typeof` results).\\n//       do not use box values types (i.e. Number(), String(), etc.)\\n\\nvar reverseKeywords = {};\\nfor (var key in cssKeywords) {\\n\\tif (cssKeywords.hasOwnProperty(key)) {\\n\\t\\treverseKeywords[cssKeywords[key]] = key;\\n\\t}\\n}\\n\\nvar convert = module.exports = {\\n\\trgb: {channels: 3, labels: 'rgb'},\\n\\thsl: {channels: 3, labels: 'hsl'},\\n\\thsv: {channels: 3, labels: 'hsv'},\\n\\thwb: {channels: 3, labels: 'hwb'},\\n\\tcmyk: {channels: 4, labels: 'cmyk'},\\n\\txyz: {channels: 3, labels: 'xyz'},\\n\\tlab: {channels: 3, labels: 'lab'},\\n\\tlch: {channels: 3, labels: 'lch'},\\n\\thex: {channels: 1, labels: ['hex']},\\n\\tkeyword: {channels: 1, labels: ['keyword']},\\n\\tansi16: {channels: 1, labels: ['ansi16']},\\n\\tansi256: {channels: 1, labels: ['ansi256']},\\n\\thcg: {channels: 3, labels: ['h', 'c', 'g']},\\n\\tapple: {channels: 3, labels: ['r16', 'g16', 'b16']},\\n\\tgray: {channels: 1, labels: ['gray']}\\n};\\n\\n// hide .channels and .labels properties\\nfor (var model in convert) {\\n\\tif (convert.hasOwnProperty(model)) {\\n\\t\\tif (!('channels' in convert[model])) {\\n\\t\\t\\tthrow new Error('missing channels property: ' + model);\\n\\t\\t}\\n\\n\\t\\tif (!('labels' in convert[model])) {\\n\\t\\t\\tthrow new Error('missing channel labels property: ' + model);\\n\\t\\t}\\n\\n\\t\\tif (convert[model].labels.length !== convert[model].channels) {\\n\\t\\t\\tthrow new Error('channel and label counts mismatch: ' + model);\\n\\t\\t}\\n\\n\\t\\tvar channels = convert[model].channels;\\n\\t\\tvar labels = convert[model].labels;\\n\\t\\tdelete convert[model].channels;\\n\\t\\tdelete convert[model].labels;\\n\\t\\tObject.defineProperty(convert[model], 'channels', {value: channels});\\n\\t\\tObject.defineProperty(convert[model], 'labels', {value: labels});\\n\\t}\\n}\\n\\nconvert.rgb.hsl = function (rgb) {\\n\\tvar r = rgb[0] / 255;\\n\\tvar g = rgb[1] / 255;\\n\\tvar b = rgb[2] / 255;\\n\\tvar min = Math.min(r, g, b);\\n\\tvar max = Math.max(r, g, b);\\n\\tvar delta = max - min;\\n\\tvar h;\\n\\tvar s;\\n\\tvar l;\\n\\n\\tif (max === min) {\\n\\t\\th = 0;\\n\\t} else if (r === max) {\\n\\t\\th = (g - b) / delta;\\n\\t} else if (g === max) {\\n\\t\\th = 2 + (b - r) / delta;\\n\\t} else if (b === max) {\\n\\t\\th = 4 + (r - g) / delta;\\n\\t}\\n\\n\\th = Math.min(h * 60, 360);\\n\\n\\tif (h < 0) {\\n\\t\\th += 360;\\n\\t}\\n\\n\\tl = (min + max) / 2;\\n\\n\\tif (max === min) {\\n\\t\\ts = 0;\\n\\t} else if (l <= 0.5) {\\n\\t\\ts = delta / (max + min);\\n\\t} else {\\n\\t\\ts = delta / (2 - max - min);\\n\\t}\\n\\n\\treturn [h, s * 100, l * 100];\\n};\\n\\nconvert.rgb.hsv = function (rgb) {\\n\\tvar rdif;\\n\\tvar gdif;\\n\\tvar bdif;\\n\\tvar h;\\n\\tvar s;\\n\\n\\tvar r = rgb[0] / 255;\\n\\tvar g = rgb[1] / 255;\\n\\tvar b = rgb[2] / 255;\\n\\tvar v = Math.max(r, g, b);\\n\\tvar diff = v - Math.min(r, g, b);\\n\\tvar diffc = function (c) {\\n\\t\\treturn (v - c) / 6 / diff + 1 / 2;\\n\\t};\\n\\n\\tif (diff === 0) {\\n\\t\\th = s = 0;\\n\\t} else {\\n\\t\\ts = diff / v;\\n\\t\\trdif = diffc(r);\\n\\t\\tgdif = diffc(g);\\n\\t\\tbdif = diffc(b);\\n\\n\\t\\tif (r === v) {\\n\\t\\t\\th = bdif - gdif;\\n\\t\\t} else if (g === v) {\\n\\t\\t\\th = (1 / 3) + rdif - bdif;\\n\\t\\t} else if (b === v) {\\n\\t\\t\\th = (2 / 3) + gdif - rdif;\\n\\t\\t}\\n\\t\\tif (h < 0) {\\n\\t\\t\\th += 1;\\n\\t\\t} else if (h > 1) {\\n\\t\\t\\th -= 1;\\n\\t\\t}\\n\\t}\\n\\n\\treturn [\\n\\t\\th * 360,\\n\\t\\ts * 100,\\n\\t\\tv * 100\\n\\t];\\n};\\n\\nconvert.rgb.hwb = function (rgb) {\\n\\tvar r = rgb[0];\\n\\tvar g = rgb[1];\\n\\tvar b = rgb[2];\\n\\tvar h = convert.rgb.hsl(rgb)[0];\\n\\tvar w = 1 / 255 * Math.min(r, Math.min(g, b));\\n\\n\\tb = 1 - 1 / 255 * Math.max(r, Math.max(g, b));\\n\\n\\treturn [h, w * 100, b * 100];\\n};\\n\\nconvert.rgb.cmyk = function (rgb) {\\n\\tvar r = rgb[0] / 255;\\n\\tvar g = rgb[1] / 255;\\n\\tvar b = rgb[2] / 255;\\n\\tvar c;\\n\\tvar m;\\n\\tvar y;\\n\\tvar k;\\n\\n\\tk = Math.min(1 - r, 1 - g, 1 - b);\\n\\tc = (1 - r - k) / (1 - k) || 0;\\n\\tm = (1 - g - k) / (1 - k) || 0;\\n\\ty = (1 - b - k) / (1 - k) || 0;\\n\\n\\treturn [c * 100, m * 100, y * 100, k * 100];\\n};\\n\\n/**\\n * See https://en.m.wikipedia.org/wiki/Euclidean_distance#Squared_Euclidean_distance\\n * */\\nfunction comparativeDistance(x, y) {\\n\\treturn (\\n\\t\\tMath.pow(x[0] - y[0], 2) +\\n\\t\\tMath.pow(x[1] - y[1], 2) +\\n\\t\\tMath.pow(x[2] - y[2], 2)\\n\\t);\\n}\\n\\nconvert.rgb.keyword = function (rgb) {\\n\\tvar reversed = reverseKeywords[rgb];\\n\\tif (reversed) {\\n\\t\\treturn reversed;\\n\\t}\\n\\n\\tvar currentClosestDistance = Infinity;\\n\\tvar currentClosestKeyword;\\n\\n\\tfor (var keyword in cssKeywords) {\\n\\t\\tif (cssKeywords.hasOwnProperty(keyword)) {\\n\\t\\t\\tvar value = cssKeywords[keyword];\\n\\n\\t\\t\\t// Compute comparative distance\\n\\t\\t\\tvar distance = comparativeDistance(rgb, value);\\n\\n\\t\\t\\t// Check if its less, if so set as closest\\n\\t\\t\\tif (distance < currentClosestDistance) {\\n\\t\\t\\t\\tcurrentClosestDistance = distance;\\n\\t\\t\\t\\tcurrentClosestKeyword = keyword;\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n\\n\\treturn currentClosestKeyword;\\n};\\n\\nconvert.keyword.rgb = function (keyword) {\\n\\treturn cssKeywords[keyword];\\n};\\n\\nconvert.rgb.xyz = function (rgb) {\\n\\tvar r = rgb[0] / 255;\\n\\tvar g = rgb[1] / 255;\\n\\tvar b = rgb[2] / 255;\\n\\n\\t// assume sRGB\\n\\tr = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);\\n\\tg = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);\\n\\tb = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);\\n\\n\\tvar x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);\\n\\tvar y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);\\n\\tvar z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);\\n\\n\\treturn [x * 100, y * 100, z * 100];\\n};\\n\\nconvert.rgb.lab = function (rgb) {\\n\\tvar xyz = convert.rgb.xyz(rgb);\\n\\tvar x = xyz[0];\\n\\tvar y = xyz[1];\\n\\tvar z = xyz[2];\\n\\tvar l;\\n\\tvar a;\\n\\tvar b;\\n\\n\\tx /= 95.047;\\n\\ty /= 100;\\n\\tz /= 108.883;\\n\\n\\tx = x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116);\\n\\ty = y > 0.008856 ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116);\\n\\tz = z > 0.008856 ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116);\\n\\n\\tl = (116 * y) - 16;\\n\\ta = 500 * (x - y);\\n\\tb = 200 * (y - z);\\n\\n\\treturn [l, a, b];\\n};\\n\\nconvert.hsl.rgb = function (hsl) {\\n\\tvar h = hsl[0] / 360;\\n\\tvar s = hsl[1] / 100;\\n\\tvar l = hsl[2] / 100;\\n\\tvar t1;\\n\\tvar t2;\\n\\tvar t3;\\n\\tvar rgb;\\n\\tvar val;\\n\\n\\tif (s === 0) {\\n\\t\\tval = l * 255;\\n\\t\\treturn [val, val, val];\\n\\t}\\n\\n\\tif (l < 0.5) {\\n\\t\\tt2 = l * (1 + s);\\n\\t} else {\\n\\t\\tt2 = l + s - l * s;\\n\\t}\\n\\n\\tt1 = 2 * l - t2;\\n\\n\\trgb = [0, 0, 0];\\n\\tfor (var i = 0; i < 3; i++) {\\n\\t\\tt3 = h + 1 / 3 * -(i - 1);\\n\\t\\tif (t3 < 0) {\\n\\t\\t\\tt3++;\\n\\t\\t}\\n\\t\\tif (t3 > 1) {\\n\\t\\t\\tt3--;\\n\\t\\t}\\n\\n\\t\\tif (6 * t3 < 1) {\\n\\t\\t\\tval = t1 + (t2 - t1) * 6 * t3;\\n\\t\\t} else if (2 * t3 < 1) {\\n\\t\\t\\tval = t2;\\n\\t\\t} else if (3 * t3 < 2) {\\n\\t\\t\\tval = t1 + (t2 - t1) * (2 / 3 - t3) * 6;\\n\\t\\t} else {\\n\\t\\t\\tval = t1;\\n\\t\\t}\\n\\n\\t\\trgb[i] = val * 255;\\n\\t}\\n\\n\\treturn rgb;\\n};\\n\\nconvert.hsl.hsv = function (hsl) {\\n\\tvar h = hsl[0];\\n\\tvar s = hsl[1] / 100;\\n\\tvar l = hsl[2] / 100;\\n\\tvar smin = s;\\n\\tvar lmin = Math.max(l, 0.01);\\n\\tvar sv;\\n\\tvar v;\\n\\n\\tl *= 2;\\n\\ts *= (l <= 1) ? l : 2 - l;\\n\\tsmin *= lmin <= 1 ? lmin : 2 - lmin;\\n\\tv = (l + s) / 2;\\n\\tsv = l === 0 ? (2 * smin) / (lmin + smin) : (2 * s) / (l + s);\\n\\n\\treturn [h, sv * 100, v * 100];\\n};\\n\\nconvert.hsv.rgb = function (hsv) {\\n\\tvar h = hsv[0] / 60;\\n\\tvar s = hsv[1] / 100;\\n\\tvar v = hsv[2] / 100;\\n\\tvar hi = Math.floor(h) % 6;\\n\\n\\tvar f = h - Math.floor(h);\\n\\tvar p = 255 * v * (1 - s);\\n\\tvar q = 255 * v * (1 - (s * f));\\n\\tvar t = 255 * v * (1 - (s * (1 - f)));\\n\\tv *= 255;\\n\\n\\tswitch (hi) {\\n\\t\\tcase 0:\\n\\t\\t\\treturn [v, t, p];\\n\\t\\tcase 1:\\n\\t\\t\\treturn [q, v, p];\\n\\t\\tcase 2:\\n\\t\\t\\treturn [p, v, t];\\n\\t\\tcase 3:\\n\\t\\t\\treturn [p, q, v];\\n\\t\\tcase 4:\\n\\t\\t\\treturn [t, p, v];\\n\\t\\tcase 5:\\n\\t\\t\\treturn [v, p, q];\\n\\t}\\n};\\n\\nconvert.hsv.hsl = function (hsv) {\\n\\tvar h = hsv[0];\\n\\tvar s = hsv[1] / 100;\\n\\tvar v = hsv[2] / 100;\\n\\tvar vmin = Math.max(v, 0.01);\\n\\tvar lmin;\\n\\tvar sl;\\n\\tvar l;\\n\\n\\tl = (2 - s) * v;\\n\\tlmin = (2 - s) * vmin;\\n\\tsl = s * vmin;\\n\\tsl /= (lmin <= 1) ? lmin : 2 - lmin;\\n\\tsl = sl || 0;\\n\\tl /= 2;\\n\\n\\treturn [h, sl * 100, l * 100];\\n};\\n\\n// http://dev.w3.org/csswg/css-color/#hwb-to-rgb\\nconvert.hwb.rgb = function (hwb) {\\n\\tvar h = hwb[0] / 360;\\n\\tvar wh = hwb[1] / 100;\\n\\tvar bl = hwb[2] / 100;\\n\\tvar ratio = wh + bl;\\n\\tvar i;\\n\\tvar v;\\n\\tvar f;\\n\\tvar n;\\n\\n\\t// wh + bl cant be > 1\\n\\tif (ratio > 1) {\\n\\t\\twh /= ratio;\\n\\t\\tbl /= ratio;\\n\\t}\\n\\n\\ti = Math.floor(6 * h);\\n\\tv = 1 - bl;\\n\\tf = 6 * h - i;\\n\\n\\tif ((i & 0x01) !== 0) {\\n\\t\\tf = 1 - f;\\n\\t}\\n\\n\\tn = wh + f * (v - wh); // linear interpolation\\n\\n\\tvar r;\\n\\tvar g;\\n\\tvar b;\\n\\tswitch (i) {\\n\\t\\tdefault:\\n\\t\\tcase 6:\\n\\t\\tcase 0: r = v; g = n; b = wh; break;\\n\\t\\tcase 1: r = n; g = v; b = wh; break;\\n\\t\\tcase 2: r = wh; g = v; b = n; break;\\n\\t\\tcase 3: r = wh; g = n; b = v; break;\\n\\t\\tcase 4: r = n; g = wh; b = v; break;\\n\\t\\tcase 5: r = v; g = wh; b = n; break;\\n\\t}\\n\\n\\treturn [r * 255, g * 255, b * 255];\\n};\\n\\nconvert.cmyk.rgb = function (cmyk) {\\n\\tvar c = cmyk[0] / 100;\\n\\tvar m = cmyk[1] / 100;\\n\\tvar y = cmyk[2] / 100;\\n\\tvar k = cmyk[3] / 100;\\n\\tvar r;\\n\\tvar g;\\n\\tvar b;\\n\\n\\tr = 1 - Math.min(1, c * (1 - k) + k);\\n\\tg = 1 - Math.min(1, m * (1 - k) + k);\\n\\tb = 1 - Math.min(1, y * (1 - k) + k);\\n\\n\\treturn [r * 255, g * 255, b * 255];\\n};\\n\\nconvert.xyz.rgb = function (xyz) {\\n\\tvar x = xyz[0] / 100;\\n\\tvar y = xyz[1] / 100;\\n\\tvar z = xyz[2] / 100;\\n\\tvar r;\\n\\tvar g;\\n\\tvar b;\\n\\n\\tr = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);\\n\\tg = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);\\n\\tb = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);\\n\\n\\t// assume sRGB\\n\\tr = r > 0.0031308\\n\\t\\t? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)\\n\\t\\t: r * 12.92;\\n\\n\\tg = g > 0.0031308\\n\\t\\t? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)\\n\\t\\t: g * 12.92;\\n\\n\\tb = b > 0.0031308\\n\\t\\t? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)\\n\\t\\t: b * 12.92;\\n\\n\\tr = Math.min(Math.max(0, r), 1);\\n\\tg = Math.min(Math.max(0, g), 1);\\n\\tb = Math.min(Math.max(0, b), 1);\\n\\n\\treturn [r * 255, g * 255, b * 255];\\n};\\n\\nconvert.xyz.lab = function (xyz) {\\n\\tvar x = xyz[0];\\n\\tvar y = xyz[1];\\n\\tvar z = xyz[2];\\n\\tvar l;\\n\\tvar a;\\n\\tvar b;\\n\\n\\tx /= 95.047;\\n\\ty /= 100;\\n\\tz /= 108.883;\\n\\n\\tx = x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116);\\n\\ty = y > 0.008856 ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116);\\n\\tz = z > 0.008856 ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116);\\n\\n\\tl = (116 * y) - 16;\\n\\ta = 500 * (x - y);\\n\\tb = 200 * (y - z);\\n\\n\\treturn [l, a, b];\\n};\\n\\nconvert.lab.xyz = function (lab) {\\n\\tvar l = lab[0];\\n\\tvar a = lab[1];\\n\\tvar b = lab[2];\\n\\tvar x;\\n\\tvar y;\\n\\tvar z;\\n\\n\\ty = (l + 16) / 116;\\n\\tx = a / 500 + y;\\n\\tz = y - b / 200;\\n\\n\\tvar y2 = Math.pow(y, 3);\\n\\tvar x2 = Math.pow(x, 3);\\n\\tvar z2 = Math.pow(z, 3);\\n\\ty = y2 > 0.008856 ? y2 : (y - 16 / 116) / 7.787;\\n\\tx = x2 > 0.008856 ? x2 : (x - 16 / 116) / 7.787;\\n\\tz = z2 > 0.008856 ? z2 : (z - 16 / 116) / 7.787;\\n\\n\\tx *= 95.047;\\n\\ty *= 100;\\n\\tz *= 108.883;\\n\\n\\treturn [x, y, z];\\n};\\n\\nconvert.lab.lch = function (lab) {\\n\\tvar l = lab[0];\\n\\tvar a = lab[1];\\n\\tvar b = lab[2];\\n\\tvar hr;\\n\\tvar h;\\n\\tvar c;\\n\\n\\thr = Math.atan2(b, a);\\n\\th = hr * 360 / 2 / Math.PI;\\n\\n\\tif (h < 0) {\\n\\t\\th += 360;\\n\\t}\\n\\n\\tc = Math.sqrt(a * a + b * b);\\n\\n\\treturn [l, c, h];\\n};\\n\\nconvert.lch.lab = function (lch) {\\n\\tvar l = lch[0];\\n\\tvar c = lch[1];\\n\\tvar h = lch[2];\\n\\tvar a;\\n\\tvar b;\\n\\tvar hr;\\n\\n\\thr = h / 360 * 2 * Math.PI;\\n\\ta = c * Math.cos(hr);\\n\\tb = c * Math.sin(hr);\\n\\n\\treturn [l, a, b];\\n};\\n\\nconvert.rgb.ansi16 = function (args) {\\n\\tvar r = args[0];\\n\\tvar g = args[1];\\n\\tvar b = args[2];\\n\\tvar value = 1 in arguments ? arguments[1] : convert.rgb.hsv(args)[2]; // hsv -> ansi16 optimization\\n\\n\\tvalue = Math.round(value / 50);\\n\\n\\tif (value === 0) {\\n\\t\\treturn 30;\\n\\t}\\n\\n\\tvar ansi = 30\\n\\t\\t+ ((Math.round(b / 255) << 2)\\n\\t\\t| (Math.round(g / 255) << 1)\\n\\t\\t| Math.round(r / 255));\\n\\n\\tif (value === 2) {\\n\\t\\tansi += 60;\\n\\t}\\n\\n\\treturn ansi;\\n};\\n\\nconvert.hsv.ansi16 = function (args) {\\n\\t// optimization here; we already know the value and don't need to get\\n\\t// it converted for us.\\n\\treturn convert.rgb.ansi16(convert.hsv.rgb(args), args[2]);\\n};\\n\\nconvert.rgb.ansi256 = function (args) {\\n\\tvar r = args[0];\\n\\tvar g = args[1];\\n\\tvar b = args[2];\\n\\n\\t// we use the extended greyscale palette here, with the exception of\\n\\t// black and white. normal palette only has 4 greyscale shades.\\n\\tif (r === g && g === b) {\\n\\t\\tif (r < 8) {\\n\\t\\t\\treturn 16;\\n\\t\\t}\\n\\n\\t\\tif (r > 248) {\\n\\t\\t\\treturn 231;\\n\\t\\t}\\n\\n\\t\\treturn Math.round(((r - 8) / 247) * 24) + 232;\\n\\t}\\n\\n\\tvar ansi = 16\\n\\t\\t+ (36 * Math.round(r / 255 * 5))\\n\\t\\t+ (6 * Math.round(g / 255 * 5))\\n\\t\\t+ Math.round(b / 255 * 5);\\n\\n\\treturn ansi;\\n};\\n\\nconvert.ansi16.rgb = function (args) {\\n\\tvar color = args % 10;\\n\\n\\t// handle greyscale\\n\\tif (color === 0 || color === 7) {\\n\\t\\tif (args > 50) {\\n\\t\\t\\tcolor += 3.5;\\n\\t\\t}\\n\\n\\t\\tcolor = color / 10.5 * 255;\\n\\n\\t\\treturn [color, color, color];\\n\\t}\\n\\n\\tvar mult = (~~(args > 50) + 1) * 0.5;\\n\\tvar r = ((color & 1) * mult) * 255;\\n\\tvar g = (((color >> 1) & 1) * mult) * 255;\\n\\tvar b = (((color >> 2) & 1) * mult) * 255;\\n\\n\\treturn [r, g, b];\\n};\\n\\nconvert.ansi256.rgb = function (args) {\\n\\t// handle greyscale\\n\\tif (args >= 232) {\\n\\t\\tvar c = (args - 232) * 10 + 8;\\n\\t\\treturn [c, c, c];\\n\\t}\\n\\n\\targs -= 16;\\n\\n\\tvar rem;\\n\\tvar r = Math.floor(args / 36) / 5 * 255;\\n\\tvar g = Math.floor((rem = args % 36) / 6) / 5 * 255;\\n\\tvar b = (rem % 6) / 5 * 255;\\n\\n\\treturn [r, g, b];\\n};\\n\\nconvert.rgb.hex = function (args) {\\n\\tvar integer = ((Math.round(args[0]) & 0xFF) << 16)\\n\\t\\t+ ((Math.round(args[1]) & 0xFF) << 8)\\n\\t\\t+ (Math.round(args[2]) & 0xFF);\\n\\n\\tvar string = integer.toString(16).toUpperCase();\\n\\treturn '000000'.substring(string.length) + string;\\n};\\n\\nconvert.hex.rgb = function (args) {\\n\\tvar match = args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);\\n\\tif (!match) {\\n\\t\\treturn [0, 0, 0];\\n\\t}\\n\\n\\tvar colorString = match[0];\\n\\n\\tif (match[0].length === 3) {\\n\\t\\tcolorString = colorString.split('').map(function (char) {\\n\\t\\t\\treturn char + char;\\n\\t\\t}).join('');\\n\\t}\\n\\n\\tvar integer = parseInt(colorString, 16);\\n\\tvar r = (integer >> 16) & 0xFF;\\n\\tvar g = (integer >> 8) & 0xFF;\\n\\tvar b = integer & 0xFF;\\n\\n\\treturn [r, g, b];\\n};\\n\\nconvert.rgb.hcg = function (rgb) {\\n\\tvar r = rgb[0] / 255;\\n\\tvar g = rgb[1] / 255;\\n\\tvar b = rgb[2] / 255;\\n\\tvar max = Math.max(Math.max(r, g), b);\\n\\tvar min = Math.min(Math.min(r, g), b);\\n\\tvar chroma = (max - min);\\n\\tvar grayscale;\\n\\tvar hue;\\n\\n\\tif (chroma < 1) {\\n\\t\\tgrayscale = min / (1 - chroma);\\n\\t} else {\\n\\t\\tgrayscale = 0;\\n\\t}\\n\\n\\tif (chroma <= 0) {\\n\\t\\thue = 0;\\n\\t} else\\n\\tif (max === r) {\\n\\t\\thue = ((g - b) / chroma) % 6;\\n\\t} else\\n\\tif (max === g) {\\n\\t\\thue = 2 + (b - r) / chroma;\\n\\t} else {\\n\\t\\thue = 4 + (r - g) / chroma + 4;\\n\\t}\\n\\n\\thue /= 6;\\n\\thue %= 1;\\n\\n\\treturn [hue * 360, chroma * 100, grayscale * 100];\\n};\\n\\nconvert.hsl.hcg = function (hsl) {\\n\\tvar s = hsl[1] / 100;\\n\\tvar l = hsl[2] / 100;\\n\\tvar c = 1;\\n\\tvar f = 0;\\n\\n\\tif (l < 0.5) {\\n\\t\\tc = 2.0 * s * l;\\n\\t} else {\\n\\t\\tc = 2.0 * s * (1.0 - l);\\n\\t}\\n\\n\\tif (c < 1.0) {\\n\\t\\tf = (l - 0.5 * c) / (1.0 - c);\\n\\t}\\n\\n\\treturn [hsl[0], c * 100, f * 100];\\n};\\n\\nconvert.hsv.hcg = function (hsv) {\\n\\tvar s = hsv[1] / 100;\\n\\tvar v = hsv[2] / 100;\\n\\n\\tvar c = s * v;\\n\\tvar f = 0;\\n\\n\\tif (c < 1.0) {\\n\\t\\tf = (v - c) / (1 - c);\\n\\t}\\n\\n\\treturn [hsv[0], c * 100, f * 100];\\n};\\n\\nconvert.hcg.rgb = function (hcg) {\\n\\tvar h = hcg[0] / 360;\\n\\tvar c = hcg[1] / 100;\\n\\tvar g = hcg[2] / 100;\\n\\n\\tif (c === 0.0) {\\n\\t\\treturn [g * 255, g * 255, g * 255];\\n\\t}\\n\\n\\tvar pure = [0, 0, 0];\\n\\tvar hi = (h % 1) * 6;\\n\\tvar v = hi % 1;\\n\\tvar w = 1 - v;\\n\\tvar mg = 0;\\n\\n\\tswitch (Math.floor(hi)) {\\n\\t\\tcase 0:\\n\\t\\t\\tpure[0] = 1; pure[1] = v; pure[2] = 0; break;\\n\\t\\tcase 1:\\n\\t\\t\\tpure[0] = w; pure[1] = 1; pure[2] = 0; break;\\n\\t\\tcase 2:\\n\\t\\t\\tpure[0] = 0; pure[1] = 1; pure[2] = v; break;\\n\\t\\tcase 3:\\n\\t\\t\\tpure[0] = 0; pure[1] = w; pure[2] = 1; break;\\n\\t\\tcase 4:\\n\\t\\t\\tpure[0] = v; pure[1] = 0; pure[2] = 1; break;\\n\\t\\tdefault:\\n\\t\\t\\tpure[0] = 1; pure[1] = 0; pure[2] = w;\\n\\t}\\n\\n\\tmg = (1.0 - c) * g;\\n\\n\\treturn [\\n\\t\\t(c * pure[0] + mg) * 255,\\n\\t\\t(c * pure[1] + mg) * 255,\\n\\t\\t(c * pure[2] + mg) * 255\\n\\t];\\n};\\n\\nconvert.hcg.hsv = function (hcg) {\\n\\tvar c = hcg[1] / 100;\\n\\tvar g = hcg[2] / 100;\\n\\n\\tvar v = c + g * (1.0 - c);\\n\\tvar f = 0;\\n\\n\\tif (v > 0.0) {\\n\\t\\tf = c / v;\\n\\t}\\n\\n\\treturn [hcg[0], f * 100, v * 100];\\n};\\n\\nconvert.hcg.hsl = function (hcg) {\\n\\tvar c = hcg[1] / 100;\\n\\tvar g = hcg[2] / 100;\\n\\n\\tvar l = g * (1.0 - c) + 0.5 * c;\\n\\tvar s = 0;\\n\\n\\tif (l > 0.0 && l < 0.5) {\\n\\t\\ts = c / (2 * l);\\n\\t} else\\n\\tif (l >= 0.5 && l < 1.0) {\\n\\t\\ts = c / (2 * (1 - l));\\n\\t}\\n\\n\\treturn [hcg[0], s * 100, l * 100];\\n};\\n\\nconvert.hcg.hwb = function (hcg) {\\n\\tvar c = hcg[1] / 100;\\n\\tvar g = hcg[2] / 100;\\n\\tvar v = c + g * (1.0 - c);\\n\\treturn [hcg[0], (v - c) * 100, (1 - v) * 100];\\n};\\n\\nconvert.hwb.hcg = function (hwb) {\\n\\tvar w = hwb[1] / 100;\\n\\tvar b = hwb[2] / 100;\\n\\tvar v = 1 - b;\\n\\tvar c = v - w;\\n\\tvar g = 0;\\n\\n\\tif (c < 1) {\\n\\t\\tg = (v - c) / (1 - c);\\n\\t}\\n\\n\\treturn [hwb[0], c * 100, g * 100];\\n};\\n\\nconvert.apple.rgb = function (apple) {\\n\\treturn [(apple[0] / 65535) * 255, (apple[1] / 65535) * 255, (apple[2] / 65535) * 255];\\n};\\n\\nconvert.rgb.apple = function (rgb) {\\n\\treturn [(rgb[0] / 255) * 65535, (rgb[1] / 255) * 65535, (rgb[2] / 255) * 65535];\\n};\\n\\nconvert.gray.rgb = function (args) {\\n\\treturn [args[0] / 100 * 255, args[0] / 100 * 255, args[0] / 100 * 255];\\n};\\n\\nconvert.gray.hsl = convert.gray.hsv = function (args) {\\n\\treturn [0, 0, args[0]];\\n};\\n\\nconvert.gray.hwb = function (gray) {\\n\\treturn [0, 100, gray[0]];\\n};\\n\\nconvert.gray.cmyk = function (gray) {\\n\\treturn [0, 0, 0, gray[0]];\\n};\\n\\nconvert.gray.lab = function (gray) {\\n\\treturn [gray[0], 0, 0];\\n};\\n\\nconvert.gray.hex = function (gray) {\\n\\tvar val = Math.round(gray[0] / 100 * 255) & 0xFF;\\n\\tvar integer = (val << 16) + (val << 8) + val;\\n\\n\\tvar string = integer.toString(16).toUpperCase();\\n\\treturn '000000'.substring(string.length) + string;\\n};\\n\\nconvert.rgb.gray = function (rgb) {\\n\\tvar val = (rgb[0] + rgb[1] + rgb[2]) / 3;\\n\\treturn [val / 255 * 100];\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/color-convert/conversions.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/color-convert/index.js\":\n/*!*********************************************!*\\\n  !*** ./node_modules/color-convert/index.js ***!\n  \\*********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"var conversions = __webpack_require__(/*! ./conversions */ \\\"./node_modules/color-convert/conversions.js\\\");\\nvar route = __webpack_require__(/*! ./route */ \\\"./node_modules/color-convert/route.js\\\");\\n\\nvar convert = {};\\n\\nvar models = Object.keys(conversions);\\n\\nfunction wrapRaw(fn) {\\n\\tvar wrappedFn = function (args) {\\n\\t\\tif (args === undefined || args === null) {\\n\\t\\t\\treturn args;\\n\\t\\t}\\n\\n\\t\\tif (arguments.length > 1) {\\n\\t\\t\\targs = Array.prototype.slice.call(arguments);\\n\\t\\t}\\n\\n\\t\\treturn fn(args);\\n\\t};\\n\\n\\t// preserve .conversion property if there is one\\n\\tif ('conversion' in fn) {\\n\\t\\twrappedFn.conversion = fn.conversion;\\n\\t}\\n\\n\\treturn wrappedFn;\\n}\\n\\nfunction wrapRounded(fn) {\\n\\tvar wrappedFn = function (args) {\\n\\t\\tif (args === undefined || args === null) {\\n\\t\\t\\treturn args;\\n\\t\\t}\\n\\n\\t\\tif (arguments.length > 1) {\\n\\t\\t\\targs = Array.prototype.slice.call(arguments);\\n\\t\\t}\\n\\n\\t\\tvar result = fn(args);\\n\\n\\t\\t// we're assuming the result is an array here.\\n\\t\\t// see notice in conversions.js; don't use box types\\n\\t\\t// in conversion functions.\\n\\t\\tif (typeof result === 'object') {\\n\\t\\t\\tfor (var len = result.length, i = 0; i < len; i++) {\\n\\t\\t\\t\\tresult[i] = Math.round(result[i]);\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\treturn result;\\n\\t};\\n\\n\\t// preserve .conversion property if there is one\\n\\tif ('conversion' in fn) {\\n\\t\\twrappedFn.conversion = fn.conversion;\\n\\t}\\n\\n\\treturn wrappedFn;\\n}\\n\\nmodels.forEach(function (fromModel) {\\n\\tconvert[fromModel] = {};\\n\\n\\tObject.defineProperty(convert[fromModel], 'channels', {value: conversions[fromModel].channels});\\n\\tObject.defineProperty(convert[fromModel], 'labels', {value: conversions[fromModel].labels});\\n\\n\\tvar routes = route(fromModel);\\n\\tvar routeModels = Object.keys(routes);\\n\\n\\trouteModels.forEach(function (toModel) {\\n\\t\\tvar fn = routes[toModel];\\n\\n\\t\\tconvert[fromModel][toModel] = wrapRounded(fn);\\n\\t\\tconvert[fromModel][toModel].raw = wrapRaw(fn);\\n\\t});\\n});\\n\\nmodule.exports = convert;\\n\\n\\n//# sourceURL=webpack:///./node_modules/color-convert/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/color-convert/route.js\":\n/*!*********************************************!*\\\n  !*** ./node_modules/color-convert/route.js ***!\n  \\*********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"var conversions = __webpack_require__(/*! ./conversions */ \\\"./node_modules/color-convert/conversions.js\\\");\\n\\n/*\\n\\tthis function routes a model to all other models.\\n\\n\\tall functions that are routed have a property `.conversion` attached\\n\\tto the returned synthetic function. This property is an array\\n\\tof strings, each with the steps in between the 'from' and 'to'\\n\\tcolor models (inclusive).\\n\\n\\tconversions that are not possible simply are not included.\\n*/\\n\\nfunction buildGraph() {\\n\\tvar graph = {};\\n\\t// https://jsperf.com/object-keys-vs-for-in-with-closure/3\\n\\tvar models = Object.keys(conversions);\\n\\n\\tfor (var len = models.length, i = 0; i < len; i++) {\\n\\t\\tgraph[models[i]] = {\\n\\t\\t\\t// http://jsperf.com/1-vs-infinity\\n\\t\\t\\t// micro-opt, but this is simple.\\n\\t\\t\\tdistance: -1,\\n\\t\\t\\tparent: null\\n\\t\\t};\\n\\t}\\n\\n\\treturn graph;\\n}\\n\\n// https://en.wikipedia.org/wiki/Breadth-first_search\\nfunction deriveBFS(fromModel) {\\n\\tvar graph = buildGraph();\\n\\tvar queue = [fromModel]; // unshift -> queue -> pop\\n\\n\\tgraph[fromModel].distance = 0;\\n\\n\\twhile (queue.length) {\\n\\t\\tvar current = queue.pop();\\n\\t\\tvar adjacents = Object.keys(conversions[current]);\\n\\n\\t\\tfor (var len = adjacents.length, i = 0; i < len; i++) {\\n\\t\\t\\tvar adjacent = adjacents[i];\\n\\t\\t\\tvar node = graph[adjacent];\\n\\n\\t\\t\\tif (node.distance === -1) {\\n\\t\\t\\t\\tnode.distance = graph[current].distance + 1;\\n\\t\\t\\t\\tnode.parent = current;\\n\\t\\t\\t\\tqueue.unshift(adjacent);\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n\\n\\treturn graph;\\n}\\n\\nfunction link(from, to) {\\n\\treturn function (args) {\\n\\t\\treturn to(from(args));\\n\\t};\\n}\\n\\nfunction wrapConversion(toModel, graph) {\\n\\tvar path = [graph[toModel].parent, toModel];\\n\\tvar fn = conversions[graph[toModel].parent][toModel];\\n\\n\\tvar cur = graph[toModel].parent;\\n\\twhile (graph[cur].parent) {\\n\\t\\tpath.unshift(graph[cur].parent);\\n\\t\\tfn = link(conversions[graph[cur].parent][cur], fn);\\n\\t\\tcur = graph[cur].parent;\\n\\t}\\n\\n\\tfn.conversion = path;\\n\\treturn fn;\\n}\\n\\nmodule.exports = function (fromModel) {\\n\\tvar graph = deriveBFS(fromModel);\\n\\tvar conversion = {};\\n\\n\\tvar models = Object.keys(graph);\\n\\tfor (var len = models.length, i = 0; i < len; i++) {\\n\\t\\tvar toModel = models[i];\\n\\t\\tvar node = graph[toModel];\\n\\n\\t\\tif (node.parent === null) {\\n\\t\\t\\t// no possible conversion, or this node is the source model.\\n\\t\\t\\tcontinue;\\n\\t\\t}\\n\\n\\t\\tconversion[toModel] = wrapConversion(toModel, graph);\\n\\t}\\n\\n\\treturn conversion;\\n};\\n\\n\\n\\n//# sourceURL=webpack:///./node_modules/color-convert/route.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/color-name/index.js\":\n/*!******************************************!*\\\n  !*** ./node_modules/color-name/index.js ***!\n  \\******************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\r\\n\\r\\nmodule.exports = {\\r\\n\\t\\\"aliceblue\\\": [240, 248, 255],\\r\\n\\t\\\"antiquewhite\\\": [250, 235, 215],\\r\\n\\t\\\"aqua\\\": [0, 255, 255],\\r\\n\\t\\\"aquamarine\\\": [127, 255, 212],\\r\\n\\t\\\"azure\\\": [240, 255, 255],\\r\\n\\t\\\"beige\\\": [245, 245, 220],\\r\\n\\t\\\"bisque\\\": [255, 228, 196],\\r\\n\\t\\\"black\\\": [0, 0, 0],\\r\\n\\t\\\"blanchedalmond\\\": [255, 235, 205],\\r\\n\\t\\\"blue\\\": [0, 0, 255],\\r\\n\\t\\\"blueviolet\\\": [138, 43, 226],\\r\\n\\t\\\"brown\\\": [165, 42, 42],\\r\\n\\t\\\"burlywood\\\": [222, 184, 135],\\r\\n\\t\\\"cadetblue\\\": [95, 158, 160],\\r\\n\\t\\\"chartreuse\\\": [127, 255, 0],\\r\\n\\t\\\"chocolate\\\": [210, 105, 30],\\r\\n\\t\\\"coral\\\": [255, 127, 80],\\r\\n\\t\\\"cornflowerblue\\\": [100, 149, 237],\\r\\n\\t\\\"cornsilk\\\": [255, 248, 220],\\r\\n\\t\\\"crimson\\\": [220, 20, 60],\\r\\n\\t\\\"cyan\\\": [0, 255, 255],\\r\\n\\t\\\"darkblue\\\": [0, 0, 139],\\r\\n\\t\\\"darkcyan\\\": [0, 139, 139],\\r\\n\\t\\\"darkgoldenrod\\\": [184, 134, 11],\\r\\n\\t\\\"darkgray\\\": [169, 169, 169],\\r\\n\\t\\\"darkgreen\\\": [0, 100, 0],\\r\\n\\t\\\"darkgrey\\\": [169, 169, 169],\\r\\n\\t\\\"darkkhaki\\\": [189, 183, 107],\\r\\n\\t\\\"darkmagenta\\\": [139, 0, 139],\\r\\n\\t\\\"darkolivegreen\\\": [85, 107, 47],\\r\\n\\t\\\"darkorange\\\": [255, 140, 0],\\r\\n\\t\\\"darkorchid\\\": [153, 50, 204],\\r\\n\\t\\\"darkred\\\": [139, 0, 0],\\r\\n\\t\\\"darksalmon\\\": [233, 150, 122],\\r\\n\\t\\\"darkseagreen\\\": [143, 188, 143],\\r\\n\\t\\\"darkslateblue\\\": [72, 61, 139],\\r\\n\\t\\\"darkslategray\\\": [47, 79, 79],\\r\\n\\t\\\"darkslategrey\\\": [47, 79, 79],\\r\\n\\t\\\"darkturquoise\\\": [0, 206, 209],\\r\\n\\t\\\"darkviolet\\\": [148, 0, 211],\\r\\n\\t\\\"deeppink\\\": [255, 20, 147],\\r\\n\\t\\\"deepskyblue\\\": [0, 191, 255],\\r\\n\\t\\\"dimgray\\\": [105, 105, 105],\\r\\n\\t\\\"dimgrey\\\": [105, 105, 105],\\r\\n\\t\\\"dodgerblue\\\": [30, 144, 255],\\r\\n\\t\\\"firebrick\\\": [178, 34, 34],\\r\\n\\t\\\"floralwhite\\\": [255, 250, 240],\\r\\n\\t\\\"forestgreen\\\": [34, 139, 34],\\r\\n\\t\\\"fuchsia\\\": [255, 0, 255],\\r\\n\\t\\\"gainsboro\\\": [220, 220, 220],\\r\\n\\t\\\"ghostwhite\\\": [248, 248, 255],\\r\\n\\t\\\"gold\\\": [255, 215, 0],\\r\\n\\t\\\"goldenrod\\\": [218, 165, 32],\\r\\n\\t\\\"gray\\\": [128, 128, 128],\\r\\n\\t\\\"green\\\": [0, 128, 0],\\r\\n\\t\\\"greenyellow\\\": [173, 255, 47],\\r\\n\\t\\\"grey\\\": [128, 128, 128],\\r\\n\\t\\\"honeydew\\\": [240, 255, 240],\\r\\n\\t\\\"hotpink\\\": [255, 105, 180],\\r\\n\\t\\\"indianred\\\": [205, 92, 92],\\r\\n\\t\\\"indigo\\\": [75, 0, 130],\\r\\n\\t\\\"ivory\\\": [255, 255, 240],\\r\\n\\t\\\"khaki\\\": [240, 230, 140],\\r\\n\\t\\\"lavender\\\": [230, 230, 250],\\r\\n\\t\\\"lavenderblush\\\": [255, 240, 245],\\r\\n\\t\\\"lawngreen\\\": [124, 252, 0],\\r\\n\\t\\\"lemonchiffon\\\": [255, 250, 205],\\r\\n\\t\\\"lightblue\\\": [173, 216, 230],\\r\\n\\t\\\"lightcoral\\\": [240, 128, 128],\\r\\n\\t\\\"lightcyan\\\": [224, 255, 255],\\r\\n\\t\\\"lightgoldenrodyellow\\\": [250, 250, 210],\\r\\n\\t\\\"lightgray\\\": [211, 211, 211],\\r\\n\\t\\\"lightgreen\\\": [144, 238, 144],\\r\\n\\t\\\"lightgrey\\\": [211, 211, 211],\\r\\n\\t\\\"lightpink\\\": [255, 182, 193],\\r\\n\\t\\\"lightsalmon\\\": [255, 160, 122],\\r\\n\\t\\\"lightseagreen\\\": [32, 178, 170],\\r\\n\\t\\\"lightskyblue\\\": [135, 206, 250],\\r\\n\\t\\\"lightslategray\\\": [119, 136, 153],\\r\\n\\t\\\"lightslategrey\\\": [119, 136, 153],\\r\\n\\t\\\"lightsteelblue\\\": [176, 196, 222],\\r\\n\\t\\\"lightyellow\\\": [255, 255, 224],\\r\\n\\t\\\"lime\\\": [0, 255, 0],\\r\\n\\t\\\"limegreen\\\": [50, 205, 50],\\r\\n\\t\\\"linen\\\": [250, 240, 230],\\r\\n\\t\\\"magenta\\\": [255, 0, 255],\\r\\n\\t\\\"maroon\\\": [128, 0, 0],\\r\\n\\t\\\"mediumaquamarine\\\": [102, 205, 170],\\r\\n\\t\\\"mediumblue\\\": [0, 0, 205],\\r\\n\\t\\\"mediumorchid\\\": [186, 85, 211],\\r\\n\\t\\\"mediumpurple\\\": [147, 112, 219],\\r\\n\\t\\\"mediumseagreen\\\": [60, 179, 113],\\r\\n\\t\\\"mediumslateblue\\\": [123, 104, 238],\\r\\n\\t\\\"mediumspringgreen\\\": [0, 250, 154],\\r\\n\\t\\\"mediumturquoise\\\": [72, 209, 204],\\r\\n\\t\\\"mediumvioletred\\\": [199, 21, 133],\\r\\n\\t\\\"midnightblue\\\": [25, 25, 112],\\r\\n\\t\\\"mintcream\\\": [245, 255, 250],\\r\\n\\t\\\"mistyrose\\\": [255, 228, 225],\\r\\n\\t\\\"moccasin\\\": [255, 228, 181],\\r\\n\\t\\\"navajowhite\\\": [255, 222, 173],\\r\\n\\t\\\"navy\\\": [0, 0, 128],\\r\\n\\t\\\"oldlace\\\": [253, 245, 230],\\r\\n\\t\\\"olive\\\": [128, 128, 0],\\r\\n\\t\\\"olivedrab\\\": [107, 142, 35],\\r\\n\\t\\\"orange\\\": [255, 165, 0],\\r\\n\\t\\\"orangered\\\": [255, 69, 0],\\r\\n\\t\\\"orchid\\\": [218, 112, 214],\\r\\n\\t\\\"palegoldenrod\\\": [238, 232, 170],\\r\\n\\t\\\"palegreen\\\": [152, 251, 152],\\r\\n\\t\\\"paleturquoise\\\": [175, 238, 238],\\r\\n\\t\\\"palevioletred\\\": [219, 112, 147],\\r\\n\\t\\\"papayawhip\\\": [255, 239, 213],\\r\\n\\t\\\"peachpuff\\\": [255, 218, 185],\\r\\n\\t\\\"peru\\\": [205, 133, 63],\\r\\n\\t\\\"pink\\\": [255, 192, 203],\\r\\n\\t\\\"plum\\\": [221, 160, 221],\\r\\n\\t\\\"powderblue\\\": [176, 224, 230],\\r\\n\\t\\\"purple\\\": [128, 0, 128],\\r\\n\\t\\\"rebeccapurple\\\": [102, 51, 153],\\r\\n\\t\\\"red\\\": [255, 0, 0],\\r\\n\\t\\\"rosybrown\\\": [188, 143, 143],\\r\\n\\t\\\"royalblue\\\": [65, 105, 225],\\r\\n\\t\\\"saddlebrown\\\": [139, 69, 19],\\r\\n\\t\\\"salmon\\\": [250, 128, 114],\\r\\n\\t\\\"sandybrown\\\": [244, 164, 96],\\r\\n\\t\\\"seagreen\\\": [46, 139, 87],\\r\\n\\t\\\"seashell\\\": [255, 245, 238],\\r\\n\\t\\\"sienna\\\": [160, 82, 45],\\r\\n\\t\\\"silver\\\": [192, 192, 192],\\r\\n\\t\\\"skyblue\\\": [135, 206, 235],\\r\\n\\t\\\"slateblue\\\": [106, 90, 205],\\r\\n\\t\\\"slategray\\\": [112, 128, 144],\\r\\n\\t\\\"slategrey\\\": [112, 128, 144],\\r\\n\\t\\\"snow\\\": [255, 250, 250],\\r\\n\\t\\\"springgreen\\\": [0, 255, 127],\\r\\n\\t\\\"steelblue\\\": [70, 130, 180],\\r\\n\\t\\\"tan\\\": [210, 180, 140],\\r\\n\\t\\\"teal\\\": [0, 128, 128],\\r\\n\\t\\\"thistle\\\": [216, 191, 216],\\r\\n\\t\\\"tomato\\\": [255, 99, 71],\\r\\n\\t\\\"turquoise\\\": [64, 224, 208],\\r\\n\\t\\\"violet\\\": [238, 130, 238],\\r\\n\\t\\\"wheat\\\": [245, 222, 179],\\r\\n\\t\\\"white\\\": [255, 255, 255],\\r\\n\\t\\\"whitesmoke\\\": [245, 245, 245],\\r\\n\\t\\\"yellow\\\": [255, 255, 0],\\r\\n\\t\\\"yellowgreen\\\": [154, 205, 50]\\r\\n};\\r\\n\\n\\n//# sourceURL=webpack:///./node_modules/color-name/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/color-string/index.js\":\n/*!********************************************!*\\\n  !*** ./node_modules/color-string/index.js ***!\n  \\********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"/* MIT license */\\nvar colorNames = __webpack_require__(/*! color-name */ \\\"./node_modules/color-name/index.js\\\");\\nvar swizzle = __webpack_require__(/*! simple-swizzle */ \\\"./node_modules/simple-swizzle/index.js\\\");\\n\\nvar reverseNames = {};\\n\\n// create a list of reverse color names\\nfor (var name in colorNames) {\\n\\tif (colorNames.hasOwnProperty(name)) {\\n\\t\\treverseNames[colorNames[name]] = name;\\n\\t}\\n}\\n\\nvar cs = module.exports = {\\n\\tto: {},\\n\\tget: {}\\n};\\n\\ncs.get = function (string) {\\n\\tvar prefix = string.substring(0, 3).toLowerCase();\\n\\tvar val;\\n\\tvar model;\\n\\tswitch (prefix) {\\n\\t\\tcase 'hsl':\\n\\t\\t\\tval = cs.get.hsl(string);\\n\\t\\t\\tmodel = 'hsl';\\n\\t\\t\\tbreak;\\n\\t\\tcase 'hwb':\\n\\t\\t\\tval = cs.get.hwb(string);\\n\\t\\t\\tmodel = 'hwb';\\n\\t\\t\\tbreak;\\n\\t\\tdefault:\\n\\t\\t\\tval = cs.get.rgb(string);\\n\\t\\t\\tmodel = 'rgb';\\n\\t\\t\\tbreak;\\n\\t}\\n\\n\\tif (!val) {\\n\\t\\treturn null;\\n\\t}\\n\\n\\treturn {model: model, value: val};\\n};\\n\\ncs.get.rgb = function (string) {\\n\\tif (!string) {\\n\\t\\treturn null;\\n\\t}\\n\\n\\tvar abbr = /^#([a-f0-9]{3,4})$/i;\\n\\tvar hex = /^#([a-f0-9]{6})([a-f0-9]{2})?$/i;\\n\\tvar rgba = /^rgba?\\\\(\\\\s*([+-]?\\\\d+)\\\\s*,\\\\s*([+-]?\\\\d+)\\\\s*,\\\\s*([+-]?\\\\d+)\\\\s*(?:,\\\\s*([+-]?[\\\\d\\\\.]+)\\\\s*)?\\\\)$/;\\n\\tvar per = /^rgba?\\\\(\\\\s*([+-]?[\\\\d\\\\.]+)\\\\%\\\\s*,\\\\s*([+-]?[\\\\d\\\\.]+)\\\\%\\\\s*,\\\\s*([+-]?[\\\\d\\\\.]+)\\\\%\\\\s*(?:,\\\\s*([+-]?[\\\\d\\\\.]+)\\\\s*)?\\\\)$/;\\n\\tvar keyword = /(\\\\D+)/;\\n\\n\\tvar rgb = [0, 0, 0, 1];\\n\\tvar match;\\n\\tvar i;\\n\\tvar hexAlpha;\\n\\n\\tif (match = string.match(hex)) {\\n\\t\\thexAlpha = match[2];\\n\\t\\tmatch = match[1];\\n\\n\\t\\tfor (i = 0; i < 3; i++) {\\n\\t\\t\\t// https://jsperf.com/slice-vs-substr-vs-substring-methods-long-string/19\\n\\t\\t\\tvar i2 = i * 2;\\n\\t\\t\\trgb[i] = parseInt(match.slice(i2, i2 + 2), 16);\\n\\t\\t}\\n\\n\\t\\tif (hexAlpha) {\\n\\t\\t\\trgb[3] = Math.round((parseInt(hexAlpha, 16) / 255) * 100) / 100;\\n\\t\\t}\\n\\t} else if (match = string.match(abbr)) {\\n\\t\\tmatch = match[1];\\n\\t\\thexAlpha = match[3];\\n\\n\\t\\tfor (i = 0; i < 3; i++) {\\n\\t\\t\\trgb[i] = parseInt(match[i] + match[i], 16);\\n\\t\\t}\\n\\n\\t\\tif (hexAlpha) {\\n\\t\\t\\trgb[3] = Math.round((parseInt(hexAlpha + hexAlpha, 16) / 255) * 100) / 100;\\n\\t\\t}\\n\\t} else if (match = string.match(rgba)) {\\n\\t\\tfor (i = 0; i < 3; i++) {\\n\\t\\t\\trgb[i] = parseInt(match[i + 1], 0);\\n\\t\\t}\\n\\n\\t\\tif (match[4]) {\\n\\t\\t\\trgb[3] = parseFloat(match[4]);\\n\\t\\t}\\n\\t} else if (match = string.match(per)) {\\n\\t\\tfor (i = 0; i < 3; i++) {\\n\\t\\t\\trgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);\\n\\t\\t}\\n\\n\\t\\tif (match[4]) {\\n\\t\\t\\trgb[3] = parseFloat(match[4]);\\n\\t\\t}\\n\\t} else if (match = string.match(keyword)) {\\n\\t\\tif (match[1] === 'transparent') {\\n\\t\\t\\treturn [0, 0, 0, 0];\\n\\t\\t}\\n\\n\\t\\trgb = colorNames[match[1]];\\n\\n\\t\\tif (!rgb) {\\n\\t\\t\\treturn null;\\n\\t\\t}\\n\\n\\t\\trgb[3] = 1;\\n\\n\\t\\treturn rgb;\\n\\t} else {\\n\\t\\treturn null;\\n\\t}\\n\\n\\tfor (i = 0; i < 3; i++) {\\n\\t\\trgb[i] = clamp(rgb[i], 0, 255);\\n\\t}\\n\\trgb[3] = clamp(rgb[3], 0, 1);\\n\\n\\treturn rgb;\\n};\\n\\ncs.get.hsl = function (string) {\\n\\tif (!string) {\\n\\t\\treturn null;\\n\\t}\\n\\n\\tvar hsl = /^hsla?\\\\(\\\\s*([+-]?(?:\\\\d*\\\\.)?\\\\d+)(?:deg)?\\\\s*,\\\\s*([+-]?[\\\\d\\\\.]+)%\\\\s*,\\\\s*([+-]?[\\\\d\\\\.]+)%\\\\s*(?:,\\\\s*([+-]?[\\\\d\\\\.]+)\\\\s*)?\\\\)$/;\\n\\tvar match = string.match(hsl);\\n\\n\\tif (match) {\\n\\t\\tvar alpha = parseFloat(match[4]);\\n\\t\\tvar h = (parseFloat(match[1]) + 360) % 360;\\n\\t\\tvar s = clamp(parseFloat(match[2]), 0, 100);\\n\\t\\tvar l = clamp(parseFloat(match[3]), 0, 100);\\n\\t\\tvar a = clamp(isNaN(alpha) ? 1 : alpha, 0, 1);\\n\\n\\t\\treturn [h, s, l, a];\\n\\t}\\n\\n\\treturn null;\\n};\\n\\ncs.get.hwb = function (string) {\\n\\tif (!string) {\\n\\t\\treturn null;\\n\\t}\\n\\n\\tvar hwb = /^hwb\\\\(\\\\s*([+-]?\\\\d*[\\\\.]?\\\\d+)(?:deg)?\\\\s*,\\\\s*([+-]?[\\\\d\\\\.]+)%\\\\s*,\\\\s*([+-]?[\\\\d\\\\.]+)%\\\\s*(?:,\\\\s*([+-]?[\\\\d\\\\.]+)\\\\s*)?\\\\)$/;\\n\\tvar match = string.match(hwb);\\n\\n\\tif (match) {\\n\\t\\tvar alpha = parseFloat(match[4]);\\n\\t\\tvar h = ((parseFloat(match[1]) % 360) + 360) % 360;\\n\\t\\tvar w = clamp(parseFloat(match[2]), 0, 100);\\n\\t\\tvar b = clamp(parseFloat(match[3]), 0, 100);\\n\\t\\tvar a = clamp(isNaN(alpha) ? 1 : alpha, 0, 1);\\n\\t\\treturn [h, w, b, a];\\n\\t}\\n\\n\\treturn null;\\n};\\n\\ncs.to.hex = function () {\\n\\tvar rgba = swizzle(arguments);\\n\\n\\treturn (\\n\\t\\t'#' +\\n\\t\\thexDouble(rgba[0]) +\\n\\t\\thexDouble(rgba[1]) +\\n\\t\\thexDouble(rgba[2]) +\\n\\t\\t(rgba[3] < 1\\n\\t\\t\\t? (hexDouble(Math.round(rgba[3] * 255)))\\n\\t\\t\\t: '')\\n\\t);\\n};\\n\\ncs.to.rgb = function () {\\n\\tvar rgba = swizzle(arguments);\\n\\n\\treturn rgba.length < 4 || rgba[3] === 1\\n\\t\\t? 'rgb(' + Math.round(rgba[0]) + ', ' + Math.round(rgba[1]) + ', ' + Math.round(rgba[2]) + ')'\\n\\t\\t: 'rgba(' + Math.round(rgba[0]) + ', ' + Math.round(rgba[1]) + ', ' + Math.round(rgba[2]) + ', ' + rgba[3] + ')';\\n};\\n\\ncs.to.rgb.percent = function () {\\n\\tvar rgba = swizzle(arguments);\\n\\n\\tvar r = Math.round(rgba[0] / 255 * 100);\\n\\tvar g = Math.round(rgba[1] / 255 * 100);\\n\\tvar b = Math.round(rgba[2] / 255 * 100);\\n\\n\\treturn rgba.length < 4 || rgba[3] === 1\\n\\t\\t? 'rgb(' + r + '%, ' + g + '%, ' + b + '%)'\\n\\t\\t: 'rgba(' + r + '%, ' + g + '%, ' + b + '%, ' + rgba[3] + ')';\\n};\\n\\ncs.to.hsl = function () {\\n\\tvar hsla = swizzle(arguments);\\n\\treturn hsla.length < 4 || hsla[3] === 1\\n\\t\\t? 'hsl(' + hsla[0] + ', ' + hsla[1] + '%, ' + hsla[2] + '%)'\\n\\t\\t: 'hsla(' + hsla[0] + ', ' + hsla[1] + '%, ' + hsla[2] + '%, ' + hsla[3] + ')';\\n};\\n\\n// hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax\\n// (hwb have alpha optional & 1 is default value)\\ncs.to.hwb = function () {\\n\\tvar hwba = swizzle(arguments);\\n\\n\\tvar a = '';\\n\\tif (hwba.length >= 4 && hwba[3] !== 1) {\\n\\t\\ta = ', ' + hwba[3];\\n\\t}\\n\\n\\treturn 'hwb(' + hwba[0] + ', ' + hwba[1] + '%, ' + hwba[2] + '%' + a + ')';\\n};\\n\\ncs.to.keyword = function (rgb) {\\n\\treturn reverseNames[rgb.slice(0, 3)];\\n};\\n\\n// helpers\\nfunction clamp(num, min, max) {\\n\\treturn Math.min(Math.max(min, num), max);\\n}\\n\\nfunction hexDouble(num) {\\n\\tvar str = num.toString(16).toUpperCase();\\n\\treturn (str.length < 2) ? '0' + str : str;\\n}\\n\\n\\n//# sourceURL=webpack:///./node_modules/color-string/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/color/index.js\":\n/*!*************************************!*\\\n  !*** ./node_modules/color/index.js ***!\n  \\*************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar colorString = __webpack_require__(/*! color-string */ \\\"./node_modules/color-string/index.js\\\");\\nvar convert = __webpack_require__(/*! color-convert */ \\\"./node_modules/color-convert/index.js\\\");\\n\\nvar _slice = [].slice;\\n\\nvar skippedModels = [\\n\\t// to be honest, I don't really feel like keyword belongs in color convert, but eh.\\n\\t'keyword',\\n\\n\\t// gray conflicts with some method names, and has its own method defined.\\n\\t'gray',\\n\\n\\t// shouldn't really be in color-convert either...\\n\\t'hex'\\n];\\n\\nvar hashedModelKeys = {};\\nObject.keys(convert).forEach(function (model) {\\n\\thashedModelKeys[_slice.call(convert[model].labels).sort().join('')] = model;\\n});\\n\\nvar limiters = {};\\n\\nfunction Color(obj, model) {\\n\\tif (!(this instanceof Color)) {\\n\\t\\treturn new Color(obj, model);\\n\\t}\\n\\n\\tif (model && model in skippedModels) {\\n\\t\\tmodel = null;\\n\\t}\\n\\n\\tif (model && !(model in convert)) {\\n\\t\\tthrow new Error('Unknown model: ' + model);\\n\\t}\\n\\n\\tvar i;\\n\\tvar channels;\\n\\n\\tif (obj == null) { // eslint-disable-line no-eq-null,eqeqeq\\n\\t\\tthis.model = 'rgb';\\n\\t\\tthis.color = [0, 0, 0];\\n\\t\\tthis.valpha = 1;\\n\\t} else if (obj instanceof Color) {\\n\\t\\tthis.model = obj.model;\\n\\t\\tthis.color = obj.color.slice();\\n\\t\\tthis.valpha = obj.valpha;\\n\\t} else if (typeof obj === 'string') {\\n\\t\\tvar result = colorString.get(obj);\\n\\t\\tif (result === null) {\\n\\t\\t\\tthrow new Error('Unable to parse color from string: ' + obj);\\n\\t\\t}\\n\\n\\t\\tthis.model = result.model;\\n\\t\\tchannels = convert[this.model].channels;\\n\\t\\tthis.color = result.value.slice(0, channels);\\n\\t\\tthis.valpha = typeof result.value[channels] === 'number' ? result.value[channels] : 1;\\n\\t} else if (obj.length) {\\n\\t\\tthis.model = model || 'rgb';\\n\\t\\tchannels = convert[this.model].channels;\\n\\t\\tvar newArr = _slice.call(obj, 0, channels);\\n\\t\\tthis.color = zeroArray(newArr, channels);\\n\\t\\tthis.valpha = typeof obj[channels] === 'number' ? obj[channels] : 1;\\n\\t} else if (typeof obj === 'number') {\\n\\t\\t// this is always RGB - can be converted later on.\\n\\t\\tobj &= 0xFFFFFF;\\n\\t\\tthis.model = 'rgb';\\n\\t\\tthis.color = [\\n\\t\\t\\t(obj >> 16) & 0xFF,\\n\\t\\t\\t(obj >> 8) & 0xFF,\\n\\t\\t\\tobj & 0xFF\\n\\t\\t];\\n\\t\\tthis.valpha = 1;\\n\\t} else {\\n\\t\\tthis.valpha = 1;\\n\\n\\t\\tvar keys = Object.keys(obj);\\n\\t\\tif ('alpha' in obj) {\\n\\t\\t\\tkeys.splice(keys.indexOf('alpha'), 1);\\n\\t\\t\\tthis.valpha = typeof obj.alpha === 'number' ? obj.alpha : 0;\\n\\t\\t}\\n\\n\\t\\tvar hashedKeys = keys.sort().join('');\\n\\t\\tif (!(hashedKeys in hashedModelKeys)) {\\n\\t\\t\\tthrow new Error('Unable to parse color from object: ' + JSON.stringify(obj));\\n\\t\\t}\\n\\n\\t\\tthis.model = hashedModelKeys[hashedKeys];\\n\\n\\t\\tvar labels = convert[this.model].labels;\\n\\t\\tvar color = [];\\n\\t\\tfor (i = 0; i < labels.length; i++) {\\n\\t\\t\\tcolor.push(obj[labels[i]]);\\n\\t\\t}\\n\\n\\t\\tthis.color = zeroArray(color);\\n\\t}\\n\\n\\t// perform limitations (clamping, etc.)\\n\\tif (limiters[this.model]) {\\n\\t\\tchannels = convert[this.model].channels;\\n\\t\\tfor (i = 0; i < channels; i++) {\\n\\t\\t\\tvar limit = limiters[this.model][i];\\n\\t\\t\\tif (limit) {\\n\\t\\t\\t\\tthis.color[i] = limit(this.color[i]);\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n\\n\\tthis.valpha = Math.max(0, Math.min(1, this.valpha));\\n\\n\\tif (Object.freeze) {\\n\\t\\tObject.freeze(this);\\n\\t}\\n}\\n\\nColor.prototype = {\\n\\ttoString: function () {\\n\\t\\treturn this.string();\\n\\t},\\n\\n\\ttoJSON: function () {\\n\\t\\treturn this[this.model]();\\n\\t},\\n\\n\\tstring: function (places) {\\n\\t\\tvar self = this.model in colorString.to ? this : this.rgb();\\n\\t\\tself = self.round(typeof places === 'number' ? places : 1);\\n\\t\\tvar args = self.valpha === 1 ? self.color : self.color.concat(this.valpha);\\n\\t\\treturn colorString.to[self.model](args);\\n\\t},\\n\\n\\tpercentString: function (places) {\\n\\t\\tvar self = this.rgb().round(typeof places === 'number' ? places : 1);\\n\\t\\tvar args = self.valpha === 1 ? self.color : self.color.concat(this.valpha);\\n\\t\\treturn colorString.to.rgb.percent(args);\\n\\t},\\n\\n\\tarray: function () {\\n\\t\\treturn this.valpha === 1 ? this.color.slice() : this.color.concat(this.valpha);\\n\\t},\\n\\n\\tobject: function () {\\n\\t\\tvar result = {};\\n\\t\\tvar channels = convert[this.model].channels;\\n\\t\\tvar labels = convert[this.model].labels;\\n\\n\\t\\tfor (var i = 0; i < channels; i++) {\\n\\t\\t\\tresult[labels[i]] = this.color[i];\\n\\t\\t}\\n\\n\\t\\tif (this.valpha !== 1) {\\n\\t\\t\\tresult.alpha = this.valpha;\\n\\t\\t}\\n\\n\\t\\treturn result;\\n\\t},\\n\\n\\tunitArray: function () {\\n\\t\\tvar rgb = this.rgb().color;\\n\\t\\trgb[0] /= 255;\\n\\t\\trgb[1] /= 255;\\n\\t\\trgb[2] /= 255;\\n\\n\\t\\tif (this.valpha !== 1) {\\n\\t\\t\\trgb.push(this.valpha);\\n\\t\\t}\\n\\n\\t\\treturn rgb;\\n\\t},\\n\\n\\tunitObject: function () {\\n\\t\\tvar rgb = this.rgb().object();\\n\\t\\trgb.r /= 255;\\n\\t\\trgb.g /= 255;\\n\\t\\trgb.b /= 255;\\n\\n\\t\\tif (this.valpha !== 1) {\\n\\t\\t\\trgb.alpha = this.valpha;\\n\\t\\t}\\n\\n\\t\\treturn rgb;\\n\\t},\\n\\n\\tround: function (places) {\\n\\t\\tplaces = Math.max(places || 0, 0);\\n\\t\\treturn new Color(this.color.map(roundToPlace(places)).concat(this.valpha), this.model);\\n\\t},\\n\\n\\talpha: function (val) {\\n\\t\\tif (arguments.length) {\\n\\t\\t\\treturn new Color(this.color.concat(Math.max(0, Math.min(1, val))), this.model);\\n\\t\\t}\\n\\n\\t\\treturn this.valpha;\\n\\t},\\n\\n\\t// rgb\\n\\tred: getset('rgb', 0, maxfn(255)),\\n\\tgreen: getset('rgb', 1, maxfn(255)),\\n\\tblue: getset('rgb', 2, maxfn(255)),\\n\\n\\thue: getset(['hsl', 'hsv', 'hsl', 'hwb', 'hcg'], 0, function (val) { return ((val % 360) + 360) % 360; }), // eslint-disable-line brace-style\\n\\n\\tsaturationl: getset('hsl', 1, maxfn(100)),\\n\\tlightness: getset('hsl', 2, maxfn(100)),\\n\\n\\tsaturationv: getset('hsv', 1, maxfn(100)),\\n\\tvalue: getset('hsv', 2, maxfn(100)),\\n\\n\\tchroma: getset('hcg', 1, maxfn(100)),\\n\\tgray: getset('hcg', 2, maxfn(100)),\\n\\n\\twhite: getset('hwb', 1, maxfn(100)),\\n\\twblack: getset('hwb', 2, maxfn(100)),\\n\\n\\tcyan: getset('cmyk', 0, maxfn(100)),\\n\\tmagenta: getset('cmyk', 1, maxfn(100)),\\n\\tyellow: getset('cmyk', 2, maxfn(100)),\\n\\tblack: getset('cmyk', 3, maxfn(100)),\\n\\n\\tx: getset('xyz', 0, maxfn(100)),\\n\\ty: getset('xyz', 1, maxfn(100)),\\n\\tz: getset('xyz', 2, maxfn(100)),\\n\\n\\tl: getset('lab', 0, maxfn(100)),\\n\\ta: getset('lab', 1),\\n\\tb: getset('lab', 2),\\n\\n\\tkeyword: function (val) {\\n\\t\\tif (arguments.length) {\\n\\t\\t\\treturn new Color(val);\\n\\t\\t}\\n\\n\\t\\treturn convert[this.model].keyword(this.color);\\n\\t},\\n\\n\\thex: function (val) {\\n\\t\\tif (arguments.length) {\\n\\t\\t\\treturn new Color(val);\\n\\t\\t}\\n\\n\\t\\treturn colorString.to.hex(this.rgb().round().color);\\n\\t},\\n\\n\\trgbNumber: function () {\\n\\t\\tvar rgb = this.rgb().color;\\n\\t\\treturn ((rgb[0] & 0xFF) << 16) | ((rgb[1] & 0xFF) << 8) | (rgb[2] & 0xFF);\\n\\t},\\n\\n\\tluminosity: function () {\\n\\t\\t// http://www.w3.org/TR/WCAG20/#relativeluminancedef\\n\\t\\tvar rgb = this.rgb().color;\\n\\n\\t\\tvar lum = [];\\n\\t\\tfor (var i = 0; i < rgb.length; i++) {\\n\\t\\t\\tvar chan = rgb[i] / 255;\\n\\t\\t\\tlum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4);\\n\\t\\t}\\n\\n\\t\\treturn 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2];\\n\\t},\\n\\n\\tcontrast: function (color2) {\\n\\t\\t// http://www.w3.org/TR/WCAG20/#contrast-ratiodef\\n\\t\\tvar lum1 = this.luminosity();\\n\\t\\tvar lum2 = color2.luminosity();\\n\\n\\t\\tif (lum1 > lum2) {\\n\\t\\t\\treturn (lum1 + 0.05) / (lum2 + 0.05);\\n\\t\\t}\\n\\n\\t\\treturn (lum2 + 0.05) / (lum1 + 0.05);\\n\\t},\\n\\n\\tlevel: function (color2) {\\n\\t\\tvar contrastRatio = this.contrast(color2);\\n\\t\\tif (contrastRatio >= 7.1) {\\n\\t\\t\\treturn 'AAA';\\n\\t\\t}\\n\\n\\t\\treturn (contrastRatio >= 4.5) ? 'AA' : '';\\n\\t},\\n\\n\\tisDark: function () {\\n\\t\\t// YIQ equation from http://24ways.org/2010/calculating-color-contrast\\n\\t\\tvar rgb = this.rgb().color;\\n\\t\\tvar yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;\\n\\t\\treturn yiq < 128;\\n\\t},\\n\\n\\tisLight: function () {\\n\\t\\treturn !this.isDark();\\n\\t},\\n\\n\\tnegate: function () {\\n\\t\\tvar rgb = this.rgb();\\n\\t\\tfor (var i = 0; i < 3; i++) {\\n\\t\\t\\trgb.color[i] = 255 - rgb.color[i];\\n\\t\\t}\\n\\t\\treturn rgb;\\n\\t},\\n\\n\\tlighten: function (ratio) {\\n\\t\\tvar hsl = this.hsl();\\n\\t\\thsl.color[2] += hsl.color[2] * ratio;\\n\\t\\treturn hsl;\\n\\t},\\n\\n\\tdarken: function (ratio) {\\n\\t\\tvar hsl = this.hsl();\\n\\t\\thsl.color[2] -= hsl.color[2] * ratio;\\n\\t\\treturn hsl;\\n\\t},\\n\\n\\tsaturate: function (ratio) {\\n\\t\\tvar hsl = this.hsl();\\n\\t\\thsl.color[1] += hsl.color[1] * ratio;\\n\\t\\treturn hsl;\\n\\t},\\n\\n\\tdesaturate: function (ratio) {\\n\\t\\tvar hsl = this.hsl();\\n\\t\\thsl.color[1] -= hsl.color[1] * ratio;\\n\\t\\treturn hsl;\\n\\t},\\n\\n\\twhiten: function (ratio) {\\n\\t\\tvar hwb = this.hwb();\\n\\t\\thwb.color[1] += hwb.color[1] * ratio;\\n\\t\\treturn hwb;\\n\\t},\\n\\n\\tblacken: function (ratio) {\\n\\t\\tvar hwb = this.hwb();\\n\\t\\thwb.color[2] += hwb.color[2] * ratio;\\n\\t\\treturn hwb;\\n\\t},\\n\\n\\tgrayscale: function () {\\n\\t\\t// http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale\\n\\t\\tvar rgb = this.rgb().color;\\n\\t\\tvar val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11;\\n\\t\\treturn Color.rgb(val, val, val);\\n\\t},\\n\\n\\tfade: function (ratio) {\\n\\t\\treturn this.alpha(this.valpha - (this.valpha * ratio));\\n\\t},\\n\\n\\topaquer: function (ratio) {\\n\\t\\treturn this.alpha(this.valpha + (this.valpha * ratio));\\n\\t},\\n\\n\\trotate: function (degrees) {\\n\\t\\tvar hsl = this.hsl();\\n\\t\\tvar hue = hsl.color[0];\\n\\t\\thue = (hue + degrees) % 360;\\n\\t\\thue = hue < 0 ? 360 + hue : hue;\\n\\t\\thsl.color[0] = hue;\\n\\t\\treturn hsl;\\n\\t},\\n\\n\\tmix: function (mixinColor, weight) {\\n\\t\\t// ported from sass implementation in C\\n\\t\\t// https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209\\n\\t\\tif (!mixinColor || !mixinColor.rgb) {\\n\\t\\t\\tthrow new Error('Argument to \\\"mix\\\" was not a Color instance, but rather an instance of ' + typeof mixinColor);\\n\\t\\t}\\n\\t\\tvar color1 = mixinColor.rgb();\\n\\t\\tvar color2 = this.rgb();\\n\\t\\tvar p = weight === undefined ? 0.5 : weight;\\n\\n\\t\\tvar w = 2 * p - 1;\\n\\t\\tvar a = color1.alpha() - color2.alpha();\\n\\n\\t\\tvar w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;\\n\\t\\tvar w2 = 1 - w1;\\n\\n\\t\\treturn Color.rgb(\\n\\t\\t\\t\\tw1 * color1.red() + w2 * color2.red(),\\n\\t\\t\\t\\tw1 * color1.green() + w2 * color2.green(),\\n\\t\\t\\t\\tw1 * color1.blue() + w2 * color2.blue(),\\n\\t\\t\\t\\tcolor1.alpha() * p + color2.alpha() * (1 - p));\\n\\t}\\n};\\n\\n// model conversion methods and static constructors\\nObject.keys(convert).forEach(function (model) {\\n\\tif (skippedModels.indexOf(model) !== -1) {\\n\\t\\treturn;\\n\\t}\\n\\n\\tvar channels = convert[model].channels;\\n\\n\\t// conversion methods\\n\\tColor.prototype[model] = function () {\\n\\t\\tif (this.model === model) {\\n\\t\\t\\treturn new Color(this);\\n\\t\\t}\\n\\n\\t\\tif (arguments.length) {\\n\\t\\t\\treturn new Color(arguments, model);\\n\\t\\t}\\n\\n\\t\\tvar newAlpha = typeof arguments[channels] === 'number' ? channels : this.valpha;\\n\\t\\treturn new Color(assertArray(convert[this.model][model].raw(this.color)).concat(newAlpha), model);\\n\\t};\\n\\n\\t// 'static' construction methods\\n\\tColor[model] = function (color) {\\n\\t\\tif (typeof color === 'number') {\\n\\t\\t\\tcolor = zeroArray(_slice.call(arguments), channels);\\n\\t\\t}\\n\\t\\treturn new Color(color, model);\\n\\t};\\n});\\n\\nfunction roundTo(num, places) {\\n\\treturn Number(num.toFixed(places));\\n}\\n\\nfunction roundToPlace(places) {\\n\\treturn function (num) {\\n\\t\\treturn roundTo(num, places);\\n\\t};\\n}\\n\\nfunction getset(model, channel, modifier) {\\n\\tmodel = Array.isArray(model) ? model : [model];\\n\\n\\tmodel.forEach(function (m) {\\n\\t\\t(limiters[m] || (limiters[m] = []))[channel] = modifier;\\n\\t});\\n\\n\\tmodel = model[0];\\n\\n\\treturn function (val) {\\n\\t\\tvar result;\\n\\n\\t\\tif (arguments.length) {\\n\\t\\t\\tif (modifier) {\\n\\t\\t\\t\\tval = modifier(val);\\n\\t\\t\\t}\\n\\n\\t\\t\\tresult = this[model]();\\n\\t\\t\\tresult.color[channel] = val;\\n\\t\\t\\treturn result;\\n\\t\\t}\\n\\n\\t\\tresult = this[model]().color[channel];\\n\\t\\tif (modifier) {\\n\\t\\t\\tresult = modifier(result);\\n\\t\\t}\\n\\n\\t\\treturn result;\\n\\t};\\n}\\n\\nfunction maxfn(max) {\\n\\treturn function (v) {\\n\\t\\treturn Math.max(0, Math.min(max, v));\\n\\t};\\n}\\n\\nfunction assertArray(val) {\\n\\treturn Array.isArray(val) ? val : [val];\\n}\\n\\nfunction zeroArray(arr, length) {\\n\\tfor (var i = 0; i < length; i++) {\\n\\t\\tif (typeof arr[i] !== 'number') {\\n\\t\\t\\tarr[i] = 0;\\n\\t\\t}\\n\\t}\\n\\n\\treturn arr;\\n}\\n\\nmodule.exports = Color;\\n\\n\\n//# sourceURL=webpack:///./node_modules/color/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/gui/component/audio-node.scss\":\n/*!**********************************************************************************************************************************!*\\\n  !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2!./src/gui/component/audio-node.scss ***!\n  \\**********************************************************************************************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"// Imports\\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \\\"./node_modules/css-loader/dist/runtime/api.js\\\");\\nexports = ___CSS_LOADER_API_IMPORT___(false);\\n// Module\\nexports.push([module.i, \\\":host {\\\\n  max-width: 320px;\\\\n  width: 100%;\\\\n  display: block; }\\\\n\\\\n#container {\\\\n  font-family: \\\\\\\"Open Sans\\\\\\\", sans-serif;\\\\n  margin-bottom: 10px;\\\\n  border-bottom: 1px solid #ddd;\\\\n  max-width: 320px;\\\\n  width: 100%; }\\\\n  #container #title {\\\\n    font-size: 18px !important;\\\\n    font-family: \\\\\\\"Roboto\\\\\\\", sans-serif; }\\\\n  #container .value {\\\\n    display: block;\\\\n    margin-top: 4px; }\\\\n  #container details {\\\\n    margin-top: 4px;\\\\n    font-size: 14px;\\\\n    line-height: 24px; }\\\\n    #container details.sub-value {\\\\n      background-color: rgba(0, 0, 0, 0.05);\\\\n      padding: 5px; }\\\\n    #container details #json {\\\\n      font-size: 0.8em; }\\\\n      #container details #json summary {\\\\n        color: #f5871f;\\\\n        padding-left: 10px; }\\\\n        #container details #json summary mwc-icon {\\\\n          --mdc-icon-size: 10px; }\\\\n      #container details #json pre {\\\\n        overflow: scroll; }\\\\n    #container details summary {\\\\n      list-style: none; }\\\\n      #container details summary mwc-icon {\\\\n        position: relative;\\\\n        transform: translate(0px, 4px);\\\\n        height: 20px;\\\\n        font-size: 20px;\\\\n        margin-left: 0px; }\\\\n      #container details summary #download {\\\\n        position: absolute;\\\\n        right: 10px;\\\\n        color: #ececec; }\\\\n      #container details summary#title {\\\\n        padding: 2px 2px 5px 2px; }\\\\n      #container details summary::-webkit-details-marker {\\\\n        display: none; }\\\\n      #container details summary::marker {\\\\n        display: none; }\\\\n      #container details summary:focus {\\\\n        outline: none;\\\\n        background-color: #fcd5b1; }\\\\n\\\", \\\"\\\"]);\\n// Exports\\nmodule.exports = exports;\\n\\n\\n//# sourceURL=webpack:///./src/gui/component/audio-node.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2\");\n\n/***/ }),\n\n/***/ \"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/gui/component/drawer.scss\":\n/*!******************************************************************************************************************************!*\\\n  !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2!./src/gui/component/drawer.scss ***!\n  \\******************************************************************************************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"// Imports\\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \\\"./node_modules/css-loader/dist/runtime/api.js\\\");\\nexports = ___CSS_LOADER_API_IMPORT___(false);\\n// Module\\nexports.push([module.i, \\\"#container {\\\\n  display: inline-block;\\\\n  position: fixed;\\\\n  right: 0px;\\\\n  bottom: 0px;\\\\n  width: 320px;\\\\n  background-color: white;\\\\n  z-index: 1000000;\\\\n  box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); }\\\\n  #container[hidden] {\\\\n    display: none; }\\\\n  #container:not([open]) {\\\\n    height: 20px; }\\\\n  #container #scroll {\\\\n    display: inline-block;\\\\n    max-height: calc( 100vh - 24px - 20px);\\\\n    margin-top: 20px;\\\\n    width: calc(100% - 20px);\\\\n    overflow-y: auto;\\\\n    padding: 10px;\\\\n    padding-bottom: 0px; }\\\\n    #container #scroll #inner-scroll {\\\\n      display: inline-block;\\\\n      width: 100%; }\\\\n  #container details summary {\\\\n    background-color: #ececec;\\\\n    color: #616161;\\\\n    text-align: center;\\\\n    font-family: \\\\\\\"Roboto\\\\\\\", sans-serif;\\\\n    text-align: center;\\\\n    position: absolute;\\\\n    top: 3px;\\\\n    width: calc(100% - 6px);\\\\n    left: 3px;\\\\n    font-size: 0.8em;\\\\n    height: 14px;\\\\n    line-height: 14px;\\\\n    border-radius: 3px;\\\\n    cursor: pointer;\\\\n    list-style: none; }\\\\n    #container details summary mwc-icon {\\\\n      position: absolute;\\\\n      top: 0px;\\\\n      left: 0px;\\\\n      height: 14px;\\\\n      font-size: 14px; }\\\\n    #container details summary::-webkit-details-marker {\\\\n      display: none; }\\\\n    #container details summary::marker {\\\\n      display: none; }\\\\n\\\", \\\"\\\"]);\\n// Exports\\nmodule.exports = exports;\\n\\n\\n//# sourceURL=webpack:///./src/gui/component/drawer.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2\");\n\n/***/ }),\n\n/***/ \"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/gui/component/folder.scss\":\n/*!******************************************************************************************************************************!*\\\n  !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2!./src/gui/component/folder.scss ***!\n  \\******************************************************************************************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"// Imports\\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \\\"./node_modules/css-loader/dist/runtime/api.js\\\");\\nexports = ___CSS_LOADER_API_IMPORT___(false);\\n// Module\\nexports.push([module.i, \\\"#container {\\\\n  font-family: \\\\\\\"Roboto\\\\\\\", sans-serif;\\\\n  width: calc(100% - 20px);\\\\n  margin-bottom: 10px; }\\\\n  #container details {\\\\n    width: 100%; }\\\\n    #container details summary {\\\\n      font-weight: bold;\\\\n      font-size: 1.1em;\\\\n      border-bottom: 1px solid black;\\\\n      list-style: none; }\\\\n      #container details summary mwc-icon {\\\\n        position: relative;\\\\n        transform: translate(0px, 4px);\\\\n        height: 20px;\\\\n        font-size: 20px;\\\\n        margin-left: 0px; }\\\\n      #container details summary::-webkit-details-marker {\\\\n        display: none; }\\\\n      #container details summary::marker {\\\\n        display: none; }\\\\n    #container details #contents {\\\\n      width: calc(100% - 5px);\\\\n      margin-left: 5px; }\\\\n\\\", \\\"\\\"]);\\n// Exports\\nmodule.exports = exports;\\n\\n\\n//# sourceURL=webpack:///./src/gui/component/folder.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2\");\n\n/***/ }),\n\n/***/ \"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/gui/value/value.scss\":\n/*!*************************************************************************************************************************!*\\\n  !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2!./src/gui/value/value.scss ***!\n  \\*************************************************************************************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"// Imports\\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \\\"./node_modules/css-loader/dist/runtime/api.js\\\");\\nexports = ___CSS_LOADER_API_IMPORT___(false);\\n// Module\\nexports.push([module.i, \\\"#container {\\\\n  width: 100%;\\\\n  font-size: 14px;\\\\n  font-family: \\\\\\\"Open Sans\\\\\\\", sans-serif;\\\\n  background-color: transparent; }\\\\n  #container label {\\\\n    padding-left: 6px; }\\\\n  #container.error input {\\\\n    transition-duration: 0s;\\\\n    color: gray; }\\\\n  #container input {\\\\n    transition: color 0.2s;\\\\n    font-family: inherit;\\\\n    font-size: inherit;\\\\n    -webkit-appearance: none;\\\\n    appearance: none;\\\\n    border: 0px;\\\\n    text-align: right;\\\\n    float: right;\\\\n    background-color: transparent;\\\\n    outline: 0px solid #fcd5b1; }\\\\n    #container input:focus {\\\\n      outline-width: 3px; }\\\\n  #container.array {\\\\n    display: flex; }\\\\n    #container.array label, #container.array #bars {\\\\n      flex: 1; }\\\\n    #container.array label[disabled] {\\\\n      color: lightgray; }\\\\n    #container.array #bars {\\\\n      display: flex;\\\\n      flex-direction: row; }\\\\n      #container.array #bars .bar {\\\\n        flex: 1;\\\\n        height: 100%;\\\\n        position: relative;\\\\n        margin: 0px 1px; }\\\\n        #container.array #bars .bar .fill {\\\\n          pointer-events: none;\\\\n          background-color: black;\\\\n          position: absolute;\\\\n          bottom: 0px;\\\\n          left: 0px;\\\\n          width: 100%;\\\\n          height: 0px; }\\\\n  #container.boolean input {\\\\n    margin: 0px;\\\\n    box-sizing: border-box;\\\\n    border: 2px solid #ddd;\\\\n    background-color: #ddd;\\\\n    width: 16px;\\\\n    height: 16px; }\\\\n    #container.boolean input[checked] {\\\\n      background-color: black; }\\\\n\\\", \\\"\\\"]);\\n// Exports\\nmodule.exports = exports;\\n\\n\\n//# sourceURL=webpack:///./src/gui/value/value.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ref--5-2\");\n\n/***/ }),\n\n/***/ \"./node_modules/css-loader/dist/runtime/api.js\":\n/*!*****************************************************!*\\\n  !*** ./node_modules/css-loader/dist/runtime/api.js ***!\n  \\*****************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\n/*\\n  MIT License http://www.opensource.org/licenses/mit-license.php\\n  Author Tobias Koppers @sokra\\n*/\\n// css base code, injected by the css-loader\\n// eslint-disable-next-line func-names\\nmodule.exports = function (useSourceMap) {\\n  var list = []; // return the list of modules as css string\\n\\n  list.toString = function toString() {\\n    return this.map(function (item) {\\n      var content = cssWithMappingToString(item, useSourceMap);\\n\\n      if (item[2]) {\\n        return \\\"@media \\\".concat(item[2], \\\" {\\\").concat(content, \\\"}\\\");\\n      }\\n\\n      return content;\\n    }).join('');\\n  }; // import a list of modules into the list\\n  // eslint-disable-next-line func-names\\n\\n\\n  list.i = function (modules, mediaQuery, dedupe) {\\n    if (typeof modules === 'string') {\\n      // eslint-disable-next-line no-param-reassign\\n      modules = [[null, modules, '']];\\n    }\\n\\n    var alreadyImportedModules = {};\\n\\n    if (dedupe) {\\n      for (var i = 0; i < this.length; i++) {\\n        // eslint-disable-next-line prefer-destructuring\\n        var id = this[i][0];\\n\\n        if (id != null) {\\n          alreadyImportedModules[id] = true;\\n        }\\n      }\\n    }\\n\\n    for (var _i = 0; _i < modules.length; _i++) {\\n      var item = [].concat(modules[_i]);\\n\\n      if (dedupe && alreadyImportedModules[item[0]]) {\\n        // eslint-disable-next-line no-continue\\n        continue;\\n      }\\n\\n      if (mediaQuery) {\\n        if (!item[2]) {\\n          item[2] = mediaQuery;\\n        } else {\\n          item[2] = \\\"\\\".concat(mediaQuery, \\\" and \\\").concat(item[2]);\\n        }\\n      }\\n\\n      list.push(item);\\n    }\\n  };\\n\\n  return list;\\n};\\n\\nfunction cssWithMappingToString(item, useSourceMap) {\\n  var content = item[1] || ''; // eslint-disable-next-line prefer-destructuring\\n\\n  var cssMapping = item[3];\\n\\n  if (!cssMapping) {\\n    return content;\\n  }\\n\\n  if (useSourceMap && typeof btoa === 'function') {\\n    var sourceMapping = toComment(cssMapping);\\n    var sourceURLs = cssMapping.sources.map(function (source) {\\n      return \\\"/*# sourceURL=\\\".concat(cssMapping.sourceRoot || '').concat(source, \\\" */\\\");\\n    });\\n    return [content].concat(sourceURLs).concat([sourceMapping]).join('\\\\n');\\n  }\\n\\n  return [content].join('\\\\n');\\n} // Adapted from convert-source-map (MIT)\\n\\n\\nfunction toComment(sourceMap) {\\n  // eslint-disable-next-line no-undef\\n  var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))));\\n  var data = \\\"sourceMappingURL=data:application/json;charset=utf-8;base64,\\\".concat(base64);\\n  return \\\"/*# \\\".concat(data, \\\" */\\\");\\n}\\n\\n//# sourceURL=webpack:///./node_modules/css-loader/dist/runtime/api.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/deep-equal/index.js\":\n/*!******************************************!*\\\n  !*** ./node_modules/deep-equal/index.js ***!\n  \\******************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar objectKeys = __webpack_require__(/*! object-keys */ \\\"./node_modules/object-keys/index.js\\\");\\nvar isArguments = __webpack_require__(/*! is-arguments */ \\\"./node_modules/is-arguments/index.js\\\");\\nvar is = __webpack_require__(/*! object-is */ \\\"./node_modules/object-is/index.js\\\");\\nvar isRegex = __webpack_require__(/*! is-regex */ \\\"./node_modules/is-regex/index.js\\\");\\nvar flags = __webpack_require__(/*! regexp.prototype.flags */ \\\"./node_modules/regexp.prototype.flags/index.js\\\");\\nvar isArray = __webpack_require__(/*! isarray */ \\\"./node_modules/deep-equal/node_modules/isarray/index.js\\\");\\nvar isDate = __webpack_require__(/*! is-date-object */ \\\"./node_modules/is-date-object/index.js\\\");\\nvar whichBoxedPrimitive = __webpack_require__(/*! which-boxed-primitive */ \\\"./node_modules/which-boxed-primitive/index.js\\\");\\nvar GetIntrinsic = __webpack_require__(/*! es-abstract/GetIntrinsic */ \\\"./node_modules/es-abstract/GetIntrinsic.js\\\");\\nvar callBound = __webpack_require__(/*! es-abstract/helpers/callBound */ \\\"./node_modules/es-abstract/helpers/callBound.js\\\");\\nvar whichCollection = __webpack_require__(/*! which-collection */ \\\"./node_modules/which-collection/index.js\\\");\\nvar getIterator = __webpack_require__(/*! es-get-iterator */ \\\"./node_modules/es-get-iterator/index.js\\\");\\nvar getSideChannel = __webpack_require__(/*! side-channel */ \\\"./node_modules/side-channel/index.js\\\");\\nvar whichTypedArray = __webpack_require__(/*! which-typed-array */ \\\"./node_modules/which-typed-array/index.js\\\");\\nvar assign = __webpack_require__(/*! object.assign */ \\\"./node_modules/object.assign/index.js\\\");\\n\\nvar $getTime = callBound('Date.prototype.getTime');\\nvar gPO = Object.getPrototypeOf;\\nvar $objToString = callBound('Object.prototype.toString');\\n\\nvar $Set = GetIntrinsic('%Set%', true);\\nvar $mapHas = callBound('Map.prototype.has', true);\\nvar $mapGet = callBound('Map.prototype.get', true);\\nvar $mapSize = callBound('Map.prototype.size', true);\\nvar $setAdd = callBound('Set.prototype.add', true);\\nvar $setDelete = callBound('Set.prototype.delete', true);\\nvar $setHas = callBound('Set.prototype.has', true);\\nvar $setSize = callBound('Set.prototype.size', true);\\n\\n// taken from https://github.com/browserify/commonjs-assert/blob/bba838e9ba9e28edf3127ce6974624208502f6bc/internal/util/comparisons.js#L401-L414\\nfunction setHasEqualElement(set, val1, opts, channel) {\\n  var i = getIterator(set);\\n  var result;\\n  while ((result = i.next()) && !result.done) {\\n    if (internalDeepEqual(val1, result.value, opts, channel)) { // eslint-disable-line no-use-before-define\\n      // Remove the matching element to make sure we do not check that again.\\n      $setDelete(set, result.value);\\n      return true;\\n    }\\n  }\\n\\n  return false;\\n}\\n\\n// taken from https://github.com/browserify/commonjs-assert/blob/bba838e9ba9e28edf3127ce6974624208502f6bc/internal/util/comparisons.js#L416-L439\\nfunction findLooseMatchingPrimitives(prim) {\\n  if (typeof prim === 'undefined') {\\n    return null;\\n  }\\n  if (typeof prim === 'object') { // Only pass in null as object!\\n    return void 0;\\n  }\\n  if (typeof prim === 'symbol') {\\n    return false;\\n  }\\n  if (typeof prim === 'string' || typeof prim === 'number') {\\n    // Loose equal entries exist only if the string is possible to convert to a regular number and not NaN.\\n    return +prim === +prim; // eslint-disable-line no-implicit-coercion\\n  }\\n  return true;\\n}\\n\\n// taken from https://github.com/browserify/commonjs-assert/blob/bba838e9ba9e28edf3127ce6974624208502f6bc/internal/util/comparisons.js#L449-L460\\nfunction mapMightHaveLoosePrim(a, b, prim, item, opts, channel) {\\n  var altValue = findLooseMatchingPrimitives(prim);\\n  if (altValue != null) {\\n    return altValue;\\n  }\\n  var curB = $mapGet(b, altValue);\\n  var looseOpts = assign({}, opts, { strict: false });\\n  if (\\n    (typeof curB === 'undefined' && !$mapHas(b, altValue))\\n    // eslint-disable-next-line no-use-before-define\\n    || !internalDeepEqual(item, curB, looseOpts, channel)\\n  ) {\\n    return false;\\n  }\\n  // eslint-disable-next-line no-use-before-define\\n  return !$mapHas(a, altValue) && internalDeepEqual(item, curB, looseOpts, channel);\\n}\\n\\n// taken from https://github.com/browserify/commonjs-assert/blob/bba838e9ba9e28edf3127ce6974624208502f6bc/internal/util/comparisons.js#L441-L447\\nfunction setMightHaveLoosePrim(a, b, prim) {\\n  var altValue = findLooseMatchingPrimitives(prim);\\n  if (altValue != null) {\\n    return altValue;\\n  }\\n\\n  return $setHas(b, altValue) && !$setHas(a, altValue);\\n}\\n\\n// taken from https://github.com/browserify/commonjs-assert/blob/bba838e9ba9e28edf3127ce6974624208502f6bc/internal/util/comparisons.js#L518-L533\\nfunction mapHasEqualEntry(set, map, key1, item1, opts, channel) {\\n  var i = getIterator(set);\\n  var result;\\n  var key2;\\n  while ((result = i.next()) && !result.done) {\\n    key2 = result.value;\\n    if (\\n      // eslint-disable-next-line no-use-before-define\\n      internalDeepEqual(key1, key2, opts, channel)\\n      // eslint-disable-next-line no-use-before-define\\n      && internalDeepEqual(item1, $mapGet(map, key2), opts, channel)\\n    ) {\\n      $setDelete(set, key2);\\n      return true;\\n    }\\n  }\\n\\n  return false;\\n}\\n\\nfunction internalDeepEqual(actual, expected, options, channel) {\\n  var opts = options || {};\\n\\n  // 7.1. All identical values are equivalent, as determined by ===.\\n  if (opts.strict ? is(actual, expected) : actual === expected) {\\n    return true;\\n  }\\n\\n  var actualBoxed = whichBoxedPrimitive(actual);\\n  var expectedBoxed = whichBoxedPrimitive(expected);\\n  if (actualBoxed !== expectedBoxed) {\\n    return false;\\n  }\\n\\n  // 7.3. Other pairs that do not both pass typeof value == 'object', equivalence is determined by ==.\\n  if (!actual || !expected || (typeof actual !== 'object' && typeof expected !== 'object')) {\\n    return opts.strict ? is(actual, expected) : actual == expected; // eslint-disable-line eqeqeq\\n  }\\n\\n  /*\\n   * 7.4. For all other Object pairs, including Array objects, equivalence is\\n   * determined by having the same number of owned properties (as verified\\n   * with Object.prototype.hasOwnProperty.call), the same set of keys\\n   * (although not necessarily the same order), equivalent values for every\\n   * corresponding key, and an identical 'prototype' property. Note: this\\n   * accounts for both named and indexed properties on Arrays.\\n   */\\n  // see https://github.com/nodejs/node/commit/d3aafd02efd3a403d646a3044adcf14e63a88d32 for memos/channel inspiration\\n\\n  var hasActual = channel.has(actual);\\n  var hasExpected = channel.has(expected);\\n  var sentinel;\\n  if (hasActual && hasExpected) {\\n    if (channel.get(actual) === channel.get(expected)) {\\n      return true;\\n    }\\n  } else {\\n    sentinel = {};\\n  }\\n  if (!hasActual) { channel.set(actual, sentinel); }\\n  if (!hasExpected) { channel.set(expected, sentinel); }\\n\\n  // eslint-disable-next-line no-use-before-define\\n  return objEquiv(actual, expected, opts, channel);\\n}\\n\\nfunction isBuffer(x) {\\n  if (!x || typeof x !== 'object' || typeof x.length !== 'number') {\\n    return false;\\n  }\\n  if (typeof x.copy !== 'function' || typeof x.slice !== 'function') {\\n    return false;\\n  }\\n  if (x.length > 0 && typeof x[0] !== 'number') {\\n    return false;\\n  }\\n\\n  return !!(x.constructor && x.constructor.isBuffer && x.constructor.isBuffer(x));\\n}\\n\\nfunction setEquiv(a, b, opts, channel) {\\n  if ($setSize(a) !== $setSize(b)) {\\n    return false;\\n  }\\n  var iA = getIterator(a);\\n  var iB = getIterator(b);\\n  var resultA;\\n  var resultB;\\n  var set;\\n  while ((resultA = iA.next()) && !resultA.done) {\\n    if (resultA.value && typeof resultA.value === 'object') {\\n      if (!set) { set = new $Set(); }\\n      $setAdd(set, resultA.value);\\n    } else if (!$setHas(b, resultA.value)) {\\n      if (opts.strict) { return false; }\\n      if (!setMightHaveLoosePrim(a, b, resultA.value)) {\\n        return false;\\n      }\\n      if (!set) { set = new $Set(); }\\n      $setAdd(set, resultA.value);\\n    }\\n  }\\n  if (set) {\\n    while ((resultB = iB.next()) && !resultB.done) {\\n      // We have to check if a primitive value is already matching and only if it's not, go hunting for it.\\n      if (resultB.value && typeof resultB.value === 'object') {\\n        if (!setHasEqualElement(set, resultB.value, opts.strict, channel)) {\\n          return false;\\n        }\\n      } else if (\\n        !opts.strict\\n        && !$setHas(a, resultB.value)\\n        && !setHasEqualElement(set, resultB.value, opts.strict, channel)\\n      ) {\\n        return false;\\n      }\\n    }\\n    return $setSize(set) === 0;\\n  }\\n  return true;\\n}\\n\\nfunction mapEquiv(a, b, opts, channel) {\\n  if ($mapSize(a) !== $mapSize(b)) {\\n    return false;\\n  }\\n  var iA = getIterator(a);\\n  var iB = getIterator(b);\\n  var resultA;\\n  var resultB;\\n  var set;\\n  var key;\\n  var item1;\\n  var item2;\\n  while ((resultA = iA.next()) && !resultA.done) {\\n    key = resultA.value[0];\\n    item1 = resultA.value[1];\\n    if (key && typeof key === 'object') {\\n      if (!set) { set = new $Set(); }\\n      $setAdd(set, key);\\n    } else {\\n      item2 = $mapGet(b, key);\\n      if ((typeof item2 === 'undefined' && !$mapHas(b, key)) || !internalDeepEqual(item1, item2, opts, channel)) {\\n        if (opts.strict) {\\n          return false;\\n        }\\n        if (!mapMightHaveLoosePrim(a, b, key, item1, opts, channel)) {\\n          return false;\\n        }\\n        if (!set) { set = new $Set(); }\\n        $setAdd(set, key);\\n      }\\n    }\\n  }\\n\\n  if (set) {\\n    while ((resultB = iB.next()) && !resultB.done) {\\n      key = resultB.value[0];\\n      item2 = resultB.value[1];\\n      if (key && typeof key === 'object') {\\n        if (!mapHasEqualEntry(set, a, key, item2, opts, channel)) {\\n          return false;\\n        }\\n      } else if (\\n        !opts.strict\\n        && (!a.has(key) || !internalDeepEqual($mapGet(a, key), item2, opts, channel))\\n        && !mapHasEqualEntry(set, a, key, item2, assign({}, opts, { strict: false }), channel)\\n      ) {\\n        return false;\\n      }\\n    }\\n    return $setSize(set) === 0;\\n  }\\n  return true;\\n}\\n\\nfunction objEquiv(a, b, opts, channel) {\\n  /* eslint max-statements: [2, 100], max-lines-per-function: [2, 120], max-depth: [2, 5] */\\n  var i, key;\\n\\n  if (typeof a !== typeof b) { return false; }\\n  if (a == null || b == null) { return false; }\\n\\n  if ($objToString(a) !== $objToString(b)) { return false; }\\n\\n  if (isArguments(a) !== isArguments(b)) { return false; }\\n\\n  var aIsArray = isArray(a);\\n  var bIsArray = isArray(b);\\n  if (aIsArray !== bIsArray) { return false; }\\n\\n  // TODO: replace when a cross-realm brand check is available\\n  var aIsError = a instanceof Error;\\n  var bIsError = b instanceof Error;\\n  if (aIsError !== bIsError) { return false; }\\n  if (aIsError || bIsError) {\\n    if (a.name !== b.name || a.message !== b.message) { return false; }\\n  }\\n\\n  var aIsRegex = isRegex(a);\\n  var bIsRegex = isRegex(b);\\n  if (aIsRegex !== bIsRegex) { return false; }\\n  if ((aIsRegex || bIsRegex) && (a.source !== b.source || flags(a) !== flags(b))) {\\n    return false;\\n  }\\n\\n  var aIsDate = isDate(a);\\n  var bIsDate = isDate(b);\\n  if (aIsDate !== bIsDate) { return false; }\\n  if (aIsDate || bIsDate) { // && would work too, because both are true or both false here\\n    if ($getTime(a) !== $getTime(b)) { return false; }\\n  }\\n  if (opts.strict && gPO && gPO(a) !== gPO(b)) { return false; }\\n\\n  if (whichTypedArray(a) !== whichTypedArray(b)) {\\n    return false;\\n  }\\n\\n  var aIsBuffer = isBuffer(a);\\n  var bIsBuffer = isBuffer(b);\\n  if (aIsBuffer !== bIsBuffer) { return false; }\\n  if (aIsBuffer || bIsBuffer) { // && would work too, because both are true or both false here\\n    if (a.length !== b.length) { return false; }\\n    for (i = 0; i < a.length; i++) {\\n      if (a[i] !== b[i]) { return false; }\\n    }\\n    return true;\\n  }\\n\\n  if (typeof a !== typeof b) { return false; }\\n\\n  var ka = objectKeys(a);\\n  var kb = objectKeys(b);\\n  // having the same number of owned properties (keys incorporates hasOwnProperty)\\n  if (ka.length !== kb.length) { return false; }\\n\\n  // the same set of keys (although not necessarily the same order),\\n  ka.sort();\\n  kb.sort();\\n  // ~~~cheap key test\\n  for (i = ka.length - 1; i >= 0; i--) {\\n    if (ka[i] != kb[i]) { return false; } // eslint-disable-line eqeqeq\\n  }\\n\\n  // equivalent values for every corresponding key, and ~~~possibly expensive deep test\\n  for (i = ka.length - 1; i >= 0; i--) {\\n    key = ka[i];\\n    if (!internalDeepEqual(a[key], b[key], opts, channel)) { return false; }\\n  }\\n\\n  var aCollection = whichCollection(a);\\n  var bCollection = whichCollection(b);\\n  if (aCollection !== bCollection) {\\n    return false;\\n  }\\n  if (aCollection === 'Set' || bCollection === 'Set') { // aCollection === bCollection\\n    return setEquiv(a, b, opts, channel);\\n  }\\n  if (aCollection === 'Map') { // aCollection === bCollection\\n    return mapEquiv(a, b, opts, channel);\\n  }\\n\\n  return true;\\n}\\n\\nmodule.exports = function deepEqual(a, b, opts) {\\n  return internalDeepEqual(a, b, opts, getSideChannel());\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/deep-equal/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/deep-equal/node_modules/isarray/index.js\":\n/*!***************************************************************!*\\\n  !*** ./node_modules/deep-equal/node_modules/isarray/index.js ***!\n  \\***************************************************************/\n/*! no static exports found */\n/***/ (function(module, exports) {\n\neval(\"var toString = {}.toString;\\n\\nmodule.exports = Array.isArray || function (arr) {\\n  return toString.call(arr) == '[object Array]';\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/deep-equal/node_modules/isarray/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/define-properties/index.js\":\n/*!*************************************************!*\\\n  !*** ./node_modules/define-properties/index.js ***!\n  \\*************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar keys = __webpack_require__(/*! object-keys */ \\\"./node_modules/object-keys/index.js\\\");\\nvar hasSymbols = typeof Symbol === 'function' && typeof Symbol('foo') === 'symbol';\\n\\nvar toStr = Object.prototype.toString;\\nvar concat = Array.prototype.concat;\\nvar origDefineProperty = Object.defineProperty;\\n\\nvar isFunction = function (fn) {\\n\\treturn typeof fn === 'function' && toStr.call(fn) === '[object Function]';\\n};\\n\\nvar arePropertyDescriptorsSupported = function () {\\n\\tvar obj = {};\\n\\ttry {\\n\\t\\torigDefineProperty(obj, 'x', { enumerable: false, value: obj });\\n\\t\\t// eslint-disable-next-line no-unused-vars, no-restricted-syntax\\n\\t\\tfor (var _ in obj) { // jscs:ignore disallowUnusedVariables\\n\\t\\t\\treturn false;\\n\\t\\t}\\n\\t\\treturn obj.x === obj;\\n\\t} catch (e) { /* this is IE 8. */\\n\\t\\treturn false;\\n\\t}\\n};\\nvar supportsDescriptors = origDefineProperty && arePropertyDescriptorsSupported();\\n\\nvar defineProperty = function (object, name, value, predicate) {\\n\\tif (name in object && (!isFunction(predicate) || !predicate())) {\\n\\t\\treturn;\\n\\t}\\n\\tif (supportsDescriptors) {\\n\\t\\torigDefineProperty(object, name, {\\n\\t\\t\\tconfigurable: true,\\n\\t\\t\\tenumerable: false,\\n\\t\\t\\tvalue: value,\\n\\t\\t\\twritable: true\\n\\t\\t});\\n\\t} else {\\n\\t\\tobject[name] = value;\\n\\t}\\n};\\n\\nvar defineProperties = function (object, map) {\\n\\tvar predicates = arguments.length > 2 ? arguments[2] : {};\\n\\tvar props = keys(map);\\n\\tif (hasSymbols) {\\n\\t\\tprops = concat.call(props, Object.getOwnPropertySymbols(map));\\n\\t}\\n\\tfor (var i = 0; i < props.length; i += 1) {\\n\\t\\tdefineProperty(object, props[i], map[props[i]], predicates[props[i]]);\\n\\t}\\n};\\n\\ndefineProperties.supportsDescriptors = !!supportsDescriptors;\\n\\nmodule.exports = defineProperties;\\n\\n\\n//# sourceURL=webpack:///./node_modules/define-properties/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/es-abstract/GetIntrinsic.js\":\n/*!**************************************************!*\\\n  !*** ./node_modules/es-abstract/GetIntrinsic.js ***!\n  \\**************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\n/* globals\\n\\tAtomics,\\n\\tSharedArrayBuffer,\\n*/\\n\\nvar undefined;\\n\\nvar $TypeError = TypeError;\\n\\nvar $gOPD = Object.getOwnPropertyDescriptor;\\nif ($gOPD) {\\n\\ttry {\\n\\t\\t$gOPD({}, '');\\n\\t} catch (e) {\\n\\t\\t$gOPD = null; // this is IE 8, which has a broken gOPD\\n\\t}\\n}\\n\\nvar throwTypeError = function () { throw new $TypeError(); };\\nvar ThrowTypeError = $gOPD\\n\\t? (function () {\\n\\t\\ttry {\\n\\t\\t\\t// eslint-disable-next-line no-unused-expressions, no-caller, no-restricted-properties\\n\\t\\t\\targuments.callee; // IE 8 does not throw here\\n\\t\\t\\treturn throwTypeError;\\n\\t\\t} catch (calleeThrows) {\\n\\t\\t\\ttry {\\n\\t\\t\\t\\t// IE 8 throws on Object.getOwnPropertyDescriptor(arguments, '')\\n\\t\\t\\t\\treturn $gOPD(arguments, 'callee').get;\\n\\t\\t\\t} catch (gOPDthrows) {\\n\\t\\t\\t\\treturn throwTypeError;\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}())\\n\\t: throwTypeError;\\n\\nvar hasSymbols = __webpack_require__(/*! has-symbols */ \\\"./node_modules/has-symbols/index.js\\\")();\\n\\nvar getProto = Object.getPrototypeOf || function (x) { return x.__proto__; }; // eslint-disable-line no-proto\\n\\nvar generator; // = function * () {};\\nvar generatorFunction = generator ? getProto(generator) : undefined;\\nvar asyncFn; // async function() {};\\nvar asyncFunction = asyncFn ? asyncFn.constructor : undefined;\\nvar asyncGen; // async function * () {};\\nvar asyncGenFunction = asyncGen ? getProto(asyncGen) : undefined;\\nvar asyncGenIterator = asyncGen ? asyncGen() : undefined;\\n\\nvar TypedArray = typeof Uint8Array === 'undefined' ? undefined : getProto(Uint8Array);\\n\\nvar INTRINSICS = {\\n\\t'%Array%': Array,\\n\\t'%ArrayBuffer%': typeof ArrayBuffer === 'undefined' ? undefined : ArrayBuffer,\\n\\t'%ArrayBufferPrototype%': typeof ArrayBuffer === 'undefined' ? undefined : ArrayBuffer.prototype,\\n\\t'%ArrayIteratorPrototype%': hasSymbols ? getProto([][Symbol.iterator]()) : undefined,\\n\\t'%ArrayPrototype%': Array.prototype,\\n\\t'%ArrayProto_entries%': Array.prototype.entries,\\n\\t'%ArrayProto_forEach%': Array.prototype.forEach,\\n\\t'%ArrayProto_keys%': Array.prototype.keys,\\n\\t'%ArrayProto_values%': Array.prototype.values,\\n\\t'%AsyncFromSyncIteratorPrototype%': undefined,\\n\\t'%AsyncFunction%': asyncFunction,\\n\\t'%AsyncFunctionPrototype%': asyncFunction ? asyncFunction.prototype : undefined,\\n\\t'%AsyncGenerator%': asyncGen ? getProto(asyncGenIterator) : undefined,\\n\\t'%AsyncGeneratorFunction%': asyncGenFunction,\\n\\t'%AsyncGeneratorPrototype%': asyncGenFunction ? asyncGenFunction.prototype : undefined,\\n\\t'%AsyncIteratorPrototype%': asyncGenIterator && hasSymbols && Symbol.asyncIterator ? asyncGenIterator[Symbol.asyncIterator]() : undefined,\\n\\t'%Atomics%': typeof Atomics === 'undefined' ? undefined : Atomics,\\n\\t'%Boolean%': Boolean,\\n\\t'%BooleanPrototype%': Boolean.prototype,\\n\\t'%DataView%': typeof DataView === 'undefined' ? undefined : DataView,\\n\\t'%DataViewPrototype%': typeof DataView === 'undefined' ? undefined : DataView.prototype,\\n\\t'%Date%': Date,\\n\\t'%DatePrototype%': Date.prototype,\\n\\t'%decodeURI%': decodeURI,\\n\\t'%decodeURIComponent%': decodeURIComponent,\\n\\t'%encodeURI%': encodeURI,\\n\\t'%encodeURIComponent%': encodeURIComponent,\\n\\t'%Error%': Error,\\n\\t'%ErrorPrototype%': Error.prototype,\\n\\t'%eval%': eval, // eslint-disable-line no-eval\\n\\t'%EvalError%': EvalError,\\n\\t'%EvalErrorPrototype%': EvalError.prototype,\\n\\t'%Float32Array%': typeof Float32Array === 'undefined' ? undefined : Float32Array,\\n\\t'%Float32ArrayPrototype%': typeof Float32Array === 'undefined' ? undefined : Float32Array.prototype,\\n\\t'%Float64Array%': typeof Float64Array === 'undefined' ? undefined : Float64Array,\\n\\t'%Float64ArrayPrototype%': typeof Float64Array === 'undefined' ? undefined : Float64Array.prototype,\\n\\t'%Function%': Function,\\n\\t'%FunctionPrototype%': Function.prototype,\\n\\t'%Generator%': generator ? getProto(generator()) : undefined,\\n\\t'%GeneratorFunction%': generatorFunction,\\n\\t'%GeneratorPrototype%': generatorFunction ? generatorFunction.prototype : undefined,\\n\\t'%Int8Array%': typeof Int8Array === 'undefined' ? undefined : Int8Array,\\n\\t'%Int8ArrayPrototype%': typeof Int8Array === 'undefined' ? undefined : Int8Array.prototype,\\n\\t'%Int16Array%': typeof Int16Array === 'undefined' ? undefined : Int16Array,\\n\\t'%Int16ArrayPrototype%': typeof Int16Array === 'undefined' ? undefined : Int8Array.prototype,\\n\\t'%Int32Array%': typeof Int32Array === 'undefined' ? undefined : Int32Array,\\n\\t'%Int32ArrayPrototype%': typeof Int32Array === 'undefined' ? undefined : Int32Array.prototype,\\n\\t'%isFinite%': isFinite,\\n\\t'%isNaN%': isNaN,\\n\\t'%IteratorPrototype%': hasSymbols ? getProto(getProto([][Symbol.iterator]())) : undefined,\\n\\t'%JSON%': typeof JSON === 'object' ? JSON : undefined,\\n\\t'%JSONParse%': typeof JSON === 'object' ? JSON.parse : undefined,\\n\\t'%Map%': typeof Map === 'undefined' ? undefined : Map,\\n\\t'%MapIteratorPrototype%': typeof Map === 'undefined' || !hasSymbols ? undefined : getProto(new Map()[Symbol.iterator]()),\\n\\t'%MapPrototype%': typeof Map === 'undefined' ? undefined : Map.prototype,\\n\\t'%Math%': Math,\\n\\t'%Number%': Number,\\n\\t'%NumberPrototype%': Number.prototype,\\n\\t'%Object%': Object,\\n\\t'%ObjectPrototype%': Object.prototype,\\n\\t'%ObjProto_toString%': Object.prototype.toString,\\n\\t'%ObjProto_valueOf%': Object.prototype.valueOf,\\n\\t'%parseFloat%': parseFloat,\\n\\t'%parseInt%': parseInt,\\n\\t'%Promise%': typeof Promise === 'undefined' ? undefined : Promise,\\n\\t'%PromisePrototype%': typeof Promise === 'undefined' ? undefined : Promise.prototype,\\n\\t'%PromiseProto_then%': typeof Promise === 'undefined' ? undefined : Promise.prototype.then,\\n\\t'%Promise_all%': typeof Promise === 'undefined' ? undefined : Promise.all,\\n\\t'%Promise_reject%': typeof Promise === 'undefined' ? undefined : Promise.reject,\\n\\t'%Promise_resolve%': typeof Promise === 'undefined' ? undefined : Promise.resolve,\\n\\t'%Proxy%': typeof Proxy === 'undefined' ? undefined : Proxy,\\n\\t'%RangeError%': RangeError,\\n\\t'%RangeErrorPrototype%': RangeError.prototype,\\n\\t'%ReferenceError%': ReferenceError,\\n\\t'%ReferenceErrorPrototype%': ReferenceError.prototype,\\n\\t'%Reflect%': typeof Reflect === 'undefined' ? undefined : Reflect,\\n\\t'%RegExp%': RegExp,\\n\\t'%RegExpPrototype%': RegExp.prototype,\\n\\t'%Set%': typeof Set === 'undefined' ? undefined : Set,\\n\\t'%SetIteratorPrototype%': typeof Set === 'undefined' || !hasSymbols ? undefined : getProto(new Set()[Symbol.iterator]()),\\n\\t'%SetPrototype%': typeof Set === 'undefined' ? undefined : Set.prototype,\\n\\t'%SharedArrayBuffer%': typeof SharedArrayBuffer === 'undefined' ? undefined : SharedArrayBuffer,\\n\\t'%SharedArrayBufferPrototype%': typeof SharedArrayBuffer === 'undefined' ? undefined : SharedArrayBuffer.prototype,\\n\\t'%String%': String,\\n\\t'%StringIteratorPrototype%': hasSymbols ? getProto(''[Symbol.iterator]()) : undefined,\\n\\t'%StringPrototype%': String.prototype,\\n\\t'%Symbol%': hasSymbols ? Symbol : undefined,\\n\\t'%SymbolPrototype%': hasSymbols ? Symbol.prototype : undefined,\\n\\t'%SyntaxError%': SyntaxError,\\n\\t'%SyntaxErrorPrototype%': SyntaxError.prototype,\\n\\t'%ThrowTypeError%': ThrowTypeError,\\n\\t'%TypedArray%': TypedArray,\\n\\t'%TypedArrayPrototype%': TypedArray ? TypedArray.prototype : undefined,\\n\\t'%TypeError%': $TypeError,\\n\\t'%TypeErrorPrototype%': $TypeError.prototype,\\n\\t'%Uint8Array%': typeof Uint8Array === 'undefined' ? undefined : Uint8Array,\\n\\t'%Uint8ArrayPrototype%': typeof Uint8Array === 'undefined' ? undefined : Uint8Array.prototype,\\n\\t'%Uint8ClampedArray%': typeof Uint8ClampedArray === 'undefined' ? undefined : Uint8ClampedArray,\\n\\t'%Uint8ClampedArrayPrototype%': typeof Uint8ClampedArray === 'undefined' ? undefined : Uint8ClampedArray.prototype,\\n\\t'%Uint16Array%': typeof Uint16Array === 'undefined' ? undefined : Uint16Array,\\n\\t'%Uint16ArrayPrototype%': typeof Uint16Array === 'undefined' ? undefined : Uint16Array.prototype,\\n\\t'%Uint32Array%': typeof Uint32Array === 'undefined' ? undefined : Uint32Array,\\n\\t'%Uint32ArrayPrototype%': typeof Uint32Array === 'undefined' ? undefined : Uint32Array.prototype,\\n\\t'%URIError%': URIError,\\n\\t'%URIErrorPrototype%': URIError.prototype,\\n\\t'%WeakMap%': typeof WeakMap === 'undefined' ? undefined : WeakMap,\\n\\t'%WeakMapPrototype%': typeof WeakMap === 'undefined' ? undefined : WeakMap.prototype,\\n\\t'%WeakSet%': typeof WeakSet === 'undefined' ? undefined : WeakSet,\\n\\t'%WeakSetPrototype%': typeof WeakSet === 'undefined' ? undefined : WeakSet.prototype\\n};\\n\\nvar bind = __webpack_require__(/*! function-bind */ \\\"./node_modules/function-bind/index.js\\\");\\nvar $replace = bind.call(Function.call, String.prototype.replace);\\n\\n/* adapted from https://github.com/lodash/lodash/blob/4.17.15/dist/lodash.js#L6735-L6744 */\\nvar rePropName = /[^%.[\\\\]]+|\\\\[(?:(-?\\\\d+(?:\\\\.\\\\d+)?)|([\\\"'])((?:(?!\\\\2)[^\\\\\\\\]|\\\\\\\\.)*?)\\\\2)\\\\]|(?=(?:\\\\.|\\\\[\\\\])(?:\\\\.|\\\\[\\\\]|%$))/g;\\nvar reEscapeChar = /\\\\\\\\(\\\\\\\\)?/g; /** Used to match backslashes in property paths. */\\nvar stringToPath = function stringToPath(string) {\\n\\tvar result = [];\\n\\t$replace(string, rePropName, function (match, number, quote, subString) {\\n\\t\\tresult[result.length] = quote ? $replace(subString, reEscapeChar, '$1') : (number || match);\\n\\t});\\n\\treturn result;\\n};\\n/* end adaptation */\\n\\nvar getBaseIntrinsic = function getBaseIntrinsic(name, allowMissing) {\\n\\tif (!(name in INTRINSICS)) {\\n\\t\\tthrow new SyntaxError('intrinsic ' + name + ' does not exist!');\\n\\t}\\n\\n\\t// istanbul ignore if // hopefully this is impossible to test :-)\\n\\tif (typeof INTRINSICS[name] === 'undefined' && !allowMissing) {\\n\\t\\tthrow new $TypeError('intrinsic ' + name + ' exists, but is not available. Please file an issue!');\\n\\t}\\n\\n\\treturn INTRINSICS[name];\\n};\\n\\nmodule.exports = function GetIntrinsic(name, allowMissing) {\\n\\tif (typeof name !== 'string' || name.length === 0) {\\n\\t\\tthrow new TypeError('intrinsic name must be a non-empty string');\\n\\t}\\n\\tif (arguments.length > 1 && typeof allowMissing !== 'boolean') {\\n\\t\\tthrow new TypeError('\\\"allowMissing\\\" argument must be a boolean');\\n\\t}\\n\\n\\tvar parts = stringToPath(name);\\n\\n\\tvar value = getBaseIntrinsic('%' + (parts.length > 0 ? parts[0] : '') + '%', allowMissing);\\n\\tfor (var i = 1; i < parts.length; i += 1) {\\n\\t\\tif (value != null) {\\n\\t\\t\\tif ($gOPD && (i + 1) >= parts.length) {\\n\\t\\t\\t\\tvar desc = $gOPD(value, parts[i]);\\n\\t\\t\\t\\tif (!allowMissing && !(parts[i] in value)) {\\n\\t\\t\\t\\t\\tthrow new $TypeError('base intrinsic for ' + name + ' exists, but the property is not available.');\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tvalue = desc ? (desc.get || desc.value) : value[parts[i]];\\n\\t\\t\\t} else {\\n\\t\\t\\t\\tvalue = value[parts[i]];\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n\\treturn value;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/es-abstract/GetIntrinsic.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/es-abstract/helpers/callBind.js\":\n/*!******************************************************!*\\\n  !*** ./node_modules/es-abstract/helpers/callBind.js ***!\n  \\******************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar bind = __webpack_require__(/*! function-bind */ \\\"./node_modules/function-bind/index.js\\\");\\n\\nvar GetIntrinsic = __webpack_require__(/*! ../GetIntrinsic */ \\\"./node_modules/es-abstract/GetIntrinsic.js\\\");\\n\\nvar $apply = GetIntrinsic('%Function.prototype.apply%');\\nvar $call = GetIntrinsic('%Function.prototype.call%');\\nvar $reflectApply = GetIntrinsic('%Reflect.apply%', true) || bind.call($call, $apply);\\n\\nmodule.exports = function callBind() {\\n\\treturn $reflectApply(bind, $call, arguments);\\n};\\n\\nmodule.exports.apply = function applyBind() {\\n\\treturn $reflectApply(bind, $apply, arguments);\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/es-abstract/helpers/callBind.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/es-abstract/helpers/callBound.js\":\n/*!*******************************************************!*\\\n  !*** ./node_modules/es-abstract/helpers/callBound.js ***!\n  \\*******************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar GetIntrinsic = __webpack_require__(/*! ../GetIntrinsic */ \\\"./node_modules/es-abstract/GetIntrinsic.js\\\");\\n\\nvar callBind = __webpack_require__(/*! ./callBind */ \\\"./node_modules/es-abstract/helpers/callBind.js\\\");\\n\\nvar $indexOf = callBind(GetIntrinsic('String.prototype.indexOf'));\\n\\nmodule.exports = function callBoundIntrinsic(name, allowMissing) {\\n\\tvar intrinsic = GetIntrinsic(name, !!allowMissing);\\n\\tif (typeof intrinsic === 'function' && $indexOf(name, '.prototype.')) {\\n\\t\\treturn callBind(intrinsic);\\n\\t}\\n\\treturn intrinsic;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/es-abstract/helpers/callBound.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/es-abstract/helpers/getOwnPropertyDescriptor.js\":\n/*!**********************************************************************!*\\\n  !*** ./node_modules/es-abstract/helpers/getOwnPropertyDescriptor.js ***!\n  \\**********************************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar GetIntrinsic = __webpack_require__(/*! ../GetIntrinsic */ \\\"./node_modules/es-abstract/GetIntrinsic.js\\\");\\n\\nvar $gOPD = GetIntrinsic('%Object.getOwnPropertyDescriptor%');\\nif ($gOPD) {\\n\\ttry {\\n\\t\\t$gOPD([], 'length');\\n\\t} catch (e) {\\n\\t\\t// IE 8 has a broken gOPD\\n\\t\\t$gOPD = null;\\n\\t}\\n}\\n\\nmodule.exports = $gOPD;\\n\\n\\n//# sourceURL=webpack:///./node_modules/es-abstract/helpers/getOwnPropertyDescriptor.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/es-get-iterator/index.js\":\n/*!***********************************************!*\\\n  !*** ./node_modules/es-get-iterator/index.js ***!\n  \\***********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"/* WEBPACK VAR INJECTION */(function(process) {\\n\\n/* eslint global-require: 0 */\\n// the code is structured this way so that bundlers can\\n// alias out `has-symbols` to `() => true` or `() => false` if your target\\n// environments' Symbol capabilities are known, and then use\\n// dead code elimination on the rest of this module.\\n//\\n// Similarly, `isarray` can be aliased to `Array.isArray` if\\n// available in all target environments.\\n\\nvar isArguments = __webpack_require__(/*! is-arguments */ \\\"./node_modules/is-arguments/index.js\\\");\\n\\nif (__webpack_require__(/*! has-symbols */ \\\"./node_modules/has-symbols/index.js\\\")() || __webpack_require__(/*! has-symbols/shams */ \\\"./node_modules/has-symbols/shams.js\\\")()) {\\n\\tvar $iterator = Symbol.iterator;\\n\\t// Symbol is available natively or shammed\\n\\t// natively:\\n\\t//  - Chrome >= 38\\n\\t//  - Edge 12-14?, Edge >= 15 for sure\\n\\t//  - FF >= 36\\n\\t//  - Safari >= 9\\n\\t//  - node >= 0.12\\n\\tmodule.exports = function getIterator(iterable) {\\n\\t\\t// alternatively, `iterable[$iterator]?.()`\\n\\t\\tif (iterable != null && typeof iterable[$iterator] !== 'undefined') {\\n\\t\\t\\treturn iterable[$iterator]();\\n\\t\\t}\\n\\t\\tif (isArguments(iterable)) {\\n\\t\\t\\t// arguments objects lack Symbol.iterator\\n\\t\\t\\t// - node 0.12\\n\\t\\t\\treturn Array.prototype[$iterator].call(iterable);\\n\\t\\t}\\n\\t};\\n} else {\\n\\t// Symbol is not available, native or shammed\\n\\tvar isArray = __webpack_require__(/*! isarray */ \\\"./node_modules/es-get-iterator/node_modules/isarray/index.js\\\");\\n\\tvar isString = __webpack_require__(/*! is-string */ \\\"./node_modules/is-string/index.js\\\");\\n\\tvar GetIntrinsic = __webpack_require__(/*! es-abstract/GetIntrinsic */ \\\"./node_modules/es-abstract/GetIntrinsic.js\\\");\\n\\tvar $Map = GetIntrinsic('%Map%', true);\\n\\tvar $Set = GetIntrinsic('%Set%', true);\\n\\tvar callBound = __webpack_require__(/*! es-abstract/helpers/callBound */ \\\"./node_modules/es-abstract/helpers/callBound.js\\\");\\n\\tvar $arrayPush = callBound('Array.prototype.push');\\n\\tvar $charCodeAt = callBound('String.prototype.charCodeAt');\\n\\tvar $stringSlice = callBound('String.prototype.slice');\\n\\n\\tvar advanceStringIndex = function advanceStringIndex(S, index) {\\n\\t\\tvar length = S.length;\\n\\t\\tif ((index + 1) >= length) {\\n\\t\\t\\treturn index + 1;\\n\\t\\t}\\n\\n\\t\\tvar first = $charCodeAt(S, index);\\n\\t\\tif (first < 0xD800 || first > 0xDBFF) {\\n\\t\\t\\treturn index + 1;\\n\\t\\t}\\n\\n\\t\\tvar second = $charCodeAt(S, index + 1);\\n\\t\\tif (second < 0xDC00 || second > 0xDFFF) {\\n\\t\\t\\treturn index + 1;\\n\\t\\t}\\n\\n\\t\\treturn index + 2;\\n\\t};\\n\\n\\tvar getArrayIterator = function getArrayIterator(arraylike) {\\n\\t\\tvar i = 0;\\n\\t\\treturn {\\n\\t\\t\\tnext: function next() {\\n\\t\\t\\t\\tvar done = i >= arraylike.length;\\n\\t\\t\\t\\tvar value;\\n\\t\\t\\t\\tif (!done) {\\n\\t\\t\\t\\t\\tvalue = arraylike[i];\\n\\t\\t\\t\\t\\ti += 1;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\treturn {\\n\\t\\t\\t\\t\\tdone: done,\\n\\t\\t\\t\\t\\tvalue: value\\n\\t\\t\\t\\t};\\n\\t\\t\\t}\\n\\t\\t};\\n\\t};\\n\\n\\tvar getNonCollectionIterator = function getNonCollectionIterator(iterable) {\\n\\t\\tif (isArray(iterable) || isArguments(iterable)) {\\n\\t\\t\\treturn getArrayIterator(iterable);\\n\\t\\t}\\n\\t\\tif (isString(iterable)) {\\n\\t\\t\\tvar i = 0;\\n\\t\\t\\treturn {\\n\\t\\t\\t\\tnext: function next() {\\n\\t\\t\\t\\t\\tvar nextIndex = advanceStringIndex(iterable, i);\\n\\t\\t\\t\\t\\tvar value = $stringSlice(iterable, i, nextIndex);\\n\\t\\t\\t\\t\\ti = nextIndex;\\n\\t\\t\\t\\t\\treturn {\\n\\t\\t\\t\\t\\t\\tdone: nextIndex > iterable.length,\\n\\t\\t\\t\\t\\t\\tvalue: value\\n\\t\\t\\t\\t\\t};\\n\\t\\t\\t\\t}\\n\\t\\t\\t};\\n\\t\\t}\\n\\t};\\n\\n\\tif (!$Map && !$Set) {\\n\\t\\t// the only language iterables are Array, String, arguments\\n\\t\\t// - Safari <= 6.0\\n\\t\\t// - Chrome < 38\\n\\t\\t// - node < 0.12\\n\\t\\t// - FF < 13\\n\\t\\t// - IE < 11\\n\\t\\t// - Edge < 11\\n\\n\\t\\tmodule.exports = getNonCollectionIterator;\\n\\t} else {\\n\\t\\t// either Map or Set are available, but Symbol is not\\n\\t\\t// - es6-shim on an ES5 browser\\n\\t\\t// - Safari 6.2 (maybe 6.1?)\\n\\t\\t// - FF v[13, 36)\\n\\t\\t// - IE 11\\n\\t\\t// - Edge 11\\n\\t\\t// - Safari v[6, 9)\\n\\n\\t\\tvar isMap = __webpack_require__(/*! is-map */ \\\"./node_modules/is-map/index.js\\\");\\n\\t\\tvar isSet = __webpack_require__(/*! is-set */ \\\"./node_modules/is-set/index.js\\\");\\n\\n\\t\\t// Firefox >= 27, IE 11, Safari 6.2 - 9, Edge 11, es6-shim in older envs, all have forEach\\n\\t\\tvar $mapForEach = callBound('Map.prototype.forEach', true);\\n\\t\\tvar $setForEach = callBound('Set.prototype.forEach', true);\\n\\t\\tif (typeof process === 'undefined' || !process.versions || !process.versions.node) { // \\\"if is not node\\\"\\n\\n\\t\\t\\t// Firefox 17 - 26 has `.iterator()`, whose iterator `.next()` either\\n\\t\\t\\t// returns a value, or throws a StopIteration object. These browsers\\n\\t\\t\\t// do not have any other mechanism for iteration.\\n\\t\\t\\tvar $mapIterator = callBound('Map.prototype.iterator', true);\\n\\t\\t\\tvar $setIterator = callBound('Set.prototype.iterator', true);\\n\\t\\t\\tvar getStopIterationIterator = function (iterator) {\\n\\t\\t\\t\\tvar done = false;\\n\\t\\t\\t\\treturn {\\n\\t\\t\\t\\t\\tnext: function next() {\\n\\t\\t\\t\\t\\t\\ttry {\\n\\t\\t\\t\\t\\t\\t\\treturn {\\n\\t\\t\\t\\t\\t\\t\\t\\tdone: done,\\n\\t\\t\\t\\t\\t\\t\\t\\tvalue: done ? undefined : iterator.next()\\n\\t\\t\\t\\t\\t\\t\\t};\\n\\t\\t\\t\\t\\t\\t} catch (e) {\\n\\t\\t\\t\\t\\t\\t\\tdone = true;\\n\\t\\t\\t\\t\\t\\t\\treturn {\\n\\t\\t\\t\\t\\t\\t\\t\\tdone: true,\\n\\t\\t\\t\\t\\t\\t\\t\\tvalue: undefined\\n\\t\\t\\t\\t\\t\\t\\t};\\n\\t\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t};\\n\\t\\t\\t};\\n\\t\\t}\\n\\t\\t// Firefox 27-35, and some older es6-shim versions, use a string \\\"@@iterator\\\" property\\n\\t\\t// this returns a proper iterator object, so we should use it instead of forEach.\\n\\t\\t// newer es6-shim versions use a string \\\"_es6-shim iterator_\\\" property.\\n\\t\\tvar $mapAtAtIterator = callBound('Map.prototype.@@iterator', true) || callBound('Map.prototype._es6-shim iterator_', true);\\n\\t\\tvar $setAtAtIterator = callBound('Set.prototype.@@iterator', true) || callBound('Set.prototype._es6-shim iterator_', true);\\n\\n\\t\\tvar getCollectionIterator = function getCollectionIterator(iterable) {\\n\\t\\t\\tif (isMap(iterable)) {\\n\\t\\t\\t\\tif ($mapIterator) {\\n\\t\\t\\t\\t\\treturn getStopIterationIterator($mapIterator(iterable));\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif ($mapAtAtIterator) {\\n\\t\\t\\t\\t\\treturn $mapAtAtIterator(iterable);\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif ($mapForEach) {\\n\\t\\t\\t\\t\\tvar entries = [];\\n\\t\\t\\t\\t\\t$mapForEach(iterable, function (v, k) {\\n\\t\\t\\t\\t\\t\\t$arrayPush(entries, [k, v]);\\n\\t\\t\\t\\t\\t});\\n\\t\\t\\t\\t\\treturn getArrayIterator(entries);\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t\\tif (isSet(iterable)) {\\n\\t\\t\\t\\tif ($setIterator) {\\n\\t\\t\\t\\t\\treturn getStopIterationIterator($setIterator(iterable));\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif ($setAtAtIterator) {\\n\\t\\t\\t\\t\\treturn $setAtAtIterator(iterable);\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif ($setForEach) {\\n\\t\\t\\t\\t\\tvar values = [];\\n\\t\\t\\t\\t\\t$setForEach(iterable, function (v) {\\n\\t\\t\\t\\t\\t\\t$arrayPush(values, v);\\n\\t\\t\\t\\t\\t});\\n\\t\\t\\t\\t\\treturn getArrayIterator(values);\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t};\\n\\n\\t\\tmodule.exports = function getIterator(iterable) {\\n\\t\\t\\treturn getCollectionIterator(iterable) || getNonCollectionIterator(iterable);\\n\\t\\t};\\n\\t}\\n}\\n\\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../process/browser.js */ \\\"./node_modules/process/browser.js\\\")))\\n\\n//# sourceURL=webpack:///./node_modules/es-get-iterator/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/es-get-iterator/node_modules/isarray/index.js\":\n/*!********************************************************************!*\\\n  !*** ./node_modules/es-get-iterator/node_modules/isarray/index.js ***!\n  \\********************************************************************/\n/*! no static exports found */\n/***/ (function(module, exports) {\n\neval(\"var toString = {}.toString;\\n\\nmodule.exports = Array.isArray || function (arr) {\\n  return toString.call(arr) == '[object Array]';\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/es-get-iterator/node_modules/isarray/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/foreach/index.js\":\n/*!***************************************!*\\\n  !*** ./node_modules/foreach/index.js ***!\n  \\***************************************/\n/*! no static exports found */\n/***/ (function(module, exports) {\n\neval(\"\\nvar hasOwn = Object.prototype.hasOwnProperty;\\nvar toString = Object.prototype.toString;\\n\\nmodule.exports = function forEach (obj, fn, ctx) {\\n    if (toString.call(fn) !== '[object Function]') {\\n        throw new TypeError('iterator must be a function');\\n    }\\n    var l = obj.length;\\n    if (l === +l) {\\n        for (var i = 0; i < l; i++) {\\n            fn.call(ctx, obj[i], i, obj);\\n        }\\n    } else {\\n        for (var k in obj) {\\n            if (hasOwn.call(obj, k)) {\\n                fn.call(ctx, obj[k], k, obj);\\n            }\\n        }\\n    }\\n};\\n\\n\\n\\n//# sourceURL=webpack:///./node_modules/foreach/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/function-bind/implementation.js\":\n/*!******************************************************!*\\\n  !*** ./node_modules/function-bind/implementation.js ***!\n  \\******************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\n/* eslint no-invalid-this: 1 */\\n\\nvar ERROR_MESSAGE = 'Function.prototype.bind called on incompatible ';\\nvar slice = Array.prototype.slice;\\nvar toStr = Object.prototype.toString;\\nvar funcType = '[object Function]';\\n\\nmodule.exports = function bind(that) {\\n    var target = this;\\n    if (typeof target !== 'function' || toStr.call(target) !== funcType) {\\n        throw new TypeError(ERROR_MESSAGE + target);\\n    }\\n    var args = slice.call(arguments, 1);\\n\\n    var bound;\\n    var binder = function () {\\n        if (this instanceof bound) {\\n            var result = target.apply(\\n                this,\\n                args.concat(slice.call(arguments))\\n            );\\n            if (Object(result) === result) {\\n                return result;\\n            }\\n            return this;\\n        } else {\\n            return target.apply(\\n                that,\\n                args.concat(slice.call(arguments))\\n            );\\n        }\\n    };\\n\\n    var boundLength = Math.max(0, target.length - args.length);\\n    var boundArgs = [];\\n    for (var i = 0; i < boundLength; i++) {\\n        boundArgs.push('$' + i);\\n    }\\n\\n    bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder);\\n\\n    if (target.prototype) {\\n        var Empty = function Empty() {};\\n        Empty.prototype = target.prototype;\\n        bound.prototype = new Empty();\\n        Empty.prototype = null;\\n    }\\n\\n    return bound;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/function-bind/implementation.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/function-bind/index.js\":\n/*!*********************************************!*\\\n  !*** ./node_modules/function-bind/index.js ***!\n  \\*********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar implementation = __webpack_require__(/*! ./implementation */ \\\"./node_modules/function-bind/implementation.js\\\");\\n\\nmodule.exports = Function.prototype.bind || implementation;\\n\\n\\n//# sourceURL=webpack:///./node_modules/function-bind/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/has-symbols/index.js\":\n/*!*******************************************!*\\\n  !*** ./node_modules/has-symbols/index.js ***!\n  \\*******************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"/* WEBPACK VAR INJECTION */(function(global) {\\n\\nvar origSymbol = global.Symbol;\\nvar hasSymbolSham = __webpack_require__(/*! ./shams */ \\\"./node_modules/has-symbols/shams.js\\\");\\n\\nmodule.exports = function hasNativeSymbols() {\\n\\tif (typeof origSymbol !== 'function') { return false; }\\n\\tif (typeof Symbol !== 'function') { return false; }\\n\\tif (typeof origSymbol('foo') !== 'symbol') { return false; }\\n\\tif (typeof Symbol('bar') !== 'symbol') { return false; }\\n\\n\\treturn hasSymbolSham();\\n};\\n\\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../webpack/buildin/global.js */ \\\"./node_modules/webpack/buildin/global.js\\\")))\\n\\n//# sourceURL=webpack:///./node_modules/has-symbols/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/has-symbols/shams.js\":\n/*!*******************************************!*\\\n  !*** ./node_modules/has-symbols/shams.js ***!\n  \\*******************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\n/* eslint complexity: [2, 18], max-statements: [2, 33] */\\nmodule.exports = function hasSymbols() {\\n\\tif (typeof Symbol !== 'function' || typeof Object.getOwnPropertySymbols !== 'function') { return false; }\\n\\tif (typeof Symbol.iterator === 'symbol') { return true; }\\n\\n\\tvar obj = {};\\n\\tvar sym = Symbol('test');\\n\\tvar symObj = Object(sym);\\n\\tif (typeof sym === 'string') { return false; }\\n\\n\\tif (Object.prototype.toString.call(sym) !== '[object Symbol]') { return false; }\\n\\tif (Object.prototype.toString.call(symObj) !== '[object Symbol]') { return false; }\\n\\n\\t// temp disabled per https://github.com/ljharb/object.assign/issues/17\\n\\t// if (sym instanceof Symbol) { return false; }\\n\\t// temp disabled per https://github.com/WebReflection/get-own-property-symbols/issues/4\\n\\t// if (!(symObj instanceof Symbol)) { return false; }\\n\\n\\t// if (typeof Symbol.prototype.toString !== 'function') { return false; }\\n\\t// if (String(sym) !== Symbol.prototype.toString.call(sym)) { return false; }\\n\\n\\tvar symVal = 42;\\n\\tobj[sym] = symVal;\\n\\tfor (sym in obj) { return false; } // eslint-disable-line no-restricted-syntax\\n\\tif (typeof Object.keys === 'function' && Object.keys(obj).length !== 0) { return false; }\\n\\n\\tif (typeof Object.getOwnPropertyNames === 'function' && Object.getOwnPropertyNames(obj).length !== 0) { return false; }\\n\\n\\tvar syms = Object.getOwnPropertySymbols(obj);\\n\\tif (syms.length !== 1 || syms[0] !== sym) { return false; }\\n\\n\\tif (!Object.prototype.propertyIsEnumerable.call(obj, sym)) { return false; }\\n\\n\\tif (typeof Object.getOwnPropertyDescriptor === 'function') {\\n\\t\\tvar descriptor = Object.getOwnPropertyDescriptor(obj, sym);\\n\\t\\tif (descriptor.value !== symVal || descriptor.enumerable !== true) { return false; }\\n\\t}\\n\\n\\treturn true;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/has-symbols/shams.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/is-arguments/index.js\":\n/*!********************************************!*\\\n  !*** ./node_modules/is-arguments/index.js ***!\n  \\********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol';\\nvar toStr = Object.prototype.toString;\\n\\nvar isStandardArguments = function isArguments(value) {\\n\\tif (hasToStringTag && value && typeof value === 'object' && Symbol.toStringTag in value) {\\n\\t\\treturn false;\\n\\t}\\n\\treturn toStr.call(value) === '[object Arguments]';\\n};\\n\\nvar isLegacyArguments = function isArguments(value) {\\n\\tif (isStandardArguments(value)) {\\n\\t\\treturn true;\\n\\t}\\n\\treturn value !== null &&\\n\\t\\ttypeof value === 'object' &&\\n\\t\\ttypeof value.length === 'number' &&\\n\\t\\tvalue.length >= 0 &&\\n\\t\\ttoStr.call(value) !== '[object Array]' &&\\n\\t\\ttoStr.call(value.callee) === '[object Function]';\\n};\\n\\nvar supportsStandardArguments = (function () {\\n\\treturn isStandardArguments(arguments);\\n}());\\n\\nisStandardArguments.isLegacyArguments = isLegacyArguments; // for tests\\n\\nmodule.exports = supportsStandardArguments ? isStandardArguments : isLegacyArguments;\\n\\n\\n//# sourceURL=webpack:///./node_modules/is-arguments/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/is-arrayish/index.js\":\n/*!*******************************************!*\\\n  !*** ./node_modules/is-arrayish/index.js ***!\n  \\*******************************************/\n/*! no static exports found */\n/***/ (function(module, exports) {\n\neval(\"module.exports = function isArrayish(obj) {\\n\\tif (!obj || typeof obj === 'string') {\\n\\t\\treturn false;\\n\\t}\\n\\n\\treturn obj instanceof Array || Array.isArray(obj) ||\\n\\t\\t(obj.length >= 0 && (obj.splice instanceof Function ||\\n\\t\\t\\t(Object.getOwnPropertyDescriptor(obj, (obj.length - 1)) && obj.constructor.name !== 'String')));\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/is-arrayish/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/is-bigint/index.js\":\n/*!*****************************************!*\\\n  !*** ./node_modules/is-bigint/index.js ***!\n  \\*****************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nif (typeof BigInt === 'function') {\\n\\tvar bigIntValueOf = BigInt.prototype.valueOf;\\n\\tvar tryBigInt = function tryBigIntObject(value) {\\n\\t\\ttry {\\n\\t\\t\\tbigIntValueOf.call(value);\\n\\t\\t\\treturn true;\\n\\t\\t} catch (e) {\\n\\t\\t}\\n\\t\\treturn false;\\n\\t};\\n\\n\\tmodule.exports = function isBigInt(value) {\\n\\t\\tif (\\n\\t\\t\\tvalue === null\\n\\t\\t\\t|| typeof value === 'undefined'\\n\\t\\t\\t|| typeof value === 'boolean'\\n\\t\\t\\t|| typeof value === 'string'\\n\\t\\t\\t|| typeof value === 'number'\\n\\t\\t\\t|| typeof value === 'symbol'\\n\\t\\t\\t|| typeof value === 'function'\\n\\t\\t) {\\n\\t\\t\\treturn false;\\n\\t\\t}\\n\\t\\tif (typeof value === 'bigint') { // eslint-disable-line valid-typeof\\n\\t\\t\\treturn true;\\n\\t\\t}\\n\\n\\t\\treturn tryBigInt(value);\\n\\t};\\n} else {\\n\\tmodule.exports = function isBigInt(value) {\\n\\t\\treturn  false && false;\\n\\t};\\n}\\n\\n\\n//# sourceURL=webpack:///./node_modules/is-bigint/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/is-boolean-object/index.js\":\n/*!*************************************************!*\\\n  !*** ./node_modules/is-boolean-object/index.js ***!\n  \\*************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar boolToStr = Boolean.prototype.toString;\\n\\nvar tryBooleanObject = function booleanBrandCheck(value) {\\n\\ttry {\\n\\t\\tboolToStr.call(value);\\n\\t\\treturn true;\\n\\t} catch (e) {\\n\\t\\treturn false;\\n\\t}\\n};\\nvar toStr = Object.prototype.toString;\\nvar boolClass = '[object Boolean]';\\nvar hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol';\\n\\nmodule.exports = function isBoolean(value) {\\n\\tif (typeof value === 'boolean') {\\n\\t\\treturn true;\\n\\t}\\n\\tif (value === null || typeof value !== 'object') {\\n\\t\\treturn false;\\n\\t}\\n\\treturn hasToStringTag && Symbol.toStringTag in value ? tryBooleanObject(value) : toStr.call(value) === boolClass;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/is-boolean-object/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/is-date-object/index.js\":\n/*!**********************************************!*\\\n  !*** ./node_modules/is-date-object/index.js ***!\n  \\**********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar getDay = Date.prototype.getDay;\\nvar tryDateObject = function tryDateGetDayCall(value) {\\n\\ttry {\\n\\t\\tgetDay.call(value);\\n\\t\\treturn true;\\n\\t} catch (e) {\\n\\t\\treturn false;\\n\\t}\\n};\\n\\nvar toStr = Object.prototype.toString;\\nvar dateClass = '[object Date]';\\nvar hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol';\\n\\nmodule.exports = function isDateObject(value) {\\n\\tif (typeof value !== 'object' || value === null) {\\n\\t\\treturn false;\\n\\t}\\n\\treturn hasToStringTag ? tryDateObject(value) : toStr.call(value) === dateClass;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/is-date-object/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/is-map/index.js\":\n/*!**************************************!*\\\n  !*** ./node_modules/is-map/index.js ***!\n  \\**************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar $Map = typeof Map === 'function' && Map.prototype ? Map : null;\\nvar $Set = typeof Set === 'function' && Set.prototype ? Set : null;\\n\\nvar exported;\\n\\nif (!$Map) {\\n\\t// eslint-disable-next-line no-unused-vars\\n\\texported = function isMap(x) {\\n\\t\\t// `Map` is not present in this environment.\\n\\t\\treturn false;\\n\\t};\\n}\\n\\nvar $mapHas = $Map ? Map.prototype.has : null;\\nvar $setHas = $Set ? Set.prototype.has : null;\\nif (!exported && !$mapHas) {\\n\\t// eslint-disable-next-line no-unused-vars\\n\\texported = function isMap(x) {\\n\\t\\t// `Map` does not have a `has` method\\n\\t\\treturn false;\\n\\t};\\n}\\n\\nmodule.exports = exported || function isMap(x) {\\n\\tif (!x || typeof x !== 'object') {\\n\\t\\treturn false;\\n\\t}\\n\\ttry {\\n\\t\\t$mapHas.call(x);\\n\\t\\tif ($setHas) {\\n\\t\\t\\ttry {\\n\\t\\t\\t\\t$setHas.call(x);\\n\\t\\t\\t} catch (e) {\\n\\t\\t\\t\\treturn true;\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\treturn x instanceof $Map; // core-js workaround, pre-v2.5.0\\n\\t} catch (e) {}\\n\\treturn false;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/is-map/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/is-number-object/index.js\":\n/*!************************************************!*\\\n  !*** ./node_modules/is-number-object/index.js ***!\n  \\************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar numToStr = Number.prototype.toString;\\nvar tryNumberObject = function tryNumberObject(value) {\\n\\ttry {\\n\\t\\tnumToStr.call(value);\\n\\t\\treturn true;\\n\\t} catch (e) {\\n\\t\\treturn false;\\n\\t}\\n};\\nvar toStr = Object.prototype.toString;\\nvar numClass = '[object Number]';\\nvar hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol';\\n\\nmodule.exports = function isNumberObject(value) {\\n\\tif (typeof value === 'number') {\\n\\t\\treturn true;\\n\\t}\\n\\tif (typeof value !== 'object') {\\n\\t\\treturn false;\\n\\t}\\n\\treturn hasToStringTag ? tryNumberObject(value) : toStr.call(value) === numClass;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/is-number-object/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/is-regex/index.js\":\n/*!****************************************!*\\\n  !*** ./node_modules/is-regex/index.js ***!\n  \\****************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar hasSymbols = __webpack_require__(/*! has-symbols */ \\\"./node_modules/has-symbols/index.js\\\")();\\nvar hasToStringTag = hasSymbols && typeof Symbol.toStringTag === 'symbol';\\nvar regexExec;\\nvar isRegexMarker;\\nvar badStringifier;\\n\\nif (hasToStringTag) {\\n\\tregexExec = Function.call.bind(RegExp.prototype.exec);\\n\\tisRegexMarker = {};\\n\\n\\tvar throwRegexMarker = function () {\\n\\t\\tthrow isRegexMarker;\\n\\t};\\n\\tbadStringifier = {\\n\\t\\ttoString: throwRegexMarker,\\n\\t\\tvalueOf: throwRegexMarker\\n\\t};\\n\\n\\tif (typeof Symbol.toPrimitive === 'symbol') {\\n\\t\\tbadStringifier[Symbol.toPrimitive] = throwRegexMarker;\\n\\t}\\n}\\n\\nvar toStr = Object.prototype.toString;\\nvar regexClass = '[object RegExp]';\\n\\nmodule.exports = hasToStringTag\\n\\t// eslint-disable-next-line consistent-return\\n\\t? function isRegex(value) {\\n\\t\\tif (!value || typeof value !== 'object') {\\n\\t\\t\\treturn false;\\n\\t\\t}\\n\\n\\t\\ttry {\\n\\t\\t\\tregexExec(value, badStringifier);\\n\\t\\t} catch (e) {\\n\\t\\t\\treturn e === isRegexMarker;\\n\\t\\t}\\n\\t}\\n\\t: function isRegex(value) {\\n\\t\\t// In older browsers, typeof regex incorrectly returns 'function'\\n\\t\\tif (!value || (typeof value !== 'object' && typeof value !== 'function')) {\\n\\t\\t\\treturn false;\\n\\t\\t}\\n\\n\\t\\treturn toStr.call(value) === regexClass;\\n\\t};\\n\\n\\n//# sourceURL=webpack:///./node_modules/is-regex/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/is-set/index.js\":\n/*!**************************************!*\\\n  !*** ./node_modules/is-set/index.js ***!\n  \\**************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar $Map = typeof Map === 'function' && Map.prototype ? Map : null;\\nvar $Set = typeof Set === 'function' && Set.prototype ? Set : null;\\n\\nvar exported;\\n\\nif (!$Set) {\\n\\t// eslint-disable-next-line no-unused-vars\\n\\texported = function isSet(x) {\\n\\t\\t// `Set` is not present in this environment.\\n\\t\\treturn false;\\n\\t};\\n}\\n\\nvar $mapHas = $Map ? Map.prototype.has : null;\\nvar $setHas = $Set ? Set.prototype.has : null;\\nif (!exported && !$setHas) {\\n\\t// eslint-disable-next-line no-unused-vars\\n\\texported = function isSet(x) {\\n\\t\\t// `Set` does not have a `has` method\\n\\t\\treturn false;\\n\\t};\\n}\\n\\nmodule.exports = exported || function isSet(x) {\\n\\tif (!x || typeof x !== 'object') {\\n\\t\\treturn false;\\n\\t}\\n\\ttry {\\n\\t\\t$setHas.call(x);\\n\\t\\tif ($mapHas) {\\n\\t\\t\\ttry {\\n\\t\\t\\t\\t$mapHas.call(x);\\n\\t\\t\\t} catch (e) {\\n\\t\\t\\t\\treturn true;\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\treturn x instanceof $Set; // core-js workaround, pre-v2.5.0\\n\\t} catch (e) {}\\n\\treturn false;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/is-set/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/is-string/index.js\":\n/*!*****************************************!*\\\n  !*** ./node_modules/is-string/index.js ***!\n  \\*****************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar strValue = String.prototype.valueOf;\\nvar tryStringObject = function tryStringObject(value) {\\n\\ttry {\\n\\t\\tstrValue.call(value);\\n\\t\\treturn true;\\n\\t} catch (e) {\\n\\t\\treturn false;\\n\\t}\\n};\\nvar toStr = Object.prototype.toString;\\nvar strClass = '[object String]';\\nvar hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol';\\n\\nmodule.exports = function isString(value) {\\n\\tif (typeof value === 'string') {\\n\\t\\treturn true;\\n\\t}\\n\\tif (typeof value !== 'object') {\\n\\t\\treturn false;\\n\\t}\\n\\treturn hasToStringTag ? tryStringObject(value) : toStr.call(value) === strClass;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/is-string/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/is-symbol/index.js\":\n/*!*****************************************!*\\\n  !*** ./node_modules/is-symbol/index.js ***!\n  \\*****************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar toStr = Object.prototype.toString;\\nvar hasSymbols = __webpack_require__(/*! has-symbols */ \\\"./node_modules/has-symbols/index.js\\\")();\\n\\nif (hasSymbols) {\\n\\tvar symToStr = Symbol.prototype.toString;\\n\\tvar symStringRegex = /^Symbol\\\\(.*\\\\)$/;\\n\\tvar isSymbolObject = function isRealSymbolObject(value) {\\n\\t\\tif (typeof value.valueOf() !== 'symbol') {\\n\\t\\t\\treturn false;\\n\\t\\t}\\n\\t\\treturn symStringRegex.test(symToStr.call(value));\\n\\t};\\n\\n\\tmodule.exports = function isSymbol(value) {\\n\\t\\tif (typeof value === 'symbol') {\\n\\t\\t\\treturn true;\\n\\t\\t}\\n\\t\\tif (toStr.call(value) !== '[object Symbol]') {\\n\\t\\t\\treturn false;\\n\\t\\t}\\n\\t\\ttry {\\n\\t\\t\\treturn isSymbolObject(value);\\n\\t\\t} catch (e) {\\n\\t\\t\\treturn false;\\n\\t\\t}\\n\\t};\\n} else {\\n\\n\\tmodule.exports = function isSymbol(value) {\\n\\t\\t// this environment does not support Symbols.\\n\\t\\treturn  false && false;\\n\\t};\\n}\\n\\n\\n//# sourceURL=webpack:///./node_modules/is-symbol/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/is-typed-array/index.js\":\n/*!**********************************************!*\\\n  !*** ./node_modules/is-typed-array/index.js ***!\n  \\**********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"/* WEBPACK VAR INJECTION */(function(global) {\\n\\nvar forEach = __webpack_require__(/*! foreach */ \\\"./node_modules/foreach/index.js\\\");\\nvar availableTypedArrays = __webpack_require__(/*! available-typed-arrays */ \\\"./node_modules/available-typed-arrays/index.js\\\");\\nvar callBound = __webpack_require__(/*! es-abstract/helpers/callBound */ \\\"./node_modules/es-abstract/helpers/callBound.js\\\");\\n\\nvar $toString = callBound('Object.prototype.toString');\\nvar hasSymbols = __webpack_require__(/*! has-symbols */ \\\"./node_modules/has-symbols/index.js\\\")();\\nvar hasToStringTag = hasSymbols && typeof Symbol.toStringTag === 'symbol';\\n\\nvar typedArrays = availableTypedArrays();\\n\\nvar $indexOf = callBound('Array.prototype.indexOf', true) || function indexOf(array, value) {\\n\\tfor (var i = 0; i < array.length; i += 1) {\\n\\t\\tif (array[i] === value) {\\n\\t\\t\\treturn i;\\n\\t\\t}\\n\\t}\\n\\treturn -1;\\n};\\nvar $slice = callBound('String.prototype.slice');\\nvar toStrTags = {};\\nvar gOPD = __webpack_require__(/*! es-abstract/helpers/getOwnPropertyDescriptor */ \\\"./node_modules/es-abstract/helpers/getOwnPropertyDescriptor.js\\\");\\nvar getPrototypeOf = Object.getPrototypeOf; // require('getprototypeof');\\nif (hasToStringTag && gOPD && getPrototypeOf) {\\n\\tforEach(typedArrays, function (typedArray) {\\n\\t\\tvar arr = new global[typedArray]();\\n\\t\\tif (!(Symbol.toStringTag in arr)) {\\n\\t\\t\\tthrow new EvalError('this engine has support for Symbol.toStringTag, but ' + typedArray + ' does not have the property! Please report this.');\\n\\t\\t}\\n\\t\\tvar proto = getPrototypeOf(arr);\\n\\t\\tvar descriptor = gOPD(proto, Symbol.toStringTag);\\n\\t\\tif (!descriptor) {\\n\\t\\t\\tvar superProto = getPrototypeOf(proto);\\n\\t\\t\\tdescriptor = gOPD(superProto, Symbol.toStringTag);\\n\\t\\t}\\n\\t\\ttoStrTags[typedArray] = descriptor.get;\\n\\t});\\n}\\n\\nvar tryTypedArrays = function tryAllTypedArrays(value) {\\n\\tvar anyTrue = false;\\n\\tforEach(toStrTags, function (getter, typedArray) {\\n\\t\\tif (!anyTrue) {\\n\\t\\t\\ttry {\\n\\t\\t\\t\\tanyTrue = getter.call(value) === typedArray;\\n\\t\\t\\t} catch (e) { /**/ }\\n\\t\\t}\\n\\t});\\n\\treturn anyTrue;\\n};\\n\\nmodule.exports = function isTypedArray(value) {\\n\\tif (!value || typeof value !== 'object') { return false; }\\n\\tif (!hasToStringTag) {\\n\\t\\tvar tag = $slice($toString(value), 8, -1);\\n\\t\\treturn $indexOf(typedArrays, tag) > -1;\\n\\t}\\n\\tif (!gOPD) { return false; }\\n\\treturn tryTypedArrays(value);\\n};\\n\\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../webpack/buildin/global.js */ \\\"./node_modules/webpack/buildin/global.js\\\")))\\n\\n//# sourceURL=webpack:///./node_modules/is-typed-array/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/is-weakmap/index.js\":\n/*!******************************************!*\\\n  !*** ./node_modules/is-weakmap/index.js ***!\n  \\******************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar $WeakMap = typeof WeakMap === 'function' && WeakMap.prototype ? WeakMap : null;\\nvar $WeakSet = typeof WeakSet === 'function' && WeakSet.prototype ? WeakSet : null;\\n\\nvar exported;\\n\\nif (!$WeakMap) {\\n\\t// eslint-disable-next-line no-unused-vars\\n\\texported = function isWeakMap(x) {\\n\\t\\t// `WeakMap` is not present in this environment.\\n\\t\\treturn false;\\n\\t};\\n}\\n\\nvar $mapHas = $WeakMap ? $WeakMap.prototype.has : null;\\nvar $setHas = $WeakSet ? $WeakSet.prototype.has : null;\\nif (!exported && !$mapHas) {\\n\\t// eslint-disable-next-line no-unused-vars\\n\\texported = function isWeakMap(x) {\\n\\t\\t// `WeakMap` does not have a `has` method\\n\\t\\treturn false;\\n\\t};\\n}\\n\\nmodule.exports = exported || function isWeakMap(x) {\\n\\tif (!x || typeof x !== 'object') {\\n\\t\\treturn false;\\n\\t}\\n\\ttry {\\n\\t\\t$mapHas.call(x, $mapHas);\\n\\t\\tif ($setHas) {\\n\\t\\t\\ttry {\\n\\t\\t\\t\\t$setHas.call(x, $setHas);\\n\\t\\t\\t} catch (e) {\\n\\t\\t\\t\\treturn true;\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\treturn x instanceof $WeakMap; // core-js workaround, pre-v3\\n\\t} catch (e) {}\\n\\treturn false;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/is-weakmap/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/is-weakset/index.js\":\n/*!******************************************!*\\\n  !*** ./node_modules/is-weakset/index.js ***!\n  \\******************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar $WeakMap = typeof WeakMap === 'function' && WeakMap.prototype ? WeakMap : null;\\nvar $WeakSet = typeof WeakSet === 'function' && WeakSet.prototype ? WeakSet : null;\\n\\nvar exported;\\n\\nif (!$WeakMap) {\\n\\t// eslint-disable-next-line no-unused-vars\\n\\texported = function isWeakSet(x) {\\n\\t\\t// `WeakSet` is not present in this environment.\\n\\t\\treturn false;\\n\\t};\\n}\\n\\nvar $mapHas = $WeakMap ? $WeakMap.prototype.has : null;\\nvar $setHas = $WeakSet ? $WeakSet.prototype.has : null;\\nif (!exported && !$setHas) {\\n\\t// eslint-disable-next-line no-unused-vars\\n\\tmodule.exports = function isWeakSet(x) {\\n\\t\\t// `WeakSet` does not have a `has` method\\n\\t\\treturn false;\\n\\t};\\n}\\n\\nmodule.exports = exported || function isWeakSet(x) {\\n\\tif (!x || typeof x !== 'object') {\\n\\t\\treturn false;\\n\\t}\\n\\ttry {\\n\\t\\t$setHas.call(x, $setHas);\\n\\t\\tif ($mapHas) {\\n\\t\\t\\ttry {\\n\\t\\t\\t\\t$mapHas.call(x, $mapHas);\\n\\t\\t\\t} catch (e) {\\n\\t\\t\\t\\treturn true;\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\treturn x instanceof $WeakSet; // core-js workaround, pre-v3\\n\\t} catch (e) {}\\n\\treturn false;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/is-weakset/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-element/lib/css-tag.js\":\n/*!*************************************************!*\\\n  !*** ./node_modules/lit-element/lib/css-tag.js ***!\n  \\*************************************************/\n/*! exports provided: supportsAdoptingStyleSheets, CSSResult, unsafeCSS, css */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"supportsAdoptingStyleSheets\\\", function() { return supportsAdoptingStyleSheets; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"CSSResult\\\", function() { return CSSResult; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"unsafeCSS\\\", function() { return unsafeCSS; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"css\\\", function() { return css; });\\n/**\\n@license\\nCopyright (c) 2019 The Polymer Project Authors. All rights reserved.\\nThis code may only be used under the BSD style license found at\\nhttp://polymer.github.io/LICENSE.txt The complete set of authors may be found at\\nhttp://polymer.github.io/AUTHORS.txt The complete set of contributors may be\\nfound at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as\\npart of the polymer project is also subject to an additional IP rights grant\\nfound at http://polymer.github.io/PATENTS.txt\\n*/\\nconst supportsAdoptingStyleSheets = ('adoptedStyleSheets' in Document.prototype) &&\\n    ('replace' in CSSStyleSheet.prototype);\\nconst constructionToken = Symbol();\\nclass CSSResult {\\n    constructor(cssText, safeToken) {\\n        if (safeToken !== constructionToken) {\\n            throw new Error('CSSResult is not constructable. Use `unsafeCSS` or `css` instead.');\\n        }\\n        this.cssText = cssText;\\n    }\\n    // Note, this is a getter so that it's lazy. In practice, this means\\n    // stylesheets are not created until the first element instance is made.\\n    get styleSheet() {\\n        if (this._styleSheet === undefined) {\\n            // Note, if `adoptedStyleSheets` is supported then we assume CSSStyleSheet\\n            // is constructable.\\n            if (supportsAdoptingStyleSheets) {\\n                this._styleSheet = new CSSStyleSheet();\\n                this._styleSheet.replaceSync(this.cssText);\\n            }\\n            else {\\n                this._styleSheet = null;\\n            }\\n        }\\n        return this._styleSheet;\\n    }\\n    toString() {\\n        return this.cssText;\\n    }\\n}\\n/**\\n * Wrap a value for interpolation in a css tagged template literal.\\n *\\n * This is unsafe because untrusted CSS text can be used to phone home\\n * or exfiltrate data to an attacker controlled site. Take care to only use\\n * this with trusted input.\\n */\\nconst unsafeCSS = (value) => {\\n    return new CSSResult(String(value), constructionToken);\\n};\\nconst textFromCSSResult = (value) => {\\n    if (value instanceof CSSResult) {\\n        return value.cssText;\\n    }\\n    else if (typeof value === 'number') {\\n        return value;\\n    }\\n    else {\\n        throw new Error(`Value passed to 'css' function must be a 'css' function result: ${value}. Use 'unsafeCSS' to pass non-literal values, but\\n            take care to ensure page security.`);\\n    }\\n};\\n/**\\n * Template tag which which can be used with LitElement's `style` property to\\n * set element styles. For security reasons, only literal string values may be\\n * used. To incorporate non-literal values `unsafeCSS` may be used inside a\\n * template string part.\\n */\\nconst css = (strings, ...values) => {\\n    const cssText = values.reduce((acc, v, idx) => acc + textFromCSSResult(v) + strings[idx + 1], strings[0]);\\n    return new CSSResult(cssText, constructionToken);\\n};\\n//# sourceMappingURL=css-tag.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-element/lib/css-tag.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-element/lib/decorators.js\":\n/*!****************************************************!*\\\n  !*** ./node_modules/lit-element/lib/decorators.js ***!\n  \\****************************************************/\n/*! exports provided: customElement, property, internalProperty, query, queryAsync, queryAll, eventOptions, queryAssignedNodes */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"customElement\\\", function() { return customElement; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"property\\\", function() { return property; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"internalProperty\\\", function() { return internalProperty; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"query\\\", function() { return query; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"queryAsync\\\", function() { return queryAsync; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"queryAll\\\", function() { return queryAll; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"eventOptions\\\", function() { return eventOptions; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"queryAssignedNodes\\\", function() { return queryAssignedNodes; });\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\nconst legacyCustomElement = (tagName, clazz) => {\\n    window.customElements.define(tagName, clazz);\\n    // Cast as any because TS doesn't recognize the return type as being a\\n    // subtype of the decorated class when clazz is typed as\\n    // `Constructor<HTMLElement>` for some reason.\\n    // `Constructor<HTMLElement>` is helpful to make sure the decorator is\\n    // applied to elements however.\\n    // tslint:disable-next-line:no-any\\n    return clazz;\\n};\\nconst standardCustomElement = (tagName, descriptor) => {\\n    const { kind, elements } = descriptor;\\n    return {\\n        kind,\\n        elements,\\n        // This callback is called once the class is otherwise fully defined\\n        finisher(clazz) {\\n            window.customElements.define(tagName, clazz);\\n        }\\n    };\\n};\\n/**\\n * Class decorator factory that defines the decorated class as a custom element.\\n *\\n * ```\\n * @customElement('my-element')\\n * class MyElement {\\n *   render() {\\n *     return html``;\\n *   }\\n * }\\n * ```\\n *\\n * @param tagName The name of the custom element to define.\\n */\\nconst customElement = (tagName) => (classOrDescriptor) => (typeof classOrDescriptor === 'function') ?\\n    legacyCustomElement(tagName, classOrDescriptor) :\\n    standardCustomElement(tagName, classOrDescriptor);\\nconst standardProperty = (options, element) => {\\n    // When decorating an accessor, pass it through and add property metadata.\\n    // Note, the `hasOwnProperty` check in `createProperty` ensures we don't\\n    // stomp over the user's accessor.\\n    if (element.kind === 'method' && element.descriptor &&\\n        !('value' in element.descriptor)) {\\n        return Object.assign(Object.assign({}, element), { finisher(clazz) {\\n                clazz.createProperty(element.key, options);\\n            } });\\n    }\\n    else {\\n        // createProperty() takes care of defining the property, but we still\\n        // must return some kind of descriptor, so return a descriptor for an\\n        // unused prototype field. The finisher calls createProperty().\\n        return {\\n            kind: 'field',\\n            key: Symbol(),\\n            placement: 'own',\\n            descriptor: {},\\n            // When @babel/plugin-proposal-decorators implements initializers,\\n            // do this instead of the initializer below. See:\\n            // https://github.com/babel/babel/issues/9260 extras: [\\n            //   {\\n            //     kind: 'initializer',\\n            //     placement: 'own',\\n            //     initializer: descriptor.initializer,\\n            //   }\\n            // ],\\n            initializer() {\\n                if (typeof element.initializer === 'function') {\\n                    this[element.key] = element.initializer.call(this);\\n                }\\n            },\\n            finisher(clazz) {\\n                clazz.createProperty(element.key, options);\\n            }\\n        };\\n    }\\n};\\nconst legacyProperty = (options, proto, name) => {\\n    proto.constructor\\n        .createProperty(name, options);\\n};\\n/**\\n * A property decorator which creates a LitElement property which reflects a\\n * corresponding attribute value. A `PropertyDeclaration` may optionally be\\n * supplied to configure property features.\\n *\\n * This decorator should only be used for public fields. Private or protected\\n * fields should use the internalProperty decorator.\\n *\\n * @example\\n *\\n *     class MyElement {\\n *       @property({ type: Boolean })\\n *       clicked = false;\\n *     }\\n *\\n * @ExportDecoratedItems\\n */\\nfunction property(options) {\\n    // tslint:disable-next-line:no-any decorator\\n    return (protoOrDescriptor, name) => (name !== undefined) ?\\n        legacyProperty(options, protoOrDescriptor, name) :\\n        standardProperty(options, protoOrDescriptor);\\n}\\n/**\\n * Declares a private or protected property that still triggers updates to the\\n * element when it changes.\\n *\\n * Properties declared this way must not be used from HTML or HTML templating\\n * systems, they're solely for properties internal to the element. These\\n * properties may be renamed by optimization tools like closure compiler.\\n */\\nfunction internalProperty(options) {\\n    return property({ attribute: false, hasChanged: options === null || options === void 0 ? void 0 : options.hasChanged });\\n}\\n/**\\n * A property decorator that converts a class property into a getter that\\n * executes a querySelector on the element's renderRoot.\\n *\\n * @param selector A DOMString containing one or more selectors to match.\\n *\\n * See: https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector\\n *\\n * @example\\n *\\n *     class MyElement {\\n *       @query('#first')\\n *       first;\\n *\\n *       render() {\\n *         return html`\\n *           <div id=\\\"first\\\"></div>\\n *           <div id=\\\"second\\\"></div>\\n *         `;\\n *       }\\n *     }\\n *\\n */\\nfunction query(selector) {\\n    return (protoOrDescriptor, \\n    // tslint:disable-next-line:no-any decorator\\n    name) => {\\n        const descriptor = {\\n            get() {\\n                return this.renderRoot.querySelector(selector);\\n            },\\n            enumerable: true,\\n            configurable: true,\\n        };\\n        return (name !== undefined) ?\\n            legacyQuery(descriptor, protoOrDescriptor, name) :\\n            standardQuery(descriptor, protoOrDescriptor);\\n    };\\n}\\n// Note, in the future, we may extend this decorator to support the use case\\n// where the queried element may need to do work to become ready to interact\\n// with (e.g. load some implementation code). If so, we might elect to\\n// add a second argument defining a function that can be run to make the\\n// queried element loaded/updated/ready.\\n/**\\n * A property decorator that converts a class property into a getter that\\n * returns a promise that resolves to the result of a querySelector on the\\n * element's renderRoot done after the element's `updateComplete` promise\\n * resolves. When the queried property may change with element state, this\\n * decorator can be used instead of requiring users to await the\\n * `updateComplete` before accessing the property.\\n *\\n * @param selector A DOMString containing one or more selectors to match.\\n *\\n * See: https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector\\n *\\n * @example\\n *\\n *     class MyElement {\\n *       @queryAsync('#first')\\n *       first;\\n *\\n *       render() {\\n *         return html`\\n *           <div id=\\\"first\\\"></div>\\n *           <div id=\\\"second\\\"></div>\\n *         `;\\n *       }\\n *     }\\n *\\n *     // external usage\\n *     async doSomethingWithFirst() {\\n *      (await aMyElement.first).doSomething();\\n *     }\\n */\\nfunction queryAsync(selector) {\\n    return (protoOrDescriptor, \\n    // tslint:disable-next-line:no-any decorator\\n    name) => {\\n        const descriptor = {\\n            async get() {\\n                await this.updateComplete;\\n                return this.renderRoot.querySelector(selector);\\n            },\\n            enumerable: true,\\n            configurable: true,\\n        };\\n        return (name !== undefined) ?\\n            legacyQuery(descriptor, protoOrDescriptor, name) :\\n            standardQuery(descriptor, protoOrDescriptor);\\n    };\\n}\\n/**\\n * A property decorator that converts a class property into a getter\\n * that executes a querySelectorAll on the element's renderRoot.\\n *\\n * @param selector A DOMString containing one or more selectors to match.\\n *\\n * See:\\n * https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll\\n *\\n * @example\\n *\\n *     class MyElement {\\n *       @queryAll('div')\\n *       divs;\\n *\\n *       render() {\\n *         return html`\\n *           <div id=\\\"first\\\"></div>\\n *           <div id=\\\"second\\\"></div>\\n *         `;\\n *       }\\n *     }\\n */\\nfunction queryAll(selector) {\\n    return (protoOrDescriptor, \\n    // tslint:disable-next-line:no-any decorator\\n    name) => {\\n        const descriptor = {\\n            get() {\\n                return this.renderRoot.querySelectorAll(selector);\\n            },\\n            enumerable: true,\\n            configurable: true,\\n        };\\n        return (name !== undefined) ?\\n            legacyQuery(descriptor, protoOrDescriptor, name) :\\n            standardQuery(descriptor, protoOrDescriptor);\\n    };\\n}\\nconst legacyQuery = (descriptor, proto, name) => {\\n    Object.defineProperty(proto, name, descriptor);\\n};\\nconst standardQuery = (descriptor, element) => ({\\n    kind: 'method',\\n    placement: 'prototype',\\n    key: element.key,\\n    descriptor,\\n});\\nconst standardEventOptions = (options, element) => {\\n    return Object.assign(Object.assign({}, element), { finisher(clazz) {\\n            Object.assign(clazz.prototype[element.key], options);\\n        } });\\n};\\nconst legacyEventOptions = \\n// tslint:disable-next-line:no-any legacy decorator\\n(options, proto, name) => {\\n    Object.assign(proto[name], options);\\n};\\n/**\\n * Adds event listener options to a method used as an event listener in a\\n * lit-html template.\\n *\\n * @param options An object that specifies event listener options as accepted by\\n * `EventTarget#addEventListener` and `EventTarget#removeEventListener`.\\n *\\n * Current browsers support the `capture`, `passive`, and `once` options. See:\\n * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Parameters\\n *\\n * @example\\n *\\n *     class MyElement {\\n *       clicked = false;\\n *\\n *       render() {\\n *         return html`\\n *           <div @click=${this._onClick}`>\\n *             <button></button>\\n *           </div>\\n *         `;\\n *       }\\n *\\n *       @eventOptions({capture: true})\\n *       _onClick(e) {\\n *         this.clicked = true;\\n *       }\\n *     }\\n */\\nfunction eventOptions(options) {\\n    // Return value typed as any to prevent TypeScript from complaining that\\n    // standard decorator function signature does not match TypeScript decorator\\n    // signature\\n    // TODO(kschaaf): unclear why it was only failing on this decorator and not\\n    // the others\\n    return ((protoOrDescriptor, name) => (name !== undefined) ?\\n        legacyEventOptions(options, protoOrDescriptor, name) :\\n        standardEventOptions(options, protoOrDescriptor));\\n}\\n/**\\n * A property decorator that converts a class property into a getter that\\n * returns the `assignedNodes` of the given named `slot`. Note, the type of\\n * this property should be annotated as `NodeListOf<HTMLElement>`.\\n *\\n */\\nfunction queryAssignedNodes(slotName = '', flatten = false) {\\n    return (protoOrDescriptor, \\n    // tslint:disable-next-line:no-any decorator\\n    name) => {\\n        const descriptor = {\\n            get() {\\n                const selector = `slot${slotName ? `[name=${slotName}]` : ''}`;\\n                const slot = this.renderRoot.querySelector(selector);\\n                return slot && slot.assignedNodes({ flatten });\\n            },\\n            enumerable: true,\\n            configurable: true,\\n        };\\n        return (name !== undefined) ?\\n            legacyQuery(descriptor, protoOrDescriptor, name) :\\n            standardQuery(descriptor, protoOrDescriptor);\\n    };\\n}\\n//# sourceMappingURL=decorators.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-element/lib/decorators.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-element/lib/updating-element.js\":\n/*!**********************************************************!*\\\n  !*** ./node_modules/lit-element/lib/updating-element.js ***!\n  \\**********************************************************/\n/*! exports provided: defaultConverter, notEqual, UpdatingElement */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"defaultConverter\\\", function() { return defaultConverter; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"notEqual\\\", function() { return notEqual; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"UpdatingElement\\\", function() { return UpdatingElement; });\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\nvar _a;\\n/**\\n * When using Closure Compiler, JSCompiler_renameProperty(property, object) is\\n * replaced at compile time by the munged name for object[property]. We cannot\\n * alias this function, so we have to use a small shim that has the same\\n * behavior when not compiling.\\n */\\nwindow.JSCompiler_renameProperty =\\n    (prop, _obj) => prop;\\nconst defaultConverter = {\\n    toAttribute(value, type) {\\n        switch (type) {\\n            case Boolean:\\n                return value ? '' : null;\\n            case Object:\\n            case Array:\\n                // if the value is `null` or `undefined` pass this through\\n                // to allow removing/no change behavior.\\n                return value == null ? value : JSON.stringify(value);\\n        }\\n        return value;\\n    },\\n    fromAttribute(value, type) {\\n        switch (type) {\\n            case Boolean:\\n                return value !== null;\\n            case Number:\\n                return value === null ? null : Number(value);\\n            case Object:\\n            case Array:\\n                return JSON.parse(value);\\n        }\\n        return value;\\n    }\\n};\\n/**\\n * Change function that returns true if `value` is different from `oldValue`.\\n * This method is used as the default for a property's `hasChanged` function.\\n */\\nconst notEqual = (value, old) => {\\n    // This ensures (old==NaN, value==NaN) always returns false\\n    return old !== value && (old === old || value === value);\\n};\\nconst defaultPropertyDeclaration = {\\n    attribute: true,\\n    type: String,\\n    converter: defaultConverter,\\n    reflect: false,\\n    hasChanged: notEqual\\n};\\nconst STATE_HAS_UPDATED = 1;\\nconst STATE_UPDATE_REQUESTED = 1 << 2;\\nconst STATE_IS_REFLECTING_TO_ATTRIBUTE = 1 << 3;\\nconst STATE_IS_REFLECTING_TO_PROPERTY = 1 << 4;\\n/**\\n * The Closure JS Compiler doesn't currently have good support for static\\n * property semantics where \\\"this\\\" is dynamic (e.g.\\n * https://github.com/google/closure-compiler/issues/3177 and others) so we use\\n * this hack to bypass any rewriting by the compiler.\\n */\\nconst finalized = 'finalized';\\n/**\\n * Base element class which manages element properties and attributes. When\\n * properties change, the `update` method is asynchronously called. This method\\n * should be supplied by subclassers to render updates as desired.\\n */\\nclass UpdatingElement extends HTMLElement {\\n    constructor() {\\n        super();\\n        this._updateState = 0;\\n        this._instanceProperties = undefined;\\n        // Initialize to an unresolved Promise so we can make sure the element has\\n        // connected before first update.\\n        this._updatePromise = new Promise((res) => this._enableUpdatingResolver = res);\\n        /**\\n         * Map with keys for any properties that have changed since the last\\n         * update cycle with previous values.\\n         */\\n        this._changedProperties = new Map();\\n        /**\\n         * Map with keys of properties that should be reflected when updated.\\n         */\\n        this._reflectingProperties = undefined;\\n        this.initialize();\\n    }\\n    /**\\n     * Returns a list of attributes corresponding to the registered properties.\\n     * @nocollapse\\n     */\\n    static get observedAttributes() {\\n        // note: piggy backing on this to ensure we're finalized.\\n        this.finalize();\\n        const attributes = [];\\n        // Use forEach so this works even if for/of loops are compiled to for loops\\n        // expecting arrays\\n        this._classProperties.forEach((v, p) => {\\n            const attr = this._attributeNameForProperty(p, v);\\n            if (attr !== undefined) {\\n                this._attributeToPropertyMap.set(attr, p);\\n                attributes.push(attr);\\n            }\\n        });\\n        return attributes;\\n    }\\n    /**\\n     * Ensures the private `_classProperties` property metadata is created.\\n     * In addition to `finalize` this is also called in `createProperty` to\\n     * ensure the `@property` decorator can add property metadata.\\n     */\\n    /** @nocollapse */\\n    static _ensureClassProperties() {\\n        // ensure private storage for property declarations.\\n        if (!this.hasOwnProperty(JSCompiler_renameProperty('_classProperties', this))) {\\n            this._classProperties = new Map();\\n            // NOTE: Workaround IE11 not supporting Map constructor argument.\\n            const superProperties = Object.getPrototypeOf(this)._classProperties;\\n            if (superProperties !== undefined) {\\n                superProperties.forEach((v, k) => this._classProperties.set(k, v));\\n            }\\n        }\\n    }\\n    /**\\n     * Creates a property accessor on the element prototype if one does not exist\\n     * and stores a PropertyDeclaration for the property with the given options.\\n     * The property setter calls the property's `hasChanged` property option\\n     * or uses a strict identity check to determine whether or not to request\\n     * an update.\\n     *\\n     * This method may be overridden to customize properties; however,\\n     * when doing so, it's important to call `super.createProperty` to ensure\\n     * the property is setup correctly. This method calls\\n     * `getPropertyDescriptor` internally to get a descriptor to install.\\n     * To customize what properties do when they are get or set, override\\n     * `getPropertyDescriptor`. To customize the options for a property,\\n     * implement `createProperty` like this:\\n     *\\n     * static createProperty(name, options) {\\n     *   options = Object.assign(options, {myOption: true});\\n     *   super.createProperty(name, options);\\n     * }\\n     *\\n     * @nocollapse\\n     */\\n    static createProperty(name, options = defaultPropertyDeclaration) {\\n        // Note, since this can be called by the `@property` decorator which\\n        // is called before `finalize`, we ensure storage exists for property\\n        // metadata.\\n        this._ensureClassProperties();\\n        this._classProperties.set(name, options);\\n        // Do not generate an accessor if the prototype already has one, since\\n        // it would be lost otherwise and that would never be the user's intention;\\n        // Instead, we expect users to call `requestUpdate` themselves from\\n        // user-defined accessors. Note that if the super has an accessor we will\\n        // still overwrite it\\n        if (options.noAccessor || this.prototype.hasOwnProperty(name)) {\\n            return;\\n        }\\n        const key = typeof name === 'symbol' ? Symbol() : `__${name}`;\\n        const descriptor = this.getPropertyDescriptor(name, key, options);\\n        if (descriptor !== undefined) {\\n            Object.defineProperty(this.prototype, name, descriptor);\\n        }\\n    }\\n    /**\\n     * Returns a property descriptor to be defined on the given named property.\\n     * If no descriptor is returned, the property will not become an accessor.\\n     * For example,\\n     *\\n     *   class MyElement extends LitElement {\\n     *     static getPropertyDescriptor(name, key, options) {\\n     *       const defaultDescriptor =\\n     *           super.getPropertyDescriptor(name, key, options);\\n     *       const setter = defaultDescriptor.set;\\n     *       return {\\n     *         get: defaultDescriptor.get,\\n     *         set(value) {\\n     *           setter.call(this, value);\\n     *           // custom action.\\n     *         },\\n     *         configurable: true,\\n     *         enumerable: true\\n     *       }\\n     *     }\\n     *   }\\n     *\\n     * @nocollapse\\n     */\\n    static getPropertyDescriptor(name, key, _options) {\\n        return {\\n            // tslint:disable-next-line:no-any no symbol in index\\n            get() {\\n                return this[key];\\n            },\\n            set(value) {\\n                const oldValue = this[name];\\n                this[key] = value;\\n                this._requestUpdate(name, oldValue);\\n            },\\n            configurable: true,\\n            enumerable: true\\n        };\\n    }\\n    /**\\n     * Returns the property options associated with the given property.\\n     * These options are defined with a PropertyDeclaration via the `properties`\\n     * object or the `@property` decorator and are registered in\\n     * `createProperty(...)`.\\n     *\\n     * Note, this method should be considered \\\"final\\\" and not overridden. To\\n     * customize the options for a given property, override `createProperty`.\\n     *\\n     * @nocollapse\\n     * @final\\n     */\\n    static getPropertyOptions(name) {\\n        return this._classProperties && this._classProperties.get(name) ||\\n            defaultPropertyDeclaration;\\n    }\\n    /**\\n     * Creates property accessors for registered properties and ensures\\n     * any superclasses are also finalized.\\n     * @nocollapse\\n     */\\n    static finalize() {\\n        // finalize any superclasses\\n        const superCtor = Object.getPrototypeOf(this);\\n        if (!superCtor.hasOwnProperty(finalized)) {\\n            superCtor.finalize();\\n        }\\n        this[finalized] = true;\\n        this._ensureClassProperties();\\n        // initialize Map populated in observedAttributes\\n        this._attributeToPropertyMap = new Map();\\n        // make any properties\\n        // Note, only process \\\"own\\\" properties since this element will inherit\\n        // any properties defined on the superClass, and finalization ensures\\n        // the entire prototype chain is finalized.\\n        if (this.hasOwnProperty(JSCompiler_renameProperty('properties', this))) {\\n            const props = this.properties;\\n            // support symbols in properties (IE11 does not support this)\\n            const propKeys = [\\n                ...Object.getOwnPropertyNames(props),\\n                ...(typeof Object.getOwnPropertySymbols === 'function') ?\\n                    Object.getOwnPropertySymbols(props) :\\n                    []\\n            ];\\n            // This for/of is ok because propKeys is an array\\n            for (const p of propKeys) {\\n                // note, use of `any` is due to TypeSript lack of support for symbol in\\n                // index types\\n                // tslint:disable-next-line:no-any no symbol in index\\n                this.createProperty(p, props[p]);\\n            }\\n        }\\n    }\\n    /**\\n     * Returns the property name for the given attribute `name`.\\n     * @nocollapse\\n     */\\n    static _attributeNameForProperty(name, options) {\\n        const attribute = options.attribute;\\n        return attribute === false ?\\n            undefined :\\n            (typeof attribute === 'string' ?\\n                attribute :\\n                (typeof name === 'string' ? name.toLowerCase() : undefined));\\n    }\\n    /**\\n     * Returns true if a property should request an update.\\n     * Called when a property value is set and uses the `hasChanged`\\n     * option for the property if present or a strict identity check.\\n     * @nocollapse\\n     */\\n    static _valueHasChanged(value, old, hasChanged = notEqual) {\\n        return hasChanged(value, old);\\n    }\\n    /**\\n     * Returns the property value for the given attribute value.\\n     * Called via the `attributeChangedCallback` and uses the property's\\n     * `converter` or `converter.fromAttribute` property option.\\n     * @nocollapse\\n     */\\n    static _propertyValueFromAttribute(value, options) {\\n        const type = options.type;\\n        const converter = options.converter || defaultConverter;\\n        const fromAttribute = (typeof converter === 'function' ? converter : converter.fromAttribute);\\n        return fromAttribute ? fromAttribute(value, type) : value;\\n    }\\n    /**\\n     * Returns the attribute value for the given property value. If this\\n     * returns undefined, the property will *not* be reflected to an attribute.\\n     * If this returns null, the attribute will be removed, otherwise the\\n     * attribute will be set to the value.\\n     * This uses the property's `reflect` and `type.toAttribute` property options.\\n     * @nocollapse\\n     */\\n    static _propertyValueToAttribute(value, options) {\\n        if (options.reflect === undefined) {\\n            return;\\n        }\\n        const type = options.type;\\n        const converter = options.converter;\\n        const toAttribute = converter && converter.toAttribute ||\\n            defaultConverter.toAttribute;\\n        return toAttribute(value, type);\\n    }\\n    /**\\n     * Performs element initialization. By default captures any pre-set values for\\n     * registered properties.\\n     */\\n    initialize() {\\n        this._saveInstanceProperties();\\n        // ensures first update will be caught by an early access of\\n        // `updateComplete`\\n        this._requestUpdate();\\n    }\\n    /**\\n     * Fixes any properties set on the instance before upgrade time.\\n     * Otherwise these would shadow the accessor and break these properties.\\n     * The properties are stored in a Map which is played back after the\\n     * constructor runs. Note, on very old versions of Safari (<=9) or Chrome\\n     * (<=41), properties created for native platform properties like (`id` or\\n     * `name`) may not have default values set in the element constructor. On\\n     * these browsers native properties appear on instances and therefore their\\n     * default value will overwrite any element default (e.g. if the element sets\\n     * this.id = 'id' in the constructor, the 'id' will become '' since this is\\n     * the native platform default).\\n     */\\n    _saveInstanceProperties() {\\n        // Use forEach so this works even if for/of loops are compiled to for loops\\n        // expecting arrays\\n        this.constructor\\n            ._classProperties.forEach((_v, p) => {\\n            if (this.hasOwnProperty(p)) {\\n                const value = this[p];\\n                delete this[p];\\n                if (!this._instanceProperties) {\\n                    this._instanceProperties = new Map();\\n                }\\n                this._instanceProperties.set(p, value);\\n            }\\n        });\\n    }\\n    /**\\n     * Applies previously saved instance properties.\\n     */\\n    _applyInstanceProperties() {\\n        // Use forEach so this works even if for/of loops are compiled to for loops\\n        // expecting arrays\\n        // tslint:disable-next-line:no-any\\n        this._instanceProperties.forEach((v, p) => this[p] = v);\\n        this._instanceProperties = undefined;\\n    }\\n    connectedCallback() {\\n        // Ensure first connection completes an update. Updates cannot complete\\n        // before connection.\\n        this.enableUpdating();\\n    }\\n    enableUpdating() {\\n        if (this._enableUpdatingResolver !== undefined) {\\n            this._enableUpdatingResolver();\\n            this._enableUpdatingResolver = undefined;\\n        }\\n    }\\n    /**\\n     * Allows for `super.disconnectedCallback()` in extensions while\\n     * reserving the possibility of making non-breaking feature additions\\n     * when disconnecting at some point in the future.\\n     */\\n    disconnectedCallback() {\\n    }\\n    /**\\n     * Synchronizes property values when attributes change.\\n     */\\n    attributeChangedCallback(name, old, value) {\\n        if (old !== value) {\\n            this._attributeToProperty(name, value);\\n        }\\n    }\\n    _propertyToAttribute(name, value, options = defaultPropertyDeclaration) {\\n        const ctor = this.constructor;\\n        const attr = ctor._attributeNameForProperty(name, options);\\n        if (attr !== undefined) {\\n            const attrValue = ctor._propertyValueToAttribute(value, options);\\n            // an undefined value does not change the attribute.\\n            if (attrValue === undefined) {\\n                return;\\n            }\\n            // Track if the property is being reflected to avoid\\n            // setting the property again via `attributeChangedCallback`. Note:\\n            // 1. this takes advantage of the fact that the callback is synchronous.\\n            // 2. will behave incorrectly if multiple attributes are in the reaction\\n            // stack at time of calling. However, since we process attributes\\n            // in `update` this should not be possible (or an extreme corner case\\n            // that we'd like to discover).\\n            // mark state reflecting\\n            this._updateState = this._updateState | STATE_IS_REFLECTING_TO_ATTRIBUTE;\\n            if (attrValue == null) {\\n                this.removeAttribute(attr);\\n            }\\n            else {\\n                this.setAttribute(attr, attrValue);\\n            }\\n            // mark state not reflecting\\n            this._updateState = this._updateState & ~STATE_IS_REFLECTING_TO_ATTRIBUTE;\\n        }\\n    }\\n    _attributeToProperty(name, value) {\\n        // Use tracking info to avoid deserializing attribute value if it was\\n        // just set from a property setter.\\n        if (this._updateState & STATE_IS_REFLECTING_TO_ATTRIBUTE) {\\n            return;\\n        }\\n        const ctor = this.constructor;\\n        // Note, hint this as an `AttributeMap` so closure clearly understands\\n        // the type; it has issues with tracking types through statics\\n        // tslint:disable-next-line:no-unnecessary-type-assertion\\n        const propName = ctor._attributeToPropertyMap.get(name);\\n        if (propName !== undefined) {\\n            const options = ctor.getPropertyOptions(propName);\\n            // mark state reflecting\\n            this._updateState = this._updateState | STATE_IS_REFLECTING_TO_PROPERTY;\\n            this[propName] =\\n                // tslint:disable-next-line:no-any\\n                ctor._propertyValueFromAttribute(value, options);\\n            // mark state not reflecting\\n            this._updateState = this._updateState & ~STATE_IS_REFLECTING_TO_PROPERTY;\\n        }\\n    }\\n    /**\\n     * This private version of `requestUpdate` does not access or return the\\n     * `updateComplete` promise. This promise can be overridden and is therefore\\n     * not free to access.\\n     */\\n    _requestUpdate(name, oldValue) {\\n        let shouldRequestUpdate = true;\\n        // If we have a property key, perform property update steps.\\n        if (name !== undefined) {\\n            const ctor = this.constructor;\\n            const options = ctor.getPropertyOptions(name);\\n            if (ctor._valueHasChanged(this[name], oldValue, options.hasChanged)) {\\n                if (!this._changedProperties.has(name)) {\\n                    this._changedProperties.set(name, oldValue);\\n                }\\n                // Add to reflecting properties set.\\n                // Note, it's important that every change has a chance to add the\\n                // property to `_reflectingProperties`. This ensures setting\\n                // attribute + property reflects correctly.\\n                if (options.reflect === true &&\\n                    !(this._updateState & STATE_IS_REFLECTING_TO_PROPERTY)) {\\n                    if (this._reflectingProperties === undefined) {\\n                        this._reflectingProperties = new Map();\\n                    }\\n                    this._reflectingProperties.set(name, options);\\n                }\\n            }\\n            else {\\n                // Abort the request if the property should not be considered changed.\\n                shouldRequestUpdate = false;\\n            }\\n        }\\n        if (!this._hasRequestedUpdate && shouldRequestUpdate) {\\n            this._updatePromise = this._enqueueUpdate();\\n        }\\n    }\\n    /**\\n     * Requests an update which is processed asynchronously. This should\\n     * be called when an element should update based on some state not triggered\\n     * by setting a property. In this case, pass no arguments. It should also be\\n     * called when manually implementing a property setter. In this case, pass the\\n     * property `name` and `oldValue` to ensure that any configured property\\n     * options are honored. Returns the `updateComplete` Promise which is resolved\\n     * when the update completes.\\n     *\\n     * @param name {PropertyKey} (optional) name of requesting property\\n     * @param oldValue {any} (optional) old value of requesting property\\n     * @returns {Promise} A Promise that is resolved when the update completes.\\n     */\\n    requestUpdate(name, oldValue) {\\n        this._requestUpdate(name, oldValue);\\n        return this.updateComplete;\\n    }\\n    /**\\n     * Sets up the element to asynchronously update.\\n     */\\n    async _enqueueUpdate() {\\n        this._updateState = this._updateState | STATE_UPDATE_REQUESTED;\\n        try {\\n            // Ensure any previous update has resolved before updating.\\n            // This `await` also ensures that property changes are batched.\\n            await this._updatePromise;\\n        }\\n        catch (e) {\\n            // Ignore any previous errors. We only care that the previous cycle is\\n            // done. Any error should have been handled in the previous update.\\n        }\\n        const result = this.performUpdate();\\n        // If `performUpdate` returns a Promise, we await it. This is done to\\n        // enable coordinating updates with a scheduler. Note, the result is\\n        // checked to avoid delaying an additional microtask unless we need to.\\n        if (result != null) {\\n            await result;\\n        }\\n        return !this._hasRequestedUpdate;\\n    }\\n    get _hasRequestedUpdate() {\\n        return (this._updateState & STATE_UPDATE_REQUESTED);\\n    }\\n    get hasUpdated() {\\n        return (this._updateState & STATE_HAS_UPDATED);\\n    }\\n    /**\\n     * Performs an element update. Note, if an exception is thrown during the\\n     * update, `firstUpdated` and `updated` will not be called.\\n     *\\n     * You can override this method to change the timing of updates. If this\\n     * method is overridden, `super.performUpdate()` must be called.\\n     *\\n     * For instance, to schedule updates to occur just before the next frame:\\n     *\\n     * ```\\n     * protected async performUpdate(): Promise<unknown> {\\n     *   await new Promise((resolve) => requestAnimationFrame(() => resolve()));\\n     *   super.performUpdate();\\n     * }\\n     * ```\\n     */\\n    performUpdate() {\\n        // Mixin instance properties once, if they exist.\\n        if (this._instanceProperties) {\\n            this._applyInstanceProperties();\\n        }\\n        let shouldUpdate = false;\\n        const changedProperties = this._changedProperties;\\n        try {\\n            shouldUpdate = this.shouldUpdate(changedProperties);\\n            if (shouldUpdate) {\\n                this.update(changedProperties);\\n            }\\n            else {\\n                this._markUpdated();\\n            }\\n        }\\n        catch (e) {\\n            // Prevent `firstUpdated` and `updated` from running when there's an\\n            // update exception.\\n            shouldUpdate = false;\\n            // Ensure element can accept additional updates after an exception.\\n            this._markUpdated();\\n            throw e;\\n        }\\n        if (shouldUpdate) {\\n            if (!(this._updateState & STATE_HAS_UPDATED)) {\\n                this._updateState = this._updateState | STATE_HAS_UPDATED;\\n                this.firstUpdated(changedProperties);\\n            }\\n            this.updated(changedProperties);\\n        }\\n    }\\n    _markUpdated() {\\n        this._changedProperties = new Map();\\n        this._updateState = this._updateState & ~STATE_UPDATE_REQUESTED;\\n    }\\n    /**\\n     * Returns a Promise that resolves when the element has completed updating.\\n     * The Promise value is a boolean that is `true` if the element completed the\\n     * update without triggering another update. The Promise result is `false` if\\n     * a property was set inside `updated()`. If the Promise is rejected, an\\n     * exception was thrown during the update.\\n     *\\n     * To await additional asynchronous work, override the `_getUpdateComplete`\\n     * method. For example, it is sometimes useful to await a rendered element\\n     * before fulfilling this Promise. To do this, first await\\n     * `super._getUpdateComplete()`, then any subsequent state.\\n     *\\n     * @returns {Promise} The Promise returns a boolean that indicates if the\\n     * update resolved without triggering another update.\\n     */\\n    get updateComplete() {\\n        return this._getUpdateComplete();\\n    }\\n    /**\\n     * Override point for the `updateComplete` promise.\\n     *\\n     * It is not safe to override the `updateComplete` getter directly due to a\\n     * limitation in TypeScript which means it is not possible to call a\\n     * superclass getter (e.g. `super.updateComplete.then(...)`) when the target\\n     * language is ES5 (https://github.com/microsoft/TypeScript/issues/338).\\n     * This method should be overridden instead. For example:\\n     *\\n     *   class MyElement extends LitElement {\\n     *     async _getUpdateComplete() {\\n     *       await super._getUpdateComplete();\\n     *       await this._myChild.updateComplete;\\n     *     }\\n     *   }\\n     */\\n    _getUpdateComplete() {\\n        return this._updatePromise;\\n    }\\n    /**\\n     * Controls whether or not `update` should be called when the element requests\\n     * an update. By default, this method always returns `true`, but this can be\\n     * customized to control when to update.\\n     *\\n     * @param _changedProperties Map of changed properties with old values\\n     */\\n    shouldUpdate(_changedProperties) {\\n        return true;\\n    }\\n    /**\\n     * Updates the element. This method reflects property values to attributes.\\n     * It can be overridden to render and keep updated element DOM.\\n     * Setting properties inside this method will *not* trigger\\n     * another update.\\n     *\\n     * @param _changedProperties Map of changed properties with old values\\n     */\\n    update(_changedProperties) {\\n        if (this._reflectingProperties !== undefined &&\\n            this._reflectingProperties.size > 0) {\\n            // Use forEach so this works even if for/of loops are compiled to for\\n            // loops expecting arrays\\n            this._reflectingProperties.forEach((v, k) => this._propertyToAttribute(k, this[k], v));\\n            this._reflectingProperties = undefined;\\n        }\\n        this._markUpdated();\\n    }\\n    /**\\n     * Invoked whenever the element is updated. Implement to perform\\n     * post-updating tasks via DOM APIs, for example, focusing an element.\\n     *\\n     * Setting properties inside this method will trigger the element to update\\n     * again after this update cycle completes.\\n     *\\n     * @param _changedProperties Map of changed properties with old values\\n     */\\n    updated(_changedProperties) {\\n    }\\n    /**\\n     * Invoked when the element is first updated. Implement to perform one time\\n     * work on the element after update.\\n     *\\n     * Setting properties inside this method will trigger the element to update\\n     * again after this update cycle completes.\\n     *\\n     * @param _changedProperties Map of changed properties with old values\\n     */\\n    firstUpdated(_changedProperties) {\\n    }\\n}\\n_a = finalized;\\n/**\\n * Marks class as having finished creating properties.\\n */\\nUpdatingElement[_a] = true;\\n//# sourceMappingURL=updating-element.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-element/lib/updating-element.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-element/lit-element.js\":\n/*!*************************************************!*\\\n  !*** ./node_modules/lit-element/lit-element.js ***!\n  \\*************************************************/\n/*! exports provided: defaultConverter, notEqual, UpdatingElement, customElement, property, internalProperty, query, queryAsync, queryAll, eventOptions, queryAssignedNodes, html, svg, TemplateResult, SVGTemplateResult, supportsAdoptingStyleSheets, CSSResult, unsafeCSS, css, LitElement */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"LitElement\\\", function() { return LitElement; });\\n/* harmony import */ var lit_html_lib_shady_render_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lit-html/lib/shady-render.js */ \\\"./node_modules/lit-html/lib/shady-render.js\\\");\\n/* harmony import */ var _lib_updating_element_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./lib/updating-element.js */ \\\"./node_modules/lit-element/lib/updating-element.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"defaultConverter\\\", function() { return _lib_updating_element_js__WEBPACK_IMPORTED_MODULE_1__[\\\"defaultConverter\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"notEqual\\\", function() { return _lib_updating_element_js__WEBPACK_IMPORTED_MODULE_1__[\\\"notEqual\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"UpdatingElement\\\", function() { return _lib_updating_element_js__WEBPACK_IMPORTED_MODULE_1__[\\\"UpdatingElement\\\"]; });\\n\\n/* harmony import */ var _lib_decorators_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./lib/decorators.js */ \\\"./node_modules/lit-element/lib/decorators.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"customElement\\\", function() { return _lib_decorators_js__WEBPACK_IMPORTED_MODULE_2__[\\\"customElement\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"property\\\", function() { return _lib_decorators_js__WEBPACK_IMPORTED_MODULE_2__[\\\"property\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"internalProperty\\\", function() { return _lib_decorators_js__WEBPACK_IMPORTED_MODULE_2__[\\\"internalProperty\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"query\\\", function() { return _lib_decorators_js__WEBPACK_IMPORTED_MODULE_2__[\\\"query\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"queryAsync\\\", function() { return _lib_decorators_js__WEBPACK_IMPORTED_MODULE_2__[\\\"queryAsync\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"queryAll\\\", function() { return _lib_decorators_js__WEBPACK_IMPORTED_MODULE_2__[\\\"queryAll\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"eventOptions\\\", function() { return _lib_decorators_js__WEBPACK_IMPORTED_MODULE_2__[\\\"eventOptions\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"queryAssignedNodes\\\", function() { return _lib_decorators_js__WEBPACK_IMPORTED_MODULE_2__[\\\"queryAssignedNodes\\\"]; });\\n\\n/* harmony import */ var lit_html_lit_html_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! lit-html/lit-html.js */ \\\"./node_modules/lit-html/lit-html.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"html\\\", function() { return lit_html_lit_html_js__WEBPACK_IMPORTED_MODULE_3__[\\\"html\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"svg\\\", function() { return lit_html_lit_html_js__WEBPACK_IMPORTED_MODULE_3__[\\\"svg\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"TemplateResult\\\", function() { return lit_html_lit_html_js__WEBPACK_IMPORTED_MODULE_3__[\\\"TemplateResult\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"SVGTemplateResult\\\", function() { return lit_html_lit_html_js__WEBPACK_IMPORTED_MODULE_3__[\\\"SVGTemplateResult\\\"]; });\\n\\n/* harmony import */ var _lib_css_tag_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./lib/css-tag.js */ \\\"./node_modules/lit-element/lib/css-tag.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"supportsAdoptingStyleSheets\\\", function() { return _lib_css_tag_js__WEBPACK_IMPORTED_MODULE_4__[\\\"supportsAdoptingStyleSheets\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"CSSResult\\\", function() { return _lib_css_tag_js__WEBPACK_IMPORTED_MODULE_4__[\\\"CSSResult\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"unsafeCSS\\\", function() { return _lib_css_tag_js__WEBPACK_IMPORTED_MODULE_4__[\\\"unsafeCSS\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"css\\\", function() { return _lib_css_tag_js__WEBPACK_IMPORTED_MODULE_4__[\\\"css\\\"]; });\\n\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n\\n\\n\\n\\n\\n\\n\\n// IMPORTANT: do not change the property name or the assignment expression.\\n// This line will be used in regexes to search for LitElement usage.\\n// TODO(justinfagnani): inject version number at build time\\n(window['litElementVersions'] || (window['litElementVersions'] = []))\\n    .push('2.3.1');\\n/**\\n * Sentinal value used to avoid calling lit-html's render function when\\n * subclasses do not implement `render`\\n */\\nconst renderNotImplemented = {};\\nclass LitElement extends _lib_updating_element_js__WEBPACK_IMPORTED_MODULE_1__[\\\"UpdatingElement\\\"] {\\n    /**\\n     * Return the array of styles to apply to the element.\\n     * Override this method to integrate into a style management system.\\n     *\\n     * @nocollapse\\n     */\\n    static getStyles() {\\n        return this.styles;\\n    }\\n    /** @nocollapse */\\n    static _getUniqueStyles() {\\n        // Only gather styles once per class\\n        if (this.hasOwnProperty(JSCompiler_renameProperty('_styles', this))) {\\n            return;\\n        }\\n        // Take care not to call `this.getStyles()` multiple times since this\\n        // generates new CSSResults each time.\\n        // TODO(sorvell): Since we do not cache CSSResults by input, any\\n        // shared styles will generate new stylesheet objects, which is wasteful.\\n        // This should be addressed when a browser ships constructable\\n        // stylesheets.\\n        const userStyles = this.getStyles();\\n        if (userStyles === undefined) {\\n            this._styles = [];\\n        }\\n        else if (Array.isArray(userStyles)) {\\n            // De-duplicate styles preserving the _last_ instance in the set.\\n            // This is a performance optimization to avoid duplicated styles that can\\n            // occur especially when composing via subclassing.\\n            // The last item is kept to try to preserve the cascade order with the\\n            // assumption that it's most important that last added styles override\\n            // previous styles.\\n            const addStyles = (styles, set) => styles.reduceRight((set, s) => \\n            // Note: On IE set.add() does not return the set\\n            Array.isArray(s) ? addStyles(s, set) : (set.add(s), set), set);\\n            // Array.from does not work on Set in IE, otherwise return\\n            // Array.from(addStyles(userStyles, new Set<CSSResult>())).reverse()\\n            const set = addStyles(userStyles, new Set());\\n            const styles = [];\\n            set.forEach((v) => styles.unshift(v));\\n            this._styles = styles;\\n        }\\n        else {\\n            this._styles = [userStyles];\\n        }\\n    }\\n    /**\\n     * Performs element initialization. By default this calls `createRenderRoot`\\n     * to create the element `renderRoot` node and captures any pre-set values for\\n     * registered properties.\\n     */\\n    initialize() {\\n        super.initialize();\\n        this.constructor._getUniqueStyles();\\n        this.renderRoot =\\n            this.createRenderRoot();\\n        // Note, if renderRoot is not a shadowRoot, styles would/could apply to the\\n        // element's getRootNode(). While this could be done, we're choosing not to\\n        // support this now since it would require different logic around de-duping.\\n        if (window.ShadowRoot && this.renderRoot instanceof window.ShadowRoot) {\\n            this.adoptStyles();\\n        }\\n    }\\n    /**\\n     * Returns the node into which the element should render and by default\\n     * creates and returns an open shadowRoot. Implement to customize where the\\n     * element's DOM is rendered. For example, to render into the element's\\n     * childNodes, return `this`.\\n     * @returns {Element|DocumentFragment} Returns a node into which to render.\\n     */\\n    createRenderRoot() {\\n        return this.attachShadow({ mode: 'open' });\\n    }\\n    /**\\n     * Applies styling to the element shadowRoot using the `static get styles`\\n     * property. Styling will apply using `shadowRoot.adoptedStyleSheets` where\\n     * available and will fallback otherwise. When Shadow DOM is polyfilled,\\n     * ShadyCSS scopes styles and adds them to the document. When Shadow DOM\\n     * is available but `adoptedStyleSheets` is not, styles are appended to the\\n     * end of the `shadowRoot` to [mimic spec\\n     * behavior](https://wicg.github.io/construct-stylesheets/#using-constructed-stylesheets).\\n     */\\n    adoptStyles() {\\n        const styles = this.constructor._styles;\\n        if (styles.length === 0) {\\n            return;\\n        }\\n        // There are three separate cases here based on Shadow DOM support.\\n        // (1) shadowRoot polyfilled: use ShadyCSS\\n        // (2) shadowRoot.adoptedStyleSheets available: use it.\\n        // (3) shadowRoot.adoptedStyleSheets polyfilled: append styles after\\n        // rendering\\n        if (window.ShadyCSS !== undefined && !window.ShadyCSS.nativeShadow) {\\n            window.ShadyCSS.ScopingShim.prepareAdoptedCssText(styles.map((s) => s.cssText), this.localName);\\n        }\\n        else if (_lib_css_tag_js__WEBPACK_IMPORTED_MODULE_4__[\\\"supportsAdoptingStyleSheets\\\"]) {\\n            this.renderRoot.adoptedStyleSheets =\\n                styles.map((s) => s.styleSheet);\\n        }\\n        else {\\n            // This must be done after rendering so the actual style insertion is done\\n            // in `update`.\\n            this._needsShimAdoptedStyleSheets = true;\\n        }\\n    }\\n    connectedCallback() {\\n        super.connectedCallback();\\n        // Note, first update/render handles styleElement so we only call this if\\n        // connected after first update.\\n        if (this.hasUpdated && window.ShadyCSS !== undefined) {\\n            window.ShadyCSS.styleElement(this);\\n        }\\n    }\\n    /**\\n     * Updates the element. This method reflects property values to attributes\\n     * and calls `render` to render DOM via lit-html. Setting properties inside\\n     * this method will *not* trigger another update.\\n     * @param _changedProperties Map of changed properties with old values\\n     */\\n    update(changedProperties) {\\n        // Setting properties in `render` should not trigger an update. Since\\n        // updates are allowed after super.update, it's important to call `render`\\n        // before that.\\n        const templateResult = this.render();\\n        super.update(changedProperties);\\n        // If render is not implemented by the component, don't call lit-html render\\n        if (templateResult !== renderNotImplemented) {\\n            this.constructor\\n                .render(templateResult, this.renderRoot, { scopeName: this.localName, eventContext: this });\\n        }\\n        // When native Shadow DOM is used but adoptedStyles are not supported,\\n        // insert styling after rendering to ensure adoptedStyles have highest\\n        // priority.\\n        if (this._needsShimAdoptedStyleSheets) {\\n            this._needsShimAdoptedStyleSheets = false;\\n            this.constructor._styles.forEach((s) => {\\n                const style = document.createElement('style');\\n                style.textContent = s.cssText;\\n                this.renderRoot.appendChild(style);\\n            });\\n        }\\n    }\\n    /**\\n     * Invoked on each update to perform rendering tasks. This method may return\\n     * any value renderable by lit-html's NodePart - typically a TemplateResult.\\n     * Setting properties inside this method will *not* trigger the element to\\n     * update.\\n     */\\n    render() {\\n        return renderNotImplemented;\\n    }\\n}\\n/**\\n * Ensure this class is marked as `finalized` as an optimization ensuring\\n * it will not needlessly try to `finalize`.\\n *\\n * Note this property name is a string to prevent breaking Closure JS Compiler\\n * optimizations. See updating-element.ts for more information.\\n */\\nLitElement['finalized'] = true;\\n/**\\n * Render method used to render the value to the element's DOM.\\n * @param result The value to render.\\n * @param container Node into which to render.\\n * @param options Element name.\\n * @nocollapse\\n */\\nLitElement.render = lit_html_lib_shady_render_js__WEBPACK_IMPORTED_MODULE_0__[\\\"render\\\"];\\n//# sourceMappingURL=lit-element.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-element/lit-element.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/directives/style-map.js\":\n/*!*******************************************************!*\\\n  !*** ./node_modules/lit-html/directives/style-map.js ***!\n  \\*******************************************************/\n/*! exports provided: styleMap */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"styleMap\\\", function() { return styleMap; });\\n/* harmony import */ var _lit_html_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../lit-html.js */ \\\"./node_modules/lit-html/lit-html.js\\\");\\n/**\\n * @license\\n * Copyright (c) 2018 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n\\n/**\\n * Stores the StyleInfo object applied to a given AttributePart.\\n * Used to unset existing values when a new StyleInfo object is applied.\\n */\\nconst previousStylePropertyCache = new WeakMap();\\n/**\\n * A directive that applies CSS properties to an element.\\n *\\n * `styleMap` can only be used in the `style` attribute and must be the only\\n * expression in the attribute. It takes the property names in the `styleInfo`\\n * object and adds the property values as CSS properties. Property names with\\n * dashes (`-`) are assumed to be valid CSS property names and set on the\\n * element's style object using `setProperty()`. Names without dashes are\\n * assumed to be camelCased JavaScript property names and set on the element's\\n * style object using property assignment, allowing the style object to\\n * translate JavaScript-style names to CSS property names.\\n *\\n * For example `styleMap({backgroundColor: 'red', 'border-top': '5px', '--size':\\n * '0'})` sets the `background-color`, `border-top` and `--size` properties.\\n *\\n * @param styleInfo {StyleInfo}\\n */\\nconst styleMap = Object(_lit_html_js__WEBPACK_IMPORTED_MODULE_0__[\\\"directive\\\"])((styleInfo) => (part) => {\\n    if (!(part instanceof _lit_html_js__WEBPACK_IMPORTED_MODULE_0__[\\\"AttributePart\\\"]) || (part instanceof _lit_html_js__WEBPACK_IMPORTED_MODULE_0__[\\\"PropertyPart\\\"]) ||\\n        part.committer.name !== 'style' || part.committer.parts.length > 1) {\\n        throw new Error('The `styleMap` directive must be used in the style attribute ' +\\n            'and must be the only part in the attribute.');\\n    }\\n    const { committer } = part;\\n    const { style } = committer.element;\\n    let previousStyleProperties = previousStylePropertyCache.get(part);\\n    if (previousStyleProperties === undefined) {\\n        // Write static styles once\\n        style.cssText = committer.strings.join(' ');\\n        previousStylePropertyCache.set(part, previousStyleProperties = new Set());\\n    }\\n    // Remove old properties that no longer exist in styleInfo\\n    // We use forEach() instead of for-of so that re don't require down-level\\n    // iteration.\\n    previousStyleProperties.forEach((name) => {\\n        if (!(name in styleInfo)) {\\n            previousStyleProperties.delete(name);\\n            if (name.indexOf('-') === -1) {\\n                // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n                style[name] = null;\\n            }\\n            else {\\n                style.removeProperty(name);\\n            }\\n        }\\n    });\\n    // Add or update properties\\n    for (const name in styleInfo) {\\n        previousStyleProperties.add(name);\\n        if (name.indexOf('-') === -1) {\\n            // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n            style[name] = styleInfo[name];\\n        }\\n        else {\\n            style.setProperty(name, styleInfo[name]);\\n        }\\n    }\\n});\\n//# sourceMappingURL=style-map.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/directives/style-map.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/default-template-processor.js\":\n/*!*****************************************************************!*\\\n  !*** ./node_modules/lit-html/lib/default-template-processor.js ***!\n  \\*****************************************************************/\n/*! exports provided: DefaultTemplateProcessor, defaultTemplateProcessor */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"DefaultTemplateProcessor\\\", function() { return DefaultTemplateProcessor; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"defaultTemplateProcessor\\\", function() { return defaultTemplateProcessor; });\\n/* harmony import */ var _parts_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./parts.js */ \\\"./node_modules/lit-html/lib/parts.js\\\");\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n\\n/**\\n * Creates Parts when a template is instantiated.\\n */\\nclass DefaultTemplateProcessor {\\n    /**\\n     * Create parts for an attribute-position binding, given the event, attribute\\n     * name, and string literals.\\n     *\\n     * @param element The element containing the binding\\n     * @param name  The attribute name\\n     * @param strings The string literals. There are always at least two strings,\\n     *   event for fully-controlled bindings with a single expression.\\n     */\\n    handleAttributeExpressions(element, name, strings, options) {\\n        const prefix = name[0];\\n        if (prefix === '.') {\\n            const committer = new _parts_js__WEBPACK_IMPORTED_MODULE_0__[\\\"PropertyCommitter\\\"](element, name.slice(1), strings);\\n            return committer.parts;\\n        }\\n        if (prefix === '@') {\\n            return [new _parts_js__WEBPACK_IMPORTED_MODULE_0__[\\\"EventPart\\\"](element, name.slice(1), options.eventContext)];\\n        }\\n        if (prefix === '?') {\\n            return [new _parts_js__WEBPACK_IMPORTED_MODULE_0__[\\\"BooleanAttributePart\\\"](element, name.slice(1), strings)];\\n        }\\n        const committer = new _parts_js__WEBPACK_IMPORTED_MODULE_0__[\\\"AttributeCommitter\\\"](element, name, strings);\\n        return committer.parts;\\n    }\\n    /**\\n     * Create parts for a text-position binding.\\n     * @param templateFactory\\n     */\\n    handleTextExpression(options) {\\n        return new _parts_js__WEBPACK_IMPORTED_MODULE_0__[\\\"NodePart\\\"](options);\\n    }\\n}\\nconst defaultTemplateProcessor = new DefaultTemplateProcessor();\\n//# sourceMappingURL=default-template-processor.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/default-template-processor.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/directive.js\":\n/*!************************************************!*\\\n  !*** ./node_modules/lit-html/lib/directive.js ***!\n  \\************************************************/\n/*! exports provided: directive, isDirective */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"directive\\\", function() { return directive; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"isDirective\\\", function() { return isDirective; });\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\nconst directives = new WeakMap();\\n/**\\n * Brands a function as a directive factory function so that lit-html will call\\n * the function during template rendering, rather than passing as a value.\\n *\\n * A _directive_ is a function that takes a Part as an argument. It has the\\n * signature: `(part: Part) => void`.\\n *\\n * A directive _factory_ is a function that takes arguments for data and\\n * configuration and returns a directive. Users of directive usually refer to\\n * the directive factory as the directive. For example, \\\"The repeat directive\\\".\\n *\\n * Usually a template author will invoke a directive factory in their template\\n * with relevant arguments, which will then return a directive function.\\n *\\n * Here's an example of using the `repeat()` directive factory that takes an\\n * array and a function to render an item:\\n *\\n * ```js\\n * html`<ul><${repeat(items, (item) => html`<li>${item}</li>`)}</ul>`\\n * ```\\n *\\n * When `repeat` is invoked, it returns a directive function that closes over\\n * `items` and the template function. When the outer template is rendered, the\\n * return directive function is called with the Part for the expression.\\n * `repeat` then performs it's custom logic to render multiple items.\\n *\\n * @param f The directive factory function. Must be a function that returns a\\n * function of the signature `(part: Part) => void`. The returned function will\\n * be called with the part object.\\n *\\n * @example\\n *\\n * import {directive, html} from 'lit-html';\\n *\\n * const immutable = directive((v) => (part) => {\\n *   if (part.value !== v) {\\n *     part.setValue(v)\\n *   }\\n * });\\n */\\nconst directive = (f) => ((...args) => {\\n    const d = f(...args);\\n    directives.set(d, true);\\n    return d;\\n});\\nconst isDirective = (o) => {\\n    return typeof o === 'function' && directives.has(o);\\n};\\n//# sourceMappingURL=directive.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/directive.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/dom.js\":\n/*!******************************************!*\\\n  !*** ./node_modules/lit-html/lib/dom.js ***!\n  \\******************************************/\n/*! exports provided: isCEPolyfill, reparentNodes, removeNodes */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"isCEPolyfill\\\", function() { return isCEPolyfill; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"reparentNodes\\\", function() { return reparentNodes; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"removeNodes\\\", function() { return removeNodes; });\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n/**\\n * True if the custom elements polyfill is in use.\\n */\\nconst isCEPolyfill = typeof window !== 'undefined' &&\\n    window.customElements != null &&\\n    window.customElements.polyfillWrapFlushCallback !==\\n        undefined;\\n/**\\n * Reparents nodes, starting from `start` (inclusive) to `end` (exclusive),\\n * into another container (could be the same container), before `before`. If\\n * `before` is null, it appends the nodes to the container.\\n */\\nconst reparentNodes = (container, start, end = null, before = null) => {\\n    while (start !== end) {\\n        const n = start.nextSibling;\\n        container.insertBefore(start, before);\\n        start = n;\\n    }\\n};\\n/**\\n * Removes nodes, starting from `start` (inclusive) to `end` (exclusive), from\\n * `container`.\\n */\\nconst removeNodes = (container, start, end = null) => {\\n    while (start !== end) {\\n        const n = start.nextSibling;\\n        container.removeChild(start);\\n        start = n;\\n    }\\n};\\n//# sourceMappingURL=dom.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/dom.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/modify-template.js\":\n/*!******************************************************!*\\\n  !*** ./node_modules/lit-html/lib/modify-template.js ***!\n  \\******************************************************/\n/*! exports provided: removeNodesFromTemplate, insertNodeIntoTemplate */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"removeNodesFromTemplate\\\", function() { return removeNodesFromTemplate; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"insertNodeIntoTemplate\\\", function() { return insertNodeIntoTemplate; });\\n/* harmony import */ var _template_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./template.js */ \\\"./node_modules/lit-html/lib/template.js\\\");\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n/**\\n * @module shady-render\\n */\\n\\nconst walkerNodeFilter = 133 /* NodeFilter.SHOW_{ELEMENT|COMMENT|TEXT} */;\\n/**\\n * Removes the list of nodes from a Template safely. In addition to removing\\n * nodes from the Template, the Template part indices are updated to match\\n * the mutated Template DOM.\\n *\\n * As the template is walked the removal state is tracked and\\n * part indices are adjusted as needed.\\n *\\n * div\\n *   div#1 (remove) <-- start removing (removing node is div#1)\\n *     div\\n *       div#2 (remove)  <-- continue removing (removing node is still div#1)\\n *         div\\n * div <-- stop removing since previous sibling is the removing node (div#1,\\n * removed 4 nodes)\\n */\\nfunction removeNodesFromTemplate(template, nodesToRemove) {\\n    const { element: { content }, parts } = template;\\n    const walker = document.createTreeWalker(content, walkerNodeFilter, null, false);\\n    let partIndex = nextActiveIndexInTemplateParts(parts);\\n    let part = parts[partIndex];\\n    let nodeIndex = -1;\\n    let removeCount = 0;\\n    const nodesToRemoveInTemplate = [];\\n    let currentRemovingNode = null;\\n    while (walker.nextNode()) {\\n        nodeIndex++;\\n        const node = walker.currentNode;\\n        // End removal if stepped past the removing node\\n        if (node.previousSibling === currentRemovingNode) {\\n            currentRemovingNode = null;\\n        }\\n        // A node to remove was found in the template\\n        if (nodesToRemove.has(node)) {\\n            nodesToRemoveInTemplate.push(node);\\n            // Track node we're removing\\n            if (currentRemovingNode === null) {\\n                currentRemovingNode = node;\\n            }\\n        }\\n        // When removing, increment count by which to adjust subsequent part indices\\n        if (currentRemovingNode !== null) {\\n            removeCount++;\\n        }\\n        while (part !== undefined && part.index === nodeIndex) {\\n            // If part is in a removed node deactivate it by setting index to -1 or\\n            // adjust the index as needed.\\n            part.index = currentRemovingNode !== null ? -1 : part.index - removeCount;\\n            // go to the next active part.\\n            partIndex = nextActiveIndexInTemplateParts(parts, partIndex);\\n            part = parts[partIndex];\\n        }\\n    }\\n    nodesToRemoveInTemplate.forEach((n) => n.parentNode.removeChild(n));\\n}\\nconst countNodes = (node) => {\\n    let count = (node.nodeType === 11 /* Node.DOCUMENT_FRAGMENT_NODE */) ? 0 : 1;\\n    const walker = document.createTreeWalker(node, walkerNodeFilter, null, false);\\n    while (walker.nextNode()) {\\n        count++;\\n    }\\n    return count;\\n};\\nconst nextActiveIndexInTemplateParts = (parts, startIndex = -1) => {\\n    for (let i = startIndex + 1; i < parts.length; i++) {\\n        const part = parts[i];\\n        if (Object(_template_js__WEBPACK_IMPORTED_MODULE_0__[\\\"isTemplatePartActive\\\"])(part)) {\\n            return i;\\n        }\\n    }\\n    return -1;\\n};\\n/**\\n * Inserts the given node into the Template, optionally before the given\\n * refNode. In addition to inserting the node into the Template, the Template\\n * part indices are updated to match the mutated Template DOM.\\n */\\nfunction insertNodeIntoTemplate(template, node, refNode = null) {\\n    const { element: { content }, parts } = template;\\n    // If there's no refNode, then put node at end of template.\\n    // No part indices need to be shifted in this case.\\n    if (refNode === null || refNode === undefined) {\\n        content.appendChild(node);\\n        return;\\n    }\\n    const walker = document.createTreeWalker(content, walkerNodeFilter, null, false);\\n    let partIndex = nextActiveIndexInTemplateParts(parts);\\n    let insertCount = 0;\\n    let walkerIndex = -1;\\n    while (walker.nextNode()) {\\n        walkerIndex++;\\n        const walkerNode = walker.currentNode;\\n        if (walkerNode === refNode) {\\n            insertCount = countNodes(node);\\n            refNode.parentNode.insertBefore(node, refNode);\\n        }\\n        while (partIndex !== -1 && parts[partIndex].index === walkerIndex) {\\n            // If we've inserted the node, simply adjust all subsequent parts\\n            if (insertCount > 0) {\\n                while (partIndex !== -1) {\\n                    parts[partIndex].index += insertCount;\\n                    partIndex = nextActiveIndexInTemplateParts(parts, partIndex);\\n                }\\n                return;\\n            }\\n            partIndex = nextActiveIndexInTemplateParts(parts, partIndex);\\n        }\\n    }\\n}\\n//# sourceMappingURL=modify-template.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/modify-template.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/part.js\":\n/*!*******************************************!*\\\n  !*** ./node_modules/lit-html/lib/part.js ***!\n  \\*******************************************/\n/*! exports provided: noChange, nothing */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"noChange\\\", function() { return noChange; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"nothing\\\", function() { return nothing; });\\n/**\\n * @license\\n * Copyright (c) 2018 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n/**\\n * A sentinel value that signals that a value was handled by a directive and\\n * should not be written to the DOM.\\n */\\nconst noChange = {};\\n/**\\n * A sentinel value that signals a NodePart to fully clear its content.\\n */\\nconst nothing = {};\\n//# sourceMappingURL=part.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/part.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/parts.js\":\n/*!********************************************!*\\\n  !*** ./node_modules/lit-html/lib/parts.js ***!\n  \\********************************************/\n/*! exports provided: isPrimitive, isIterable, AttributeCommitter, AttributePart, NodePart, BooleanAttributePart, PropertyCommitter, PropertyPart, EventPart */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"isPrimitive\\\", function() { return isPrimitive; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"isIterable\\\", function() { return isIterable; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"AttributeCommitter\\\", function() { return AttributeCommitter; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"AttributePart\\\", function() { return AttributePart; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"NodePart\\\", function() { return NodePart; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"BooleanAttributePart\\\", function() { return BooleanAttributePart; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"PropertyCommitter\\\", function() { return PropertyCommitter; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"PropertyPart\\\", function() { return PropertyPart; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"EventPart\\\", function() { return EventPart; });\\n/* harmony import */ var _directive_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./directive.js */ \\\"./node_modules/lit-html/lib/directive.js\\\");\\n/* harmony import */ var _dom_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./dom.js */ \\\"./node_modules/lit-html/lib/dom.js\\\");\\n/* harmony import */ var _part_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./part.js */ \\\"./node_modules/lit-html/lib/part.js\\\");\\n/* harmony import */ var _template_instance_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./template-instance.js */ \\\"./node_modules/lit-html/lib/template-instance.js\\\");\\n/* harmony import */ var _template_result_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./template-result.js */ \\\"./node_modules/lit-html/lib/template-result.js\\\");\\n/* harmony import */ var _template_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./template.js */ \\\"./node_modules/lit-html/lib/template.js\\\");\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n/**\\n * @module lit-html\\n */\\n\\n\\n\\n\\n\\n\\nconst isPrimitive = (value) => {\\n    return (value === null ||\\n        !(typeof value === 'object' || typeof value === 'function'));\\n};\\nconst isIterable = (value) => {\\n    return Array.isArray(value) ||\\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n        !!(value && value[Symbol.iterator]);\\n};\\n/**\\n * Writes attribute values to the DOM for a group of AttributeParts bound to a\\n * single attribute. The value is only set once even if there are multiple parts\\n * for an attribute.\\n */\\nclass AttributeCommitter {\\n    constructor(element, name, strings) {\\n        this.dirty = true;\\n        this.element = element;\\n        this.name = name;\\n        this.strings = strings;\\n        this.parts = [];\\n        for (let i = 0; i < strings.length - 1; i++) {\\n            this.parts[i] = this._createPart();\\n        }\\n    }\\n    /**\\n     * Creates a single part. Override this to create a differnt type of part.\\n     */\\n    _createPart() {\\n        return new AttributePart(this);\\n    }\\n    _getValue() {\\n        const strings = this.strings;\\n        const l = strings.length - 1;\\n        let text = '';\\n        for (let i = 0; i < l; i++) {\\n            text += strings[i];\\n            const part = this.parts[i];\\n            if (part !== undefined) {\\n                const v = part.value;\\n                if (isPrimitive(v) || !isIterable(v)) {\\n                    text += typeof v === 'string' ? v : String(v);\\n                }\\n                else {\\n                    for (const t of v) {\\n                        text += typeof t === 'string' ? t : String(t);\\n                    }\\n                }\\n            }\\n        }\\n        text += strings[l];\\n        return text;\\n    }\\n    commit() {\\n        if (this.dirty) {\\n            this.dirty = false;\\n            this.element.setAttribute(this.name, this._getValue());\\n        }\\n    }\\n}\\n/**\\n * A Part that controls all or part of an attribute value.\\n */\\nclass AttributePart {\\n    constructor(committer) {\\n        this.value = undefined;\\n        this.committer = committer;\\n    }\\n    setValue(value) {\\n        if (value !== _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"] && (!isPrimitive(value) || value !== this.value)) {\\n            this.value = value;\\n            // If the value is a not a directive, dirty the committer so that it'll\\n            // call setAttribute. If the value is a directive, it'll dirty the\\n            // committer if it calls setValue().\\n            if (!Object(_directive_js__WEBPACK_IMPORTED_MODULE_0__[\\\"isDirective\\\"])(value)) {\\n                this.committer.dirty = true;\\n            }\\n        }\\n    }\\n    commit() {\\n        while (Object(_directive_js__WEBPACK_IMPORTED_MODULE_0__[\\\"isDirective\\\"])(this.value)) {\\n            const directive = this.value;\\n            this.value = _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"];\\n            directive(this);\\n        }\\n        if (this.value === _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"]) {\\n            return;\\n        }\\n        this.committer.commit();\\n    }\\n}\\n/**\\n * A Part that controls a location within a Node tree. Like a Range, NodePart\\n * has start and end locations and can set and update the Nodes between those\\n * locations.\\n *\\n * NodeParts support several value types: primitives, Nodes, TemplateResults,\\n * as well as arrays and iterables of those types.\\n */\\nclass NodePart {\\n    constructor(options) {\\n        this.value = undefined;\\n        this.__pendingValue = undefined;\\n        this.options = options;\\n    }\\n    /**\\n     * Appends this part into a container.\\n     *\\n     * This part must be empty, as its contents are not automatically moved.\\n     */\\n    appendInto(container) {\\n        this.startNode = container.appendChild(Object(_template_js__WEBPACK_IMPORTED_MODULE_5__[\\\"createMarker\\\"])());\\n        this.endNode = container.appendChild(Object(_template_js__WEBPACK_IMPORTED_MODULE_5__[\\\"createMarker\\\"])());\\n    }\\n    /**\\n     * Inserts this part after the `ref` node (between `ref` and `ref`'s next\\n     * sibling). Both `ref` and its next sibling must be static, unchanging nodes\\n     * such as those that appear in a literal section of a template.\\n     *\\n     * This part must be empty, as its contents are not automatically moved.\\n     */\\n    insertAfterNode(ref) {\\n        this.startNode = ref;\\n        this.endNode = ref.nextSibling;\\n    }\\n    /**\\n     * Appends this part into a parent part.\\n     *\\n     * This part must be empty, as its contents are not automatically moved.\\n     */\\n    appendIntoPart(part) {\\n        part.__insert(this.startNode = Object(_template_js__WEBPACK_IMPORTED_MODULE_5__[\\\"createMarker\\\"])());\\n        part.__insert(this.endNode = Object(_template_js__WEBPACK_IMPORTED_MODULE_5__[\\\"createMarker\\\"])());\\n    }\\n    /**\\n     * Inserts this part after the `ref` part.\\n     *\\n     * This part must be empty, as its contents are not automatically moved.\\n     */\\n    insertAfterPart(ref) {\\n        ref.__insert(this.startNode = Object(_template_js__WEBPACK_IMPORTED_MODULE_5__[\\\"createMarker\\\"])());\\n        this.endNode = ref.endNode;\\n        ref.endNode = this.startNode;\\n    }\\n    setValue(value) {\\n        this.__pendingValue = value;\\n    }\\n    commit() {\\n        if (this.startNode.parentNode === null) {\\n            return;\\n        }\\n        while (Object(_directive_js__WEBPACK_IMPORTED_MODULE_0__[\\\"isDirective\\\"])(this.__pendingValue)) {\\n            const directive = this.__pendingValue;\\n            this.__pendingValue = _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"];\\n            directive(this);\\n        }\\n        const value = this.__pendingValue;\\n        if (value === _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"]) {\\n            return;\\n        }\\n        if (isPrimitive(value)) {\\n            if (value !== this.value) {\\n                this.__commitText(value);\\n            }\\n        }\\n        else if (value instanceof _template_result_js__WEBPACK_IMPORTED_MODULE_4__[\\\"TemplateResult\\\"]) {\\n            this.__commitTemplateResult(value);\\n        }\\n        else if (value instanceof Node) {\\n            this.__commitNode(value);\\n        }\\n        else if (isIterable(value)) {\\n            this.__commitIterable(value);\\n        }\\n        else if (value === _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"nothing\\\"]) {\\n            this.value = _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"nothing\\\"];\\n            this.clear();\\n        }\\n        else {\\n            // Fallback, will render the string representation\\n            this.__commitText(value);\\n        }\\n    }\\n    __insert(node) {\\n        this.endNode.parentNode.insertBefore(node, this.endNode);\\n    }\\n    __commitNode(value) {\\n        if (this.value === value) {\\n            return;\\n        }\\n        this.clear();\\n        this.__insert(value);\\n        this.value = value;\\n    }\\n    __commitText(value) {\\n        const node = this.startNode.nextSibling;\\n        value = value == null ? '' : value;\\n        // If `value` isn't already a string, we explicitly convert it here in case\\n        // it can't be implicitly converted - i.e. it's a symbol.\\n        const valueAsString = typeof value === 'string' ? value : String(value);\\n        if (node === this.endNode.previousSibling &&\\n            node.nodeType === 3 /* Node.TEXT_NODE */) {\\n            // If we only have a single text node between the markers, we can just\\n            // set its value, rather than replacing it.\\n            // TODO(justinfagnani): Can we just check if this.value is primitive?\\n            node.data = valueAsString;\\n        }\\n        else {\\n            this.__commitNode(document.createTextNode(valueAsString));\\n        }\\n        this.value = value;\\n    }\\n    __commitTemplateResult(value) {\\n        const template = this.options.templateFactory(value);\\n        if (this.value instanceof _template_instance_js__WEBPACK_IMPORTED_MODULE_3__[\\\"TemplateInstance\\\"] &&\\n            this.value.template === template) {\\n            this.value.update(value.values);\\n        }\\n        else {\\n            // Make sure we propagate the template processor from the TemplateResult\\n            // so that we use its syntax extension, etc. The template factory comes\\n            // from the render function options so that it can control template\\n            // caching and preprocessing.\\n            const instance = new _template_instance_js__WEBPACK_IMPORTED_MODULE_3__[\\\"TemplateInstance\\\"](template, value.processor, this.options);\\n            const fragment = instance._clone();\\n            instance.update(value.values);\\n            this.__commitNode(fragment);\\n            this.value = instance;\\n        }\\n    }\\n    __commitIterable(value) {\\n        // For an Iterable, we create a new InstancePart per item, then set its\\n        // value to the item. This is a little bit of overhead for every item in\\n        // an Iterable, but it lets us recurse easily and efficiently update Arrays\\n        // of TemplateResults that will be commonly returned from expressions like:\\n        // array.map((i) => html`${i}`), by reusing existing TemplateInstances.\\n        // If _value is an array, then the previous render was of an\\n        // iterable and _value will contain the NodeParts from the previous\\n        // render. If _value is not an array, clear this part and make a new\\n        // array for NodeParts.\\n        if (!Array.isArray(this.value)) {\\n            this.value = [];\\n            this.clear();\\n        }\\n        // Lets us keep track of how many items we stamped so we can clear leftover\\n        // items from a previous render\\n        const itemParts = this.value;\\n        let partIndex = 0;\\n        let itemPart;\\n        for (const item of value) {\\n            // Try to reuse an existing part\\n            itemPart = itemParts[partIndex];\\n            // If no existing part, create a new one\\n            if (itemPart === undefined) {\\n                itemPart = new NodePart(this.options);\\n                itemParts.push(itemPart);\\n                if (partIndex === 0) {\\n                    itemPart.appendIntoPart(this);\\n                }\\n                else {\\n                    itemPart.insertAfterPart(itemParts[partIndex - 1]);\\n                }\\n            }\\n            itemPart.setValue(item);\\n            itemPart.commit();\\n            partIndex++;\\n        }\\n        if (partIndex < itemParts.length) {\\n            // Truncate the parts array so _value reflects the current state\\n            itemParts.length = partIndex;\\n            this.clear(itemPart && itemPart.endNode);\\n        }\\n    }\\n    clear(startNode = this.startNode) {\\n        Object(_dom_js__WEBPACK_IMPORTED_MODULE_1__[\\\"removeNodes\\\"])(this.startNode.parentNode, startNode.nextSibling, this.endNode);\\n    }\\n}\\n/**\\n * Implements a boolean attribute, roughly as defined in the HTML\\n * specification.\\n *\\n * If the value is truthy, then the attribute is present with a value of\\n * ''. If the value is falsey, the attribute is removed.\\n */\\nclass BooleanAttributePart {\\n    constructor(element, name, strings) {\\n        this.value = undefined;\\n        this.__pendingValue = undefined;\\n        if (strings.length !== 2 || strings[0] !== '' || strings[1] !== '') {\\n            throw new Error('Boolean attributes can only contain a single expression');\\n        }\\n        this.element = element;\\n        this.name = name;\\n        this.strings = strings;\\n    }\\n    setValue(value) {\\n        this.__pendingValue = value;\\n    }\\n    commit() {\\n        while (Object(_directive_js__WEBPACK_IMPORTED_MODULE_0__[\\\"isDirective\\\"])(this.__pendingValue)) {\\n            const directive = this.__pendingValue;\\n            this.__pendingValue = _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"];\\n            directive(this);\\n        }\\n        if (this.__pendingValue === _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"]) {\\n            return;\\n        }\\n        const value = !!this.__pendingValue;\\n        if (this.value !== value) {\\n            if (value) {\\n                this.element.setAttribute(this.name, '');\\n            }\\n            else {\\n                this.element.removeAttribute(this.name);\\n            }\\n            this.value = value;\\n        }\\n        this.__pendingValue = _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"];\\n    }\\n}\\n/**\\n * Sets attribute values for PropertyParts, so that the value is only set once\\n * even if there are multiple parts for a property.\\n *\\n * If an expression controls the whole property value, then the value is simply\\n * assigned to the property under control. If there are string literals or\\n * multiple expressions, then the strings are expressions are interpolated into\\n * a string first.\\n */\\nclass PropertyCommitter extends AttributeCommitter {\\n    constructor(element, name, strings) {\\n        super(element, name, strings);\\n        this.single =\\n            (strings.length === 2 && strings[0] === '' && strings[1] === '');\\n    }\\n    _createPart() {\\n        return new PropertyPart(this);\\n    }\\n    _getValue() {\\n        if (this.single) {\\n            return this.parts[0].value;\\n        }\\n        return super._getValue();\\n    }\\n    commit() {\\n        if (this.dirty) {\\n            this.dirty = false;\\n            // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n            this.element[this.name] = this._getValue();\\n        }\\n    }\\n}\\nclass PropertyPart extends AttributePart {\\n}\\n// Detect event listener options support. If the `capture` property is read\\n// from the options object, then options are supported. If not, then the third\\n// argument to add/removeEventListener is interpreted as the boolean capture\\n// value so we should only pass the `capture` property.\\nlet eventOptionsSupported = false;\\n// Wrap into an IIFE because MS Edge <= v41 does not support having try/catch\\n// blocks right into the body of a module\\n(() => {\\n    try {\\n        const options = {\\n            get capture() {\\n                eventOptionsSupported = true;\\n                return false;\\n            }\\n        };\\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n        window.addEventListener('test', options, options);\\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n        window.removeEventListener('test', options, options);\\n    }\\n    catch (_e) {\\n        // event options not supported\\n    }\\n})();\\nclass EventPart {\\n    constructor(element, eventName, eventContext) {\\n        this.value = undefined;\\n        this.__pendingValue = undefined;\\n        this.element = element;\\n        this.eventName = eventName;\\n        this.eventContext = eventContext;\\n        this.__boundHandleEvent = (e) => this.handleEvent(e);\\n    }\\n    setValue(value) {\\n        this.__pendingValue = value;\\n    }\\n    commit() {\\n        while (Object(_directive_js__WEBPACK_IMPORTED_MODULE_0__[\\\"isDirective\\\"])(this.__pendingValue)) {\\n            const directive = this.__pendingValue;\\n            this.__pendingValue = _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"];\\n            directive(this);\\n        }\\n        if (this.__pendingValue === _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"]) {\\n            return;\\n        }\\n        const newListener = this.__pendingValue;\\n        const oldListener = this.value;\\n        const shouldRemoveListener = newListener == null ||\\n            oldListener != null &&\\n                (newListener.capture !== oldListener.capture ||\\n                    newListener.once !== oldListener.once ||\\n                    newListener.passive !== oldListener.passive);\\n        const shouldAddListener = newListener != null && (oldListener == null || shouldRemoveListener);\\n        if (shouldRemoveListener) {\\n            this.element.removeEventListener(this.eventName, this.__boundHandleEvent, this.__options);\\n        }\\n        if (shouldAddListener) {\\n            this.__options = getOptions(newListener);\\n            this.element.addEventListener(this.eventName, this.__boundHandleEvent, this.__options);\\n        }\\n        this.value = newListener;\\n        this.__pendingValue = _part_js__WEBPACK_IMPORTED_MODULE_2__[\\\"noChange\\\"];\\n    }\\n    handleEvent(event) {\\n        if (typeof this.value === 'function') {\\n            this.value.call(this.eventContext || this.element, event);\\n        }\\n        else {\\n            this.value.handleEvent(event);\\n        }\\n    }\\n}\\n// We copy options because of the inconsistent behavior of browsers when reading\\n// the third argument of add/removeEventListener. IE11 doesn't support options\\n// at all. Chrome 41 only reads `capture` if the argument is an object.\\nconst getOptions = (o) => o &&\\n    (eventOptionsSupported ?\\n        { capture: o.capture, passive: o.passive, once: o.once } :\\n        o.capture);\\n//# sourceMappingURL=parts.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/parts.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/render.js\":\n/*!*********************************************!*\\\n  !*** ./node_modules/lit-html/lib/render.js ***!\n  \\*********************************************/\n/*! exports provided: parts, render */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"parts\\\", function() { return parts; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"render\\\", function() { return render; });\\n/* harmony import */ var _dom_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./dom.js */ \\\"./node_modules/lit-html/lib/dom.js\\\");\\n/* harmony import */ var _parts_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./parts.js */ \\\"./node_modules/lit-html/lib/parts.js\\\");\\n/* harmony import */ var _template_factory_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./template-factory.js */ \\\"./node_modules/lit-html/lib/template-factory.js\\\");\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n/**\\n * @module lit-html\\n */\\n\\n\\n\\nconst parts = new WeakMap();\\n/**\\n * Renders a template result or other value to a container.\\n *\\n * To update a container with new values, reevaluate the template literal and\\n * call `render` with the new result.\\n *\\n * @param result Any value renderable by NodePart - typically a TemplateResult\\n *     created by evaluating a template tag like `html` or `svg`.\\n * @param container A DOM parent to render to. The entire contents are either\\n *     replaced, or efficiently updated if the same result type was previous\\n *     rendered there.\\n * @param options RenderOptions for the entire render tree rendered to this\\n *     container. Render options must *not* change between renders to the same\\n *     container, as those changes will not effect previously rendered DOM.\\n */\\nconst render = (result, container, options) => {\\n    let part = parts.get(container);\\n    if (part === undefined) {\\n        Object(_dom_js__WEBPACK_IMPORTED_MODULE_0__[\\\"removeNodes\\\"])(container, container.firstChild);\\n        parts.set(container, part = new _parts_js__WEBPACK_IMPORTED_MODULE_1__[\\\"NodePart\\\"](Object.assign({ templateFactory: _template_factory_js__WEBPACK_IMPORTED_MODULE_2__[\\\"templateFactory\\\"] }, options)));\\n        part.appendInto(container);\\n    }\\n    part.setValue(result);\\n    part.commit();\\n};\\n//# sourceMappingURL=render.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/render.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/shady-render.js\":\n/*!***************************************************!*\\\n  !*** ./node_modules/lit-html/lib/shady-render.js ***!\n  \\***************************************************/\n/*! exports provided: html, svg, TemplateResult, render */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"render\\\", function() { return render; });\\n/* harmony import */ var _dom_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./dom.js */ \\\"./node_modules/lit-html/lib/dom.js\\\");\\n/* harmony import */ var _modify_template_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./modify-template.js */ \\\"./node_modules/lit-html/lib/modify-template.js\\\");\\n/* harmony import */ var _render_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./render.js */ \\\"./node_modules/lit-html/lib/render.js\\\");\\n/* harmony import */ var _template_factory_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./template-factory.js */ \\\"./node_modules/lit-html/lib/template-factory.js\\\");\\n/* harmony import */ var _template_instance_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./template-instance.js */ \\\"./node_modules/lit-html/lib/template-instance.js\\\");\\n/* harmony import */ var _template_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./template.js */ \\\"./node_modules/lit-html/lib/template.js\\\");\\n/* harmony import */ var _lit_html_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lit-html.js */ \\\"./node_modules/lit-html/lit-html.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"html\\\", function() { return _lit_html_js__WEBPACK_IMPORTED_MODULE_6__[\\\"html\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"svg\\\", function() { return _lit_html_js__WEBPACK_IMPORTED_MODULE_6__[\\\"svg\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"TemplateResult\\\", function() { return _lit_html_js__WEBPACK_IMPORTED_MODULE_6__[\\\"TemplateResult\\\"]; });\\n\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n/**\\n * Module to add shady DOM/shady CSS polyfill support to lit-html template\\n * rendering. See the [[render]] method for details.\\n *\\n * @module shady-render\\n * @preferred\\n */\\n/**\\n * Do not remove this comment; it keeps typedoc from misplacing the module\\n * docs.\\n */\\n\\n\\n\\n\\n\\n\\n\\n// Get a key to lookup in `templateCaches`.\\nconst getTemplateCacheKey = (type, scopeName) => `${type}--${scopeName}`;\\nlet compatibleShadyCSSVersion = true;\\nif (typeof window.ShadyCSS === 'undefined') {\\n    compatibleShadyCSSVersion = false;\\n}\\nelse if (typeof window.ShadyCSS.prepareTemplateDom === 'undefined') {\\n    console.warn(`Incompatible ShadyCSS version detected. ` +\\n        `Please update to at least @webcomponents/webcomponentsjs@2.0.2 and ` +\\n        `@webcomponents/shadycss@1.3.1.`);\\n    compatibleShadyCSSVersion = false;\\n}\\n/**\\n * Template factory which scopes template DOM using ShadyCSS.\\n * @param scopeName {string}\\n */\\nconst shadyTemplateFactory = (scopeName) => (result) => {\\n    const cacheKey = getTemplateCacheKey(result.type, scopeName);\\n    let templateCache = _template_factory_js__WEBPACK_IMPORTED_MODULE_3__[\\\"templateCaches\\\"].get(cacheKey);\\n    if (templateCache === undefined) {\\n        templateCache = {\\n            stringsArray: new WeakMap(),\\n            keyString: new Map()\\n        };\\n        _template_factory_js__WEBPACK_IMPORTED_MODULE_3__[\\\"templateCaches\\\"].set(cacheKey, templateCache);\\n    }\\n    let template = templateCache.stringsArray.get(result.strings);\\n    if (template !== undefined) {\\n        return template;\\n    }\\n    const key = result.strings.join(_template_js__WEBPACK_IMPORTED_MODULE_5__[\\\"marker\\\"]);\\n    template = templateCache.keyString.get(key);\\n    if (template === undefined) {\\n        const element = result.getTemplateElement();\\n        if (compatibleShadyCSSVersion) {\\n            window.ShadyCSS.prepareTemplateDom(element, scopeName);\\n        }\\n        template = new _template_js__WEBPACK_IMPORTED_MODULE_5__[\\\"Template\\\"](result, element);\\n        templateCache.keyString.set(key, template);\\n    }\\n    templateCache.stringsArray.set(result.strings, template);\\n    return template;\\n};\\nconst TEMPLATE_TYPES = ['html', 'svg'];\\n/**\\n * Removes all style elements from Templates for the given scopeName.\\n */\\nconst removeStylesFromLitTemplates = (scopeName) => {\\n    TEMPLATE_TYPES.forEach((type) => {\\n        const templates = _template_factory_js__WEBPACK_IMPORTED_MODULE_3__[\\\"templateCaches\\\"].get(getTemplateCacheKey(type, scopeName));\\n        if (templates !== undefined) {\\n            templates.keyString.forEach((template) => {\\n                const { element: { content } } = template;\\n                // IE 11 doesn't support the iterable param Set constructor\\n                const styles = new Set();\\n                Array.from(content.querySelectorAll('style')).forEach((s) => {\\n                    styles.add(s);\\n                });\\n                Object(_modify_template_js__WEBPACK_IMPORTED_MODULE_1__[\\\"removeNodesFromTemplate\\\"])(template, styles);\\n            });\\n        }\\n    });\\n};\\nconst shadyRenderSet = new Set();\\n/**\\n * For the given scope name, ensures that ShadyCSS style scoping is performed.\\n * This is done just once per scope name so the fragment and template cannot\\n * be modified.\\n * (1) extracts styles from the rendered fragment and hands them to ShadyCSS\\n * to be scoped and appended to the document\\n * (2) removes style elements from all lit-html Templates for this scope name.\\n *\\n * Note, <style> elements can only be placed into templates for the\\n * initial rendering of the scope. If <style> elements are included in templates\\n * dynamically rendered to the scope (after the first scope render), they will\\n * not be scoped and the <style> will be left in the template and rendered\\n * output.\\n */\\nconst prepareTemplateStyles = (scopeName, renderedDOM, template) => {\\n    shadyRenderSet.add(scopeName);\\n    // If `renderedDOM` is stamped from a Template, then we need to edit that\\n    // Template's underlying template element. Otherwise, we create one here\\n    // to give to ShadyCSS, which still requires one while scoping.\\n    const templateElement = !!template ? template.element : document.createElement('template');\\n    // Move styles out of rendered DOM and store.\\n    const styles = renderedDOM.querySelectorAll('style');\\n    const { length } = styles;\\n    // If there are no styles, skip unnecessary work\\n    if (length === 0) {\\n        // Ensure prepareTemplateStyles is called to support adding\\n        // styles via `prepareAdoptedCssText` since that requires that\\n        // `prepareTemplateStyles` is called.\\n        //\\n        // ShadyCSS will only update styles containing @apply in the template\\n        // given to `prepareTemplateStyles`. If no lit Template was given,\\n        // ShadyCSS will not be able to update uses of @apply in any relevant\\n        // template. However, this is not a problem because we only create the\\n        // template for the purpose of supporting `prepareAdoptedCssText`,\\n        // which doesn't support @apply at all.\\n        window.ShadyCSS.prepareTemplateStyles(templateElement, scopeName);\\n        return;\\n    }\\n    const condensedStyle = document.createElement('style');\\n    // Collect styles into a single style. This helps us make sure ShadyCSS\\n    // manipulations will not prevent us from being able to fix up template\\n    // part indices.\\n    // NOTE: collecting styles is inefficient for browsers but ShadyCSS\\n    // currently does this anyway. When it does not, this should be changed.\\n    for (let i = 0; i < length; i++) {\\n        const style = styles[i];\\n        style.parentNode.removeChild(style);\\n        condensedStyle.textContent += style.textContent;\\n    }\\n    // Remove styles from nested templates in this scope.\\n    removeStylesFromLitTemplates(scopeName);\\n    // And then put the condensed style into the \\\"root\\\" template passed in as\\n    // `template`.\\n    const content = templateElement.content;\\n    if (!!template) {\\n        Object(_modify_template_js__WEBPACK_IMPORTED_MODULE_1__[\\\"insertNodeIntoTemplate\\\"])(template, condensedStyle, content.firstChild);\\n    }\\n    else {\\n        content.insertBefore(condensedStyle, content.firstChild);\\n    }\\n    // Note, it's important that ShadyCSS gets the template that `lit-html`\\n    // will actually render so that it can update the style inside when\\n    // needed (e.g. @apply native Shadow DOM case).\\n    window.ShadyCSS.prepareTemplateStyles(templateElement, scopeName);\\n    const style = content.querySelector('style');\\n    if (window.ShadyCSS.nativeShadow && style !== null) {\\n        // When in native Shadow DOM, ensure the style created by ShadyCSS is\\n        // included in initially rendered output (`renderedDOM`).\\n        renderedDOM.insertBefore(style.cloneNode(true), renderedDOM.firstChild);\\n    }\\n    else if (!!template) {\\n        // When no style is left in the template, parts will be broken as a\\n        // result. To fix this, we put back the style node ShadyCSS removed\\n        // and then tell lit to remove that node from the template.\\n        // There can be no style in the template in 2 cases (1) when Shady DOM\\n        // is in use, ShadyCSS removes all styles, (2) when native Shadow DOM\\n        // is in use ShadyCSS removes the style if it contains no content.\\n        // NOTE, ShadyCSS creates its own style so we can safely add/remove\\n        // `condensedStyle` here.\\n        content.insertBefore(condensedStyle, content.firstChild);\\n        const removes = new Set();\\n        removes.add(condensedStyle);\\n        Object(_modify_template_js__WEBPACK_IMPORTED_MODULE_1__[\\\"removeNodesFromTemplate\\\"])(template, removes);\\n    }\\n};\\n/**\\n * Extension to the standard `render` method which supports rendering\\n * to ShadowRoots when the ShadyDOM (https://github.com/webcomponents/shadydom)\\n * and ShadyCSS (https://github.com/webcomponents/shadycss) polyfills are used\\n * or when the webcomponentsjs\\n * (https://github.com/webcomponents/webcomponentsjs) polyfill is used.\\n *\\n * Adds a `scopeName` option which is used to scope element DOM and stylesheets\\n * when native ShadowDOM is unavailable. The `scopeName` will be added to\\n * the class attribute of all rendered DOM. In addition, any style elements will\\n * be automatically re-written with this `scopeName` selector and moved out\\n * of the rendered DOM and into the document `<head>`.\\n *\\n * It is common to use this render method in conjunction with a custom element\\n * which renders a shadowRoot. When this is done, typically the element's\\n * `localName` should be used as the `scopeName`.\\n *\\n * In addition to DOM scoping, ShadyCSS also supports a basic shim for css\\n * custom properties (needed only on older browsers like IE11) and a shim for\\n * a deprecated feature called `@apply` that supports applying a set of css\\n * custom properties to a given location.\\n *\\n * Usage considerations:\\n *\\n * * Part values in `<style>` elements are only applied the first time a given\\n * `scopeName` renders. Subsequent changes to parts in style elements will have\\n * no effect. Because of this, parts in style elements should only be used for\\n * values that will never change, for example parts that set scope-wide theme\\n * values or parts which render shared style elements.\\n *\\n * * Note, due to a limitation of the ShadyDOM polyfill, rendering in a\\n * custom element's `constructor` is not supported. Instead rendering should\\n * either done asynchronously, for example at microtask timing (for example\\n * `Promise.resolve()`), or be deferred until the first time the element's\\n * `connectedCallback` runs.\\n *\\n * Usage considerations when using shimmed custom properties or `@apply`:\\n *\\n * * Whenever any dynamic changes are made which affect\\n * css custom properties, `ShadyCSS.styleElement(element)` must be called\\n * to update the element. There are two cases when this is needed:\\n * (1) the element is connected to a new parent, (2) a class is added to the\\n * element that causes it to match different custom properties.\\n * To address the first case when rendering a custom element, `styleElement`\\n * should be called in the element's `connectedCallback`.\\n *\\n * * Shimmed custom properties may only be defined either for an entire\\n * shadowRoot (for example, in a `:host` rule) or via a rule that directly\\n * matches an element with a shadowRoot. In other words, instead of flowing from\\n * parent to child as do native css custom properties, shimmed custom properties\\n * flow only from shadowRoots to nested shadowRoots.\\n *\\n * * When using `@apply` mixing css shorthand property names with\\n * non-shorthand names (for example `border` and `border-width`) is not\\n * supported.\\n */\\nconst render = (result, container, options) => {\\n    if (!options || typeof options !== 'object' || !options.scopeName) {\\n        throw new Error('The `scopeName` option is required.');\\n    }\\n    const scopeName = options.scopeName;\\n    const hasRendered = _render_js__WEBPACK_IMPORTED_MODULE_2__[\\\"parts\\\"].has(container);\\n    const needsScoping = compatibleShadyCSSVersion &&\\n        container.nodeType === 11 /* Node.DOCUMENT_FRAGMENT_NODE */ &&\\n        !!container.host;\\n    // Handle first render to a scope specially...\\n    const firstScopeRender = needsScoping && !shadyRenderSet.has(scopeName);\\n    // On first scope render, render into a fragment; this cannot be a single\\n    // fragment that is reused since nested renders can occur synchronously.\\n    const renderContainer = firstScopeRender ? document.createDocumentFragment() : container;\\n    Object(_render_js__WEBPACK_IMPORTED_MODULE_2__[\\\"render\\\"])(result, renderContainer, Object.assign({ templateFactory: shadyTemplateFactory(scopeName) }, options));\\n    // When performing first scope render,\\n    // (1) We've rendered into a fragment so that there's a chance to\\n    // `prepareTemplateStyles` before sub-elements hit the DOM\\n    // (which might cause them to render based on a common pattern of\\n    // rendering in a custom element's `connectedCallback`);\\n    // (2) Scope the template with ShadyCSS one time only for this scope.\\n    // (3) Render the fragment into the container and make sure the\\n    // container knows its `part` is the one we just rendered. This ensures\\n    // DOM will be re-used on subsequent renders.\\n    if (firstScopeRender) {\\n        const part = _render_js__WEBPACK_IMPORTED_MODULE_2__[\\\"parts\\\"].get(renderContainer);\\n        _render_js__WEBPACK_IMPORTED_MODULE_2__[\\\"parts\\\"].delete(renderContainer);\\n        // ShadyCSS might have style sheets (e.g. from `prepareAdoptedCssText`)\\n        // that should apply to `renderContainer` even if the rendered value is\\n        // not a TemplateInstance. However, it will only insert scoped styles\\n        // into the document if `prepareTemplateStyles` has already been called\\n        // for the given scope name.\\n        const template = part.value instanceof _template_instance_js__WEBPACK_IMPORTED_MODULE_4__[\\\"TemplateInstance\\\"] ?\\n            part.value.template :\\n            undefined;\\n        prepareTemplateStyles(scopeName, renderContainer, template);\\n        Object(_dom_js__WEBPACK_IMPORTED_MODULE_0__[\\\"removeNodes\\\"])(container, container.firstChild);\\n        container.appendChild(renderContainer);\\n        _render_js__WEBPACK_IMPORTED_MODULE_2__[\\\"parts\\\"].set(container, part);\\n    }\\n    // After elements have hit the DOM, update styling if this is the\\n    // initial render to this container.\\n    // This is needed whenever dynamic changes are made so it would be\\n    // safest to do every render; however, this would regress performance\\n    // so we leave it up to the user to call `ShadyCSS.styleElement`\\n    // for dynamic changes.\\n    if (!hasRendered && needsScoping) {\\n        window.ShadyCSS.styleElement(container.host);\\n    }\\n};\\n//# sourceMappingURL=shady-render.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/shady-render.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/template-factory.js\":\n/*!*******************************************************!*\\\n  !*** ./node_modules/lit-html/lib/template-factory.js ***!\n  \\*******************************************************/\n/*! exports provided: templateFactory, templateCaches */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"templateFactory\\\", function() { return templateFactory; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"templateCaches\\\", function() { return templateCaches; });\\n/* harmony import */ var _template_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./template.js */ \\\"./node_modules/lit-html/lib/template.js\\\");\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n\\n/**\\n * The default TemplateFactory which caches Templates keyed on\\n * result.type and result.strings.\\n */\\nfunction templateFactory(result) {\\n    let templateCache = templateCaches.get(result.type);\\n    if (templateCache === undefined) {\\n        templateCache = {\\n            stringsArray: new WeakMap(),\\n            keyString: new Map()\\n        };\\n        templateCaches.set(result.type, templateCache);\\n    }\\n    let template = templateCache.stringsArray.get(result.strings);\\n    if (template !== undefined) {\\n        return template;\\n    }\\n    // If the TemplateStringsArray is new, generate a key from the strings\\n    // This key is shared between all templates with identical content\\n    const key = result.strings.join(_template_js__WEBPACK_IMPORTED_MODULE_0__[\\\"marker\\\"]);\\n    // Check if we already have a Template for this key\\n    template = templateCache.keyString.get(key);\\n    if (template === undefined) {\\n        // If we have not seen this key before, create a new Template\\n        template = new _template_js__WEBPACK_IMPORTED_MODULE_0__[\\\"Template\\\"](result, result.getTemplateElement());\\n        // Cache the Template for this key\\n        templateCache.keyString.set(key, template);\\n    }\\n    // Cache all future queries for this TemplateStringsArray\\n    templateCache.stringsArray.set(result.strings, template);\\n    return template;\\n}\\nconst templateCaches = new Map();\\n//# sourceMappingURL=template-factory.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/template-factory.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/template-instance.js\":\n/*!********************************************************!*\\\n  !*** ./node_modules/lit-html/lib/template-instance.js ***!\n  \\********************************************************/\n/*! exports provided: TemplateInstance */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"TemplateInstance\\\", function() { return TemplateInstance; });\\n/* harmony import */ var _dom_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./dom.js */ \\\"./node_modules/lit-html/lib/dom.js\\\");\\n/* harmony import */ var _template_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./template.js */ \\\"./node_modules/lit-html/lib/template.js\\\");\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n/**\\n * @module lit-html\\n */\\n\\n\\n/**\\n * An instance of a `Template` that can be attached to the DOM and updated\\n * with new values.\\n */\\nclass TemplateInstance {\\n    constructor(template, processor, options) {\\n        this.__parts = [];\\n        this.template = template;\\n        this.processor = processor;\\n        this.options = options;\\n    }\\n    update(values) {\\n        let i = 0;\\n        for (const part of this.__parts) {\\n            if (part !== undefined) {\\n                part.setValue(values[i]);\\n            }\\n            i++;\\n        }\\n        for (const part of this.__parts) {\\n            if (part !== undefined) {\\n                part.commit();\\n            }\\n        }\\n    }\\n    _clone() {\\n        // There are a number of steps in the lifecycle of a template instance's\\n        // DOM fragment:\\n        //  1. Clone - create the instance fragment\\n        //  2. Adopt - adopt into the main document\\n        //  3. Process - find part markers and create parts\\n        //  4. Upgrade - upgrade custom elements\\n        //  5. Update - set node, attribute, property, etc., values\\n        //  6. Connect - connect to the document. Optional and outside of this\\n        //     method.\\n        //\\n        // We have a few constraints on the ordering of these steps:\\n        //  * We need to upgrade before updating, so that property values will pass\\n        //    through any property setters.\\n        //  * We would like to process before upgrading so that we're sure that the\\n        //    cloned fragment is inert and not disturbed by self-modifying DOM.\\n        //  * We want custom elements to upgrade even in disconnected fragments.\\n        //\\n        // Given these constraints, with full custom elements support we would\\n        // prefer the order: Clone, Process, Adopt, Upgrade, Update, Connect\\n        //\\n        // But Safari does not implement CustomElementRegistry#upgrade, so we\\n        // can not implement that order and still have upgrade-before-update and\\n        // upgrade disconnected fragments. So we instead sacrifice the\\n        // process-before-upgrade constraint, since in Custom Elements v1 elements\\n        // must not modify their light DOM in the constructor. We still have issues\\n        // when co-existing with CEv0 elements like Polymer 1, and with polyfills\\n        // that don't strictly adhere to the no-modification rule because shadow\\n        // DOM, which may be created in the constructor, is emulated by being placed\\n        // in the light DOM.\\n        //\\n        // The resulting order is on native is: Clone, Adopt, Upgrade, Process,\\n        // Update, Connect. document.importNode() performs Clone, Adopt, and Upgrade\\n        // in one step.\\n        //\\n        // The Custom Elements v1 polyfill supports upgrade(), so the order when\\n        // polyfilled is the more ideal: Clone, Process, Adopt, Upgrade, Update,\\n        // Connect.\\n        const fragment = _dom_js__WEBPACK_IMPORTED_MODULE_0__[\\\"isCEPolyfill\\\"] ?\\n            this.template.element.content.cloneNode(true) :\\n            document.importNode(this.template.element.content, true);\\n        const stack = [];\\n        const parts = this.template.parts;\\n        // Edge needs all 4 parameters present; IE11 needs 3rd parameter to be null\\n        const walker = document.createTreeWalker(fragment, 133 /* NodeFilter.SHOW_{ELEMENT|COMMENT|TEXT} */, null, false);\\n        let partIndex = 0;\\n        let nodeIndex = 0;\\n        let part;\\n        let node = walker.nextNode();\\n        // Loop through all the nodes and parts of a template\\n        while (partIndex < parts.length) {\\n            part = parts[partIndex];\\n            if (!Object(_template_js__WEBPACK_IMPORTED_MODULE_1__[\\\"isTemplatePartActive\\\"])(part)) {\\n                this.__parts.push(undefined);\\n                partIndex++;\\n                continue;\\n            }\\n            // Progress the tree walker until we find our next part's node.\\n            // Note that multiple parts may share the same node (attribute parts\\n            // on a single element), so this loop may not run at all.\\n            while (nodeIndex < part.index) {\\n                nodeIndex++;\\n                if (node.nodeName === 'TEMPLATE') {\\n                    stack.push(node);\\n                    walker.currentNode = node.content;\\n                }\\n                if ((node = walker.nextNode()) === null) {\\n                    // We've exhausted the content inside a nested template element.\\n                    // Because we still have parts (the outer for-loop), we know:\\n                    // - There is a template in the stack\\n                    // - The walker will find a nextNode outside the template\\n                    walker.currentNode = stack.pop();\\n                    node = walker.nextNode();\\n                }\\n            }\\n            // We've arrived at our part's node.\\n            if (part.type === 'node') {\\n                const part = this.processor.handleTextExpression(this.options);\\n                part.insertAfterNode(node.previousSibling);\\n                this.__parts.push(part);\\n            }\\n            else {\\n                this.__parts.push(...this.processor.handleAttributeExpressions(node, part.name, part.strings, this.options));\\n            }\\n            partIndex++;\\n        }\\n        if (_dom_js__WEBPACK_IMPORTED_MODULE_0__[\\\"isCEPolyfill\\\"]) {\\n            document.adoptNode(fragment);\\n            customElements.upgrade(fragment);\\n        }\\n        return fragment;\\n    }\\n}\\n//# sourceMappingURL=template-instance.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/template-instance.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/template-result.js\":\n/*!******************************************************!*\\\n  !*** ./node_modules/lit-html/lib/template-result.js ***!\n  \\******************************************************/\n/*! exports provided: TemplateResult, SVGTemplateResult */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"TemplateResult\\\", function() { return TemplateResult; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"SVGTemplateResult\\\", function() { return SVGTemplateResult; });\\n/* harmony import */ var _dom_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./dom.js */ \\\"./node_modules/lit-html/lib/dom.js\\\");\\n/* harmony import */ var _template_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./template.js */ \\\"./node_modules/lit-html/lib/template.js\\\");\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n/**\\n * @module lit-html\\n */\\n\\n\\nconst commentMarker = ` ${_template_js__WEBPACK_IMPORTED_MODULE_1__[\\\"marker\\\"]} `;\\n/**\\n * The return type of `html`, which holds a Template and the values from\\n * interpolated expressions.\\n */\\nclass TemplateResult {\\n    constructor(strings, values, type, processor) {\\n        this.strings = strings;\\n        this.values = values;\\n        this.type = type;\\n        this.processor = processor;\\n    }\\n    /**\\n     * Returns a string of HTML used to create a `<template>` element.\\n     */\\n    getHTML() {\\n        const l = this.strings.length - 1;\\n        let html = '';\\n        let isCommentBinding = false;\\n        for (let i = 0; i < l; i++) {\\n            const s = this.strings[i];\\n            // For each binding we want to determine the kind of marker to insert\\n            // into the template source before it's parsed by the browser's HTML\\n            // parser. The marker type is based on whether the expression is in an\\n            // attribute, text, or comment position.\\n            //   * For node-position bindings we insert a comment with the marker\\n            //     sentinel as its text content, like <!--{{lit-guid}}-->.\\n            //   * For attribute bindings we insert just the marker sentinel for the\\n            //     first binding, so that we support unquoted attribute bindings.\\n            //     Subsequent bindings can use a comment marker because multi-binding\\n            //     attributes must be quoted.\\n            //   * For comment bindings we insert just the marker sentinel so we don't\\n            //     close the comment.\\n            //\\n            // The following code scans the template source, but is *not* an HTML\\n            // parser. We don't need to track the tree structure of the HTML, only\\n            // whether a binding is inside a comment, and if not, if it appears to be\\n            // the first binding in an attribute.\\n            const commentOpen = s.lastIndexOf('<!--');\\n            // We're in comment position if we have a comment open with no following\\n            // comment close. Because <-- can appear in an attribute value there can\\n            // be false positives.\\n            isCommentBinding = (commentOpen > -1 || isCommentBinding) &&\\n                s.indexOf('-->', commentOpen + 1) === -1;\\n            // Check to see if we have an attribute-like sequence preceding the\\n            // expression. This can match \\\"name=value\\\" like structures in text,\\n            // comments, and attribute values, so there can be false-positives.\\n            const attributeMatch = _template_js__WEBPACK_IMPORTED_MODULE_1__[\\\"lastAttributeNameRegex\\\"].exec(s);\\n            if (attributeMatch === null) {\\n                // We're only in this branch if we don't have a attribute-like\\n                // preceding sequence. For comments, this guards against unusual\\n                // attribute values like <div foo=\\\"<!--${'bar'}\\\">. Cases like\\n                // <!-- foo=${'bar'}--> are handled correctly in the attribute branch\\n                // below.\\n                html += s + (isCommentBinding ? commentMarker : _template_js__WEBPACK_IMPORTED_MODULE_1__[\\\"nodeMarker\\\"]);\\n            }\\n            else {\\n                // For attributes we use just a marker sentinel, and also append a\\n                // $lit$ suffix to the name to opt-out of attribute-specific parsing\\n                // that IE and Edge do for style and certain SVG attributes.\\n                html += s.substr(0, attributeMatch.index) + attributeMatch[1] +\\n                    attributeMatch[2] + _template_js__WEBPACK_IMPORTED_MODULE_1__[\\\"boundAttributeSuffix\\\"] + attributeMatch[3] +\\n                    _template_js__WEBPACK_IMPORTED_MODULE_1__[\\\"marker\\\"];\\n            }\\n        }\\n        html += this.strings[l];\\n        return html;\\n    }\\n    getTemplateElement() {\\n        const template = document.createElement('template');\\n        template.innerHTML = this.getHTML();\\n        return template;\\n    }\\n}\\n/**\\n * A TemplateResult for SVG fragments.\\n *\\n * This class wraps HTML in an `<svg>` tag in order to parse its contents in the\\n * SVG namespace, then modifies the template to remove the `<svg>` tag so that\\n * clones only container the original fragment.\\n */\\nclass SVGTemplateResult extends TemplateResult {\\n    getHTML() {\\n        return `<svg>${super.getHTML()}</svg>`;\\n    }\\n    getTemplateElement() {\\n        const template = super.getTemplateElement();\\n        const content = template.content;\\n        const svgElement = content.firstChild;\\n        content.removeChild(svgElement);\\n        Object(_dom_js__WEBPACK_IMPORTED_MODULE_0__[\\\"reparentNodes\\\"])(content, svgElement.firstChild);\\n        return template;\\n    }\\n}\\n//# sourceMappingURL=template-result.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/template-result.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lib/template.js\":\n/*!***********************************************!*\\\n  !*** ./node_modules/lit-html/lib/template.js ***!\n  \\***********************************************/\n/*! exports provided: marker, nodeMarker, markerRegex, boundAttributeSuffix, Template, isTemplatePartActive, createMarker, lastAttributeNameRegex */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"marker\\\", function() { return marker; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"nodeMarker\\\", function() { return nodeMarker; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"markerRegex\\\", function() { return markerRegex; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"boundAttributeSuffix\\\", function() { return boundAttributeSuffix; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"Template\\\", function() { return Template; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"isTemplatePartActive\\\", function() { return isTemplatePartActive; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"createMarker\\\", function() { return createMarker; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"lastAttributeNameRegex\\\", function() { return lastAttributeNameRegex; });\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n/**\\n * An expression marker with embedded unique key to avoid collision with\\n * possible text in templates.\\n */\\nconst marker = `{{lit-${String(Math.random()).slice(2)}}}`;\\n/**\\n * An expression marker used text-positions, multi-binding attributes, and\\n * attributes with markup-like text values.\\n */\\nconst nodeMarker = `<!--${marker}-->`;\\nconst markerRegex = new RegExp(`${marker}|${nodeMarker}`);\\n/**\\n * Suffix appended to all bound attribute names.\\n */\\nconst boundAttributeSuffix = '$lit$';\\n/**\\n * An updatable Template that tracks the location of dynamic parts.\\n */\\nclass Template {\\n    constructor(result, element) {\\n        this.parts = [];\\n        this.element = element;\\n        const nodesToRemove = [];\\n        const stack = [];\\n        // Edge needs all 4 parameters present; IE11 needs 3rd parameter to be null\\n        const walker = document.createTreeWalker(element.content, 133 /* NodeFilter.SHOW_{ELEMENT|COMMENT|TEXT} */, null, false);\\n        // Keeps track of the last index associated with a part. We try to delete\\n        // unnecessary nodes, but we never want to associate two different parts\\n        // to the same index. They must have a constant node between.\\n        let lastPartIndex = 0;\\n        let index = -1;\\n        let partIndex = 0;\\n        const { strings, values: { length } } = result;\\n        while (partIndex < length) {\\n            const node = walker.nextNode();\\n            if (node === null) {\\n                // We've exhausted the content inside a nested template element.\\n                // Because we still have parts (the outer for-loop), we know:\\n                // - There is a template in the stack\\n                // - The walker will find a nextNode outside the template\\n                walker.currentNode = stack.pop();\\n                continue;\\n            }\\n            index++;\\n            if (node.nodeType === 1 /* Node.ELEMENT_NODE */) {\\n                if (node.hasAttributes()) {\\n                    const attributes = node.attributes;\\n                    const { length } = attributes;\\n                    // Per\\n                    // https://developer.mozilla.org/en-US/docs/Web/API/NamedNodeMap,\\n                    // attributes are not guaranteed to be returned in document order.\\n                    // In particular, Edge/IE can return them out of order, so we cannot\\n                    // assume a correspondence between part index and attribute index.\\n                    let count = 0;\\n                    for (let i = 0; i < length; i++) {\\n                        if (endsWith(attributes[i].name, boundAttributeSuffix)) {\\n                            count++;\\n                        }\\n                    }\\n                    while (count-- > 0) {\\n                        // Get the template literal section leading up to the first\\n                        // expression in this attribute\\n                        const stringForPart = strings[partIndex];\\n                        // Find the attribute name\\n                        const name = lastAttributeNameRegex.exec(stringForPart)[2];\\n                        // Find the corresponding attribute\\n                        // All bound attributes have had a suffix added in\\n                        // TemplateResult#getHTML to opt out of special attribute\\n                        // handling. To look up the attribute value we also need to add\\n                        // the suffix.\\n                        const attributeLookupName = name.toLowerCase() + boundAttributeSuffix;\\n                        const attributeValue = node.getAttribute(attributeLookupName);\\n                        node.removeAttribute(attributeLookupName);\\n                        const statics = attributeValue.split(markerRegex);\\n                        this.parts.push({ type: 'attribute', index, name, strings: statics });\\n                        partIndex += statics.length - 1;\\n                    }\\n                }\\n                if (node.tagName === 'TEMPLATE') {\\n                    stack.push(node);\\n                    walker.currentNode = node.content;\\n                }\\n            }\\n            else if (node.nodeType === 3 /* Node.TEXT_NODE */) {\\n                const data = node.data;\\n                if (data.indexOf(marker) >= 0) {\\n                    const parent = node.parentNode;\\n                    const strings = data.split(markerRegex);\\n                    const lastIndex = strings.length - 1;\\n                    // Generate a new text node for each literal section\\n                    // These nodes are also used as the markers for node parts\\n                    for (let i = 0; i < lastIndex; i++) {\\n                        let insert;\\n                        let s = strings[i];\\n                        if (s === '') {\\n                            insert = createMarker();\\n                        }\\n                        else {\\n                            const match = lastAttributeNameRegex.exec(s);\\n                            if (match !== null && endsWith(match[2], boundAttributeSuffix)) {\\n                                s = s.slice(0, match.index) + match[1] +\\n                                    match[2].slice(0, -boundAttributeSuffix.length) + match[3];\\n                            }\\n                            insert = document.createTextNode(s);\\n                        }\\n                        parent.insertBefore(insert, node);\\n                        this.parts.push({ type: 'node', index: ++index });\\n                    }\\n                    // If there's no text, we must insert a comment to mark our place.\\n                    // Else, we can trust it will stick around after cloning.\\n                    if (strings[lastIndex] === '') {\\n                        parent.insertBefore(createMarker(), node);\\n                        nodesToRemove.push(node);\\n                    }\\n                    else {\\n                        node.data = strings[lastIndex];\\n                    }\\n                    // We have a part for each match found\\n                    partIndex += lastIndex;\\n                }\\n            }\\n            else if (node.nodeType === 8 /* Node.COMMENT_NODE */) {\\n                if (node.data === marker) {\\n                    const parent = node.parentNode;\\n                    // Add a new marker node to be the startNode of the Part if any of\\n                    // the following are true:\\n                    //  * We don't have a previousSibling\\n                    //  * The previousSibling is already the start of a previous part\\n                    if (node.previousSibling === null || index === lastPartIndex) {\\n                        index++;\\n                        parent.insertBefore(createMarker(), node);\\n                    }\\n                    lastPartIndex = index;\\n                    this.parts.push({ type: 'node', index });\\n                    // If we don't have a nextSibling, keep this node so we have an end.\\n                    // Else, we can remove it to save future costs.\\n                    if (node.nextSibling === null) {\\n                        node.data = '';\\n                    }\\n                    else {\\n                        nodesToRemove.push(node);\\n                        index--;\\n                    }\\n                    partIndex++;\\n                }\\n                else {\\n                    let i = -1;\\n                    while ((i = node.data.indexOf(marker, i + 1)) !== -1) {\\n                        // Comment node has a binding marker inside, make an inactive part\\n                        // The binding won't work, but subsequent bindings will\\n                        // TODO (justinfagnani): consider whether it's even worth it to\\n                        // make bindings in comments work\\n                        this.parts.push({ type: 'node', index: -1 });\\n                        partIndex++;\\n                    }\\n                }\\n            }\\n        }\\n        // Remove text binding nodes after the walk to not disturb the TreeWalker\\n        for (const n of nodesToRemove) {\\n            n.parentNode.removeChild(n);\\n        }\\n    }\\n}\\nconst endsWith = (str, suffix) => {\\n    const index = str.length - suffix.length;\\n    return index >= 0 && str.slice(index) === suffix;\\n};\\nconst isTemplatePartActive = (part) => part.index !== -1;\\n// Allows `document.createComment('')` to be renamed for a\\n// small manual size-savings.\\nconst createMarker = () => document.createComment('');\\n/**\\n * This regex extracts the attribute name preceding an attribute-position\\n * expression. It does this by matching the syntax allowed for attributes\\n * against the string literal directly preceding the expression, assuming that\\n * the expression is in an attribute-value position.\\n *\\n * See attributes in the HTML spec:\\n * https://www.w3.org/TR/html5/syntax.html#elements-attributes\\n *\\n * \\\" \\\\x09\\\\x0a\\\\x0c\\\\x0d\\\" are HTML space characters:\\n * https://www.w3.org/TR/html5/infrastructure.html#space-characters\\n *\\n * \\\"\\\\0-\\\\x1F\\\\x7F-\\\\x9F\\\" are Unicode control characters, which includes every\\n * space character except \\\" \\\".\\n *\\n * So an attribute is:\\n *  * The name: any character except a control character, space character, ('),\\n *    (\\\"), \\\">\\\", \\\"=\\\", or \\\"/\\\"\\n *  * Followed by zero or more space characters\\n *  * Followed by \\\"=\\\"\\n *  * Followed by zero or more space characters\\n *  * Followed by:\\n *    * Any character except space, ('), (\\\"), \\\"<\\\", \\\">\\\", \\\"=\\\", (`), or\\n *    * (\\\") then any non-(\\\"), or\\n *    * (') then any non-(')\\n */\\nconst lastAttributeNameRegex = \\n// eslint-disable-next-line no-control-regex\\n/([ \\\\x09\\\\x0a\\\\x0c\\\\x0d])([^\\\\0-\\\\x1F\\\\x7F-\\\\x9F \\\"'>=/]+)([ \\\\x09\\\\x0a\\\\x0c\\\\x0d]*=[ \\\\x09\\\\x0a\\\\x0c\\\\x0d]*(?:[^ \\\\x09\\\\x0a\\\\x0c\\\\x0d\\\"'`<>=]*|\\\"[^\\\"]*|'[^']*))$/;\\n//# sourceMappingURL=template.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lib/template.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/lit-html/lit-html.js\":\n/*!*******************************************!*\\\n  !*** ./node_modules/lit-html/lit-html.js ***!\n  \\*******************************************/\n/*! exports provided: DefaultTemplateProcessor, defaultTemplateProcessor, directive, isDirective, removeNodes, reparentNodes, noChange, nothing, AttributeCommitter, AttributePart, BooleanAttributePart, EventPart, isIterable, isPrimitive, NodePart, PropertyCommitter, PropertyPart, parts, render, templateCaches, templateFactory, TemplateInstance, SVGTemplateResult, TemplateResult, createMarker, isTemplatePartActive, Template, html, svg */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"html\\\", function() { return html; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"svg\\\", function() { return svg; });\\n/* harmony import */ var _lib_default_template_processor_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./lib/default-template-processor.js */ \\\"./node_modules/lit-html/lib/default-template-processor.js\\\");\\n/* harmony import */ var _lib_template_result_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./lib/template-result.js */ \\\"./node_modules/lit-html/lib/template-result.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"DefaultTemplateProcessor\\\", function() { return _lib_default_template_processor_js__WEBPACK_IMPORTED_MODULE_0__[\\\"DefaultTemplateProcessor\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"defaultTemplateProcessor\\\", function() { return _lib_default_template_processor_js__WEBPACK_IMPORTED_MODULE_0__[\\\"defaultTemplateProcessor\\\"]; });\\n\\n/* harmony import */ var _lib_directive_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./lib/directive.js */ \\\"./node_modules/lit-html/lib/directive.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"directive\\\", function() { return _lib_directive_js__WEBPACK_IMPORTED_MODULE_2__[\\\"directive\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"isDirective\\\", function() { return _lib_directive_js__WEBPACK_IMPORTED_MODULE_2__[\\\"isDirective\\\"]; });\\n\\n/* harmony import */ var _lib_dom_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./lib/dom.js */ \\\"./node_modules/lit-html/lib/dom.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"removeNodes\\\", function() { return _lib_dom_js__WEBPACK_IMPORTED_MODULE_3__[\\\"removeNodes\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"reparentNodes\\\", function() { return _lib_dom_js__WEBPACK_IMPORTED_MODULE_3__[\\\"reparentNodes\\\"]; });\\n\\n/* harmony import */ var _lib_part_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./lib/part.js */ \\\"./node_modules/lit-html/lib/part.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"noChange\\\", function() { return _lib_part_js__WEBPACK_IMPORTED_MODULE_4__[\\\"noChange\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"nothing\\\", function() { return _lib_part_js__WEBPACK_IMPORTED_MODULE_4__[\\\"nothing\\\"]; });\\n\\n/* harmony import */ var _lib_parts_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./lib/parts.js */ \\\"./node_modules/lit-html/lib/parts.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"AttributeCommitter\\\", function() { return _lib_parts_js__WEBPACK_IMPORTED_MODULE_5__[\\\"AttributeCommitter\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"AttributePart\\\", function() { return _lib_parts_js__WEBPACK_IMPORTED_MODULE_5__[\\\"AttributePart\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"BooleanAttributePart\\\", function() { return _lib_parts_js__WEBPACK_IMPORTED_MODULE_5__[\\\"BooleanAttributePart\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"EventPart\\\", function() { return _lib_parts_js__WEBPACK_IMPORTED_MODULE_5__[\\\"EventPart\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"isIterable\\\", function() { return _lib_parts_js__WEBPACK_IMPORTED_MODULE_5__[\\\"isIterable\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"isPrimitive\\\", function() { return _lib_parts_js__WEBPACK_IMPORTED_MODULE_5__[\\\"isPrimitive\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"NodePart\\\", function() { return _lib_parts_js__WEBPACK_IMPORTED_MODULE_5__[\\\"NodePart\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"PropertyCommitter\\\", function() { return _lib_parts_js__WEBPACK_IMPORTED_MODULE_5__[\\\"PropertyCommitter\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"PropertyPart\\\", function() { return _lib_parts_js__WEBPACK_IMPORTED_MODULE_5__[\\\"PropertyPart\\\"]; });\\n\\n/* harmony import */ var _lib_render_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./lib/render.js */ \\\"./node_modules/lit-html/lib/render.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"parts\\\", function() { return _lib_render_js__WEBPACK_IMPORTED_MODULE_6__[\\\"parts\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"render\\\", function() { return _lib_render_js__WEBPACK_IMPORTED_MODULE_6__[\\\"render\\\"]; });\\n\\n/* harmony import */ var _lib_template_factory_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./lib/template-factory.js */ \\\"./node_modules/lit-html/lib/template-factory.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"templateCaches\\\", function() { return _lib_template_factory_js__WEBPACK_IMPORTED_MODULE_7__[\\\"templateCaches\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"templateFactory\\\", function() { return _lib_template_factory_js__WEBPACK_IMPORTED_MODULE_7__[\\\"templateFactory\\\"]; });\\n\\n/* harmony import */ var _lib_template_instance_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./lib/template-instance.js */ \\\"./node_modules/lit-html/lib/template-instance.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"TemplateInstance\\\", function() { return _lib_template_instance_js__WEBPACK_IMPORTED_MODULE_8__[\\\"TemplateInstance\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"SVGTemplateResult\\\", function() { return _lib_template_result_js__WEBPACK_IMPORTED_MODULE_1__[\\\"SVGTemplateResult\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"TemplateResult\\\", function() { return _lib_template_result_js__WEBPACK_IMPORTED_MODULE_1__[\\\"TemplateResult\\\"]; });\\n\\n/* harmony import */ var _lib_template_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./lib/template.js */ \\\"./node_modules/lit-html/lib/template.js\\\");\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"createMarker\\\", function() { return _lib_template_js__WEBPACK_IMPORTED_MODULE_9__[\\\"createMarker\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"isTemplatePartActive\\\", function() { return _lib_template_js__WEBPACK_IMPORTED_MODULE_9__[\\\"isTemplatePartActive\\\"]; });\\n\\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \\\"Template\\\", function() { return _lib_template_js__WEBPACK_IMPORTED_MODULE_9__[\\\"Template\\\"]; });\\n\\n/**\\n * @license\\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\\n * This code may only be used under the BSD style license found at\\n * http://polymer.github.io/LICENSE.txt\\n * The complete set of authors may be found at\\n * http://polymer.github.io/AUTHORS.txt\\n * The complete set of contributors may be found at\\n * http://polymer.github.io/CONTRIBUTORS.txt\\n * Code distributed by Google as part of the polymer project is also\\n * subject to an additional IP rights grant found at\\n * http://polymer.github.io/PATENTS.txt\\n */\\n/**\\n *\\n * Main lit-html module.\\n *\\n * Main exports:\\n *\\n * -  [[html]]\\n * -  [[svg]]\\n * -  [[render]]\\n *\\n * @module lit-html\\n * @preferred\\n */\\n/**\\n * Do not remove this comment; it keeps typedoc from misplacing the module\\n * docs.\\n */\\n\\n\\n\\n\\n// TODO(justinfagnani): remove line when we get NodePart moving methods\\n\\n\\n\\n\\n\\n\\n\\n\\n// IMPORTANT: do not change the property name or the assignment expression.\\n// This line will be used in regexes to search for lit-html usage.\\n// TODO(justinfagnani): inject version number at build time\\nif (typeof window !== 'undefined') {\\n    (window['litHtmlVersions'] || (window['litHtmlVersions'] = [])).push('1.2.1');\\n}\\n/**\\n * Interprets a template literal as an HTML template that can efficiently\\n * render to and update a container.\\n */\\nconst html = (strings, ...values) => new _lib_template_result_js__WEBPACK_IMPORTED_MODULE_1__[\\\"TemplateResult\\\"](strings, values, 'html', _lib_default_template_processor_js__WEBPACK_IMPORTED_MODULE_0__[\\\"defaultTemplateProcessor\\\"]);\\n/**\\n * Interprets a template literal as an SVG template that can efficiently\\n * render to and update a container.\\n */\\nconst svg = (strings, ...values) => new _lib_template_result_js__WEBPACK_IMPORTED_MODULE_1__[\\\"SVGTemplateResult\\\"](strings, values, 'svg', _lib_default_template_processor_js__WEBPACK_IMPORTED_MODULE_0__[\\\"defaultTemplateProcessor\\\"]);\\n//# sourceMappingURL=lit-html.js.map\\n\\n//# sourceURL=webpack:///./node_modules/lit-html/lit-html.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/object-inspect/index.js\":\n/*!**********************************************!*\\\n  !*** ./node_modules/object-inspect/index.js ***!\n  \\**********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"var hasMap = typeof Map === 'function' && Map.prototype;\\nvar mapSizeDescriptor = Object.getOwnPropertyDescriptor && hasMap ? Object.getOwnPropertyDescriptor(Map.prototype, 'size') : null;\\nvar mapSize = hasMap && mapSizeDescriptor && typeof mapSizeDescriptor.get === 'function' ? mapSizeDescriptor.get : null;\\nvar mapForEach = hasMap && Map.prototype.forEach;\\nvar hasSet = typeof Set === 'function' && Set.prototype;\\nvar setSizeDescriptor = Object.getOwnPropertyDescriptor && hasSet ? Object.getOwnPropertyDescriptor(Set.prototype, 'size') : null;\\nvar setSize = hasSet && setSizeDescriptor && typeof setSizeDescriptor.get === 'function' ? setSizeDescriptor.get : null;\\nvar setForEach = hasSet && Set.prototype.forEach;\\nvar hasWeakMap = typeof WeakMap === 'function' && WeakMap.prototype;\\nvar weakMapHas = hasWeakMap ? WeakMap.prototype.has : null;\\nvar hasWeakSet = typeof WeakSet === 'function' && WeakSet.prototype;\\nvar weakSetHas = hasWeakSet ? WeakSet.prototype.has : null;\\nvar booleanValueOf = Boolean.prototype.valueOf;\\nvar objectToString = Object.prototype.toString;\\nvar functionToString = Function.prototype.toString;\\nvar match = String.prototype.match;\\nvar bigIntValueOf = typeof BigInt === 'function' ? BigInt.prototype.valueOf : null;\\n\\nvar inspectCustom = __webpack_require__(/*! ./util.inspect */ 0).custom;\\nvar inspectSymbol = inspectCustom && isSymbol(inspectCustom) ? inspectCustom : null;\\n\\nmodule.exports = function inspect_(obj, options, depth, seen) {\\n    var opts = options || {};\\n\\n    if (has(opts, 'quoteStyle') && (opts.quoteStyle !== 'single' && opts.quoteStyle !== 'double')) {\\n        throw new TypeError('option \\\"quoteStyle\\\" must be \\\"single\\\" or \\\"double\\\"');\\n    }\\n    if (\\n        has(opts, 'maxStringLength') && (typeof opts.maxStringLength === 'number'\\n            ? opts.maxStringLength < 0 && opts.maxStringLength !== Infinity\\n            : opts.maxStringLength !== null\\n        )\\n    ) {\\n        throw new TypeError('option \\\"maxStringLength\\\", if provided, must be a positive integer, Infinity, or `null`');\\n    }\\n    var customInspect = has(opts, 'customInspect') ? opts.customInspect : true;\\n    if (typeof customInspect !== 'boolean') {\\n        throw new TypeError('option \\\"customInspect\\\", if provided, must be `true` or `false`');\\n    }\\n\\n    if (\\n        has(opts, 'indent')\\n        && opts.indent !== null\\n        && opts.indent !== '\\\\t'\\n        && !(parseInt(opts.indent, 10) === opts.indent && opts.indent > 0)\\n    ) {\\n        throw new TypeError('options \\\"indent\\\" must be \\\"\\\\\\\\t\\\", an integer > 0, or `null`');\\n    }\\n\\n    if (typeof obj === 'undefined') {\\n        return 'undefined';\\n    }\\n    if (obj === null) {\\n        return 'null';\\n    }\\n    if (typeof obj === 'boolean') {\\n        return obj ? 'true' : 'false';\\n    }\\n\\n    if (typeof obj === 'string') {\\n        return inspectString(obj, opts);\\n    }\\n    if (typeof obj === 'number') {\\n        if (obj === 0) {\\n            return Infinity / obj > 0 ? '0' : '-0';\\n        }\\n        return String(obj);\\n    }\\n    if (typeof obj === 'bigint') { // eslint-disable-line valid-typeof\\n        return String(obj) + 'n';\\n    }\\n\\n    var maxDepth = typeof opts.depth === 'undefined' ? 5 : opts.depth;\\n    if (typeof depth === 'undefined') { depth = 0; }\\n    if (depth >= maxDepth && maxDepth > 0 && typeof obj === 'object') {\\n        return isArray(obj) ? '[Array]' : '[Object]';\\n    }\\n\\n    var indent = getIndent(opts, depth);\\n\\n    if (typeof seen === 'undefined') {\\n        seen = [];\\n    } else if (indexOf(seen, obj) >= 0) {\\n        return '[Circular]';\\n    }\\n\\n    function inspect(value, from, noIndent) {\\n        if (from) {\\n            seen = seen.slice();\\n            seen.push(from);\\n        }\\n        if (noIndent) {\\n            var newOpts = {\\n                depth: opts.depth\\n            };\\n            if (has(opts, 'quoteStyle')) {\\n                newOpts.quoteStyle = opts.quoteStyle;\\n            }\\n            return inspect_(value, newOpts, depth + 1, seen);\\n        }\\n        return inspect_(value, opts, depth + 1, seen);\\n    }\\n\\n    if (typeof obj === 'function') {\\n        var name = nameOf(obj);\\n        return '[Function' + (name ? ': ' + name : ' (anonymous)') + ']';\\n    }\\n    if (isSymbol(obj)) {\\n        var symString = Symbol.prototype.toString.call(obj);\\n        return typeof obj === 'object' ? markBoxed(symString) : symString;\\n    }\\n    if (isElement(obj)) {\\n        var s = '<' + String(obj.nodeName).toLowerCase();\\n        var attrs = obj.attributes || [];\\n        for (var i = 0; i < attrs.length; i++) {\\n            s += ' ' + attrs[i].name + '=' + wrapQuotes(quote(attrs[i].value), 'double', opts);\\n        }\\n        s += '>';\\n        if (obj.childNodes && obj.childNodes.length) { s += '...'; }\\n        s += '</' + String(obj.nodeName).toLowerCase() + '>';\\n        return s;\\n    }\\n    if (isArray(obj)) {\\n        if (obj.length === 0) { return '[]'; }\\n        var xs = arrObjKeys(obj, inspect);\\n        if (indent && !singleLineValues(xs)) {\\n            return '[' + indentedJoin(xs, indent) + ']';\\n        }\\n        return '[ ' + xs.join(', ') + ' ]';\\n    }\\n    if (isError(obj)) {\\n        var parts = arrObjKeys(obj, inspect);\\n        if (parts.length === 0) { return '[' + String(obj) + ']'; }\\n        return '{ [' + String(obj) + '] ' + parts.join(', ') + ' }';\\n    }\\n    if (typeof obj === 'object' && customInspect) {\\n        if (inspectSymbol && typeof obj[inspectSymbol] === 'function') {\\n            return obj[inspectSymbol]();\\n        } else if (typeof obj.inspect === 'function') {\\n            return obj.inspect();\\n        }\\n    }\\n    if (isMap(obj)) {\\n        var mapParts = [];\\n        mapForEach.call(obj, function (value, key) {\\n            mapParts.push(inspect(key, obj, true) + ' => ' + inspect(value, obj));\\n        });\\n        return collectionOf('Map', mapSize.call(obj), mapParts, indent);\\n    }\\n    if (isSet(obj)) {\\n        var setParts = [];\\n        setForEach.call(obj, function (value) {\\n            setParts.push(inspect(value, obj));\\n        });\\n        return collectionOf('Set', setSize.call(obj), setParts, indent);\\n    }\\n    if (isWeakMap(obj)) {\\n        return weakCollectionOf('WeakMap');\\n    }\\n    if (isWeakSet(obj)) {\\n        return weakCollectionOf('WeakSet');\\n    }\\n    if (isNumber(obj)) {\\n        return markBoxed(inspect(Number(obj)));\\n    }\\n    if (isBigInt(obj)) {\\n        return markBoxed(inspect(bigIntValueOf.call(obj)));\\n    }\\n    if (isBoolean(obj)) {\\n        return markBoxed(booleanValueOf.call(obj));\\n    }\\n    if (isString(obj)) {\\n        return markBoxed(inspect(String(obj)));\\n    }\\n    if (!isDate(obj) && !isRegExp(obj)) {\\n        var ys = arrObjKeys(obj, inspect);\\n        if (ys.length === 0) { return '{}'; }\\n        if (indent) {\\n            return '{' + indentedJoin(ys, indent) + '}';\\n        }\\n        return '{ ' + ys.join(', ') + ' }';\\n    }\\n    return String(obj);\\n};\\n\\nfunction wrapQuotes(s, defaultStyle, opts) {\\n    var quoteChar = (opts.quoteStyle || defaultStyle) === 'double' ? '\\\"' : \\\"'\\\";\\n    return quoteChar + s + quoteChar;\\n}\\n\\nfunction quote(s) {\\n    return String(s).replace(/\\\"/g, '&quot;');\\n}\\n\\nfunction isArray(obj) { return toStr(obj) === '[object Array]'; }\\nfunction isDate(obj) { return toStr(obj) === '[object Date]'; }\\nfunction isRegExp(obj) { return toStr(obj) === '[object RegExp]'; }\\nfunction isError(obj) { return toStr(obj) === '[object Error]'; }\\nfunction isSymbol(obj) { return toStr(obj) === '[object Symbol]'; }\\nfunction isString(obj) { return toStr(obj) === '[object String]'; }\\nfunction isNumber(obj) { return toStr(obj) === '[object Number]'; }\\nfunction isBigInt(obj) { return toStr(obj) === '[object BigInt]'; }\\nfunction isBoolean(obj) { return toStr(obj) === '[object Boolean]'; }\\n\\nvar hasOwn = Object.prototype.hasOwnProperty || function (key) { return key in this; };\\nfunction has(obj, key) {\\n    return hasOwn.call(obj, key);\\n}\\n\\nfunction toStr(obj) {\\n    return objectToString.call(obj);\\n}\\n\\nfunction nameOf(f) {\\n    if (f.name) { return f.name; }\\n    var m = match.call(functionToString.call(f), /^function\\\\s*([\\\\w$]+)/);\\n    if (m) { return m[1]; }\\n    return null;\\n}\\n\\nfunction indexOf(xs, x) {\\n    if (xs.indexOf) { return xs.indexOf(x); }\\n    for (var i = 0, l = xs.length; i < l; i++) {\\n        if (xs[i] === x) { return i; }\\n    }\\n    return -1;\\n}\\n\\nfunction isMap(x) {\\n    if (!mapSize || !x || typeof x !== 'object') {\\n        return false;\\n    }\\n    try {\\n        mapSize.call(x);\\n        try {\\n            setSize.call(x);\\n        } catch (s) {\\n            return true;\\n        }\\n        return x instanceof Map; // core-js workaround, pre-v2.5.0\\n    } catch (e) {}\\n    return false;\\n}\\n\\nfunction isWeakMap(x) {\\n    if (!weakMapHas || !x || typeof x !== 'object') {\\n        return false;\\n    }\\n    try {\\n        weakMapHas.call(x, weakMapHas);\\n        try {\\n            weakSetHas.call(x, weakSetHas);\\n        } catch (s) {\\n            return true;\\n        }\\n        return x instanceof WeakMap; // core-js workaround, pre-v2.5.0\\n    } catch (e) {}\\n    return false;\\n}\\n\\nfunction isSet(x) {\\n    if (!setSize || !x || typeof x !== 'object') {\\n        return false;\\n    }\\n    try {\\n        setSize.call(x);\\n        try {\\n            mapSize.call(x);\\n        } catch (m) {\\n            return true;\\n        }\\n        return x instanceof Set; // core-js workaround, pre-v2.5.0\\n    } catch (e) {}\\n    return false;\\n}\\n\\nfunction isWeakSet(x) {\\n    if (!weakSetHas || !x || typeof x !== 'object') {\\n        return false;\\n    }\\n    try {\\n        weakSetHas.call(x, weakSetHas);\\n        try {\\n            weakMapHas.call(x, weakMapHas);\\n        } catch (s) {\\n            return true;\\n        }\\n        return x instanceof WeakSet; // core-js workaround, pre-v2.5.0\\n    } catch (e) {}\\n    return false;\\n}\\n\\nfunction isElement(x) {\\n    if (!x || typeof x !== 'object') { return false; }\\n    if (typeof HTMLElement !== 'undefined' && x instanceof HTMLElement) {\\n        return true;\\n    }\\n    return typeof x.nodeName === 'string' && typeof x.getAttribute === 'function';\\n}\\n\\nfunction inspectString(str, opts) {\\n    if (str.length > opts.maxStringLength) {\\n        var remaining = str.length - opts.maxStringLength;\\n        var trailer = '... ' + remaining + ' more character' + (remaining > 1 ? 's' : '');\\n        return inspectString(str.slice(0, opts.maxStringLength), opts) + trailer;\\n    }\\n    // eslint-disable-next-line no-control-regex\\n    var s = str.replace(/(['\\\\\\\\])/g, '\\\\\\\\$1').replace(/[\\\\x00-\\\\x1f]/g, lowbyte);\\n    return wrapQuotes(s, 'single', opts);\\n}\\n\\nfunction lowbyte(c) {\\n    var n = c.charCodeAt(0);\\n    var x = {\\n        8: 'b', 9: 't', 10: 'n', 12: 'f', 13: 'r'\\n    }[n];\\n    if (x) { return '\\\\\\\\' + x; }\\n    return '\\\\\\\\x' + (n < 0x10 ? '0' : '') + n.toString(16);\\n}\\n\\nfunction markBoxed(str) {\\n    return 'Object(' + str + ')';\\n}\\n\\nfunction weakCollectionOf(type) {\\n    return type + ' { ? }';\\n}\\n\\nfunction collectionOf(type, size, entries, indent) {\\n    var joinedEntries = indent ? indentedJoin(entries, indent) : entries.join(', ');\\n    return type + ' (' + size + ') {' + joinedEntries + '}';\\n}\\n\\nfunction singleLineValues(xs) {\\n    for (var i = 0; i < xs.length; i++) {\\n        if (indexOf(xs[i], '\\\\n') >= 0) {\\n            return false;\\n        }\\n    }\\n    return true;\\n}\\n\\nfunction getIndent(opts, depth) {\\n    var baseIndent;\\n    if (opts.indent === '\\\\t') {\\n        baseIndent = '\\\\t';\\n    } else if (typeof opts.indent === 'number' && opts.indent > 0) {\\n        baseIndent = Array(opts.indent + 1).join(' ');\\n    } else {\\n        return null;\\n    }\\n    return {\\n        base: baseIndent,\\n        prev: Array(depth + 1).join(baseIndent)\\n    };\\n}\\n\\nfunction indentedJoin(xs, indent) {\\n    if (xs.length === 0) { return ''; }\\n    var lineJoiner = '\\\\n' + indent.prev + indent.base;\\n    return lineJoiner + xs.join(',' + lineJoiner) + '\\\\n' + indent.prev;\\n}\\n\\nfunction arrObjKeys(obj, inspect) {\\n    var isArr = isArray(obj);\\n    var xs = [];\\n    if (isArr) {\\n        xs.length = obj.length;\\n        for (var i = 0; i < obj.length; i++) {\\n            xs[i] = has(obj, i) ? inspect(obj[i], obj) : '';\\n        }\\n    }\\n    for (var key in obj) { // eslint-disable-line no-restricted-syntax\\n        if (!has(obj, key)) { continue; } // eslint-disable-line no-restricted-syntax, no-continue\\n        if (isArr && String(Number(key)) === key && key < obj.length) { continue; } // eslint-disable-line no-restricted-syntax, no-continue\\n        if ((/[^\\\\w$]/).test(key)) {\\n            xs.push(inspect(key, obj) + ': ' + inspect(obj[key], obj));\\n        } else {\\n            xs.push(key + ': ' + inspect(obj[key], obj));\\n        }\\n    }\\n    return xs;\\n}\\n\\n\\n//# sourceURL=webpack:///./node_modules/object-inspect/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/object-is/implementation.js\":\n/*!**************************************************!*\\\n  !*** ./node_modules/object-is/implementation.js ***!\n  \\**************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar numberIsNaN = function (value) {\\n\\treturn value !== value;\\n};\\n\\nmodule.exports = function is(a, b) {\\n\\tif (a === 0 && b === 0) {\\n\\t\\treturn 1 / a === 1 / b;\\n\\t}\\n\\tif (a === b) {\\n\\t\\treturn true;\\n\\t}\\n\\tif (numberIsNaN(a) && numberIsNaN(b)) {\\n\\t\\treturn true;\\n\\t}\\n\\treturn false;\\n};\\n\\n\\n\\n//# sourceURL=webpack:///./node_modules/object-is/implementation.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/object-is/index.js\":\n/*!*****************************************!*\\\n  !*** ./node_modules/object-is/index.js ***!\n  \\*****************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar define = __webpack_require__(/*! define-properties */ \\\"./node_modules/define-properties/index.js\\\");\\nvar callBind = __webpack_require__(/*! es-abstract/helpers/callBind */ \\\"./node_modules/es-abstract/helpers/callBind.js\\\");\\n\\nvar implementation = __webpack_require__(/*! ./implementation */ \\\"./node_modules/object-is/implementation.js\\\");\\nvar getPolyfill = __webpack_require__(/*! ./polyfill */ \\\"./node_modules/object-is/polyfill.js\\\");\\nvar shim = __webpack_require__(/*! ./shim */ \\\"./node_modules/object-is/shim.js\\\");\\n\\nvar polyfill = callBind(getPolyfill(), Object);\\n\\ndefine(polyfill, {\\n\\tgetPolyfill: getPolyfill,\\n\\timplementation: implementation,\\n\\tshim: shim\\n});\\n\\nmodule.exports = polyfill;\\n\\n\\n//# sourceURL=webpack:///./node_modules/object-is/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/object-is/polyfill.js\":\n/*!********************************************!*\\\n  !*** ./node_modules/object-is/polyfill.js ***!\n  \\********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar implementation = __webpack_require__(/*! ./implementation */ \\\"./node_modules/object-is/implementation.js\\\");\\n\\nmodule.exports = function getPolyfill() {\\n\\treturn typeof Object.is === 'function' ? Object.is : implementation;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/object-is/polyfill.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/object-is/shim.js\":\n/*!****************************************!*\\\n  !*** ./node_modules/object-is/shim.js ***!\n  \\****************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar getPolyfill = __webpack_require__(/*! ./polyfill */ \\\"./node_modules/object-is/polyfill.js\\\");\\nvar define = __webpack_require__(/*! define-properties */ \\\"./node_modules/define-properties/index.js\\\");\\n\\nmodule.exports = function shimObjectIs() {\\n\\tvar polyfill = getPolyfill();\\n\\tdefine(Object, { is: polyfill }, {\\n\\t\\tis: function testObjectIs() {\\n\\t\\t\\treturn Object.is !== polyfill;\\n\\t\\t}\\n\\t});\\n\\treturn polyfill;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/object-is/shim.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/object-keys/implementation.js\":\n/*!****************************************************!*\\\n  !*** ./node_modules/object-keys/implementation.js ***!\n  \\****************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar keysShim;\\nif (!Object.keys) {\\n\\t// modified from https://github.com/es-shims/es5-shim\\n\\tvar has = Object.prototype.hasOwnProperty;\\n\\tvar toStr = Object.prototype.toString;\\n\\tvar isArgs = __webpack_require__(/*! ./isArguments */ \\\"./node_modules/object-keys/isArguments.js\\\"); // eslint-disable-line global-require\\n\\tvar isEnumerable = Object.prototype.propertyIsEnumerable;\\n\\tvar hasDontEnumBug = !isEnumerable.call({ toString: null }, 'toString');\\n\\tvar hasProtoEnumBug = isEnumerable.call(function () {}, 'prototype');\\n\\tvar dontEnums = [\\n\\t\\t'toString',\\n\\t\\t'toLocaleString',\\n\\t\\t'valueOf',\\n\\t\\t'hasOwnProperty',\\n\\t\\t'isPrototypeOf',\\n\\t\\t'propertyIsEnumerable',\\n\\t\\t'constructor'\\n\\t];\\n\\tvar equalsConstructorPrototype = function (o) {\\n\\t\\tvar ctor = o.constructor;\\n\\t\\treturn ctor && ctor.prototype === o;\\n\\t};\\n\\tvar excludedKeys = {\\n\\t\\t$applicationCache: true,\\n\\t\\t$console: true,\\n\\t\\t$external: true,\\n\\t\\t$frame: true,\\n\\t\\t$frameElement: true,\\n\\t\\t$frames: true,\\n\\t\\t$innerHeight: true,\\n\\t\\t$innerWidth: true,\\n\\t\\t$onmozfullscreenchange: true,\\n\\t\\t$onmozfullscreenerror: true,\\n\\t\\t$outerHeight: true,\\n\\t\\t$outerWidth: true,\\n\\t\\t$pageXOffset: true,\\n\\t\\t$pageYOffset: true,\\n\\t\\t$parent: true,\\n\\t\\t$scrollLeft: true,\\n\\t\\t$scrollTop: true,\\n\\t\\t$scrollX: true,\\n\\t\\t$scrollY: true,\\n\\t\\t$self: true,\\n\\t\\t$webkitIndexedDB: true,\\n\\t\\t$webkitStorageInfo: true,\\n\\t\\t$window: true\\n\\t};\\n\\tvar hasAutomationEqualityBug = (function () {\\n\\t\\t/* global window */\\n\\t\\tif (typeof window === 'undefined') { return false; }\\n\\t\\tfor (var k in window) {\\n\\t\\t\\ttry {\\n\\t\\t\\t\\tif (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') {\\n\\t\\t\\t\\t\\ttry {\\n\\t\\t\\t\\t\\t\\tequalsConstructorPrototype(window[k]);\\n\\t\\t\\t\\t\\t} catch (e) {\\n\\t\\t\\t\\t\\t\\treturn true;\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t}\\n\\t\\t\\t} catch (e) {\\n\\t\\t\\t\\treturn true;\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\treturn false;\\n\\t}());\\n\\tvar equalsConstructorPrototypeIfNotBuggy = function (o) {\\n\\t\\t/* global window */\\n\\t\\tif (typeof window === 'undefined' || !hasAutomationEqualityBug) {\\n\\t\\t\\treturn equalsConstructorPrototype(o);\\n\\t\\t}\\n\\t\\ttry {\\n\\t\\t\\treturn equalsConstructorPrototype(o);\\n\\t\\t} catch (e) {\\n\\t\\t\\treturn false;\\n\\t\\t}\\n\\t};\\n\\n\\tkeysShim = function keys(object) {\\n\\t\\tvar isObject = object !== null && typeof object === 'object';\\n\\t\\tvar isFunction = toStr.call(object) === '[object Function]';\\n\\t\\tvar isArguments = isArgs(object);\\n\\t\\tvar isString = isObject && toStr.call(object) === '[object String]';\\n\\t\\tvar theKeys = [];\\n\\n\\t\\tif (!isObject && !isFunction && !isArguments) {\\n\\t\\t\\tthrow new TypeError('Object.keys called on a non-object');\\n\\t\\t}\\n\\n\\t\\tvar skipProto = hasProtoEnumBug && isFunction;\\n\\t\\tif (isString && object.length > 0 && !has.call(object, 0)) {\\n\\t\\t\\tfor (var i = 0; i < object.length; ++i) {\\n\\t\\t\\t\\ttheKeys.push(String(i));\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\tif (isArguments && object.length > 0) {\\n\\t\\t\\tfor (var j = 0; j < object.length; ++j) {\\n\\t\\t\\t\\ttheKeys.push(String(j));\\n\\t\\t\\t}\\n\\t\\t} else {\\n\\t\\t\\tfor (var name in object) {\\n\\t\\t\\t\\tif (!(skipProto && name === 'prototype') && has.call(object, name)) {\\n\\t\\t\\t\\t\\ttheKeys.push(String(name));\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\tif (hasDontEnumBug) {\\n\\t\\t\\tvar skipConstructor = equalsConstructorPrototypeIfNotBuggy(object);\\n\\n\\t\\t\\tfor (var k = 0; k < dontEnums.length; ++k) {\\n\\t\\t\\t\\tif (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) {\\n\\t\\t\\t\\t\\ttheKeys.push(dontEnums[k]);\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\treturn theKeys;\\n\\t};\\n}\\nmodule.exports = keysShim;\\n\\n\\n//# sourceURL=webpack:///./node_modules/object-keys/implementation.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/object-keys/index.js\":\n/*!*******************************************!*\\\n  !*** ./node_modules/object-keys/index.js ***!\n  \\*******************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar slice = Array.prototype.slice;\\nvar isArgs = __webpack_require__(/*! ./isArguments */ \\\"./node_modules/object-keys/isArguments.js\\\");\\n\\nvar origKeys = Object.keys;\\nvar keysShim = origKeys ? function keys(o) { return origKeys(o); } : __webpack_require__(/*! ./implementation */ \\\"./node_modules/object-keys/implementation.js\\\");\\n\\nvar originalKeys = Object.keys;\\n\\nkeysShim.shim = function shimObjectKeys() {\\n\\tif (Object.keys) {\\n\\t\\tvar keysWorksWithArguments = (function () {\\n\\t\\t\\t// Safari 5.0 bug\\n\\t\\t\\tvar args = Object.keys(arguments);\\n\\t\\t\\treturn args && args.length === arguments.length;\\n\\t\\t}(1, 2));\\n\\t\\tif (!keysWorksWithArguments) {\\n\\t\\t\\tObject.keys = function keys(object) { // eslint-disable-line func-name-matching\\n\\t\\t\\t\\tif (isArgs(object)) {\\n\\t\\t\\t\\t\\treturn originalKeys(slice.call(object));\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\treturn originalKeys(object);\\n\\t\\t\\t};\\n\\t\\t}\\n\\t} else {\\n\\t\\tObject.keys = keysShim;\\n\\t}\\n\\treturn Object.keys || keysShim;\\n};\\n\\nmodule.exports = keysShim;\\n\\n\\n//# sourceURL=webpack:///./node_modules/object-keys/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/object-keys/isArguments.js\":\n/*!*************************************************!*\\\n  !*** ./node_modules/object-keys/isArguments.js ***!\n  \\*************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar toStr = Object.prototype.toString;\\n\\nmodule.exports = function isArguments(value) {\\n\\tvar str = toStr.call(value);\\n\\tvar isArgs = str === '[object Arguments]';\\n\\tif (!isArgs) {\\n\\t\\tisArgs = str !== '[object Array]' &&\\n\\t\\t\\tvalue !== null &&\\n\\t\\t\\ttypeof value === 'object' &&\\n\\t\\t\\ttypeof value.length === 'number' &&\\n\\t\\t\\tvalue.length >= 0 &&\\n\\t\\t\\ttoStr.call(value.callee) === '[object Function]';\\n\\t}\\n\\treturn isArgs;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/object-keys/isArguments.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/object.assign/implementation.js\":\n/*!******************************************************!*\\\n  !*** ./node_modules/object.assign/implementation.js ***!\n  \\******************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\n// modified from https://github.com/es-shims/es6-shim\\nvar keys = __webpack_require__(/*! object-keys */ \\\"./node_modules/object-keys/index.js\\\");\\nvar bind = __webpack_require__(/*! function-bind */ \\\"./node_modules/function-bind/index.js\\\");\\nvar canBeObject = function (obj) {\\n\\treturn typeof obj !== 'undefined' && obj !== null;\\n};\\nvar hasSymbols = __webpack_require__(/*! has-symbols/shams */ \\\"./node_modules/has-symbols/shams.js\\\")();\\nvar toObject = Object;\\nvar push = bind.call(Function.call, Array.prototype.push);\\nvar propIsEnumerable = bind.call(Function.call, Object.prototype.propertyIsEnumerable);\\nvar originalGetSymbols = hasSymbols ? Object.getOwnPropertySymbols : null;\\n\\nmodule.exports = function assign(target, source1) {\\n\\tif (!canBeObject(target)) { throw new TypeError('target must be an object'); }\\n\\tvar objTarget = toObject(target);\\n\\tvar s, source, i, props, syms, value, key;\\n\\tfor (s = 1; s < arguments.length; ++s) {\\n\\t\\tsource = toObject(arguments[s]);\\n\\t\\tprops = keys(source);\\n\\t\\tvar getSymbols = hasSymbols && (Object.getOwnPropertySymbols || originalGetSymbols);\\n\\t\\tif (getSymbols) {\\n\\t\\t\\tsyms = getSymbols(source);\\n\\t\\t\\tfor (i = 0; i < syms.length; ++i) {\\n\\t\\t\\t\\tkey = syms[i];\\n\\t\\t\\t\\tif (propIsEnumerable(source, key)) {\\n\\t\\t\\t\\t\\tpush(props, key);\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\tfor (i = 0; i < props.length; ++i) {\\n\\t\\t\\tkey = props[i];\\n\\t\\t\\tvalue = source[key];\\n\\t\\t\\tif (propIsEnumerable(source, key)) {\\n\\t\\t\\t\\tobjTarget[key] = value;\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n\\treturn objTarget;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/object.assign/implementation.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/object.assign/index.js\":\n/*!*********************************************!*\\\n  !*** ./node_modules/object.assign/index.js ***!\n  \\*********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar defineProperties = __webpack_require__(/*! define-properties */ \\\"./node_modules/define-properties/index.js\\\");\\n\\nvar implementation = __webpack_require__(/*! ./implementation */ \\\"./node_modules/object.assign/implementation.js\\\");\\nvar getPolyfill = __webpack_require__(/*! ./polyfill */ \\\"./node_modules/object.assign/polyfill.js\\\");\\nvar shim = __webpack_require__(/*! ./shim */ \\\"./node_modules/object.assign/shim.js\\\");\\n\\nvar polyfill = getPolyfill();\\n\\ndefineProperties(polyfill, {\\n\\tgetPolyfill: getPolyfill,\\n\\timplementation: implementation,\\n\\tshim: shim\\n});\\n\\nmodule.exports = polyfill;\\n\\n\\n//# sourceURL=webpack:///./node_modules/object.assign/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/object.assign/polyfill.js\":\n/*!************************************************!*\\\n  !*** ./node_modules/object.assign/polyfill.js ***!\n  \\************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar implementation = __webpack_require__(/*! ./implementation */ \\\"./node_modules/object.assign/implementation.js\\\");\\n\\nvar lacksProperEnumerationOrder = function () {\\n\\tif (!Object.assign) {\\n\\t\\treturn false;\\n\\t}\\n\\t// v8, specifically in node 4.x, has a bug with incorrect property enumeration order\\n\\t// note: this does not detect the bug unless there's 20 characters\\n\\tvar str = 'abcdefghijklmnopqrst';\\n\\tvar letters = str.split('');\\n\\tvar map = {};\\n\\tfor (var i = 0; i < letters.length; ++i) {\\n\\t\\tmap[letters[i]] = letters[i];\\n\\t}\\n\\tvar obj = Object.assign({}, map);\\n\\tvar actual = '';\\n\\tfor (var k in obj) {\\n\\t\\tactual += k;\\n\\t}\\n\\treturn str !== actual;\\n};\\n\\nvar assignHasPendingExceptions = function () {\\n\\tif (!Object.assign || !Object.preventExtensions) {\\n\\t\\treturn false;\\n\\t}\\n\\t// Firefox 37 still has \\\"pending exception\\\" logic in its Object.assign implementation,\\n\\t// which is 72% slower than our shim, and Firefox 40's native implementation.\\n\\tvar thrower = Object.preventExtensions({ 1: 2 });\\n\\ttry {\\n\\t\\tObject.assign(thrower, 'xy');\\n\\t} catch (e) {\\n\\t\\treturn thrower[1] === 'y';\\n\\t}\\n\\treturn false;\\n};\\n\\nmodule.exports = function getPolyfill() {\\n\\tif (!Object.assign) {\\n\\t\\treturn implementation;\\n\\t}\\n\\tif (lacksProperEnumerationOrder()) {\\n\\t\\treturn implementation;\\n\\t}\\n\\tif (assignHasPendingExceptions()) {\\n\\t\\treturn implementation;\\n\\t}\\n\\treturn Object.assign;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/object.assign/polyfill.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/object.assign/shim.js\":\n/*!********************************************!*\\\n  !*** ./node_modules/object.assign/shim.js ***!\n  \\********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar define = __webpack_require__(/*! define-properties */ \\\"./node_modules/define-properties/index.js\\\");\\nvar getPolyfill = __webpack_require__(/*! ./polyfill */ \\\"./node_modules/object.assign/polyfill.js\\\");\\n\\nmodule.exports = function shimAssign() {\\n\\tvar polyfill = getPolyfill();\\n\\tdefine(\\n\\t\\tObject,\\n\\t\\t{ assign: polyfill },\\n\\t\\t{ assign: function () { return Object.assign !== polyfill; } }\\n\\t);\\n\\treturn polyfill;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/object.assign/shim.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/process/browser.js\":\n/*!*****************************************!*\\\n  !*** ./node_modules/process/browser.js ***!\n  \\*****************************************/\n/*! no static exports found */\n/***/ (function(module, exports) {\n\neval(\"// shim for using process in browser\\nvar process = module.exports = {};\\n\\n// cached from whatever global is present so that test runners that stub it\\n// don't break things.  But we need to wrap it in a try catch in case it is\\n// wrapped in strict mode code which doesn't define any globals.  It's inside a\\n// function because try/catches deoptimize in certain engines.\\n\\nvar cachedSetTimeout;\\nvar cachedClearTimeout;\\n\\nfunction defaultSetTimout() {\\n    throw new Error('setTimeout has not been defined');\\n}\\nfunction defaultClearTimeout () {\\n    throw new Error('clearTimeout has not been defined');\\n}\\n(function () {\\n    try {\\n        if (typeof setTimeout === 'function') {\\n            cachedSetTimeout = setTimeout;\\n        } else {\\n            cachedSetTimeout = defaultSetTimout;\\n        }\\n    } catch (e) {\\n        cachedSetTimeout = defaultSetTimout;\\n    }\\n    try {\\n        if (typeof clearTimeout === 'function') {\\n            cachedClearTimeout = clearTimeout;\\n        } else {\\n            cachedClearTimeout = defaultClearTimeout;\\n        }\\n    } catch (e) {\\n        cachedClearTimeout = defaultClearTimeout;\\n    }\\n} ())\\nfunction runTimeout(fun) {\\n    if (cachedSetTimeout === setTimeout) {\\n        //normal enviroments in sane situations\\n        return setTimeout(fun, 0);\\n    }\\n    // if setTimeout wasn't available but was latter defined\\n    if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {\\n        cachedSetTimeout = setTimeout;\\n        return setTimeout(fun, 0);\\n    }\\n    try {\\n        // when when somebody has screwed with setTimeout but no I.E. maddness\\n        return cachedSetTimeout(fun, 0);\\n    } catch(e){\\n        try {\\n            // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\\n            return cachedSetTimeout.call(null, fun, 0);\\n        } catch(e){\\n            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error\\n            return cachedSetTimeout.call(this, fun, 0);\\n        }\\n    }\\n\\n\\n}\\nfunction runClearTimeout(marker) {\\n    if (cachedClearTimeout === clearTimeout) {\\n        //normal enviroments in sane situations\\n        return clearTimeout(marker);\\n    }\\n    // if clearTimeout wasn't available but was latter defined\\n    if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {\\n        cachedClearTimeout = clearTimeout;\\n        return clearTimeout(marker);\\n    }\\n    try {\\n        // when when somebody has screwed with setTimeout but no I.E. maddness\\n        return cachedClearTimeout(marker);\\n    } catch (e){\\n        try {\\n            // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally\\n            return cachedClearTimeout.call(null, marker);\\n        } catch (e){\\n            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.\\n            // Some versions of I.E. have different rules for clearTimeout vs setTimeout\\n            return cachedClearTimeout.call(this, marker);\\n        }\\n    }\\n\\n\\n\\n}\\nvar queue = [];\\nvar draining = false;\\nvar currentQueue;\\nvar queueIndex = -1;\\n\\nfunction cleanUpNextTick() {\\n    if (!draining || !currentQueue) {\\n        return;\\n    }\\n    draining = false;\\n    if (currentQueue.length) {\\n        queue = currentQueue.concat(queue);\\n    } else {\\n        queueIndex = -1;\\n    }\\n    if (queue.length) {\\n        drainQueue();\\n    }\\n}\\n\\nfunction drainQueue() {\\n    if (draining) {\\n        return;\\n    }\\n    var timeout = runTimeout(cleanUpNextTick);\\n    draining = true;\\n\\n    var len = queue.length;\\n    while(len) {\\n        currentQueue = queue;\\n        queue = [];\\n        while (++queueIndex < len) {\\n            if (currentQueue) {\\n                currentQueue[queueIndex].run();\\n            }\\n        }\\n        queueIndex = -1;\\n        len = queue.length;\\n    }\\n    currentQueue = null;\\n    draining = false;\\n    runClearTimeout(timeout);\\n}\\n\\nprocess.nextTick = function (fun) {\\n    var args = new Array(arguments.length - 1);\\n    if (arguments.length > 1) {\\n        for (var i = 1; i < arguments.length; i++) {\\n            args[i - 1] = arguments[i];\\n        }\\n    }\\n    queue.push(new Item(fun, args));\\n    if (queue.length === 1 && !draining) {\\n        runTimeout(drainQueue);\\n    }\\n};\\n\\n// v8 likes predictible objects\\nfunction Item(fun, array) {\\n    this.fun = fun;\\n    this.array = array;\\n}\\nItem.prototype.run = function () {\\n    this.fun.apply(null, this.array);\\n};\\nprocess.title = 'browser';\\nprocess.browser = true;\\nprocess.env = {};\\nprocess.argv = [];\\nprocess.version = ''; // empty string to avoid regexp issues\\nprocess.versions = {};\\n\\nfunction noop() {}\\n\\nprocess.on = noop;\\nprocess.addListener = noop;\\nprocess.once = noop;\\nprocess.off = noop;\\nprocess.removeListener = noop;\\nprocess.removeAllListeners = noop;\\nprocess.emit = noop;\\nprocess.prependListener = noop;\\nprocess.prependOnceListener = noop;\\n\\nprocess.listeners = function (name) { return [] }\\n\\nprocess.binding = function (name) {\\n    throw new Error('process.binding is not supported');\\n};\\n\\nprocess.cwd = function () { return '/' };\\nprocess.chdir = function (dir) {\\n    throw new Error('process.chdir is not supported');\\n};\\nprocess.umask = function() { return 0; };\\n\\n\\n//# sourceURL=webpack:///./node_modules/process/browser.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/regexp.prototype.flags/implementation.js\":\n/*!***************************************************************!*\\\n  !*** ./node_modules/regexp.prototype.flags/implementation.js ***!\n  \\***************************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar $Object = Object;\\nvar $TypeError = TypeError;\\n\\nmodule.exports = function flags() {\\n\\tif (this != null && this !== $Object(this)) {\\n\\t\\tthrow new $TypeError('RegExp.prototype.flags getter called on non-object');\\n\\t}\\n\\tvar result = '';\\n\\tif (this.global) {\\n\\t\\tresult += 'g';\\n\\t}\\n\\tif (this.ignoreCase) {\\n\\t\\tresult += 'i';\\n\\t}\\n\\tif (this.multiline) {\\n\\t\\tresult += 'm';\\n\\t}\\n\\tif (this.dotAll) {\\n\\t\\tresult += 's';\\n\\t}\\n\\tif (this.unicode) {\\n\\t\\tresult += 'u';\\n\\t}\\n\\tif (this.sticky) {\\n\\t\\tresult += 'y';\\n\\t}\\n\\treturn result;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/regexp.prototype.flags/implementation.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/regexp.prototype.flags/index.js\":\n/*!******************************************************!*\\\n  !*** ./node_modules/regexp.prototype.flags/index.js ***!\n  \\******************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar define = __webpack_require__(/*! define-properties */ \\\"./node_modules/define-properties/index.js\\\");\\nvar callBind = __webpack_require__(/*! es-abstract/helpers/callBind */ \\\"./node_modules/es-abstract/helpers/callBind.js\\\");\\n\\nvar implementation = __webpack_require__(/*! ./implementation */ \\\"./node_modules/regexp.prototype.flags/implementation.js\\\");\\nvar getPolyfill = __webpack_require__(/*! ./polyfill */ \\\"./node_modules/regexp.prototype.flags/polyfill.js\\\");\\nvar shim = __webpack_require__(/*! ./shim */ \\\"./node_modules/regexp.prototype.flags/shim.js\\\");\\n\\nvar flagsBound = callBind(implementation);\\n\\ndefine(flagsBound, {\\n\\tgetPolyfill: getPolyfill,\\n\\timplementation: implementation,\\n\\tshim: shim\\n});\\n\\nmodule.exports = flagsBound;\\n\\n\\n//# sourceURL=webpack:///./node_modules/regexp.prototype.flags/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/regexp.prototype.flags/polyfill.js\":\n/*!*********************************************************!*\\\n  !*** ./node_modules/regexp.prototype.flags/polyfill.js ***!\n  \\*********************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar implementation = __webpack_require__(/*! ./implementation */ \\\"./node_modules/regexp.prototype.flags/implementation.js\\\");\\n\\nvar supportsDescriptors = __webpack_require__(/*! define-properties */ \\\"./node_modules/define-properties/index.js\\\").supportsDescriptors;\\nvar $gOPD = Object.getOwnPropertyDescriptor;\\nvar $TypeError = TypeError;\\n\\nmodule.exports = function getPolyfill() {\\n\\tif (!supportsDescriptors) {\\n\\t\\tthrow new $TypeError('RegExp.prototype.flags requires a true ES5 environment that supports property descriptors');\\n\\t}\\n\\tif ((/a/mig).flags === 'gim') {\\n\\t\\tvar descriptor = $gOPD(RegExp.prototype, 'flags');\\n\\t\\tif (descriptor && typeof descriptor.get === 'function' && typeof (/a/).dotAll === 'boolean') {\\n\\t\\t\\treturn descriptor.get;\\n\\t\\t}\\n\\t}\\n\\treturn implementation;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/regexp.prototype.flags/polyfill.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/regexp.prototype.flags/shim.js\":\n/*!*****************************************************!*\\\n  !*** ./node_modules/regexp.prototype.flags/shim.js ***!\n  \\*****************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar supportsDescriptors = __webpack_require__(/*! define-properties */ \\\"./node_modules/define-properties/index.js\\\").supportsDescriptors;\\nvar getPolyfill = __webpack_require__(/*! ./polyfill */ \\\"./node_modules/regexp.prototype.flags/polyfill.js\\\");\\nvar gOPD = Object.getOwnPropertyDescriptor;\\nvar defineProperty = Object.defineProperty;\\nvar TypeErr = TypeError;\\nvar getProto = Object.getPrototypeOf;\\nvar regex = /a/;\\n\\nmodule.exports = function shimFlags() {\\n\\tif (!supportsDescriptors || !getProto) {\\n\\t\\tthrow new TypeErr('RegExp.prototype.flags requires a true ES5 environment that supports property descriptors');\\n\\t}\\n\\tvar polyfill = getPolyfill();\\n\\tvar proto = getProto(regex);\\n\\tvar descriptor = gOPD(proto, 'flags');\\n\\tif (!descriptor || descriptor.get !== polyfill) {\\n\\t\\tdefineProperty(proto, 'flags', {\\n\\t\\t\\tconfigurable: true,\\n\\t\\t\\tenumerable: false,\\n\\t\\t\\tget: polyfill\\n\\t\\t});\\n\\t}\\n\\treturn polyfill;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/regexp.prototype.flags/shim.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/side-channel/index.js\":\n/*!********************************************!*\\\n  !*** ./node_modules/side-channel/index.js ***!\n  \\********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar GetIntrinsic = __webpack_require__(/*! es-abstract/GetIntrinsic */ \\\"./node_modules/es-abstract/GetIntrinsic.js\\\");\\nvar callBound = __webpack_require__(/*! es-abstract/helpers/callBound */ \\\"./node_modules/es-abstract/helpers/callBound.js\\\");\\nvar inspect = __webpack_require__(/*! object-inspect */ \\\"./node_modules/object-inspect/index.js\\\");\\n\\nvar $TypeError = GetIntrinsic('%TypeError%');\\nvar $WeakMap = GetIntrinsic('%WeakMap%', true);\\nvar $Map = GetIntrinsic('%Map%', true);\\nvar $push = callBound('Array.prototype.push');\\n\\nvar $weakMapGet = callBound('WeakMap.prototype.get', true);\\nvar $weakMapSet = callBound('WeakMap.prototype.set', true);\\nvar $weakMapHas = callBound('WeakMap.prototype.has', true);\\nvar $mapGet = callBound('Map.prototype.get', true);\\nvar $mapSet = callBound('Map.prototype.set', true);\\nvar $mapHas = callBound('Map.prototype.has', true);\\nvar objectGet = function (objects, key) { // eslint-disable-line consistent-return\\n\\tfor (var i = 0; i < objects.length; i += 1) {\\n\\t\\tif (objects[i].key === key) {\\n\\t\\t\\treturn objects[i].value;\\n\\t\\t}\\n\\t}\\n};\\nvar objectSet = function (objects, key, value) {\\n\\tfor (var i = 0; i < objects.length; i += 1) {\\n\\t\\tif (objects[i].key === key) {\\n\\t\\t\\tobjects[i].value = value; // eslint-disable-line no-param-reassign\\n\\t\\t\\treturn;\\n\\t\\t}\\n\\t}\\n\\t$push(objects, {\\n\\t\\tkey: key,\\n\\t\\tvalue: value\\n\\t});\\n};\\nvar objectHas = function (objects, key) {\\n\\tfor (var i = 0; i < objects.length; i += 1) {\\n\\t\\tif (objects[i].key === key) {\\n\\t\\t\\treturn true;\\n\\t\\t}\\n\\t}\\n\\treturn false;\\n};\\n\\nmodule.exports = function getSideChannel() {\\n\\tvar $wm;\\n\\tvar $m;\\n\\tvar $o;\\n\\tvar channel = {\\n\\t\\tassert: function (key) {\\n\\t\\t\\tif (!channel.has(key)) {\\n\\t\\t\\t\\tthrow new $TypeError('Side channel does not contain ' + inspect(key));\\n\\t\\t\\t}\\n\\t\\t},\\n\\t\\tget: function (key) { // eslint-disable-line consistent-return\\n\\t\\t\\tif ($WeakMap && key && (typeof key === 'object' || typeof key === 'function')) {\\n\\t\\t\\t\\tif ($wm) {\\n\\t\\t\\t\\t\\treturn $weakMapGet($wm, key);\\n\\t\\t\\t\\t}\\n\\t\\t\\t} else if ($Map) {\\n\\t\\t\\t\\tif ($m) {\\n\\t\\t\\t\\t\\treturn $mapGet($m, key);\\n\\t\\t\\t\\t}\\n\\t\\t\\t} else {\\n\\t\\t\\t\\tif ($o) { // eslint-disable-line no-lonely-if\\n\\t\\t\\t\\t\\treturn objectGet($o, key);\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t},\\n\\t\\thas: function (key) {\\n\\t\\t\\tif ($WeakMap && key && (typeof key === 'object' || typeof key === 'function')) {\\n\\t\\t\\t\\tif ($wm) {\\n\\t\\t\\t\\t\\treturn $weakMapHas($wm, key);\\n\\t\\t\\t\\t}\\n\\t\\t\\t} else if ($Map) {\\n\\t\\t\\t\\tif ($m) {\\n\\t\\t\\t\\t\\treturn $mapHas($m, key);\\n\\t\\t\\t\\t}\\n\\t\\t\\t} else {\\n\\t\\t\\t\\tif ($o) { // eslint-disable-line no-lonely-if\\n\\t\\t\\t\\t\\treturn objectHas($o, key);\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t\\treturn false;\\n\\t\\t},\\n\\t\\tset: function (key, value) {\\n\\t\\t\\tif ($WeakMap && key && (typeof key === 'object' || typeof key === 'function')) {\\n\\t\\t\\t\\tif (!$wm) {\\n\\t\\t\\t\\t\\t$wm = new $WeakMap();\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\t$weakMapSet($wm, key, value);\\n\\t\\t\\t} else if ($Map) {\\n\\t\\t\\t\\tif (!$m) {\\n\\t\\t\\t\\t\\t$m = new $Map();\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\t$mapSet($m, key, value);\\n\\t\\t\\t} else {\\n\\t\\t\\t\\tif (!$o) {\\n\\t\\t\\t\\t\\t$o = [];\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tobjectSet($o, key, value);\\n\\t\\t\\t}\\n\\t\\t}\\n\\t};\\n\\treturn channel;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/side-channel/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/simple-swizzle/index.js\":\n/*!**********************************************!*\\\n  !*** ./node_modules/simple-swizzle/index.js ***!\n  \\**********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar isArrayish = __webpack_require__(/*! is-arrayish */ \\\"./node_modules/is-arrayish/index.js\\\");\\n\\nvar concat = Array.prototype.concat;\\nvar slice = Array.prototype.slice;\\n\\nvar swizzle = module.exports = function swizzle(args) {\\n\\tvar results = [];\\n\\n\\tfor (var i = 0, len = args.length; i < len; i++) {\\n\\t\\tvar arg = args[i];\\n\\n\\t\\tif (isArrayish(arg)) {\\n\\t\\t\\t// http://jsperf.com/javascript-array-concat-vs-push/98\\n\\t\\t\\tresults = concat.call(results, slice.call(arg));\\n\\t\\t} else {\\n\\t\\t\\tresults.push(arg);\\n\\t\\t}\\n\\t}\\n\\n\\treturn results;\\n};\\n\\nswizzle.wrap = function (fn) {\\n\\treturn function () {\\n\\t\\treturn fn(swizzle(arguments));\\n\\t};\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/simple-swizzle/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/tslib/tslib.es6.js\":\n/*!*****************************************!*\\\n  !*** ./node_modules/tslib/tslib.es6.js ***!\n  \\*****************************************/\n/*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __createBinding, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault, __classPrivateFieldGet, __classPrivateFieldSet */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\neval(\"__webpack_require__.r(__webpack_exports__);\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__extends\\\", function() { return __extends; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__assign\\\", function() { return __assign; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__rest\\\", function() { return __rest; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__decorate\\\", function() { return __decorate; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__param\\\", function() { return __param; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__metadata\\\", function() { return __metadata; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__awaiter\\\", function() { return __awaiter; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__generator\\\", function() { return __generator; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__createBinding\\\", function() { return __createBinding; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__exportStar\\\", function() { return __exportStar; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__values\\\", function() { return __values; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__read\\\", function() { return __read; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__spread\\\", function() { return __spread; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__spreadArrays\\\", function() { return __spreadArrays; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__await\\\", function() { return __await; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__asyncGenerator\\\", function() { return __asyncGenerator; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__asyncDelegator\\\", function() { return __asyncDelegator; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__asyncValues\\\", function() { return __asyncValues; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__makeTemplateObject\\\", function() { return __makeTemplateObject; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__importStar\\\", function() { return __importStar; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__importDefault\\\", function() { return __importDefault; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__classPrivateFieldGet\\\", function() { return __classPrivateFieldGet; });\\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \\\"__classPrivateFieldSet\\\", function() { return __classPrivateFieldSet; });\\n/*! *****************************************************************************\\r\\nCopyright (c) Microsoft Corporation.\\r\\n\\r\\nPermission to use, copy, modify, and/or distribute this software for any\\r\\npurpose with or without fee is hereby granted.\\r\\n\\r\\nTHE SOFTWARE IS PROVIDED \\\"AS IS\\\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\\r\\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\\r\\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\\r\\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\\r\\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\\r\\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\\r\\nPERFORMANCE OF THIS SOFTWARE.\\r\\n***************************************************************************** */\\r\\n/* global Reflect, Promise */\\r\\n\\r\\nvar extendStatics = function(d, b) {\\r\\n    extendStatics = Object.setPrototypeOf ||\\r\\n        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\\r\\n        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\\r\\n    return extendStatics(d, b);\\r\\n};\\r\\n\\r\\nfunction __extends(d, b) {\\r\\n    extendStatics(d, b);\\r\\n    function __() { this.constructor = d; }\\r\\n    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\\r\\n}\\r\\n\\r\\nvar __assign = function() {\\r\\n    __assign = Object.assign || function __assign(t) {\\r\\n        for (var s, i = 1, n = arguments.length; i < n; i++) {\\r\\n            s = arguments[i];\\r\\n            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\\r\\n        }\\r\\n        return t;\\r\\n    }\\r\\n    return __assign.apply(this, arguments);\\r\\n}\\r\\n\\r\\nfunction __rest(s, e) {\\r\\n    var t = {};\\r\\n    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\\r\\n        t[p] = s[p];\\r\\n    if (s != null && typeof Object.getOwnPropertySymbols === \\\"function\\\")\\r\\n        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\\r\\n            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\\r\\n                t[p[i]] = s[p[i]];\\r\\n        }\\r\\n    return t;\\r\\n}\\r\\n\\r\\nfunction __decorate(decorators, target, key, desc) {\\r\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\r\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\r\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\r\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\r\\n}\\r\\n\\r\\nfunction __param(paramIndex, decorator) {\\r\\n    return function (target, key) { decorator(target, key, paramIndex); }\\r\\n}\\r\\n\\r\\nfunction __metadata(metadataKey, metadataValue) {\\r\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.metadata === \\\"function\\\") return Reflect.metadata(metadataKey, metadataValue);\\r\\n}\\r\\n\\r\\nfunction __awaiter(thisArg, _arguments, P, generator) {\\r\\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\\r\\n    return new (P || (P = Promise))(function (resolve, reject) {\\r\\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\\r\\n        function rejected(value) { try { step(generator[\\\"throw\\\"](value)); } catch (e) { reject(e); } }\\r\\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\\r\\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\\r\\n    });\\r\\n}\\r\\n\\r\\nfunction __generator(thisArg, body) {\\r\\n    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\\r\\n    return g = { next: verb(0), \\\"throw\\\": verb(1), \\\"return\\\": verb(2) }, typeof Symbol === \\\"function\\\" && (g[Symbol.iterator] = function() { return this; }), g;\\r\\n    function verb(n) { return function (v) { return step([n, v]); }; }\\r\\n    function step(op) {\\r\\n        if (f) throw new TypeError(\\\"Generator is already executing.\\\");\\r\\n        while (_) try {\\r\\n            if (f = 1, y && (t = op[0] & 2 ? y[\\\"return\\\"] : op[0] ? y[\\\"throw\\\"] || ((t = y[\\\"return\\\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\\r\\n            if (y = 0, t) op = [op[0] & 2, t.value];\\r\\n            switch (op[0]) {\\r\\n                case 0: case 1: t = op; break;\\r\\n                case 4: _.label++; return { value: op[1], done: false };\\r\\n                case 5: _.label++; y = op[1]; op = [0]; continue;\\r\\n                case 7: op = _.ops.pop(); _.trys.pop(); continue;\\r\\n                default:\\r\\n                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\\r\\n                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\\r\\n                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\\r\\n                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\\r\\n                    if (t[2]) _.ops.pop();\\r\\n                    _.trys.pop(); continue;\\r\\n            }\\r\\n            op = body.call(thisArg, _);\\r\\n        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\\r\\n        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\\r\\n    }\\r\\n}\\r\\n\\r\\nfunction __createBinding(o, m, k, k2) {\\r\\n    if (k2 === undefined) k2 = k;\\r\\n    o[k2] = m[k];\\r\\n}\\r\\n\\r\\nfunction __exportStar(m, exports) {\\r\\n    for (var p in m) if (p !== \\\"default\\\" && !exports.hasOwnProperty(p)) exports[p] = m[p];\\r\\n}\\r\\n\\r\\nfunction __values(o) {\\r\\n    var s = typeof Symbol === \\\"function\\\" && Symbol.iterator, m = s && o[s], i = 0;\\r\\n    if (m) return m.call(o);\\r\\n    if (o && typeof o.length === \\\"number\\\") return {\\r\\n        next: function () {\\r\\n            if (o && i >= o.length) o = void 0;\\r\\n            return { value: o && o[i++], done: !o };\\r\\n        }\\r\\n    };\\r\\n    throw new TypeError(s ? \\\"Object is not iterable.\\\" : \\\"Symbol.iterator is not defined.\\\");\\r\\n}\\r\\n\\r\\nfunction __read(o, n) {\\r\\n    var m = typeof Symbol === \\\"function\\\" && o[Symbol.iterator];\\r\\n    if (!m) return o;\\r\\n    var i = m.call(o), r, ar = [], e;\\r\\n    try {\\r\\n        while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\\r\\n    }\\r\\n    catch (error) { e = { error: error }; }\\r\\n    finally {\\r\\n        try {\\r\\n            if (r && !r.done && (m = i[\\\"return\\\"])) m.call(i);\\r\\n        }\\r\\n        finally { if (e) throw e.error; }\\r\\n    }\\r\\n    return ar;\\r\\n}\\r\\n\\r\\nfunction __spread() {\\r\\n    for (var ar = [], i = 0; i < arguments.length; i++)\\r\\n        ar = ar.concat(__read(arguments[i]));\\r\\n    return ar;\\r\\n}\\r\\n\\r\\nfunction __spreadArrays() {\\r\\n    for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\\r\\n    for (var r = Array(s), k = 0, i = 0; i < il; i++)\\r\\n        for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\\r\\n            r[k] = a[j];\\r\\n    return r;\\r\\n};\\r\\n\\r\\nfunction __await(v) {\\r\\n    return this instanceof __await ? (this.v = v, this) : new __await(v);\\r\\n}\\r\\n\\r\\nfunction __asyncGenerator(thisArg, _arguments, generator) {\\r\\n    if (!Symbol.asyncIterator) throw new TypeError(\\\"Symbol.asyncIterator is not defined.\\\");\\r\\n    var g = generator.apply(thisArg, _arguments || []), i, q = [];\\r\\n    return i = {}, verb(\\\"next\\\"), verb(\\\"throw\\\"), verb(\\\"return\\\"), i[Symbol.asyncIterator] = function () { return this; }, i;\\r\\n    function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\\r\\n    function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\\r\\n    function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\\r\\n    function fulfill(value) { resume(\\\"next\\\", value); }\\r\\n    function reject(value) { resume(\\\"throw\\\", value); }\\r\\n    function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\\r\\n}\\r\\n\\r\\nfunction __asyncDelegator(o) {\\r\\n    var i, p;\\r\\n    return i = {}, verb(\\\"next\\\"), verb(\\\"throw\\\", function (e) { throw e; }), verb(\\\"return\\\"), i[Symbol.iterator] = function () { return this; }, i;\\r\\n    function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \\\"return\\\" } : f ? f(v) : v; } : f; }\\r\\n}\\r\\n\\r\\nfunction __asyncValues(o) {\\r\\n    if (!Symbol.asyncIterator) throw new TypeError(\\\"Symbol.asyncIterator is not defined.\\\");\\r\\n    var m = o[Symbol.asyncIterator], i;\\r\\n    return m ? m.call(o) : (o = typeof __values === \\\"function\\\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\\\"next\\\"), verb(\\\"throw\\\"), verb(\\\"return\\\"), i[Symbol.asyncIterator] = function () { return this; }, i);\\r\\n    function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\\r\\n    function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\\r\\n}\\r\\n\\r\\nfunction __makeTemplateObject(cooked, raw) {\\r\\n    if (Object.defineProperty) { Object.defineProperty(cooked, \\\"raw\\\", { value: raw }); } else { cooked.raw = raw; }\\r\\n    return cooked;\\r\\n};\\r\\n\\r\\nfunction __importStar(mod) {\\r\\n    if (mod && mod.__esModule) return mod;\\r\\n    var result = {};\\r\\n    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];\\r\\n    result.default = mod;\\r\\n    return result;\\r\\n}\\r\\n\\r\\nfunction __importDefault(mod) {\\r\\n    return (mod && mod.__esModule) ? mod : { default: mod };\\r\\n}\\r\\n\\r\\nfunction __classPrivateFieldGet(receiver, privateMap) {\\r\\n    if (!privateMap.has(receiver)) {\\r\\n        throw new TypeError(\\\"attempted to get private field on non-instance\\\");\\r\\n    }\\r\\n    return privateMap.get(receiver);\\r\\n}\\r\\n\\r\\nfunction __classPrivateFieldSet(receiver, privateMap, value) {\\r\\n    if (!privateMap.has(receiver)) {\\r\\n        throw new TypeError(\\\"attempted to set private field on non-instance\\\");\\r\\n    }\\r\\n    privateMap.set(receiver, value);\\r\\n    return value;\\r\\n}\\r\\n\\n\\n//# sourceURL=webpack:///./node_modules/tslib/tslib.es6.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/webmidi/webmidi.min.js\":\n/*!*********************************************!*\\\n  !*** ./node_modules/webmidi/webmidi.min.js ***!\n  \\*********************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*\\n\\nWebMidi v2.5.1\\n\\nWebMidi.js helps you tame the Web MIDI API. Send and receive MIDI messages with ease. Control instruments with user-friendly functions (playNote, sendPitchBend, etc.). React to MIDI input with simple event listeners (noteon, pitchbend, controlchange, etc.).\\nhttps://github.com/djipco/webmidi\\n\\n\\nThe MIT License (MIT)\\n\\nCopyright (c) 2015-2019, Jean-Philippe Côté\\n\\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and\\nassociated documentation files (the \\\"Software\\\"), to deal in the Software without restriction,\\nincluding without limitation the rights to use, copy, modify, merge, publish, distribute,\\nsublicense, and/or sell copies of the Software, and to permit persons to whom the Software is\\nfurnished to do so, subject to the following conditions:\\n\\nThe above copyright notice and this permission notice shall be included in all copies or substantial\\nportions of the Software.\\n\\nTHE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\\nNOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES\\nOR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\\n\\n*/\\n\\n\\n!function(scope){\\\"use strict\\\";function WebMidi(){if(WebMidi.prototype._singleton)throw new Error(\\\"WebMidi is a singleton, it cannot be instantiated directly.\\\");(WebMidi.prototype._singleton=this)._inputs=[],this._outputs=[],this._userHandlers={},this._stateChangeQueue=[],this._processingStateChange=!1,this._midiInterfaceEvents=[\\\"connected\\\",\\\"disconnected\\\"],this._nrpnBuffer=[[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]],this._nrpnEventsEnabled=!0,this._nrpnTypes=[\\\"entry\\\",\\\"increment\\\",\\\"decrement\\\"],this._notes=[\\\"C\\\",\\\"C#\\\",\\\"D\\\",\\\"D#\\\",\\\"E\\\",\\\"F\\\",\\\"F#\\\",\\\"G\\\",\\\"G#\\\",\\\"A\\\",\\\"A#\\\",\\\"B\\\"],this._semitones={C:0,D:2,E:4,F:5,G:7,A:9,B:11},Object.defineProperties(this,{MIDI_SYSTEM_MESSAGES:{value:{sysex:240,timecode:241,songposition:242,songselect:243,tuningrequest:246,sysexend:247,clock:248,start:250,continue:251,stop:252,activesensing:254,reset:255,midimessage:0,unknownsystemmessage:-1},writable:!1,enumerable:!0,configurable:!1},MIDI_CHANNEL_MESSAGES:{value:{noteoff:8,noteon:9,keyaftertouch:10,controlchange:11,channelmode:11,nrpn:11,programchange:12,channelaftertouch:13,pitchbend:14},writable:!1,enumerable:!0,configurable:!1},MIDI_REGISTERED_PARAMETER:{value:{pitchbendrange:[0,0],channelfinetuning:[0,1],channelcoarsetuning:[0,2],tuningprogram:[0,3],tuningbank:[0,4],modulationrange:[0,5],azimuthangle:[61,0],elevationangle:[61,1],gain:[61,2],distanceratio:[61,3],maximumdistance:[61,4],maximumdistancegain:[61,5],referencedistanceratio:[61,6],panspreadangle:[61,7],rollangle:[61,8]},writable:!1,enumerable:!0,configurable:!1},MIDI_CONTROL_CHANGE_MESSAGES:{value:{bankselectcoarse:0,modulationwheelcoarse:1,breathcontrollercoarse:2,footcontrollercoarse:4,portamentotimecoarse:5,dataentrycoarse:6,volumecoarse:7,balancecoarse:8,pancoarse:10,expressioncoarse:11,effectcontrol1coarse:12,effectcontrol2coarse:13,generalpurposeslider1:16,generalpurposeslider2:17,generalpurposeslider3:18,generalpurposeslider4:19,bankselectfine:32,modulationwheelfine:33,breathcontrollerfine:34,footcontrollerfine:36,portamentotimefine:37,dataentryfine:38,volumefine:39,balancefine:40,panfine:42,expressionfine:43,effectcontrol1fine:44,effectcontrol2fine:45,holdpedal:64,portamento:65,sustenutopedal:66,softpedal:67,legatopedal:68,hold2pedal:69,soundvariation:70,resonance:71,soundreleasetime:72,soundattacktime:73,brightness:74,soundcontrol6:75,soundcontrol7:76,soundcontrol8:77,soundcontrol9:78,soundcontrol10:79,generalpurposebutton1:80,generalpurposebutton2:81,generalpurposebutton3:82,generalpurposebutton4:83,reverblevel:91,tremololevel:92,choruslevel:93,celestelevel:94,phaserlevel:95,databuttonincrement:96,databuttondecrement:97,nonregisteredparametercoarse:98,nonregisteredparameterfine:99,registeredparametercoarse:100,registeredparameterfine:101},writable:!1,enumerable:!0,configurable:!1},MIDI_NRPN_MESSAGES:{value:{entrymsb:6,entrylsb:38,increment:96,decrement:97,paramlsb:98,parammsb:99,nullactiveparameter:127},writable:!1,enumerable:!0,configurable:!1},MIDI_CHANNEL_MODE_MESSAGES:{value:{allsoundoff:120,resetallcontrollers:121,localcontrol:122,allnotesoff:123,omnimodeoff:124,omnimodeon:125,monomodeon:126,polymodeon:127},writable:!1,enumerable:!0,configurable:!1},octaveOffset:{value:0,writable:!0,enumerable:!0,configurable:!1}}),Object.defineProperties(this,{supported:{enumerable:!0,get:function(){return\\\"requestMIDIAccess\\\"in navigator}},enabled:{enumerable:!0,get:function(){return void 0!==this.interface}.bind(this)},inputs:{enumerable:!0,get:function(){return this._inputs}.bind(this)},outputs:{enumerable:!0,get:function(){return this._outputs}.bind(this)},sysexEnabled:{enumerable:!0,get:function(){return!(!this.interface||!this.interface.sysexEnabled)}.bind(this)},nrpnEventsEnabled:{enumerable:!0,get:function(){return!!this._nrpnEventsEnabled}.bind(this),set:function(enabled){return this._nrpnEventsEnabled=enabled,this._nrpnEventsEnabled}},nrpnTypes:{enumerable:!0,get:function(){return this._nrpnTypes}.bind(this)},time:{enumerable:!0,get:function(){return performance.now()}}})}var wm=new WebMidi;function Input(midiInput){var that=this;this._userHandlers={channel:{},system:{}},this._midiInput=midiInput,Object.defineProperties(this,{connection:{enumerable:!0,get:function(){return that._midiInput.connection}},id:{enumerable:!0,get:function(){return that._midiInput.id}},manufacturer:{enumerable:!0,get:function(){return that._midiInput.manufacturer}},name:{enumerable:!0,get:function(){return that._midiInput.name}},state:{enumerable:!0,get:function(){return that._midiInput.state}},type:{enumerable:!0,get:function(){return that._midiInput.type}}}),this._initializeUserHandlers(),this._midiInput.onmidimessage=this._onMidiMessage.bind(this)}function Output(midiOutput){var that=this;this._midiOutput=midiOutput,Object.defineProperties(this,{connection:{enumerable:!0,get:function(){return that._midiOutput.connection}},id:{enumerable:!0,get:function(){return that._midiOutput.id}},manufacturer:{enumerable:!0,get:function(){return that._midiOutput.manufacturer}},name:{enumerable:!0,get:function(){return that._midiOutput.name}},state:{enumerable:!0,get:function(){return that._midiOutput.state}},type:{enumerable:!0,get:function(){return that._midiOutput.type}}})}WebMidi.prototype.enable=function(callback,sysex){this.enabled||(this.supported?navigator.requestMIDIAccess({sysex:sysex}).then(function(midiAccess){var promiseTimeout,events=[],promises=[];this.interface=midiAccess,this._resetInterfaceUserHandlers(),this.interface.onstatechange=function(e){events.push(e)};for(var inputs=midiAccess.inputs.values(),input=inputs.next();input&&!input.done;input=inputs.next())promises.push(input.value.open());for(var outputs=midiAccess.outputs.values(),output=outputs.next();output&&!output.done;output=outputs.next())promises.push(output.value.open());function onPortsOpen(){clearTimeout(promiseTimeout),this._updateInputsAndOutputs(),this.interface.onstatechange=this._onInterfaceStateChange.bind(this),\\\"function\\\"==typeof callback&&callback.call(this),events.forEach(function(event){this._onInterfaceStateChange(event)}.bind(this))}promiseTimeout=setTimeout(onPortsOpen.bind(this),200),Promise&&Promise.all(promises).catch(function(err){}).then(onPortsOpen.bind(this))}.bind(this),function(err){\\\"function\\\"==typeof callback&&callback.call(this,err)}.bind(this)):\\\"function\\\"==typeof callback&&callback(new Error(\\\"The Web MIDI API is not supported by your browser.\\\")))},WebMidi.prototype.disable=function(){if(!this.supported)throw new Error(\\\"The Web MIDI API is not supported by your browser.\\\");this.interface&&(this.interface.onstatechange=void 0),this.interface=void 0,this._inputs=[],this._outputs=[],this._nrpnEventsEnabled=!0,this._resetInterfaceUserHandlers()},WebMidi.prototype.addListener=function(type,listener){if(!this.enabled)throw new Error(\\\"WebMidi must be enabled before adding event listeners.\\\");if(\\\"function\\\"!=typeof listener)throw new TypeError(\\\"The 'listener' parameter must be a function.\\\");if(!(0<=this._midiInterfaceEvents.indexOf(type)))throw new TypeError(\\\"The specified event type is not supported.\\\");return this._userHandlers[type].push(listener),this},WebMidi.prototype.hasListener=function(type,listener){if(!this.enabled)throw new Error(\\\"WebMidi must be enabled before checking event listeners.\\\");if(\\\"function\\\"!=typeof listener)throw new TypeError(\\\"The 'listener' parameter must be a function.\\\");if(!(0<=this._midiInterfaceEvents.indexOf(type)))throw new TypeError(\\\"The specified event type is not supported.\\\");for(var o=0;o<this._userHandlers[type].length;o++)if(this._userHandlers[type][o]===listener)return!0;return!1},WebMidi.prototype.removeListener=function(type,listener){if(!this.enabled)throw new Error(\\\"WebMidi must be enabled before removing event listeners.\\\");if(void 0!==listener&&\\\"function\\\"!=typeof listener)throw new TypeError(\\\"The 'listener' parameter must be a function.\\\");if(0<=this._midiInterfaceEvents.indexOf(type))if(listener)for(var o=0;o<this._userHandlers[type].length;o++)this._userHandlers[type][o]===listener&&this._userHandlers[type].splice(o,1);else this._userHandlers[type]=[];else{if(void 0!==type)throw new TypeError(\\\"The specified event type is not supported.\\\");this._resetInterfaceUserHandlers()}return this},WebMidi.prototype.toMIDIChannels=function(channel){var channels;if(\\\"all\\\"===channel||void 0===channel)channels=[\\\"all\\\"];else{if(\\\"none\\\"===channel)return channels=[];channels=Array.isArray(channel)?channel:[channel]}return-1<channels.indexOf(\\\"all\\\")&&(channels=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]),channels.map(function(ch){return parseInt(ch)}).filter(function(ch){return 1<=ch&&ch<=16})},WebMidi.prototype.getInputById=function(id){if(!this.enabled)throw new Error(\\\"WebMidi is not enabled.\\\");id=String(id);for(var i=0;i<this.inputs.length;i++)if(this.inputs[i].id===id)return this.inputs[i];return!1},WebMidi.prototype.getOutputById=function(id){if(!this.enabled)throw new Error(\\\"WebMidi is not enabled.\\\");id=String(id);for(var i=0;i<this.outputs.length;i++)if(this.outputs[i].id===id)return this.outputs[i];return!1},WebMidi.prototype.getInputByName=function(name){if(!this.enabled)throw new Error(\\\"WebMidi is not enabled.\\\");for(var i=0;i<this.inputs.length;i++)if(~this.inputs[i].name.indexOf(name))return this.inputs[i];return!1},WebMidi.prototype.getOctave=function(number){if(null!=number&&0<=number&&number<=127)return Math.floor(Math.floor(number)/12-1)+Math.floor(wm.octaveOffset)},WebMidi.prototype.getOutputByName=function(name){if(!this.enabled)throw new Error(\\\"WebMidi is not enabled.\\\");for(var i=0;i<this.outputs.length;i++)if(~this.outputs[i].name.indexOf(name))return this.outputs[i];return!1},WebMidi.prototype.guessNoteNumber=function(input){var output=!1;if(input&&input.toFixed&&0<=input&&input<=127?output=Math.round(input):0<=parseInt(input)&&parseInt(input)<=127?output=parseInt(input):(\\\"string\\\"==typeof input||input instanceof String)&&(output=this.noteNameToNumber(input)),!1===output)throw new Error(\\\"Invalid input value (\\\"+input+\\\").\\\");return output},WebMidi.prototype.noteNameToNumber=function(name){\\\"string\\\"!=typeof name&&(name=\\\"\\\");var matches=name.match(/([CDEFGAB])(#{0,2}|b{0,2})(-?\\\\d+)/i);if(!matches)throw new RangeError(\\\"Invalid note name.\\\");var semitones=wm._semitones[matches[1].toUpperCase()],result=12*(parseInt(matches[3])+1-Math.floor(wm.octaveOffset))+semitones;if(-1<matches[2].toLowerCase().indexOf(\\\"b\\\")?result-=matches[2].length:-1<matches[2].toLowerCase().indexOf(\\\"#\\\")&&(result+=matches[2].length),result<0||127<result)throw new RangeError(\\\"Invalid note name or note outside valid range.\\\");return result},WebMidi.prototype._updateInputsAndOutputs=function(){this._updateInputs(),this._updateOutputs()},WebMidi.prototype._updateInputs=function(){for(var i=0;i<this._inputs.length;i++){for(var remove=!0,updated=this.interface.inputs.values(),input=updated.next();input&&!input.done;input=updated.next())if(this._inputs[i]._midiInput===input.value){remove=!1;break}remove&&this._inputs.splice(i,1)}this.interface&&this.interface.inputs.forEach(function(nInput){for(var add=!0,j=0;j<this._inputs.length;j++)this._inputs[j]._midiInput===nInput&&(add=!1);add&&this._inputs.push(new Input(nInput))}.bind(this))},WebMidi.prototype._updateOutputs=function(){for(var i=0;i<this._outputs.length;i++){for(var remove=!0,updated=this.interface.outputs.values(),output=updated.next();output&&!output.done;output=updated.next())if(this._outputs[i]._midiOutput===output.value){remove=!1;break}remove&&this._outputs.splice(i,1)}this.interface&&this.interface.outputs.forEach(function(nOutput){for(var add=!0,j=0;j<this._outputs.length;j++)this._outputs[j]._midiOutput===nOutput&&(add=!1);add&&this._outputs.push(new Output(nOutput))}.bind(this))},WebMidi.prototype._onInterfaceStateChange=function(e){this._updateInputsAndOutputs();var event={timestamp:e.timeStamp,type:e.port.state};this.interface&&\\\"connected\\\"===e.port.state?\\\"output\\\"===e.port.type?event.port=this.getOutputById(e.port.id):\\\"input\\\"===e.port.type&&(event.port=this.getInputById(e.port.id)):event.port={connection:\\\"closed\\\",id:e.port.id,manufacturer:e.port.manufacturer,name:e.port.name,state:e.port.state,type:e.port.type},this._userHandlers[e.port.state].forEach(function(handler){handler(event)})},WebMidi.prototype._resetInterfaceUserHandlers=function(){for(var i=0;i<this._midiInterfaceEvents.length;i++)this._userHandlers[this._midiInterfaceEvents[i]]=[]},Input.prototype.on=Input.prototype.addListener=function(type,channel,listener){var that=this;if(void 0===channel&&(channel=\\\"all\\\"),Array.isArray(channel)||(channel=[channel]),channel.forEach(function(item){if(\\\"all\\\"!==item&&!(1<=item&&item<=16))throw new RangeError(\\\"The 'channel' parameter is invalid.\\\")}),\\\"function\\\"!=typeof listener)throw new TypeError(\\\"The 'listener' parameter must be a function.\\\");if(void 0!==wm.MIDI_SYSTEM_MESSAGES[type])this._userHandlers.system[type]||(this._userHandlers.system[type]=[]),this._userHandlers.system[type].push(listener);else{if(void 0===wm.MIDI_CHANNEL_MESSAGES[type])throw new TypeError(\\\"The specified event type is not supported.\\\");if(-1<channel.indexOf(\\\"all\\\")){channel=[];for(var j=1;j<=16;j++)channel.push(j)}this._userHandlers.channel[type]||(this._userHandlers.channel[type]=[]),channel.forEach(function(ch){that._userHandlers.channel[type][ch]||(that._userHandlers.channel[type][ch]=[]),that._userHandlers.channel[type][ch].push(listener)})}return this},Input.prototype.hasListener=function(type,channel,listener){var that=this;if(\\\"function\\\"!=typeof listener)throw new TypeError(\\\"The 'listener' parameter must be a function.\\\");if(void 0===channel&&(channel=\\\"all\\\"),channel.constructor!==Array&&(channel=[channel]),void 0!==wm.MIDI_SYSTEM_MESSAGES[type]){for(var o=0;o<this._userHandlers.system[type].length;o++)if(this._userHandlers.system[type][o]===listener)return!0}else if(void 0!==wm.MIDI_CHANNEL_MESSAGES[type]){if(-1<channel.indexOf(\\\"all\\\")){channel=[];for(var j=1;j<=16;j++)channel.push(j)}return!!this._userHandlers.channel[type]&&channel.every(function(chNum){var listeners=that._userHandlers.channel[type][chNum];return listeners&&-1<listeners.indexOf(listener)})}return!1},Input.prototype.removeListener=function(type,channel,listener){var that=this;if(void 0!==listener&&\\\"function\\\"!=typeof listener)throw new TypeError(\\\"The 'listener' parameter must be a function.\\\");if(void 0===channel&&(channel=\\\"all\\\"),channel.constructor!==Array&&(channel=[channel]),void 0!==wm.MIDI_SYSTEM_MESSAGES[type])if(void 0===listener)this._userHandlers.system[type]=[];else for(var o=0;o<this._userHandlers.system[type].length;o++)this._userHandlers.system[type][o]===listener&&this._userHandlers.system[type].splice(o,1);else if(void 0!==wm.MIDI_CHANNEL_MESSAGES[type]){if(-1<channel.indexOf(\\\"all\\\")){channel=[];for(var j=1;j<=16;j++)channel.push(j)}if(!this._userHandlers.channel[type])return this;channel.forEach(function(chNum){var listeners=that._userHandlers.channel[type][chNum];if(listeners)if(void 0===listener)that._userHandlers.channel[type][chNum]=[];else for(var l=0;l<listeners.length;l++)listeners[l]===listener&&listeners.splice(l,1)})}else{if(void 0!==type)throw new TypeError(\\\"The specified event type is not supported.\\\");this._initializeUserHandlers()}return this},Input.prototype._initializeUserHandlers=function(){for(var prop1 in wm.MIDI_CHANNEL_MESSAGES)wm.MIDI_CHANNEL_MESSAGES.hasOwnProperty(prop1)&&(this._userHandlers.channel[prop1]={});for(var prop2 in wm.MIDI_SYSTEM_MESSAGES)wm.MIDI_SYSTEM_MESSAGES.hasOwnProperty(prop2)&&(this._userHandlers.system[prop2]=[])},Input.prototype._onMidiMessage=function(e){if(0<this._userHandlers.system.midimessage.length){var event={target:this,data:e.data,timestamp:e.timeStamp,type:\\\"midimessage\\\"};this._userHandlers.system.midimessage.forEach(function(callback){callback(event)})}e.data[0]<240?(this._parseChannelEvent(e),this._parseNrpnEvent(e)):e.data[0]<=255&&this._parseSystemEvent(e)},Input.prototype._parseNrpnEvent=function(e){var data1,data2,command=e.data[0]>>4,channelBufferIndex=15&e.data[0],channel=1+channelBufferIndex;if(1<e.data.length&&(data1=e.data[1],data2=2<e.data.length?e.data[2]:void 0),wm.nrpnEventsEnabled&&command===wm.MIDI_CHANNEL_MESSAGES.controlchange&&(data1>=wm.MIDI_NRPN_MESSAGES.increment&&data1<=wm.MIDI_NRPN_MESSAGES.parammsb||data1===wm.MIDI_NRPN_MESSAGES.entrymsb||data1===wm.MIDI_NRPN_MESSAGES.entrylsb)){var ccEvent={target:this,type:\\\"controlchange\\\",data:e.data,timestamp:e.timeStamp,channel:channel,controller:{number:data1,name:this.getCcNameByNumber(data1)},value:data2};if(ccEvent.controller.number===wm.MIDI_NRPN_MESSAGES.parammsb&&ccEvent.value!=wm.MIDI_NRPN_MESSAGES.nullactiveparameter)wm._nrpnBuffer[channelBufferIndex]=[],wm._nrpnBuffer[channelBufferIndex][0]=ccEvent;else if(1===wm._nrpnBuffer[channelBufferIndex].length&&ccEvent.controller.number===wm.MIDI_NRPN_MESSAGES.paramlsb)wm._nrpnBuffer[channelBufferIndex].push(ccEvent);else if(2!==wm._nrpnBuffer[channelBufferIndex].length||ccEvent.controller.number!==wm.MIDI_NRPN_MESSAGES.increment&&ccEvent.controller.number!==wm.MIDI_NRPN_MESSAGES.decrement&&ccEvent.controller.number!==wm.MIDI_NRPN_MESSAGES.entrymsb)if(3===wm._nrpnBuffer[channelBufferIndex].length&&wm._nrpnBuffer[channelBufferIndex][2].number===wm.MIDI_NRPN_MESSAGES.entrymsb&&ccEvent.controller.number===wm.MIDI_NRPN_MESSAGES.entrylsb)wm._nrpnBuffer[channelBufferIndex].push(ccEvent);else if(3<=wm._nrpnBuffer[channelBufferIndex].length&&wm._nrpnBuffer[channelBufferIndex].length<=4&&ccEvent.controller.number===wm.MIDI_NRPN_MESSAGES.parammsb&&ccEvent.value===wm.MIDI_NRPN_MESSAGES.nullactiveparameter)wm._nrpnBuffer[channelBufferIndex].push(ccEvent);else if(4<=wm._nrpnBuffer[channelBufferIndex].length&&wm._nrpnBuffer[channelBufferIndex].length<=5&&ccEvent.controller.number===wm.MIDI_NRPN_MESSAGES.paramlsb&&ccEvent.value===wm.MIDI_NRPN_MESSAGES.nullactiveparameter){wm._nrpnBuffer[channelBufferIndex].push(ccEvent);var rawData=[];wm._nrpnBuffer[channelBufferIndex].forEach(function(ev){rawData.push(ev.data)});var nrpnNumber=wm._nrpnBuffer[channelBufferIndex][0].value<<7|wm._nrpnBuffer[channelBufferIndex][1].value,nrpnValue=wm._nrpnBuffer[channelBufferIndex][2].value;6===wm._nrpnBuffer[channelBufferIndex].length&&(nrpnValue=wm._nrpnBuffer[channelBufferIndex][2].value<<7|wm._nrpnBuffer[channelBufferIndex][3].value);var nrpnControllerType=\\\"\\\";switch(wm._nrpnBuffer[channelBufferIndex][2].controller.number){case wm.MIDI_NRPN_MESSAGES.entrymsb:nrpnControllerType=wm._nrpnTypes[0];break;case wm.MIDI_NRPN_MESSAGES.increment:nrpnControllerType=wm._nrpnTypes[1];break;case wm.MIDI_NRPN_MESSAGES.decrement:nrpnControllerType=wm._nrpnTypes[2];break;default:throw new Error(\\\"The NPRN type was unidentifiable.\\\")}var nrpnEvent={timestamp:ccEvent.timestamp,channel:ccEvent.channel,type:\\\"nrpn\\\",data:rawData,controller:{number:nrpnNumber,type:nrpnControllerType,name:\\\"Non-Registered Parameter \\\"+nrpnNumber},value:nrpnValue};wm._nrpnBuffer[channelBufferIndex]=[],this._userHandlers.channel[nrpnEvent.type]&&this._userHandlers.channel[nrpnEvent.type][nrpnEvent.channel]&&this._userHandlers.channel[nrpnEvent.type][nrpnEvent.channel].forEach(function(callback){callback(nrpnEvent)})}else wm._nrpnBuffer[channelBufferIndex]=[];else wm._nrpnBuffer[channelBufferIndex].push(ccEvent)}},Input.prototype._parseChannelEvent=function(e){var data1,data2,command=e.data[0]>>4,channel=1+(15&e.data[0]);1<e.data.length&&(data1=e.data[1],data2=2<e.data.length?e.data[2]:void 0);var event={target:this,data:e.data,timestamp:e.timeStamp,channel:channel};command===wm.MIDI_CHANNEL_MESSAGES.noteoff||command===wm.MIDI_CHANNEL_MESSAGES.noteon&&0===data2?(event.type=\\\"noteoff\\\",event.note={number:data1,name:wm._notes[data1%12],octave:wm.getOctave(data1)},event.velocity=data2/127,event.rawVelocity=data2):command===wm.MIDI_CHANNEL_MESSAGES.noteon?(event.type=\\\"noteon\\\",event.note={number:data1,name:wm._notes[data1%12],octave:wm.getOctave(data1)},event.velocity=data2/127,event.rawVelocity=data2):command===wm.MIDI_CHANNEL_MESSAGES.keyaftertouch?(event.type=\\\"keyaftertouch\\\",event.note={number:data1,name:wm._notes[data1%12],octave:wm.getOctave(data1)},event.value=data2/127):command===wm.MIDI_CHANNEL_MESSAGES.controlchange&&0<=data1&&data1<=119?(event.type=\\\"controlchange\\\",event.controller={number:data1,name:this.getCcNameByNumber(data1)},event.value=data2):command===wm.MIDI_CHANNEL_MESSAGES.channelmode&&120<=data1&&data1<=127?(event.type=\\\"channelmode\\\",event.controller={number:data1,name:this.getChannelModeByNumber(data1)},event.value=data2):command===wm.MIDI_CHANNEL_MESSAGES.programchange?(event.type=\\\"programchange\\\",event.value=data1):command===wm.MIDI_CHANNEL_MESSAGES.channelaftertouch?(event.type=\\\"channelaftertouch\\\",event.value=data1/127):command===wm.MIDI_CHANNEL_MESSAGES.pitchbend?(event.type=\\\"pitchbend\\\",event.value=((data2<<7)+data1-8192)/8192):event.type=\\\"unknownchannelmessage\\\",this._userHandlers.channel[event.type]&&this._userHandlers.channel[event.type][channel]&&this._userHandlers.channel[event.type][channel].forEach(function(callback){callback(event)})},Input.prototype.getCcNameByNumber=function(number){if(!(0<=(number=Math.floor(number))&&number<=119))throw new RangeError(\\\"The control change number must be between 0 and 119.\\\");for(var cc in wm.MIDI_CONTROL_CHANGE_MESSAGES)if(wm.MIDI_CONTROL_CHANGE_MESSAGES.hasOwnProperty(cc)&&number===wm.MIDI_CONTROL_CHANGE_MESSAGES[cc])return cc},Input.prototype.getChannelModeByNumber=function(number){if(!(120<=(number=Math.floor(number))&&status<=127))throw new RangeError(\\\"The control change number must be between 120 and 127.\\\");for(var cm in wm.MIDI_CHANNEL_MODE_MESSAGES)if(wm.MIDI_CHANNEL_MODE_MESSAGES.hasOwnProperty(cm)&&number===wm.MIDI_CHANNEL_MODE_MESSAGES[cm])return cm},Input.prototype._parseSystemEvent=function(e){var command=e.data[0],event={target:this,data:e.data,timestamp:e.timeStamp};command===wm.MIDI_SYSTEM_MESSAGES.sysex?event.type=\\\"sysex\\\":command===wm.MIDI_SYSTEM_MESSAGES.timecode?event.type=\\\"timecode\\\":command===wm.MIDI_SYSTEM_MESSAGES.songposition?event.type=\\\"songposition\\\":command===wm.MIDI_SYSTEM_MESSAGES.songselect?(event.type=\\\"songselect\\\",event.song=e.data[1]):command===wm.MIDI_SYSTEM_MESSAGES.tuningrequest?event.type=\\\"tuningrequest\\\":command===wm.MIDI_SYSTEM_MESSAGES.clock?event.type=\\\"clock\\\":command===wm.MIDI_SYSTEM_MESSAGES.start?event.type=\\\"start\\\":command===wm.MIDI_SYSTEM_MESSAGES.continue?event.type=\\\"continue\\\":command===wm.MIDI_SYSTEM_MESSAGES.stop?event.type=\\\"stop\\\":command===wm.MIDI_SYSTEM_MESSAGES.activesensing?event.type=\\\"activesensing\\\":command===wm.MIDI_SYSTEM_MESSAGES.reset?event.type=\\\"reset\\\":event.type=\\\"unknownsystemmessage\\\",this._userHandlers.system[event.type]&&this._userHandlers.system[event.type].forEach(function(callback){callback(event)})},Output.prototype.send=function(status,data,timestamp){if(!(128<=status&&status<=255))throw new RangeError(\\\"The status byte must be an integer between 128 (0x80) and 255 (0xFF).\\\");void 0===data&&(data=[]),Array.isArray(data)||(data=[data]);var message=[];return data.forEach(function(item){var parsed=Math.floor(item);if(!(0<=parsed&&parsed<=255))throw new RangeError(\\\"Data bytes must be integers between 0 (0x00) and 255 (0xFF).\\\");message.push(parsed)}),this._midiOutput.send([status].concat(message),parseFloat(timestamp)||0),this},Output.prototype.sendSysex=function(manufacturer,data,options){if(!wm.sysexEnabled)throw new Error(\\\"Sysex message support must first be activated.\\\");return options=options||{},manufacturer=[].concat(manufacturer),data.forEach(function(item){if(item<0||127<item)throw new RangeError(\\\"The data bytes of a sysex message must be integers between 0 (0x00) and 127 (0x7F).\\\")}),data=manufacturer.concat(data,wm.MIDI_SYSTEM_MESSAGES.sysexend),this.send(wm.MIDI_SYSTEM_MESSAGES.sysex,data,this._parseTimeParameter(options.time)),this},Output.prototype.sendTimecodeQuarterFrame=function(value,options){return options=options||{},this.send(wm.MIDI_SYSTEM_MESSAGES.timecode,value,this._parseTimeParameter(options.time)),this},Output.prototype.sendSongPosition=function(value,options){options=options||{};var msb=(value=Math.floor(value)||0)>>7&127,lsb=127&value;return this.send(wm.MIDI_SYSTEM_MESSAGES.songposition,[msb,lsb],this._parseTimeParameter(options.time)),this},Output.prototype.sendSongSelect=function(value,options){if(options=options||{},!(0<=(value=Math.floor(value))&&value<=127))throw new RangeError(\\\"The song number must be between 0 and 127.\\\");return this.send(wm.MIDI_SYSTEM_MESSAGES.songselect,[value],this._parseTimeParameter(options.time)),this},Output.prototype.sendTuningRequest=function(options){return options=options||{},this.send(wm.MIDI_SYSTEM_MESSAGES.tuningrequest,void 0,this._parseTimeParameter(options.time)),this},Output.prototype.sendClock=function(options){return options=options||{},this.send(wm.MIDI_SYSTEM_MESSAGES.clock,void 0,this._parseTimeParameter(options.time)),this},Output.prototype.sendStart=function(options){return options=options||{},this.send(wm.MIDI_SYSTEM_MESSAGES.start,void 0,this._parseTimeParameter(options.time)),this},Output.prototype.sendContinue=function(options){return options=options||{},this.send(wm.MIDI_SYSTEM_MESSAGES.continue,void 0,this._parseTimeParameter(options.time)),this},Output.prototype.sendStop=function(options){return options=options||{},this.send(wm.MIDI_SYSTEM_MESSAGES.stop,void 0,this._parseTimeParameter(options.time)),this},Output.prototype.sendActiveSensing=function(options){return options=options||{},this.send(wm.MIDI_SYSTEM_MESSAGES.activesensing,[],this._parseTimeParameter(options.time)),this},Output.prototype.sendReset=function(options){return options=options||{},this.send(wm.MIDI_SYSTEM_MESSAGES.reset,void 0,this._parseTimeParameter(options.time)),this},Output.prototype.stopNote=function(note,channel,options){if(\\\"all\\\"===note)return this.sendChannelMode(\\\"allnotesoff\\\",0,channel,options);var nVelocity=64;return(options=options||{}).rawVelocity?!isNaN(options.velocity)&&0<=options.velocity&&options.velocity<=127&&(nVelocity=options.velocity):!isNaN(options.velocity)&&0<=options.velocity&&options.velocity<=1&&(nVelocity=127*options.velocity),this._convertNoteToArray(note).forEach(function(item){wm.toMIDIChannels(channel).forEach(function(ch){this.send((wm.MIDI_CHANNEL_MESSAGES.noteoff<<4)+(ch-1),[item,Math.round(nVelocity)],this._parseTimeParameter(options.time))}.bind(this))}.bind(this)),this},Output.prototype.playNote=function(note,channel,options){var time,nVelocity=64;if((options=options||{}).rawVelocity?!isNaN(options.velocity)&&0<=options.velocity&&options.velocity<=127&&(nVelocity=options.velocity):!isNaN(options.velocity)&&0<=options.velocity&&options.velocity<=1&&(nVelocity=127*options.velocity),time=this._parseTimeParameter(options.time),this._convertNoteToArray(note).forEach(function(item){wm.toMIDIChannels(channel).forEach(function(ch){this.send((wm.MIDI_CHANNEL_MESSAGES.noteon<<4)+(ch-1),[item,Math.round(nVelocity)],time)}.bind(this))}.bind(this)),!isNaN(options.duration)){options.duration<=0&&(options.duration=0);var nRelease=64;options.rawVelocity?!isNaN(options.release)&&0<=options.release&&options.release<=127&&(nRelease=options.release):!isNaN(options.release)&&0<=options.release&&options.release<=1&&(nRelease=127*options.release),this._convertNoteToArray(note).forEach(function(item){wm.toMIDIChannels(channel).forEach(function(ch){this.send((wm.MIDI_CHANNEL_MESSAGES.noteoff<<4)+(ch-1),[item,Math.round(nRelease)],(time||wm.time)+options.duration)}.bind(this))}.bind(this))}return this},Output.prototype.sendKeyAftertouch=function(note,channel,pressure,options){var that=this;if(options=options||{},channel<1||16<channel)throw new RangeError(\\\"The channel must be between 1 and 16.\\\");(isNaN(pressure)||pressure<0||1<pressure)&&(pressure=.5);var nPressure=Math.round(127*pressure);return this._convertNoteToArray(note).forEach(function(item){wm.toMIDIChannels(channel).forEach(function(ch){that.send((wm.MIDI_CHANNEL_MESSAGES.keyaftertouch<<4)+(ch-1),[item,nPressure],that._parseTimeParameter(options.time))})}),this},Output.prototype.sendControlChange=function(controller,value,channel,options){if(options=options||{},\\\"string\\\"==typeof controller){if(void 0===(controller=wm.MIDI_CONTROL_CHANGE_MESSAGES[controller]))throw new TypeError(\\\"Invalid controller name.\\\")}else if(!(0<=(controller=Math.floor(controller))&&controller<=119))throw new RangeError(\\\"Controller numbers must be between 0 and 119.\\\");if(!(0<=(value=Math.floor(value)||0)&&value<=127))throw new RangeError(\\\"Controller value must be between 0 and 127.\\\");return wm.toMIDIChannels(channel).forEach(function(ch){this.send((wm.MIDI_CHANNEL_MESSAGES.controlchange<<4)+(ch-1),[controller,value],this._parseTimeParameter(options.time))}.bind(this)),this},Output.prototype._selectRegisteredParameter=function(parameter,channel,time){var that=this;if(parameter[0]=Math.floor(parameter[0]),!(0<=parameter[0]&&parameter[0]<=127))throw new RangeError(\\\"The control65 value must be between 0 and 127\\\");if(parameter[1]=Math.floor(parameter[1]),!(0<=parameter[1]&&parameter[1]<=127))throw new RangeError(\\\"The control64 value must be between 0 and 127\\\");return wm.toMIDIChannels(channel).forEach(function(){that.sendControlChange(101,parameter[0],channel,{time:time}),that.sendControlChange(100,parameter[1],channel,{time:time})}),this},Output.prototype._selectNonRegisteredParameter=function(parameter,channel,time){var that=this;if(parameter[0]=Math.floor(parameter[0]),!(0<=parameter[0]&&parameter[0]<=127))throw new RangeError(\\\"The control63 value must be between 0 and 127\\\");if(parameter[1]=Math.floor(parameter[1]),!(0<=parameter[1]&&parameter[1]<=127))throw new RangeError(\\\"The control62 value must be between 0 and 127\\\");return wm.toMIDIChannels(channel).forEach(function(){that.sendControlChange(99,parameter[0],channel,{time:time}),that.sendControlChange(98,parameter[1],channel,{time:time})}),this},Output.prototype._setCurrentRegisteredParameter=function(data,channel,time){var that=this;if((data=[].concat(data))[0]=Math.floor(data[0]),!(0<=data[0]&&data[0]<=127))throw new RangeError(\\\"The msb value must be between 0 and 127\\\");return wm.toMIDIChannels(channel).forEach(function(){that.sendControlChange(6,data[0],channel,{time:time})}),data[1]=Math.floor(data[1]),0<=data[1]&&data[1]<=127&&wm.toMIDIChannels(channel).forEach(function(){that.sendControlChange(38,data[1],channel,{time:time})}),this},Output.prototype._deselectRegisteredParameter=function(channel,time){var that=this;return wm.toMIDIChannels(channel).forEach(function(){that.sendControlChange(101,127,channel,{time:time}),that.sendControlChange(100,127,channel,{time:time})}),this},Output.prototype.setRegisteredParameter=function(parameter,data,channel,options){var that=this;if(options=options||{},!Array.isArray(parameter)){if(!wm.MIDI_REGISTERED_PARAMETER[parameter])throw new Error(\\\"The specified parameter is not available.\\\");parameter=wm.MIDI_REGISTERED_PARAMETER[parameter]}return wm.toMIDIChannels(channel).forEach(function(){that._selectRegisteredParameter(parameter,channel,options.time),that._setCurrentRegisteredParameter(data,channel,options.time),that._deselectRegisteredParameter(channel,options.time)}),this},Output.prototype.setNonRegisteredParameter=function(parameter,data,channel,options){var that=this;if(options=options||{},!(0<=parameter[0]&&parameter[0]<=127&&0<=parameter[1]&&parameter[1]<=127))throw new Error(\\\"Position 0 and 1 of the 2-position parameter array must both be between 0 and 127.\\\");return data=[].concat(data),wm.toMIDIChannels(channel).forEach(function(){that._selectNonRegisteredParameter(parameter,channel,options.time),that._setCurrentRegisteredParameter(data,channel,options.time),that._deselectRegisteredParameter(channel,options.time)}),this},Output.prototype.incrementRegisteredParameter=function(parameter,channel,options){var that=this;if(options=options||{},!Array.isArray(parameter)){if(!wm.MIDI_REGISTERED_PARAMETER[parameter])throw new Error(\\\"The specified parameter is not available.\\\");parameter=wm.MIDI_REGISTERED_PARAMETER[parameter]}return wm.toMIDIChannels(channel).forEach(function(){that._selectRegisteredParameter(parameter,channel,options.time),that.sendControlChange(96,0,channel,{time:options.time}),that._deselectRegisteredParameter(channel,options.time)}),this},Output.prototype.decrementRegisteredParameter=function(parameter,channel,options){if(options=options||{},!Array.isArray(parameter)){if(!wm.MIDI_REGISTERED_PARAMETER[parameter])throw new TypeError(\\\"The specified parameter is not available.\\\");parameter=wm.MIDI_REGISTERED_PARAMETER[parameter]}return wm.toMIDIChannels(channel).forEach(function(){this._selectRegisteredParameter(parameter,channel,options.time),this.sendControlChange(97,0,channel,{time:options.time}),this._deselectRegisteredParameter(channel,options.time)}.bind(this)),this},Output.prototype.setPitchBendRange=function(semitones,cents,channel,options){var that=this;if(options=options||{},!(0<=(semitones=Math.floor(semitones)||0)&&semitones<=127))throw new RangeError(\\\"The semitones value must be between 0 and 127\\\");if(!(0<=(cents=Math.floor(cents)||0)&&cents<=127))throw new RangeError(\\\"The cents value must be between 0 and 127\\\");return wm.toMIDIChannels(channel).forEach(function(){that.setRegisteredParameter(\\\"pitchbendrange\\\",[semitones,cents],channel,{time:options.time})}),this},Output.prototype.setModulationRange=function(semitones,cents,channel,options){var that=this;if(options=options||{},!(0<=(semitones=Math.floor(semitones)||0)&&semitones<=127))throw new RangeError(\\\"The semitones value must be between 0 and 127\\\");if(!(0<=(cents=Math.floor(cents)||0)&&cents<=127))throw new RangeError(\\\"The cents value must be between 0 and 127\\\");return wm.toMIDIChannels(channel).forEach(function(){that.setRegisteredParameter(\\\"modulationrange\\\",[semitones,cents],channel,{time:options.time})}),this},Output.prototype.setMasterTuning=function(value,channel,options){var that=this;if(options=options||{},(value=parseFloat(value)||0)<=-65||64<=value)throw new RangeError(\\\"The value must be a decimal number larger than -65 and smaller than 64.\\\");var coarse=Math.floor(value)+64,fine=value-Math.floor(value),msb=(fine=Math.round((fine+1)/2*16383))>>7&127,lsb=127&fine;return wm.toMIDIChannels(channel).forEach(function(){that.setRegisteredParameter(\\\"channelcoarsetuning\\\",coarse,channel,{time:options.time}),that.setRegisteredParameter(\\\"channelfinetuning\\\",[msb,lsb],channel,{time:options.time})}),this},Output.prototype.setTuningProgram=function(value,channel,options){var that=this;if(options=options||{},!(0<=(value=Math.floor(value))&&value<=127))throw new RangeError(\\\"The program value must be between 0 and 127\\\");return wm.toMIDIChannels(channel).forEach(function(){that.setRegisteredParameter(\\\"tuningprogram\\\",value,channel,{time:options.time})}),this},Output.prototype.setTuningBank=function(value,channel,options){var that=this;if(options=options||{},!(0<=(value=Math.floor(value)||0)&&value<=127))throw new RangeError(\\\"The bank value must be between 0 and 127\\\");return wm.toMIDIChannels(channel).forEach(function(){that.setRegisteredParameter(\\\"tuningbank\\\",value,channel,{time:options.time})}),this},Output.prototype.sendChannelMode=function(command,value,channel,options){if(options=options||{},\\\"string\\\"==typeof command){if(!(command=wm.MIDI_CHANNEL_MODE_MESSAGES[command]))throw new TypeError(\\\"Invalid channel mode message name.\\\")}else if(!(120<=(command=Math.floor(command))&&command<=127))throw new RangeError(\\\"Channel mode numerical identifiers must be between 120 and 127.\\\");if((value=Math.floor(value)||0)<0||127<value)throw new RangeError(\\\"Value must be an integer between 0 and 127.\\\");return wm.toMIDIChannels(channel).forEach(function(ch){this.send((wm.MIDI_CHANNEL_MESSAGES.channelmode<<4)+(ch-1),[command,value],this._parseTimeParameter(options.time))}.bind(this)),this},Output.prototype.sendProgramChange=function(program,channel,options){var that=this;if(options=options||{},program=Math.floor(program),isNaN(program)||program<0||127<program)throw new RangeError(\\\"Program numbers must be between 0 and 127.\\\");return wm.toMIDIChannels(channel).forEach(function(ch){that.send((wm.MIDI_CHANNEL_MESSAGES.programchange<<4)+(ch-1),[program],that._parseTimeParameter(options.time))}),this},Output.prototype.sendChannelAftertouch=function(pressure,channel,options){var that=this;options=options||{},pressure=parseFloat(pressure),(isNaN(pressure)||pressure<0||1<pressure)&&(pressure=.5);var nPressure=Math.round(127*pressure);return wm.toMIDIChannels(channel).forEach(function(ch){that.send((wm.MIDI_CHANNEL_MESSAGES.channelaftertouch<<4)+(ch-1),[nPressure],that._parseTimeParameter(options.time))}),this},Output.prototype.sendPitchBend=function(bend,channel,options){var that=this;if(options=options||{},isNaN(bend)||bend<-1||1<bend)throw new RangeError(\\\"Pitch bend value must be between -1 and 1.\\\");var nLevel=Math.round((bend+1)/2*16383),msb=nLevel>>7&127,lsb=127&nLevel;return wm.toMIDIChannels(channel).forEach(function(ch){that.send((wm.MIDI_CHANNEL_MESSAGES.pitchbend<<4)+(ch-1),[lsb,msb],that._parseTimeParameter(options.time))}),this},Output.prototype._parseTimeParameter=function(time){var value,parsed=parseFloat(time);return\\\"string\\\"==typeof time&&\\\"+\\\"===time.substring(0,1)?parsed&&0<parsed&&(value=wm.time+parsed):parsed>wm.time&&(value=parsed),value},Output.prototype._convertNoteToArray=function(note){var notes=[];return Array.isArray(note)||(note=[note]),note.forEach(function(item){notes.push(wm.guessNoteNumber(item))}),notes}, true?!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = (function(){return wm}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),\\n\\t\\t\\t\\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)):undefined}(this);\\n\\n//# sourceURL=webpack:///./node_modules/webmidi/webmidi.min.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/webpack/buildin/global.js\":\n/*!***********************************!*\\\n  !*** (webpack)/buildin/global.js ***!\n  \\***********************************/\n/*! no static exports found */\n/***/ (function(module, exports) {\n\neval(\"var g;\\n\\n// This works in non-strict mode\\ng = (function() {\\n\\treturn this;\\n})();\\n\\ntry {\\n\\t// This works if eval is allowed (see CSP)\\n\\tg = g || new Function(\\\"return this\\\")();\\n} catch (e) {\\n\\t// This works if the window reference is available\\n\\tif (typeof window === \\\"object\\\") g = window;\\n}\\n\\n// g can still be undefined, but nothing to do about it...\\n// We return undefined, instead of nothing here, so it's\\n// easier to handle this case. if(!global) { ...}\\n\\nmodule.exports = g;\\n\\n\\n//# sourceURL=webpack:///(webpack)/buildin/global.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/which-boxed-primitive/index.js\":\n/*!*****************************************************!*\\\n  !*** ./node_modules/which-boxed-primitive/index.js ***!\n  \\*****************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar isString = __webpack_require__(/*! is-string */ \\\"./node_modules/is-string/index.js\\\");\\nvar isNumber = __webpack_require__(/*! is-number-object */ \\\"./node_modules/is-number-object/index.js\\\");\\nvar isBoolean = __webpack_require__(/*! is-boolean-object */ \\\"./node_modules/is-boolean-object/index.js\\\");\\nvar isSymbol = __webpack_require__(/*! is-symbol */ \\\"./node_modules/is-symbol/index.js\\\");\\nvar isBigInt = __webpack_require__(/*! is-bigint */ \\\"./node_modules/is-bigint/index.js\\\");\\n\\n// eslint-disable-next-line consistent-return\\nmodule.exports = function whichBoxedPrimitive(value) {\\n\\t// eslint-disable-next-line eqeqeq\\n\\tif (value == null || (typeof value !== 'object' && typeof value !== 'function')) {\\n\\t\\treturn null;\\n\\t}\\n\\tif (isString(value)) {\\n\\t\\treturn 'String';\\n\\t}\\n\\tif (isNumber(value)) {\\n\\t\\treturn 'Number';\\n\\t}\\n\\tif (isBoolean(value)) {\\n\\t\\treturn 'Boolean';\\n\\t}\\n\\tif (isSymbol(value)) {\\n\\t\\treturn 'Symbol';\\n\\t}\\n\\tif (isBigInt(value)) {\\n\\t\\treturn 'BigInt';\\n\\t}\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/which-boxed-primitive/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/which-collection/index.js\":\n/*!************************************************!*\\\n  !*** ./node_modules/which-collection/index.js ***!\n  \\************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\n\\nvar isMap = __webpack_require__(/*! is-map */ \\\"./node_modules/is-map/index.js\\\");\\nvar isSet = __webpack_require__(/*! is-set */ \\\"./node_modules/is-set/index.js\\\");\\nvar isWeakMap = __webpack_require__(/*! is-weakmap */ \\\"./node_modules/is-weakmap/index.js\\\");\\nvar isWeakSet = __webpack_require__(/*! is-weakset */ \\\"./node_modules/is-weakset/index.js\\\");\\n\\nmodule.exports = function whichCollection(value) {\\n\\tif (value && typeof value === 'object') {\\n\\t\\tif (isMap(value)) {\\n\\t\\t\\treturn 'Map';\\n\\t\\t}\\n\\t\\tif (isSet(value)) {\\n\\t\\t\\treturn 'Set';\\n\\t\\t}\\n\\t\\tif (isWeakMap(value)) {\\n\\t\\t\\treturn 'WeakMap';\\n\\t\\t}\\n\\t\\tif (isWeakSet(value)) {\\n\\t\\t\\treturn 'WeakSet';\\n\\t\\t}\\n\\t}\\n\\treturn false;\\n};\\n\\n\\n//# sourceURL=webpack:///./node_modules/which-collection/index.js?\");\n\n/***/ }),\n\n/***/ \"./node_modules/which-typed-array/index.js\":\n/*!*************************************************!*\\\n  !*** ./node_modules/which-typed-array/index.js ***!\n  \\*************************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"/* WEBPACK VAR INJECTION */(function(global) {\\n\\nvar forEach = __webpack_require__(/*! foreach */ \\\"./node_modules/foreach/index.js\\\");\\nvar availableTypedArrays = __webpack_require__(/*! available-typed-arrays */ \\\"./node_modules/available-typed-arrays/index.js\\\");\\nvar callBound = __webpack_require__(/*! es-abstract/helpers/callBound */ \\\"./node_modules/es-abstract/helpers/callBound.js\\\");\\n\\nvar $toString = callBound('Object.prototype.toString');\\nvar hasSymbols = __webpack_require__(/*! has-symbols */ \\\"./node_modules/has-symbols/index.js\\\")();\\nvar hasToStringTag = hasSymbols && typeof Symbol.toStringTag === 'symbol';\\n\\nvar typedArrays = availableTypedArrays();\\n\\nvar $slice = callBound('String.prototype.slice');\\nvar toStrTags = {};\\nvar gOPD = __webpack_require__(/*! es-abstract/helpers/getOwnPropertyDescriptor */ \\\"./node_modules/es-abstract/helpers/getOwnPropertyDescriptor.js\\\");\\nvar getPrototypeOf = Object.getPrototypeOf; // require('getprototypeof');\\nif (hasToStringTag && gOPD && getPrototypeOf) {\\n\\tforEach(typedArrays, function (typedArray) {\\n\\t\\tif (typeof global[typedArray] === 'function') {\\n\\t\\t\\tvar arr = new global[typedArray]();\\n\\t\\t\\tif (!(Symbol.toStringTag in arr)) {\\n\\t\\t\\t\\tthrow new EvalError('this engine has support for Symbol.toStringTag, but ' + typedArray + ' does not have the property! Please report this.');\\n\\t\\t\\t}\\n\\t\\t\\tvar proto = getPrototypeOf(arr);\\n\\t\\t\\tvar descriptor = gOPD(proto, Symbol.toStringTag);\\n\\t\\t\\tif (!descriptor) {\\n\\t\\t\\t\\tvar superProto = getPrototypeOf(proto);\\n\\t\\t\\t\\tdescriptor = gOPD(superProto, Symbol.toStringTag);\\n\\t\\t\\t}\\n\\t\\t\\ttoStrTags[typedArray] = descriptor.get;\\n\\t\\t}\\n\\t});\\n}\\n\\nvar tryTypedArrays = function tryAllTypedArrays(value) {\\n\\tvar foundName = false;\\n\\tforEach(toStrTags, function (getter, typedArray) {\\n\\t\\tif (!foundName) {\\n\\t\\t\\ttry {\\n\\t\\t\\t\\tvar name = getter.call(value);\\n\\t\\t\\t\\tif (name === typedArray) {\\n\\t\\t\\t\\t\\tfoundName = name;\\n\\t\\t\\t\\t}\\n\\t\\t\\t} catch (e) {}\\n\\t\\t}\\n\\t});\\n\\treturn foundName;\\n};\\n\\nvar isTypedArray = __webpack_require__(/*! is-typed-array */ \\\"./node_modules/is-typed-array/index.js\\\");\\n\\nmodule.exports = function whichTypedArray(value) {\\n\\tif (!isTypedArray(value)) { return false; }\\n\\tif (!hasToStringTag) { return $slice($toString(value), 8, -1); }\\n\\treturn tryTypedArrays(value);\\n};\\n\\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../webpack/buildin/global.js */ \\\"./node_modules/webpack/buildin/global.js\\\")))\\n\\n//# sourceURL=webpack:///./node_modules/which-typed-array/index.js?\");\n\n/***/ }),\n\n/***/ \"./src/gui/component/audio-node.scss\":\n/*!*******************************************!*\\\n  !*** ./src/gui/component/audio-node.scss ***!\n  \\*******************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"\\n        var result = __webpack_require__(/*! !../../../node_modules/css-loader/dist/cjs.js!../../../node_modules/sass-loader/dist/cjs.js??ref--5-2!./audio-node.scss */ \\\"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/gui/component/audio-node.scss\\\");\\n\\n        if (typeof result === \\\"string\\\") {\\n            module.exports = result;\\n        } else {\\n            module.exports = result.toString();\\n        }\\n    \\n\\n//# sourceURL=webpack:///./src/gui/component/audio-node.scss?\");\n\n/***/ }),\n\n/***/ \"./src/gui/component/audio-node.ts\":\n/*!*****************************************!*\\\n  !*** ./src/gui/component/audio-node.ts ***!\n  \\*****************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\\n    return new (P || (P = Promise))(function (resolve, reject) {\\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\\n        function rejected(value) { try { step(generator[\\\"throw\\\"](value)); } catch (e) { reject(e); } }\\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\\n    });\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.createElement = exports.ToneAudioNodeElement = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\n__webpack_require__(/*! ../value/number */ \\\"./src/gui/value/number.ts\\\");\\n__webpack_require__(/*! ../value/string */ \\\"./src/gui/value/string.ts\\\");\\n__webpack_require__(/*! ../value/array */ \\\"./src/gui/value/array.ts\\\");\\n__webpack_require__(/*! ../value/boolean */ \\\"./src/gui/value/boolean.ts\\\");\\n__webpack_require__(/*! ../vis/visualizer */ \\\"./src/gui/vis/visualizer.ts\\\");\\nconst style = __webpack_require__(/*! ./audio-node.scss */ \\\"./src/gui/component/audio-node.scss\\\");\\n__webpack_require__(/*! @material/mwc-icon */ \\\"./node_modules/@material/mwc-icon/mwc-icon.js\\\");\\nlet ToneAudioNodeElement = class ToneAudioNodeElement extends lit_element_1.LitElement {\\n    constructor() {\\n        super(...arguments);\\n        /**\\n         * If the node is open or closed\\n         */\\n        this.open = true;\\n    }\\n    pathToObject(path, value) {\\n        const obj = {};\\n        let subValue = obj;\\n        path.forEach((prop, index) => {\\n            if (index === path.length - 1) {\\n                subValue[prop] = value;\\n            }\\n            else {\\n                subValue[prop] = {};\\n                subValue = subValue[prop];\\n            }\\n        });\\n        return obj;\\n    }\\n    pathToValue(path, obj) {\\n        let subValue = obj;\\n        let retValue = undefined;\\n        path.forEach((prop, index) => {\\n            if (index === path.length - 1) {\\n                retValue = subValue[prop];\\n            }\\n            else {\\n                subValue = subValue[prop];\\n            }\\n        });\\n        return retValue;\\n    }\\n    bind(tone) {\\n        return __awaiter(this, void 0, void 0, function* () {\\n            this.tone = tone;\\n            yield this.requestUpdate();\\n            // also bind all of the children nodes\\n            this.shadowRoot\\n                .querySelectorAll(\\\"tone-visualizer\\\")\\n                .forEach((vis) => {\\n                vis.bind(this.tone);\\n            });\\n        });\\n    }\\n    setValue(path, detail) {\\n        if (this.tone) {\\n            const currentValue = this.tone.get();\\n            try {\\n                this.tone.set(this.pathToObject(path, detail.value));\\n            }\\n            catch (e) {\\n                const previousValue = this.pathToValue(path, currentValue);\\n                this.tone.set(this.pathToObject(path, previousValue));\\n                detail.reject(previousValue);\\n            }\\n            this.requestUpdate();\\n        }\\n    }\\n    renderValue(name, values, path) {\\n        const value = values[name];\\n        if (typeof value === \\\"number\\\") {\\n            return lit_element_1.html `\\n\\t\\t\\t\\t<tone-number\\n\\t\\t\\t\\t\\tclass=\\\"value\\\"\\n\\t\\t\\t\\t\\t@value=${(e) => this.setValue(path, e.detail)}\\n\\t\\t\\t\\t\\tname=\\\"${name}\\\"\\n\\t\\t\\t\\t\\tvalue=${value}\\n\\t\\t\\t\\t></tone-number>\\n\\t\\t\\t`;\\n        }\\n        else if (typeof value === \\\"string\\\") {\\n            return lit_element_1.html `\\n\\t\\t\\t\\t<tone-string\\n\\t\\t\\t\\t\\tclass=\\\"value\\\"\\n\\t\\t\\t\\t\\t@value=${(e) => this.setValue(path, e.detail)}\\n\\t\\t\\t\\t\\tname=\\\"${name}\\\"\\n\\t\\t\\t\\t\\tvalue=\\\"${value}\\\"\\n\\t\\t\\t\\t></tone-string>\\n\\t\\t\\t`;\\n        }\\n        else if (typeof value === \\\"boolean\\\") {\\n            return lit_element_1.html `\\n\\t\\t\\t\\t<tone-boolean\\n\\t\\t\\t\\t\\tclass=\\\"value\\\"\\n\\t\\t\\t\\t\\t@value=${(e) => this.setValue(path, e.detail)}\\n\\t\\t\\t\\t\\tname=\\\"${name}\\\"\\n\\t\\t\\t\\t\\t?value=${value}\\n\\t\\t\\t\\t></tone-boolean>\\n\\t\\t\\t`;\\n        }\\n        else if (Array.isArray(value)) {\\n            return lit_element_1.html `\\n\\t\\t\\t\\t<tone-array\\n\\t\\t\\t\\t\\tclass=\\\"value\\\"\\n\\t\\t\\t\\t\\t@value=${(e) => this.setValue(path, e.detail)}\\n\\t\\t\\t\\t\\tname=\\\"${name}\\\"\\n\\t\\t\\t\\t\\tvalue=${JSON.stringify(value)}\\n\\t\\t\\t\\t></tone-array>\\n\\t\\t\\t`;\\n        }\\n        else if (typeof value === \\\"object\\\") {\\n            return lit_element_1.html `\\n\\t\\t\\t\\t<details\\n\\t\\t\\t\\t\\tclass=\\\"sub-value\\\"\\n\\t\\t\\t\\t\\t@toggle=${(e) => (e.target.querySelector(\\\"mwc-icon\\\").textContent = e\\n                .target.open\\n                ? \\\"arrow_drop_down\\\"\\n                : \\\"arrow_right\\\")}\\n\\t\\t\\t\\t>\\n\\t\\t\\t\\t\\t<summary>\\n\\t\\t\\t\\t\\t\\t<mwc-icon>\\n\\t\\t\\t\\t\\t\\t\\tarrow_right\\n\\t\\t\\t\\t\\t\\t</mwc-icon>\\n\\t\\t\\t\\t\\t\\t${name}\\n\\t\\t\\t\\t\\t</summary>\\n\\t\\t\\t\\t\\t<div class=\\\"sub-values\\\">\\n\\t\\t\\t\\t\\t\\t${this.renderValues(value, [...path])}\\n\\t\\t\\t\\t\\t</div>\\n\\t\\t\\t\\t</details>\\n\\t\\t\\t`;\\n        }\\n    }\\n    toneObjFromPath(path) {\\n        let tone = this.tone;\\n        path.forEach((seg) => {\\n            tone = tone[seg];\\n        });\\n        if (tone) {\\n            return tone.get();\\n        }\\n        else {\\n            return {};\\n        }\\n    }\\n    sortValues(values) {\\n        const ret = {};\\n        const keys = Object.keys(values);\\n        function isObject(value) {\\n            return typeof value === \\\"object\\\" && !Array.isArray(value);\\n        }\\n        // first put in all of the non-objects\\n        keys.sort().forEach((key) => {\\n            const value = values[key];\\n            if (!isObject(value)) {\\n                ret[key] = value;\\n            }\\n        });\\n        // put in all of the objects\\n        keys.sort().forEach((key) => {\\n            const value = values[key];\\n            if (isObject(value) && Object.keys(value).length) {\\n                ret[key] = value;\\n            }\\n        });\\n        return ret;\\n    }\\n    renderValues(values, path) {\\n        values = this.sortValues(values);\\n        return lit_element_1.html `\\n\\t\\t\\t<tone-visualizer\\n\\t\\t\\t\\tpath=${JSON.stringify(path)}\\n\\t\\t\\t\\tvalues=${JSON.stringify(this.toneObjFromPath(path))}\\n\\t\\t\\t>\\n\\t\\t\\t</tone-visualizer>\\n\\t\\t\\t${Object.keys(values).map((name) => lit_element_1.html `\\n\\t\\t\\t\\t\\t${this.renderValue(name, values, [...path, name])}\\n\\t\\t\\t\\t`)}\\n\\t\\t`;\\n    }\\n    static get styles() {\\n        return lit_element_1.css `\\n\\t\\t\\t${lit_element_1.unsafeCSS(style)}\\n\\t\\t`;\\n    }\\n    render() {\\n        if (this.tone) {\\n            return lit_element_1.html `\\n\\t\\t\\t\\t<div id=\\\"container\\\">\\n\\t\\t\\t\\t\\t<details\\n\\t\\t\\t\\t\\t\\t?open=${this.open}\\n\\t\\t\\t\\t\\t\\t@toggle=${(e) => (this.open = e.target.open)}\\n\\t\\t\\t\\t\\t>\\n\\t\\t\\t\\t\\t\\t<summary id=\\\"title\\\">\\n\\t\\t\\t\\t\\t\\t\\t<mwc-icon>\\n\\t\\t\\t\\t\\t\\t\\t\\t${this.open\\n                ? \\\"keyboard_arrow_down\\\"\\n                : \\\"keyboard_arrow_right\\\"}\\n\\t\\t\\t\\t\\t\\t\\t</mwc-icon>\\n\\t\\t\\t\\t\\t\\t\\t<span>\\n\\t\\t\\t\\t\\t\\t\\t\\t${this.name}\\n\\t\\t\\t\\t\\t\\t\\t</span>\\n\\t\\t\\t\\t\\t\\t</summary>\\n\\t\\t\\t\\t\\t\\t${this.renderValues(this.tone.get(), [])}\\n\\t\\t\\t\\t\\t\\t<details id=\\\"json\\\">\\n\\t\\t\\t\\t\\t\\t\\t<summary> <mwc-icon>code</mwc-icon> </summary>\\n\\t\\t\\t\\t\\t\\t\\t<pre>\\n${JSON.stringify(this.tone.get(), undefined, \\\"\\\\t\\\")}</pre\\n\\t\\t\\t\\t\\t\\t\\t>\\n\\t\\t\\t\\t\\t\\t</details>\\n\\t\\t\\t\\t\\t</details>\\n\\t\\t\\t\\t</div>\\n\\t\\t\\t`;\\n        }\\n        else {\\n            return lit_element_1.html `\\n\\t\\t\\t\\t<div id=\\\"container\\\">\\n\\t\\t\\t\\t\\t<h4>${this.name}</h4>\\n\\t\\t\\t\\t\\t<div>Set a Tone.js object with 'bind'</div>\\n\\t\\t\\t\\t</div>\\n\\t\\t\\t`;\\n        }\\n    }\\n};\\n__decorate([\\n    lit_element_1.property({ type: String })\\n], ToneAudioNodeElement.prototype, \\\"name\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], ToneAudioNodeElement.prototype, \\\"open\\\", void 0);\\nToneAudioNodeElement = __decorate([\\n    lit_element_1.customElement(\\\"tone-audio-node\\\")\\n], ToneAudioNodeElement);\\nexports.ToneAudioNodeElement = ToneAudioNodeElement;\\n/**\\n * Create an audio node element\\n */\\nfunction createElement({ tone, name = tone.toString(), parent, open = false, }) {\\n    const element = document.createElement(\\\"tone-audio-node\\\");\\n    element.bind(tone);\\n    element.name = name;\\n    element.open = open;\\n    if (parent) {\\n        parent.appendChild(element);\\n    }\\n    return element;\\n}\\nexports.createElement = createElement;\\n\\n\\n//# sourceURL=webpack:///./src/gui/component/audio-node.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/component/drawer.scss\":\n/*!***************************************!*\\\n  !*** ./src/gui/component/drawer.scss ***!\n  \\***************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"\\n        var result = __webpack_require__(/*! !../../../node_modules/css-loader/dist/cjs.js!../../../node_modules/sass-loader/dist/cjs.js??ref--5-2!./drawer.scss */ \\\"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/gui/component/drawer.scss\\\");\\n\\n        if (typeof result === \\\"string\\\") {\\n            module.exports = result;\\n        } else {\\n            module.exports = result.toString();\\n        }\\n    \\n\\n//# sourceURL=webpack:///./src/gui/component/drawer.scss?\");\n\n/***/ }),\n\n/***/ \"./src/gui/component/drawer.ts\":\n/*!*************************************!*\\\n  !*** ./src/gui/component/drawer.ts ***!\n  \\*************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.createDrawer = exports.ToneDrawerElement = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst audio_node_1 = __webpack_require__(/*! ./audio-node */ \\\"./src/gui/component/audio-node.ts\\\");\\nconst folder_1 = __webpack_require__(/*! ./folder */ \\\"./src/gui/component/folder.ts\\\");\\nconst style = __webpack_require__(/*! ./drawer.scss */ \\\"./src/gui/component/drawer.scss\\\");\\n__webpack_require__(/*! @material/mwc-icon */ \\\"./node_modules/@material/mwc-icon/mwc-icon.js\\\");\\n/**\\n * Collapsible element to add\\n */\\nlet ToneDrawerElement = class ToneDrawerElement extends lit_element_1.LitElement {\\n    constructor() {\\n        super(...arguments);\\n        /**\\n         * If the element is collapsed\\n         */\\n        this.open = true;\\n        /**\\n         * If the element is not visible on the page\\n         */\\n        this.hidden = false;\\n    }\\n    firstUpdated(props) {\\n        super.firstUpdated(props);\\n        document.body.addEventListener(\\\"keypress\\\", (e) => {\\n            if (e.key === \\\"H\\\") {\\n                this.hidden = !this.hidden;\\n            }\\n        });\\n    }\\n    static get styles() {\\n        return lit_element_1.css `\\n\\t\\t\\t${lit_element_1.unsafeCSS(style)}\\n\\t\\t`;\\n    }\\n    /**\\n     * Add a Tone.js ToneAudioNode\\n     */\\n    add(options) {\\n        const element = audio_node_1.createElement(options);\\n        this.appendChild(element);\\n        return this;\\n    }\\n    /**\\n     * Create a folder with the given name\\n     */\\n    folder({ name, open }) {\\n        const element = folder_1.createFolder({ name, open });\\n        this.appendChild(element);\\n        return element;\\n    }\\n    render() {\\n        return lit_element_1.html `\\n\\t\\t\\t<div id=\\\"container\\\" ?open=${this.open} ?hidden=${this.hidden}>\\n\\t\\t\\t\\t<details\\n\\t\\t\\t\\t\\t?open=${this.open}\\n\\t\\t\\t\\t\\t@toggle=${(e) => (this.open = e.target.open)}\\n\\t\\t\\t\\t>\\n\\t\\t\\t\\t\\t<summary>\\n\\t\\t\\t\\t\\t\\t<mwc-icon>\\n\\t\\t\\t\\t\\t\\t\\t${!this.open ? \\\"unfold_more\\\" : \\\"unfold_less\\\"}\\n\\t\\t\\t\\t\\t\\t</mwc-icon>\\n\\t\\t\\t\\t\\t\\t${this.open ? \\\"close\\\" : \\\"controls\\\"}\\n\\t\\t\\t\\t\\t</summary>\\n\\t\\t\\t\\t\\t<div id=\\\"scroll\\\">\\n\\t\\t\\t\\t\\t\\t<div id=\\\"inner-scroll\\\">\\n\\t\\t\\t\\t\\t\\t\\t<slot></slot>\\n\\t\\t\\t\\t\\t\\t</div>\\n\\t\\t\\t\\t\\t</div>\\n\\t\\t\\t\\t</details>\\n\\t\\t\\t</div>\\n\\t\\t`;\\n    }\\n};\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], ToneDrawerElement.prototype, \\\"open\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], ToneDrawerElement.prototype, \\\"hidden\\\", void 0);\\nToneDrawerElement = __decorate([\\n    lit_element_1.customElement(\\\"tone-drawer\\\")\\n], ToneDrawerElement);\\nexports.ToneDrawerElement = ToneDrawerElement;\\n/**\\n * Create a collapsible drawer\\n */\\nfunction createDrawer({ parent = document.body, open = false, } = {}) {\\n    const element = document.createElement(\\\"tone-drawer\\\");\\n    if (parent) {\\n        parent.appendChild(element);\\n    }\\n    element.open = open;\\n    return element;\\n}\\nexports.createDrawer = createDrawer;\\n\\n\\n//# sourceURL=webpack:///./src/gui/component/drawer.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/component/folder.scss\":\n/*!***************************************!*\\\n  !*** ./src/gui/component/folder.scss ***!\n  \\***************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"\\n        var result = __webpack_require__(/*! !../../../node_modules/css-loader/dist/cjs.js!../../../node_modules/sass-loader/dist/cjs.js??ref--5-2!./folder.scss */ \\\"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/gui/component/folder.scss\\\");\\n\\n        if (typeof result === \\\"string\\\") {\\n            module.exports = result;\\n        } else {\\n            module.exports = result.toString();\\n        }\\n    \\n\\n//# sourceURL=webpack:///./src/gui/component/folder.scss?\");\n\n/***/ }),\n\n/***/ \"./src/gui/component/folder.ts\":\n/*!*************************************!*\\\n  !*** ./src/gui/component/folder.ts ***!\n  \\*************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.createFolder = exports.ToneFolderElement = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst audio_node_1 = __webpack_require__(/*! ./audio-node */ \\\"./src/gui/component/audio-node.ts\\\");\\nconst style = __webpack_require__(/*! ./folder.scss */ \\\"./src/gui/component/folder.scss\\\");\\n__webpack_require__(/*! @material/mwc-icon */ \\\"./node_modules/@material/mwc-icon/mwc-icon.js\\\");\\n/**\\n * A collapsible folder inside tone-drawer\\n */\\nlet ToneFolderElement = class ToneFolderElement extends lit_element_1.LitElement {\\n    constructor() {\\n        super(...arguments);\\n        /**\\n         * If it is open or collapsed\\n         */\\n        this.open = true;\\n    }\\n    static get styles() {\\n        return lit_element_1.css `\\n\\t\\t\\t${lit_element_1.unsafeCSS(style)}\\n\\t\\t`;\\n    }\\n    /**\\n     * Add a Tone.js ToneAudioNode\\n     */\\n    add({ tone, name }) {\\n        const element = audio_node_1.createElement({\\n            tone,\\n            name,\\n        });\\n        this.appendChild(element);\\n        return this;\\n    }\\n    render() {\\n        return lit_element_1.html `\\n\\t\\t\\t<div id=\\\"container\\\" ?open=${this.open}>\\n\\t\\t\\t\\t<details\\n\\t\\t\\t\\t\\t?open=${this.open}\\n\\t\\t\\t\\t\\t@toggle=${(e) => (this.open = e.target.open)}\\n\\t\\t\\t\\t>\\n\\t\\t\\t\\t\\t<summary>\\n\\t\\t\\t\\t\\t\\t<mwc-icon>\\n\\t\\t\\t\\t\\t\\t\\t${this.open\\n            ? \\\"keyboard_arrow_down\\\"\\n            : \\\"keyboard_arrow_right\\\"}\\n\\t\\t\\t\\t\\t\\t</mwc-icon>\\n\\t\\t\\t\\t\\t\\t<span>\\n\\t\\t\\t\\t\\t\\t\\t${this.name}\\n\\t\\t\\t\\t\\t\\t</span>\\n\\t\\t\\t\\t\\t</summary>\\n\\t\\t\\t\\t\\t<div id=\\\"contents\\\">\\n\\t\\t\\t\\t\\t\\t<slot></slot>\\n\\t\\t\\t\\t\\t</div>\\n\\t\\t\\t\\t</details>\\n\\t\\t\\t</div>\\n\\t\\t`;\\n    }\\n};\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], ToneFolderElement.prototype, \\\"open\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: String })\\n], ToneFolderElement.prototype, \\\"name\\\", void 0);\\nToneFolderElement = __decorate([\\n    lit_element_1.customElement(\\\"tone-folder\\\")\\n], ToneFolderElement);\\nexports.ToneFolderElement = ToneFolderElement;\\n/**\\n * Create a folder with the given name\\n */\\nfunction createFolder({ name, parent, open = false, }) {\\n    const element = document.createElement(\\\"tone-folder\\\");\\n    element.name = name;\\n    element.open = open;\\n    if (parent) {\\n        parent.appendChild(element);\\n    }\\n    return element;\\n}\\nexports.createFolder = createFolder;\\n\\n\\n//# sourceURL=webpack:///./src/gui/component/folder.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/index.ts\":\n/*!**************************!*\\\n  !*** ./src/gui/index.ts ***!\n  \\**************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.piano = exports.meter = exports.fft = exports.waveform = exports.folder = exports.drawer = exports.ui = void 0;\\n__webpack_require__(/*! ./component/audio-node */ \\\"./src/gui/component/audio-node.ts\\\");\\n__webpack_require__(/*! ./component/drawer */ \\\"./src/gui/component/drawer.ts\\\");\\n__webpack_require__(/*! ./component/folder */ \\\"./src/gui/component/folder.ts\\\");\\n__webpack_require__(/*! ./piano/piano */ \\\"./src/gui/piano/piano.ts\\\");\\n__webpack_require__(/*! @material/mwc-icon */ \\\"./node_modules/@material/mwc-icon/mwc-icon.js\\\");\\nconst audio_node_1 = __webpack_require__(/*! ./component/audio-node */ \\\"./src/gui/component/audio-node.ts\\\");\\nconst drawer_1 = __webpack_require__(/*! ./component/drawer */ \\\"./src/gui/component/drawer.ts\\\");\\nconst folder_1 = __webpack_require__(/*! ./component/folder */ \\\"./src/gui/component/folder.ts\\\");\\nconst waveform_1 = __webpack_require__(/*! ./vis/waveform */ \\\"./src/gui/vis/waveform.ts\\\");\\nconst fft_1 = __webpack_require__(/*! ./vis/fft */ \\\"./src/gui/vis/fft.ts\\\");\\nconst meter_1 = __webpack_require__(/*! ./vis/meter */ \\\"./src/gui/vis/meter.ts\\\");\\nconst piano_1 = __webpack_require__(/*! ./piano/piano */ \\\"./src/gui/piano/piano.ts\\\");\\nvar drawer_2 = __webpack_require__(/*! ./component/drawer */ \\\"./src/gui/component/drawer.ts\\\");\\nObject.defineProperty(exports, \\\"ToneDrawerElement\\\", { enumerable: true, get: function () { return drawer_2.ToneDrawerElement; } });\\nvar folder_2 = __webpack_require__(/*! ./component/folder */ \\\"./src/gui/component/folder.ts\\\");\\nObject.defineProperty(exports, \\\"ToneFolderElement\\\", { enumerable: true, get: function () { return folder_2.ToneFolderElement; } });\\nvar audio_node_2 = __webpack_require__(/*! ./component/audio-node */ \\\"./src/gui/component/audio-node.ts\\\");\\nObject.defineProperty(exports, \\\"ToneAudioNodeElement\\\", { enumerable: true, get: function () { return audio_node_2.ToneAudioNodeElement; } });\\nexports.ui = audio_node_1.createElement;\\nexports.drawer = drawer_1.createDrawer;\\nexports.folder = folder_1.createFolder;\\nexports.waveform = waveform_1.createWaveform;\\nexports.fft = fft_1.createFFT;\\nexports.meter = meter_1.createMeter;\\nexports.piano = piano_1.createPiano;\\n\\n\\n//# sourceURL=webpack:///./src/gui/index.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/piano/keyboard.ts\":\n/*!***********************************!*\\\n  !*** ./src/gui/piano/keyboard.ts ***!\n  \\***********************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneKeyboard = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst AudioKeys = __webpack_require__(/*! audiokeys */ \\\"./node_modules/audiokeys/src/AudioKeys.js\\\");\\n__webpack_require__(/*! ./octave */ \\\"./src/gui/piano/octave.ts\\\");\\n__webpack_require__(/*! ./note */ \\\"./src/gui/piano/note.ts\\\");\\nlet ToneKeyboard = class ToneKeyboard extends lit_element_1.LitElement {\\n    constructor() {\\n        super();\\n        this.rootoctave = 4;\\n        this.octaves = 4;\\n        this.polyphonic = false;\\n        this._computerKeyboard = new AudioKeys({ polyphony: Infinity });\\n        this._computerKeyboard.down((e) => {\\n            this.noteon(e.note);\\n        });\\n        this._computerKeyboard.up((e) => {\\n            this.noteoff(e.note);\\n        });\\n    }\\n    getNoteByTouchId(id) {\\n        const octaves = Array.from(this.shadowRoot.querySelectorAll(\\\"tone-keyboard-octave\\\"));\\n        const octave = octaves.find((o) => o.getNoteByTouchId(id));\\n        if (octave) {\\n            return octave.getNoteByTouchId(id);\\n        }\\n    }\\n    _touchmove(event) {\\n        Array.from(event.changedTouches).forEach((e) => {\\n            this.getNoteByTouchId(e.identifier);\\n            const activeNote = this.getNoteByTouchId(e.identifier);\\n            const element = this.shadowRoot.elementFromPoint(e.clientX, e.clientY);\\n            if (element && element.shadowRoot) {\\n                const note = element.shadowRoot.elementFromPoint(e.clientX, e.clientY);\\n                if (note && note.note && activeNote.note !== note.note) {\\n                    activeNote.active = false;\\n                    activeNote.touchid = -1;\\n                    note.active = true;\\n                    note.touchid = e.identifier;\\n                }\\n            }\\n        });\\n    }\\n    _touchend(event) {\\n        Array.from(event.changedTouches).forEach((e) => {\\n            this.getNoteByTouchId(e.identifier);\\n            const activeNote = this.getNoteByTouchId(e.identifier);\\n            if (activeNote && activeNote.active) {\\n                activeNote.active = false;\\n                activeNote.touchid = -1;\\n            }\\n        });\\n    }\\n    noteon(midi) {\\n        const octaveNumber = Math.floor(midi / 12);\\n        const toneOctave = this.shadowRoot.querySelector(`tone-keyboard-octave[octave=\\\"${octaveNumber}\\\"]`);\\n        if (toneOctave) {\\n            toneOctave.noteon(midi);\\n        }\\n    }\\n    noteoff(midi) {\\n        const octaveNumber = Math.floor(midi / 12);\\n        const toneOctave = this.shadowRoot.querySelector(`tone-keyboard-octave[octave=\\\"${octaveNumber}\\\"]`);\\n        if (toneOctave) {\\n            toneOctave.noteoff(midi);\\n        }\\n    }\\n    render() {\\n        const octaves = [];\\n        for (let i = this.rootoctave; i < this.rootoctave + this.octaves; i++) {\\n            octaves.push(i);\\n        }\\n        return lit_element_1.html `\\n\\t\\t\\t<style>\\n\\t\\t\\t\\t#container {\\n\\t\\t\\t\\t\\tdisplay: flex;\\n\\t\\t\\t\\t\\tbackground-color: white;\\n\\t\\t\\t\\t\\theight: 80px;\\n\\t\\t\\t\\t}\\n\\n\\t\\t\\t\\ttone-keyboard-octave {\\n\\t\\t\\t\\t\\tflex-grow: 1;\\n\\t\\t\\t\\t}\\n\\t\\t\\t</style>\\n\\t\\t\\t<div\\n\\t\\t\\t\\tid=\\\"container\\\"\\n\\t\\t\\t\\t@touchmove=${this._touchmove.bind(this)}\\n\\t\\t\\t\\t@touchend=${this._touchend.bind(this)}\\n\\t\\t\\t>\\n\\t\\t\\t\\t${octaves.map((o) => lit_element_1.html `\\n\\t\\t\\t\\t\\t\\t<tone-keyboard-octave\\n\\t\\t\\t\\t\\t\\t\\toctave=${o.toString()}\\n\\t\\t\\t\\t\\t\\t></tone-keyboard-octave>\\n\\t\\t\\t\\t\\t`)}\\n\\t\\t\\t</div>\\n\\t\\t`;\\n    }\\n};\\n__decorate([\\n    lit_element_1.property({ type: Number })\\n], ToneKeyboard.prototype, \\\"rootoctave\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Number })\\n], ToneKeyboard.prototype, \\\"octaves\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], ToneKeyboard.prototype, \\\"polyphonic\\\", void 0);\\nToneKeyboard = __decorate([\\n    lit_element_1.customElement(\\\"tone-keyboard\\\")\\n], ToneKeyboard);\\nexports.ToneKeyboard = ToneKeyboard;\\n\\n\\n//# sourceURL=webpack:///./src/gui/piano/keyboard.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/piano/midi-in.ts\":\n/*!**********************************!*\\\n  !*** ./src/gui/piano/midi-in.ts ***!\n  \\**********************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneMidiIn = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\n// import * as WebMidi from \\\"webmidi\\\";\\nconst WebMidi = __webpack_require__(/*! webmidi */ \\\"./node_modules/webmidi/webmidi.min.js\\\");\\nlet ToneMidiIn = class ToneMidiIn extends lit_element_1.LitElement {\\n    constructor() {\\n        super();\\n        this._flashTimeout = -1;\\n        WebMidi.enable((e) => {\\n            if (!e) {\\n                WebMidi.addListener(\\\"connected\\\", (e) => {\\n                    if (e.port.type === \\\"input\\\") {\\n                        this.requestUpdate();\\n                    }\\n                });\\n                WebMidi.addListener(\\\"disconnected\\\", (e) => {\\n                    this.requestUpdate();\\n                });\\n            }\\n        });\\n    }\\n    _flash() {\\n        clearTimeout(this._flashTimeout);\\n        const light = this.shadowRoot.querySelector(\\\"#light\\\");\\n        light.classList.add(\\\"flash\\\");\\n        this._flashTimeout = setTimeout(() => light.classList.remove(\\\"flash\\\"), 100);\\n    }\\n    _connectMidi(event) {\\n        if (event.target.value === \\\"none\\\") {\\n            this.shadowRoot\\n                .querySelector(\\\"#light\\\")\\n                .classList.remove(\\\"connected\\\");\\n            return;\\n        }\\n        else {\\n            this.shadowRoot.querySelector(\\\"#light\\\").classList.add(\\\"connected\\\");\\n        }\\n        const input = WebMidi.getInputById(event.target.value);\\n        if (input) {\\n            input.addListener(\\\"noteon\\\", \\\"all\\\", (e) => {\\n                const name = `${e.note.name}${e.note.octave}`;\\n                const midi = e.note.number;\\n                this._flash();\\n                this.dispatchEvent(new CustomEvent(\\\"noteon\\\", {\\n                    detail: {\\n                        name,\\n                        midi,\\n                        velocity: e.velocity,\\n                    },\\n                    composed: true,\\n                    bubbles: true,\\n                }));\\n            });\\n            input.addListener(\\\"noteoff\\\", \\\"all\\\", (e) => {\\n                const name = `${e.note.name}${e.note.octave}`;\\n                const midi = e.note.number;\\n                this._flash();\\n                this.dispatchEvent(new CustomEvent(\\\"noteoff\\\", {\\n                    detail: {\\n                        name,\\n                        midi,\\n                        velocity: e.velocity,\\n                    },\\n                    composed: true,\\n                    bubbles: true,\\n                }));\\n            });\\n            input.addListener(\\\"controlchange\\\", \\\"all\\\", (e) => {\\n                this._flash();\\n            });\\n        }\\n    }\\n    static get styles() {\\n        return lit_element_1.css `\\n\\t\\t\\t:host {\\n\\t\\t\\t\\tdisplay: block;\\n\\t\\t\\t}\\n\\n\\t\\t\\t#container {\\n\\t\\t\\t\\tdisplay: block;\\n\\t\\t\\t\\tmargin-bottom: 10px;\\n\\t\\t\\t\\tposition: relative;\\n\\t\\t\\t}\\n\\t\\t\\tlabel {\\n\\t\\t\\t\\tfont-family: var(--label-font-family);\\n\\t\\t\\t\\tfont-size: var(--label-font-size);\\n\\t\\t\\t\\tmargin-right: 5px;\\n\\t\\t\\t\\tfont-size: 0.7em;\\n\\t\\t\\t}\\n\\n\\t\\t\\tselect,\\n\\t\\t\\tlabel {\\n\\t\\t\\t\\tdisplay: inline-block;\\n\\t\\t\\t}\\n\\n\\t\\t\\t#light {\\n\\t\\t\\t\\twidth: 10px;\\n\\t\\t\\t\\theight: 10px;\\n\\t\\t\\t\\tbackground-color: white;\\n\\t\\t\\t\\tdisplay: inline-block;\\n\\t\\t\\t}\\n\\t\\t\\t#light.connected {\\n\\t\\t\\t\\tbackground-color: var(--color-gray);\\n\\t\\t\\t}\\n\\n\\t\\t\\t#light.connected.flash {\\n\\t\\t\\t\\tbackground-color: black !important;\\n\\t\\t\\t}\\n\\t\\t`;\\n    }\\n    render() {\\n        if (WebMidi.supported) {\\n            return lit_element_1.html `\\n\\t\\t\\t\\t<div id=\\\"container\\\">\\n\\t\\t\\t\\t\\t<div id=\\\"light\\\"></div>\\n\\t\\t\\t\\t\\t<label>MIDI IN:</label>\\n\\t\\t\\t\\t\\t<select @change=${this._connectMidi.bind(this)}>\\n\\t\\t\\t\\t\\t\\t<option value=\\\"none\\\">none</option>\\n\\t\\t\\t\\t\\t\\t${WebMidi.inputs.map((input) => lit_element_1.html `\\n\\t\\t\\t\\t\\t\\t\\t\\t<option value=${input.id}>${input.name}</option>\\n\\t\\t\\t\\t\\t\\t\\t`)}\\n\\t\\t\\t\\t\\t</select>\\n\\t\\t\\t\\t</div>\\n\\t\\t\\t`;\\n        }\\n        else {\\n            return lit_element_1.html ``;\\n        }\\n    }\\n};\\nToneMidiIn = __decorate([\\n    lit_element_1.customElement(\\\"tone-midi-in\\\")\\n], ToneMidiIn);\\nexports.ToneMidiIn = ToneMidiIn;\\n\\n\\n//# sourceURL=webpack:///./src/gui/piano/midi-in.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/piano/note.ts\":\n/*!*******************************!*\\\n  !*** ./src/gui/piano/note.ts ***!\n  \\*******************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneKeyboardNote = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst tone_1 = __webpack_require__(/*! tone */ \\\"tone\\\");\\nlet ToneKeyboardNote = class ToneKeyboardNote extends lit_element_1.LitElement {\\n    constructor() {\\n        super(...arguments);\\n        this.color = \\\"#eee\\\";\\n        this.activecolor = \\\"white\\\";\\n        this.active = false;\\n        this.touchid = -1;\\n    }\\n    _fromMidi(midi) {\\n        return tone_1.Midi(midi).toNote();\\n    }\\n    updated(changed) {\\n        if (changed.has(\\\"active\\\") && changed.get(\\\"active\\\") !== undefined) {\\n            const eventName = this.active ? \\\"noteon\\\" : \\\"noteoff\\\";\\n            if (!this.active) {\\n                this.touchid = -1;\\n            }\\n            this.dispatchEvent(new CustomEvent(eventName, {\\n                detail: {\\n                    name: this._fromMidi(this.note),\\n                    midi: this.note,\\n                    velocity: this.active ? 1 : 0,\\n                },\\n                composed: true,\\n                bubbles: true,\\n            }));\\n        }\\n    }\\n    _mouseover(e) {\\n        if (e.buttons) {\\n            this.active = true;\\n            this.shadowRoot.querySelector(\\\"button\\\").focus();\\n        }\\n    }\\n    _keydown(e) {\\n        if (!e.repeat && (e.key === \\\" \\\" || e.key === \\\"Enter\\\")) {\\n            this.active = true;\\n        }\\n    }\\n    _keyup(e) {\\n        if (e.key === \\\" \\\" || e.key === \\\"Enter\\\") {\\n            this.active = false;\\n        }\\n    }\\n    _touchstart(e) {\\n        e.preventDefault();\\n        this.touchid = e.touches[0].identifier;\\n        this.active = true;\\n    }\\n    static get styles() {\\n        return lit_element_1.css `\\n\\t\\t\\t:host {\\n\\t\\t\\t\\tdisplay: block;\\n\\t\\t\\t}\\n\\n\\t\\t\\t#container {\\n\\t\\t\\t\\twidth: 100%;\\n\\t\\t\\t\\theight: 100%;\\n\\t\\t\\t\\tdisplay: block;\\n\\t\\t\\t}\\n\\t\\t\\t#container:not([show]) {\\n\\t\\t\\t\\topacity: 0;\\n\\t\\t\\t\\tmargin: 2px;\\n\\t\\t\\t\\tpointer-events: none;\\n\\t\\t\\t}\\n\\n\\t\\t\\tbutton {\\n\\t\\t\\t\\tborder: none;\\n\\t\\t\\t\\t-webkit-appearance: none;\\n\\t\\t\\t\\t--key-margin: 2px;\\n\\t\\t\\t\\twidth: 100%;\\n\\t\\t\\t\\theight: 100%;\\n\\t\\t\\t\\tborder: 2px solid white;\\n\\t\\t\\t\\tbox-sizing: border-box;\\n\\t\\t\\t\\tpadding: 0;\\n\\t\\t\\t\\toutline: none;\\n\\t\\t\\t\\ttransition: background-color 0.2s;\\n\\t\\t\\t\\tcolor: transparent;\\n\\t\\t\\t\\tfont-size: 0px;\\n\\t\\t\\t\\tborder-radius: 2px;\\n\\t\\t\\t}\\n\\t\\t\\tbutton[active] {\\n\\t\\t\\t\\tbackground-color: #666 !important;\\n\\t\\t\\t\\ttransition-duration: 0s;\\n\\t\\t\\t}\\n\\t\\t\\tbutton:focus {\\n\\t\\t\\t\\tborder-color: #666;\\n\\t\\t\\t}\\n\\t\\t`;\\n    }\\n    render() {\\n        const show = this.note !== 0;\\n        return lit_element_1.html `\\n\\t\\t\\t<div id=\\\"container\\\" ?show=${show}>\\n\\t\\t\\t\\t${show\\n            ? lit_element_1.html ` <button\\n\\t\\t\\t\\t\\t\\t\\t?active=${this.active}\\n\\t\\t\\t\\t\\t\\t\\t@mouseover=${this._mouseover.bind(this)}\\n\\t\\t\\t\\t\\t\\t\\t@mouseleave=${() => (this.active = false)}\\n\\t\\t\\t\\t\\t\\t\\t@mousedown=${() => (this.active = true)}\\n\\t\\t\\t\\t\\t\\t\\t@touchstart=${this._touchstart.bind(this)}\\n\\t\\t\\t\\t\\t\\t\\t@touchend=${() => (this.active = false)}\\n\\t\\t\\t\\t\\t\\t\\t@mouseup=${() => (this.active = false)}\\n\\t\\t\\t\\t\\t\\t\\t@keydown=${this._keydown.bind(this)}\\n\\t\\t\\t\\t\\t\\t\\t@keyup=${this._keyup.bind(this)}\\n\\t\\t\\t\\t\\t\\t\\tstyle=\\\"background-color: ${this.active\\n                ? this.activecolor\\n                : this.color};\\\"\\n\\t\\t\\t\\t\\t  >\\n\\t\\t\\t\\t\\t\\t\\t${this._fromMidi(this.note).replace(\\\"#\\\", \\\"♯\\\")}\\n\\t\\t\\t\\t\\t  </button>`\\n            : lit_element_1.html ``}\\n\\t\\t\\t</div>\\n\\t\\t`;\\n    }\\n};\\n__decorate([\\n    lit_element_1.property({ type: Number })\\n], ToneKeyboardNote.prototype, \\\"note\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: String })\\n], ToneKeyboardNote.prototype, \\\"color\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: String })\\n], ToneKeyboardNote.prototype, \\\"activecolor\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], ToneKeyboardNote.prototype, \\\"active\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Number })\\n], ToneKeyboardNote.prototype, \\\"velocity\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Number })\\n], ToneKeyboardNote.prototype, \\\"touchid\\\", void 0);\\nToneKeyboardNote = __decorate([\\n    lit_element_1.customElement(\\\"tone-keyboard-note\\\")\\n], ToneKeyboardNote);\\nexports.ToneKeyboardNote = ToneKeyboardNote;\\n\\n\\n//# sourceURL=webpack:///./src/gui/piano/note.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/piano/octave.ts\":\n/*!*********************************!*\\\n  !*** ./src/gui/piano/octave.ts ***!\n  \\*********************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneKeyboardOctave = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nlet ToneKeyboardOctave = class ToneKeyboardOctave extends lit_element_1.LitElement {\\n    constructor() {\\n        super(...arguments);\\n        this.octave = 1;\\n    }\\n    noteon(number) {\\n        const note = this.shadowRoot.querySelector(`tone-keyboard-note[note=\\\"${number}\\\"]`);\\n        note.active = true;\\n    }\\n    noteoff(number) {\\n        const note = this.shadowRoot.querySelector(`tone-keyboard-note[note=\\\"${number}\\\"]`);\\n        note.active = false;\\n    }\\n    getNoteByTouchId(id) {\\n        const notes = Array.from(this.shadowRoot.querySelectorAll(\\\"tone-keyboard-note\\\"));\\n        const element = notes.find((e) => e.touchid === id);\\n        if (element && element.note) {\\n            return element;\\n        }\\n    }\\n    static get styles() {\\n        return lit_element_1.css `\\n\\t\\t\\t#container {\\n\\t\\t\\t\\tdisplay: block;\\n\\t\\t\\t\\tposition: relative;\\n\\t\\t\\t\\theight: 100%;\\n\\t\\t\\t\\twidth: 100%;\\n\\t\\t\\t}\\n\\t\\t\\ttone-keyboard-note {\\n\\t\\t\\t\\torder: 0;\\n\\t\\t\\t\\tflex-grow: 1;\\n\\t\\t\\t}\\n\\n\\t\\t\\t#white-notes {\\n\\t\\t\\t\\tposition: absolute;\\n\\t\\t\\t\\tleft: 0px;\\n\\t\\t\\t\\ttop: 0px;\\n\\t\\t\\t\\twidth: 100%;\\n\\t\\t\\t\\theight: 100%;\\n\\t\\t\\t\\tdisplay: flex;\\n\\t\\t\\t\\tflex-direction: row;\\n\\t\\t\\t}\\n\\n\\t\\t\\t#black-notes {\\n\\t\\t\\t\\tposition: absolute;\\n\\t\\t\\t\\ttop: 0px;\\n\\t\\t\\t\\twidth: 100%;\\n\\t\\t\\t\\tdisplay: flex;\\n\\t\\t\\t\\tflex-direction: row;\\n\\t\\t\\t\\theight: 55%;\\n\\t\\t\\t}\\n\\n\\t\\t\\t#black-notes tone-keyboard-note:first-child,\\n\\t\\t\\t#black-notes tone-keyboard-note:last-child {\\n\\t\\t\\t\\tflex-grow: 0.5;\\n\\t\\t\\t\\tpointer-events: none;\\n\\t\\t\\t}\\n\\t\\t`;\\n    }\\n    render() {\\n        const startNote = 12 * this.octave;\\n        const whiteNotes = [0, 2, 4, 5, 7, 9, 11].map((i) => i + startNote);\\n        const blackNotes = [0, 1, 3, 0, 6, 8, 10, 0].map((i) => {\\n            if (i) {\\n                return i + startNote;\\n            }\\n            else {\\n                return 0;\\n            }\\n        });\\n        return lit_element_1.html `\\n\\t\\t\\t<div id=\\\"container\\\">\\n\\t\\t\\t\\t<div id=\\\"white-notes\\\">\\n\\t\\t\\t\\t\\t${whiteNotes.map((note) => lit_element_1.html `\\n\\t\\t\\t\\t\\t\\t\\t<tone-keyboard-note\\n\\t\\t\\t\\t\\t\\t\\t\\tcolor=\\\"#aaa\\\"\\n\\t\\t\\t\\t\\t\\t\\t\\tnote=\\\"${note.toString()}\\\"\\n\\t\\t\\t\\t\\t\\t\\t></tone-keyboard-note>\\n\\t\\t\\t\\t\\t\\t`)}\\n\\t\\t\\t\\t</div>\\n\\t\\t\\t\\t<div id=\\\"black-notes\\\">\\n\\t\\t\\t\\t\\t${blackNotes.map((note) => lit_element_1.html `\\n\\t\\t\\t\\t\\t\\t\\t<tone-keyboard-note\\n\\t\\t\\t\\t\\t\\t\\t\\tcolor=\\\"black\\\"\\n\\t\\t\\t\\t\\t\\t\\t\\tnote=\\\"${note.toString()}\\\"\\n\\t\\t\\t\\t\\t\\t\\t></tone-keyboard-note>\\n\\t\\t\\t\\t\\t\\t`)}\\n\\t\\t\\t\\t</div>\\n\\t\\t\\t</div>\\n\\t\\t`;\\n    }\\n};\\n__decorate([\\n    lit_element_1.property({ type: Number })\\n], ToneKeyboardOctave.prototype, \\\"octave\\\", void 0);\\nToneKeyboardOctave = __decorate([\\n    lit_element_1.customElement(\\\"tone-keyboard-octave\\\")\\n], ToneKeyboardOctave);\\nexports.ToneKeyboardOctave = ToneKeyboardOctave;\\n\\n\\n//# sourceURL=webpack:///./src/gui/piano/octave.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/piano/piano.ts\":\n/*!********************************!*\\\n  !*** ./src/gui/piano/piano.ts ***!\n  \\********************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.createPiano = exports.TonePiano = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\n__webpack_require__(/*! ./keyboard */ \\\"./src/gui/piano/keyboard.ts\\\");\\n__webpack_require__(/*! ./midi-in */ \\\"./src/gui/piano/midi-in.ts\\\");\\nlet TonePiano = class TonePiano extends lit_element_1.LitElement {\\n    constructor() {\\n        super(...arguments);\\n        this.polyphonic = false;\\n    }\\n    firstUpdated(props) {\\n        super.firstUpdated(props);\\n        const keyboard = this.shadowRoot.querySelector(\\\"tone-keyboard\\\");\\n        // this.shadowRoot.querySelector(\\\"tone-midi-in\\\").addEventListener(\\\"noteon\\\", e => {\\n        // \\te.stopPropagation();\\n        // \\tkeyboard.noteon(e.detail.midi);\\n        // });\\n        // this.shadowRoot.querySelector(\\\"tone-midi-in\\\").addEventListener(\\\"noteoff\\\", e => {\\n        // \\te.stopPropagation();\\n        // \\tkeyboard.noteoff(e.detail.midi);\\n        // });\\n        window.addEventListener(\\\"resize\\\", this._resize.bind(this));\\n        setTimeout(() => this._resize(), 100);\\n    }\\n    _clamp(v, floor, ceil) {\\n        return Math.max(Math.min(v, ceil), floor);\\n    }\\n    _scale(v, inMin, inMax, outMin, outMax) {\\n        return ((v - inMin) / (inMax - inMin)) * (outMax - outMin) + outMin;\\n    }\\n    _resize() {\\n        const width = this.shadowRoot.querySelector(\\\"#container\\\").clientWidth;\\n        const octaves = this._clamp(Math.floor(width / 100) - 1, 1, 8);\\n        const rootNote = Math.ceil(this._scale(octaves, 1, 8, 5, 1));\\n        this.shadowRoot.querySelector(\\\"tone-keyboard\\\").rootoctave = rootNote;\\n        this.shadowRoot.querySelector(\\\"tone-keyboard\\\").octaves = octaves;\\n    }\\n    render() {\\n        return lit_element_1.html `\\n\\t\\t\\t<style>\\n\\t\\t\\t\\t:host {\\n\\t\\t\\t\\t\\tdisplay: block;\\n\\t\\t\\t\\t}\\n\\n\\t\\t\\t\\t#container {\\n\\t\\t\\t\\t\\tbackground-color: var(--color-light-gray);\\n\\t\\t\\t\\t\\tposition: relative;\\n\\t\\t\\t\\t\\tpadding: 5px;\\n\\t\\t\\t\\t\\tdisplay: block;\\n\\t\\t\\t\\t}\\n\\n\\t\\t\\t\\ttone-keyboard {\\n\\t\\t\\t\\t\\tdisplay: block;\\n\\t\\t\\t\\t\\tclear: both;\\n\\t\\t\\t\\t}\\n\\n\\t\\t\\t\\ttone-midi-in {\\n\\t\\t\\t\\t\\tposition: relative;\\n\\t\\t\\t\\t\\ttop: 5px;\\n\\t\\t\\t\\t\\tright: 5px;\\n\\t\\t\\t\\t\\tdisplay: inline-block;\\n\\t\\t\\t\\t\\tfloat: right;\\n\\t\\t\\t\\t}\\n\\t\\t\\t</style>\\n\\t\\t\\t<div id=\\\"container\\\">\\n\\t\\t\\t\\t<tone-midi-in> </tone-midi-in>\\n\\t\\t\\t\\t<tone-keyboard ?polyphonic=${this.polyphonic}></tone-keyboard>\\n\\t\\t\\t</div>\\n\\t\\t`;\\n    }\\n};\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], TonePiano.prototype, \\\"polyphonic\\\", void 0);\\nTonePiano = __decorate([\\n    lit_element_1.customElement(\\\"tone-piano\\\")\\n], TonePiano);\\nexports.TonePiano = TonePiano;\\n/**\\n * Create an audio node element\\n */\\nfunction createPiano({ parent, polyphonic = true, noteon = () => { }, noteoff = () => { }, }) {\\n    const element = document.createElement(\\\"tone-piano\\\");\\n    element.polyphonic = polyphonic;\\n    element.addEventListener(\\\"noteon\\\", (e) => noteon(e.detail));\\n    element.addEventListener(\\\"noteoff\\\", (e) => noteoff(e.detail));\\n    if (parent) {\\n        parent.appendChild(element);\\n    }\\n    return element;\\n}\\nexports.createPiano = createPiano;\\n\\n\\n//# sourceURL=webpack:///./src/gui/piano/piano.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/value/array.ts\":\n/*!********************************!*\\\n  !*** ./src/gui/value/array.ts ***!\n  \\********************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneArrayValue = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst value_1 = __webpack_require__(/*! ./value */ \\\"./src/gui/value/value.ts\\\");\\nconst style_map_1 = __webpack_require__(/*! lit-html/directives/style-map */ \\\"./node_modules/lit-html/directives/style-map.js\\\");\\nlet ToneArrayValue = class ToneArrayValue extends value_1.ToneValue {\\n    constructor() {\\n        super(...arguments);\\n        this.value = [];\\n    }\\n    reset() {\\n        // do nothing\\n    }\\n    scale(v, inMin, inMax, outMin, outMax) {\\n        const normV = Math.pow((v - inMin) / (inMax - inMin), 0.25);\\n        return normV * (outMax - outMin) + outMin;\\n    }\\n    _mousemove(index, e) {\\n        if (e.buttons) {\\n            let normValue = e.offsetY / e.target.clientHeight;\\n            normValue = Math.min(Math.max(normValue, 0), 1);\\n            this.value[index] = Math.pow(1 - normValue, 1 / 0.25);\\n            this.dispatchValue(this.value);\\n            this.requestUpdate();\\n        }\\n    }\\n    render() {\\n        const values = this.value.map(Math.abs);\\n        const min = Math.min(...values, 0);\\n        const max = Math.max(...values, 1);\\n        return lit_element_1.html `\\n\\t\\t\\t<div id=\\\"container\\\" class=\\\"array\\\">\\n\\t\\t\\t\\t<label ?disabled=${values.length === 0}>${this.name}</label>\\n\\t\\t\\t\\t<span id=\\\"bars\\\">\\n\\t\\t\\t\\t\\t${values.map((v, i) => lit_element_1.html `\\n\\t\\t\\t\\t\\t\\t\\t<span\\n\\t\\t\\t\\t\\t\\t\\t\\tclass=\\\"bar\\\"\\n\\t\\t\\t\\t\\t\\t\\t\\t@mousedown=${(e) => this._mousemove(i, e)}\\n\\t\\t\\t\\t\\t\\t\\t\\t@mousemove=${(e) => this._mousemove(i, e)}\\n\\t\\t\\t\\t\\t\\t\\t>\\n\\t\\t\\t\\t\\t\\t\\t\\t<span\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tstyle=${style_map_1.styleMap({\\n            height: `${this.scale(v, min, max, 0, 100)}%`,\\n        })}\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tclass=\\\"fill\\\"\\n\\t\\t\\t\\t\\t\\t\\t\\t></span>\\n\\t\\t\\t\\t\\t\\t\\t</span>\\n\\t\\t\\t\\t\\t\\t`)}\\n\\t\\t\\t\\t</span>\\n\\t\\t\\t</div>\\n\\t\\t`;\\n    }\\n};\\n__decorate([\\n    lit_element_1.property({ type: String })\\n], ToneArrayValue.prototype, \\\"name\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Array })\\n], ToneArrayValue.prototype, \\\"value\\\", void 0);\\nToneArrayValue = __decorate([\\n    lit_element_1.customElement(\\\"tone-array\\\")\\n], ToneArrayValue);\\nexports.ToneArrayValue = ToneArrayValue;\\n\\n\\n//# sourceURL=webpack:///./src/gui/value/array.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/value/boolean.ts\":\n/*!**********************************!*\\\n  !*** ./src/gui/value/boolean.ts ***!\n  \\**********************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneBooleanValue = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst value_1 = __webpack_require__(/*! ./value */ \\\"./src/gui/value/value.ts\\\");\\nlet ToneBooleanValue = class ToneBooleanValue extends value_1.ToneValue {\\n    constructor() {\\n        super(...arguments);\\n        this.value = false;\\n    }\\n    _oninput(e) {\\n        e.stopPropagation();\\n        this.value = this.inputEl.checked;\\n        this.dispatchValue(this.value);\\n    }\\n    reset() {\\n        this.inputEl.checked = this.value;\\n    }\\n    render() {\\n        return lit_element_1.html `\\n\\t\\t\\t<div id=\\\"container\\\" class=\\\"boolean\\\">\\n\\t\\t\\t\\t<label for=\\\"check\\\">${this.name}</label>\\n\\t\\t\\t\\t<input\\n\\t\\t\\t\\t\\t@input=${this._oninput.bind(this)}\\n\\t\\t\\t\\t\\tname=\\\"check\\\"\\n\\t\\t\\t\\t\\ttype=\\\"checkbox\\\"\\n\\t\\t\\t\\t\\t?checked=${this.value}\\n\\t\\t\\t\\t/>\\n\\t\\t\\t</div>\\n\\t\\t`;\\n    }\\n};\\n__decorate([\\n    lit_element_1.query(\\\"input\\\")\\n], ToneBooleanValue.prototype, \\\"inputEl\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: String })\\n], ToneBooleanValue.prototype, \\\"name\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Boolean })\\n], ToneBooleanValue.prototype, \\\"value\\\", void 0);\\nToneBooleanValue = __decorate([\\n    lit_element_1.customElement(\\\"tone-boolean\\\")\\n], ToneBooleanValue);\\nexports.ToneBooleanValue = ToneBooleanValue;\\n\\n\\n//# sourceURL=webpack:///./src/gui/value/boolean.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/value/number.ts\":\n/*!*********************************!*\\\n  !*** ./src/gui/value/number.ts ***!\n  \\*********************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneNumberValue = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst value_1 = __webpack_require__(/*! ./value */ \\\"./src/gui/value/value.ts\\\");\\nlet ToneNumberValue = class ToneNumberValue extends value_1.ToneValue {\\n    constructor() {\\n        super(...arguments);\\n        this.value = 0;\\n        this.alt = false;\\n        this.shift = false;\\n        this.dragging = false;\\n    }\\n    firstUpdated(changed) {\\n        super.firstUpdated(changed);\\n        window.addEventListener(\\\"mousemove\\\", (e) => {\\n            if (this.dragging) {\\n                e.preventDefault();\\n                // find the relative change\\n                const box = this.shadowRoot.host.getBoundingClientRect();\\n                const yDiff = box.top + (box.bottom - box.top) / 2 - e.clientY;\\n                const multiplier = this.shift\\n                    ? this.alt\\n                        ? 0.01\\n                        : 10\\n                    : this.alt\\n                        ? 0.1\\n                        : 1;\\n                this.value =\\n                    this.dragstartValue + Math.floor(yDiff / 10) * multiplier;\\n                this.dispatchValue(this.value);\\n            }\\n        });\\n        window.addEventListener(\\\"keydown\\\", (e) => {\\n            if (e.keyCode === 18) {\\n                this.alt = true;\\n            }\\n            this.shift = e.shiftKey;\\n        });\\n        window.addEventListener(\\\"keyup\\\", (e) => {\\n            if (e.keyCode === 18) {\\n                this.alt = false;\\n            }\\n            this.shift = e.shiftKey;\\n        });\\n    }\\n    _oninput(e) {\\n        e.preventDefault();\\n        e.stopPropagation();\\n        const value = parseFloat(this.shadowRoot.querySelector(\\\"input\\\").value);\\n        if (isFinite(value)) {\\n            this.value = value;\\n            this.dispatchValue(value);\\n        }\\n    }\\n    _onkeypress(e) {\\n        let modified = false;\\n        if (e.key === \\\"ArrowUp\\\") {\\n            modified = true;\\n            if (this.shift) {\\n                this.value += this.alt ? 0.01 : 10;\\n            }\\n            else {\\n                this.value += this.alt ? 0.1 : 1;\\n            }\\n        }\\n        else if (e.key === \\\"ArrowDown\\\") {\\n            modified = true;\\n            if (this.shift) {\\n                this.value -= this.alt ? 0.01 : 10;\\n            }\\n            else {\\n                this.value -= this.alt ? 0.1 : 1;\\n            }\\n        }\\n        if (modified) {\\n            e.preventDefault();\\n            this.dispatchValue(this.value);\\n        }\\n    }\\n    reset() {\\n        this.shadowRoot.querySelector(\\\"input\\\").value = this.beautifyValue(this.value).toString();\\n    }\\n    _dragstart(e) {\\n        this.dragging = true;\\n        this.dragstartValue = this.value;\\n        window.addEventListener(\\\"mouseup\\\", () => {\\n            if (this.dragstartValue !== this.value) {\\n                this.dispatchValue(this.value);\\n            }\\n            this.dragging = false;\\n        }, { once: true });\\n    }\\n    beautifyValue(val) {\\n        const float = val.toString().split(\\\".\\\")[1];\\n        return parseFloat(val.toFixed(Math.min(float && float.length, 4)));\\n    }\\n    render() {\\n        return lit_element_1.html `\\n\\t\\t\\t<div id=\\\"container\\\">\\n\\t\\t\\t\\t<label for=\\\"number\\\">${this.name}</label>\\n\\t\\t\\t\\t<input\\n\\t\\t\\t\\t\\t@mousedown=${this._dragstart.bind(this)}\\n\\t\\t\\t\\t\\t@keydown=${this._onkeypress.bind(this)}\\n\\t\\t\\t\\t\\t@change=${this._oninput.bind(this)}\\n\\t\\t\\t\\t\\tname=\\\"number\\\"\\n\\t\\t\\t\\t\\ttype=\\\"text\\\"\\n\\t\\t\\t\\t\\t.value=\\\"${this.beautifyValue(this.value)}\\\"\\n\\t\\t\\t\\t/>\\n\\t\\t\\t</div>\\n\\t\\t`;\\n    }\\n};\\n__decorate([\\n    lit_element_1.property({ type: String })\\n], ToneNumberValue.prototype, \\\"name\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Number })\\n], ToneNumberValue.prototype, \\\"value\\\", void 0);\\nToneNumberValue = __decorate([\\n    lit_element_1.customElement(\\\"tone-number\\\")\\n], ToneNumberValue);\\nexports.ToneNumberValue = ToneNumberValue;\\n\\n\\n//# sourceURL=webpack:///./src/gui/value/number.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/value/string.ts\":\n/*!*********************************!*\\\n  !*** ./src/gui/value/string.ts ***!\n  \\*********************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneStringValue = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst value_1 = __webpack_require__(/*! ./value */ \\\"./src/gui/value/value.ts\\\");\\nlet ToneStringValue = class ToneStringValue extends value_1.ToneValue {\\n    constructor() {\\n        super(...arguments);\\n        this.value = \\\"\\\";\\n    }\\n    _oninput(e) {\\n        e.stopPropagation();\\n        e.stopImmediatePropagation();\\n        this.value = this.inputEl.value;\\n        this.dispatchValue(this.value);\\n    }\\n    reset() {\\n        this.inputEl.value = this.value;\\n    }\\n    render() {\\n        return lit_element_1.html `\\n\\t\\t\\t<div id=\\\"container\\\">\\n\\t\\t\\t\\t<label for=\\\"string\\\">${this.name}</label>\\n\\t\\t\\t\\t<input\\n\\t\\t\\t\\t\\t@input=${(e) => e.stopPropagation()}\\n\\t\\t\\t\\t\\t@change=${this._oninput.bind(this)}\\n\\t\\t\\t\\t\\tname=\\\"string\\\"\\n\\t\\t\\t\\t\\ttype=\\\"text\\\"\\n\\t\\t\\t\\t\\t.value=${this.value}\\n\\t\\t\\t\\t/>\\n\\t\\t\\t</div>\\n\\t\\t`;\\n    }\\n};\\n__decorate([\\n    lit_element_1.property({ type: String })\\n], ToneStringValue.prototype, \\\"name\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: String })\\n], ToneStringValue.prototype, \\\"value\\\", void 0);\\n__decorate([\\n    lit_element_1.query(\\\"input\\\")\\n], ToneStringValue.prototype, \\\"inputEl\\\", void 0);\\nToneStringValue = __decorate([\\n    lit_element_1.customElement(\\\"tone-string\\\")\\n], ToneStringValue);\\nexports.ToneStringValue = ToneStringValue;\\n\\n\\n//# sourceURL=webpack:///./src/gui/value/string.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/value/value.scss\":\n/*!**********************************!*\\\n  !*** ./src/gui/value/value.scss ***!\n  \\**********************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\neval(\"\\n        var result = __webpack_require__(/*! !../../../node_modules/css-loader/dist/cjs.js!../../../node_modules/sass-loader/dist/cjs.js??ref--5-2!./value.scss */ \\\"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js?!./src/gui/value/value.scss\\\");\\n\\n        if (typeof result === \\\"string\\\") {\\n            module.exports = result;\\n        } else {\\n            module.exports = result.toString();\\n        }\\n    \\n\\n//# sourceURL=webpack:///./src/gui/value/value.scss?\");\n\n/***/ }),\n\n/***/ \"./src/gui/value/value.ts\":\n/*!********************************!*\\\n  !*** ./src/gui/value/value.ts ***!\n  \\********************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneValue = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\n// eslint-disable-next-line @typescript-eslint/no-var-requires\\nconst style = __webpack_require__(/*! ./value.scss */ \\\"./src/gui/value/value.scss\\\");\\n/**\\n * Base class for values\\n */\\nclass ToneValue extends lit_element_1.LitElement {\\n    /**\\n     * Beautify the value before it's set\\n     */\\n    beautifyValue(val) {\\n        return val;\\n    }\\n    /**\\n     * Trigger a \\\"value\\\" event. Value events have a rejected callback\\n     * in case the value is not valid\\n     */\\n    dispatchValue(value) {\\n        this.dispatchEvent(new CustomEvent(\\\"value\\\", {\\n            detail: {\\n                value,\\n                reject: (val) => {\\n                    this.value = val;\\n                    // flash red quickly?\\n                    this.shadowRoot\\n                        .querySelector(\\\"#container\\\")\\n                        .classList.add(\\\"error\\\");\\n                    setTimeout(() => {\\n                        this.shadowRoot\\n                            .querySelector(\\\"#container\\\")\\n                            .classList.remove(\\\"error\\\");\\n                    }, 100);\\n                    this.reset();\\n                },\\n            },\\n        }));\\n    }\\n    static get styles() {\\n        return lit_element_1.css `\\n\\t\\t\\t${lit_element_1.unsafeCSS(style)}\\n\\t\\t`;\\n    }\\n    render() {\\n        return lit_element_1.html ` ${this.name} `;\\n    }\\n}\\n__decorate([\\n    lit_element_1.property({ type: String })\\n], ToneValue.prototype, \\\"name\\\", void 0);\\nexports.ToneValue = ToneValue;\\n\\n\\n//# sourceURL=webpack:///./src/gui/value/value.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/vis/buffer.ts\":\n/*!*******************************!*\\\n  !*** ./src/gui/vis/buffer.ts ***!\n  \\*******************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\\n    return new (P || (P = Promise))(function (resolve, reject) {\\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\\n        function rejected(value) { try { step(generator[\\\"throw\\\"](value)); } catch (e) { reject(e); } }\\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\\n    });\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneBufferViz = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst vis_base_1 = __webpack_require__(/*! ./vis-base */ \\\"./src/gui/vis/vis-base.ts\\\");\\nlet ToneBufferViz = class ToneBufferViz extends vis_base_1.VisBase {\\n    generate() {\\n        return __awaiter(this, void 0, void 0, function* () {\\n            if (!this.tone) {\\n                return;\\n            }\\n            if (!this.tone.buffer.loaded) {\\n                yield new Promise((done) => (this.tone.buffer.onload = done));\\n            }\\n            const values = this.tone.buffer.getChannelData(0);\\n            this.draw(values);\\n        });\\n    }\\n    bind(tone) {\\n        this.tone = tone;\\n        this.generate();\\n    }\\n};\\nToneBufferViz = __decorate([\\n    lit_element_1.customElement(\\\"tone-buffer-vis\\\")\\n], ToneBufferViz);\\nexports.ToneBufferViz = ToneBufferViz;\\n\\n\\n//# sourceURL=webpack:///./src/gui/vis/buffer.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/vis/compressor.ts\":\n/*!***********************************!*\\\n  !*** ./src/gui/vis/compressor.ts ***!\n  \\***********************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\\n    return new (P || (P = Promise))(function (resolve, reject) {\\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\\n        function rejected(value) { try { step(generator[\\\"throw\\\"](value)); } catch (e) { reject(e); } }\\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\\n    });\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneCompressorVis = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst vis_base_1 = __webpack_require__(/*! ./vis-base */ \\\"./src/gui/vis/vis-base.ts\\\");\\nlet ToneCompressorVis = class ToneCompressorVis extends vis_base_1.VisBase {\\n    constructor() {\\n        super(...arguments);\\n        this.normalizeCurve = false;\\n    }\\n    generate() {\\n        return __awaiter(this, void 0, void 0, function* () {\\n            if (!this.tone) {\\n                return;\\n            }\\n            const length = this.width;\\n            const kneeWidth = this.scale(this.tone.knee.value, 0, 100, 0, length);\\n            const threshIndex = this.scale(this.tone.threshold.value, -100, 40, 0, length);\\n            const retArray = new Float32Array(length);\\n            const ratio = this.tone.ratio.value;\\n            const kneeBegin = threshIndex - kneeWidth / 2;\\n            const kneeEnd = threshIndex + kneeWidth / 2;\\n            const kneeBeginNorm = this.scale(kneeBegin, 0, length, 0, 1);\\n            const threshNorm = this.scale(threshIndex, 0, length, 0, 1);\\n            const values = retArray.map((_, i) => {\\n                const linearVal = this.scale(i, 0, length, 0, 1);\\n                // apply the ratio\\n                if (i < kneeBegin) {\\n                    // linear\\n                    return linearVal;\\n                }\\n                else if (kneeBegin <= i && i <= kneeEnd) {\\n                    // in the knee\\n                    const over = this.scale(kneeEnd - threshIndex, 0, length, 0, 1);\\n                    const compressedValue = threshNorm + over * (1 / ratio);\\n                    return this.scale(i, kneeBegin, kneeEnd, kneeBeginNorm, compressedValue);\\n                }\\n                else {\\n                    // compressing\\n                    const over = this.scale(i - threshIndex, 0, length, 0, 1);\\n                    const compressedValue = threshNorm + over * (1 / ratio);\\n                    return compressedValue;\\n                }\\n            });\\n            this.draw(values);\\n        });\\n    }\\n    draw(values) {\\n        // draw the values\\n        super.draw(values);\\n        const canvas = this.shadowRoot.querySelector(\\\"canvas\\\");\\n        const context = canvas.getContext(\\\"2d\\\");\\n        context.setLineDash([2, 2]);\\n        context.lineWidth = 1;\\n        context.strokeStyle = \\\"rgba(0, 0, 0, 0.25)\\\";\\n        // draw the thresh and knee lines\\n        const threshX = this.scale(this.tone.threshold.value, -100, 40, 0, canvas.width);\\n        const threshY = this.scale(this.tone.threshold.value, -100, 40, canvas.height, 0);\\n        context.moveTo(threshX, 0);\\n        context.lineTo(threshX, canvas.height);\\n        context.stroke();\\n        context.moveTo(0, threshY);\\n        context.lineTo(canvas.width, threshY);\\n        context.stroke();\\n        context.setLineDash([]);\\n    }\\n    bind(tone) {\\n        this.tone = tone;\\n        this.generate();\\n        this.loop();\\n    }\\n    loop() {\\n        requestAnimationFrame(this.loop.bind(this));\\n        // check the reduction\\n        const reduction = this.scale(this.tone.reduction, 0, -100, 0, 100);\\n        this.shadowRoot.querySelector(\\\"#reduction #fill\\\").style.height = `${reduction.toFixed(1)}%`;\\n    }\\n    render() {\\n        return lit_element_1.html `\\n\\t\\t\\t<style>\\n\\t\\t\\t\\t#container {\\n\\t\\t\\t\\t\\tmargin-top: 5px;\\n\\t\\t\\t\\t\\tposition: relative;\\n\\t\\t\\t\\t}\\n\\n\\t\\t\\t\\tcanvas {\\n\\t\\t\\t\\t\\twidth: calc(100% - 50px);\\n\\t\\t\\t\\t\\theight: ${this.height}px;\\n\\t\\t\\t\\t}\\n\\n\\t\\t\\t\\t#reduction {\\n\\t\\t\\t\\t\\tposition: absolute;\\n\\t\\t\\t\\t\\twidth: 20px;\\n\\t\\t\\t\\t\\theight: ${this.height}px;\\n\\t\\t\\t\\t\\tright: 0px;\\n\\t\\t\\t\\t\\ttop: 0px;\\n\\t\\t\\t\\t}\\n\\n\\t\\t\\t\\t#reduction #fill {\\n\\t\\t\\t\\t\\tbackground-color: black;\\n\\t\\t\\t\\t\\twidth: 100%;\\n\\t\\t\\t\\t\\theight: 0%;\\n\\t\\t\\t\\t\\ttop: 0px;\\n\\t\\t\\t\\t\\tleft: 0px;\\n\\t\\t\\t\\t}\\n\\t\\t\\t</style>\\n\\t\\t\\t<div id=\\\"container\\\">\\n\\t\\t\\t\\t<canvas></canvas>\\n\\t\\t\\t\\t<div id=\\\"reduction\\\">\\n\\t\\t\\t\\t\\t<div id=\\\"fill\\\"></div>\\n\\t\\t\\t\\t</div>\\n\\t\\t\\t</div>\\n\\t\\t`;\\n    }\\n};\\nToneCompressorVis = __decorate([\\n    lit_element_1.customElement(\\\"tone-compressor-vis\\\")\\n], ToneCompressorVis);\\nexports.ToneCompressorVis = ToneCompressorVis;\\n\\n\\n//# sourceURL=webpack:///./src/gui/vis/compressor.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/vis/envelope.ts\":\n/*!*********************************!*\\\n  !*** ./src/gui/vis/envelope.ts ***!\n  \\*********************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\\n    return new (P || (P = Promise))(function (resolve, reject) {\\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\\n        function rejected(value) { try { step(generator[\\\"throw\\\"](value)); } catch (e) { reject(e); } }\\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\\n    });\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneEnvelopeVis = void 0;\\nconst vis_base_1 = __webpack_require__(/*! ./vis-base */ \\\"./src/gui/vis/vis-base.ts\\\");\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst style_map_1 = __webpack_require__(/*! lit-html/directives/style-map */ \\\"./node_modules/lit-html/directives/style-map.js\\\");\\nlet ToneEnvelopeVis = class ToneEnvelopeVis extends vis_base_1.VisBase {\\n    generate() {\\n        return __awaiter(this, void 0, void 0, function* () {\\n            if (!this.tone) {\\n                return;\\n            }\\n            const values = yield this.tone.asArray(this.width);\\n            this.draw(values);\\n            this.requestUpdate();\\n        });\\n    }\\n    bind(tone) {\\n        this.tone = tone;\\n        this.generate();\\n    }\\n    render() {\\n        const times = [];\\n        if (this.tone) {\\n            const tickCount = 4;\\n            // add the timing to the bottom\\n            const totalDuration = 1.1 *\\n                (this.tone.toSeconds(this.tone.attack) +\\n                    this.tone.toSeconds(this.tone.decay) +\\n                    this.tone.toSeconds(this.tone.release));\\n            // scoot the canvas up 10px\\n            // context.drawImage(canvas, 0, 0, this.width, this.height - 10);\\n            const subdivision = Math.pow(2, Math.ceil(Math.log2(totalDuration / tickCount)));\\n            const rounding = (subdivision.toString().split(\\\".\\\")[1] &&\\n                subdivision.toString().split(\\\".\\\")[1].length) ||\\n                0;\\n            for (let time = 0; time < totalDuration * 0.9; time += subdivision) {\\n                const x = time / totalDuration;\\n                times.push({\\n                    x,\\n                    time: time.toFixed(rounding),\\n                });\\n            }\\n        }\\n        return lit_element_1.html `\\n\\t\\t\\t<style>\\n\\t\\t\\t\\t#timeline {\\n\\t\\t\\t\\t\\tmargin-top: -10px;\\n\\t\\t\\t\\t\\tfont-size: 10px;\\n\\t\\t\\t\\t\\tfont-family: monospace;\\n\\t\\t\\t\\t\\tposition: relative;\\n\\t\\t\\t\\t\\theight: 20px;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\t#timeline span {\\n\\t\\t\\t\\t\\tposition: absolute;\\n\\t\\t\\t\\t}\\n\\t\\t\\t</style>\\n\\t\\t\\t${super.render()}\\n\\t\\t\\t<div id=\\\"timeline\\\">\\n\\t\\t\\t\\t${times.map(({ x, time }) => lit_element_1.html `\\n\\t\\t\\t\\t\\t\\t<span\\n\\t\\t\\t\\t\\t\\t\\tstyle=${style_map_1.styleMap({\\n            left: `${(x * 100).toFixed(2)}%`,\\n        })}\\n\\t\\t\\t\\t\\t\\t>\\n\\t\\t\\t\\t\\t\\t\\t${time}s\\n\\t\\t\\t\\t\\t\\t</span>\\n\\t\\t\\t\\t\\t`)}\\n\\t\\t\\t</div>\\n\\t\\t`;\\n    }\\n};\\nToneEnvelopeVis = __decorate([\\n    lit_element_1.customElement(\\\"tone-envelope-vis\\\")\\n], ToneEnvelopeVis);\\nexports.ToneEnvelopeVis = ToneEnvelopeVis;\\n\\n\\n//# sourceURL=webpack:///./src/gui/vis/envelope.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/vis/fft.ts\":\n/*!****************************!*\\\n  !*** ./src/gui/vis/fft.ts ***!\n  \\****************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.createFFT = void 0;\\nconst vis_base_1 = __webpack_require__(/*! ./vis-base */ \\\"./src/gui/vis/vis-base.ts\\\");\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nlet ToneFFTElement = class ToneFFTElement extends vis_base_1.VisBase {\\n    constructor() {\\n        super(...arguments);\\n        this.height = 40;\\n    }\\n    generate() {\\n        // ignored\\n    }\\n    loop() {\\n        requestAnimationFrame(this.loop.bind(this));\\n        if (!this.tone) {\\n            return;\\n        }\\n        const values = this.tone.getValue();\\n        this.draw(values);\\n    }\\n    bind(tone) {\\n        this.tone = tone;\\n        this.loop();\\n    }\\n};\\nToneFFTElement = __decorate([\\n    lit_element_1.customElement(\\\"tone-fft-vis\\\")\\n], ToneFFTElement);\\n/**\\n * Create an audio node element\\n */\\nfunction createFFT({ tone, parent, height, }) {\\n    const element = document.createElement(\\\"tone-fft-vis\\\");\\n    element.bind(tone);\\n    if (parent) {\\n        parent.appendChild(element);\\n    }\\n    if (height) {\\n        element.setAttribute(\\\"height\\\", height.toString());\\n    }\\n    return element;\\n}\\nexports.createFFT = createFFT;\\n\\n\\n//# sourceURL=webpack:///./src/gui/vis/fft.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/vis/filter.ts\":\n/*!*******************************!*\\\n  !*** ./src/gui/vis/filter.ts ***!\n  \\*******************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneFFTVis = void 0;\\nconst vis_base_1 = __webpack_require__(/*! ./vis-base */ \\\"./src/gui/vis/vis-base.ts\\\");\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nlet ToneFFTVis = class ToneFFTVis extends vis_base_1.VisBase {\\n    generate() {\\n        if (!this.tone) {\\n            return;\\n        }\\n        const values = this.tone.getFrequencyResponse(this.width);\\n        this.draw(values);\\n    }\\n    bind(tone) {\\n        this.tone = tone;\\n        this.generate();\\n    }\\n};\\nToneFFTVis = __decorate([\\n    lit_element_1.customElement(\\\"tone-filter-vis\\\")\\n], ToneFFTVis);\\nexports.ToneFFTVis = ToneFFTVis;\\n\\n\\n//# sourceURL=webpack:///./src/gui/vis/filter.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/vis/meter.ts\":\n/*!******************************!*\\\n  !*** ./src/gui/vis/meter.ts ***!\n  \\******************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.createMeter = exports.ToneMeterElement = void 0;\\nconst vis_base_1 = __webpack_require__(/*! ./vis-base */ \\\"./src/gui/vis/vis-base.ts\\\");\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst Color = __webpack_require__(/*! color */ \\\"./node_modules/color/index.js\\\");\\nconst style_map_1 = __webpack_require__(/*! lit-html/directives/style-map */ \\\"./node_modules/lit-html/directives/style-map.js\\\");\\nlet ToneMeterElement = class ToneMeterElement extends vis_base_1.VisBase {\\n    constructor() {\\n        super(...arguments);\\n        this.height = 40;\\n        this.meterLevels = [];\\n    }\\n    generate() {\\n        // ignored\\n    }\\n    loop() {\\n        requestAnimationFrame(this.loop.bind(this));\\n        if (!this.tone) {\\n            return;\\n        }\\n        const values = this.tone.getValue();\\n        this.meterLevels = Array.isArray(values) ? values : [values];\\n        this.requestUpdate();\\n    }\\n    bind(tone) {\\n        this.tone = tone;\\n        this.tone.normalRange = true;\\n        this.loop();\\n    }\\n    renderColor(val) {\\n        return Color(\\\"#aaa\\\")\\n            .mix(Color(\\\"rgb(209, 196, 15)\\\"), Math.pow(val, 0.5))\\n            .hex();\\n    }\\n    render() {\\n        return lit_element_1.html `\\n\\t\\t\\t<style>\\n\\t\\t\\t\\t#container {\\n\\t\\t\\t\\t\\tdisplay: flex;\\n\\t\\t\\t\\t\\talign-items: flex-end;\\n\\t\\t\\t\\t\\tborder: 2px outset #ddd;\\n\\t\\t\\t\\t\\tborder-color: transparent transparent #ddd;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\t.level {\\n\\t\\t\\t\\t\\tflex: 1;\\n\\t\\t\\t\\t\\tbackground-color: #aaa;\\n\\t\\t\\t\\t\\tmargin: 2px;\\n\\t\\t\\t\\t\\tmin-height: 2px;\\n\\t\\t\\t\\t\\tborder-top-left-radius: 2px;\\n\\t\\t\\t\\t\\tborder-top-right-radius: 2px;\\n\\t\\t\\t\\t}\\n\\t\\t\\t</style>\\n\\t\\t\\t<div\\n\\t\\t\\t\\tid=\\\"container\\\"\\n\\t\\t\\t\\tstyle=${style_map_1.styleMap({\\n            height: `${this.height}px`,\\n        })}\\n\\t\\t\\t>\\n\\t\\t\\t\\t${this.meterLevels.map((val) => lit_element_1.html `\\n\\t\\t\\t\\t\\t\\t<div\\n\\t\\t\\t\\t\\t\\t\\tclass=\\\"level\\\"\\n\\t\\t\\t\\t\\t\\t\\tstyle=${style_map_1.styleMap({\\n            height: `${(Math.pow(val, 0.2) * 100).toFixed(2)}%`,\\n            backgroundColor: this.renderColor(val),\\n        })}\\n\\t\\t\\t\\t\\t\\t></div>\\n\\t\\t\\t\\t\\t`)}\\n\\t\\t\\t</div>\\n\\t\\t`;\\n    }\\n};\\nToneMeterElement = __decorate([\\n    lit_element_1.customElement(\\\"tone-meter-vis\\\")\\n], ToneMeterElement);\\nexports.ToneMeterElement = ToneMeterElement;\\n/**\\n * Create an audio node element\\n */\\nfunction createMeter({ tone, parent, height, }) {\\n    const element = document.createElement(\\\"tone-meter-vis\\\");\\n    element.bind(tone);\\n    if (parent) {\\n        parent.appendChild(element);\\n    }\\n    if (height) {\\n        element.setAttribute(\\\"height\\\", height.toString());\\n    }\\n    return element;\\n}\\nexports.createMeter = createMeter;\\n\\n\\n//# sourceURL=webpack:///./src/gui/vis/meter.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/vis/oscillator.ts\":\n/*!***********************************!*\\\n  !*** ./src/gui/vis/oscillator.ts ***!\n  \\***********************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\\n    return new (P || (P = Promise))(function (resolve, reject) {\\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\\n        function rejected(value) { try { step(generator[\\\"throw\\\"](value)); } catch (e) { reject(e); } }\\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\\n    });\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneOscillatorVis = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst vis_base_1 = __webpack_require__(/*! ./vis-base */ \\\"./src/gui/vis/vis-base.ts\\\");\\nlet ToneOscillatorVis = class ToneOscillatorVis extends vis_base_1.VisBase {\\n    generate() {\\n        return __awaiter(this, void 0, void 0, function* () {\\n            if (!this.tone) {\\n                return;\\n            }\\n            const values = yield this.tone.asArray(600);\\n            this.draw(values);\\n        });\\n    }\\n    bind(tone) {\\n        this.tone = tone;\\n        this.generate();\\n    }\\n};\\nToneOscillatorVis = __decorate([\\n    lit_element_1.customElement(\\\"tone-oscillator-vis\\\")\\n], ToneOscillatorVis);\\nexports.ToneOscillatorVis = ToneOscillatorVis;\\n\\n\\n//# sourceURL=webpack:///./src/gui/vis/oscillator.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/vis/vis-base.ts\":\n/*!*********************************!*\\\n  !*** ./src/gui/vis/vis-base.ts ***!\n  \\*********************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.VisBase = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nclass VisBase extends lit_element_1.LitElement {\\n    constructor() {\\n        super(...arguments);\\n        this.bgcolor = \\\"white\\\";\\n        this.color = \\\"black\\\";\\n        this.values = {};\\n        this.height = 100;\\n        this.width = 310;\\n        this.normalizeCurve = true;\\n    }\\n    scale(v, inMin, inMax, outMin, outMax) {\\n        return ((v - inMin) / (inMax - inMin)) * (outMax - outMin) + outMin;\\n    }\\n    draw(values) {\\n        const canvas = this.shadowRoot.querySelector(\\\"canvas\\\");\\n        if (canvas) {\\n            const context = canvas.getContext(\\\"2d\\\");\\n            canvas.height = this.height;\\n            canvas.width = this.width;\\n            const width = canvas.width;\\n            const height = canvas.height;\\n            context.clearRect(0, 0, width, height);\\n            const maxValuesLength = 2048;\\n            if (values.length > maxValuesLength) {\\n                const resampled = new Float32Array(maxValuesLength);\\n                // down sample to maxValuesLength values\\n                for (let i = 0; i < maxValuesLength; i++) {\\n                    resampled[i] =\\n                        values[Math.floor((i / maxValuesLength) * values.length)];\\n                }\\n                values = resampled;\\n            }\\n            const max = this.normalizeCurve\\n                ? Math.max(0.001, ...values) * 1.1\\n                : 1;\\n            const min = this.normalizeCurve\\n                ? Math.min(-0.001, ...values) * 1.1\\n                : 0;\\n            const lineWidth = 3;\\n            context.lineWidth = lineWidth;\\n            context.beginPath();\\n            for (let i = 0; i < values.length; i++) {\\n                const v = values[i];\\n                const x = this.scale(i, 0, values.length, lineWidth, width - lineWidth);\\n                const y = this.scale(v, max, min, 0, height - lineWidth);\\n                if (i === 0) {\\n                    context.moveTo(x, y);\\n                }\\n                else {\\n                    context.lineTo(x, y);\\n                }\\n            }\\n            context.lineCap = \\\"round\\\";\\n            context.strokeStyle = \\\"white\\\";\\n            context.stroke();\\n        }\\n    }\\n    updated() {\\n        clearTimeout(this.timeout);\\n        this.timeout = setTimeout(() => {\\n            this.generate();\\n        }, 50);\\n    }\\n    render() {\\n        return lit_element_1.html `\\n\\t\\t\\t<style>\\n\\t\\t\\t\\t#container {\\n\\t\\t\\t\\t\\tmargin-top: 5px;\\n\\t\\t\\t\\t}\\n\\n\\t\\t\\t\\tcanvas {\\n\\t\\t\\t\\t\\tbackground-color: #aaa;\\n\\t\\t\\t\\t\\twidth: 100%;\\n\\t\\t\\t\\t\\tborder-radius: 4px;\\n\\t\\t\\t\\t\\theight: ${this.height}px;\\n\\t\\t\\t\\t}\\n\\t\\t\\t</style>\\n\\t\\t\\t<div id=\\\"container\\\">\\n\\t\\t\\t\\t<canvas></canvas>\\n\\t\\t\\t</div>\\n\\t\\t`;\\n    }\\n}\\n__decorate([\\n    lit_element_1.property({ type: String })\\n], VisBase.prototype, \\\"bgcolor\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: String })\\n], VisBase.prototype, \\\"color\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Object })\\n], VisBase.prototype, \\\"values\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Number })\\n], VisBase.prototype, \\\"height\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Number })\\n], VisBase.prototype, \\\"width\\\", void 0);\\nexports.VisBase = VisBase;\\n\\n\\n//# sourceURL=webpack:///./src/gui/vis/vis-base.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/vis/visualizer.ts\":\n/*!***********************************!*\\\n  !*** ./src/gui/vis/visualizer.ts ***!\n  \\***********************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\\n    return new (P || (P = Promise))(function (resolve, reject) {\\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\\n        function rejected(value) { try { step(generator[\\\"throw\\\"](value)); } catch (e) { reject(e); } }\\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\\n    });\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.ToneVisualizer = void 0;\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nconst deepEquals = __webpack_require__(/*! deep-equal */ \\\"./node_modules/deep-equal/index.js\\\");\\n__webpack_require__(/*! ./oscillator */ \\\"./src/gui/vis/oscillator.ts\\\");\\n__webpack_require__(/*! ./envelope */ \\\"./src/gui/vis/envelope.ts\\\");\\n__webpack_require__(/*! ./filter */ \\\"./src/gui/vis/filter.ts\\\");\\n__webpack_require__(/*! ./compressor */ \\\"./src/gui/vis/compressor.ts\\\");\\n__webpack_require__(/*! ./meter */ \\\"./src/gui/vis/meter.ts\\\");\\n__webpack_require__(/*! ./waveform */ \\\"./src/gui/vis/waveform.ts\\\");\\n__webpack_require__(/*! ./buffer */ \\\"./src/gui/vis/buffer.ts\\\");\\nlet ToneVisualizer = class ToneVisualizer extends lit_element_1.LitElement {\\n    constructor() {\\n        super(...arguments);\\n        /**\\n         * Make sure that it is rendered for the first time\\n         * before applying shouldUpdate optimization\\n         */\\n        this.firstRendered = false;\\n    }\\n    bind(tone) {\\n        return __awaiter(this, void 0, void 0, function* () {\\n            // find the sub object\\n            this.tone = tone;\\n            this.path.forEach((path) => {\\n                this.tone = tone[path];\\n            });\\n            if (this.tone) {\\n                yield this.requestUpdate();\\n                this.shadowRoot\\n                    .querySelectorAll(\\\".vis\\\")\\n                    .forEach((vis) => {\\n                    vis.bind(this.tone);\\n                });\\n                this.firstRendered = true;\\n            }\\n        });\\n    }\\n    shouldUpdate() {\\n        if (this.tone && this.firstRendered) {\\n            return deepEquals(this.values, this.tone.get());\\n        }\\n        else {\\n            return true;\\n        }\\n    }\\n    chooseVis() {\\n        if (this.tone.toString().includes(\\\"Envelope\\\")) {\\n            return lit_element_1.html `\\n\\t\\t\\t\\t<tone-envelope-vis\\n\\t\\t\\t\\t\\tclass=\\\"vis\\\"\\n\\t\\t\\t\\t\\tvalues=${JSON.stringify(this.values)}\\n\\t\\t\\t\\t></tone-envelope-vis>\\n\\t\\t\\t`;\\n        }\\n        else if (this.tone.toString().includes(\\\"Oscillator\\\")) {\\n            return lit_element_1.html `\\n\\t\\t\\t\\t<tone-oscillator-vis\\n\\t\\t\\t\\t\\tclass=\\\"vis\\\"\\n\\t\\t\\t\\t\\tvalues=${JSON.stringify(this.values)}\\n\\t\\t\\t\\t></tone-oscillator-vis>\\n\\t\\t\\t`;\\n        }\\n        else if (this.tone.toString() === \\\"Compressor\\\") {\\n            return lit_element_1.html `\\n\\t\\t\\t\\t<tone-compressor-vis\\n\\t\\t\\t\\t\\tclass=\\\"vis\\\"\\n\\t\\t\\t\\t\\tvalues=${JSON.stringify(this.values)}\\n\\t\\t\\t\\t></tone-compressor-vis>\\n\\t\\t\\t`;\\n        }\\n        else if (this.tone.toString() === \\\"Filter\\\" ||\\n            this.tone.toString() === \\\"OnePoleFilter\\\") {\\n            return lit_element_1.html `\\n\\t\\t\\t\\t<tone-filter-vis\\n\\t\\t\\t\\t\\tclass=\\\"vis\\\"\\n\\t\\t\\t\\t\\tvalues=${JSON.stringify(this.values)}\\n\\t\\t\\t\\t></tone-filter-vis>\\n\\t\\t\\t`;\\n        }\\n        else if (this.tone.toString() === \\\"Meter\\\") {\\n            return lit_element_1.html `\\n\\t\\t\\t\\t<tone-meter-vis\\n\\t\\t\\t\\t\\tclass=\\\"vis\\\"\\n\\t\\t\\t\\t\\tvalues=${JSON.stringify(this.values)}\\n\\t\\t\\t\\t></tone-meter-vis>\\n\\t\\t\\t`;\\n        }\\n        else if (this.tone.toString() === \\\"Waveform\\\") {\\n            return lit_element_1.html `\\n\\t\\t\\t\\t<tone-waveform-vis\\n\\t\\t\\t\\t\\tclass=\\\"vis\\\"\\n\\t\\t\\t\\t\\tvalues=${JSON.stringify(this.values)}\\n\\t\\t\\t\\t></tone-waveform-vis>\\n\\t\\t\\t`;\\n        }\\n        else if (this.tone.toString() === \\\"FFT\\\") {\\n            return lit_element_1.html `\\n\\t\\t\\t\\t<tone-fft-vis\\n\\t\\t\\t\\t\\tclass=\\\"vis\\\"\\n\\t\\t\\t\\t\\tvalues=${JSON.stringify(this.values)}\\n\\t\\t\\t\\t></tone-fft-vis>\\n\\t\\t\\t`;\\n        }\\n        else if (Reflect.has(this.tone, \\\"buffer\\\")) {\\n            return lit_element_1.html `\\n\\t\\t\\t\\t<tone-buffer-vis\\n\\t\\t\\t\\t\\tclass=\\\"vis\\\"\\n\\t\\t\\t\\t\\tvalues=${JSON.stringify(this.values)}\\n\\t\\t\\t\\t></tone-buffer-vis>\\n\\t\\t\\t`;\\n        }\\n    }\\n    render() {\\n        if (this.tone) {\\n            return lit_element_1.html `\\n\\t\\t\\t\\t<div id=\\\"container\\\">\\n\\t\\t\\t\\t\\t${this.chooseVis()}\\n\\t\\t\\t\\t</div>\\n\\t\\t\\t`;\\n        }\\n    }\\n};\\n__decorate([\\n    lit_element_1.property({ type: Array })\\n], ToneVisualizer.prototype, \\\"path\\\", void 0);\\n__decorate([\\n    lit_element_1.property({ type: Object })\\n], ToneVisualizer.prototype, \\\"values\\\", void 0);\\nToneVisualizer = __decorate([\\n    lit_element_1.customElement(\\\"tone-visualizer\\\")\\n], ToneVisualizer);\\nexports.ToneVisualizer = ToneVisualizer;\\n\\n\\n//# sourceURL=webpack:///./src/gui/vis/visualizer.ts?\");\n\n/***/ }),\n\n/***/ \"./src/gui/vis/waveform.ts\":\n/*!*********************************!*\\\n  !*** ./src/gui/vis/waveform.ts ***!\n  \\*********************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\neval(\"\\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\\n    if (typeof Reflect === \\\"object\\\" && typeof Reflect.decorate === \\\"function\\\") r = Reflect.decorate(decorators, target, key, desc);\\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\\n};\\nObject.defineProperty(exports, \\\"__esModule\\\", { value: true });\\nexports.createWaveform = void 0;\\nconst vis_base_1 = __webpack_require__(/*! ./vis-base */ \\\"./src/gui/vis/vis-base.ts\\\");\\nconst lit_element_1 = __webpack_require__(/*! lit-element */ \\\"./node_modules/lit-element/lit-element.js\\\");\\nlet ToneWaveformElement = class ToneWaveformElement extends vis_base_1.VisBase {\\n    constructor() {\\n        super(...arguments);\\n        this.height = 40;\\n    }\\n    generate() {\\n        // ignored\\n    }\\n    loop() {\\n        requestAnimationFrame(this.loop.bind(this));\\n        if (!this.tone) {\\n            return;\\n        }\\n        const values = this.tone.getValue();\\n        this.draw(values);\\n    }\\n    bind(tone) {\\n        this.tone = tone;\\n        this.loop();\\n    }\\n};\\nToneWaveformElement = __decorate([\\n    lit_element_1.customElement(\\\"tone-waveform-vis\\\")\\n], ToneWaveformElement);\\n/**\\n * Create an audio node element\\n */\\nfunction createWaveform({ tone, parent, height, }) {\\n    const element = document.createElement(\\\"tone-waveform-vis\\\");\\n    element.bind(tone);\\n    if (parent) {\\n        parent.appendChild(element);\\n    }\\n    if (height) {\\n        element.setAttribute(\\\"height\\\", height.toString());\\n    }\\n    return element;\\n}\\nexports.createWaveform = createWaveform;\\n\\n\\n//# sourceURL=webpack:///./src/gui/vis/waveform.ts?\");\n\n/***/ }),\n\n/***/ 0:\n/*!********************************!*\\\n  !*** ./util.inspect (ignored) ***!\n  \\********************************/\n/*! no static exports found */\n/***/ (function(module, exports) {\n\neval(\"/* (ignored) */\\n\\n//# sourceURL=webpack:///./util.inspect_(ignored)?\");\n\n/***/ }),\n\n/***/ \"tone\":\n/*!***********************!*\\\n  !*** external \"Tone\" ***!\n  \\***********************/\n/*! no static exports found */\n/***/ (function(module, exports) {\n\neval(\"module.exports = __WEBPACK_EXTERNAL_MODULE_tone__;\\n\\n//# sourceURL=webpack:///external_%22Tone%22?\");\n\n/***/ })\n\n/******/ });\n});"
  },
  {
    "path": "examples/jump.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>FatOscillator</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<style type=\"text/css\">\n\t\t\ttone-play-toggle {\n\t\t\t\tmargin-bottom: 10px;\n\t\t\t}\n\t\t</style>\n\t\t<tone-example label=\"Supersaw\">\n\t\t\t<div slot=\"explanation\">\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/FatOscillator\"\n\t\t\t\t\t>Tone.FatOscillator</a\n\t\t\t\t>\n\t\t\t\tcreates multiple oscillators and detunes them slightly from each\n\t\t\t\tother to thicken the sound. The <code>count</code> parameter\n\t\t\t\tsets the number of oscillators and <code>spread</code> sets the\n\t\t\t\ttotal spread (in cents) between the oscillators. <br /><br />\n\t\t\t\tFatOscillator is also available in\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/OmniOscillator\"\n\t\t\t\t\t>Tone.OmniOscillator</a\n\t\t\t\t>\n\t\t\t\tby prefixing another type with \"fat\", then use the count and\n\t\t\t\tspread to control the number and detune of the oscillators. To\n\t\t\t\tcreate a \"supersaw\":\n\t\t\t\t<code>omniOscillator.type = \"fatsawtooth\"</code>. <br /><br />\n\t\t\t\t<a href=\"http://www.midiworld.com/files/1121/\"\n\t\t\t\t\t>Jump by Van Halen MIDI</a\n\t\t\t\t>\n\t\t\t\tconverted using\n\t\t\t\t<a href=\"https://tonejs.github.io/Midi/\">@tonejs/midi</a>\n\t\t\t</div>\n\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\tconst synth = new Tone.PolySynth(Tone.Synth, {\n\t\t\t\toscillator: {\n\t\t\t\t\ttype: \"fatsawtooth\",\n\t\t\t\t\tcount: 3,\n\t\t\t\t\tspread: 30,\n\t\t\t\t},\n\t\t\t\tenvelope: {\n\t\t\t\t\tattack: 0.01,\n\t\t\t\t\tdecay: 0.1,\n\t\t\t\t\tsustain: 0.5,\n\t\t\t\t\trelease: 0.4,\n\t\t\t\t\tattackCurve: \"exponential\",\n\t\t\t\t},\n\t\t\t}).toDestination();\n\n\t\t\t// Van Halen - Jump MIDI from http://www.midiworld.com/files/1121/\n\t\t\t// converted using\n\t\t\tconst part = new Tone.Part(\n\t\t\t\t(time, note) => {\n\t\t\t\t\tsynth.triggerAttackRelease(\n\t\t\t\t\t\tnote.noteName,\n\t\t\t\t\t\tnote.duration,\n\t\t\t\t\t\ttime,\n\t\t\t\t\t\tnote.velocity\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\t[\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"192i\",\n\t\t\t\t\t\tnoteName: \"G4\",\n\t\t\t\t\t\tvelocity: 0.8110236220472441,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"192i\",\n\t\t\t\t\t\tnoteName: \"B4\",\n\t\t\t\t\t\tvelocity: 0.7874015748031497,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"192i\",\n\t\t\t\t\t\tnoteName: \"D5\",\n\t\t\t\t\t\tvelocity: 0.8031496062992126,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"480i\",\n\t\t\t\t\t\tnoteName: \"G4\",\n\t\t\t\t\t\tvelocity: 0.7559055118110236,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"480i\",\n\t\t\t\t\t\tnoteName: \"C5\",\n\t\t\t\t\t\tvelocity: 0.6850393700787402,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"480i\",\n\t\t\t\t\t\tnoteName: \"E5\",\n\t\t\t\t\t\tvelocity: 0.6771653543307087,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"768i\",\n\t\t\t\t\t\tnoteName: \"F4\",\n\t\t\t\t\t\tvelocity: 0.8661417322834646,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"768i\",\n\t\t\t\t\t\tnoteName: \"A4\",\n\t\t\t\t\t\tvelocity: 0.8346456692913385,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"768i\",\n\t\t\t\t\t\tnoteName: \"C5\",\n\t\t\t\t\t\tvelocity: 0.8188976377952756,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"1056i\",\n\t\t\t\t\t\tnoteName: \"F4\",\n\t\t\t\t\t\tvelocity: 0.7007874015748031,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"1056i\",\n\t\t\t\t\t\tnoteName: \"A4\",\n\t\t\t\t\t\tvelocity: 0.6850393700787402,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"1056i\",\n\t\t\t\t\t\tnoteName: \"C5\",\n\t\t\t\t\t\tvelocity: 0.6614173228346457,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"1248i\",\n\t\t\t\t\t\tnoteName: \"G4\",\n\t\t\t\t\t\tvelocity: 0.6771653543307087,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"1248i\",\n\t\t\t\t\t\tnoteName: \"B4\",\n\t\t\t\t\t\tvelocity: 0.6771653543307087,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"1248i\",\n\t\t\t\t\t\tnoteName: \"D5\",\n\t\t\t\t\t\tvelocity: 0.7165354330708661,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"1440i\",\n\t\t\t\t\t\tnoteName: \"G4\",\n\t\t\t\t\t\tvelocity: 0.8818897637795275,\n\t\t\t\t\t\tduration: \"248i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"1440i\",\n\t\t\t\t\t\tnoteName: \"B4\",\n\t\t\t\t\t\tvelocity: 0.84251968503937,\n\t\t\t\t\t\tduration: \"248i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"1440i\",\n\t\t\t\t\t\tnoteName: \"D5\",\n\t\t\t\t\t\tvelocity: 0.8818897637795275,\n\t\t\t\t\t\tduration: \"248i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"1728i\",\n\t\t\t\t\t\tnoteName: \"G4\",\n\t\t\t\t\t\tvelocity: 0.8267716535433071,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"1728i\",\n\t\t\t\t\t\tnoteName: \"C5\",\n\t\t\t\t\t\tvelocity: 0.8031496062992126,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"1728i\",\n\t\t\t\t\t\tnoteName: \"E5\",\n\t\t\t\t\t\tvelocity: 0.8188976377952756,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"2016i\",\n\t\t\t\t\t\tnoteName: \"F4\",\n\t\t\t\t\t\tvelocity: 0.7086614173228346,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"2016i\",\n\t\t\t\t\t\tnoteName: \"A4\",\n\t\t\t\t\t\tvelocity: 0.7244094488188977,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"2016i\",\n\t\t\t\t\t\tnoteName: \"C5\",\n\t\t\t\t\t\tvelocity: 0.7007874015748031,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"2208i\",\n\t\t\t\t\t\tnoteName: \"C4\",\n\t\t\t\t\t\tvelocity: 0.9921259842519685,\n\t\t\t\t\t\tduration: \"296i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"2208i\",\n\t\t\t\t\t\tnoteName: \"F4\",\n\t\t\t\t\t\tvelocity: 0.968503937007874,\n\t\t\t\t\t\tduration: \"200i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"2208i\",\n\t\t\t\t\t\tnoteName: \"A4\",\n\t\t\t\t\t\tvelocity: 0.9606299212598425,\n\t\t\t\t\t\tduration: \"208i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"2400i\",\n\t\t\t\t\t\tnoteName: \"E4\",\n\t\t\t\t\t\tvelocity: 0.7559055118110236,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"2400i\",\n\t\t\t\t\t\tnoteName: \"G4\",\n\t\t\t\t\t\tvelocity: 0.7007874015748031,\n\t\t\t\t\t\tduration: \"104i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"2592i\",\n\t\t\t\t\t\tnoteName: \"C4\",\n\t\t\t\t\t\tvelocity: 0.968503937007874,\n\t\t\t\t\t\tduration: \"488i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"2592i\",\n\t\t\t\t\t\tnoteName: \"D4\",\n\t\t\t\t\t\tvelocity: 0.9448818897637795,\n\t\t\t\t\t\tduration: \"488i\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttime: \"2592i\",\n\t\t\t\t\t\tnoteName: \"G4\",\n\t\t\t\t\t\tvelocity: 0.937007874015748,\n\t\t\t\t\t\tduration: \"488i\",\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t).start(0);\n\n\t\t\tpart.loop = true;\n\t\t\tpart.loopEnd = \"4m\";\n\n\t\t\tTone.Transport.bpm.value = 132;\n\n\t\t\tdrawer().add({\n\t\t\t\ttone: synth,\n\t\t\t});\n\n\t\t\t// bind the interface\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"start\", () => Tone.Transport.start());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"stop\", () => Tone.Transport.stop());\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/lfoEffects.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>LFO Effects</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<tone-example label=\"LFO Effects\">\n\t\t\t<div slot=\"explanation\">\n\t\t\t\tThese effects use an\n\t\t\t\t<a href=\"https://tonejs.github.io/docs/latest/classes/LFO\"\n\t\t\t\t\t>LFO</a\n\t\t\t\t>\n\t\t\t\t(Low Frequency Oscillator) to modulate the effect. Click and\n\t\t\t\tdrag the dot to change the frequency and depth of the effect.\n\t\t\t\t<br /><br />\n\t\t\t\tDocs on\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/AutoPanner\"\n\t\t\t\t\t>Tone.AutoPanner</a\n\t\t\t\t>,\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/AutoFilter\"\n\t\t\t\t\t>Tone.AutoFilter</a\n\t\t\t\t>, and\n\t\t\t\t<a href=\"https://tonejs.github.io/docs/latest/classes/Tremolo\"\n\t\t\t\t\t>Tone.Tremolo</a\n\t\t\t\t>\n\t\t\t</div>\n\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-slider\n\t\t\t\t\tlabel=\"Panner\"\n\t\t\t\t\tid=\"panner\"\n\t\t\t\t\tunits=\"hz\"\n\t\t\t\t\tvalue=\"4\"\n\t\t\t\t\tstep=\"0.5\"\n\t\t\t\t\tmin=\"1\"\n\t\t\t\t\tmax=\"15\"\n\t\t\t\t></tone-slider>\n\t\t\t\t<tone-play-toggle id=\"osc0\"></tone-play-toggle>\n\t\t\t\t<tone-slider\n\t\t\t\t\tlabel=\"Filter\"\n\t\t\t\t\tid=\"filter\"\n\t\t\t\t\tunits=\"hz\"\n\t\t\t\t\tvalue=\"4\"\n\t\t\t\t\tstep=\"0.5\"\n\t\t\t\t\tmin=\"1\"\n\t\t\t\t\tmax=\"15\"\n\t\t\t\t></tone-slider>\n\t\t\t\t<tone-play-toggle id=\"osc1\"></tone-play-toggle>\n\t\t\t\t<tone-slider\n\t\t\t\t\tlabel=\"Tremolo\"\n\t\t\t\t\tid=\"tremolo\"\n\t\t\t\t\tunits=\"hz\"\n\t\t\t\t\tvalue=\"4\"\n\t\t\t\t\tstep=\"0.5\"\n\t\t\t\t\tmin=\"1\"\n\t\t\t\t\tmax=\"15\"\n\t\t\t\t></tone-slider>\n\t\t\t\t<tone-play-toggle id=\"osc2\"></tone-play-toggle>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\t// AutoPanner - a panning modulation effect\n\t\t\tconst panner = new Tone.AutoPanner({\n\t\t\t\tfrequency: 4,\n\t\t\t\tdepth: 1,\n\t\t\t})\n\t\t\t\t.toDestination()\n\t\t\t\t.start();\n\n\t\t\t// AutoFilter - a filter modulation effect\n\t\t\tconst filter = new Tone.AutoFilter({\n\t\t\t\tfrequency: 2,\n\t\t\t\tdepth: 0.6,\n\t\t\t})\n\t\t\t\t.toDestination()\n\t\t\t\t.start();\n\n\t\t\t// Tremolo - an amplitude modulation effect\n\t\t\tconst tremolo = new Tone.Tremolo({\n\t\t\t\tfrequency: 0.6,\n\t\t\t\tdepth: 0.7,\n\t\t\t})\n\t\t\t\t.toDestination()\n\t\t\t\t.start();\n\n\t\t\t// the input oscillators\n\t\t\tconst pannerOsc = new Tone.Oscillator({\n\t\t\t\tvolume: -12,\n\t\t\t\ttype: \"square6\",\n\t\t\t\tfrequency: \"C4\",\n\t\t\t}).connect(panner);\n\n\t\t\tconst filterOsc = new Tone.Oscillator({\n\t\t\t\tvolume: -12,\n\t\t\t\ttype: \"square6\",\n\t\t\t\tfrequency: \"E4\",\n\t\t\t}).connect(filter);\n\n\t\t\tconst tremoloOsc = new Tone.Oscillator({\n\t\t\t\tvolume: -12,\n\t\t\t\ttype: \"square6\",\n\t\t\t\tfrequency: \"A4\",\n\t\t\t}).connect(tremolo);\n\n\t\t\t// bind the interface\n\t\t\tdocument\n\t\t\t\t.querySelector(\"#osc0\")\n\t\t\t\t.addEventListener(\"start\", () => pannerOsc.start());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"#osc0\")\n\t\t\t\t.addEventListener(\"stop\", () => pannerOsc.stop());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"#panner\")\n\t\t\t\t.addEventListener(\n\t\t\t\t\t\"input\",\n\t\t\t\t\t(e) => (panner.frequency.value = parseFloat(e.target.value))\n\t\t\t\t);\n\t\t\tdocument\n\t\t\t\t.querySelector(\"#osc1\")\n\t\t\t\t.addEventListener(\"start\", () => filterOsc.start());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"#osc1\")\n\t\t\t\t.addEventListener(\"stop\", () => filterOsc.stop());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"#filter\")\n\t\t\t\t.addEventListener(\n\t\t\t\t\t\"input\",\n\t\t\t\t\t(e) => (filter.frequency.value = parseFloat(e.target.value))\n\t\t\t\t);\n\t\t\tdocument\n\t\t\t\t.querySelector(\"#osc2\")\n\t\t\t\t.addEventListener(\"start\", () => tremoloOsc.start());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"#osc2\")\n\t\t\t\t.addEventListener(\"stop\", () => tremoloOsc.stop());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"#tremolo\")\n\t\t\t\t.addEventListener(\n\t\t\t\t\t\"input\",\n\t\t\t\t\t(e) =>\n\t\t\t\t\t\t(tremolo.frequency.value = parseFloat(e.target.value))\n\t\t\t\t);\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/meter.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Meter</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<tone-example label=\"Meter\">\n\t\t\t<tone-loader></tone-loader>\n\t\t\t<div slot=\"explanation\">\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/Meter\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t>Tone.Meter</a\n\t\t\t\t>\n\t\t\t\tgives you the level of the incoming signal in decibels.\n\t\t\t</div>\n\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\tconst player = new Tone.Player({\n\t\t\t\turl: \"https://tonejs.github.io/audio/berklee/Resonant_FM_laser1.mp3\",\n\t\t\t\tloop: true,\n\t\t\t}).toDestination();\n\n\t\t\tconst toneMeter = new Tone.Meter({\n\t\t\t\tchannelCount: 2,\n\t\t\t});\n\t\t\tplayer.connect(toneMeter);\n\n\t\t\tmeter({\n\t\t\t\ttone: toneMeter,\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t});\n\n\t\t\tui({\n\t\t\t\ttone: player,\n\t\t\t\tname: \"Player\",\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t});\n\n\t\t\t// bind the interface\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"start\", () => player.start());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"stop\", () => player.stop());\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/mic.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Microphone</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<style type=\"text/css\">\n\t\t\ttone-oscilloscope {\n\t\t\t\twidth: 100%;\n\t\t\t\tbackground-color: black;\n\t\t\t\theight: 40px;\n\t\t\t\tborder-radius: 20px;\n\t\t\t\tmargin-bottom: 10px;\n\t\t\t}\n\t\t</style>\n\t\t<tone-example label=\"Microphone\">\n\t\t\t<div slot=\"explanation\">\n\t\t\t\tIf supported, Tone.UserMedia uses <code>getUserMedia</code> to\n\t\t\t\topen the user's microphone where it can then be processed with\n\t\t\t\tTone.js. Only works on https domains.\n\t\t\t</div>\n\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-mic-button></tone-mic-button>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\t// you probably DON'T want to connect the microphone\n\t\t\t// directly to the master output because of feedback.\n\t\t\tconst mic = new Tone.UserMedia();\n\n\t\t\tconst micFFT = new Tone.FFT();\n\t\t\tmic.connect(micFFT);\n\n\t\t\tfft({\n\t\t\t\ttone: micFFT,\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t});\n\n\t\t\t// bind the interface\n\t\t\tconst micButton = document.querySelector(\"tone-mic-button\");\n\t\t\tmicButton.supported = Tone.UserMedia.supported;\n\t\t\tmicButton.addEventListener(\"open\", () => mic.open());\n\t\t\tmicButton.addEventListener(\"close\", () => mic.close());\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/mixer.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Mixer</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t\t<style type=\"text/css\">\n\t\t\t#tracks {\n\t\t\t\tdisplay: flex;\n\t\t\t}\n\t\t\t#tracks tone-channel {\n\t\t\t\tflex-grow: 1;\n\t\t\t\tmargin: 5px;\n\t\t\t\twidth: 20%;\n\t\t\t}\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<tone-example label=\"Channel\">\n\t\t\t<div slot=\"explanation\">\n\t\t\t\t<a href=\"https://tonejs.github.io/docs/latest/classes/Channel\"\n\t\t\t\t\t>Tone.Channel</a\n\t\t\t\t>\n\t\t\t\tprovides a simple channel interface. It allows for panning and\n\t\t\t\tvolume changes as well as the ability to\n\t\t\t\t<a href=\"https://tonejs.github.io/docs/latest/classes/Solo\"\n\t\t\t\t\t>solo</a\n\t\t\t\t>\n\t\t\t\t(exclude audio in other Tone.Channels).\n\t\t\t</div>\n\n\t\t\t<tone-loader></tone-loader>\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\tfunction makeChannel(name, url, pan) {\n\t\t\t\tconst channel = new Tone.Channel({\n\t\t\t\t\tpan,\n\t\t\t\t}).toDestination();\n\t\t\t\tconst player = new Tone.Player({\n\t\t\t\t\turl: `https://tonejs.github.io/audio/berklee/${url}.mp3`,\n\t\t\t\t\tloop: true,\n\t\t\t\t})\n\t\t\t\t\t.sync()\n\t\t\t\t\t.start(0);\n\t\t\t\tplayer.connect(channel);\n\n\t\t\t\t// add a UI element\n\t\t\t\tui({\n\t\t\t\t\tname,\n\t\t\t\t\ttone: channel,\n\t\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// create a meter on the destination node\n\t\t\tconst toneMeter = new Tone.Meter({ channelCount: 2 });\n\t\t\tTone.Destination.chain(toneMeter);\n\t\t\tmeter({\n\t\t\t\ttone: toneMeter,\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t});\n\n\t\t\tmakeChannel(\"Guitar 0\", \"comping1\", 1);\n\t\t\tmakeChannel(\"Guitar 1\", \"comping2\", -1);\n\t\t\tmakeChannel(\"Guitar 2\", \"comping3\", 0.25);\n\t\t\tmakeChannel(\"Guitar 3\", \"comping4\", -0.25);\n\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"start\", () => Tone.Transport.start());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"stop\", () => Tone.Transport.stop());\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/monoSynth.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>MonoSynth</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<style>\n\t\t\ttone-piano {\n\t\t\t\tmargin-bottom: 10px;\n\t\t\t}\n\t\t</style>\n\t\t<tone-example label=\"MonoSynth\">\n\t\t\t<div slot=\"explanation\">\n\t\t\t\t<a href=\"https://tonejs.github.io/docs/latest/classes/MonoSynth\"\n\t\t\t\t\t>Tone.MonoSynth</a\n\t\t\t\t>\n\t\t\t\tis composed of one oscillator, one filter, and two envelopes.\n\t\t\t\tBoth envelopes are triggered simultaneously when a note is\n\t\t\t\ttriggered.\n\t\t\t</div>\n\n\t\t\t<div id=\"content\"></div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\tconst synth = new Tone.PolySynth(Tone.MonoSynth, {\n\t\t\t\tvolume: -8,\n\t\t\t\toscillator: {\n\t\t\t\t\ttype: \"square8\",\n\t\t\t\t},\n\t\t\t\tenvelope: {\n\t\t\t\t\tattack: 0.05,\n\t\t\t\t\tdecay: 0.3,\n\t\t\t\t\tsustain: 0.4,\n\t\t\t\t\trelease: 0.8,\n\t\t\t\t},\n\t\t\t\tfilterEnvelope: {\n\t\t\t\t\tattack: 0.001,\n\t\t\t\t\tdecay: 0.7,\n\t\t\t\t\tsustain: 0.1,\n\t\t\t\t\trelease: 0.8,\n\t\t\t\t\tbaseFrequency: 300,\n\t\t\t\t\toctaves: 4,\n\t\t\t\t},\n\t\t\t}).toDestination();\n\n\t\t\tpiano({\n\t\t\t\tnoteon: (note) => synth.triggerAttack(note.name),\n\t\t\t\tnoteoff: (note) => synth.triggerRelease(note.name),\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t});\n\n\t\t\tui({\n\t\t\t\ttone: synth,\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t\tname: \"MonoSynth\",\n\t\t\t});\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/noises.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Noise</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<style>\n\t\t\ttone-trigger,\n\t\t\ttone-oscilloscope {\n\t\t\t\tmargin-bottom: 10px;\n\t\t\t}\n\t\t\ttone-oscilloscope {\n\t\t\t\tbackground-color: black;\n\t\t\t\theight: 60px;\n\t\t\t\twidth: 100%;\n\t\t\t}\n\t\t</style>\n\t\t<tone-example label=\"Noise\">\n\t\t\t<div slot=\"explanation\">\n\t\t\t\t<a href=\"https://tonejs.github.io/docs/latest/classes/Noise\"\n\t\t\t\t\t>Tone.Noise</a\n\t\t\t\t>\n\t\t\t\thas 3 different types of noise. Careful, it's loud!\n\t\t\t</div>\n\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-momentary-button></tone-momentary-button>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\t// make the noise and connect it to the output\n\t\t\tconst noise = new Tone.Noise({\n\t\t\t\tvolume: -10,\n\t\t\t\ttype: \"brown\",\n\t\t\t}).toDestination();\n\n\t\t\tconst toneWaveform = new Tone.Waveform();\n\t\t\tnoise.connect(toneWaveform);\n\n\t\t\twaveform({\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t\ttone: toneWaveform,\n\t\t\t});\n\n\t\t\tui({\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t\ttone: noise,\n\t\t\t});\n\n\t\t\t// bind the interface\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-momentary-button\")\n\t\t\t\t.addEventListener(\"down\", () => noise.start());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-momentary-button\")\n\t\t\t\t.addEventListener(\"up\", () => noise.stop());\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/offline.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Offline</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t\t<style type=\"text/css\">\n\t\t\ttone-button {\n\t\t\t\tmargin-bottom: 10px;\n\t\t\t}\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<tone-example label=\"Offline Rendering\">\n\t\t\t<tone-loader></tone-loader>\n\t\t\t<div slot=\"explanation\">\n\t\t\t\tTone.Offline renders a chunk of Tone.js code into an\n\t\t\t\tAudioBuffer. An offline instance of Tone.Transport is passed\n\t\t\t\tinto the callback which can be used to schedule events. It may\n\t\t\t\ttake a moment to render the sound.\n\t\t\t\t<br /><br />\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/functions/Offline.html\"\n\t\t\t\t\t>Tone.Offline</a\n\t\t\t\t>\n\t\t\t\tdocs.\n\t\t\t</div>\n\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-play-toggle disabled></tone-play-toggle>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\t// play the buffer with a Tone.Player when it's been generated\n\t\t\tconst player = new Tone.Player().toDestination();\n\n\t\t\tconst renderingPromise = Tone.Offline(({ transport }) => {\n\t\t\t\tconst reverb = new Tone.Reverb().toDestination();\n\n\t\t\t\tconst pannerA = new Tone.Panner(-1).connect(reverb);\n\t\t\t\tconst synthA = new Tone.Synth({\n\t\t\t\t\tenvelope: {\n\t\t\t\t\t\tattack: 0.01,\n\t\t\t\t\t\tdecay: 5,\n\t\t\t\t\t\tsustain: 0,\n\t\t\t\t\t},\n\t\t\t\t\toscillator: {\n\t\t\t\t\t\ttype: \"sawtooth4\",\n\t\t\t\t\t},\n\t\t\t\t}).connect(pannerA);\n\t\t\t\tconst seqA = new Tone.Sequence(\n\t\t\t\t\t(time, note) => {\n\t\t\t\t\t\tsynthA.triggerAttack(note, time);\n\t\t\t\t\t},\n\t\t\t\t\t[\"A4\", \"G4\", \"G#4\", \"F#4\", \"E4\"],\n\t\t\t\t\t\"8n\"\n\t\t\t\t).start(0);\n\t\t\t\tseqA.loop = false;\n\n\t\t\t\tconst pannerB = new Tone.Panner(1).connect(reverb);\n\t\t\t\tconst synthB = new Tone.Synth({\n\t\t\t\t\tenvelope: {\n\t\t\t\t\t\tattack: 0.001,\n\t\t\t\t\t\tdecay: 3,\n\t\t\t\t\t\tsustain: 0,\n\t\t\t\t\t},\n\t\t\t\t\toscillator: {\n\t\t\t\t\t\ttype: \"square8\",\n\t\t\t\t\t},\n\t\t\t\t}).connect(pannerB);\n\t\t\t\tconst seqB = new Tone.Sequence(\n\t\t\t\t\t(time, note) => {\n\t\t\t\t\t\tsynthB.triggerAttack(note, time);\n\t\t\t\t\t},\n\t\t\t\t\t[\"G#4\", \"A4\", \"G4\", \"F4\", \"C4\"],\n\t\t\t\t\t\"8n\"\n\t\t\t\t).start(\"16n\");\n\t\t\t\tseqB.loop = false;\n\n\t\t\t\tconst bass = new Tone.MonoSynth({\n\t\t\t\t\tenvelope: {\n\t\t\t\t\t\tattack: 0.01,\n\t\t\t\t\t\tdecay: 3,\n\t\t\t\t\t\tsustain: 0.1,\n\t\t\t\t\t},\n\t\t\t\t}).toDestination();\n\t\t\t\tconst bassSeq = new Tone.Sequence(\n\t\t\t\t\t(time, note) => {\n\t\t\t\t\t\tbass.triggerAttackRelease(note, \"1n\", time);\n\t\t\t\t\t},\n\t\t\t\t\t[\"C2\", \"C2\", \"F1\", \"F1\"],\n\t\t\t\t\t\"4n\"\n\t\t\t\t).start(0);\n\t\t\t\tbassSeq.loop = false;\n\n\t\t\t\ttransport.bpm.value = 150;\n\t\t\t\ttransport.start();\n\n\t\t\t\t// return a promise\n\t\t\t\treturn reverb.ready;\n\t\t\t}, 7);\n\n\t\t\t// set the buffer when it's done\n\t\t\trenderingPromise.then((buffer) => (player.buffer = buffer));\n\t\t\trenderingPromise.then(\n\t\t\t\t() =>\n\t\t\t\t\t(document.querySelector(\"tone-play-toggle\").disabled =\n\t\t\t\t\t\tfalse)\n\t\t\t);\n\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"start\", () => player.start());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"stop\", () => player.stop());\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/oscillator.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Oscillator</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t\t<style type=\"text/css\">\n\t\t\ttone-play-toggle {\n\t\t\t\tmargin-bottom: 10px;\n\t\t\t}\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<tone-example label=\"Oscillator\">\n\t\t\t<div slot=\"explanation\">\n\t\t\t\tThe oscillator has 4 basic types which can be altered by setting\n\t\t\t\tthe number of partials and partials array.\n\t\t\t\t<br /><br />\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/Oscillator\"\n\t\t\t\t\t>Tone.Oscillator</a\n\t\t\t\t>\n\t\t\t\tdocs.\n\t\t\t</div>\n\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-momentary-button></tone-momentary-button>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\tconst osc = new Tone.Oscillator({\n\t\t\t\ttype: \"square\",\n\t\t\t\tfrequency: 440,\n\t\t\t\tvolume: -16,\n\t\t\t}).toDestination();\n\n\t\t\tui({\n\t\t\t\ttone: osc,\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t});\n\n\t\t\t// bind the interface\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-momentary-button\")\n\t\t\t\t.addEventListener(\"down\", () => osc.start());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-momentary-button\")\n\t\t\t\t.addEventListener(\"up\", () => osc.stop());\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/pianoPhase.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n\t<title>Phasing</title>\n\n\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\">\n\t<link rel=\"icon\" type=\"image/png\" sizes=\"174x174\" href=\"./favicon.png\">\n\n\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t<link href=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\" rel=\"stylesheet\"/>\n\t<script src=\"../build/Tone.js\"></script>\n\t<script src=\"./js/tone-ui.js\"></script>\n\t<script src=\"./js/components.js\"></script>\n</head>\n<body>\n\t<style type=\"text/css\">\n\t\t#loop {\n\t\t\tmargin-bottom: 10px;\n\t\t\tdisplay: flex;\n\t\t}\n\n\t\t#loop .bar {\n\t\t\tflex-grow: 1;\n\t\t\twidth: 40%;\n\t\t\theight: 20px;\n\t\t\tmargin: 10px;\n\t\t\tbackground-color: #ececec;\n\t\t\tborder-radius: 4px;\n\t\t\toverflow: hidden;\n\t\t\tposition: relative;\n\t\t}\n\n\t\t#loop .bar .fill {\n\t\t\theight: 100%;\n\t\t\twidth: 50%;\n\t\t\tbackground-color:#7F33ED;\n\t\t\tposition: absolute;\n\t\t\tleft: 50%;\n\t\t\ttransform: translate(-50%, 0);\n\t\t}\n\t</style>\n\t<tone-example label=\"Piano Phase\">\n\t\t<div slot=\"explanation\">\n\t\t\tBy slightly slowing down the playbackRate of the Tone.Sequence in the right channel,\n\t\t\tthe two identical melodies phase against each other in interesting ways.\n\t\t\t<br><br>\n\t\t\tComposition by Steve Reich. Inspiration from Alexander Chen.\n\t\t</div>\n\n\t\t<div id=\"content\">\n\t\t\t<div id=\"loop\">\n\t\t\t\t<div class=\"bar\">\n\t\t\t\t\t<div class=\"fill\"  id=\"left\"></div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"bar\">\n\t\t\t\t\t<div class=\"fill\" id=\"right\"></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t</div>\n\t</tone-example>\n\n\t<script type=\"text/javascript\">\n\t\t// set the bpm and time signature first\n\t\tTone.Transport.timeSignature = [6, 4];\n\t\tTone.Transport.bpm.value = 180;\n\t\t\t\t\n\t\t// L/R channel merging\n\t\tconst merge = new Tone.Merge();\n\n\t\t// a little reverb\n\t\tconst reverb = new Tone.Reverb({\n\t\t\twet: 0.3\n\t\t});\n\n\t\tmerge.chain(reverb, Tone.Destination);\n\n\t\t// left and right synthesizers\n\t\tconst synthL = new Tone.Synth({\n\t\t\toscillator: {\n\t\t\t\ttype: \"custom\",\n\t\t\t\tpartials: [2, 1, 2, 2],\n\t\t\t},\n\t\t\tenvelope: {\n\t\t\t\tattack: 0.005,\n\t\t\t\tdecay: 0.3,\n\t\t\t\tsustain: 0.2,\n\t\t\t\trelease: 1,\n\t\t\t},\n\t\t\tportamento: 0.01,\n\t\t\tvolume: -20\n\t\t}).connect(merge, 0, 0);\n\t\tconst synthR = new Tone.Synth({\n\t\t\toscillator: {\n\t\t\t\ttype: \"custom\",\n\t\t\t\tpartials: [2, 1, 2, 2],\n\t\t\t},\n\t\t\tenvelope: {\n\t\t\t\tattack: 0.005,\n\t\t\t\tdecay: 0.3,\n\t\t\t\tsustain: 0.2,\n\t\t\t\trelease: 1,\n\t\t\t},\n\t\t\tportamento: 0.01,\n\t\t\tvolume: -20\n\t\t}).connect(merge, 0, 1);\n\n\t\t// the two Tone.Sequences\n\t\tconst partL = new Tone.Sequence(((time, note) => {\n\t\t\tsynthL.triggerAttackRelease(note, \"8n\", time);\n\t\t}), [\"E4\", \"F#4\", \"B4\", \"C#5\", \"D5\", \"F#4\", \"E4\", \"C#5\", \"B4\", \"F#4\", \"D5\", \"C#5\"], \"8n\").start();\n\n\t\tconst partR = new Tone.Sequence(((time, note) => {\n\t\t\tsynthR.triggerAttackRelease(note, \"8n\", time);\n\t\t}), [\"E4\", \"F#4\", \"B4\", \"C#5\", \"D5\", \"F#4\", \"E4\", \"C#5\", \"B4\", \"F#4\", \"D5\", \"C#5\"], \"8n\").start(\"2m\");\n\n\t\t// set the playback rate of the right part to be slightly slower\n\t\tpartR.playbackRate = 0.985;\n\n\t\t// bind the interface\n\t\tdocument.querySelector(\"tone-play-toggle\").addEventListener(\"start\", () => Tone.Transport.start());\n\t\tdocument.querySelector(\"tone-play-toggle\").addEventListener(\"stop\", () => Tone.Transport.stop());\n\n\t\t// update the width of the fill bars to reflect the left and right progress\n\t\tfunction progressToWidth(progress) {\n\t\t\tprogress = Math.cos(progress * Math.PI * 2 + Math.PI);\n\t\t\tprogress = (progress + 1) / 2;\n\t\t\treturn `${progress * 100}%`;\n\t\t}\n\t\tfunction loop() {\n\t\t\trequestAnimationFrame(loop);\n\t\t\t// make it go out and back for each loop\n\t\t\t// @ts-ignore\n\t\t\tdocument.querySelector(\"#left\").style.width = progressToWidth(partL.progress);\n\t\t\t// @ts-ignore\n\t\t\tdocument.querySelector(\"#right\").style.width = progressToWidth(partR.progress);\n\t\t}\n\t\tloop();\n\t\t\n\t</script>\n</body>\n</html>\n"
  },
  {
    "path": "examples/pingPongDelay.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Ping Pong Delay</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<tone-example label=\"Ping Pong Delay\">\n\t\t\t<tone-loader></tone-loader>\n\n\t\t\t<div slot=\"explanation\">\n\t\t\t\tA Ping Pong Delay is a stereo feedback delay where the delay\n\t\t\t\tbounces back and forth between the left and right channels. Hit\n\t\t\t\tthe button to trigger a snare sample into the effect.\n\t\t\t\t<br /><br />\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/PingPongDelay\"\n\t\t\t\t\t>Tone.PingPongDelay</a\n\t\t\t\t>\n\t\t\t\tdocs.\n\t\t\t</div>\n\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-momentary-button></tone-momentary-button>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\t// the feedback delay\n\t\t\tconst feedbackDelay = new Tone.PingPongDelay({\n\t\t\t\tdelayTime: \"8n\",\n\t\t\t\tfeedback: 0.6,\n\t\t\t\twet: 0.5,\n\t\t\t}).toDestination();\n\n\t\t\t// play a snare sound through it\n\t\t\tconst player = new Tone.Player(\n\t\t\t\t\"https://tonejs.github.io/audio/drum-samples/CR78/snare.mp3\"\n\t\t\t).connect(feedbackDelay);\n\n\t\t\tconst toneMeter = new Tone.Meter({ channelCount: 2 });\n\t\t\tfeedbackDelay.connect(toneMeter);\n\n\t\t\tmeter({\n\t\t\t\ttone: toneMeter,\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t});\n\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-momentary-button\")\n\t\t\t\t.addEventListener(\"down\", () => player.start());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-momentary-button\")\n\t\t\t\t.addEventListener(\"up\", () => player.stop());\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/pitchShift.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Pitch Shift</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<style>\n\t\t\ttone-slider {\n\t\t\t\twidth: 100%;\n\t\t\t\tmargin-top: 10px;\n\t\t\t}\n\t\t</style>\n\t\t<tone-example label=\"Pitch Shift\">\n\t\t\t<div slot=\"explanation\">\n\t\t\t\tThis example demonstrates the Pitch Shift effect.\n\t\t\t\t<br /><br />\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/PitchShift\"\n\t\t\t\t\t>Tone.Pitch Shift</a\n\t\t\t\t>\n\t\t\t\tdocs.\n\t\t\t</div>\n\n\t\t\t<tone-loader></tone-loader>\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t\t\t<tone-slider\n\t\t\t\t\tlabel=\"pitch\"\n\t\t\t\t\tmin=\"-12\"\n\t\t\t\t\tmax=\"12\"\n\t\t\t\t\tvalue=\"0\"\n\t\t\t\t\tunits=\"hz\"\n\t\t\t\t></tone-slider>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\tconst pitchShift = new Tone.PitchShift().toDestination();\n\t\t\tconst player = new Tone.Player(\n\t\t\t\t\"https://tonejs.github.io/audio/berklee/groovin_analogsynth1.mp3\"\n\t\t\t).connect(pitchShift);\n\t\t\tplayer.loop = true;\n\n\t\t\tconst toneFFT = new Tone.FFT();\n\t\t\tpitchShift.connect(toneFFT);\n\t\t\tfft({\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t\ttone: toneFFT,\n\t\t\t});\n\n\t\t\t// bind the interface\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"start\", () => player.start());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"stop\", () => player.stop());\n\t\t\t// document.querySelector(\"tone-play-toggle\").addEventListener('start', () => {\n\t\t\t// \tdebugger;\n\t\t\t// });\n\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-slider\")\n\t\t\t\t.addEventListener(\"input\", (e) => {\n\t\t\t\t\tpitchShift.pitch = parseFloat(e.target.value);\n\t\t\t\t});\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/player.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Player</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t\t<style type=\"text/css\">\n\t\t\ttone-play-toggle {\n\t\t\t\tmargin-bottom: 10px;\n\t\t\t}\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<tone-example label=\"Player\">\n\t\t\t<tone-loader></tone-loader>\n\t\t\t<div slot=\"explanation\">\n\t\t\t\tClick on the button to play the audio file on loop using\n\t\t\t\t<a href=\"https://tonejs.github.io/docs/latest/classes/Player\"\n\t\t\t\t\t>Tone.Player</a\n\t\t\t\t>.\n\t\t\t</div>\n\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\t// the player\n\t\t\tconst player = new Tone.Player({\n\t\t\t\turl: \"https://tonejs.github.io/audio/loop/FWDL.mp3\",\n\t\t\t\tloop: true,\n\t\t\t\tloopStart: 0.5,\n\t\t\t\tloopEnd: 0.7,\n\t\t\t}).toDestination();\n\n\t\t\tui({\n\t\t\t\ttone: player,\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t});\n\n\t\t\t// bind the interface\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"start\", () => player.start());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"stop\", () => player.stop());\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/polySynth.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>PolySynth</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<style>\n\t\t\ttone-piano {\n\t\t\t\tmargin-bottom: 10px;\n\t\t\t}\n\t\t</style>\n\t\t<tone-example label=\"Polyphony\">\n\t\t\t<div slot=\"explanation\">\n\t\t\t\t<a href=\"https://tonejs.github.io/docs/latest/classes/PolySynth\"\n\t\t\t\t\t>Tone.PolySynth</a\n\t\t\t\t>\n\t\t\t\thandles voice creation and allocation for any monophonic\n\t\t\t\tinstruments passed in as the second parameter. PolySynth is not\n\t\t\t\ta synthesizer by itself, it merely manages voices of one of the\n\t\t\t\tother types of synths, allowing any of the monophonic\n\t\t\t\tsynthesizers to be polyphonic.\n\t\t\t</div>\n\n\t\t\t<div id=\"content\"></div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\tconst synth = new Tone.PolySynth(Tone.Synth, {\n\t\t\t\toscillator: {\n\t\t\t\t\tpartials: [0, 2, 3, 4],\n\t\t\t\t},\n\t\t\t}).toDestination();\n\n\t\t\tpiano({\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t\tpolyphonic: true,\n\t\t\t\tnoteon: (note) => synth.triggerAttack(note.name),\n\t\t\t\tnoteoff: (note) => synth.triggerRelease(note.name),\n\t\t\t});\n\n\t\t\tui({\n\t\t\t\ttone: synth,\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t});\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/quantization.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n\t<title>Quantization</title>\n\n\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\">\n\t<link rel=\"icon\" type=\"image/png\" sizes=\"174x174\" href=\"./favicon.png\">\n\n\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t<link href=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\" rel=\"stylesheet\"/>\n\t<script src=\"../build/Tone.js\"></script>\n\t<script src=\"./js/tone-ui.js\"></script>\n\t<script src=\"./js/components.js\"></script>\n</head>\n<body>\n\t<style>\n\t\t#buttons {\n\t\t\tdisplay: flex;\n\t\t\tmargin: 10px 0;\n\t\t}\n\t\t#buttons tone-button {\n\t\t\tflex-grow: 1;\n\t\t\tmargin: 5px;\n\t\t}\n\t\t#progress {\n\t\t\tmargin: 10px;\n\t\t\tcolor: #8c8c8c;\n\t\t}\n\t</style>\n\t<tone-example label=\"Quantization\">\n\t\t<div slot=\"explanation\">\n\t\t\tUsing the \"@\" symbol, <a href=\"https://github.com/Tonejs/Tone.js/wiki/Time\" target=\"_blank\">Time</a> \n\t\t\texpressions can be <a href=\"https://en.wikipedia.org/wiki/Quantization_(music)\" target=\"_blank\">quantized</a> \n\t\t\t(aligned to a subdivision). In this example, a note's start time is aligned to the given subdivision. \n\t\t\t<br><br>\n\t\t\tThe Transport must be started\n\t\t</div>\n\n\t\t<div id=\"content\">\n\t\t\t<div id=\"progress\"></div>\n\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t\t<div id=\"buttons\">\n\t\t\t\t<tone-button disabled id=\"at8n\" label=\"@8n\">@8n</tone-button>\n\t\t\t\t<tone-button disabled id=\"at4n\" label=\"@4n\">@4n</tone-button>\n\t\t\t\t<tone-button disabled id=\"at2n\" label=\"@2n\">@2n</tone-button>\n\t\t\t\t<tone-button disabled id=\"at1m\" label=\"@1m\">@1m</tone-button>\n\t\t\t</div>\n\t\t</div>\n\t</tone-example>\n\n\t<script type=\"text/javascript\">\n\t\tconst polySynth = new Tone.PolySynth(Tone.Synth).toDestination();\n\n\t\tfunction loop() {\n\t\t\trequestAnimationFrame(loop);\n\t\t\t// @ts-ignore\n\t\t\tconst [bar, beat, sixteenth] = Tone.Transport.position.split(\":\");\n\t\t\tdocument.querySelector(\"#progress\").textContent = `\n\t\t\t\tbar: ${bar}, beat: ${beat}, sixteenth: ${sixteenth}\n\t\t\t`;\n\t\t}\n\t\tloop();\n\n\t\t// bind the interface\n\t\tdocument.querySelector(\"tone-play-toggle\").addEventListener(\"start\", e => {\n\t\t\tTone.Transport.start();\n\t\t\t// enable all of the buttons if it's playing\n\t\t\t// @ts-ignore\t\t\n\t\t\tArray.from(document.querySelectorAll(\"tone-button\")).forEach(el => el.disabled = false);\n\t\t});\n\t\tdocument.querySelector(\"tone-play-toggle\").addEventListener(\"stop\", () => {\n\t\t\tTone.Transport.stop();\n\t\t\t// disable all of the buttons if it's not playing\n\t\t\t// @ts-ignore\t\t\n\t\t\tArray.from(document.querySelectorAll(\"tone-button\")).forEach(el => el.disabled = true);\n\t\t});\n\t\tdocument.querySelector(\"#at8n\").addEventListener(\"click\", e => {\n\t\t\tpolySynth.triggerAttackRelease(\"B4\", \"8n\", \"@8n\");\n\t\t});\n\t\tdocument.querySelector(\"#at4n\").addEventListener(\"click\", e => {\n\t\t\tpolySynth.triggerAttackRelease(\"E4\", \"8n\", \"@4n\");\n\t\t});\n\t\tdocument.querySelector(\"#at2n\").addEventListener(\"click\", e => {\n\t\t\tpolySynth.triggerAttackRelease(\"G3\", \"8n\", \"@2n\");\n\t\t});\n\t\tdocument.querySelector(\"#at1m\").addEventListener(\"click\", e => {\n\t\t\tpolySynth.triggerAttackRelease(\"C2\", \"8n\", \"@1m\");\n\t\t});\n\t</script>\n</body>\n</html>\n"
  },
  {
    "path": "examples/rampTo.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n\t<title>Signal Ramping</title>\n\n\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\">\n\t<link rel=\"icon\" type=\"image/png\" sizes=\"174x174\" href=\"./favicon.png\">\n\n\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t<link href=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\" rel=\"stylesheet\"/>\n\t<script src=\"../build/Tone.js\"></script>\n\t<script src=\"./js/tone-ui.js\"></script>\n\t<script src=\"./js/components.js\"></script>\n</head>\n<body>\n\t<style>\n\t\ttone-slider {\n\t\t\twidth: 100%;\n\t\t\tmargin-top: 10px;\n\t\t}\n\t</style>\n\t<tone-example label=\"rampTo\">\n\t\t<div slot=\"explanation\">\n\t\t\tWorking with signals is different than working with numbers or strings:\n\t\t\tSignals are values which are updated at audio rate,\n\t\t\twhich allows for sample-accurate scheduling and ramping. <code>.rampTo(value, rampTime)</code>\n\t\t\tsmoothly changes the signal from the current value to the target value over the duration of the rampTime.\n\t\t\tThis example uses <code>.rampTo</code> in to smooth out changes in volume and frequency.\n\t\t</div>\n\n\t\t<div id=\"content\">\n\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t\t<tone-slider label=\"harmonicity\" min=\"0.5\" max=\"2\" value=\"1\"></tone-slider>\n\t\t</div>\n\t</tone-example>\n\n\t<script type=\"text/javascript\">\n\t\tconst oscillators = [];\n\n\t\tconst bassFreq = 32;\n\n\t\tfor (let i = 0; i < 8; i++) {\n\t\t\toscillators.push(new Tone.Oscillator({\n\t\t\t\tfrequency: bassFreq * i,\n\t\t\t\ttype: \"sawtooth4\",\n\t\t\t\tvolume: -Infinity,\n\t\t\t\tdetune: Math.random() * 30 - 15,\n\t\t\t}).toDestination());\n\t\t}\n\n\t\t// bind the interface\n\t\tdocument.querySelector(\"tone-play-toggle\").addEventListener(\"start\", e => {\n\t\t\toscillators.forEach(o => {\n\t\t\t\to.start();\n\t\t\t\to.volume.rampTo(-20, 1);\n\t\t\t});\n\t\t});\n\t\t\n\t\tdocument.querySelector(\"tone-play-toggle\").addEventListener(\"stop\", e => {\n\t\t\toscillators.forEach(o => {\n\t\t\t\to.stop(\"+1.2\");\n\t\t\t\to.volume.rampTo(-Infinity, 1);\n\t\t\t});\n\t\t});\n\n\t\tdocument.querySelector(\"tone-slider\").addEventListener(\"input\", e => {\n\t\t\toscillators.forEach((osc, i) => {\n\t\t\t\tosc.frequency.rampTo(bassFreq * i * parseFloat(e.target.value), 0.4);\n\t\t\t});\n\t\t});\n\n\t</script>\n</body>\n</html>\n"
  },
  {
    "path": "examples/reverb.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Reverb</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<style>\n\t\t\ttone-play-toggle {\n\t\t\t\tmargin-bottom: 10px;\n\t\t\t}\n\t\t</style>\n\t\t<tone-example label=\"Reverb\">\n\t\t\t<div slot=\"explanation\">\n\t\t\t\t<a href=\"https://tonejs.github.io/docs/latest/classes/Reverb\"\n\t\t\t\t\t>Tone.Reverb</a\n\t\t\t\t>\n\t\t\t\tis a convolution-based reverb. An impulse response is created\n\t\t\t\twith a decaying noise burst when you click 'Generate Reverb'.\n\t\t\t\tThe 'Decay Time' controls how long the noise burst lasts. If the\n\t\t\t\t'Decay Time' is changed, a new noise burst will need to be\n\t\t\t\tgenerated.\n\t\t\t</div>\n\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\tconst reverb = new Tone.Reverb().toDestination();\n\n\t\t\tconst player = new Tone.Player({\n\t\t\t\turl: \"https://tonejs.github.io/audio/berklee/shaker_slow_1.mp3\",\n\t\t\t\tloop: true,\n\t\t\t\tvolume: 6,\n\t\t\t}).connect(reverb);\n\n\t\t\tui({\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t\ttone: reverb,\n\t\t\t});\n\n\t\t\t// bind the interface\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"start\", () => player.start());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"stop\", () => player.stop());\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/reverseDelay.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Reverse Delay</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<tone-example label=\"Reverse Delay\">\n\t\t\t<tone-loader></tone-loader>\n\n\t\t\t<div slot=\"explanation\">\n\t\t\t\tThe <a href=\"https://tonejs.github.io/docs/latest/classes/ReverseDelay\"\n\t\t\t\t\t>Tone.ReverseDelay</a> is a feedback delay where the echoes are played in reverse. If the delayTime is 1 second, each second will play the input from the previous second in reverse, and the reversed signal will repeat and fade like a feedback delay.\n\t\t\t</div>\n\n\t\t\t<div id=\"content\"></div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\tconst reverseDelay = new Tone.ReverseDelay().toDestination();\n\n\t\t\tconst synth = new Tone.Synth().connect(reverseDelay);\n\n\t\t\tpiano({\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t\tpolyphonic: true,\n\t\t\t\tnoteon: (note) => synth.triggerAttack(note.name),\n\t\t\t\tnoteoff: (note) => synth.triggerRelease(),\n\t\t\t});\n\n\t\t\tui({\n\t\t\t\ttone: reverseDelay,\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t});\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/sampler.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Sampler</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<style>\n\t\t\ttone-piano {\n\t\t\t\tmargin-bottom: 10px;\n\t\t\t}\n\t\t</style>\n\t\t<tone-example label=\"Sampler\">\n\t\t\t<tone-loader></tone-loader>\n\n\t\t\t<div slot=\"explanation\">\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/Sampler\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t>Tone.Sampler</a\n\t\t\t\t>\n\t\t\t\tmakes it easy to create an instrument from audio samples. Pass\n\t\t\t\tin an object which maps the note's pitch or midi value to the\n\t\t\t\turl, then you can trigger the attack and release of that note\n\t\t\t\tlike other instruments. By automatically repitching the samples,\n\t\t\t\tit is possible to play pitches which were not explicitly\n\t\t\t\tincluded which can save loading time.\n\t\t\t</div>\n\n\t\t\t<div id=\"content\"></div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\tconst sampler = new Tone.Sampler({\n\t\t\t\turls: {\n\t\t\t\t\tA0: \"A0.mp3\",\n\t\t\t\t\tC1: \"C1.mp3\",\n\t\t\t\t\t\"D#1\": \"Ds1.mp3\",\n\t\t\t\t\t\"F#1\": \"Fs1.mp3\",\n\t\t\t\t\tA1: \"A1.mp3\",\n\t\t\t\t\tC2: \"C2.mp3\",\n\t\t\t\t\t\"D#2\": \"Ds2.mp3\",\n\t\t\t\t\t\"F#2\": \"Fs2.mp3\",\n\t\t\t\t\tA2: \"A2.mp3\",\n\t\t\t\t\tC3: \"C3.mp3\",\n\t\t\t\t\t\"D#3\": \"Ds3.mp3\",\n\t\t\t\t\t\"F#3\": \"Fs3.mp3\",\n\t\t\t\t\tA3: \"A3.mp3\",\n\t\t\t\t\tC4: \"C4.mp3\",\n\t\t\t\t\t\"D#4\": \"Ds4.mp3\",\n\t\t\t\t\t\"F#4\": \"Fs4.mp3\",\n\t\t\t\t\tA4: \"A4.mp3\",\n\t\t\t\t\tC5: \"C5.mp3\",\n\t\t\t\t\t\"D#5\": \"Ds5.mp3\",\n\t\t\t\t\t\"F#5\": \"Fs5.mp3\",\n\t\t\t\t\tA5: \"A5.mp3\",\n\t\t\t\t\tC6: \"C6.mp3\",\n\t\t\t\t\t\"D#6\": \"Ds6.mp3\",\n\t\t\t\t\t\"F#6\": \"Fs6.mp3\",\n\t\t\t\t\tA6: \"A6.mp3\",\n\t\t\t\t\tC7: \"C7.mp3\",\n\t\t\t\t\t\"D#7\": \"Ds7.mp3\",\n\t\t\t\t\t\"F#7\": \"Fs7.mp3\",\n\t\t\t\t\tA7: \"A7.mp3\",\n\t\t\t\t\tC8: \"C8.mp3\",\n\t\t\t\t},\n\t\t\t\trelease: 1,\n\t\t\t\tbaseUrl: \"https://tonejs.github.io/audio/salamander/\",\n\t\t\t}).toDestination();\n\n\t\t\tpiano({\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t\tnoteon: (note) => sampler.triggerAttack(note.name),\n\t\t\t\tnoteoff: (note) => sampler.triggerRelease(note.name),\n\t\t\t});\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/shiny.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n\t<title>Play Along</title>\n\n\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\">\n\t<link rel=\"icon\" type=\"image/png\" sizes=\"174x174\" href=\"./favicon.png\">\n\n\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t<link href=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\" rel=\"stylesheet\"/>\n\t<script src=\"../build/Tone.js\"></script>\n\t<script src=\"./js/tone-ui.js\"></script>\n\t<script src=\"./js/components.js\"></script>\n\t<style type=\"text/css\">\n\t\ttone-play-toggle {\n\t\t\tmargin-bottom: 10px;\n\t\t}\n\t\ttone-slider {\n\t\t\tdisplay: block;\n\t\t\twidth: 100%;\n\t\t}\n\t</style>\n</head>\n<body>\n\t<tone-example>\n\t\t<tone-loader></tone-loader>\n\t\t<tone-explanation label=\"Play Along\">\n\t\t\tTouch/Mouse and drag to play along with the probabilistic backtrack. X = pitch, Y = modulation.\n\t\t</div>\n\n\t\t<div id=\"content\">\n\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t\t<tone-slider-pad></tone-slider-pad>\n\t\t</div>\n\t</tone-example>\n\n\t<script type=\"text/javascript\">\n\t\t// a compressor\n\t\tconst drumCompress = new Tone.Compressor({\n\t\t\tthreshold: -30,\n\t\t\tratio: 10,\n\t\t\tattack: 0.01,\n\t\t\trelease: 0.2\n\t\t}).toDestination();\n\n\t\tconst distortion = new Tone.Distortion({\n\t\t\tdistortion: 0.4,\n\t\t\twet: 0.4\n\t\t});\n\n\t\t// hats\n\t\tconst hats = new Tone.Player({\n\t\t\turl: \"https://tonejs.github.io/audio/drum-samples/CR78/hihat.mp3\",\n\t\t\tvolume: -10,\n\t\t\tfadeOut: 0.01\n\t\t}).chain(distortion, drumCompress);\n\n\t\tconst hatsLoop = new Tone.Loop({\n\t\t\tcallback: function(time) {\n\t\t\t\thats.start(time).stop(time + 0.05);\n\t\t\t},\n\t\t\tinterval: \"16n\",\n\t\t\tprobability: 0.8\n\t\t}).start(\"1m\");\n\n\t\t// SNARE PART\n\t\tconst snare = new Tone.Player({\n\t\t\turl: \"https://tonejs.github.io/audio/drum-samples/CR78/snare.mp3\",\n\t\t\tfadeOut: 0.1\n\t\t}).chain(distortion, drumCompress);\n\n\t\tconst snarePart = new Tone.Sequence(((time, velocity) => {\n\t\t\tsnare.volume.value = Tone.gainToDb(velocity);\n\t\t\tsnare.start(time).stop(time + 0.1);\n\t\t}), [null, 1, null, [1, 0.3]], \"4n\").start(0);\n\n\t\tconst kick = new Tone.MembraneSynth({\n\t\t\tpitchDecay: 0.02,\n\t\t\toctaves: 6,\n\t\t\toscillator: {\n\t\t\t\ttype: \"square4\"\n\t\t\t},\n\t\t\tenvelope: {\n\t\t\t\tattack: 0.001,\n\t\t\t\tdecay: 0.2,\n\t\t\t\tsustain: 0\n\t\t\t}\n\t\t}).connect(drumCompress);\n\n\t\tconst kickPart = new Tone.Sequence(((time, probability) => {\n\t\t\tif (Math.random() < probability) {\n\t\t\t\tkick.triggerAttack(\"C1\", time);\n\t\t\t}\n\t\t}), [1, [1, [null, 0.3]], 1, [1, [null, 0.5]], 1, 1, 1, [1, [null, 0.8]]], \"2n\").start(0);\n\n\t\t// BASS\n\t\tconst bass = new Tone.FMSynth({\n\t\t\tharmonicity: 1,\n\t\t\tmodulationIndex: 3.5,\n\t\t\toscillator: {\n\t\t\t\ttype: \"custom\",\n\t\t\t\tpartials: [0, 1, 0, 2]\n\t\t\t},\n\t\t\tenvelope: {\n\t\t\t\tattack: 0.08,\n\t\t\t\tdecay: 0.3,\n\t\t\t\tsustain: 0,\n\t\t\t},\n\t\t\tmodulation: {\n\t\t\t\ttype: \"square\"\n\t\t\t},\n\t\t\tmodulationEnvelope: {\n\t\t\t\tattack: 0.1,\n\t\t\t\tdecay: 0.2,\n\t\t\t\tsustain: 0.3,\n\t\t\t\trelease: 0.01\n\t\t\t},\n\t\t}).toDestination();\n\n\t\tconst bassPart = new Tone.Part(((time, event) => {\n\t\t\tif (Math.random() < event.prob) {\n\t\t\t\tbass.triggerAttackRelease(event.note, event.dur, time);\n\t\t\t}\n\t\t}), [{ time: \"0:0\", note: \"C2\", dur: \"4n.\", prob: 1 }, { time: \"0:2\", note: \"C2\", dur: \"8n\", prob: 0.6 },\n\t\t\t{ time: \"0:2.6666\", note: \"C2\", dur: \"8n\", prob: 0.4 }, { time: \"0:3.33333\", note: \"C2\", dur: \"8n\", prob: 0.9 },\n\t\t\t{ time: \"1:0\", note: \"C2\", dur: \"4n.\", prob: 1 }, { time: \"1:2\", note: \"C2\", dur: \"8n\", prob: 0.6 },\n\t\t\t{ time: \"1:2.6666\", note: \"C2\", dur: \"8n\", prob: 0.4 }, { time: \"1:3.33333\", note: \"E2\", dur: \"8n\", prob: 0.9 },\n\t\t\t{ time: \"2:0\", note: \"F2\", dur: \"4n.\", prob: 1 }, { time: \"2:2\", note: \"F2\", dur: \"8n\", prob: 0.6 },\n\t\t\t{ time: \"2:2.6666\", note: \"F2\", dur: \"8n\", prob: 0.4 }, { time: \"2:3.33333\", note: \"F2\", dur: \"8n\", prob: 0.9 },\n\t\t\t{ time: \"3:0\", note: \"F2\", dur: \"4n.\", prob: 1 }, { time: \"3:2\", note: \"F2\", dur: \"8n\", prob: 0.6 },\n\t\t\t{ time: \"3:2.6666\", note: \"F2\", dur: \"8n\", prob: 0.4 }, { time: \"3:3.33333\", note: \"B1\", dur: \"8n\", prob: 0.9 }]).start(0);\n\n\t\tbassPart.loop = true;\n\t\tbassPart.loopEnd = \"4m\";\n\n\t\t// SYNTH\n\t\tconst synth = new Tone.DuoSynth({\n\t\t\tvibratoAmount: 0.5,\n\t\t\tvibratoRate: 5,\n\t\t\tportamento: 0.1,\n\t\t\tharmonicity: 1.005,\n\t\t\tvolume: 5,\n\t\t\tvoice0: {\n\t\t\t\toscillator: {\n\t\t\t\t\ttype: \"sawtooth\"\n\t\t\t\t},\n\t\t\t\tfilter: {\n\t\t\t\t\tQ: 1,\n\t\t\t\t\ttype: \"lowpass\",\n\t\t\t\t\trolloff: -24\n\t\t\t\t},\n\t\t\t\tenvelope: {\n\t\t\t\t\tattack: 0.01,\n\t\t\t\t\tdecay: 0.25,\n\t\t\t\t\tsustain: 0.4,\n\t\t\t\t\trelease: 1.2\n\t\t\t\t},\n\t\t\t\tfilterEnvelope: {\n\t\t\t\t\tattack: 0.001,\n\t\t\t\t\tdecay: 0.05,\n\t\t\t\t\tsustain: 0.3,\n\t\t\t\t\trelease: 2,\n\t\t\t\t\tbaseFrequency: 100,\n\t\t\t\t\toctaves: 4\n\t\t\t\t}\n\t\t\t},\n\t\t\tvoice1: {\n\t\t\t\toscillator: {\n\t\t\t\t\ttype: \"sawtooth\"\n\t\t\t\t},\n\t\t\t\tfilter: {\n\t\t\t\t\tQ: 2,\n\t\t\t\t\ttype: \"bandpass\",\n\t\t\t\t\trolloff: -12\n\t\t\t\t},\n\t\t\t\tenvelope: {\n\t\t\t\t\tattack: 0.25,\n\t\t\t\t\tdecay: 4,\n\t\t\t\t\tsustain: 0.1,\n\t\t\t\t\trelease: 0.8\n\t\t\t\t},\n\t\t\t\tfilterEnvelope: {\n\t\t\t\t\tattack: 0.05,\n\t\t\t\t\tdecay: 0.05,\n\t\t\t\t\tsustain: 0.7,\n\t\t\t\t\trelease: 2,\n\t\t\t\t\tbaseFrequency: 5000,\n\t\t\t\t\toctaves: -1.5\n\t\t\t\t}\n\t\t\t}\n\t\t}).toDestination();\n\n\t\tconst synthNotes = [\"C2\", \"E2\", \"G2\", \"A2\",\n\t\t\t\"C3\", \"D3\", \"E3\", \"G3\", \"A3\", \"B3\",\n\t\t\t\"C4\", \"D4\", \"E4\", \"G4\", \"A4\", \"B4\", \"C5\"];\n\n\t\tTone.Transport.bpm.value = 125;\n\n\t\tfunction move({ x, y }) {\n\t\t\t// use the x and y values to set the note and vibrato\n\t\t\tconst note = synthNotes[Math.round(x * (synthNotes.length - 1))];\n\t\t\tsynth.setNote(note);\n\t\t\tsynth.vibratoAmount.value = y;\n\t\t}\n\n\t\tfunction triggerAttack({ x, y }) {\n\t\t\t// use the x and y values to set the note and vibrato\n\t\t\tconst note = synthNotes[Math.round(x * (synthNotes.length - 1))];\n\t\t\tsynth.triggerAttack(note);\n\t\t\tsynth.vibratoAmount.value = y;\n\t\t}\n\n\t\tconst drwr = drawer({\n\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\topen: false,\n\t\t});\n\n\t\tdrwr.folder({\n\t\t\tname: \"Drums\"\n\t\t}).add({\n\t\t\ttone: hats,\n\t\t\tname: \"Hats\"\n\t\t}).add({\n\t\t\ttone: kick,\n\t\t\tname: \"Kick\"\n\t\t}).add({\n\t\t\ttone: snare,\n\t\t\tname: \"Snare\"\n\t\t}).add({\n\t\t\ttone: drumCompress,\n\t\t\tname: \"Compressor\"\n\t\t}).add({\n\t\t\ttone: distortion,\n\t\t\tname: \"Distortion\"\n\t\t});\n\n\t\tdrwr.folder({\n\t\t\tname: \"Synths\"\n\t\t}).add({\n\t\t\ttone: bass,\n\t\t\tname: \"Bass\"\n\t\t}).add({\n\t\t\ttone: synth,\n\t\t\tname: \"Synth\"\n\t\t});\n\n\t\t// @ts-ignore\n\t\tdocument.querySelector(\"tone-slider-pad\").addEventListener(\"move\", e => move(e.detail));\n\t\t// @ts-ignore\n\t\tdocument.querySelector(\"tone-slider-pad\").addEventListener(\"down\", e => triggerAttack(e.detail));\n\t\tdocument.querySelector(\"tone-slider-pad\").addEventListener(\"up\", () => synth.triggerRelease());\n\n\t\tdocument.querySelector(\"tone-play-toggle\").addEventListener(\"start\", () => Tone.Transport.start());\n\t\tdocument.querySelector(\"tone-play-toggle\").addEventListener(\"stop\", () => Tone.Transport.stop());\n\t</script>\n</body>\n</html>\n"
  },
  {
    "path": "examples/signal.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Signal</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t\t<style type=\"text/css\">\n\t\t\ttone-play-toggle {\n\t\t\t\tmargin-bottom: 10px;\n\t\t\t}\n\t\t\ttone-slider {\n\t\t\t\tdisplay: block;\n\t\t\t\twidth: 100%;\n\t\t\t}\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<tone-example label=\"Control Voltage\">\n\t\t\t<div slot=\"explanation\">\n\t\t\t\tOne of the most powerful features of Tone.js and the Web Audio\n\t\t\t\tAPI is the ability to perform math and logic on audio-rate\n\t\t\t\tsignal. Signals can be ramped and scheduled to control Audio\n\t\t\t\tParameters and other Signals making it simple to create\n\t\t\t\telaborate, interconnected automations.\n\t\t\t\t<br /><br />\n\t\t\t\tThis example applies a series of mappings to a signal value and\n\t\t\t\tapplies the results of those mappings to the frequency attribute\n\t\t\t\tof 2\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/Oscillator\"\n\t\t\t\t\t>Tone.Oscillators</a\n\t\t\t\t>\n\t\t\t\tand a\n\t\t\t\t<a href=\"https://tonejs.github.io/docs/latest/classes/LFO\"\n\t\t\t\t\t>Tone.LFO</a\n\t\t\t\t>.\n\t\t\t</div>\n\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t\t\t<tone-slider\n\t\t\t\t\tlabel=\"Modulation Rate\"\n\t\t\t\t\tmin=\"0.1\"\n\t\t\t\t\tmax=\"1\"\n\t\t\t\t\texp=\"2\"\n\t\t\t\t\tvalue=\"0.5\"\n\t\t\t\t></tone-slider>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\t// use this to pan the two oscillators hard left/right\n\t\t\tconst merge = new Tone.Merge().toDestination();\n\n\t\t\t// two oscillators panned hard left / hard right\n\t\t\tconst rightOsc = new Tone.Oscillator({\n\t\t\t\ttype: \"sawtooth\",\n\t\t\t\tvolume: -20,\n\t\t\t}).connect(merge, 0, 0);\n\n\t\t\tconst leftOsc = new Tone.Oscillator({\n\t\t\t\ttype: \"square\",\n\t\t\t\tvolume: -20,\n\t\t\t}).connect(merge, 0, 1);\n\n\t\t\t// create an oscillation that goes from 0 to 1200\n\t\t\t// connection it to the detune of the two oscillators\n\t\t\tconst detuneLFO = new Tone.LFO({\n\t\t\t\ttype: \"square\",\n\t\t\t\tmin: 0,\n\t\t\t\tmax: 1200,\n\t\t\t})\n\t\t\t\t.fan(rightOsc.detune, leftOsc.detune)\n\t\t\t\t.start();\n\n\t\t\t// the frequency signal\n\t\t\tconst frequency = new Tone.Signal(0.5);\n\n\t\t\t// the move the 0 to 1 value into frequency range\n\t\t\tconst scale = new Tone.ScaleExp(110, 440);\n\n\t\t\t// multiply the frequency by 2.5 to get a 10th above\n\t\t\tconst mult = new Tone.Multiply(2.5);\n\n\t\t\t// chain the components together\n\t\t\tfrequency.chain(scale, mult);\n\t\t\tscale.connect(rightOsc.frequency);\n\t\t\tmult.connect(leftOsc.frequency);\n\n\t\t\t// multiply the frequency by 2 to get the octave above\n\t\t\tconst detuneScale = new Tone.Scale(14, 4);\n\t\t\tfrequency.chain(detuneScale, detuneLFO.frequency);\n\n\t\t\t// start the oscillators with the play button\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"start\", () => {\n\t\t\t\t\trightOsc.start();\n\t\t\t\t\tleftOsc.start();\n\t\t\t\t});\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"stop\", () => {\n\t\t\t\t\trightOsc.stop();\n\t\t\t\t\tleftOsc.stop();\n\t\t\t\t});\n\n\t\t\t// ramp the frequency with the slider\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-slider\")\n\t\t\t\t.addEventListener(\"input\", (e) => {\n\t\t\t\t\tfrequency.rampTo(parseFloat(e.target.value), 0.1);\n\t\t\t\t});\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/simpleHtml.html",
    "content": "<!DOCTYPE HTML>\n<html>\n\t<head>\t\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Simple HTML</title>\n\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\t\t<!-- LOAD Tone.js from unpkg -->\n\t\t<script src=\"https://unpkg.com/tone\"></script>\n\t\t<script>\n\t\t\tfunction playNote() {\n\t\t\t\t// create a synth\n\t\t\t\tconst synth = new Tone.Synth().toDestination();\n\t\t\t\t// play a note from that synth\n\t\t\t\tsynth.triggerAttackRelease(\"C4\", \"8n\");\n\t\t\t}\n\t\t</script>\n\n\t</head>\n\t<body>\n\t\t<h1>Simple HTML5 Tone.js Demo</h1>\n\t\t<button onclick=\"playNote()\">Click me to play note!</button>\n\t</body>\n</html>\n\n"
  },
  {
    "path": "examples/simpleSynth.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Synth</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t</head>\n\t<body>\n\t\t<style>\n\t\t\ttone-piano {\n\t\t\t\tmargin-bottom: 10px;\n\t\t\t}\n\t\t</style>\n\t\t<tone-example label=\"Synth\">\n\t\t\t<div slot=\"explanation\">\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/Synth\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t>Tone.Synth</a\n\t\t\t\t>\n\t\t\t\tis composed simply of a\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/OmniOscillator\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t>Tone.OmniOscillator</a\n\t\t\t\t>\n\t\t\t\trouted through a\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/classes/AmplitudeEnvelope\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t>Tone.AmplitudeEnvelope</a\n\t\t\t\t>.\n\t\t\t</div>\n\n\t\t\t<div id=\"content\"></div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\tconst synth = new Tone.Synth({\n\t\t\t\toscillator: {\n\t\t\t\t\ttype: \"amtriangle\",\n\t\t\t\t\tharmonicity: 0.5,\n\t\t\t\t\tmodulationType: \"sine\",\n\t\t\t\t},\n\t\t\t\tenvelope: {\n\t\t\t\t\tattackCurve: \"exponential\",\n\t\t\t\t\tattack: 0.05,\n\t\t\t\t\tdecay: 0.2,\n\t\t\t\t\tsustain: 0.2,\n\t\t\t\t\trelease: 1.5,\n\t\t\t\t},\n\t\t\t\tportamento: 0.05,\n\t\t\t}).toDestination();\n\n\t\t\tpiano({\n\t\t\t\ttone: synth,\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t\tnoteon: (note) => synth.triggerAttack(note.name),\n\t\t\t\tnoteoff: (note) => synth.triggerRelease(),\n\t\t\t});\n\n\t\t\tui({\n\t\t\t\ttone: synth,\n\t\t\t\tname: \"Synth\",\n\t\t\t\tparent: document.querySelector(\"#content\"),\n\t\t\t});\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/spatialPanner.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n\t<title>Panner3d</title>\n\n\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\">\n\t<link rel=\"icon\" type=\"image/png\" sizes=\"174x174\" href=\"./favicon.png\">\n\n\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t<link href=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\" rel=\"stylesheet\"/>\n\t<script src=\"../build/Tone.js\"></script>\n\t<script src=\"./js/tone-ui.js\"></script>\n\t<script src=\"./js/components.js\"></script>\n\n\t<style type=\"text/css\">\n\t\ttone-play-toggle {\n\t\t\tmargin-bottom: 10px;\n\t\t}\n\t</style>\n</head>\n<body>\n\t<tone-example label=\"3D Panning\">\n\t\t<tone-loader></tone-loader>\n\t\t<div slot=\"explanation\">\n\t\t\tTone.Panner3D and Tone.Listener work together to create 3D audio. Connect your synths and sources to Panner3D and then to the master output, anything you connect to the panner will be spatialized according the position of the panner relative to the position of the listener. This example synchronizes the position of the camera with Tone.Listener and the position of each of the spheres with a track.\n\t\t\t<br><br>\n\t\t\tNote: the 3D panning effect is more effective with headphones.\n\t\t</div>\n\n\t\t<div id=\"content\">\n\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t\t<tone-slider \n\t\t\t\tlabel=\"x\"\n\t\t\t\tid=\"xSlider\"\n\t\t\t\tmin=\"-2\"\n\t\t\t\tmax=\"2\"\n\t\t\t\tvalue=\"0\"\n\t\t\t></tone-slider>\n\t\t\t<tone-slider \n\t\t\t\tid=\"zSlider\"\n\t\t\t\tlabel=\"z\"\n\t\t\t\tmin=\"-2\"\n\t\t\t\tmax=\"2\"\n\t\t\t\tvalue=\"0\"\n\t\t\t></tone-slider>\n\t\t\t<tone-slider \n\t\t\t\tid=\"rotation\"\n\t\t\t\tlabel=\"rotation\"\n\t\t\t\tmin=\"0\"\n\t\t\t\tmax=\"6.28\"\n\t\t\t\tvalue=\"0\"\n\t\t\t\tunits=\"rad\"\n\t\t\t></tone-slider>\n\t\t</div>\n\t</tone-example>\n\n\t<script type=\"text/javascript\">\n\t\tfunction createPlayerPlusPanner(url, positionX, positionY, positionZ) {\n\t\t\tconst panner = new Tone.Panner3D({\n\t\t\t\tpanningModel: \"HRTF\",\n\t\t\t\tpositionX,\n\t\t\t\tpositionY,\n\t\t\t\tpositionZ,\n\t\t\t}).toDestination();\n\n\t\t\tconst player = new Tone.Player({\n\t\t\t\turl,\n\t\t\t\tloop: true,\n\t\t\t}).connect(panner).sync().start(0);\n\t\t}\n\t\tcreatePlayerPlusPanner(\"https://tonejs.github.io/audio/berklee/taps_1c.mp3\", 2, 0, 0);\n\t\tcreatePlayerPlusPanner(\"https://tonejs.github.io/audio/berklee/tinkle3.mp3\", 0, 0, 2);\n\t\tcreatePlayerPlusPanner(\"https://tonejs.github.io/audio/berklee/tapping1.mp3\", -2, 0, 2);\n\t\tcreatePlayerPlusPanner(\"https://tonejs.github.io/audio/berklee/thump1.mp3\", -2, 0, -2);\n\n\t\tdocument.querySelector(\"tone-play-toggle\").addEventListener(\"start\", () => Tone.Transport.start());\n\t\tdocument.querySelector(\"tone-play-toggle\").addEventListener(\"stop\", () => Tone.Transport.stop());\n\t\t\n\t\tfunction setRotation(angle) {\n\t\t\tTone.Listener.forwardX.value = Math.sin(angle);\n\t\t\tTone.Listener.forwardY.value = 0;\n\t\t\tTone.Listener.forwardZ.value = -Math.cos(angle);\n\t\t}\n\n\t\tdocument.querySelector(\"#xSlider\").addEventListener(\"input\", (e) => Tone.Listener.positionX.value = parseFloat(e.target.value));\n\t\tdocument.querySelector(\"#zSlider\").addEventListener(\"input\", (e) => Tone.Listener.positionY.value = parseFloat(e.target.value));\n\t\tdocument.querySelector(\"#rotation\").addEventListener(\"input\", (e) => setRotation(parseFloat(e.target.value)));\n\n\t</script>\n\n\t</style>\n</body>\n</html>\n"
  },
  {
    "path": "examples/stepSequencer.html",
    "content": "<!doctype html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Step Sequencer</title>\n\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1\"\n\t\t/>\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\ttype=\"image/png\"\n\t\t\tsizes=\"174x174\"\n\t\t\thref=\"./favicon.png\"\n\t\t/>\n\n\t\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js\"></script>\n\t\t<link\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Material+Icons&display=block\"\n\t\t\trel=\"stylesheet\"\n\t\t/>\n\t\t<script src=\"../build/Tone.js\"></script>\n\t\t<script src=\"./js/tone-ui.js\"></script>\n\t\t<script src=\"./js/components.js\"></script>\n\t\t<style type=\"text/css\">\n\t\t\ttone-transport {\n\t\t\t\tmargin-bottom: 10px;\n\t\t\t}\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<tone-example label=\"Step Sequencer\">\n\t\t\t<tone-loader></tone-loader>\n\t\t\t<div slot=\"explanation\">\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://tonejs.github.io/docs/latest/functions/getTransport.html\"\n\t\t\t\t\t>Tone.Transport</a\n\t\t\t\t>\n\t\t\t\tis the application-wide timekeeper. Its clock source enables\n\t\t\t\tsample-accurate scheduling as well as tempo-curves and\n\t\t\t\tautomation. This example uses Tone.Sequence to invoke a callback\n\t\t\t\tevery 16th note.\n\t\t\t</div>\n\n\t\t\t<div id=\"content\">\n\t\t\t\t<tone-play-toggle></tone-play-toggle>\n\t\t\t\t<tone-slider\n\t\t\t\t\tlabel=\"tempo\"\n\t\t\t\t\tunits=\"bpm\"\n\t\t\t\t\tmin=\"60\"\n\t\t\t\t\tmax=\"240\"\n\t\t\t\t\tvalue=\"120\"\n\t\t\t\t></tone-slider>\n\t\t\t\t<tone-step-sequencer></tone-step-sequencer>\n\t\t\t</div>\n\t\t</tone-example>\n\n\t\t<script type=\"text/javascript\">\n\t\t\tconst keys = new Tone.Players({\n\t\t\t\turls: {\n\t\t\t\t\t0: \"A1.mp3\",\n\t\t\t\t\t1: \"Cs2.mp3\",\n\t\t\t\t\t2: \"E2.mp3\",\n\t\t\t\t\t3: \"Fs2.mp3\",\n\t\t\t\t},\n\t\t\t\tfadeOut: \"64n\",\n\t\t\t\tbaseUrl: \"https://tonejs.github.io/audio/casio/\",\n\t\t\t}).toDestination();\n\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"start\", () => Tone.Transport.start());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-play-toggle\")\n\t\t\t\t.addEventListener(\"stop\", () => Tone.Transport.stop());\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-slider\")\n\t\t\t\t.addEventListener(\n\t\t\t\t\t\"input\",\n\t\t\t\t\t(e) =>\n\t\t\t\t\t\t(Tone.Transport.bpm.value = parseFloat(e.target.value))\n\t\t\t\t);\n\t\t\tdocument\n\t\t\t\t.querySelector(\"tone-step-sequencer\")\n\t\t\t\t.addEventListener(\"trigger\", ({ detail }) => {\n\t\t\t\t\tkeys.player(detail.row).start(detail.time, 0, \"16t\");\n\t\t\t\t});\n\t\t</script>\n\t</body>\n</html>\n"
  },
  {
    "path": "package.json",
    "content": "{\n\t\"name\": \"tone\",\n\t\"version\": \"15.5.0\",\n\t\"description\": \"A Web Audio framework for making interactive music in the browser.\",\n\t\"type\": \"module\",\n\t\"main\": \"build/esm/index.js\",\n\t\"module\": \"build/esm/index.js\",\n\t\"types\": \"build/esm/index.d.ts\",\n\t\"unpkg\": \"build/Tone.js\",\n\t\"files\": [\n\t\t\"README.md\",\n\t\t\"LICENSE.md\",\n\t\t\"build\",\n\t\t\"docs\",\n\t\t\"Tone\"\n\t],\n\t\"scripts\": {\n\t\t\"remove\": \"node -e \\\"fs.rmSync('./build', { recursive: true, force: true })\\\"\",\n\t\t\"build\": \"npm run increment && npm run remove && npm run ts:build && npm run webpack:build\",\n\t\t\"docs:json\": \"typedoc --options \\\"./scripts/typedoc.json\\\" --json \\\"./docs/tone.json\\\"\",\n\t\t\"increment\": \"node scripts/increment_version.cjs\",\n\t\t\"lint\": \"tsc --noEmit && eslint ./Tone\",\n\t\t\"lint:fix\": \"tsc --noEmit && eslint ./Tone ./test --fix\",\n\t\t\"pretty\": \"prettier ./Tone ./test -w\",\n\t\t\"scratch\": \"webpack serve --env scratch=1 --mode=development --config ./scripts/webpack.config.cjs\",\n\t\t\"spellcheck\": \"cspell --config ./scripts/cspell.json ./Tone ./test/**/*.ts ./examples/**/*.html\",\n\t\t\"test\": \"tsc && web-test-runner --config=./test/web-test-runner.config.js --coverage ${npm_config_group:+--group ${npm_config_group}}\",\n\t\t\"test:examples\": \"node ./test/scripts/test_examples.mjs\",\n\t\t\"test:html\": \"node ./test/scripts/test_html.mjs\",\n\t\t\"test:integrations\": \"zx ./test/scripts/test_integrations.mjs\",\n\t\t\"test:readme\": \"node ./test/scripts/test_readme.mjs\",\n\t\t\"test:watch\": \"tsc && concurrently --raw \\\"tsc -w\\\" \\\"web-test-runner --config=./test/web-test-runner.config.js --watch ${npm_config_group:+--group ${npm_config_group}}\\\"\",\n\t\t\"ts:build\": \"tsc --project ./scripts/tsconfig.build.json\",\n\t\t\"watch\": \"tsc --watch\",\n\t\t\"webpack:build\": \"webpack --env production=1 --config ./scripts/webpack.config.cjs\"\n\t},\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/Tonejs/Tone.js.git\"\n\t},\n\t\"keywords\": [\n\t\t\"Web Audio\",\n\t\t\"Web Audio API\",\n\t\t\"Synthesis\",\n\t\t\"Playback\",\n\t\t\"Effect\",\n\t\t\"Instrument\",\n\t\t\"DSP\",\n\t\t\"Signal Processing\",\n\t\t\"Interactive Music\"\n\t],\n\t\"author\": \"Yotam Mann (https://yotammann.info/)\",\n\t\"license\": \"MIT\",\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/Tonejs/Tone.js/issues\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@rollup/plugin-commonjs\": \"^26.0.3\",\n\t\t\"@stylistic/eslint-plugin-js\": \"^4.2.0\",\n\t\t\"@stylistic/eslint-plugin-ts\": \"^4.2.0\",\n\t\t\"@types/chai\": \"^4.3.0\",\n\t\t\"@types/mocha\": \"^5.2.6\",\n\t\t\"@types/sinon\": \"^21.0.0\",\n\t\t\"@types/sinon-chai\": \"^4.0.0\",\n\t\t\"@types/ua-parser-js\": \"^0.7.36\",\n\t\t\"@web/dev-server-esbuild\": \"^1.0.2\",\n\t\t\"@web/dev-server-rollup\": \"^0.6.1\",\n\t\t\"@web/test-runner\": \"^0.20.0\",\n\t\t\"@web/test-runner-puppeteer\": \"^0.18.0\",\n\t\t\"array2d\": \"^0.0.5\",\n\t\t\"audiobuffer-to-wav\": \"^1.0.0\",\n\t\t\"chai\": \"^5.1.0\",\n\t\t\"codecov\": \"^3.8.3\",\n\t\t\"concurrently\": \"^8.2.2\",\n\t\t\"cspell\": \"^9.0.2\",\n\t\t\"eslint\": \"^9.25.1\",\n\t\t\"eslint-plugin-html\": \"^8.1.2\",\n\t\t\"eslint-plugin-jsdoc\": \"^50.6.11\",\n\t\t\"eslint-plugin-simple-import-sort\": \"^12.1.1\",\n\t\t\"eslint-plugin-unused-imports\": \"^4.1.4\",\n\t\t\"fft-windowing\": \"^0.1.4\",\n\t\t\"fourier-transform\": \"^1.1.2\",\n\t\t\"fs-fixture\": \"^2.7.1\",\n\t\t\"html-webpack-plugin\": \"^5.6.3\",\n\t\t\"http-server\": \"^13.0.2\",\n\t\t\"jsdom\": \"^26.1.0\",\n\t\t\"marked\": \"^15.0.12\",\n\t\t\"mocha\": \"^11.1.0\",\n\t\t\"plotly.js-dist\": \"^2.32.0\",\n\t\t\"prettier\": \"^3.2.5\",\n\t\t\"puppeteer\": \"^24.2.1\",\n\t\t\"semver\": \"^5.7.1\",\n\t\t\"sinon\": \"^21.0.0\",\n\t\t\"sinon-chai\": \"^4.0.1\",\n\t\t\"teoria\": \"^2.5.0\",\n\t\t\"tinyglobby\": \"^0.2.14\",\n\t\t\"tonal\": \"^6.0.1\",\n\t\t\"ts-loader\": \"^9.5.1\",\n\t\t\"typedoc\": \"^0.28.12\",\n\t\t\"typescript\": \"^5.4.5\",\n\t\t\"typescript-eslint\": \"^8.31.0\",\n\t\t\"ua-parser-js\": \"^0.7.31\",\n\t\t\"webpack\": \"^5.91.0\",\n\t\t\"webpack-cli\": \"^5.1.4\",\n\t\t\"webpack-dev-server\": \"^5.2.0\",\n\t\t\"yargs\": \"^17.3.0\",\n\t\t\"zx\": \"^8.0.2\"\n\t},\n\t\"dependencies\": {\n\t\t\"standardized-audio-context\": \"^25.3.70\",\n\t\t\"tslib\": \"^2.3.1\"\n\t},\n\t\"prettier\": {\n\t\t\"trailingComma\": \"es5\",\n\t\t\"tabWidth\": 4,\n\t\t\"semi\": true,\n\t\t\"useTabs\": true,\n\t\t\"singleQuote\": false\n\t},\n\t\"publishConfig\": {\n\t\t\"provenance\": true\n\t}\n}\n"
  },
  {
    "path": "scripts/cspell.json",
    "content": "{\n\t\"version\": \"0.2\",\n\t\"language\": \"en\",\n\t\"ignoreWords\": [\n\t\t\"abbb\",\n\t\t\"adsr\",\n\t\t\"amcustom\",\n\t\t\"ampltiude\",\n\t\t\"amsawtooth\",\n\t\t\"amsine\",\n\t\t\"amsquare\",\n\t\t\"amtriangle\",\n\t\t\"arpeggiates\",\n\t\t\"autofilter\",\n\t\t\"automatable\",\n\t\t\"automations\",\n\t\t\"autopanner\",\n\t\t\"autowah\",\n\t\t\"bembe\",\n\t\t\"cbbb\",\n\t\t\"ccrma\",\n\t\t\"cheby\",\n\t\t\"chebyshev\",\n\t\t\"chowning\",\n\t\t\"crossfading\",\n\t\t\"dbbb\",\n\t\t\"detuned\",\n\t\t\"detunes\",\n\t\t\"drwr\",\n\t\t\"drywet\",\n\t\t\"ebbb\",\n\t\t\"etienne\",\n\t\t\"fatcustom\",\n\t\t\"fatsawtooth\",\n\t\t\"fatsine\",\n\t\t\"fatsquare\",\n\t\t\"fattriangle\",\n\t\t\"fbbb\",\n\t\t\"fbcf\",\n\t\t\"fmcustom\",\n\t\t\"fmsawtooth\",\n\t\t\"fmsine\",\n\t\t\"fmsquare\",\n\t\t\"fmtriangle\",\n\t\t\"freeverb\",\n\t\t\"freqs\",\n\t\t\"ftom\",\n\t\t\"ftomf\",\n\t\t\"fwdl\",\n\t\t\"gbbb\",\n\t\t\"halen\",\n\t\t\"harmonicity\",\n\t\t\"hihat\",\n\t\t\"inharm\",\n\t\t\"karplus\",\n\t\t\"kvraudio\",\n\t\t\"lespinasse\",\n\t\t\"lfcf\",\n\t\t\"lfpf\",\n\t\t\"loopable\",\n\t\t\"lpcf\",\n\t\t\"matos\",\n\t\t\"millis\",\n\t\t\"monosynth\",\n\t\t\"mtof\",\n\t\t\"mult\",\n\t\t\"multiband\",\n\t\t\"niemitalo\",\n\t\t\"nontype\",\n\t\t\"nosuchfile\",\n\t\t\"noteoff\",\n\t\t\"noteon\",\n\t\t\"olli\",\n\t\t\"onsilence\",\n\t\t\"panners\",\n\t\t\"polyrhythmatic\",\n\t\t\"predelay\",\n\t\t\"pucket\",\n\t\t\"repitch\",\n\t\t\"repitches\",\n\t\t\"repitching\",\n\t\t\"santell\",\n\t\t\"sched\",\n\t\t\"schedulable\",\n\t\t\"spatialized\",\n\t\t\"stackoverflow\",\n\t\t\"startable\",\n\t\t\"subarrays\",\n\t\t\"subdiv\",\n\t\t\"supersaw\",\n\t\t\"thresholded\",\n\t\t\"tonejs\",\n\t\t\"unloops\",\n\t\t\"unmutes\",\n\t\t\"unmuting\",\n\t\t\"unsolo\",\n\t\t\"unsoloed\",\n\t\t\"unsync\",\n\t\t\"unsyncing\",\n\t\t\"unsyncs\",\n\t\t\"vorbis\",\n\t\t\"waveshaper\",\n\t\t\"waveshaping\",\n\t\t\"worklets\",\n\t\t\"yotam\",\n\t\t\"𝑄𝑙𝑖𝑚\"\n\t],\n\t\"ignorePaths\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "scripts/increment_version.cjs",
    "content": "const { execSync } = require(\"node:child_process\");\nconst fs = require(\"node:fs\");\nconst { resolve } = require(\"node:path\");\n\nconst semver = require(\"semver\");\n\nconst tsVersion = execSync(\"npm show tone@next version\").toString();\nconst mainVersion = execSync(\"npm show tone version\").toString();\n\n// go with whichever is the latest version\nlet version = mainVersion;\nif (tsVersion && semver.gt(tsVersion, mainVersion)) {\n\tversion = tsVersion;\n}\n\n// increment the patch\nversion = semver.inc(version, \"patch\");\n\n// write it to the package.json\nconst packageFile = resolve(__dirname, \"../package.json\");\nconst packageObj = JSON.parse(fs.readFileSync(packageFile, \"utf-8\"));\n\n// if the package version if the latest, go with that one\nif (semver.gt(packageObj.version, version)) {\n\tversion = packageObj.version;\n}\n\nconsole.log(`incrementing to version ${version}`);\npackageObj.version = version;\n// only if it's travis, update the package.json\nif (process.env.GITHUB_CI) {\n\tfs.writeFileSync(packageFile, JSON.stringify(packageObj, undefined, \"  \"));\n\n\t// write a version file\n\tconst versionFile = `export const version: string = ${JSON.stringify(version)};\\n`;\n\tfs.writeFileSync(resolve(__dirname, \"../Tone/version.ts\"), versionFile);\n}\n\n"
  },
  {
    "path": "scripts/tsconfig.build.json",
    "content": "{\n\t\"compilerOptions\": {\n\t\t\"sourceMap\": true,\n\t\t\"declaration\": true,\n\t\t\"noUnusedLocals\": true,\n\t\t\"rootDir\": \"../Tone\"\n\t},\n\t\"extends\": \"../tsconfig.json\",\n\t\"include\": [\n\t\t\"../Tone/**/*.ts\"\n\t],\n\t\"exclude\": [\n\t\t\"../node_modules\",\n\t\t\"../Tone/**/*.test.ts\",\n\t\t\"../test/**/*.ts\"\n\t]\n}"
  },
  {
    "path": "scripts/typedoc.json",
    "content": "{\n\t\"name\": \"Tone.js\",\n\t\"entryPoints\": [\"../Tone\"],\n\t\"out\": \"../docs\",\n\t\"defaultCategory\": \"Global\",\n\t\"categorizeByGroup\": true,\n\t\"categoryOrder\": [\n\t\t\"Core\",\n\t\t\"Source\",\n\t\t\"Instrument\",\n\t\t\"Effect\",\n\t\t\"Component\",\n\t\t\"Signal\"\n\t],\n\t\"navigation\": {\n\t\t\"includeCategories\": true,\n\t\t\"includeFolders\": false,\n\t\t\"includeGroups\": true\n\t},\n\t\"externalPattern\": [\"**/node_modules/**\"],\n\t\"excludeProtected\": true,\n\t\"excludePrivate\": true,\n\t\"hideGenerator\": true,\n\t\"includeVersion\": false,\n\t\"excludeInternal\": true\n}\n"
  },
  {
    "path": "scripts/webpack.config.cjs",
    "content": "const path = require(\"node:path\");\n\nconst HtmlWebpackPlugin = require(\"html-webpack-plugin\");\n\n// /////////////////////////////////////\n// Defaults\n// /////////////////////////////////////\n\nconst defaults = {\n\tmode: \"development\",\n\tcontext: __dirname,\n\tentry: {\n\t\tTone: \"../Tone/index.ts\",\n\t},\n\toutput: {\n\t\tpath: path.resolve(__dirname, \"../build\"),\n\t\tfilename: \"[name].js\",\n\t\tlibrary: \"Tone\",\n\t\tlibraryTarget: \"umd\",\n\t\tglobalObject: \"typeof self !== 'undefined' ? self : this\",\n\t},\n\tresolve: {\n\t\textensionAlias: {\n\t\t\t\".js\": [\".js\", \".ts\"],\n\t\t},\n\t},\n\tmodule: {\n\t\trules: [\n\t\t\t{\n\t\t\t\ttest: /\\.ts$/,\n\t\t\t\tuse: \"ts-loader\",\n\t\t\t\texclude: /(node_modules)/,\n\t\t\t},\n\t\t],\n\t},\n\tdevtool: \"cheap-source-map\",\n};\n\n// /////////////////////////////////////\n// Production\n// /////////////////////////////////////\n\nconst production = Object.assign({}, defaults, {\n\tmode: \"production\",\n\tdevtool: \"source-map\",\n});\n\n// /////////////////////////////////////\n// Scratch\n// create a file called examples/scratch.ts to test things out locally\n// /////////////////////////////////////\n\nconst scratch = Object.assign({}, defaults, {\n\tentry: {\n\t\tscratch: \"../examples/scratch.ts\",\n\t},\n\toutput: {\n\t\tpath: path.resolve(__dirname, \"../scratch\"),\n\t\tfilename: \"[name].js\",\n\t},\n\tdevtool: \"source-map\",\n\tplugins: [\n\t\tnew HtmlWebpackPlugin({\n\t\t\tfilename: \"index.html\",\n\t\t}),\n\t],\n\tdevServer: {\n\t\tstatic: {\n\t\t\tdirectory: path.join(__dirname, \"../scratch/\"),\n\t\t},\n\t\thot: true,\n\t\tport: 9000,\n\t},\n});\n\nmodule.exports = (env) => {\n\tif (env.test) {\n\t\treturn test;\n\t} else if (env.production) {\n\t\treturn production;\n\t} else if (env.scratch) {\n\t\treturn scratch;\n\t}\n};\n"
  },
  {
    "path": "test/README.md",
    "content": "Both Chrome and Firefox are required to run the run the full set of tests.\n\n## Basic\n\nTo run tests in both browsers headlessly and report the results:\n\n`npm run test`\n\n## Selective Testing\n\nTo test only individual directory:\n\n`npm run test --group=[core,component,effect,event,instrument,signal,source]`\n\nOr in watch mode:\n\n`npm run test:watch --group=[core,component,effect,event,instrument,signal,source]`\n"
  },
  {
    "path": "test/helper/Basic.ts",
    "content": "import \"../../Tone/core/clock/Transport.js\";\nimport \"../../Tone/core/context/Destination.js\";\n\nimport { expect } from \"chai\";\n\nimport * as Classes from \"../../Tone/classes.js\";\nimport { createAudioContext } from \"../../Tone/core/context/AudioContext.js\";\nimport { OfflineContext } from \"../../Tone/core/context/OfflineContext.js\";\nimport { ToneAudioNode } from \"../../Tone/core/context/ToneAudioNode.js\";\nimport { ToneWithContext } from \"../../Tone/core/context/ToneWithContext.js\";\nimport { getContext, setContext } from \"../../Tone/core/Global.js\";\nimport { Tone } from \"../../Tone/core/Tone.js\";\nimport { setLogger } from \"../../Tone/core/util/Debug.js\";\nimport { noOp } from \"../../Tone/core/util/Interface.js\";\nimport { isFunction } from \"../../Tone/core/util/TypeCheck.js\";\nimport { ConnectTest } from \"./Connect.js\";\n\nexport const testAudioContext = new OfflineContext(1, 1, 11025);\n\nexport function BasicTests(Constr, ...args: any[]): void {\n\tcontext(\"Basic\", () => {\n\t\tbefore(() => {\n\t\t\treturn getContext().resume();\n\t\t});\n\n\t\tit(\"can be created and disposed\", () => {\n\t\t\tconst instance = new Constr(...args);\n\t\t\tinstance.dispose();\n\t\t\t// check that all of the attributes were disposed\n\t\t\texpect(instance.disposed).to.equal(true);\n\t\t\t// also check all of its attributes to see if they also have the right context\n\t\t\tfor (const member in instance) {\n\t\t\t\tif (instance[member] instanceof Tone && member !== \"context\") {\n\t\t\t\t\texpect(\n\t\t\t\t\t\tinstance[member].disposed,\n\t\t\t\t\t\t`member ${member}`\n\t\t\t\t\t).to.equal(true);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// check that all callback functions are assigned to noOp\n\t\t\tfor (const member in instance) {\n\t\t\t\tif (isFunction(instance[member]) && member.startsWith(\"on\")) {\n\t\t\t\t\texpect(instance[member]).to.equal(noOp);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tit(\"extends Tone\", () => {\n\t\t\tconst instance = new Constr(...args);\n\t\t\texpect(instance).to.be.an.instanceof(Tone);\n\t\t\tinstance.dispose();\n\t\t});\n\n\t\tit(\"can specify the AudioContext\", () => {\n\t\t\tconst instance = new Constr(\n\t\t\t\tObject.assign(\n\t\t\t\t\t{\n\t\t\t\t\t\tcontext: testAudioContext,\n\t\t\t\t\t},\n\t\t\t\t\t...args\n\t\t\t\t)\n\t\t\t);\n\t\t\tif (instance instanceof ToneWithContext) {\n\t\t\t\texpect(instance.context).to.equal(testAudioContext);\n\t\t\t\t// also check all of its attributes to see if they also have the right context\n\t\t\t\tfor (const member in instance) {\n\t\t\t\t\tif (instance[member] instanceof ToneWithContext) {\n\t\t\t\t\t\texpect(\n\t\t\t\t\t\t\tinstance[member].context,\n\t\t\t\t\t\t\t`member: ${member}`\n\t\t\t\t\t\t).to.equal(testAudioContext);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tinstance.dispose();\n\t\t});\n\n\t\tit(\"can be serialized to JSON\", () => {\n\t\t\tconst instance = new Constr(...args);\n\t\t\tif (instance instanceof ToneAudioNode) {\n\t\t\t\tconst json = instance.get();\n\t\t\t\t// this throws an error if the object is recursive\n\t\t\t\tJSON.stringify(json);\n\t\t\t}\n\t\t});\n\n\t\tConnectTest(Constr, ...args);\n\t});\n\n\tit(\"exports its class name\", () => {\n\t\t// find the constructor\n\t\tfor (const className in Classes) {\n\t\t\tif (Classes[className] === Constr) {\n\t\t\t\tconst instance = new Constr(...args);\n\t\t\t\texpect(instance.toString()).to.equal(className);\n\t\t\t\tinstance.dispose();\n\t\t\t}\n\t\t}\n\t});\n\n\tit(\"can be created in a suspended context and then resumed\", async () => {\n\t\tconst originalContext = getContext();\n\t\tconst audioContext = createAudioContext();\n\t\tawait audioContext.suspend();\n\t\tsetContext(audioContext, false);\n\t\tconst instance = new Constr(...args);\n\n\t\texpect(audioContext.state).to.equal(\"suspended\");\n\t\tawait audioContext.resume();\n\t\texpect(audioContext.state).to.equal(\"running\");\n\n\t\t// restore the original context\n\t\tinstance.dispose();\n\t\tsetContext(originalContext);\n\t\taudioContext.close();\n\t});\n}\n\n/**\n * Assert that the function triggers a warning\n */\nexport async function warns(fn: (...args: any[]) => any): Promise<void> {\n\tlet wasInvoked = false;\n\tsetLogger({\n\t\tlog: () => {},\n\t\twarn: () => (wasInvoked = true),\n\t});\n\tconst ret = fn();\n\tif (ret instanceof Promise) {\n\t\tawait ret;\n\t}\n\texpect(wasInvoked).to.equal(true);\n\t// return to the original logger\n\tsetLogger(console);\n}\n"
  },
  {
    "path": "test/helper/CompareToFile.ts",
    "content": "import { Context } from \"../../Tone/core/context/Context.js\";\nimport { Offline } from \"../../Tone/core/context/Offline.js\";\nimport { ToneAudioBuffer } from \"../../Tone/core/context/ToneAudioBuffer.js\";\nimport { Compare, TestAudioBuffer } from \"./compare/index.js\";\n\n/**\n * Load a file for comparison\n */\nasync function getBuffersToCompare(\n\tcallback: (context: Context) => Promise<void> | void,\n\tfilename: string,\n\tduration = 0.5,\n\tchannels = 1,\n\tsampleRate = 11025,\n\tforceRender = false\n): Promise<{ bufferA: TestAudioBuffer; bufferB: TestAudioBuffer } | void> {\n\tif (forceRender) {\n\t\tconst buffer = await Offline(callback, duration, channels, sampleRate);\n\t\tnew TestAudioBuffer(buffer).downloadWav(filename);\n\t} else {\n\t\tconst loadedBuffer = await ToneAudioBuffer.fromUrl(filename);\n\t\tconst bufferB = new TestAudioBuffer(loadedBuffer);\n\t\tconst renderedBuffer = await Offline(\n\t\t\tcallback,\n\t\t\tbufferB.duration,\n\t\t\tbufferB.numberOfChannels,\n\t\t\tbufferB.sampleRate\n\t\t);\n\t\tconst bufferA = new TestAudioBuffer(renderedBuffer);\n\t\treturn {\n\t\t\tbufferA,\n\t\t\tbufferB,\n\t\t};\n\t}\n}\n\n/**\n * Compare the output of the callback to a pre-rendered file\n */\nexport async function CompareToFile(\n\tcallback,\n\turl: string,\n\tthreshold = 0.001,\n\tRENDER_NEW = false,\n\tduration = 0.1,\n\tchannels = 1\n): Promise<void> {\n\turl = \"test/audio/compare/\" + url;\n\tconst response = await getBuffersToCompare(\n\t\tcallback,\n\t\turl,\n\t\tduration,\n\t\tchannels,\n\t\t44100,\n\t\tRENDER_NEW\n\t);\n\tif (response) {\n\t\tconst { bufferA, bufferB } = response;\n\t\tconst error = Compare.compareSpectra(bufferA, bufferB);\n\t\tif (error > threshold) {\n\t\t\tthrow new Error(\n\t\t\t\t`Error ${error} greater than threshold ${threshold}`\n\t\t\t);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "test/helper/Connect.ts",
    "content": "import { Gain } from \"../../Tone/core/context/Gain.js\";\n\nexport function connectFrom(): Gain {\n\treturn new Gain();\n}\n\nexport function connectTo(): Gain {\n\treturn new Gain();\n}\n\nexport function ConnectTest(constr, ...args: any[]): void {\n\tit(\"handles input and output connections\", () => {\n\t\tconst instance = new constr(...args);\n\t\t// test each of the input and outputs and connect\n\t\tif (instance.numberOfInputs) {\n\t\t\tfor (let input = 0; input < instance.numberOfInputs; input++) {\n\t\t\t\tconnectFrom().connect(instance, 0, input);\n\t\t\t}\n\t\t}\n\t\tif (instance.numberOfOutputs) {\n\t\t\tfor (let output = 0; output < instance.numberOfOutputs; output++) {\n\t\t\t\tinstance.connect(connectTo(), output, 0);\n\t\t\t}\n\t\t}\n\t\tinstance.dispose();\n\t});\n}\n"
  },
  {
    "path": "test/helper/ConstantOutput.ts",
    "content": "import { expect } from \"chai\";\n\nimport { OfflineContext } from \"../../Tone/core/context/OfflineContext.js\";\nimport { Offline } from \"./Offline.js\";\n\n/**\n * Test that the output of the callback is a constant value\n */\nexport async function ConstantOutput(\n\tcallback: (context: OfflineContext) => Promise<void> | void,\n\tvalue: number,\n\tthreshold = 0.01\n): Promise<void> {\n\tconst buffer = await Offline(callback, 0.01, 1);\n\texpect(buffer.value()).to.be.closeTo(value, threshold);\n}\n"
  },
  {
    "path": "test/helper/Dispose.ts",
    "content": "export function isDisposed(instance): void {\n\tfor (const prop in instance) {\n\t\tif (instance.hasOwnProperty(prop)) {\n\t\t\tconst member = instance[prop];\n\t\t\tif (\n\t\t\t\ttypeof member !== \"function\" &&\n\t\t\t\ttypeof member !== \"string\" &&\n\t\t\t\ttypeof member !== \"number\" &&\n\t\t\t\ttypeof member !== \"boolean\" &&\n\t\t\t\ttypeof member !== \"undefined\" &&\n\t\t\t\tprop !== \"preset\" &&\n\t\t\t\t!(member instanceof AudioContext)\n\t\t\t) {\n\t\t\t\tif (member !== null) {\n\t\t\t\t\tthrow Error(\n\t\t\t\t\t\t\"property was not completely disposed: \" + prop\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "test/helper/EffectTests.ts",
    "content": "import { expect } from \"chai\";\n\nimport { Signal } from \"../../Tone/signal/Signal.js\";\nimport { connectFrom, connectTo } from \"./Connect.js\";\nimport { Offline } from \"./Offline.js\";\nimport { PassAudio } from \"./PassAudio.js\";\n\nexport function EffectTests(Constr, args?, before?): void {\n\tcontext(\"Effect Tests\", () => {\n\t\tit(\"has an input and output\", () => {\n\t\t\tconst instance = new Constr(args);\n\t\t\tif (before) {\n\t\t\t\tbefore(instance);\n\t\t\t}\n\t\t\tinstance.connect(connectTo());\n\t\t\tconnectFrom().connect(instance);\n\t\t\tinstance.dispose();\n\t\t});\n\n\t\tit(\"can set the dry/wet value\", () => {\n\t\t\tconst instance = new Constr(args);\n\t\t\tif (before) {\n\t\t\t\tbefore(instance);\n\t\t\t}\n\t\t\tinstance.wet.value = 0;\n\t\t\texpect(instance.wet.value).to.equal(0);\n\t\t\tinstance.wet.value = 0.5;\n\t\t\texpect(instance.wet.value).to.equal(0.5);\n\t\t\tinstance.dispose();\n\t\t});\n\n\t\tit(\"can be constructed with an object\", () => {\n\t\t\tconst instance = new Constr({\n\t\t\t\twet: 0.25,\n\t\t\t});\n\t\t\tif (before) {\n\t\t\t\tbefore(instance);\n\t\t\t}\n\t\t\texpect(instance.wet.value).to.equal(0.25);\n\t\t\tinstance.dispose();\n\t\t});\n\n\t\tit(\"passes audio from input to output\", () => {\n\t\t\treturn PassAudio((input) => {\n\t\t\t\tconst instance = new Constr(args);\n\t\t\t\tif (before) {\n\t\t\t\t\tbefore(instance);\n\t\t\t\t}\n\t\t\t\tinput.connect(instance);\n\t\t\t\tinstance.toDestination();\n\t\t\t});\n\t\t});\n\n\t\tit(\"has no sound when not connected to any inputs\", () => {\n\t\t\treturn Offline(\n\t\t\t\t() => {\n\t\t\t\t\tconst instance = new Constr(args).toDestination();\n\t\t\t\t\tif (before) {\n\t\t\t\t\t\tbefore(instance);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t0.5,\n\t\t\t\t1\n\t\t\t).then((buffer) => {\n\t\t\t\texpect(buffer.isSilent()).to.be.true;\n\t\t\t});\n\t\t});\n\n\t\tit.skip(\"can pass 100% dry signal\", () => {\n\t\t\treturn Offline(\n\t\t\t\t() => {\n\t\t\t\t\tconst instance = new Constr(args).toDestination();\n\t\t\t\t\tif (before) {\n\t\t\t\t\t\tbefore(instance);\n\t\t\t\t\t}\n\t\t\t\t\tconst signal = new Signal(-1).connect(instance);\n\t\t\t\t\t// make the signals ramp\n\t\t\t\t\tsignal.linearRampTo(1, 1, 0);\n\t\t\t\t\tinstance.wet.value = 0;\n\t\t\t\t},\n\t\t\t\t0.5,\n\t\t\t\t1\n\t\t\t).then((buffer) => {\n\t\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\t\tconst value = time * 2 - 1;\n\t\t\t\t\texpect(sample).to.be.closeTo(value, 0.1);\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\n\t\tit.skip(\"effects the incoming signal\", () => {\n\t\t\treturn Offline(\n\t\t\t\t() => {\n\t\t\t\t\tconst instance = new Constr(args).toDestination();\n\t\t\t\t\tif (before) {\n\t\t\t\t\t\tbefore(instance);\n\t\t\t\t\t}\n\t\t\t\t\tconst signal = new Signal(-1).connect(instance);\n\t\t\t\t\t// make the signals ramp\n\t\t\t\t\tsignal.linearRampTo(1, 1);\n\t\t\t\t\tinstance.wet.value = 1;\n\t\t\t\t},\n\t\t\t\t0.5,\n\t\t\t\t1\n\t\t\t).then((buffer) => {\n\t\t\t\tlet affected = false;\n\t\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\t\tconst value = time * 2 - 1;\n\t\t\t\t\tif (Math.abs(value - sample) > 0.01) {\n\t\t\t\t\t\taffected = true;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\texpect(affected).to.be.true;\n\t\t\t});\n\t\t});\n\t});\n}\n"
  },
  {
    "path": "test/helper/InstrumentTests.ts",
    "content": "import { expect } from \"chai\";\n\nimport { Frequency } from \"../../Tone/core/type/Units.js\";\nimport { Instrument } from \"../../Tone/instrument/Instrument.js\";\nimport { Monophonic } from \"../../Tone/instrument/Monophonic.js\";\nimport { connectTo } from \"./Connect.js\";\nimport { Offline } from \"./Offline.js\";\nimport { OutputAudio } from \"./OutputAudio.js\";\n\nfunction wait(time) {\n\treturn new Promise((done) => setTimeout(done, time));\n}\n\nexport function InstrumentTest(\n\tConstr,\n\tnote?: Frequency,\n\tconstrArg?: any,\n\toptionsIndex?: any,\n\tnoPortamento = false\n): void {\n\tcontext(\"Instrument Tests\", () => {\n\t\tit(\"extends Tone.Instrument\", () => {\n\t\t\tconst instance = new Constr(constrArg);\n\t\t\texpect(instance).to.be.an.instanceof(Instrument);\n\t\t\tinstance.dispose();\n\t\t});\n\n\t\tit(\"can connect the output\", () => {\n\t\t\tconst instance = new Constr(constrArg);\n\t\t\tinstance.connect(connectTo());\n\t\t\tinstance.dispose();\n\t\t});\n\n\t\tit(\"can set the volume\", () => {\n\t\t\tlet instance;\n\t\t\tif (!optionsIndex) {\n\t\t\t\tinstance = new Constr({\n\t\t\t\t\tvolume: -10,\n\t\t\t\t});\n\t\t\t} else if (optionsIndex === 1) {\n\t\t\t\tinstance = new Constr(constrArg, {\n\t\t\t\t\tvolume: -10,\n\t\t\t\t});\n\t\t\t}\n\t\t\texpect(instance.volume.value).to.be.closeTo(-10, 0.1);\n\t\t\tinstance.dispose();\n\t\t});\n\n\t\tit(\"makes a sound\", () => {\n\t\t\treturn OutputAudio(() => {\n\t\t\t\tconst instance = new Constr(constrArg);\n\t\t\t\tinstance.toDestination();\n\t\t\t\tinstance.triggerAttack(note);\n\t\t\t});\n\t\t});\n\n\t\tit(\"is silent before being triggered\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst instance = new Constr(constrArg);\n\t\t\t\tinstance.toDestination();\n\t\t\t});\n\t\t\texpect(buffer.isSilent()).to.be.true;\n\t\t});\n\n\t\tif (Constr.prototype.triggerRelease) {\n\t\t\tit(\"can trigger release after attack\", async () => {\n\t\t\t\tconst buffer = await Offline(() => {\n\t\t\t\t\tconst instance = new Constr(constrArg);\n\t\t\t\t\tinstance.toDestination();\n\t\t\t\t\tif (note) {\n\t\t\t\t\t\tinstance.triggerAttack(note, 0.05);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tinstance.triggerAttack(0.05);\n\t\t\t\t\t}\n\t\t\t\t\tinstance.triggerRelease(0.1);\n\t\t\t\t}, 1);\n\t\t\t\texpect(buffer.getTimeOfFirstSound()).to.be.within(0.05, 0.1);\n\t\t\t});\n\n\t\t\tit(\"can trigger another attack before the release has ended\", async () => {\n\t\t\t\t// compute the end time\n\t\t\t\tconst buffer = await Offline(() => {\n\t\t\t\t\tconst instance = new Constr(constrArg);\n\t\t\t\t\tinstance.toDestination();\n\t\t\t\t\tif (note) {\n\t\t\t\t\t\tinstance.triggerAttack(note, 0.05);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tinstance.triggerAttack(0.05);\n\t\t\t\t\t}\n\t\t\t\t\tinstance.triggerRelease(0.1);\n\t\t\t\t}, 1);\n\t\t\t\tconst bufferDuration = buffer.getTimeOfLastSound();\n\t\t\t\tconst secondTrigger = 0.15;\n\t\t\t\tconst resultingBuffer = await Offline(\n\t\t\t\t\t() => {\n\t\t\t\t\t\tconst instance_1 = new Constr(constrArg);\n\t\t\t\t\t\tinstance_1.toDestination();\n\t\t\t\t\t\tif (note) {\n\t\t\t\t\t\t\tinstance_1.triggerAttack(note, 0.05);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tinstance_1.triggerAttack(0.05);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tinstance_1.triggerRelease(0.1);\n\t\t\t\t\t\t// star the note again before the last one has finished\n\t\t\t\t\t\tif (note) {\n\t\t\t\t\t\t\tinstance_1.triggerAttack(note, secondTrigger);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tinstance_1.triggerAttack(secondTrigger);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tbufferDuration + secondTrigger * 2\n\t\t\t\t);\n\t\t\t\texpect(resultingBuffer.getTimeOfLastSound()).to.be.gt(\n\t\t\t\t\tbufferDuration\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tit(\"can combine triggerAttack and triggerRelease\", async () => {\n\t\t\t\tconst buffer = await Offline(() => {\n\t\t\t\t\tconst instance = new Constr(constrArg);\n\t\t\t\t\tinstance.toDestination();\n\t\t\t\t\tif (note) {\n\t\t\t\t\t\tinstance.triggerAttackRelease(note, 0.1, 0.05);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tinstance.triggerAttackRelease(0.1, 0.05);\n\t\t\t\t\t}\n\t\t\t\t}, 0.2);\n\t\t\t\texpect(buffer.getTimeOfFirstSound()).to.be.within(0.05, 0.1);\n\t\t\t});\n\t\t}\n\n\t\tit(\"be scheduled to start in the future\", async () => {\n\t\t\tconst buffer = await Offline(() => {\n\t\t\t\tconst instance = new Constr(constrArg);\n\t\t\t\tinstance.toDestination();\n\t\t\t\tif (note) {\n\t\t\t\t\tinstance.triggerAttack(note, 0.1);\n\t\t\t\t} else {\n\t\t\t\t\tinstance.triggerAttack(0.1);\n\t\t\t\t}\n\t\t\t}, 0.2);\n\t\t\texpect(buffer.getTimeOfFirstSound()).to.be.within(0.1, 0.15);\n\t\t});\n\n\t\tit(\"can sync triggerAttack to the Transport\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst instance = new Constr(constrArg);\n\t\t\t\tinstance.toDestination();\n\t\t\t\tinstance.sync();\n\t\t\t\tif (note) {\n\t\t\t\t\tinstance.triggerAttack(note, 0.1);\n\t\t\t\t} else {\n\t\t\t\t\tinstance.triggerAttack(0.1);\n\t\t\t\t}\n\t\t\t\ttransport.start(0.1);\n\t\t\t}, 0.3);\n\t\t\texpect(buffer.getTimeOfFirstSound()).to.be.within(0.19, 0.25);\n\t\t});\n\n\t\tit(\"can unsync triggerAttack to the Transport\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst instance = new Constr(constrArg);\n\t\t\t\tinstance.toDestination();\n\t\t\t\tinstance.sync();\n\t\t\t\tif (note) {\n\t\t\t\t\tinstance.triggerAttack(note, 0.1);\n\t\t\t\t} else {\n\t\t\t\t\tinstance.triggerAttack(0.1);\n\t\t\t\t}\n\t\t\t\tinstance.unsync();\n\t\t\t\ttransport.start(0.1);\n\t\t\t}, 0.3);\n\t\t\texpect(buffer.isSilent()).to.be.true;\n\t\t});\n\n\t\tit(\"can unsync and re-sync triggerAttack to the Transport\", async () => {\n\t\t\tconst buffer = await Offline(async ({ transport }) => {\n\t\t\t\tconst instance = new Constr(constrArg);\n\t\t\t\tinstance.toDestination();\n\n\t\t\t\tinstance.sync();\n\t\t\t\tif (note) {\n\t\t\t\t\tinstance.triggerAttack(note, 0.1);\n\t\t\t\t} else {\n\t\t\t\t\tinstance.triggerAttack(0.1);\n\t\t\t\t}\n\t\t\t\ttransport.start(0.1);\n\t\t\t\tawait wait(100);\n\t\t\t\tinstance.unsync();\n\t\t\t\ttransport.stop();\n\n\t\t\t\tinstance.sync();\n\t\t\t\tif (note) {\n\t\t\t\t\tinstance.triggerAttack(note, 0.1);\n\t\t\t\t} else {\n\t\t\t\t\tinstance.triggerAttack(0.1);\n\t\t\t\t}\n\t\t\t\ttransport.start(0.1);\n\t\t\t}, 1);\n\t\t\texpect(buffer.getTimeOfFirstSound()).to.be.within(0.19, 0.25);\n\t\t});\n\n\t\tit(\"calling sync and unsync multiple times has no effect\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst instance = new Constr(constrArg);\n\t\t\t\tinstance.toDestination();\n\t\t\t\tinstance.sync();\n\t\t\t\tinstance.sync();\n\t\t\t\tif (note) {\n\t\t\t\t\tinstance.triggerAttack(note, 0.1);\n\t\t\t\t} else {\n\t\t\t\t\tinstance.triggerAttack(0.1);\n\t\t\t\t}\n\t\t\t\tinstance.unsync();\n\t\t\t\tinstance.unsync();\n\t\t\t\ttransport.start(0.1);\n\t\t\t}, 0.3);\n\t\t\texpect(buffer.isSilent()).to.be.true;\n\t\t});\n\n\t\tit(\"can sync triggerAttackRelease to the Transport\", async () => {\n\t\t\tconst buffer = await Offline(({ transport }) => {\n\t\t\t\tconst instance = new Constr(constrArg);\n\t\t\t\tinstance.toDestination();\n\t\t\t\tinstance.sync();\n\t\t\t\tif (note) {\n\t\t\t\t\tinstance.triggerAttackRelease(note, 0.25, 0.1);\n\t\t\t\t} else {\n\t\t\t\t\tinstance.triggerAttackRelease(0.25, 0.1);\n\t\t\t\t}\n\t\t\t\ttransport.start(0.1);\n\t\t\t}, 1);\n\t\t\texpect(buffer.getTimeOfFirstSound()).to.be.within(0.19, 0.25);\n\t\t\t// test a sample enough in the future for the decay to die down\n\t\t\texpect(buffer.getRmsAtTime(0.9)).to.be.closeTo(0, 0.1);\n\t\t});\n\n\t\tit(\"invokes onsilence\", (done) => {\n\t\t\tOffline(() => {\n\t\t\t\tconst instance = new Constr(constrArg);\n\t\t\t\tif (instance instanceof Monophonic) {\n\t\t\t\t\tinstance.triggerAttackRelease(note!, 0.1, 0);\n\t\t\t\t\tinstance.onsilence = (voice) => {\n\t\t\t\t\t\texpect(voice).to.equal(instance);\n\t\t\t\t\t\tdone();\n\t\t\t\t\t};\n\t\t\t\t} else {\n\t\t\t\t\tdone();\n\t\t\t\t}\n\t\t\t}, 3);\n\t\t});\n\n\t\tif (!noPortamento) {\n\t\t\tit(\"can do portamento glide between notes\", () => {\n\t\t\t\treturn Offline(() => {\n\t\t\t\t\tconst instance = new Constr(constrArg);\n\t\t\t\t\tif (instance instanceof Monophonic) {\n\t\t\t\t\t\tinstance.portamento = 0.5;\n\t\t\t\t\t\tinstance.triggerAttackRelease(\"C4\", 0.2, 0);\n\t\t\t\t\t\texpect(instance.getLevelAtTime(0.4)).to.be.greaterThan(\n\t\t\t\t\t\t\t0\n\t\t\t\t\t\t);\n\t\t\t\t\t\tinstance.triggerAttackRelease(\"C2\", 0.2, 0.4);\n\t\t\t\t\t}\n\t\t\t\t}, 0.5);\n\t\t\t});\n\t\t}\n\t});\n}\n"
  },
  {
    "path": "test/helper/MonophonicTests.ts",
    "content": "import { expect } from \"chai\";\n\nimport { Offline } from \"./Offline.js\";\n\nexport function MonophonicTest(Constr, note, constrArg?): void {\n\tcontext(\"Monophonic Tests\", () => {\n\t\tit(\"has an onsilence callback which is invoked after the release has finished\", () => {\n\t\t\tlet wasInvoked = false;\n\t\t\treturn Offline(() => {\n\t\t\t\tconst instance = new Constr(constrArg);\n\t\t\t\tinstance.toDestination();\n\t\t\t\tinstance.triggerAttackRelease(note, 0.1, 0);\n\t\t\t\tinstance.onsilence = () => (wasInvoked = true);\n\t\t\t}, 2).then(() => {\n\t\t\t\texpect(wasInvoked).to.equal(true);\n\t\t\t});\n\t\t});\n\n\t\tit(\"invokes onsilence callback when the sustain is set to 0\", () => {\n\t\t\tlet wasInvoked = false;\n\t\t\treturn Offline(() => {\n\t\t\t\tconst instance = new Constr(constrArg);\n\t\t\t\tinstance.toDestination();\n\t\t\t\tif (instance.envelope) {\n\t\t\t\t\tinstance.envelope.sustain = 0;\n\t\t\t\t} else if (instance.voice0) {\n\t\t\t\t\t// DuoSynth is a special case\n\t\t\t\t\tinstance.voice0.envelope.sustain = 0;\n\t\t\t\t\tinstance.voice1.envelope.sustain = 0;\n\t\t\t\t}\n\t\t\t\tinstance.triggerAttack(note, 0);\n\t\t\t\tinstance.onsilence = () => (wasInvoked = true);\n\t\t\t}, 2).then(() => {\n\t\t\t\texpect(wasInvoked).to.equal(true);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can pass in the detune into the constructor\", () => {\n\t\t\tconst instance = new Constr({\n\t\t\t\tdetune: -100,\n\t\t\t});\n\t\t\texpect(instance.detune.value).to.be.closeTo(-100, 0.1);\n\t\t\tinstance.dispose();\n\t\t});\n\t});\n}\n"
  },
  {
    "path": "test/helper/Offline.ts",
    "content": "import { OfflineContext } from \"../../Tone/core/context/OfflineContext.js\";\nimport { getContext, setContext } from \"../../Tone/core/Global.js\";\nimport { Seconds } from \"../../Tone/core/type/Units.js\";\nimport { isArray, isFunction } from \"../../Tone/core/util/TypeCheck.js\";\nimport { TestAudioBuffer } from \"./compare/index.js\";\n\ntype ReturnFunction = (time: Seconds) => void;\n\nexport async function Offline(\n\tcallback: (\n\t\tcontext: OfflineContext\n\t) =>\n\t\t| void\n\t\t| ReturnFunction\n\t\t| ReturnFunction[]\n\t\t| Promise<void | ReturnFunction>\n\t\t| void,\n\tduration = 0.1,\n\tchannels = 1,\n\tsampleRate = 44100\n): Promise<TestAudioBuffer> {\n\tconst originalContext = getContext();\n\tconst offline = new OfflineContext(\n\t\tchannels,\n\t\tduration + 1 / sampleRate,\n\t\tsampleRate\n\t);\n\tsetContext(offline);\n\tlet error: Error | null = null;\n\ttry {\n\t\tlet retFunction = callback(offline);\n\t\tif (retFunction instanceof Promise) {\n\t\t\tretFunction = await retFunction;\n\t\t}\n\t\tif (isFunction(retFunction)) {\n\t\t\tconst fn = retFunction;\n\t\t\toffline.on(\"tick\", () => fn(offline.now()));\n\t\t} else if (isArray(retFunction)) {\n\t\t\t// each element in the array is a timing callback\n\t\t\tretFunction.forEach((fn) => {\n\t\t\t\toffline.on(\"tick\", () => fn(offline.now()));\n\t\t\t});\n\t\t}\n\t} catch (e) {\n\t\terror = e as Error;\n\t} finally {\n\t\tsetContext(originalContext);\n\t\tconst buffer = await offline.render();\n\t\tif (error) {\n\t\t\tthrow error;\n\t\t}\n\t\treturn new TestAudioBuffer(buffer.get() as AudioBuffer);\n\t}\n}\n\nexport function whenBetween(\n\tvalue: Seconds,\n\tstart: Seconds,\n\tstop: Seconds,\n\tcallback: () => void\n): void {\n\tif (value >= start && value < stop) {\n\t\tcallback();\n\t}\n}\n\n// invoked only once\nexport function atTime(\n\twhen: Seconds,\n\tcallback: (time: Seconds) => void\n): (time: Seconds) => void {\n\tlet wasInvoked = false;\n\treturn (time) => {\n\t\tif (time >= when && !wasInvoked) {\n\t\t\tcallback(time);\n\t\t\twasInvoked = true;\n\t\t}\n\t};\n}\n"
  },
  {
    "path": "test/helper/OscillatorTests.ts",
    "content": "import { expect } from \"chai\";\n\nimport { connectFrom } from \"./Connect.js\";\nimport { Offline } from \"./Offline.js\";\n\nexport function OscillatorTests(Constr, args?): void {\n\tcontext(\"Oscillator Tests\", () => {\n\t\tit(\"can be created with an options object\", () => {\n\t\t\tconst instance = new Constr({\n\t\t\t\tdetune: -20,\n\t\t\t\tfrequency: 200,\n\t\t\t});\n\t\t\texpect(instance.frequency.value).to.equal(200);\n\t\t\texpect(instance.detune.value).to.equal(-20);\n\t\t\tinstance.dispose();\n\t\t});\n\n\t\tit(\"can set/set the frequency\", () => {\n\t\t\tconst instance = new Constr(args);\n\t\t\tinstance.frequency.value = 110;\n\t\t\texpect(instance.frequency.value).to.equal(110);\n\t\t\tinstance.start();\n\t\t\tinstance.frequency.value = 220;\n\t\t\texpect(instance.frequency.value).to.equal(220);\n\t\t\tinstance.dispose();\n\t\t});\n\n\t\tit(\"can set/set the detune\", () => {\n\t\t\tconst instance = new Constr(args);\n\t\t\tinstance.detune.value = -50;\n\t\t\texpect(instance.detune.value).to.equal(-50);\n\t\t\tinstance.start();\n\t\t\tinstance.detune.value = 92;\n\t\t\texpect(instance.detune.value).to.equal(92);\n\t\t\tinstance.dispose();\n\t\t});\n\n\t\tit(\"can connect to detune and frequency\", () => {\n\t\t\tconst instance = new Constr(args);\n\t\t\tconnectFrom().connect(instance.frequency);\n\t\t\tconnectFrom().connect(instance.detune);\n\t\t\tinstance.dispose();\n\t\t});\n\n\t\tit(\"can get/set the phase\", () => {\n\t\t\tconst osc = new Constr({\n\t\t\t\tphase: 180,\n\t\t\t});\n\t\t\texpect(osc.phase).to.be.closeTo(180, 0.001);\n\t\t\tosc.phase = 270;\n\t\t\texpect(osc.phase).to.be.closeTo(270, 0.001);\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"does not clip in volume\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tnew Constr(args).toDestination().start(0);\n\t\t\t}).then((buffer) => {\n\t\t\t\texpect(buffer.max()).to.be.at.most(1);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can generate a waveform\", async () => {\n\t\t\tconst osc = new Constr();\n\t\t\tconst waveform = await osc.asArray();\n\t\t\twaveform.forEach((v: number) => expect(v).to.be.within(-1, 1));\n\t\t\tosc.dispose();\n\t\t});\n\n\t\tit(\"can generate a waveform of a specific length\", async () => {\n\t\t\tconst osc = new Constr();\n\t\t\tconst waveform = await osc.asArray(256);\n\t\t\texpect(waveform.length).to.equal(256);\n\t\t\tosc.dispose();\n\t\t});\n\t});\n}\n"
  },
  {
    "path": "test/helper/OutputAudio.ts",
    "content": "import { expect } from \"chai\";\n\nimport { Offline } from \"./Offline.js\";\n\nexport function OutputAudio(callback): Promise<void> {\n\treturn Offline(callback, 0.1).then((buffer) => {\n\t\texpect(buffer.isSilent(), \"no audio\").to.equal(false);\n\t});\n}\n"
  },
  {
    "path": "test/helper/PassAudio.ts",
    "content": "import { expect } from \"chai\";\n\nimport { ToneAudioNode } from \"../../Tone/core/context/ToneAudioNode.js\";\nimport { Signal } from \"../../Tone/signal/Signal.js\";\nimport { Offline } from \"./Offline.js\";\n\n/**\n * Make sure that the audio passes from input node\n * to the destination node\n */\nexport function PassAudio(\n\tcallback: (input: ToneAudioNode) => void,\n\tpasses = true\n): Promise<void> {\n\tconst duration = 0.2;\n\treturn Offline(\n\t\t() => {\n\t\t\tconst sig = new Signal(0);\n\t\t\tcallback(sig);\n\t\t\tsig.setValueAtTime(1, duration / 2);\n\t\t},\n\t\t0.2,\n\t\t1\n\t).then((buffer) => {\n\t\texpect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.001);\n\t\texpect(buffer.getValueAtTime(duration / 2 - 0.01)).to.be.closeTo(\n\t\t\t0,\n\t\t\t0.001\n\t\t);\n\t\tif (passes) {\n\t\t\texpect(buffer.getValueAtTime(duration / 2 + 0.01)).to.not.equal(0);\n\t\t\texpect(buffer.getValueAtTime(duration - 0.01)).to.not.equal(0);\n\t\t} else {\n\t\t\texpect(buffer.getValueAtTime(duration / 2 + 0.01)).to.be.closeTo(\n\t\t\t\t0,\n\t\t\t\t0.001\n\t\t\t);\n\t\t\texpect(buffer.getValueAtTime(duration - 0.01)).to.be.closeTo(\n\t\t\t\t0,\n\t\t\t\t0.001\n\t\t\t);\n\t\t}\n\t});\n}\n"
  },
  {
    "path": "test/helper/SignalTests.ts",
    "content": "import { expect } from \"chai\";\n\nimport { Gain } from \"../../Tone/core/context/Gain.js\";\nimport { ToneAudioNode } from \"../../Tone/core/context/ToneAudioNode.js\";\nimport { Signal } from \"../../Tone/signal/Signal.js\";\nimport { ConstantOutput } from \"./ConstantOutput.js\";\n\ninterface ToneAudioNodeConstructor {\n\tnew (...args: unknown[]): ToneAudioNode;\n}\n\n/**\n * Test overwriting of connected signals with classes that use signalConnect / signalDisconnect.\n */\nexport function SignalConnectAndDisconnect(\n\tConstructor: ToneAudioNodeConstructor\n) {\n\tcontext(\"signal connect/disconnect\", () => {\n\t\tit(\"overwrites the output of a signal\", () => {\n\t\t\tconst signal = new Signal();\n\t\t\tconst instance = new Constructor();\n\t\t\texpect(signal.overridden).to.be.false;\n\n\t\t\tinstance.connect(signal);\n\t\t\texpect(signal.overridden).to.be.true;\n\t\t\texpect(signal.value).to.equal(0);\n\n\t\t\tsignal.dispose();\n\t\t\tinstance.dispose();\n\t\t});\n\n\t\tit(\"can disconnect from an AudioNode\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst instance = new Constructor();\n\t\t\t\tconst gain = new Gain({\n\t\t\t\t\tgain: 0.5,\n\t\t\t\t}).toDestination();\n\t\t\t\tinstance.connect(gain);\n\t\t\t\tinstance.disconnect(gain);\n\t\t\t}, 0);\n\t\t});\n\n\t\tit(\"restores the output of a Signal when disconnected\", () => {\n\t\t\treturn ConstantOutput(() => {\n\t\t\t\tconst signal = new Signal(3).toDestination();\n\t\t\t\tconst instance = new Constructor();\n\t\t\t\tinstance.connect(signal);\n\t\t\t\tinstance.disconnect(signal);\n\t\t\t}, 3);\n\t\t});\n\n\t\tit(\"restores an AudioParam when disconnected\", () => {\n\t\t\tconst gainNode = new Gain(1);\n\t\t\tconst instance = new Constructor();\n\t\t\texpect(gainNode.gain.overridden).to.be.false;\n\t\t\texpect(gainNode.gain.value).to.equal(1);\n\n\t\t\t// overwritten values\n\t\t\tinstance.connect(gainNode.gain);\n\t\t\texpect(gainNode.gain.overridden).to.be.true;\n\t\t\texpect(gainNode.gain.value).to.equal(0);\n\n\t\t\t// back to the original values\n\t\t\tinstance.disconnect(gainNode.gain);\n\t\t\texpect(gainNode.gain.overridden).to.be.false;\n\t\t\texpect(gainNode.gain.value).to.equal(1);\n\n\t\t\tgainNode.dispose();\n\t\t\tinstance.dispose();\n\t\t});\n\t});\n}\n"
  },
  {
    "path": "test/helper/SourceTests.ts",
    "content": "// import APITest from \"helper/APITest\";\nimport { expect } from \"chai\";\n\nimport { connectTo } from \"./Connect.js\";\nimport { Offline } from \"./Offline.js\";\nimport { OutputAudio } from \"./OutputAudio.js\";\n\nexport function SourceTests(Constr, args?): void {\n\tcontext(\"Source Tests\", () => {\n\t\tit(\"can connect the output\", () => {\n\t\t\tconst instance = new Constr(args);\n\t\t\tinstance.connect(connectTo());\n\t\t\tinstance.dispose();\n\t\t});\n\n\t\tit(\"has no input\", () => {\n\t\t\tconst instance = new Constr(args);\n\t\t\t// has no input\n\t\t\texpect(instance.numberOfInputs).to.equal(0);\n\t\t\tinstance.dispose();\n\t\t});\n\n\t\tit(\"starts and stops\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst instance = new Constr(args);\n\t\t\t\texpect(instance.state).to.equal(\"stopped\");\n\t\t\t\tinstance.start(0).stop(0.2);\n\t\t\t\treturn (time) => {\n\t\t\t\t\tif (time >= 0 && time < 0.2) {\n\t\t\t\t\t\texpect(instance.state).to.equal(\"started\");\n\t\t\t\t\t} else if (time > 0.2) {\n\t\t\t\t\t\texpect(instance.state).to.equal(\"stopped\");\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}, 0.3);\n\t\t});\n\n\t\tit(\"makes a sound\", () => {\n\t\t\treturn OutputAudio(() => {\n\t\t\t\tconst instance = new Constr(args);\n\t\t\t\tinstance.toDestination();\n\t\t\t\tinstance.start();\n\t\t\t});\n\t\t});\n\n\t\tit(\"invokes the onstop method the source is stopped\", () => {\n\t\t\tlet wasInvoked = false;\n\t\t\treturn Offline(() => {\n\t\t\t\tconst instance = new Constr(args);\n\t\t\t\tinstance.toDestination();\n\t\t\t\tinstance.onstop = () => (wasInvoked = true);\n\t\t\t\tinstance.start(0).stop(0.1);\n\t\t\t}, 0.2).then(() => {\n\t\t\t\texpect(wasInvoked).to.equal(true);\n\t\t\t});\n\t\t});\n\n\t\tit(\"be scheduled to start in the future\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst instance = new Constr(args).toDestination();\n\t\t\t\tinstance.start(0.1);\n\t\t\t}, 0.3).then((buffer) => {\n\t\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\t\tif (sample > 0) {\n\t\t\t\t\t\texpect(time).to.be.at.least(0.099);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\n\t\tit(\"makes no sound if it is started and then stopped with a time at or before the start time\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst instance = new Constr(args).toDestination();\n\t\t\t\tinstance.start(0.1).stop(0.05);\n\t\t\t}, 0.3).then((buffer) => {\n\t\t\t\texpect(buffer.isSilent()).to.equal(true);\n\t\t\t});\n\t\t});\n\n\t\tit(\"can be muted\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst instance = new Constr(args).toDestination();\n\t\t\t\tinstance.start(0);\n\t\t\t\tinstance.mute = true;\n\t\t\t}, 0.3).then((buffer) => {\n\t\t\t\texpect(buffer.isSilent()).to.equal(true);\n\t\t\t});\n\t\t});\n\n\t\tit(\"be scheduled to stop in the future\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst instance = new Constr(args).toDestination();\n\t\t\t\tinstance.start(0).stop(0.2);\n\t\t\t}, 0.3).then((buffer) => {\n\t\t\t\tbuffer.forEach((sample, time) => {\n\t\t\t\t\tif (time > 0.2) {\n\t\t\t\t\t\texpect(sample).to.equal(0);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\n\t\tit(\"can be restarted\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst instance = new Constr(args).toDestination();\n\t\t\t\tinstance.start(0).stop(0.2);\n\t\t\t\tinstance.restart(0.1);\n\t\t\t\tinstance.stop(0.25);\n\t\t\t}, 0.32).then((buffer) => {\n\t\t\t\texpect(buffer.getRmsAtTime(0)).to.be.gt(0);\n\t\t\t\texpect(buffer.getRmsAtTime(0.1)).to.be.gt(0);\n\t\t\t\texpect(buffer.getRmsAtTime(0.2)).to.be.gt(0);\n\t\t\t\texpect(buffer.getRmsAtTime(0.23)).to.be.gt(0);\n\t\t\t\texpect(buffer.getRmsAtTime(0.3)).to.equal(0);\n\t\t\t});\n\t\t});\n\n\t\tit(\"calling restart before calling start has no effect\", () => {\n\t\t\treturn Offline(() => {\n\t\t\t\tconst instance = new Constr(args).toDestination();\n\t\t\t\tinstance.restart(0.1);\n\t\t\t}, 0.2).then((buffer) => {\n\t\t\t\texpect(buffer.isSilent()).to.be.true;\n\t\t\t});\n\t\t});\n\t});\n}\n"
  },
  {
    "path": "test/helper/StereoSignal.ts",
    "content": "import { Merge } from \"../../Tone/component/channel/Merge.js\";\nimport { Signal } from \"../../Tone/signal/Signal.js\";\n\nexport function StereoSignal(l: number, r: number): Merge {\n\tconst merge = new Merge();\n\tnew Signal(l).connect(merge, 0, 0);\n\tnew Signal(r).connect(merge, 0, 1);\n\treturn merge;\n}\n"
  },
  {
    "path": "test/helper/compare/Compare.ts",
    "content": "import { OfflineRender } from \"./OfflineRender.js\";\nimport { analyze } from \"./Spectrum.js\";\nimport { TestAudioBuffer } from \"./TestAudioBuffer.js\";\n\nexport function compareSpectra(\n\tbufferA: TestAudioBuffer,\n\tbufferB: TestAudioBuffer\n): number {\n\tif (bufferA.length !== bufferB.length) {\n\t\tthrow new Error(\"buffers must be the same length to compare\");\n\t}\n\tconst analysisA = analyze(bufferA, 1024, 64);\n\tconst analysisB = analyze(bufferB, 1024, 64);\n\n\tlet diff = 0;\n\tanalysisA.forEach((columnA, columnNum) => {\n\t\tconst columnB = analysisB[columnNum];\n\t\tcolumnA.forEach((valA, index) => {\n\t\t\tconst valB = columnB[index];\n\t\t\tdiff += Math.pow(valA - valB, 2);\n\t\t});\n\t});\n\treturn Math.sqrt(diff / analysisA.length);\n}\n\nexport function compareSignals(\n\tbufferA: TestAudioBuffer,\n\tbufferB: TestAudioBuffer\n): number {\n\tconst arrayA = bufferA.toArray();\n\tconst arrayB = bufferB.toArray();\n\tconst diffs = arrayA.map((channelA, channelNum) => {\n\t\tlet diff = 0;\n\t\tconst channelB = arrayB[channelNum];\n\t\tchannelA.forEach((valA, index) => {\n\t\t\tconst valB = channelB[index];\n\t\t\tdiff += Math.pow(valA - valB, 2);\n\t\t});\n\t\treturn Math.sqrt(diff / channelA.length);\n\t});\n\t// average across the channels\n\treturn diffs.reduce((t, v) => t + v, 0) / diffs.length;\n}\n\ninterface BufferResponse {\n\tbufferA: TestAudioBuffer;\n\tbufferB: TestAudioBuffer;\n}\n\ntype BufferResponseType = BufferResponse | void;\n\nasync function getBuffersToCompare(\n\tcallback: (context: OfflineAudioContext) => Promise<void> | void,\n\tfilename: string,\n\tduration = 0.5,\n\tchannels = 1,\n\tsampleRate = 11025,\n\tforceRender = false\n): Promise<BufferResponseType> {\n\tif (forceRender) {\n\t\tconst buffer = await OfflineRender(\n\t\t\tcallback,\n\t\t\tduration,\n\t\t\tchannels,\n\t\t\tsampleRate\n\t\t);\n\t\tbuffer.downloadWav(filename);\n\t\treturn Promise.resolve();\n\t} else {\n\t\tconst bufferB = await fetch(filename)\n\t\t\t.then((response) => response.arrayBuffer())\n\t\t\t.then((buffer) => {\n\t\t\t\tconst context = new OfflineAudioContext(\n\t\t\t\t\tchannels,\n\t\t\t\t\t1,\n\t\t\t\t\tsampleRate\n\t\t\t\t);\n\t\t\t\treturn context.decodeAudioData(buffer);\n\t\t\t})\n\t\t\t.then((audioBuffer) => new TestAudioBuffer(audioBuffer));\n\t\tconst bufferA = await OfflineRender(\n\t\t\tcallback,\n\t\t\tbufferB.duration,\n\t\t\tbufferB.numberOfChannels,\n\t\t\tbufferB.sampleRate\n\t\t);\n\n\t\t// const [bufferA, bufferB] = await Promise.all([bufferAPromise, bufferBPromise]);\n\t\treturn {\n\t\t\tbufferA,\n\t\t\tbufferB,\n\t\t};\n\t}\n}\n\nexport async function toFile(\n\tcallback: (context: OfflineAudioContext) => Promise<void> | void,\n\tfilename: string,\n\tthreshold = 0.1,\n\tforceRender = false,\n\tduration = 0.1,\n\tchannels = 1,\n\tsampleRate = 11025\n) {\n\tconst response = await getBuffersToCompare(\n\t\tcallback,\n\t\tfilename,\n\t\tduration,\n\t\tchannels,\n\t\tsampleRate,\n\t\tforceRender\n\t);\n\tif (response) {\n\t\tconst { bufferA, bufferB } = response;\n\t\tconst error = compareSpectra(bufferA, bufferB);\n\t\tif (error > threshold) {\n\t\t\tthrow new Error(\n\t\t\t\t`Error ${error} greater than threshold ${threshold}`\n\t\t\t);\n\t\t}\n\t}\n}\n\nexport async function toFileSignal(\n\tcallback: (context: OfflineAudioContext) => Promise<void> | void,\n\tfilename: string,\n\tthreshold = 0.1,\n\tforceRender = false,\n\tduration = 0.1,\n\tchannels = 1,\n\tsampleRate = 11025\n) {\n\tconst response = await getBuffersToCompare(\n\t\tcallback,\n\t\tfilename,\n\t\tduration,\n\t\tchannels,\n\t\tsampleRate,\n\t\tforceRender\n\t);\n\tif (response) {\n\t\tconst { bufferA, bufferB } = response;\n\t\tif (compareSignals(bufferA, bufferB) > threshold) {\n\t\t\tthrow new Error(`generated buffer does not match file ${filename}`);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "test/helper/compare/OfflineRender.ts",
    "content": "import { TestAudioBuffer } from \"./TestAudioBuffer.js\";\n\nexport async function OfflineRender(\n\tcallback: (context: OfflineAudioContext) => Promise<void> | void,\n\tduration = 0.001,\n\tchannels = 1,\n\tsampleRate = 11025\n): Promise<TestAudioBuffer> {\n\t// the offline context\n\tconst offlineContext = new OfflineAudioContext(\n\t\tchannels,\n\t\tMath.floor(duration * sampleRate),\n\t\tsampleRate\n\t) as unknown as OfflineAudioContext;\n\n\t// wait for the callback\n\tawait callback(offlineContext);\n\n\t// render the buffer\n\tconst buffer = await offlineContext.startRendering();\n\n\t// wrap the buffer\n\treturn new TestAudioBuffer(buffer);\n}\n\n/**\n * Returns true if the input passes audio to the output\n */\nexport async function PassesAudio(\n\tcallback: (\n\t\tcontext: OfflineAudioContext,\n\t\tinput: ConstantSourceNode,\n\t\toutput: AudioDestinationNode\n\t) => Promise<void> | void\n): Promise<boolean> {\n\tconst buffer = await OfflineRender(\n\t\tasync (context) => {\n\t\t\tconst source =\n\t\t\t\tcontext.createConstantSource() as unknown as ConstantSourceNode;\n\t\t\tsource.start(0);\n\t\t\tsource.offset.setValueAtTime(0, 0);\n\t\t\tsource.offset.setValueAtTime(1, 0.25);\n\t\t\tconst destination =\n\t\t\t\tcontext.destination as unknown as AudioDestinationNode;\n\t\t\tawait callback(context, source, destination);\n\t\t},\n\t\t0.5,\n\t\t1,\n\t\t11025\n\t);\n\tconst sample0 = buffer.getValueAtTime(0) === 0;\n\tconst sample1 = buffer.getValueAtTime(0.2) === 0;\n\tconst sample2 = (buffer.getValueAtTime(0.26) as number) > 0;\n\tconst sample3 = (buffer.getValueAtTime(0.49) as number) > 0;\n\treturn sample0 && sample1 && sample2 && sample3;\n}\n\n/**\n * Returns true if the callback makes a sound\n */\nexport async function MakesSound(\n\tcallback: (context: OfflineAudioContext) => Promise<void> | void,\n\tduration = 0.001,\n\tchannels = 1,\n\tsampleRate = 11025\n): Promise<boolean> {\n\tconst buffer = await OfflineRender(\n\t\tcallback,\n\t\tduration,\n\t\tchannels,\n\t\tsampleRate\n\t);\n\treturn !buffer.isSilent();\n}\n"
  },
  {
    "path": "test/helper/compare/Plot.ts",
    "content": "import array2d from \"array2d\";\nimport plotly from \"plotly.js-dist\";\n\nimport type { ToneAudioBuffer } from \"../../../Tone/core/context/ToneAudioBuffer.js\";\nimport { analyze } from \"./Spectrum.js\";\nimport { TestAudioBuffer } from \"./TestAudioBuffer.js\";\n\n/**\n * Generate a 2d spectrogram image of the audio buffer\n */\nexport function spectrogram(\n\tbuffer: TestAudioBuffer | ToneAudioBuffer,\n\tfftSize = 2048,\n\thopSize = 32\n): HTMLElement {\n\tbuffer = new TestAudioBuffer(buffer);\n\tconst analysis = analyze(buffer, fftSize, hopSize);\n\tconst element = document.createElement(\"div\");\n\tconst rotated = array2d.rotate(analysis, array2d.DIRECTIONS.LEFT);\n\tconst flipped = array2d.flip(rotated, array2d.AXES.X);\n\tplotly.newPlot(\n\t\telement,\n\t\t[\n\t\t\t{\n\t\t\t\tz: flipped,\n\t\t\t\ttype: \"heatmap\",\n\t\t\t\tcolorscale: \"Viridis\",\n\t\t\t},\n\t\t],\n\t\t{\n\t\t\tyaxis: {\n\t\t\t\ttype: \"log\",\n\t\t\t\tautorange: true,\n\t\t\t},\n\t\t\tzaxis: {\n\t\t\t\ttype: \"log\",\n\t\t\t\tautorange: true,\n\t\t\t},\n\t\t}\n\t);\n\treturn element;\n}\n\n/**\n * Generate a plot of the input signal\n */\nexport function signal(buffer: TestAudioBuffer | ToneAudioBuffer): HTMLElement {\n\tbuffer = new TestAudioBuffer(buffer);\n\tconst descriptions = buffer.toArray().map((array, i) => {\n\t\treturn {\n\t\t\ty: array,\n\t\t\tx: array.map((_, t: number) => t / buffer.sampleRate),\n\t\t\txaxis: \"x\",\n\t\t\tyaxis: `y${i + 1}`,\n\t\t\ttype: \"scatter\",\n\t\t\tmode: \"lines\",\n\t\t\tname: `channel ${i}`,\n\t\t};\n\t});\n\tconst element = document.createElement(\"div\");\n\tplotly.newPlot(element, descriptions, {\n\t\tgrid: {\n\t\t\trows: buffer.numberOfChannels,\n\t\t\tcolumns: 1,\n\t\t},\n\t\txaxis: {\n\t\t\ttitle: \"Seconds\",\n\t\t},\n\t\tshowlegend: false,\n\t\tcolorway: [\"#a600a6\", \"#f20076\", \"#ff5c40\", \"#ffa600\"],\n\t});\n\treturn element;\n}\n"
  },
  {
    "path": "test/helper/compare/Spectrum.ts",
    "content": "import windowing from \"fft-windowing\";\nimport ft from \"fourier-transform\";\n\nimport { TestAudioBuffer } from \"./TestAudioBuffer.js\";\n\n/**\n * Return a spectrogram of the buffer\n */\nexport function analyze(buffer: TestAudioBuffer, fftSize = 256, hopSize = 128) {\n\tconst spectrogram: number[][] = [];\n\tbuffer\n\t\t.toMono()\n\t\t.toArray()\n\t\t.forEach((channel) => {\n\t\t\tfor (\n\t\t\t\tlet index = 0;\n\t\t\t\tindex < channel.length - fftSize;\n\t\t\t\tindex += hopSize\n\t\t\t) {\n\t\t\t\tconst segment = windowing.blackman_harris(\n\t\t\t\t\tchannel.slice(index, index + fftSize)\n\t\t\t\t);\n\t\t\t\tspectrogram.push(ft(segment));\n\t\t\t}\n\t\t});\n\treturn spectrogram;\n}\n"
  },
  {
    "path": "test/helper/compare/TestAudioBuffer.ts",
    "content": "import toWav from \"audiobuffer-to-wav\";\n\nimport type { ToneAudioBuffer } from \"../../../Tone/core/context/ToneAudioBuffer.js\";\n\nexport class TestAudioBuffer {\n\tstatic async fromUrl(\n\t\turl: string,\n\t\tchannels = 1,\n\t\tsampleRate = 11025\n\t): Promise<TestAudioBuffer> {\n\t\tconst response = await fetch(url);\n\t\tif (response.ok) {\n\t\t\tconst buffer = await response.arrayBuffer();\n\t\t\tconst context = new OfflineAudioContext(channels, 1, sampleRate);\n\t\t\tconst audioBuffer = await context.decodeAudioData(buffer);\n\t\t\treturn new TestAudioBuffer(audioBuffer);\n\t\t} else {\n\t\t\tthrow new Error(`could not load url ${url}`);\n\t\t}\n\t}\n\n\tstatic fromTone(buffer: ToneAudioBuffer) {\n\t\treturn new TestAudioBuffer(buffer);\n\t}\n\n\tprivate _buffer: AudioBuffer;\n\tprivate _rms?: Float32Array[];\n\tprivate _array?: Float32Array[];\n\n\tconstructor(buffer: AudioBuffer | TestAudioBuffer | ToneAudioBuffer) {\n\t\tif (buffer instanceof AudioBuffer) {\n\t\t\tthis._buffer = buffer;\n\t\t} else if (buffer instanceof TestAudioBuffer) {\n\t\t\tthis._buffer = buffer._buffer;\n\t\t} else {\n\t\t\tthis._buffer = buffer.get() as AudioBuffer;\n\t\t}\n\t}\n\n\t/**\n\t * The number of channels of the audio file.\n\t */\n\tget numberOfChannels(): number {\n\t\treturn this._buffer.numberOfChannels;\n\t}\n\n\t/**\n\t * The duration in seconds\n\t */\n\tget duration(): number {\n\t\treturn this._buffer.duration;\n\t}\n\n\t/**\n\t * The length in samples\n\t */\n\tget length(): number {\n\t\treturn this._buffer.length;\n\t}\n\n\t/**\n\t * The sample rate of the audio file\n\t */\n\tget sampleRate(): number {\n\t\treturn this._buffer.sampleRate;\n\t}\n\n\t/**\n\t * Return the buffer as a nested array where the first axis is the number of channels\n\t */\n\ttoArray(): Float32Array[] {\n\t\tif (!this._array) {\n\t\t\tconst output: Float32Array[] = [];\n\t\t\tfor (\n\t\t\t\tlet channel = 0;\n\t\t\t\tchannel < this._buffer.numberOfChannels;\n\t\t\t\tchannel++\n\t\t\t) {\n\t\t\t\toutput[channel] = this._buffer.getChannelData(channel);\n\t\t\t}\n\t\t\tthis._array = output;\n\t\t}\n\t\treturn this._array;\n\t}\n\n\t/**\n\t * Return a new TestAudioBuffer which has all of the channels summed to a single channel\n\t */\n\ttoMono(): TestAudioBuffer {\n\t\tconst context = new OfflineAudioContext(1, 1, this._buffer.sampleRate);\n\t\tconst buffer = context.createBuffer(\n\t\t\t1,\n\t\t\tthis._buffer.length,\n\t\t\tthis._buffer.sampleRate\n\t\t);\n\t\t// sum all the channels into a single channel\n\t\tconst bufferArray = buffer.getChannelData(0);\n\t\tthis.toArray().forEach((channel) => {\n\t\t\tchannel.forEach((value, index) => {\n\t\t\t\tbufferArray[index] += value;\n\t\t\t});\n\t\t});\n\t\treturn new TestAudioBuffer(buffer);\n\t}\n\n\t/**\n\t * Return the Root Mean Square of the channels at that slice of time.\n\t * If buffer is mono, it will return a single value, otherwise it returns an array of numbers\n\t * @param time Seconds\n\t */\n\tgetRmsAtTime(time: number): number[] | number {\n\t\tif (!this._rms) {\n\t\t\tconst blockSize = 512;\n\t\t\tthis._rms = [];\n\t\t\tthis.toArray().forEach((channel) => {\n\t\t\t\tconst channelRMS = new Float32Array(channel.length);\n\t\t\t\tthis._rms?.push(channelRMS);\n\t\t\t\tfor (let i = 0; i < channel.length; i++) {\n\t\t\t\t\tconst sqrSum = channel\n\t\t\t\t\t\t.slice(i, i + blockSize)\n\t\t\t\t\t\t.reduce((total, value) => {\n\t\t\t\t\t\t\treturn total + value * value;\n\t\t\t\t\t\t}, 0);\n\t\t\t\t\tchannelRMS[i] = Math.sqrt(sqrSum / blockSize);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\tconst sampleTime = Math.floor(time * this._buffer.sampleRate);\n\t\tif (sampleTime < this._rms[0].length) {\n\t\t\tconst values = this._rms.map((rms) => rms[sampleTime]);\n\t\t\tif (values.length === 1) {\n\t\t\t\treturn values[0];\n\t\t\t} else {\n\t\t\t\treturn values;\n\t\t\t}\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t/**\n\t * Get the value of a sample at the given time. if the buffer has multiple\n\t * channels, will return an array.\n\t * @param time seconds\n\t */\n\tgetValueAtTime(time: number): number[] | number {\n\t\tconst sampleTime = Math.floor(time * this._buffer.sampleRate);\n\t\tconst array = this.toArray();\n\t\tif (sampleTime < array[0].length) {\n\t\t\tconst values = array.map((channel) => channel[sampleTime]);\n\t\t\tif (values.length === 1) {\n\t\t\t\treturn values[0];\n\t\t\t} else {\n\t\t\t\treturn values;\n\t\t\t}\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t/**\n\t * return the time in seconds of the first time\n\t * the AudioBuffer rose above the silence threshold\n\t */\n\tgetTimeOfFirstSound(threshold = 1e-6): number {\n\t\tconst firstSampleTimes = this.toArray().map((channel) => {\n\t\t\tfor (let i = 0; i < channel.length; i++) {\n\t\t\t\tconst sample = channel[i];\n\t\t\t\tif (sample > threshold) {\n\t\t\t\t\treturn i / this._buffer.sampleRate;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn -1;\n\t\t});\n\t\treturn Math.min(...firstSampleTimes);\n\t}\n\n\t/**\n\t * Return the last time a sample rose above the threshold\n\t * @param threshold\n\t */\n\tgetTimeOfLastSound(threshold = 1e-6): number {\n\t\tconst lastSampleTimes = this.toArray().map((channel) => {\n\t\t\tfor (let i = channel.length - 1; i >= 0; i--) {\n\t\t\t\tconst sample = channel[i];\n\t\t\t\tif (sample > threshold) {\n\t\t\t\t\treturn i / this._buffer.sampleRate;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn -1;\n\t\t});\n\t\treturn Math.max(...lastSampleTimes);\n\t}\n\n\t/**\n\t * The maximum sample value across all the channels\n\t */\n\tmax(): number {\n\t\tlet max = -Infinity;\n\t\tthis.toArray().forEach((channel) => {\n\t\t\tmax = Math.max(max, ...Array.from(channel));\n\t\t});\n\t\treturn max;\n\t}\n\n\t/**\n\t * The minimum sample value across all the channels\n\t */\n\tmin(): number {\n\t\tlet min = Infinity;\n\t\tthis.toArray().forEach((channel) => {\n\t\t\tmin = Math.min(min, ...Array.from(channel));\n\t\t});\n\t\treturn min;\n\t}\n\n\t/**\n\t * The value (only if it is consistent throughout the entire buffer).\n\t * Throws an error if there are multiple values found.\n\t */\n\tvalue(): number {\n\t\tconst max = this.max();\n\t\tconst min = this.min();\n\t\tif (max - min > 1e-6) {\n\t\t\tthrow new Error(\"multiple values found in this buffer\");\n\t\t}\n\t\treturn max;\n\t}\n\n\t/**\n\t * Test if the buffer has no audio data. if it is at or near 0 the entire buffer.\n\t */\n\tisSilent(threshold = 1e-6): boolean {\n\t\ttry {\n\t\t\treturn Math.abs(this.value()) < threshold;\n\t\t} catch (e) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Return a copy of the TestAudioBuffer\n\t */\n\tclone(): TestAudioBuffer {\n\t\t// should probably also clone the buffer\n\t\treturn new TestAudioBuffer(this._buffer);\n\t}\n\n\t/**\n\t * Return a new TestAudioBuffer at the given sample rate.\n\t * @param sampleRate a new sample rate to compute the buffer ar\n\t */\n\tasync resample(sampleRate: number): Promise<TestAudioBuffer> {\n\t\tconst offlineCtx = new OfflineAudioContext(\n\t\t\tthis._buffer.numberOfChannels,\n\t\t\tthis._buffer.duration * sampleRate,\n\t\t\tsampleRate\n\t\t);\n\t\tconst resampledBuffer = offlineCtx.createBuffer(\n\t\t\tthis._buffer.numberOfChannels,\n\t\t\tthis._buffer.length,\n\t\t\tthis._buffer.sampleRate\n\t\t);\n\n\t\t// Copy the source data into the offline AudioBuffer\n\t\tfor (\n\t\t\tlet channel = 0;\n\t\t\tchannel < resampledBuffer.numberOfChannels;\n\t\t\tchannel++\n\t\t) {\n\t\t\tresampledBuffer.copyToChannel(\n\t\t\t\tthis._buffer.getChannelData(channel),\n\t\t\t\tchannel\n\t\t\t);\n\t\t}\n\n\t\t// Play it from the beginning.\n\t\tconst source = offlineCtx.createBufferSource();\n\t\tsource.buffer = resampledBuffer;\n\t\tsource.connect(offlineCtx.destination);\n\t\tsource.start(0);\n\n\t\t// compute the results\n\t\tconst computedBuffer = await offlineCtx.startRendering();\n\t\treturn new TestAudioBuffer(computedBuffer);\n\t}\n\n\ttoWav(): ArrayBuffer {\n\t\t// check that the min and max are between -1 and 1\n\t\treturn toWav(this._buffer, {\n\t\t\tfloat32: false,\n\t\t});\n\t}\n\n\tdownloadWav(filename = \"test_audio\"): void {\n\t\tconst wave = this.toWav();\n\t\tconst blob = new Blob([wave], { type: \"audio/wav\" });\n\t\tconst blobUrl = window.URL.createObjectURL(blob);\n\t\tconst a = document.createElement(\"a\");\n\t\ta.href = blobUrl;\n\t\ta.download = filename;\n\t\ta.click();\n\t\twindow.URL.revokeObjectURL(blobUrl);\n\t}\n\n\tforEach(callback: (sample: number, time: number) => void): void {\n\t\tconst channels = this.toMono().toArray();\n\t\tchannels[0].forEach((sample, index) => {\n\t\t\tcallback(sample, index / this.sampleRate);\n\t\t});\n\t}\n\n\tforEachBetween(\n\t\tcallback: (sample: number, time: number) => void,\n\t\tstartTime = 0,\n\t\tendTime: number = this.duration\n\t): void {\n\t\tconst channels = this.toMono().toArray();\n\t\tconst startSamples = Math.floor(startTime * this.sampleRate);\n\t\tconst endSamples = Math.floor(\n\t\t\tMath.min(endTime * this.sampleRate, this.length)\n\t\t);\n\t\tfor (let s = startSamples; s < endSamples; s++) {\n\t\t\tconst sample = channels[0][s];\n\t\t\tcallback(sample, s / this.sampleRate);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "test/helper/compare/index.ts",
    "content": "import * as Compare from \"./Compare.js\";\nimport * as Plot from \"./Plot.js\";\nexport { OfflineRender as Offline } from \"./OfflineRender.js\";\nexport { PassesAudio } from \"./OfflineRender.js\";\nexport { MakesSound } from \"./OfflineRender.js\";\nexport { TestAudioBuffer } from \"./TestAudioBuffer.js\";\n\nexport { Compare, Plot };\n"
  },
  {
    "path": "test/integration/node/package.json",
    "content": "{\n\t\"name\": \"tone-node-test\",\n\t\"dependencies\": {\n\t\t\"tone\": \"file:../../..\"\n\t},\n\t\"scripts\": {\n\t\t\"test\": \"node test.mjs\"\n\t}\n}\n"
  },
  {
    "path": "test/integration/node/test.mjs",
    "content": "/**\n * @fileoverview Basic loading in node.js\n */\nimport assert from \"node:assert\";\nimport * as Tone from \"tone\";\n\nassert(\"MonoSynth\" in Tone, \"Tone missing expected export\");\nassert(\"start\" in Tone, \"Tone missing expected export\");\n"
  },
  {
    "path": "test/integration/typescript/package.json",
    "content": "{\n\t\"name\": \"tone-typescript-test\",\n\t\"dependencies\": {\n\t\t\"@types/node\": \"^20.12.8\",\n\t\t\"tone\": \"file:../../..\",\n\t\t\"typescript\": \"^5.4.5\"\n\t},\n\t\"scripts\": {\n\t\t\"test\": \"tsc ./test.ts --noEmit --lib dom\"\n\t}\n}\n"
  },
  {
    "path": "test/integration/typescript/test.ts",
    "content": "import * as Tone from \"tone\";\n\nconst synth = new Tone.MonoSynth();\n"
  },
  {
    "path": "test/integration/unpkg/package.json",
    "content": "{\n\t\"name\": \"tone-unpkg-test\",\n\t\"dependencies\": {\n\t\t\"puppeteer\": \"^22.7.1\",\n\t\t\"tone\": \"file:../../..\"\n\t},\n\t\"scripts\": {\n\t\t\"test\": \"node test.mjs\"\n\t}\n}\n"
  },
  {
    "path": "test/integration/unpkg/test.mjs",
    "content": "/**\n * @fileoverview Ensure that the unpkg link can be loaded in the browser\n */\nimport assert from \"node:assert\";\nimport { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport puppeteer from \"puppeteer\";\n\nconst __dirname = fileURLToPath(new URL(\".\", import.meta.url));\nconst rootDir = resolve(__dirname, \"../../../\");\nconst pkg = JSON.parse(\n\t(await readFile(resolve(rootDir, \"package.json\"))).toString()\n);\n\nconst browser = await puppeteer.launch({\n\theadless: true,\n\targs: [\"--no-sandbox\", \"--disable-setuid-sandbox\"],\n});\nconst page = await browser.newPage();\nawait page.addScriptTag({\n\tpath: resolve(rootDir, pkg.unpkg),\n});\nconst time = await page.evaluate(\"Tone.now()\");\nawait browser.close();\n\nassert(time >= 0, new Error(\"did not export a time value\"));\n"
  },
  {
    "path": "test/integration/vite/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"UTF-8\" />\n\t</head>\n\t<body>\n\t\t<script src=\"./index.ts\" type=\"module\"></script>\n\t</body>\n</html>\n"
  },
  {
    "path": "test/integration/vite/index.ts",
    "content": "import { MonoSynth } from \"tone\";\n\nconst synth = new MonoSynth();\n"
  },
  {
    "path": "test/integration/vite/package.json",
    "content": "{\n\t\"name\": \"tone-vite-test\",\n\t\"dependencies\": {\n\t\t\"tone\": \"file:../../..\",\n\t\t\"vite\": \"^5.2.11\"\n\t},\n\t\"scripts\": {\n\t\t\"test\": \"vite build ./\"\n\t}\n}\n"
  },
  {
    "path": "test/integration/webpack/package.json",
    "content": "{\n\t\"name\": \"tone-webpack-test\",\n\t\"type\": \"module\",\n\t\"dependencies\": {\n\t\t\"tone\": \"file:../../..\",\n\t\t\"webpack\": \"^5.91.0\",\n\t\t\"webpack-cli\": \"^5.1.4\"\n\t},\n\t\"scripts\": {\n\t\t\"test\": \"webpack ./test.js --target=web\"\n\t}\n}\n"
  },
  {
    "path": "test/integration/webpack/test.js",
    "content": "import { MonoSynth } from \"tone\";\n\nconst synth = new MonoSynth();\n"
  },
  {
    "path": "test/scripts/test_examples.mjs",
    "content": "import { createFixture } from \"fs-fixture\";\n\nimport toneJson from \"../../docs/tone.json\" with { type: \"json\" };\nimport { execPromise, ROOT_DIR } from \"./utils.mjs\";\n\n/**\n * Get all of the examples\n */\nfunction findExamples(obj) {\n\tconst examples = [];\n\n\tfunction traverse(node) {\n\t\tif (node.comment && node.comment.blockTags) {\n\t\t\tnode.comment.blockTags.forEach((tag) => {\n\t\t\t\tif (tag.tag === \"@example\") {\n\t\t\t\t\ttag.content.forEach((example) => {\n\t\t\t\t\t\texamples.push(\n\t\t\t\t\t\t\texample.text.trim().replace(/^```ts\\n|```$/g, \"\")\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t[\"children\", \"getSignature\", \"setSignature\", \"signatures\"].forEach(\n\t\t\t(prop) => {\n\t\t\t\tif (prop in node) {\n\t\t\t\t\tif (Array.isArray(node[prop])) {\n\t\t\t\t\t\tnode[prop].forEach((child) => traverse(child));\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttraverse(node[prop]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n\ttraverse(obj);\n\n\t// filter any repeats\n\treturn [...new Set(examples)];\n}\n\nasync function createFixtureFiles(examples) {\n\tconst createExampleString = (str) => `\nimport * as Tone from \"${ROOT_DIR}\"\nfunction main(){\n\t${str}\n}\nmain();\n`;\n\n\tconst data = {};\n\n\tfor (const [i, e] of Object.entries(examples)) {\n\t\tdata[`${i}.ts`] = createExampleString(e);\n\t}\n\n\treturn await createFixture(data);\n}\n\n/**\n * Run the string through the typescript compiler\n */\nasync function main() {\n\tconst examples = findExamples(toneJson);\n\tconst fixtures = await createFixtureFiles(examples);\n\n\tawait execPromise(\n\t\t`tsc --noEmit --target es5 --lib dom,ES2015 ${fixtures.path}/*.ts`\n\t);\n\n\tawait fixtures.rm();\n\n\tconsole.log(`Successfully tested ${examples.length} examples.`);\n}\n\nmain();\n"
  },
  {
    "path": "test/scripts/test_html.mjs",
    "content": "import { readFile } from \"node:fs/promises\";\nimport { basename, resolve } from \"node:path\";\n\nimport { createFixture } from \"fs-fixture\";\nimport { JSDOM } from \"jsdom\";\nimport { globSync } from \"tinyglobby\";\n\nimport { execPromise, ROOT_DIR } from \"./utils.mjs\";\n\nconst htmlFiles = globSync(resolve(ROOT_DIR, \"examples/*.html\"), { absolute: true });\n\nasync function createFixtureFiles(files) {\n\tconst createExampleString = (str) => `\nimport * as Tone from \"${ROOT_DIR}\"\nlet ui: any;\nlet drawer: any;\nlet meter: any;\nlet piano: any;\nlet fft: any;\nlet waveform: any;\nlet document: any;\nlet p5: any;\n${str}\n`;\n\n\tconst data = {};\n\n\tfor (const file of files) {\n\t\tconst name = basename(file).split(\".\")[0];\n\t\tconst html = await readFile(file, \"utf-8\");\n\t\tconst dom = new JSDOM(html);\n\t\tconst script = dom.window.document.querySelector(\"body script\");\n\n\t\tif (!script || !script.textContent) {\n\t\t\tconsole.warn(\"Could not get script contents: %s\", file);\n\t\t\tcontinue;\n\t\t};\n\n\t\tdata[`${name}.ts`] = createExampleString(script.textContent);\n\t}\n\n\treturn await createFixture(data);\n}\n\nasync function main() {\n\tconst fixtures = await createFixtureFiles(htmlFiles);\n\n\ttry {\n\t\tawait execPromise(\n\t\t\t`tsc --noEmit --target es5 --lib dom,ES2015 ${fixtures.path}/*.ts`\n\t\t);\n\t} catch (error) {\n\t\tif (error instanceof Error && error?.stdout) {\n\t\t\tconsole.warn(error.stdout);\n\t\t} else {\n\t\t\tthrow Error(\"Unexpected\", { cause: error });\n\t\t}\n\t}\n\n\tawait fixtures.rm();\n\n\tconsole.log(`Successfully tested ${htmlFiles.length} examples.`);\n}\n\nmain();\n"
  },
  {
    "path": "test/scripts/test_integrations.mjs",
    "content": "#!/usr/bin/env zx\nimport \"zx/globals\";\n\nimport { basename, resolve } from \"node:path\";\n\nimport { glob } from \"tinyglobby\";\n\nimport { ROOT_DIR } from \"./utils.mjs\";\n\nconst integrations = await glob(\n\tresolve(ROOT_DIR, \"test/integration/*\"),\n\t{ absolute: true, onlyDirectories: true }\n);\n\nfor (let dir of integrations) {\n\tawait within(async () => {\n\t\tcd(dir);\n\t\tconsole.log(\"Integration:\", basename(dir));\n\t\tawait $`npm i`;\n\t\tawait $`npm run test`;\n\t});\n}\n"
  },
  {
    "path": "test/scripts/test_readme.mjs",
    "content": "import { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\n\nimport { createFixture } from \"fs-fixture\";\nimport { JSDOM } from \"jsdom\";\nimport { marked } from \"marked\";\n\nimport { execPromise, ROOT_DIR } from \"./utils.mjs\";\n\nconst entry = \"README.md\";\n\nasync function findScripts() {\n\tconst readme = await readFile(resolve(ROOT_DIR, entry), \"utf-8\");\n\tconst html = await marked.parse(readme);\n\tconst dom = new JSDOM(html);\n\treturn dom.window.document.querySelectorAll(\"code.language-javascript\");\n}\n\nasync function createFixtureFiles(scripts) {\n\tconst createExampleString = (str) => `\nimport * as Tone from \"${ROOT_DIR}\"\n${str}\n`;\n\n\tconst data = {};\n\n\tfor (const [i, e] of Object.entries(scripts)) {\n\t\tdata[`${i}.ts`] = createExampleString(e.textContent);\n\t}\n\n\treturn await createFixture(data);\n}\n\nasync function main() {\n\tconst scripts = await findScripts();\n\tconst fixtures = await createFixtureFiles(scripts);\n\n\tawait execPromise(\n\t\t`tsc --noEmit --target es5 --lib dom,ES2015 ${fixtures.path}/*.ts`\n\t);\n\n\tawait fixtures.rm();\n\n\tconsole.log(\"Successfully tested %o scripts in %o\", scripts.length, entry);\n}\n\nmain();\n"
  },
  {
    "path": "test/scripts/utils.mjs",
    "content": "import { exec } from \"node:child_process\";\nimport { fileURLToPath } from \"node:url\";\nimport { promisify } from \"node:util\";\n\nexport const execPromise = promisify(exec);\n\n// trim trailing slash\nexport const ROOT_DIR = fileURLToPath(new URL(\"../..\", import.meta.url)).slice(0, -1);\n"
  },
  {
    "path": "test/web-test-runner.config.js",
    "content": "import { resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport rollupCommonjs from \"@rollup/plugin-commonjs\";\nimport { fromRollup } from \"@web/dev-server-rollup\";\nimport { puppeteerLauncher } from \"@web/test-runner-puppeteer\";\n\nconst __dirname = fileURLToPath(new URL(\".\", import.meta.url));\nconst commonjs = fromRollup(rollupCommonjs);\n\nconst BUILD_DIR = resolve(__dirname, \"../build/esm\");\n\nfunction getFilesInToneDir(dir) {\n\treturn [\n\t\tresolve(BUILD_DIR, \"Tone\", dir, \"**/*.test.js\"),\n\t\tresolve(BUILD_DIR, \"Tone\", dir, \"*.test.js\"),\n\t];\n}\n\nexport default {\n\tgroups: [\n\t\t{\n\t\t\tname: \"core\",\n\t\t\tfiles: [\n\t\t\t\t...getFilesInToneDir(\"core\"),\n\t\t\t\tresolve(BUILD_DIR, \"Tone/*.test.js\"),\n\t\t\t],\n\t\t},\n\t\t{\n\t\t\tname: \"component\",\n\t\t\tfiles: getFilesInToneDir(\"component\"),\n\t\t},\n\t\t{\n\t\t\tname: \"effect\",\n\t\t\tfiles: getFilesInToneDir(\"effect\"),\n\t\t},\n\t\t{\n\t\t\tname: \"event\",\n\t\t\tfiles: getFilesInToneDir(\"event\"),\n\t\t},\n\t\t{\n\t\t\tname: \"instrument\",\n\t\t\tfiles: getFilesInToneDir(\"instrument\"),\n\t\t},\n\t\t{\n\t\t\tname: \"signal\",\n\t\t\tfiles: getFilesInToneDir(\"signal\"),\n\t\t},\n\t\t{\n\t\t\tname: \"source\",\n\t\t\tfiles: getFilesInToneDir(\"source\"),\n\t\t},\n\t],\n\tnodeResolve: true,\n\tbrowsers: [\n\t\tpuppeteerLauncher({\n\t\t\tlaunchOptions: {\n\t\t\t\theadless: true,\n\t\t\t\targs: [\n\t\t\t\t\t\"--no-sandbox\",\n\t\t\t\t\t\"--disable-setuid-sandbox\",\n\t\t\t\t\t\"--use-fake-ui-for-media-stream\",\n\t\t\t\t\t\"--use-fake-device-for-media-stream\",\n\t\t\t\t\t\"--autoplay-policy=no-user-gesture-required\",\n\t\t\t\t],\n\t\t\t},\n\t\t}),\n\t],\n\ttestFramework: {\n\t\tconfig: {\n\t\t\ttimeout: 10000,\n\t\t\tretries: 2,\n\t\t\tui: \"bdd\",\n\t\t},\n\t},\n\tplugins: [\n\t\tcommonjs({\n\t\t\tinclude: [\"**/node_modules/**/*\"],\n\t\t}),\n\t],\n\trootDir: resolve(__dirname, \"../\"),\n\ttestRunnerHtml: (testFramework) =>\n\t\t`<!DOCTYPE html>\n\t\t\t<html>\n\t\t\t<body>\n\t\t\t\t<script>window.TONE_SILENCE_LOGGING = true</script>\n\t\t\t\t<script type=\"module\" src=\"${testFramework}\"></script>\n\t\t\t</body>\n\t\t</html>`,\n};\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n\t\"compileOnSave\": true,\n\t\"compilerOptions\": {\n\t\t\"strictNullChecks\": true,\n\t\t\"target\": \"ES6\",\n\t\t\"module\": \"Node16\",\n\t\t\"noImplicitAny\": false,\n\t\t\"importHelpers\": true,\n\t\t\"noUnusedLocals\": false,\n\t\t\"removeComments\": false,\n\t\t\"outDir\": \"./build/esm\",\n\t\t\"sourceMap\": true,\n\t\t\"esModuleInterop\": true,\n\t\t\"skipLibCheck\": true,\n\t\t\"moduleResolution\": \"Node16\",\n\t\t\"strictPropertyInitialization\": true,\n\t\t\"downlevelIteration\": true,\n\t\t\"experimentalDecorators\": true,\n\t\t\"lib\": [\"es6\", \"dom\", \"es2015\"],\n\t\t\"baseUrl\": \"./\",\n\t\t\"rootDir\": \"./\"\n\t},\n\t\"include\": [\"Tone/**/*.ts\", \"test/**/*.ts\"],\n\t\"exclude\": [\"node_modules\", \"test/integration/**\"]\n}\n"
  }
]