Exemple #1
0
 def test_percent_possible(self):
     # Test guaranteed outcomes
     self.assertTrue(rand.prob_bool(1000))
     self.assertTrue(rand.prob_bool(100))
     self.assertFalse(rand.prob_bool(0))
     self.assertFalse(rand.prob_bool(-1000))
     # Test that probabilties are working as expected
     true_count = 0
     for i in range(1000):
         if rand.percent_possible(20):
             true_count += 1
     self.assertTrue(5 <= true_count <= 400)
Exemple #2
0
 def test_percent_possible(self):
     # Test guaranteed outcomes
     self.assertTrue(rand.prob_bool(1000))
     self.assertTrue(rand.prob_bool(100))
     self.assertFalse(rand.prob_bool(0))
     self.assertFalse(rand.prob_bool(-1000))
     # Test that probabilties are working as expected
     true_count = 0
     for i in range(1000):
         if rand.percent_possible(20):
             true_count += 1
     self.assertTrue(5 <= true_count <= 400)
    def populate_item_list(self, item_count):
        """
        Fill ``self.item_list`` with Node instances.

        Args:
            item_count (int): Number of items to create

        Returns: None
        """

        graph_weights = [(network, 1) for network in self.word_graphs]

        # Pick a random network to start on
        current_network = random.choice(self.word_graphs)

        # Main item population loop
        for i in range(item_count):
            # Determine if we should change networks (crude)
            if rand.prob_bool(0.01):
                old_network = current_network
                while current_network == old_network:
                    current_network = rand.weighted_choice(graph_weights)

            # Determine with self.pause_or_write_network whether to append a
            # blank line or a word to self.item_list
            if self.pause_or_write_network.pick().get_value() == 0:
                self.item_list.append(custom_nodes.BlankLine())
            else:
                new_node = current_network.pick()
                self.item_list.append(new_node)
def manage_replayers(data_paths, replayer_list,
                     add_player_prob, remove_player_prob):
    """
    Manage a list of ``Replayer`` 's, sometimes adding and removing items.

    Args:
        data_paths (list[str]):
        replayer_list (list[str]):
        add_player_prob (float): probability between 0 and 1 to add a replayer
            to the replayer list
        remove_player_prob (float): probability between 0 and 1 to to add a
            replayer to the replayer list

    Returns:

    """
    if rand.prob_bool(add_player_prob):
        add_random_replayer(replayer_list, data_paths)
    if rand.prob_bool(remove_player_prob):
        remove_random_replayer(replayer_list)
Exemple #5
0
def build_chunk(oscillators):
    """
    Build an audio chunk and progress the oscillator states.

    Args:
        oscillators (list): A list of oscillator.Oscillator objects
            to build chunks from

    Returns:
        str: a string of audio sample bytes ready to be written to a wave file
    """
    step_random_processes(oscillators)
    subchunks = []
    for osc in oscillators:
        osc.amplitude.step_amp()
        osc_chunk = osc.get_samples(config.CHUNK_SIZE)
        if osc_chunk is not None:
            subchunks.append(osc_chunk)
    if len(subchunks):
        new_chunk = sum(subchunks)
    else:
        new_chunk = numpy.zeros(config.CHUNK_SIZE)
    # If we exceed the maximum amplitude, handle it gracefully
    chunk_amplitude = amplitude.find_amplitude(new_chunk)
    if chunk_amplitude > config.MAX_AMPLITUDE:
        # Normalize the amplitude chunk to mitigate immediate clipping
        new_chunk = amplitude.normalize_amplitude(new_chunk,
                                                  config.MAX_AMPLITUDE)
        # Pick some of the offending oscillators (and some random others)
        # and lower their drift targets
        avg_amp = (sum(osc.amplitude.value for osc in oscillators) /
                   len(oscillators))
        for osc in oscillators:
            if (osc.amplitude.value > avg_amp and rand.prob_bool(0.1) or
                    rand.prob_bool(0.01)):
                osc.amplitude.drift_target = rand.weighted_rand(
                    [(-5, 1), (0, 10)])
                osc.amplitude.change_rate = rand.weighted_rand(
                    osc.amplitude.change_rate_weights)
    return new_chunk.astype(config.SAMPLE_DATA_TYPE).tostring()
