### Beeping in Java

The objective of this article is to write a beep() method in Java. It will just play a tone in a specified frequency. Before we look into the details of the beep() method, let's have a look at the caller first.// main program to call the beep() method public static void main(String[] args) throws Exception { int frequency=400; // hz int duration =2000; // milliseconds beep(frequency,duration); }

### Physics of Sound

Before we can define the beep() method, we must know the mathematical modeling of a sound wave. Mathematically, a "pure tone" can be represented by a sine wave. The following program will generate a sine wave. Just compile the program and go to the "Visualize" section below.

/****************************************************************************** * File : Sine.java * Author : http://java.macteki.com/ * Description : * Create sample data points of a Sine wave * Tested with : JDK 1.6 ******************************************************************************/ class Sine { static short[] makeSineSample() { double frequency = 400; double sampleRate = 16000; // 16000 samples per second int bytesPerSample = 2; short[] audioData = new short[160]; // 160 sample points = 10 ms int sampleLength = audioData.length; double volume = 8192; for(int i = 0; i < sampleLength; i++){ double time = i/sampleRate; double angle = 2*Math.PI*frequency*time; double sinValue = Math.sin(angle); short amplitude = (short) (volume*sinValue); audioData[i]=amplitude; } return audioData; } public static void main(String[] args) throws Exception { short[] buffer=makeSineSample(); for (int i=0;i<160;i++) { System.out.println(buffer[i]); } } }

The above program will create 160 sample pixels of the sine wave with frequency 400hz. That is, the sine wave will complete 400 cycles in 1 second. If we generate 10 ms of data, there would be 4 cycles. Since the sampling rate is 16000 samples per second, 160 samples will contains 10 ms of data.

### Visualize the Sample Data

First execute the program :

java Sine >out.txtLoad the output file into a excel file, then insert a graph with the sample data. You should see 4 cycles of sine wave as expected.

### Java Sound API

The javax.sound.sampled package provides API to play a sound wave. All we have to do is to feed the sound wave sample data points to a SourceDataLine object. The following is a complete sample of playing a beep sound.

/****************************************************************************** * File : Beep.java * Author : http://java.macteki.com/ * Description : * Play a pure tone with specified frequency * Tested with : JDK 1.6 ******************************************************************************/ class Beep { static void beep(double frequency, int duration) throws Exception { int nChannel = 1; // number of channel : 1 or 2 // samples per second float sampleRate = 16000; // valid:8000,11025,16000,22050,44100 int nBit = 16; // 8 bit or 16 bit sample int bytesPerSample = nChannel*nBit/8; double durationInSecond = duration/1000; int bufferSize = (int) (nChannel*sampleRate*durationInSecond*bytesPerSample); byte[] audioData = new byte[bufferSize]; // "type cast" to ShortBuffer java.nio.ByteBuffer byteBuffer = java.nio.ByteBuffer.wrap(audioData); java.nio.ShortBuffer shortBuffer = byteBuffer.asShortBuffer(); int sampleLength = audioData.length/bytesPerSample; // generate the sine wave double volume = 8192; // 0-32767 double PI = Math.PI; for(int i = 0; i < sampleLength; i++){ double time = i/sampleRate; double freq = frequency; double angle = 2*PI*freq*time; double sinValue = Math.sin(angle); short amplitude = (short) (volume*sinValue); for (int c=0;c<nChannel;c++) { shortBuffer.put(amplitude); } }//end generating sound wave sample boolean isSigned=true; boolean isBigEndian=true; // Define audio format javax.sound.sampled.AudioFormat audioFormat = new javax.sound.sampled.AudioFormat(sampleRate, nBit, nChannel, isSigned,isBigEndian); javax.sound.sampled.DataLine.Info dataLineInfo = new javax.sound.sampled.DataLine.Info( javax.sound.sampled.SourceDataLine.class, audioFormat); // get the SourceDataLine object javax.sound.sampled.SourceDataLine sourceDataLine = (javax.sound.sampled.SourceDataLine) javax.sound.sampled.AudioSystem.getLine(dataLineInfo); sourceDataLine.open(audioFormat); sourceDataLine.start(); // actually play the sound sourceDataLine.write(audioData,0,audioData.length); // "flush", wait until the sound is completed sourceDataLine.drain(); } public static void main(String[] args) throws Exception { int frequency=400; // hz int duration =2000; // milliseconds beep(frequency,duration); } }

Can you tell me why double volume = 8192; ? Why this value?

ReplyDeleteThe volume level 8192 is just an arbitrary choice between 0 and 32767.

DeleteThis comment has been removed by the author.

ReplyDeletewhy volume is a number from 0 to 32767

ReplyDeleteBecause it is a 16 bit sound sample (see line 19 of Beep.java).

DeleteFor a 16 bit sample, the amplitude is stored in a short integer (see line 43).

And for a 16 bit short integer, the range is from -32768 to +32767. That means your sine wave will have a maximum amplitude of 32767. And in Physics, amplitude is volume.

Hope this help.

thx you for these sound posts. i was looking for this for quite some time.

Deletewhy sample rates must be // valid:8000,11025,16000,22050,44100 ?

They are typical rates that most codec would support. Selecting a value from one of them is a safe choice.

Delete