#! /usr/bin/env python3

# -*- coding: utf-8 -*-

"""

Copyright 2022 , Nils Hilbricht , Germany ( https : / / www . hilbricht . net )

```
```

This file is part of the Laborejo Software Suite ( https : / / www . laborejo . org ) ,

```
```

This application is free software : you can redistribute it and / or modify

it under the terms of the GNU General Public License as published by

the Free Software Foundation , either version 3 of the License , or

( at your option ) any later version .

```
```

This program is distributed in the hope that it will be useful ,

but WITHOUT ANY WARRANTY ; without even the implied warranty of

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the

GNU General Public License for more details .

```
```

You should have received a copy of the GNU General Public License

along with this program . If not , see < http : / / www . gnu . org / licenses / > .

"""

```
```

"""

This file handles various pitches and their conversions .

"""

```
```

```
```

import logging ; logger = logging . getLogger ( __name__ ) ; logger . info ( " import " )

```
```

#Standard Library

from collections import defaultdict

from typing import Dict , Tuple , List , DefaultDict

```
```

#Third Party Modules

#Template Modules

#Our modules

```
```

class KeySignature ( object ) :

` `""" For tests and typechecking. The real one is in Laborejo/engine/items.py """

` `def __init__ ( self , root , deviationFromMajorScale ) :

` `self . root : int = root

` `self . deviationFromMajorScale : List = deviationFromMajorScale

` `self . keysigList : tuple = tuple ( )

```
```

#Constants

OCTAVE = 350

STEP = 50

MAX = 3140

MIN = 0

```
```

#Without a keysignature

def plain ( pitch : int ) - > int :

` `""" Extract the note from a note-number, without any octave but with the tailing zero.

` `This means we double - use the lowest octave as abstract version . """

` `#Dividing through the octave, 350, results in the number of the octave and the note as remainder.

` `return divmod ( pitch , 350 ) [ 1 ]

```
```

def octave ( pitch : int ) - > int :

` `""" Return the octave of given note. Lowest 0 is X,,, """

` `return divmod ( pitch , 350 ) [ 0 ]

```
```

def toOctave ( pitch : int , octave : int ) - > int :

` `""" Take a plain note and give the octave variant. Starts with 0 """

` `return pitch + octave * 350

```
```

def mirror ( pitch : int , axis : int ) - > int :

` `""" Calculate the distance between the pitch and the axis-pitch and

` `set the new pitch twice as far , which creates a mirror effect :

` `Half the distancen is object - > mirror and then mirror - > object on the

` `other side again . """

` `#1420 = c', 1520 = e', 1620 = g'

```
```

` `#1420 to 1520 is a third so the mirror would be a fifth.

` `#1420 + 2 * (1520 - 1420)

` `#1420 + 2 * 100

` `#1420 + 200 = 1620

` `return pitch + 2 * ( axis - pitch )

```
```

def diatonicIndex ( pitch : int ) - > int :

` `""" Return an int between 0 and 6, resembling the diatonic position

` `of the given pitch without octave , accidentals . 0 is c """

` `return divmod ( plain ( toWhite [ pitch ] ) , 50 ) [ 0 ]

```
```

def absoluteDiatonicIndex ( pitch : int ) - > int :

` `""" Like diatonicIndex but works from pitch 20 which gets index 0

` `middle c is 28

` `tuning a is 33

` `these two are indeed 5 steps apart

` `( not traditional interval steps , real step counting from 1 ) """

` `return divmod ( toWhite [ pitch ] , 50 ) [ 0 ]

```
```

def distanceInDiatonicSteps ( first : int , second : int ) - > int :

` `""" root is a pitch like 1720. Pitch as well

` `Returns not a signed int . If the first is lower than the second

` `you get a negative return value . """

` `return absoluteDiatonicIndex ( first ) - absoluteDiatonicIndex ( second )

```
```

def diatonicIndexToPitch ( index : int , octave : int ) - > int :

` `""" supports indices from - to +. """

` `while index < 0 :

` `index + = 7 #plus one octave. index -1 becomes b

` `octave - = 1

` `while index > 6 :

` `index - = 7 #minus one octave. index 7 becomes c again.

` `octave + = 1

` `return toOctave ( index * 50 + 20 , octave ) #0 is cesces, 20 is c

```
```

def upStepsFromRoot ( root : int , pitch : int ) - > int :

` `""" Like diatonicIndex but assumes a different root than C. So it is:

` `' stepcount upward in white keys from root to pitch ' .

` `It is always assumed it should go up .

` `Also it will never report anything over an octave since it

` `uses diatonicIndex ( ) """

` `assert root < = pitch

` `if root == pitch :

` `return 0

` `else :

` `r = diatonicIndex ( root )

` `p = diatonicIndex ( pitch )

` `if plain ( root ) > plain ( pitch ) : #we have an octave break g' to d''

` `p + = 7

` `return p - r

```
```

def fromMidi ( midipitch : int , keysig : KeySignature ) - > int :

` `""" Convert a midi pitch to internal pitch.

` `Nearest to pillar of fifth """

` `if ( midipitch , keysig ) in cache_fromMidi :

` `return cache_fromMidi [ ( midipitch , keysig ) ]

` `else :

` `midioctave , pitch = divmod ( midipitch , 12 )

