Ver código fonte

Switch to premade SoundSets

master
Fen Dweller 4 anos atrás
pai
commit
4172de5a07
9 arquivos alterados com 117 adições e 175 exclusões
  1. +35
    -19
      src/audio.ts
  2. +6
    -14
      src/components/Menu.vue
  3. +19
    -13
      src/components/SoundscapeComp.vue
  4. +13
    -1
      src/components/nodes/SourceNode.vue
  5. +15
    -0
      src/data/sound-sets.ts
  6. +4
    -2
      src/sources/IntervalSource.ts
  7. +3
    -3
      src/sources/LoopingSource.ts
  8. +0
    -114
      src/sources/PremadeSources.ts
  9. +22
    -9
      src/sources/Source.ts

+ 35
- 19
src/audio.ts Ver arquivo

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

let ogg_support = false;

@@ -18,6 +18,19 @@ export class Soundscape {
source.start();
}

removeSource(source: Source): void {
if (this.sources.includes(source)) {
source.output.disconnect();
this.sources = this.sources.filter((x) => x !== source);
} else {
console.warn(
"Tried to remove a source from a Soundscape that wasn't using it"
);
console.warn(this);
console.warn(source);
}
}

addFilter(filter: Filter): void {
if (this.filters.length > 0) {
const last: Filter = this.filters[this.filters.length - 1];
@@ -90,7 +103,7 @@ export let context: AudioContext;

const audioBaseUrl = "/audio/";

const waiting: Map<string, Array<Source>> = new Map();
const waiting: Map<string, Array<SoundSet>> = new Map();
const audioDict: Map<string, AudioBuffer> = new Map();

// decide if we can load oggs
@@ -100,28 +113,31 @@ export function audioTest(): void {
}
// asynchronously load an audio file

export function loadAudio(name: string, source: Source, flush = false): void {
export function loadAudio(name: string, client: SoundSet, flush = false): void {
// pick a format

name += ogg_support ? ".ogg" : ".mp3";
// 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);
if (buf !== undefined) client.loadSound(name, buf);

return;
}

// are we already trying to get the audio?

if (!waiting.has(name)) {
waiting.set(name, []);
}

const list: Array<SoundSet> | undefined = waiting.get(name);

if (list !== undefined) list.push(client);

// is the audio already stored locally?

if (!flush) {
@@ -139,14 +155,14 @@ function cacheAndParse(name: string, data: ArrayBuffer) {
function parseAudioData(name: string, data: ArrayBuffer) {
context.decodeAudioData(
data,
function (buffer) {
audioDict.set(name, buffer);
function (buf) {
audioDict.set(name, buf);

const waitingSources: Array<Source> | undefined = waiting.get(name);
const waitingClients: Array<SoundSet> | undefined = waiting.get(name);

if (waitingSources !== undefined) {
waitingSources.forEach((source) => {
source.addLoadedSound(buffer);
if (waitingClients !== undefined) {
waitingClients.forEach((client) => {
client.loadSound(name, buf);
});
}
},


+ 6
- 14
src/components/Menu.vue Ver arquivo

@@ -1,11 +1,11 @@
<template>
<div id="menu">
<div class="list-label">Sources</div>
<div class="list-label">Sounds</div>
<div class="list">
<draggable
v-for="(source, index) in sourceTypes"
v-for="(source, index) in soundSets"
:key="index"
:label="source"
:label="source.name"
/>
</div>
</div>
@@ -14,6 +14,8 @@
<script lang="ts">
import { Options, Vue } from "vue-class-component";
import Draggable from "@/components/Draggable.vue";
import * as SoundSets from "@/data/sound-sets";
import { SoundSet } from "@/sources/Source";

@Options({
components: {
@@ -21,17 +23,7 @@ import Draggable from "@/components/Draggable.vue";
},
})
export default class Menu extends Vue {
sourceTypes = [
"Rumble",
"Glorps",
"Heartbeat",
"Breathing",
"Squishing",
"Burps",
"Gurgles",
];

foo = 3;
soundSets: Array<SoundSet> = Array.from(Object.values(SoundSets));
}
</script>



+ 19
- 13
src/components/SoundscapeComp.vue Ver arquivo

@@ -4,6 +4,7 @@
v-for="(source, index) in soundscape.sources"
:key="index"
:source="source"
v-on:delete="deleteSource(source)"
>
</source-node>
<source-node
@@ -26,8 +27,10 @@ import { Soundscape } from "@/audio";
import { Options, Vue } from "vue-class-component";
import SourceNode from "./nodes/SourceNode.vue";
import FilterNode from "./nodes/FilterNode.vue";
import * as Sources from "@/sources/PremadeSources";
import { Source } from "@/sources/Source";
import * as SoundSets from "@/data/sound-sets";
import { SoundSet, Source } from "@/sources/Source";
import { IntervalSource } from "@/sources/IntervalSource";
import { LoopingSource } from "@/sources/LoopingSource";

@Options({
props: {
@@ -42,16 +45,11 @@ export default class SoundscapeComp extends Vue {
soundscape!: Soundscape;
started = false;
context!: AudioContext;

makers: Record<string, () => Source> = {
Gurgles: Sources.makeGurgles,
Burps: Sources.makeBurps,
Glorps: Sources.makeGlorps,
Squishing: Sources.makeSquishing,
Heartbeat: Sources.makeHeartbeat,
Breathing: Sources.makeBreathing,
Rumble: Sources.makeRumble,
sources: { [key: string]: new (name: string) => Source } = {
IntervalSource: IntervalSource,
LoopingSource: LoopingSource,
};
soundSets: { [key: string]: SoundSet } = SoundSets;

drag(ev: DragEvent): void {
ev.preventDefault();
@@ -63,11 +61,19 @@ export default class SoundscapeComp extends Vue {
if (event.dataTransfer) {
const label = event.dataTransfer.getData("text/plain");

console.log(this.makers[label])
this.soundscape.addSource(this.makers[label]());
const soundSet = this.soundSets[label];

const source = new this.sources[soundSet.defaultSource](soundSet.name);
source.soundSet = soundSet;
this.soundscape.addSource(source);
// TODO
}
}

deleteSource(source: Source): void {
this.soundscape.removeSource(source);
}

mounted(): void {
this.soundscape.start();
}


+ 13
- 1
src/components/nodes/SourceNode.vue Ver arquivo

@@ -5,7 +5,8 @@
:class="source.active ? '' : 'inactive'"
class="source-node"
>
<Toggle class="active-toggle" v-model="source.active" />
<button class="delete-button" v-on:click="$emit('delete')">X</button>
<toggle class="active-toggle" v-model="source.active" />
<div class="node-name">{{ source.name }}</div>
<node-props :node="source"></node-props>
</div>
@@ -28,9 +29,11 @@ import Toggle from "@vueform/toggle";
NodeProps,
Toggle,
},
emits: ["delete"],
})
export default class SourceNode extends Vue {
source!: Source;
dummy = false;
}
</script>

@@ -69,4 +72,13 @@ export default class SourceNode extends Vue {
.dummy {
min-height: 200px;
}

.delete-button {
position: absolute;
top: 5px;
right: 5px;
width: 25px;
height: 25px;
font-size: 24px;
}
</style>

+ 15
- 0
src/data/sound-sets.ts Ver arquivo

@@ -0,0 +1,15 @@
import { SoundSet } from "@/sources/Source";

export const Gurgles: SoundSet = new SoundSet(
"Gurgles",
Array(21)
.fill(0)
.map((x, i) => "gurgles/gurgle (" + (i + 1) + ")"),
"IntervalSource"
);

export const Squishing: SoundSet = new SoundSet(
"Squishing",
["squishing"],
"LoopingSource"
);

+ 4
- 2
src/sources/IntervalSource.ts Ver arquivo

@@ -71,11 +71,13 @@ export class IntervalSource extends Source {
if (this.started) {
this.remaining -= dt;
if (this.remaining <= 0) {
const index = Math.floor(Math.random() * this.sounds.length);
const index = Math.floor(
Math.random() * this.soundSet.soundList.length
);

const node = context.createBufferSource();

node.buffer = this.sounds[index];
node.buffer = this.soundSet.soundList[index];

const pan = context.createStereoPanner();
pan.pan.value =


+ 3
- 3
src/sources/LoopingSource.ts Ver arquivo

@@ -26,9 +26,9 @@ export class LoopingSource extends Source {
}

private pickRandom(): void {
const index = Math.floor(Math.random() * this.sounds.length);
const index = Math.floor(Math.random() * this.soundSet.soundList.length);
this.source = context.createBufferSource();
this.source.buffer = this.sounds[index];
this.source.buffer = this.soundSet.soundList[index];
this.source.connect(this.gain);
this.source.onended = () => {
this.pickRandom();
@@ -37,7 +37,7 @@ export class LoopingSource extends Source {
}
public tick(dt: number): void {
super.tick(dt);
if (this.started && this.sounds.length > 0 && !this.running) {
if (this.started && this.soundSet.soundList.length > 0 && !this.running) {
this.pickRandom();
this.source.start();
this.running = true;


+ 0
- 114
src/sources/PremadeSources.ts Ver arquivo

@@ -1,114 +0,0 @@
import { IntervalSource } from "./IntervalSource";
import { LoopingSource } from "./LoopingSource";
import { Source } from "./Source";

export function makeGlorps(): Source {
const source: IntervalSource = new IntervalSource("Guts");
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");

console.log(source);

source.interval = [4, 8];
source.pitch = [0.75, 1.25];

return source;
}

export function makeBurps(): Source {
const source: IntervalSource = new IntervalSource("Burps");
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.interval = [10, 30];

source.pitch = [0.8, 1.1];

source.active = false;

return source;
}

export function makeGurgles(): Source {
const source: IntervalSource = new IntervalSource("Gurgles");
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)");

source.pitch = [0.6, 1.2];
source.interval = [2, 10];
source.panning = [-0.6, 0.6];
return source;
}

export function makeHeartbeat(): LoopingSource {
const source: LoopingSource = new LoopingSource("Heartbeat");

source.loadSound("heartbeat");
source.volume = 0.3;

return source;
}

export function makeBreathing(): LoopingSource {
const source: LoopingSource = new LoopingSource("Breathing");

source.loadSound("breaths");

return source;
}

export function makeRumble(): LoopingSource {
const source: LoopingSource = new LoopingSource("Rumble");

source.loadSound("rumble");

return source;
}

export function makeSquishing(): LoopingSource {
const source: LoopingSource = new LoopingSource("Squishing");

source.loadSound("squishing");

return source;
}

+ 22
- 9
src/sources/Source.ts Ver arquivo

@@ -1,8 +1,28 @@
import { Node, context, exposedNumber, loadAudio } from "../audio";

export class SoundSet {
soundMap: Map<string, AudioBuffer> = new Map();
soundList: Array<AudioBuffer> = [];

constructor(
public name: string,
public soundKeys: Array<string>,
public defaultSource: string
) {
this.soundKeys.forEach((sound) => {
loadAudio(sound, this);
});
}

public loadSound(name: string, buf: AudioBuffer): void {
this.soundList.push(buf);
this.soundMap.set(name, buf);
}
}

export abstract class Source extends Node {
public abstract kind: string;
public sounds: Array<AudioBuffer> = [];
public soundSet: SoundSet = new SoundSet("Empty", [], "IntervalSource");
public gain: GainNode;
public output: GainNode;
public _active = true;
@@ -35,16 +55,9 @@ export abstract class Source extends Node {
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;

// eslint-disable-next-line @typescript-eslint/no-unused-vars
public tick(dt: number): void {
this.gain.gain.value = this.volume;
}


Carregando…
Cancelar
Salvar