am and fm modulation

This commit is contained in:
aprilnightk 2025-09-13 21:03:46 +03:00
parent f8206281de
commit b3b44810a6
4 changed files with 187 additions and 13 deletions

View file

@ -23,6 +23,9 @@ OPCODES = {
'slideskew': 18,
'slidepos': 19,
'pulse': 20,
'setfmsettings': 21,
'fm': 22,
'am': 23,
}
class Activity:

View file

@ -67,4 +67,13 @@ class SoundNode:
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, [])
self.act('pulse', start_tick, end_tick, self, None, [])
def setfmsettings(self, start_tick, fmbasefreq, fmq):
self.act('setfmsettings', start_tick, start_tick, self, None, [fmbasefreq, fmq])
def fm(self, start_tick, end_tick):
self.act('fm', start_tick, end_tick, self, None, [])
def am(self, start_tick, end_tick):
self.act('am', start_tick, end_tick, self, None, [])

View file

@ -1,4 +1,4 @@
ln = s.sec(2)
ln = s.sec(6);
s.endtick(ln)
@ -9,18 +9,18 @@ left.setpos(0, -0.3, 0, 0)
right.setpos(0, 0.3, 0, 0)
tr1 = s.node()
tr1.setbasefreq(0, 11)
tr1.setgain(0, 0.45)
tr1.triangle(0, ln)
tr2 = s.node()
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.am(0, ln)
tr2.square(0, ln)
s.wire(tr1, left)
s.wire(tr1, tr2)
s.wire(tr2, left)
s.wire(tr2, right)

View file

@ -50,6 +50,9 @@ pub const Activity = struct {
18 => { try self.slideskew(); },
19 => { self.slidepos(); },
20 => { self.pulse(); },
21 => { try self.setfmsettings(); },
22 => { try self.fm(); },
23 => { try self.am(); },
else => {},
}
}
@ -136,7 +139,6 @@ pub const Activity = struct {
pub fn setbasefreq(self: *Activity) !void {
try self.soundnode.s("basefreq", self.operands[0]);
}
pub fn setgain(self: *Activity) !void {
@ -255,7 +257,7 @@ pub const Activity = struct {
const startfreq = self.operands[0];
const endfreq = self.operands[1];
const x = (current_tick * (current_tick / 2)) - (start_tick*current_tick);
const xx = ((endfreq - startfreq) / (end_tick - start_tick)) * x;
const freq = ((startfreq * current_tick) + xx) / current_tick;
@ -264,6 +266,29 @@ pub const Activity = struct {
}
pub fn slidebasefreq_iterative(self: *Activity) !void {
const current_tick: f64 = @floatFromInt(self.soundnode.fab.current_tick);
const start_tick: f64 = @floatFromInt(self.start_tick);
const end_tick: f64 = @floatFromInt(self.end_tick);
const startfreq = self.operands[0];
const endfreq = self.operands[1];
const instfreq = utility.interpolate(current_tick, start_tick, end_tick, startfreq, endfreq);
const c = current_tick / 44100;
const prevphase = self.soundnode.g("phase");
const prevfreq = self.soundnode.g("basefreq");
const pp = prevphase + c*(instfreq - prevfreq) + @floor(c * prevfreq - prevphase);
const newphase = pp - @floor(pp);
try self.soundnode.s("phase", newphase);
try self.soundnode.s("basefreq", instfreq);
}
pub fn slidegain(self: *Activity) !void {
const current_tick: f64 = @floatFromInt(self.soundnode.fab.current_tick);
@ -349,4 +374,141 @@ pub const Activity = struct {
self.soundnode.fab.add_r_amp(final_amp);
}
pub fn setfmsettings(self: *Activity) !void {
try self.soundnode.s("fmbasefreq", self.operands[0]);
try self.soundnode.s("instfreq", self.operands[0]);
try self.soundnode.s("fmq", self.operands[1]);
}
pub fn fm(self: *Activity) !void {
const current_tick: u32 = self.soundnode.fab.current_tick;
const fcurrent_tick: f64 = @floatFromInt(self.soundnode.fab.current_tick);
var fprev_tick: f64 = 0;
if (fcurrent_tick > 0) {
fprev_tick = @floatFromInt(current_tick - 1);
}
const fmq = self.soundnode.g("fmq");
const fmbasefreq = self.soundnode.g("fmbasefreq");
const prevphase = self.soundnode.g("phase");
const prevfreq = self.soundnode.g("basefreq");
var srcamp: f64 = 0;
for (self.soundnode.wire_in.items, 0..) |wired_sn, i| {
const relayed_r_amp = wired_sn.fab.get_r_amp(current_tick);
srcamp += relayed_r_amp;
_ = i;
}
for (self.soundnode.air_in.items, 0..) |aired_sn, i| {
const dist: f64 = self.soundnode.distance(aired_sn);
var b_sample_tick: u32 = 0;
var n_sample_tick: u32 = 0;
const tck = @as(f64, @floatFromInt(current_tick)) - (128.571428 * dist);
if (tck > 0) {
b_sample_tick = @intFromFloat( @floor(tck) );
n_sample_tick = b_sample_tick + 1;
const attenuation: f64 = @as(f64, std.math.exp(-(dist / 100.0)));
const b_r_amp = aired_sn.fab.get_r_amp(b_sample_tick);
const n_r_amp = aired_sn.fab.get_r_amp(n_sample_tick);
const tick_diff = tck - @as(f64, @floatFromInt(b_sample_tick));
const relayed_r_amp = (b_r_amp + (tick_diff * (n_r_amp - b_r_amp))) * attenuation;
srcamp += relayed_r_amp;
}
_ = i;
}
if (srcamp > 1) {
srcamp = 1;
} else if (srcamp < -1) {
srcamp = -1;
}
const instfreq = fmbasefreq + (fmbasefreq * fmq * srcamp);
const c = fcurrent_tick / 44100;
const pp = prevphase + c*(instfreq - prevfreq) + @floor(c * prevfreq - prevphase);
const newphase = pp - @floor(pp);
try self.soundnode.s("phase", newphase);
try self.soundnode.s("basefreq", instfreq);
}
pub fn am(self: *Activity) !void {
const current_tick: u32 = self.soundnode.fab.current_tick;
var srcamp: f64 = 0;
for (self.soundnode.wire_in.items, 0..) |wired_sn, i| {
const relayed_r_amp = wired_sn.fab.get_r_amp(current_tick);
srcamp += relayed_r_amp;
_ = i;
}
for (self.soundnode.air_in.items, 0..) |aired_sn, i| {
const dist: f64 = self.soundnode.distance(aired_sn);
var b_sample_tick: u32 = 0;
var n_sample_tick: u32 = 0;
const tck = @as(f64, @floatFromInt(current_tick)) - (128.571428 * dist);
if (tck > 0) {
b_sample_tick = @intFromFloat( @floor(tck) );
n_sample_tick = b_sample_tick + 1;
const attenuation: f64 = @as(f64, std.math.exp(-(dist / 100.0)));
const b_r_amp = aired_sn.fab.get_r_amp(b_sample_tick);
const n_r_amp = aired_sn.fab.get_r_amp(n_sample_tick);
const tick_diff = tck - @as(f64, @floatFromInt(b_sample_tick));
const relayed_r_amp = (b_r_amp + (tick_diff * (n_r_amp - b_r_amp))) * attenuation;
srcamp += relayed_r_amp;
}
_ = i;
}
if (srcamp > 1) {
srcamp = 1;
} else if (srcamp < -1) {
srcamp = -1;
}
try self.soundnode.s("gain", srcamp);
}
};