def limiting_notes(block): r""" Given a block, generate all the limiting notes and the index of the chord they belong to. Note that, for the sake of predictability, notes within the same chord are generated based on their string order: limiting notes on a high string are yielded before limiting notes on a low string within the same chord. >>> limiting_notes(['E|-0', 'B|-0', 'G|-0', 'D|-0', 'A|-0', 'E|-0']).next() (('E', 2), 0) """ chord_index = 0 for chord in chords(block): for string_num in sorted(chord.keys()): note = fret2note(chord[string_num], string_num) if is_limiting(note): yield (note, chord_index) chord_index += 1
def midi_contexts(midi_path): r""" For each chord in a midi file, yield a context. Note that these contexts differ from those provided by the `chord_contexts` function, because data about physical notes is unavailable. Specifically, the information provided is as follows: #. the current theoretical chord #. the following theoretical chords #. the chord index of the current chord #. the next limiting note along with its chord index **Also note that only notes occur in contexts. Rests are ignored, and only the melody section is examined, so chords are not relevant.** """ piece = music21.converter.parse(midi_path) melody_part = _find_melody_part(piece) pitches = [n.pitch for n in melody_part if isinstance(n, Note)] for pitch_index in range(0, len(pitches)): if "-" in pitches[pitch_index].name: pitches[pitch_index] = pitches[pitch_index].getEnharmonic() notes = [(p.name, p.octave) for p in pitches] following_indices = range(1, CHORDS_AFTER_CURRENT + 1) # assuming slack for current_index in range(0, len(notes)): limiting = None for search_index in range(current_index + 1, len(notes)): if is_limiting(notes[search_index]): limiting = (notes[search_index], search_index) break current = Counter({notes[current_index]: 1}) # standard rep following = [Counter({notes[index]: 1}) for index in following_indices] guesstimate = [current, following, current_index, limiting] yield tuple(guesstimate) if following_indices: del (following_indices[0]) if following_indices and following_indices[-1] < len(notes) - 1: following_indices.append(following_indices[-1] + 1)
def test_middle_c_not_limiting(self, mock_frets): note = ('C', 3) mock_frets.return_value = [(8, ('E', 2)), (3, ('A', 3))] self.assertFalse(notemappings.is_limiting(note))
def test_highest_a_two_positions(self, mock_frets): note = ('A', 6) mock_frets.return_value = [(22, ('B', 4)), (17, ('E', 4))] self.assertTrue(notemappings.is_limiting(note))
def test_lowest_e_one_position(self, mock_frets): note = ('E', 2) mock_frets.return_value = [(0, ('E', 2))] self.assertTrue(notemappings.is_limiting(note))