Results 1 to 11 of 11
  1. #1
    dkas is offline Member
    Join Date
    Dec 2010
    Posts
    11
    Rep Power
    0

    Default 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.

  2. #2
    milovan is offline Senior Member
    Join Date
    Jan 2011
    Location
    Belgrade, Serbia
    Posts
    272
    Rep Power
    4

    Default

    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...

  3. #3
    dkas is offline Member
    Join Date
    Dec 2010
    Posts
    11
    Rep Power
    0

    Default

    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.

  4. #4
    quad64bit's Avatar
    quad64bit is offline Moderator
    Join Date
    Jul 2009
    Location
    VA
    Posts
    1,323
    Rep Power
    6

    Default

    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.

  5. #5
    dkas is offline Member
    Join Date
    Dec 2010
    Posts
    11
    Rep Power
    0

    Default

    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

    }

  6. #6
    quad64bit's Avatar
    quad64bit is offline Moderator
    Join Date
    Jul 2009
    Location
    VA
    Posts
    1,323
    Rep Power
    6

    Default

    Hmm.. okay. So then I have to go via microphone.
    You don't have to, thats why I suggested line out to line in. Have you tried that?

  7. #7
    dkas is offline Member
    Join Date
    Dec 2010
    Posts
    11
    Rep Power
    0

    Default

    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.

  8. #8
    quad64bit's Avatar
    quad64bit is offline Moderator
    Join Date
    Jul 2009
    Location
    VA
    Posts
    1,323
    Rep Power
    6

    Default

    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.

  9. #9
    dkas is offline Member
    Join Date
    Dec 2010
    Posts
    11
    Rep Power
    0

    Default

    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++;
    }

  10. #10
    quad64bit's Avatar
    quad64bit is offline Moderator
    Join Date
    Jul 2009
    Location
    VA
    Posts
    1,323
    Rep Power
    6

    Default

    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.

  11. #11
    dkas is offline Member
    Join Date
    Dec 2010
    Posts
    11
    Rep Power
    0

    Default

    Thanks for your detailed reply. My purpose is as simple as figuring out if it is sound A or sound B. There has to be a simple solution !

Similar Threads

  1. Toolkit.getDefaultToolkit().beep() does not work
    By adelfa in forum New To Java
    Replies: 8
    Last Post: 11-10-2010, 06:05 AM
  2. Replies: 4
    Last Post: 06-30-2009, 11:31 PM
  3. Java ME beep(frequency, time)
    By Morfmor in forum New To Java
    Replies: 2
    Last Post: 08-28-2008, 10:34 PM
  4. Beep
    By JavaLerner in forum New To Java
    Replies: 3
    Last Post: 07-16-2008, 10:17 AM
  5. How to beep every 5 minutes in Java
    By Java Tip in forum java.lang
    Replies: 0
    Last Post: 04-16-2008, 10:40 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •