Skip to Main Content

Java SE (Java Platform, Standard Edition)

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Interested in getting your voice heard by members of the Developer Marketing team at Oracle? Check out this post for AppDev or this post for AI focus group information.

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

843802
Any reason why you call getSourceDataLine() twice? This is quite handy, thank you.
User_64CKJ
JLudwig wrote:
Any reason why you call getSourceDataLine() twice? ..
Oh wait, I know this one (..snaps fingers. yes) it is because I am a mor0n, and forgot the class level (static) attribute declared earlier in the source when I (re)declared the local attribute and called getSourceDatLine (which was redundant, given the next line, which as you point out also called getSourceDataLine).

There are (at least) two ways to correct this problem.
1) Remove the class level attribute and the second call.
2) Remove the local attribute as well as the first call (all on the same code line).

Method 1 makes more sense, unless you intend to refactor the code to only instantiate a single SDL for however many times the user presses (what was it? Oh yeah..) 'Generate Tone'.

My 'excuse' for my odd programming is that this was 'hacked down' from a longer program to form an SSCCE. I should have paid more attention to the fine details (and perhaps run a lint checker on it).

Thanks for pointing that out. I guess from the fact you spotted it, that you have already corrected the problem. That you thought to report it, gives me confidence that you 'will go far (and be well thought of, besides)' in the open source community.
..This is quite handy, thank you.
You're welcome. Thanks for letting us know about the error (OK - the pointless redundancy). Thanks to your report, other people who see this code later, will not have to wonder what (the heck) I was thinking when I did that.

Another thing I noted, now I run the source on a 400MHz laptop (it's hard times, here) is that the logic could be improved. At the speeds that my laptop can feed data into the SDL, the sound that comes out the speakers approximates the sound of flatulence (with embedded static, as a free bonus!).

Edit 1: Changed one descriptive word so that it might get by the net-nanny.

Edited by: AndrewThompson64 on Mar 27, 2008 11:09 PM
843802
Please help I'm trying to use your code as a guide to create DTMF tones.
The DTMF requirements are to produce 2 tones at different frequencies. If you do a search on wikipedia they have a nice little table.
I can get the first tone to produce the right note and I can get the second note to produce the right note, individually. However when I do:
            
double angle = i / (frequency / hz1)* ttpi;
double angle2 = i / (frequency / hz2) * ttpi;
buf[0] = (byte) (Math.sin(angle) * volume);
buf[1] = (byte) (Math.sin(2*angle2) * (volume));
sdl.write(buf, 0, 2);
I dont get the two tones to be produced in the proper manner. Can you help me adjust this code to work?
User_64CKJ
The problem is most probably in the code you did not write.

Post an SSCCE* to a new thread, add some dukes, and if I see it and have time, I'll look into it (assuming somebody else does not see the code and solve it first).

* Google it.
843802
Started a new thread

Edited by: karlmarxxx on Apr 16, 2008 1:43 AM
843802
AndrewThompson64 wrote:
sTone.setToolTipText(
"Tone (in Hertz or cycles per second - middle C is 441 Hz)");
middle c is certainly not 441 hz. : )
frequencies
User_64CKJ
TuringPest wrote:
AndrewThompson64 wrote:
sTone.setToolTipText(
"Tone (in Hertz or cycles per second - middle C is 441 Hz)");
middle c is certainly not 441 hz. : )
frequencies
That's a pity. In that case, amend that to..
    sTone.setToolTipText(
      "Tone (in Hertz or cycles per second)");
;-)
843802
First of all I thank you for posting this code. It is very much what I need.

Now, when I run the program I get hard sounds at both beginning and end of the tone. Is this just a symptom of a crappy sound system, poor quality headphones, or is it avoidable by coding? I am trying to convert a Morse code training program that I wrote quite a few years ago in C. The hard sounds in the headphones would get very tiring very quickly. Any help you can give me would be greatly appreciated.

I think that I might have to ramp up the volume at the beginning of the tone and ramp it down again at the end. First, is this possible and second, is there a better way to eliminate the hard sounds?

Thanks.
843802
To avoid static:

In the generateTone method, you have put sdl.start() just after sdl.open(af).
Instead put sdl.start() and put it just after the for loop and just before sdl.drain().

Hope that helps.

Ram
--
843802
you might want to look at JSyn:

[http://www.softsynth.com/jsyn/|http://www.softsynth.com/jsyn/]




or leave the world altogether and look at SuperCollider :

[http://supercollider.sourceforge.net/|http://supercollider.sourceforge.net/]

sc3*2
PhHein
Please stop posting to years old threads. Locking.
1 - 11
Locked Post
New comments cannot be posted to this locked post.

Post Details

Locked on Apr 14 2009
Added on Dec 5 2007
11 comments
13,939 views