Java声音生成产生嘈杂的声音 [英] Java sound generation produces noisy sound

查看:60
本文介绍了Java声音生成产生嘈杂的声音的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 javax.sound 来制作声音,但是当您播放它时,它们会在背景中产生某种噪音,如果您一次演奏几个音符,它甚至会克服声音.代码如下:

I am using javax.sound to make sounds, however when you play it they have some sort of noise in background, which even overcomes the sound if you play few notes at once. Here 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, 0, 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;
}

此代码来自:https://stackoverflow.com/a/1932537/3787777

推荐答案

在这个答案中,我将参考 1) 您的代码,2) 更好的方法 (恕我直言:) 和 3) 同时演奏两个音符.

In this answer I will refer to 1) your code, 2) better approach (IMHO:) and 3) playing of two notes in the same time.

首先,采样率应该取决于音符频率.因此尝试:

First, the sample rate should not depend on note frequency. Therefore try:

AudioFormat(44100,...

接下来,使用 16 位采样(听起来更好!).这是您的代码,它播放简单的音调而没有噪音 - 但我会以不同的方式使用它(见下文).请看评论:

Next, use 16 bit sampling (sounds better!). Here is your code that plays simple tone without noise - but I would use it bit differently (see later). Please look for the comments:

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

            int sound = (440 * 100);        // play A
            AudioFormat af = new AudioFormat(44100, 16, 1, true, 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, 0, maxi);
            sdl.drain();
            sdl.stop();
            sdl.close();
        } catch (LineUnavailableException e) {
            e.printStackTrace();
        }
    }
};

t.start();

关于更好代码的提案

这是您的代码的简化版本,它播放一些音符(频率) 没有噪音.我更喜欢它,因为我们首先创建了 double 数组,它们是通用值.这些值可以组合在一起,或存储或进一步修改.然后我们将它们转换为(8 位或 16 位)样本值.

Proposal for better code

Here is a simplified version of your code that plays some note (frequency) without noise. I like it better as we first create array of doubles, which are universal values. These values can be combined together, or stored or further modified. Then we convert them to (8bit or 16bit) samples 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, 0, 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, 16, 1, true, 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();
}

听起来不错;)

只需结合两个音符:

double[] a = tone(440, 1.0);        // note A
double[] b = tone(523.25, 1.0);     // note C (i hope:)
for (int i = 0; i < a.length; i++) {
    a[i] = (a[i] + b[i]) / 2;
}
for (double t : a) {
    play(sdl, t);
}

请记住,使用双阵列,您可以组合和操纵您的音调 - 即制作同时播放的音调声音.当然,如果加3个色调,则需要除以3等归一化值.

Remember that with double array you can combine and manipulate your tones - i.e. to make composition of tone sounds that are being played in the same time. Of course, if you add 3 tones, you need to normalize the value by dividing with 3 and so on.

叮咚:)

这篇关于Java声音生成产生嘈杂的声音的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