def testGetWorkList(self): self.assertEqual(len(corpus.getPaths('.md')) >= 38, True) workList = corpus.getWorkList('bach/artOfFugue_bwv1080', 1, '.zip') self.assertEqual(len(workList), 1) self.assertEqual(len(corpus.getWorkList('handel/hwv56', (1, 1), '.md')), 1) self.assertEqual(len(corpus.getWorkList('handel/hwv56', '1-01', '.md')), 1) self.assertEqual(len(corpus.getWorkList('bach/artOfFugue_bwv1080')), 21) self.assertEqual(len(corpus.getWorkList('bach/artOfFugue_bwv1080', 1)), 1) # there are two versions of this file self.assertEqual(len(corpus.getWorkList('beethoven/opus18no1', 1)), 2) # if specify movement for bwv in [ 'bwv846', 'bwv847', 'bwv848', 'bwv849', 'bwv850', 'bwv851', 'bwv852', 'bwv853', 'bwv854', 'bwv855', 'bwv856', 'bwv857', 'bwv858', 'bwv859', 'bwv860', 'bwv861', 'bwv862', 'bwv863', 'bwv864', 'bwv865', 'bwv866', 'bwv867', 'bwv868', 'bwv869', 'bwv870', 'bwv871', 'bwv872', 'bwv873', 'bwv874', 'bwv875', 'bwv876', 'bwv877', 'bwv878', 'bwv879', 'bwv880', 'bwv881', 'bwv882', 'bwv883', 'bwv884', 'bwv885', 'bwv886', 'bwv887', 'bwv888', 'bwv889', 'bwv890', 'bwv891', 'bwv892', 'bwv893', ]: #print bwv self.assertEqual(len(corpus.getWorkList(bwv)), 2) self.assertEqual(len(corpus.getWorkList(bwv, 1)), 1) self.assertEqual(len(corpus.getWorkList(bwv, 2)), 1)
def music21ModWSGICorpusURLApplication(environ, start_response): ''' Application function in proper format for a MOD-WSGI Application: A server-mounted app that uses portions of the URL to parse and return musicxml of manipulated sections of corpus files. Results can be returned either as a noteflight embed in the browser or downloaded as an xml file. ''' status = '200 OK' pathInfo = environ['PATH_INFO'] # Contents of path after mount point of wsgi app but before question mark queryString = environ['QUERY_STRING'] # Contents of URL after question mark returnType = queryString pathParts = pathInfo.split("/") error = False resultStr = "" if len(pathParts) > 1 and pathParts[1] in ['corpusParse','corpusReduce']: workList = corpus.getWorkList(pathParts[2]) if len(workList) >1: resultStr = "Multiple choices for query "+pathParts[2]+". Please try one of the following\n" for p in workList: resultStr += path.splitext(path.basename(p))[0] + "\n" response_headers = [('Content-type', 'text/plain'), ('Content-Length', str(len(resultStr)))] start_response(status, response_headers) return [resultStr] elif len(workList) == 0: resultStr = "No results for for query "+pathParts[2]+"." response_headers = [('Content-type', 'text/plain'), ('Content-Length', str(len(resultStr)))] start_response(status, response_headers) return [resultStr] workName = workList[0] try: sc = corpus.parse(workName).measures(int(pathParts[3]),int(pathParts[4])) if pathParts[1] == 'corpusReduce': sc = reduction(sc) resultStr = sc.musicxml title = pathParts[2]+": Measures "+str(pathParts[3])+"-"+str(pathParts[4]) filename = str(pathParts[2])+".m"+str(pathParts[3])+"-"+str(pathParts[4])+"-reduced.xml" except: try: sc = corpus.parse(pathParts[2]).measures(int(pathParts[3]),int(pathParts[3])) if pathParts[1] == 'corpusReduce': sc = reduction(sc) resultStr = sc.musicxml title = pathParts[2]+": Measure "+str(pathParts[3]) filename = str(pathParts[2])+".m"+str(pathParts[3])+"-reduced.xml" except: try: sc = corpus.parse(pathParts[2]) if pathParts[1] == 'corpusReduce': sc = reduction(sc) resultStr = sc.musicxml title = pathParts[2] filename = str(pathParts[2])+"-reduced.xml" except Exception as e: resultStr = "Error parsing file "+str(e) + '\n\n' error = True else: error = True if error: resultStr += "Try calling a url of the form:" resultStr += "\n /music21/urlinterface/corpusParse/<WORKNAME> to download a musicxml file of the specified corpus file." resultStr += "\n\n /music21/urlinterface/corpusParse/<WORKNAME>/<MEASURE_NUM> to download a musicxml file of the specified measure of a corpus file." resultStr += "\n\n /music21/urlinterface/corpusParse/<WORKNAME>/<MEASURE_START>/<MEASURE_END> to download a musicxml file of the specified measures of a corpus file." resultStr += "\n\n /music21/urlinterface/corpusReduce/<WORKNAME> to download an annotated, chordified reduction of the specified corpus file." resultStr += "\n\n /music21/urlinterface/corpusReduce/<WORKNAME>/<MEASURE_NUM> to download an annotated, chordified reduction of the specified measure of a corpus file." resultStr += "\n\n /music21/urlinterface/corpusReduce/<WORKNAME>/<MEASURE_START>/<MEASURE_END> to download an annotated, chordified reduction of the specified measures of a corpus file." resultStr += "\n\n\nSpecifying Return Format:" resultStr += "\n The return format will default to a Noteflight embed that will load the resulting score." resultStr += "\n\n Add ?xmltext to the end of the url to display the xmltext of the score as plain text" resultStr += "\n\n Add ?xml to the end of the url to download the result as a .xml file" error = True response_headers = [('Content-type', 'text/plain'), ('Content-Length', str(len(resultStr)))] start_response(status, response_headers) return [resultStr] else: if returnType == "xml": response_headers = [('Content-type', 'application/vnd.recordare.musicxml+xml'), ('Content-disposition','attachment; filename='+filename), ('Content-Length', str(len(resultStr))), ] start_response(status, response_headers) return [resultStr] elif returnType == "xmltext": response_headers = [('Content-type', 'text/plain'), ('Content-Length', str(len(resultStr)))] start_response(status, response_headers) return [resultStr] else: templateStr = noteflightEmbedTemplate(resultStr,title) response_headers = [('Content-type', 'text/html'), ('Content-Length', str(len(templateStr)))] start_response(status, response_headers) return [templateStr]
def parse( workName, movementNumber=None, number=None, fileExtensions=None, forceSource=False, ): ''' The most important method call for corpus. Similar to the :meth:`~music21.converter.parse` method of converter (which takes in a filepath on the local hard drive), this method searches the corpus (including the virtual corpus) for a work fitting the workName description and returns a :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. For instance, some of our ABC documents contain dozens of folk songs within a single file. Advanced: if `forceSource` is True, the original file will always be loaded freshly and pickled (e.g., pre-parsed) files will be ignored. This should not be needed if the file has been changed, since the filetime of the file and the filetime of the pickled version are compared. But it might be needed if the music21 parsing routine has changed. Example, get a chorale by Bach. Note that the source type does not need to be specified, nor does the name Bach even (since it's the only piece with the title BWV 66.6) >>> from music21 import corpus >>> bachChorale = corpus.Corpus.parse('bwv66.6') >>> len(bachChorale.parts) 4 After parsing, the file path within the corpus is stored as ``.corpusFilePath`` >>> bachChorale.corpusFilepath u'bach/bwv66.6.mxl' ''' from music21 import corpus if workName in (None, ''): raise corpus.CorpusException( 'a work name must be provided as an argument') if not common.isListLike(fileExtensions): fileExtensions = [fileExtensions] workList = corpus.getWorkList( workName, movementNumber, fileExtensions) if not workList: if common.isListLike(workName): workName = os.path.sep.join(workName) if workName.endswith(".xml"): # might be compressed MXL file newWorkName = os.path.splitext(workName)[0] + ".mxl" try: return Corpus.parse( newWorkName, movementNumber, number, fileExtensions, forceSource, ) except corpus.CorpusException: # avoids having the name come back with .mxl instead of # .xmlrle raise corpus.CorpusException( 'Could not find an xml or mxl work that met this ' + 'criterion: {0}'.format(workName) + '. If you are searching for a file on disk, use "converter" instead of "corpus".') workList = corpus.getVirtualWorkList( workName, movementNumber, fileExtensions, ) if len(workList) == 1: filePath = workList[0] elif not len(workList): raise corpus.CorpusException( 'Could not find a work that met this criterion: {0};'.format( workName) + 'if you are searching for a file on disk, use "converter" instead of "corpus".') else: filePath = workList[0] streamObject = converter.parse( filePath, forceSource=forceSource, number=number, ) corpus._addCorpusFilepath(streamObject, filePath) return streamObject
def testGetWorkList(self): self.assertEqual(len(corpus.getPaths('.md')) >= 38, True) workList = corpus.getWorkList('bach/artOfFugue_bwv1080', 1, '.zip') self.assertEqual(len(workList), 1) self.assertEqual( len(corpus.getWorkList('handel/hwv56', (1, 1), '.md')), 1) self.assertEqual( len(corpus.getWorkList('handel/hwv56', '1-01', '.md')), 1) self.assertEqual(len(corpus.getWorkList('bach/artOfFugue_bwv1080')), 21) self.assertEqual(len(corpus.getWorkList('bach/artOfFugue_bwv1080', 1)), 1) # there are two versions of this file self.assertEqual(len(corpus.getWorkList('beethoven/opus18no1', 1)), 2) # if specify movement for bwv in [ 'bwv846', 'bwv847', 'bwv848', 'bwv849', 'bwv850', 'bwv851', 'bwv852', 'bwv853', 'bwv854', 'bwv855', 'bwv856', 'bwv857', 'bwv858', 'bwv859', 'bwv860', 'bwv861', 'bwv862', 'bwv863', 'bwv864', 'bwv865', 'bwv866', 'bwv867', 'bwv868', 'bwv869', 'bwv870', 'bwv871', 'bwv872', 'bwv873', 'bwv874', 'bwv875', 'bwv876', 'bwv877', 'bwv878', 'bwv879', 'bwv880', 'bwv881', 'bwv882', 'bwv883', 'bwv884', 'bwv885', 'bwv886', 'bwv887', 'bwv888', 'bwv889', 'bwv890', 'bwv891', 'bwv892', 'bwv893', ]: #print bwv self.assertEqual(len(corpus.getWorkList(bwv)), 2) self.assertEqual(len(corpus.getWorkList(bwv, 1)), 1) self.assertEqual(len(corpus.getWorkList(bwv, 2)), 1)