Just as an addition, this doesn't work either:
p1Env = MidiAdsr(note['velocity'], attack=0.1, decay=0.01, sustain=0.1, release=0.1)
p2Env = MidiAdsr(note['velocity'], attack=5, decay=0.01, sustain=0.2, release=0.1)
t = HarmTable([1*p1Env]+[0.07*p2Env]+[0.01]+[0.003]+[0]*20, size=512)
I think this probably cuts to the heart of the issue which is that (correct me if I'm wrong), these tables are arrays, and we can't assign a dynamic value like an envelope to array addresses. In this case, I think the way to go seems to be to create a bank of sine waves each assigned their own envelope, or if that's too processing intensive, to create a bank of harmonic tables that are stacked or latticed somehow.
TLDR is: can we assign independent operators to the partials of HarmTable. It seems like the answer is no.
This seems to be working for four partials:
from pyo import *
s = Server()
s.setMidiInputDevice(99)
s.boot()
randDev = Sig(1)
note = Notein(poly=10, scale=0, first=0, last=127, channel=0, mul=1)
note.keyboard()
p1Env = MidiAdsr(note['velocity'], attack=0.1, decay=0.02, sustain=0.3, release=0.1, mul=1)
p2Env = MidiAdsr(note['velocity'], attack=0.2, decay=0.04, sustain=0.2, release=0.1, mul=1)
p3Env = MidiAdsr(note['velocity'], attack=0.05, decay=0.01, sustain=0.1, release=0.1, mul=1)
p4Env = MidiAdsr(note['velocity'], attack=0.07, decay=0.008, sustain=0.05, release=0.1, mul=1)
noiseEnv = MidiAdsr(note['velocity'], attack=0.001, decay=0.146, sustain=0.158, release=0.1)
freq = MToF(note['pitch'])
noise = PinkNoise(5) * noiseEnv
noise = Reson(noise, freq=(freq*(20/4)), q=10)
p1 = Sine(freq=freq+Randi(-randDev, randDev, 5), mul=p1Env)
p2= Sine(freq=(freq*2)+Randi(-randDev, randDev, 5), mul=p2Env)
p3 = Sine(freq=(freq*3)+Randi(-randDev, randDev, 5), mul=p3Env)
p4 = Sine(freq=(freq*4)+Randi(-randDev, randDev, 5), mul=p4Env)
sound = Mix(p1+p2+p3+p4+noise, 1)
p1Env.ctrl(title="p1Env")
p2Env.ctrl(title="p2Env")
p3Env.ctrl(title="p3Env")
p4Env.ctrl(title="p4Env")
noise.ctrl(title="Noise")
noiseEnv.ctrl(title="Noise Envelope")
SL = sound.out()
SR = sound.out(1)
s.amp = 0.3
s.start()
s.gui(locals())
But I'm not sure why this doesn't seem to work with multichannel expansion:
#putting all our frequencies and partials in arrays
freq = MToF(note['pitch'])
pEnvs = [p1Env, p2Env, p3Env, p4Env]
freqs = [freq, freq*2, freq*3, freq*4]
#and then instantiating a Sine object with multichannel expansion
sound = Sine(freq=freqs, mul=pEnvs)
sound = Mix(sound+noise, 1)
I tried this to no avail:
freqs = [freq.value, freq.value*2, freq.value*3, freq.value*4]
and even:
freqs = [MToF(note['pitch']), MToF(note['pitch'])*2, MToF(note['pitch'])*3, MToF(note['pitch'])*4]
I'm also not sure how to control the overall gain of each partial with a slider. The .ctrl method for MidiAdsr does not have a mul slider, and if I multiply the MidiAdsr by Sig(1), it tells me there are no controls for a dummy object.
Thanks for your patience!
Kjel