class Aqueous(PyoObject): """ Aqueous 1.0 This instrument is (loosely) based on a favorite patch from the Analog synthesizer device in Ableton Live. Doesn't really sound like the original at all, but I like it... Meant for a MIDI range of 30-77. Signal chain: saw1 -> reson1 -> resonEnv -> ampEnv -> filter -> out |________ ^ | | saw2 -> reson2 -> resonEnv --->| We have four independent envelopes (reson1Env, reson2Env, amp1Env, amp2Env) with slightly different sustain levels/timing. The envelopes are the most complex aspect of this instrument. I don't entirely understand what goes on here (design by tweak). :Parent: :py:class:`PyoObject` :Args: freq : PyoObject Frequency to generate. dur : float Time in seconds for the instrument to play once triggered. """ def __init__(self, freq=1000, dur=1, mul=1, add=0): PyoObject.__init__(self, mul, add) self._freq = freq self._dur = dur self._mul = mul self._add = add # Begin processing. # 1st Saw oscillator. saw1Table = SawTable(order=50, size=24000).normalize() self._saw1 = Osc(saw1Table, self._freq, interp=4, mul=0.6839) # Dummy amplitude knobs to split Saw 1 into two paths with independent # amplitudes. # Out to Reson1. saw1Dummy1 = self._saw1 * 1.0 saw1Dummy1.setMul(0.63) # Out to Reson2. saw1Dummy2 = self._saw1 * 1.0 saw1Dummy2.setMul(0.38) # 1st Resonant filter. # total duration = note value + 1954ms # sustain at 95% self._reson1Env = Adsr(1.280, 0.097, 0.95, 0.577, dur=self._dur) reson1 = EQ(saw1Dummy1, freq=self._freq, q=100, boost=3.0, type=1, mul=self._reson1Env * 0.7079) # Dummy amplitude knob; lets us more easily balance the filter levels. reson1Dummy = reson1 * 1.0 # 2nd Saw oscillator. saw2Table = SawTable(order=50, size=24000).normalize() self._saw2 = Osc(saw2Table, self._freq / 2, interp=4, mul=0.5433) # Dummy amplitude knob to allow mixing with Saw1, going into Reson2. saw2Dummy = self._saw2 * 1.0 saw2Dummy.setMul(0.38) # 2nd Resonant filter. # total duration = note value + 1954ms # sustain at 53% self._reson2Env = Adsr(1.280, 0.097, 0.53, 0.577, dur=self._dur) reson2 = EQ(saw1Dummy2 + saw2Dummy, freq=self._freq + 1300, q=100, boost=3.0, type=1, mul=self._reson2Env * 0.7079) # Dummy amplitude knob; lets us more easily balance the filter levels. reson2Dummy = reson2 * 1.0 # Amplitude envelopes for the filters. # total duration = note value + 1954ms # sustain at %100 self._amp1Env = Adsr(0.577, 0.097, 1.0, 1.280, dur=self._dur) # total duration = note value + 1862ms # sustain at %100 self._amp2Env = Adsr(0.577, 0.005, 1.0, 1.280, dur=self._dur) # Tweak filter levels reson1Dummy.setMul(self._amp1Env * 0.3) reson2Dummy.setMul(self._amp2Env * 0.4842) filtersDummy = reson1Dummy + reson2Dummy bpf = ButBP(filtersDummy, freq=325, q=1) # Volume knob aqueous = Mix(bpf, mul=self._mul) self._base_objs = aqueous.getBaseObjects() def setFreq(self, x): """ Replace the `freq` attribute. :Args: x : float or PyoObject New `freq` attribute. """ self._freq = x self._saw1.freq = x self._saw2.freq = x @property def freq(self): """float or PyoObject. Frequency.""" return self._freq @freq.setter def freq(self, x): self.setFreq(x) def __dir__(self): return ["freq", "mul", "add"] def play(self, dur=0, delay=0): self._reson1Env.play(dur, delay) self._reson2Env.play(dur, delay) self._amp1Env.play(dur, delay) self._amp2Env.play(dur, delay) return PyoObject.play(self, dur, delay) def stop(self): self._reson1Env.stop() self._reson2Env.stop() self._amp1Env.stop() self._amp2Env.stop() return PyoObject.stop(self) def out(self, chnl=0, inc=1, dur=0, delay=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)