37

I'm trying to capture user's audio input from the browser. I have done it with WAV but the files are really big. A friend of mine told me that OGG files are much smaller. Does anyone knows how to convert WAV to OGG? I also have the raw data buffer, I don't really need to convert. But I just need the OGG encoder.

Here's the WAV encoder from Matt Diamond's RecorderJS:

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

  /* RIFF identifier */
  writeString(view, 0, 'RIFF');
  /* file length */
  view.setUint32(4, 32 + samples.length * 2, true);
  /* RIFF type */
  writeString(view, 8, 'WAVE');
  /* format chunk identifier */
  writeString(view, 12, 'fmt ');
  /* format chunk length */
  view.setUint32(16, 16, true);
  /* sample format (raw) */
  view.setUint16(20, 1, true);
  /* channel count */
  view.setUint16(22, 2, true);
  /* sample rate */
  view.setUint32(24, sampleRate, true);
  /* byte rate (sample rate * block align) */
  view.setUint32(28, sampleRate * 4, true);
  /* block align (channel count * bytes per sample) */
  view.setUint16(32, 4, true);
  /* bits per sample */
  view.setUint16(34, 16, true);
  /* data chunk identifier */
  writeString(view, 36, 'data');
  /* data chunk length */
  view.setUint32(40, samples.length * 2, true);

  floatTo16BitPCM(view, 44, samples);

  return view;
}

is there one for OGG?

Donal Lafferty
  • 5,807
  • 7
  • 43
  • 60
himura
  • 1,555
  • 3
  • 19
  • 30

4 Answers4

19

The Web Audio spec is actually intended to allow exactly this kind of functionality, but is just not close to fulfilling that purpose yet:

This specification describes a high-level JavaScript API for processing and synthesizing audio in web applications. The primary paradigm is of an audio routing graph, where a number of AudioNode objects are connected together to define the overall audio rendering. The actual processing will primarily take place in the underlying implementation (typically optimized Assembly / C / C++ code), but direct JavaScript processing and synthesis is also supported.

Here's a statement on the current w3c audio spec draft, which makes the following points:

  • While processing audio in JavaScript, it is extremely challenging to get reliable, glitch-free audio while achieving a reasonably low-latency, especially under heavy processor load.
  • JavaScript is very much slower than heavily optimized C++ code and is not able to take advantage of SSE optimizations and multi-threading which is critical for getting good performance on today's processors. Optimized native code can be on the order of twenty times faster for processing FFTs as compared with JavaScript. It is not efficient enough for heavy-duty processing of audio such as convolution and 3D spatialization of large numbers of audio sources.
  • setInterval() and XHR handling will steal time from the audio processing. In a reasonably complex game, some JavaScript resources will be needed for game physics and graphics. This creates challenges because audio rendering is deadline driven (to avoid glitches and get low enough latency). JavaScript does not run in a real-time processing thread and thus can be pre-empted by many other threads running on the system.
  • Garbage Collection (and autorelease pools on Mac OS X) can cause unpredictable delay on a JavaScript thread.
  • Multiple JavaScript contexts can be running on the main thread, stealing time from the context doing the processing.
  • Other code (other than JavaScript) such as page rendering runs on the main thread.
  • Locks can be taken and memory is allocated on the JavaScript thread. This can cause additional thread preemption.
  • The problems are even more difficult with today's generation of mobile devices which have processors with relatively poor performance and power consumption / battery-life issues.

ECMAScript (js) is really fast for a lot of things, and is getting faster all the time depending on what engine is interpreting the code. For something as intensive as audio processing however, you would be much better off using a low-level tool that's compiled to optimize resources specific to the task. I'm currently using ffmpeg on the server side to accomplish something similar.

I know that it is really inefficient to have to send a wav file across an internet connection just to obtain a more compact .ogg file, but that's the current state of things with the web audio api. To do any client-side processing the user would have to explicitly give access to the local file system and execution privileges for the file to make the conversion.

Edit: You could also use Google's native-client if you don't mind limiting your users to Chrome. It seems like very promising technology that loads in a sandbox and achieves speeds nearly as good natively executed code. I'm assuming that there will be similar implementations in other browsers at some point.

miken32
  • 42,008
  • 16
  • 111
  • 154
jtrick
  • 1,329
  • 18
  • 23
  • Thanks a lot @jtrick. Chrome native-client seems to be my solution. The whole idea of converting to ogg is not to send huge wav files (i guess that sorts out ffmpeg on the server option). And special thanks for your support in my question :) – himura Jul 21 '13 at 07:30
  • @himura: Happy to help! I'm doing something similar, so I'll probably go that route myself as soon as I have time to focus on it. I'd love to hear how it goes for you. – jtrick Jul 21 '13 at 22:37
