Godtone
Joined 17 December 2020
m →Installation issues/troubleshooting strategies/recommendations: note potential firewall issue |
m →zeta and optimal_edo_sequence: more data |
||
| (22 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 | * 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 459: | Line 466: | ||
== My Python 3 code == | == My Python 3 code == | ||
IMPORTANT NOTE: there seems to be | 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 599: | 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,326: | 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== | if type(weighting)==str: | ||
weighting = | if weighting in [None,'none','unweighted','trivial','basic','constant']: | ||
weighting = 0 | |||
elif weighting in ['','default','proportional']: | |||
weighting = 1 | |||
weighting = lambda x: iv_complexity(x)** | 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,410: | 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',mapping=True): | 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) | ||
| Line 1,420: | 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,430: | Line 1,455: | ||
def strict_optimal_edo_sequence(ivs,edo_set=range(2,311+1),weighting=lambda x: iv_complexity(x),combine='avg',mapping=True): | 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,mapping),edo_set) | return optimal_edo_sequence(lambda edo: et_badness(ivs,edo,lambda rel_err: rel_err**2,weighting,combine,mapping),edo_set) | ||
# 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 | |||
def scalestr(liststr): | def scalestr(liststr): | ||
| Line 1,463: | Line 1,502: | ||
return totalivs | 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> | </syntaxhighlight> | ||
| Line 1,525: | Line 1,637: | ||
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 | 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. | ||
| Line 1,534: | Line 1,646: | ||
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]]. | 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 programmer mode; it has been confirmed to work for the Launchpad X so will likely also work for a Launchpad Mini MK3.''' | '''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.) | 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. | 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 === | === 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. | 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/ | 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/ | ||
| Line 1,551: | Line 1,665: | ||
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. | 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. | 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. 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. | ||
| Line 1,571: | Line 1,687: | ||
7. '''Final remedies''' (mainly for Windows being janky): | 7. '''Final remedies''' (mainly for Windows being janky): | ||
7.1. Try uninstalling and reinstalling <code> | 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> | <pre> | ||
pip uninstall python-rtmidi | pip uninstall python-rtmidi | ||
| Line 1,878: | 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 + | 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: | ||