Godtone (talk | contribs)
note bird's eye view of temperaments by accuracy that i worked on for a while in case it helps anyone to find good temperaments
Godtone (talk | contribs)
 
(40 intermediate revisions by the same user not shown)
Line 4: Line 4:
== [[User:Godtone/Bird's eye view of temperaments by accuracy|Bird's eye view of temperaments by accuracy]] (W.I.P) ==
== [[User:Godtone/Bird's eye view of temperaments by accuracy|Bird's eye view of temperaments by accuracy]] (W.I.P) ==
If you want to contribute make sure the temperaments make sure to follow the format, such as specifying the exact note count needed for a set of odds separately from the smallest MOS scale that has at least or more than that number of notes. The focus is on practically-useful temperaments of general interest. Many temperaments have not yet been documented there. It's supposed to be a compilation of "cream of the crop" basically, sorted by accuracy so that you can determine your own accuracy-to-simplicity tradeoff that is best for you, but note many higher-accuracy temperaments there are simple ''despite'' being accurate, so I recommend looking at the note counts and set of targetted odds for higher-accuracy stuff first.
If you want to contribute make sure the temperaments make sure to follow the format, such as specifying the exact note count needed for a set of odds separately from the smallest MOS scale that has at least or more than that number of notes. The focus is on practically-useful temperaments of general interest. Many temperaments have not yet been documented there. It's supposed to be a compilation of "cream of the crop" basically, sorted by accuracy so that you can determine your own accuracy-to-simplicity tradeoff that is best for you, but note many higher-accuracy temperaments there are simple ''despite'' being accurate, so I recommend looking at the note counts and set of targetted odds for higher-accuracy stuff first.
== zeta and optimal_edo_sequence ==
On a separate subpage I've shown the best scoring equal temperaments according to the zeta function, using a small modification to the code kindly provided at [[User:Sintel/Zeta plot python]]:
* [[User:Godtone/zeta]]
Whose significance is backed up by the more psychoacoustically-informed tuning metrics I've designed (<code>optimal_edo_sequence</code>s from [[#My Python 3 code]]):
* [[User:Godtone/optimal edo sequences]] (and [[User:Godtone/strict_optimal_edo_sequences]])
...as well as by my own knowledge of tuning theory.


== Simple ratios and where I think limits should be drawn ==
== Simple ratios and where I think limits should be drawn ==
Line 98: Line 105:
* 31: The next EDO that melodically approximates the 11-limit, and considerably better. Extremely nice arrangement of intervals that feels weirdly intuitive and ideal. Colourful EDO. Basically ideal meantone tuning as more notes than this is overkill for meantone if you don't specifically want meantone.
* 31: The next EDO that melodically approximates the 11-limit, and considerably better. Extremely nice arrangement of intervals that feels weirdly intuitive and ideal. Colourful EDO. Basically ideal meantone tuning as more notes than this is overkill for meantone if you don't specifically want meantone.
* 32: 16 EDO with a sharp fifth. I like it primarily because of it being a power of 2. Exploration into this EDO could be interesting. 80 EDO offers a reasonably good approximation of it through a 16L16s MOSS.
* 32: 16 EDO with a sharp fifth. I like it primarily because of it being a power of 2. Exploration into this EDO could be interesting. 80 EDO offers a reasonably good approximation of it through a 16L16s MOSS.
* 34: The first good approximation of the 5-prime-limit due to being the first reasonably accurate tuning of [[Kleismic family|kleismic]] and [[srutal archagall]] which are IMO the best 5-limit temperaments that observe the [[81/80|syntonic comma]]. 19 is also a tuning for kleismic but feels like it doesn't do justice to the accuracy and pristineness of kleismic to me, plus its harmonic interpretation is pretty lacking. And 22 is very obviously to Has the sharp 3/2's of 17 EDO, and as 17 EDO is a good colour system, 34 EDO is a natural extension. Also is a very logical "completion" of 17 due to giving a very logical 2.3.5.13.17(.23)-subgroup interpretation of the sqrt(2).sqrt(3) subgroup with some really intriguing possibilities. If you're lacking in inspiration and its wide array of supported MOSSes aren't inspiration enough, try taking a look at the diaschismic-tetracot continuum ([[2048/2025]])<sup>n</sup> / ([[20000/19683]]).
* 34: The first good approximation of the 5-prime-limit due to being the first reasonably accurate tuning of [[Kleismic family|kleismic]] and [[srutal archagall]] which are IMO the best 5-limit temperaments that observe the [[81/80|syntonic comma]]. 19 is also a tuning for kleismic but feels like it doesn't do justice to the accuracy and pristineness of kleismic to me, plus its harmonic interpretation is pretty lacking. And 22 is very obviously too high-damage for srutal archagall. Has the sharp 3/2's of 17 EDO, and as 17 EDO is a good colour system, 34 EDO is a natural extension. Also is a very logical "completion" of 17 due to giving a very logical 2.3.5.13.17(.23)-subgroup interpretation of the sqrt(2).sqrt(3) subgroup with some really intriguing possibilities. If you're lacking in inspiration and its wide array of supported MOSSes aren't inspiration enough, try taking a look at the diaschismic-tetracot continuum ([[2048/2025]])<sup>n</sup> / ([[20000/19683]]).
* 35: A subset of 140 EDO, a ridiculously strong generalist system, which endows it with magical tuning qualities.
* 35: A subset of 140 EDO, a ridiculously strong generalist system, which endows it with magical tuning qualities.
* 36: Because of being a superset of 12, quite overlooked. It is actually a very good subgroup temperament! A natural extension of 12 EDO's colour palette, preferring to avoid the neutral and semi- intervals of 24 EDO. I should note though that while both 24 and 36 are reasonably good systems, I do not think they should be used together, as there are preferable EDOs in the high end range, such as 80 EDO.
* 36: Because of being a superset of 12, quite overlooked. It is actually a very good subgroup temperament! A natural extension of 12 EDO's colour palette, preferring to avoid the neutral and semi- intervals of 24 EDO. I should note though that while both 24 and 36 are reasonably good systems, I do not think they should be used together, as there are preferable EDOs in the high end range, such as 80 EDO.
Line 207: Line 214:


==== Generalised colours of supertonics, subtonics, leads and contraleads ====
==== Generalised colours of supertonics, subtonics, leads and contraleads ====
Note: This scheme is a bit idiosyncratic and is instead intuitive in nature; specifically, a more systematic view would usually consider 11/10 as a submajor second, and 10/9 as a major second, but here I interpreted 11/10 instead as a sharp flavour of neutral.
<pre>
<pre>
inframinor (AKA 'ultraminor') second aka one quarter-tone: (many things)
inframinor (AKA 'ultraminor') second aka one quarter-tone: (many things)
Line 277: Line 285:
...
...
</pre>
</pre>
==== 87 EDO interval colours/types (seconds and thirds) ====
<pre>
<pre>
80 EDO MOSS gens table:
41.4c fifth-tone
 
