Пример #1
0
def getDocumentationFiles(runOne=False):
    '''
    returns a list of namedtuples for each module that should be run

    >>> from music21.test import testDocumentation
    >>> testDocumentation.getDocumentationFiles()
    [ModTuple(module='index.rst', fullModulePath='...music21/documentation/autogenerated/index.rst',
    moduleNoExtension='index', autoGen=False),
    ...,
    ModTuple(module='usersGuide_03_pitches.rst',
      fullModulePath='...music21/documentation/autogenerated/usersGuide/usersGuide_03_pitches.rst',
       moduleNoExtension='usersGuide_03_pitches', autoGen=True),
    ...]
    '''
    from music21 import common
    music21basedir = common.getRootFilePath()
    builddocRstDir = os.path.join(music21basedir, 'documentation', 'source')
    if not os.path.exists(builddocRstDir):
        raise Music21Exception(
            "Cannot run tests on documentation because the rst files " +
            "in documentation/source do not exist")

    allModules = []
    for root, unused_dirnames, filenames in os.walk(builddocRstDir):
        for module in filenames:
            fullModulePath = os.path.join(root, module)
            if not module.endswith('.rst'):
                continue
            if module.startswith('module'):  # we have this already...
                continue
            if module in skipModules:
                continue
            if runOne is not False:
                if not module.endswith(runOne):
                    continue

            with io.open(fullModulePath, 'r', encoding='utf-8') as f:
                incipit = f.read(1000)
                if 'AUTOMATICALLY GENERATED' in incipit:
                    autoGen = True
                else:
                    autoGen = False

            moduleNoExtension = module[:-4]
            modTuple = ModTuple(module, fullModulePath, moduleNoExtension,
                                autoGen)
            allModules.append(modTuple)
    return allModules
Пример #2
0
def extractHarmonies(music21Stream):
    # noinspection PyShadowingNames
    '''
    Takes in a :class:`~music21.stream.Stream` and returns a dictionary whose values
    are the voice leading moments of the :class:`~music21.stream.Stream` and whose
    keys are (offset, endTime) pairs delimiting their duration. The voice leading
    moments are spelled out from the first or highest :class:`~music21.stream.Part`
    to the lowest one.

    >>> from music21 import corpus
    >>> score = corpus.parse('corelli/opus3no1/1grave').measures(1, 3)
    >>> #_DOCS_SHOW score.show()

    .. image:: images/figuredBass/corelli_grave.*
            :width: 700


    >>> from music21.figuredBass import checker
    >>> allHarmonies = checker.extractHarmonies(score)
    >>> for (offsets, notes) in sorted(allHarmonies.items()):
    ...    print("{0!s:15}[{1!s:23}{2!s:23}{3!s:22}]".format(offsets, notes[0], notes[1], notes[2]))
    (0.0, 1.5)     [<music21.note.Note C>  <music21.note.Note A>  <music21.note.Note F> ]
    (1.5, 2.0)     [<music21.note.Note C>  <music21.note.Note A>  <music21.note.Note F> ]
    (2.0, 3.0)     [<music21.note.Note B-> <music21.note.Note G>  <music21.note.Note G> ]
    (3.0, 3.5)     [<music21.note.Note A>  <music21.note.Note F>  <music21.note.Note A> ]
    (3.5, 4.0)     [<music21.note.Note A>  <music21.note.Note F>  <music21.note.Note B->]
    (4.0, 6.0)     [<music21.note.Note G>  <music21.note.Note E>  <music21.note.Note C> ]
    (6.0, 6.5)     [<music21.note.Note A>  <music21.note.Note F>  <music21.note.Note A> ]
    (6.5, 7.0)     [<music21.note.Note B-> <music21.note.Note F>  <music21.note.Note A> ]
    (7.0, 7.5)     [<music21.note.Note C>  <music21.note.Note F>  <music21.note.Note A> ]
    (7.5, 8.0)     [<music21.note.Note C>  <music21.note.Note E>  <music21.note.Note A> ]
    (8.0, 8.5)     [<music21.note.Note C>  <music21.note.Note D>  <music21.note.Note B->]
    (8.5, 9.0)     [<music21.note.Note F>  <music21.note.Note D>  <music21.note.Note B->]
    (9.0, 9.5)     [<music21.note.Note B-> <music21.note.Note D>  <music21.note.Note B->]
    (9.5, 10.0)    [<music21.note.Note B-> <music21.note.Note G>  <music21.note.Note B->]
    (10.0, 10.5)   [<music21.note.Note B-> <music21.note.Note E>  <music21.note.Note C> ]
    (10.5, 11.0)   [<music21.note.Note B-> <music21.note.Note C>  <music21.note.Note C> ]
    (11.0, 11.5)   [<music21.note.Note A>  <music21.note.Note F>  <music21.note.Note D> ]
    (11.5, 12.0)   [<music21.note.Note A>  <music21.note.Note F>  <music21.note.Note A> ]
    '''
    allParts = music21Stream.getElementsByClass(stream.Part)
    if len(allParts) < 2:
        raise Music21Exception(
            'There must be at least two parts to extract harmonies')
    allHarmonies = createOffsetMapping(allParts[0])
    for music21Part in allParts[1:]:
        allHarmonies = correlateHarmonies(allHarmonies, music21Part)
    return allHarmonies
