def _doesnt_create_hiddens_or_parallels(self, note: Note,
                                         index: int) -> bool:
     chro_interval = note.get_chromatic_interval(self._cf.get_note(index))
     if abs(chro_interval) not in [7, 12]:
         return True
     prev_note = self._counterpoint[index - 1]
     next_note = self._counterpoint[index + 1]
     if prev_note is not None:
         prev_interval = prev_note.get_scale_degree_interval(note)
         cf_prev_interval = self._cf.get_note(index -
                                              1).get_scale_degree_interval(
                                                  self._cf.get_note(index))
         if (prev_interval > 0
                 and cf_prev_interval > 0) or (prev_interval < 0
                                               and cf_prev_interval < 0):
             return False
     if next_note is not None:
         next_interval = note.get_scale_degree_interval(next_note)
         cf_next_interval = self._cf.get_note(
             index).get_scale_degree_interval(self._cf.get_note(index + 1))
         if (next_interval > 0
                 and cf_next_interval > 0) or (next_interval < 0
                                               and cf_next_interval < 0):
             next_chro_interval = next_note.get_chromatic_interval(
                 self._cf.get_note(index + 1))
             if abs(next_chro_interval) in [7, 12]:
                 return False
     return True
 def _is_valid_harmonically(self, note1: Note, note2: Note) -> bool:
     sdg_interval = note1.get_scale_degree_interval(note2)
     chro_interval = note1.get_chromatic_interval(note2)
     if ( sdg_interval in LegalIntervalsFourthSpecies["harmonic_scalar"] 
         and chro_interval in LegalIntervalsFourthSpecies["harmonic_chromatic"]
         and (sdg_interval, chro_interval) not in LegalIntervalsFourthSpecies["forbidden_combinations"] ):
         return True 
     return False 
 def _valid_outline(self, note1: Note, note2: Note) -> bool:
     chro_interval = note1.get_chromatic_interval(note2)
     sdg_interval = note1.get_scale_degree_interval(note2)
     if chro_interval in CONSONANT_MELODIC_INTERVALS_CHROMATIC and (
             abs(sdg_interval),
             abs(chro_interval)) not in FORBIDDEN_INTERVAL_COMBINATIONS:
         return True
     return False
 def _is_valid_adjacent(self, note1: Note, note2: Note) -> bool:
     sdg_interval = note1.get_scale_degree_interval(note2)
     chro_interval = note1.get_chromatic_interval(note2)
     if (self._mr.is_leading_tone(note1) or self._mr.is_leading_tone(note2)) and abs(sdg_interval) > 3: return False 
     if ( sdg_interval in LegalIntervalsFourthSpecies["adjacent_melodic_scalar"] 
         and chro_interval in LegalIntervalsFourthSpecies["adjacent_melodic_chromatic"]
         and (sdg_interval, chro_interval) not in LegalIntervalsFourthSpecies["forbidden_combinations"] ):
         return True 
     return False 
 def _is_valid_outline(self, note1: Note, note2: Note) -> bool:
     sdg_interval = note1.get_scale_degree_interval(note2)
     chro_interval = note1.get_chromatic_interval(note2)
     if (sdg_interval in LegalIntervals["outline_melodic_scalar"] and
             chro_interval in LegalIntervals["outline_melodic_chromatic"]
             and (sdg_interval, chro_interval)
             not in LegalIntervals["forbidden_combinations"]):
         return True
     return False
 def _valid_harmonically(self, note1: Note, note2: Note) -> bool:
     chro_interval = note1.get_chromatic_interval(note2)
     if chro_interval == 0: return False
     sdg_interval = note1.get_scale_degree_interval(note2)
     if sdg_interval in CONSONANT_HARMONIC_INTERVALS_SCALE_DEGREES and abs(
             chro_interval) % 12 in CONSONANT_HARMONIC_INTERVALS_CHROMATIC:
         combo = (abs(sdg_interval if sdg_interval <= 8 else sdg_interval -
                      7), abs(chro_interval) % 12)
         if combo not in FORBIDDEN_INTERVAL_COMBINATIONS:
             return True
     return False
 def _valid_adjacent(self, note1: Note, note2: Note) -> bool:
     chro_interval = note1.get_chromatic_interval(note2)
     sdg_interval = note1.get_scale_degree_interval(note2)
     if chro_interval in VALID_MELODIC_INTERVALS_CHROMATIC and (
             abs(sdg_interval),
             abs(chro_interval)) not in FORBIDDEN_INTERVAL_COMBINATIONS:
         if note1.get_accidental(
         ) == ScaleOption.NATURAL or note2.get_accidental(
         ) == ScaleOption.NATURAL or abs(chro_interval) == 2:
             return True
     return False
 def _doesnt_create_parallels(self, note: Note, index: tuple) -> bool:
     (i, j) = index
     cf_note, next_note, cf_next = self._cantus[i], self._counterpoint[(
         i + 1, 0)], self._cantus[i + 1]
     if next_note is not None and abs(
             next_note.get_chromatic_interval(cf_next)) in [0, 7, 12, 19]:
         #next measure is a perfect interval.  check for parallels first
         if note.get_chromatic_interval(
                 cf_note) == next_note.get_chromatic_interval(cf_next):
             return False
         #check for hidden intervals
         if (j == 2 and
             ((note.get_scale_degree_interval(next_note) > 0
               and cf_note.get_scale_degree_interval(cf_next) > 0) or
              (note.get_scale_degree_interval(next_note) < 0
               and cf_note.get_scale_degree_interval(cf_next) < 0))):
             return False
     #if j is 2 we don't have to check what comes before
     if j == 0 and abs(
             note.get_chromatic_interval(cf_note)) in [0, 7, 12, 19]:
         cf_prev = self._cantus[i - 1]
         #check previous downbeat if it exists
         if i - 1 != 0 or self._start_on_beat:
             prev_downbeat = self._counterpoint[(i - 1, 0)]
             if prev_downbeat is not None and note.get_chromatic_interval(
                     cf_note) == prev_downbeat.get_chromatic_interval(
                         cf_prev):
                 return False
         #previous weak beat will always exist when we check an insertion
         prev_note = self._counterpoint[(i - 1, 2)]
         if prev_note is not None and note.get_chromatic_interval(
                 cf_note) == prev_note.get_chromatic_interval(cf_prev):
             return False
         #check for hiddens
         if (prev_note is not None and
             ((prev_note.get_scale_degree_interval(note) > 0
               and cf_prev.get_scale_degree_interval(cf_note) > 0) or
              (prev_note.get_scale_degree_interval(note) < 0
               and cf_prev.get_scale_degree_interval(cf_note) < 0))):
             return False
     return True
