tone 14.8.35 → 14.8.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Tone/component/analysis/Meter.test.ts +25 -0
- package/Tone/component/analysis/Meter.ts +7 -5
- package/Tone/core/clock/TickSource.test.ts +52 -0
- package/Tone/core/clock/TickSource.ts +70 -9
- package/Tone/core/clock/Ticker.ts +11 -5
- package/Tone/core/context/Context.test.ts +2 -0
- package/Tone/core/context/Context.ts +29 -38
- package/Tone/core/context/ToneAudioBuffer.ts +52 -27
- package/Tone/event/Pattern.test.ts +31 -5
- package/Tone/event/Pattern.ts +19 -6
- package/Tone/event/PatternGenerator.test.ts +18 -26
- package/Tone/event/PatternGenerator.ts +52 -59
- package/Tone/instrument/MetalSynth.ts +48 -21
- package/Tone/signal/ToneConstantSource.test.ts +1 -1
- package/Tone/source/OneShotSource.ts +1 -1
- package/Tone/source/buffer/Player.test.ts +25 -0
- package/Tone/source/buffer/Player.ts +1 -1
- package/Tone/source/oscillator/ToneOscillatorNode.test.ts +1 -1
- package/Tone/version.ts +1 -1
- package/build/Tone.js +1 -1
- package/build/Tone.js.map +1 -1
- package/build/esm/component/analysis/Meter.d.ts +1 -1
- package/build/esm/component/analysis/Meter.js +5 -7
- package/build/esm/component/analysis/Meter.js.map +1 -1
- package/build/esm/core/clock/TickSource.d.ts +8 -0
- package/build/esm/core/clock/TickSource.js +49 -7
- package/build/esm/core/clock/TickSource.js.map +1 -1
- package/build/esm/core/clock/Ticker.d.ts +5 -1
- package/build/esm/core/clock/Ticker.js +6 -4
- package/build/esm/core/clock/Ticker.js.map +1 -1
- package/build/esm/core/context/Context.d.ts +12 -12
- package/build/esm/core/context/Context.js +26 -29
- package/build/esm/core/context/Context.js.map +1 -1
- package/build/esm/core/context/ToneAudioBuffer.js +25 -15
- package/build/esm/core/context/ToneAudioBuffer.js.map +1 -1
- package/build/esm/event/Pattern.d.ts +8 -0
- package/build/esm/event/Pattern.js +11 -4
- package/build/esm/event/Pattern.js.map +1 -1
- package/build/esm/event/PatternGenerator.d.ts +4 -4
- package/build/esm/event/PatternGenerator.js +52 -58
- package/build/esm/event/PatternGenerator.js.map +1 -1
- package/build/esm/instrument/MetalSynth.d.ts +0 -1
- package/build/esm/instrument/MetalSynth.js +15 -13
- package/build/esm/instrument/MetalSynth.js.map +1 -1
- package/build/esm/source/OneShotSource.js +1 -1
- package/build/esm/source/OneShotSource.js.map +1 -1
- package/build/esm/source/buffer/Player.js +2 -1
- package/build/esm/source/buffer/Player.js.map +1 -1
- package/build/esm/version.js +1 -1
- package/docs/tone.json +1 -1
- package/package.json +2 -2
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
import { Envelope, EnvelopeOptions } from "../component/envelope/Envelope";
|
|
2
2
|
import { Filter } from "../component/filter/Filter";
|
|
3
3
|
import { Gain } from "../core/context/Gain";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import {
|
|
5
|
+
ToneAudioNode,
|
|
6
|
+
ToneAudioNodeOptions,
|
|
7
|
+
} from "../core/context/ToneAudioNode";
|
|
8
|
+
import {
|
|
9
|
+
Frequency,
|
|
10
|
+
NormalRange,
|
|
11
|
+
Positive,
|
|
12
|
+
Seconds,
|
|
13
|
+
Time,
|
|
14
|
+
} from "../core/type/Units";
|
|
15
|
+
import {
|
|
16
|
+
deepMerge,
|
|
17
|
+
omitFromObject,
|
|
18
|
+
optionsFromArguments,
|
|
19
|
+
} from "../core/util/Defaults";
|
|
7
20
|
import { noOp, RecursivePartial } from "../core/util/Interface";
|
|
8
21
|
import { Multiply } from "../signal/Multiply";
|
|
9
22
|
import { Scale } from "../signal/Scale";
|
|
@@ -23,17 +36,15 @@ export interface MetalSynthOptions extends MonophonicOptions {
|
|
|
23
36
|
* Inharmonic ratio of frequencies based on the Roland TR-808
|
|
24
37
|
* Taken from https://ccrma.stanford.edu/papers/tr-808-cymbal-physically-informed-circuit-bendable-digital-model
|
|
25
38
|
*/
|
|
26
|
-
const inharmRatios: number[] = [1.0, 1.483, 1.932, 2.546, 2.
|
|
39
|
+
const inharmRatios: number[] = [1.0, 1.483, 1.932, 2.546, 2.63, 3.897];
|
|
27
40
|
|
|
28
41
|
/**
|
|
29
42
|
* A highly inharmonic and spectrally complex source with a highpass filter
|
|
30
43
|
* and amplitude envelope which is good for making metallophone sounds.
|
|
31
44
|
* Based on CymbalSynth by [@polyrhythmatic](https://github.com/polyrhythmatic).
|
|
32
|
-
* Inspiration from [Sound on Sound](https://shorturl.at/rSZ12).
|
|
33
45
|
* @category Instrument
|
|
34
46
|
*/
|
|
35
47
|
export class MetalSynth extends Monophonic<MetalSynthOptions> {
|
|
36
|
-
|
|
37
48
|
readonly name: string = "MetalSynth";
|
|
38
49
|
|
|
39
50
|
/**
|
|
@@ -84,10 +95,13 @@ export class MetalSynth extends Monophonic<MetalSynthOptions> {
|
|
|
84
95
|
*/
|
|
85
96
|
readonly envelope: Envelope;
|
|
86
97
|
|
|
87
|
-
constructor(options?: RecursivePartial<MetalSynthOptions>)
|
|
98
|
+
constructor(options?: RecursivePartial<MetalSynthOptions>);
|
|
88
99
|
constructor() {
|
|
89
100
|
super(optionsFromArguments(MetalSynth.getDefaults(), arguments));
|
|
90
|
-
const options = optionsFromArguments(
|
|
101
|
+
const options = optionsFromArguments(
|
|
102
|
+
MetalSynth.getDefaults(),
|
|
103
|
+
arguments
|
|
104
|
+
);
|
|
91
105
|
|
|
92
106
|
this.detune = new Signal({
|
|
93
107
|
context: this.context,
|
|
@@ -158,12 +172,15 @@ export class MetalSynth extends Monophonic<MetalSynthOptions> {
|
|
|
158
172
|
static getDefaults(): MetalSynthOptions {
|
|
159
173
|
return deepMerge(Monophonic.getDefaults(), {
|
|
160
174
|
envelope: Object.assign(
|
|
161
|
-
omitFromObject(
|
|
175
|
+
omitFromObject(
|
|
176
|
+
Envelope.getDefaults(),
|
|
177
|
+
Object.keys(ToneAudioNode.getDefaults())
|
|
178
|
+
),
|
|
162
179
|
{
|
|
163
180
|
attack: 0.001,
|
|
164
181
|
decay: 1.4,
|
|
165
182
|
release: 0.2,
|
|
166
|
-
}
|
|
183
|
+
}
|
|
167
184
|
),
|
|
168
185
|
harmonicity: 5.1,
|
|
169
186
|
modulationIndex: 32,
|
|
@@ -177,24 +194,33 @@ export class MetalSynth extends Monophonic<MetalSynthOptions> {
|
|
|
177
194
|
* @param time When the attack should be triggered.
|
|
178
195
|
* @param velocity The velocity that the envelope should be triggered at.
|
|
179
196
|
*/
|
|
180
|
-
protected _triggerEnvelopeAttack(
|
|
197
|
+
protected _triggerEnvelopeAttack(
|
|
198
|
+
time: Seconds,
|
|
199
|
+
velocity: NormalRange = 1
|
|
200
|
+
): this {
|
|
181
201
|
this.envelope.triggerAttack(time, velocity);
|
|
182
|
-
this._oscillators.forEach(osc => osc.start(time));
|
|
202
|
+
this._oscillators.forEach((osc) => osc.start(time));
|
|
183
203
|
if (this.envelope.sustain === 0) {
|
|
184
|
-
this._oscillators.forEach(osc => {
|
|
185
|
-
osc.stop(
|
|
204
|
+
this._oscillators.forEach((osc) => {
|
|
205
|
+
osc.stop(
|
|
206
|
+
time +
|
|
207
|
+
this.toSeconds(this.envelope.attack) +
|
|
208
|
+
this.toSeconds(this.envelope.decay)
|
|
209
|
+
);
|
|
186
210
|
});
|
|
187
211
|
}
|
|
188
212
|
return this;
|
|
189
213
|
}
|
|
190
|
-
|
|
214
|
+
|
|
191
215
|
/**
|
|
192
216
|
* Trigger the release of the envelope.
|
|
193
217
|
* @param time When the release should be triggered.
|
|
194
218
|
*/
|
|
195
219
|
protected _triggerEnvelopeRelease(time: Seconds): this {
|
|
196
220
|
this.envelope.triggerRelease(time);
|
|
197
|
-
this._oscillators.forEach(osc =>
|
|
221
|
+
this._oscillators.forEach((osc) =>
|
|
222
|
+
osc.stop(time + this.toSeconds(this.envelope.release))
|
|
223
|
+
);
|
|
198
224
|
return this;
|
|
199
225
|
}
|
|
200
226
|
|
|
@@ -213,7 +239,7 @@ export class MetalSynth extends Monophonic<MetalSynthOptions> {
|
|
|
213
239
|
return this._oscillators[0].modulationIndex.value;
|
|
214
240
|
}
|
|
215
241
|
set modulationIndex(val) {
|
|
216
|
-
this._oscillators.forEach(osc => (osc.modulationIndex.value = val));
|
|
242
|
+
this._oscillators.forEach((osc) => (osc.modulationIndex.value = val));
|
|
217
243
|
}
|
|
218
244
|
|
|
219
245
|
/**
|
|
@@ -226,7 +252,7 @@ export class MetalSynth extends Monophonic<MetalSynthOptions> {
|
|
|
226
252
|
return this._oscillators[0].harmonicity.value;
|
|
227
253
|
}
|
|
228
254
|
set harmonicity(val) {
|
|
229
|
-
this._oscillators.forEach(osc => (osc.harmonicity.value = val));
|
|
255
|
+
this._oscillators.forEach((osc) => (osc.harmonicity.value = val));
|
|
230
256
|
}
|
|
231
257
|
|
|
232
258
|
/**
|
|
@@ -254,13 +280,14 @@ export class MetalSynth extends Monophonic<MetalSynthOptions> {
|
|
|
254
280
|
}
|
|
255
281
|
set octaves(val) {
|
|
256
282
|
this._octaves = val;
|
|
257
|
-
this._filterFreqScaler.max =
|
|
283
|
+
this._filterFreqScaler.max =
|
|
284
|
+
this._filterFreqScaler.min * Math.pow(2, val);
|
|
258
285
|
}
|
|
259
286
|
|
|
260
287
|
dispose(): this {
|
|
261
288
|
super.dispose();
|
|
262
|
-
this._oscillators.forEach(osc => osc.dispose());
|
|
263
|
-
this._freqMultipliers.forEach(freqMult => freqMult.dispose());
|
|
289
|
+
this._oscillators.forEach((osc) => osc.dispose());
|
|
290
|
+
this._freqMultipliers.forEach((freqMult) => freqMult.dispose());
|
|
264
291
|
this.frequency.dispose();
|
|
265
292
|
this.detune.dispose();
|
|
266
293
|
this._filterFreqScaler.dispose();
|
|
@@ -152,7 +152,7 @@ describe("ToneConstantSource", () => {
|
|
|
152
152
|
expect(source.getStateAtTime(0)).to.equal("stopped");
|
|
153
153
|
expect(source.getStateAtTime(currentTime)).to.equal("started");
|
|
154
154
|
setTimeout(() => {
|
|
155
|
-
currentTime = source.
|
|
155
|
+
currentTime = source.now();
|
|
156
156
|
source.stop(0);
|
|
157
157
|
expect(source.getStateAtTime(currentTime + 0.01)).to.equal("stopped");
|
|
158
158
|
source.dispose();
|
|
@@ -168,7 +168,7 @@ export abstract class OneShotSource<
|
|
|
168
168
|
|
|
169
169
|
// schedule the stop callback
|
|
170
170
|
this._stopTime = this.toSeconds(time) + fadeOutTime;
|
|
171
|
-
this._stopTime = Math.max(this._stopTime, this.
|
|
171
|
+
this._stopTime = Math.max(this._stopTime, this.now());
|
|
172
172
|
if (fadeOutTime > 0) {
|
|
173
173
|
// start the fade out curve at the given time
|
|
174
174
|
if (this._curve === "linear") {
|
|
@@ -696,5 +696,30 @@ describe("Player", () => {
|
|
|
696
696
|
expect(buff.getRmsAtTime(duration + 0.1)).to.be.closeTo(0, 0.1);
|
|
697
697
|
});
|
|
698
698
|
});
|
|
699
|
+
|
|
700
|
+
it("stops only last activeSource when restarting at intervals < latencyHint", (done) => {
|
|
701
|
+
const originalLookAhead = getContext().lookAhead;
|
|
702
|
+
getContext().lookAhead = .3;
|
|
703
|
+
const player = new Player({
|
|
704
|
+
onload(): void {
|
|
705
|
+
player.start(undefined, undefined, 1);
|
|
706
|
+
setTimeout(() => player.restart(undefined, undefined, 1), 50);
|
|
707
|
+
setTimeout(() => player.restart(undefined, undefined, 1), 100);
|
|
708
|
+
setTimeout(() => player.restart(undefined, undefined, 1), 150);
|
|
709
|
+
setTimeout(() => {
|
|
710
|
+
player.restart(undefined, undefined, 1);
|
|
711
|
+
const checkStopTimes = new Set();
|
|
712
|
+
player["_activeSources"].forEach(source => {
|
|
713
|
+
checkStopTimes.add(source["_stopTime"]);
|
|
714
|
+
});
|
|
715
|
+
getContext().lookAhead = originalLookAhead;
|
|
716
|
+
// ensure each source has a different stopTime
|
|
717
|
+
expect(checkStopTimes.size).to.equal(player["_activeSources"].size);
|
|
718
|
+
done();
|
|
719
|
+
}, 250);
|
|
720
|
+
},
|
|
721
|
+
url: "./audio/sine.wav",
|
|
722
|
+
});
|
|
723
|
+
});
|
|
699
724
|
});
|
|
700
725
|
});
|
|
@@ -284,7 +284,7 @@ export class Player extends Source<PlayerOptions> {
|
|
|
284
284
|
}
|
|
285
285
|
|
|
286
286
|
protected _restart(time?: Seconds, offset?: Time, duration?: Time): void {
|
|
287
|
-
this.
|
|
287
|
+
[...this._activeSources].pop()?.stop(time); // explicitly stop only the most recently created source, to avoid edge case when > 1 source exists and _stop() erroneously sets all stop times past original end offset
|
|
288
288
|
this._start(time, offset, duration);
|
|
289
289
|
}
|
|
290
290
|
|
|
@@ -191,7 +191,7 @@ describe("ToneOscillatorNode", () => {
|
|
|
191
191
|
expect(osc.getStateAtTime(0)).to.equal("stopped");
|
|
192
192
|
expect(osc.getStateAtTime(currentTime)).to.equal("started");
|
|
193
193
|
setTimeout(() => {
|
|
194
|
-
currentTime = osc.
|
|
194
|
+
currentTime = osc.now();
|
|
195
195
|
osc.stop(0);
|
|
196
196
|
expect(osc.getStateAtTime(currentTime + 0.01)).to.equal("stopped");
|
|
197
197
|
osc.dispose();
|
package/Tone/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version: string = "14.8.
|
|
1
|
+
export const version: string = "14.8.38";
|