11

This question has been driving me crazy because I haven't seen anyone come up with a really clean solution, so I came up with my own library:

https://github.com/sb2702/audioRecord.js

Basic usage

audioRecord.requestDevice(function(recorder){
  // Request user permission for microphone access

      recorder.record(); // Start recording

      recorder.stop();  /Stop recording

      recorder.exportOGG(function(oggBlob){
        //Here's your OGG file
      });

      recorder.exportMP3(function(mp3Blob){
               //Here's your mp3 file
      });

      recorder.exportWAV(function(wavBlob){
            //Here's your WAV file
      });

});

Using the continuous mp3 encoding option, it's entirely reasonable to capture and encode audio input entirely in the browser, cross-browser, without a server or native code.

DEMO: http://sb2702.github.io/audioRecord.js/

It's still rough around the edges, but I'll try to clean / fix it up.

Sam
  • 995
  • 9
  • 16
  • I like what you have created ... did you consider adding [Opus support](https://github.com/chris-rudmin/Recorderjs/)? – Rainer Rillke Jul 15 '15 at 20:06
  • Sure! I'll take a look this weekend - I'll see if I can integrate our projects together to put in OGG Opus as well. – Sam Jul 16 '15 at 16:41
  • I do not work on this anymore, but I have up-voted your answer so that people see it. I really hope it came in earlier :) – himura Jul 25 '15 at 21:14
  • Is it possible to request authorization first time user clicks Record? Because some user may not need to use recording function on the page. Just that the red dot in Chrome tab is quite annoying – Toolkit Aug 19 '15 at 04:12
  • Hi @Toolkit - You can call audioRecord.requestDevice when the user hits record (within whatever function gets called when the user hits record), instead of on page load. You're right though - it's a bit clunky - I'll try to think of a more streamlined way of requesting permission if you don't have it, the first time that you use recorder.record() – Sam Aug 19 '15 at 23:44
  • http://stackoverflow.com/users/3404137/sam I love what you have created. Not clunky in my book. What is the license? I would love to use it in a project. – LenB Mar 09 '16 at 14:42
  • Sorry. I see MIT license. Thanks. – LenB Mar 09 '16 at 14:51
  • Awesome implementation of recording and encoding. Easy to understand and works great! Most of the newer recorders cannot output wav, ogg/vorbis or mp3 so it is very cool to have all 3 in one project. – techdog May 28 '19 at 05:50
5

NEW: Derivative work of Matt Diamond's recorderjs recording to Ogg-Opus

To encode to Ogg-Opus a file in whole in a browser without special extensions, one may use an Emscripten port of opus-tools/opusenc (demo). It comes with decoding support for WAV, AIFF and a couple of other formats and a re-sampler built in.

An Ogg-Vorbis encoder is also available.

Since the questioner is primarily out for audio compression, they might be also interested in mp3 encoding using lame.

Rainer Rillke
  • 1,281
  • 12
  • 24
3

Ok, this might not be a direct answer as it does not say how to convert .wav into .ogg. Then again, why bother with the conversion, when you can the .ogg file directly. This depends on MediaRecorder API, but browsers which support WebAudio usually have this too( Firefox 25+ and Chrome 47+)

github.io Demo

Github Code Source

mido
  • 24,198
  • 15
  • 92
  • 117
  • Apparently the only format for audio in Chrome 49 is Opus @ 48kHz. – timmacp Apr 14 '16 at 19:51
  • 1
    opus is a new format afaik. Just looking into it. Bad for music but good for speech according to [this](https://addpipe.com/blog/mediarecorder-api/) – timmacp Apr 15 '16 at 09:39
  • @timmacp nice article, apparantly, .ogg is container for both vorbis and opus formats, check out this [reddit](https://www.reddit.com/r/linux/comments/34ke3q/ogg_vorbs_vs_ogg_opus/) page for their discussion – mido Apr 15 '16 at 09:50
  • tried your MediaRecorder-sample in chrome 49 & I got script.js:17 Uncaught TypeError: navigator.mediaDevices.getUserMedia is not a function. Matt diamonds sample uses navigator.webkitGetUserMedia for chrome I presume? – timmacp Apr 15 '16 at 10:10
  • you are correct, should have added adapter.js to take care of browser inconsistencies, – mido Apr 15 '16 at 11:06
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/109268/discussion-between-timmacp-and-mido). – timmacp Apr 15 '16 at 15:36