# -*- coding: UTF-8 -*-




# -*- coding: ISO-8859-1 -*-





#
""" capellaScript -- Copyright (c) 2004 Hartmut Ring
>>> Braille-View (capella 7)

    Dieses Skript soll blinden capella-Anwendern über eine Braille-Zeile
    einen schnellen Überblick über eine capella-Partitur geben.||

    Es eignet sich zur Einbindung über Extras - Optionen - |
    Allgemein - Positionsanzeige per Skript.||

    Optionen werden mit braille-view-Options.py verwaltet.| 
<<<
"""

"""
Anpassungen von Paul Villiger (villpaul@swissonline.ch)
27.12.04 - Absturz bei b-Tonarten korrigiert
         - Punktierte Noten korrigiert
         - Mehrtaktpausen, bei > 9 werden Pausen unterteilt ???
         - Tonartwechsel innerhalb Zeile nach C-Dur
11.02.05 - Fehler bei Taktwechsel innerhalb Notenzeile
14.02.05 - Vorzeichen; Einschränkung: Folgende Vorzeichen
           innerhalb eines Taktes werden noch nicht unterdrückt.
20.10.05 - Bindebogen mit C und <B .. >; implementiert
         - Haltebogen mit "C implementiert
21.10.05 - 8tel- Noten klein
         - Ganze Noten {} durch [] ersetzt ??
         - Taktstriche und Wiederholungen
         - Vor Tonart/Takt innerhalb einer Zeile wird eine doppelter Taktstrich gezeichnet, wenn nicht vorhanden ??
22.10.05 - Alle Buchstaben in Kleinschrift
         - Vorzeichen auch bei C-Dur
         - Neue Zeichen bei Tonarten mit mehr als 3 B/3
         - Leerschlag nach Taktwechsel innerhalb Notenzeile
         - kurzer Phrasierungsbogen (punktierter Bindebogen)
         - Oktavierung eine Stufe höher
         - C- und allaBreve-Zeichen
         - Dynamikzeichen
         - Artikulationszeichen
23.10.05 - Zwischen Dynamik und Artikulation steht ein Punkt 3
27.10.05 - 1/256 Noten
         - Wertscheidungszeichen (WSZ) zwischen Noten
         - Wertscheidungszeichen am Zeilenanfang
         - Kastennoten
28.10.05 - Oktavierungszeichen zwischen WSZ und Note
         - Fehler mit Punkt 3 Zeichen
29.10.05 - G-F-C-Schlüssel mit Oktavierung
30.10.05 - Vorzeichenwiederholung in einem Takt funktioniert
31.10.05 - Korrektur Vorzeichenwiederholung
01.11.05 - Behandlung von Tuplets
05.11.05 - Intervalle (Akkorde)
         - Voltenklammern
         - Crescendo, Decrescendo
         - diverse Musiksymbole: segno, D.S., D.C., coda, pedal, fermate, auf/abstrich
06.11.05 - Voltenklammern für alle Nummern
         - Haltebogen für Akkorde $c
         - automatischer Taktstrich (' ') vor Schlüssel
         - Fermate nach Note
         - Voltazeichen mit @#
         - Pedalzeichenende vor Dynamikzeichen und wedge
         - Fehler bei Akkorden mit Oktav
         - Punkt 3 Behandlung nach Dynamikzeichen und Voltenklammern
08.11.05 - Absturz bei Punkt 3 behoben
09.11.05 - Bei Dynamikzeichen de-cresc Ende weglassen
         - Liedtext erste Implementation
13.11.05 - Triller, Doppelschlag und Mordent
14.11.05 - tr wird zu @tr
16.11.05 - '_'  Erweiterung bei Liedtext
         - Atemzeichen
         - Instrumenten-/Stimmenbezeichnung
         - Texte
19.11.05 - Ziffern in Texten und Stimmenbezeichnungen werden nach Braille konvertiert
         - Fehler bei Alteration ohne Vorzeichen
         - römische Bezifferung im Text
20.11.05 - de/cresc vor Dynamikzeichen
21.11.05 - Ziffern in Liedtextnummern werden nach Braille konvertiert
         - nach de/cresc Oktavzeichen
         - nach Text Punkt 3 wenn notwendig
22.11.05 - Vor Wortzeichen '@' ist kein P3 notwendig
         - Titel aus Pageobjkten
24.11.05 - Pageobjekte werden sortiert von oben nach unten
15.12.05 - Transponierbare Symbole werden nicht als Text behandelt
16.12.05 - Behandlung Ausgabedirectory
19.12.05 - falsche Leerzeichen nach Ganztaktpausen
21.12.05 - Mehrtaktpausen mit Braillezahlen
19.01.06 - Falsche Zeitberechnung bei Ganz- und Mehrtaktpausen

27.11.08 - Variante zur Ausgabe auf Braille-Zeile zur Orientierung in capella-Sitzung
            Bernd Jungmann
21.12.08 - Ausgabe von Texten, die an die Seite gebunden sind, wird jetzt unterdrückt.
8.4.09  - Korrektur der Anzeige der Stimmennummer (bisher wurde immer Stimme 1 angezeigt,
            obwohl der richtige Inhalt der per Cursor ausgewählten Stimme gezeigt wurde)
17.11.09 - Variante mit Unterstützung setSelection (capella 7)
5.2.11     Absturz bei leeren Einfachtexten abgefangen BJ
15.3.11 -  Atemzeichen am Zeilenende unterstützt BJ
6.4.11     Variante ohne capDOM mit XNode, Optionsverwaltung in braille-view-Options.py BJ
3.5.11    Akkorde und Option "Vorlesen" korrigiert, Partiturtitel in Titelleiste BJ
14.7.11    Funktion von "Wo bin ich?" integriert bei einheitlicher Darstellung
17.10.11   Korrektur bei Markierung und beim Vorlesen.
"""

#test = 0 # Ausgabe in Braillenotation
test = 1 # Ausgabe im Klartext zur besseren Lesbarkeit beim Testen
#test = 2 # Ausgabe im Klartext für Screenreader

#import zipfile, caplib.capDOM, tempfile, sys, new, string
from xml.dom.minidom import xml, NodeList, Node, Element
import tempfile, sys, new, string, capXNode, time

#-----------------------------------------------------------------------
translations = [('de', {
    'myTitle': 'Wo bin ich?',
    'rest': 'P',
    'restLong': 'Pause ',
    'wholeMeasureRest': 'G',
    'measure': 'T',
    'measureLong': 'Takt ',
    'object': 'O',
    'objectLong': 'Objekt ',
    'voice': 'St',
    'voiceLong': 'Stimme ',
    'stave': 'Z',
    'staveLong': 'Zeile ',
    'key': 'Tonart',
    'system': 'Sy',
    'systemLong': 'System ',
    'barline': 'fester Taktstrich',
    'clef': 'Schlüssel',
    'meter': 'Metrum',
    'nometer':' kein Takt',
    'slur': 'Bindebogen',
    'notes': 'Noten',
    'drawObjs': 'Grafikobjekte',
    'simpleText': 'Einfachtext',
    'transpos': 'Transponierbar',
    'guitar': 'Gitarrengriff',
    'image': 'Bild',
    'richText': 'Textfeld: ',
    'line': 'Linie',
    'rect': 'Rechteck',
    'ellipse': 'Ellipse',
    'wavy': 'Schlangenlinie',
    'triplet': 'Triole',
    'duplet': 'Duole',
    'tuplet': 'Tole',
    'decrescendo': 'Decrescendo',
    'crescendo': 'Crescendo',
    'noteLines': 'Notenlinien',
    'polygon': 'Polygon',
    'ending': 'Voltenklammer',
    'number': 'Nummer',
    'trill': 'Trillerschlange',
    'group': 'Gruppe',
    'verse': 'Strophe',
    'chord': '(',
    'chordLong': 'Akkord ',
    'chordend': ')',
    'chordendLong': ' Akkordende',
    'Musiksymbol': 'Musiksymbol ',
    'ganze':'ganze',
    'halbe':'halbe',
    'viertel':'viertel',
    'achtel':'achtel',
    'sechzehntel':'sechzehntel',
    '1/32':'zweiunddreißigstel',
    '1/64':'vierundsechzigstel',
    '1/128':'hundertachtundzwanzigstel',
    'mit':' mit ',
    'Punkt':'Punkt',
    'Punkten':' Punkten',
    'und':' und ',
    'schlag':' Schlag ',
    'gehalten':'gehalten',
    'fortgesetzt':'fortgesetzt',
    'Seitenobjekte':'Seitenobjekte',
    'start': 'Anfang'}),
                ("en", {
    'myTitle': 'Where am I?',
    'rest': 'R',
    'restLong': 'rest ',
    'wholeMeasureRest': 'W',
    'measure': 'M',
    'measureLong': 'Measure ',
    'object': 'O',
    'objectLong': 'object ',
    'voice': 'V',
    'voiceLong': 'voice ',
    'stave': 'St',
    'staveLong': 'staff ',
    'key': 'key',
    'system': 'Sy',
    'systemLong': 'system ',
    'barline': 'fixed barline',
    'clef': 'clef',
    'meter': 'meter',
    'nometer':' no meter',
    'slur': 'slur',
    'notes': 'notes',
    'drawObjs': 'grafic objects',
    'simpleText': 'simple text',
    'transpos': 'transposable',
    'guitar': 'guitar diagram',
    'image': 'image',
    'richText': 'freeform text: ',
    'line': 'line',
    'rect': 'rectangle',
    'ellipse': 'ellipse',
    'wavy': 'wavy line',
    'triplet': 'triplet',
    'duplet': 'duplet',
    'tuplet': 'tuplet',
    'decrescendo': 'decrescendo',
    'crescendo': 'crescendo',
    'noteLines': 'note lines',
    'polygon': 'polygon',
    'ending': 'ending',
    'number': 'number',
    'trill': 'trill',
    'group': 'group',
    'verse': 'verse',
    'chord': '(',
    'chordLong': 'chord ',
    'chordend': ')',
    'chordendLong': ' chord end',
    'Musiksymbol': 'music symbol ',
    'ganze':'whole',
    'halbe':'half',
    'viertel':'quarter',
    'achtel':'eighth',
    'sechzehntel':'sixteenth',
    '1/32':'1/32',
    '1/64':'1/64',
    '1/128':'1/128',
    'mit':' with ',
    'Punkt':'Dot',
    'Punkten':' Dots',
    'und':' and ',
    'schlag':' beat ',
    'gehalten':'tied',
    'fortgesetzt':'continued',
    'Seitenobjekte':'page objects',
    'start': 'start'})]

setLanguages(translations)
#-----------------------------------------------------------------------
# verwendete Braille-Zeichen:

digits  = 'jabcdefghi'
digits2 = '),;:/?+=(*'

# Zeichen für c, d, e, f, g, a, h, Pause
wholeNotes   = 'yz&%[^]m' # auch 1/16
halfNotes    = 'nopqrstu' # auch 1/32
quarterNotes = '456789wv' # auch 1/64
eighthNotes  = 'defghijx' # auch 1/128
sixteenthNotes   = 'yz&%[^]m' # auch 1/1
thirtysecondthNotes    = 'nopqrstu' # auch 1/2
fourtysixthNotes = '456789wv' # auch 1/4
hundredtwentyeightthNotes  = 'defghijx' # auch 1/8

