@maccesar/titools 5.2.0 → 5.2.2
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 +82 -0
- package/README.md +83 -72
- package/agents/ti-pro.md +1 -1
- package/commands/ti-audit.md +2 -2
- package/docs/examples.md +91 -0
- package/docs/knowledge-index.md +57 -0
- package/lib/commands/uninstall.js +19 -16
- package/lib/commands/update.js +1 -1
- package/lib/downloader.js +1 -1
- package/lib/utils.js +2 -0
- package/package.json +4 -2
- package/skills/purgetss/references/multi-density-images.md +1 -1
- package/skills/ti-admob-unified/SKILL.md +21 -7
- package/skills/ti-admob-unified/assets/example/app.js +229 -25
- package/skills/ti-admob-unified/assets/example/lib/ads.js +30 -2
- package/skills/ti-admob-unified/assets/example/library-usage.js +33 -1
- package/skills/ti-admob-unified/references/api-reference.md +39 -16
- package/skills/ti-admob-unified/references/banners.md +9 -9
- package/skills/ti-admob-unified/references/contributing.md +14 -9
- package/skills/ti-admob-unified/references/dependencies.md +31 -25
- package/skills/ti-admob-unified/references/fullscreen.md +43 -28
- package/skills/ti-admob-unified/references/game-monetization.md +138 -7
- package/skills/ti-admob-unified/references/getting-started.md +75 -31
- package/skills/ti-admob-unified/references/index.md +5 -2
- package/skills/ti-admob-unified/references/integration.md +8 -6
- package/skills/ti-admob-unified/references/library.md +41 -10
- package/skills/ti-admob-unified/references/mediation-parity.md +17 -0
- package/skills/ti-admob-unified/references/mediation.md +22 -9
- package/skills/ti-admob-unified/references/migration.md +11 -7
- package/skills/ti-admob-unified/references/module-changelog.md +41 -11
- package/skills/ti-admob-unified/references/privacy.md +35 -8
- package/skills/ti-admob-unified/references/production.md +67 -0
- package/skills/ti-admob-unified/references/rewarded-interstitial.md +101 -0
- package/skills/ti-admob-unified/references/roadmap.md +28 -31
- package/skills/ti-admob-unified/references/source-notes.md +51 -4
- package/skills/ti-admob-unified/references/source-snapshot.json +249 -45
- package/skills/ti-admob-unified/references/third-party-notices.md +4 -4
- package/skills/ti-game/SKILL.md +23 -6
- package/skills/ti-game/references/api.md +34 -30
- package/skills/ti-game/references/debugging-performance.md +18 -9
- package/skills/ti-game/references/examples.md +103 -20
- package/skills/ti-game/references/input.md +101 -0
- package/skills/ti-game/references/patterns.md +39 -15
- package/skills/ti-game/references/physics.md +80 -52
- package/skills/ti-game/references/project-setup.md +118 -56
- package/skills/ti-game/references/recipes-action.md +107 -8
- package/skills/ti-game/references/recipes-adventure-effects.md +41 -9
- package/skills/ti-game/references/roadmap.md +10 -3
- package/skills/ti-game/references/source-notes.md +81 -0
- package/skills/ti-game/references/tilemaps.md +12 -4
- package/skills/ti-synthengine/SKILL.md +81 -95
- package/skills/ti-synthengine/assets/example/README.md +84 -0
- package/skills/ti-synthengine/assets/example/app.js +1178 -0
- package/skills/ti-synthengine/assets/example/lib/sequenceOwner.js +83 -0
- package/skills/ti-synthengine/assets/example/lib/sequenceScore.js +25 -0
- package/skills/ti-synthengine/references/advanced-examples.md +174 -0
- package/skills/ti-synthengine/references/android-sim80-correction-evidence.zip +0 -0
- package/skills/ti-synthengine/references/android-sim80-correction.json +162 -0
- package/skills/ti-synthengine/references/api.md +434 -380
- package/skills/ti-synthengine/references/audio-engine.md +157 -230
- package/skills/ti-synthengine/references/bypass-physical-recheck-evidence.zip +0 -0
- package/skills/ti-synthengine/references/examples.md +123 -253
- 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 +1918 -0
- package/skills/ti-synthengine/references/guide.md +188 -156
- package/skills/ti-synthengine/references/performance-review-evidence.zip +0 -0
- package/skills/ti-synthengine/references/performance-review.json +1146 -0
- package/skills/ti-synthengine/references/physical-validation.json +1457 -0
- package/skills/ti-synthengine/references/recipes-interaction.md +549 -0
- package/skills/ti-synthengine/references/recipes.md +423 -599
- package/skills/ti-synthengine/references/recommendations.md +63 -113
- package/skills/ti-synthengine/references/sound-design.md +134 -258
- package/skills/ti-synthengine/references/source-notes.md +93 -105
- package/skills/ti-synthengine/references/source-snapshot.json +379 -32
- package/skills/ti-synthengine/references/stats-performance.md +64 -20
- package/skills/ti-synthengine/references/studio-validation.json +6202 -0
- package/skills/ti-synthengine/references/troubleshooting.md +109 -121
- package/skills/ti-synthengine/references/unified-bypass-performance.json +22425 -0
- package/skills/ti-synthengine/references/unified-validation.json +314 -0
- package/AGENTS-VERCEL-RESEARCH.md +0 -175
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
> Source snapshot: official TiSynthEngine 1.0.0
|
|
1
|
+
> Source snapshot: official TiSynthEngine 1.0.0 documentation at release source commit `e7cbbe8a6f9ab38088fd8029c7b43cef6501101f` (2026-10-24). Upstream `documentation/examples.md` SHA-256: `48104b9d413050d439ee605c92a2456a50b42c4c80e2d7c2c05706eecc7db215`.
|
|
2
2
|
|
|
3
3
|
# Examples
|
|
4
4
|
|
|
5
|
-
Every snippet on this page uses the TiSynthEngine 1.0.0 contract. Unless a
|
|
6
|
-
|
|
5
|
+
Every snippet on this page uses the TiSynthEngine 1.0.0 contract. Unless a snippet includes startup code, it assumes the engine is already running.
|
|
6
|
+
|
|
7
|
+
Additional [curated recipes](recipes.md) provide application sound and interaction variants.
|
|
8
|
+
|
|
9
|
+
For interactive instruments and native processing, begin with [held motors](advanced-examples.md#sustained-game-motor), [native sequences](advanced-examples.md#native-sequence-with-chords-and-edits), [master processing](advanced-examples.md#chorus-delay-reverb-and-creative-saturation) or [two LFOs](advanced-examples.md#two-voice-lfos). Use matching official packages and check method availability before enabling a feature.
|
|
7
10
|
|
|
8
11
|
```javascript
|
|
9
12
|
var synth = require('ti.synthengine')
|
|
@@ -40,7 +43,7 @@ if (contract.apiVersion !== '1.0.0') {
|
|
|
40
43
|
- [Wah and filtered laser](#wah-and-filtered-laser)
|
|
41
44
|
- [Kick and hi-hat in one pattern](#kick-and-hi-hat-in-one-pattern)
|
|
42
45
|
- [Detuned chords](#detuned-chords)
|
|
43
|
-
- [Chain
|
|
46
|
+
- [Chain sequences with `sequenceend`](#chain-sequences-with-sequenceend)
|
|
44
47
|
- [Rules across keys](#rules-across-keys)
|
|
45
48
|
- [Speaker-safe startup](#speaker-safe-startup)
|
|
46
49
|
- [Validation at an input boundary](#validation-at-an-input-boundary)
|
|
@@ -60,10 +63,12 @@ function onPostLayout () {
|
|
|
60
63
|
timer = setTimeout(function () {
|
|
61
64
|
timer = null
|
|
62
65
|
win.removeEventListener('postlayout', onPostLayout)
|
|
63
|
-
started = synth.
|
|
66
|
+
started = synth.start({
|
|
64
67
|
maxVoices: 16,
|
|
65
|
-
mixingProfile: 'conservative'
|
|
68
|
+
mixingProfile: 'conservative',
|
|
69
|
+
audioSession: 'ambient'
|
|
66
70
|
})
|
|
71
|
+
if (!started) Ti.API.warn('Audio startup failed; keep playback controls disabled')
|
|
67
72
|
}, 250)
|
|
68
73
|
}
|
|
69
74
|
|
|
@@ -78,26 +83,21 @@ win.addEventListener('close', cleanup)
|
|
|
78
83
|
win.open()
|
|
79
84
|
```
|
|
80
85
|
|
|
86
|
+
The startup example uses `ambient` for game/UI feedback. On iOS it respects silent mode and mixes with other apps. The module default is `playback`; Android validates either value without changing its output. Shut down before changing the policy. Use the [interactive session controls](../assets/example/README.md#audio-session) to compare them.
|
|
87
|
+
|
|
81
88
|
## Built-in waveforms
|
|
82
89
|
|
|
83
90
|
```javascript
|
|
84
91
|
var names = ['SINE', 'SQUARE', 'SAWTOOTH', 'TRIANGLE', 'NOISE']
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
duration: 400,
|
|
91
|
-
attack: 8,
|
|
92
|
-
release: 100,
|
|
93
|
-
volume: 0.6,
|
|
94
|
-
waveType: WAVE[name]
|
|
95
|
-
})
|
|
96
|
-
}, index * 500)
|
|
92
|
+
synth.playSequence({ timeUnit: 'ms', stepDuration: 500,
|
|
93
|
+
voice: { attack: 8, release: 100, volume: 0.6 },
|
|
94
|
+
steps: names.map(function (name) {
|
|
95
|
+
return { notes: [69], length: 300, overrides: { waveType: WAVE[name] } }
|
|
96
|
+
})
|
|
97
97
|
})
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
-
Noise ignores pitch
|
|
100
|
+
Noise ignores pitch; each sounding step still supplies one pitch array.
|
|
101
101
|
|
|
102
102
|
## Variable-rate filtered noise
|
|
103
103
|
|
|
@@ -116,8 +116,7 @@ synth.playTone({
|
|
|
116
116
|
})
|
|
117
117
|
```
|
|
118
118
|
|
|
119
|
-
`noiseRate` starts at 12 kHz and falls to 600 Hz. `lowPassHz` removes high
|
|
120
|
-
frequency energy after the 8-bit source quantizer.
|
|
119
|
+
`noiseRate` starts at 12 kHz and falls to 600 Hz. `lowPassHz` removes high frequency energy after the 8-bit source quantizer.
|
|
121
120
|
|
|
122
121
|
## Pulse-width sweep
|
|
123
122
|
|
|
@@ -151,8 +150,7 @@ synth.playTone({
|
|
|
151
150
|
})
|
|
152
151
|
```
|
|
153
152
|
|
|
154
|
-
The table repeats as a stepped cycle. `bitDepth: 8` quantizes each table value
|
|
155
|
-
before filtering and the amplitude envelope.
|
|
153
|
+
The table repeats as a stepped cycle. `bitDepth: 8` quantizes each table value before filtering and the amplitude envelope.
|
|
156
154
|
|
|
157
155
|
## Fixed controls on a chord
|
|
158
156
|
|
|
@@ -171,48 +169,25 @@ synth.playChord({
|
|
|
171
169
|
})
|
|
172
170
|
```
|
|
173
171
|
|
|
174
|
-
Chord voices share fixed shaping controls. Sweep fields such as
|
|
175
|
-
`pulseWidthEnd` and `noiseRateEnd` are not accepted by `playChord()`.
|
|
172
|
+
Chord voices share fixed shaping controls. Sweep fields such as `pulseWidthEnd` and `noiseRateEnd` are not accepted by `playChord()`.
|
|
176
173
|
|
|
177
174
|
## Wave-shaping pattern overrides
|
|
178
175
|
|
|
179
176
|
```javascript
|
|
180
|
-
synth.
|
|
177
|
+
synth.playSequence({
|
|
178
|
+
timeUnit: 'ms',
|
|
181
179
|
stepDuration: 210,
|
|
182
|
-
attack: 2,
|
|
183
|
-
release: 80,
|
|
184
|
-
volume: 0.48,
|
|
185
|
-
waveType: WAVE.NOISE,
|
|
186
|
-
noiseRate: 12000,
|
|
187
|
-
lowPassHz: 2600,
|
|
188
|
-
bitDepth: 8,
|
|
180
|
+
voice: { attack: 2, release: 80, volume: 0.48, waveType: WAVE.NOISE, noiseRate: 12000, lowPassHz: 2600, bitDepth: 8 },
|
|
189
181
|
steps: [
|
|
190
|
-
{
|
|
182
|
+
{ frequencies: [120], duration: 180, overrides: { release: 150, noiseRateEnd: 800 } },
|
|
191
183
|
{ rest: true, duration: 100 },
|
|
192
|
-
{
|
|
193
|
-
|
|
194
|
-
duration: 300,
|
|
195
|
-
release: 120,
|
|
196
|
-
waveType: WAVE.SQUARE,
|
|
197
|
-
pulseWidth: 0.1,
|
|
198
|
-
pulseWidthEnd: 0.82,
|
|
199
|
-
lowPassHz: 0,
|
|
200
|
-
bitDepth: 0
|
|
201
|
-
},
|
|
202
|
-
{
|
|
203
|
-
note: 'D4',
|
|
204
|
-
duration: 360,
|
|
205
|
-
release: 160,
|
|
206
|
-
waveType: WAVE.WAVETABLE,
|
|
207
|
-
waveTable: [-1, -0.7, -0.1, 0.8, 1, 0.35, -0.25, -0.55]
|
|
208
|
-
}
|
|
184
|
+
{ notes: [57], duration: 300, overrides: { release: 120, waveType: WAVE.SQUARE, pulseWidth: 0.1, pulseWidthEnd: 0.82, lowPassHz: 0, bitDepth: 0 } },
|
|
185
|
+
{ notes: [62], duration: 360, overrides: { release: 160, waveType: WAVE.WAVETABLE, waveTable: [-1, -0.7, -0.1, 0.8, 1, 0.35, -0.25, -0.55] } }
|
|
209
186
|
]
|
|
210
187
|
})
|
|
211
188
|
```
|
|
212
189
|
|
|
213
|
-
Pattern roots provide inherited values. Each sounding step can override the
|
|
214
|
-
source and any shaping control; a `WAVETABLE` step needs a local or inherited
|
|
215
|
-
`waveTable`.
|
|
190
|
+
Pattern roots provide inherited values. Each sounding step can override the source and any shaping control; a `WAVETABLE` step needs a local or inherited `waveTable`.
|
|
216
191
|
|
|
217
192
|
## Pitch sweep and pan movement
|
|
218
193
|
|
|
@@ -230,8 +205,7 @@ synth.playTone({
|
|
|
230
205
|
})
|
|
231
206
|
```
|
|
232
207
|
|
|
233
|
-
Set `frequencyEnd: 0` to keep the starting pitch. Set `panEnd` equal to `pan`
|
|
234
|
-
when no stereo movement is wanted.
|
|
208
|
+
Set `frequencyEnd: 0` to keep the starting pitch. Set `panEnd` equal to `pan` when no stereo movement is wanted.
|
|
235
209
|
|
|
236
210
|
## Vibrato
|
|
237
211
|
|
|
@@ -248,8 +222,7 @@ synth.playTone({
|
|
|
248
222
|
})
|
|
249
223
|
```
|
|
250
224
|
|
|
251
|
-
`lfoFreq` and `lfoDepth` are both in hertz. A depth of 6 Hz is gentle around
|
|
252
|
-
E4; use your ears when moving the same setting to a much lower note.
|
|
225
|
+
`lfoFreq` and `lfoDepth` are both in hertz. A depth of 6 Hz is gentle around E4; use your ears when moving the same setting to a much lower note.
|
|
253
226
|
|
|
254
227
|
## Chord with an even spread
|
|
255
228
|
|
|
@@ -279,79 +252,63 @@ synth.playChord({
|
|
|
279
252
|
})
|
|
280
253
|
```
|
|
281
254
|
|
|
282
|
-
Use `playChord` for a known simultaneous group. Launching four separate tones
|
|
283
|
-
is not atomic and gives each one full event gain.
|
|
255
|
+
Use `playChord` for a known simultaneous group. Launching four separate tones is not atomic and gives each one full event gain.
|
|
284
256
|
|
|
285
257
|
## Tempo, note values and swing
|
|
286
258
|
|
|
287
259
|
```javascript
|
|
288
|
-
synth.
|
|
289
|
-
|
|
260
|
+
synth.setTempo({ bpm: 132 })
|
|
261
|
+
synth.playSequence({
|
|
262
|
+
timeUnit: 'beats',
|
|
263
|
+
stepDuration: 0.5,
|
|
290
264
|
swing: 0.12,
|
|
291
|
-
|
|
292
|
-
attack: 4,
|
|
293
|
-
release: 55,
|
|
294
|
-
volume: 0.55,
|
|
295
|
-
waveType: WAVE.SQUARE,
|
|
265
|
+
voice: { attack: 4, release: 55, volume: 0.55, waveType: WAVE.SQUARE },
|
|
296
266
|
steps: [
|
|
297
|
-
{
|
|
298
|
-
{
|
|
267
|
+
{ notes: [60] },
|
|
268
|
+
{ notes: [64] },
|
|
299
269
|
{ rest: true },
|
|
300
|
-
{
|
|
301
|
-
{
|
|
270
|
+
{ notes: [67] },
|
|
271
|
+
{ notes: [72], duration: 1 }
|
|
302
272
|
]
|
|
303
273
|
})
|
|
304
274
|
```
|
|
305
275
|
|
|
306
|
-
Swing
|
|
276
|
+
Swing adjusts pairs of intervals by `swing * min(A, B)`: the first grows and the second shrinks by that amount, preserving the pair total. Negative values reverse the adjustment. The default is 0 and the range is −0.75…0.75.
|
|
307
277
|
|
|
308
278
|
## Millisecond pattern
|
|
309
279
|
|
|
310
280
|
```javascript
|
|
311
|
-
synth.
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
waveType: WAVE.TRIANGLE,
|
|
281
|
+
synth.playSequence({
|
|
282
|
+
timeUnit: 'ms',
|
|
283
|
+
stepDuration: 100,
|
|
284
|
+
voice: { pan: -0.4, panEnd: 0.4, waveType: WAVE.TRIANGLE },
|
|
315
285
|
steps: [
|
|
316
|
-
{
|
|
286
|
+
{ notes: [72], duration: 90 },
|
|
317
287
|
{ rest: true, duration: 20 },
|
|
318
|
-
{
|
|
288
|
+
{ notes: [74], duration: 90 },
|
|
319
289
|
{ rest: true, duration: 20 },
|
|
320
|
-
{
|
|
290
|
+
{ notes: [76], duration: 90 },
|
|
321
291
|
{ rest: true, duration: 20 },
|
|
322
|
-
{
|
|
292
|
+
{ notes: [79], duration: 180 }
|
|
323
293
|
]
|
|
324
294
|
})
|
|
325
295
|
```
|
|
326
296
|
|
|
327
|
-
Each `duration` sets
|
|
328
|
-
The 90 ms tones followed by 20 ms rests put the first four notes 110 ms apart;
|
|
329
|
-
the last tone lasts 180 ms. Rests provide actual silence. `release` only fades
|
|
330
|
-
within a sounding step, not a separate gate. The pattern root does not accept
|
|
331
|
-
`duration`, and `stepDuration` is only a fallback when a step has no timing.
|
|
297
|
+
Each `duration` sets the interval until the next step. The 90 ms intervals followed by 20 ms rests place attacks 110 ms apart; a release can overlap a rest. Gate defaults to 0.8. Use `length` to choose note duration independently, while ADSR remains milliseconds.
|
|
332
298
|
|
|
333
299
|
## Step overrides
|
|
334
300
|
|
|
335
301
|
```javascript
|
|
336
|
-
synth.
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
release: 90,
|
|
341
|
-
volume: 0.5,
|
|
342
|
-
waveType: WAVE.SINE,
|
|
302
|
+
synth.setTempo({ bpm: 100 })
|
|
303
|
+
synth.playSequence({
|
|
304
|
+
timeUnit: 'beats',
|
|
305
|
+
stepDuration: 0.5,
|
|
306
|
+
voice: { attack: 10, release: 90, volume: 0.5, waveType: WAVE.SINE },
|
|
343
307
|
steps: [
|
|
344
|
-
{
|
|
345
|
-
{
|
|
346
|
-
note: 'E4',
|
|
347
|
-
waveType: WAVE.SAWTOOTH,
|
|
348
|
-
pan: -0.7,
|
|
349
|
-
panEnd: 0.7,
|
|
350
|
-
lfoFreq: 7,
|
|
351
|
-
lfoDepth: 10
|
|
352
|
-
},
|
|
308
|
+
{ notes: [60] },
|
|
309
|
+
{ notes: [64], overrides: { waveType: WAVE.SAWTOOTH, pan: -0.7, panEnd: 0.7, lfoFreq: 7, lfoDepth: 10 } },
|
|
353
310
|
{ rest: true },
|
|
354
|
-
{
|
|
311
|
+
{ notes: [67], duration: 1, overrides: { volume: 0.75 } }
|
|
355
312
|
]
|
|
356
313
|
})
|
|
357
314
|
```
|
|
@@ -359,51 +316,37 @@ synth.playPattern({
|
|
|
359
316
|
## Noise percussion
|
|
360
317
|
|
|
361
318
|
```javascript
|
|
362
|
-
synth.
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
waveType: WAVE.NOISE,
|
|
319
|
+
synth.setTempo({ bpm: 116 })
|
|
320
|
+
synth.playSequence({
|
|
321
|
+
timeUnit: 'beats',
|
|
322
|
+
stepDuration: 0.25,
|
|
323
|
+
voice: { volume: 0.32, waveType: WAVE.NOISE },
|
|
367
324
|
steps: [
|
|
368
|
-
{
|
|
325
|
+
{ frequencies: [200], overrides: { attack: 1, decay: 70, sustain: 0, release: 60 } },
|
|
369
326
|
{ rest: true },
|
|
370
|
-
{
|
|
371
|
-
{
|
|
327
|
+
{ frequencies: [200], overrides: { attack: 1, decay: 32, sustain: 0, release: 25 } },
|
|
328
|
+
{ frequencies: [200], overrides: { attack: 1, decay: 32, sustain: 0, release: 25 } },
|
|
372
329
|
{ rest: true },
|
|
373
|
-
{
|
|
330
|
+
{ frequencies: [200], overrides: { attack: 1, decay: 52, sustain: 0, release: 44 } }
|
|
374
331
|
]
|
|
375
332
|
})
|
|
376
333
|
```
|
|
377
334
|
|
|
378
|
-
The steps retain the sixteenth-note grid. Short decay with `sustain: 0` makes
|
|
379
|
-
each hit settle to silence before its step ends, without changing that grid.
|
|
380
|
-
Every sounding step needs `frequency` or `note`, including a noise step. Do not
|
|
381
|
-
write a primitive step such as `200`; primitive steps return
|
|
382
|
-
`invalid_step_type`.
|
|
335
|
+
The steps retain the sixteenth-note grid. Short decay with `sustain: 0` makes each hit settle to silence before its step ends, without changing that grid. Every sounding step needs `frequencies` or `notes`, including a noise step. Do not write a primitive step such as `200`; primitive steps reject the complete publication.
|
|
383
336
|
|
|
384
337
|
## Xylophone sketch
|
|
385
338
|
|
|
386
339
|
```javascript
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
waveType: WAVE.TRIANGLE,
|
|
395
|
-
pan: pan
|
|
396
|
-
})
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
playBar('C5', -0.7)
|
|
400
|
-
setTimeout(function () { playBar('E5', -0.2) }, 130)
|
|
401
|
-
setTimeout(function () { playBar('G5', 0.3) }, 260)
|
|
402
|
-
setTimeout(function () { playBar('C6', 0.75) }, 390)
|
|
340
|
+
synth.playSequence({ timeUnit: 'ms', stepDuration: 130,
|
|
341
|
+
voice: { attack: 2, release: 430, volume: 0.62, waveType: WAVE.TRIANGLE },
|
|
342
|
+
steps: [{ notes: [72], length: 90, overrides: { pan: -0.7 } },
|
|
343
|
+
{ notes: [76], length: 90, overrides: { pan: -0.2 } },
|
|
344
|
+
{ notes: [79], length: 90, overrides: { pan: 0.3 } },
|
|
345
|
+
{ notes: [84], length: 90, overrides: { pan: 0.75 } }]
|
|
346
|
+
})
|
|
403
347
|
```
|
|
404
348
|
|
|
405
|
-
|
|
406
|
-
headroom in `volume` and choose enough `maxVoices` for the tails.
|
|
349
|
+
Native attacks are 130 ms apart. Each note releases after 90 ms and its 430 ms tail overlaps later strikes. Leave headroom and voice capacity for those tails.
|
|
407
350
|
|
|
408
351
|
## Simon-style pads
|
|
409
352
|
|
|
@@ -436,9 +379,7 @@ function playAllPads () {
|
|
|
436
379
|
|
|
437
380
|
## Pluck and electric piano
|
|
438
381
|
|
|
439
|
-
`decay` and `sustain`
|
|
440
|
-
adds an FM index that falls with the level, so the attack is bright and the
|
|
441
|
-
tail is mellow.
|
|
382
|
+
`decay` and `sustain` shape the tone into a plucked or struck sound. The electric piano also lowers the FM index as the level falls, giving it a bright attack and a mellow tail.
|
|
442
383
|
|
|
443
384
|
```javascript
|
|
444
385
|
function pluck (note) {
|
|
@@ -489,94 +430,45 @@ synth.playTone({
|
|
|
489
430
|
})
|
|
490
431
|
```
|
|
491
432
|
|
|
492
|
-
A fractional `fmRatio` puts the overtones between harmonics, which reads as
|
|
493
|
-
metal. `fmDepthEnd: 0` lets the brightness die away completely.
|
|
433
|
+
A fractional `fmRatio` puts the overtones between harmonics, which reads as metal. `fmDepthEnd: 0` lets the brightness die away completely.
|
|
494
434
|
|
|
495
435
|
## Wah and filtered laser
|
|
496
436
|
|
|
497
437
|
```javascript
|
|
498
|
-
synth.
|
|
499
|
-
|
|
500
|
-
duration:
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
filterHz: 350,
|
|
507
|
-
filterHzEnd: 2400,
|
|
508
|
-
filterQ: 5
|
|
438
|
+
synth.playSequence({ timeUnit: 'ms',
|
|
439
|
+
voice: { waveType: WAVE.SAWTOOTH },
|
|
440
|
+
steps: [{ notes: [45], duration: 1300, length: 800,
|
|
441
|
+
overrides: { attack: 10, release: 200, volume: 0.5,
|
|
442
|
+
filterType: 'bandpass', filterHz: 350, filterHzEnd: 2400, filterQ: 5 } },
|
|
443
|
+
{ frequencies: [1600], duration: 340, length: 250,
|
|
444
|
+
overrides: { frequencyEnd: 160, attack: 2, release: 90, volume: 0.4,
|
|
445
|
+
filterType: 'lowpass', filterHz: 7000, filterHzEnd: 500, filterQ: 4 } }]
|
|
509
446
|
})
|
|
510
|
-
|
|
511
|
-
setTimeout(function () {
|
|
512
|
-
synth.playTone({
|
|
513
|
-
frequency: 1600,
|
|
514
|
-
frequencyEnd: 160,
|
|
515
|
-
duration: 340,
|
|
516
|
-
attack: 2,
|
|
517
|
-
release: 90,
|
|
518
|
-
volume: 0.4,
|
|
519
|
-
waveType: WAVE.SAWTOOTH,
|
|
520
|
-
filterType: 'lowpass',
|
|
521
|
-
filterHz: 7000,
|
|
522
|
-
filterHzEnd: 500,
|
|
523
|
-
filterQ: 4
|
|
524
|
-
})
|
|
525
|
-
}, 1300)
|
|
526
447
|
```
|
|
527
448
|
|
|
528
|
-
|
|
449
|
+
Each sweep reaches its destination at `length`, then holds there through release. Intervals and note lengths remain fixed in milliseconds when the global tempo changes.
|
|
529
450
|
|
|
530
451
|
## Kick and hi-hat in one pattern
|
|
531
452
|
|
|
532
453
|
Each step can carry its own envelope and filter.
|
|
533
454
|
|
|
534
455
|
```javascript
|
|
535
|
-
synth.
|
|
536
|
-
|
|
537
|
-
|
|
456
|
+
synth.setTempo({ bpm: 110 })
|
|
457
|
+
synth.playSequence({
|
|
458
|
+
timeUnit: 'beats',
|
|
459
|
+
stepDuration: 0.5,
|
|
538
460
|
steps: [
|
|
539
|
-
{
|
|
540
|
-
|
|
541
|
-
frequencyEnd: 42,
|
|
542
|
-
noteValue: '4n',
|
|
543
|
-
attack: 1,
|
|
544
|
-
decay: 140,
|
|
545
|
-
sustain: 0.3,
|
|
546
|
-
release: 120,
|
|
547
|
-
volume: 0.85
|
|
548
|
-
},
|
|
549
|
-
{
|
|
550
|
-
frequency: 440,
|
|
551
|
-
waveType: WAVE.NOISE,
|
|
552
|
-
attack: 1,
|
|
553
|
-
decay: 30,
|
|
554
|
-
sustain: 0.25,
|
|
555
|
-
release: 45,
|
|
556
|
-
volume: 0.45,
|
|
557
|
-
filterType: 'highpass',
|
|
558
|
-
filterHz: 7000
|
|
559
|
-
},
|
|
461
|
+
{ frequencies: [150], duration: 1, overrides: { frequencyEnd: 42, attack: 1, decay: 140, sustain: 0.3, release: 120, volume: 0.85 } },
|
|
462
|
+
{ frequencies: [440], overrides: { waveType: WAVE.NOISE, attack: 1, decay: 30, sustain: 0.25, release: 45, volume: 0.45, filterType: 'highpass', filterHz: 7000 } },
|
|
560
463
|
{ rest: true },
|
|
561
|
-
{
|
|
562
|
-
frequency: 440,
|
|
563
|
-
waveType: WAVE.NOISE,
|
|
564
|
-
attack: 1,
|
|
565
|
-
decay: 30,
|
|
566
|
-
sustain: 0.25,
|
|
567
|
-
release: 45,
|
|
568
|
-
volume: 0.45,
|
|
569
|
-
filterType: 'highpass',
|
|
570
|
-
filterHz: 7000
|
|
571
|
-
}
|
|
464
|
+
{ frequencies: [440], overrides: { waveType: WAVE.NOISE, attack: 1, decay: 30, sustain: 0.25, release: 45, volume: 0.45, filterType: 'highpass', filterHz: 7000 } }
|
|
572
465
|
]
|
|
573
466
|
})
|
|
574
467
|
```
|
|
575
468
|
|
|
576
469
|
## Detuned chords
|
|
577
470
|
|
|
578
|
-
Repeat a pitch with small offsets in `detunes` to make it beat and widen. Two
|
|
579
|
-
copies 12 cents apart at 440 Hz beat about three times a second.
|
|
471
|
+
Repeat a pitch with small offsets in `detunes` to make it beat and widen. Two copies 12 cents apart at 440 Hz beat about three times a second.
|
|
580
472
|
|
|
581
473
|
```javascript
|
|
582
474
|
synth.playChord({
|
|
@@ -589,8 +481,8 @@ synth.playChord({
|
|
|
589
481
|
waveType: WAVE.SINE
|
|
590
482
|
})
|
|
591
483
|
|
|
592
|
-
|
|
593
|
-
|
|
484
|
+
// Alternative voicing:
|
|
485
|
+
synth.playChord({
|
|
594
486
|
notes: ['A3', 'E4', 'A3', 'E4', 'A3', 'E4'],
|
|
595
487
|
detunes: [-9, -9, 0, 0, 9, 9],
|
|
596
488
|
duration: 3200,
|
|
@@ -601,53 +493,34 @@ setTimeout(function () {
|
|
|
601
493
|
filterType: 'lowpass',
|
|
602
494
|
filterHz: 1500,
|
|
603
495
|
panSpread: 0.8
|
|
604
|
-
|
|
605
|
-
}, 2400)
|
|
496
|
+
})
|
|
606
497
|
```
|
|
607
498
|
|
|
608
|
-
Each repeated pitch is a voice. The second chord needs `maxVoices` of at least
|
|
609
|
-
6.
|
|
499
|
+
Each repeated pitch is a voice. The second chord needs `maxVoices` of at least 6.
|
|
610
500
|
|
|
611
|
-
## Chain
|
|
501
|
+
## Chain sequences with `sequenceend`
|
|
612
502
|
|
|
613
|
-
|
|
614
|
-
var jingles = [
|
|
615
|
-
[{ note: 'C5' }, { note: 'E5' }, { note: 'G5' }],
|
|
616
|
-
[{ note: 'G5' }, { note: 'E5' }, { note: 'C5' }]
|
|
617
|
-
]
|
|
618
|
-
var nextJingle = 0
|
|
619
|
-
|
|
620
|
-
function playNextJingle () {
|
|
621
|
-
if (nextJingle >= jingles.length) return false
|
|
622
|
-
return synth.playPattern({
|
|
623
|
-
noteValue: '8n',
|
|
624
|
-
attack: 5,
|
|
625
|
-
release: 60,
|
|
626
|
-
volume: 0.5,
|
|
627
|
-
waveType: WAVE.SQUARE,
|
|
628
|
-
steps: jingles[nextJingle++]
|
|
629
|
-
})
|
|
630
|
-
}
|
|
503
|
+
Use one sequence containing all steps for uninterrupted, sample-clock phrasing. The asynchronous completion event is useful for presentation or launching an unrelated cue:
|
|
631
504
|
|
|
632
|
-
|
|
633
|
-
|
|
505
|
+
```javascript
|
|
506
|
+
var jingleId = synth.playSequence({
|
|
507
|
+
stepDuration: 0.5,
|
|
508
|
+
voice: { attack: 5, release: 60, volume: 0.5, waveType: WAVE.SQUARE },
|
|
509
|
+
steps: [{ notes: [72] }, { notes: [76] }, { notes: [79] }]
|
|
510
|
+
})
|
|
511
|
+
function onSequenceEnd (event) {
|
|
512
|
+
if (event.sequenceId === jingleId && event.reason === 'completed') Ti.API.info('Jingle scheduled to completion')
|
|
634
513
|
}
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
// When the audio owner closes:
|
|
640
|
-
synth.removeEventListener('patternend', onPatternEnd)
|
|
514
|
+
synth.addEventListener('sequenceend', onSequenceEnd)
|
|
515
|
+
// When the owner closes:
|
|
516
|
+
synth.removeEventListener('sequenceend', onSequenceEnd)
|
|
641
517
|
```
|
|
642
518
|
|
|
643
|
-
|
|
644
|
-
one, so a listener that only chains on `completed: true` never double-starts.
|
|
519
|
+
A positive identifier acknowledges publication; 0 rejects the complete operation. Sequence completion does not guarantee audible silence: release envelopes and effect tails can continue.
|
|
645
520
|
|
|
646
521
|
## Rules across keys
|
|
647
522
|
|
|
648
|
-
Some combinations are rejected even when every value is in range. This call
|
|
649
|
-
returns `false` with `sustain_without_decay`, because a sustain below 1 with no
|
|
650
|
-
decay would jump in level and click:
|
|
523
|
+
Some combinations are rejected even when every value is in range. This call returns `false` with `sustain_without_decay`, because a sustain below 1 with no decay would jump in level and click:
|
|
651
524
|
|
|
652
525
|
```javascript
|
|
653
526
|
// Rejected on purpose: sustain needs a decay.
|
|
@@ -660,7 +533,7 @@ synth.playTone({ note: 'A4', decay: 200, sustain: 0.5, duration: 800 })
|
|
|
660
533
|
## Speaker-safe startup
|
|
661
534
|
|
|
662
535
|
```javascript
|
|
663
|
-
var accepted = synth.
|
|
536
|
+
var accepted = synth.start({
|
|
664
537
|
maxVoices: 12,
|
|
665
538
|
mixingProfile: 'speakerSafe'
|
|
666
539
|
})
|
|
@@ -668,9 +541,7 @@ var accepted = synth.startEngine({
|
|
|
668
541
|
if (accepted) synth.setVolume({ volume: 0.85 })
|
|
669
542
|
```
|
|
670
543
|
|
|
671
|
-
This profile lowers source gain and the limiter ceiling. It cannot repair a
|
|
672
|
-
speaker that physically struggles with a very low pitch, so test the real
|
|
673
|
-
device and raise the pitch when needed.
|
|
544
|
+
This profile lowers source gain and the limiter ceiling. It cannot repair a speaker that physically struggles with a very low pitch, so test the real device and raise the pitch when needed.
|
|
674
545
|
|
|
675
546
|
## Validation at an input boundary
|
|
676
547
|
|
|
@@ -686,9 +557,7 @@ function playUserFrequency (input) {
|
|
|
686
557
|
}
|
|
687
558
|
```
|
|
688
559
|
|
|
689
|
-
The native contract rejects
|
|
690
|
-
the app lets you give the user a specific message before the call reaches the
|
|
691
|
-
module.
|
|
560
|
+
The native contract rejects invalid values without clamping them. Validation in the app lets you give the user a specific message before the call reaches the module.
|
|
692
561
|
|
|
693
562
|
## Stop and clean up
|
|
694
563
|
|
|
@@ -699,14 +568,13 @@ synth.stopAll()
|
|
|
699
568
|
synth.shutdown()
|
|
700
569
|
```
|
|
701
570
|
|
|
702
|
-
`stopAll()` fades current voices
|
|
703
|
-
`shutdown()` cancels the scheduler and releases the native stream.
|
|
571
|
+
`stopAll()` stops all native sequences, fades current voices and invalidates effect histories. `shutdown()` also releases the native stream. To stop only one sequence owner, use `stopSequence({ sequenceId })`.
|
|
704
572
|
|
|
705
|
-
|
|
573
|
+
Follow the [interactive demo setup and test checklist](../assets/example/README.md) to run [`example/app.js`](../assets/example/app.js). It includes headphone positioning, session selection, pattern completion/replacement and all three statistics methods. For a service-level statistics recipe, see [read engine statistics](guide.md#read-engine-statistics).
|
|
706
574
|
|
|
707
575
|
## Positioned headphone effect
|
|
708
576
|
|
|
709
|
-
|
|
577
|
+
With the engine running, check the installed coordinate limits. This example places one generated noise effect above and to the right. Other sound calls keep their existing placement:
|
|
710
578
|
|
|
711
579
|
```javascript
|
|
712
580
|
if (!contract.limits.spatialX || !contract.limits.spatialY) {
|
|
@@ -725,3 +593,5 @@ if (!synth.playTone({
|
|
|
725
593
|
```
|
|
726
594
|
|
|
727
595
|
For app switches, amplitude sliders, all nine screen positions and routing multiple effects through one service, use the [binaural integration guide](guide.md#integrate-binaural-in-a-2d-app). Omitting both coordinates disables binaural for that event; setting both to zero keeps it enabled at the front center.
|
|
596
|
+
|
|
597
|
+
Continue with [advanced examples](advanced-examples.md).
|
|
Binary file
|
|
Binary file
|