Source code for musicscore.util

import math
from typing import Union, List

from musicscore.exceptions import WrongNumberOfChordsError, LyricSyllabicOrExtensionError
from musicxml.xmlelement.xmlelement import *

note_types = {(1, 12): '32nd',
              (1, 11): '32nd',
              (2, 11): '16th',
              (3, 11): '16th',
              (4, 11): 'eighth',
              (6, 11): 'eighth',
              (8, 11): 'quarter',
              (1, 10): '32nd',
              (3, 10): '16th',
              (1, 9): '32nd',
              (2, 9): '16th',
              (4, 9): 'eighth',
              (8, 9): 'quarter',
              (1, 8): '32nd',
              (3, 8): '16th',
              (7, 8): 'eighth',
              (1, 7): '16th',
              (2, 7): 'eighth',
              (3, 7): 'eighth',
              (4, 7): 'quarter',
              (6, 7): 'quarter',
              (1, 6): '16th',
              (1, 5): '16th',
              (2, 5): 'eighth',
              (3, 5): 'eighth',
              (4, 5): 'quarter',
              (6, 5): 'quarter',
              (8, 5): 'half',
              (1, 4): '16th',
              (2, 4): 'eighth',
              (3, 4): 'eighth',
              (7, 4): 'quarter',
              (4, 3): 'half',
              (1, 3): 'eighth',
              (2, 3): 'quarter',
              (3, 2): 'quarter',
              (1, 2): 'eighth',
              (1, 1): 'quarter',
              (2, 1): 'half',
              (3, 1): 'half',
              (4, 1): 'whole',
              (6, 1): 'whole',
              (8, 1): 'breve',
              (12, 1): 'breve'
              }

#:
XML_ARTICULATION_CLASSES = [XMLAccent, XMLStrongAccent, XMLStaccato, XMLTenuto, XMLDetachedLegato, XMLStaccatissimo,
                            XMLSpiccato, XMLScoop, XMLPlop, XMLDoit, XMLFalloff, XMLBreathMark, XMLCaesura, XMLStress,
                            XMLUnstress]

#:
XML_TECHNICAL_CLASSES = [XMLUpBow, XMLDownBow, XMLHarmonic, XMLOpenString, XMLThumbPosition, XMLFingering, XMLPluck,
                         XMLDoubleTongue,
                         XMLTripleTongue, XMLStopped, XMLSnapPizzicato, XMLFret, XMLString, XMLHammerOn, XMLPullOff,
                         XMLBend, XMLTap,
                         XMLHeel, XMLToe, XMLFingernails, XMLHole, XMLArrow, XMLHandbell, XMLBrassBend, XMLFlip,
                         XMLSmear, XMLOpen,
                         XMLHalfMuted, XMLHarmonMute, XMLGolpe, XMLOtherTechnical]

#:
XML_ORNAMENT_CLASSES = [XMLDelayedInvertedTurn, XMLDelayedTurn, XMLHaydn, XMLInvertedMordent,
                        XMLInvertedTurn,
                        XMLInvertedVerticalTurn, XMLMordent, XMLOtherOrnament, XMLSchleifer, XMLShake, XMLTremolo,
                        XMLTrillMark, XMLTurn,
                        XMLVerticalTurn, XMLWavyLine]

#:
XML_DYNAMIC_CLASSES = [XMLF, XMLFf, XMLFff, XMLFfff, XMLFffff, XMLFfffff, XMLFp, XMLFz, XMLMf, XMLMp, XMLP, XMLPf,
                       XMLPp, XMLPpp, XMLPppp,
                       XMLPpppp, XMLPppppp, XMLRf, XMLRfz, XMLSf, XMLSffz, XMLSfp, XMLSfpp, XMLSfz, XMLSfzp,
                       XMLOtherDynamics]

#:
XML_OTHER_NOTATIONS = [XMLArpeggiate, XMLFermata, XMLFootnote, XMLGlissando, XMLLevel, XMLNonArpeggiate,
                       XMLOtherNotation, XMLSlide,
                       XMLSlur]

#:
XML_DIRECTION_TYPE_CLASSES = [
    XMLRehearsal, XMLSegno, XMLCoda, XMLWords, XMLSymbol, XMLWedge, XMLDashes, XMLBracket, XMLPedal,
    XMLMetronome, XMLOctaveShift, XMLHarpPedals, XMLDamp, XMLDampAll, XMLEyeglasses, XMLStringMute, XMLScordatura,
    XMLPrincipalVoice, XMLPercussion, XMLAccordionRegistration, XMLStaffDivide, XMLOtherDirection
]

#:
XML_ORNAMENT_AND_OTHER_NOTATIONS = [XMLAccidentalMark]

#:
XML_DIRECTION_TYPE_AND_OTHER_NOTATIONS = [XMLDynamics]