octaves = ('""', '"', '>', '_', '!', '$', '<', "'") # Subkontraoktave bis dreigestrichene Oktave

# Die Oktave wird geschrieben:
# (a) vor dem ersten Ton einer Notenzeile
# (b) falls Schritt von letzter Note mindestens Sexte ist
# (c) falls Schritt von letzter Note Quarte oder Quinte ist
#     und die Oktave (c...h) gewechselt wird

clefG        = '@\\l'     # Violinschlüssel
clefF        = '@#l'      # Bass-Schlüssel
clefC        = '@0l'       # Alt-Schlüssel
clefBassa    = '#('        # Oktavierung nach unten
clefAlta     = '#h'        # Oktavierung nach oben
numberSign   = '#'         # um ABC... als 123... zu verwenden
symbolC      = '$c'        # C
allaBreve    = '_c'        # alla Breve
doublesharp  = '33'
sharp        = '3'         # Kreuz
flat         = '2'         # Be
doubleflat   = '22'
natural      = '1'         # Auflösungszeichen
sharps       = ['','3','33','333','#d3','#e3','#f3','#g3']
flats        = ['','2','22','222','#d2','#e2','#f2','#g2']
naturals     = ['','1','11','111','#d1','#e1','#f1','#g1']
tieSign      = '"c'        # Haltebogen
allTieSign   = '$c'        # Haltebogen bei Akkorden (alle Töne gleich)
slurShort    = 'c'         # kurzer Bindebogen
slurBegin    = '<b'        # langer Bindebogen Anfang
slurEnd      = '>;'        # langer Bindebogen Ende
slurPhrase   = '_c'        # punktierter Bindebogen kurz
crescBegin   = '@c'
crescEnd     = '@:'
decrescBegin = '@d'
decrescEnd   = '@/'
undefined    = ''
barlineEnd      = '2k'
barlineDouble   = '2k.'
barlineRepBegin = '2='
barlineRepEnd   = '2;'
barSeparation   = '! '     # Takttrennungspunkt
prefix256       = '<2.'    # Ankündigung 256tel
valueSepCommon  = '2,'     # Wertscheidungszeichen allgemein
valueSepGreater = '>2,'    # Wertscheidungszeichen Gross
valueSepSmaller = "'2,"    # Wertscheidungszeichen Klein
boxSign         = '>c'     # Kastenzeichen für Kastennoten
lyricSign       = '<;'
extenderSign    = '-'      # _ bei Lied
hyphenSign      = '-'      # Liedtext Silbentrennung

trSign          = '@tr'    # tr
trillSign       = '+'      # Trillerschlange ohne tr
shortTrillSign  = '!+'     # kurzer Pralltriller
longTrillSign   = '<+'     # langer Pralltriller

shortMordentSign      = '!+L'    # kurzer Mordent
longMordentSign       = '<+L'    # langer Mordent
continuationStartSign = '..'     # Weitergeltungslinie Anfang
continuationEndSign   = '..'     # Weitergeltungslinie Ende
dSchlagSign     = '/'      # Doppelschlag
aboveSign       = "'"      # Doppelschlag ist über Note ( '/ )
reverseSign     = 'L'      # Umgekehrter Doppelschlag ( /L oder '/L )

breathSign      = '@,'     # Atemzeichen

voltaSignBegin  = '@#'
voltaSignContinue = '-'

p3Sign          = '.'      # Punkt 3
withoutPoint123 = ' !"$\'<>_'

intervalSigns   = '-\\0#*):-'  # Prime (Oktave), Sekunde, Terz, Quart Quint, Sext, Septime, Oktave

dynamicSigns    = {'f':'@f',        # f
                   'g':'@ff',       # ff
                   'h':'@fff',      # fff
                   'i':'@mp',       # mp
                   'j':'@mf',       # mf
                   'p':'@p',        # p
                   'q':'@pp',       # pp
                   'r':'@ppp',      # ppp
                   's':'@sf',       # sf
                   'z':'@sfz',      # sfz
                   '{':'@fz',       # fz
                   '|':'@fp',       # fp
                   }

segnoSign       = {'$':' 0 ',       # Segno 2
                   'y':' 0 '}       # Segno
codaSign        = {'n':' 0l ',      # Coda gross
                   'o':' 0l '}      # Coda klein
dsSign          = {'d':'@ds.'}      # D.S.
dcSign          = {'e':'@dc.'}      # D.C.
fermateSign     = {'k':'2L',        # Fermate unten
                   'u':'2L'}        # Fermate oben
pedalDownSign   = {'a':'2c'}        # Pedal Anfang
pedalUpSign     = {'b':'1c'}        # Pedal Ende
bowSign         = {'Y':'2b',        # Abstrich
                   'Z':'2.'}        # Aufstrich

                   

articulationChars = { chr(200):'tenuto',            # Tenuto    
                      chr(201):'staccatissimo',     # Staccatissimo
                      chr(202):'normalAccent',      # normaler Akzent
                      chr(203):'strongAccent',      # starker Akzent
                      chr(204):'weakBeat',          # weicher Schlag
                      chr(205):'strongBeat',        # harter Schlag
                      chr(206):'staccatissimo',     # unten
                      chr(207):'strongBeat',        # harter Schlag unten
                      chr(180) :'staccato'          # staccato (Fingersymbol)
                    }

# Die Reihenfolge wie die Artikulationszeichen gesetzt werden
articulationsList = ['staccato', 'tenuto', 'staccatissimo', 'normalAccent', 'strongAccent', 'weakBeat', 'strongBeat']

staccato = '('
tenuto   = '_('
staccatissimo = "'("
normalAccent = '$('
mezzostaccato = '!('    # Punkt und Querstrich
strongAccent = '<('
weakBeat = ''           # ??
strongBeat = ''         # ??

# In dieser Version wird nur eine Stimme eines Systems ausgegeben!

pos1Voice = "Anfang"
title1Obj = 'Wo bin ich? '
titleVoice = 'Stimme '
positionSeparator = '-'
positionSeparTakt = '+'

#-----------------------------------------------------------------------
# Hilfsfunktionen

def latin1(u):
    return u.encode('Latin-1')
#    return u.encode('utf-8')
import codecs
class ScriptOptions (object):
    def __init__(self):
        dir, file = os.path.split(sys.argv[0])
        fileName = 'braille-view.opt'
        self._optionsFile = os.path.join(dir, fileName)

    def get(self):
        opt = dict()
        try:
            f = codecs.open(self._optionsFile, 'r','utf-8')
            l = f.readlines()
            f.close()
            for x in l:
##                messageBox("get line ",escapeString(x))
                a = [s.strip() for s in x.split('=')] 
                if len(a) == 2:
                    opt[a[0]] = a[1]
        except: pass
        return opt

    def set(self, d):
#        f = file(self._optionsFile, 'w')
        f = codecs.EncodedFile(file(self._optionsFile, 'w'),'unicode_internal','utf-8')
        # würde gerne codecs.BOM_UTF8 an den Anfang schreiben, das klappt nicht so einfach.
        for i in d:
            if not isinstance(d[i], basestring):
                f.write('%s = %s\n' % (i, str(d[i])))
            else:
##                messageBox("set "+i,escapeString(d[i]))
                wrs='%s = %s\n' % (i, d[i])
                f.write(wrs)
        f.flush()            
        f.close()

options = ScriptOptions()
opt = options.get()     # opt = dict()

if opt.has_key('OutputStyle'):
    if opt['OutputStyle'] == 'Braille':
        test = 0
    elif opt['OutputStyle'] == 'Schwarzschrift':
        test = 1
    elif opt['OutputStyle'] == 'Vorlesbar':
        test = 2

if test == 1: # zur besseren Lesbarkeit beim Testen
    digits  = '0123456789'
    
    wholeNotes   = ['<C1>','<D1>','<E1>','<F1>','<G1>','<A1>','<B1>','<P1>']  # Zeichen für c, d, e, f, g, a, h, Pause
    halfNotes    = ['<C2>','<D2>','<E2>','<F2>','<G2>','<A2>','<B2>','<P2>']
    quarterNotes = ['<C4>','<D4>','<E4>','<F4>','<G4>','<A4>','<B4>','<P4>']
    eighthNotes  = ['<C8>','<D8>','<E8>','<F8>','<G8>','<A8>','<B8>','<P8>']
    sixteenthNotes   = ['<C16>','<D16>','<E16>','<F16>','<G16>','<A16>','<B16>','<P16>']  # Zeichen für c, d, e, f, g, a, h, Pause
    thirtysecondthNotes    = ['<C32>','<D32>','<E32>','<F32>','<G32>','<A32>','<B32>','<P32>']
    fourtysixthNotes = ['<C64>','<D64>','<E64>','<F64>','<G64>','<A64>','<B64>','<P64>']
    hundredtwentyeightthNotes  = ['<C128>','<D128>','<E128>','<F128>','<G128>','<A128>','<B128>','<P128>']
    octaves = ('<O2>', '<O3>', '<O4>', '<O5>', '<O6>', '<O7>', '<O8>', "<O9>") # Subkontraoktave bis dreigestrichene Oktave
    intervalSigns   = ['<Prime>','<Sekunde>','<Terz>', '<Quart>', '<Quint>', '<Sext>', '<Septime>', '<Oktave>']
    sharp        = '<#>'         # Kreuz
    doublesharp  = '<##>'        # Kreuz
    flat         = '<b>'         # Be
    doubleflat   = '<bb>'        # Bb
    natural      = '<Auflöser>'         # Auflösungszeichen

    sharps       = ['','<1#>','<2#>','<3#>','<4#>','<5#>','<6#>','<7#>']
    flats        = ['','<1b>','<2b>','<3b>','<4b>','<5b>','<6b>','<7b>']

    clefG   = '<SG> '               # Violinschlüssel
    clefF     = '<SF> '               # Bass-Schlüssel
    clefC   = '<SC> '               # Alt-Schlüssel
    tieSign      = '<Haltebogen>'        # Haltebogen
    allTieSign   = '<Haltebögen>'
    slurShort    = '<Bindebogen>'        # kurzer Bindebogen
    slurBegin    = '<Bindebogen Anfang>' # langer Bindebogen Anfang
    slurEnd      = '<Bindebogen Ende>'   # langer Bindebogen Ende
    crescBegin   = '<Crescendo Anfang>'
    crescEnd     = '<Crescendo Ende>'
    decrescBegin = '<Decrescendo Anfang>'
    decrescEnd   = '<Decrescendo Ende>'
    undefined    = '<undefined>'

