UNPKG

gibberish-dsp

Version:

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

123 lines (104 loc) 3.98 kB
const g = require( 'genish.js' ), instrument = require( './instrument.js' ), feedbackOsc = require( '../oscillators/fmfeedbackosc.js' ) module.exports = function( Gibberish ) { const Mono = argumentProps => { const syn = Object.create( instrument ), oscs = [], frequency = g.in( 'frequency' ), glide = g.max( 1, g.in( 'glide' ) ), slidingFreq = g.memo( g.slide( frequency, glide, glide ) ), attack = g.in( 'attack' ), decay = g.in( 'decay' ), sustain = g.in( 'sustain' ), sustainLevel = g.in( 'sustainLevel' ), release = g.in( 'release' ), loudness = g.in( 'loudness' ), triggerLoudness = g.in( '__triggerLoudness' ), Loudness = g.mul( loudness, triggerLoudness ), saturation = g.in( 'saturation' ) const props = Object.assign( {}, Mono.defaults, argumentProps ) Object.assign( syn, props ) syn.__createGraph = function() { const env = Gibberish.envelopes.factory( props.useADSR, props.shape, attack, decay, sustain, sustainLevel, release, props.triggerRelease ) for( let i = 0; i < 3; i++ ) { let osc, freq switch( i ) { case 1: freq = g.add( slidingFreq, g.mul( slidingFreq, g.in('detune2') ) ) break; case 2: freq = g.add( slidingFreq, g.mul( slidingFreq, g.in('detune3') ) ) break; default: freq = slidingFreq } osc = Gibberish.oscillators.factory( syn.waveform, freq, syn.antialias ) oscs[ i ] = osc } //const baseCutoffFreq = g.in('cutoff') * (frequency / (g.gen.samplerate / 16 )) //const cutoff = baseCutoffFreq * g.pow( 2, g.in('filterMult') * loudness ) * env const oscSum = g.add( ...oscs ), // XXX horrible hack below to "use" saturation even when not using a diode filter oscWithEnv = props.filterModel=== 2 ? g.mul( oscSum, env ) : g.sub( g.add( g.mul( oscSum, env), saturation ), saturation ), baseCutoffFreq = g.mul( g.in('cutoff'), g.div( frequency, g.gen.samplerate / 16 ) ), cutoff = g.mul( g.mul( baseCutoffFreq, g.pow( 2, g.mul( g.in('filterMult'), Loudness ) )), env ), filteredOsc = Gibberish.filters.factory( oscWithEnv, cutoff, g.in('saturation'), syn ) if( props.panVoices ) { const panner = g.pan( filteredOsc,filteredOsc, g.in( 'pan' ) ) syn.graph = [ g.mul( panner.left, g.in('gain'), Loudness ), g.mul( panner.right, g.in('gain'), Loudness ) ] syn.isStereo = true }else{ syn.graph = g.mul( filteredOsc, g.in('gain'), Loudness ) syn.isStereo = false } syn.env = env } syn.__requiresRecompilation = [ 'waveform', 'antialias', 'filterModel', 'filterMode' ] syn.__createGraph() const out = Gibberish.factory( syn, syn.graph, ['instruments','Monosynth'], props ) return out } Mono.defaults = { waveform: 'saw', attack: 44, decay: 22050, sustain:44100, sustainLevel:.6, release:22050, useADSR:false, shape:'linear', triggerRelease:false, gain: .25, pulsewidth:.25, frequency:220, pan: .5, detune2:.005, detune3:-.005, cutoff: .5, Q: .25, panVoices:false, glide: 1, antialias:false, //filterType: 1, filterModel: 1, filterMode: 0, // 0 = LP, 1 = HP, 2 = BP, 3 = Notch saturation:.5, filterMult: 2, loudness:1, __triggerLoudness:1 } let PolyMono = Gibberish.PolyTemplate( Mono, [ 'frequency','attack','decay','cutoff','Q', 'detune2','detune3','pulsewidth','pan','gain', 'glide', 'saturation', 'filterMult', 'antialias', 'filterModel', 'waveform', 'filterMode', 'loudness', '__triggerLoudness' ] ) PolyMono.defaults = Mono.defaults return [ Mono, PolyMono ] }