` `table = [

` `20 , #c

` `60 , #des

` `70 , #d

` `110 , #ees

` `120 , #e

` `170 , #f

` `180 , #fis

` `220 , #g

` `260 , #aas

` `270 , #a

` `310 , #bes

` `320 , #b / h

` `]

```
```

` `#Sample note Gis/Aes in D Major should become Gis, which is the same as Fis in C Maj.

` `midiRoot = toMidi [ keysig . root ] - 12 #in D Major thats 2 (halftone steps away from C)

` `simpleConverted = toOctave ( table [ pitch ] , midioctave - 1 ) #in D Maj it is still Aes

` `fromC = halfToneDistanceFromC ( simpleConverted )

` `soundingDistanceToKeysigRoot = fromC - midiRoot #8 half tone steps - 2 from root = 6 (Tritonus)

` `#We now need to know how the 6 steps / tritonus look like in the current keysignature/root enviroment. This is told by the table above.

` `pitchInCMaj = table [ soundingDistanceToKeysigRoot ] #fis

```
```

` `#Interval between keysig root and c.

` `plainInterval , intervalOctaveOffset = interval ( 20 , keysig . root )

` `newInterval = ( plainInterval , midioctave - 1 ) #tuplets are immutable

```
```

` `#Transpose it by this interval

` `pitchInOriginalKey = intervalUp ( pitchInCMaj , newInterval , midiIn = True )

```
```

` `#Back to the correct Octave. This is what we wanted.

` `#bugfix/workaround. 320 b/h in keysigs <= Bes Major is "ces", but somehow one octave to low. Compensate here.

` `if pillarOfFifth . index ( keysig . root ) < = 13 and pitch == 11 :

` `returnValue = pitchInOriginalKey + 350

` `else :

` `returnValue = pitchInOriginalKey

```
```

` `cache_fromMidi [ ( midipitch , keysig ) ] = returnValue

` `return returnValue

```
```

```
```

```
```

def halfToneDistanceFromC ( pitch : int ) - > int :

` `""" Return the half-tone step distance from C. The " sounding " interval """

` `return {

` `#00 : 10, # ceses,,, -> bes

` `#10 : 11, # ces,,, -> b

```
```

` `00 : - 2 , # ceses,,, -> bes

` `10 : - 1 , # ces,,, -> b

` `20 : 0 , # c,,,

` `30 : 1 , # cis,,,

` `40 : 2 , # cisis,,, -> d ...

` `50 : 0 , # deses,,,

` `60 : 1 , # des,,,

` `70 : 2 , # d,,,

` `80 : 3 , # dis,,,

` `90 : 4 , # disis,,,

` `100 : 2 , # eeses,,,

` `110 : 3 , # ees,,,

` `120 : 4 , # e,,,

` `130 : 5 , # eis,,,

` `140 : 6 , # eisis,,,

` `150 : 3 , # feses,,,

` `160 : 4 , # fes,,,

` `170 : 5 , # f,,,

` `180 : 6 , # fis,,,

` `190 : 7 , # fisis,,,

` `200 : 5 , # geses,,,

` `210 : 6 , # ges,,,

` `220 : 7 , # g,,,

` `230 : 8 , # gis,,,

` `240 : 9 , # gisis,,,

` `250 : 7 , # aeses,,,

` `260 : 8 , # aes,,,

` `270 : 9 , # a,,,

` `280 : 10 , # ais,,,

` `290 : 11 , # aisis,,,

` `300 : 9 , # beses,,,

` `310 : 10 , # bes,,,

` `320 : 11 , # b,,,

` `330 : 12 , # bis,,,

` `340 : 13 , # bisis,,,

` `#330 : 0, # bis,,,

` `#340 : 1, # bisis,,,

` `} [ plain ( pitch ) ]

```
```

```
```

def sharpen ( pitch : int ) - > int :

` `""" Sharpen the pitch until double crossed """

` `sharper = pitch + 10

` `if toWhite [ sharper ] == toWhite [ pitch ] : #still the same base note?

` `return sharper

` `else :

` `return pitch #too sharp, do nothing.

```
```

def flatten ( pitch : int ) - > int :

` `""" Flatten the pitch until double flat """

` `flatter = pitch - 10

` `if toWhite [ flatter ] == toWhite [ pitch ] : #still the same base note?

` `return flatter

` `else :

` `return pitch #too flat, do nothing.

```
```

def interval ( pitch1 : int , pitch2 : int ) - > Tuple [ int , int ] :

` `""" Return the distance between two pitches as steps in the pillar of fifths.

` `Intervals are tuplets with two members x = 1 , 0 #fifth in the same octave

` `x [ 0 ] = interval . Steps in the pillar of fifths .

` `x [ 1 ] = octave in between . Octave is always > = 0 because an interval has no direction .

` `Just a base note and the other note , which is higher per definition """

` `if pitch1 > pitch2 : #bring the notes in right order. We want to calculate from higher to lower

` `return ( pillarOfFifth . index ( plain ( pitch1 ) ) - pillarOfFifth . index ( plain ( pitch2 ) ) , octave ( pitch1 - pitch2 ) )

` `else :

` `return ( pillarOfFifth . index ( plain ( pitch2 ) ) - pillarOfFifth . index ( plain ( pitch1 ) ) , octave ( pitch2 - pitch1 ) )

```
```

def intervalUp ( pitch : int , interval : Tuple [ int , int ] , midiIn : bool = False ) - > int :

` `""" Return a pitch which is _interval_ higher than the given pitch """

` `octv = octave ( pitch )

