def getKey(self): ''' This returns a Key, not a KeySignature object ''' myKey = self.src.rstrip(self.footerStrip) myKey = key.convertKeyStringToMusic21KeyString(myKey) return key.Key(myKey)
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 getKey(self): ''' This returns a Key, not a KeySignature object ''' myKey = self.src.rstrip(self.footerStrip) myKey = key.convertKeyStringToMusic21KeyString(myKey) return key.Key(myKey)
def homeKeySig(self): ''' gets the initial, or 'home', key signature by looking at the musictext and locating the key signature at the start of the S: rule. >>> s = romanText.clercqTemperley.CTSong(romanText.clercqTemperley.textString) >>> s.homeKeySig <music21.key.Key of A major> ''' #look at 'S' Rule and grab the home key Signature if self.text and 'S:' in self.text: lines = self.text.split('\n') for line in lines: if line.startswith('S:'): for atom in line.split()[1:3]: if '[' not in atom: self._homeKeySig = key.Key('C') return self._homeKeySig elif not '/' in atom: m21keyStr = key.convertKeyStringToMusic21KeyString(atom[1:-1]) self._homeKeySig = key.Key(m21keyStr) return self._homeKeySig else: pass return self._homeKeySig
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 mixed_sequences(data_path, output_path): for (number, filename) in enumerate(os.listdir(data_path), start=1): try: full_path = os.path.join(data_path, filename) LOG.debug("Finding mixed sequences in piece {number}: {filename}.".format(**locals())) piece = parse(full_path) temp_abspath = os.path.join(output_path, TEMP_MIDI_NAME) piece.write('midi', temp_abspath) chord_per_measure = temperley.chord_per_measure(piece, temp_abspath) keys = temperley.key_sequence(temp_abspath) if len(set(keys)) > 1: continue # more than one key in piece is complicated... else: key_string = convertKeyStringToMusic21KeyString(keys[0].replace('b','-')) key = Key() key_pitch = key.getPitches()[0] instrument = lambda x: x.getInstrument().instrumentName.lower() guitar_parts = (e for e in piece if isinstance (e, Part) and \ ('guitar' in instrument(e) or \ 'gtr' in instrument(e)) and not \ 'bass' in instrument(e)) for part in guitar_parts: current_sequence = None last_note = None measures = [elem for elem in part if isinstance(elem, Measure)] if len(chord_per_measure) != len(measures): continue for chord, measure in zip(chord_per_measure, measures): chord_pitch = music21.pitch.Pitch(convertKeyStringToMusic21KeyString(chord)) for element in measure: if isinstance(element, Note): if not last_note: current_sequence = [(0, 0, notesToChromatic(key_pitch, element).semitones, key.mode, notesToChromatic(key_pitch, chord_pitch).semitones)] else: interval = notesToChromatic(last_note, element) entry = (current_sequence[-1][1], interval.semitones, notesToChromatic(key_pitch, element).semitones, key.mode, notesToChromatic(key_pitch, chord_pitch).semitones) current_sequence.append(entry) last_note = element elif isinstance(element, Rest) and element.quarterLength < 4: pass elif current_sequence: yield current_sequence current_sequence = None last_note = None except Exception: LOG.warning('Encountered exception in {filename}'.format(**locals()))
def _getHomeKeySig(self): #look at 'S' Rule and grab the home key Signature if self.text and 'S:' in self.text: lines = self.text.split('\n') for line in lines: if line.startswith('S:'): for atom in line.split()[1:3]: if '[' not in atom: self._homeKeySig = key.Key('C') return self._homeKeySig elif not '/' in atom: m21keyStr = key.convertKeyStringToMusic21KeyString(atom[1:-1]) self._homeKeySig = key.Key(m21keyStr) return self._homeKeySig else: pass return self._homeKeySig
def _getHomeKeySig(self): #look at 'S' Rule and grab the home key Signature if self.text and 'S:' in self.text: lines = self.text.split('\n') for line in lines: if line.startswith('S:'): for atom in line.split()[1:3]: if '[' not in atom: self._homeKeySig = key.Key('C') return self._homeKeySig elif not '/' in atom: m21keyStr = key.convertKeyStringToMusic21KeyString( atom[1:-1]) self._homeKeySig = key.Key(m21keyStr) return self._homeKeySig else: pass return self._homeKeySig
def expand(self, ts=None, ks=None): ''' The meat of it all -- expand one rule completely and return a list of Measure objects. ''' if ts is None: ts = meter.TimeSignature('4/4') if ks is None: ks = key.Key('C') measures = [] lastRegularAtom = None lastChord = None for content, sep, numReps in self._measureGroups(): lastChordIsInSameMeasure = False if sep == "$": if content not in self.parent.rules: raise CTRuleException( "Cannot expand rule {0} in {2}".format(content, self)) rule = self.parent.rules[content] for i in range(numReps): returnedMeasures = rule.expand(ts, ks) self.insertKsTs(returnedMeasures[0], ts, ks) for m in returnedMeasures: tsEs = m.iter.getElementsByClass('TimeSignature') for returnedTs in tsEs: if returnedTs is not ts: # the TS changed mid-rule; create a new one for return. ts = copy.deepcopy(ts) measures.extend(returnedMeasures) elif sep == "|": m = stream.Measure() atoms = content.split() # key/timeSig pass... regularAtoms = [] for atom in atoms: if atom.startswith('['): atomContent = atom[1:-1] if atomContent == '0': ts = meter.TimeSignature('4/4') # irregular meter. Cannot fully represent; #TODO: replace w/ senza misura when possible. elif '/' in atomContent: # only one key / ts per measure. ts = meter.TimeSignature(atomContent) else: ks = key.Key( key.convertKeyStringToMusic21KeyString( atomContent)) elif atom == '.': if lastRegularAtom is None: raise CTRuleException(" . w/o previous atom: %s" % self) regularAtoms.append(lastRegularAtom) elif atom in ("", None): pass else: regularAtoms.append(atom) lastRegularAtom = atom numAtoms = len(regularAtoms) if numAtoms == 0: continue # maybe just ts and ks setting self.insertKsTs(m, ts, ks) atomLength = common.opFrac(ts.barDuration.quarterLength / numAtoms) for atom in regularAtoms: if atom == 'R': rest = note.Rest(quarterLength=atomLength) lastChord = None lastChordIsInSameMeasure = False m.append(rest) else: atom = self.fixupChordAtom(atom) rn = roman.RomanNumeral(atom, ks) if self.isSame(rn, lastChord) and lastChordIsInSameMeasure: lastChord.duration.quarterLength += atomLength m.elementsChanged() else: rn.duration.quarterLength = atomLength self.addOptionalTieAndLyrics(rn, lastChord) lastChord = rn lastChordIsInSameMeasure = True m.append(rn) measures.append(m) for i in range(1, numReps): measures.append(copy.deepcopy(m)) else: environLocal.warn( "Rule found without | or $, ignoring: '{0}','{1}': in {2}". format(content, sep, self.text)) #pass if len(measures) > 0: for m in measures: noteIter = m.recurse().notes if (noteIter and (self.parent is None or self.parent.labelSubsectionsOnScore is True) and self.LHS != 'S'): rn = noteIter[0] lyricNum = len(rn.lyrics) + 1 rn.lyrics.append(note.Lyric(self.LHS, number=lyricNum)) break return measures
def expand(self, ts=None, ks=None): ''' The meat of it all -- expand one rule completely and return a list of Measure objects. ''' if ts is None: ts = meter.TimeSignature('4/4') if ks is None: ks = key.Key('C') measures = [] lastRegularAtom = None lastChord = None for content, sep, numReps in self._measureGroups(): lastChordIsInSameMeasure = False if sep == "$": if content not in self.parent.rules: raise CTRuleException("Cannot expand rule {0} in {2}".format(content, self)) rule = self.parent.rules[content] for i in range(numReps): returnedMeasures = rule.expand(ts, ks) self.insertKsTs(returnedMeasures[0], ts, ks) for m in returnedMeasures: tsEs = m.getElementsByClass('TimeSignature', returnStreamSubClass='list') for returnedTs in tsEs: if returnedTs is not ts: ts = copy.deepcopy(ts) # the TS changed mid-rule; create a new one for return. measures.extend(returnedMeasures) elif sep == "|": m = stream.Measure() atoms = content.split() # key/timeSig pass... regularAtoms = [] for atom in atoms: if atom.startswith('['): atomContent = atom[1:-1] if atomContent == '0': ts = meter.TimeSignature('4/4') # irregular meter. Cannot fully represent; #TODO: replace w/ senza misura when possible. elif '/' in atomContent: # only one key / ts per measure. ts = meter.TimeSignature(atomContent) else: ks = key.Key(key.convertKeyStringToMusic21KeyString(atomContent)) elif atom == '.': if lastRegularAtom is None: raise CTRuleException(" . w/o previous atom: %s" % self) regularAtoms.append(lastRegularAtom) elif atom in ("", None): pass else: regularAtoms.append(atom) lastRegularAtom = atom numAtoms = len(regularAtoms) if numAtoms == 0: continue # maybe just ts and ks setting self.insertKsTs(m, ts, ks) atomLength = common.opFrac(ts.barDuration.quarterLength / numAtoms) for atom in regularAtoms: if atom == 'R': rest = note.Rest(quarterLength=atomLength) lastChord = None lastChordIsInSameMeasure = False m.append(rest) else: atom = self.fixupChordAtom(atom) rn = roman.RomanNumeral(atom, ks) if self.isSame(rn, lastChord) and lastChordIsInSameMeasure: lastChord.duration.quarterLength += atomLength m.elementsChanged() else: rn.duration.quarterLength = atomLength self.addOptionalTieAndLyrics(rn, lastChord) lastChord = rn lastChordIsInSameMeasure = True m.append(rn) measures.append(m) for i in range(1, numReps): measures.append(copy.deepcopy(m)) else: environLocal.warn("Rule found without | or $, ignoring: '{0}','{1}': in {2}".format( content, sep, self.text)) #pass if len(measures) > 0: for m in measures: noteIter = m.recurse().notes if noteIter and (self.parent is None or self.parent.labelSubsectionsOnScore is True) and self.LHS != 'S': rn = noteIter[0] lyricNum = len(rn.lyrics) + 1 rn.lyrics.append(note.Lyric(self.LHS, number=lyricNum)) break return measures
def mixed_sequences(data_path, output_path): for (number, filename) in enumerate(os.listdir(data_path), start=1): try: full_path = os.path.join(data_path, filename) LOG.debug("Finding mixed sequences in piece {number}: {filename}.". format(**locals())) piece = parse(full_path) temp_abspath = os.path.join(output_path, TEMP_MIDI_NAME) piece.write('midi', temp_abspath) chord_per_measure = temperley.chord_per_measure( piece, temp_abspath) keys = temperley.key_sequence(temp_abspath) if len(set(keys)) > 1: continue # more than one key in piece is complicated... else: key_string = convertKeyStringToMusic21KeyString( keys[0].replace('b', '-')) key = Key() key_pitch = key.getPitches()[0] instrument = lambda x: x.getInstrument().instrumentName.lower() guitar_parts = (e for e in piece if isinstance (e, Part) and \ ('guitar' in instrument(e) or \ 'gtr' in instrument(e)) and not \ 'bass' in instrument(e)) for part in guitar_parts: current_sequence = None last_note = None measures = [elem for elem in part if isinstance(elem, Measure)] if len(chord_per_measure) != len(measures): continue for chord, measure in zip(chord_per_measure, measures): chord_pitch = music21.pitch.Pitch( convertKeyStringToMusic21KeyString(chord)) for element in measure: if isinstance(element, Note): if not last_note: current_sequence = [ (0, 0, notesToChromatic( key_pitch, element).semitones, key.mode, notesToChromatic(key_pitch, chord_pitch).semitones) ] else: interval = notesToChromatic(last_note, element) entry = (current_sequence[-1][1], interval.semitones, notesToChromatic(key_pitch, element).semitones, key.mode, notesToChromatic( key_pitch, chord_pitch).semitones) current_sequence.append(entry) last_note = element elif isinstance(element, Rest) and element.quarterLength < 4: pass elif current_sequence: yield current_sequence current_sequence = None last_note = None except Exception: LOG.warning( 'Encountered exception in {filename}'.format(**locals()))
def testExtractionOfKeySignatureAttributes(self): """Check the key, mode, tonic pitch class extraction from key signature.""" num_to_major_key = {0: 'C', 1: 'G', 2: 'D', 3: 'A', 4: 'E', 5: 'B', 6: 'F#', 7: 'C#', 8: 'G#', 9: 'D#', 10: 'A#', 11: 'E#', 12: 'B#', -2: 'Bb', -12: 'Dbb', -11: 'Abb', -10: 'Ebb', -9: 'Bbb', -8: 'Fb', -7: 'Cb', -6: 'Gb', -5: 'Db', -4: 'Ab', -3: 'Eb', -1: 'F'} num_to_minor_key = {0: 'a', 1: 'e', 2: 'b', 3: 'f#', 4: 'c#', 5: 'g#', 6: 'd#', 7: 'a#', 8: 'e#', 9: 'b#', 10: 'f##', 11: 'c##', 12: 'g##', -2: 'g', -12: 'bbb', -11: 'fb', -10: 'cb', -9: 'gb', -8: 'db', -7: 'ab', -6: 'eb', -5: 'bb', -4: 'f', -3: 'c', -1: 'd'} for test_mode in ['major', 'minor']: for i in range(-12, 13): ks = key.KeySignature(i) ks.mode = test_mode if test_mode == 'major': key_map = num_to_major_key else: key_map = num_to_minor_key try: key_name, num_sharps, mode, tonic_pitchclass = ( pretty_music21._extract_key_signature_attributes(ks)) except pretty_music21.PrettyMusic21Error: self.assertTrue(i < 7 or i > 7) continue self.assertEqual(key_name, key_map[i]) if mode == 'minor': self.assertEqual( key.sharpsToPitch(num_sharps + 3).name, key.convertKeyStringToMusic21KeyString(key_name).upper()) else: self.assertEqual( key.sharpsToPitch(num_sharps).name, key.convertKeyStringToMusic21KeyString(key_name).upper()) self.assertEqual(mode, ks.mode) check_pitch = pitch.Pitch( key.convertKeyStringToMusic21KeyString(key_map[i])) check_pitchclass = check_pitch.pitchClass self.assertEqual(tonic_pitchclass, check_pitchclass)
def testExtractionOfKeySignatureAttributes(self): """Check the key, mode, tonic pitch class extraction from key signature.""" num_to_major_key = { 0: 'C', 1: 'G', 2: 'D', 3: 'A', 4: 'E', 5: 'B', 6: 'F#', 7: 'C#', 8: 'G#', 9: 'D#', 10: 'A#', 11: 'E#', 12: 'B#', -2: 'Bb', -12: 'Dbb', -11: 'Abb', -10: 'Ebb', -9: 'Bbb', -8: 'Fb', -7: 'Cb', -6: 'Gb', -5: 'Db', -4: 'Ab', -3: 'Eb', -1: 'F' } num_to_minor_key = { 0: 'a', 1: 'e', 2: 'b', 3: 'f#', 4: 'c#', 5: 'g#', 6: 'd#', 7: 'a#', 8: 'e#', 9: 'b#', 10: 'f##', 11: 'c##', 12: 'g##', -2: 'g', -12: 'bbb', -11: 'fb', -10: 'cb', -9: 'gb', -8: 'db', -7: 'ab', -6: 'eb', -5: 'bb', -4: 'f', -3: 'c', -1: 'd' } for test_mode in ['major', 'minor']: for i in range(-12, 13): ks = key.KeySignature(i) ks.mode = test_mode if test_mode == 'major': key_map = num_to_major_key else: key_map = num_to_minor_key try: key_name, num_sharps, mode, tonic_pitchclass = ( pretty_music21._extract_key_signature_attributes(ks)) except pretty_music21.PrettyMusic21Error: self.assertTrue(i < 7 or i > 7) continue self.assertEqual(key_name, key_map[i]) if mode == 'minor': self.assertEqual( key.sharpsToPitch(num_sharps + 3).name, key.convertKeyStringToMusic21KeyString( key_name).upper()) else: self.assertEqual( key.sharpsToPitch(num_sharps).name, key.convertKeyStringToMusic21KeyString( key_name).upper()) self.assertEqual(mode, ks.mode) check_pitch = pitch.Pitch( key.convertKeyStringToMusic21KeyString(key_map[i])) check_pitchclass = check_pitch.pitchClass self.assertEqual(tonic_pitchclass, check_pitchclass)