Tone.js/Tone/source/oscillator/Oscillator.test.ts
Yotam Mann bfc3d7ed15 toMaster() -> toDestination()
more consistent with the Web Audio API
2019-07-25 11:32:56 -04:00

245 lines
6.3 KiB
TypeScript

import { expect } from "chai";
import { BasicTests } from "test/helper/Basic";
import { CompareToFile } from "test/helper/CompareToFile";
import { Offline } from "test/helper/Offline";
import { OscillatorTests } from "test/helper/OscillatorTests";
import { OutputAudio } from "test/helper/OutputAudio";
import { SourceTests } from "test/helper/SourceTests";
import { Oscillator } from "./Oscillator";
import { ToneOscillatorType } from "./OscillatorInterface";
describe("Oscillator", () => {
// run the common tests
BasicTests(Oscillator);
SourceTests(Oscillator);
OscillatorTests(Oscillator);
it("matches a file", () => {
return CompareToFile(() => {
const osc = new Oscillator().toDestination();
osc.type = "square";
osc.start(0).stop(0.2);
}, "oscillator.wav", 0.1);
});
context("Get/Set", () => {
it("can be set with an options object", () => {
const osc = new Oscillator();
osc.set({
detune: -21,
frequency: 231,
type: "square",
});
expect(osc.frequency.value).to.equal(231);
expect(osc.detune.value).to.equal(-21);
expect(osc.type).to.equal("square");
osc.dispose();
});
it("can be get the values as an object", () => {
const osc = new Oscillator(450, "square");
expect(osc.get().frequency).to.equal(450);
expect(osc.get().type).to.equal("square");
osc.dispose();
});
it("only returns partials when type is 'custom'", () => {
const osc = new Oscillator(450, "square");
expect(osc.get().partials).to.equal(undefined);
osc.partials = [0, 1, 2, 3];
expect(osc.get().type).to.equal("custom");
expect(osc.get().partials).to.deep.equal([0, 1, 2, 3]);
osc.dispose();
});
});
context("Phase Rotation", () => {
it("can change the phase to 90", () => {
return Offline(() => {
const instance = new Oscillator({
frequency: 1,
phase: 90,
});
instance.toDestination();
instance.start(0);
}, 1).then((buffer) => {
buffer.forEach((sample, time) => {
if (time < 0.25) {
expect(sample).to.be.within(-1, 0);
} else if (time > 0.25 && time < 0.5) {
expect(sample).to.be.within(0, 1);
}
});
});
});
it("can change the phase to -90", () => {
return Offline(() => {
const instance = new Oscillator({
frequency: 1,
phase: 270,
});
instance.toDestination();
instance.start(0);
}, 1).then((buffer) => {
buffer.forEach((sample, time) => {
if (time < 0.25) {
expect(sample).to.be.within(0, 1);
} else if (time > 0.25 && time < 0.5) {
expect(sample).to.be.within(-1, 0);
}
});
});
});
});
context("Type", () => {
it("can get and set the type", () => {
const osc = new Oscillator({
type: "sawtooth",
});
expect(osc.type).to.equal("sawtooth");
osc.dispose();
});
it("handles 4 basic types", () => {
const osc = new Oscillator();
const types: ToneOscillatorType[] = ["triangle", "sawtooth", "sine", "square"];
for (const type of types) {
osc.type = type;
expect(osc.type).to.equal(type);
}
osc.dispose();
});
it("throws an error if invalid type is set", () => {
const osc = new Oscillator();
expect(() => {
// @ts-ignore
osc.type = "invalid";
}).to.throw(Error);
osc.dispose();
});
it("can set extended types", () => {
const osc = new Oscillator();
osc.type = "sine5";
expect(osc.type).to.equal("sine5");
osc.type = "triangle2";
expect(osc.type).to.equal("triangle2");
osc.dispose();
});
it("can get/set the baseType", () => {
const osc = new Oscillator();
osc.type = "sine5";
expect(osc.baseType).to.equal("sine");
osc.baseType = "triangle";
expect(osc.type).to.equal("triangle5");
expect(osc.partialCount).to.equal(5);
osc.partialCount = 2;
expect(osc.type).to.equal("triangle2");
osc.baseType = "custom";
expect(osc.type).to.equal("custom");
osc.partials = [1, 2, 3];
expect(osc.baseType).to.equal("custom");
osc.baseType = "square";
expect(osc.type).to.equal("square");
osc.dispose();
});
});
context("Partials", () => {
it("can pass partials in the constructor", () => {
const osc = new Oscillator({
partials: [1, 0.3, 0.3],
type: "custom",
});
expect(osc.type).to.equal("custom");
expect(osc.partials[1]).to.equal(0.3);
osc.dispose();
});
it("can set partials", () => {
const osc = new Oscillator();
osc.partials = [1, 0.2, 0.2, 0.2];
expect(osc.type).to.equal("custom");
expect(osc.partials[1]).to.equal(0.2);
osc.dispose();
});
it("makes a sound with custom partials", () => {
return OutputAudio(() => {
const osc = new Oscillator().toDestination().start();
osc.partials = [1, 0.2, 0.2, 0.2];
});
});
it("outputs the partials of the given waveform", () => {
const osc = new Oscillator();
osc.type = "sine2";
expect(osc.type).to.equal("sine2");
expect(osc.partials.length).to.equal(2);
expect(osc.partials).to.deep.equal([1, 1]);
osc.dispose();
});
it("partialCount is 0 when set to max", () => {
const osc = new Oscillator();
expect(osc.partialCount).to.equal(0);
osc.type = "square32";
expect(osc.partialCount).to.equal(32);
osc.type = "square";
expect(osc.partialCount).to.equal(0);
osc.dispose();
});
it("can pass in number of partials into constructor", () => {
const osc = new Oscillator({
partialCount: 3,
type: "sine",
});
expect(osc.type).to.equal("sine3");
expect(osc.partialCount).to.equal(3);
osc.partialCount = 4;
expect(osc.partialCount).to.equal(4);
expect(osc.type).to.equal("sine4");
osc.dispose();
});
});
context("Synchronization", () => {
it("can sync the frequency to the Transport", () => {
return Offline(({transport}) => {
transport.bpm.value = 120;
const osc = new Oscillator(2);
osc.frequency.toDestination();
osc.syncFrequency();
transport.bpm.value = 240;
}).then((buffer) => {
expect(buffer.value()).to.be.closeTo(4, 0.001);
});
});
it("can unsync the frequency from the Transport", () => {
return Offline(({transport}) => {
transport.bpm.value = 120;
const osc = new Oscillator(2);
osc.frequency.toDestination();
osc.syncFrequency();
transport.bpm.value = 240;
osc.unsyncFrequency();
}).then((buffer) => {
expect(buffer.value()).to.be.closeTo(2, 0.001);
});
});
});
});