@maccesar/titools 5.1.0 → 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/purgetss/SKILL.md +4 -4
- package/skills/purgetss/references/EXAMPLES.md +3 -3
- package/skills/purgetss/references/adopting-purgetss.md +2 -2
- package/skills/purgetss/references/animation-advanced.md +2 -2
- package/skills/purgetss/references/arbitrary-values.md +8 -5
- package/skills/purgetss/references/class-categories.md +5 -5
- package/skills/purgetss/references/class-index-properties.md +6 -6
- package/skills/purgetss/references/class-index.md +2 -2
- package/skills/purgetss/references/cli-commands.md +2 -2
- package/skills/purgetss/references/dynamic-component-creation.md +2 -2
- package/skills/purgetss/references/grid-layout.md +1 -1
- package/skills/purgetss/references/migration-guide.md +34 -4
- package/skills/purgetss/references/multi-density-images.md +6 -6
- package/skills/purgetss/references/platform-modifiers.md +21 -0
- package/skills/purgetss/references/ui-ux-design.md +1 -1
- package/skills/purgetss/references/version-history.md +9 -4
- 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/sound-design.md` SHA-256: `4ccbb55b92879c59d20116aff942e16d431c619341b3d4714da4c50c3c691cf9`.
|
|
2
2
|
|
|
3
3
|
# Sound design with TiSynthEngine
|
|
4
4
|
|
|
@@ -19,9 +19,14 @@ var WAVE = synth.getDefaults().waveTypes
|
|
|
19
19
|
|
|
20
20
|
- [Notes, frequencies and octaves](#notes-frequencies-and-octaves)
|
|
21
21
|
- [Waveform and timbre](#waveform-and-timbre)
|
|
22
|
+
- [Filter, pulse width and quantization](#filter-pulse-width-and-quantization)
|
|
22
23
|
- [Envelope and total duration](#envelope-and-total-duration)
|
|
24
|
+
- [Decay and sustain](#decay-and-sustain)
|
|
23
25
|
- [Pan and movement](#pan-and-movement)
|
|
24
26
|
- [Vibrato and the LFO](#vibrato-and-the-lfo)
|
|
27
|
+
- [Resonant filter](#resonant-filter)
|
|
28
|
+
- [Frequency modulation](#frequency-modulation)
|
|
29
|
+
- [Detune](#detune)
|
|
25
30
|
- [Chords, polyphony and gain](#chords-polyphony-and-gain)
|
|
26
31
|
- [Mixing profiles and limiter](#mixing-profiles-and-limiter)
|
|
27
32
|
- [Speakers, headphones and devices](#speakers-headphones-and-devices)
|
|
@@ -105,7 +110,28 @@ melodies, pads and xylophone-like sketches.
|
|
|
105
110
|
changing that value does not tune the noise. A short envelope turns it into a
|
|
106
111
|
click, hat or impact layer; a long envelope creates wind or static.
|
|
107
112
|
|
|
108
|
-
|
|
113
|
+
`noiseRate` changes the source into variable-rate sample-and-hold noise. Zero
|
|
114
|
+
keeps the white-noise default. Lower rates hold each pseudo-random value longer
|
|
115
|
+
and sound grainier. `noiseRateEnd` moves the rate over the event.
|
|
116
|
+
|
|
117
|
+
### Wavetable
|
|
118
|
+
|
|
119
|
+
`WAVETABLE` repeats 2 to 64 values supplied in `waveTable`. Values range from
|
|
120
|
+
-1 to 1 and are read as steps, without interpolation. Short asymmetric tables
|
|
121
|
+
are useful for coarse DAC-like voices, buzzy radio tones and original retro
|
|
122
|
+
effects that do not fit the four built-in oscillator shapes.
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
synth.playTone({
|
|
126
|
+
note: 'D4',
|
|
127
|
+
duration: 600,
|
|
128
|
+
waveType: WAVE.WAVETABLE,
|
|
129
|
+
waveTable: [-1, -0.8, -0.1, 0.9, 0.45, 0.1, -0.25, -0.6],
|
|
130
|
+
bitDepth: 8
|
|
131
|
+
})
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Try the built-in sources at a moderate level before choosing one:
|
|
109
135
|
|
|
110
136
|
```javascript
|
|
111
137
|
;[WAVE.SINE, WAVE.SQUARE, WAVE.SAWTOOTH, WAVE.TRIANGLE, WAVE.NOISE]
|
|
@@ -123,6 +149,34 @@ Try every waveform at a moderate level before choosing one:
|
|
|
123
149
|
})
|
|
124
150
|
```
|
|
125
151
|
|
|
152
|
+
## Filter, pulse width and quantization
|
|
153
|
+
|
|
154
|
+
`lowPassHz` enables a per-voice one-pole low-pass filter. It is most obvious on
|
|
155
|
+
noise, square and sawtooth sources. Zero bypasses the filter. For resonance,
|
|
156
|
+
high-pass and band-pass shapes or a moving cutoff, use the
|
|
157
|
+
[resonant filter](#resonant-filter) below.
|
|
158
|
+
|
|
159
|
+
`pulseWidth` controls how much of each square-wave cycle stays high. The 0.5
|
|
160
|
+
default is a normal square. Values closer to 0.05 or 0.95 become thinner and
|
|
161
|
+
brighter. `pulseWidthEnd` creates a linear duty-cycle sweep.
|
|
162
|
+
|
|
163
|
+
```javascript
|
|
164
|
+
synth.playTone({
|
|
165
|
+
note: 'A3',
|
|
166
|
+
duration: 700,
|
|
167
|
+
release: 180,
|
|
168
|
+
waveType: WAVE.SQUARE,
|
|
169
|
+
pulseWidth: 0.1,
|
|
170
|
+
pulseWidthEnd: 0.86,
|
|
171
|
+
lowPassHz: 4200
|
|
172
|
+
})
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
`bitDepth` rounds the oscillator or noise amplitude to a fixed number of
|
|
176
|
+
levels before filtering. Values from 2 to 16 are accepted. Zero preserves the
|
|
177
|
+
floating-point signal. Quantization adds harmonic grit; it does not change the
|
|
178
|
+
audio device's output format.
|
|
179
|
+
|
|
126
180
|
## Envelope and total duration
|
|
127
181
|
|
|
128
182
|
Every event uses an attack, an implicit sustain section and a release:
|
|
@@ -153,6 +207,34 @@ release <= duration - attack
|
|
|
153
207
|
Defaults are adjusted internally if a very short duration leaves no room, but
|
|
154
208
|
values supplied by the caller are never reshaped silently.
|
|
155
209
|
|
|
210
|
+
## Decay and sustain
|
|
211
|
+
|
|
212
|
+
Plucked strings, struck keys and mallets start loud and settle. A flat
|
|
213
|
+
envelope cannot do that, so `decay` and `sustain` add a stage after the attack:
|
|
214
|
+
the level falls from full scale to `sustain` over `decay` milliseconds, then
|
|
215
|
+
holds until the release.
|
|
216
|
+
|
|
217
|
+
```text
|
|
218
|
+
decay: 0 flat tone, the default
|
|
219
|
+
decay: 260, sustain: 0.18 pluck: loud start, settles low
|
|
220
|
+
decay: 2000, sustain: 0.02 bell or mallet: fades by itself
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Practical starting regions:
|
|
224
|
+
|
|
225
|
+
- plucks and keys: attack 2 to 10 ms, decay 100 to 400 ms, sustain 0.1 to 0.4;
|
|
226
|
+
- struck percussion with a pitch drop: decay about half the duration, sustain
|
|
227
|
+
near 0.3;
|
|
228
|
+
- bells and mallets: decay over most of the duration, sustain near 0.
|
|
229
|
+
|
|
230
|
+
`sustain` below 1 needs a nonzero `decay`. Without one the level would jump
|
|
231
|
+
instantly, which clicks, so the call is rejected with `sustain_without_decay`.
|
|
232
|
+
|
|
233
|
+
The release scales the level the note has reached. If the release begins while
|
|
234
|
+
the decay is still running, the note leaves smoothly from that point. The
|
|
235
|
+
decay still has to fit: `attack` plus `decay` cannot exceed `duration`, and the
|
|
236
|
+
50 ms default attack counts. Set a short `attack` explicitly for a tight pluck.
|
|
237
|
+
|
|
156
238
|
## Pan and movement
|
|
157
239
|
|
|
158
240
|
`pan` ranges from -1 on the left to 1 on the right. Zero is centered. Stereo
|
|
@@ -209,12 +291,111 @@ A rate around 4 to 7 Hz with a small depth sounds like musical vibrato. A fast
|
|
|
209
291
|
rate or large depth becomes an effect. Because depth is measured in hertz, 8 Hz
|
|
210
292
|
is a larger musical interval on a low note than on a high note.
|
|
211
293
|
|
|
294
|
+
## Resonant filter
|
|
295
|
+
|
|
296
|
+
`filterType` adds a filter that removes or emphasizes part of the spectrum. It
|
|
297
|
+
has 12 dB per octave of slope, twice as steep as the one-pole `lowPassHz`
|
|
298
|
+
filter, and can be combined with it (`lowPassHz` runs first).
|
|
299
|
+
|
|
300
|
+
- `lowpass` darkens the sound. A sawtooth through a closing low-pass reads as a
|
|
301
|
+
zap or a sound moving away; an opening one reads as a swell.
|
|
302
|
+
- `highpass` thins the sound by removing body. It makes hats, hiss and tinny
|
|
303
|
+
effects out of noise.
|
|
304
|
+
- `bandpass` keeps one band around `filterHz`, which gives vocal, nasal and
|
|
305
|
+
wah-like colors.
|
|
306
|
+
|
|
307
|
+
Filters shape harmonics, so give them a source that has some: `SAWTOOTH`,
|
|
308
|
+
`SQUARE` and `NOISE` respond strongly. A sine has only its fundamental, so a
|
|
309
|
+
filter mostly changes its level.
|
|
310
|
+
|
|
311
|
+
`filterQ` is the resonance. The default 0.7071 is flat. Values from 2 to 4 add
|
|
312
|
+
character, and above about 6 the filter whistles around the cutoff. A low-pass
|
|
313
|
+
or high-pass boosts the cutoff region by about `filterQ`, so Q 10 is roughly
|
|
314
|
+
20 dB. Lower the event `volume` as Q goes up. The limiter catches peaks, but a
|
|
315
|
+
resonance that keeps hitting it makes the whole mix pump. The band-pass keeps
|
|
316
|
+
unity gain at its center for every Q and only narrows.
|
|
317
|
+
|
|
318
|
+
`filterHzEnd` moves the cutoff over the whole event. The motion is exponential,
|
|
319
|
+
so each second covers the same musical distance. Set it above `filterHz` to
|
|
320
|
+
open the filter and below to close it. Zero disables the sweep.
|
|
321
|
+
|
|
322
|
+
```javascript
|
|
323
|
+
synth.playTone({
|
|
324
|
+
note: 'A2',
|
|
325
|
+
duration: 1000,
|
|
326
|
+
attack: 10,
|
|
327
|
+
release: 200,
|
|
328
|
+
volume: 0.5,
|
|
329
|
+
waveType: WAVE.SAWTOOTH,
|
|
330
|
+
filterType: 'bandpass',
|
|
331
|
+
filterHz: 350,
|
|
332
|
+
filterHzEnd: 2400,
|
|
333
|
+
filterQ: 5
|
|
334
|
+
})
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## Frequency modulation
|
|
338
|
+
|
|
339
|
+
FM makes rich, bright and metallic sounds from a plain sine. A second sine, the
|
|
340
|
+
modulator, bends the pitch of the first one, the carrier. Turn it on with
|
|
341
|
+
`fmDepth` or `fmDepthEnd`, on a `SINE` voice.
|
|
342
|
+
|
|
343
|
+
- `fmRatio` is the modulator frequency as a multiple of the carrier's. Whole
|
|
344
|
+
numbers (1, 2, 3) keep the added overtones on the harmonic series, so the
|
|
345
|
+
pitch stays clear and the sound reads as organ- or piano-like. Fractional
|
|
346
|
+
ratios such as 1.4142 or 3.5 put the overtones between harmonics, which reads
|
|
347
|
+
as bells, glass and metal.
|
|
348
|
+
- `fmDepth` is the modulation index and works like a brightness control. Around
|
|
349
|
+
0.5 to 1.5 it warms a sine, 2 to 5 makes it bright and rich, and values near
|
|
350
|
+
10 get harsh.
|
|
351
|
+
- `fmDepthEnd` moves the index over the event. Starting high and ending low
|
|
352
|
+
gives a bright attack that mellows, which is the signature of electric pianos,
|
|
353
|
+
bells and mallets. Pair it with `decay` so the level falls with the brightness.
|
|
354
|
+
|
|
355
|
+
FM does not change the sine's amplitude, so gain staging is the same as for a
|
|
356
|
+
plain sine. There is no band-limiting: a high carrier with a large index and
|
|
357
|
+
ratio puts sidebands above the Nyquist frequency, where they alias into
|
|
358
|
+
inharmonic noise. Keep bell carriers modest, around 500 Hz, or lower the index.
|
|
359
|
+
|
|
360
|
+
## Detune
|
|
361
|
+
|
|
362
|
+
`detune` shifts a pitch by cents, hundredths of a semitone. Two tones a few
|
|
363
|
+
cents apart drift in and out of phase and beat at a rate close to
|
|
364
|
+
`frequency * (2 ^ (cents / 1200) - 1)`. A 12-cent gap at 440 Hz beats about
|
|
365
|
+
3 times a second. Slow beating (0.5 to 4 Hz) sounds warm and wide, like a
|
|
366
|
+
chorus; past about 20 cents it starts to sound out of tune.
|
|
367
|
+
|
|
368
|
+
On a single tone, `detune` just retunes it, which is handy for small variations
|
|
369
|
+
so a repeated effect does not sound identical. The effect comes from stacking
|
|
370
|
+
detuned copies. In a chord, give `detunes` one entry per pitch and repeat a
|
|
371
|
+
pitch to thicken it:
|
|
372
|
+
|
|
373
|
+
```javascript
|
|
374
|
+
synth.playChord({
|
|
375
|
+
frequencies: [440, 440],
|
|
376
|
+
detunes: [-6, 6],
|
|
377
|
+
duration: 2000,
|
|
378
|
+
attack: 200,
|
|
379
|
+
release: 600,
|
|
380
|
+
volume: 0.55,
|
|
381
|
+
waveType: WAVE.SINE
|
|
382
|
+
})
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Each repeated pitch is a voice, so size `maxVoices` for the full stack. Protected
|
|
386
|
+
profiles divide per-voice source gain by the square root of the event voice
|
|
387
|
+
count. This reduces buildup; it does not guarantee equal loudness. Correlated
|
|
388
|
+
voices can still reinforce each other, and detuned voices can produce peaks
|
|
389
|
+
as their phases align. `raw` does not apply this event normalization.
|
|
390
|
+
|
|
212
391
|
## Chords, polyphony and gain
|
|
213
392
|
|
|
214
393
|
`playChord` is for notes that should start together. The call is placed in the
|
|
215
394
|
native queue as one event, so the audio callback sees the whole chord or none
|
|
216
|
-
of it.
|
|
217
|
-
|
|
395
|
+
of it. In protected profiles, per-voice source gain is divided by the square
|
|
396
|
+
root of the chord's voice count. This approximately stabilizes power for
|
|
397
|
+
uncorrelated voices, not coherent copies; it does not guarantee constant peaks
|
|
398
|
+
or perceived loudness. `raw` bypasses this normalization.
|
|
218
399
|
|
|
219
400
|
```javascript
|
|
220
401
|
synth.playChord({
|
|
@@ -358,16 +539,18 @@ synth.playPattern({
|
|
|
358
539
|
volume: 0.5,
|
|
359
540
|
waveType: WAVE.SQUARE,
|
|
360
541
|
steps: [
|
|
361
|
-
{ note: 'C5'
|
|
362
|
-
{ note: 'E5'
|
|
363
|
-
{ note: 'G5'
|
|
364
|
-
{ note: 'C6',
|
|
542
|
+
{ note: 'C5' },
|
|
543
|
+
{ note: 'E5' },
|
|
544
|
+
{ note: 'G5' },
|
|
545
|
+
{ note: 'C6', noteValue: '8n' }
|
|
365
546
|
]
|
|
366
547
|
})
|
|
367
548
|
```
|
|
368
549
|
|
|
369
|
-
The
|
|
370
|
-
|
|
550
|
+
The first three steps use sixteenth notes and the last uses an eighth note.
|
|
551
|
+
`release` fades each voice within that rhythmic length. The pattern root does
|
|
552
|
+
not accept `duration`; a step `duration` replaces its rhythmic length as well
|
|
553
|
+
as its voice length. There is no separate gate parameter.
|
|
371
554
|
|
|
372
555
|
### Noise percussion
|
|
373
556
|
|
|
@@ -378,17 +561,179 @@ synth.playPattern({
|
|
|
378
561
|
waveType: WAVE.NOISE,
|
|
379
562
|
volume: 0.34,
|
|
380
563
|
steps: [
|
|
381
|
-
{ frequency: 220,
|
|
564
|
+
{ frequency: 220, attack: 1, decay: 65, sustain: 0, release: 55 },
|
|
382
565
|
{ rest: true },
|
|
383
|
-
{ frequency: 220,
|
|
384
|
-
{ frequency: 220,
|
|
566
|
+
{ frequency: 220, attack: 1, decay: 35, sustain: 0, release: 28 },
|
|
567
|
+
{ frequency: 220, attack: 1, decay: 35, sustain: 0, release: 28 }
|
|
385
568
|
]
|
|
386
569
|
})
|
|
387
570
|
```
|
|
388
571
|
|
|
572
|
+
The steps keep the eighth-note grid while short decay and `sustain: 0` let
|
|
573
|
+
each hit settle to silence inside its step.
|
|
574
|
+
|
|
389
575
|
Noise steps still need `frequency` or `note` because every sounding pattern
|
|
390
576
|
step follows the same shape. The pitch value is not used by the noise source.
|
|
391
577
|
|
|
578
|
+
### Filtered noise burst
|
|
579
|
+
|
|
580
|
+
```javascript
|
|
581
|
+
synth.playTone({
|
|
582
|
+
frequency: 120,
|
|
583
|
+
duration: 760,
|
|
584
|
+
attack: 1,
|
|
585
|
+
release: 580,
|
|
586
|
+
volume: 0.62,
|
|
587
|
+
waveType: WAVE.NOISE,
|
|
588
|
+
noiseRate: 12000,
|
|
589
|
+
noiseRateEnd: 650,
|
|
590
|
+
lowPassHz: 2500,
|
|
591
|
+
bitDepth: 8
|
|
592
|
+
})
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
The decreasing update rate makes the texture break into slower chunks while
|
|
596
|
+
the envelope removes energy. Reverse the two rates for an effect that becomes
|
|
597
|
+
more frantic.
|
|
598
|
+
|
|
599
|
+
### Pluck
|
|
600
|
+
|
|
601
|
+
```javascript
|
|
602
|
+
synth.playTone({
|
|
603
|
+
note: 'E4',
|
|
604
|
+
duration: 900,
|
|
605
|
+
attack: 2,
|
|
606
|
+
decay: 260,
|
|
607
|
+
sustain: 0.18,
|
|
608
|
+
release: 380,
|
|
609
|
+
volume: 0.6,
|
|
610
|
+
waveType: WAVE.TRIANGLE
|
|
611
|
+
})
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
### Electric piano
|
|
615
|
+
|
|
616
|
+
```javascript
|
|
617
|
+
synth.playTone({
|
|
618
|
+
note: 'E3',
|
|
619
|
+
duration: 1800,
|
|
620
|
+
attack: 3,
|
|
621
|
+
decay: 700,
|
|
622
|
+
sustain: 0.3,
|
|
623
|
+
release: 600,
|
|
624
|
+
volume: 0.55,
|
|
625
|
+
waveType: WAVE.SINE,
|
|
626
|
+
fmRatio: 1,
|
|
627
|
+
fmDepth: 2.2,
|
|
628
|
+
fmDepthEnd: 0.25
|
|
629
|
+
})
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
The index falls from 2.2 to 0.25 while the level settles, so the attack is
|
|
633
|
+
bright and the sustain is mellow.
|
|
634
|
+
|
|
635
|
+
### Bell
|
|
636
|
+
|
|
637
|
+
```javascript
|
|
638
|
+
synth.playTone({
|
|
639
|
+
note: 'C5',
|
|
640
|
+
duration: 2600,
|
|
641
|
+
attack: 1,
|
|
642
|
+
decay: 2000,
|
|
643
|
+
sustain: 0.02,
|
|
644
|
+
release: 500,
|
|
645
|
+
volume: 0.5,
|
|
646
|
+
waveType: WAVE.SINE,
|
|
647
|
+
fmRatio: 3.5,
|
|
648
|
+
fmDepth: 4,
|
|
649
|
+
fmDepthEnd: 0
|
|
650
|
+
})
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
The fractional ratio makes the overtones inharmonic. Try 1.4142 or 2.76 for a
|
|
654
|
+
different metal.
|
|
655
|
+
|
|
656
|
+
### Wah
|
|
657
|
+
|
|
658
|
+
The wah in [Resonant filter](#resonant-filter) is also a recipe. Reverse the
|
|
659
|
+
two cutoffs for a sound that closes instead of opening.
|
|
660
|
+
|
|
661
|
+
### Filtered laser
|
|
662
|
+
|
|
663
|
+
```javascript
|
|
664
|
+
synth.playTone({
|
|
665
|
+
frequency: 1600,
|
|
666
|
+
frequencyEnd: 160,
|
|
667
|
+
duration: 340,
|
|
668
|
+
attack: 2,
|
|
669
|
+
release: 90,
|
|
670
|
+
volume: 0.4,
|
|
671
|
+
waveType: WAVE.SAWTOOTH,
|
|
672
|
+
filterType: 'lowpass',
|
|
673
|
+
filterHz: 7000,
|
|
674
|
+
filterHzEnd: 500,
|
|
675
|
+
filterQ: 4
|
|
676
|
+
})
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
### Hi-hat
|
|
680
|
+
|
|
681
|
+
```javascript
|
|
682
|
+
synth.playTone({
|
|
683
|
+
duration: 80,
|
|
684
|
+
attack: 1,
|
|
685
|
+
decay: 30,
|
|
686
|
+
sustain: 0.25,
|
|
687
|
+
release: 45,
|
|
688
|
+
volume: 0.45,
|
|
689
|
+
waveType: WAVE.NOISE,
|
|
690
|
+
filterType: 'highpass',
|
|
691
|
+
filterHz: 7000
|
|
692
|
+
})
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
For an open hat, use `duration: 320`, `decay: 70` and `release: 220`.
|
|
696
|
+
|
|
697
|
+
### Thick pad
|
|
698
|
+
|
|
699
|
+
```javascript
|
|
700
|
+
synth.playChord({
|
|
701
|
+
notes: ['A3', 'E4', 'A3', 'E4', 'A3', 'E4'],
|
|
702
|
+
detunes: [-9, -9, 0, 0, 9, 9],
|
|
703
|
+
duration: 3200,
|
|
704
|
+
attack: 700,
|
|
705
|
+
release: 1300,
|
|
706
|
+
volume: 0.5,
|
|
707
|
+
waveType: WAVE.SAWTOOTH,
|
|
708
|
+
filterType: 'lowpass',
|
|
709
|
+
filterHz: 1500,
|
|
710
|
+
panSpread: 0.8
|
|
711
|
+
})
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
Six voices play two pitches, each in three slightly different tunings. The
|
|
715
|
+
low-pass takes the harshness off the sawtooth stack. Start the engine with
|
|
716
|
+
`maxVoices` of at least 6.
|
|
717
|
+
|
|
718
|
+
### Kick
|
|
719
|
+
|
|
720
|
+
```javascript
|
|
721
|
+
synth.playTone({
|
|
722
|
+
frequency: 150,
|
|
723
|
+
frequencyEnd: 42,
|
|
724
|
+
duration: 320,
|
|
725
|
+
attack: 1,
|
|
726
|
+
decay: 150,
|
|
727
|
+
sustain: 0.3,
|
|
728
|
+
release: 140,
|
|
729
|
+
volume: 0.85,
|
|
730
|
+
waveType: WAVE.SINE
|
|
731
|
+
})
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
The pitch drop is the punch and the decay is the thump. A phone speaker cannot
|
|
735
|
+
reproduce 42 Hz, so raise `frequencyEnd` toward 70 for speaker playback.
|
|
736
|
+
|
|
392
737
|
### Simon-style cues
|
|
393
738
|
|
|
394
739
|
Use short, distinct square-wave pitches. Play one tone for the sequence and
|
|
@@ -424,5 +769,4 @@ function playAllSimonPads () {
|
|
|
424
769
|
For more complete code, continue with [Examples](examples.md) and
|
|
425
770
|
[Curated sound and interaction recipes](recipes.md). The latter includes retro
|
|
426
771
|
effects, a playable xylophone, memory-pad timbres, layered chords and timer
|
|
427
|
-
ownership. For gain and device-testing advice, see
|
|
428
|
-
[Recommendations](recommendations.md).
|
|
772
|
+
ownership. For gain and device-testing advice, see [Recommendations](recommendations.md).
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Maintaining the synthesis snapshot
|
|
2
|
+
|
|
3
|
+
The eight official Markdown mirrors and raw statistics comparison are derived
|
|
4
|
+
from the reviewed TiSynthEngine working tree based on the commit in
|
|
5
|
+
[source-snapshot.json](source-snapshot.json). This snapshot includes uncommitted
|
|
6
|
+
native statistics methods, tests and documentation. The commit identifies the
|
|
7
|
+
base; it does not contain all reviewed content. `reviewed_worktree_sha256`
|
|
8
|
+
records the reviewed dirty-state fingerprint, including tracked differences
|
|
9
|
+
and untracked files. The checker verifies that fingerprint in addition to the
|
|
10
|
+
individual source/mirror hashes. A match establishes fidelity to that source
|
|
11
|
+
state; it does not establish that the source is correct, committed, published
|
|
12
|
+
or installed in an app. A different dirty fingerprint requires a fresh review.
|
|
13
|
+
Read the native contracts, command conversion and renderers when auditing
|
|
14
|
+
behavior. The maintainer workflow is `titools-skill-auditor` in this repository.
|
|
15
|
+
|
|
16
|
+
## Sources and permitted transformations
|
|
17
|
+
|
|
18
|
+
`api.md`, `audio-engine.md`, `examples.md`, `guide.md`, `recommendations.md`,
|
|
19
|
+
`sound-design.md`, `troubleshooting.md` and `stats-performance.md` mirror the
|
|
20
|
+
corresponding upstream `documentation/` files. `stats-performance.json` preserves
|
|
21
|
+
the complete raw trials without Markdown transformations. These nine assets
|
|
22
|
+
each record a full-source SHA-256 and final mirror SHA-256. Markdown provenance
|
|
23
|
+
headers identify the working tree, base commit and full-source hash.
|
|
24
|
+
|
|
25
|
+
Only these transformations are currently declared:
|
|
26
|
+
|
|
27
|
+
- A provenance header and generated `TOC-START`/`TOC-END` navigation.
|
|
28
|
+
- The upstream demo link in `examples.md` is rebased to the last committed
|
|
29
|
+
`example/app.js` at the base commit. Its label explicitly distinguishes that
|
|
30
|
+
demo from the pending statistics example in the reviewed working tree; a
|
|
31
|
+
GitHub commit link cannot expose uncommitted changes. It requires access to
|
|
32
|
+
the official module repository; the runnable app is not bundled here.
|
|
33
|
+
- `examples.md` and `sound-design.md` retain their TiTools links to
|
|
34
|
+
[curated recipes](recipes.md). These additions are recorded as reversible
|
|
35
|
+
`link_fixes`, with the complete original and mirrored Markdown fragments.
|
|
36
|
+
|
|
37
|
+
For Markdown mirrors, the snapshot test removes the header and generated
|
|
38
|
+
navigation, reverses those fragments, and checks the full original source hash.
|
|
39
|
+
The raw JSON is checked byte for byte. Update the declared
|
|
40
|
+
transformations when an intentional source-derived edit is reviewed; never
|
|
41
|
+
regenerate hashes merely to conceal an unexplained difference.
|
|
42
|
+
|
|
43
|
+
## Protected curated content
|
|
44
|
+
|
|
45
|
+
[recipes.md](recipes.md) is a TiTools contribution, not an official mirror.
|
|
46
|
+
Preserve its recipes, lifecycle patterns and navigation during synchronization.
|
|
47
|
+
Check every native option and envelope against the current contract. The
|
|
48
|
+
rhythm tests execute the Markdown examples and assert their intended note
|
|
49
|
+
onsets, lengths and cancellation behavior; they do not render audio.
|
|
50
|
+
|
|
51
|
+
Do not remove either official mirror's curated recipe link just because the
|
|
52
|
+
upstream source has no equivalent. The snapshot records these intentional
|
|
53
|
+
differences so preservation and source fidelity can both be checked.
|
|
54
|
+
|
|
55
|
+
## Statistics scope and evidence
|
|
56
|
+
|
|
57
|
+
The reviewed source adds `getStats()`, `resetStats()` and
|
|
58
|
+
`setStatsEnabled(Boolean)` to the previous eight-method API. Detect support
|
|
59
|
+
before using them with older 1.0.0 beta binaries; the version string alone does
|
|
60
|
+
not identify the feature. Basic counters remain available without enabling
|
|
61
|
+
diagnostics. Monotonic-clock render timing and signal measurements are optional
|
|
62
|
+
and default off; missing/unmeasured fields stay `null`, distinct from measured
|
|
63
|
+
zero. Android backend underrun, buffer and latency fields are independent of
|
|
64
|
+
that diagnostics switch and remain best-effort. Poll at a modest rate and
|
|
65
|
+
cancel polling with the owning screen/service.
|
|
66
|
+
|
|
67
|
+
[stats-performance.md](stats-performance.md) and its
|
|
68
|
+
[raw trials](stats-performance.json) document an Android native host comparison
|
|
69
|
+
against the base engine, including variability and excluded costs. They do not
|
|
70
|
+
run the iOS callback, JavaScript bridge or real device stream, and do not prove
|
|
71
|
+
device CPU, battery, heat, latency or physical underrun behavior. Review the
|
|
72
|
+
native statistics contract/publication and tests independently of the benchmark
|
|
73
|
+
percentages; no zero-overhead or unchanged device-performance guarantee follows.
|
|
74
|
+
|
|
75
|
+
## Upstream documents outside the mirror set
|
|
76
|
+
|
|
77
|
+
The snapshot declares `documentation/index.md` and
|
|
78
|
+
`documentation/third-party-notices.md` in `excluded_documents`, including each
|
|
79
|
+
reviewed hash and reason. SKILL.md supplies the distributed navigation;
|
|
80
|
+
dependency notices accompany the official module and native packages. This
|
|
81
|
+
skill does not distribute Oboe, native binaries or KEMAR impulse responses.
|
|
82
|
+
Changes or deletion of these excluded documents still require review. New
|
|
83
|
+
upstream documents remain visible as new documents until reviewed and mapped
|
|
84
|
+
or explicitly excluded; these records are not a blanket ignore rule.
|
|
85
|
+
|
|
86
|
+
## Verification after a reviewed update
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
node scripts/verify-module-snapshot.mjs --skill ti-synthengine --source /path/to/TiSynthEngine
|
|
90
|
+
node --test test/ti-synthengine.test.js test/ti-synthengine-recipes.test.js
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Run these from TiTools. The checker is read-only: it reports source dirtiness,
|
|
94
|
+
commit drift, source/mirror changes, missing files and new official documents.
|
|
95
|
+
It never fetches, pulls or synchronizes. In the module checkout, also run the
|
|
96
|
+
applicable official documentation, contract and DSP checks described in
|
|
97
|
+
[audio-engine.md](audio-engine.md#regression-coverage).
|
|
98
|
+
|
|
99
|
+
Regenerate navigation only after inspecting the generator's dry run. Refresh
|
|
100
|
+
the snapshot's mirror hashes after navigation and declared additions are final.
|
|
101
|
+
Before committing, inspect source differences and the distributed package;
|
|
102
|
+
neither an old passing test count nor hash equality substitutes for that review.
|
|
103
|
+
|
|
104
|
+
## Native findings and acceptance boundaries
|
|
105
|
+
|
|
106
|
+
At the 2026-10-14 audit, iOS command construction converted zero attack/release
|
|
107
|
+
to at least one sample; Android preserved zero. The shared envelope therefore
|
|
108
|
+
has a one-sample boundary difference. This remains an upstream implementation
|
|
109
|
+
finding: no native changes were made during the documentation correction.
|
|
110
|
+
Recheck command construction or rendered output before calling it resolved.
|
|
111
|
+
|
|
112
|
+
Java/iOS corpus parity covers validator acceptance/reasons, not rendered
|
|
113
|
+
samples. The shared FIR suite and Android host tests establish narrower DSP
|
|
114
|
+
properties. Inspect their current assertions for rate endpoints and exact
|
|
115
|
+
tail-history coverage rather than assuming every advertised case is tested.
|
|
116
|
+
The JavaScript rhythm checks interpret submitted options; they are not native
|
|
117
|
+
scheduler timing measurements.
|
|
118
|
+
|
|
119
|
+
Device startup/route behavior, iOS rendering, headphone localization, CPU,
|
|
120
|
+
battery and underruns need their own evidence. Contract-valid recipes are not
|
|
121
|
+
automatically pleasant or perceptually well localized.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
{
|
|
2
|
+
"module": "ti.synthengine",
|
|
3
|
+
"version": "1.0.0 beta",
|
|
4
|
+
"repository": "https://github.com/macCesar/TiSynthEngine",
|
|
5
|
+
"commit": "95901c98af5353b86d9dc7c60b29ab9186b038cd",
|
|
6
|
+
"reviewed_on": "2026-10-14",
|
|
7
|
+
"files": [
|
|
8
|
+
{
|
|
9
|
+
"source": "documentation/api.md",
|
|
10
|
+
"destination": "references/api.md",
|
|
11
|
+
"source_sha256": "60f9eda77f327bad6b66b0b6a49089c383a49a211c0691d09a0d715731434b56",
|
|
12
|
+
"mirrored_sha256": "5c07828516109386224c6380d8e603f6889cb1cbc0f29dd79609db288cabd908",
|
|
13
|
+
"links": [],
|
|
14
|
+
"link_fixes": []
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"source": "documentation/audio-engine.md",
|
|
18
|
+
"destination": "references/audio-engine.md",
|
|
19
|
+
"source_sha256": "7b5707ee22e01a351af3633be14458726f8956069fb9355d1fb31cc4f7b9438a",
|
|
20
|
+
"mirrored_sha256": "22b3665068d9507ef7481a606f8949de24e7429e40609b9760164567220dd8fd",
|
|
21
|
+
"links": [],
|
|
22
|
+
"link_fixes": []
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"source": "documentation/examples.md",
|
|
26
|
+
"destination": "references/examples.md",
|
|
27
|
+
"source_sha256": "53a8bd95215cc24a35776edb8686fa0d60c5399be0b4ff2685eee1563738f6cb",
|
|
28
|
+
"mirrored_sha256": "6679554e7f1df97d45a1e3c5ea842a0999d713933c677fc1a4678e72ca226f63",
|
|
29
|
+
"links": [],
|
|
30
|
+
"link_fixes": [
|
|
31
|
+
{
|
|
32
|
+
"original_markdown": "The complete interactive demo is in [`example/app.js`](../example/app.js).",
|
|
33
|
+
"mirrored_markdown": "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)."
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"source": "documentation/guide.md",
|
|
39
|
+
"destination": "references/guide.md",
|
|
40
|
+
"source_sha256": "c5fb4ff34ec425487221b80d6793bda24aa328281ab9ccb02e65b0065e54842e",
|
|
41
|
+
"mirrored_sha256": "d8f58c77c4d622e67ae6e2cafee58a2c24c1c8e31bad719a05ec8a5d968b3d04",
|
|
42
|
+
"links": [],
|
|
43
|
+
"link_fixes": []
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"source": "documentation/recommendations.md",
|
|
47
|
+
"destination": "references/recommendations.md",
|
|
48
|
+
"source_sha256": "0f09ee6ef0876b3a23021fddb509dfd1e1206d08e836acae8f32b58b6481c055",
|
|
49
|
+
"mirrored_sha256": "f2480f455e55e461c880c8614ac383d60abf0ea8e744e3b99deabea290deb6c6",
|
|
50
|
+
"links": [],
|
|
51
|
+
"link_fixes": []
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"source": "documentation/sound-design.md",
|
|
55
|
+
"destination": "references/sound-design.md",
|
|
56
|
+
"source_sha256": "4ccbb55b92879c59d20116aff942e16d431c619341b3d4714da4c50c3c691cf9",
|
|
57
|
+
"mirrored_sha256": "ac716003ff31a9d8dc896faa48ab0a18787a153797b7fa2f77ba0d7a936e8868",
|
|
58
|
+
"links": [],
|
|
59
|
+
"link_fixes": [
|
|
60
|
+
{
|
|
61
|
+
"original_markdown": "For more complete code, continue with [Examples](examples.md). For gain and\ndevice-testing advice, see [Recommendations](recommendations.md).",
|
|
62
|
+
"mirrored_markdown": "For more complete code, continue with [Examples](examples.md) and\n[Curated sound and interaction recipes](recipes.md). The latter includes retro\neffects, a playable xylophone, memory-pad timbres, layered chords and timer\nownership. For gain and device-testing advice, see [Recommendations](recommendations.md)."
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"source": "documentation/troubleshooting.md",
|
|
68
|
+
"destination": "references/troubleshooting.md",
|
|
69
|
+
"source_sha256": "10949f8f18f9e97933bfb1f025a12217746648c01805ff0fafe2c8e064b1c0cc",
|
|
70
|
+
"mirrored_sha256": "baaa2e31f1c1e0ab8b3dd9924929ec987caa13962b526af1389bdbfb77f4f9af",
|
|
71
|
+
"links": [],
|
|
72
|
+
"link_fixes": []
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"source": "documentation/stats-performance.md",
|
|
76
|
+
"destination": "references/stats-performance.md",
|
|
77
|
+
"source_sha256": "798075f7bec08b4dafcaa46f1c43552d90ba23e2c85b49b4ab1d4ddf72c210df",
|
|
78
|
+
"mirrored_sha256": "40e4dc748379a24a90a812f26177372530a8138324d465a11f75ff7f45c3dc1d",
|
|
79
|
+
"links": [],
|
|
80
|
+
"link_fixes": []
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"source": "documentation/stats-performance.json",
|
|
84
|
+
"destination": "references/stats-performance.json",
|
|
85
|
+
"source_sha256": "bd0cf07295d0d8f1120e66f527e9ca6d9a014efdc43dff5675716e8e26abe5b3",
|
|
86
|
+
"mirrored_sha256": "bd0cf07295d0d8f1120e66f527e9ca6d9a014efdc43dff5675716e8e26abe5b3",
|
|
87
|
+
"links": [],
|
|
88
|
+
"link_fixes": []
|
|
89
|
+
}
|
|
90
|
+
],
|
|
91
|
+
"excluded_documents": [
|
|
92
|
+
{
|
|
93
|
+
"source": "documentation/index.md",
|
|
94
|
+
"source_sha256": "a1fee9bfc45e461594b54cc226cf21e9ecbee358400b3414643a199c18b1edb2",
|
|
95
|
+
"reason": "Upstream documentation index; SKILL.md is the distributed navigation entry point."
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"source": "documentation/third-party-notices.md",
|
|
99
|
+
"source_sha256": "cff5eb2cb19c9128e33f26d524fac1f7cad43e263693f34413392ead97b0f1c5",
|
|
100
|
+
"reason": "Dependency and KEMAR notices remain with the official module and its binary packages; this skill redistributes documentation, not the native code or HRTF data. Re-review attribution when the source notice changes."
|
|
101
|
+
}
|
|
102
|
+
],
|
|
103
|
+
"source_state": "working-tree",
|
|
104
|
+
"reviewed_worktree_sha256": "5a5085884d65ec92b6281f2c04cf47adaa864d988e3462fca98340d4a9a27ad9"
|
|
105
|
+
}
|