@maccesar/titools 5.2.0 → 5.2.1
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 +69 -0
- package/README.md +80 -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/downloader.js +1 -1
- 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,11 +1,10 @@
|
|
|
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/sound-design.md` SHA-256: `dd543e07c825aaf67a0a5f85619088a8d02721a9d33dbf4579edf760dad3e262`.
|
|
2
2
|
|
|
3
3
|
# Sound design with TiSynthEngine
|
|
4
4
|
|
|
5
|
-
TiSynthEngine
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
musical cues, alarms, retro effects and simple percussion.
|
|
5
|
+
TiSynthEngine generates sound with oscillators, without recorded samples. Pitch, waveform, envelope, movement and level define each sound, from interface feedback and musical cues to alarms, retro effects and simple percussion.
|
|
6
|
+
|
|
7
|
+
Additional [curated recipes](recipes.md) provide application sound and interaction variants.
|
|
9
8
|
|
|
10
9
|
The examples assume the engine is running and use these constants:
|
|
11
10
|
|
|
@@ -31,95 +30,68 @@ var WAVE = synth.getDefaults().waveTypes
|
|
|
31
30
|
- [Mixing profiles and limiter](#mixing-profiles-and-limiter)
|
|
32
31
|
- [Speakers, headphones and devices](#speakers-headphones-and-devices)
|
|
33
32
|
- [Recipes](#recipes)
|
|
33
|
+
- [Holding a sound and adding movement](#holding-a-sound-and-adding-movement)
|
|
34
|
+
- [Native space and creative drive](#native-space-and-creative-drive)
|
|
34
35
|
|
|
35
36
|
<!-- TOC-END -->
|
|
36
37
|
|
|
37
38
|
## Notes, frequencies and octaves
|
|
38
39
|
|
|
39
|
-
Frequency is the number of waveform cycles per second, measured in hertz. A
|
|
40
|
-
440 Hz oscillator repeats 440 times each second. TiSynthEngine accepts a
|
|
41
|
-
frequency directly or converts a note name for you:
|
|
40
|
+
Frequency is the number of waveform cycles per second, measured in hertz. A 440 Hz oscillator repeats 440 times each second. TiSynthEngine accepts a frequency directly or converts a note name for you:
|
|
42
41
|
|
|
43
42
|
```javascript
|
|
44
43
|
synth.playTone({ frequency: 440 })
|
|
45
44
|
synth.playTone({ note: 'A4' })
|
|
46
45
|
```
|
|
47
46
|
|
|
48
|
-
Both calls have the same pitch. Note names use an octave number: `C4` is middle
|
|
49
|
-
C, `C5` is one octave higher, and `C3` is one octave lower. Moving up one
|
|
50
|
-
octave doubles frequency; moving down halves it.
|
|
47
|
+
Both calls have the same pitch. Note names use an octave number: `C4` is middle C, `C5` is one octave higher, and `C3` is one octave lower. Moving up one octave doubles frequency; moving down halves it.
|
|
51
48
|
|
|
52
|
-
The note parser accepts English letters and solfege. Sharps use `#`; flats use
|
|
53
|
-
a lowercase `b`.
|
|
49
|
+
The note parser accepts English letters and solfege. Sharps use `#`; flats use a lowercase `b`.
|
|
54
50
|
|
|
55
51
|
```text
|
|
56
52
|
C4 C#4 Db4 D4
|
|
57
53
|
DO4 DO#4 REb4 RE4
|
|
58
54
|
```
|
|
59
55
|
|
|
60
|
-
When no octave is present, octave 4 is used. The supported octave digit is 0
|
|
61
|
-
through 9, subject to the current frequency ceiling.
|
|
56
|
+
When no octave is present, octave 4 is used. The supported octave digit is 0 through 9, subject to the current frequency ceiling.
|
|
62
57
|
|
|
63
|
-
The tuning system is twelve-tone equal temperament with A4 at 440 Hz. Each
|
|
64
|
-
semitone multiplies frequency by the twelfth root of two:
|
|
58
|
+
The tuning system is twelve-tone equal temperament with A4 at 440 Hz. Each semitone multiplies frequency by the twelfth root of two:
|
|
65
59
|
|
|
66
60
|
```text
|
|
67
61
|
frequency = 440 * 2 ^ ((midiNote - 69) / 12)
|
|
68
62
|
```
|
|
69
63
|
|
|
70
|
-
Equal temperament keeps intervals consistent in every key. It also means a
|
|
71
|
-
major third is the practical keyboard interval, not a pure 5:4 frequency
|
|
72
|
-
ratio. That distinction rarely matters for game or interface sounds.
|
|
64
|
+
Equal temperament keeps intervals consistent in every key. It also means a major third is the practical keyboard interval, not a pure 5:4 frequency ratio. That distinction rarely matters for game or interface sounds.
|
|
73
65
|
|
|
74
66
|
## Waveform and timbre
|
|
75
67
|
|
|
76
|
-
Pitch says how fast the oscillator repeats. Waveform says how it moves within
|
|
77
|
-
each cycle, which determines the harmonic content and perceived timbre.
|
|
68
|
+
Pitch says how fast the oscillator repeats. Waveform says how it moves within each cycle, which determines the harmonic content and perceived timbre.
|
|
78
69
|
|
|
79
70
|
### Sine
|
|
80
71
|
|
|
81
|
-
`SINE` contains the fundamental and no intentional overtones.
|
|
82
|
-
clean beeps, soft bass notes and sounds that should stay out of the way. On a
|
|
83
|
-
small speaker, very low sines may be quiet or may excite the speaker's own
|
|
84
|
-
distortion because there are no upper harmonics to carry the pitch.
|
|
72
|
+
`SINE` contains the fundamental and no intentional overtones. Use it for clean beeps, soft bass notes and unobtrusive sounds. On a small speaker, very low sines may be quiet or may excite the speaker's own distortion because there are no upper harmonics to carry the pitch.
|
|
85
73
|
|
|
86
74
|
### Square
|
|
87
75
|
|
|
88
|
-
`SQUARE` contains strong odd harmonics. It sounds hollow, bright and electronic.
|
|
89
|
-
It is a good starting point for retro game cues and clear melodic prompts. The
|
|
90
|
-
extra high-frequency energy makes it more assertive than a sine at the same
|
|
91
|
-
pitch.
|
|
76
|
+
`SQUARE` contains strong odd harmonics. It sounds hollow, bright and electronic. Try it for retro game cues and clear melodic prompts. The extra high-frequency energy makes it more assertive than a sine at the same pitch.
|
|
92
77
|
|
|
93
78
|
### Sawtooth
|
|
94
79
|
|
|
95
|
-
`SAWTOOTH` contains both even and odd harmonics. It is the densest pitched
|
|
96
|
-
waveform in the module and reads as buzzy or brassy. Use it for alarms, arcade
|
|
97
|
-
leads and short sweeps. Square and sawtooth are band-limited with PolyBLEP to
|
|
98
|
-
reduce aliasing at discontinuities.
|
|
80
|
+
`SAWTOOTH` contains both even and odd harmonics. It is the densest pitched waveform in the module and reads as buzzy or brassy. Use it for alarms, arcade leads and short sweeps. Square and sawtooth are band-limited with PolyBLEP to reduce aliasing at discontinuities.
|
|
99
81
|
|
|
100
82
|
### Triangle
|
|
101
83
|
|
|
102
|
-
`TRIANGLE` contains odd harmonics that fall off faster than a square wave. It
|
|
103
|
-
has more body than a sine without the hard edge of a square. It suits gentle
|
|
104
|
-
melodies, pads and xylophone-like sketches.
|
|
84
|
+
`TRIANGLE` contains odd harmonics that fall off faster than a square wave. It has more body than a sine without the hard edge of a square. It suits gentle melodies, pads and xylophone-like sketches.
|
|
105
85
|
|
|
106
86
|
### Noise
|
|
107
87
|
|
|
108
|
-
`NOISE` produces white noise rather than a repeating pitched cycle. Its
|
|
109
|
-
`frequency` is accepted because every sound event uses the same contract, but
|
|
110
|
-
changing that value does not tune the noise. A short envelope turns it into a
|
|
111
|
-
click, hat or impact layer; a long envelope creates wind or static.
|
|
88
|
+
`NOISE` produces white noise rather than a repeating pitched cycle. Its `frequency` is accepted because every sound event uses the same contract, but changing that value does not tune the noise. A short envelope turns it into a click, hat or impact layer; a long envelope creates wind or static.
|
|
112
89
|
|
|
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.
|
|
90
|
+
`noiseRate` changes the source into variable-rate sample-and-hold noise. Zero keeps the white-noise default. Lower rates hold each pseudo-random value longer and sound grainier. `noiseRateEnd` moves the rate over the event.
|
|
116
91
|
|
|
117
92
|
### Wavetable
|
|
118
93
|
|
|
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.
|
|
94
|
+
`WAVETABLE` repeats 2 to 64 values supplied in `waveTable`. Values range from -1 to 1 and are read as steps, without interpolation. Short asymmetric tables are useful for coarse DAC-like voices, buzzy radio tones and original retro effects that do not fit the four built-in oscillator shapes.
|
|
123
95
|
|
|
124
96
|
```javascript
|
|
125
97
|
synth.playTone({
|
|
@@ -134,31 +106,20 @@ synth.playTone({
|
|
|
134
106
|
Try the built-in sources at a moderate level before choosing one:
|
|
135
107
|
|
|
136
108
|
```javascript
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
attack: 8,
|
|
145
|
-
release: 120,
|
|
146
|
-
volume: 0.65
|
|
147
|
-
})
|
|
148
|
-
}, index * 550)
|
|
149
|
-
})
|
|
109
|
+
synth.playSequence({ timeUnit: 'ms', stepDuration: 550,
|
|
110
|
+
voice: { attack: 8, release: 120, volume: 0.65 },
|
|
111
|
+
steps: [WAVE.SINE, WAVE.SQUARE, WAVE.SAWTOOTH, WAVE.TRIANGLE, WAVE.NOISE]
|
|
112
|
+
.map(function (waveType) {
|
|
113
|
+
return { notes: [69], length: 330, overrides: { waveType: waveType } }
|
|
114
|
+
})
|
|
115
|
+
})
|
|
150
116
|
```
|
|
151
117
|
|
|
152
118
|
## Filter, pulse width and quantization
|
|
153
119
|
|
|
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.
|
|
120
|
+
`lowPassHz` enables a per-voice one-pole low-pass filter. It is most obvious on noise, square and sawtooth sources. Zero bypasses the filter. For resonance, high-pass and band-pass shapes or a moving cutoff, use the [resonant filter](#resonant-filter) below.
|
|
158
121
|
|
|
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.
|
|
122
|
+
`pulseWidth` controls how much of each square-wave cycle stays high. The 0.5 default is a normal square. Values closer to 0.05 or 0.95 become thinner and brighter. `pulseWidthEnd` creates a linear duty-cycle sweep.
|
|
162
123
|
|
|
163
124
|
```javascript
|
|
164
125
|
synth.playTone({
|
|
@@ -172,10 +133,7 @@ synth.playTone({
|
|
|
172
133
|
})
|
|
173
134
|
```
|
|
174
135
|
|
|
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.
|
|
136
|
+
`bitDepth` rounds the oscillator or noise amplitude to a fixed number of levels before filtering. Values from 2 to 16 are accepted. Zero preserves the floating-point signal. Quantization adds harmonic grit; it does not change the audio device's output format.
|
|
179
137
|
|
|
180
138
|
## Envelope and total duration
|
|
181
139
|
|
|
@@ -186,16 +144,11 @@ silence -> attack -> full level -> release -> silence
|
|
|
186
144
|
|<---------- duration ---------->|
|
|
187
145
|
```
|
|
188
146
|
|
|
189
|
-
`duration` is the total time, not the sustain time. If duration is 500 ms,
|
|
190
|
-
attack is 50 ms and release is 100 ms, the full-level middle lasts 350 ms.
|
|
147
|
+
`duration` is the total time, not the sustain time. If duration is 500 ms, attack is 50 ms and release is 100 ms, the full-level middle lasts 350 ms.
|
|
191
148
|
|
|
192
|
-
Short attacks feel immediate. A 0 or 1 ms attack can be useful for percussion,
|
|
193
|
-
but an abrupt start at an unlucky phase can sound like a click. Values between
|
|
194
|
-
5 and 15 ms keep most game feedback crisp without a hard edge.
|
|
149
|
+
Short attacks feel immediate. A 0 or 1 ms attack can be useful for percussion, but an abrupt start at an unlucky phase can sound like a click. Values between 5 and 15 ms keep most game feedback crisp without a hard edge.
|
|
195
150
|
|
|
196
|
-
Long attacks soften the onset. Use 100 to 500 ms for pads and slow warnings.
|
|
197
|
-
Release controls how the sound leaves: 20 to 80 ms feels tight, while several
|
|
198
|
-
hundred milliseconds leaves a tail.
|
|
151
|
+
Long attacks soften the onset. Use 100 to 500 ms for pads and slow warnings. Release controls how the sound leaves: 20 to 80 ms feels tight, while several hundred milliseconds leaves a tail.
|
|
199
152
|
|
|
200
153
|
Explicit attack and release values must fit. These relationships are required:
|
|
201
154
|
|
|
@@ -204,15 +157,11 @@ attack < duration
|
|
|
204
157
|
release <= duration - attack
|
|
205
158
|
```
|
|
206
159
|
|
|
207
|
-
Defaults are adjusted internally if a very short duration leaves no room, but
|
|
208
|
-
values supplied by the caller are never reshaped silently.
|
|
160
|
+
Defaults are adjusted internally if a very short duration leaves no room, but values supplied by the caller are never reshaped silently.
|
|
209
161
|
|
|
210
162
|
## Decay and sustain
|
|
211
163
|
|
|
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.
|
|
164
|
+
Plucked strings, struck keys and mallets start loud and settle. A flat envelope cannot do that, so `decay` and `sustain` add a stage after the attack: the level falls from full scale to `sustain` over `decay` milliseconds, then holds until the release.
|
|
216
165
|
|
|
217
166
|
```text
|
|
218
167
|
decay: 0 flat tone, the default
|
|
@@ -223,22 +172,16 @@ decay: 2000, sustain: 0.02 bell or mallet: fades by itself
|
|
|
223
172
|
Practical starting regions:
|
|
224
173
|
|
|
225
174
|
- 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;
|
|
175
|
+
- struck percussion with a pitch drop: decay about half the duration, sustain near 0.3;
|
|
228
176
|
- bells and mallets: decay over most of the duration, sustain near 0.
|
|
229
177
|
|
|
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`.
|
|
178
|
+
`sustain` below 1 needs a nonzero `decay`. Without one the level would jump instantly, which clicks, so the call is rejected with `sustain_without_decay`.
|
|
232
179
|
|
|
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.
|
|
180
|
+
The release scales the level the note has reached. If the release begins while the decay is still running, the note leaves smoothly from that point. The decay still has to fit: `attack` plus `decay` cannot exceed `duration`, and the 50 ms default attack counts. Set a short `attack` explicitly for a tight pluck.
|
|
237
181
|
|
|
238
182
|
## Pan and movement
|
|
239
183
|
|
|
240
|
-
`pan` ranges from -1 on the left to 1 on the right. Zero is centered. Stereo
|
|
241
|
-
movement is a straight interpolation from `pan` to `panEnd` over the event.
|
|
184
|
+
`pan` ranges from -1 on the left to 1 on the right. Zero is centered. Stereo movement is a straight interpolation from `pan` to `panEnd` over the event.
|
|
242
185
|
|
|
243
186
|
```javascript
|
|
244
187
|
synth.playTone({
|
|
@@ -252,11 +195,9 @@ synth.playTone({
|
|
|
252
195
|
})
|
|
253
196
|
```
|
|
254
197
|
|
|
255
|
-
Phone speakers are often mono or close together, so pan may be subtle. Treat it
|
|
256
|
-
as extra detail rather than the only cue that distinguishes two sounds.
|
|
198
|
+
Phone speakers are often mono or close together, so pan may be subtle. Treat it as extra detail rather than the only cue that distinguishes two sounds.
|
|
257
199
|
|
|
258
|
-
`frequencyEnd` makes a linear pitch sweep. Use an upward sweep for activation
|
|
259
|
-
or reward and a downward sweep for dismissal, power-down or impact.
|
|
200
|
+
`frequencyEnd` makes a linear pitch sweep. Use an upward sweep for activation or reward and a downward sweep for dismissal, power-down or impact.
|
|
260
201
|
|
|
261
202
|
```javascript
|
|
262
203
|
synth.playTone({
|
|
@@ -272,8 +213,7 @@ synth.playTone({
|
|
|
272
213
|
|
|
273
214
|
## Vibrato and the LFO
|
|
274
215
|
|
|
275
|
-
The low-frequency oscillator modulates pitch. `lfoFreq` is the modulation rate
|
|
276
|
-
in cycles per second, and `lfoDepth` is the maximum pitch movement in hertz.
|
|
216
|
+
The low-frequency oscillator modulates pitch. `lfoFreq` is the modulation rate in cycles per second, and `lfoDepth` is the maximum pitch movement in hertz.
|
|
277
217
|
|
|
278
218
|
```javascript
|
|
279
219
|
synth.playTone({
|
|
@@ -287,37 +227,21 @@ synth.playTone({
|
|
|
287
227
|
})
|
|
288
228
|
```
|
|
289
229
|
|
|
290
|
-
A rate around 4 to 7 Hz with a small depth sounds like musical vibrato. A fast
|
|
291
|
-
rate or large depth becomes an effect. Because depth is measured in hertz, 8 Hz
|
|
292
|
-
is a larger musical interval on a low note than on a high note.
|
|
230
|
+
A rate around 4 to 7 Hz with a small depth sounds like musical vibrato. A fast rate or large depth becomes an effect. Because depth is measured in hertz, 8 Hz is a larger musical interval on a low note than on a high note.
|
|
293
231
|
|
|
294
232
|
## Resonant filter
|
|
295
233
|
|
|
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).
|
|
234
|
+
`filterType` adds a filter that removes or emphasizes part of the spectrum. It has 12 dB per octave of slope, twice as steep as the one-pole `lowPassHz` filter, and can be combined with it (`lowPassHz` runs first).
|
|
299
235
|
|
|
300
|
-
- `lowpass` darkens the sound. A sawtooth through a closing low-pass reads as a
|
|
301
|
-
|
|
302
|
-
- `
|
|
303
|
-
effects out of noise.
|
|
304
|
-
- `bandpass` keeps one band around `filterHz`, which gives vocal, nasal and
|
|
305
|
-
wah-like colors.
|
|
236
|
+
- `lowpass` darkens the sound. A sawtooth through a closing low-pass reads as a zap or a sound moving away; an opening one reads as a swell.
|
|
237
|
+
- `highpass` thins the sound by removing body. It makes hats, hiss and tinny effects out of noise.
|
|
238
|
+
- `bandpass` keeps one band around `filterHz`, which gives vocal, nasal and wah-like colors.
|
|
306
239
|
|
|
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.
|
|
240
|
+
Filters shape harmonics, so give them a source that has some: `SAWTOOTH`, `SQUARE` and `NOISE` respond strongly. A sine has only its fundamental, so a filter mostly changes its level.
|
|
310
241
|
|
|
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.
|
|
242
|
+
`filterQ` is the resonance. The default 0.7071 is flat. Values from 2 to 4 add character, and above about 6 the filter whistles around the cutoff. A low-pass or high-pass boosts the cutoff region by about `filterQ`, so Q 10 is roughly 20 dB. Lower the event `volume` as Q goes up. The limiter catches peaks, but a resonance that keeps hitting it makes the whole mix pump. The band-pass keeps unity gain at its center for every Q and only narrows.
|
|
317
243
|
|
|
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.
|
|
244
|
+
`filterHzEnd` moves the cutoff over the whole event. The motion is exponential, so each second covers the same musical distance. Set it above `filterHz` to open the filter and below to close it. Zero disables the sweep.
|
|
321
245
|
|
|
322
246
|
```javascript
|
|
323
247
|
synth.playTone({
|
|
@@ -336,39 +260,19 @@ synth.playTone({
|
|
|
336
260
|
|
|
337
261
|
## Frequency modulation
|
|
338
262
|
|
|
339
|
-
FM makes rich, bright and metallic sounds from a plain sine. A second sine, the
|
|
340
|
-
|
|
341
|
-
`
|
|
342
|
-
|
|
343
|
-
- `
|
|
344
|
-
|
|
345
|
-
|
|
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.
|
|
263
|
+
FM makes rich, bright and metallic sounds from a plain sine. A second sine, the modulator, bends the pitch of the first one, the carrier. Turn it on with `fmDepth` or `fmDepthEnd`, on a `SINE` voice.
|
|
264
|
+
|
|
265
|
+
- `fmRatio` is the modulator frequency as a multiple of the carrier's. Whole numbers (1, 2, 3) keep the added overtones on the harmonic series, so the pitch stays clear and the sound reads as organ- or piano-like. Fractional ratios such as 1.4142 or 3.5 put the overtones between harmonics, which reads as bells, glass and metal.
|
|
266
|
+
- `fmDepth` is the modulation index and works like a brightness control. Around 0.5 to 1.5 it warms a sine, 2 to 5 makes it bright and rich, and values near 10 get harsh.
|
|
267
|
+
- `fmDepthEnd` moves the index over the event. Starting high and ending low gives a bright attack that mellows, which is the signature of electric pianos, bells and mallets. Pair it with `decay` so the level falls with the brightness.
|
|
268
|
+
|
|
269
|
+
FM does not change the sine's amplitude, so gain staging is the same as for a plain sine. There is no band-limiting: a high carrier with a large index and ratio puts sidebands above the Nyquist frequency, where they alias into inharmonic noise. Keep bell carriers modest, around 500 Hz, or lower the index.
|
|
359
270
|
|
|
360
271
|
## Detune
|
|
361
272
|
|
|
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.
|
|
273
|
+
`detune` shifts a pitch by cents, hundredths of a semitone. Two tones a few cents apart drift in and out of phase and beat at a rate close to `frequency * (2 ^ (cents / 1200) - 1)`. A 12-cent gap at 440 Hz beats about 3 times a second. Slow beating (0.5 to 4 Hz) sounds warm and wide, like a chorus; past about 20 cents it starts to sound out of tune.
|
|
367
274
|
|
|
368
|
-
|
|
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:
|
|
275
|
+
Use `detune` on a single tone to vary the pitch slightly between repetitions. The effect comes from stacking detuned copies. In a chord, give `detunes` one entry per pitch and repeat a pitch to thicken it:
|
|
372
276
|
|
|
373
277
|
```javascript
|
|
374
278
|
synth.playChord({
|
|
@@ -382,20 +286,11 @@ synth.playChord({
|
|
|
382
286
|
})
|
|
383
287
|
```
|
|
384
288
|
|
|
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.
|
|
289
|
+
Each repeated pitch is a voice, so size `maxVoices` for the full stack. Protected profiles divide per-voice source gain by the square root of the event voice count. This reduces buildup; it does not guarantee equal loudness. Correlated voices can still reinforce each other, and detuned voices can produce peaks as their phases align. `raw` does not apply this event normalization.
|
|
390
290
|
|
|
391
291
|
## Chords, polyphony and gain
|
|
392
292
|
|
|
393
|
-
`playChord` is for notes that should start together. The call is placed in the
|
|
394
|
-
native queue as one event, so the audio callback sees the whole chord or none
|
|
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.
|
|
293
|
+
`playChord` is for notes that should start together. The call is placed in the native queue as one event, so the audio callback sees the whole chord or none of it. In protected profiles, per-voice source gain is divided by the square root of the chord's voice count. This approximately stabilizes power for uncorrelated voices, not coherent copies; it does not guarantee constant peaks or perceived loudness. `raw` bypasses this normalization.
|
|
399
294
|
|
|
400
295
|
```javascript
|
|
401
296
|
synth.playChord({
|
|
@@ -409,42 +304,28 @@ synth.playChord({
|
|
|
409
304
|
})
|
|
410
305
|
```
|
|
411
306
|
|
|
412
|
-
Four separate `playTone` calls are four independent full-gain events. They are
|
|
413
|
-
not atomic and may start in different audio callbacks. Their sum is also hotter
|
|
414
|
-
and can push the limiter. Separate calls are correct for unrelated taps or
|
|
415
|
-
effects; use `playChord` when the app already knows the pitches are one chord.
|
|
307
|
+
Four separate `playTone` calls are four independent full-gain events. They are not atomic and may start in different audio callbacks. Their sum is also hotter and can push the limiter. Separate calls are correct for unrelated taps or effects; use `playChord` when the app already knows the pitches are one chord.
|
|
416
308
|
|
|
417
|
-
`maxVoices`
|
|
418
|
-
voice with the least time remaining is faded and reused. Leave a small margin for release tails, but do
|
|
419
|
-
not set 32 by habit when the app can only make four sounds at once.
|
|
309
|
+
`maxVoices` sets voice capacity without changing loudness. Timed-only pools replace the least remaining duration; held/transport pools prefer a releasing voice, then the oldest attack. Leave a small margin for release tails, but do not set 32 by habit when the app can only make four sounds at once.
|
|
420
310
|
|
|
421
311
|
## Mixing profiles and limiter
|
|
422
312
|
|
|
423
|
-
Choose the profile once in `
|
|
313
|
+
Choose the profile once in `start()`:
|
|
424
314
|
|
|
425
|
-
| Profile
|
|
426
|
-
|
|
|
427
|
-
| `conservative` | Default for mixed effects, chords and unpredictable overlap.
|
|
428
|
-
| `balanced`
|
|
429
|
-
| `speakerSafe`
|
|
430
|
-
| `raw`
|
|
315
|
+
| Profile | Practical use |
|
|
316
|
+
| -------------- | ----------------------------------------------------------------- |
|
|
317
|
+
| `conservative` | Default for mixed effects, chords and unpredictable overlap. |
|
|
318
|
+
| `balanced` | More level for mostly monophonic sounds. |
|
|
319
|
+
| `speakerSafe` | Lower source gain and a 0.70 ceiling for small speakers. |
|
|
320
|
+
| `raw` | Full source gain; useful only when the app owns all gain staging. |
|
|
431
321
|
|
|
432
|
-
Protected profiles calibrate source gain by waveform and event voice count.
|
|
433
|
-
The final stereo-linked limiter catches exceptional peaks with 10 ms of
|
|
434
|
-
lookahead and a 100 ms release. Its ceiling is 0.85, or 0.70 for `speakerSafe`.
|
|
322
|
+
Protected profiles calibrate source gain by waveform and event voice count. The final stereo-linked limiter catches exceptional peaks with 10 ms of lookahead and a 100 ms release. Its ceiling is 0.85, or 0.70 for `speakerSafe`.
|
|
435
323
|
|
|
436
|
-
The limiter
|
|
437
|
-
lower event volume or choose a more conservative profile. Repeatedly starting
|
|
438
|
-
the same long sound before its previous release ends raises and lowers the sum,
|
|
439
|
-
which can produce audible pumping. That overlap is useful as a stress test, but
|
|
440
|
-
it is a poor reference for the tone's normal quality.
|
|
324
|
+
The limiter protects against peaks. If it engages on every note, lower event volume or choose a more conservative profile instead of using it to raise loudness. Repeatedly starting the same long sound before its previous release ends raises and lowers the sum, which can produce audible pumping. That overlap is useful as a stress test, but it is a poor reference for the tone's normal quality.
|
|
441
325
|
|
|
442
326
|
## Speakers, headphones and devices
|
|
443
327
|
|
|
444
|
-
Headphones usually reproduce bass and stereo movement more cleanly than a phone
|
|
445
|
-
speaker. A sound that is smooth in headphones can buzz on a small driver even
|
|
446
|
-
when the digital signal never clips. Low pitches and square or sawtooth waves
|
|
447
|
-
are the most demanding.
|
|
328
|
+
Headphones usually reproduce bass and stereo movement more cleanly than a phone speaker. A sound that is smooth in headphones can buzz on a small driver even when the digital signal never clips. Low pitches and square or sawtooth waves are the most demanding.
|
|
448
329
|
|
|
449
330
|
For speaker-facing sounds:
|
|
450
331
|
|
|
@@ -454,15 +335,11 @@ For speaker-facing sounds:
|
|
|
454
335
|
- test at several system volume settings on the target device;
|
|
455
336
|
- keep critical meaning in rhythm and pitch, not pan alone.
|
|
456
337
|
|
|
457
|
-
Different phones have different sample rates, speaker protection and acoustic
|
|
458
|
-
resonances. Test the real device family. A desktop browser or simulator cannot
|
|
459
|
-
answer whether a small speaker will rattle.
|
|
338
|
+
Different phones have different sample rates, speaker protection and acoustic resonances. Test the real device family. A desktop browser or simulator cannot answer whether a small speaker will rattle.
|
|
460
339
|
|
|
461
340
|
## Recipes
|
|
462
341
|
|
|
463
|
-
These recipes use only the 1.0.0 contract and keep explicit envelopes valid.
|
|
464
|
-
Tune pitch and volume for the app's other audio rather than treating the values
|
|
465
|
-
as mastering targets.
|
|
342
|
+
These recipes use only the 1.0.0 contract and keep explicit envelopes valid. Adjust pitch and volume to fit the app's other audio; the recipe values are starting points, not mastering targets.
|
|
466
343
|
|
|
467
344
|
### Interface click
|
|
468
345
|
|
|
@@ -477,8 +354,7 @@ synth.playTone({
|
|
|
477
354
|
})
|
|
478
355
|
```
|
|
479
356
|
|
|
480
|
-
The short sine is cleaner than a full-band noise click. Raise the frequency for
|
|
481
|
-
a lighter control or lower it for a heavier one.
|
|
357
|
+
The short sine is cleaner than a full-band noise click. Raise the frequency for a lighter control or lower it for a heavier one.
|
|
482
358
|
|
|
483
359
|
### Confirmation hit
|
|
484
360
|
|
|
@@ -511,18 +387,16 @@ synth.playChord({
|
|
|
511
387
|
### Two-tone alarm
|
|
512
388
|
|
|
513
389
|
```javascript
|
|
514
|
-
synth.
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
release: 70,
|
|
519
|
-
volume: 0.55,
|
|
520
|
-
waveType: WAVE.SAWTOOTH,
|
|
390
|
+
synth.setTempo({ bpm: 150 })
|
|
391
|
+
synth.playSequence({
|
|
392
|
+
timeUnit: 'beats',
|
|
393
|
+
stepDuration: 0.5,
|
|
394
|
+
voice: { attack: 8, release: 70, volume: 0.55, waveType: WAVE.SAWTOOTH },
|
|
521
395
|
steps: [
|
|
522
|
-
{
|
|
523
|
-
{
|
|
524
|
-
{
|
|
525
|
-
{
|
|
396
|
+
{ notes: [69] },
|
|
397
|
+
{ notes: [76] },
|
|
398
|
+
{ notes: [69] },
|
|
399
|
+
{ notes: [76] }
|
|
526
400
|
]
|
|
527
401
|
})
|
|
528
402
|
```
|
|
@@ -530,50 +404,43 @@ synth.playPattern({
|
|
|
530
404
|
### Retro pickup
|
|
531
405
|
|
|
532
406
|
```javascript
|
|
533
|
-
synth.
|
|
534
|
-
|
|
407
|
+
synth.setTempo({ bpm: 180 })
|
|
408
|
+
synth.playSequence({
|
|
409
|
+
timeUnit: 'beats',
|
|
410
|
+
stepDuration: 0.25,
|
|
535
411
|
swing: 0.06,
|
|
536
|
-
|
|
537
|
-
attack: 2,
|
|
538
|
-
release: 45,
|
|
539
|
-
volume: 0.5,
|
|
540
|
-
waveType: WAVE.SQUARE,
|
|
412
|
+
voice: { attack: 2, release: 45, volume: 0.5, waveType: WAVE.SQUARE },
|
|
541
413
|
steps: [
|
|
542
|
-
{
|
|
543
|
-
{
|
|
544
|
-
{
|
|
545
|
-
{
|
|
414
|
+
{ notes: [72] },
|
|
415
|
+
{ notes: [76] },
|
|
416
|
+
{ notes: [79] },
|
|
417
|
+
{ notes: [84], duration: 0.5 }
|
|
546
418
|
]
|
|
547
419
|
})
|
|
548
420
|
```
|
|
549
421
|
|
|
550
|
-
The first three
|
|
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.
|
|
422
|
+
The first three intervals are sixteenth notes and the last is an eighth note. Gate sets when release begins; `length` overrides that note duration independently of the next attack.
|
|
554
423
|
|
|
555
424
|
### Noise percussion
|
|
556
425
|
|
|
557
426
|
```javascript
|
|
558
|
-
synth.
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
volume: 0.34,
|
|
427
|
+
synth.setTempo({ bpm: 112 })
|
|
428
|
+
synth.playSequence({
|
|
429
|
+
timeUnit: 'beats',
|
|
430
|
+
stepDuration: 0.5,
|
|
431
|
+
voice: { waveType: WAVE.NOISE, volume: 0.34 },
|
|
563
432
|
steps: [
|
|
564
|
-
{
|
|
433
|
+
{ frequencies: [220], overrides: { attack: 1, decay: 65, sustain: 0, release: 55 } },
|
|
565
434
|
{ rest: true },
|
|
566
|
-
{
|
|
567
|
-
{
|
|
435
|
+
{ frequencies: [220], overrides: { attack: 1, decay: 35, sustain: 0, release: 28 } },
|
|
436
|
+
{ frequencies: [220], overrides: { attack: 1, decay: 35, sustain: 0, release: 28 } }
|
|
568
437
|
]
|
|
569
438
|
})
|
|
570
439
|
```
|
|
571
440
|
|
|
572
|
-
The steps keep the eighth-note grid while short decay and `sustain: 0` let
|
|
573
|
-
each hit settle to silence inside its step.
|
|
441
|
+
The steps keep the eighth-note grid while short decay and `sustain: 0` let each hit settle to silence inside its step.
|
|
574
442
|
|
|
575
|
-
Noise steps still need `
|
|
576
|
-
step follows the same shape. The pitch value is not used by the noise source.
|
|
443
|
+
Noise steps still need `frequencies` or `notes` because every sounding pattern step follows the same shape. The pitch value is not used by the noise source.
|
|
577
444
|
|
|
578
445
|
### Filtered noise burst
|
|
579
446
|
|
|
@@ -592,9 +459,7 @@ synth.playTone({
|
|
|
592
459
|
})
|
|
593
460
|
```
|
|
594
461
|
|
|
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.
|
|
462
|
+
The decreasing update rate makes the texture break into slower chunks while the envelope removes energy. Reverse the two rates for an effect that becomes more frantic.
|
|
598
463
|
|
|
599
464
|
### Pluck
|
|
600
465
|
|
|
@@ -629,8 +494,7 @@ synth.playTone({
|
|
|
629
494
|
})
|
|
630
495
|
```
|
|
631
496
|
|
|
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.
|
|
497
|
+
The index falls from 2.2 to 0.25 while the level settles, so the attack is bright and the sustain is mellow.
|
|
634
498
|
|
|
635
499
|
### Bell
|
|
636
500
|
|
|
@@ -650,13 +514,11 @@ synth.playTone({
|
|
|
650
514
|
})
|
|
651
515
|
```
|
|
652
516
|
|
|
653
|
-
The fractional ratio makes the overtones inharmonic. Try 1.4142 or 2.76 for a
|
|
654
|
-
different metal.
|
|
517
|
+
The fractional ratio makes the overtones inharmonic. Try 1.4142 or 2.76 for a different metal.
|
|
655
518
|
|
|
656
519
|
### Wah
|
|
657
520
|
|
|
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.
|
|
521
|
+
The wah in [Resonant filter](#resonant-filter) is also a recipe. Reverse the two cutoffs for a sound that closes instead of opening.
|
|
660
522
|
|
|
661
523
|
### Filtered laser
|
|
662
524
|
|
|
@@ -711,9 +573,7 @@ synth.playChord({
|
|
|
711
573
|
})
|
|
712
574
|
```
|
|
713
575
|
|
|
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.
|
|
576
|
+
Six voices play two pitches, each in three slightly different tunings. The low-pass takes the harshness off the sawtooth stack. Start the engine with `maxVoices` of at least 6.
|
|
717
577
|
|
|
718
578
|
### Kick
|
|
719
579
|
|
|
@@ -731,13 +591,11 @@ synth.playTone({
|
|
|
731
591
|
})
|
|
732
592
|
```
|
|
733
593
|
|
|
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.
|
|
594
|
+
The pitch drop is the punch and the decay is the thump. A phone speaker cannot reproduce 42 Hz, so raise `frequencyEnd` toward 70 for speaker playback.
|
|
736
595
|
|
|
737
596
|
### Simon-style cues
|
|
738
597
|
|
|
739
|
-
Use short, distinct square-wave pitches. Play one tone for the sequence and
|
|
740
|
-
one atomic chord only when demonstrating all pads together.
|
|
598
|
+
Use short, distinct square-wave pitches. Play one tone for the sequence and one atomic chord only when demonstrating all pads together.
|
|
741
599
|
|
|
742
600
|
```javascript
|
|
743
601
|
var SIMON = [329.63, 440, 554.37, 659.25]
|
|
@@ -766,7 +624,25 @@ function playAllSimonPads () {
|
|
|
766
624
|
}
|
|
767
625
|
```
|
|
768
626
|
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
627
|
+
See [Examples](examples.md) for complete code and [Recommendations](recommendations.md) for gain and device-testing advice.
|
|
628
|
+
|
|
629
|
+
## Holding a sound and adding movement
|
|
630
|
+
|
|
631
|
+
Choose a held voice when the ending follows a player action instead of a fixed duration: motor, charge beam, pad or the last chord of a ceremony. `noteOn` starts a positive app-owned ID; `noteOff` begins release from the current level, and compatible `updateVoice` edits ramp over 10 ms. Distinct IDs remain independent events with fixed gain. Reserve enough capacity for their releases and unrelated effects, and release on cancellation as well as ordinary key up. See the [held motor recipe](advanced-examples.md#sustained-game-motor) for retry/cleanup handling.
|
|
632
|
+
|
|
633
|
+
A fanfare can use beat or millisecond sequences with native chords, rests, gate, independent length, swing and pitch-ordered arpeggios. A long release can ring over later steps. Use held voices when release follows presentation or interaction. See [transport usage](guide.md#choose-the-musical-transport).
|
|
634
|
+
|
|
635
|
+
The two additional voice LFOs move filter cutoff, square PWM or sine FM index using sine/triangle shapes. Cutoff movement creates slow breathing or rhythmic filtering; PWM adds changing harmonic color; a small FM-index modulation varies brightness. Free rates reach 20 Hz, and synced rates follow native transport tempo. These slots are separate from pitch vibrato. Avoid deep/high-rate modulation with strong resonance or high-frequency FM; safe parameter clamping does not guarantee a pleasant or alias-free sound. The [two-LFO example](advanced-examples.md#two-voice-lfos) shows a filtered PWM pad.
|
|
636
|
+
|
|
637
|
+
## Native space and creative drive
|
|
638
|
+
|
|
639
|
+
| Processor | What changes | Useful starting region |
|
|
640
|
+
| --- | --- | --- |
|
|
641
|
+
| Stereo chorus | A short interpolated delay with offset LFO phases adds width and movement. | Rate 0.3 to 0.8 Hz, depth 0.15 to 0.35, mix 0.08 to 0.2. |
|
|
642
|
+
| Ping-pong delay | Alternating echoes create rhythmic or spatial repeats. | 180 to 350 ms or synced eighths, feedback 0.15 to 0.35, mix 0.08 to 0.18. |
|
|
643
|
+
| Stereo reverb | Damped comb/allpass reflections create a diffuse decay. | Decay 0.8 to 1.8 seconds, damping 0.5 to 0.7, mix 0.08 to 0.18. |
|
|
644
|
+
| Optional saturation | Soft waveshaping adds harmonics and changes attack/timbre. | Drive 1.2 to 1.6 with a small blend; compare at matched levels. |
|
|
645
|
+
|
|
646
|
+
All processors are off initially, with input gain 1. Enable one shared chain through `setMasterProcessing`; select `applyTo` categories such as `music` and `ambience` to keep explosions dry. Per-voice `effectSend` overrides that category selection. [Configuration](advanced-examples.md#chorus-delay-reverb-and-creative-saturation) and [exact ranges](api.md#setmasterprocessingoptions) explain chorus, delay, reverb and optional saturation.
|
|
647
|
+
|
|
648
|
+
Disabling an effect closes its input gradually and drains the tail before exact bypass; it does not immediately erase its history. Panic invalidates histories. Saturation is a creative choice rather than automatic gain protection; the final limiter stays in place. Match dry/wet comparison levels and watch accumulated limiter reduction so a louder version does not win an A/B comparison merely by level. None of these effects makes a small speaker reproduce missing bass.
|