Exemplo n.º 1
0
 def _createTablesForSave(self):
     nbRecs = self._num_rec+1
     self.dlg = wx.ProgressDialog("Saving...", "Creating files", maximum = nbRecs, parent=self._parent, 
             style = wx.PD_APP_MODAL|wx.PD_ELAPSED_TIME)
     self.count = 0
     #le timer garde la fenetre de progres a jour selon le compte
     timer = Metro(.75).play()
     trigfunc = TrigFunc(timer, self._updateProgress)
     if self._raw_data:
         for i in range(nbRecs):
             #creation de nouvelles tables avec la duree reelle des enreg.
             self._save_analyzed.append(NewTable(length=self._actual_rec_time[i], chnls=3))
             self._save_raw.append(NewTable(length=self._actual_rec_time[i], chnls=3))
             #population des nouvelles tables echantillon par echantillon
             for samp in range(self._save_analyzed[i].getSize(False)):
                 self._save_analyzed[i][0].put(self.analyzed_list[i][0].get(samp), samp)
                 self._save_analyzed[i][1].put(self.analyzed_list[i][1].get(samp), samp)
                 self._save_analyzed[i][2].put(self.analyzed_list[i][2].get(samp), samp)
                 self._save_raw[i][0].put(self.raw_list[i][0].get(samp), samp)
                 self._save_raw[i][1].put(self.raw_list[i][1].get(samp), samp)
                 self._save_raw[i][2].put(self.raw_list[i][2].get(samp), samp)
             self.count += 1
     else:
         for i in range(nbRecs):
             self._save_analyzed.append(NewTable(length=self._actual_rec_time[i], chnls=3))
             for samp in range(self._save_analyzed[i].getSize(False)):
                 self._save_analyzed[i][0].put(self.analyzed_list[i][0].get(samp), samp)
                 self._save_analyzed[i][1].put(self.analyzed_list[i][1].get(samp), samp)
                 self._save_analyzed[i][2].put(self.analyzed_list[i][2].get(samp), samp)
             self.count += 1
     timer.stop()
     trigfunc.stop()
     del timer
     del trigfunc
     del self.count
Exemplo n.º 2
0
 def __init__(self, notes=[], tempo=96):
     self.notes = [note.frequency for note in notes]
     self.times = [note.time(tempo) for note in notes]
     self.amps = [note.amp for note in notes]
     self.tempo = tempo
     self._metro = Metro()
     self.amp = Iter(self._metro, self.amps, init=self.amps[0])
     self.time = Iter(self._metro, self.times, init=self.times[0])
     self._metro.setTime(self.time)
     self.signal = Iter(self._metro, self.notes)
     #triggers are only sent when amp is >0
     self.trigger = Ceil(self.amp * self._metro)
Exemplo n.º 3
0
 def __init__(self, notes=[], tempo=96):
     self.notes = [note.frequency for note in notes]
     self.times = [note.time(tempo) for note in notes]
     self.amps = [note.amp for note in notes]
     self.tempo = tempo
     self._metro = Metro()
     self.amp = Iter(self._metro, self.amps, init=self.amps[0])
     self.time = Iter(self._metro, self.times, init=self.times[0])
     self._metro.setTime(self.time)
     self.signal = Iter(self._metro, self.notes)
     #triggers are only sent when amp is >0
     self.trigger = Ceil(self.amp*self._metro)
 def __init__(self, port, address, smoothing=0):
     self.port = port
     self.address = address
     self.smoothing = smoothing
     
     self._buffer_size = 128
     self._buffer_time = float(BUFFER_SIZE)/SAMP_RATE
     self._buffer_count = -1
     self._buffer = NewTable(self._buffer_time, chnls=3)
     self._data = []
     self._type = None
     
     self._createOSC(port, address)
     self._metro = Metro(self._buffer_time)
     self._table_rec = TrigTableRec([self._oscx,self._oscy,self._oscz], self._metro, self._buffer).stop()
     self._trig_dump = TrigFunc(self._table_rec['trig'], self._dump).stop()