Пример #3
0
def readPickleGzip(filePath: Union[str, pathlib.Path]) -> Any:
    '''
    Read a gzip-compressed pickle file, uncompress it, unpickle it, and
    return the contents.
    '''
    with gzip.open(filePath, 'rb') as pickledFile:
        try:
            uncompressed = pickledFile.read()
            newMdb = pickle.loads(uncompressed)
        except Exception as e:  # pylint: disable=broad-except
            # pickle exceptions cannot be caught directly
            # because they might come from pickle or _pickle and the latter cannot
            # be caught.
            raise Music21Exception('Cannot load file ' + str(filePath)) from e

    return newMdb
Пример #4
0
def slashMixedToFraction(valueSrc: str) -> Tuple[NumDenomTupleList, bool]:
    '''
    Given a mixture if possible meter fraction representations, return a list
    of pairs. If originally given as a summed numerator; break into separate
    fractions and return True as the second element of the tuple

    >>> meter.tools.slashMixedToFraction('4/4')
    ([(4, 4)], False)

    >>> meter.tools.slashMixedToFraction('3/8+2/8')
    ([(3, 8), (2, 8)], False)

    >>> meter.tools.slashMixedToFraction('3+2/8')
    ([(3, 8), (2, 8)], True)

    >>> meter.tools.slashMixedToFraction('3+2+5/8')
    ([(3, 8), (2, 8), (5, 8)], True)

    >>> meter.tools.slashMixedToFraction('3+2+5/8+3/4')
    ([(3, 8), (2, 8), (5, 8), (3, 4)], True)

    >>> meter.tools.slashMixedToFraction('3+2+5/8+3/4+2+1+4/16')
    ([(3, 8), (2, 8), (5, 8), (3, 4), (2, 16), (1, 16), (4, 16)], True)

    >>> meter.tools.slashMixedToFraction('3+2+5/8+3/4+2+1+4')
    Traceback (most recent call last):
    music21.exceptions21.MeterException: cannot match denominator to numerator in: 3+2+5/8+3/4+2+1+4
    '''
    pre = []
    post = []
    summedNumerator = False
    value = valueSrc.strip()  # rem whitespace
    value = value.split('+')
    for part in value:
        if '/' in part:
            tup = slashToTuple(part)
            if tup is None:
                raise TimeSignatureException(
                    'cannot create time signature from:', valueSrc)
            pre.append([tup.numerator, tup.denominator])
        else:  # its just a numerator
            try:
                pre.append([int(part), None])
            except ValueError:
                raise Music21Exception(
                    'Cannot parse this file -- this error often comes ' +
                    'up if the musicxml pickled file is out of date after a change '
                    + 'in musicxml/__init__.py . ' +
                    'Clear your temp directory of .p and .p.gz files and try again...; '
                    + f'Time Signature: {valueSrc} ')

    # when encountering a missing denominator, find the first defined
    # and apply to all previous
    for i in range(len(pre)):
        if pre[i][1] is not None:  # there is a denominator
            post.append(tuple(pre[i]))
        else:  # search ahead for next defined denominator
            summedNumerator = True
            match = None
            for j in range(i, len(pre)):
                if pre[j][1] is not None:
                    match = pre[j][1]
                    break
            if match is None:
                raise MeterException(
                    f'cannot match denominator to numerator in: {valueSrc}')

            pre[i][1] = match
            post.append(tuple(pre[i]))

    return post, summedNumerator
