Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using local file for Web Audio API in Javascript

I'm trying to get sound working on my iPhone game using the Web Audio API. The problem is that this app is entirely client side. I want to store my mp3s in a local folder (and without being user input driven) so I can't use XMLHttpRequest to read the data. I was looking into using FileSystem but Safari doesn't support it.

Is there any alternative?

Edit: Thanks for the below responses. Unfortunately the Audio API is horribly slow for games. I had this working and the latency just makes the user experience unacceptable. To clarify, what I need is sounething like -

var request = new XMLHttpRequest(); request.open('GET', 'file:///./../sounds/beep-1.mp3', true); request.responseType = 'arraybuffer'; request.onload = function() {     context.decodeAudioData(request.response, function(buffer) {     dogBarkingBuffer = buffer; }, onError); } request.send(); 

But this gives me the errors -

XMLHttpRequest cannot load file:///sounds/beep-1.mp3. Cross origin requests are only supported for HTTP. Uncaught Error: NETWORK_ERR: XMLHttpRequest Exception 101

I understand the security risks with reading local files but surely within your own domain should be ok?

like image 989
user1904515 Avatar asked Dec 28 '12 19:12

user1904515


People also ask

Can JavaScript play WAV files?

Method 2: JavaScriptYou may also load a sound file with JavaScript, with new Audio() . const audio = new Audio("freejazz. wav"); You may then play back the sound with the .

How do you connect audio in JavaScript?

Use . We can load an audio file in JavaScript simply by creating an audio object instance, i.e. using new Audio() . After an audio file is loaded, we can play it using the . play() function. In the above code, we load an audio file and then simply play it.

Can JavaScript generate sound?

js creates an AudioContext when it loads and shims it for maximum browser compatibility using standardized-audio-context. The AudioContext can be accessed at Tone. context . Or set your own AudioContext using Tone.


2 Answers

I had the same problem and I found this very simple solution.

audio_file.onchange = function(){    var files = this.files;    var file = URL.createObjectURL(files[0]);                 audio_player.src = file;     audio_player.play();  };
<input id="audio_file" type="file" accept="audio/*" />  <audio id="audio_player" />

You can test here: http://jsfiddle.net/Tv8Cm/

like image 190
João Mosmann Avatar answered Sep 30 '22 08:09

João Mosmann


Ok, it's taken me two days of prototyping different solutions and I've finally figured out how I can do this without storing my resources on a server. There's a few blogs that detail this but I couldn't find the full solution in one place so I'm adding it here. This may be considered a bit hacky by seasoned programmers but it's the only way I can see this working, so if anyone has a more elegent solution I'd love to hear it.

The solution was to store my sound files as a Base64 encoded string. The sound files are relatively small (less than 30kb) so I'm hoping performance won't be too much of an issue. Note that I put 'xxx' in front of some of the hyperlinks as my n00b status means I can't post more than two links.

Step 1: create Base 64 sound font

First I need to convert my mp3 to a Base64 encoded string and store it as JSON. I found a website that does this conversion for me here - xxxhttp://www.mobilefish.com/services/base64/base64.php You may need to remove return characters using a text editor but for anyone that needs an example I found some piano tones here - xxxhttps://raw.github.com/mudcube/MIDI.js/master/soundfont/acoustic_grand_piano-mp3.js Note that in order to work with my example you're need to remove the header part data:audio/mpeg;base64,

Step 2: decode sound font to ArrayBuffer

You could implement this yourself but I found an API that does this perfectly (why re-invent the wheel, right?) - https://github.com/danguer/blog-examples/blob/master/js/base64-binary.js Resource taken from - here

Step 3: Adding the rest of the code

Fairly straightforward

var cNote  = acoustic_grand_piano.C2; var byteArray = Base64Binary.decodeArrayBuffer(cNote);  var context = new webkitAudioContext();  context.decodeAudioData(byteArray, function(buffer) {     var source = context.createBufferSource(); // creates a sound source     source.buffer = buffer;         source.connect(context.destination); // connect the source to the context's destination (the speakers)     source.noteOn(0);  }, function(err) { console.log("err(decodeAudioData): "+err); }); 

And that's it! I have this working through my desktop version of Chrome and also running on mobile Safari (iOS 6 only of course as Web Audio is not supported in older versions). It takes a couple of seconds to load on mobile Safari (Vs less than 1 second on desktop Chrome) but this might be due to the fact that it spends time downloading the sound fonts. It might also be the fact that iOS prevents any sound playing until a user interaction event has occured. I need to do more work looking at how it performs.

Hope this saves someone else the grief I went through.

like image 42
user1904515 Avatar answered Sep 30 '22 10:09

user1904515