Exemplo n.º 5
0
 def __init__(self, port, address, inmin=-1, inmax=1, smoothing=True):
     self.port = port
     self.address = address
     self._inmin = inmin
     self._inmax = inmax
     
     self._data = []
     self._buffer = []
     self._buffer_size = 64
     self._buffer_count = -1
     self._precision = float(BUFFER_SIZE)/SAMP_RATE
     self._trig_buffer = Trig().stop()
     self._type = None
     
     self._createOSC(port, address)
     self._metro = Metro(self._precision).play()
     if smoothing:
         self._trig_fill = TrigFunc(self._metro, self._fill_buffer_w_smooth)
     else:
         self._trig_fill = TrigFunc(self._metro, self._fill_buffer_wo_smooth)
Exemplo n.º 6
0
    def __init__(self):
        """Constructor for music_player"""
        """Make sure to call add_gui once initialized"""
        self.instruments = [] #instrument/track volume is here
        self.tempo = 120.0 #BPM (for now)
        self.global_volume = 0.75 #between 0 and 1
        self.page_index = 0 #1st page
        self.play_all = False
        self.playhead_index = 0
        self.beat_index = 0

        self.server = Server(duplex=0)
        """Set proper output device for latency-free playback on Windows"""
        """Source: https://groups.google.com/d/msg/pyo-discuss/9fvFiGbch3c/tzJTfbpLUY8J"""
        if platform.system() == "Windows":
            out_devices = pa_get_output_devices()
            od_index = 0
            for od in out_devices[0]:
                if "Primary Sound Driver" in od:
                    pai = int(out_devices[1][od_index])
                    self.server.setOutputDevice(pai)
                    break
                od_index += 1

        self.server.boot()
        self.server.start()

        metronome_time = self.SECONDS_PER_MIN / self.tempo
        self.metronome = Metro(time=metronome_time)
        self.metronome_callback = TrigFunc(self.metronome, function=self.step)
        
        # Create instruments
        wavetable_a = WaveInstrument(self, WaveInstrument.BASS)
        wavetable_b = WaveInstrument(self, WaveInstrument.LEAD)
        drums = DrumInstrument(self)
        
        self.instruments.append(wavetable_a)
        self.instruments.append(wavetable_b)
        self.instruments.append(drums)

        self.mixer_setup()
Exemplo n.º 7
0
class Sequence:
    """Sequence of midi notes and rythms using the least amount of pure python as possible """

    def __init__(self, notes=[], tempo=96):
        self.notes = [note.frequency for note in notes]
        self.times = [note.time(tempo) for note in notes]
        self.amps = [note.amp for note in notes]
        self.tempo = tempo
        self._metro = Metro()
        self.amp = Iter(self._metro, self.amps, init=self.amps[0])
        self.time = Iter(self._metro, self.times, init=self.times[0])
        self._metro.setTime(self.time)
        self.signal = Iter(self._metro, self.notes)
        #triggers are only sent when amp is >0
        self.trigger = Ceil(self.amp*self._metro)

    def append(self, note):
        self.notes.append(note.frequency)
        self.rythms.append(note.time(tempo))
        self.amps.append(note.amp)

        self.amp.setChoice(self.amps)
        self.time.setChoice(self.times)
        self.signal.setChoice(self.notes)

    def set_notes(self, notes):
        self.notes = [note.frequency for note in notes]
        self.rythms = [note.time(self.tempo) for note in notes]
        self.amps = [note.amp for note in notes]

        self.amp.setChoice(self.amps)
        self.time.setChoice(self.times)
        self.signal.setChoice(self.notes)

    def play(self):
        self._metro.play()
        return self
    def stop(self):
        self._metro.stop()
Exemplo n.º 8
0
class Sequence:
    """Sequence of midi notes and rythms using the least amount of pure python as possible """
    def __init__(self, notes=[], tempo=96):
        self.notes = [note.frequency for note in notes]
        self.times = [note.time(tempo) for note in notes]
        self.amps = [note.amp for note in notes]
        self.tempo = tempo
        self._metro = Metro()
        self.amp = Iter(self._metro, self.amps, init=self.amps[0])
        self.time = Iter(self._metro, self.times, init=self.times[0])
        self._metro.setTime(self.time)
        self.signal = Iter(self._metro, self.notes)
        #triggers are only sent when amp is >0
        self.trigger = Ceil(self.amp * self._metro)

    def append(self, note):
        self.notes.append(note.frequency)
        self.rythms.append(note.time(tempo))
        self.amps.append(note.amp)

        self.amp.setChoice(self.amps)
        self.time.setChoice(self.times)
        self.signal.setChoice(self.notes)

    def set_notes(self, notes):
        self.notes = [note.frequency for note in notes]
        self.rythms = [note.time(self.tempo) for note in notes]
        self.amps = [note.amp for note in notes]

        self.amp.setChoice(self.amps)
        self.time.setChoice(self.times)
        self.signal.setChoice(self.notes)

    def play(self):
        self._metro.play()
        return self

    def stop(self):
        self._metro.stop()
