UNPKG

gibberish-dsp

Version:

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

124 lines (96 loc) 4.3 kB
let g = require( 'genish.js' ), effect = require( './effect.js' ) module.exports = function( Gibberish ) { let proto = Object.create( effect ) let Shuffler = inputProps => { let bufferShuffler = Object.create( proto ), bufferSize = 88200 const props = Object.assign( {}, Shuffler.defaults, effect.defaults, inputProps ) let out bufferShuffler.__createGraph = function() { let isStereo = false if( out === undefined ) { isStereo = typeof props.input.isStereo !== 'undefined' ? props.input.isStereo : true }else{ isStereo = out.input.isStereo //out.isStereo = isStereo } const phase = g.accum( 1,0,{ shouldWrap: false }) const input = g.in( 'input' ), inputGain = g.in( 'inputGain' ), __leftInput = isStereo ? input[ 0 ] : input, __rightInput = isStereo ? input[ 1 ] : null, leftInput = g.mul( __leftInput, inputGain ), rightInput = g.mul( __rightInput, inputGain ), rateOfShuffling = g.in( 'rate' ), chanceOfShuffling = g.in( 'chance' ), reverseChance = g.in( 'reverseChance' ), repitchChance = g.in( 'repitchChance' ), repitchMin = g.in( 'repitchMin' ), repitchMax = g.in( 'repitchMax' ) let pitchMemory = g.history(1) let shouldShuffleCheck = g.eq( g.mod( phase, rateOfShuffling ), 0 ) let isShuffling = g.memo( g.sah( g.lt( g.noise(), chanceOfShuffling ), shouldShuffleCheck, 0 ) ) // if we are shuffling and on a repeat boundary... let shuffleChanged = g.memo( g.and( shouldShuffleCheck, isShuffling ) ) let shouldReverse = g.lt( g.noise(), reverseChance ), reverseMod = g.switch( shouldReverse, -1, 1 ) let pitch = g.ifelse( g.and( shuffleChanged, g.lt( g.noise(), repitchChance ) ), g.memo( g.mul( g.add( repitchMin, g.mul( g.sub( repitchMax, repitchMin ), g.noise() ) ), reverseMod ) ), reverseMod ) // only switch pitches on repeat boundaries pitchMemory.in( g.switch( shuffleChanged, pitch, pitchMemory.out ) ) let fadeLength = g.memo( g.div( rateOfShuffling, 100 ) ), fadeIncr = g.memo( g.div( 1, fadeLength ) ) const bufferL = g.data( bufferSize ) const bufferR = isStereo ? g.data( bufferSize ) : null let readPhase = g.accum( pitchMemory.out, 0, { shouldWrap:false }) let stutter = g.wrap( g.sub( g.mod( readPhase, bufferSize ), 22050 ), 0, bufferSize ) let normalSample = g.peek( bufferL, g.accum( 1, 0, { max:88200 }), { mode:'simple' }) let stutterSamplePhase = g.switch( isShuffling, stutter, g.mod( readPhase, bufferSize ) ) let stutterSample = g.memo( g.peek( bufferL, stutterSamplePhase, { mode:'samples' } ) ) let stutterShouldFadeIn = g.and( shuffleChanged, isShuffling ) let stutterPhase = g.accum( 1, shuffleChanged, { shouldWrap: false }) let fadeInAmount = g.memo( g.div( stutterPhase, fadeLength ) ) let fadeOutAmount = g.div( g.sub( rateOfShuffling, stutterPhase ), g.sub( rateOfShuffling, fadeLength ) ) let fadedStutter = g.ifelse( g.lt( stutterPhase, fadeLength ), g.memo( g.mul( g.switch( g.lt( fadeInAmount, 1 ), fadeInAmount, 1 ), stutterSample ) ), g.gt( stutterPhase, g.sub( rateOfShuffling, fadeLength ) ), g.memo( g.mul( g.gtp( fadeOutAmount, 0 ), stutterSample ) ), stutterSample ) let outputL = g.mix( normalSample, fadedStutter, isShuffling ) let pokeL = g.poke( bufferL, leftInput, g.mod( g.add( phase, 44100 ), 88200 ) ) let panner = g.pan( outputL, outputL, g.in( 'pan' ) ) bufferShuffler.graph = [ panner.left, panner.right ] } bufferShuffler.__createGraph() bufferShuffler.__requiresRecompilation = [ 'input' ] out = Gibberish.factory( bufferShuffler, bufferShuffler.graph, ['fx','shuffler'], props ) return out } Shuffler.defaults = { input:0, rate:22050, chance:.25, reverseChance:.5, repitchChance:.5, repitchMin:.5, repitchMax:2, pan:.5, mix:.5 } return Shuffler }