added pulse, fixed phase for basic waveforms, more versatile frontend

This commit is contained in:
aprilnightk 2025-09-13 12:13:07 +03:00
parent c9487762b2
commit f8206281de
6 changed files with 73 additions and 36 deletions

1
.gitignore vendored
View file

@ -4,6 +4,7 @@
# https://www.atlassian.com/git/tutorials/saving-changes/gitignore
sonnum.prj
sonnum
# Node artifact files
node_modules/

View file

@ -22,6 +22,7 @@ OPCODES = {
'slidephase': 17,
'slideskew': 18,
'slidepos': 19,
'pulse': 20,
}
class Activity:

View file

@ -64,4 +64,7 @@ class SoundNode:
self.act('slideskew', start_tick, end_tick, self, None, [startskew, endskew])
def slidepos(self, start_tick, end_tick, sx, sy, sz, ex, ey, ez):
self.act('slidepos', start_tick, end_tick, self, None, [sx, sy, sz, ex, ey, ez])
self.act('slidepos', start_tick, end_tick, self, None, [sx, sy, sz, ex, ey, ez])
def pulse(self, start_tick, end_tick):
self.act('pulse', start_tick, end_tick, self, None, [])

View file

@ -1,4 +1,4 @@
ln = s.sec(6)
ln = s.sec(2)
s.endtick(ln)
@ -9,12 +9,18 @@ left.setpos(0, -0.3, 0, 0)
right.setpos(0, 0.3, 0, 0)
tr1 = s.node()
tr1.setbasefreq(0, s.note("E4"))
tr1.slidebasefreq(s.sec(2), s.sec(4), s.note("E4"), s.note("C4"))
tr1.setbasefreq(s.sec(4), s.note("C4"))
tr1.sine(0, ln)
tr1.setgain(0, 0.3)
tr2 = s.node()
tr1.setpos(0, 100, 0, 0)
s.wire(tr1, [left])
s.wire(tr1, [right])
tr1.setbasefreq(0, s.note("E4"))
tr1.setgain(0, 0.45)
tr1.setskew(0, 0.3)
tr1.square(0, ln)
tr2.setbasefreq(0, s.note("E4"))
tr2.setgain(0, 0.4)
tr2.setphase(0, 0.4)
tr1.setskew(0, 0.3)
tr2.square(0, ln)
s.wire(tr1, left)
s.wire(tr2, right)

49
snm.py
View file

@ -10,8 +10,9 @@ parser = argparse.ArgumentParser(description="Sonnum - the additive synthesizer.
parser.add_argument('input_snm_fn', metavar="INPUT", nargs='?', type=str, help="Input *.snm source file", default='')
parser.add_argument('-t', '--transpile', help="View the transpiled python code", action='store_true')
parser.add_argument('-b', '--bytecode', help="View the resulting bytecode", action='store_true')
parser.add_argument('-r', '--rebuild', help="Rebuild the executable", action='store_true')
parser.add_argument('-z', '--zigrun', help="Zig run instead of executable", action='store_true')
parser.add_argument('-o', '--output', metavar='FN', help="Synthesize to given wav filenames", type=str)
@ -21,30 +22,34 @@ def run():
args = parser.parse_args()
C = SonnumCompiler()
fn = args.input_snm_fn
with open(fn, 'r', encoding = 'utf-8') as fl:
snm = fl.read()
if args.rebuild:
os.system(f'zig build-exe zigsonnum/sonnum.zig -lc -OReleaseFast')
if args.transpile:
py_snm = C.transpile_snm_to_py(snm)
print('TRANSPILED CODE')
print(py_snm)
else:
fn = args.input_snm_fn
elif args.bytecode:
py_snm = C.transpile_snm_to_py(snm)
C.run_transpiled_code(py_snm)
C.sort_activities()
C.list_activities()
elif args.output:
C.compile_to_smnb(snm, 'source.snmb')
os.system(f'./zigsonnum/sonnum > {args.output}')
else:
C.compile_to_smnb(snm, 'source.snmb')
os.system(f'zig run zigsonnum/sonnum.zig -lc -OReleaseFast > {fn}.wav')
#os.system(f'zig run zigsonnum/sonnum.zig -lc > {fn}.wav')
with open(fn, 'r', encoding = 'utf-8') as fl:
snm = fl.read()
if args.bytecode:
py_snm = C.transpile_snm_to_py(snm)
C.run_transpiled_code(py_snm)
C.sort_activities()
C.list_activities()
elif args.output:
C.compile_to_smnb(snm, 'source.snmb')
os.system(f'./sonnum > {args.output}')
elif args.zigrun:
C.compile_to_smnb(snm, 'source.snmb')
os.system(f'zig run zigsonnum/sonnum.zig -lc > {fn}.wav')
else:
C.compile_to_smnb(snm, 'source.snmb')
os.system(f'./sonnum > {fn}.wav')
#os.system(f'zig run zigsonnum/sonnum.zig -lc > {fn}.wav')
if __name__ == '__main__':
run()

View file

@ -49,6 +49,7 @@ pub const Activity = struct {
17 => { try self.slidephase(); },
18 => { try self.slideskew(); },
19 => { self.slidepos(); },
20 => { self.pulse(); },
else => {},
}
}
@ -175,9 +176,9 @@ pub const Activity = struct {
const phase = self.soundnode.g("phase");
const period = 44100 / freq;
const tp = current_tick / period;
const tp = (current_tick - (period * phase)) / period;
const amp = r_amp * (@abs(2 * (2 * ( tp - @floor(tp + 0.5) ) )) - 1 - (phase * utility.tau));
const amp = r_amp * (@abs(2 * (2 * ( tp - @floor(tp + 0.5) ) )) - 1);
self.soundnode.fab.add_r_amp(amp);
}
@ -209,9 +210,9 @@ pub const Activity = struct {
const phase = self.soundnode.g("phase");
const period = 44100 / freq;
const tp = current_tick / period;
const tp = (current_tick - (period * phase)) / period;
const amp = r_amp * (2 * (tp - @floor(0.5+tp) - (phase * utility.tau)));
const amp = r_amp * (2 * (tp - @floor(0.5+tp)));
self.soundnode.fab.add_r_amp(amp);
}
@ -328,4 +329,24 @@ pub const Activity = struct {
}
pub fn pulse(self: *Activity) void {
const current_tick: f64 = @floatFromInt(self.soundnode.fab.current_tick);
const freq = self.soundnode.g("basefreq");
const r_amp = self.soundnode.g("gain");
const phase = self.soundnode.g("phase");
const period = 44100 / freq;
const tp = current_tick / period;
const tp_detract = (current_tick - (period * phase)) / period;
const amp =2 * (tp - @floor(0.5+tp));
const amp_detract = 2 * (tp_detract - @floor(0.5+tp_detract));
const final_amp = r_amp * (amp - amp_detract);
self.soundnode.fab.add_r_amp(final_amp);
}
};