sonnum/mysynths/epiano.py
2025-09-21 14:01:29 +03:00

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)