def __init__(self, bassNote = 'C3', notationString = None, fbScale = None, fbRules = rules.Rules(), numParts = 4, maxPitch = 'B5', listOfPitches = None): ''' A Segment corresponds to a 1:1 realization of a bassNote and notationString of a :class:`~music21.figuredBass.realizer.FiguredBassLine`. It is created by passing six arguments: a :class:`~music21.figuredBass.realizerScale.FiguredBassScale`, a bassNote, a notationString, a :class:`~music21.figuredBass.rules.Rules` object, a number of parts and a maximum pitch. Realizations of a Segment are represented as possibility tuples (see :mod:`~music21.figuredBass.possibility` for more details). Methods in Python's `itertools <http://docs.python.org/library/itertools.html>`_ module are used extensively. Methods which generate possibilities or possibility progressions return iterators, which are turned into lists in the examples for display purposes only. if fbScale is None, a realizerScale.FiguredBassScale() is created if fbRules is None, a rules.Rules() instance is created. Each Segment gets its own deepcopy of the one given. Here, a Segment is created using the default values: a FiguredBassScale in C, a bassNote of C3, an empty notationString, and a default Rules object. >>> from music21.figuredBass import segment >>> s1 = segment.Segment() >>> s1.bassNote <music21.note.Note C> >>> s1.numParts 4 >>> s1.pitchNamesInChord ['C', 'E', 'G'] >>> [str(p) for p in s1.allPitchesAboveBass] ['C3', 'E3', 'G3', 'C4', 'E4', 'G4', 'C5', 'E5', 'G5'] >>> s1.segmentChord <music21.chord.Chord C3 E3 G3 C4 E4 G4 C5 E5 G5> ''' if common.isStr(bassNote): bassNote = note.Note(bassNote) if common.isStr(maxPitch): maxPitch = pitch.Pitch(maxPitch) if fbScale is None: global _defaultRealizerScale if _defaultRealizerScale is None: _defaultRealizerScale = realizerScale.FiguredBassScale() fbScale = _defaultRealizerScale # save making it if fbRules is None: self.fbRules = rules.Rules() else: self.fbRules = copy.deepcopy(fbRules) self.bassNote = bassNote self.numParts = numParts self._maxPitch = maxPitch if notationString == None and listOfPitches != None: #must be a chord symbol or roman numeral.... self.pitchNamesInChord = listOfPitches #!---------- Added to accommodate harmony.ChordSymbol and roman.RomanNumeral objects --------! else: self.pitchNamesInChord = fbScale.getPitchNames(self.bassNote.pitch, notationString) self.allPitchesAboveBass = getPitches(self.pitchNamesInChord, self.bassNote.pitch, self._maxPitch) self.segmentChord = chord.Chord(self.allPitchesAboveBass, quarterLength = bassNote.quarterLength) self._environRules = environment.Environment(_MOD)
def printDebug(self, msg, statusLevel=common.DEBUG_USER, debugFormat=None): ''' Format one or more data elements into string, and print it to stderr. The first arg can be a list of strings or a string; lists are concatenated with common.formatStr(). ''' #if not common.isNum(statusLevel): # raise EnvironmentException('bad statusLevel argument given: %s' % statusLevel) # if self.__getitem__('debug') >= statusLevel: # if common.isStr(msg): # msg = [msg] # make into a list # if msg[0] != self.modNameParent and self.modNameParent != None: # msg = [self.modNameParent + ':'] + msg # # pass list to common.formatStr # msg = common.formatStr(*msg, format=debugFormat) # sys.stderr.write(msg) if _environStorage['instance'].__getitem__('debug') >= statusLevel: if common.isStr(msg): msg = [msg] # make into a list if msg[0] != self.modNameParent and self.modNameParent != None: msg = [self.modNameParent + ':'] + msg # pass list to common.formatStr msg = common.formatStr(*msg, format=debugFormat) sys.stderr.write(msg)
def parseData(self, tnData, number=None): '''Open TinyNotation data from a string or list >>> tnData = ["E4 r f# g=lastG trip{b-8 a g} c", "3/4"] >>> c = converter.subConverters.ConverterTinyNotation() >>> s = c.parseData(tnData) >>> c.stream.show('text') {0.0} <music21.meter.TimeSignature 3/4> {0.0} <music21.note.Note E> {1.0} <music21.note.Rest rest> {2.0} <music21.note.Note F#> {3.0} <music21.note.Note G> {4.0} <music21.note.Note B-> {4.3333} <music21.note.Note A> {4.6667} <music21.note.Note G> {5.0} <music21.note.Note C> ''' if common.isStr(tnData): tnStr = tnData tnTs = None else: # assume a 2 element sequence tnStr = tnData[0] tnTs = tnData[1] from music21 import tinyNotation self.stream = tinyNotation.TinyNotationStream(tnStr, tnTs)
def romanTextToStreamOpus(rtHandler, inputM21=None): '''The main processing routine for RomanText objects that may or may not be multi movement. Takes in a romanText.base.RTFile() object, or a string as rtHandler. Runs `romanTextToStreamScore()` as its main work. If inputM21 is None then it will create a Score or Opus object. Return either a Score object, or, if a multi-movement work is defined, an Opus object. ''' from music21 import romanText as romanTextModule from music21 import stream if common.isStr(rtHandler): rtf = romanTextModule.RTFile() rtHandler = rtf.readstr(rtHandler) # return handler, processes tokens if rtHandler.definesMovements(): # create an opus if inputM21 == None: s = stream.Opus() else: s = inputM21 # copy the common header to each of the sub-handlers handlerBundles = rtHandler.splitByMovement(duplicateHeader=True) # see if we have header information for h in handlerBundles: #print h, len(h) # append to opus s.append(romanTextToStreamScore(h)) return s # an opus else: # create a Score return romanTextToStreamScore(rtHandler, inputM21=inputM21)
def parseData(self, tnData, number=None): '''Open TinyNotation data from a string >>> tnData = "3/4 E4 r f# g=lastG trip{b-8 a g} c" >>> c = converter.subConverters.ConverterTinyNotation() >>> s = c.parseData(tnData) >>> c.stream.show('text') {0.0} <music21.stream.Measure 1 offset=0.0> {0.0} <music21.clef.TrebleClef> {0.0} <music21.meter.TimeSignature 3/4> {0.0} <music21.note.Note E> {1.0} <music21.note.Rest rest> {2.0} <music21.note.Note F#> {3.0} <music21.stream.Measure 2 offset=3.0> {0.0} <music21.note.Note G> {1.0} <music21.note.Note B-> {1.3333} <music21.note.Note A> {1.6667} <music21.note.Note G> {2.0} <music21.note.Note C> {2.5} <music21.bar.Barline style=final> ''' if common.isStr(tnData): tnStr = tnData else: # assume a 2 element sequence raise SubConverterException( "TinyNotation no longer supports two-element calls; put the time signature in the stream" ) from music21 import tinyNotation self.stream = tinyNotation.Converter(tnStr, **self.keywords).parse().stream
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
def _filterNodeId(self, id): '''Given a node id, return the edge coordinates. Node 1 is the first node, even though the edge coordinates are 'start' and 0. >>> edgeList = ['M2', 'M2', 'm2', 'M2', 'M2', 'M2', 'm2'] >>> net = IntervalNetwork() >>> net.setEdges(edgeList) >>> net._filterNodeId(1) ('start', 0) >>> net._filterNodeId([3,4]) (3, 4) >>> net._filterNodeId('last') (5, 'end') >>> net._filterNodeId('first') ('start', 0) ''' if common.isNum(id): # assume counting nodes from 1 return self._nodesOrdered[id-1 % len(self._nodesOrdered)] if common.isStr(id): if id.lower() in ['start', 'first']: return self._getFirstNode() elif id.lower() in ['end', 'last']: return self._getLastNode() else: # match coords if tuple(id) in self._nodesOrdered: return tuple(id)
def romanTextToStreamOpus(rtHandler, inputM21=None): '''The main processing routine for RomanText objects that may or may not be multi movement. Takes in a romanText.rtObjects.RTFile() object, or a string as rtHandler. Runs `romanTextToStreamScore()` as its main work. If inputM21 is None then it will create a Score or Opus object. Return either a Score object, or, if a multi-movement work is defined, an Opus object. ''' from music21 import stream if common.isStr(rtHandler): rtf = rtObjects.RTFile() rtHandler = rtf.readstr(rtHandler) # return handler, processes tokens if rtHandler.definesMovements(): # create an opus if inputM21 == None: s = stream.Opus() else: s = inputM21 # copy the common header to each of the sub-handlers handlerBundles = rtHandler.splitByMovement(duplicateHeader=True) # see if we have header information for h in handlerBundles: #print h, len(h) # append to opus s.append(romanTextToStreamScore(h)) return s # an opus else: # create a Score return romanTextToStreamScore(rtHandler, inputM21=inputM21)
def _getKeyAndPrefix(rtKeyOrString): '''Given an RTKey specification, return the Key and a string prefix based on the tonic: >>> romanText.translate._getKeyAndPrefix('c') (<music21.key.Key of c minor>, 'c: ') >>> romanText.translate._getKeyAndPrefix('F#') (<music21.key.Key of F# major>, 'F#: ') >>> romanText.translate._getKeyAndPrefix('Eb') (<music21.key.Key of E- major>, 'E-: ') >>> romanText.translate._getKeyAndPrefix('Bb') (<music21.key.Key of B- major>, 'B-: ') >>> romanText.translate._getKeyAndPrefix('bb') (<music21.key.Key of b- minor>, 'b-: ') >>> romanText.translate._getKeyAndPrefix('b#') (<music21.key.Key of b# minor>, 'b#: ') ''' from music21 import key if common.isStr(rtKeyOrString): rtKeyOrString = key.convertKeyStringToMusic21KeyString(rtKeyOrString) k = key.Key(rtKeyOrString) else: k = rtKeyOrString.getKey() tonicName = k.tonic.name if k.mode == 'minor': tonicName = tonicName.lower() prefix = tonicName + ": " return k, prefix
def parseData(self, tnData, number=None): '''Open TinyNotation data from a string >>> tnData = "3/4 E4 r f# g=lastG trip{b-8 a g} c" >>> c = converter.subConverters.ConverterTinyNotation() >>> s = c.parseData(tnData) >>> c.stream.show('text') {0.0} <music21.stream.Measure 1 offset=0.0> {0.0} <music21.clef.TrebleClef> {0.0} <music21.meter.TimeSignature 3/4> {0.0} <music21.note.Note E> {1.0} <music21.note.Rest rest> {2.0} <music21.note.Note F#> {3.0} <music21.stream.Measure 2 offset=3.0> {0.0} <music21.note.Note G> {1.0} <music21.note.Note B-> {1.3333} <music21.note.Note A> {1.6667} <music21.note.Note G> {2.0} <music21.note.Note C> {2.5} <music21.bar.Barline style=final> ''' if common.isStr(tnData): tnStr = tnData else: # assume a 2 element sequence raise SubConverterException( "TinyNotation no longer supports two-element calls; put the time signature " + "in the stream") from music21 import tinyNotation self.stream = tinyNotation.Converter(tnStr, **self.keywords).parse().stream
def __init__(self, value = None): music21.Music21Object.__init__(self) if not common.isStr(value): # assume it is a number, try to convert value = dynamicStrFromDecimal(value) self.value = value if self.value in longNames: self.longName = longNames[self.value] else: self.longName = None if self.value in englishNames: self.englishName = englishNames[self.value] else: self.englishName = None # for position, as musicxml, all units are in tenths of interline space # position is needed as default positions are often incorrect self.posDefaultX = None self.posDefaultY = None self.posRelativeX = -36 # this value provides good 16th note alignment self.posRelativeY = None self.posPlacement = 'below' # attr in mxDirection, below or above
def __init__(self, value=None): base.Music21Object.__init__(self) # the scalar is used to calculate the final output of a note # under this dynamic. if this property is set, it will override # use of a default. self._volumeScalar = None self.longName = None self.englishName = None self._value = None if not common.isStr(value): # assume it is a number, try to convert self._volumeScalar = value self.value = dynamicStrFromDecimal(value) else: self.value = value # will use property # for position, as musicxml, all units are in tenths of interline space # position is needed as default positions are often incorrect self._positionDefaultX = -36 self._positionDefaultY = -80 # below top line # this value provides good 16th note alignment self._positionRelativeX = None self._positionRelativeY = None # this does not do anything if default y is defined self._positionPlacement = None
def antiParallelMotion(self, simpleName = None): ''' Returns true if the simple interval before is the same as the simple interval after and the motion is contrary. if simpleName is specified as an Interval object or a string then it only returns true if the simpleName of both intervals is the same as simpleName (i.e., use to find antiParallel fifths) >>> from music21 import * >>> n11 = note.Note("C4") >>> n12 = note.Note("D3") # descending 7th >>> n21 = note.Note("G4") >>> n22 = note.Note("A4") # ascending 2nd >>> vlq1 = voiceLeading.VoiceLeadingQuartet(n11, n12, n21, n22) >>> vlq1.antiParallelMotion() True >>> vlq1.antiParallelMotion('M2') False >>> vlq1.antiParallelMotion('P5') True We can also use interval objects >>> p5Obj = interval.Interval("P5") >>> p8Obj = interval.Interval('P8') >>> vlq1.antiParallelMotion(p5Obj) True >>> p8Obj = interval.Interval('P8') >>> vlq1.antiParallelMotion(p8Obj) False >>> n1 = note.Note('G4') >>> n2 = note.Note('G4') >>> m1 = note.Note('G4') >>> m2 = note.Note('G3') >>> vl2 = VoiceLeadingQuartet(n1, n2, m1, m2) >>> vl2.antiParallelMotion() False ''' if not self.contraryMotion(): return False else: if self.vIntervals[0].simpleName == self.vIntervals[1].simpleName: if simpleName is None: return True else: if common.isStr(simpleName): if self.vIntervals[0].simpleName == simpleName: return True else: return False else: # assume Interval object if self.vIntervals[0].simpleName == simpleName.simpleName: return True else: return False else: return False
def pitchToSharps(value, mode=None): '''Given a pitch or :class:`music21.pitch.Pitch` object, return the number of sharps found in the major key. The `mode` parameter can be None (=Major), 'major', or 'minor'. >>> from music21 import * >>> key.pitchToSharps('c') 0 >>> key.pitchToSharps('c', 'minor') -3 >>> key.pitchToSharps('a', 'minor') 0 >>> key.pitchToSharps('d') 2 >>> key.pitchToSharps('e-') -3 >>> key.pitchToSharps('a') 3 >>> key.pitchToSharps('e', 'minor') 1 >>> key.pitchToSharps('f#', 'major') 6 >>> key.pitchToSharps('g-', 'major') -6 >>> key.pitchToSharps('c#') 7 >>> key.pitchToSharps('g#') 8 ''' if common.isStr(value): p = pitch.Pitch(value) else: p = value # start at C and continue in both directions sharpSource = [0] for i in range(1,13): sharpSource.append(i) sharpSource.append(-i) minorShift = interval.Interval('-m3') # NOTE: this may not be the fastest approach match = None for i in sharpSource: pCandidate = sharpsToPitch(i) if mode in [None, 'major']: if pCandidate.name == p.name: match = i break else: # match minor pitch pMinor = pCandidate.transpose(minorShift) if pMinor.name == p.name: match = i break return match
def warn(self, msg): '''To print a warning to the user, send a list of strings to this method. ''' if common.isStr(msg): msg = [msg] # make into a list if msg[0] != self.modNameParent and self.modNameParent != None: msg = [self.modNameParent + ': WARNING:'] + msg msg = common.formatStr(*msg) sys.stderr.write(msg)
def __init__(self, text=None, number=1, syllabic=None): if not common.isStr(text): # do not want to do this unless we are sure this is not a string # possible might alter unicode or other string-like representations self.text = str(text) else: self.text = text if not common.isNum(number): raise LyricException('Number best be number') self.number = number self.syllabic = syllabic # can be begin, middle, or end
def __setitem__(self, key, value): '''Dictionary-like setting. Changes are made only to local dictionary. Must call write() to make permanent >>> from music21 import * >>> a = music21.environment.Environment() >>> a['debug'] = 1 >>> a['graphicsPath'] = '/test&Encode' >>> a['graphicsPath'] '/test&Encode' >>> a['autoDownload'] = 'adsf' Traceback (most recent call last): EnvironmentException: adsf is not an acceptable value for preference: autoDownload >>> a['showFormat'] = 'adsf' Traceback (most recent call last): EnvironmentException: adsf is not an acceptable value for preference: showFormat >>> a['showFormat'] = 'musicxml' ''' #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') if key not in self.ref.keys(): 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 == 'debug': log.setLevel(logging.INFO) elif key == 'autoDownload': value = value.lower() if value in common.VALID_AUTO_DOWNLOAD: 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)) if common.isStr(value): value = xml.sax.saxutils.escape(value).encode('UTF-8') self.ref[key] = value
def _filterPitchList(self, pitchTest): '''Given a list or one pitch, check if all are pitch objects; convert if necessary. ''' if not common.isListLike(pitchTest): if common.isStr(pitchTest): pitchTest = pitch.Pitch(pitchTest) pitchTest = [pitchTest] else: # convert a list of string into pitch objects temp = [] for p in pitchTest: if common.isStr(p): temp.append(pitch.Pitch(p)) if len(temp) == len(pitchTest): pitchTest = temp sortList = [(pitchTest[i].ps, i) for i in range(len(pitchTest))] sortList.sort() minPitch = pitchTest[sortList[0][1]] # first index maxPitch = pitchTest[sortList[-1][1]] # last index return pitchTest, minPitch, maxPitch
def warn(self, msg, header=None): '''To print a warning to the user, send a list of strings to this method. Similar to printDebug but even if debug is off. ''' if common.isStr(msg): msg = [msg] # make into a list if header == None: if msg[0] != self.modNameParent and self.modNameParent != None: msg = [self.modNameParent + ': WARNING:'] + msg else: msg = [header] + msg msg = common.formatStr(*msg) sys.stderr.write(msg)
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: 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( '%s is not an acceptable value for preference: %s' % (value, key)) # need to escape problematic characters for xml storage if common.isStr(value): value = 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
def printDebug(self, msg, statusLevel=common.DEBUG_USER): '''Format one or more data elements into string, and print it to stderr. The first arg can be a list of string; lists are concatenated with common.formatStr(). ''' if not common.isNum(statusLevel): raise EnvironmentException('bad statusLevel argument given: %s' % statusLevel) if self.__getitem__('debug') >= statusLevel: if common.isStr(msg): msg = [msg] # make into a list if msg[0] != self.modNameParent and self.modNameParent != None: msg = [self.modNameParent + ':'] + msg msg = common.formatStr(*msg) sys.stderr.write(msg)
def parseData(self, tnData): '''Open TinyNotation data from a string or list >>> tnData = ["E4 r f# g=lastG trip{b-8 a g} c", "3/4"] >>> c = ConverterTinyNotation() >>> s = c.parseData(tnData) ''' if common.isStr(tnData): tnStr = tnData tnTs = None else: # assume a 2 element sequence tnStr = tnData[0] tnTs = tnData[1] self.stream = tinyNotation.TinyNotationStream(tnStr, tnTs)
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: 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('%s is not an acceptable value for preference: %s' % (value, key)) # need to escape problematic characters for xml storage if common.isStr(value): value = 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
def warn(self, msg, header=None): ''' To print a warning to the user, send a list of strings to this method. Similar to printDebug but even if debug is off. ''' if common.isStr(msg): msg = [msg] # make into a list elif isinstance(msg, dict): msg = [repr(msg)] if header == None: if msg[0] != self.modNameParent and self.modNameParent != None: msg = [self.modNameParent + ': WARNING:'] + msg else: msg = [header] + msg msg = common.formatStr(*msg) sys.stderr.write(msg)
def load(self, value): '''Load values by string, datetime object, or Date object. >>> a = Date(year=1843, month=3, day=3) >>> b = Date() >>> b.load(a) >>> b.year 1843 ''' if isinstance(value, datetime.datetime): self.loadDatetime(value) elif common.isStr(value): self.loadStr(value) elif isinstance(value, Date): self.loadOther(value) else: raise MetadataException('cannot load data: %s' % value)
def parseData(self, strData, number=None): '''Get musedata from a string representation. ''' from music21 import musedata as musedataModule from music21.musedata import translate as musedataTranslate if common.isStr(strData): strDataList = [strData] else: strDataList = strData mdw = musedataModule.MuseDataWork() for strData in strDataList: mdw.addString(strData) musedataTranslate.museDataWorkToStreamScore(mdw, self.stream)
def load(self, value): r''' Load values by string, datetime object, or Date object: >>> a = metadata.Date(year=1843, month=3, day=3) >>> b = metadata.Date() >>> b.load(a) >>> b.year 1843 ''' if isinstance(value, datetime.datetime): self.loadDatetime(value) elif common.isStr(value): self.loadStr(value) elif isinstance(value, Date): self.loadOther(value) else: raise exceptions21.MetadataException('Cannot load data: %s' % value)
def ch1_basic_II_C(data, intervalShift): '''Function for C1, C2, C3, and C4 ''' from music21 import stream, common, chord ex = stream.Stream() for chunk in data: m = stream.Measure() for e in chunk: if common.isStr(e): n1 = note.Note(e) n1.quarterLength = 4 n2 = n1.transpose(intervalShift) m.append(chord.Chord([n1, n2])) # chord to show both else: m.append(e) m.timeSignature = m.bestTimeSignature() ex.append(m) return ex
def _createPartBundles(self): ''' Fill the _partBundles list with dictionaries, each dictionary defining a name (part id or supplied), a color, and list of Parts that match. ''' self._partBundles = [] if self._partGroups is not None: for d in self._partGroups: # a list of dictionaries name, pColor, matches = d['name'], d['color'], d['match'] sub = [] for p in self._score.parts: #environLocal.printDebug(['_createPartBundles: part.id', p.id]) # if matches is None, use group name if matches is None: matches = [name] for m in matches: # strings or instruments if common.isStr(m): if str(p.id).lower().find(m.lower()) >= 0: sub.append(p) break # TODO: match if m is Instrument class if sub == []: continue data = {'pGroupId':name, 'color':pColor, 'parts':sub} self._partBundles.append(data) else: # manually creates for p in self._score.parts: # store one or more Parts associated with an id data = {'pGroupId':p.id, 'color':'#666666', 'parts':[p]} self._partBundles.append(data) # create flat representation of all parts in a bundle for partBundle in self._partBundles: if len(partBundle['parts']) == 1: partBundle['parts.flat'] = partBundle['parts'][0].flat else: # align all parts and flatten # this takes a flat presentation of all parts s = stream.Stream() for p in partBundle['parts']: s.insert(0, p) partBundle['parts.flat'] = s.flat
def _setAccidental(self, value): ''' Adds an accidental to the Note, given as an Accidental object. Also alters the name of the note >>> from music21 import * >>> a = note.Note() >>> a.step = "D" >>> a.name 'D' >>> b = pitch.Accidental("sharp") >>> a.setAccidental(b) >>> a.name 'D#' ''' if common.isStr(value): accidental = pitch.Accidental(value) else: accidental = value self.pitch.accidental = accidental
def addLyric(self, text, lyricNumber = None): '''Adds a lyric, or an additional lyric, to a Note, Chord, or Rest's lyric list. If `lyricNumber` is not None, a specific line of lyric text can be set. >>> from music21 import * >>> n1 = note.Note() >>> n1.addLyric("hello") >>> n1.lyrics[0].text 'hello' >>> n1.lyrics[0].number 1 >>> # note that the option number specified gives the lyric number, not the list position >>> n1.addLyric("bye", 3) >>> n1.lyrics[1].text 'bye' >>> n1.lyrics[1].number 3 >>> # replace existing lyric >>> n1.addLyric("ciao", 3) >>> n1.lyrics[1].text 'ciao' >>> n1.lyrics[1].number 3 ''' if not common.isStr(text): text = str(text) if lyricNumber is None: maxLyrics = len(self.lyrics) + 1 self.lyrics.append(Lyric(text, maxLyrics)) else: foundLyric = False for thisLyric in self.lyrics: if thisLyric.number == lyricNumber: thisLyric.text = text foundLyric = True break if foundLyric is False: self.lyrics.append(Lyric(text, lyricNumber))
def __init__(self, content=None): Expression.__init__(self) # numerous properties are inherited from TextFormat text.TextFormat.__init__(self) # the text string to be displayed; not that line breaks # are given in the xml with this non-printing character: (#) if not common.isStr(content): self._content = str(content) else: self._content = content self._enclosure = None # numerous parameters are inherited from text.TextFormat self._positionDefaultX = None self._positionDefaultY = 20 # two staff lines above # these values provided for musicxml compatibility self._positionRelativeX = None self._positionRelativeY = None # this does not do anything if default y is defined self._positionPlacement = None
def load(self, value): r''' Load values by string, datetime object, or Date object: :: >>> from music21 import metadata >>> a = metadata.Date(year=1843, month=3, day=3) >>> b = metadata.Date() >>> b.load(a) >>> b.year 1843 ''' if isinstance(value, datetime.datetime): self.loadDatetime(value) elif common.isStr(value): self.loadStr(value) elif isinstance(value, Date): self.loadOther(value) else: raise exceptions21.MetadataException('Cannot load data: %s' % value)
def romanTextToStreamOpus(rtHandler, inputM21=None): '''Return either a Score object, or, if a multi-movement work is defined, an Opus object. ''' from music21 import stream if common.isStr(rtHandler): rtf = romanTextModule.RTFile() rtHandler = rtf.readstr(rtHandler) # return handler, processes tokens if rtHandler.definesMovements(): # create an opus if inputM21 == None: s = stream.Opus() else: s = inputM21 # copy the common header to each of the sub-handlers handlerBundles = rtHandler.splitByMovement(duplicateHeader=True) # see if we have header information for h in handlerBundles: #print h, len(h) # append to opus s.append(romanTextToStreamScore(h)) return s # an opus else: # create a Score return romanTextToStreamScore(rtHandler, inputM21=inputM21)
def romanTextToStreamScore(rtHandler, inputM21=None): '''The main processing module for single-movement RomanText works. Given a romanText handler or string, return or fill a Score Stream. ''' # accept a string directly; mostly for testing from music21 import romanText as romanTextModule if common.isStr(rtHandler): rtf = romanTextModule.RTFile() rtHandler = rtf.readstr(rtHandler) # return handler, processes tokens # this could be just a Stream, but b/c we are creating metadata, perhaps better to match presentation of other scores. from music21 import metadata from music21 import stream from music21 import note from music21 import meter from music21 import key from music21 import roman from music21 import tie if inputM21 == None: s = stream.Score() else: s = inputM21 # metadata can be first md = metadata.Metadata() s.insert(0, md) p = stream.Part() # ts indication are found in header, and also found elsewhere tsCurrent = meter.TimeSignature('4/4') # create default 4/4 tsSet = False # store if set to a measure lastMeasureToken = None lastMeasureNumber = 0 previousRn = None keySigCurrent = None keySigSet = True # set a keySignature foundAKeySignatureSoFar = False kCurrent, unused_prefixLyric = _getKeyAndPrefix('C') # default if none defined prefixLyric = '' repeatEndings = {} for t in rtHandler.tokens: try: # environLocal.printDebug(['token', t]) if t.isTitle(): md.title = t.data elif t.isWork(): md.alternativeTitle = t.data elif t.isPiece(): md.alternativeTitle = t.data elif t.isComposer(): md.composer = t.data elif t.isMovement(): md.movementNumber = t.data elif t.isTimeSignature(): tsCurrent = meter.TimeSignature(t.data) tsSet = False # environLocal.printDebug(['tsCurrent:', tsCurrent]) elif t.isKeySignature(): if t.data == "": keySigCurrent = key.KeySignature(0) elif t.data == "Bb": keySigCurrent = key.KeySignature(-1) else: pass # better to print a message # environLocal.printDebug(['still need to write a generic RomanText KeySignature routine. this is just temporary']) # raise RomanTextTranslateException("still need to write a generic RomanText KeySignature routine. this is just temporary") keySigSet = False # environLocal.printDebug(['keySigCurrent:', keySigCurrent]) foundAKeySignatureSoFar = True elif t.isMeasure(): # environLocal.printDebug(['handling measure token:', t]) if t.variantNumber is not None: # environLocal.printDebug(['skipping variant: %s' % t]) continue if t.variantLetter is not None: # environLocal.printDebug(['skipping variant: %s' % t]) continue # if this measure number is more than 1 greater than the last # defined measure number, and the previous chord is not None, # then fill with copies of the last-defined measure if ((t.number[0] > lastMeasureNumber + 1) and (previousRn is not None)): for i in range(lastMeasureNumber + 1, t.number[0]): mFill = stream.Measure() mFill.number = i newRn = copy.deepcopy(previousRn) newRn.lyric = "" # set to entire bar duration and tie newRn.duration = copy.deepcopy(tsCurrent.barDuration) if previousRn.tie is None: previousRn.tie = tie.Tie('start') else: previousRn.tie.type = 'continue' # set to stop for now; may extend on next iteration newRn.tie = tie.Tie('stop') previousRn = newRn mFill.append(newRn) appendMeasureToRepeatEndingsDict(lastMeasureToken, mFill, repeatEndings, i) p.append(mFill) lastMeasureNumber = t.number[0] - 1 lastMeasureToken = t # create a new measure or copy a past measure if len(t.number) == 1 and t.isCopyDefinition: # if not a range m, kCurrent = _copySingleMeasure(t, p, kCurrent) p.append(m) lastMeasureNumber = m.number lastMeasureToken = t romans = m.getElementsByClass(roman.RomanNumeral) if len(romans) > 0: previousRn = romans[-1] elif len(t.number) > 1: measures, kCurrent = _copyMultipleMeasures(t, p, kCurrent) p.append(measures) lastMeasureNumber = measures[-1].number lastMeasureToken = t romans = measures[-1].getElementsByClass(roman.RomanNumeral) if len(romans) > 0: previousRn = romans[-1] else: m = stream.Measure() m.number = t.number[0] appendMeasureToRepeatEndingsDict(t, m, repeatEndings) lastMeasureNumber = t.number[0] lastMeasureToken = t if not tsSet: m.timeSignature = tsCurrent tsSet = True # only set when changed if not keySigSet and keySigCurrent is not None: m.insert(0, keySigCurrent) keySigSet = True # only set when changed o = 0.0 # start offsets at zero previousChordInMeasure = None pivotChordPossible = False numberOfAtoms = len(t.atoms) setKeyChangeToken = False # first RomanNumeral object after a key change should have this set to True for i, a in enumerate(t.atoms): if isinstance(a, romanTextModule.RTKey) or \ ((foundAKeySignatureSoFar == False) and \ (isinstance(a, romanTextModule.RTAnalyticKey))): # found a change of Key+KeySignature or # just found a change of analysis but no keysignature so far # environLocal.printDebug(['handling key token:', a]) try: # this sets the key and the keysignature kCurrent, pl = _getKeyAndPrefix(a) prefixLyric += pl except: raise RomanTextTranslateException('cannot get key from %s in line %s' % (a.src, t.src)) # insert at beginning of measure if at beginning -- for things like pickups. if m.number < 2: m.insert(0, kCurrent) else: m.insert(o, kCurrent) foundAKeySignatureSoFar = True setKeyChangeToken = True elif isinstance(a, romanTextModule.RTKeySignature): try: # this sets the keysignature but not the prefix text thisSig = a.getKeySignature() except: raise RomanTextTranslateException('cannot get key from %s in line %s' % (a.src, t.src)) #insert at beginning of measure if at beginning -- for things like pickups. if m.number < 2: m.insert(0, thisSig) else: m.insert(o, thisSig) foundAKeySignatureSoFar = True elif isinstance(a, romanTextModule.RTAnalyticKey): # just a change in analyzed key, not a change in anything else #try: # this sets the key, not the keysignature kCurrent, pl = _getKeyAndPrefix(a) prefixLyric += pl setKeyChangeToken = True #except: # raise RomanTextTranslateException('cannot get key from %s in line %s' % (a.src, t.src)) elif isinstance(a, romanTextModule.RTBeat): # set new offset based on beat try: o = a.getOffset(tsCurrent) except ValueError: raise RomanTextTranslateException("cannot properly get an offset from beat data %s under timeSignature %s in line %s" % (a.src, tsCurrent, t.src)) if (previousChordInMeasure is None and previousRn is not None and o > 0): # setting a new beat before giving any chords firstChord = copy.deepcopy(previousRn) firstChord.quarterLength = o firstChord.lyric = "" if previousRn.tie == None: previousRn.tie = tie.Tie('start') else: previousRn.tie.type = 'continue' firstChord.tie = tie.Tie('stop') previousRn = firstChord previousChordInMeasure = firstChord m.insert(0, firstChord) pivotChordPossible = False elif isinstance(a, romanTextModule.RTNoChord): # use source to evaluation roman rn = note.Rest() if pivotChordPossible == False: # probably best to find duration if previousChordInMeasure is None: pass # use default duration else: # update duration of previous chord in Measure oPrevious = previousChordInMeasure.getOffsetBySite(m) newQL = o - oPrevious if newQL <= 0: raise RomanTextTranslateException('too many notes in this measure: %s' % t.src) previousChordInMeasure.quarterLength = newQL prefixLyric = "" m.insert(o, rn) previousChordInMeasure = rn previousRn = rn pivotChordPossible = False elif isinstance(a, romanTextModule.RTChord): # use source to evaluation roman try: asrc = a.src # if kCurrent.mode == 'minor': # if asrc.lower().startswith('vi'): #vi or vii w/ or w/o o # if asrc.upper() == a.src: # VI or VII to bVI or bVII # asrc = 'b' + asrc rn = roman.RomanNumeral(asrc, copy.deepcopy(kCurrent)) if setKeyChangeToken is True: rn.followsKeyChange = True setKeyChangeToken = False else: rn.followsKeyChange = False except (roman.RomanNumeralException, common.Music21CommonException): #environLocal.printDebug('cannot create RN from: %s' % a.src) rn = note.Note() # create placeholder if pivotChordPossible == False: # probably best to find duration if previousChordInMeasure is None: pass # use default duration else: # update duration of previous chord in Measure oPrevious = previousChordInMeasure.getOffsetBySite(m) newQL = o - oPrevious if newQL <= 0: raise RomanTextTranslateException('too many notes in this measure: %s' % t.src) previousChordInMeasure.quarterLength = newQL rn.addLyric(prefixLyric + a.src) prefixLyric = "" m.insert(o, rn) previousChordInMeasure = rn previousRn = rn pivotChordPossible = True else: previousChordInMeasure.lyric += "//" + prefixLyric + a.src previousChordInMeasure.pivotChord = rn prefixLyric = "" pivotChordPossible = False elif isinstance(a, romanTextModule.RTRepeat): if o == 0: if isinstance(a, romanTextModule.RTRepeatStart): m.leftBarline = bar.Repeat(direction='start') else: rtt = RomanTextUnprocessedToken(a) m.insert(o, rtt) elif tsCurrent is not None and (tsCurrent.barDuration.quarterLength == o or i == numberOfAtoms - 1): if isinstance(a, romanTextModule.RTRepeatStop): m.rightBarline = bar.Repeat(direction='end') else: rtt = RomanTextUnprocessedToken(a) m.insert(o, rtt) else: # mid measure repeat signs rtt = RomanTextUnprocessedToken(a) m.insert(o, rtt) else: rtt = RomanTextUnprocessedToken(a) m.insert(o, rtt) #environLocal.warn("Got an unknown token: %r" % a) # may need to adjust duration of last chord added if tsCurrent is not None: previousRn.quarterLength = tsCurrent.barDuration.quarterLength - o p.append(m) except Exception: import traceback tracebackMessage = traceback.format_exc() raise RomanTextTranslateException("At line %d for token %r, an exception was raised: \n%s" % (t.lineNumber, t, tracebackMessage)) fixPickupMeasure(p) p.makeBeams(inPlace=True) p.makeAccidentals(inPlace=True) _addRepeatsFromRepeatEndings(p, repeatEndings) # 1st and second endings... s.insert(0, p) return s
def getFrequenciesFromPartialAudioFile(waveFilenameOrHandle='temp', length=10.0, startSample=0): ''' It calculates the fundamental frequency at every instant of time of an audio signal extracted either from the microphone or from an already recorded song. It uses a period of time defined by the variable "length" in seconds. It returns a list with the frequencies, a variable with the file descriptor, and the end sample position. >>> #_DOCS_SHOW readFile = 'pachelbel.wav' >>> import os #_DOCS_HIDE >>> readFile = common.getSourceFilePath() + os.path.sep + 'audioSearch' + os.path.sep + 'test_audio.wav' #_DOCS_HIDE >>> frequencyList, pachelbelFileHandle, currentSample = audioSearch.getFrequenciesFromPartialAudioFile(readFile, length=1.0) >>> for i in range(5): ... print(frequencyList[i]) 143.627689055 99.0835452019 211.004784689 4700.31347962 767.827403482 >>> print(currentSample) # should be near 44100, but probably not exact 44032 Now read the next 1 second... >>> frequencyList, pachelbelFileHandle, currentSample = audioSearch.getFrequenciesFromPartialAudioFile(pachelbelFileHandle, length=1.0, startSample = currentSample) >>> for i in range(5): ... print(frequencyList[i]) 187.798213268 238.263483185 409.700397349 149.958733396 101.989786226 >>> print(currentSample) # should be exactly double the previous 88064 ''' if "numpy" in base._missingImport: raise AudioSearchException( "Cannot run getFrequenciesFromPartialAudioFile without numpy installed" ) import numpy if waveFilenameOrHandle == 'temp': waveFilenameOrHandle = environLocal.getRootTempDir( ) + os.path.sep + 'temp.wav' if common.isStr(waveFilenameOrHandle): # waveFilenameOrHandle is a filename waveFilename = waveFilenameOrHandle try: waveHandle = wave.open(waveFilename, 'r') except IOError: raise AudioSearchException( "Cannot open %s for reading, does not exist" % waveFilename) else: # waveFilenameOrHandle is a filehandle waveHandle = waveFilenameOrHandle storedWaveSampleList = [] environLocal.printDebug("* reading file from disk a part of the song") for i in range( int(math.floor(length * recordSampleRate / audioChunkLength))): startSample = startSample + audioChunkLength if startSample < waveHandle.getnframes(): data = waveHandle.readframes(audioChunkLength) storedWaveSampleList.append(data) freqFromAQList = [] for data in storedWaveSampleList: samps = numpy.fromstring(data, dtype=numpy.int16) freqFromAQList.append(autocorrelationFunction(samps, recordSampleRate)) endSample = startSample return (freqFromAQList, waveHandle, endSample)
def romanTextToStreamScore(rtHandler, inputM21=None): '''The main processing module for single-movement RomanText works. Given a romanText handler or string, return or fill a Score Stream. ''' # accept a string directly; mostly for testing if common.isStr(rtHandler): rtf = rtObjects.RTFile() rtHandler = rtf.readstr(rtHandler) # return handler, processes tokens # this could be just a Stream, but b/c we are creating metadata, perhaps better to match presentation of other scores. from music21 import metadata from music21 import stream from music21 import note from music21 import meter from music21 import key from music21 import roman from music21 import tie if inputM21 == None: s = stream.Score() else: s = inputM21 # metadata can be first md = metadata.Metadata() s.insert(0, md) p = stream.Part() # ts indication are found in header, and also found elsewhere tsCurrent = meter.TimeSignature('4/4') # create default 4/4 tsSet = False # store if set to a measure lastMeasureToken = None lastMeasureNumber = 0 previousRn = None keySigCurrent = None keySigSet = True # set a keySignature foundAKeySignatureSoFar = False kCurrent, unused_prefixLyric = _getKeyAndPrefix( 'C') # default if none defined prefixLyric = '' repeatEndings = {} rnKeyCache = {} for t in rtHandler.tokens: try: # environLocal.printDebug(['token', t]) if t.isTitle(): md.title = t.data elif t.isWork(): md.alternativeTitle = t.data elif t.isPiece(): md.alternativeTitle = t.data elif t.isComposer(): md.composer = t.data elif t.isMovement(): md.movementNumber = t.data elif t.isTimeSignature(): tsCurrent = meter.TimeSignature(t.data) tsSet = False # environLocal.printDebug(['tsCurrent:', tsCurrent]) elif t.isKeySignature(): if t.data == "": keySigCurrent = key.KeySignature(0) elif t.data == "Bb": keySigCurrent = key.KeySignature(-1) else: pass # better to print a message # environLocal.printDebug(['still need to write a generic RomanText KeySignature routine. this is just temporary']) # raise RomanTextTranslateException("still need to write a generic RomanText KeySignature routine. this is just temporary") keySigSet = False # environLocal.printDebug(['keySigCurrent:', keySigCurrent]) foundAKeySignatureSoFar = True elif t.isMeasure(): # environLocal.printDebug(['handling measure token:', t]) #if t.number[0] % 10 == 0: # print "at number " + str(t.number[0]) if t.variantNumber is not None: # environLocal.printDebug(['skipping variant: %s' % t]) continue if t.variantLetter is not None: # environLocal.printDebug(['skipping variant: %s' % t]) continue # if this measure number is more than 1 greater than the last # defined measure number, and the previous chord is not None, # then fill with copies of the last-defined measure if ((t.number[0] > lastMeasureNumber + 1) and (previousRn is not None)): for i in range(lastMeasureNumber + 1, t.number[0]): mFill = stream.Measure() mFill.number = i newRn = copy.deepcopy(previousRn) newRn.lyric = "" # set to entire bar duration and tie newRn.duration = copy.deepcopy(tsCurrent.barDuration) if previousRn.tie is None: previousRn.tie = tie.Tie('start') else: previousRn.tie.type = 'continue' # set to stop for now; may extend on next iteration newRn.tie = tie.Tie('stop') previousRn = newRn mFill.append(newRn) appendMeasureToRepeatEndingsDict( lastMeasureToken, mFill, repeatEndings, i) p._appendCore(mFill) lastMeasureNumber = t.number[0] - 1 lastMeasureToken = t # create a new measure or copy a past measure if len(t.number) == 1 and t.isCopyDefinition: # if not a range p.elementsChanged() m, kCurrent = _copySingleMeasure(t, p, kCurrent) p._appendCore(m) lastMeasureNumber = m.number lastMeasureToken = t romans = m.getElementsByClass(roman.RomanNumeral, returnStreamSubClass='list') if len(romans) > 0: previousRn = romans[-1] elif len(t.number) > 1: p.elementsChanged() measures, kCurrent = _copyMultipleMeasures(t, p, kCurrent) p.append(measures) # appendCore does not work with list lastMeasureNumber = measures[-1].number lastMeasureToken = t romans = measures[-1].getElementsByClass( roman.RomanNumeral, returnStreamSubClass='list') if len(romans) > 0: previousRn = romans[-1] else: m = stream.Measure() m.number = t.number[0] appendMeasureToRepeatEndingsDict(t, m, repeatEndings) lastMeasureNumber = t.number[0] lastMeasureToken = t if not tsSet: m.timeSignature = tsCurrent tsSet = True # only set when changed if not keySigSet and keySigCurrent is not None: m.insert(0, keySigCurrent) keySigSet = True # only set when changed o = 0.0 # start offsets at zero previousChordInMeasure = None pivotChordPossible = False numberOfAtoms = len(t.atoms) setKeyChangeToken = False # first RomanNumeral object after a key change should have this set to True for i, a in enumerate(t.atoms): if isinstance(a, rtObjects.RTKey) or \ ((foundAKeySignatureSoFar == False) and \ (isinstance(a, rtObjects.RTAnalyticKey))): # found a change of Key+KeySignature or # just found a change of analysis but no keysignature so far # environLocal.printDebug(['handling key token:', a]) try: # this sets the key and the keysignature kCurrent, pl = _getKeyAndPrefix(a) prefixLyric += pl except: raise RomanTextTranslateException( 'cannot get key from %s in line %s' % (a.src, t.src)) # insert at beginning of measure if at beginning -- for things like pickups. if m.number < 2: m._insertCore(0, kCurrent) else: m._insertCore(o, kCurrent) foundAKeySignatureSoFar = True setKeyChangeToken = True elif isinstance(a, rtObjects.RTKeySignature): try: # this sets the keysignature but not the prefix text thisSig = a.getKeySignature() except: raise RomanTextTranslateException( 'cannot get key from %s in line %s' % (a.src, t.src)) #insert at beginning of measure if at beginning -- for things like pickups. if m.number < 2: m._insertCore(0, thisSig) else: m._insertCore(o, thisSig) foundAKeySignatureSoFar = True elif isinstance(a, rtObjects.RTAnalyticKey): # just a change in analyzed key, not a change in anything else #try: # this sets the key, not the keysignature kCurrent, pl = _getKeyAndPrefix(a) prefixLyric += pl setKeyChangeToken = True #except: # raise RomanTextTranslateException('cannot get key from %s in line %s' % (a.src, t.src)) elif isinstance(a, rtObjects.RTBeat): # set new offset based on beat try: o = a.getOffset(tsCurrent) except ValueError: raise RomanTextTranslateException( "cannot properly get an offset from beat data %s under timeSignature %s in line %s" % (a.src, tsCurrent, t.src)) if (previousChordInMeasure is None and previousRn is not None and o > 0): # setting a new beat before giving any chords firstChord = copy.deepcopy(previousRn) firstChord.quarterLength = o firstChord.lyric = "" if previousRn.tie == None: previousRn.tie = tie.Tie('start') else: previousRn.tie.type = 'continue' firstChord.tie = tie.Tie('stop') previousRn = firstChord previousChordInMeasure = firstChord m._insertCore(0, firstChord) pivotChordPossible = False elif isinstance(a, rtObjects.RTNoChord): # use source to evaluation roman rn = note.Rest() if pivotChordPossible == False: # probably best to find duration if previousChordInMeasure is None: pass # use default duration else: # update duration of previous chord in Measure oPrevious = previousChordInMeasure.getOffsetBySite( m) newQL = o - oPrevious if newQL <= 0: raise RomanTextTranslateException( 'too many notes in this measure: %s' % t.src) previousChordInMeasure.quarterLength = newQL prefixLyric = "" m._insertCore(o, rn) previousChordInMeasure = rn previousRn = rn pivotChordPossible = False elif isinstance(a, rtObjects.RTChord): # use source to evaluation roman try: asrc = a.src # if kCurrent.mode == 'minor': # if asrc.lower().startswith('vi'): #vi or vii w/ or w/o o # if asrc.upper() == a.src: # VI or VII to bVI or bVII # asrc = 'b' + asrc cacheTuple = (asrc, kCurrent.tonicPitchNameWithCase) if USE_RN_CACHE and cacheTuple in rnKeyCache: #print "Got a match: " + str(cacheTuple) # Problems with Caches not picking up pivot chords... Not faster, see below. rn = copy.deepcopy(rnKeyCache[cacheTuple]) else: #print "No match for: " + str(cacheTuple) rn = roman.RomanNumeral( asrc, copy.deepcopy(kCurrent)) rnKeyCache[cacheTuple] = rn # surprisingly, not faster... and more dangerous #rn = roman.RomanNumeral(asrc, kCurrent) ## SLOWEST!!! #rn = roman.RomanNumeral(asrc, kCurrent.tonicPitchNameWithCase) #>>> from timeit import timeit as t #>>> t('roman.RomanNumeral("IV", "c#")', 'from music21 import roman', number=1000) #45.75 #>>> t('roman.RomanNumeral("IV", k)', 'from music21 import roman, key; k = key.Key("c#")', number=1000) #16.09 #>>> t('roman.RomanNumeral("IV", copy.deepcopy(k))', 'from music21 import roman, key; import copy; k = key.Key("c#")', number=1000) #22.49 ## key cache, does not help much... #>>> t('copy.deepcopy(r)', 'from music21 import roman; import copy; r = roman.RomanNumeral("IV", "c#")', number=1000) #19.01 if setKeyChangeToken is True: rn.followsKeyChange = True setKeyChangeToken = False else: rn.followsKeyChange = False except (roman.RomanNumeralException, common.Music21CommonException): #environLocal.printDebug('cannot create RN from: %s' % a.src) rn = note.Note() # create placeholder if pivotChordPossible == False: # probably best to find duration if previousChordInMeasure is None: pass # use default duration else: # update duration of previous chord in Measure oPrevious = previousChordInMeasure.getOffsetBySite( m) newQL = o - oPrevious if newQL <= 0: raise RomanTextTranslateException( 'too many notes in this measure: %s' % t.src) previousChordInMeasure.quarterLength = newQL rn.addLyric(prefixLyric + a.src) prefixLyric = "" m._insertCore(o, rn) previousChordInMeasure = rn previousRn = rn pivotChordPossible = True else: previousChordInMeasure.lyric += "//" + prefixLyric + a.src previousChordInMeasure.pivotChord = rn prefixLyric = "" pivotChordPossible = False elif isinstance(a, rtObjects.RTRepeat): if o == 0: if isinstance(a, rtObjects.RTRepeatStart): m.leftBarline = bar.Repeat( direction='start') else: rtt = RomanTextUnprocessedToken(a) m._insertCore(o, rtt) elif tsCurrent is not None and ( tsCurrent.barDuration.quarterLength == o or i == numberOfAtoms - 1): if isinstance(a, rtObjects.RTRepeatStop): m.rightBarline = bar.Repeat( direction='end') else: rtt = RomanTextUnprocessedToken(a) m._insertCore(o, rtt) else: # mid measure repeat signs rtt = RomanTextUnprocessedToken(a) m._insertCore(o, rtt) else: rtt = RomanTextUnprocessedToken(a) m._insertCore(o, rtt) #environLocal.warn("Got an unknown token: %r" % a) # may need to adjust duration of last chord added if tsCurrent is not None: previousRn.quarterLength = tsCurrent.barDuration.quarterLength - o m.elementsChanged() p._appendCore(m) except Exception: import traceback tracebackMessage = traceback.format_exc() raise RomanTextTranslateException( "At line %d for token %r, an exception was raised: \n%s" % (t.lineNumber, t, tracebackMessage)) p.elementsChanged() fixPickupMeasure(p) p.makeBeams(inPlace=True) p.makeAccidentals(inPlace=True) _addRepeatsFromRepeatEndings(p, repeatEndings) # 1st and second endings... s.insert(0, p) return s
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
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
def pitchToSharps(value, mode=None): '''Given a pitch or :class:`music21.pitch.Pitch` object, return the number of sharps found in that mode. The `mode` parameter can be 'major', 'minor', or most of the common church/jazz modes ('dorian', 'mixolydian', etc.) including Locrian. If `mode` is omitted or not found, the default mode is major. (extra points to anyone who can find the earliest reference to the Locrian mode in print. David Cohen and I (MSC) have been looking for this for years). >>> key.pitchToSharps('c') 0 >>> key.pitchToSharps('c', 'minor') -3 >>> key.pitchToSharps('a', 'minor') 0 >>> key.pitchToSharps('d') 2 >>> key.pitchToSharps('e-') -3 >>> key.pitchToSharps('a') 3 >>> key.pitchToSharps('e', 'minor') 1 >>> key.pitchToSharps('f#', 'major') 6 >>> key.pitchToSharps('g-', 'major') -6 >>> key.pitchToSharps('c#') 7 >>> key.pitchToSharps('g#') 8 >>> key.pitchToSharps('e', 'dorian') 2 >>> key.pitchToSharps('d', 'dorian') 0 >>> key.pitchToSharps('g', 'mixolydian') 0 >>> key.pitchToSharps('e-', 'lydian') -2 >>> key.pitchToSharps('e-', 'lydian') -2 >>> key.pitchToSharps('a', 'phrygian') -1 >>> key.pitchToSharps('e', 'phrygian') 0 >>> key.pitchToSharps('f#') 6 >>> key.pitchToSharps('f-') -8 >>> key.pitchToSharps('f--') -15 >>> key.pitchToSharps('f--', 'locrian') -20 But quarter tones don't work: >>> key.pitchToSharps('C~') Traceback (most recent call last): KeyException: Cannot determine sharps for quarter-tone keys! silly! ''' if common.isStr(value): value = pitch.Pitch(value) elif 'Pitch' in value.classes: value = value elif 'Note' in value.classes: value = value.pitch else: raise KeyException('Cannot get a sharp number from value') # the -1 is because we begin with F not C. sharps = fifthsOrder.index(value.step) - 1 if value.accidental is not None: if value.accidental.isTwelveTone() is False: raise KeyException( 'Cannot determine sharps for quarter-tone keys! silly!') vaa = int(value.accidental.alter) sharps = sharps + 7 * vaa if mode is not None and mode in modeSharpsAlter: sharps += modeSharpsAlter[mode] return sharps
def search(self, query, field=None): r''' Search one or all fields with a query, given either as a string or a regular expression match. >>> md = metadata.Metadata() >>> md.composer = 'Beethoven, Ludwig van' >>> md.title = 'Third Symphony' >>> md.search( ... 'beethoven', ... field='composer', ... ) (True, 'composer') Note how the incomplete field name in the following example is still matched: >>> md.search( ... 'beethoven', ... field='compose', ... ) (True, 'composer') >>> md.search( ... 'frank', ... field='composer', ... ) (False, None) >>> md.search('frank') (False, None) >>> md.search('third') (True, 'title') >>> md.search( ... 'third', ... field='composer', ... ) (False, None) >>> md.search( ... 'third', ... field='title', ... ) (True, 'title') >>> md.search('third|fourth') (True, 'title') >>> md.search('thove(.*)') (True, 'composer') ''' valueFieldPairs = [] if field is not None: match = False try: value = getattr(self, field) valueFieldPairs.append((value, field)) match = True except AttributeError: pass if not match: for searchAttribute in self._searchAttributes: #environLocal.printDebug(['comparing fields:', f, field]) # look for partial match in all fields if field.lower() in searchAttribute.lower(): value = getattr(self, searchAttribute) valueFieldPairs.append((value, searchAttribute)) match = True break # if cannot find a match for any field, return if not match: return False, None else: # get all fields for field in self._searchAttributes: value = getattr(self, field) valueFieldPairs.append((value, field)) # for now, make all queries strings # ultimately, can look for regular expressions by checking for # .search useRegex = False if hasattr(query, 'search'): useRegex = True reQuery = query # already compiled # look for regex characters elif common.isStr(query) and \ any(character in query for character in '*.|+?{}'): useRegex = True reQuery = re.compile(query, flags=re.I) if useRegex: for value, field in valueFieldPairs: # re.I makes case insensitive if common.isStr(value): match = reQuery.search(value) if match is not None: return True, field elif callable(query): for value, field in valueFieldPairs: if query(value): return True, field else: for value, field in valueFieldPairs: if common.isStr(value): query = str(query) if query.lower() in value.lower(): return True, field elif query == value: return True, field return False, None
def getObjByClass(self, className, serialReverseSearch=True, callerFirst=None, sortByCreationTime=False, prioritizeActiveSite=False, priorityTarget=None, getElementMethod='getElementAtOrBefore', memo=None): ''' Return the most recently added reference based on className. Class name can be a string or the class name. This will recursively search the sitesDicts of objects in Site objects in the siteDict. The `callerFirst` parameters is simply used to pass a reference of the first caller; this is necessary if we are looking within a Stream for a flat offset position. If `priorityTarget` is specified, this location will be searched first. The `prioritizeActiveSite` is pased to to any recursively called getContextByClass() calls. The `getElementMethod` is a string that selects which Stream method is used to get elements for searching with getElementsByClass() calls. :: >>> import music21 >>> class Mock(music21.Music21Object): ... pass ... >>> import time >>> aObj = Mock() >>> bObj = Mock() >>> aSites = music21.Sites() >>> aSites.add(aObj) >>> aSites.add(bObj) >>> # we get the most recently added object first >>> aSites.getObjByClass('Mock', sortByCreationTime=True) == bObj True :: >>> aSites.getObjByClass(Mock, sortByCreationTime=True) == bObj True OMIT_FROM_DOCS TODO: not sure if memo is properly working: need a test case ''' #if DEBUG_CONTEXT: print 'Y: first call' # in general, this should not be the first caller, as this method # is called from a Music21Object, not directly on the Sites # instance. Nonetheless, if this is the first caller, it is the first # caller. if callerFirst is None: # this is the first caller callerFirst = self # set Sites as caller first if memo is None: memo = {} # intialize post = None #count = 0 # search any defined contexts first # need to sort: look at most-recently added objs are first objs = self.get( locationsTrail=False, sortByCreationTime=sortByCreationTime, priorityTarget=priorityTarget, excludeNone=True, ) #printMemo(memo, 'getObjByClass() called: looking at %s sites' % len(objs)) classNameIsStr = common.isStr(className) for obj in objs: #environLocal.printDebug(['memo', memo]) if classNameIsStr: if className in obj.classes: post = obj break elif isinstance(obj, className): post = obj break if post is not None: return post # all objs here are containers, as they are all locations # if we could be sure that these objs do not have their own locations # and do not have the target class, we can skip for obj in objs: #if DEBUG_CONTEXT: print '\tY: getObjByClass: iterating objs:', id(obj), obj if (classNameIsStr and obj.isFlat): #if DEBUG_CONTEXT: print '\tY: skipping flat stream that does not contain object:', id(obj), obj #environLocal.printDebug(['\tY: skipping flat stream that does not contain object:']) if obj.sites.getSiteCount( ) == 0: # is top level; no more to search... if not obj.hasElementOfClass(className, forceFlat=True): continue # skip, not in this stream # if after trying to match name, look in the defined contexts' # defined contexts [sic!] #if post is None: # no match yet # access public method to recurse if id(obj) not in memo: # if the object is a Musci21Object #if hasattr(obj, 'getContextByClass'): # store this object as having been searched memo[id(obj)] = obj post = obj.getContextByClass( className, serialReverseSearch=serialReverseSearch, callerFirst=callerFirst, sortByCreationTime=sortByCreationTime, prioritizeActiveSite=prioritizeActiveSite, getElementMethod=getElementMethod, memo=memo) if post is not None: break # else: # this is not a music21 object # pass #environLocal.printDebug['cannot call getContextByClass on obj stored in DefinedContext:', obj] # else: # objec has already been searched # pass #environLocal.printDebug['skipping searching of object already searched:', obj] # else: # post is not None # break return post
def getAllByClass(self, className, found=None, idFound=None, memo=None): ''' Return all known references of a given class found in any association with this Sites object. This will recursively search the defined contexts of existing defined contexts, and return a list of all objects that match the given class. :: >>> import music21 >>> class Mock(music21.Music21Object): ... pass ... >>> class Mocker(music21.Music21Object): ... pass ... >>> aObj = Mock() >>> bObj = Mock() >>> cObj = Mocker() >>> dc = music21.Sites() >>> dc.add(aObj) >>> dc.add(bObj) >>> dc.add(cObj) >>> dc.getAllByClass(Mock) == [aObj, bObj] True ''' if memo is None: memo = {} # intialize if found is None: found = [] if idFound is None: idFound = [] objs = self.get(locationsTrail=False) for obj in objs: #environLocal.printDebug(['memo', memo]) if obj is None: continue # in case the reference is dead if common.isStr(className): if type(obj).__name__.lower() == className.lower(): found.append(obj) idFound.append(id(obj)) elif isinstance(obj, className): found.append(obj) idFound.append(id(obj)) for obj in objs: if obj is None: continue # in case the reference is dead # if after trying to match name, look in the defined contexts' # defined contexts [sic!] if id(obj) not in memo: # if the object is a Musci21Object #if hasattr(obj, 'getContextByClass'): # store this object as having been searched memo[id(obj)] = obj # will add values to found #environLocal.printDebug(['getAllByClass()', 'about to call getAllContextsByClass', 'found', found, 'obj', obj]) obj.getAllContextsByClass(className, found=found, idFound=idFound, memo=memo) # returning found, but not necessary return found
def _setContent(self, value): if not common.isStr(value): self._content = str(value) else: self._content = value
def samplesFromRecording(seconds=10.0, storeFile=True, recordFormat=None, recordChannels=recordChannels, recordSampleRate=recordSampleRate, recordChunkLength=1024): ''' records `seconds` length of sound in the given format (default Wave) and optionally stores it to disk using the filename of `storeFile` Returns a list of samples. ''' try: import pyaudio #@UnresolvedImport recordFormatDefault = pyaudio.paInt16 except (ImportError, SystemExit): pyaudio = None environLocal.warn( "No Pyaudio found. Recording will probably not work.") recordFormatDefault = 8 # pyaudio.paInt16 if recordFormat is None: recordFormat = recordFormatDefault if recordFormat == pyaudio.paInt8: raise RecordingException( "cannot perform freq_from_autocorr on 8-bit samples") p_audio = pyaudio.PyAudio() st = p_audio.open(format=recordFormat, channels=recordChannels, rate=recordSampleRate, input=True, frames_per_buffer=recordChunkLength) recordingLength = int(recordSampleRate * float(seconds) / recordChunkLength) storedWaveSampleList = [] #time_start = time.time() for i in range(recordingLength): data = st.read(recordChunkLength) storedWaveSampleList.append(data) #print 'Time elapsed: %.3f s\n' % (time.time() - time_start) st.close() p_audio.terminate() if storeFile != False: if common.isStr(storeFile): waveFilename = storeFile else: waveFilename = environLocal.getRootTempDir( ) + os.path.sep + 'recordingTemp.wav' ### write recording to disk data = ''.join(storedWaveSampleList) try: wf = wave.open(waveFilename, 'wb') wf.setnchannels(recordChannels) wf.setsampwidth(p_audio.get_sample_size(recordFormat)) wf.setframerate(recordSampleRate) wf.writeframes(data) wf.close() except IOError: raise RecordingException("Cannot open %s for writing." % waveFilename) return storedWaveSampleList