Skip to content

Commit

Permalink
feat: Add GainNode that controls Dry and Wet parameters to Phaser
Browse files Browse the repository at this point in the history
  • Loading branch information
Korilakkuma committed Sep 29, 2024
1 parent df2c2e4 commit f5321a3
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 27 deletions.
62 changes: 49 additions & 13 deletions src/SoundModule/Effectors/Phaser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ export type PhaserParams = {
resonance?: number,
depth?: number,
rate?: number,
mix?: number
mix?: number,
dry?: number,
wet?: number
};

/**
Expand All @@ -20,7 +22,8 @@ export class Phaser extends Effector {

private numberOfStages: PhaserNumberOfStages = 12; // The default number of All-pass Filters
private filters: BiquadFilterNode[] = [];
private mix: GainNode;
private dry: GainNode;
private wet: GainNode;
private depthRate = 0;

/**
Expand All @@ -40,12 +43,14 @@ export class Phaser extends Effector {
this.filters.push(filter);
}

this.mix = context.createGain();
this.dry = context.createGain();
this.wet = context.createGain();

// Initialize parameters
this.depth.gain.value = 0;
this.rate.value = 0;
this.mix.gain.value = 0;
this.dry.gain.value = 1;
this.wet.gain.value = 0;

// `Phaser` is not connected by default
this.deactivate();
Expand Down Expand Up @@ -82,22 +87,24 @@ export class Phaser extends Effector {
this.filters[i].disconnect(0);
}

this.mix.disconnect(0);
this.dry.disconnect(0);
this.wet.disconnect(0);

// GainNode (Input) -> GainNode (Output)
this.input.connect(this.output);
// GainNode (Input) -> GainNode (Dry) -> GainNode (Output)
this.input.connect(this.dry);
this.dry.connect(this.output);

// Effect ON
if (this.isActive && (this.numberOfStages > 0)) {
// GainNode (Input) -> BiquadFilterNode (All-pass Filter x N) -> GainNode (Mix) -> GainNode (Output)
// GainNode (Input) -> BiquadFilterNode (All-pass Filter x N) -> GainNode (Wet) -> GainNode (Output)
this.input.connect(this.filters[0]);

for (let i = 0; i < this.numberOfStages; i++) {
if (i < (this.numberOfStages - 1)) {
this.filters[i].connect(this.filters[i + 1]);
} else {
this.filters[i].connect(this.mix);
this.mix.connect(this.output);
this.filters[i].connect(this.wet);
this.wet.connect(this.output);
}
}

Expand All @@ -122,6 +129,8 @@ export class Phaser extends Effector {
public param(params: 'depth'): number;
public param(params: 'rate'): number;
public param(params: 'mix'): number;
public param(params: 'dry'): number;
public param(params: 'wet'): number;
public param(params: PhaserParams): Phaser;
public param(params: keyof PhaserParams | PhaserParams): PhaserParams[keyof PhaserParams] | Phaser {
if (typeof params === 'string') {
Expand Down Expand Up @@ -151,7 +160,15 @@ export class Phaser extends Effector {
}

case 'mix': {
return this.mix.gain.value;
return this.wet.gain.value;
}

case 'dry': {
return this.dry.gain.value;
}

case 'wet': {
return this.wet.gain.value;
}
}
}
Expand Down Expand Up @@ -226,7 +243,24 @@ export class Phaser extends Effector {

case 'mix': {
if (typeof value === 'number') {
this.mix.gain.value = value;
this.wet.gain.value = value;
this.dry.gain.value = 1 - this.wet.gain.value;
}

break;
}

case 'dry': {
if (typeof value === 'number') {
this.dry.gain.value = value;
}

break;
}

case 'wet': {
if (typeof value === 'number') {
this.wet.gain.value = value;
}

break;
Expand All @@ -246,7 +280,9 @@ export class Phaser extends Effector {
resonance: this.filters[0].Q.value,
depth : this.depthRate,
rate : this.rate.value,
mix : this.mix.gain.value
mix : this.wet.gain.value,
dry : this.dry.gain.value,
wet : this.wet.gain.value
};
}

Expand Down
49 changes: 35 additions & 14 deletions test/SoundModule/Effectors/Phaser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,17 @@ describe(Phaser.name, () => {
describe(phaser.connect.name, () => {
/* eslint-disable dot-notation */
const originalInput = phaser['input'];
const originalMix = phaser['mix'];
const originalDry = phaser['dry'];
const originalWet = phaser['wet'];
const originalConnect = BiquadFilterNode.prototype.connect;
const originalDisconnect = BiquadFilterNode.prototype.disconnect;
/* eslint-enable dot-notation */

