awslabs / aws-lex-browser-audio-capture

An example web application using the Lex JavaScript SDK to send and receive audio from the Lex PostContent API. Demonstrates how to capture an audio device, record audio, and convert the audio into a format that Lex will recognize, and play the response. All from a web browser.
MIT No Attribution
165 stars 75 forks source link

Update recordSampleRate after downsampleBuffer #14

Open expatiating opened 5 years ago

expatiating commented 5 years ago

In testing this, I used startRecording, stopRecording, and exportWAV similar to below.

audioControl.startRecording(() => {
  audioControl.stopRecording()
  audioControl.exportWAV()
}

When I call exportWAV it appears that sampleRate change done in downsampleBuffer is not reflected in encodeWAV.

The browser records in 44.1 kHz, and downsampling to 16 kHz, and exporting the WAV, the file has 44.1 kHz encoding and the audio played by Audacity was at 44.1 kHz rate. In Audacity I changed the file rate to 16 kHz and the audio plays correctly.

By setting recordSampleRate = exportSampleRate; after downsampling corrected the issue.

vogler75 commented 4 years ago

I had the same issue. But I think to change the recordSampleRate is not the best way to fix it. I added an argument sampleRate to the function "encodeWAV" and use this argument instead of the global "recordSampleRate" variable. And where the encodeWAV function is called I passed the exportSampleRate...

function exportBuffer(exportSampleRate) {
        var mergedBuffers = mergeBuffers(recBuffer, recLength);
        var downsampledBuffer = downsampleBuffer(mergedBuffers, exportSampleRate);
        var encodedWav = encodeWAV(downsampledBuffer, **exportSampleRate**);
        var audioBlob = new Blob([encodedWav], { type: 'application/octet-stream' });
        postMessage({
          blob: audioBlob,
          hasContent: encodedWav.hasContent
        });
      }  

function encodeWAV(samples, **sampleRate**) {
        const samplesLength = samples.length;
        let hasContent = false;
        for (let i = 0; i < samplesLength; ++i) {
          if (Math.abs(samples[i]) > 0.05) {
            hasContent = true
            break;
          }
        }

        var buffer = new ArrayBuffer(44 + samples.length * 2);
        var view = new DataView(buffer);

        writeString(view, 0, 'RIFF');
        view.setUint32(4, 32 + samples.length * 2, true);
        writeString(view, 8, 'WAVE');
        writeString(view, 12, 'fmt ');
        view.setUint32(16, 16, true);
        view.setUint16(20, 1, true);
        view.setUint16(22, 1, true);
        view.setUint32(24, **sampleRate**, true);
        view.setUint32(28, **sampleRate** * 2, true);
        view.setUint16(32, 2, true);
        view.setUint16(34, 16, true);
        writeString(view, 36, 'data');
        view.setUint32(40, samples.length * 2, true);
        floatTo16BitPCM(view, 44, samples);

        view.hasContent = hasContent;

        return view;
      }
expatiating commented 4 years ago

@vogler75 you are welcome to add a commit to my PR with your change, your solution adds a bit of additional flexibility. Since we are approaching 2 years on my original fix hopefully your interest gets helps get this PR a review from @palafranchise and this gets fixed.

vogler75 commented 4 years ago

@expatiating it seems that I do not have permission to publish a branch on this repo.

vogler75 commented 4 years ago

ok, I had to create a fork (was my first time doing a pull request), additionally i create an issue.

expatiating commented 4 years ago

Addresses #22, but see PR #23 for a more complete implementation by @vogler75