[docs]def lcm(l): return math.lcm(*l)
[docs]def dToX(input_list, first_element=0): if isinstance(input_list, list) is False: raise TypeError('xToD(input_list)') else: output = [first_element] for i in range(len(input_list)): output.append(input_list[i] + output[i]) return output
[docs]def xToD(input_list): result = [] for i in range(1, len(input_list)): result.append(input_list[i] - input_list[i - 1]) return result
[docs]def isinstance_as_string(child: object, parent_class_names: Union[str, List[str]]) -> bool: """ This function can be used to check if some class names (parent_class_names) can be found in another class's __mro__. If parent classes cannot be imported due to recursive imports this can be used instead of isinstance function. :param object child: :param str/[str] parent_class_names: :return: bool """ if isinstance(parent_class_names, str): parent_class_names = [parent_class_names] for parent_class_name in parent_class_names: if parent_class_name not in [cls.__name__ for cls in child.__class__.__mro__]: return False return True
def _chord_is_in_a_repetition(chord): my_index = chord.up.up.get_chords().index(chord) if my_index > 0 and not chord.is_tied_to_previous: all_previous_chords = [chord.up.up.get_chords()[my_index - i] for i in range(1, my_index + 1)] if set([ch.is_tied_to_previous for ch in all_previous_chords]) == {True}: return False previous_chord = all_previous_chords[0] if chord.has_same_pitches(previous_chord): return True return False
[docs]def slur_chords(chords, number=1, **kwargs): if len(chords) < 2: raise WrongNumberOfChordsError('util.slur_chords needs at list two chords.') chords[0].add_x(XMLSlur(type='start', number=number, **kwargs)) chords[-1].add_x(XMLSlur(type='stop', number=number)) for ch in chords[1:-1]: ch.add_x(XMLSlur(type='continue', number=number))
[docs]def trill_chords(chords, number=1, placement='above', **kwargs): if len(chords) < 2: raise WrongNumberOfChordsError('util.trill_chords needs at list two chords.') chords[0].add_x(XMLTrillMark(placement=placement, **kwargs)) chords[0].add_x(XMLWavyLine(type='start', number=number, **kwargs), placement=placement) chords[-1].add_x(XMLWavyLine(type='stop', number=number, **kwargs), placement=placement) for ch in chords[1:-1]: ch.add_x(XMLWavyLine(type='continue', number=number, **kwargs), placement=placement)
[docs]def wedge_chords(chords, wedge_type, number=1, placement='below', **kwargs): if len(chords) < 2: raise WrongNumberOfChordsError('util.wedge_chords needs at list two chords.') chords[0].add_x(XMLWedge(type=wedge_type, number=number, **kwargs), placement=placement) chords[-1].add_x(XMLWedge(type='stop', number=number), placement=placement) for ch in chords[1:-1]: ch.add_x(XMLWedge(type='continue', number=number), placement=placement)
[docs]def bracket_chords(chords, line_type='solid', start_line_end='down', end_line_end='down', placement='above', number=1): if len(chords) < 2: raise WrongNumberOfChordsError('util.bracket_chords needs at list two chords.') chords[0].add_x(XMLBracket(type='start', line_end=start_line_end, line_type=line_type, number=number), placement=placement) chords[-1].add_x(XMLBracket(type='stop', line_end=end_line_end, line_type=line_type, number=number), placement=placement) for ch in chords[1:-1]: ch.add_x(XMLBracket(type='continue', line_end='none', line_type=line_type, number=number), placement=placement)
[docs]def octave_chords(chords, type='down', size=8, number=1): try: len(chords) except TypeError: chords = [chords] if type == 'down': placement = 'above' else: placement = 'below' chords[0].add_x(XMLOctaveShift(type=type, size=size, number=number), placement=placement) chords[-1].add_x(XMLOctaveShift(type='stop', size=size, number=number), placement=placement) for ch in chords[1:-1]: ch.add_x(XMLOctaveShift(type='continue', size=size, number=number), placement=placement)
def _generate_lyrics(lyrics, number=1, show_number=False, mode='list', **kwargs): def _get_syllables_extensions_from_group(syllabic_group): if syllabic_group[0] is None: raise LyricSyllabicOrExtensionError( f'Syllabic or extension cannot be added to the beginning of a syllabic group.') extensions_ = [] syllables_ = list(syllabic_group)[:] while syllables_[-1] is None: extensions_.append(syllables_.pop()) return [syllables_, extensions_] if isinstance(lyrics, str) or isinstance(lyrics, tuple): lyrics = [lyrics] output = [] if mode == 'list': for i in range(len(lyrics)): ll = lyrics[i] if isinstance(ll, str): xl = XMLLyric(number=str(number), **kwargs) xl.xml_text = ll xl.xml_syllabic = 'single' output.append(xl) elif isinstance(ll, tuple) or isinstance(ll, list): syllables, extensions = _get_syllables_extensions_from_group(ll) if len(syllables) == 1: xl = XMLLyric(number=str(number), **kwargs) xl.xml_text = syllables[0] xl.xml_syllabic = 'single' if len(extensions) > 0: xl.xml_extend = XMLExtend(type='start') output.append(xl) else: for j in range(len(syllables)): xl = XMLLyric(number=str(number), **kwargs) l = syllables[j] if l: xl.xml_text = l if j == 0: xl.xml_syllabic = 'begin' elif j == len(syllables) - 1: xl.xml_syllabic = 'end' if len(extensions) > 0: xl.xml_extend = XMLExtend(type='start') else: xl.xml_syllabic = 'middle' else: xl = None output.append(xl) for k in range(len(extensions)): xl = XMLLyric(number=str(number), **kwargs) if k == len(extensions) - 1: xl.xml_extend = XMLExtend(type='stop') else: xl.xml_extend = XMLExtend(type='continue') xl.xsd_check = False output.append(xl) elif ll is None: output.append(None) else: raise NotImplementedError(ll) else: raise NotImplementedError if show_number: first = XMLLyric(**kwargs) for k, i in output[0].attributes.items(): setattr(first, k, i) first.add_child(XMLSyllabic('single')) first.add_child(XMLText(f'{number}.')) first.add_child(XMLElision(' ')) for child in output[0].get_children(): first.add_child(child) output[0] = first return output