/**
 * Pass this function an audio context to check to see if it is unlocked
 * An isUnlocked boolean is passed as a parameter of the callback function
 */ export function isIOSAudioUnlocked ( context , cb ) { const source = createEmptyBuffer ( context ) ; setTimeout ( ( ) => { cb ( ( ( < any > source ) . playbackState === ( < any > source ) . PLAYING_STATE || ( < any > source ) . playbackState === ( < any > source ) . FINISHED_STATE ) ) ; } , 1 ) ; } export function createEmptyBuffer ( context ) { const buffer = context . createBuffer ( 1 , 1 , 22050 ) ; const source = context . createBufferSource ( ) ; source . buffer = buffer ; source . connect ( context . destination ) ; source . start ( context . currentTime ) ; return source ; } returns { AudioContext } constructor export function createIOSSafeAudioContext ( desiredSampleRate = 44100 ) { const AudioContext = ( < any > window ) . AudioContext || ( < any > window ) . webkitAudioContext ; let context = new AudioContext ( ) ; if ( /(iPhone|iPad)/i . test ( navigator . userAgent ) && context . sampleRate !== desiredSampleRate ) { var buffer = context . createBuffer ( 1 , 1 , desiredSampleRate ) ; var dummy = context . createBufferSource ( ) ; dummy . buffer = buffer ; dummy . connect ( context . destination ) ; dummy . start ( 0 ) ; dummy . disconnect ( ) ; context . close ( ) ; context = new AudioContext ( ) ; } return context ; } param oldBuffer { AudioBuffer } param newBuffer { AudioBuffer } returns { AudioBuffer } export function appendBuffer ( oldBuffer , newBuffer = oldBuffer , audioContext ) { if ( ! oldBuffer && newBuffer ) { return newBuffer ; } else if ( ! newBuffer && oldBuffer ) { return oldBuffer ; } const numOfChannels = Math . min ( oldBuffer . numberOfChannels , newBuffer . numberOfChannels ) ; const joinedLength = ( oldBuffer . length + newBuffer . length ) ; const joinedBuffer = audioContext . createBuffer ( numOfChannels , joinedLength , oldBuffer . sampleRate ) ; for ( var i = 0 ; i < numOfChannels ; i ++ ) { var channel = joinedBuffer . getChannelData ( i ) ; channel . set ( oldBuffer . getChannelData ( i ) , 0 ) ; channel . set ( newBuffer . getChannelData ( i ) , oldBuffer . length ) ; } return joinedBuffer ; } ; param buffer param volume param audioContext returns { AudioBuffer } export function weakenBuffer ( buffer , volume , audioContext ) { volume = Math . min ( 1 , volume ) ; const newBuffer = audioContext . createBuffer ( buffer . numberOfChannels , buffer . length , buffer . sampleRate ) ; for ( let channel = 0 , c = buffer . numberOfChannels ; channel < c ; channel ++ ) { let oldData = buffer . getChannelData ( channel ) ; let newData = newBuffer . getChannelData ( channel ) ; for ( var j = 0 ; j < oldData . length ; j ++ ) { newData [ j ] = oldData [ j ] * volume ; } } return newBuffer ; }