1 | import {
|
2 | ToneAudioWorklet,
|
3 | ToneAudioWorkletOptions,
|
4 | } from "../core/worklet/ToneAudioWorklet.js";
|
5 | import { Effect, EffectOptions } from "./Effect.js";
|
6 | import { Positive } from "../core/type/Units.js";
|
7 | import { Gain } from "../core/context/Gain.js";
|
8 | import { optionsFromArguments } from "../core/util/Defaults.js";
|
9 | import { connectSeries } from "../core/context/ToneAudioNode.js";
|
10 | import { Param } from "../core/context/Param.js";
|
11 | import { workletName } from "./BitCrusher.worklet.js";
|
12 |
|
13 | export interface BitCrusherOptions extends EffectOptions {
|
14 | bits: Positive;
|
15 | }
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 | export class BitCrusher extends Effect<BitCrusherOptions> {
|
30 | readonly name: string = "BitCrusher";
|
31 |
|
32 | |
33 |
|
34 |
|
35 |
|
36 |
|
37 | readonly bits: Param<"positive">;
|
38 |
|
39 | |
40 |
|
41 |
|
42 | private _bitCrusherWorklet: BitCrusherWorklet;
|
43 |
|
44 | constructor(bits?: Positive);
|
45 | constructor(options?: Partial<BitCrusherWorkletOptions>);
|
46 | constructor() {
|
47 | const options = optionsFromArguments(
|
48 | BitCrusher.getDefaults(),
|
49 | arguments,
|
50 | ["bits"]
|
51 | );
|
52 | super(options);
|
53 |
|
54 | this._bitCrusherWorklet = new BitCrusherWorklet({
|
55 | context: this.context,
|
56 | bits: options.bits,
|
57 | });
|
58 | // connect it up
|
59 | this.connectEffect(this._bitCrusherWorklet);
|
60 |
|
61 | this.bits = this._bitCrusherWorklet.bits;
|
62 | }
|
63 |
|
64 | static getDefaults(): BitCrusherOptions {
|
65 | return Object.assign(Effect.getDefaults(), {
|
66 | bits: 4,
|
67 | });
|
68 | }
|
69 |
|
70 | dispose(): this {
|
71 | super.dispose();
|
72 | this._bitCrusherWorklet.dispose();
|
73 | return this;
|
74 | }
|
75 | }
|
76 |
|
77 | interface BitCrusherWorkletOptions extends ToneAudioWorkletOptions {
|
78 | bits: number;
|
79 | }
|
80 |
|
81 |
|
82 |
|
83 |
|
84 | class BitCrusherWorklet extends ToneAudioWorklet<BitCrusherWorkletOptions> {
|
85 | readonly name: string = "BitCrusherWorklet";
|
86 |
|
87 | readonly input: Gain;
|
88 | readonly output: Gain;
|
89 |
|
90 | readonly bits: Param<"positive">;
|
91 |
|
92 | constructor(options?: Partial<BitCrusherWorkletOptions>);
|
93 | constructor() {
|
94 | const options = optionsFromArguments(
|
95 | BitCrusherWorklet.getDefaults(),
|
96 | arguments
|
97 | );
|
98 | super(options);
|
99 |
|
100 | this.input = new Gain({ context: this.context });
|
101 | this.output = new Gain({ context: this.context });
|
102 |
|
103 | this.bits = new Param<"positive">({
|
104 | context: this.context,
|
105 | value: options.bits,
|
106 | units: "positive",
|
107 | minValue: 1,
|
108 | maxValue: 16,
|
109 | param: this._dummyParam,
|
110 | swappable: true,
|
111 | });
|
112 | }
|
113 |
|
114 | static getDefaults(): BitCrusherWorkletOptions {
|
115 | return Object.assign(ToneAudioWorklet.getDefaults(), {
|
116 | bits: 12,
|
117 | });
|
118 | }
|
119 |
|
120 | protected _audioWorkletName(): string {
|
121 | return workletName;
|
122 | }
|
123 |
|
124 | onReady(node: AudioWorkletNode) {
|
125 | connectSeries(this.input, node, this.output);
|
126 | const bits = node.parameters.get("bits") as AudioParam;
|
127 | this.bits.setParam(bits);
|
128 | }
|
129 |
|
130 | dispose(): this {
|
131 | super.dispose();
|
132 | this.input.dispose();
|
133 | this.output.dispose();
|
134 | this.bits.dispose();
|
135 | return this;
|
136 | }
|
137 | }
|