Exemplo n.º 1
0
def getWorkList(workName, movementNumber=None, extList=None):
    '''Search the corpus and return a list of works, always in a list. If no matches are found, an empty list is returned.

    >>> len(getWorkList('beethoven/opus18no1'))
    8
    >>> len(getWorkList('beethoven/opus18no1', 1))
    2 
    >>> len(getWorkList('beethoven/opus18no1', 1, '.krn'))
    1
    >>> len(getWorkList('beethoven/opus18no1', 1, '.xml'))
    1
    >>> len(getWorkList('beethoven/opus18no1', 0, '.xml'))
    0
    '''
    if not common.isListLike(extList):
        extList = [extList]

    paths = getPaths(extList)
    post = []

    # permit workName to be a list of paths/branches
    if common.isListLike(workName):
        workName = os.path.sep.join(workName)
    # replace with os-dependent separators 
    workSlashes = workName.replace('/', os.path.sep)

    for path in paths:
        if workName.lower() in path.lower():
            post.append(path)
        elif workSlashes.lower() in path.lower():
            post.append(path)

    post.sort()
    postMvt = []
    if movementNumber is not None and len(post) > 0:
        movementStrList = ['movement%s' % movementNumber]
        for fp in post:
            for movementStr in movementStrList:
                if movementStr.lower() in fp.lower():
                    postMvt.append(fp)
        if len(postMvt) == 0:
            pass # return an empty list
    else:
        postMvt = post

    if len(postMvt) == 0:
        return []
    else:
        return postMvt
Exemplo n.º 2
0
def getWork(workName, movementNumber=None, fileExtensions=None):
    '''
    Search the corpus, then the virtual corpus, for a work, and return a file
    path or URL.  N.B. does not parse the work: but it's suitable for passing
    to converter.parse.

    This method will return either a list of file paths or, if there is a
    single match, a single file path. If no matches are found an Exception is
    raised.

    ::

        >>> import os
        >>> from music21 import corpus
        >>> a = corpus.getWork('opus74no2', 4)
        >>> a.endswith(os.path.sep.join([
        ...     'haydn', 'opus74no2', 'movement4.mxl']))
        True

    ::

        >>> a = corpus.getWork(['haydn', 'opus74no2', 'movement4.xml'])
        >>> a.endswith(os.path.sep.join([
        ...     'haydn', 'opus74no2', 'movement4.mxl']))
        True

    ::

        >>> trecentoFiles = corpus.getWork('trecento')
        >>> len(trecentoFiles) > 100 and len(trecentoFiles) < 200
        True

    '''
    if not common.isListLike(fileExtensions):
        fileExtensions = [fileExtensions]
    results = getWorkList(workName, movementNumber, fileExtensions)
    if len(results) == 0:
        if common.isListLike(workName):
            workName = os.path.sep.join(workName)
        if workName.endswith(".xml"):  # might be compressed MXL file
            newWorkName = workName[0:len(workName) - 4] + ".mxl"
            return getWork(newWorkName, movementNumber, fileExtensions)
        results = getVirtualWorkList(workName, movementNumber, fileExtensions)
    if len(results) == 1:
        return results[0]
    elif len(results) == 0:
        raise CorpusException(
            'Could not find a file/url that met these criteria')
    return results
Exemplo n.º 3
0
def getWork(workName, movementNumber=None, fileExtensions=None):
    '''
    Search the corpus, then the virtual corpus, for a work, and return a file
    path or URL.  N.B. does not parse the work: but it's suitable for passing
    to converter.parse.

    This method will return either a list of file paths or, if there is a
    single match, a single file path. If no matches are found an Exception is
    raised.

    ::

        >>> import os
        >>> from music21 import corpus
        >>> a = corpus.getWork('opus74no2', 4)
        >>> a.endswith(os.path.sep.join([
        ...     'haydn', 'opus74no2', 'movement4.mxl']))
        True

    ::

        >>> a = corpus.getWork(['haydn', 'opus74no2', 'movement4.xml'])
        >>> a.endswith(os.path.sep.join([
        ...     'haydn', 'opus74no2', 'movement4.mxl']))
        True

    ::

        >>> trecentoFiles = corpus.getWork('trecento')
        >>> len(trecentoFiles) > 100 and len(trecentoFiles) < 200
        True

    '''
    if not common.isListLike(fileExtensions):
        fileExtensions = [fileExtensions]
    results = getWorkList(workName, movementNumber, fileExtensions)
    if len(results) == 0:
        if common.isListLike(workName):
            workName = os.path.sep.join(workName)
        if workName.endswith(".xml"):  # might be compressed MXL file
            newWorkName = workName[0:len(workName) - 4] + ".mxl"
            return getWork(newWorkName, movementNumber, fileExtensions)
        results = getVirtualWorkList(workName, movementNumber, fileExtensions)
    if len(results) == 1:
        return results[0]
    elif len(results) == 0:
        raise CorpusException(
            'Could not find a file/url that met these criteria')
    return results
Exemplo n.º 4
0
    def __init__(self, target=()):
        super().__init__()
        if not common.isListLike(target):
            target = (target, )

        self.target = target
        self.numToFind = len(target)
Exemplo n.º 5
0
    def __init__(self, classList=()):
        super().__init__()

        if not common.isListLike(classList):
            classList = (classList, )

        self.classList = classList
Exemplo n.º 6
0
    def __setitem__(self, key, value):
        '''Dictionary-like setting. Changes are made and written to the user configuration file.

        
        >>> us = environment.UserSettings()
        >>> us['musicxmlPath'] = 'asdfwerasdffasdfwer'
        Traceback (most recent call last):
        UserSettingsException: attempting to set a path that does not exist: asdfwerasdffasdfwer

        >>> us['localCorpusPath'] = '/path/to/local'
        Traceback (most recent call last):
        UserSettingsException: attempting to set a path that does not exist: /path/to/local
        '''
        # NOTE: testing setting of any UserSettings key will result
        # in a change in your local preferences files

        # before setting value, see if this is a path and test existence
        # this will accept localCorpusPath
        if key in self._environment.getKeysToPaths():
            # try to expand user if found; otherwise return unaltered
            value = os.path.expanduser(value)
            if not os.path.exists(value):
                raise UserSettingsException(
                    'attempting to set a path that does not exist: %s' % value)
        # when setting a local corpus setting, if not a list, append
        elif key in ['localCorpusSettings']:
            if not common.isListLike(value):
                raise UserSettingsException(
                    'localCorpusSettings must be provided as a list.')
        # location specific, cannot test further
        self._environment.__setitem__(key, value)
        self._environment.write()
Exemplo n.º 7
0
    def _translateExtensions(
        self,
        fileExtensions=None,
        expandExtensions=True,
    ):
        # noinspection PyShadowingNames
        '''
        Utility to get default extensions, or, optionally, expand extensions to
        all known formats.

        >>> coreCorpus = corpus.corpora.CoreCorpus()
        >>> for extension in coreCorpus._translateExtensions():
        ...     extension
        ...
        '.abc'
        '.capx'
        '.mid'
        '.midi'
        '.xml'
        '.mxl'
        '.musicxml'
        '.md'
        '.musedata'
        '.zip'
        '.krn'
        '.rntxt'
        '.rntext'
        '.romantext'
        '.rtxt'
        '.nwctxt'
        '.nwc'

        >>> coreCorpus._translateExtensions('.mid', False)
        ['.mid']

        >>> coreCorpus._translateExtensions('.mid', True)
        ['.mid', '.midi']

        It does not matter if you choose a canonical name or not, the output is the same:

        >>> coreCorpus._translateExtensions('.musicxml', True)
        ['.xml', '.mxl', '.musicxml']

        >>> coreCorpus._translateExtensions('.xml', True)
        ['.xml', '.mxl', '.musicxml']
        '''
        if not common.isListLike(fileExtensions):
            fileExtensions = [fileExtensions]
        if len(fileExtensions) == 1 and fileExtensions[0] is None:
            fileExtensions = Corpus._allExtensions
        elif expandExtensions:
            expandedExtensions = []
            for extension in fileExtensions:
                allInputExtensions = common.findInputExtension(extension)
                if allInputExtensions is None:
                    pass
                else:
                    expandedExtensions += allInputExtensions
            return expandedExtensions
        return fileExtensions
Exemplo n.º 8
0
def parse(value, *args, **keywords):
    '''Given a file path, encoded data in a Python string, or a URL, attempt to parse the item into a Stream. Note: URL downloading will not happen automatically unless the user has set their Environment "autoDownload" preference to "allow". 

    >>> s = parse(["E4 r f# g=lastG trip{b-8 a g} c", "3/4"])
    >>> s = parse("E8 f# g#' G f g# g G#", "2/4")

    '''

    #environLocal.printDebug(['attempting to parse()', value])
    if 'forceSource' in keywords.keys():
        forceSource = keywords['forceSource']
    else:   
        forceSource = False

    if common.isListLike(value) or len(args) > 0: # tiny notation list
        if len(args) > 0: # add additional args to a lost
            value = [value] + list(args)
        return parseData(value)
    elif os.path.exists(value):
        return parseFile(value, forceSource=forceSource)
    elif value.startswith('http://'): 
        # its a url; may need to broaden these criteria
        return parseURL(value, forceSource=forceSource)
    else:
        return parseData(value)
Exemplo n.º 9
0
def parseWork(workName, movementNumber=None, number=None, 
    extList=None, forceSource=False):
    '''Search the corpus, then the virtual corpus, for a work, and return a parsed :class:`music21.stream.Stream`.

    If `movementNumber` is defined, and a movement is included in the corpus, that movement will be returned. 

    If `number` is defined, and the work is a collection with multiple components, that work number will be returned. 

    If `forceSource` is True, the original file will always be loaded and pickled files, if available, will be ignored.

    >>> aStream = parseWork('opus74no1/movement3')
    '''
    if not common.isListLike(extList):
        extList = [extList]

    post = getWorkList(workName, movementNumber, extList)
    #environLocal.printDebug(['result of getWorkList()', post])
    if len(post) == 0:
        post = getVirtualWorkList(workName, movementNumber, extList)    

    if len(post) == 1:
        fp = post[0]
    elif len(post) == 0:
        raise CorpusException("Could not find a work that met this criteria")
    else: # greater than zero:
        fp = post[0] # get first
      
    return converter.parse(fp, forceSource=forceSource, number=number)
