Using the Web Audio API and createMediaElement method you can use a typed array to get frequency data from audio playback in an <audio>
element and it works in most browsers as long as the source URL is local (not streaming). See Codepen: http://codepen.io/soulwire/pen/Dscga
Actual Code:
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var audioElement = new Audio('http://crossorigin.me/http://87.230.103.9:80/top100station.mp3'); // example stream
audioElement.crossOrigin = 'anonymous';
audioElement.type = 'audio/mpeg';
var analyser = audioCtx.createAnalyser();
audioElement.addEventListener('canplay', function() {
var audioSrc = audioCtx.createMediaElementSource(audioElement);
// Bind our analyser to the media element source.
audioSrc.connect(analyser);
audioSrc.connect(audioCtx.destination);
});
var frequencyData = new Uint8Array(20);
var svgHeight = ($window.innerHeight / 2) - 20;
var svgWidth = $window.innerWidth - 20;
var barPadding = '2';
function createSvg(parent, height, width) {
return d3.select(parent).append('svg').attr('height', height).attr('width', width);
}
var svg = createSvg('.visualizer', svgHeight, svgWidth);
// Create our initial D3 chart.
svg.selectAll('rect')
.data(frequencyData)
.enter()
.append('rect')
.attr('x', function (d, i) {
return i * (svgWidth / frequencyData.length);
})
.attr('width', svgWidth / frequencyData.length - barPadding);
// Continuously loop and update chart with frequency data.
function renderChart() {
requestAnimationFrame(renderChart);
// Copy frequency data to frequencyData array.
analyser.getByteFrequencyData(frequencyData);
console.log(frequencyData);
// Update d3 chart with new data.
svg.selectAll('rect')
.data(frequencyData)
.attr('y', function(d) {
return svgHeight - d;
})
.attr('height', function(d) {
return d;
})
.style('opacity', function(d) {
return d / 255;
})
.attr('fill', function() {
return 'rgb(255, 255, 255)';
});
}
// Run the loop
renderChart();
Where .visualizer
is an empty <div>
I'm developing a hybrid app for a radio station using Ionic/Angular and the audio stream is through Icecast (http://dir.xiph.org/) and I've run into the following issue: local mp3s are analyzed and visualized no problem however if you use the streaming URL, analyser.getByteFrequencyData is all zeroes in iOS Safari but it plays fine.
So to recap:
I know there was a bug in earlier versions of Safari where createMediaElementSource() would fail but if that were still the case then it wouldn't work on the local file?
Any ideas?