@@ -22,33 +22,23 @@ DEALINGS IN THE SOFTWARE.
2222( function ( window ) {
2323
2424 var Recorder = function ( source , audioProcessor , startFun , stopFun ) {
25- var bufferLen = 4096 ;
2625 var websocket ;
2726 var audioContext = source . context ;
27+ var inputSampleRate = ( audioContext ) ? audioContext . sampleRate : source . sampleRate ;
28+ var outputSampleRate = 16000 ;
2829
2930 var recording = false ;
3031
3132 function processAudio ( inputAudioFrame ) {
3233 if ( ! recording ) return ;
3334
34- var length = Math . floor ( inputAudioFrame . length / 3 ) ;
35- var result = new Float32Array ( length ) ;
36-
37- var index = 0 ;
38- var inputIndex = 0 ;
39-
40- while ( index < length ) {
41- result [ index ++ ] = inputAudioFrame [ inputIndex ] ;
42- inputIndex += 3 ;
43- }
35+ //downsample
36+ var result = downsampleFloat32 ( inputAudioFrame , inputSampleRate , outputSampleRate ) ;
4437
4538 var offset = 0 ;
46- var buffer = new ArrayBuffer ( length * 2 ) ;
39+ var buffer = new ArrayBuffer ( result . length * 2 ) ;
4740 var view = new DataView ( buffer ) ;
48- for ( var i = 0 ; i < result . length ; i ++ , offset += 2 ) {
49- var s = Math . max ( - 1 , Math . min ( 1 , result [ i ] ) ) ;
50- view . setInt16 ( offset , s < 0 ? s * 0x8000 : s * 0x7FFF , true ) ;
51- }
41+ floatTo16BitPCM ( view , offset , result ) ;
5242
5343 //console.log('Recorder onaudioprocess - view: ' + view); //DEBUG
5444 if ( websocket ) {
@@ -63,6 +53,7 @@ DEALINGS IN THE SOFTWARE.
6353 }
6454 //Web-Audio
6555 } else if ( audioContext ) {
56+ var bufferLen = 4096 ;
6657 let processNode ;
6758 if ( 'createScriptProcessor' in audioContext ) {
6859 processNode = audioContext . createScriptProcessor ( bufferLen , 1 , 1 ) ;
@@ -112,7 +103,6 @@ DEALINGS IN THE SOFTWARE.
112103 this . sendHeader = function ( ws ) {
113104 var sampleLength = 1000000 ;
114105 var mono = true ;
115- var sampleRate = 16000 ; //TODO: this might not be true! We cannot guarantee that!
116106 var buffer = new ArrayBuffer ( 44 ) ;
117107 var view = new DataView ( buffer ) ;
118108
@@ -131,9 +121,9 @@ DEALINGS IN THE SOFTWARE.
131121 //channel count
132122 view . setUint16 ( 22 , mono ? 1 : 2 , true ) ;
133123 //sample rate
134- view . setUint32 ( 24 , sampleRate , true ) ;
124+ view . setUint32 ( 24 , outputSampleRate , true ) ;
135125 //byte rate (sample rate * block align)
136- view . setUint32 ( 28 , sampleRate * 2 , true ) ;
126+ view . setUint32 ( 28 , outputSampleRate * 2 , true ) ;
137127 //block align (channel count * bytes per sample)
138128 view . setUint16 ( 32 , 2 , true ) ;
139129 //bits per sample
@@ -146,11 +136,78 @@ DEALINGS IN THE SOFTWARE.
146136 //console.log('Recorder sendHeader - view: ' + view); //DEBUG
147137 ws . send ( view ) ;
148138 }
149- function writeString ( view , offset , string ) {
150- for ( var i = 0 ; i < string . length ; i ++ ) {
139+
140+ //--- conversion methods ---
141+
142+ function writeString ( view , offset , string ) {
143+ for ( let i = 0 ; i < string . length ; i ++ ) {
151144 view . setUint8 ( offset + i , string . charCodeAt ( i ) ) ;
152145 }
153- }
146+ }
147+
148+ function floatTo16BitPCM ( output , offset , input ) {
149+ for ( let i = 0 ; i < input . length ; i ++ , offset += 2 ) {
150+ let s = Math . max ( - 1 , Math . min ( 1 , input [ i ] ) ) ;
151+ output . setInt16 ( offset , s < 0 ? s * 0x8000 : s * 0x7FFF , true ) ;
152+ }
153+ }
154+
155+ function downsampleAndConvertToInt16 ( buffer , sampleRate , outSampleRate ) {
156+ if ( outSampleRate == sampleRate ) {
157+ return buffer ;
158+ }
159+ if ( outSampleRate > sampleRate ) {
160+ console . error ( "Recorder - Downsampling to " + outSampleRate + " failed! Input sampling rate was too low: " + sampleRate ) ;
161+ return buffer ;
162+ }
163+ var sampleRateRatio = sampleRate / outSampleRate ;
164+ var newLength = Math . round ( buffer . length / sampleRateRatio ) ;
165+ var result = new Int16Array ( newLength ) ;
166+ var offsetResult = 0 ;
167+ var offsetBuffer = 0 ;
168+ while ( offsetResult < result . length ) {
169+ var nextOffsetBuffer = Math . round ( ( offsetResult + 1 ) * sampleRateRatio ) ;
170+ var accum = 0 , count = 0 ;
171+ for ( var i = offsetBuffer ; i < nextOffsetBuffer && i < buffer . length ; i ++ ) {
172+ accum += buffer [ i ] ;
173+ count ++ ;
174+ }
175+ result [ offsetResult ] = Math . min ( 1 , accum / count ) * 0x7FFF ;
176+ offsetResult ++ ;
177+ offsetBuffer = nextOffsetBuffer ;
178+ }
179+ return result . buffer ;
180+ }
181+ function downsampleFloat32 ( array , sampleRate , outSampleRate ) {
182+ if ( outSampleRate == sampleRate ) {
183+ var result = new Float32Array ( array . length ) ;
184+ for ( let i = 0 ; i < array . length ; i ++ ) {
185+ result . push ( array [ i ] ) ;
186+ }
187+ return array ;
188+ }
189+ if ( outSampleRate > sampleRate ) {
190+ console . error ( "Recorder - Downsampling to " + outSampleRate + " failed! Input sampling rate was too low: " + sampleRate ) ;
191+ return downsampleFloat32 ( array , sampleRate , sampleRate ) ;
192+ }
193+ var sampleRateRatio = sampleRate / outSampleRate ;
194+ var newLength = Math . round ( array . length / sampleRateRatio ) ;
195+ var result = new Float32Array ( newLength ) ;
196+ var offsetResult = 0 ;
197+ var offsetBuffer = 0 ;
198+ while ( offsetResult < result . length ) {
199+ var nextOffsetBuffer = Math . round ( ( offsetResult + 1 ) * sampleRateRatio ) ;
200+ var accum = 0 , count = 0 ;
201+ for ( var i = offsetBuffer ; i < nextOffsetBuffer && i < array . length ; i ++ ) {
202+ accum += array [ i ] ;
203+ count ++ ;
204+ }
205+ result [ offsetResult ] = accum / count ;
206+ offsetResult ++ ;
207+ offsetBuffer = nextOffsetBuffer ;
208+ }
209+ return result ;
210+ }
154211 } ;
155212
156213 window . RecorderJS = Recorder ;
0 commit comments