Exemplo n.º 10
0
    def parseFile(self, fp, number=None):
        '''
        parse fp and number
        '''
        from music21 import converter
        from music21 import musedata as musedataModule
        from music21.musedata import translate as musedataTranslate

        mdw = musedataModule.MuseDataWork()

        af = converter.ArchiveManager(fp)

        #environLocal.printDebug(['ConverterMuseData: parseFile', fp, af.isArchive()])
        # for dealing with one or more files
        if fp.endswith('.zip') or af.isArchive():
            #environLocal.printDebug(['ConverterMuseData: found archive', fp])
            # get data will return all data from the zip as a single string
            for partStr in af.getData(dataFormat='musedata'):
                #environLocal.printDebug(['partStr', len(partStr)])
                mdw.addString(partStr)
        else:
            if os.path.isdir(fp):
                mdd = musedataModule.MuseDataDirectory(fp)
                fpList = mdd.getPaths()
            elif not common.isListLike(fp):
                fpList = [fp]
            else:
                fpList = fp

            for fp in fpList:
                mdw.addFile(fp)

        #environLocal.printDebug(['ConverterMuseData: mdw file count', len(mdw.files)])

        musedataTranslate.museDataWorkToStreamScore(mdw, self.stream)
Exemplo n.º 11
0
    def __setitem__(self, key, value):
        """
        Dictionary-like setting. Changes are made and written to the user
        configuration file.

        >>> from music21 import environment
        >>> us = environment.UserSettings()
        >>> us['musicxmlPath'] = 'asdfwerasdffasdfwer'
        Traceback (most recent call last):
        UserSettingsException: attempting to set a path that does not exist: asdfwerasdffasdfwer

        >>> us['localCorpusPath'] = '/path/to/local'
        Traceback (most recent call last):
        UserSettingsException: attempting to set a path that does not exist: /path/to/local
        """
        # NOTE: testing setting of any UserSettings key will result
        # in a change in your local preferences files

        # before setting value, see if this is a path and test existence
        # this will accept localCorpusPath
        if key in self._environment.getKeysToPaths():
            # try to expand user if found; otherwise return unaltered
            if value is not None:
                value = os.path.expanduser(value)
                if not os.path.exists(value):
                    raise UserSettingsException("attempting to set a path that does not exist: {}".format(value))
        # when setting a local corpus setting, if not a list, append
        elif key == "localCorpusSettings":
            if not common.isListLike(value):
                raise UserSettingsException("localCorpusSettings must be provided as a list.")
        # location specific, cannot test further
        self._environment.__setitem__(key, value)
        self._environment.write()
Exemplo n.º 12
0
    def parseFile(self, fp, number=None):
        '''
        parse fp and number
        '''
        from music21 import converter
        from music21 import musedata as musedataModule
        from music21.musedata import translate as musedataTranslate

        mdw = musedataModule.MuseDataWork()

        af = converter.ArchiveManager(fp)

        #environLocal.printDebug(['ConverterMuseData: parseFile', fp, af.isArchive()])
        # for dealing with one or more files
        if fp.endswith('.zip') or af.isArchive():
            #environLocal.printDebug(['ConverterMuseData: found archive', fp])
            # get data will return all data from the zip as a single string
            for partStr in af.getData(dataFormat='musedata'):
                #environLocal.printDebug(['partStr', len(partStr)])
                mdw.addString(partStr)
        else:
            if os.path.isdir(fp):
                mdd = musedataModule.MuseDataDirectory(fp)
                fpList = mdd.getPaths()
            elif not common.isListLike(fp):
                fpList = [fp]
            else:
                fpList = fp

            for fp in fpList:
                mdw.addFile(fp)

        #environLocal.printDebug(['ConverterMuseData: mdw file count', len(mdw.files)])

        musedataTranslate.museDataWorkToStreamScore(mdw, self.stream)
Exemplo n.º 13
0
    def __init__(self, target=()):
        super().__init__()
        if not common.isListLike(target):
            target = (target,)

        self.target = target
        self.numToFind = len(target)
Exemplo n.º 14
0
    def getWorkList(
        self,
        workName,
        movementNumber=None,
        fileExtensions=None,
        ):
        '''
        Given a work name, search all virtual works and return a list of URLs
        for any matches.

        >>> from music21 import corpus
        >>> virtualCorpus = corpus.VirtualCorpus()
        >>> virtualCorpus.getWorkList('bach/bwv1007/prelude')
        ['http://kern.ccarh.org/cgi-bin/ksdata?l=cc/bach/cello&file=bwv1007-01.krn&f=xml']

        >>> virtualCorpus.getWorkList('junk')
        []

        '''
        if not common.isListLike(fileExtensions):
            fileExtensions = [fileExtensions]
        for obj in VirtualCorpus._virtual_works:
            if obj.corpusPath is not None and \
                workName.lower() in obj.corpusPath.lower():
                return obj.getUrlByExt(fileExtensions)
        return []
Exemplo n.º 15
0
    def getDoc(self, partName):
        element = self.getElement(partName)

        if hasattr(self.srcNameEval, '_DOC_ATTR'):
            docAttr = self.srcNameEval._DOC_ATTR
        else:
            docAttr = {}

        match = None
                
        if partName in docAttr.keys():
            match = docAttr[partName]
        # if its an undocumented public attribute and basic python
        # data structure, we do not want to show that documentation
        elif (element.kind in ['data'] and (
            common.isStr(element.object) or 
            common.isListLike(element.object) or
            common.isNum(element.object)
            )):
            pass
        else:
            try:
                match = element.object.__doc__
            except AttributeError:
                match = None

        if match == None:
            return NO_DOC
        else:
            return match
Exemplo n.º 16
0
    def __init__(self, classList=()):
        super().__init__()

        if not common.isListLike(classList):
            classList = (classList,)

        self.classList = classList
Exemplo n.º 17
0
def getWork(workName, movementNumber=None, extList=None):
    '''Search the corpus, then the virtual corpus, for a work. This method will return either a list of file paths or, if there is a single match, a single file path. If no matches are found an Exception is raised. 

    >>> import os
    >>> a = getWork('opus74no2', 4)
    >>> a.endswith(os.path.sep.join(['haydn', 'opus74no2', 'movement4.xml']))
    True

    >>> a = getWork(['haydn', 'opus74no2', 'movement4.xml'])
    >>> a.endswith(os.path.sep.join(['haydn', 'opus74no2', 'movement4.xml']))
    True

    '''
    if not common.isListLike(extList):
        extList = [extList]

    post = getWorkList(workName, movementNumber, extList)
    if len(post) == 0:
        post = getVirtualWorkList(workName, movementNumber, extList)

    if len(post) == 1:
        return post[0]
    elif len(post) == 0:
        raise CorpusException("Could not find a file/url that met this criteria")
    else: # return a list
        return post
Exemplo n.º 18
0
    def getWorkList(
        self,
        workName,
        movementNumber=None,
        fileExtensions=None,
    ):
        '''
        Given a work name, search all virtual works and return a list of URLs
        for any matches.

        >>> virtualCorpus = corpus.corpora.VirtualCorpus()
        >>> virtualCorpus.getWorkList('bach/bwv1007/prelude')
        ['http://kern.ccarh.org/cgi-bin/ksdata?l=cc/bach/cello&file=bwv1007-01.krn&f=xml']

        >>> virtualCorpus.getWorkList('junk')
        []

        '''
        if not common.isListLike(fileExtensions):
            fileExtensions = [fileExtensions]
        for obj in VirtualCorpus._virtual_works:
            if obj.corpusPath is not None and workName.lower(
            ) in obj.corpusPath.lower():
                return obj.getUrlByExt(fileExtensions)
        return []
Exemplo n.º 19
0
 def _setPitches(self, value):
     if common.isListLike(value):
         if 'Pitch' in value[0].classes:
             self.pitch = value[0]
         else:
             raise NoteException('must provide a list containing a Pitch, not: %s' % value)
     else:
         raise NoteException('cannot set pitches with provided object: %s' % value)
Exemplo n.º 20
0
def getPaths(extList=None, expandExtensions=True):    
    '''Get all paths in the corpus that match a known extension, or an extenion
    provided by an argument.

    If `expandExtensions` is True, a format for an extension, and related extensions, will replaced by all known input extensions. This is convenient when an input format might match for multiple extensions.

    >>> a = getPaths()
    >>> len(a) > 30
    True

    >>> a = getPaths('krn')
    >>> len(a) >= 4
    True

    >>> a = getPaths('abc')
    >>> len(a) >= 10
    True

    '''
    if not common.isListLike(extList):
        extList = [extList]

    if extList == [None]:
        extList = _ALL_EXTENSIONS
    elif expandExtensions:
        extMod = []
        for e in extList:
            extMod += common.findInputExtension(e)
        extList = extMod
        
    #environLocal.printDebug(['getting paths with extensions:', extList])
    paths = []    
    for moduleName in MODULES:
        if not hasattr(moduleName, '__path__'):
            # when importing a package name (a directory) the moduleName        
            # may be a list of all paths contained within the package
            # this seems to be dependent on the context of the call:
            # from the command line is different than from the interpreter
            dirListing = moduleName
        else:
            # returns a list with one or more paths
            # the first is the path to the directory that contains xml files
            dir = moduleName.__path__[0] 
            dirListing = [os.path.join(dir, x) for x in os.listdir(dir)]

        for fp in dirListing:
            if fp in paths:
                continue
            match = False
            for ext in extList:
                if fp.endswith(ext):
                    match = True
                    break 
            if match:
                if fp not in paths:
                    paths.append(fp)    
    return paths