55.2c ultraminor (AKA quarter-tone)
(1\10: 120c)
69.0c subminor (AKA third-tone)
(~1\9: 135c (~~8L1s))
82.8c neominor
(1\8: 150c)
96.6c novaminor
7L1s: 165c
110.3c minor
6L1s: 180c (7L6s) (note 195c (6L7s) is extreme with L/s=6.5)
124.1c supraminor
5L1s: 210c (6L5s), 225c (5L6s)
137.9c subneutral (AKA minor neutral)
(1\5: 240c)
151.7c superneutral (AKA major neutral)
5L4s: 255c
165.5c submajor
4L5s: 270c, 285c
179.3c major
(1\4: 300c)
193.1c novamajor
4L7s: 315c
206.9c neomajor
(~~1\11: 330c (~7L4s))
220.7c supermajor
7L3s: 345c
234.5c ultramajor
3L4s: 360c
248.3c semifourth
3L7s: 375c, 390c
262.1c ultraminor
3L8s: 405c, 420c, 435c (all also ofc 3L5s; biased to 435c)
275.9c subminor
(3\8: 450c)
289.7c neominor
5L3s: 465c
303.4c novaminor
(2\5: 480c)
317.2c minor
5L2s: 495c, 510c
331.0c supraminor
7L2s: 525c
344.8c subneutral
2L7s: 540c, 555c, 570c, 585c (all also ofc 2L5s; biased to 540c)
358.6c superneutral
372.4c submajor
386.2c major
400.0c novamajor
413.8c neomajor
427.6c supermajor
441.4c ultramajor
455.2c semisixth
</pre>
== Miscellaneous ==
==== 80 EDO MOSS gens table ====
<pre>
80 EDO MOSS gens table:
 
(1\10: 120c)
(~1\9: 135c (~~8L1s))
(1\8: 150c)
7L1s: 165c
6L1s: 180c (7L6s) (note 195c (6L7s) is extreme with L/s=6.5)
5L1s: 210c (6L5s), 225c (5L6s)
(1\5: 240c)
5L4s: 255c
4L5s: 270c, 285c
(1\4: 300c)
4L7s: 315c
(~~1\11: 330c (~7L4s))
7L3s: 345c
3L4s: 360c
3L7s: 375c, 390c
3L8s: 405c, 420c, 435c (all also ofc 3L5s; biased to 435c)
(3\8: 450c)
5L3s: 465c
(2\5: 480c)
5L2s: 495c, 510c
7L2s: 525c
2L7s: 540c, 555c, 570c, 585c (all also ofc 2L5s; biased to 540c)
</pre>
</pre>


Line 318: Line 363:
</pre>
</pre>


