add note calls everywhere

This commit is contained in:
Felix Roos 2022-10-29 17:38:54 +02:00
parent 5d7e46b246
commit 08c4c641ec
6 changed files with 95 additions and 62 deletions

View File

@ -32,52 +32,52 @@ const euclid = (pulses, steps, rotation = 0) => {
* @returns Pattern * @returns Pattern
* @example * @example
* // The Cuban tresillo pattern. * // The Cuban tresillo pattern.
* n("c3").euclid(3,8) * note("c3").euclid(3,8)
*/ */
/** /**
* @example // A thirteenth century Persian rhythm called Khafif-e-ramal. * @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. * @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. * @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. * @example // A Ruchenitza rhythm used in a Bulgarian folk-dance.
* "c3".euclid(3,7) * note("c3").euclid(3,7)
* @example // The Cuban tresillo pattern. * @example // The Cuban tresillo pattern.
* "c3".euclid(3,8) * note("c3").euclid(3,8)
* @example // Another Ruchenitza Bulgarian folk-dance rhythm. * @example // Another Ruchenitza Bulgarian folk-dance rhythm.
* "c3".euclid(4,7) * note("c3").euclid(4,7)
* @example // The Aksak rhythm of Turkey. * @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. * @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. * @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. * @example // The Nawakhat pattern, another popular Arab rhythm.
* "c3".euclid(5,7) * note("c3").euclid(5,7)
* @example // The Cuban cinquillo pattern. * @example // The Cuban cinquillo pattern.
* "c3".euclid(5,8) * note("c3").euclid(5,8)
* @example // A popular Arab rhythm called Agsag-Samai. * @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. * @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 childrens song. * @example // The Venda clapping pattern of a South African childrens song.
* "c3".euclid(5,12) * note("c3").euclid(5,12)
* @example // The Bossa-Nova rhythm necklace of Brazil. * @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). * @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. * @example // A common West African bell pattern.
* "c3".euclid(7,12) * note("c3").euclid(7,12)
* @example // A Samba rhythm necklace from Brazil. * @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. * @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. * @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. * @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) { Pattern.prototype.euclid = function (pulses, steps, rotation = 0) {
return this.struct(euclid(pulses, steps, rotation)); return this.struct(euclid(pulses, steps, rotation));

View File

@ -472,7 +472,7 @@ export class Pattern {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* "0.5 1.5 2.5".round().scale('C major') * "0.5 1.5 2.5".round().scale('C major').note()
*/ */
round() { round() {
return this._asNumber().fmap((v) => Math.round(v)); return this._asNumber().fmap((v) => Math.round(v));
@ -704,7 +704,7 @@ export class Pattern {
* @name apply * @name apply
* @memberof Pattern * @memberof Pattern
* @example * @example
* "<c3 eb3 g3>".scale('C minor').apply(scaleTranspose("0,2,4")) * "<c3 eb3 g3>".scale('C minor').apply(scaleTranspose("0,2,4")).note()
*/ */
_apply(func) { _apply(func) {
return func(this); return func(this);
@ -925,9 +925,9 @@ export class Pattern {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* "c3,eb3,g3" * note("c3,eb3,g3")
* .struct("x ~ x ~ ~ x ~ x ~ ~ ~ x ~ x ~ ~") * .struct("x ~ x ~ ~ x ~ x ~ ~ ~ x ~ x ~ ~")
* .slow(4).note() * .slow(4)
*/ */
// struct(...binary_pats) { // struct(...binary_pats) {
// // Re structure the pattern according to a binary pattern (false values are dropped) // // Re structure the pattern according to a binary pattern (false values are dropped)
@ -984,7 +984,7 @@ export class Pattern {
* @param {function} func * @param {function} func
* @returns Pattern * @returns Pattern
* @example * @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) { when(binary_pat, func) {
//binary_pat = sequence(binary_pat) //binary_pat = sequence(binary_pat)
@ -1003,7 +1003,7 @@ export class Pattern {
* @param {function} func function to apply * @param {function} func function to apply
* @returns Pattern * @returns Pattern
* @example * @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) { off(time_pat, func) {
return stack(this, func(this.late(time_pat))); return stack(this, func(this.late(time_pat)));
@ -1077,7 +1077,7 @@ export class Pattern {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* "c3 d3 e3 g3".rev() * note("c3 d3 e3 g3").rev()
*/ */
rev() { rev() {
const pat = this; const pat = this;
@ -1297,7 +1297,7 @@ export class Pattern {
* @name legato * @name legato
* @memberof Pattern * @memberof Pattern
* @example * @example
* n("c3 eb3 g3 c4").legato("<.25 .5 1 2>") * note("c3 eb3 g3 c4").legato("<.25 .5 1 2>")
*/ */
_legato(value) { _legato(value) {
return this.withHapSpan((span) => new TimeSpan(span.begin, span.begin.add(span.end.sub(span.begin).mul(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 * @memberof Pattern
* @example * @example
* // Here, the triad 0, 2, 4 is shifted by different amounts * // 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: * // 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 * @example
* // You can also use add with notes: * // 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: * // 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 add: [(a, b) => a + b, numOrString], // support string concatenation
/** /**
@ -1403,7 +1403,7 @@ function _composeOp(a, b, func) {
* @name sub * @name sub
* @memberof Pattern * @memberof Pattern
* @example * @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. * // See add for more information.
*/ */
sub: [(a, b) => a - b, num], sub: [(a, b) => a - b, num],
@ -1579,7 +1579,7 @@ export function reify(thing) {
* *
* @return {Pattern} * @return {Pattern}
* @example * @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) { export function stack(...pats) {
// Array test here is to avoid infinite recursions.. // Array test here is to avoid infinite recursions..
@ -1652,7 +1652,7 @@ export function fastcat(...pats) {
* @param {...any} items - The items to concatenate * @param {...any} items - The items to concatenate
* @return {Pattern} * @return {Pattern}
* @example * @example
* cat(e5, b4, [d5, c5]) // "<e5 b4 [d5 c5]>" * cat(e5, b4, [d5, c5]).note() // "<e5 b4 [d5 c5]>".note()
* *
*/ */
export function cat(...pats) { 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. /** Like {@link seq}, but each step has a length, relative to the whole.
* @return {Pattern} * @return {Pattern}
* @example * @example
* timeCat([3,e3],[1, g3]) // "e3@3 g3" * timeCat([3,e3],[1, g3]).note() // "e3@3 g3".note()
*/ */
export function timeCat(...timepats) { export function timeCat(...timepats) {
const total = timepats.map((a) => a[0]).reduce((a, b) => a.add(b), Fraction(0)); 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 /** Like **cat**, but the items are crammed into one cycle. Synonyms: fastcat, sequence
* @example * @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) { export function seq(...pats) {

View File

@ -27,9 +27,9 @@ export const isaw2 = isaw._toBipolar();
* *
* @return {Pattern} * @return {Pattern}
* @example * @example
* "c3 [eb3,g3] g2 [g3,bb3]".legato(saw.slow(4)) * "c3 [eb3,g3] g2 [g3,bb3]".legato(saw.slow(4)).note()
* @example * @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); export const saw = signal((t) => t % 1);
@ -42,7 +42,7 @@ export const sine2 = signal((t) => Math.sin(Math.PI * 2 * t));
* *
* @return {Pattern} * @return {Pattern}
* @example * @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(); export const sine = sine2._fromBipolar();
@ -52,7 +52,7 @@ export const sine = sine2._fromBipolar();
* *
* @return {Pattern} * @return {Pattern}
* @example * @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)); export const cosine = sine._early(Fraction(1).div(4));
@ -63,7 +63,7 @@ export const cosine2 = sine2._early(Fraction(1).div(4));
* *
* @return {Pattern} * @return {Pattern}
* @example * @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)); export const square = signal((t) => Math.floor((t * 2) % 2));

View File

@ -69,9 +69,9 @@ function scaleOffset(scale, offset, note) {
* @memberof Pattern * @memberof Pattern
* @name transpose * @name transpose
* @example * @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 * @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) { Pattern.prototype._transpose = function (intervalOrSemitones) {
@ -107,6 +107,7 @@ Pattern.prototype._transpose = function (intervalOrSemitones) {
* "-8 [2,4,6]" * "-8 [2,4,6]"
* .scale('C4 bebop major') * .scale('C4 bebop major')
* .scaleTranspose("<0 -1 -2 -3 -4 -5 -6 -4>") * .scaleTranspose("<0 -1 -2 -3 -4 -5 -6 -4>")
* .note()
*/ */
Pattern.prototype._scaleTranspose = function (offset /* : number | string */) { Pattern.prototype._scaleTranspose = function (offset /* : number | string */) {
@ -134,9 +135,10 @@ Pattern.prototype._scaleTranspose = function (offset /* : number | string */) {
* @name scale * @name scale
* @param {string} scale Name of scale * @param {string} scale Name of scale
* @returns Pattern * @returns Pattern
* @example * @example
* "0 2 4 6 4 2" * "0 2 4 6 4 2"
* .scale(seq('C2 major', 'C2 minor').slow(2)) * .scale(seq('C2 major', 'C2 minor').slow(2))
* .note()
*/ */
Pattern.prototype._scale = function (scale /* : string */) { Pattern.prototype._scale = function (scale /* : string */) {

View File

@ -40,7 +40,7 @@ Pattern.prototype.fmapNested = function (func) {
* @param {range} range note range for possible voicings (optional, defaults to `['F3', 'A4']`) * @param {range} range note range for possible voicings (optional, defaults to `['F3', 'A4']`)
* @returns Pattern * @returns Pattern
* @example * @example
* stack("<C^7 A7 Dm7 G7>".voicings(), "<C3 A2 D3 G2>") * stack("<C^7 A7 Dm7 G7>".voicings(), "<C3 A2 D3 G2>").note()
*/ */
Pattern.prototype.voicings = function (range) { Pattern.prototype.voicings = function (range) {

View File

@ -260,9 +260,9 @@ resulting in a rhythmical structure of "x ~ ~ x ~ ~ x ~" (3 beats over 8 segment
<br /> <br />
# 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 ## Synths
@ -447,11 +447,38 @@ Wether you're using a synth or a sample, you can apply these effects:
<br /> <br />
# Core API # JavaScript API
While the mini notation is powerful on its own, there is much more to discover. 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. Internally, the mini notation will expand to use the actual functional JavaScript API.
For example, this Pattern in Mini Notation:
<MiniRepl tune={`note("c3 eb3 g3")`} />
is equivalent to this Pattern without Mini Notation:
<MiniRepl tune={`note(seq(c3, eb3, g3))`} />
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:
<MiniRepl
tune={`stack(
note("c2 eb2(3,8)").s('sawtooth').cutoff(800),
s("bd,~ sd,hh*4")
)`}
/>
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
Notes are automatically available as variables: 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
<MiniRepl tune={`seq(d4, fs4, a4).note()`} /> <MiniRepl tune={`seq(d4, fs4, a4).note()`} />
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 ## Pattern Factories
The following functions will return a pattern. The following functions will return a pattern.
<!--
{{ 'pure' | jsdoc }} {{ 'pure' | jsdoc }}
Most of the time, you won't need that function as input values of pattern creating functions are purified by default. Most of the time, you won't need that function as input values of pattern creating functions are purified by default.
-->
{{ 'cat' | jsdoc }} {{ '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(a3,c3,e4),
stack(b3,d3,fs4), stack(b3,d3,fs4),
stack(b3,e4,g4) stack(b3,e4,g4)
)`} ).note()`}
/> />
...is equivalent to: ...is equivalent to:
@ -537,12 +566,12 @@ You can freely mix JS patterns, mini patterns and values! For example, this patt
"a3,c3,e4", "a3,c3,e4",
"b3,d3,f#4", "b3,d3,f#4",
"b3,e4,g4" "b3,e4,g4"
)`} ).note()`}
/> />
... as well as: ... as well as:
<MiniRepl tune={`"<[g3,b3,e4] [a3,c3,e4] [b3,d3,f#4] [b3,e4,g4]>"`} /> <MiniRepl tune={`note("<[g3,b3,e4] [a3,c3,e4] [b3,d3,f#4] [b3,e4,g4]>")`} />
While mini notation is almost always shorter, it only has a handful of modifiers: \* / ! @. 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. 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: Transposes all notes to the given number of semitones:
<MiniRepl tune={`"c2 c3".fast(2).transpose("<0 -2 5 3>".slow(2)).transpose(0)`} /> <MiniRepl tune={`"c2 c3".fast(2).transpose("<0 -2 5 3>".slow(2)).note()`} />
This method gets really exciting when we use it with a pattern as above. 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: Instead of numbers, scientific interval notation can be used as well:
<MiniRepl tune={`"c2 c3".fast(2).transpose("<1P -2M 4P 3m>".slow(2)).transpose(1)`} /> <MiniRepl tune={`"c2 c3".fast(2).transpose("<1P -2M 4P 3m>".slow(2)).note()`} />
### scale(name) ### scale(name)
@ -703,7 +732,8 @@ Turns numbers into notes in the scale (zero indexed). Also sets scale for other
<MiniRepl <MiniRepl
tune={`"0 2 4 6 4 2" tune={`"0 2 4 6 4 2"
.scale(seq('C2 major', 'C2 minor').slow(2))`} .scale(seq('C2 major', 'C2 minor').slow(2))
.note()`}
/> />
Note that the scale root is octaved here. You can also omit the octave, then index zero will default to octave 3. 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:
<MiniRepl <MiniRepl
tune={`"-8 [2,4,6]" tune={`"-8 [2,4,6]"
.scale('C4 bebop major') .scale('C4 bebop major')
.scaleTranspose("<0 -1 -2 -3 -4 -5 -6 -4>")`} .scaleTranspose("<0 -1 -2 -3 -4 -5 -6 -4>")
.note()`}
/> />
### voicings(range?) ### voicings(range?)
Turns chord symbols into voicings, using the smoothest voice leading possible: Turns chord symbols into voicings, using the smoothest voice leading possible:
<MiniRepl tune={`stack("<C^7 A7 Dm7 G7>".voicings(), "<C3 A2 D3 G2>")`} /> <MiniRepl tune={`stack("<C^7 A7 Dm7 G7>".voicings(), "<C3 A2 D3 G2>").note()`} />
<!-- TODO: use voicing collection as first param + patternify. --> <!-- TODO: use voicing collection as first param + patternify. -->
@ -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. Turns chord symbols into root notes of chords in given octave.
<MiniRepl tune={`"<C^7 A7b13 Dm7 G7>".rootNotes(3)`} /> <MiniRepl tune={`"<C^7 A7b13 Dm7 G7>".rootNotes(3).note()`} />
Together with layer, struct and voicings, this can be used to create a basic backing track: 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={`"<C^7 A7b13 Dm7 G7>".layer( tune={`"<C^7 A7b13 Dm7 G7>".layer(
x => x.voicings(['d3','g4']).struct("~ x"), x => x.voicings(['d3','g4']).struct("~ x"),
x => x.rootNotes(2).tone(synth(osc('sawtooth4')).chain(out())) x => x.rootNotes(2).tone(synth(osc('sawtooth4')).chain(out()))
)`} ).note()`}
/> />
<!-- TODO: use range instead of octave. --> <!-- TODO: use range instead of octave. -->