genish.js
Version:
207 lines (153 loc) • 4.09 kB
JavaScript
'use strict'
let gen = {
memo: new Map(),
graph:null,
accum:0,
isNotNumber( v ) {
return (typeof v)[0] !== 'n'
},
getUID() {
return this.accum++
},
out() {
this.memo.clear()
return this.graph.out()
},
}
let table = function( frequency ) {
if( ! (this instanceof table) ) return new table( frequency )
let tableSize = 1024
Object.assign( this, {
frequency,
phase:0,
tableFreq: 44100 / 1024,
table: new Float32Array( tableSize ),
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 }