@maccesar/titools 5.2.5 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +1 -1
- package/README.md +58 -97
- package/agents/ti-pro.md +4 -2
- package/commands/ti-audit.md +7 -5
- package/docs/examples.md +24 -13
- package/docs/knowledge-index.md +2 -1
- package/lib/config.js +1 -0
- package/package.json +1 -1
- package/skills/alloy-guides/SKILL.md +18 -179
- package/skills/alloy-guides/references/CLI_TASKS.md +17 -216
- package/skills/alloy-guides/references/CONCEPTS.md +27 -162
- package/skills/alloy-guides/references/CONTROLLERS.md +38 -236
- package/skills/alloy-guides/references/MODELS.md +47 -723
- package/skills/alloy-guides/references/MODELS_ADVANCED.md +21 -482
- package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +12 -222
- package/skills/alloy-guides/references/VIEWS_STYLES.md +39 -358
- package/skills/alloy-guides/references/VIEWS_XML.md +36 -552
- package/skills/alloy-guides/references/WIDGETS.md +49 -127
- package/skills/alloy-howtos/SKILL.md +14 -169
- package/skills/alloy-howtos/references/best_practices.md +9 -113
- package/skills/alloy-howtos/references/cli_reference.md +18 -223
- package/skills/alloy-howtos/references/config_files.md +50 -133
- package/skills/alloy-howtos/references/debugging_troubleshooting.md +19 -63
- package/skills/alloy-howtos/references/samples.md +21 -138
- package/skills/ti-api/SKILL.md +10 -2
- package/skills/ti-api/references/api-android.md +36 -2
- package/skills/ti-api/references/api-app-platform.md +39 -3
- package/skills/ti-api/references/api-core.md +50 -18
- package/skills/ti-api/references/api-data-network.md +49 -35
- package/skills/ti-api/references/api-media.md +45 -27
- package/skills/ti-api/references/api-services.md +39 -9
- package/skills/ti-api/references/api-ui-android.md +33 -13
- package/skills/ti-api/references/api-ui-extras.md +41 -15
- package/skills/ti-api/references/api-ui-ios-animator.md +42 -26
- package/skills/ti-api/references/api-ui-ios.md +74 -2
- package/skills/ti-api/references/api-ui-lists.md +32 -16
- package/skills/ti-api/references/api-ui-text-input.md +34 -17
- package/skills/ti-api/references/api-ui-views.md +27 -1
- package/skills/ti-api/references/api-ui-windows-navigation.md +32 -18
- package/skills/ti-api/references/api-xml-global.md +66 -16
- package/skills/ti-create-release/SKILL.md +98 -0
- package/skills/ti-create-release/references/module-discovery.md +69 -0
- package/skills/ti-expert/references/adaptive-layouts.md +1 -1
- package/skills/ti-guides/SKILL.md +37 -76
- package/skills/ti-guides/references/advanced-data-and-images.md +122 -126
- package/skills/ti-guides/references/android-manifest.md +24 -83
- package/skills/ti-guides/references/app-distribution.md +31 -377
- package/skills/ti-guides/references/application-frameworks.md +127 -335
- package/skills/ti-guides/references/cli-reference.md +184 -633
- package/skills/ti-guides/references/commonjs-advanced.md +81 -231
- package/skills/ti-guides/references/compatibility-matrix.md +36 -75
- package/skills/ti-guides/references/hello-world.md +95 -70
- package/skills/ti-guides/references/hyperloop-native-access.md +52 -448
- package/skills/ti-guides/references/resources.md +174 -142
- package/skills/ti-guides/references/sdk-release-notes.md +28 -71
- package/skills/ti-guides/references/tiapp-config.md +222 -598
- package/skills/ti-howtos/SKILL.md +23 -123
- package/skills/ti-howtos/references/cross-platform-development.md +119 -324
- package/skills/ti-howtos/references/debugging-profiling.md +77 -445
- package/skills/ti-howtos/references/extending-titanium.md +199 -673
- package/skills/ti-howtos/references/local-data-sources.md +87 -300
- package/skills/ti-howtos/references/location-and-maps.md +86 -213
- package/skills/ti-howtos/references/media-apis.md +103 -223
- package/skills/ti-howtos/references/notification-services.md +86 -506
- package/skills/ti-howtos/references/remote-data-sources.md +97 -316
- package/skills/ti-howtos/references/using-modules.md +77 -133
- package/skills/ti-synthengine/SKILL.md +62 -111
- package/skills/ti-synthengine/assets/example/README.md +50 -59
- package/skills/ti-synthengine/assets/example/app.js +67 -65
- package/skills/ti-synthengine/assets/example/lib/sequenceOwner.js +39 -40
- package/skills/ti-synthengine/assets/example/lib/soundPreset.js +34 -0
- package/skills/ti-synthengine/assets/index.d.ts +122 -2
- package/skills/ti-synthengine/references/advanced-examples.md +4 -4
- package/skills/ti-synthengine/references/api.md +40 -18
- package/skills/ti-synthengine/references/audio-engine.md +15 -57
- package/skills/ti-synthengine/references/examples.md +63 -6
- package/skills/ti-synthengine/references/guide.md +61 -57
- package/skills/ti-synthengine/references/instruments-and-effects.md +15 -15
- package/skills/ti-synthengine/references/native-variation.md +53 -14
- package/skills/ti-synthengine/references/recipes-interaction.md +25 -20
- package/skills/ti-synthengine/references/recipes.md +19 -16
- package/skills/ti-synthengine/references/recommendations.md +12 -12
- package/skills/ti-synthengine/references/sound-api.md +197 -0
- package/skills/ti-synthengine/references/sound-design.md +7 -7
- package/skills/ti-synthengine/references/source-notes.md +62 -172
- package/skills/ti-synthengine/references/troubleshooting.md +17 -19
- package/skills/ti-synthengine/references/upgrade-2.0.0.md +40 -0
- package/skills/ti-ui/SKILL.md +28 -143
- package/skills/ti-ui/references/icons-and-splash-screens.md +74 -403
- package/skills/ti-ui/references/layouts-and-positioning.md +175 -402
- package/skills/ti-ui/references/listviews-and-performance.md +100 -703
- package/skills/ti-ui/references/platform-conventions.md +180 -0
- package/skills/ti-ui/references/user-interface.md +43 -0
- package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +0 -102
- package/skills/alloy-howtos/references/custom_tags.md +0 -148
- package/skills/ti-guides/references/coding-best-practices.md +0 -149
- package/skills/ti-guides/references/javascript-primer.md +0 -414
- package/skills/ti-guides/references/reserved-words.md +0 -36
- package/skills/ti-guides/references/style-and-conventions.md +0 -103
- package/skills/ti-howtos/references/android-platform-deep-dives.md +0 -624
- package/skills/ti-howtos/references/automation-fastlane-appium.md +0 -96
- package/skills/ti-howtos/references/buffer-codec-streams.md +0 -162
- package/skills/ti-howtos/references/google-maps-v2.md +0 -172
- package/skills/ti-howtos/references/ios-map-kit.md +0 -149
- package/skills/ti-howtos/references/ios-platform-deep-dives.md +0 -611
- package/skills/ti-howtos/references/tutorials.md +0 -565
- package/skills/ti-howtos/references/web-content-integration.md +0 -287
- package/skills/ti-howtos/references/webpack-build-pipeline.md +0 -124
- package/skills/ti-synthengine/references/android-sim80-correction-evidence.zip +0 -0
- package/skills/ti-synthengine/references/android-sim80-correction.json +0 -162
- package/skills/ti-synthengine/references/audio-pipeline-validation.md +0 -19
- package/skills/ti-synthengine/references/bypass-physical-recheck-evidence.zip +0 -0
- package/skills/ti-synthengine/references/frontier-android-evidence.zip +0 -0
- package/skills/ti-synthengine/references/frontier-ipad-evidence.zip +0 -0
- package/skills/ti-synthengine/references/frontier-physical-validation.json +0 -1918
- package/skills/ti-synthengine/references/native-tone-repetition-validation.md +0 -59
- package/skills/ti-synthengine/references/native-variation-proposal.md +0 -182
- package/skills/ti-synthengine/references/native-variation-validation.md +0 -63
- package/skills/ti-synthengine/references/performance-review-evidence.zip +0 -0
- package/skills/ti-synthengine/references/performance-review.json +0 -1146
- package/skills/ti-synthengine/references/physical-validation.json +0 -1457
- package/skills/ti-synthengine/references/source-snapshot.json +0 -542
- package/skills/ti-synthengine/references/stats-performance.json +0 -2992
- package/skills/ti-synthengine/references/stats-performance.md +0 -82
- package/skills/ti-synthengine/references/studio-validation.json +0 -6202
- package/skills/ti-synthengine/references/unified-bypass-performance.json +0 -22425
- package/skills/ti-synthengine/references/unified-validation.json +0 -314
- package/skills/ti-ui/references/accessibility-deep-dive.md +0 -288
- package/skills/ti-ui/references/animation-and-matrices.md +0 -569
- package/skills/ti-ui/references/application-structures.md +0 -626
- package/skills/ti-ui/references/custom-fonts-styling.md +0 -549
- package/skills/ti-ui/references/event-handling.md +0 -401
- package/skills/ti-ui/references/gestures.md +0 -448
- package/skills/ti-ui/references/orientation.md +0 -374
- package/skills/ti-ui/references/platform-ui-android.md +0 -727
- package/skills/ti-ui/references/platform-ui-ios.md +0 -576
- package/skills/ti-ui/references/scrolling-views.md +0 -288
- package/skills/ti-ui/references/tableviews.md +0 -542
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
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 =
|
|
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
|
|
22
|
-
if (!
|
|
23
|
-
current =
|
|
24
|
-
|
|
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 (
|
|
38
|
-
//
|
|
39
|
-
|
|
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', {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** TiSynthEngine
|
|
1
|
+
/** TiSynthEngine 2.0.0 candidate. One module version for the entire public interface. */
|
|
2
2
|
declare namespace synth {
|
|
3
3
|
type Bus = 'music' | 'effects' | 'ui' | 'ambience';
|
|
4
4
|
type FilterType = 'none' | 'lowpass' | 'highpass' | 'bandpass';
|
|
@@ -46,7 +46,7 @@ declare namespace synth {
|
|
|
46
46
|
audioSession?: 'playback' | 'ambient';
|
|
47
47
|
}
|
|
48
48
|
interface Defaults {
|
|
49
|
-
|
|
49
|
+
version: string;
|
|
50
50
|
capabilities: { variation: true; toneRepetition: true; [key: string]: boolean };
|
|
51
51
|
variationSchemaVersion: 1;
|
|
52
52
|
limits: Record<string, { min: number; max: number }>;
|
|
@@ -70,27 +70,147 @@ declare namespace synth {
|
|
|
70
70
|
sequenceId: number; playing: boolean; step: number; beat: number;
|
|
71
71
|
position: number; bpm: number; revision: number;
|
|
72
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. */
|
|
73
176
|
function getDefaults(): Defaults;
|
|
74
177
|
function start(options?: StartOptions): boolean;
|
|
75
178
|
/** One finite attack. intervalMs is rejected; use repeatTone for repetition. */
|
|
179
|
+
/** @deprecated Use createSound(...).play(). The existing signature and behavior remain supported. */
|
|
76
180
|
function playTone(options: ToneOptions & { intervalMs?: never }): boolean;
|
|
77
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. */
|
|
78
183
|
function repeatTone(options: RepeatingToneOptions): number;
|
|
184
|
+
/** @deprecated Use the repetition control update(). The existing signature and behavior remain supported. */
|
|
79
185
|
function updateTone(options: ToneUpdate): boolean;
|
|
80
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. */
|
|
81
188
|
function stopTone(options: { toneId: number }): boolean;
|
|
189
|
+
/** @deprecated Use a Sound with playback.type chord. The existing signature and behavior remain supported. */
|
|
82
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. */
|
|
83
192
|
function noteOn(options: NoteOptions): boolean;
|
|
193
|
+
/** @deprecated Use Note.update(). The existing signature and behavior remain supported. */
|
|
84
194
|
function updateNote(options: NoteUpdate): boolean;
|
|
85
195
|
/** @deprecated Use updateNote; identical behavior and voiceId contract. */
|
|
86
196
|
function updateVoice(options: NoteUpdate): boolean;
|
|
197
|
+
/** @deprecated Use Note.noteOff(). The existing signature and behavior remain supported. */
|
|
87
198
|
function noteOff(options: { voiceId: number }): boolean;
|
|
199
|
+
/** @deprecated Use a Sound with playback.type pattern. The existing signature and behavior remain supported. */
|
|
88
200
|
function playSequence(options: SequenceOptions): number;
|
|
201
|
+
/** @deprecated Use the pattern control update(). The existing signature and behavior remain supported. */
|
|
89
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. */
|
|
90
204
|
function stopSequence(options: { sequenceId: number }): boolean;
|
|
205
|
+
/** @deprecated Use the pattern control getState(). The existing signature and behavior remain supported. */
|
|
91
206
|
function getSequenceState(options: { sequenceId: number }): SequenceState | null;
|
|
207
|
+
function setTempo(bpm: number): boolean;
|
|
208
|
+
/** @deprecated Use setTempo(bpm); the dictionary signature remains supported. */
|
|
92
209
|
function setTempo(options: { bpm: number }): boolean;
|
|
210
|
+
function setVolume(volume: number): boolean;
|
|
211
|
+
/** @deprecated Use setVolume(volume); the dictionary signature remains supported. */
|
|
93
212
|
function setVolume(options: { volume: number }): boolean;
|
|
213
|
+
/** @deprecated Use setProcessing(); its reverb decay unit is milliseconds. The existing signature and behavior remain supported. */
|
|
94
214
|
function setMasterProcessing(options: Record<string, unknown>): boolean;
|
|
95
215
|
function enableStats(): boolean;
|
|
96
216
|
function disableStats(): boolean;
|
|
@@ -1,8 +1,8 @@
|
|
|
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/examples.md` SHA-256: `ee8aed566a63062ae63ae78f0b96fa8d73c70ab2f50aed81081c26acc24718af`.
|
|
2
2
|
|
|
3
3
|
## Sustained game motor
|
|
4
4
|
|
|
5
|
-
|
|
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
8
|
if (!['noteOn', 'noteOff', 'updateNote'].every(function (name) {
|
|
@@ -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
|
-
|
|
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') {
|
|
@@ -175,7 +175,7 @@ Call `closeMixMeter` when its owner hides or closes. Display unavailable or unme
|
|
|
175
175
|
|
|
176
176
|
## Bounded variation for repeated noise impacts
|
|
177
177
|
|
|
178
|
-
The
|
|
178
|
+
The 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')
|
|
@@ -1,17 +1,18 @@
|
|
|
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/api.md` SHA-256: `ca5b7f1a44ef79543399fd1a40fa83024c190c086b6412fb79dc54de91a2a329`.
|
|
2
2
|
|
|
3
3
|
# API reference
|
|
4
4
|
|
|
5
5
|
Module id: `ti.synthengine`
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Module version: `2.0.0`. Read the [Sound object reference](sound-api.md) for reusable definitions, playback controls and property units. This page documents the global controls and direct native parameters behind those interpretations.
|
|
8
8
|
|
|
9
|
-
Android and iOS expose the same public methods
|
|
9
|
+
Android and iOS expose the same public methods and waveform values. Pattern controls emit `end`; direct native sequences emit `sequenceend`. Option objects are strict: an unknown key is rejected with `unsupported_option`. Reported metadata and rejection diagnostics have platform differences; this reference does not promise sample-identical rendering between Android and iOS.
|
|
10
10
|
|
|
11
11
|
<!-- TOC-START -->
|
|
12
12
|
## Contents
|
|
13
13
|
|
|
14
|
-
- [
|
|
14
|
+
- [Sound interface](#sound-interface)
|
|
15
|
+
- [Native attack variation](#native-attack-variation)
|
|
15
16
|
- [Return values](#return-values)
|
|
16
17
|
- [`getDefaults()`](#getdefaults)
|
|
17
18
|
- [Limits](#limits)
|
|
@@ -42,9 +43,30 @@ Android and iOS expose the same public methods, one event and waveform values. O
|
|
|
42
43
|
|
|
43
44
|
<!-- TOC-END -->
|
|
44
45
|
|
|
45
|
-
##
|
|
46
|
+
## Sound interface
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
| Method | Result |
|
|
49
|
+
| --- | --- |
|
|
50
|
+
| `getContract()` | Installed module version, capabilities, units and structural property allowlists |
|
|
51
|
+
| `createSound({ name?, sound?, playback? })` | A reusable validated Sound; no audio starts |
|
|
52
|
+
| `Sound.play(changes?)` | Finite acceptance or an independent note/repetition/pattern control |
|
|
53
|
+
| `Sound.noteOn(changes?)` | One held-note control, or `false` on operational rejection |
|
|
54
|
+
| `Sound.set({ sound?, playback? })` | Atomic stored revision for future executions |
|
|
55
|
+
| `Sound.getPreset()` | Detached authored definition |
|
|
56
|
+
| Note `update(changes)`, `noteOff()` | Edit or release that held note |
|
|
57
|
+
| Repetition `update(changes)`, `stop()` | Edit future finite attacks or cancel repetition |
|
|
58
|
+
| Pattern `update(changes)`, `stop()`, `getState()` | Edit, stop or inspect that pattern |
|
|
59
|
+
| Pattern `addEventListener('end', fn)`, `removeEventListener('end', fn)` | Subscribe to that pattern's completion or stopping |
|
|
60
|
+
| `setProcessing(options)` | Shared effects with delay `time` and reverb `decay` in milliseconds |
|
|
61
|
+
| `setVolume(number)`, `setTempo(number)` | Global gain and beats per minute |
|
|
62
|
+
|
|
63
|
+
Sound definitions split synthesis into `sound` and execution defaults into `playback`. `play()` and `noteOn()` accept flat temporary overrides. Invalid configurations throw before publication; operational playback rejection returns `false`. Finite events end naturally without individual controls. Shutdown invalidates controls while definitions remain reusable.
|
|
64
|
+
|
|
65
|
+
The [Sound reference](sound-api.md) supplies all properties, defaults, units and interpretation restrictions. The direct native methods below remain supported and document the validators and rendering parameters behind each interpretation. Use the [upgrade guide](upgrade-2.0.0.md) for method mappings.
|
|
66
|
+
|
|
67
|
+
## Native attack variation
|
|
68
|
+
|
|
69
|
+
The optional `variation` dictionary is accepted by `playTone`, `repeatTone`, `playChord`, `noteOn`, sequence `voice` and step `overrides`. Both platforms advertise `capabilities.variation: true` and `variationSchemaVersion: 1`; consumers must require both before sending the dictionary. See [native variation](native-variation.md) for fields, source restrictions, seeds and examples. Native `amount` is linear; Studio divides its displayed percentage by 100. `updateNote` rejects the dictionary. An override replaces the whole inherited dictionary, and an amount-zero dictionary still validates its ranges.
|
|
48
70
|
|
|
49
71
|
## Return values
|
|
50
72
|
|
|
@@ -60,11 +82,11 @@ Returns the installed contract without starting the audio stream.
|
|
|
60
82
|
var contract = synth.getDefaults()
|
|
61
83
|
```
|
|
62
84
|
|
|
63
|
-
The shared result in
|
|
85
|
+
The shared result in TiSynth 2.0.0 has this shape; Android adds the platform metadata described below. `version` identifies the installed module, with no independent API version:
|
|
64
86
|
|
|
65
87
|
```javascript
|
|
66
88
|
{
|
|
67
|
-
|
|
89
|
+
version: '2.0.0',
|
|
68
90
|
capabilities: { variation: true, toneRepetition: true },
|
|
69
91
|
variationSchemaVersion: 1,
|
|
70
92
|
defaults: {
|
|
@@ -127,7 +149,7 @@ The shared result in version 1.1.0 has this shape; Android adds the platform met
|
|
|
127
149
|
|
|
128
150
|
`fmDepthEnd`, `detunes`, `spatialX` and `spatialY` have no reported default: their presence changes how the call is interpreted. Supplying a spatial coordinate enables binaural; the other coordinate then defaults to 0 internally. The maximum frequency is `sampleRate * 0.45`. Before the stream opens, the reported fallback is 19,845 Hz. Read the object again after `start()` if the precise device limit matters.
|
|
129
151
|
|
|
130
|
-
|
|
152
|
+
Both platforms report `capabilities.variation: true` and `variationSchemaVersion: 1`. Android also reports `nativeSequence`, `masterProcessing` and `modulations` capability flags and `limits.stepDurationMs`. iOS omits those three flags and `limits.stepDurationMs` while implementing the corresponding methods and millisecond sequences. Detect a required core method with `typeof synth.playSequence === 'function'` (and the other methods your feature needs); require the capability/schema pair specifically for variation. Both platforms report `limits.maxSequences`, `limits.priority` and `limits.effectSend`. `limits.stepDuration` is in beats on both platforms; millisecond sequences accept `4000 / sampleRate` through 60,000 even when `limits.stepDurationMs` is absent.
|
|
131
153
|
|
|
132
154
|
## Limits
|
|
133
155
|
|
|
@@ -192,7 +214,7 @@ On iOS, `playback` ignores the silent switch and interrupts other apps' audio. `
|
|
|
192
214
|
|
|
193
215
|
## `noteOn(options)`
|
|
194
216
|
|
|
195
|
-
Starts a sustained native voice.
|
|
217
|
+
Starts a sustained native voice. Check `typeof synth.noteOn === 'function'`, `noteOff` and `updateNote` before enabling their controls. Read the installed module version from `getDefaults().version`. The note has no duration limit and needs no JavaScript timer to remain held.
|
|
196
218
|
|
|
197
219
|
| Field | Rule |
|
|
198
220
|
| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -251,7 +273,7 @@ Begins release from the current level, including during attack or decay. Repeate
|
|
|
251
273
|
| `spatialX`, `spatialY` | Target position for a spatial held voice; omitted coordinate stays unchanged. |
|
|
252
274
|
| `effectSend` | Explicit processed share, 0-1, overriding category selection. |
|
|
253
275
|
|
|
254
|
-
|
|
276
|
+
Supply at least one change. An incompatible change rejects the entire request when the ID is known; unknown/ended IDs accept publication as a no-op. The callback also checks source compatibility before applying a command. Changed continuous parameters ramp linearly from their current values over 10 ms. A new target redirects the ramp without restarting oscillator phase or the envelope. Unchanged parameters keep their current ramps. These edits also work during release.
|
|
255
277
|
|
|
256
278
|
Pitch updates are absolute: an initial `detune` is already included in the note's starting frequency. To edit tuning later, compute the desired effective frequency in the app and send `frequency`. There is no `detune` update field. Filter type, ADSR, quantization and wavetable require a new attack. Noise clock, low-pass cutoff, send and compatible stereo/spatial position support live 10 ms updates.
|
|
257
279
|
|
|
@@ -319,7 +341,7 @@ Plays one pitch. It uses 440 Hz when neither pitch field is present. Note names
|
|
|
319
341
|
|
|
320
342
|
Omitted attack/release values are shortened to fit an event smaller than the default envelope. Explicit values must satisfy the documented envelope rules. `getDefaults()` reports the baseline defaults, not these per-event adjustments.
|
|
321
343
|
|
|
322
|
-
In the
|
|
344
|
+
In the native implementation, the iOS timed tone/chord command builder
|
|
323
345
|
initially rounds accepted zero attack/release values to one sample, before
|
|
324
346
|
trimming them to the event duration budget. Android retains zero samples.
|
|
325
347
|
Validator acceptance does not imply identical zero-edge rendering. Held notes
|
|
@@ -375,7 +397,7 @@ Those three calls use JavaScript timing and independent attack selection. For an
|
|
|
375
397
|
|
|
376
398
|
Returns Boolean acceptance. Requires a known positive repetition identifier and at least one change. Accepts partial finite-tone options, including `intervalMs`, and merges them with the latest accepted recipe before validating the entire result. Supplying `note` replaces an earlier `frequency`; supplying `frequency` replaces an earlier `note`. Supplying both is invalid. Invalid edits leave the last accepted recipe intact.
|
|
377
399
|
|
|
378
|
-
An accepted edit affects the next
|
|
400
|
+
An accepted edit affects the next scheduled attack without moving its deadline. The new interval sets the gap after that attack. Active attacks keep their original configuration. A supplied `variation` dictionary replaces the whole previous dictionary; `{ amount: 0 }` disables future variation. Each repetition keeps its own seed and admitted-attack counter. Edits preserve the stream unless the seed changes, which restarts it. Unknown or retired IDs reject edits.
|
|
379
401
|
|
|
380
402
|
### `stopTone({ toneId })`
|
|
381
403
|
|
|
@@ -440,7 +462,7 @@ synth.stopSequence({ sequenceId: musicId })
|
|
|
440
462
|
|
|
441
463
|
Selected audio follows fixed input gain → chorus → ping-pong delay → reverb → master volume → optional saturation. Dry audio receives the same global input/master gains, then recombines before one final sample-peak protector with no retained samples. Independent notes never trigger voice-count normalization. The limiter remains the final protection.
|
|
442
464
|
|
|
443
|
-
|
|
465
|
+
This method requires a running engine and returns Boolean acceptance. It merges partial updates into the last accepted processing configuration, validates the complete result and publishes it atomically. Continuous controls ramp over 10 ms. Unknown fields, numeric booleans and non-finite values reject the whole edit. Check that the method exists before calling it.
|
|
444
466
|
|
|
445
467
|
| Section | Fields and initial values |
|
|
446
468
|
| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -455,7 +477,7 @@ Delay sync accepts `off`, `quarter`, `eighth`, `sixteenth`, `quarterTriplet`, `e
|
|
|
455
477
|
|
|
456
478
|
Processing uses one shared chain for the selected categories. `applyTo` is an array drawn from `music`, `effects`, `ui` and `ambience`; default all four. Each event or held voice uses `bus: 'effects'` by default. Optional `effectSend: 0…1` overrides category selection for that voice. Input gain and master volume remain global. Selected audio receives chorus, delay, reverb and optional saturation, then recombines with dry audio before one final limiter. Send changes ramp over 10 ms.
|
|
457
479
|
|
|
458
|
-
Defaults keep all effects and saturation disabled, input gain at unity, and
|
|
480
|
+
Defaults keep all effects and saturation disabled, input gain at unity, and route audio through the unprocessed path. Enabling saturation is an explicit sound-design choice. Output protection is still required with dense voices and effect feedback.
|
|
459
481
|
|
|
460
482
|
## Additional voice modulation
|
|
461
483
|
|
|
@@ -469,7 +491,7 @@ Defaults keep all effects and saturation disabled, input gain at unity, and pres
|
|
|
469
491
|
| `depth` | 0-1, default 0; scales up to four cutoff octaves, 0.45 PWM offset or ten FM-index units. Two contributions sum with safe clamping. |
|
|
470
492
|
| `sync` | Same musical values as delay; default off. Synced rates follow native tempo (up to 30 Hz at 300 BPM in sixteenth-note triplets). |
|
|
471
493
|
|
|
472
|
-
Edits preserve oscillator/LFO phases. Continuous modulation contributions ramp over 10 ms; cutoff stays within 20 Hz and the frequency maximum, PWM within 0.05-0.95, FM index within 0-10.
|
|
494
|
+
Edits preserve oscillator/LFO phases. Continuous modulation contributions ramp over 10 ms; cutoff stays within 20 Hz and the frequency maximum, PWM within 0.05-0.95, FM index within 0-10. Sequence voices can inherit initial modulations, and steps can override them. These two slots coexist with the independent `lfoFreq`/`lfoDepth` pitch vibrato. Timed tones and chords reject them.
|
|
473
495
|
|
|
474
496
|
## `playChord(options)`
|
|
475
497
|
|
|
@@ -669,7 +691,7 @@ Listen with stereo headphones. Height perception depends on the listener, headph
|
|
|
669
691
|
|
|
670
692
|
Use `typeof synth.getStats === 'function'` to check that the expected module is installed before enabling a diagnostics panel.
|
|
671
693
|
|
|
672
|
-
|
|
694
|
+
This method returns a new snapshot without resetting counters and is available before start and after shutdown. Occupancy comes from the last completed render block; queued commands are read at query time. The query adds no audio-thread allocation, locks or waiting.
|
|
673
695
|
|
|
674
696
|
| Field | Meaning |
|
|
675
697
|
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -697,7 +719,7 @@ Returns a new snapshot without resetting counters. Available before start and af
|
|
|
697
719
|
| `bufferFrames` | Android Oboe output buffer size; otherwise `null`. This is distinct from `callbackFrames`. |
|
|
698
720
|
| `estimatedOutputLatencyMs` | Android timestamp-based stream-to-DAC estimate, when valid; otherwise `null` (always `null` on this iOS backend). |
|
|
699
721
|
|
|
700
|
-
In the
|
|
722
|
+
In the native implementation, iOS early rejections in tempo/sequence operations and a
|
|
701
723
|
stopped `setMasterProcessing` call can bypass rejection counters. Incompatible
|
|
702
724
|
held spatial-mode or modulation updates also have uncounted iOS returns.
|
|
703
725
|
Android counts more of these cases, but an unknown/retired `stopSequence` return
|