@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.
Files changed (44) hide show
  1. package/README.md +27 -32
  2. package/agents/ti-pro.md +1 -1
  3. package/commands/ti-audit.md +1 -1
  4. package/docs/examples.md +15 -8
  5. package/package.json +1 -1
  6. package/skills/ti-synthengine/SKILL.md +62 -92
  7. package/skills/ti-synthengine/assets/example/README.md +51 -54
  8. package/skills/ti-synthengine/assets/example/app.js +96 -57
  9. package/skills/ti-synthengine/assets/example/lib/sequenceOwner.js +39 -40
  10. package/skills/ti-synthengine/assets/example/lib/soundPreset.js +34 -0
  11. package/skills/ti-synthengine/assets/index.d.ts +226 -0
  12. package/skills/ti-synthengine/references/advanced-examples.md +12 -12
  13. package/skills/ti-synthengine/references/api.md +125 -33
  14. package/skills/ti-synthengine/references/audio-engine.md +24 -59
  15. package/skills/ti-synthengine/references/examples.md +64 -7
  16. package/skills/ti-synthengine/references/guide.md +69 -63
  17. package/skills/ti-synthengine/references/instruments-and-effects.md +34 -27
  18. package/skills/ti-synthengine/references/native-variation.md +92 -51
  19. package/skills/ti-synthengine/references/recipes-interaction.md +26 -19
  20. package/skills/ti-synthengine/references/recipes.md +19 -15
  21. package/skills/ti-synthengine/references/recommendations.md +14 -14
  22. package/skills/ti-synthengine/references/sound-api.md +197 -0
  23. package/skills/ti-synthengine/references/sound-design.md +11 -11
  24. package/skills/ti-synthengine/references/source-notes.md +62 -147
  25. package/skills/ti-synthengine/references/troubleshooting.md +22 -24
  26. package/skills/ti-synthengine/references/upgrade-2.0.0.md +40 -0
  27. package/skills/ti-synthengine/references/android-sim80-correction-evidence.zip +0 -0
  28. package/skills/ti-synthengine/references/android-sim80-correction.json +0 -162
  29. package/skills/ti-synthengine/references/audio-pipeline-validation.md +0 -19
  30. package/skills/ti-synthengine/references/bypass-physical-recheck-evidence.zip +0 -0
  31. package/skills/ti-synthengine/references/frontier-android-evidence.zip +0 -0
  32. package/skills/ti-synthengine/references/frontier-ipad-evidence.zip +0 -0
  33. package/skills/ti-synthengine/references/frontier-physical-validation.json +0 -1918
  34. package/skills/ti-synthengine/references/native-variation-proposal.md +0 -182
  35. package/skills/ti-synthengine/references/native-variation-validation.md +0 -63
  36. package/skills/ti-synthengine/references/performance-review-evidence.zip +0 -0
  37. package/skills/ti-synthengine/references/performance-review.json +0 -1146
  38. package/skills/ti-synthengine/references/physical-validation.json +0 -1457
  39. package/skills/ti-synthengine/references/source-snapshot.json +0 -463
  40. package/skills/ti-synthengine/references/stats-performance.json +0 -2992
  41. package/skills/ti-synthengine/references/stats-performance.md +0 -82
  42. package/skills/ti-synthengine/references/studio-validation.json +0 -6202
  43. package/skills/ti-synthengine/references/unified-bypass-performance.json +0 -22425
  44. package/skills/ti-synthengine/references/unified-validation.json +0 -314
