コード例 #1
0
ファイル: test_ordered_map.py プロジェクト: dpazel/music_rep
 def test_ceil(self):
     ordered_list = [(10, 100), (5, 20), (7, 70), (2, 50)]
     om = OrderedMap(ordered_list)
     answers = [2, 5, 5, 5, 7, 7, 10, 10, 10, None, None]
     for i in range(1, 12):
         key = om.ceil(i)
         self.assertTrue(key == answers[i - 1])
         mapto = None if key is None else om[key]
         print('find {0} is {1} --> {2}'.format(i, key, mapto))
コード例 #2
0
class ChromaticRangeInterpreter(PitchRangeInterpreter):
    """
    Class that interprets a number as being in the chromatic range A:0-C:8,
        and computes pitches that relate to that range.
    """
    def __init__(self,
                 anchor_pitch=DiatonicPitch.parse('A:0'),
                 anchor_value=9,
                 pitch_unit=1):
        """
        Constructor,
        """
        self.__anchor_pitch = anchor_pitch
        if not isinstance(self.anchor_pitch, DiatonicPitch):
            raise Exception('Anchor is not a DiatonicPitch')

        self.__anchor_value = anchor_value
        self.__pitch_unit = pitch_unit

        anchor_index = self.anchor_pitch.chromatic_distance
        base_value = anchor_value - anchor_index * pitch_unit

        self.value_to_pitch = OrderedMap()
        self.pitch_to_value = dict()
        for i in range(ChromaticScale.chromatic_start_index(),
                       ChromaticScale.chromatic_end_index() + 1):
            pitch = DiatonicFoundation.map_to_diatonic_scale(i)[0]
            value = base_value + i * pitch_unit
            self.value_to_pitch.insert(value, pitch)
            self.pitch_to_value[pitch] = value

        PitchRangeInterpreter.__init__(self)

    @property
    def anchor_pitch(self):
        return self.__anchor_pitch

    @property
    def anchor_value(self):
        return self.__anchor_value

    @property
    def pitch_unit(self):
        return self.__pitch_unit

    def eval_as_nearest_pitch(self, v):
        candidates = self.eval_as_pitch(v)
        if len(candidates) == 1:
            return candidates[0]
        v1 = self.pitch_to_value[candidates[0]]
        v2 = self.pitch_to_value[candidates[1]]
        if v <= (v1 + v2) / 2:
            return candidates[0]
        return candidates[1]

    def value_for(self, diatonic_pitch):
        if isinstance(diatonic_pitch, str):
            diatonic_pitch = DiatonicPitch.parse(diatonic_pitch)
            if diatonic_pitch is None:
                return None
        if diatonic_pitch not in self.pitch_to_value:
            enharmonics = diatonic_pitch.enharmonics()
            found = False
            for p in enharmonics:
                if p in self.pitch_to_value:
                    diatonic_pitch = p
                    found = True
                    break
            if not found:
                return None
        return self.pitch_to_value[
            diatonic_pitch] if diatonic_pitch in self.pitch_to_value else None

    def eval_as_pitch(self, v):
        floor_value = self.value_to_pitch.floor(v)
        ceil_value = self.value_to_pitch.ceil(v)
        if floor_value is None or ceil_value is None:
            raise ChromaticRangeInterpreterException(
                'Illegal chromatic pitch range paramger value {0}.'.format(v))
        if math.isclose(v, self.value_for(self.value_to_pitch[floor_value])):
            return [self.value_to_pitch[floor_value]]
        else:
            p1 = self.value_to_pitch[floor_value]
            p2 = self.value_to_pitch[ceil_value]
            return [p1, p2]

    def eval_as_accurate_chromatic_distance(self, v):
        floor_value = self.value_to_pitch.floor(v)
        if floor_value is None:
            raise ChromaticRangeInterpreterException(
                'Illegal chromatic pitch range paramger value {0}.'.format(v))
        low_pitch = self.value_to_pitch[floor_value]
        index = low_pitch.chromatic_distance

        if index >= ChromaticScale.chromatic_end_index() or math.isclose(
                v, floor_value):
            return low_pitch.chromatic_distance
        high_pitch = DiatonicFoundation.map_to_diatonic_scale(index + 1)[0]
        return low_pitch.chromatic_distance + \
            ((v - floor_value) / self.pitch_unit) * \
            (high_pitch.chromatic_distance - low_pitch.chromatic_distance)