Skip to content

Commit

Permalink
Add tables of contents to docs
Browse files Browse the repository at this point in the history
Expand tempering section.
Fix val standard basis conversion.
Use the orthogonal basis instead of the dual for minor increase in clarity.
Make output of errorTE human-readable.
Implement nextGPV and supportingGPVs.

ref #336, #370
  • Loading branch information
frostburn committed Jun 28, 2024
1 parent c2aab91 commit 6e2537f
Show file tree
Hide file tree
Showing 21 changed files with 1,070 additions and 285 deletions.
15 changes: 12 additions & 3 deletions documentation/BUILTIN.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ Obtain the docstring of the given riff.
### entries(*record*)
Obtain an array of `[key, value]` pairs of the record.

### errorTE(*val*, *weights*)
Calculate Tenney-Euclid error w.r.t the vals basis. Weights are applied multiplicatively on top of Tenney weights if given.
### errorTE(*val*, *weights*, *unnormalized = false*)
Calculate Tenney-Euclid error w.r.t the vals basis. Weights are applied multiplicatively on top of Tenney weights if given. Unnormalized values are slightly faster to compute and are in the linear domain instead of (logarithmic) cents.

### every(*array = $$*, *test*)
Tests whether all elements in the array pass the test implemented by the provided function. It returns a Boolean value. It doesn't modify the array. If no array is provided it defaults to the current scale. If no test is provided it defaults to truthiness.
Expand Down Expand Up @@ -241,7 +241,7 @@ Return the label of the interval.
Obtain the smallest (linear) interval that shares both arguments as multiplicative factors. Applies to the current scale if not arguments are given.

### length(*scale = $$*)
Return the number of intervals in the scale.
Return the number of intervals in the scale, the length of a string or the size of a basis.

### linear(*interval*)
Convert interval to linear representation. Formatting information of logarithmic quantities is lost.
Expand Down Expand Up @@ -276,6 +276,9 @@ Calculate a subset of equally tempered degrees with maximum variety two per scal
### nedji(*interval*, *preferredNumerator*, *preferredDenominator*, *preferredEquaveNumerator*, *preferredEquaveDenominator*)
Convert interval to N-steps-of-Equally-Divided-interval-of-Just-Intonation.

### nextGPV(*val*, *weights*)
Obtain the next generalized patent val in the sequence.

### nthPrime(*interval*)
Obtain the nth odd prime or prime 2 if n = 0.

Expand Down Expand Up @@ -414,6 +417,9 @@ Prepend an interval at the beginning of the current/given scale.
### valFromPrimeArray(*primeExponents*, *basis*)
Convert an array of prime mapping entries to a val.

### vstr(*value*)
Obtain a string representation of a primitive value (w/o color or label). Vectorizes over arrays.

### warn(*...args*)
Print the arguments to the console with "warning" emphasis.

Expand Down Expand Up @@ -701,6 +707,9 @@ Obtain a copy of the popped/given scale with only the given degrees kept. Omitti
### sum(*terms = $$*)
Calculate the (linear) sum of the terms or the current scale.

### supportingGPVs(*initialVal*, *commas*, *count = 5*, *weights = niente*, *maxIter = 1000*)
Obtain generalized patent vals in the same sequence as the initial val that make the given commas vanish.

### tanh(*x*)
Calculate the hyperbolic tangent of x.

Expand Down
178 changes: 63 additions & 115 deletions documentation/advanced-dsl.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,64 @@
# SonicWeave DSL (advanced)
This document describes programming in the SonicWeave domain-specific language.