` `indexNumber = pillarOfFifth . index ( plain ( pitch ) )

` `targetPitch = pillarOfFifth [ indexNumber + interval [ 0 ] ] + octv * 350 #return to the old octave

` `if not midiIn and targetPitch < pitch : #the new note is lower than where we started. This is wrong. +1 octave!. Reason: it was the break between two octaves.

` `targetPitch + = 350

` `targetPitch + = interval [ 1 ] * 350

` `return targetPitch

```
```

def intervalDown ( pitch : int , interval : Tuple [ int , int ] ) - > int :

` `""" Return a pitch which is _interval_ lower than the given pitch

` `intervalUp ( 20 , ( - 12 , 1 ) ) #c,,, to deses,,"""

```
```

` `octv = octave ( pitch )

` `indexNumber = pillarOfFifth . index ( plain ( pitch ) )

` `targetPitch = pillarOfFifth [ indexNumber - interval [ 0 ] ] + octv * 350 #return to the old octave.

` `if targetPitch > pitch : #the new note is higher than where we started. This is wrong. -1 octave!. Reason: it was the break between two octaves.

` `targetPitch - = 350

` `targetPitch - = interval [ 1 ] * 350

` `return targetPitch

```
```

def intervalAutomatic ( originalPitch : int , rootPitch : int , targetPitch : int ) - > int :

` `""" Return the original pitch transposed by the interval

` `between rootPitch and targetPitch """

` `iv = interval ( rootPitch , targetPitch )

` `if rootPitch > = targetPitch :

` `return intervalDown ( originalPitch , iv )

` `else : #rootPitch < targetPitch

` `return intervalUp ( originalPitch , iv )

```
```

```
```

#With a Key Signature

def toScale ( pitch : int , keysig : KeySignature ) - > int :

` `""" Return a pitch which is the in-scale variant of the given one.

` `Needs a Key Signature as second parameter """

` `if ( pitch , keysig ) in cache_toScale :

` `return cache_toScale [ ( pitch , keysig ) ]

` `else :

` `workingcopy = list ( keysig . keysigList )

` `workingcopy . sort ( ) # sort first.

` `mod = workingcopy [ tonalDistanceFromC [ pitch ] ] # tonalDistanceFromC has the same syntax as the keysig step/list position. mod becomes the (step, value) tuplet

` `value = toWhite [ pitch ] + mod [ 1 ]

` `cache_toScale [ ( pitch , keysig ) ] = value

` `return value

```
```

def diffToKey ( pitch : int , keysig : KeySignature ) - > int :

` `""" Return if a note is natural, sharp, flat etc.

` `Same syntax as Key Signature :

` `- 20 double flat , 0 natural , + 20 d - sharp . """

` `return pitch - toScale ( pitch , keysig )

```
```

#Ordered pitches in fifths.

#To calculate real and correct intervals you need the pillar of fifth with 35 steps for each of the 31 realistic notenames (and 4 unrealistic ones)"""

pillarOfFifth = [

` `#pillarOfFifth.index(260) -> 11

` `150 , #feses 0

` `0 , #ceses 1

` `200 , #geses 2

` `50 , #deses 3

` `250 , #aeses 4

` `100 , #eeses 5

` `300 , #beses 6

` `160 , #fes 7

` `10 , #ces 8

` `210 , #ges 9

` `60 , #des 10

` `260 , #aes 11

` `110 , #ees 12

` `310 , #bes 13

` `170 , #f 14

` `20 , #c 15

` `220 , #g 16

` `70 , #d 17

` `270 , #a 18

` `120 , #e 19

` `320 , #b 20

` `180 , #fis 21

` `30 , #cis 22

` `230 , #gis 23

` `80 , #dis 24

` `280 , #ais 25

` `130 , #eis 26

` `330 , #bis 27

` `190 , #fisis 28

` `40 , #cisis 29

` `240 , #gisis 30

` `90 , #disis 31

` `290 , #aisis 32

` `140 , #eisis 33

` `340 , #bisis 34

` `]

```
```

```
```

def midiPitchLimiter ( pitch : int , transpose : int ) - > int :

` `if pitch + transpose < 0 :

` `logger . warning ( f " Tranpose lead to a note below midi value 0: { pitch } . Limiting to 0. Please fix manually " )

` `return 0

` `elif pitch + transpose > 127 :

` `logger . warning ( f " Tranpose lead to a note above midi value 127: { pitch } . Limiting to 127. Please fix manually " )

` `return 127

` `else :

` `return pitch + transpose

```
```

def midiChannelLimiter ( value : int ) - > int :

` `""" makes sure that a midi channel is in range 0-15 """

` `if value > 15 :

` `logger . warning ( " Midi Channel bigger 15 detected: {} . Limiting to 15. Please fix manually " . format ( value ) )

` `return 15

` `elif value < 0 :

` `logger . warning ( " Midi Channel smaller 0 detected: {} . Limiting to 0. Please fix manually " . format ( value ) )

` `return 0

` `else :

` `return value

```
```

```
```

#The table to convert internal pitches into lilypond and back.

#0 - A tone humans cannot hear anymore.

#1420 - "Middle" c'

#2130 - Soprano-Singers high C

#3150 - Goes beyond the range of a modern piano

#+inf.0 - A rest

```
```

#<10 is reserved for microtones, in the future.

#+10 One accidental up jumps over to the next note after cisis

