tuning

Constant summary
+edo-prime-octave-offsets+ (loop for prime in +primes+ collect (round (log (/ prime (ji-pc-ratio prime)) 2)))
+nominal->ratio-table+ (alexandria.0.dev:alist-hash-table (loop for nom in +nominals+ for no-of-fifths from -1 collect (cons nom (ji-pc-ratio (monzo-to-ratio (list 0 no-of-fifths))))))
+nominals+ '(f c g d a e b)
+prime->comma-ratio-table+ (alexandria.0.dev:alist-hash-table (list* (list* 3 (expt 2187/2048 -1)) (list* (list* 5 (expt 81/80 -1)) (list* (list* 7 (expt 64/63 -1)) (list* '(11 . 33/32) (list* (list* 13 (expt 27/26 -1)) (list* (list* 17 (expt 256/255 -1)) (list* '(19 . 513/512) (list* '(23 . 736/729) (list* '(29 . 145/144) (list (list* 31 (expt 1024/1023 -1)))))))))))))
+primes+ '(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61)
+ratio->nominal-table+ (flip-hash-table +nominal->ratio-table+)
Function summary
add-accidentals-as-text-attributes
add-all-accidental-powers-and-accidental-combinations specs
add-power-accidentals accidental n
aux-add-accidental-combinations
aux-add-all-accidental-powers specs
aux-add-power-accidentals accidental-string orig-ratio i
aux-pythagorean-ratio-to-pc-symbols limit-3-expt
cent-to-ratio cent
edo-val edo mappings
equal-prime-limit? ratio1 ratio2
flip-hash-table table
get-all-temperament-names
get-ji-accidentals event
get-ratio-octave ratio
get-temperament-generators name
get-temperament-vals name
has-fewer-accidentals? ratio1 ratio2
has-lower-prime-limit? ratio1 ratio2
identity-matrix n
is-ji-accidental x
ji-pc-symbols-to-ratio nominal &rest accidentals
monzo-limit monzo
monzo-to-ratio monzo
omn-event-to-ji-pc-ratio event &key (use-ji-accidentals? t)
omn-event-to-pc-cents temperament event &key (use-ji-accidentals? t)
omn-to-tunings temperament sequence
parse-omn-pitch pitch
prettify-exported-accidental accidental-string
prime-factors n
primes-in-limit limit
pythagorean-ratio-to-pc-symbols ratio
ratio-to-1d-temperament-cents frac val step-generator
ratio-to-1d-temperament-degree frac val
ratio-to-cent frac &key (round? nil)
ratio-to-higher-limit-ji-accidental-symbols ratio
ratio-to-ji-pc-symbols ratio
ratio-to-monzo frac
ratio-to-omn ratio
ratio-to-regular-temperament-cents frac vals generators
ratio-to-regular-temperament-degrees frac vals
regular-temperament-degrees-to-ratio degrees &optional (generator-ratios +primes+)
replace-all string part replacement &key (test #'char=)
set-ji-accidental name ratio
store-temperament name vals generators
temperament-degrees generators ns &key (mode :up-and-down)
temperament-pcs-infos temperament generator-ns limit-ratios ratio-ns fn &key (ratios-comparison #'has-fewer-accidentals?)
+primes+   '(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61)  [Constant]

List of prime numbers from 2 to 61.

+edo-prime-octave-offsets+   (loop for prime in +primes+ collect (round (log (/ prime (ji-pc-ratio prime)) 2)))  [Constant]

List of octave offsets of prime frequency ratios, i.e., in which octave lies a prime frequency ratio compared to 1/1. For example, the first prime (2) is one octave and the third prime (5) is two octaves above 1.

+nominals+   '(f c g d a e b)  [Constant]

Standard pitch nominals in order of fifth chain. These will be tuned Pythagorean in JI.

+nominal->ratio-table+   (alexandria.0.dev:alist-hash-table (loop for nom in +nominals+ for no-of-fifths from -1 collect (cons nom (ji-pc-ratio (monzo-to-ratio (list 0 no-of-fifths))))))  [Constant]

Hashtable mapping pitch nominals (symbols like A, B, C...) to their corresponding Pythagorean frequency ratios.

+ratio->nominal-table+   (flip-hash-table +nominal->ratio-table+)  [Constant]

Hashtable mapping Pythagorean frequency ratios for pitch nominals to their corresponding symbols (A, B, C...).

+prime->comma-ratio-table+   (alexandria.0.dev:alist-hash-table (list* (list* 3 (expt 2187/2048 -1)) (list* (list* 5 (expt 81/80 -1)) (list* (list* 7 (expt 64/63 -1)) (list* '(11 . 33/32) (list* (list* 13 (expt 27/26 -1)) (list* (list* 17 (expt 256/255 -1)) (list* '(19 . 513/512) (list* '(23 . 736/729) (list* '(29 . 145/144) (list (list* 31 (expt 1024/1023 -1)))))))))))))  [Constant]
+limit-31-primes+    [Variable]

