UNPKG

genish.js

Version:
95 lines (77 loc) 3.14 kB
'use strict' let gen = require( './gen.js' ), mul = require( './mul.js' ), sub = require( './sub.js' ), div = require( './div.js' ), data = require( './data.js' ), peek = require( './peek.js' ), accum = require( './accum.js' ), ifelse = require( './ifelseif.js' ), lt = require( './lt.js' ), bang = require( './bang.js' ), env = require( './env.js' ), add = require( './add.js' ), poke = require( './poke.js' ), neq = require( './neq.js' ), and = require( './and.js' ), gte = require( './gte.js' ), memo = require( './memo.js' ), utilities= require( './utilities.js' ) module.exports = ( attackTime = 44100, decayTime = 44100, _props ) => { const props = Object.assign({}, { shape:'exponential', alpha:5, trigger:null }, _props ) const _bang = props.trigger !== null ? props.trigger : bang(), phase = accum( 1, _bang, { min:0, max: Infinity, initialValue:-Infinity, shouldWrap:false }) let bufferData, bufferDataReverse, decayData, out, buffer //console.log( 'shape:', props.shape, 'attack time:', attackTime, 'decay time:', decayTime ) let completeFlag = data( [0] ) // slightly more efficient to use existing phase accumulator for linear envelopes if( props.shape === 'linear' ) { out = ifelse( and( gte( phase, 0), lt( phase, attackTime )), div( phase, attackTime ), and( gte( phase, 0), lt( phase, add( attackTime, decayTime ) ) ), sub( 1, div( sub( phase, attackTime ), decayTime ) ), neq( phase, -Infinity), poke( completeFlag, 1, 0, { inline:0 }), 0 ) } else { bufferData = env({ length:1024, type:props.shape, alpha:props.alpha }) bufferDataReverse = env({ length:1024, type:props.shape, alpha:props.alpha, reverse:true }) out = ifelse( and( gte( phase, 0), lt( phase, attackTime ) ), peek( bufferData, div( phase, attackTime ), { boundmode:'clamp' } ), and( gte(phase,0), lt( phase, add( attackTime, decayTime ) ) ), peek( bufferDataReverse, div( sub( phase, attackTime ), decayTime ), { boundmode:'clamp' }), neq( phase, -Infinity ), poke( completeFlag, 1, 0, { inline:0 }), 0 ) } const usingWorklet = gen.mode === 'worklet' if( usingWorklet === true ) { out.node = null utilities.register( out ) } // needed for gibberish... getting this to work right with worklets // via promises will probably be tricky out.isComplete = ()=> { if( usingWorklet === true && out.node !== null ) { const p = new Promise( resolve => { out.node.getMemoryValue( completeFlag.memory.values.idx, resolve ) }) return p }else{ return gen.memory.heap[ completeFlag.memory.values.idx ] } } out.trigger = ()=> { if( usingWorklet === true && out.node !== null ) { out.node.port.postMessage({ key:'set', idx:completeFlag.memory.values.idx, value:0 }) }else{ gen.memory.heap[ completeFlag.memory.values.idx ] = 0 } _bang.trigger() } return out }