Skip to Main Content

Example: Code to generate audio tone

User_64CKJDec 5 2007 — edited Mar 17 2009
This code shows how to generate and play a simple sinusoidal audio tone using the javax.sound.sampled API (see the generateTone() method for the details).

This can be particularly useful for checking a PCs sound system, as well as testing/debugging other sound related applications (such as an audio trace app.).

The latest version should be available at..
<http://www.physci.org/test/sound/Tone.java>

You can launch it directly from..
<http://www.physci.org/test/oscilloscope/tone.jar>

Hoping it may be of use.
package org.physci.sound;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.LineUnavailableException;

import java.awt.BorderLayout;
import java.awt.Toolkit;
import java.awt.Image;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JSlider;
import javax.swing.JCheckBox;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import javax.swing.border.TitledBorder;

import java.net.URL;

/**
Audio tone generator, using the Java sampled sound API.
@author andrew Thompson
@version 2007/12/6
*/
public class Tone extends JFrame {

  static AudioFormat af;
  static SourceDataLine sdl;

  public Tone() {
    super("Audio Tone");
    // Use current OS look and feel.
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            SwingUtilities.updateComponentTreeUI(this);
        } catch (Exception e) {
            System.err.println("Internal Look And Feel Setting Error.");
            System.err.println(e);
        }

    JPanel pMain=new JPanel(new BorderLayout());

    final JSlider sTone=new JSlider(JSlider.VERTICAL,200,2000,441);
    sTone.setPaintLabels(true);
    sTone.setPaintTicks(true);
    sTone.setMajorTickSpacing(200);
    sTone.setMinorTickSpacing(100);
    sTone.setToolTipText(
      "Tone (in Hertz or cycles per second - middle C is 441 Hz)");
    sTone.setBorder(new TitledBorder("Frequency"));
    pMain.add(sTone,BorderLayout.CENTER);

    final JSlider sDuration=new JSlider(JSlider.VERTICAL,0,2000,1000);
    sDuration.setPaintLabels(true);
    sDuration.setPaintTicks(true);
    sDuration.setMajorTickSpacing(200);
    sDuration.setMinorTickSpacing(100);
    sDuration.setToolTipText("Duration in milliseconds");
    sDuration.setBorder(new TitledBorder("Length"));
    pMain.add(sDuration,BorderLayout.EAST);

    final JSlider sVolume=new JSlider(JSlider.VERTICAL,0,100,20);
    sVolume.setPaintLabels(true);
    sVolume.setPaintTicks(true);
    sVolume.setSnapToTicks(false);
    sVolume.setMajorTickSpacing(20);
    sVolume.setMinorTickSpacing(10);
    sVolume.setToolTipText("Volume 0 - none, 100 - full");
    sVolume.setBorder(new TitledBorder("Volume"));
    pMain.add(sVolume,BorderLayout.WEST);

    final JCheckBox cbHarmonic  = new JCheckBox( "Add Harmonic", true );
    cbHarmonic.setToolTipText("..else pure sine tone");

    JButton bGenerate = new JButton("Generate Tone");
    bGenerate.addActionListener( new ActionListener() {
        public void actionPerformed(ActionEvent ae) {
          try{
            generateTone(sTone.getValue(),
              sDuration.getValue(),
              (int)(sVolume.getValue()*1.28),
              cbHarmonic.isSelected());
          }catch(LineUnavailableException lue){
            System.out.println(lue);
          }
        }
      } );

    JPanel pNorth = new JPanel(new BorderLayout());
    pNorth.add(bGenerate,BorderLayout.WEST);

    pNorth.add( cbHarmonic, BorderLayout.EAST );

    pMain.add(pNorth, BorderLayout.NORTH);
    pMain.setBorder( new javax.swing.border.EmptyBorder(5,3,5,3) );

    getContentPane().add(pMain);
    pack();
    setLocation(0,20);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLocationRelativeTo(null);

    String address = "/image/tone32x32.png";
    URL url = getClass().getResource(address);

    if (url!=null) {
      Image icon = Toolkit.getDefaultToolkit().getImage(url);
      setIconImage(icon);
    }
  }

  /** Generates a tone.
  @param hz Base frequency (neglecting harmonic) of the tone in cycles per second
  @param msecs The number of milliseconds to play the tone.
  @param volume Volume, form 0 (mute) to 100 (max).
  @param addHarmonic Whether to add an harmonic, one octave up. */
  public static void generateTone(int hz,int msecs, int volume, boolean addHarmonic)
    throws LineUnavailableException {

    float frequency = 44100;
    byte[] buf;
    AudioFormat af;
    if (addHarmonic) {
      buf = new byte[2];
      af = new AudioFormat(frequency,8,2,true,false);
    } else {
      buf = new byte[1];
      af = new AudioFormat(frequency,8,1,true,false);
    }
    SourceDataLine sdl = AudioSystem.getSourceDataLine(af);
    sdl = AudioSystem.getSourceDataLine(af);
    sdl.open(af);
    sdl.start();
    for(int i=0; i<msecs*frequency/1000; i++){
      double angle = i/(frequency/hz)*2.0*Math.PI;
      buf[0]=(byte)(Math.sin(angle)*volume);

      if(addHarmonic) {
        double angle2 = (i)/(frequency/hz)*2.0*Math.PI;
        buf[1]=(byte)(Math.sin(2*angle2)*volume*0.6);
        sdl.write(buf,0,2);
      } else {
        sdl.write(buf,0,1);
      }
    }
    sdl.drain();
    sdl.stop();
    sdl.close();
  }

  public static void main(String[] args){
    Runnable r = new Runnable() {
      public void run() {
        Tone t = new Tone();
        t.setVisible(true);
      }
    };
    SwingUtilities.invokeLater(r);
  }
}
Comments
Post Details
Added on Dec 5 2007
11 comments
11,474 views