From 9306e5188c0904a6a99eb1ba1753bdc5f5dc39ab Mon Sep 17 00:00:00 2001 From: Yotam Mann Date: Tue, 23 Jul 2019 13:43:11 -0400 Subject: [PATCH] adding additional option to StateTimeline.add enables more strict typing of returned object --- Tone/core/util/StateTimeline.ts | 27 +++++++++++---------------- Tone/event/ToneEvent.ts | 18 +++++++++--------- Tone/source/buffer/Player.ts | 7 +++---- 3 files changed, 23 insertions(+), 29 deletions(-) diff --git a/Tone/core/util/StateTimeline.ts b/Tone/core/util/StateTimeline.ts index 80acf6e2..50404c2c 100644 --- a/Tone/core/util/StateTimeline.ts +++ b/Tone/core/util/StateTimeline.ts @@ -1,24 +1,18 @@ // import "../type/Type"; import { Timeline, TimelineEvent } from "./Timeline"; -export type PlaybackState = "started" | "stopped" | "paused"; +export type BasicPlaybackState = "started" | "stopped"; +export type PlaybackState = BasicPlaybackState | "paused"; export interface StateTimelineEvent extends TimelineEvent { state: PlaybackState; - duration?: Seconds; - offset?: Seconds; - /** - * Either the buffer is explicitly scheduled to end using the stop method, - * or it's implicitly ended when the buffer is over. - */ - implicitEnd?: boolean; } /** * A Timeline State. Provides the methods: `setStateAtTime("state", time)` and `getValueAtTime(time)` * @param initial The initial state of the StateTimeline. Defaults to `undefined` */ -export class StateTimeline extends Timeline { +export class StateTimeline extends Timeline { /** * The initial state @@ -47,16 +41,17 @@ export class StateTimeline extends Timeline { /** * Add a state to the timeline. - * @param state The name of the state to set. - * @param time The time to query. + * @param state The name of the state to set. + * @param time The time to query. + * @param options Any additional options that are needed in the timeline. */ - setStateAtTime(state: PlaybackState, time: Seconds): this { + setStateAtTime(state: PlaybackState, time: Seconds, options?: AdditionalOptions): this { // all state changes need to be >= the previous state time // TODO throw error if time < the previous event time - this.add({ + this.add(Object.assign({}, options, { state, time, - }); + })); return this; } @@ -66,7 +61,7 @@ export class StateTimeline extends Timeline { * @param time When to check before * @return The event with the given state before the time */ - getLastState(state: PlaybackState, time: number): StateTimelineEvent | undefined { + getLastState(state: PlaybackState, time: number): StateTimelineEvent & AdditionalOptions | undefined { // time = this.toSeconds(time); const index = this._search(time); for (let i = index; i >= 0; i--) { @@ -83,7 +78,7 @@ export class StateTimeline extends Timeline { * @param time When to check from * @return The event with the given state after the time */ - getNextState(state: PlaybackState, time: number): StateTimelineEvent | undefined { + getNextState(state: PlaybackState, time: number): StateTimelineEvent & AdditionalOptions | undefined { // time = this.toSeconds(time); const index = this._search(time); if (index !== -1) { diff --git a/Tone/event/ToneEvent.ts b/Tone/event/ToneEvent.ts index 71de0eb9..d58af162 100644 --- a/Tone/event/ToneEvent.ts +++ b/Tone/event/ToneEvent.ts @@ -3,7 +3,7 @@ import { ToneWithContext, ToneWithContextOptions } from "../core/context/ToneWit import { TicksClass } from "../core/type/Ticks"; import { defaultArg, optionsFromArguments } from "../core/util/Defaults"; import { noOp } from "../core/util/Interface"; -import { PlaybackState, StateTimeline } from "../core/util/StateTimeline"; +import { BasicPlaybackState, StateTimeline } from "../core/util/StateTimeline"; import { isBoolean, isDefined, isNumber } from "../core/util/TypeCheck"; type ToneEventCallback = (time: Seconds, value: any) => void; @@ -71,7 +71,7 @@ export class ToneEvent extends ToneWithContext { /** * Tracks the scheduled events */ - private _state: StateTimeline = new StateTimeline("stopped"); + private _state: StateTimeline<{id: number}> = new StateTimeline("stopped"); /** * The playback speed of the note. A speed of 1 @@ -143,7 +143,7 @@ export class ToneEvent extends ToneWithContext { this._state.forEachFrom(after, event => { let duration; if (event.state === "started") { - if (isDefined(event.id)) { + if (event.id !== -1) { this.context.transport.clear(event.id); } const startTick = event.time + Math.round(this.startOffset / this._playbackRate); @@ -158,7 +158,7 @@ export class ToneEvent extends ToneWithContext { } if (duration !== Infinity) { // schedule a stop since it's finite duration - this._state.setStateAtTime("stopped", startTick + duration + 1); + this._state.setStateAtTime("stopped", startTick + duration + 1, { id : -1 }); duration = new TicksClass(this.context, duration); } const interval = new TicksClass(this.context, this._getLoopDuration()); @@ -174,8 +174,8 @@ export class ToneEvent extends ToneWithContext { /** * Returns the playback state of the note, either "started" or "stopped". */ - get state(): PlaybackState { - return this._state.getValueAtTime(this.context.transport.ticks); + get state(): BasicPlaybackState { + return this._state.getValueAtTime(this.context.transport.ticks) as BasicPlaybackState; } /** @@ -221,7 +221,7 @@ export class ToneEvent extends ToneWithContext { time = this.toTicks(time); if (this._state.getValueAtTime(time) === "stopped") { this._state.add({ - id : undefined, + id : -1, state : "started", time, }); @@ -238,7 +238,7 @@ export class ToneEvent extends ToneWithContext { this.cancel(time); time = this.toTicks(time); if (this._state.getValueAtTime(time) === "started") { - this._state.setStateAtTime("stopped", time); + this._state.setStateAtTime("stopped", time, { id: -1 }); const previousEvent = this._state.getBefore(time); let reschedulTime = time; if (previousEvent !== null) { @@ -257,7 +257,7 @@ export class ToneEvent extends ToneWithContext { time = defaultArg(time, -Infinity); time = this.toTicks(time); this._state.forEachFrom(time, event => { - this.context.transport.clear(event.id as number); + this.context.transport.clear(event.id); }); this._state.cancel(time); return this; diff --git a/Tone/source/buffer/Player.ts b/Tone/source/buffer/Player.ts index 2f3383d4..ac45994f 100644 --- a/Tone/source/buffer/Player.ts +++ b/Tone/source/buffer/Player.ts @@ -1,4 +1,3 @@ -import { StateTimelineEvent } from "Tone/core/util/StateTimeline"; import { ToneAudioBuffer } from "../../core/context/ToneAudioBuffer"; import { defaultArg, optionsFromArguments } from "../../core/util/Defaults"; import { noOp } from "../../core/util/Interface"; @@ -220,9 +219,9 @@ export class Player extends Source { // set the looping properties if (!this._loop && !this._synced) { // if it's not looping, set the state change at the end of the sample - this._state.setStateAtTime("stopped", startTime + computedDuration); - // mark that ending as an implicit ending - (this._state.get(startTime + computedDuration) as StateTimelineEvent).implicitEnd = true; + this._state.setStateAtTime("stopped", startTime + computedDuration, { + implicitEnd: true, + }); } // add it to the array of active sources