def check_unresolved_leaps(voice): """Raises an error if a voice does not resolve its leap. >>> from music21 import note, stream >>> soprano = stream.Part(map(note.Note, ['C5', 'F5', 'E5'])) >>> alto = stream.Part(map(note.Note, ['G4', 'D4', 'C4'])) >>> check_unresolved_leaps(soprano) >>> check_unresolved_leaps(alto) Traceback (most recent call last): ... errors.UnresolvedLeapError: Found unresolved leap at index 2 """ previous_note, must_resolve = None, 0 for i, current_note in enumerate(voice): if previous_note == current_note: pass elif must_resolve: test_interval = interval.notesToGeneric(previous_note, current_note) if test_interval.directed != must_resolve: raise UnresolvedLeapError(i) must_resolve = 0 elif i > 0: test_interval = interval.notesToGeneric(previous_note, current_note) if test_interval.undirected >= 4: must_resolve = -2*test_interval.directed//test_interval.undirected previous_note = current_note
def check_direct_octaves(bass, soprano): """Raises an error if two voices contain direct octaves. >>> from music21 import note, stream >>> soprano = stream.Part(map(note.Note, ['C5', 'D5', 'E5'])) >>> bass = stream.Part(map(note.Note, ['E3', 'D3', 'A3'])) >>> check_direct_octaves(bass, soprano) >>> soprano = stream.Part(map(note.Note, ['E5', 'E5', 'A5'])) >>> check_direct_octaves(bass, soprano) Traceback (most recent call last): ... errors.DirectOctavesError: Found direct octave at index 2 """ if len(bass) <= 1: return for i, (bass_note, soprano_note) in enumerate(zip(bass, soprano)): is_p8 = helpers.is_perfect_octave(bass_note, soprano_note) if is_p8 and i > 0: bass_interval = interval.notesToGeneric(bass[i-1], bass_note).directed soprano_interval = interval.notesToGeneric(soprano[i-1], soprano_note).directed if soprano_interval * bass_interval > 0 and abs(soprano_interval) > 2: raise DirectOctavesError(i)
def check_spacing(lower_voice, upper_voice): """Raises an error if the interval between two voices exceeds an octave. >>> from music21 import note, stream >>> soprano = stream.Part(map(note.Note, ['C5', 'D5', 'E5'])) >>> alto = stream.Part(map(note.Note, ['A4', 'B4', 'A4'])) >>> tenor = stream.Part(map(note.Note, ['A3', 'G3', 'A3'])) >>> check_spacing(alto, soprano) >>> check_spacing(tenor, alto) Traceback (most recent call last): ... errors.SpacingError: Found spacing error at index 1 """ for i, (lower_note, upper_note) in enumerate(zip(lower_voice, upper_voice)): if interval.notesToGeneric(lower_note, upper_note).undirected > 8: raise SpacingError(i)
def is_fourth(lower_note, upper_note): """Returns whether the interval between two given notes reduced to an octave is a is_fourth. >>> from music21 import note >>> c4 = note.Note('C4') >>> f4 = note.Note('F4') >>> g4 = note.Note('G4') >>> is_fourth(c4, f4) True >>> is_fourth(c4, g4) False """ test_interval = interval.notesToGeneric(lower_note, upper_note) if test_interval.simpleUndirected == 4: return True return False
def part_to_codestring(part): s = stream.Stream() notes = list(part.notes) codestring = '' for i in range(len(notes) - 2): n_0 = notes[i] n_1 = notes[i + 1] if isinstance(n_0, chord.Chord): n_0 = n_0[0] if isinstance(n_1, chord.Chord): n_1 = n_1[0] interval_obj = interval.notesToGeneric(n_0, n_1) interval_num = interval_obj.directed # print(interval_num) codestring += interval_to_codestring(interval_num) return codestring
def addChords(score, quarterLength=1): """ Inputs provisional chords based on leaps in the melodic line. """ # Raise exception for illegal beatStrengths validQuarterLengths = {4, 3, 2, 1.5, 1, 0.5, 0.25} if quarterLength not in validQuarterLengths: raise ValueError(f'Invalid quarter length: must be one of {validQuarterLengths}.') # Prepare dict of offsets and corresponding lists of pitches chordDict = {} vpr = score.parts[0].recurse() for i in range(1, len(vpr.notesAndRests)): # starting pair index = [1] and [0] note2 = vpr.notesAndRests[i] adjustedBeatPosition = floor(note2.offset / quarterLength) * quarterLength # i.e. floor(x * accuracy) / accuracy # signs reversed as < 1 if adjustedBeatPosition != note2.offset: # metrically weak enough if 'NotRest' in note2.classes: note1 = vpr.notesAndRests[i-1] if 'NotRest' in note1.classes: if abs(interval.notesToGeneric(note1, note2).directed) > 2: # a leap measureOffset = note2.activeSite.offset offset = measureOffset + adjustedBeatPosition # combined unique value if offset in chordDict.keys(): # Add to existing tempList = [x for x in chordDict[offset][0]] tempList.append(note1.pitch) tempList.append(note2.pitch) chordDict[offset][0] = tempList else: # Create new entry chordDict[offset] = [[note1.pitch, note2.pitch], measureOffset, adjustedBeatPosition ] # Prepare and insert chords for x in chordDict.keys(): noDuplicatesChord = chord.Chord(list(set([y for y in chordDict[x][0]]))) noDuplicatesChord.quarterLength = quarterLength measureOffset = round(chordDict[x][1], 2) # NB not int adjustedBeatPosition = chordDict[x][2] finalStep = score.parts[1].getElementsByClass('Measure').getElementsByOffset(measureOffset)[0] finalStep.insert(adjustedBeatPosition, noDuplicatesChord) return score
def same_distance(note1, note2): if interval.notesToGeneric(note1, note2) == 'P1': return 0.2 else: return 1
def three_steps(note1, note2): if interval.notesToGeneric(note1, note2) == 'P4' or 'A4': return 0.8 else: return 0
def two_steps(note1, note2): if interval.notesToGeneric(note1, note2) == 'M3' or 'm3': return 1 else: return 0
def one_step(note1, note2): if interval.notesToGeneric(note1, note2) == 'M2' or 'm2': return 0.7 else: return 0