elif test == 2: # Ausgabe im Klartext für Screenreader
    digits  = '0123456789'

    wholeNotes   = ['ganze C ','ganze D ','ganze E ','ganze F ','ganze G ','ganze A ','ganze B ','ganze Pause ']  # Zeichen für c, d, e, f, g, a, h, Pause
    halfNotes    = ['halbe C ','halbe D ','halbe E ','halbe F ','halbe G ','halbe A ','halbe B ','halbe Pause ']
    quarterNotes = ['viertel C ','viertel D ','viertel E ','viertel F ','viertel G ','viertel A ','viertel B ','viertel Pause ']
    eighthNotes  = ['achtel C ','achtel D ','achtel E ','achtel F ','achtel G ','achtel A ','achtel B ','achtel Pause ']
    sixteenthNotes   = ['sechzehntel C ','sechzehntel D ','sechzehntel E ','sechzehntel F ','sechzehntel G ','sechzehntel A ','sechzehntel B ','sechzehntel Pause ']  # Zeichen für c, d, e, f, g, a, h, Pause
    thirtysecondthNotes    = ['zweiunddreßigstel C ','zweiunddreßigstel D ','zweiunddreßigstel E ','zweiunddreßigstel F ','zweiunddreßigstel G ','zweiunddreßigstel A ','zweiunddreßigstel B ','zweiunddreßigstel Pause ']
    fourtysixthNotes = ['vierundsechzigstel C ','vierundsechzigstel D ','vierundsechzigstel E ','vierundsechzigstel F ','vierundsechzigstel G ','vierundsechzigstel A ','vierundsechzigstel B ','vierundsechzigstel Pause ']
    hundredtwentyeightthNotes  = ['hundertachtundzwanzigstel C ','hundertachtundzwanzigstel D ','hundertachtundzwanzigstel E ','hundertachtundzwanzigstel F ','hundertachtundzwanzigstel G ','hundertachtundzwanzigstel A ','hundertachtundzwanzigstel B ','hundertachtundzwanzigstel Pause ']
    octaves = ('Subkontraoktave ', 'Kontraoktave ', 'große Oktave ', 'kleine Oktave ', 'eingestrichen ', 'zweigestrichen ', 'dreigestrichen ', "viergestrichen ") # Subkontraoktave bis dreigestrichene Oktave
    intervalSigns   = ['Prime ','Sekunde ','Terz ', 'Quart ', 'Quint ', 'Sext ', 'Septime ', 'Oktave ']


    clefG   = 'Violinschlüssel '               # Violinschlüssel
    clefF     = 'Bass-Schlüssel '               # Bass-Schlüssel
    clefC   = 'Alt-Schlüssel '
    numberSign = ''                     # Beim Vorlesen überflüssig
    symbolC      = 'Symbol C '        # C
    allaBreve    = 'alla breve '        # alla Breve
    sharp        = 'Kreuz '     # Kreuz
    doublesharp  = 'Doppelkreuz ' # Doppelkreuz
    flat         = 'b '         # Be
    doubleflat   = 'bb '        # Bb
    natural      = 'Auflöser '  # Auflösungszeichen
    sharps       = ['','ein Kreuz ','2 Kreuze ','3 Kreuze ','4 Kreuze ','5 Kreuze ','6 Kreuze ','7 Kreuze ']
    flats        = ['','ein b ','2 b ','3 b ','4 b ','5 b ','6 b ','7 b ']

    tieSign      = 'Haltebogen '        # Haltebogen
    allTieSign   = 'Haltebögen '
    slurShort    = 'Bindebogen '        # kurzer Bindebogen
    slurBegin    = 'Bindebogen Anfang ' # langer Bindebogen Anfang
    slurEnd      = 'Bindebogen Ende '   # langer Bindebogen Ende
    crescBegin   = 'Crescendo Anfang '
    crescEnd     = 'Crescendo Ende '
    decrescBegin = 'Decrescendo Anfang '
    decrescEnd   = 'Decrescendo Ende '
    undefined    = 'undefiniert '

    barlineEnd      = 'Taktstrich Abschluss'
    barlineDouble   = 'Taktstrich doppelt'
    barlineRepBegin = 'Taktstrich Wiederholung Start'
    barlineRepEnd   = 'Taktstrich Wiederholung Ende'
    
    barSeparation   = '! '     # Takttrennungspunkt
    prefix256       = '<2.'    # Ankündigung 256tel
    valueSepCommon  = '2,'     # Wertscheidungszeichen allgemein
    valueSepGreater = '>2,'    # Wertscheidungszeichen Gross
    valueSepSmaller = "'2,"    # Wertscheidungszeichen Klein
    boxSign         = '>c'     # Kastenzeichen für Kastennoten
    lyricSign       = 'Liedtext '
    extenderSign    = '-'      # _ bei Lied
    hyphenSign      = '-'      # Liedtext Silbentrennung

    trSign          = 'Triller'    # tr
    trillSign       = '+'      # Trillerschlange ohne tr
    shortTrillSign  = 'kurzer Pralltriller '     # kurzer Pralltriller
    longTrillSign   = 'langer Pralltriller '     # langer Pralltriller

    shortMordentSign      = 'kurzer Mordent '    # kurzer Mordent
    longMordentSign       = 'langer Mordent'    # langer Mordent
    continuationStartSign = '..'     # Weitergeltungslinie Anfang
    continuationEndSign   = '..'     # Weitergeltungslinie Ende
    dSchlagSign     = 'Doppelschlag '      # Doppelschlag
    aboveSign       = "'"      # Doppelschlag ist über Note ( '/ )
    reverseSign     = 'umgekehrt '      # Umgekehrter Doppelschlag ( /L oder '/L )

    breathSign      = 'Atemzeichen '     # Atemzeichen

    voltaSignBegin  = 'Voltenklammer Start '
    voltaSignContinue = 'Voltenklammer weiter '
    
    staccato = 'Staccato '
    tenuto   = 'Tenuto '
    staccatissimo = 'Staccatissimo '
    normalAccent = 'Akzent '
    mezzostaccato = 'Mezzostaccato '    # Punkt und Querstrich
    strongAccent = 'Starker Akzent '

    positionSeparator = ' '
    positionSeparTakt = ' plus '

# hier die übersetzten Bezeichnungen einsetzen
articulation2Braille = {'staccato':staccato,
                        'tenuto':tenuto,
                        'staccatissimo':staccatissimo,
                        'normalAccent':normalAccent,
                        'strongAccent':strongAccent,
                        'weakBeat':weakBeat,
                        'strongBeat':strongBeat}

#----- zusätzliche Funktionen für CapXNode zur Unterstützung von ScoreExportXNode
def getAttribute(self, p):
    try:
        if not self._attrs:
            return ''
    except:
        self._attrs = self.getAttributes()      
    if self._attrs.has_key(p):
        return self._attrs[p]
    return ''
CapXNode.getAttribute = new.instancemethod(getAttribute, None, CapXNode)
def hasAttribute(self, p):
    return '' != self.getAttribute(p)
CapXNode.hasAttribute = new.instancemethod(hasAttribute, None, CapXNode)
def getElementsByTagName(self, name):
    iEl = 0
    list = []
    while True:
        child = self.getChildNodeI(iEl)
        if child.isEmpty():
            break
        # viel Zeit sparen durch Verzicht auf transposable:
        if child.getName() == 'transposable':
            break
        iEl += 1
        if child.getName() == name:
            list.append(child)
        list.extend(child.getElementsByTagName(name))
    return list
CapXNode.getElementsByTagName = new.instancemethod(getElementsByTagName, None, CapXNode)

##def gotoChild(self, name, new=False):
##    newEl = None
##    if new:
##        pass
##    else:
##        for child in self.childNodes:
##            if child.nodeType == child.ELEMENT_NODE and child.tagName == name:
##                newEl = child
##                break
##    if newEl == None:
##        newEl = doc.createElement(name)
##        self.appendChild(newEl)
##    return newEl
##
##Node.gotoChild = new.instancemethod(gotoChild,None,Node)

##def getChildNodes(self):
##    childs = []
##    for child in self.childNodes:
##        if child.nodeType == child.ELEMENT_NODE:
##            childs.append(child)
##    return childs
##Node.getChildNodes = new.instancemethod(getChildNodes,None,Node)

def brailleNumToChar(c):
    return chr(ord('A') + ord(c) - ord('0'))

def convertDigitsToBraille(s):
    returnString = ''
    digitSign = False
    for c in s:
        if c in string.digits:
            if not digitSign:
                returnString += numberSign
                digitSign = True
            returnString += digits[int(c)]
        else:
            returnString += c
            digitSign = False
    return returnString

def meterToRational(s):
    if s in ('allaBreve', 'C'):
        s = '4/4'
    elif s == 'infinite':
        s = '1000/1'
    try:
        t = s.split('/')
        p = t[0].strip()
        q = t[1].strip()
        return Rational(int(p),int(q))
    except:
        messageBox('Fehler', '[%s]' % s);

class RingStorage(int):
    def __init__(self):
        self.ring = [None] * 64
        for i in range(0,64):
            self.ring[i] = []
        self.pointer = 0

    def add(self, offset, el):
        poi = (self.pointer + offset) % 64
        self.ring[poi].append(el)

    def isfilled(self, offset=0):
        return self.ring[(self.pointer + offset) % 64] <> []

    def getFirst(self, offset=0):
        poi = (self.pointer + offset) % 64
        l = self.ring[poi]
        r = None
        if len(l) > 0:
            self.ring[poi] = l[1:]
            r = l[0]
        return r

    def getLast(self, offset=0):
        poi = (self.pointer + offset) % 64
        l = self.ring[poi]
        r = None
        if len(l) > 0:
            self.ring[poi] = l[:len(l)-1]
            r = l[len(l)]
        return r

    def next(self):
        self.pointer = (self.pointer + 1) % 64
            
            
slurStorage = RingStorage()  # Bindebogen
wedgeStorage = RingStorage() # Cresc. Decresc. Zeichen
trillStorage = RingStorage() # Triller über mehrere Noten

#---------------------------------------------------------------

class BrailleExport (capXNode.ScoreExportXNode):
    def __init__(self, sel):

        self.s = ""
        self.sPos = " "
        self.selstop = sel[1]
        # falls Teil einer Stimme selektiert ist, können wir das auf der
        # Braille-Zeile sichtbar machen:
        self.selstart = sel[0]
        if self.selstop[0] != self.selstart[0] or self.selstop[1] != self.selstart[1] or self.selstop[2] != self.selstart[2]:
            self.selstart = self.selstop
        if self.selstop[3] < self.selstart[3]:
            tmp = self.selstop
            self.selstop = self.selstart
            self.selstart = tmp
        self.pyselstop = 0
        self.pyselstart = 0
        self.py2cap = {}

        self.root = rootNode()
        xmlns = self.root.getAttributes()["xmlns"]
        self.isCAPX2 = 0 > xmlns.find("1.0")
#        messageBox("BrailleExport xmlns", xmlns + " isCAPX2 "+str(self.isCAPX2))
        self.handleScore(self.root)
##        n = self.root.getChildNodeCount()
##        for i in range(n):
##            node = self.root.getChildNodeI(i)
##            messageBox("BrailleExport", node.getName())
##            if node.getName() == 'score':
##                self.handleScore(node)

    def showWindow(self, vanish):
        nCR = self.s.find("\n")
        if vanish:
            edit = Edit(self.s[0:nCR], width=90, readonly="true")
        else:
            edit = Edit(self.s[0:nCR], width=90, sel=(self.pyselstart, self.pyselstop), readonly="true")
        if self.isCAPX2: # sollte beim Aufruf von capella7 immer der Fall sein
            lyrics = Label(self.s[nCR:-1], width=90)
        else:
            lyrics = Label(LegacyToUtf(self.s[nCR:-1]), width=90)
