Odd Harmonics Sounds Great

I've never found good principles for making tuned chords that use high-prime-limit frequency ratios, but I recently heard of a cool trick that seems to work.

A tuned chord can be written "otonally" as a sequence of integers, like [4, 5, 6]. Divide all the list elements through by the first list entry to get the frequency ratios, e.g. [4, 5, 6] -> (1/1, 5/4, 3/2). That's a major chord and it sounds great.

You can generate random sequences of integers all day to make chords, and some will be okay, some will be bad, some will be good. But it's not easy to listen to 500 random chords, pick your favorites, try to remember how they sounds based on a name that is a list of integers, and then try to use them to compose. It would be nicer if we had some principles for finding tuned chords that sounded good almost surely.

I heard about such a method from Kite Giedraitis; you just use sequences of odd integers. I find that things sound better if you also keep all your integers within an octave, i.e. the largest integer in your list is smaller than twice the first integer in your list.

These chords almost all sound good to my ear. Or maybe I was just in a very-open-to-weirdness headspace when I played with them last night. But I think it's the former. And that's very exciting, because you can get very high prime limit chords.

Here's a list of frequency ratios between 1/1 and 2/2 that show up in such chords, with numerators up to 31: [1/1, 5/3, 7/5, 9/5, 9/7, 11/7, 11/9, 13/7, 13/9, 13/11, 15/11, 15/13, 17/9, 17/11, 17/13, 17/15, 19/11, 19/13, 19/15, 19/17, 21/11, 21/13, 21/17, 21/19, 23/13, 23/15, 23/17, 23/19, 23/21, 25/13, 25/17, 25/19, 25/21, 25/23, 27/17, 27/19, 27/23, 27/25, 29/15, 29/17, 29/19, 29/21, 29/23, 29/25, 29/27, 31/17, 31/19, 31/21, 31/23, 31/25, 31/27, 31/29].

Here they are sorted by increasing size: [1/1, 31/29, 29/27, 27/25, 25/23, 23/21, 21/19, 19/17, 17/15, 31/27, 15/13, 29/25, 27/23, 13/11, 25/21, 23/19, 11/9, 21/17, 31/25, 29/23, 19/15, 9/7, 9/7, 17/13, 25/19, 31/23, 23/17, 15/11, 29/21, 7/5, 27/19, 13/9, 19/13, 25/17, 31/21, 29/19, 23/15, 17/11, 11/7, 27/17, 21/13, 31/19, 5/3, 5/3, 5/3, 29/17, 19/11, 23/13, 9/5, 9/5, 31/17, 13/7, 17/9, 21/11, 25/13, 29/15].

If you sounds those in order against 1/1, you'll notice some elements are very close to each other. Like right at the start,

(29/27) / (31/29) = 841/837 @ 8 cents

is a fairly small comma, and

(25/23) / (27/25) = 625/621 @ 11 cents

is similarly small.

They're not unnoticeable commas, but if you want very-high-prime-limit temperaments, then I've heard of worse methods to generate very-high-prime-limit tuned commas.

The Bohlen-Pierce scale also doesn't use any even harmonics, but it limits things to 7-limit frequency ratios. I think it's cool that this extends Bohlen-Pierce.

I have no idea why this works. But let's figure it out. 

I've forgotten almost everything I've written about otonality and utonality. I haven't written much. Time to redo it, and better.

Chords made of frequency ratios are called tuned chords. They differ from chords made of intervals. Those are intervallic chords, like [P1, M3, P5]. We'll be looking at tuned chords in this post.

Here are the just frequency ratios for a 5-limit major chord: [1/1, 5/4, 3/2]. We can multiply through by the least common multiple of the denominators to get a sequence of integers: [4, 5, 6]. This is the otonal representation. To get back to the ratios, divide everything through by the first element of the otonal list.

We can find "inversions" of tuned chords, by which I  mean cyclic permutations modulo the octave. Pop the first element off of the list, multiply by 2, and stick it at the end of the list. Divide all the list elements by the new first element. Multiply through by the least common multiple of the denominators if you want that chordal inversion to be represented otonally.

The otonal major chord [4, 5, 6] has cyclic inversions of [5, 6, 8] and [3, 4, 5].

We can also find the elementwise inverse of chords. For each element {e} in a list, take {1/e} for the new element in that position. Sort by size and multiply through by the least common multiple of denominators. We'll call this the utonal inverse of the chord. Optionally you can divide through by the first element if you want frequency ratios. Cyclic inversions versus utonal inverses.

Here are the three inversions of the otonal major chord and the utonal inverse for each after a double colon:

    [4, 5, 6] :: [10, 12, 15]

    [5, 6, 8] :: [15, 20, 24]

    [3, 4, 5] :: [12, 15, 20]

The utonal inverses are also inversions of each other, i.e. the set is closed under cyclic permutation modulo the octave. They happen to also be justly-tuned minor chords. 

What if we space things out more, beyond the octave? If we remove factors of two, i.e. raise and lower things by octaves until the factors of two are gone from the utonal integer list, then the major chord has only one all-odd voicing: [1, 3, 5] and its utonal inverse has only one all-odd voicing, [3, 5, 15].

And.... all-odd voicings usually sound good, at least within an octave, not that these necessarily are within an octave. So can we take a bad sounding chord and make it sound better by spacing it out in an all-odd voicing? Are there chords that sound better when compressed into an octave than when expanded to the all-odd voicing?

I think a normally voiced harmonic seventh chord, [4, 5, 6, 7], sounds way better than its all-odd voicing, [1, 3, 5, 7]. So there's one.

...

Defective Portuguese

In Portuguese, a few verbs are missing some conjugations. They're called "defective verbs". The standard example is "colorir", to color, which has no first person singular forms. You might say, "Obviously the simple present tense form should just be coloro?" and your language teacher will say that word is forbidden.

Wiktionary has a list of which verbs are defective in continental versus Brazilian, and there's... no overlap. So basically all the verbs have obvious forms, but different countries have different taboos?

To be fair, I have heard that "colorir" is defective in both Continental and Brazilian Portuguese, even though it isn't on both lists. But it's still pretty suspicious pair of lists. And it's pretty weird to have defective verbs at all, regardless of whether they're agreed on.

The weird spells to summon leather

I was reading about different tanning methods and I'm fairly confused about what they're achieving.

Like, some cultures would soak hides in poop... for proteolytic enzymes? And others just wouldn't and that seemed to work fine. Or you can use chromium III sulfate to change the spacing between collagen threads, but also you can just cover the thing in astringent bark water (or other sources of tannic acid, but why would you gather small rare parasitic oak galls if you could just use waste tree bark or leaves), and wouldn't it be nice if your nice-smelling leather products that children might want to chew on weren't impregnated with poisonous heavy metals?

Or I saw a buckskin recipe that covered the hide in egg wash, or a mix of grated bar soap and vegetable oil, or you can rub the deer's brain on its skin, and supposedly these methods all soften the leather in equivalent ways, with emulsions of triglycerides in water, but they don't even mention a protein changing step to finish. It's just: 1) take off the fur and fat with alkali and then 2) soften with brain grease or eggs.

And then I see references to "tawing", meaning treating the hide with alum and something else, like eggs or flour, as an alternative to proteolytic enzymes or protein-complexing chromium or protein-binding tannins, so maybe the alum does something like tanning but you need to soften the hide at the same time to prevent the alum from over-drying the hide?

It feels like there are 20 different ways to make leather, so it shouldn't be a finicky process, but all of the processes require some highly specific bullshit like green papaya latex or deer brains or fermented pigeon droppings.

Chitosan Fiber

The Thought Emporium on youtube made a video about weaving fibers made from the chitin, obtained from waste arthropod exoskeletons, e.g. shrimp and crab shells. I shared it with a friend and they didn't like the presenter's style, so here is a text summary. It's also a summary for me, because I don't remember all that many exact process details after watching a 16 minute video.

To make chitosan: reduce crustacean shells to very small pieces, perhaps powder, and cover with 10% solution of HCl. Stir for several hours (with heat?). Filter out solids and rinse. Cover solids in 10% solution of NaOH. Heat at 90 C for 2 hours. Filter out solids and rinse. Cover in 45% NaOH. Boil vigorously for 3 hours, topping off with water to maintain coverage. Strain and rinse. Now you have chitosan.

To make chitosan threads: Dissolve in vinegar. The mixture thickens a lot and will need to be stirred for a day for full incorporation. You'll only get about 3% chitosan by weight into your solvent, but you need more like an 11% solution for making threads. Heat the dilute solution to 65 C with stirring overnight (for 16 hours? until the solution reduces to a 1/4 of its initial volume?) to drive off water. You'll have a thick brown jelly now. Chitosan is soluble in the vinegar (and other acids), but not in bases, so to form fibers, extrude the jelly solution into NaOH and you get coagulation or some similar effect. Pull the coagulated thread from the extrusion syringe, through te NaOH bath, and then through a water bath to rinse, then hang to dry. Thinner extrusions will be less brittle. You might be able to loop the thread around a sequence of rollers with gradually increasing speeds to pull the thread thinner.

The lab hopes to put acetyl groups back on the chitosan threads at some point, turning the chitosan back into chitin, to make the threads more generally insoluble.

Sugar-Free Juice

