Пример #1
0
    def __init__(
        self,
        n_repetitions: int,
        # how many beats one loop containts
        loop_duration: fractions.Fraction,
        # how many bars one loop containts
        loop_size: int,
        bars: tuple,
        rhythm_and_metricity_per_prime: dict,
        instrument_prime_mapping: dict,
    ):
        self._n_repetitions = n_repetitions
        self._basic_bars = bars
        self._bars = tuple(
            tuple(abjad.TimeSignature(b) for b in bars) * n_repetitions)
        self._loop_duration = loop_duration
        self._duration = loop_duration * n_repetitions
        self._loop_size = loop_size
        self._instrument_prime_mapping = instrument_prime_mapping
        self._absolute_rhythm_and_metricity_per_prime = {
            prime: ((
                # absolute rhythms
                tools.accumulate_from_zero(
                    rhythm_and_metricity_per_prime[prime][0] * n_repetitions)
                [:-1],
                # metricities, rescaled to range 0 - 1
                tuple(
                    tools.scale(rhythm_and_metricity_per_prime[prime][1], 0, 1)
                    * n_repetitions),
            ))
            for prime in rhythm_and_metricity_per_prime
        }
        absolute_rhythm_and_metricities = functools.reduce(
            operator.add,
            (tuple(zip(*self._absolute_rhythm_and_metricity_per_prime[prime]))
             for prime in self._absolute_rhythm_and_metricity_per_prime),
        )

        absolute_rhythm_and_metricities_dict = {}
        for position, metricity in absolute_rhythm_and_metricities:
            is_addable = True
            if position in absolute_rhythm_and_metricities_dict:
                if metricity < absolute_rhythm_and_metricities_dict[position]:
                    is_addable = False

            if is_addable:
                absolute_rhythm_and_metricities_dict.update(
                    {position: metricity})

        self._absolute_rhythm_and_metricities = tuple(
            sorted(
                ((position, absolute_rhythm_and_metricities_dict[position])
                 for position in absolute_rhythm_and_metricities_dict),
                key=operator.itemgetter(0),
            ))

        self._absolute_rhythm = tuple(
            map(operator.itemgetter(0), self._absolute_rhythm_and_metricities))
        self._metricities = tuple(
            map(operator.itemgetter(1), self._absolute_rhythm_and_metricities))
Пример #2
0
    def mul(self, value: float):
        self._mul = tools.scale((0, 1, value), self.min_vol, self.max_vol)[-1]
        if value <= self.max_value_for_filter:
            filter_freq = self.filter_scale[int(
                (value / self.max_value_for_filter) * self.n_steps)]
        else:
            filter_freq = self.max_max_filter_freq

        for process in self.processed_tables:
            process.setFreq(filter_freq)
Пример #3
0
    def _calculate_metricity_per_beat(self) -> tuple:
        primes = list(globals_.TIME_SIGNATURES2COMPOSITION_STRUCTURES[
            abjad.TimeSignature((self.numerator, self.denominator))])
        duration = self.duration

        while (duration / functools.reduce(operator.mul, primes) >
               self._smallest_expected_unit):
            primes.append(2)

        return tools.scale(
            indispensability.indispensability_for_bar(tuple(primes)), 0, 1)
Пример #4
0
    def _generate_potential_meters() -> tuple:
        """Return tuple filled with subtuples where one subtuple represents one meter.

        Each subtuple is composed of (TIME_SIGNATURE, INDISPENSABILITY_PER_BEAT).
        """
        return tuple(
            (
                abjad.TimeSignature(ts),
                tools.scale(indispensability.indispensability_for_bar(primes), 0, 1),
            )
            for ts, primes in globals_.AVAILABLE_TIME_SIGNATURES
        )
Пример #5
0
    def find_attack_indices(self) -> tuple:
        possible_attack_indices = self.find_possible_attack_indices()
        scaled_weights = tools.scale(self.segment._weight_per_beat,
                                     *self._likelihood_range)

        attack_positions = []
        original_weight = []
        for possible_attack_position in possible_attack_indices:
            if self._random_module.random(
            ) < scaled_weights[possible_attack_position]:
                attack_positions.append(possible_attack_position)
                original_weight.append(
                    self.segment._weight_per_beat[possible_attack_position])

        return tuple(attack_positions), tuple(original_weight)
