Results 1 to 11 of 11
- 02-08-2011, 05:02 PM #1
Member
- Join Date
- Dec 2010
- Posts
- 11
- Rep Power
- 0
How to detect beep sound using java
Hi,
I am new to audio/sound in java.
Looking for pointers on how to detect that a beep sound was played using java. The sound is going to be played from a independent application onto the computer so I don't know if PCM is going to be 8 bit or 16 bit. I do not have clue about the various parameters that need to be passed to AudioFormat class either, viz. format, sample size etc.
Basically, I want to know if 'beep' or a specific loud sound was played ? Rest of the time, there will be sound disturbance but not this specific sound. I would ideally want to detect loud sound of letter 'O' and letter 'E'. But to start with, I think if I can handle beep, I should be able to do other sounds too.
Appreciate any help with this.
Thanks.
- 02-08-2011, 07:22 PM #2
Senior Member
- Join Date
- Jan 2011
- Location
- Belgrade, Serbia
- Posts
- 227
- Rep Power
- 3
For detecting sounds of letters, I don't know... try to google on java sound api and java speach api, maybe find something for you...
- 02-08-2011, 07:44 PM #3
Member
- Join Date
- Dec 2010
- Posts
- 11
- Rep Power
- 0
Most data / code that I see is reading data from TargetDataLine , which is a microphone.
What I am looking for is the sound that will be coming off of machine speakers.
So, I want to 'read' the sound that is fed to speakers. Most machines do not have microphone and then there will be time delay too. Sound would be relayed from speakers and then read from microphone.
Preferably, I want to skip microphone.
- 02-08-2011, 10:58 PM #4
Yeah, java cannot hijack audio from the system like that. You could always feed the line out into the line in on the machine, and grab audio that way.
- 02-09-2011, 05:35 PM #5
Member
- Join Date
- Dec 2010
- Posts
- 11
- Rep Power
- 0
Hmm.. okay. So then I have to go via microphone.
I have the following code that reads bytes off of targetDataLine. I am converting the bytes read to numbers. The problem here is that whatever sound I play, it is printing the same output.
Problem 2: The tempBuffer throws "ArrayIndexOutofBounds" exception after about 10 seconds even though sound is continously being fed to Microphone.
Here is the code:
boolean running = false;
ByteArrayOutputStream byteArrayOutputStream = null;
AudioFormat format;
TargetDataLine targetDataLine;
AudioInputStream audioInputStream;
SourceDataLine sourceDataLine;
public void testMain(Object[] args)
{
captureAudio();
sleep(120);
running = false;
}
private void captureAudio(){
try{
//Get everything set up for
// capture
format = getFormat();
DataLine.Info dataLineInfo =
new DataLine.Info(
TargetDataLine.class,
format);
targetDataLine = (TargetDataLine)
AudioSystem.getLine(
dataLineInfo);
targetDataLine.open(format);
targetDataLine.start();
//Create a thread to capture the
// microphone data and start it
// running. It will run until
// the Stop button is clicked.
Thread captureThread =
new Thread(
new CaptureThread());
captureThread.start();
} catch (Exception e) {
System.out.println(e);
System.exit(0);
}//end catch
}//end captureAudio method
public static final int signedShortToInt(byte[] b) {
int result = (b[0] & 0xff) | (b[1] & 0xff) << 8;
return result;
}
private void getSound( byte[] buffer) {
for (int i = 0; i < buffer.length; i++) {
byte[] b = new byte[] { buffer[i], buffer[i + 1] };
int level = (signedShortToInt(b) * 100 / 32767);
if (level < 100) {
System.out.println(level + "SOUND NOT FOUND");
}
else {
System.out.println(level + " SOUND FOUND");;
}
}
}
private AudioFormat getFormat() {
float sampleRate = 16000;
int sampleSizeInBits = 8;
int channels = 1;
boolean signed = true;
boolean bigEndian = true;
return new AudioFormat(sampleRate,
sampleSizeInBits, channels, signed, bigEndian);
}
class CaptureThread extends Thread{
//An arbitrary-size temporary holding
// buffer
byte tempBuffer[] = new byte[10000];
public void run(){
byteArrayOutputStream =
new ByteArrayOutputStream();
running = false;
try{//Loop until stopCapture is set
// by another thread that
// services the Stop button.
while(!running){
//Read data from the internal
// buffer of the data line.
int cnt = targetDataLine.read(
tempBuffer,
0,
tempBuffer.length);
if(cnt > 0){
//Save data in output stream
// object.
byteArrayOutputStream.write(
tempBuffer, 0, cnt);
getSound(tempBuffer);
}//end if
}//end while
byteArrayOutputStream.close();
}catch (Exception e) {
System.out.println(e);
// System.exit(0);
}//end catch
}//end run
}//end inner class CaptureThread
}
- 02-09-2011, 05:50 PM #6
You don't have to, thats why I suggested line out to line in. Have you tried that?Hmm.. okay. So then I have to go via microphone.
- 02-09-2011, 06:33 PM #7
Member
- Join Date
- Dec 2010
- Posts
- 11
- Rep Power
- 0
I figured the exception problem .It was issue in getSound method. So my program is running now.
But, I am not 100% sure if this is the correct approach to detect a specific sound. For example a beep sound and thud sound ?
I would basically differentiate them by the 'level' that I get from the above posted code.
- 02-09-2011, 06:42 PM #8
You've encountered the amazingly painful world for frequency analysis. A beep and a thud might appear to be the same thing if you only look at the overall amplification. One thing you can do is a Fourier transform on the data to convert between the time and frequency domains. This allows you to see how much a particular frequency dominates a sound. A beep might be 800Hz, where as a thud might be 50hz. The amplification for either might be the same. The transform shows you what frequencies are dominant.
- 02-09-2011, 09:33 PM #9
Member
- Join Date
- Dec 2010
- Posts
- 11
- Rep Power
- 0
Thanks for the pointer.
I found the code below to get the frequency but it gets frequency of each byte and hence it takes forever to give me the resultant frequency ( I have averaged out the total frequency).
Is there a simpler way to get this frequency. Any sample code would help. I only need to differenciate between two sounds (like Beep and a explosion/thud).
public void getFrequency(byte[] tempBuffer)
{
int counter = 0;
double totalFrequency = 0;
float sample_rate = format.getSampleRate();
System.out.println("sample rate = "+sample_rate);
//Calculate the length in seconds of the sample
// float T = audioInputStream.getFrameLength() / format.getFrameRate();
float T = 2;
System.out.println("T = "+T+ " (length of sampled sound in seconds)");
//Calculate the number of equidistant points in time
int n = (int) (T * sample_rate) / 2;
System.out.println("n = "+n+" (number of equidistant points)");
//Calculate the time interval at each equidistant point
float h = (T / n);
System.out.println("h = "+h+" (length of each time interval in seconds)");
boolean isBigEndian = format.isBigEndian();
//this array is the value of the signal at time i*h
int x[] = new int[n];
//convert each pair of byte values from the byte array to an Endian value
for (int i = 0; i < n*2; i+=2) {
int b1 = tempBuffer[i];
int b2 = tempBuffer[i + 1];
if (b1 < 0) b1 += 0x100;
if (b2 < 0) b2 += 0x100;
int value;
//Store the data based on the original Endian encoding format
if (!isBigEndian) value = (b1 << 8) + b2;
else value = b1 + (b2 << 8);
x[i/2] = value;
//do the DFT for each value of x sub j and store as f sub j
double f[] = new double[n/2];
for (int j = 0; j < n/2; j++) {
double firstSummation = 0;
double secondSummation = 0;
for (int k = 0; k < n; k++) {
double twoPInjk = ((2 * Math.PI) / n) * (j * k);
firstSummation += x[k] * Math.cos(twoPInjk);
secondSummation += x[k] * Math.sin(twoPInjk);
}
f[j] = Math.abs( Math.sqrt(Math.pow(firstSummation,2) +
Math.pow(secondSummation,2)) );
double amplitude = 2 * f[j]/n;
double frequency = j * h / T * sample_rate;
//System.out.println("frequency = "+frequency+", amp = "+amplitude);
totalFrequency += frequency;
counter++;
}
- 02-09-2011, 09:45 PM #10
Well, like I said. The only way to get the frequency for the whole sound is a Fourier transform. Remember that there is no such thing as a frequency of a byte. A byte has a certain level. The very definition of the word frequency is the number of times a given level occurs in a time frame.
A sound stream is a collection of levels over time. The value in the byte array is the amplitude of a given sample. The frequency is determined by the shape of the wave form created by converting the discrete samples into an analog waveform. The number of times a given wave happens per second (Hz) determines the tone, the amplitude of the wave determines the volume.
To measure the frequency of a sound in byte array form, you need to convert it from time domain to the frequency domain. Fourier transform - Wikipedia, the free encyclopedia
By performing a transform, you can supply a sin wave to the data to find out what percentage of the series matches the frequency of the supplied wave.
For instance, a sin wave that cycles 800 times per second would generate a tone of 800Hz. Thats a beep. By passing a whole bunch of different sin waves to the transformed data, you can determine what the level of each frequency is. So, if you had a perfect 800Hz beep, passing in a sin of 100Hz would produce a 0. Passing in a sin of 800Hz might produce 100. 900Hz, 0. In real life, the tones aren't perfect, so you check for a range of values and map out each one.
This website has more detail: Fun with Java, How and Why Spectral Analysis Works - Developer.com
and his article about the Fast Fourier Transform (FFT): Fun with Java, Understanding the Fast Fourier Transform (FFT) Algorithm - Developer.com
Don't feel bad if this is hard to understand. This process involves calculus, understanding of how bytes work on a pretty low level, and a mess of other things. It is difficult. Keep at it! I had to read the docs several times to grasp it initially.
- 02-09-2011, 11:07 PM #11
Member
- Join Date
- Dec 2010
- Posts
- 11
- Rep Power
- 0
Similar Threads
-
Toolkit.getDefaultToolkit().beep() does not work
By adelfa in forum New To JavaReplies: 8Last Post: 11-10-2010, 06:05 AM -
In java,how to detect Plug & Unplug USB key for both linux and Windows OS
By Santhoshkumarp in forum Advanced JavaReplies: 4Last Post: 06-30-2009, 11:31 PM -
Java ME beep(frequency, time)
By Morfmor in forum New To JavaReplies: 2Last Post: 08-28-2008, 10:34 PM -
Beep
By JavaLerner in forum New To JavaReplies: 3Last Post: 07-16-2008, 10:17 AM -
How to beep every 5 minutes in Java
By Java Tip in forum java.langReplies: 0Last Post: 04-16-2008, 10:40 PM


LinkBack URL
About LinkBacks
Reply With Quote
Bookmarks