I want to try extracting some things from juice - like organic acids and pigments and polyphenols - and I think this will be easier if I get rid of the sugar. But how does one get rid of the sugar in juice? Here's my plan.

If you aerate yeast, it's more likely to use aerobic respiration than fermentation. This is called the Pasteur effect. So let's put an aquarium pump and some yeast in bottle of juice and see what it does? I don't think that will quite work; lots of yeasts will still ferment sugars when aerated if there's a lot of sugar around - like in juice. This is called the Crabtree effect.

So we could dilute the juice to reduce its sugar content, but I estimate you have to dilute by something like 1000 times to prevent the Crabtree effect when using saccharomyces cerevisiae on juice. And that's not a home scale experiment. 

Another option is that we could find a food-grade yeast that doesn't have the Crabtree effect. Kluyveromyces species fit this bill. Kluyveromyces species are pretty good at doing just respiration on carbohydrates when aerated, and they're found in live-culture kefir.

I don't know the composition of yeast and bacteria in the kefir itself (the fermented milk) as well as the composition in the kefir grains; the latter is the thing that's analyzed in detail in biology publications. Here are some quotes about the grains:

"Kefir grain is composed of a diverse spectrum of species and genera including lactic acid bacteria (Lactobacillus, Lactococcus, Leuconostoc), yeasts (Kluyveromyces, Candida, Saccharomyces, and Pichia) and sometimes acetic acid bacteria (Acetobacter) in a symbiotic association."

"A complex and highly variable symbiotic community can be found in these grains, which can include acetic acid bacteria (such as Acetobacter aceti and A. rasens), yeasts (such as Candida kefyr and Saccharomyces cerevisiae) and a number of Lactobacillus species, such as L. parakefiri, L. kefiranofaciens (and subsp. kefirgranum), L. kefiri, etc."

"Many different species of Saccharomyces have been isolated from kefir, however, S. cerevisiae and S. unisporus are the most common and present in many varieties (Angulo et al., 1993; Marquina et al., 2002; Latorre-García et al., 2007; Diosma et al., 2014). Kluyveromyces make up the majority or entirety of the lactose utilizing yeast population, with K. marxianus and K. lactis being the two most common species (Simova et al., 2002; Latorre-García et al., 2007; Diosma et al., 2014). The Candida population is made up of a wide range of species with C. holmii and C. kefyr being the most prevalent (Angulo et al., 1993; Marquina et al., 2002). Outside of these three genera, only Pichia has been identified with any regularity and in each case the species was identified as Pichia fermentans."

"As fermentation progresses the proportions of some yeast species change with non-lactose fermenting yeasts, such as Saccharomyces, decreasing, whereas lactose utilizing K. marxianus and K. lactis show a similar distribution between grain and kefir (Simova et al., 2002)."

Based on the last quote, I'm hopeful that I can use a well fermented kefir's liquid as a purer source of Kluyveromyces yeast than the grains would be.

Once source, "Survivability of Kluyveromyces marxianus Isolated From Korean Kefir in a Simulated Gastrointestinal Environment" says that "Kluyveromyces marxianus accounts for > 90% of the yeast population of kefir", so our isolation is already well in progress.

I've seen a procedure for isolating Kluyveromyces that used kefir directly (the fermented milk) rather than kefir grains. You take a wire loop and dip it in the kefir and scratch it over an agar plate enriched with a growth medium favorable to yeasts and then grab a sample of the the right yeast by visual discrimination once some spots have grown on the plate. 

I think that would work fine, but I don't want to do it. I'm not really up to mixing a growth medium, or making an agar plate, or waiting for cultures to grow on agar. For this to be an experiment worth my time, it has to be a lot less time consuming than that. But I think I have a solution!

Kluyveromyces species are famously heat tolerant as yeasts. Some quotes:

"The thermotolerance of different K. marxianus strains has already been documented, where it has been observed to grow at temperatures of up to 52°C and to ferment ethanol at temperatures between 38 and 45°C (Choudhary et al., 2016)."

"The thermotolerant yeast Kluyveromyces marxianus, growing at high temperature (45℃) , showed stronger survival under heat shock at 50℃ than the brewing yeast Saccharomyces cerevisiae, which was unable to grow at 45℃. The survival rate of K. marxianus decreased to 10% during heat shock at 50℃ for 20 min, and to less than 0.01% at 60℃ for 20 min. Cells with damaged cellular membranes were infrequently observed at 50℃ and had decreased significantly from heat shock at 60℃. The metabolic activity of K. marxianus was retained at 50℃, whereas that of S. cerevisiae was not."

So my plan is get some Kluyveromyces from kefir, and heat it to 50℃ for long enough to reduce other yeasts (and hopefully bacteria) without killing the Kluyveromyces, i.e. perhaps somewhat less than 20 minutes so that I don't decrease it all the way down to 10%.

I think this temperature and exposure length will kill Lactococcus and Leuconostoc and Acetobacter, but not all Lactobacillus.

So that's where I'm stuck at the moment. I think I can kill the other yeasts, but I want to also kill of the other bacteria. And then I'll maybe build up the Kluyveromyces culture a little by feeding it some sugar and add it to a container of juice with an air pump. Maybe there will be a HEPA filter or two somewhere for sterility.

Instead of using Kluyveromyces, I've also put some thought into protocols that remove sugar from juice by fermenting the sugar to alcohol using the standard Saccharomyces and then removing the alcohol, perhaps simultaneously with the ferment or in several alternating stages. I'm not optimistic about that, but I haven't given up on it entirely.

...

Anyway, the next task is selection for Kluyveromyces over Lactobaccilus. I think Kluyveromyces might be a little more tolerant of low pH, but I'm not sure and even if I'm right, I don't think it's a big enough effect that I'd want to rely on it for selection. I've heard of using a protein called lysozyme as an anti-bacterial agent against gram-positive bacteria, and Lactobaccilus species are gram-positive, but apparently their response to lysozyme is strain dependent and I don't have any to begin with. Perhaps I could find a food that Kluyveromyces can metabolize but Lactobaccilus can't? That might be hard: lactobaccilus species can produce at least lactase, proteases, fructanases, amylases, bile salt hydrolases, phytases, and esterases. I hear most Lactobaccilus species are disparaged by the presence of hops in beer, but Lactobacillus brevis isn't.

...

You know, if I can't separate the two, maybe it's not the biggest problem? I'll still get juice that's free of simple sugars and alcohol. It might have extra lactic acid. Sad. Also, I'm a little worried that if I have a yeast and a bacteria, then that's a lot of metabolic machinery, and other things in juice that I wanted to extract might get eaten - no more esters, no more weird polysaccharides, no more variety. 

...

Hm! Here's an interesting quote: "Because they are unable to synthesize cytochromes, Streptococci cannot carry out oxidative phosphorylation. They are able to ferment sugars, but the end product is always lactic acid. Therefore, Streptococci are very acid tolerant and count among the lactic acid bacteria order."

Cytochromes are proteins that can perform electron transport because they have a heme group, a little tetrapyrole with an iron atom in the middle. So I looked into Streptococcus thermophilus, a lactic acid bacterium which is also a streptococcus, and which is used in dairy fermentation. And I got some different quotes from a source that I trust more, "Metabolic Profiles of Carbohydrates in Streptococcus thermophilus During pH-Controlled Batch Fermentation":

"S. thermophilus ferment sugars by the Embden-Meyerhoff-Parnas (EMP) pathway to pyruvate, which is converted into lactic acid by lactate dehydrogenase (LDH)."

"Streptococcus thermophilus is a typical homofermentative organism but also produces other metabolites, such as acetic acid, formic acid, acetaldehyde, and ethanol."

"Mixed-acid metabolism, a type of homofermentation, is characterized by the production of formate, acetate, ethanol, and/or CO2 in addition to lactate. And the homolactic metabolism can be shifted to a mixed-acid metabolism under certain conditions (carbon limitation, carbon excess of slowly metabolized sugars) (Mayo et al., 2015). However, the mechanisms underlying the shift from homolactic fermentation to mixed-acid fermentation have been the subject of considerable controversy (Papagianni et al., 2007). The primary metabolites and genes of carbohydrate metabolism in LAB have been studied."

If I'm reading table 1 correctly, it looks like S. thermophilus produces about 5000 times as much lactic acid as ethanol, so maybe that would be fine. Maybe I could take some juice, and turn the sugar into lactic acid, and then neutralize that with a base to get at all the other non-sugar and non-acid things.

...

Septimal Harmony Again

:: Roughly six rambling paragraphs of motivation for 7-limit just intonation

We mostly play instruments that are harmonic, meaning that sounded notes have strong identifiable base frequencies in addition to strongly present spectral spikes, or "partials", at frequencies which are integer multiples of the base frequency - so called harmonic partials or harmonics. We can sound multiple notes against each other that are related by simple frequency ratios ("just intonation") to produce nice combination-sounds because of this. If you have instruments whose partials are inharmonic, then just intonation stops being the right framework for producing euphonious polyphony among them.

