Beschreibung: ----------------------------------------------------------- Es werden von allen Zeilen der Musterpartitur Einzeldateien im .capx Format in ein wählbares Zielverzeichnis exportiert.
Dabei werden unsichtbare Füllpausen sichtbar gemacht, und Grafikobjekte erstellt, die für das ganze System gelten (z.B. D.S., D.C., Coda, Voltenklammern)
Voraussetzungen: - Die Musterpartitur muss mindestens 2 Stimmen enthalten - Es müssen alle Stimmen der Musterpartitur in allen Systemen vorhanden sein
Allerdings ist Rapidshare ein ziemlich ungeeignetes Medium um Skripte der Allgemeinheit zur Verfügung zu stellen. Auch im Sinne eines automatischen Downloads über das Skriptdownload Skript.
Wenn Du möchtest kann ich Deine Skripte über meine Seite zur Verfügung stellen.
Hallo zusammen. Mein Skript möchte ich den Usern nicht vorenthalten. Ich habe mir erlaubt auch ein paar Skripte anderer Autoren (siehe Kommentare) einzubinden. Ich hoffe jemand anders hat auch dafür Verwendung.
# -*- coding: ISO-8859-1 -*- """ capellaScript -- >>>Einzelstimmauszug Es werden von allen Zeilen der Musterpartitur Einzeldateien im .capx Format in ein wählbares Zielverzeichnis exportiert.||
Dabei werden unsichtbare Füllpausen sichtbar gemacht, und Grafikobjekte erstellt, die für das ganze System gelten (z.B. D.S., D.C., Coda, Voltenklammern). Diese Elemente sollten dabei nur in einer Stimme vorkommen, um keine Zeichen doppelt zu kopieren.||
Voraussetzungen:| - Die Musterpartitur muss mindestens 2 Stimmen enthalten| - Es müssen alle Stimmen der Musterpartitur in allen Systemen vorhanden sein| - Symbole, die für alle Systeme gelten, müssen entsprechend deklariert sein (Eigenschaften->Sichtbarkeit)|
||
History:| 11.10.2010 - neu erstellt| 14.07.2011 - Voltenklammern noteRange richtig gestellt| Voltenklammern ausrichten und Mehrtaktpausen erstellen integriert|
muss ein 'chord'- oder 'rest'-Knoten sein
# Grundnotenwert ermitteln duration = firstChildElement(note, 'duration') if duration.getAttribute('noDuration') == 'true': return 0 n = Rational(str(duration.getAttribute('base')))
# Punktierung dots = duration.getAttribute('dots') if dots != '': if int(dots) == 1: #Einfach punktiert n = (3 * n) / 2 else: #Doppelt punktiert n = (7 * n) / 4
# Triolen usw. ermitteln tuplet = firstChildElement(duration, 'tuplet') if tuplet != None: nenner = Rational(int(tuplet.getAttribute('count'))) zaehler = Rational(1) # Dreiertakt if tuplet.getAttribute('tripartite') == 'true': zaehler = Rational(3,2) while zaehler Abbruch und Meldung #------------------------------------------------------------------- def check_systems(score): global allSystems allSystems = 1 sysCount = 0
# Zeilen zählen, System zählen für Fehlerausgabe for system in score.getElementsByTagName('system'): staffCount = 0 sysCount += 1 for staff in system.getElementsByTagName('staff'): staffCount += 1 # Abbruchbedingung if staffCount != len(layoutZeilenListe): messageBox('Abbruch','Bitte fügen Sie zuerst mit "Strg + Eingabe" im System ' +str(sysCount) + ' alle Stimmen in alle Systeme ein!nDadurch werden leere Zeilen automatisch mit Pausen vorbelegt ') allSystems = 0 return 0 # Alles OK return 1
#------------------------------------------------------------------- # ScoreChange Klasse zum Vorbereiten der Partitur #------------------------------------------------------------------- class PrepareScore(ScoreChange): def changeScore(self, score): rests_visible(score) copy_drawObjs(score) copy_voltas(score) voltenklammern_ausrichten(score)
#------------------------------------------------------------------- # Macht automatisch eingefügte Füllpausen in Einzelstimmauszug sichtbar #------------------------------------------------------------------- def rests_visible(score): # Durchlaufen des xml Dokuments for rest in score.getElementsByTagName('rest'): for display in rest.getElementsByTagName('display'): # Nur automatisch erzeugte Füllpausen sichtbar machen if display.hasAttribute('filler') and display.hasAttribute('invisible') and display.getAttribute('filler') == 'true': display.removeAttribute('invisible') display.removeAttribute('filler')
#------------------------------------------------------------------- # Kopiert alle Elemente drawObj, die sich auf das System beziehen # dies sind vor allen: D.S., D.C., Coda usw. # So werden diese Zeichen auch in der Einzelstimme angezeigt #------------------------------------------------------------------- def copy_drawObjs(score): copyObjs=[] #zu kopierende drawObj Objekte copyPattern = ['y','$','n','o','d','e'] # DS_1, DS_2, Coda_1 (groß), Coda_2 (klein), D.C., D.S. # Vergleich mit drawObj->text->content, wenn drawObj->text->font.getAttribute('face') == 'capella'
# Durchlaufen des Dokuments, mit der Möglichkeit auf aktuell gültige Nodes direkt zuzugreifen # Erfassen der zu kopierenden Zeichen # System -> Zeile -> Stimme -> Noten/Pausen -> Zeichen for system in score.getElementsByTagName('system'): for staff in system.getElementsByTagName('staff'): for voice in staff.getElementsByTagName('voice'): beginn = Rational(0) #Zählzeit Beginn noteObjects = firstChildElement(voice,'noteObjects') for chord_rest in noteObjects.childNodes: if chord_rest.nodeType == chord_rest.ELEMENT_NODE: if chord_rest.tagName in ['rest', 'chord','barline']: for drawObj in chord_rest.getElementsByTagName('drawObj'): # Voltenklammern ------------------------------------------- if firstChildElement(drawObj, 'volta'): continue #werden extra behandelt # für das ganze System gültige Zeichen ab Capella 7 -------------------------- if firstChildElement(drawObj,'basic'): for basic in drawObj.getElementsByTagName('basic'): if basic.hasAttribute and basic.getAttribute('scope') == "system": #nur system relevante Zeichen copyObjs.append((system, staff, chord_rest, drawObj, beginn)) #Tupel erzeugen continue # Altes Format für die speziellen Zeichen -------------------- if firstChildElement(drawObj,'text'): for content in drawObj.getElementsByTagName('content'): if latin1(content.firstChild.nodeValue) in copyPattern: text = firstChildElement(drawObj, 'text') font = firstChildElement(text,'font') if 'capella' in font.getAttribute('face'): copyObjs.append((system, staff, chord_rest, drawObj, beginn)) #Tupel erzeugen continue # Erweiterbar für andere Elemente ------------------------------------ # ... # Notenwerte aufsummieren für Zählzeit if chord_rest.tagName not in ['barline']: beginn += getDuration(chord_rest)
# Objekte kopieren anhand der übergebenen Referenzen kopierenErfolgreich = 0 #Für Fehlermedlung anzahlObjekte = 0 #Für Fehlermedlung # ---------------- Durchlaufen der Grafikobjekte und Kopieren --------------------------- for s, st, c_r, dO, b in copyObjs: #b ist der Beginn des Zeichens # zu kopierende Objekte zählen anzahlObjekte += 1 # Durchlaufen aller Notenzeilen (verschiedenen Einzelstimmen) for staff in s.getElementsByTagName('staff'): if st == staff: # die Notenzeile, in der das urpsrüngliche Zeichen steht wird übersprungen continue #nur erste Stimme bearbeiten, dmait keine Zeichen doppelt kopiert werden voices = firstChildElement(staff,'voices') voice = firstChildElement(voices,'voice') #nach jeder Stimme die Zählung auf Null setzen dauer = Rational(0) # Noten und Pausen durchlaufen noteObjects = firstChildElement(voice,'noteObjects') for chord_rest in noteObjects.childNodes: if chord_rest.nodeType == chord_rest.ELEMENT_NODE: if chord_rest.tagName in ['rest', 'chord', 'barline']: # Zählzeit im System ermitteln, falls kein Taktstrich if chord_rest.tagName not in ['barline']: dauer += getDuration(chord_rest) # Bei gleicher Zählzeit in anderer Zeile wird das Zeichen reinkopiert # Falls das Objekt an einem Taktstrich war, muss es auch an einen Taktstrich kopiert werden if (dauer >= b and c_r.tagName == chord_rest.tagName == 'barline') or (dauer > b and c_r.tagName != 'barline' ): # Knoten erzeugen, falls noch nicht vorhanden drawObjects = firstChildElement(chord_rest,'drawObjects') if drawObjects == None: drawObjects = score.parentNode.createElement('drawObjects') chord_rest.appendChild(drawObjects) # Zeichen rekursiv kopieren (deep=1) dOClone = dO.cloneNode(1) drawObjects.appendChild(dOClone) # kopierte Objekte zählen kopierenErfolgreich += 1 break
# Die Objekte müssen in alle anderen Systeme kopiert werden --> (Anzahl_systeme -1) * Objekte if anzahlObjekte * (len(layoutZeilenListe)-1) != kopierenErfolgreich: messageBox('Fehler', str((anzahlObjekte * (len(layoutZeilenListe)-1))-kopierenErfolgreich) + ' Objekt(e) können nicht kopiert werden.nnStellen Sie sicher,' ' dass alle Takte vollständig sind, und die Taktstriche in allen Zeilen gleich sind.')
#------------------------------------------------------------------- # Kopiert Voltenklammern (drawObject) # Dabei wird für jede Zeile der entsprechende NoteRange berechnet #------------------------------------------------------------------- def copy_voltas(score): copyObjs=[] #zu kopierende drawObj Objekte
# Durchlaufen des Dokuments, mit der Möglichkeit auf aktuell gültige Nodes direkt zuzugreifen # Erfassen der zu kopierenden Zeichen # System -> Zeile -> Stimme -> Noten/Pausen -> Zeichen for system in score.getElementsByTagName('system'): for staff in system.getElementsByTagName('staff'): for voice in staff.getElementsByTagName('voice'): beginn = Rational(0) #Zählzeit Beginn noteObjects = firstChildElement(voice,'noteObjects') for chord_rest in noteObjects.childNodes: if chord_rest.nodeType == chord_rest.ELEMENT_NODE: if chord_rest.tagName in ['rest', 'chord','barline']: for drawObj in chord_rest.getElementsByTagName('drawObj'): # Voltenklammern ------------------------------------------- if firstChildElement(drawObj, 'volta'): #Anmerkung "dauer" ist die Zählzeit, bei der das Element beginnt for basic in drawObj.getElementsByTagName('basic'): # Es sind (noteRange + 1) Noten unter der Voltenklammer if basic.getAttribute('noteRange'): noteRange = int(basic.getAttribute('noteRange')) + 1 #+1 wegen Zaehlen else: noteRange = 1 # Ermitteln von Beginn und Dauer der Klammer tempNoteObj = chord_rest ende = beginn # aktuelle Note dazuzaehlen if tempNoteObj.nodeType == tempNoteObj.ELEMENT_NODE: if tempNoteObj.tagName in ['rest', 'chord','barline']: if tempNoteObj.tagName not in ['barline']: ende += getDuration(tempNoteObj) #messageBox('',"Beginn: "+str(beginn)) # solange weitergehen und zaehlen, bis Voltenklammer zu Ende ist # mextSibling liefert None, am Zeilenende while tempNoteObj.nextSibling !=None : tempNoteObj = tempNoteObj.nextSibling #naechstes NoteObj if tempNoteObj.nodeType == tempNoteObj.ELEMENT_NODE: if tempNoteObj.tagName in ['rest', 'chord','barline']: noteRange = noteRange-1 #diese Zeichen zaehlen zum Noterange if tempNoteObj.tagName not in ['barline']: ende += getDuration(tempNoteObj) if noteRange = b and c_r.tagName == chord_rest.tagName == 'barline') or (dauer > b and c_r.tagName != 'barline' ) : # Knoten erzeugen, falls noch nicht vorhanden drawObjects = firstChildElement(chord_rest,'drawObjects') if drawObjects == None: drawObjects = score.parentNode.createElement('drawObjects') chord_rest.appendChild(drawObjects) # Zeichen rekursiv kopieren (deep=1) dOClone = dO.cloneNode(1) drawObjects.appendChild(dOClone)
#NoteRange ermitteln tempNoteObj = chord_rest tempDauer = dauer noteRange = 0 #messageBox('',"Beginn: "+str(beginn)) # solange weitergehen und zaehlen, bis Voltenklammer zu Ende ist # mextSibling liefert None, am Zeilenende
while tempDauer 0: basic.setAttribute('noteRange',str(noteRange)) elif basic.hasAttribute('noteRange'): # Nur ein NoteObj unter der Klammer basic.removeAttribute('noteRange') # kopierte Objekte zählen kopierenErfolgreich += 1 break
# Die Objekte müssen in alle anderen Systeme kopiert werden --> (Anzahl_systeme -1) * Objekte if anzahlObjekte * (len(layoutZeilenListe)-1) != kopierenErfolgreich: messageBox('Fehler', str((anzahlObjekte * (len(layoutZeilenListe)-1))-kopierenErfolgreich) + ' Voltenklammern können nicht kopiert werden.nnStellen Sie sicher,' ' dass alle Takte vollständig sind, und die Taktstriche in allen Zeilen gleich sind.')
#------------------------------------------------------------------- # Abgeleitete ScoreChange Klasse zum Bearbeiten der score.xml Datei # Die Methoden changeScore(self, score) und changeElement(self, el) # werden dabei automatisch im __init__ Konstruktor aufgerufen. # Diese Funktionen müssen hier überladen werden. # # Die Variable score enthält dabei eine Referenz auf das xml Dokument #------------------------------------------------------------------- class Einzelstimmen(ScoreChange): def changeScore(self, score): stimmen_loeschen(score) pausenQuetscher(score)
#------------------------------------------------------------------- # Löscht alle Stimmen bis auf die aktuelle #------------------------------------------------------------------- def stimmen_loeschen(score): staffLayouts = score.getElementsByTagName('staffLayout')
# Löschen der Stimme im Layout, ausser es ist die aktuelle Einzelstimme # Zuordnung über global iterator for staffLayout in staffLayouts: if layoutZeilenListe[iterator]!=staffLayout.getAttribute('description'): staffLayout.parentNode.removeChild(staffLayout) #messageBox('',layoutZeilenListe[iterator]) else: continue
# Löschen der Stimme in der Partitur, ausser es ist die aktuelle Einzelstimme # Zuordnung über global iterator for staff in score.getElementsByTagName('staff'): if layoutZeilenListe[iterator]!=staff.getAttribute('layout'): staff.parentNode.removeChild(staff) else: continue
#------------------------------------------------------------------- # Aus Skript Voltenklammer_ausrichten.px von Paul Villinger # Stand: 03.09.10 #------------------------------------------------------------------- def adjustVolta(sy,st,vo,ob,noteRange, noteObjects): system = activeScore().system(sy) staff = system.staff(st) voice = staff.voice(vo) posBegin = voice.noteObj(ob).posX()
# Barline Anfang suchen, n = ob - 1 barLineFound = False while n >= 0 and not barLineFound: obj = voice.noteObj(n) if obj.implBarline() != 0: posBLBegin = obj.implBarline().posX() barLineFound = True elif obj.subType() == NoteObj.KEY and n = nNoteObjects: # noteRange korrigieren wenn ueber Zeilenende noteRange = nNoteObjects - ob - 1 basic.setAttribute('noteRange',str(noteRange))
duration = child.getElementsByTagName('duration')[0] wert = duration.getAttribute('base') display = child.getElementsByTagName('display') dispNum = 0 if wert '1/2' and wert '1/4' and wert '1/8' and wert '1/16' and wert '1/32' and wert '1/64' and doppelganze == 0: if display: dispNum = child.getElementsByTagName('display')[0] elif wert >= '1' and doppelganze == 1: if display: dispNum = child.getElementsByTagName('display')[0] count = 0 mRest = 'no' if dispNum 0 and useMulti == 1: number = dispNum.getAttribute('number') if number == 'up' or number == 'down': # Mehrtaktpause gefunden count = duration.getAttribute('base') mRest = 'yes'
if (duration.getAttribute('base') == '1' or duration.getAttribute('base') == '1/1' or mRest == 'yes') and (doppelganze == 0 and time '4/2'): if restCnt == 0: barlineEx = 1 firstRest = child # Die erste Pause zum Umwandeln merken if useMulti == 1 and mRest == 'yes': restCnt += int(count) else: restCnt += 1 else: # Grafikobjekte von Folgepausen an erste Pause hängen drawObjects=child.getElementsByTagName('drawObjects') if drawObjects.length: for drawObj in drawObjects[0].getElementsByTagName('drawObj'): addDrawObj(score,firstRest,drawObj.cloneNode(True))
child.parentNode.removeChild(child) if useMulti == 1 and mRest == 'yes': restCnt += int(count) else: restCnt += 1
if disps.length == 0: disp = score.parentNode.createElement('display') firstRest.appendChild(disp) disps[0] = disp if pausenTyp == 1: disps[0].setAttribute('churchStyle','false') else: disps[0].setAttribute('churchStyle','true')
if zifferPos == 1: disps[0].setAttribute('number','up') else: disps[0].setAttribute('number','down')
elif (duration.getAttribute('base') == '2' or duration.getAttribute('base') == '2/1' or mRest == 'yes') and (doppelganze == 1 and time == '4/2'): if restCnt == 0: barlineEx = 1 firstRest = child # Die erste Pause zum Umwandeln merken if useMulti == 1 and mRest == 'yes': restCnt += int(count) else: restCnt += 1 else: # Grafikobjekte von Folgepausen an erste Pause hängen drawObjects=child.getElementsByTagName('drawObjects') if drawObjects.length: for drawObj in drawObjects[0].getElementsByTagName('drawObj'): addDrawObj(score,firstRest,drawObj.cloneNode(True))
child.parentNode.removeChild(child) if useMulti == 1 and mRest == 'yes': restCnt += int(count) else: restCnt += 1
if disps.length == 0: disp = score.parentNode.createElement('display') firstRest.appendChild(disp) disps[0] = disp if pausenTyp == 1: disps[0].setAttribute('churchStyle','false') else: disps[0].setAttribute('churchStyle','true')
if zifferPos == 1: disps[0].setAttribute('number','up') else: disps[0].setAttribute('number','down') else: # alle übrigen Pausen barlineEx = 0 restCnt = 0
if child.tagName in ['barline','timeSign','chord']: if child.tagName == 'barline' and not child.hasAttribute('type') and taktstrich == 1 and barlineEx == 1: child.parentNode.removeChild(child) # überflüssige feste Taktstriche löschen else: zeilenAnfang = False restCnt = 0 if child.tagName == 'timeSign': time = child.getAttribute('time') takt = "gefunden"
if child.tagName == 'clefSign': # Bei einem Schlüssel am Zeilenanfang wird der Zähler nicht zurückgesetzt if not zeilenAnfang: restCnt = 0 if child.tagName == 'keySign': # Bei einer Tonartänderung an Zeilenanfang wird der Zähler zurückgesetzt if child.getAttribute('fifth') actKey: restCnt = 0 actKey = child.getAttribute('fifth') if not zeilenAnfang: restCnt = 0 skiprest = False removeEmptyLines(score)
#------------------------------------------------------------------- # Aus Skript Pausen_zusammenfassen.py von Peter Becker # Stand: 19.06.2010 #------------------------------------------------------------------- def removeEmptyLines(score): firstVoice = 1 eV = 0 if score.getElementsByTagName('chord').length == 0 and score.getElementsByTagName('rest').length == 0: return # damit nicht die letzte Zeile gelöscht wird for voice in score.getElementsByTagName('voice'): if voice.getElementsByTagName('chord').length == 0 and voice.getElementsByTagName('rest').length == 0: if voice.getElementsByTagName('barline').length == 0: # testen ob noch ein fester zusammenTyp da ist voice.parentNode.removeChild(voice) # falls nicht, weg mit der Zeile else: if not firstVoice: # falls doch Zeile mir der oberen verbinden no = voice.getElementsByTagName('noteObjects') bl = no[0].getElementsByTagName('barline') bln = bl[0].cloneNode('deep') no2 = emptyVoice.getElementsByTagName('noteObjects') fc2 = no2[0].firstChild fc2.parentNode.appendChild(bln) voice.parentNode.removeChild(voice) # und dann erst löschen else: eV = 0
if eV == 0: emptyVoice = voice # falls mehrere Pausenzeilen hintereinander eV = 1 firstVoice = 0
for staff in score.getElementsByTagName('staff'): if staff.getElementsByTagName('voice').length == 0: staff.parentNode.removeChild(staff) for system in score.getElementsByTagName('system'): if system.getElementsByTagName('staff').length == 0: system.parentNode.removeChild(system)
#Falls mehr als eine Zeile enthalten ist und alle Systeme vorhanden -> ausführen if len(layoutZeilenListe)>1 and allSystems: dir = chooseFolder() #Verzeichnis zum Speichern #"D:\Eigene Dateien\capella\" PrepareScore(tempBackup, tempPrepare) if os.path.exists(dir): #Prüfung tempOutput = tempfile.mktemp('.capx') #Durchlaufen aller Musterpartitur Stimmen for iterator in range(0, len(layoutZeilenListe)): #Löschen aller Zeilen in Systemen und Musterpartitur, ausser der aktuellen Einzelstimmen(tempPrepare, tempOutput) #Abspeichern als neue Datei im ausgewählten Verzeichnis activeScore().read(tempOutput) activeScore().write(dir + '/' +activeScore().title()[0:-5] +'_' + str(iterator) +'_' +latin1(layoutZeilenListe[iterator]) +".capx") os.remove(tempOutput) elif dir != "": #Rückgabewert für Abbruch messageBox('Fehler','Verzeichnis existiert nicht') else: pass
#Zurücklesen der Partitur activeScore().read(tempBackup) #Temporäre Dateien löschen os.remove(tempBackup) os.remove(tempPrepare)
Außerdem hier noch ein Batch Skript zum Drucken aller Capella Partituren in einem Verzeichnis auf dem Standard Drucker. Je nach OS muss es evtl. der Capella Pfad angepasst werden.
@echo off echo ----------------------------------- echo FreePDF muss Standard Drucker sein tasklist |find "capella.exe" >nul IF %ERRORLEVEL%==0 echo !!!! Achtung: Capella muss zuerst geschlossen werden IF %ERRORLEVEL%==0 goto abbruch echo ----------------------------------- :: Aktuellen Standard Drucker ausgeben echo aktueller Drucker ist: wmic printer where "Default = 'True'" get Name echo ----------------------------------- echo Abbruch mit Strg+C echo ----------------------------------- pause :: Alle Dateien im Verzeichnis drucken for %%f in (*.cap*) do ( "C:Programmecapella-softwarecapella 7capella.exe" -p %%f echo Drucke %%f )
Erst mal vielen Dank für die Bereitschaft das Skript mit anderen zu teilen.
Es scheint aber, dass es da noch einige Macken auszubügeln gibt. Bei der ersten Partitur mit der ich es probiert habe erzeugen die Einzelstimmen beim laden noch zahllose Nachrichten "Es wurde ein falsches Argument erzeugt"
Weiterhin lässt sich das Skript nicht mit Cut and Paste in eine Python Datei verwandeln. sowohl in Idle als auch in PythonWin werden vor jede Zeile noch 4 Leerstellen gepackt, was dann bei der Ausführung zu Problemen führt.
Zitat von PeterBeckerWeiterhin lässt sich das Skript nicht mit Cut and Paste in eine Python Datei verwandeln. sowohl in Idle als auch in PythonWin werden vor jede Zeile noch 4 Leerstellen gepackt, was dann bei der Ausführung zu Problemen führt.
Nunja, das liegt wohl eher an der Forumsoftware, die den Code beim Pasten mit Leerzeichen versieht. Jeder gute Editor sollte das beheben können.¹
. Aber das erinnert mich wieder daran, was mir an Python immer suspekt war:
Das ich durch Ändern von Leerzeichen die Semantik eines Programms verändere. [/*]
Bei jeder anderen Programmiersprache lässt sich die Einrückung mit entsprechenden AutoIndent Tools wiederherstellen. Bei Python nicht. [/*]
Wenn ich die Tab-Weite von 8 auf 4 Leerzeichen ändere, macht das Programm plötzlich was ganz anderes [/*]
Zitat von WikipediaDie gemischte Verwendung von Leerzeichen und Tabulatorzeichen kann zu Problemen führen, da der Pythoninterpreter Tab-Stops im Abstand von acht Leerzeichen annimmt. Je nach Konfiguration des Editors können Tabulatoren optisch mit weniger als acht Leerzeichen dargestellt werden, was zu Syntaxfehlern oder ungewollter Programmstrukturierung führen kann.
¹ In SciTe z.B. [Strg]+[A], [Shift]+[Tab]
Musik: Notensatz&Musizieren&Recording@Jazz,Rock,Chor@Bass,Gitarre,Gesang. Soft: Aktuell : PriMusPublisher, CapalleScan8, Transcribe, Ardour (+MuseScore, Audacity, PdfToMusic, u.v.a.m.) Früher: GuitarPro(1…6), Capella(1…6), TuxGuitar, CakeWalk, … Prog: Lua, C++, Perl, Bash, ... HW: i7-8086K, 32GB-Ram, 2x1TB SSD + 2x4TB HD BS: xubuntu18.04LTS (Früher auch W7x64, W10 hat bei mir Hausverbot) Sound: Allen &Heath QU16, Focusrite Scarlett 2i2
ZitatNunja, das liegt wohl eher an der Forumsoftware, die den Code beim Pasten mit Leerzeichen versieht. Jeder gute Editor sollte das beheben können
Stimmt. Jeder Programmierer hat derartige Editoren. Ich auch. Das war nur als Hinweis für den unbedarften Anwender zu verstehen der nur über den mitgelieferten Editor Idle oder den kostenfreien Pythonwin verfügt. Die beiden können das nämlich nicht.