@@ -1,15 +1,8 @@
1
- // One application owner, with latest-request coalescing across native retirement.
2
- // A stop is accepted before its slot becomes reusable. Only sequenceend permits
3
- // the next complete publication; JavaScript never schedules individual notes.
1
+ // Wait for native retirement before publishing the latest requested pattern.
2
+ var SoundPreset = require('./soundPreset')
4
3
  module.exports = function createSequenceOwner(synth, options) {
5
4
  options = options || {}
6
- var current = 0, pending = null, stopping = false, listening = false
7
- function listen() {
8
- if (!listening) {
9
- synth.addEventListener('sequenceend', ended)
10
- listening = true
11
- }
12
- }
5
+ var current = null, pending = null, stopping = false, recipe = null, listener = null
13
6
  function rejected(method, payload) {
14
7
  if (options.rejected) options.rejected(method, payload)
15
8
  return false
@@ -18,32 +11,40 @@ module.exports = function createSequenceOwner(synth, options) {
18
11
  if (!pending) return true
19
12
  var payload = pending
20
13
  pending = null
21
- var id = synth.playSequence(payload)
22
- if (!Number.isInteger(id) || id <= 0) return rejected('playSequence', payload)
23
- current = id
24
- if (options.published) options.published(id, payload)
14
+ var control = synth.createSound(SoundPreset.fromRecipe('pattern', payload)).play()
15
+ if (!control) return rejected('playSequence', payload)
16
+ current = control
17
+ recipe = payload
18
+ listener = function(event) {
19
+ if (current !== control) return
20
+ control.removeEventListener('end', listener)
21
+ current = null
22
+ listener = null
23
+ stopping = false
24
+ if (pending) publish()
25
+ if (options.ended) options.ended(event)
26
+ }
27
+ control.addEventListener('end', listener)
28
+ if (options.published) options.published(control, payload)
25
29
  return true
26
30
  }
27
- function ended(event) {
28
- if (event.sequenceId !== current) return
29
- current = 0
30
- stopping = false
31
- if (pending) publish()
32
- if (options.ended) options.ended(event)
33
- }
34
31
  function requestStop() {
35
32
  if (!current || stopping) return true
36
33
  stopping = true
37
- if (synth.stopSequence({ sequenceId: current })) return true
38
- // A naturally retired ID can already have its completion queued for JS.
39
- // Its slot still needs event draining before a replacement publication.
40
- if (synth.getSequenceState({ sequenceId: current }) === null) return true
34
+ if (current.stop()) return true
35
+ // An ended pattern can have its completion queued for JavaScript.
36
+ if (current.getState() === null) return true
41
37
  stopping = false
42
- return rejected('stopSequence', { sequenceId: current })
38
+ return rejected('stopSequence', {})
39
+ }
40
+ function merged(previous, changes) {
41
+ var voice = changes.voice ? Object.assign({}, previous.voice || {}, changes.voice) : previous.voice
42
+ var next = Object.assign({}, previous, changes)
43
+ if (voice) next.voice = voice
44
+ return next
43
45
  }
44
46
  return {
45
47
  submit: function(payload) {
46
- listen()
47
48
  pending = payload
48
49
  if (!current) return publish()
49
50
  if (!requestStop()) {
@@ -54,28 +55,26 @@ module.exports = function createSequenceOwner(synth, options) {
54
55
  },
55
56
  update: function(changes) {
56
57
  if (pending) {
57
- if (changes.steps !== undefined) {
58
- pending = changes
59
- return true
60
- }
61
- var voice = changes.voice ? Object.assign({}, pending.voice || {}, changes.voice) : pending.voice
62
- pending = Object.assign({}, pending, changes)
63
- if (voice) pending.voice = voice
58
+ pending = changes.steps !== undefined ? changes : merged(pending, changes)
64
59
  return true
65
60
  }
66
61
  if (!current || stopping) return false
67
- return synth.updateSequence(Object.assign({ sequenceId: current }, changes))
62
+ var next = merged(recipe, changes)
63
+ var preset = SoundPreset.fromRecipe('pattern', next)
64
+ if (!current.update(Object.assign({}, preset.sound, preset.playback))) return false
65
+ recipe = next
66
+ return true
68
67
  },
69
68
  stop: function() { pending = null; return requestStop() },
70
69
  reset: function() {
71
70
  pending = null
72
- current = 0
71
+ if (current && listener) current.removeEventListener('end', listener)
72
+ current = null
73
+ listener = null
74
+ recipe = null
73
75
  stopping = false
74
- if (listening) {
75
- synth.removeEventListener('sequenceend', ended)
76
- listening = false
77
- }
78
76
  },
77
+ getState: function() { return current ? current.getState() : null },
79
78
  id: function() { return current },
80
79
  pending: function() { return pending !== null },
81
80
  stopping: function() { return stopping }
@@ -0,0 +1,34 @@
1
+ // Convert an editable recipe to a Sound definition; this module never plays audio.
2
+ exports.fromRecipe = function(type, recipe) {
3
+ var source = JSON.parse(JSON.stringify(recipe || {}))
4
+ var sound = type === 'pattern' ? source.voice || {} : {}
5
+ var playback = { type: type }
6
+ if (type === 'pattern') {
7
+ ;['timeUnit', 'gate', 'loop', 'swing', 'mode', 'tuning'].forEach(function(key) {
8
+ if (source[key] !== undefined) playback[key] = source[key]
9
+ })
10
+ if (sound.frequencyEnd !== undefined) {
11
+ playback.frequencyEnd = sound.frequencyEnd
12
+ delete sound.frequencyEnd
13
+ }
14
+ if (source.detune !== undefined) sound.detune = source.detune
15
+ if (source.stepDuration !== undefined) playback.interval = source.stepDuration
16
+ playback.steps = (source.steps || []).map(function(step) {
17
+ var result = {}
18
+ ;['notes', 'frequencies', 'rest', 'length', 'gate'].forEach(function(key) {
19
+ if (step[key] !== undefined) result[key] = step[key]
20
+ })
21
+ if (step.duration !== undefined) result.interval = step.duration
22
+ if (step.overrides !== undefined) result.sound = step.overrides
23
+ return result
24
+ })
25
+ } else {
26
+ Object.keys(source).forEach(function(key) {
27
+ if (key === 'note') playback.notes = [source[key]]
28
+ else if (key === 'frequency') playback.frequencies = [source[key]]
29
+ else if (['notes', 'frequencies', 'frequencyEnd', 'duration'].indexOf(key) >= 0) playback[key] = source[key]
30
+ else sound[key] = source[key]
31
+ })
32
+ }
33
+ return { sound: sound, playback: playback }
34
+ }
@@ -0,0 +1,226 @@
1
+ /** TiSynthEngine 2.0.0 candidate. One module version for the entire public interface. */
2
+ declare namespace synth {
3
+ type Bus = 'music' | 'effects' | 'ui' | 'ambience';
4
+ type FilterType = 'none' | 'lowpass' | 'highpass' | 'bandpass';
5
+ type Range = [number, number];
6
+ interface Variation {
7
+ amount?: number;
8
+ seed?: number;
9
+ ranges?: Partial<Record<'volume' | 'filterHz' | 'filterQ' | 'fmDepth' |
10
+ 'noiseRate' | 'lowPassHz' | 'pulseWidth' | 'pitchCents', Range>>;
11
+ }
12
+ interface VoiceOptions {
13
+ attack?: number; decay?: number; sustain?: number; release?: number;
14
+ volume?: number; waveType?: number; pan?: number;
15
+ lfoFreq?: number; lfoDepth?: number; noiseRate?: number; lowPassHz?: number;
16
+ pulseWidth?: number; waveTable?: number[]; bitDepth?: number;
17
+ filterType?: FilterType; filterHz?: number; filterQ?: number;
18
+ fmRatio?: number; fmDepth?: number; spatialX?: number; spatialY?: number;
19
+ bus?: Bus; effectSend?: number; priority?: number; variation?: Variation;
20
+ }
21
+ type Pitch = { note?: string; frequency?: never } | { frequency?: number; note?: never };
22
+ interface FiniteOptions extends VoiceOptions {
23
+ duration?: number; panEnd?: number; frequencyEnd?: number;
24
+ noiseRateEnd?: number; pulseWidthEnd?: number; filterHzEnd?: number;
25
+ fmDepthEnd?: number; detune?: number;
26
+ }
27
+ type ToneOptions = FiniteOptions & Pitch;
28
+ type RepeatingToneOptions = ToneOptions & { intervalMs: number };
29
+ /** Partial changes merge with the latest accepted recipe; never retriggers immediately. */
30
+ type ToneUpdate = Partial<FiniteOptions> & Pitch & { toneId: number; intervalMs?: number };
31
+ interface Modulation {
32
+ target: 'filterHz' | 'pulseWidth' | 'fmDepth';
33
+ wave?: 'sine' | 'triangle'; rate?: number; sync?: string; depth?: number;
34
+ }
35
+ type NoteOptions = VoiceOptions & Pitch & { voiceId: number; detune?: number; modulations?: Modulation[] };
36
+ type NoteUpdate = Pick<VoiceOptions, 'volume' | 'pan' | 'lfoFreq' | 'lfoDepth' |
37
+ 'noiseRate' | 'lowPassHz' | 'pulseWidth' | 'filterHz' | 'filterQ' |
38
+ 'fmRatio' | 'fmDepth' | 'spatialX' | 'spatialY' | 'effectSend'> & Pitch &
39
+ { voiceId: number; modulations?: Modulation[] };
40
+ type ChordOptions = VoiceOptions & { duration?: number; detune?: number;
41
+ detunes?: number[]; pans?: number[]; panSpread?: number } &
42
+ ({ notes: string[]; frequencies?: never } | { frequencies: number[]; notes?: never });
43
+ interface StartOptions {
44
+ maxVoices?: number; maxSequences?: number;
45
+ mixingProfile?: 'conservative' | 'raw' | 'balanced' | 'speakerSafe';
46
+ audioSession?: 'playback' | 'ambient';
47
+ }
48
+ interface Defaults {
49
+ version: string;
50
+ capabilities: { variation: true; toneRepetition: true; [key: string]: boolean };
51
+ variationSchemaVersion: 1;
52
+ limits: Record<string, { min: number; max: number }>;
53
+ defaults: Record<string, unknown>;
54
+ waveTypes: Record<'SINE' | 'SQUARE' | 'SAWTOOTH' | 'TRIANGLE' | 'NOISE' | 'WAVETABLE', number>;
55
+ mixingProfiles: string[]; audioSessions: string[]; buses: Bus[]; filterTypes: FilterType[];
56
+ }
57
+ interface SequenceVoice extends Omit<FiniteOptions, 'duration' | 'detune'> { modulations?: Modulation[] }
58
+ type SequenceStep = { duration?: number; length?: number; gate?: number;
59
+ overrides?: SequenceVoice; bus?: Bus; effectSend?: number; priority?: number } &
60
+ ({ notes: number[]; frequencies?: never; rest?: never } |
61
+ { frequencies: number[]; notes?: never; rest?: never } |
62
+ { rest: true; notes?: never; frequencies?: never });
63
+ interface SequenceOptions {
64
+ timeUnit?: 'beats' | 'ms'; stepDuration?: number; gate?: number; loop?: boolean;
65
+ swing?: number; mode?: 'normal' | 'up' | 'down' | 'updown'; tuning?: number;
66
+ detune?: number; voice?: SequenceVoice; steps: SequenceStep[];
67
+ bus?: Bus; effectSend?: number; priority?: number;
68
+ }
69
+ interface SequenceState {
70
+ sequenceId: number; playing: boolean; step: number; beat: number;
71
+ position: number; bpm: number; revision: number;
72
+ }
73
+ /** Numbers are MIDI notes 12..119; strings are native note names. */
74
+ type Notes = string[] | number[];
75
+ type SoundType = 'tone' | 'chord' | 'repeat' | 'pattern' | 'held';
76
+ type ModernPitch = { notes?: Notes; frequencies?: never } | { frequencies?: number[]; notes?: never };
77
+ /** Shared allowlist; each interpretation also validates source-specific compatibility. */
78
+ interface SoundProperties extends VoiceOptions {
79
+ detune?: number; panEnd?: number; noiseRateEnd?: number; pulseWidthEnd?: number;
80
+ filterHzEnd?: number; fmDepthEnd?: number; detunes?: number[]; pans?: number[];
81
+ panSpread?: number; modulations?: Modulation[];
82
+ }
83
+ type TonePlayback = ModernPitch & { type?: 'tone'; duration?: number; frequencyEnd?: number };
84
+ type ChordPlayback = ({ notes: Notes; frequencies?: never } | { frequencies: number[]; notes?: never }) & { type: 'chord'; duration?: number };
85
+ type RepeatPlayback = ModernPitch & { type: 'repeat'; duration?: number; frequencyEnd?: number; interval: number };
86
+ type HeldPlayback = ModernPitch & { type: 'held' };
87
+ type PatternStep = { interval?: number; length?: number; gate?: number;
88
+ sound?: SoundProperties & { frequencyEnd?: number } } &
89
+ ({ notes: Notes; frequencies?: never; rest?: never } |
90
+ { frequencies: number[]; notes?: never; rest?: never } |
91
+ { rest: true; notes?: never; frequencies?: never });
92
+ interface PatternPlayback {
93
+ type?: 'pattern'; timeUnit?: 'beats' | 'ms'; interval?: number; gate?: number;
94
+ loop?: boolean; swing?: number; mode?: 'normal' | 'up' | 'down' | 'updown';
95
+ tuning?: number; frequencyEnd?: number; steps: PatternStep[];
96
+ }
97
+ type SoundPlayback = TonePlayback | ChordPlayback | RepeatPlayback | PatternPlayback | HeldPlayback;
98
+ interface SoundPreset { name?: string; sound?: SoundProperties; playback?: SoundPlayback }
99
+ /** Objects merge recursively; arrays replace. Null removes a leaf if the resulting preset is valid. */
100
+ type PresetPatch<T> = T extends unknown[] ? T | null : T extends object ?
101
+ { [K in keyof T]?: PresetPatch<T[K]> } : T | null;
102
+ interface SoundChanges {
103
+ name?: string;
104
+ sound?: PresetPatch<SoundProperties>;
105
+ playback?: PresetPatch<SoundPlayback>;
106
+ }
107
+ /** Execution overrides are flat, unlike the stored sound/playback definition. */
108
+ type RepeatChanges = PresetPatch<SoundProperties> & ModernPitch & {
109
+ type?: 'repeat'; duration?: number | null; frequencyEnd?: number | null; interval?: number;
110
+ };
111
+ type PatternChanges = PresetPatch<SoundProperties> & PresetPatch<Partial<PatternPlayback>>;
112
+ type SoundOverrides = SoundProperties & (TonePlayback | Partial<ChordPlayback> | HeldPlayback |
113
+ (ModernPitch & { type?: 'repeat'; duration?: number; frequencyEnd?: number; interval?: number }) |
114
+ Partial<PatternPlayback>);
115
+ type NoteChanges = Pick<VoiceOptions, 'volume' | 'pan' | 'lfoFreq' | 'lfoDepth' |
116
+ 'noiseRate' | 'lowPassHz' | 'pulseWidth' | 'filterHz' | 'filterQ' | 'fmRatio' |
117
+ 'fmDepth' | 'spatialX' | 'spatialY' | 'effectSend'> & ModernPitch & { modulations?: Modulation[] };
118
+ interface Note {
119
+ /** Ramps compatible live fields without retriggering. Attack-only fields are rejected. */
120
+ update(changes: NoteChanges): boolean;
121
+ /** Begins this note's release; false after release, shutdown or invalidation. */
122
+ noteOff(): boolean;
123
+ }
124
+ interface RepeatingPlaybackControl {
125
+ /** Applies at the next scheduled attack without moving its existing deadline. */
126
+ update(changes: RepeatChanges): boolean;
127
+ /** Cancels future attacks; already sounding finite attacks finish. */
128
+ stop(): boolean;
129
+ }
130
+ type PatternState = Omit<SequenceState, 'sequenceId'>;
131
+ interface PatternEndEvent { reason: 'completed' | 'stopped' }
132
+ interface PatternPlaybackControl {
133
+ update(changes: PatternChanges): boolean;
134
+ stop(): boolean;
135
+ getState(): PatternState | null;
136
+ /** Transport retirement, not a promise of audible silence. No native ID is exposed. */
137
+ addEventListener(name: 'end', listener: (event: PatternEndEvent) => void): void;
138
+ removeEventListener(name: 'end', listener: (event: PatternEndEvent) => void): void;
139
+ }
140
+ type PlaybackResult = boolean | Note | RepeatingPlaybackControl | PatternPlaybackControl;
141
+ interface Sound {
142
+ getPreset(): SoundPreset;
143
+ /** Validates before replacing the stored definition; affects future executions only. */
144
+ set(changes: SoundChanges): void;
145
+ play(changes: SoundOverrides & { type: 'held' }): Note | false;
146
+ play(changes: SoundOverrides & { type: 'pattern' }): PatternPlaybackControl | false;
147
+ play(changes: SoundOverrides & { type: 'repeat' }): RepeatingPlaybackControl | false;
148
+ play(changes: SoundOverrides & { type: 'tone' | 'chord' }): boolean;
149
+ /** The stored type can change through set(), so an omitted type has a mixed return. */
150
+ play(changes?: SoundOverrides): PlaybackResult;
151
+ noteOn(changes?: SoundProperties & ModernPitch): Note | false;
152
+ }
153
+ interface Contract extends Defaults {
154
+ capabilities: Defaults['capabilities'] & { soundObjects: true };
155
+ interpretations: SoundType[];
156
+ units: { envelope: 'ms'; duration: 'msIncludingRelease'; repetitionInterval: 'ms'; pattern: ('beats' | 'ms')[] };
157
+ soundProperties: (keyof SoundProperties)[];
158
+ playbackProperties: string[];
159
+ }
160
+ type Sync = 'off' | 'quarter' | 'eighth' | 'sixteenth' | 'quarterTriplet' | 'eighthTriplet' | 'sixteenthTriplet';
161
+ interface ProcessingOptions {
162
+ inputGain?: number; applyTo?: Bus[];
163
+ chorus?: { enabled?: boolean; rate?: number; depth?: number; mix?: number };
164
+ /** time is milliseconds; timeMs is a deprecated exclusive input spelling. */
165
+ delay?: { enabled?: boolean; sync?: Sync; feedback?: number; mix?: number } &
166
+ ({ time?: number; timeMs?: never } | { time?: never; timeMs?: number });
167
+ /** decay is milliseconds (200..8000), unlike setMasterProcessing's seconds. */
168
+ reverb?: { enabled?: boolean; decay?: number; damping?: number; mix?: number };
169
+ saturation?: { enabled?: boolean; drive?: number; mix?: number };
170
+ }
171
+ function createSound(preset: SoundPreset): Sound;
172
+ function getContract(): Contract;
173
+ /** Strict configuration errors throw; operational rejection returns false. */
174
+ function setProcessing(options: ProcessingOptions): boolean;
175
+ /** Installed module version, native defaults, limits and capabilities. */
176
+ function getDefaults(): Defaults;
177
+ function start(options?: StartOptions): boolean;
178
+ /** One finite attack. intervalMs is rejected; use repeatTone for repetition. */
179
+ /** @deprecated Use createSound(...).play(). The existing signature and behavior remain supported. */
180
+ function playTone(options: ToneOptions & { intervalMs?: never }): boolean;
181
+ /** Integer 1-60000 ms: positive module-owned ID, or 0 on rejection. */
182
+ /** @deprecated Use a Sound with playback.type repeat and its playback control. The existing signature and behavior remain supported. */
183
+ function repeatTone(options: RepeatingToneOptions): number;
184
+ /** @deprecated Use the repetition control update(). The existing signature and behavior remain supported. */
185
+ function updateTone(options: ToneUpdate): boolean;
186
+ /** Cancels future attacks at the next block; admitted attacks finish. */
187
+ /** @deprecated Use the repetition control stop(). The existing signature and behavior remain supported. */
188
+ function stopTone(options: { toneId: number }): boolean;
189
+ /** @deprecated Use a Sound with playback.type chord. The existing signature and behavior remain supported. */
190
+ function playChord(options: ChordOptions): boolean;
191
+ /** @deprecated Use Sound.noteOn() or a Sound with playback.type held. The existing signature and behavior remain supported. */
192
+ function noteOn(options: NoteOptions): boolean;
193
+ /** @deprecated Use Note.update(). The existing signature and behavior remain supported. */
194
+ function updateNote(options: NoteUpdate): boolean;
195
+ /** @deprecated Use updateNote; identical behavior and voiceId contract. */
196
+ function updateVoice(options: NoteUpdate): boolean;
197
+ /** @deprecated Use Note.noteOff(). The existing signature and behavior remain supported. */
198
+ function noteOff(options: { voiceId: number }): boolean;
199
+ /** @deprecated Use a Sound with playback.type pattern. The existing signature and behavior remain supported. */
200
+ function playSequence(options: SequenceOptions): number;
201
+ /** @deprecated Use the pattern control update(). The existing signature and behavior remain supported. */
202
+ function updateSequence(options: Partial<Omit<SequenceOptions, 'timeUnit'>> & { sequenceId: number }): boolean;
203
+ /** @deprecated Use the pattern control stop(). The existing signature and behavior remain supported. */
204
+ function stopSequence(options: { sequenceId: number }): boolean;
205
+ /** @deprecated Use the pattern control getState(). The existing signature and behavior remain supported. */
206
+ function getSequenceState(options: { sequenceId: number }): SequenceState | null;
207
+ function setTempo(bpm: number): boolean;
208
+ /** @deprecated Use setTempo(bpm); the dictionary signature remains supported. */
209
+ function setTempo(options: { bpm: number }): boolean;
210
+ function setVolume(volume: number): boolean;
211
+ /** @deprecated Use setVolume(volume); the dictionary signature remains supported. */
212
+ function setVolume(options: { volume: number }): boolean;
213
+ /** @deprecated Use setProcessing(); its reverb decay unit is milliseconds. The existing signature and behavior remain supported. */
214
+ function setMasterProcessing(options: Record<string, unknown>): boolean;
215
+ function enableStats(): boolean;
216
+ function disableStats(): boolean;
217
+ /** @deprecated Use enableStats or disableStats; identical diagnostic behavior. */
218
+ function setStatsEnabled(enabled: boolean): boolean;
219
+ function getStats(): Record<string, number | boolean | string | null>;
220
+ function resetStats(): void;
221
+ function stopAll(): void;
222
+ function shutdown(): void;
223
+ function addEventListener(name: 'sequenceend', listener: (event: { sequenceId: number; reason: 'completed' | 'stopped' }) => void): void;
224
+ function removeEventListener(name: 'sequenceend', listener: (event: { sequenceId: number; reason: 'completed' | 'stopped' }) => void): void;
225
+ }
226
+ export = synth;
@@ -1,11 +1,11 @@
1
- > Source snapshot: official TiSynthEngine documentation at commit `b07c97c762be5905f132cecf33e9d60ea0c21316` (2026-11-02). Published 1.0.2; local 1.1.0 candidates; public API 1.0.0. Upstream `documentation/examples.md` SHA-256: `637806516d2804c43427d187a37786cfcf2f0d28758762f01a570ba15194bae3`.
1
+ > Source snapshot: official TiSynthEngine documentation at commit `9d74aa45f84d3f2822d4aab76874efe37d81257f` (2026-11-03). Published module 2.0.0. Upstream `documentation/examples.md` SHA-256: `ee8aed566a63062ae63ae78f0b96fa8d73c70ab2f50aed81081c26acc24718af`.
2
2
 
3
3
  ## Sustained game motor
4
4
 
5
- Assume one running engine owned by this service. The positive voice ID belongs to the app; do not reuse it during the session or share its counter with an independent audio owner. There is no `duration` or `*End` target on `noteOn`.
5
+ This example assumes the service owns one running engine. The positive voice ID belongs to the app; do not reuse it during the session or share its counter with an independent audio owner. There is no `duration` or `*End` target on `noteOn`.
6
6
 
7
7
  ```javascript
8
- if (!['noteOn', 'noteOff', 'updateVoice'].every(function (name) {
8
+ if (!['noteOn', 'noteOff', 'updateNote'].every(function (name) {
9
9
  return typeof synth[name] === 'function'
10
10
  })) throw new Error('Held-voice APIs are required')
11
11
 
@@ -25,7 +25,7 @@ function startMotor () {
25
25
 
26
26
  function changeMotor (boosted) {
27
27
  if (motorId === null) return false
28
- return synth.updateVoice({ voiceId: motorId,
28
+ return synth.updateNote({ voiceId: motorId,
29
29
  filterHz: boosted ? 320 : 220, volume: boosted ? 0.18 : 0.15 })
30
30
  }
31
31
 
@@ -92,7 +92,7 @@ The UI timer presents state; native audio schedules every attack/release. For fi
92
92
 
93
93
  ## Chorus, delay, reverb and creative saturation
94
94
 
95
- This configures the selected share of a running engine; `applyTo` defaults to all categories. Check method presence and Boolean acceptance; partial section updates merge with the last accepted settings. Effects start disabled, input gain starts at 1, and no LFOs are added to voices implicitly.
95
+ The example below configures the selected share of a running engine; `applyTo` defaults to all categories. Check method presence and Boolean acceptance; partial section updates merge with the last accepted settings. Effects start disabled, input gain starts at 1, and no LFOs are added to voices implicitly.
96
96
 
97
97
  ```javascript
98
98
  if (typeof synth.setMasterProcessing !== 'function') {
@@ -128,7 +128,7 @@ Call `setCreativeDrive(true)` only for a deliberate timbre change and check acce
128
128
  This square voice modulates cutoff and PWM independently. The original `lfoFreq`/`lfoDepth` pitch vibrato remains a separate control. All LFOs run natively; edits preserve their phases and ramp contributions over 10 ms.
129
129
 
130
130
  ```javascript
131
- if (typeof synth.noteOn !== 'function' || typeof synth.updateVoice !== 'function') {
131
+ if (typeof synth.noteOn !== 'function' || typeof synth.updateNote !== 'function') {
132
132
  throw new Error('Held-voice APIs are required')
133
133
  }
134
134
  var modulatedId = 100001 // Reserve an unused ID from the owner's counter in an app.
@@ -141,23 +141,23 @@ if (!synth.noteOn({ voiceId: modulatedId, note: 'A3', waveType: WAVE.SQUARE,
141
141
  ] })) throw new Error('Modulated voice rejected')
142
142
 
143
143
  function disableVoiceLfos () {
144
- return synth.updateVoice({ voiceId: modulatedId, modulations: [] })
144
+ return synth.updateNote({ voiceId: modulatedId, modulations: [] })
145
145
  }
146
146
  // Call disableVoiceLfos on the UI action and handle false.
147
147
  // Later release this ID with the bounded release policy above, or shut down its owner.
148
148
  ```
149
149
 
150
- Use `target: 'fmDepth'` only with `WAVE.SINE`; a filter target requires an active filter and PWM requires `WAVE.SQUARE`. Free rates are 0 to 20 Hz; synced subdivisions follow native transport BPM. Depth is normalized, with cutoff/PWM/FM contributions clamped to safe parameter ranges. `modulations: []` disables both slots; omitting the field on update preserves them. Copy the same initial `modulations` array into a sequence's `voice` or a step's `overrides` to modulate transport notes. Timed tones and chords do not accept the new array; native sequences accept it in `voice` or step `overrides`.
150
+ Use `target: 'fmDepth'` only with `WAVE.SINE`; a filter target requires an active filter and PWM requires `WAVE.SQUARE`. Free rates are 0 to 20 Hz; synced subdivisions follow native transport BPM. Depth is normalized, with cutoff/PWM/FM contributions clamped to safe parameter ranges. `modulations: []` disables both slots; omitting the field on update preserves them. Copy the same initial `modulations` array into a sequence's `voice` or a step's `overrides` to modulate transport notes. Timed tones and chords do not accept this array; native sequences accept it in `voice` or step `overrides`.
151
151
 
152
152
  ## Measure peaks and limiter reduction
153
153
 
154
154
  Enable diagnostics only while measuring and keep unavailable readings distinct from zero. A brief overload can disappear from the window meter while remaining in the accumulated maximum.
155
155
 
156
156
  ```javascript
157
- if (!['setStatsEnabled', 'getStats', 'resetStats'].every(function (name) {
157
+ if (!['enableStats', 'disableStats', 'getStats', 'resetStats'].every(function (name) {
158
158
  return typeof synth[name] === 'function'
159
159
  })) throw new Error('Statistics APIs are required')
160
- if (!synth.setStatsEnabled(true)) throw new Error('Diagnostics rejected')
160
+ if (!synth.enableStats()) throw new Error('Diagnostics rejected')
161
161
  synth.resetStats()
162
162
  var mixTimer = setInterval(function () {
163
163
  var stats = synth.getStats()
@@ -167,7 +167,7 @@ var mixTimer = setInterval(function () {
167
167
 
168
168
  function closeMixMeter () {
169
169
  clearInterval(mixTimer)
170
- if (!synth.setStatsEnabled(false)) Ti.API.warn('Diagnostics disable rejected')
170
+ if (!synth.disableStats()) Ti.API.warn('Diagnostics disable rejected')
171
171
  }
172
172
  ```
173
173
 
@@ -175,7 +175,7 @@ Call `closeMixMeter` when its owner hides or closes. Display unavailable or unme
175
175
 
176
176
  ## Bounded variation for repeated noise impacts
177
177
 
178
- The local 1.1.0 packages choose values once per admitted attack. This example keeps the noise source and envelope fixed, varies the initial noise/filter settings, and lets the authored sweep endpoints finish unchanged. Call it through the application's existing effect cadence after normal engine startup.
178
+ The native engine chooses values once per admitted attack. This example keeps the noise source and envelope fixed, varies the initial noise/filter settings, and lets the authored sweep endpoints finish unchanged. Call it for actual gameplay events after normal engine startup. For periodic repetition, pass the finite recipe to `repeatTone` with `intervalMs` and retain its positive tone ID; use `stopTone` on cancellation.
179
179
 
180
180
  ```javascript
181
181
  var synth = require('ti.synthengine')