@maccesar/titools 5.1.1 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -12
- package/agents/ti-pro.md +4 -0
- package/commands/ti-audit.md +4 -0
- package/lib/config.js +2 -0
- package/package.json +1 -1
- package/skills/ti-admob-unified/SKILL.md +44 -0
- package/skills/ti-admob-unified/agents/openai.yaml +4 -0
- package/skills/ti-admob-unified/assets/example/app.js +1003 -0
- package/skills/ti-admob-unified/assets/example/lib/ads.js +618 -0
- package/skills/ti-admob-unified/assets/example/library-usage.js +104 -0
- package/skills/ti-admob-unified/references/api-reference.md +592 -0
- package/skills/ti-admob-unified/references/banners.md +435 -0
- package/skills/ti-admob-unified/references/contributing.md +228 -0
- package/skills/ti-admob-unified/references/dependencies.md +85 -0
- package/skills/ti-admob-unified/references/fullscreen.md +223 -0
- package/skills/ti-admob-unified/references/game-monetization.md +17 -0
- package/skills/ti-admob-unified/references/getting-started.md +275 -0
- package/skills/ti-admob-unified/references/index.md +30 -0
- package/skills/ti-admob-unified/references/integration.md +85 -0
- package/skills/ti-admob-unified/references/library.md +189 -0
- package/skills/ti-admob-unified/references/mediation.md +132 -0
- package/skills/ti-admob-unified/references/migration.md +255 -0
- package/skills/ti-admob-unified/references/module-changelog.md +54 -0
- package/skills/ti-admob-unified/references/module-license.txt +21 -0
- package/skills/ti-admob-unified/references/privacy.md +254 -0
- package/skills/ti-admob-unified/references/roadmap.md +146 -0
- package/skills/ti-admob-unified/references/source-notes.md +33 -0
- package/skills/ti-admob-unified/references/source-snapshot.json +440 -0
- package/skills/ti-admob-unified/references/third-party-notices.md +22 -0
- package/skills/ti-game/SKILL.md +10 -1
- package/skills/ti-game/references/api.md +10 -2
- package/skills/ti-game/references/debugging-performance.md +6 -0
- package/skills/ti-game/references/examples.md +11 -1
- package/skills/ti-game/references/patterns.md +24 -2
- package/skills/ti-game/references/physics.md +502 -0
- package/skills/ti-game/references/project-setup.md +23 -1
- package/skills/ti-game/references/recipes-action.md +46 -14
- package/skills/ti-game/references/recipes-adventure-effects.md +12 -1
- package/skills/ti-game/references/roadmap.md +2 -2
- package/skills/ti-game/references/tilemaps.md +2 -1
- package/skills/ti-game-assets/SKILL.md +53 -0
- package/skills/ti-game-assets/agents/openai.yaml +4 -0
- package/skills/ti-game-assets/references/alpha.md +26 -0
- package/skills/ti-game-assets/references/art-direction.md +37 -0
- package/skills/ti-game-assets/references/integration.md +49 -0
- package/skills/ti-game-assets/references/manifest.example.json +429 -0
- package/skills/ti-game-assets/references/manifest.md +39 -0
- package/skills/ti-game-assets/references/offline-audio.md +33 -0
- package/skills/ti-game-assets/references/prompts.md +33 -0
- package/skills/ti-game-assets/references/repeating-textures.md +17 -0
- package/skills/ti-game-assets/references/responsible-ads.md +31 -0
- package/skills/ti-game-assets/references/sound-assets.md +42 -0
- package/skills/ti-game-assets/references/vector-sources.md +21 -0
- package/skills/ti-game-assets/scripts/alpha_tools.py +160 -0
- package/skills/ti-game-assets/scripts/requirements.txt +1 -0
- package/skills/ti-game-assets/scripts/validate_manifest.py +267 -0
- package/skills/ti-synthengine/SKILL.md +37 -13
- package/skills/ti-synthengine/references/api.md +397 -31
- package/skills/ti-synthengine/references/audio-engine.md +235 -14
- package/skills/ti-synthengine/references/examples.md +396 -17
- package/skills/ti-synthengine/references/guide.md +331 -12
- package/skills/ti-synthengine/references/recipes.md +212 -22
- package/skills/ti-synthengine/references/recommendations.md +53 -16
- package/skills/ti-synthengine/references/sound-design.md +359 -15
- package/skills/ti-synthengine/references/source-notes.md +121 -0
- package/skills/ti-synthengine/references/source-snapshot.json +105 -0
- package/skills/ti-synthengine/references/stats-performance.json +2992 -0
- package/skills/ti-synthengine/references/stats-performance.md +38 -0
- package/skills/ti-synthengine/references/troubleshooting.md +61 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
> Source snapshot: official TiSynthEngine 1.0.0 documentation
|
|
1
|
+
> Source snapshot: official TiSynthEngine 1.0.0 beta documentation from the reviewed working tree based on `95901c98af5353b86d9dc7c60b29ab9186b038cd` (2026-10-14), including uncommitted statistics changes. Upstream `documentation/examples.md` SHA-256: `53a8bd95215cc24a35776edb8686fa0d60c5399be0b4ff2685eee1563738f6cb`.
|
|
2
2
|
|
|
3
3
|
# Examples
|
|
4
4
|
|
|
@@ -19,7 +19,12 @@ if (contract.apiVersion !== '1.0.0') {
|
|
|
19
19
|
## Contents
|
|
20
20
|
|
|
21
21
|
- [Start once after layout](#start-once-after-layout)
|
|
22
|
-
- [
|
|
22
|
+
- [Built-in waveforms](#built-in-waveforms)
|
|
23
|
+
- [Variable-rate filtered noise](#variable-rate-filtered-noise)
|
|
24
|
+
- [Pulse-width sweep](#pulse-width-sweep)
|
|
25
|
+
- [Stepped wavetable](#stepped-wavetable)
|
|
26
|
+
- [Fixed controls on a chord](#fixed-controls-on-a-chord)
|
|
27
|
+
- [Wave-shaping pattern overrides](#wave-shaping-pattern-overrides)
|
|
23
28
|
- [Pitch sweep and pan movement](#pitch-sweep-and-pan-movement)
|
|
24
29
|
- [Vibrato](#vibrato)
|
|
25
30
|
- [Chord with an even spread](#chord-with-an-even-spread)
|
|
@@ -30,9 +35,17 @@ if (contract.apiVersion !== '1.0.0') {
|
|
|
30
35
|
- [Noise percussion](#noise-percussion)
|
|
31
36
|
- [Xylophone sketch](#xylophone-sketch)
|
|
32
37
|
- [Simon-style pads](#simon-style-pads)
|
|
38
|
+
- [Pluck and electric piano](#pluck-and-electric-piano)
|
|
39
|
+
- [Bell](#bell)
|
|
40
|
+
- [Wah and filtered laser](#wah-and-filtered-laser)
|
|
41
|
+
- [Kick and hi-hat in one pattern](#kick-and-hi-hat-in-one-pattern)
|
|
42
|
+
- [Detuned chords](#detuned-chords)
|
|
43
|
+
- [Chain patterns with `patternend`](#chain-patterns-with-patternend)
|
|
44
|
+
- [Rules across keys](#rules-across-keys)
|
|
33
45
|
- [Speaker-safe startup](#speaker-safe-startup)
|
|
34
46
|
- [Validation at an input boundary](#validation-at-an-input-boundary)
|
|
35
47
|
- [Stop and clean up](#stop-and-clean-up)
|
|
48
|
+
- [Positioned headphone effect](#positioned-headphone-effect)
|
|
36
49
|
|
|
37
50
|
<!-- TOC-END -->
|
|
38
51
|
|
|
@@ -65,7 +78,7 @@ win.addEventListener('close', cleanup)
|
|
|
65
78
|
win.open()
|
|
66
79
|
```
|
|
67
80
|
|
|
68
|
-
##
|
|
81
|
+
## Built-in waveforms
|
|
69
82
|
|
|
70
83
|
```javascript
|
|
71
84
|
var names = ['SINE', 'SQUARE', 'SAWTOOTH', 'TRIANGLE', 'NOISE']
|
|
@@ -86,6 +99,121 @@ names.forEach(function (name, index) {
|
|
|
86
99
|
|
|
87
100
|
Noise ignores pitch, but `note` keeps the event shape valid.
|
|
88
101
|
|
|
102
|
+
## Variable-rate filtered noise
|
|
103
|
+
|
|
104
|
+
```javascript
|
|
105
|
+
synth.playTone({
|
|
106
|
+
frequency: 100,
|
|
107
|
+
duration: 760,
|
|
108
|
+
attack: 1,
|
|
109
|
+
release: 580,
|
|
110
|
+
volume: 0.65,
|
|
111
|
+
waveType: WAVE.NOISE,
|
|
112
|
+
noiseRate: 12000,
|
|
113
|
+
noiseRateEnd: 600,
|
|
114
|
+
lowPassHz: 2400,
|
|
115
|
+
bitDepth: 8
|
|
116
|
+
})
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`noiseRate` starts at 12 kHz and falls to 600 Hz. `lowPassHz` removes high
|
|
120
|
+
frequency energy after the 8-bit source quantizer.
|
|
121
|
+
|
|
122
|
+
## Pulse-width sweep
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
synth.playTone({
|
|
126
|
+
note: 'A3',
|
|
127
|
+
duration: 700,
|
|
128
|
+
attack: 3,
|
|
129
|
+
release: 180,
|
|
130
|
+
volume: 0.55,
|
|
131
|
+
waveType: WAVE.SQUARE,
|
|
132
|
+
pulseWidth: 0.1,
|
|
133
|
+
pulseWidthEnd: 0.86
|
|
134
|
+
})
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The square duty cycle moves from 10 percent to 86 percent over the event.
|
|
138
|
+
|
|
139
|
+
## Stepped wavetable
|
|
140
|
+
|
|
141
|
+
```javascript
|
|
142
|
+
synth.playTone({
|
|
143
|
+
note: 'D4',
|
|
144
|
+
duration: 650,
|
|
145
|
+
attack: 4,
|
|
146
|
+
release: 220,
|
|
147
|
+
volume: 0.58,
|
|
148
|
+
waveType: WAVE.WAVETABLE,
|
|
149
|
+
waveTable: [-1, -0.7, -0.1, 0.8, 1, 0.35, -0.25, -0.55],
|
|
150
|
+
bitDepth: 8
|
|
151
|
+
})
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
The table repeats as a stepped cycle. `bitDepth: 8` quantizes each table value
|
|
155
|
+
before filtering and the amplitude envelope.
|
|
156
|
+
|
|
157
|
+
## Fixed controls on a chord
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
synth.playChord({
|
|
161
|
+
notes: ['A3', 'E4', 'A4'],
|
|
162
|
+
duration: 900,
|
|
163
|
+
attack: 8,
|
|
164
|
+
release: 220,
|
|
165
|
+
volume: 0.5,
|
|
166
|
+
waveType: WAVE.SQUARE,
|
|
167
|
+
pulseWidth: 0.22,
|
|
168
|
+
lowPassHz: 3600,
|
|
169
|
+
bitDepth: 8,
|
|
170
|
+
pans: [-0.65, 0, 0.65]
|
|
171
|
+
})
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Chord voices share fixed shaping controls. Sweep fields such as
|
|
175
|
+
`pulseWidthEnd` and `noiseRateEnd` are not accepted by `playChord()`.
|
|
176
|
+
|
|
177
|
+
## Wave-shaping pattern overrides
|
|
178
|
+
|
|
179
|
+
```javascript
|
|
180
|
+
synth.playPattern({
|
|
181
|
+
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,
|
|
189
|
+
steps: [
|
|
190
|
+
{ frequency: 120, duration: 180, release: 150, noiseRateEnd: 800 },
|
|
191
|
+
{ rest: true, duration: 100 },
|
|
192
|
+
{
|
|
193
|
+
note: 'A3',
|
|
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
|
+
}
|
|
209
|
+
]
|
|
210
|
+
})
|
|
211
|
+
```
|
|
212
|
+
|
|
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`.
|
|
216
|
+
|
|
89
217
|
## Pitch sweep and pan movement
|
|
90
218
|
|
|
91
219
|
```javascript
|
|
@@ -166,37 +294,41 @@ synth.playPattern({
|
|
|
166
294
|
volume: 0.55,
|
|
167
295
|
waveType: WAVE.SQUARE,
|
|
168
296
|
steps: [
|
|
169
|
-
{ note: 'C4'
|
|
170
|
-
{ note: 'E4'
|
|
297
|
+
{ note: 'C4' },
|
|
298
|
+
{ note: 'E4' },
|
|
171
299
|
{ rest: true },
|
|
172
|
-
{ note: 'G4'
|
|
173
|
-
{ note: 'C5',
|
|
300
|
+
{ note: 'G4' },
|
|
301
|
+
{ note: 'C5', noteValue: '4n' }
|
|
174
302
|
]
|
|
175
303
|
})
|
|
176
304
|
```
|
|
177
305
|
|
|
178
|
-
|
|
179
|
-
that relationship. Keep it subtle unless the lurch is the intended effect.
|
|
306
|
+
Swing offsets scheduled starts without changing voice durations: positive swing delays even steps and advances odd steps (zero-based); negative swing reverses those offsets. Each offset is the swing value times that step's duration, and a start before the call time is clamped to zero. This can overlap voices. Keep it subtle unless the lurch is the intended effect.
|
|
180
307
|
|
|
181
308
|
## Millisecond pattern
|
|
182
309
|
|
|
183
310
|
```javascript
|
|
184
311
|
synth.playPattern({
|
|
185
|
-
stepDuration: 110,
|
|
186
312
|
pan: -0.4,
|
|
187
313
|
panEnd: 0.4,
|
|
188
314
|
waveType: WAVE.TRIANGLE,
|
|
189
315
|
steps: [
|
|
190
316
|
{ note: 'C5', duration: 90 },
|
|
317
|
+
{ rest: true, duration: 20 },
|
|
191
318
|
{ note: 'D5', duration: 90 },
|
|
319
|
+
{ rest: true, duration: 20 },
|
|
192
320
|
{ note: 'E5', duration: 90 },
|
|
321
|
+
{ rest: true, duration: 20 },
|
|
193
322
|
{ note: 'G5', duration: 180 }
|
|
194
323
|
]
|
|
195
324
|
})
|
|
196
325
|
```
|
|
197
326
|
|
|
198
|
-
`
|
|
199
|
-
|
|
327
|
+
Each `duration` sets both the voice length and the advance to the next step.
|
|
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.
|
|
200
332
|
|
|
201
333
|
## Step overrides
|
|
202
334
|
|
|
@@ -233,16 +365,18 @@ synth.playPattern({
|
|
|
233
365
|
volume: 0.32,
|
|
234
366
|
waveType: WAVE.NOISE,
|
|
235
367
|
steps: [
|
|
236
|
-
{ frequency: 200,
|
|
368
|
+
{ frequency: 200, attack: 1, decay: 70, sustain: 0, release: 60 },
|
|
237
369
|
{ rest: true },
|
|
238
|
-
{ frequency: 200,
|
|
239
|
-
{ frequency: 200,
|
|
370
|
+
{ frequency: 200, attack: 1, decay: 32, sustain: 0, release: 25 },
|
|
371
|
+
{ frequency: 200, attack: 1, decay: 32, sustain: 0, release: 25 },
|
|
240
372
|
{ rest: true },
|
|
241
|
-
{ frequency: 200,
|
|
373
|
+
{ frequency: 200, attack: 1, decay: 52, sustain: 0, release: 44 }
|
|
242
374
|
]
|
|
243
375
|
})
|
|
244
376
|
```
|
|
245
377
|
|
|
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.
|
|
246
380
|
Every sounding step needs `frequency` or `note`, including a noise step. Do not
|
|
247
381
|
write a primitive step such as `200`; primitive steps return
|
|
248
382
|
`invalid_step_type`.
|
|
@@ -300,6 +434,229 @@ function playAllPads () {
|
|
|
300
434
|
}
|
|
301
435
|
```
|
|
302
436
|
|
|
437
|
+
## Pluck and electric piano
|
|
438
|
+
|
|
439
|
+
`decay` and `sustain` turn a flat tone into an instrument. The electric piano
|
|
440
|
+
adds an FM index that falls with the level, so the attack is bright and the
|
|
441
|
+
tail is mellow.
|
|
442
|
+
|
|
443
|
+
```javascript
|
|
444
|
+
function pluck (note) {
|
|
445
|
+
return synth.playTone({
|
|
446
|
+
note: note,
|
|
447
|
+
duration: 900,
|
|
448
|
+
attack: 2,
|
|
449
|
+
decay: 260,
|
|
450
|
+
sustain: 0.18,
|
|
451
|
+
release: 380,
|
|
452
|
+
volume: 0.6,
|
|
453
|
+
waveType: WAVE.TRIANGLE
|
|
454
|
+
})
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function electricPiano (note) {
|
|
458
|
+
return synth.playTone({
|
|
459
|
+
note: note,
|
|
460
|
+
duration: 1800,
|
|
461
|
+
attack: 3,
|
|
462
|
+
decay: 700,
|
|
463
|
+
sustain: 0.3,
|
|
464
|
+
release: 600,
|
|
465
|
+
volume: 0.55,
|
|
466
|
+
waveType: WAVE.SINE,
|
|
467
|
+
fmRatio: 1,
|
|
468
|
+
fmDepth: 2.2,
|
|
469
|
+
fmDepthEnd: 0.25
|
|
470
|
+
})
|
|
471
|
+
}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
## Bell
|
|
475
|
+
|
|
476
|
+
```javascript
|
|
477
|
+
synth.playTone({
|
|
478
|
+
note: 'C5',
|
|
479
|
+
duration: 2600,
|
|
480
|
+
attack: 1,
|
|
481
|
+
decay: 2000,
|
|
482
|
+
sustain: 0.02,
|
|
483
|
+
release: 500,
|
|
484
|
+
volume: 0.5,
|
|
485
|
+
waveType: WAVE.SINE,
|
|
486
|
+
fmRatio: 3.5,
|
|
487
|
+
fmDepth: 4,
|
|
488
|
+
fmDepthEnd: 0
|
|
489
|
+
})
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
A fractional `fmRatio` puts the overtones between harmonics, which reads as
|
|
493
|
+
metal. `fmDepthEnd: 0` lets the brightness die away completely.
|
|
494
|
+
|
|
495
|
+
## Wah and filtered laser
|
|
496
|
+
|
|
497
|
+
```javascript
|
|
498
|
+
synth.playTone({
|
|
499
|
+
note: 'A2',
|
|
500
|
+
duration: 1000,
|
|
501
|
+
attack: 10,
|
|
502
|
+
release: 200,
|
|
503
|
+
volume: 0.5,
|
|
504
|
+
waveType: WAVE.SAWTOOTH,
|
|
505
|
+
filterType: 'bandpass',
|
|
506
|
+
filterHz: 350,
|
|
507
|
+
filterHzEnd: 2400,
|
|
508
|
+
filterQ: 5
|
|
509
|
+
})
|
|
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
|
+
```
|
|
527
|
+
|
|
528
|
+
The cutoff sweep spans the whole event, so a longer note sweeps more slowly.
|
|
529
|
+
|
|
530
|
+
## Kick and hi-hat in one pattern
|
|
531
|
+
|
|
532
|
+
Each step can carry its own envelope and filter.
|
|
533
|
+
|
|
534
|
+
```javascript
|
|
535
|
+
synth.playPattern({
|
|
536
|
+
bpm: 110,
|
|
537
|
+
noteValue: '8n',
|
|
538
|
+
steps: [
|
|
539
|
+
{
|
|
540
|
+
frequency: 150,
|
|
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
|
+
},
|
|
560
|
+
{ 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
|
+
}
|
|
572
|
+
]
|
|
573
|
+
})
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
## Detuned chords
|
|
577
|
+
|
|
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.
|
|
580
|
+
|
|
581
|
+
```javascript
|
|
582
|
+
synth.playChord({
|
|
583
|
+
frequencies: [440, 440],
|
|
584
|
+
detunes: [-6, 6],
|
|
585
|
+
duration: 2000,
|
|
586
|
+
attack: 200,
|
|
587
|
+
release: 600,
|
|
588
|
+
volume: 0.55,
|
|
589
|
+
waveType: WAVE.SINE
|
|
590
|
+
})
|
|
591
|
+
|
|
592
|
+
setTimeout(function () {
|
|
593
|
+
synth.playChord({
|
|
594
|
+
notes: ['A3', 'E4', 'A3', 'E4', 'A3', 'E4'],
|
|
595
|
+
detunes: [-9, -9, 0, 0, 9, 9],
|
|
596
|
+
duration: 3200,
|
|
597
|
+
attack: 700,
|
|
598
|
+
release: 1300,
|
|
599
|
+
volume: 0.5,
|
|
600
|
+
waveType: WAVE.SAWTOOTH,
|
|
601
|
+
filterType: 'lowpass',
|
|
602
|
+
filterHz: 1500,
|
|
603
|
+
panSpread: 0.8
|
|
604
|
+
})
|
|
605
|
+
}, 2400)
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
Each repeated pitch is a voice. The second chord needs `maxVoices` of at least
|
|
609
|
+
6.
|
|
610
|
+
|
|
611
|
+
## Chain patterns with `patternend`
|
|
612
|
+
|
|
613
|
+
```javascript
|
|
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
|
+
}
|
|
631
|
+
|
|
632
|
+
function onPatternEnd (event) {
|
|
633
|
+
if (event.completed) playNextJingle()
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
synth.addEventListener('patternend', onPatternEnd)
|
|
637
|
+
playNextJingle()
|
|
638
|
+
|
|
639
|
+
// When the audio owner closes:
|
|
640
|
+
synth.removeEventListener('patternend', onPatternEnd)
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
The event reports `completed: false` when another pattern replaces the running
|
|
644
|
+
one, so a listener that only chains on `completed: true` never double-starts.
|
|
645
|
+
|
|
646
|
+
## Rules across keys
|
|
647
|
+
|
|
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:
|
|
651
|
+
|
|
652
|
+
```javascript
|
|
653
|
+
// Rejected on purpose: sustain needs a decay.
|
|
654
|
+
var accepted = synth.playTone({ note: 'A4', sustain: 0.5 })
|
|
655
|
+
|
|
656
|
+
// Accepted: the same note with a decay.
|
|
657
|
+
synth.playTone({ note: 'A4', decay: 200, sustain: 0.5, duration: 800 })
|
|
658
|
+
```
|
|
659
|
+
|
|
303
660
|
## Speaker-safe startup
|
|
304
661
|
|
|
305
662
|
```javascript
|
|
@@ -345,4 +702,26 @@ synth.shutdown()
|
|
|
345
702
|
`stopAll()` fades current voices but leaves pending pattern scheduling alone.
|
|
346
703
|
`shutdown()` cancels the scheduler and releases the native stream.
|
|
347
704
|
|
|
348
|
-
The
|
|
705
|
+
The last committed interactive demo is in the upstream [`example/app.js`](https://github.com/macCesar/TiSynthEngine/blob/95901c98af5353b86d9dc7c60b29ab9186b038cd/example/app.js); that commit does not contain the pending statistics example. For additional retro effects, playable xylophone interaction, memory pads, layered polyphony and cancellable repetition, continue with [Curated sound and interaction recipes](recipes.md).
|
|
706
|
+
|
|
707
|
+
## Positioned headphone effect
|
|
708
|
+
|
|
709
|
+
Check the installed coordinate limits and keep the engine running. This JavaScript places one generated noise effect above and to the right; it does not change other sound calls:
|
|
710
|
+
|
|
711
|
+
```javascript
|
|
712
|
+
if (!contract.limits.spatialX || !contract.limits.spatialY) {
|
|
713
|
+
throw new Error('This installed module does not report binaural support')
|
|
714
|
+
}
|
|
715
|
+
if (!synth.playTone({
|
|
716
|
+
frequency: 90,
|
|
717
|
+
waveType: WAVE.NOISE,
|
|
718
|
+
duration: 500,
|
|
719
|
+
attack: 2,
|
|
720
|
+
release: 200,
|
|
721
|
+
volume: 0.3,
|
|
722
|
+
spatialX: 0.8,
|
|
723
|
+
spatialY: 0.75
|
|
724
|
+
})) Ti.API.warn('Positioned effect rejected')
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
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.
|