##        lyrics = Label(self.s[nCR:-1], width=90)
        if opt.has_key("pathname"):
            pathname = opt["pathname"]
        else:
            pathname = ""
##        messageBox("pathName()",escapeString(activeScore().pathName()))
##        messageBox("pathname",escapeString(pathname))
        if activeScore().pathName() == pathname:
            if vanish:
                displTitle = title1Obj
            else:
                displTitle = titleVoice
        else:
            pathname = activeScore().pathName()
            indbs = pathname.rfind("\\")
            if indbs < 0:
                displTitle = activeScore().title()
            else:
                displTitle = pathname[indbs+1:-1]
        if vanish:
            editlist = [edit]
            for item in self.objlist:
                ed = Edit(item, width=90,readonly="true")
                editlist.append(ed)
                
            dlg = Dialog(displTitle.encode('utf-8') + self.sPos, VBox(editlist))
            dlg["timeout"] = 2000
        else:
            dlg = Dialog(displTitle.encode('utf-8') + self.sPos, VBox([edit, lyrics]))

        opt["pathname"] = pathname
        options.set(opt)

        if dlg.run():
            if edit.value() != self.s[0:nCR]:
                # messageBox("BrailleExport", "Es gab Änderungen im Text")
                pass
            if not vanish and (edit.sel()[0] != self.pyselstart or edit.sel()[1] != self.pyselstop):
#                messageBox("Es gab Änderungen in der Selektion", str(edit.sel())+", vorher "+str(self.pyselstart)+" , "+str(self.pyselstop))
                sel0 = edit.sel()[0]
                sel1 = edit.sel()[1]
                reverse = sel1 < sel0
                if reverse:
                    messageBox("Gibt's doch gar nicht","EM_GETSEL sagt wo der Cursor ist!!")
                    tmp = sel1
                    sel1 = sel2
                    sel2 = tmp
                while not self.py2cap.has_key(sel0) and sel0 > 0:
                    sel0 = sel0 - 1
                if not self.py2cap.has_key(sel0):
                    self.selstart = (self.selstart[0], self.selstart[1], self.selstart[2], 0)
                else:
                    self.selstart = (self.selstart[0], self.selstart[1], self.selstart[2], self.py2cap[sel0])
                while not self.py2cap.has_key(sel1) and sel1 < nCR:
                    sel1 = sel1 + 1
                if not self.py2cap.has_key(sel1):
                    nNoteObjs = activeScore().system(self.selstop[0]).staff(self.selstop[1]).voice(self.selstop[2]).nNoteObjs()
                    self.selstop = (self.selstop[0], self.selstop[1], self.selstop[2], nNoteObjs)
                else:
                    self.selstop = (self.selstop[0], self.selstop[1], self.selstop[2], self.py2cap[sel1])
                if reverse:
                    setSelection((self.selstop, self.selstart))
                else:
#                    messageBox("Änderungen in der Selektion", "setSelection "+str(self.selstart)+", "+str(self.selstop))
                    setSelection((self.selstart, self.selstop))
                    
                
            return True
        return False

    def handleVoice(self, voice):
        if self.iSys == self.selstop[0] and self.iStv == self.selstop[1] and self.iVc == self.selstop[2]:
            self.nVoice = self.iVc
            self.startVoice(voice)
            noteObjects = voice.getChildNode('noteObjects',0)
            nObjs = noteObjects.getChildNodeCount()
            for iObj in range(nObjs):
                s = noteObjects.getChildNodeI(iObj)
                length = len(self.s.decode('utf-8'))
                self.py2cap[length] = iObj
                if self.selstop[3] == iObj:
                    self.pyselstop = length
                if self.selstart[3] == iObj:
                    self.pyselstart = length
                self.handleNoteObj(s)
            length = len(self.s.decode('utf-8'))
            self.py2cap[length] = nObjs
            self.finishVoice(voice)
            if self.pyselstop == 0:
                # Selektion bis zum Ende der Stimme
                self.pyselstop = length
                if self.selstop[3] == self.selstart[3]:
                    self.pyselstart = self.pyselstop
                
                
        
    def writeBraille(self, s):
        if self.printP3:
            if len(s) > 0:
                # vor einem Wortzeichen ist kein Punkt notwendig
                if s[0] == '@':
                    pass
                # Punkt muss vor Zeichen folgen, welche nicht Punkt 1, 2 oder 3 enthalten
                elif s[0] not in withoutPoint123:
#                    self.f.write(p3Sign)
                    self.s += p3Sign
                self.printP3 = False
        self.s += s

    def startScore(self, score):
        self.printP3 = False

##  Für die window-Variante wollen wir keine pageObjects!
##        titleFound = False
##        pageTexts = []
##        for pageObject in score.getElementsByTagName('pageObjects'):
##            for text in pageObject.getElementsByTagName('text'):
##                y = float(text.getAttribute('y'))
##                for content in text.getElementsByTagName('content'):
##                    cont = latin1(content.firstChild.nodeValue)
##                    cont = convertDigitsToBraille(cont)
##                    cont = string.replace(cont, '\n', ' ')
##                    pageTexts.append([y, cont])
##
##        pageTexts.sort()
##        for t in pageTexts:
##            self.writeBraille(' ' * 10)
##            self.writeBraille(t[1])
##            self.writeBraille('\n')
##            titleFound = True
##            
##        if titleFound:
##            self.writeBraille('\n')
            
        self.staffNames = {}
        staves = score.getChildNode('layout',0).getChildNode('staves',0)
        i = 0
        while True:
            staffLayout = staves.getChildNode('staffLayout',i)
            if staffLayout.isEmpty():
                break
            i += 1
            description = staffLayout.getAttribute('description')
            instrument = staffLayout.getChildNode('instrument', 0)
            name = instrument.getAttribute('name')
            abbrev = instrument.getAttribute('abbrev')
            name = convertDigitsToBraille(name)
            abbrev = convertDigitsToBraille(abbrev)
            self.staffNames[description] = [name,abbrev]
            
##        for staffLayout in score.getElementsByTagName('staffLayout'):
##            description = self.encode(staffLayout.getAttribute('description'))
##            for instrument in staffLayout.getElementsByTagName('instrument'):
##                name = self.encode(instrument.getAttribute('name'))
##                abbrev = self.encode(instrument.getAttribute('abbrev'))
##            name = convertDigitsToBraille(name)
##            abbrev = convertDigitsToBraille(abbrev)
##            self.staffNames[description] = [name,abbrev]
        
        self.nSys = 0

    def finishScore(self, score):
        pass

    def startSystem(self, sys):
        self.nSys += 1
        self.nStave = 0
        self.instrNotation = sys.getAttribute('instrNotation')

    def startStaff(self, staff):
        self.nStave += 1
        self.nVoice = 0
        self.meter = meterToRational(staff.getAttribute('defaultTime'))
        self.staffLayout = self.encode(staff.getAttribute('layout'))

    def finishSystem(self, sys):
#        self.f.write('\n')
#        self.s += '\n' wir wollen nur eine Stimme in 1 System bearbeiten
        pass

    def startVoice(self, vc):
        self.firstNote = True
        self.barline = True
        self.barSeparation = False
        self.printP3 = False
        self.triplet = False
        self.nVoice += 1
##        
##        name, abbrev = self.staffNames[self.staffLayout]
##        if self.instrNotation == 'long':
##            if name <> '':
##                self.writeBraille(name + ' ')
##        elif self.instrNotation == 'short':
##            if abbrev <> '':
##                self.writeBraille(abbrev + ' ')
##            
##        self.writeBraille('%d-%d-%d ' % (self.nSys, self.nStave, self.nVoice))

        # wir arbeiten nur für eine Stimme!
        name, abbrev = self.staffNames[self.staffLayout]
        if self.instrNotation == 'long':
            if name <> '':
                self.sPos += (name + ' ')
        elif self.instrNotation == 'short':
            if abbrev <> '':
                self.sPos += (abbrev + ' ')
            
        self.sPos += '%d%s%d%s%d' % (self.nSys, positionSeparator, self.nStave, positionSeparator, self.nVoice)
        self.lastPitch = -100  # am Anfang eine Oktavangabe erzwingen!
        self.time = Rational(0)
        self.fifths = 0
        self.lastBase = '0'
        self.octaveSign = ''
        self.pedalDown = ''
        self.pedalUp = ''
        self.alterationSigns = {}   # Zwischenspeicher für alle Vorzeichen innerhalb eines Taktes
        self.tupletTime = Rational(0)
        self.lyricDict = dict()
        self.breathStorage = ''     # Zwischenspeicher für Atemzeichen
        self.hasTie = False
        
    def finishVoice(self, voice):
        self.writePendingBreathSign()
        self.writeLyric()
