//! example: generate a filtered sine wave with tremolo //! //! writes output.wav - no ffmpeg needed. const std = @import("std"); const noise = @import("noise"); pub fn main() !void { const sample_rate: u32 = 48000; const duration: f32 = 5.0; const num_samples: u32 = @intFromFloat(@as(f32, @floatFromInt(sample_rate)) * duration); // oscillator frequency (A4 = 440 Hz) const freq: f32 = 440.0; // lowpass at 2kHz to soften the tone const lpf = noise.biquad.lowpass(2000, 0.707, @floatFromInt(sample_rate)); var lpf_state: noise.State = .{}; // tremolo at 4 Hz var tremolo = noise.Lfo.init(4.0, @floatFromInt(sample_rate)); // create output file const file = try std.fs.cwd().createFile("output.wav", .{}); defer file.close(); // write WAV header const header = noise.WavHeader.init(num_samples, sample_rate, 1); try file.writeAll(header.asBytes()); // write samples for (0..num_samples) |i| { const t: f32 = @floatFromInt(i); const sr: f32 = @floatFromInt(sample_rate); // generate sine wave const phase = t * 2.0 * std.math.pi * freq / sr; var sample = @sin(phase); // apply lowpass filter sample = noise.biquad.step(lpf, &lpf_state, sample); // apply tremolo (amplitude modulation) const mod = (tremolo.step(.sine) + 1.0) / 2.0; // 0 to 1 sample *= 0.3 + 0.7 * mod; // depth of 70% // fade in/out const fade_samples: f32 = 0.1 * sr; if (t < fade_samples) { sample *= t / fade_samples; } else if (t > @as(f32, @floatFromInt(num_samples)) - fade_samples) { sample *= (@as(f32, @floatFromInt(num_samples)) - t) / fade_samples; } // write sample try file.writeAll(std.mem.asBytes(&sample)); } }