Also goes back to avoiding default-export where possiblemaster
| @@ -1,33 +0,0 @@ | |||||
| <template> | |||||
| <VoreAudio /> | |||||
| </template> | |||||
| <script lang="ts"> | |||||
| import { Options, Vue } from "vue-class-component"; | |||||
| import VoreAudio from "./components/VoreAudio.vue"; | |||||
| @Options({ | |||||
| components: { | |||||
| VoreAudio, | |||||
| }, | |||||
| }) | |||||
| export default class App extends Vue {} | |||||
| </script> | |||||
| <style> | |||||
| body { | |||||
| background: #111; | |||||
| } | |||||
| #app { | |||||
| font-family: Avenir, Helvetica, Arial, sans-serif; | |||||
| -webkit-font-smoothing: antialiased; | |||||
| -moz-osx-font-smoothing: grayscale; | |||||
| text-align: center; | |||||
| color: #ddd; | |||||
| background: #111; | |||||
| margin-top: 60px; | |||||
| } | |||||
| </style> | |||||
| <style src="@vueform/slider/themes/default.css"></style> | |||||
| <style src="@vueform/toggle/themes/default.css"></style> | |||||
| @@ -0,0 +1,63 @@ | |||||
| <template> | |||||
| <h1>Dissolve</h1> | |||||
| <div>This is a mega-early-alpha vore audio generator.</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="start" class="start-button"> | |||||
| {{ started ? "Add" : "Start" }} | |||||
| </button> | |||||
| <SoundscapeComp | |||||
| v-for="(soundscape, index) in soundscapes" | |||||
| :key="index" | |||||
| :soundscape="soundscape" | |||||
| /> | |||||
| </template> | |||||
| <script lang="ts"> | |||||
| import { Options, Vue } from "vue-class-component"; | |||||
| import { setup, Soundscape } from "./audio"; | |||||
| import SoundscapeComp from "./components/SoundscapeComp.vue"; | |||||
| @Options({ | |||||
| components: { | |||||
| SoundscapeComp, | |||||
| }, | |||||
| }) | |||||
| export default class Dissolve extends Vue { | |||||
| started = false; | |||||
| soundscapes: Array<Soundscape> = []; | |||||
| start(): void { | |||||
| this.started = true; | |||||
| const scape: Soundscape = new Soundscape(); | |||||
| this.soundscapes.push(scape); | |||||
| } | |||||
| mounted(): void { | |||||
| setup(); | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style> | |||||
| body { | |||||
| background: #111; | |||||
| } | |||||
| #app { | |||||
| font-family: Avenir, Helvetica, Arial, sans-serif; | |||||
| -webkit-font-smoothing: antialiased; | |||||
| -moz-osx-font-smoothing: grayscale; | |||||
| text-align: center; | |||||
| color: #ddd; | |||||
| background: #111; | |||||
| margin-top: 60px; | |||||
| } | |||||
| </style> | |||||
| <style src="@vueform/slider/themes/default.css"></style> | |||||
| <style src="@vueform/toggle/themes/default.css"></style> | |||||
| @@ -1,8 +1,49 @@ | |||||
| import "reflect-metadata"; | import "reflect-metadata"; | ||||
| import Source from "./sources/Source"; | |||||
| import { Filter } from "./filters/Filter"; | |||||
| import { Source } from "./sources/Source"; | |||||
| let ogg_support = false; | let ogg_support = false; | ||||
| export class Soundscape { | |||||
| public sources: Array<Source> = []; | |||||
| public filters: Array<Filter> = []; | |||||
| public filterBus: GainNode; | |||||
| addSource(source: Source): void { | |||||
| source.output.connect(this.filterBus); | |||||
| this.sources.push(source); | |||||
| source.start(); | |||||
| } | |||||
| addFilter(filter: Filter): void { | |||||
| if (this.filters.length > 0) { | |||||
| const last: Filter = this.filters[this.filters.length - 1]; | |||||
| last.output.disconnect(); | |||||
| last.output.connect(filter.input); | |||||
| filter.output.connect(context.destination); | |||||
| } else { | |||||
| this.filterBus.disconnect(); | |||||
| this.filterBus.connect(filter.input); | |||||
| filter.output.connect(context.destination); | |||||
| } | |||||
| filter.start(); | |||||
| this.filters.push(filter); | |||||
| } | |||||
| start(): void { | |||||
| setInterval(() => { | |||||
| this.sources.forEach((source) => source.tick(100)); | |||||
| this.filters.forEach((filter) => filter.tick(100)); | |||||
| }, 100); | |||||
| context.resume(); | |||||
| } | |||||
| constructor() { | |||||
| this.filterBus = context.createGain(); | |||||
| } | |||||
| } | |||||
| export abstract class Node { | export abstract class Node { | ||||
| constructor(public name: string) {} | constructor(public name: string) {} | ||||
| } | } | ||||
| @@ -0,0 +1,87 @@ | |||||
| <template> | |||||
| <div class="soundscape"> | |||||
| <source-node | |||||
| v-for="(source, index) in soundscape.sources" | |||||
| :key="index" | |||||
| :source="source" | |||||
| > | |||||
| </source-node> | |||||
| <filter-node | |||||
| v-for="(filter, index) in soundscape.filters" | |||||
| :key="index" | |||||
| :filter="filter" | |||||
| > | |||||
| </filter-node> | |||||
| </div> | |||||
| <div></div> | |||||
| <button v-on:click="clear">Delete all cached sound (if it gets stuck)</button> | |||||
| </template> | |||||
| <script lang="ts"> | |||||
| import { clearCache, Soundscape } from "@/audio"; | |||||
| import { Options, Vue } from "vue-class-component"; | |||||
| import SourceNode from "./nodes/SourceNode.vue"; | |||||
| import FilterNode from "./nodes/FilterNode.vue"; | |||||
| import { Filter } from "@/filters/Filter"; | |||||
| import { BiquadFilter } from "@/filters/LowpassFilter"; | |||||
| import { StereoWidthFilter } from "@/filters/StereoWidthFilter"; | |||||
| import { HighpassFilter } from "@/filters/HighpassFilter"; | |||||
| import * as Sources from "@/sources/PremadeSources"; | |||||
| @Options({ | |||||
| props: { | |||||
| soundscape: Soundscape, | |||||
| }, | |||||
| components: { | |||||
| SourceNode, | |||||
| FilterNode, | |||||
| }, | |||||
| }) | |||||
| export default class SoundscapeComp extends Vue { | |||||
| soundscape!: Soundscape; | |||||
| started = false; | |||||
| context!: AudioContext; | |||||
| clear(): void { | |||||
| clearCache(); | |||||
| } | |||||
| mounted(): void { | |||||
| this.soundscape.addSource(Sources.makeGlorps()); | |||||
| this.soundscape.addSource(Sources.makeDigestion()); | |||||
| this.soundscape.addSource(Sources.makeBurps()); | |||||
| this.soundscape.addSource(Sources.makeGurgles()); | |||||
| const biquad: Filter = new BiquadFilter(); | |||||
| biquad.active = false; | |||||
| this.soundscape.addFilter(biquad); | |||||
| const stereo: Filter = new StereoWidthFilter(); | |||||
| stereo.active = false; | |||||
| this.soundscape.addFilter(stereo); | |||||
| const highpass: Filter = new HighpassFilter(); | |||||
| highpass.active = false; | |||||
| this.soundscape.addFilter(highpass); | |||||
| this.soundscape.start(); | |||||
| console.log(this.soundscape); | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style scoped> | |||||
| .soundscape { | |||||
| margin: auto; | |||||
| padding: 20px; | |||||
| height: 100%; | |||||
| display: grid; | |||||
| grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); | |||||
| grid-auto-rows: 200px; | |||||
| grid-gap: 20px; | |||||
| } | |||||
| .start-button { | |||||
| font-size: 60pt; | |||||
| } | |||||
| </style> | |||||
| @@ -1,211 +0,0 @@ | |||||
| <template> | |||||
| <h1>Dissolve</h1> | |||||
| <div>This is a mega-early-alpha vore audio generator.</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="start" class="start-button" v-if="!started">Start</button> | |||||
| <div class="soundscape"> | |||||
| <source-node | |||||
| v-for="(source, index) in sources" | |||||
| :key="index" | |||||
| :source="source" | |||||
| > | |||||
| </source-node> | |||||
| <filter-node | |||||
| v-for="(filter, index) in filters" | |||||
| :key="index" | |||||
| :filter="filter" | |||||
| > | |||||
| </filter-node> | |||||
| </div> | |||||
| <div></div> | |||||
| <button v-on:click="clear">Delete all cached sound (if it gets stuck)</button> | |||||
| </template> | |||||
| <script lang="ts"> | |||||
| import { clearCache, setup } from "@/audio"; | |||||
| import { Options, Vue } from "vue-class-component"; | |||||
| import Source from "@/sources/Source"; | |||||
| import SourceNode from "./nodes/SourceNode.vue"; | |||||
| import FilterNode from "./nodes/FilterNode.vue"; | |||||
| import LoopingSource from "@/sources/LoopingSource"; | |||||
| import IntervalSource from "@/sources/IntervalSource"; | |||||
| import Filter from "@/filters/Filter"; | |||||
| import BiquadFilter from "@/filters/LowpassFilter"; | |||||
| import StereoWidthFilter from "@/filters/StereoWidthFilter"; | |||||
| import HighpassFilter from "@/filters/HighpassFilter"; | |||||
| @Options({ | |||||
| props: { | |||||
| msg: String, | |||||
| }, | |||||
| components: { | |||||
| SourceNode, | |||||
| FilterNode, | |||||
| }, | |||||
| }) | |||||
| export default class VoreAudio extends Vue { | |||||
| started = false; | |||||
| context!: AudioContext; | |||||
| sources: Array<Source> = []; | |||||
| filters: Array<Filter> = []; | |||||
| filterBus!: GainNode; | |||||
| addSource(source: Source): void { | |||||
| source.output.connect(this.filterBus); | |||||
| this.sources.push(source); | |||||
| source.start(); | |||||
| } | |||||
| addFilter(filter: Filter): void { | |||||
| if (this.filters.length > 0) { | |||||
| const last: Filter = this.filters[this.filters.length - 1]; | |||||
| last.output.disconnect(); | |||||
| last.output.connect(filter.input); | |||||
| filter.output.connect(this.context.destination); | |||||
| } else { | |||||
| this.filterBus.disconnect(); | |||||
| this.filterBus.connect(filter.input); | |||||
| filter.output.connect(this.context.destination); | |||||
| } | |||||
| filter.start(); | |||||
| this.filters.push(filter); | |||||
| } | |||||
| startGlorps(): void { | |||||
| const source: Source = new IntervalSource("Guts", 5, 8); | |||||
| source.loadSound("bowels-to-intestines"); | |||||
| source.loadSound("intestines-to-bowels"); | |||||
| source.loadSound("intestines-to-stomach"); | |||||
| source.loadSound("intestines-to-stomach-forced"); | |||||
| source.loadSound("stomach-to-intestines"); | |||||
| source.loadSound("stomach-to-intestines-fail"); | |||||
| source.loadSound("stomach-churn"); | |||||
| source.loadSound("bowels-churn-safe"); | |||||
| source.loadSound("bowels-churn-danger"); | |||||
| source.active = false; | |||||
| this.addSource(source); | |||||
| } | |||||
| startDigestion(): void { | |||||
| const source: Source = new LoopingSource("Digestion"); | |||||
| source.loadSound("fen-stomach"); | |||||
| source.loadSound("fen-intestines"); | |||||
| source.loadSound("fen-bowels"); | |||||
| this.addSource(source); | |||||
| } | |||||
| startBurps(): void { | |||||
| const source: Source = new IntervalSource("Burps", 5, 15); | |||||
| source.loadSound("belch (1)"); | |||||
| source.loadSound("belch (2)"); | |||||
| source.loadSound("belch (3)"); | |||||
| source.loadSound("belch (4)"); | |||||
| source.loadSound("belch (5)"); | |||||
| source.loadSound("belch (6)"); | |||||
| source.loadSound("belch (7)"); | |||||
| source.loadSound("belch (8)"); | |||||
| source.loadSound("belch (9)"); | |||||
| source.loadSound("belch (10)"); | |||||
| source.loadSound("belch (11)"); | |||||
| source.loadSound("belch (12)"); | |||||
| source.loadSound("belch (13)"); | |||||
| source.loadSound("belch (14)"); | |||||
| source.loadSound("belch (15)"); | |||||
| source.loadSound("belch (16)"); | |||||
| source.active = false; | |||||
| this.addSource(source); | |||||
| } | |||||
| startGurgles(): void { | |||||
| const source: Source = new IntervalSource("Gurgles", 3, 10); | |||||
| source.loadSound("gurgles/gurgle (1)"); | |||||
| source.loadSound("gurgles/gurgle (2)"); | |||||
| source.loadSound("gurgles/gurgle (3)"); | |||||
| source.loadSound("gurgles/gurgle (4)"); | |||||
| source.loadSound("gurgles/gurgle (5)"); | |||||
| source.loadSound("gurgles/gurgle (6)"); | |||||
| source.loadSound("gurgles/gurgle (7)"); | |||||
| source.loadSound("gurgles/gurgle (8)"); | |||||
| source.loadSound("gurgles/gurgle (9)"); | |||||
| source.loadSound("gurgles/gurgle (10)"); | |||||
| source.loadSound("gurgles/gurgle (11)"); | |||||
| source.loadSound("gurgles/gurgle (12)"); | |||||
| source.loadSound("gurgles/gurgle (13)"); | |||||
| source.loadSound("gurgles/gurgle (14)"); | |||||
| source.loadSound("gurgles/gurgle (15)"); | |||||
| source.loadSound("gurgles/gurgle (16)"); | |||||
| source.loadSound("gurgles/gurgle (17)"); | |||||
| source.loadSound("gurgles/gurgle (18)"); | |||||
| source.loadSound("gurgles/gurgle (19)"); | |||||
| source.loadSound("gurgles/gurgle (20)"); | |||||
| source.loadSound("gurgles/gurgle (21)"); | |||||
| this.addSource(source); | |||||
| } | |||||
| clear(): void { | |||||
| clearCache(); | |||||
| } | |||||
| start(): void { | |||||
| this.context.resume(); | |||||
| if (this.started) { | |||||
| return; | |||||
| } | |||||
| this.started = true; | |||||
| this.startGlorps(); | |||||
| this.startGurgles(); | |||||
| this.startDigestion(); | |||||
| this.startBurps(); | |||||
| const biquad: Filter = new BiquadFilter(); | |||||
| biquad.active = false; | |||||
| this.addFilter(biquad); | |||||
| const stereo: Filter = new StereoWidthFilter(); | |||||
| stereo.active = false; | |||||
| this.addFilter(stereo); | |||||
| const highpass: Filter = new HighpassFilter(); | |||||
| highpass.active = false; | |||||
| this.addFilter(highpass); | |||||
| setInterval(() => { | |||||
| this.sources.forEach((source) => source.tick(100)); | |||||
| this.filters.forEach((filter) => filter.tick(100)); | |||||
| }, 100); | |||||
| } | |||||
| mounted(): void { | |||||
| this.context = setup(); | |||||
| this.filterBus = this.context.createGain(); | |||||
| this.filterBus.connect(this.context.destination); | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style scoped> | |||||
| .soundscape { | |||||
| margin: auto; | |||||
| padding: 20px; | |||||
| width: minmax(50vw, 1500px); | |||||
| height: 100%; | |||||
| display: grid; | |||||
| grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); | |||||
| grid-auto-rows: 200px; | |||||
| grid-gap: 20px; | |||||
| } | |||||
| .start-button { | |||||
| font-size: 60pt; | |||||
| } | |||||
| </style> | |||||
| @@ -7,7 +7,7 @@ | |||||
| </template> | </template> | ||||
| <script lang="ts"> | <script lang="ts"> | ||||
| import Filter from "@/filters/Filter"; | |||||
| import { Filter } from "@/filters/Filter"; | |||||
| import { Options, Vue } from "vue-class-component"; | import { Options, Vue } from "vue-class-component"; | ||||
| import NodeProps from "@/components/NodeProps.vue"; | import NodeProps from "@/components/NodeProps.vue"; | ||||
| @@ -7,7 +7,7 @@ | |||||
| </template> | </template> | ||||
| <script lang="ts"> | <script lang="ts"> | ||||
| import Source from "@/sources/Source"; | |||||
| import { Source } from "@/sources/Source"; | |||||
| import { Options, Vue } from "vue-class-component"; | import { Options, Vue } from "vue-class-component"; | ||||
| import NodeProps from "@/components/NodeProps.vue"; | import NodeProps from "@/components/NodeProps.vue"; | ||||
| import Toggle from "@vueform/toggle"; | import Toggle from "@vueform/toggle"; | ||||
| @@ -15,7 +15,7 @@ import Toggle from "@vueform/toggle"; | |||||
| @Options({ | @Options({ | ||||
| props: { | props: { | ||||
| source: Source, | source: Source, | ||||
| }, | |||||
| }, | |||||
| components: { | components: { | ||||
| NodeProps, | NodeProps, | ||||
| Toggle, | Toggle, | ||||
| @@ -1,6 +1,6 @@ | |||||
| import { Node, context } from "../audio"; | import { Node, context } from "../audio"; | ||||
| export default abstract class Filter extends Node { | |||||
| export abstract class Filter extends Node { | |||||
| public abstract kind: string; | public abstract kind: string; | ||||
| public input: GainNode; | public input: GainNode; | ||||
| protected filterInput: GainNode; | protected filterInput: GainNode; | ||||
| @@ -1,6 +1,6 @@ | |||||
| import Filter from "./Filter"; | |||||
| import { Filter } from "./Filter"; | |||||
| import { context, exposedNumber } from "../audio"; | import { context, exposedNumber } from "../audio"; | ||||
| export default class HighpassFilter extends Filter { | |||||
| export class HighpassFilter extends Filter { | |||||
| public kind = "Biquad Filter"; | public kind = "Biquad Filter"; | ||||
| private biquad: BiquadFilterNode; | private biquad: BiquadFilterNode; | ||||
| @@ -1,6 +1,6 @@ | |||||
| import Filter from "./Filter"; | |||||
| import { Filter } from "./Filter"; | |||||
| import { context, exposedNumber } from "../audio"; | import { context, exposedNumber } from "../audio"; | ||||
| export default class BiquadFilter extends Filter { | |||||
| export class BiquadFilter extends Filter { | |||||
| public kind = "Biquad Filter"; | public kind = "Biquad Filter"; | ||||
| private biquad: BiquadFilterNode; | private biquad: BiquadFilterNode; | ||||
| @@ -1,6 +1,6 @@ | |||||
| import Filter from "./Filter"; | |||||
| import { Filter } from "./Filter"; | |||||
| import { context, exposedNumber } from "../audio"; | import { context, exposedNumber } from "../audio"; | ||||
| export default class StereoWidthFilter extends Filter { | |||||
| export class StereoWidthFilter extends Filter { | |||||
| public kind = "Stereo Width"; | public kind = "Stereo Width"; | ||||
| private mono: GainNode; | private mono: GainNode; | ||||
| private stereo: GainNode; | private stereo: GainNode; | ||||
| @@ -1,4 +1,4 @@ | |||||
| import { createApp } from "vue"; | import { createApp } from "vue"; | ||||
| import App from "./App.vue"; | |||||
| import Dissolve from "./Dissolve.vue"; | |||||
| createApp(App).mount("#app"); | |||||
| createApp(Dissolve).mount("#app"); | |||||
| @@ -1,7 +1,7 @@ | |||||
| import Source from "./Source"; | |||||
| import { Source } from "./Source"; | |||||
| import { exposedRange, context } from "../audio"; | import { exposedRange, context } from "../audio"; | ||||
| export default class IntervalSource extends Source { | |||||
| export class IntervalSource extends Source { | |||||
| kind = "Interval"; | kind = "Interval"; | ||||
| @exposedRange("Interval", 0.25, 30) | @exposedRange("Interval", 0.25, 30) | ||||
| @@ -1,7 +1,7 @@ | |||||
| import Source from "./Source"; | |||||
| import { Source } from "./Source"; | |||||
| import { context } from "../audio"; | import { context } from "../audio"; | ||||
| export default class LoopingSource extends Source { | |||||
| export class LoopingSource extends Source { | |||||
| kind = "Looping"; | kind = "Looping"; | ||||
| private source!: AudioBufferSourceNode; | private source!: AudioBufferSourceNode; | ||||
| private started = false; | private started = false; | ||||
| @@ -0,0 +1,78 @@ | |||||
| import { IntervalSource } from "./IntervalSource"; | |||||
| import { LoopingSource } from "./LoopingSource"; | |||||
| import { Source } from "./Source"; | |||||
| export function makeGlorps(): Source { | |||||
| const source: Source = new IntervalSource("Guts", 5, 8); | |||||
| source.loadSound("bowels-to-intestines"); | |||||
| source.loadSound("intestines-to-bowels"); | |||||
| source.loadSound("intestines-to-stomach"); | |||||
| source.loadSound("intestines-to-stomach-forced"); | |||||
| source.loadSound("stomach-to-intestines"); | |||||
| source.loadSound("stomach-to-intestines-fail"); | |||||
| source.loadSound("stomach-churn"); | |||||
| source.loadSound("bowels-churn-safe"); | |||||
| source.loadSound("bowels-churn-danger"); | |||||
| return source; | |||||
| } | |||||
| export function makeDigestion(): Source { | |||||
| const source: Source = new LoopingSource("Digestion"); | |||||
| source.loadSound("fen-stomach"); | |||||
| source.loadSound("fen-intestines"); | |||||
| source.loadSound("fen-bowels"); | |||||
| return source; | |||||
| } | |||||
| export function makeBurps(): Source { | |||||
| const source: Source = new IntervalSource("Burps", 5, 15); | |||||
| source.loadSound("belch (1)"); | |||||
| source.loadSound("belch (2)"); | |||||
| source.loadSound("belch (3)"); | |||||
| source.loadSound("belch (4)"); | |||||
| source.loadSound("belch (5)"); | |||||
| source.loadSound("belch (6)"); | |||||
| source.loadSound("belch (7)"); | |||||
| source.loadSound("belch (8)"); | |||||
| source.loadSound("belch (9)"); | |||||
| source.loadSound("belch (10)"); | |||||
| source.loadSound("belch (11)"); | |||||
| source.loadSound("belch (12)"); | |||||
| source.loadSound("belch (13)"); | |||||
| source.loadSound("belch (14)"); | |||||
| source.loadSound("belch (15)"); | |||||
| source.loadSound("belch (16)"); | |||||
| source.active = false; | |||||
| return source; | |||||
| } | |||||
| export function makeGurgles(): Source { | |||||
| const source: Source = new IntervalSource("Gurgles", 3, 10); | |||||
| source.loadSound("gurgles/gurgle (1)"); | |||||
| source.loadSound("gurgles/gurgle (2)"); | |||||
| source.loadSound("gurgles/gurgle (3)"); | |||||
| source.loadSound("gurgles/gurgle (4)"); | |||||
| source.loadSound("gurgles/gurgle (5)"); | |||||
| source.loadSound("gurgles/gurgle (6)"); | |||||
| source.loadSound("gurgles/gurgle (7)"); | |||||
| source.loadSound("gurgles/gurgle (8)"); | |||||
| source.loadSound("gurgles/gurgle (9)"); | |||||
| source.loadSound("gurgles/gurgle (10)"); | |||||
| source.loadSound("gurgles/gurgle (11)"); | |||||
| source.loadSound("gurgles/gurgle (12)"); | |||||
| source.loadSound("gurgles/gurgle (13)"); | |||||
| source.loadSound("gurgles/gurgle (14)"); | |||||
| source.loadSound("gurgles/gurgle (15)"); | |||||
| source.loadSound("gurgles/gurgle (16)"); | |||||
| source.loadSound("gurgles/gurgle (17)"); | |||||
| source.loadSound("gurgles/gurgle (18)"); | |||||
| source.loadSound("gurgles/gurgle (19)"); | |||||
| source.loadSound("gurgles/gurgle (20)"); | |||||
| source.loadSound("gurgles/gurgle (21)"); | |||||
| return source; | |||||
| } | |||||
| @@ -1,6 +1,6 @@ | |||||
| import { Node, context, exposedNumber, loadAudio } from "../audio"; | import { Node, context, exposedNumber, loadAudio } from "../audio"; | ||||
| export default abstract class Source extends Node { | |||||
| export abstract class Source extends Node { | |||||
| public abstract kind: string; | public abstract kind: string; | ||||
| public sounds: Array<AudioBuffer> = []; | public sounds: Array<AudioBuffer> = []; | ||||
| public gain: GainNode; | public gain: GainNode; | ||||