@maccesar/titools 5.2.5 → 5.4.0
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/CONTRIBUTING.md +1 -1
- package/README.md +58 -97
- package/agents/ti-pro.md +4 -2
- package/commands/ti-audit.md +7 -5
- package/docs/examples.md +24 -13
- package/docs/knowledge-index.md +2 -1
- package/lib/config.js +1 -0
- package/package.json +1 -1
- package/skills/alloy-guides/SKILL.md +18 -179
- package/skills/alloy-guides/references/CLI_TASKS.md +17 -216
- package/skills/alloy-guides/references/CONCEPTS.md +27 -162
- package/skills/alloy-guides/references/CONTROLLERS.md +38 -236
- package/skills/alloy-guides/references/MODELS.md +47 -723
- package/skills/alloy-guides/references/MODELS_ADVANCED.md +21 -482
- package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +12 -222
- package/skills/alloy-guides/references/VIEWS_STYLES.md +39 -358
- package/skills/alloy-guides/references/VIEWS_XML.md +36 -552
- package/skills/alloy-guides/references/WIDGETS.md +49 -127
- package/skills/alloy-howtos/SKILL.md +14 -169
- package/skills/alloy-howtos/references/best_practices.md +9 -113
- package/skills/alloy-howtos/references/cli_reference.md +18 -223
- package/skills/alloy-howtos/references/config_files.md +50 -133
- package/skills/alloy-howtos/references/debugging_troubleshooting.md +19 -63
- package/skills/alloy-howtos/references/samples.md +21 -138
- package/skills/ti-api/SKILL.md +10 -2
- package/skills/ti-api/references/api-android.md +36 -2
- package/skills/ti-api/references/api-app-platform.md +39 -3
- package/skills/ti-api/references/api-core.md +50 -18
- package/skills/ti-api/references/api-data-network.md +49 -35
- package/skills/ti-api/references/api-media.md +45 -27
- package/skills/ti-api/references/api-services.md +39 -9
- package/skills/ti-api/references/api-ui-android.md +33 -13
- package/skills/ti-api/references/api-ui-extras.md +41 -15
- package/skills/ti-api/references/api-ui-ios-animator.md +42 -26
- package/skills/ti-api/references/api-ui-ios.md +74 -2
- package/skills/ti-api/references/api-ui-lists.md +32 -16
- package/skills/ti-api/references/api-ui-text-input.md +34 -17
- package/skills/ti-api/references/api-ui-views.md +27 -1
- package/skills/ti-api/references/api-ui-windows-navigation.md +32 -18
- package/skills/ti-api/references/api-xml-global.md +66 -16
- package/skills/ti-create-release/SKILL.md +98 -0
- package/skills/ti-create-release/references/module-discovery.md +69 -0
- package/skills/ti-expert/references/adaptive-layouts.md +1 -1
- package/skills/ti-guides/SKILL.md +37 -76
- package/skills/ti-guides/references/advanced-data-and-images.md +122 -126
- package/skills/ti-guides/references/android-manifest.md +24 -83
- package/skills/ti-guides/references/app-distribution.md +31 -377
- package/skills/ti-guides/references/application-frameworks.md +127 -335
- package/skills/ti-guides/references/cli-reference.md +184 -633
- package/skills/ti-guides/references/commonjs-advanced.md +81 -231
- package/skills/ti-guides/references/compatibility-matrix.md +36 -75
- package/skills/ti-guides/references/hello-world.md +95 -70
- package/skills/ti-guides/references/hyperloop-native-access.md +52 -448
- package/skills/ti-guides/references/resources.md +174 -142
- package/skills/ti-guides/references/sdk-release-notes.md +28 -71
- package/skills/ti-guides/references/tiapp-config.md +222 -598
- package/skills/ti-howtos/SKILL.md +23 -123
- package/skills/ti-howtos/references/cross-platform-development.md +119 -324
- package/skills/ti-howtos/references/debugging-profiling.md +77 -445
- package/skills/ti-howtos/references/extending-titanium.md +199 -673
- package/skills/ti-howtos/references/local-data-sources.md +87 -300
- package/skills/ti-howtos/references/location-and-maps.md +86 -213
- package/skills/ti-howtos/references/media-apis.md +103 -223
- package/skills/ti-howtos/references/notification-services.md +86 -506
- package/skills/ti-howtos/references/remote-data-sources.md +97 -316
- package/skills/ti-howtos/references/using-modules.md +77 -133
- package/skills/ti-synthengine/SKILL.md +62 -111
- package/skills/ti-synthengine/assets/example/README.md +50 -59
- package/skills/ti-synthengine/assets/example/app.js +67 -65
- package/skills/ti-synthengine/assets/example/lib/sequenceOwner.js +39 -40
- package/skills/ti-synthengine/assets/example/lib/soundPreset.js +34 -0
- package/skills/ti-synthengine/assets/index.d.ts +122 -2
- package/skills/ti-synthengine/references/advanced-examples.md +4 -4
- package/skills/ti-synthengine/references/api.md +40 -18
- package/skills/ti-synthengine/references/audio-engine.md +15 -57
- package/skills/ti-synthengine/references/examples.md +63 -6
- package/skills/ti-synthengine/references/guide.md +61 -57
- package/skills/ti-synthengine/references/instruments-and-effects.md +15 -15
- package/skills/ti-synthengine/references/native-variation.md +53 -14
- package/skills/ti-synthengine/references/recipes-interaction.md +25 -20
- package/skills/ti-synthengine/references/recipes.md +19 -16
- package/skills/ti-synthengine/references/recommendations.md +12 -12
- package/skills/ti-synthengine/references/sound-api.md +197 -0
- package/skills/ti-synthengine/references/sound-design.md +7 -7
- package/skills/ti-synthengine/references/source-notes.md +62 -172
- package/skills/ti-synthengine/references/troubleshooting.md +17 -19
- package/skills/ti-synthengine/references/upgrade-2.0.0.md +40 -0
- package/skills/ti-ui/SKILL.md +28 -143
- package/skills/ti-ui/references/icons-and-splash-screens.md +74 -403
- package/skills/ti-ui/references/layouts-and-positioning.md +175 -402
- package/skills/ti-ui/references/listviews-and-performance.md +100 -703
- package/skills/ti-ui/references/platform-conventions.md +180 -0
- package/skills/ti-ui/references/user-interface.md +43 -0
- package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +0 -102
- package/skills/alloy-howtos/references/custom_tags.md +0 -148
- package/skills/ti-guides/references/coding-best-practices.md +0 -149
- package/skills/ti-guides/references/javascript-primer.md +0 -414
- package/skills/ti-guides/references/reserved-words.md +0 -36
- package/skills/ti-guides/references/style-and-conventions.md +0 -103
- package/skills/ti-howtos/references/android-platform-deep-dives.md +0 -624
- package/skills/ti-howtos/references/automation-fastlane-appium.md +0 -96
- package/skills/ti-howtos/references/buffer-codec-streams.md +0 -162
- package/skills/ti-howtos/references/google-maps-v2.md +0 -172
- package/skills/ti-howtos/references/ios-map-kit.md +0 -149
- package/skills/ti-howtos/references/ios-platform-deep-dives.md +0 -611
- package/skills/ti-howtos/references/tutorials.md +0 -565
- package/skills/ti-howtos/references/web-content-integration.md +0 -287
- package/skills/ti-howtos/references/webpack-build-pipeline.md +0 -124
- package/skills/ti-synthengine/references/android-sim80-correction-evidence.zip +0 -0
- package/skills/ti-synthengine/references/android-sim80-correction.json +0 -162
- package/skills/ti-synthengine/references/audio-pipeline-validation.md +0 -19
- package/skills/ti-synthengine/references/bypass-physical-recheck-evidence.zip +0 -0
- package/skills/ti-synthengine/references/frontier-android-evidence.zip +0 -0
- package/skills/ti-synthengine/references/frontier-ipad-evidence.zip +0 -0
- package/skills/ti-synthengine/references/frontier-physical-validation.json +0 -1918
- package/skills/ti-synthengine/references/native-tone-repetition-validation.md +0 -59
- package/skills/ti-synthengine/references/native-variation-proposal.md +0 -182
- package/skills/ti-synthengine/references/native-variation-validation.md +0 -63
- package/skills/ti-synthengine/references/performance-review-evidence.zip +0 -0
- package/skills/ti-synthengine/references/performance-review.json +0 -1146
- package/skills/ti-synthengine/references/physical-validation.json +0 -1457
- package/skills/ti-synthengine/references/source-snapshot.json +0 -542
- package/skills/ti-synthengine/references/stats-performance.json +0 -2992
- package/skills/ti-synthengine/references/stats-performance.md +0 -82
- package/skills/ti-synthengine/references/studio-validation.json +0 -6202
- package/skills/ti-synthengine/references/unified-bypass-performance.json +0 -22425
- package/skills/ti-synthengine/references/unified-validation.json +0 -314
- package/skills/ti-ui/references/accessibility-deep-dive.md +0 -288
- package/skills/ti-ui/references/animation-and-matrices.md +0 -569
- package/skills/ti-ui/references/application-structures.md +0 -626
- package/skills/ti-ui/references/custom-fonts-styling.md +0 -549
- package/skills/ti-ui/references/event-handling.md +0 -401
- package/skills/ti-ui/references/gestures.md +0 -448
- package/skills/ti-ui/references/orientation.md +0 -374
- package/skills/ti-ui/references/platform-ui-android.md +0 -727
- package/skills/ti-ui/references/platform-ui-ios.md +0 -576
- package/skills/ti-ui/references/scrolling-views.md +0 -288
- package/skills/ti-ui/references/tableviews.md +0 -542
|
@@ -1,27 +1,66 @@
|
|
|
1
|
-
> Source snapshot: official TiSynthEngine documentation at commit `
|
|
1
|
+
> Source snapshot: official TiSynthEngine documentation at commit `9d74aa45f84d3f2822d4aab76874efe37d81257f` (2026-11-03). Published module 2.0.0. Upstream `documentation/native-variation.md` SHA-256: `6cfd65b0741dea79d37bb5eee14d1bcb98445ee6b5db14a8c00e3ccfd00a5190`.
|
|
2
2
|
|
|
3
3
|
# Native per-attack variation
|
|
4
4
|
|
|
5
5
|
`variation` lets the engine choose bounded parameter values when it admits an attack. Repeated shots can have different pitch, noise color or filter settings without JavaScript randomization. Each voice keeps the chosen values for its lifetime; existing envelopes, sweeps and LFOs continue from that starting configuration.
|
|
6
6
|
|
|
7
|
-
Android and iOS support this dictionary in
|
|
7
|
+
Android and iOS support this dictionary in TiSynth 2.0.0. The variation data schema is `1`. Store it in `sound.variation`; a pattern step can supply `steps[i].sound.variation`.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
<!-- TOC-START -->
|
|
10
|
+
## Contents
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
- [Reuse a sound with variation](#reuse-a-sound-with-variation)
|
|
13
|
+
- [Select the module version](#select-the-module-version)
|
|
14
|
+
- [Detect support and start playback](#detect-support-and-start-playback)
|
|
15
|
+
- [Supported locations](#supported-locations)
|
|
16
|
+
- [Dictionary reference](#dictionary-reference)
|
|
17
|
+
- [What amount means](#what-amount-means)
|
|
18
|
+
- [Repeated independent effects](#repeated-independent-effects)
|
|
19
|
+
- [Chords and application gain](#chords-and-application-gain)
|
|
20
|
+
- [Sustained voices and explicit live edits](#sustained-voices-and-explicit-live-edits)
|
|
21
|
+
- [Native loops and dictionary inheritance](#native-loops-and-dictionary-inheritance)
|
|
22
|
+
- [Seeds and reproducibility](#seeds-and-reproducibility)
|
|
23
|
+
- [Rejected configurations](#rejected-configurations)
|
|
24
|
+
- [Studio and game integration](#studio-and-game-integration)
|
|
25
|
+
- [Implementation and verification](#implementation-and-verification)
|
|
26
|
+
|
|
27
|
+
<!-- TOC-END -->
|
|
28
|
+
|
|
29
|
+
## Reuse a sound with variation
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
var synth = require('ti.synthengine')
|
|
33
|
+
var bell = synth.createSound({
|
|
34
|
+
sound: {
|
|
35
|
+
waveType: synth.getContract().waveTypes.SINE,
|
|
36
|
+
volume: 0.25, attack: 5, release: 120,
|
|
37
|
+
variation: { amount: 0.6, ranges: { volume: [0.18, 0.25], pitchCents: [-8, 8] } }
|
|
38
|
+
},
|
|
39
|
+
playback: { type: 'tone', notes: ['A4'], duration: 400 }
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
bell.play()
|
|
43
|
+
bell.play({ notes: ['C5'] })
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Call playback after engine startup. The detailed native dictionaries below explain source restrictions and inheritance. For Sound patterns, root variation belongs in `sound.variation` and a step replacement belongs in `steps[i].sound.variation`.
|
|
47
|
+
|
|
48
|
+
## Select the module version
|
|
49
|
+
|
|
50
|
+
Install the matching Android and iOS 2.0.0 archives in the app and select them in `tiapp.xml`:
|
|
12
51
|
|
|
13
52
|
```xml
|
|
14
53
|
<modules>
|
|
15
|
-
<module platform="android" version="
|
|
16
|
-
<module platform="iphone" version="
|
|
54
|
+
<module platform="android" version="2.0.0">ti.synthengine</module>
|
|
55
|
+
<module platform="iphone" version="2.0.0">ti.synthengine</module>
|
|
17
56
|
</modules>
|
|
18
57
|
```
|
|
19
58
|
|
|
20
|
-
Rebuild and reinstall the application after replacing native modules. Copying module files alone does not update an installed app. Keep
|
|
59
|
+
Rebuild and reinstall the application after replacing native modules. Copying module files alone does not update an installed app. Keep historical released archives separate. The installed module version is available as `getDefaults().version`.
|
|
21
60
|
|
|
22
61
|
## Detect support and start playback
|
|
23
62
|
|
|
24
|
-
Check both
|
|
63
|
+
Check both capability/schema fields, even when the module version matches the one you expect. Omit the property completely if either field is missing, including when the requested amount is zero.
|
|
25
64
|
|
|
26
65
|
```javascript
|
|
27
66
|
var synth = require('ti.synthengine')
|
|
@@ -133,11 +172,11 @@ function fireLaser() {
|
|
|
133
172
|
fireLaser()
|
|
134
173
|
```
|
|
135
174
|
|
|
136
|
-
The engine samples after
|
|
175
|
+
The engine samples after admitting an attack, before initializing its filters, smoothing controls and trajectories. Rejected attacks consume no selection. Release tails, capacity policy and voice replacement remain unchanged.
|
|
137
176
|
|
|
138
177
|
## Chords and application gain
|
|
139
178
|
|
|
140
|
-
|
|
179
|
+
A chord is published atomically. Each voice's position within the attack determines its independent field samples, so later voices do not reuse the first voice's result. If the chord cannot be admitted, none of its voices starts and no event is consumed.
|
|
141
180
|
|
|
142
181
|
Scale a volume range with the same application gain as the authored volume. Let the engine apply its existing chord compensation once.
|
|
143
182
|
|
|
@@ -234,7 +273,7 @@ if (supportsVariation && sequenceId > 0) {
|
|
|
234
273
|
}
|
|
235
274
|
```
|
|
236
275
|
|
|
237
|
-
Stop the owned sequence
|
|
276
|
+
Stop the owned sequence during normal lifecycle cleanup when it is no longer needed. Stopping and starting playback again creates a new stream.
|
|
238
277
|
|
|
239
278
|
## Seeds and reproducibility
|
|
240
279
|
|
|
@@ -276,10 +315,10 @@ Also check pitch corners near 1 Hz or the reported ceiling. A valid base pitch c
|
|
|
276
315
|
|
|
277
316
|
Studio calls this control Variantes. Its displayed percentage maps linearly: 25% sends native amount `0.25`, 50% sends `0.5`, and 100% sends `1`. Studio prepares broader ranges for its editor. The games retain their authored range profiles.
|
|
278
317
|
|
|
279
|
-
Frontier automatically applies authored ranges only to its eligible destruction sounds; Guardian applies them only to its two lasers. Both require the capability/schema pair
|
|
318
|
+
Frontier automatically applies authored ranges only to its eligible destruction sounds; Guardian applies them only to its two lasers. Both require the capability/schema pair. Studio allows any source to opt in through compatible parameter ranges. See [Studio's control and preset guide](https://github.com/macCesar/TiSynth-Studio/blob/main/documentation/variation.md); the native contract in this document does not depend on a consumer app.
|
|
280
319
|
|
|
281
320
|
## Implementation and verification
|
|
282
321
|
|
|
283
|
-
Both renderers use [`shared/synth_variation.h`](https://github.com/macCesar/TiSynthEngine/blob/
|
|
322
|
+
Both renderers use [`shared/synth_variation.h`](https://github.com/macCesar/TiSynthEngine/blob/9d74aa45f84d3f2822d4aab76874efe37d81257f/shared/synth_variation.h): stable schema slots, integer-defined SplitMix64 finalization and exact uint32-to-uniform conversion. Parsing prepares a fixed 144-byte configuration outside the audio callback. The callback performs bounded arithmetic without allocation, locks, JavaScript calls or entropy services.
|
|
284
323
|
|
|
285
|
-
Focused checks cover known vectors, both native validators, attack admission, chord ordinals, sustained stability, loops, revisions, rejection and old-renderer compatibility with controlled noise initialization. [Technical verification](native-variation-validation.md) records the measured memory/callback cost and its limits. Host results do not certify physical latency or listening quality on every device.
|
|
324
|
+
Focused checks cover known vectors, both native validators, attack admission, chord ordinals, sustained stability, loops, revisions, rejection and old-renderer compatibility with controlled noise initialization. [Technical verification](https://github.com/macCesar/TiSynthEngine/blob/9d74aa45f84d3f2822d4aab76874efe37d81257f/documentation/native-variation-validation.md) records the measured memory/callback cost and its limits. Host results do not certify physical latency or listening quality on every device.
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
# Instrument, polyphony and expressive recipes
|
|
2
2
|
|
|
3
|
-
These
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
These TiTools recipes use the supported direct interface in 2.0.0 and share
|
|
4
|
+
the running engine and runtime `WAVE` constants from
|
|
5
|
+
[the arcade recipes](recipes.md). Keep one engine owner, check native acceptance
|
|
6
|
+
and follow the [verification checklist](recipes.md#recipe-verification-checklist).
|
|
7
|
+
|
|
8
|
+
The envelope, filter and FM ranges are starting points checked against the
|
|
9
|
+
public contract. They have not been auditioned on a device, so listen before
|
|
10
|
+
shipping.
|
|
11
|
+
|
|
12
|
+
For new reusable instruments, read [Sound definitions and controls](sound-api.md).
|
|
13
|
+
Keep these recipes' gains, pitch arrays, envelopes and ownership when adapting them.
|
|
8
14
|
|
|
9
15
|
```javascript
|
|
10
16
|
const synth = require('ti.synthengine')
|
|
@@ -114,9 +120,8 @@ In a Titanium view:
|
|
|
114
120
|
- call `gesture.finish()` on both `touchend` and `touchcancel`;
|
|
115
121
|
- keep visual pressed-state counts separate if multiple touches are supported.
|
|
116
122
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
sequence and invalidates shared effect histories. Use an owner's
|
|
123
|
+
For a xylophone, let the audio release continue after the finger leaves a bar.
|
|
124
|
+
`stopAll()` is a global panic: it also cancels every native sequence and invalidates shared effect histories. Use an owner's
|
|
120
125
|
`stopSequence({ sequenceId })` when only that sequence should stop.
|
|
121
126
|
|
|
122
127
|
## Four-pad memory cues
|
|
@@ -169,8 +174,8 @@ function playMemoryBank (bankName) {
|
|
|
169
174
|
|
|
170
175
|
### Controlled timbre comparison
|
|
171
176
|
|
|
172
|
-
For an
|
|
173
|
-
|
|
177
|
+
For an A/B test, hold pitches, duration, envelope and pan constant. Change
|
|
178
|
+
only the waveform and its comparison level. Never pass a profile object
|
|
174
179
|
containing labels or other app metadata directly to `playChord()` because its
|
|
175
180
|
options dictionary is closed.
|
|
176
181
|
|
|
@@ -202,8 +207,8 @@ function auditionTimbre (profileName) {
|
|
|
202
207
|
|
|
203
208
|
### Convert MIDI pitch to hertz
|
|
204
209
|
|
|
205
|
-
|
|
206
|
-
|
|
210
|
+
Use the standard A4 = 440 Hz formula to build interval recipes without
|
|
211
|
+
embedding a long frequency table.
|
|
207
212
|
|
|
208
213
|
```javascript
|
|
209
214
|
function midiToHz (midi) {
|
|
@@ -337,9 +342,9 @@ This repeated chord uses one centered native sequence. The one-off layered chord
|
|
|
337
342
|
|
|
338
343
|
### Cancellable repetition
|
|
339
344
|
|
|
340
|
-
The chord pulse above
|
|
345
|
+
The chord pulse above belongs to one identified sequence owner. Repeated start requests coalesce until the matching `sequenceend` event retires it and frees the slot. When its window closes, stop that sequence ID and cancel pending restarts. The native sequence schedules subsequent chord attacks.
|
|
341
346
|
|
|
342
|
-
For repetition of an original finite tone
|
|
347
|
+
For direct repetition of an original finite tone, use `repeatTone({ intervalMs, ...recipe })`, retain its positive tone ID, edit future attacks with `updateTone`, and cancel with `stopTone`. Each independent layer retains its own tone ID and overlap budget. `stopTone` preserves admitted finite attacks; `stopSequence` releases its sequence's voices. Tone IDs have no completion event, so the sequence retirement/restart procedure above does not apply to them. Independent event calls and intentionally timed finite JavaScript bursts remain supported; cancel any app-owned timers at teardown. See [the repetition contract](api.md#finite-tone-repetition) and [complete effect fidelity](instruments-and-effects.md#repeated-firing-uses-the-native-clock).
|
|
343
348
|
|
|
344
349
|
```javascript
|
|
345
350
|
function cleanupAudio () {
|
|
@@ -356,9 +361,9 @@ Call `shutdown()` only from the screen or service that owns the shared engine.
|
|
|
356
361
|
|
|
357
362
|
### Plucked marimba note
|
|
358
363
|
|
|
359
|
-
A short attack
|
|
360
|
-
|
|
361
|
-
needs a decay, and `attack + decay` must fit inside `duration`.
|
|
364
|
+
A short attack followed by decay to a low sustain gives the strike and ring
|
|
365
|
+
of a mallet or plucked string. Keep the release within the available duration.
|
|
366
|
+
A sustain below 1 needs a decay, and `attack + decay` must fit inside `duration`.
|
|
362
367
|
|
|
363
368
|
```javascript
|
|
364
369
|
synth.playTone({
|
|
@@ -412,9 +417,9 @@ synth.playTone({
|
|
|
412
417
|
|
|
413
418
|
### Electric piano
|
|
414
419
|
|
|
415
|
-
Frequency modulation with a 1:1 ratio gives a tine-like tone.
|
|
416
|
-
modulation index
|
|
417
|
-
|
|
420
|
+
Frequency modulation with a 1:1 ratio gives a tine-like tone. Reduce the
|
|
421
|
+
modulation index through `fmDepthEnd` so the note mellows as it rings, as a
|
|
422
|
+
struck tine does. FM needs a sine carrier.
|
|
418
423
|
|
|
419
424
|
```javascript
|
|
420
425
|
synth.playTone({
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# Curated sound and interaction recipes
|
|
2
2
|
|
|
3
|
-
These recipes use the
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
These recipes use the supported direct native interface in `ti.synthengine` 2.0.0
|
|
4
|
+
and earlier 1.x modules. For reusable definitions in new code, use
|
|
5
|
+
[Sound objects](sound-api.md) while preserving how each recipe renders.
|
|
6
|
+
|
|
7
|
+
The examples use public option keys and valid explicit envelopes. They read
|
|
8
|
+
waveforms from the runtime contract instead of hardcoding integers. Install
|
|
9
|
+
matching official Android/iOS packages and follow the
|
|
10
|
+
[installation and lifecycle guide](guide.md) to set up the engine owner.
|
|
9
11
|
|
|
10
12
|
Unless a section says otherwise, the snippets assume one owner has already
|
|
11
13
|
started the engine:
|
|
@@ -16,13 +18,13 @@ const contract = synth.getDefaults()
|
|
|
16
18
|
const WAVE = contract.waveTypes
|
|
17
19
|
```
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
Use the levels as starting points for listening tests, rather than final
|
|
22
|
+
mastering targets. Test on the actual phone speaker and leave headroom for
|
|
23
|
+
overlapping release tails or independent events.
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
[the interaction recipes](recipes-interaction.md).
|
|
25
|
-
|
|
25
|
+
For instrument interactions, layered chords and expressive synthesis, see
|
|
26
|
+
[the interaction recipes](recipes-interaction.md). Listen to those starting
|
|
27
|
+
ranges on the target device before shipping.
|
|
26
28
|
|
|
27
29
|
<!-- TOC-START -->
|
|
28
30
|
## Contents
|
|
@@ -166,8 +168,8 @@ if (!sequenceId) throw new Error('Sequence rejected')
|
|
|
166
168
|
|
|
167
169
|
### Fast four-note arpeggio
|
|
168
170
|
|
|
169
|
-
Very short square notes with a small attack
|
|
170
|
-
edge
|
|
171
|
+
Very short square notes with a small attack keep the hard cartridge-era
|
|
172
|
+
edge and reduce uncontrolled clicks. The 10 ms rests keep the first three
|
|
171
173
|
40 ms notes on a 50 ms grid; the final note rings for 80 ms.
|
|
172
174
|
|
|
173
175
|
```javascript
|
|
@@ -404,8 +406,9 @@ if (!sequenceId) throw new Error('Sequence rejected')
|
|
|
404
406
|
|
|
405
407
|
### Hovering craft
|
|
406
408
|
|
|
407
|
-
A triangle voice with strong sine vibrato creates a
|
|
408
|
-
remains the primary cue
|
|
409
|
+
A triangle voice with strong sine vibrato creates a repeating engine wobble.
|
|
410
|
+
Slow stereo travel adds movement on headphones; pitch remains the primary cue
|
|
411
|
+
on mono speakers.
|
|
409
412
|
|
|
410
413
|
```javascript
|
|
411
414
|
synth.playTone({
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
> Source snapshot: official TiSynthEngine documentation at commit `
|
|
1
|
+
> Source snapshot: official TiSynthEngine documentation at commit `9d74aa45f84d3f2822d4aab76874efe37d81257f` (2026-11-03). Published module 2.0.0. Upstream `documentation/recommendations.md` SHA-256: `0e7c55830b05ef21bdd1fd125e7d158ea5b598e02618202e65ddd8b8d2044cab`.
|
|
2
2
|
|
|
3
3
|
# Recommendations
|
|
4
4
|
|
|
@@ -6,9 +6,9 @@ The defaults work for ordinary tones and chords. Use the guidance below when an
|
|
|
6
6
|
|
|
7
7
|
## Group simultaneous notes
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Declare `playback.type: 'chord'` when pitches form one known simultaneous event. The chord is atomic. Protected profiles normalize per-voice source gain by the square root of the event voice count; `raw` bypasses that normalization. Separate tone executions suit independent effects, but their start times and gain are independent too.
|
|
10
10
|
|
|
11
|
-
For keys or pads
|
|
11
|
+
For freely triggered keys or pads, keep each event around 0.4 to 0.7 until you have listened to the worst overlap. If every event needs gain above 1, consider `balanced` for the session before raising individual notes further.
|
|
12
12
|
|
|
13
13
|
## Choose the mixing profile once
|
|
14
14
|
|
|
@@ -25,7 +25,7 @@ If a phone buzzes under `speakerSafe`, lower the event volume or raise the pitch
|
|
|
25
25
|
|
|
26
26
|
## Size `maxVoices` for real overlap
|
|
27
27
|
|
|
28
|
-
`maxVoices`
|
|
28
|
+
`maxVoices` sets voice capacity without changing event gain.
|
|
29
29
|
|
|
30
30
|
| App behavior | Starting value |
|
|
31
31
|
| ---------------------------------- | -------------: |
|
|
@@ -34,7 +34,7 @@ If a phone buzzes under `speakerSafe`, lower the event volume or raise the pitch
|
|
|
34
34
|
| Chords, keys or long release tails | 16 to 24 |
|
|
35
35
|
| Explicit stress testing | 32 |
|
|
36
36
|
|
|
37
|
-
Count release tails
|
|
37
|
+
Count release tails as well as buttons pressed at the same instant. Replacement first selects the lowest eligible priority; higher-priority voices are protected. Among that priority, timed-only events steal the slot with the least time remaining; sustained/transport voices prefer a releasing slot, then the oldest attack. The short fade avoids a hard click; the stolen note still ends early.
|
|
38
38
|
|
|
39
39
|
## Keep one lifecycle owner
|
|
40
40
|
|
|
@@ -67,7 +67,7 @@ The resonant filter, FM and stacked detuned voices change level and spectrum mor
|
|
|
67
67
|
- A resonance that keeps reaching the limiter makes the whole mix pump. Lower the volume or the Q before reaching for a different profile.
|
|
68
68
|
- FM is not band-limited. A high carrier with a large `fmDepth` and `fmRatio` aliases. Keep carriers of bell-like sounds around 500 Hz, or lower the index.
|
|
69
69
|
- A detuned stack is one voice per copy. Count them when choosing `maxVoices`. Protected profiles divide per-voice source gain by the square root of the event voice count; `raw` does not. Correlated or phase-aligned voices can still reinforce each other, so this is not a guarantee of constant loudness or peaks.
|
|
70
|
-
- `
|
|
70
|
+
- A pattern control emits `end` on completion or stopping. Put contiguous notes into one pattern when sample timing matters; the event crosses JavaScript delivery latency.
|
|
71
71
|
|
|
72
72
|
## Validate values at the app boundary
|
|
73
73
|
|
|
@@ -87,7 +87,7 @@ Do not copy the frequency maximum into application code. It depends on the activ
|
|
|
87
87
|
|
|
88
88
|
The same rule applies to `noiseRate`, `lowPassHz` and `filterHz`. Validate a custom `waveTable` as 2 to 64 finite values from -1 to 1, and remember that `bitDepth` accepts zero or an integer from 2 to 16. For `detune`, check the resulting pitch too: a shifted pitch that leaves the frequency range is rejected even when the cents value is in range.
|
|
89
89
|
|
|
90
|
-
Check each method's documented return value during development
|
|
90
|
+
Check each method's documented return value during development. Sound playback returns finite acceptance, a playback control, or `false` on operational rejection; invalid Sound configurations throw. Direct native methods keep their documented Boolean or identifier returns. Methods that emit structured validation warnings include the method, key and reason in the native log, but some sequence/control rejection paths do not log. Logging the return at the caller helps identify a stale preset or misspelled field. A silent native log does not establish acceptance.
|
|
91
91
|
|
|
92
92
|
## Test the intended sound
|
|
93
93
|
|
|
@@ -111,13 +111,13 @@ Use the [integration guide](guide.md#integrate-binaural-in-a-2d-app) to convert
|
|
|
111
111
|
|
|
112
112
|
## Known limits
|
|
113
113
|
|
|
114
|
-
-
|
|
114
|
+
- Keep the control returned by `sound.noteOn()` or held `play()` for release and compatible live updates. Finite tones and chords return no individual control.
|
|
115
115
|
- Timed tones and chords last at most 60 seconds including release. Sequence intervals and explicit note lengths use the sequence unit, at most 300 beats or 60,000 ms; sequence ADSR remains in milliseconds and release may extend beyond the interval. Sustained `noteOn` voices last until release, replacement or shutdown.
|
|
116
116
|
- The module synthesizes waveforms and does not play audio files.
|
|
117
117
|
- One native transport supports up to four independent sequences, preallocated by `maxSequences`. All share at most 32 voices.
|
|
118
|
-
- A single tone or chord has no completion event.
|
|
118
|
+
- A single finite tone or chord has no completion event. A pattern control emits `end` with its completed/stopped reason.
|
|
119
119
|
- Voice capacity and mixing profile remain fixed until shutdown.
|
|
120
|
-
-
|
|
120
|
+
- Patterns run on the sample clock in beats or milliseconds. Root and step `interval` control onset spacing; `length` independently controls note duration.
|
|
121
121
|
- `lowPassHz` is a plain one-pole filter. The resonant filter has fixed 12 dB per octave and one exponential sweep; there is no filter envelope.
|
|
122
122
|
- FM has one modulator and works only on `SINE`.
|
|
123
123
|
- Binaural positions occupy a front plane. Spatial held voices support smooth live movement; there is no rear positioning, distance attenuation or head tracking. Output is two channels, without a multichannel 2.1/5.1 routing API.
|
|
@@ -128,10 +128,10 @@ Use a sample player or a dedicated music engine when a product needs streaming,
|
|
|
128
128
|
|
|
129
129
|
## Use effects and held voices deliberately
|
|
130
130
|
|
|
131
|
-
Use `noteOn` for a sound whose duration follows interaction, such as a key, motor or beam; release its
|
|
131
|
+
Use `sound.noteOn()` for a sound whose duration follows interaction, such as a key, motor or beam; release its note control on touch end, cancellation, pause or scene teardown. Use a pattern definition for a finite musical cue or repeating grid. The native engine sustains notes and schedules attacks. Both share the same 32-voice maximum with collision and interface tones; held notes can be stolen, and updates to a stolen note are accepted as no-ops. Optional priority 0-3 affects stealing without reserving voices. There is no voice-finished event.
|
|
132
132
|
|
|
133
133
|
Keep chorus/delay/reverb mixes modest when dialogue or short game feedback must remain distinct. By default they process all four categories, so enabling reverb for a victory chord also affects simultaneous shots and collisions. Select categories with `applyTo` and assign each voice a `bus`, or use explicit `effectSend` values to choose the processed share. All selected voices share one effects chain. Disabling effects lets tails drain for at most 30 seconds; use panic when immediate history invalidation is required. Start with saturation disabled and compare creative drive at matched levels. Do not use saturation as an automatic substitute for the final limiter.
|
|
134
134
|
|
|
135
135
|
Fixed input/event gain does not decrease when unrelated voices start. If level dips, inspect `maxLimiterReductionDb` and `preLimiterPeakDb`, then consider same-pitch phase cancellation or the device's speaker protection. Eight coherent independent voices can still exceed the limiter threshold; module capacity is not a clean-mix loudness guarantee. See [measurement example](advanced-examples.md#measure-peaks-and-limiter-reduction).
|
|
136
136
|
|
|
137
|
-
Measure the complete workload on each target device, including held voices, binaural, LFOs, all enabled effects and tails. The [historical statistics benchmark](stats-performance.md) predates these features; the [current technical report](studio-validation.json) includes an unmet full-chain host deadline criterion. Neither is a guarantee of game-frame rate, physical audio deadlines, heat or battery life.
|
|
137
|
+
Measure the complete workload on each target device, including held voices, binaural, LFOs, all enabled effects and tails. The [historical statistics benchmark](https://github.com/macCesar/TiSynthEngine/blob/9d74aa45f84d3f2822d4aab76874efe37d81257f/documentation/stats-performance.md) predates these features; the [current technical report](https://github.com/macCesar/TiSynthEngine/blob/9d74aa45f84d3f2822d4aab76874efe37d81257f/docs/validation/studio-validation.json) includes an unmet full-chain host deadline criterion. Neither is a guarantee of game-frame rate, physical audio deadlines, heat or battery life.
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
> Source snapshot: official TiSynthEngine documentation at commit `9d74aa45f84d3f2822d4aab76874efe37d81257f` (2026-11-03). Published module 2.0.0. Upstream `documentation/sound-api.md` SHA-256: `bb7bfe10a63aba700bdd3584e803436852e07200b82798f5f16c83383687a546`.
|
|
2
|
+
|
|
3
|
+
# Sound objects: TiSynth 2.0.0
|
|
4
|
+
|
|
5
|
+
TiSynth 2.0.0 provides reusable sound definitions and independent playback controls on Android and iOS. `createSound()` allocates no voice. Its definition survives `shutdown()` and can play again after `start()`. Rendering, gain, admission limits and scheduling use the existing native tone, chord, held, repetition and sequence paths.
|
|
6
|
+
|
|
7
|
+
TiSynth uses one version: the installed module version. Both `getContract().version` and `getDefaults().version` report `2.0.0`. `getContract()` also describes `capabilities.soundObjects: true`, supported interpretations, property names and units.
|
|
8
|
+
|
|
9
|
+
## First sound
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
const synth = require('ti.synthengine')
|
|
13
|
+
const contract = synth.getContract()
|
|
14
|
+
if (contract.version !== '2.0.0') throw new Error('Sound objects require TiSynth 2.0.0')
|
|
15
|
+
if (!synth.start({ maxVoices: 16, maxSequences: 4, mixingProfile: 'conservative', audioSession: 'ambient' })) {
|
|
16
|
+
throw new Error('Audio startup rejected')
|
|
17
|
+
}
|
|
18
|
+
const bell = synth.createSound({
|
|
19
|
+
name: 'Bell',
|
|
20
|
+
sound: { waveType: contract.waveTypes.SINE, volume: 0.25, attack: 5, release: 120 },
|
|
21
|
+
playback: { type: 'tone', notes: ['A4'], duration: 400 }
|
|
22
|
+
})
|
|
23
|
+
if (!bell.play()) throw new Error('Bell rejected')
|
|
24
|
+
bell.play({ notes: ['C5'], volume: 0.15 })
|
|
25
|
+
synth.setVolume(0.8)
|
|
26
|
+
synth.setTempo(110)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Start the engine after the owning screen has settled, and call `shutdown()` when its audio owner closes. Follow the [lifecycle guidance](guide.md#lifecycle) and plan the [voice budget](recommendations.md). A later higher-priority event can replace a finite event that was accepted earlier.
|
|
30
|
+
|
|
31
|
+
## Stored definitions and temporary overrides
|
|
32
|
+
|
|
33
|
+
A preset has optional `name`, `sound` and `playback` dictionaries. `sound` holds synthesis and routing; `playback` holds pitch and interpretation. `getPreset()` returns a detached copy, preserving whether `type` was authored or inferred. Inputs are copied too.
|
|
34
|
+
|
|
35
|
+
`Sound.set({ sound, playback })` recursively merges objects, replaces whole arrays and validates the complete result before replacing the stored definition. A failed change throws without partially applying it. `null` removes an optional leaf when the remaining preset is valid; it does not remove a whole `sound` or `playback` dictionary. Arrays, including `steps`, `notes`, `frequencies`, `waveTable`, `modulations` and variation ranges, replace the complete array; they do not concatenate. `set()` affects future executions; it does not edit controls already playing.
|
|
36
|
+
|
|
37
|
+
`Sound.play(changes)` and `Sound.noteOn(changes)` accept **flat** overrides, such as `{ notes: ['D4'], volume: 0.2 }`. They do not accept nested `{ sound, playback }` arguments. An execution never mutates the stored preset. Repetition and pattern updates also accept `null` to remove an optional leaf when the complete resulting revision is valid. Such resets replace the native recipe without restarting its transport or repetition deadline. Held-note updates require concrete live values; use supported disabling values such as zero or an empty modulation array. Setting `notes` replaces a previously stored `frequencies` source and vice versa; supplying both together throws.
|
|
38
|
+
|
|
39
|
+
```javascript
|
|
40
|
+
const sound = synth.createSound({
|
|
41
|
+
sound: { volume: 0.3, pan: 0.2, variation: { amount: 1, ranges: { volume: [0.2, 0.3] } } },
|
|
42
|
+
playback: { notes: ['C4'], duration: 300 }
|
|
43
|
+
})
|
|
44
|
+
sound.set({ sound: { pan: null, variation: { amount: 0.5 } } })
|
|
45
|
+
sound.set({ playback: { notes: ['D4'] } })
|
|
46
|
+
const preset = sound.getPreset()
|
|
47
|
+
// The volume range is retained; pan is absent; notes is now exactly ['D4'].
|
|
48
|
+
if (preset.sound.pan !== undefined || preset.playback.notes.length !== 1) throw new Error('Unexpected preset')
|
|
49
|
+
sound.play({ notes: ['E4'] })
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Unknown keys, wrong types, incompatible fields and out-of-range values throw descriptive `TypeError`s before publication. Fields are never silently stripped to make a definition valid. Numeric ranges and waveform-dependent rules remain those in the [native reference](api.md#strict-validation). Operational failures, including an unavailable engine or a rejected publication, return `false`.
|
|
53
|
+
|
|
54
|
+
## Interpretations and returns
|
|
55
|
+
|
|
56
|
+
An explicit type on the call wins over the preset's declared type. If neither declares a type, `steps` infers a pattern, more than one pitch infers a chord, and otherwise a tone is inferred. Inference never writes a type into the stored preset. Repetition and held interpretation require an explicit type, or `noteOn()` for held execution.
|
|
57
|
+
|
|
58
|
+
| Type or method | Accepted return | Playback fields | Native path |
|
|
59
|
+
| --- | --- | --- | --- |
|
|
60
|
+
| `tone` | `true` | `notes` or `frequencies`, `duration`, `frequencyEnd` | One finite tone |
|
|
61
|
+
| `chord` | `true` | `notes` or `frequencies`, `duration` | Atomic finite chord, including an explicitly declared one-note chord |
|
|
62
|
+
| `repeat` | Repetition control | Single pitch, `duration`, `frequencyEnd`, required `interval` | Native finite-tone repetition |
|
|
63
|
+
| `pattern` | Pattern control | `steps`, `interval`, `timeUnit`, `gate`, `loop`, `swing`, `mode`, `tuning`, optional root `frequencyEnd` | Native sequence |
|
|
64
|
+
| `held` or `Sound.noteOn()` | Note control | Single pitch only | Existing sustained voice |
|
|
65
|
+
|
|
66
|
+
All executions can return `false` on operational rejection. Finite tones and chords expose no individual control or identifier. A declared type remains in force when pitches change: `type: 'tone'` with two notes throws; an explicit `type: 'chord'` with one note retains chord gain and admission behavior. Choosing another type does not discard incompatible preset fields: clear or replace them in the definition first.
|
|
67
|
+
|
|
68
|
+
Use either `notes` as note names or integer MIDI notes 12 through 119, or `frequencies` in hertz. Tone, held and repetition use one-element arrays. Chords use 1 through 32 pitches. Numeric pitches in finite/held calls convert to native note names; pattern pitches remain MIDI integers. Keep duplicate pitches when unison is intentional.
|
|
69
|
+
|
|
70
|
+
Each interpretation has restrictions beyond the shared sound-property allowlist below. Finite-tone endpoints cannot be used as held live controls, and the native chord validator rejects sweeps and modulations. Source rules require sine for FM, square for PWM, an active filter for filter targets, and compatible stereo or spatial controls. Use explicit `type: 'held'` when a definition contains held-only modulation or envelopes so construction validates the intended native path.
|
|
71
|
+
|
|
72
|
+
## Held notes
|
|
73
|
+
|
|
74
|
+
```javascript
|
|
75
|
+
const heldSound = synth.createSound({
|
|
76
|
+
sound: { waveType: 0, volume: 0.2, fmRatio: 2, fmDepth: 1, attack: 10, release: 160,
|
|
77
|
+
modulations: [{ target: 'fmDepth', wave: 'sine', rate: 2, depth: 0.1 }] },
|
|
78
|
+
playback: { type: 'held', notes: ['C4'] }
|
|
79
|
+
})
|
|
80
|
+
const note = heldSound.play()
|
|
81
|
+
if (note) {
|
|
82
|
+
note.update({ notes: ['D4'], volume: 0.15, fmDepth: 0 })
|
|
83
|
+
if (!note.noteOff()) throw new Error('Note release rejected; owner must retry or close audio')
|
|
84
|
+
}
|
|
85
|
+
const anotherNote = heldSound.noteOn({ notes: ['E4'] })
|
|
86
|
+
if (anotherNote) anotherNote.noteOff()
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Each start returns an independent `{ update, noteOff }` control with private identity. No `voiceId` is accepted or exposed. `noteOn()` always uses the single-note held path, even when called on a finite preset; finite `playback.duration` and `playback.frequencyEnd` are not applied to that held execution. Incompatible synthesis leaves, such as `sound.panEnd`, still throw rather than being discarded. It accepts flat synthesis and live pitch overrides, not `type`, `duration` or `frequencyEnd`.
|
|
90
|
+
|
|
91
|
+
`Note.update()` accepts `notes` or `frequencies`, `volume`, `pan`, `lfoFreq`, `lfoDepth`, `noiseRate`, `lowPassHz`, `pulseWidth`, `filterHz`, `filterQ`, `fmRatio`, `fmDepth`, `spatialX`, `spatialY`, `effectSend` and `modulations`. Only compatible source controls can change; variation, waveform, attack/release, bus and priority are not live fields. Live FM depth can reach zero. Updates retain phase and envelope, using the existing native 10 ms transition. They validate the live patch without requiring attack-only settings again.
|
|
92
|
+
|
|
93
|
+
Release on touch cancellation, pause and owner teardown. A rejected release remains retryable; the [held ownership guidance](guide.md#hold-and-edit-a-voice) describes bounded recovery. After an accepted release, that control no longer updates or releases a second time. Ended or stolen voices retain the native no-op edit behavior while their control generation remains valid.
|
|
94
|
+
|
|
95
|
+
## Repetition
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
const pulse = synth.createSound({
|
|
99
|
+
sound: { waveType: 1, volume: 0.15, attack: 2, release: 40 },
|
|
100
|
+
playback: { type: 'repeat', frequencies: [440], duration: 120, interval: 200 }
|
|
101
|
+
})
|
|
102
|
+
const repetition = pulse.play()
|
|
103
|
+
if (repetition) {
|
|
104
|
+
repetition.update({ frequencies: [660], interval: 180 })
|
|
105
|
+
repetition.stop()
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
A repetition exposes `{ update, stop }`. `interval` is integer milliseconds from 1 through 60000. Each attack retains finite-tone duration, envelope and sweep semantics. An update affects the next scheduled attack without moving its existing deadline; the edited interval controls the following gap. Already admitted attacks retain their original recipe. `stop()` cancels future attacks while admitted finite attacks finish. Repetition has no end event and uses its existing capacity independently of pattern slots. Shared voice admission still applies to each attack.
|
|
110
|
+
|
|
111
|
+
## Patterns
|
|
112
|
+
|
|
113
|
+
```javascript
|
|
114
|
+
const melody = synth.createSound({
|
|
115
|
+
sound: { waveType: 3, volume: 0.2, attack: 5, release: 80, bus: 'music', priority: 2 },
|
|
116
|
+
playback: { type: 'pattern', timeUnit: 'beats', interval: 0.25, loop: false,
|
|
117
|
+
steps: [{ notes: ['C4'] }, { notes: [64], interval: 0.5, sound: { volume: 0.15 } },
|
|
118
|
+
{ rest: true }, { notes: [60, 64, 67], length: 0.4 }] }
|
|
119
|
+
})
|
|
120
|
+
const pattern = melody.play()
|
|
121
|
+
if (pattern) {
|
|
122
|
+
pattern.addEventListener('end', event => {
|
|
123
|
+
// event.reason is 'completed' or 'stopped'. Release and effects may remain audible.
|
|
124
|
+
Ti.API.info(event.reason)
|
|
125
|
+
})
|
|
126
|
+
pattern.update({ swing: 0.1 })
|
|
127
|
+
const state = pattern.getState()
|
|
128
|
+
if (state) Ti.API.info(state.step)
|
|
129
|
+
pattern.stop()
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
A pattern exposes `{ update, stop, getState, addEventListener, removeEventListener }`. The event name is `end`; its payload is `{ reason: 'completed' | 'stopped' }`, with no native identifier. A control receives completion at most once. `getState()` returns the existing applied transport state with `sequenceId` removed, or `null` when unavailable. Removing a listener requires the same function reference.
|
|
134
|
+
|
|
135
|
+
Root and per-step `interval` specify time until the next attack. `length` still controls sounding length; omitting it uses `gate`. A step contains exactly one of `notes`, `frequencies` or `rest: true`, with optional `interval`, `length`, `gate` and `sound`. Per-step `sound` supplies synthesis settings for that attack. Root `sound.detune` applies the pattern pitch rule. Root `playback.frequencyEnd` maps to the native voice endpoint, while a per-step endpoint belongs in `steps[i].sound.frequencyEnd`.
|
|
136
|
+
|
|
137
|
+
`timeUnit` is `beats` by default or `ms`, and stays fixed during playback. Root interval defaults to 0.25 beats or 100 ms. Patterns contain up to 512 steps and 32 pitches per sounding step, with the existing swing, mode, revision and capacity rules. Updates replace arrays and preserve native revision scheduling; they do not restart transport. Pattern `stop()` remains accepted before its native slot is retired. Coalesce replacements and wait for the owned control's `end` event before publishing the next score when capacity is occupied. An `end` event marks transport retirement, not audible silence: release and processing tails may continue.
|
|
138
|
+
|
|
139
|
+
## Units and processing
|
|
140
|
+
|
|
141
|
+
| Quantity | Unit and meaning |
|
|
142
|
+
| --- | --- |
|
|
143
|
+
| `sound.attack`, `decay`, `release` | Milliseconds in every interpretation |
|
|
144
|
+
| Tone, chord or repetition `playback.duration` | Total milliseconds including release, including the complete finite envelope |
|
|
145
|
+
| Tone or repetition `playback.frequencyEnd` | Hertz; native finite sweep endpoint |
|
|
146
|
+
| Repetition `playback.interval` | Integer milliseconds, independent of global tempo |
|
|
147
|
+
| Pattern root/step `interval` and step `length` | Beats or milliseconds according to the pattern's `timeUnit` |
|
|
148
|
+
| Pattern `frequencyEnd` | Hertz; native note-length sweep timing with release afterward |
|
|
149
|
+
| `setTempo(number)` | Beats per minute, 20 through 300 |
|
|
150
|
+
| `setProcessing().delay.time` | Milliseconds, 20 through 2000 |
|
|
151
|
+
| `setProcessing().reverb.decay` | Milliseconds, 200 through 8000 |
|
|
152
|
+
|
|
153
|
+
Finite and pattern envelopes are different native paths. Converting a finite total duration of 150 ms with 25 ms release to a millisecond pattern requires `length: 125` and `release: 25` to preserve that sounding lifetime; attack spacing is a separate `interval`. Do not replace grouped chords with independent tone starts or convert repetition into a sequence when preserving the original gain and envelope interpretation.
|
|
154
|
+
|
|
155
|
+
```javascript
|
|
156
|
+
synth.setProcessing({ inputGain: 1, applyTo: ['music'],
|
|
157
|
+
delay: { enabled: true, time: 250, feedback: 0.25, mix: 0.1 },
|
|
158
|
+
reverb: { enabled: true, decay: 1500, damping: 0.6, mix: 0.12 } })
|
|
159
|
+
synth.enableStats()
|
|
160
|
+
const statistics = synth.getStats()
|
|
161
|
+
synth.disableStats()
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
`setProcessing()` uses the shared effects chain and strict native validation. Supply delay `time` and reverb `decay` in milliseconds. The adapter converts them to native `timeMs` and seconds-based decay. Other chorus/delay/reverb/saturation, `inputGain` and `applyTo` fields retain the [processing reference](api.md#setmasterprocessingoptions) ranges and semantics.
|
|
165
|
+
|
|
166
|
+
`bus`, `effectSend` and `priority` belong to `sound`, including a step's `sound` where supported. Routes, sends, fixed per-event gain and chord grouping are unchanged. Sound creation does not enable diagnostics; use `enableStats()` and `disableStats()`, and retain unavailable readings as `null`.
|
|
167
|
+
|
|
168
|
+
## Lifetime and errors
|
|
169
|
+
|
|
170
|
+
A Sound is reusable across engine shutdown/start; a playback control is bound to the generation that created it. Shutdown invalidates old controls, which subsequently return `false` for updates/releases/stops and `null` for pattern state. They cannot affect a new execution or a reused app identifier. Stale completion/invalidation events cannot retire a new generation's pattern. Listener installation on an invalid pattern has no effect. `stopAll()` retains its global panic behavior; prefer an owned control for ordinary release or cancellation.
|
|
171
|
+
|
|
172
|
+
The [upgrade guide](upgrade-2.0.0.md) records method mappings and metadata changes. Global `setVolume()` and `setTempo()` return Boolean acceptance. Sound and `setProcessing()` reject invalid configurations with descriptive errors.
|
|
173
|
+
|
|
174
|
+
The [TypeScript declarations](../assets/index.d.ts) describe Sound definitions, controls and the supported direct methods. `Sound.play()` has a mixed return when the stored interpretation is not known at the call: narrow the result before calling a control method, or supply an explicit call `type`. Runtime validation remains authoritative for numeric ranges and combinations.
|
|
175
|
+
|
|
176
|
+
## Property allowlists
|
|
177
|
+
|
|
178
|
+
`getContract()` reports these shared structural allowlists. Native validators then apply each interpretation's compatibility rules.
|
|
179
|
+
|
|
180
|
+
### Sound properties
|
|
181
|
+
|
|
182
|
+
| Keys | Purpose |
|
|
183
|
+
| --- | --- |
|
|
184
|
+
| `attack`, `decay`, `sustain`, `release`, `volume`, `waveType` | Envelope, gain and source |
|
|
185
|
+
| `pan`, `panEnd`, `pans`, `panSpread`, `spatialX`, `spatialY` | Stereo or spatial placement |
|
|
186
|
+
| `lfoFreq`, `lfoDepth`, `noiseRate`, `noiseRateEnd`, `lowPassHz` | Vibrato and noise shaping |
|
|
187
|
+
| `pulseWidth`, `pulseWidthEnd`, `waveTable`, `bitDepth` | Wave shaping |
|
|
188
|
+
| `filterType`, `filterHz`, `filterHzEnd`, `filterQ` | Resonant filter |
|
|
189
|
+
| `fmRatio`, `fmDepth`, `fmDepthEnd`, `detune`, `detunes`, `modulations` | Pitch, FM and compatible LFOs |
|
|
190
|
+
| `bus`, `effectSend`, `priority`, `variation` | Routing, admission and native variation |
|
|
191
|
+
|
|
192
|
+
### Playback properties
|
|
193
|
+
|
|
194
|
+
| Keys | Purpose |
|
|
195
|
+
| --- | --- |
|
|
196
|
+
| `type`, `notes`, `frequencies`, `frequencyEnd`, `duration` | Interpretation, pitches and finite timing |
|
|
197
|
+
| `interval`, `timeUnit`, `steps`, `gate`, `loop`, `swing`, `mode`, `tuning` | Repetition or pattern scheduling |
|