@maccesar/titools 5.2.0 → 5.2.1

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.
Files changed (78) hide show
  1. package/CONTRIBUTING.md +69 -0
  2. package/README.md +80 -72
  3. package/agents/ti-pro.md +1 -1
  4. package/commands/ti-audit.md +2 -2
  5. package/docs/examples.md +91 -0
  6. package/docs/knowledge-index.md +57 -0
  7. package/lib/downloader.js +1 -1
  8. package/package.json +4 -2
  9. package/skills/purgetss/references/multi-density-images.md +1 -1
  10. package/skills/ti-admob-unified/SKILL.md +21 -7
  11. package/skills/ti-admob-unified/assets/example/app.js +229 -25
  12. package/skills/ti-admob-unified/assets/example/lib/ads.js +30 -2
  13. package/skills/ti-admob-unified/assets/example/library-usage.js +33 -1
  14. package/skills/ti-admob-unified/references/api-reference.md +39 -16
  15. package/skills/ti-admob-unified/references/banners.md +9 -9
  16. package/skills/ti-admob-unified/references/contributing.md +14 -9
  17. package/skills/ti-admob-unified/references/dependencies.md +31 -25
  18. package/skills/ti-admob-unified/references/fullscreen.md +43 -28
  19. package/skills/ti-admob-unified/references/game-monetization.md +138 -7
  20. package/skills/ti-admob-unified/references/getting-started.md +75 -31
  21. package/skills/ti-admob-unified/references/index.md +5 -2
  22. package/skills/ti-admob-unified/references/integration.md +8 -6
  23. package/skills/ti-admob-unified/references/library.md +41 -10
  24. package/skills/ti-admob-unified/references/mediation-parity.md +17 -0
  25. package/skills/ti-admob-unified/references/mediation.md +22 -9
  26. package/skills/ti-admob-unified/references/migration.md +11 -7
  27. package/skills/ti-admob-unified/references/module-changelog.md +41 -11
  28. package/skills/ti-admob-unified/references/privacy.md +35 -8
  29. package/skills/ti-admob-unified/references/production.md +67 -0
  30. package/skills/ti-admob-unified/references/rewarded-interstitial.md +101 -0
  31. package/skills/ti-admob-unified/references/roadmap.md +28 -31
  32. package/skills/ti-admob-unified/references/source-notes.md +51 -4
  33. package/skills/ti-admob-unified/references/source-snapshot.json +249 -45
  34. package/skills/ti-admob-unified/references/third-party-notices.md +4 -4
  35. package/skills/ti-game/SKILL.md +23 -6
  36. package/skills/ti-game/references/api.md +34 -30
  37. package/skills/ti-game/references/debugging-performance.md +18 -9
  38. package/skills/ti-game/references/examples.md +103 -20
  39. package/skills/ti-game/references/input.md +101 -0
  40. package/skills/ti-game/references/patterns.md +39 -15
  41. package/skills/ti-game/references/physics.md +80 -52
  42. package/skills/ti-game/references/project-setup.md +118 -56
  43. package/skills/ti-game/references/recipes-action.md +107 -8
  44. package/skills/ti-game/references/recipes-adventure-effects.md +41 -9
  45. package/skills/ti-game/references/roadmap.md +10 -3
  46. package/skills/ti-game/references/source-notes.md +81 -0
  47. package/skills/ti-game/references/tilemaps.md +12 -4
  48. package/skills/ti-synthengine/SKILL.md +81 -95
  49. package/skills/ti-synthengine/assets/example/README.md +84 -0
  50. package/skills/ti-synthengine/assets/example/app.js +1178 -0
  51. package/skills/ti-synthengine/assets/example/lib/sequenceOwner.js +83 -0
  52. package/skills/ti-synthengine/assets/example/lib/sequenceScore.js +25 -0
  53. package/skills/ti-synthengine/references/advanced-examples.md +174 -0
  54. package/skills/ti-synthengine/references/android-sim80-correction-evidence.zip +0 -0
  55. package/skills/ti-synthengine/references/android-sim80-correction.json +162 -0
  56. package/skills/ti-synthengine/references/api.md +434 -380
  57. package/skills/ti-synthengine/references/audio-engine.md +157 -230
  58. package/skills/ti-synthengine/references/bypass-physical-recheck-evidence.zip +0 -0
  59. package/skills/ti-synthengine/references/examples.md +123 -253
  60. package/skills/ti-synthengine/references/frontier-android-evidence.zip +0 -0
  61. package/skills/ti-synthengine/references/frontier-ipad-evidence.zip +0 -0
  62. package/skills/ti-synthengine/references/frontier-physical-validation.json +1918 -0
  63. package/skills/ti-synthengine/references/guide.md +188 -156
  64. package/skills/ti-synthengine/references/performance-review-evidence.zip +0 -0
  65. package/skills/ti-synthengine/references/performance-review.json +1146 -0
  66. package/skills/ti-synthengine/references/physical-validation.json +1457 -0
  67. package/skills/ti-synthengine/references/recipes-interaction.md +549 -0
  68. package/skills/ti-synthengine/references/recipes.md +423 -599
  69. package/skills/ti-synthengine/references/recommendations.md +63 -113
  70. package/skills/ti-synthengine/references/sound-design.md +134 -258
  71. package/skills/ti-synthengine/references/source-notes.md +93 -105
  72. package/skills/ti-synthengine/references/source-snapshot.json +379 -32
  73. package/skills/ti-synthengine/references/stats-performance.md +64 -20
  74. package/skills/ti-synthengine/references/studio-validation.json +6202 -0
  75. package/skills/ti-synthengine/references/troubleshooting.md +109 -121
  76. package/skills/ti-synthengine/references/unified-bypass-performance.json +22425 -0
  77. package/skills/ti-synthengine/references/unified-validation.json +314 -0
  78. package/AGENTS-VERCEL-RESEARCH.md +0 -175
