Output ChannelOutput Channel

NASA Quindar Tones in Web Audio

December 06, 2015

If you've ever listened to recordings of the Apollo moon landing missions, you'll probably have heard a number of high pitched beeps:

They are known as Quindar tones (named after Quindar Electronics, Inc - the manufacturer of the tone generating equipment) and were used by NASA as part of a system designed to turn on and off transmitters on Earth, enabling CapCom (based at mission control, Houston) to communicate with the astronauts.

The system consisted of an intro and outro tone - each one a single sine wave lasting 250ms. The intro tone, which turned the transmitters on, had a frequency of 2525Hz, and the outro tone (which turned the transmitters off) had a frequency of 2475Hz.

So, to talk with the astronauts, you needed to push and hold a button. When the button was first pushed, the intro tone would be sent, then you would speak your message. When you had finished the message, you would release the button and the outro tone would play.

To recreate this in Web Audio, we'll first make a Quindar object that will contain all our methods and functions. Our initial properties will be an AudioContext (essential for creating and hearing our oscillators), the 2 frequencies needed for our tones, and a variable broadcastStatus which tells us whether we are currently "broadcasting" or not.

function Quindar(context) {
  this.context = context;
  this.introFreq = 2525;
  this.outroFreq = 2475;
  this.broadcastStatus = 0;
}

Next up, we need to create our oscillators and connect them to the speakers. Remembering that oscillator nodes can only be used one time, it's useful to write the code in a re-usable method, setup. We're going to add in a gain node too to make it easy for us to adjust the volume of the tones. Because the default waveform of a web audio oscillator is a sine wave, we don't need to change the type: we can just leave it as it is.

Quindar.prototype.setup = function(){

  // create the oscillator
  this.osc = context.createOscillator();

  // create the gain node, and set its gain to an appropriate value
  this.gainNode = this.context.createGain();
  this.gainNode.gain.value = 0.2;

  // connect the oscillator to the gain and the gain to the output
  this.osc.connect(this.gainNode);
  this.gainNode.connect(context.destination);
}

Now we need some way of playing the tones, and for that we'll create a method called playSound.

Quindar.prototype.playSound = function(frequency){
  this.setup();
  this.osc.frequency.value = frequency;
  this.osc.start(0);
  this.osc.stop(this.context.currentTime + 0.25);
}

This method calls the setup() method to create the single-use oscillator and assigns it a frequency, which will be either the intro frequency or the outro frequency. Then it calls the start() method of the oscillator which causes it to start playing as soon as the function is called, and finally, the stop method is scheduled to run 0.25 seconds later.

It's now time to think about some sort of user-interface. We just want a single button that we press and hold. So, on the mousedown event, we want our intro tone to play and have broadcastStatus switch to 1. On mouseup, we want the outro tone to play and broadcastStatus to switch to 0. We'll create 2 functions that help us do that:

Quindar.prototype.beginBroadcast = function(){
  this.playSound(this.introFreq);
  this.broadcastStatus = 1;
}

Quindar.prototype.endBroadcast = function(){
  this.playSound(this.outroFreq);
  this.broadcastStatus = 0;
}

Finally, all that remains is to create an HTML button for the interface, create an instance of the quindar tone object, and then set up the event listeners.

<div class='button' id='js-quindar-button'>Quindar Toggle</div>

<script>
// create the audio context
var context = new AudioContext();

// Create a Quindar instace.
var quindar = new Quindar(context);

// detect mousdown clicks on the button
$("#js-quindar-button").on("mousedown touchstart", function(e){
  e.preventDefault();

  if (quindar.broadcastStatus == 0){
    quindar.beginBroadcast();
  }
});

// we detect the mouseup event on the window tag as opposed to the button
// because otherwise if we release the mouse when not over the button,
// the tone will remain playing
$(window).on("mouseup touchend", function(){
  if (typeof quindar !== "undefined" && quindar.broadcastStatus == 1){
      quindar.endBroadcast();
  }
});
</script>

The CodePen below demonstrates the finished demo.

See the Pen NASA Quindar tones in Web Audio by Ed Ball (@edball) on CodePen.

Header image: Buzz Aldrin on the Moon by NASA