#        self.f.write('\n')
        self.s += '\n'

    def startChord(self, chord):
        self.nHeads = 0
        self.hasTie = False  # Irgend ein Kopf hat Haltebogen
        self.allTie = True   # Bleibt auf True wenn alle Köpfe Haltebogen haben
        self.pitches = []

    def handleClefSign(self, clefSign):
        clef = clefSign.getAttribute('clef')
        if   clef == 'treble': clef = 'G2'
        elif clef == 'bass' : clef = 'F4'
        elif clef == 'alto' : clef = 'C3'
        elif clef == 'tenor': clef = 'C4'

        self.clefSign = clef        
            
        if   'G' in clef:
            if clef[1] == '2' : self.writeBraille(clefG)
            else: self.writeBraille(clefG[0:2] + octaves[ int(clef[1]) ] + clefG[2])

        elif 'F' in clef:
            if clef[1] == '4' : self.writeBraille(clefF)
            else: self.writeBraille(clefF[0:2] + octaves[ int(clef[1]) ] + clefF[2])
            
        elif 'C' in clef:
            if clef[1] == '3' : self.writeBraille(clefC)
            else: self.writeBraille(clefC[0:2] + octaves[ int(clef[1]) ] + clefC[2])
        
        if   '-' in clef: self.writeBraille(clefBassa)
        elif '+' in clef: self.writeBraille(clefAlta)

        self.writeBraille(' ') # nach dem Schlüssel ein Leerzeichen         
        self.lastPitch = -100  # nach Schlüssel eine Oktavangabe erzwingen!

        
    def handleKeySign(self, keySign):
        # Vor die Tonart wird eine doppelter Taktstrich gezeichnet, wenn nicht vorhanden ??
        if not self.barline:
            self.writeBraille(barlineDouble)
            self.writeBraille(barSeparation)
            self.barline = True
        self.time = Rational(0)
        self.alterationSigns = {}
            
        fifths = int(keySign.getAttribute('fifths'))
        if fifths > 0:  self.writeBraille(sharps[fifths])
        elif fifths < 0: self.writeBraille(flats[-fifths])
        elif fifths == 0: self.writeBraille(naturals[abs(self.fifths)])
        self.firstNote = True
        self.triplet = False
        self.fifths = fifths
        self.lastPitch = -100  # nach Tonartwechsel eine Oktavangabe erzwingen!

    def handleTimeSign(self, timeSign):
        # Vor die Taktangabe wird eine doppelter Taktstrich gezeichnet, wenn nicht vorhanden ??
        if not self.barline:
            self.writeBraille(barlineDouble)
            self.writeBraille(barSeparation)
            self.barline = True
        self.time = Rational(0)
        self.alterationSigns = {}

        time = timeSign.getAttribute('time')
        if time == 'allaBreve':
            self.writeBraille(allaBreve)
            time = '2/2'
        elif time == 'C':
            self.writeBraille(symbolC)
            time = '4/4'
        else:
            t = time.split('/')
            self.writeBraille(meterSign(t[0], t[1]))
        self.meter = meterToRational(time)
        self.firstNote = True

    def handleBarline(self, n):    
        if n.getName() == 'barline':
            self.time = Rational(0)
            self.alterationSigns = {}
            self.lastBase = '0'
            self.barline = True
            type = n.getAttribute('type')
            if type == 'end':
                self.writeBraille(barlineEnd)
                self.barSeparation = True
            elif type == 'repEnd':
                self.writeBraille(barlineRepEnd)
                self.barSeparation = True
            elif type == 'double':
                self.writeBraille(barlineDouble)
                self.barSeparation = True
            elif type == 'repBegin':
                self.writeBraille(barlineRepBegin)
            elif type == 'repEndBegin':
                self.writeBraille(barlineRepEnd + barSeparation + barlineRepBegin)
            else:
                self.writeBraille(' ')

        elif self.time >= self.meter:
            # Leerschlag für Taktstrich
            while self.time >= self.meter:
                self.time -= self.meter
            self.alterationSigns = {}
            self.lastBase = '0'
            self.writeBraille(' ')


    def handleDynamics(self,noteObject):
        if noteObject.getName() in ['chord', 'rest']:
            for text in noteObject.getElementsByTagName('text'):
                for font in text.getElementsByTagName('font'):
                    if 'capella' in font.getAttribute('face'):
                        for content in text.getElementsByTagName('content'):
                            txt = content.getText()
                            if txt == '':
                                continue
                            cont = self.encode(txt)
                            if cont in dynamicSigns:
                                # Das Ende einer Pedalklammer muss vor einem Dynamikzeichen stehen
                                if self.pedalUp <> '':
                                    self.writeBraille(self.pedalUp)
                                    self.pedalUp = ''

                                # das Ende eines wedge-Zeichens muss vor einem Dynamikzeichen stehen
                                while wedgeStorage.isfilled():
                                    self.writeBraille(wedgeStorage.getFirst())
                                    
                                self.writeBraille(dynamicSigns[cont])
                                self.printP3 = True
                                self.lastPitch = -100  # eine Oktavangabe erzwingen!

    def handleWedge(self, n):
        # cresc. decresc.
        for drawObj in n.getElementsByTagName('drawObj'):
            noteRange = 0
            for basic in drawObj.getElementsByTagName('basic'):
                nr = basic.getAttribute('noteRange')
                if nr: noteRange = eval(nr)
                break
            for wedge in drawObj.getElementsByTagName('wedge'):

                # Das Ende einer Pedalklammer muss vor einem Dynamikzeichen stehen
                if self.pedalUp <> '':
                    self.writeBraille(self.pedalUp)
                    self.pedalUp = ''

                # das Ende eines wedge-Zeichens muss vor einem Dynamikzeichen stehen
                while wedgeStorage.isfilled():
                    self.writeBraille(wedgeStorage.getFirst())

                if wedge.getAttribute('decrescendo') == 'true':
                    self.writeBraille(decrescBegin)
                    wedgeStorage.add(noteRange, decrescEnd)
                else:
                    self.writeBraille(crescBegin)
                    wedgeStorage.add(noteRange, crescEnd)

                self.lastPitch = -100  # eine Oktavangabe erzwingen!


    def handleTrill(self,noteObject):
        trillFound = False
        
        shortVerticalLineFound = False
        for line in noteObject.getElementsByTagName('line'):
            x1 = line.getAttribute('x1')
            x2 = line.getAttribute('x2')
            y1 = line.getAttribute('y1')
            y2 = line.getAttribute('y2')
            if x1 and x2 and y1 and y2:
                if abs(float(x1) - float(x2)) < 0.5 and abs(float(y1) - float(y2)) < 3.0 :
                    shortVerticalLineFound = True

        for drawObj in noteObject.getElementsByTagName('drawObj'):
            noteRange = 0
            for basic in drawObj.getElementsByTagName('basic'):
                nr = basic.getAttribute('noteRange')
                if nr: noteRange = eval(nr)
                break

            for trill in drawObj.getElementsByTagName('trill'):
                tr = trill.getAttribute('tr')
                if noteRange > 0:
                    if tr == 'false':
                        self.writeBraille(trillSign)
                    else:
                        self.writeBraille(trSign)
                        self.lastPitch = -100  # eine Oktavangabe erzwingen!
                    self.writeBraille(continuationStartSign)
                    trillStorage.add(noteRange, continuationEndSign)
                elif tr == 'false':
                    if shortVerticalLineFound:
                        # langer Mordent (Trillerschlange mit kurzer senkrechter Linie)
                        self.writeBraille(longMordentSign)
                    else:
                        # langer Pralltriller
                        self.writeBraille(longTrillSign)
                else:
                    # normaler Triller eine Note
                    self.writeBraille(trSign)
                    self.lastPitch = -100  # eine Oktavangabe erzwingen!
                    
                trillFound = True

        if not trillFound:
            for text in noteObject.getElementsByTagName('text'):
                x = text.getAttribute('x')
                for font in text.getElementsByTagName('font'):
                    if 'capella' in font.getAttribute('face'):
                        for content in text.getElementsByTagName('content'):
                            txt = content.getText()
                            if txt == '':
                                continue
                            cont = self.encode(txt)
                            if cont == 'l':   # kurzer Pralltriller 
                                self.writeBraille(shortTrillSign)
                            elif cont == 't':   # Triller (tr)
                                self.writeBraille(trSign)
                                self.lastPitch = -100  # eine Oktavangabe erzwingen!
                            elif cont == 'x':   # Mordent
                                self.writeBraille(shortMordentSign)
                            elif cont == 'w':   # Doppelschlag (liegendes S)
                                if x and float(x) > 1.0: # Doppelschlag zwischen den Noten
                                    self.writeBraille(dSchlagSign)
                                else:                   # Doppelschlag über/unter den Noten
                                    self.writeBraille(aboveSign + dSchlagSign)
                                    
                                if shortVerticalLineFound: # Umgekehrter Doppelschlag (senkrechte Linie durch liegendes S)
                                    self.writeBraille(reverseSign)
                                    


    def handleMusicalSymbolsBeforeNote(self, noteObject):
        if noteObject.getName() in ['chord', 'rest']:
            for text in noteObject.getElementsByTagName('text'):
                for font in text.getElementsByTagName('font'):
                    if 'capella' in font.getAttribute('face'):
                        for content in text.getElementsByTagName('content'):
                            txt = content.getText()
                            if txt == '':
                                continue
                            cont = self.encode(txt)
                            # Segno
                            if cont in segnoSign:
                                self.writeBraille(segnoSign[cont])
                                self.lastPitch = -100  # eine Oktavangabe erzwingen!
                            # Coda
                            elif cont in codaSign:
                                self.writeBraille(codaSign[cont])
                                self.lastPitch = -100  # eine Oktavangabe erzwingen!
                            # D.S.
                            elif cont in dsSign:
                                self.writeBraille(dsSign[cont])
                            # D.C.                                
                            elif cont in dcSign:
                                self.writeBraille(dcSign[cont])
                            # Pedalen ab
                            elif cont in pedalDownSign:
                                self.pedalDown = pedalDownSign[cont]
                            # Pedalen ab
                            if cont in pedalUpSign:
                                self.pedalUp = pedalUpSign[cont]
                            # Bogen auf- abstrich
                            elif cont in bowSign:
                                self.writeBraille(bowSign[cont])

        if self.pedalDown <> '':
            if self.pedalUp <> '':
                self.writeBraille(self.pedalUp)
                self.pedalUp = ''
            self.writeBraille(self.pedalDown)
            self.pedalDown = ''
            
                                
                            
    def handleMusicalSymbolsAfterNote(self, noteObject):
        if noteObject.getName() in ['chord', 'rest']:
            for text in noteObject.getElementsByTagName('text'):
                for font in text.getElementsByTagName('font'):
                    if 'capella' in font.getAttribute('face'):
                        for content in text.getElementsByTagName('content'):
                            txt = content.getText()
                            if txt == '':
                                continue
                            cont = self.encode(txt)
                            # Fermate
                            if cont in fermateSign:
                                self.writeBraille(fermateSign[cont])
        if self.pedalUp <> '':
            self.writeBraille(self.pedalUp)
            self.pedalUp = ''
        

    def handleArticulation(self, chord):
        articulation = []
        for art in chord.getElementsByTagName('articulation'):
            type = art.getAttribute('type')
            articulation.extend(string.split(type))

        for text in chord.getElementsByTagName('text'):
            font = text.getChildNode('font',0)
            content = text.getChildNode('content',0)
            if 'capella' in font.getAttribute('face'):
                if content.getText() != '':
                    cont = self.encode(content.getText())
                    if len(cont) == 1 and cont in articulationChars:
                        articulation.append(articulationChars[cont])

        for a in articulationsList:
            if a in articulation:
                if (a in ['staccato','tenuto']
                    and 'staccato' in articulation
                    and 'tenuto' in articulation):
                    if a == 'staccato':
                        self.writeBraille(mezzostaccato)
                else:
                    self.writeBraille(articulation2Braille[a])

    def handleVoltaSigns(self,n):
        if n.getName() in ['chord', 'rest']:
            iV = 0
            for volta in n.getElementsByTagName('volta'):
                firstNumber = volta.getAttribute('firstNumber')
                lastNumber = volta.getAttribute('lastNumber')
                if firstNumber:
                    self.writeBraille(voltaSignBegin)
                    for ch in firstNumber:
                        self.writeBraille(digits2[int(ch)])
                    if lastNumber:
                        self.writeBraille(voltaSignContinue)
                        for ch in lastNumber:
                            self.writeBraille(digits2[int(ch)])
                else:
                    # Rest oder Voltazeichen ohne Nummer
                    self.writeBraille(voltaSignBegin)
                    self.writeBraille(digits2[1])  # 1.
                self.printP3 = True
                self.lastPitch = -100  # eine Oktavangabe erzwingen!
                break # For-Schleife verlassen
        

    def handleLyric(self,n):
        for vers in n.getElementsByTagName('verse'):
            i = vers.getAttribute('i')
            hyphen = vers.getAttribute('hyphen')
            verseNumber = convertDigitsToBraille(self.encode(vers.getAttribute('verseNumber')))
            extender = vers.getAttribute('extender')
            cont = ''
            if vers.getText():
                cont = self.encode(vers.getText())
            if i:
                self.lyricDict[i] = self.lyricDict.setdefault(i, '') + cont
                if hyphen == 'true':
                    self.lyricDict[i] += hyphenSign
                elif extender == 'true':
                    self.lyricDict[i] += extenderSign
                else:
                    self.lyricDict[i] += ' '
                    
                if verseNumber:
                    self.lyricDict[i] = verseNumber + '$' + self.lyricDict[i]
                    self.lyricDict['lenVerseNumber'] = len(verseNumber) + 1


    def writeLyric(self):
        lenVersNumber = self.lyricDict.pop('lenVerseNumber', 0)
        prefix = lyricSign
        verses = self.lyricDict.keys()
        verses.sort()
        for i in verses:
#            self.f.write('\n')
            self.s += '\n'
            if '$' in self.lyricDict[i]:
                s = string.replace(self.lyricDict[i], '$', ' ')
            else:
                s = ' ' * lenVersNumber + self.lyricDict[i]
            self.writeBraille(prefix + s)
            prefix = ' ' * len(lyricSign)

    def writePendingBreathSign(self):
        if self.breathStorage <> '':
            self.writeBraille(self.breathStorage)
            self.breathStorage = ''
        
    def handleBreathSign(self, noteObject):
        self.writePendingBreathSign()
        for text in noteObject.getElementsByTagName('text'):
            x = text.getAttribute('x')
            for content in text.getElementsByTagName('content'):
                txt = content.getText()
                if txt == '':
                    continue
                cont = self.encode(txt)
                if cont in [',' , "'"]:
                    if float(x) < 0.5:
                        self.writeBraille(breathSign) # atemzeichen links von Note
                    else:
                        self.breathStorage = breathSign # atemzeichen rechts von Note

    def handleText(self, noteObject):
        self.printP3 = False
        textFound = False
        setWordSign = False
        drawObjList = []
        for drawObjects in noteObject.getElementsByTagName('drawObjects'):
            drawObj = drawObjects.getChildNode('drawObj',0)
            if drawObj.getChildNode('transposable',0).isEmpty():
                drawObjList.append(drawObj)
        
        for drawObj in drawObjList:
            for text in drawObj.getElementsByTagName('text'):
                x = text.getAttribute('x')
                y = text.getAttribute('y')
                for content in text.getElementsByTagName('content'):
                    txt = content.getText()
                    if txt == '':
                        continue
                    cont = self.encode(txt)
                    cont = convertDigitsToBraille(cont)

                    # römische Bezifferung I, II, III ausfiltern ind durch >i[i[i]] ersetzen 
                    iCount = 0
                    for i in range(len(cont)):
                        if cont[i] == 'I':
                            iCount += 1
                        elif iCount and cont[i] in ['.', ' ']:
                            break
                        else:
                            iCount = 0
                            break
                    if iCount:
                        cont = '>' + 'i' * iCount + cont[iCount:]

#                    cont = cont.replace('\n',' ') # Sonst springt das Ergebnis aus der Edit-Zeile in den Liedtext
                    contlines = cont.split('\n') # Für jede Zeile ein neues @
                    for contline in contlines:
                        conts = string.split(contline)
                        for font in text.getElementsByTagName('font'):
                            if 'capella' in font.getAttribute('face'):
                                # capella-Text wird ignoriert
                                continue
                            elif not iCount and len(contline) <= 2:
                                # kurzer Text wird ausgefiltert
                                continue
                            elif not (-6.0 < float(y) < 8.0):
                                # Text darf nicht zu weit von Notenlinie entfernt sein
                                continue
                            else:
                                if len(conts)  <= 2:  # Text aus max. 2 Blöcken
                                    for c in conts:
                                        self.writeBraille('@%s' % (c))
                                    setWordSign = False
                                    self.lastPitch = -100  # eine Oktavangabe erzwingen!
                                    textFound = True
                                else:  # langer Text
                                    if not textFound and self.lastBase <> '0':
                                        # Wenn dies der erste Text ist und der Text nicht am Taktanfang steht
                                        self.writeBraille(barSeparation)  
                                    self.writeBraille('@%s' % (contline))
                                    setWordSign = True
                                    self.lastPitch = -100  # eine Oktavangabe erzwingen!
                                    textFound = True

        if setWordSign:
            self.writeBraille('@ ')
        elif textFound and cont[len(cont)-1:] <> '.':
            self.printP3 = True
        

    def startNoteObj(self, n):
        if self.barSeparation:
            self.writeBraille(barSeparation)
            self.barSeparation = False

        self.handleBarline(n)            

        if n.getName() in ('chord', 'rest'):

            wedgeStorage.next()
            trillStorage.next()

            if self.firstNote:
                self.writeBraille(' ')
                self.lastBase = '0'
                self.firstNote = False

            #Volta Signs
            self.handleVoltaSigns(n)

            # Tuplets
            if self.tupletTime <= Rational('0'):
                self.triplet = False
                for tuplet in n.getElementsByTagName('tuplet'):
                    if tuplet.hasAttribute('count'):
                        count = tuplet.getAttribute('count')
                        if count == '3':
                            self.writeBraille(';')
                        else:
                            self.writeBraille('_')
                            for ch in count:
                                self.writeBraille(digits2[int(ch)])
                            self.writeBraille('.')
                        self.triplet = True       # damit wird der Wert des Tuplets berechnet
                            
            # Bindebogen
            for drawObj in n.getElementsByTagName('drawObj'):
                if len(drawObj.getElementsByTagName('slur')) > 0:
                    basic = drawObj.getElementsByTagName('basic')
                    if len(basic) > 0:
                        noteRange = eval(basic[0].getAttribute('noteRange'))
                        isPhrase = len(drawObj.getElementsByTagName('form')) > 0   # punktierter Bindebogen
                        if noteRange in [1,2,3]:
                            # Das Zeichen C wird für einen Bindebogen über höchstens vier Noten benutzt.
                            # Es steht nach jeder Note mit Ausnahme der letzten.
                            if isPhrase:
                                for i in range(0, noteRange):
                                    slurStorage.add(i + 1, slurPhrase)
                            else:                                
                                for i in range(0, noteRange):
                                    slurStorage.add(i + 1, slurShort)
                        elif noteRange > 3:
                            # Das Zeichen <B steht vor der ersten Note der Phrase und
                            # das Zeichen >; nach der letzten Note der Phrase
                            self.writeBraille(slurBegin)
                            slurStorage.add(noteRange + 1, slurEnd)
                    else:
                        # Bindebogen hängt nur an einer Note
                        # ToDo
                        pass

            # diverse Musiksymbole vor der Note
            self.handleMusicalSymbolsBeforeNote(n)

            # Atemzeichen
            self.handleBreathSign(n)

            # Text
            self.handleText(n)

            # Triller / Mordent
            self.handleTrill(n)

            # Dynamikzeichen 
            self.handleDynamics(n)

            # cresc. decresc.
            self.handleWedge(n)

            # Artikulationszeichen
            self.handleArticulation(n)

            # Liedtext
            self.handleLyric(n)
            

    def calculateChords(self,n):
        self.intervalSigns = ''
        self.octaveSign = ''
        if n.getName() <> 'chord':
            return            
        
        if self.clefSign[0] in ['G','C']:
            # höchste Note zuerst bei G und C Schlüssel
            self.pitches.reverse()
            alterOctave = -1
        else:
            # tiefste Note zuerst bei F Schlüssel
            self.pitches.sort()
            alterOctave = +1

        pitch, alteration = self.pitches[0]
        self.relPitch = pitch % 7
        octave = pitch // 7
        self.pitch = pitch
        self.alteration = alteration

        interval = abs(pitch - self.lastPitch)

        # Oktave schreiben (Regel siehe oben!)
        if interval > 4 or interval > 2 and pitch//7 != self.lastPitch//7:
            self.octaveSign = octaves[octave-1]
        else:
            self.octaveSign = ''

        self.lastPitch = pitch

        # Intervalle bestimmen
        I = intervals(self.pitches)
        self.intervalSigns = ''
        if I <> 0:
            # Intervalle vorhanden
            i = 0
#            messageBox("calculateChords","self.pitches "+str(self.pitches))
            for (p,a) in I:
                if abs(self.pitches[i+1][0] - self.pitches[i][0]) > 8:
                    # Intervall ist grösser als Oktave dann Oktavzeichen
                    self.intervalSigns += octaves[octave-1 + alterOctave]
                pitch1,alter1 = self.pitches[i+1]
                relPitch1 = pitch1 % 7
                self.intervalSigns += self.getAlterationString(pitch1, relPitch1, alter1)
                self.intervalSigns += intervalSigns[p]
                i += 1
        

    def getAlterSign(self, pitch, alterSign, sign):
        # alterSign - von Note
        # sign - in Tonart enthalten
        retval = ''
        if self.alterationSigns.get(pitch) == alterSign:
            pass
        elif alterSign <> sign:
            retval = alterSign
#            self.writeBraille(alterSign)
            self.alterationSigns[pitch] = alterSign
        elif not self.alterationSigns.get(pitch):
            pass
        elif self.alterationSigns.get(pitch) <> alterSign:
            retval = alterSign
#            self.writeBraille(alterSign)
            self.alterationSigns[pitch] = alterSign
        return retval

    def finishNoteObj(self, n):
        if n.getName() in ('chord', 'rest'):

            # Haltebogen auswerten
            if self.hasTie:
                if self.nHeads > 1 and self.allTie:
                    slurStorage.add(1, allTieSign)
                else:
                    slurStorage.add(1, tieSign)
                    
            slurStorage.next()
            self.barline = False
            d = n.getElementsByTagName('duration')[0]
            base = str(d.getAttribute('base'))
            #d = Rational(base)
            t = base.split('/')
            p = t[0].strip()
            if len(t) > 1:
                q = t[1].strip()
            else:
                q = 1
            d = Rational(int(p),int(q))

            # Notenwert und Intervalle berechnen
            self.calculateChords(n)
            
            # Notenwert                
            if n.getName() == 'rest':
                self.relPitch = 7

            # kleines Wertscheidungszeichen am Zeilenbeginn, wenn Takt / 1ste Note == 16
            #    z.B. 4/4 und 16tel
            if self.firstNote:
                if self.meter / Rational(base) == Rational(16):
                    self.writeBraille(valueSepSmaller)
                
            # zwischen Noten mit gleichem Namen, aber unterschiedlichem Wert wird ein Wertscheidungszeichen gesetzt
            baseQ = Rational(self.lastBase) / Rational(base)
            if  baseQ == Rational(16) and base <> '1/256':
                self.writeBraille(valueSepSmaller)
            elif baseQ == Rational('1/16'):
                self.writeBraille(valueSepGreater)
            elif base == '1/256':
                if self.lastBase <> '1/256':
                    self.writeBraille(prefix256)
                
            # Vorzeichen
            if n.getName() == 'chord':
                self.writeBraille(self.getAlterationString(self.pitch, self.relPitch, self.alteration))