@@ -1,62 +1,51 @@
1
- > Source snapshot: official TiSynthEngine 1.0.0 beta documentation from the reviewed working tree based on `95901c98af5353b86d9dc7c60b29ab9186b038cd` (2026-10-14), including uncommitted statistics changes. Upstream `documentation/troubleshooting.md` SHA-256: `10949f8f18f9e97933bfb1f025a12217746648c01805ff0fafe2c8e064b1c0cc`.
1
+ > Source snapshot: official TiSynthEngine 1.0.0 documentation at release source commit `e7cbbe8a6f9ab38088fd8029c7b43cef6501101f` (2026-10-24). Upstream `documentation/troubleshooting.md` SHA-256: `939960cde5860569699916208c0d3b352e60ba2a7603b5046dcefa9970294b70`.
2
2
 
3
3
  # Troubleshooting
4
4
 
5
- Start with the Boolean returned by the call and the native log. Most silent
6
- requests are contract rejections, a stale binary or an engine that never
7
- started.
5
+ Start with the Boolean returned by the call and the native log. Most silent requests are contract rejections, a stale binary or an engine that never started.
8
6
 
9
7
  ## A call returns `false`
10
8
 
11
- Look for a structured warning in logcat or the Xcode console:
9
+ For methods that emit structured validation warnings, inspect logcat or the Xcode console:
12
10
 
13
11
  ```text
14
- event=validation_warning method=playPattern key=steps reason=invalid_step_type action=rejected value=C4
12
+ event=validation_warning method=playTone key=duraton reason=unsupported_option action=rejected value=200
15
13
  ```
16
14
 
15
+ Always check the return value: `playSequence` rejects with 0, while Boolean methods reject with `false`. Some sequence/control rejection paths do not emit a structured warning; absence of a new log entry does not establish acceptance.
16
+
17
17
  Common fixes:
18
18
 