Exemplo n.º 21
0
def cacheMetadata(
    corpusNames=('local', 'core', 'virtual'),
    useMultiprocessing=True,
    ):
    '''
    Cache metadata from corpuses in `corpusNames` as local cache files:

    Call as ``metadata.cacheMetadata()``

    '''
    from music21 import corpus
    from music21 import metadata

    if not common.isListLike(corpusNames):
        corpusNames = (corpusNames,)

    timer = common.Timer()
    timer.start()

    # store list of file paths that caused an error
    failingFilePaths = []

    # the core cache is based on local files stored in music21
    # virtual is on-line
    for corpusName in corpusNames:
        if corpusName == 'core':
            metadataBundle = metadata.MetadataBundle.fromCoreCorpus()
            paths = corpus.getCorePaths()
            useCorpus = True
        elif corpusName == 'local':
            metadataBundle = metadata.MetadataBundle.fromLocalCorpus()
            paths = corpus.getLocalPaths()
            useCorpus = False
        elif corpusName == 'virtual':
            metadataBundle = metadata.MetadataBundle.fromVirtualCorpus()
            paths = corpus.getVirtualPaths()
            useCorpus = False
        else:
            message = 'invalid corpus name provided: {0!r}'.format(corpusName)
            raise MetadataCacheException(message)
        message = 'metadata cache: starting processing of paths: {0}'.format(
                len(paths))
        environLocal.printDebug(message)
        failingFilePaths += metadataBundle.addFromPaths(
            paths,
            useCorpus=useCorpus,
            useMultiprocessing=useMultiprocessing,
            )
        message = 'cache: writing time: {0} md items: {1}'.format(
            timer, len(metadataBundle))
        environLocal.printDebug(message)
        del metadataBundle
    message = 'cache: final writing time: {0} seconds'.format(timer)
    environLocal.printDebug(message)
    for failingFilePath in failingFilePaths:
        message = 'path failed to parse: {0}'.format(failingFilePath)
        environLocal.printDebug(message)
Exemplo n.º 22
0
def cacheMetadata(corpusNames=('local',)):
    '''
    Rebuild the metadata cache.
    '''
    if not common.isListLike(corpusNames):
        corpusNames = [corpusNames]
    for name in corpusNames:
        corpora.Corpus._metadataBundles[name] = None
    metadata.cacheMetadata(corpusNames)
Exemplo n.º 23
0
def cacheMetadata(corpusNames=('local', )):
    '''
    Rebuild the metadata cache.
    '''
    if not common.isListLike(corpusNames):
        corpusNames = [corpusNames]
    for name in corpusNames:
        corpora.Corpus._metadataBundles[name] = None
    metadata.cacheMetadata(corpusNames)
Exemplo n.º 24
0
def cacheMetadata(
        corpusNames=('local', 'core', 'virtual'),
        useMultiprocessing=True,
):
    '''
    Cache metadata from corpuses in `corpusNames` as local cache files:

    Call as ``metadata.cacheMetadata()``

    '''
    from music21 import corpus
    from music21 import metadata

    if not common.isListLike(corpusNames):
        corpusNames = (corpusNames, )

    timer = common.Timer()
    timer.start()

    # store list of file paths that caused an error
    failingFilePaths = []

    # the core cache is based on local files stored in music21
    # virtual is on-line
    for corpusName in corpusNames:
        if corpusName == 'core':
            metadataBundle = metadata.MetadataBundle.fromCoreCorpus()
            paths = corpus.getCorePaths()
            useCorpus = True
        elif corpusName == 'local':
            metadataBundle = metadata.MetadataBundle.fromLocalCorpus()
            paths = corpus.getLocalPaths()
            useCorpus = False
        elif corpusName == 'virtual':
            metadataBundle = metadata.MetadataBundle.fromVirtualCorpus()
            paths = corpus.getVirtualPaths()
            useCorpus = False
        else:
            message = 'invalid corpus name provided: {0!r}'.format(corpusName)
            raise MetadataCacheException(message)
        message = 'metadata cache: starting processing of paths: {0}'.format(
            len(paths))
        environLocal.printDebug(message)
        failingFilePaths += metadataBundle.addFromPaths(
            paths,
            useCorpus=useCorpus,
            useMultiprocessing=useMultiprocessing,
        )
        message = 'cache: writing time: {0} md items: {1}'.format(
            timer, len(metadataBundle))
        environLocal.printDebug(message)
        del metadataBundle
    message = 'cache: final writing time: {0} seconds'.format(timer)
    environLocal.printDebug(message)
    for failingFilePath in failingFilePaths:
        message = 'path failed to parse: {0}'.format(failingFilePath)
        environLocal.printDebug(message)
Exemplo n.º 25
0
 def _dynamicToWeight(targets):
     # permit a stream
     if hasattr(targets, 'isStream') and targets.isStream:
         pass
     elif not common.isListLike(targets):
         targets = [targets]
     summation = 0
     for e in targets: # a Stream
         summation += e.volumeScalar # for dynamics
     return summation / float(len(target))
Exemplo n.º 26
0
    def __setitem__(self, key, value):
        #saxutils.escape # used for escaping strings going to xml
        # with unicode encoding
        # http://www.xml.com/pub/a/2002/11/13/py-xml.html?page=2
        # saxutils.escape(msg).encode('UTF-8')

        # add local corpus path as a key
        #if six.PY3 and isinstance(value, bytes):
        #    value = value.decode(errors='replace')
        if 'path' in key.lower() and value is not None:
            value = common.cleanpath(value)
        
        if key not in self._ref:
            if key != 'localCorpusPath':
                raise EnvironmentException('no preference: %s' % key)
        if value == '':
            value = None  # always replace '' with None

        valid = False
        if key == 'showFormat':
            value = value.lower()
            if value in common.VALID_SHOW_FORMATS:
                valid = True
        elif key == 'writeFormat':
            value = value.lower()
            if value in common.VALID_WRITE_FORMATS:
                valid = True
        elif key == 'autoDownload':
            value = value.lower()
            if value in common.VALID_AUTO_DOWNLOAD:
                valid = True
        elif key == 'localCorpusSettings':
            # needs to be a list of strings for now
            if common.isListLike(value):
                valid = True
        else:  # temporarily not validating other preferences
            valid = True

        if not valid:
            raise EnvironmentException(
                '{} is not an acceptable value for preference: {}'.format(
                    value, key))

        # need to escape problematic characters for xml storage
        if isinstance(value, six.string_types):
            value = saxutils.escape(value) #.encode('UTF-8')
        # set value
        if key == 'localCorpusPath':
            # only add if unique
            #value = xmlnode.fixBytes(value)
            if value not in self._ref['localCorpusSettings']:
                # check for malicious values here
                self._ref['localCorpusSettings'].append(value)
        else:
            self._ref[key] = value
Exemplo n.º 27
0
    def __setitem__(self, key, value):
        #saxutils.escape # used for escaping strings going to xml
        # with unicode encoding
        # http://www.xml.com/pub/a/2002/11/13/py-xml.html?page=2
        # saxutils.escape(msg).encode('UTF-8')

        # add local corpus path as a key
        #if six.PY3 and isinstance(value, bytes):
        #    value = value.decode(errors='replace')
        if 'path' in key.lower() and value is not None:
            value = common.cleanpath(value)

        if key not in self._ref:
            if key != 'localCorpusPath':
                raise EnvironmentException('no preference: %s' % key)
        if value == '':
            value = None  # always replace '' with None

        valid = False
        if key == 'showFormat':
            value = value.lower()
            if value in common.VALID_SHOW_FORMATS:
                valid = True
        elif key == 'writeFormat':
            value = value.lower()
            if value in common.VALID_WRITE_FORMATS:
                valid = True
        elif key == 'autoDownload':
            value = value.lower()
            if value in common.VALID_AUTO_DOWNLOAD:
                valid = True
        elif key == 'localCorpusSettings':
            # needs to be a list of strings for now
            if common.isListLike(value):
                valid = True
        else:  # temporarily not validating other preferences
            valid = True

        if not valid:
            raise EnvironmentException(
                '{} is not an acceptable value for preference: {}'.format(
                    value, key))

        # need to escape problematic characters for xml storage
        if isinstance(value, six.string_types):
            value = saxutils.escape(value)  #.encode('UTF-8')
        # set value
        if key == 'localCorpusPath':
            # only add if unique
            #value = xmlnode.fixBytes(value)
            if value not in self._ref['localCorpusSettings']:
                # check for malicious values here
                self._ref['localCorpusSettings'].append(value)
        else:
            self._ref[key] = value
Exemplo n.º 28
0
    def _translateExtensions(
        self,
        fileExtensions=None,
        expandExtensions=True,
        ):
        '''
        Utility to get default extensions, or, optionally, expand extensions to
        all known formats.

        >>> from music21 import corpus
        >>> coreCorpus = corpus.CoreCorpus()
        >>> for extension in coreCorpus._translateExtensions():
        ...     extension
        ...
        '.abc'
        '.capx'
        '.mid'
        '.midi'
        '.xml'
        '.mxl'
        '.mx'
        '.musicxml'
        '.md'
        '.musedata'
        '.zip'
        '.krn'
        '.rntxt'
        '.rntext'
        '.romantext'
        '.rtxt'
        '.nwctxt'
        '.nwc'

        >>> coreCorpus._translateExtensions('.mid', False)
        ['.mid']

        >>> coreCorpus._translateExtensions('.mid', True)
        ['.mid', '.midi']

        '''
        if not common.isListLike(fileExtensions):
            fileExtensions = [fileExtensions]
        if fileExtensions == [None]:
            fileExtensions = Corpus._allExtensions
        elif expandExtensions:
            expandedExtensions = []
            for extension in fileExtensions:
                allInputExtensions = common.findInputExtension(extension)
                if allInputExtensions is None:
                    pass
                else:
                    expandedExtensions += allInputExtensions
            return expandedExtensions
        return fileExtensions