#+50 One diatonic step, preserve accidentals

#+350 One Octave

ly2pitch = {

` `" ceses,,, " : 00 ,

` `" ces,,, " : 10 ,

` `" c,,, " : 20 ,

` `" cis,,, " : 30 ,

` `" cisis,,, " : 40 ,

` `" deses,,, " : 50 ,

` `" des,,, " : 60 ,

` `" d,,, " : 70 ,

` `" dis,,, " : 80 ,

` `" disis,,, " : 90 ,

` `" eeses,,, " : 100 ,

` `" ees,,, " : 110 ,

` `" e,,, " : 120 ,

` `" eis,,, " : 130 ,

` `" eisis,,, " : 140 ,

` `" feses,,, " : 150 ,

` `" fes,,, " : 160 ,

` `" f,,, " : 170 ,

` `" fis,,, " : 180 ,

` `" fisis,,, " : 190 ,

` `" geses,,, " : 200 ,

` `" ges,,, " : 210 ,

` `" g,,, " : 220 ,

` `" gis,,, " : 230 ,

` `" gisis,,, " : 240 ,

` `" aeses,,, " : 250 ,

` `" aes,,, " : 260 ,

` `" a,,, " : 270 ,

` `" ais,,, " : 280 ,

` `" aisis,,, " : 290 ,

` `" beses,,, " : 300 ,

` `" bes,,, " : 310 ,

` `" b,,, " : 320 ,

` `" bis,,, " : 330 ,

` `" bisis,,, " : 340 ,

` `" ceses,, " : 350 ,

` `" ces,, " : 360 ,

` `" c,, " : 370 ,

` `" cis,, " : 380 ,

` `" cisis,, " : 390 ,

` `" deses,, " : 400 ,

` `" des,, " : 410 ,

` `" d,, " : 420 ,

` `" dis,, " : 430 ,

` `" disis,, " : 440 ,

` `" eeses,, " : 450 ,

` `" ees,, " : 460 ,

` `" e,, " : 470 ,

` `" eis,, " : 480 ,

` `" eisis,, " : 490 ,

` `" feses,, " : 500 ,

` `" fes,, " : 510 ,

` `" f,, " : 520 ,

` `" fis,, " : 530 ,

` `" fisis,, " : 540 ,

` `" geses,, " : 550 ,

` `" ges,, " : 560 ,

` `" g,, " : 570 ,

` `" gis,, " : 580 ,

` `" gisis,, " : 590 ,

` `" aeses,, " : 600 ,

` `" aes,, " : 610 ,

` `" a,, " : 620 ,

` `" ais,, " : 630 ,

` `" aisis,, " : 640 ,

` `" beses,, " : 650 ,

` `" bes,, " : 660 ,

` `" b,, " : 670 ,

` `" bis,, " : 680 ,

` `" bisis,, " : 690 ,

` `" ceses, " : 700 ,

` `" ces, " : 710 ,

` `" c, " : 720 ,

` `" cis, " : 730 ,

` `" cisis, " : 740 ,

` `" deses, " : 750 ,

` `" des, " : 760 ,

` `" d, " : 770 ,

` `" dis, " : 780 ,

` `" disis, " : 790 ,

` `" eeses, " : 800 ,

` `" ees, " : 810 ,

` `" e, " : 820 ,

` `" eis, " : 830 ,

` `" eisis, " : 840 ,

` `" feses, " : 850 ,

` `" fes, " : 860 ,

` `" f, " : 870 ,

` `" fis, " : 880 ,

` `" fisis, " : 890 ,

` `" geses, " : 900 ,

` `" ges, " : 910 ,

` `" g, " : 920 ,

` `" gis, " : 930 ,

` `" gisis, " : 940 ,

` `" aeses, " : 950 ,

` `" aes, " : 960 ,

` `" a, " : 970 ,

` `" ais, " : 980 ,

` `" aisis, " : 990 ,

` `" beses, " : 1000 ,

` `" bes, " : 1010 ,

` `" b, " : 1020 ,

` `" bis, " : 1030 ,

` `" bisis, " : 1040 ,

` `" ceses " : 1050 ,

` `" ces " : 1060 ,

` `" c " : 1070 ,

` `" cis " : 1080 ,

` `" cisis " : 1090 ,

` `" deses " : 1100 ,

` `" des " : 1110 ,

` `" d " : 1120 ,

` `" dis " : 1130 ,

` `" disis " : 1140 ,

` `" eeses " : 1150 ,

` `" ees " : 1160 ,

` `" e " : 1170 ,

` `" eis " : 1180 ,

` `" eisis " : 1190 ,

` `" feses " : 1200 ,

` `" fes " : 1210 ,

` `" f " : 1220 ,

` `" fis " : 1230 ,

` `" fisis " : 1240 ,

` `" geses " : 1250 ,

` `" ges " : 1260 ,

` `" g " : 1270 ,

` `" gis " : 1280 ,

` `" gisis " : 1290 ,

` `" aeses " : 1300 ,

` `" aes " : 1310 ,

` `" a " : 1320 ,

` `" ais " : 1330 ,

` `" aisis " : 1340 ,

` `" beses " : 1350 ,

` `" bes " : 1360 ,

` `" b " : 1370 ,

` `" bis " : 1380 ,

` `" bisis " : 1390 ,

` `" ceses ' " : 1400 ,

` `" ces ' " : 1410 ,

` `" c ' " : 1420 ,

` `" cis ' " : 1430 ,

` `" cisis ' " : 1440 ,

` `" deses ' " : 1450 ,

` `" des ' " : 1460 ,

` `" d ' " : 1470 ,

` `" dis ' " : 1480 ,

` `" disis ' " : 1490 ,

` `" eeses ' " : 1500 ,

` `" ees ' " : 1510 ,

` `" e ' " : 1520 ,

` `" eis ' " : 1530 ,

` `" eisis ' " : 1540 ,

` `" feses ' " : 1550 ,

` `" fes ' " : 1560 ,

` `" f ' " : 1570 ,

` `" fis ' " : 1580 ,

` `" fisis ' " : 1590 ,

` `" geses ' " : 1600 ,

` `" ges ' " : 1610 ,

` `" g ' " : 1620 ,

` `" gis ' " : 1630 ,

` `" gisis ' " : 1640 ,

` `" aeses ' " : 1650 ,

` `" aes ' " : 1660 ,

` `" a ' " : 1670 ,

` `" ais ' " : 1680 ,

` `" aisis ' " : 1690 ,

` `" beses ' " : 1700 ,

` `" bes ' " : 1710 ,

` `" b ' " : 1720 ,

` `" bis ' " : 1730 ,

` `" bisis ' " : 1740 ,

` `" ceses ' ' " : 1750 ,

` `" ces ' ' " : 1760 ,

` `" c ' ' " : 1770 ,

` `" cis ' ' " : 1780 ,

` `" cisis ' ' " : 1790 ,

` `" deses ' ' " : 1800 ,

` `" des ' ' " : 1810 ,

` `" d ' ' " : 1820 ,

` `" dis ' ' " : 1830 ,

` `" disis ' ' " : 1840 ,

` `" eeses ' ' " : 1850 ,

` `" ees ' ' " : 1860 ,

` `" e ' ' " : 1870 ,

` `" eis ' ' " : 1880 ,

` `" eisis ' ' " : 1890 ,

` `" feses ' ' " : 1900 ,

` `" fes ' ' " : 1910 ,

` `" f ' ' " : 1920 ,

` `" fis ' ' " : 1930 ,

` `" fisis ' ' " : 1940 ,

` `" geses ' ' " : 1950 ,

` `" ges ' ' " : 1960 ,

` `" g ' ' " : 1970 ,

` `" gis ' ' " : 1980 ,

` `" gisis ' ' " : 1990 ,

` `" aeses ' ' " : 2000 ,

` `" aes ' ' " : 2010 ,

` `" a ' ' " : 2020 ,

` `" ais ' ' " : 2030 ,

` `" aisis ' ' " : 2040 ,

` `" beses ' ' " : 2050 ,

` `" bes ' ' " : 2060 ,

` `" b ' ' " : 2070 ,

` `" bis ' ' " : 2080 ,

` `" bisis ' ' " : 2090 ,

` `" ceses ' ' ' " : 2100 ,

` `" ces ' ' ' " : 2110 ,

` `" c ' ' ' " : 2120 ,

` `" cis ' ' ' " : 2130 ,

` `" cisis ' ' ' " : 2140 ,

` `" deses ' ' ' " : 2150 ,

` `" des ' ' ' " : 2160 ,

` `" d ' ' ' " : 2170 ,

` `" dis ' ' ' " : 2180 ,

` `" disis ' ' ' " : 2190 ,

` `" eeses ' ' ' " : 2200 ,

` `" ees ' ' ' " : 2210 ,

` `" e ' ' ' " : 2220 ,

` `" eis ' ' ' " : 2230 ,

` `" eisis ' ' ' " : 2240 ,

` `" feses ' ' ' " : 2250 ,

` `" fes ' ' ' " : 2260 ,

` `" f ' ' ' " : 2270 ,

` `" fis ' ' ' " : 2280 ,

` `" fisis ' ' ' " : 2290 ,

` `" geses ' ' ' " : 2300 ,

` `" ges ' ' ' " : 2310 ,

` `" g ' ' ' " : 2320 ,

` `" gis ' ' ' " : 2330 ,

` `" gisis ' ' ' " : 2340 ,

` `" aeses ' ' ' " : 2350 ,

` `" aes ' ' ' " : 2360 ,

` `" a ' ' ' " : 2370 ,

` `" ais ' ' ' " : 2380 ,

` `" aisis ' ' ' " : 2390 ,

` `" beses ' ' ' " : 2400 ,

` `" bes ' ' ' " : 2410 ,

` `" b ' ' ' " : 2420 ,

` `" bis ' ' ' " : 2430 ,

` `" bisis ' ' ' " : 2440 ,

` `" ceses ' ' ' ' " : 2450 ,

` `" ces ' ' ' ' " : 2460 ,

` `" c ' ' ' ' " : 2470 ,

` `" cis ' ' ' ' " : 2480 ,

` `" cisis ' ' ' ' " : 2490 ,

` `" deses ' ' ' ' " : 2500 ,

` `" des ' ' ' ' " : 2510 ,

` `" d ' ' ' ' " : 2520 ,

` `" dis ' ' ' ' " : 2530 ,

` `" disis ' ' ' ' " : 2540 ,

` `" eeses ' ' ' ' " : 2550 ,

` `" ees ' ' ' ' " : 2560 ,

` `" e ' ' ' ' " : 2570 ,

` `" eis ' ' ' ' " : 2580 ,

` `" eisis ' ' ' ' " : 2590 ,

` `" feses ' ' ' ' " : 2600 ,

` `" fes ' ' ' ' " : 2610 ,

` `" f ' ' ' ' " : 2620 ,

` `" fis ' ' ' ' " : 2630 ,

` `" fisis ' ' ' ' " : 2640 ,

` `" geses ' ' ' ' " : 2650 ,

` `" ges ' ' ' ' " : 2660 ,

` `" g ' ' ' ' " : 2670 ,

` `" gis ' ' ' ' " : 2680 ,

` `" gisis ' ' ' ' " : 2690 ,

` `" aeses ' ' ' ' " : 2700 ,

` `" aes ' ' ' ' " : 2710 ,

` `" a ' ' ' ' " : 2720 ,

` `" ais ' ' ' ' " : 2730 ,

` `" aisis ' ' ' ' " : 2740 ,

` `" beses ' ' ' ' " : 2750 ,

` `" bes ' ' ' ' " : 2760 ,

` `" b ' ' ' ' " : 2770 ,

` `" bis ' ' ' ' " : 2780 ,

` `" bisis ' ' ' ' " : 2790 ,

` `" ceses ' ' ' ' ' " : 2800 ,

` `" ces ' ' ' ' ' " : 2810 ,

` `" c ' ' ' ' ' " : 2820 ,

` `" cis ' ' ' ' ' " : 2830 ,

` `" cisis ' ' ' ' ' " : 2840 ,

` `" deses ' ' ' ' ' " : 2850 ,

` `" des ' ' ' ' ' " : 2860 ,

` `" d ' ' ' ' ' " : 2870 ,

` `" dis ' ' ' ' ' " : 2880 ,

` `" disis ' ' ' ' ' " : 2890 ,

` `" eeses ' ' ' ' ' " : 2900 ,

` `" ees ' ' ' ' ' " : 2910 ,

` `" e ' ' ' ' ' " : 2920 ,

` `" eis ' ' ' ' ' " : 2930 ,

` `" eisis ' ' ' ' ' " : 2940 ,

` `" feses ' ' ' ' ' " : 2950 ,

` `" fes ' ' ' ' ' " : 2960 ,

` `" f ' ' ' ' ' " : 2970 ,

` `" fis ' ' ' ' ' " : 2980 ,

` `" fisis ' ' ' ' ' " : 2990 ,

` `" geses ' ' ' ' ' " : 3000 ,

` `" ges ' ' ' ' ' " : 3010 ,

` `" g ' ' ' ' ' " : 3020 ,

` `" gis ' ' ' ' ' " : 3030 ,

` `" gisis ' ' ' ' ' " : 3040 ,

` `" aeses ' ' ' ' ' " : 3050 ,

` `" aes ' ' ' ' ' " : 3060 ,

` `" a ' ' ' ' ' " : 3070 ,

` `" ais ' ' ' ' ' " : 3080 ,

` `" aisis ' ' ' ' ' " : 3090 ,

` `" beses ' ' ' ' ' " : 3100 ,

` `" bes ' ' ' ' ' " : 3110 ,

` `" b ' ' ' ' ' " : 3120 ,

` `" bis ' ' ' ' ' " : 3130 ,

` `" bisis ' ' ' ' ' " : 3140 ,

` `#"r" : float('inf'), a rest is not a pitch

` `}

