<commit_before>"""

This module provides classes to declare, play and plot auditory scene populated by elements in the (time, frequency) domain
The scene is organized as a tree with Leaves as atom elements of the scene.

The tree offers a way to group atoms, and make group of groups etc...

This is useful:
    - to declare structured groups of atoms (ex. shepard tone)
    - to easily create repeated patterns (ex. time shifted groups)

.. _Google Python Style Guide:
   http://google-styleguide.googlecode.com/svn/trunk/pyguide.html

"""

import numpy as np
from abc import *
from matplotlib import pyplot as plt
import copy
import collections

class Node(object):
    """Node

    Attributes:
        List (list): list of Leaf elements in the node
        delay (float): delay relative to absolute scene start time
        scale (float): scaling to be applied to all elements deeper in tree
        active (bool): flag declaring inclusion/exclusion from scene
        index (int) : additional flag, useful for ordering items
    """
    TAG = "Node"

    def __init__(self, List=[], delay=0., scale=1., active=True, index=None, draw_bbox=False):
        self.List = List
        self.delay = delay
        self.scale = scale
        self.active = active
        self.index = index
        self.draw_bbox = draw_bbox

    def getduration(self):
        """Duration of node

        Returns:
            duration of node

        """
        return np.max([item.delay+item.getduration() for item in self.List if item.active==True])

    def getbbox(self):
        """
        Get the smallest time/freq box containing elements of the node

        Returns:
            [tmin, tmax, fmin, fmax] (absolute time and frequency wrt origin of scene)
        """

        rel_box = [0, 0, float("inf"), float("-inf")] # init relative box
        for item in self.List:
            if item.active is True:
                # get subnode box
                item_box = item.getbbox()
                # update current node box
                rel_box[0] = rel_box[0] if rel_box[0]<item_box[0] else item_box[0]
                rel_box[2] = rel_box[2] if rel_box[2]<item_box[2] else item_box[2]
                rel_box[1] = rel_box[1] if rel_box[1]>item_box[1] else item_box[1]
                rel_box[3] = rel_box[3] if rel_box[3]>item_box[3] else item_box[3]
        return rel_box

    def addItemToList(self, item):
        """Populate node

        Args:
            item (Node/Leaf or list): element or subtree to add to node
        """
        if type(item) == list:
            self.List = self.List + item
        else:
            self.List.append(item)

    def flatten(self, cum_delay, prod_scale):
        l = []
        for item in self.List:
            l += item.flatten(cum_delay, prod_scale)

    def print_content(self):
        for item in self.List:
            item.print_content()

    def generate(self, fs):
        """Generate soundwave

        Args:
            fs (float): sampling frequency (Hz)

        """
        duration = self.getduration()
        x = np.zeros((int(duration*fs),))
        for item in self.List:
            if item.active is True:
                xt = item.generate(fs)
                i_start = int(item.delay*fs)
                x[i_start:i_start+len(xt)] += xt*self.scale
        return x

    def draw(self, ax, prop_delay, prop_scale):
        """Draw node

        Args:
            ax (matplotlib.axes.Axes): axe instance to plot into
            prop_delay (float): propagated absolute delay of parent node
            prop_scale (float): propagated absolute scale of parent node

        """
        if self.active is True:
            for node in self.List:
                node.draw(ax, prop_delay+self.delay, prop_scale*self.scale)

        if self.draw_bbox==True:
            color = "black"
            box = self.getbbox()
            box[0] += prop_delay + self.delay
            box[1] += prop_delay + self.delay
            # horizontal
            ax.plot([box[0], box[1]], [box[2], box[2]], color=color)
            ax.plot([box[0], box[1]], [box[3], box[3]], color=color)
            # vertical
            ax.plot([box[0], box[0]], [box[2], box[3]], color=color)
            ax.plot([box[1], box[1]], [box[2], box[3]], color=color)

class Scene(Node):
    """Scene

    Scene, implements Node + has extra method to draw spectrogram
    It is the root reference for time and scale

    """

    TAG = "Scene"

    def __init__(self, List=[]):
        """Constructor"""
        super(Scene, self).__init__(List=List)


    def draw_spectrogram(self, f_axis="log"):
        """
        Returns a matplotlib figure containing drawn spectrogram

        Args:
            f_axis (string): type of plot ('log' or 'lin')

        """
        fig = plt.figure()
        ax = fig.add_subplot(1,1,1)
        for node in self.List:
            node.draw(ax, prop_delay=0., prop_scale=1.)
        ax.set_yscale(f_axis)
        ax.set_ylabel(f_axis=="log" and "log freq (Hz)" or "freq (Hz)")
        ax.set_xlabel("time (s)")
        ax.set_title("Spectrogram")
        return fig

    def flatten_scene(self):
        """
        Clear all hierarchy in tone<commit_msg>changing the way flag active is assessed recursively<commit_after>"""

This module provides classes to declare, play and plot auditory scene populated by elements in the (time, frequency) domain
The scene is organized as a tree with Leaves as atom elements of the scene.