Exemplo n.º 29
0
def getWork(
    workName,
    movementNumber=None,
    fileExtensions=None,
):
    '''
    this parse method is called from `corpus.parse()` and does nothing differently from it.

    Searches all corpora for a file that matches the name and returns it parsed.
    '''
    addXMLWarning = False
    workNameJoined = workName
    mxlWorkName = workName

    if workName in (None, ''):
        raise CorpusException('a work name must be provided as an argument')
    if not common.isListLike(fileExtensions):
        fileExtensions = [fileExtensions]
    if common.isIterable(workName):
        workNameJoined = os.path.sep.join(workName)

    if workNameJoined.endswith(".xml"):
        # might be compressed MXL file
        mxlWorkName = os.path.splitext(workNameJoined)[0] + ".mxl"
        addXMLWarning = True

    filePaths = None
    for corpusObject in iterateCorpora():
        workList = corpusObject.getWorkList(workName, movementNumber,
                                            fileExtensions)
        if not workList and addXMLWarning:
            workList = corpusObject.getWorkList(mxlWorkName, movementNumber,
                                                fileExtensions)
            if not workList:
                continue
        if len(workList) >= 1:
            filePaths = workList
            break

    if filePaths is None:
        warningMessage = 'Could not find a'
        if addXMLWarning:
            warningMessage += 'n xml or mxl'
        warningMessage += ' work that met this criterion: {0};'.format(
            workName)
        warningMessage += ' if you are searching for a file on disk, '
        warningMessage += 'use "converter" instead of "corpus".'
        raise CorpusException(warningMessage)
    else:
        if len(filePaths) == 1:
            return filePaths[0]
        else:
            return filePaths
Exemplo n.º 30
0
def getWork(workName,
            movementNumber=None,
            fileExtensions=None,
        ):
    '''
    this parse method is called from `corpus.parse()` and does nothing differently from it.
    
    Searches all corpora for a file that matches the name and returns it parsed.
    '''
    addXMLWarning = False
    workNameJoined = workName
    mxlWorkName = workName
    
    if workName in (None, ''):
        raise CorpusException(
            'a work name must be provided as an argument')
    if not common.isListLike(fileExtensions):
        fileExtensions = [fileExtensions]
    if common.isIterable(workName):
        workNameJoined = os.path.sep.join(workName)

    if workNameJoined.endswith(".xml"):
        # might be compressed MXL file
        mxlWorkName = os.path.splitext(workNameJoined)[0] + ".mxl"
        addXMLWarning = True

    filePaths = None    
    for corpusObject in iterateCorpora():    
        workList = corpusObject.getWorkList(workName, movementNumber, fileExtensions)
        if not workList and addXMLWarning:
            workList = corpusObject.getWorkList(mxlWorkName, movementNumber, fileExtensions)
            if not workList:
                continue
        if len(workList) >= 1:
            filePaths = workList
            break

    if filePaths is None:
        warningMessage = 'Could not find a'
        if addXMLWarning:
            warningMessage += 'n xml or mxl'
        warningMessage += ' work that met this criterion: {0};'.format(workName)
        warningMessage += ' if you are searching for a file on disk, '
        warningMessage += 'use "converter" instead of "corpus".'
        raise CorpusException(warningMessage)
    else:
        if len(filePaths) == 1:
            return filePaths[0]
        else:
            return filePaths
Exemplo n.º 31
0
def midiEventsToKeySignature(eventList):
    '''Convert a single MIDI event into a music21 TimeSignature object.

    >>> from music21 import *
    >>> mt = midi.MidiTrack(1)
    >>> me1 = midi.MidiEvent(mt)
    >>> me1.type = "KEY_SIGNATURE"
    >>> me1.data = midi.putNumbersAsList([2, 0]) # d major
    >>> ks = midiEventsToKeySignature(me1)
    >>> ks
    <music21.key.KeySignature of 2 sharps>

    >>> me2 = midi.MidiEvent(mt)
    >>> me2.type = "KEY_SIGNATURE"
    >>> me2.data = midi.putNumbersAsList([-2, 0]) # b- major
    >>> me2.data
    '\\xfe\\x00'
    >>> midi.getNumbersAsList(me2.data)
    [254, 0]
    >>> ks = midiEventsToKeySignature(me2)
    >>> ks
    <music21.key.KeySignature of 2 flats>

    '''
    # This meta event is used to specify the key (number of sharps or flats) and scale (major or minor) of a sequence. A positive value for the key specifies the number of sharps and a negative value specifies the number of flats. A value of 0 for the scale specifies a major key and a value of 1 specifies a minor key.
    from music21 import key

    if not common.isListLike(eventList):
        event = eventList
    else: # get the second event; first is delta time
        event = eventList[1]
    post = midiModule.getNumbersAsList(event.data)

    if post[0] > 12:
        # flip around 256
        sharpCount = post[0] - 256 # need negative values
    else:
        sharpCount = post[0]

    environLocal.printDebug(['midiEventsToKeySignature', post, sharpCount])

    # first value is number of sharp, or neg for number of flat
    ks = key.KeySignature(sharpCount)

    if post[1] == 0:
        ks.mode = 'major'
    if post[1] == 1:
        ks.mode = 'minor'
    return ks
Exemplo n.º 32
0
    def _fillData(self):
        '''
        >>> from music21 import pitch
        >>> a = PartitionedModule(pitch)
        >>> len(a.names) == len(a._data)
        True
        >>> a.namesOrdered
        ['Pitch', 'Accidental']
        >>> a.names[0]
        'Pitch'
        >>> a.names[0] == a._data[0].name
        True
        '''
        post = []

        for name in self.names:
            objName = '%s.%s' % (self.srcNameStr, name)
            obj = eval(objName)

            # skip for now
            homecls = self.srcNameEval
            if hasattr(obj, '__module__'):
                if self.srcNameStr not in obj.__module__:
                    homecls = obj.__module__

            # get kind
            if isinstance(obj, types.ModuleType):
                kind = 'module'
            elif (isinstance(obj, types.StringTypes) or 
                isinstance(obj, types.DictionaryType) or 
                isinstance(obj, types.ListType) or 
                common.isNum(obj) or common.isListLike(obj) or 
                isinstance(obj, type(MOCK_RE))): 
                kind = 'data'

            elif isinstance(obj, types.FunctionType):
                kind = 'function'
            elif isinstance(obj, types.TypeType):
                kind = 'class'
            elif isinstance(obj, environment.Environment):
                kind = 'data' # skip environment object
            else:
                environLocal.printDebug(['cannot process module level name: %s' % self.srcNameStr])
                kind = None

            post.append(inspect.Attribute(name, kind, homecls, obj))

        return post
Exemplo n.º 33
0
def cacheMetadata(domainList=['local','core', 'virtual']): 
    '''The core cache is all locally-stored corpus files. 
    '''
    from music21 import corpus, metadata

    if not common.isListLike(domainList):
        domainList = [domainList]

    t = common.Timer()
    t.start()

    # store list of file paths that caused an error
    fpError = []

    # the core cache is based on local files stored in music21
    # virtual is on-line
    for domain in domainList:
        # the domain passed here becomes the name of the bundle
        # determines the file name of the json bundle
        mdb = metadata.MetadataBundle(domain)

        if domain == 'virtual':
            getPaths = corpus.getVirtualPaths
        elif domain == 'core':
            getPaths = corpus.getCorePaths
        elif domain == 'local':
            getPaths = corpus.getLocalPaths  
        else:
            raise MetadataCacheException('invalid domain provided: %s' % domain)
            
        paths = getPaths()
    
        environLocal.warn([
            'metadata cache: starting processing of paths:', len(paths)])
    
        #mdb.addFromPaths(paths[-3:])
        # returns any paths that failed to load
        fpError += mdb.addFromPaths(paths, printDebugAfter = 50) 
        #print mdb.storage
        mdb.write() # will use a default file path based on domain

        environLocal.warn(['cache: writing time:', t, 'md items:', len(mdb.storage)])
        del mdb

    environLocal.warn(['cache: final writing time:', t])
    
    for fp in fpError:
        environLocal.warn('path failed to parse: %s' % fp)
Exemplo n.º 34
0
def getVirtualWorkList(workName, movementNumber=None, extList=None):
    '''Given a work name, search all virtual works and return a list of URLs for any matches.

    >>> getVirtualWorkList('bach/bwv1007/prelude')
    ['http://kern.ccarh.org/cgi-bin/ksdata?l=cc/bach/cello&file=bwv1007-01.krn&f=xml']

    >>> getVirtualWorkList('junk')
    []
    '''
    if not common.isListLike(extList):
        extList = [extList]

    for obj in VIRTUAL:
        if obj.corpusPath != None and workName.lower() in obj.corpusPath.lower():
            return obj.getUrlByExt(extList)
    return []
Exemplo n.º 35
0
    def __setitem__(self, key, value):

        #saxutils.escape # used for escaping strings going to xml
        # with unicode encoding
        # http://www.xml.com/pub/a/2002/11/13/py-xml.html?page=2
        # saxutils.escape(msg).encode('UTF-8')

        # add local corpus path as a key
        if key not in self._ref.keys() + ['localCorpusPath']:
            raise EnvironmentException('no preference: %s' % key)
        if value == '':
            value = None # always replace '' with None

        valid = False
        if key == 'showFormat':
            value = value.lower()
            if value in common.VALID_SHOW_FORMATS:
                valid = True
        elif key == 'writeFormat':
            value = value.lower()
            if value in common.VALID_WRITE_FORMATS:
                valid = True
        elif key == 'autoDownload':
            value = value.lower()
            if value in common.VALID_AUTO_DOWNLOAD:
                valid = True
        elif key == 'localCorpusSettings':
            # needs to be a list of strings for now
            if common.isListLike(value):
                valid = True
        else: # temporarily not validating other preferences
            valid = True

        if not valid:
            raise EnvironmentException('%s is not an acceptable value for preference: %s' % (value, key))

        # need to escape problematic characters for xml storage
        if common.isStr(value):
            value = xml.sax.saxutils.escape(value).encode('UTF-8')
        # set value
        if key == 'localCorpusPath':
            # only add if unique
            if value not in self._ref['localCorpusSettings']:
                # check for malicious values here
                self._ref['localCorpusSettings'].append(value)
        else:
            self._ref[key] = value
