def generateRandomRealization(self): ''' Generates a random realization of a figured bass as a :class:`~music21.stream.Score`, with the default rules set **and** a soprano line limited to stepwise motion. .. note:: Deprecated. Use :meth:`~music21.figuredBass.realizer.FiguredBassLine.realize` which returns a :class:`~music21.figuredBass.realizer.Realization`. Then, call :meth:`~music21.figuredBass.realizer.Realization.generateRandomRealization`. ''' fbRules = rules.Rules() fbRules.partMovementLimits = [(1, 2), (2, 12), (3, 12)] return self.realize(fbRules).generateRandomRealization()
def singlePossibilityRules(self, fbRules=None): ''' A framework for storing single possibility rules and methods to be applied in :meth:`~music21.figuredBass.segment.Segment.allCorrectSinglePossibilities`. Takes in a :class:`~music21.figuredBass.rules.Rules` object, fbRules. If None then a new rules object is created. Items are added within this method in the following form: (willRunOnlyIfTrue, methodToRun, keepSolnsWhichReturn, optionalArgs) These items are compiled internally when :meth:`~music21.figuredBass.segment.Segment.allCorrectSinglePossibilities` is called on a Segment. Here, the compilation of rules and methods bases on a default fbRules is shown. >>> from music21.figuredBass import segment >>> segmentA = segment.Segment() >>> allSingleRules = segmentA.singlePossibilityRules() >>> segment.printRules(allSingleRules) Will run: Method: Keep solutions which return: Arguments: True isIncomplete False ['C', 'E', 'G'] True upperPartsWithinLimit True 12 True voiceCrossing False None Here, a modified fbRules is provided, which allows for incomplete possibilities. >>> from music21.figuredBass import rules >>> fbRules = rules.Rules() >>> fbRules.forbidIncompletePossibilities = False >>> allSingleRules = segmentA.singlePossibilityRules(fbRules) >>> segment.printRules(allSingleRules) Will run: Method: Keep solutions which return: Arguments: False isIncomplete False ['C', 'E', 'G'] True upperPartsWithinLimit True 12 True voiceCrossing False None ''' if fbRules is None: fbRules = rules.Rules() singlePossibRules = [ (fbRules.forbidIncompletePossibilities, possibility.isIncomplete, False, [self.pitchNamesInChord]), (True, possibility.upperPartsWithinLimit, True, [fbRules.upperPartsMaxSemitoneSeparation]), (fbRules.forbidVoiceCrossing, possibility.voiceCrossing, False) ] return singlePossibRules
def retrieveSegments(self, fbRules=None, numParts=4, maxPitch=None): ''' generates the segmentList from an fbList, including any overlaid Segments if fbRules is None, creates a new rules.Rules() object if maxPitch is None, uses pitch.Pitch('B5') ''' if fbRules is None: fbRules = rules.Rules() if maxPitch is None: maxPitch = pitch.Pitch('B5') segmentList = [] bassLine = self.generateBassLine() if len(self._overlaidParts) >= 1: self._overlaidParts.append(bassLine) currentMapping = checker.extractHarmonies(self._overlaidParts) else: currentMapping = checker.createOffsetMapping(bassLine) allKeys = sorted(currentMapping.keys()) bassLine = bassLine.flatten().notes bassNoteIndex = 0 previousBassNote = bassLine[bassNoteIndex] bassNote = currentMapping[allKeys[0]][-1] previousSegment = segment.OverlaidSegment( bassNote, bassNote.editorial.notationString, self._fbScale, fbRules, numParts, maxPitch) previousSegment.quarterLength = previousBassNote.quarterLength segmentList.append(previousSegment) for k in allKeys[1:]: (startTime, unused_endTime) = k bassNote = currentMapping[k][-1] currentSegment = segment.OverlaidSegment( bassNote, bassNote.editorial.notationString, self._fbScale, fbRules, numParts, maxPitch) for partNumber in range(1, len(currentMapping[k])): upperPitch = currentMapping[k][partNumber - 1] currentSegment.fbRules._partPitchLimits.append( (partNumber, upperPitch)) if startTime == previousBassNote.offset + previousBassNote.quarterLength: bassNoteIndex += 1 previousBassNote = bassLine[bassNoteIndex] currentSegment.quarterLength = previousBassNote.quarterLength else: for partNumber in range(len(currentMapping[k]), numParts + 1): previousSegment.fbRules._partsToCheck.append(partNumber) # Fictitious, representative only for harmonies preserved # with addition of melody or melodies currentSegment.quarterLength = 0.0 segmentList.append(currentSegment) previousSegment = currentSegment return segmentList
def showRandomRealization(self): ''' Displays a random realization of a figured bass as a musicxml in external software, with the default rules set **and** a soprano line limited to stepwise motion. .. note:: Deprecated. Use :meth:`~music21.figuredBass.realizer.FiguredBassLine.realize` which returns a :class:`~music21.figuredBass.realizer.Realization`. Then, call :meth:`~music21.figuredBass.realizer.Realization.generateRandomRealization` followed by a call to :meth:`~music21.base.Music21Object.show`. ''' fbRules = rules.Rules() fbRules.partMovementLimits = [(1, 2), (2, 12), (3, 12)] return self.realize(fbRules).generateRandomRealization().show()
def generateTripletBlues(blRealization=None, numRepeats=5): # 12/8 ''' Turns whole notes in twelve bar blues bass line to triplet blues bass line. Takes in numRepeats, which is the number of times to repeat the bass line. Also, takes in a realization of :meth:`~music21.figuredBass.examples.twelveBarBlues`. If none is provided, a default realization with :attr:`~music21.figuredBass.rules.Rules.forbidVoiceOverlap` set to False and :attr:`~music21.figuredBass.rules.Rules.partMovementLimits` set to [(1, 4), (2, 12), (3, 12)] is used. >>> from music21.figuredBass import examples >>> #_DOCS_SHOW examples.generateTripletBlues(numRepeats=1).show() .. image:: images/figuredBass/fbExamples_tripletBlues.* :width: 700 ''' from music21 import converter from music21 import stream from music21 import interval from music21 import meter if blRealization is None: bluesLine = twelveBarBlues() fbRules = rules.Rules() fbRules.partMovementLimits = [(1, 4), (2, 12), (3, 12)] fbRules.forbidVoiceOverlap = False blRealization = bluesLine.realize(fbRules) sampleScore = blRealization.generateRandomRealizations(numRepeats) tripletBassLine = converter.parse( "tinynotation: BB-4 BB-8 D4 D8 F4 F8 A-8 G8 F8", makeNotation=False) newBassLine = stream.Part() for n in sampleScore[1].notes: i = interval.notesToInterval(tripletBassLine[0], n) tp = tripletBassLine.transpose(i) for lyr in n.lyrics: tp.notes.first().addLyric(lyr.text) for m in tp.notes: newBassLine.append(m) newTopLine = stream.Part() for sampleChord in sampleScore[0].notes: sampleChordCopy = copy.deepcopy(sampleChord) sampleChordCopy.quarterLength = 6.0 newTopLine.append(sampleChordCopy) newScore = stream.Score() newScore.append(meter.TimeSignature("12/8")) # Time signature newScore.append(sampleScore[1][1]) # Key signature newScore.insert(0, newTopLine) newScore.insert(0, newBassLine) return newScore
def generateRandomRealization(self): ''' Generates a random realization of a figured bass as a :class:`~music21.stream.Score`, with the default rules set **and** a soprano line limited to stepwise motion. .. note:: Deprecated. Use :meth:`~music21.figuredBass.realizer.FiguredBassLine.realize` which returns a :class:`~music21.figuredBass.realizer.Realization`. Then, call :meth:`~music21.figuredBass.realizer.Realization.generateRandomRealization`. ''' _environRules = environment.Environment(_MOD) _environRules.warn( "The method generateRandomRealization() is deprecated. Use realize() instead and call generateRandomRealization() on the result.", DeprecationWarning) fbRules = rules.Rules() fbRules.partMovementLimits = [(1, 2), (2, 12), (3, 12)] return self.realize(fbRules).generateRandomRealization()
def generateBoogieVamp(blRealization=None, numRepeats=5): ''' Turns whole notes in twelve bar blues bass line to blues boogie woogie bass line. Takes in numRepeats, which is the number of times to repeat the bass line. Also, takes in a realization of :meth:`~music21.figuredBass.examples.twelveBarBlues`. If none is provided, a default realization with :attr:`~music21.figuredBass.rules.Rules.forbidVoiceOverlap` set to False and :attr:`~music21.figuredBass.rules.Rules.partMovementLimits` set to [(1, 4), (2, 12), (3, 12)] is used. >>> from music21.figuredBass import examples >>> #_DOCS_SHOW examples.generateBoogieVamp(numRepeats=1).show() .. image:: images/figuredBass/fbExamples_boogieVamp.* :width: 700 ''' from music21 import converter from music21 import stream from music21 import interval if blRealization is None: bluesLine = twelveBarBlues() fbRules = rules.Rules() fbRules.partMovementLimits = [(1, 4), (2, 12), (3, 12)] fbRules.forbidVoiceOverlap = False blRealization = bluesLine.realize(fbRules) sampleScore = blRealization.generateRandomRealizations(numRepeats) boogieBassLine = converter.parse( "tinynotation: BB-8. D16 F8. G16 A-8. G16 F8. D16", makeNotation=False) newBassLine = stream.Part() newBassLine.append(sampleScore[1][0]) # Time signature newBassLine.append(sampleScore[1][1]) # Key signature for n in sampleScore[1].notes: i = interval.notesToInterval(boogieBassLine[0], n) tp = boogieBassLine.transpose(i) for lyr in n.lyrics: tp.notes.first().addLyric(lyr.text) for m in tp.notes: newBassLine.append(m) newScore = stream.Score() newScore.insert(0, sampleScore[0]) newScore.insert(newBassLine) return newScore
def showAllRealizations(self): ''' Displays all realizations of a figured bass as a musicxml in external software, with the default rules set **and** a soprano line limited to stepwise motion. .. note:: Deprecated. Use :meth:`~music21.figuredBass.realizer.FiguredBassLine.realize` which returns a :class:`~music21.figuredBass.realizer.Realization`. Then, call :meth:`~music21.figuredBass.realizer.Realization.generateAllRealizations` followed by a call to :meth:`~music21.base.Music21Object.show`. .. warning:: This method is unoptimized, and may take a prohibitive amount of time for a Realization which has more than tens of unique realizations. ''' fbRules = rules.Rules() fbRules.partMovementLimits = [(1, 2), (2, 12), (3, 12)] return self.realize(fbRules).generateAllRealizations().show()
def realize(self, fbRules=None, numParts=4, maxPitch=None): ''' Creates a :class:`~music21.figuredBass.segment.Segment` for each (bassNote, notationString) pair added using :meth:`~music21.figuredBass.realizer.FiguredBassLine.addElement`. Each Segment is associated with the :class:`~music21.figuredBass.rules.Rules` object provided, meaning that rules are universally applied across all Segments. The number of parts in a realization (including the bass) can be controlled through numParts, and the maximum pitch can likewise be controlled through maxPitch. Returns a :class:`~music21.figuredBass.realizer.Realization`. If this methods is called without having provided any (bassNote, notationString) pairs, a FiguredBassLineException is raised. If only one pair is provided, the Realization will contain :meth:`~music21.figuredBass.segment.Segment.allCorrectConsecutivePossibilities` for the one note. if `fbRules` is None, creates a new rules.Rules() object if `maxPitch` is None, uses pitch.Pitch('B5') >>> from music21.figuredBass import realizer >>> from music21.figuredBass import rules >>> from music21 import key >>> from music21 import meter >>> from music21 import note >>> fbLine = realizer.FiguredBassLine(key.Key('B'), meter.TimeSignature('3/4')) >>> fbLine.addElement(note.Note('B2')) >>> fbLine.addElement(note.Note('C#3'), "6") >>> fbLine.addElement(note.Note('D#3'), "6") >>> fbRules = rules.Rules() >>> r1 = fbLine.realize(fbRules) >>> r1.getNumSolutions() 208 >>> fbRules.forbidVoiceOverlap = False >>> r2 = fbLine.realize(fbRules) >>> r2.getNumSolutions() 7908 OMIT_FROM_DOCS >>> fbLine3 = realizer.FiguredBassLine(key.Key('C'), meter.TimeSignature('2/4')) >>> h1 = harmony.ChordSymbol('C') >>> h1.bass().octave = 4 >>> fbLine3.addElement(h1) >>> h2 = harmony.ChordSymbol('G') >>> h2.bass().octave = 4 >>> fbLine3.addElement(h2) >>> r3 = fbLine3.realize() >>> r3.getNumSolutions() 13 >>> fbLine4 = realizer.FiguredBassLine(key.Key('C'), meter.TimeSignature('2/4')) >>> fbLine4.addElement(roman.RomanNumeral('I')) >>> fbLine4.addElement(roman.RomanNumeral('IV')) >>> r4 = fbLine4.realize() >>> r4.getNumSolutions() 13 ''' if fbRules is None: fbRules = rules.Rules() if maxPitch is None: maxPitch = pitch.Pitch('B5') segmentList = [] listOfHarmonyObjects = False for item in self._fbList: try: c = item.classes except AttributeError: continue if 'Note' in c: break #!---------- Added to accommodate harmony.ChordSymbol and roman.RomanNumeral objects --------! if 'RomanNumeral' in c or 'ChordSymbol' in c: #and item.isClassOrSubclass(harmony.Harmony): listOfHarmonyObjects = True break if listOfHarmonyObjects: for harmonyObject in self._fbList: listofpitchesjustnames = [] for thisPitch in harmonyObject.pitches: listofpitchesjustnames.append(thisPitch.name) #remove duplicates just in case... d = {} for x in listofpitchesjustnames: d[x] = x outputList = d.values() g = lambda x: x if x != 0.0 else 1.0 passedNote = note.Note( harmonyObject.bass().nameWithOctave, quarterLength=g(harmonyObject.duration.quarterLength)) correspondingSegment = segment.Segment(bassNote=passedNote, \ fbScale=self._fbScale, fbRules=fbRules, numParts=numParts, maxPitch=maxPitch, listOfPitches=outputList) correspondingSegment.quarterLength = g( harmonyObject.duration.quarterLength) segmentList.append(correspondingSegment) #!---------- Original code - Accommodates a tuple (figured bass) --------! else: segmentList = self.retrieveSegments(fbRules, numParts, maxPitch) if len(segmentList) >= 2: for segmentIndex in range(len(segmentList) - 1): segmentA = segmentList[segmentIndex] segmentB = segmentList[segmentIndex + 1] correctAB = segmentA.allCorrectConsecutivePossibilities( segmentB) segmentA.movements = collections.defaultdict(list) listAB = list(correctAB) for (possibA, possibB) in listAB: segmentA.movements[possibA].append(possibB) self._trimAllMovements(segmentList) elif len(segmentList) == 1: segmentA = segmentList[0] segmentA.correctA = list(segmentA.allCorrectSinglePossibilities()) elif len(segmentList) == 0: raise FiguredBassLineException( "No (bassNote, notationString) pairs to realize.") return Realization(realizedSegmentList=segmentList, inKey=self.inKey, inTime=self.inTime, overlayedParts=self._overlayedParts[0:-1], paddingLeft=self._paddingLeft)
def generateBaroqueRules(): fbRules = rules.Rules() return fbRules
def __init__(self, bassNote='C3', notationString=None, fbScale=None, fbRules=None, 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: if _defaultRealizerScale['scale'] is None: _defaultRealizerScale[ 'scale'] = realizerScale.FiguredBassScale() fbScale = _defaultRealizerScale['scale'] # save making it if fbRules is None: self.fbRules = rules.Rules() else: self.fbRules = copy.deepcopy(fbRules) self._specialResolutionRuleChecking = None self._singlePossibilityRuleChecking = None self._consecutivePossibilityRuleChecking = None self.bassNote = bassNote self.numParts = numParts self._maxPitch = maxPitch if notationString == None and listOfPitches != None: #must be a chord symbol or roman num. 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 specialResolutionRules(self, fbRules=None): ''' A framework for storing methods which perform special resolutions on Segments. Unlike the methods in :meth:`~music21.figuredBass.segment.Segment.singlePossibilityRules` and :meth:`~music21.figuredBass.segment.Segment.consecutivePossibilityRules`, these methods deal with the Segment itself, and rely on submethods to resolve the individual possibilities accordingly depending on what the resolution Segment is. If fbRules is None, then a new rules.Rules() object is created. Items are added within this method in the following form: (willRunOnlyIfTrue, methodToRun, optionalArgs) These items are compiled internally when :meth:`~music21.figuredBass.segment.Segment.allCorrectConsecutivePossibilities` is called on a Segment. Here, the compilation of rules and methods based on a default fbRules is shown. >>> from music21.figuredBass import segment >>> segmentA = segment.Segment() >>> allSpecialResRules = segmentA.specialResolutionRules() >>> segment.printRules(allSpecialResRules, maxLength = 3) Will run: Method: Arguments: False resolveDominantSeventhSegment None False resolveDiminishedSeventhSegment False False resolveAugmentedSixthSegment None Dominant Seventh Segment: >>> from music21 import note >>> segmentA = segment.Segment(bassNote = note.Note('B2'), notationString = "6,5") >>> allSpecialResRules = segmentA.specialResolutionRules() >>> segment.printRules(allSpecialResRules, maxLength = 3) Will run: Method: Arguments: True resolveDominantSeventhSegment None False resolveDiminishedSeventhSegment False False resolveAugmentedSixthSegment None Fully-Diminished Seventh Segment: >>> segmentA = segment.Segment(bassNote = note.Note('B2'), notationString = "-7") >>> allSpecialResRules = segmentA.specialResolutionRules() >>> segment.printRules(allSpecialResRules, maxLength = 3) Will run: Method: Arguments: False resolveDominantSeventhSegment None True resolveDiminishedSeventhSegment False False resolveAugmentedSixthSegment None Augmented Sixth Segment: >>> segmentA = segment.Segment(bassNote = note.Note('A-2'), notationString = "#6,b5") >>> allSpecialResRules = segmentA.specialResolutionRules() >>> segment.printRules(allSpecialResRules, maxLength = 3) Will run: Method: Arguments: False resolveDominantSeventhSegment None False resolveDiminishedSeventhSegment False True resolveAugmentedSixthSegment None ''' if fbRules is None: fbRules = rules.Rules() isDominantSeventh = self.segmentChord.isDominantSeventh() isDiminishedSeventh = self.segmentChord.isDiminishedSeventh() isAugmentedSixth = self.segmentChord.isAugmentedSixth() specialResRules = [ (fbRules.resolveDominantSeventhProperly and isDominantSeventh, self.resolveDominantSeventhSegment), (fbRules.resolveDiminishedSeventhProperly and isDiminishedSeventh, self.resolveDiminishedSeventhSegment, [fbRules.doubledRootInDim7]), (fbRules.resolveAugmentedSixthProperly and isAugmentedSixth, self.resolveAugmentedSixthSegment) ] return specialResRules
def consecutivePossibilityRules(self, fbRules=None): ''' A framework for storing consecutive possibility rules and methods to be applied in :meth:`~music21.figuredBass.segment.Segment.allCorrectConsecutivePossibilities`. Takes in a :class:`~music21.figuredBass.rules.Rules` object, fbRules; if None then a new rules.Rules() object is created. Items are added within this method in the following form: (willRunOnlyIfTrue, methodToRun, keepSolnsWhichReturn, optionalArgs) These items are compiled internally when :meth:`~music21.figuredBass.segment.Segment.allCorrectConsecutivePossibilities` is called on a Segment. Here, the compilation of rules and methods bases on a default fbRules is shown. >>> from music21.figuredBass import segment >>> segmentA = segment.Segment() >>> allConsecRules = segmentA.consecutivePossibilityRules() >>> segment.printRules(allConsecRules) Will run: Method: Keep solutions which return: Arguments: True partsSame True [] False upperPartsSame True None True voiceOverlap False None True partMovementsWithinLimits True [] True parallelFifths False None True parallelOctaves False None True hiddenFifth False None True hiddenOctave False None False couldBeItalianA6Resolution True [<music21.pitch.Pitch C3>, <music21.pitch.Pitch C3>, <music21.pitch.Pitch E3>, <music21.pitch.Pitch G3>], True Now, a modified fbRules is provided, allowing hidden octaves and voice overlap, and limiting the soprano line to stepwise motion. >>> from music21.figuredBass import rules >>> fbRules = rules.Rules() >>> fbRules.forbidVoiceOverlap = False >>> fbRules.forbidHiddenOctaves = False >>> fbRules.partMovementLimits.append((1,2)) >>> allConsecRules = segmentA.consecutivePossibilityRules(fbRules) >>> segment.printRules(allConsecRules) Will run: Method: Keep solutions which return: Arguments: True partsSame True [] False upperPartsSame True None False voiceOverlap False None True partMovementsWithinLimits True [(1, 2)] True parallelFifths False None True parallelOctaves False None True hiddenFifth False None False hiddenOctave False None False couldBeItalianA6Resolution True [<music21.pitch.Pitch C3>, <music21.pitch.Pitch C3>, <music21.pitch.Pitch E3>, <music21.pitch.Pitch G3>], True ''' if fbRules is None: fbRules = rules.Rules() isItalianAugmentedSixth = self.segmentChord.isItalianAugmentedSixth() consecPossibRules = [ (True, possibility.partsSame, True, [fbRules._partsToCheck]), (fbRules._upperPartsRemainSame, possibility.upperPartsSame, True), (fbRules.forbidVoiceOverlap, possibility.voiceOverlap, False), (True, possibility.partMovementsWithinLimits, True, [fbRules.partMovementLimits]), (fbRules.forbidParallelFifths, possibility.parallelFifths, False), (fbRules.forbidParallelOctaves, possibility.parallelOctaves, False), (fbRules.forbidHiddenFifths, possibility.hiddenFifth, False), (fbRules.forbidHiddenOctaves, possibility.hiddenOctave, False), (fbRules.resolveAugmentedSixthProperly and isItalianAugmentedSixth, possibility.couldBeItalianA6Resolution, True, [ _unpackTriad(self.segmentChord), fbRules.restrictDoublingsInItalianA6Resolution ]) ] return consecPossibRules