Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I detect the number of audio channels in an mp3 in an <audio> tag?

From what I've read I would expect the following JavaScript code to log "All is well", but instead it hits the error case:

var audio = document.createElement('audio');
var ctx = new window.AudioContext();
var source = ctx.createMediaElementSource(audio);
audio.src = 'http://www.mediacollege.com/audio/tone/files/440Hz_44100Hz_16bit_30sec.mp3';
// As @padenot mentioned, this is the number of channels in the source node, not the actual media file
var chans = source.channelCount;
if(chans == 1) {
  snippet.log("All is well");
} else {
  snippet.log("Expected to see 1 channel, instead saw: " + chans)
}
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

What's going on?

Is this, perhaps a CORS issue? Is there some other way to determine that this mp3 file is, in fact, mono?

Edit: As @padenot mentioned, this is the number of channels in the source node, not the actual media file

Clarification

I would love a solution that avoids having to decoding the entire audio file in memeory. decodeAudioData(), in my experience, requires decoding the entire mp3 at one, which can take seconds. createMediaElementSource() allows you to stream the media and decode as you listen.

like image 784
Jordan Eldredge Avatar asked Sep 29 '15 03:09

Jordan Eldredge


1 Answers

A MediaElementAudioSourceNode does have a channelCount attribute, but it refers to the number of channel of the AudioNode, not of the underlying HTMLMEdiaElement.

Instead, you can decode the buffer, and query its channel count, like so:

var xhr = new XMLHttpRequest();
xhr.open('GET', "file.mp3", true);
xhr.responseType = "arraybuffer";
xhr.onload = function() {
  var cx = new AudioContext() ;
  cx.decodeAudioData(xhr.response, function(decodedBuffer) {
    console.log(decodedBuffer.numberOfChannels);
  });
}
xhr.send(null);

And yes, you need CORS headers in the response for this to work.

like image 153
padenot Avatar answered Nov 04 '22 03:11

padenot