Exemple #6
0
def build_chunk(oscillators):
    """
    Build an audio chunk and progress the oscillator states.

    Args:
        oscillators (list): A list of oscillator.Oscillator objects
            to build chunks from

    Returns:
        str: a string of audio sample bytes ready to be written to a wave file
    """
    step_random_processes(oscillators)
    subchunks = []
    for osc in oscillators:
        osc.amplitude.step_amp()
        osc_chunk = osc.get_samples(config.CHUNK_SIZE)
        if osc_chunk is not None:
            subchunks.append(osc_chunk)
    if len(subchunks):
        new_chunk = sum(subchunks)
    else:
        new_chunk = numpy.zeros(config.CHUNK_SIZE)
    # If we exceed the maximum amplitude, handle it gracefully
    chunk_amplitude = amplitude.find_amplitude(new_chunk)
    if chunk_amplitude > config.MAX_AMPLITUDE:
        # Normalize the amplitude chunk to mitigate immediate clipping
        new_chunk = amplitude.normalize_amplitude(new_chunk,
                                                  config.MAX_AMPLITUDE)
        # Pick some of the offending oscillators (and some random others)
        # and lower their drift targets
        avg_amp = (sum(osc.amplitude.value
                       for osc in oscillators) / len(oscillators))
        for osc in oscillators:
            if (osc.amplitude.value > avg_amp and rand.prob_bool(0.1)
                    or rand.prob_bool(0.01)):
                osc.amplitude.drift_target = rand.weighted_rand([(-5, 1),
                                                                 (0, 10)])
                osc.amplitude.change_rate = rand.weighted_rand(
                    osc.amplitude.change_rate_weights)
    return new_chunk.astype(config.SAMPLE_DATA_TYPE).tostring()
    def step_amp(self):
        """
        Change the amplitude according to the change rate and drift target.

        Also offer a chance to re-roll behavior attributes.

        Returns: None
        """
        # Roll for a chance to change the drift target and change rate
        if rand.prob_bool(self.move_freq):
            self.re_roll_behaviors()
        # step the amplitude
        difference = self.drift_target - self.value
        if abs(difference) < self.change_rate:
            self.value = self.drift_target
        else:
            delta = self.change_rate * numpy.sign(difference)
            self.value += delta
Exemple #8
0
def step_random_processes(oscillators):
    """
    Args:
        oscillators (list): A list of oscillator.Oscillator objects
            to operate on

    Returns: None
    """
    if not rand.prob_bool(0.01):
        return
    amp_bias_weights = [(0.001, 1), (0.1, 100), (0.15, 40), (1, 0)]
    # Find out how many oscillators should move
    num_moves = iching.get_hexagram('NAIVE') % len(oscillators)
    for i in range(num_moves):
        pair = [gram % len(oscillators)
                for gram in iching.get_hexagram('THREE COIN')]
        amplitudes = [(gram / 64) * rand.weighted_rand(amp_bias_weights)
                      for gram in iching.get_hexagram('THREE COIN')]
        oscillators[pair[0]].amplitude.drift_target = amplitudes[0]
        oscillators[pair[1]].amplitude.drift_target = amplitudes[1]
