import * as assert from 'assert' ; import { ZxAudioBeeper } from '../src/remotes/zsimulator/zsimwebview/zxaudiobeeper' ; import { BeeperBuffer } from '../src/remotes/zsimulator/zxbeeper' ; class ZxAudioMock extends ZxAudioBeeper { public MIN_LATENCY : number ; public MAX_LATENCY : number ; public ctx : AudioContext ; public volume : number ; public sampleRate : number ; public audioCtxStartTime : number ; public nextFrameIndex : number ; public fixedFrameLength : number ; public nextFrame : Float32Array ; constructor ( sampleRate ) { super ( sampleRate ) ; AudioBufferSourceNodeMock . mockClear ( ) ; } protected createAudioContext ( sampleRate ) { return new AudioContextMock ( sampleRate ) as any ; } protected updateVisualBeeper ( ) { } get ctxMock ( ) : AudioContextMock { return this . ctx as any ; } } class GainNodeMock { public gain = { value : 0 } ; public connect ( destinationNode , output ? , input ? ) { return destinationNode ; } public linearRampToValueAtTime ( value , endTime ) { return undefined as any ; } } class AudioContextMock { public sampleRate : number ; public channelBuffer : Array < Float32Array > ; public sourceBuffer : Array < number > ; public audioBufferSourceNodeMock : AudioBufferSourceNodeMock ; public currentTimeMock = 0 ; constructor ( sampleRate ) { this . sampleRate = sampleRate ; } get currentTime ( ) { return this . currentTimeMock ; } protected createGain ( ) { return new GainNodeMock ( ) as any ; } public createBuffer ( numberOfChannels , length , sampleRate ) { this . channelBuffer = new Array < Float32Array > ( numberOfChannels ) ; for ( let i = 0 ; i < numberOfChannels ; i ++ ) this . channelBuffer [ i ] = new Float32Array ( length ) ; return new AudioBufferMock ( this . channelBuffer ) as any ; } public createBufferSource ( ) { this . audioBufferSourceNodeMock = new AudioBufferSourceNodeMock ( ) ; return this . audioBufferSourceNodeMock as any ; } get frameStartTime ( ) { return this . audioBufferSourceNodeMock . frameStartTime ; } } class AudioBufferMock { protected channelBuffer : Array < Float32Array > ; constructor ( channelBuffer ) { this . channelBuffer = channelBuffer ; } public getChannelData ( channel ) { return this . channelBuffer [ channel ] ; } } class AudioBufferSourceNodeMock { public frameStartTime : number | undefined ; public buffer : AudioBuffer | undefined ; constructor ( ) { AudioBufferSourceNodeMock . sourceNodes . push ( this ) ; } public connect ( destinationNode , output ? , input ? ) { return destinationNode ; } public start ( when ? , offset ? , duration ? ) { this . frameStartTime = when ; } public addEventListener ( event , func ) { } public static sourceNodes : Array < AudioBufferSourceNodeMock > ; public static mockClear ( ) { this . sourceNodes = new Array < AudioBufferSourceNodeMock > ( ) ; } } suite ( 'ZxAudioBeeper' , ( ) => { test ( 'constructor' , ( ) => { const zxAudio = new ZxAudioMock ( 22000 ) ; assert . equal ( zxAudio . volume , 0.75 ) ; assert . notEqual ( zxAudio . ctx , undefined ) ; assert . equal ( zxAudio . ctx . sampleRate , 22000 ) ; assert . equal ( zxAudio . sampleRate , 22000 ) ; assert . equal ( zxAudio . audioCtxStartTime , 0 ) ; } ) ; suite ( 'writeBeeperSamples' , ( ) => { test ( 'basics' , ( ) => { const zxAudio = new ZxAudioMock ( 22000 ) ; assert . equal ( zxAudio . audioCtxStartTime , 0 ) ; let beeperBuffer = { totalLength : 0 , startValue : true , buffer : new Uint16Array ( 0 ) , bufferLen : 0 } ; zxAudio . writeBeeperSamples ( beeperBuffer ) ; assert . equal ( zxAudio . audioCtxStartTime , 0 ) ; assert . equal ( zxAudio . nextFrameIndex , 0 ) ; assert . equal ( AudioBufferSourceNodeMock . sourceNodes . length , 2 ) ; beeperBuffer = { totalLength : 10 , startValue : false , buffer : new Uint16Array ( [ 10 ] ) , bufferLen : 1 } ; zxAudio . writeBeeperSamples ( beeperBuffer ) ; assert . equal ( zxAudio . audioCtxStartTime , 0 ) ; assert . equal ( zxAudio . nextFrameIndex , 10 ) ; beeperBuffer = { totalLength : zxAudio . fixedFrameLength + 5 , startValue : true , buffer : new Uint16Array ( [ zxAudio . fixedFrameLength + 5 ] ) , bufferLen : 1 } ; AudioBufferSourceNodeMock . mockClear ( ) ; zxAudio . writeBeeperSamples ( beeperBuffer ) ; assert . equal ( zxAudio . nextFrameIndex , 10 + 5 ) ; assert . equal ( AudioBufferSourceNodeMock . sourceNodes . length , 1 ) ; beeperBuffer = { totalLength : 2 * zxAudio . fixedFrameLength , startValue : true , buffer : new Uint16Array ( [ zxAudio . fixedFrameLength , zxAudio . fixedFrameLength ] ) , bufferLen : 2 } ; AudioBufferSourceNodeMock . mockClear ( ) ; zxAudio . writeBeeperSamples ( beeperBuffer ) ; assert . equal ( zxAudio . nextFrameIndex , 10 + 5 ) ; assert . equal ( AudioBufferSourceNodeMock . sourceNodes . length , 2 ) ; } ) ; test ( 'startValue' , ( ) => { const zxAudio = new ZxAudioMock ( 22000 ) ; zxAudio . volume = 1 ; assert . equal ( zxAudio . audioCtxStartTime , 0 ) ; let beeperBuffer = { totalLength : 3 , startValue : true , buffer : new Uint16Array ( [ 3 ] ) , bufferLen : 1 } ; zxAudio . writeBeeperSamples ( beeperBuffer ) ; assert . equal ( zxAudio . nextFrameIndex , 3 ) ; for ( let i = 0 ; i < 3 ; i ++ ) { assert . equal ( zxAudio . nextFrame [ i ] , 1.0 ) ; } beeperBuffer = { totalLength : 4 , startValue : false , buffer : new Uint16Array ( [ 4 ] ) , bufferLen : 1 } ; zxAudio . writeBeeperSamples ( beeperBuffer ) ; assert . equal ( zxAudio . nextFrameIndex , 7 ) ; for ( let i = 3 ; i < 7 ; i ++ ) { assert . equal ( zxAudio . nextFrame [ i ] , 0.0 ) ; } } ) ; } ) ; } ) ;