Exemplo n.º 36
0
def getComposerDir(composerName):
    '''Given the name of a composer, get the path to the top-level directory
    of that composer 

    >>> import os
    >>> a = getComposerDir('beethoven')
    >>> a.endswith(os.path.join('corpus', os.sep, 'beethoven'))
    True
    >>> a = getComposerDir('bach')
    >>> a.endswith(os.path.join('corpus', os.sep, 'bach'))
    True
    >>> a = getComposerDir('mozart')
    >>> a.endswith(os.path.join('corpus', os.sep, 'mozart'))
    True
    >>> a = getComposerDir('luca')
    >>> a.endswith(os.path.join('corpus', os.sep, 'luca'))
    True
    '''
    # TODO: have this also search COMPOSERS references for full names
    match = None
    for moduleName in MODULES:          
        if common.isListLike(moduleName):
            candidate = moduleName[0]         
        else:
            candidate = str(moduleName)
        if composerName.lower() not in candidate.lower():
            continue
        # might also slook at .__file__
        if not hasattr(moduleName, '__path__'): # its a list of files
            dirCandidate = moduleName[0]
            while True:
                dir = os.path.dirname(dirCandidate)
                if dir.lower().endswith(composerName.lower()):
                    break
                else:
                    dirCandidate = dir
                if dirCandidate.count(os.sep) < 2: # done enough checks
                    break
        else:
            dir = moduleName.__path__[0] 

        # last check
        if dir.lower().endswith(composerName.lower()):
            match = dir     
            break
    return match
Exemplo n.º 37
0
def getPaths(extList=None):    
    '''Get all paths in the corpus that match a known extension, or an extenion
    provided by an argument.

    >>> a = getPaths()
    >>> len(a) > 30
    True

    >>> a = getPaths('krn')
    >>> len(a) >= 4
    True
    '''
    if not common.isListLike(extList):
        extList = [extList]

    if extList == [None]:
        extList = (common.findInputExtension('lily') +
                   common.findInputExtension('musicxml') +
                   common.findInputExtension('humdrum'))
    #environLocal.printDebug(['getting paths with extensions:', extList])
    paths = []    
    for moduleName in MODULES:
        if not hasattr(moduleName, '__path__'):
            # when importing a package name (a directory) the moduleName        
            # may be a list of all paths contained within the package
            # this seems to be dependent on the context of the call:
            # from the command line is different than from the interpreter
            dirListing = moduleName
        else:
            # returns a list with one or more paths
            # the first is the path to the directory that contains xml files
            dir = moduleName.__path__[0] 
            dirListing = [os.path.join(dir, x) for x in os.listdir(dir)]

        for fp in dirListing:
            if fp in paths:
                continue
            match = False
            for ext in extList:
                if fp.endswith(ext):
                    match = True
                    break 
            if match:
                if fp not in paths:
                    paths.append(fp)    
    return paths
Exemplo n.º 38
0
    def getUrlByExt(self, extList=None):
        '''Given a request for an extension, find a best match for a URL from
        the list of known URLs. If ext is None, return the first URL.
        '''
        if not common.isListLike(extList):
            extList = [extList]
        if extList is None or extList == [None]:
            return [self.urlList[0]]  # return a list of all

        post = []
        for ext in extList:
            for url in self.urlList:
                unused_format, extFound = common.findFormatExtURL(url)
                # environLocal.printDebug([extFound, ext])
                if extFound == ext:
                    post.append(url)
        return post  # no match
Exemplo n.º 39
0
    def getUrlByExt(self, extList=None):
        '''Given a request for an extension, find a best match for a URL from 
        the list of known URLs. If ext is None, return the first URL.
        '''
        if not common.isListLike(extList):
            extList = [extList]
        if extList == None or extList == [None]:
            return [self.urlList[0]] # return a list of all 

        post = []
        for ext in extList:
            for url in self.urlList:
                unused_format, extFound = common.findFormatExtURL(url)
                #environLocal.printDebug([extFound, ext])
                if extFound == ext:
                    post.append(url)
        return post # no match
Exemplo n.º 40
0
    def _setMX(self, mxKeyList):
        """Given a mxKey object or keyList, load internal attributes
        >>> a = musicxml.Key()
        >>> a.set('fifths', 5)
        >>> b = KeySignature()
        >>> b.mx = [a]
        >>> b.sharps
        5 
        """
        if not common.isListLike(mxKeyList):
            mxKey = mxKeyList
        else:  # there may be more than one if we have more staffs per part
            mxKey = mxKeyList[0]

        self.sharps = int(mxKey.get("fifths"))
        mxMode = mxKey.get("mode")
        if mxMode != None:
            self.mode = mxMode
Exemplo n.º 41
0
    def parseData(self, dataStr):
        '''Given raw data, determine format and parse into a music21 Stream.
        '''
        format = None
        if common.isListLike(dataStr):
            format = 'tinyNotation'
        
        if format == None: # its a string
            dataStr = dataStr.lstrip()
            if dataStr.startswith('<?xml'):
                format = 'musicxml'
            elif dataStr.startswith('!!!') or dataStr.startswith('**'):
                format = 'humdrum'
            else:
                raise ConverterException('no such format found for: %s' % dataStr)

        self._setConverter(format)
        self._converter.parseData(dataStr)
Exemplo n.º 42
0
def getVirtualPaths(extList=None):
    '''Get all paths in the virtual corpus that match a known extension. An extension of None will return all known extensions.
   
    >>> len(getVirtualPaths()) > 6
    True
    '''
    if not common.isListLike(extList):
        extList = [extList]

    if extList == [None]:
        extList = _ALL_EXTENSIONS
    paths = []
    for obj in VIRTUAL:
        if obj.corpusPath != None:
            for ext in extList:
                #environLocal.printDebug([obj.corpusPath, ext])
                post = obj.getUrlByExt(ext)
                for part in post:
                    if part not in paths:
                        paths.append(part)
    return paths
Exemplo n.º 43
0
    def add(self, spanner, component):
        '''Add a spanner and one or more component references.

        The `spanner` is the object represent the connections, such as a Slur or GroupBracket.

        The `component` is one or more (a list) objects, such as Note or Part.
        
        If the spanner already exists, the component will be added to the components list.


        >>> from music21 import *
        >>> class TestMock(object): pass
        >>> tm1 = TestMock()
        >>> n1 = note.Note('c2')
        >>> n2 = note.Note('g3')
        >>> sp1 = Spanners()
        >>> sp1.add(tm1, [n1, n2])
        >>> len(sp1)
        1
        '''
        idSpanner = id(spanner)
        if idSpanner not in self.keys():
            self._storage[idSpanner] = (common.wrapWeakref(spanner), [])
            self._idRef[idSpanner] = []  # just a list

        refPair = self._storage[idSpanner]
        idList = self._idRef[idSpanner]

        # presently this does not look for redundant entries
        # store component as weak ref
        if common.isListLike(component):
            bundle = component
        else:  # just append one
            bundle = [component]

        for sub in bundle:  # permit a lost of spanners
            refPair[1].append(common.wrapWeakref(sub))
            idList.append(id(sub))
Exemplo n.º 44
0
    def getWorkList(
        self,
        workName,
        movementNumber=None,
        fileExtensions=None,
    ):
        r'''
        Search the corpus and return a list of filenames of works, always in a
        list.

        If no matches are found, an empty list is returned.

        >>> from music21 import corpus
        >>> coreCorpus = corpus.corpora.CoreCorpus()

        # returns 1 even though there is a '.mus' file, which cannot be read...

        >>> len(coreCorpus.getWorkList('cpebach/h186'))
        1
        >>> len(coreCorpus.getWorkList('cpebach/h186', None, '.xml'))
        1

        >>> len(coreCorpus.getWorkList('schumann_clara/opus17', 3))
        1
        >>> len(coreCorpus.getWorkList('schumann_clara/opus17', 2))
        0

        Make sure that 'verdi' just gets the single Verdi piece and not the
        Monteverdi pieces:

        >>> len(coreCorpus.getWorkList('verdi'))
        1

        '''
        if not common.isListLike(fileExtensions):
            fileExtensions = [fileExtensions]
        paths = self.getPaths(fileExtensions)
        results = []

        workPath = pathlib.PurePath(workName)
        workPosix = workPath.as_posix().lower()
        # find all matches for the work name
        # TODO: this should match by path component, not just
        # substring
        for path in paths:
            if workPosix in path.as_posix().lower():
                results.append(path)

        if results:
            # more than one matched...use more stringent criterion:
            # must have a slash before the name
            previousResults = results
            results = []
            for path in previousResults:
                if '/' + workPosix in path.as_posix().lower():
                    results.append(path)
            if not results:
                results = previousResults

        movementResults = []
        if movementNumber is not None and results:
            # store one ore more possible mappings of movement number
            movementStrList = []
            # see if this is a pair
            if common.isIterable(movementNumber):
                movementStrList.append(''.join(str(x) for x in movementNumber))
                movementStrList.append('-'.join(
                    str(x) for x in movementNumber))
                movementStrList.append('movement' + '-'.join(
                    str(x) for x in movementNumber))
                movementStrList.append('movement' + '-0'.join(
                    str(x) for x in movementNumber))
            else:
                movementStrList += [
                    '0{0}'.format(movementNumber),
                    str(movementNumber),
                    'movement{0}'.format(movementNumber),
                ]
            for filePath in sorted(results):
                filename = filePath.name
                if filePath.suffix:
                    filenameWithoutExtension = filePath.stem
                else:
                    filenameWithoutExtension = None
                searchPartialMatch = True
                if filenameWithoutExtension is not None:
                    # look for direct matches first
                    for movementStr in movementStrList:
                        # if movementStr.lower() in filePath.lower():
                        if filenameWithoutExtension.lower(
                        ) == movementStr.lower():
                            movementResults.append(filePath)
                            searchPartialMatch = False
                # if we have one direct match, all other matches must
                # be direct. this will match multiple files with different
                # file extensions
                if movementResults:
                    continue
                if searchPartialMatch:
                    for movementStr in movementStrList:
                        if filename.startswith(movementStr.lower()):
                            movementResults.append(filePath)
            if not movementResults:
                pass
        else:
            movementResults = results
        return sorted(set(movementResults))
