# -*- coding: ISO-8859-1 -*-
""" capellaScript -- Bernd Jungmann
>>> Wo bin ich
Unterstützung für Blinde:||
Das Skript zeigt ein Fenster mit 
einem Edit-Feld, in dem die aktuelle 
Cursor-Position beschrieben ist. Diese 
Beschreibung kann über einen Screen-Reader 
auf der Braille-Zeile ausgegeben oder laut 
vorglesen werden.
Version 3.1 BJ 26.11.08
Versetzungszeichen jetzt gefiltert nach Tonart,
abschaltbar durch g_noRedundantAlters = False
Version 3: BJ 15.11.08
Unterstützung für Englisch
Version 2: Bernd Jungmann 30.9.08
Textausgabe modifiziert
DrawObj in separaten Fenstern
Version 1: Bernd Jungmann 25.9.08
<<<
<?xml version="1.0" encoding="ISO-8859-1"?>
<info>
  <lang id="en">
    <title>Where am I?</title>
    <descr>
      <p>Support for blind users:</p>
      <p></p>
      <p>The script shows a window with an edit field containing
a description of the note object at the cursor position. This
description may be read aloud by a screen reader or routed to
a Braille display.</p>
        <p></p>
        <p>Version 3.1 Bernd Jungmann 26.11.08</p>
    </descr>
  </lang>
  <lang id="de">
    <title>Wo bin ich?</title>
    <descr>
      <p>Unterstützung für Blinde:</p>
      <p></p>
      <p>Das Skript zeigt ein Fenster mit 
einem Edit-Feld, in dem das Notenobjekt an der 
Cursor-Position beschrieben ist. Diese 
Beschreibung kann über einen Screen-Reader 
auf der Braille-Zeile ausgegeben oder laut 
vorglesen werden. </p>
      <p></p>
      <p>Version 3.1 Bernd Jungmann 26.11.08</p>
    </descr>
  </lang>
</info>
"""
# Vielen Dank an Loic Fejoz für seinen RTF-Parser Rtf2TxtAndFont
# http://sourceforge.net/projects/pyrtflib

# unterdrücke Vorzeichen, die zur aktuellen Tonart gehören
# (d.h. Note wird angezeigt wie per Computertastatur eingegeben)
g_noRedundantAlters = True

translations = [('de', {
    'myTitle': 'Wo bin ich?',
    'rest': 'P',
    'wholeMeasureRest': 'G',
    'measure': 'T',
    'object': 'O',
    'voice': 'St',
    'stave': 'Z',
    'key': 'Tonart',
    'system': 'Sy',
    'barline': 'fester Taktstrich',
    'clef': 'Schlüssel',
    'meter': 'Metrum',
    'slur': 'Bindebogen',
    'notes': 'Noten',
    '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',
    'Musiksymbol': 'Musiksymbol ',
    'end': 'Ende'}),
                ("en", {
    'myTitle': 'Where am I?',
    'rest': 'R',
    'wholeMeasureRest': 'W',
    'measure': 'M',
    'object': 'O',
    'voice': 'V',
    'stave': 'St',
    'key': 'key',
    'system': 'Sy',
    'barline': 'fixed barline',
    'clef': 'clef',
    'meter': 'meter',
    'slur': 'slur',
    'notes': 'notes',
    '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',
    'Musiksymbol': 'music symbol ',
    'end': 'end'})]

setLanguages(translations)


import time

def gettime(duration):
    if duration == 0:
        return ""
    dots = 0
    while duration.p > 1 and duration.q > 1:
        duration.p -= 1
        duration.p /= 2
        duration.q /= 2
        dots +=1
    time = str(duration.q)
    while dots > 0:
        time += "."
        dots -= 1
    if duration.q == 1:
        time = tr('wholeMeasureRest') + str(duration)
    return time

def barAndPos(as,pos):
    staff = as.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 = 0
            measurecount += 1
    return measurecount, durationsum

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"
    return tr('Musiksymbol')+capella3str

g_alterstring = {-1:"-", -2:"--",0:"", 1:"+",2:"++"}
locale = getLocale()
if locale == "de-DE":
    g_octaves = ["?","SK","KO","GR","KL","1","2","3","4","5","6"]
    g_notes = ["c","d","e","f","g","a","h"]
else:
    g_octaves = ["?","0","1","2","3","4","5","6","7","8","9"]
    g_notes = ["c","d","e","f","g","a","b"]
g_noteKeys = [(-6,2),(-4,4),(-2,6),(-7,1),(-5,3),(-3,5),(-1,7)]

def pitchToString(dp, key):
    step, alter = dp
    iOctave = step / 7
    iNote = step%7
    if g_noRedundantAlters:
        low, high = g_noteKeys[iNote]
        if alter == 0:
            if key <= low:
                alterfiltered = 1
            elif key >= high:
                alterfiltered = -1
            else:
                alterfiltered = alter
        elif alter < 0:
            if key <= low:
                alterfiltered = 0
            elif key >= high:
                alterfiltered = -2
            else:
                alterfiltered = alter
        elif alter > 0:
            if key >= high:
                alterfiltered = 0
            elif key <= low:
                alterfiltered = 2
            else:
                alterfiltered = alter
    else:
        alterfiltered = alter
    notestring = g_octaves[iOctave] + g_alterstring[alterfiltered] + g_notes[iNote]
    return notestring
    
