@maccesar/titools 5.2.4 → 5.2.5
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 +16 -11
- package/docs/examples.md +9 -4
- package/package.json +1 -1
- package/skills/ti-synthengine/SKILL.md +42 -23
- package/skills/ti-synthengine/assets/example/README.md +15 -9
- package/skills/ti-synthengine/assets/example/app.js +49 -12
- package/skills/ti-synthengine/assets/index.d.ts +106 -0
- package/skills/ti-synthengine/references/advanced-examples.md +10 -10
- package/skills/ti-synthengine/references/api.md +96 -26
- package/skills/ti-synthengine/references/audio-engine.md +17 -10
- package/skills/ti-synthengine/references/audio-pipeline-validation.md +1 -1
- package/skills/ti-synthengine/references/examples.md +5 -5
- package/skills/ti-synthengine/references/guide.md +26 -24
- package/skills/ti-synthengine/references/instruments-and-effects.md +31 -24
- package/skills/ti-synthengine/references/native-tone-repetition-validation.md +59 -0
- package/skills/ti-synthengine/references/native-variation-proposal.md +1 -1
- package/skills/ti-synthengine/references/native-variation-validation.md +1 -1
- package/skills/ti-synthengine/references/native-variation.md +45 -43
- package/skills/ti-synthengine/references/recipes-interaction.md +3 -1
- package/skills/ti-synthengine/references/recipes.md +3 -2
- package/skills/ti-synthengine/references/recommendations.md +4 -4
- package/skills/ti-synthengine/references/sound-design.md +5 -5
- package/skills/ti-synthengine/references/source-notes.md +35 -10
- package/skills/ti-synthengine/references/source-snapshot.json +168 -89
- package/skills/ti-synthengine/references/stats-performance.md +1 -1
- package/skills/ti-synthengine/references/troubleshooting.md +15 -15
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
> Source snapshot: official TiSynthEngine documentation at commit `
|
|
1
|
+
> Source snapshot: official TiSynthEngine documentation at commit `ec04f4e634075c41b55f66279eabcd78b9652d58` (2026-11-02). Published module 1.1.0; public API 1.1.0. Upstream `documentation/examples.md` SHA-256: `1b3be798d8f606381696d9e00cda330c11475402397e4760dcbc3041a39ef404`.
|
|
2
2
|
|
|
3
3
|
## Sustained game motor
|
|
4
4
|
|
|
5
5
|
Assume one running engine owned by this service. The positive voice ID belongs to the app; do not reuse it during the session or share its counter with an independent audio owner. There is no `duration` or `*End` target on `noteOn`.
|
|
6
6
|
|
|
7
7
|
```javascript
|
|
8
|
-
if (!['noteOn', 'noteOff', '
|
|
8
|
+
if (!['noteOn', 'noteOff', 'updateNote'].every(function (name) {
|
|
9
9
|
return typeof synth[name] === 'function'
|
|
10
10
|
})) throw new Error('Held-voice APIs are required')
|
|
11
11
|
|
|
@@ -25,7 +25,7 @@ function startMotor () {
|
|
|
25
25
|
|
|
26
26
|
function changeMotor (boosted) {
|
|
27
27
|
if (motorId === null) return false
|
|
28
|
-
return synth.
|
|
28
|
+
return synth.updateNote({ voiceId: motorId,
|
|
29
29
|
filterHz: boosted ? 320 : 220, volume: boosted ? 0.18 : 0.15 })
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -128,7 +128,7 @@ Call `setCreativeDrive(true)` only for a deliberate timbre change and check acce
|
|
|
128
128
|
This square voice modulates cutoff and PWM independently. The original `lfoFreq`/`lfoDepth` pitch vibrato remains a separate control. All LFOs run natively; edits preserve their phases and ramp contributions over 10 ms.
|
|
129
129
|
|
|
130
130
|
```javascript
|
|
131
|
-
if (typeof synth.noteOn !== 'function' || typeof synth.
|
|
131
|
+
if (typeof synth.noteOn !== 'function' || typeof synth.updateNote !== 'function') {
|
|
132
132
|
throw new Error('Held-voice APIs are required')
|
|
133
133
|
}
|
|
134
134
|
var modulatedId = 100001 // Reserve an unused ID from the owner's counter in an app.
|
|
@@ -141,23 +141,23 @@ if (!synth.noteOn({ voiceId: modulatedId, note: 'A3', waveType: WAVE.SQUARE,
|
|
|
141
141
|
] })) throw new Error('Modulated voice rejected')
|
|
142
142
|
|
|
143
143
|
function disableVoiceLfos () {
|
|
144
|
-
return synth.
|
|
144
|
+
return synth.updateNote({ voiceId: modulatedId, modulations: [] })
|
|
145
145
|
}
|
|
146
146
|
// Call disableVoiceLfos on the UI action and handle false.
|
|
147
147
|
// Later release this ID with the bounded release policy above, or shut down its owner.
|
|
148
148
|
```
|
|
149
149
|
|
|
150
|
-
Use `target: 'fmDepth'` only with `WAVE.SINE`; a filter target requires an active filter and PWM requires `WAVE.SQUARE`. Free rates are 0 to 20 Hz; synced subdivisions follow native transport BPM. Depth is normalized, with cutoff/PWM/FM contributions clamped to safe parameter ranges. `modulations: []` disables both slots; omitting the field on update preserves them. Copy the same initial `modulations` array into a sequence's `voice` or a step's `overrides` to modulate transport notes. Timed tones and chords do not accept
|
|
150
|
+
Use `target: 'fmDepth'` only with `WAVE.SINE`; a filter target requires an active filter and PWM requires `WAVE.SQUARE`. Free rates are 0 to 20 Hz; synced subdivisions follow native transport BPM. Depth is normalized, with cutoff/PWM/FM contributions clamped to safe parameter ranges. `modulations: []` disables both slots; omitting the field on update preserves them. Copy the same initial `modulations` array into a sequence's `voice` or a step's `overrides` to modulate transport notes. Timed tones and chords do not accept this array; native sequences accept it in `voice` or step `overrides`.
|
|
151
151
|
|
|
152
152
|
## Measure peaks and limiter reduction
|
|
153
153
|
|
|
154
154
|
Enable diagnostics only while measuring and keep unavailable readings distinct from zero. A brief overload can disappear from the window meter while remaining in the accumulated maximum.
|
|
155
155
|
|
|
156
156
|
```javascript
|
|
157
|
-
if (!['
|
|
157
|
+
if (!['enableStats', 'disableStats', 'getStats', 'resetStats'].every(function (name) {
|
|
158
158
|
return typeof synth[name] === 'function'
|
|
159
159
|
})) throw new Error('Statistics APIs are required')
|
|
160
|
-
if (!synth.
|
|
160
|
+
if (!synth.enableStats()) throw new Error('Diagnostics rejected')
|
|
161
161
|
synth.resetStats()
|
|
162
162
|
var mixTimer = setInterval(function () {
|
|
163
163
|
var stats = synth.getStats()
|
|
@@ -167,7 +167,7 @@ var mixTimer = setInterval(function () {
|
|
|
167
167
|
|
|
168
168
|
function closeMixMeter () {
|
|
169
169
|
clearInterval(mixTimer)
|
|
170
|
-
if (!synth.
|
|
170
|
+
if (!synth.disableStats()) Ti.API.warn('Diagnostics disable rejected')
|
|
171
171
|
}
|
|
172
172
|
```
|
|
173
173
|
|
|
@@ -175,7 +175,7 @@ Call `closeMixMeter` when its owner hides or closes. Display unavailable or unme
|
|
|
175
175
|
|
|
176
176
|
## Bounded variation for repeated noise impacts
|
|
177
177
|
|
|
178
|
-
The
|
|
178
|
+
The 1.1.0 packages choose values once per admitted attack. This example keeps the noise source and envelope fixed, varies the initial noise/filter settings, and lets the authored sweep endpoints finish unchanged. Call it for actual gameplay events after normal engine startup. For periodic repetition, pass the finite recipe to `repeatTone` with `intervalMs` and retain its positive tone ID; use `stopTone` on cancellation.
|
|
179
179
|
|
|
180
180
|
```javascript
|
|
181
181
|
var synth = require('ti.synthengine')
|
|
@@ -1,25 +1,28 @@
|
|
|
1
|
-
> Source snapshot: official TiSynthEngine documentation at commit `
|
|
1
|
+
> Source snapshot: official TiSynthEngine documentation at commit `ec04f4e634075c41b55f66279eabcd78b9652d58` (2026-11-02). Published module 1.1.0; public API 1.1.0. Upstream `documentation/api.md` SHA-256: `b58d60cf38a96157e523722d1f9cb9508f785cc2de9c2c1ff306e328c77df9dc`.
|
|
2
2
|
|
|
3
3
|
# API reference
|
|
4
4
|
|
|
5
5
|
Module id: `ti.synthengine`
|
|
6
6
|
|
|
7
|
-
Public API version: `1.
|
|
7
|
+
Public API version: `1.1.0`
|
|
8
8
|
|
|
9
|
-
Android and iOS expose the same
|
|
9
|
+
Android and iOS expose the same public methods, one event and waveform values. Option objects are strict: an unknown key is rejected with `unsupported_option`. Reported metadata and rejection diagnostics have platform differences; this reference does not promise sample-identical rendering between Android and iOS.
|
|
10
10
|
|
|
11
11
|
<!-- TOC-START -->
|
|
12
12
|
## Contents
|
|
13
13
|
|
|
14
|
-
- [Native attack variation (
|
|
14
|
+
- [Native attack variation (package 1.1.0)](#native-attack-variation-package-110)
|
|
15
15
|
- [Return values](#return-values)
|
|
16
16
|
- [`getDefaults()`](#getdefaults)
|
|
17
17
|
- [Limits](#limits)
|
|
18
18
|
- [`start(options)`](#startoptions)
|
|
19
19
|
- [`noteOn(options)`](#noteonoptions)
|
|
20
20
|
- [`noteOff(options)`](#noteoffoptions)
|
|
21
|
-
- [`
|
|
21
|
+
- [`updateNote(options)`](#updatenoteoptions)
|
|
22
|
+
- [`updateVoice(options)` (deprecated)](#updatevoiceoptions-deprecated)
|
|
22
23
|
- [`playTone(options)`](#playtoneoptions)
|
|
24
|
+
- [`repeatTone(options)`](#repeattoneoptions)
|
|
25
|
+
- [Finite-tone repetition](#finite-tone-repetition)
|
|
23
26
|
- [Native sequence transport](#native-sequence-transport)
|
|
24
27
|
- [`setMasterProcessing(options)`](#setmasterprocessingoptions)
|
|
25
28
|
- [Additional voice modulation](#additional-voice-modulation)
|
|
@@ -32,21 +35,22 @@ Android and iOS expose the same nineteen methods, one event and waveform values.
|
|
|
32
35
|
- [Strict validation](#strict-validation)
|
|
33
36
|
- [Binaural front-plane positioning](#binaural-front-plane-positioning)
|
|
34
37
|
- [`getStats()`](#getstats)
|
|
35
|
-
- [`
|
|
38
|
+
- [`enableStats()` and `disableStats()`](#enablestats-and-disablestats)
|
|
39
|
+
- [`setStatsEnabled(enabled)` (deprecated)](#setstatsenabledenabled-deprecated)
|
|
36
40
|
- [`resetStats()`](#resetstats)
|
|
37
41
|
- [Routing and voice priority](#routing-and-voice-priority)
|
|
38
42
|
|
|
39
43
|
<!-- TOC-END -->
|
|
40
44
|
|
|
41
|
-
## Native attack variation (
|
|
45
|
+
## Native attack variation (package 1.1.0)
|
|
42
46
|
|
|
43
|
-
The optional `variation` dictionary is accepted by `playTone`, `playChord`, `noteOn`, sequence `voice` and step `overrides`.
|
|
47
|
+
The optional `variation` dictionary is accepted by `playTone`, `repeatTone`, `playChord`, `noteOn`, sequence `voice` and step `overrides`. Version 1.1.0 reports public API `1.1.0`. Both platforms advertise `capabilities.variation: true` and `variationSchemaVersion: 1`; consumers must require both before sending the dictionary. The published 1.0.2 packages do not support it. See [native variation](native-variation.md) for fields, source restrictions, seeds and examples. Native `amount` is linear; Studio divides its displayed percentage by 100. `updateNote` rejects the dictionary. An override replaces the whole inherited dictionary, and an amount-zero dictionary still validates its ranges.
|
|
44
48
|
|
|
45
49
|
## Return values
|
|
46
50
|
|
|
47
|
-
`start`, `playTone`, `playChord`, `noteOn`, `noteOff`, `updateVoice`, `setVolume`, `setTempo`, `updateSequence`, `stopSequence` and `setMasterProcessing` return a Boolean. `playSequence` returns a positive sequence identifier, or 0 when rejected. `true` means the request was accepted. `false` means validation failed, the engine was unavailable, or the native command queue was full.
|
|
51
|
+
`start`, `playTone`, `playChord`, `noteOn`, `noteOff`, `updateNote`, `updateVoice`, `updateTone`, `stopTone`, `setVolume`, `setTempo`, `updateSequence`, `stopSequence` and `setMasterProcessing` return a Boolean. `repeatTone` returns a positive tone identifier, or 0 when rejected. Its required `intervalMs` is an integer from 1 to 60,000 ms. `playSequence` returns a positive sequence identifier, or 0 when rejected. `true` means the request was accepted. `false` means validation failed, the engine was unavailable, or the native command queue was full.
|
|
48
52
|
|
|
49
|
-
`setStatsEnabled` also
|
|
53
|
+
`enableStats`, `disableStats` and the deprecated `setStatsEnabled` also return Boolean acceptance. `stopAll`, `resetStats` and `shutdown` do not return a value. `getDefaults` returns the contract object described below. `getStats` returns a new statistics snapshot. `getSequenceState` returns the applied sequence state or `null`.
|
|
50
54
|
|
|
51
55
|
## `getDefaults()`
|
|
52
56
|
|
|
@@ -56,12 +60,12 @@ Returns the installed contract without starting the audio stream.
|
|
|
56
60
|
var contract = synth.getDefaults()
|
|
57
61
|
```
|
|
58
62
|
|
|
59
|
-
The shared result in
|
|
63
|
+
The shared result in version 1.1.0 has this shape; Android adds the platform metadata described below. Published 1.0.2 packages retain the core contract but omit the variation capability/schema fields:
|
|
60
64
|
|
|
61
65
|
```javascript
|
|
62
66
|
{
|
|
63
|
-
apiVersion: '1.
|
|
64
|
-
capabilities: { variation: true },
|
|
67
|
+
apiVersion: '1.1.0',
|
|
68
|
+
capabilities: { variation: true, toneRepetition: true },
|
|
65
69
|
variationSchemaVersion: 1,
|
|
66
70
|
defaults: {
|
|
67
71
|
maxVoices: 8,
|
|
@@ -123,7 +127,7 @@ The shared result in the local 1.1.0 candidates has this shape; Android adds the
|
|
|
123
127
|
|
|
124
128
|
`fmDepthEnd`, `detunes`, `spatialX` and `spatialY` have no reported default: their presence changes how the call is interpreted. Supplying a spatial coordinate enables binaural; the other coordinate then defaults to 0 internally. The maximum frequency is `sampleRate * 0.45`. Before the stream opens, the reported fallback is 19,845 Hz. Read the object again after `start()` if the precise device limit matters.
|
|
125
129
|
|
|
126
|
-
In
|
|
130
|
+
In version 1.1.0, both platforms report `capabilities.variation: true` and `variationSchemaVersion: 1`. Android also reports `nativeSequence`, `masterProcessing` and `modulations` capability flags and `limits.stepDurationMs`. iOS omits those three older flags and `limits.stepDurationMs` while implementing the corresponding methods and millisecond sequences. Published 1.0.2 packages do not advertise variation; their iOS metadata has no `capabilities` map. Detect a required core method with `typeof synth.playSequence === 'function'` (and the other methods your feature needs); require the capability/schema pair specifically for variation. Both platforms report `limits.maxSequences`, `limits.priority` and `limits.effectSend`. `limits.stepDuration` is in beats on both platforms; millisecond sequences accept `4000 / sampleRate` through 60,000 even when `limits.stepDurationMs` is absent.
|
|
127
131
|
|
|
128
132
|
## Limits
|
|
129
133
|
|
|
@@ -131,6 +135,8 @@ All ranges include their endpoints. `getDefaults().limits` uses `{ min, max }` o
|
|
|
131
135
|
|
|
132
136
|
| Field | Minimum | Maximum | Unit or rule |
|
|
133
137
|
| --------------------------- | ------------------: | ------------------: | ------------------------------------------------------------------------- |
|
|
138
|
+
| `maxToneRepetitions` | 1 | 32 | fixed independent repetition capacity |
|
|
139
|
+
| `intervalMs` | 1 | 60,000 | integer milliseconds between finite-tone attacks |
|
|
134
140
|
| `maxSequences` | 1 | 4 | preallocated sequence capacity |
|
|
135
141
|
| `priority` | 0 | 3 | integer admission priority |
|
|
136
142
|
| `effectSend` | 0 | 1 | explicit processed share |
|
|
@@ -186,7 +192,7 @@ On iOS, `playback` ignores the silent switch and interrupts other apps' audio. `
|
|
|
186
192
|
|
|
187
193
|
## `noteOn(options)`
|
|
188
194
|
|
|
189
|
-
Starts a sustained native voice. Detect `typeof synth.noteOn === 'function'`, `noteOff` and `
|
|
195
|
+
Starts a sustained native voice. Detect `typeof synth.noteOn === 'function'`, `noteOff` and `updateNote` before enabling their controls; the current `apiVersion` is `1.1.0`. There is no duration limit and no JavaScript timer holds the note.
|
|
190
196
|
|
|
191
197
|
| Field | Rule |
|
|
192
198
|
| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -228,7 +234,7 @@ Repeating a public sustained note can inherit the oscillator phase and pre-envel
|
|
|
228
234
|
|
|
229
235
|
Begins release from the current level, including during attack or decay. Repeated release requests never restart or lengthen a release. An ended or stolen ID is a no-op. `true` reports validation and queue publication, not proof of an audible voice. On `false` from a full queue, an instrument should retry twice at 16 ms intervals, then shut down and report failure if release still cannot be published.
|
|
230
236
|
|
|
231
|
-
## `
|
|
237
|
+
## `updateNote(options)`
|
|
232
238
|
|
|
233
239
|
| Field | Rule |
|
|
234
240
|
| ------------------------ | -------------------------------------------------------------------------------- |
|
|
@@ -251,20 +257,26 @@ Pitch updates are absolute: an initial `detune` is already included in the note'
|
|
|
251
257
|
|
|
252
258
|
```javascript
|
|
253
259
|
if (typeof synth.noteOn !== 'function' || typeof synth.noteOff !== 'function' ||
|
|
254
|
-
typeof synth.
|
|
260
|
+
typeof synth.updateNote !== 'function') throw new Error('Sustained voices unavailable')
|
|
255
261
|
if (!synth.noteOn({ voiceId: 1, note: 'C4', attack: 8, decay: 180, sustain: 0.6,
|
|
256
262
|
release: 300, filterType: 'lowpass', filterHz: 1200, volume: 0.25 })) {
|
|
257
263
|
throw new Error('Note rejected')
|
|
258
264
|
}
|
|
259
|
-
synth.
|
|
265
|
+
synth.updateNote({ voiceId: 1, filterHz: 3600 })
|
|
260
266
|
synth.noteOff({ voiceId: 1 })
|
|
261
267
|
```
|
|
262
268
|
|
|
263
|
-
Use `stopAll()` for panic: it stops every sequence, fades sounding voices and invalidates effect histories. Owner close should call `shutdown()` after cancelling app-owned UI/retry timers.
|
|
269
|
+
Use `stopAll()` for panic: it stops every sequence, cancels finite-tone repetitions, fades sounding voices and invalidates effect histories. Owner close should call `shutdown()` after cancelling app-owned UI/retry timers.
|
|
264
270
|
|
|
265
271
|
|
|
272
|
+
## `updateVoice(options)` (deprecated)
|
|
273
|
+
|
|
274
|
+
Compatibility alias of [`updateNote(options)`](#updatenoteoptions), with identical validation, partial updates, 10 ms transitions, `voiceId` ownership and ended/stolen-ID behavior. Use `updateNote` in new code. The alias remains available without repeated runtime warnings or a scheduled removal date.
|
|
275
|
+
|
|
266
276
|
## `playTone(options)`
|
|
267
277
|
|
|
278
|
+
`playTone` always plays one finite pitch and returns Boolean acceptance. Its closed options reject `intervalMs` with `false`. Use `repeatTone` for native repetition.
|
|
279
|
+
|
|
268
280
|
Plays one pitch. It uses 440 Hz when neither pitch field is present. Note names accept C through B or DO, RE, MI, FA, SOL, LA, SI and TI, followed by optional `#` or lowercase `b` and one octave digit from 0 to 9. Letters are case-insensitive, the omitted octave is 4, and A4 is 440 Hz. A valid named pitch is limited to the active frequency ceiling when rendered; an out-of-range numeric `frequency` is rejected.
|
|
269
281
|
|
|
270
282
|
| Key | Type | Default | Description |
|
|
@@ -315,6 +327,60 @@ have the separately documented 3 ms minimum.
|
|
|
315
327
|
|
|
316
328
|
The controls from `decay` to `detune` are described in [Expressive controls](#expressive-controls), including the rules that tie them together.
|
|
317
329
|
|
|
330
|
+
## `repeatTone(options)`
|
|
331
|
+
|
|
332
|
+
Returns a positive `toneId`, or 0 on rejection. Requires integer `intervalMs` from 1 to 60,000 ms; missing or invalid intervals return 0. All remaining options use the same finite-tone contract as `playTone`, with the same admission, envelope, sweeps, gain and routes. Repetition uses neither sustained nor sequence voices.
|
|
333
|
+
|
|
334
|
+
Always supply exact integer milliseconds. The current Apple validator tolerates extremely near-integer values: for example, `1.0000000001` is accepted and converted to `1`, while Android rejects it. This is a native validation discrepancy, not an additional supported interval format; do not rely on that tolerance.
|
|
335
|
+
|
|
336
|
+
| Key | Type | Rule |
|
|
337
|
+
| ----------------- | -------- | ------------------------------------------------- |
|
|
338
|
+
| `intervalMs` | integer | Required; 1-60,000 ms |
|
|
339
|
+
| Other tone fields | as above | Same fields and validation as `playTone(options)` |
|
|
340
|
+
|
|
341
|
+
## Finite-tone repetition
|
|
342
|
+
|
|
343
|
+
Both platforms advertise `capabilities.toneRepetition: true`, `limits.maxToneRepetitions: { min: 1, max: 32 }` and `limits.intervalMs: { min: 1, max: 60000 }`. These 32 repetition slots are independent of the four sequence slots; attacks still share the configured voice pool. Reserve for overlaps, active voices and release tails if the application promises no stealing. Native priority policy remains in force. A positive `toneId` accepts the repeating recipe; it does not guarantee admission of every future attack.
|
|
344
|
+
|
|
345
|
+
The first attack occurs at the first render opportunity. Later attacks use the audio sample clock, retain fractional samples across intervals and blocks, and do not follow `setTempo`. If voice capacity rejects an attack, it is dropped without catch-up and without consuming a variation selection. Every admitted attack finishes its original duration even after `stopTone`.
|
|
346
|
+
|
|
347
|
+
```javascript
|
|
348
|
+
var toneId = synth.repeatTone({ frequency: 1380, frequencyEnd: 340,
|
|
349
|
+
duration: 105, attack: 2, release: 40, waveType: synth.getDefaults().waveTypes.SQUARE,
|
|
350
|
+
volume: 0.1, intervalMs: 150 })
|
|
351
|
+
if (!toneId) throw new Error('Repeating tone rejected')
|
|
352
|
+
// Edits enter at the next scheduled attack, without adding an immediate attack.
|
|
353
|
+
if (!synth.updateTone({ toneId: toneId, intervalMs: 120, volume: 0.08 })) {
|
|
354
|
+
throw new Error('Tone edit rejected')
|
|
355
|
+
}
|
|
356
|
+
// On release/cancel/preset change/owner close:
|
|
357
|
+
if (!synth.stopTone({ toneId: toneId })) throw new Error('Tone stop rejected')
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
Independent JavaScript calls remain supported and always keep their Boolean return through `playTone`. A game can fire in response to events or deliberately schedule a fixed count of standalone calls, for example:
|
|
361
|
+
|
|
362
|
+
```javascript
|
|
363
|
+
var recipe = { frequency: 880, duration: 100, attack: 2, release: 30, volume: 0.1 }
|
|
364
|
+
function fireStandalone() {
|
|
365
|
+
if (!synth.playTone(recipe)) Ti.API.warn('Independent tone rejected')
|
|
366
|
+
}
|
|
367
|
+
fireStandalone()
|
|
368
|
+
setTimeout(fireStandalone, 200)
|
|
369
|
+
setTimeout(fireStandalone, 400)
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Those three calls use JavaScript timing and independent attack selection. For an ongoing native repetition, call `repeatTone` with `intervalMs` once and use its tone ID. Owner teardown must cancel any application timers it creates.
|
|
373
|
+
|
|
374
|
+
### `updateTone({ toneId, ...changes })`
|
|
375
|
+
|
|
376
|
+
Returns Boolean acceptance. Requires a known positive repetition identifier and at least one change. Accepts partial finite-tone options, including `intervalMs`, and merges them with the latest accepted recipe before validating the entire result. Supplying `note` replaces an earlier `frequency`; supplying `frequency` replaces an earlier `note`. Supplying both is invalid. Invalid edits leave the last accepted recipe intact.
|
|
377
|
+
|
|
378
|
+
An accepted edit affects the next already scheduled attack, preserving its deadline. The new interval determines separation after that attack. Active attacks retain their original configuration. A supplied `variation` dictionary replaces the whole previous dictionary; `{ amount: 0 }` disables future variation. Each repetition retains its own seed and admitted-attack counter. Edits preserve the stream; changing its seed restarts that succession. Unknown or retired IDs reject edits.
|
|
379
|
+
|
|
380
|
+
### `stopTone({ toneId })`
|
|
381
|
+
|
|
382
|
+
Returns Boolean acceptance. Accepts only a known positive repetition identifier. Cancels future attacks at the next render block, including before the first attack, while admitted finite voices finish completely. Stop publication is independent of the ordinary command queue and remains available when that queue is full. Unknown or retired IDs return `false`. There is no `toneend` event. Identifiers are never reused during the module lifetime, including shutdown/start. `stopAll`, shutdown and destruction invalidate all repetitions and their pending edits.
|
|
383
|
+
|
|
318
384
|
## Native sequence transport
|
|
319
385
|
|
|
320
386
|
`start({ maxSequences: 1 })` preallocates capacity for 1-4 independent sequences; the default is 1. All sequences, timed sounds and held notes share one renderer and the same pool of at most 32 voices. No sequence or category reserves voices.
|
|
@@ -385,7 +451,7 @@ Requires a running engine and returns Boolean acceptance. Partial updates merge
|
|
|
385
451
|
| `reverb` | `enabled`: false; `decay`: 0.2-8 seconds, initially 1.5; `damping`: 0-1, initially 0.5; `mix`: 0-1, initially 0.2. Stereo damped comb/allpass Schroeder network. |
|
|
386
452
|
| `saturation` | `enabled`: false; `drive`: 1-4, initially 1; `mix`: 0-1, initially 1. Creative soft waveshaping that changes timbre. |
|
|
387
453
|
|
|
388
|
-
Delay sync accepts `off`, `quarter`, `eighth`, `sixteenth`, `quarterTriplet`, `eighthTriplet` or `sixteenthTriplet`. Sync follows the native transport BPM, initially 120. Disabling an effect gradually closes its input and drains its tail, then restores exact bypass. Tails are bounded to 30 seconds with a final fade. `stopAll()` performs panic: it fades voices, stops the
|
|
454
|
+
Delay sync accepts `off`, `quarter`, `eighth`, `sixteenth`, `quarterTriplet`, `eighthTriplet` or `sixteenthTriplet`. Sync follows the native transport BPM, initially 120. Disabling an effect gradually closes its input and drains its tail, then restores exact bypass. Tails are bounded to 30 seconds with a final fade. `stopAll()` performs panic: it fades voices, stops the transport and invalidates effect histories in bounded work. `shutdown()` stops the stream and frees buffers outside the callback.
|
|
389
455
|
|
|
390
456
|
Processing uses one shared chain for the selected categories. `applyTo` is an array drawn from `music`, `effects`, `ui` and `ambience`; default all four. Each event or held voice uses `bus: 'effects'` by default. Optional `effectSend: 0…1` overrides category selection for that voice. Input gain and master volume remain global. Selected audio receives chorus, delay, reverb and optional saturation, then recombines with dry audio before one final limiter. Send changes ramp over 10 ms.
|
|
391
457
|
|
|
@@ -393,7 +459,7 @@ Defaults keep all effects and saturation disabled, input gain at unity, and pres
|
|
|
393
459
|
|
|
394
460
|
## Additional voice modulation
|
|
395
461
|
|
|
396
|
-
`noteOn` and `
|
|
462
|
+
`noteOn` and `updateNote` accept `modulations`, an array of up to two LFO objects. An empty array disables them. Omission on update preserves the previous configuration. Each object accepts only these fields:
|
|
397
463
|
|
|
398
464
|
| Field | Rule |
|
|
399
465
|
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
@@ -642,9 +708,13 @@ rejected request. These counters are diagnostics; the API return is authoritativ
|
|
|
642
708
|
|
|
643
709
|
Render load is a fraction: multiply by 100 for a percentage. For example, `0.012` is 1.2% of the block budget, while `1.0` is 100%. An open stream still renders silent blocks, including output/limiter work and enabled signal measurements, so no active voices does not imply zero load. Callback elapsed time varies with scheduling and system activity; displayed decimal places do not establish measurement accuracy. Compare the same configuration on the same device. Percentages from a simulator and a phone do not provide a direct performance comparison.
|
|
644
710
|
|
|
645
|
-
## `
|
|
711
|
+
## `enableStats()` and `disableStats()`
|
|
712
|
+
|
|
713
|
+
Both return Boolean acceptance. `enableStats()` enables optional timing and signal measurements; `disableStats()` disables them. Default `false`. Enabling starts a new diagnostic window, without restarting audio. Calling `enableStats()` again also starts a fresh window. Disabling hides timing and signal fields immediately. Basic counters remain available in either mode. The setting persists across shutdown/start, while a new engine starts with fresh counters.
|
|
714
|
+
|
|
715
|
+
## `setStatsEnabled(enabled)` (deprecated)
|
|
646
716
|
|
|
647
|
-
|
|
717
|
+
Compatibility alias for the same statistics logic. Requires a Boolean and returns Boolean acceptance. Use `enableStats()` or `disableStats()` in new code. It remains available without repeated runtime deprecation warnings or a scheduled removal date.
|
|
648
718
|
|
|
649
719
|
## `resetStats()`
|
|
650
720
|
|
|
@@ -652,11 +722,11 @@ Returns nothing. Resets accumulated counters and maxima without stopping sounds,
|
|
|
652
722
|
|
|
653
723
|
```javascript
|
|
654
724
|
// Optional diagnostics; poll at 5 Hz and stop the timer with the owner.
|
|
655
|
-
if (synth.
|
|
725
|
+
if (synth.enableStats()) {
|
|
656
726
|
var statsTimer = setInterval(function () {
|
|
657
727
|
Ti.API.info(JSON.stringify(synth.getStats()))
|
|
658
728
|
}, 200)
|
|
659
|
-
// Later: clearInterval(statsTimer); synth.
|
|
729
|
+
// Later: clearInterval(statsTimer); synth.disableStats()
|
|
660
730
|
}
|
|
661
731
|
```
|
|
662
732
|
|
|
@@ -664,4 +734,4 @@ if (synth.setStatsEnabled(true)) {
|
|
|
664
734
|
|
|
665
735
|
`playTone`, `playChord`, `noteOn` and sequence voices accept `bus`, `effectSend` and `priority`. Categories are `music`, `effects` (default), `ui` and `ambience`. An omitted send follows `setMasterProcessing({ applyTo })`; an explicit 0-1 send replaces that selection. Priority is integer 0-3, default 0. When the pool fills, the lowest eligible priority is replaced first; a lower-priority event cannot steal a higher-priority voice. Existing release/age tie-breakers remain. Chords are admitted or dropped completely; no voices are reserved. `getStats().priorityDropCount` counts these drops; `rejectedPublicationCount` counts unavailable sequence capacity/banks separately from output diagnostics.
|
|
666
736
|
|
|
667
|
-
`
|
|
737
|
+
`updateNote` also accepts `noiseRate`, `lowPassHz`, `pan`, `spatialX`, `spatialY` and `effectSend`, with 10 ms transitions. Noise rate 0 means white noise; low-pass 0 means bypass. Noise phase, oscillator phase and spatial history survive compatible edits. Pan updates require a stereo voice; coordinates require a voice started with spatial coordinates. An omitted coordinate retains its previous value. The source/filter type still requires a new attack. Updates are generation-scoped so queued old commands cannot change a later attack sharing the public voice ID.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
> Source snapshot: official TiSynthEngine documentation at commit `
|
|
1
|
+
> Source snapshot: official TiSynthEngine documentation at commit `ec04f4e634075c41b55f66279eabcd78b9652d58` (2026-11-02). Published module 1.1.0; public API 1.1.0. Upstream `documentation/audio-engine.md` SHA-256: `3e7728703a9f82631f5c4ba2641b1a9735c0d3988ef9001b8e4a4f5e47d1818d`.
|
|
2
2
|
|
|
3
3
|
# Audio engine
|
|
4
4
|
|
|
@@ -29,6 +29,7 @@ The native signal path explains how mixing profiles and voice capacity affect th
|
|
|
29
29
|
- [Sustained voices](#sustained-voices)
|
|
30
30
|
- [Native transport and processing](#native-transport-and-processing)
|
|
31
31
|
- [Unified transport acceptance boundaries](#unified-transport-acceptance-boundaries)
|
|
32
|
+
- [Native finite-tone repetition (API 1.1.0)](#native-finite-tone-repetition-api-110)
|
|
32
33
|
|
|
33
34
|
<!-- TOC-END -->
|
|
34
35
|
|
|
@@ -68,7 +69,7 @@ The engine has six sources:
|
|
|
68
69
|
| `NOISE` | White or variable-rate sample-and-hold pseudo-random generator. |
|
|
69
70
|
| `WAVETABLE` | Caller-supplied 2 to 64-sample stepped cycle. |
|
|
70
71
|
|
|
71
|
-
Pitch can move linearly from `frequency` to `frequencyEnd`. A sine LFO adds `lfoDepth * sin(lfoPhase)` in hertz before the oscillator advances.
|
|
72
|
+
Pitch can move linearly from `frequency` to `frequencyEnd`. A sine LFO adds `lfoDepth * sin(lfoPhase)` in hertz before the oscillator advances. Vibrato depth is therefore an absolute value in hertz, rather than a value in cents.
|
|
72
73
|
|
|
73
74
|
Noise rate advances an independent phase accumulator. A zero `noiseRate` uses one new pseudo-random value per output sample; a positive rate holds that value until the accumulator crosses the next update. `noiseRateEnd` changes the increment linearly over the event.
|
|
74
75
|
|
|
@@ -172,7 +173,7 @@ Both ports use a 128-slot single-consumer ring buffer. Producers are serialized
|
|
|
172
173
|
|
|
173
174
|
`playChord()` publishes its note data and advances the queue index once. The consumer receives the complete event or nothing. `stopAll` and `shutdown` have a control fallback so cleanup is not lost under queue pressure.
|
|
174
175
|
|
|
175
|
-
`playSequence` runs inside the sample-clock callback; JavaScript publishes entire configurations
|
|
176
|
+
`playSequence` runs inside the sample-clock callback; JavaScript publishes entire configurations instead of individual notes. Scheduled releases execute independently of public command-queue capacity. `sequenceend` records are delivered outside the callback and retain their sequence identifier when slots are reused.
|
|
176
177
|
|
|
177
178
|
## Shared DSP core
|
|
178
179
|
|
|
@@ -180,7 +181,7 @@ The envelope, the state-variable filter, the sweep helpers, the FM sine and the
|
|
|
180
181
|
|
|
181
182
|
## Native per-attack variation
|
|
182
183
|
|
|
183
|
-
|
|
184
|
+
Version 1.1.0 supports optional `variation`; published 1.0.2 packages reject it. Check both `capabilities.variation === true` and `variationSchemaVersion === 1`, then select bounded values at admitted attacks. The chosen configuration stays stable during that voice; existing sweeps, envelopes and explicit live edits keep their normal roles. Parsing prepares fixed-size state outside audio; the callback uses bounded shared arithmetic without allocation or locks. See [native variation](native-variation.md) for supported locations, source constraints, inheritance and seeds, and [technical verification](native-variation-validation.md) for measured compatibility and limits.
|
|
184
185
|
|
|
185
186
|
## Android implementation
|
|
186
187
|
|
|
@@ -295,7 +296,7 @@ Android ARM64 reuses coefficients across eight consecutive samples, with four-sa
|
|
|
295
296
|
|
|
296
297
|
## Own-platform performance verification
|
|
297
298
|
|
|
298
|
-
The measurements in this section predate native variation and describe the archived revisions in the cited reports. They do not measure
|
|
299
|
+
The measurements in this section predate native variation and describe the archived revisions in the cited reports. They do not measure version 1.1.0. Its separate [variation verification](native-variation-validation.md) records compatibility, storage and callback checks.
|
|
299
300
|
|
|
300
301
|
The [performance review](performance-review.json) separates measured host improvements, exact compatibility checks and pending device acceptance. Its [raw evidence](performance-review-evidence.zip) retains rejected prototypes and the investigation of idle/stereo regressions. The Apple FIR, stable-control cache and exact idle-effects bypass were evaluated as one atomic candidate and then rejected after physical 32-stereo timing regressed. All three production changes were removed together; the full-score publication and control-memory fixes remain.
|
|
301
302
|
|
|
@@ -361,7 +362,7 @@ python3 tests/run_stats_java.py
|
|
|
361
362
|
|
|
362
363
|
## Sustained voices
|
|
363
364
|
|
|
364
|
-
`noteOn`, `noteOff` and `
|
|
365
|
+
`noteOn`, `noteOff` and `updateNote` use the existing bounded native command queue. Voice storage, smoothing ramps and identity snapshots are preallocated. The callback owns envelopes, oscillator/filter state and replacement decisions; it does not allocate or acquire producer locks. `shared/synth_held.h` supplies the same held ADSR, current-level release and independent 10 ms linear parameter ramps to both renderers. Held attack/decay counters stop advancing after those stages, avoiding sample-counter overflow on long notes.
|
|
365
366
|
|
|
366
367
|
IDs are app-supplied positive 32-bit integers. Atomic 32-bit identity snapshots and queued attacks let producers validate update source compatibility without reading mutable DSP state. The callback checks compatibility again. A full queue rejects note release with `false`; the caller owns its bounded retry and shutdown policy. See the [sustained contract](api.md#noteonoptions) for immutable configuration and supported updates.
|
|
367
368
|
|
|
@@ -372,13 +373,13 @@ Run `tests/held_core_regression.c` with C11 for shared envelope/ramp/identity ch
|
|
|
372
373
|
|
|
373
374
|
`shared/synth_transport.h` owns up to four independent sequences and one global tempo/beat/millisecond clock; `shared/synth_sequence.h` advances each traversal with compensated sample increments. Beat lengths follow tempo changes; millisecond lengths remain constant. A serialized producer prepares sorted traversal and all pitches before publishing one of three immutable banks. The callback accepts tempo at the block boundary and structure at a step boundary; swing changes at a pair boundary. Transport voices share the sustained pool, retain owner identifiers and absolute note deadlines beyond internal slot reuse and release independently of the public command queue. See the [public transport contract](api.md#native-sequence-transport).
|
|
374
375
|
|
|
375
|
-
`shared/synth_effects.h` supplies chorus, ping-pong delay, damped Schroeder reverb and optional saturation; `shared/synth_modulation.h` supplies two phase-preserving LFOs. Buffers allocate at engine initialization and free after the audio backend stops. Epoch tags on 16-sample pages invalidate histories during panic without walking delay memory; recovery clears at most one short page on a first write. Effects start disabled and default rendering follows exact bypass. Enabled effects drain on disable, bounded to 30 seconds.
|
|
376
|
+
`shared/synth_effects.h` supplies chorus, ping-pong delay, damped Schroeder reverb and optional saturation; `shared/synth_modulation.h` supplies two phase-preserving LFOs. Buffers allocate at engine initialization and free after the audio backend stops. Epoch tags on 16-sample pages invalidate histories during panic without walking delay memory; recovery clears at most one short page on a first write. Effects start disabled and default rendering follows exact bypass. Enabled effects drain on disable, bounded to 30 seconds. The implementation uses no additional external DSP dependency.
|
|
376
377
|
|
|
377
378
|
Pre-limiter peak and maximum limiter reduction accumulate natively until reset, so polling cannot miss a brief intervention. The callback tracks linear extrema and converts to decibels once per block. Existing output peak/RMS and reduction windows remain approximately 200 ms. Diagnostics are optional; host measurements do not establish device audio deadlines or listening acceptance.
|
|
378
379
|
|
|
379
|
-
Portable checks: compile and run `tests/sequence_core_regression.c`, `tests/effects_core_regression.c` and `tests/modulation_core_regression.c` with C11, optimization and libm. The transport test checks ten minutes at five sample rates against calculated event times, plus edits, swing, rests, chords and publication pressure. Effects tests check bypass, tails, panic, automation, memory and stability at 16, 44.1, 48, 96 and 192 kHz. On macOS, `tests/studio_contract_ios.m` validates the
|
|
380
|
+
Portable checks: compile and run `tests/sequence_core_regression.c`, `tests/effects_core_regression.c` and `tests/modulation_core_regression.c` with C11, optimization and libm. The transport test checks ten minutes at five sample rates against calculated event times, plus edits, swing, rests, chords and publication pressure. Effects tests check bypass, tails, panic, automation, memory and stability at 16, 44.1, 48, 96 and 192 kHz. On macOS, `tests/studio_contract_ios.m` validates the iOS configuration contract without Titanium.
|
|
380
381
|
|
|
381
|
-
`tools/calibrate_studio.py --studio-root PATH` measures the production Android callback; add `--platform ios` for the production Apple callback. The report covers each preset/scenario at 1, 2, 4, 8, 16 and 32 voices, including independent low/mid/high notes, grouped chords, coherent unisons and overlapping releases. Recommendations target −6 dBFS before protection (with 0.01 dB margin) using the maximum measured peak of the declared usual 1-8-voice configuration and the public voice-volume limit. Larger workloads are separate stress diagnostics. The tool reports fixed scalar recommendations and never edits Studio. Effects and
|
|
382
|
+
`tools/calibrate_studio.py --studio-root PATH` measures the production Android callback; add `--platform ios` for the production Apple callback. The report covers each preset/scenario at 1, 2, 4, 8, 16 and 32 voices, including independent low/mid/high notes, grouped chords, coherent unisons and overlapping releases. Recommendations target −6 dBFS before protection (with 0.01 dB margin) using the maximum measured peak of the declared usual 1-8-voice configuration and the public voice-volume limit. Larger workloads are separate stress diagnostics. The tool reports fixed scalar recommendations and never edits Studio. Effects and additional LFOs are disabled, so recommendations do not guarantee headroom for other configurations. See [audio pipeline validation](audio-pipeline-validation.md).
|
|
382
383
|
|
|
383
384
|
Device feedback superseded that headroom target for Studio's initial Cristal preset: its fixed gain is restored to 1 because the calibrated setting made a fresh Android installation barely audible. This adds 10.83 dB without saturation or voice-count normalization. Three coherent factory notes remain below the limiter ceiling at maximum master; eight independent coherent notes can require limiting. The calibration recommendations remain recorded separately from this active preset exception.
|
|
384
385
|
|
|
@@ -386,4 +387,10 @@ The [Studio technical validation report](studio-validation.json) records the cal
|
|
|
386
387
|
|
|
387
388
|
## Unified transport acceptance boundaries
|
|
388
389
|
|
|
389
|
-
Public API 1.
|
|
390
|
+
Public API 1.1.0 uses one renderer, at most 32 voices and capacity for 1-4 sequences. `bus` categories and per-voice sends share one effects chain. These API changes do not establish complete multiplatform ten-minute maximum-load acceptance; the measured iPad result and Android limits are recorded separately in [physical validation](physical-validation.json) and [the performance summary](stats-performance.md). Host timing, bypass comparisons, memory accounting, actual Android/iOS builds and the remaining device/listening checks are separate evidence. The cited Studio and unified-transport benchmarks are historical observations. In the pre-variation layout, effects buffers at 192 kHz used approximately 13.1 MiB and four maximum-size triple-bank transports used 8,627,712 bytes (8.23 MiB), excluding renderer voices and queues. Version 1.1.0 grows those four transports to 9,537,152 bytes (9.10 MiB) on the measured 64-bit macOS layout, an increase of 909,440 bytes; see [variation storage measurements](native-variation-validation.md#storage-and-callback-work). These structure sizes are not a new whole-process or physical-device measurement. Total accounting must also include renderer voices/tails, command queues, effects, bridge/canonical options and recovery peaks. The 32 MiB additional-memory target remains a target, not a certified bound for version 1.1.0.
|
|
391
|
+
|
|
392
|
+
## Native finite-tone repetition (API 1.1.0)
|
|
393
|
+
|
|
394
|
+
The shared C scheduler owns 32 repetition slots independently of sequence capacity. It retains fractional sample deadlines across normal and spatial render blocks. Each `repeatTone` attack emits the same finite-tone command used by a standalone `playTone`. The first attack starts at the first render opportunity, independent of tempo. Preallocated publication banks carry complete validated configurations; the callback allocates no memory, takes no producer locks and runs no JavaScript. Stop publication has a separate atomic path, so a full ordinary command queue cannot prevent cancellation at the next block.
|
|
395
|
+
|
|
396
|
+
Each repetition owns its variation stream and admitted-attack counter. Admission failure skips that attack without advancing variation or queuing catch-up work. Updates preserve the pending deadline and affect its attack; a new interval controls the subsequent gap. `stopTone` cancels only future attacks, leaving admitted finite tones to complete. Global stop, shutdown and destruction invalidate slots and pending edits. These implementation guarantees require the updated 1.1.0 binaries; historical measurements elsewhere on this page do not measure this scheduler. See [the public contract](api.md#finite-tone-repetition).
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
> Source snapshot: official TiSynthEngine documentation at commit `
|
|
1
|
+
> Source snapshot: official TiSynthEngine documentation at commit `ec04f4e634075c41b55f66279eabcd78b9652d58` (2026-11-02). Published module 1.1.0; public API 1.1.0. Upstream `documentation/audio-pipeline-validation.md` SHA-256: `7359d85de63e9fe94f85477e03a22fc1531c8acaabe30333e7ff2515cc5ec3e9`.
|
|
2
2
|
|
|
3
3
|
# Audio pipeline correction
|
|
4
4
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
> Source snapshot: official TiSynthEngine documentation at commit `
|
|
1
|
+
> Source snapshot: official TiSynthEngine documentation at commit `ec04f4e634075c41b55f66279eabcd78b9652d58` (2026-11-02). Published module 1.1.0; public API 1.1.0. Upstream `documentation/examples.md` SHA-256: `1b3be798d8f606381696d9e00cda330c11475402397e4760dcbc3041a39ef404`.
|
|
2
2
|
|
|
3
3
|
# Examples
|
|
4
4
|
|
|
5
|
-
Every snippet on this page uses the TiSynthEngine 1.
|
|
5
|
+
Every snippet on this page uses the TiSynthEngine 1.1.0 contract. Unless a snippet includes startup code, it assumes the engine is already running.
|
|
6
6
|
|
|
7
7
|
Additional [curated recipes](recipes.md) provide application sound and interaction variants.
|
|
8
8
|
|
|
@@ -13,8 +13,8 @@ var synth = require('ti.synthengine')
|
|
|
13
13
|
var contract = synth.getDefaults()
|
|
14
14
|
var WAVE = contract.waveTypes
|
|
15
15
|
|
|
16
|
-
if (contract.apiVersion !== '1.
|
|
17
|
-
throw new Error('TiSynthEngine 1.
|
|
16
|
+
if (contract.apiVersion !== '1.1.0') {
|
|
17
|
+
throw new Error('TiSynthEngine 1.1.0 is required')
|
|
18
18
|
}
|
|
19
19
|
```
|
|
20
20
|
|
|
@@ -570,7 +570,7 @@ synth.shutdown()
|
|
|
570
570
|
|
|
571
571
|
`stopAll()` stops all native sequences, fades current voices and invalidates effect histories. `shutdown()` also releases the native stream. To stop only one sequence owner, use `stopSequence({ sequenceId })`.
|
|
572
572
|
|
|
573
|
-
Follow the [interactive demo setup and test checklist](../assets/example/README.md) to run [`example/app.js`](../assets/example/app.js). It includes headphone positioning, session selection, pattern completion/replacement and
|
|
573
|
+
Follow the [interactive demo setup and test checklist](../assets/example/README.md) to run [`example/app.js`](../assets/example/app.js). It includes headphone positioning, session selection, pattern completion/replacement and the statistics methods `getStats`, `enableStats`, `disableStats` and `resetStats`. For a service-level statistics recipe, see [read engine statistics](guide.md#read-engine-statistics).
|
|
574
574
|
|
|
575
575
|
## Positioned headphone effect
|
|
576
576
|
|