| @@ -1,13 +1,15 @@ | |||||
| <template> | <template> | ||||
| <div id="app-area"> | <div id="app-area"> | ||||
| <Menu /> | <Menu /> | ||||
| <button v-if="!started" v-on:click="start">Start</button> | |||||
| <div id="soundscapes"> | |||||
| <div v-if="started" id="soundscapes"> | |||||
| <SoundscapeComp | <SoundscapeComp | ||||
| v-for="(soundscape, index) in soundscapes" | v-for="(soundscape, index) in soundscapes" | ||||
| :key="index" | :key="index" | ||||
| :soundscape="soundscape" | :soundscape="soundscape" | ||||
| /> | /> | ||||
| <button v-on:click="newSoundscape">Add soundscape...</button> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </template> | </template> | ||||
| @@ -17,6 +19,8 @@ import { Options, Vue } from "vue-class-component"; | |||||
| import { clearCache, setup, Soundscape } from "./audio"; | import { clearCache, setup, Soundscape } from "./audio"; | ||||
| import SoundscapeComp from "./components/SoundscapeComp.vue"; | import SoundscapeComp from "./components/SoundscapeComp.vue"; | ||||
| import Menu from "./components/Menu.vue"; | import Menu from "./components/Menu.vue"; | ||||
| import { DemoScene } from "./data/presets"; | |||||
| import { deserializeSoundscape } from "./serialize"; | |||||
| @Options({ | @Options({ | ||||
| components: { | components: { | ||||
| SoundscapeComp, | SoundscapeComp, | ||||
| @@ -28,19 +32,22 @@ export default class Dissolve extends Vue { | |||||
| started = false; | started = false; | ||||
| soundscapes: Array<Soundscape> = []; | soundscapes: Array<Soundscape> = []; | ||||
| newSoundscape(): void { | |||||
| this.addSoundscape(new Soundscape()); | |||||
| } | |||||
| addSoundscape(scape: Soundscape): void { | addSoundscape(scape: Soundscape): void { | ||||
| scape.output.connect(this.context.destination); | scape.output.connect(this.context.destination); | ||||
| this.soundscapes.push(scape); | this.soundscapes.push(scape); | ||||
| } | } | ||||
| start(): void { | |||||
| this.started = true; | |||||
| } | |||||
| mounted(): void { | mounted(): void { | ||||
| this.context = setup(); | this.context = setup(); | ||||
| this.addSoundscape(new Soundscape()); | |||||
| DemoScene.forEach((scapeData) => { | |||||
| const scape = deserializeSoundscape(scapeData); | |||||
| this.addSoundscape(scape); | |||||
| }); | |||||
| this.started = true; | |||||
| } | } | ||||
| clear(): void { | clear(): void { | ||||
| @@ -296,11 +296,9 @@ function createCache(): void { | |||||
| const idb = window.indexedDB; | const idb = window.indexedDB; | ||||
| const req = idb.open("cache", 1); | const req = idb.open("cache", 1); | ||||
| console.log("Create cache"); | |||||
| req.onupgradeneeded = (event) => { | req.onupgradeneeded = (event) => { | ||||
| const db = req.result; | const db = req.result; | ||||
| console.log("Version change"); | |||||
| if (event.oldVersion > 0) { | if (event.oldVersion > 0) { | ||||
| db.deleteObjectStore("audio"); | db.deleteObjectStore("audio"); | ||||
| } | } | ||||
| @@ -308,8 +306,6 @@ function createCache(): void { | |||||
| db.createObjectStore("audio", { keyPath: ["name"] }); | db.createObjectStore("audio", { keyPath: ["name"] }); | ||||
| }; | }; | ||||
| console.log(req); | |||||
| req.onerror = () => { | req.onerror = () => { | ||||
| alert("Couldn't open the database?"); | alert("Couldn't open the database?"); | ||||
| }; | }; | ||||
| @@ -16,6 +16,10 @@ | |||||
| :node="source" | :node="source" | ||||
| /> | /> | ||||
| </div> | </div> | ||||
| <div class="list-label">Presets</div> | |||||
| <div class="list"> | |||||
| <button v-on:click="$emit('demo')">Demo</button> | |||||
| </div> | |||||
| </div> | </div> | ||||
| </template> | </template> | ||||
| @@ -51,7 +55,7 @@ export default class Menu extends Vue { | |||||
| .list { | .list { | ||||
| display: grid; | display: grid; | ||||
| grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); | |||||
| grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); | |||||
| grid-auto-rows: minmax(max-content, 1fr); | grid-auto-rows: minmax(max-content, 1fr); | ||||
| background: #777; | background: #777; | ||||
| } | } | ||||
| @@ -104,8 +104,6 @@ export default class SoundscapeComp extends Vue { | |||||
| mounted(): void { | mounted(): void { | ||||
| this.soundscape.start(); | this.soundscape.start(); | ||||
| console.log(this.soundscape); | |||||
| } | } | ||||
| } | } | ||||
| </script> | </script> | ||||
| @@ -35,10 +35,57 @@ export const PresetSources: Array<{ | |||||
| volume: 1, | volume: 1, | ||||
| interval: [4, 6], | interval: [4, 6], | ||||
| pitch: [0.9, 1.1], | pitch: [0.9, 1.1], | ||||
| panning: [-0.2, 0.2], | |||||
| panning: [-0.7, 0.7], | |||||
| name: "Gurgles", | name: "Gurgles", | ||||
| type: "IntervalSource", | type: "IntervalSource", | ||||
| }, | }, | ||||
| { | |||||
| soundSet: { | |||||
| name: "Burps", | |||||
| soundKeys: [ | |||||
| "belch (1)", | |||||
| "belch (2)", | |||||
| "belch (3)", | |||||
| "belch (4)", | |||||
| "belch (5)", | |||||
| "belch (6)", | |||||
| "belch (7)", | |||||
| "belch (8)", | |||||
| "belch (9)", | |||||
| "belch (10)", | |||||
| "belch (11)", | |||||
| "belch (12)", | |||||
| "belch (13)", | |||||
| "belch (14)", | |||||
| "belch (15)", | |||||
| ], | |||||
| }, | |||||
| kind: "source", | |||||
| volume: 1, | |||||
| interval: [15, 45], | |||||
| pitch: [0.7, 1.1], | |||||
| panning: [-0.1, 0.1], | |||||
| name: "Burps", | |||||
| type: "IntervalSource", | |||||
| }, | |||||
| { | |||||
| soundSet: { | |||||
| name: "Guts", | |||||
| soundKeys: [ | |||||
| "stomach-churn", | |||||
| "intestines-to-bowels", | |||||
| "intestines-to-stomach", | |||||
| "intestines-to-stomach-forced", | |||||
| ], | |||||
| }, | |||||
| kind: "source", | |||||
| volume: 1, | |||||
| interval: [7, 15], | |||||
| pitch: [0.7, 1.1], | |||||
| panning: [-0.5, 0.5], | |||||
| name: "Guts", | |||||
| type: "IntervalSource", | |||||
| }, | |||||
| { | { | ||||
| soundSet: { | soundSet: { | ||||
| name: "Squishing", | name: "Squishing", | ||||
| @@ -50,14 +97,230 @@ export const PresetSources: Array<{ | |||||
| name: "Squishing", | name: "Squishing", | ||||
| type: "LoopingSource", | type: "LoopingSource", | ||||
| }, | }, | ||||
| { | |||||
| soundSet: { | |||||
| name: "Heartbeat", | |||||
| soundKeys: ["heartbeat"], | |||||
| }, | |||||
| kind: "source", | |||||
| volume: 1, | |||||
| pitch: 1, | |||||
| name: "Heartbeat", | |||||
| type: "LoopingSource", | |||||
| }, | |||||
| { | |||||
| soundSet: { | |||||
| name: "Breathing", | |||||
| soundKeys: ["breaths"], | |||||
| }, | |||||
| kind: "source", | |||||
| volume: 1, | |||||
| pitch: 1, | |||||
| name: "Breathing", | |||||
| type: "LoopingSource", | |||||
| }, | |||||
| { | |||||
| soundSet: { | |||||
| name: "Rumble", | |||||
| soundKeys: ["rumble"], | |||||
| }, | |||||
| kind: "source", | |||||
| volume: 1, | |||||
| pitch: 1, | |||||
| name: "Rumble", | |||||
| type: "LoopingSource", | |||||
| }, | |||||
| ]; | ]; | ||||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||||
| export const PresetFilters: Array<{ name: string; [x: string]: any }> = [ | export const PresetFilters: Array<{ name: string; [x: string]: any }> = [ | ||||
| { | { | ||||
| cutoff: 1000, | cutoff: 1000, | ||||
| name: "Lowpass Filter", | |||||
| name: "Lowpass", | |||||
| kind: "filter", | kind: "filter", | ||||
| type: "LowpassFilter", | type: "LowpassFilter", | ||||
| }, | }, | ||||
| { | |||||
| cutoff: 200, | |||||
| name: "Highpass", | |||||
| kind: "filter", | |||||
| type: "HighpassFilter", | |||||
| }, | |||||
| { | |||||
| width: 1, | |||||
| name: "Stereo Width", | |||||
| kind: "filter", | |||||
| type: "StereoWidthFilter", | |||||
| }, | |||||
| ]; | |||||
| export const DemoScene = [ | |||||
| { | |||||
| name: "Soundscape", | |||||
| sources: [ | |||||
| { | |||||
| soundSet: { | |||||
| name: "Guts", | |||||
| soundKeys: [ | |||||
| "stomach-churn", | |||||
| "intestines-to-bowels", | |||||
| "intestines-to-stomach", | |||||
| "intestines-to-stomach-forced", | |||||
| ], | |||||
| }, | |||||
| volume: 1, | |||||
| interval: [7, 15], | |||||
| pitch: [0.7, 1.1], | |||||
| panning: [-0.5, 0.5], | |||||
| kind: "source", | |||||
| name: "Guts", | |||||
| type: "IntervalSource", | |||||
| }, | |||||
| { | |||||
| soundSet: { name: "Squishing", soundKeys: ["squishing"] }, | |||||
| volume: 1, | |||||
| pitch: 1, | |||||
| kind: "source", | |||||
| name: "Squishing", | |||||
| type: "LoopingSource", | |||||
| }, | |||||
| { | |||||
| soundSet: { name: "Heartbeat", soundKeys: ["heartbeat"] }, | |||||
| volume: 0.65, | |||||
| pitch: 1, | |||||
| kind: "source", | |||||
| name: "Heartbeat", | |||||
| type: "LoopingSource", | |||||
| }, | |||||
| { | |||||
| soundSet: { name: "Rumble", soundKeys: ["rumble"] }, | |||||
| volume: 1, | |||||
| pitch: 1, | |||||
| kind: "source", | |||||
| name: "Rumble", | |||||
| type: "LoopingSource", | |||||
| }, | |||||
| { | |||||
| soundSet: { | |||||
| name: "Gurgles", | |||||
| soundKeys: [ | |||||
| "gurgles/gurgle (1)", | |||||
| "gurgles/gurgle (2)", | |||||
| "gurgles/gurgle (3)", | |||||
| "gurgles/gurgle (4)", | |||||
| "gurgles/gurgle (5)", | |||||
| "gurgles/gurgle (6)", | |||||
| "gurgles/gurgle (7)", | |||||
| "gurgles/gurgle (8)", | |||||
| "gurgles/gurgle (9)", | |||||
| "gurgles/gurgle (10)", | |||||
| "gurgles/gurgle (11)", | |||||
| "gurgles/gurgle (12)", | |||||
| "gurgles/gurgle (13)", | |||||
| "gurgles/gurgle (14)", | |||||
| "gurgles/gurgle (15)", | |||||
| "gurgles/gurgle (16)", | |||||
| "gurgles/gurgle (17)", | |||||
| "gurgles/gurgle (18)", | |||||
| "gurgles/gurgle (19)", | |||||
| "gurgles/gurgle (20)", | |||||
| "gurgles/gurgle (21)", | |||||
| ], | |||||
| }, | |||||
| volume: 1, | |||||
| interval: [1.0281138266560665, 1.9724654089867184], | |||||
| pitch: [0.9, 1.1], | |||||
| panning: [-0.7, 0.7], | |||||
| kind: "source", | |||||
| name: "Gurgles", | |||||
| type: "IntervalSource", | |||||
| }, | |||||
| { | |||||
| soundSet: { | |||||
| name: "Gurgles", | |||||
| soundKeys: [ | |||||
| "gurgles/gurgle (1)", | |||||
| "gurgles/gurgle (2)", | |||||
| "gurgles/gurgle (3)", | |||||
| "gurgles/gurgle (4)", | |||||
| "gurgles/gurgle (5)", | |||||
| "gurgles/gurgle (6)", | |||||
| "gurgles/gurgle (7)", | |||||
| "gurgles/gurgle (8)", | |||||
| "gurgles/gurgle (9)", | |||||
| "gurgles/gurgle (10)", | |||||
| "gurgles/gurgle (11)", | |||||
| "gurgles/gurgle (12)", | |||||
| "gurgles/gurgle (13)", | |||||
| "gurgles/gurgle (14)", | |||||
| "gurgles/gurgle (15)", | |||||
| "gurgles/gurgle (16)", | |||||
| "gurgles/gurgle (17)", | |||||
| "gurgles/gurgle (18)", | |||||
| "gurgles/gurgle (19)", | |||||
| "gurgles/gurgle (20)", | |||||
| "gurgles/gurgle (21)", | |||||
| ], | |||||
| }, | |||||
| volume: 1, | |||||
| interval: [4, 14.123247940650476], | |||||
| pitch: [0.3438854545349359, 0.6155722066724582], | |||||
| panning: [-0.7, 0.7], | |||||
| kind: "source", | |||||
| name: "Gurgles", | |||||
| type: "IntervalSource", | |||||
| }, | |||||
| ], | |||||
| filters: [], | |||||
| }, | |||||
| { | |||||
| name: "Soundscape", | |||||
| sources: [ | |||||
| { | |||||
| soundSet: { | |||||
| name: "Burps", | |||||
| soundKeys: [ | |||||
| "belch (1)", | |||||
| "belch (2)", | |||||
| "belch (3)", | |||||
| "belch (4)", | |||||
| "belch (5)", | |||||
| "belch (6)", | |||||
| "belch (7)", | |||||
| "belch (8)", | |||||
| "belch (9)", | |||||
| "belch (10)", | |||||
| "belch (11)", | |||||
| "belch (12)", | |||||
| "belch (13)", | |||||
| "belch (14)", | |||||
| "belch (15)", | |||||
| ], | |||||
| }, | |||||
| volume: 1, | |||||
| interval: [11.080875744887399, 29.040612970149155], | |||||
| pitch: [0.7, 1.1], | |||||
| panning: [-0.1, 0.1], | |||||
| kind: "source", | |||||
| name: "Burps", | |||||
| type: "IntervalSource", | |||||
| }, | |||||
| { | |||||
| soundSet: { name: "Breathing", soundKeys: ["breaths"] }, | |||||
| volume: 1, | |||||
| pitch: 0.8585654364377537, | |||||
| kind: "source", | |||||
| name: "Breathing", | |||||
| type: "LoopingSource", | |||||
| }, | |||||
| ], | |||||
| filters: [ | |||||
| { | |||||
| cutoff: 596.3435962718496, | |||||
| kind: "filter", | |||||
| name: "Lowpass Filter", | |||||
| type: "LowpassFilter", | |||||
| }, | |||||
| ], | |||||
| }, | |||||
| ]; | ]; | ||||
| @@ -16,7 +16,7 @@ const constructors: { [key: string]: new (name: string) => Node } = { | |||||
| LoopingSource: LoopingSource, | LoopingSource: LoopingSource, | ||||
| LowpassFilter: LowpassFilter, | LowpassFilter: LowpassFilter, | ||||
| HighpassFilter: HighpassFilter, | HighpassFilter: HighpassFilter, | ||||
| SterwoWidthFilter: StereoWidthFilter, | |||||
| StereoWidthFilter: StereoWidthFilter, | |||||
| }; | }; | ||||
| import { SoundSet, Source } from "./sources/Source"; | import { SoundSet, Source } from "./sources/Source"; | ||||