List of prime numbers from 2 to 31.

*temperaments*    [Variable]

A hashtable filled with function store-temperament and accessed by get-temperament-vals and get-temperament-generators.

*current-temperament*    [Variable]

Currently set global temperament (e.g., used by my snippet audition from within Emacs).

*accidental->ratio-table*    [Variable]

Hashtable mapping symbols representing accidentals to corresponding prime limit ratios and their combinations. Combinations are representing by their own symbol, so that for notating chords we only need a single accidental symbol per tone.

Notation: s and b are the Pythagorean sharp and flat accidentals K stands for prime limit 'c'omma (K as in the original Greek κόμμα, 'c' is already used for OMN attributes denoting cents) 5K means prime limit 5 comma up -5K means prime limit 5 comma down 1K is the natural accidental xx is used for combinations of the same symbol (two quasi multiplication signs read as power of frequency ratios) 5Kxx3 means triple prime limit 5 comma up x combines accidentals (quasi multiplication sign read as factor of frequency ratios) -5Kx-7K means a limit 5 and additionally a limit 7 comma down 5Kxx2x7K means two limit 5 commas and additionally a limit 7 comma up

Remember that these symbols do not distinguish between upper and lower case, case is just used for a (very little) bit of readability.

NOTE: Currently always only at most 2 prime limits are combined in a single accidental.

Source for the initial prime limit ratios: Nicholson, T. & Sabat, M. (2018) Fundamental Principles of Just Intonation and Microtonal Composition. p. 18

*ratio->accidental-table*    [Variable]

Map prime limit ratios to corresponding symbols representing accidentals. The inverse map of *accidental->ratio-table*

*ji-accidentals*    [Variable]
*1/1-octave*    [Variable]

Octave in which the frequency ratio 1/1 sounds.

flip-hash-table   table  [Function]

Turns the keys of the given hash `table' into values and vice versa

primes-in-limit   limit  [Function]

Return list of primes up to the given prime limit.

prime-factors   n  [Function]

Return list of prime factors of given integer.

monzo-to-ratio   monzo  [Function]

Return a ratio that corresponds to a monzo represented by a list of integers.

See also https://en.xen.wiki/w/Monzo

ratio-to-monzo   frac  [Function]

Return a monzo represented by a list of integers that corresponds to the fraction `frac'.

See also https://en.xen.wiki/w/Monzo

monzo-limit   monzo  [Function]

Return the prime limit of the given `monzo'.

ratio-to-cent   frac &key (round? nil)  [Function]

Transform the frequency ratio `frac' into the corresponding cent value.

cent-to-ratio   cent  [Function]
edo-val   edo mappings  [Function]

