java Android:正弦波生成

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11436472/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 05:08:01  来源:igfitidea点击:

Android: Sine Wave Generation

javaandroidwaveform

提问by K. Barresi

I'm trying to use AudioTrack to generate sine, square, and sawtooth waves. However, the audio this is creating doesn't sound like a pure sine wave, but like it has some kind of other wave overlayed. How would I go about getting the pure sine wave like in the second code example, while using the method in my first example? Since the top example only moves around some of the arithmetic used in the second, shouldn't they produce an identical wave?

我正在尝试使用 AudioTrack 生成正弦波、方波和锯齿波。但是,由此产生的音频听起来不像是纯正弦波,而是叠加了某种其他波。在使用第一个示例中的方法时,我将如何像在第二个代码示例中那样获得纯正弦波?由于上面的例子只围绕第二个中使用的一些算术移动,它们不应该产生相同的波浪吗?

@Override
        protected Void doInBackground(Void... foo) {
            short[] buffer = new short[1024];
            this.track = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrack.MODE_STREAM);
            float samples[] = new float[1024];

            this.track.play();

            while (true) {
                for (int i = 0; i < samples.length; i++) {
                    samples[i] = (float) Math.sin( (float)i * ((float)(2*Math.PI) * frequency / 44100));    //the part that makes this a sine wave....
                    buffer[i] = (short) (samples[i] * Short.MAX_VALUE);
                }
                this.track.write( buffer, 0, samples.length );  //write to the audio buffer.... and start all over again!

            }           
        }

Note: This does give me a pure sine wave:

注意:这确实给了我一个纯正弦波:

@Override
        protected Void doInBackground(Void... foo) {
            short[] buffer = new short[1024];
            this.track = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrack.MODE_STREAM);
            float increment = (float)(2*Math.PI) * frequency / 44100; // angular increment for each sample
            float angle = 0;
            float samples[] = new float[1024];

            this.track.play();

            while (true) {
                for (int i = 0; i < samples.length; i++) {
                    samples[i] = (float) Math.sin(angle);   //the part that makes this a sine wave....
                    buffer[i] = (short) (samples[i] * Short.MAX_VALUE);
                    angle += increment;
                }
                this.track.write( buffer, 0, samples.length );  //write to the audio buffer.... and start all over again!

            }           
        }

Thanks to Martijn: The problem is that the wave is getting cut off between wavelengths in the buffer. Increasing the buffer size solves the problem in the second example. It appears that the Math.PI * 2 arithmetic was the most intensive of the loop, so moving that value to an external variable that is only computed once solves everything.

感谢 Martijn:问题是波在缓冲区中的波长之间被截断了。增加缓冲区大小解决了第二个示例中的问题。看起来 Math.PI * 2 算术是循环中最密集的,因此将该值移动到仅计算一次的外部变量可以解决所有问题。

采纳答案by Martijn Courteaux

Try to optimise your code by

尝试通过以下方式优化您的代码

  1. increase buffer size
  2. prepare the buffer once, and keep rewriting it to the output stream (this will require some math calculating the perfect size for the buffer to make sure that the whole sine wave fits perfectly in it).
  1. 增加缓冲区大小
  2. 准备一次缓冲区,并不断将其重写到输出流(这将需要一些数学计算来计算缓冲区的完美大小,以确保整个正弦波完全适合其中)。

Why? Because I suspect the buffer to taking to long to prepare, what causes a lag between two buffer pushes to big, which might be causing the noise.

为什么?因为我怀疑缓冲区需要很长时间来准备,导致两个缓冲区之间的延迟推大,这可能会导致噪音。

回答by Robert Harvey

The only material difference that I can see in your two code samples is that the equation in your first example contains an integer (I), and therefore you're probably doing integer (not floating-point) arithmetic. This would cause a staircasing effect, adding unwanted harmonics to your waveform.

我在您的两个代码示例中看到的唯一实质性区别是您的第一个示例中的方程包含一个整数 ( I),因此您可能正在执行整数(而不是浮点)算术。这会导致阶梯效应,在波形中添加不需要的谐波。

I suspect that if you simply cast Ito a float in your equation, it will produce a pure sine wave.

我怀疑,如果你只是I在方程中转换为浮点数,它会产生一个纯正弦波。

samples[i] 
    = (float) Math.sin( (float)i * ((float)(2*Math.PI) * frequency / 44100));

回答by Léon Pelletier

None of these anwers fixes the problem. The buffer length should be a multiple of the sample rate, or at least the length of one rotation. Let's break it in ton of variables to show we understand things:

这些答案都不能解决问题。缓冲区长度应该是采样率的倍数,或者至少是一圈的长度。让我们将其分解为大量变量以表明我们理解事物:

int sampleRate = 44100;
int bitsPerChannel = 16;
int bytesPerChannel = bitsPerChannel / 8;
int channelCount = 1;
int bytesPerSample = channelCount * bytesPerChannel;
int bytesPerRotation = sampleRate * bytesPerSample * (1d / (double) frequency);

Then you can multiply this bytesPerRotationby anything, it won't change a fact: there won't be glitch in the sound.

然后你可以把它乘以bytesPerRotation任何东西,它不会改变一个事实:声音中不会有毛刺。