Source code for music21.braille.noteGrouping

# ------------------------------------------------------------------------------
# Name:         noteGrouping.py
# Purpose:      Transcribes note groupings into Braille
# Authors:      Jose Cabal-Ugaz
#               Michael Scott Asato Cuthbert
#
# Copyright:    Copyright © 2012, 2016 Michael Scott Asato Cuthbert
# License:      BSD, see license.txt
# ------------------------------------------------------------------------------
from __future__ import annotations

from collections import OrderedDict
import unittest

from music21 import clef
from music21 import dynamics
from music21 import environment
from music21 import expressions
from music21.braille import basic
from music21.braille.lookup import symbols

environRules = environment.Environment('braille/noteGrouping.py')


[docs] class NoteGroupingTranscriber: ''' Object that can transcribe note groupings. ''' def __init__(self, brailleElementGrouping=None): self.showLeadingOctave = True self.brailleElementGrouping = brailleElementGrouping self._upperFirstInFingering = None self._showClefSigns = None # duplicate of reset self.previousNote = None self.previousElement = None self.trans = [] self.transText = None
[docs] def reset(self): self.previousNote = None self.previousElement = None self.trans = [] self.transText = None
@property def showClefSigns(self): ''' Generally, in Braille, clef signs are not used. However, they can be shown for pedagogical purposes or to make a facsimile transcription of the sighted text. If not set but self.brailleElementGrouping.showClefSigns is set, uses that instead. >>> ngt = braille.noteGrouping.NoteGroupingTranscriber() >>> ngt.showClefSigns False >>> beg = braille.segment.BrailleElementGrouping() >>> ngt.brailleElementGrouping = beg >>> ngt.showClefSigns False >>> beg.showClefSigns = True >>> ngt.showClefSigns True >>> ngt.showClefSigns = False >>> ngt.showClefSigns False ''' if self._showClefSigns is not None: return self._showClefSigns elif self.brailleElementGrouping is not None: return self.brailleElementGrouping.showClefSigns else: return False @showClefSigns.setter def showClefSigns(self, new): self._showClefSigns = new @property def upperFirstInFingering(self): ''' When there are multiple fingering patterns listed at the same time, should the highest be listed first (default True) or last? If not set but self.brailleElementGrouping.upperFirstInNoteFingering is set, uses that instead. (note the slight difference in names: NoteFingering) >>> ngt = braille.noteGrouping.NoteGroupingTranscriber() >>> ngt.upperFirstInFingering True >>> beg = braille.segment.BrailleElementGrouping() >>> ngt.brailleElementGrouping = beg >>> ngt.upperFirstInFingering True >>> beg.upperFirstInNoteFingering = False >>> ngt.upperFirstInFingering False >>> ngt.upperFirstInFingering = True >>> ngt.upperFirstInFingering True ''' if self._upperFirstInFingering is not None: return self._upperFirstInFingering elif self.brailleElementGrouping is not None: return self.brailleElementGrouping.upperFirstInNoteFingering else: return True @upperFirstInFingering.setter def upperFirstInFingering(self, new): self._upperFirstInFingering = new
[docs] def transcribeGroup(self, brailleElementGrouping=None): ''' transcribe a group of notes, possibly excluding certain attributes. Returns a (unicode) string of brailleElementGrouping transcribed. ''' self.reset() if brailleElementGrouping is not None: self.brailleElementGrouping = brailleElementGrouping for brailleElement in self.brailleElementGrouping: self.transcribeOneElement(brailleElement) if brailleElementGrouping.withHyphen: self.trans.append(symbols['music_hyphen']) return ''.join(self.trans)
[docs] def translateNote(self, currentNote): if self.previousNote is None: doShowOctave = self.showLeadingOctave else: doShowOctave = basic.showOctaveWithNote(self.previousNote, currentNote) brailleNote = basic.noteToBraille(currentNote, showOctave=doShowOctave, upperFirstInFingering=self.upperFirstInFingering) self.previousNote = currentNote return brailleNote
[docs] def translateRest(self, currentRest): return basic.restToBraille(currentRest)
[docs] def translateChord(self, currentChord): allNotes = sorted(currentChord.notes, key=lambda n: n.pitch) if self.brailleElementGrouping.descendingChords: currentNote = allNotes[-1] else: currentNote = allNotes[0] if self.previousNote is None: doShowOctave = self.showLeadingOctave else: doShowOctave = basic.showOctaveWithNote(self.previousNote, currentNote) descendingChords = self.brailleElementGrouping.descendingChords brailleChord = basic.chordToBraille(currentChord, descending=descendingChords, showOctave=doShowOctave) self.previousNote = currentNote return brailleChord
[docs] def translateDynamic(self, currentDynamic): brailleDynamic = basic.dynamicToBraille(currentDynamic) self.previousNote = None self.showLeadingOctave = True return brailleDynamic
[docs] def translateTextExpression(self, currentExpression): brailleExpression = basic.textExpressionToBraille(currentExpression) self.previousNote = None self.showLeadingOctave = True return brailleExpression
[docs] def translateBarline(self, currentBarline): return basic.barlineToBraille(currentBarline)
[docs] def translateClef(self, currentClef): ''' translate Clefs to braille IF self.showClefSigns is True ''' if self.showClefSigns: brailleClef = basic.clefToBraille(currentClef) self.previousNote = None self.showLeadingOctave = True return brailleClef
translateDict = OrderedDict([ ('Note', translateNote), ('Rest', translateRest), ('Chord', translateChord), ('Dynamic', translateDynamic), ('TextExpression', translateTextExpression), ('Barline', translateBarline), ('Clef', translateClef), ])
[docs] def transcribeOneElement(self, el): ''' Transcribe a single element and add it to self.trans, setting self.previousElement along the way. >>> ngt = braille.noteGrouping.NoteGroupingTranscriber() >>> n = note.Note('C4') >>> ngt.transcribeOneElement(n) >>> ''.join(ngt.trans) '⠐⠹' >>> ngt.previousElement <music21.note.Note C> ''' elClasses = el.classes for className, classMethod in self.translateDict.items(): if className in elClasses: addBraille = classMethod(self, el) if addBraille is not None: self.trans.append(addBraille) break else: environRules.warn(f'{el} not transcribed to braille.') self.optionallyAddDotToPrevious(el) self.previousElement = el
[docs] def optionallyAddDotToPrevious(self, el=None): ''' if el is None or not a Dynamic or TextExpression, add a dot-3 Dot before the current transcription under certain circumstances: 1. self.previousElement exists 2. the last character in the current transcription (self.trans) fits the criteria for basic.yieldDots() 3. one of these three. PreviousElement was: a. a Dynamic. b. a Clef and clef signs are being transcribed c. a TextExpression not ending in "." Returns True if a dot as added, or False otherwise. ''' prev = self.previousElement if prev is None: return False if not self.trans: return False # need to consult previous element in translation if el is not None and isinstance(el, dynamics.Dynamic): return False if el is not None and isinstance(el, expressions.TextExpression): return False if (isinstance(prev, dynamics.Dynamic) or (isinstance(prev, clef.Clef) and self.showClefSigns) or (isinstance(prev, expressions.TextExpression) # TE is an abbreviation, no extra dot 3 necessary and prev.content[-1] != '.')): for dot in basic.yieldDots(self.trans[-1][0]): self.trans.insert(-1, dot) # insert one before the end, not append prev.editorial.brailleEnglish.append(f'Dot 3 {dot}') return True # only append max one dot. return False
[docs] def transcribeNoteGrouping(brailleElementGrouping, showLeadingOctave=True): ''' transcribe a group of notes, possibly excluding certain attributes. To be DEPRECATED -- called only by BrailleGrandSegment now. ''' ngt = NoteGroupingTranscriber() ngt.showLeadingOctave = showLeadingOctave return ngt.transcribeGroup(brailleElementGrouping)
# ------------------------------------------------------------------------------ class Test(unittest.TestCase): pass if __name__ == '__main__': import music21 music21.mainTest(Test) # , runTest='testGetRawSegments')