| @@ -16,5 +16,6 @@ module.exports = { | |||||
| rules: { | rules: { | ||||
| "no-console": process.env.NODE_ENV === "production" ? "warn" : "off", | "no-console": process.env.NODE_ENV === "production" ? "warn" : "off", | ||||
| "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", | "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", | ||||
| "no-empty": "off", | |||||
| }, | }, | ||||
| }; | }; | ||||
| @@ -0,0 +1 @@ | |||||
| *.ogg filter=lfs diff=lfs merge=lfs -text | |||||
| @@ -1,5 +1,5 @@ | |||||
| { | { | ||||
| "name": "vore-audio-player", | |||||
| "name": "dissolve", | |||||
| "version": "0.1.0", | "version": "0.1.0", | ||||
| "private": true, | "private": true, | ||||
| "scripts": { | "scripts": { | ||||
| oid sha256:787ad0cb527987a856fbf3da3cf540846e27ed7a714ce9357f99cce7b1dcd53d | |||||
| size 111664 |
| oid sha256:667e7572fe9ebe564068566befbb07d105e925b205933a3c023306e288021880 | |||||
| size 71568 |
| oid sha256:191b8a31da076d8066a7b30b24e487dc7a472671236e78bc61817ee2ab0abd8c | |||||
| size 144433 |
| oid sha256:d805cb879329f2ca69c8231cb30a5fcdf10a5986c00cbae5ea2852df7998166e | |||||
| size 105222 |
| oid sha256:5b8b2dd57393eaedc39686196320d1d6d12d2d03248cfadd646afeef0e88713c | |||||
| size 85350 |
| oid sha256:cd66b49e128e235d2dead975f16f4196e4dea54e471fa110792e3dc4d66c8f41 | |||||
| size 96405 |
| oid sha256:1d9af0bd8d4a1a136b2535d2c1ede70c62886a8339d6cc18cea0f145f987a1f0 | |||||
| size 98411 |
| oid sha256:00b24b7889fd8fa485b5531526764de0a0152746c8b74f602dc24840e3484122 | |||||
| size 116286 |
| oid sha256:4adf1562dbf188fac687e663d9cd85ab4458f55e797fc80d57c0dddf9adc3486 | |||||
| size 101056 |
| oid sha256:b7c7b21843a7cbb1f529b950fb25b79bc70a2b830601a8787c0c8ec2cc948bd8 | |||||
| size 74018 |
| oid sha256:11815532099c48b2be2abfd65e7ce0159ce88db5cbbad13aa60176e59d015110 | |||||
| size 64020 |
| oid sha256:03f38bed1cb53fb487c242812797f5687741c6a3767af1ec845124b7122cca28 | |||||
| size 74535 |
| oid sha256:51a23b81633892ed6f7d140ba43595380fade8796b7a33af4e69b8570581bbb5 | |||||
| size 101174 |
| oid sha256:1813168987dd1501ba47c61ebba8017ce44005f25704cb3f97676aca5614dd7b | |||||
| size 104667 |
| oid sha256:f45bc21cc39b03c7c7e211edbd8d8964c24d0a4b2882d008ce023cbfbbac8e73 | |||||
| size 85117 |
| oid sha256:ff286fcdbaa529096aef35d8d05fd0eed3c8dcc3efb9dd60002300cc4672a591 | |||||
| size 67899 |
| oid sha256:353212c0b88d5acf1cba7795462b516e07c5743117e8773f8694d7e1e1d52490 | |||||
| size 294651 |
| oid sha256:545cbe12f08f53c70c841c7fa1c1d55283804a0d72b39667c9763a24c7acb842 | |||||
| size 248493 |
| oid sha256:a81d487034696805b5862119b4b0e71336ac9fbc4eee22e89b6d20e82f16d967 | |||||
| size 176136 |
| oid sha256:cad1673ea5f4a85a7eb2cd125073ac9daf1bc27d105520e847af06549bd44abb | |||||
| size 2698636 |
| oid sha256:7f7645ce0b6fed13c6222edc1c66b73aa5c71c7f9fd8df6d651d28e1cfeaa94c | |||||
| size 3251342 |
| oid sha256:0dcd827ff7f1daafaed20af0b8f34f5aa249b005e60380ff75ce5e356eeafa9d | |||||
| size 5468962 |
| oid sha256:be6ce6f1ed6cb26836e39d36e55390cfc1f0fad2bb6c6e0ad5fae57f36495732 | |||||
| size 43798 |
| oid sha256:3d5f673013170cf01fc2c76a8c04dffe353d3d9f1a527cebc696cd5a8f4d1983 | |||||
| size 86792 |
| oid sha256:6bac55e232a6e64fcbb03da218ace13d157f8b3ef6a2bbd48037235e5d2c41e1 | |||||
| size 114425 |
| oid sha256:912c6a0feb86dba876f56ae32f809fdf824ffaaf0468a0a9e77517cb892a6f33 | |||||
| size 34352 |
| oid sha256:9e24374ab8689bac44da4aff4e17929287a80a6bc62720f3a9cba4ff48bf929d | |||||
| size 22501 |
| oid sha256:63b52747920519584fcf64695ad5137e26f275634475392ef4a71fdf7fb81214 | |||||
| size 8763 |
| oid sha256:d491aab879924058018e2ba82041d0537479e8eff3b729523eb5b84a5a5ef7e4 | |||||
| size 37195 |
| oid sha256:ce4af58cb2a7abd4aa9be45a166688767e6a1debff993eccf2ba3c4b46c0915d | |||||
| size 28025 |
| oid sha256:6dfa0cb957dc6657c481b367a362e2669798477a554cebf6023a2ce53da60132 | |||||
| size 102297 |
| oid sha256:fea24bd27776c01cfff88ce00ec25a12a5b7f95ef6d2dfd1436d323f3db1c5e0 | |||||
| size 86243 |
| oid sha256:1c8ee26034a297a83f0932db94a1f87939644481895b8d7cd8dbafa84bf9c967 | |||||
| size 362766 |
| oid sha256:d5d1ed3b5105e6f962e22660c60439b20d294bd4f6e9ebfff94cc898535fbc80 | |||||
| size 35220 |
| oid sha256:2bc566fc21590e686dd046a15c6da91145dc80e9ca4b6fa6e17c972616ce02a7 | |||||
| size 19268 |
| oid sha256:f2384d3ffec939090c738c2e39df801cb0df952ff2126e74e46fca2c75bf6dfc | |||||
| size 39596 |
| oid sha256:6097f9a3572c47c6672863510dd6832081f47e7feec078ac49e46ba95da57ade | |||||
| size 71176 |
| oid sha256:eb2f32585650ef6a74cedfc53e9592cd80f387a80998220763810478833fb60e | |||||
| size 139272 |
| oid sha256:9b511101e5f5eeff9aa352857fc921e47d5667fb15958b2b98dccf14dafc8c09 | |||||
| size 36841 |
| oid sha256:3eaa8ce88a35682c9b604a7aa97dc617d1a6525ec3e75f2edaf39f380792def2 | |||||
| size 110538 |
| oid sha256:2222bf410cfd60eff7c4eac9755f496c58353fe460f941c51bbadef5ea2b037c | |||||
| size 23283 |
| oid sha256:d42fd045363e92baea0816926a0354695a141b4bfb42a8965c1441c7e7751ecb | |||||
| size 20813 |
| oid sha256:56422f9b551589cc4926e813e97119d59be4f50760ab5b8324154fc7ffa88154 | |||||
| size 23520 |
| oid sha256:cb38da98e5d9761d49b985472cb3ba857fc5f87740417e296a013d2877848ea9 | |||||
| size 192147 |
| oid sha256:54234c188544a284d98ce95620428614b56d5d7c599b5f8ad63a990566beb84f | |||||
| size 344218 |
| oid sha256:fd78e3b1e6ef70d937368e3b27a794d0091c8ed41f0b3d1e4f5152f79a67b956 | |||||
| size 204429 |
| oid sha256:00bef9333b297f6d8b4e56360f7eb45a886f353a9e218adf850e288e2c18b8ba | |||||
| size 249950 |
| oid sha256:54fcf614d14a8dd17512a69963bc5807bfd9429a0090fb81842f50c3bf904a1a | |||||
| size 205753 |
| oid sha256:515dc49dc92add3ab47d0e1444dbe40ebb147245f6ed738b71037a183ee1c1ea | |||||
| size 193869 |
| @@ -5,7 +5,7 @@ | |||||
| <meta http-equiv="X-UA-Compatible" content="IE=edge"> | <meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||||
| <meta name="viewport" content="width=device-width,initial-scale=1.0"> | <meta name="viewport" content="width=device-width,initial-scale=1.0"> | ||||
| <link rel="icon" href="<%= BASE_URL %>favicon.ico"> | <link rel="icon" href="<%= BASE_URL %>favicon.ico"> | ||||
| <title><%= htmlWebpackPlugin.options.title %></title> | |||||
| <title>Dissolve</title> | |||||
| </head> | </head> | ||||
| <body> | <body> | ||||
| <noscript> | <noscript> | ||||
| @@ -1,15 +1,14 @@ | |||||
| <template> | <template> | ||||
| <img alt="Vue logo" src="./assets/logo.png" /> | |||||
| <HelloWorld msg="Welcome to Your Vue.js + TypeScript App" /> | |||||
| <VoreAudio /> | |||||
| </template> | </template> | ||||
| <script lang="ts"> | <script lang="ts"> | ||||
| import { Options, Vue } from "vue-class-component"; | import { Options, Vue } from "vue-class-component"; | ||||
| import HelloWorld from "./components/HelloWorld.vue"; | |||||
| import VoreAudio from "./components/VoreAudio.vue"; | |||||
| @Options({ | @Options({ | ||||
| components: { | components: { | ||||
| HelloWorld, | |||||
| VoreAudio, | |||||
| }, | }, | ||||
| }) | }) | ||||
| export default class App extends Vue {} | export default class App extends Vue {} | ||||
| @@ -0,0 +1,249 @@ | |||||
| export abstract class Source { | |||||
| public abstract kind: string; | |||||
| protected sounds: Array<AudioBuffer> = []; | |||||
| public gain: GainNode; | |||||
| public output: StereoPannerNode; | |||||
| constructor(public name: string) { | |||||
| this.gain = context.createGain(); | |||||
| this.output = context.createStereoPanner(); | |||||
| this.gain.connect(this.output); | |||||
| } | |||||
| public loadSound(name: string): void { | |||||
| loadAudio(name, this); | |||||
| } | |||||
| public addLoadedSound(sound: AudioBuffer): void { | |||||
| this.sounds.push(sound); | |||||
| } | |||||
| public abstract start(): void; | |||||
| public abstract tick(dt: number): void; | |||||
| } | |||||
| export class IntervalSource extends Source { | |||||
| kind = "Interval"; | |||||
| private remaining: number; | |||||
| private started = false; | |||||
| constructor(name: string, public interval: number, public randomness = 0) { | |||||
| super(name); | |||||
| this.remaining = this.interval + (Math.random() - 0.5) * 2 * this.randomness | |||||
| } | |||||
| public start(): void { | |||||
| this.started = true; | |||||
| } | |||||
| public tick(dt: number): void { | |||||
| if (this.started) { | |||||
| this.remaining -= dt; | |||||
| if (this.remaining <= 0) { | |||||
| const index = Math.floor(Math.random() * this.sounds.length); | |||||
| const node = context.createBufferSource(); | |||||
| node.buffer = this.sounds[index]; | |||||
| node.connect(this.gain); | |||||
| node.start(); | |||||
| this.output.pan.value = Math.random() * 0.4 - 0.2; | |||||
| this.remaining = this.interval + (Math.random() - 0.5) * 2 * this.randomness | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| export class LoopingSource extends Source { | |||||
| kind = "Looping"; | |||||
| private source!: AudioBufferSourceNode; | |||||
| private started = false; | |||||
| private running = false; | |||||
| constructor(name: string) { | |||||
| super(name); | |||||
| } | |||||
| public start(): void { | |||||
| this.started = true; | |||||
| } | |||||
| private pickRandom(): void { | |||||
| const index = Math.floor(Math.random() * this.sounds.length); | |||||
| this.source = context.createBufferSource(); | |||||
| this.source.buffer = this.sounds[index]; | |||||
| this.source.connect(this.gain); | |||||
| this.source.onended = () => { this.pickRandom(); this.source.start(); }; | |||||
| } | |||||
| public tick(dt: number) { | |||||
| if (this.started && this.sounds.length > 0 && !this.running) { | |||||
| this.pickRandom(); | |||||
| this.source.start(); | |||||
| this.running = true; | |||||
| } | |||||
| } | |||||
| } | |||||
| let context: AudioContext; | |||||
| const audioBaseUrl = "/audio/"; | |||||
| const waiting: Map<string, Array<Source>> = new Map(); | |||||
| const audioDict: Map<string, AudioBuffer> = new Map(); | |||||
| // asynchronously load an audio file | |||||
| function loadAudio(name: string, source: Source, flush = false) { | |||||
| // are we already trying to get the audio? | |||||
| if (!waiting.has(name)) { | |||||
| waiting.set(name, []); | |||||
| } | |||||
| const list: Array<Source> | undefined = waiting.get(name); | |||||
| if (list !== undefined) list.push(source); | |||||
| // do we already have the audio? | |||||
| if (audioDict.has(name) && !flush) { | |||||
| const buf: AudioBuffer | undefined = audioDict.get(name); | |||||
| if (buf !== undefined) source.addLoadedSound(buf); | |||||
| } | |||||
| // is the audio already stored locally? | |||||
| if (!flush) { | |||||
| checkCache(name); | |||||
| } else { | |||||
| loadRemoteAudio(name); | |||||
| } | |||||
| } | |||||
| function cacheAndParse(name: string, data: ArrayBuffer) { | |||||
| storeCache(name, data.slice(0)); | |||||
| parseAudioData(name, data); | |||||
| } | |||||
| function parseAudioData(name: string, data: ArrayBuffer) { | |||||
| context.decodeAudioData( | |||||
| data, | |||||
| function (buffer) { | |||||
| audioDict.set(name, buffer); | |||||
| const waitingSources: Array<Source> | undefined = waiting.get(name); | |||||
| if (waitingSources !== undefined) { | |||||
| waitingSources.forEach((source) => { | |||||
| source.addLoadedSound(buffer); | |||||
| }); | |||||
| } | |||||
| }, | |||||
| function (e) { | |||||
| console.error("Error with decoding audio data for " + name + ": " + e); | |||||
| } | |||||
| ); | |||||
| } | |||||
| function loadRemoteAudio(name: string) { | |||||
| const xhr = new XMLHttpRequest(); | |||||
| xhr.open("GET", audioBaseUrl + name, true); | |||||
| xhr.responseType = "arraybuffer"; | |||||
| xhr.onload = () => { | |||||
| if (xhr.status == 200) cacheAndParse(name, xhr.response); | |||||
| else { | |||||
| console.error("Couldn't load " + name); | |||||
| } | |||||
| }; | |||||
| xhr.onerror = () => { | |||||
| console.error("Couldn't load " + name); | |||||
| }; | |||||
| xhr.send(); | |||||
| } | |||||
| // check if the content is cached | |||||
| function checkCache(name: string) { | |||||
| const req = window.indexedDB.open("cache", 1); | |||||
| req.onsuccess = () => { | |||||
| const db = req.result; | |||||
| const tx = db.transaction("audio", "readonly"); | |||||
| const audio = tx.objectStore("audio"); | |||||
| const read: IDBRequest = audio.get([name]); | |||||
| read.onsuccess = () => { | |||||
| const res = read.result; | |||||
| if (res === undefined) { | |||||
| loadRemoteAudio(name); | |||||
| } else { | |||||
| parseAudioData(name, res.content); | |||||
| } | |||||
| }; | |||||
| tx.oncomplete = () => { | |||||
| db.close(); | |||||
| }; | |||||
| }; | |||||
| } | |||||
| // caching stuff here | |||||
| function storeCache(name: string, blob: ArrayBuffer) { | |||||
| const req = window.indexedDB.open("cache", 1); | |||||
| req.onsuccess = () => { | |||||
| const db = req.result; | |||||
| const tx = db.transaction("audio", "readwrite"); | |||||
| const audio = tx.objectStore("audio"); | |||||
| audio.put({ | |||||
| name: name, | |||||
| content: blob, | |||||
| }); | |||||
| tx.oncomplete = () => { | |||||
| db.close(); | |||||
| }; | |||||
| }; | |||||
| } | |||||
| export function setup(): AudioContext { | |||||
| context = new AudioContext(); | |||||
| createCache(); | |||||
| return context; | |||||
| } | |||||
| export function clearCache(): void { | |||||
| const idb = window.indexedDB; | |||||
| idb.deleteDatabase("cache"); | |||||
| createCache(); | |||||
| } | |||||
| // if the indexedDB table doesn't exist at all, make it | |||||
| function createCache(): void { | |||||
| const idb = window.indexedDB; | |||||
| const req = idb.open("cache", 1); | |||||
| req.onupgradeneeded = (event) => { | |||||
| const db = req.result; | |||||
| if (event.oldVersion > 0 && event.oldVersion < 3) { | |||||
| db.deleteObjectStore("audio"); | |||||
| } | |||||
| db.createObjectStore("audio", { keyPath: ["name"] }); | |||||
| }; | |||||
| req.onerror = () => { | |||||
| alert("Couldn't open the database?"); | |||||
| }; | |||||
| } | |||||
| @@ -1,126 +0,0 @@ | |||||
| <template> | |||||
| <div class="hello"> | |||||
| <h1>{{ msg }}</h1> | |||||
| <p> | |||||
| For a guide and recipes on how to configure / customize this project,<br /> | |||||
| check out the | |||||
| <a href="https://cli.vuejs.org" target="_blank" rel="noopener" | |||||
| >vue-cli documentation</a | |||||
| >. | |||||
| </p> | |||||
| <h3>Installed CLI Plugins</h3> | |||||
| <ul> | |||||
| <li> | |||||
| <a | |||||
| href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" | |||||
| target="_blank" | |||||
| rel="noopener" | |||||
| >babel</a | |||||
| > | |||||
| </li> | |||||
| <li> | |||||
| <a | |||||
| href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-typescript" | |||||
| target="_blank" | |||||
| rel="noopener" | |||||
| >typescript</a | |||||
| > | |||||
| </li> | |||||
| <li> | |||||
| <a | |||||
| href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" | |||||
| target="_blank" | |||||
| rel="noopener" | |||||
| >eslint</a | |||||
| > | |||||
| </li> | |||||
| </ul> | |||||
| <h3>Essential Links</h3> | |||||
| <ul> | |||||
| <li> | |||||
| <a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a> | |||||
| </li> | |||||
| <li> | |||||
| <a href="https://forum.vuejs.org" target="_blank" rel="noopener" | |||||
| >Forum</a | |||||
| > | |||||
| </li> | |||||
| <li> | |||||
| <a href="https://chat.vuejs.org" target="_blank" rel="noopener" | |||||
| >Community Chat</a | |||||
| > | |||||
| </li> | |||||
| <li> | |||||
| <a href="https://twitter.com/vuejs" target="_blank" rel="noopener" | |||||
| >Twitter</a | |||||
| > | |||||
| </li> | |||||
| <li> | |||||
| <a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a> | |||||
| </li> | |||||
| </ul> | |||||
| <h3>Ecosystem</h3> | |||||
| <ul> | |||||
| <li> | |||||
| <a href="https://router.vuejs.org" target="_blank" rel="noopener" | |||||
| >vue-router</a | |||||
| > | |||||
| </li> | |||||
| <li> | |||||
| <a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a> | |||||
| </li> | |||||
| <li> | |||||
| <a | |||||
| href="https://github.com/vuejs/vue-devtools#vue-devtools" | |||||
| target="_blank" | |||||
| rel="noopener" | |||||
| >vue-devtools</a | |||||
| > | |||||
| </li> | |||||
| <li> | |||||
| <a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener" | |||||
| >vue-loader</a | |||||
| > | |||||
| </li> | |||||
| <li> | |||||
| <a | |||||
| href="https://github.com/vuejs/awesome-vue" | |||||
| target="_blank" | |||||
| rel="noopener" | |||||
| >awesome-vue</a | |||||
| > | |||||
| </li> | |||||
| </ul> | |||||
| </div> | |||||
| </template> | |||||
| <script lang="ts"> | |||||
| import { Options, Vue } from "vue-class-component"; | |||||
| @Options({ | |||||
| props: { | |||||
| msg: String, | |||||
| }, | |||||
| }) | |||||
| export default class HelloWorld extends Vue { | |||||
| msg!: string; | |||||
| } | |||||
| </script> | |||||
| <!-- Add "scoped" attribute to limit CSS to this component only --> | |||||
| <style scoped> | |||||
| h3 { | |||||
| margin: 40px 0 0; | |||||
| } | |||||
| ul { | |||||
| list-style-type: none; | |||||
| padding: 0; | |||||
| } | |||||
| li { | |||||
| display: inline-block; | |||||
| margin: 0 10px; | |||||
| } | |||||
| a { | |||||
| color: #42b983; | |||||
| } | |||||
| </style> | |||||
| @@ -0,0 +1,135 @@ | |||||
| <template> | |||||
| <h1>Dissolve</h1> | |||||
| <div>This is a mega-early-alpha vore audio generator.</div> | |||||
| <div>Click the buttons below to start each kind of audio.</div> | |||||
| <div>(clicking repeatedly will play even MORE audio)</div> | |||||
| <div>Follow <a href="https://twitter.com/causticcrux">@causticcrux</a> for more.</div> | |||||
| <div>Many sounds by <a href="https://www.furaffinity.net/user/jeschke">Jit</a>!</div> | |||||
| <button v-on:click="startGlorps">Glorps</button> | |||||
| <button v-on:click="startDigestion">Digestion</button> | |||||
| <button v-on:click="startBurps">Burps</button> | |||||
| <button v-on:click="startGurgles">Gurgles</button> | |||||
| <div></div> | |||||
| <button v-on:click="clear">Delete all cached sound (if it gets stuck)</button> | |||||
| </template> | |||||
| <script lang="ts"> | |||||
| import { clearCache, IntervalSource, LoopingSource, setup, Source } from "@/audio"; | |||||
| import { Options, Vue } from "vue-class-component"; | |||||
| @Options({ | |||||
| props: { | |||||
| msg: String, | |||||
| }, | |||||
| }) | |||||
| export default class VoreAudio extends Vue { | |||||
| context!: AudioContext; | |||||
| startGlorps(): void { | |||||
| const source: Source = new IntervalSource("Guts", 5000, 2000); | |||||
| source.loadSound("bowels-to-intestines.ogg"); | |||||
| source.loadSound("intestines-to-bowels.ogg"); | |||||
| source.loadSound("intestines-to-stomach.ogg"); | |||||
| source.loadSound("intestines-to-stomach-forced.ogg"); | |||||
| source.loadSound("stomach-to-intestines.ogg"); | |||||
| source.loadSound("stomach-to-intestines-fail.ogg"); | |||||
| source.loadSound("stomach-churn.ogg"); | |||||
| source.loadSound("bowels-churn-safe.ogg"); | |||||
| source.loadSound("bowels-churn-danger.ogg"); | |||||
| source.output.connect(this.context.destination); | |||||
| console.log(source) | |||||
| source.start(); | |||||
| setInterval(() => source.tick(100), 100); | |||||
| } | |||||
| startDigestion(): void { | |||||
| const source: Source = new LoopingSource("Digestion"); | |||||
| source.loadSound("fen-stomach.ogg"); | |||||
| source.loadSound("fen-intestines.ogg"); | |||||
| source.loadSound("fen-bowels.ogg"); | |||||
| source.output.connect(this.context.destination); | |||||
| source.start(); | |||||
| console.log(source); | |||||
| setInterval(() => source.tick(100), 100); | |||||
| } | |||||
| startBurps(): void { | |||||
| const source: Source = new IntervalSource("Burps", 12000, 3000); | |||||
| source.loadSound("belch (1).ogg"); | |||||
| source.loadSound("belch (2).ogg"); | |||||
| source.loadSound("belch (3).ogg"); | |||||
| source.loadSound("belch (4).ogg"); | |||||
| source.loadSound("belch (5).ogg"); | |||||
| source.loadSound("belch (6).ogg"); | |||||
| source.loadSound("belch (7).ogg"); | |||||
| source.loadSound("belch (8).ogg"); | |||||
| source.loadSound("belch (9).ogg"); | |||||
| source.loadSound("belch (10).ogg"); | |||||
| source.loadSound("belch (11).ogg"); | |||||
| source.loadSound("belch (12).ogg"); | |||||
| source.loadSound("belch (13).ogg"); | |||||
| source.loadSound("belch (14).ogg"); | |||||
| source.loadSound("belch (15).ogg"); | |||||
| source.loadSound("belch (16).ogg"); | |||||
| source.output.connect(this.context.destination); | |||||
| source.start(); | |||||
| console.log(source); | |||||
| setInterval(() => source.tick(100), 100); | |||||
| } | |||||
| startGurgles(): void { | |||||
| const source: Source = new IntervalSource("Gurgles", 3000, 1000); | |||||
| source.loadSound("gurgles/gurgle (1).ogg"); | |||||
| source.loadSound("gurgles/gurgle (2).ogg"); | |||||
| source.loadSound("gurgles/gurgle (3).ogg"); | |||||
| source.loadSound("gurgles/gurgle (4).ogg"); | |||||
| source.loadSound("gurgles/gurgle (5).ogg"); | |||||
| source.loadSound("gurgles/gurgle (6).ogg"); | |||||
| source.loadSound("gurgles/gurgle (7).ogg"); | |||||
| source.loadSound("gurgles/gurgle (8).ogg"); | |||||
| source.loadSound("gurgles/gurgle (9).ogg"); | |||||
| source.loadSound("gurgles/gurgle (10).ogg"); | |||||
| source.loadSound("gurgles/gurgle (11).ogg"); | |||||
| source.loadSound("gurgles/gurgle (12).ogg"); | |||||
| source.loadSound("gurgles/gurgle (13).ogg"); | |||||
| source.loadSound("gurgles/gurgle (14).ogg"); | |||||
| source.loadSound("gurgles/gurgle (15).ogg"); | |||||
| source.loadSound("gurgles/gurgle (16).ogg"); | |||||
| source.loadSound("gurgles/gurgle (17).ogg"); | |||||
| source.loadSound("gurgles/gurgle (18).ogg"); | |||||
| source.loadSound("gurgles/gurgle (19).ogg"); | |||||
| source.loadSound("gurgles/gurgle (20).ogg"); | |||||
| source.loadSound("gurgles/gurgle (21).ogg"); | |||||
| source.output.connect(this.context.destination); | |||||
| source.start(); | |||||
| source.gain.gain.value = 0.5; | |||||
| console.log(source); | |||||
| setInterval(() => source.tick(100), 100); | |||||
| } | |||||
| clear() { | |||||
| clearCache(); | |||||
| } | |||||
| mounted(): void { | |||||
| this.context = setup(); | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style scoped> | |||||
| h3 { | |||||
| margin: 40px 0 0; | |||||
| } | |||||
| ul { | |||||
| list-style-type: none; | |||||
| padding: 0; | |||||
| } | |||||
| li { | |||||
| display: inline-block; | |||||
| margin: 0 10px; | |||||
| } | |||||
| a { | |||||
| color: #42b983; | |||||
| } | |||||
| </style> | |||||