Source code for music21.corpus.work

# -----------------------------------------------------------------------------
# Name:         corpus/work.py
# Purpose:      Manage one work
#
# Authors:      Michael Scott Asato Cuthbert
#
# Copyright:    Copyright © 2015 Michael Scott Asato Cuthbert
# License:      BSD, see license.txt
# -----------------------------------------------------------------------------
'''
This is a lightweight module that stores information about individual corpus works.
'''
from __future__ import annotations

from collections import namedtuple, OrderedDict
import os

from music21 import common
from music21 import prebase

# -----------------------------------------------------------------------------
CorpusWork = namedtuple('CorpusWork', ['title', 'files', 'virtual'])
CorpusFile = namedtuple('CorpusFile', ['path', 'title', 'filename', 'format', 'ext'])
# VirtualCorpusFile = namedtuple('VirtualCorpusFile', ['path', 'title', 'url', 'format'])


[docs] class DirectoryInformation(prebase.ProtoM21Object): ''' returns information about a directory in a Corpus. Called from corpus.corpora.Corpus only tested with CoreCorpus so far. ''' def __init__(self, dirName='', dirTitle='', isComposer=True, corpusObject=None): self.directoryName = dirName self.directoryTitle = dirTitle self.isComposer = isComposer self.works = OrderedDict() self.corpusObject = corpusObject self.findWorks() def _reprInternal(self): return str(self.directoryName)
[docs] def findWorks(self): r''' Populate other information about the directory such as files and filenames. >>> di = corpus.work.DirectoryInformation('schoenberg', ... corpusObject=corpus.corpora.CoreCorpus()) >>> di.findWorks() OrderedDict({'opus19': CorpusWork(title='Opus 19', files=[CorpusFile(path='schoenberg...opus19...movement2.mxl', title='Movement 2', filename='movement2.mxl', format='musicxml', ext='.mxl'), CorpusFile(path='schoenberg...opus19...movement6.mxl', title='Movement 6', filename='movement6.mxl', format='musicxml', ext='.mxl')], virtual=False)}) (The ellipses in the documentation above represent '/' on Mac/Unix systems and '\' on Windows.) ''' self.works.clear() works = self.corpusObject.getComposer(self.directoryName) # TODO: this should be renamed since not all are composers for path in works: # split by the composer dir to get relative path # environLocal.printDebug(['dir composer', composerDirectory, path]) try: # only split once in case a composer name appears in the path and filename. junk, fileStub = str(path).split(self.directoryName, 1) except ValueError: # too many/few values to unpack print('Error in processing path:', path, 'directoryName:', self.directoryName) continue if fileStub.startswith(os.sep): fileStub = fileStub[len(os.sep):] # break into file components fileComponents = fileStub.split(os.sep) # the first is either a directory for containing components # or a top-level name m21Format, ext = common.findFormatExtFile(fileComponents[-1]) if ext is None: # environLocal.printDebug([ # 'file that does not seem to have an extension', # ext, path]) continue # if not a file w/ ext, we will get None for format if m21Format is None: workStub = fileComponents[0] else: # remove the extension workStub = fileComponents[0].replace(ext, '') # create list location if not already added if workStub not in self.works: title = common.spaceCamelCase(workStub).title() self.works[workStub] = CorpusWork(title=title, files=[], virtual=False) # last component is the name m21Format, ext = common.findFormatExtFile(fileComponents[-1]) # all path parts after corpus corpusPath = os.path.join(str(self.directoryName), fileStub) corpusFileName = fileComponents[-1] # all after title = None # this works but takes a long time! # title = converter.parse(path).metadata.title # TODO: get from RichMetadataBundle! if title is None: title = common.spaceCamelCase( fileComponents[-1].replace(ext, '')) title = title.title() fileTuple = CorpusFile(path=corpusPath, title=title, filename=corpusFileName, format=m21Format, ext=ext) self.works[workStub].files.append(fileTuple) # add this path return self.works
# ----------------------------------------------------------------------------- if __name__ == '__main__': import music21 music21.mainTest()