Beep boop, making progress on my FM synthesizer. Had a nasty popping sound with my phase-feedback logic and needed some way to rapidly graph out the logic. Powershell to the rescue:
# plot-sample.ps1
$samples = 1024;
$width = 2048;
$height = 512;
[Reflection.Assembly]::LoadWithPartialName("System.Drawing");
$bmp = new-object Drawing.Bitmap $width, $height;
$g = [Drawing.Graphics]::FromImage($bmp);
$g.SmoothingMode = "AntiAlias";
$penAxis = new-object Drawing.Pen 0xFF808080, 2;
$penLineA = new-object Drawing.Pen 0xFF0000F0, 2;
$penLineB = new-object Drawing.Pen 0xFFF00000, 2;
$ptsA = new-object Drawing.PointF[] $samples;
$ptsB = new-object Drawing.PointF[] $samples;
0..($samples-1) |% {
$Q = 4*[Math]::pi/$samples;
$feedback = 0;
} {
$ampA = [Math]::sin($_*$Q + $feedback); # A[t] = sin(t + 1.05*A[t-1])
$ampB = [Math]::sin($_*$Q); # B[t] = sin(t) $feedback = $ampA * 1.05;
$x = $bmp.Width * $_/$samples;
$yA = $bmp.Height * (-$ampA/2.1 + .5);
$yB = $bmp.Height * (-$ampB/2.1 + .5);
$ptsA[$_] = new-object Drawing.PointF $x, $yA;
$ptsB[$_] = new-object Drawing.PointF $x, $yB;
} {
$g.Clear([Drawing.Color]::White);
$g.DrawLine($penAxis,0,$bmp.Height/2,$bmp.Width,$bmp.Height/2);
$g.DrawLines($penLineB,$ptsB);
$g.DrawLines($penLineA,$ptsA);
$bmp.Save("$pwd\plot.png");
}
Looks like the logic should be sound. I did find that the phase-feedback wasn't being sin'd in the synthesizer, and that was causing the popping noise. And here's a sample of what it sounds like right now: fm-sample.ogg (36.4KB)
And here's the instrument used to generate that sound:
/*
unit:
mul frequency multiplier
ofs additive frequency
amp volume
feed phase feedback
envelope:
A attack rate, in degrees
D1 decay rate to sustain level, in degrees
D2 decay rate to silence, in degrees
R release rate, in degrees
S sustain level
program:
u unit to render
in phase buffer input slot, 0 for null input
out phase buffer output slot, 0 for audio data
*/
instrument i;
int idx = 0;
// mul ofs amp feed A D1 D2 R S
i.units[idx++] = { 2.00f, 0.00f, 0.50f, 1.00f, {80.0, 20.0, 10.0, 45.0, 0.75 }};
i.units[idx++] = { 1.00f, 0.00f, 0.25f, 0.00f, {85.0, 45.0, 5.0, 60.0, 0.50 }};
i.units[idx++] = { 7.00f, 0.33f, 0.12f, 0.00f, {88.5, 60.0, 5.0, 60.0, 0.25 }};
i.units[idx++] = { 1.00f, 0.33f, 0.50f, 0.00f, {87.0, 30.0, 5.0, 60.0, 0.67 }};
i.ct_units = idx;
// program:
// ┌─┐┌─┐
// │0├──►│1├──┐
// └─┘└─┘│┌─┐
// ├──►│3├──►out
// ┌─┐│└─┘
// │2├──┘
// └─┘
idx = 0;
// u in out
i.program[idx++] = { 0, 0, 2 };
i.program[idx++] = { 1, 2, 1 };
i.program[idx++] = { 2, 0, 1 };
i.program[idx++] = { 3, 1, 0 };
i.ct_program = idx;
Hue.
↧