genish.js
Version:
84 lines (63 loc) • 2.84 kB
JavaScript
/*************************************************************
****** Freeverb (reverb via comb and allpass filters) ********
**************************************************************
ported from gibberish by thecharlie, 5/16/2016
Freeverb is a simple reverb model where 8 comb filters that run
in parallel are summed and then fed through four allpass filters
in series. The comb filters simultate reflections while the allpass
filters 'smear' the phase response to prevent feedback from creating
frequecny peaks.
See https://ccrma.stanford.edu/~jos/pasp/Freeverb.html for more info.
*/
// define a convenience for creating combFilters; see the comb filter
// demo for more information
combFilter = function( _input, combLength, damping=.5*.4, feedbackCoeff=.84 ) {
let lastSample = ssd(),
readWriteIdx = counter( 1,0,combLength ),
combBuffer = data( combLength ),
out = peek( combBuffer, readWriteIdx, { interp:'none', mode:'samples' }),
storeInput = memo( add( mul( out, sub( 1, damping)), mul( lastSample.out, damping ) ) )
lastSample.in( storeInput )
poke( combBuffer, add( _input, mul( storeInput, feedbackCoeff ) ), readWriteIdx )
return out
}
// constructor for schroeder allpass filters
allPass = function( _input, length=500, feedback=.5 ) {
let index = counter( 1,0,length ),
buffer = data( length ),
bufferSample = peek( buffer, index, { interp:'none', mode:'samples' }),
out = memo( add( mul( -1, _input), bufferSample ) )
poke( buffer, add( _input, mul( bufferSample, feedback ) ), index )
return out
}
// tuning settings for schroeder / moorer model
tuning = {
combCount: 8,
combTuning: [ 1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617 ],
allPassCount: 4,
allPassTuning: [ 225, 556, 441, 341 ],
allPassFeedback: 0.5,
fixedGain: 0.015,
scaleDamping: 0.4,
scaleRoom: 0.28,
offsetRoom: 0.7,
}
combs = []
amenData = data( './resources/audiofiles/dead-presidents.wav' ).then( ()=> {
let wet = .55, dry = .5, roomSize = .95, damping =.75
amenSignal = peek( amenData, accum( 1,0, { max:amenData.buffer.length } ), { interp:'none', mode:'samples' } )
attenuatedAmen = memo( mul( amenSignal, tuning.fixedGain ) )
// create comb filters in parallel...
for( let i = 0; i < 8; i++ ) {
combs.push(
combFilter( attenuatedAmen, tuning.combTuning[i], damping*.4, (tuning.scaleRoom + tuning.offsetRoom) * roomSize )
)
}
// ... and sum them with attenuated input
let out = add( attenuatedAmen, ...combs )
// run through allpass filters in series
for( let i = 0; i < 4; i++ ) out = allPass( out, tuning.allPassTuning[ 0 ] )
// combine wet and dry signals
out = add( mul( amenSignal, dry ), mul( out, wet ) )
cb = play( out, true )
})