#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright 2021, 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

#Third Party Modules
#Template Modules
#Our modules


#Constants
OCTAVE = 350
STEP = 50
MAX = 3140
MIN = 0

#Without a keysignature
def plain(pitch):
    """ 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):
    """Return the octave of given note. Lowest 0 is X,,,"""
    return divmod(pitch, 350)[0]

def toOctave(pitch, octave):
    """Take a plain note and give the octave variant. Starts with 0"""
    return pitch + octave * 350

def mirror(pitch, axis):
    """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):
    """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):
    """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, second):
    """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, octave):
    """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, pitch):
    """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, keysig):
    """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):
    """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):
    """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):
    """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, pitch2):
    """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, interval, midiIn = False):
    """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, interval):
    """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, rootPitch, targetPitch):
    """Return the original pitch transposed by the interval
    between rootPitch and targetPitch"""
    iv = interval(rootPitch, targetPitch)
    if rootPitch >= targetPitch:
        return intervalDown(originalPitch, iv)
    elif rootPitch < targetPitch:
        return intervalUp(originalPitch, iv)


#With a Key Signature
def toScale(pitch, keysig):
    """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, keysig):
    """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, transpose):
    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):
    """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 = {} #filled dynamically
cache_fromMidi = {} #filled dynamically
toMidi = {} #filled for all pitches on startup, below
toWhite = {} #filled for all pitches on startup, below
tonalDistanceFromC = {} #filled for all pitches on startup, below
distanceInDiatonicStepsFrom1720 = {} #filled for all pitches on startup, below. Utilized by item.asDotOnLine


for pitch in ly2pitch.values():
    toWhite[pitch] = divmod(pitch, 50)[0] * 50 + 20
    octOffset = (octave(pitch) +1) * 12 #twelve tones per midi octave
    toMidi[pitch] = octOffset +  halfToneDistanceFromC(pitch)
    tonalDistanceFromC[pitch] = divmod(plain(toWhite[pitch]), 50)[0]

#second round for dependencies on finished pitchmath
for pitch in ly2pitch.values():
    distanceInDiatonicStepsFrom1720[pitch] = distanceInDiatonicSteps(1720, pitch) #offset from the middle line in treble clef h', which is 0. c'' is -1, a' is +1

#Lists of Notenames. Maps midi to different note systems
#These are simple fixed lists without root notes or key signatures. For a real conversion use pitch.fromMidi(root, keysig)
midi_notenames_english = []
for _midipitch in range(128):
    _octave, _pitch = divmod(_midipitch, 12)
    midi_notenames_english.append("{}{}".format("C Db D Eb E F F# G Ab A Bb B".split()[_pitch] ,_octave-1))

midi_notenames_german = []
for _midipitch in range(128):
    _octave, _pitch = divmod(_midipitch, 12)
    midi_notenames_german.append("{}{}".format("C Des D Es E F Fis G As A B H".split()[_pitch] ,_octave-1))

"""midi_notenames_lilypond = []
for _midipitch in range(128):
    _octave, _pitch = divmod(_midipitch, 12)
    midi_notenames_lilypond.append("{}{}".format("C Des D Ees E F Fis G Aes A Bes B".split()[_pitch] ,_octave-1))
"""

#60 is C'
t = """
C,,,, Des,,,, D,,,, Ees,,,, E,,,, F,,,, Fis,,,, G,,,, Aes,,,, A,,,, Bes,,,, B,,,,
C,,, Des,,, D,,, Ees,,, E,,, F,,, Fis,,, G,,, Aes,,, A,,, Bes,,, B,,,
C,, Des,, D,, Ees,, E,, F,, Fis,, G,, Aes,, A,, Bes,, B,,
C, Des, D, Ees, E, F, Fis, G, Aes, A, Bes, B,
C Des D Ees E F Fis G Aes A Bes B
C' Des' D' Ees' E' F' Fis' G' Aes' A' Bes' B'
C'' Des'' D'' Ees'' E'' F'' Fis'' G'' Aes'' A'' Bes'' B''
C''' Des''' D''' Ees''' E''' F''' Fis''' G''' Aes''' A''' Bes''' B'''
C'''' Des'''' D'''' Ees'''' E'''' F'''' Fis'''' G'''' Aes'''' A'''' Bes'''' B''''
C''''' Des''''' D''''' Ees''''' E''''' F''''' Fis''''' G''''' Aes''''' A''''' Bes''''' B'''''
C'''''' Des'''''' D'''''' Ees'''''' E'''''' F'''''' Fis'''''' G''''''
"""
midi_notenames_lilypond = t.split()


midi_notenames_gm_drums = [str(i) for i in range(0,35)] + [
    "Acoustic BD",
    "Bass Drum 1",
    "Side Stick",
    "Acoustic Snare",
    "Hand Clap",
    "Electric Snare",
    "Low Floor Tom",
    "Closed Hi Hat",
    "High Floor Tom",
    "Pedal Hi-Hat",
    "Low Tom",
    "Open Hi-Hat",
    "Low-Mid Tom",
    "Hi-Mid Tom",
    "Crash Cymbal 1",
    "High Tom",
    "Ride Cymbal 1",
    "Chinese Cymbal",
    "Ride Bell",
    "Tambourine",
    "Splash Cymbal",
    "Cowbell",
    "Crash Cymbal 2",
    "Vibraslap",
    "Ride Cymbal 2",
    "Hi Bongo",
    "Low Bongo",
    "Mute Hi Conga",
    "Open Hi Conga",
    "Low Conga",
    "High Timbale",
    "Low Timbale",
    "High Agogo",
    "Low Agogo",
    "Cabasa",
    "Maracas",
    "Short Whistle",
    "Long Whistle",
    "Short Guiro",
    "Long Guiro",
    "Claves",
    "Hi Wood Block",
    "Low Wood Block",
    "Mute Cuica",
    "Open Cuica",
    "Mute Triangle",
    "Open Triangle",
    ] + [str(i) for i in range(87,128)]


def _defaultSimpleNoteNames():
    return midi_notenames_english

simpleNoteNames = defaultdict(_defaultSimpleNoteNames)
simpleNoteNames["German"] = midi_notenames_german
simpleNoteNames["English"] = midi_notenames_english
simpleNoteNames["Lilypond"] = midi_notenames_lilypond
simpleNoteNames["Drums GM"] = midi_notenames_gm_drums



