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,79 @@
|
|
|
1
|
+
# Getting started
|
|
2
|
+
|
|
3
|
+
What TuttiCode is, how a program loops, and how to play your first line.
|
|
4
|
+
|
|
5
|
+
TuttiCode is a small language for writing music as text. You describe a
|
|
6
|
+
**pattern** (which notes or drum hits happen, and when), and TuttiDAW plays it
|
|
7
|
+
with its own instruments and effects. The pattern repeats, so a single line is
|
|
8
|
+
already a loop you can listen to while you change it.
|
|
9
|
+
|
|
10
|
+
The language is a superset of [Strudel](https://strudel.cc): most Strudel code
|
|
11
|
+
plays here as written, and TuttiDAW adds a few methods of its own for real
|
|
12
|
+
instruments and effects (see [TuttiDAW extensions](tuttidaw-extensions.md)).
|
|
13
|
+
|
|
14
|
+
## Your first line
|
|
15
|
+
|
|
16
|
+
Every example in this guide plays: press **Play** under it on the web page,
|
|
17
|
+
or paste it into TuttiCode at tuttidaw.com/code. Change a letter while it
|
|
18
|
+
plays and evaluate again (Ctrl/Cmd+Enter): the change starts on the next bar.
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
note("c3 e3 g3 c4")
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`note(...)` turns the text between the quotes into notes. Four names share
|
|
25
|
+
one bar equally, so you hear four quarter notes.
|
|
26
|
+
|
|
27
|
+
## Cycles
|
|
28
|
+
|
|
29
|
+
The unit of time is the **cycle**. In TuttiDAW one cycle is one bar. Every
|
|
30
|
+
pattern is squeezed into its cycle: more steps means shorter steps.
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
note("c3 e3 g3 c4 e4 g4 c5 g4")
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Eight names in one cycle play as eighth notes; the bar stays the same length.
|
|
37
|
+
|
|
38
|
+
## Tempo
|
|
39
|
+
|
|
40
|
+
`setcpm(n)` asks for `n` cycles per minute. Because a cycle is a 4/4 bar,
|
|
41
|
+
`setcpm(30)` is 120 BPM and `setcpm(25)` is 100 BPM.
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
setcpm(25)
|
|
45
|
+
note("c3 e3 g3 c4")
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Several voices
|
|
49
|
+
|
|
50
|
+
A program can play several **voices** at once. Give each one a label followed
|
|
51
|
+
by a colon. A label that starts with `_` is muted, which is handy while you
|
|
52
|
+
work on another part.
|
|
53
|
+
|
|
54
|
+
```js
|
|
55
|
+
setcpm(30)
|
|
56
|
+
drums: s("bd sd bd sd")
|
|
57
|
+
bass: note("c2 c2 g1 bb1")
|
|
58
|
+
_lead: note("c4 e4 g4 e4")
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`$:` also starts a voice without naming it. Named voices are better when you
|
|
62
|
+
take a program into the studio, because each label becomes a track name.
|
|
63
|
+
|
|
64
|
+
## Where code runs
|
|
65
|
+
|
|
66
|
+
- **TuttiCode** plays a whole program in your browser, without an
|
|
67
|
+
account. Its **Open in TuttiDAW** button saves it as a studio project.
|
|
68
|
+
- **Pattern Clips** in the studio hold code in a MIDI clip; the notes are
|
|
69
|
+
rendered from the code.
|
|
70
|
+
- **Muse**, TuttiDAW's AI assistant, can write, explain and fix code for you
|
|
71
|
+
(see [Muse on /TuttiCode](muse.md)).
|
|
72
|
+
|
|
73
|
+
## Same code, same notes
|
|
74
|
+
|
|
75
|
+
Randomness in a program is seeded: the same code always gives the same notes,
|
|
76
|
+
on every computer and every time you open it. That is what lets a project
|
|
77
|
+
with code be shared and played back exactly.
|
|
78
|
+
|
|
79
|
+
Source: https://tuttidaw.com/code/learn/getting-started
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Harmony and scales
|
|
2
|
+
|
|
3
|
+
Note names and octaves, scale degrees, transposition, chord symbols, voicings and arpeggios.
|
|
4
|
+
|
|
5
|
+
## Note names and octaves
|
|
6
|
+
|
|
7
|
+
A note name is a letter, an optional accidental (`#` sharp, `b` flat) and an
|
|
8
|
+
octave number. `c4` is MIDI 60, middle C; `a4` is 69 (440 Hz). Each octave
|
|
9
|
+
starts at C, so `b3` is just below `c4`.
|
|
10
|
+
|
|
11
|
+
A name without an octave is in octave 3: `note("c e g")` is the same as
|
|
12
|
+
`note("c3 e3 g3")`.
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
note("c e g b")
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
TuttiDAW's piano roll uses Live's names, where MIDI 60 is **C3**. Code and the
|
|
19
|
+
clip disagree by one octave in the label only: the pitch is the same.
|
|
20
|
+
|
|
21
|
+
## Scale degrees: n and scale
|
|
22
|
+
|
|
23
|
+
`n("0 2 4")` writes numbers; `.scale("C:minor")` turns them into notes of a
|
|
24
|
+
scale. Degree 0 is the root, 1 the next note of the scale, and so on.
|
|
25
|
+
Numbers past the end of the scale continue in the next octave, and negative
|
|
26
|
+
numbers go down.
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
n("0 1 2 3 4 5 6 7").scale("C:minor")
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The root is in octave 3 unless you give one (`C4:minor`). Scale names
|
|
33
|
+
include `major`, `minor`, `dorian`, `mixolydian`, `lydian`, `phrygian`,
|
|
34
|
+
`blues` and `chromatic`. Join the root and every word of the name with
|
|
35
|
+
colons: `A:minor:pentatonic`, `C:harmonic:minor`. Inside double quotes a
|
|
36
|
+
space starts a new step, so `"C:harmonic minor"` is not one scale name.
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
n("0 2 4 <7 6>").scale("<D:dorian G:mixolydian>")
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Because the scale is a pattern too, a melody written in degrees follows the
|
|
43
|
+
chord changes on its own.
|
|
44
|
+
|
|
45
|
+
## Moving notes: add and transpose
|
|
46
|
+
|
|
47
|
+
`.transpose(n)` moves notes by semitones. `.add(...)` adds to the values: on
|
|
48
|
+
degrees it moves along the scale, on `note` patterns use `note(...)` inside.
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
note("c3 e3 g3 e3").transpose("<0 5 7 0>")
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```js
|
|
55
|
+
n("0 2 4 2".add("<0 3>")).scale("A:minor")
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Chord symbols: chord and voicing
|
|
59
|
+
|
|
60
|
+
`chord("...")` takes chord symbols such as `C`, `Am7`, `F^7`, `G7` or
|
|
61
|
+
`Bbm9`. `.voicing()` turns each symbol into notes, laid out so that the top
|
|
62
|
+
of the chord sits at or just below c5.
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
chord("<C Am F G>").voicing()
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Move the whole voicing with `.anchor(...)`: the chord is laid out below that
|
|
69
|
+
note instead.
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
chord("<Dm7 G7 C^7 A7>").anchor("g4").voicing()
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Picking chord notes: n with chords
|
|
76
|
+
|
|
77
|
+
With a chord set, `n` picks notes of the voicing by index, from the bottom
|
|
78
|
+
up - an arpeggio that follows the changes.
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
n("0 1 2 3 2 1").chord("<Cm7 Fm7 Bb7 Eb^7>").voicing()
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Bass lines: rootNotes
|
|
85
|
+
|
|
86
|
+
`.rootNotes(octave)` plays each chord's root, in the octave you give.
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
stack(
|
|
90
|
+
chord("<Am F C G>").voicing(),
|
|
91
|
+
chord("<Am F C G>").rootNotes(2)
|
|
92
|
+
)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Exact notes when you need them
|
|
96
|
+
|
|
97
|
+
Voicings follow their anchor note, not fixed shapes. When you need
|
|
98
|
+
exact pitches - a specific inversion, a doubled root - write the chord as a
|
|
99
|
+
stack of note names.
|
|
100
|
+
|
|
101
|
+
```js
|
|
102
|
+
note("<[a2,e3,a3,c4] [f2,c3,a3,c4] [c3,g3,c4,e4] [g2,d3,b3,d4]>")
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Source: https://tuttidaw.com/code/learn/harmony-and-scales
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# JavaScript in code
|
|
2
|
+
|
|
3
|
+
Variables, functions, loops and register - and the sandbox, determinism and limits that keep shared code safe.
|
|
4
|
+
|
|
5
|
+
A program is JavaScript. Most programs only chain pattern methods, but you
|
|
6
|
+
can use variables, functions, arrays, loops and conditions to build them.
|
|
7
|
+
|
|
8
|
+
## Variables and functions
|
|
9
|
+
|
|
10
|
+
`const` names a pattern so you can reuse it. A function can build a pattern
|
|
11
|
+
from arguments.
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
const groove = s("bd [~ bd] sd ~, hh*8")
|
|
15
|
+
const riff = (root) => n("0 2 4 2").scale(`${root}:minor`)
|
|
16
|
+
drums: groove.bank("tr909")
|
|
17
|
+
lead: cat(riff("C"), riff("F"), riff("G"), riff("C"))
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Double and single quotes
|
|
21
|
+
|
|
22
|
+
Double quotes (and backticks) are mini-notation: `"c3 e3"` is a pattern of
|
|
23
|
+
two notes. Single quotes are a plain string that is not read as
|
|
24
|
+
mini-notation - useful for names that contain spaces.
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
n("0 1 2 3").scale('C minor')
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Loops and arrays
|
|
31
|
+
|
|
32
|
+
Ordinary JavaScript can generate patterns. Here an array of degrees is built
|
|
33
|
+
with a loop and joined into mini-notation:
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
const steps = []
|
|
37
|
+
for (let i = 0; i < 8; i++) steps.push(i % 3 === 0 ? i : "~")
|
|
38
|
+
n(steps.join(" ")).scale("A:minor").s("triangle")
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Your own methods: register
|
|
42
|
+
|
|
43
|
+
`register(name, fn)` adds a method you can chain like the built-in ones. The
|
|
44
|
+
pattern comes last in the function's arguments.
|
|
45
|
+
|
|
46
|
+
```js
|
|
47
|
+
register('dub', (amount, pat) => pat.delay(amount).delayfeedback(0.6).room(0.3))
|
|
48
|
+
note("c3 ~ ~ eb3 ~ ~ g3 ~").s("square").dub(0.5)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## The sandbox
|
|
52
|
+
|
|
53
|
+
Code arrives in shared projects and links, so TuttiDAW never runs it as
|
|
54
|
+
ordinary page script. Simple programs are read by TuttiDAW's own interpreter;
|
|
55
|
+
anything else runs in a sealed JavaScript sandbox (QuickJS in WebAssembly)
|
|
56
|
+
whose only ability is building patterns:
|
|
57
|
+
|
|
58
|
+
- there is no network, no page, no storage, no timers and no `eval`;
|
|
59
|
+
- `import(...)` and `fetch` are not available; external audio is declared with
|
|
60
|
+
`samples(...)` and only loaded by the player when you press Play;
|
|
61
|
+
- every program has a work budget and a time limit, so an endless loop stops
|
|
62
|
+
with an error instead of freezing the page.
|
|
63
|
+
|
|
64
|
+
## Determinism
|
|
65
|
+
|
|
66
|
+
The same code always plays the same notes - on your computer, a
|
|
67
|
+
collaborator's, in an export:
|
|
68
|
+
|
|
69
|
+
- `Math.random()` and the pattern functions `rand`, `?`, `|`,
|
|
70
|
+
`sometimes` and friends are seeded;
|
|
71
|
+
- the clock is stopped: `Date.now()` always returns the same moment;
|
|
72
|
+
- every render starts fresh, so state kept in variables does not carry over
|
|
73
|
+
from one play to the next.
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
const pick = Math.floor(Math.random() * 4)
|
|
77
|
+
n(`<${pick} 2 4 6>`).scale("E:minor")
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
This program picks the same "random" note every time it is run.
|
|
81
|
+
|
|
82
|
+
## Limits
|
|
83
|
+
|
|
84
|
+
- a program can be up to 100,000 characters (a TuttiCode link up to 20,000);
|
|
85
|
+
- a cycle can hold up to 2,048 events in one voice.
|
|
86
|
+
|
|
87
|
+
A program over a limit reports an error at the code that caused it; the other
|
|
88
|
+
voices keep playing.
|
|
89
|
+
|
|
90
|
+
Source: https://tuttidaw.com/code/learn/javascript
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Mini-notation
|
|
2
|
+
|
|
3
|
+
The rhythm language inside the quotes - sequences, rests, groups, alternation, polymeter, Euclidean rhythms and chance.
|
|
4
|
+
|
|
5
|
+
Everything between double quotes is **mini-notation**: a compact way to write
|
|
6
|
+
rhythm. The same rules work for drum names, note names and numbers.
|
|
7
|
+
|
|
8
|
+
## Sequences and rests
|
|
9
|
+
|
|
10
|
+
Steps separated by spaces share the cycle equally. `~` (or `-`) is a rest.
|
|
11
|
+
|
|
12
|
+
```js
|
|
13
|
+
s("bd ~ ~ bd ~ ~ sd ~")
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Groups: [ ]
|
|
17
|
+
|
|
18
|
+
Square brackets squeeze several steps into the space of one.
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
s("bd [sd sd] bd [~ sd]")
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Groups can be nested as deep as you like: `[hh [hh hh]]` is an eighth note
|
|
25
|
+
followed by two sixteenths.
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
s("hh [hh hh] hh [hh [hh hh]]")
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Faster and slower: * and /
|
|
32
|
+
|
|
33
|
+
`*n` plays a step `n` times in its own space; `/n` stretches it over `n`
|
|
34
|
+
cycles, so it only sounds every `n` bars.
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
s("bd*2 sd, hh*8, cp/2")
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Alternation: < >
|
|
41
|
+
|
|
42
|
+
Angle brackets play **one** of their steps per cycle, in turn. They are the
|
|
43
|
+
easiest way to make a pattern change from bar to bar.
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
note("<c3 a2 f2 g2>").s("sawtooth")
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Combine them with `*` to step through the list faster:
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
note("<c3 e3 g3 b3>*4")
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Chords and layers: ,
|
|
56
|
+
|
|
57
|
+
A comma plays its parts at the same time. Inside a group it makes a chord.
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
note("[c3,e3,g3] [a2,c3,e3] [f2,a2,c3] [g2,b2,d3]")
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Longer and repeated steps: @ ! _
|
|
64
|
+
|
|
65
|
+
`@n` makes a step `n` times as long as the others. `!n` repeats a step `n`
|
|
66
|
+
times, each copy a full step. `_` extends the previous step by one step.
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
note("c3@3 eb3 g3!2 bb3 _")
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Polymeter: { }
|
|
73
|
+
|
|
74
|
+
Curly brackets play layers of different lengths with the **same** step size,
|
|
75
|
+
so they drift against each other and meet again later. `%n` sets how many
|
|
76
|
+
steps fit in a cycle.
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
note("{c3 eb3 g3, c4 d4 eb4 f4 g4}%4")
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Euclidean rhythms: (k,n)
|
|
83
|
+
|
|
84
|
+
`x(k,n)` spreads `k` hits as evenly as possible over `n` steps. Many
|
|
85
|
+
traditional rhythms are Euclidean: `(3,8)` is the tresillo, `(5,8)` the
|
|
86
|
+
cinquillo. A third number rotates the pattern.
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
s("bd(3,8), hh(5,8,2), sd(2,8,4)")
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Chance: ? and |
|
|
93
|
+
|
|
94
|
+
`?` drops a step half of the time (`?0.2` drops it 20% of the time). `|`
|
|
95
|
+
chooses one of its options at random. Chance is seeded: the program plays
|
|
96
|
+
the same "random" notes every time you run it, until you change the code.
|
|
97
|
+
|
|
98
|
+
```js
|
|
99
|
+
s("hh*16?, bd [sd|cp]")
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Sample variants and number ranges: : and ..
|
|
103
|
+
|
|
104
|
+
`name:n` chooses variant `n` of a sound (`bd:3`). `a .. b` counts from `a` to
|
|
105
|
+
`b`.
|
|
106
|
+
|
|
107
|
+
```js
|
|
108
|
+
n("0 .. 7").scale("C:major")
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Mini-notation is a pattern everywhere
|
|
112
|
+
|
|
113
|
+
Any argument that takes a number also accepts a quoted pattern, so the same
|
|
114
|
+
syntax can drive speed, volume or a filter:
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
s("hh*8").gain("0.9 0.4 0.6 0.4").fast("<1 2>")
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Source: https://tuttidaw.com/code/learn/mini-notation
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Mixing: buses and master
|
|
2
|
+
|
|
3
|
+
Shared reverbs and delays on buses, sends from the voices, each voice's fader and pan, and the program's master chain - the same tracks Open in TuttiDAW makes.
|
|
4
|
+
|
|
5
|
+
A program can mix itself the way a studio project is mixed: **buses** for
|
|
6
|
+
shared effects, **sends** from the voices into them, a **fader and pan** per
|
|
7
|
+
voice, and a **master** that everything goes through. "Open in TuttiDAW"
|
|
8
|
+
makes exactly these tracks.
|
|
9
|
+
|
|
10
|
+
| Code | What it is | In the studio |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| `bus(name)` | a shared effect track | a return track inside the program's group |
|
|
13
|
+
| `.send(bus, dB)` | how much of a voice goes to a bus | the voice track's send knob |
|
|
14
|
+
| `.mix({vol, pan, mute})` | a voice's (or a bus's) mixer | the track's fader, pan and mute |
|
|
15
|
+
| `master` | the program's own bus | the program group's devices and fader |
|
|
16
|
+
|
|
17
|
+
These are TuttiDAW-only, like `.fx`: a program that uses them does not play
|
|
18
|
+
on strudel.cc.
|
|
19
|
+
|
|
20
|
+
## Buses and sends
|
|
21
|
+
|
|
22
|
+
Declare a bus with `bus("name")` on its own line and give it effects with
|
|
23
|
+
`.fx`. A bus usually holds a "wet only" effect (Dry/Wet at 100%): the voices
|
|
24
|
+
keep their dry sound and send some of it to the bus.
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
bus("verb").fx("Reverb:Large Hall", {dryWetBalance: 1})
|
|
28
|
+
|
|
29
|
+
drums: s("bd*2 [~ bd] sd ~, hh*8").bank("tr909")
|
|
30
|
+
keys: chord("<Cm7 Fm7>").voicing().inst("Electric").send("verb", -10)
|
|
31
|
+
lead: n("0 2 4 7").scale("C4:minor").s("triangle").send("verb", -18)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`.send(bus, dB)` takes a level in dB: `0` is the most, `-70` is off. Send
|
|
35
|
+
from as many voices as you like, and from one voice to several buses:
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
bus("verb").fx("Reverb", {dryWetBalance: 1, decayTime: "3s"})
|
|
39
|
+
bus("echo").fx("Delay", {feedback: 0.4}).mix({vol: -6})
|
|
40
|
+
|
|
41
|
+
keys: note("<c3 e3 g3>").inst("Drift").send("verb", -10).send("echo", -20)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
A pattern moves the level - here the reverb opens up every other bar:
|
|
45
|
+
|
|
46
|
+
```js
|
|
47
|
+
bus("verb").fx("Reverb", {dryWetBalance: 1})
|
|
48
|
+
keys: note("c3 e3 g3 e3").s("sine").send("verb", "<-24 -6>")
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
A send to a bus the program does not declare is a warning, and the editor
|
|
52
|
+
offers to add `bus("...")` for you.
|
|
53
|
+
|
|
54
|
+
Why buses? Two voices that share one reverb sound like they are in one
|
|
55
|
+
room, and you change the room in one place. Strudel's `.room()` still works
|
|
56
|
+
too: it gives that voice its own reverb.
|
|
57
|
+
|
|
58
|
+
## A voice's fader, pan and mute
|
|
59
|
+
|
|
60
|
+
`.mix()` sets the voice's mixer: `vol` in dB (`0` leaves it as it is, `-6`
|
|
61
|
+
is half as loud, `-70` is silent), `pan` from `-1` (left) to `1` (right),
|
|
62
|
+
`mute` on or off.
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
bass: note("c2 ~ c2 g1").s("sawtooth").lpf(500).mix({vol: -3})
|
|
66
|
+
hats: s("hh*8").mix({vol: -12, pan: 0.4})
|
|
67
|
+
perc: s("~ rim").mix({pan: -0.4, mute: true})
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`vol` and `pan` can be patterns too. When a voice has both `.pan()` (Strudel)
|
|
71
|
+
and `.mix({pan})`, the `.mix` value wins.
|
|
72
|
+
|
|
73
|
+
## The master
|
|
74
|
+
|
|
75
|
+
`master` is the program's own bus: every voice and bus goes through it.
|
|
76
|
+
Give it effects and a fader like any bus - a gentle compressor to glue the
|
|
77
|
+
mix and a limiter at the end are a common start:
|
|
78
|
+
|
|
79
|
+
```js
|
|
80
|
+
master.fx("Glue Compressor", {threshold: -12}).fx("Limiter")
|
|
81
|
+
master.mix({vol: -1})
|
|
82
|
+
|
|
83
|
+
drums: s("bd*4, ~ cp, hh*8").bank("tr909")
|
|
84
|
+
bass: note("<c2 g1 a1 f1>").ply(4).s("sawtooth").lpf(600)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
On this page the master is what you hear. In a project, a program lives in
|
|
88
|
+
its own group track, so `master` is that group's chain; it feeds the
|
|
89
|
+
project's master like any other track.
|
|
90
|
+
|
|
91
|
+
## In the studio
|
|
92
|
+
|
|
93
|
+
Open the program in TuttiDAW and you get its group with one track per
|
|
94
|
+
voice, the buses as return tracks inside the group, and the master chain on
|
|
95
|
+
the group. The values the code sets belong to the code: change one by hand
|
|
96
|
+
(a device param, a fader, pan or mute, or a device added, removed or moved
|
|
97
|
+
on a bus or the master) and that voice, bus or master is detached from the
|
|
98
|
+
code (Re-attach brings it back). Remove
|
|
99
|
+
a bus from the code and its return track stays, marked "not in code".
|
|
100
|
+
|
|
101
|
+
Source: https://tuttidaw.com/code/learn/mixing
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Muse on /TuttiCode
|
|
2
|
+
|
|
3
|
+
Ask TuttiDAW's AI assistant to write, explain, fix or restyle your program, from text, a Strudel tune, a screenshot or a reference track.
|
|
4
|
+
|
|
5
|
+
**Muse** is TuttiDAW's AI assistant. On TuttiCode, the **Muse AI**
|
|
6
|
+
button opens it in a sidebar next to the editor. Muse needs you to be signed
|
|
7
|
+
in; playing code does not.
|
|
8
|
+
|
|
9
|
+
## What to ask
|
|
10
|
+
|
|
11
|
+
Muse reads the program in the editor before it changes anything, so you can
|
|
12
|
+
talk about the code that is there:
|
|
13
|
+
|
|
14
|
+
- "Write a slow lo-fi beat in F minor with electric piano chords."
|
|
15
|
+
- "Make the bass follow the kick and add a fill every fourth bar."
|
|
16
|
+
- "Why is the lead silent?" - Muse reads the diagnostics with the code.
|
|
17
|
+
- "Explain what `.off(1/8, ...)` does in my program."
|
|
18
|
+
- "Turn this into a TuttiDAW version with real instruments" - Muse can
|
|
19
|
+
replace waveform sounds with `.inst(...)` and `.fx(...)` devices.
|
|
20
|
+
|
|
21
|
+
A request like the first one might come back as:
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
setcpm(18)
|
|
25
|
+
drums: s("bd ~ [~ bd] ~, ~ sd, hh*8").bank("linn").swingBy(1/6, 4).gain(0.8)
|
|
26
|
+
keys: chord("<Fm9 Bbm9 Eb^9 Db^7>").voicing().inst("Electric").fx("Chorus")
|
|
27
|
+
bass: n("<0 -2 -4 -5>").scale("F2:minor").s("gm_acoustic_bass")
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## How Muse edits
|
|
31
|
+
|
|
32
|
+
- Every change is checked first: Muse compiles and renders the program before
|
|
33
|
+
it touches the editor, and repairs its own mistake once if the check fails.
|
|
34
|
+
- A change arrives as **one undoable edit**: Ctrl/Cmd+Z takes it back.
|
|
35
|
+
- If you changed the code while Muse was working, it asks before overwriting
|
|
36
|
+
your edit (unless Autopilot is on).
|
|
37
|
+
- Muse's edits are evaluated like your typing, so they never start a sample
|
|
38
|
+
download; press Play to load new samples.
|
|
39
|
+
|
|
40
|
+
## Attachments
|
|
41
|
+
|
|
42
|
+
Use **+** in the message box (or paste, or drop a file on the sidebar):
|
|
43
|
+
|
|
44
|
+
- **a text or code file** - for example a Strudel tune to adapt;
|
|
45
|
+
- **an image** - a screenshot of code, or of a DAW arrangement to recreate;
|
|
46
|
+
- **audio** - a reference track. Muse measures its tempo, key, loudness,
|
|
47
|
+
brightness and rhythm, and can look at a spectrogram.
|
|
48
|
+
|
|
49
|
+
Files stay in your browser's memory: Muse receives the text, the picture or
|
|
50
|
+
the measurements, and nothing is saved to a project.
|
|
51
|
+
|
|
52
|
+
## Conversations
|
|
53
|
+
|
|
54
|
+
Conversations are kept in your browser for your account, with the same
|
|
55
|
+
models and points as Muse in the studio. In the studio itself, Muse writes
|
|
56
|
+
code into Pattern Clips; other AI apps can do the same through TuttiDAW's MCP
|
|
57
|
+
server (see the agent skill below).
|
|
58
|
+
|
|
59
|
+
## For AI agents
|
|
60
|
+
|
|
61
|
+
The same guide is published as an agent skill at
|
|
62
|
+
`/skills/tuttidaw-code/SKILL.md` (with a downloadable zip), and listed in
|
|
63
|
+
`/llms.txt`. Its references are generated from these pages, the engine's
|
|
64
|
+
function table and the device catalogue, so they always match what TuttiDAW
|
|
65
|
+
plays. Muse on TuttiCode reads the same pages when it needs a detail.
|
|
66
|
+
|
|
67
|
+
Source: https://tuttidaw.com/code/learn/muse
|
|
@@ -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
|