# Table of Contents
1. [Record broadcasting](#record-broadcasting)
2. [Tiers](#tiers)
3. [Deleting container contents](#deleting-container-contents)
4. [Blocks](#blocks)
1. [Block expressions](#block-expressions)
1. [Block expression return value](#block-expression-return-value)
2. [Parent scale](#parent-scale)
3. [Popped parent scale](#popped-parent-scale)
5. [Defer](#defer)
6. [While](#while)
7. [For...of](#forof)
8. [For...in](#forin)
9. [Break](#break)
10. [Continue](#continue)
11. [While..else and for..else](#whileelse-and-forofelse)
1. [Array comprehensions](#array-comprehensions)
2. [If clause](#if-clause)
12. [If...else](#ifelse)
13. [Ternary expressions](#ternary-expressions)
1. [Vectorizing where...else](#vectorizing-whereelse)
14. [Function declaration](#function-declaration)
1. [Calling functions](#calling-functions)
2. [Stdlib conventions](#stdlib-conventions)
3. [Lambda expressions](#lambda-expressions)
15. [Throwing](#throwing)
16. [Exception handling](#exception-handling)
17. [Implicit mapping](#implicit-mapping)
18. [Stdlib](#stdlib)
1. [Constants](#constants)
2. [Built-in functions](#built-in-functions)
3. [Prelude functions](#prelude-functions)
4. [Highlights](#highlights)
19. [Issues with the decimal separator](#issues-with-the-decimal-separator)
1. [Dot cents](#dot-cents)
2. [Comma decimals](#comma-decimals)
3. [Recommendations](#recommendations)
20. [Fractional just intonation subgroups](#fractional-just-intonation-subgroups)
21. [Universal monzos](#universal-monzos)
22. [The interordinal semioctave](#the-interordinal-semioctave)
1. [Interordinal intervals](#interordinal-intervals)
2. [Absolute semioctave notation](#absolute-semioctave-notation)
1. [Alternative semioctave notation](#alternative-semioctave-notation)
3. [Splitting the fourth](#splitting-the-fourth)
1. [Nicknames](#nicknames)
23. [Quarter-augmented Pythagorean notation](#quarter-augmented-pythagorean-notation)
1. [Further splits](#further-splits)
2. [Extra comma flavors](#extra-comma-flavors)
3. [Non-standard pitch declaration](#non-standard-pitch-declaration)
24. [Implicit intrinsic calls](#implicit-intrinsic-calls)
25. [Obscure types](#obscure-types)
26. [Obscure operations](#obscure-operations)
27. [Future work](#future-work)
28. [Next steps](#next-steps)
1. [Examples](https://github.com/xenharmonic-devs/sonic-weave/tree/main/examples)
2. [Technical documentation](https://github.com/xenharmonic-devs/sonic-weave/blob/main/documentation/technical.md)
3. [Tempering](https://github.com/xenharmonic-devs/sonic-weave/blob/main/documentation/tempering.md)

## Record broadcasting
Records behave like arrays in that operations are broadcast over their values e.g. `#{a: 1, b: 2, c:3} * 5` evaluates to
```ocaml
Expand Down Expand Up @@ -211,7 +269,7 @@ Once declared, functions can be called: `subharmonics(4, 8)` evaluates to `[8/7,

while `pythagoras(4)` evaluates to `[9/8, 81/64, 3/2, 27/16, 2]`. The missing `down` argument defaulted to `0`.

#### Stblib conventions
### Stdlib conventions
You may have noticed that we passed an argument to `sort` in the body of `fn pythagoras`. We could've achieved the same with.
```ocaml
fn pythagoras(up, down = 0) {
Expand Down Expand Up @@ -306,7 +364,7 @@ The expression `1,2` for `6/5` is problematic when you consider the rest of the
### Recommendations
To avoid ambiguity use explicit cents i.e. `100.0c` or explicit scientific notation i.e. `1.2e0` or just `1.2e`.

## Fractional Just Intonation Subgroups
## Fractional just intonation subgroups
By default monzos are vectors of prime exponents and vals are maps of primes, but sometimes you may wish to use other rational numbers as the basis.

Let's take a look at [Barbados temperament](https://en.xen.wiki/w/The_Archipelago#Barbados). We can treat `13/5` like a prime alongside `2` and `3` and map it to `7\5`. The syntax is `[email protected]/5` or `<5 8 7]@2.3.13/5`. Now `<5 8 7]@2.3.13/5 dot 15/13` evaluates to 1 step, exactly half of the 2 steps that an approximate `4/3` spans, as desired.
Expand Down Expand Up @@ -513,117 +571,7 @@ Intrinsic behavior may be evoked explicitly by simply calling a value e.g. `3/2(
Some expressions like `440Hz` or `440 Hz` appear similar to intrinsic calls and would correspond to `440 × (1 Hz)` but `600.0 Hz` is actually `600.0e × (1 Hz)`.
It's legal to declare `let Hz = 'whatever'`, but the grammar prevents the `Hz` variable from invoking intrinsic behavior of integer literals from the right.

## Advanced tempering
While vals are technically powerful enough to describe any pure-octaves tuning to sufficient precision, it can be challenging to discover them from first principles.

### Tempering out a comma
[Tenney-Euclidean tuning](https://en.xen.wiki/w/Tenney-Euclidean_tuning) is a commonly used scheme for adjusting intervals in such a way that some of them coincide. This can help tame the complexity of pure just intonation. It is desirable to make these tiny adjustments with minimal damage.

To make two intervals such as `9/8` and `10/9` coincide we *temper out* their geometric difference `81/80` using the `TE` helper.
```ocaml
(* Generate Pythagorean major scale *)
rank2(3/2, 5, 1)
(* Temper out the syntonic comma 81/80 *)
TE(9/8 ÷ 10/9)
```

Now the `81/64` major thirds sounds more like `5/4` and the major chord resembles `4:5:6`. Compared to just intonation the scale maintains the nice property that there are only two step sizes.

The downside is that the scale is now expressed in terms of real cents and all structural information such as the stack of pure fifths has been lost.

#### Maintaining pure octaves
TE optimal tunings damage all primes including the octave which is often undesirable.

To destretch the octave after the fact use the stretching operator `~^` alongside the size-comparison operator `~/_`. The expression `2 ~/_ $[-1]` tells you how much wider the octave is compared to the last interval in the scale (the current equave).

```ocaml
"POTE meantone[7]"
rank2(3/2, 5, 1)
TE(81/80)
(* Destretch octaves *)
£ ~^ (2 ~/_ £[-1])
```

##### CTE
[Constrained tunings](https://en.xen.wiki/w/Constrained_tuning) have more finesse when it comes to maintaining the size of important intervals like the octave. While SonicWeave doesn't support CTE exactly, you can get close enough by assigning a large weight to the octave.

```ocaml
"Near-CTE meantone[7]"
rank2(3/2, 5, 1)
(* Temper out the syntonic comma while making octaves 1000 times more important than anything else. *)
TE(81/80, 1000)
```

#### Tempering out multiple commas
Multiple commas can be tempered out by passing in an array to `TE`. Multiple primes can be weighted by passing in an array as the second argument.

```ocaml
"Unimarv[19] with a focus on near-pure octaves and undecimal harmony"
(* Unimarv[19] 5-limit transversal *)
25/24
16/15
9/8
75/64
6/5
5/4
32/25
4/3
45/32
64/45
3/2
25/16
8/5
5/3
128/75
16/9
15/8
48/25
2/1
(* Temper out the marvel comma and the keenanisma *)
TE(
[225/224, 385/384],
(* Give 1000 times more weight to octaves and 10 times more weight to prime 11. *)
[1000, 1, 1, 1, 10],
)
```

### Combining multiple vals
Linear combinations of vals share the same temperament. In the 11-limit unimarv can also be expressed as the 19 & 22 temperament. In SonicWeave we must be explicit about the subgroup `@2.3.5.7.11` or `@.11` for short and pass the vals as arguments to `TE`.

```ocaml
"Marveldene but using unimarv for no reason"
(* Generate duodene *)
eulerGenus(675)
(* TE unimarv 19 & 22 *)
TE([[email protected], [email protected]])
```

It is strongly advised to use an explicit subgroup when combining vals in `TE`. Depending on the runtime the ambient subgroup might contain tens of primes, most of little interest, only wasting compute and hurting the low prime accuracy of the tuning.

#### Subgroup weights
Because vals always come with a subgroup basis the weights are associated with it instead of the actual primes when combining vals.
```ocaml
"Barbados[5]"
15/13
4/3
3/2
26/15
2/1
(** Importance weights:
* 2/1: 200%
* 3/1: 100%
* 13/5: 300%
*)
TE([[email protected]/5, [email protected]/5], [2, 1, 3])
```

### Obscure types
## Obscure types
| Type | Literal | Meaning |
| ----------------- | ---------- | ---------------------------------------------------------- |
| Infinity | `inf` | Linear relative infinity |
Expand All @@ -634,7 +582,7 @@ TE([[email protected]/5, [email protected]/5], [2, 1, 3])
| Basis | `@√2.√3` | Basis of a fractional just intonation subgroup |
| Template argument | `¥0`, `¥1` | Arguments passed to the `sw\`${arg0} ${arg1}\`` tag in JS |

### Obscure operations
## Obscure operations
| Name | Linear | Result | Logarithmic | Result |
| ------------------------- | ------------ | -------- | ---------------- | ---------- |
| Harmonic/lens addition | `3 /+ 5` | `15/8` | _N/A_ | |
Expand Down Expand Up @@ -663,4 +611,4 @@ Although the real *raison d'être* is to complete the [Triangle of Power](https:
The syntax could be extended to cover movement in time i.e. to become a full textual music notation vis-à-vis Xenpaper.

## Next steps
Check out the [examples](https://github.com/xenharmonic-devs/sonic-weave/tree/main/examples) and [technical documentation](https://github.com/xenharmonic-devs/sonic-weave/blob/main/documentation/technical.md).
Check out the [examples](https://github.com/xenharmonic-devs/sonic-weave/tree/main/examples) and [technical documentation](https://github.com/xenharmonic-devs/sonic-weave/blob/main/documentation/technical.md). Also make sure you've read up on [tempering](https://github.com/xenharmonic-devs/sonic-weave/blob/main/documentation/tempering.md) to make TE and CTE optimized tunings.
7 changes: 7 additions & 0 deletions documentation/cli.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
# SonicWeave CLI
This document describes the command-line interface of the sonic-weave package.

# Table of Contents
1. [REPL](#repl)
2. [Input](#input)
3. [Interval calculator](#interval-calculator)
2. [Conversion to other formats](#conversion-to-other-formats): Scala
1. [SonicWeave Interchange format](#sonicweave-interchange-format)

## REPL
The read-eval-print-loop is engaged by running `npx sonic-weave` if you have the package installed as a dependency or simply `sonic-weave` if installed globally.

Expand Down
8 changes: 8 additions & 0 deletions documentation/commas.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

These inflections always go in the direction of the arrow so `6/5` ~ `m3^5h` instead of `m3_5` as in plain FJS.

# Table of Contents
1. [Helmholtz-Ellis 2020 + Richie's extension](#helmholtz-ellis-2020--richies-extension)
2. [Syntonic rastmic subchroma notation](#syntonic-rastmic-subchroma-notation)
3. [HEWM-53](#hewm-53)
4. [Semifourth bridges](#semifourth-bridges)
5. [Tone-splitter bridges](#tone-splitter-bridges)
6. [Lumi's irrational bridges](#lumis-irrational-bridges)

## Helmholtz-Ellis 2020 + Richie's extension

Updated 2020 version by Marc Sabat and Thomas Nicholson as defined on [XenWiki](https://en.xen.wiki/w/Helmholtz-Ellis_notation) including [Richie's extension](https://en.xen.wiki/w/Richie%27s_HEJI_extensions).
Expand Down
25 changes: 25 additions & 0 deletions documentation/dsl.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,31 @@
# SonicWeave DSL
This document describes the SonicWeave domain-specific language for manipulating musical frequencies, ratios and equal temperaments.

# Table of Contents
1. [Basic example](#basic-example): Ratios
1. [Absolute pitch notation](#absolute-pitch-notation)
2. [Cents](#cents)
3. [Equal temperaments](#equal-temperaments)
4. [Relative pitch notation](#relative-pitch-notation)
2. [Domains](#domains): Linear vs. logarithmic
1. [Breaking changes](#breaking-change-compared-to-scale-workshop-2)
3. [Adding colors to notes](#adding-colors-to-notes)
4. [Code comments](#code-comments)
5. [Accidentals](#accidentals)
1. [Double accidentals](#double-accidentals)
6. [Relative Pythagorean notation](#relative-pythagorean-notation)
1. [Pythagorean absolute notation](#pythagorean-absolute-notation)
7. [FJS inflections](#fjs-inflections)
8. [Enumerated chord](#enumerated-chords)
1. [Harmonic segments](#harmonic-segments)
2. [Reflected enumerations](#reflected-enumerations)
9. [Scale title](#scale-title)
10. [Ups and downs notation](#ups-and-downs-notation)
1. [Lifts and drops](#lifts-and-drops)
11. [Helper functions](#helper-functions)
12. [Next steps](#next-steps)
1. [Intermediate DSL](https://github.com/xenharmonic-devs/sonic-weave/blob/main/documentation/intermediate-dsl.md)

## Basic example

SonicWeave is related to [Scala .scl](https://www.huygens-fokker.org/scala/scl_format.html) and a successor of Scale Workshop 2. It is intended for constructing microtonal scales that repeat at the octave (or some other period).
Expand Down
21 changes: 20 additions & 1 deletion documentation/interchange.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
# SonicWeave - Technical overview
# SonicWeave Interchange
This documentation describes the .swi interchange format for transferring microtonal scales between programs

# Table of Contents
1. [Comments](#comments)
2. [Empty lines](#empty-lines)
3. [Strings](#strings)
4. [CSS colors](#css-colors)
5. [Scale title](#scale-title)
6. [Unison frequency](#unison-frequency)
7. [Intervals](#intervals)
1. [Relative intervals](#relative-intervals)
1. [23-limit monzos](#23-limit-monzos)
2. [Higher primes](#higher-primes)
3. [Non-primes](#non-primes)
4. [Real values](#real-values)
2. [Absolute pitches](#absolute-pitches)
1. [Real absolute pitches](#real-absolute-pitches)
3. [Edosteps](#edosteps)
4. [Not-a-number](#not-a-number)
8. [Example](#example)

## Comments
Comments work as in OCaml. Everything between a pair of `(*` and `*)` is ignored. Comments can be nested
```ocaml
Expand Down
Loading

0 comments on commit 6e2537f

Please sign in to comment.