I'm using ReactJS to develop a web page (.html + .js) that will be bundled in a USB drive and shipped to customers. This USB drive contains some audio (.wav) files that are played through an HTML5 audio
element in the web page. Customers will open the HTML file through their browser and listen to the songs available inside the USB drive.
I used the recent Web Audio API (specifically the analyser
node) to analyze the frequency data of the current playing audio and then draw a sort of visual audio spectrum on an HTML5 canvas
element.
Sadly, I was using a NodeJS local webserver during the development. Now, I prepared everything for production, just to discover that due to CORS-related restrictions my JS code can't access the audio file through the Web Audio API. (This is because the URL protocol would be "file://", and there is no CORS policy defined for this protocol – This is the behaviour on Chrome and Firefox, using Safari it just works.)
The visual audio spectrum is an essential part of the design of this web page, and I'd hate to throw it away just because of the CORS policy. My idea is to embed inside the JS code a JSON representation of the frequency data for the audio file, and then to use the JSON object in sync with the playing audio file to draw a fake (not in real-time) spectrum.
I tried – modifying the original code I was using to draw the spectrum – to use the JS requestAnimationFrame
loop to get the frequency data for each frame and save it to a JSON file, but the JSON data seems to be incomplete and some frames (a lot) are missing.
this.audioContext = new AudioContext();
// this.props.audio is a reference to the HTML5 audio element
let src = this.audioContext.createMediaElementSource(this.props.audio);
this.analyser = this.audioContext.createAnalyser();
src.connect(this.analyser);
this.analyser.connect(this.audioContext.destination);
this.analyser.smoothingTimeConstant = 0.95;
this.analyser.fftSize = 64;
this.bufferLength = this.analyser.frequencyBinCount;
this.frequencyData = new Uint8Array(this.bufferLength);
[...]
const drawSpectrum = () => {
if (this.analyser) {
this.analyser.getByteFrequencyData(this.frequencyData);
/*
* storing this.frequencyData in a JSON file here,
* this works but I get sometimes 26 frames per seconds,
* sometimes 2 frames per seconds, never 60.
*/
}
requestAnimationFrame(drawSpectrum);
};
drawSpectrum();
Do you have a better idea to fake the visual audio spectrum? How would you go to "circumvent" the CORS-related restrictions in this case? What could be a solid method to export audio frequency data to JSON (and then access it)?
CordovaElectron (which would have other advantages, such as having a known browser version)? – Thomas Jun 16 '20 at 12:33