30

I am working on a Java program, and I really need to be able to play a sound by a certain frequency and duration, similarly to the c# method System.Beep, I know how to use it in C#, but I can't find a way to do this in Java. Is there some equivalent, or another way to do this?

using System;

class Program
{
    static void Main()
    {
    // The official music of Dot Net Perls.
    for (int i = 37; i <= 32767; i += 200)
    {
        Console.Beep(i, 100);
    }
    }
}
informatik01
  • 15,174
  • 9
  • 67
  • 100
Glen654
  • 1,012
  • 3
  • 13
  • 18

8 Answers8

58

You can use this:

java.awt.Toolkit.getDefaultToolkit().beep();

EDIT

If you are trying to play anything of duration and with different sounds you should really look into the Java MIDI library. The default beep won't be able to meet your needs as you can't change the length of the beep.

http://www.oracle.com/technetwork/java/index-139508.html

Hunter McMillen
  • 52,839
  • 21
  • 105
  • 154
8

Just print it:

System.out.println("\007")

Works on Windows and MacOS.

PHPst
  • 14,868
  • 20
  • 85
  • 158
Adrian
  • 3,652
  • 2
  • 27
  • 38
  • 3
    @devoured-elysium, works on W7 if executed with java.exe. If executed with javaw.exe or eclipse (ie. no real console) then there is no beep. – RealHowTo Mar 17 '14 at 23:19
  • And you can't play a tune like this ... unless your users are all completely tone-deaf. – Stephen C Feb 21 '18 at 00:14
5

I've hacked together a function that works for me. It uses a bunch of stuff from javax.sound.sampled. I've geared it to work with the audio format my system automatically gives a new Clip from AudioSystem.getClip(). There's probably all kinds of ways it could be made more robust and more efficient.

/**
 * Beeps.  Currently half-assumes that the format the system expects is
 * "PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, big-endian"
 * I don't know what to do about the sample rate.  Using 11025, since that
 * seems to be right, by testing against A440.  I also can't figure out why
 * I had to *4 the duration.  Also, there's up to about a 100 ms delay before
 * the sound starts playing.
 * @param freq
 * @param millis 
 */
public static void beep(double freq, final double millis) {
    try {
        final Clip clip = AudioSystem.getClip();
        AudioFormat af = clip.getFormat();

        if (af.getSampleSizeInBits() != 16) {
            System.err.println("Weird sample size.  Dunno what to do with it.");
            return;
        }

        //System.out.println("format " + af);

        int bytesPerFrame = af.getFrameSize();
        double fps = 11025;
        int frames = (int)(fps * (millis / 1000));
        frames *= 4; // No idea why it wasn't lasting as long as it should.

        byte[] data = new byte[frames * bytesPerFrame];

        double freqFactor = (Math.PI / 2) * freq / fps;
        double ampFactor = (1 << af.getSampleSizeInBits()) - 1;

        for (int frame = 0; frame < frames; frame++) {
            short sample = (short)(0.5 * ampFactor * Math.sin(frame * freqFactor));
            data[(frame * bytesPerFrame) + 0] = (byte)((sample >> (1 * 8)) & 0xFF);
            data[(frame * bytesPerFrame) + 1] = (byte)((sample >> (0 * 8)) & 0xFF);
            data[(frame * bytesPerFrame) + 2] = (byte)((sample >> (1 * 8)) & 0xFF);
            data[(frame * bytesPerFrame) + 3] = (byte)((sample >> (0 * 8)) & 0xFF);
        }
        clip.open(af, data, 0, data.length);

        // This is so Clip releases its data line when done.  Otherwise at 32 clips it breaks.
        clip.addLineListener(new LineListener() {                
            @Override
            public void update(LineEvent event) {
                if (event.getType() == Type.START) {
                    Timer t = new Timer((int)millis + 1, new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            clip.close();
                        }
                    });
                    t.setRepeats(false);
                    t.start();
                }
            }
        });
        clip.start();
    } catch (LineUnavailableException ex) {
        System.err.println(ex);
    }
}

EDIT: Apparently somebody's improved my code. I haven't tried it yet, but give it a go: https://gist.github.com/jbzdak/61398b8ad795d22724dd

