Implementing a basic anti-aliasing strategy from a 2016 DAFx paper. Listen for the aliasing artifacts (low frequencies produced when the filter is fed with high frequencies) : this technique aims to reduce them. Better results could be obtained with a higher-order kernel, or by oversampling.
Log in to post a comment.
// Antiderivative anti-aliasing, as proposed in the 2016 DAFx paper: // // Parker, J. D., Zavalishin, V., & Le Bivic, E. (2016, September). // Reducing the aliasing of nonlinear waveshaping using continuous-time convolution. // In Proc. Int. Conf. Digital Audio Effects (DAFx-16), Brno, Czech Republic (pp. 137-144). // // http://dafx.de/paper-archive/2016/dafxpapers/20-DAFx-16_paper_41-PN.pdf function abs(x) { return x >= 0 ? x : -x; } // Hard clipping function function clip11(x) { return x < -1 ? -1 : x > 1 ? 1 : x; } // Antiderivative of hard clipping function function clip11_antider(x) { return x < -1 ? -x-0.5 : x > 1 ? x-0.5 : 0.5*x*x; } // Soft clipping function function softclip(x) { return x < -1 ? -1 : x > 1 ? 1 : 1.5*(1 - x*x/3)*x; } function softclip_antider(x) { const x2 = x*x; return x < -1 ? -x-(3/8) : x > 1 ? x-(3/8) : (3/4)*x2 - (1/8)*x2*x2; } const hardClipper = filter.def( (input,options) => [options.clipf(input[0]) * options.outgain, options.clipf(input[1]) * options.outgain], {clipf: () => clip11, outgain:0.1} ); const hardClipperADAA = filter.def(class { constructor(options) { this.x_nm1 = 0; this.F_xnm1 = 0; } process(input, options) { let x_n = input[0]; if(abs(x_n - this.x_nm1) > 1e-3) { const F_xn = options.clipF(x_n); const outv = (F_xn - this.F_xnm1) / (x_n - this.x_nm1) * options.outgain; this.x_nm1 = x_n; this.F_xnm1 = F_xn; return [outv,outv]; } else { const outv = options.clipf(0.5*(x_n + this.x_nm1)) * options.outgain; return [outv,outv]; } } }, { clipf: () => clip11, clipF: () => clip11_antider, outgain: 0.1 }); loop( (i) => { sine.play((tick) => hz_to_midi(20000*tick/5), {env:one, duration:5, amp:3}); sleep(7); sleep(10); sleep(7); sleep(10); }, {name:"Hard clipping (naive)"}).connect(hardClipper.create()); loop( (i) => { sleep(7); sine.play((tick) => hz_to_midi(20000*tick/5), {env:one, duration:5, amp:3}); sleep(10); sleep(7); sleep(10); }, {name:"Hard clipping with ADAA"}).connect(hardClipperADAA.create()); loop( (i) => { sleep(7); sleep(10); sine.play((tick) => hz_to_midi(20000*tick/5), {env:one, duration:5, amp:2}); sleep(7); sleep(10); }, {name:"Soft clipping (naive)"}).connect(hardClipper.create({clipf: () => softclip})); loop( (i) => { sleep(7); sleep(10); sleep(7); sine.play((tick) => hz_to_midi(20000*tick/5), {env:one, duration:5, amp:2}); sleep(10); }, {name:"Soft clipping with ADAA"}).connect(hardClipperADAA.create({clipf: () => softclip, clipF: () => softclip_antider}));