0

So I'm pretty new to the Web Audio API, having only heard about it 4 days ago (though since then I've put in probably about 50 hours of research and experimentation with it). I'm also more of a novice at javascript.

Situation: I'm trying to develop a script that will take Google's TTS return from the API (which is encoded as a base64 string) and transfer it to an arrayBuffer for use in the Web Audio API so that I can send it through some of the nodes.

I've already got the return from the Google TTS API integrated into my website. When I test the script on my test-server on my computer, I can hear the audioContext activate in the form of slight static. However, there is an error popping up with one of my base64ToArray strings that I can't seem to diagnose or fix.

Here's the error:

Uncaught DOMException: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded. at base64ToArrayBuffer(16:31) at (10:23)

And here's the code. For the sake of this post, I've only kept a portion of the base64 strings. Also a side note: I've tried formatting the base64Strings by including the data URI, as well just the base64String - neither method has worked.

Any help would be apprciated!

var isPlaying = false;
var audioContext;
var avaVoice;
var gainNode;
var reverbNode;
var pannerNode;
var updateTime = 200;
var global = global || window;

var avaVoiceDataUri = base64ToArrayBuffer('UklGRuC6DABXQVZFZm10IBAAAAABAAIAAHcBAADKCAAGABgAYmV4dFoCAABNdWx0aW1lZGlhIGludGVyZmFjZSBzb3VuZCBlZmZlY3QuIFVJIEh1ZCBtb2Rlcm4gYW5kIFNjaWVudGlmaWMuAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');

var impulseResponse = base64ToArrayBuffer("data:audio/wav;base64,UklGRhCjBwBXQVZFZm10IBAAAAABAAIARKwAAJgJBAAGABgAZGF0YeyiBwAAAAAAAADRBwDKBgCwAQBA+/8y6v/yuP8JAQA2R/");


function base64ToArrayBuffer(base64) {
    var binaryString = window.atob(base64);
    var len = binaryString.length;
    var bytes = new Uint8Array(len);
    for (var i = 0; i < len; i++)        {
        bytes[i] = binaryString.charCodeAt(i);
    }
    return bytes.buffer;
}



function initSound() {
    audioContext = new AudioContext();
    

    avaVoice.crossOrigin = "anonymous";
    avaVoice.loop = false;
    var source = audioContext.createMediaElementSource(avaVoice);

    gainNode = audioContext.createGain();
    gainNode.gain.value = 0.5;

    reverbNode = audioContext.createConvolver();
    var reverbSoundArrayBuffer = base64ToArrayBuffer(impulseResponse);
    audioContext.decodeAudioData(reverbSoundArrayBuffer,
        function(buffer) {
            reverbNode.buffer = buffer;
        },
        function(e) {
            alert("Error when decoding audio data" + e.err);
    });

    // Connect the audio chain together
    source.connect(gainNode);
    gainNode.connect(reverbNode);
    reverbNode.connect(audioContext.destination);

    avaVoice.play();
  var intervalId = setInterval(updateTime);
}




window.addEventListener("click", function(){
    isPlaying = true
});



initSound();

1 Answers1

1

Your base64 is invalid.

Looks to me like you're missing an A on the end. If you add it, it decodes just fine.

Also note that if you're using atob, you won't include the data URI portion.

If you do have a data URI to begin with, you should use the Fetch API to get a Blob, so that way the MIME type is included. You can then decode audio data directly from it. See also: https://stackoverflow.com/a/62677424/362536

Brad
  • 159,648
  • 54
  • 349
  • 530
  • The base64 strings are just a small portion of the actual string. I didn't want to post the whole thing because it's huge. I may try and use the Fetch API that you mention though and see if that works. Thanks! – Heleus Brands - Dev Dec 15 '20 at 00:12
  • Also, I've never used Fetch to get a blob. How exactly would that look in the context of my code? I've been researching it, but I can't find anyone using it in a similar situation. Thanks again! – Heleus Brands - Dev Dec 15 '20 at 01:33