UNPKG

gibberish-dsp

Version:

Gibberish is designed to be an optimized API for audio synthesis using per-sample techniques.

75 lines (62 loc) 1.99 kB
let g = require( 'genish.js' ) let feedbackOsc = function( frequency, filter, pulsewidth=.5, argumentProps ) { if( argumentProps === undefined ) argumentProps = { type: 0 } let lastSample = g.history(), // determine phase increment and memoize result w = g.memo( g.div( frequency, g.gen.samplerate ) ), // create scaling factor n = g.sub( -.5, w ), scaling = g.mul( g.mul( 13, filter ), g.pow( n, 5 ) ), // calculate dc offset and normalization factors DC = g.sub( .376, g.mul( w, .752 ) ), norm = g.sub( 1, g.mul( 2, w ) ), // determine phase osc1Phase = g.accum( w, 0, { min:-1 }), osc1, out // create current sample... from the paper: // osc = (osc + sin(2*pi*(phase + osc*scaling)))*0.5f; osc1 = g.memo( g.mul( g.add( lastSample.out, g.sin( g.mul( Math.PI * 2, g.memo( g.add( osc1Phase, g.mul( lastSample.out, scaling ) ) ) ) ) ), .5 ) ) // store sample to use as modulation lastSample.in( osc1 ) // if pwm / square waveform instead of sawtooth... if( argumentProps.type === 1 ) { const lastSample2 = g.history() // for osc 2 const lastSampleMaster = g.history() // for sum of osc1,osc2 const osc2 = g.mul( g.add( lastSample2.out, g.sin( g.mul( Math.PI * 2, g.memo( g.add( osc1Phase, g.mul( lastSample2.out, scaling ), pulsewidth ) ) ) ) ), .5 ) lastSample2.in( osc2 ) out = g.memo( g.sub( lastSample.out, lastSample2.out ) ) out = g.memo( g.add( g.mul( 2.5, out ), g.mul( -1.5, lastSampleMaster.out ) ) ) lastSampleMaster.in( g.sub( osc1, osc2 ) ) }else{ // offset and normalize osc1 = g.add( g.mul( 2.5, osc1 ), g.mul( -1.5, lastSample.out ) ) osc1 = g.add( osc1, DC ) out = osc1 } return g.mul( out, norm ) } module.exports = feedbackOsc