5

私は、周波数値の配列 (つまり、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) を再生します。このコードが機能するかどうかをテストするためでした。ここで、一連の周波数を取得し、何らかの計算を実行して、サンプル データを書き込む必要があります。

4

2 に答える 2

2

複数の波形を1つにミックスする場合は、いくつかの方法でクリッピングを防ぐことができます。

sample[i]がすべての音の合計を表すフロートであると仮定します。

ハードクリップ:

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

ヘッドルーム(曲線の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];
于 2012-08-27T14:10:51.110 に答える
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 がクラッシュする可能性があります。だから、これがお役に立てば幸いです-私はこれを答えとしてマークしています。

于 2012-08-06T00:48:12.040 に答える