diff --git a/decs.d.ts b/decs.d.ts
new file mode 100644
index 0000000..7b1c176
--- /dev/null
+++ b/decs.d.ts
@@ -0,0 +1 @@
+declare module "soundbank-reverb"
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 5dcb2d1..033294e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,6 +14,7 @@
"mobile-drag-drop": "^2.3.0-rc.2",
"postcss": "^8.3.6",
"reflect-metadata": "^0.1.13",
+ "soundbank-reverb": "^1.1.2",
"vue": "^3.0.0",
"vue-class-component": "^8.0.0-0",
"vue-slider-component": "^3.2.14"
@@ -15445,6 +15446,11 @@
"node": ">=0.10.0"
}
},
+ "node_modules/soundbank-reverb": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/soundbank-reverb/-/soundbank-reverb-1.1.2.tgz",
+ "integrity": "sha1-uBspdgt5B7jIuuEMDZEz2Oxk+/c="
+ },
"node_modules/source-list-map": {
"version": "2.0.1",
"resolved": "https://registry.npm.taobao.org/source-list-map/download/source-list-map-2.0.1.tgz",
@@ -30432,6 +30438,11 @@
}
}
},
+ "soundbank-reverb": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/soundbank-reverb/-/soundbank-reverb-1.1.2.tgz",
+ "integrity": "sha1-uBspdgt5B7jIuuEMDZEz2Oxk+/c="
+ },
"source-list-map": {
"version": "2.0.1",
"resolved": "https://registry.npm.taobao.org/source-list-map/download/source-list-map-2.0.1.tgz",
diff --git a/package.json b/package.json
index a1f2643..0b39136 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
"mobile-drag-drop": "^2.3.0-rc.2",
"postcss": "^8.3.6",
"reflect-metadata": "^0.1.13",
+ "soundbank-reverb": "^1.1.2",
"vue": "^3.0.0",
"vue-class-component": "^8.0.0-0",
"vue-slider-component": "^3.2.14"
diff --git a/src/components/Menu.vue b/src/components/Menu.vue
index d0e5bbc..7f5f628 100644
--- a/src/components/Menu.vue
+++ b/src/components/Menu.vue
@@ -17,6 +17,7 @@
:node="filter"
/>
+
diff --git a/src/components/nodes/FilterNode.vue b/src/components/nodes/FilterNode.vue
index cfd1cee..b672a59 100644
--- a/src/components/nodes/FilterNode.vue
+++ b/src/components/nodes/FilterNode.vue
@@ -57,6 +57,7 @@ export default class FilterNode extends Vue {
font-size: 24pt;
margin: 4pt;
color: #fcf;
+ margin-top: 30pt;
}
.node-properties {
diff --git a/src/components/nodes/SourceNode.vue b/src/components/nodes/SourceNode.vue
index 2a256e9..0b8fa7a 100644
--- a/src/components/nodes/SourceNode.vue
+++ b/src/components/nodes/SourceNode.vue
@@ -56,6 +56,7 @@ export default class SourceNode extends Vue {
font-size: 24pt;
margin: 4pt;
color: #fcf;
+ margin-top: 30pt;
}
.node-properties {
diff --git a/src/data/presets.ts b/src/data/presets.ts
index 562479a..14248f5 100644
--- a/src/data/presets.ts
+++ b/src/data/presets.ts
@@ -102,6 +102,15 @@ export const PresetFilters: Array<{ name: string; [x: string]: any }> = [
kind: "filter",
type: "StereoWidthFilter",
},
+ {
+ time: 1,
+ decay: 1,
+ dry: 1,
+ wet: 0.5,
+ name: "Reverb",
+ kind: "filter",
+ type: "ReverbFilter",
+ },
];
export const DemoScene = [
diff --git a/src/filters/ReverbFilter.ts b/src/filters/ReverbFilter.ts
new file mode 100644
index 0000000..d7073c1
--- /dev/null
+++ b/src/filters/ReverbFilter.ts
@@ -0,0 +1,81 @@
+import { Filter } from "./Filter";
+import { context, exposedNumber } from "../audio";
+import Reverb from "soundbank-reverb";
+
+export class ReverbFilter extends Filter {
+ private reverb: any;
+
+ @exposedNumber({
+ name: "Reverb Time",
+ min: 0.1,
+ max: 5,
+ format: (value: number) =>
+ Math.pow(2, value).toLocaleString(undefined, {
+ maximumFractionDigits: 1,
+ }) + "s",
+ map: (value: number) => Math.log(value) / Math.log(2),
+ unmap: (value: number) => Math.pow(2, value),
+ })
+ public time = 1;
+ private oldTime = -1;
+
+ @exposedNumber({
+ name: "Decay Rate",
+ min: 0.1,
+ max: 5,
+ format: (value: number) =>
+ Math.pow(2, value).toLocaleString(undefined, {
+ maximumFractionDigits: 1,
+ }),
+ map: (value: number) => Math.log(value) / Math.log(2),
+ unmap: (value: number) => Math.pow(2, value),
+ })
+ public decay = 1;
+ private oldDecay = -1;
+
+ @exposedNumber({
+ name: "Dry Mix",
+ min: 0,
+ max: 1,
+ format: (value: number) =>
+ (value * 100).toLocaleString(undefined, {
+ maximumFractionDigits: 0,
+ }) + "%",
+ })
+ public dry = 1;
+
+ @exposedNumber({
+ name: "Wet Mix",
+ min: 0,
+ max: 1,
+ format: (value: number) =>
+ (value * 100).toLocaleString(undefined, {
+ maximumFractionDigits: 0,
+ }) + "%",
+ })
+ public wet = 0.5;
+
+ constructor() {
+ super("Reverb Filter");
+ this.reverb = Reverb(context);
+
+ this.reverb.time = 1;
+ this.input.connect(this.reverb);
+ this.reverb.connect(this.output);
+ }
+
+ public tick(dt: number): void {
+ super.tick(dt);
+ if (this.oldTime != this.time) {
+ this.reverb.time = this.time;
+ this.oldTime = this.time;
+ }
+
+ if (this.oldDecay != this.decay) {
+ this.reverb.decay = this.decay;
+ this.oldDecay = this.decay;
+ }
+ this.reverb.dry.setTargetAtTime(this.dry, context.currentTime, 0.3);
+ this.reverb.wet.setTargetAtTime(this.wet, context.currentTime, 0.3);
+ }
+}
diff --git a/src/serialize.ts b/src/serialize.ts
index fb52e7a..1986f25 100644
--- a/src/serialize.ts
+++ b/src/serialize.ts
@@ -17,6 +17,7 @@ const constructors: { [key: string]: new (name: string) => Node } = {
LowpassFilter: LowpassFilter,
HighpassFilter: HighpassFilter,
StereoWidthFilter: StereoWidthFilter,
+ ReverbFilter: ReverbFilter,
};
import { SoundSet, Source } from "./sources/Source";
@@ -25,6 +26,7 @@ import { LowpassFilter } from "./filters/LowpassFilter";
import { HighpassFilter } from "./filters/HighpassFilter";
import { StereoWidthFilter } from "./filters/StereoWidthFilter";
import { PresetSoundSets } from "./data/sound-sets";
+import { ReverbFilter } from "./filters/ReverbFilter";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function serializeNode(_node: T): any {
diff --git a/tsconfig.json b/tsconfig.json
index 8c93ef5..be8b06c 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -32,7 +32,8 @@
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
- "tests/**/*.tsx"
+ "tests/**/*.tsx",
+ "decs.d.ts",
],
"exclude": [
"node_modules"