# -*- coding: ISO-8859-1 -*- """ capellaScript -- Urs Ganz >>> Pausen durch überbalkte Pausen ersetzen In einer Stimme markierte Noten werden | über Pausen hinweg mit Balken verbunden | nach der Methode, die in der Capella-Hilfe | im Kapitel "12.2 Grafikobjekte an (unsichtbaren)| Noten verankern" beschrieben ist.| | Voraussetzung:| - vor den markierten Pausen muss sich| mindestens 1 Note <= 1/8. im System befinden| | - mindestens 1 Pause markiert | | - Markierte Noten und Pausen <= 1/8. >= 1/64| | | Version 6: Urs Ganz 06.06.2005| <<< History:| Version 6: Urs Ganz 06.06.2005| - Absturz behoben, wenn Cursor am Zeilenende ohne Markierung| Version 5: Urs Ganz 28.04.2005| - Absturz behoben, wenn Nachbarnoten zu Pause keine| Dauer haben (z.B. Vorschlagsnoten)| Version 4: Urs Ganz 14.04.2005| - erzeugt, wenn möglich Stummelbalken| - bei punktierten Pausen werden jetzt auch punktierte| Ersatznoten erzeugt| Version 3: Urs Ganz 11.04.2005| - Hänger behoben. Andere Ermittlung der Referenznote| Version 2: Urs Ganz 25.03.2005| - Pausenbereich erweitert von 1/8. bis 1/64| Version 1: Urs Ganz 18.03.2005| - Pausen mit unterschiedlicher Dauer erlaubt| - punktierte Pausen erlaubt| Dieses Script wurde erstellt aus "BalkenVerlaengern.py"| Version 3: Bernd Jungmann 02.02.2005| - unsichtbar gemachte Noten jetzt auch unhörbar| Version 2: Bernd Jungmann 22.01.2005| - jetzt auch Mehrfachpausen überbrückt - letzte Note im Umwandelbereich nicht mehr mit beam-force Attribut Version 1: Bernd Jungmann 10.01.2005| """ from caplib.capDOM import ScoreChange import tempfile def latin1(u): return u.encode('Latin-1') class MarkedScoreChange (ScoreChange): def __init__(self, inputFile, outputFile, cursor1, cursor2): self.sysI1, self.staffI1, self.voiceI1, self.objI1 = cursor1 self.sysI2,self.staffI2,self.voiceI2,self.objI2 = cursor2 self.sysCurrent = 0 self.staffCurrent = 0 self.voiceCurrent = 0 self.objCurrent = 0 self.lastchord = 0 ScoreChange.__init__(self, inputFile, outputFile) def copyElement(self, el): ScoreChange.copyElement(self, el) # Positionsmerker aktualisieren if el.tagName == 'system': self.sysCurrent = self.sysCurrent + 1 self.staffCurrent = 0 self.voiceCurrent = 0 self.objCurrent = 0 if el.tagName == 'staff': self.staffCurrent = self.staffCurrent + 1 self.voiceCurrent = 0 self.objCurrent = 0 if el.tagName == 'voice': self.voiceCurrent = self.voiceCurrent + 1 self.objCurrent = 0 if el.tagName in ['clefSign','keySign','timeSign','chord','rest','ExplicitBarline']: self.objCurrent = self.objCurrent + 1 def isInMarkedArea(self): if self.sysI1 <= self.sysCurrent and self.sysCurrent < self.sysI2: return True if self.sysI1 == self.sysCurrent and self.sysCurrent == self.sysI2 \ and self.staffI1 == self.staffCurrent \ and self.voiceI1 == self.voiceCurrent \ and self.objI1 <= self.objCurrent and self.objCurrent < self.objI2: return True return False # capella3.ttf-Code für die Grafik-Pausen def getRestCode(rat): if str(rat) == "1/8": return 'L' if str(rat) == "1/16": return 'M' if str(rat) == "1/32": return 'N' return 'O' def getValue(rat): nDur0 = str(rat).replace('/','.') nDur1 = int(float(nDur0)) nDur2 = (float(nDur0) - nDur1) * 10 ** (len(str(rat)) -2) return nDur1 / nDur2 class BalkenScoreChange (MarkedScoreChange): def changeElement(self, el): if el.tagName in 'clefSign': global elmnt elmnt = 0 if el.tagName in 'chord' and not elmnt: duration = el.getElementsByTagName('duration')[0] rDur = duration.getAttribute('base') if getValue(rDur) <= getValue("3/8"): if self.lastchord: self.lastchord.unlink() self.lastchord = el.cloneNode(True) elmnt = 1 if self.isInMarkedArea(): if el.tagName == 'chord' or el.tagName == 'rest': duration = el.getElementsByTagName('duration')[0] rDur = duration.getAttribute('base') # jetzt sind wir in der Stimme, in der die Markierung ist. # Wir wissen bereits: Wir können hier alle Pausen ersetzen # durch Akkorde gleicher Spieldauer if el.tagName == 'chord': if getValue(rDur) <= getValue("3/8"): # wir merken uns den Akkord, um ihn unsichtbar an die Stelle der nächsten Pause zu setzen if self.lastchord: self.lastchord.unlink() self.lastchord = el.cloneNode(True) elmnt = 1 if self.objCurrent < self.objI2-1: # Außer beim letzten: Sicherstellen, dass der Balken durchgezogen ist oldbeams = el.getElementsByTagName('beam') if oldbeams: beam = oldbeams[0] else: beam = self.doc.createElement('beam') el.appendChild(beam) beam.setAttribute('group','force') elif el.tagName == 'rest' and elmnt == 1 and getValue(rDur) < getValue("1/4"): # wir setzen anstelle der Pause den letzen Akkord dots = duration.getAttribute('dots') # Grafik-Offset für Stummelbalken offs = 0.0 if rDur == "1/16": offw = 1.5 elif rDur == "1/32": offw = 1.25 elif rDur == "1/64": offw = 1.0 else: offw = 0.0 # Prüfen, ob Stummelbalken erzeugt werden kann prevobj = voice.noteObj(self.objCurrent - 1) pduration = prevobj.duration() if self.objCurrent < no - 2: nextobj = voice.noteObj(self.objCurrent + 1) nduration = nextobj.duration() if prevobj.isChord() and nextobj.isChord() and pduration <> 0 and nduration <> 0 \ and getValue(pduration) < getValue("1/4") and getValue(nduration) < getValue("1/4"): if getValue(pduration) == getValue(rDur): offs = offs - offw if getValue(nduration) == getValue(rDur): offs = offs + offw # die Pause könnte eine verticalPos haben. Ggfls. wegnehmen verticalPos = el.getElementsByTagName('verticalPos') if verticalPos: el.removeChild(verticalPos[0]) verticalPos[0].unlink() # Pause zu Akkord machen (da können ggfls. drangehängte drawObjects dranbleiben) el.tagName = 'chord' global cdone cdone = cdone + 1 heads = self.lastchord.getElementsByTagName('heads')[0] newheads = el.appendChild(heads.cloneNode(True)) headlist = newheads.getElementsByTagName('head') for head in headlist: head.setAttribute('silent','true') # Wert des Ersatz-Akkords = Wert der Pause setzen duration = self.doc.createElement('duration') duration.setAttribute('base',rDur) if dots: duration.setAttribute('dots',str(dots)) el.appendChild(duration) # Ersatz-Akkord unsichtbar machen olddisplays = el.getElementsByTagName('display') if olddisplays: display = olddisplays[0] else: display = self.doc.createElement('display') el.appendChild(display) display.setAttribute('invisible','true') display.setAttribute('xShift',str(offs)) # Sicherstellen, dass der Balken durchgezogen ist beam = self.doc.createElement('beam') beam.setAttribute('group','force') el.appendChild(beam) # Pause als DrawObject erzeugen font = self.doc.createElement('font') font.setAttribute('face','capella3') font.setAttribute('height','18') font.setAttribute('charSet','2') font.setAttribute('pitchAndFamily','2') text = self.doc.createElement('text') text.setAttribute('x',str(-offs)) text.setAttribute('y','0') text.appendChild(font) string = self.doc.createTextNode(getRestCode(rDur)) content = self.doc.createElement('content') content.appendChild(string) text.appendChild(content) drawObj = self.doc.createElement('drawObj') drawObj.appendChild(text) # Vorm Anhängen feststellen, ob's schon drawObjects gibt olddrawObjects = el.getElementsByTagName('drawObjects') if(olddrawObjects): drawObjects = olddrawObjects[0] else: drawObjects = self.doc.createElement('drawObjects') el.appendChild(drawObjects) drawObjects.appendChild(drawObj) if dots: # Punktierung als DrawObject erzeugen font = self.doc.createElement('font') font.setAttribute('face','capella3') font.setAttribute('height','18') font.setAttribute('charSet','2') font.setAttribute('pitchAndFamily','2') text = self.doc.createElement('text') text.setAttribute('x',str(-offs + 0.25)) text.setAttribute('y','-0.5') text.appendChild(font) string = self.doc.createTextNode('.') content = self.doc.createElement('content') content.appendChild(string) text.appendChild(content) drawObj = self.doc.createElement('drawObj') drawObj.appendChild(text) # Vorm Anhängen checken, ob's schon drawObjects gibt olddrawObjects = el.getElementsByTagName('drawObjects') if(olddrawObjects): drawObjects = olddrawObjects[0] else: drawObjects = self.doc.createElement('drawObjects') el.appendChild(drawObjects) drawObjects.appendChild(drawObj) def BalkenVerlaengern(score,(sysind, staffind, voiceind, objind),(sysind2, staffind2, voiceind2, objind2)): if sysind == sysind2 and staffind == staffind2 and voiceind == voiceind2: sys = score.system(sysind) staff = sys.staff(staffind) global voice voice = staff.voice(voiceind) global no no = voice.nNoteObjs() if objind <= no and objind2 <= no and (objind <> no or objind2 <> no): # man kann auch rückwärts markieren. Wozu eigentlich?? if objind > objind2: obji = objind objind = objind2 objind2 = obji # wir untersuchen, ob Balkennoten mit Pausen # dazwischen vorliegen global elmnt elmnt = 0 global cdone cdone = 0 firstobj = voice.noteObj(objind) duration = firstobj.duration() maxduration = Rational("3/16") minduration = Rational("1/64") ind = objind nPausen = 0 nMarken = 0 while ind < objind2: obj = voice.noteObj(ind) if obj.isChord():pass elif obj.isRest(): nMarken = 1 if obj.duration() <= maxduration and obj.duration() >= minduration: nPausen = nPausen + 1 else: nPausen = 0 ind = objind2 break ind = ind + 1 if ind == objind2 and nMarken > 0: if ind == objind2 and nPausen > 0: score.registerUndo("Balken über Pausen") tempFile1 = tempfile.mktemp('.capx') tempFile2 = tempfile.mktemp('.capx') score.write(tempFile1) BalkenScoreChange(tempFile1,tempFile2,(sysind, staffind, voiceind, objind),\ (sysind, staffind, voiceind, objind2)) if cdone == nPausen: score.read(tempFile2) os.remove(tempFile1) os.remove(tempFile2) else: messageBox("Int. Fehler","Bitte vor der Pause 1-2 Referenznoten mit 1/4-Kopf markieren!") else: messageBox("Keine Aktion!","Die Pausenwerte müssen <= 1/8. >= 1/64 sein") else: messageBox("Keine Aktion!","Keine Pausen markiert!") else: messageBox("Keine Aktion!","Keine Pausen markiert!") else: messageBox("Keine Aktion!","Markierung muss in einer einzigen Zeile und Stimme sein") # Hauptprogramm as = activeScore() if as: sel = curSelection() start = sel[0] stop = sel[1] BalkenVerlaengern(as, start, stop)