gibberish-dsp
Version:
Gibberish is designed to be an optimized API for audio synthesis using per-sample techniques.
215 lines (161 loc) • 6.1 kB
JavaScript
const g = require( 'genish.js' ),
analyzer = require( './analyzer.js' ),
ugen = require( '../ugen.js' )
const genish = g
module.exports = function( Gibberish ) {
const Follow = function( __props ){
const props = Object.assign( {}, Follow.defaults, __props )
let isStereo = typeof props.input.isStereo !== 'undefined' ? props.input.isStereo : false
let out = props
/* if we are in the main thread,
* only send a command to make a Follow instance
* to the processor thread and include the id #
* of the input ugen.
*/
//console.log( 'isStereo:', Gibberish.mode, isStereo, props.input )
if( Gibberish.mode === 'worklet' ) {
// send obj to be made in processor thread
props.input = { id: props.input.id }
props.isStereo = isStereo
// creates clashes in processor thread unless
// we skip a number here... nice
Gibberish.utilities.getUID()
props.overrideid = Gibberish.utilities.getUID()
// XXX seems like this id gets overridden somewhere
// hence .overrideid
props.id = props.overrideid
Gibberish.worklet.port.postMessage({
address:'add',
properties:JSON.stringify( props ),
name:['analysis','Follow']
})
Gibberish.worklet.ugens.set( props.overrideid, out )
let mult = props.multiplier
Object.defineProperty( out, 'multiplier', {
get() { return mult },
set(v){
mult = v
Gibberish.worklet.port.postMessage({
address:'set',
object:props.overrideid,
name:'multiplier',
value:mult
})
}
})
let offset = props.offset
Object.defineProperty( out, 'offset', {
get() { return offset },
set(v){
offset = v
Gibberish.worklet.port.postMessage({
address:'set',
object:props.overrideid,
name:'offset',
value:offset
})
}
})
}else{
//isStereo = props.isStereo
const buffer = g.data( props.bufferSize, 1 )
const input = g.in( 'input' )
const multiplier = g.in( 'multiplier' )
const offset = g.in( 'offset' )
const follow_out = Object.create( analyzer )
follow_out.id = props.id = __props.overrideid
let avg = g.data( 1,1, { meta:true } ) // output; make available outside jsdsp block
const idx = avg.memory.values.idx
const callback = function( memory ) {
return avg[0]
}
const out = {
callback,
input:props.input,
isStereo,
dirty:true,
inputNames:[ 'input', 'memory' ],
inputs:[ props.input ],
id: Gibberish.utilities.getUID(),
__properties__: { input:props.input },
}
// nonsense to make our custom function work
out.callback.ugenName = out.ugenName = `follow_out_${follow_out.id}`
out.id = __props.overrideid
// begin input tracker
const follow_in = Object.create( ugen )
if( isStereo === true ) {
if( props.outputStereo === false ) {
{
"use jsdsp"
// phase to write to follow buffer
const bufferPhaseOut = g.accum( 1,0,{ max:props.bufferSize, min:0 })
// hold running sum
const sum = g.data( 1, 1, { meta:true })
const mono = props.abs === true ? g.abs( input[0] + input[1] ) : input[0] + input[1]
sum[0] = sum[0] + mono - g.peek( buffer, bufferPhaseOut, { mode:'simple' })
g.poke( buffer, g.abs( mono ), bufferPhaseOut )
avg = (sum[0] / props.bufferSize) * multiplier + offset
}
}else{
const bufferL = buffer
const bufferR = g.data( props.bufferSize, 1 )
{
"use jsdsp"
// phase to write to follow buffer
const bufferPhaseOut = g.accum( 1,0,{ max:props.bufferSize, min:0 })
// hold running sum
const sumL = g.data( 1, 1, { meta:true })
const sumR = g.data( 1, 1, { meta:true })
const left = props.abs === true ? g.abs( input[0] ) : input[0]
const right = props.abs === true ? g.abs( input[1] ) : input[1]
sumL[0] = sumL[0] + left - g.peek( bufferL, bufferPhaseOut, { mode:'simple' })
sumR[0] = sumR[0] + right- g.peek( bufferR, bufferPhaseOut, { mode:'simple' })
g.poke( bufferL, g.abs( left ), bufferPhaseOut )
g.poke( bufferR, g.abs( right ), bufferPhaseOut )
avg = [
(sumL[0] / props.bufferSize) * multiplier + offset,
(sumR[0] / props.bufferSize) * multiplier + offset,
]
}
}
}else{
{
"use jsdsp"
// phase to write to follow buffer
const bufferPhaseOut = g.accum( 1,0,{ max:props.bufferSize, min:0 })
// hold running sum
const sum = g.data( 1, 1, { meta:true })
const __input = props.abs === true ? g.abs( input ) : input
sum[0] = sum[0] + __input - g.peek( buffer, bufferPhaseOut, { mode:'simple' })
g.poke( buffer, g.abs( input ), bufferPhaseOut )
avg = (sum[0] / props.bufferSize) * multiplier + offset
}
}
Gibberish.utilities.getUID()
props.isStereo = false
const record = Gibberish.factory(
follow_in,
avg,
['analysis', 'follow_in'],
props
)
// nonsense to make our custom function work
record.callback.ugenName = record.ugenName = `follow_in_${follow_out.id}`
if( Gibberish.analyzers.indexOf( record ) === -1 ) Gibberish.analyzers.push( record )
Gibberish.dirty( Gibberish.analyzers )
Gibberish.ugens.set( __props.overrideid, record )
out.record = record
}
return out
}
Follow.defaults = {
input:0,
bufferSize:1024,
multiplier:1,
abs: true,
outputStereo:false,
offset:0
}
return Follow
}