class Module(BaseModule):
    """
    "Algorithmic beat maker module"
    
    Description

    Four voices beat generator where sounds are extracted from a soundfile.

    Sliders
    
        # Num of Taps : 
            Number of taps in a measure
        # Tempo : 
            Speed of taps in BPM (ref. to quarter note)
        # Beat 1 Tap Length : 
            Length of taps of the first beat, in seconds
        # Beat 1 Index : 
            Soundfile index of the first beat
        # Beat 1 Gain : 
            Gain of the first beat
        # Beat 1 Distribution : 
            Repartition of taps for the first beat (100% weak <--> 100% down)
        # Beat 2 Tap Length : 
            Length of taps of the second beat, in seconds
        # Beat 2 Index : 
            Soundfile index of the second beat
        # Beat 2 Gain : 
            Gain of the second beat
        # Beat 2 Distribution : 
            Repartition of taps for the second beat (100% weak <--> 100% down)
        # Beat 3 Tap Length : 
            Length of taps of the third beat, in seconds
        # Beat 3 Index : 
            Soundfile index of the third beat
        # Beat 3 Gain : 
            Gain of the third beat
        # Beat 3 Distribution : 
            Repartition of taps for the third beat (100% weak <--> 100% down)
        # Beat 4 Tap Length : 
            Length of taps of the fourth beat, in seconds
        # Beat 4 Index : 
            Soundfile index of the fourth beat
        # Beat 4 Gain : 
            Gain of the fourth beat
        # Beat 4 Distribution : 
            Repartition of taps for the fourth beat (100% weak <--> 100% down)
        # Global Seed : 
            Seed value for the algorithmic beats, using the same seed with 
            the same distributions will yield the exact same beats.
        
    Graph Only
    
        # Beat 1 ADSR : 
            Envelope of taps for the first beat in breakpoint fashion
        # Beat 2 ADSR : 
            Envelope of taps for the second beat in breakpoint fashion
        # Beat 3 ADSR : 
            Envelope of taps for the third beat in breakpoint fashion
        # Beat 4 ADSR : 
            Envelope of taps for the fourth beat in breakpoint fashion
        # Overall Amplitude : 
            The amplitude curve applied on the total duration of the performance

    """
    def __init__(self):
        BaseModule.__init__(self)
        self.snd = self.addFilein("snd")
        self.last_we1 =self.last_we2 = self.last_we3 = self.last_we4 = self.last_taps = -1
        self.rtempo = 1/(self.tempo/15)
        self.setGlobalSeed(int(self.seed.get()))
        w1, w2, w3 = self.newdist1(int(self.we1.get()))
        self.beat1 = Beat(time=self.rtempo, taps=int(self.taps.get()), w1=w1, w2=w2, w3=w3, poly=10).play()
        w1, w2, w3 = self.newdist2(int(self.we2.get()))
        self.beat2 = Beat(time=self.rtempo, taps=int(self.taps.get()), w1=w1, w2=w2, w3=w3, poly=10).play()
        w1, w2, w3 = self.newdist3(int(self.we3.get()))
        self.beat3 = Beat(time=self.rtempo, taps=int(self.taps.get()), w1=w1, w2=w2, w3=w3, poly=10).play()
        w1, w2, w3 = self.newdist4(int(self.we4.get()))
        self.beat4 = Beat(time=self.rtempo, taps=int(self.taps.get()), w1=w1, w2=w2, w3=w3, poly=10).play()
        self.tre1 = TrigEnv(input=self.beat1, table=self.adsr1, dur=self.tapsl1, mul=self.beat1['amp'])
        self.tre2 = TrigEnv(input=self.beat2, table=self.adsr2, dur=self.tapsl2, mul=self.beat2['amp'])
        self.tre3 = TrigEnv(input=self.beat3, table=self.adsr3, dur=self.tapsl3, mul=self.beat3['amp'])
        self.tre4 = TrigEnv(input=self.beat4, table=self.adsr4, dur=self.tapsl4, mul=self.beat4['amp'])
        self.linseg1 = TrigLinseg(input=self.beat1, list=[(0,self.bindex1.get()),(self.tapsl1.get(),1/(self.snd.getDur(False)/self.tapsl1.get())+self.bindex1.get())])
        self.linseg2 = TrigLinseg(input=self.beat2, list=[(0,self.bindex2.get()),(self.tapsl2.get(),(1/(self.snd.getDur(False)/self.tapsl2.get()))+self.bindex2.get())])
        self.linseg3 = TrigLinseg(input=self.beat3, list=[(0,self.bindex3.get()),(self.tapsl3.get(),(1/(self.snd.getDur(False)/self.tapsl3.get()))+self.bindex3.get())])
        self.linseg4 = TrigLinseg(input=self.beat4, list=[(0,self.bindex4.get()),(self.tapsl4.get(),(1/(self.snd.getDur(False)/self.tapsl4.get()))+self.bindex4.get())])
        self.trf1 = TrigFunc(self.linseg1['trig'], self.newseg1)
        self.trf2 = TrigFunc(self.linseg2['trig'], self.newseg2)
        self.trf3 = TrigFunc(self.linseg3['trig'], self.newseg3)
        self.trf4 = TrigFunc(self.linseg4['trig'], self.newseg4)
        self.again1 = DBToA(self.gain1, mul=0.7)
        self.again2 = DBToA(self.gain2, mul=0.7)
        self.again3 = DBToA(self.gain3, mul=0.7)
        self.again4 = DBToA(self.gain4, mul=0.7)
        self.pointer1 = Pointer(table=self.snd, index=self.linseg1, mul=self.tre1*self.again1)
        self.pointer2 = Pointer(table=self.snd, index=self.linseg2, mul=self.tre2*self.again2)
        self.pointer3 = Pointer(table=self.snd, index=self.linseg3, mul=self.tre3*self.again3)
        self.pointer4 = Pointer(table=self.snd, index=self.linseg4, mul=self.tre4*self.again4)
        self.mixx = self.pointer1+self.pointer2+self.pointer3+self.pointer4
        self.out = Sig(self.mixx, mul=self.env).mix(self.nchnls)

        self.trigend = TrigFunc(self.beat1["end"], self.newdist)

    def seed_up(self, value):
        self.setGlobalSeed(int(value))
        self.beat1.new()
        self.beat2.new()
        self.beat3.new()
        self.beat4.new()

    def newseg1(self):
        self.linseg1.setList([(0,self.bindex1.get()),(self.tapsl1.get(),1/(self.snd.getDur(False)/self.tapsl1.get())+self.bindex1.get())])

    def newseg2(self):
        self.linseg2.setList([(0,self.bindex2.get()),(self.tapsl2.get(),1/(self.snd.getDur(False)/self.tapsl2.get())+self.bindex2.get())])

    def newseg3(self):
        self.linseg3.setList([(0,self.bindex3.get()),(self.tapsl3.get(),1/(self.snd.getDur(False)/self.tapsl3.get())+self.bindex3.get())])

    def newseg4(self):
        self.linseg4.setList([(0,self.bindex4.get()),(self.tapsl4.get(),1/(self.snd.getDur(False)/self.tapsl4.get())+self.bindex4.get())])

    def newtaps(self, value):
        self.beat1.setTaps(value)
        self.beat2.setTaps(value)
        self.beat3.setTaps(value)
        self.beat4.setTaps(value)

    def newdist1(self, value):
        w1 = value
        if value <= 50:
            w2 = value*2
        else:
            w2 = (100-value)*2
        w3 = 100-value
        return (w1, w2, w3)
        
    def newdist2(self, value):
        w1 = value
        if value <= 50:
            w2 = value*2
        else:
            w2 = (100-value)*2
        w3 = 100-value
        return (w1, w2, w3)
        
    def newdist3(self, value):
        w1 = value
        if value <= 50:
            w2 = value*2
        else:
            w2 = (100-value)*2
        w3 = 100-value
        return (w1, w2, w3)
        
    def newdist4(self, value):
        w1 = value
        if value <= 50:
            w2 = value*2
        else:
            w2 = (100-value)*2
        w3 = 100-value
        return (w1, w2, w3)

    def newdist(self):
        taps = int(self.taps.get())
        if taps != self.last_taps:
            self.last_taps = taps
            self.newtaps(taps)
        value = int(self.we1.get())
        if value != self.last_we1:
            self.last_we1 = value
            self.beat1.setWeights(*self.newdist1(value))
        value = int(self.we2.get())
        if value != self.last_we2:
            self.last_we2 = value
            self.beat2.setWeights(*self.newdist2(value))
        value = int(self.we3.get())
        if value != self.last_we3:
            self.last_we3 = value
            self.beat3.setWeights(*self.newdist3(value))
        value = int(self.we4.get())
        if value != self.last_we4:
            self.last_we4 = value
            self.beat4.setWeights(*self.newdist4(value))

