diff --git a/website/src/config.ts b/website/src/config.ts index ba9b0666..0d774a5a 100644 --- a/website/src/config.ts +++ b/website/src/config.ts @@ -70,12 +70,10 @@ export const SIDEBAR: Sidebar = { { text: 'MIDI & OSC', link: 'learn/input-output' }, ], More: [ + { text: 'Recipes', link: 'recipes/recipes' }, { text: 'Mini-Notation', link: 'learn/mini-notation' }, - { text: 'Coding syntax', link: 'learn/code' }, { text: 'Offline', link: 'learn/pwa' }, { text: 'Patterns', link: 'technical-manual/patterns' }, - { text: 'Pattern Alignment', link: 'technical-manual/alignment' }, - { text: 'Strudel vs Tidal', link: 'learn/strudel-vs-tidal' }, { text: 'Music metadata', link: 'learn/metadata' }, { text: 'CSound', link: 'learn/csound' }, ], @@ -89,7 +87,13 @@ export const SIDEBAR: Sidebar = { { text: 'Accumulation', link: 'learn/accumulation' }, { text: 'Tonal Functions', link: 'learn/tonal' }, ], - Understand: [{ text: 'Pitch', link: 'understand/pitch' }], + Understand: [ + { text: 'Coding syntax', link: 'learn/code' }, + { text: 'Pitch', link: 'understand/pitch' }, + { text: 'Cycles', link: 'understand/cycles' }, + { text: 'Pattern Alignment', link: 'technical-manual/alignment' }, + { text: 'Strudel vs Tidal', link: 'learn/strudel-vs-tidal' }, + ], Development: [ { text: 'REPL', link: 'technical-manual/repl' }, { text: 'Sounds', link: 'technical-manual/sounds' }, diff --git a/website/src/pages/recipes/recipes.mdx b/website/src/pages/recipes/recipes.mdx new file mode 100644 index 00000000..22617e4b --- /dev/null +++ b/website/src/pages/recipes/recipes.mdx @@ -0,0 +1,312 @@ +--- +title: Recipes +layout: ../../layouts/MainLayout.astro +--- + +import { MiniRepl } from '../../docs/MiniRepl'; + +# Recipes + +This page shows possible ways to achieve common (or not so common) musical goals. +There are often many ways to do a thing and there is no right or wrong. +The fun part is that each representation will give you different impulses when improvising. + +## Arpeggios + +An arpeggio is when the notes of a chord are played in sequence. +We can either write the notes by hand: + + + +...or use scales: + + + +...or chord symbols: + + + +...using off: + + + +## Chopping Breaks + +A sample can be looped and chopped like this: + + + +This fits the break into 8 cycles + chops it in 16 pieces. +The chops are not audible yet, because we're not doing any manipulation. +Let's add randmized doubling + reversing: + + + +If we want to specify the order of samples, we can replace `chop` with `slice`: + +") + .cut(1).rarely(ply(2))`} + punchcard +/> + +If we use `splice` instead of `slice`, the speed adjusts to the duration of the event: + +") + .cut(1).rarely(ply(2))`} + punchcard +/> + +Note that we don't need `fit`, because `splice` will do that by itself. + +## Filter Envelopes + +A minimal filter envelope looks like this: + + d2") + .s("sawtooth") + .lpf(400).lpa(.2).lpenv(4) + .scope()`} +/> + +We can flip the envelope by setting `lpenv` negative + add some resonance `lpq`: + + d2") + .s("sawtooth").lpq(8) + .lpf(400).lpa(.2).lpenv(-4) + .scope()`} +/> + +## Layering Sounds + +We can layer sounds by separating them with ",": + +") +.s("sawtooth, square") // <------ +.scope()`} +/> + +We can control the gain of individual sounds like this: + +") +.s("sawtooth, square:0:.5") // <--- "name:number:gain" +.scope()`} +/> + +For more control over each voice, we can use `layer`: + +").layer( + x=>x.s("sawtooth").vib(4), + x=>x.s("square").add(note(12)) +).scope()`} +/> + +Here, we give the sawtooth a vibrato and the square is moved an octave up. +With `layer`, you can use any pattern method available on each voice, so sky is the limit.. + +## Oscillator Detune + +We can fatten a sound by adding a detuned version to itself: + +") +.add(note("0,.1")) // <------ chorus +.s("sawtooth").scope()`} + punchcard +/> + +Try out different values, or add another voice! + +## Polyrhythms + +Here is a simple example of a polyrhythm: + + + +A polyrhythm is when 2 different tempos happen at the same time. + +## Polymeter + +This is a polymeter: + +,").fast(2)`} punchcard /> + +A polymeter is when 2 different bar lengths play at the same tempo. + +## Phasing + +This is a phasing: + +*[6,6.1]").piano()`} punchcard /> + +Phasing happens when the same sequence plays at slightly different tempos. + +## Running through samples + +Using `run` with `n`, we can rush through a sample bank: + + + +This works great with sample banks that contain similar sounds, like in this case different recordings of a tabla. +Often times, you'll hear the beginning of the phrase not where the pattern begins. +In this case, I hear the beginning at the third sample, which can be accounted for with `early`. + + + +Let's add some randomness: + + + +## Tape Warble + +We can emulate a pitch warbling effect like this: + + + +## Sound Duration + +There are a number of ways to change the sound duration. Using clip: + +/2")`} +/> + +The value of clip is relative to the duration of each event. +We can also create overlaps using release: + +/2")`} +/> + +This will smoothly fade out each sound for the given number of seconds. +We could also make the notes shorter with decay / sustain: + +/2").sustain(0)`} +/> + +For now, there is a limitation where decay values that exceed the event duration may cause little cracks, so use higher numbers with caution.. + +When using samples, we also have `.end` to cut relative to the sample length: + +")`} /> + +Compare that to clip: + +")`} /> + +or decay / sustain + +").sustain(0)`} /> + +## Wavetable Synthesis + +You can loop a sample with `loop` / `loopEnd`: + +").s("bd").loop(1).loopEnd(.05).gain(.2)`} /> + +This allows us to play the first 5% of the bass drum as a synth! +To simplify loading wavetables, any sample that starts with `wt_` will be looped automatically: + + + +Running through different wavetables can also give interesting variations: + + + +...adding a filter envelope + reverb: + + diff --git a/website/src/pages/understand/cycles.mdx b/website/src/pages/understand/cycles.mdx new file mode 100644 index 00000000..a66794be --- /dev/null +++ b/website/src/pages/understand/cycles.mdx @@ -0,0 +1,130 @@ +--- +title: Understanding Cycles +layout: ../../layouts/MainLayout.astro +--- + +import { MiniRepl } from '../../docs/MiniRepl'; +import { PitchSlider } from '../../components/PitchSlider'; +import Box from '@components/Box.astro'; + +# Understanding Cycles + +The concept of cycles is very central to be able to understand how Strudel works. +Strudel's mother language, TidalCycles, even has it in its name. + +## Cycles and BPM + +In most music software, the unit BPM (beats per minute) is used to set the tempo. +Strudel expresses tempo as CPS (cycles per second), with a default of 1CPS: + + + +Here we can hear the 1CPS in action: The kick repeats once per second like a clock. +We could say 1CPS = 1BPS (beats per second) = 60BPM. Let's add another kick: + + + +Now we have 2 kicks per second, but the whole pattern still plays at 1CPS. +In terms of BPM, most musicians would tell you this is playing at 120bpm. +What about this one: + + + +Because the second sound is now a hihat, the tempo feels slower again. +This brings us to an important realization: + + + +Tempo is based on perception. +The choice of sounds also has an impact on the tempo feel. +This is why the same CPS can produce different perceived tempos. + + + +## Setting CPM + +If you're familiar with BPM, you can use the `cpm` method to set the tempo in cycles per minute: + + + +If you want to add more beats per cycle, you might want to divide the cpm: + + + +Or using 2 beats per cycle: + + + + + +To set a specific bpm, use `.cpm(bpm/bpc)` + +- bpm: the target beats per minute +- bpc: the number of perceived beats per cycle + + + +## Cycles and Bars + +Also in most music software, multiple beats form a bar (or measure). +The so called time signature specifies how many beats are in each bar. +In many types of music, it is common to use 4 beats per bar, also known as 4/4 time. +Many music programs use it as a default. + +Strudel does not a have concept of bars or measures, there are only cycles. +How you use them is up to you. Above, we've had this example: + + + +This could be interpreted as 4/4 time with a tempo of 110bpm. +We could write out multiple bars like this: + +\`).cpm(110/4)`} +/> + +Instead of writing out each bar separately, we could express this much shorter: + +>,hh*4").cpm(110/2)`} /> + +Here we can see that thinking in cycles rather than bars simplifies things a lot! +These types of simplifications work because of the repetitive nature of rhythm. +In computational terms, you could say the former notation has a lot of redundancy. + +## Time Signatures + +To get a time signature, just change the number of elements per bar. Here is a rhythm with 7 beats: + + + +or with 5: + +*5")`} /> + +We could also write multiple bars with different time signatures: + +\`).cpm(110*2)`} +/> + +Here we switch between 3/4 and 4/4, keeping the same tempo. + +If we don't specify the length, we get what's called a metric modulation: + +\`).cpm(110/2)`} +/> + +Now the 3 elements get the same time as the 4 elements, which is why the tempo changes.