==== 87 EDO interval colours/types (seconds and thirds) ====
== MOSS names i think are pretty ==
<pre>
Note: I am only considering octave-period MOSSes here. Table is an edited version of the standardised version at [[TAMNAMS#Mos_pattern_names]]. I made a few small changes of personal preference:
41.4c fifth-tone
 
55.2c ultraminor (AKA quarter-tone)
* [[4L 1s]] I call "pentoid" after [[Bug_family#Pentoid|the 11-limit 4&5 exotemperament]] for which practically the entire tuning range of the MOSS is valid due to its impractically low accuracy/high damage (this is evidenced by it also being supported by patent val in EDOs 4+5=9 (the basic tuning) and 4+5+4=14 (the hard tuning), and by the 13b val (the soft tuning) where you take the (only barely) second-best fifth).
69.0c subminor (AKA third-tone)
 
82.8c neominor
* [[1L 6s]] I find significant as a 7-note scale underlying all nL1s scales for n>=7. I have named it "onyx", which has a variety of aesthetic reasonings for it: "1Ln-ic's" and "nL1-ic's (like, the -ic suffix applied to MOSS names, collectivised for 1Lns and nL1s) sounds like "one-el-en-ics" or "en-el-one-ics" which abbreviated sort of sounds like "one-ics" => "onyx". Then "onyx" sounds sort of like "one-six". Furthermore the onyx mineral comes in many colours and types, which seems fitting given this is the parent scale for a wide variety of MOSSes; specifically of interest being [[7L 1s]] (pine), [[8L 1s]] (subneutralic) and [[9L 1s]] (sinatonic). Finally, the name "onyx" is also supposed to be vaguely reminiscent of "anti-archaeotonic" as "chi" (the greek letter) is written like an "x" (this is related to why "christmas" is abbreviated sometimes as "X-mas") and other than that, the letters "o" and "n" and their sounds are also present in "archaeotonic", and "x" is vaguely reminiscent of negation and multiplication. There is also something like a "y" sound in "archaeotonic" in the "aeo" part (depending partially on your pronounciation).
96.6c novaminor
 
110.3c minor
* [[4L 3s]] I noticed is unique in that out of [[1L 6s]], [[2L 5s]], [[3L 4s]], [[4L 3s]] and [[5L 2s]] it is the only MOSS pattern that doesn't have both of its child MOSSes named and included. Note that it makes sense to make an exception for [[6L 1s]] as the large number of large steps and small number of small steps makes the range of valid tunings for the generator(s) the most strict of all the 7-note MOSSes. Anyway, as generators close to 6/5 corresponding to [[kleismic]] temperament seem to be of especial importance for this MOSS, I consider the [[4L 7s]] pattern important enough to be named, and it had a proposed name of "kleistonic", a name I think is fitting. As a result, [[7L 4s]] could be named "anti-kleistonic", but I think its actually sort of the more natural extension of the [[4L 3s]] scale pattern which has sharper minor thirds in less complex tunings, hence I've opted for naming it "suprasmitonic" instead after its (and to a lesser extent smitonic's) supraminor third generator AKA "sharp minor third" - the origin of the name "smitonic". Note that another reason I think [[4L 7s]] is worth distinguishing and naming is because kleismic temperaments tend to need both more generators and very hard tunings for [[4L 3s]], as evidenced by the basic tuning of [[11edo]] being way too sharp for kleismic and the hard tuning of [[15edo]] being the sharpest kleismic that could ever make some sense (as it requires, for instance, accepting 720c as an approximation of 3/2 and 400c as an approximation of 5/4). The interval prefixes/abbreviations for [[7L 4s]] are "ssmi" to show preference in comparing it to the underlying [[4L 3s]] scale and as a shortenage of "sharp supraminor third" and "suprasmitonic" correspondingly.
124.1c supraminor
 
137.9c subneutral (AKA minor neutral)
* I gave names for the interval prefixes and interval name abbreviations for [[5L 7s]] (p-chromatic) and [[7L 5s]] (m-chromatic). For [[7L 5s]] I picked "chrome" as it is strongly befitting of meantone as meantone does the 7-limit efficiently, elegantly and colourfully, and because its a contraction of "chromatic" and the "me" in "meantone". Pronounced like the word. For [[5L 7s]], in contrast with [[5L 7s]] which is mellow and harmonic, [[5L 7s]] is sharp and active, perhaps like fire, hence I picked "pyr-" from "pyro" and from "[py]thago[r]ean", with the letters "pyr" of course also being for "[p]a[r]a[py]th", "su[p]e[rpy]th" and "ult[r]a[py]yth".
151.7c superneutral (AKA major neutral)
 
165.5c submajor
* Similarly to how I made an exception for the 1Lns scale form of [[1L 6s]], I'm also making an exception to include the multiMOSS of [[6L 2s]] as [[Diaschismic_family#Echidna|echidna]] (from which the MOSS derives its name) is a strong and important temperament to me with a period of half an octave and where one generator is both 11/10 and 9/7 depending on from which direction you view it, as 11/10 * 9/7 is extremely close to half an octave, the period for this MOSS scale. ("MultiMOSS" stands for "multi-period Moment Of Symmetry Scale".) '''However,''' this would not be included if I were to have this as "the semi-official [[TAMNAMS]] minimal MOSS name list", because this is a true exception to a lot of the design principles behind choosing this set of MOSSes to name and recognise as important.
179.3c major
 
193.1c novamajor
{| class="wikitable center-all"
206.9c neomajor
|+ TAMNAMS mos names
220.7c supermajor
|-
234.5c ultramajor
!colspan=5| 5-note mosses
248.3c semifourth
|-
262.1c ultraminor
! Pattern !! Name !! Interval prefix<ref name=prefix>used in interval names, e.g. ''perfect 3-oneirostep''</ref> !! Abbreviation<ref name=abbr>used in abbreviations of interval names, e.g. ''P3ons''</ref> !! Notes
275.9c subminor
|-
289.7c neominor
| [[2L 3s]] || pentic || pent- || pent || Shortening of pentatonic.
303.4c novaminor
|-
317.2c minor
| [[3L 2s]] || antipentic || apent- || apent || Sister MOSS of pentic.
331.0c supraminor
|-
344.8c subneutral
| [[4L 1s]] || pentoid || man- || man || The 11-lim[4&5] exotemperament "pentoid" is practically equivalent.
358.6c superneutral
|-
372.4c submajor
!colspan=5| 6-note mosses
386.2c major
|-
400.0c novamajor
! Pattern !! Name !! Interval prefix<ref name=prefix>used in interval names, e.g. ''perfect 3-oneirostep''</ref> !! Abbreviation<ref name=abbr>used in abbreviations of interval names, e.g. ''P3ons''</ref> !! Notes
413.8c neomajor
|-
427.6c supermajor
| [[5L 1s]] || machinoid || mech- || mech || Named after the 2.9.7.11 5&6 temperament [[machine]].
441.4c ultramajor
|-
455.2c semisixth
!colspan=5| 7-note mosses
</pre>
 
== MOSS names i think are pretty ==
Note: I am only considering octave-period MOSSes here. Table is an edited version of the standardised version at [[TAMNAMS#Mos_pattern_names]]. I made a few small changes of personal preference:
 
* [[4L 1s]] I call "pentoid" after [[Bug_family#Pentoid|the 11-limit 4&5 exotemperament]] for which practically the entire tuning range of the MOSS is valid due to its impractically low accuracy/high damage (this is evidenced by it also being supported by patent val in EDOs 4+5=9 (the basic tuning) and 4+5+4=14 (the hard tuning), and by the 13b val (the soft tuning) where you take the (only barely) second-best fifth).
 
* [[1L 6s]] I find significant as a 7-note scale underlying all nL1s scales for n>=7. I have named it "onyx", which has a variety of aesthetic reasonings for it: "1Ln-ic's" and "nL1-ic's (like, the -ic suffix applied to MOSS names, collectivised for 1Lns and nL1s) sounds like "one-el-en-ics" or "en-el-one-ics" which abbreviated sort of sounds like "one-ics" => "onyx". Then "onyx" sounds sort of like "one-six". Furthermore the onyx mineral comes in many colours and types, which seems fitting given this is the parent scale for a wide variety of MOSSes; specifically of interest being [[7L 1s]] (pine), [[8L 1s]] (subneutralic) and [[9L 1s]] (sinatonic). Finally, the name "onyx" is also supposed to be vaguely reminiscent of "anti-archaeotonic" as "chi" (the greek letter) is written like an "x" (this is related to why "christmas" is abbreviated sometimes as "X-mas") and other than that, the letters "o" and "n" and their sounds are also present in "archaeotonic", and "x" is vaguely reminiscent of negation and multiplication. There is also something like a "y" sound in "archaeotonic" in the "aeo" part (depending partially on your pronounciation).
 
* [[4L 3s]] I noticed is unique in that out of [[1L 6s]], [[2L 5s]], [[3L 4s]], [[4L 3s]] and [[5L 2s]] it is the only MOSS pattern that doesn't have both of its child MOSSes named and included. Note that it makes sense to make an exception for [[6L 1s]] as the large number of large steps and small number of small steps makes the range of valid tunings for the generator(s) the most strict of all the 7-note MOSSes. Anyway, as generators close to 6/5 corresponding to [[kleismic]] temperament seem to be of especial importance for this MOSS, I consider the [[4L 7s]] pattern important enough to be named, and it had a proposed name of "kleistonic", a name I think is fitting. As a result, [[7L 4s]] could be named "anti-kleistonic", but I think its actually sort of the more natural extension of the [[4L 3s]] scale pattern which has sharper minor thirds in less complex tunings, hence I've opted for naming it "suprasmitonic" instead after its (and to a lesser extent smitonic's) supraminor third generator AKA "sharp minor third" - the origin of the name "smitonic". Note that another reason I think [[4L 7s]] is worth distinguishing and naming is because kleismic temperaments tend to need both more generators and very hard tunings for [[4L 3s]], as evidenced by the basic tuning of [[11edo]] being way too sharp for kleismic and the hard tuning of [[15edo]] being the sharpest kleismic that could ever make some sense (as it requires, for instance, accepting 720c as an approximation of 3/2 and 400c as an approximation of 5/4). The interval prefixes/abbreviations for [[7L 4s]] are "ssmi" to show preference in comparing it to the underlying [[4L 3s]] scale and as a shortenage of "sharp supraminor third" and "suprasmitonic" correspondingly.
 
* I gave names for the interval prefixes and interval name abbreviations for [[5L 7s]] (p-chromatic) and [[7L 5s]] (m-chromatic). For [[7L 5s]] I picked "chrome" as it is strongly befitting of meantone as meantone does the 7-limit efficiently, elegantly and colourfully, and because its a contraction of "chromatic" and the "me" in "meantone". Pronounced like the word. For [[5L 7s]], in contrast with [[5L 7s]] which is mellow and harmonic, [[5L 7s]] is sharp and active, perhaps like fire, hence I picked "pyr-" from "pyro" and from "[py]thago[r]ean", with the letters "pyr" of course also being for "[p]a[r]a[py]th", "su[p]e[rpy]th" and "ult[r]a[py]yth".
 
* Similarly to how I made an exception for the 1Lns scale form of [[1L 6s]], I'm also making an exception to include the multiMOSS of [[6L 2s]] as [[Diaschismic_family#Echidna|echidna]] (from which the MOSS derives its name) is a strong and important temperament to me with a period of half an octave and where one generator is both 11/10 and 9/7 depending on from which direction you view it, as 11/10 * 9/7 is extremely close to half an octave, the period for this MOSS scale. ("MultiMOSS" stands for "multi-period Moment Of Symmetry Scale".) '''However,''' this would not be included if I were to have this as "the semi-official [[TAMNAMS]] minimal MOSS name list", because this is a true exception to a lot of the design principles behind choosing this set of MOSSes to name and recognise as important.
 
{| class="wikitable center-all"
|+ TAMNAMS mos names
|-
|-
!colspan=5| 5-note mosses
! Pattern !! Name !! Interval prefix<ref name=prefix/>!! Abbreviation<ref name=abbr/> !! Notes
|-
|-
! Pattern !! Name !! Interval prefix<ref name=prefix>used in interval names, e.g. ''perfect 3-oneirostep''</ref> !! Abbreviation<ref name=abbr>used in abbreviations of interval names, e.g. ''P3ons''</ref> !! Notes
| [[1L 6s]] || onyx || on- || on || My name for this scale. It is important as the parent of 7L1s, 8L1s, 9L1s, etc.
|-
|-
| [[2L 3s]] || pentic || pent- || pent || Shortening of pentatonic.
| [[2L 5s]] || antidiatonic || pel- || pel || Established name. ''pel'' comes from ''pelog''.
|-
|-
| [[3L 2s]] || antipentic || apent- || apent || Sister MOSS of pentic.
| [[3L 4s]] || mosh || mosh- || mosh || Graham Breed's name, from ''[[mohajira]]-ish''.
|-
| [[4L 1s]] || pentoid || man- || man || The 11-lim[4&5] exotemperament "pentoid" is practically equivalent.
|-
!colspan=5| 6-note mosses
|-
! Pattern !! Name !! Interval prefix<ref name=prefix>used in interval names, e.g. ''perfect 3-oneirostep''</ref> !! Abbreviation<ref name=abbr>used in abbreviations of interval names, e.g. ''P3ons''</ref> !! Notes
|-
| [[5L 1s]] || machinoid || mech- || mech || Named after the 2.9.7.11 5&6 temperament [[machine]].
|-
!colspan=5| 7-note mosses
|-
! Pattern !! Name !! Interval prefix<ref name=prefix/>!! Abbreviation<ref name=abbr/> !! Notes
|-
| [[1L 6s]] || onyx || on- || on || My name for this scale. It is important as the parent of 7L1s, 8L1s, 9L1s, etc.
|-
| [[2L 5s]] || antidiatonic || pel- || pel || Established name. ''pel'' comes from ''pelog''.
|-
| [[3L 4s]] || mosh || mosh- || mosh || Graham Breed's name, from ''[[mohajira]]-ish''.
|-
|-
| [[4L 3s]] || smitonic || smi- || smi || From ''sharp minor third''.
| [[4L 3s]] || smitonic || smi- || smi || From ''sharp minor third''.
Line 419: Line 429:
| [[2L 7s]] || joanatonic || jo- || jo || From [[joan]] temperament.
| [[2L 7s]] || joanatonic || jo- || jo || From [[joan]] temperament.
|-
|-
| [[4L 5s]] || orwelloid || or- || or || From [[orwell]] temperament.
| [[4L&nbsp;5s]] || gramitonic || gram- || gm || From "grave minor third". Formerly "orwelloid".
|-
|-
| [[5L 4s]] || semiquartal || sequar- || seq || From ''half-fourth''.
| [[5L 4s]] || semiquartal || sequar- || seq || From ''half-fourth''.
Line 456: Line 466:


== My Python 3 code ==
== My Python 3 code ==
IMPORTANT NOTE: there seems to be a bug for subgroup mappings at the moment, pending investigation, but ideally usage of subgroups should be made far easier too:
IMPORTANT NOTE: there seems to be bugs for subgroup mappings at the moment, pending investigation, but ideally usage of subgroups should be made far easier too:
<syntaxhighlight lang="python">
<syntaxhighlight lang="python">
>>> sg = [2, 3, 7, 11, 13, 17, 19]
>>> sg = [2, 3, 7, 11, 13, 17, 19]
Line 596: Line 606:
def sub_iv(r1, r2):
def sub_iv(r1, r2):
return iv( r1[0]*r2[1] - r2[0]*r1[1], r1[1]*r2[1] )
return iv( r1[0]*r2[1] - r2[0]*r1[1], r1[1]*r2[1] )
# IMPORTANT: assume x and y are nonnegative!
def iv_greater_than(x, y):
result = div_iv(x,y)
return result[0] > result[1]
def iv_greater_or_equal(x, y):
result = div_iv(x,y)
return result[0] >= result[1]
def iv_less_than(x, y):
return not iv_greater_or_equal(x, y)
def iv_less_or_equal(x, y):
return not iv_greater_than(x, y)
def as_float(x, p=None):
def as_float(x, p=None):
if type(x)==list: # monzo (factored)
if type(x)==list: # monzo (factored)
Line 1,158: Line 1,181:
# returns [] if cs or details of earliest counterexample if not;
# returns [] if cs or details of earliest counterexample if not;
# "earliest" is defined as "search all 1-steps from beginning to end, then all 2-steps, etc."
# "earliest" is defined as "search all 1-steps from beginning to end, then all 2-steps, etc."
def cs(scale_in):
def notcs(scale_in): # the alias cs for this function is deprecated due to being named confusingly but defined for convenience/backwards-compatibility
stepmap = dict()
stepmap = dict()
scale = scale_in.copy()
scale = scale_in.copy()
Line 1,172: Line 1,195:
stepmap[interval] = j
stepmap[interval] = j
return []
return []
cs = notcs # the alias cs for this function is deprecated due to being named confusingly but defined for convenience/backwards-compatibility


def rotate(scale,n,p=(2,1)):
def rotate(scale,n,p=(2,1)):
Line 1,221: Line 1,245:
print(edo,'EDO interpretation')
print(edo,'EDO interpretation')
if not sg:
if not sg:
sg = lim(ol)
sg = lim(max(ol,max(add)))
odds = [odd for odd in range(1,ol+1,2) if in_subgroup(odd,sg) and odd not in no] + add
odds = [odd for odd in range(1,ol+1,2) if in_subgroup(odd,sg) and odd not in no] + add
sedo = 0
sedo = 0
Line 1,316: Line 1,340:
# IMPORTANT: on Jan 9 i corrected rel_err**2 * et2 to rel_err**2 * et2**2 in et_badness which optimal_edo_sequence depends on;
# IMPORTANT: on Jan 9 i corrected rel_err**2 * et2 to rel_err**2 * et2**2 in et_badness which optimal_edo_sequence depends on;
#            strict_optimal_edo_sequence is unaffected however.
#            strict_optimal_edo_sequence is unaffected however.
def et_badness(ivs,v,badness=lambda rel_err,x,et2: rel_err**2 * et2**2,weighting=lambda x: iv_complexity(x),combine='avg',et2=0):
def et_badness(ivs,v,badness=lambda rel_err,x,et2: rel_err**2 * et2**2,weighting=lambda x: iv_complexity(x),combine='avg',mapping=True,et2=0):
# if the weighting is unspecified, use the default of:
# if the weighting is unspecified, use the default of:
# weighting an interval x's (by default squared) error contribution proportional to its odd-limit complexity (iv_complexity(x));
# weighting an interval x's (by default squared) error contribution proportional to its odd-limit complexity (iv_complexity(x));
Line 1,322: Line 1,346:
# and not underweighting simpler intervals and accounting for that more complex intervals will tend to be used
# and not underweighting simpler intervals and accounting for that more complex intervals will tend to be used
# in a harmonic/chordal context which justifies their otherwise-higher effective felt error through templating
# in a harmonic/chordal context which justifies their otherwise-higher effective felt error through templating
if weighting==1 or weighting in ['unweighted','trivial','basic']:
if type(weighting)==str:
weighting = lambda x: 1
if weighting in [None,'none','unweighted','trivial','basic','constant']:
elif weighting=='sensitive':
weighting = 0
weighting = lambda x: iv_complexity(x)**2
elif weighting in ['','default','proportional']:
weighting = 1
elif weighting in ['sensitive','dyadic']:
weighting = 2
elif weighting=='simple':
weighting = -0.5 # as we may square after when doing a MSE, we use the square root
if type(weighting) in [int,float]:
weighting = lambda x,w=weighting: iv_complexity(x)**w
global ivs_cache
global ivs_cache
global ivs_int_cache
global ivs_int_cache
Line 1,369: Line 1,400:
# alternatively, feed the real number of divisions of the octave that generates your val for each val you want to compare.   
# alternatively, feed the real number of divisions of the octave that generates your val for each val you want to compare.   
global patent_vals
global patent_vals
if type(v)==int:
if type(v)==int and v:
if v in patent_vals:
if v in patent_vals:
v = patent_vals[v]
v = patent_vals[v]
Line 1,377: Line 1,408:
elif type(v)==float:
elif type(v)==float:
v = val(lim(255),ed(v))
v = val(lim(255),ed(v))
elif not mapping and not v:
pass # not using a val
elif mapping and not v:
raise(Exception('mapping=True but no val v is given'))
# deduce the number of arguments in the badness function to allow only using the first n arguments as needed
# deduce the number of arguments in the badness function to allow only using the first n arguments as needed
num_args = badness.__code__.co_argcount
num_args = badness.__code__.co_argcount
Line 1,390: Line 1,425:
et2 = 1/v[0]
et2 = 1/v[0]
# finally, return the result:
# finally, return the result:
return combine([ badness3args(abs( map_iv(v,x) - steps(x,et2) ), x, et2) * weighting(x) for x in ivs ]) / (ivs_sum_weights_cache if using_avg else 1)
if not mapping: # new path
return combine([ badness3args(abs( step_err(x,et2) ), x, et2) * weighting(x) for x in ivs ]) / (ivs_sum_weights_cache if using_avg else 1)
else:
return combine([ badness3args(abs( map_iv(v,x) - steps(x,et2) ), x, et2) * weighting(x) for x in ivs ]) / (ivs_sum_weights_cache if using_avg else 1)
# if you just give a list or set of intervals (a,b), the default behaviour is to judge the badness of an edo as:
# if you just give a list or set of intervals (a,b), the default behaviour is to judge the badness of an edo as:
# * sum of squares of errors with each interval's contribution weighted proportional to its odd-limit complexity,
# * sum of squares of errors with each interval's contribution weighted proportional to its odd-limit complexity,
Line 1,397: Line 1,435:
# IMPORTANT: on Jan 9 i corrected rel_err**2 * et2 to rel_err**2 * et2**2 in et_badness which optimal_edo_sequence depends on;
# IMPORTANT: on Jan 9 i corrected rel_err**2 * et2 to rel_err**2 * et2**2 in et_badness which optimal_edo_sequence depends on;
#            strict_optimal_edo_sequence is unaffected however.
#            strict_optimal_edo_sequence is unaffected however.
def optimal_edo_sequence(ivs_or_edo_badness,edo_set=range(2,311+1),weighting=lambda x: iv_complexity(x),combine='avg'):
def optimal_edo_sequence(ivs_or_edo_badness,edo_set=range(2,311+1),weighting=lambda x: iv_complexity(x),combine='avg',mapping=True,times_better=1+2**-29):
et_badness_judger = ivs_or_edo_badness
et_badness_judger = ivs_or_edo_badness
if type(ivs_or_edo_badness) in [int,set,list]: # user gave intervals (default et_badness)
if type(ivs_or_edo_badness) in [int,set,list]: # user gave intervals (default et_badness)
ivs = ivs_or_edo_badness
ivs = ivs_or_edo_badness
et_badness_judger = lambda edo: et_badness(ivs,edo,weighting=weighting,combine=combine)
et_badness_judger = lambda edo: et_badness(ivs,edo,weighting=weighting,combine=combine,mapping=mapping)
# else user gave et_badness manually (custom)
# else user gave et_badness manually (custom)
best_edo = et_badness_judger(1)
best_edo = et_badness_judger(1)
Line 1,407: Line 1,445:
for edo in edo_set:
for edo in edo_set:
current = et_badness_judger(edo)
current = et_badness_judger(edo)
if current < best_edo:
if current < best_edo * times_better:
best_edo = current
best_edo = current
best_edos.append(edo)
best_edos.append(edo)
Line 1,415: Line 1,453:
# this gives much sparser but also much more interesting lists.
# this gives much sparser but also much more interesting lists.
# default weighting of an interval x is proportional to its odd-limit complexity iv_complexity(x).
# default weighting of an interval x is proportional to its odd-limit complexity iv_complexity(x).
def strict_optimal_edo_sequence(ivs,edo_set=range(2,311+1),weighting=lambda x: iv_complexity(x),combine='avg'):
def strict_optimal_edo_sequence(ivs,edo_set=range(2,311+1),weighting=lambda x: iv_complexity(x),combine='avg',mapping=True):
return optimal_edo_sequence(lambda edo: et_badness(ivs,edo,lambda rel_err: rel_err**2,weighting,combine),edo_set)
return optimal_edo_sequence(lambda edo: et_badness(ivs,edo,lambda rel_err: rel_err**2,weighting,combine,mapping),edo_set)


</syntaxhighlight>
# returns a set of odds in the subgroup that are sorted by their octave-reduced size
# which map to every distinct number of steps/degrees of the val given, therefore,
# dwarf(lim(p),N) is the set of odds for the dwarf scale of N EDO in the p-limit
def dwarf(sg,v):
if type(v)==int: # to be able to specify N for the patent val for N EDO
v = val( lim(max(sg)), ed(v) )
result = [0] * v[0] # implies you can have a tritave dwarf if sg and v agree on the subgroup
odd = 1
while 0 in result:
if in_subgroup(odd,sg) and result[ map_iv(v,(odd,1)) % v[0] ]==0:
result[ map_iv(v,(odd,1)) % v[0] ] = odd
odd += 2
return result


=== Important 23-limit EDOs ===
def scalestr(liststr):
Produced with the help of my above code and corrected with love. Below are theoretically important [[23-limit]] [[EDO]]s in that they do an increasingly better job at representing the [[27-odd-limit]] minus zero or one of composite odds 25 and 27. The exception is that if an EDO (such as 94) achieves less than 2 inconsistencies in the [[25-odd-limit]] or no-25's [[27-odd-limit]] then we don't consider a record to be set to give a chance to larger EDOs that are often interesting for having better approximations (of the intervals mentioned or of other intervals in higher limits). The logical stopping point is [[311edo]] due to its extreme efficiency and elegance as a [[23-limit]] and [[41-limit]] temperament (plus a handful of optional large primes). Please note that there may be one or two important 23-limit EDOs missing here, because I've only checked patent val and occasionally a non-patent-val will perform better for consistency, however, one can argue that a patent val representation should be a requirement for any serious 23-limit EDO.
commastrs = []
if ',' in liststr:
commastrs = [comma.strip() for comma in liststr.split(',')]
else:
commastrs = liststr.split()
return [iv( int(comma.split('/')[0]), int(comma.split('/')[1]) ) for comma in commastrs]


It should hopefully go without saying that by "serious 23-limit EDO" I mean in terms of archetypal and structural importance; to me it's obvious, with the exception of maybe EDOs 46 and 53 (corresponding to [[Eros]] (rank 3) and maybe also [[Amity]] (rank 2)), that any 23-limit EDO must have at least 77 notes, to allow for the fitting of a submajor third ([[21/17]] plus various higher-complexity submajor thirds), a superneutral third ([[16/13]]), a subneutral third ([[11/9]]) and a supraminor third (most notably [[17/14]] and [[23/19]]; equated in any "small" system) between 5/4 and 6/5, corresponding to splitting 25/24 into 5 equal parts. If you do this with one part equated to [[81/80]] you get [[absurdity]], explaining its non-absurdity and, to the contrary, ''intuitiveness'', as a [[29-limit]] temperament (given that prime 29 is essentially free for multiples of 7 EDO). If you instead choose to exaggerate 81/80 to 2 parts you get an extension of 5-limit [[artoneutral]] (I specify 5-limit as [[80edo]], one logical tuning for it, uses a different mapping for 7).
# find positive (possibly contorted) comma for a^n ~ b and by default print the result
def continuumpt(a,b,n,printcomma=1): # assumes n >= 0
comma = div_iv( (a[0]**n[0], a[1]**n[0]), (b[0]**n[1], b[1]**n[1]) )
if comma[0] < comma[1]:
comma = recip_iv(comma)
if printcomma==1:
return print(striv(comma))
elif printcomma>=2:
print('['+' '.join([ str(k) for k in fact(comma) ])+']',end='')
if printcomma==2:
return print()
elif printcomma==3:
return print(' = '+striv(comma))
else:
return comma
 
# note: the default can be used to get n octaves of an interval set (ivs) contained in the 1/1 to 2/1 range
def interleave(n,ivs,offset=(2,1)): # https://en.xen.wiki/w/Interleaving
totalivs = []
for i in range(n):
totalivs = totalivs + [mul_iv( *([x] + [offset]*i) ) for x in ivs if x not in totalivs]
totalivs.sort(key=lambda x: as_float(x))
return totalivs
 
 
def mediant_path(x):
x = convert(x,tuple)
x = iv(x[0], x[1])
bottom, middle, top = (0, 1), (1, 1), (1, 0)
result = ''
while x != middle:
if iv_less_than(x, middle):
result += 'D'
top = middle
else:
result += 'U'
bottom = middle
middle = (bottom[0] + top[0], bottom[1] + top[1])
return result
 
# the length of the mediant path of whichever octave-revoicing gives the interval x the least length
def mediant_complexity(x,revoicing_octs=7):
mincomplexity = 2**30
for octs in range(revoicing_octs+1):
mincomplexity = min(mincomplexity,len(mediant_path( div_iv(x,(2**octs,1)) )))
mincomplexity = min(mincomplexity,len(mediant_path( mul_iv(x,(2**octs,1)) )))
return mincomplexity
 
# showmode: minimum number of equated interval pairs (incl. distinct octave-complements).
# if minimum isnt reached, only the spacing interval is shown. 0 means dont print anything.
# for odd-limits, to look for "multiple indistinction commas", use 3 for showmode.
def spaces_in_set(ivs,max_cents = 100,showmode = 1):
spaces = dict()
if type(max_cents) in [tuple,float,int]:
max_cents = steps(max_cents,ed(1200))
for lower in ivs:
for upper in ivs:
diff = div_iv(upper,lower)
if 0 < steps(diff,ed(1200)) <= max_cents:
if diff not in spaces:
spaces[diff] = [(upper,lower)]
else:
spaces[diff].append((upper,lower))
commas = [comma for comma in spaces]
commas.sort(key=lambda x: steps(x,1))
if showmode:
for comma in commas:
print(striv(comma)+':',', '.join([
'('+striv(ivpair[0])+')/('+striv(ivpair[1])+')' for ivpair in spaces[comma]
if len(spaces[comma])>=showmode
]))
print()
return spaces
 
# there is only finitely many EDOs which provide some simplification of a set of intervals as contrasted to all-distinct
def efficient_edos( n, inconsistencies=0, min_simplifications=1, edos=range(1,1000) ):
if type(n)==int:
n = odd_lim(n)
elif type(n)==list and type(n[0])==int:
n = odd_lim(1,[],n)
results = []
for edo in edos:
v = edo
if type(v)==int:
v = val( lim(max([ prime_idx(len(fact(x))-1) for x in n ])), ed(edo) )
# else v is assumed to be a mapping
m = dict()
for x in n: # collect mappings of intervals
sedo = map_iv(v,x)
if sedo in m:
m[sedo].append(x)
else:
m[sedo] = [x]
if len(inconsistent_ivs_by_val(n,v)) <= inconsistencies:
if len(n) - len([ sedo for sedo in m ]) >= min_simplifications:
results.append(edo)
return results
</syntaxhighlight>
 
=== Important 23-limit EDOs ===
Produced with the help of my above code and corrected with love. Below are theoretically important [[23-limit]] [[EDO]]s in that they do an increasingly better job at representing the [[27-odd-limit]] minus zero or one of composite odds 25 and 27. The exception is that if an EDO (such as 94) achieves less than 2 inconsistencies in the [[25-odd-limit]] or no-25's [[27-odd-limit]] then we don't consider a record to be set to give a chance to larger EDOs that are often interesting for having better approximations (of the intervals mentioned or of other intervals in higher limits). The logical stopping point is [[311edo]] due to its extreme efficiency and elegance as a [[23-limit]] and [[41-limit]] temperament (plus a handful of optional large primes). Please note that there may be one or two important 23-limit EDOs missing here, because I've only checked patent val and occasionally a non-patent-val will perform better for consistency, however, one can argue that a patent val representation should be a requirement for any serious 23-limit EDO.
 
It should hopefully go without saying that by "serious 23-limit EDO" I mean in terms of archetypal and structural importance; to me it's obvious, with the exception of maybe EDOs 46 and 53 (corresponding to [[Eros]] (rank 3) and maybe also [[Amity]] (rank 2)), that any 23-limit EDO must have at least 77 notes, to allow for the fitting of a submajor third ([[21/17]] plus various higher-complexity submajor thirds), a superneutral third ([[16/13]]), a subneutral third ([[11/9]]) and a supraminor third (most notably [[17/14]] and [[23/19]]; equated in any "small" system) between 5/4 and 6/5, corresponding to splitting 25/24 into 5 equal parts. If you do this with one part equated to [[81/80]] you get [[absurdity]], explaining its non-absurdity and, to the contrary, ''intuitiveness'', as a [[29-limit]] temperament (given that prime 29 is essentially free for multiples of 7 EDO). If you instead choose to exaggerate 81/80 to 2 parts you get an extension of 5-limit [[artoneutral]] (I specify 5-limit as [[80edo]], one logical tuning for it, uses a different mapping for 7).


[[10edo]] gets 13 wrong in the no-25's 27-odd-limit (and 14 wrong in the 25-odd-limit (noticed the code produced a mistake here))
[[10edo]] gets 13 wrong in the no-25's 27-odd-limit (and 14 wrong in the 25-odd-limit (noticed the code produced a mistake here))
Line 1,477: Line 1,634:
[[311edo]] gets 0 wrong in the 27-odd-limit
[[311edo]] gets 0 wrong in the 27-odd-limit


== Novation Launchpad isomorphic keyboard code ==
== Novation Launchpad isomorphic keyboard code ==
The code and usage/debugging instructions are the same as for the Novation Launchpad Pro MK3, so see [[#Novation Launchpad Pro MK3 isomorphic keyboard code]].
The code and usage/debugging instructions are the same as for the Novation Launchpad Pro MK3, so see [[#Novation Launchpad Pro MK3 isomorphic keyboard code]].
 
 
Note that in theory, any Launchpad with programmer mode should work, so any MK3 model such as the Launchpad X and the cheaper (but not velocity-sensitive) mini version of that should work.
Note that any Launchpad with programmer mode should work, so any MK3 model such as the Launchpad X and the cheaper (but not velocity-sensitive) mini version of that should work. The Launchpad X has successfully been used as an isomorphic keyboard with this code, but currently requires manually specifying the MIDI ports; how to do this is explained below.
 
 
A launchpad X is potentially recommendable as having more comfortable/similar side/control buttons so that you get what feels more like a proper 9x9 grid (also due to being less costly), as the Pro MK3 has hard side-buttons that require significantly more pressure, though in both cases note that these buttons do not have pressure sensitivity so depend on the default velocity outputted by the program.
A launchpad X is potentially recommendable as having more comfortable/similar side/control buttons so that you get what feels more like a proper 9x9 grid (also due to being less costly), as the Pro MK3 has hard side-buttons that require significantly more pressure, though in both cases note that these buttons do not have pressure sensitivity so depend on the default velocity outputted by the program.
 
(More generally, Launchpads are '''''very''''' affordable xen MIDI instruments, nearly optimal for xen in that (with the help of the code below) they provide a fully customisable isomorphic MIDI keyboard with custom highlighting options. Also note that the tuning itself is not specified by the program; only the layout, though for the aforementioned large tunings the code will give you a .scl file to use, with all such .scl files using the same MIDI mapping, but requiring the base MIDI note/reference being 0.)
 
== Novation Launchpad Pro MK3 isomorphic keyboard code ==
This code is licensed under the AGPLv3 (https://www.gnu.org/licenses/agpl-3.0.html), a version of the [[wikipedia:Affero General Public License|AGPL]] corresponding to the [[wikipedia:GNU General Public License#Version 3|GPLv3]].
 
'''It should be compatible with any Launchpad that has [[#Putting the Launchpad in programmer mode|programmer mode]]; it has been confirmed to work for the Launchpad X so will likely also work for a Launchpad Mini MK3.'''
 
ALSO: This should go without saying but take care of your launchpad! If you wipe it don't expect it to be properly responsive until fully dry and even then wiping it can have risks if the liquid goes inside. Similarly, do not bang it and probably don't leave it upside down (especially if for long periods of time) in case it causes the velocity sensitivity to go weird. Treat it as an instrument. If you do all this, it should be fine to use it for its intended purpose: just don't press ''too'' hard; try not press with more velocity than the buttons actually require, if possible. (Because of my silliness (not heeding such obvious procedures) there is a possibility that I may have weared my launchpad slightly in that I think I now require more pressure for the pressure-sensitive pads. I thought it responsible to add this note about taking care of your launchpad, as we are technically using it in a nonstandard way by treating the buttons as though they were just insensitive pads that require extra velocity/pressure.)
 
IMPORTANT: for the Python 3 code to work, it requires the launchpad to be plugged in with updated firmware and be in [[#Putting the Launchpad in programmer mode|programmer mode]]! Also requires [https://www.tobias-erichsen.de/software/loopmidi.html loopMIDI] on Windows.
 
=== Installation issues/troubleshooting strategies/recommendations ===
The most potentially difficult part is that depending on what OS you are using, how you have Python installed, what version, etc. there can be complications so that running <code>pip install rtmidi</code> and <code>pip install mido</code> in a terminal does not work, or only appears to work so that there's issues when the code tries to use mido. I list potential issues below, so please read carefully for something applicable to your case if it isn't going smoothly.
 
'''IMPORTANT: A strange error has been found: Python 3.14 and later versions have removed a functionality used by mido internally, so downgrading to Python 3.12 is required if nothing here works.'''
 
'''IMPORTANT:''' Before deeming an installation of mido/rtmidi to "not be working", make sure that the issue is not just one of what MIDI ports are being autoselected; see (6.) onwards for details.
 
0. Technically not an issue with rtmidi, but an easy one to solve: you forgot to update the firmware of your launchpad to be up-to-date via the official site: https://components.novationmusic.com/
 
1. The easiest issue is if you have a version of Python 2 installed (regardless of whether you have Python 3 installed), then sometimes <code>pip</code> and <code>python</code> refer to Python 2, so use <code>pip3</code> and <code>python3</code> instead wherever applicable. Alternatively, if you don't need Python 2, uninstalling it may help.
 
2. If you installed Python 3 but it doesn't work on command line, maybe you haven't used an official installer, as that usually shouldn't be an issue, or if you did use an official installer, you may not have marked the checkbox that makes it change PATH environment variables for you automatically, in which case adding the location of the Python 3 (and potentially pip) executables should fix it.
 
3. <code>rtmidi</code> doesn't seem to exist when trying to install it; try installing <code>python-rtmidi</code> instead.
 
3.1. <code>rtmidi</code> seems to install but there's issues when trying to use it; installing <code>python-rtmidi</code> may help in such a case; if that still doesn't help, try uninstalling rtmidi (<code>pip uninstall rtmidi</code>) and following the instructions of (7.1.). {{nowrap| (As a note of my experience: }} in the code, as a comment, I have <code>pip install mido && pip install python-rtmidi</code> (with a note about the loopMIDI requirement on Windows) as the default/simplest installation goal/recommendation, present at the beginning of the code where I <code>import mido</code>, because lately it seems that's the most reliable, however some systems may need <code>rtmidi</code> instead of <code>python-rtmidi</code> or may need both; I'm not sure what the most common case is.)
 
4. If you are getting a long error where towards the end there is <code>error: Microsoft Visual C++ 14.0 or greater is required.</code> (which might happen if you are using an older version of Windows) then try <code>pip install --only-binary :all: rtmidi</code> which will save you a huge amount of trouble if it works. Versions apparently should be available for almost every relevant version of Python 3, so if it isn't, try a different version of Python 3 if you know how. If your system doesn't use Python 3 and you installed it, it should definitely be safe to uninstall the current version.
 
4.1. I haven't seen this issue, but possibly if <code>pip install --only-binary :all: rtmidi</code> seems to work but then brings an error when trying to use the code, try <code>pip install --only-binary :all: python-rtmidi</code> in case it helps.
 
5. If you are on Windows, make sure you have [https://www.tobias-erichsen.de/software/loopmidi.html loopMIDI] installed and running with the default port name! (The default name should work; the code searches for the first name starting with "loop".) Though it hasn't been observed, if loopMIDI itself doesn't seem to be working, check that it's not a firewall issue.
 
6. '''If after all these remedies it doesn't work,''' then it's likely because the attempt at autoselecting the name of the MIDI input and MIDI output failed. To fix this:
 
6.0. A trivial but easy to forget fix: make sure that the USB you're using isn't faulty by trying a different USB that you can confirm works/isn't faulty.
 
6.1. First check that the Launchpad, ''after being set into programmer mode'' (see [[#Putting the Launchpad in programmer mode]]), is responsive, by using it as a MIDI input on [[Scale Workshop]] and checking if one of the Launchpad-related options makes Scale Workshop clearly press/release notes based on what you are pressing/releasing (so not as a mess of vaguely correlated noisy data, but as obviously directly responding to you touching the Launchpad). If this doesn't work (no [[#Success indicators]]), see (step 0.) and try restarting your computer (which is much more likely to be a relevant fix if you are using Windows).
 
6.2. Look at the output of running <code>iso()</code>; specifically, it'll tell you <code>midi outputs detected:</code> followed by a list of the ''text strings'' that correspond to valid MIDI outputs detected (here meaning valid devices/targets which the code can ''output''/''send'' MIDI data to); so you want to find the one that corresponds to telling the Launchpad how to light up, EG {{nowrap| <code>iso(midi_out_col{{=}}'MIDIOUT2 (LPX MIDI) 2')</code> }} if you saw {{nowrap| <code>MIDIOUT2 (LPX MIDI) 2</code> }} in the list.  If this is the only fix that was needed, you should see all [[#Success indicators]].
 
6.3. '''If this did not fix it,''' you should get a new error with new information to help you; you should see <code>midi_inputs_detected:</code> followed by a list of the ''text strings'' that correspond to valid MIDI inputs (here meaning valid devices/targets that the code can ''input''/''read'' MIDI data from); so you want to find the one that corresponds to receiving the data about what pads and buttons are pressed on the Launchpad, EG {{nowrap| <code>iso(midi_out_col{{=}}'MIDIOUT2 (LPX MIDI) 2',midi_input{{=}}'MIDIIN2 (LPX MIDI) 1')</code> }} if you saw {{nowrap| <code>MIDIIN2 (LPX MIDI) 1</code> }} in the list, where note we need to keep the {{nowrap| <code>midi_out_col=...</code> }} part so that we don't go back to failing at the first error. Again, if this was the last fix that was needed, you should see all [[#Success indicators]]. If you ''still'' can't get it working, see the final remedies below:
 
7. '''Final remedies''' (mainly for Windows being janky):
 
7.1. Try uninstalling and reinstalling <code>mido</code> and <code>python-rtmidi</code> with <code>pip</code> (or if on your system that corresponds to Python 2 rather than Python 3, then with <code>pip3</code> instead):
<pre>
pip uninstall python-rtmidi
pip uninstall mido
pip install mido
pip install python-rtmidi
</pre>
 
7.2. Restart the system (this is especially likely to fix things if you use Windows). (Possibly followed by uninstalling and reinstalling if that didn't fix it or fix something at least.)
 
7.3. Try installing (or if you did that, uninstalling and reinstalling) <code>rtmidi</code> in case it helps (note the distinctness from <code>python-rtmidi</code>). I vaguely recall this being a valid installation target in some cases. However, if installing <code>rtmidi</code> is valid (it installs) but it doesn't help, uninstall it and then uninstall and reinstall <code>python-rtmidi</code> and <code>mido</code> as shown in (7.1) above.
 
'''Mix and match these solutions as you find them potentially relevant to your situation, and hopefully you should be able to get it working.''' Also, remember, the order of doing these can matter; for example, if the installation is subtly bugged for whatever incomprehensible reason, then that'll invalidate all the other steps you took so you'll have to do them again with a non-bugged installation.
 
Feel free to send me a friend request to ask me for help on Discord (<code>@osmiumic</code>).
 
==== Putting the Launchpad in programmer mode ====
'''Launchpad X''': Once plugged in by USB and on, "hold Session, then press bottom Scene Launch button" (which I think should be orange?); the pads may flash to display a running text saying "Program" for confirmation. Once successfully put in programmer mode, the Launchpad should become unlit and appear unresponsive. '''This means it worked.''' To get it out of programmer mode and into the default mode, simply unplug it and plug it in again.


(More generally, Launchpads are '''''very''''' affordable xen MIDI instruments, nearly optimal for xen in that (with the help of the code below) they provide a fully customisable isomorphic MIDI keyboard with custom highlighting options. Also note that the tuning itself is not specified by the program; only the layout, though for the aforementioned large tunings the code will give you a .scl file to use, with all such .scl files using the same MIDI mapping, but requiring the base MIDI note/reference being 0.)
'''Launchpad Pro MK3:''' Once plugged in by USB and on, hold the small "Setup" button (bottom left) and press and release the "Print to Clip" button (bottom right). The Launchpad should become unlit and appear unresponsive. '''This means it worked.''' To get it out of programmer mode and into the default mode, simply unplug it and plug it in again.


== Novation Launchpad Pro MK3 isomorphic keyboard code ==
==== Success indicators ====
This code is licensed under the AGPLv3 (https://www.gnu.org/licenses/agpl-3.0.html), a version of the [[wikipedia:Affero General Public License|AGPL]] corresponding to the [[wikipedia:GNU General Public License#Version 3|GPLv3]].
If your fixes worked, then assuming you didn't specify a colouring so that you didn't specify anything other than running either <code>iso()</code>, <code>iso(midi_out_col='...')</code> or <code>iso(midi_out_col='...',midi_input='...')</code>, the launchpad should turn fully cyan. Then, assuming the call to <code>iso(...)</code> is currently running in your terminal/console, you should be able to see MIDI data being printed to the terminal/console whenever you press and release a pad or button on your Launchpad. As a result, and assuming that if on Windows you set up loopMIDI correctly and that it's running, you should be able to select the appropriate instance of RtMidi or loopMIDI as a MIDI input in Scale Workshop and play whatever scale you have loaded via the Launchpad. ''Remember to allow the website MIDI permissions first before looking at its list of MIDI inputs, as there can be a small (few seconds) latency for it to update the list of detected MIDI inputs, and that list may not update unless you close the browser and open it again to hard-refresh the page.''
 
'''It should be compatible with any Launchpad that has programmer mode; it has been confirmed to work for the Launchpad X so will likely also work for a Launchpad Mini MK3.'''
 
NOTE: I discovered it was possible to use custom colour palettes after I'd spent a lot of time making these rainbows using the rather limited and uneven set of factory colours. I haven't tested using this yet, but for those who want to take that route to achieve a more even rainbow, here is the link: https://fw.mat1jaczyyy.com/
 
ALSO: This should go without saying but take care of your launchpad! If you wipe it don't expect it to be properly responsive until fully dry and even then wiping it can have risks if the liquid goes inside. Similarly, do not bang it and probably don't leave it upside down (especially if for long periods of time) in case it causes the velocity sensitivity to go weird. Treat it as an instrument. If you do all this, it should be fine to use it for its intended purpose: just don't press ''too'' hard; try not press with more velocity than the buttons actually require, if possible. (Because of my silliness (not heeding such obvious procedures) there is a possibility that I may have weared my launchpad slightly in that I think I now require more pressure for the pressure-sensitive pads. I thought it responsible to add this note about taking care of your launchpad, as we are technically using it in a nonstandard way by treating the buttons as though they were just insensitive pads that require extra velocity/pressure.)
 
IMPORTANT: for the Python 3 code to work, it requires the launchpad to be plugged in with updated firmware and be in programmer mode! Also requires loopMIDI on Windows.
 
=== Installation issues/troubleshooting strategies/recommendations: ===
The most potentially difficult part is that depending on what OS you are using, how you have Python installed, what version, etc. there can be complications so that running <code>pip install rtmidi</code> in a terminal does not work. I list potential issues below, so please read carefully for something applicable to your case if it isn't going smoothly.
 
0. Technically not an issue with rtmidi, but an easy one to solve: you forgot to update the firmware of your launchpad to be up-to-date via the official site: https://components.novationmusic.com/
 
1. The easiest issue is if you have a version of Python 2 installed (regardless of whether you have Python 3 installed), then sometimes <code>pip</code> and <code>python</code> refer to Python 2, so use <code>pip3</code> and <code>python3</code> instead wherever applicable. Alternatively, if you don't need Python 2, uninstalling it may help.
 
2. If you installed Python 3 but it doesn't work on command line, maybe you haven't used an official installer, as that usually shouldn't be an issue, or if you did use an official installer, you may not have marked the checkbox that makes it change PATH environment variables for you automatically, in which case adding the location of the Python 3 (and potentially pip) executables should fix it.
 
3. <code>rtmidi</code> seems to install but there's issues when trying to use it; installing <code>python-rtmidi</code> may help in such a case. That's why I have "pip install mido && pip install python-rtmidi" with a note about the loopMIDI requirement on Windows as the default/simplest installation recommendation present at the beginning of the code where I <code>import mido</code>.
 
4. If you are getting a long error where towards the end there is <code>error: Microsoft Visual C++ 14.0 or greater is required.</code> (which might happen if you are using an older version of Windows) then try <code>pip install --only-binary :all: rtmidi</code> which will save you a huge amount of trouble if it works. Versions apparently should be available for almost every relevant version of Python 3, so if it isn't, try a different version of Python 3 if you know how. If your system doesn't use Python 3 and you installed it, it should definitely be safe to uninstall the current version.
 
4.1. I haven't seen this issue, but possibly if <code>pip install --only-binary :all: rtmidi</code> seems to work but then brings an error when trying to use the code, try <code>pip install --only-binary :all: python-rtmidi</code> in case it helps.
 
5. If you are on Windows, make sure you have [https://www.tobias-erichsen.de/software/loopmidi.html loopMIDI] installed and running with the default port name! (The default name should work; the code searches for a name starting with "loop".)
 
'''Mix and match these solutions as you find them potentially relevant to your situation, and hopefully you should be able to get it working.'''
 
Feel free to send me a friend request to ask me for help on Discord (<code>@osmiumic</code>).


=== Isomorphic keyboard code for launchpads with programmer mode ===
=== Isomorphic keyboard code for launchpads with programmer mode ===
Line 1,801: Line 1,994:
if j!=0 or i!=0: # equiv. if (i,j) != (0,0) (i think)
if j!=0 or i!=0: # equiv. if (i,j) != (0,0) (i think)
steps = i*x - i//every_x*x_reducer + j*y - j//every_y*y_reducer
steps = i*x - i//every_x*x_reducer + j*y - j//every_y*y_reducer
print( str(steps)+'\\'+str(edo) if args.get('backslash') or args.get('backslashes') else int(.5 + 10000 * steps/edo*1200)/10000 )
print( str(steps)+'\\'+str(edo) if args.get('backslash') or args.get('backslashes') else int(.5 + 1000**2 * steps/edo*1200)/1000**2 )
print()
print()
# for the launchpad pro MK3 specifically:
# for the launchpad pro MK3 specifically: