declare function __non_webpack_require__ ( fn ) ; import { audio as SDLAudio } from 'node-sdl2/lib/audio' ; const NS = __non_webpack_require__ ( 'node-sdl2' ) ; const SDL_audio = NS . require ( 'SDL_audio' ) ; class AudioParam { public value = 0 ; public setValueAtTime ( value , _time ) { this . value = value ; } } abstract class AudioNode { protected connectedNodes = new Array < AudioNode > ( ) ; public constructor ( protected context ) { } public connect ( destNode ) { destNode . connectedNodes . push ( this ) ; } public disconnect ( ) { } public start ( ) { } public abstract sample ( counter , sampleRate ) ; } export class PeriodicWave { constructor ( _real , _imag ) { } } const enum OscillatorType { NONE , TRIANGLE , SAWTOOTH , PERIODIC_WAVE } export class OscillatorNode extends AudioNode { public frequency = new AudioParam ( ) ; private oscType = OscillatorType . NONE ; public set type ( value ) { switch ( value ) { case 'triangle' : this . oscType = OscillatorType . TRIANGLE ; break ; case 'sawtooth' : this . oscType = OscillatorType . SAWTOOTH ; break ; default : this . oscType = OscillatorType . NONE ; break ; } } setPeriodicWave ( _wave ) { this . oscType = OscillatorType . PERIODIC_WAVE ; } public sample ( counter , sampleRate ) { switch ( this . oscType ) { case OscillatorType . TRIANGLE : { const waveLength = sampleRate / this . frequency . value ; const t = ( ( counter + sampleRate ) * 4 / waveLength ) % 4 ; return t < 2 ? t - 1 : 3 - t ; } case OscillatorType . SAWTOOTH : { const waveLength = sampleRate / this . frequency . value ; const t = ( ( counter + sampleRate ) * 2 / waveLength ) % 2 ; return t - 1 ; } } return 0 ; } } export class GainNode extends AudioNode { public gain = new AudioParam ( ) ; public sample ( counter , sampleRate ) { const gain = this . gain . value ; if ( gain === 0 ) return 0 ; let value = 0 ; const nodes = this . connectedNodes ; for ( let i = 0 ; i < nodes . length ; ++ i ) value += nodes [ i ] . sample ( counter , sampleRate ) ; return value * gain ; } } export class DelayNode extends AudioNode { public delayTime = new AudioParam ( ) ; public sample ( counter , sampleRate ) { let value = 0 ; const nodes = this . connectedNodes ; const c = counter - ( ( this . delayTime . value * sampleRate ) | 0 ) ; for ( let i = 0 ; i < nodes . length ; ++ i ) value += nodes [ i ] . sample ( c , sampleRate ) ; return value ; } } class AudioDestinationNode extends AudioNode { private time = 0 ; public fillBuffer ( array ) { const len = array . length ; const nodes = this . connectedNodes ; const sampleRate = this . context . sampleRate | 0 ; let counter = Math . round ( this . time * sampleRate ) | 0 ; for ( let i = 0 ; i < len ; ++ i ) { let value = 0 ; for ( let j = 0 ; j < nodes . length ; ++ j ) { const node = nodes [ j ] ; value += node . sample ( ( counter + i ) | 0 , sampleRate ) ; } array [ i ] = value ; } this . time = ( ( counter + len ) / sampleRate ) % 1.0 ; } public sample ( _counter , _sampleRate ) { return 0 ; } } export class AudioContext { private audio : SDLAudio ; private destination = new AudioDestinationNode ( this ) ; public get sampleRate ( ) : number { return this . audio . spec . freq ; } public constructor ( ) { this . audio = NS . audio . create ( ) ; const options = { freq : 48000 , channels : 1 , format : SDL_audio . SDL_AudioFormatFlag . AUDIO_F32 , samples : 512 , } ; this . audio . openAudioDevice ( options , ( arrayBuffer ) => { const array = new Float32Array ( arrayBuffer ) ; this . destination . fillBuffer ( array ) ; } ) ; } public createGain ( ) { return new GainNode ( this ) ; } public createOscillator ( ) { return new OscillatorNode ( this ) ; } public createDelay ( ) { return new DelayNode ( this ) ; } public createPeriodicWave ( real , imag ) { return new PeriodicWave ( real , imag ) ; } }