Return a val (list of ints) given a subdivision of the octave (an int) and mappings for all prime limits as a list of temperament degrees *within an octave* (list of ints). The first mapping should be 0 (and not `edo').

ratio-to-1d-temperament-degree   frac val  [Function]

Return an interval in a 1D temperament specified by its `val' that corresponds to the JI interval ratio `frac'. The resulting interval is specified as a factor (or exponent) for the single generator of the temperament. For example, if the generator is the smallest interval of an equal temperament, the returned degree specifies how many such intervals are needed to reach a pitch that corresponds to the given fraction. (If the generator is measured in cents, the returned degree is to be used as a factor for the measured, but if the generator is a frequency ratio, then the returned degree is to be used as an exponent.)

Arguments:

  • frac (rational): a JI interval for which we want to get a tempered interval

  • val (list of ints): the val that specifies how JI pitches of prime limits are mapped to the temperament. See also https://en.xen.wiki/w/Keenan%27s_explanation_of_vals and https://en.xen.wiki/w/Val

Examples:

We can specify arbitrary equal temperaments (not just EDOs) by using their smallest step as a generator. The val then contains the ordered number of theses steps to the temperament intervals that should serve as the prime frequency ratios 2, 3, 5... up to the desired prime limit. For 12-EDO, the smallest step is 100 cent. 12 such steps correspond to the frequency ratio 2 (the octave), 19 such steps to the frequency ratios 3 (the octave plus a fifth), 28 such steps correspond to the frequency ratio 5 and so on.

    (setf 12-EDO-val '(12 19 28)) 

With this 5-limit val, we can now obtain the 12-EDO intervals for arbitrary 5-limit JI intervals specified by ratios, for example the minor third (6/5) in 12-EDO is 3 steps.

    (ratio-to-1D-temperament-degree 6/5 12-EDO-val) 

=> 3

Remember that 12-EDO is a meantone temperament (https://en.wikipedia.org/wiki/Meantone_temperament), so the syntonic comma (81/80) is tempered out: the size of that interval is 0.

    (ratio-to-1D-temperament-degree 81/80 12-EDO-val) 

=> 0

As a consequence, intervals that differ only by this comma have the same size in this temperament. For example, the Pythagorean minor third (32/27) has also the size of 3 in 12-EDO.

    (ratio-to-1D-temperament-degree (* 6/5 80/81) 12-EDO-val) 

=> 3

The 7-limit val for the temperament 22-EDO (https://en.xen.wiki/w/22edo) is as follows. You can collect the data for writing such vals yourself simply by collecting the temperament interval sizes for prime frequency ratios up to the relevant limit (2, 3, 5, and 7 in this case), e.g., from a table for that temperament listing all its intervals the the approximated JI ratios (e.g., see https://en.xen.wiki/w/22edo#Superpyth.2FPorcupine_Notation). For 22-EDO, the ratio 2 corresponds to 22 steps, the ratio 3 to 13 (fifth) plus 22 (1 octave) steps and so forth.

    (setf 22-EDO-val (list 22 (+ 13 22) (+ 7 (* 2 22)) (+ 18 (* 2 22)))) 

With this 7-limit val for 22-EDO, we can now get the 22-EDO intervals for arbitrary 7-limit JI ratios. Here is the subminor third (7/6). You can confirm the resulting value with the above-mentioned table for this temperament.

    (ratio-to-1D-temperament-degree 7/6 22-EDO-val) 

=> 5

ratio-to-1d-temperament-cents   frac val step-generator  [Function]

Return the pitch of an interval (measured in cents) that corresponds to the JI interval ratio `frac' in an equal temperament (not just EDOs) defined by the given `val' and the generator for a step in that equal temperament (also measured in cents).

ratio-to-regular-temperament-degrees   frac vals  [Function]

Return an interval in an arbitrary regular temperament specified by a list of its `vals' that corresponds to the JI interval ratio `frac'. The resulting interval is specified as a list of factors for the generators of the temperament measured in cent (or as exponents for generators that are frequency ratios).

Arguments:

  • frac (rational): a JI interval for which we want to get a tempered interval

  • vals (list of list of ints): the list of vals that specify how the temperament how JI pitches are mapped to the temperament. See also https://en.xen.wiki/w/Keenan%27s_explanation_of_vals and https://en.xen.wiki/w/Val

Examples:

We can specify arbitrary regular temperaments by their generators. The vals then specify how JI pitches are mapped into this temperament. This is done by stating how often each generator must be repeated to reach a tempered tone that should serve as the prime frequency ratios 2, 3, 5... up to the desired prime limit.

Meantone temperament is specified by two generators, one specifying the size of the octave and one that of the fifth (the second generator can also be an octave plus a fifth, but then the vals are slightly different). As meantone has two generators, we must specify two vals, one for each of them. The first value in each val states how often its generator must be repeated to reach the frequency ratio 2, i.e., the octave. For reaching the octave we need 1 octave (generator 1) and 0 fifths (generator 2), so the first value in the first val is 1 and the first in the second val is 0. The second value in each val states how often its generator must be repeated to reach the frequency ratio 3, i.e., the octave plus a fifth. Obviously, we need one octave (second value of val 1) and one fifth (second value of val 2). The third (and for 5-limit meantone the last) val values state how to reach the prime frequency ratio 5 (two octaves and a major third). We can reach this interval by stacking 5 fifths and no additional octave is needed. So, the third value for the val 1 is 0 and for val 2 is 4. So, the vals for meantone are as follows.

    (setf 5-limit-meantone-vals '((1 1 0) (0 1 4))) 

With this 5-limit val, we can now obtain the meantone intervals measured in repetitions of generators for arbitrary 5-limit JI intervals specified by ratios. For example, to reach a fourth (ratio 4/3), we need to go one octave up and one fifth down. So, the first generator is repeated once upwards, and the second once downwards (specified by a negative count).

(ratio-to-regular-temperament-degrees 4/3 5-limit-meantone-vals) => (1 -1)

A minor third (6/5) is reached by 2 octaves up and 3 fifths down.

    (ratio-to-regular-temperament-degrees 6/5 5-limit-meantone-vals) 

=> (2 -3)

regular-temperament-degrees-to-ratio   degrees &optional (generator-ratios +primes+)  [Function]

Translate given temperament `degrees' into a corresponding JI ratio. `generator-ratios' is the list of primes that correspond to the generators for which the given degrees would be fitting. Does not temper out any commas and gives preference to ratios with a lower limit (e.g., Pythagorean third instead of just third).

ratio-to-regular-temperament-cents   frac vals generators  [Function]

[main function in background] Translate a JI interval (ratio) into the corresponding interval measured in cents of a regular temperament. The temperament is specified by its `vals' and `generators'.

Arguments:

  • frac (rational): a JI interval for which we want to get a tempered interval

  • vals (list of list of ints): the list of vals that specify how the temperament how JI pitches are mapped to the temperament. See also https://en.xen.wiki/w/Keenan%27s_explanation_of_vals and https://en.xen.wiki/w/Val

  • generators (list of numbers): the list of generators that specify the temperament.

The order of vals and generators must match (i.e. the val of a certain generator must be at the same position).

See the documentation of `deftemperament' and also `ratio-to-regular-temperament-degrees' for more information.

store-temperament   name vals generators  [Function]

Store a temperament with the given `vals' and `generators' under the key the `name' in `*temperaments*'.

get-all-temperament-names    [Function]

Return list of names (symbols) of all temperaments so far defined with `deftemperament'.

You can jump to the definition of a temperament, by jumping to the definition of a function/method with the name of a temperament.

get-temperament-vals   name  [Function]

Return vals of a temperament with `name' defined with `deftemperament'.

get-temperament-generators   name  [Function]

Return generators of a temperament with `name' defined with `deftemperament'.

identity-matrix   n  [Function]
temperament-degrees   generators ns &key (mode :up-and-down)  [Function]

Return list of degrees of the temperament specified by `generators'.

Arguments:

  • generators (list of rationals or list of floats): List of temperament generators. If rationals, generators are assumed to be frequency ratios, otherwise they are assumed to be measured in cent.

  • ns (list of its): Specifies how often the generators should be repeated. Each n specifies the number the corresponding generator (at the same position) is repeated.

  • mode (either :up-and-down or :up): Whether generators are repeated upwards and downwards or only upwards.

* Examples

Using just the octave (2) as a generator, repeating that generator up and down until in total 7 frequency ratios are generated.

    (temperament-degrees '(2) '(7)) 

=> (1/8 1/4 1/2 1 2 4 8)

Generating a single octave of 12-EDO by repeating its generator (100.0 cent) to result in 12 tones.

    (temperament-degrees '(100.0) '(12)) 

=> (-600.0 -500.0 -400.0 -300.0 -200.0 -100.0 0.0 100.0 200.0 300.0 400.0 500.0)

Collect the ratios of a 5-limit JI lattice without the octave, so that there is a sequence of 12 tones in the dimension of fifths and 3 tones in the dimension of thirds.

    (temperament-degrees '(3/2 5/4) '(12 3)) 

Repeating generators only upwards.

    (temperament-degrees '(100.0) '(12) :mode :up) 

=> (0.0 100.0 200.0 300.0 400.0 500.0 600.0 700.0 800.0 900.0 1000.0 1100.0)

has-lower-prime-limit?   ratio1 ratio2  [Function]

[For temperament-pcs-infos arg sort-ratios] Given two ratios, return T if the first ratio has a lower prime limit.

has-fewer-accidentals?   ratio1 ratio2  [Function]

[For temperament-pcs-infos arg sort-ratios] Given two ratios, return T if the first ratio needs fewer accidentals for notating it.

temperament-pcs-infos   temperament generator-ns limit-ratios ratio-ns fn &key (ratios-comparison #'has-fewer-accidentals?)  [Function]

Return nested list where each sublist starts with a temperament degree measured in cents (as returned by `temperament-degrees') and the remaining values of each sublist are results of the function `fn' given rationals that are tempered to this degree in the given temperament.

Arguments:

  • temperament (symbol): A temperament defined by `deftemperament'.

  • generator-ns (list of ints): Specifies how often each generator (implicitly specified by the temperament symbol) should be repeated. Each n specifies the number the corresponding generator (at the same position) is repeated.

  • limit-ratios (list of rationals): Specifies generators for creating a JI tuning that is then matched to the temperament.

  • ratio-ns (list of ints): Specifies how often the corresponding generator (at the same position) is repeated.

  • fn (binary function): Function for generating further information on temperament tones. The function expects a JI rational and the corresponding temperament degree in cents. ;; - sorted-degrees? (Boolean): if T, the result is sorted in increasing order of degrees.

  • ratios-comparison (binary function): Function comparing two ratios that is used for sorting ratios per degree. * Examples

TODO:

Collect list of (relatively simple) note names for temperament degrees

Compute tuning errors as difference between degrees and ratios turned into cents.

aux-add-power-accidentals   accidental-string orig-ratio i  [Function]
add-power-accidentals   accidental n  [Function]

For the given `accidental' symbol, add `n' accidentals that are powers of the corresponding frequency ratios. If `n' is two, accidental doubles are added, if it is tree, triple are added etc. These accidentals are notated with a double star for expressing the power relation. E.g., sxx3 is a triple sharp.

equal-prime-limit?   ratio1 ratio2  [Function]

Return T if ratio1 or ratio2 share the same prime limit (of if either is 1).

replace-all   string part replacement &key (test #'char=)  [Function]

Returns a new string in which all the occurrences of the part is replaced with replacement.

prettify-exported-accidental   accidental-string  [Function]
add-accidentals-as-text-attributes    [Function]

Automatically define for all accidentals (keys of `*accidental->ratio-table*') corresponding OMN text attributes.

aux-add-accidental-combinations    [Function]

Pairwise combine all accidentals into product accidentals (resulting in a huge accidental number overall).

aux-add-all-accidental-powers   specs  [Function]

Each spec is a pair (accidentals . n), where accidentals is a list of accidental symbols, and n is the number of power accidentals to add to them.

add-all-accidental-powers-and-accidental-combinations   specs  [Function]

Each spec is a pair (accidentals . n), where accidentals is a list of accidental symbols, and n is the number of power accidentals to add to them.

set-ji-accidental   name ratio  [Function]

Can be used, e.g., for adding some custom interpretation of the OMN builtin accidentals like + and - or (for adding higher prime limits?).

is-ji-accidental   x  [Function]
ji-pc-symbols-to-ratio   nominal &rest accidentals  [Function]
aux-pythagorean-ratio-to-pc-symbols   limit-3-expt  [Function]
pythagorean-ratio-to-pc-symbols   ratio  [Function]
ratio-to-higher-limit-ji-accidental-symbols   ratio  [Function]

[Aux for ratio-to-ji-pc-symbols etc] Return list of accidental symbols list beyond limit 5 that corresponds to ratio.

ratio-to-ji-pc-symbols   ratio  [Function]

Return PC symbol list that corresponds to ratio (i.e. octaves are ignored).

get-ratio-octave   ratio  [Function]
ratio-to-omn   ratio  [Function]

Return OMN pitch plus accidental attribute that corresponds to ratio (i.e. octaves are ignored).

parse-omn-pitch   pitch  [Function]

Return a plist that contains the components of `pitch' (an OMN pitch symbol), each component as a string.

    (parse-OMN-pitch 'c4) 

=> (:NOMINAL C :STANDARD-ACCIDENTAL NIL :OCTAVE 4 :MICROTONE-ACCIDENTAL ||)

    (parse-OMN-pitch 'cs4+) 

=> (:NOMINAL C :STANDARD-ACCIDENTAL S :OCTAVE 4 :MICROTONE-ACCIDENTAL +)

get-ji-accidentals   event  [Function]
omn-event-to-ji-pc-ratio   event &key (use-ji-accidentals? t)  [Function]
omn-event-to-pc-cents   temperament event &key (use-ji-accidentals? t)  [Function]
omn-to-tunings   temperament sequence  [Function]

Return a flat list of tuning values for the given `sequence'. The tuning values are floats (1.0 is 100 cents).

Arguments:

  • sequence (list, possibly nested): OMN sequence with custom JI accidentals (as defined in *accidental->ratio-table*) as OMN attributes.