Erhannis
  • 3,613
  • 2
  • 24
  • 38
  • With this, I could generate sound under Ubuntu 12.04. Thanks! – Joanis Sep 04 '14 at 22:09
  • @Erhannis: I have slightly enhanced this snippet and now it sound clearer on my system --- feek free to incorporate it in your answer: https://gist.github.com/jbzdak/61398b8ad795d22724dd – jb. Mar 20 '15 at 19:41
  • Can't access Type from a variable declared.Instead just call it with class name because it is static.So change the line event.Type.START to LineEvent.Type.START – ShihabSoft Aug 06 '15 at 14:30
  • @ShihabSoft I...don't see such a line? There's `event.getType() == Type.START`, but that's different. – Erhannis Aug 06 '15 at 20:38
  • Sorry its not just Type.START its LineEvent.Type.START – ShihabSoft Aug 07 '15 at 17:55
  • 1
    @jb: for me first solution from Erhannis works better - smoother. – mojmir.novak May 09 '17 at 08:35
4

I don't think there's a way to play tunes1 with "beep" in portable2 Java. You'll need to use the javax.sound.* APIs I think ... unless you can find a third-party library that simplifies things for you.

If you want to go down this path, then this page might give you some ideas.


1 - Unless your users are all tone-deaf. Of course you can do things like beeping in Morse code ... but that's not a tune.

2 - Obviously, you could make native calls to a Windows beep function. But that would not be portable.

Stephen C
  • 632,615
  • 86
  • 730
  • 1,096
4

Another solution, Windows dependent is to use JNA and call directly Windows Beep function, available in kernel32. Unfortunately Kernel32 in JNA doesn't provide this method in 4.2.1, but you can easily extend it.

public interface Kernel32 extends com.sun.jna.platform.win32.Kernel32 {

        /**
         * Generates simple tones on the speaker. The function is synchronous; 
         * it performs an alertable wait and does not return control to its caller until the sound finishes.
         * 
         * @param dwFreq : The frequency of the sound, in hertz. This parameter must be in the range 37 through 32,767 (0x25 through 0x7FFF).
         * @param dwDuration : The duration of the sound, in milliseconds.
         */
        public abstract void Beep(int dwFreq, int dwDuration);
}

To use it :

static public void main(String... args) throws Exception {
    Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
    kernel32.Beep(800, 3000);
}

If you use maven you have to add the following dependencies :

<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna</artifactId>
    <version>4.2.1</version>
</dependency>
<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna-platform</artifactId>
    <version>4.2.1</version>
</dependency>
EFalco
  • 628
  • 1
  • 8
  • 10
  • Problems with this solution: 1) It will only work on Windows. The OP doesn't state that a Windows-only solution is acceptable. 2) You are depending on an internal API which could change or be closed off in a future Java version. 3) This is unlikely to work if the JVM is sandboxed. (Just saying). – Stephen C Feb 21 '18 at 00:20
0

You can get the reference of Toolkit class here, where the method beep() is defined.

Bhavik Ambani
  • 6,357
  • 14
  • 52
  • 84
0

Use Applet instead. You'll have to supply the beep audio file as a wav file, but it works. I tried this on Ubuntu:

package javaapplication2;

import java.applet.Applet;
import java.applet.AudioClip;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;

public class JavaApplication2 {

    public static void main(String[] args) throws MalformedURLException {
        File file = new File("/path/to/your/sounds/beep3.wav");
        URL url = null;
        if (file.canRead()) {url = file.toURI().toURL();}
        System.out.println(url);
        AudioClip clip = Applet.newAudioClip(url);
        clip.play();
        System.out.println("should've played by now");
    }
}
//beep3.wav was available from: http://www.pacdv.com/sounds/interface_sound_effects/beep-3.wav
Nav
  • 16,995
  • 26
  • 78
  • 120
0

If you're using SWT widgets, you can do it this way (SYSTEM SOUND BEEP!)

org.eclipse.swt.widgets.Display.getCurrent().beep();

if you want NATIVE JAVA, here is a class for it: https://github.com/marcolopes/dma/blob/master/org.dma.java/src/org/dma/java/util/SoundUtils.java

marcolopes
  • 8,929
  • 14
  • 46
  • 65