Exemplo n.º 45
0
    def parseInputToPrimitive(self, inpVal):
        '''
        Determines what format a given input is in and returns a value in that format..
        First checks if it is the name of a variable defined in the parsedDataDict or the
        name of an allowable function. In either of these cases, it will return the actual value
        of the data or the actual function.
        
        Next, it will check if the string is an int, float, boolean, or none, returning the appropriate value.
        If it is a quoted string then it will remove the quotes on the ends and return it as a string.
        If it has square braces indicating a list, the inner elements will be parsed using this same function recursively.
        (Note that recursive lists like [1, 2, [3, 4]] are not yet supported
        
        If the input corresponds to none of these types, it is returned as a string.
        
        
        >>> agenda = webapps.Agenda()
        >>> agenda.addData("a",2)
        >>> agenda.addData("b",[1,2,3],"list")

        >>> processor = webapps.CommandProcessor(agenda)
        >>> processor.parseInputToPrimitive("a")
        2
        >>> processor.parseInputToPrimitive("b")
        [1, 2, 3]
        >>> processor.parseInputToPrimitive("1.0")
        1.0
        >>> processor.parseInputToPrimitive("2")
        2
        >>> processor.parseInputToPrimitive("True")
        True
        >>> processor.parseInputToPrimitive("False")
        False
        >>> processor.parseInputToPrimitive("None") == None
        True
        >>> processor.parseInputToPrimitive("'hi'")
        'hi'
        >>> processor.parseInputToPrimitive("'Madam I\'m Adam'")
        "Madam I'm Adam"
        >>> processor.parseInputToPrimitive("[1,2,3]")
        [1, 2, 3]
        >>> processor.parseInputToPrimitive("[1,'hi',3.0,True, a, justAStr]")
        [1, 'hi', 3.0, True, 2, 'justAStr']
        '''
        returnVal = None

        if common.isNum(inpVal):
            return inpVal

        if common.isListLike(inpVal):
            return [self.parseInputToPrimitive(element) for element in inpVal]

        if not common.isStr(inpVal):
            self.recordError("Unknown type for parseInputToPrimitive " +
                             str(inpVal))

        strVal = inpVal

        strVal = strVal.strip()  # removes whitespace on ends

        if strVal in self.parsedDataDict:  # Used to specify data via variable name
            returnVal = self.parsedDataDict[strVal]
        elif strVal in availableFunctions:  # Used to specify function via variable name
            returnVal = strVal
        else:
            try:
                returnVal = int(strVal)
            except:
                try:
                    returnVal = float(strVal)
                except:
                    if strVal == "True":
                        returnVal = True

                    elif strVal == "None":
                        returnVal = None

                    elif strVal == "False":
                        returnVal = False

                    elif strVal[0] == '"' and strVal[
                            -1] == '"':  # Double Quoted String
                        returnVal = strVal[1:-1]  # remove quotes

                    elif strVal[0] == "'" and strVal[
                            -1] == "'":  # Single Quoted String
                        returnVal = strVal[1:-1]  # remove quotes

                    elif strVal[0] == "[" and strVal[-1] == "]":  # List
                        listElements = strVal[1:-1].split(
                            ",")  # remove [] and split by commas
                        returnVal = [
                            self.parseInputToPrimitive(element)
                            for element in listElements
                        ]
                    else:
                        returnVal = cgi.escape(str(strVal))
        return returnVal
Exemplo n.º 46
0
def makeRests(s, refStreamOrTimeRange=None, fillGaps=False,
    timeRangeFromBarDuration=False, inPlace=True):
    '''
    Given a Stream with an offset not equal to zero,
    fill with one Rest preeceding this offset.
    This can be called on any Stream,
    a Measure alone, or a Measure that contains
    Voices.

    If `refStreamOrTimeRange` is provided as a Stream, this
    Stream is used to get min and max offsets. If a list is provided,
    the list assumed to provide minimum and maximum offsets. Rests will
    be added to fill all time defined within refStream.

    If `fillGaps` is True, this will create rests in any
    time regions that have no active elements.

    If `timeRangeFromBarDuration` is True, and the calling Stream
    is a Measure with a TimeSignature, the time range will be determined
    based on the .barDuration property.

    If `inPlace` is True, this is done in-place; if `inPlace` is False,
    this returns a modified deepcopy.

    ::

        >>> from music21 import note
        >>> from music21 import stream

    ::

        >>> a = stream.Stream()
        >>> a.insert(20, note.Note())
        >>> len(a)
        1

    ::

        >>> a.lowestOffset
        20.0

    ::

        >>> b = a.makeRests()
        >>> len(b)
        2

    ::

        >>> b.lowestOffset
        0.0

    OMIT_FROM_DOCS
    TODO: if inPlace is True, this should return None
    TODO: default inPlace = False
    '''
    from music21 import stream

    if not inPlace:  # make a copy
        returnObj = copy.deepcopy(s)
    else:
        returnObj = s

    #environLocal.printDebug([
    #    'makeRests(): object lowestOffset, highestTime', oLow, oHigh])
    if refStreamOrTimeRange is None:  # use local
        oLowTarget = 0
        if timeRangeFromBarDuration and returnObj.isMeasure:
            # NOTE: this will raise an exception if no meter can be found
            oHighTarget = returnObj.barDuration.quarterLength
        else:
            oHighTarget = returnObj.highestTime
    elif isinstance(refStreamOrTimeRange, stream.Stream):
        oLowTarget = refStreamOrTimeRange.lowestOffset
        oHighTarget = refStreamOrTimeRange.highestTime
        #environLocal.printDebug([
        #    'refStream used in makeRests', oLowTarget, oHighTarget,
        #    len(refStreamOrTimeRange)])
    # treat as a list
    elif common.isListLike(refStreamOrTimeRange):
        oLowTarget = min(refStreamOrTimeRange)
        oHighTarget = max(refStreamOrTimeRange)
        #environLocal.printDebug([
        #    'offsets used in makeRests', oLowTarget, oHighTarget,
        #    len(refStreamOrTimeRange)])
    if returnObj.hasVoices():
        bundle = returnObj.voices
    else:
        bundle = [returnObj]

    for v in bundle:
        v._elementsChanged()  # required to get correct offset times
        oLow = v.lowestOffset
        oHigh = v.highestTime

        # create rest from start to end
        qLen = oLow - oLowTarget
        if qLen > 0:
            r = note.Rest()
            r.duration.quarterLength = qLen
            #environLocal.printDebug(['makeRests(): add rests', r, r.duration])
            # place at oLowTarget to reach to oLow
            v._insertCore(oLowTarget, r)

        # create rest from end to highest
        qLen = oHighTarget - oHigh
        #environLocal.printDebug(['v', v, oHigh, oHighTarget, 'qLen', qLen])
        if qLen > 0:
            r = note.Rest()
            r.duration.quarterLength = qLen
            # place at oHigh to reach to oHighTarget
            v._insertCore(oHigh, r)
        v._elementsChanged()  # must update otherwise might add double r

        if fillGaps:
            gapStream = v.findGaps()
            if gapStream is not None:
                for e in gapStream:
                    r = note.Rest()
                    r.duration.quarterLength = e.duration.quarterLength
                    v._insertCore(e.offset, r)
        v._elementsChanged()
        #environLocal.printDebug(['post makeRests show()', v])
        # NOTE: this sorting has been found to be necessary, as otherwise
        # the resulting Stream is not sorted and does not get sorted in
        # preparing musicxml output
        if v.autoSort:
            v.sort()

    # with auto sort no longer necessary.

    #returnObj.elements = returnObj.sorted.elements
    #s.isSorted = False
    # changes elements
#         returnObj._elementsChanged()
#         if returnObj.autoSort:
#             returnObj.sort()

    return returnObj
