Android - 将多个静态波形混合到一个AudioTrack中

时间:2012-08-05 23:00:03

标签: android audio audiotrack

我正在制作一个带有一系列频率值(即440Hz,880Hz,1760Hz)的类,并播放它们如何组合成单个AudioTrack的声音。我不是一个合理的程序员,所以我自己写这篇文章很困难,我认为对于经验丰富的声音程序员来说这是一个相对容易的问题。以下是play方法中的一些代码:

public void play() {
    // Get array of frequencies with their relative strengths
    double[][] soundData = getData();

    // TODO
    // Perform a calculation to fill an array with the mixed sound - then play it in an infinite loop
    // Need an AudioTrack that will play calculated loop
    // Track sample info
    int numOfSamples = DURATION * SAMPLE_RATE;
    double sample[] = new double[numOfSamples];
    byte sound[] = new byte[2 * numOfSamples];

    // fill out the array
    for (int i = 0; i < numOfSamples; ++i) {
            sample[i] = Math.sin(2 * Math.PI * i / (SAMPLE_RATE / 440));
    }

    int i = 0;
    for (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
        sound[i++] = (byte) (val & 0x00ff);
        sound[i++] = (byte) ((val & 0xff00) >>> 8);
    }

    // Obtain a minimum buffer size
    int minBuffer = AudioTrack.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);

    if (minBuffer > 0) {
        // Create an AudioTrack
        AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO, 
                AudioFormat.ENCODING_PCM_16BIT, numOfSamples, AudioTrack.MODE_STATIC);

        // Write audio data to track
        track.write(sound, 0, sound.length);

        // Begin playing track
        track.play();
    }

    // Once everything has successfully begun, indicate such.
    isPlaying = true;
}

目前,此代码只播放音乐会A(440Hz)。这是测试此代码是否有效。现在,我需要采取一堆频率,执行某种计算,并编写样本数据。

2 个答案:

答案 0 :(得分:2)

好的,所以答案确实是一个简单的求和循环。在这里,只需用原来的那个替换这个for循环:

    // fill out the array
    for (int i = 0; i < numOfSamples; ++i) {
            double valueSum = 0;

            for (int j = 0; j < soundData.length; j++) {
                valueSum += Math.sin(2 * Math.PI * i / (SAMPLE_RATE / soundData[j][0]));
            }

            sample[i] = valueSum / soundData.length;
    }

现在,这样做只需采用所有可能的频率,将它们一起添加到变量valueSum中,然后将其除以频率数组的长度soundData,这很简单平均。这产生了一个任意长的频率阵列的漂亮的正弦波混合。

我还没有测试过性能,但是我确实在一个线程中运行了它,否则它可能会崩溃UI。所以,希望这会有所帮助 - 我将此标记为答案。

答案 1 :(得分:2)

如果您打算将多个波形混合为一个,可以通过多种方式防止削波。

假设sample [i]是一个表示所有声音总和的浮点数。

HARD CLIPPING:

if (sample[i]> 1.0f)
{
    sample[i]= 1.0f;
}
if (sample[i]< -1.0f)
{
    sample[i]= -1.0f;
}

HEADROOM (y = 1.1x - 0.2x ^ 3曲线,最小和最大上限略低于1.0f)

if (sample[i] <= -1.25f)
{
    sample[i] = -0.987654f;
}
else if (sample[i] >= 1.25f)
{
    sample[i] = 0.987654f;
}
else
{
    sample[i] = 1.1f * sample[i] - 0.2f * sample[i] * sample[i] * sample[i];
}

对于第3个多项式wavehapper(不太平滑),将上一行替换为:

sample[i]= 1.1f * sample[i]- 0.2f * sample[i] * sample[i] * sample[i];