Пример #6
0
    def _get_position_metricity_pairs(
        time_signature: tuple, smallest_unit: fractions.Fraction
    ) -> tuple:
        ts = fractions.Fraction(
            time_signature[0].numerator, time_signature[0].denominator
        )
        current_unit_size = ts / functools.reduce(operator.mul, time_signature[1])
        smallest_unit = min((smallest_unit, current_unit_size))
        factors = tuple(time_signature[1])
        if smallest_unit < current_unit_size:
            factors += (int(current_unit_size / smallest_unit),)

        metricities = tools.scale(
            indispensability.indispensability_for_bar(factors), 0, 1
        )
        return tuple((smallest_unit, metricity) for metricity in metricities)
Пример #7
0
    def find_start_and_duration_and_volume(self) -> tuple:
        """1. start values, 2. duration per attack, 3. volume per attack"""

        attack_indices, weight_per_attack = self.find_attack_indices()

        has_first_attack = True
        if 0 not in attack_indices:
            attack_indices = (0, ) + attack_indices
            has_first_attack = False

        duration_values = tuple((b - a) * self.segment._tempo_factor
                                for a, b in zip(
                                    attack_indices, attack_indices[1:] +
                                    (int(self.segment._duration), )))
        start_values = tools.accumulate_from_zero(duration_values)

        if not has_first_attack:
            start_values = start_values[1:]
            duration_values = duration_values[1:]

        volume_per_attack = tools.scale(weight_per_attack, *self._volume_range)

        return start_values, duration_values, volume_per_attack
Пример #8
0
    def make_counterpoint_result(self) -> tuple:
        allowed_pitches_per_voice = self.find_allowed_pitches_per_voice()
        self._organism = organisms.Organism(
            self._action_per_voice,
            self._sound_per_voice,
            allowed_pitches_per_voice,
            self._rhythms,
            tools.scale(self._weight_per_beat, *self._weight_range),
            predefined_voices=self._predefined_voices,
            allow_unisono=self._allow_unisono,
            allow_melodic_octaves=self._allow_melodic_octaves,
            random_seed=self._random_seed,
            harmonic_weight=self._harmonic_weight,
            melodic_weight=self._melodic_weight,
        )
        converted_voices0 = []
        converted_voices1 = []
        for vox in tuple(self._organism):
            converted = (tuple(vox.pitch), binr.Compound(vox.delay))
            converted_voices0.append(converted + (tuple(True
                                                        for i in vox.delay), ))
            converted_voices1.append(converted)

        return tuple(converted_voices0), tuple(converted_voices1)
Пример #9
0
    def _detect_rhythmic_orientation(self,
                                     density: float = 0.5,
                                     temperature: float = 0.65) -> tuple:
        """Return indices of beats that are part of rhythmic orientation."""

        for percent in (density, temperature):
            assert percent >= 0 and percent <= 1

        spread_metrical_loop = self.transcription.spread_metrical_loop

        pairs = spread_metrical_loop.get_all_rhythm_metricitiy_pairs()
        n_beats = len(pairs)
        average_distance_between_two_attacks = n_beats / (n_beats * density)

        indices = []
        for idx, pair in enumerate(pairs):
            rhythm, metricity = pair
            primes = spread_metrical_loop.get_primes_of_absolute_rhythm(rhythm)
            # get responsible slice for the current rhythmical position
            slice_ = self.bread.find_responsible_slices(rhythm, rhythm + 1)[0]

            # check if point is inhabited by any allowed pitch(es)
            is_inhabited = False
            if slice_.harmonic_field:
                available_instruments = tuple(
                    spread_metrical_loop.prime_instrument_mapping[prime]
                    for prime in primes)
                available_pitches = tuple(
                    p for p in slice_.harmonic_field
                    # only use pitches that are available in the instrument that are
                    # allowed to play during this beat
                    if globals_.PITCH2INSTRUMENT[p] in available_instruments
                    # prohibit auxiliary pitches for rhythmic orientation
                    and globals_.PITCH2SCALE_DEGREE[p] not in (3, 6))

                if available_pitches:
                    is_inhabited = True

            if is_inhabited:
                ratio = (4, 3, 2)

                if indices:
                    distance_to_last_index = idx - indices[-1]

                    if distance_to_last_index >= average_distance_between_two_attacks:
                        energy_by_density_and_equilibrium = 1

                    else:
                        energy_by_density_and_equilibrium = tools.scale(
                            (
                                1,
                                distance_to_last_index,
                                average_distance_between_two_attacks,
                            ),
                            0,
                            1,
                        )[1]

                else:
                    energy_by_density_and_equilibrium = 1

                energy_items = (
                    metricity,
                    energy_by_density_and_equilibrium,
                    len(available_instruments) / 3,
                )
                energy_level = sum(
                    item * factor for item, factor in zip(energy_items, ratio))
                energy_level /= sum(ratio)
                if energy_level > temperature:
                    indices.append(idx)

        return tuple(indices)