In just intonation, you can get a fairly good scale using frequency ratios with prime factors of just 2 and 3. The interval system that abstracts this frequency ratio space is called rank-2 interval space and it's what almost all western musicians learn - it has intervals like the perfect fourth, the minor second, the augmented sixth, and the diminished seventh. Purely tuning rank-2 intervals is also called "Pythagorean tuning". The major, minor, and chromatic scales you get by purely tuning rank-2 intervals are fairly good, but not great. Most tuning systems you're familiar with, like 12-tone equal temperament and quarter comma meantone, are a patch for this: by mistuning rank-2 interval space a little, you can get some notes to sound like they have simpler and prettier ratios with factors of (2, 3, 5) instead of more complex ratios with just factors of (2, 3). For example, if you tune the rank-2 major seventh purely, you get a frequency ratio of 243/128, whereas the rank-3 major seventh is more simply 15/8. In addition to being have a smaller numerator and denominator, 15/8 does in fact sound better when sounded against the unison. Quarter comma meantone and 12-TET slide the major seventh toward its 5-limit value.

I contend that major, minor, and chromatic scales of western music theory are fundamentally rank-3, in that they're correctly abstracted from frequency ratios with factors of 5. Our music is most naturally represented with rank-3 intervals. There are many reasons why we use mistuned rank-2 intervals instead of purely tuned rank-3 intervals to represent western music - some of which are convenience of mental representation, convenience of symbolic representation on written scores, convenience of instrument construction, and convenience of performance. And at this point, people are so used to mistuned rank-2 intervals, that lots of people don't even like the sound of purely tuned rank-3 intervals as much, so called 5-limit just intonation.

But I believe western music is fundamentally rank-3, and I'm committed to rewriting music theory to reflect this. We've already got the convenient theory written, now it's time to do it right.

If harmony sounds better when we consider prime factors of 5 in our frequency ratios, what about higher primes? Is there a use for factors of 7?

The seventh harmonic sounds pretty good sounded against unison. It's definitely not a piano note, but it's not offensive. If anything it's kind of too pure? Like if you're used to 12-TET you'll be like, "Wait a second, why isn't this beating slightly? I'm use to slight beating." Also, barbershop quartets often use the seventh harmonic, and let's be honest, barbershop quartet music is sometimes technically impressive, but it's not really good. Some instruments are designed to suppress reduce spectral content near the 7th harmonic and its multiples: piano hammers are placed along the string that way. But despite the fact that some instruments suppress it, and that barbershop quartets aren't transcendently beautiful, I think think the 7th harmonic and other septimal intervals are pretty cool and valuable/useful in just intonation. "Blue notes" in blues which fall between the usual piano keys are often analyzed as being septimal. Like blues guitarists don't  just bend their strings to make ornamental variations in their melodies - they can be observed bending reliably to the same non-12-TET notes, and septimal frequency ratios are one framework for understanding the function of those notes. I've also used septimal intervals productively in analyzing middle eastern microtonal music. As we go to higher primes, they definitely become less relevant: you can't really pluck a 13th harmonic on a string, for example. Higher harmonics also get weaker in magnitude/volume as you go higher, so it gradually becomes unlikely that they're contributing perceptually to the timbre of instruments or the timbre of harmonies. Also people have imperfect pitch discrimination, so I think it stops making much sense to analyze pitches past a certain granularity - like even if it were loud enough to hear, is the 29th harmonic different enough from intervals available with harmonics up to 23 that we should name it that way? Or more concretely, trained people can only hear like 3 to 5 cents of frequency difference in a quiet laboratory setting, but my guess is that most people in noisy environments don't do much better than 20 cents. If an octave is 1200 cents, and there are perhaps 12 simple frequency ratios within an octave that are associated with each prime, then we can cover all the perceptually distinguishable frequencies with 1200 / 20 / 12 = 5 primes; [2, 3, 5, 7, 11]. Even if allow finer discrimination of frequency ratios in this model, it's not obvious to me that people will use frequency ratios differently just because they can notice a difference - a 5 cent sharp perfect fourth is still just going to be used like a perfect fourth. The fact that different tuning systems in wide use (or former/historic wide use) will place intervals more than 5-cents away from their pure values proves that our functional-assignments aren't as fine as our pitch discrimination.

Anyway, I recognize that the 11th harmonic contributs audibly to musical timbre. You can use audio filters to amplify or diminish the magnitude of a the 11th harmonic of a sound to experience its contribution and train yourself to recognize it - and it is fairly present and important, I'd say, having done a little of this training. So there's logical room for a theory of how to use 11-limit frequency ratios harmonically. But also the 11th harmonic sounded against the unison sounds pretty bad to my ear, while the 7th harmonic sounds quite good. So I myself am strongly motivated to understand septimal harmony, while the 11th harmonic and higher I mostly leave for other people to theorize about. The 7th harmonic, which sounds good/cool/interesting, and is also definitely useful for analyzing microtones beyond 5-limit just intonation, which are not uncommon in human music, even if they're not in the core of major/minor/chromatic notes that we use for most daily music in the west.

: Investigating 7-limit Just Intonation 

...

I started by making a little scale with septimal intervals and finer divisions than the chromatic. And then I picked three random distinct intervals from the scale to make a chord and listened to them to judge their consonance. I also removed the lowest note from all the intervals of the chord, so that below they're all have P1 in the bass. This made for a lot more intervals in my chord space than were in my original scale. Which is fine. It means I did a more thorough investigation of septimal intervals. Anyway, then I rated the chords as {"good", "okay", or "bad"} in terms of consonance. And I did that at least four times for each chord below and many others that were too ugly to include. Then I associated those categories with {3, 2, 1} so I could take an average and sort numerically. And here below we have, a bunch of chords with septimal intervals sorted by how consonant I thought they were. Higher values for higher consonance.

...

3.0 : ('P1', 'm3', 'SpM6')

3.0 : ('P1', 'SpGrA5', 'SpA9')

3.0 : ('P1', 'SpA6', 'M10')

3.0 : ('P1', 'SpA4', 'SpM6')

3.0 : ('P1', 'SpA3', 'M6')

3.0 : ('P1', 'Sbd4', 'Sbd6')

3.0 : ('P1', 'SbAcd4', 'AcM6')

3.0 : ('P1', 'P5', 'SbAcd11')

3.0 : ('P1', 'M6', 'SbAc11')

2.8333333333333335 : ('P1', 'SpGrA5', 'M10')

2.8333333333333335 : ('P1', 'P4', 'Sbd7')

2.8 : ('P1', 'Sbm3', 'Gr5')

2.8 : ('P1', 'Sbd5', 'M6')

2.8 : ('P1', 'Sbd3', 'Sbd5')

2.8 : ('P1', 'SbSb4', 'SbSbm6')

2.8 : ('P1', 'AcM2', 'Sbd5')

2.75 : ('P1', 'SpGrM3', 'SpM6')

2.75 : ('P1', 'SpA6', 'P8')

2.75 : ('P1', 'SpA3', 'SpA6')

2.75 : ('P1', 'SpA2', 'SpGrA5')

2.75 : ('P1', 'Sbd5', 'Sbd7')

2.75 : ('P1', 'SbAcd4', 'SbAcm6')

2.75 : ('P1', 'SbAcd4', 'AcM9')

2.7142857142857144 : ('P1', 'm7', 'SbAcd11')

2.7142857142857144 : ('P1', 'SpM6', 'SpA11')

2.7142857142857144 : ('P1', 'Grm3', 'Sbd6')

2.6666666666666665 : ('P1', 'm3', 'SpA4')

2.6666666666666665 : ('P1', 'm10', 'SpA11')

2.6666666666666665 : ('P1', 'm10', 'Sbd12')

2.6666666666666665 : ('P1', 'SpGr5', 'SpM6')

2.6666666666666665 : ('P1', 'SpA3', 'SpM6')

2.6666666666666665 : ('P1', 'Sbm7', 'M13')

2.6666666666666665 : ('P1', 'Grm7', 'Sbd10')

2.6 : ('P1', 'SpM6', 'SpA9')

2.6 : ('P1', 'SpGrM3', 'm6')

2.6 : ('P1', 'Sbm3', 'M6')

2.5 : ('P1', 'm3', 'Sbd5')

2.5 : ('P1', 'SpSpM3', 'M6')

2.5 : ('P1', 'SpA4', 'm6')

2.5 : ('P1', 'Sbd7', 'AcM9')

2.5 : ('P1', 'SbAcd4', 'P5')

2.5 : ('P1', 'SbAcd11', 'AcM13')

2.5 : ('P1', 'M3', 'SpGrA5')

2.5 : ('P1', 'AcA2', 'Sbm7')

2.4285714285714284 : ('P1', 'SpA2', 'SpA4')

2.4 : ('P1', 'm3', 'Sp5')

2.4 : ('P1', 'd8', 'SbAcd11')

2.4 : ('P1', 'SpGrm3', 'SpGr5')

2.4 : ('P1', 'SpA2', 'M6')

2.4 : ('P1', 'Sbd4', 'Grm7')

2.4 : ('P1', 'SbAcd4', 'm7')

2.3333333333333335 : ('P1', 'm3', 'SpA5')

2.3333333333333335 : ('P1', 'd4', 'Sbd6')

2.3333333333333335 : ('P1', 'SpM2', 'SpA4')

2.3333333333333335 : ('P1', 'SpM2', 'SpA3')

2.3333333333333335 : ('P1', 'SpA5', 'P8')

2.3333333333333335 : ('P1', 'SpA3', 'P8')

2.3333333333333335 : ('P1', 'Sbm7', 'Sbm10')

