import { debug as Debug } from 'debug' ; import { BaseRenderer , PlayingState } from './BaseRenderer' ; import { XAudioBuffer } from '../XAudioBuffer' ; import { TimeInstant } from '../time' ; import { mixdownToAudioBuffer } from '../AudioBufferUtils' ; import { XAudioContext } from '../WebAudioContext' ; const DBG_STR = 'nf:script-processor-renderer' ; const dbg = Debug ( DBG_STR ) ; export class ScriptProcessorRenderer extends BaseRenderer { private processor ? : ScriptProcessorNode ; constructor ( private ctx = XAudioContext ( ) , quantumSize = BaseRenderer . DEFAULT_QUANTUM_SIZE , autoRolloff = true ) { super ( { channelCount : ctx . destination . channelCount , sampleRate : ctx . sampleRate , quantumSize : Math . min ( Math . max ( quantumSize , 0 ) , 16384 ) , decode : ( uri , ab ) => new Promise < XAudioBuffer > ( ( resolve , reject ) => { dbg ( 'decoding file %s' , uri ) ; ctx . decodeAudioData ( ab , buffer => { dbg ( 'decoded file %s with length %d' , uri , buffer . length ) ; resolve ( XAudioBuffer . fromAudioBuffer ( buffer ) ) ; } , err => { dbg ( 'failed to decode file %s, %s' , uri , err && err . message ) ; reject ( err ) ; } ) ; } ) } , autoRolloff ) ; this . processor = this . ctx . createScriptProcessor ( this . info . quantumSize ) ; this . processor . onaudioprocess = evt => { const start = window . performance . now ( ) ; for ( let i = 0 ; i < evt . outputBuffer . numberOfChannels ; i ++ ) { const destChan = evt . outputBuffer . getChannelData ( i ) ; for ( let s = 0 ; s < destChan . length ; s ++ ) { destChan [ s ] = 0 ; } } const buffer = this . renderQuantum ( ) ; if ( buffer ) { mixdownToAudioBuffer ( evt . outputBuffer , [ buffer ] ) ; } if ( ! this . playing ) return ; if ( dbg . enabled ) { const end = window . performance . now ( ) ; const lastDuration = end - start ; console . log ( 'sampleIndex' , this . samplesElapsed - this . info . quantumSize , 'processor duration' , lastDuration + 'ms' , 'budget remaining' , TimeInstant . fromSeconds ( evt . playbackTime ) . sub ( TimeInstant . fromSeconds ( this . ctx . currentTime ) ) . asMillis ( ) + 'ms' ) ; } } ; this . processor . connect ( this . ctx . destination ) ; } get playing ( ) { return super . playing ; } set playing ( state ) { if ( this . ctx && this . ctx . state === 'suspended' ) { this . ctx . resume ( ) ; } super . playing = ! ! state ; } }