149 lines
No EOL
3.3 KiB
Python
149 lines
No EOL
3.3 KiB
Python
import random
|
|
|
|
class PianoString:
|
|
|
|
def __init__(self, s, piano, notename, note_no, string_no):
|
|
|
|
self.s = s
|
|
self.piano = piano
|
|
self.note = notename
|
|
self.note_no = note_no
|
|
self.string_no = string_no
|
|
|
|
self.xshift = [-0.002, 0, 0.002][string_no]
|
|
self.x = (1/24.0)*note_no - 1.5 + self.xshift
|
|
|
|
if string_no == 1:
|
|
overtones = 10
|
|
else:
|
|
overtones = 8
|
|
|
|
self.node = self.s.node(overtones)
|
|
|
|
for reflector in self.piano.reflectors:
|
|
pass
|
|
#;self.node -> reflector
|
|
|
|
;0 self.node.@air_lr()
|
|
|
|
;0 self.node.setpos(self.x, 0, 0)
|
|
;0 self.node.@setgain(0.5)
|
|
|
|
fm_mod = self.piano.fm_mods[self.string_no]
|
|
;fm_mod:0 >> self.node:10
|
|
|
|
;0 self.node.setpin(40, 0.9)
|
|
;0 self.node.setpin(41, 0.4)
|
|
;0 self.node.setpin(35, 0.3)
|
|
|
|
for overtone in range(overtones):
|
|
|
|
;0 self.node.@setfreq(overtone, note(self.note)*(overtone+1))
|
|
;0 self.node.@setfreqgain(overtone, 0.1/(overtone**1.5+1))
|
|
|
|
def play_string(self, startsec, endsec, gainmult):
|
|
|
|
for overtone in range(0, 8):
|
|
ovfreq = note(self.note)*(overtone+1)
|
|
dispersion = (8-overtone) * 0.1
|
|
;startsec-endsec self.node:10:-1/1 ::> fp(overtone):ovfreq-dispersion/ovfreq+dispersion
|
|
|
|
attack = sec(0.05)
|
|
hold = sec(0.1)
|
|
decay = sec(0.5)
|
|
sustain = sec(endsec - startsec)
|
|
release = sec(endsec - startsec + 0.2)
|
|
|
|
;startsec-endsec+0.2 self.node.adsr(attack, hold, decay, sustain, release, gainmult)
|
|
|
|
|
|
#;startsec-endsec+0.2 self.node.sine(0.3)
|
|
#;startsec-endsec+0.2 self.node.skewsine(35, 0.1)
|
|
#;startsec-endsec+0.2 self.node.square(0.04)
|
|
#;startsec-endsec+0.2 self.node.triangle(0.4)
|
|
;startsec-endsec+0.2 self.node.residualsines(3, 0.00002)
|
|
|
|
class Piano:
|
|
|
|
def __init__(self, s):
|
|
|
|
self.s = s
|
|
|
|
notes = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#','G','G#','A','A#','B']
|
|
octaves = '3456'
|
|
|
|
gamma = []
|
|
|
|
for o in octaves:
|
|
for n in notes:
|
|
gamma.append(n+o)
|
|
|
|
self.fm_mods = []
|
|
|
|
self.reflectors = []
|
|
|
|
for i in range(0, 7):
|
|
|
|
self.reflectors.append(self.s.relay())
|
|
;0 self.reflectors[-1].@air_lr()
|
|
;0 self.reflectors[-1].@setgain(0.4)
|
|
;0 self.reflectors[-1].setpos(0,-1.1*i,-1.1*i)
|
|
|
|
for i in range(0,3):
|
|
|
|
fm_mod = self.s.node(1)
|
|
;0 fm_mod.@setfreq(0, 4*i)
|
|
;0-tick(self.s.end) fm_mod.sine()
|
|
|
|
self.fm_mods.append(fm_mod)
|
|
|
|
self.strings = dict() # {note: []}
|
|
|
|
for i in range(0, len(gamma)):
|
|
note = gamma[i]
|
|
|
|
self.strings[note] = []
|
|
self.strings[note].append(self.s.PianoString(s, self, note, i, 0))
|
|
self.strings[note].append(self.s.PianoString(s, self, note, i, 1))
|
|
self.strings[note].append(self.s.PianoString(s, self, note, i, 2))
|
|
|
|
|
|
|
|
def get_nodes(self, note):
|
|
|
|
if note in self.strings:
|
|
return self.strings[note]
|
|
|
|
def play(self, note, startsec, endsec, gainmult):
|
|
|
|
for node in self.get_nodes(note):
|
|
node.play_string(startsec, endsec, gainmult)
|
|
|
|
###
|
|
|
|
s.setup(8)
|
|
s.PianoString = PianoString
|
|
|
|
P = Piano(s)
|
|
|
|
if False:
|
|
P.play("C4", 0, 7, 0.6)
|
|
else:
|
|
P.play("C4", 0, 2, 0.6)
|
|
|
|
P.play("E4", 0.3, 2, 0.6)
|
|
P.play("G4", 0.6, 2, 0.6)
|
|
|
|
P.play("C4", 2, 3, 0.6)
|
|
P.play("A4", 2, 3, 0.6)
|
|
P.play("F4", 2, 3, 0.6)
|
|
|
|
P.play("B3", 3, 4, 0.6)
|
|
P.play("G4", 3, 4, 0.6)
|
|
P.play("D4", 3, 4, 0.6)
|
|
|
|
P.play("C4", 4, 5, 0.6)
|
|
P.play("E4", 4, 5, 0.6)
|
|
P.play("A3", 4, 5, 0.6)
|
|
P.play("C5", 4, 5, 0.6)
|
|
|