Exemplo n.º 1
0
 def create(start_spn, end_spn):
     """
     Create PitchRange based on start and end scientific pitch notation.
     
     Args:
       start_spn: start spn (pitch string).
       end_spn: end spn (pitch string).
     Returns:
       PitchRange based on inputs.
     """
     start = DiatonicFoundation.get_chromatic_distance(
         DiatonicPitch.parse(start_spn) if isinstance(start_spn, str
                                                      ) else start_spn)
     end = DiatonicFoundation.get_chromatic_distance(
         DiatonicPitch.parse(end_spn) if isinstance(end_spn, str
                                                    ) else end_spn)
     return PitchRange(start, end)
Exemplo n.º 2
0
 def is_pitch_inbounds(self, pitch):
     """
     Determines if given chromatic location is in bounds of range.
     
     Args:
       pitch: spn text for pitch, e.g. 'c:4' or DiatonticPitch object.
     Returns:
       boolean indicating if in bounds.
     """
     p = DiatonicPitch.parse(pitch) if isinstance(pitch, str) else pitch
     return self.is_inbounds(DiatonicFoundation.get_chromatic_distance(p))
Exemplo n.º 3
0
 def test_semitone_difference(self):
     assert DiatonicFoundation.get_chromatic_distance(DiatonicPitch.parse('C:4')) == 48
     
     equi_list = DiatonicFoundation.add_semitones(DiatonicPitch.parse('eb:4'), 13)
     assert equi_list is not None
     assert len(equi_list) == 3
     assert DiatonicPitch.parse('E:5') in equi_list
     assert DiatonicPitch.parse('D##:5') in equi_list
     assert DiatonicPitch.parse('Fb:5') in equi_list
            
     a = DiatonicPitch.parse('C:5')
     b = DiatonicPitch.parse('F#:4')
     
     assert DiatonicFoundation.semitone_difference(a, b) == 6
     assert DiatonicFoundation.semitone_difference(b, a) == -6
    def _find_closest_pitch(self, pitch):
        """
        Given a pitch, find the scale pitch closest to it in chromatic distance.
        :param pitch:
        :return:
           1) closest in half-steps pitch in tonality.
           2) chromatic distance measured from closest pitch to given pitch.
        Note: algorithm looks for tonal pitches with same letter as pitch first, otherwise nearest non-tonal pitch.
        """
        start_octave = max(pitch.octave - 1, ChromaticScale.CHROMATIC_START[0])
        end_octave = min(pitch.octave + 1, ChromaticScale.CHROMATIC_END[0])

        # Compute the first and last pitches within the start/end octave range. To build a PitchScale
        first_pitch = None
        for t in self.tonality.annotation:
            first_pitch = DiatonicPitch(start_octave, t)
            if DiatonicFoundation.get_chromatic_distance(first_pitch) >= ChromaticScale.chromatic_start_index():
                break

        last_pitch = None
        loop_finished = False
        for o in range(end_octave, end_octave - 2, -1):
            if loop_finished:
                break
            for t in reversed(self.tonality.annotation):
                last_pitch = DiatonicPitch(o, t)
                if DiatonicFoundation.get_chromatic_distance(last_pitch) <= ChromaticScale.chromatic_end_index():
                    loop_finished = True
                    break

        scale = PitchScale(self.tonality, PitchRange.create(first_pitch, last_pitch))

        # determine if pitch ltr is in tonality, get that tone
        ll = [t for t in self.tones if t.diatonic_letter == pitch.diatonic_tone.diatonic_letter]
        if len(ll) == 1:
            pp = DiatonicPitch(pitch.octave, ll[0])
            return pp, pitch.chromatic_distance - pp.chromatic_distance

        # Do something if len(ll) > 1
        elif len(ll) > 1:
            ll.sort(key=lambda x: abs(x.augmentation_offset - pitch.diatonic_tone.augmentation_offset))
            pp = DiatonicPitch(pitch.octave, ll[0])
            return pp, pitch.chromatic_distance - pp.chromatic_distance

        before_pitch = first_pitch
        after_pitch = last_pitch
        for p in scale.pitch_scale:
            if pitch.chromatic_distance <= p.chromatic_distance:
                after_pitch = p
                break
            else:
                before_pitch = p

        before_distance = pitch.chromatic_distance - before_pitch.chromatic_distance
        after_distance = pitch.chromatic_distance - after_pitch.chromatic_distance

        if pitch.diatonic_tone.diatonic_letter == before_pitch.diatonic_tone.diatonic_letter:
            closest_distance = before_distance
            closest_pitch = before_pitch
        elif pitch.diatonic_tone.diatonic_letter == after_pitch.diatonic_tone.diatonic_letter:
            closest_distance = after_distance
            closest_pitch = after_pitch
        else:
            if abs(before_distance) < abs(after_distance):
                closest_distance = before_distance
                closest_pitch = before_pitch
            else:
                closest_distance = after_distance
                closest_pitch = after_pitch

        return closest_pitch, closest_distance