javascriptnode.jsvue.jsarraybuffergoogle-text-to-speech

Google Text-toSpeech - Getting the Audio File in Front-end


I have a requirement where I need to convert some text to audio using Google Text to Speech.

I am using Nodejs to get convert the text to audio file, and want to send the audio output to the front-end.

NodeJS code:

const client = new textToSpeech.TextToSpeechClient();
const request = {
  input: {text: 'Hello World'},
  // Select the language and SSML voice gender (optional)
  voice: {languageCode: 'en-US', ssmlGender: 'NEUTRAL'},
  // select the type of audio encoding
  audioConfig: {audioEncoding: 'MP3'},
};

const [response] = await client.synthesizeSpeech(request);

response.audioContent contains the audio data which is a buffer object and looks like this:

<Buffer ff f3 44 c4 00 00 00 03 48 00 00 00 00 ff 88 89 40 04 06 3d d1 38 20 e1 3b f5 83 f0 7c 1f 0f c1 30 7f 83 ef 28 08 62 00 c6 20 0c 62 03 9f e2 77 d6 0f ... > 

I send this as an api response to the front-end. However, what I get in the front-end is a plain object with an array which looks like below:

{ "type": "Buffer", "data": [ 255, 243, 68, 196, 0, 0, 0, 3, 72, 0, 0, 0, 0, 255, 136, 137, 64, 4, 6, 61, 209, 56, 32, 225, 59, 245, 131, 240.......]}

My problems:

1) Since the data received by the front-end from the api is not a buffer anymore, how do I convert this data back to Buffer.

2) Once I have a proper buffer in the frontend, how do I use it to play the audio.

In my case, the text to be converted will always be 3-4 word phrases. So, I don't need any streaming ability.

My front-end is VueJS.


Solution

  • You can download the audio and play using an html audio player.

    We need two files, index.js (Node.js) code and index.html (Vue.js / Client).

    This will synthesize the text you input and play it.

    Run the node script and go to http://localhost:8000/ to see the demo.

    You could omit the "controls" attribute in to hide the audio player, it should still play the sound though!

    index.js

    const express = require("express");
    const port = 8000;
    const app = express();
    const stream = require("stream");
    const textToSpeech = require('@google-cloud/text-to-speech');
    
    app.use(express.static("./"));
    
    app.get('/download-audio', async (req, res) => { 
    
        let textToSynthesize = req.query.textToSynthesize;
        console.log("textToSynthesize:", textToSynthesize);
    
        const client = new textToSpeech.TextToSpeechClient();
        const request = {
            input: {text: textToSynthesize || 'Hello World'},
            // Select the language and SSML voice gender (optional)
            voice: {languageCode: 'en-US', ssmlGender: 'NEUTRAL'},
            // select the type of audio encoding
            audioConfig: {audioEncoding: 'MP3'},
        };
    
        const [response] = await client.synthesizeSpeech(request);
        console.log(`Audio synthesized, content-length: ${response.audioContent.length} bytes`)
        const readStream = new stream.PassThrough();
    
        readStream.end(response.audioContent);
        res.set("Content-disposition", 'attachment; filename=' + 'audio.mp3');
        res.set("Content-Type", "audio/mpeg");
    
        readStream.pipe(res);
    });
    
    app.listen(port);
    console.log(`Serving at http://localhost:${port}`);
    

    index.html

    <!DOCTYPE html>
    <html>
    <body>
    <script src="https://unpkg.com/vue@2.2.6/dist/vue.js"></script>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
    
    <div class="container m-3" id="app">
    <h2>Speech synthesis demo</h2>
    <h4>Press synthesize and play to hear</h4>
    <audio :src="audio" ref="audio" controls autoplay>
    </audio>
    <div class="form-group">
        <label for="text">Text to synthesize:</label>
        <input type="text" class="form-control" v-model="synthesisText" placeholder="Enter text" id="text">
    </div>
    <div>
        <button @click="downloadAudio">Synthesize and play</button>
    </div>
    </div>
    
    <script>
    
        new Vue({
            el: "#app",
            data: {
                audio: null,
                synthesisText: "Gatsby believed in the green light, the orgiastic future that year by year recedes before us."
            },
            methods: {
                downloadAudio() {
                    this.audio = "/download-audio?textToSynthesize=" + encodeURIComponent(this.synthesisText);
                    this.$refs.audio.load();
                    this.$refs.audio.play();
                }
            }
        });
    
    </script>
    </body>
    </html>