Node.js app that plays sounds

Hey!

I’m trying to make a node.js app on Glitch that plays a sound effect when a function is called.
I know how to upload sound files into the assets folder and how to get their link, but I can’t figure out how to actually play them.
Could anyone give me some pointers?

1 Like

Thank you for the reply!
I tried:
var audio = new Audio(‘https://cdn.glitch.com/restofthepath’);
audio.play();

It gives me this error:
ReferenceError: Audio is not defined

How should I solve this?

Where did you place those lines? If I might suggest that you do a quick search “play a sound in a browser”. You will be shown thousands of working examples. You can click on them and hear them play.

You do realize that sounds aren’t “played by Node” on the server right? They are played in the browser.

https://www.w3schools.com/html/html5_audio.asp

1 Like

I have to say I honestly didn’t understand the difference of doing something on the server and in the browser, but thanks to your reply, I now realize what Node actually is. I’m completely new to web coding, so my questions are pretty naive.

I put an index.html file into my Glitch project and inside it I added a javascript code to play sounds when a picture is clicked. Then I made my node.js app render the page with express.js framework, and it works!

What I would like to do now is to send a command from my node.js script to the html page to run the javascript that plays the sound. Is that possible?

JavaScript started with running on the “client” meaning it is hosted in the webpage by each individual viewing it. Node demonstrated that it was possible to write server-based solutions (the back end) in JS as well.

Your browser typically is “pull based” so a user pushes a button or selects and option and that request is sent to the server, data is pulled. The server determines what the request was about and sends a response. There is generally no need to involve Node once the page has been loaded. A button click can initiate the playing, hovering over a link can do it, a timer could do it. If you want a Node to be in charge it involves “push based” interactions. As long as the user initiates the action it is easy.

1 Like

Thank you for your response!

The app I’m making is a bot that reacts to specific messages during my livestream. The node script is listening to the chat feed and parsing commands from it. So far the only thing it can do is post text in the chat (according to the commands), but I’m trying to expand it to support playing sound effects too.

My plan right now is to use my browser as a sound player (it’s enough that the sound is just played on my computer). So Node would be in charge, and tell the html page to play the sound when needed. If I understood your reply correctly, that would be an example of a push based interaction. However, I’m struggling to make this happen in practice. There doesn’t seem to be an obvious way to make the Node script tell the html page to run the JavaScript function that plays the sounds.

We’ll need some clarification. A “bot” as in a Discord Bot or some generic thing you’re calling a bot? You would do things differently if it was a Discord Bot.

1 Like

I use it on Twitch.com. Right now it takes messages from my Twitch chat, parses them, and if it’s a known input, it makes a bot account post a specified response.
For example, if someone in the chat posts “!d20”, the Node script randomizes a number between 1 and 20, and then makes the bot account post the result in the chat. I made it according to this tutorial Glitch

What I’m aiming to do is playing some sound effects according to inputs in the chat. For example, there could be a random sound if someone posts “!sfx”.
The only place where the sound needs to play is my browser, since I’m streaming my system sound. Right now I can make an html page here on Glitch that plays sounds when I click buttons and such, but I don’t know how to make my Node script that listens to the Twitch chat give the command to do that.

1 Like

Okay got it. I looked at that sample app and need to ask, you did update the libraries correct? The node version specified is particularly old.

I thought about the least invasive way to do this and there are libraries designed for service workers but you’re going to be dealing with public and private keys, encryption and such. Generally not fun for most people.

It seems to me that you could set up a “chat app” so your browser and the bot have a method of chatting. Turn off anyone else’s ability to join that chat. The bot sends your browser messages, you receive them and instead of displaying some text you play the sound.

This has the code:

I think this may be the same but in tutorial form:
https://www.tutorialspoint.com/socket.io/socket.io_chat_application.htm

and this is about the https://socket.io/ library generally

1 Like

In case it hasn’t become obvious: the problem you’re solving is not a simple one – unlucky! :sweat_smile:

tleylan’s suggestion is a pretty good one, his proposed architecture is something like this (I think):

  • Your twitch bot monitors twitch chat
  • When it sees a msg like !sfx:
    • It sends a signal via websocket to a web page (could be same Glitch project or another one)
    • The web page plays the noise locally on your machine

I would like to briefly propose another idea

There should be a way to have some javascript on your machine monitor the twitch chat without the bot. This could be a simple browser extension that you customise yourself, or maybe (not sure if this would work) a Glitch webpage that pulls in the content of the twitch chat.

In this case, it can constantly monitor the chat, and if the most recent message (by filtering the lines of HTML that exist in the chat window) is !sfx, you get your page (or browser extension) to play the noise.


You know what… I just looked up twitch developer resources, and they seem to have some pretty flexible extension points, somebody made a thing a lot like what you want to make: Sound Alerts: A Twitch Bits-in-Extensions success story | Twitch Blog

Maybe you can look into how that’s done at the extension docs: Extensions | Twitch Developers

Hope this doesn’t overwhelm you with options :slight_smile: Have fun!!

2 Likes

Your reply made me think, perhaps his browser JS could simply subscribe to the feed via the API and simply cut out the server. From what I can see it is only monitoring messages and posting responses in some cases. If a browser-based implementation can register with the feed it seemingly could be informed of incoming messages, process them and post accordingly. All the code would be client-side in such a scenario.

Does this provide any useful info? EventSub | Twitch Developers

1 Like

Thank you so much for all the great ideas tleylan and SteGriff!
I will try the different options and see what I can get working with my meager (but constantly improving) web coding skills, but I’ll try my best and post here when I get something working.
Thanks again for the help!

4 Likes

I managed to get it working exactly as I wanted to!
The solution that I managed to implement was putting the code that watches the chat and plays sounds on the html page, and not in the Node script. I just left the part of the bot that responds to chat messages there, since I think that has to happen on the server side.

This is how I did it:

I downloaded the Twitch chat library tmi.min.js and added it to my Glitch project folder.
<script src="/tmi.min.js"></script>

<script>
  const channel_name = 'channelname';

  const client = new tmi.Client({
      connection: {
	      secure: true,
      reconnect: true
      },
      channels: [channel_name]
  });

  client.connect();

  client.on('message', (channel, tags, message, self) => {
    handleMessage(message);
    console.log(`${tags['display-name']}: ${message}`);
  });
  
  function handleMessage(msg) {
    msg.trim();
    var mesg = msg.toString().toLowerCase();
    if (mesg == "!sound1") {
      playFile("https://cdn.glitch.com/restofthepath");
    }
    if (mesg == "!sound2") {
      playFile("https://cdn.glitch.com/restofthepath");
    }
  }

  //This implementation allows "spamming" sounds instead of playing them one at a time
  function playFile(file) {
    var audio = document.createElement('audio');
    audio.src = file;
    document.body.appendChild(audio);
    audio.play();

    audio.onended = function () {
      this.parentNode.removeChild(this);
    }
  }
  
  function onConnectedHandler (addr, port) {
    console.log(`* Connected to ${addr}:${port}`);
}
</script>

I can’t thank you enough for the help! I learned a lot about web coding while doing this, and I think the bot will be a lot of fun during my streams!

2 Likes

That’s good news. If you feel like spending a little time “tweaking” it a bit. It is a habit of mine not to connect until the handlers are in place. Granted it is milliseconds but you eliminate that by setting up your client.on() right before you call client.connect().

msg.trim();
var mesg = msg.toString().toLowerCase();

can be reduced to a single line and you don’t need toString() as it must be a string. And don’t use var anymore it is old, generally to-be-avoided syntax.

const mesg = msg.trim().toLowerCase();

As a habit consider always using triple equal signs for equality checks. The == will say that 10 == “10” which we tend think isn’t true.

I am a little surprised that playFile creates and destroys an audio element each time. I would think you could have an audio element variable defined globally that could be used and it wouldn’t need to be created/destroyed every time.

Have fun!