Convert blob to WAV file without loosing data or compressing
Asked Answered
D

1

8

I am working on recording speeches and converting them to downloadable WAV files. I am using Angular6 and MediaRecorder. Firstly I obtain the blob and from the blob, I get the .wav file. The problem is that the WAV file (which can be played and sounds good) loss much of its properties during the process and is not a valid WAV. It keeps being a WebM file. For further processing, I need really valid and high-quality WAV files. In the end, I get files of ~20KB, instead of bigger files of ~300KB.

My code looks like this:

//convert Blob to File. Pass the blob and the file title as arguments
var blobToFile = (theBlob: Blob, fileName:string): File => {
  var b: any = theBlob;
  //Add properties to the blob
  b.lastModifiedDate = new Date();
  b.name = fileName;
  return <File>theBlob;
}

var browser = <any>navigator;  
var headers = new Headers();  
var audioCtx = new AudioContext();
var chunks =[];
var constraints = { audio: true, video: false }; 

var promisifiedOldGUM = function(constraints, successCallback, errorCallback) {
  var getUserMedia = (browser.getUserMedia || browser.webkitGetUserMedia || browser.mozGetUserMedia || browser.msGetUserMedia);

  // Some browsers just don't implement it - return a rejected promise with an error to keep a consistent interface
  if(!getUserMedia) {
    return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
  }

  // Otherwise, wrap the call to the old navigator.getUserMedia with a Promise
  return new Promise(function(successCallback, errorCallback) {
    getUserMedia.call(browser, constraints, successCallback, errorCallback);
  });

}
if (browser.mediaDevices.getUserMedia) {
  browser.mediaDevices.getUserMedia(constraints).then((stream) => { 
  this.mediaRecorder = new MediaRecorder(stream);        

this.mediaRecorder.onstop  = function(){
        var last_bit= chunks[chunks.length-1];
        var blob = new Blob([last_bit], { 'type' : 'audio/wav' });
        var audioURL = window.URL.createObjectURL(blob);
        //convert Blob to file 
        var file = blobToFile(blob, "my-recording.wav"); 

        var link = document.createElement("a");
        link.href = audioURL;
        link.download = 'audio_recording_' + new Date().getTime() + '.wav';
        link.innerHTML = "download file";
        document.body.appendChild(link);  
};     

And the MediaRecorder setup in typings.d.ts file looks like this:

declare class MediaRecorder extends EventTarget {

// readonly mimeType: string;
readonly MimeType: 'audio/x-wav';  // 'audio/vnd.wav';
readonly state: 'inactive' | 'recording' | 'paused';
readonly stream: MediaStream;
ignoreMutedMedia: boolean;
videoBitsPerSecond: number;
audioBitsPerSecond: 16000//number;

ondataavailable: (event : MediaRecorderDataAvailableEvent) => void;
onerror: (event: MediaRecorderErrorEvent) => void;
onpause: () => void;
onresume: () => void;
onstart: () => void;
onstop: () => void;

constructor(stream: MediaStream);

start();

stop();

resume();

pause();

isTypeSupported(type: string): boolean;

requestData();


addEventListener<K extends keyof MediaRecorderEventMap>(type: K, listener: (this: MediaStream, ev: MediaRecorderEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;

addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;

removeEventListener<K extends keyof MediaRecorderEventMap>(type: K, listener: (this: MediaStream, ev: MediaRecorderEventMap[K]) => any, options?: boolean | EventListenerOptions): void;

removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;

} 

I don't know how can change the blobToFile() function in order to preserve the recording quality during conversion. If you can help me with this, I would appreciate very much.

Dialogize answered 25/8, 2018 at 21:22 Comment(3)
Have you setted a proper bit/sample frequency rate?Fernyak
Not sure for the quality, but it is probably not a wav file you have here. No implementation of MediaRecorder I know of does record as wav, and if they did that wouldn't be here that you'd set it, but before you start the recorder. So what you have is an opus oga/webm-audio file.Harrell
I edited my post to show where I declared MediaRecorder. Indeed, the file I obtain is webm.Dialogize
F
8

As I can see in the metadatas of the file you've linked in the comment. You use a codec (here Opus) that compresses the file.

I see two solutions:

  • Reduce the compressing ratio of the codec if you can.
  • Use WAV container with an uncompressed configuration (for example PCM)

as you described me the problem in the chat I think it's more of the second solution. I don't use mediarecorder myself but I've found this method to check if a mime type works with it.

MediaRecorder.isTypeSupported("audio/wav;codecs=MS_PCM")

then you I suggest you change the mime type when creating the Blob to

new Blob(chunks, { 'type' : 'audio/wav; codecs=MS_PCM' });

or

new Blob(chunks, { 'type' : 'audio/wav; codecs=0' });
Fernyak answered 25/8, 2018 at 21:56 Comment(7)
Thank you! I didn't set it anywhere. But as I can see from the detailed information provided here get-metadata.com/result/10525caf-9757-4b4d-910e-abf60b62655b, the Audio Sample Rate is 48000Hz and Audio Bits Per Sample is 32Dialogize
Actually, the detailed analysis provided here get-metadata.com/result/10525caf-9757-4b4d-910e-abf60b62655b is identifying that the Audio Bits Per Sample is 32 and, still for Streams, the Bits Per Sample is 0. I think the problem is here.Dialogize
Yes, I did. They sound well. Listen to it here: drive.google.com/file/d/1zMGkgkA5EW7iCYSL7Kv7mePnEpMokJ0N/…Dialogize
I don't have an initial audio file. I just record my voice. Based on the recording I get a blob and based on the blob, I generate the audio file.Dialogize
Let us continue this discussion in chat.Fernyak
not yet. I am considering switching from MediaRecorder to Recorder.jsDialogize
I am opening it nowDialogize

© 2022 - 2024 — McMap. All rights reserved.