@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
114 lines (113 loc) • 3.13 kB
JavaScript
;
import { TypedAudioNode } from "./_Base";
import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig";
import { AudioBuilder } from "../../../core/audio/AudioBuilder";
import { Sampler } from "tone/build/esm/instrument/Sampler";
import { StringParamLanguage } from "../../params/utils/OptionsController";
import { sanitizeUrl } from "../../../core/UrlHelper";
import { CoreLoaderAudio } from "../../../core/loader/Audio";
import { Poly } from "../../Poly";
import { AudioType } from "../../poly/registers/nodes/types/Audio";
export const SAMPLER_DEFAULTS = {
attack: 0.01,
release: 1
};
const DEFAULT_NOTE_MAP = {
A0: "A0",
C1: "C1",
"D#1": "Ds1",
"F#1": "Fs1",
A1: "A1",
C2: "C2",
"D#2": "Ds2",
"F#2": "Fs2",
A2: "A2",
C3: "C3",
"D#3": "Ds3",
"F#3": "Fs3",
A3: "A3",
C4: "C4",
"D#4": "Ds4",
"F#4": "Fs4",
A4: "A4",
C5: "C5",
"D#5": "Ds5",
"F#5": "Fs5",
A5: "A5",
C6: "C6",
"D#6": "Ds6",
"F#6": "Fs6",
A6: "A6",
C7: "C7",
"D#7": "Ds7",
"F#7": "Fs7",
A7: "A7",
C8: "C8"
};
class SamplerAudioParamsConfig extends NodeParamsConfig {
constructor() {
super(...arguments);
/** @param map of notes to load */
this.urlsMap = ParamConfig.STRING(JSON.stringify(DEFAULT_NOTE_MAP, null, 2), {
language: StringParamLanguage.JSON
});
/** @param base url */
this.baseUrl = ParamConfig.STRING("./");
/** @param extension */
this.extension = ParamConfig.STRING("mp3");
}
}
const ParamsConfig = new SamplerAudioParamsConfig();
export class SamplerAudioNode extends TypedAudioNode {
constructor() {
super(...arguments);
this.paramsConfig = ParamsConfig;
}
static type() {
return AudioType.SAMPLER;
}
initializeNode() {
this.io.inputs.setCount(1);
}
dispose() {
super.dispose();
Poly.blobs.clearBlobsForNode(this);
}
async cook(inputContents) {
const envelopeBuilder = inputContents[0];
const envelopeParams = envelopeBuilder.envelopeParams() || SAMPLER_DEFAULTS;
let urlsJSON = {};
let urls = [];
try {
const extension = this.pv.extension;
urlsJSON = JSON.parse(this.pv.urlsMap);
const noteNames = Object.keys(urlsJSON);
for (const noteName of noteNames) {
const urlFileName = urlsJSON[noteName];
const url = `${this.pv.baseUrl}/${urlFileName}.${extension}`;
urlsJSON[noteName] = sanitizeUrl(url);
urls.push(url);
}
} catch (err) {
this.states.error.set("urlsMap is invalid JSON");
}
const loaders = urls.map(
(url) => new CoreLoaderAudio(url, this, { multiAssetsForNode: true })
);
await Promise.all(loaders.map((loader) => loader.load()));
const sampler = new Sampler({
urls: urlsJSON,
attack: envelopeParams.attack,
release: envelopeParams.release,
baseUrl: "",
onerror: (err) => {
this.states.error.set(err.message);
},
onload: () => {
const audioBuilder = new AudioBuilder();
audioBuilder.setInstrument(sampler);
this.setAudioBuilder(audioBuilder);
}
});
}
}