UNPKG

gibberish-dsp

Version:

Gibberish is designed to be an optimized API for audio synthesis using per-sample techniques.

160 lines (135 loc) 4.93 kB
const __proxy = require( './workletProxy.js' ) const effectProto = require( './fx/effect.js' ) module.exports = function( Gibberish ) { const proxy = __proxy( Gibberish ) const factory = function( ugen, graph, __name, values, cb=null, shouldProxy = true ) { if( Gibberish.mode === 'processor' ) ugen.callback = cb === null ? Gibberish.genish.gen.createCallback( graph, Gibberish.memory, false, true ) : cb else ugen.callback = { out:[] } let name = Array.isArray( __name ) ? __name[ __name.length - 1 ] : __name Object.assign( ugen, { //type: 'ugen', id: values.id || Gibberish.utilities.getUID(), ugenName: name + '_', graph: graph, inputNames: ugen.inputNames || new Set( Gibberish.genish.gen.parameters ), isStereo: Array.isArray( graph ), dirty: true, __properties__:values, __addresses__:{} }) ugen.ugenName += ugen.id if( Gibberish.mode === 'processor' ) { ugen.callback.ugenName = ugen.ugenName // XXX hacky ugen.callback.id = ugen.id } //console.log( 'ugen name/id:', ugen.ugenName, ugen.id ) //console.log( 'callback name/id:', ugen.callback.ugenName, ugen.callback.id ) for( let param of ugen.inputNames ) { if( param === 'memory' ) continue let value = values[ param ], isNumber = typeof value === 'object' || isNaN( value ) ? false : true, idx if( isNumber ) { idx = Gibberish.memory.alloc( 1 ) Gibberish.memory.heap[ idx ] = value ugen.__addresses__[ param ] = idx } // TODO: do we need to check for a setter? let desc = Object.getOwnPropertyDescriptor( ugen, param ), setter if( desc !== undefined ) { setter = desc.set } Object.defineProperty( ugen, param, { configurable:true, get() { if( isNumber ) { return Gibberish.memory.heap[ idx ] }else{ return value } }, set( v ) { //if( param === 'input' ) console.log( 'INPUT:', v, isNumber ) if( value !== v ) { if( setter !== undefined ) setter( v ) if( typeof v === 'number' ) { Gibberish.memory.heap[ idx ] = value = v if( isNumber === false ) Gibberish.dirty( ugen ) isNumber = true }else{ value = v /*if( isNumber === true )*/ Gibberish.dirty( ugen ) //console.log( 'switching from number:', param, value ) isNumber = false } } } }) } // add bypass if( effectProto.isPrototypeOf( ugen ) ) { let value = ugen.bypass Object.defineProperty( ugen, 'bypass', { configurable:true, get() { return value }, set( v ) { if( value !== v ) { Gibberish.dirty( ugen ) value = v } } }) } if( ugen.__requiresRecompilation !== undefined ) { ugen.__requiresRecompilation.forEach( prop => { let value = values[ prop ] let isNumber = !isNaN( value ) Object.defineProperty( ugen, prop, { configurable:true, get() { if( isNumber ) { let idx = ugen.__addresses__[ prop ] return Gibberish.memory.heap[ idx ] }else{ //console.log( 'returning:', prop, value, Gibberish.mode ) return value } }, set( v ) { if( value !== v ) { if( typeof v === 'number' ) { let idx = ugen.__addresses__[ prop ] if( idx === undefined ){ idx = Gibberish.memory.alloc( 1 ) ugen.__addresses__[ prop ] = idx } value = values[ prop ] = Gibberish.memory.heap[ idx ] = v isNumber = true }else{ value = values[ prop ] = v isNumber = false //console.log( 'setting ugen', value, Gibberish.mode ) Gibberish.dirty( ugen ) } //console.log( 'SETTING REDO GRAPH', prop, Gibberish.mode ) // needed for filterType at the very least, becauae the props // are reused when re-creating the graph. This seems like a cheaper // way to solve this problem. //values[ prop ] = v this.__redoGraph() } } }) }) } // will only create proxy if worklets are being used // otherwise will return unaltered ugen if( values.shouldAddToUgen === true ) Object.assign( ugen, values ) return shouldProxy ? proxy( __name, values, ugen ) : ugen } factory.getUID = () => { return Gibberish.utilities.getUID() } return factory }