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))
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)
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)
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 )
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)
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)
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
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)
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)
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())
def mul(self, value: float): self._mul = tools.scale((0, 1, value), self.min_vol, self.max_vol)[-1]