android - 安卓产生的正弦波每秒产生一次爆震噪声

标签 android audio wave trigonometry

我想生成具有组合频率的正弦波。我要这样:

public static byte[] combineSineWave(Collection<Double> frequencies) {
    double[] sample = new double[SAMPLE_RATE];
    byte[] result = new byte[2 * SAMPLE_RATE];

    double coefficient = 2 * Math.PI;

    for (int i = 0; i < SAMPLE_RATE; i++) {
        double sum = 0;

        for (double frequency : frequencies) {
            sum += Math.sin(coefficient * i * frequency / SAMPLE_RATE);
        }

        sample[i] = sum / frequencies.size();
    }

    convertToPCM16Bit(sample, result);

    return result;
}

private static void convertToPCM16Bit(double[] sample, byte[] result) {
    int idx = 0;
    for (final double dVal : sample) {
        // scale to maximum amplitude
        final short val = (short) ((dVal * 32767));
        // in 16 bit wav PCM, first byte is the low order byte
        result[idx++] = (byte) (val & 0x00ff);
        result[idx++] = (byte) ((val & 0xff00) >>> 8);
    }
}

并通过此代码播放生成的字节:
AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, SoundWaveGenerator.SAMPLE_RATE,
            AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, 2 * SoundWaveGenerator.SAMPLE_RATE,
            AudioTrack.MODE_STREAM);

    audioTrack.play();

    while (true) {
        byte[] bytes = SoundWaveGenerator.combineSineWave(frequencies);
        audioTrack.write(bytes, 0, bytes.length);
    }

但是问题是我听到了每秒的咔嗒声。怎么了?

最佳答案

您听到的点击是每次调用CombineSineWave之间的中断。在每次调用CombineSineWave时,每个频率将以零度相位开始。但是,根据频率,到1秒间隔结束时,可能不会产生偶数个周期。假设其中一个频率是第二个频率的最后一个采样点为90度(1.0),则在生成下一个间隔时会出现间断。

要解决此问题,您需要跟踪连续调用之间的某些状态。我在下面编写了一个示例,但是我不知道如何在Java中通过引用传递。另外,您还需要处理i滚动的可能性。

int i = 0;
while (true) {
    byte[] bytes = SoundWaveGenerator.combineSineWave(frequencies, ref i);
    audioTrack.write(bytes, 0, bytes.length);
}


public static byte[] combineSineWave(Collection<Double> frequencies, ref int i) {
    double[] sample = new double[SAMPLE_RATE];
    byte[] result = new byte[2 * SAMPLE_RATE];

    double coefficient = 2 * Math.PI;

    for (int j = 0; j < SAMPLE_RATE; j++) {
        double sum = 0;

        for (double frequency : frequencies) {
            sum += Math.sin(coefficient * i++ * frequency / SAMPLE_RATE);
        }
        sample[i] = sum / frequencies.size();
    }

    convertToPCM16Bit(sample, result);

    return result;
}

附言您可以在循环外部按SAMPLE_RATE进行划分。
double coefficient = 2 * Math.PI / SAMPLE_RATE;

关于android - 安卓产生的正弦波每秒产生一次爆震噪声,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26609416/

相关文章:

accessibility - 使用 WAVE 工具检查本地 html 文件

python-3.x - python 3 : Convert wave data (byte array) to numpy array of floating point values

android - 在android中使用mapsforge的离线 map

java - 如何在 JAVA 中将 ID 添加到已编程的布局项 (android)

android - AndroidX 不支持 Facebook SDK

iphone - 获取音频路由给出空字符串

Android sdk内容加载器错误

javascript - JavaScript API 问题

audio - 使用 ffmpeg 将 MP3 文件拆分为多个相同长度的文件

python - 从声音文件中获取帧