UNPKG

genish.js

Version:
232 lines (172 loc) 4.67 kB
'use strict' let gen = { memo: []. graph:null, accum:0, isNotNumber( v ) { return (typeof v)[0] !== 'n' }, getUID() { return this.accum++ }, out() { this.memo.length = 0 return this.graph.out() }, codegen() { let code if( !gen.memocode[ this.uid ] ) { // not memooutized code = this._name + '(' this.inputs.map( ( propertyValue, idx, array ) => { if( typeof propertyValue === 'function' ) { propertyValue = propertyValue.codegen() } code += propertyValue code += idx < array.length - 1 ? ',' : ')' }) gen.memocode[ this.uid ] = code } else { // use memoized code code = gen.memocode[ this.uid ] } return code } } let table = function( frequency ) { if( ! (this instanceof table) ) return new table( frequency ) let tableSize = 1024 Object.assign( this, { frequency, uid: gen.getUID() phase:0, tableFreq: 44100 / 1024, table: new Float32Array( tableSize ), codegen: gen.codegen, sample() { let index, frac, base this.phase += this.frequency / this.tableFreq while( this.phase >= 1024 ) this.phase -= 1024 index = this.phase | 0 frac = this.phase - index base = this.table[ index ] return base + ( frac * ( this.table[ (index+1) & 1023 ] - base ) ) * 1 }, initTable() { for( let i = 0; i < this.table.length; i++ ) { this.table[ i ] = Math.sin( ( i / this.tableSize ) * ( Math.PI * 2 ) ) } } }) this.initTable() } let mul = function( x,y ) { if( ! (this instanceof mul) ) return new mul( x,y ) Object.assign( this, { x,y, sample() { let x = this.x, y = this.y if( xIsUgen ) x = x.sample() if( yIsUgen ) y = y.sample() return x*y } }) let xIsUgen = gen.isNotNumber( x ), yIsUgen = gen.isNotNumber( y ) } let add = function( x,y ) { if( ! (this instanceof add) ) return new add( x,y ); Object.assign( this, { x,y, sample() { let x = this.x, y = this.y if( xIsUgen ) x = x.sample() if( yIsUgen ) y = y.sample() return x+y } }) let xIsUgen = gen.isNotNumber( x ), yIsUgen = gen.isNotNumber( y ) } let abs = x => { let ugen = function() { if( this.uid in this.memo ) return this.memo[ this.uid ] let out = this.inputs[ 0 ] if( this.isNotNumber( out ) ) out = out() out = this.abs( out ) this.memo.set( this.uid, out ) return out } return { uid: gen.getUID(), inputs: [ x ], abs: Math.abs, memo: gen.memo, isNotNumber: gen.isNotNumber, out:ugen } } let sin = x => { let ugen = function() { if( this.uid in this.memo ) return this.memo[ this.uid ] let out = this.inputs[ 0 ] if( this.isNotNumber( out ) ) out = out() out = this.sin( out ) this.memo.set( this.uid, out ) return out } return ugen.bind({ uid: gen.getUID(), inputs: [ x ], sin: Math.sin, memo: gen.memo, isNotNumber: gen.isNotNumber }) } let accum = ( incr, reset=0, min=0, max=1 ) => { let ugen = function() { if( this.uid in this.memo ) return this.memo[ this.uid ] let incr = this.inputs[ 0 ], reset = this.inputs[ 1 ] if( this.isNotNumber( incr ) ) incr = incr() if( this.isNotNumber( reset ) ) reset = reset() this.out += incr if( reset ) { this.out = this.min }else{ if( this.out > this.max ) this.out = this.min } this.memo.set( this.uid, this.out ) return this.out } return ugen.bind({ min, max, out: 0, uid: gen.getUID(), inputs: [ incr, reset ], memo: gen.memo, isNotNumber: gen.isNotNumber }) } let bus = function( ...args ) { if( !( this instanceof bus ) ) return new bus( ...args ) Object.assign( this, { inputs: args, sample() { let out = 0 for( let i = 0, l = this.inputs.length; i < l; i++ ) { let input = this.inputs[ i ] out += input.sample() } return out } }) } let param = value => { let p = function( v ) { if( v !== undefined ) this.value = v return this.value } return p.bind({ value }) } let PI = Math.PI, SR = 44100 module.exports = { gen, add, mul, accum, abs, sin, bus, param, table, PI, SR, table }