Exemplo n.º 47
0
def music21ModWSGIFeatureApplication(environ, start_response):
    '''
    Music21 webapp to demonstrate processing of a zip file containing scores.
    Will be moved and integrated into __init__.py upon developing a standardized URL format
    as application that can perform variety of commands on user-uploaded files
    '''
    status = '200 OK'

    pathInfo = environ[
        'PATH_INFO']  # Contents of path after mount point of wsgi app but before question mark

    if pathInfo == '/uploadForm':
        output = getUploadForm()
        response_headers = [('Content-type', 'text/html'),
                            ('Content-Length', str(len(output)))]

        start_response(status, response_headers)

        return [output]

    #command = pathInfo

    formFields = cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ)

    # Check if form data is present. If not found, display error
    try:
        unused_subUploadFormFile = formFields['subUploadForm']
    except:
        html = """
            <html >
            <body style='font-family:calibri' bgcolor='#EEE' onLoad="toggleExtractors('m21')">
            <table border=0 width='100%'>
            <tr><td align='center'>
            <table border=0 width='500px' cellpadding='10px' style='background-color:#FFF'>
            <tr><td align='left'>
            <h1>Error:</h1>
            <p>Form information not found</p>
            <p><a href='/music21/featureapp/uploadForm'>Try Again</a></p>
            </td></tr></table>
            </td></tr></table>
            </body></html>
            """
        response_headers = [('Content-type', 'text/html'),
                            ('Content-Length', str(len(html)))]

        start_response(status, response_headers)

        return [html]

    # Get file from POST
    uploadedFile = formFields['fileupload'].file
    filename = formFields['fileupload'].filename

    uploadType = formFields['fileupload'].type

    # Check if filename is empty - display no file chosen error
    if filename == "":
        html = """
            <html >
            <body style='font-family:calibri' bgcolor='#EEE' onLoad="toggleExtractors('m21')">
            <table border=0 width='100%'>
            <tr><td align='center'>
            <table border=0 width='500px' cellpadding='10px' style='background-color:#FFF'>
            <tr><td align='left'>
            <h1>Music 21 Feature Extraction:</h1>
            <p><b>Error:</b> No file selected</p>
            <p><a href='/music21/featureapp/uploadForm'>Try Again</a></p>
            </td></tr></table>
            </td></tr></table>
            </body></html>
            """
        response_headers = [('Content-type', 'text/html'),
                            ('Content-Length', str(len(html)))]

        start_response(status, response_headers)

        return [html]

    # Check if uploadType is zip - display no file chosen error
    if uploadType != "application/zip":
        html = """
            <html >
            <body style='font-family:calibri' bgcolor='#EEE' onLoad="toggleExtractors('m21')">
            <table border=0 width='100%'>
            <tr><td align='center'>
            <table border=0 width='500px' cellpadding='10px' style='background-color:#FFF'>
            <tr><td align='left'>
            <h1>Music 21 Feature Extraction:</h1>
            <p><b>Error:</b> File not in .zip format</p>
            <p><a href='/music21/featureapp/uploadForm'>Try Again</a></p>
            </td></tr></table>
            </td></tr></table>
            </body></html>
            """
        response_headers = [('Content-type', 'text/html'),
                            ('Content-Length', str(len(html)))]

        start_response(status, response_headers)

        return [html]

    # Setup Feature Extractors and Data Set
    ds = features.DataSet(classLabel='Class')

    featureIDList = list()

    # Check if features have been selected. Else display error
    try:
        unused_featureFile = formFields['features']
    except:
        html = """
            <html ><body>
            <h1>Error:</h1>
            <p>No extractors selected</p>
            <p><a href='/music21/featureapp/uploadForm'>try again</a></p>
            </body></html>
            """
        return html

    if common.isListLike(formFields['features']):
        print(formFields['features'])
        for featureId in formFields['features']:
            featureIDList.append(str(featureId.value))
    else:
        featureIDList.append(formFields['features'].value)

    fes = features.extractorsById(featureIDList)
    ds.addFeatureExtractors(fes)

    # Create ZipFile Object
    zipf = zipfile.ZipFile(uploadedFile, 'r')

    # Loop Through Files
    for scoreFileInfo in zipf.infolist():

        filePath = scoreFileInfo.filename

        # Skip Directories
        if (filePath.endswith('/')):
            continue
        scoreFile = zipf.open(filePath)

        # Use Music21's converter to parse file
        parsedFile = idAndParseFile(scoreFile, filePath)

        # If valid music21 format, add to data set
        if parsedFile is not None:

            # Split into directory structure and filname
            pathPartitioned = filePath.rpartition('/')
            directory = pathPartitioned[0]
            filename = pathPartitioned[2]

            if directory == "":
                directory = 'uncategorized'

            ds.addData(parsedFile, classValue=directory, id=filename)

    # Process data set
    ds.process()

    # Get output format from POST and set appropriate output:
    outputFormatID = formFields['outputformat'].value
    if outputFormatID == CSV_OUTPUT_ID:
        output = features.OutputCSV(ds).getString()
    elif outputFormatID == ORANGE_OUTPUT_ID:
        output = features.OutputTabOrange(ds).getString()
    elif outputFormatID == ARFF_OUTPUT_ID:
        output = features.OutputARFF(ds).getString()
    else:
        output = "invalid output format"

    response_headers = [('Content-type', 'text/plain'),
                        ('Content-Length', str(len(output)))]

    start_response(status, response_headers)

    return [output]
Exemplo n.º 48
0
    def getRealized(
        self,
        useDynamicContext=True,
        useVelocity=True,
        useArticulations=True,
        baseLevel=0.5,
        clip=True,
    ):
        '''
        Get a realized unit-interval scalar for this Volume. This scalar is to
        be applied to the dynamic range of whatever output is available,
        whatever that may be.

        The `baseLevel` value is a middle value between 0 and 1 that all
        scalars modify. This also becomes the default value for unspecified
        dynamics. When scalars (between 0 and 1) are used, their values are
        doubled, such that mid-values (around .5, which become 1) make no
        change.

        This can optionally take into account `dynamicContext`, `useVelocity`,
        and `useArticulation`.

        If `useDynamicContext` is True, a context search for a dynamic will be
        done, else dynamics are ignored. Alternatively, the useDynamicContext
        may supply a Dynamic object that will be used instead of a context
        search.

        If `useArticulations` is True and parent is not None, any articulations
        found on that parent will be used to adjust the volume. Alternatively,
        the `useArticulations` parameter may supply a list of articulations
        that will be used instead of that available on a parent.

        The `velocityIsRelative` tag determines if the velocity value includes
        contextual values, such as dynamics and and accents, or not.

        ::

            >>> s = stream.Stream()
            >>> s.repeatAppend(note.Note('d3', quarterLength=.5), 8)
            >>> s.insert([0, dynamics.Dynamic('p'), 1, dynamics.Dynamic('mp'), 2, dynamics.Dynamic('mf'), 3, dynamics.Dynamic('f')])

        ::

            >>> s.notes[0].volume.getRealized()
            0.496...

        ::

            >>> s.notes[1].volume.getRealized()
            0.496...

        ::

            >>> s.notes[2].volume.getRealized()
            0.63779...

        ::

            >>> s.notes[7].volume.getRealized()
            0.99212...

        ::

            >>> # velocity, if set, will be scaled by dynamics
            >>> s.notes[7].volume.velocity = 20
            >>> s.notes[7].volume.getRealized()
            0.22047...

        ::

            >>> # unless we set the velocity to not be relative
            >>> s.notes[7].volume.velocityIsRelative = False
            >>> s.notes[7].volume.getRealized()
            0.1574803...

        '''
        #velocityIsRelative might be best set at import. e.g., from MIDI,
        # velocityIsRelative is False, but in other applications, it may not
        # be
        val = baseLevel
        dm = None  # no dynamic mark
        # velocity is checked first; the range between 0 and 1 is doubled,
        # to 0 to 2. a velocityScalar of .7 thus scales the base value of
        # .5 by 1.4 to become .7
        if useVelocity:
            if self._velocity is not None:
                if not self.velocityIsRelative:
                    # if velocity is not relateive
                    # it should fully determines output independent of anything
                    # else
                    val = self.velocityScalar
                else:
                    val = val * (self.velocityScalar * 2.0)
            # this value provides a good default velocity, as .5 is low
            # this not a scalar application but a shift.
            else:  # target :0.70866
                val += 0.20866
        # only change the val from here if velocity is relative
        if self.velocityIsRelative:
            if useDynamicContext is not False:
                if hasattr(
                        useDynamicContext,
                        'classes') and 'Dynamic' in useDynamicContext.classes:
                    dm = useDynamicContext  # it is a dynamic
                elif self.parent is not None:
                    dm = self.getDynamicContext()  # dm may be None
                else:
                    environLocal.printDebug([
                        'getRealized():',
                        'useDynamicContext is True but no dynamic supplied or found in context'
                    ])
                if dm is not None:
                    # double scalare (so range is between 0 and 1) and scale
                    # t he current val (around the base)
                    val = val * (dm.volumeScalar * 2.0)
            # userArticulations can be a list of 1 or more articulation objects
            # as well as True/False
            if useArticulations is not False:
                am = None
                if common.isListLike(useArticulations):
                    am = useArticulations
                elif hasattr(useArticulations, 'classes'
                             ) and 'Articulation' in useArticulations.classes:
                    am = [useArticulations]  # place in a list
                elif self.parent is not None:
                    am = self.parent.articulations
                if am is not None:
                    for a in am:
                        # add in volume shift for all articulations
                        val += a.volumeShift
        if clip:  # limit between 0 and 1
            if val > 1:
                val = 1.0
            elif val < 0:
                val = 0.0
        # might to rebalance range after scalings
        # always update cached result each time this is called
        self._cachedRealized = val
        return val
Exemplo n.º 49
0
    def _parseData(self):
        '''
        Parses data specified as strings in self.dataDict into objects in self.parsedDataDict
        '''
        for (name, dataDictElement) in self.dataDict.iteritems():
            if 'data' not in dataDictElement:
                self.addError("no data specified for data element " +
                              unicode(dataDictElement))
                continue

            dataStr = dataDictElement['data']

            if 'fmt' in dataDictElement:
                fmt = dataDictElement['fmt']

                if name in self.parsedDataDict:
                    self.addError("duplicate definition for data named " +
                                  str(name) + " " + str(dataDictElement))
                    continue
                if fmt not in availableDataFormats:
                    self.addError("invalid data format for data element " +
                                  str(dataDictElement))
                    continue

                if fmt == 'string' or fmt == 'str':
                    if dataStr.count("'") == 2:  # Single Quoted String
                        data = dataStr.replace("'", "")  # remove excess quotes
                    elif dataStr.count("\"") == 2:  # Double Quoted String
                        data = dataStr.replace("\"",
                                               "")  # remove excess quotes
                    else:
                        self.addError(
                            "invalid string (not in quotes...) for data element "
                            + str(dataDictElement))
                        continue
                elif fmt == 'int':
                    try:
                        data = int(dataStr)
                    except:
                        self.addError("invalid integer for data element " +
                                      str(dataDictElement))
                        continue
                elif fmt in ['bool', 'boolean']:
                    if dataStr in ['true', 'True']:
                        data = True
                    elif dataStr in ['false', 'False']:
                        data = False
                    else:
                        self.addError("invalid boolean for data element " +
                                      str(dataDictElement))
                        continue
                elif fmt == 'list':
                    # in this case dataStr should actually be an list object.
                    if not common.isListLike(dataStr):
                        self.addError(
                            "list format must actually be a list structure " +
                            str(dataDictElement))
                        continue
                    data = []
                    for elementStr in dataStr:
                        if common.isStr(elementStr):
                            (matchFound, dataElement
                             ) = self.parseStringToPrimitive(elementStr)
                            if not matchFound:
                                self.addError(
                                    "format could not be detected for data element  "
                                    + str(elementStr))
                                continue
                        else:
                            dataElement = elementStr
                        data.append(dataElement)
                else:
                    if fmt in ['xml', 'musicxml']:
                        if dataStr.find("<!DOCTYPE") == -1:
                            dataStr = """<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 1.1 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">""" + dataStr
                        if dataStr.find("<?xml") == -1:
                            dataStr = """<?xml version="1.0" encoding="UTF-8"?>""" + dataStr
                    try:
                        data = converter.parseData(dataStr)
                    except converter.ConverterException as e:
                        #self.addError("Error parsing data variable "+name+": "+str(e)+"\n\n"+dataStr)
                        self.addError(
                            "Error parsing data variable " + name + ": " +
                            unicode(e) + "\n\n" + dataStr, e)
                        continue
            else:  # No format specified
                (matchFound, data) = self.parseStringToPrimitive(dataStr)
                if not matchFound:
                    self.addError(
                        "format could not be detected for data element  " +
                        str(dataDictElement))
                    continue

            self.parsedDataDict[name] = data