```
```

sortedNoteNameList = [

` `" ceses,,, " ,

` `" ces,,, " ,

` `" c,,, " ,

` `" cis,,, " ,

` `" cisis,,, " ,

` `" deses,,, " ,

` `" des,,, " ,

` `" d,,, " ,

` `" dis,,, " ,

` `" disis,,, " ,

` `" eeses,,, " ,

` `" ees,,, " ,

` `" e,,, " ,

` `" eis,,, " ,

` `" eisis,,, " ,

` `" feses,,, " ,

` `" fes,,, " ,

` `" f,,, " ,

` `" fis,,, " ,

` `" fisis,,, " ,

` `" geses,,, " ,

` `" ges,,, " ,

` `" g,,, " ,

` `" gis,,, " ,

` `" gisis,,, " ,

` `" aeses,,, " ,

` `" aes,,, " ,

` `" a,,, " ,

` `" ais,,, " ,

` `" aisis,,, " ,

` `" beses,,, " ,

` `" bes,,, " ,

` `" b,,, " ,

` `" bis,,, " ,

` `" bisis,,, " ,

` `" ceses,, " ,

` `" ces,, " ,

` `" c,, " ,

` `" cis,, " ,

` `" cisis,, " ,

` `" deses,, " ,

` `" des,, " ,

` `" d,, " ,

` `" dis,, " ,

` `" disis,, " ,

` `" eeses,, " ,

` `" ees,, " ,

` `" e,, " ,

` `" eis,, " ,

` `" eisis,, " ,

` `" feses,, " ,

` `" fes,, " ,

` `" f,, " ,

` `" fis,, " ,

` `" fisis,, " ,

` `" geses,, " ,

` `" ges,, " ,

` `" g,, " ,

` `" gis,, " ,

` `" gisis,, " ,

` `" aeses,, " ,

` `" aes,, " ,

` `" a,, " ,

` `" ais,, " ,

` `" aisis,, " ,

` `" beses,, " ,

` `" bes,, " ,

` `" b,, " ,

` `" bis,, " ,

` `" bisis,, " ,

` `" ceses, " ,

` `" ces, " ,

` `" c, " ,

` `" cis, " ,

` `" cisis, " ,

` `" deses, " ,

` `" des, " ,

` `" d, " ,

` `" dis, " ,

` `" disis, " ,

` `" eeses, " ,

` `" ees, " ,

` `" e, " ,

` `" eis, " ,

` `" eisis, " ,

` `" feses, " ,

` `" fes, " ,

` `" f, " ,

` `" fis, " ,

` `" fisis, " ,

` `" geses, " ,

` `" ges, " ,

` `" g, " ,

` `" gis, " ,

` `" gisis, " ,

` `" aeses, " ,

` `" aes, " ,

` `" a, " ,

` `" ais, " ,

` `" aisis, " ,

` `" beses, " ,

` `" bes, " ,

` `" b, " ,

` `" bis, " ,

` `" bisis, " ,

` `" ceses " ,

` `" ces " ,

` `" c " ,

` `" cis " ,

` `" cisis " ,

` `" deses " ,

` `" des " ,

` `" d " ,

` `" dis " ,

` `" disis " ,

` `" eeses " ,

` `" ees " ,

` `" e " ,

` `" eis " ,

` `" eisis " ,

` `" feses " ,

` `" fes " ,

` `" f " ,

` `" fis " ,

` `" fisis " ,

` `" geses " ,

` `" ges " ,

` `" g " ,

` `" gis " ,

` `" gisis " ,

` `" aeses " ,

` `" aes " ,

` `" a " ,

` `" ais " ,

` `" aisis " ,

` `" beses " ,

` `" bes " ,

` `" b " ,

` `" bis " ,

` `" bisis " ,

` `" ceses ' " ,

` `" ces ' " ,

` `" c ' " ,

` `" cis ' " ,

` `" cisis ' " ,

` `" deses ' " ,

` `" des ' " ,

` `" d ' " ,

` `" dis ' " ,

` `" disis ' " ,

` `" eeses ' " ,

` `" ees ' " ,

` `" e ' " ,

` `" eis ' " ,

` `" eisis ' " ,

` `" feses ' " ,

` `" fes ' " ,

` `" f ' " ,

` `" fis ' " ,

` `" fisis ' " ,

` `" geses ' " ,

` `" ges ' " ,

` `" g ' " ,

` `" gis ' " ,

` `" gisis ' " ,

` `" aeses ' " ,

` `" aes ' " ,

` `" a ' " ,

` `" ais ' " ,

` `" aisis ' " ,

` `" beses ' " ,

` `" bes ' " ,

` `" b ' " ,

` `" bis ' " ,

` `" bisis ' " ,

` `" ceses ' ' " ,

` `" ces ' ' " ,

` `" c ' ' " ,

` `" cis ' ' " ,

` `" cisis ' ' " ,

` `" deses ' ' " ,

` `" des ' ' " ,

` `" d ' ' " ,

` `" dis ' ' " ,

` `" disis ' ' " ,

` `" eeses ' ' " ,

` `" ees ' ' " ,

` `" e ' ' " ,

` `" eis ' ' " ,

` `" eisis ' ' " ,

` `" feses ' ' " ,

` `" fes ' ' " ,

` `" f ' ' " ,

` `" fis ' ' " ,

` `" fisis ' ' " ,

` `" geses ' ' " ,

` `" ges ' ' " ,

` `" g ' ' " ,

` `" gis ' ' " ,

` `" gisis ' ' " ,

` `" aeses ' ' " ,

` `" aes ' ' " ,

` `" a ' ' " ,

` `" ais ' ' " ,

` `" aisis ' ' " ,

` `" beses ' ' " ,

` `" bes ' ' " ,

` `" b ' ' " ,

` `" bis ' ' " ,

` `" bisis ' ' " ,

` `" ceses ' ' ' " ,

` `" ces ' ' ' " ,

` `" c ' ' ' " ,

` `" cis ' ' ' " ,

` `" cisis ' ' ' " ,

` `" deses ' ' ' " ,

` `" des ' ' ' " ,

` `" d ' ' ' " ,

` `" dis ' ' ' " ,

` `" disis ' ' ' " ,

` `" eeses ' ' ' " ,

` `" ees ' ' ' " ,

` `" e ' ' ' " ,

` `" eis ' ' ' " ,

` `" eisis ' ' ' " ,

` `" feses ' ' ' " ,

` `" fes ' ' ' " ,

` `" f ' ' ' " ,

` `" fis ' ' ' " ,

` `" fisis ' ' ' " ,

` `" geses ' ' ' " ,

` `" ges ' ' ' " ,

` `" g ' ' ' " ,

` `" gis ' ' ' " ,

` `" gisis ' ' ' " ,

` `" aeses ' ' ' " ,

` `" aes ' ' ' " ,

` `" a ' ' ' " ,

` `" ais ' ' ' " ,

` `" aisis ' ' ' " ,

` `" beses ' ' ' " ,

` `" bes ' ' ' " ,

` `" b ' ' ' " ,

` `" bis ' ' ' " ,

` `" bisis ' ' ' " ,

` `" ceses ' ' ' ' " ,

` `" ces ' ' ' ' " ,

` `" c ' ' ' ' " ,

` `" cis ' ' ' ' " ,

` `" cisis ' ' ' ' " ,

` `" deses ' ' ' ' " ,

` `" des ' ' ' ' " ,

` `" d ' ' ' ' " ,

` `" dis ' ' ' ' " ,

` `" disis ' ' ' ' " ,

` `" eeses ' ' ' ' " ,

` `" ees ' ' ' ' " ,

` `" e ' ' ' ' " ,

` `" eis ' ' ' ' " ,

` `" eisis ' ' ' ' " ,

` `" feses ' ' ' ' " ,

` `" fes ' ' ' ' " ,

` `" f ' ' ' ' " ,

` `" fis ' ' ' ' " ,

` `" fisis ' ' ' ' " ,

` `" geses ' ' ' ' " ,

` `" ges ' ' ' ' " ,

` `" g ' ' ' ' " ,

` `" gis ' ' ' ' " ,

` `" gisis ' ' ' ' " ,

` `" aeses ' ' ' ' " ,

` `" aes ' ' ' ' " ,

` `" a ' ' ' ' " ,

` `" ais ' ' ' ' " ,

` `" aisis ' ' ' ' " ,

` `" beses ' ' ' ' " ,

` `" bes ' ' ' ' " ,

` `" b ' ' ' ' " ,

` `" bis ' ' ' ' " ,

` `" bisis ' ' ' ' " ,

` `" ceses ' ' ' ' ' " ,

` `" ces ' ' ' ' ' " ,

` `" c ' ' ' ' ' " ,

` `" cis ' ' ' ' ' " ,

` `" cisis ' ' ' ' ' " ,

` `" deses ' ' ' ' ' " ,

` `" des ' ' ' ' ' " ,

` `" d ' ' ' ' ' " ,

` `" dis ' ' ' ' ' " ,

` `" disis ' ' ' ' ' " ,

` `" eeses ' ' ' ' ' " ,

` `" ees ' ' ' ' ' " ,

` `" e ' ' ' ' ' " ,

` `" eis ' ' ' ' ' " ,

` `" eisis ' ' ' ' ' " ,

` `" feses ' ' ' ' ' " ,

` `" fes ' ' ' ' ' " ,

` `" f ' ' ' ' ' " ,

` `" fis ' ' ' ' ' " ,

` `" fisis ' ' ' ' ' " ,

` `" geses ' ' ' ' ' " ,

` `" ges ' ' ' ' ' " ,

` `" g ' ' ' ' ' " ,

` `" gis ' ' ' ' ' " ,

` `" gisis ' ' ' ' ' " ,

` `" aeses ' ' ' ' ' " ,

` `" aes ' ' ' ' ' " ,

` `" a ' ' ' ' ' " ,

` `" ais ' ' ' ' ' " ,

` `" aisis ' ' ' ' ' " ,

` `" beses ' ' ' ' ' " ,

` `" bes ' ' ' ' ' " ,

` `" b ' ' ' ' ' " ,

` `" bis ' ' ' ' ' " ,

` `" bisis ' ' ' ' ' " ,

` `]

