g/l💖a:~/xenedoji🌈 cat readme
Xenedoji
Xenedoji's simplicity picks up where standard tuning's simplicity falls short.
- Explore various tunings with just a few lines of code
- Interface with midi devices and transform a button grid instrument such as a Mystrix, UNTZstrument, LinnStrument, Monome, or Launchpad into a microtonal synth
- Turn a standard Halberstadt piano keyboard or qwerty keyboard into a microtonal midi instrument
- Adapt affordable human interface devices to substitute for expensive midi devices
- Work efficiently with rational and irrational frequency ratios and easily get them to sound on a synth quickly with minimal code
- Translate between frequency ratios, cents, and edos
Why?
12edo (standard tuning) cannot accurately match the harmonics. It is also just one of other edos. MIDI is easy to use in 12edo and difficult to get other notes from other tunings. The purpose of xenedoji is to make the harmonic series and other tunings easy to explore.
Download
License
GNU General Public License v3
Getting sound
- Download Surge synth. It is FLO software licensed under GNU General Public License. This means that it respects your Human Tech Rights.
- If you are using GNU/Linux, the greatest operating system of all time, start the jack server and make sure Surge is using jack instead of ALSA. This is found under Options > Audio/MIDI Settings...
- Make sure you select the MPE box under "Status"
- Open a shell. Change directory (cd) to the folder where xenedoji is downloaded and unzipped. Run python3 to open the interactive shell. Then from literals import *.
~🌈 cd path/to/xenedoji
~/path/to/xenedoji🌈 python3
>>> from literals import *
- This will create a midi port called xenedoji. Make sure it is selected in Surge under Options > Audio/MIDI Settings... > Active MIDI inputs. Note that when closing and opening a midi port with the same name, you have to uncheck and recheck the box for it to work. This will happen any time you close a program using this port and then reopen the program. It's confusing because the port appears to be active because it has a check in the checkbox.
- go back to the shell and run
>>> play([4/4], [5/4], [6/4])
Hearing triads from the smallest harmonic numbers and primes
A major triad is found in the harmonic series from harmonics 4:5:6. A minor triad is found in the harmonic series from harmonics 10:12:15.
>>> play([4/4, 5/4, 6/4]) # simple major melody
>>> play([4/4], [5/4], [6/4]) # harmony
>>> play([10/8, 12/8, 15/8]) # simple minor melody
>>> play([10/8], [12/8], [15/8]) # harmony
These two chords are complements of each other. This means they are flipped. A chord can be made with xf(). This reads a string and interprets it. Then we can take the reciprocal of each note with **-1. Finally to get this subharmonic chord back into the context of harmonics, run the .colon() method for colon notation.
>>> xf('4:5:6')
Chord[4:5:6]
>>> _**-1
Chord[1/6, 1/5, 1/4]
>>> _.colon()
Chord[10:12:15]
Melody vs harmony
play([5/4, 4/4]) will play these two notes melodically. This means that 5/4 and 4/4 will not be played at the same time. Use two voices to play them both at the same time harmonically. This is done with two lists.
>>> play([5/4, 4/4]) # 2 note melody with one voice
>>> play(
[5/4],
[4/4],
) # 2 voice harmony
Compare this with 12edo's approximation. To play backslash (\) ratios of 12edo, start a number with "x." x0 through x1024 are variables defined as literals. This allows us to work with rational ratios and use "//" as a backslash operator.
>>> 3/2 # normal python
1.5
>>> 1/3 # normal python
0.3333333333333333
>>> x3/2 # rational ratio
3/2
>>> x1/3 # rational ratio
1/3
>>> x4//12 # // for backslash
400c
>>> play([x4//12], [x0//12]) # 12edo 2 note melody
>>> play(
[x4//12],
[x0//12],
) # 12edo 2 voice harmony
Play the harmonic series
>>> play([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
>>> play([1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16])
>>> play([1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14], [15])
Octave complement
The octave complement of 5/4 (vM3) is 8/5 (^m6).
>>> (x5/4 / 2)**-1 # vM3
8/5
>>> (x8/5 / 2)**-1 # ^m6
5/4
5th complement
The 5th complement of 5/4 (vM3) is 6/5 (^m3).
>>> (x5/4 * 2/3)**-1 # vM3
6/5
>>> (x6/5 * 2/3)**-1 # ^m3
5/4
The thirds of 41edo
12edo has 2 flavors of 3rds. These are Major and minor. 41edo has 7 flavors of 3rds. These flavors are vm3, m3, ^m3, ~3, vM3, M3, ^M3. Each of these goes with the prime numbers 7, 3, 5, and 11. When 7 is the highest prime in the denominator for 9/7 = ^M3, taking the 5th complement will put 7 in the numerator for 7/6 = vm3. You can see each of the 5th complements below. The 5th complement of 11/9 is 27/22. Both of these map on to 12\41. 12\41 functions as both 11/9 and 27/22. This is because 3/2 maps on to 24\41 and 24 - 12 = 12. 12\41 is a ~3 or neutral 3rd. It is in between Major and minor. The difference between 11/9 and 27/22 is tempered out in 41edo. To find the difference between the two, take 27/22 divided by 11/9 = 243/242. This is only 7.14 cents and one edostep of 41 (1\41) is 29.27 cents.
>>> (x7/6 * 2/3)**-1
9/7
>>> (x32/27 * 2/3)**-1
81/64
>>> (x6/5 * 2/3)**-1
5/4
>>> (x11/9 * 2/3)**-1 # both are 12\41
27/22
>>> x27/22 / (x11/9)
243/242
>>> to_cents(_)
7.14c
>>> to_cents(x1//41) # 1\41
29.27c
Play 94edo intervals
>>> play(
[vM3],
[P1],
)
>>> play(
[M3],
[P1],
)
Play cents
>>> play(
[386*c],
[ 0*c],
)
>>> play(
[400*c],
[ 0*c],
)
Convert to cents
- How many cents is 3/2?
- How many cents is 7 half-steps of 12edo?
- What about powers of 2?
- How many cents is 5/4?
- How many cents is 7/4?
- How many cents is 11/8?
>>> to_cents(3/2)
702c
>>> to_cents(x7//12)
700c
>>> to_cents(2**(7/12))
700c
>>> to_cents(5/4)
386.31c
>>> to_cents(7/4)
968.83c
>>> to_cents(11/8)
551.32c
Use Hertz and mix with edos
>>> 440*Hz * 3/2
660 Hz
>>> 440*Hz + x7//12
659.26 Hz
>>> 440*Hz + x24//41
660.18 Hz
>>> 440*Hz + x31//53
659.97 Hz
>>> 440*Hz + x55//94
660.07 Hz
Some scores
>>> play(
[1/1, 9/8, 5/4, 4/3, 3/2, 4/3, 5/4, 9/8, 1/1],
[5/8, 3/4, 1/1, 10/9, 5/4, 10/9, 1/1, 3/4, 5/8],
)
>>> play(
[9/4, 9/4 , 81/35],
[2/1, 27/14, 72/35],
[3/2, 45/28, 54/35],
[5/4, 9/7 , 9/7 ],
)
>>> play(
[3/2, 5/3, 5/3, 3/2 , 5/4, 4/3, 4/3, 40/27, 40/27],
[5/4, 5/4, 4/3, 9/8 , 1/1, 1/1, 10/9, 10/9 , 100/81],
[1/1, 1/1, 1/1, 15/16, 5/6, 5/6, 5/6, 25/27, 80/81],
)
>>> play(
[ 40/27, 40/27, 4/3, 4/3, 5/4, 3/2 , 5/3, 5/3, 3/2],
[100/81, 10/9 , 10/9, 1/1, 1/1, 9/8 , 4/3, 5/4, 5/4],
[ 80/81, 25/27, 5/6, 5/6, 5/6, 15/16, 1/1, 1/1, 1/1],
)
>>> play(
[ 40/27, 40/27, 4/3, 3/2, 3/2, 3/2 , 5/3, 5/3 , 3/2],
[100/81, 35/27, 10/9, 4/3, 5/4, 21/16, 4/3, 5/4 , 5/4],
[ 10/9 , 10/9 , 1/1, 1/1, 1/1, 9/8 , 5/4, 1/1 , 9/8],
[ 80/81, 25/27, 5/6, 5/6, 5/6, 15/16, 1/1, 15/16, 1/1],
)
>>> play(
[160/81, 50/27, 5/3, 5/3, 5/3, 15/8 , 2/1, 15/8 , 2/1],
[ 40/27, 40/27, 4/3, 3/2, 3/2, 3/2 , 5/3, 25/16, 3/2],
[100/81, 35/27, 10/9, 4/3, 5/4, 21/16, 4/3, 5/4 , 5/4],
[ 10/9 , 10/9 , 1/1, 1/1, 1/1, 9/8 , 5/4, 1/1 , 9/8],
)
>>> play(
[1/1, 9/8, 5/4, 4/3, 3/2, 4/3, 5/4, 9/8, 1/1],
[5/8, 3/4, 1/1, 10/9, 5/4, 10/9, 1/1, 3/4, 5/8],
)
>>> play(
[ 5/2, 5/2 , 9/4],
[ 2/1, 15/8 , 15/8],
[ 4/3, 21/16, 5/4],
[10/9, 3/4 , 1/1],
) # vII^m9 Vv9/5 IvM9
>>> play(
[ 9/4, 5/2 , 81/32],
[15/8, 15/8 , 81/40],
[ 5/4, 21/16, 27/20],
[ 1/1, 3/4 , 9/8 ],
)
>>> play(
[81/32, 5/2 , 9/4],
[81/40, 15/8 , 15/8],
[27/20, 21/16, 5/4],
[ 9/8 , 3/4 , 1/1],
) # II^m9 Vv9/5 IvM9
>>> play(
[5/4, 6/5, 5/4, 6/5, 6/5 ],
[1/1, 1/1, 1/1, 1/1, 24/25],
[3/4, 4/5, 3/4, 4/5, 18/25],
)
>>> play(
[9/4, 12/5 , 81/35, 9/4, 27/10],
[9/5, 9/5 , 9/5 , 15/8, 12/5 ],
[3/2, 36/25, 54/35, 1/1, 9/4 ],
[6/5, 6/5 , 9/7 , 5/4, 9/5 ],
[1/1, 24/25, 36/35, 1/1, 3/4 ],
)
>>> play(
[15/8, 9/5, 7/4, 9/5, 15/8, 27/14, 2/1, 9/4 ],
[ 3/2, 3/2, 3/2, 3/2, 3/2, 3/2 , 3/2, 3/2 ],
[ 9/8, 6/5, 5/4, 6/5, 9/8, 15/14, 1/1, 15/16],
[ 3/4, 3/5, 1/2, 3/5, 3/4, 3/7 , 5/8, 3/8 ],
)