genish.js
Version:
118 lines (89 loc) • 3.62 kB
JavaScript
let gen = require('./gen.js')
let proto = {
basename:'accum',
gen() {
let code,
inputs = gen.getInputs( this ),
genName = 'gen.' + this.name,
functionBody
gen.requestMemory( this.memory )
gen.memory.heap[ this.memory.value.idx ] = this.initialValue
functionBody = this.callback( genName, inputs[0], inputs[1], `memory[${this.memory.value.idx}]` )
//gen.closures.add({ [ this.name ]: this })
gen.memo[ this.name ] = this.name + '_value'
return [ this.name + '_value', functionBody ]
},
callback( _name, _incr, _reset, valueRef ) {
let diff = this.max - this.min,
out = '',
wrap = ''
/* three different methods of wrapping, third is most expensive:
*
* 1: range {0,1}: y = x - (x | 0)
* 2: log2(this.max) == integer: y = x & (this.max - 1)
* 3: all others: if( x >= this.max ) y = this.max -x
*
*/
// must check for reset before storing value for output
if( !(typeof this.inputs[1] === 'number' && this.inputs[1] < 1) ) {
if( this.resetValue !== this.min ) {
out += ` if( ${_reset} >=1 ) ${valueRef} = ${this.resetValue}\n\n`
//out += ` if( ${_reset} >=1 ) ${valueRef} = ${this.min}\n\n`
}else{
out += ` if( ${_reset} >=1 ) ${valueRef} = ${this.min}\n\n`
//out += ` if( ${_reset} >=1 ) ${valueRef} = ${this.initialValue}\n\n`
}
}
out += ` var ${this.name}_value = ${valueRef}\n`
if( this.shouldWrap === false && this.shouldClamp === true ) {
out += ` if( ${valueRef} < ${this.max } ) ${valueRef} += ${_incr}\n`
}else{
out += ` ${valueRef} += ${_incr}\n` // store output value before accumulating
}
if( this.max !== Infinity && this.shouldWrapMax ) wrap += ` if( ${valueRef} >= ${this.max} ) ${valueRef} -= ${diff}\n`
if( this.min !== -Infinity && this.shouldWrapMin ) wrap += ` if( ${valueRef} < ${this.min} ) ${valueRef} += ${diff}\n`
//if( this.min === 0 && this.max === 1 ) {
// wrap = ` ${valueRef} = ${valueRef} - (${valueRef} | 0)\n\n`
//} else if( this.min === 0 && ( Math.log2( this.max ) | 0 ) === Math.log2( this.max ) ) {
// wrap = ` ${valueRef} = ${valueRef} & (${this.max} - 1)\n\n`
//} else if( this.max !== Infinity ){
// wrap = ` if( ${valueRef} >= ${this.max} ) ${valueRef} -= ${diff}\n\n`
//}
out = out + wrap + '\n'
return out
},
defaults : { min:0, max:1, resetValue:0, initialValue:0, shouldWrap:true, shouldWrapMax: true, shouldWrapMin:true, shouldClamp:false }
}
module.exports = ( incr, reset=0, properties ) => {
const ugen = Object.create( proto )
Object.assign( ugen,
{
uid: gen.getUID(),
inputs: [ incr, reset ],
memory: {
value: { length:1, idx:null }
}
},
proto.defaults,
properties
)
if( properties !== undefined && properties.shouldWrapMax === undefined && properties.shouldWrapMin === undefined ) {
if( properties.shouldWrap !== undefined ) {
ugen.shouldWrapMin = ugen.shouldWrapMax = properties.shouldWrap
}
}
if( properties !== undefined && properties.resetValue === undefined ) {
ugen.resetValue = ugen.min
}
if( ugen.initialValue === undefined ) ugen.initialValue = ugen.min
Object.defineProperty( ugen, 'value', {
get() {
//console.log( 'gen:', gen, gen.memory )
return gen.memory.heap[ this.memory.value.idx ]
},
set(v) { gen.memory.heap[ this.memory.value.idx ] = v }
})
ugen.name = `${ugen.basename}${ugen.uid}`
return ugen
}