【问题标题】:Android: Sine Wave GenerationAndroid:正弦波生成
【发布时间】:2012-07-11 07:06:55
【问题描述】:

我正在尝试使用 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!

            }           
        }

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

@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!

            }           
        }

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

【问题讨论】:

  • 听起来您可能听到了一些混叠或削波。尝试降低您正在生成的声波的幅度。
  • 那么为什么不使用有效的代码呢?我不确定你的问题是什么。
  • 罗伯特,我也想创建方波和锯齿波,但是在处理更高级别的波函数时,整个角度和增量的想法让我感到困惑。
  • 尝试通过以下方式优化您的代码:1) 增加缓冲区大小,2) 准备一次缓冲区,并继续将其重写到输出流(这将需要一些数学计算来计算缓冲区的完美大小确保整个正弦波完全适合它)。
  • 哦,我明白你的意思了。由于在缓冲区中可能会在一个完整波长之间结束波,导致波在每次缓冲区推送的开始和结束时变形?

标签: java android waveform


【解决方案1】:

尝试通过

优化你的代码
  1. 增加缓冲区大小
  2. 准备一次缓冲区,然后继续将其重写到输出流(这将需要一些数学计算来计算缓冲区的完美大小,以确保整个正弦波完全适合其中)。

为什么?因为我怀疑缓冲区需要很长时间才能准备好,所以导致两个缓冲区之间的延迟变大的原因可能会导致噪音。

【讨论】:

    【解决方案2】:

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

    我怀疑如果您只是将I 转换为方程式中的浮点数,它将产生纯正弦波。

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

    【讨论】:

    • 将 i 转换为浮点数根本不会影响计算。
    • @you786 是的,好的。我想我们已经确定了这一点。
    【解决方案3】:

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

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

    然后你可以将这个bytesPerRotation 乘以任何东西,它不会改变一个事实:声音不会有故障。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-21
      • 2015-02-01
      • 2018-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-10
      • 1970-01-01
      相关资源
      最近更新 更多