Skip to content

Commit

Permalink
feat: Render a segment of the envelope as an array
Browse files Browse the repository at this point in the history
  • Loading branch information
tambien committed Oct 8, 2019
1 parent 9ad519e commit fc5b6f7
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 0 deletions.
14 changes: 14 additions & 0 deletions Tone/component/envelope/Envelope.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,20 @@ describe("Envelope", () => {
});
});

it("can render the envelope to a curve", async () => {
const env = new Envelope();
const curve = await env.asArray();
curve.forEach(v => expect(v).to.be.within(0, 1));
env.dispose();
});

it("can render the envelope to an array with a given length", async () => {
const env = new Envelope();
const curve = await env.asArray(256);
expect(curve.length).to.equal(256);
env.dispose();
});

it("can retrigger partial envelope with custom type", () => {
return Offline(() => {
const env = new Envelope({
Expand Down
22 changes: 22 additions & 0 deletions Tone/component/envelope/Envelope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { NormalRange, Time } from "../../core/type/Units";
import { optionsFromArguments } from "../../core/util/Defaults";
import { isArray, isObject, isString } from "../../core/util/TypeCheck";
import { connectSignal, Signal } from "../../signal/Signal";
import { OfflineContext } from "../../core/context/OfflineContext";

type BasicEnvelopeCurve = "linear" | "exponential";
type InternalEnvelopeCurve = BasicEnvelopeCurve | number[];
Expand Down Expand Up @@ -438,6 +439,27 @@ export class Envelope extends ToneAudioNode<EnvelopeOptions> {
return this;
}

/**
* Render the envelope curve to an array of the given length.
* Good for visualizing the envelope curve
*/
async asArray(length: number = 1024): Promise<Float32Array> {
const duration = length / this.context.sampleRate;
const context = new OfflineContext(1, duration, this.context.sampleRate);
// normalize the ADSR for the given duration with 20% sustain time
const totalDuration = (this.toSeconds(this.attack) + this.toSeconds(this.decay) + this.toSeconds(this.release)) * 1.2;
// @ts-ignore
const clone = new this.constructor(Object.assign(this.get(), {
attack: duration * this.toSeconds(this.attack) / totalDuration,
decay: duration * this.toSeconds(this.decay) / totalDuration,
release: duration * this.toSeconds(this.release) / totalDuration,
context
})).toDestination() as Envelope;
clone.triggerAttackRelease(duration * 0.2, 0);
const buffer = await context.render();
return buffer.getChannelData(0);
}

dispose(): this {
super.dispose();
this._sig.dispose();
Expand Down

0 comments on commit fc5b6f7

Please sign in to comment.