cacophony 0.9.4 → 0.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"cacophony.cjs.js","sources":["../src/bundles/phase-vocoder-bundle.js?url","../src/cache.ts","../src/filters.ts","../src/group.ts","../src/container.ts","../src/pannerMixin.ts","../src/volumeMixin.ts","../src/playback.ts","../src/sound.ts","../src/stream.ts","../src/oscillatorMixin.ts","../src/synthPlayback.ts","../src/synth.ts","../src/cacophony.ts"],"sourcesContent":["export default \"data:text/javascript;base64,KGZ1bmN0aW9uIChleHBvcnRzKSB7CiAgICAndXNlIHN0cmljdCc7CgogICAgY29uc3QgV0VCQVVESU9fQkxPQ0tfU0laRSA9IDEyODsKICAgIGNvbnN0IERFRkFVTFRfQkxPQ0tfU0laRSA9IDEwMjQ7IC8vIERlZmF1bHQgYmxvY2sgc2l6ZSBpZiBub3QgcHJvdmlkZWQgaW4gb3B0aW9ucwogICAgLyoqIE92ZXJsYXAtQWRkIE5vZGUgKi8KICAgIGNsYXNzIE9MQVByb2Nlc3NvciBleHRlbmRzIEF1ZGlvV29ya2xldFByb2Nlc3NvciB7CiAgICAgICAgbmJJbnB1dHM7CiAgICAgICAgbmJPdXRwdXRzOwogICAgICAgIGJsb2NrU2l6ZTsKICAgICAgICBob3BTaXplOwogICAgICAgIG5iT3ZlcmxhcHM7CiAgICAgICAgaW5wdXRCdWZmZXJzID0gW107CiAgICAgICAgaW5wdXRCdWZmZXJzSGVhZCA9IFtdOwogICAgICAgIGlucHV0QnVmZmVyc1RvU2VuZCA9IFtdOwogICAgICAgIG91dHB1dEJ1ZmZlcnMgPSBbXTsKICAgICAgICBvdXRwdXRCdWZmZXJzVG9SZXRyaWV2ZSA9IFtdOwogICAgICAgIGNvbnN0cnVjdG9yKG9wdGlvbnMpIHsKICAgICAgICAgICAgc3VwZXIob3B0aW9ucyk7CiAgICAgICAgICAgIHRoaXMubmJJbnB1dHMgPSBvcHRpb25zLm51bWJlck9mSW5wdXRzIHx8IDE7CiAgICAgICAgICAgIHRoaXMubmJPdXRwdXRzID0gb3B0aW9ucy5udW1iZXJPZk91dHB1dHMgfHwgMTsKICAgICAgICAgICAgdGhpcy5ibG9ja1NpemUgPSBvcHRpb25zLnByb2Nlc3Nvck9wdGlvbnMuYmxvY2tTaXplIHx8IERFRkFVTFRfQkxPQ0tfU0laRTsKICAgICAgICAgICAgdGhpcy5ob3BTaXplID0gV0VCQVVESU9fQkxPQ0tfU0laRTsKICAgICAgICAgICAgdGhpcy5uYk92ZXJsYXBzID0gTWF0aC5mbG9vcih0aGlzLmJsb2NrU2l6ZSAvIHRoaXMuaG9wU2l6ZSk7CiAgICAgICAgICAgIHRoaXMuaW5pdGlhbGl6ZUJ1ZmZlcnMoKTsKICAgICAgICB9CiAgICAgICAgaW5pdGlhbGl6ZUJ1ZmZlcnMoKSB7CiAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzID0gbmV3IEFycmF5KHRoaXMubmJJbnB1dHMpOwogICAgICAgICAgICB0aGlzLmlucHV0QnVmZmVyc0hlYWQgPSBuZXcgQXJyYXkodGhpcy5uYklucHV0cyk7CiAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzVG9TZW5kID0gbmV3IEFycmF5KHRoaXMubmJJbnB1dHMpOwogICAgICAgICAgICB0aGlzLm91dHB1dEJ1ZmZlcnMgPSBuZXcgQXJyYXkodGhpcy5uYk91dHB1dHMpOwogICAgICAgICAgICB0aGlzLm91dHB1dEJ1ZmZlcnNUb1JldHJpZXZlID0gbmV3IEFycmF5KHRoaXMubmJPdXRwdXRzKTsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm5iSW5wdXRzOyBpKyspIHsKICAgICAgICAgICAgICAgIHRoaXMuYWxsb2NhdGVJbnB1dENoYW5uZWxzKGksIDEpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5uYk91dHB1dHM7IGkrKykgewogICAgICAgICAgICAgICAgdGhpcy5hbGxvY2F0ZU91dHB1dENoYW5uZWxzKGksIDEpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGFsbG9jYXRlSW5wdXRDaGFubmVscyhpbnB1dEluZGV4LCBuYkNoYW5uZWxzKSB7CiAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzW2lucHV0SW5kZXhdID0gbmV3IEFycmF5KG5iQ2hhbm5lbHMpOwogICAgICAgICAgICB0aGlzLmlucHV0QnVmZmVyc0hlYWRbaW5wdXRJbmRleF0gPSBuZXcgQXJyYXkobmJDaGFubmVscyk7CiAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzVG9TZW5kW2lucHV0SW5kZXhdID0gbmV3IEFycmF5KG5iQ2hhbm5lbHMpOwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG5iQ2hhbm5lbHM7IGkrKykgewogICAgICAgICAgICAgICAgdGhpcy5pbnB1dEJ1ZmZlcnNbaW5wdXRJbmRleF1baV0gPSBuZXcgRmxvYXQzMkFycmF5KHRoaXMuYmxvY2tTaXplICsgV0VCQVVESU9fQkxPQ0tfU0laRSk7CiAgICAgICAgICAgICAgICB0aGlzLmlucHV0QnVmZmVyc1tpbnB1dEluZGV4XVtpXS5maWxsKDApOwogICAgICAgICAgICAgICAgdGhpcy5pbnB1dEJ1ZmZlcnNIZWFkW2lucHV0SW5kZXhdW2ldID0gdGhpcy5pbnB1dEJ1ZmZlcnNbaW5wdXRJbmRleF1baV0uc3ViYXJyYXkoMCwgdGhpcy5ibG9ja1NpemUpOwogICAgICAgICAgICAgICAgdGhpcy5pbnB1dEJ1ZmZlcnNUb1NlbmRbaW5wdXRJbmRleF1baV0gPSBuZXcgRmxvYXQzMkFycmF5KHRoaXMuYmxvY2tTaXplKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBhbGxvY2F0ZU91dHB1dENoYW5uZWxzKG91dHB1dEluZGV4LCBuYkNoYW5uZWxzKSB7CiAgICAgICAgICAgIHRoaXMub3V0cHV0QnVmZmVyc1tvdXRwdXRJbmRleF0gPSBuZXcgQXJyYXkobmJDaGFubmVscyk7CiAgICAgICAgICAgIHRoaXMub3V0cHV0QnVmZmVyc1RvUmV0cmlldmVbb3V0cHV0SW5kZXhdID0gbmV3IEFycmF5KG5iQ2hhbm5lbHMpOwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG5iQ2hhbm5lbHM7IGkrKykgewogICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRCdWZmZXJzW291dHB1dEluZGV4XVtpXSA9IG5ldyBGbG9hdDMyQXJyYXkodGhpcy5ibG9ja1NpemUpOwogICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRCdWZmZXJzW291dHB1dEluZGV4XVtpXS5maWxsKDApOwogICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRCdWZmZXJzVG9SZXRyaWV2ZVtvdXRwdXRJbmRleF1baV0gPSBuZXcgRmxvYXQzMkFycmF5KHRoaXMuYmxvY2tTaXplKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZWFsbG9jYXRlQ2hhbm5lbHNJZk5lZWRlZChpbnB1dHMsIG91dHB1dHMpIHsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm5iSW5wdXRzOyBpKyspIHsKICAgICAgICAgICAgICAgIGxldCBuYkNoYW5uZWxzID0gaW5wdXRzW2ldLmxlbmd0aDsKICAgICAgICAgICAgICAgIGlmIChuYkNoYW5uZWxzICE9PSB0aGlzLmlucHV0QnVmZmVyc1tpXS5sZW5ndGgpIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmFsbG9jYXRlSW5wdXRDaGFubmVscyhpLCBuYkNoYW5uZWxzKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJPdXRwdXRzOyBpKyspIHsKICAgICAgICAgICAgICAgIGxldCBuYkNoYW5uZWxzID0gb3V0cHV0c1tpXS5sZW5ndGg7CiAgICAgICAgICAgICAgICBpZiAobmJDaGFubmVscyAhPT0gdGhpcy5vdXRwdXRCdWZmZXJzW2ldLmxlbmd0aCkgewogICAgICAgICAgICAgICAgICAgIHRoaXMuYWxsb2NhdGVPdXRwdXRDaGFubmVscyhpLCBuYkNoYW5uZWxzKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZWFkSW5wdXRzKGlucHV0cykgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJJbnB1dHM7IGkrKykgewogICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCB0aGlzLmlucHV0QnVmZmVyc1tpXS5sZW5ndGg7IGorKykgewogICAgICAgICAgICAgICAgICAgIGxldCB3ZWJBdWRpb0Jsb2NrID0gaW5wdXRzW2ldW2pdOwogICAgICAgICAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzW2ldW2pdLnNldCh3ZWJBdWRpb0Jsb2NrLCB0aGlzLmJsb2NrU2l6ZSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgd3JpdGVPdXRwdXRzKG91dHB1dHMpIHsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm5iT3V0cHV0czsgaSsrKSB7CiAgICAgICAgICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IHRoaXMub3V0cHV0QnVmZmVyc1tpXS5sZW5ndGg7IGorKykgewogICAgICAgICAgICAgICAgICAgIGxldCB3ZWJBdWRpb0Jsb2NrID0gb3V0cHV0c1tpXVtqXTsKICAgICAgICAgICAgICAgICAgICB3ZWJBdWRpb0Jsb2NrLnNldCh0aGlzLm91dHB1dEJ1ZmZlcnNbaV1bal0uc3ViYXJyYXkoMCwgV0VCQVVESU9fQkxPQ0tfU0laRSkpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHNoaWZ0SW5wdXRCdWZmZXJzKCkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJJbnB1dHM7IGkrKykgewogICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCB0aGlzLmlucHV0QnVmZmVyc1tpXS5sZW5ndGg7IGorKykgewogICAgICAgICAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzW2ldW2pdLmNvcHlXaXRoaW4oMCwgV0VCQVVESU9fQkxPQ0tfU0laRSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgc2hpZnRPdXRwdXRCdWZmZXJzKCkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJPdXRwdXRzOyBpKyspIHsKICAgICAgICAgICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgdGhpcy5vdXRwdXRCdWZmZXJzW2ldLmxlbmd0aDsgaisrKSB7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRCdWZmZXJzW2ldW2pdLmNvcHlXaXRoaW4oMCwgV0VCQVVESU9fQkxPQ0tfU0laRSk7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRCdWZmZXJzW2ldW2pdLmZpbGwoMCwgdGhpcy5ibG9ja1NpemUgLSBXRUJBVURJT19CTE9DS19TSVpFKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBwcmVwYXJlSW5wdXRCdWZmZXJzVG9TZW5kKCkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJJbnB1dHM7IGkrKykgewogICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCB0aGlzLmlucHV0QnVmZmVyc1tpXS5sZW5ndGg7IGorKykgewogICAgICAgICAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzVG9TZW5kW2ldW2pdLnNldCh0aGlzLmlucHV0QnVmZmVyc0hlYWRbaV1bal0pOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGhhbmRsZU91dHB1dEJ1ZmZlcnNUb1JldHJpZXZlKCkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJPdXRwdXRzOyBpKyspIHsKICAgICAgICAgICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgdGhpcy5vdXRwdXRCdWZmZXJzW2ldLmxlbmd0aDsgaisrKSB7CiAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgayA9IDA7IGsgPCB0aGlzLmJsb2NrU2l6ZTsgaysrKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMub3V0cHV0QnVmZmVyc1tpXVtqXVtrXSArPSB0aGlzLm91dHB1dEJ1ZmZlcnNUb1JldHJpZXZlW2ldW2pdW2tdIC8gdGhpcy5uYk92ZXJsYXBzOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBwcm9jZXNzKGlucHV0cywgb3V0cHV0cywgcGFyYW1ldGVycykgewogICAgICAgICAgICB0aGlzLnJlYWxsb2NhdGVDaGFubmVsc0lmTmVlZGVkKGlucHV0cywgb3V0cHV0cyk7CiAgICAgICAgICAgIHRoaXMucmVhZElucHV0cyhpbnB1dHMpOwogICAgICAgICAgICB0aGlzLnNoaWZ0SW5wdXRCdWZmZXJzKCk7CiAgICAgICAgICAgIHRoaXMucHJlcGFyZUlucHV0QnVmZmVyc1RvU2VuZCgpOwogICAgICAgICAgICB0aGlzLnByb2Nlc3NPTEEodGhpcy5pbnB1dEJ1ZmZlcnNUb1NlbmQsIHRoaXMub3V0cHV0QnVmZmVyc1RvUmV0cmlldmUsIHBhcmFtZXRlcnMpOwogICAgICAgICAgICB0aGlzLmhhbmRsZU91dHB1dEJ1ZmZlcnNUb1JldHJpZXZlKCk7CiAgICAgICAgICAgIHRoaXMud3JpdGVPdXRwdXRzKG91dHB1dHMpOwogICAgICAgICAgICB0aGlzLnNoaWZ0T3V0cHV0QnVmZmVycygpOwogICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9CiAgICB9CgogICAgZnVuY3Rpb24gZ2V0RGVmYXVsdEV4cG9ydEZyb21DanMgKHgpIHsKICAgIAlyZXR1cm4geCAmJiB4Ll9fZXNNb2R1bGUgJiYgT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHgsICdkZWZhdWx0JykgPyB4WydkZWZhdWx0J10gOiB4OwogICAgfQoKICAgIGZ1bmN0aW9uIEZGVChzaXplKSB7CiAgICAgIHRoaXMuc2l6ZSA9IHNpemUgfCAwOwogICAgICBpZiAodGhpcy5zaXplIDw9IDEgfHwgKHRoaXMuc2l6ZSAmICh0aGlzLnNpemUgLSAxKSkgIT09IDApCiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdGRlQgc2l6ZSBtdXN0IGJlIGEgcG93ZXIgb2YgdHdvIGFuZCBiaWdnZXIgdGhhbiAxJyk7CgogICAgICB0aGlzLl9jc2l6ZSA9IHNpemUgPDwgMTsKCiAgICAgIC8vIE5PVEU6IFVzZSBvZiBgdmFyYCBpcyBpbnRlbnRpb25hbCBmb3Igb2xkIFY4IHZlcnNpb25zCiAgICAgIHZhciB0YWJsZSA9IG5ldyBBcnJheSh0aGlzLnNpemUgKiAyKTsKICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0YWJsZS5sZW5ndGg7IGkgKz0gMikgewogICAgICAgIGNvbnN0IGFuZ2xlID0gTWF0aC5QSSAqIGkgLyB0aGlzLnNpemU7CiAgICAgICAgdGFibGVbaV0gPSBNYXRoLmNvcyhhbmdsZSk7CiAgICAgICAgdGFibGVbaSArIDFdID0gLU1hdGguc2luKGFuZ2xlKTsKICAgICAgfQogICAgICB0aGlzLnRhYmxlID0gdGFibGU7CgogICAgICAvLyBGaW5kIHNpemUncyBwb3dlciBvZiB0d28KICAgICAgdmFyIHBvd2VyID0gMDsKICAgICAgZm9yICh2YXIgdCA9IDE7IHRoaXMuc2l6ZSA+IHQ7IHQgPDw9IDEpCiAgICAgICAgcG93ZXIrKzsKCiAgICAgIC8vIENhbGN1bGF0ZSBpbml0aWFsIHN0ZXAncyB3aWR0aDoKICAgICAgLy8gICAqIElmIHdlIGFyZSBmdWxsIHJhZGl4LTQgLSBpdCBpcyAyeCBzbWFsbGVyIHRvIGdpdmUgaW5pdGFsIGxlbj04CiAgICAgIC8vICAgKiBPdGhlcndpc2UgaXQgaXMgdGhlIHNhbWUgYXMgYHBvd2VyYCB0byBnaXZlIGxlbj00CiAgICAgIHRoaXMuX3dpZHRoID0gcG93ZXIgJSAyID09PSAwID8gcG93ZXIgLSAxIDogcG93ZXI7CgogICAgICAvLyBQcmUtY29tcHV0ZSBiaXQtcmV2ZXJzYWwgcGF0dGVybnMKICAgICAgdGhpcy5fYml0cmV2ID0gbmV3IEFycmF5KDEgPDwgdGhpcy5fd2lkdGgpOwogICAgICBmb3IgKHZhciBqID0gMDsgaiA8IHRoaXMuX2JpdHJldi5sZW5ndGg7IGorKykgewogICAgICAgIHRoaXMuX2JpdHJldltqXSA9IDA7CiAgICAgICAgZm9yICh2YXIgc2hpZnQgPSAwOyBzaGlmdCA8IHRoaXMuX3dpZHRoOyBzaGlmdCArPSAyKSB7CiAgICAgICAgICB2YXIgcmV2U2hpZnQgPSB0aGlzLl93aWR0aCAtIHNoaWZ0IC0gMjsKICAgICAgICAgIHRoaXMuX2JpdHJldltqXSB8PSAoKGogPj4+IHNoaWZ0KSAmIDMpIDw8IHJldlNoaWZ0OwogICAgICAgIH0KICAgICAgfQoKICAgICAgdGhpcy5fb3V0ID0gbnVsbDsKICAgICAgdGhpcy5fZGF0YSA9IG51bGw7CiAgICAgIHRoaXMuX2ludiA9IDA7CiAgICB9CiAgICB2YXIgZmZ0ID0gRkZUOwoKICAgIEZGVC5wcm90b3R5cGUuZnJvbUNvbXBsZXhBcnJheSA9IGZ1bmN0aW9uIGZyb21Db21wbGV4QXJyYXkoY29tcGxleCwgc3RvcmFnZSkgewogICAgICB2YXIgcmVzID0gc3RvcmFnZSB8fCBuZXcgQXJyYXkoY29tcGxleC5sZW5ndGggPj4+IDEpOwogICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNvbXBsZXgubGVuZ3RoOyBpICs9IDIpCiAgICAgICAgcmVzW2kgPj4+IDFdID0gY29tcGxleFtpXTsKICAgICAgcmV0dXJuIHJlczsKICAgIH07CgogICAgRkZULnByb3RvdHlwZS5jcmVhdGVDb21wbGV4QXJyYXkgPSBmdW5jdGlvbiBjcmVhdGVDb21wbGV4QXJyYXkoKSB7CiAgICAgIGNvbnN0IHJlcyA9IG5ldyBBcnJheSh0aGlzLl9jc2l6ZSk7CiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcmVzLmxlbmd0aDsgaSsrKQogICAgICAgIHJlc1tpXSA9IDA7CiAgICAgIHJldHVybiByZXM7CiAgICB9OwoKICAgIEZGVC5wcm90b3R5cGUudG9Db21wbGV4QXJyYXkgPSBmdW5jdGlvbiB0b0NvbXBsZXhBcnJheShpbnB1dCwgc3RvcmFnZSkgewogICAgICB2YXIgcmVzID0gc3RvcmFnZSB8fCB0aGlzLmNyZWF0ZUNvbXBsZXhBcnJheSgpOwogICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHJlcy5sZW5ndGg7IGkgKz0gMikgewogICAgICAgIHJlc1tpXSA9IGlucHV0W2kgPj4+IDFdOwogICAgICAgIHJlc1tpICsgMV0gPSAwOwogICAgICB9CiAgICAgIHJldHVybiByZXM7CiAgICB9OwoKICAgIEZGVC5wcm90b3R5cGUuY29tcGxldGVTcGVjdHJ1bSA9IGZ1bmN0aW9uIGNvbXBsZXRlU3BlY3RydW0oc3BlY3RydW0pIHsKICAgICAgdmFyIHNpemUgPSB0aGlzLl9jc2l6ZTsKICAgICAgdmFyIGhhbGYgPSBzaXplID4+PiAxOwogICAgICBmb3IgKHZhciBpID0gMjsgaSA8IGhhbGY7IGkgKz0gMikgewogICAgICAgIHNwZWN0cnVtW3NpemUgLSBpXSA9IHNwZWN0cnVtW2ldOwogICAgICAgIHNwZWN0cnVtW3NpemUgLSBpICsgMV0gPSAtc3BlY3RydW1baSArIDFdOwogICAgICB9CiAgICB9OwoKICAgIEZGVC5wcm90b3R5cGUudHJhbnNmb3JtID0gZnVuY3Rpb24gdHJhbnNmb3JtKG91dCwgZGF0YSkgewogICAgICBpZiAob3V0ID09PSBkYXRhKQogICAgICAgIHRocm93IG5ldyBFcnJvcignSW5wdXQgYW5kIG91dHB1dCBidWZmZXJzIG11c3QgYmUgZGlmZmVyZW50Jyk7CgogICAgICB0aGlzLl9vdXQgPSBvdXQ7CiAgICAgIHRoaXMuX2RhdGEgPSBkYXRhOwogICAgICB0aGlzLl9pbnYgPSAwOwogICAgICB0aGlzLl90cmFuc2Zvcm00KCk7CiAgICAgIHRoaXMuX291dCA9IG51bGw7CiAgICAgIHRoaXMuX2RhdGEgPSBudWxsOwogICAgfTsKCiAgICBGRlQucHJvdG90eXBlLnJlYWxUcmFuc2Zvcm0gPSBmdW5jdGlvbiByZWFsVHJhbnNmb3JtKG91dCwgZGF0YSkgewogICAgICBpZiAob3V0ID09PSBkYXRhKQogICAgICAgIHRocm93IG5ldyBFcnJvcignSW5wdXQgYW5kIG91dHB1dCBidWZmZXJzIG11c3QgYmUgZGlmZmVyZW50Jyk7CgogICAgICB0aGlzLl9vdXQgPSBvdXQ7CiAgICAgIHRoaXMuX2RhdGEgPSBkYXRhOwogICAgICB0aGlzLl9pbnYgPSAwOwogICAgICB0aGlzLl9yZWFsVHJhbnNmb3JtNCgpOwogICAgICB0aGlzLl9vdXQgPSBudWxsOwogICAgICB0aGlzLl9kYXRhID0gbnVsbDsKICAgIH07CgogICAgRkZULnByb3RvdHlwZS5pbnZlcnNlVHJhbnNmb3JtID0gZnVuY3Rpb24gaW52ZXJzZVRyYW5zZm9ybShvdXQsIGRhdGEpIHsKICAgICAgaWYgKG91dCA9PT0gZGF0YSkKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0lucHV0IGFuZCBvdXRwdXQgYnVmZmVycyBtdXN0IGJlIGRpZmZlcmVudCcpOwoKICAgICAgdGhpcy5fb3V0ID0gb3V0OwogICAgICB0aGlzLl9kYXRhID0gZGF0YTsKICAgICAgdGhpcy5faW52ID0gMTsKICAgICAgdGhpcy5fdHJhbnNmb3JtNCgpOwogICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG91dC5sZW5ndGg7IGkrKykKICAgICAgICBvdXRbaV0gLz0gdGhpcy5zaXplOwogICAgICB0aGlzLl9vdXQgPSBudWxsOwogICAgICB0aGlzLl9kYXRhID0gbnVsbDsKICAgIH07CgogICAgLy8gcmFkaXgtNCBpbXBsZW1lbnRhdGlvbgogICAgLy8KICAgIC8vIE5PVEU6IFVzZXMgb2YgYHZhcmAgYXJlIGludGVudGlvbmFsIGZvciBvbGRlciBWOCB2ZXJzaW9uIHRoYXQgZG8gbm90CiAgICAvLyBzdXBwb3J0IGJvdGggYGxldCBjb21wb3VuZCBhc3NpZ25tZW50c2AgYW5kIGBjb25zdCBwaGlgCiAgICBGRlQucHJvdG90eXBlLl90cmFuc2Zvcm00ID0gZnVuY3Rpb24gX3RyYW5zZm9ybTQoKSB7CiAgICAgIHZhciBvdXQgPSB0aGlzLl9vdXQ7CiAgICAgIHZhciBzaXplID0gdGhpcy5fY3NpemU7CgogICAgICAvLyBJbml0aWFsIHN0ZXAgKHBlcm11dGUgYW5kIHRyYW5zZm9ybSkKICAgICAgdmFyIHdpZHRoID0gdGhpcy5fd2lkdGg7CiAgICAgIHZhciBzdGVwID0gMSA8PCB3aWR0aDsKICAgICAgdmFyIGxlbiA9IChzaXplIC8gc3RlcCkgPDwgMTsKCiAgICAgIHZhciBvdXRPZmY7CiAgICAgIHZhciB0OwogICAgICB2YXIgYml0cmV2ID0gdGhpcy5fYml0cmV2OwogICAgICBpZiAobGVuID09PSA0KSB7CiAgICAgICAgZm9yIChvdXRPZmYgPSAwLCB0ID0gMDsgb3V0T2ZmIDwgc2l6ZTsgb3V0T2ZmICs9IGxlbiwgdCsrKSB7CiAgICAgICAgICBjb25zdCBvZmYgPSBiaXRyZXZbdF07CiAgICAgICAgICB0aGlzLl9zaW5nbGVUcmFuc2Zvcm0yKG91dE9mZiwgb2ZmLCBzdGVwKTsKICAgICAgICB9CiAgICAgIH0gZWxzZSB7CiAgICAgICAgLy8gbGVuID09PSA4CiAgICAgICAgZm9yIChvdXRPZmYgPSAwLCB0ID0gMDsgb3V0T2ZmIDwgc2l6ZTsgb3V0T2ZmICs9IGxlbiwgdCsrKSB7CiAgICAgICAgICBjb25zdCBvZmYgPSBiaXRyZXZbdF07CiAgICAgICAgICB0aGlzLl9zaW5nbGVUcmFuc2Zvcm00KG91dE9mZiwgb2ZmLCBzdGVwKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8vIExvb3AgdGhyb3VnaCBzdGVwcyBpbiBkZWNyZWFzaW5nIG9yZGVyCiAgICAgIHZhciBpbnYgPSB0aGlzLl9pbnYgPyAtMSA6IDE7CiAgICAgIHZhciB0YWJsZSA9IHRoaXMudGFibGU7CiAgICAgIGZvciAoc3RlcCA+Pj0gMjsgc3RlcCA+PSAyOyBzdGVwID4+PSAyKSB7CiAgICAgICAgbGVuID0gKHNpemUgLyBzdGVwKSA8PCAxOwogICAgICAgIHZhciBxdWFydGVyTGVuID0gbGVuID4+PiAyOwoKICAgICAgICAvLyBMb29wIHRocm91Z2ggb2Zmc2V0cyBpbiB0aGUgZGF0YQogICAgICAgIGZvciAob3V0T2ZmID0gMDsgb3V0T2ZmIDwgc2l6ZTsgb3V0T2ZmICs9IGxlbikgewogICAgICAgICAgLy8gRnVsbCBjYXNlCiAgICAgICAgICB2YXIgbGltaXQgPSBvdXRPZmYgKyBxdWFydGVyTGVuOwogICAgICAgICAgZm9yICh2YXIgaSA9IG91dE9mZiwgayA9IDA7IGkgPCBsaW1pdDsgaSArPSAyLCBrICs9IHN0ZXApIHsKICAgICAgICAgICAgY29uc3QgQSA9IGk7CiAgICAgICAgICAgIGNvbnN0IEIgPSBBICsgcXVhcnRlckxlbjsKICAgICAgICAgICAgY29uc3QgQyA9IEIgKyBxdWFydGVyTGVuOwogICAgICAgICAgICBjb25zdCBEID0gQyArIHF1YXJ0ZXJMZW47CgogICAgICAgICAgICAvLyBPcmlnaW5hbCB2YWx1ZXMKICAgICAgICAgICAgY29uc3QgQXIgPSBvdXRbQV07CiAgICAgICAgICAgIGNvbnN0IEFpID0gb3V0W0EgKyAxXTsKICAgICAgICAgICAgY29uc3QgQnIgPSBvdXRbQl07CiAgICAgICAgICAgIGNvbnN0IEJpID0gb3V0W0IgKyAxXTsKICAgICAgICAgICAgY29uc3QgQ3IgPSBvdXRbQ107CiAgICAgICAgICAgIGNvbnN0IENpID0gb3V0W0MgKyAxXTsKICAgICAgICAgICAgY29uc3QgRHIgPSBvdXRbRF07CiAgICAgICAgICAgIGNvbnN0IERpID0gb3V0W0QgKyAxXTsKCiAgICAgICAgICAgIC8vIE1pZGRsZSB2YWx1ZXMKICAgICAgICAgICAgY29uc3QgTUFyID0gQXI7CiAgICAgICAgICAgIGNvbnN0IE1BaSA9IEFpOwoKICAgICAgICAgICAgY29uc3QgdGFibGVCciA9IHRhYmxlW2tdOwogICAgICAgICAgICBjb25zdCB0YWJsZUJpID0gaW52ICogdGFibGVbayArIDFdOwogICAgICAgICAgICBjb25zdCBNQnIgPSBCciAqIHRhYmxlQnIgLSBCaSAqIHRhYmxlQmk7CiAgICAgICAgICAgIGNvbnN0IE1CaSA9IEJyICogdGFibGVCaSArIEJpICogdGFibGVCcjsKCiAgICAgICAgICAgIGNvbnN0IHRhYmxlQ3IgPSB0YWJsZVsyICoga107CiAgICAgICAgICAgIGNvbnN0IHRhYmxlQ2kgPSBpbnYgKiB0YWJsZVsyICogayArIDFdOwogICAgICAgICAgICBjb25zdCBNQ3IgPSBDciAqIHRhYmxlQ3IgLSBDaSAqIHRhYmxlQ2k7CiAgICAgICAgICAgIGNvbnN0IE1DaSA9IENyICogdGFibGVDaSArIENpICogdGFibGVDcjsKCiAgICAgICAgICAgIGNvbnN0IHRhYmxlRHIgPSB0YWJsZVszICoga107CiAgICAgICAgICAgIGNvbnN0IHRhYmxlRGkgPSBpbnYgKiB0YWJsZVszICogayArIDFdOwogICAgICAgICAgICBjb25zdCBNRHIgPSBEciAqIHRhYmxlRHIgLSBEaSAqIHRhYmxlRGk7CiAgICAgICAgICAgIGNvbnN0IE1EaSA9IERyICogdGFibGVEaSArIERpICogdGFibGVEcjsKCiAgICAgICAgICAgIC8vIFByZS1GaW5hbCB2YWx1ZXMKICAgICAgICAgICAgY29uc3QgVDByID0gTUFyICsgTUNyOwogICAgICAgICAgICBjb25zdCBUMGkgPSBNQWkgKyBNQ2k7CiAgICAgICAgICAgIGNvbnN0IFQxciA9IE1BciAtIE1DcjsKICAgICAgICAgICAgY29uc3QgVDFpID0gTUFpIC0gTUNpOwogICAgICAgICAgICBjb25zdCBUMnIgPSBNQnIgKyBNRHI7CiAgICAgICAgICAgIGNvbnN0IFQyaSA9IE1CaSArIE1EaTsKICAgICAgICAgICAgY29uc3QgVDNyID0gaW52ICogKE1CciAtIE1Ecik7CiAgICAgICAgICAgIGNvbnN0IFQzaSA9IGludiAqIChNQmkgLSBNRGkpOwoKICAgICAgICAgICAgLy8gRmluYWwgdmFsdWVzCiAgICAgICAgICAgIGNvbnN0IEZBciA9IFQwciArIFQycjsKICAgICAgICAgICAgY29uc3QgRkFpID0gVDBpICsgVDJpOwoKICAgICAgICAgICAgY29uc3QgRkNyID0gVDByIC0gVDJyOwogICAgICAgICAgICBjb25zdCBGQ2kgPSBUMGkgLSBUMmk7CgogICAgICAgICAgICBjb25zdCBGQnIgPSBUMXIgKyBUM2k7CiAgICAgICAgICAgIGNvbnN0IEZCaSA9IFQxaSAtIFQzcjsKCiAgICAgICAgICAgIGNvbnN0IEZEciA9IFQxciAtIFQzaTsKICAgICAgICAgICAgY29uc3QgRkRpID0gVDFpICsgVDNyOwoKICAgICAgICAgICAgb3V0W0FdID0gRkFyOwogICAgICAgICAgICBvdXRbQSArIDFdID0gRkFpOwogICAgICAgICAgICBvdXRbQl0gPSBGQnI7CiAgICAgICAgICAgIG91dFtCICsgMV0gPSBGQmk7CiAgICAgICAgICAgIG91dFtDXSA9IEZDcjsKICAgICAgICAgICAgb3V0W0MgKyAxXSA9IEZDaTsKICAgICAgICAgICAgb3V0W0RdID0gRkRyOwogICAgICAgICAgICBvdXRbRCArIDFdID0gRkRpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgfTsKCiAgICAvLyByYWRpeC0yIGltcGxlbWVudGF0aW9uCiAgICAvLwogICAgLy8gTk9URTogT25seSBjYWxsZWQgZm9yIGxlbj00CiAgICBGRlQucHJvdG90eXBlLl9zaW5nbGVUcmFuc2Zvcm0yID0gZnVuY3Rpb24gX3NpbmdsZVRyYW5zZm9ybTIob3V0T2ZmLCBvZmYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcCkgewogICAgICBjb25zdCBvdXQgPSB0aGlzLl9vdXQ7CiAgICAgIGNvbnN0IGRhdGEgPSB0aGlzLl9kYXRhOwoKICAgICAgY29uc3QgZXZlblIgPSBkYXRhW29mZl07CiAgICAgIGNvbnN0IGV2ZW5JID0gZGF0YVtvZmYgKyAxXTsKICAgICAgY29uc3Qgb2RkUiA9IGRhdGFbb2ZmICsgc3RlcF07CiAgICAgIGNvbnN0IG9kZEkgPSBkYXRhW29mZiArIHN0ZXAgKyAxXTsKCiAgICAgIGNvbnN0IGxlZnRSID0gZXZlblIgKyBvZGRSOwogICAgICBjb25zdCBsZWZ0SSA9IGV2ZW5JICsgb2RkSTsKICAgICAgY29uc3QgcmlnaHRSID0gZXZlblIgLSBvZGRSOwogICAgICBjb25zdCByaWdodEkgPSBldmVuSSAtIG9kZEk7CgogICAgICBvdXRbb3V0T2ZmXSA9IGxlZnRSOwogICAgICBvdXRbb3V0T2ZmICsgMV0gPSBsZWZ0STsKICAgICAgb3V0W291dE9mZiArIDJdID0gcmlnaHRSOwogICAgICBvdXRbb3V0T2ZmICsgM10gPSByaWdodEk7CiAgICB9OwoKICAgIC8vIHJhZGl4LTQKICAgIC8vCiAgICAvLyBOT1RFOiBPbmx5IGNhbGxlZCBmb3IgbGVuPTgKICAgIEZGVC5wcm90b3R5cGUuX3NpbmdsZVRyYW5zZm9ybTQgPSBmdW5jdGlvbiBfc2luZ2xlVHJhbnNmb3JtNChvdXRPZmYsIG9mZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwKSB7CiAgICAgIGNvbnN0IG91dCA9IHRoaXMuX291dDsKICAgICAgY29uc3QgZGF0YSA9IHRoaXMuX2RhdGE7CiAgICAgIGNvbnN0IGludiA9IHRoaXMuX2ludiA/IC0xIDogMTsKICAgICAgY29uc3Qgc3RlcDIgPSBzdGVwICogMjsKICAgICAgY29uc3Qgc3RlcDMgPSBzdGVwICogMzsKCiAgICAgIC8vIE9yaWdpbmFsIHZhbHVlcwogICAgICBjb25zdCBBciA9IGRhdGFbb2ZmXTsKICAgICAgY29uc3QgQWkgPSBkYXRhW29mZiArIDFdOwogICAgICBjb25zdCBCciA9IGRhdGFbb2ZmICsgc3RlcF07CiAgICAgIGNvbnN0IEJpID0gZGF0YVtvZmYgKyBzdGVwICsgMV07CiAgICAgIGNvbnN0IENyID0gZGF0YVtvZmYgKyBzdGVwMl07CiAgICAgIGNvbnN0IENpID0gZGF0YVtvZmYgKyBzdGVwMiArIDFdOwogICAgICBjb25zdCBEciA9IGRhdGFbb2ZmICsgc3RlcDNdOwogICAgICBjb25zdCBEaSA9IGRhdGFbb2ZmICsgc3RlcDMgKyAxXTsKCiAgICAgIC8vIFByZS1GaW5hbCB2YWx1ZXMKICAgICAgY29uc3QgVDByID0gQXIgKyBDcjsKICAgICAgY29uc3QgVDBpID0gQWkgKyBDaTsKICAgICAgY29uc3QgVDFyID0gQXIgLSBDcjsKICAgICAgY29uc3QgVDFpID0gQWkgLSBDaTsKICAgICAgY29uc3QgVDJyID0gQnIgKyBEcjsKICAgICAgY29uc3QgVDJpID0gQmkgKyBEaTsKICAgICAgY29uc3QgVDNyID0gaW52ICogKEJyIC0gRHIpOwogICAgICBjb25zdCBUM2kgPSBpbnYgKiAoQmkgLSBEaSk7CgogICAgICAvLyBGaW5hbCB2YWx1ZXMKICAgICAgY29uc3QgRkFyID0gVDByICsgVDJyOwogICAgICBjb25zdCBGQWkgPSBUMGkgKyBUMmk7CgogICAgICBjb25zdCBGQnIgPSBUMXIgKyBUM2k7CiAgICAgIGNvbnN0IEZCaSA9IFQxaSAtIFQzcjsKCiAgICAgIGNvbnN0IEZDciA9IFQwciAtIFQycjsKICAgICAgY29uc3QgRkNpID0gVDBpIC0gVDJpOwoKICAgICAgY29uc3QgRkRyID0gVDFyIC0gVDNpOwogICAgICBjb25zdCBGRGkgPSBUMWkgKyBUM3I7CgogICAgICBvdXRbb3V0T2ZmXSA9IEZBcjsKICAgICAgb3V0W291dE9mZiArIDFdID0gRkFpOwogICAgICBvdXRbb3V0T2ZmICsgMl0gPSBGQnI7CiAgICAgIG91dFtvdXRPZmYgKyAzXSA9IEZCaTsKICAgICAgb3V0W291dE9mZiArIDRdID0gRkNyOwogICAgICBvdXRbb3V0T2ZmICsgNV0gPSBGQ2k7CiAgICAgIG91dFtvdXRPZmYgKyA2XSA9IEZEcjsKICAgICAgb3V0W291dE9mZiArIDddID0gRkRpOwogICAgfTsKCiAgICAvLyBSZWFsIGlucHV0IHJhZGl4LTQgaW1wbGVtZW50YXRpb24KICAgIEZGVC5wcm90b3R5cGUuX3JlYWxUcmFuc2Zvcm00ID0gZnVuY3Rpb24gX3JlYWxUcmFuc2Zvcm00KCkgewogICAgICB2YXIgb3V0ID0gdGhpcy5fb3V0OwogICAgICB2YXIgc2l6ZSA9IHRoaXMuX2NzaXplOwoKICAgICAgLy8gSW5pdGlhbCBzdGVwIChwZXJtdXRlIGFuZCB0cmFuc2Zvcm0pCiAgICAgIHZhciB3aWR0aCA9IHRoaXMuX3dpZHRoOwogICAgICB2YXIgc3RlcCA9IDEgPDwgd2lkdGg7CiAgICAgIHZhciBsZW4gPSAoc2l6ZSAvIHN0ZXApIDw8IDE7CgogICAgICB2YXIgb3V0T2ZmOwogICAgICB2YXIgdDsKICAgICAgdmFyIGJpdHJldiA9IHRoaXMuX2JpdHJldjsKICAgICAgaWYgKGxlbiA9PT0gNCkgewogICAgICAgIGZvciAob3V0T2ZmID0gMCwgdCA9IDA7IG91dE9mZiA8IHNpemU7IG91dE9mZiArPSBsZW4sIHQrKykgewogICAgICAgICAgY29uc3Qgb2ZmID0gYml0cmV2W3RdOwogICAgICAgICAgdGhpcy5fc2luZ2xlUmVhbFRyYW5zZm9ybTIob3V0T2ZmLCBvZmYgPj4+IDEsIHN0ZXAgPj4+IDEpOwogICAgICAgIH0KICAgICAgfSBlbHNlIHsKICAgICAgICAvLyBsZW4gPT09IDgKICAgICAgICBmb3IgKG91dE9mZiA9IDAsIHQgPSAwOyBvdXRPZmYgPCBzaXplOyBvdXRPZmYgKz0gbGVuLCB0KyspIHsKICAgICAgICAgIGNvbnN0IG9mZiA9IGJpdHJldlt0XTsKICAgICAgICAgIHRoaXMuX3NpbmdsZVJlYWxUcmFuc2Zvcm00KG91dE9mZiwgb2ZmID4+PiAxLCBzdGVwID4+PiAxKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8vIExvb3AgdGhyb3VnaCBzdGVwcyBpbiBkZWNyZWFzaW5nIG9yZGVyCiAgICAgIHZhciBpbnYgPSB0aGlzLl9pbnYgPyAtMSA6IDE7CiAgICAgIHZhciB0YWJsZSA9IHRoaXMudGFibGU7CiAgICAgIGZvciAoc3RlcCA+Pj0gMjsgc3RlcCA+PSAyOyBzdGVwID4+PSAyKSB7CiAgICAgICAgbGVuID0gKHNpemUgLyBzdGVwKSA8PCAxOwogICAgICAgIHZhciBoYWxmTGVuID0gbGVuID4+PiAxOwogICAgICAgIHZhciBxdWFydGVyTGVuID0gaGFsZkxlbiA+Pj4gMTsKICAgICAgICB2YXIgaHF1YXJ0ZXJMZW4gPSBxdWFydGVyTGVuID4+PiAxOwoKICAgICAgICAvLyBMb29wIHRocm91Z2ggb2Zmc2V0cyBpbiB0aGUgZGF0YQogICAgICAgIGZvciAob3V0T2ZmID0gMDsgb3V0T2ZmIDwgc2l6ZTsgb3V0T2ZmICs9IGxlbikgewogICAgICAgICAgZm9yICh2YXIgaSA9IDAsIGsgPSAwOyBpIDw9IGhxdWFydGVyTGVuOyBpICs9IDIsIGsgKz0gc3RlcCkgewogICAgICAgICAgICB2YXIgQSA9IG91dE9mZiArIGk7CiAgICAgICAgICAgIHZhciBCID0gQSArIHF1YXJ0ZXJMZW47CiAgICAgICAgICAgIHZhciBDID0gQiArIHF1YXJ0ZXJMZW47CiAgICAgICAgICAgIHZhciBEID0gQyArIHF1YXJ0ZXJMZW47CgogICAgICAgICAgICAvLyBPcmlnaW5hbCB2YWx1ZXMKICAgICAgICAgICAgdmFyIEFyID0gb3V0W0FdOwogICAgICAgICAgICB2YXIgQWkgPSBvdXRbQSArIDFdOwogICAgICAgICAgICB2YXIgQnIgPSBvdXRbQl07CiAgICAgICAgICAgIHZhciBCaSA9IG91dFtCICsgMV07CiAgICAgICAgICAgIHZhciBDciA9IG91dFtDXTsKICAgICAgICAgICAgdmFyIENpID0gb3V0W0MgKyAxXTsKICAgICAgICAgICAgdmFyIERyID0gb3V0W0RdOwogICAgICAgICAgICB2YXIgRGkgPSBvdXRbRCArIDFdOwoKICAgICAgICAgICAgLy8gTWlkZGxlIHZhbHVlcwogICAgICAgICAgICB2YXIgTUFyID0gQXI7CiAgICAgICAgICAgIHZhciBNQWkgPSBBaTsKCiAgICAgICAgICAgIHZhciB0YWJsZUJyID0gdGFibGVba107CiAgICAgICAgICAgIHZhciB0YWJsZUJpID0gaW52ICogdGFibGVbayArIDFdOwogICAgICAgICAgICB2YXIgTUJyID0gQnIgKiB0YWJsZUJyIC0gQmkgKiB0YWJsZUJpOwogICAgICAgICAgICB2YXIgTUJpID0gQnIgKiB0YWJsZUJpICsgQmkgKiB0YWJsZUJyOwoKICAgICAgICAgICAgdmFyIHRhYmxlQ3IgPSB0YWJsZVsyICoga107CiAgICAgICAgICAgIHZhciB0YWJsZUNpID0gaW52ICogdGFibGVbMiAqIGsgKyAxXTsKICAgICAgICAgICAgdmFyIE1DciA9IENyICogdGFibGVDciAtIENpICogdGFibGVDaTsKICAgICAgICAgICAgdmFyIE1DaSA9IENyICogdGFibGVDaSArIENpICogdGFibGVDcjsKCiAgICAgICAgICAgIHZhciB0YWJsZURyID0gdGFibGVbMyAqIGtdOwogICAgICAgICAgICB2YXIgdGFibGVEaSA9IGludiAqIHRhYmxlWzMgKiBrICsgMV07CiAgICAgICAgICAgIHZhciBNRHIgPSBEciAqIHRhYmxlRHIgLSBEaSAqIHRhYmxlRGk7CiAgICAgICAgICAgIHZhciBNRGkgPSBEciAqIHRhYmxlRGkgKyBEaSAqIHRhYmxlRHI7CgogICAgICAgICAgICAvLyBQcmUtRmluYWwgdmFsdWVzCiAgICAgICAgICAgIHZhciBUMHIgPSBNQXIgKyBNQ3I7CiAgICAgICAgICAgIHZhciBUMGkgPSBNQWkgKyBNQ2k7CiAgICAgICAgICAgIHZhciBUMXIgPSBNQXIgLSBNQ3I7CiAgICAgICAgICAgIHZhciBUMWkgPSBNQWkgLSBNQ2k7CiAgICAgICAgICAgIHZhciBUMnIgPSBNQnIgKyBNRHI7CiAgICAgICAgICAgIHZhciBUMmkgPSBNQmkgKyBNRGk7CiAgICAgICAgICAgIHZhciBUM3IgPSBpbnYgKiAoTUJyIC0gTURyKTsKICAgICAgICAgICAgdmFyIFQzaSA9IGludiAqIChNQmkgLSBNRGkpOwoKICAgICAgICAgICAgLy8gRmluYWwgdmFsdWVzCiAgICAgICAgICAgIHZhciBGQXIgPSBUMHIgKyBUMnI7CiAgICAgICAgICAgIHZhciBGQWkgPSBUMGkgKyBUMmk7CgogICAgICAgICAgICB2YXIgRkJyID0gVDFyICsgVDNpOwogICAgICAgICAgICB2YXIgRkJpID0gVDFpIC0gVDNyOwoKICAgICAgICAgICAgb3V0W0FdID0gRkFyOwogICAgICAgICAgICBvdXRbQSArIDFdID0gRkFpOwogICAgICAgICAgICBvdXRbQl0gPSBGQnI7CiAgICAgICAgICAgIG91dFtCICsgMV0gPSBGQmk7CgogICAgICAgICAgICAvLyBPdXRwdXQgZmluYWwgbWlkZGxlIHBvaW50CiAgICAgICAgICAgIGlmIChpID09PSAwKSB7CiAgICAgICAgICAgICAgdmFyIEZDciA9IFQwciAtIFQycjsKICAgICAgICAgICAgICB2YXIgRkNpID0gVDBpIC0gVDJpOwogICAgICAgICAgICAgIG91dFtDXSA9IEZDcjsKICAgICAgICAgICAgICBvdXRbQyArIDFdID0gRkNpOwogICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyBEbyBub3Qgb3ZlcndyaXRlIG91cnNlbHZlcwogICAgICAgICAgICBpZiAoaSA9PT0gaHF1YXJ0ZXJMZW4pCiAgICAgICAgICAgICAgY29udGludWU7CgogICAgICAgICAgICAvLyBJbiB0aGUgZmxpcHBlZCBjYXNlOgogICAgICAgICAgICAvLyBNQWkgPSAtTUFpCiAgICAgICAgICAgIC8vIE1Ccj0tTUJpLCBNQmk9LU1CcgogICAgICAgICAgICAvLyBNQ3I9LU1DcgogICAgICAgICAgICAvLyBNRHI9TURpLCBNRGk9TURyCiAgICAgICAgICAgIHZhciBTVDByID0gVDFyOwogICAgICAgICAgICB2YXIgU1QwaSA9IC1UMWk7CiAgICAgICAgICAgIHZhciBTVDFyID0gVDByOwogICAgICAgICAgICB2YXIgU1QxaSA9IC1UMGk7CiAgICAgICAgICAgIHZhciBTVDJyID0gLWludiAqIFQzaTsKICAgICAgICAgICAgdmFyIFNUMmkgPSAtaW52ICogVDNyOwogICAgICAgICAgICB2YXIgU1QzciA9IC1pbnYgKiBUMmk7CiAgICAgICAgICAgIHZhciBTVDNpID0gLWludiAqIFQycjsKCiAgICAgICAgICAgIHZhciBTRkFyID0gU1QwciArIFNUMnI7CiAgICAgICAgICAgIHZhciBTRkFpID0gU1QwaSArIFNUMmk7CgogICAgICAgICAgICB2YXIgU0ZCciA9IFNUMXIgKyBTVDNpOwogICAgICAgICAgICB2YXIgU0ZCaSA9IFNUMWkgLSBTVDNyOwoKICAgICAgICAgICAgdmFyIFNBID0gb3V0T2ZmICsgcXVhcnRlckxlbiAtIGk7CiAgICAgICAgICAgIHZhciBTQiA9IG91dE9mZiArIGhhbGZMZW4gLSBpOwoKICAgICAgICAgICAgb3V0W1NBXSA9IFNGQXI7CiAgICAgICAgICAgIG91dFtTQSArIDFdID0gU0ZBaTsKICAgICAgICAgICAgb3V0W1NCXSA9IFNGQnI7CiAgICAgICAgICAgIG91dFtTQiArIDFdID0gU0ZCaTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH07CgogICAgLy8gcmFkaXgtMiBpbXBsZW1lbnRhdGlvbgogICAgLy8KICAgIC8vIE5PVEU6IE9ubHkgY2FsbGVkIGZvciBsZW49NAogICAgRkZULnByb3RvdHlwZS5fc2luZ2xlUmVhbFRyYW5zZm9ybTIgPSBmdW5jdGlvbiBfc2luZ2xlUmVhbFRyYW5zZm9ybTIob3V0T2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcCkgewogICAgICBjb25zdCBvdXQgPSB0aGlzLl9vdXQ7CiAgICAgIGNvbnN0IGRhdGEgPSB0aGlzLl9kYXRhOwoKICAgICAgY29uc3QgZXZlblIgPSBkYXRhW29mZl07CiAgICAgIGNvbnN0IG9kZFIgPSBkYXRhW29mZiArIHN0ZXBdOwoKICAgICAgY29uc3QgbGVmdFIgPSBldmVuUiArIG9kZFI7CiAgICAgIGNvbnN0IHJpZ2h0UiA9IGV2ZW5SIC0gb2RkUjsKCiAgICAgIG91dFtvdXRPZmZdID0gbGVmdFI7CiAgICAgIG91dFtvdXRPZmYgKyAxXSA9IDA7CiAgICAgIG91dFtvdXRPZmYgKyAyXSA9IHJpZ2h0UjsKICAgICAgb3V0W291dE9mZiArIDNdID0gMDsKICAgIH07CgogICAgLy8gcmFkaXgtNAogICAgLy8KICAgIC8vIE5PVEU6IE9ubHkgY2FsbGVkIGZvciBsZW49OAogICAgRkZULnByb3RvdHlwZS5fc2luZ2xlUmVhbFRyYW5zZm9ybTQgPSBmdW5jdGlvbiBfc2luZ2xlUmVhbFRyYW5zZm9ybTQob3V0T2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcCkgewogICAgICBjb25zdCBvdXQgPSB0aGlzLl9vdXQ7CiAgICAgIGNvbnN0IGRhdGEgPSB0aGlzLl9kYXRhOwogICAgICBjb25zdCBpbnYgPSB0aGlzLl9pbnYgPyAtMSA6IDE7CiAgICAgIGNvbnN0IHN0ZXAyID0gc3RlcCAqIDI7CiAgICAgIGNvbnN0IHN0ZXAzID0gc3RlcCAqIDM7CgogICAgICAvLyBPcmlnaW5hbCB2YWx1ZXMKICAgICAgY29uc3QgQXIgPSBkYXRhW29mZl07CiAgICAgIGNvbnN0IEJyID0gZGF0YVtvZmYgKyBzdGVwXTsKICAgICAgY29uc3QgQ3IgPSBkYXRhW29mZiArIHN0ZXAyXTsKICAgICAgY29uc3QgRHIgPSBkYXRhW29mZiArIHN0ZXAzXTsKCiAgICAgIC8vIFByZS1GaW5hbCB2YWx1ZXMKICAgICAgY29uc3QgVDByID0gQXIgKyBDcjsKICAgICAgY29uc3QgVDFyID0gQXIgLSBDcjsKICAgICAgY29uc3QgVDJyID0gQnIgKyBEcjsKICAgICAgY29uc3QgVDNyID0gaW52ICogKEJyIC0gRHIpOwoKICAgICAgLy8gRmluYWwgdmFsdWVzCiAgICAgIGNvbnN0IEZBciA9IFQwciArIFQycjsKCiAgICAgIGNvbnN0IEZCciA9IFQxcjsKICAgICAgY29uc3QgRkJpID0gLVQzcjsKCiAgICAgIGNvbnN0IEZDciA9IFQwciAtIFQycjsKCiAgICAgIGNvbnN0IEZEciA9IFQxcjsKICAgICAgY29uc3QgRkRpID0gVDNyOwoKICAgICAgb3V0W291dE9mZl0gPSBGQXI7CiAgICAgIG91dFtvdXRPZmYgKyAxXSA9IDA7CiAgICAgIG91dFtvdXRPZmYgKyAyXSA9IEZCcjsKICAgICAgb3V0W291dE9mZiArIDNdID0gRkJpOwogICAgICBvdXRbb3V0T2ZmICsgNF0gPSBGQ3I7CiAgICAgIG91dFtvdXRPZmYgKyA1XSA9IDA7CiAgICAgIG91dFtvdXRPZmYgKyA2XSA9IEZEcjsKICAgICAgb3V0W291dE9mZiArIDddID0gRkRpOwogICAgfTsKCiAgICB2YXIgRkZUJDEgPSAvKkBfX1BVUkVfXyovZ2V0RGVmYXVsdEV4cG9ydEZyb21DanMoZmZ0KTsKCiAgICBjb25zdCBCVUZGRVJFRF9CTE9DS19TSVpFID0gMjA0ODsKICAgIGZ1bmN0aW9uIGdlbkhhbm5XaW5kb3cobGVuZ3RoKSB7CiAgICAgICAgbGV0IHdpbiA9IG5ldyBGbG9hdDMyQXJyYXkobGVuZ3RoKTsKICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgIHdpbltpXSA9IDAuNSAqICgxIC0gTWF0aC5jb3MoMiAqIE1hdGguUEkgKiBpIC8gbGVuZ3RoKSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiB3aW47CiAgICB9CiAgICBjbGFzcyBQaGFzZVZvY29kZXJQcm9jZXNzb3IgZXh0ZW5kcyBPTEFQcm9jZXNzb3IgewogICAgICAgIGZmdFNpemU7CiAgICAgICAgdGltZUN1cnNvcjsKICAgICAgICBoYW5uV2luZG93OwogICAgICAgIGZmdDsKICAgICAgICBmcmVxQ29tcGxleEJ1ZmZlcjsKICAgICAgICBmcmVxQ29tcGxleEJ1ZmZlclNoaWZ0ZWQ7CiAgICAgICAgdGltZUNvbXBsZXhCdWZmZXI7CiAgICAgICAgbWFnbml0dWRlczsKICAgICAgICBwZWFrSW5kZXhlczsKICAgICAgICBuYlBlYWtzOwogICAgICAgIHN0YXRpYyBnZXQgcGFyYW1ldGVyRGVzY3JpcHRvcnMoKSB7CiAgICAgICAgICAgIHJldHVybiBbewogICAgICAgICAgICAgICAgICAgIG5hbWU6ICdwaXRjaEZhY3RvcicsCiAgICAgICAgICAgICAgICAgICAgZGVmYXVsdFZhbHVlOiAxLjAKICAgICAgICAgICAgICAgIH1dOwogICAgICAgIH0KICAgICAgICBjb25zdHJ1Y3RvcihvcHRpb25zKSB7CiAgICAgICAgICAgIG9wdGlvbnMucHJvY2Vzc29yT3B0aW9ucyA9IHsKICAgICAgICAgICAgICAgIGJsb2NrU2l6ZTogQlVGRkVSRURfQkxPQ0tfU0laRSwKICAgICAgICAgICAgfTsKICAgICAgICAgICAgc3VwZXIob3B0aW9ucyk7CiAgICAgICAgICAgIHRoaXMuZmZ0U2l6ZSA9IHRoaXMuYmxvY2tTaXplOwogICAgICAgICAgICB0aGlzLnRpbWVDdXJzb3IgPSAwOwogICAgICAgICAgICB0aGlzLmhhbm5XaW5kb3cgPSBnZW5IYW5uV2luZG93KHRoaXMuYmxvY2tTaXplKTsKICAgICAgICAgICAgLy8gcHJlcGFyZSBGRlQgYW5kIHByZS1hbGxvY2F0ZSBidWZmZXJzCiAgICAgICAgICAgIHRoaXMuZmZ0ID0gbmV3IEZGVCQxKHRoaXMuZmZ0U2l6ZSk7CiAgICAgICAgICAgIHRoaXMuZnJlcUNvbXBsZXhCdWZmZXIgPSB0aGlzLmZmdC5jcmVhdGVDb21wbGV4QXJyYXkoKTsKICAgICAgICAgICAgdGhpcy5mcmVxQ29tcGxleEJ1ZmZlclNoaWZ0ZWQgPSB0aGlzLmZmdC5jcmVhdGVDb21wbGV4QXJyYXkoKTsKICAgICAgICAgICAgdGhpcy50aW1lQ29tcGxleEJ1ZmZlciA9IHRoaXMuZmZ0LmNyZWF0ZUNvbXBsZXhBcnJheSgpOwogICAgICAgICAgICB0aGlzLm1hZ25pdHVkZXMgPSBuZXcgRmxvYXQzMkFycmF5KHRoaXMuZmZ0U2l6ZSAvIDIgKyAxKTsKICAgICAgICAgICAgdGhpcy5wZWFrSW5kZXhlcyA9IG5ldyBJbnQzMkFycmF5KHRoaXMubWFnbml0dWRlcy5sZW5ndGgpOwogICAgICAgICAgICB0aGlzLm5iUGVha3MgPSAwOwogICAgICAgIH0KICAgICAgICBwcm9jZXNzT0xBKGlucHV0cywgb3V0cHV0cywgcGFyYW1ldGVycykgewogICAgICAgICAgICAvLyBAdHMtaWdub3JlCiAgICAgICAgICAgIGNvbnN0IHBpdGNoRmFjdG9yID0gcGFyYW1ldGVycy5waXRjaEZhY3RvcltwYXJhbWV0ZXJzLnBpdGNoRmFjdG9yLmxlbmd0aCAtIDFdOwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJJbnB1dHM7IGkrKykgewogICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBpbnB1dHNbaV0ubGVuZ3RoOyBqKyspIHsKICAgICAgICAgICAgICAgICAgICB2YXIgaW5wdXQgPSBpbnB1dHNbaV1bal07CiAgICAgICAgICAgICAgICAgICAgdmFyIG91dHB1dCA9IG91dHB1dHNbaV1bal07CiAgICAgICAgICAgICAgICAgICAgdGhpcy5hcHBseUhhbm5XaW5kb3coaW5wdXQpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuZmZ0LnJlYWxUcmFuc2Zvcm0odGhpcy5mcmVxQ29tcGxleEJ1ZmZlciwgaW5wdXQpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuY29tcHV0ZU1hZ25pdHVkZXMoKTsKICAgICAgICAgICAgICAgICAgICB0aGlzLmZpbmRQZWFrcygpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuc2hpZnRQZWFrcyhwaXRjaEZhY3Rvcik7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5mZnQuY29tcGxldGVTcGVjdHJ1bSh0aGlzLmZyZXFDb21wbGV4QnVmZmVyU2hpZnRlZCk7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5mZnQuaW52ZXJzZVRyYW5zZm9ybSh0aGlzLnRpbWVDb21wbGV4QnVmZmVyLCB0aGlzLmZyZXFDb21wbGV4QnVmZmVyU2hpZnRlZCk7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5mZnQuZnJvbUNvbXBsZXhBcnJheSh0aGlzLnRpbWVDb21wbGV4QnVmZmVyLCBvdXRwdXQpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuYXBwbHlIYW5uV2luZG93KG91dHB1dCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy50aW1lQ3Vyc29yICs9IHRoaXMuaG9wU2l6ZTsKICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgfQogICAgICAgIGFwcGx5SGFubldpbmRvdyhpbnB1dCkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuYmxvY2tTaXplOyBpKyspIHsKICAgICAgICAgICAgICAgIGlucHV0W2ldICo9IHRoaXMuaGFubldpbmRvd1tpXTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBjb21wdXRlTWFnbml0dWRlcygpIHsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDAsIGogPSAwOyBpIDwgdGhpcy5tYWduaXR1ZGVzLmxlbmd0aDsgaSsrLCBqICs9IDIpIHsKICAgICAgICAgICAgICAgIGNvbnN0IHJlYWwgPSB0aGlzLmZyZXFDb21wbGV4QnVmZmVyW2pdOwogICAgICAgICAgICAgICAgY29uc3QgaW1hZyA9IHRoaXMuZnJlcUNvbXBsZXhCdWZmZXJbaiArIDFdOwogICAgICAgICAgICAgICAgdGhpcy5tYWduaXR1ZGVzW2ldID0gcmVhbCAqKiAyICsgaW1hZyAqKiAyOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGZpbmRQZWFrcygpIHsKICAgICAgICAgICAgdGhpcy5uYlBlYWtzID0gMDsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDIsIGVuZCA9IHRoaXMubWFnbml0dWRlcy5sZW5ndGggLSAyOyBpIDwgZW5kOyBpKyspIHsKICAgICAgICAgICAgICAgIGNvbnN0IG1hZyA9IHRoaXMubWFnbml0dWRlc1tpXTsKICAgICAgICAgICAgICAgIGlmICh0aGlzLm1hZ25pdHVkZXNbaSAtIDFdID49IG1hZyB8fCB0aGlzLm1hZ25pdHVkZXNbaSAtIDJdID49IG1hZyB8fCB0aGlzLm1hZ25pdHVkZXNbaSArIDFdID49IG1hZyB8fCB0aGlzLm1hZ25pdHVkZXNbaSArIDJdID49IG1hZykgewogICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgdGhpcy5wZWFrSW5kZXhlc1t0aGlzLm5iUGVha3MrK10gPSBpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHNoaWZ0UGVha3MocGl0Y2hGYWN0b3IpIHsKICAgICAgICAgICAgdGhpcy5mcmVxQ29tcGxleEJ1ZmZlclNoaWZ0ZWQuZmlsbCgwKTsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm5iUGVha3M7IGkrKykgewogICAgICAgICAgICAgICAgY29uc3QgcGVha0luZGV4ID0gdGhpcy5wZWFrSW5kZXhlc1tpXTsKICAgICAgICAgICAgICAgIGNvbnN0IHBlYWtJbmRleFNoaWZ0ZWQgPSBNYXRoLnJvdW5kKHBlYWtJbmRleCAqIHBpdGNoRmFjdG9yKTsKICAgICAgICAgICAgICAgIGlmIChwZWFrSW5kZXhTaGlmdGVkID4gdGhpcy5tYWduaXR1ZGVzLmxlbmd0aCkgewogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgbGV0IHN0YXJ0SW5kZXggPSAoaSA+IDApID8gcGVha0luZGV4IC0gTWF0aC5mbG9vcigocGVha0luZGV4IC0gdGhpcy5wZWFrSW5kZXhlc1tpIC0gMV0pIC8gMikgOiAwOwogICAgICAgICAgICAgICAgbGV0IGVuZEluZGV4ID0gKGkgPCB0aGlzLm5iUGVha3MgLSAxKSA/IHBlYWtJbmRleCArIE1hdGguY2VpbCgodGhpcy5wZWFrSW5kZXhlc1tpICsgMV0gLSBwZWFrSW5kZXgpIC8gMikgOiB0aGlzLmZmdFNpemU7CiAgICAgICAgICAgICAgICBmb3IgKGxldCBqID0gc3RhcnRJbmRleCAtIHBlYWtJbmRleDsgaiA8IGVuZEluZGV4IC0gcGVha0luZGV4OyBqKyspIHsKICAgICAgICAgICAgICAgICAgICBjb25zdCBiaW5JbmRleCA9IHBlYWtJbmRleCArIGo7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgYmluSW5kZXhTaGlmdGVkID0gcGVha0luZGV4U2hpZnRlZCArIGo7CiAgICAgICAgICAgICAgICAgICAgaWYgKGJpbkluZGV4U2hpZnRlZCA+PSB0aGlzLm1hZ25pdHVkZXMubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBjb25zdCBvbWVnYURlbHRhID0gMiAqIE1hdGguUEkgKiAoYmluSW5kZXhTaGlmdGVkIC0gYmluSW5kZXgpIC8gdGhpcy5mZnRTaXplOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IHBoYXNlU2hpZnRSZWFsID0gTWF0aC5jb3Mob21lZ2FEZWx0YSAqIHRoaXMudGltZUN1cnNvcik7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgcGhhc2VTaGlmdEltYWcgPSBNYXRoLnNpbihvbWVnYURlbHRhICogdGhpcy50aW1lQ3Vyc29yKTsKICAgICAgICAgICAgICAgICAgICBjb25zdCBpbmRleFJlYWwgPSBiaW5JbmRleCAqIDI7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgaW5kZXhJbWFnID0gaW5kZXhSZWFsICsgMTsKICAgICAgICAgICAgICAgICAgICBjb25zdCB2YWx1ZVJlYWwgPSB0aGlzLmZyZXFDb21wbGV4QnVmZmVyW2luZGV4UmVhbF07CiAgICAgICAgICAgICAgICAgICAgY29uc3QgdmFsdWVJbWFnID0gdGhpcy5mcmVxQ29tcGxleEJ1ZmZlcltpbmRleEltYWddOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IHZhbHVlU2hpZnRlZFJlYWwgPSB2YWx1ZVJlYWwgKiBwaGFzZVNoaWZ0UmVhbCAtIHZhbHVlSW1hZyAqIHBoYXNlU2hpZnRJbWFnOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IHZhbHVlU2hpZnRlZEltYWcgPSB2YWx1ZVJlYWwgKiBwaGFzZVNoaWZ0SW1hZyArIHZhbHVlSW1hZyAqIHBoYXNlU2hpZnRSZWFsOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IGluZGV4U2hpZnRlZFJlYWwgPSBiaW5JbmRleFNoaWZ0ZWQgKiAyOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IGluZGV4U2hpZnRlZEltYWcgPSBpbmRleFNoaWZ0ZWRSZWFsICsgMTsKICAgICAgICAgICAgICAgICAgICB0aGlzLmZyZXFDb21wbGV4QnVmZmVyU2hpZnRlZFtpbmRleFNoaWZ0ZWRSZWFsXSArPSB2YWx1ZVNoaWZ0ZWRSZWFsOwogICAgICAgICAgICAgICAgICAgIHRoaXMuZnJlcUNvbXBsZXhCdWZmZXJTaGlmdGVkW2luZGV4U2hpZnRlZEltYWddICs9IHZhbHVlU2hpZnRlZEltYWc7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CiAgICAvLyBAdHMtaWdub3JlCiAgICByZWdpc3RlclByb2Nlc3NvcigicGhhc2Utdm9jb2RlciIsIFBoYXNlVm9jb2RlclByb2Nlc3Nvcik7CiAgICBjb25zb2xlLmxvZygiUGhhc2VWb2NvZGVyUHJvY2Vzc29yIHJlZ2lzdGVyZWQiKTsKCiAgICBleHBvcnRzLlBoYXNlVm9jb2RlclByb2Nlc3NvciA9IFBoYXNlVm9jb2RlclByb2Nlc3NvcjsKCiAgICByZXR1cm4gZXhwb3J0czsKCn0pKHt9KTsK\"","import type { AudioContext } from './context';\n\nclass LRUCache<K, V> {\n private maxSize: number;\n private cache: Map<K, V>;\n\n constructor(maxSize: number) {\n this.maxSize = maxSize;\n this.cache = new Map();\n }\n\n get(key: K): V | undefined {\n if (!this.cache.has(key)) return undefined;\n const value = this.cache.get(key)!;\n this.cache.delete(key);\n this.cache.set(key, value);\n return value;\n }\n\n set(key: K, value: V): void {\n if (this.cache.has(key)) {\n this.cache.delete(key);\n } else if (this.cache.size >= this.maxSize) {\n const firstKey = this.cache.keys().next().value;\n this.cache.delete(firstKey);\n }\n this.cache.set(key, value);\n }\n\n has(key: K): boolean {\n return this.cache.has(key);\n }\n}\n\n\ninterface CacheMetadata {\n url: string;\n etag?: string;\n lastModified?: string;\n}\n\nconst DEFAULT_CACHE_SIZE = 100;\n\nexport class AudioCache {\n private static pendingRequests = new Map<string, Promise<AudioBuffer>>();\n private static decodedBuffers = new LRUCache<string, AudioBuffer>(100); // Limit to 500 items\n\n private static async openCache(): Promise<Cache> {\n try {\n return await caches.open('audio-cache');\n } catch (error) {\n console.error('Failed to open cache:', error);\n throw error;\n }\n }\n\n private static async getBufferFromCache(url: string, cache: Cache): Promise<ArrayBuffer | null> {\n try {\n const response = await cache.match(url);\n if (response && response.ok) {\n return await response.arrayBuffer();\n }\n return null;\n } catch (error) {\n console.error('Failed to get data from cache:', error);\n return null;\n }\n }\n\n private static async fetchAndCacheBuffer(url: string, cache: Cache, etag?: string, lastModified?: string): Promise<ArrayBuffer> {\n try {\n const headers = new Headers();\n if (etag) headers.append('If-None-Match', etag);\n if (lastModified) headers.append('If-Modified-Since', lastModified);\n\n const fetchResponse = await fetch(url, { headers });\n const responseClone = fetchResponse.clone();\n\n if (fetchResponse.status === 200) {\n const newEtag = fetchResponse.headers.get('ETag') || undefined;\n const newLastModified = fetchResponse.headers.get('Last-Modified') || undefined;\n const cacheData: CacheMetadata = { url, etag: newEtag, lastModified: newLastModified };\n\n await cache.put(url, responseClone);\n await cache.put(url + ':meta', new Response(JSON.stringify(cacheData), { headers: { 'Content-Type': 'application/json' } }));\n } else if (fetchResponse.status === 304) {\n const cachedResponse = await cache.match(url);\n if (cachedResponse) {\n return await cachedResponse.arrayBuffer();\n }\n }\n\n return await fetchResponse.arrayBuffer();\n } catch (error) {\n console.error('Failed to fetch and cache data:', error);\n throw error;\n }\n }\n\n private static async decodeAudioData(context: AudioContext, arrayBuffer: ArrayBuffer): Promise<AudioBuffer> {\n try {\n return await context.decodeAudioData(arrayBuffer);\n } catch (error) {\n console.error('Failed to decode audio data:', error);\n throw error;\n }\n }\n\n private static async getMetadataFromCache(url: string, cache: Cache): Promise<CacheMetadata | null> {\n try {\n const metaResponse = await cache.match(url + ':meta');\n if (metaResponse && metaResponse.ok) {\n return await metaResponse.json();\n }\n return null;\n } catch (error) {\n console.error('Failed to get metadata from cache:', error);\n return null;\n }\n }\n\n public static async getAudioBuffer(context: AudioContext, url: string): Promise<AudioBuffer> {\n // Check if the decoded buffer is already available\n if (this.decodedBuffers.has(url)) {\n return this.decodedBuffers.get(url)!;\n }\n\n // handle data: urls\n if (url.startsWith('data:')) {\n const base64Data = url.split(',')[1];\n const buffer = Uint8Array.from(atob(base64Data), c => c.charCodeAt(0)).buffer;\n const audioBuffer = await this.decodeAudioData(context, buffer);\n this.decodedBuffers.set(url, audioBuffer);\n return audioBuffer;\n }\n\n const cache = await this.openCache();\n\n // First, check if there's a pending request.\n let pendingRequest = this.pendingRequests.get(url);\n if (pendingRequest) {\n return pendingRequest;\n }\n\n // Try getting the buffer from cache.\n const bufferFromCache = await this.getBufferFromCache(url, cache);\n if (bufferFromCache) {\n const audioBuffer = await this.decodeAudioData(context, bufferFromCache);\n this.decodedBuffers.set(url, audioBuffer);\n return audioBuffer;\n }\n\n // Check for cached metadata (ETag, Last-Modified)\n const metadata = await this.getMetadataFromCache(url, cache);\n const etag = metadata?.etag;\n const lastModified = metadata?.lastModified;\n\n // If it's not in the cache or needs revalidation, fetch and cache it.\n pendingRequest = this.fetchAndCacheBuffer(url, cache, etag, lastModified)\n .then(arrayBuffer => this.decodeAudioData(context, arrayBuffer))\n .then(audioBuffer => {\n this.decodedBuffers.set(url, audioBuffer);\n return audioBuffer;\n })\n .finally(() => {\n this.pendingRequests.delete(url); // Cleanup pending request\n });\n this.pendingRequests.set(url, pendingRequest);\n\n return pendingRequest;\n }\n\n\n public static clearMemoryCache(): void {\n this.decodedBuffers = new LRUCache<string, AudioBuffer>(DEFAULT_CACHE_SIZE);\n this.pendingRequests.clear();\n }\n}\n\n\n","import { BiquadFilterNode } from './context'\n\nexport type FilterCloneOverrides = {\n filters?: BiquadFilterNode[];\n};\n\nexport abstract class FilterManager {\n protected _filters: BiquadFilterNode[] = [];\n\n addFilter(filter: BiquadFilterNode) {\n this._filters.push(filter);\n }\n\n removeFilter(filter: BiquadFilterNode) {\n this._filters = this._filters.filter(f => f.frequency.value !== filter.frequency.value && f.type !== filter.type && f.Q.value !== filter.Q.value && f.gain.value !== filter.gain.value);\n }\n\n applyFilters(connection: any): any {\n this._filters.reduce((prevConnection, filter) => {\n prevConnection.connect(filter);\n return filter;\n }, connection);\n return this._filters.length > 0 ? this._filters[this._filters.length - 1] : connection;\n }\n\n get filters() {\n return this._filters;\n }\n\n addFilters(filters: BiquadFilterNode[]) {\n // todo: be more efficient\n filters.forEach(filter => this.addFilter(filter));\n }\n\n\n removeFilters(filters: BiquadFilterNode[]) {\n filters.forEach(filter => this.removeFilter(filter));\n }\n}\n\n","import type { BaseSound, LoopCount, Position } from './cacophony';\n\nimport { BiquadFilterNode } from './context';\nimport { Playback } from './playback';\nimport { Sound } from './sound';\n\n\nexport class Group implements BaseSound {\n\n private _position: Position = [0, 0, 0];\n loopCount: LoopCount = 0;\n private playIndex: number = 0;\n\n constructor(\n public sounds: Sound[] = [],\n ) { }\n\n /**\n * Plays a random sound from the group.\n * @returns The playback object representing the played sound.\n * @throws Error if the group is empty and there are no sounds to play.\n */\n\n playRandom(): Playback {\n if (this.sounds.length === 0) {\n throw new Error('Cannot play a random sound from an empty group');\n }\n const randomIndex = Math.floor(Math.random() * this.sounds.length);\n const randomSound = this.sounds[randomIndex] as Sound;\n const playback = randomSound.preplay();\n playback.forEach(p => p.play());\n return playback[0];\n }\n\n\n /**\n * Plays the sounds in the group in a specific order.\n * \n * @param shouldLoop - Indicates whether the sounds should be played in a loop.\n * @returns The playback object representing the first sound being played.\n * @throws Error if the group is empty and shouldLoop is false.\n */\n\n playOrdered(shouldLoop: boolean = true): Playback {\n if (this.sounds.length === 0) {\n throw new Error('Cannot play an ordered sound from an empty group');\n }\n const sound = this.sounds[this.playIndex] as Sound;\n const playback = sound.preplay();\n playback.forEach(p => p.play());\n this.playIndex++;\n if (this.playIndex >= this.sounds.length) {\n if (shouldLoop) {\n this.playIndex = 0;\n } else {\n this.playIndex = this.sounds.length; // Set to length to indicate end of list\n }\n }\n return playback[0];\n }\n\n get duration() {\n return this.sounds.map(sound => sound.duration).reduce((a, b) => Math.max(a, b), 0);\n }\n\n seek(time: number): void {\n this.sounds.forEach(sound => sound.seek && sound.seek(time));\n }\n\n addSound(sound: Sound): void {\n this.sounds.push(sound);\n }\n\n preplay(): Playback[] {\n return (this.sounds as Sound[]).reduce<Playback[]>((playbacks, sound) => {\n sound.loop && sound.loop(this.loopCount);\n return playbacks.concat(sound.preplay());\n }, []);\n }\n\n /***\n * Plays all sounds in the group.\n * @returns {Playback[]} An array of Playback objects, one for each sound in the group.\n */\n\n play(): Playback[] {\n return this.preplay().map(playback => playback.play()[0]\n );\n }\n\n /**\n * A boolean indicating whether any of the sounds in the group are currently playing.\n * @returns {boolean} True if any sound is playing, false otherwise.\n */\n\n get isPlaying(): boolean {\n return this.sounds.some(sound => sound.isPlaying);\n }\n\n /**\n * Stops all the sounds in the group.\n */\n\n stop(): void {\n this.sounds.forEach(sound => sound.stop());\n }\n\n pause(): void {\n this.sounds.forEach(sound => sound.pause());\n }\n\n loop(loopCount?: LoopCount): LoopCount {\n if (loopCount === undefined) {\n return this.loopCount;\n }\n this.loopCount = loopCount;\n this.sounds.forEach(sound => sound.loop(loopCount));\n return this.loopCount;\n }\n\n addFilter(filter: BiquadFilterNode): void {\n this.sounds.forEach(sound => sound.addFilter(filter));\n }\n\n removeFilter(filter: BiquadFilterNode): void {\n this.sounds.forEach(sound => sound.removeFilter(filter));\n }\n\n set position(position: [number, number, number]) {\n this._position = position;\n this.sounds.forEach(sound => sound.position = this._position);\n }\n\n get position(): [number, number, number] {\n return this._position;\n }\n\n get volume(): number {\n return this.sounds.map(sound => sound.volume).reduce((a, b) => a + b, 0) / this.sounds.length;\n }\n\n set volume(volume: number) {\n this.sounds.forEach(sound => sound.volume = volume);\n }\n\n get playbackRate(): number {\n if (this.sounds.length === 0) {\n return 1;\n }\n return this.sounds[0].playbackRate;\n }\n\n set playbackRate(rate: number) {\n this.sounds.forEach(sound => sound.playbackRate = rate);\n }\n\n\n}\n","import type { Position } from \"./cacophony\";\nimport { BiquadFilterNode } from \"./context\";\nimport { FilterManager } from \"./filters\";\nimport { BasePlayback, Playback } from \"./playback\";\n\ntype Constructor<T = FilterManager> = abstract new (...args: any[]) => T;\n\nexport function PlaybackContainer<TBase extends Constructor>(Base: TBase) {\n abstract class PlaybackContainer extends Base {\n protected playbacks: BasePlayback[] = [];\n protected _position: Position = [0, 0, 0];\n protected _stereoPan: number = 0;\n protected _threeDOptions: PannerOptions = {\n coneInnerAngle: 360,\n coneOuterAngle: 360,\n coneOuterGain: 0,\n distanceModel: 'inverse',\n maxDistance: 10000,\n channelCount: 2,\n channelCountMode: 'clamped-max',\n channelInterpretation: 'speakers',\n panningModel: 'HRTF',\n refDistance: 1,\n rolloffFactor: 1,\n positionX: 0,\n positionY: 0,\n positionZ: 0,\n orientationX: 0,\n orientationY: 0,\n orientationZ: 0\n };\n protected _volume: number = 1;\n\n abstract preplay(): BasePlayback[]\n\n /**\n * Starts playback of the sound and returns a Playback instance representing this particular playback.\n * Multiple Playback instances can be created by calling this method multiple times,\n * allowing for the same sound to be played concurrently with different settings.\n * @returns {Playback[]} An array containing the Playback instances that have been started.\n */\n\n play(): BasePlayback[] {\n const playback = this.preplay();\n playback.forEach(p => p.play());\n return playback;\n }\n\n /**\n * Stops all current playbacks of the sound immediately. This will halt the sound regardless of how many times it has been played.\n */\n\n stop() {\n this.playbacks.forEach(p => p.stop());\n this.playbacks = [];\n }\n\n /**\n * Pauses all current playbacks of the sound.\n */\n\n pause(): void {\n this.playbacks.forEach(playback => playback.pause());\n }\n\n /**\n * Adds a BiquadFilterNode to the container's filter chain.\n * Filters are applied in the order they are added.\n * @param { BiquadFilterNode } filter - The filter to add to the chain.\n */\n\n addFilter(filter: BiquadFilterNode): void {\n super.addFilter(filter);\n this.playbacks.forEach(p => p.addFilter(filter));\n }\n\n\n /**\n * Removes a BiquadFilterNode from the container's filter chain.\n * If the filter is not part of the chain, the method has no effect.\n * @param { BiquadFilterNode } filter - The filter to remove from the chain.\n */\n\n removeFilter(filter: BiquadFilterNode): void {\n super.removeFilter(filter);\n this.playbacks.forEach(p => p.removeFilter(filter));\n }\n\n /**\n * Returns a boolean indicating whether the object is currently playing.\n * an object is playing if any of its playbacks are currently playing.\n * @returns {boolean} True if the object is playing, false otherwise.\n */\n\n get isPlaying(): boolean {\n return this.playbacks.some(p => p.isPlaying);\n }\n\n /**\n * Retrieves the current 3D spatial position of the sound in the audio context.\n * The position is returned as an array of three values[x, y, z].\n * @returns { Position } The current position of the sound.\n */\n\n get position(): Position {\n return [this._threeDOptions.positionX as number, this._threeDOptions.positionY as number, this._threeDOptions.positionZ as number]\n }\n\n /**\n * Sets the 3D spatial position of the sound in the audio context.\n * The position is an array of three values[x, y, z].\n * This method updates the position of all active playbacks of the sound.\n * @param { Position } position - The new position of the sound.\n */\n\n set position(position: Position) {\n this._threeDOptions.positionX = position[0];\n this._threeDOptions.positionY = position[1];\n this._threeDOptions.positionZ = position[2];\n this.playbacks.forEach(p => p.position = position);\n }\n\n\n get threeDOptions(): PannerOptions {\n return this._threeDOptions;\n }\n\n set threeDOptions(options: Partial<PannerOptions>) {\n this._threeDOptions = { ...this._threeDOptions, ...options };\n this.playbacks.forEach(p => p.threeDOptions = this._threeDOptions);\n }\n\n get stereoPan(): number | null {\n return this._stereoPan;\n }\n\n set stereoPan(value: number) {\n this._stereoPan = value;\n this.playbacks.forEach(p => p.stereoPan = value);\n }\n\n\n /*** \n * Gets the volume of the sound. This volume level affects all current and future playbacks of this sound instance.\n * The volume is specified as a linear value between 0 (silent) and 1 (full volume).\n * \n * @returns {number} The current volume of the sound.\n */\n\n get volume(): number {\n return this._volume;\n }\n\n /***\n * Sets the volume of the sound. This volume level affects all current and future playbacks of this sound instance.\n * The volume is specified as a linear value between 0 (silent) and 1 (full volume).\n * \n * @param {number} volume - The new volume level for the sound.\n */\n\n set volume(volume: number) {\n this._volume = volume;\n this.playbacks.forEach(p => p.volume = volume);\n }\n\n };\n return PlaybackContainer;\n}","import type { PanType, Position } from \"./cacophony\";\nimport type { AudioContext, PannerNode, StereoPannerNode } from \"./context\";\nimport { FilterManager } from \"./filters\";\n\nexport type PanCloneOverrides = {\n panType?: PanType;\n stereoPan?: number; // -1 (left) to 1 (right)\n threeDOptions?: Partial<PannerOptions>; // HRTF panning only\n position?: Position; // HRTF panning only, [x, y, z]\n};\n\ntype Constructor<T = FilterManager> = abstract new (...args: any[]) => T;\n\nexport function PannerMixin<TBase extends Constructor>(Base: TBase) {\n abstract class PannerMixin extends Base {\n protected panner?: PannerNode | StereoPannerNode;\n private _panType: PanType = 'stereo';\n\n get panType(): PanType {\n return this._panType;\n }\n\n setPanType(panType: PanType, audioContext: AudioContext) {\n this._panType = panType;\n if (panType === 'stereo') {\n this.panner = audioContext.createStereoPanner();\n } else {\n this.panner = audioContext.createPanner();\n }\n }\n\n setPannerNode(pannerNode: PannerNode) {\n this.panner = pannerNode;\n }\n\n /**\n * Gets the stereo panning value.\n * @returns {number | null} The current stereo pan value, or null if stereo panning is not applicable.\n * @throws {Error} Throws an error if stereo panning is not available or if the sound has been cleaned up.\n */\n\n get stereoPan(): number | null {\n if (this.panType === 'stereo') {\n return (this.panner as StereoPannerNode).pan.value;\n }\n return null;\n }\n\n /**\n * Sets the stereo panning value.\n * @param {number} value - The stereo pan value to set, between -1 (left) and 1 (right).\n * @throws {Error} Throws an error if stereo panning is not available, if the sound has been cleaned up, or if the value is out of bounds.\n */\n\n set stereoPan(value: number) {\n if (this.panType !== 'stereo') {\n throw new Error('Stereo panning is not available when using HRTF.');\n }\n if (!this.panner) {\n throw new Error('Cannot set stereo pan of a sound that has been cleaned up');\n }\n value = clamp(value, -1, 1);\n (this.panner as StereoPannerNode).pan.setValueAtTime(clamp(value, -1, 1), this.panner.context.currentTime);\n }\n\n\n /**\n * Gets the 3D audio options if HRTF panning is used.\n * @returns {IPannerOptions} The current 3D audio options.\n * @throws {Error} Throws an error if the sound has been cleaned up or if HRTF panning is not used.\n */\n\n get threeDOptions(): PannerOptions {\n if (!this.panner) {\n throw new Error('Cannot get 3D options of a sound that has been cleaned up');\n }\n if (this.panType !== 'HRTF') {\n throw new Error('Cannot get 3D options of a sound that is not using HRTF');\n }\n const panner = this.panner as PannerNode;\n return {\n coneInnerAngle: panner.coneInnerAngle,\n coneOuterAngle: panner.coneOuterAngle,\n coneOuterGain: panner.coneOuterGain,\n distanceModel: panner.distanceModel,\n maxDistance: panner.maxDistance,\n channelCount: this.panner.channelCount,\n channelCountMode: panner.channelCountMode,\n channelInterpretation: panner.channelInterpretation,\n panningModel: panner.panningModel,\n refDistance: panner.refDistance,\n rolloffFactor: panner.rolloffFactor,\n positionX: panner.positionX.value,\n positionY: panner.positionY.value,\n positionZ: panner.positionZ.value,\n orientationX: panner.orientationX.value,\n orientationY: panner.orientationY.value,\n orientationZ: panner.orientationZ.value\n }\n }\n\n /**\n * Sets the 3D audio options for HRTF panning.\n * @param {Partial<IPannerOptions>} options - The 3D audio options to set.\n * @throws {Error} Throws an error if the sound has been cleaned up or if HRTF panning is not used.\n */\n set threeDOptions(options: Partial<PannerOptions>) {\n if (!this.panner) {\n throw new Error('Cannot set 3D options of a sound that has been cleaned up');\n }\n if (this.panType !== 'HRTF') {\n throw new Error('Cannot set 3D options of a sound that is not using HRTF');\n }\n const panner = this.panner as PannerNode;\n panner.coneInnerAngle = options.coneInnerAngle !== undefined ? options.coneInnerAngle : panner.coneInnerAngle;\n panner.coneOuterAngle = options.coneOuterAngle !== undefined ? options.coneOuterAngle : panner.coneOuterAngle;\n panner.coneOuterGain = options.coneOuterGain !== undefined ? options.coneOuterGain : panner.coneOuterGain;\n panner.distanceModel = options.distanceModel || panner.distanceModel;\n panner.maxDistance = options.maxDistance !== undefined ? options.maxDistance : panner.maxDistance;\n panner.channelCount = options.channelCount !== undefined ? options.channelCount : panner.channelCount;\n panner.channelCountMode = options.channelCountMode || panner.channelCountMode;\n panner.channelInterpretation = options.channelInterpretation || panner.channelInterpretation;\n panner.panningModel = options.panningModel || panner.panningModel;\n panner.refDistance = options.refDistance !== undefined ? options.refDistance : panner.refDistance;\n panner.rolloffFactor = options.rolloffFactor !== undefined ? options.rolloffFactor : panner.rolloffFactor;\n panner.positionX.value = options.positionX !== undefined ? options.positionX : panner.positionX.value;\n panner.positionY.value = options.positionY !== undefined ? options.positionY : panner.positionY.value;\n panner.positionZ.value = options.positionZ !== undefined ? options.positionZ : panner.positionZ.value;\n panner.orientationX.value = options.orientationX !== undefined ? options.orientationX : panner.orientationX.value;\n panner.orientationY.value = options.orientationY !== undefined ? options.orientationY : panner.orientationY.value;\n panner.orientationZ.value = options.orientationZ !== undefined ? options.orientationZ : panner.orientationZ.value;\n }\n\n\n /**\n * Sets the position of the audio source in 3D space (HRTF panning only).\n * @param {Position} position - The [x, y, z] coordinates of the audio source.\n * @throws {Error} Throws an error if the sound has been cleaned up or if HRTF panning is not used.\n */\n\n set position(position: Position) {\n if (!this.panner) {\n throw new Error('Cannot move a sound that has been cleaned up');\n }\n if (this.panType !== 'HRTF') {\n throw new Error('Cannot move a sound that is not using HRTF');\n }\n const [x, y, z] = position;\n const panner = this.panner as PannerNode;\n panner.positionX.value = x;\n panner.positionY.value = y;\n panner.positionZ.value = z;\n }\n\n /**\n * Gets the position of the audio source in 3D space (HRTF panning only).\n * @returns {Position} The [x, y, z] coordinates of the audio source.\n * @throws {Error} Throws an error if the sound has been cleaned up or if HRTF panning is not used.\n */\n\n get position(): Position {\n if (!this.panner) {\n throw new Error('Cannot get position of a sound that has been cleaned up');\n }\n if (this.panType !== 'HRTF') {\n throw new Error('Cannot get position of a sound that is not using HRTF');\n }\n const panner = this.panner as PannerNode;\n return [panner.positionX.value, panner.positionY.value, panner.positionZ.value];\n }\n\n\n }\n\n return PannerMixin;\n}\n\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n","import { GainNode } from \"./context\";\nimport { FilterManager } from \"./filters\";\n\nexport type VolumeCloneOverrides = {\n volume?: number;\n};\n\ntype Constructor<T = FilterManager> = abstract new (...args: any[]) => T;\n\nexport function VolumeMixin<TBase extends Constructor>(Base: TBase) {\n abstract class VolumeMixin extends Base {\n protected gainNode?: GainNode;\n\n setGainNode(gainNode: GainNode) {\n this.gainNode = gainNode;\n }\n\n /**\n * Gets the current volume of the audio.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n * @returns {number} The current volume.\n */\n\n get volume(): number {\n if (!this.gainNode) {\n throw new Error('Cannot get volume of a sound that has been cleaned up');\n }\n return this.gainNode.gain.value;\n }\n\n /**\n * Sets the volume of the audio.\n * @param {number} v - The volume to set.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n\n set volume(v: number) {\n if (!this.gainNode) {\n throw new Error('Cannot set volume of a sound that has been cleaned up');\n }\n this.gainNode.gain.value = v;\n }\n\n };\n\n return VolumeMixin;\n}\n","/**\n * The Playback class encapsulates the functionality for playing audio in a web application.\n * It integrates with the standardized-audio-context library to provide a cross-browser way to handle audio.\n * This class allows for the manipulation of audio playback through various features such as:\n * - Playing and stopping audio\n * - Looping audio a specific number of times or infinitely\n * - Adjusting volume and playback rate\n * - Applying stereo or 3D (HRTF) panning\n * - Adding and removing filters to modify the audio output\n * - Handling audio looping with custom logic\n * - Fading audio in and out linearly or exponentially\n * - Seeking to specific points in the audio\n * - Checking if the audio is currently playing\n * - Cleaning up resources when the audio is no longer needed\n * \n * The class is designed to be flexible and can be used with different types of audio sources,\n * including buffer sources and media elements. It also provides detailed control over the audio's\n * spatial characteristics when using 3D audio.\n */\n\nimport type { BaseSound, LoopCount, PanType } from \"./cacophony\";\nimport type { AudioBuffer, AudioBufferSourceNode, AudioContext, AudioNode, BiquadFilterNode, GainNode, SourceNode } from \"./context\";\nimport { FilterManager } from \"./filters\";\nimport { PannerMixin } from \"./pannerMixin\";\nimport { VolumeMixin } from \"./volumeMixin\";\n\nexport abstract class BasePlayback extends PannerMixin(VolumeMixin(FilterManager)) {\n public source?: AudioNode\n protected _playing: boolean = false;\n\n abstract play(): [this];\n abstract pause(): void;\n abstract stop(): void;\n\n /**\n * Checks if the audio is currently playing.\n * @returns {boolean} True if the audio is playing, false otherwise.\n */\n\n get isPlaying(): boolean {\n if (!this.source) {\n return false;\n }\n return this._playing;\n }\n\n\n}\n\nexport class Playback extends BasePlayback implements BaseSound {\n private context: AudioContext;\n declare public source?: SourceNode;\n loopCount: LoopCount = 0;\n currentLoop: number = 0;\n private buffer?: AudioBuffer;\n pauseTime: number = 0;\n startTime: number = 0;\n\n /**\n * Creates an instance of the Playback class.\n * @param {SourceNode} source - The audio source node.\n * @param {GainNode} gainNode - The gain node for controlling volume.\n * @param {AudioContext} context - The audio context.\n * @param {LoopCount} loopCount - The number of times the audio should loop. 'infinite' for endless looping.\n * @param {PanType} panType - The type of panning to use ('HRTF' for 3D audio or 'stereo' for stereo panning).\n * @throws {Error} Throws an error if an invalid pan type is provided.\n */\n\n constructor(source: SourceNode, gainNode: GainNode, context: AudioContext, loopCount: LoopCount = 0, panType: PanType = 'HRTF') {\n super();\n this.loopCount = loopCount;\n this.setPanType(panType, context);\n this.source = source;\n if ('buffer' in source && source.buffer) {\n this.buffer = source.buffer;\n }\n if ('mediaElement' in source && source.mediaElement) {\n source.mediaElement.onended = this.handleLoop;\n } else if ('onended' in source) {\n source.onended = this.handleLoop;\n } else {\n throw new Error('Unsupported source type');\n }\n this.context = context;\n this.source.connect(this.panner!);\n this.setGainNode(gainNode);\n this.panner!.connect(this.gainNode!);\n this.refreshFilters();\n }\n\n /**\n * Gets the duration of the audio in seconds.\n * @returns {number} The duration of the audio.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n\n get duration() {\n if (!this.buffer) {\n throw new Error('Cannot get duration of a sound that has been cleaned up');\n }\n return this.buffer.duration;\n }\n\n /**\n * Gets the current playback rate of the audio.\n * @returns {number} The current playback rate.\n * @throws {Error} Throws an error if the sound has been cleaned up or if the source type is unsupported.\n */\n\n get playbackRate() {\n if (!this.source) {\n throw new Error('Cannot get playback rate of a sound that has been cleaned up');\n }\n if ('playbackRate' in this.source) {\n return this.source.playbackRate.value;\n }\n if ('mediaElement' in this.source && this.source.mediaElement) {\n return this.source.mediaElement.playbackRate;\n }\n throw new Error('Unsupported source type');\n }\n\n /**\n * Sets the playback rate of the audio.\n * @param {number} rate - The playback rate to set.\n * @throws {Error} Throws an error if the sound has been cleaned up or if the source type is unsupported.\n */\n\n set playbackRate(rate: number) {\n if (!this.source) {\n throw new Error('Cannot set playback rate of a sound that has been cleaned up');\n }\n if ('playbackRate' in this.source) {\n this.source.playbackRate.value = rate;\n }\n if ('mediaElement' in this.source && this.source.mediaElement) {\n this.source.mediaElement.playbackRate = rate;\n }\n }\n\n /**\n * Handles the loop event when the audio ends.\n * This method is bound to the 'onended' event of the audio source.\n * It manages looping logic and restarts playback if necessary.\n */\n\n handleLoop = () => {\n if (!this.source) {\n return;\n }\n this.currentLoop++;\n if (this.loopCount !== 'infinite' && this.currentLoop > this.loopCount) {\n this._playing = false;\n this.stop();\n }\n if (this.loopCount === 'infinite' || this.currentLoop < this.loopCount) {\n if (this.buffer) {\n this.recreateSource();\n if (this._playing) {\n (this.source as AudioBufferSourceNode).start(0);\n this._playing = true;\n }\n } else {\n if (this._playing) {\n this.seek(0);\n }\n }\n } else {\n this._playing = false;\n }\n }\n\n private recreateSource() {\n if (!this.buffer || !this.source || !this.panner || !this.context || !this.gainNode) {\n throw new Error('Cannot recreate source of a sound that has been cleaned up');\n }\n this.source = this.context.createBufferSource();\n this.source.buffer = this.buffer;\n this.source.connect(this.panner);\n this.source.onended = this.handleLoop;\n }\n\n /**\n * Starts playing the audio.\n * @returns {[this]} Returns the instance of the Playback class for chaining.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n\n play(): [this] {\n if (!this.source) {\n throw new Error('Cannot play a sound that has been cleaned up');\n }\n if ('mediaElement' in this.source && this.source.mediaElement) {\n this.source.mediaElement.play();\n } else if ('start' in this.source && this.source.start) {\n const offset = this.pauseTime ? this.pauseTime : 0;\n this.source.start(0, offset);\n }\n this._playing = true;\n return [this];\n }\n\n pause(): void {\n if (!this.source) {\n throw new Error('Cannot pause a sound that has been cleaned up');\n }\n if ('mediaElement' in this.source && this.source.mediaElement) {\n this.source.mediaElement.pause();\n } else if ('stop' in this.source && this.source.stop) {\n this.pauseTime = this.context.currentTime - this.startTime;\n this.source.stop();\n }\n this._playing = false;\n }\n\n /**\n * Seeks to a specific time in the audio.\n * @param {number} time - The time in seconds to seek to.\n * @throws {Error} Throws an error if the sound has been cleaned up or if the source type is unsupported.\n */\n\n seek(time: number): void {\n if (!this.source || !this.gainNode || !this.panner) {\n throw new Error('Cannot seek a sound that has been cleaned up');\n }\n const playing = this.isPlaying;\n this.stop();\n if ('mediaElement' in this.source && this.source.mediaElement) {\n this.source.mediaElement.currentTime = time;\n if (playing) {\n this.source.mediaElement.play();\n }\n } else if (this.buffer) {\n // Create a new source to start from the desired time\n this.source = this.context.createBufferSource();\n this.source.buffer = this.buffer;\n this.source.onended = this.handleLoop;\n this.refreshFilters();\n this.source.connect(this.panner);\n if (playing) {\n this.source.start(0, time);\n }\n } else {\n throw new Error('Unsupported source type for seeking');\n }\n }\n\n /**\n * Sets whether the audio source should loop.\n * @param {boolean} loop - Whether the audio should loop.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n set sourceLoop(loop: boolean) {\n if (!this.source) {\n throw new Error('Cannot set loop on a sound that has been cleaned up');\n }\n if ('loop' in this.source) {\n this.source.loop = loop;\n }\n if (\"mediaElement\" in this.source && this.source.mediaElement) {\n this.source.mediaElement.loop = loop;\n }\n }\n\n /**\n * Cleans up resources used by the Playback instance.\n * This method should be called when the audio is no longer needed to free up resources.\n */\n\n cleanup(): void {\n // Ensure cleanup is idempotent\n if (this.source) {\n this.source.disconnect();\n this.source = undefined;\n }\n if (this.gainNode) {\n this.gainNode.disconnect();\n this.gainNode = undefined;\n }\n this._filters.forEach(filter => {\n if (filter) {\n filter.disconnect();\n }\n });\n this._filters = [];\n }\n\n /**\n * Sets or gets the loop count for the audio.\n * @param {LoopCount} loopCount - The number of times the audio should loop. 'infinite' for endless looping.\n * @returns {LoopCount} The loop count if no parameter is provided.\n * @throws {Error} Throws an error if the sound has been cleaned up or if the source type is unsupported.\n */\n\n loop(loopCount?: LoopCount): LoopCount {\n if (!this.source) {\n throw new Error('Cannot loop a sound that has been cleaned up');\n }\n if ('mediaElement' in this.source && this.source.mediaElement) {\n const mediaElement = this.source.mediaElement;\n if (loopCount === undefined) {\n return mediaElement.loop === true ? 'infinite' : 0;\n }\n mediaElement.loop = true;\n // Looping for HTMLMediaElement is controlled by the 'loop' attribute, no need for loopStart or loopEnd\n return mediaElement.loop === true ? 'infinite' : 0;\n\n } else if ('loop' in this.source) {\n if (loopCount === undefined) {\n return this.source.loop === true ? 'infinite' : 0;\n }\n this.source.loop = true;\n this.source.loopEnd = this.source.buffer?.duration || 0;\n this.source.loopStart = 0;\n return this.source.loop === true ? 'infinite' : 0;\n }\n\n throw new Error('Unsupported source type');\n }\n\n /**\n * Stops the audio playback immediately.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n\n stop(): void {\n if (!this.source) {\n throw new Error('Cannot stop a sound that has been cleaned up');\n }\n if (!this.isPlaying) {\n return;\n }\n try {\n if ('stop' in this.source) {\n this.source.stop();\n }\n if (\"mediaElement\" in this.source && this.source.mediaElement) {\n this.source.mediaElement.pause();\n this.source.mediaElement.currentTime = 0;\n }\n } catch (e) {\n }\n this._playing = false;\n this.startTime = 0;\n this.pauseTime = 0;\n }\n\n /**\n * Adds a filter to the audio signal chain.\n * @param {BiquadFilterNode} filter - The filter to add.\n */\n\n addFilter(filter: BiquadFilterNode): void {\n // we have to clone the filter to avoid reusing the same filter node\n const newFilter = filter.context.createBiquadFilter();\n newFilter.type = filter.type;\n newFilter.frequency.value = filter.frequency.value;\n newFilter.Q.value = filter.Q.value;\n super.addFilter(newFilter);\n this.refreshFilters();\n }\n\n /**\n * Removes a filter from the audio signal chain.\n * @param {BiquadFilterNode} filter - The filter to remove.\n */\n\n removeFilter(filter: BiquadFilterNode): void {\n super.removeFilter(filter);\n this.refreshFilters();\n }\n\n /**\n * Refreshes the audio filters by re-applying them to the audio signal chain.\n * This method is called internally whenever filters are added or removed.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n\n private refreshFilters(): void {\n if (!this.panner || !this.gainNode) {\n throw new Error('Cannot update filters on a sound that has been cleaned up');\n }\n let connection = this.panner;\n connection.disconnect();\n connection = this.applyFilters(connection);\n connection.connect(this.gainNode);\n }\n\n /**\n * Creates a clone of the current Playback instance with optional overrides for certain properties.\n * This method allows for the creation of a new Playback instance that shares the same audio context\n * and source node but can have different settings such as loop count or pan type.\n * @param {Partial<Playback>} overrides - An object containing properties to override in the cloned instance.\n * @returns {Playback} A new Playback instance cloned from the current one with the specified overrides applied.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n\n clone(overrides: Partial<{ loopCount: LoopCount; panType: PanType }> = {}): Playback {\n if (!this.source || !this.gainNode || !this.context) {\n throw new Error('Cannot clone a sound that has been cleaned up');\n }\n const panType = overrides.panType || this.panType;\n // we'll need to create a new gain node\n const gainNode = this.context.createGain();\n // clone the source node\n let source: SourceNode;\n if ('buffer' in this.source && this.source.buffer) {\n source = this.context.createBufferSource();\n source.buffer = this.source.buffer;\n } else if ('mediaElement' in this.source && this.source.mediaElement) {\n source = this.context.createMediaElementSource(this.source.mediaElement);\n } else {\n throw new Error('Unsupported source type');\n }\n const loopCount = overrides.loopCount !== undefined ? overrides.loopCount : this.loopCount;\n return new Playback(source, gainNode, this.context, loopCount, panType);\n }\n}\n","/**\n * The Sound class represents an audio asset within a web application, providing a high-level interface\n * for loading, manipulating, and playing audio. It supports both buffer-based and media element-based audio,\n * allowing for efficient playback and manipulation of sound resources.\n *\n * A Sound instance can manage multiple Playback instances, which represent individual playbacks of the sound.\n * This allows for the same sound to be played multiple times simultaneously or with different settings (e.g., volume,\n * playback rate, spatial positioning). The Sound class provides methods to control these playbacks collectively or individually.\n *\n * Key features include:\n * - Loading audio from a URL or using a pre-loaded buffer.\n * - Playing, pausing, resuming, and stopping audio playback.\n * - Looping audio a specific number of times or infinitely.\n * - Adjusting volume, playback rate, and spatial positioning (for 3D audio).\n * - Applying audio filters for effects like reverb, equalization, etc.\n * - Cloning the Sound instance for independent manipulation and playback.\n *\n * The relationship between Sound and Playback is central to the design of the audio system. A Sound object acts as a container\n * and manager for one or more Playback objects. Each Playback object represents a single instance of the sound being played,\n * and can be controlled individually. This architecture allows for complex audio behaviors, such as playing multiple overlapping\n * instances of a sound with different settings, without requiring the user to manually manage each playback instance.\n */\n\n\nimport { SoundType, type BaseSound, type LoopCount, type PanType } from \"./cacophony\";\nimport { PlaybackContainer } from \"./container\";\nimport type { AudioBuffer, AudioContext, BiquadFilterNode, GainNode, SourceNode, } from './context';\nimport { FilterManager } from \"./filters\";\nimport type { PanCloneOverrides } from \"./pannerMixin\";\nimport { Playback } from \"./playback\";\nimport type { VolumeCloneOverrides } from \"./volumeMixin\";\n\ntype SoundCloneOverrides = PanCloneOverrides & VolumeCloneOverrides & {\n loopCount?: LoopCount;\n playbackRate?: number;\n filters?: BiquadFilterNode[];\n};\n\nexport class Sound extends PlaybackContainer(FilterManager) implements BaseSound {\n protected playbacks: Playback[] = [];\n buffer?: AudioBuffer;\n context: AudioContext;\n loopCount: LoopCount = 0;\n private _playbackRate: number = 1;\n\n constructor(public url: string, buffer: AudioBuffer | undefined, context: AudioContext, private globalGainNode: GainNode, public type: SoundType = SoundType.Buffer, public panType: PanType = 'HRTF'\n ) {\n super();\n this.buffer = buffer;\n this.context = context;\n }\n\n /**\n * Clones the current Sound instance, creating a deep copy with the option to override specific properties.\n * This method allows for the creation of a new, independent Sound instance based on the current one, with the\n * flexibility to modify certain attributes through the `overrides` parameter. This is particularly useful for\n * creating variations of a sound without affecting the original instance. The cloned instance includes all properties,\n * playback settings, and filters of the original, unless explicitly overridden.\n *\n * @param {SoundCloneOverrides} overrides - An object specifying properties to override in the cloned instance.\n * This can include audio settings like volume, playback rate, and spatial positioning, as well as\n * more complex configurations like 3D audio options and filter adjustments.\n * @returns {Sound} A new Sound instance that is a clone of the current sound.\n */\n\n clone(overrides: Partial<SoundCloneOverrides> = {}): Sound {\n const panType = overrides.panType || this.panType;\n const stereoPan = overrides.stereoPan !== undefined ? overrides.stereoPan : this.stereoPan;\n const threeDOptions = (overrides.threeDOptions || this.threeDOptions) as PannerOptions;\n const loopCount = overrides.loopCount !== undefined ? overrides.loopCount : this.loopCount;\n const playbackRate = overrides.playbackRate || this.playbackRate;\n const volume = overrides.volume !== undefined ? overrides.volume : this.volume;\n const position = overrides.position && overrides.position.length ? overrides.position : this.position;\n const filters = overrides.filters && overrides.filters.length ? overrides.filters : this._filters;\n\n const clone = new Sound(this.url, this.buffer, this.context, this.globalGainNode, this.type, panType);\n clone.loopCount = loopCount;\n clone._playbackRate = playbackRate;\n clone._volume = volume;\n clone._position = position;\n clone._stereoPan = stereoPan as number;\n clone._threeDOptions = threeDOptions;\n clone.addFilters(filters);\n return clone;\n }\n\n /**\n * Generates a Playback instance for the sound without starting playback.\n * This allows for pre-configuration of playback properties such as volume and position before the sound is actually played.\n * @returns {Playback[]} An array of Playback instances that are ready to be played.\n */\n\n preplay(): Playback[] {\n let source: SourceNode;\n if (this.buffer) {\n source = this.context.createBufferSource();\n source.buffer = this.buffer;\n } else {\n const audio = new Audio();\n audio.crossOrigin = 'anonymous';\n audio.src = this.url;\n audio.preload = \"auto\"\n // we have the audio, let's make a buffer source node out of it\n source = this.context.createMediaElementSource(audio);\n }\n const gainNode = this.context.createGain();\n gainNode.connect(this.globalGainNode);\n const playback = new Playback(source, gainNode, this.context, this.loopCount, this.panType);\n // this.finalizationRegistry.register(playback, playback);\n playback.setGainNode(gainNode);\n playback.volume = this.volume;\n playback.playbackRate = this.playbackRate;\n this._filters.forEach(filter => playback.addFilter(filter));\n if (this.panType === 'HRTF') {\n playback.threeDOptions = this.threeDOptions;\n playback.position = this.position;\n } else if (this.panType === 'stereo') {\n playback.stereoPan = this.stereoPan as number;\n }\n this.playbacks.push(playback);\n return [playback];\n }\n\n /**\n * Seeks to a specific time within the sound's playback.\n * @param { number } time - The time in seconds to seek to.\n * This method iterates through all active `Playback` instances and calls their `seek()` method with the specified time.\n */\n\n seek(time: number): void {\n this.playbacks.forEach(playback => playback.seek(time));\n }\n\n /**\n * Retrieves the duration of the sound in seconds.\n * If the sound is based on an AudioBuffer, it returns the duration of the buffer.\n * Otherwise, it returns 0, indicating that the duration is unknown or not applicable.\n * @returns { number } The duration of the sound in seconds.\n */\n\n get duration() {\n return this.buffer?.duration || 0;\n }\n\n /**\n * Sets or retrieves the loop behavior for the sound.\n * If loopCount is provided, the sound will loop the specified number of times.\n * If loopCount is 'infinite', the sound will loop indefinitely until stopped.\n * If no argument is provided, the method returns the current loop count setting.\n * @param { LoopCount } [loopCount] - The number of times to loop or 'infinite' for indefinite looping.\n * @returns { LoopCount } The current loop count setting if no argument is provided.\n */\n\n loop(loopCount?: LoopCount): LoopCount {\n if (loopCount === undefined) {\n return this.loopCount;\n }\n this.loopCount = loopCount;\n this.playbacks.forEach(p => p.loop(loopCount));\n return this.loopCount;\n }\n\n get playbackRate(): number {\n return this._playbackRate;\n }\n\n set playbackRate(rate: number) {\n this._playbackRate = rate;\n this.playbacks.forEach(p => p.playbackRate = rate);\n }\n\n}\n\n","import { AudioContext, IAudioBuffer } from 'standardized-audio-context';\n\n\nconst appendBuffer = (buffer1: ArrayBuffer, buffer2: ArrayBuffer): ArrayBuffer => {\n var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);\n tmp.set(new Uint8Array(buffer1), 0);\n tmp.set(new Uint8Array(buffer2), buffer1.byteLength);\n return tmp.buffer;\n}\n\n\nexport function createStream(url: string, context: AudioContext) {\n const audioStack: IAudioBuffer[] = [];\n let nextTime = 0;\n\n fetch(url).then(function (response) {\n if (!response.ok) {\n throw new Error('HTTP error, status = ' + response.status);\n }\n if (!response.body) {\n throw new Error('Missing body');\n }\n\n var reader = response.body.getReader();\n let header = new ArrayBuffer(0);//first 44bytes\n\n function read() {\n return reader.read().then(({ value, done }) => {\n let audioBuffer = null;\n if (!value) {\n return;\n }\n\n if (!header.byteLength) {\n //copy first 44 bytes (wav header)\n header = value.buffer.slice(0, 44);\n audioBuffer = value.buffer;\n } else {\n audioBuffer = appendBuffer(header, value.buffer);\n }\n\n context.decodeAudioData(audioBuffer, function (buffer) {\n\n audioStack.push(buffer);\n if (audioStack.length) {\n scheduleBuffers();\n }\n }, function (err) {\n console.log(\"err(decodeAudioData): \" + err);\n });\n if (done) {\n console.log('done');\n return;\n }\n //read next buffer\n read();\n });\n }\n read();\n })\n\n function scheduleBuffers() {\n while (audioStack.length) {\n let buffer = audioStack.shift();\n const source = context.createBufferSource();\n if (!buffer) {\n return;\n }\n source.buffer = buffer;\n source.connect(context.destination);\n if (nextTime == 0)\n nextTime = context.currentTime + 0.02; /// add 50ms latency to work well across systems - tune this if you like\n source.start(nextTime);\n nextTime += source.buffer.duration; // Make the next buffer wait the length of the last buffer before being played\n };\n }\n}\n\n","import type { OscillatorNode } from \"./context\";\r\nimport { BasePlayback } from \"./playback\";\r\n\r\nexport type OscillatorCloneOverrides = {\r\n oscillatorOptions?: Partial<OscillatorOptions>;\r\n};\r\n\r\ntype Constructor<T = {}> = abstract new (...args: any[]) => T;\r\n\r\nexport function OscillatorMixin<TBase extends Constructor>(Base: TBase) {\r\n abstract class OscillatorMixin extends BasePlayback {\r\n\r\n private _oscillatorOptions: Partial<OscillatorOptions> = {};\r\n declare public source?: OscillatorNode;\r\n\r\n get oscillatorOptions(): Partial<OscillatorOptions> {\r\n return this._oscillatorOptions;\r\n }\r\n\r\n set oscillatorOptions(options: Partial<OscillatorOptions>) {\r\n this._oscillatorOptions = options;\r\n if (this.source && this.source instanceof OscillatorNode) {\r\n if (this.oscillatorOptions.detune) this.source.detune.value = this.oscillatorOptions.detune;\r\n if (this.oscillatorOptions.frequency) this.source.frequency.value = this.oscillatorOptions.frequency;\r\n if (this.oscillatorOptions.type) this.source.type = this.oscillatorOptions.type;\r\n }\r\n }\r\n\r\n play(): [this] {\r\n if (!this.source) {\r\n throw new Error('No source node found');\r\n }\r\n if (this.oscillatorOptions.detune) this.source.detune.value = this.oscillatorOptions.detune;\r\n if (this.oscillatorOptions.frequency) this.source.frequency.value = this.oscillatorOptions.frequency;\r\n if (this.oscillatorOptions.type) this.source.type = this.oscillatorOptions.type;\r\n this.source.start();\r\n this._playing = true;\r\n return [this];\r\n }\r\n\r\n stop() {\r\n if (this.source && this.source.stop) {\r\n this.source.stop();\r\n this._playing = false;\r\n }\r\n }\r\n\r\n pause(): void {\r\n this.stop();\r\n }\r\n\r\n };\r\n return OscillatorMixin;\r\n}\r\n","import type { BaseSound, PanType } from \"./cacophony\";\r\nimport type { AudioContext, GainNode, OscillatorNode } from \"./context\";\r\nimport { FilterManager } from \"./filters\";\r\nimport { OscillatorMixin } from \"./oscillatorMixin\";\r\nimport { PannerMixin } from \"./pannerMixin\";\r\nimport { VolumeMixin } from \"./volumeMixin\";\r\n\r\nexport class SynthPlayback extends OscillatorMixin(PannerMixin(VolumeMixin(FilterManager))) implements BaseSound {\r\n constructor(public source: OscillatorNode, gainNode: GainNode, private context: AudioContext, panType: PanType = 'HRTF') {\r\n super()\r\n this.setPanType(panType, context)\r\n this.source.connect(this.panner!);\r\n this.setGainNode(gainNode)\r\n this.panner!.connect(this.gainNode!);\r\n this.refreshFilters()\r\n }\r\n\r\n /**\r\n * Refreshes the audio filters by re-applying them to the audio signal chain.\r\n * This method is called internally whenever filters are added or removed.\r\n * @throws {Error} Throws an error if the sound has been cleaned up.\r\n */\r\n\r\n private refreshFilters(): void {\r\n if (!this.panner || !this.gainNode) {\r\n throw new Error('Cannot update filters on a sound that has been cleaned up');\r\n }\r\n let connection = this.panner;\r\n connection.disconnect();\r\n connection = this.applyFilters(connection);\r\n connection.connect(this.gainNode);\r\n }\r\n}\r\n","import { SoundType, type BaseSound, type PanType } from \"./cacophony\";\r\nimport { PlaybackContainer } from \"./container\";\r\nimport type { AudioContext, GainNode } from './context';\r\nimport type { FilterCloneOverrides } from \"./filters\";\r\nimport { FilterManager } from \"./filters\";\r\nimport type { OscillatorCloneOverrides } from \"./oscillatorMixin\";\r\nimport type { PanCloneOverrides } from \"./pannerMixin\";\r\nimport { SynthPlayback } from \"./synthPlayback\";\r\nimport type { VolumeCloneOverrides } from \"./volumeMixin\";\r\n\r\ntype SynthCloneOverrides = FilterCloneOverrides & OscillatorCloneOverrides & PanCloneOverrides & VolumeCloneOverrides\r\n\r\nexport class Synth extends PlaybackContainer(FilterManager) implements BaseSound {\r\n private _oscillatorOptions: Partial<OscillatorOptions>;\r\n protected playbacks: SynthPlayback[] = [];\r\n\r\n constructor(\r\n public context: AudioContext,\r\n private globalGainNode: GainNode,\r\n public type: SoundType = SoundType.Oscillator,\r\n public panType: PanType = 'HRTF',\r\n oscillatorOptions: Partial<OscillatorOptions> = {}\r\n ) {\r\n super();\r\n this.context = context;\r\n this._oscillatorOptions = oscillatorOptions;\r\n }\r\n\r\n /**\r\n * Clones the current Synth instance, creating a deep copy with the option to override specific properties.\r\n * This method allows for the creation of a new, independent Synth instance based on the current one, with the\r\n * flexibility to modify certain attributes through the `overrides` parameter. This is particularly useful for\r\n * creating variations of a synth without affecting the original instance. The cloned instance includes all properties,\r\n * playback settings, and filters of the original, unless explicitly overridden.\r\n *\r\n * @param {SynthCloneOverrides} overrides - An object specifying properties to override in the cloned instance.\r\n * This can include audio settings like volume, playback rate, and spatial positioning, as well as\r\n * more complex configurations like 3D audio options and filter adjustments.\r\n * @returns {Sound} A new Sound instance that is a clone of the current sound.\r\n */\r\n clone(overrides: Partial<SynthCloneOverrides> = {}): Synth {\r\n const panType = overrides.panType || this.panType;\r\n const stereoPan = overrides.stereoPan !== undefined ? overrides.stereoPan : (this.stereoPan ?? 0);\r\n const threeDOptions = (overrides.threeDOptions || this.threeDOptions) as PannerOptions;\r\n const volume = overrides.volume !== undefined ? overrides.volume : this.volume;\r\n const position = overrides.position && overrides.position.length ? overrides.position : this.position;\r\n const filters = overrides.filters && overrides.filters.length ? overrides.filters : this._filters;\r\n const oscillatorOptions = overrides.oscillatorOptions || this._oscillatorOptions;\r\n\r\n const clone = new Synth(this.context, this.globalGainNode, this.type, panType, oscillatorOptions);\r\n clone._volume = volume;\r\n clone._position = position;\r\n clone._stereoPan = stereoPan as number;\r\n clone._threeDOptions = threeDOptions;\r\n clone.addFilters(filters);\r\n return clone;\r\n }\r\n\r\n /**\r\n * Generates a Playback instance for the sound without starting playback.\r\n * This allows for pre-configuration of playback properties such as volume and position before the sound is actually played.\r\n * @returns {Playback[]} An array of Playback instances that are ready to be played.\r\n */\r\n preplay(): SynthPlayback[] {\r\n const oscillator = this.context.createOscillator();\r\n if (this.oscillatorOptions.detune) oscillator.detune.value = this.oscillatorOptions.detune;\r\n if (this.oscillatorOptions.frequency) oscillator.frequency.value = this.oscillatorOptions.frequency;\r\n if (this.oscillatorOptions.type) oscillator.type = this.oscillatorOptions.type;\r\n\r\n const gainNode = this.context.createGain();\r\n gainNode.connect(this.globalGainNode);\r\n const playback = new SynthPlayback(oscillator, gainNode, this.context, this.panType);\r\n playback.volume = this.volume;\r\n this._filters.forEach(filter => playback.addFilter(filter));\r\n if (this.panType === 'HRTF') {\r\n playback.threeDOptions = this.threeDOptions;\r\n playback.position = this.position;\r\n } else if (this.panType === 'stereo') {\r\n playback.stereoPan = this.stereoPan as number;\r\n }\r\n this.playbacks.push(playback);\r\n return [playback];\r\n }\r\n\r\n get oscillatorOptions(): Partial<OscillatorOptions> {\r\n return this._oscillatorOptions;\r\n }\r\n\r\n set oscillatorOptions(options: Partial<OscillatorOptions>) {\r\n this._oscillatorOptions = options;\r\n this.playbacks.forEach(p => {\r\n if (p.source instanceof OscillatorNode) {\r\n if (this.oscillatorOptions.detune) p.source.detune.value = this.oscillatorOptions.detune;\r\n if (this.oscillatorOptions.frequency) p.source.frequency.value = this.oscillatorOptions.frequency;\r\n if (this.oscillatorOptions.type) p.source.type = this.oscillatorOptions.type;\r\n }\r\n });\r\n }\r\n}\r\n","import { AudioContext, AudioWorkletNode, IAudioListener, IMediaStreamAudioSourceNode, IPannerNode, IPannerOptions } from 'standardized-audio-context';\nimport phaseVocoderProcessorWorkletUrl from './bundles/phase-vocoder-bundle.js?url';\nimport { AudioCache } from './cache';\nimport { AudioBuffer, BiquadFilterNode, GainNode } from './context';\nimport { FilterManager } from './filters';\nimport { Group } from './group';\nimport type { Playback } from './playback';\nimport { Sound } from './sound';\nimport { createStream } from './stream';\nimport { Synth } from './synth';\n\n\nexport enum SoundType {\n HTML = 'HTML',\n Streaming = 'Streaming',\n Buffer = 'Buffer',\n Oscillator = 'oscillator'\n}\n\n\n\ntype PannerNode = IPannerNode<AudioContext>;\n\n\n\ntype MediaStreamAudioSourceNode = IMediaStreamAudioSourceNode<AudioContext>;\n\n\n/**\n * Represents a 3D position in space.\n * @typedef {Array<number>} Position - An array of three numbers representing the x, y, and z coordinates.\n */\nexport type Position = [x: number, y: number, z: number];\n\n/**\n * Represents the orientation of an object in 3D space.\n * @typedef {Object} Orientation - An object containing two positions: forward and up.\n * @property {Position} forward - The forward direction of the object.\n * @property {Position} up - The up direction of the object.\n */\nexport type Orientation = {\n forward: Position;\n up: Position;\n}\n\n/**\n * Represents the number of times a sound should loop.\n * @typedef {number | 'infinite'} LoopCount - The number of loops, or 'infinite' for endless looping.\n */\nexport type LoopCount = number | 'infinite';\n\n/**\n * Represents the type of fade effect to apply.\n * @typedef {'linear' | 'exponential'} FadeType - The fade type, either 'linear' or 'exponential'.\n */\nexport type FadeType = 'linear' | 'exponential';\n\n/**\n * Represents the type of panning effect to apply.\n * @typedef {'HRTF' | 'stereo'} PanType - The pan type, either 'HRTF' for 3D audio or 'stereo' for traditional stereo panning.\n */\nexport type PanType = 'HRTF' | 'stereo';\n\n/**\n * The base interface for any sound-producing entity, including individual sounds, groups, and playbacks.\n * @interface BaseSound\n */\nexport interface BaseSound {\n isPlaying: boolean;\n play(): BaseSound[];\n seek?(time: number): void;\n stop(): void;\n pause(): void;\n addFilter(filter: BiquadFilterNode): void;\n removeFilter(filter: BiquadFilterNode): void;\n volume: number;\n position?: Position;\n threeDOptions?: any;\n}\n\n\n\n\n\nexport class Cacophony {\n context: AudioContext;\n globalGainNode: GainNode;\n listener: IAudioListener;\n private prevVolume: number = 1;\n private finalizationRegistry: FinalizationRegistry<Playback>;\n\n constructor(context?: AudioContext) {\n this.context = context || new AudioContext();\n this.listener = this.context.listener;\n this.globalGainNode = this.context.createGain();\n this.globalGainNode.connect(this.context.destination);\n\n this.finalizationRegistry = new FinalizationRegistry((heldValue) => {\n // Cleanup callback for Playbacks\n heldValue.cleanup();\n });\n }\n\n async loadWorklets() {\n if (this.context.audioWorklet) {\n await this.createWorkletNode('phase-vocoder', phaseVocoderProcessorWorkletUrl);\n }\n else {\n console.warn('AudioWorklet not supported');\n }\n }\n\n\n async createWorkletNode(\n name: string,\n url: string\n ) {\n // ensure audioWorklet has been loaded\n if (!this.context.audioWorklet) {\n throw new Error('AudioWorklet not supported');\n }\n try {\n return new AudioWorkletNode!(this.context, name);\n } catch (err) {\n console.error(err)\n console.log(\"Loading worklet from url\", url);\n try {\n await this.context.audioWorklet.addModule(url);\n } catch (err) {\n console.error(err);\n throw new Error(`Could not load worklet from url ${url}`);\n }\n\n return new AudioWorkletNode!(this.context, name);\n }\n }\n\n clearMemoryCache(): void {\n AudioCache.clearMemoryCache();\n }\n\n\n createOscillator(options: OscillatorOptions) {\n const synth = new Synth(this.context, this.globalGainNode, SoundType.Oscillator, 'HRTF', options);\n return synth;\n }\n\n async createSound(buffer: AudioBuffer, soundType?: SoundType, panType?: PanType): Promise<Sound>\n\n async createSound(url: string, soundType?: SoundType, panType?: PanType): Promise<Sound>\n\n async createSound(bufferOrUrl: AudioBuffer | string, soundType: SoundType = SoundType.Buffer, panType: PanType = 'HRTF'): Promise<Sound> {\n if (typeof bufferOrUrl === 'object') {\n return Promise.resolve(new Sound(\"\", bufferOrUrl, this.context, this.globalGainNode, SoundType.Buffer, panType));\n }\n const url = bufferOrUrl;\n if (soundType === SoundType.HTML) {\n const audio = new Audio();\n audio.src = url;\n audio.crossOrigin = 'anonymous';\n return new Sound(url, undefined, this.context, this.globalGainNode, SoundType.HTML, panType);\n }\n return AudioCache.getAudioBuffer(this.context, url).then(buffer => new Sound(url as string, buffer, this.context, this.globalGainNode, soundType, panType));\n }\n\n async createGroup(sounds: Sound[]): Promise<Group> {\n const group = new Group();\n sounds.forEach(sound => group.addSound(sound));\n return group;\n }\n\n async createGroupFromUrls(urls: string[], soundType: SoundType = SoundType.Buffer, panType: PanType = 'HRTF'): Promise<Group> {\n const group = new Group();\n const sounds = await Promise.all(urls.map(url => this.createSound(url, soundType, panType)));\n sounds.forEach(sound => group.addSound(sound));\n return group;\n }\n\n async createStream(url: string): Promise<Sound> {\n const stream = await createStream(url, this.context);\n const sound = new Sound(url, undefined, this.context, this.globalGainNode, SoundType.Streaming);\n return sound;\n }\n\n createBiquadFilter = ({ type, frequency, gain, Q }: BiquadFilterOptions): BiquadFilterNode => {\n if (frequency === undefined) {\n frequency = 350;\n }\n const filter = this.context.createBiquadFilter();\n filter.type = type || 'lowpass';\n filter.frequency.value = frequency;\n filter.gain.value = gain || 0;\n filter.Q.value = Q || 1;\n return filter;\n }\n\n /**\n * Creates a PannerNode with the specified options.\n * @param {IPannerOptions} options - An object containing the options to use when creating the PannerNode.\n * @returns {PannerNode} A new PannerNode instance with the specified options.\n * @example\n * const panner = audio.createPanner({\n * positionX: 0,\n * positionY: 0,\n * positionZ: 0,\n * orientationX: 0,\n * orientationY: 0,\n * orientationZ: 0,\n * });\n */\n\n createPanner({ coneInnerAngle, coneOuterAngle, coneOuterGain, distanceModel, maxDistance, channelCount, channelCountMode, channelInterpretation, panningModel, refDistance, rolloffFactor, positionX, positionY, positionZ, orientationX, orientationY, orientationZ }: Partial<IPannerOptions>): PannerNode {\n const panner = this.context.createPanner();\n panner.coneInnerAngle = coneInnerAngle || 360;\n panner.coneOuterAngle = coneOuterAngle || 360;\n panner.coneOuterGain = coneOuterGain || 0;\n panner.distanceModel = distanceModel || 'inverse';\n panner.maxDistance = maxDistance || 10000;\n panner.channelCount = channelCount || 2;\n panner.channelCountMode = channelCountMode || 'clamped-max';\n panner.channelInterpretation = channelInterpretation || 'speakers';\n panner.panningModel = panningModel || 'HRTF';\n panner.refDistance = refDistance || 1;\n panner.rolloffFactor = rolloffFactor || 1;\n panner.positionX.value = positionX || 0;\n panner.positionY.value = positionY || 0;\n panner.positionZ.value = positionZ || 0;\n panner.orientationX.value = orientationX || 0;\n panner.orientationY.value = orientationY || 0;\n panner.orientationZ.value = orientationZ || 0;\n return panner;\n }\n\n /**\n * Suspends the audio context.\n */\n pause(): void {\n if ('suspend' in this.context) {\n this.context.suspend();\n }\n }\n\n /**\n * Resumes the audio context.\n * This method is required to resume the audio context on mobile devices.\n * On desktop, the audio context will automatically resume when a sound is played.\n */\n\n resume() {\n if ('resume' in this.context) {\n this.context.resume();\n }\n }\n\n setGlobalVolume(volume: number) {\n this.globalGainNode.gain.value = volume;\n }\n\n get volume(): number {\n return this.globalGainNode.gain.value;\n }\n\n set volume(volume: number) {\n if (this.muted) {\n this.prevVolume = volume;\n return;\n }\n this.setGlobalVolume(volume);\n }\n\n mute() {\n if (!this.muted) {\n this.prevVolume = this.globalGainNode.gain.value;\n this.setGlobalVolume(0);\n }\n }\n\n unmute() {\n if (this.muted) {\n this.setGlobalVolume(this.prevVolume);\n }\n }\n\n get muted(): boolean {\n return this.globalGainNode.gain.value === 0;\n }\n\n set muted(muted: boolean) {\n if (muted !== this.muted) {\n if (muted) {\n this.mute();\n } else {\n this.unmute();\n }\n }\n }\n\n getMicrophoneStream(): Promise<MicrophoneStream> {\n return new Promise((resolve, reject) => {\n navigator.mediaDevices.getUserMedia({ audio: true })\n .then(stream => {\n const microphoneStream = new MicrophoneStream(this.context);\n microphoneStream.play();\n resolve(microphoneStream);\n })\n .catch(err => {\n reject(err);\n });\n });\n }\n\n get listenerOrientation(): Orientation {\n return {\n forward: [this.listener.forwardX.value, this.listener.forwardY.value, this.listener.forwardZ.value],\n up: [this.listener.upX.value, this.listener.upY.value, this.listener.upZ.value]\n };\n }\n\n set listenerOrientation(orientation: Orientation) {\n const { forward, up } = orientation;\n const [forwardX, forwardY, forwardZ] = forward;\n const [upX, upY, upZ] = up;\n this.listener.forwardX.value = forwardX;\n this.listener.forwardY.value = forwardY;\n this.listener.forwardZ.value = forwardZ;\n this.listener.upX.value = upX;\n this.listener.upY.value = upY;\n this.listener.upZ.value = upZ;\n }\n\n get listenerUpOrientation(): Position {\n return [this.listener.upX.value, this.listener.upY.value, this.listener.upZ.value];\n }\n\n set listenerUpOrientation(up: Position) {\n const [x, y, z] = up;\n this.listener.upX.value = x;\n this.listener.upY.value = y;\n this.listener.upZ.value = z;\n }\n\n get listenerForwardOrientation(): Position {\n return [this.listener.forwardX.value, this.listener.forwardY.value, this.listener.forwardZ.value];\n }\n\n set listenerForwardOrientation(forward: Position) {\n const [x, y, z] = forward;\n this.listener.forwardX.value = x;\n this.listener.forwardY.value = y;\n this.listener.forwardZ.value = z;\n }\n\n get listenerPosition(): Position {\n return [this.listener.positionX.value, this.listener.positionY.value, this.listener.positionZ.value];\n }\n\n set listenerPosition(position: Position) {\n const [x, y, z] = position;\n const currentTime = this.context.currentTime;\n this.listener.positionX.setValueAtTime(x, currentTime);\n this.listener.positionY.setValueAtTime(y, currentTime);\n this.listener.positionZ.setValueAtTime(z, currentTime);\n }\n\n}\n\n\nexport class MicrophonePlayback extends FilterManager {\n private context: AudioContext;\n private source?: MediaStreamAudioSourceNode;\n private gainNode?: GainNode;\n private panner?: PannerNode;\n\n\n constructor(source: MediaStreamAudioSourceNode, gainNode: GainNode, context: AudioContext, loopCount: LoopCount = 0) {\n super();\n this.source = source;\n this.gainNode = gainNode;\n this.context = context;\n this.panner = context.createPanner();\n source.connect(this.panner).connect(this.gainNode);\n this.refreshFilters();\n }\n\n get duration() {\n return 0;\n }\n\n play() {\n if (!this.source) {\n throw new Error('Cannot play a sound that has been cleaned up');\n }\n return [this];\n }\n\n\n /**\n * Indicates whether the audio is currently playing.\n * @returns {boolean} True if the audio is playing, false otherwise.\n */\n\n get isPlaying() {\n return Boolean(this.source);\n }\n\n get volume(): number {\n if (!this.gainNode) {\n throw new Error('Cannot get volume of a sound that has been cleaned up');\n }\n return this.gainNode.gain.value;\n }\n\n set volume(v: number) {\n if (!this.gainNode) {\n throw new Error('Cannot set volume of a sound that has been cleaned up');\n }\n this.gainNode.gain.value = v;\n }\n\n stop(): void {\n if (!this.source) {\n throw new Error('Cannot stop a sound that has been cleaned up');\n }\n this.source.mediaStream.getTracks().forEach(track => track.stop());\n }\n\n pause(): void {\n if (!this.source) {\n throw new Error('Cannot pause a sound that has been cleaned up');\n }\n this.source.mediaStream.getTracks().forEach(track => track.enabled = false);\n }\n\n resume(): void {\n if (!this.source) {\n throw new Error('Cannot resume a sound that has been cleaned up');\n }\n this.source.mediaStream.getTracks().forEach(track => track.enabled = true);\n }\n\n addFilter(filter: BiquadFilterNode): void {\n super.addFilter(filter);\n this.refreshFilters();\n }\n\n removeFilter(filter: BiquadFilterNode): void {\n super.removeFilter(filter);\n this.refreshFilters();\n }\n\n set position(position: Position) {\n if (!this.panner) {\n throw new Error('Cannot move a sound that has been cleaned up');\n }\n const [x, y, z] = position;\n this.panner.positionX.value = x;\n this.panner.positionY.value = y;\n this.panner.positionZ.value = z;\n }\n\n get position(): Position {\n if (!this.panner) {\n throw new Error('Cannot get position of a sound that has been cleaned up');\n }\n return [this.panner.positionX.value, this.panner.positionY.value, this.panner.positionZ.value];\n }\n\n private refreshFilters(): void {\n if (!this.source || !this.gainNode) {\n throw new Error('Cannot update filters on a sound that has been cleaned up');\n }\n let connection = this.source;\n this.source.disconnect();\n connection = this.applyFilters(connection);\n connection.connect(this.gainNode);\n }\n\n get playbackRate(): number {\n // Playback rate is not applicable for live microphone stream\n return 1;\n }\n\n set playbackRate(rate: number) {\n }\n\n\n\n}\n\nexport class MicrophoneStream extends FilterManager implements BaseSound {\n context: AudioContext;\n private _position: Position = [0, 0, 0];\n loopCount: LoopCount = 0;\n private prevVolume: number = 1;\n private microphoneGainNode: GainNode;\n private streamPlayback?: MicrophonePlayback;\n private stream: MediaStream | undefined;\n private streamSource?: MediaStreamAudioSourceNode;\n\n constructor(context: AudioContext) {\n super();\n this.context = context;\n this.microphoneGainNode = this.context.createGain();\n }\n\n play(): MicrophonePlayback[] {\n if (!this.stream) {\n navigator.mediaDevices.getUserMedia({ audio: true })\n .then(stream => {\n this.stream = stream;\n this.streamSource = this.context.createMediaStreamSource(this.stream);\n this.streamPlayback = new MicrophonePlayback(this.streamSource, this.microphoneGainNode, this.context);\n this.streamPlayback.play();\n })\n .catch(err => {\n console.error('Error initializing microphone stream:', err);\n });\n }\n return this.streamPlayback ? [this.streamPlayback] : [];\n }\n\n get duration() {\n return 0;\n }\n\n\n seek(time: number) {\n // Seeking is not applicable for live microphone stream\n }\n\n /**\n * A boolean indicating whether the sound is currently playing.\n * @returns {boolean} True if the sound is playing, false otherwise.\n */\n\n get isPlaying(): boolean {\n return Boolean(this.streamPlayback);\n }\n\n stop() {\n if (this.streamPlayback) {\n this.streamPlayback.stop();\n this.streamPlayback = undefined;\n }\n }\n\n pause() {\n if (this.streamPlayback) {\n this.streamPlayback.pause();\n }\n }\n\n resume() {\n if (this.streamPlayback) {\n this.streamPlayback.resume();\n }\n }\n\n addFilter(filter: BiquadFilterNode): void {\n if (this.streamPlayback) {\n this.streamPlayback.addFilter(filter);\n }\n }\n\n removeFilter(filter: BiquadFilterNode): void {\n if (this.streamPlayback) {\n this.streamPlayback.removeFilter(filter);\n }\n }\n\n get volume(): number {\n return this.streamPlayback ? this.streamPlayback.volume : 0;\n }\n\n set volume(volume: number) {\n if (this.streamPlayback) {\n this.streamPlayback.volume = volume;\n }\n }\n\n get position(): Position {\n // Position is not applicable for live microphone stream\n return [0, 0, 0];\n }\n\n set position(position: Position) {\n // Position is not applicable for live microphone stream\n }\n\n loop(loopCount?: LoopCount): LoopCount {\n // Looping is not applicable for live microphone stream\n return 0;\n }\n\n\n get playbackRate(): number {\n // Playback rate is not applicable for live microphone stream\n return 1;\n }\n\n set playbackRate(rate: number) {\n }\n}\n"],"names":["phaseVocoderProcessorWorkletUrl","LRUCache","maxSize","key","value","firstKey","DEFAULT_CACHE_SIZE","AudioCache","error","url","cache","response","etag","lastModified","headers","fetchResponse","responseClone","newEtag","newLastModified","cacheData","cachedResponse","context","arrayBuffer","metaResponse","base64Data","buffer","c","audioBuffer","pendingRequest","bufferFromCache","metadata","FilterManager","filter","f","connection","prevConnection","filters","Group","sounds","randomIndex","playback","p","shouldLoop","sound","a","b","time","playbacks","loopCount","position","volume","rate","PlaybackContainer","Base","options","PannerMixin","panType","audioContext","pannerNode","clamp","panner","x","y","z","min","max","VolumeMixin","gainNode","v","BasePlayback","Playback","source","offset","playing","loop","mediaElement","newFilter","overrides","Sound","globalGainNode","type","SoundType","stereoPan","threeDOptions","playbackRate","clone","audio","appendBuffer","buffer1","buffer2","tmp","createStream","audioStack","nextTime","reader","header","read","done","scheduleBuffers","err","OscillatorMixin","SynthPlayback","Synth","oscillatorOptions","oscillator","Cacophony","AudioContext","heldValue","name","AudioWorkletNode","bufferOrUrl","soundType","group","urls","frequency","gain","Q","coneInnerAngle","coneOuterAngle","coneOuterGain","distanceModel","maxDistance","channelCount","channelCountMode","channelInterpretation","panningModel","refDistance","rolloffFactor","positionX","positionY","positionZ","orientationX","orientationY","orientationZ","muted","resolve","reject","stream","microphoneStream","MicrophoneStream","orientation","forward","up","forwardX","forwardY","forwardZ","upX","upY","upZ","currentTime","MicrophonePlayback","track"],"mappings":"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"}
1
+ {"version":3,"file":"cacophony.cjs.js","sources":["../src/bundles/phase-vocoder-bundle.js?url","../src/cache.ts","../src/filters.ts","../src/group.ts","../src/container.ts","../src/pannerMixin.ts","../src/volumeMixin.ts","../src/playback.ts","../src/sound.ts","../src/stream.ts","../src/oscillatorMixin.ts","../src/synthPlayback.ts","../src/synth.ts","../src/cacophony.ts"],"sourcesContent":["export default \"data:text/javascript;base64,KGZ1bmN0aW9uIChleHBvcnRzKSB7CiAgICAndXNlIHN0cmljdCc7CgogICAgY29uc3QgV0VCQVVESU9fQkxPQ0tfU0laRSA9IDEyODsKICAgIGNvbnN0IERFRkFVTFRfQkxPQ0tfU0laRSA9IDEwMjQ7IC8vIERlZmF1bHQgYmxvY2sgc2l6ZSBpZiBub3QgcHJvdmlkZWQgaW4gb3B0aW9ucwogICAgLyoqIE92ZXJsYXAtQWRkIE5vZGUgKi8KICAgIGNsYXNzIE9MQVByb2Nlc3NvciBleHRlbmRzIEF1ZGlvV29ya2xldFByb2Nlc3NvciB7CiAgICAgICAgbmJJbnB1dHM7CiAgICAgICAgbmJPdXRwdXRzOwogICAgICAgIGJsb2NrU2l6ZTsKICAgICAgICBob3BTaXplOwogICAgICAgIG5iT3ZlcmxhcHM7CiAgICAgICAgaW5wdXRCdWZmZXJzID0gW107CiAgICAgICAgaW5wdXRCdWZmZXJzSGVhZCA9IFtdOwogICAgICAgIGlucHV0QnVmZmVyc1RvU2VuZCA9IFtdOwogICAgICAgIG91dHB1dEJ1ZmZlcnMgPSBbXTsKICAgICAgICBvdXRwdXRCdWZmZXJzVG9SZXRyaWV2ZSA9IFtdOwogICAgICAgIGNvbnN0cnVjdG9yKG9wdGlvbnMpIHsKICAgICAgICAgICAgc3VwZXIob3B0aW9ucyk7CiAgICAgICAgICAgIHRoaXMubmJJbnB1dHMgPSBvcHRpb25zLm51bWJlck9mSW5wdXRzIHx8IDE7CiAgICAgICAgICAgIHRoaXMubmJPdXRwdXRzID0gb3B0aW9ucy5udW1iZXJPZk91dHB1dHMgfHwgMTsKICAgICAgICAgICAgdGhpcy5ibG9ja1NpemUgPSBvcHRpb25zLnByb2Nlc3Nvck9wdGlvbnMuYmxvY2tTaXplIHx8IERFRkFVTFRfQkxPQ0tfU0laRTsKICAgICAgICAgICAgdGhpcy5ob3BTaXplID0gV0VCQVVESU9fQkxPQ0tfU0laRTsKICAgICAgICAgICAgdGhpcy5uYk92ZXJsYXBzID0gTWF0aC5mbG9vcih0aGlzLmJsb2NrU2l6ZSAvIHRoaXMuaG9wU2l6ZSk7CiAgICAgICAgICAgIHRoaXMuaW5pdGlhbGl6ZUJ1ZmZlcnMoKTsKICAgICAgICB9CiAgICAgICAgaW5pdGlhbGl6ZUJ1ZmZlcnMoKSB7CiAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzID0gbmV3IEFycmF5KHRoaXMubmJJbnB1dHMpOwogICAgICAgICAgICB0aGlzLmlucHV0QnVmZmVyc0hlYWQgPSBuZXcgQXJyYXkodGhpcy5uYklucHV0cyk7CiAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzVG9TZW5kID0gbmV3IEFycmF5KHRoaXMubmJJbnB1dHMpOwogICAgICAgICAgICB0aGlzLm91dHB1dEJ1ZmZlcnMgPSBuZXcgQXJyYXkodGhpcy5uYk91dHB1dHMpOwogICAgICAgICAgICB0aGlzLm91dHB1dEJ1ZmZlcnNUb1JldHJpZXZlID0gbmV3IEFycmF5KHRoaXMubmJPdXRwdXRzKTsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm5iSW5wdXRzOyBpKyspIHsKICAgICAgICAgICAgICAgIHRoaXMuYWxsb2NhdGVJbnB1dENoYW5uZWxzKGksIDEpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5uYk91dHB1dHM7IGkrKykgewogICAgICAgICAgICAgICAgdGhpcy5hbGxvY2F0ZU91dHB1dENoYW5uZWxzKGksIDEpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGFsbG9jYXRlSW5wdXRDaGFubmVscyhpbnB1dEluZGV4LCBuYkNoYW5uZWxzKSB7CiAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzW2lucHV0SW5kZXhdID0gbmV3IEFycmF5KG5iQ2hhbm5lbHMpOwogICAgICAgICAgICB0aGlzLmlucHV0QnVmZmVyc0hlYWRbaW5wdXRJbmRleF0gPSBuZXcgQXJyYXkobmJDaGFubmVscyk7CiAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzVG9TZW5kW2lucHV0SW5kZXhdID0gbmV3IEFycmF5KG5iQ2hhbm5lbHMpOwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG5iQ2hhbm5lbHM7IGkrKykgewogICAgICAgICAgICAgICAgdGhpcy5pbnB1dEJ1ZmZlcnNbaW5wdXRJbmRleF1baV0gPSBuZXcgRmxvYXQzMkFycmF5KHRoaXMuYmxvY2tTaXplICsgV0VCQVVESU9fQkxPQ0tfU0laRSk7CiAgICAgICAgICAgICAgICB0aGlzLmlucHV0QnVmZmVyc1tpbnB1dEluZGV4XVtpXS5maWxsKDApOwogICAgICAgICAgICAgICAgdGhpcy5pbnB1dEJ1ZmZlcnNIZWFkW2lucHV0SW5kZXhdW2ldID0gdGhpcy5pbnB1dEJ1ZmZlcnNbaW5wdXRJbmRleF1baV0uc3ViYXJyYXkoMCwgdGhpcy5ibG9ja1NpemUpOwogICAgICAgICAgICAgICAgdGhpcy5pbnB1dEJ1ZmZlcnNUb1NlbmRbaW5wdXRJbmRleF1baV0gPSBuZXcgRmxvYXQzMkFycmF5KHRoaXMuYmxvY2tTaXplKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBhbGxvY2F0ZU91dHB1dENoYW5uZWxzKG91dHB1dEluZGV4LCBuYkNoYW5uZWxzKSB7CiAgICAgICAgICAgIHRoaXMub3V0cHV0QnVmZmVyc1tvdXRwdXRJbmRleF0gPSBuZXcgQXJyYXkobmJDaGFubmVscyk7CiAgICAgICAgICAgIHRoaXMub3V0cHV0QnVmZmVyc1RvUmV0cmlldmVbb3V0cHV0SW5kZXhdID0gbmV3IEFycmF5KG5iQ2hhbm5lbHMpOwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG5iQ2hhbm5lbHM7IGkrKykgewogICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRCdWZmZXJzW291dHB1dEluZGV4XVtpXSA9IG5ldyBGbG9hdDMyQXJyYXkodGhpcy5ibG9ja1NpemUpOwogICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRCdWZmZXJzW291dHB1dEluZGV4XVtpXS5maWxsKDApOwogICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRCdWZmZXJzVG9SZXRyaWV2ZVtvdXRwdXRJbmRleF1baV0gPSBuZXcgRmxvYXQzMkFycmF5KHRoaXMuYmxvY2tTaXplKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZWFsbG9jYXRlQ2hhbm5lbHNJZk5lZWRlZChpbnB1dHMsIG91dHB1dHMpIHsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm5iSW5wdXRzOyBpKyspIHsKICAgICAgICAgICAgICAgIGxldCBuYkNoYW5uZWxzID0gaW5wdXRzW2ldLmxlbmd0aDsKICAgICAgICAgICAgICAgIGlmIChuYkNoYW5uZWxzICE9PSB0aGlzLmlucHV0QnVmZmVyc1tpXS5sZW5ndGgpIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmFsbG9jYXRlSW5wdXRDaGFubmVscyhpLCBuYkNoYW5uZWxzKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJPdXRwdXRzOyBpKyspIHsKICAgICAgICAgICAgICAgIGxldCBuYkNoYW5uZWxzID0gb3V0cHV0c1tpXS5sZW5ndGg7CiAgICAgICAgICAgICAgICBpZiAobmJDaGFubmVscyAhPT0gdGhpcy5vdXRwdXRCdWZmZXJzW2ldLmxlbmd0aCkgewogICAgICAgICAgICAgICAgICAgIHRoaXMuYWxsb2NhdGVPdXRwdXRDaGFubmVscyhpLCBuYkNoYW5uZWxzKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZWFkSW5wdXRzKGlucHV0cykgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJJbnB1dHM7IGkrKykgewogICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCB0aGlzLmlucHV0QnVmZmVyc1tpXS5sZW5ndGg7IGorKykgewogICAgICAgICAgICAgICAgICAgIGxldCB3ZWJBdWRpb0Jsb2NrID0gaW5wdXRzW2ldW2pdOwogICAgICAgICAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzW2ldW2pdLnNldCh3ZWJBdWRpb0Jsb2NrLCB0aGlzLmJsb2NrU2l6ZSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgd3JpdGVPdXRwdXRzKG91dHB1dHMpIHsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm5iT3V0cHV0czsgaSsrKSB7CiAgICAgICAgICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IHRoaXMub3V0cHV0QnVmZmVyc1tpXS5sZW5ndGg7IGorKykgewogICAgICAgICAgICAgICAgICAgIGxldCB3ZWJBdWRpb0Jsb2NrID0gb3V0cHV0c1tpXVtqXTsKICAgICAgICAgICAgICAgICAgICB3ZWJBdWRpb0Jsb2NrLnNldCh0aGlzLm91dHB1dEJ1ZmZlcnNbaV1bal0uc3ViYXJyYXkoMCwgV0VCQVVESU9fQkxPQ0tfU0laRSkpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHNoaWZ0SW5wdXRCdWZmZXJzKCkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJJbnB1dHM7IGkrKykgewogICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCB0aGlzLmlucHV0QnVmZmVyc1tpXS5sZW5ndGg7IGorKykgewogICAgICAgICAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzW2ldW2pdLmNvcHlXaXRoaW4oMCwgV0VCQVVESU9fQkxPQ0tfU0laRSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgc2hpZnRPdXRwdXRCdWZmZXJzKCkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJPdXRwdXRzOyBpKyspIHsKICAgICAgICAgICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgdGhpcy5vdXRwdXRCdWZmZXJzW2ldLmxlbmd0aDsgaisrKSB7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRCdWZmZXJzW2ldW2pdLmNvcHlXaXRoaW4oMCwgV0VCQVVESU9fQkxPQ0tfU0laRSk7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRCdWZmZXJzW2ldW2pdLmZpbGwoMCwgdGhpcy5ibG9ja1NpemUgLSBXRUJBVURJT19CTE9DS19TSVpFKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBwcmVwYXJlSW5wdXRCdWZmZXJzVG9TZW5kKCkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJJbnB1dHM7IGkrKykgewogICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCB0aGlzLmlucHV0QnVmZmVyc1tpXS5sZW5ndGg7IGorKykgewogICAgICAgICAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzVG9TZW5kW2ldW2pdLnNldCh0aGlzLmlucHV0QnVmZmVyc0hlYWRbaV1bal0pOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGhhbmRsZU91dHB1dEJ1ZmZlcnNUb1JldHJpZXZlKCkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJPdXRwdXRzOyBpKyspIHsKICAgICAgICAgICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgdGhpcy5vdXRwdXRCdWZmZXJzW2ldLmxlbmd0aDsgaisrKSB7CiAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgayA9IDA7IGsgPCB0aGlzLmJsb2NrU2l6ZTsgaysrKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMub3V0cHV0QnVmZmVyc1tpXVtqXVtrXSArPSB0aGlzLm91dHB1dEJ1ZmZlcnNUb1JldHJpZXZlW2ldW2pdW2tdIC8gdGhpcy5uYk92ZXJsYXBzOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBwcm9jZXNzKGlucHV0cywgb3V0cHV0cywgcGFyYW1ldGVycykgewogICAgICAgICAgICB0aGlzLnJlYWxsb2NhdGVDaGFubmVsc0lmTmVlZGVkKGlucHV0cywgb3V0cHV0cyk7CiAgICAgICAgICAgIHRoaXMucmVhZElucHV0cyhpbnB1dHMpOwogICAgICAgICAgICB0aGlzLnNoaWZ0SW5wdXRCdWZmZXJzKCk7CiAgICAgICAgICAgIHRoaXMucHJlcGFyZUlucHV0QnVmZmVyc1RvU2VuZCgpOwogICAgICAgICAgICB0aGlzLnByb2Nlc3NPTEEodGhpcy5pbnB1dEJ1ZmZlcnNUb1NlbmQsIHRoaXMub3V0cHV0QnVmZmVyc1RvUmV0cmlldmUsIHBhcmFtZXRlcnMpOwogICAgICAgICAgICB0aGlzLmhhbmRsZU91dHB1dEJ1ZmZlcnNUb1JldHJpZXZlKCk7CiAgICAgICAgICAgIHRoaXMud3JpdGVPdXRwdXRzKG91dHB1dHMpOwogICAgICAgICAgICB0aGlzLnNoaWZ0T3V0cHV0QnVmZmVycygpOwogICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9CiAgICB9CgogICAgZnVuY3Rpb24gZ2V0RGVmYXVsdEV4cG9ydEZyb21DanMgKHgpIHsKICAgIAlyZXR1cm4geCAmJiB4Ll9fZXNNb2R1bGUgJiYgT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHgsICdkZWZhdWx0JykgPyB4WydkZWZhdWx0J10gOiB4OwogICAgfQoKICAgIGZ1bmN0aW9uIEZGVChzaXplKSB7CiAgICAgIHRoaXMuc2l6ZSA9IHNpemUgfCAwOwogICAgICBpZiAodGhpcy5zaXplIDw9IDEgfHwgKHRoaXMuc2l6ZSAmICh0aGlzLnNpemUgLSAxKSkgIT09IDApCiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdGRlQgc2l6ZSBtdXN0IGJlIGEgcG93ZXIgb2YgdHdvIGFuZCBiaWdnZXIgdGhhbiAxJyk7CgogICAgICB0aGlzLl9jc2l6ZSA9IHNpemUgPDwgMTsKCiAgICAgIC8vIE5PVEU6IFVzZSBvZiBgdmFyYCBpcyBpbnRlbnRpb25hbCBmb3Igb2xkIFY4IHZlcnNpb25zCiAgICAgIHZhciB0YWJsZSA9IG5ldyBBcnJheSh0aGlzLnNpemUgKiAyKTsKICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0YWJsZS5sZW5ndGg7IGkgKz0gMikgewogICAgICAgIGNvbnN0IGFuZ2xlID0gTWF0aC5QSSAqIGkgLyB0aGlzLnNpemU7CiAgICAgICAgdGFibGVbaV0gPSBNYXRoLmNvcyhhbmdsZSk7CiAgICAgICAgdGFibGVbaSArIDFdID0gLU1hdGguc2luKGFuZ2xlKTsKICAgICAgfQogICAgICB0aGlzLnRhYmxlID0gdGFibGU7CgogICAgICAvLyBGaW5kIHNpemUncyBwb3dlciBvZiB0d28KICAgICAgdmFyIHBvd2VyID0gMDsKICAgICAgZm9yICh2YXIgdCA9IDE7IHRoaXMuc2l6ZSA+IHQ7IHQgPDw9IDEpCiAgICAgICAgcG93ZXIrKzsKCiAgICAgIC8vIENhbGN1bGF0ZSBpbml0aWFsIHN0ZXAncyB3aWR0aDoKICAgICAgLy8gICAqIElmIHdlIGFyZSBmdWxsIHJhZGl4LTQgLSBpdCBpcyAyeCBzbWFsbGVyIHRvIGdpdmUgaW5pdGFsIGxlbj04CiAgICAgIC8vICAgKiBPdGhlcndpc2UgaXQgaXMgdGhlIHNhbWUgYXMgYHBvd2VyYCB0byBnaXZlIGxlbj00CiAgICAgIHRoaXMuX3dpZHRoID0gcG93ZXIgJSAyID09PSAwID8gcG93ZXIgLSAxIDogcG93ZXI7CgogICAgICAvLyBQcmUtY29tcHV0ZSBiaXQtcmV2ZXJzYWwgcGF0dGVybnMKICAgICAgdGhpcy5fYml0cmV2ID0gbmV3IEFycmF5KDEgPDwgdGhpcy5fd2lkdGgpOwogICAgICBmb3IgKHZhciBqID0gMDsgaiA8IHRoaXMuX2JpdHJldi5sZW5ndGg7IGorKykgewogICAgICAgIHRoaXMuX2JpdHJldltqXSA9IDA7CiAgICAgICAgZm9yICh2YXIgc2hpZnQgPSAwOyBzaGlmdCA8IHRoaXMuX3dpZHRoOyBzaGlmdCArPSAyKSB7CiAgICAgICAgICB2YXIgcmV2U2hpZnQgPSB0aGlzLl93aWR0aCAtIHNoaWZ0IC0gMjsKICAgICAgICAgIHRoaXMuX2JpdHJldltqXSB8PSAoKGogPj4+IHNoaWZ0KSAmIDMpIDw8IHJldlNoaWZ0OwogICAgICAgIH0KICAgICAgfQoKICAgICAgdGhpcy5fb3V0ID0gbnVsbDsKICAgICAgdGhpcy5fZGF0YSA9IG51bGw7CiAgICAgIHRoaXMuX2ludiA9IDA7CiAgICB9CiAgICB2YXIgZmZ0ID0gRkZUOwoKICAgIEZGVC5wcm90b3R5cGUuZnJvbUNvbXBsZXhBcnJheSA9IGZ1bmN0aW9uIGZyb21Db21wbGV4QXJyYXkoY29tcGxleCwgc3RvcmFnZSkgewogICAgICB2YXIgcmVzID0gc3RvcmFnZSB8fCBuZXcgQXJyYXkoY29tcGxleC5sZW5ndGggPj4+IDEpOwogICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNvbXBsZXgubGVuZ3RoOyBpICs9IDIpCiAgICAgICAgcmVzW2kgPj4+IDFdID0gY29tcGxleFtpXTsKICAgICAgcmV0dXJuIHJlczsKICAgIH07CgogICAgRkZULnByb3RvdHlwZS5jcmVhdGVDb21wbGV4QXJyYXkgPSBmdW5jdGlvbiBjcmVhdGVDb21wbGV4QXJyYXkoKSB7CiAgICAgIGNvbnN0IHJlcyA9IG5ldyBBcnJheSh0aGlzLl9jc2l6ZSk7CiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcmVzLmxlbmd0aDsgaSsrKQogICAgICAgIHJlc1tpXSA9IDA7CiAgICAgIHJldHVybiByZXM7CiAgICB9OwoKICAgIEZGVC5wcm90b3R5cGUudG9Db21wbGV4QXJyYXkgPSBmdW5jdGlvbiB0b0NvbXBsZXhBcnJheShpbnB1dCwgc3RvcmFnZSkgewogICAgICB2YXIgcmVzID0gc3RvcmFnZSB8fCB0aGlzLmNyZWF0ZUNvbXBsZXhBcnJheSgpOwogICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHJlcy5sZW5ndGg7IGkgKz0gMikgewogICAgICAgIHJlc1tpXSA9IGlucHV0W2kgPj4+IDFdOwogICAgICAgIHJlc1tpICsgMV0gPSAwOwogICAgICB9CiAgICAgIHJldHVybiByZXM7CiAgICB9OwoKICAgIEZGVC5wcm90b3R5cGUuY29tcGxldGVTcGVjdHJ1bSA9IGZ1bmN0aW9uIGNvbXBsZXRlU3BlY3RydW0oc3BlY3RydW0pIHsKICAgICAgdmFyIHNpemUgPSB0aGlzLl9jc2l6ZTsKICAgICAgdmFyIGhhbGYgPSBzaXplID4+PiAxOwogICAgICBmb3IgKHZhciBpID0gMjsgaSA8IGhhbGY7IGkgKz0gMikgewogICAgICAgIHNwZWN0cnVtW3NpemUgLSBpXSA9IHNwZWN0cnVtW2ldOwogICAgICAgIHNwZWN0cnVtW3NpemUgLSBpICsgMV0gPSAtc3BlY3RydW1baSArIDFdOwogICAgICB9CiAgICB9OwoKICAgIEZGVC5wcm90b3R5cGUudHJhbnNmb3JtID0gZnVuY3Rpb24gdHJhbnNmb3JtKG91dCwgZGF0YSkgewogICAgICBpZiAob3V0ID09PSBkYXRhKQogICAgICAgIHRocm93IG5ldyBFcnJvcignSW5wdXQgYW5kIG91dHB1dCBidWZmZXJzIG11c3QgYmUgZGlmZmVyZW50Jyk7CgogICAgICB0aGlzLl9vdXQgPSBvdXQ7CiAgICAgIHRoaXMuX2RhdGEgPSBkYXRhOwogICAgICB0aGlzLl9pbnYgPSAwOwogICAgICB0aGlzLl90cmFuc2Zvcm00KCk7CiAgICAgIHRoaXMuX291dCA9IG51bGw7CiAgICAgIHRoaXMuX2RhdGEgPSBudWxsOwogICAgfTsKCiAgICBGRlQucHJvdG90eXBlLnJlYWxUcmFuc2Zvcm0gPSBmdW5jdGlvbiByZWFsVHJhbnNmb3JtKG91dCwgZGF0YSkgewogICAgICBpZiAob3V0ID09PSBkYXRhKQogICAgICAgIHRocm93IG5ldyBFcnJvcignSW5wdXQgYW5kIG91dHB1dCBidWZmZXJzIG11c3QgYmUgZGlmZmVyZW50Jyk7CgogICAgICB0aGlzLl9vdXQgPSBvdXQ7CiAgICAgIHRoaXMuX2RhdGEgPSBkYXRhOwogICAgICB0aGlzLl9pbnYgPSAwOwogICAgICB0aGlzLl9yZWFsVHJhbnNmb3JtNCgpOwogICAgICB0aGlzLl9vdXQgPSBudWxsOwogICAgICB0aGlzLl9kYXRhID0gbnVsbDsKICAgIH07CgogICAgRkZULnByb3RvdHlwZS5pbnZlcnNlVHJhbnNmb3JtID0gZnVuY3Rpb24gaW52ZXJzZVRyYW5zZm9ybShvdXQsIGRhdGEpIHsKICAgICAgaWYgKG91dCA9PT0gZGF0YSkKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0lucHV0IGFuZCBvdXRwdXQgYnVmZmVycyBtdXN0IGJlIGRpZmZlcmVudCcpOwoKICAgICAgdGhpcy5fb3V0ID0gb3V0OwogICAgICB0aGlzLl9kYXRhID0gZGF0YTsKICAgICAgdGhpcy5faW52ID0gMTsKICAgICAgdGhpcy5fdHJhbnNmb3JtNCgpOwogICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG91dC5sZW5ndGg7IGkrKykKICAgICAgICBvdXRbaV0gLz0gdGhpcy5zaXplOwogICAgICB0aGlzLl9vdXQgPSBudWxsOwogICAgICB0aGlzLl9kYXRhID0gbnVsbDsKICAgIH07CgogICAgLy8gcmFkaXgtNCBpbXBsZW1lbnRhdGlvbgogICAgLy8KICAgIC8vIE5PVEU6IFVzZXMgb2YgYHZhcmAgYXJlIGludGVudGlvbmFsIGZvciBvbGRlciBWOCB2ZXJzaW9uIHRoYXQgZG8gbm90CiAgICAvLyBzdXBwb3J0IGJvdGggYGxldCBjb21wb3VuZCBhc3NpZ25tZW50c2AgYW5kIGBjb25zdCBwaGlgCiAgICBGRlQucHJvdG90eXBlLl90cmFuc2Zvcm00ID0gZnVuY3Rpb24gX3RyYW5zZm9ybTQoKSB7CiAgICAgIHZhciBvdXQgPSB0aGlzLl9vdXQ7CiAgICAgIHZhciBzaXplID0gdGhpcy5fY3NpemU7CgogICAgICAvLyBJbml0aWFsIHN0ZXAgKHBlcm11dGUgYW5kIHRyYW5zZm9ybSkKICAgICAgdmFyIHdpZHRoID0gdGhpcy5fd2lkdGg7CiAgICAgIHZhciBzdGVwID0gMSA8PCB3aWR0aDsKICAgICAgdmFyIGxlbiA9IChzaXplIC8gc3RlcCkgPDwgMTsKCiAgICAgIHZhciBvdXRPZmY7CiAgICAgIHZhciB0OwogICAgICB2YXIgYml0cmV2ID0gdGhpcy5fYml0cmV2OwogICAgICBpZiAobGVuID09PSA0KSB7CiAgICAgICAgZm9yIChvdXRPZmYgPSAwLCB0ID0gMDsgb3V0T2ZmIDwgc2l6ZTsgb3V0T2ZmICs9IGxlbiwgdCsrKSB7CiAgICAgICAgICBjb25zdCBvZmYgPSBiaXRyZXZbdF07CiAgICAgICAgICB0aGlzLl9zaW5nbGVUcmFuc2Zvcm0yKG91dE9mZiwgb2ZmLCBzdGVwKTsKICAgICAgICB9CiAgICAgIH0gZWxzZSB7CiAgICAgICAgLy8gbGVuID09PSA4CiAgICAgICAgZm9yIChvdXRPZmYgPSAwLCB0ID0gMDsgb3V0T2ZmIDwgc2l6ZTsgb3V0T2ZmICs9IGxlbiwgdCsrKSB7CiAgICAgICAgICBjb25zdCBvZmYgPSBiaXRyZXZbdF07CiAgICAgICAgICB0aGlzLl9zaW5nbGVUcmFuc2Zvcm00KG91dE9mZiwgb2ZmLCBzdGVwKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8vIExvb3AgdGhyb3VnaCBzdGVwcyBpbiBkZWNyZWFzaW5nIG9yZGVyCiAgICAgIHZhciBpbnYgPSB0aGlzLl9pbnYgPyAtMSA6IDE7CiAgICAgIHZhciB0YWJsZSA9IHRoaXMudGFibGU7CiAgICAgIGZvciAoc3RlcCA+Pj0gMjsgc3RlcCA+PSAyOyBzdGVwID4+PSAyKSB7CiAgICAgICAgbGVuID0gKHNpemUgLyBzdGVwKSA8PCAxOwogICAgICAgIHZhciBxdWFydGVyTGVuID0gbGVuID4+PiAyOwoKICAgICAgICAvLyBMb29wIHRocm91Z2ggb2Zmc2V0cyBpbiB0aGUgZGF0YQogICAgICAgIGZvciAob3V0T2ZmID0gMDsgb3V0T2ZmIDwgc2l6ZTsgb3V0T2ZmICs9IGxlbikgewogICAgICAgICAgLy8gRnVsbCBjYXNlCiAgICAgICAgICB2YXIgbGltaXQgPSBvdXRPZmYgKyBxdWFydGVyTGVuOwogICAgICAgICAgZm9yICh2YXIgaSA9IG91dE9mZiwgayA9IDA7IGkgPCBsaW1pdDsgaSArPSAyLCBrICs9IHN0ZXApIHsKICAgICAgICAgICAgY29uc3QgQSA9IGk7CiAgICAgICAgICAgIGNvbnN0IEIgPSBBICsgcXVhcnRlckxlbjsKICAgICAgICAgICAgY29uc3QgQyA9IEIgKyBxdWFydGVyTGVuOwogICAgICAgICAgICBjb25zdCBEID0gQyArIHF1YXJ0ZXJMZW47CgogICAgICAgICAgICAvLyBPcmlnaW5hbCB2YWx1ZXMKICAgICAgICAgICAgY29uc3QgQXIgPSBvdXRbQV07CiAgICAgICAgICAgIGNvbnN0IEFpID0gb3V0W0EgKyAxXTsKICAgICAgICAgICAgY29uc3QgQnIgPSBvdXRbQl07CiAgICAgICAgICAgIGNvbnN0IEJpID0gb3V0W0IgKyAxXTsKICAgICAgICAgICAgY29uc3QgQ3IgPSBvdXRbQ107CiAgICAgICAgICAgIGNvbnN0IENpID0gb3V0W0MgKyAxXTsKICAgICAgICAgICAgY29uc3QgRHIgPSBvdXRbRF07CiAgICAgICAgICAgIGNvbnN0IERpID0gb3V0W0QgKyAxXTsKCiAgICAgICAgICAgIC8vIE1pZGRsZSB2YWx1ZXMKICAgICAgICAgICAgY29uc3QgTUFyID0gQXI7CiAgICAgICAgICAgIGNvbnN0IE1BaSA9IEFpOwoKICAgICAgICAgICAgY29uc3QgdGFibGVCciA9IHRhYmxlW2tdOwogICAgICAgICAgICBjb25zdCB0YWJsZUJpID0gaW52ICogdGFibGVbayArIDFdOwogICAgICAgICAgICBjb25zdCBNQnIgPSBCciAqIHRhYmxlQnIgLSBCaSAqIHRhYmxlQmk7CiAgICAgICAgICAgIGNvbnN0IE1CaSA9IEJyICogdGFibGVCaSArIEJpICogdGFibGVCcjsKCiAgICAgICAgICAgIGNvbnN0IHRhYmxlQ3IgPSB0YWJsZVsyICoga107CiAgICAgICAgICAgIGNvbnN0IHRhYmxlQ2kgPSBpbnYgKiB0YWJsZVsyICogayArIDFdOwogICAgICAgICAgICBjb25zdCBNQ3IgPSBDciAqIHRhYmxlQ3IgLSBDaSAqIHRhYmxlQ2k7CiAgICAgICAgICAgIGNvbnN0IE1DaSA9IENyICogdGFibGVDaSArIENpICogdGFibGVDcjsKCiAgICAgICAgICAgIGNvbnN0IHRhYmxlRHIgPSB0YWJsZVszICoga107CiAgICAgICAgICAgIGNvbnN0IHRhYmxlRGkgPSBpbnYgKiB0YWJsZVszICogayArIDFdOwogICAgICAgICAgICBjb25zdCBNRHIgPSBEciAqIHRhYmxlRHIgLSBEaSAqIHRhYmxlRGk7CiAgICAgICAgICAgIGNvbnN0IE1EaSA9IERyICogdGFibGVEaSArIERpICogdGFibGVEcjsKCiAgICAgICAgICAgIC8vIFByZS1GaW5hbCB2YWx1ZXMKICAgICAgICAgICAgY29uc3QgVDByID0gTUFyICsgTUNyOwogICAgICAgICAgICBjb25zdCBUMGkgPSBNQWkgKyBNQ2k7CiAgICAgICAgICAgIGNvbnN0IFQxciA9IE1BciAtIE1DcjsKICAgICAgICAgICAgY29uc3QgVDFpID0gTUFpIC0gTUNpOwogICAgICAgICAgICBjb25zdCBUMnIgPSBNQnIgKyBNRHI7CiAgICAgICAgICAgIGNvbnN0IFQyaSA9IE1CaSArIE1EaTsKICAgICAgICAgICAgY29uc3QgVDNyID0gaW52ICogKE1CciAtIE1Ecik7CiAgICAgICAgICAgIGNvbnN0IFQzaSA9IGludiAqIChNQmkgLSBNRGkpOwoKICAgICAgICAgICAgLy8gRmluYWwgdmFsdWVzCiAgICAgICAgICAgIGNvbnN0IEZBciA9IFQwciArIFQycjsKICAgICAgICAgICAgY29uc3QgRkFpID0gVDBpICsgVDJpOwoKICAgICAgICAgICAgY29uc3QgRkNyID0gVDByIC0gVDJyOwogICAgICAgICAgICBjb25zdCBGQ2kgPSBUMGkgLSBUMmk7CgogICAgICAgICAgICBjb25zdCBGQnIgPSBUMXIgKyBUM2k7CiAgICAgICAgICAgIGNvbnN0IEZCaSA9IFQxaSAtIFQzcjsKCiAgICAgICAgICAgIGNvbnN0IEZEciA9IFQxciAtIFQzaTsKICAgICAgICAgICAgY29uc3QgRkRpID0gVDFpICsgVDNyOwoKICAgICAgICAgICAgb3V0W0FdID0gRkFyOwogICAgICAgICAgICBvdXRbQSArIDFdID0gRkFpOwogICAgICAgICAgICBvdXRbQl0gPSBGQnI7CiAgICAgICAgICAgIG91dFtCICsgMV0gPSBGQmk7CiAgICAgICAgICAgIG91dFtDXSA9IEZDcjsKICAgICAgICAgICAgb3V0W0MgKyAxXSA9IEZDaTsKICAgICAgICAgICAgb3V0W0RdID0gRkRyOwogICAgICAgICAgICBvdXRbRCArIDFdID0gRkRpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgfTsKCiAgICAvLyByYWRpeC0yIGltcGxlbWVudGF0aW9uCiAgICAvLwogICAgLy8gTk9URTogT25seSBjYWxsZWQgZm9yIGxlbj00CiAgICBGRlQucHJvdG90eXBlLl9zaW5nbGVUcmFuc2Zvcm0yID0gZnVuY3Rpb24gX3NpbmdsZVRyYW5zZm9ybTIob3V0T2ZmLCBvZmYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcCkgewogICAgICBjb25zdCBvdXQgPSB0aGlzLl9vdXQ7CiAgICAgIGNvbnN0IGRhdGEgPSB0aGlzLl9kYXRhOwoKICAgICAgY29uc3QgZXZlblIgPSBkYXRhW29mZl07CiAgICAgIGNvbnN0IGV2ZW5JID0gZGF0YVtvZmYgKyAxXTsKICAgICAgY29uc3Qgb2RkUiA9IGRhdGFbb2ZmICsgc3RlcF07CiAgICAgIGNvbnN0IG9kZEkgPSBkYXRhW29mZiArIHN0ZXAgKyAxXTsKCiAgICAgIGNvbnN0IGxlZnRSID0gZXZlblIgKyBvZGRSOwogICAgICBjb25zdCBsZWZ0SSA9IGV2ZW5JICsgb2RkSTsKICAgICAgY29uc3QgcmlnaHRSID0gZXZlblIgLSBvZGRSOwogICAgICBjb25zdCByaWdodEkgPSBldmVuSSAtIG9kZEk7CgogICAgICBvdXRbb3V0T2ZmXSA9IGxlZnRSOwogICAgICBvdXRbb3V0T2ZmICsgMV0gPSBsZWZ0STsKICAgICAgb3V0W291dE9mZiArIDJdID0gcmlnaHRSOwogICAgICBvdXRbb3V0T2ZmICsgM10gPSByaWdodEk7CiAgICB9OwoKICAgIC8vIHJhZGl4LTQKICAgIC8vCiAgICAvLyBOT1RFOiBPbmx5IGNhbGxlZCBmb3IgbGVuPTgKICAgIEZGVC5wcm90b3R5cGUuX3NpbmdsZVRyYW5zZm9ybTQgPSBmdW5jdGlvbiBfc2luZ2xlVHJhbnNmb3JtNChvdXRPZmYsIG9mZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwKSB7CiAgICAgIGNvbnN0IG91dCA9IHRoaXMuX291dDsKICAgICAgY29uc3QgZGF0YSA9IHRoaXMuX2RhdGE7CiAgICAgIGNvbnN0IGludiA9IHRoaXMuX2ludiA/IC0xIDogMTsKICAgICAgY29uc3Qgc3RlcDIgPSBzdGVwICogMjsKICAgICAgY29uc3Qgc3RlcDMgPSBzdGVwICogMzsKCiAgICAgIC8vIE9yaWdpbmFsIHZhbHVlcwogICAgICBjb25zdCBBciA9IGRhdGFbb2ZmXTsKICAgICAgY29uc3QgQWkgPSBkYXRhW29mZiArIDFdOwogICAgICBjb25zdCBCciA9IGRhdGFbb2ZmICsgc3RlcF07CiAgICAgIGNvbnN0IEJpID0gZGF0YVtvZmYgKyBzdGVwICsgMV07CiAgICAgIGNvbnN0IENyID0gZGF0YVtvZmYgKyBzdGVwMl07CiAgICAgIGNvbnN0IENpID0gZGF0YVtvZmYgKyBzdGVwMiArIDFdOwogICAgICBjb25zdCBEciA9IGRhdGFbb2ZmICsgc3RlcDNdOwogICAgICBjb25zdCBEaSA9IGRhdGFbb2ZmICsgc3RlcDMgKyAxXTsKCiAgICAgIC8vIFByZS1GaW5hbCB2YWx1ZXMKICAgICAgY29uc3QgVDByID0gQXIgKyBDcjsKICAgICAgY29uc3QgVDBpID0gQWkgKyBDaTsKICAgICAgY29uc3QgVDFyID0gQXIgLSBDcjsKICAgICAgY29uc3QgVDFpID0gQWkgLSBDaTsKICAgICAgY29uc3QgVDJyID0gQnIgKyBEcjsKICAgICAgY29uc3QgVDJpID0gQmkgKyBEaTsKICAgICAgY29uc3QgVDNyID0gaW52ICogKEJyIC0gRHIpOwogICAgICBjb25zdCBUM2kgPSBpbnYgKiAoQmkgLSBEaSk7CgogICAgICAvLyBGaW5hbCB2YWx1ZXMKICAgICAgY29uc3QgRkFyID0gVDByICsgVDJyOwogICAgICBjb25zdCBGQWkgPSBUMGkgKyBUMmk7CgogICAgICBjb25zdCBGQnIgPSBUMXIgKyBUM2k7CiAgICAgIGNvbnN0IEZCaSA9IFQxaSAtIFQzcjsKCiAgICAgIGNvbnN0IEZDciA9IFQwciAtIFQycjsKICAgICAgY29uc3QgRkNpID0gVDBpIC0gVDJpOwoKICAgICAgY29uc3QgRkRyID0gVDFyIC0gVDNpOwogICAgICBjb25zdCBGRGkgPSBUMWkgKyBUM3I7CgogICAgICBvdXRbb3V0T2ZmXSA9IEZBcjsKICAgICAgb3V0W291dE9mZiArIDFdID0gRkFpOwogICAgICBvdXRbb3V0T2ZmICsgMl0gPSBGQnI7CiAgICAgIG91dFtvdXRPZmYgKyAzXSA9IEZCaTsKICAgICAgb3V0W291dE9mZiArIDRdID0gRkNyOwogICAgICBvdXRbb3V0T2ZmICsgNV0gPSBGQ2k7CiAgICAgIG91dFtvdXRPZmYgKyA2XSA9IEZEcjsKICAgICAgb3V0W291dE9mZiArIDddID0gRkRpOwogICAgfTsKCiAgICAvLyBSZWFsIGlucHV0IHJhZGl4LTQgaW1wbGVtZW50YXRpb24KICAgIEZGVC5wcm90b3R5cGUuX3JlYWxUcmFuc2Zvcm00ID0gZnVuY3Rpb24gX3JlYWxUcmFuc2Zvcm00KCkgewogICAgICB2YXIgb3V0ID0gdGhpcy5fb3V0OwogICAgICB2YXIgc2l6ZSA9IHRoaXMuX2NzaXplOwoKICAgICAgLy8gSW5pdGlhbCBzdGVwIChwZXJtdXRlIGFuZCB0cmFuc2Zvcm0pCiAgICAgIHZhciB3aWR0aCA9IHRoaXMuX3dpZHRoOwogICAgICB2YXIgc3RlcCA9IDEgPDwgd2lkdGg7CiAgICAgIHZhciBsZW4gPSAoc2l6ZSAvIHN0ZXApIDw8IDE7CgogICAgICB2YXIgb3V0T2ZmOwogICAgICB2YXIgdDsKICAgICAgdmFyIGJpdHJldiA9IHRoaXMuX2JpdHJldjsKICAgICAgaWYgKGxlbiA9PT0gNCkgewogICAgICAgIGZvciAob3V0T2ZmID0gMCwgdCA9IDA7IG91dE9mZiA8IHNpemU7IG91dE9mZiArPSBsZW4sIHQrKykgewogICAgICAgICAgY29uc3Qgb2ZmID0gYml0cmV2W3RdOwogICAgICAgICAgdGhpcy5fc2luZ2xlUmVhbFRyYW5zZm9ybTIob3V0T2ZmLCBvZmYgPj4+IDEsIHN0ZXAgPj4+IDEpOwogICAgICAgIH0KICAgICAgfSBlbHNlIHsKICAgICAgICAvLyBsZW4gPT09IDgKICAgICAgICBmb3IgKG91dE9mZiA9IDAsIHQgPSAwOyBvdXRPZmYgPCBzaXplOyBvdXRPZmYgKz0gbGVuLCB0KyspIHsKICAgICAgICAgIGNvbnN0IG9mZiA9IGJpdHJldlt0XTsKICAgICAgICAgIHRoaXMuX3NpbmdsZVJlYWxUcmFuc2Zvcm00KG91dE9mZiwgb2ZmID4+PiAxLCBzdGVwID4+PiAxKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8vIExvb3AgdGhyb3VnaCBzdGVwcyBpbiBkZWNyZWFzaW5nIG9yZGVyCiAgICAgIHZhciBpbnYgPSB0aGlzLl9pbnYgPyAtMSA6IDE7CiAgICAgIHZhciB0YWJsZSA9IHRoaXMudGFibGU7CiAgICAgIGZvciAoc3RlcCA+Pj0gMjsgc3RlcCA+PSAyOyBzdGVwID4+PSAyKSB7CiAgICAgICAgbGVuID0gKHNpemUgLyBzdGVwKSA8PCAxOwogICAgICAgIHZhciBoYWxmTGVuID0gbGVuID4+PiAxOwogICAgICAgIHZhciBxdWFydGVyTGVuID0gaGFsZkxlbiA+Pj4gMTsKICAgICAgICB2YXIgaHF1YXJ0ZXJMZW4gPSBxdWFydGVyTGVuID4+PiAxOwoKICAgICAgICAvLyBMb29wIHRocm91Z2ggb2Zmc2V0cyBpbiB0aGUgZGF0YQogICAgICAgIGZvciAob3V0T2ZmID0gMDsgb3V0T2ZmIDwgc2l6ZTsgb3V0T2ZmICs9IGxlbikgewogICAgICAgICAgZm9yICh2YXIgaSA9IDAsIGsgPSAwOyBpIDw9IGhxdWFydGVyTGVuOyBpICs9IDIsIGsgKz0gc3RlcCkgewogICAgICAgICAgICB2YXIgQSA9IG91dE9mZiArIGk7CiAgICAgICAgICAgIHZhciBCID0gQSArIHF1YXJ0ZXJMZW47CiAgICAgICAgICAgIHZhciBDID0gQiArIHF1YXJ0ZXJMZW47CiAgICAgICAgICAgIHZhciBEID0gQyArIHF1YXJ0ZXJMZW47CgogICAgICAgICAgICAvLyBPcmlnaW5hbCB2YWx1ZXMKICAgICAgICAgICAgdmFyIEFyID0gb3V0W0FdOwogICAgICAgICAgICB2YXIgQWkgPSBvdXRbQSArIDFdOwogICAgICAgICAgICB2YXIgQnIgPSBvdXRbQl07CiAgICAgICAgICAgIHZhciBCaSA9IG91dFtCICsgMV07CiAgICAgICAgICAgIHZhciBDciA9IG91dFtDXTsKICAgICAgICAgICAgdmFyIENpID0gb3V0W0MgKyAxXTsKICAgICAgICAgICAgdmFyIERyID0gb3V0W0RdOwogICAgICAgICAgICB2YXIgRGkgPSBvdXRbRCArIDFdOwoKICAgICAgICAgICAgLy8gTWlkZGxlIHZhbHVlcwogICAgICAgICAgICB2YXIgTUFyID0gQXI7CiAgICAgICAgICAgIHZhciBNQWkgPSBBaTsKCiAgICAgICAgICAgIHZhciB0YWJsZUJyID0gdGFibGVba107CiAgICAgICAgICAgIHZhciB0YWJsZUJpID0gaW52ICogdGFibGVbayArIDFdOwogICAgICAgICAgICB2YXIgTUJyID0gQnIgKiB0YWJsZUJyIC0gQmkgKiB0YWJsZUJpOwogICAgICAgICAgICB2YXIgTUJpID0gQnIgKiB0YWJsZUJpICsgQmkgKiB0YWJsZUJyOwoKICAgICAgICAgICAgdmFyIHRhYmxlQ3IgPSB0YWJsZVsyICoga107CiAgICAgICAgICAgIHZhciB0YWJsZUNpID0gaW52ICogdGFibGVbMiAqIGsgKyAxXTsKICAgICAgICAgICAgdmFyIE1DciA9IENyICogdGFibGVDciAtIENpICogdGFibGVDaTsKICAgICAgICAgICAgdmFyIE1DaSA9IENyICogdGFibGVDaSArIENpICogdGFibGVDcjsKCiAgICAgICAgICAgIHZhciB0YWJsZURyID0gdGFibGVbMyAqIGtdOwogICAgICAgICAgICB2YXIgdGFibGVEaSA9IGludiAqIHRhYmxlWzMgKiBrICsgMV07CiAgICAgICAgICAgIHZhciBNRHIgPSBEciAqIHRhYmxlRHIgLSBEaSAqIHRhYmxlRGk7CiAgICAgICAgICAgIHZhciBNRGkgPSBEciAqIHRhYmxlRGkgKyBEaSAqIHRhYmxlRHI7CgogICAgICAgICAgICAvLyBQcmUtRmluYWwgdmFsdWVzCiAgICAgICAgICAgIHZhciBUMHIgPSBNQXIgKyBNQ3I7CiAgICAgICAgICAgIHZhciBUMGkgPSBNQWkgKyBNQ2k7CiAgICAgICAgICAgIHZhciBUMXIgPSBNQXIgLSBNQ3I7CiAgICAgICAgICAgIHZhciBUMWkgPSBNQWkgLSBNQ2k7CiAgICAgICAgICAgIHZhciBUMnIgPSBNQnIgKyBNRHI7CiAgICAgICAgICAgIHZhciBUMmkgPSBNQmkgKyBNRGk7CiAgICAgICAgICAgIHZhciBUM3IgPSBpbnYgKiAoTUJyIC0gTURyKTsKICAgICAgICAgICAgdmFyIFQzaSA9IGludiAqIChNQmkgLSBNRGkpOwoKICAgICAgICAgICAgLy8gRmluYWwgdmFsdWVzCiAgICAgICAgICAgIHZhciBGQXIgPSBUMHIgKyBUMnI7CiAgICAgICAgICAgIHZhciBGQWkgPSBUMGkgKyBUMmk7CgogICAgICAgICAgICB2YXIgRkJyID0gVDFyICsgVDNpOwogICAgICAgICAgICB2YXIgRkJpID0gVDFpIC0gVDNyOwoKICAgICAgICAgICAgb3V0W0FdID0gRkFyOwogICAgICAgICAgICBvdXRbQSArIDFdID0gRkFpOwogICAgICAgICAgICBvdXRbQl0gPSBGQnI7CiAgICAgICAgICAgIG91dFtCICsgMV0gPSBGQmk7CgogICAgICAgICAgICAvLyBPdXRwdXQgZmluYWwgbWlkZGxlIHBvaW50CiAgICAgICAgICAgIGlmIChpID09PSAwKSB7CiAgICAgICAgICAgICAgdmFyIEZDciA9IFQwciAtIFQycjsKICAgICAgICAgICAgICB2YXIgRkNpID0gVDBpIC0gVDJpOwogICAgICAgICAgICAgIG91dFtDXSA9IEZDcjsKICAgICAgICAgICAgICBvdXRbQyArIDFdID0gRkNpOwogICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyBEbyBub3Qgb3ZlcndyaXRlIG91cnNlbHZlcwogICAgICAgICAgICBpZiAoaSA9PT0gaHF1YXJ0ZXJMZW4pCiAgICAgICAgICAgICAgY29udGludWU7CgogICAgICAgICAgICAvLyBJbiB0aGUgZmxpcHBlZCBjYXNlOgogICAgICAgICAgICAvLyBNQWkgPSAtTUFpCiAgICAgICAgICAgIC8vIE1Ccj0tTUJpLCBNQmk9LU1CcgogICAgICAgICAgICAvLyBNQ3I9LU1DcgogICAgICAgICAgICAvLyBNRHI9TURpLCBNRGk9TURyCiAgICAgICAgICAgIHZhciBTVDByID0gVDFyOwogICAgICAgICAgICB2YXIgU1QwaSA9IC1UMWk7CiAgICAgICAgICAgIHZhciBTVDFyID0gVDByOwogICAgICAgICAgICB2YXIgU1QxaSA9IC1UMGk7CiAgICAgICAgICAgIHZhciBTVDJyID0gLWludiAqIFQzaTsKICAgICAgICAgICAgdmFyIFNUMmkgPSAtaW52ICogVDNyOwogICAgICAgICAgICB2YXIgU1QzciA9IC1pbnYgKiBUMmk7CiAgICAgICAgICAgIHZhciBTVDNpID0gLWludiAqIFQycjsKCiAgICAgICAgICAgIHZhciBTRkFyID0gU1QwciArIFNUMnI7CiAgICAgICAgICAgIHZhciBTRkFpID0gU1QwaSArIFNUMmk7CgogICAgICAgICAgICB2YXIgU0ZCciA9IFNUMXIgKyBTVDNpOwogICAgICAgICAgICB2YXIgU0ZCaSA9IFNUMWkgLSBTVDNyOwoKICAgICAgICAgICAgdmFyIFNBID0gb3V0T2ZmICsgcXVhcnRlckxlbiAtIGk7CiAgICAgICAgICAgIHZhciBTQiA9IG91dE9mZiArIGhhbGZMZW4gLSBpOwoKICAgICAgICAgICAgb3V0W1NBXSA9IFNGQXI7CiAgICAgICAgICAgIG91dFtTQSArIDFdID0gU0ZBaTsKICAgICAgICAgICAgb3V0W1NCXSA9IFNGQnI7CiAgICAgICAgICAgIG91dFtTQiArIDFdID0gU0ZCaTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH07CgogICAgLy8gcmFkaXgtMiBpbXBsZW1lbnRhdGlvbgogICAgLy8KICAgIC8vIE5PVEU6IE9ubHkgY2FsbGVkIGZvciBsZW49NAogICAgRkZULnByb3RvdHlwZS5fc2luZ2xlUmVhbFRyYW5zZm9ybTIgPSBmdW5jdGlvbiBfc2luZ2xlUmVhbFRyYW5zZm9ybTIob3V0T2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcCkgewogICAgICBjb25zdCBvdXQgPSB0aGlzLl9vdXQ7CiAgICAgIGNvbnN0IGRhdGEgPSB0aGlzLl9kYXRhOwoKICAgICAgY29uc3QgZXZlblIgPSBkYXRhW29mZl07CiAgICAgIGNvbnN0IG9kZFIgPSBkYXRhW29mZiArIHN0ZXBdOwoKICAgICAgY29uc3QgbGVmdFIgPSBldmVuUiArIG9kZFI7CiAgICAgIGNvbnN0IHJpZ2h0UiA9IGV2ZW5SIC0gb2RkUjsKCiAgICAgIG91dFtvdXRPZmZdID0gbGVmdFI7CiAgICAgIG91dFtvdXRPZmYgKyAxXSA9IDA7CiAgICAgIG91dFtvdXRPZmYgKyAyXSA9IHJpZ2h0UjsKICAgICAgb3V0W291dE9mZiArIDNdID0gMDsKICAgIH07CgogICAgLy8gcmFkaXgtNAogICAgLy8KICAgIC8vIE5PVEU6IE9ubHkgY2FsbGVkIGZvciBsZW49OAogICAgRkZULnByb3RvdHlwZS5fc2luZ2xlUmVhbFRyYW5zZm9ybTQgPSBmdW5jdGlvbiBfc2luZ2xlUmVhbFRyYW5zZm9ybTQob3V0T2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcCkgewogICAgICBjb25zdCBvdXQgPSB0aGlzLl9vdXQ7CiAgICAgIGNvbnN0IGRhdGEgPSB0aGlzLl9kYXRhOwogICAgICBjb25zdCBpbnYgPSB0aGlzLl9pbnYgPyAtMSA6IDE7CiAgICAgIGNvbnN0IHN0ZXAyID0gc3RlcCAqIDI7CiAgICAgIGNvbnN0IHN0ZXAzID0gc3RlcCAqIDM7CgogICAgICAvLyBPcmlnaW5hbCB2YWx1ZXMKICAgICAgY29uc3QgQXIgPSBkYXRhW29mZl07CiAgICAgIGNvbnN0IEJyID0gZGF0YVtvZmYgKyBzdGVwXTsKICAgICAgY29uc3QgQ3IgPSBkYXRhW29mZiArIHN0ZXAyXTsKICAgICAgY29uc3QgRHIgPSBkYXRhW29mZiArIHN0ZXAzXTsKCiAgICAgIC8vIFByZS1GaW5hbCB2YWx1ZXMKICAgICAgY29uc3QgVDByID0gQXIgKyBDcjsKICAgICAgY29uc3QgVDFyID0gQXIgLSBDcjsKICAgICAgY29uc3QgVDJyID0gQnIgKyBEcjsKICAgICAgY29uc3QgVDNyID0gaW52ICogKEJyIC0gRHIpOwoKICAgICAgLy8gRmluYWwgdmFsdWVzCiAgICAgIGNvbnN0IEZBciA9IFQwciArIFQycjsKCiAgICAgIGNvbnN0IEZCciA9IFQxcjsKICAgICAgY29uc3QgRkJpID0gLVQzcjsKCiAgICAgIGNvbnN0IEZDciA9IFQwciAtIFQycjsKCiAgICAgIGNvbnN0IEZEciA9IFQxcjsKICAgICAgY29uc3QgRkRpID0gVDNyOwoKICAgICAgb3V0W291dE9mZl0gPSBGQXI7CiAgICAgIG91dFtvdXRPZmYgKyAxXSA9IDA7CiAgICAgIG91dFtvdXRPZmYgKyAyXSA9IEZCcjsKICAgICAgb3V0W291dE9mZiArIDNdID0gRkJpOwogICAgICBvdXRbb3V0T2ZmICsgNF0gPSBGQ3I7CiAgICAgIG91dFtvdXRPZmYgKyA1XSA9IDA7CiAgICAgIG91dFtvdXRPZmYgKyA2XSA9IEZEcjsKICAgICAgb3V0W291dE9mZiArIDddID0gRkRpOwogICAgfTsKCiAgICB2YXIgRkZUJDEgPSAvKkBfX1BVUkVfXyovZ2V0RGVmYXVsdEV4cG9ydEZyb21DanMoZmZ0KTsKCiAgICBjb25zdCBCVUZGRVJFRF9CTE9DS19TSVpFID0gMjA0ODsKICAgIGZ1bmN0aW9uIGdlbkhhbm5XaW5kb3cobGVuZ3RoKSB7CiAgICAgICAgbGV0IHdpbiA9IG5ldyBGbG9hdDMyQXJyYXkobGVuZ3RoKTsKICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgIHdpbltpXSA9IDAuNSAqICgxIC0gTWF0aC5jb3MoMiAqIE1hdGguUEkgKiBpIC8gbGVuZ3RoKSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiB3aW47CiAgICB9CiAgICBjbGFzcyBQaGFzZVZvY29kZXJQcm9jZXNzb3IgZXh0ZW5kcyBPTEFQcm9jZXNzb3IgewogICAgICAgIGZmdFNpemU7CiAgICAgICAgdGltZUN1cnNvcjsKICAgICAgICBoYW5uV2luZG93OwogICAgICAgIGZmdDsKICAgICAgICBmcmVxQ29tcGxleEJ1ZmZlcjsKICAgICAgICBmcmVxQ29tcGxleEJ1ZmZlclNoaWZ0ZWQ7CiAgICAgICAgdGltZUNvbXBsZXhCdWZmZXI7CiAgICAgICAgbWFnbml0dWRlczsKICAgICAgICBwZWFrSW5kZXhlczsKICAgICAgICBuYlBlYWtzOwogICAgICAgIHN0YXRpYyBnZXQgcGFyYW1ldGVyRGVzY3JpcHRvcnMoKSB7CiAgICAgICAgICAgIHJldHVybiBbewogICAgICAgICAgICAgICAgICAgIG5hbWU6ICdwaXRjaEZhY3RvcicsCiAgICAgICAgICAgICAgICAgICAgZGVmYXVsdFZhbHVlOiAxLjAKICAgICAgICAgICAgICAgIH1dOwogICAgICAgIH0KICAgICAgICBjb25zdHJ1Y3RvcihvcHRpb25zKSB7CiAgICAgICAgICAgIG9wdGlvbnMucHJvY2Vzc29yT3B0aW9ucyA9IHsKICAgICAgICAgICAgICAgIGJsb2NrU2l6ZTogQlVGRkVSRURfQkxPQ0tfU0laRSwKICAgICAgICAgICAgfTsKICAgICAgICAgICAgc3VwZXIob3B0aW9ucyk7CiAgICAgICAgICAgIHRoaXMuZmZ0U2l6ZSA9IHRoaXMuYmxvY2tTaXplOwogICAgICAgICAgICB0aGlzLnRpbWVDdXJzb3IgPSAwOwogICAgICAgICAgICB0aGlzLmhhbm5XaW5kb3cgPSBnZW5IYW5uV2luZG93KHRoaXMuYmxvY2tTaXplKTsKICAgICAgICAgICAgLy8gcHJlcGFyZSBGRlQgYW5kIHByZS1hbGxvY2F0ZSBidWZmZXJzCiAgICAgICAgICAgIHRoaXMuZmZ0ID0gbmV3IEZGVCQxKHRoaXMuZmZ0U2l6ZSk7CiAgICAgICAgICAgIHRoaXMuZnJlcUNvbXBsZXhCdWZmZXIgPSB0aGlzLmZmdC5jcmVhdGVDb21wbGV4QXJyYXkoKTsKICAgICAgICAgICAgdGhpcy5mcmVxQ29tcGxleEJ1ZmZlclNoaWZ0ZWQgPSB0aGlzLmZmdC5jcmVhdGVDb21wbGV4QXJyYXkoKTsKICAgICAgICAgICAgdGhpcy50aW1lQ29tcGxleEJ1ZmZlciA9IHRoaXMuZmZ0LmNyZWF0ZUNvbXBsZXhBcnJheSgpOwogICAgICAgICAgICB0aGlzLm1hZ25pdHVkZXMgPSBuZXcgRmxvYXQzMkFycmF5KHRoaXMuZmZ0U2l6ZSAvIDIgKyAxKTsKICAgICAgICAgICAgdGhpcy5wZWFrSW5kZXhlcyA9IG5ldyBJbnQzMkFycmF5KHRoaXMubWFnbml0dWRlcy5sZW5ndGgpOwogICAgICAgICAgICB0aGlzLm5iUGVha3MgPSAwOwogICAgICAgIH0KICAgICAgICBwcm9jZXNzT0xBKGlucHV0cywgb3V0cHV0cywgcGFyYW1ldGVycykgewogICAgICAgICAgICAvLyBAdHMtaWdub3JlCiAgICAgICAgICAgIGNvbnN0IHBpdGNoRmFjdG9yID0gcGFyYW1ldGVycy5waXRjaEZhY3RvcltwYXJhbWV0ZXJzLnBpdGNoRmFjdG9yLmxlbmd0aCAtIDFdOwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJJbnB1dHM7IGkrKykgewogICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBpbnB1dHNbaV0ubGVuZ3RoOyBqKyspIHsKICAgICAgICAgICAgICAgICAgICB2YXIgaW5wdXQgPSBpbnB1dHNbaV1bal07CiAgICAgICAgICAgICAgICAgICAgdmFyIG91dHB1dCA9IG91dHB1dHNbaV1bal07CiAgICAgICAgICAgICAgICAgICAgdGhpcy5hcHBseUhhbm5XaW5kb3coaW5wdXQpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuZmZ0LnJlYWxUcmFuc2Zvcm0odGhpcy5mcmVxQ29tcGxleEJ1ZmZlciwgaW5wdXQpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuY29tcHV0ZU1hZ25pdHVkZXMoKTsKICAgICAgICAgICAgICAgICAgICB0aGlzLmZpbmRQZWFrcygpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuc2hpZnRQZWFrcyhwaXRjaEZhY3Rvcik7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5mZnQuY29tcGxldGVTcGVjdHJ1bSh0aGlzLmZyZXFDb21wbGV4QnVmZmVyU2hpZnRlZCk7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5mZnQuaW52ZXJzZVRyYW5zZm9ybSh0aGlzLnRpbWVDb21wbGV4QnVmZmVyLCB0aGlzLmZyZXFDb21wbGV4QnVmZmVyU2hpZnRlZCk7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5mZnQuZnJvbUNvbXBsZXhBcnJheSh0aGlzLnRpbWVDb21wbGV4QnVmZmVyLCBvdXRwdXQpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuYXBwbHlIYW5uV2luZG93KG91dHB1dCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy50aW1lQ3Vyc29yICs9IHRoaXMuaG9wU2l6ZTsKICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgfQogICAgICAgIGFwcGx5SGFubldpbmRvdyhpbnB1dCkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuYmxvY2tTaXplOyBpKyspIHsKICAgICAgICAgICAgICAgIGlucHV0W2ldICo9IHRoaXMuaGFubldpbmRvd1tpXTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBjb21wdXRlTWFnbml0dWRlcygpIHsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDAsIGogPSAwOyBpIDwgdGhpcy5tYWduaXR1ZGVzLmxlbmd0aDsgaSsrLCBqICs9IDIpIHsKICAgICAgICAgICAgICAgIGNvbnN0IHJlYWwgPSB0aGlzLmZyZXFDb21wbGV4QnVmZmVyW2pdOwogICAgICAgICAgICAgICAgY29uc3QgaW1hZyA9IHRoaXMuZnJlcUNvbXBsZXhCdWZmZXJbaiArIDFdOwogICAgICAgICAgICAgICAgdGhpcy5tYWduaXR1ZGVzW2ldID0gcmVhbCAqKiAyICsgaW1hZyAqKiAyOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGZpbmRQZWFrcygpIHsKICAgICAgICAgICAgdGhpcy5uYlBlYWtzID0gMDsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDIsIGVuZCA9IHRoaXMubWFnbml0dWRlcy5sZW5ndGggLSAyOyBpIDwgZW5kOyBpKyspIHsKICAgICAgICAgICAgICAgIGNvbnN0IG1hZyA9IHRoaXMubWFnbml0dWRlc1tpXTsKICAgICAgICAgICAgICAgIGlmICh0aGlzLm1hZ25pdHVkZXNbaSAtIDFdID49IG1hZyB8fCB0aGlzLm1hZ25pdHVkZXNbaSAtIDJdID49IG1hZyB8fCB0aGlzLm1hZ25pdHVkZXNbaSArIDFdID49IG1hZyB8fCB0aGlzLm1hZ25pdHVkZXNbaSArIDJdID49IG1hZykgewogICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgdGhpcy5wZWFrSW5kZXhlc1t0aGlzLm5iUGVha3MrK10gPSBpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHNoaWZ0UGVha3MocGl0Y2hGYWN0b3IpIHsKICAgICAgICAgICAgdGhpcy5mcmVxQ29tcGxleEJ1ZmZlclNoaWZ0ZWQuZmlsbCgwKTsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm5iUGVha3M7IGkrKykgewogICAgICAgICAgICAgICAgY29uc3QgcGVha0luZGV4ID0gdGhpcy5wZWFrSW5kZXhlc1tpXTsKICAgICAgICAgICAgICAgIGNvbnN0IHBlYWtJbmRleFNoaWZ0ZWQgPSBNYXRoLnJvdW5kKHBlYWtJbmRleCAqIHBpdGNoRmFjdG9yKTsKICAgICAgICAgICAgICAgIGlmIChwZWFrSW5kZXhTaGlmdGVkID4gdGhpcy5tYWduaXR1ZGVzLmxlbmd0aCkgewogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgbGV0IHN0YXJ0SW5kZXggPSAoaSA+IDApID8gcGVha0luZGV4IC0gTWF0aC5mbG9vcigocGVha0luZGV4IC0gdGhpcy5wZWFrSW5kZXhlc1tpIC0gMV0pIC8gMikgOiAwOwogICAgICAgICAgICAgICAgbGV0IGVuZEluZGV4ID0gKGkgPCB0aGlzLm5iUGVha3MgLSAxKSA/IHBlYWtJbmRleCArIE1hdGguY2VpbCgodGhpcy5wZWFrSW5kZXhlc1tpICsgMV0gLSBwZWFrSW5kZXgpIC8gMikgOiB0aGlzLmZmdFNpemU7CiAgICAgICAgICAgICAgICBmb3IgKGxldCBqID0gc3RhcnRJbmRleCAtIHBlYWtJbmRleDsgaiA8IGVuZEluZGV4IC0gcGVha0luZGV4OyBqKyspIHsKICAgICAgICAgICAgICAgICAgICBjb25zdCBiaW5JbmRleCA9IHBlYWtJbmRleCArIGo7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgYmluSW5kZXhTaGlmdGVkID0gcGVha0luZGV4U2hpZnRlZCArIGo7CiAgICAgICAgICAgICAgICAgICAgaWYgKGJpbkluZGV4U2hpZnRlZCA+PSB0aGlzLm1hZ25pdHVkZXMubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBjb25zdCBvbWVnYURlbHRhID0gMiAqIE1hdGguUEkgKiAoYmluSW5kZXhTaGlmdGVkIC0gYmluSW5kZXgpIC8gdGhpcy5mZnRTaXplOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IHBoYXNlU2hpZnRSZWFsID0gTWF0aC5jb3Mob21lZ2FEZWx0YSAqIHRoaXMudGltZUN1cnNvcik7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgcGhhc2VTaGlmdEltYWcgPSBNYXRoLnNpbihvbWVnYURlbHRhICogdGhpcy50aW1lQ3Vyc29yKTsKICAgICAgICAgICAgICAgICAgICBjb25zdCBpbmRleFJlYWwgPSBiaW5JbmRleCAqIDI7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgaW5kZXhJbWFnID0gaW5kZXhSZWFsICsgMTsKICAgICAgICAgICAgICAgICAgICBjb25zdCB2YWx1ZVJlYWwgPSB0aGlzLmZyZXFDb21wbGV4QnVmZmVyW2luZGV4UmVhbF07CiAgICAgICAgICAgICAgICAgICAgY29uc3QgdmFsdWVJbWFnID0gdGhpcy5mcmVxQ29tcGxleEJ1ZmZlcltpbmRleEltYWddOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IHZhbHVlU2hpZnRlZFJlYWwgPSB2YWx1ZVJlYWwgKiBwaGFzZVNoaWZ0UmVhbCAtIHZhbHVlSW1hZyAqIHBoYXNlU2hpZnRJbWFnOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IHZhbHVlU2hpZnRlZEltYWcgPSB2YWx1ZVJlYWwgKiBwaGFzZVNoaWZ0SW1hZyArIHZhbHVlSW1hZyAqIHBoYXNlU2hpZnRSZWFsOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IGluZGV4U2hpZnRlZFJlYWwgPSBiaW5JbmRleFNoaWZ0ZWQgKiAyOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IGluZGV4U2hpZnRlZEltYWcgPSBpbmRleFNoaWZ0ZWRSZWFsICsgMTsKICAgICAgICAgICAgICAgICAgICB0aGlzLmZyZXFDb21wbGV4QnVmZmVyU2hpZnRlZFtpbmRleFNoaWZ0ZWRSZWFsXSArPSB2YWx1ZVNoaWZ0ZWRSZWFsOwogICAgICAgICAgICAgICAgICAgIHRoaXMuZnJlcUNvbXBsZXhCdWZmZXJTaGlmdGVkW2luZGV4U2hpZnRlZEltYWddICs9IHZhbHVlU2hpZnRlZEltYWc7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CiAgICAvLyBAdHMtaWdub3JlCiAgICByZWdpc3RlclByb2Nlc3NvcigicGhhc2Utdm9jb2RlciIsIFBoYXNlVm9jb2RlclByb2Nlc3Nvcik7CiAgICBjb25zb2xlLmxvZygiUGhhc2VWb2NvZGVyUHJvY2Vzc29yIHJlZ2lzdGVyZWQiKTsKCiAgICBleHBvcnRzLlBoYXNlVm9jb2RlclByb2Nlc3NvciA9IFBoYXNlVm9jb2RlclByb2Nlc3NvcjsKCiAgICByZXR1cm4gZXhwb3J0czsKCn0pKHt9KTsK\"","import type { AudioContext } from './context';\n\nclass LRUCache<K, V> {\n private maxSize: number;\n private cache: Map<K, V>;\n\n constructor(maxSize: number) {\n this.maxSize = maxSize;\n this.cache = new Map();\n }\n\n get(key: K): V | undefined {\n if (!this.cache.has(key)) return undefined;\n const value = this.cache.get(key)!;\n this.cache.delete(key);\n this.cache.set(key, value);\n return value;\n }\n\n set(key: K, value: V): void {\n if (this.cache.has(key)) {\n this.cache.delete(key);\n } else if (this.cache.size >= this.maxSize) {\n const firstKey = this.cache.keys().next().value;\n this.cache.delete(firstKey);\n }\n this.cache.set(key, value);\n }\n\n has(key: K): boolean {\n return this.cache.has(key);\n }\n}\n\n\ninterface CacheMetadata {\n url: string;\n etag?: string;\n lastModified?: string;\n}\n\nconst DEFAULT_CACHE_SIZE = 100;\n\nexport class AudioCache {\n private static pendingRequests = new Map<string, Promise<AudioBuffer>>();\n private static decodedBuffers = new LRUCache<string, AudioBuffer>(100); // Limit to 500 items\n\n private static async openCache(): Promise<Cache> {\n try {\n return await caches.open('audio-cache');\n } catch (error) {\n console.error('Failed to open cache:', error);\n throw error;\n }\n }\n\n private static async getBufferFromCache(url: string, cache: Cache): Promise<ArrayBuffer | null> {\n try {\n const response = await cache.match(url);\n if (response && response.ok) {\n return await response.arrayBuffer();\n }\n return null;\n } catch (error) {\n console.error('Failed to get data from cache:', error);\n return null;\n }\n }\n\n private static async fetchAndCacheBuffer(url: string, cache: Cache, etag?: string, lastModified?: string): Promise<ArrayBuffer> {\n try {\n const headers = new Headers();\n if (etag) headers.append('If-None-Match', etag);\n if (lastModified) headers.append('If-Modified-Since', lastModified);\n\n const fetchResponse = await fetch(url, { headers });\n const responseClone = fetchResponse.clone();\n\n if (fetchResponse.status === 200) {\n const newEtag = fetchResponse.headers.get('ETag') || undefined;\n const newLastModified = fetchResponse.headers.get('Last-Modified') || undefined;\n const cacheData: CacheMetadata = { url, etag: newEtag, lastModified: newLastModified };\n\n await cache.put(url, responseClone);\n await cache.put(url + ':meta', new Response(JSON.stringify(cacheData), { headers: { 'Content-Type': 'application/json' } }));\n } else if (fetchResponse.status === 304) {\n const cachedResponse = await cache.match(url);\n if (cachedResponse) {\n return await cachedResponse.arrayBuffer();\n }\n }\n\n return await fetchResponse.arrayBuffer();\n } catch (error) {\n console.error('Failed to fetch and cache data:', error);\n throw error;\n }\n }\n\n private static async decodeAudioData(context: AudioContext, arrayBuffer: ArrayBuffer): Promise<AudioBuffer> {\n try {\n return await context.decodeAudioData(arrayBuffer);\n } catch (error) {\n console.error('Failed to decode audio data:', error);\n throw error;\n }\n }\n\n private static async getMetadataFromCache(url: string, cache: Cache): Promise<CacheMetadata | null> {\n try {\n const metaResponse = await cache.match(url + ':meta');\n if (metaResponse && metaResponse.ok) {\n return await metaResponse.json();\n }\n return null;\n } catch (error) {\n console.error('Failed to get metadata from cache:', error);\n return null;\n }\n }\n\n public static async getAudioBuffer(context: AudioContext, url: string): Promise<AudioBuffer> {\n // Check if the decoded buffer is already available\n if (this.decodedBuffers.has(url)) {\n return this.decodedBuffers.get(url)!;\n }\n\n // handle data: urls\n if (url.startsWith('data:')) {\n const base64Data = url.split(',')[1];\n const buffer = Uint8Array.from(atob(base64Data), c => c.charCodeAt(0)).buffer;\n const audioBuffer = await this.decodeAudioData(context, buffer);\n this.decodedBuffers.set(url, audioBuffer);\n return audioBuffer;\n }\n\n const cache = await this.openCache();\n\n // First, check if there's a pending request.\n let pendingRequest = this.pendingRequests.get(url);\n if (pendingRequest) {\n return pendingRequest;\n }\n\n // Try getting the buffer from cache.\n const bufferFromCache = await this.getBufferFromCache(url, cache);\n if (bufferFromCache) {\n const audioBuffer = await this.decodeAudioData(context, bufferFromCache);\n this.decodedBuffers.set(url, audioBuffer);\n return audioBuffer;\n }\n\n // Check for cached metadata (ETag, Last-Modified)\n const metadata = await this.getMetadataFromCache(url, cache);\n const etag = metadata?.etag;\n const lastModified = metadata?.lastModified;\n\n // If it's not in the cache or needs revalidation, fetch and cache it.\n pendingRequest = this.fetchAndCacheBuffer(url, cache, etag, lastModified)\n .then(arrayBuffer => this.decodeAudioData(context, arrayBuffer))\n .then(audioBuffer => {\n this.decodedBuffers.set(url, audioBuffer);\n return audioBuffer;\n })\n .finally(() => {\n this.pendingRequests.delete(url); // Cleanup pending request\n });\n this.pendingRequests.set(url, pendingRequest);\n\n return pendingRequest;\n }\n\n\n public static clearMemoryCache(): void {\n this.decodedBuffers = new LRUCache<string, AudioBuffer>(DEFAULT_CACHE_SIZE);\n this.pendingRequests.clear();\n }\n}\n\n\n","import { BiquadFilterNode } from './context'\n\nexport type FilterCloneOverrides = {\n filters?: BiquadFilterNode[];\n};\n\nexport abstract class FilterManager {\n _filters: BiquadFilterNode[] = [];\n\n addFilter(filter: BiquadFilterNode) {\n this._filters.push(filter);\n }\n\n removeFilter(filter: BiquadFilterNode) {\n this._filters = this._filters.filter(f => f.frequency.value !== filter.frequency.value && f.type !== filter.type && f.Q.value !== filter.Q.value && f.gain.value !== filter.gain.value);\n }\n\n applyFilters(connection: any): any {\n this._filters.reduce((prevConnection, filter) => {\n prevConnection.connect(filter);\n return filter;\n }, connection);\n return this._filters.length > 0 ? this._filters[this._filters.length - 1] : connection;\n }\n\n get filters() {\n return this._filters;\n }\n\n addFilters(filters: BiquadFilterNode[]) {\n // todo: be more efficient\n filters.forEach(filter => this.addFilter(filter));\n }\n\n\n removeFilters(filters: BiquadFilterNode[]) {\n filters.forEach(filter => this.removeFilter(filter));\n }\n}\n\n","import type { BaseSound, LoopCount, Position } from './cacophony';\n\nimport { BiquadFilterNode } from './context';\nimport { Playback } from './playback';\nimport { Sound } from './sound';\n\n\nexport class Group implements BaseSound {\n\n private _position: Position = [0, 0, 0];\n loopCount: LoopCount = 0;\n private playIndex: number = 0;\n\n constructor(\n public sounds: Sound[] = [],\n ) { }\n\n /**\n * Plays a random sound from the group.\n * @returns The playback object representing the played sound.\n * @throws Error if the group is empty and there are no sounds to play.\n */\n\n playRandom(): Playback {\n if (this.sounds.length === 0) {\n throw new Error('Cannot play a random sound from an empty group');\n }\n const randomIndex = Math.floor(Math.random() * this.sounds.length);\n const randomSound = this.sounds[randomIndex] as Sound;\n const playback = randomSound.preplay();\n playback.forEach(p => p.play());\n return playback[0];\n }\n\n\n /**\n * Plays the sounds in the group in a specific order.\n * \n * @param shouldLoop - Indicates whether the sounds should be played in a loop.\n * @returns The playback object representing the first sound being played.\n * @throws Error if the group is empty and shouldLoop is false.\n */\n\n playOrdered(shouldLoop: boolean = true): Playback {\n if (this.sounds.length === 0) {\n throw new Error('Cannot play an ordered sound from an empty group');\n }\n const sound = this.sounds[this.playIndex] as Sound;\n const playback = sound.preplay();\n playback.forEach(p => p.play());\n this.playIndex++;\n if (this.playIndex >= this.sounds.length) {\n if (shouldLoop) {\n this.playIndex = 0;\n } else {\n this.playIndex = this.sounds.length; // Set to length to indicate end of list\n }\n }\n return playback[0];\n }\n\n get duration() {\n return this.sounds.map(sound => sound.duration).reduce((a, b) => Math.max(a, b), 0);\n }\n\n seek(time: number): void {\n this.sounds.forEach(sound => sound.seek && sound.seek(time));\n }\n\n addSound(sound: Sound): void {\n this.sounds.push(sound);\n }\n\n preplay(): Playback[] {\n return (this.sounds as Sound[]).reduce<Playback[]>((playbacks, sound) => {\n sound.loop && sound.loop(this.loopCount);\n return playbacks.concat(sound.preplay());\n }, []);\n }\n\n /***\n * Plays all sounds in the group.\n * @returns {Playback[]} An array of Playback objects, one for each sound in the group.\n */\n\n play(): Playback[] {\n return this.preplay().map(playback => playback.play()[0]\n );\n }\n\n /**\n * A boolean indicating whether any of the sounds in the group are currently playing.\n * @returns {boolean} True if any sound is playing, false otherwise.\n */\n\n get isPlaying(): boolean {\n return this.sounds.some(sound => sound.isPlaying);\n }\n\n /**\n * Stops all the sounds in the group.\n */\n\n stop(): void {\n this.sounds.forEach(sound => sound.stop());\n }\n\n pause(): void {\n this.sounds.forEach(sound => sound.pause());\n }\n\n loop(loopCount?: LoopCount): LoopCount {\n if (loopCount === undefined) {\n return this.loopCount;\n }\n this.loopCount = loopCount;\n this.sounds.forEach(sound => sound.loop(loopCount));\n return this.loopCount;\n }\n\n addFilter(filter: BiquadFilterNode): void {\n this.sounds.forEach(sound => sound.addFilter(filter));\n }\n\n removeFilter(filter: BiquadFilterNode): void {\n this.sounds.forEach(sound => sound.removeFilter(filter));\n }\n\n set position(position: [number, number, number]) {\n this._position = position;\n this.sounds.forEach(sound => sound.position = this._position);\n }\n\n get position(): [number, number, number] {\n return this._position;\n }\n\n get volume(): number {\n return this.sounds.map(sound => sound.volume).reduce((a, b) => a + b, 0) / this.sounds.length;\n }\n\n set volume(volume: number) {\n this.sounds.forEach(sound => sound.volume = volume);\n }\n\n get playbackRate(): number {\n if (this.sounds.length === 0) {\n return 1;\n }\n return this.sounds[0].playbackRate;\n }\n\n set playbackRate(rate: number) {\n this.sounds.forEach(sound => sound.playbackRate = rate);\n }\n\n\n}\n","import type { Position } from \"./cacophony\";\nimport { BiquadFilterNode } from \"./context\";\nimport { FilterManager } from \"./filters\";\nimport { BasePlayback, Playback } from \"./playback\";\n\ntype Constructor<T = FilterManager> = abstract new (...args: any[]) => T;\n\nexport function PlaybackContainer<TBase extends Constructor>(Base: TBase) {\n abstract class PlaybackContainer extends Base {\n playbacks: BasePlayback[] = [];\n _position: Position = [0, 0, 0];\n _stereoPan: number = 0;\n _threeDOptions: PannerOptions = {\n coneInnerAngle: 360,\n coneOuterAngle: 360,\n coneOuterGain: 0,\n distanceModel: 'inverse',\n maxDistance: 10000,\n channelCount: 2,\n channelCountMode: 'clamped-max',\n channelInterpretation: 'speakers',\n panningModel: 'HRTF',\n refDistance: 1,\n rolloffFactor: 1,\n positionX: 0,\n positionY: 0,\n positionZ: 0,\n orientationX: 0,\n orientationY: 0,\n orientationZ: 0\n };\n _volume: number = 1;\n\n abstract preplay(): BasePlayback[]\n\n /**\n * Starts playback of the sound and returns a Playback instance representing this particular playback.\n * Multiple Playback instances can be created by calling this method multiple times,\n * allowing for the same sound to be played concurrently with different settings.\n * @returns {Playback[]} An array containing the Playback instances that have been started.\n */\n\n play(): BasePlayback[] {\n const playback = this.preplay();\n playback.forEach(p => p.play());\n return playback;\n }\n\n /**\n * Stops all current playbacks of the sound immediately. This will halt the sound regardless of how many times it has been played.\n */\n\n stop() {\n this.playbacks.forEach(p => p.stop());\n this.playbacks = [];\n }\n\n /**\n * Pauses all current playbacks of the sound.\n */\n\n pause(): void {\n this.playbacks.forEach(playback => playback.pause());\n }\n\n /**\n * Adds a BiquadFilterNode to the container's filter chain.\n * Filters are applied in the order they are added.\n * @param { BiquadFilterNode } filter - The filter to add to the chain.\n */\n\n addFilter(filter: BiquadFilterNode): void {\n super.addFilter(filter);\n this.playbacks.forEach(p => p.addFilter(filter));\n }\n\n\n /**\n * Removes a BiquadFilterNode from the container's filter chain.\n * If the filter is not part of the chain, the method has no effect.\n * @param { BiquadFilterNode } filter - The filter to remove from the chain.\n */\n\n removeFilter(filter: BiquadFilterNode): void {\n super.removeFilter(filter);\n this.playbacks.forEach(p => p.removeFilter(filter));\n }\n\n /**\n * Returns a boolean indicating whether the object is currently playing.\n * an object is playing if any of its playbacks are currently playing.\n * @returns {boolean} True if the object is playing, false otherwise.\n */\n\n get isPlaying(): boolean {\n return this.playbacks.some(p => p.isPlaying);\n }\n\n /**\n * Retrieves the current 3D spatial position of the sound in the audio context.\n * The position is returned as an array of three values[x, y, z].\n * @returns { Position } The current position of the sound.\n */\n\n get position(): Position {\n return [this._threeDOptions.positionX as number, this._threeDOptions.positionY as number, this._threeDOptions.positionZ as number]\n }\n\n /**\n * Sets the 3D spatial position of the sound in the audio context.\n * The position is an array of three values[x, y, z].\n * This method updates the position of all active playbacks of the sound.\n * @param { Position } position - The new position of the sound.\n */\n\n set position(position: Position) {\n this._threeDOptions.positionX = position[0];\n this._threeDOptions.positionY = position[1];\n this._threeDOptions.positionZ = position[2];\n this.playbacks.forEach(p => p.position = position);\n }\n\n\n get threeDOptions(): PannerOptions {\n return this._threeDOptions;\n }\n\n set threeDOptions(options: Partial<PannerOptions>) {\n this._threeDOptions = { ...this._threeDOptions, ...options };\n this.playbacks.forEach(p => p.threeDOptions = this._threeDOptions);\n }\n\n get stereoPan(): number | null {\n return this._stereoPan;\n }\n\n set stereoPan(value: number) {\n this._stereoPan = value;\n this.playbacks.forEach(p => p.stereoPan = value);\n }\n\n\n /*** \n * Gets the volume of the sound. This volume level affects all current and future playbacks of this sound instance.\n * The volume is specified as a linear value between 0 (silent) and 1 (full volume).\n * \n * @returns {number} The current volume of the sound.\n */\n\n get volume(): number {\n return this._volume;\n }\n\n /***\n * Sets the volume of the sound. This volume level affects all current and future playbacks of this sound instance.\n * The volume is specified as a linear value between 0 (silent) and 1 (full volume).\n * \n * @param {number} volume - The new volume level for the sound.\n */\n\n set volume(volume: number) {\n this._volume = volume;\n this.playbacks.forEach(p => p.volume = volume);\n }\n\n };\n return PlaybackContainer;\n}","import type { PanType, Position } from \"./cacophony\";\nimport type { AudioContext, PannerNode, StereoPannerNode } from \"./context\";\nimport { FilterManager } from \"./filters\";\n\nexport type PanCloneOverrides = {\n panType?: PanType;\n stereoPan?: number; // -1 (left) to 1 (right)\n threeDOptions?: Partial<PannerOptions>; // HRTF panning only\n position?: Position; // HRTF panning only, [x, y, z]\n};\n\ntype Constructor<T = FilterManager> = abstract new (...args: any[]) => T;\n\nexport function PannerMixin<TBase extends Constructor>(Base: TBase) {\n abstract class PannerMixin extends Base {\n panner?: PannerNode | StereoPannerNode;\n _panType: PanType = 'stereo';\n\n get panType(): PanType {\n return this._panType;\n }\n\n setPanType(panType: PanType, audioContext: AudioContext) {\n this._panType = panType;\n if (panType === 'stereo') {\n this.panner = audioContext.createStereoPanner();\n } else {\n this.panner = audioContext.createPanner();\n }\n }\n\n setPannerNode(pannerNode: PannerNode) {\n this.panner = pannerNode;\n }\n\n /**\n * Gets the stereo panning value.\n * @returns {number | null} The current stereo pan value, or null if stereo panning is not applicable.\n * @throws {Error} Throws an error if stereo panning is not available or if the sound has been cleaned up.\n */\n\n get stereoPan(): number | null {\n if (this.panType === 'stereo') {\n return (this.panner as StereoPannerNode).pan.value;\n }\n return null;\n }\n\n /**\n * Sets the stereo panning value.\n * @param {number} value - The stereo pan value to set, between -1 (left) and 1 (right).\n * @throws {Error} Throws an error if stereo panning is not available, if the sound has been cleaned up, or if the value is out of bounds.\n */\n\n set stereoPan(value: number) {\n if (this.panType !== 'stereo') {\n throw new Error('Stereo panning is not available when using HRTF.');\n }\n if (!this.panner) {\n throw new Error('Cannot set stereo pan of a sound that has been cleaned up');\n }\n value = clamp(value, -1, 1);\n (this.panner as StereoPannerNode).pan.setValueAtTime(clamp(value, -1, 1), this.panner.context.currentTime);\n }\n\n\n /**\n * Gets the 3D audio options if HRTF panning is used.\n * @returns {IPannerOptions} The current 3D audio options.\n * @throws {Error} Throws an error if the sound has been cleaned up or if HRTF panning is not used.\n */\n\n get threeDOptions(): PannerOptions {\n if (!this.panner) {\n throw new Error('Cannot get 3D options of a sound that has been cleaned up');\n }\n if (this.panType !== 'HRTF') {\n throw new Error('Cannot get 3D options of a sound that is not using HRTF');\n }\n const panner = this.panner as PannerNode;\n return {\n coneInnerAngle: panner.coneInnerAngle,\n coneOuterAngle: panner.coneOuterAngle,\n coneOuterGain: panner.coneOuterGain,\n distanceModel: panner.distanceModel,\n maxDistance: panner.maxDistance,\n channelCount: this.panner.channelCount,\n channelCountMode: panner.channelCountMode,\n channelInterpretation: panner.channelInterpretation,\n panningModel: panner.panningModel,\n refDistance: panner.refDistance,\n rolloffFactor: panner.rolloffFactor,\n positionX: panner.positionX.value,\n positionY: panner.positionY.value,\n positionZ: panner.positionZ.value,\n orientationX: panner.orientationX.value,\n orientationY: panner.orientationY.value,\n orientationZ: panner.orientationZ.value\n }\n }\n\n /**\n * Sets the 3D audio options for HRTF panning.\n * @param {Partial<IPannerOptions>} options - The 3D audio options to set.\n * @throws {Error} Throws an error if the sound has been cleaned up or if HRTF panning is not used.\n */\n set threeDOptions(options: Partial<PannerOptions>) {\n if (!this.panner) {\n throw new Error('Cannot set 3D options of a sound that has been cleaned up');\n }\n if (this.panType !== 'HRTF') {\n throw new Error('Cannot set 3D options of a sound that is not using HRTF');\n }\n const panner = this.panner as PannerNode;\n panner.coneInnerAngle = options.coneInnerAngle !== undefined ? options.coneInnerAngle : panner.coneInnerAngle;\n panner.coneOuterAngle = options.coneOuterAngle !== undefined ? options.coneOuterAngle : panner.coneOuterAngle;\n panner.coneOuterGain = options.coneOuterGain !== undefined ? options.coneOuterGain : panner.coneOuterGain;\n panner.distanceModel = options.distanceModel || panner.distanceModel;\n panner.maxDistance = options.maxDistance !== undefined ? options.maxDistance : panner.maxDistance;\n panner.channelCount = options.channelCount !== undefined ? options.channelCount : panner.channelCount;\n panner.channelCountMode = options.channelCountMode || panner.channelCountMode;\n panner.channelInterpretation = options.channelInterpretation || panner.channelInterpretation;\n panner.panningModel = options.panningModel || panner.panningModel;\n panner.refDistance = options.refDistance !== undefined ? options.refDistance : panner.refDistance;\n panner.rolloffFactor = options.rolloffFactor !== undefined ? options.rolloffFactor : panner.rolloffFactor;\n panner.positionX.value = options.positionX !== undefined ? options.positionX : panner.positionX.value;\n panner.positionY.value = options.positionY !== undefined ? options.positionY : panner.positionY.value;\n panner.positionZ.value = options.positionZ !== undefined ? options.positionZ : panner.positionZ.value;\n panner.orientationX.value = options.orientationX !== undefined ? options.orientationX : panner.orientationX.value;\n panner.orientationY.value = options.orientationY !== undefined ? options.orientationY : panner.orientationY.value;\n panner.orientationZ.value = options.orientationZ !== undefined ? options.orientationZ : panner.orientationZ.value;\n }\n\n\n /**\n * Sets the position of the audio source in 3D space (HRTF panning only).\n * @param {Position} position - The [x, y, z] coordinates of the audio source.\n * @throws {Error} Throws an error if the sound has been cleaned up or if HRTF panning is not used.\n */\n\n set position(position: Position) {\n if (!this.panner) {\n throw new Error('Cannot move a sound that has been cleaned up');\n }\n if (this.panType !== 'HRTF') {\n throw new Error('Cannot move a sound that is not using HRTF');\n }\n const [x, y, z] = position;\n const panner = this.panner as PannerNode;\n panner.positionX.value = x;\n panner.positionY.value = y;\n panner.positionZ.value = z;\n }\n\n /**\n * Gets the position of the audio source in 3D space (HRTF panning only).\n * @returns {Position} The [x, y, z] coordinates of the audio source.\n * @throws {Error} Throws an error if the sound has been cleaned up or if HRTF panning is not used.\n */\n\n get position(): Position {\n if (!this.panner) {\n throw new Error('Cannot get position of a sound that has been cleaned up');\n }\n if (this.panType !== 'HRTF') {\n throw new Error('Cannot get position of a sound that is not using HRTF');\n }\n const panner = this.panner as PannerNode;\n return [panner.positionX.value, panner.positionY.value, panner.positionZ.value];\n }\n\n\n }\n\n return PannerMixin;\n}\n\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n","import { GainNode } from \"./context\";\nimport { FilterManager } from \"./filters\";\n\nexport type VolumeCloneOverrides = {\n volume?: number;\n};\n\ntype Constructor<T = FilterManager> = abstract new (...args: any[]) => T;\n\nexport function VolumeMixin<TBase extends Constructor>(Base: TBase) {\n abstract class VolumeMixin extends Base {\n gainNode?: GainNode;\n\n setGainNode(gainNode: GainNode) {\n this.gainNode = gainNode;\n }\n\n /**\n * Gets the current volume of the audio.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n * @returns {number} The current volume.\n */\n\n get volume(): number {\n if (!this.gainNode) {\n throw new Error('Cannot get volume of a sound that has been cleaned up');\n }\n return this.gainNode.gain.value;\n }\n\n /**\n * Sets the volume of the audio.\n * @param {number} v - The volume to set.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n\n set volume(v: number) {\n if (!this.gainNode) {\n throw new Error('Cannot set volume of a sound that has been cleaned up');\n }\n this.gainNode.gain.value = v;\n }\n\n };\n\n return VolumeMixin;\n}\n","/**\n * The Playback class encapsulates the functionality for playing audio in a web application.\n * It integrates with the standardized-audio-context library to provide a cross-browser way to handle audio.\n * This class allows for the manipulation of audio playback through various features such as:\n * - Playing and stopping audio\n * - Looping audio a specific number of times or infinitely\n * - Adjusting volume and playback rate\n * - Applying stereo or 3D (HRTF) panning\n * - Adding and removing filters to modify the audio output\n * - Handling audio looping with custom logic\n * - Fading audio in and out linearly or exponentially\n * - Seeking to specific points in the audio\n * - Checking if the audio is currently playing\n * - Cleaning up resources when the audio is no longer needed\n * \n * The class is designed to be flexible and can be used with different types of audio sources,\n * including buffer sources and media elements. It also provides detailed control over the audio's\n * spatial characteristics when using 3D audio.\n */\n\nimport type { BaseSound, LoopCount, PanType } from \"./cacophony\";\nimport type { AudioBuffer, AudioBufferSourceNode, AudioContext, AudioNode, BiquadFilterNode, GainNode, SourceNode } from \"./context\";\nimport { FilterManager } from \"./filters\";\nimport { PannerMixin } from \"./pannerMixin\";\nimport { VolumeMixin } from \"./volumeMixin\";\n\nexport abstract class BasePlayback extends PannerMixin(VolumeMixin(FilterManager)) {\n public source?: AudioNode\n _playing: boolean = false;\n\n abstract play(): [this];\n abstract pause(): void;\n abstract stop(): void;\n\n /**\n * Checks if the audio is currently playing.\n * @returns {boolean} True if the audio is playing, false otherwise.\n */\n\n get isPlaying(): boolean {\n if (!this.source) {\n return false;\n }\n return this._playing;\n }\n\n\n}\n\nexport class Playback extends BasePlayback implements BaseSound {\n private context: AudioContext;\n declare public source?: SourceNode;\n loopCount: LoopCount = 0;\n currentLoop: number = 0;\n private buffer?: AudioBuffer;\n pauseTime: number = 0;\n startTime: number = 0;\n\n /**\n * Creates an instance of the Playback class.\n * @param {SourceNode} source - The audio source node.\n * @param {GainNode} gainNode - The gain node for controlling volume.\n * @param {AudioContext} context - The audio context.\n * @param {LoopCount} loopCount - The number of times the audio should loop. 'infinite' for endless looping.\n * @param {PanType} panType - The type of panning to use ('HRTF' for 3D audio or 'stereo' for stereo panning).\n * @throws {Error} Throws an error if an invalid pan type is provided.\n */\n\n constructor(source: SourceNode, gainNode: GainNode, context: AudioContext, loopCount: LoopCount = 0, panType: PanType = 'HRTF') {\n super();\n this.loopCount = loopCount;\n this.setPanType(panType, context);\n this.source = source;\n if ('buffer' in source && source.buffer) {\n this.buffer = source.buffer;\n }\n if ('mediaElement' in source && source.mediaElement) {\n source.mediaElement.onended = this.handleLoop;\n } else if ('onended' in source) {\n source.onended = this.handleLoop;\n } else {\n throw new Error('Unsupported source type');\n }\n this.context = context;\n this.source.connect(this.panner!);\n this.setGainNode(gainNode);\n this.panner!.connect(this.gainNode!);\n this.refreshFilters();\n }\n\n /**\n * Gets the duration of the audio in seconds.\n * @returns {number} The duration of the audio.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n\n get duration() {\n if (!this.buffer) {\n throw new Error('Cannot get duration of a sound that has been cleaned up');\n }\n return this.buffer.duration;\n }\n\n /**\n * Gets the current playback rate of the audio.\n * @returns {number} The current playback rate.\n * @throws {Error} Throws an error if the sound has been cleaned up or if the source type is unsupported.\n */\n\n get playbackRate() {\n if (!this.source) {\n throw new Error('Cannot get playback rate of a sound that has been cleaned up');\n }\n if ('playbackRate' in this.source) {\n return this.source.playbackRate.value;\n }\n if ('mediaElement' in this.source && this.source.mediaElement) {\n return this.source.mediaElement.playbackRate;\n }\n throw new Error('Unsupported source type');\n }\n\n /**\n * Sets the playback rate of the audio.\n * @param {number} rate - The playback rate to set.\n * @throws {Error} Throws an error if the sound has been cleaned up or if the source type is unsupported.\n */\n\n set playbackRate(rate: number) {\n if (!this.source) {\n throw new Error('Cannot set playback rate of a sound that has been cleaned up');\n }\n if ('playbackRate' in this.source) {\n this.source.playbackRate.value = rate;\n }\n if ('mediaElement' in this.source && this.source.mediaElement) {\n this.source.mediaElement.playbackRate = rate;\n }\n }\n\n /**\n * Handles the loop event when the audio ends.\n * This method is bound to the 'onended' event of the audio source.\n * It manages looping logic and restarts playback if necessary.\n */\n\n handleLoop = () => {\n if (!this.source) {\n return;\n }\n this.currentLoop++;\n if (this.loopCount !== 'infinite' && this.currentLoop > this.loopCount) {\n this._playing = false;\n this.stop();\n }\n if (this.loopCount === 'infinite' || this.currentLoop < this.loopCount) {\n if (this.buffer) {\n this.recreateSource();\n if (this._playing) {\n (this.source as AudioBufferSourceNode).start(0);\n this._playing = true;\n }\n } else {\n if (this._playing) {\n this.seek(0);\n }\n }\n } else {\n this._playing = false;\n }\n }\n\n private recreateSource() {\n if (!this.buffer || !this.source || !this.panner || !this.context || !this.gainNode) {\n throw new Error('Cannot recreate source of a sound that has been cleaned up');\n }\n this.source = this.context.createBufferSource();\n this.source.buffer = this.buffer;\n this.source.connect(this.panner);\n this.source.onended = this.handleLoop;\n }\n\n /**\n * Starts playing the audio.\n * @returns {[this]} Returns the instance of the Playback class for chaining.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n\n play(): [this] {\n if (!this.source) {\n throw new Error('Cannot play a sound that has been cleaned up');\n }\n if ('mediaElement' in this.source && this.source.mediaElement) {\n this.source.mediaElement.play();\n } else if ('start' in this.source && this.source.start) {\n const offset = this.pauseTime ? this.pauseTime : 0;\n this.source.start(0, offset);\n }\n this._playing = true;\n return [this];\n }\n\n pause(): void {\n if (!this.source) {\n throw new Error('Cannot pause a sound that has been cleaned up');\n }\n if ('mediaElement' in this.source && this.source.mediaElement) {\n this.source.mediaElement.pause();\n } else if ('stop' in this.source && this.source.stop) {\n this.pauseTime = this.context.currentTime - this.startTime;\n this.source.stop();\n }\n this._playing = false;\n }\n\n /**\n * Seeks to a specific time in the audio.\n * @param {number} time - The time in seconds to seek to.\n * @throws {Error} Throws an error if the sound has been cleaned up or if the source type is unsupported.\n */\n\n seek(time: number): void {\n if (!this.source || !this.gainNode || !this.panner) {\n throw new Error('Cannot seek a sound that has been cleaned up');\n }\n const playing = this.isPlaying;\n this.stop();\n if ('mediaElement' in this.source && this.source.mediaElement) {\n this.source.mediaElement.currentTime = time;\n if (playing) {\n this.source.mediaElement.play();\n }\n } else if (this.buffer) {\n // Create a new source to start from the desired time\n this.source = this.context.createBufferSource();\n this.source.buffer = this.buffer;\n this.source.onended = this.handleLoop;\n this.refreshFilters();\n this.source.connect(this.panner);\n if (playing) {\n this.source.start(0, time);\n }\n } else {\n throw new Error('Unsupported source type for seeking');\n }\n }\n\n /**\n * Sets whether the audio source should loop.\n * @param {boolean} loop - Whether the audio should loop.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n set sourceLoop(loop: boolean) {\n if (!this.source) {\n throw new Error('Cannot set loop on a sound that has been cleaned up');\n }\n if ('loop' in this.source) {\n this.source.loop = loop;\n }\n if (\"mediaElement\" in this.source && this.source.mediaElement) {\n this.source.mediaElement.loop = loop;\n }\n }\n\n /**\n * Cleans up resources used by the Playback instance.\n * This method should be called when the audio is no longer needed to free up resources.\n */\n\n cleanup(): void {\n // Ensure cleanup is idempotent\n if (this.source) {\n this.source.disconnect();\n this.source = undefined;\n }\n if (this.gainNode) {\n this.gainNode.disconnect();\n this.gainNode = undefined;\n }\n this._filters.forEach(filter => {\n if (filter) {\n filter.disconnect();\n }\n });\n this._filters = [];\n }\n\n /**\n * Sets or gets the loop count for the audio.\n * @param {LoopCount} loopCount - The number of times the audio should loop. 'infinite' for endless looping.\n * @returns {LoopCount} The loop count if no parameter is provided.\n * @throws {Error} Throws an error if the sound has been cleaned up or if the source type is unsupported.\n */\n\n loop(loopCount?: LoopCount): LoopCount {\n if (!this.source) {\n throw new Error('Cannot loop a sound that has been cleaned up');\n }\n if ('mediaElement' in this.source && this.source.mediaElement) {\n const mediaElement = this.source.mediaElement;\n if (loopCount === undefined) {\n return mediaElement.loop === true ? 'infinite' : 0;\n }\n mediaElement.loop = true;\n // Looping for HTMLMediaElement is controlled by the 'loop' attribute, no need for loopStart or loopEnd\n return mediaElement.loop === true ? 'infinite' : 0;\n\n } else if ('loop' in this.source) {\n if (loopCount === undefined) {\n return this.source.loop === true ? 'infinite' : 0;\n }\n this.source.loop = true;\n this.source.loopEnd = this.source.buffer?.duration || 0;\n this.source.loopStart = 0;\n return this.source.loop === true ? 'infinite' : 0;\n }\n\n throw new Error('Unsupported source type');\n }\n\n /**\n * Stops the audio playback immediately.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n\n stop(): void {\n if (!this.source) {\n throw new Error('Cannot stop a sound that has been cleaned up');\n }\n if (!this.isPlaying) {\n return;\n }\n try {\n if ('stop' in this.source) {\n this.source.stop();\n }\n if (\"mediaElement\" in this.source && this.source.mediaElement) {\n this.source.mediaElement.pause();\n this.source.mediaElement.currentTime = 0;\n }\n } catch (e) {\n }\n this._playing = false;\n this.startTime = 0;\n this.pauseTime = 0;\n }\n\n /**\n * Adds a filter to the audio signal chain.\n * @param {BiquadFilterNode} filter - The filter to add.\n */\n\n addFilter(filter: BiquadFilterNode): void {\n // we have to clone the filter to avoid reusing the same filter node\n const newFilter = filter.context.createBiquadFilter();\n newFilter.type = filter.type;\n newFilter.frequency.value = filter.frequency.value;\n newFilter.Q.value = filter.Q.value;\n super.addFilter(newFilter);\n this.refreshFilters();\n }\n\n /**\n * Removes a filter from the audio signal chain.\n * @param {BiquadFilterNode} filter - The filter to remove.\n */\n\n removeFilter(filter: BiquadFilterNode): void {\n super.removeFilter(filter);\n this.refreshFilters();\n }\n\n /**\n * Refreshes the audio filters by re-applying them to the audio signal chain.\n * This method is called internally whenever filters are added or removed.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n\n private refreshFilters(): void {\n if (!this.panner || !this.gainNode) {\n throw new Error('Cannot update filters on a sound that has been cleaned up');\n }\n let connection = this.panner;\n connection.disconnect();\n connection = this.applyFilters(connection);\n connection.connect(this.gainNode);\n }\n\n /**\n * Creates a clone of the current Playback instance with optional overrides for certain properties.\n * This method allows for the creation of a new Playback instance that shares the same audio context\n * and source node but can have different settings such as loop count or pan type.\n * @param {Partial<Playback>} overrides - An object containing properties to override in the cloned instance.\n * @returns {Playback} A new Playback instance cloned from the current one with the specified overrides applied.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n\n clone(overrides: Partial<{ loopCount: LoopCount; panType: PanType }> = {}): Playback {\n if (!this.source || !this.gainNode || !this.context) {\n throw new Error('Cannot clone a sound that has been cleaned up');\n }\n const panType = overrides.panType || this.panType;\n // we'll need to create a new gain node\n const gainNode = this.context.createGain();\n // clone the source node\n let source: SourceNode;\n if ('buffer' in this.source && this.source.buffer) {\n source = this.context.createBufferSource();\n source.buffer = this.source.buffer;\n } else if ('mediaElement' in this.source && this.source.mediaElement) {\n source = this.context.createMediaElementSource(this.source.mediaElement);\n } else {\n throw new Error('Unsupported source type');\n }\n const loopCount = overrides.loopCount !== undefined ? overrides.loopCount : this.loopCount;\n return new Playback(source, gainNode, this.context, loopCount, panType);\n }\n}\n","/**\n * The Sound class represents an audio asset within a web application, providing a high-level interface\n * for loading, manipulating, and playing audio. It supports both buffer-based and media element-based audio,\n * allowing for efficient playback and manipulation of sound resources.\n *\n * A Sound instance can manage multiple Playback instances, which represent individual playbacks of the sound.\n * This allows for the same sound to be played multiple times simultaneously or with different settings (e.g., volume,\n * playback rate, spatial positioning). The Sound class provides methods to control these playbacks collectively or individually.\n *\n * Key features include:\n * - Loading audio from a URL or using a pre-loaded buffer.\n * - Playing, pausing, resuming, and stopping audio playback.\n * - Looping audio a specific number of times or infinitely.\n * - Adjusting volume, playback rate, and spatial positioning (for 3D audio).\n * - Applying audio filters for effects like reverb, equalization, etc.\n * - Cloning the Sound instance for independent manipulation and playback.\n *\n * The relationship between Sound and Playback is central to the design of the audio system. A Sound object acts as a container\n * and manager for one or more Playback objects. Each Playback object represents a single instance of the sound being played,\n * and can be controlled individually. This architecture allows for complex audio behaviors, such as playing multiple overlapping\n * instances of a sound with different settings, without requiring the user to manually manage each playback instance.\n */\n\n\nimport { SoundType, type BaseSound, type LoopCount, type PanType } from \"./cacophony\";\nimport { PlaybackContainer } from \"./container\";\nimport type { AudioBuffer, AudioContext, BiquadFilterNode, GainNode, SourceNode, } from './context';\nimport { FilterManager } from \"./filters\";\nimport type { PanCloneOverrides } from \"./pannerMixin\";\nimport { Playback } from \"./playback\";\nimport type { VolumeCloneOverrides } from \"./volumeMixin\";\n\ntype SoundCloneOverrides = PanCloneOverrides & VolumeCloneOverrides & {\n loopCount?: LoopCount;\n playbackRate?: number;\n filters?: BiquadFilterNode[];\n};\n\nexport class Sound extends PlaybackContainer(FilterManager) implements BaseSound {\n playbacks: Playback[] = [];\n buffer?: AudioBuffer;\n context: AudioContext;\n loopCount: LoopCount = 0;\n private _playbackRate: number = 1;\n\n constructor(public url: string, buffer: AudioBuffer | undefined, context: AudioContext, private globalGainNode: GainNode, public type: SoundType = SoundType.Buffer, public panType: PanType = 'HRTF'\n ) {\n super();\n this.buffer = buffer;\n this.context = context;\n }\n\n /**\n * Clones the current Sound instance, creating a deep copy with the option to override specific properties.\n * This method allows for the creation of a new, independent Sound instance based on the current one, with the\n * flexibility to modify certain attributes through the `overrides` parameter. This is particularly useful for\n * creating variations of a sound without affecting the original instance. The cloned instance includes all properties,\n * playback settings, and filters of the original, unless explicitly overridden.\n *\n * @param {SoundCloneOverrides} overrides - An object specifying properties to override in the cloned instance.\n * This can include audio settings like volume, playback rate, and spatial positioning, as well as\n * more complex configurations like 3D audio options and filter adjustments.\n * @returns {Sound} A new Sound instance that is a clone of the current sound.\n */\n\n clone(overrides: Partial<SoundCloneOverrides> = {}): Sound {\n const panType = overrides.panType || this.panType;\n const stereoPan = overrides.stereoPan !== undefined ? overrides.stereoPan : this.stereoPan;\n const threeDOptions = (overrides.threeDOptions || this.threeDOptions) as PannerOptions;\n const loopCount = overrides.loopCount !== undefined ? overrides.loopCount : this.loopCount;\n const playbackRate = overrides.playbackRate || this.playbackRate;\n const volume = overrides.volume !== undefined ? overrides.volume : this.volume;\n const position = overrides.position && overrides.position.length ? overrides.position : this.position;\n const filters = overrides.filters && overrides.filters.length ? overrides.filters : this._filters;\n\n const clone = new Sound(this.url, this.buffer, this.context, this.globalGainNode, this.type, panType);\n clone.loopCount = loopCount;\n clone._playbackRate = playbackRate;\n clone._volume = volume;\n clone._position = position;\n clone._stereoPan = stereoPan as number;\n clone._threeDOptions = threeDOptions;\n clone.addFilters(filters);\n return clone;\n }\n\n /**\n * Generates a Playback instance for the sound without starting playback.\n * This allows for pre-configuration of playback properties such as volume and position before the sound is actually played.\n * @returns {Playback[]} An array of Playback instances that are ready to be played.\n */\n\n preplay(): Playback[] {\n let source: SourceNode;\n if (this.buffer) {\n source = this.context.createBufferSource();\n source.buffer = this.buffer;\n } else {\n const audio = new Audio();\n audio.crossOrigin = 'anonymous';\n audio.src = this.url;\n audio.preload = \"auto\"\n // we have the audio, let's make a buffer source node out of it\n source = this.context.createMediaElementSource(audio);\n }\n const gainNode = this.context.createGain();\n gainNode.connect(this.globalGainNode);\n const playback = new Playback(source, gainNode, this.context, this.loopCount, this.panType);\n // this.finalizationRegistry.register(playback, playback);\n playback.setGainNode(gainNode);\n playback.volume = this.volume;\n playback.playbackRate = this.playbackRate;\n this._filters.forEach(filter => playback.addFilter(filter));\n if (this.panType === 'HRTF') {\n playback.threeDOptions = this.threeDOptions;\n playback.position = this.position;\n } else if (this.panType === 'stereo') {\n playback.stereoPan = this.stereoPan as number;\n }\n this.playbacks.push(playback);\n return [playback];\n }\n\n /**\n * Seeks to a specific time within the sound's playback.\n * @param { number } time - The time in seconds to seek to.\n * This method iterates through all active `Playback` instances and calls their `seek()` method with the specified time.\n */\n\n seek(time: number): void {\n this.playbacks.forEach(playback => playback.seek(time));\n }\n\n /**\n * Retrieves the duration of the sound in seconds.\n * If the sound is based on an AudioBuffer, it returns the duration of the buffer.\n * Otherwise, it returns 0, indicating that the duration is unknown or not applicable.\n * @returns { number } The duration of the sound in seconds.\n */\n\n get duration() {\n return this.buffer?.duration || 0;\n }\n\n /**\n * Sets or retrieves the loop behavior for the sound.\n * If loopCount is provided, the sound will loop the specified number of times.\n * If loopCount is 'infinite', the sound will loop indefinitely until stopped.\n * If no argument is provided, the method returns the current loop count setting.\n * @param { LoopCount } [loopCount] - The number of times to loop or 'infinite' for indefinite looping.\n * @returns { LoopCount } The current loop count setting if no argument is provided.\n */\n\n loop(loopCount?: LoopCount): LoopCount {\n if (loopCount === undefined) {\n return this.loopCount;\n }\n this.loopCount = loopCount;\n this.playbacks.forEach(p => p.loop(loopCount));\n return this.loopCount;\n }\n\n get playbackRate(): number {\n return this._playbackRate;\n }\n\n set playbackRate(rate: number) {\n this._playbackRate = rate;\n this.playbacks.forEach(p => p.playbackRate = rate);\n }\n\n}\n\n","import { AudioContext, IAudioBuffer } from 'standardized-audio-context';\n\n\nconst appendBuffer = (buffer1: ArrayBuffer, buffer2: ArrayBuffer): ArrayBuffer => {\n var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);\n tmp.set(new Uint8Array(buffer1), 0);\n tmp.set(new Uint8Array(buffer2), buffer1.byteLength);\n return tmp.buffer;\n}\n\n\nexport function createStream(url: string, context: AudioContext) {\n const audioStack: IAudioBuffer[] = [];\n let nextTime = 0;\n\n fetch(url).then(function (response) {\n if (!response.ok) {\n throw new Error('HTTP error, status = ' + response.status);\n }\n if (!response.body) {\n throw new Error('Missing body');\n }\n\n var reader = response.body.getReader();\n let header = new ArrayBuffer(0);//first 44bytes\n\n function read() {\n return reader.read().then(({ value, done }) => {\n let audioBuffer = null;\n if (!value) {\n return;\n }\n\n if (!header.byteLength) {\n //copy first 44 bytes (wav header)\n header = value.buffer.slice(0, 44);\n audioBuffer = value.buffer;\n } else {\n audioBuffer = appendBuffer(header, value.buffer);\n }\n\n context.decodeAudioData(audioBuffer, function (buffer) {\n\n audioStack.push(buffer);\n if (audioStack.length) {\n scheduleBuffers();\n }\n }, function (err) {\n console.log(\"err(decodeAudioData): \" + err);\n });\n if (done) {\n console.log('done');\n return;\n }\n //read next buffer\n read();\n });\n }\n read();\n })\n\n function scheduleBuffers() {\n while (audioStack.length) {\n let buffer = audioStack.shift();\n const source = context.createBufferSource();\n if (!buffer) {\n return;\n }\n source.buffer = buffer;\n source.connect(context.destination);\n if (nextTime == 0)\n nextTime = context.currentTime + 0.02; /// add 50ms latency to work well across systems - tune this if you like\n source.start(nextTime);\n nextTime += source.buffer.duration; // Make the next buffer wait the length of the last buffer before being played\n };\n }\n}\n\n","import type { OscillatorNode } from \"./context\";\r\nimport { BasePlayback } from \"./playback\";\r\n\r\nexport type OscillatorCloneOverrides = {\r\n oscillatorOptions?: Partial<OscillatorOptions>;\r\n};\r\n\r\ntype Constructor<T = {}> = abstract new (...args: any[]) => T;\r\n\r\nexport function OscillatorMixin<TBase extends Constructor>(Base: TBase) {\r\n abstract class OscillatorMixin extends BasePlayback {\r\n _oscillatorOptions: Partial<OscillatorOptions> = {};\r\n declare public source?: OscillatorNode;\r\n\r\n get oscillatorOptions(): Partial<OscillatorOptions> {\r\n return this._oscillatorOptions;\r\n }\r\n\r\n set oscillatorOptions(options: Partial<OscillatorOptions>) {\r\n this._oscillatorOptions = options;\r\n if (this.source && this.source instanceof OscillatorNode) {\r\n if (this.oscillatorOptions.detune) this.source.detune.value = this.oscillatorOptions.detune;\r\n if (this.oscillatorOptions.frequency) this.source.frequency.value = this.oscillatorOptions.frequency;\r\n if (this.oscillatorOptions.type) this.source.type = this.oscillatorOptions.type;\r\n }\r\n }\r\n\r\n play(): [this] {\r\n if (!this.source) {\r\n throw new Error('No source node found');\r\n }\r\n if (this.oscillatorOptions.detune) this.source.detune.value = this.oscillatorOptions.detune;\r\n if (this.oscillatorOptions.frequency) this.source.frequency.value = this.oscillatorOptions.frequency;\r\n if (this.oscillatorOptions.type) this.source.type = this.oscillatorOptions.type;\r\n this.source.start();\r\n this._playing = true;\r\n return [this];\r\n }\r\n\r\n stop() {\r\n if (this.source && this.source.stop) {\r\n this.source.stop();\r\n this._playing = false;\r\n }\r\n }\r\n\r\n pause(): void {\r\n this.stop();\r\n }\r\n\r\n };\r\n return OscillatorMixin;\r\n}\r\n","import type { BaseSound, PanType } from \"./cacophony\";\r\nimport type { AudioContext, GainNode, OscillatorNode } from \"./context\";\r\nimport { FilterManager } from \"./filters\";\r\nimport { OscillatorMixin } from \"./oscillatorMixin\";\r\nimport { PannerMixin } from \"./pannerMixin\";\r\nimport { VolumeMixin } from \"./volumeMixin\";\r\n\r\nexport class SynthPlayback extends OscillatorMixin(PannerMixin(VolumeMixin(FilterManager))) implements BaseSound {\r\n constructor(public source: OscillatorNode, gainNode: GainNode, private context: AudioContext, panType: PanType = 'HRTF') {\r\n super()\r\n this.setPanType(panType, context)\r\n this.source.connect(this.panner!);\r\n this.setGainNode(gainNode)\r\n this.panner!.connect(this.gainNode!);\r\n this.refreshFilters()\r\n }\r\n\r\n /**\r\n * Refreshes the audio filters by re-applying them to the audio signal chain.\r\n * This method is called internally whenever filters are added or removed.\r\n * @throws {Error} Throws an error if the sound has been cleaned up.\r\n */\r\n\r\n private refreshFilters(): void {\r\n if (!this.panner || !this.gainNode) {\r\n throw new Error('Cannot update filters on a sound that has been cleaned up');\r\n }\r\n let connection = this.panner;\r\n connection.disconnect();\r\n connection = this.applyFilters(connection);\r\n connection.connect(this.gainNode);\r\n }\r\n}\r\n","import { SoundType, type BaseSound, type PanType } from \"./cacophony\";\r\nimport { PlaybackContainer } from \"./container\";\r\nimport type { AudioContext, GainNode } from './context';\r\nimport type { FilterCloneOverrides } from \"./filters\";\r\nimport { FilterManager } from \"./filters\";\r\nimport type { OscillatorCloneOverrides } from \"./oscillatorMixin\";\r\nimport type { PanCloneOverrides } from \"./pannerMixin\";\r\nimport { SynthPlayback } from \"./synthPlayback\";\r\nimport type { VolumeCloneOverrides } from \"./volumeMixin\";\r\n\r\ntype SynthCloneOverrides = FilterCloneOverrides & OscillatorCloneOverrides & PanCloneOverrides & VolumeCloneOverrides\r\n\r\nexport class Synth extends PlaybackContainer(FilterManager) implements BaseSound {\r\n _oscillatorOptions: Partial<OscillatorOptions>;\r\n playbacks: SynthPlayback[] = [];\r\n\r\n constructor(\r\n public context: AudioContext,\r\n private globalGainNode: GainNode,\r\n public type: SoundType = SoundType.Oscillator,\r\n public panType: PanType = 'HRTF',\r\n oscillatorOptions: Partial<OscillatorOptions> = {}\r\n ) {\r\n super();\r\n this.context = context;\r\n this._oscillatorOptions = oscillatorOptions;\r\n }\r\n\r\n /**\r\n * Clones the current Synth instance, creating a deep copy with the option to override specific properties.\r\n * This method allows for the creation of a new, independent Synth instance based on the current one, with the\r\n * flexibility to modify certain attributes through the `overrides` parameter. This is particularly useful for\r\n * creating variations of a synth without affecting the original instance. The cloned instance includes all properties,\r\n * playback settings, and filters of the original, unless explicitly overridden.\r\n *\r\n * @param {SynthCloneOverrides} overrides - An object specifying properties to override in the cloned instance.\r\n * This can include audio settings like volume, playback rate, and spatial positioning, as well as\r\n * more complex configurations like 3D audio options and filter adjustments.\r\n * @returns {Sound} A new Sound instance that is a clone of the current sound.\r\n */\r\n clone(overrides: Partial<SynthCloneOverrides> = {}): Synth {\r\n const panType = overrides.panType || this.panType;\r\n const stereoPan = overrides.stereoPan !== undefined ? overrides.stereoPan : (this.stereoPan ?? 0);\r\n const threeDOptions = (overrides.threeDOptions || this.threeDOptions) as PannerOptions;\r\n const volume = overrides.volume !== undefined ? overrides.volume : this.volume;\r\n const position = overrides.position && overrides.position.length ? overrides.position : this.position;\r\n const filters = overrides.filters && overrides.filters.length ? overrides.filters : this._filters;\r\n const oscillatorOptions = overrides.oscillatorOptions || this._oscillatorOptions;\r\n\r\n const clone = new Synth(this.context, this.globalGainNode, this.type, panType, oscillatorOptions);\r\n clone._volume = volume;\r\n clone._position = position;\r\n clone._stereoPan = stereoPan as number;\r\n clone._threeDOptions = threeDOptions;\r\n clone.addFilters(filters);\r\n return clone;\r\n }\r\n\r\n /**\r\n * Generates a Playback instance for the sound without starting playback.\r\n * This allows for pre-configuration of playback properties such as volume and position before the sound is actually played.\r\n * @returns {Playback[]} An array of Playback instances that are ready to be played.\r\n */\r\n preplay(): SynthPlayback[] {\r\n const oscillator = this.context.createOscillator();\r\n if (this.oscillatorOptions.detune) oscillator.detune.value = this.oscillatorOptions.detune;\r\n if (this.oscillatorOptions.frequency) oscillator.frequency.value = this.oscillatorOptions.frequency;\r\n if (this.oscillatorOptions.type) oscillator.type = this.oscillatorOptions.type;\r\n\r\n const gainNode = this.context.createGain();\r\n gainNode.connect(this.globalGainNode);\r\n const playback = new SynthPlayback(oscillator, gainNode, this.context, this.panType);\r\n playback.volume = this.volume;\r\n this._filters.forEach(filter => playback.addFilter(filter));\r\n if (this.panType === 'HRTF') {\r\n playback.threeDOptions = this.threeDOptions;\r\n playback.position = this.position;\r\n } else if (this.panType === 'stereo') {\r\n playback.stereoPan = this.stereoPan as number;\r\n }\r\n this.playbacks.push(playback);\r\n return [playback];\r\n }\r\n\r\n get oscillatorOptions(): Partial<OscillatorOptions> {\r\n return this._oscillatorOptions;\r\n }\r\n\r\n set oscillatorOptions(options: Partial<OscillatorOptions>) {\r\n this._oscillatorOptions = options;\r\n this.playbacks.forEach(p => {\r\n if (p.source instanceof OscillatorNode) {\r\n if (this.oscillatorOptions.detune) p.source.detune.value = this.oscillatorOptions.detune;\r\n if (this.oscillatorOptions.frequency) p.source.frequency.value = this.oscillatorOptions.frequency;\r\n if (this.oscillatorOptions.type) p.source.type = this.oscillatorOptions.type;\r\n }\r\n });\r\n }\r\n}\r\n","import { AudioContext, AudioWorkletNode, IAudioListener, IMediaStreamAudioSourceNode, IPannerNode, IPannerOptions } from 'standardized-audio-context';\nimport phaseVocoderProcessorWorkletUrl from './bundles/phase-vocoder-bundle.js?url';\nimport { AudioCache } from './cache';\nimport { AudioBuffer, BiquadFilterNode, GainNode } from './context';\nimport { FilterManager } from './filters';\nimport { Group } from './group';\nimport type { Playback } from './playback';\nimport { Sound } from './sound';\nimport { createStream } from './stream';\nimport { Synth } from './synth';\n\n\nexport enum SoundType {\n HTML = 'HTML',\n Streaming = 'Streaming',\n Buffer = 'Buffer',\n Oscillator = 'oscillator'\n}\n\n\n\ntype PannerNode = IPannerNode<AudioContext>;\n\n\n\ntype MediaStreamAudioSourceNode = IMediaStreamAudioSourceNode<AudioContext>;\n\n\n/**\n * Represents a 3D position in space.\n * @typedef {Array<number>} Position - An array of three numbers representing the x, y, and z coordinates.\n */\nexport type Position = [x: number, y: number, z: number];\n\n/**\n * Represents the orientation of an object in 3D space.\n * @typedef {Object} Orientation - An object containing two positions: forward and up.\n * @property {Position} forward - The forward direction of the object.\n * @property {Position} up - The up direction of the object.\n */\nexport type Orientation = {\n forward: Position;\n up: Position;\n}\n\n/**\n * Represents the number of times a sound should loop.\n * @typedef {number | 'infinite'} LoopCount - The number of loops, or 'infinite' for endless looping.\n */\nexport type LoopCount = number | 'infinite';\n\n/**\n * Represents the type of fade effect to apply.\n * @typedef {'linear' | 'exponential'} FadeType - The fade type, either 'linear' or 'exponential'.\n */\nexport type FadeType = 'linear' | 'exponential';\n\n/**\n * Represents the type of panning effect to apply.\n * @typedef {'HRTF' | 'stereo'} PanType - The pan type, either 'HRTF' for 3D audio or 'stereo' for traditional stereo panning.\n */\nexport type PanType = 'HRTF' | 'stereo';\n\n/**\n * The base interface for any sound-producing entity, including individual sounds, groups, and playbacks.\n * @interface BaseSound\n */\nexport interface BaseSound {\n isPlaying: boolean;\n play(): BaseSound[];\n seek?(time: number): void;\n stop(): void;\n pause(): void;\n addFilter(filter: BiquadFilterNode): void;\n removeFilter(filter: BiquadFilterNode): void;\n volume: number;\n position?: Position;\n threeDOptions?: any;\n}\n\n\n\n\n\nexport class Cacophony {\n context: AudioContext;\n globalGainNode: GainNode;\n listener: IAudioListener;\n private prevVolume: number = 1;\n private finalizationRegistry: FinalizationRegistry<Playback>;\n\n constructor(context?: AudioContext) {\n this.context = context || new AudioContext();\n this.listener = this.context.listener;\n this.globalGainNode = this.context.createGain();\n this.globalGainNode.connect(this.context.destination);\n\n this.finalizationRegistry = new FinalizationRegistry((heldValue) => {\n // Cleanup callback for Playbacks\n heldValue.cleanup();\n });\n }\n\n async loadWorklets() {\n if (this.context.audioWorklet) {\n await this.createWorkletNode('phase-vocoder', phaseVocoderProcessorWorkletUrl);\n }\n else {\n console.warn('AudioWorklet not supported');\n }\n }\n\n\n async createWorkletNode(\n name: string,\n url: string\n ) {\n // ensure audioWorklet has been loaded\n if (!this.context.audioWorklet) {\n throw new Error('AudioWorklet not supported');\n }\n try {\n return new AudioWorkletNode!(this.context, name);\n } catch (err) {\n console.error(err)\n console.log(\"Loading worklet from url\", url);\n try {\n await this.context.audioWorklet.addModule(url);\n } catch (err) {\n console.error(err);\n throw new Error(`Could not load worklet from url ${url}`);\n }\n\n return new AudioWorkletNode!(this.context, name);\n }\n }\n\n clearMemoryCache(): void {\n AudioCache.clearMemoryCache();\n }\n\n\n createOscillator(options: OscillatorOptions) {\n const synth = new Synth(this.context, this.globalGainNode, SoundType.Oscillator, 'HRTF', options);\n return synth;\n }\n\n async createSound(buffer: AudioBuffer, soundType?: SoundType, panType?: PanType): Promise<Sound>\n\n async createSound(url: string, soundType?: SoundType, panType?: PanType): Promise<Sound>\n\n async createSound(bufferOrUrl: AudioBuffer | string, soundType: SoundType = SoundType.Buffer, panType: PanType = 'HRTF'): Promise<Sound> {\n if (typeof bufferOrUrl === 'object') {\n return Promise.resolve(new Sound(\"\", bufferOrUrl, this.context, this.globalGainNode, SoundType.Buffer, panType));\n }\n const url = bufferOrUrl;\n if (soundType === SoundType.HTML) {\n const audio = new Audio();\n audio.src = url;\n audio.crossOrigin = 'anonymous';\n return new Sound(url, undefined, this.context, this.globalGainNode, SoundType.HTML, panType);\n }\n return AudioCache.getAudioBuffer(this.context, url).then(buffer => new Sound(url as string, buffer, this.context, this.globalGainNode, soundType, panType));\n }\n\n async createGroup(sounds: Sound[]): Promise<Group> {\n const group = new Group();\n sounds.forEach(sound => group.addSound(sound));\n return group;\n }\n\n async createGroupFromUrls(urls: string[], soundType: SoundType = SoundType.Buffer, panType: PanType = 'HRTF'): Promise<Group> {\n const group = new Group();\n const sounds = await Promise.all(urls.map(url => this.createSound(url, soundType, panType)));\n sounds.forEach(sound => group.addSound(sound));\n return group;\n }\n\n async createStream(url: string): Promise<Sound> {\n const stream = await createStream(url, this.context);\n const sound = new Sound(url, undefined, this.context, this.globalGainNode, SoundType.Streaming);\n return sound;\n }\n\n createBiquadFilter = ({ type, frequency, gain, Q }: BiquadFilterOptions): BiquadFilterNode => {\n if (frequency === undefined) {\n frequency = 350;\n }\n const filter = this.context.createBiquadFilter();\n filter.type = type || 'lowpass';\n filter.frequency.value = frequency;\n filter.gain.value = gain || 0;\n filter.Q.value = Q || 1;\n return filter;\n }\n\n /**\n * Creates a PannerNode with the specified options.\n * @param {IPannerOptions} options - An object containing the options to use when creating the PannerNode.\n * @returns {PannerNode} A new PannerNode instance with the specified options.\n * @example\n * const panner = audio.createPanner({\n * positionX: 0,\n * positionY: 0,\n * positionZ: 0,\n * orientationX: 0,\n * orientationY: 0,\n * orientationZ: 0,\n * });\n */\n\n createPanner({ coneInnerAngle, coneOuterAngle, coneOuterGain, distanceModel, maxDistance, channelCount, channelCountMode, channelInterpretation, panningModel, refDistance, rolloffFactor, positionX, positionY, positionZ, orientationX, orientationY, orientationZ }: Partial<IPannerOptions>): PannerNode {\n const panner = this.context.createPanner();\n panner.coneInnerAngle = coneInnerAngle || 360;\n panner.coneOuterAngle = coneOuterAngle || 360;\n panner.coneOuterGain = coneOuterGain || 0;\n panner.distanceModel = distanceModel || 'inverse';\n panner.maxDistance = maxDistance || 10000;\n panner.channelCount = channelCount || 2;\n panner.channelCountMode = channelCountMode || 'clamped-max';\n panner.channelInterpretation = channelInterpretation || 'speakers';\n panner.panningModel = panningModel || 'HRTF';\n panner.refDistance = refDistance || 1;\n panner.rolloffFactor = rolloffFactor || 1;\n panner.positionX.value = positionX || 0;\n panner.positionY.value = positionY || 0;\n panner.positionZ.value = positionZ || 0;\n panner.orientationX.value = orientationX || 0;\n panner.orientationY.value = orientationY || 0;\n panner.orientationZ.value = orientationZ || 0;\n return panner;\n }\n\n /**\n * Suspends the audio context.\n */\n pause(): void {\n if ('suspend' in this.context) {\n this.context.suspend();\n }\n }\n\n /**\n * Resumes the audio context.\n * This method is required to resume the audio context on mobile devices.\n * On desktop, the audio context will automatically resume when a sound is played.\n */\n\n resume() {\n if ('resume' in this.context) {\n this.context.resume();\n }\n }\n\n setGlobalVolume(volume: number) {\n this.globalGainNode.gain.value = volume;\n }\n\n get volume(): number {\n return this.globalGainNode.gain.value;\n }\n\n set volume(volume: number) {\n if (this.muted) {\n this.prevVolume = volume;\n return;\n }\n this.setGlobalVolume(volume);\n }\n\n mute() {\n if (!this.muted) {\n this.prevVolume = this.globalGainNode.gain.value;\n this.setGlobalVolume(0);\n }\n }\n\n unmute() {\n if (this.muted) {\n this.setGlobalVolume(this.prevVolume);\n }\n }\n\n get muted(): boolean {\n return this.globalGainNode.gain.value === 0;\n }\n\n set muted(muted: boolean) {\n if (muted !== this.muted) {\n if (muted) {\n this.mute();\n } else {\n this.unmute();\n }\n }\n }\n\n getMicrophoneStream(): Promise<MicrophoneStream> {\n return new Promise((resolve, reject) => {\n navigator.mediaDevices.getUserMedia({ audio: true })\n .then(stream => {\n const microphoneStream = new MicrophoneStream(this.context);\n microphoneStream.play();\n resolve(microphoneStream);\n })\n .catch(err => {\n reject(err);\n });\n });\n }\n\n get listenerOrientation(): Orientation {\n return {\n forward: [this.listener.forwardX.value, this.listener.forwardY.value, this.listener.forwardZ.value],\n up: [this.listener.upX.value, this.listener.upY.value, this.listener.upZ.value]\n };\n }\n\n set listenerOrientation(orientation: Orientation) {\n const { forward, up } = orientation;\n const [forwardX, forwardY, forwardZ] = forward;\n const [upX, upY, upZ] = up;\n this.listener.forwardX.value = forwardX;\n this.listener.forwardY.value = forwardY;\n this.listener.forwardZ.value = forwardZ;\n this.listener.upX.value = upX;\n this.listener.upY.value = upY;\n this.listener.upZ.value = upZ;\n }\n\n get listenerUpOrientation(): Position {\n return [this.listener.upX.value, this.listener.upY.value, this.listener.upZ.value];\n }\n\n set listenerUpOrientation(up: Position) {\n const [x, y, z] = up;\n this.listener.upX.value = x;\n this.listener.upY.value = y;\n this.listener.upZ.value = z;\n }\n\n get listenerForwardOrientation(): Position {\n return [this.listener.forwardX.value, this.listener.forwardY.value, this.listener.forwardZ.value];\n }\n\n set listenerForwardOrientation(forward: Position) {\n const [x, y, z] = forward;\n this.listener.forwardX.value = x;\n this.listener.forwardY.value = y;\n this.listener.forwardZ.value = z;\n }\n\n get listenerPosition(): Position {\n return [this.listener.positionX.value, this.listener.positionY.value, this.listener.positionZ.value];\n }\n\n set listenerPosition(position: Position) {\n const [x, y, z] = position;\n const currentTime = this.context.currentTime;\n this.listener.positionX.setValueAtTime(x, currentTime);\n this.listener.positionY.setValueAtTime(y, currentTime);\n this.listener.positionZ.setValueAtTime(z, currentTime);\n }\n\n}\n\n\nexport class MicrophonePlayback extends FilterManager {\n private context: AudioContext;\n private source?: MediaStreamAudioSourceNode;\n private gainNode?: GainNode;\n private panner?: PannerNode;\n\n\n constructor(source: MediaStreamAudioSourceNode, gainNode: GainNode, context: AudioContext, loopCount: LoopCount = 0) {\n super();\n this.source = source;\n this.gainNode = gainNode;\n this.context = context;\n this.panner = context.createPanner();\n source.connect(this.panner).connect(this.gainNode);\n this.refreshFilters();\n }\n\n get duration() {\n return 0;\n }\n\n play() {\n if (!this.source) {\n throw new Error('Cannot play a sound that has been cleaned up');\n }\n return [this];\n }\n\n\n /**\n * Indicates whether the audio is currently playing.\n * @returns {boolean} True if the audio is playing, false otherwise.\n */\n\n get isPlaying() {\n return Boolean(this.source);\n }\n\n get volume(): number {\n if (!this.gainNode) {\n throw new Error('Cannot get volume of a sound that has been cleaned up');\n }\n return this.gainNode.gain.value;\n }\n\n set volume(v: number) {\n if (!this.gainNode) {\n throw new Error('Cannot set volume of a sound that has been cleaned up');\n }\n this.gainNode.gain.value = v;\n }\n\n stop(): void {\n if (!this.source) {\n throw new Error('Cannot stop a sound that has been cleaned up');\n }\n this.source.mediaStream.getTracks().forEach(track => track.stop());\n }\n\n pause(): void {\n if (!this.source) {\n throw new Error('Cannot pause a sound that has been cleaned up');\n }\n this.source.mediaStream.getTracks().forEach(track => track.enabled = false);\n }\n\n resume(): void {\n if (!this.source) {\n throw new Error('Cannot resume a sound that has been cleaned up');\n }\n this.source.mediaStream.getTracks().forEach(track => track.enabled = true);\n }\n\n addFilter(filter: BiquadFilterNode): void {\n super.addFilter(filter);\n this.refreshFilters();\n }\n\n removeFilter(filter: BiquadFilterNode): void {\n super.removeFilter(filter);\n this.refreshFilters();\n }\n\n set position(position: Position) {\n if (!this.panner) {\n throw new Error('Cannot move a sound that has been cleaned up');\n }\n const [x, y, z] = position;\n this.panner.positionX.value = x;\n this.panner.positionY.value = y;\n this.panner.positionZ.value = z;\n }\n\n get position(): Position {\n if (!this.panner) {\n throw new Error('Cannot get position of a sound that has been cleaned up');\n }\n return [this.panner.positionX.value, this.panner.positionY.value, this.panner.positionZ.value];\n }\n\n private refreshFilters(): void {\n if (!this.source || !this.gainNode) {\n throw new Error('Cannot update filters on a sound that has been cleaned up');\n }\n let connection = this.source;\n this.source.disconnect();\n connection = this.applyFilters(connection);\n connection.connect(this.gainNode);\n }\n\n get playbackRate(): number {\n // Playback rate is not applicable for live microphone stream\n return 1;\n }\n\n set playbackRate(rate: number) {\n }\n\n\n\n}\n\nexport class MicrophoneStream extends FilterManager implements BaseSound {\n context: AudioContext;\n private _position: Position = [0, 0, 0];\n loopCount: LoopCount = 0;\n private prevVolume: number = 1;\n private microphoneGainNode: GainNode;\n private streamPlayback?: MicrophonePlayback;\n private stream: MediaStream | undefined;\n private streamSource?: MediaStreamAudioSourceNode;\n\n constructor(context: AudioContext) {\n super();\n this.context = context;\n this.microphoneGainNode = this.context.createGain();\n }\n\n play(): MicrophonePlayback[] {\n if (!this.stream) {\n navigator.mediaDevices.getUserMedia({ audio: true })\n .then(stream => {\n this.stream = stream;\n this.streamSource = this.context.createMediaStreamSource(this.stream);\n this.streamPlayback = new MicrophonePlayback(this.streamSource, this.microphoneGainNode, this.context);\n this.streamPlayback.play();\n })\n .catch(err => {\n console.error('Error initializing microphone stream:', err);\n });\n }\n return this.streamPlayback ? [this.streamPlayback] : [];\n }\n\n get duration() {\n return 0;\n }\n\n\n seek(time: number) {\n // Seeking is not applicable for live microphone stream\n }\n\n /**\n * A boolean indicating whether the sound is currently playing.\n * @returns {boolean} True if the sound is playing, false otherwise.\n */\n\n get isPlaying(): boolean {\n return Boolean(this.streamPlayback);\n }\n\n stop() {\n if (this.streamPlayback) {\n this.streamPlayback.stop();\n this.streamPlayback = undefined;\n }\n }\n\n pause() {\n if (this.streamPlayback) {\n this.streamPlayback.pause();\n }\n }\n\n resume() {\n if (this.streamPlayback) {\n this.streamPlayback.resume();\n }\n }\n\n addFilter(filter: BiquadFilterNode): void {\n if (this.streamPlayback) {\n this.streamPlayback.addFilter(filter);\n }\n }\n\n removeFilter(filter: BiquadFilterNode): void {\n if (this.streamPlayback) {\n this.streamPlayback.removeFilter(filter);\n }\n }\n\n get volume(): number {\n return this.streamPlayback ? this.streamPlayback.volume : 0;\n }\n\n set volume(volume: number) {\n if (this.streamPlayback) {\n this.streamPlayback.volume = volume;\n }\n }\n\n get position(): Position {\n // Position is not applicable for live microphone stream\n return [0, 0, 0];\n }\n\n set position(position: Position) {\n // Position is not applicable for live microphone stream\n }\n\n loop(loopCount?: LoopCount): LoopCount {\n // Looping is not applicable for live microphone stream\n return 0;\n }\n\n\n get playbackRate(): number {\n // Playback rate is not applicable for live microphone stream\n return 1;\n }\n\n set playbackRate(rate: number) {\n }\n}\n"],"names":["phaseVocoderProcessorWorkletUrl","LRUCache","maxSize","key","value","firstKey","DEFAULT_CACHE_SIZE","AudioCache","error","url","cache","response","etag","lastModified","headers","fetchResponse","responseClone","newEtag","newLastModified","cacheData","cachedResponse","context","arrayBuffer","metaResponse","base64Data","buffer","c","audioBuffer","pendingRequest","bufferFromCache","metadata","FilterManager","filter","f","connection","prevConnection","filters","Group","sounds","randomIndex","playback","p","shouldLoop","sound","a","b","time","playbacks","loopCount","position","volume","rate","PlaybackContainer","Base","options","PannerMixin","panType","audioContext","pannerNode","clamp","panner","x","y","z","min","max","VolumeMixin","gainNode","v","BasePlayback","Playback","source","offset","playing","loop","mediaElement","newFilter","overrides","Sound","globalGainNode","type","SoundType","stereoPan","threeDOptions","playbackRate","clone","audio","appendBuffer","buffer1","buffer2","tmp","createStream","audioStack","nextTime","reader","header","read","done","scheduleBuffers","err","OscillatorMixin","SynthPlayback","Synth","oscillatorOptions","oscillator","Cacophony","AudioContext","heldValue","name","AudioWorkletNode","bufferOrUrl","soundType","group","urls","frequency","gain","Q","coneInnerAngle","coneOuterAngle","coneOuterGain","distanceModel","maxDistance","channelCount","channelCountMode","channelInterpretation","panningModel","refDistance","rolloffFactor","positionX","positionY","positionZ","orientationX","orientationY","orientationZ","muted","resolve","reject","stream","microphoneStream","MicrophoneStream","orientation","forward","up","forwardX","forwardY","forwardZ","upX","upY","upZ","currentTime","MicrophonePlayback","track"],"mappings":"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"}