The tree offers a way to group atoms, and make group of groups etc...

This is useful:
    - to declare structured groups of atoms (ex. shepard tone)
    - to easily create repeated patterns (ex. time shifted groups)

.. _Google Python Style Guide:
   http://google-styleguide.googlecode.com/svn/trunk/pyguide.html

"""

import numpy as np
from abc import *
from matplotlib import pyplot as plt
import copy
import collections

class Node(object):
    """Node

    Attributes:
        List (list): list of Leaf elements in the node
        delay (float): delay relative to absolute scene start time
        scale (float): scaling to be applied to all elements deeper in tree
        active (bool): flag declaring inclusion/exclusion from scene
        index (int) : additional flag, useful for ordering items
    """
    TAG = "Node"

    def __init__(self, List=[], delay=0., scale=1., active=True, index=None, draw_bbox=False):
        self.List = List
        self.delay = delay
        self.scale = scale
        self.active = active
        self.index = index
        self.draw_bbox = draw_bbox

    def getduration(self):
        """Duration of node

        Returns:
            duration of node

        """
        return np.max([item.delay+item.getduration() for item in self.List if item.active==True])

    def getbbox(self):
        """
        Get the smallest time/freq box containing elements of the node

        Returns:
            [tmin, tmax, fmin, fmax] (absolute time and frequency wrt origin of scene)
        """

        rel_box = [0, 0, float("inf"), float("-inf")] # init relative box
        for item in self.List:
            if item.active is True:
                # get subnode box
                item_box = item.getbbox()
                # update current node box
                rel_box[0] = rel_box[0] if rel_box[0]<item_box[0] else item_box[0]
                rel_box[2] = rel_box[2] if rel_box[2]<item_box[2] else item_box[2]
                rel_box[1] = rel_box[1] if rel_box[1]>item_box[1] else item_box[1]
                rel_box[3] = rel_box[3] if rel_box[3]>item_box[3] else item_box[3]
        return rel_box

    def addItemToList(self, item):
        """Populate node

        Args:
            item (Node/Leaf or list): element or subtree to add to node
        """
        if type(item) == list:
            self.List = self.List + item
        else:
            self.List.append(item)

    def flatten(self, cum_delay, prod_scale):
        l = []
        for item in self.List:
            l += item.flatten(cum_delay, prod_scale)

    def print_content(self):
        for item in self.List:
            item.print_content()

    def generate(self, fs):
        """Generate soundwave

        Args:
            fs (float): sampling frequency (Hz)

        """
        duration = self.getduration()
        x = np.zeros((int(duration*fs),))
        for item in self.List:
            if item.active is True:
                xt = item.generate(fs)
                i_start = int(item.delay*fs)
                x[i_start:i_start+len(xt)] += xt*self.scale
        return x

    def draw(self, ax, prop_delay, prop_scale):
        """Draw node

        Args:
            ax (matplotlib.axes.Axes): axe instance to plot into
            prop_delay (float): propagated absolute delay of parent node
            prop_scale (float): propagated absolute scale of parent node

        """
        for node in self.List:
            if node.active is True:
                node.draw(ax, prop_delay+self.delay, prop_scale*self.scale)

        if self.draw_bbox==True:
            color = "black"
            box = self.getbbox()
            box[0] += prop_delay + self.delay
            box[1] += prop_delay + self.delay
            # horizontal
            ax.plot([box[0], box[1]], [box[2], box[2]], color=color)
            ax.plot([box[0], box[1]], [box[3], box[3]], color=color)
            # vertical
            ax.plot([box[0], box[0]], [box[2], box[3]], color=color)
            ax.plot([box[1], box[1]], [box[2], box[3]], color=color)

class Scene(Node):
    """Scene

    Scene, implements Node + has extra method to draw spectrogram
    It is the root reference for time and scale

    """

    TAG = "Scene"

    def __init__(self, List=[]):
        """Constructor"""
        super(Scene, self).__init__(List=List)


    def draw_spectrogram(self, f_axis="log"):
        """
        Returns a matplotlib figure containing drawn spectrogram

        Args:
            f_axis (string): type of plot ('log' or 'lin')

        """
        fig = plt.figure()
        ax = fig.add_subplot(1,1,1)
        for node in self.List:
            if self.active is True:
                node.draw(ax, prop_delay=0., prop_scale=1.)
        ax.set_yscale(f_axis)
        ax.set_ylabel(f_axis=="log" and "log freq (Hz)" or "freq (Hz)")
        ax.set_xlabel("time (s)")
        ax.set_title("Spectrogram")
        return fig

    def flatten_scene(self):
        """
        Clear all hierarchy in tone
{'fraction_non_alphanumeric': 0.1103618577262798, 'fraction_numerical': 0.008927723430525216, 'mean_word_length': 2.0690760711162928, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '480757', 'n_tokens_mistral': 3196, 'n_tokens_neox': 3085, 'n_words': 984}