##                pitch = 'CDEFGAB'[self.relPitch]
##                alterSign = [doubleflat,flat,natural,sharp,doublesharp][self.alteration + 2]
##                if self.fifths > 0:
##                    # messageBox('self.fifth',str(self.pitch) + ' ' + str(self.fifths))
##                    alterPitch = pitch in 'FCGDAEB'[0:self.fifths]
##                    if alterPitch:
##                        self.setAlterSign(alterSign,sharp)
##                    else:
##                        self.setAlterSign(alterSign,natural)
##                        
##                elif self.fifths < 0:
##                    alterPitch = pitch in 'BEADGCF'[0:-self.fifths]
##                    if alterPitch:
##                        self.setAlterSign(alterSign,flat)
##                    else:
##                        self.setAlterSign(alterSign,natural)
##                else:  # C-Dur
##                    self.setAlterSign(alterSign,natural)

            # Oktavzeichen
            if self.octaveSign <> '':
                self.writeBraille(self.octaveSign)
                self.octaveSign = ''

            # Noten / Pausen
            if   base == '1/1':
                self.writeBraille(wholeNotes  [self.relPitch])
            elif base == '1/16':
                self.writeBraille(sixteenthNotes  [self.relPitch])
            elif base == '1/2':
                self.writeBraille(halfNotes   [self.relPitch])
            elif base == '1/32':
                self.writeBraille(thirtysecondthNotes   [self.relPitch])
            elif base == '1/4':
                self.writeBraille(quarterNotes[self.relPitch])
            elif base == '1/64':
                self.writeBraille(fourtysixthNotes[self.relPitch])
            elif base == '1/8':
                self.writeBraille(eighthNotes [self.relPitch])
            elif base =='1/128':
                self.writeBraille(hundredtwentyeightthNotes [self.relPitch])
            elif base == '1/256':
                self.writeBraille(hundredtwentyeightthNotes  [self.relPitch])

            # Kasten-, Mehrtaktpausen
            elif  n.getName() == 'rest' and d.q == 1:
                i = d.p
                if i in [1,2,3]:
                    self.writeBraille(i * wholeNotes  [self.relPitch])
                elif i > 3:
                    b = convertDigitsToBraille(str(i))
                    self.writeBraille( b + wholeNotes  [self.relPitch])

            # Kastennoten
            elif  n.getName() == 'chord' and d.q == 1:
                i = d.p
                self.writeBraille(wholeNotes  [self.relPitch])
                i -= 1
                while i > 0:
                    self.writeBraille(boxSign)
                    self.writeBraille(wholeNotes  [self.relPitch])
                    i -= 1
            else:
                self.writeBraille(undefined)

            self.lastBase = base

            # Notendauer berechnen
            if len(n.getElementsByTagName('duration')) == 0:
                duration = Rational('0')
            elif  n.getName() == 'rest' and d.q == 1:   # Ganz- und Mehrtaktpausen 
                self.time = self.meter
                duration = Rational('0')
            else:
                dur = n.getElementsByTagName('duration')[0]
                if dur.getAttribute('noDuration') == 'true':
                    duration = Rational('0')
                else:
                    duration = Rational(str(dur.getAttribute('base')))
                    count = '1'
                    for tuplet in dur.getElementsByTagName('tuplet'):
                        if tuplet.hasAttribute('count'):
                            count = tuplet.getAttribute('count')
                        else:
                            count = '1'
                        if tuplet.hasAttribute('tripartite') and tuplet.getAttribute('tripartite') == 'true':
                            #                   0     1     2     3     4     5     6     7     8     9     10     11     12      13
                            factor = Rational(['1/1','1/1','3/4','2/3','3/4','3/5','3/6','6/7','6/8','6/9','6/10','6/11','12/12','12/13','12/14','12/15'][eval(count)])
                        else:
                            factor = Rational(['1/1','1/1','2/2','2/3','4/4','4/5','4/6','4/7','8/8','8/9','8/10','8/11','8/12', '8/13', '8/14', '8/15' ][eval(count)])
                        if tuplet.hasAttribute('prolong') and tuplet.getAttribute('prolong') == 'true':
                            factor = factor * 2
                        duration = duration * factor
                        
                    if dur.hasAttribute('dots'):
                        if dur.getAttribute('dots') == '1':
                            duration = duration * Rational('3/2')
                            self.writeBraille('.')
                        else:
                            duration = duration * Rational('7/4')
                            self.writeBraille('..')

                    # Wenn triplet gesetzt ist, wird die Tuplet Dauer anhand der ersten Note berechnet
                    if self.triplet:
                        self.triplet = False
                        self.tupletTime = Rational(str(count)) * duration

            if self.tupletTime > Rational('0'):
                self.tupletTime -= duration

            self.time += duration

            #IntervalLzeichen
            self.writeBraille(self.intervalSigns)                

            # diverse Musiksymbole nach der Note
            self.handleMusicalSymbolsAfterNote(n)

            # Witergeltungslinie Ende
            while trillStorage.isfilled():
                self.writeBraille(trillStorage.getFirst())

            # Bindebogen
            while slurStorage.isfilled():
                self.writeBraille(slurStorage.getFirst())

            # Crescendo, Decrescendo
            while wedgeStorage.isfilled():
                self.writeBraille(wedgeStorage.getFirst())
                self.lastPitch = -100  # eine Oktavangabe erzwingen!

    def getAlterationString(self, absPitch, relPitch, alteration):
        retval = ''
        pitch = 'CDEFGAB'[relPitch]
        alterSign = [doubleflat,flat,natural,sharp,doublesharp][alteration + 2]
        if self.fifths > 0:
            # messageBox('self.fifth',str(self.pitch) + ' ' + str(self.fifths))
            alterPitch = pitch in 'FCGDAEB'[0:self.fifths]
            if alterPitch:
                retval = self.getAlterSign(absPitch, alterSign,sharp)
            else:
                retval = self.getAlterSign(absPitch, alterSign,natural)
                
        elif self.fifths < 0:
            alterPitch = pitch in 'BEADGCF'[0:-self.fifths]
            if alterPitch:
                retval = self.getAlterSign(absPitch, alterSign,flat)
            else:
                retval = self.getAlterSign(absPitch, alterSign,natural)
        else:  # C-Dur
            retval = self.getAlterSign(absPitch, alterSign,natural)
        return retval

    def handleHead(self, head):
        p = head.getAttribute('pitch')
        pitch = 'CDEFGAB'.find(p[0]) + 7 * int(p[1])
        # Vorzeichen -2 ... +2, bb ... ##
        alteration = 0
        for alter in  head.getElementsByTagName('alter'):
            if alter.getAttribute('step'):
                alteration = int(alter.getAttribute('step'))
        self.pitches += [(pitch, alteration)]

        # Haltebogen
        hasTie = False
        for tie in head.getElementsByTagName('tie'):
            if tie.getAttribute('begin') == 'true':
                hasTie = True
        if hasTie:
            self.hasTie = True
        else:
            self.allTie = False
                
        self.nHeads += 1

#---------------------------------------------------------------
def cursorObjM1():
    score = activeScore()
    if not score:
        return 0
    sel = curSelection()[1]
    voice = activeScore().system(sel[0]).staff(sel[1]).voice(sel[2])
    if sel[3] > 0:
        return voice.noteObj(sel[3]-1)
    return 0

def meterSign(p,q):
    if test == 1:
        s = '<'+str(p) + ' ' + str(q) + 'tel-Takt>'
    elif test == 2:
        s = str(p) + ' '
        if q == "2":
            s += 'halbetakt '
        elif q == "4":
            s += 'vierteltakt'
        elif q == "8":
            s += 'achteltakt'
    else:
        s = '#'
        for c in p:
            s += digits[int(c)]
        for c in q:
            s += digits2[int(c)]
    return s

def strRational(r):
    if test == 2:
        if r.q == 2:
            if r.p == 1:
                return "ein halb"
            return str(r.p)+" halbe"
        elif r.q == 4:
            if r.p == 1:
                return "ein viertel"
            return str(r.p)+" viertel"
        elif r.q == 8:
            if r.p == 1:
                return "ein achtel"
            return str(r.p)+" achtel"
        elif r.q == 16:
            if r.p == 1:
                return "ein sechzehntel"
            return str(r.p)+" sechzehntel"
        elif r.q == 32:
            if r.p == 1:
                return "ein zweiunddreißigstel"
            return str(r.p)+" zweiunddreißigstel"
        elif r.q == 64:
            if r.p == 1:
                return "ein vierundsechzigstel"
            return str(r.p)+" vierundsechzigstel"
        elif r.q == 128:
            if r.p == 1:
                return "ein hundertachtundzwanzigstel"
            return str(r.p)+" hundertachtundzwanzigstel"
    return str(r)

def fromCapella3(capella3str):
    if capella3str == "f":
        return "forte"
    elif capella3str == "g":
        return "fortissimo"
    elif capella3str == "h":
        return "ffortissimo"
    elif capella3str == "j":
        return "mezzoforte"
    elif capella3str == "p":
        return "piano"
    elif capella3str == "q":
        return "pianissimo"
    elif capella3str == "r":
        return "ppianissimo"
    elif capella3str == "i":
        return "mezzopiano"
    elif capella3str == "s":
        return "sforzato"
    elif capella3str == "z":
        return "sforzato"
    elif capella3str == "{":
        return "forzato"
    elif capella3str == "|":
        return "fortepiano"
    elif capella3str == "\xc2":
        return "Triller194"   
    elif capella3str == "\xff":
        return "Ziffer 9"
    elif capella3str == "y":
        return "Segno"
    return tr('Musiksymbol')+capella3str

def extractRichText(rtfstring):
    import Rtf2TxtAndFont
    TxtAndFonts = Rtf2TxtAndFont.getTxt(rtfstring)
#    messageBox("TxtAndFonts",str(TxtAndFonts))
    drawObjStr = ""
    for j in range(1,len(TxtAndFonts)):
        textchunk = TxtAndFonts[j].encode('utf-8')
        index = 0
#        messageBox("textchunk",str(textchArr))
        for i in range(6):
            index = textchunk.find(";",index) + 1
        drawObjStr += textchunk[index:]
    return drawObjStr

def readDrawObjDict(d):
    if d["type"] == "slur":
        drawObjStr = "%s %d %s"%(tr('slur'),d["noteRange"]+1, tr('notes'))
    elif d["type"] == "text":
        font = d["font"]
        if capVersion() >= (7, 0, 2):
            stext = d["content"]
        else:
            stext = d["content"]
        if font["face"] == "capella3":
            drawObjStr = fromCapella3(stext)
        else:
            drawObjStr = "%s: %s"%(tr('simpleText'),stext)
    elif d["type"] == "transposable":
        drawObjStr = tr('transpos')+" "
        items = d["items"]
        item = items[d["nRefNote"]+len(items)/2-2]
#        messageBox("readDrawObjDict "+str(len(items))+" items",str(item))
        if item["type"] == "group":
            items1 = item["items"]
