genish.js
Version:
77 lines (61 loc) • 2.14 kB
JavaScript
/**********************************************
****** Bamd-limited Saw via FM feedback *******
***********************************************
ported from gibberish by thecharlie 5/15/2016
based on research from : http://scp.web.elte.hu/papers/synthesis1.pdf
In the paper linked above, the author describes how a sine oscillator whose
output is used to modulate itself produces harmonics similar to a saw wave.
With additional filtering, this waveform can create a reasonable version
of a band-limited sawtooth wave.
A scaling factor is applied to the amount of feedback used for modulation.
The scaling factor can in turn be scaled in a range of {0,1} to create a
low-pass filter effect; here that effect is controlled via GUI.
*/
// create some notes to play w/ a little portamento
frequencies = peek(
data([220,330,440,660,880]),
phasor( param('speed',.5), 0, { min:0 } ),
{ interp:'none', min:0 }
)
slideFreqs = slide( frequencies, 1000 )
// expose our feedback scaling factor for control
pseudoFilter = param( 'filter', 1 )
// store output to use as modulation for next sample
lastSample = ssd()
// determine phase increment and memoize result
w = memo( div( slideFreqs, gen.samplerate ) )
// create scaling factor
n = sub( -.5, w )
scaling = mul( mul( 13, pseudoFilter ), pow( n, 5 ) )
// calculate dc offset and normalization factors
DC = sub( .376, mul( w, .752 ) )
norm = sub( 1, mul( 2, w ) )
// determine phase
phase = accum( w, 0, { min:-1 })
// create current sample... from the paper:
// osc = (osc + sin(2*pi*(phase + osc*scaling)))*0.5f;
thisSample = memo(
mul(
add(
lastSample.out,
sin(
mul(
Math.PI * 2,
add( phase, mul( lastSample.out, scaling ) )
)
)
), .5
)
)
// store sample to use as modulation
lastSample.in( thisSample )
// offset and normalize
out = add( mul( 2.5, thisSample), mul( -1.5, lastSample.out ) )
out = add( out, DC )
out = mul( out, norm )
play( mul( out,.15 ) ).then( node => {
// gui
gui = new dat.GUI({ width: 400 })
gui.add( node, 'filter', 0, 1 )
gui.add( node, 'speed', .1,2 )
})