2.3333333333333335 : ('P1', 'Sbm7', 'M10')

2.3333333333333335 : ('P1', 'Sbd8', 'P11')

2.3333333333333335 : ('P1', 'Sbd5', 'Grd7')

2.3333333333333335 : ('P1', 'Sbd12', 'M13')

2.3333333333333335 : ('P1', 'SbSbm7', 'SbSbAc11')

2.3333333333333335 : ('P1', 'SbAc4', 'Sbm7')

2.3333333333333335 : ('P1', 'P4', 'Sbm6')

2.3333333333333335 : ('P1', 'AcM6', 'SbAcd8')

2.2857142857142856 : ('P1', 'SpA4', 'SpM9')

2.25 : ('P1', 'm7', 'SpA8')

2.25 : ('P1', 'SpGrm7', 'SpM9')

2.25 : ('P1', 'SpGr5', 'M10')

2.25 : ('P1', 'SpA4', 'SpGrA5')

2.25 : ('P1', 'SpA2', 'SpGr5')

2.25 : ('P1', 'Sbd7', 'P8')

2.25 : ('P1', 'SbAc11', 'SbAcM13')

2.25 : ('P1', 'Sb4', 'Sbm6')

2.25 : ('P1', 'P5', 'Sbd7')

2.2 : ('P1', 'm3', 'SbAcm6')

2.2 : ('P1', 'SpGrm3', 'SpGrm7')

2.2 : ('P1', 'SpGrM3', 'SpA4')

2.2 : ('P1', 'Sp5', 'SpGrm7')

2.2 : ('P1', 'Sbm3', 'P5')

2.2 : ('P1', 'Sbm3', 'A5')

2.1666666666666665 : ('P1', 'm3', 'SpGrm7')

2.1666666666666665 : ('P1', 'Grd5', 'Sbd8')

2.0 : ('P1', 'm6', 'SpGrM7')

2.0 : ('P1', 'SpSpA2', 'SpSpGrA5')

2.0 : ('P1', 'SpM6', 'SpM9')

2.0 : ('P1', 'SpM3', 'SpGrm7')

2.0 : ('P1', 'SpM3', 'SpGrA5')

2.0 : ('P1', 'SpM3', 'SpA5')

2.0 : ('P1', 'SpM3', 'P5')

2.0 : ('P1', 'SpM2', 'SpGrM7')

2.0 : ('P1', 'SpGrm3', 'SpA4')

2.0 : ('P1', 'SpGrM7', 'SpA9')

2.0 : ('P1', 'SpGrM7', 'M10')

2.0 : ('P1', 'SpGrM3', 'SbGrm7')

2.0 : ('P1', 'SpGr5', 'SpA9')

2.0 : ('P1', 'SpGr5', 'P8')

2.0 : ('P1', 'SpA5', 'SpA11')

2.0 : ('P1', 'SpA3', 'SpA9')

2.0 : ('P1', 'Sp4', 'SpM6')

2.0 : ('P1', 'Sbm7', 'SbAcd11')

2.0 : ('P1', 'Sbm7', 'P8')

2.0 : ('P1', 'Sbm6', 'M9')

2.0 : ('P1', 'Sbd8', 'Sbd10')

2.0 : ('P1', 'Sbd5', 'Sbm7')

2.0 : ('P1', 'Sbd5', 'Grm7')

2.0 : ('P1', 'Sbd4', 'Sbd10')

2.0 : ('P1', 'Sbd3', 'Grm7')

2.0 : ('P1', 'SbSbd5', 'SbGrd7')

2.0 : ('P1', 'SbSbAcd4', 'Sbm6')

2.0 : ('P1', 'SbAcd4', 'P12')

2.0 : ('P1', 'SbAcd4', 'Acm6')

2.0 : ('P1', 'SbAc4', 'SbAcM6')

2.0 : ('P1', 'SbAc11', 'AcA13')

2.0 : ('P1', 'P8', 'SpA10')

2.0 : ('P1', 'P8', 'Sbd10')

2.0 : ('P1', 'M3', 'Sbm7')

2.0 : ('P1', 'Grm7', 'Sbm10')

2.0 : ('P1', 'Grm3', 'Sbd8')

2.0 : ('P1', 'Grd5', 'Sbd10')

2.0 : ('P1', 'Acd4', 'SbAcm6')

2.0 : ('P1', 'AcM6', 'SbAc11')

2.0 : ('P1', 'AcM3', 'SbAcd8')

2.0 : ('P1', 'AcM2', 'SpAcA4')

2.0 : ('P1', 'Ac5', 'SbAcm10')

2.0 : ('P1', 'A4', 'Sbm6')

2.0 : ('P1', 'A2', 'SbGrm7')

1.8571428571428572 : ('P1', 'SpM3', 'SpA4')

1.8333333333333333 : ('P1', 'SpGr5', 'SpGrM7')

1.8333333333333333 : ('P1', 'Sb5', 'AcA9')

1.8 : ('P1', 'm3', 'SpA11')

1.8 : ('P1', 'SpGrM3', 'SpA8')

1.8 : ('P1', 'SpA2', 'SpA3')

1.8 : ('P1', 'Sbd4', 'SbGrm7')

1.8 : ('P1', 'Sbd4', 'Grd5')

1.8 : ('P1', 'Sb4', 'M6')

1.8 : ('P1', 'P8', 'SpA11')

1.8 : ('P1', 'P5', 'SpM6')

1.8 : ('P1', 'M3', 'SpGrM7')

1.75 : ('P1', 'Spm6', 'Sp11')

1.75 : ('P1', 'SpM3', 'SpSpGrA5')

1.75 : ('P1', 'SpM3', 'SpGrM7')

1.75 : ('P1', 'SpM2', 'SpM6')

1.75 : ('P1', 'SpGrm7', 'SpM10')

1.75 : ('P1', 'Sp4', 'Spm6')

1.75 : ('P1', 'Sbm3', 'SbAc11')

1.75 : ('P1', 'Sbd8', 'm10')

1.75 : ('P1', 'Sbd5', 'm10')

1.75 : ('P1', 'Sbd3', 'd5')

1.75 : ('P1', 'SbAc4', 'P8')

1.75 : ('P1', 'Sb5', 'SbSbm10')

1.75 : ('P1', 'M2', 'Sbm7')

1.7142857142857142 : ('P1', 'SbAcm2', 'Ac4')

1.6666666666666667 : ('P1', 'm6', 'SbAc11')

1.6666666666666667 : ('P1', 'm3', 'Sbm6')

1.6666666666666667 : ('P1', 'm3', 'SbSbAcm6')

1.6666666666666667 : ('P1', 'SpM3', 'd5')

1.6666666666666667 : ('P1', 'SpM2', 'SpGr5')

1.6666666666666667 : ('P1', 'SpM2', 'SpA5')

1.6666666666666667 : ('P1', 'SpA4', 'SpA5')

1.6666666666666667 : ('P1', 'SpA3', 'SpM7')

1.6666666666666667 : ('P1', 'SpA3', 'SpA8')

1.6666666666666667 : ('P1', 'SpA2', 'SpA8')

1.6666666666666667 : ('P1', 'Sbm6', 'Sb8')

1.6666666666666667 : ('P1', 'Sbm3', 'P8')

1.6666666666666667 : ('P1', 'SbAcm3', 'SbAc4')

1.6666666666666667 : ('P1', 'SbAcM2', 'AcA4')

1.6666666666666667 : ('P1', 'SbAc4', 'AcA9')

1.6666666666666667 : ('P1', 'P5', 'SpGrM7')

1.6666666666666667 : ('P1', 'P5', 'Sbd10')

1.6666666666666667 : ('P1', 'M3', 'Sbm6')

1.6666666666666667 : ('P1', 'M2', 'SpA10')

1.6666666666666667 : ('P1', 'Gr5', 'Sbm10')

1.6666666666666667 : ('P1', 'AcA2', 'SbAcM6')

1.6666666666666667 : ('P1', 'AcA2', 'SbAc4')

1.6 : ('P1', 'm7', 'SbAcm9')

1.6 : ('P1', 'SpM2', 'Sbd5')

1.6 : ('P1', 'SpA4', 'SpGrm7')

1.6 : ('P1', 'SpA3', 'SpGr5')

1.6 : ('P1', 'Sbm7', 'AcM9')

1.6 : ('P1', 'Sbm3', 'A4')

1.6 : ('P1', 'Sbd3', 'm6')

1.6 : ('P1', 'P4', 'Sbm7')

1.5 : ('P1', 'm3', 'Sbm7')

1.5 : ('P1', 'm3', 'Sb5')

1.5 : ('P1', 'SpM6', 'Sp11')

1.5 : ('P1', 'SpM3', 'SpM9')

1.5 : ('P1', 'SpM3', 'SpA6')

1.5 : ('P1', 'SpGrm7', 'SpA11')

1.5 : ('P1', 'SpGrM3', 'Spm6')

1.5 : ('P1', 'SpGrM3', 'SpGrm7')

1.5 : ('P1', 'SpAcM6', 'Ac11')

1.5 : ('P1', 'SpAcA2', 'Ac4')

1.5 : ('P1', 'SpA5', 'SpM9')

1.5 : ('P1', 'SpA5', 'SpGrM7')