Exemplo n.º 50
0
def getColor(color):
    '''
    Convert any specification of a color to a hexadecimal color used by matplotlib.

    >>> graph.utilities.getColor('red')
    '#ff0000'
    >>> graph.utilities.getColor('r')
    '#ff0000'
    >>> graph.utilities.getColor('Steel Blue')
    '#4682b4'
    >>> graph.utilities.getColor('#f50')
    '#ff5500'
    >>> graph.utilities.getColor([0.5, 0.5, 0.5])
    '#808080'
    >>> graph.utilities.getColor(0.8)
    '#cccccc'
    >>> graph.utilities.getColor([0.8])
    '#cccccc'
    >>> graph.utilities.getColor([255, 255, 255])
    '#ffffff'

    Invalid colors raise GraphExceptions:

    >>> graph.utilities.getColor('l')
    Traceback (most recent call last):
    music21.graph.utilities.GraphException: invalid color abbreviation: l

    >>> graph.utilities.getColor('chalkywhitebutsortofgreenish')
    Traceback (most recent call last):
    music21.graph.utilities.GraphException: invalid color name: chalkywhitebutsortofgreenish

    >>> graph.utilities.getColor(True)
    Traceback (most recent call last):
    music21.graph.utilities.GraphException: invalid color specification: True
    '''
    # expand a single value to three
    if common.isNum(color):
        color = [color, color, color]
    if isinstance(color, str):
        if color[0] == '#':  # assume is hex
            # this will expand three-value codes, and check for badly
            # formed codes
            return webcolors.normalize_hex(color)
        color = color.lower().replace(' ', '')
        # check for one character matplotlib colors
        if len(color) == 1:
            colorMap = {
                'b': 'blue',
                'g': 'green',
                'r': 'red',
                'c': 'cyan',
                'm': 'magenta',
                'y': 'yellow',
                'k': 'black',
                'w': 'white'
            }
            try:
                color = colorMap[color]
            except KeyError:
                raise GraphException('invalid color abbreviation: %s' % color)
        try:
            return webcolors.css3_names_to_hex[color]
        except KeyError:  # no color match
            raise GraphException('invalid color name: %s' % color)

    elif common.isListLike(color):
        percent = False
        for sub in color:
            if sub < 1:
                percent = True
                break
        if percent:
            if len(color) == 1:
                color = [color[0], color[0], color[0]]
            # convert to 0 100% values as strings with % symbol
            colorStrList = [str(x * 100) + "%" for x in color]
            return webcolors.rgb_percent_to_hex(colorStrList)
        else:  # assume integers
            return webcolors.rgb_to_hex(tuple(color))
    raise GraphException('invalid color specification: %s' % color)
Exemplo n.º 51
0
    def __init__(self, groupFilterList=()):
        super().__init__()

        if not common.isListLike(groupFilterList):
            groupFilterList = [groupFilterList]
        self.groupFilterList = groupFilterList
Exemplo n.º 52
0
def getPlotsToMake(*args, **keywords):
    '''
    Given `format` and `values` provided as arguments or keywords, return a list of plot classes.
    
    no arguments = horizontalbar

    >>> graph.getPlotsToMake()
    [<class 'music21.graph.plot.HorizontalBarPitchSpaceOffset'>]
    
    >>> graph.getPlotsToMake('windowed')
    [<class 'music21.graph.plot.WindowedKey'>]
    '''
    plotClasses = [
        # histograms
        plot.HistogramPitchSpace, 
        plot.HistogramPitchClass, 
        plot.HistogramQuarterLength,
        # scatters
        plot.ScatterPitchSpaceQuarterLength, 
        plot.ScatterPitchClassQuarterLength, 
        plot.ScatterPitchClassOffset,
        plot.ScatterPitchSpaceDynamicSymbol,
        # offset based horizontal
        plot.HorizontalBarPitchSpaceOffset, 
        plot.HorizontalBarPitchClassOffset,
        # weighted scatter
        plot.ScatterWeightedPitchSpaceQuarterLength, 
        plot.ScatterWeightedPitchClassQuarterLength,
        plot.ScatterWeightedPitchSpaceDynamicSymbol,
        # 3d graphs
        plot.Plot3DBarsPitchSpaceQuarterLength,
        # windowed plots
        plot.WindowedKey,
        plot.WindowedAmbitus,
        # instrumentation and part graphs
        plot.Dolan,
    ]

    showFormat = ''
    values = ()

    # can match by format
    if 'format' in keywords:
        showFormat = keywords['format']
    elif 'showFormat' in keywords:
        showFormat = keywords['showFormat']

    if 'values' in keywords:
        values = keywords['values'] # should be a tuple or list

    #environLocal.printDebug(['got args pre conversion', args])
    # if no args, use pianoroll
    foundClassName = None
    if (not args 
            and showFormat == '' 
            and not values):
        showFormat = 'horizontalbar'
        values = 'pitch'
    elif len(args) == 1:
        formatCandidate = utilities.userFormatsToFormat(args[0])
        #environLocal.printDebug(['formatCandidate', formatCandidate])
        match = False
        if formatCandidate in utilities.FORMATS:
            showFormat = formatCandidate
            values = 'pitch'
            match = True
        # if one arg, assume it is a histogram value
        if formatCandidate in utilities.VALUES:
            showFormat = 'histogram'
            values = (args[0],)
            match = True
        # permit directly matching the class name
        if not match:
            for className in plotClasses:
                if formatCandidate in str(className).lower():
                    match = True
                    foundClassName = className
                    break
    elif len(args) > 1:
        showFormat = utilities.userFormatsToFormat(args[0])
        values = args[1:] # get all remaining
    if not common.isListLike(values):
        values = (values,)
        
    # make it mutable
    values = list(values)

    #environLocal.printDebug(['got args post conversion', 'format', showFormat, 
    #    'values', values, 'foundClassName', foundClassName])

    # clean data and process synonyms
    # will return unaltered if no change
    showFormat = utilities.userFormatsToFormat(showFormat) 
    values = utilities.userValuesToValues(values)
    #environLocal.printDebug(['plotStream: format, values', showFormat , values])

    plotMake = []
    if showFormat.lower() == 'all':
        plotMake = plotClasses
    elif foundClassName is not None:
        plotMake = [foundClassName] # place in a list
    else:
        plotMakeCandidates = [] # store pairs of score, class
        from music21 import stream
        sDummy = stream.Stream()
        for plotClassName in plotClasses:
            # try to match by complete class name
            pcnStr = plotClassName.__name__.lower()
            if pcnStr == showFormat.lower():
                #environLocal.printDebug(['got plot class:', plotClassName])
                plotMake.append(plotClassName)
            elif pcnStr.replace('plot', '') == showFormat.lower():
                plotMake.append(plotClassName)
            elif pcnStr in utilities.PLOTCLASS_SYNONYMS:
                syns = utilities.PLOTCLASS_SYNONYMS[pcnStr]
                for syn in syns:
                    if syn == showFormat.lower():
                        plotMake.append(plotClassName)
                        

            # try direct match of format and values
            plotClassNameValues = [x.axisLabelDefault.lower().replace(' ', '')
                                        for x in plotClassName(sDummy).allAxes if x is not None]
            plotClassNameFormat = plotClassName.graphType.lower()
            if showFormat and plotClassNameFormat != showFormat.lower():
                continue
            #environLocal.printDebug(['matching format', showFormat])
            # see if a matching set of values is specified
            # normally plots need to match all values 
            match = []
            for requestedValue in values:
                if requestedValue is None: 
                    continue
                if (requestedValue.lower() in plotClassNameValues
                        and requestedValue not in match):
                    # do not allow the same value to be requested
                    match.append(requestedValue)
                if pcnStr in utilities.PLOTCLASS_SYNONYMS:
                    syns = utilities.PLOTCLASS_SYNONYMS[pcnStr]
                    if requestedValue in syns:
                        match.append(requestedValue)                    

            if len(match) >= len(values):
                plotMake.append(plotClassName)
            else:
                sortTuple = (len(match), plotClassName)
                plotMakeCandidates.append(sortTuple)

        # if no matches, try something more drastic:
        if not plotMake and plotMakeCandidates:
            plotMakeCandidates.sort(key=lambda x: (x[0], x[1].__name__.lower()) )
            # last in list has highest score; second item is class
            plotMake.append(plotMakeCandidates[-1][1])

        elif not plotMake: # none to make and no candidates
            for plotClassName in plotClasses:
                # create a list of all possible identifiers
                plotClassIdentifiers = [plotClassName.graphType.lower()]
                plotClassIdentifiers += [x.axisLabelDefault.lower().replace(' ', '')
                                         for x in plotClassName(sDummy).allAxes if x is not None]
                
                # combine format and values args
                for requestedValue in [showFormat] + values:
                    if requestedValue.lower() in plotClassIdentifiers:
                        plotMake.append(plotClassName)
                        break
                if plotMake: # found a match
                    break
    #environLocal.printDebug(['plotMake', plotMake])
    return plotMake