Пример #5
0
def slashMixedToFraction(valueSrc: str) -> t.Tuple[NumDenomTuple, bool]:
    '''
    Given a mixture if possible meter fraction representations, return a tuple
    of two elements: The first element is a tuple of pairs of numerator, denominators
    that are implied by the time signature.

    The second element is False if the value was a simple time signature (like 4/4)
    or a composite meter where all numerators had their own denominators.

    >>> meter.tools.slashMixedToFraction('4/4')
    (((4, 4),), False)

    >>> meter.tools.slashMixedToFraction('3/8+2/8')
    (((3, 8), (2, 8)), False)

    >>> meter.tools.slashMixedToFraction('3+2/8')
    (((3, 8), (2, 8)), True)

    >>> meter.tools.slashMixedToFraction('3+2+5/8')
    (((3, 8), (2, 8), (5, 8)), True)

    >>> meter.tools.slashMixedToFraction('3+2+5/8+3/4')
    (((3, 8), (2, 8), (5, 8), (3, 4)), True)

    >>> meter.tools.slashMixedToFraction('3+2+5/8+3/4+2+1+4/16')
    (((3, 8), (2, 8), (5, 8), (3, 4), (2, 16), (1, 16), (4, 16)), True)

    >>> meter.tools.slashMixedToFraction('3+2+5/8+3/4+2+1+4')
    Traceback (most recent call last):
    music21.exceptions21.MeterException: cannot match denominator to numerator in: 3+2+5/8+3/4+2+1+4

    >>> meter.tools.slashMixedToFraction('3.0/4.0')
    Traceback (most recent call last):
    music21.exceptions21.TimeSignatureException: Cannot create time signature from "3.0/4.0"

    Changed in v7 -- new location and returns a tuple as first value.
    '''
    pre: t.List[t.Union[NumDenom, t.Tuple[int, None]]] = []
    post: t.List[NumDenom] = []
    summedNumerator = False
    value = valueSrc.strip()  # rem whitespace
    value = value.split('+')
    for part in value:
        if '/' in part:
            try:
                tup = slashToTuple(part)
            except MeterException as me:
                raise TimeSignatureException(
                    f'Cannot create time signature from "{valueSrc}"') from me
            pre.append((tup.numerator, tup.denominator))
        else:  # its just a numerator
            try:
                pre.append((int(part), None))
            except ValueError:
                raise Music21Exception(
                    'Cannot parse this file -- this error often comes ' +
                    'up if the musicxml pickled file is out of date after a change '
                    + 'in musicxml/__init__.py . ' +
                    'Clear your temp directory of .p and .p.gz files and try again...; '
                    + f'Time Signature: {valueSrc} ')

    # when encountering a missing denominator, find the first defined
    # and apply to all previous
    for i in range(len(pre)):
        if pre[i][1] is not None:  # there is a denominator
            intNum = pre[i][0]  # this is all for type checking
            intDenom = pre[i][1]
            if t.TYPE_CHECKING:
                assert isinstance(intNum, int) and isinstance(intDenom, int)
            post.append((intNum, intDenom))
        else:  # search ahead for next defined denominator
            summedNumerator = True
            match: t.Optional[int] = None
            for j in range(
                    i, len(pre)
            ):  # this O(n^2) operation is easily simplified to O(n)
                if pre[j][1] is not None:
                    match = pre[j][1]
                    break
            if match is None:
                raise MeterException(
                    f'cannot match denominator to numerator in: {valueSrc}')

            preBothAreInts = (pre[i][0], match)
            post.append(preBothAreInts)

    return tuple(post), summedNumerator