瀏覽代碼

Move the lists of sources and filters into a Soundscape

Also goes back to avoiding default-export where possible
master
Fen Dweller 4 年之前
父節點
當前提交
8b3d699f25
共有 16 個文件被更改,包括 287 次插入262 次删除
  1. +0
    -33
      src/App.vue
  2. +63
    -0
      src/Dissolve.vue
  3. +42
    -1
      src/audio.ts
  4. +87
    -0
      src/components/SoundscapeComp.vue
  5. +0
    -211
      src/components/VoreAudio.vue
  6. +1
    -1
      src/components/nodes/FilterNode.vue
  7. +2
    -2
      src/components/nodes/SourceNode.vue
  8. +1
    -1
      src/filters/Filter.ts
  9. +2
    -2
      src/filters/HighpassFilter.ts
  10. +2
    -2
      src/filters/LowpassFilter.ts
  11. +2
    -2
      src/filters/StereoWidthFilter.ts
  12. +2
    -2
      src/main.ts
  13. +2
    -2
      src/sources/IntervalSource.ts
  14. +2
    -2
      src/sources/LoopingSource.ts
  15. +78
    -0
      src/sources/PremadeSources.ts
  16. +1
    -1
      src/sources/Source.ts

+ 0
- 33
src/App.vue 查看文件

@@ -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>

+ 63
- 0
src/Dissolve.vue 查看文件

@@ -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>

+ 42
- 1
src/audio.ts 查看文件

@@ -1,8 +1,49 @@
import "reflect-metadata";
import Source from "./sources/Source";
import { Filter } from "./filters/Filter";
import { Source } from "./sources/Source";

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 {
constructor(public name: string) {}
}


+ 87
- 0
src/components/SoundscapeComp.vue 查看文件

@@ -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>

+ 0
- 211
src/components/VoreAudio.vue 查看文件

@@ -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>

+ 1
- 1
src/components/nodes/FilterNode.vue 查看文件

@@ -7,7 +7,7 @@
</template>

<script lang="ts">
import Filter from "@/filters/Filter";
import { Filter } from "@/filters/Filter";

import { Options, Vue } from "vue-class-component";
import NodeProps from "@/components/NodeProps.vue";


+ 2
- 2
src/components/nodes/SourceNode.vue 查看文件

@@ -7,7 +7,7 @@
</template>

<script lang="ts">
import Source from "@/sources/Source";
import { Source } from "@/sources/Source";
import { Options, Vue } from "vue-class-component";
import NodeProps from "@/components/NodeProps.vue";
import Toggle from "@vueform/toggle";
@@ -15,7 +15,7 @@ import Toggle from "@vueform/toggle";
@Options({
props: {
source: Source,
},
},
components: {
NodeProps,
Toggle,


+ 1
- 1
src/filters/Filter.ts 查看文件

@@ -1,6 +1,6 @@
import { Node, context } from "../audio";

export default abstract class Filter extends Node {
export abstract class Filter extends Node {
public abstract kind: string;
public input: GainNode;
protected filterInput: GainNode;


+ 2
- 2
src/filters/HighpassFilter.ts 查看文件

@@ -1,6 +1,6 @@
import Filter from "./Filter";
import { Filter } from "./Filter";
import { context, exposedNumber } from "../audio";
export default class HighpassFilter extends Filter {
export class HighpassFilter extends Filter {
public kind = "Biquad Filter";
private biquad: BiquadFilterNode;



+ 2
- 2
src/filters/LowpassFilter.ts 查看文件

@@ -1,6 +1,6 @@
import Filter from "./Filter";
import { Filter } from "./Filter";
import { context, exposedNumber } from "../audio";
export default class BiquadFilter extends Filter {
export class BiquadFilter extends Filter {
public kind = "Biquad Filter";
private biquad: BiquadFilterNode;



+ 2
- 2
src/filters/StereoWidthFilter.ts 查看文件

@@ -1,6 +1,6 @@
import Filter from "./Filter";
import { Filter } from "./Filter";
import { context, exposedNumber } from "../audio";
export default class StereoWidthFilter extends Filter {
export class StereoWidthFilter extends Filter {
public kind = "Stereo Width";
private mono: GainNode;
private stereo: GainNode;


+ 2
- 2
src/main.ts 查看文件

@@ -1,4 +1,4 @@
import { createApp } from "vue";
import App from "./App.vue";
import Dissolve from "./Dissolve.vue";

createApp(App).mount("#app");
createApp(Dissolve).mount("#app");

+ 2
- 2
src/sources/IntervalSource.ts 查看文件

@@ -1,7 +1,7 @@
import Source from "./Source";
import { Source } from "./Source";
import { exposedRange, context } from "../audio";

export default class IntervalSource extends Source {
export class IntervalSource extends Source {
kind = "Interval";

@exposedRange("Interval", 0.25, 30)


+ 2
- 2
src/sources/LoopingSource.ts 查看文件

@@ -1,7 +1,7 @@
import Source from "./Source";
import { Source } from "./Source";
import { context } from "../audio";

export default class LoopingSource extends Source {
export class LoopingSource extends Source {
kind = "Looping";
private source!: AudioBufferSourceNode;
private started = false;


+ 78
- 0
src/sources/PremadeSources.ts 查看文件

@@ -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
- 1
src/sources/Source.ts 查看文件

@@ -1,6 +1,6 @@
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 sounds: Array<AudioBuffer> = [];
public gain: GainNode;


Loading…
取消
儲存