| @@ -11,6 +11,7 @@ | |||||
| "@vueform/slider": "^2.0.5", | "@vueform/slider": "^2.0.5", | ||||
| "@vueform/toggle": "^2.0.1", | "@vueform/toggle": "^2.0.1", | ||||
| "core-js": "^3.6.5", | "core-js": "^3.6.5", | ||||
| "js-base64": "^3.7.1", | |||||
| "mobile-drag-drop": "^2.3.0-rc.2", | "mobile-drag-drop": "^2.3.0-rc.2", | ||||
| "postcss": "^8.3.6", | "postcss": "^8.3.6", | ||||
| "reflect-metadata": "^0.1.13", | "reflect-metadata": "^0.1.13", | ||||
| @@ -10254,6 +10255,11 @@ | |||||
| "integrity": "sha1-J8dlOb4U2L0Sghmi1zGwkzeQTnk=", | "integrity": "sha1-J8dlOb4U2L0Sghmi1zGwkzeQTnk=", | ||||
| "dev": true | "dev": true | ||||
| }, | }, | ||||
| "node_modules/js-base64": { | |||||
| "version": "3.7.1", | |||||
| "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.1.tgz", | |||||
| "integrity": "sha512-XyYXEUTP3ykPPnGPoesMr4yBygopit99iXW52yT1EWrkzwzvtAor/pbf+EBuDkwqSty7K10LeTjCkUn8c166aQ==" | |||||
| }, | |||||
| "node_modules/js-message": { | "node_modules/js-message": { | ||||
| "version": "1.0.7", | "version": "1.0.7", | ||||
| "resolved": "https://registry.npm.taobao.org/js-message/download/js-message-1.0.7.tgz?cache=0&sync_timestamp=1605128844887&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjs-message%2Fdownload%2Fjs-message-1.0.7.tgz", | "resolved": "https://registry.npm.taobao.org/js-message/download/js-message-1.0.7.tgz?cache=0&sync_timestamp=1605128844887&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjs-message%2Fdownload%2Fjs-message-1.0.7.tgz", | ||||
| @@ -26321,6 +26327,11 @@ | |||||
| "integrity": "sha1-J8dlOb4U2L0Sghmi1zGwkzeQTnk=", | "integrity": "sha1-J8dlOb4U2L0Sghmi1zGwkzeQTnk=", | ||||
| "dev": true | "dev": true | ||||
| }, | }, | ||||
| "js-base64": { | |||||
| "version": "3.7.1", | |||||
| "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.1.tgz", | |||||
| "integrity": "sha512-XyYXEUTP3ykPPnGPoesMr4yBygopit99iXW52yT1EWrkzwzvtAor/pbf+EBuDkwqSty7K10LeTjCkUn8c166aQ==" | |||||
| }, | |||||
| "js-message": { | "js-message": { | ||||
| "version": "1.0.7", | "version": "1.0.7", | ||||
| "resolved": "https://registry.npm.taobao.org/js-message/download/js-message-1.0.7.tgz?cache=0&sync_timestamp=1605128844887&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjs-message%2Fdownload%2Fjs-message-1.0.7.tgz", | "resolved": "https://registry.npm.taobao.org/js-message/download/js-message-1.0.7.tgz?cache=0&sync_timestamp=1605128844887&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjs-message%2Fdownload%2Fjs-message-1.0.7.tgz", | ||||
| @@ -11,6 +11,7 @@ | |||||
| "@vueform/slider": "^2.0.5", | "@vueform/slider": "^2.0.5", | ||||
| "@vueform/toggle": "^2.0.1", | "@vueform/toggle": "^2.0.1", | ||||
| "core-js": "^3.6.5", | "core-js": "^3.6.5", | ||||
| "js-base64": "^3.7.1", | |||||
| "mobile-drag-drop": "^2.3.0-rc.2", | "mobile-drag-drop": "^2.3.0-rc.2", | ||||
| "postcss": "^8.3.6", | "postcss": "^8.3.6", | ||||
| "reflect-metadata": "^0.1.13", | "reflect-metadata": "^0.1.13", | ||||
| @@ -1,6 +1,6 @@ | |||||
| <template> | <template> | ||||
| <div id="app-area"> | <div id="app-area"> | ||||
| <Menu /> | |||||
| <Menu v-on:permalink="permalink" /> | |||||
| <div id="first-input" v-if="needsInput"> | <div id="first-input" v-if="needsInput"> | ||||
| <button class="soundscapes" v-on:click="resumeContext">Start</button> | <button class="soundscapes" v-on:click="resumeContext">Start</button> | ||||
| </div> | </div> | ||||
| @@ -21,7 +21,9 @@ 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 { DemoScene } from "./data/presets"; | ||||
| import { deserializeSoundscape } from "./serialize"; | |||||
| import { deserializeSoundscape, serializeSoundscape } from "./serialize"; | |||||
| import { Base64 } from "js-base64"; | |||||
| @Options({ | @Options({ | ||||
| components: { | components: { | ||||
| SoundscapeComp, | SoundscapeComp, | ||||
| @@ -42,6 +44,11 @@ export default class Dissolve extends Vue { | |||||
| this.soundscapes.push(scape); | this.soundscapes.push(scape); | ||||
| } | } | ||||
| permalink(): void { | |||||
| const data = this.soundscapes.map((scape) => serializeSoundscape(scape)); | |||||
| window.location.hash = Base64.encodeURI(JSON.stringify(data)); | |||||
| } | |||||
| mounted(): void { | mounted(): void { | ||||
| this.context = setup(); | this.context = setup(); | ||||
| console.log(this.context); | console.log(this.context); | ||||
| @@ -53,6 +60,15 @@ export default class Dissolve extends Vue { | |||||
| if (this.context.state == "suspended") { | if (this.context.state == "suspended") { | ||||
| this.needsInput = true; | this.needsInput = true; | ||||
| } | } | ||||
| if (window.location.hash) { | |||||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | |||||
| const data: Array<any> = JSON.parse(Base64.decode(window.location.hash)); | |||||
| data.forEach((entry) => { | |||||
| this.addSoundscape(deserializeSoundscape(entry)); | |||||
| }); | |||||
| } | |||||
| } | } | ||||
| resumeContext(): void { | resumeContext(): void { | ||||
| @@ -57,4 +57,14 @@ export default class Menu extends Vue { | |||||
| grid-auto-rows: minmax(max-content, 1fr); | grid-auto-rows: minmax(max-content, 1fr); | ||||
| background: #777; | background: #777; | ||||
| } | } | ||||
| button { | |||||
| width: 100%; | |||||
| height: 50px; | |||||
| background: #ccc; | |||||
| font-size: 24pt; | |||||
| font-family: "Coda"; | |||||
| } | |||||
| button:active { | |||||
| background: #999; | |||||
| } | |||||
| </style> | </style> | ||||
| @@ -66,7 +66,7 @@ export function serializeNode<T extends Node>(_node: T): any { | |||||
| const soundSet = node[key] as SoundSet; | const soundSet = node[key] as SoundSet; | ||||
| results[key] = { | results[key] = { | ||||
| name: soundSet.name, | name: soundSet.name, | ||||
| soundKeys: soundSet.soundKeys, | |||||
| soundKeys: soundSet.preset ? undefined : soundSet.soundKeys, | |||||
| }; | }; | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -115,7 +115,8 @@ export function deserializeNode(data: any): Node { | |||||
| if (data[key].soundKeys === undefined) { | if (data[key].soundKeys === undefined) { | ||||
| node[key] = new SoundSet( | node[key] = new SoundSet( | ||||
| data[key].name, | data[key].name, | ||||
| PresetSoundSets[data[key].name] | |||||
| PresetSoundSets[data[key].name], | |||||
| true | |||||
| ); | ); | ||||
| } else { | } else { | ||||
| node[key] = new SoundSet(data[key].name, data[key].soundKeys); | node[key] = new SoundSet(data[key].name, data[key].soundKeys); | ||||
| @@ -10,7 +10,11 @@ export class SoundSet { | |||||
| soundMap: Map<string, AudioBuffer> = new Map(); | soundMap: Map<string, AudioBuffer> = new Map(); | ||||
| soundList: Array<AudioBuffer> = []; | soundList: Array<AudioBuffer> = []; | ||||
| constructor(public name: string, public soundKeys: Array<string>) { | |||||
| constructor( | |||||
| public name: string, | |||||
| public soundKeys: Array<string>, | |||||
| public preset = false | |||||
| ) { | |||||
| this.soundKeys.forEach((sound) => { | this.soundKeys.forEach((sound) => { | ||||
| loadAudio(sound, this); | loadAudio(sound, this); | ||||
| }); | }); | ||||