1.5 : ('P1', 'SpA2', 'SpA10')

1.5 : ('P1', 'Sp4', 'SpGrM7')

1.5 : ('P1', 'Sbm2', 'Sb4')

1.5 : ('P1', 'Sbd5', 'SbSbd7')

1.5 : ('P1', 'Sbd4', 'Sbd11')

1.5 : ('P1', 'SbSbm3', 'Sbm6')

1.5 : ('P1', 'SbAcm2', 'SbSbd5')

1.5 : ('P1', 'SbAc4', 'P5')

1.5 : ('P1', 'SbAc4', 'AcM9')

1.5 : ('P1', 'Sb5', 'Grm7')

1.5 : ('P1', 'Sb4', 'GrM10')

1.5 : ('P1', 'M6', 'Sb8')

1.5 : ('P1', 'M3', 'Sb5')

1.5 : ('P1', 'Grm3', 'Sb4')

1.5 : ('P1', 'Acm6', 'SbAcd11')

1.5 : ('P1', 'AcA1', 'SbAcm6')

1.5 : ('P1', 'A5', 'Sb8')

1.4 : ('P1', 'SpA4', 'SpA8')

1.4 : ('P1', 'Sbm3', 'P4')

1.4 : ('P1', 'Sbd5', 'M7')

1.4 : ('P1', 'SbAcM6', 'P12')

1.3333333333333333 : ('P1', 'd4', 'Sbd10')

1.3333333333333333 : ('P1', 'SpSpA2', 'SpM6')

1.3333333333333333 : ('P1', 'SpM6', 'SpA8')

1.3333333333333333 : ('P1', 'SpM6', 'P12')

1.3333333333333333 : ('P1', 'SpM3', 'SpA3')

1.3333333333333333 : ('P1', 'SpM3', 'SpA11')

1.3333333333333333 : ('P1', 'SpM3', 'SbAcm13')

1.3333333333333333 : ('P1', 'SpGrm7', 'SpA8')

1.3333333333333333 : ('P1', 'SpGrm3', 'm6')

1.3333333333333333 : ('P1', 'SpGrm3', 'SpGrM7')

1.3333333333333333 : ('P1', 'SpGrm3', 'Sp8')

1.3333333333333333 : ('P1', 'SpGrM7', 'SpM10')

1.3333333333333333 : ('P1', 'SpGrA5', 'SpA6')

1.3333333333333333 : ('P1', 'SpGr5', 'SpM10')

1.3333333333333333 : ('P1', 'SpA4', 'SpA12')

1.3333333333333333 : ('P1', 'Sp5', 'SpGrM7')

1.3333333333333333 : ('P1', 'Sbm6', 'SpGrM10')

1.3333333333333333 : ('P1', 'Sbm3', 'Sb5')

1.3333333333333333 : ('P1', 'Sbm10', 'm13')

1.3333333333333333 : ('P1', 'Sbd5', 'Sbd12')

1.3333333333333333 : ('P1', 'Sbd4', 'Grd7')

1.3333333333333333 : ('P1', 'SbSbm6', 'SbSbd8')

1.3333333333333333 : ('P1', 'SbAcm9', 'SbAc11')

1.3333333333333333 : ('P1', 'SbAc4', 'AcA6')

1.3333333333333333 : ('P1', 'Sb5', 'M7')

1.3333333333333333 : ('P1', 'P5', 'SbAc11')

1.3333333333333333 : ('P1', 'P4', 'SbM10')

1.3333333333333333 : ('P1', 'M6', 'SpM9')

1.3333333333333333 : ('P1', 'M6', 'Sbd8')

1.3333333333333333 : ('P1', 'M3', 'SpM9')

1.3333333333333333 : ('P1', 'M10', 'SbAcM13')

1.3333333333333333 : ('P1', 'Grd3', 'Sbd6')

1.3333333333333333 : ('P1', 'AcA2', 'Sb5')

1.3333333333333333 : ('P1', 'Ac4', 'SbAcm10')

1.3333333333333333 : ('P1', 'A4', 'Sbm10')

1.25 : ('P1', 'SpSpGrA5', 'P8')

1.25 : ('P1', 'SpM9', 'Sbd11')

1.25 : ('P1', 'SpM2', 'SpGrm7')

1.25 : ('P1', 'SpGrM3', 'Sp8')

1.25 : ('P1', 'SpA3', 'SpGrM7')

1.25 : ('P1', 'SpA1', 'SpGrm7')

1.25 : ('P1', 'SpA1', 'SpGr5')

1.25 : ('P1', 'Sbm6', 'SbSbd7')

1.25 : ('P1', 'SbSbAcd4', 'SbAcM13')

1.25 : ('P1', 'SbAcd4', 'd5')

1.25 : ('P1', 'Sb5', 'A11')

1.25 : ('P1', 'M3', 'Sbd5')

1.25 : ('P1', 'GrM6', 'SbGrm7')

1.2 : ('P1', 'SpA1', 'SpA3')

1.2 : ('P1', 'Sbd3', 'm3')

...

A bunch of these intervals I find pretty suspicious; I think they're probably not representing simple septimal sounds. Rather they're consonant to my ear because they're approximating other frequency ratios, like 3-limit ratios or 5-limit ratios or even irrational 12-EDO frequency ratios, which my ear is unfortunately also accustomed to and sometimes picks out as consonant.

The next step of my investigation is to go through the more consonant chords and try to figure out which ones are actually septimal in character, and then I can piece together some heuristics for building consonant septimal chords, which can then be used as constraints in composing counterpoint and other polyphony.

There are other options for judging chordal consonance programmatically - I could use a Sethares-inspired psychoacoustic model of polyphonic audition (which I think would work fairly well but is overkill as a thing to include in a program for composing) or I could look at complexity of the chord's otonal representation (which I think is nonsense psychoacoustically but it would be easy). But my program of reverse engineering chords that I like worked well when I learned/invented heuristics for composing in 5-limit just intonation and I think it will continue to serve me well in 7-limit.

...

When I look through all the internal intervals within the harmonious-rated chords above, a lot of the frequency ratios of internal intervals are close to 5-limit ratios - off by a factor of 225/224, which is like 7 cents. The interval justly associated with 225/224 is called the septimal super augmented zeroth, SpA0. I'm going to use this fact to figure out which of the chords are not really septimal.

First I define the basis for a tunings system

    (SpA0, Sbm7, P8, M3)

In the rank-4 Lilley Johnston comma basis, this basis is written

    ((0, 0, -1, 1), (3, 10, 6, -1), (3, 12, 7, 0), (1, 4, 2, 0))

This has a determinant of 2, which will be important shortly. The basis intervals are justly tuned to (225/224, 7/4, 2/1, 5/4), but I'm going to define a tuning system that tempers out the first interval, SpA0.

    (SpA0, Sbm7, P8, M3) -> (1/1, 7/4, 2/1, 5/4)

Now we have the pieces we need to tune arbitrary rank-4 intervals in a system that tempers out SpA0, and therefore assigns equal frequency ratios to two intervals that differ by SpA0. I can go through chords and look at their intervals and say for each one, "Is there an interval with these same tempered coordinates / the same frequency ratio that has a shorter name? If  so, let's make a new chord where the intervals are simplified and we'll see that some of these harmonious chords with complex rank-4 intervals were functioning as harmonious chords with only rank-3 intervals, as far as someone with pitch discrimination around 7 cents can discern."

I am also interested in using this temperament procedure to replace complex intervals with simpler intervals of a different kind - those with lower prime-rank, rather than shorter/simpler names. And I suppose I could combine these two: like if Grm7 and Sbm7 happened to have the same tempered coordinates, then I could prefer to spell by chords with Grm7 on account of it being 5-limit. I think that's worth exploring at some point, but first I'm just going to use short interval names as my measure of complexity, and given two interval names of equal length, I'm going to prefer ones which come earlier in the list of intervals I added to a list as they became relevant when I was playing around with septimal chords. This is kind of arbitrary, but I don't think it's exactly wrong to say "these intervals are in practice more important, so I'm going to use them in my future analyses".

We could also use a measure of just-frequency-ratio complexity to judge which of two intervals is simpler when they have the same tempered coordinates. Lots of options. For another time.

...

Okay, so the super augmented third, SpA3 showed up a few times in my harmonious septimal chords. This differs from P4 by SpA0, and P4 is way simpler, so I'm going to reinterpret all the SpA3s as being not really septimal. Like [P1, SpA3, M6] should be called [P1, P4, M6], which is an inversion of [P4, M6, P8] which is a major chord rooted on P4, like F.maj in they key of C major. Not septimal.

Likewise our temperament maps Sbd6 to P5. Not septimal. I'm replacing SpGrA5 with Grm6. I'm replacing SpSpM3 with Spd4. And SbAcd4 becomes AcM3. And Sbd3 becomes AcM2. And SbAcd11 is AcM10. And SpA6 becomes Grm7.

Using the tempering procedure, SbSb4 becomes SbA3. But neither one of these are particularly useful/functional/interpretable intervals. But they're both within 6 cents of AcM3. And that's how I'll treat them. This is like tempering out the intervals justly associated with 19683/19600 or 4375/4374 (a schisma off from SpA0), respectively. I think I'd also like to push SpGrM3 and Grd4 to AcM3.