#            messageBox("item",str(items1))
            for item1 in items1:
                if item1["type"] == "text":
                    if item1["font"]["face"] == "capella3":
                        if item1["content"] == "Q":
                            drawObjStr += "b"
                        elif item1["content"] == "S":
                            drawObjStr += "#"
                    else:
                        drawObjStr += item1["content"]
        elif item["type"] == "richText":
            drawObjStr += extractRichText(item["data"])
    elif d["type"] == "guitar":
        drawObjStr = tr('guitar')
    elif d["type"] == "metafile":
        drawObjStr = tr('image')
    elif d["type"] == "richText":
        drawObjStr = tr('richText')
        drawObjStr += extractRichText(d["data"])
    elif d["type"] == "line":
        drawObjStr = tr('line')
    elif d["type"] == "rectangle":
        drawObjStr = tr('rect')
    elif d["type"] == "ellipse":
        drawObjStr = tr('ellipse')
    elif d["type"] == "wavyLine":
        drawObjStr = tr('wavy')
    elif d["type"] == "bracket":
        number = d["number"]
        if number == 3:
            oleStr = tr('triplet')
        elif number == 2:
            oleStr = tr('duplet')
        else:
            oleStr = "%d-%s"%(number,tr('tuplet'))
        drawObjStr = "%s %d %s"%(oleStr, d["noteRange"]+1,tr('notes'))
    elif d["type"] == "wedge":
        try:
            if d["decrescendo"]:
                drawObjStr = "%s %d %s"%(tr('decrescendo'),d["noteRange"]+1,tr('notes'))
            else:
                drawObjStr = "%s %d %s"%(tr('crescendo'),d["noteRange"]+1,tr('notes'))
        except:
            drawObjStr = "%s %d %s"%(tr('crescendo'),d["noteRange"]+1,tr('notes'))
    elif d["type"] == "notelines":
        drawObjStr = tr('noteLines')
    elif d["type"] == "polygon":
        drawObjStr = tr('polygon')
    elif d["type"] == "volta":
        drawObjStr = "%s %s %d %d %s"%(tr('ending'),tr('number'), d["firstNumber"],d["noteRange"]+1,tr('notes'))
    elif d["type"] == "trill":
        drawObjStr = tr('trill')
    elif d["type"] == "group":
        drawObjStr = tr('group')
    else:
        drawObjStr = "??"
    return drawObjStr

def makeDrawObjDictFromNode(drawObjNode):
    specNode = drawObjNode.getChildNodeI(0)
    name = specNode.getName()
    d = {}
    d["type"] = name
    if name == "text":
        d["content"] = specNode.getChildNode("content",0).getText()
        font = {}
        font["face"] = specNode.getChildNode("font",0).getAttributes()["face"]
        d["font"] = font
    elif name == "richText":
        attrs = specNode.getAttributes()
#        messageBox("makeDrawObjDictFromNode",str(attrs))
        d["data"] = readInternalFile(attrs['file'])
    elif name == "transposable":
        attrs = specNode.getAttributes()
        items = {}
        d["nRefNote"] = ord(attrs["base"])-ord("C")
        d["items"] = items

    return d


class BrailleExport1Obj (BrailleExport):
    def __init__(self, sel):

        self.s = ""
        self.sPos = " "
        self.selstop = sel[1]
        # falls Teil einer Stimme selektiert ist, können wir das auf der
        # Braille-Zeile sichtbar machen:
        self.selstart = sel[0]
        if self.selstop[0] != self.selstart[0] or self.selstop[1] != self.selstart[1] or self.selstop[2] != self.selstart[2]:
            self.selstart = self.selstop
        if self.selstop[3] < self.selstart[3]:
            tmp = self.selstop
            self.selstop = self.selstart
            self.selstart = tmp
        self.pyselstop = 0
        self.pyselstart = 0
        self.py2cap = {}
        self.objlist = []

        self.root = rootNode()
        xmlns = self.root.getAttributes()["xmlns"]
        self.isCAPX2 = 0 > xmlns.find("1.0")
#        messageBox("BrailleExport1Obj xmlns", xmlns + " isCAPX2 "+str(self.isCAPX2))
        sysind, staffind, voiceind, objind = sel[1]
        objind -= 1
        if sysind >= 0:
            self.startScore(self.root)
            sys = self.root.getChildNode('systems',0).getChildNode('system',sysind)
            self.nSys = sysind
            self.startSystem(sys)
            staff = sys.getChildNode('staves',0).getChildNode('staff',staffind)
            self.nStave = staffind
            self.startStaff(staff)
            voice = staff.getChildNode('voices',0).getChildNode('voice',voiceind)
            self.nVoice = voiceind
            self.startVoice(voice)
            self.firstNote = False # ' ' am Anfang vermeiden
            # zur Position noch die Taktposition hinzu
            bar, pos = self.barAndPos(sel[1])
            self.sPos += positionSeparator+str(bar)+positionSeparTakt+strRational(pos)+" "

            # hier muss noch der gültige Schlüssel gesucht werden!
            objects = voice.getChildNode('noteObjects',0);
            i = objind
            while i >= 0:
                o = objects.getChildNodeI(i)
                i -= 1
                if o.getName() == 'clefSign':
                    self.prepareClefSign(o)
                    break

        if objind >= 0 and sysind >= 0:
            s = objects.getChildNodeI(objind)
#            messageBox("BrailleExport1Obj","objind: "+str(objind))
            self.handleNoteObj(s)
            obj = cursorObjM1()
            self.handleDrawLyric(s, obj)
            self.doSound(s,obj)
        elif sysind < 0:
            self.s += tr("Seitenobjekte")
            s = self.root.getChildNode('pageObjects',0)
            self.handleDrawObjs(s)
        else:
            self.s = pos1Voice
        self.s += '\n'

#        self.handleScore(self.root)
    def prepareClefSign(self, clefSign):
        clef = clefSign.getAttribute('clef')
        if   clef == 'treble': clef = 'G2'
        elif clef == 'bass' : clef = 'F4'
        elif clef == 'alto' : clef = 'C3'
        elif clef == 'tenor': clef = 'C4'
        self.clefSign = clef        
    def barAndPos(self,pos):
        staff = activeScore().system(pos[0]).staff(pos[1])
        dm = staff.defaultMeter()
        voice = staff.voice(pos[2])
        durationsum = Rational(0)
        measurecount = 1
        for ob in voice.noteObjs():
            if ob.index() >= pos[3]:
                break
            durationsum += ob.duration()
            if durationsum >= dm:
                measurecount += 1
                durationsum -= dm
            if ob.subType() == ob.METER:
                dm = ob.meter()
            elif ob.subType() == ob.EXPL_BARLINE:
                durationsum = Rational(0)
                measurecount += 1
        return measurecount, durationsum

    def handleDrawLyric(self, objNode, obj):
        # Liedtexte
        lyricNode = objNode.getChildNode("lyric",0)
        nVerse = 0
        if not lyricNode.isEmpty():
            nVerse = lyricNode.getChildNodeCount()
        for iV in range(nVerse):
            verseNode = lyricNode.getChildNode("verse", iV)
            attrs = verseNode.getAttributes()
            if test == 2:
                verseStr = "Strophe"+" "+str(int(attrs["i"])+1)+": "
            else:
                verseStr = str(int(attrs["i"])+1)+": "
            txt = verseNode.getText()
            if not self.isCAPX2:
                txt = LegacyToUtf(txt)
            verseStr += txt
            self.objlist.append(verseStr)
        # Grafikobjekte
        if obj:
            nDrawObjs = obj.nDrawObjs()
            for i in range(nDrawObjs):
                d = obj.drawObj(i)
                drawObjStr = readDrawObjDict(d)
                self.objlist.append(drawObjStr)
        # Grafikobjekte über CapXNode
##        drawObjsNode = objNode.getChildNode("drawObjects",0)
##        self.handleDrawObjs(drawObjsNode)

    def handleDrawObjs(self, pageObjsNode):
        nDrawObjs = pageObjsNode.getChildNodeCount()
#        messageBox("handleDrawObjs Node","nDrawObjs: "+str(nDrawObjs))
        for i in range(nDrawObjs):
            drawObjNode = pageObjsNode.getChildNode("drawObj",i)
            d = makeDrawObjDictFromNode(drawObjNode)
            drawObjStr = readDrawObjDict(d)
            self.objlist.append(drawObjStr)
    
    def doSound(self, s, obj):
        name = s.getName()
        percussionPitch = 58 # vibraslap
        if name == "chord":
            nHeads = obj.nHeads()
            pitches = []
            for i in range(nHeads):
                pitches.append(obj.chromaticPitch(i))
            MidiChan = 0  # nur 16 Midikanäle möglich
            MidiVolume = 127       # todo: aus Mustersystem holen
            for pitch in pitches:
                MidiOut.noteOn(MidiChan, pitch, MidiVolume)
            time.sleep(0.5)
            for pitch in pitches:
                MidiOut.noteOff(MidiChan, pitch)
        else:
            if name == "rest":
                percussionPitch = 38 # acoustic snare
            elif name == "barline":
                percussionPitch = 42 # closed high-hat
            elif name == "clefSign":
                percussionPitch = 84 # chimes (Schlüsselbund!)
            elif name == "timeSign":
                percussionPitch = 72 # long whistle (Rhythmusänderung im Samba!)
            elif name == "keySign":
                percussionPitch = 79 # open cuica
                
            MidiChan = 9  # nur 16 Midikanäle möglich
            MidiVolume = 127       # todo: aus Mustersystem holen
            MidiOut.noteOn(MidiChan, percussionPitch, MidiVolume)
            time.sleep(0.5)
            MidiOut.noteOff(MidiChan, percussionPitch)
        
#-----------------------------------------------------------------------

def writeBrailleRel():
    """ schreibt die aktuelle Partitur unter gleichem Namen mit Erweiterung '.braille'
    """
    if activeScore():
##        if not ':' in activeScore().pathName():
##            messageBox('Braille-Export', 'Bitte Partitur zunächst speichern')
##            return
##        tmpFile = tempfile.mktemp('.capx')
##        
##        h, t = os.path.split(activeScore().pathName())
##
##        dirHandling = opt.setdefault('BrailleDirectoryHandling','0')
##        if dirHandling == '0':
##            ownDir = h
##        elif dirHandling == '1':
##            ownDir = os.path.join(h, 'Braille')
##            opt['BrailleDirectory'] = ownDir
##        elif dirHandling == '2':
##            ownDir = opt.get('BrailleDirectory')
##            if ownDir :
##                pass
##            else:
##                ownDir = os.path.join(h, 'Braille')
##                opt['BrailleDirectory'] = ownDir
##
##        if not os.path.isdir(ownDir):
##            os.makedirs(ownDir)
##
##        options.set(opt)


#        activeScore().write(tmpFile)
        BrEx1 = BrailleExport1Obj(curSelection())
        if BrEx1.showWindow(True) and BrEx1.sPos != " ":

            BrEx = BrailleExport(curSelection())
            if BrEx.showWindow(False):
                pass

#        os.remove(tmpFile)

def writeBrailleAbs():
    """ schreibt die aktuelle Partitur in eine feste Datei
    """
    if activeScore():
        tmpFile = tempfile.mktemp('.capx')
#        outFile = r'c:\test.braille' # nach Wunsch anpassen !!!
        activeScore().write(tmpFile)
        BrailleExport(tmpFile, curSelection())
        os.remove(tmpFile)

writeBrailleRel()
#---------------- weiter runter gehts wirklich nicht ----------------