Пример #10
0
    def __init__(
        self,
        action_per_voice: tuple,
        sound_per_voice: tuple,
        allowed_pitches_per_voice: tuple,
        allowed_attacks_per_voice: tuple,
        weights_per_beat: tuple,
        predefined_voices: tuple = tuple([]),
        allow_unisono: bool = True,
        allow_melodic_octaves: bool = False,
        harmonic_weight: float = 2,
        melodic_weight: float = 1,
        random_seed: int = 1000,
        harmonic_range: tuple = (0, 1),
        melodic_range: tuple = (0, 1),
        distance_range: tuple = (0, 1),
        metrical_range: tuple = (0, 1),
    ) -> None:
        self.test_arguments_for_equal_size(
            "voice specific arguments",
            (
                action_per_voice,
                sound_per_voice,
                allowed_attacks_per_voice,
                allowed_pitches_per_voice,
            ),
            lambda data: len(data),
        )
        self.test_arguments_for_equal_size(
            "allowed_attacks_per_voice",
            allowed_attacks_per_voice + tuple(vox.delay for vox in predefined_voices),
            lambda rhythm: sum(rhythm),
        )

        # set attributes
        available_pitches = functools.reduce(operator.add, allowed_pitches_per_voice)
        for vox in predefined_voices:
            available_pitches += tuple(p for p in vox.pitch if not p.is_empty)

        import random

        random.seed(random_seed)

        self._average_distance_per_voice = self._detect_average_distance_per_voice(
            action_per_voice, allowed_attacks_per_voice
        )
        self._linspace_for_distance_likelihood = interpolations.Linear()(
            0, 1, self._GRIDSIZE
        )
        self._duration = len(weights_per_beat)
        self._melodic_weight = melodic_weight
        self._harmonic_weight = harmonic_weight
        self._predefined_voices = predefined_voices
        self._predefined_polyphon = old.Polyphon(predefined_voices)
        self._weights_per_beat = tools.scale(weights_per_beat, *metrical_range)
        self._sound_per_voice = sound_per_voice
        self._allowed_pitches_per_voice = allowed_pitches_per_voice
        self._absolute_allowed_attacks_per_voice = tuple(
            tuple(r.convert2absolute()) for r in allowed_attacks_per_voice
        )
        self._random_module = random
        self._n_voices = len(sound_per_voice)
        self._melodicity_dict_per_voice = self._detect_melodicity_dict_per_voice(
            allowed_pitches_per_voice
        )
        self._harmonicity_dict = self._make_harmonicity_dict(available_pitches)
        self._allow_melodic_octaves = allow_melodic_octaves
        self._allow_unisono = allow_unisono

        self._position_and_voices_pairs = self._detect_position_and_voices_pairs(
            allowed_attacks_per_voice
        )

        super().__init__(self._make_voices())
Пример #11
0
 def mul(self, value: float):
     self._mul = tools.scale((0, 1, value), self.min_vol, self.max_vol)[-1]