From 89952cf8f672006a0b598f4985955b6bf5fbf4c0 Mon Sep 17 00:00:00 2001 From: aprilnightk Date: Sun, 21 Sep 2025 14:01:29 +0300 Subject: [PATCH] conserving for now --- mysynths/epiano.py | 202 ++++++++++++++++++--------- mysynths/test.py | 15 +- pysonnum/compiler.py | 18 +-- pysonnum/sonnum.py | 4 +- pysonnum/soundnode.py | 8 ++ zigsonnum/activities/basicsynths.zig | 43 ++++++ zigsonnum/activity.zig | 1 + 7 files changed, 205 insertions(+), 86 deletions(-) diff --git a/mysynths/epiano.py b/mysynths/epiano.py index 4f9c12d..f02b6f3 100644 --- a/mysynths/epiano.py +++ b/mysynths/epiano.py @@ -2,84 +2,148 @@ import random class PianoString: - def __init__(self, s, note, i): - + def __init__(self, s, piano, notename, note_no, string_no): + self.s = s - - self.basefreq = self.s.note(note) - self.primary_gain = 0.4 + self.piano = piano + self.note = notename + self.note_no = note_no + self.string_no = string_no - self.mod = self.s.node() - self.node = self.s.node() - - self.node.setpos(0, -10.0+i, 0, 0) + self.xshift = [-0.002, 0, 0.002][string_no] + self.x = (1/24.0)*note_no - 1.5 + self.xshift - self.node.setbasefreq(0, self.basefreq) - self.node.setgain(0, self.primary_gain) - - self.mod.setbasefreq(0, 10) - self.mod.setgain(0, 0.8) - self.node.fmsetup(0, self.basefreq, 0.009) - self.node.setskew(0, 0.3) - - self.node.setadsrgain(0, 1) - self.node.setadsrsustain(0, 0.2) - - self.s.wire(self.mod, self.node) - self.s.air(self.node, [self.s.left, self.s.right]) + if string_no == 1: + overtones = 10 + else: + overtones = 8 - def gain(self, starttick, gain): + self.node = self.s.node(overtones) - self.node.setgain(starttick, gain) - - def play(self, starttick, endtick): + for reflector in self.piano.reflectors: + pass + #;self.node -> reflector + + ;0 self.node.@air_lr() - keyhold_endtick = endtick - endtick += self.s.sec(0.3) + ;0 self.node.setpos(self.x, 0, 0) + ;0 self.node.@setgain(0.5) - self.node.adsr(starttick, endtick, - self.s.sec(0.03), - self.s.sec(0.03), - self.s.sec(0.36), - keyhold_endtick - starttick, - keyhold_endtick - starttick + self.s.sec(0.3)) - - #self.mod.sine(starttick, endtick) - #self.node.fm(starttick, endtick) - self.node.sine(starttick, endtick, 0.2) - self.node.skewsine(starttick, endtick, 0.3) - self.node.square(starttick, endtick, 0.04) + fm_mod = self.piano.fm_mods[self.string_no] + ;fm_mod:0 >> self.node:10 - self.node.adsr(starttick, endtick, - self.s.sec(0.067), - self.s.sec(0.07), - self.s.sec(0.09), - self.s.sec(0.1), - self.s.sec(0.2)) - - self.node.whitenoise(starttick, endtick, 0.01) - self.node.triangle(starttick, endtick, 0.2) - - - def playsec(self, start, end): + ;0 self.node.setpin(40, 0.9) + ;0 self.node.setpin(41, 0.4) + ;0 self.node.setpin(35, 0.3) - self.play(self.s.sec(start), self.s.sec(end)) + 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)) - -notes = 'CDEFGAB' -octaves = '345' - -gamma = [] - -for o in octaves: - for n in notes: - gamma.append(n+o) -s.setup(s.sec(60)) - -for i in range(0, len(gamma)): - note = gamma[i] + 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: - S = PianoString(s, note, i) - - S.playsec(i, i+1.4) + 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) + \ No newline at end of file diff --git a/mysynths/test.py b/mysynths/test.py index 01bbd4c..9ad8cfd 100644 --- a/mysynths/test.py +++ b/mysynths/test.py @@ -8,16 +8,17 @@ sn = s.node(1) ;0 sn.@setfreq(0, 4) ;0-10 sn.sine() -sn2 = s.node(2) +sn2 = s.node(3) ;sn:0 >> sn2:10 ;0 sn2.@wire_lr() -;0 sn2.@setfreq(0,400) +;0 sn2.@setfreq(0, note("C4")) ;0 sn2.@setfreq(1,800) -;0-10 sn2:10:-1/1 ::> fp(0):396/404 -;0-10 sn2:10:-1/1 ::> fp(1):795/806 +;0-10 sn2:10:-1/1 ::> fp(0):note("A5")-10/note("A5")+10 +;0-10 sn2:10:-1/1 ::> fp(0):note("E4")-10/note("E4")+10 +;0-10 sn2:10:-1/1 ::> fp(1):note("C6")-10/note("C6")+10 ;0 sn2.setpin(40, 0.9) ;0 sn2.setpin(41, 0.4) @@ -25,5 +26,7 @@ sn2 = s.node(2) ;0-10 sn2:10:-1/1 ::> 35:0.1/0.9 ;0-10 sn2.adsr(sec(0.1), sec(0.2), sec(0.3), sec(0.4), sec(0.5)) -;0-10 sn2.triangle(0.5) -;0-10 sn2.sine(0.5) \ No newline at end of file +;0-10 sn2.triangle(0.4) +;0-10 sn2.sine(0.5) +;0-10 sn2.sawtooth(0.04) +;0-10 sn2.whitenoise(0.004) \ No newline at end of file diff --git a/pysonnum/compiler.py b/pysonnum/compiler.py index 6103d91..41cdaa4 100644 --- a/pysonnum/compiler.py +++ b/pysonnum/compiler.py @@ -48,29 +48,29 @@ class SonnumCompiler: if '=>' in ln: name_src, name_trg = ln[1:].split('=>') - ln = f'self.add_activity("link", 0, 0, {name_src}, {name_trg}, [0, 1])' + ln = f'{name_src}.act("link", 0, 0, {name_src}, {name_trg}, [0, 1])' elif '->' in ln: name_src, name_trg = ln[1:].split('->') - ln = f'self.add_activity("link", 0, 0, {name_src}, {name_trg}, [0, 2])' + ln = f'{name_src}.act("link", 0, 0, {name_src}, {name_trg}, [0, 2])' elif '=/>' in ln: name_src, name_trg = ln[1:].split('=/>') - ln = f'self.add_activity("unlink", 0, 0, {name_src}, {name_trg}, [0, 1])' + ln = f'{name_src}.act("unlink", 0, 0, {name_src}, {name_trg}, [0, 1])' elif '-/>' in ln: name_src, name_trg = ln[1:].split('-/>') - ln = f'self.add_activity("unlink", 0, 0, {name_src}, {name_trg}, [0, 2])' + ln = f'{name_src}.act("unlink", 0, 0, {name_src}, {name_trg}, [0, 2])' elif '>>' in ln: name_src, name_trg = ln[1:].split('>>') name_src, pin_src = name_src.split(':') name_trg, pin_trg = name_trg.split(':') - ln = f'self.add_activity("link", 0, 0, {name_src}, {name_trg}, [{pin_src}, {pin_trg}])' + ln = f'{name_src}.act("link", 0, 0, {name_src}, {name_trg}, [{pin_src}, {pin_trg}])' elif '::>' in ln: tickdata, cmd = ln[1:].split(' ',1) @@ -85,7 +85,7 @@ class SonnumCompiler: pin_trg, rangepair_trg = name_trg.split(':') from_src, from_trg = rangepair_src.split('/') to_src, to_trg = rangepair_trg.split('/') - ln = f'self.add_activity("rerange", sec({starttick}), sec({endtick}), {name_src}, {name_src}, [{pin_src}, {pin_trg}, {from_src}, {from_trg}, {to_src}, {to_trg}])' + ln = f'{name_src}.act("rerange", sec({starttick}), sec({endtick}), {name_src}, {name_src}, [{pin_src}, {pin_trg}, {from_src}, {from_trg}, {to_src}, {to_trg}])' elif ':>' in ln: tickdata, cmd = ln[1:].split(' ',1) @@ -97,7 +97,7 @@ class SonnumCompiler: endtick = starttick name_src, pin_trg = cmd.split(':>') name_src, pin_src = name_src.split(':') - ln = f'self.add_activity("copy", sec({starttick}), sec({endtick}), {name_src}, None, [{pin_src}, {pin_trg}])' + ln = f'{name_src}.act("copy", sec({starttick}), sec({endtick}), {name_src}, None, [{pin_src}, {pin_trg}])' else: @@ -116,7 +116,7 @@ class SonnumCompiler: cmdparts = cmdcore.split('.') operand = cmdparts.pop(-1) nodenames = '.'.join(cmdparts) - + print(operand, nodenames) if '>' in nodenames: src_nodename, trg_nodename = nodenames.split('>') else: @@ -128,7 +128,7 @@ class SonnumCompiler: ln = f'{src_nodename}.{operand}(sec({starttick}), sec({endtick}), [{cmdargs}])' else: - ln = f'self.add_activity("{operand}", sec({starttick}), sec({endtick}), {src_nodename}, {trg_nodename}, [{cmdargs}])' + ln = f'{src_nodename}.act("{operand}", sec({starttick}), sec({endtick}), {src_nodename}, {trg_nodename}, [{cmdargs}])' ln = tablevel*'\t' + ln py_src.append(ln) diff --git a/pysonnum/sonnum.py b/pysonnum/sonnum.py index 6e8d81f..aa1f89f 100644 --- a/pysonnum/sonnum.py +++ b/pysonnum/sonnum.py @@ -18,8 +18,8 @@ class Sonnum: self.left = self.relay() self.right = self.relay() - self.left.act("setpos", 0, 0, self.left, None, [0.3, 0, 0]) - self.right.act("setpos", 0, 0, self.right, None, [-0.3, 0, 0]) + self.left.act("setpos", 0, 0, self.left, None, [-0.3, 0, 0]) + self.right.act("setpos", 0, 0, self.right, None, [0.3, 0, 0]) def add_node(self, name, freq_q): diff --git a/pysonnum/soundnode.py b/pysonnum/soundnode.py index 69129fd..04ef421 100644 --- a/pysonnum/soundnode.py +++ b/pysonnum/soundnode.py @@ -1,3 +1,5 @@ +from .notes import * + R_AMP = 0 WIRE_IN = 1 AIR_IN = 2 @@ -28,6 +30,12 @@ def sp(freq_no): def sec(seconds): return seconds * 44100 +def note(note): + return note_to_freq(note) + +def tick(ticks): + return ticks / 44100.0 + class SoundNode: def __init__(self, sonnum, order, name): diff --git a/zigsonnum/activities/basicsynths.zig b/zigsonnum/activities/basicsynths.zig index 3257fd2..3ce7be5 100644 --- a/zigsonnum/activities/basicsynths.zig +++ b/zigsonnum/activities/basicsynths.zig @@ -226,4 +226,47 @@ pub fn whitenoise(self: *Activity) void { self.soundnode.fab.add_r_amp(final_amp); +} + +// Produces a sine wave to r_amp pin +pub fn residualsines(self: *Activity) void { + + const current_tick: f64 = @floatFromInt(self.soundnode.fab.current_tick); + const maingain = self.soundnode.corrGain(self.operands[1]); + + const resolution: usize = @intFromFloat(self.operands[0]); + + var final_amp: f64 = 0; + + const max_freq_pin = 64 + self.soundnode.freq_q; + for (64..max_freq_pin) |freq_pin| { + + if (self.soundnode.pins[freq_pin] > 0) { + + const gain = self.soundnode.pins[freq_pin + 48]; + const shift = self.soundnode.pins[freq_pin + 96]; + const phase = self.soundnode.pins[freq_pin + 144]; + + const totalphase = self.soundnode.pins[33] + shift + phase; + + for (0..resolution) |residual| { + + const fresidual = @as(f64,@floatFromInt(residual))+1; + const res_gain = 1 / math.pow(f64, gain, fresidual); + + var amp = math.sin(utility.corrected_tau * (self.soundnode.pins[freq_pin]-fresidual) * current_tick - totalphase * utility.tau); + + final_amp += maingain * res_gain * amp; + + + amp = math.sin(utility.corrected_tau * (self.soundnode.pins[freq_pin]+fresidual) * current_tick - totalphase * utility.tau); + + final_amp += maingain * res_gain * amp; + } + + } + } + + self.soundnode.add_r_amp(final_amp); + } \ No newline at end of file diff --git a/zigsonnum/activity.zig b/zigsonnum/activity.zig index f0839dc..62cb70b 100644 --- a/zigsonnum/activity.zig +++ b/zigsonnum/activity.zig @@ -51,6 +51,7 @@ pub const Activity = struct { 54 => { basicsynths.skewsine(self); }, 55 => { basicsynths.pulse(self); }, 56 => { basicsynths.whitenoise(self); }, + 57 => { basicsynths.residualsines(self); }, //100 => { generators.singenN(self); }, 150 => { generators.adsr(self); },