19
- | Reason | Check |
20
- | --- | --- |
21
- | `unsupported_option` | Remove or correct the named key. Every options object is strict. |
22
- | `invalid_step_type` | Make every pattern step an object, not a number or string. |
23
- | `conflicting_pitch_fields` | Send only one of `note`, `frequency` or `rest: true`. |
24
- | `missing_pitch_or_rest` | Add one pitch field or an explicit rest. |
25
- | `out_of_range` | Compare the value with `getDefaults().limits`. |
26
- | `not_integer` | Use whole milliseconds and integer waveform values where required. |
27
- | `invalid_note` | Check spelling, accidental case and octave. |
28
- | `invalid_sample_count` | Supply 2 to 64 values in `waveTable`. |
29
- | `unsupported_value` | Use `none`, `lowpass`, `highpass` or `bandpass` for `filterType`. |
30
- | `sustain_without_decay` | Add a `decay` greater than 0, or remove `sustain`. |
31
- | `decay_exceeds_remaining_duration` | Shorten `attack` or `decay`, or lengthen `duration`. The default attack counts. |
32
- | `filter_type_required` | Set `filterType` to a filter, or remove `filterHz`, `filterHzEnd` and `filterQ`. |
33
- | `fm_requires_sine` | Use `SINE` for FM, or set `fmDepth` to 0 and remove `fmDepthEnd`. |
34
- | `fm_depth_required` | Set `fmDepth` or `fmDepthEnd`, or remove `fmRatio`. |
35
- | `conflicting_spatial_fields` | Remove `pan`, `panEnd`, `pans` and `panSpread` whenever sending `spatialX` or `spatialY`; check pattern root and steps. |
36
- | `too_many_values` | Pass no more `pans` or `detunes` than the chord has pitches. |
37
- | `missing_required` with `waveTable` | Add a table whenever `waveType` is `WAVETABLE`. |
38
- | envelope reason | Make attack and release fit inside total duration. |
39
-
40
- Warnings are deduplicated by method, key and reason. Repeating the same bad
41
- call may return `false` without printing a new line each time.
42
-
43
- An `overflow` warning means the command queue was full. Reduce the command
44
- burst or wait for the audio thread to consume queued work. Chords are rejected
45
- as a whole rather than partially started.
46
-
47
- The envelope and filter rules read the values a sounding event ends up with.
48
- In a pattern that means the step over the pattern root, so a `sustain` on the
49
- root is fine when each step supplies a `decay`, and a root `filterHz` is
50
- rejected when no step has a `filterType`. A `detune` that pushes the pitch, or
51
- `frequencyEnd`, outside the frequency range is rejected with `out_of_range`.
52
-
53
- `fmDepthEnd: 0` is valid. It sweeps the index down to nothing. Omit the key,
54
- rather than passing 0, when the index should not move.
55
-
56
- For the shaping controls, check the discontinuous disabled values as well
57
- as the numeric range: `bitDepth` accepts 0 or 2 through 16, and
58
- `pulseWidthEnd` accepts 0 or 0.05 through 0.95. A `waveTable` must contain only
59
- finite values from -1 to 1.
19
+ | Reason | Check |
20
+ | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
21
+ | `unsupported_option` | Remove or correct the named key. Every options object is strict. |
22
+ | `invalid_step_type` | Make every pattern step an object, not a number or string. |
23
+ | `conflicting_pitch_fields` | Timed/held calls use mutually exclusive `note`/`frequency`; each sequence step uses exactly one `notes` array, `frequencies` array or `rest: true`. |
24
+ | `missing_pitch_or_rest` | Add one pitch field or an explicit rest. |
25
+ | `out_of_range` | Compare the value with `getDefaults().limits`. |
26
+ | `not_integer` | Use integer milliseconds for timed tone/chord envelope fields and integer waveform values; native sequence intervals and lengths may be fractional. |
27
+ | `invalid_note` | Check spelling, accidental case and octave. |
28
+ | `invalid_sample_count` | Supply 2 to 64 values in `waveTable`. |
29
+ | `unsupported_value` | Use `none`, `lowpass`, `highpass` or `bandpass` for `filterType`. |
30
+ | `sustain_without_decay` | Add a `decay` greater than 0, or remove `sustain`. |
31
+ | `decay_exceeds_remaining_duration` | Shorten `attack` or `decay`, or lengthen `duration`. The default attack counts. |
32
+ | `filter_type_required` | Set `filterType` to a filter, or remove `filterHz`, `filterHzEnd` and `filterQ`. |
33
+ | `fm_requires_sine` | Use `SINE` for FM, or set `fmDepth` to 0 and remove `fmDepthEnd`. |
34
+ | `fm_depth_required` | Set `fmDepth` or `fmDepthEnd`, or remove `fmRatio`. |
35
+ | `conflicting_spatial_fields` | Remove `pan`, `panEnd`, `pans` and `panSpread` whenever sending `spatialX` or `spatialY`; check pattern root and steps. |
36
+ | `too_many_values` | Pass no more `pans` or `detunes` than the chord has pitches. |
37
+ | `missing_required` with `waveTable` | Add a table whenever `waveType` is `WAVETABLE`. |
38
+ | envelope reason | Make attack and release fit inside total duration. |
39
+
40
+ Warnings are deduplicated by method, key and reason. Repeating the same bad call may return `false` without printing a new line each time.
41
+
42
+ An `overflow` warning means the command queue was full. Reduce the command burst or wait for the audio thread to consume queued work. A chord is either accepted in full or rejected; it cannot start partially.
43
+
44
+ The envelope and filter rules apply to the final values of each sounding event. In a native sequence, each step's `overrides` merges over root `voice`: root `voice.sustain` is valid when every sounding step supplies compatible decay, and `voice.filterHz` needs a non-none filter type after merging. Timed tones/chords enforce their total-duration envelope budget; held and sequence ADSR has no sequence-interval budget. A `detune` that pushes the pitch, or `frequencyEnd`, outside the frequency range is rejected with `out_of_range`.
45
+
46
+ `fmDepthEnd: 0` is valid. It sweeps the index down to nothing. Omit the key, rather than passing 0, when the index should not move.
47
+
48
+ For the shaping controls, check the discontinuous disabled values as well as the numeric range: `bitDepth` accepts 0 or 2 through 16, and `pulseWidthEnd` accepts 0 or 0.05 through 0.95. A `waveTable` must contain only finite values from -1 to 1.
60
49
 
