import { MiniRepl } from './MiniRepl'; # Table of Contents # What is Strudel? With Strudel, you can expressively write dynamic music pieces. It aims to be [Tidal Cycles](https://tidalcycles.org/) for JavaScript (started by the same author). You don't need to know JavaScript or Tidal Cycles to make music with Strudel. This interactive tutorial will guide you through the basics of Strudel. The best place to actually make music with Strudel is the [Strudel REPL](https://strudel.tidalcycles.org/). ## Show me a Demo To get a taste of what Strudel can do, check out this track: /8"), "~ ".tone(snare).bypass("<0@7 1>/4"), "[~ c4]*2".tone(hihat) ); const thru = (x) => x.transpose("<0 1>/8").transpose(-1); const synths = stack( "/2".scale(timeCat([3,'C minor'],[1,'C melodic minor']).slow(8)).struct("[~ x]\*2") .layer( scaleTranspose(0).early(0), scaleTranspose(2).early(1/8), scaleTranspose(7).early(1/4), scaleTranspose(8).early(3/8) ).layer(thru).tone(keys).bypass("<1 0>/16"), "/2".struct("[x [~ x] <[~ [~ x]]!3 [x x]>@2]/2".fast(2)).layer(thru).tone(bass), "/2".struct("~ [x@0.1 ~]".fast(2)).voicings().layer(thru).every(2, early(1/8)).tone(keys).bypass("<0@7 1>/8".early(1/4)) ) stack( drums.fast(2), synths ).slow(2); `} /> [Open this track in the REPL](https://strudel.tidalcycles.org/#KCkgPT4gewogIGNvbnN0IGRlbGF5ID0gbmV3IEZlZWRiYWNrRGVsYXkoMS84LCAuNCkuY2hhaW4odm9sKDAuNSksIG91dCk7CiAgY29uc3Qga2ljayA9IG5ldyBNZW1icmFuZVN5bnRoKCkuY2hhaW4odm9sKC44KSwgb3V0KTsKICBjb25zdCBzbmFyZSA9IG5ldyBOb2lzZVN5bnRoKCkuY2hhaW4odm9sKC44KSwgb3V0KTsKICBjb25zdCBoaWhhdCA9IG5ldyBNZXRhbFN5bnRoKCkuc2V0KGFkc3IoMCwgLjA4LCAwLCAuMSkpLmNoYWluKHZvbCguMykuY29ubmVjdChkZWxheSksb3V0KTsKICBjb25zdCBiYXNzID0gbmV3IFN5bnRoKCkuc2V0KHsgLi4ub3NjKCdzYXd0b290aCcpLCAuLi5hZHNyKDAsIC4xLCAuNCkgfSkuY2hhaW4obG93cGFzcyg5MDApLCB2b2woLjUpLCBvdXQpOwogIGNvbnN0IGtleXMgPSBuZXcgUG9seVN5bnRoKCkuc2V0KHsgLi4ub3NjKCdzYXd0b290aCcpLCAuLi5hZHNyKDAsIC41LCAuMiwgLjcpIH0pLmNoYWluKGxvd3Bhc3MoMTIwMCksIHZvbCguNSksIG91dCk7CiAgCiAgY29uc3QgZHJ1bXMgPSBzdGFjaygKICAgICdjMSoyJy5tLnRvbmUoa2ljaykuYnlwYXNzKCc8MEA3IDE%2BLzgnLm0pLAogICAgJ34gPHghNyBbeEAzIHhdPicubS50b25lKHNuYXJlKS5ieXBhc3MoJzwwQDcgMT4vNCcubSksCiAgICAnW34gYzRdKjInLm0udG9uZShoaWhhdCkKICApOwogIAogIGNvbnN0IHRocnUgPSAoeCkgPT4geC50cmFuc3Bvc2UoJzwwIDE%2BLzgnLm0pLnRyYW5zcG9zZSgtMSk7CiAgY29uc3Qgc3ludGhzID0gc3RhY2soCiAgICAnPGViNCBkNCBjNCBiMz4vMicubS5zY2FsZSh0aW1lQ2F0KFszLCdDIG1pbm9yJ10sWzEsJ0MgbWVsb2RpYyBtaW5vciddKS5zbG93KDgpKS5ncm9vdmUoJ1t%2BIHhdKjInLm0pCiAgICAuZWRpdCgKICAgICAgc2NhbGVUcmFuc3Bvc2UoMCkuZWFybHkoMCksCiAgICAgIHNjYWxlVHJhbnNwb3NlKDIpLmVhcmx5KDEvOCksCiAgICAgIHNjYWxlVHJhbnNwb3NlKDcpLmVhcmx5KDEvNCksCiAgICAgIHNjYWxlVHJhbnNwb3NlKDgpLmVhcmx5KDMvOCkKICAgICkuZWRpdCh0aHJ1KS50b25lKGtleXMpLmJ5cGFzcygnPDEgMD4vMTYnLm0pLAogICAgJzxDMiBCYjEgQWIxIFtHMSBbRzIgRzFdXT4vMicubS5ncm9vdmUoJ1t4IFt%2BIHhdIDxbfiBbfiB4XV0hMyBbeCB4XT5AMl0vMicubS5mYXN0KDIpKS5lZGl0KHRocnUpLnRvbmUoYmFzcyksCiAgICAnPENtNyBCYjcgRm03IEc3YjEzPi8yJy5tLmdyb292ZSgnfiBbeEAwLjEgfl0nLm0uZmFzdCgyKSkudm9pY2luZ3MoKS5lZGl0KHRocnUpLmV2ZXJ5KDIsIGVhcmx5KDEvOCkpLnRvbmUoa2V5cykuYnlwYXNzKCc8MEA3IDE%2BLzgnLm0uZWFybHkoMS80KSkKICApCiAgcmV0dXJuIHN0YWNrKAogICAgZHJ1bXMuZmFzdCgyKSwgCiAgICBzeW50aHMKICApLnNsb3coMik7Cn0%3D) ## Disclaimer - This project is still in its experimental state. In the future, parts of it might change significantly. - This tutorial is far from complete.
# Mini Notation Similar to Tidal Cycles, Strudel has an embedded mini language that is designed to write rhythmic patterns in a short manner. Before diving deeper into the details, here is a flavor of how the mini language looks like: The snippet above is enclosed in backticks (`), which allows you to write multi-line strings. You can also use double quotes (") for single line mini notation. ## Notes Notes are notated with the note letter, followed by the octave number. You can notate flats with `b` and sharps with `#`. Here, the same note is played over and over again, once a second. This one second is the default length of one so called "cycle". By the way, you can edit the contents of the player, and press "update" to hear your change! You can also press "play" on the next player without needing to stop the last one. ## Sequences We can play more notes by separating them with spaces: Here, those four notes are squashed into one cycle, so each note is a quarter second long. ## Division We can slow the sequence down by enclosing it in brackets and dividing it by a number: The division by two means that the sequence will be played over the course of two cycles. You can also use decimal numbers for any tempo you like. ## Angle Brackets Using angle brackets, we can define the sequence length based on the number of children: "`} /> The above snippet is the same as: The advantage of the angle brackets, is that we can add more children without needing to change the number at the end. ## Multiplication Contrary to division, a sequence can be sped up by multiplying it by a number: The multiplication by 2 here means that the sequence will play twice a cycle. ## Bracket Nesting To create more interesting rhythms, you can nest sequences with brackets, like this: ## Rests The "~" represents a rest: ## Parallel Using commas, we can play chords: To play multiple chords in a sequence, we have to wrap them in brackets: "`} /> ## Elongation With the "@" symbol, we can specify temporal "weight" of a sequence child: "`} /> Here, the first chord has a weight of 2, making it twice the length of the other chords. The default weight is 1. ## Replication Using "!" we can repeat without speeding up: "`} /> In essence, the `x!n` is like a shortcut for `[x*n]@n`. ## Euclidian Using round brackets, we can create rhythmical sub-divisions based on three parameters: beats, segments and offset. The first parameter controls how may beats will be played. The second parameter controls the total amount of segments the beats will be distributed over. The third (optional) parameter controls the starting position for distributing the beats. One popular Euclidian rhythm (going by various names, such as "Pop Clave") is "(3,8,1)" or simply "(3,8)", resulting in a rhythmical structure of "x ~ ~ x ~ ~ x ~" (3 beats over 8 segments, starting on position 1).
# Web Audio Output The default way to output sound is by using the Web Audio Output. Here is a little beat to show some of the possibilities: ],hh(3,4)") // drums .speed(perlin.range(.7,.9)) // random sample speed variation ,"" // bassline .off(1/8,x=>x.add(12).degradeBy(.5)) // random octave jumps .add(perlin.range(0,.5)) // random pitch variation .superimpose(add(.05)) // add second, slightly detuned voice .n() // wrap in "n" .decay(.15).sustain(0) // make each note of equal length .s('sawtooth') // waveform .gain(.4) // turn down .cutoff(sine.slow(7).range(300,5000)) // automate cutoff ,">".voicings() // chords .superimpose(x=>x.add(.04)) // add second, slightly detuned voice .add(perlin.range(0,.5)) // random pitch variation .n() // wrap in "n" .s('sawtooth') // waveform .gain(.16) // turn down .cutoff(500) // fixed cutoff .attack(1) // slowly fade in ) .slow(3/2) .out()`} /> ## Synths So far, all the mini notation examples all used the same sound, which is kind of boring. We can change the sound, using the `s` function: >").s('sawtooth').out()`} /> Here, we are wrapping our notes inside `note` and set the sound using `s`, connected by a dot. Those functions are only 2 of many ways to alter the properties, or _params_ of a sound. The power of patterns allows us to sequence any _param_ independently: >").s("").out()`} /> Now we not only pattern the notes, but the sound as well! `sawtooth` `square` and `triangle` are the basic waveforms available in `s`. ### Envelope You can control the envelope of a synth using the `attack`, `decay`, `sustain` and `release` functions: >").s('sawtooth') .attack(.1).decay(.1).sustain(.2).release(.1).out()`} /> ## Samples Besides Synths, `s` can also play back samples: To know which sounds are available, open the [default sample map](https://strudel.tidalcycles.org/EmuSP12.json) ### Custom Sample Maps You can load your own sample map like this: The `samples` function takes an object that maps sound names to audio file paths. The second argument is the base URL that comes before each path. Make sure your base URL ends with a slash, while your sample paths do **not** begin with one. Because github is a popular choice to dump samples, there is a shortcut for that: The format is `github:user/repo/branch/`. ### Multiple Samples per Sound It is also possible, to declare multiple files for one sound, using the array notation: ,~ ,[hh:0 hh:1]*2").out()`} /> The `:0` `:1` etc. are the indices of the array. The sample number can also be set using `n`: ").out()`} /> ### Pitched Sounds For pitched sounds, you can use `note`, just like with synths: @2").s('gtr').gain(.5).out()`} /> Here, the guitar samples will overlap, because they always play till the end. If we want them to behave more like a synth, we can add `clip(1)`: @2").s('gtr').clip(1) .gain(.5).out()`} /> ### Base Pitch If we have 2 samples with different base pitches, we can make them in tune by specifying the pitch like this: @2").s("gtr,moog").clip(1) .gain(.5).out()`} /> If a sample has no pitch set, `c3` is the default. We can also declare different samples for different regions of the keyboard: !2, g4 f4]>") .s('moog').clip(1) .gain(.5).out()`} /> The sampler will always pick the closest matching sample for the current note! ## Effects Wether you're using a synth or a sample, you can apply these effects: {{ 'cutoff' | jsdoc }} {{ 'resonance' | jsdoc }} {{ 'hcutoff' | jsdoc }} {{ 'hresonance' | jsdoc }} {{ 'bandf' | jsdoc }} {{ 'bandq' | jsdoc }} {{ 'vowel' | jsdoc }} {{ 'pan' | jsdoc }} {{ 'coarse' | jsdoc }} {{ 'shape' | jsdoc }} {{ 'crush' | jsdoc }}
# Core API While the mini notation is powerful on its own, there is much more to discover. Internally, the mini notation will expand to use the actual functional JavaScript API. ## Notes Notes are automatically available as variables: An important difference to the mini notation: For sharp notes, the letter "s" is used instead of "#", because JavaScript does not support "#" in a variable name. The above is the same as: Using strings, you can also use "#". ## Functions that create Patterns The following functions will return a pattern. We will see later what that means. ## pure(value) To create a pattern from a value, you can wrap the value in pure: Most of the time, you won't need that function as input values of pattern creating functions are purified by default. ### cat(...values) The given items are con**cat**enated, where each one takes one cycle: - Square brackets will create a subsequence - The function **slowcat** does the same as **cat**. ### seq(...values) Like **cat**, but the items are crammed into one cycle: - Synonyms: **fastcat**, **sequence** ### stack(...values) The given items are played at the same time at the same length: - Square Brackets will create a subsequence ### Nesting functions You can nest functions inside one another: The above is equivalent to "`} /> ### timeCat(...[weight,value]) Like with "@" in mini notation, we can specify weights to the items in a sequence: ### polyrhythm(...[...values]) Plays the given items at the same time, within the same length: We can write the same with **stack** and **cat**: You can also use the shorthand **pr** instead of **polyrhythm**. ## Time Modifiers The following functions modify a pattern temporal structure in some way. {{ 'Pattern.slow' | jsdoc }} {{ 'Pattern.fast' | jsdoc }} {{ 'Pattern.early' | jsdoc }} {{ 'Pattern.late' | jsdoc }} {{ 'Pattern.rev' | jsdoc }} ### struct(binary_pat) Applies the given structure to the pattern: This is also useful to sample signals: ## Conditional Modifiers {{ 'Pattern.every' | jsdoc }} {{ 'Pattern.each' | jsdoc }} ### when(binary_pat, func) Applies the given function whenever the given pattern is in a true state. /2", sub(5))`} /> ## Accumulation Modifiers ### stack(pat) Stacks the given pattern to the current pattern: ### superimpose(...func) Superimposes the result of the given function(s) on top of the original pattern: ".scale('C minor').superimpose(scaleTranspose("2,4"))`} /> ### layer(...func) Layers the result of the given function(s) on top of each other. Like superimpose, but the original pattern is not part of the result. ".scale('C minor').layer(scaleTranspose("0,2,4"))`} /> ### off(time, func) Applies the given function by the given time offset: ## Value Modifiers ### add(n) Adds the given number to each item in the pattern: ").scale('C major')`} /> Here, the triad `0, 2, 4` is shifted by different amounts. Without add, the equivalent would be: ".scale('C major')`} /> You can also use add with notes: ")`} /> Behind the scenes, the notes are converted to midi numbers as soon before add is applied, which is equivalent to: ")`} /> ### sub(n) Like add, but the given numbers are subtracted: ").scale('C4 minor')`} /> See add for more information. ### mul(n) Multiplies each number by the given factor: ").scale('C4 minor')`} /> ... is equivalent to: ".scale('C4 minor')`} /> This function is really useful in combination with signals: Here, we sample a sine wave 16 times, and multiply each sample by 7. This way, we let values oscillate between 0 and 7. ### div(n) Like mul, but dividing by the given number. ### round() Rounds all values to the nearest integer: ### apply(func) Like layer, but with a single function: ".scale('C minor').apply(scaleTranspose("0,2,4"))`} /> ## Randomness These methods add random behavior to your Patterns. {{ 'chooseCycles' | jsdoc }} {{ 'Pattern.degradeBy' | jsdoc }} {{ 'Pattern.degrade' | jsdoc }} {{ 'Pattern.undegradeBy' | jsdoc }} {{ 'Pattern.sometimesBy' | jsdoc }} {{ 'Pattern.sometimes' | jsdoc }} {{ 'Pattern.someCyclesBy' | jsdoc }} {{ 'Pattern.someCycles' | jsdoc }} {{ 'Pattern.often' | jsdoc }} {{ 'Pattern.rarely' | jsdoc }} {{ 'Pattern.almostNever' | jsdoc }} {{ 'Pattern.almostAlways' | jsdoc }} {{ 'Pattern.never' | jsdoc }} {{ 'Pattern.always' | jsdoc }} {{ 'rand' | jsdoc }} {{ 'perlin' | jsdoc }} {{ 'irand' | jsdoc }} ## Tone API To make the sounds more interesting, we can use Tone.js instruments ands effects. [Show Source on Github](https://github.com/tidalcycles/strudel/blob/main/repl/src/tone.ts) ### tone(instrument) To change the instrument of a pattern, you can pass any [Tone.js Source](https://tonejs.github.io/docs/14.7.77/index.html) to .tone: While this works, it is a little bit verbose. To simplify things, all Tone Synths have a shortcut: ```js const amsynth = (options) => new AMSynth(options); const duosynth = (options) => new DuoSynth(options); const fmsynth = (options) => new FMSynth(options); const membrane = (options) => new MembraneSynth(options); const metal = (options) => new MetalSynth(options); const monosynth = (options) => new MonoSynth(options); const noise = (options) => new NoiseSynth(options); const pluck = (options) => new PluckSynth(options); const polysynth = (options) => new PolySynth(options); const synth = (options) => new Synth(options); const sampler = (options, baseUrl?) => new Sampler(options); // promisified, see below const players = (options, baseUrl?) => new Sampler(options); // promisified, see below ``` ### sampler With sampler, you can create tonal instruments from samples: saw.struct("x*8").mul(16).round() .legato(4).scale('D dorian').slow(2) .tone(kalimba.toDestination()) )`} /> The sampler function promisifies [Tone.js Sampler](https://tonejs.github.io/docs/14.7.77/Sampler). Note that this function currently only works with this promise notation, but in the future, it will be possible to use async instruments in a synchronous fashion. ### players With players, you can create sound banks: "bd hh sn hh".tone(drums.toDestination()) ) `} /> The sampler function promisifies [Tone.js Players](https://tonejs.github.io/docs/14.7.77/Players). Note that this function currently only works with this promise notation, but in the future, it will be possible to use async instruments in a synchronous fashion. ### out Shortcut for Tone.Destination. Intended to be used with Tone's .chain: This alone is not really useful, so read on.. ### vol(volume) Helper that returns a Gain Node with the given volume. Intended to be used with Tone's .chain: ### osc(type) Helper to set the waveform of a synth, monosynth or polysynth: The base types are `sine`, `square`, `sawtooth`, `triangle`. You can also append a number between 1 and 32 to reduce the harmonic partials. ### lowpass(cutoff) Helper that returns a Filter Node of type lowpass with the given cutoff. Intended to be used with Tone's .chain: ### highpass(cutoff) Helper that returns a Filter Node of type highpass with the given cutoff. Intended to be used with Tone's .chain: ### adsr Helper to set the envelope of a Tone.js instrument. Intended to be used with Tone's .set: ## Tonal API The Tonal API, uses [tonaljs](https://github.com/tonaljs/tonal) to provide helpers for musical operations. ### transpose(semitones) Transposes all notes to the given number of semitones: ".slow(2)).transpose(0)`} /> This method gets really exciting when we use it with a pattern as above. Instead of numbers, scientific interval notation can be used as well: ".slow(2)).transpose(1)`} /> ### scale(name) Turns numbers into notes in the scale (zero indexed). Also sets scale for other scale operations, like scaleTranpose. Note that the scale root is octaved here. You can also omit the octave, then index zero will default to octave 3. All the available scale names can be found [here](https://github.com/tonaljs/tonal/blob/main/packages/scale-type/data.ts). ### scaleTranspose(steps) Transposes notes inside the scale by the number of steps: ")`} /> ### voicings(range?) Turns chord symbols into voicings, using the smoothest voice leading possible: ".voicings(), "")`} /> ### rootNotes(octave = 2) Turns chord symbols into root notes of chords in given octave. ".rootNotes(3)`} /> Together with layer, struct and voicings, this can be used to create a basic backing track: ".layer( x => x.voicings(['d3','g4']).struct("~ x"), x => x.rootNotes(2).tone(synth(osc('sawtooth4')).chain(out())) )`} /> ## Microtonal API TODO ## MIDI API Strudel also supports midi via [webmidi](https://npmjs.com/package/webmidi). ### midi(outputName?) Make sure to have a midi device connected or to use an IAC Driver. If no outputName is given, it uses the first midi output it finds. Midi is currently not supported by the mini repl used here, but you can [open the midi example in the repl](https://strudel.tidalcycles.org/#c3RhY2soIjxDXjcgQTcgRG03IEc3PiIubS52b2ljaW5ncygpLCAnPEMzIEEyIEQzIEcyPicubSkKICAubWlkaSgp). In the REPL, you will se a log of the available MIDI devices. # Contributing Contributions of any sort are very welcome! You can contribute by editing [this file](https://github.com/tidalcycles/strudel/blob/main/repl/src/tutorial/tutorial.mdx). All you need is a github account. If you want to run the tutorial locally, you can clone the and run: ```sh cd repl && npm i && npm run tutorial ``` If you want to contribute in another way, either - [fork strudel repo on GitHub](https://github.com/tidalcycles/strudel) - [Join the Discord Channel](https://discord.gg/remJ6gQA) - [play with the Strudel REPL](https://strudel.tidalcycles.org/)