if activeScore():
    as = activeScore()
    vl = as.voiceList()
    sel = curSelection()
    start = sel[0]
    stop = sel[1]
    sysind, staffind, voiceind, objind = stop
    obj = cursorObj()
    pitches = []
    bar, pos = barAndPos(as, stop)
    barstring = "%s%d+%s"%(tr('measure'),bar,str(pos))
    nDrawObjs = 0
    if obj:
        system = as.system(sysind)
        moment = obj.time()
        subtype = obj.subType()
        objstring = "?"
        timestring = gettime(obj.duration())
        keystring = obj.curKey()
        if subtype == obj.CHORD:
            nDrawObjs = obj.nDrawObjs()
            nHeads = obj.nHeads()
            if nHeads > 1:
                objstring = "("
                for i in range(nHeads):
                    if i > 0:
                        objstring += " "
                    dp = obj.diatonicPitch(i)
                    objstring += pitchToString(dp, keystring) + timestring
                    pitches.append(obj.chromaticPitch(i))
                objstring += ")"
            else:
                dp = obj.diatonicPitch(0)
#                objstring += " " + str(dp)
                objstring = pitchToString(dp, keystring) + timestring
                pitches.append(obj.chromaticPitch(0))
        elif subtype == obj.REST:
            nDrawObjs = obj.nDrawObjs()
            objstring = "%s%s"%(tr('rest'),timestring)
        elif subtype == obj.EXPL_BARLINE:
            objstring = tr('barline')
        elif subtype == obj.CLEF:
            objstring = tr('clef')
        elif subtype == obj.METER:
            d = obj.meter()
            objstring = "%s %s"%(tr('meter'),str(d))
        elif subtype == obj.KEY:
            voice = activeScore().system(stop[0]).staff(stop[1]).voice(stop[2])
            if obj.index()+1 < voice.nNoteObjs():
                obj1 = voice.noteObj(obj.index()+1)
                objstring = "%s %s"%(tr('key'),str(obj1.curKey()))
            else:
                objstring = tr('key')
    else:
        objstring = tr('end')
        voice = activeScore().system(stop[0]).staff(stop[1]).voice(stop[2])
        if 0 < voice.nNoteObjs():
            lastObj = voice.noteObj(voice.nNoteObjs()-1)
            moment = lastObj.time() + lastObj.duration().__float__()
        else:
            moment = 0.0
        if stop[3] > 1:
            keystring = voice.noteObj(stop[3]-1).curKey()
        else:
            keystring = 0
    if nDrawObjs > 0:
        drawObjString = "+%d"%nDrawObjs
    else:
        drawObjString = ""
    edit = Edit("%s %s %s%d%s %s%d %s%d %s%d %s%d"%
                (objstring, barstring, tr('object'),objind+1, drawObjString, tr('voice'),
                voiceind+1, tr('stave'), staffind+1, tr('key'), keystring, tr('system'),sysind+1), width=60)
    if nDrawObjs > 0:
        list = [edit]
        for i in range(nDrawObjs):
            d = obj.drawObj(i)
            if d["type"] == "slur":
                drawObjString = "%s %d %s"%(tr('slur'),d["noteRange"]+1, tr('notes'))
            elif d["type"] == "text":
                font = d["font"]
                if font["face"] == "capella3":
                    drawObjString = fromCapella3(d["content"])
                else:
                    drawObjString = "%s: %s"%(tr('simpleText'),d["content"])
            elif d["type"] == "transposable":
                drawObjString = tr('transpos')
            elif d["type"] == "guitar":
                drawObjString = tr('guitar')
            elif d["type"] == "metafile":
                drawObjString = tr('image')
            elif d["type"] == "richText":
                import Rtf2TxtAndFont
                TxtAndFonts = Rtf2TxtAndFont.getTxt(d["data"])
 #               messageBox("TxtAndFonts",str(TxtAndFonts))
                drawObjString = tr('richText')
                for j in range(1,len(TxtAndFonts)):
                    textchunk = TxtAndFonts[j]
                    index = 0
#                    messageBox("textchunk",textchunk)
                    for i in range(6):
                        index = textchunk.find(";",index) + 1
                    drawObjString += textchunk[index:]
            elif d["type"] == "line":
                drawObjString = tr('line')
            elif d["type"] == "rectangle":
                drawObjString = tr('rect')
            elif d["type"] == "ellipse":
                drawObjString = tr('ellipse')
            elif d["type"] == "wavyLine":
                drawObjString = 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'))
                drawObjString = "%s %d %s"%(oleStr, d["noteRange"]+1,tr('notes'))
            elif d["type"] == "wedge":
                try:
                    if d["decrescendo"]:
                        drawObjString = "%s %d %s"%(tr('decrescendo'),d["noteRange"]+1,tr('notes'))
                    else:
                        drawObjString = "%s %d %s"%(tr('crescendo'),d["noteRange"]+1,tr('notes'))
                except:
                    drawObjString = "%s %d %s"%(tr('crescendo'),d["noteRange"]+1,tr('notes'))
            elif d["type"] == "notelines":
                drawObjString = tr('noteLines')
            elif d["type"] == "polygon":
                drawObjString = tr('polygon')
            elif d["type"] == "volta":
                messageBox("Volta", str(d))
                drawObjString = "%s %s %d %d %s"%(tr('ending'),tr('number'), d["firstNumber"],d["noteRange"]+1,tr('notes'))
            elif d["type"] == "trill":
                drawObjString = tr('trill')
            elif d["type"] == "group":
                drawObjString = tr('group')
            editDraw = Edit(drawObjString, width=60)
            list.append(editDraw)
        vbox = VBox(list)
    else:
        vbox = VBox([edit])
    dlg = Dialog(tr('myTitle'), vbox )
    if dlg.run():
        if len(pitches) > 0:
            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)

