Skip to content

Instantly share code, notes, and snippets.

@TheConstructor
Created December 15, 2023 19:56
Show Gist options
  • Save TheConstructor/c58cf6a2f0e878e26cd6a0003534d59b to your computer and use it in GitHub Desktop.
Save TheConstructor/c58cf6a2f0e878e26cd6a0003534d59b to your computer and use it in GitHub Desktop.
Skript um Noten-Namen in Capella zu ergänzen
# -*- coding: UTF-8 -*-
""" capellaScript -- 15.12.2023 Matthias Vill
>>> Bunte Notennamen einfügen
(Version 1.0 - 15.12.2023)|||
Mit diesem Skript werden die Notennamen der ausgewählten Notenzeile als Grafikobject eingefügt.
Zur leichteren Unterscheidung wird ein farbiger Rahmen hinter den Namen der Note gelegt.||
Der Nutzer hat die Wahl zwischen transponierbaren Symbolen und Symbolen mit Oktaven-Bezeichnung.||
Bitte den Cursor für die automatische Zeilenwahl in die entsprechende Notenzeile setzen,
oder die gewünschte Notenzeile im nachfolgenden Dialog wählen.||
Es werden nur einstimmige Notenzeilen unterstützt.|
Bei mehrstimmigen Notenzeilen werden die Notennamen der obersten Stimme angezeigt.||
Bei Akkorden wird der Name der untersten Note angezeigt.|||
Rückmeldungen bitte an Matthias Vill
<<<
NEU in Version 1.0: Erste Version basierend auf Notennamen-anzeigen.py von Hans H. Lampe
und chordSymbols.py von Hartmut Ring et. al.
"""
isUsingAutoPl = False
#if capVersion() >= (9, 0, 0):
# if activeScore():
# if activeScore().isUsingAutoPlacement():
# isUsingAutoPl = True
noteNames = {
0:('ceses','ces','c','cis','cisis'),
1:('deses','des','d','dis','disis'),
2:('eses', 'es', 'e','eis','eisis'),
3:('feses','fes','f','fis','fisis'),
4:('geses','ges','g','gis','gisis'),
5:('asas', 'as', 'a','ais','aisis'),
6:('heses','b', 'h','his','hisis'),
7:('Ceses','Ces','C','Cis','Cisis'),
8:('Deses','Des','D','Dis','Disis'),
9:('Eses', 'Es', 'E','Eis','Eisis'),
10:('Feses','Fes','F','Fis','Fisis'),
11:('Geses','Ges','G','Gis','Gisis'),
12:('Asas', 'As', 'A','Ais','Aisis'),
13:('Heses','B', 'H','His','Hisis'),
}
noteColors = {
0: (0x000000, 0x00FFFF), #c
1: (0xFFFFFF, 0xA03070), #d
2: (0x000000, 0x00C0FF), #e
3: (0x000000, 0xADCBF8), #f
4: (0xFFFFFF, 0x50B000), #g
5: (0xFFFFFF, 0x0000C0), #a
6: (0xFFFFFF, 0xC07000), #h
7: (0x000000, 0x00FFFF), #C
8: (0xFFFFFF, 0xA03070), #D
9: (0x000000, 0x00C0FF), #E
10: (0x000000, 0xADCBF8), #F
11: (0xFFFFFF, 0x50B000), #G
12: (0xFFFFFF, 0x0000C0), #A
13: (0xFFFFFF, 0xC07000), #H
}
# (pitch, alter) -> pitch: u.a. Index der Note oben - 7; alter: 1 -> b, 2 -> '', 3 -> #
quintenZirkel = [
(3, 1), # Fes
(0, 1), # Ces
(4, 1), # Ges
(1, 1), # Des
(5, 1), # As
(2, 1), # Es
(6, 1), # B
(3, 2), # F
(0, 2), # C
(4, 2), # G
(1, 2), # D
(5, 2), # A
(2, 2), # E
(6, 2), # H
(3, 3), # Fis
(0, 3), # Cis
(4, 3), # Gis
(1, 3), # Dis
(5, 3), # Ais
(2, 3), # Eis
(6, 3) # His
]
# 0, 7, 14, 21, 28, 35, 42, 49, 56, 63
octaves = ("3", "2", "1", "", "", "'", '"', "'''", '4', '5')
# -------- Cursorzeile ermitteln --------- #
staffList = activeScore().voiceList()
staffIndex = 0
sel = curSelection()
if sel != 0:
(sy,st,vo,no) = sel[0]
system = activeScore().system(sy)
staff = system.staff(st)
# ------ Aktuellen Eintrag im Mustersystem bestimmen ------- #
i = 0
for descr in staffList:
if staff.index() == system.staffIndexFromDescr(descr):
staffIndex = i
i += 1
# ------------- Dialog ------------- #
labStaff1 = Label('Notenzeile des Instruments wählen (durch Cursorpositionierung automatisch vorgewählt)')
selStaff = ComboBox(staffList, value = staffIndex, width=23)
labStaff2 = Label(' "Beschreibung" der Notenzeile im Mustersystem', width=38)
numberSize = Edit(' 8', width=2)
labSize = Label(' Zeichengröße ')
vertDist = Edit('-5', width=2)
labDist = Label(' vertikaler Abstand von der Notenzeile nach oben ("negative Werte" nach unten)')
displOct = CheckBox('Sollen Oktavkennzeichnungen angezeigt werden?', value=0)
remark = Label('HINWEIS: Oktavkennzeichnungen deaktivieren die Transponierbarkeit der Texte!\r\n\r\nHINWEIS: Es wird jeweils nur der unterste Ton jedes Akords der obersten Stimme in der Notenzeile angegeben')
dlg = Dialog(' Bunte Notennamen (Version 1.0)',
VBox([
HBox([labStaff1]),
(''),
HBox([selStaff, labStaff2]),
(''),
HBox([numberSize, labSize, vertDist, labDist]),
(''),
HBox([displOct]),
(''),
HBox([remark]),
('')
]
)
)
# ---------------------------------- #
from caplib.capDOM import ScoreChange
import tempfile, codecs
def displayNoteNames(score):
displOctaves = displOct.value()
for system in activeScore().systems():
for staff in system.staves():
if staff.index() != selStaff.value(): # suche die gewählte Notenzeile
continue
voice = staff.voice(0) # nur einstimmige Notenzeilen
for noteObj in voice.noteObjs():
subType = noteObj.subType()
if subType != 1: # 1 = Chord
continue
else: # Chord
head = noteObj.head(0)
diatonic = head.diatonicPitch()
pitch = int(diatonic[0])
alter = int(diatonic[1]) + 2 # Alteration - Vorzeichen
newDrawObject = None
if displOctaves:
octave = octaves[int(pitch / 7)]
pitch = (pitch % 7 + 7) if pitch < 28 else pitch % 7
newDrawObject = CreateGroup(pitch, alter, octave)
else:
pitch = int(diatonic[0]) % 7 # Name des Stammtones
nRefNote = 0
for (i, note) in enumerate(quintenZirkel):
if note[0] == pitch and note[1] == alter:
nRefNote = i - 8
break
newDrawObject = CreateTransposable(nRefNote)
replacedDrawObject = False
# Rückwärts iterieren, damit wir nach dem Löschen eines Objekts nicht durcheinander kommen
for i in range(noteObj.nDrawObjs() - 1, -1, -1):
drawObject = noteObj.drawObj(i)
if drawObject.get('tag', None) == '118614-1':
if replacedDrawObject:
noteObj.deleteDrawObj(i)
else:
noteObj.replaceDrawObj(i, newDrawObject)
replacedDrawObject = True
if not replacedDrawObject:
noteObj.addDrawObj(newDrawObject)
def CreateTransposable(nRefNote):
objectList = []
for note in quintenZirkel:
objectList.append(CreateGroup(note[0] + 7, note[1]))
if isUsingAutoPl:
return {
'type': 'transposable',
'nRefNote': nRefNote,
'items': objectList,
'tag': '118614-1',
'placement': 'auto',
'yPlacement': ("above" if int(vertDist.value()) >= 0 else "below"),
'placementHint': 'chordSymbol'
}
else:
return {
'type': 'transposable',
'nRefNote': nRefNote,
'items': objectList,
'tag': '118614-1'
}
def CreateGroup(pitch, alter, octave=''):
noteColor = noteColors[pitch] # Table-LookUp
noteName = noteNames[pitch] # Table-LookUp
textDrawObject = {
'type': 'text',
'x': 0,
'y': -int(vertDist.value()),
'font': {
'weight': 700, # fett
'height': int(numberSize.value()),
'color': noteColor[0]
},
'content': noteName[alter]+octave,
'tag': '118614-1'
}
rectangleDrawObject = {
'type': 'rectangle',
'x1': -0.3,
'y1': -int(vertDist.value()) - 1.5,
'x2': 2.3,
'y2': -int(vertDist.value()) + 0.4,
'filled': True,
'fillColor': noteColor[1],
'lineWidth': 0,
'tag': '118614-1'
}
groupDrawObject = {
'type': 'group',
'items': [rectangleDrawObject, textDrawObject],
'tag': '118614-1'
}
return groupDrawObject
class displNoteNames(ScoreChange):
def changeScore(self, score):
global scriptAction, doc
doc = score.parentNode
displayNoteNames(score)
# ------ Hauptprogramm ------ #
activeScore().registerUndo("Notennamen anzeigen")
if dlg.run():
if activeScore():
activeScore().registerUndo("Notennamen anzeigen")
tempInput = tempfile.mktemp('.capx') # für aktuelle aktive Partitur #
tempOutput = tempfile.mktemp('.capx')
activeScore().write(tempInput)
displNoteNames(tempInput, tempOutput) # Notennamen anzeigen
os.remove(tempInput)
os.remove(tempOutput)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment