def _Rule_10(s: stave.Stave): """Éviter les marches d'harmonie""" for start in range(s.barNumber): for end in range(start, s.barNumber): motif = [] for i in range(start, end + 1): for n in s.getBar(i): motif.append(n) motif_bar_number = end - start + 1 try: following = [] for i in range(end + 1, motif_bar_number + end + 1): for n in s.getBar(i): following.append(n) except IndexError: break try: if tools.matchSequence(motif, following, s.scale): msg = f"Sequence in {s.title}. It should be avoided" if len(motif) == 1: continue if len(motif) <= 2: error.warn(msg, motif, following) else: raise error.CompositionError(msg, motif, following) except ValueError: # It should be that the relative one is encountered, so no sequence here continue
def rule_4(s: stave.Stave): """On doit commencer par une consonance parfaite (unisson, quinte ou douzième, octave ou quinzième) et finir par l'octave ou l'unisson """ def nb_error(poss, posi, notes): if len(notes) != 2: raise error.CompositionError( f"Two notes are expected at the {poss} of the track", s.getBar(posi)) # start notes = s.atFirstPos(0) nb_error("start", 0, notes) if not notes[0].pitch.isPerfectlyConsonantWith(notes[1].pitch): raise error.CompositionError( "The first two notes are not fully consonant.", s.getBar(0)) # end notes = s.atFirstPos(s.lastFirstPos) nb_error("end", s.getBar(s.barNumber - 1), notes) if not notes[0].pitch.isInterval(1, 8, True).With(notes[1].pitch): raise error.CompositionError( "The last interval must be an unison or an octave.", s.getBar(s.barNumber - 1))
def rule_23(s: stave.Stave): """La première et la dernière mesure sont obligatoirement harmonisées par l'accord de tonique à l'état fondamental""" c = chord.Chord(1, s.scale) for bar in (s.getBar(0), s.getBar(-1)): if not c.isInversion([*bar], 0): raise error.CompositionError( "First and last bar must be at the root position of the chord of the first degree", bar)
def rule_26(s: stave.Stave): """La première et la dernière mesure sont obligatoirement harmonisées par l'accord de tonique à l'état fondamental""" tonic = chord.Chord(1, s.scale) for measure in (s.getBar(0), s.getBar(-1)): is_error = False try: if not tonic.isInversion([*measure], 0): is_error = True except ValueError: is_error = True if is_error: raise error.CompositionError( f"In {s.title}, the first bar or the last bar is not the tonic chord at root position", measure)
def rule_22(cp: stave.Stave, cf: stave.Stave): """À l'avant dernière mesure, on emploiera la sixte majeure lorsque le chant donné sera à la basse et la tierce mineure suivie de l'octave ou de l'unisson lorsqu'il sera à la partie supérieure""" # is the cantus firmus above or beyond? cp_above = None for cpn, cfn in zip(cp.barIter(), cf.barIter()): cpn, cfn = [util.to_pitch(n[0]) for n in (cpn, cfn)] if cpn != cfn: cp_above = cpn.value.step > cfn.value.step break assert cp_above is not None # check the before last one bar cpn = util.to_pitch(cp.getBar(cp.barNumber - 2)[0]) cfn = util.to_pitch(cf.getBar(cf.barNumber - 2)[0]) cp = cp.copy() cp.extend(cf) before_last_bar = cp.getBar(cp.barNumber - 2) if cp_above and not cfn.isQualifiedInterval((6, "major")): raise error.CompositionError( "The before last interval must be a 6th major", before_last_bar) elif not cp_above and not cfn.isQualifiedInterval((3, "minor")): raise error.CompositionError( "The before last interval must be a 3rd minor", before_last_bar)
def rule_14(s: stave.Stave): """Pour la fausse relation de triton, la règle est la même qu'en harmonie : la fausse relation de triton est défendue.""" get_pitches = lambda b: sorted([util.to_pitch(x) for x in b], key=lambda x: x.value.semitone) old_high = None for i, bar in enumerate(s.barIter()): if len(bar) != 2: raise error.CompositionError("Two notes expected", bar) bass, high = get_pitches(bar) # check with last bar if old_high is not None and bass.isQualifiedInterval( (4, 'augmented')).With(old_high): raise error.CompositionError("False relation is forbidden", bar) # check with next bar if i + 1 < s.barNumber: next_bass, next_high = get_pitches(s.getBar(i + 1)) if bass.isQualifiedInterval((4, 'augmented')).With(next_high): raise error.CompositionError("False relation is forbidden", bar) # prepare next iteration old_high = high