tutticode 0.0.0-stage → 0.1.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/LICENSE +56 -0
- package/README.md +159 -2
- package/README.zh-CN.md +138 -0
- package/dist/skills/tutticode/SKILL.md +140 -0
- package/dist/skills/tutticode/references/agent-loop.md +103 -0
- package/dist/skills/tutticode/references/devices/aligndelay.md +28 -0
- package/dist/skills/tutticode/references/devices/amp.md +25 -0
- package/dist/skills/tutticode/references/devices/analog.md +180 -0
- package/dist/skills/tutticode/references/devices/arpeggiator.md +37 -0
- package/dist/skills/tutticode/references/devices/autopan.md +37 -0
- package/dist/skills/tutticode/references/devices/autoshift.md +66 -0
- package/dist/skills/tutticode/references/devices/beatrepeat.md +35 -0
- package/dist/skills/tutticode/references/devices/cabinet.md +19 -0
- package/dist/skills/tutticode/references/devices/channeleq.md +23 -0
- package/dist/skills/tutticode/references/devices/chorus.md +31 -0
- package/dist/skills/tutticode/references/devices/collision.md +129 -0
- package/dist/skills/tutticode/references/devices/compressor.md +40 -0
- package/dist/skills/tutticode/references/devices/corpus.md +51 -0
- package/dist/skills/tutticode/references/devices/delay.md +37 -0
- package/dist/skills/tutticode/references/devices/denoise.md +19 -0
- package/dist/skills/tutticode/references/devices/drift.md +82 -0
- package/dist/skills/tutticode/references/devices/drumbuss.md +29 -0
- package/dist/skills/tutticode/references/devices/drumrack.md +225 -0
- package/dist/skills/tutticode/references/devices/dsclang.md +26 -0
- package/dist/skills/tutticode/references/devices/dsclap.md +25 -0
- package/dist/skills/tutticode/references/devices/dscymbal.md +22 -0
- package/dist/skills/tutticode/references/devices/dsfm.md +25 -0
- package/dist/skills/tutticode/references/devices/dshh.md +23 -0
- package/dist/skills/tutticode/references/devices/dskick.md +25 -0
- package/dist/skills/tutticode/references/devices/dssnare.md +23 -0
- package/dist/skills/tutticode/references/devices/dstom.md +24 -0
- package/dist/skills/tutticode/references/devices/dynamic-tube.md +26 -0
- package/dist/skills/tutticode/references/devices/echo.md +56 -0
- package/dist/skills/tutticode/references/devices/electric.md +50 -0
- package/dist/skills/tutticode/references/devices/ensemble.md +129 -0
- package/dist/skills/tutticode/references/devices/eqeight.md +69 -0
- package/dist/skills/tutticode/references/devices/eqthree.md +27 -0
- package/dist/skills/tutticode/references/devices/erosion.md +22 -0
- package/dist/skills/tutticode/references/devices/filter.md +55 -0
- package/dist/skills/tutticode/references/devices/filterdelay.md +37 -0
- package/dist/skills/tutticode/references/devices/gate.md +36 -0
- package/dist/skills/tutticode/references/devices/glue.md +36 -0
- package/dist/skills/tutticode/references/devices/graindelay.md +26 -0
- package/dist/skills/tutticode/references/devices/hybrid-reverb.md +22 -0
- package/dist/skills/tutticode/references/devices/impulse.md +157 -0
- package/dist/skills/tutticode/references/devices/leveler.md +23 -0
- package/dist/skills/tutticode/references/devices/limiter.md +26 -0
- package/dist/skills/tutticode/references/devices/meld.md +239 -0
- package/dist/skills/tutticode/references/devices/midichord.md +46 -0
- package/dist/skills/tutticode/references/devices/midifmarp.md +26 -0
- package/dist/skills/tutticode/references/devices/midinoteecho.md +30 -0
- package/dist/skills/tutticode/references/devices/midinotelength.md +27 -0
- package/dist/skills/tutticode/references/devices/midipitch.md +26 -0
- package/dist/skills/tutticode/references/devices/midirandom.md +24 -0
- package/dist/skills/tutticode/references/devices/midiscale.md +25 -0
- package/dist/skills/tutticode/references/devices/midivelocity.md +27 -0
- package/dist/skills/tutticode/references/devices/multibanddynamics.md +62 -0
- package/dist/skills/tutticode/references/devices/operator.md +163 -0
- package/dist/skills/tutticode/references/devices/overdrive.md +24 -0
- package/dist/skills/tutticode/references/devices/pedal.md +26 -0
- package/dist/skills/tutticode/references/devices/phaserflanger.md +42 -0
- package/dist/skills/tutticode/references/devices/pitchshifter.md +56 -0
- package/dist/skills/tutticode/references/devices/redux.md +27 -0
- package/dist/skills/tutticode/references/devices/resonator.md +49 -0
- package/dist/skills/tutticode/references/devices/reverb.md +43 -0
- package/dist/skills/tutticode/references/devices/roar.md +70 -0
- package/dist/skills/tutticode/references/devices/sampler.md +228 -0
- package/dist/skills/tutticode/references/devices/saturator.md +24 -0
- package/dist/skills/tutticode/references/devices/simpler.md +230 -0
- package/dist/skills/tutticode/references/devices/sixop.md +190 -0
- package/dist/skills/tutticode/references/devices/spectralresonator.md +42 -0
- package/dist/skills/tutticode/references/devices/spectraltime.md +45 -0
- package/dist/skills/tutticode/references/devices/synth.md +28 -0
- package/dist/skills/tutticode/references/devices/tension.md +117 -0
- package/dist/skills/tutticode/references/devices/utility.md +29 -0
- package/dist/skills/tutticode/references/devices/vinyl.md +31 -0
- package/dist/skills/tutticode/references/devices/vocoder.md +41 -0
- package/dist/skills/tutticode/references/devices/wavetable.md +128 -0
- package/dist/skills/tutticode/references/devices.md +114 -0
- package/dist/skills/tutticode/references/effect-controls.md +145 -0
- package/dist/skills/tutticode/references/first-sounds.md +89 -0
- package/dist/skills/tutticode/references/for-agents.md +119 -0
- package/dist/skills/tutticode/references/functions.md +1848 -0
- package/dist/skills/tutticode/references/getting-started.md +79 -0
- package/dist/skills/tutticode/references/harmony-and-scales.md +105 -0
- package/dist/skills/tutticode/references/javascript.md +90 -0
- package/dist/skills/tutticode/references/mini-notation.md +120 -0
- package/dist/skills/tutticode/references/mixing.md +101 -0
- package/dist/skills/tutticode/references/muse.md +67 -0
- package/dist/skills/tutticode/references/sample-operations.md +102 -0
- package/dist/skills/tutticode/references/sounds.md +109 -0
- package/dist/skills/tutticode/references/time-and-structure.md +161 -0
- package/dist/skills/tutticode/references/tuttidaw-extensions.md +131 -0
- package/dist/skills/tutticode-sound-for-media/SKILL.md +97 -0
- package/dist/skills/tutticode-sound-for-media/references/music-recipes.md +86 -0
- package/dist/skills/tutticode-sound-for-media/references/sfx-recipes.md +129 -0
- package/dist/tutticode.cjs +18694 -0
- package/package.json +39 -4
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Sounds
|
|
2
|
+
|
|
3
|
+
Drum kits and banks, synth waveforms, General MIDI instrument names, Ensemble sounds and your own samples.
|
|
4
|
+
|
|
5
|
+
A voice's sound decides which TuttiDAW instrument plays it. You can name
|
|
6
|
+
sounds the Strudel way with `s(...)`, or load any TuttiDAW instrument by name
|
|
7
|
+
with `.inst(...)` (next chapters).
|
|
8
|
+
|
|
9
|
+
## Drum kits
|
|
10
|
+
|
|
11
|
+
Drum names (`bd sd rim cp hh oh cr rd ht mt lt sh cb`) play the pads of a
|
|
12
|
+
Drum Rack. Without a bank the voice uses the 808 Core Kit; `.bank(...)`
|
|
13
|
+
chooses another factory kit by its machine (`tr909`, `tr707`, `tr606`,
|
|
14
|
+
`tr505`, `linn`, `dmx`, `cr78`).
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
setcpm(30)
|
|
18
|
+
kit: s("bd [~ bd] sd ~, [~ hh]*4, ~ ~ ~ oh").bank("tr909")
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Strudel's banked names such as `RolandTR909_bd` are read as that drum. A
|
|
22
|
+
number after a colon (`bd:2`) or `.n(...)` picks another variant of the same
|
|
23
|
+
drum where the kit has one.
|
|
24
|
+
|
|
25
|
+
## Synth waveforms
|
|
26
|
+
|
|
27
|
+
`sine`, `triangle`, `square` and `sawtooth` (short: `sin`, `tri`, `sqr`,
|
|
28
|
+
`saw`) play on a TuttiDAW synth whose envelope is set to match Strudel's
|
|
29
|
+
built-in synth. `supersaw` is a detuned stack of saws.
|
|
30
|
+
|
|
31
|
+
```js
|
|
32
|
+
note("c2 [~ c2] eb2 [g1 bb1]").s("sawtooth").lpf(700)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
note("<[c3,eb3,g3] [ab2,c3,eb3]>").s("supersaw").gain(0.6)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`white`, `pink` and `brown` are noise, from bright to soft (pink falls
|
|
40
|
+
3 dB per octave, brown 6 dB). They take the envelope and filters like the
|
|
41
|
+
waveforms: short noise bursts make hats. `crackle` is approximated with
|
|
42
|
+
Vinyl Distortion's crackle.
|
|
43
|
+
|
|
44
|
+
```js
|
|
45
|
+
s("<white pink brown>*8").decay(0.04).sustain(0)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Instrument names
|
|
49
|
+
|
|
50
|
+
`piano` plays TuttiDAW's sampled grand piano. General MIDI names in Strudel's
|
|
51
|
+
`gm_` style play the closest TuttiDAW instrument: for example `gm_piano`,
|
|
52
|
+
`gm_epiano1`, `gm_acoustic_bass`, `gm_violin`, `gm_vibraphone`, `gm_flute`,
|
|
53
|
+
`gm_pad_warm`, and the Asian instruments `gm_koto`, `gm_dulcimer` and
|
|
54
|
+
`gm_shakuhachi`.
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
setcpm(22)
|
|
58
|
+
koto: n("0 2 4 <7 5> 4 2").scale("D:minor:pentatonic").s("gm_koto")
|
|
59
|
+
bass: note("<d2 a1 bb1 c2>").s("gm_acoustic_bass")
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
A name TuttiDAW does not know still plays: drum-like names fall back to a
|
|
63
|
+
drum pad, everything else to a synth, with a warning in the diagnostics.
|
|
64
|
+
|
|
65
|
+
## Ensemble sounds
|
|
66
|
+
|
|
67
|
+
Ensemble is TuttiDAW's multi-engine sound module (Physical, Sample, Duo, FM6
|
|
68
|
+
and more). Its factory sounds are named `<Engine> <SOUND>`, for example
|
|
69
|
+
`Physical PLUCK` or `Sample FLUTE`, and are loaded with `.inst`:
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
setcpm(24)
|
|
73
|
+
pluck: n("0 2 4 6 4 2").scale("E:minor").inst("Ensemble:Physical PLUCK")
|
|
74
|
+
flute: note("<b4 a4 g4 e4>").inst("Ensemble:Sample FLUTE")
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Ensemble parts play inside an Ensemble Set with its own chorus, delay and
|
|
78
|
+
reverb. On TuttiCode up to four Ensemble voices share one Set; **Open in
|
|
79
|
+
TuttiDAW** builds the same Set in your project. The [device
|
|
80
|
+
catalogue](devices.md) lists every Ensemble sound.
|
|
81
|
+
|
|
82
|
+
## Your own samples
|
|
83
|
+
|
|
84
|
+
`samples(...)` declares audio files hosted on the web (HTTPS). The names you
|
|
85
|
+
declare then work in `s(...)` like the built-in ones. A `github:user/repo`
|
|
86
|
+
shortcut reads the `strudel.json` sample map at the root of that repository.
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
samples({ stab: "https://example.com/sounds/stab.wav" })
|
|
90
|
+
s("stab ~ stab [~ stab]")
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
What TuttiDAW does with them:
|
|
94
|
+
|
|
95
|
+
- **Nothing is downloaded until you ask.** TuttiCode loads new samples
|
|
96
|
+
only when you press **Play** or **Evaluate** yourself; typing never starts a
|
|
97
|
+
download, and Muse's edits never do either.
|
|
98
|
+
- Files are fetched by your browser from where they are hosted, kept in
|
|
99
|
+
memory for the session, and never uploaded to TuttiDAW. A saved project
|
|
100
|
+
stores the links, not the audio.
|
|
101
|
+
- Limits keep pages safe: at most 8 MB per file, 32 MB in total, 10 seconds
|
|
102
|
+
per download, mono or stereo audio up to 120 seconds.
|
|
103
|
+
- If a file cannot load, the voice plays a built-in sound and the diagnostics
|
|
104
|
+
say which file failed.
|
|
105
|
+
|
|
106
|
+
Only use samples you are allowed to use; TuttiDAW plays them from their host
|
|
107
|
+
and does not check their licence.
|
|
108
|
+
|
|
109
|
+
Source: https://tuttidaw.com/code/learn/sounds
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Time and structure
|
|
2
|
+
|
|
3
|
+
Functions that speed up, shift, reverse, repeat and combine patterns, and arrange them into sections.
|
|
4
|
+
|
|
5
|
+
Mini-notation writes one cycle. Methods - the `.name(...)` calls after a
|
|
6
|
+
pattern - change how it unfolds over time. They can be chained, and most
|
|
7
|
+
take patterns as arguments too.
|
|
8
|
+
|
|
9
|
+
## Speed: fast and slow
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
note("c3 eb3 g3 bb3").fast(2)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
note("c3 eb3 g3 bb3").slow(2)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
A patterned argument changes the speed from bar to bar:
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
s("bd sd").fast("<1 2 4 2>")
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Shifting: early and late
|
|
26
|
+
|
|
27
|
+
`.late(t)` delays a pattern by `t` cycles; `.early(t)` moves it forward. A
|
|
28
|
+
quarter of a cycle is one beat.
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
stack(
|
|
32
|
+
s("bd*4"),
|
|
33
|
+
s("cp*2").late(0.25)
|
|
34
|
+
)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Reversing and rotating
|
|
38
|
+
|
|
39
|
+
`.rev()` plays each cycle backwards, `.palindrome()` alternates forwards and
|
|
40
|
+
backwards, and `.iter(n)` starts each cycle one step further into the pattern.
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
note("c3 d3 e3 g3").iter(4)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```js
|
|
47
|
+
note("c3 d3 e3 g3 a3").palindrome()
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Repeating: ply
|
|
51
|
+
|
|
52
|
+
`.ply(n)` repeats every event `n` times within its own length - a quick way
|
|
53
|
+
to make rolls.
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
s("bd sd bd [sd cp]").ply("<1 2>")
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Every few cycles: every, lastOf, chunk
|
|
60
|
+
|
|
61
|
+
`.every(n, f)` applies the change `f` on the first of every `n` cycles;
|
|
62
|
+
`.lastOf(n, f)` on the last one, which suits a fill at the end of a phrase.
|
|
63
|
+
`f` is a small function written with an arrow: `x => x.fast(2)`.
|
|
64
|
+
|
|
65
|
+
```js
|
|
66
|
+
s("bd sd bd sd").lastOf(4, x => x.ply(2))
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`.chunk(n, f)` applies `f` to one quarter (one `n`th) of the cycle, moving
|
|
70
|
+
along each cycle.
|
|
71
|
+
|
|
72
|
+
```js
|
|
73
|
+
note("c3 d3 e3 f3").chunk(4, x => x.add(note(12)))
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Layering: off, superimpose, layer, jux
|
|
77
|
+
|
|
78
|
+
`.off(t, f)` adds a copy that is shifted by `t` and changed by `f` - an echo
|
|
79
|
+
with a twist.
|
|
80
|
+
|
|
81
|
+
```js
|
|
82
|
+
note("c3 eb3 g3 bb3").off(1/8, x => x.add(note(12)))
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`.superimpose(f)` stacks a changed copy without moving it; `.jux(f)` puts the
|
|
86
|
+
original on the left and the changed copy on the right.
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
note("c3 e3 g3 e3").superimpose(x => x.add(note(7)))
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
```js
|
|
93
|
+
s("bd hh sd hh").jux(rev)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Echoes: echo
|
|
97
|
+
|
|
98
|
+
`.echo(times, time, feedback)` repeats each event, quieter each time.
|
|
99
|
+
|
|
100
|
+
```js
|
|
101
|
+
s("cp ~ ~ ~").echo(3, 1/8, 0.6)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Rhythm from another pattern: struct, mask, euclid
|
|
105
|
+
|
|
106
|
+
`.struct("x ~ x x")` plays the values on the rhythm of `x`s.
|
|
107
|
+
`.mask("1 0 1 1")` silences the parts where the mask is 0. `.euclid(k, n)` is
|
|
108
|
+
the method form of `(k,n)`.
|
|
109
|
+
|
|
110
|
+
```js
|
|
111
|
+
note("[c3,eb3,g3]").struct("x ~ x x ~ x ~ ~")
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
```js
|
|
115
|
+
note("c2").euclid(5, 8)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Swing
|
|
119
|
+
|
|
120
|
+
`.swingBy(amount, n)` divides the cycle into `n` slices and delays the second
|
|
121
|
+
half of each slice. `1/3` gives a triplet feel; `.swing(n)` is a shortcut for
|
|
122
|
+
it.
|
|
123
|
+
|
|
124
|
+
```js
|
|
125
|
+
s("hh*8").swingBy(1/3, 4)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Combining patterns: stack, cat, seq
|
|
129
|
+
|
|
130
|
+
`stack(a, b)` plays patterns together, `cat(a, b)` plays one per cycle in turn
|
|
131
|
+
and `seq(a, b)` squeezes them into one cycle.
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
cat(
|
|
135
|
+
note("c3 e3 g3 e3"),
|
|
136
|
+
note("a2 c3 e3 c3")
|
|
137
|
+
)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Sections: arrange
|
|
141
|
+
|
|
142
|
+
`arrange([cycles, pattern], ...)` builds a song form: each pattern plays for
|
|
143
|
+
its number of cycles, then the next one, and the whole thing loops.
|
|
144
|
+
|
|
145
|
+
```js
|
|
146
|
+
const verse = note("c3 eb3 g3 eb3")
|
|
147
|
+
const chorus = note("ab2 c3 eb3 c3").fast(2)
|
|
148
|
+
arrange([4, verse], [2, chorus])
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Randomness that repeats
|
|
152
|
+
|
|
153
|
+
`.sometimes(f)` applies `f` to about half of the events, `.degradeBy(p)` drops
|
|
154
|
+
events with probability `p`. Like `?` and `|`, they are seeded, so a program
|
|
155
|
+
always plays the same way.
|
|
156
|
+
|
|
157
|
+
```js
|
|
158
|
+
s("hh*16").degradeBy(0.3).sometimes(x => x.velocity(0.5))
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Source: https://tuttidaw.com/code/learn/time-and-structure
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# TuttiDAW extensions
|
|
2
|
+
|
|
3
|
+
Load any TuttiDAW instrument, MIDI effect or audio effect with presets and parameters; voices, groups and Open in TuttiDAW.
|
|
4
|
+
|
|
5
|
+
Strudel controls such as `.lpf` or `.room` describe a sound in general terms.
|
|
6
|
+
TuttiDAW adds three methods that name **real devices** - the same ones you
|
|
7
|
+
find in the studio's browser - with their factory presets and parameters:
|
|
8
|
+
|
|
9
|
+
| Method | What it adds | Where it goes |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `.inst(name, params)` | an instrument (one per voice) | the voice's instrument slot |
|
|
12
|
+
| `.midifx(name, params)` | a MIDI effect | before the instrument, in call order |
|
|
13
|
+
| `.fx(name, params)` | an audio effect | after the instrument, in call order |
|
|
14
|
+
|
|
15
|
+
These are TuttiDAW-only: a program that uses them does not play on
|
|
16
|
+
strudel.cc, so TuttiCode hides its "Open in strudel.cc" link for it.
|
|
17
|
+
|
|
18
|
+
## Instruments: .inst
|
|
19
|
+
|
|
20
|
+
The name is a device, or a device and one of its factory presets joined by a
|
|
21
|
+
colon. Case and punctuation do not matter.
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
setcpm(30)
|
|
25
|
+
bass: note("c2 [~ c2] eb2 [~ g1]").inst("Drift:Deep Bass")
|
|
26
|
+
keys: chord("<Cm7 Ab^7 Fm7 G7>").voicing().inst("Electric")
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`.inst` decides the instrument, even when the voice also has an `s(...)`.
|
|
30
|
+
On a drum voice `s(...)` still picks the pads, so you can play the names on
|
|
31
|
+
any kit:
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
s("bd*2 [~ bd] sd ~, hh*8").inst("Drum Rack:909 Core Kit")
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Audio effects: .fx
|
|
38
|
+
|
|
39
|
+
Effects are added after the instrument in the order you call them. Use
|
|
40
|
+
several `.fx` calls to build a chain.
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
note("<[c3,eb3,g3] [bb2,d3,f3]>")
|
|
44
|
+
.inst("Wavetable")
|
|
45
|
+
.fx("Chorus:Wide Classic")
|
|
46
|
+
.fx("Reverb:Large Hall", { decayTime: "4s", dryWetBalance: 0.35 })
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## MIDI effects: .midifx
|
|
50
|
+
|
|
51
|
+
MIDI effects change the notes on their way into the instrument - for example
|
|
52
|
+
an Arpeggiator turns held chords into runs. The clip keeps the notes you
|
|
53
|
+
wrote; the effect plays them live, as in the studio.
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
note("<[c3,eb3,g3] [ab2,c3,eb3]>")
|
|
57
|
+
.midifx("Arpeggiator", { style: "UpDown", rate: "1/16" })
|
|
58
|
+
.inst("Operator")
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
note("c3 ~ f3 ~").midifx("Chord:Minor 7 Chord").inst("Electric")
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Parameters
|
|
66
|
+
|
|
67
|
+
The second argument is an object of parameter values:
|
|
68
|
+
|
|
69
|
+
- **Keys** are the device's parameter keys (`decayTime`, `cutoff`,
|
|
70
|
+
`dryWetBalance`); a parameter's unique Live label works too. The
|
|
71
|
+
[device catalogue](devices.md) lists every key with its range and unit.
|
|
72
|
+
- **Numbers** are in the parameter's own unit (Hz, ms, dB, semitones). A
|
|
73
|
+
string with a unit is converted: `"250ms"`, `"2s"`, `"-6dB"`,
|
|
74
|
+
`"1.2kHz"`, `"30%"`.
|
|
75
|
+
- **Choices** take their label (`"UpDown"`, `"1/16"`, `"Dorian"`) or a
|
|
76
|
+
0-based index; switches take `true` or `false`.
|
|
77
|
+
- Two reserved keys: `on` switches the device on or off, `id` names a device
|
|
78
|
+
when a voice uses the same one twice.
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
s("bd*4, ~ sd, hh*8")
|
|
82
|
+
.fx("Saturator", { drive: "6dB" })
|
|
83
|
+
.fx("Compressor", { threshold: "-18dB", ratio: 4, attack: "10ms" })
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Values outside a parameter's range are clamped, with a warning. Device
|
|
87
|
+
parameters take constant values for now; a pattern such as `"<300 600>"` as a
|
|
88
|
+
device parameter is reported and not applied yet. Strudel controls
|
|
89
|
+
(`.lpf("<300 600>")`) can already change over time.
|
|
90
|
+
|
|
91
|
+
## Strudel controls and devices together
|
|
92
|
+
|
|
93
|
+
Strudel controls keep working next to devices: `.lpf(...)` still adds an
|
|
94
|
+
Auto Filter. When a voice names the same kind of device itself, the control
|
|
95
|
+
goes onto that device instead of adding a second one - `.room(0.4)` with
|
|
96
|
+
`.fx("Reverb:...")` sets that Reverb's mix.
|
|
97
|
+
|
|
98
|
+
## Inline controls: slider and toggle
|
|
99
|
+
|
|
100
|
+
`slider(value, min, max)` puts a small slider in the editor next to the
|
|
101
|
+
number; dragging it changes the program while it plays. `toggle(1)` (a
|
|
102
|
+
TuttiDAW addition) puts an on/off switch there.
|
|
103
|
+
|
|
104
|
+
```js
|
|
105
|
+
note("c2*8").s("sawtooth").lpf(slider(800, 200, 4000))
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```js
|
|
109
|
+
stack(
|
|
110
|
+
s("bd*4"),
|
|
111
|
+
s("hh*8").mask(toggle(1))
|
|
112
|
+
)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Voices become tracks
|
|
116
|
+
|
|
117
|
+
Each labelled voice of a program is one track. **Open in TuttiDAW** on
|
|
118
|
+
TuttiCode saves the program as a studio project:
|
|
119
|
+
|
|
120
|
+
- the program lives on a **group track**: its `{}` button opens the code,
|
|
121
|
+
and evaluating there updates every voice;
|
|
122
|
+
- each voice is a track in the group, with its instrument, effects and a
|
|
123
|
+
Pattern Clip holding that voice's code;
|
|
124
|
+
- moving controls become clip envelopes.
|
|
125
|
+
|
|
126
|
+
Editing a voice by hand - its notes, or a parameter the code set - detaches
|
|
127
|
+
that voice from the code, so your edit is kept. **Re-attach** gives it back
|
|
128
|
+
to the code. A single Pattern Clip (code in a MIDI clip without a group)
|
|
129
|
+
plays notes only: devices named in its code are not applied there.
|
|
130
|
+
|
|
131
|
+
Source: https://tuttidaw.com/code/learn/tuttidaw-extensions
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tutticode-sound-for-media
|
|
3
|
+
description: Make music beds, loops, stems and sound effects (riser, impact, whoosh, UI click/confirm/error, notification, transition, ambience) for videos, apps and games with TuttiCode, rendered to files at an exact length and a platform loudness (-14 LUFS web/social, -16 podcasts, -23 broadcast) with the tutticode tools. Use when a video, app, game, podcast or presentation needs music or sound effects, or when asked to render audio of a given length or loudness.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Sound for videos, apps and games with TuttiCode
|
|
7
|
+
|
|
8
|
+
Make music beds, loops, stems and sound effects for media in TuttiCode, and
|
|
9
|
+
deliver files at the right length and loudness. The language itself is in
|
|
10
|
+
the `tutticode` skill (install both: `tutticode skills install`); the tools
|
|
11
|
+
are `code_check`, `code_render`, `code_compare` from the local `tutticode`
|
|
12
|
+
MCP server or CLI (default: free, renders in the user's browser, writes
|
|
13
|
+
files) or TuttiDAW's web MCP (server renders, Muse points, 60 s, no files:
|
|
14
|
+
a `listenUrl`).
|
|
15
|
+
|
|
16
|
+
## Workflow
|
|
17
|
+
|
|
18
|
+
1. **Brief.** Pin down: what it is for (video, app UI, game, podcast),
|
|
19
|
+
mood, exact length in seconds (or loop), where it plays (the loudness
|
|
20
|
+
target below), whether it sits under speech, stems or not, file format.
|
|
21
|
+
Ask only what you cannot infer.
|
|
22
|
+
2. **Pick a recipe** nearest the brief: `references/sfx-recipes.md` for
|
|
23
|
+
effects, `references/music-recipes.md` for beds and loops. Recipes are
|
|
24
|
+
tested to compile and render clean.
|
|
25
|
+
3. **Write**: adapt the recipe (key, chords, sounds, tempo, length). Label
|
|
26
|
+
every voice (`drums:`, `pad:`): labels name the stems and the tracks.
|
|
27
|
+
4. **`code_check`**: fix every error, then the mix warnings.
|
|
28
|
+
5. **`code_render`** with the delivery settings: the exact length
|
|
29
|
+
(`seconds`, or `loops` for a loop), `fadeIn` / `fadeOut`, a `tail` for
|
|
30
|
+
reverbs, `lufs` for the platform, `stems: true` if the editor wants
|
|
31
|
+
them, `out` with the extension of the format (`.wav`, `.flac`, `.mp3`).
|
|
32
|
+
6. **Read the stats** (the `tutticode` skill's `references/agent-loop.md`):
|
|
33
|
+
loudness and true peak, clipping, silent bars, every voice's level,
|
|
34
|
+
`barTimes` / `beatTimes` for syncing cuts.
|
|
35
|
+
7. **Revise** one thing at a time and render again; `code_compare` with
|
|
36
|
+
`againstRenderId` says whether the edit moved what you meant.
|
|
37
|
+
8. **Deliver**: the file paths, the length and loudness, and the
|
|
38
|
+
`editUrl` (local) or `listenUrl` (web).
|
|
39
|
+
|
|
40
|
+
Recipe index:
|
|
41
|
+
|
|
42
|
+
- Sound effects (`references/sfx-recipes.md`): `riser`, `impact`, `whoosh`, `ui-click`, `ui-confirm`, `ui-error`, `notification`, `transition`, `ambience-bed`
|
|
43
|
+
- Music beds (`references/music-recipes.md`): `lofi-bed`, `upbeat-pop-bed`, `cinematic-tension`, `ambient-bed`, `chiptune-loop`
|
|
44
|
+
|
|
45
|
+
## Loudness and length
|
|
46
|
+
|
|
47
|
+
| Where it plays | `lufs` |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| Web, social video, apps, games (music) | -14 |
|
|
50
|
+
| Podcasts, video beds | -16 |
|
|
51
|
+
| A bed under a voice-over | -20..-24 (or -16 and let the editor duck it) |
|
|
52
|
+
| Broadcast (EBU R128) | -23 |
|
|
53
|
+
| Short sound effects | -18..-26: peaky, see each recipe |
|
|
54
|
+
|
|
55
|
+
- True peak ceiling -1 dBTP (the default). `lufs` is one static gain, never
|
|
56
|
+
a limiter: a peaky program fails with `clip`. Then lower the target, or
|
|
57
|
+
lower the loudest voice's `.gain` and render again. Where loudness
|
|
58
|
+
matters (music beds at -14..-17), end the program with
|
|
59
|
+
`master.fx("Limiter", {gainDb: 3, ceiling: -3})`: the program's own bus
|
|
60
|
+
catches the peaks before the gain, as the music recipes do.
|
|
61
|
+
- Exact durations: `seconds` cuts exactly. A one-shot effect is one bar
|
|
62
|
+
long: `setcpm` sets the bar (`setcpm(60)` = 1 s, `setcpm(15)` = 4 s).
|
|
63
|
+
- Video beds: `fadeIn` 1-3 s, `fadeOut` 2-5 s, `tail` for the reverb.
|
|
64
|
+
- Loops for apps and games: `loops` N with `tail: 0`, no fades, so the file
|
|
65
|
+
is exactly N loops and repeats in time; keep the last step short.
|
|
66
|
+
- Stems: `stems: true` writes one file per voice (named by the labels); a
|
|
67
|
+
`lufs` gain applies to the stems too, so they still sum to the mix.
|
|
68
|
+
|
|
69
|
+
## Quality bar: never deliver
|
|
70
|
+
|
|
71
|
+
- a render whose `check.diagnostics` has an `error`, or the `clip` error;
|
|
72
|
+
- clipping (`analysis.loudness.clipping`) or a true peak above -1 dBTP;
|
|
73
|
+
- a dead mix: integrated loudness null / -70, an unplanned silent bar, or a
|
|
74
|
+
voice whose `lufs` is null;
|
|
75
|
+
- a length other than the one asked for (check `window.seconds`, plus the
|
|
76
|
+
tail);
|
|
77
|
+
- without the `editUrl` (or `listenUrl`): always give it to the user, it
|
|
78
|
+
opens the program in TuttiCode to keep editing.
|
|
79
|
+
|
|
80
|
+
## Sound effects
|
|
81
|
+
|
|
82
|
+
Synth voices work everywhere. Noise is `s("white")`, `s("pink")` or
|
|
83
|
+
`s("brown")` (hard to soft), shaped by the envelope and filters like any
|
|
84
|
+
synth voice (`s("crackle")` is approximated). Pitch sweeps
|
|
85
|
+
use the pitch envelope (`.penv(semitones).pattack(s)` / `.pdecay(s)`),
|
|
86
|
+
swells the amplitude envelope (`.attack` / `.decay` / `.sustain(0)`), and
|
|
87
|
+
`gm_reverse_cymbal`, `gm_fx_rain`, `gm_seashore`, `gm_fx_sci_fi` are ready
|
|
88
|
+
riser, rain, waves and sci-fi textures (`note("c4").s(...)`).
|
|
89
|
+
|
|
90
|
+
## References
|
|
91
|
+
|
|
92
|
+
- `references/sfx-recipes.md`: riser, impact, whoosh, UI click / confirm /
|
|
93
|
+
error, notification, transition, ambience bed; each with render settings.
|
|
94
|
+
- `references/music-recipes.md`: music beds and loops by mood, with their
|
|
95
|
+
Muse style for `code_compare`.
|
|
96
|
+
- The `tutticode` skill: the language, `references/agent-loop.md` (every
|
|
97
|
+
report field), functions and devices.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Music-bed recipes
|
|
2
|
+
|
|
3
|
+
Loopable background music for videos, apps and games. Each recipe compiles
|
|
4
|
+
and renders (tested on every change). Start from the one nearest the brief,
|
|
5
|
+
change the key, chords and sounds, then check and render. `style` is the
|
|
6
|
+
Muse style id to compare with (`code_compare { goals: { style } }`); a
|
|
7
|
+
bed without a master chain sits a few LU under a style's mastered loudness,
|
|
8
|
+
so compare its spectrum and balance, and set the level with `lufs`.
|
|
9
|
+
|
|
10
|
+
## Lo-fi bed (`lofi-bed`)
|
|
11
|
+
|
|
12
|
+
Study, cooking, vlog and tutorial backgrounds: 80 BPM, swung drums, electric piano, soft bass. Style: `lofi-hip-hop`.
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
setcpm(20) // 80 BPM
|
|
16
|
+
drums: s("bd ~ [~ bd] ~, ~ sd, hh*8").bank("tr808").swingBy(1/6, 4).gain(0.45)
|
|
17
|
+
keys: chord("<Fm9 Bbm9>").voicing().inst("Electric").gain(0.7)
|
|
18
|
+
bass: n("<0 -4>").scale("F2:minor").s("sawtooth").lpf(400).gain(0.8)
|
|
19
|
+
master.fx("Limiter", {gainDb: 3, ceiling: -3}) // fewer peaks at the loudness target
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Render: `tutticode render lofi-bed.tc -o lofi-bed.wav --loops 8 --fade-out 3 --lufs -19`, or `code_render` with `{"loops":8,"fadeOut":3,"lufs":-19}`.
|
|
23
|
+
|
|
24
|
+
Vary: Another key: change the chords and the scale together. Under speech: drop the keys gain to 0.4 and render at -22 LUFS.
|
|
25
|
+
|
|
26
|
+
## Upbeat pop bed (`upbeat-pop-bed`)
|
|
27
|
+
|
|
28
|
+
App promos, product launches, upbeat social videos: 120 BPM four-on-the-floor, I-V-vi-IV. Style: `modern-pop`.
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
setcpm(30) // 120 BPM
|
|
32
|
+
drums: s("bd*4, ~ cp ~ cp, hh*8").bank("tr909").gain(0.6)
|
|
33
|
+
chords: chord("<C G Am F>").voicing().s("supersaw").release(0.2).lpf(2500).gain(0.2)
|
|
34
|
+
bass: note("<c2 g1 a1 f1>").ply(4).s("sawtooth").lpf(600).gain(0.6)
|
|
35
|
+
lead: n("<[0 2 4 2] [4 6 8 6] [5 7 9 7] [3 5 7 5]>").scale("C5:major").s("triangle").gain(0.4)
|
|
36
|
+
master.fx("Limiter", {gainDb: 3, ceiling: -3})
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Render: `tutticode render upbeat-pop-bed.tc -o upbeat-pop-bed.wav --loops 2 --fade-out 2 --lufs -17`, or `code_render` with `{"loops":2,"fadeOut":2,"lufs":-17}`.
|
|
40
|
+
|
|
41
|
+
Vary: The lead arpeggiates each chord (scale degrees of the chord tones): keep that relation when you change the chords. Under a voice-over: mute the lead (_lead:).
|
|
42
|
+
|
|
43
|
+
## Cinematic tension (`cinematic-tension`)
|
|
44
|
+
|
|
45
|
+
Trailers, reveals, suspense, game menus: a low drone, slow minor strings and a ticking pulse at 60 BPM. Style: `cinematic`.
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
setcpm(15) // 60 BPM
|
|
49
|
+
drone: note("c2").s("sawtooth").lpf(300).attack(1).release(1).gain(0.5)
|
|
50
|
+
strings: chord("<Cm Ab>").voicing().s("supersaw").attack(2).release(2).lpf(1200).gain(0.3).room(0.7)
|
|
51
|
+
pulse: note("c6*8").s("sine").decay(0.1).sustain(0).gain(0.4)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Render: `tutticode render cinematic-tension.tc -o cinematic-tension.wav --loops 3 --tail 3 --fade-out 4 --lufs -18`, or `code_render` with `{"loops":3,"tail":3,"fadeOut":4,"lufs":-18}`.
|
|
55
|
+
|
|
56
|
+
Vary: Rising tension: double the pulse (c6*16) for the last loop, or render the riser over the end.
|
|
57
|
+
|
|
58
|
+
## Ambient bed (`ambient-bed`)
|
|
59
|
+
|
|
60
|
+
Meditation, wellness, slow product shots: a wide pad and sparse echoing bells at 48 BPM. Style: `ambient`.
|
|
61
|
+
|
|
62
|
+
```js
|
|
63
|
+
setcpm(12) // 48 BPM
|
|
64
|
+
pad: chord("<Dm F>").voicing().s("supersaw").attack(2).release(3).lpf(1000).gain(0.3).room(0.8).size(0.9)
|
|
65
|
+
bells: n("0 2 4 7 4 2").scale("D5:minor").s("sine").decay(0.8).sustain(0).delay(0.4).gain(0.4)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Render: `tutticode render ambient-bed.tc -o ambient-bed.wav --loops 3 --tail 4 --fade-in 3 --fade-out 5 --lufs -20`, or `code_render` with `{"loops":3,"tail":4,"fadeIn":3,"fadeOut":5,"lufs":-20}`.
|
|
69
|
+
|
|
70
|
+
Vary: The bells play chord tones of both chords (d f a): keep them on tones the chords share when you change the harmony.
|
|
71
|
+
|
|
72
|
+
## Chiptune game loop (`chiptune-loop`)
|
|
73
|
+
|
|
74
|
+
Retro and casual games, pixel-art videos: 150 BPM square-wave lead and bass that loop seamlessly.
|
|
75
|
+
|
|
76
|
+
```js
|
|
77
|
+
setcpm(37.5) // 150 BPM
|
|
78
|
+
lead: n("<[0 2 4 7] [4 2 0 ~]>*2").scale("C4:major").s("square").decay(0.12).sustain(0.3).gain(0.35)
|
|
79
|
+
bass: note("<c2 a1 f1 g1>").ply(8).s("square").lpf(800).gain(0.45)
|
|
80
|
+
drums: s("bd ~ sd ~, hh*8").bank("tr808").gain(0.6)
|
|
81
|
+
master.fx("Limiter", {gainDb: 3, ceiling: -3})
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Render: `tutticode render chiptune-loop.tc -o chiptune-loop.wav --loops 2 --tail 0 --lufs -19`, or `code_render` with `{"loops":2,"tail":0,"lufs":-19}`.
|
|
85
|
+
|
|
86
|
+
Vary: A game loop file has no fades and `tail: 0`: exactly N loops, so it repeats in time. A boss level: setcpm(45) and a minor scale.
|