# -*- coding: ISO-8859-1 -*- """ capellaScript -- Bernd Jungmann >>> Balken über Pausen hinweg fortsetzen 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:| - Alle markierten Noten und Pausen sind | gleichlang| - Anfang und Ende der Markierung ist | jeweils eine Note (bzw. Akkord)| | Version 3: Bernd Jungmann 2.2.05| <<< Version 3: Bernd Jungmann 2.2.05| - unsichtbar gemachte Noten jetzt auch unhörbar| Version 2: Bernd Jungmann 22.1.05 - jetzt auch Mehrfachpausen überbrückt - letzte Note im Umwandelbereich nicht mehr mit beam-force Attribut Version 1: Bernd Jungmann 10.1.05| """ 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 # messageBox("__init__: objI1, objI2", str(self.objI1)+', '+str(self.objI2)) 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' class BalkenScoreChange (MarkedScoreChange): def changeElement(self, el): if self.isInMarkedArea(): if el.tagName == 'chord' or el.tagName == 'rest': # 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 # messageBox("Jetzt ändern",el.tagName) if el.tagName == 'chord': # 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) 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': # wir setzen anstelle der Pause den letzen Akkord duration = el.getElementsByTagName('duration')[0] rDur = duration.getAttribute('base') # 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' heads = self.lastchord.getElementsByTagName('heads')[0] newheads = el.appendChild(heads.cloneNode(True)) headlist = newheads.getElementsByTagName('head') for head in headlist: head.setAttribute('silent','true') # Drangehängten 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') # 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','0') 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) 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) voice = staff.voice(voiceind) no = voice.nNoteObjs() if objind <= no and objind2 <= no: # man kann auch rückwärts markieren. Wozu eigentlich?? if objind > objind2: obji = objind objind = objind2 objind2 = obji # wir untersuchen, ob gleichlange Balkennoten mit Pausen # dazwischen vorliegen firstobj = voice.noteObj(objind) duration = firstobj.duration() maxduration = Rational("1/8") if firstobj.isChord() and duration <= maxduration: ind = objind + 1 nPausen = 0 while ind < objind2: obj = voice.noteObj(ind) if duration == obj.duration(): if obj.isChord():pass elif obj.isRest(): nPausen = nPausen + 1 else: break ind = ind + 1 else: break if ind == objind2 and nPausen > 0 and obj.isChord(): # wir sind sicher, dass erstes und letztes Objekt Akkorde sind # und dass dazwischen höchstens Pausen gleicher Länge liegen. if 2 == messageBox("Balken verlängern", str(nPausen) + " " + str(duration) + "-Pausen mit Balken überbrücken?", 1,2): score.registerUndo("Balken über Pausen") tempFile1 = tempfile.mktemp('.capx') tempFile2 = tempfile.mktemp('.capx') # messageBox("BalkenVerlaengern - jetzt ScoreChange rufen",str(tempFile1)) score.write(tempFile1) BalkenScoreChange(tempFile1,tempFile2,(sysind, staffind, voiceind, objind),\ (sysind, staffind, voiceind, objind2)) # messageBox("BalkenVerlaengern - jetzt modifizierte Partitur laden",str(tempFile2)) score.read(tempFile2) os.remove(tempFile1) os.remove(tempFile2) else: messageBox("BalkenVerlaengern - keine Aktion!","Der markierte Bereich darf nur Noten und Pausen gleicher Länge enthalten \n\ und muß mit einer Note aufhören und mindestens eine Pause enthalten") else: messageBox("BalkenVerlaengern - keine Aktion!","Der markierte Bereich muss mit einer Note <= 1/8 anfangen") else: messageBox("Klappt nicht:","objind "+str(objind)+"objind2 "+str(objind2)+" no "+str(no)) else: messageBox("BalkenVerlaengern - 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)