import Recording from './recording' ; import mp3_encode from './mp3_encode' ; import wav_encode from './wav_encode' ; let recording = null ; let memoryUsageInterval = null ; let lastHeapSize = 0 ; self . onmessage = function ( e ) { if ( e . data === null ) { self . onmessage = messageHandler ; self . postMessage ( null ) ; } } ; function messageHandler ( e ) { const { id , command , payload } = e . data ; const t = new Transaction ( id ) ; try { let result = false ; switch ( command ) { case 'init' : result = init ( payload ) ; break ; case 'addSamples' : recording . addSamples ( payload . samples ) ; result = true ; break ; case 'truncate' : result = recording . truncateAt ( payload . position ) ; break ; case 'export' : { result = { } ; const audioBuffer = recording . getAudioBuffer ( function ( progress ) { t . send ( { step : 'copy' , progress } ) ; } ) ; result . duration = audioBuffer . duration ; if ( payload . raw ) { result . raw = exportRaw ( audioBuffer , payload . raw ) ; } if ( payload . wav ) { result . wav = exportWav ( audioBuffer , payload . wav , function ( progress ) { t . send ( { step : 'wav' , progress } ) ; } ) ; } if ( payload . mp3 ) { result . mp3 = exportMp3 ( audioBuffer , payload . mp3 , function ( progress ) { t . send ( { step : 'mp3' , progress } ) ; } ) ; } break ; } case 'cleanup' : result = cleanup ( ) ; break ; } t . done ( result ) ; } catch ( error ) { t . fail ( error ) ; } } function Transaction ( id ) { this . _id = id ; } Transaction . prototype . done = function ( payload ) { self . postMessage ( { id : this . _id , done : true , payload } ) ; } ; Transaction . prototype . send = function ( payload ) { self . postMessage ( { id : this . _id , done : false , payload } ) ; } ; Transaction . prototype . fail = function ( error ) { self . postMessage ( { id : this . _id , done : true , error } ) ; } ; function init ( { sampleRate , numberOfChannels } ) { cleanup ( ) ; if ( numberOfChannels > 2 ) { throw new Error ( 'invalid number of channels' ) ; } recording = new Recording ( { numberOfChannels , sampleRate } ) ; memoryUsageInterval = setInterval ( reportMemoryUsage , 1000 ) ; return true ; } function reportMemoryUsage ( ) { let heapSize = 0 ; if ( recording ) { heapSize = recording . length * recording . numberOfChannels * 4 ; } if ( heapSize !== lastHeapSize ) { lastHeapSize = heapSize ; self . postMessage ( { id : 'memoryUsage' , done : false , payload : heapSize } ) ; } } function cleanup ( ) { recording = null ; if ( memoryUsageInterval !== null ) { clearInterval ( memoryUsageInterval ) ; } return true ; } function exportRaw ( audioBuffer ) { const { numberOfChannels , sampleRate , length , duration } = audioBuffer ; const result = { numberOfChannels , sampleRate , length , duration , channels : [ ] } ; for ( let channelNumber = 0 ; channelNumber < numberOfChannels ; channelNumber += 1 ) { result . channels . push ( audioBuffer . getChannelData ( channelNumber ) ) ; } return result ; } function exportWav ( audioBuffer , options , progressCallback ) { if ( typeof options !== 'object' ) { options = { numChannels : audioBuffer . numberOfChannels , sampleRate : audioBuffer . sampleRate , sampleSize : 2 , } ; } return wav_encode ( audioBuffer , options , progressCallback ) ; } function exportMp3 ( audioBuffer , options , progressCallback ) { if ( typeof options !== 'object' ) { options = { outputRate : 128 , } ; } return mp3_encode ( audioBuffer , options , progressCallback ) ; }