Exemple #9
0
 def _handles_first_note(self, note: Note, index: tuple, line: int) -> bool:
     if index[0] != 0: return True
     intvl = self._counterpoint_obj[0][(0, 0)].get_chromatic_interval(
         note) if line != 0 else note.get_chromatic_interval(
             self._counterpoint_obj[self._cf_index][(0, 0)])
     if intvl < 0 or intvl % 12 not in [0, 4, 7]: return False
     if line != self._height - 1 and (line != self._height - 2 or
                                      self._cf_index != self._height - 1):
         return True
     has_fifth, has_third = False, False
     for i in range(1, self._height):
         low_note, high_note = self._counterpoint_obj[0][(
             0, 0)], self._counterpoint_obj[i][(0, 0)]
         if low_note is None or high_note is None: continue
         intvl_to_check = low_note.get_chromatic_interval(high_note) % 12
         if intvl_to_check == 4: has_third = True
         if intvl_to_check == 7: has_fifth = True
     if not has_third or not has_fifth: return False
     return True
    def _is_valid_adjacent(self, note1: Note, note2: Note) -> bool:
        sdg_interval = note1.get_scale_degree_interval(note2)
        if (note1.get_accidental() == ScaleOption.SHARP
                or note2.get_accidental()
                == ScaleOption.SHARP) and abs(sdg_interval) > 3:
            return False
        #if a sharp is not followed by a step up, we'll give it an arbitrary 50% chance of passing
        is_leading_tone = note1.get_accidental == ScaleOption.SHARP or (
            note1.get_scale_degree() == 7
            and self._mode in [ModeOption.DORIAN, ModeOption.LYDIAN])
        if sdg_interval != 2 and is_leading_tone and random() > .5:
            return False

        chro_interval = note1.get_chromatic_interval(note2)
        if (sdg_interval in LegalIntervals["adjacent_melodic_scalar"] and
                chro_interval in LegalIntervals["adjacent_melodic_chromatic"]
                and (sdg_interval, chro_interval)
                not in LegalIntervals["forbidden_combinations"]):
            return True
        return False
 def _valid_melodic_interval(self, first_note: Note, second_note: Note) -> bool:
     scale_interval = first_note.get_scale_degree_interval(second_note)
     chro_interval = first_note.get_chromatic_interval(second_note)
     if scale_interval not in VALID_MELODIC_INTERVALS_SCALE_DEGREES: return False 
     if chro_interval not in VALID_MELODIC_INTERVALS_CHROMATIC: return False
     return True
 def _is_unison(self, note1: Note, note2: Note) -> bool:
     return note1.get_scale_degree_interval(
         note2) == 1 and note1.get_chromatic_interval(note2) == 0