tutticode 0.0.0-stage → 0.1.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.
Files changed (99) hide show
  1. package/LICENSE +56 -0
  2. package/README.md +163 -2
  3. package/README.zh-CN.md +141 -0
  4. package/dist/skills/tutticode/SKILL.md +141 -0
  5. package/dist/skills/tutticode/references/agent-loop.md +112 -0
  6. package/dist/skills/tutticode/references/devices/aligndelay.md +28 -0
  7. package/dist/skills/tutticode/references/devices/amp.md +25 -0
  8. package/dist/skills/tutticode/references/devices/analog.md +180 -0
  9. package/dist/skills/tutticode/references/devices/arpeggiator.md +37 -0
  10. package/dist/skills/tutticode/references/devices/autopan.md +37 -0
  11. package/dist/skills/tutticode/references/devices/autoshift.md +66 -0
  12. package/dist/skills/tutticode/references/devices/beatrepeat.md +35 -0
  13. package/dist/skills/tutticode/references/devices/cabinet.md +19 -0
  14. package/dist/skills/tutticode/references/devices/channeleq.md +23 -0
  15. package/dist/skills/tutticode/references/devices/chorus.md +31 -0
  16. package/dist/skills/tutticode/references/devices/collision.md +129 -0
  17. package/dist/skills/tutticode/references/devices/compressor.md +40 -0
  18. package/dist/skills/tutticode/references/devices/corpus.md +51 -0
  19. package/dist/skills/tutticode/references/devices/delay.md +37 -0
  20. package/dist/skills/tutticode/references/devices/denoise.md +19 -0
  21. package/dist/skills/tutticode/references/devices/drift.md +82 -0
  22. package/dist/skills/tutticode/references/devices/drumbuss.md +29 -0
  23. package/dist/skills/tutticode/references/devices/drumrack.md +225 -0
  24. package/dist/skills/tutticode/references/devices/dsclang.md +26 -0
  25. package/dist/skills/tutticode/references/devices/dsclap.md +25 -0
  26. package/dist/skills/tutticode/references/devices/dscymbal.md +22 -0
  27. package/dist/skills/tutticode/references/devices/dsfm.md +25 -0
  28. package/dist/skills/tutticode/references/devices/dshh.md +23 -0
  29. package/dist/skills/tutticode/references/devices/dskick.md +25 -0
  30. package/dist/skills/tutticode/references/devices/dssnare.md +23 -0
  31. package/dist/skills/tutticode/references/devices/dstom.md +24 -0
  32. package/dist/skills/tutticode/references/devices/dynamic-tube.md +26 -0
  33. package/dist/skills/tutticode/references/devices/echo.md +56 -0
  34. package/dist/skills/tutticode/references/devices/electric.md +50 -0
  35. package/dist/skills/tutticode/references/devices/ensemble.md +129 -0
  36. package/dist/skills/tutticode/references/devices/eqeight.md +69 -0
  37. package/dist/skills/tutticode/references/devices/eqthree.md +27 -0
  38. package/dist/skills/tutticode/references/devices/erosion.md +22 -0
  39. package/dist/skills/tutticode/references/devices/filter.md +55 -0
  40. package/dist/skills/tutticode/references/devices/filterdelay.md +37 -0
  41. package/dist/skills/tutticode/references/devices/gate.md +36 -0
  42. package/dist/skills/tutticode/references/devices/glue.md +36 -0
  43. package/dist/skills/tutticode/references/devices/graindelay.md +26 -0
  44. package/dist/skills/tutticode/references/devices/hybrid-reverb.md +22 -0
  45. package/dist/skills/tutticode/references/devices/impulse.md +157 -0
  46. package/dist/skills/tutticode/references/devices/leveler.md +23 -0
  47. package/dist/skills/tutticode/references/devices/limiter.md +26 -0
  48. package/dist/skills/tutticode/references/devices/meld.md +239 -0
  49. package/dist/skills/tutticode/references/devices/midichord.md +46 -0
  50. package/dist/skills/tutticode/references/devices/midifmarp.md +26 -0
  51. package/dist/skills/tutticode/references/devices/midinoteecho.md +30 -0
  52. package/dist/skills/tutticode/references/devices/midinotelength.md +27 -0
  53. package/dist/skills/tutticode/references/devices/midipitch.md +26 -0
  54. package/dist/skills/tutticode/references/devices/midirandom.md +24 -0
  55. package/dist/skills/tutticode/references/devices/midiscale.md +25 -0
  56. package/dist/skills/tutticode/references/devices/midivelocity.md +27 -0
  57. package/dist/skills/tutticode/references/devices/multibanddynamics.md +62 -0
  58. package/dist/skills/tutticode/references/devices/operator.md +163 -0
  59. package/dist/skills/tutticode/references/devices/overdrive.md +24 -0
  60. package/dist/skills/tutticode/references/devices/pedal.md +26 -0
  61. package/dist/skills/tutticode/references/devices/phaserflanger.md +42 -0
  62. package/dist/skills/tutticode/references/devices/pitchshifter.md +56 -0
  63. package/dist/skills/tutticode/references/devices/redux.md +27 -0
  64. package/dist/skills/tutticode/references/devices/resonator.md +49 -0
  65. package/dist/skills/tutticode/references/devices/reverb.md +43 -0
  66. package/dist/skills/tutticode/references/devices/roar.md +70 -0
  67. package/dist/skills/tutticode/references/devices/sampler.md +228 -0
  68. package/dist/skills/tutticode/references/devices/saturator.md +24 -0
  69. package/dist/skills/tutticode/references/devices/simpler.md +230 -0
  70. package/dist/skills/tutticode/references/devices/sixop.md +190 -0
  71. package/dist/skills/tutticode/references/devices/spectralresonator.md +42 -0
  72. package/dist/skills/tutticode/references/devices/spectraltime.md +45 -0
  73. package/dist/skills/tutticode/references/devices/synth.md +28 -0
  74. package/dist/skills/tutticode/references/devices/tension.md +117 -0
  75. package/dist/skills/tutticode/references/devices/utility.md +29 -0
  76. package/dist/skills/tutticode/references/devices/vinyl.md +31 -0
  77. package/dist/skills/tutticode/references/devices/vocoder.md +41 -0
  78. package/dist/skills/tutticode/references/devices/wavetable.md +128 -0
  79. package/dist/skills/tutticode/references/devices.md +114 -0
  80. package/dist/skills/tutticode/references/effect-controls.md +145 -0
  81. package/dist/skills/tutticode/references/first-sounds.md +89 -0
  82. package/dist/skills/tutticode/references/for-agents.md +119 -0
  83. package/dist/skills/tutticode/references/functions.md +1848 -0
  84. package/dist/skills/tutticode/references/getting-started.md +79 -0
  85. package/dist/skills/tutticode/references/harmony-and-scales.md +105 -0
  86. package/dist/skills/tutticode/references/javascript.md +90 -0
  87. package/dist/skills/tutticode/references/melodies-with-do-re-mi.md +59 -0
  88. package/dist/skills/tutticode/references/mini-notation.md +120 -0
  89. package/dist/skills/tutticode/references/mixing.md +101 -0
  90. package/dist/skills/tutticode/references/muse.md +67 -0
  91. package/dist/skills/tutticode/references/sample-operations.md +102 -0
  92. package/dist/skills/tutticode/references/sounds.md +109 -0
  93. package/dist/skills/tutticode/references/time-and-structure.md +161 -0
  94. package/dist/skills/tutticode/references/tuttidaw-extensions.md +131 -0
  95. package/dist/skills/tutticode-sound-for-media/SKILL.md +104 -0
  96. package/dist/skills/tutticode-sound-for-media/references/music-recipes.md +86 -0
  97. package/dist/skills/tutticode-sound-for-media/references/sfx-recipes.md +129 -0
  98. package/dist/tutticode.cjs +18746 -0
  99. package/package.json +39 -4