afterAll(() => {
/* eslint-disable dot-notation */
phaser['input'] = originalInput;
phaser['mix'] = originalMix;
phaser['dry'] = originalDry;
phaser['wet'] = originalWet;
BiquadFilterNode.prototype.connect = originalConnect;
BiquadFilterNode.prototype.disconnect = originalDisconnect;
/* eslint-enable dot-notation */
Expand All @@ -80,14 +82,18 @@ describe(Phaser.name, () => {
const inputDisconnectMock = jest.fn();
const filterConnectMock = jest.fn();
const filterDisconnectMock = jest.fn();
const mixConnectMock = jest.fn();
const mixDisconnectMock = jest.fn();
const dryConnectMock = jest.fn();
const dryDisconnectMock = jest.fn();
const wetConnectMock = jest.fn();
const wetDisconnectMock = jest.fn();

/* eslint-disable dot-notation */
phaser['input'].connect = inputConnectMock;
phaser['input'].disconnect = inputDisconnectMock;
phaser['mix'].connect = mixConnectMock;
phaser['mix'].disconnect = mixDisconnectMock;
phaser['dry'].connect = dryConnectMock;
phaser['dry'].disconnect = dryDisconnectMock;
phaser['wet'].connect = wetConnectMock;
phaser['wet'].disconnect = wetDisconnectMock;
BiquadFilterNode.prototype.connect = filterConnectMock;
BiquadFilterNode.prototype.disconnect = filterDisconnectMock;
/* eslint-enable dot-notation */
Expand All @@ -96,19 +102,20 @@ describe(Phaser.name, () => {

expect(inputConnectMock).toHaveBeenCalledTimes(1);
expect(filterConnectMock).toHaveBeenCalledTimes(0);
expect(mixConnectMock).toHaveBeenCalledTimes(0);
expect(mixConnectMock).toHaveBeenCalledTimes(0);
expect(dryConnectMock).toHaveBeenCalledTimes(1);
expect(wetConnectMock).toHaveBeenCalledTimes(0);
expect(inputDisconnectMock).toHaveBeenCalledTimes(1);
expect(filterDisconnectMock).toHaveBeenCalledTimes(24);
expect(mixDisconnectMock).toHaveBeenCalledTimes(1);
expect(dryDisconnectMock).toHaveBeenCalledTimes(1);
expect(wetDisconnectMock).toHaveBeenCalledTimes(1);

phaser.activate();

expect(inputConnectMock).toHaveBeenCalledTimes(3);
expect(filterConnectMock).toHaveBeenCalledTimes(12);
expect(mixConnectMock).toHaveBeenCalledTimes(1);
expect(dryConnectMock).toHaveBeenCalledTimes(2);
expect(filterDisconnectMock).toHaveBeenCalledTimes(48);
expect(mixDisconnectMock).toHaveBeenCalledTimes(2);
expect(wetDisconnectMock).toHaveBeenCalledTimes(2);
});
});

Expand All @@ -119,7 +126,9 @@ describe(Phaser.name, () => {
resonance: 1,
depth : 0,
rate : 0,
mix : 0
mix : 0,
dry : 1,
wet : 0,
};

const params: PhaserParams = {
Expand All @@ -128,7 +137,9 @@ describe(Phaser.name, () => {
resonance: 10,
depth : 0.5,
rate : 0.5,
mix : 0.5
mix : 0.5,
dry : 0.5,
wet : 0.5
};

beforeAll(() => {
Expand Down Expand Up @@ -168,6 +179,14 @@ describe(Phaser.name, () => {
test('should return `mix`', () => {
expect(phaser.param('mix')).toBeCloseTo(0.5, 1);
});

test('should return `dry`', () => {
expect(phaser.param('dry')).toBeCloseTo(0.5, 1);
});

test('should return `wet`', () => {
expect(phaser.param('wet')).toBeCloseTo(0.5, 1);
});
});

describe(phaser.params.name, () => {
Expand All @@ -179,7 +198,9 @@ describe(Phaser.name, () => {
resonance: 1,
depth : 0,
rate : 0,
mix : 0
mix : 0,
dry : 1,
wet : 0
});
});
});
Expand Down

0 comments on commit f5321a3

Please sign in to comment.