# API Docs The following is generated from the source documentation. ## Pattern Factories The following functions will return a pattern. We will see later what that means. {{ 'pure' | jsdoc }} {{ 'slowcat' | jsdoc }} {{ 'fastcat' | jsdoc }} {{ 'stack' | jsdoc }} {{ 'timeCat' | jsdoc }} {{ 'polyrhythm' | jsdoc }} ## Pattern Modifiers {{ 'Pattern.slow' | jsdoc }} {{ 'Pattern.fast' | jsdoc }} {{ 'Pattern.early' | jsdoc }} {{ 'Pattern.late' | jsdoc }} {{ 'Pattern.rev' | jsdoc }} {{ 'Pattern.legato' | jsdoc }} ## Continuous Signals Signals are patterns with continuous values, meaning they have theoretically infinite steps. They can provide streams of numbers that can be sampled at discrete points in time. {{ 'Pattern.range' | jsdoc }} {{ 'saw' | jsdoc }} {{ 'saw2' | jsdoc }} {{ 'sine' | jsdoc }} {{ 'sine2' | jsdoc }} {{ 'cosine' | jsdoc }} {{ 'cosine2' | jsdoc }} {{ 'tri' | jsdoc }} {{ 'tri2' | jsdoc }} {{ 'square' | jsdoc }} {{ 'square2' | jsdoc }} ## Using Samples with Webdirt You can use the powerful sampling engine [Webdirt](https://github.com/dktr0/WebDirt) with Strudel. {{ 'Pattern.webdirt' | jsdoc }} ## Using Superdirt via OSC In mainline tidal, the actual sound is generated via Superdirt, which runs inside Supercollider. Strudel also supports using Superdirt as a backend, although it requires some developer tooling to run. ### Getting Started Getting Superdirt to work with Strudel, you need to 1. install SuperCollider + sc3 plugins, see [Tidal Docs](https://tidalcycles.org/docs/) (Install Tidal) for more info. 2. install [node.js](https://nodejs.org/en/) 3. download [Strudel Repo](https://github.com/tidalcycles/strudel/) (or git clone, if you have git installed) 4. run `npm i` in the strudel directory 5. run `npm run osc` to start the osc server, which forwards OSC messages from Strudel REPL to SuperCollider Now you're all set! ### Usage 1. Start SuperCollider, either using SuperCollider IDE or by running `sclang` in a terminal 2. Open the [Strudel REPL](https://strudel.tidalcycles.org/#cygiYmQgc2QiKS5vc2MoKQ%3D%3D) ...or test it here: If you now hear sound, congratulations! If not, you can get help on the [#strudel channel in the TidalCycles discord](https://discord.com/invite/HGEdXmRkzT). {{ 'Pattern.osc' | jsdoc }} # Superdirt Params The following functions are specific to SuperDirt and won't work with other Strudel outputs. ## Basic Types {{ 's' | jsdoc }} {{ 'n' | jsdoc }} {{ 'freq' | jsdoc }} {{ 'channel' | jsdoc }} {{ 'orbit' | jsdoc }} ## Filters {{ 'cutoff' | jsdoc }} {{ 'resonance' | jsdoc }} {{ 'hcutoff' | jsdoc }} {{ 'hresonance' | jsdoc }} {{ 'bandf' | jsdoc }} {{ 'bandq' | jsdoc }} {{ 'djf' | jsdoc }} {{ 'vowel' | jsdoc }} ## Sample Editing {{ 'cut' | jsdoc }} {{ 'begin' | jsdoc }} {{ 'end' | jsdoc }} {{ 'loop' | jsdoc }} {{ 'fadeTime' | jsdoc }} {{ 'speed' | jsdoc }} {{ 'unit' | jsdoc }} ## Audio Effects {{ 'gain' | jsdoc }} {{ 'amp' | jsdoc }} {{ 'accelerate' | jsdoc }} {{ 'crush' | jsdoc }} {{ 'coarse' | jsdoc }} {{ 'delay' | jsdoc }} {{ 'lock' | jsdoc }} {{ 'leslie' | jsdoc }} {{ 'lrate' | jsdoc }} {{ 'lsize' | jsdoc }} {{ 'pan' | jsdoc }} {{ 'panspan' | jsdoc }} {{ 'pansplay' | jsdoc }} {{ 'room' | jsdoc }} {{ 'size' | jsdoc }} {{ 'dry' | jsdoc }} {{ 'shape' | jsdoc }} {{ 'squiz' | jsdoc }} {{ 'waveloss' | jsdoc }} {{ 'attack' | jsdoc }} {{ 'decay' | jsdoc }} ## Synth Effects {{ 'octave' | jsdoc }} {{ 'detune' | jsdoc }} {{ 'tremolodepth' | jsdoc }}