61
50
  ## The installed contract is wrong
62
51
 
@@ -69,20 +58,18 @@ if (actual !== '1.0.0') {
69
58
  }
70
59
  ```
71
60
 
72
- Confirm both entries in `tiapp.xml` pin 1.0.0. Then remove the application's
73
- build output and rebuild so Titanium does not reuse an archive from an earlier
74
- build. The module directories should be:
61
+ Confirm both entries in `tiapp.xml` pin 1.0.0. Then remove the application's build output and rebuild so Titanium does not reuse an archive from an earlier build. The module directories should be:
75
62
 
76
63
  ```text
77
64
  modules/android/ti.synthengine/1.0.0/
78
65
  modules/iphone/ti.synthengine/1.0.0/
79
66
  ```
80
67
 
81
- For binaural, also inspect `getDefaults().limits.spatialX` and `.spatialY`. During the unreleased beta, two binaries can both report 1.0.0 while only one includes positioning. Copying the package does not update an already installed app: rebuild and reinstall it.
68
+ For binaural, also inspect `getDefaults().limits.spatialX` and `.spatialY`. Use the official packages to avoid stale development binaries. Copying the package does not update an already installed app: rebuild and reinstall it.
82
69
 
83
70
  ## Binaural does not change the position
84
71
 
85
- Check the actual object sent to the native method, not only the settings screen:
72
+ Inspect the options sent to the native method as well as the settings screen:
86
73
 
87
74
  - Every effect that should be spatial sends `spatialX` and/or `spatialY`. A switch alone does not modify existing playback calls.
88
75
  - Values are finite numbers within -1 to 1, with positive Y above and negative Y below. A 0 to 100% height slider scales the source position; it does not put all sounds above.
@@ -90,110 +77,81 @@ Check the actual object sent to the native method, not only the settings screen:
90
77
  - No stereo placement fields remain, even with value 0 or through pattern inheritance. Handle the Boolean return value.
91
78
  - The installed contract reports both spatial limits and the device has the rebuilt app.
92
79
  - Use headphones and one broadband event at a time; with binaural off, points with the same X use the same horizontal placement regardless of Y.
93
- - Positions are fixed for active voices. Later calls can use updated coordinates, but there is no method to move a voice already playing.
80
+ - Timed tones/chords and each sequence attack keep their specified position. A spatial held voice can move through `updateVoice({ voiceId, spatialX, spatialY })`; omitted coordinates retain their previous value, and the FIR ramps over 10 ms without clearing history. A stereo voice cannot be converted to spatial by an update.
94
81
 
95
82
  The [integration guide](guide.md#integrate-binaural-in-a-2d-app) contains the JavaScript conversion and explains switch/slider behavior.
96
83
 
84
+ ## Statistics are missing or show `null`
85
+
86
+ Older development packages can report 1.0.0 without statistics methods. Check `typeof synth.getStats`, `typeof synth.setStatsEnabled` and `typeof synth.resetStats`; install the current packages, rebuild and reinstall the app if needed.
87
+
88
+ Basic voice/queue/rejection counters do not require diagnostics. Timing, output peak/RMS and limiter reduction require `setStatsEnabled(true)` and a measured callback/window. `null` means unmeasured or unavailable; keep it distinct from zero. The current iOS backend always reports `null` for underruns, output buffer size and estimated hardware latency. Android backend metrics are best-effort and independent of the diagnostic switch.
89
+
90
+ Read at a modest rate, such as 5 Hz, and stop polling and optional measurements when the diagnostic owner hides or closes. `getStats()` never resets counters; call `resetStats()` deliberately. See the [integration recipe](guide.md#read-engine-statistics).
91
+
92
+ ## Render load changes while no notes are playing
93
+
94
+ `renderLoad` is measured callback elapsed time divided by the time represented by that audio block. The native value is a fraction: `0.012` means 1.2%, and `1.0` means 100%. The interactive example displays percentages.
95
+
96
+ An open stream keeps delivering blocks, even in silence. It consumes commands, processes the output/limiter and measures signal levels when diagnostics are enabled. That work continues with zero active voices. Later sounds can use the running output without reopening it for each event, reducing repeated startup work. Envelopes and fades still handle abrupt signal changes; an open stream alone cannot guarantee a click-free onset.
97
+
98
+ The iOS app-wide session policy (`ambient` or `playback`) is separate from whether the native stream is open. Scheduling, system activity and measurement overhead cause elapsed time to vary between blocks. Expect a small, changing baseline. The two displayed decimals do not guarantee that level of timing accuracy.
99
+
100
+ A block at 100% has used its nominal time budget; repeated readings at or above that level warrant investigation. Low readings describe the observed blocks and do not prove every deadline was met or establish sound quality. Compare matching configurations on the same device. Stopping playback with `stopAll()` leaves the stream open; `shutdown()` closes it and optional measurements become `null`. See the [statistics contract](api.md#getstats).
101
+
97
102
  ## The first sound glitches
98
103
 
99
- Do not start the engine during the first layout. Add the `postlayout` listener
100
- before opening the window, debounce it for about 250 ms, and start after the
101
- screen settles. Cancel the timer if the owner closes first. The complete code
102
- is in the [guide](guide.md#lifecycle).
104
+ Do not start the engine during the first layout. Add the `postlayout` listener before opening the window, debounce it for about 250 ms, and start after the screen settles. Cancel the timer if the owner closes first. The complete code is in the [guide](guide.md#lifecycle).
103
105
 
104
- If startup remains noisy, temporarily remove other launch work and increase the
105
- quiet period. Ads, animations, remote configuration and another audio module
106
- can all compete during the same short interval.
106
+ If startup remains noisy, temporarily remove other launch work and increase the quiet period. Ads, animations, remote configuration and another audio module can all compete during the same short interval.
107
107
 
108
108
  ## The app is silent
109
109
 
110
110
  Check these in order:
111
111
 
112
- 1. `startEngine()` returned `true`.
112
+ 1. `start()` returned `true`.
113
113
  2. The tone, chord or pattern call returned `true`.
114
114
  3. Master and event `volume` are above zero.
115
115
  4. The device media volume is up and the expected route is selected.
116
116
  5. `shutdown()` was not called by another owner.
117
117
  6. The note is within the current frequency range.
118
- 7. The app is not relying on a pattern that another `playPattern()` call
119
- replaced.
120
-
121
- On iOS, the module uses a `Playback` session by default, so the silent switch
122
- should not mute it. With `audioSession: 'ambient'` the silent switch mutes it by
123
- design. Another audio component can change the app-wide session after engine
124
- startup; inspect the order if behavior differs from the simple example.
125
-
126
- ## A pattern stops or skips steps
127
-
128
- Only one pattern is pending. A new `playPattern()` call cancels steps from the
129
- previous scheduler that have not fired. Voices already on the audio thread keep
130
- playing.
118
+ 7. The app retained the positive sequence identifier and checked publication acceptance.
131
119
 
132
- `stopAll()` fades current voices but does not cancel later scheduled steps. Use
133
- `shutdown()` when both active audio and future scheduling must end, or replace
134
- the pattern deliberately before stopping its current voices.
135
-
136
- Make sure every step is an object and has exactly one pitch source:
137
-
138
- ```javascript
139
- steps: [
140
- { note: 'C4' },
141
- { rest: true },
142
- { frequency: 660 }
143
- ]
144
- ```
120
+ On iOS, the module uses a `Playback` session by default, so the silent switch should not mute it. With `audioSession: 'ambient'` the silent switch mutes it by design. Another audio component can change the app-wide session after engine startup; inspect the order if behavior differs from the simple example.
145
121
 
146
- ## `patternend` never arrives
122
+ ## A sequence stops or skips steps
147
123
 
148
- The event fires once per accepted `playPattern`. Check, in order:
124
+ Check the positive sequence ID, available `maxSequences` capacity and accepted updates. New sequences do not replace existing ones. All sequences and direct events share the voice pool; higher-priority voices can cause an entire lower-priority chord to drop. Inspect `priorityDropCount`, `rejectedPublicationCount` and output diagnostics separately. A stopped or completed identifier is retired and cannot be resumed by an update.
149
125
 
150
- 1. The call returned `true`. A rejected pattern produces no event.
151
- 2. The listener is on the module (`synth.addEventListener`), registered before
152
- the pattern started and not removed by a cleanup that already ran.
153
- 3. `shutdown()` was not called first. It discards a pending pattern silently.
154
- 4. The pattern was not replaced. A newer accepted pattern delivers
155
- `completed: false` for the old one instead of a natural end.
126
+ ## `sequenceend` never arrives
156
127
 
157
- The event arrives when the pattern ends, about 1 ms after the sum of its step
158
- lengths, not when you call. A 30 second pattern reports after 30 seconds.
128
+ The event uses `{ sequenceId, reason }`, where reason is `completed` or `stopped`. Looping sequences complete only after an explicit stop. Check that publication returned a positive ID, the listener remains registered and JavaScript is able to receive events. Delivery happens outside audio and does not time the next attack. Shutdown tears down the owner; do not depend on a future completion callback after cleanup.
159
129
 
160
130
  ## A chord is distorted or pumps
161
131
 
162
- Use one `playChord()` call for notes that should begin together. Several
163
- `playTone()` calls have independent source gain and produce a hotter sum.
132
+ Use one `playChord()` call for notes that should begin together. Several `playTone()` calls have independent source gain and produce a hotter sum.
164
133
 
165
134
  If the limiter engages repeatedly:
166
135
 
167
136
  - lower event volume;
168
- - lower `filterQ`, because a resonant low-pass or high-pass boosts its cutoff
169
- by about Q;
137
+ - lower `filterQ`, because a resonant low-pass or high-pass boosts its cutoff by about Q;
170
138
  - use `conservative` instead of `balanced` or `raw`;
171
139
  - use `speakerSafe` on a small speaker;
172
140
  - avoid retriggering a long event before its previous release ends.
173
141
 
174
- A repeating overlap test is expected to change the summed level. Judge tonal
175
- quality with one chord, then use the loop only to test stress behavior.
142
+ A repeating overlap test is expected to change the summed level. Judge tonal quality with one chord, then use the loop only to test stress behavior.
176
143
 
177
144
  ## The phone speaker buzzes but headphones are clean
178
145
 
179
- That usually points to the physical speaker or its protection system. Try
180
- `speakerSafe`, lower the event level, shorten low-frequency energy, or move the
181
- important pitch above roughly 200 Hz. A digital limiter cannot make a tiny
182
- speaker reproduce bass it cannot move cleanly.
146
+ The physical speaker or its protection system is usually the cause. Try `speakerSafe`, lower the event level, shorten low-frequency energy, or move the important pitch above roughly 200 Hz. A digital limiter cannot make a tiny speaker reproduce bass it cannot move cleanly.
183
147
 
184
- Compare several devices before changing the synthesis globally. A resonance on
185
- one handset may not exist on another.
148
+ Compare several devices before changing the synthesis globally. A resonance on one handset may not exist on another.
186
149
 
187
150
  ## Audio changes after connecting headphones
188
151
 
189
- Route recovery is automatic, but the sound crossing the hardware transition
190
- may end early. The operating system can also mute or fade the new route for a
191
- brief device-dependent interval. Wait for the route to settle and play a new
192
- sound; do not restart the app.
152
+ Route recovery is automatic, but the sound crossing the hardware transition may end early. The operating system can also mute or fade the new route for a brief device-dependent interval. Wait for the route to settle and play a new sound; do not restart the app.
193
153
 
194
- If later sounds remain silent, capture the Android or Xcode log around the route
195
- change. Confirm that no screen lifecycle handler called `shutdown()` at the same
196
- time.
154
+ If later sounds remain silent, capture the Android or Xcode log around the route change. Confirm that no screen lifecycle handler called `shutdown()` at the same time.
197
155
 
198
156
  ## Android-specific checks
199
157
 
@@ -212,8 +170,38 @@ time.
212
170
 
213
171
  ## What to include in a bug report
214
172
 
215
- Include the platform, OS version, device model, Titanium SDK version, module
216
- version, mixing profile, `maxVoices`, the smallest accepted call that reproduces
217
- the problem, and the native log around startup and playback. For a sound-quality
218
- report, say whether it reproduces through the built-in speaker, wired
219
- headphones, Bluetooth or all routes.
173
+ Include the platform, OS version, device model, Titanium SDK version, module version, mixing profile, `maxVoices`, the smallest accepted call that reproduces the problem, and the native log around startup and playback. For a sound-quality report, say whether it reproduces through the built-in speaker, wired headphones, Bluetooth or all routes.
174
+
175
+ ## Held notes, sequences or effects methods are missing
176
+
177
+ The official release reports API version 1.0.0. Detect `noteOn`/`noteOff`/`updateVoice`, all four sequence methods and `setMasterProcessing` according to the feature needed. Install matching current Android/iOS packages, rebuild and reinstall the consumer app. A stale development binary may report the same version without the complete release API. See [capability detection](guide.md#detect-required-capabilities).
178
+
179
+ ## A held voice does not release or update
180
+
181
+ Use the original positive `voiceId`, not the pitch or an ID that has already been reused. `noteOn` does not accept `duration` or temporal `*End` fields. Source, filter type, table, quantization and ADSR require a new attack. Compatible `updateVoice` controls include live noise clock, one-pole cutoff, spatial position for a spatial voice, stereo pan for a stereo voice, modulation and explicit effect send, in addition to pitch/volume/filter/vibrato/FM/pulse targets. Changed continuous controls ramp for 10 ms while retaining phase, envelope and spatial history; `noiseRate: 0` means white noise and `lowPassHz: 0` bypasses that filter.
182
+
183
+ Check Boolean returns. A full public queue can reject `noteOff`; retry twice at 16 ms outside render, then shut down/report if still rejected. Cancel those retries on owner teardown. The [held motor example](advanced-examples.md#sustained-game-motor) implements this policy. Touch cancellation, pause and close need cleanup as well as normal key up.
184
+
185
+ An ended or stolen ID accepts updates as a no-op, so acceptance does not prove audible continuity. Held voices share capacity with timed sounds and transport voices. Check replacement counts under dense collision load, leave headroom in the pool and use an app-owned renewal policy if needed. Increasing capacity above 32 or enabling reverb does not reserve a voice.
186
+
187
+ ## A native sequence edit seems delayed or does not resume
188
+
189
+ Boolean update acceptance precedes application. Query `getSequenceState({ sequenceId }).revision` when the state is non-null. Structural edits enter at the next step and swing at the next pair. `setTempo` applies globally at the next audio block. Bank pressure rejects the whole publication; retain accepted UI state and retry later. Updates cannot resume retired IDs; create a new sequence and store its new ID. Steps contain MIDI `notes`, `frequencies` or `rest: true`, with optional interval `duration` and independent note `length`.
190
+
191
+ ## Effects are silent, remain audible when disabled or affect other sounds
192
+
193
+ The stream must run and `setMasterProcessing` must accept the configuration. Effects start disabled. Check `applyTo` categories, each event's `bus` and any explicit `effectSend`, which overrides selection. Delay and LFO sync follow global `setTempo`, initially 120 BPM. Free settings retain hertz or milliseconds.
194
+
195
+ Disabling effects closes input smoothly and lets bounded tails finish, then bypasses exactly. It retains input gain. Panic through `stopAll` stops every sequence, fades voices and invalidates effect histories. Shutdown closes audio and frees resources. Saturation changes timbre separately from the limiter.
196
+
197
+ ## A brief level dip is gone before the meter refreshes
198
+
199
+ Enable diagnostics, reset deliberately, then inspect `preLimiterPeakDb` and `maxLimiterReductionDb`. They retain the native pre-limiter peak and greatest attenuation since reset, including brief interventions between UI polls. `limiterReductionDb` is a window measurement and can return to zero sooner. Older packages may omit the accumulated fields; disabled/unmeasured diagnostics return `null`. See [measurement example](advanced-examples.md#measure-peaks-and-limiter-reduction).
200
+
201
+ If accumulated attenuation remains near zero, investigate phase cancellation between repeated same-pitch oscillators, changing filters or the device speaker/protection path. Compatible released public held-note repetitions preserve predecessor phase; simultaneous unisons, timed calls and transport notes retain their existing phase behavior. Extra effects and resonance can consume headroom even when source gain is fixed. Compare matched levels through headphones and the physical speaker before changing the mix globally.
202
+
203
+ ## A wavetable sounds rough
204
+
205
+ `WAVETABLE` repeats the supplied values using a stepped lookup. A short table can sound grainy or buzzy even when its values describe a sine wave and `bitDepth` is 0. Its harmonic character changes with pitch and filtering; this does not require reverb, an LFO or creative saturation to be enabled.
206
+
207
+ Compare one note with `SINE`, at a comfortable matched level, to distinguish the source's texture from the combined sound of overlapping notes. Read `preLimiterPeakDb` and `maxLimiterReductionDb` with diagnostics enabled to investigate mix headroom. No limiter reduction does not prove that the physical speaker, headphones or output processing are clean. Keep a subjective listening observation separate from a confirmed clipping or buffer-loss diagnosis.