```
```

baseNotesToBaseNames = {

` `20 : " C " ,

` `70 : " D " ,

` `120 : " E " ,

` `170 : " F " ,

` `220 : " G " ,

` `270 : " A " ,

` `320 : " B/H " ,

```
```

` `20 - 10 : " Ces " ,

` `70 - 10 : " Des " ,

` `120 - 10 : " Ees " ,

` `170 - 10 : " Fes " ,

` `220 - 10 : " Ges " ,

` `270 - 10 : " Aes " ,

` `320 - 10 : " Bes/Bb " ,

```
```

` `20 + 10 : " Cis " ,

` `70 + 10 : " Dis " ,

` `120 + 10 : " Eis " ,

` `170 + 10 : " Fis " ,

` `220 + 10 : " Gis " ,

` `270 + 10 : " Ais " ,

` `320 + 10 : " Bis/His " ,

` `}

```
```

orderedBaseNotes = [ " C " , " D " , " E " , " F " , " G " , " A " , " H/B " ]

```
```

```
```

#Basic notes. For example to use as parameter for key-signatures in the API.

#P for Pitch

P_C = 20

P_D = 70

P_E = 120

P_F = 170

P_G = 220

P_B = P_H = 270

```
```

#This is a funny historical coincidence. The s was used as sharp-sign before. Which lead to people pronouncing Cs "Cis".

P_Cs = 20 + 10

P_Ds = 70 + 10

P_Es = 120 + 10

P_Fs = 170 + 10

P_Gs = 220 + 10

P_Bs = P_Hs = 270 + 10

```
```

P_Cb = 20 - 10

P_Db = 70 - 10

P_Eb = 120 - 10

P_Fb = 170 - 10

P_Gb = 220 - 10

P_Bb = P_Hb = 270 - 10

```
```

```
```

#Generate some tables and other cached dicts on startup

#These are mostly values that are called multiple thousand times per track for every callback

pitch2ly = dict ( ( ly2pitch [ k ] , k ) for k in ly2pitch )

```
```

cache_toScale : Dict [ Tuple [ int , KeySignature ] , int ] = { } #filled dynamically. int is a pitch, object is a keysignature. value is pitch

cache_fromMidi : Dict [ Tuple [ int , KeySignature ] , int ] = { } #filled dynamically midipitch:keysig . type is (midipitch, keysig) : internal pitch

toMidi = { } #filled for all pitches on startup, below

toWhite = { } #filled for all pitches on startup, below

tonalDistanceFromC = { } #filled for all pitches on startup, below