From 08c4c641ecdba6e6af503ddee58939ca39546aea Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 29 Oct 2022 17:38:54 +0200 Subject: [PATCH] add note calls everywhere --- packages/core/euclid.mjs | 44 +++++++++++++-------------- packages/core/pattern.mjs | 34 ++++++++++----------- packages/core/signal.mjs | 10 +++---- packages/tonal/tonal.mjs | 8 +++-- packages/tonal/voicings.mjs | 2 +- tutorial/tutorial.mdx | 59 ++++++++++++++++++++++++++++--------- 6 files changed, 95 insertions(+), 62 deletions(-) diff --git a/packages/core/euclid.mjs b/packages/core/euclid.mjs index 8cb36857..45a59783 100644 --- a/packages/core/euclid.mjs +++ b/packages/core/euclid.mjs @@ -32,52 +32,52 @@ const euclid = (pulses, steps, rotation = 0) => { * @returns Pattern * @example * // The Cuban tresillo pattern. - * n("c3").euclid(3,8) + * note("c3").euclid(3,8) */ /** * @example // A thirteenth century Persian rhythm called Khafif-e-ramal. - * n("c3").euclid(2,5) + * note("c3").euclid(2,5) * @example // The archetypal pattern of the Cumbia from Colombia, as well as a Calypso rhythm from Trinidad. - * "c3".euclid(3,4) + * note("c3").euclid(3,4) * @example // Another thirteenth century Persian rhythm by the name of Khafif-e-ramal, as well as a Rumanian folk-dance rhythm. - * "c3".euclid(3,5,2) + * note("c3").euclid(3,5,2) * @example // A Ruchenitza rhythm used in a Bulgarian folk-dance. - * "c3".euclid(3,7) + * note("c3").euclid(3,7) * @example // The Cuban tresillo pattern. - * "c3".euclid(3,8) + * note("c3").euclid(3,8) * @example // Another Ruchenitza Bulgarian folk-dance rhythm. - * "c3".euclid(4,7) + * note("c3").euclid(4,7) * @example // The Aksak rhythm of Turkey. - * "c3".euclid(4,9) + * note("c3").euclid(4,9) * @example // The metric pattern used by Frank Zappa in his piece titled Outside Now. - * "c3".euclid(4,11) + * note("c3").euclid(4,11) * @example // Yields the York-Samai pattern, a popular Arab rhythm. - * "c3".euclid(5,6) + * note("c3").euclid(5,6) * @example // The Nawakhat pattern, another popular Arab rhythm. - * "c3".euclid(5,7) + * note("c3").euclid(5,7) * @example // The Cuban cinquillo pattern. - * "c3".euclid(5,8) + * note("c3").euclid(5,8) * @example // A popular Arab rhythm called Agsag-Samai. - * "c3".euclid(5,9) + * note("c3").euclid(5,9) * @example // The metric pattern used by Moussorgsky in Pictures at an Exhibition. - * "c3".euclid(5,11) + * note("c3").euclid(5,11) * @example // The Venda clapping pattern of a South African children’s song. - * "c3".euclid(5,12) + * note("c3").euclid(5,12) * @example // The Bossa-Nova rhythm necklace of Brazil. - * "c3".euclid(5,16) + * note("c3").euclid(5,16) * @example // A typical rhythm played on the Bendir (frame drum). - * "c3".euclid(7,8) + * note("c3").euclid(7,8) * @example // A common West African bell pattern. - * "c3".euclid(7,12) + * note("c3").euclid(7,12) * @example // A Samba rhythm necklace from Brazil. - * "c3".euclid(7,16,14) + * note("c3").euclid(7,16,14) * @example // A rhythm necklace used in the Central African Republic. - * "c3".euclid(9,16) + * note("c3").euclid(9,16) * @example // A rhythm necklace of the Aka Pygmies of Central Africa. - * "c3".euclid(11,24,14) + * note("c3").euclid(11,24,14) * @example // Another rhythm necklace of the Aka Pygmies of the upper Sangha. - * "c3".euclid(13,24,5) + * note("c3").euclid(13,24,5) */ Pattern.prototype.euclid = function (pulses, steps, rotation = 0) { return this.struct(euclid(pulses, steps, rotation)); diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 3750539b..e98c69e1 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -472,7 +472,7 @@ export class Pattern { * @memberof Pattern * @returns Pattern * @example - * "0.5 1.5 2.5".round().scale('C major') + * "0.5 1.5 2.5".round().scale('C major').note() */ round() { return this._asNumber().fmap((v) => Math.round(v)); @@ -704,7 +704,7 @@ export class Pattern { * @name apply * @memberof Pattern * @example - * "".scale('C minor').apply(scaleTranspose("0,2,4")) + * "".scale('C minor').apply(scaleTranspose("0,2,4")).note() */ _apply(func) { return func(this); @@ -925,9 +925,9 @@ export class Pattern { * @memberof Pattern * @returns Pattern * @example - * "c3,eb3,g3" + * note("c3,eb3,g3") * .struct("x ~ x ~ ~ x ~ x ~ ~ ~ x ~ x ~ ~") - * .slow(4).note() + * .slow(4) */ // struct(...binary_pats) { // // Re structure the pattern according to a binary pattern (false values are dropped) @@ -984,7 +984,7 @@ export class Pattern { * @param {function} func * @returns Pattern * @example - * "c3 eb3 g3".when("<0 1>/2", x=>x.sub(5)) + * "c3 eb3 g3".when("<0 1>/2", x=>x.sub(5)).note() */ when(binary_pat, func) { //binary_pat = sequence(binary_pat) @@ -1003,7 +1003,7 @@ export class Pattern { * @param {function} func function to apply * @returns Pattern * @example - * "c3 eb3 g3".off(1/8, x=>x.add(7)) + * "c3 eb3 g3".off(1/8, x=>x.add(7)).note() */ off(time_pat, func) { return stack(this, func(this.late(time_pat))); @@ -1077,7 +1077,7 @@ export class Pattern { * @memberof Pattern * @returns Pattern * @example - * "c3 d3 e3 g3".rev() + * note("c3 d3 e3 g3").rev() */ rev() { const pat = this; @@ -1297,7 +1297,7 @@ export class Pattern { * @name legato * @memberof Pattern * @example - * n("c3 eb3 g3 c4").legato("<.25 .5 1 2>") + * note("c3 eb3 g3 c4").legato("<.25 .5 1 2>") */ _legato(value) { return this.withHapSpan((span) => new TimeSpan(span.begin, span.begin.add(span.end.sub(span.begin).mul(value)))); @@ -1387,14 +1387,14 @@ function _composeOp(a, b, func) { * @memberof Pattern * @example * // Here, the triad 0, 2, 4 is shifted by different amounts - * "0 2 4".add("<0 3 4 0>").scale('C major') + * "0 2 4".add("<0 3 4 0>").scale('C major').note() * // Without add, the equivalent would be: - * // "<[0 2 4] [3 5 7] [4 6 8] [0 2 4]>".scale('C major') + * // "<[0 2 4] [3 5 7] [4 6 8] [0 2 4]>".scale('C major').note() * @example * // You can also use add with notes: - * "c3 e3 g3".add("<0 5 7 0>") + * "c3 e3 g3".add("<0 5 7 0>").note() * // Behind the scenes, the notes are converted to midi numbers: - * // "48 52 55".add("<0 5 7 0>") + * // "48 52 55".add("<0 5 7 0>").note() */ add: [(a, b) => a + b, numOrString], // support string concatenation /** @@ -1403,7 +1403,7 @@ function _composeOp(a, b, func) { * @name sub * @memberof Pattern * @example - * "0 2 4".sub("<0 1 2 3>").scale('C4 minor') + * "0 2 4".sub("<0 1 2 3>").scale('C4 minor').note() * // See add for more information. */ sub: [(a, b) => a - b, num], @@ -1579,7 +1579,7 @@ export function reify(thing) { * * @return {Pattern} * @example - * stack(g3, b3, [e4, d4]) // "g3,b3,[e4,d4]" + * stack(g3, b3, [e4, d4]).note() // "g3,b3,[e4,d4]".note() */ export function stack(...pats) { // Array test here is to avoid infinite recursions.. @@ -1652,7 +1652,7 @@ export function fastcat(...pats) { * @param {...any} items - The items to concatenate * @return {Pattern} * @example - * cat(e5, b4, [d5, c5]) // "" + * cat(e5, b4, [d5, c5]).note() // "".note() * */ export function cat(...pats) { @@ -1662,7 +1662,7 @@ export function cat(...pats) { /** Like {@link seq}, but each step has a length, relative to the whole. * @return {Pattern} * @example - * timeCat([3,e3],[1, g3]) // "e3@3 g3" + * timeCat([3,e3],[1, g3]).note() // "e3@3 g3".note() */ export function timeCat(...timepats) { const total = timepats.map((a) => a[0]).reduce((a, b) => a.add(b), Fraction(0)); @@ -1683,7 +1683,7 @@ export function sequence(...pats) { /** Like **cat**, but the items are crammed into one cycle. Synonyms: fastcat, sequence * @example - * seq(e5, b4, [d5, c5]) // "e5 b4 [d5 c5]" + * seq(e5, b4, [d5, c5]).note() // "e5 b4 [d5 c5]".note() * */ export function seq(...pats) { diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index a33e3bdb..825c1cf1 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -27,9 +27,9 @@ export const isaw2 = isaw._toBipolar(); * * @return {Pattern} * @example - * "c3 [eb3,g3] g2 [g3,bb3]".legato(saw.slow(4)) + * "c3 [eb3,g3] g2 [g3,bb3]".legato(saw.slow(4)).note() * @example - * saw.range(0,8).segment(8).scale('C major').slow(4) + * saw.range(0,8).segment(8).scale('C major').slow(4).note() * */ export const saw = signal((t) => t % 1); @@ -42,7 +42,7 @@ export const sine2 = signal((t) => Math.sin(Math.PI * 2 * t)); * * @return {Pattern} * @example - * sine.segment(16).range(0,15).slow(2).scale('C minor') + * sine.segment(16).range(0,15).slow(2).scale('C minor').note() * */ export const sine = sine2._fromBipolar(); @@ -52,7 +52,7 @@ export const sine = sine2._fromBipolar(); * * @return {Pattern} * @example - * stack(sine,cosine).segment(16).range(0,15).slow(2).scale('C minor') + * stack(sine,cosine).segment(16).range(0,15).slow(2).scale('C minor').note() * */ export const cosine = sine._early(Fraction(1).div(4)); @@ -63,7 +63,7 @@ export const cosine2 = sine2._early(Fraction(1).div(4)); * * @return {Pattern} * @example - * square.segment(2).range(0,7).scale('C minor') + * square.segment(2).range(0,7).scale('C minor').note() * */ export const square = signal((t) => Math.floor((t * 2) % 2)); diff --git a/packages/tonal/tonal.mjs b/packages/tonal/tonal.mjs index 10140e78..35fbaba3 100644 --- a/packages/tonal/tonal.mjs +++ b/packages/tonal/tonal.mjs @@ -69,9 +69,9 @@ function scaleOffset(scale, offset, note) { * @memberof Pattern * @name transpose * @example - * "c2 c3".fast(2).transpose("<0 -2 5 3>".slow(2)).transpose(0) + * "c2 c3".fast(2).transpose("<0 -2 5 3>".slow(2)).note() * @example - * "c2 c3".fast(2).transpose("<1P -2M 4P 3m>".slow(2)).transpose(0) + * "c2 c3".fast(2).transpose("<1P -2M 4P 3m>".slow(2)).note() */ Pattern.prototype._transpose = function (intervalOrSemitones) { @@ -107,6 +107,7 @@ Pattern.prototype._transpose = function (intervalOrSemitones) { * "-8 [2,4,6]" * .scale('C4 bebop major') * .scaleTranspose("<0 -1 -2 -3 -4 -5 -6 -4>") + * .note() */ Pattern.prototype._scaleTranspose = function (offset /* : number | string */) { @@ -134,9 +135,10 @@ Pattern.prototype._scaleTranspose = function (offset /* : number | string */) { * @name scale * @param {string} scale Name of scale * @returns Pattern - * @example + * @example * "0 2 4 6 4 2" * .scale(seq('C2 major', 'C2 minor').slow(2)) + * .note() */ Pattern.prototype._scale = function (scale /* : string */) { diff --git a/packages/tonal/voicings.mjs b/packages/tonal/voicings.mjs index 046fa02b..785f76d0 100644 --- a/packages/tonal/voicings.mjs +++ b/packages/tonal/voicings.mjs @@ -40,7 +40,7 @@ Pattern.prototype.fmapNested = function (func) { * @param {range} range note range for possible voicings (optional, defaults to `['F3', 'A4']`) * @returns Pattern * @example - * stack("".voicings(), "") + * stack("".voicings(), "").note() */ Pattern.prototype.voicings = function (range) { diff --git a/tutorial/tutorial.mdx b/tutorial/tutorial.mdx index ce90569a..de12742e 100644 --- a/tutorial/tutorial.mdx +++ b/tutorial/tutorial.mdx @@ -260,9 +260,9 @@ resulting in a rhythmical structure of "x ~ ~ x ~ ~ x ~" (3 beats over 8 segment
-# Web Audio Output +# Synths, Samples & Effects -The default way to output sound is by using the Web Audio Output. +Let's take a closer look at how we can control synths, sounds and effects. ## Synths @@ -447,11 +447,38 @@ Wether you're using a synth or a sample, you can apply these effects:
-# Core API +# JavaScript 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. +For example, this Pattern in Mini Notation: + + + +is equivalent to this Pattern without Mini Notation: + + + +Similarly, there is an equivalent function for every aspect of the mini notation. + +Which representation to use is a matter of context. As a rule of thumb, you can think of the JavaScript API +to fit better for the larger context, while mini notation is more practical for individiual rhythms. + +## Limits of Mini Notation + +While the Mini Notation is a powerful way to write rhythms shortly, it also has its limits. Take this example: + + + +Here, we are using mini notation for the individual rhythms, while using the function `stack` to mix them. +While stack is also available as `,` in mini notation, we cannot use it here, because we have different types of sounds. + ## Notes Notes are automatically available as variables: @@ -474,15 +501,17 @@ To avoid getting to many nested parens, there is an alternative syntax to add a -You can use this with any function that declares a type, just make sure to leave the parens empty! +You can use this with any function that declares a type (like `n`, `s`, `note`, `freq` etc), just make sure to leave the parens empty! ## Pattern Factories The following functions will return a pattern. + {{ 'cat' | jsdoc }} @@ -526,7 +555,7 @@ You can freely mix JS patterns, mini patterns and values! For example, this patt stack(a3,c3,e4), stack(b3,d3,fs4), stack(b3,e4,g4) -)`} +).note()`} /> ...is equivalent to: @@ -537,12 +566,12 @@ You can freely mix JS patterns, mini patterns and values! For example, this patt "a3,c3,e4", "b3,d3,f#4", "b3,e4,g4" -)`} +).note()`} /> ... as well as: -"`} /> +")`} /> While mini notation is almost always shorter, it only has a handful of modifiers: \* / ! @. When using JS patterns, there is a lot more you can do. @@ -689,13 +718,13 @@ The Tonal API, uses [tonaljs](https://github.com/tonaljs/tonal) to provide helpe Transposes all notes to the given number of semitones: -".slow(2)).transpose(0)`} /> +".slow(2)).note()`} /> 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)`} /> +".slow(2)).note()`} /> ### scale(name) @@ -703,7 +732,8 @@ Turns numbers into notes in the scale (zero indexed). Also sets scale for other Note that the scale root is octaved here. You can also omit the octave, then index zero will default to octave 3. @@ -717,14 +747,15 @@ Transposes notes inside the scale by the number of steps: ")`} +.scaleTranspose("<0 -1 -2 -3 -4 -5 -6 -4>") +.note()`} /> ### voicings(range?) Turns chord symbols into voicings, using the smoothest voice leading possible: -".voicings(), "")`} /> +".voicings(), "").note()`} /> @@ -732,7 +763,7 @@ Turns chord symbols into voicings, using the smoothest voice leading possible: Turns chord symbols into root notes of chords in given octave. -".rootNotes(3)`} /> +".rootNotes(3).note()`} /> Together with layer, struct and voicings, this can be used to create a basic backing track: @@ -740,7 +771,7 @@ Together with layer, struct and voicings, this can be used to create a basic bac tune={`"".layer( x => x.voicings(['d3','g4']).struct("~ x"), x => x.rootNotes(2).tone(synth(osc('sawtooth4')).chain(out())) -)`} +).note()`} />