mirror of
https://github.com/Tonejs/Tone.js
synced 2024-11-16 08:38:00 +00:00
466 lines
11 KiB
TypeScript
466 lines
11 KiB
TypeScript
import { expect } from "chai";
|
|
import { BasicTests } from "test/helper/Basic";
|
|
import { IntervalTimeline, IntervalTimelineEvent } from "./IntervalTimeline";
|
|
|
|
describe("IntervalTimeline", () => {
|
|
|
|
BasicTests(IntervalTimeline);
|
|
|
|
context("inserting/deleting events", () => {
|
|
|
|
it("accepts events into the timeline", () => {
|
|
const sched = new IntervalTimeline();
|
|
sched.add({
|
|
duration: 0.2,
|
|
state: "A",
|
|
time: 0,
|
|
});
|
|
sched.add({
|
|
duration: 0.4,
|
|
state: "B",
|
|
time: 1,
|
|
});
|
|
sched.add({
|
|
duration: 12,
|
|
state: "C",
|
|
time: 2,
|
|
});
|
|
sched.dispose();
|
|
});
|
|
|
|
it("computes the lenght of the timeline correctly after adding events", () => {
|
|
const sched = new IntervalTimeline();
|
|
sched.add({
|
|
duration: 0.2,
|
|
state: "A",
|
|
time: 0,
|
|
});
|
|
sched.add({
|
|
duration: 0.4,
|
|
state: "B",
|
|
time: 1,
|
|
});
|
|
sched.add({
|
|
duration: 12,
|
|
state: "C",
|
|
time: 2,
|
|
});
|
|
expect(sched.length).to.equal(3);
|
|
sched.dispose();
|
|
});
|
|
|
|
it("can remove events from the timeline", () => {
|
|
const sched = new IntervalTimeline();
|
|
|
|
const ev0 = {
|
|
duration: 0.2,
|
|
time: 0,
|
|
};
|
|
const ev1 = {
|
|
duration: 0.2,
|
|
time: 0.2,
|
|
};
|
|
const ev2 = {
|
|
duration: 0.2,
|
|
time: 0.1,
|
|
};
|
|
sched.add(ev0);
|
|
sched.add(ev1);
|
|
sched.add(ev2);
|
|
expect(sched.length).to.equal(3);
|
|
sched.remove(ev0);
|
|
sched.remove(ev1);
|
|
expect(sched.length).to.equal(1);
|
|
sched.remove(ev2);
|
|
expect(sched.length).to.equal(0);
|
|
sched.dispose();
|
|
});
|
|
|
|
it("removing on a null set does nothing", () => {
|
|
const sched = new IntervalTimeline();
|
|
expect(sched.length).to.equal(0);
|
|
// @ts-ignore
|
|
sched.remove({});
|
|
expect(sched.length).to.equal(0);
|
|
sched.dispose();
|
|
});
|
|
|
|
it("can add and remove and add again events from the timeline", () => {
|
|
const sched = new IntervalTimeline();
|
|
|
|
const ev0 = {
|
|
duration: 0.2,
|
|
time: 0,
|
|
};
|
|
const ev1 = {
|
|
duration: 0.2,
|
|
time: 0.2,
|
|
};
|
|
const ev2 = {
|
|
duration: 0.2,
|
|
time: 0.1,
|
|
};
|
|
sched.add(ev0);
|
|
sched.add(ev1);
|
|
sched.add(ev2);
|
|
expect(sched.length).to.equal(3);
|
|
sched.remove(ev0);
|
|
sched.remove(ev1);
|
|
expect(sched.length).to.equal(1);
|
|
sched.add(ev0);
|
|
sched.add(ev1);
|
|
expect(sched.length).to.equal(3);
|
|
sched.dispose();
|
|
});
|
|
|
|
it("throws an error if events do not have both time and duration attributes", () => {
|
|
const sched = new IntervalTimeline();
|
|
expect(() => {
|
|
// @ts-ignore
|
|
sched.add({
|
|
time: 0,
|
|
});
|
|
}).to.throw(Error);
|
|
expect(() => {
|
|
// @ts-ignore
|
|
sched.add({
|
|
duration: 0,
|
|
});
|
|
}).to.throw(Error);
|
|
sched.dispose();
|
|
});
|
|
|
|
});
|
|
|
|
context("getting events", () => {
|
|
|
|
it("returns null when no events are in the timeline", () => {
|
|
const sched = new IntervalTimeline();
|
|
expect(sched.get(3)).to.equal(null);
|
|
sched.dispose();
|
|
});
|
|
|
|
it("returns the event which overlaps the given time", () => {
|
|
const sched = new IntervalTimeline();
|
|
sched.add({
|
|
duration: Infinity,
|
|
state: "A",
|
|
time: 0,
|
|
});
|
|
sched.add({
|
|
duration: 0.4,
|
|
state: "B",
|
|
time: 1,
|
|
});
|
|
sched.add({
|
|
duration: 12,
|
|
state: "C",
|
|
time: 2,
|
|
});
|
|
// @ts-ignore
|
|
expect(sched.get(0.2).state).to.equal("A");
|
|
sched.dispose();
|
|
});
|
|
|
|
it("returns events exclusive of the end time", () => {
|
|
const sched = new IntervalTimeline();
|
|
sched.add({
|
|
duration: 1,
|
|
state: "A",
|
|
time: 0,
|
|
});
|
|
// @ts-ignore
|
|
expect(sched.get(0.99).state).to.equal("A");
|
|
expect(sched.get(1)).to.equal(null);
|
|
sched.dispose();
|
|
});
|
|
|
|
it("factors in start position and duration when checking for overlaps", () => {
|
|
const sched = new IntervalTimeline();
|
|
sched.add({
|
|
duration: 0.4,
|
|
time: 0,
|
|
});
|
|
expect(sched.get(0.5)).to.equal(null);
|
|
expect(sched.get(-1)).to.equal(null);
|
|
expect(sched.get(0)).to.not.equal(null);
|
|
expect(sched.get(0.39)).to.not.equal(null);
|
|
sched.dispose();
|
|
});
|
|
|
|
it("returns the event whose start is closest to the given time", () => {
|
|
const sched = new IntervalTimeline();
|
|
sched.add({
|
|
duration: Infinity,
|
|
state: "A",
|
|
time: 0,
|
|
});
|
|
sched.add({
|
|
duration: 0.4,
|
|
state: "B",
|
|
time: 0.2,
|
|
});
|
|
sched.add({
|
|
duration: 12,
|
|
state: "C",
|
|
time: 2,
|
|
});
|
|
// @ts-ignore
|
|
expect(sched.get(0.2).state).to.equal("B");
|
|
sched.dispose();
|
|
});
|
|
|
|
it("returns the events correctly after some events are removed", () => {
|
|
const sched = new IntervalTimeline();
|
|
const ev0 = {
|
|
duration: 0.2,
|
|
state: "A",
|
|
time: 0.1,
|
|
};
|
|
const ev1 = {
|
|
duration: 0.3,
|
|
state: "B",
|
|
time: 0.2,
|
|
};
|
|
const ev2 = {
|
|
duration: Infinity,
|
|
state: "C",
|
|
time: 0,
|
|
};
|
|
sched.add(ev0);
|
|
sched.add(ev1);
|
|
sched.add(ev2);
|
|
sched.remove(ev0);
|
|
sched.remove(ev1);
|
|
// @ts-ignore
|
|
expect(sched.get(0.2)).to.not.equal(null);
|
|
// @ts-ignore
|
|
expect(sched.get(0.2).state).to.equal("C");
|
|
sched.dispose();
|
|
});
|
|
|
|
it("can handle many items", () => {
|
|
const sched = new IntervalTimeline();
|
|
const len = 5000;
|
|
const events: IntervalTimelineEvent[] = [];
|
|
let duration = 1;
|
|
let time = 0;
|
|
for (let i = 0; i < len; i++) {
|
|
const event = {
|
|
duration,
|
|
time,
|
|
};
|
|
time = (time + 3.1) % 109;
|
|
duration = (duration + 5.7) % 19;
|
|
sched.add(event);
|
|
events.push(event);
|
|
}
|
|
// tslint:disable-next-line: prefer-for-of
|
|
for (let j = 0; j < events.length; j++) {
|
|
const event = events[j];
|
|
const eventVal = sched.get(event.time);
|
|
if (eventVal) {
|
|
expect(eventVal.time).to.equal(event.time);
|
|
}
|
|
}
|
|
|
|
for (let k = 0; k < events.length; k++) {
|
|
sched.remove(events[k]);
|
|
expect(sched.length).to.equal(events.length - k - 1);
|
|
}
|
|
sched.dispose();
|
|
});
|
|
|
|
});
|
|
|
|
context("cancelling", () => {
|
|
|
|
it("can cancel items after the given time", () => {
|
|
const sched = new IntervalTimeline();
|
|
for (let i = 5; i < 100; i++) {
|
|
sched.add({
|
|
duration: 10,
|
|
time: i,
|
|
});
|
|
}
|
|
sched.cancel(10);
|
|
expect(sched.length).to.equal(5);
|
|
sched.cancel(0);
|
|
expect(sched.length).to.equal(0);
|
|
sched.dispose();
|
|
});
|
|
|
|
it("can cancel items at the given time", () => {
|
|
const sched = new IntervalTimeline();
|
|
sched.add({
|
|
duration: 10,
|
|
time: 0,
|
|
});
|
|
sched.cancel(1);
|
|
expect(sched.length).to.equal(1);
|
|
sched.cancel(0);
|
|
expect(sched.length).to.equal(0);
|
|
sched.dispose();
|
|
});
|
|
});
|
|
|
|
context("Iterators", () => {
|
|
|
|
it("iterates over all items and returns and item", () => {
|
|
const sched = new IntervalTimeline();
|
|
sched.add({ time: 0, duration: 5 });
|
|
sched.add({ time: 0.1, duration: 5 });
|
|
sched.add({ time: 0.2, duration: 5 });
|
|
sched.add({ time: 0.3, duration: 5 });
|
|
sched.add({ time: 0.4, duration: 5 });
|
|
let count = 0;
|
|
sched.forEach((event) => {
|
|
expect(event).to.be.an("object");
|
|
count++;
|
|
});
|
|
expect(count).to.equal(5);
|
|
sched.dispose();
|
|
});
|
|
|
|
it("iterate over null set", () => {
|
|
const sched = new IntervalTimeline();
|
|
let count = 0;
|
|
sched.forEach(() => {
|
|
count++;
|
|
});
|
|
expect(count).to.equal(0);
|
|
sched.dispose();
|
|
});
|
|
|
|
it("iterates over all items overlapping the given time", () => {
|
|
const sched = new IntervalTimeline();
|
|
sched.add({ time: 0, duration: 5 });
|
|
sched.add({ time: 0.1, duration: 5 });
|
|
sched.add({ time: 0.2, duration: 5 });
|
|
sched.add({ time: 0.3, duration: 5 });
|
|
sched.add({ time: 0.4, duration: 5 });
|
|
let count = 0;
|
|
sched.forEachAtTime(0.3, (event) => {
|
|
expect(event).to.be.an("object");
|
|
expect(event.time).to.be.at.most(0.3);
|
|
count++;
|
|
});
|
|
expect(count).to.equal(4);
|
|
sched.dispose();
|
|
});
|
|
|
|
it("handles time ranges before the available objects", () => {
|
|
const sched = new IntervalTimeline();
|
|
sched.add({ time: 0.1, duration: 5 });
|
|
sched.add({ time: 0.2, duration: 5 });
|
|
sched.add({ time: 0.3, duration: 5 });
|
|
sched.add({ time: 0.4, duration: 5 });
|
|
let count = 0;
|
|
sched.forEachAtTime(0, () => {
|
|
count++;
|
|
});
|
|
expect(count).to.equal(0);
|
|
sched.dispose();
|
|
});
|
|
|
|
it("handles time ranges after the available objects", () => {
|
|
const sched = new IntervalTimeline();
|
|
sched.add({ time: 0.1, duration: 5 });
|
|
sched.add({ time: 0.2, duration: 5 });
|
|
sched.add({ time: 0.3, duration: 5 });
|
|
sched.add({ time: 0.4, duration: 5 });
|
|
let count = 0;
|
|
sched.forEachAtTime(5.5, () => {
|
|
count++;
|
|
});
|
|
expect(count).to.equal(0);
|
|
sched.dispose();
|
|
});
|
|
|
|
it("iterates over all items after the given time", () => {
|
|
const sched = new IntervalTimeline();
|
|
sched.add({ time: 0.1, duration: 5 });
|
|
sched.add({ time: 0.2, duration: 5 });
|
|
sched.add({ time: 0.3, duration: 5 });
|
|
sched.add({ time: 0.4, duration: 5 });
|
|
let count = 0;
|
|
sched.forEachFrom(0.2, (event) => {
|
|
expect(event).to.be.an("object");
|
|
expect(event.time).to.be.gte(0.2);
|
|
count++;
|
|
});
|
|
expect(count).to.equal(3);
|
|
count = 0;
|
|
sched.forEachFrom(0.35, (event) => {
|
|
expect(event.time).to.be.gte(0.35);
|
|
count++;
|
|
});
|
|
expect(count).to.equal(1);
|
|
sched.dispose();
|
|
});
|
|
|
|
it("handles time ranges after the available objects", () => {
|
|
const sched = new IntervalTimeline();
|
|
sched.add({ time: 0.1, duration: 5 });
|
|
sched.add({ time: 0.2, duration: 5 });
|
|
sched.add({ time: 0.3, duration: 5 });
|
|
sched.add({ time: 0.4, duration: 5 });
|
|
let count = 0;
|
|
sched.forEachFrom(0.5, () => {
|
|
count++;
|
|
});
|
|
expect(count).to.equal(0);
|
|
sched.dispose();
|
|
});
|
|
|
|
it("iterates over all items", () => {
|
|
const sched = new IntervalTimeline();
|
|
sched.add({ time: 0.1, duration: 5 });
|
|
sched.add({ time: 0.2, duration: 5 });
|
|
sched.add({ time: 0.3, duration: 5 });
|
|
sched.add({ time: 0.4, duration: 5 });
|
|
let count = 0;
|
|
sched.forEach(() => {
|
|
count++;
|
|
});
|
|
expect(count).to.equal(4);
|
|
sched.dispose();
|
|
});
|
|
|
|
it("can remove items during forEach iterations", () => {
|
|
const sched = new IntervalTimeline();
|
|
for (let i = 0; i < 1000; i++) {
|
|
sched.add({ time: i, duration: 0.01 });
|
|
}
|
|
sched.forEach((event) => {
|
|
sched.cancel(event.time);
|
|
});
|
|
expect(sched.length).to.equal(0);
|
|
sched.dispose();
|
|
});
|
|
|
|
it("can remove items during forEachAtTime iterations", () => {
|
|
const sched = new IntervalTimeline();
|
|
for (let i = 0; i < 1000; i++) {
|
|
sched.add({ time: i, duration: Infinity });
|
|
}
|
|
sched.forEachAtTime(1000, (event) => {
|
|
sched.cancel(event.time);
|
|
});
|
|
expect(sched.length).to.equal(0);
|
|
sched.dispose();
|
|
});
|
|
|
|
it("can remove items during forEachFrom iterations", () => {
|
|
const sched = new IntervalTimeline();
|
|
for (let i = 0; i < 1000; i++) {
|
|
sched.add({ time: i, duration: Infinity });
|
|
}
|
|
sched.forEachFrom(0, (event) => {
|
|
sched.remove(event);
|
|
});
|
|
expect(sched.length).to.equal(0);
|
|
sched.dispose();
|
|
});
|
|
});
|
|
});
|