@maccesar/titools 5.2.4 → 5.3.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/README.md +27 -32
- package/agents/ti-pro.md +1 -1
- package/commands/ti-audit.md +1 -1
- package/docs/examples.md +15 -8
- package/package.json +1 -1
- package/skills/ti-synthengine/SKILL.md +62 -92
- package/skills/ti-synthengine/assets/example/README.md +51 -54
- package/skills/ti-synthengine/assets/example/app.js +96 -57
- 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 +226 -0
- package/skills/ti-synthengine/references/advanced-examples.md +12 -12
- package/skills/ti-synthengine/references/api.md +125 -33
- package/skills/ti-synthengine/references/audio-engine.md +24 -59
- package/skills/ti-synthengine/references/examples.md +64 -7
- package/skills/ti-synthengine/references/guide.md +69 -63
- package/skills/ti-synthengine/references/instruments-and-effects.md +34 -27
- package/skills/ti-synthengine/references/native-variation.md +92 -51
- package/skills/ti-synthengine/references/recipes-interaction.md +26 -19
- package/skills/ti-synthengine/references/recipes.md +19 -15
- package/skills/ti-synthengine/references/recommendations.md +14 -14
- package/skills/ti-synthengine/references/sound-api.md +197 -0
- package/skills/ti-synthengine/references/sound-design.md +11 -11
- package/skills/ti-synthengine/references/source-notes.md +62 -147
- package/skills/ti-synthengine/references/troubleshooting.md +22 -24
- package/skills/ti-synthengine/references/upgrade-2.0.0.md +40 -0
- 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-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 -463
- 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
|
@@ -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 |
|
|
@@ -1,11 +1,11 @@
|
|
|
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/sound-design.md` SHA-256: `41f294143b8a4bb8cbee550a66b51768c13a583c94e1f7f810dfdeb471f14922`.
|
|
2
2
|
|
|
3
3
|
# Sound design with TiSynthEngine
|
|
4
4
|
|
|
5
|
-
TiSynthEngine generates sound with oscillators, without recorded samples. Pitch, waveform, envelope, movement and level define each sound, from interface feedback and musical cues to alarms, retro effects and simple percussion.
|
|
6
|
-
|
|
7
5
|
Additional [curated recipes](recipes.md) provide application sound and interaction variants.
|
|
8
6
|
|
|
7
|
+
TiSynthEngine generates sound with oscillators, without recorded samples. Pitch, waveform, envelope, movement and level define each sound, from interface feedback and musical cues to alarms, retro effects and simple percussion.
|
|
8
|
+
|
|
9
9
|
For the distinction between a playable timbre and a complete effect recipe, start with [instruments, sound effects and complete sequences](instruments-and-effects.md). It covers held keys, independent shots, native sequences, layered effects, demonstrations and shared output headroom.
|
|
10
10
|
|
|
11
11
|
The examples assume the engine is running and use these constants:
|
|
@@ -67,7 +67,7 @@ Equal temperament keeps intervals consistent in every key. It also means a major
|
|
|
67
67
|
|
|
68
68
|
## Waveform and timbre
|
|
69
69
|
|
|
70
|
-
Pitch
|
|
70
|
+
Pitch describes how fast the oscillator repeats. Waveform describes its motion within each cycle, which determines the harmonic content and perceived timbre.
|
|
71
71
|
|
|
72
72
|
### Sine
|
|
73
73
|
|
|
@@ -79,7 +79,7 @@ Pitch says how fast the oscillator repeats. Waveform says how it moves within ea
|
|
|
79
79
|
|
|
80
80
|
### Sawtooth
|
|
81
81
|
|
|
82
|
-
`SAWTOOTH` contains both even and odd harmonics. It is the densest pitched waveform in the module and
|
|
82
|
+
`SAWTOOTH` contains both even and odd harmonics. It is the densest pitched waveform in the module and sounds buzzy or brassy. Use it for alarms, arcade leads and short sweeps. Square and sawtooth are band-limited with PolyBLEP to reduce aliasing at discontinuities.
|
|
83
83
|
|
|
84
84
|
### Triangle
|
|
85
85
|
|
|
@@ -235,7 +235,7 @@ A rate around 4 to 7 Hz with a small depth sounds like musical vibrato. A fast r
|
|
|
235
235
|
|
|
236
236
|
`filterType` adds a filter that removes or emphasizes part of the spectrum. It has 12 dB per octave of slope, twice as steep as the one-pole `lowPassHz` filter, and can be combined with it (`lowPassHz` runs first).
|
|
237
237
|
|
|
238
|
-
- `lowpass` darkens the sound. A sawtooth through a closing low-pass
|
|
238
|
+
- `lowpass` darkens the sound. A sawtooth through a closing low-pass sounds like a zap or a sound moving away; an opening one sounds like a swell.
|
|
239
239
|
- `highpass` thins the sound by removing body. It makes hats, hiss and tinny effects out of noise.
|
|
240
240
|
- `bandpass` keeps one band around `filterHz`, which gives vocal, nasal and wah-like colors.
|
|
241
241
|
|
|
@@ -264,7 +264,7 @@ synth.playTone({
|
|
|
264
264
|
|
|
265
265
|
FM makes rich, bright and metallic sounds from a plain sine. A second sine, the modulator, bends the pitch of the first one, the carrier. Turn it on with `fmDepth` or `fmDepthEnd`, on a `SINE` voice.
|
|
266
266
|
|
|
267
|
-
- `fmRatio` is the modulator frequency as a multiple of the carrier's. Whole numbers (1, 2, 3) keep the added overtones on the harmonic series, so the pitch stays clear and the sound
|
|
267
|
+
- `fmRatio` is the modulator frequency as a multiple of the carrier's. Whole numbers (1, 2, 3) keep the added overtones on the harmonic series, so the pitch stays clear and the sound resembles an organ or piano. Fractional ratios such as 1.4142 or 3.5 put the overtones between harmonics, giving the sound the character of bells, glass and metal.
|
|
268
268
|
- `fmDepth` is the modulation index and works like a brightness control. Around 0.5 to 1.5 it warms a sine, 2 to 5 makes it bright and rich, and values near 10 get harsh.
|
|
269
269
|
- `fmDepthEnd` moves the index over the event. Starting high and ending low gives a bright attack that mellows, which is the signature of electric pianos, bells and mallets. Pair it with `decay` so the level falls with the brightness.
|
|
270
270
|
|
|
@@ -341,7 +341,7 @@ Different phones have different sample rates, speaker protection and acoustic re
|
|
|
341
341
|
|
|
342
342
|
## Recipes
|
|
343
343
|
|
|
344
|
-
These recipes use
|
|
344
|
+
These recipes use the supported direct native parameter contract and keep explicit envelopes valid. Reusable definitions put synthesis fields in `sound` and pitches/timing in `playback`; see the [Sound interface](sound-api.md). Adjust pitch and volume to fit the app's other audio; the recipe values are starting points, not mastering targets.
|
|
345
345
|
|
|
346
346
|
### Interface click
|
|
347
347
|
|
|
@@ -593,7 +593,7 @@ synth.playTone({
|
|
|
593
593
|
})
|
|
594
594
|
```
|
|
595
595
|
|
|
596
|
-
The pitch drop
|
|
596
|
+
The pitch drop creates the punch, while the decay shapes the thump. A phone speaker cannot reproduce 42 Hz, so raise `frequencyEnd` toward 70 for speaker playback.
|
|
597
597
|
|
|
598
598
|
### Simon-style cues
|
|
599
599
|
|
|
@@ -630,7 +630,7 @@ See [Examples](examples.md) for complete code and [Recommendations](recommendati
|
|
|
630
630
|
|
|
631
631
|
## Holding a sound and adding movement
|
|
632
632
|
|
|
633
|
-
Choose a held voice when the ending follows a player action instead of a fixed duration: motor, charge beam, pad or the last chord of a ceremony. `noteOn` starts a positive app-owned ID; `noteOff` begins release from the current level, and compatible `
|
|
633
|
+
Choose a held voice when the ending follows a player action instead of a fixed duration: motor, charge beam, pad or the last chord of a ceremony. `noteOn` starts a positive app-owned ID; `noteOff` begins release from the current level, and compatible `updateNote` edits ramp over 10 ms. Distinct IDs remain independent events with fixed gain. Reserve enough capacity for their releases and unrelated effects, and release on cancellation as well as ordinary key up. See the [held motor recipe](advanced-examples.md#sustained-game-motor) for retry/cleanup handling.
|
|
634
634
|
|
|
635
635
|
A fanfare can use beat or millisecond sequences with native chords, rests, gate, independent length, swing and pitch-ordered arpeggios. A long release can ring over later steps. Use held voices when release follows presentation or interaction. See [transport usage](guide.md#choose-the-musical-transport).
|
|
636
636
|
|
|
@@ -647,4 +647,4 @@ The two additional voice LFOs move filter cutoff, square PWM or sine FM index us
|
|
|
647
647
|
|
|
648
648
|
All processors are off initially, with input gain 1. Enable one shared chain through `setMasterProcessing`; select `applyTo` categories such as `music` and `ambience` to keep explosions dry. Per-voice `effectSend` overrides that category selection. [Configuration](advanced-examples.md#chorus-delay-reverb-and-creative-saturation) and [exact ranges](api.md#setmasterprocessingoptions) explain chorus, delay, reverb and optional saturation.
|
|
649
649
|
|
|
650
|
-
Disabling an effect closes its input gradually and drains the tail before exact bypass; it does not immediately erase its history. Panic invalidates histories. Saturation
|
|
650
|
+
Disabling an effect closes its input gradually and drains the tail before exact bypass; it does not immediately erase its history. Panic invalidates histories. Saturation changes the sound and provides no automatic gain protection; the final limiter stays in place. Match dry/wet comparison levels and watch accumulated limiter reduction so a louder version does not win an A/B comparison merely by level. None of these effects makes a small speaker reproduce missing bass.
|
|
@@ -1,147 +1,62 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
These references cover
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
##
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
retained samples, immediate stereo-linked sample protection, ceilings 0.85/0.70,
|
|
64
|
-
100 ms exponential recovery and reset after two consecutive quiet stereo frames.
|
|
65
|
-
Master volume ramps linearly over 10 ms on both platforms, independently of the
|
|
66
|
-
protector. The iOS `raw` startup correction now applies its documented gain;
|
|
67
|
-
existing raw mixes need review. Overload changes the waveform, and sample
|
|
68
|
-
ceilings do not certify inter-sample peaks or speaker behavior.
|
|
69
|
-
|
|
70
|
-
[Pipeline validation](audio-pipeline-validation.md) preserves the new production
|
|
71
|
-
callback/CI checks, five-rate output comparisons and physical scope. Preset
|
|
72
|
-
calibration measures both renderers and six scenarios at 1/2/4/8/16/32 voices;
|
|
73
|
-
fixed-gain recommendations target the measured 1–8-voice configuration, with
|
|
74
|
-
16/32 kept as stress diagnostics. It never edits Studio. The Android startup
|
|
75
|
-
underrun remains unresolved, including independent silent Oboe reproduction.
|
|
76
|
-
Route-wide latency, Bluetooth and extended maximum-load acceptance remain open.
|
|
77
|
-
|
|
78
|
-
Official documentation corrections preserve panic cancellation (`stopAll` stops every
|
|
79
|
-
sequence and invalidates effect histories), compatible live `updateVoice`
|
|
80
|
-
noise/low-pass/spatial/send edits, and category selection with `applyTo` plus
|
|
81
|
-
explicit `effectSend` overrides. The matching mirror-only errata were removed from the transformation list; curated recipe navigation remains reversible.
|
|
82
|
-
Android and Apple production callback tests now run in CI; the historical Java
|
|
83
|
-
DSP model is not the production audio oracle. No native binaries were installed
|
|
84
|
-
or device/listening tests rerun during this skill update.
|
|
85
|
-
|
|
86
|
-
### Historical evidence
|
|
87
|
-
|
|
88
|
-
The [performance review](performance-review.json) documents the accepted
|
|
89
|
-
control-thread changes: partial sequence-bank preparation and removal of idle
|
|
90
|
-
allocations/orphan held-position metadata. The Apple rendering bundle was
|
|
91
|
-
rejected after a physical stereo regression, and production returned to the
|
|
92
|
-
stable callback. Earlier candidate timings and fidelity checks remain evidence
|
|
93
|
-
of that rejected candidate, not a promised Apple render speedup. Current matched
|
|
94
|
-
Apple bypass measurements and actual hardware/rate/block-size scope are in the
|
|
95
|
-
report; global performance acceptance remains open.
|
|
96
|
-
|
|
97
|
-
Historical statistics, Studio/unified transport, physical/Frontier measurements
|
|
98
|
-
and Android FIR8 correction reports keep their original artifact and acceptance
|
|
99
|
-
boundaries. The short Android Sim80 headphone result had zero backend xruns and
|
|
100
|
-
accepted listening; it does not close the distinct ten-minute maximum-load,
|
|
101
|
-
bypass, memory and strict Frontier presentation criteria. Current evidence and
|
|
102
|
-
rejected candidates must not be combined into a general pass. This skill update
|
|
103
|
-
did not rerun devices, install binaries or alter native source.
|
|
104
|
-
|
|
105
|
-
The native differences below were rechecked against current sources on November 2 and are now documented accurately in the official API/engine guides as well as the mirrors. They describe implementation differences, not unresolved documentation contradictions:
|
|
106
|
-
|
|
107
|
-
- iOS timed tone/chord command construction initially rounds accepted zero attack
|
|
108
|
-
and release to one sample before duration-budget trimming; Android preserves zero. Validator
|
|
109
|
-
acceptance does not establish identical sample envelopes.
|
|
110
|
-
- iOS early tempo/sequence/processing rejections and incompatible held spatial/
|
|
111
|
-
modulation edits can bypass rejection counters. Android also leaves some
|
|
112
|
-
unknown/retired sequence-stop returns uncounted. The recorded reason sum is
|
|
113
|
-
consistent with recorded totals, not a complete API-call rejection tally.
|
|
114
|
-
- Sequence cutoff coefficients currently refresh every 16 samples on Android
|
|
115
|
-
and every 8 samples on Apple; both use note length but do not promise identical
|
|
116
|
-
sample output. See [engine details](audio-engine.md).
|
|
117
|
-
- Local 1.1.0 returns `capabilities.variation: true` and `variationSchemaVersion: 1` on both platforms. Android also reports native sequence/master processing/modulation flags and `limits.stepDurationMs`; iOS omits those additional entries. Published 1.0.2 does not accept variation. Both platforms return sequence-capacity, priority and send limits; use the [API](api.md) for exact beat/millisecond ranges.
|
|
118
|
-
- Official examples now bind their waveform constants and document native sequence modulation, complete effect fidelity and publication ownership correctly. The mirrors preserve the same facts.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
These are official-documentation and skill corrections, not native implementation fixes. No module code, public range or hardware acceptance was changed.
|
|
122
|
-
A validator corpus establishes accepted/rejected dictionaries, not sample-identical
|
|
123
|
-
rendering on a physical device. Current source-first coverage ledgers and native locators are recorded in the maintainer's November 2 audit evidence.
|
|
124
|
-
|
|
125
|
-
## Local 1.1.0 attack variation
|
|
126
|
-
|
|
127
|
-
Both platforms validate eight bounded parameter ranges and select once per admitted attack. Require the capability/schema pair and omit the property entirely on published 1.0.2, including amount zero. The [variation guide](native-variation.md) preserves exact bounds, linear amount, pitch ratio, source prerequisites, per-chord ordinals, held stability, whole-dictionary step replacement, revision merging and deterministic seed identity. `updateVoice` rejects the attack dictionary. Preserve all of the authored envelope, cadence, routing and layer gains.
|
|
128
|
-
|
|
129
|
-
The [verification report](native-variation-validation.md) separates initial host/build checks from later consumer installations and scoped listening feedback. It records the 144-byte configuration and four-transport growth from 8,627,712 to 9,537,152 bytes, excluding other engine/bridge/process storage. Earlier 1.0.2 memory reports remain historical. Host callback timings do not prove device overhead or sustained acceptance.
|
|
130
|
-
|
|
131
|
-
This audit reran the paired production validators (156 cases per platform), the affected documentation checks and TiTools mirror/recipe checks. New source inspection verified sampling/admission and sequence seed identity. Historical renderer PCM, native build, consumer install and listening results were read with their original boundaries; they were not repeated or expanded into general device acceptance. No native source or binary was changed.
|
|
132
|
-
|
|
133
|
-
All thirteen raw JSON/ZIP records moved upstream from `documentation/` to `docs/validation/` without changing bytes. Their distributed skill paths are preserved; the snapshot now records their actual upstream locations. All five ZIPs passed CRC checks. The three example JavaScript assets remain byte-identical; `app.js` now includes the capability-gated attack-variation action.
|
|
134
|
-
|
|
135
|
-
## Upstream documents outside the mirror set
|
|
136
|
-
|
|
137
|
-
The official index is replaced by this skill's task routing. Dependency/license notices remain in the official module and binary packages. Both are recorded with hashes and reasons in `excluded_documents`, so changed or newly added documents still require review.
|
|
138
|
-
|
|
139
|
-
## Verification after a reviewed update
|
|
140
|
-
|
|
141
|
-
Run the focused mirror/link and recipe tests, then:
|
|
142
|
-
|
|
143
|
-
```sh
|
|
144
|
-
node scripts/verify-module-snapshot.mjs --source /path/to/TiSynthEngine --skill ti-synthengine
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
The verifier checks source/mirror hashes, exclusions, new documents, base HEAD and the exact tracked/untracked worktree fingerprint. Refresh that fingerprint only after the source changes are finished. No npm version, publication or native-device acceptance follows from this procedure.
|
|
1
|
+
# Source and platform caveats
|
|
2
|
+
|
|
3
|
+
These references cover published TiSynthEngine 2.0.0, reviewed at
|
|
4
|
+
`9d74aa45f84d3f2822d4aab76874efe37d81257f` on 2026-11-03. Both platform
|
|
5
|
+
release ZIPs declare 2.0.0 and their packaged declarations match the bundled
|
|
6
|
+
[TypeScript asset](../assets/index.d.ts). Read the [guide](guide.md) for
|
|
7
|
+
installation and the [upgrade guide](upgrade-2.0.0.md) for migration.
|
|
8
|
+
|
|
9
|
+
## Choose the correct interface
|
|
10
|
+
|
|
11
|
+
Use [Sound objects](sound-api.md) for new code. The [direct API](api.md) remains
|
|
12
|
+
supported, including its Boolean/ID return contracts and original option names.
|
|
13
|
+
The [sound](recipes.md) and [interaction](recipes-interaction.md) recipes use
|
|
14
|
+
that direct interface. Preserve their pitch, envelope, gain and timing when
|
|
15
|
+
adapting them. A Sound definition survives shutdown, but its playback controls
|
|
16
|
+
become invalid.
|
|
17
|
+
Do not combine `sound`/`playback` presets with direct native dictionaries.
|
|
18
|
+
|
|
19
|
+
Runtime metadata uses `version`, not `apiVersion`. Native module manifest
|
|
20
|
+
`apiversion` is a separate Titanium ABI field. Older 1.0.2 binaries lack variation
|
|
21
|
+
and repetition; detect methods/capabilities before sending new closed-dictionary
|
|
22
|
+
fields. Native variation requires its capability and schema pair. Android reports
|
|
23
|
+
some extra sequence/processing/modulation flags that iOS omits while supporting
|
|
24
|
+
the methods; do not use those flags as a universal feature gate.
|
|
25
|
+
|
|
26
|
+
`setProcessing()` reverb decay is milliseconds; direct `setMasterProcessing()`
|
|
27
|
+
reverb decay remains seconds. See the [unit mapping](upgrade-2.0.0.md#names-and-units).
|
|
28
|
+
|
|
29
|
+
## Native differences that affect decisions
|
|
30
|
+
|
|
31
|
+
- Submit exact integer repetition intervals. The reviewed Apple validator accepts
|
|
32
|
+
values extremely close to an integer within its 1e-9 tolerance and truncates
|
|
33
|
+
them; Android rejects them. This is not a portable fractional interval feature.
|
|
34
|
+
- Timed zero attack/release initially becomes one sample on Apple before duration
|
|
35
|
+
trimming; Android preserves zero. Matching validation does not establish
|
|
36
|
+
sample-identical envelopes.
|
|
37
|
+
- Some early Apple rejections and unknown/retired Android sequence stops bypass
|
|
38
|
+
rejection counters. Recorded reason totals describe recorded failures, not
|
|
39
|
+
every rejected API call.
|
|
40
|
+
- Sequence filter sweeps refresh every 16 samples on Android and every 8 on Apple.
|
|
41
|
+
Both use note length, but their PCM output is not guaranteed to match.
|
|
42
|
+
|
|
43
|
+
Exact constraints and platform differences are in the [API](api.md) and
|
|
44
|
+
[engine](audio-engine.md). Sound objects follow the same native source-compatibility rules.
|
|
45
|
+
|
|
46
|
+
## Diagnose audio without overstating evidence
|
|
47
|
+
|
|
48
|
+
Use the [statistics API](api.md#getstats) and [engine telemetry](audio-engine.md#engine-statistics).
|
|
49
|
+
Keep unavailable readings as `null`, poll slowly, and cancel the owner's timer.
|
|
50
|
+
Render load is callback work divided by its deadline, not whole-app CPU.
|
|
51
|
+
Sample-peak ceilings do not certify speaker safety or inter-sample peaks.
|
|
52
|
+
Start after layout settles; Android startup underruns, output routes, Bluetooth
|
|
53
|
+
latency and sustained maximum load require their own device checks.
|
|
54
|
+
|
|
55
|
+
The official [Sound validation record](https://github.com/macCesar/TiSynthEngine/blob/9d74aa45f84d3f2822d4aab76874efe37d81257f/documentation/sound-api-validation.md)
|
|
56
|
+
separates validator, bridge, within-platform PCM, host allocation/GC and scoped
|
|
57
|
+
physical evidence. Host dispatch timings are not Titanium bridge/device latency;
|
|
58
|
+
byte-identical PCM comparisons are within each platform, not across platforms.
|
|
59
|
+
Historical measurements retain their original revision and acceptance limits,
|
|
60
|
+
including failed or inconclusive results. They do not certify every workload.
|
|
61
|
+
Raw reports and reproduction tools remain in the native module repository
|
|
62
|
+
for maintenance. You do not need those files to implement sounds.
|