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
JavaScript
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