@@ -0,0 +1,102 @@
1
+ # Sample operations
2
+
3
+ Play part of a sample, change its speed, cut it into slices, fit it to the tempo and choke it.
4
+
5
+ Drum sounds and your own samples are recordings, so you can play a window of
6
+ them, faster or slower, forwards or backwards. In TuttiDAW every variation
7
+ becomes its own pad in a Drum Rack, so the result opens in the studio exactly
8
+ as it sounds.
9
+
10
+ ## Window: begin and end
11
+
12
+ `.begin(...)` and `.end(...)` set where a sample starts and stops, as a
13
+ fraction of its length (0 to 1).
14
+
15
+ ```js
16
+ s("oh*4").end("<0.1 0.3 0.6 1>")
17
+ ```
18
+
19
+ ## Speed
20
+
21
+ `.speed(n)` plays a sample `n` times as fast: 2 is an octave up, 0.5 an
22
+ octave down, and a negative speed plays it backwards.
23
+
24
+ ```js
25
+ s("cp*4").speed("1 2 0.5 -1")
26
+ ```
27
+
28
+ ## Gating and choke groups: clip and cut
29
+
30
+ A sample normally plays to its end. `.clip(1)` stops it at the end of its
31
+ step (`.clip(0.5)` halfway). `.cut(n)` puts sounds in a choke group: a new
32
+ hit stops the one still ringing, like an open hi-hat closed by a closed one.
33
+
34
+ ```js
35
+ s("[oh hh]*4").cut(1)
36
+ ```
37
+
38
+ ```js
39
+ s("oh*8").clip("<1 0.25>")
40
+ ```
41
+
42
+ ## Cutting into parts: chop and striate
43
+
44
+ `.chop(n)` cuts every event, and its sample, into `n` parts played one after
45
+ another. `.striate(n)` plays the whole pattern `n` times, a later part of each
46
+ sample each time.
47
+
48
+ ```js
49
+ s("cr").chop(8).speed("<1 -1>")
50
+ ```
51
+
52
+ ```js
53
+ s("bd sd").striate(4)
54
+ ```
55
+
56
+ ## Slices: slice and splice
57
+
58
+ `.slice(n, indices)` cuts a sample into `n` equal slices and plays the slices
59
+ the index pattern names - the classic way to rearrange a break. `.splice` does
60
+ the same and changes each slice's speed so it fills its step exactly.
61
+
62
+ ```js
63
+ s("cr").slice(8, "0 7 2 5 4 3 6 1")
64
+ ```
65
+
66
+ ```js
67
+ s("oh").splice(4, "0 2 1 [3 3]")
68
+ ```
69
+
70
+ ## Fitting to the tempo: loopAt and fit
71
+
72
+ `.loopAt(n)` changes a sample's speed so it lasts exactly `n` cycles - ideal
73
+ for loops and breaks. `.fit()` makes each sample fill its own step. Both follow
74
+ the tempo, so the loop stays in time when you change `setcpm`.
75
+
76
+ ```js
77
+ s("cr").loopAt(1).chop(4)
78
+ ```
79
+
80
+ ## Scrubbing
81
+
82
+ `.scrub("position:speed")` starts the sample at a position, like moving a
83
+ tape head.
84
+
85
+ ```js
86
+ s("cr*4").scrub("0 0.5:2 0.25 0.75:0.5")
87
+ ```
88
+
89
+ ## With your own loops
90
+
91
+ These operations are at their best on your own recordings. Declare them with
92
+ `samples(...)` (see [Sounds](sounds.md#your-own-samples)) and slice away:
93
+
94
+ ```js
95
+ samples({ break: "https://example.com/loops/break-120.wav" })
96
+ s("break").loopAt(2).slice(8, "0 1 <2 6> 3 [4 4] 5 6 <7 1>")
97
+ ```
98
+
99
+ A pitched instrument - a synth or a General MIDI name - plays its notes as
100
+ written: these operations only change sampled drums and samples.
101
+
102
+ Source: https://tuttidaw.com/code/learn/sample-operations
@@ -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,104 @@
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, `truePeak`). No file is written
56
+ clipped: without `lufs`, a render that would pass the ceiling is lowered
57
+ by one static gain (a negative `gainDb` and a line in `warnings`). `lufs`
58
+ is one static gain: a peaky program (most drum programs at -14..-16)
59
+ fails with `clip`. Then lower the target, lower the loudest voice's
60
+ `.gain` and render again, end the program with
61
+ `master.fx("Limiter", {gainDb: 3, ceiling: -3})` (the program's own bus
62
+ catches the peaks before the gain, as the music recipes do), or add
63
+ `limit: true` (`--limit`): the render's true-peak limiter holds the
64
+ ceiling and reports the most it took off (`limitDb`). More than about
65
+ 6 dB of it flattens the drums: then lower the target instead.
66
+ - Exact durations: `seconds` cuts exactly. A one-shot effect is one bar
67
+ long: `setcpm` sets the bar (`setcpm(60)` = 1 s, `setcpm(15)` = 4 s).
68
+ - Video beds: `fadeIn` 1-3 s, `fadeOut` 2-5 s, `tail` for the reverb.
69
+ - Loops for apps and games: `loops` N with `tail: 0`, no fades, so the file
70
+ is exactly N loops and repeats in time; keep the last step short.
71
+ - Stems: `stems: true` writes one file per voice (named by the labels); the
72
+ mix's static gain applies to the stems too, so they still sum to the mix.
73
+ A stem that would clip on its own is lowered further (its `gainDb` in
74
+ `voices`, a line in `warnings`); the limiter never touches stems.
75
+
76
+ ## Quality bar: never deliver
77
+
78
+ - a render whose `check.diagnostics` has an `error`, or the `clip` error;
79
+ - clipping (`analysis.loudness.clipping`) or a true peak above -1 dBTP;
80
+ - a dead mix: integrated loudness null / -70, an unplanned silent bar, or a
81
+ voice whose `lufs` is null;
82
+ - a length other than the one asked for (check `window.seconds`, plus the
83
+ tail);
84
+ - without the `editUrl` (or `listenUrl`): always give it to the user, it
85
+ opens the program in TuttiCode to keep editing.
86
+
87
+ ## Sound effects
88
+
89
+ Synth voices work everywhere. Noise is `s("white")`, `s("pink")` or
90
+ `s("brown")` (hard to soft), shaped by the envelope and filters like any
91
+ synth voice (`s("crackle")` is approximated). Pitch sweeps
92
+ use the pitch envelope (`.penv(semitones).pattack(s)` / `.pdecay(s)`),
93
+ swells the amplitude envelope (`.attack` / `.decay` / `.sustain(0)`), and
94
+ `gm_reverse_cymbal`, `gm_fx_rain`, `gm_seashore`, `gm_fx_sci_fi` are ready
95
+ riser, rain, waves and sci-fi textures (`note("c4").s(...)`).
96
+
97
+ ## References
98
+
99
+ - `references/sfx-recipes.md`: riser, impact, whoosh, UI click / confirm /
100
+ error, notification, transition, ambience bed; each with render settings.
101
+ - `references/music-recipes.md`: music beds and loops by mood, with their
102
+ Muse style for `code_compare`.
103
+ - The `tutticode` skill: the language, `references/agent-loop.md` (every
104
+ 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.