Java sound generation generates noise

I'm using javax Sound to make sound, but when you play, they will make some noise in the background. If you play several notes at a time, it will even overcome the sound This is the code:

public final static double notes[] = new double[] {130.81,138.59,146.83,155.56,164.81,174.61,185,196,207.65,220,233.08,246.94,261.63,277.18,293.66,311.13,329.63,349.23,369.99,392,415.3,440,466.16,493.88,523.25,554.37};



public static void playSound(int note,int type) throws LineUnavailableException {          //type 0 = sin,type 1 = square

    Thread t = new Thread() {
        public void run() {
            try {

                int sound = (int) (notes[note] * 100);


                byte[] buf = new byte[1];
                AudioFormat af = new AudioFormat((float) sound,8,1,true,false);
                SourceDataLine sdl;

                sdl = AudioSystem.getSourceDataLine(af);

                sdl = AudioSystem.getSourceDataLine(af);
                sdl.open(af);
                sdl.start();
                int maxi = (int) (1000 * (float) sound / 1000);
                for (int i = 0; i < maxi; i++) {
                    double angle = i / ((float) 44100 / 440) * 2.0
                            * Math.PI;
                    double val = 0;
                    if (type == 0) val = Math.sin(angle)*100;
                    if (type == 1) val = square(angle)*50;

                    buf[0] = (byte) (val * (maxi - i) / maxi);
                    sdl.write(buf,1);
                }
                sdl.drain();
                sdl.stop();
                sdl.close();
            } catch (LineUnavailableException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        };
    };

    t.start();
}

public static double square (double angle){
    angle = angle % (Math.PI*2);
    if (angle > Math.PI) return 1;
    else return 0;
}

This code comes from: https://stackoverflow.com/a/1932537/3787777

Solution

In this answer, I will refer to 1) your code, 2) a better way (with all due respect:) and 3) playing two notes at the same time

Your code

First, the sampling rate should not depend on the note frequency So try:

AudioFormat(44100,...

Next, use 16 bit sampling (sounds better!) Here's your code to play a simple tone without noise - but I'll use it a little (see later) Please review the comments:

Thread t = new Thread() {
    public void run() {
        try {

            int sound = (440 * 100);        // play A
            AudioFormat af = new AudioFormat(44100,16,false);
            SourceDataLine sdl;
            sdl = AudioSystem.getSourceDataLine(af);
            sdl.open(af,4096 * 2);
            sdl.start();

            int maxi = (int) (1000 * (float) sound / 1000); // should not depend on notes frequency!
            byte[] buf = new byte[maxi * 2];   // try to find better len!
            int i = 0;
            while (i < maxi * 2) {
                // formula is changed to be simple sine!!
                double val = Math.sin(Math.PI * i * 440 / 44100);
                short s = (short) (Short.MAX_VALUE * val);
                buf[i++] = (byte) s;
                buf[i++] = (byte) (s >> 8);   // little endian
            }
            sdl.write(buf,maxi);
            sdl.drain();
            sdl.stop();
            sdl.close();
        } catch (LineUnavailableException e) {
            e.printStackTrace();
        }
    }
};

t.start();

Suggest better code

The following is a simplified version of the code, which can play some noiseless notes (frequencies) I prefer it because we first create a doubles array, which is a general value These values can be combined, stored or further modified We then convert them to (8 - bit or 16 - bit) sample values

private static byte[] buffer = new byte[4096 * 2 / 3];
private static int bufferSize = 0;

// plays a sample in range (-1,+1).
public static void play(SourceDataLine line,double in) {
    if (in < -1.0) in = -1.0;  // just sanity checks
    if (in > +1.0) in = +1.0;

    // convert to bytes - need 2 bytes for 16 bit sample
    short s = (short) (Short.MAX_VALUE * in);
    buffer[bufferSize++] = (byte) s;
    buffer[bufferSize++] = (byte) (s >> 8);   // little Endian

    // send to line when buffer is full
    if (bufferSize >= buffer.length) {
        line.write(buffer,buffer.length);
        bufferSize = 0;
    }
    // todo: be sure that whole buffer is sent to line!
}

// prepares array of doubles,not related with the sampling value!
private static double[] tone(double hz,double duration) {
    double amplitude = 1.0;
    int N = (int) (44100 * duration);
    double[] a = new double[N + 1];
    for (int i = 0; i <= N; i++) {
        a[i] = amplitude * Math.sin(2 * Math.PI * i * hz / 44100);
    }
    return a;
}

// finally:
public static void main(String[] args) throws LineUnavailableException {
    AudioFormat af = new AudioFormat(44100,false);
    SourceDataLine sdl = AudioSystem.getSourceDataLine(af);

    sdl.open(af,4096 * 2);
    sdl.start();

    double[] tones = tone(440,2.0);    // play A for 2 seconds
    for (double t : tones) {
        play(sdl,t);
    }

    sdl.drain();
    sdl.stop();
    sdl.close();
}

That sounds good

The above is the whole content of the noise generated by Java sound generation collected and sorted by the programming house for you. I hope this article can help you solve the program development problems encountered by the noise generated by Java sound generation.

If you think the content of the programming home website is good, you are welcome to recommend the programming home website to programmers and friends.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>