Interface = [   cfilein(name="snd", label="Audio"),
                cgraph(name="env", label="Overall Amplitude", func=[(0,1),(1,1)], col="blue"),
                cgraph(name="adsr1", label="Beat 1 ADSR", func=[(0,0),(0.001,1),(0.125,0.25),(1,0)], table=True, col="blue1"),
                cgraph(name="adsr2", label="Beat 2 ADSR", func=[(0,0),(0.005,1),(0.135,0.3),(1,0)], table=True, col="purple1"),
                cgraph(name="adsr3", label="Beat 3 ADSR", func=[(0,0),(0.01,1),(0.145,0.35),(1,0)], table=True, col="red1"),
                cgraph(name="adsr4", label="Beat 4 ADSR", func=[(0,0),(0.015,1),(0.155,0.4),(1,0)], table=True, col="green1"),
                cslider(name="taps", label="Num of Taps", min=1, max=64, init=16, res="int", rel="lin", unit="x", col= "orange1"),
                cslider(name="tempo", label="Tempo", min=20, max=240, gliss=0, init=120, rel="lin", unit="bpm", col="orange3"),
                cslider(name="tapsl1", label="Beat 1 Tap Length", min=0.01, max=1, init=0.2, rel="lin", unit="sec", col="blue1",half=True),
                cslider(name="tapsl3", label="Beat 3 Tap Length", min=0.01, max=1, init=0.2, rel="lin", unit="sec", col="red1",half=True),
                cslider(name="bindex1", label="Beat 1 Index", min=0, max=1, init=0, rel="lin", unit="x", col="blue2",half=True),
                cslider(name="bindex3", label="Beat 3 Index", min=0, max=1, init=0.25, rel="lin", unit="x", col="red2",half=True),
                cslider(name="gain1", label="Beat 1 Gain", min=-48, max=18, init=0, rel="lin", unit="dB", col="blue3",half=True),
                cslider(name="gain3", label="Beat 3 Gain", min=-48, max=18, init=0, rel="lin", unit="dB", col="red3",half=True),
                cslider(name="we1", label="Beat 1 Distribution", min=0, max=100, init=80, res="int", rel="lin", unit="%", col="blue4",half=True),
                cslider(name="we3", label="Beat 3 Distribution", min=0, max=100, init=30, rel="lin", res="int", unit="%", col="red4",half=True),
                cslider(name="tapsl2", label="Beat 2 Tap Length", min=0.01, max=1, init=0.2, rel="lin", unit="sec", col="purple1",half=True),
                cslider(name="tapsl4", label="Beat 4 Tap Length", min=0.01, max=1, init=0.2, rel="lin", unit="sec", col="green1",half=True),
                cslider(name="bindex2", label="Beat 2 Index", min=0, max=1, init=0.5, rel="lin", unit="x", col="purple2",half=True),
                cslider(name="bindex4", label="Beat 4 Index", min=0, max=1, init=0.75, rel="lin", unit="x", col="green2",half=True),
                cslider(name="gain2", label="Beat 2 Gain", min=-48, max=18, init=0, rel="lin", unit="dB", col="purple3",half=True),
                cslider(name="gain4", label="Beat 4 Gain", min=-48, max=18, init=0, rel="lin", unit="dB", col="green3",half=True),
                cslider(name="we2", label="Beat 2 Distribution", min=0, max=100, init=50, rel="lin", res="int", unit="%", col="purple4",half=True),
                cslider(name="we4", label="Beat 4 Distribution", min=0, max=100, init=10, rel="lin",  res="int", unit="%", col="green4",half=True),
                cslider(name="seed", label="Global seed", min=0, max=5000, init=0, rel="lin", res="int", unit="x", up=True),
          ]