My tempering procedure would turn SpGr5 into Grd6, which is like {32/21 -> 1024/675}. Neither one makes much sense to me. I think I'll stick with the first one. There really isn't much nearby that's simpler for frequency ratios other than P5. I suppose I should listen to the chord with P5 instead of SpGr5 to see which is better.

Due to my kind of arbitrary preference ordering of intervals that have the same length names, the temperament procedure actually introduced a septimal interval where it hadn't been before: I stand by AcA2 being re-interpreted as Sbm3, so now the harmonious chord [P1, AcA2, Sbm7] has an interpretation that' seven more septimal, [P1, Sbm3, Sbm7]. And {AcA2 -> Sbm3} looks like {75/64 -> 7/6} in frequency space, so that's attractive. Sbd10 tempers the same as the simpler AcM9, which is {56/25 -> 9/4}. And an octave down, Sbd3 goes to AcM2, which looks like {28/25 -> 9/8}.

These tempered substitutions look at a little suspicious to me:

    SbSb4 -> SbA3

    SbSbm6 -> SbA5

    SpGrM3 -> Grd4

    SpGr5 -> Grd6

I'll probably go through the frequency ratios and cent values for each substitution to see what's going on there / whether there are better options.

The more I look at this, the more I think that I should only use complexity of frequency ratios as my determining factor in choosing tempered interpretations.

The substitution SbAcm6 -> AcA5 is like {63/40 -> 405/256} which is suspicious for its increasing numerical complexity and for the fact that neither of those are simple intervals with standard harmonic functions relative to P1. Their cent values are 786 -> 794. Since Grm6, justly tuned to128/81, is a 3-limit interval with a standard harmonic function and its about as numerically simple as 63/40, I think that's the substitution I'm going to make instead. This is like tempering out the interval justly associated with (128/81) / (63/40) = 5120/5103, which is about 5 cents. This differs from SpA0 by a schisma, and I'd been seriously considering tempering out the schisma in addition to SpA0 in order to simplify interval names, so this is great.

...

So close. Three more intervals to decide about, and then I'll have septimal chords with simplified names, and I can go through and figure out if the simplified ones are more consonant. And then I can compare all the most consonant chords and decide which I like best among e.g.
    [P1, m3, Sbd5]
    [P1, m3, SpA4]
    [P1, m3, SpM6]

And pretty soon I'll have strong opinions about the best septimal chords. And then I can codify them with programmatic constraints and use them to compose and generate septimal music with really good harmony.

...

Here's a thought: if a chord is harmonious, then its inversions should be harmonious too. So if I can find any triad that is unambiguously nice and septimal, then I get two more triads for free that are nice and septimal. And if I have ratings for one chord, and four for another, and I find out that they're inversions of one another, then I've now got 8 ratings for the inversion family, which hopefully means greater precision or accuracy or something in my catalogue of how good these chords are.

...

Oh, super interesting. I was going through a new set of chords, giving them ratings. And I tried changing the instrument. And my ratings changed! Broadly, more chords sound consonant/harmonious/euphonious when played on a (software) clarinet ensemble than on a (software) set of guitar strings.

...

Here's are some summaries of a new round of ratings I did for a new batch of chords: Higher score mean greater consonance.

