loov / jsfx

Javascript Sound Effect Generator
MIT License
576 stars 49 forks source link

How to get the raw data (WAV format) as a string to create a base64 dataURI? #14

Closed jalbam closed 8 years ago

jalbam commented 8 years ago

Hello,

Thank you very much for this project. It is very interesting.

I would like to use it for an open-source and free project I am developing (a game engine framework in JavaScript) but I do not see any method that can return the raw data of the sound generated in base64 (WAV format).

Other libraries (which use or are based on riffwave.js) as https://github.com/mneubrand/jsfxr or https://github.com/grumdrig/jsfxr can return or can be modified easily to return the dataURI because it is a method that is already contaiend in riffwave.js. But those libraries are not longer being updated and seem quite old.

Please, would it be possible to add a method in your library to return the dataURI as a string for the WAV generated? Indeed I would like it to return just the data (without "data:audio/wav;base64,").

I would like to use that string to generate an Audio element (and possibly falling back to a Flash plugin that can support base64 audio for old browser or browsers that do not support WAV format as IE). I could even convert that WAV into MP3 format with JavaScript on the fly (although that could take a long time depending on the case).

Thank you very much for your patience. Sorry about my English.

egonelbre commented 8 years ago

Do you need the base64 encoded or the floating point values or the uint16 values?

In any case the basic workflow how it generates it is this (https://github.com/loov/jsfx/blob/master/jsfx.js#L26)

var processor = new jsfx.Processor(params, jsfx.DefaultModules);
var block = new Float32Array(processor.getSamplesLeft()); // note: older browser may not have Float32Array
processor.generate(block);
// the block contains the floating point values, which may need to be clamped
var audio = jsfx.CreateAudio(block); // https://github.com/loov/jsfx/blob/master/jsfx.js#L965

I'm not sure how much or what you need, but you can strip out the unnecessary parts, i.e. copy the CreateAudio part and keep only the pieces that you need.

jalbam commented 8 years ago

Thank you for your reply.

What I need is the sound effect generated in WAV format but encoded in base64. It would be nice if the library had a method to return this as a string. It would be much more powerful. But I am not sure what part I should modify.

Instead of playing the sound using the library, I could use the string returned (WAV in base64) to create a new Audio element, or send it to a Flash plugin. I could even convert it into MP3 or anything else.

egonelbre commented 8 years ago

If you just need the base64, just cut off the header from the src.

audio = jsfx.Sound(...);
b64 = audio.src.substr(22);

It doesn't make sense to add base64 to jsfx API, it would increase the surface and break up ideas, without clear upsides. WAV support is very good in browsers (http://caniuse.com/#feat=audio), so I really don't have good justification... I could understand using byte array, but not base64.

jalbam commented 8 years ago

Thanks again for your reply.

That link you sent talks about HTML5 Audio API support (Audio object), but is not about WAV support.

After some tests, I think Internet Explorer 11 does not support WAV format as far as I know (unless I am wrong). To overcome that, someone could use a library to encode WAV into another compatible format (despite the performance decrease), but only if the base64 code can be accessed.

I am not using Sound method but this way to create the sound FX (from the example in the official readme):

<script src="jsfx.js"></script>
<script>
var library = {
    "static": {"Volume":{"Sustain":0.1,"Decay":0.15,"Punch":0.55}},
    "dynamic": function(){
        return {"Frequency": { "Start": Math.random()*440 + 220 }};
    },
    "coin": jsfx.Preset.Coin
};
var sfx = jsfx.Live(library);
</script>
<button onclick="sfx.static()">Static</button>
<button onclick="sfx.dynamic()">Dynamic</button>
<button onclick="sfx.coin()">Coin</button>

If the sfx.static(), sfx.dynamic() and sfx.coin() returned an Audio object, as you said, substr method could be used to get the base64. But they are not returning an Audio Object. Furthermore, that example is using HTML5 Web Audio API instead of HTML Audio API.

As far as I know, the jsfx library is generating base64 audio internally to create the sound effects. If it provided a method to access that base64 already generated by the library, the library could be used for many more applications and more browsers (and even in platforms which are not browsers as Node.js, etc.). It would not matter too much if the method returned base64 in a simple string, an array or a byte array. That way could be used in a very simple way (maybe var coinCode = sfx.getBase64("coin");).

egonelbre commented 8 years ago

For some reason I mis-remembered IE WAV support, Edge might have it.

jsfx.Live creates an AudioContext, if possible, so it may not generate the Audio objects and base64 at all. You would need to use jsfx.SoundsImmediate to definitely create audio objects, then you can access the audio objects from ._audio.

var sounds =jsfx.SoundsImmediate(library);
console.log(sounds._audio);

By adding more functions to the library, it just makes it more complicated. To create the coin, you can just do:

var coinAudio = jsfx.Sound(jsfx.Preset.Coin());
jsfx.DownloadAsFile(coinAudio);
jalbam commented 8 years ago

Thank you very much. I will use your library in my project (a game engine framework) and the users will be able to tweak it in the case they want.