Skip to content

Commit 2dcf7cc

Browse files
test: add basic DynamicsCompressorNode automation test
1 parent 1b8245f commit 2dcf7cc

File tree

1 file changed

+138
-8
lines changed

1 file changed

+138
-8
lines changed

test/integration/audio-nodes/dynamics-compressor-node.js

Lines changed: 138 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
import { AudioBuffer, AudioBufferSourceNode, ConstantSourceNode, DynamicsCompressorNode, GainNode } from '../../../src/module';
1+
import {
2+
AudioBuffer,
3+
AudioBufferSourceNode,
4+
AudioWorkletNode,
5+
ConstantSourceNode,
6+
DynamicsCompressorNode,
7+
GainNode,
8+
addAudioWorkletModule
9+
} from '../../../src/module';
210
import { createAudioContext } from '../../helper/create-audio-context';
311
import { createMinimalAudioContext } from '../../helper/create-minimal-audio-context';
412
import { createMinimalOfflineAudioContext } from '../../helper/create-minimal-offline-audio-context';
@@ -557,13 +565,9 @@ if (typeof window !== 'undefined') {
557565
});
558566

559567
describe('ratio', () => {
560-
let dynamicsCompressorNode;
561-
562-
beforeEach(() => {
563-
dynamicsCompressorNode = createDynamicsCompressorNode(context);
564-
});
565-
566568
it('should return an implementation of the AudioParam interface', () => {
569+
const dynamicsCompressorNode = createDynamicsCompressorNode(context);
570+
567571
expect(dynamicsCompressorNode.ratio.cancelAndHoldAtTime).to.be.a('function');
568572
expect(dynamicsCompressorNode.ratio.cancelScheduledValues).to.be.a('function');
569573
expect(dynamicsCompressorNode.ratio.defaultValue).to.equal(12);
@@ -578,24 +582,44 @@ if (typeof window !== 'undefined') {
578582
});
579583

580584
it('should be readonly', () => {
585+
const dynamicsCompressorNode = createDynamicsCompressorNode(context);
586+
581587
expect(() => {
582588
dynamicsCompressorNode.ratio = 'anything';
583589
}).to.throw(TypeError);
584590
});
585591

586592
describe('cancelAndHoldAtTime()', () => {
593+
let dynamicsCompressorNode;
594+
595+
beforeEach(() => {
596+
dynamicsCompressorNode = createDynamicsCompressorNode(context);
597+
});
598+
587599
it('should be chainable', () => {
588600
expect(dynamicsCompressorNode.ratio.cancelAndHoldAtTime(0)).to.equal(dynamicsCompressorNode.ratio);
589601
});
590602
});
591603

592604
describe('cancelScheduledValues()', () => {
605+
let dynamicsCompressorNode;
606+
607+
beforeEach(() => {
608+
dynamicsCompressorNode = createDynamicsCompressorNode(context);
609+
});
610+
593611
it('should be chainable', () => {
594612
expect(dynamicsCompressorNode.ratio.cancelScheduledValues(0)).to.equal(dynamicsCompressorNode.ratio);
595613
});
596614
});
597615

598616
describe('exponentialRampToValueAtTime()', () => {
617+
let dynamicsCompressorNode;
618+
619+
beforeEach(() => {
620+
dynamicsCompressorNode = createDynamicsCompressorNode(context);
621+
});
622+
599623
it('should be chainable', () => {
600624
expect(dynamicsCompressorNode.ratio.exponentialRampToValueAtTime(1, 0)).to.equal(dynamicsCompressorNode.ratio);
601625
});
@@ -614,24 +638,48 @@ if (typeof window !== 'undefined') {
614638
});
615639

616640
describe('linearRampToValueAtTime()', () => {
641+
let dynamicsCompressorNode;
642+
643+
beforeEach(() => {
644+
dynamicsCompressorNode = createDynamicsCompressorNode(context);
645+
});
646+
617647
it('should be chainable', () => {
618648
expect(dynamicsCompressorNode.ratio.linearRampToValueAtTime(1, 0)).to.equal(dynamicsCompressorNode.ratio);
619649
});
620650
});
621651

622652
describe('setTargetAtTime()', () => {
653+
let dynamicsCompressorNode;
654+
655+
beforeEach(() => {
656+
dynamicsCompressorNode = createDynamicsCompressorNode(context);
657+
});
658+
623659
it('should be chainable', () => {
624660
expect(dynamicsCompressorNode.ratio.setTargetAtTime(1, 0, 0.1)).to.equal(dynamicsCompressorNode.ratio);
625661
});
626662
});
627663

628664
describe('setValueAtTime()', () => {
665+
let dynamicsCompressorNode;
666+
667+
beforeEach(() => {
668+
dynamicsCompressorNode = createDynamicsCompressorNode(context);
669+
});
670+
629671
it('should be chainable', () => {
630672
expect(dynamicsCompressorNode.ratio.setValueAtTime(1, 0)).to.equal(dynamicsCompressorNode.ratio);
631673
});
632674
});
633675

634676
describe('setValueCurveAtTime()', () => {
677+
let dynamicsCompressorNode;
678+
679+
beforeEach(() => {
680+
dynamicsCompressorNode = createDynamicsCompressorNode(context);
681+
});
682+
635683
for (const [arrayType, values] of [
636684
['regular Array', [1, 0]],
637685
['Float32Array', new Float32Array([1, 0])]
@@ -646,7 +694,89 @@ if (typeof window !== 'undefined') {
646694
}
647695
});
648696

649-
// @todo automation
697+
describe('automation', () => {
698+
for (const [withADirectConnection, withAnAppendedAudioWorklet] of description.includes('Offline')
699+
? [
700+
[true, true],
701+
[true, false],
702+
[false, true]
703+
]
704+
: [[true, false]]) {
705+
describe(`${withADirectConnection ? 'with' : 'without'} a direct connection and ${
706+
withAnAppendedAudioWorklet ? 'with' : 'without'
707+
} an appended AudioWorklet`, () => {
708+
let renderer;
709+
let values;
710+
711+
beforeEach(async function () {
712+
this.timeout(10000);
713+
714+
values = [1, 0.5, 0, -0.5, -1];
715+
716+
if (withAnAppendedAudioWorklet) {
717+
await addAudioWorkletModule(context, 'base/test/fixtures/gain-processor.js');
718+
}
719+
720+
renderer = createRenderer({
721+
context,
722+
length: context.length === undefined ? lookAhead + 5 : undefined,
723+
setup(destination) {
724+
// Bug #112: Firefox pauses the DynamicsCompressorNode without waiting for the tail time.
725+
const audioBuffer = new AudioBuffer({ length: lookAhead + 5, sampleRate: context.sampleRate });
726+
const audioBufferSourceNode = new AudioBufferSourceNode(context);
727+
const audioWorkletNode = withAnAppendedAudioWorklet
728+
? new AudioWorkletNode(context, 'gain-processor', { channelCount: 1 })
729+
: null;
730+
const dynamicsCompressorNode = createDynamicsCompressorNode(context);
731+
const masterGainNode = new GainNode(context, {
732+
gain: withADirectConnection && withAnAppendedAudioWorklet ? 0.5 : 1
733+
});
734+
735+
audioBuffer.copyToChannel(new Float32Array(values), 0);
736+
737+
audioBufferSourceNode.buffer = audioBuffer;
738+
739+
audioBufferSourceNode.connect(dynamicsCompressorNode);
740+
741+
if (withADirectConnection) {
742+
dynamicsCompressorNode.connect(masterGainNode);
743+
}
744+
745+
if (withAnAppendedAudioWorklet) {
746+
dynamicsCompressorNode.connect(audioWorkletNode).connect(masterGainNode);
747+
}
748+
749+
masterGainNode.connect(destination);
750+
751+
return { audioBufferSourceNode };
752+
}
753+
});
754+
});
755+
756+
describe('without any automation', () => {
757+
it('should not modify the signal', function () {
758+
this.timeout(10000);
759+
760+
return renderer({
761+
start(startTime, { audioBufferSourceNode }) {
762+
audioBufferSourceNode.start(startTime);
763+
}
764+
}).then((channelData) => {
765+
for (let i = 0; i < lookAhead; i += 1) {
766+
expect(channelData[i]).to.equal(0);
767+
}
768+
769+
expect(channelData[lookAhead]).to.be.closeTo(0.304, 0.004);
770+
expect(channelData[lookAhead + 1]).to.be.closeTo(0.152, 0.003);
771+
expect(channelData[lookAhead + 2]).to.be.closeTo(0, 0.0001);
772+
expect(channelData[lookAhead + 3]).to.be.closeTo(-0.152, 0.003);
773+
expect(channelData[lookAhead + 4]).to.be.closeTo(-0.304, 0.004);
774+
});
775+
});
776+
});
777+
});
778+
}
779+
});
650780
});
651781

652782
// @todo reduction

0 commit comments

Comments
 (0)