1.1666666666666667 : ('P1', 'M3', 'SpGr5')
1.1666666666666667 : ('P1', 'Sb5', 'M6')
1.1666666666666667 : ('P1', 'Sbd3', 'Grd7')
1.2 : ('P1', 'SpM3', 'Sbm7')
1.2857142857142858 : ('P1', 'SpM2', 'SpA5')
1.3333333333333333 : ('P1', 'P5', 'SpM6')
1.3333333333333333 : ('P1', 'Sbd3', 'Grm7')
1.4 : ('P1', 'SpM2', 'SpAcA4')
1.4285714285714286 : ('P1', 'GrM3', 'Sbm6')
1.4285714285714286 : ('P1', 'SbAc4', 'AcM6')
1.5 : ('P1', 'SbAcm6', 'm7')
1.5 : ('P1', 'SbGrd4', 'Grm6')
1.5 : ('P1', 'SpGrA5', 'SpA6')
1.5 : ('P1', 'SpM2', 'SpGr5')
1.5714285714285714 : ('P1', 'M2', 'Sbd5')
1.5714285714285714 : ('P1', 'SpM3', 'P5')
1.6 : ('P1', 'Sbm3', 'SbGrd6')
1.6 : ('P1', 'SpM3', 'SpAcA5')
1.6666666666666667 : ('P1', 'AcM3', 'SpM6')
1.6666666666666667 : ('P1', 'M3', 'Sbm7')
1.6666666666666667 : ('P1', 'M3', 'SpA6')
1.6666666666666667 : ('P1', 'Sbd4', 'Grd7')
1.6666666666666667 : ('P1', 'm3', 'SpGrm7')
1.7142857142857142 : ('P1', 'AcA2', 'SbAcM6')
1.7142857142857142 : ('P1', 'SbAc4', 'SbAcM6')
1.8 : ('P1', 'Sbm3', 'A5')
1.8 : ('P1', 'Sbm3', 'P4')
1.8 : ('P1', 'Sp5', 'SpGrM7')
1.8 : ('P1', 'SpA2', 'SpA10')
1.8 : ('P1', 'SpA3', 'SpGr5')
1.8 : ('P1', 'SpGrM3', 'SpGrm7')
1.8 : ('P1', 'SpGrm3', 'SpGrm7')
1.8 : ('P1', 'SpGrm3', 'm6')
1.8 : ('P1', 'SpSpM3', 'M6')
1.8 : ('P1', 'm3', 'Sbd5')
1.8333333333333333 : ('P1', 'A4', 'Sbm6')
1.8333333333333333 : ('P1', 'AcA4', 'Sbm7')
1.8333333333333333 : ('P1', 'Grd4', 'SpM6')
1.8333333333333333 : ('P1', 'Grm3', 'Sbd8')
1.8333333333333333 : ('P1', 'M3', 'SpGrA5')
1.8333333333333333 : ('P1', 'M3', 'SpM6')
1.8333333333333333 : ('P1', 'P4', 'Sbm7')
1.8333333333333333 : ('P1', 'P4', 'SpM6')
1.8333333333333333 : ('P1', 'SbA3', 'SbA5')
1.8333333333333333 : ('P1', 'Sp4', 'SpA5')
1.8333333333333333 : ('P1', 'SpA4', 'SpGrm7')
1.8333333333333333 : ('P1', 'SpM6', 'SpM13')
1.8571428571428572 : ('P1', 'Sbm3', 'A11')
1.8571428571428572 : ('P1', 'SpA2', 'SpM6')
2.0 : ('P1', 'AcM2', 'Sbd5')
2.0 : ('P1', 'AcM3', 'Sbm7')
2.0 : ('P1', 'Grd7', 'Sbd13')
2.0 : ('P1', 'Grm3', 'Sbm6')
2.0 : ('P1', 'M3', 'Sbm6')
2.0 : ('P1', 'Sb5', 'M7')
2.0 : ('P1', 'SbAcd4', 'd8')
2.0 : ('P1', 'SbGrM3', 'Grm6')
2.0 : ('P1', 'Sbm10', 'P11')
2.0 : ('P1', 'Sbm3', 'Grm7')
2.0 : ('P1', 'Sbm6', 'Sbm10')
2.0 : ('P1', 'SpA4', 'M6')
2.0 : ('P1', 'SpA4', 'SpGrA5')
2.0 : ('P1', 'SpA4', 'SpM6')
2.0 : ('P1', 'SpA4', 'SpM9')
2.0 : ('P1', 'SpA4', 'm6')
2.0 : ('P1', 'SpA5', 'SpM9')
2.0 : ('P1', 'SpGr4', 'Grm6')
2.0 : ('P1', 'SpGr5', 'M10')
2.0 : ('P1', 'SpGr5', 'P8')
2.0 : ('P1', 'SpGr5', 'SpM6')
2.0 : ('P1', 'SpGrM3', 'SpM6')
2.0 : ('P1', 'SpM3', 'SpA6')
2.0 : ('P1', 'SpM3', 'SpGrM7')
2.0 : ('P1', 'SpM3', 'SpGrm7')
2.0 : ('P1', 'd4', 'Sbd7')
2.0 : ('P1', 'm10', 'Sbd12')
2.0 : ('P1', 'm10', 'SpA11')
2.0 : ('P1', 'm3', 'Sbd7')
2.0 : ('P1', 'm3', 'SpM6')
2.0 : ('P1', 'm3', 'SpSp5')
2.142857142857143 : ('P1', 'Sbd6', 'Grm7')
2.142857142857143 : ('P1', 'Sbm3', 'P8')
2.142857142857143 : ('P1', 'Sbm6', 'M9')
2.142857142857143 : ('P1', 'SpGrA5', 'M10')
2.142857142857143 : ('P1', 'm3', 'SbAcm6')
2.1666666666666665 : ('P1', 'Grm3', 'Sbd13')
2.1666666666666665 : ('P1', 'M3', 'SpGrM7')
2.1666666666666665 : ('P1', 'SbAcd4', 'm7')
2.1666666666666665 : ('P1', 'Sbd5', 'M7')
2.1666666666666665 : ('P1', 'Sbd5', 'Sbd7')
2.1666666666666665 : ('P1', 'SpGr5', 'SpM9')
2.1666666666666665 : ('P1', 'SpM6', 'SpA9')
2.1666666666666665 : ('P1', 'm3', 'SpA4')
2.2 : ('P1', 'Sbm3', 'Gr5')
2.2 : ('P1', 'Sbm3', 'Sbd5')
2.2 : ('P1', 'Sbm3', 'Sbm6')
2.2 : ('P1', 'SpA10', 'SpM13')
2.2 : ('P1', 'SpA3', 'SpA9')
2.2 : ('P1', 'SpA4', 'SpA5')
2.2 : ('P1', 'SpA5', 'SpA11')
2.2 : ('P1', 'SpGr5', 'SpM10')
2.2 : ('P1', 'SpGrM3', 'SpA5')
2.2 : ('P1', 'SpGrM3', 'm6')
2.2 : ('P1', 'SpGrM7', 'M10')
2.2 : ('P1', 'SpM3', 'SpA5')
2.2 : ('P1', 'SpM3', 'SpGrA5')
2.2 : ('P1', 'SpSpM3', 'SpSpAcA5')
2.2 : ('P1', 'm3', 'SpA5')
2.2 : ('P1', 'm3', 'Spd6')
2.2857142857142856 : ('P1', 'M6', 'SpA9')
2.2857142857142856 : ('P1', 'SbAcd4', 'SbAcm6')
2.2857142857142856 : ('P1', 'SpA2', 'Grm6')
2.2857142857142856 : ('P1', 'SpA2', 'SpGrA5')
2.3333333333333335 : ('P1', 'AcA9', 'SbAcM13')
2.3333333333333335 : ('P1', 'Grm3', 'Sbm7')
2.3333333333333335 : ('P1', 'P5', 'Sbm10')
2.3333333333333335 : ('P1', 'SbAc4', 'A5')
2.3333333333333335 : ('P1', 'SbAcd4', 'Acm6')
2.4 : ('P1', 'Sbm3', 'P5')
2.4 : ('P1', 'Sbm3', 'Sbm7')
2.4 : ('P1', 'Sbm7', 'Sbm10')
2.4 : ('P1', 'Sp4', 'SpM6')
2.4 : ('P1', 'Sp4', 'm6')
2.4 : ('P1', 'SpA2', 'SpGr5')
2.4 : ('P1', 'SpA3', 'SpGrA5')
2.4 : ('P1', 'SpA9', 'SpA11')
2.4 : ('P1', 'SpGr5', 'SpA10')
2.4 : ('P1', 'SpM2', 'SpGr4')
2.4 : ('P1', 'SpM3', 'SpGr5')
2.4 : ('P1', 'SpM3', 'SpM6')
2.4 : ('P1', 'Spd4', 'M6')
2.4 : ('P1', 'd8', 'SbAcd11')
2.4 : ('P1', 'm7', 'SbAcd11')
2.4285714285714284 : ('P1', 'AcM6', 'SbAcd11')
2.4285714285714284 : ('P1', 'Grm3', 'Sbd6')
2.4285714285714284 : ('P1', 'Sbd4', 'Grm7')
2.5 : ('P1', 'AcM3', 'SbA5')
2.5 : ('P1', 'AcM3', 'Sbm6')
2.5 : ('P1', 'Gr5', 'Sbm10')
2.5 : ('P1', 'SbAcd4', 'AcM6')
2.5 : ('P1', 'SbAcd4', 'SbAcm13')
2.5 : ('P1', 'SbGrdd5', 'Grm6')
2.5 : ('P1', 'SbSbGrd4', 'Grm6')
2.5 : ('P1', 'Sbd5', 'M6')
2.5 : ('P1', 'SpGrA5', 'SpA9')
2.6 : ('P1', 'SpA3', 'SpM6')
2.6 : ('P1', 'SpA9', 'M13')
2.6 : ('P1', 'SpA9', 'SpA10')
2.6 : ('P1', 'SpGrM3', 'SpGr5')
2.6 : ('P1', 'Spd4', 'SpAcm6')
2.6666666666666665 : ('P1', 'A4', 'Sbm10')
2.6666666666666665 : ('P1', 'AcM3', 'SbAcm6')
2.6666666666666665 : ('P1', 'SbAcd4', 'P12')
2.6666666666666665 : ('P1', 'Sbd4', 'Grm6')
2.6666666666666665 : ('P1', 'Sbd4', 'm6')
2.7142857142857144 : ('P1', 'Sbd7', 'AcM9')
2.8 : ('P1', 'Sbm7', 'M10')
2.8 : ('P1', 'SpA2', 'SpAcAA4')
2.8 : ('P1', 'SpA3', 'M6')
2.8 : ('P1', 'SpA6', 'M10')
2.8 : ('P1', 'SpA6', 'P8')
2.8333333333333335 : ('P1', 'A5', 'Sbm10')
2.8333333333333335 : ('P1', 'AcM3', 'SbSbm6')
2.8333333333333335 : ('P1', 'Grm6', 'SpA9')
2.8333333333333335 : ('P1', 'Grm7', 'Sbd10')
2.8333333333333335 : ('P1', 'M6', 'SbAc11')
2.8333333333333335 : ('P1', 'SbAc4', 'M6')
2.8333333333333335 : ('P1', 'SbAcd11', 'AcM13')
2.8333333333333335 : ('P1', 'SbAcd4', 'AcM9')
2.8333333333333335 : ('P1', 'Sbd4', 'Sbd6')
2.857142857142857 : ('P1', 'AcM3', 'SpAcAA4')
2.857142857142857 : ('P1', 'P4', 'Sbm6')
2.857142857142857 : ('P1', 'SbAcd4', 'P5')
3.0 : ('P1', 'AcM3', 'Sbd7')
3.0 : ('P1', 'P4', 'Sbd7')
3.0 : ('P1', 'P5', 'SbAcd11')
3.0 : ('P1', 'SbGrdd5', 'Sbd7')
3.0 : ('P1', 'SbSb4', 'SbSbm6')
3.0 : ('P1', 'Sbd7', 'P8')
3.0 : ('P1', 'Sbm7', 'M13')

...

I had the idea of using some math I used to use for document retrieval and word clouds and things like that. Basically find out which internal intervals are more likely to be in good chords and which are more likely to be in bad chords. And make allowances that only one bad interval needs to appear for a chord to sound bad, whereas all of the intervals in a chord need to be good or okay for the whole thing to sound good or okay.

...

Okay! Good news and bad news. The good news is I think I'm almost done analyzing septimal harmony. The bad news is that I don't like septimal harmony and I'm probably just going to give up on it soon. I figured out what most most of the septimal chords with [1, 3, 5] or [1, 3, 6] or [1, 4, 6] intervals were - I looked at triads with intervals of lower ordinal than 7ths. Aaaaand .... they're all just 5-limit chords in disguise.

I'm pretty sure (P1, SpSpM3, SpSpAcA5) was just functioning as (P1, P4, M6) to my ear. This is an inversion of [P1, M3, P5], along with [P1, m3, m6].

And (P1, SbGrdd5, Grm6) was just functioning as (P1, P4, Grm6). This is an inversion of [P1, Grm3, P5] along with [P1, AcM3, AcM6].

These three
(P1, SpA2, Grm6)
(P1, SpA2, SpGrA5)
(P1, m3, SpSp5)
were all functioning as (P1, m3, Grm6). This one looks weirder as an inversion: [P1, AcM3, Ac5] in root position, and [P1, Gr4, M6] for the (1, 4, 6) option. Did you know that those sounded decent? Its news to me. I should add them as chords to my 5-limit just intonation composition suite.

These three 
(P1, AcM3, SpAcAA4)
(P1, SbAcd4, P5)
(P1, SpGrM3, SpGr5)
were all functioning as
(P1, AcM3, P5)
That's already in root position, but its inversions are [P1, P4, AcM6] and [P1, Grm3, Grm6] if you were curious.

This guy
(P1, SpA2, SpAcAA4),
was functioning as
(P1, m3, P5)
which has inversions of [P1, P4, m6]  and [P1, M3, M6].

And (P1, Sbm3, P5) is pretty much the only simple septimal triad that might have a unique sound to my ear, but its sound is pretty close to (P1, m3, P5) also, and not necessarily better than (P1, m3, P5). So what am I even doing here? Its inversions are [P1, P4, Sbm6] and [P1, SpM3, SpM6].

From those chord equivalences above, it seems my ear doesn't particularly notice any of these commas:

225/224 x5, "marvel"
126/125 x2, "starling"
19683/19600 x2, "cataharry"
245/243 x1, "sensamagic"
5120/5103 x1, "hemifamity"
64/63 x1, "Archytas"

I've got "x5" because there were 5 different intervals among the chords that differed from 5-limit ones by factors of 225/224 in their just tunings. That's 7-cents and I already knew that I have a little bit of a hard time choosing among intervals that differ by 22 cents, so no surprise here, but it's ...  it's a little disheartening to do so much math and coding and chord rating investigation, just to have it all be useless because I'm so tone deaf.

...

