19

I want a function that works like this:

playSound(345, 1000) 

Which would play a tone of 345 hz for 1000 milliseconds. What is the simplest way to achieve this in JavaScript? I don't mind if it uses a sample (maybe of a sin wave, or piano), or uses the computer's hardware to generate the sound.

4
  • 6
    WebAudioAPI and AudioContext.createOscillator ? Commented Aug 29, 2016 at 7:50
  • 1
    Never thought this can be donei mean creating waveform in a web-browser. Nice one :D Commented Aug 29, 2016 at 12:33
  • Awesome. Thanks @Kaiido. I might need to make another question, but I'd now like to know how to shape a sin wave to emulate a tuning fork, including attack and decay. Anyone reading know how to do this? Commented Aug 29, 2016 at 21:29
  • Check the link I gave you and the link it contains, we can't write a full tutorial for you Commented Aug 29, 2016 at 22:41

2 Answers 2

31

As already pointed out in the comments, the way to do it is through the OscillatorNode.

// create web audio api context var audioCtx = new(window.AudioContext || window.webkitAudioContext)(); function playNote(frequency, duration) { // create Oscillator node var oscillator = audioCtx.createOscillator(); oscillator.type = 'square'; oscillator.frequency.value = frequency; // value in hertz oscillator.connect(audioCtx.destination); oscillator.start(); setTimeout( function() { oscillator.stop(); playMelody(); }, duration); } function playMelody() { if (notes.length > 0) { note = notes.pop(); playNote(note[0], 1000 * 256 / (note[1] * tempo)); } } notes = [ [659, 4], [659, 4], [659, 4], [523, 8], [0, 16], [783, 16], [659, 4], [523, 8], [0, 16], [783, 16], [659, 4], [0, 4], [987, 4], [987, 4], [987, 4], [1046, 8], [0, 16], [783, 16], [622, 4], [523, 8], [0, 16], [783, 16], [659, 4] ]; notes.reverse(); tempo = 100; playMelody();

Sign up to request clarification or add additional context in comments.

5 Comments

If I may, don't use setTimeout here. AudioScheduledSourceNode (like the OscillatorNode)'s start() and stop() method accept a time parameter, which allows to schedule both method relatively with the AudioContext own clock. This is far more precise than any other external timing method. Also note that these nodes also have an onended event handler, so your fiddle could be rewritten to jsfiddle.net/njb91z84/113
Wow, thanks @Kaiido that's a nice update! I've would have done it this way if I knew about the feature at the time
Rather than "notes.pop()" You can use "notes.shift()" That takes the first one from the array, so you don't need to reverse the array
I was on headphones and the volume was on max, this gave me a heart attack
"The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page." And no amount of clicking or interacting will make it work.
10

There is a library called simpleTones.js that greatly simplifies the Web Audio API to do exactly what you are attempting.

Once the library is included in your project, playing a timed frequency is as easy as calling

playTone(345, sine, 1)

345 being the frequency in Hz, sine being the wave pattern(there are other wave pattern options as well) and "1" being one second, or 1000 milliseconds.

You can download the library and read the documentation here: https://github.com/escottalexander/simpleTones.js

Best of luck on your project.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.