gibberish-dsp
Version:
Gibberish is designed to be an optimized API for audio synthesis using per-sample techniques.
1,868 lines (1,438 loc) • 528 kB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Gibberish = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
'use strict'
let gen = require('./gen.js')
let proto = {
name:'abs',
gen() {
let out,
inputs = gen.getInputs( this )
const isWorklet = gen.mode === 'worklet'
const ref = isWorklet ? '' : 'gen.'
if( isNaN( inputs[0] ) ) {
gen.closures.add({ [ this.name ]: isWorklet ? 'Math.abs' : Math.abs })
out = `${ref}abs( ${inputs[0]} )`
} else {
out = Math.abs( parseFloat( inputs[0] ) )
}
return out
}
}
module.exports = x => {
let abs = Object.create( proto )
abs.inputs = [ x ]
return abs
}
},{"./gen.js":33}],2:[function(require,module,exports){
'use strict'
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
}
},{"./gen.js":33}],3:[function(require,module,exports){
'use strict'
let gen = require('./gen.js')
let proto = {
basename:'acos',
gen() {
let out,
inputs = gen.getInputs( this )
const isWorklet = gen.mode === 'worklet'
const ref = isWorklet ? '' : 'gen.'
if( isNaN( inputs[0] ) ) {
gen.closures.add({ 'acos': isWorklet ? 'Math.acos' :Math.acos })
out = `${ref}acos( ${inputs[0]} )`
} else {
out = Math.acos( parseFloat( inputs[0] ) )
}
return out
}
}
module.exports = x => {
let acos = Object.create( proto )
acos.inputs = [ x ]
acos.id = gen.getUID()
acos.name = `${acos.basename}{acos.id}`
return acos
}
},{"./gen.js":33}],4:[function(require,module,exports){
'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
}
},{"./accum.js":2,"./add.js":5,"./and.js":7,"./bang.js":11,"./data.js":19,"./div.js":24,"./env.js":25,"./gen.js":33,"./gte.js":35,"./ifelseif.js":38,"./lt.js":41,"./memo.js":45,"./mul.js":51,"./neq.js":52,"./peek.js":57,"./poke.js":61,"./sub.js":72,"./utilities.js":78}],5:[function(require,module,exports){
'use strict'
const gen = require('./gen.js')
const proto = {
basename:'add',
gen() {
let inputs = gen.getInputs( this ),
out='',
sum = 0, numCount = 0, adderAtEnd = false, alreadyFullSummed = true
if( inputs.length === 0 ) return 0
out = ` var ${this.name} = `
inputs.forEach( (v,i) => {
if( isNaN( v ) ) {
out += v
if( i < inputs.length -1 ) {
adderAtEnd = true
out += ' + '
}
alreadyFullSummed = false
}else{
sum += parseFloat( v )
numCount++
}
})
if( numCount > 0 ) {
out += adderAtEnd || alreadyFullSummed ? sum : ' + ' + sum
}
out += '\n'
gen.memo[ this.name ] = this.name
return [ this.name, out ]
}
}
module.exports = ( ...args ) => {
const add = Object.create( proto )
add.id = gen.getUID()
add.name = add.basename + add.id
add.inputs = args
return add
}
},{"./gen.js":33}],6:[function(require,module,exports){
'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' ),
param = require( './param.js' ),
add = require( './add.js' ),
gtp = require( './gtp.js' ),
not = require( './not.js' ),
and = require( './and.js' ),
neq = require( './neq.js' ),
poke = require( './poke.js' )
module.exports = ( attackTime=44, decayTime=22050, sustainTime=44100, sustainLevel=.6, releaseTime=44100, _props ) => {
let envTrigger = bang(),
phase = accum( 1, envTrigger, { max: Infinity, shouldWrap:false, initialValue:Infinity }),
shouldSustain = param( 1 ),
defaults = {
shape: 'exponential',
alpha: 5,
triggerRelease: false,
},
props = Object.assign({}, defaults, _props ),
bufferData, decayData, out, buffer, sustainCondition, releaseAccum, releaseCondition
const completeFlag = data( [0] )
bufferData = env({ length:1024, alpha:props.alpha, shift:0, type:props.shape })
sustainCondition = props.triggerRelease
? shouldSustain
: lt( phase, add( attackTime, decayTime, sustainTime ) )
releaseAccum = props.triggerRelease
? gtp( sub( sustainLevel, accum( div( sustainLevel, releaseTime ) , 0, { shouldWrap:false }) ), 0 )
: sub( sustainLevel, mul( div( sub( phase, add( attackTime, decayTime, sustainTime ) ), releaseTime ), sustainLevel ) ),
releaseCondition = props.triggerRelease
? not( shouldSustain )
: lt( phase, add( attackTime, decayTime, sustainTime, releaseTime ) )
out = ifelse(
// attack
lt( phase, attackTime ),
peek( bufferData, div( phase, attackTime ), { boundmode:'clamp' } ),
// decay
lt( phase, add( attackTime, decayTime ) ),
peek( bufferData, sub( 1, mul( div( sub( phase, attackTime ), decayTime ), sub( 1, sustainLevel ) ) ), { boundmode:'clamp' }),
// sustain
and( sustainCondition, neq( phase, Infinity ) ),
peek( bufferData, sustainLevel ),
// release
releaseCondition, //lt( phase, attackTime + decayTime + sustainTime + releaseTime ),
peek(
bufferData,
releaseAccum,
//sub( sustainLevel, mul( div( sub( phase, attackTime + decayTime + sustainTime), releaseTime ), sustainLevel ) ),
{ 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 )
}
out.trigger = ()=> {
shouldSustain.value = 1
envTrigger.trigger()
}
// 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.release = ()=> {
shouldSustain.value = 0
// XXX pretty nasty... grabs accum inside of gtp and resets value manually
// unfortunately envTrigger won't work as it's back to 0 by the time the release block is triggered...
if( usingWorklet && out.node !== null ) {
out.node.port.postMessage({ key:'set', idx:releaseAccum.inputs[0].inputs[1].memory.value.idx, value:0 })
}else{
gen.memory.heap[ releaseAccum.inputs[0].inputs[1].memory.value.idx ] = 0
}
}
return out
}
},{"./accum.js":2,"./add.js":5,"./and.js":7,"./bang.js":11,"./data.js":19,"./div.js":24,"./env.js":25,"./gen.js":33,"./gtp.js":36,"./ifelseif.js":38,"./lt.js":41,"./mul.js":51,"./neq.js":52,"./not.js":54,"./param.js":56,"./peek.js":57,"./poke.js":61,"./sub.js":72}],7:[function(require,module,exports){
'use strict'
let gen = require( './gen.js' )
let proto = {
basename:'and',
gen() {
let inputs = gen.getInputs( this ), out
out = ` var ${this.name} = (${inputs[0]} !== 0 && ${inputs[1]} !== 0) | 0\n\n`
gen.memo[ this.name ] = `${this.name}`
return [ `${this.name}`, out ]
},
}
module.exports = ( in1, in2 ) => {
let ugen = Object.create( proto )
Object.assign( ugen, {
uid: gen.getUID(),
inputs: [ in1, in2 ],
})
ugen.name = `${ugen.basename}${ugen.uid}`
return ugen
}
},{"./gen.js":33}],8:[function(require,module,exports){
'use strict'
let gen = require('./gen.js')
let proto = {
basename:'asin',
gen() {
let out,
inputs = gen.getInputs( this )
const isWorklet = gen.mode === 'worklet'
const ref = isWorklet ? '' : 'gen.'
if( isNaN( inputs[0] ) ) {
gen.closures.add({ 'asin': isWorklet ? 'Math.sin' : Math.asin })
out = `${ref}asin( ${inputs[0]} )`
} else {
out = Math.asin( parseFloat( inputs[0] ) )
}
return out
}
}
module.exports = x => {
let asin = Object.create( proto )
asin.inputs = [ x ]
asin.id = gen.getUID()
asin.name = `${asin.basename}{asin.id}`
return asin
}
},{"./gen.js":33}],9:[function(require,module,exports){
'use strict'
let gen = require('./gen.js')
let proto = {
basename:'atan',
gen() {
let out,
inputs = gen.getInputs( this )
const isWorklet = gen.mode === 'worklet'
const ref = isWorklet ? '' : 'gen.'
if( isNaN( inputs[0] ) ) {
gen.closures.add({ 'atan': isWorklet ? 'Math.atan' : Math.atan })
out = `${ref}atan( ${inputs[0]} )`
} else {
out = Math.atan( parseFloat( inputs[0] ) )
}
return out
}
}
module.exports = x => {
let atan = Object.create( proto )
atan.inputs = [ x ]
atan.id = gen.getUID()
atan.name = `${atan.basename}{atan.id}`
return atan
}
},{"./gen.js":33}],10:[function(require,module,exports){
'use strict'
let gen = require( './gen.js' ),
history = require( './history.js' ),
mul = require( './mul.js' ),
sub = require( './sub.js' )
module.exports = ( decayTime = 44100 ) => {
let ssd = history ( 1 ),
t60 = Math.exp( -6.907755278921 / decayTime )
ssd.in( mul( ssd.out, t60 ) )
ssd.out.trigger = ()=> {
ssd.value = 1
}
return sub( 1, ssd.out )
}
},{"./gen.js":33,"./history.js":37,"./mul.js":51,"./sub.js":72}],11:[function(require,module,exports){
'use strict'
let gen = require('./gen.js')
let proto = {
gen() {
gen.requestMemory( this.memory )
let out =
` var ${this.name} = memory[${this.memory.value.idx}]
if( ${this.name} === 1 ) memory[${this.memory.value.idx}] = 0
`
gen.memo[ this.name ] = this.name
return [ this.name, out ]
}
}
module.exports = ( _props ) => {
let ugen = Object.create( proto ),
props = Object.assign({}, { min:0, max:1 }, _props )
ugen.name = 'bang' + gen.getUID()
ugen.min = props.min
ugen.max = props.max
const usingWorklet = gen.mode === 'worklet'
if( usingWorklet === true ) {
ugen.node = null
utilities.register( ugen )
}
ugen.trigger = () => {
if( usingWorklet === true && ugen.node !== null ) {
ugen.node.port.postMessage({ key:'set', idx:ugen.memory.value.idx, value:ugen.max })
}else{
if( gen.memory && gen.memory.heap )
gen.memory.heap[ ugen.memory.value.idx ] = ugen.max
}
}
ugen.memory = {
value: { length:1, idx:null }
}
return ugen
}
},{"./gen.js":33}],12:[function(require,module,exports){
'use strict'
let gen = require( './gen.js' )
let proto = {
basename:'bool',
gen() {
let inputs = gen.getInputs( this ), out
out = `${inputs[0]} === 0 ? 0 : 1`
//gen.memo[ this.name ] = `gen.data.${this.name}`
//return [ `gen.data.${this.name}`, ' ' +out ]
return out
}
}
module.exports = ( in1 ) => {
let ugen = Object.create( proto )
Object.assign( ugen, {
uid: gen.getUID(),
inputs: [ in1 ],
})
ugen.name = `${ugen.basename}${ugen.uid}`
return ugen
}
},{"./gen.js":33}],13:[function(require,module,exports){
'use strict'
let gen = require('./gen.js')
let proto = {
name:'ceil',
gen() {
let out,
inputs = gen.getInputs( this )
const isWorklet = gen.mode === 'worklet'
const ref = isWorklet ? '' : 'gen.'
if( isNaN( inputs[0] ) ) {
gen.closures.add({ [ this.name ]: isWorklet ? 'Math.ceil' : Math.ceil })
out = `${ref}ceil( ${inputs[0]} )`
} else {
out = Math.ceil( parseFloat( inputs[0] ) )
}
return out
}
}
module.exports = x => {
let ceil = Object.create( proto )
ceil.inputs = [ x ]
return ceil
}
},{"./gen.js":33}],14:[function(require,module,exports){
'use strict'
let gen = require('./gen.js'),
floor= require('./floor.js'),
sub = require('./sub.js'),
memo = require('./memo.js')
let proto = {
basename:'clip',
gen() {
let code,
inputs = gen.getInputs( this ),
out
out =
` var ${this.name} = ${inputs[0]}
if( ${this.name} > ${inputs[2]} ) ${this.name} = ${inputs[2]}
else if( ${this.name} < ${inputs[1]} ) ${this.name} = ${inputs[1]}
`
out = ' ' + out
gen.memo[ this.name ] = this.name
return [ this.name, out ]
},
}
module.exports = ( in1, min=-1, max=1 ) => {
let ugen = Object.create( proto )
Object.assign( ugen, {
min,
max,
uid: gen.getUID(),
inputs: [ in1, min, max ],
})
ugen.name = `${ugen.basename}${ugen.uid}`
return ugen
}
},{"./floor.js":30,"./gen.js":33,"./memo.js":45,"./sub.js":72}],15:[function(require,module,exports){
'use strict'
let gen = require('./gen.js')
let proto = {
basename:'cos',
gen() {
let out,
inputs = gen.getInputs( this )
const isWorklet = gen.mode === 'worklet'
const ref = isWorklet ? '' : 'gen.'
if( isNaN( inputs[0] ) ) {
gen.closures.add({ 'cos': isWorklet ? 'Math.cos' : Math.cos })
out = `${ref}cos( ${inputs[0]} )`
} else {
out = Math.cos( parseFloat( inputs[0] ) )
}
return out
}
}
module.exports = x => {
let cos = Object.create( proto )
cos.inputs = [ x ]
cos.id = gen.getUID()
cos.name = `${cos.basename}{cos.id}`
return cos
}
},{"./gen.js":33}],16:[function(require,module,exports){
'use strict'
let gen = require('./gen.js')
let proto = {
basename:'counter',
gen() {
let code,
inputs = gen.getInputs( this ),
genName = 'gen.' + this.name,
functionBody
if( this.memory.value.idx === null ) gen.requestMemory( this.memory )
gen.memory.heap[ this.memory.value.idx ] = this.initialValue
functionBody = this.callback( genName, inputs[0], inputs[1], inputs[2], inputs[3], inputs[4], `memory[${this.memory.value.idx}]`, `memory[${this.memory.wrap.idx}]` )
gen.memo[ this.name ] = this.name + '_value'
if( gen.memo[ this.wrap.name ] === undefined ) this.wrap.gen()
return [ this.name + '_value', functionBody ]
},
callback( _name, _incr, _min, _max, _reset, loops, valueRef, wrapRef ) {
let diff = this.max - this.min,
out = '',
wrap = ''
// must check for reset before storing value for output
if( !(typeof this.inputs[3] === 'number' && this.inputs[3] < 1) ) {
out += ` if( ${_reset} >= 1 ) ${valueRef} = ${_min}\n`
}
out += ` var ${this.name}_value = ${valueRef};\n ${valueRef} += ${_incr}\n` // store output value before accumulating
if( typeof this.max === 'number' && this.max !== Infinity && typeof this.min !== 'number' ) {
wrap =
` if( ${valueRef} >= ${this.max} && ${loops} > 0) {
${valueRef} -= ${diff}
${wrapRef} = 1
}else{
${wrapRef} = 0
}\n`
}else if( this.max !== Infinity && this.min !== Infinity ) {
wrap =
` if( ${valueRef} >= ${_max} && ${loops} > 0) {
${valueRef} -= ${_max} - ${_min}
${wrapRef} = 1
}else if( ${valueRef} < ${_min} && ${loops} > 0) {
${valueRef} += ${_max} - ${_min}
${wrapRef} = 1
}else{
${wrapRef} = 0
}\n`
}else{
out += '\n'
}
out = out + wrap
return out
}
}
module.exports = ( incr=1, min=0, max=Infinity, reset=0, loops=1, properties ) => {
let ugen = Object.create( proto ),
defaults = Object.assign( { initialValue: 0, shouldWrap:true }, properties )
Object.assign( ugen, {
min: min,
max: max,
initialValue: defaults.initialValue,
value: defaults.initialValue,
uid: gen.getUID(),
inputs: [ incr, min, max, reset, loops ],
memory: {
value: { length:1, idx: null },
wrap: { length:1, idx: null }
},
wrap : {
gen() {
if( ugen.memory.wrap.idx === null ) {
gen.requestMemory( ugen.memory )
}
gen.getInputs( this )
gen.memo[ this.name ] = `memory[ ${ugen.memory.wrap.idx} ]`
return `memory[ ${ugen.memory.wrap.idx} ]`
}
}
},
defaults )
Object.defineProperty( ugen, 'value', {
get() {
//console.log( 'counter value', this.memory.value.idx, gen.memory.heap[ this.memory.value.idx ], gen.memory )
if( this.memory.value.idx !== null ) {
return gen.memory.heap[ this.memory.value.idx ]
}
},
set( v ) {
if( this.memory.value.idx !== null ) {
//console.log( 'settting counter', v )
gen.memory.heap[ this.memory.value.idx ] = v
}
}
})
ugen.wrap.inputs = [ ugen ]
ugen.name = `${ugen.basename}${ugen.uid}`
ugen.wrap.name = ugen.name + '_wrap'
return ugen
}
},{"./gen.js":33}],17:[function(require,module,exports){
'use strict'
let gen = require( './gen.js' ),
accum= require( './phasor.js' ),
data = require( './data.js' ),
peek = require( './peek.js' ),
mul = require( './mul.js' ),
phasor=require( './phasor.js')
let proto = {
basename:'cycle',
initTable() {
let buffer = new Float32Array( 1024 )
for( let i = 0, l = buffer.length; i < l; i++ ) {
buffer[ i ] = Math.sin( ( i / l ) * ( Math.PI * 2 ) )
}
gen.globals.cycle = data( buffer, 1, { immutable:true } )
}
}
module.exports = ( frequency=1, reset=0, _props ) => {
if( typeof gen.globals.cycle === 'undefined' ) proto.initTable()
const props = Object.assign({}, { min:0 }, _props )
const ugen = peek( gen.globals.cycle, phasor( frequency, reset, props ))
ugen.name = 'cycle' + gen.getUID()
return ugen
}
},{"./data.js":19,"./gen.js":33,"./mul.js":51,"./peek.js":57,"./phasor.js":59}],18:[function(require,module,exports){
'use strict'
const gen = require( './gen.js' ),
accum= require( './phasor.js' ),
data = require( './data.js' ),
peek = require( './peek.js' ),
mul = require( './mul.js' ),
add = require( './add.js' ),
phasor=require( './phasor.js')
const proto = {
basename:'cycleN',
initTable() {
let buffer = new Float32Array( 1024 )
for( let i = 0, l = buffer.length; i < l; i++ ) {
buffer[ i ] = Math.sin( ( i / l ) * ( Math.PI * 2 ) )
}
gen.globals.cycle = data( buffer, 1, { immutable:true } )
}
}
module.exports = ( frequency=1, reset=0, _props ) => {
if( typeof gen.globals.cycle === 'undefined' ) proto.initTable()
const props = Object.assign({}, { min:0 }, _props )
const ugen = mul( add( 1, peek( gen.globals.cycle, phasor( frequency, reset, props )) ), .5 )
ugen.name = 'cycle' + gen.getUID()
return ugen
}
},{"./add.js":5,"./data.js":19,"./gen.js":33,"./mul.js":51,"./peek.js":57,"./phasor.js":59}],19:[function(require,module,exports){
'use strict'
const gen = require('./gen.js'),
utilities = require( './utilities.js' ),
peek = require('./peek.js'),
poke = require('./poke.js')
const proto = {
basename:'data',
globals: {},
memo:{},
gen() {
let idx
//console.log( 'data name:', this.name, proto.memo )
//debugger
if( gen.memo[ this.name ] === undefined ) {
let ugen = this
gen.requestMemory( this.memory, this.immutable )
idx = this.memory.values.idx
if( this.buffer !== undefined ) {
try {
gen.memory.heap.set( this.buffer, idx )
}catch( e ) {
console.log( e )
throw Error( 'error with request. asking for ' + this.buffer.length +'. current index: ' + gen.memoryIndex + ' of ' + gen.memory.heap.length )
}
}
//gen.data[ this.name ] = this
//return 'gen.memory' + this.name + '.buffer'
if( this.name.indexOf('data') === -1 ) {
proto.memo[ this.name ] = idx
}else{
gen.memo[ this.name ] = idx
}
}else{
//console.log( 'using gen data memo', proto.memo[ this.name ] )
idx = gen.memo[ this.name ]
}
return idx
},
}
module.exports = ( x, y=1, properties ) => {
let ugen, buffer, shouldLoad = false
if( properties !== undefined && properties.global !== undefined ) {
if( gen.globals[ properties.global ] ) {
return gen.globals[ properties.global ]
}
}
if( typeof x === 'number' ) {
if( y !== 1 ) {
buffer = []
for( let i = 0; i < y; i++ ) {
buffer[ i ] = new Float32Array( x )
}
}else{
buffer = new Float32Array( x )
}
}else if( Array.isArray( x ) ) { //! (x instanceof Float32Array ) ) {
let size = x.length
buffer = new Float32Array( size )
for( let i = 0; i < x.length; i++ ) {
buffer[ i ] = x[ i ]
}
}else if( typeof x === 'string' ) {
//buffer = { length: y > 1 ? y : gen.samplerate * 60 } // XXX what???
//if( proto.memo[ x ] === undefined ) {
buffer = { length: y > 1 ? y : 1 } // XXX what???
shouldLoad = true
//}else{
//buffer = proto.memo[ x ]
//}
}else if( x instanceof Float32Array ) {
buffer = x
}else if( x instanceof Uint8Array ) {
buffer = x
}else if( x instanceof AudioBuffer ) {
buffer = x.getChannelData(0)
}
ugen = Object.create( proto )
Object.assign( ugen,
{
buffer,
name: proto.basename + gen.getUID(),
dim: buffer !== undefined ? buffer.length : 1, // XXX how do we dynamically allocate this?
channels : 1,
onload: properties !== undefined ? properties.onload || null : null,
//then( fnc ) {
// ugen.onload = fnc
// return ugen
//},
immutable: properties !== undefined && properties.immutable === true ? true : false,
load( filename, __resolve ) {
let promise = utilities.loadSample( filename, ugen )
promise.then( _buffer => {
proto.memo[ x ] = _buffer
ugen.name = filename
ugen.memory.values.length = ugen.dim = _buffer.length
gen.requestMemory( ugen.memory, ugen.immutable )
gen.memory.heap.set( _buffer, ugen.memory.values.idx )
if( typeof ugen.onload === 'function' ) ugen.onload( _buffer )
__resolve( ugen )
})
},
memory : {
values: { length:buffer !== undefined ? buffer.length : 1, idx:null }
}
},
properties
)
if( properties !== undefined ) {
if( properties.global !== undefined ) {
gen.globals[ properties.global ] = ugen
}
if( properties.meta === true ) {
for( let i = 0, length = ugen.buffer.length; i < length; i++ ) {
Object.defineProperty( ugen, i, {
get () {
return peek( ugen, i, { mode:'simple', interp:'none' } )
},
set( v ) {
return poke( ugen, v, i )
}
})
}
}
}
let returnValue
if( shouldLoad === true ) {
returnValue = new Promise( (resolve,reject) => {
//ugen.load( x, resolve )
let promise = utilities.loadSample( x, ugen )
promise.then( _buffer => {
proto.memo[ x ] = _buffer
ugen.memory.values.length = ugen.dim = _buffer.length
ugen.buffer = _buffer
//gen.once( 'memory init', ()=> {
// console.log( "CALLED", ugen.memory )
// gen.requestMemory( ugen.memory, ugen.immutable )
// gen.memory.heap.set( _buffer, ugen.memory.values.idx )
// if( typeof ugen.onload === 'function' ) ugen.onload( _buffer )
//})
resolve( ugen )
})
})
}else if( proto.memo[ x ] !== undefined ) {
gen.once( 'memory init', ()=> {
gen.requestMemory( ugen.memory, ugen.immutable )
gen.memory.heap.set( ugen.buffer, ugen.memory.values.idx )
if( typeof ugen.onload === 'function' ) ugen.onload( ugen.buffer )
})
returnValue = ugen
}else{
returnValue = ugen
}
return returnValue
}
},{"./gen.js":33,"./peek.js":57,"./poke.js":61,"./utilities.js":78}],20:[function(require,module,exports){
'use strict'
let gen = require( './gen.js' ),
history = require( './history.js' ),
sub = require( './sub.js' ),
add = require( './add.js' ),
mul = require( './mul.js' ),
memo = require( './memo.js' )
module.exports = ( in1 ) => {
let x1 = history(),
y1 = history(),
filter
//History x1, y1; y = in1 - x1 + y1*0.9997; x1 = in1; y1 = y; out1 = y;
filter = memo( add( sub( in1, x1.out ), mul( y1.out, .9997 ) ) )
x1.in( in1 )
y1.in( filter )
return filter
}
},{"./add.js":5,"./gen.js":33,"./history.js":37,"./memo.js":45,"./mul.js":51,"./sub.js":72}],21:[function(require,module,exports){
'use strict'
let gen = require( './gen.js' ),
history = require( './history.js' ),
mul = require( './mul.js' ),
t60 = require( './t60.js' )
module.exports = ( decayTime = 44100, props ) => {
let properties = Object.assign({}, { initValue:1 }, props ),
ssd = history ( properties.initValue )
ssd.in( mul( ssd.out, t60( decayTime ) ) )
ssd.out.trigger = ()=> {
ssd.value = 1
}
return ssd.out
}
},{"./gen.js":33,"./history.js":37,"./mul.js":51,"./t60.js":74}],22:[function(require,module,exports){
'use strict'
const gen = require( './gen.js' ),
data = require( './data.js' ),
poke = require( './poke.js' ),
peek = require( './peek.js' ),
sub = require( './sub.js' ),
wrap = require( './wrap.js' ),
accum= require( './accum.js'),
memo = require( './memo.js' )
const proto = {
basename:'delay',
gen() {
let inputs = gen.getInputs( this )
gen.memo[ this.name ] = inputs[0]
return inputs[0]
},
}
const defaults = { size: 512, interp:'none' }
module.exports = ( in1, taps, properties ) => {
const ugen = Object.create( proto )
let writeIdx, readIdx, delaydata
if( Array.isArray( taps ) === false ) taps = [ taps ]
const props = Object.assign( {}, defaults, properties )
const maxTapSize = Math.max( ...taps )
if( props.size < maxTapSize ) props.size = maxTapSize
delaydata = data( props.size )
ugen.inputs = []
writeIdx = accum( 1, 0, { max:props.size, min:0 })
for( let i = 0; i < taps.length; i++ ) {
ugen.inputs[ i ] = peek( delaydata, wrap( sub( writeIdx, taps[i] ), 0, props.size ),{ mode:'samples', interp:props.interp })
}
ugen.outputs = ugen.inputs // XXX ugh, Ugh, UGH! but i guess it works.
poke( delaydata, in1, writeIdx )
ugen.name = `${ugen.basename}${gen.getUID()}`
return ugen
}
},{"./accum.js":2,"./data.js":19,"./gen.js":33,"./memo.js":45,"./peek.js":57,"./poke.js":61,"./sub.js":72,"./wrap.js":80}],23:[function(require,module,exports){
'use strict'
let gen = require( './gen.js' ),
history = require( './history.js' ),
sub = require( './sub.js' )
module.exports = ( in1 ) => {
let n1 = history()
n1.in( in1 )
let ugen = sub( in1, n1.out )
ugen.name = 'delta'+gen.getUID()
return ugen
}
},{"./gen.js":33,"./history.js":37,"./sub.js":72}],24:[function(require,module,exports){
'use strict'
let gen = require('./gen.js')
const proto = {
basename:'div',
gen() {
let inputs = gen.getInputs( this ),
out=` var ${this.name} = `,
diff = 0,
numCount = 0,
lastNumber = inputs[ 0 ],
lastNumberIsUgen = isNaN( lastNumber ),
divAtEnd = false
inputs.forEach( (v,i) => {
if( i === 0 ) return
let isNumberUgen = isNaN( v ),
isFinalIdx = i === inputs.length - 1
if( !lastNumberIsUgen && !isNumberUgen ) {
lastNumber = lastNumber / v
out += lastNumber
}else{
out += `${lastNumber} / ${v}`
}
if( !isFinalIdx ) out += ' / '
})
out += '\n'
gen.memo[ this.name ] = this.name
return [ this.name, out ]
}
}
module.exports = (...args) => {
const div = Object.create( proto )
Object.assign( div, {
id: gen.getUID(),
inputs: args,
})
div.name = div.basename + div.id
return div
}
},{"./gen.js":33}],25:[function(require,module,exports){
'use strict'
let gen = require( './gen' ),
windows = require( './windows' ),
data = require( './data' ),
peek = require( './peek' ),
phasor = require( './phasor' ),
defaults = {
type:'triangular', length:1024, alpha:.15, shift:0, reverse:false
}
module.exports = props => {
let properties = Object.assign( {}, defaults, props )
let buffer = new Float32Array( properties.length )
let name = properties.type + '_' + properties.length + '_' + properties.shift + '_' + properties.reverse + '_' + properties.alpha
if( typeof gen.globals.windows[ name ] === 'undefined' ) {
for( let i = 0; i < properties.length; i++ ) {
buffer[ i ] = windows[ properties.type ]( properties.length, i, properties.alpha, properties.shift )
}
if( properties.reverse === true ) {
buffer.reverse()
}
gen.globals.windows[ name ] = data( buffer )
}
let ugen = gen.globals.windows[ name ]
ugen.name = 'env' + gen.getUID()
return ugen
}
},{"./data":19,"./gen":33,"./peek":57,"./phasor":59,"./windows":79}],26:[function(require,module,exports){
'use strict'
let gen = require( './gen.js' )
let proto = {
basename:'eq',
gen() {
let inputs = gen.getInputs( this ), out
out = this.inputs[0] === this.inputs[1] ? 1 : ` var ${this.name} = (${inputs[0]} === ${inputs[1]}) | 0\n\n`
gen.memo[ this.name ] = `${this.name}`
return [ `${this.name}`, out ]
},
}
module.exports = ( in1, in2 ) => {
let ugen = Object.create( proto )
Object.assign( ugen, {
uid: gen.getUID(),
inputs: [ in1, in2 ],
})
ugen.name = `${ugen.basename}${ugen.uid}`
return ugen
}
},{"./gen.js":33}],27:[function(require,module,exports){
'use strict'
let gen = require('./gen.js')
let proto = {
name:'exp',
gen() {
let out,
inputs = gen.getInputs( this )
const isWorklet = gen.mode === 'worklet'
const ref = isWorklet? '' : 'gen.'
if( isNaN( inputs[0] ) ) {
gen.closures.add({ [ this.name ]: isWorklet ? 'Math.exp' : Math.exp })
out = `${ref}exp( ${inputs[0]} )`
} else {
out = Math.exp( parseFloat( inputs[0] ) )
}
return out
}
}
module.exports = x => {
let exp = Object.create( proto )
exp.inputs = [ x ]
return exp
}
},{"./gen.js":33}],28:[function(require,module,exports){
/**
* Copyright 2018 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
// originally from:
// https://github.com/GoogleChromeLabs/audioworklet-polyfill
// I am modifying it to accept variable buffer sizes
// and to get rid of some strange global initialization that seems required to use it
// with browserify. Also, I added changes to fix a bug in Safari for the AudioWorkletProcessor
// property not having a prototype (see:https://github.com/GoogleChromeLabs/audioworklet-polyfill/pull/25)
// TODO: Why is there an iframe involved? (realm.js)
const Realm = require( './realm.js' )
const AWPF = function( self = window, bufferSize = 4096 ) {
const PARAMS = []
let nextPort
if (typeof AudioWorkletNode !== 'function' || !("audioWorklet" in AudioContext.prototype)) {
self.AudioWorkletNode = function AudioWorkletNode (context, name, options) {
const processor = getProcessorsForContext(context)[name];
const outputChannels = options && options.outputChannelCount ? options.outputChannelCount[0] : 2;
const scriptProcessor = context.createScriptProcessor( bufferSize, 2, outputChannels);
scriptProcessor.parameters = new Map();
if (processor.properties) {
for (let i = 0; i < processor.properties.length; i++) {
const prop = processor.properties[i];
const node = context.createGain().gain;
node.value = prop.defaultValue;
// @TODO there's no good way to construct the proxy AudioParam here
scriptProcessor.parameters.set(prop.name, node);
}
}
const mc = new MessageChannel();
nextPort = mc.port2;
const inst = new processor.Processor(options || {});
nextPort = null;
scriptProcessor.port = mc.port1;
scriptProcessor.processor = processor;
scriptProcessor.instance = inst;
scriptProcessor.onaudioprocess = onAudioProcess;
return scriptProcessor;
};
Object.defineProperty((self.AudioContext || self.webkitAudioContext).prototype, 'audioWorklet', {
get () {
return this.$$audioWorklet || (this.$$audioWorklet = new self.AudioWorklet(this));
}
});
/* XXX - ADDED TO OVERCOME PROBLEM IN SAFARI WHERE AUDIOWORKLETPROCESSOR PROTOTYPE IS NOT AN OBJECT */
const AudioWorkletProcessor = function() {
this.port = nextPort
}
AudioWorkletProcessor.prototype = {}
self.AudioWorklet = class AudioWorklet {
constructor (audioContext) {
this.$$context = audioContext;
}
addModule (url, options) {
return fetch(url).then(r => {
if (!r.ok) throw Error(r.status);
return r.text();
}).then( code => {
const context = {
sampleRate: this.$$context.sampleRate,
currentTime: this.$$context.currentTime,
AudioWorkletProcessor,
registerProcessor: (name, Processor) => {
const processors = getProcessorsForContext(this.$$context);
processors[name] = {
realm,
context,
Processor,
properties: Processor.parameterDescriptors || []
};
}
};
context.self = context;
const realm = new Realm(context, document.documentElement);
realm.exec(((options && options.transpile) || String)(code));
return null;
});
}
};
}
function onAudioProcess (e) {
const parameters = {};
let index = -1;
this.parameters.forEach((value, key) => {
const arr = PARAMS[++index] || (PARAMS[index] = new Float32Array(this.bufferSize));
// @TODO proper values here if possible
arr.fill(value.value);
parameters[key] = arr;
});
this.processor.realm.exec(
'self.sampleRate=sampleRate=' + this.context.sampleRate + ';' +
'self.currentTime=currentTime=' + this.context.currentTime
);
const inputs = channelToArray(e.inputBuffer);
const outputs = channelToArray(e.outputBuffer);
this.instance.process([inputs], [outputs], parameters);
}
function channelToArray (ch) {
const out = [];
for (let i = 0; i < ch.numberOfChannels; i++) {
out[i] = ch.getChannelData(i);
}
return out;
}
function getProcessorsForContext (audioContext) {
return audioContext.$$processors || (audioContext.$$processors = {});
}
}
module.exports = AWPF
},{"./realm.js":29}],29:[function(require,module,exports){
/**
* Copyright 2018 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
module.exports = function Realm (scope, parentElement) {
const frame = document.createElement('iframe');
frame.style.cssText = 'position:absolute;left:0;top:-999px;width:1px;height:1px;';
parentElement.appendChild(frame);
const win = frame.contentWindow;
const doc = win.document;
let vars = 'var window,$hook';
for (const i in win) {
if (!(i in scope) && i !== 'eval') {
vars += ',';
vars += i;
}
}
for (const i in scope) {
vars += ',';
vars += i;
vars += '=self.';
vars += i;
}
const script = doc.createElement('script');
script.appendChild(doc.createTextNode(
`function $hook(self,console) {"use strict";
${vars};return function() {return eval(arguments[0])}}`
));
doc.body.appendChild(script);
this.exec = win.$hook.call(scope, scope, console);
}
},{}],30:[function(require,module,exports){
'use strict'
let gen = require('./gen.js')
let proto = {
name:'floor',
gen() {
let out,
inputs = gen.getInputs( this )
if( isNaN( inputs[0] ) ) {
//gen.closures.add({ [ this.name ]: Math.floor })
out = `( ${inputs[0]} | 0 )`
} else {
out = inputs[0] | 0
}
return out
}
}
module.exports = x => {
let floor = Object.create( proto )
floor.inputs = [ x ]
return floor
}
},{"./gen.js":33}],31:[function(require,module,exports){
'use strict'
let gen = require('./gen.js')
let proto = {
basename:'fold',
gen() {
let code,
inputs = gen.getInputs( this ),
out
out = this.createCallback( inputs[0], this.min, this.max )
gen.memo[ this.name ] = this.name + '_value'
return [ this.name + '_value', out ]
},
createCallback( v, lo, hi ) {
let out =
` var ${this.name}_value = ${v},
${this.name}_range = ${hi} - ${lo},
${this.name}_numWraps = 0
if(${this.name}_value >= ${hi}){
${this.name}_value -= ${this.name}_range
if(${this.name}_value >= ${hi}){
${this.name}_numWraps = ((${this.name}_value - ${lo}) / ${this.name}_range) | 0
${this.name}_value -= ${this.name}_range * ${this.name}_numWraps
}
${this.name}_numWraps++
} else if(${this.name}_value < ${lo}){
${this.name}_value += ${this.name}_range
if(${this.name}_value < ${lo}){
${this.name}_numWraps = ((${this.name}_value - ${lo}) / ${this.name}_range- 1) | 0
${this.name}_value -= ${this.name}_range * ${this.name}_numWraps
}
${this.name}_numWraps--
}
if(${this.name}_numWraps & 1) ${this.name}_value = ${hi} + ${lo} - ${this.name}_value
`
return ' ' + out
}
}
module.exports = ( in1, min=0, max=1 ) => {
let ugen = Object.create( proto )
Object.assign( ugen, {
min,
max,
uid: gen.getUID(),
inputs: [ in1 ],
})
ugen.name = `${ugen.basename}${ugen.uid}`
return ugen
}
},{"./gen.js":33}],32:[function(require,module,exports){
'use strict'
let gen = require( './gen.js' )
let proto = {
basename:'gate',
controlString:null, // insert into output codegen for determining indexing
gen() {
let inputs = gen.getInputs( this ), out
gen.requestMemory( this.memory )
let lastInputMemoryIdx = 'memory[ ' + this.memory.lastInput.idx + ' ]',
outputMemoryStartIdx = this.memory.lastInput.idx + 1,
inputSignal = inputs[0],
controlSignal = inputs[1]
/*
* we check to see if the current control inputs equals our last input
* if so, we store the signal input in the memory associated with the currently
* selected index. If not, we put 0 in the memory associated with the last selected index,
* change the selected index, and then store the signal in put in the memery assoicated
* with the newly selected index
*/
out =
` if( ${controlSignal} !== ${lastInputMemoryIdx} ) {
memory[ ${lastInputMemoryIdx} + ${outputMemoryStartIdx} ] = 0
${lastInputMemoryIdx} = ${controlSignal}
}
memory[ ${outputMemoryStartIdx} + ${controlSignal} ] = ${inputSignal}
`
this.controlString = inputs[1]
this.initialized = true
gen.memo[ this.name ] = this.name
this.outputs.forEach( v => v.gen() )
return [ null, ' ' + out ]
},
childgen() {
if( this.parent.initialized === false ) {
gen.getInputs( this ) // parent gate is only input of a gate output, should only be gen'd once.
}
if( gen.memo[ this.name ] === undefined ) {
gen.requestMemory( this.memory )
gen.memo[ this.name ] = `memory[ ${this.memory.value.idx} ]`
}
return `memory[ ${this.memory.value.idx} ]`
}
}
module.exports = ( control, in1, properties ) => {
let ugen = Object.create( proto ),
defaults = { count: 2 }
if( typeof properties !== undefined ) Object.assign( defaults, properties )
Object.assign( ugen, {
outputs: [],
uid: gen.getUID(),
inputs: [ in1, control ],
memory: {
lastInput: { length:1, idx:null }
},
initialized:false
},
defaults )
ugen.name = `${ugen.basename}${gen.getUID()}`
for( let i = 0; i < ugen.count; i++ ) {
ugen.outputs.push({
index:i,
gen: proto.childgen,
parent:ugen,
inputs: [ ugen ],
memory: {
value: { length:1, idx:null }
},
initialized:false,
name: `${ugen.name}_out${gen.getUID()}`
})
}
return ugen
}
},{"./gen.js":33}],33:[function(require,module,exports){
'use strict'
/* gen.js
*
* low-level code generation for unit generators
*
*/
const MemoryHelper = require( 'memory-helper' )
const EE = require( 'events' ).EventEmitter
const gen = {
accum:0,
getUID() { return this.accum++ },
debug:false,
samplerate: 44100, // change on audiocontext creation
shouldLocalize: false,
graph:null,
alwaysReturnArrays: false,
globals:{
windows: {},
},
mode:'worklet',
/* closures
*
* Functions that are included as arguments to master callback. Examples: Math.abs, Math.random etc.
* XXX Should probably be renamed callbackProperties or something similar... closures are no longer used.
*/
closures: new Set(),
params: new Set(),
inputs: new Set(),
parameters: new Set(),
endBlock: new Set(),
histories: new Map(),
memo: {},
//data: {},
/* export
*
* place gen functions into another object for easier reference
*/
export( obj ) {},
addToEndBlock( v ) {
this.endBlock.add( ' ' + v )
},
requestMemory( memorySpec, immutable=false ) {
for( let key in memorySpec ) {
let request = memorySpec[ key ]
//console.log( 'requesting ' + key + ':' , JSON.stringify( reques