Anyway! We've got one root position septimal triad that might be worth using: [P1, Sbm3, P5]. And also there might be septimal intervals that are useful to put on top of triads, old and new. So septimal harmony might not be a total dud. But I need to stop looking at the whole chord space and start looking at like, "which seventh do I like best on top of  [P1, Sbm3, P5]". Or "what root positions triads work well with the harmonic seventh". And I think I'd like to know if there's any use for these intervals: [Sbm7, SpM7, Sbm9, SpM9, Sbm10, SpM10] which is noticeably different in sound/function from simple 5-limit intervals. Like if you flatten a minor interval by 36/35 instead of 81/80, or if you raise a major interval by 36/35 instead of sharpening it by 81/80, are the septimal intervals recognizably septimal in sound, or are they just close to Pythagorean intervals? My ear mostly ignored 225/224, not (36/35) / (81/80) = 64/63, and that guy is a whole 1200 * log_2(64/63) = 27 cents, so I should be able to hear it and make judgements about it. And hopefully I can find some harmonies that are both nice and recognizably septimal.

...

I already did some of that back in February of this year. 

...

Closed form expressions for matrix entries generated by iterative proportional fitting

Inspired by this.

If we start with a matrix [[1, 1], [1, 1]] and we perform iterative proportional fitting with real-valued non-zero growth factors [a, b], I've found that the equilibrium matrix has the form:

    [2a^2 / (a + b), 2ab / (a + b)]

    [2ab / (a + b), 2b^2 / (a + b)]

By growth factors, I mean the desired row and column sums are given by the original ones times those factors.

What if we have a different initial matrix?

If your initial matrix is all 5s instead of all 1s, then all the entries in the equilibrium matrix are 5 times larger.

If you scale the initial matrix columns by positive integers (m, n), then in the equilibrium matrix, the columns are scaled by (m, n). 

If you scale the initial rows by constants, you don't get anything like that though. Which is weird, because the iterative-proportional-fitting procedure is pretty symmetric between rows and columns. I guess in my code I take turns scaling rows (first) and columns (second) over and over, so that's one source of asymmetry.

Anyway, let's say we have an initial matrix [[m, m], [n, n]]. What's the equilibrium matrix for different growth factors (a, b)? Weirdly it only converges when the growth factors are equal, {a = b}. Otherwise, for example, the top left matrix entry alternates between two small rational values. When the growth factors are equal, the equilibrium matrix is the initial matrix scaled by the growth factor, i.e. [[am, am], [an, an]].

Okay, we've seen fully-constant initial matrices, and matrices with constant columns, and matrices with constant rows. Now for something spicier. Let's investigate a matrix that has all 1s except for the top left entry. Let's have a small change of notation: [a, b] no longer refer to growth factors. Instead our initial matrix is [[a, b], [c, d]], so that we can say {b=c=d=1}.

I've figured out symbolic expressions for the equilibrium matrix when we have growth factors [1/p, 1] for {p} a positive integer. I don't know of any reason why these formulas wouldn't work with {p} drawn from a more general classes of numbers, but I figured out the formulas using {p} over positive integers, and that's the only place where I've checked the formulas, and that's the only place where I'll assert their correctness now.

All the entries can be written as solutions of quadratic equations with leading terms {px^2} and rational coefficients. For given values of {a} and {p}, all the quadratic equations associated with the four entries of the equilibrium matrix have the same discriminant.

The top left entry of the equilibrium matrix is

    ((p + a^2 + a/2 - 1/2) - sqrt(D)) / (p(a - 1))

for discriminant

    D = p^2 + (2a^2 + a - 1)p + ((a+1)/2)^2

The anti-diagonal of the equilibrium matrix is constant. Both values are given by

    (-(p + (a+1)/2) + sqrt(D)) / (p(a -1))

The bottom right entry of the equilibrium matrix is

    ((2ap + a/2 - p + 1/2) - sqrt(D)) / (p(a - 1))

My method for figuring out these formulas mostly amounted to finding symbolic forms for entries of equilibrium matrices with defined {a} and {p}, and gradually noticing linear and quadratic patterns in constants, generalizing repeatedly from special cases. All pattern recognition, no proofs. But the formulas are correct. And if you can explain why, that'd be cool to see.

Next I'd like to try finding symbolic expressions for the equilibrium matrix terms when we have independent growth rates, or perhaps when we have non-unitary values for both {a} and {d} in the initial matrix, but those sound pretty hard, and I'm just going to savor the accomplishment of finding the above formulas for a while.

Oh! I can figure out growth rates [1, 1/p] instead of [1/p, 1]. That sounds like a manageable challenge. Please hold!

...

For growth rates [1, 1/p] and initial matrix [[a, 1], [1, 1]], IPF gives us an equilibrium matrix with top left entry

    ((a^2 + a/2 - 1/2)p + 1 - sqrt(D)) / ((a - 1)p)

for discriminant 

    D = ((a + 1)/2)^2 p^2 + (2a^2 + a - 1) p + 1

The antidiagonal is constant, and both values are given by

    (-1 * (((a + 1)/2)p + 1) + sqrt(D)) / ((a - 1)p)

and the bottom right entry of the equilibrium matrix is
    (p(a + 1)/2 + (2a - 1) - sqrt(D)) / ((a - 1)p)

Nice.

I just checked, and these formulas still work if your second growth rate isn't the reciprocal of an integer. You can use a growth rates of [1, 6/1] or [1, 5/8] or whatever. Just set {p} equal to the reciprocal of your second growth rate and they'll still predict correctly. And the case is likewise the set of formulas before these, for growth rates [1/p, 1]. You can use positive reals in the first slot, just set {p} to the reciprocal of the first growth rate.

...

I want to take small steps to generalize from here. I'm thinking that I could either look at initial matrices of the form [[a, 1], [1, a]] or I could look at growth rates {c * [1/p, 1]} and {c * [1, 1/p]}. And then eventually I'll get to independent diagonal values and independent growth rates. Or maybe that's already equivalent to independent growth rates? Because two real numbers will be related by a multiplicative constant {c}, namely their ratio. And {p} will be the inverse of one of them. I think that might be everything. Welp.

Let's start with an initial matrix of the form [[a, 1], [1, a]] and growth factors [1/p, 1], for {p} a positive integer. I fully expect that the formulas will continue to generalize to {1/p} being any positive real number.

For a=3, the discriminant term of entries in the equilibrium matrices has the form
D = p^2 + 34p + 1

The top left entry is given by 
    (p + 17 - sqrt(D)) / 4p

The anti-diagonal is constant with both values given by
    (-p  - 1 + sqrt(D)) / 4p

And the bottom right entry is given by
    (17p + 1 - sqrt(D)) / 4p

.

For a = 5, my first guess was that the discriminant was
    D = 1/4 p^2 + 49/2 p + 1/4

but that looks a little funny, and you can move a constant between the discriminant and the rest of the expression. So let's also consider four times the previous expression: 
    D = p^2 + 98p + 1

If we use that 4x discriminant, then the upper left entry of the equilibrium matrix has the form
    (p + 49 - sqrt(D)) / 8p

which isn't so bad. Let's stick with this discriminant. The anti-diagonal is constant, with values of the form
    (-p + -1 + sqrt(D)) / 8p

and the bottom right entry looks like
     (49p + 1 - sqrt(D)) / 8p

Smashing. Let's do {a = 7} and then we'll guess and check the full form for general {a} and then move on to something more challenging.

For {a = 7}, the discriminant term in the equilibrium matrix entries is
    D = p^2 + 194p + 1

The top left entry is
    (p + 97 - sqrt(D)) / 12p

the anti-diagonal is
    (-p - 1 + sqrt(D)) / 12p

and the bottom right entry is
    (97p + 1 - sqrt(D)) / 12p
.

So, generalizing over a=(3, 5, 7), it looks like the general discriminant term of the equilibrium matrix entries generated by IPF from a starting matrix [[a, 1], [1, a]] and growth factors [1/p, 1] is:

    p^2 + (4a^2 - 2)p + 1

We'll check that of course, but I've heard of crazier things.

The top left entry generalized to depend on {a} looks like
    (p + (2a^2 - 1) - sqrt(D)) / (2(a - 1)p)

The anti-diagonal is
    (-p - 1 + sqrt(D)) / (2(a - 1)p)

and the bottom right entry is
    ((2a^2 - 1)p + 1 - sqrt(D)) / (2(a - 1)p)

...

I had the thought that if I do analyze initial matrix 
    [[a, 1], [1, a]]
and the
    [[a, 1], [1, 2a]]
and then
    [[a, 1], [1, 3a]]
and maybe a few more, then I could try to generalize over those formulas and hopefully get a formula that's free in the coefficient in front of {a} on the bottom left, and then if that generalizes past the positive integers, then I've basically got independent upper-left and bottom-right entries. And then hopefully the simple patterns continue where you can multiply columns or rows by constants. And then we've got the whole damn thing solved. For one growth factor at least.

I'm starting to think that this problem is too boring to solve.

...
 
Maybe I can power through it. Just do 5 minutes a day.


Let's work on the case of initial matrix [[a, 1], [1, 2a]], growth rates [1/p, 1].

For a = 3, the discriminant term is
    D = ?
The top left entry is 
(p + ? - sqrt(D)) / (?p)

The antidiagonal is constant with value 
(-(p + 1) + sqrt(D)) / (?p)

The bottom right entry is 
(?p + ? - sqrt(D)) / (?p)

...