Exemple #9
0
def step_random_processes(oscillators):
    """
    Args:
        oscillators (list): A list of oscillator.Oscillator objects
            to operate on

    Returns: None
    """
    if not rand.prob_bool(0.01):
        return
    amp_bias_weights = [(0.001, 1), (0.1, 100), (0.15, 40), (1, 0)]
    # Find out how many oscillators should move
    num_moves = iching.get_hexagram('NAIVE') % len(oscillators)
    for i in range(num_moves):
        pair = [
            gram % len(oscillators)
            for gram in iching.get_hexagram('THREE COIN')
        ]
        amplitudes = [(gram / 64) * rand.weighted_rand(amp_bias_weights)
                      for gram in iching.get_hexagram('THREE COIN')]
        oscillators[pair[0]].amplitude.drift_target = amplitudes[0]
        oscillators[pair[1]].amplitude.drift_target = amplitudes[1]
    def get(self):
        """
        Render the poem as an HTML string.

        Returns:
            str: the body of the poem in HTML
        """
        if rand.prob_bool(self.mutable_chance):
            # Render text from a markov graph derived from the source text
            word_list = []
            word_count = rand.weighted_rand(
                self.word_count_weights, round_result=True)
            word_graph = Graph.from_file(self.filepath, self.distance_weights)
            for i in range(word_count):
                word = word_graph.pick().get_value()
                word_list.append(word)
        else:
            # Otherwise, copy source contents literally
            source_file = open(self.filepath, 'r')
            word_list = source_file.read().split()
        # Combine words, process markups, and return HTML
        return self.render_markups(word_list)
    def render_markups(self, word_list):
        """
        Render a list of words and markups to html with automatic line breaks.

        This method performs several processing steps preparing the poem text
        for HTML delivery. It:
            * Converts `---` to stochastic length dashes in the form of empty
              `<span class="variable-length-dash"></span>` tags
            * Converts `|||` to stochastic height line breaks in the form of
              empty `<span class="variable-height-break"></span>` tags
            * Spontaneously inserts horizontal blank space between words in the
              form of empty `<span class="horizontal-blank-space"></span>` tags
            * Calculates the position of line breaks and renders them as divs
              in the form `<div class="poem-line"> ... </div>`

        Line breaks are triggered after every word which exceeds
        `LINE_LENGTH`. This character limit ignores HTML tags,
        allowing lines containing spans (variable-length-dash or
        horizontal-blank-space) to intentionally visually exceed the apparent
        right edge of the poem.

        Args:
            word_list (list[str]): The list of words (as well as punctuation
                marks and markups) to render.

        Returns:
            str: The contents of `word_list` rendered as HTML
        """
        working_text = word_list[:]  # Copy of word_list to avoid side-effects
        lines = []                   # List of lines in the generated poem
        current_line = []            # List of words in the current line
        visible_char_count = 0       # Number of visible chars in current line

        for word in working_text:
            if word == '---':
                # Render triple dashes to variable length visible dashes
                # (in the form of inline-block spans)
                dash_length = rand.weighted_rand(self.dash_length_weights)
                word = variable_length_dash(dash_length)
            elif word == '|||':
                # Render triple pipes as variable height breaks
                # (in the form of fixed-height spans)
                y_gap = rand.weighted_rand(
                        self.y_gap_height_weights)
                word = variable_height_break(y_gap)
            else:
                # Otherwise, the word will be rendered literally as visible
                # text, so count it toward the visible character count used
                # in placing line breaks
                visible_char_count += len(word)

            # Roll to insert x-axis gaps
            if rand.prob_bool(self.x_gap_freq):
                x_gap = rand.weighted_rand(self.x_gap_length_weights)
                # Sometimes place space before word, sometimes after (50/50)
                word = horizontal_blank_space(x_gap) + word
            # Break lines when LINE_LENGTH is exceeded
            if visible_char_count > LINE_LENGTH:
                visible_char_count = 0
                lines.append(''.join(current_line))
                current_line = []
            # Handle spaces appropriately for punctuation marks
            if word in PUNCTUATIONS:
                current_line.append(word)
            else:
                current_line.append(' ' + word)
        # Attach final line
        if current_line:
            lines.append(''.join(current_line))

        return (''.join((surround_with_tag(line, 'div', 'class="poem-line"')
                         for line in lines)))