# -*- coding: ISO-8859-1 -*- """ capellaScript -- Copyright (c) 2003 Peter Becker >>> Spezial_Achtel Dieses Script erzeugt überbalkte Achtelpausen. || Zur Zeit sind folgende Taktarten, auch gemischt, unterstützt:| 2/4, 4/8, 6/8, 4/4, 2/2, 4/2, C und allaBreve.| Die Überbalkung startet auf den Schlag.| Es werden 16tel und 8tel gemischt unterstützt ausser bei 6/8.| Überbalkte 16tel sind nicht unterstützt (Capella Problem).| Einige unsinnige Muster werden unterdrückt.|| Bei Problemen bitte eine Mail an peter_becker@freenet.de <<< """ # 29.12.2003 Erste Version # 30.12.2003 Maske erweitert # 22.01.2004 Artikulationszeichen an unsichtbarer Note entfernen # unsichtbare Note in die Mitte, wg. Hilfslinienproblem # 02.03.2004 Um einen Absturz zu vermeiden wird bei fehlender Taktangabe # 4/4 angenommen, Mustererkennung verbessert # 03.03.2004 unsichtbare Note auf A5 geändert um überlange Hälse zu vermeiden # 11.04.2004 Mustererkennung erweitert, Balkengruppierung wird nicht mehr verändert # Formatierungsdialog hinzugefügt # 12.11.2004 Formatierungsfehler bei Auftakt behoben # 25.01.2005 Takwechsel werden jetzt unterstützt # 26.01.2005 6/8 Option in der Auswahl entfernt. Jetzt automatisch. # 27.01.2005 überflüssige Grafikobjekte an der unsichtbaren Note löschen, # tolerieren von ganzen und halben Noten im 6/8 Takt # Vorschlagnoten ignorieren # 02.06.2005 Taktlänge wird u.U. falsch berechnet # 16.12.2007 Bassschlüssel bei unsichtbarer Note berücksichtigen # 25.08.2009 Bugfix, grafische 16-tel Pause # 12.05.2010 Diverse mehrfache beams unterdrückt, bei mehreren Köpfen am Hals silent=true an allen Köpfen, # Silbenverdopplung bei Liedtext beseitigt # 19.06.2010 beamGrouping je nach Mustergröße anpassen # eventuell definierter beam an Noten löschen um offene beams zu vermeiden import xml.dom, tempfile from caplib.capDOM import ScoreChange from xml.dom.minidom import NodeList, Node, Element doc = [] # parentNode von score impBarline = 0 summe = 0 notenWert = dict( W16 = dict(wert=0.25 , punkt=0.125 ), W8 = dict(wert=0.5 , punkt=0.25 ), W4 = dict(wert=1.0 , punkt=0.5 ), W2 = dict(wert=2.0 , punkt=1.0 ), W1 = dict(wert=4.0 , punkt=2.0 ) ) #xx = notenWert['W16']['wert'] #so wird das Dictionary abgefragt #messageBox('Dict',str(notenWert)) #messageBox('Dict',str(xx)) jetzt wird 0.25 ausgegeben class SpezialAchtel(ScoreChange): def changeScore(self, score): global doc doc = score.parentNode changeDoc(score) def changeDoc(score): global pausenTyp, zifferPos, summe, formatTyp, clef Cnt = 0 m0 = ' ' formatTypOrg = formatTyp # 4er Muster # c=chord, r=rest, 1=8tel punktiert, 2=8tel, 3=16tel m1 = ' c2r2c2r2' m2 = ' c2r2c1r3' m3 = ' c2r2c2c2' m4 = ' c2r2c1c3' m5 = ' c1r3c2r2' #überbalktes 16tel, case1 m6 = ' c1r3c1r3' #überbalktes 16tel, case1 m7 = ' c1r3c2c2' #überbalktes 16tel, case2 m8 = ' c1r3c1c3' #überbalktes 16tel, case2 m9 = ' r2c2r2c2' m10 = ' r1c3r2c2' m11 = ' c2c2r2c2' m12 = ' c1c3r2c2' m13 = ' r2c2r1c3' m14 = ' r1c3r1c3' #sehr ungewöhnlich, case2 m15 = ' c2c2r1c3' m16 = ' c1c3r1c3' m17 = ' c3r1c2r2' m18 = ' c3r1c3r1' #sehr ungewöhnlich, case1 m19 = ' r3c1r2c2' m20 = ' r3c1r3c1' #überbalktes 16tel, case2 m21 = ' c2r2c3r1' m22 = ' c3r1c2c2' m23 = ' c3c1r2c2' m24 = ' c3r1c3c1' #sehr ungewöhnlich, case1 m25 = ' c3c1r3c1' #überbalktes 16tel, case2 mCase1a = m1 # klassisch ohne 16tel mCase1b = m9 mCase2a = m1 + m2 + m17 + m21 # klassisch mit 16tel mCase2b = m9 + m10 + m13 + m19 mCase3a = m1 + m3 # modern ohne 16tel mCase3b = m9 + m11 mCase4a = m1 + m2 + m3 + m4 + m17 + m21 + m22 # modern mit 16tel mCase4b = m9 + m10 + m11 + m12 + m13 + m15 + m16 + m19 + m23 mCase5a = m1 + m2 + m3 + m4 + m5 + m6 + m7 + m8 + m17 + m18 + m21 + m22 + m24 # experimentell mCase5b = m9 + m10 + m11 + m12 + m13 + m14 + m15 + m16 + m19 + m20 + m23 + m25 # 3er Muster m30 = ' c2r2c2' mCase9a = m30 supTime = '2/4, 4/8, 4/4, 2/2, 4/2, C, allaBreve, 6/8' getClef(score) t = getTime(score) if t not in (supTime): #messageBox('SpezialAchtel',str(t) + ' Takt nicht unterstützt') return if formatTyp == 5: if t <> '6/8': #messageBox('SpezialAchtel','6/8 Takt wurde ausgewählt.' + '\n' + 'Das Stück steht aber im ' + str(t) + ' Takt') return elif formatTyp <> 5: if t == '6/8': # 6/8 forcieren formatTyp = 5 for system in score.getElementsByTagName('system'): # beamGrouping je nach Mustergröße anpassen if formatTyp == 0 or formatTyp == 1: system.setAttribute('beamGrouping','2') else: system.setAttribute('beamGrouping','3') for voice in score.getElementsByTagName('voice'): noteObjects = voice.getElementsByTagName('noteObjects') # Liste mit einem Element [0] for child in noteObjects[0].childNodes: if child.nodeType == child.ELEMENT_NODE: if child.tagName == 'timeSign': ChildTagName = child.tagName time = child.getAttribute('time') if time == '6/8' : formatTyp = 5 else: formatTyp = formatTypOrg #messageBox('METER',str(ChildTagName) + ' ' + str(time) + ' ' + str(formatTyp)) if child.tagName == 'rest' or child.tagName == 'chord': ChildTagName = child.tagName duration = child.getElementsByTagName('duration')[0] if duration.hasAttribute('noDuration'): xx = 0 # ignoriere Vorschlagnoten elif duration.getAttribute('base') == '1/8' or duration.getAttribute('base') == '1/16': impBarline = barLine(duration) dauer = duration.getAttribute('base') dot = '0' m = ' ' if duration.getAttribute('dots'): dot = '1' m = ChildTagName[0:1] if dauer == '1/8' and dot == '1': m = m + '1' elif dauer == '1/8' and dot == '0': m = m + '2' elif dauer == '1/16': m = m + '3' if Cnt == 0: #messageBox('Cnt0',str(child.tagName) + ' ' + 'mx=' + str(mx)) Cnt = 1 element1 = child # erstes Element merken mx = m0 + m # Maske erzeugen if impBarline == 1: #messageBox('Cnt0',str(impBarline)) Cnt = 0 mx = ' ' elif Cnt == 1: #messageBox('Cnt1',str(child.tagName) + ' ' + 'mx=' + str(mx)) Cnt = 2 element2 = child # zweites Element merken mx = mx + m # Maske erzeugen if impBarline == 1: #messageBox('Cnt1',str(impBarline)) Cnt = 0 mx = ' ' elif Cnt == 2: #messageBox('Cnt2',str(child.tagName) + ' ' + 'mx=' + str(mx)) Cnt = 3 element3 = child # drittes Element merken mx = mx + m # Maske erzeugen if formatTyp == 5: if mx in mCase9a: #messageBox('Cnt2',str(mx) + ' ' + 'in mCase9a') replaceRest(score, element2, element3, element1, element1, element1) # Die Pause umwandeln Cnt = 0 mx = ' ' if impBarline == 1: #messageBox('Cnt2','implicit Barline') Cnt = 0 mx = ' ' elif Cnt == 3: Cnt = 0 element4 = child # viertes Element merken mx = mx + m # Maske erzeugen if formatTyp == 0: if mx in mCase1b: replaceRest(score, element3, element4, element2, element1, element3) # Die Pause umwandeln mx = ' ' elif mx in mCase1a: replaceRest(score, element2, element3, element1, element1, element3) # Die Pause umwandeln mx = ' ' elif formatTyp == 1: if mx in mCase2b: replaceRest(score, element3, element4, element2, element1, element3) # Die Pause umwandeln mx = ' ' elif mx in mCase2a: replaceRest(score, element2, element3, element1, element1, element3) # Die Pause umwandeln mx = ' ' elif formatTyp == 2: if mx in mCase3b: replaceRest(score, element3, element4, element2, element1, element3) # Die Pause umwandeln mx = ' ' elif mx in mCase3a: replaceRest(score, element2, element3, element1, element1, element3) # Die Pause umwandeln mx = ' ' elif formatTyp == 3: if mx in mCase4b: replaceRest(score, element3, element4, element2, element1, element3) # Die Pause umwandeln mx = ' ' elif mx in mCase4a: replaceRest(score, element2, element3, element1, element1, element3) # Die Pause umwandeln mx = ' ' elif formatTyp == 4: if mx in mCase5b: replaceRest(score, element3, element4, element2, element1, element3) # Die Pause umwandeln mx = ' ' elif mx in mCase5a: replaceRest(score, element2, element3, element1, element1, element3) # Die Pause umwandeln mx = '' if impBarline == 1: #messageBox('implicit Barline','implicit Barline found') Cnt = 0 mx = ' ' else: #messageBox('ELSE1',str(Cnt) + ' ' + str(mx)) Cnt = 0 mx = ' ' impBarline = barLine(duration) # Takt weiterrechnen 2.6.2005 #messageBox('ELSE2',str(Cnt) + ' ' + str(mx) + ' ' + str(summe)) #messageBox('nach Noten/Chords',str(Cnt) + ' ' + str(mx)) elif child.tagName <> 'chord' and child.tagName <> 'rest': #messageBox('Tag gefunden',str(child.tagName)) Cnt = 0 mx = ' ' summe = 0 # setzt nach explizitem Taktstrich den Summenzähler von barLine() zurück def barLine(duration): #gibt 1 zurück wenn impliziter Taktstrich global notenWert, impBarline, summe, formatTyp if formatTyp == 5: # Anzahl 4tel pro Figur takt = 1.5 # 6/8 tel Takt else: takt = 2 #2er und 4er Takt wert1 = 0 wert2 = 0 xxx = '000' dauer_noteObj = duration.getAttribute('base') dot = duration.getAttribute('dots') if dauer_noteObj == '1/16': wert1 = notenWert['W16']['wert'] if dot: wert2 = notenWert['W16']['punkt'] if dauer_noteObj == '1/8': wert1 = notenWert['W8']['wert'] if dot: wert2 = notenWert['W8']['punkt'] if dauer_noteObj == '1/4': wert1 = notenWert['W4']['wert'] if dot: wert2 = notenWert['W4']['punkt'] if dauer_noteObj == '1/2': wert1 = notenWert['W2']['wert'] if dot: wert2 = notenWert['W2']['punkt'] if dauer_noteObj == '1/1': wert1 = notenWert['W1']['wert'] if dot: wert2 = notenWert['W1']['punkt'] summe = summe + wert1 + wert2 if summe == takt or summe == takt*2: # takt*2 ist Fix für halbe und ganze Noten im 6/8 Takt impBarline = 1 summe = 0 else: impBarline = 0 return(impBarline) def getTime(score): if score.getElementsByTagName('timeSign'): ts = score.getElementsByTagName('timeSign')[0] t = ts.getAttribute('time') return(t) else: #messageBox('Time','Taktangabe fehlt, 4/4 wird angenommen') return('4/4') def getClef(score): global clef clef = 'None' if score.getElementsByTagName('clefSign'): cl = score.getElementsByTagName('clefSign')[0] if cl: clef = cl.getAttribute('clef') return def latin1_d(u): return u.decode('Latin-1') def addElementNode(el,tagName): # add new Node to el if Node "tagName" does not exist # otherwise return the existing Node global doc childs = el.childNodes for n in range(childs.length): if childs[n].nodeType ==childs[n].ELEMENT_NODE and childs[n].tagName == tagName: return childs[n] newChild = doc.createElement(tagName) el.appendChild(newChild) return newChild def addNewElementNode(el,tagName): # add new Node with tagName "tagName" to el global doc newChild = doc.createElement(tagName) el.appendChild(newChild) return newChild def addDrawObj(chord, sym, x, y): global doc if chord.nodeType == chord.ELEMENT_NODE and chord.tagName == 'chord': drawObjects = addElementNode(chord,'drawObjects') drawObj = addNewElementNode(drawObjects,'drawObj') text = addNewElementNode(drawObj,'text') text.setAttribute('x', x) text.setAttribute('y', y) text.setAttribute('align','center') font = addNewElementNode(text,'font') font.setAttribute('face','capella3') font.setAttribute('height','18') font.setAttribute('charSet','2') font.setAttribute('pitchAndFamily','2') content = addNewElementNode(text,'content') textNode = doc.createTextNode(latin1_d(sym)) content.appendChild(textNode) def replaceRest(score, firstRest, child, prevNote, firstNote, thirdNote): global clef note = child.cloneNode('TRUE') duration = firstRest.getElementsByTagName('duration')[0] noteDauer = duration.getAttribute('base') noteDot = duration.getAttribute('dots') child.parentNode.insertBefore(note,child) # Achtel nach Pause verdoppeln dO=child.previousSibling.getElementsByTagName('drawObjects') # falls Grafikobjekte an der Note lDo=len(dO) # hängen, if lDo <> 0: # diese Objekte löschen dO[0].parentNode.removeChild(dO[0]) ly=child.previousSibling.getElementsByTagName('lyric') # falls Lyrics an der Note lLy=len(ly) # hängen, if lLy <> 0: # diese Objekte löschen ly[0].parentNode.removeChild(ly[0]) bm=child.previousSibling.getElementsByTagName('beam') # falls beam an der Note hängt lbm=len(bm) # if lbm <> 0: # diese Objekte löschen bm[0].parentNode.removeChild(bm[0]) firstRest.parentNode.removeChild(firstRest) # und die Pause löschen invisible = score.parentNode.createElement('display') invisible.setAttribute('invisible','true') child.previousSibling.appendChild(invisible) # vedoppelte Note unsichtbar machen #beam = score.parentNode.createElement('beam') # an unsichtbarer Note Balken forcen #beam.setAttribute('group','force') #child.previousSibling.appendChild(beam) beam2 = score.parentNode.createElement('beam') # an Note vor unsichtbarer Note Balken forcen beam2.setAttribute('group','force') prevNote.appendChild(beam2) #beam3 = score.parentNode.createElement('beam') # an fehlender Note Balken forcen #beam3.setAttribute('group','force') #if firstRest <> thirdNote: # bei case1 an dritter Note Balken forcen # thirdNote.appendChild(beam3) #else: # case2 falls erstes Objekt eine Note Balken forcen # if firstNote.tagName == 'chord': # firstNote.appendChild(beam3) prevChild = child.previousSibling if noteDauer == '1/8': addDrawObj(prevChild, 'L', '0', '0') # grafische Pause einsetzen 1/8 else: addDrawObj(prevChild, 'M', '0', '0') # grafische Pause einsetzen 1/16 if noteDot: addDrawObj(prevChild, '.', '0.5', '-0.5') head = prevChild.getElementsByTagName('head')[0] heads = prevChild.getElementsByTagName('head') #messageBox('HEAD',str(head)) for n in range(heads.length): #for head in prevChild.getElementsByTagName('head'): heads[n].setAttribute('silent','true') # und Note stummschalten, alle Köpfe if clef == 'bass': head.setAttribute('pitch','C4') # Note ohne Hilfslinien else: head.setAttribute('pitch','A5') # Note ohne Hilfslinien duration = prevChild.getElementsByTagName('duration')[0] duration.setAttribute('base',noteDauer) if noteDot: duration.setAttribute('dots',noteDot) else: if duration.hasAttribute('dots'): duration.removeAttribute('dots') if prevChild.getElementsByTagName('articulation'): # falls Artikulationszeichen, weg damit arti = prevChild.getElementsByTagName('articulation')[0] prevChild.removeChild(arti) def saDialog(): global formatTyp options = ScriptOptions() opt = options.get() placeholder1 = Label(' ',width=1) placeholder2 = Label(' ',width=1) placeholder3 = Label(' ',width=1) placeholder4 = Label(' ',width=1) # radFormatTyp = Radio(['klassisch ( 2er Gruppe nur 8tel )','klassisch ( 2er Gruppe mit 16tel )','modern ( 4er Gruppe nur 8tel )','modern ( 4er Gruppe mit 16tel )','experimental ( alles - sinnloses wird nicht unterdrückt )','6/8 Takt ( nur 8tel )'],text='Formatierungsoption auswählen',value=int(opt.get('FormatTyp','0'))) radFormatTyp = Radio(['klassisch ( 2er Gruppe nur 8tel )','klassisch ( 2er Gruppe mit 16tel )','modern ( 4er Gruppe nur 8tel )','modern ( 4er Gruppe mit 16tel )','experimental ( alles - sinnloses wird nicht unterdrückt )'],text='Formatierungsoption auswählen',value=int(opt.get('FormatTyp','0'))) subboxFormat = HBox([radFormatTyp,placeholder2],padding=4) mainboxFormat = VBox([subboxFormat],text='Format') box = VBox([mainboxFormat,placeholder1],padding=1) dlg = Dialog('Spezial Achtel', box) if dlg.run(): formatTyp = radFormatTyp.value() options.set(opt) return True else: return False # Hauptprogramm: if activeScore(): if saDialog(): activeScore().registerUndo("SpezialAchtel") tempInput = tempfile.mktemp('.capx') tempOutput = tempfile.mktemp('.capx') activeScore().write(tempInput) SpezialAchtel(tempInput, tempOutput) activeScore().read(tempOutput) os.remove(tempInput) os.remove(tempOutput)