# -*- coding: ISO-8859-1 -*- """CapellaScript -- R. v. Salis, >>> Swiss_Oergeli : Tabulaturschrift für das Schweizer Oergeli Setzt Noten in die Tabulaturschrift für Schwyzerörgeli um. <<< History: 23. Juni 2005 - erste Ausgabe """ import xml.dom, tempfile from caplib.capDOM import ScoreChange from xml.dom.minidom import NodeList verboten = (51,52,59,76,83,89,90) #nicht existierende Töne aus der chromatischen Leiter ziehen = (0,0,0,2,0,0,56,4,3,0,6,52,5,8,1,7,58,10,9,12,62,54,93,60,13,16,0,15,64,18,17,20,66,0,19,68,21,70,0,0,0,0) stossen = (2,0,0,4,52,3,0,0,90,0,0,56,8,7,1,10,0,9,60,0,91,54,58,62,14,13,0,16,0,15,64,0,92,0,66,68,20,19,70,0,0,21) notenListe = [] griffListe = [] druckzugListe = [] #Für jeden Takt die Richtung +1 oder -1 taktListe = [1] #Notennummer der ersten Note in jedem Takt barListe = [0] #Taktnummer des ersten Taktes in jedem Abschnitt ausnahmeListe = [] #Noten im Musikstück, die auf dem Oergeli nicht gespielt werden können verdecktListe = [] #verdeckte Kreuztöne merkTime = 0 def getKoordinaten(chromatic): #Wandelt Tonhöhe in Koordinaten um if chromatic < 50 or chromatic > 91 or chromatic in verboten: clef=[-1,-1] else: clef=[ziehen[chromatic-50],stossen[chromatic-50]] return clef def analyseScore(score): global takt global merkTime for s in score.systems(): takt = float(s.staff(0).defaultMeter()) #Ermittelt Takt m=score.nSystems() n = 0 #Notennummer newTime = 0 Flag = True offsetTime = 0 for k in range(0,m,1): for a in score.system(k).noteObjs(): if a.isBarline(): if (k == 0 and len(taktListe) == 1): #Auftakt ist vorhanden Flag = False if (len(taktListe) > 1 and barListe[len(barListe)-1] != len(taktListe)) : barListe.append(len(taktListe)) #Stellung des festen Taktstriches in barListe if a.isChord(): n +=1 #Notenzähler erhöhen oldTime = newTime t = a.time() tonh = score.system(k).pitches(t,True,False) #Holt Notenwerte des Akkords j=0 liste=[] for b in a.heads(): ton=tonh[j]; listeneintrag = getKoordinaten(ton) #Wandelt sie in Koordinaten um liste.append(listeneintrag) j += 1 notenListe.append(liste) #Ergänzt notenListe mit Akkord if Flag == False: #Auftakt ist vorhanden offsetTime = t merkTime = t Flag = True newTime = int((t-offsetTime)/takt) if newTime-oldTime != 0: taktListe.append(n) #Stellung des Taktstriches in taktListe elif a.isRest(): #nur wirksam, falls Auftakt vorhanden und -> if Flag == False: #erstes Objekt nach dem ersten Taktstrich -> t = a.time() #eine Pause ist offsetTime = t Flag = True offsetTime = 0 taktListe.append(n+1) #Taktlistenabschluss L = len(taktListe) - 1 if barListe[len(barListe)-1] != L: #Barlistenabschluss barListe.append(L) def ausgleichen(abschnitt): #erzeugt pro Abschnitt eine gerade Anzahl von -> n = len(abschnitt) #etwa gleich langen Unterabschnitten if n == 0: return m = n/10 if n%10 <> 0: m += 1 m = 2 * m #Anzahl Hinundher pro Abschnitt hh = n / m #Anzahl Takte pro Hinundher hhrest = n % m #Resttakte info = [] eintrag = 1 if n == 1: info.append(eintrag) else: for k1 in range(0,m,1): for k2 in range(0,hh,1): info.append(eintrag) if hhrest > 0: info.append(eintrag) hhrest -= 1 eintrag = -eintrag for k in range(0,n,1): test = info[k]+abschnitt[k] if test > 2: messageBox('Achtung','Takt muss aufgespalten werden, andere Stimmung probieren') elif test == 0: info[k]=-info[k] test = 0 for k in range(0,n,1): #Summe bilden test += info[k] if test > 0: #zu viele Zugtakte pro Abschnitt for k in range(1,n,1): if (abschnitt[k] == 0 and info[k] == 1): info[k] = -1 test -= 1 if test < 2: break elif test < 0: #zu viele Drucktakte pro Abschnitt for k in range(1,n,1): if (abschnitt[k] == 0 and info[k] == -1): info[k] = 1 test += 1 if test > 0: break return info def createRichtung(): #für jeden Takt wird die mögliche Balgrichtung ermittelt global druckzugListe richtungsListe = [] m_alt = 1 for m in taktListe: if m > 1: druck = 1 zug = 1 for k in range(m_alt,m,1): akkord = notenListe[k-1] for i in akkord: clef = i if clef[1] == 0: zug = 0 if clef[0] == 0: druck = 0 if (zug == 0 and druck == 0): richtungsListe.append(4) #Takt muss aufgespalten werden if (zug == 0 and druck == 1): richtungsListe.append(1) #Takt muss auf Druck gespielt werden if (druck == 0 and zug == 1): richtungsListe.append(-1) #Takt muss auf Zug gespielt werden if (druck == 1 and zug == 1): richtungsListe.append(0) #Takt kann in beiden Richtungen gespielt werden m_alt = m for k in range(0,len(barListe)-1,1): hinzu = richtungsListe[barListe[k]:barListe[k+1]] druckzugListe.append(hinzu) richtungsListe=[] for a in druckzugListe: #abschnittsweise ausgleichen richtungsListe.append(ausgleichen(a)) druckzugListe = [] for a in richtungsListe: for b in a: druckzugListe.append(b) return druckzugListe #zu jedem Takt die Richtung liefern def berechneGriff(note): info1 = ['D5','B5','A6','E6'] #kann dem Spieler angepasst werden info2 = ['E4','F4','G4','A4','B4','C5','D5','E5','F5','G5','A5','B5', 'C6','D6','E6','F6','G6','A6','B6','C7','D7','E7',] if note > 70: griff = info1[note-90] elif note > 21: griff = info2[note-50]+'x' elif note >= 0: griff = info2[note] else: griff = 'XX' return griff def createGriff(druckzugListe): n = len(taktListe) for k in range(0,n-1,1): beginn = taktListe[k] ende = taktListe[k+1] richtung = druckzugListe[k] for j in range(beginn,ende,1): notenInfo = notenListe[j-1] remember = [] for a in notenInfo: #es könnte ein Akkord sein if richtung == 1: #stossen note = a[0] else: #ziehen note = a[1] info = berechneGriff(note) for r in remember: if info[:2] == r: info += '*' #verdeckte Kreuznote verdecktListe.append(j) remember.append(info[:2]) if info == 'XX': #Griff existiert nicht ausnahmeListe.append(j-1) griffListe.append(info) def faerbeNoten(druckzugListe): if len(ausnahmeListe) == 0: return else: messageBox('Alert','Einzelne Noten können nicht gegriffen werden. Die Akkorde, in denen sie vorkommen, werden rot eingefärbt') for j in ausnahmeListe: #Nicht spielbare Akkorde rot einfärben k = 0 for a in activeScore().noteObjs(): if a.isChord(): if k == j: a.setColor(Color.RGB(255,0,0)) k += 1 def drawBalken(breite,dicke): return dict( type = 'line', x1 = -2, y1 = 9, x2 = -2 + breite, y2 = 9, lineWidth = dicke) def druckBalken(score): #Kodiert Druck- (dick) und Zugrichtung (dünn) -> m=score.nSystems() #als Linie unter den Notenzeilen tak = 1 #Taktnummer n = 0 for a in score.system(0).noteObjs(): #Erste Zeile des Musikstücks if (a.isChord() and n == 0): #Erste Note b = a x0 = a.posX(True) if (a.isChord() and n < taktListe[1]-1): #sucht Ende des ersten Taktes n += 1 elif (a.isChord() or a.isRest()): t = a.time() test = (t-merkTime)/takt if test-tak >=0: #neuer Takt beginnt x1 = a.posX(True) breite = (x1 - x0) dicke = 0.4 - 0.2 * druckzugListe[tak-1] b.addDrawObj(drawBalken(breite,dicke)) b = a #merke erste Note oder Pause im Takt x0 = x1 tak += 1 x1 = a.posX(True) + 7 #letzter Takt in der ersten Zeile if a.isBarline(): x1=x1-5 breite = (x1 - x0) dicke = 0.4 - 0.2 * druckzugListe[tak-1] b.addDrawObj(drawBalken(breite,dicke)) for k in range(1,m,1): #alle anderen Zeilen n = 0 ta = 1 for a in score.system(k).noteObjs(): if ((a.isChord() or a.isRest()) and n == 0): #erste Note oder Pause in der Zeile b = a x0 = a.posX(True) n += 1 elif (a.isChord() or a.isRest()): t = a.time() test = t/takt if test-ta >= 0: #neuer Takt beginnt ta += 1 tak += 1 x1 = a.posX(True) breite = (x1 - x0) dicke = 0.4 - 0.2 * druckzugListe[tak-1] b.addDrawObj(drawBalken(breite,dicke)) b = a #merke erste Note oder Pause im Takt x0 = x1 x1 = a.posX(False) + 7 if a.isBarline(): x1=x1-5 breite = (x1 - x0) if tak < len(druckzugListe): dicke = 0.4 - 0.2 * druckzugListe[tak] b.addDrawObj(drawBalken(breite,dicke)) tak += 1 def Text(): return dict( type = 'text', x = -3, y = -6, content = 'Schwyzerörgeli B') def writeSchwyzeroergeli(score): k = 0 for obj in score.noteObjs(): if k > 0: return if obj.isChord(): obj.addDrawObj(Text()) k += 1 def getElementObjects(objList): newList = NodeList() for n in range(objList.length): if objList[n].nodeType == objList[n].ELEMENT_NODE: newList.append(objList[n]) return newList def rewrite(score): systems = score.getElementsByTagName('system') k=0 for sy in range(systems.length): staves = systems[sy].getElementsByTagName('staff') for st in range(staves.length): for keySign in staves[st].getElementsByTagName('keySign'): #Tonart entfernen keySign.parentNode.removeChild(keySign) for clefSign in staves[st].getElementsByTagName('clefSign'): #Schlüssel entfernen clefSign.parentNode.removeChild(clefSign) voices = staves[st].getElementsByTagName('voice') for vo in range(voices.length): noteObjects = getElementObjects(voices[vo].getElementsByTagName('noteObjects')[0].childNodes) for ob in range(noteObjects.length): nv = noteObjects[ob].nodeName if nv == 'chord': heads = getElementObjects(noteObjects[ob].getElementsByTagName('heads')[0].childNodes) for hd in range(heads.length): griff = griffListe[k] if griff[len(griff)-1]=='x': heads[hd].setAttribute('shape','crossCircle') #Kreuzton heads[hd].setAttribute('pitch',griff[:2]) #Griffbild zeichnen alter = heads[hd].getElementsByTagName('alter') if alter: alter[0].setAttribute('step','0') #Vorzeichen entfernen if griff[len(griff)-1]=='*': #verdeckte Kreuznote alter[0].setAttribute('step','2') k += 1 class ScoreChange(ScoreChange): def changeScore(self,score): rewrite(score) #------------------------------------------------------------------------------------------------------------- # M a i n #------------------------------------------------------------------------------------------------------------- s = activeScore() s.registerUndo("swiss_oergeli") analyseScore(s) #Musikstück analysieren liste = createRichtung() #Taktweise Balgrichtung ermitteln createGriff(liste) faerbeNoten(liste) #Nicht spielbare Akkorde rot einfärben if len(ausnahmeListe) == 0: tempInput = tempfile.mktemp('.capx') tempOutput = tempfile.mktemp('.capx') activeScore().write(tempInput) ScoreChange(tempInput,tempOutput) activeScore().read(tempOutput) os.remove(tempInput) os.remove(tempOutput) druckBalken(s) writeSchwyzeroergeli(s)