Exemplo n.º 9
0
        self._reson1Env.play(dur, delay)
        self._reson2Env.play(dur, delay)
        self._amp1Env.play(dur, delay)
        self._amp2Env.play(dur, delay)
        return PyoObject.out(self, chnl, inc, dur, delay)


# Run this script to test the Aqueous class.
if __name__ == "__main__":
    from pyo import Delay, Metro, Server, Snap, TrigXnoiseMidi, WGVerb, Pattern

    s = Server(duplex=0).boot()
    s.setAmp(1.0)
    s.start()
    t = 3.776
    metroAqueous = Metro(time=t * 2).play()
    noteAqeous = TrigXnoiseMidi(metroAqueous, dist=0, mrange=(42, 83))
    snapAqueous = Snap(noteAqeous, choice=[0, 2, 4, 5, 7, 9, 11], scale=1)
    a = Aqueous(snapAqueous, dur=t * 0.75, mul=0.9)

    def noteOn():
        a.play()

    playAqueous = Pattern(function=noteOn, time=t * 2).play()
    delay = Delay(a,
                  delay=t * 0.75,
                  feedback=0.6,
                  maxdelay=t * 0.75,
                  mul=0.445)
    wetdry = delay + a
    d = WGVerb(wetdry,
class AccDataAnalyser:
    def __init__(self, port, address, smoothing=0):
        self.port = port
        self.address = address
        self.smoothing = smoothing
        
        self._buffer_size = 128
        self._buffer_time = float(BUFFER_SIZE)/SAMP_RATE
        self._buffer_count = -1
        self._buffer = NewTable(self._buffer_time, chnls=3)
        self._data = []
        self._type = None
        
        self._createOSC(port, address)
        self._metro = Metro(self._buffer_time)
        self._table_rec = TrigTableRec([self._oscx,self._oscy,self._oscz], self._metro, self._buffer).stop()
        self._trig_dump = TrigFunc(self._table_rec['trig'], self._dump).stop()
        
    def _createOSC(self, port, address):
        if isinstance(address, list) and len(address) == 3:
            self._type = "simple"
            self._osc = OscReceive(port=port, address=address)
        elif isinstance(address, str):
            self._type = "list"
            self._osc = OscListReceive(port=port, address=address, num=3)
        else:
            print ">>>class AccDataAnalyser :\n<Error type: 'address' attribute must contain either 1 or 3 addresses>"
        self._createScaleObjs()
        
    def _createScaleObjs(self):
        if self._type == "simple":
            self._oscx = Scale(self._osc[self.address[0]], inmin=-1, inmax=1, outmin=-90, outmax=90)
            self._oscy = Scale(self._osc[self.address[1]], inmin=-1, inmax=1, outmin=-90, outmax=90)
            self._oscz = Scale(self._osc[self.address[2]], inmin=-1, inmax=1, outmin=-90, outmax=90)
        elif self._type == "list":
            self._oscx = Scale(self._osc[self.address][0], inmin=-1, inmax=1, outmin=-90, outmax=90)
            self._oscy = Scale(self._osc[self.address][1], inmin=-1, inmax=1, outmin=-90, outmax=90)
            self._oscz = Scale(self._osc[self.address][2], inmin=-1, inmax=1, outmin=-90, outmax=90)

    def _convert_data(self, buffer):
        x_data = []
        y_data = []
        z_data = []
        for i in range(self._buffer_size):
            x, y, z = buffer[0].get(i), buffer[1].get(i), buffer[2].get(i)
            degx = degrees(atan2(-y, -z) + pi);
            degy = degrees(atan2(-x, -z) + pi);
            degz = degrees(atan2(-y, -x) + pi);
            x_data.append(degx)
            y_data.append(degy)
            z_data.append(degz)
        return [x_data, y_data, z_data]
        
    def _dump(self):
        self._pending = self._buffer.copy()
        self._data.append(self._convert_data(self._pending))
        self._buffer_count += 1
        #Que fais-je maintenant de mes précieux échantillons?
        
    def _print_data(self):
        self.cpt += 1
        if self.cpt <= self.num:
            print "Buffer %d :" % self._buffer_count
            print self._data[self._buffer_count]
        else:
            print "---------------------------------------------------------"
            self.trig_print.stop()
            del self.cpt
            del self.num
            del self.trig_print
            if hasattr(self, 'percent'):
                del self.percent
            
            
    ########################
    ## Methodes publiques ##
    ########################
    def play(self):
        self._metro.play()
        self._table_rec.play()
        self._trig_dump.play()
        return self
        
    def stop(self):
        self._metro.stop()
        self._table_rec.stop()
        self._trig_dump.stop()
        
    def print_data(self, num, step=1):
        self.cpt = 0
        self.num = num
        print "\n>>>class AccDataAnalyser"
        if step > 1:
            print "[[X list], [Y list], [Z list]] Data for %d buffers in steps of %d." % (num, step)
            self.percent = Percent(self._table_rec['trig'], percent=100./step)
            self.trig_print = TrigFunc(self.percent, self._print_data)
        else:
            print "[[X list], [Y list], [Z list]] Data for %d buffer(s)." % num
            self.trig_print = TrigFunc(self._table_rec['trig'], self._print_data)
Exemplo n.º 11
0
ESC = 27
PLUS = 43
MINUS = 45

notes1 = ['a', 'b', 'c']
notes2 = ['d', 'g', 'h']
notes3 = ['e', 'f', 'i', 'j']

screen = pygame.display.set_mode((800, 600))

run = True

server = Server().boot()
server.start()

met = Metro(.125, 12).play()

players.append(Player(met, notes1))
players.append(Player(met, notes2))
players.append(Player(met, notes3))

while run:
    for event in pygame.event.get():
        if event.type == pygame.KEYUP:
            for player in players:
                player.note_off(chr(event.key))

            if event.key == ESC:
                run = False
                break
            if event.key == PLUS:
Exemplo n.º 12
0
# <http://code.google.com/p/pyo>.
# Latest version always available at <http://gist.github.com/tildebyte>.
# Copyright (C) 2014  Ben Alkov <*****@*****.**>

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version <http://www.gnu.org/licenses/>.
from pyo import Delay, Snap, Metro, TrigXnoiseMidi, WGVerb

from ground_state.pyo.instruments.whale import Whale
from ground_state.pyo.utils.tempo import Tempo
from ground_state.pyo.utils.dbToAmp import dbToAmp
from ground_state.pyo.utils.serverSetup import serverSetup


t = Tempo(63.5)
# OSX
s = serverSetup(2, 192, 'coreaudio')

metro = Metro(time=t.whole * 4).play()
note = TrigXnoiseMidi(metro, dist=0, mrange=(30, 41))
snap = Snap(note, choice=[0, 2, 4, 5, 7, 9, 11], scale=1)
w = Whale(snap, metro, dur=t.whole, mul=0.9)
delay = Delay(w, delay=t.whole, feedback=0.64,
              maxdelay=t.whole, mul=dbToAmp(-6))
wetdry = delay + w
d = WGVerb(wetdry, feedback=[0.73, 0.76], cutoff=5000,
           bal=dbToAmp(-12.04), mul=dbToAmp(-10.5)).out()
s.gui(locals())
Exemplo n.º 13
0
class MusicPlayer:
    """Playback engine for sequencer samples and sounds"""

    NUM_PAGES = 8
    NUM_ROWS = 8
    NUM_COLS = 8
    NUM_TRACKS = 3
    NUM_BEATS = NUM_PAGES * NUM_COLS

    SECONDS_PER_MIN = 60.0

    # Parameters for GUI to build sliders
    MIN_TEMPO = 40.0
    MAX_TEMPO = 240.0
    MIN_VOLUME = 0.0
    MAX_VOLUME = 1.0
    MIN_REVERB = 0.0
    MAX_REVERB = 1.0 

    # Instrument descriptive constants
    WAVETABLE_A = 0
    WAVETABLE_B = 1
    DRUM_KIT = 2

    def __init__(self):
        """Constructor for music_player"""
        """Make sure to call add_gui once initialized"""
        self.instruments = [] #instrument/track volume is here
        self.tempo = 120.0 #BPM (for now)
        self.global_volume = 0.75 #between 0 and 1
        self.page_index = 0 #1st page
        self.play_all = False
        self.playhead_index = 0
        self.beat_index = 0

        self.server = Server(duplex=0)
        """Set proper output device for latency-free playback on Windows"""
        """Source: https://groups.google.com/d/msg/pyo-discuss/9fvFiGbch3c/tzJTfbpLUY8J"""
        if platform.system() == "Windows":
            out_devices = pa_get_output_devices()
            od_index = 0
            for od in out_devices[0]:
                if "Primary Sound Driver" in od:
                    pai = int(out_devices[1][od_index])
                    self.server.setOutputDevice(pai)
                    break
                od_index += 1

        self.server.boot()
        self.server.start()

        metronome_time = self.SECONDS_PER_MIN / self.tempo
        self.metronome = Metro(time=metronome_time)
        self.metronome_callback = TrigFunc(self.metronome, function=self.step)
        
        # Create instruments
        wavetable_a = WaveInstrument(self, WaveInstrument.BASS)
        wavetable_b = WaveInstrument(self, WaveInstrument.LEAD)
        drums = DrumInstrument(self)
        
        self.instruments.append(wavetable_a)
        self.instruments.append(wavetable_b)
        self.instruments.append(drums)

        self.mixer_setup()
    
    def mixer_setup(self):
        # Combine all tracks in mixer
        self.track_mixer = Mixer(outs=1)
        for inst_index in range(0, len(self.instruments)):
            instrument = self.instruments[inst_index]
            generator = instrument.get_generator()
            self.track_mixer.addInput(inst_index, generator)
            self.track_mixer.setAmp(inst_index, 0, instrument.get_volume())
        
        # Prepare master output
        self.master_out = Mixer(outs=1, chnls=2)
        self.master_out.addInput(0, self.track_mixer[0])
        self.master_out.setAmp(0, 0, self.global_volume)
        self.master_out.out()

    def add_gui(self, gui):
        """ Sets the GUI that this music player must instruct to update playhead.
        Must be called right after constructor before operation.

        Arguments:
        gui: GUI object monitoring this player

        """
        self.gui = gui
    
    def terminate(self):
        """Terminate MusicPlayer server in preparation for shutdown"""
        self.server.stop()
        self.server.shutdown()

    def step(self):
        """ Step the music player through next beat """
        # Set GUI to reflect current beat
        self.gui.update_playhead()
        
        # Play step for instruments
        for instrument in self.instruments:
            instrument.play_step()

        # For next iteration, increment playhead and beat indices
        self.playhead_index = (self.playhead_index + 1) % self.NUM_COLS
        if (self.play_all == True):
            self.beat_index = (self.beat_index + 1) % self.NUM_BEATS
        elif (self.play_all == False):
            self.beat_index = (self.page_index * self.NUM_COLS) +\
                              self.playhead_index

    def add_network_handler(self, network_handler):
        self.network_handler = network_handler
        
    """playback methods"""
    def play(self):
        self.metronome.play()

    def pause(self):
        for instrument in self.instruments:
            instrument.pause()
        self.metronome.stop()

    def set_session(self, session):
        """used to load a session into the music player"""
        # Reload pertinent MusicPlayer variables
        self.set_tempo(session.tempo)

        # Reconstruct each instrument from session data
        self.instruments = []
        instrument_data = session.instrument_data
        for data in instrument_data:
            volume = data.volume
            reverb_mix = data.reverb_mix
            notes = data.notes
            if isinstance(data, WaveInstrumentData):
                wavetype = data.wavetype
                wave_instrument = WaveInstrument(self, wavetype, volume, 
                                                 reverb_mix, notes)
                self.instruments.append(wave_instrument)
            elif isinstance(data, DrumInstrumentData):
                drum_instrument = DrumInstrument(self, volume, reverb_mix,
                                                 notes)
                self.instruments.append(drum_instrument)

        # Reload mixer to reflect new instruments
        self.mixer_setup()

    """ Modifiers """
    def set_note(self, note):
        instrument = self.instruments[note.track_id]
        instrument.set_note(note)

    def set_global_volume(self, volume):
        self.global_volume = volume
        self.master_out.setAmp(0, 0, volume)

    def set_volume(self, track_id, volume):
        self.instruments[track_id].set_volume(volume)
        self.track_mixer.setAmp(track_id, 0, volume)
    
    def set_reverb(self, track_id, reverb):
        self.instruments[track_id].set_reverb(reverb)

    def set_tempo(self, new_tempo):
        new_time = self.SECONDS_PER_MIN / new_tempo
        self.metronome.setTime(new_time)
        self.tempo = new_tempo

    """getter methods"""
    def get_session(self):
        """Get descriptive MusicPlayer session to restore later"""
        session = Session(self, self.instruments)
        return session

    """getter methods for GUI"""
    def get_names(self, track_id):
        return self.instruments[track_id].get_names()

    def get_reverb(self, track_id):
        return self.instruments[track_id].get_reverb()

    def get_volume(self, track_id):
        return self.instruments[track_id].get_volume()

    def get_global_volume(self):
        return self.global_volume

    def get_tempo(self):
        return self.tempo

    def get_note(self, track_id, page_index, position, pitch):
        pass

    def get_current_page(self, track_id):
        instrument = self.instruments[track_id]
        notes = instrument.get_page(self.page_index)
        return notes
Exemplo n.º 14
0
# (at your option) any later version <http://www.gnu.org/licenses/>.
from pyo import Delay, Metro, Pattern, Snap, STRev, TrigXnoiseMidi

# iPython: %cd \path\to\pyo\files
from ground_state.pyo.instruments.aqueous import Aqueous
from ground_state.pyo.instruments.whale import Whale
from ground_state.pyo.utils.tempo import Tempo
from ground_state.pyo.utils.dbToAmp import dbToAmp
from ground_state.pyo.utils.serverSetup import serverSetup

t = Tempo(63.5)  # q=944ms, w=3.776s
# Windows
# server = serverSetup(10, 700)
# OSX
server = serverSetup(2, 192, 'coreaudio')
metroWhale = Metro(time=t.whole * 4).play()
metroAqueous = Metro(time=t.whole).play()
noteWhale = TrigXnoiseMidi(metroWhale, dist=0, mrange=(30, 41))
noteAqeous = TrigXnoiseMidi(metroAqueous, dist=0, mrange=(42, 83))
snapWhale = Snap(noteWhale, choice=[0, 2, 4, 5, 7, 9, 11], scale=1)
snapAqueous = Snap(noteAqeous, choice=[0, 2, 4, 5, 7, 9, 11], scale=1)
whale = Whale(snapWhale, metroWhale, dur=t.whole, mul=dbToAmp(-9.0))
aqueous = Aqueous(snapAqueous, dur=t.whole * 2, mul=dbToAmp(-12.0))


def noteOn():
    aqueous.play()


playAqueous = Pattern(function=noteOn, time=t.whole * 2).play()
delayWhale = Delay(whale,
"""
Python code snippets vol 39:
stevepython.wordpress.com

191-Generate melodies

requirements: pip3 install pyo

source:
http://ajaxsoundstudio.com/software/pyo/

"""
from pyo import CosTable, Metro, Osc, Server
from pyo import SquareTable, TrigEnv, TrigXnoiseMidi

s = Server().boot()
s.start()
wav = SquareTable()
env = CosTable([(0, 0), (100, 1), (500, .3), (8191, 0)])
met = Metro(.125, 12).play()
amp = TrigEnv(met, table=env, dur=1, mul=.1)
pit = TrigXnoiseMidi(met, dist='loopseg', x1=20, scale=1, mrange=(48, 84))
out = Osc(table=wav, freq=pit, mul=amp).out()
Exemplo n.º 16
0
class AccDataReceiver:
    """
    >>>class AccDataReceiver
    
    Receives accelerometre data, converts it to degrees and smoothes it.
    
    Attr : port : Integer. Port to listen on.
           address : String. Address(es) that carries the data.
           smoothing : Boolean. Applies a gaussian smoother.
    
    Notes : - Give only one address if the stream is a list. If the
              data is coming on three different addresses, put them
              in a list as follows ["x_addr", "y_addr", "z_addr"].
            
            - Attributes are available at initialization only.
           
    User can retreive original streams as follows : obj['coord']
    where coord is x, y or z.
    
    User can also retreive a stream of triggers informing when a buffer
    has been filled the following way : obj['trig'].
    """
    def __init__(self, port, address, inmin=-1, inmax=1, smoothing=True):
        self.port = port
        self.address = address
        self._inmin = inmin
        self._inmax = inmax
        
        self._data = []
        self._buffer = []
        self._buffer_size = 64
        self._buffer_count = -1
        self._precision = float(BUFFER_SIZE)/SAMP_RATE
        self._trig_buffer = Trig().stop()
        self._type = None
        
        self._createOSC(port, address)
        self._metro = Metro(self._precision).play()
        if smoothing:
            self._trig_fill = TrigFunc(self._metro, self._fill_buffer_w_smooth)
        else:
            self._trig_fill = TrigFunc(self._metro, self._fill_buffer_wo_smooth)
        
    def __getitem__(self, i):
        if i == 'trig':
            return self._trig_buffer
        if i == 'x':
            return self._oscx
        if i == 'y':
            return self._oscy
        if i == 'z':
            return self._oscz
        
    def _createOSC(self, port, address):
        if isinstance(address, list) and len(address) == 3:
            self._type = "simple"
            self._osc = OscReceive(port=port, address=address)
        elif isinstance(address, str):
            self._type = "list"
            self._osc = OscListReceive(port=port, address=address, num=3)
        else:
            print ">>>class AccDataAnalyser :\n<Error type: 'address' attribute must contain either 1 or 3 addresses>"
        self._createScaleObjs()
        
    def _createScaleObjs(self):
        if self._type == "simple":
            self._oscx = Scale(self._osc[self.address[0]], inmin=self._inmin, inmax=self._inmax, outmin=-90, outmax=90)
            self._oscy = Scale(self._osc[self.address[1]], inmin=self._inmin, inmax=self._inmax, outmin=-90, outmax=90)
            self._oscz = Scale(self._osc[self.address[2]], inmin=self._inmin, inmax=self._inmax, outmin=-90, outmax=90)
        elif self._type == "list":
            self._oscx = Scale(self._osc[self.address][0], inmin=self._inmin, inmax=self._inmax, outmin=-90, outmax=90)
            self._oscy = Scale(self._osc[self.address][1], inmin=self._inmin, inmax=self._inmax, outmin=-90, outmax=90)
            self._oscz = Scale(self._osc[self.address][2], inmin=self._inmin, inmax=self._inmax, outmin=-90, outmax=90)

    def _convert_data(self):
        x, y, z = self._oscx.get(), self._oscy.get(), self._oscz.get()
        degx = degrees(atan2(-y, -z) + pi)
        degy = degrees(atan2(-x, -z) + pi)
        degz = degrees(atan2(-y, -x) + pi)
        return [degx,degy,degz]
        
    ## Method when smoothing is on
    def _dump_w_smooth(self):
        self._pending = copy(self._buffer)
        del self._buffer[:]
        self._buffer_count += 1
        self.call = CallAfter(self._smoother, .005)
        
    ## Method when smoothing is on
    def _fill_buffer_w_smooth(self):
        if len(self._buffer) < self._buffer_size:
            self._buffer.append(self._convert_data())
        else:
            self._dump_w_smooth()
            self._buffer.append(self._convert_data())
            
    ## Method when smoothing is off
    def _dump_wo_smooth(self):
        self._pending = copy(self._buffer)
        del self._buffer[:]
        self._buffer_count += 1
        self.call = CallAfter(self._reorder, .005)
        
    ## Method when smoothing is off
    def _fill_buffer_wo_smooth(self):
        if len(self._buffer) < self._buffer_size:
            self._buffer.append(self._convert_data())
        else:
            self._dump_wo_smooth()
            self._buffer.append(self._convert_data())
        
    def _print_data(self):
        self.cpt += 1
        if self.cpt <= self.num:
            self.temp_data.append(self._pending)
            self.temp_id.append(self._buffer_count)
        else:
            self.trig_print.stop()
            if self.print_mode == 0:
                print "\n>>>class AccDataAnalyser :"
                print "Data for %d buffer(s)." % self.num
                for i in range(self.num):
                    print "\nBuffer %d" % self.temp_id[i]
                    print "------------------------------------"
                    for j in range(self._buffer_size):
                        print "X: %.3f, Y: %.3f, Z: %.3f" % (self.temp_data[i][j][0],
                                                             self.temp_data[i][j][1],
                                                             self.temp_data[i][j][2])
                print "------------------------------------"
            elif self.print_mode == 1:
                file = open(SAVE_PATH+"RAW_DATA_ACCELEROMETER.txt", "w")
                for i in range(self.num):
                    file.write("Buffer %d\n" % self.temp_id[i])
                    for j in range(3):
                        if j == 0:
                            file.write("X : [")
                        if j == 1:
                            file.write("Y : [")
                        if j == 2:
                            file.write("Z : [")
                        for k in range(self._buffer_size):
                            file.write("%.3f" % self.temp_data[i][k][j])
                            if k < self._buffer_size-1:
                                file.write(", ")
                        file.write("]")
                        file.write("\n")
                    if i < self.num-1:
                        file.write("\n")
                file.close()
            del self.trig_print
            del self.cpt
            del self.temp_data
            del self.temp_id
            del self.num
            del self.print_mode
            
    def _reorder(self):
        x = [self._pending[i][0] for i in range(self._buffer_size)]
        y = [self._pending[i][1] for i in range(self._buffer_size)]
        z = [self._pending[i][2] for i in range(self._buffer_size)]
        
        self._data.append([x, y, z])
        self._trig_buffer.play()
        
    def _smoother(self, degree=5):
        x = [self._pending[i][0] for i in range(self._buffer_size)]
        y = [self._pending[i][1] for i in range(self._buffer_size)]
        z = [self._pending[i][2] for i in range(self._buffer_size)]
        
        smooth_x = self._gaussianListSmoother(x)
        smooth_y = self._gaussianListSmoother(y)
        smooth_z = self._gaussianListSmoother(z)
        
        self._data.append([smooth_x, smooth_y, smooth_z])
        self._trig_buffer.play()
        
    def _gaussianListSmoother(self, buffer, degree=5):
        """
        Smoothing algorithm from Scott W. Harden
        Source : http://www.swharden.com/blog/2008-11-17-linear-data-smoothing-in-python/
        """
        #Solution temporaire pour agrandir la liste de 9 elems
        #l'algorithme perd des donnees en cours de route
        #valide seulement pour un buffer de 64 et un degree de 5
        list = [buffer[0]]*5
        for i in range(len(buffer)):list.append(buffer[i])
        for i in range(4):list.append(buffer[-1])
        #########################################
        window=degree*2-1  

        weight=numpy.array([1.0]*window)
        weightGauss=[]
        
        for i in range(window):  
            i=i-degree+1
            frac=i/float(window)
            gauss=1/(numpy.exp((4*(frac))**2))
            weightGauss.append(gauss)
            
        weight=numpy.array(weightGauss)*weight  
        smoothed=[0.0]*(len(list)-window)  

        for i in range(len(smoothed)):
            smoothed[i]=sum(numpy.array(list[i:i+window])*weight)/sum(weight)
        
        return smoothed
            
    ########################
    ## Methodes publiques ##
    ########################
    def get(self):
        """
        Returns last completed buffer after being smoothed.
        """
        return self._data[self._buffer_count]
        
    def getData(self):
        """
        Returns all data since the begining of the app.
        Data is smoothed and not raw.
        """
        return self._data
        
    def getBufferSize(self):
        return self._buffer_size
        
    def play(self):
        """
        Starts processing the accelerometer data.
        """
        self._metro.play()
        self._trig_fill.play()
        self._osc.play()
        return self
        
    def stop(self):
        """
        Stops processing the accelerometer data.
        """
        self._metro.stop()
        self._trig_fill.stop()
        self._osc.stop()
        return self
        
    def print_data(self, num, mode=0):
        """
        num : nunmber of buffers to print
        mode=0 : prints info on screen
        mode=1 : saves data to a .txt file where specified in the preferences
        """
        self.cpt = 0
        self.num = num
        self.temp_data = []
        self.temp_id = []
        self.print_mode = mode
        self.trig_print = TrigFunc(self._trig_buffer, self._print_data)