tone 14.9.14 → 14.9.16
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/README.md +78 -61
- package/Tone/core/context/ToneWithContext.ts +45 -14
- package/Tone/event/Part.ts +2 -2
- package/Tone/event/Sequence.ts +2 -2
- package/Tone/index.ts +13 -9
- package/Tone/signal/SyncedSignal.ts +1 -0
- package/Tone/signal/WaveShaper.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/core/context/ToneWithContext.js +15 -8
- package/build/esm/core/context/ToneWithContext.js.map +1 -1
- package/build/esm/event/Part.d.ts +2 -2
- package/build/esm/event/Sequence.d.ts +2 -2
- package/build/esm/index.d.ts +13 -9
- package/build/esm/index.js.map +1 -1
- package/build/esm/signal/SyncedSignal.js.map +1 -1
- package/build/esm/signal/WaveShaper.d.ts +1 -1
- package/build/esm/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
Tone.js
|
|
2
|
-
=========
|
|
1
|
+
# Tone.js
|
|
3
2
|
|
|
4
3
|
[](https://codecov.io/gh/Tonejs/Tone.js)
|
|
5
4
|
|
|
6
|
-
|
|
7
5
|
Tone.js is a Web Audio framework for creating interactive music in the browser. The architecture of Tone.js aims to be familiar to both musicians and audio programmers creating web-based audio applications. On the high-level, Tone offers common DAW (digital audio workstation) features like a global transport for synchronizing and scheduling events as well as prebuilt synths and effects. Additionally, Tone provides high-performance building blocks to create your own synthesizers, effects, and complex control signals.
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
- [API](https://tonejs.github.io/docs/)
|
|
8
|
+
- [Examples](https://tonejs.github.io/examples/)
|
|
11
9
|
|
|
12
10
|
# Installation
|
|
13
11
|
|
|
@@ -21,7 +19,7 @@ npm install tone@next // Or, alternatively, use the 'next' version
|
|
|
21
19
|
Add Tone.js to a project using the JavaScript `import` syntax:
|
|
22
20
|
|
|
23
21
|
```js
|
|
24
|
-
import * as Tone from
|
|
22
|
+
import * as Tone from "tone";
|
|
25
23
|
```
|
|
26
24
|
|
|
27
25
|
Tone.js is also hosted at unpkg.com. It can be added directly within an HTML document, as long as it precedes any project scripts. [See the example here](https://github.com/Tonejs/Tone.js/blob/master/examples/simpleHtml.html) for more details.
|
|
@@ -40,46 +38,46 @@ const synth = new Tone.Synth().toDestination();
|
|
|
40
38
|
synth.triggerAttackRelease("C4", "8n");
|
|
41
39
|
```
|
|
42
40
|
|
|
43
|
-
|
|
41
|
+
## Tone.Synth
|
|
44
42
|
|
|
45
43
|
`Tone.Synth` is a basic synthesizer with a single oscillator and an ADSR envelope.
|
|
46
44
|
|
|
47
|
-
|
|
45
|
+
### triggerAttack / triggerRelease
|
|
48
46
|
|
|
49
47
|
`triggerAttack` starts the note (the amplitude is rising), and `triggerRelease` is when the amplitude is going back to 0 (i.e. **note off**).
|
|
50
48
|
|
|
51
49
|
```javascript
|
|
52
50
|
const synth = new Tone.Synth().toDestination();
|
|
53
|
-
const now = Tone.now()
|
|
51
|
+
const now = Tone.now();
|
|
54
52
|
// trigger the attack immediately
|
|
55
|
-
synth.triggerAttack("C4", now)
|
|
53
|
+
synth.triggerAttack("C4", now);
|
|
56
54
|
// wait one second before triggering the release
|
|
57
|
-
synth.triggerRelease(now + 1)
|
|
55
|
+
synth.triggerRelease(now + 1);
|
|
58
56
|
```
|
|
59
57
|
|
|
60
|
-
|
|
58
|
+
### triggerAttackRelease
|
|
61
59
|
|
|
62
60
|
`triggerAttackRelease` is a combination of `triggerAttack` and `triggerRelease`
|
|
63
61
|
|
|
64
|
-
The first argument to the note which can either be a frequency in hertz (like `440`) or as "pitch-octave" notation (like `"D#2"`).
|
|
62
|
+
The first argument to the note which can either be a frequency in hertz (like `440`) or as "pitch-octave" notation (like `"D#2"`).
|
|
65
63
|
|
|
66
|
-
The second argument is the duration that the note is held. This value can either be in seconds, or as a [tempo-relative value](https://github.com/Tonejs/Tone.js/wiki/Time).
|
|
64
|
+
The second argument is the duration that the note is held. This value can either be in seconds, or as a [tempo-relative value](https://github.com/Tonejs/Tone.js/wiki/Time).
|
|
67
65
|
|
|
68
66
|
The third (optional) argument of `triggerAttackRelease` is _when_ along the AudioContext time the note should play. It can be used to schedule events in the future.
|
|
69
67
|
|
|
70
68
|
```javascript
|
|
71
69
|
const synth = new Tone.Synth().toDestination();
|
|
72
|
-
const now = Tone.now()
|
|
73
|
-
synth.triggerAttackRelease("C4", "8n", now)
|
|
74
|
-
synth.triggerAttackRelease("E4", "8n", now + 0.5)
|
|
75
|
-
synth.triggerAttackRelease("G4", "8n", now + 1)
|
|
70
|
+
const now = Tone.now();
|
|
71
|
+
synth.triggerAttackRelease("C4", "8n", now);
|
|
72
|
+
synth.triggerAttackRelease("E4", "8n", now + 0.5);
|
|
73
|
+
synth.triggerAttackRelease("G4", "8n", now + 1);
|
|
76
74
|
```
|
|
77
75
|
|
|
78
|
-
|
|
76
|
+
## Time
|
|
79
77
|
|
|
80
78
|
Web Audio has advanced, sample accurate scheduling capabilities. The AudioContext time is what the Web Audio API uses to schedule events, starts at 0 when the page loads and counts up in **seconds**.
|
|
81
79
|
|
|
82
|
-
`Tone.now()` gets the current time of the AudioContext.
|
|
80
|
+
`Tone.now()` gets the current time of the AudioContext.
|
|
83
81
|
|
|
84
82
|
```javascript
|
|
85
83
|
setInterval(() => console.log(Tone.now()), 100);
|
|
@@ -91,21 +89,21 @@ Tone.js abstracts away the AudioContext time. Instead of defining all values in
|
|
|
91
89
|
|
|
92
90
|
# Starting Audio
|
|
93
91
|
|
|
94
|
-
**IMPORTANT**: Browsers will not play _any_ audio until a user clicks something (like a play button). Run your Tone.js code only after calling `Tone.start()` from a event listener which is triggered by a user action such as "click" or "keydown".
|
|
92
|
+
**IMPORTANT**: Browsers will not play _any_ audio until a user clicks something (like a play button). Run your Tone.js code only after calling `Tone.start()` from a event listener which is triggered by a user action such as "click" or "keydown".
|
|
95
93
|
|
|
96
94
|
`Tone.start()` returns a promise, the audio will be ready only after that promise is resolved. Scheduling or playing audio before the AudioContext is running will result in silence or incorrect scheduling.
|
|
97
95
|
|
|
98
96
|
```javascript
|
|
99
97
|
//attach a click listener to a play button
|
|
100
|
-
document.querySelector(
|
|
101
|
-
await Tone.start()
|
|
102
|
-
console.log(
|
|
103
|
-
})
|
|
104
|
-
```
|
|
98
|
+
document.querySelector("button")?.addEventListener("click", async () => {
|
|
99
|
+
await Tone.start();
|
|
100
|
+
console.log("audio is ready");
|
|
101
|
+
});
|
|
102
|
+
```
|
|
105
103
|
|
|
106
104
|
# Scheduling
|
|
107
105
|
|
|
108
|
-
|
|
106
|
+
## Transport
|
|
109
107
|
|
|
110
108
|
`Tone.getTransport()` returns the main timekeeper. Unlike the AudioContext clock, it can be started, stopped, looped and adjusted on the fly. You can think of it like the arrangement view in a Digital Audio Workstation.
|
|
111
109
|
|
|
@@ -116,72 +114,76 @@ Multiple events and parts can be arranged and synchronized along the Transport.
|
|
|
116
114
|
const synthA = new Tone.FMSynth().toDestination();
|
|
117
115
|
const synthB = new Tone.AMSynth().toDestination();
|
|
118
116
|
//play a note every quarter-note
|
|
119
|
-
const loopA = new Tone.Loop(time => {
|
|
117
|
+
const loopA = new Tone.Loop((time) => {
|
|
120
118
|
synthA.triggerAttackRelease("C2", "8n", time);
|
|
121
119
|
}, "4n").start(0);
|
|
122
120
|
//play another note every off quarter-note, by starting it "8n"
|
|
123
|
-
const loopB = new Tone.Loop(time => {
|
|
121
|
+
const loopB = new Tone.Loop((time) => {
|
|
124
122
|
synthB.triggerAttackRelease("C4", "8n", time);
|
|
125
123
|
}, "4n").start("8n");
|
|
126
124
|
// all loops start when the Transport is started
|
|
127
|
-
Tone.getTransport().start()
|
|
125
|
+
Tone.getTransport().start();
|
|
126
|
+
// ramp up to 800 bpm over 10 seconds
|
|
127
|
+
Tone.getTransport().bpm.rampTo(800, 10);
|
|
128
128
|
```
|
|
129
129
|
|
|
130
130
|
Since Javascript callbacks are **not precisely timed**, the sample-accurate time of the event is passed into the callback function. **Use this time value to schedule the events**.
|
|
131
131
|
|
|
132
132
|
# Instruments
|
|
133
133
|
|
|
134
|
-
There are numerous synths to choose from including `Tone.FMSynth`, `Tone.AMSynth` and `Tone.NoiseSynth`.
|
|
134
|
+
There are numerous synths to choose from including `Tone.FMSynth`, `Tone.AMSynth` and `Tone.NoiseSynth`.
|
|
135
135
|
|
|
136
|
-
All of these instruments are **monophonic** (single voice) which means that they can only play one note at a time.
|
|
136
|
+
All of these instruments are **monophonic** (single voice) which means that they can only play one note at a time.
|
|
137
137
|
|
|
138
|
-
To create a **polyphonic** synthesizer, use `Tone.PolySynth`, which accepts a monophonic synth as its first parameter and automatically handles the note allocation so you can pass in multiple notes. The API is similar to the monophonic synths, except `triggerRelease` must be given a note or array of notes.
|
|
138
|
+
To create a **polyphonic** synthesizer, use `Tone.PolySynth`, which accepts a monophonic synth as its first parameter and automatically handles the note allocation so you can pass in multiple notes. The API is similar to the monophonic synths, except `triggerRelease` must be given a note or array of notes.
|
|
139
139
|
|
|
140
140
|
```javascript
|
|
141
|
-
//pass in some initial values for the filter and filter envelope
|
|
142
141
|
const synth = new Tone.PolySynth(Tone.Synth).toDestination();
|
|
143
|
-
const now = Tone.now()
|
|
142
|
+
const now = Tone.now();
|
|
144
143
|
synth.triggerAttack("D4", now);
|
|
145
144
|
synth.triggerAttack("F4", now + 0.5);
|
|
146
145
|
synth.triggerAttack("A4", now + 1);
|
|
147
|
-
synth.triggerAttack("
|
|
148
|
-
synth.triggerAttack("
|
|
149
|
-
synth.triggerRelease(["D4", "F4", "A4", "
|
|
146
|
+
synth.triggerAttack("C5", now + 1.5);
|
|
147
|
+
synth.triggerAttack("E5", now + 2);
|
|
148
|
+
synth.triggerRelease(["D4", "F4", "A4", "C5", "E5"], now + 4);
|
|
150
149
|
```
|
|
151
150
|
|
|
152
151
|
# Samples
|
|
153
152
|
|
|
154
|
-
Sound generation is not limited to synthesized sounds. You can also load a sample and play that back in a number of ways. `Tone.Player` is one way to load and play back an audio file.
|
|
153
|
+
Sound generation is not limited to synthesized sounds. You can also load a sample and play that back in a number of ways. `Tone.Player` is one way to load and play back an audio file.
|
|
155
154
|
|
|
156
155
|
```javascript
|
|
157
|
-
const player = new Tone.Player(
|
|
156
|
+
const player = new Tone.Player(
|
|
157
|
+
"https://tonejs.github.io/audio/berklee/gong_1.mp3"
|
|
158
|
+
).toDestination();
|
|
158
159
|
Tone.loaded().then(() => {
|
|
159
160
|
player.start();
|
|
160
161
|
});
|
|
161
162
|
```
|
|
162
163
|
|
|
163
|
-
`Tone.loaded()` returns a promise which resolves when _all_ audio files are loaded. It's a helpful shorthand instead of waiting on each individual audio buffer's `onload` event to resolve.
|
|
164
|
+
`Tone.loaded()` returns a promise which resolves when _all_ audio files are loaded. It's a helpful shorthand instead of waiting on each individual audio buffer's `onload` event to resolve.
|
|
164
165
|
|
|
165
|
-
## Sampler
|
|
166
|
+
## Tone.Sampler
|
|
166
167
|
|
|
167
|
-
Multiple samples can also be combined into an instrument. If you have audio files organized by note, `Tone.Sampler` will pitch shift the samples to fill in gaps between notes. So for example, if you only have every 3rd note on a piano sampled, you could turn that into a full piano sample.
|
|
168
|
+
Multiple samples can also be combined into an instrument. If you have audio files organized by note, `Tone.Sampler` will pitch shift the samples to fill in gaps between notes. So for example, if you only have every 3rd note on a piano sampled, you could turn that into a full piano sample.
|
|
168
169
|
|
|
169
170
|
Unlike the other synths, Tone.Sampler is polyphonic so doesn't need to be passed into Tone.PolySynth
|
|
170
171
|
|
|
171
172
|
```javascript
|
|
172
173
|
const sampler = new Tone.Sampler({
|
|
173
174
|
urls: {
|
|
174
|
-
|
|
175
|
+
C4: "C4.mp3",
|
|
175
176
|
"D#4": "Ds4.mp3",
|
|
176
177
|
"F#4": "Fs4.mp3",
|
|
177
|
-
|
|
178
|
+
A4: "A4.mp3",
|
|
178
179
|
},
|
|
180
|
+
release: 1,
|
|
179
181
|
baseUrl: "https://tonejs.github.io/audio/salamander/",
|
|
180
182
|
}).toDestination();
|
|
181
183
|
|
|
182
184
|
Tone.loaded().then(() => {
|
|
183
|
-
sampler.triggerAttackRelease(["Eb4", "G4", "Bb4"],
|
|
184
|
-
})
|
|
185
|
+
sampler.triggerAttackRelease(["Eb4", "G4", "Bb4"], 4);
|
|
186
|
+
});
|
|
185
187
|
```
|
|
186
188
|
|
|
187
189
|
# Effects
|
|
@@ -193,22 +195,35 @@ const player = new Tone.Player({
|
|
|
193
195
|
url: "https://tonejs.github.io/audio/berklee/gurgling_theremin_1.mp3",
|
|
194
196
|
loop: true,
|
|
195
197
|
autostart: true,
|
|
196
|
-
})
|
|
198
|
+
});
|
|
197
199
|
//create a distortion effect
|
|
198
200
|
const distortion = new Tone.Distortion(0.4).toDestination();
|
|
199
201
|
//connect a player to the distortion
|
|
200
202
|
player.connect(distortion);
|
|
201
203
|
```
|
|
202
204
|
|
|
203
|
-
The connection routing is
|
|
205
|
+
The connection routing is flexible, connections can run serially or in parallel.
|
|
206
|
+
|
|
207
|
+
```javascript
|
|
208
|
+
const player = new Tone.Player({
|
|
209
|
+
url: "https://tonejs.github.io/audio/drum-samples/loops/ominous.mp3",
|
|
210
|
+
autostart: true,
|
|
211
|
+
});
|
|
212
|
+
const filter = new Tone.Filter(400, "lowpass").toDestination();
|
|
213
|
+
const feedbackDelay = new Tone.FeedbackDelay(0.125, 0.5).toDestination();
|
|
214
|
+
|
|
215
|
+
// connect the player to the feedback delay and filter in parallel
|
|
216
|
+
player.connect(filter);
|
|
217
|
+
player.connect(feedbackDelay);
|
|
218
|
+
```
|
|
204
219
|
|
|
205
|
-
`Tone.Gain` is
|
|
220
|
+
Multiple nodes can be connected to the same input enabling sources to share effects. `Tone.Gain` is useful utility node for creating complex routing.
|
|
206
221
|
|
|
207
222
|
# Signals
|
|
208
223
|
|
|
209
224
|
Like the underlying Web Audio API, Tone.js is built with audio-rate signal control over nearly everything. This is a powerful feature which allows for sample-accurate synchronization and scheduling of parameters.
|
|
210
225
|
|
|
211
|
-
`Signal` properties have a few built in methods for creating automation curves.
|
|
226
|
+
`Signal` properties have a few built in methods for creating automation curves.
|
|
212
227
|
|
|
213
228
|
For example, the `frequency` parameter on `Oscillator` is a Signal so you can create a smooth ramp from one frequency to another.
|
|
214
229
|
|
|
@@ -216,8 +231,10 @@ For example, the `frequency` parameter on `Oscillator` is a Signal so you can cr
|
|
|
216
231
|
const osc = new Tone.Oscillator().toDestination();
|
|
217
232
|
// start at "C4"
|
|
218
233
|
osc.frequency.value = "C4";
|
|
219
|
-
// ramp to "
|
|
220
|
-
osc.frequency.rampTo("
|
|
234
|
+
// ramp to "C2" over 2 seconds
|
|
235
|
+
osc.frequency.rampTo("C2", 2);
|
|
236
|
+
// start the oscillator for 2 seconds
|
|
237
|
+
osc.start().stop("+3");
|
|
221
238
|
```
|
|
222
239
|
|
|
223
240
|
# AudioContext
|
|
@@ -230,13 +247,13 @@ To use MIDI files, you'll first need to convert them into a JSON format which To
|
|
|
230
247
|
|
|
231
248
|
# Performance
|
|
232
249
|
|
|
233
|
-
Tone.js makes extensive use of the native Web Audio Nodes such as the GainNode and WaveShaperNode for all signal processing, which enables Tone.js to work well on both desktop and mobile browsers.
|
|
250
|
+
Tone.js makes extensive use of the native Web Audio Nodes such as the GainNode and WaveShaperNode for all signal processing, which enables Tone.js to work well on both desktop and mobile browsers.
|
|
234
251
|
|
|
235
252
|
[This wiki](https://github.com/Tonejs/Tone.js/wiki/Performance) article has some suggestions related to performance for best practices.
|
|
236
253
|
|
|
237
254
|
# Testing
|
|
238
255
|
|
|
239
|
-
Tone.js runs an extensive test suite using [mocha](https://mochajs.org/) and [chai](http://chaijs.com/) with nearly 100% coverage. Passing builds on the 'dev' branch are published on npm as `tone@next`.
|
|
256
|
+
Tone.js runs an extensive test suite using [mocha](https://mochajs.org/) and [chai](http://chaijs.com/) with nearly 100% coverage. Passing builds on the 'dev' branch are published on npm as `tone@next`.
|
|
240
257
|
|
|
241
258
|
# Contributing
|
|
242
259
|
|
|
@@ -246,9 +263,9 @@ If you have questions (or answers) that are not necessarily bugs/issues, please
|
|
|
246
263
|
|
|
247
264
|
# References and Inspiration
|
|
248
265
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
266
|
+
- [Many of Chris Wilson's Repositories](https://github.com/cwilso)
|
|
267
|
+
- [Many of Mohayonao's Repositories](https://github.com/mohayonao)
|
|
268
|
+
- [The Spec](http://webaudio.github.io/web-audio-api/)
|
|
269
|
+
- [Sound on Sound - Synth Secrets](http://www.soundonsound.com/sos/may99/articles/synthsec.htm)
|
|
270
|
+
- [Miller Puckette - Theory and Techniques of Electronic Music](http://msp.ucsd.edu/techniques.htm)
|
|
271
|
+
- [standardized-audio-context](https://github.com/chrisguttandin/standardized-audio-context)
|
|
@@ -5,10 +5,21 @@ import { TimeClass } from "../type/Time";
|
|
|
5
5
|
import { TransportTimeClass } from "../type/TransportTime";
|
|
6
6
|
import { Frequency, Hertz, Seconds, Ticks, Time } from "../type/Units";
|
|
7
7
|
import { assertUsedScheduleTime } from "../util/Debug";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
getDefaultsFromInstance,
|
|
10
|
+
optionsFromArguments,
|
|
11
|
+
} from "../util/Defaults";
|
|
9
12
|
import { RecursivePartial } from "../util/Interface";
|
|
10
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
isArray,
|
|
15
|
+
isBoolean,
|
|
16
|
+
isDefined,
|
|
17
|
+
isNumber,
|
|
18
|
+
isString,
|
|
19
|
+
isUndef,
|
|
20
|
+
} from "../util/TypeCheck";
|
|
11
21
|
import { BaseContext } from "./BaseContext";
|
|
22
|
+
import type { TransportClass } from "../clock/Transport";
|
|
12
23
|
|
|
13
24
|
/**
|
|
14
25
|
* A unit which process audio
|
|
@@ -20,8 +31,9 @@ export interface ToneWithContextOptions {
|
|
|
20
31
|
/**
|
|
21
32
|
* The Base class for all nodes that have an AudioContext.
|
|
22
33
|
*/
|
|
23
|
-
export abstract class ToneWithContext<
|
|
24
|
-
|
|
34
|
+
export abstract class ToneWithContext<
|
|
35
|
+
Options extends ToneWithContextOptions
|
|
36
|
+
> extends Tone {
|
|
25
37
|
/**
|
|
26
38
|
* The context belonging to the node.
|
|
27
39
|
*/
|
|
@@ -37,11 +49,15 @@ export abstract class ToneWithContext<Options extends ToneWithContextOptions> ex
|
|
|
37
49
|
/**
|
|
38
50
|
* Pass in a constructor as the first argument
|
|
39
51
|
*/
|
|
40
|
-
constructor(context?: BaseContext)
|
|
52
|
+
constructor(context?: BaseContext);
|
|
41
53
|
constructor(options?: Partial<ToneWithContextOptions>);
|
|
42
54
|
constructor() {
|
|
43
55
|
super();
|
|
44
|
-
const options = optionsFromArguments(
|
|
56
|
+
const options = optionsFromArguments(
|
|
57
|
+
ToneWithContext.getDefaults(),
|
|
58
|
+
arguments,
|
|
59
|
+
["context"]
|
|
60
|
+
);
|
|
45
61
|
if (this.defaultContext) {
|
|
46
62
|
this.context = this.defaultContext;
|
|
47
63
|
} else {
|
|
@@ -94,7 +110,7 @@ export abstract class ToneWithContext<Options extends ToneWithContextOptions> ex
|
|
|
94
110
|
}
|
|
95
111
|
|
|
96
112
|
/**
|
|
97
|
-
* Convert the incoming time to seconds.
|
|
113
|
+
* Convert the incoming time to seconds.
|
|
98
114
|
* This is calculated against the current {@link TransportClass} bpm
|
|
99
115
|
* @example
|
|
100
116
|
* const gain = new Tone.Gain();
|
|
@@ -137,7 +153,7 @@ export abstract class ToneWithContext<Options extends ToneWithContextOptions> ex
|
|
|
137
153
|
protected _getPartialProperties(props: Options): Partial<Options> {
|
|
138
154
|
const options = this.get();
|
|
139
155
|
// remove attributes from the prop that are not in the partial
|
|
140
|
-
Object.keys(options).forEach(name => {
|
|
156
|
+
Object.keys(options).forEach((name) => {
|
|
141
157
|
if (isUndef(props[name])) {
|
|
142
158
|
delete options[name];
|
|
143
159
|
}
|
|
@@ -153,15 +169,26 @@ export abstract class ToneWithContext<Options extends ToneWithContextOptions> ex
|
|
|
153
169
|
*/
|
|
154
170
|
get(): Options {
|
|
155
171
|
const defaults = getDefaultsFromInstance(this) as Options;
|
|
156
|
-
Object.keys(defaults).forEach(attribute => {
|
|
172
|
+
Object.keys(defaults).forEach((attribute) => {
|
|
157
173
|
if (Reflect.has(this, attribute)) {
|
|
158
174
|
const member = this[attribute];
|
|
159
|
-
if (
|
|
175
|
+
if (
|
|
176
|
+
isDefined(member) &&
|
|
177
|
+
isDefined(member.value) &&
|
|
178
|
+
isDefined(member.setValueAtTime)
|
|
179
|
+
) {
|
|
160
180
|
defaults[attribute] = member.value;
|
|
161
181
|
} else if (member instanceof ToneWithContext) {
|
|
162
|
-
defaults[attribute] = member._getPartialProperties(
|
|
182
|
+
defaults[attribute] = member._getPartialProperties(
|
|
183
|
+
defaults[attribute]
|
|
184
|
+
);
|
|
163
185
|
// otherwise make sure it's a serializable type
|
|
164
|
-
} else if (
|
|
186
|
+
} else if (
|
|
187
|
+
isArray(member) ||
|
|
188
|
+
isNumber(member) ||
|
|
189
|
+
isString(member) ||
|
|
190
|
+
isBoolean(member)
|
|
191
|
+
) {
|
|
165
192
|
defaults[attribute] = member;
|
|
166
193
|
} else {
|
|
167
194
|
// remove all undefined and unserializable attributes
|
|
@@ -186,9 +213,13 @@ export abstract class ToneWithContext<Options extends ToneWithContextOptions> ex
|
|
|
186
213
|
* player.autostart = true;
|
|
187
214
|
*/
|
|
188
215
|
set(props: RecursivePartial<Options>): this {
|
|
189
|
-
Object.keys(props).forEach(attribute => {
|
|
216
|
+
Object.keys(props).forEach((attribute) => {
|
|
190
217
|
if (Reflect.has(this, attribute) && isDefined(this[attribute])) {
|
|
191
|
-
if (
|
|
218
|
+
if (
|
|
219
|
+
this[attribute] &&
|
|
220
|
+
isDefined(this[attribute].value) &&
|
|
221
|
+
isDefined(this[attribute].setValueAtTime)
|
|
222
|
+
) {
|
|
192
223
|
// small optimization
|
|
193
224
|
if (this[attribute].value !== props[attribute]) {
|
|
194
225
|
this[attribute].value = props[attribute];
|
package/Tone/event/Part.ts
CHANGED
|
@@ -60,7 +60,7 @@ export class Part<ValueType = any> extends ToneEvent<ValueType> {
|
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
62
|
* @param callback The callback to invoke on each event
|
|
63
|
-
* @param
|
|
63
|
+
* @param value the array of events
|
|
64
64
|
*/
|
|
65
65
|
constructor(callback?: ToneEventCallback<CallbackType<ValueType>>, value?: ValueType[]);
|
|
66
66
|
constructor(options?: Partial<PartOptions<ValueType>>);
|
|
@@ -209,7 +209,7 @@ export class Part<ValueType = any> extends ToneEvent<ValueType> {
|
|
|
209
209
|
* Add a an event to the part.
|
|
210
210
|
* @param time The time the note should start. If an object is passed in, it should
|
|
211
211
|
* have a 'time' attribute and the rest of the object will be used as the 'value'.
|
|
212
|
-
* @param value
|
|
212
|
+
* @param value Any value to add to the timeline
|
|
213
213
|
* @example
|
|
214
214
|
* const part = new Tone.Part();
|
|
215
215
|
* part.add("1m", "C#+11");
|
package/Tone/event/Sequence.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { isArray, isString } from "../core/util/TypeCheck";
|
|
|
5
5
|
import { Part } from "./Part";
|
|
6
6
|
import { ToneEvent, ToneEventCallback, ToneEventOptions } from "./ToneEvent";
|
|
7
7
|
|
|
8
|
-
type SequenceEventDescription<T> = Array<T |
|
|
8
|
+
type SequenceEventDescription<T> = Array<T | SequenceEventDescription<T>>;
|
|
9
9
|
|
|
10
10
|
interface SequenceOptions<T> extends Omit<ToneEventOptions<T>, "value"> {
|
|
11
11
|
loopStart: number;
|
|
@@ -59,7 +59,7 @@ export class Sequence<ValueType = any> extends ToneEvent<ValueType> {
|
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
61
|
* @param callback The callback to invoke with every note
|
|
62
|
-
* @param
|
|
62
|
+
* @param events The sequence of events
|
|
63
63
|
* @param subdivision The subdivision between which events are placed.
|
|
64
64
|
*/
|
|
65
65
|
constructor(
|
package/Tone/index.ts
CHANGED
|
@@ -7,9 +7,13 @@ import { ToneAudioBuffer } from "./core/context/ToneAudioBuffer";
|
|
|
7
7
|
export { start } from "./core/Global";
|
|
8
8
|
import { Seconds } from "./core/type/Units";
|
|
9
9
|
export { supported } from "./core/context/AudioContext";
|
|
10
|
+
import type { TransportClass } from "./core/clock/Transport";
|
|
11
|
+
import type { DestinationClass } from "./core/context/Destination";
|
|
12
|
+
import type { DrawClass } from "./core/util/Draw";
|
|
13
|
+
import type { ListenerClass } from "./core/context/Listener";
|
|
10
14
|
|
|
11
15
|
/**
|
|
12
|
-
* The current audio context time of the global {@link BaseContext}.
|
|
16
|
+
* The current audio context time of the global {@link BaseContext}.
|
|
13
17
|
* @see {@link Context.now}
|
|
14
18
|
* @category Core
|
|
15
19
|
*/
|
|
@@ -39,7 +43,7 @@ export const Transport = getContext().transport;
|
|
|
39
43
|
* @see {@link TransportClass}
|
|
40
44
|
* @category Core
|
|
41
45
|
*/
|
|
42
|
-
export function getTransport():
|
|
46
|
+
export function getTransport(): TransportClass {
|
|
43
47
|
return getContext().transport;
|
|
44
48
|
}
|
|
45
49
|
|
|
@@ -61,7 +65,7 @@ export const Master = getContext().destination;
|
|
|
61
65
|
* @see {@link DestinationClass}
|
|
62
66
|
* @category Core
|
|
63
67
|
*/
|
|
64
|
-
export function getDestination():
|
|
68
|
+
export function getDestination(): DestinationClass {
|
|
65
69
|
return getContext().destination;
|
|
66
70
|
}
|
|
67
71
|
|
|
@@ -76,12 +80,12 @@ export const Listener = getContext().listener;
|
|
|
76
80
|
* The {@link ListenerClass} belonging to the global Tone.js Context.
|
|
77
81
|
* @category Core
|
|
78
82
|
*/
|
|
79
|
-
export function getListener():
|
|
83
|
+
export function getListener(): ListenerClass {
|
|
80
84
|
return getContext().listener;
|
|
81
85
|
}
|
|
82
86
|
|
|
83
87
|
/**
|
|
84
|
-
* Draw is used to synchronize the draw frame with the Transport's callbacks.
|
|
88
|
+
* Draw is used to synchronize the draw frame with the Transport's callbacks.
|
|
85
89
|
* @see {@link DrawClass}
|
|
86
90
|
* @category Core
|
|
87
91
|
* @deprecated Use {@link getDraw} instead
|
|
@@ -89,12 +93,12 @@ export function getListener(): import("./core/context/Listener").ListenerClass {
|
|
|
89
93
|
export const Draw = getContext().draw;
|
|
90
94
|
|
|
91
95
|
/**
|
|
92
|
-
* Get the singleton attached to the global context.
|
|
93
|
-
* Draw is used to synchronize the draw frame with the Transport's callbacks.
|
|
96
|
+
* Get the singleton attached to the global context.
|
|
97
|
+
* Draw is used to synchronize the draw frame with the Transport's callbacks.
|
|
94
98
|
* @see {@link DrawClass}
|
|
95
99
|
* @category Core
|
|
96
100
|
*/
|
|
97
|
-
export function getDraw():
|
|
101
|
+
export function getDraw(): DrawClass {
|
|
98
102
|
return getContext().draw;
|
|
99
103
|
}
|
|
100
104
|
|
|
@@ -106,7 +110,7 @@ export function getDraw(): import("./core/util/Draw").DrawClass {
|
|
|
106
110
|
export const context = getContext();
|
|
107
111
|
|
|
108
112
|
/**
|
|
109
|
-
* Promise which resolves when all of the loading promises are resolved.
|
|
113
|
+
* Promise which resolves when all of the loading promises are resolved.
|
|
110
114
|
* Alias for static {@link ToneAudioBuffer.loaded} method.
|
|
111
115
|
* @category Core
|
|
112
116
|
*/
|
|
@@ -4,6 +4,7 @@ import { optionsFromArguments } from "../core/util/Defaults";
|
|
|
4
4
|
import { TransportTimeClass } from "../core/type/TransportTime";
|
|
5
5
|
import { ToneConstantSource } from "./ToneConstantSource";
|
|
6
6
|
import { OutputNode } from "../core/context/ToneAudioNode";
|
|
7
|
+
import type { TransportClass } from "../core/clock/Transport";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Adds the ability to synchronize the signal to the {@link TransportClass}
|
|
@@ -55,7 +55,7 @@ export class WaveShaper extends SignalOperator<WaveShaperOptions> {
|
|
|
55
55
|
* signal is an AudioRange [-1, 1] value and the output
|
|
56
56
|
* signal can take on any numerical values.
|
|
57
57
|
*
|
|
58
|
-
* @param
|
|
58
|
+
* @param length The length of the WaveShaperNode buffer.
|
|
59
59
|
*/
|
|
60
60
|
constructor(mapping?: WaveShaperMapping, length?: number);
|
|
61
61
|
constructor(options?: Partial<WaveShaperOptions>);
|
package/Tone/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version: string = "14.9.
|
|
1
|
+
export const version: string = "14.9.16";
|