Android輸出正弦波音頻信號(左右聲道對稱)


轉載請說明出處!
作者:kqw攻城獅
出處:個人站 | CSDN


需求:左右聲道分別輸出不同的音頻數據,波形要是一個正弦波,左右聲道還要對稱!
對硬件不是很瞭解,說是要通過音波避障。

效果圖

效果圖

之前已經介紹瞭如何在左右聲道輸出不同的音頻數據。
那麼這裏主要介紹如何模擬出波形是正弦波的音頻數據。

模擬正弦波

/**
 * 模擬正弦波音頻數據
 * @param isLeft 左右聲道
 * @return 音頻數據
 */
private short[] initData(boolean isLeft) {
    double phase = 0.0;
    int amp = 10000;
    short[] data = new short[bufferSize];

    double phaseIncrement = (2 * Math.PI * mFrequency) / mSampleRateInHz;

    for (int i = 0; i < bufferSize; i++) {
        if (isLeft) {
            data[i] = (short) (amp * Math.sin(phase));
        } else {
            data[i] = (short) (-amp * Math.sin(phase));
        }
        phase += phaseIncrement;
        Log.i(TAG, "initData: isLeft = " + isLeft + "  buffer[" + i + "] = " + data[i]);
    }
    return data;
}

主要參數

  • mFrequency:頻率
  • mSampleRateInHz:採樣率
// 單聲道
private int mChannelConfig = AudioFormat.CHANNEL_OUT_MONO;
// 頻率
private int mFrequency = 19000;
// 採樣率
private int mSampleRateInHz = 44100;

播放音頻的線程封裝

package kong.qingwei.myapplication;

import android.annotation.TargetApi;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Build;
import android.util.Log;

/**
 * Created by kqw on 2016/8/29.
 * 播放音樂的線程
 */
public class ChannelThread extends Thread {

    private static final String TAG = "ChannelThread";
    private AudioTrack mAudioTrack;

    private short[] mData;

    /**
     * 構造方法
     *
     * @param channelConfig  聲道
     * @param sampleRateInHz 採樣率
     * @param data           音頻數據
     * @param bufferSize     緩存大小
     * @param isLeft         左右聲道
     */
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public ChannelThread(int channelConfig, int sampleRateInHz, short[] data, int bufferSize, boolean isLeft) {
        mData = data;

        mAudioTrack = new AudioTrack(
                AudioManager.STREAM_MUSIC,
                sampleRateInHz,
                channelConfig,
                AudioFormat.ENCODING_PCM_16BIT,
                bufferSize,
                AudioTrack.MODE_STREAM);

        if (isLeft) {
            mAudioTrack.setStereoVolume(AudioTrack.getMaxVolume(), 0);
        } else {
            mAudioTrack.setStereoVolume(0, AudioTrack.getMaxVolume());
        }
    }

    @Override
    public void run() {
        super.run();
        try {
            if (null != mAudioTrack) {
                mAudioTrack.play();
                while (AudioTrack.PLAYSTATE_STOPPED != mAudioTrack.getPlayState()) {
                    mAudioTrack.write(mData, 0, mData.length);
                }
            }
            Log.i(TAG, "run: End");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 釋放AudioTrack
     */
    public void releaseAudioTrack() {
        if (null != mAudioTrack) {
            mAudioTrack.stop();
            mAudioTrack.release();
            mAudioTrack = null;
        }
    }
}

播放

mLeftChannelThread = new ChannelThread(mChannelConfig, mSampleRateInHz, mDataLeft, bufferSize, true);
mRightChannelThread = new ChannelThread(mChannelConfig, mSampleRateInHz, mDataRight, bufferSize, false);

mLeftChannelThread.start();
mRightChannelThread.start();

停止

if (null != mLeftChannelThread) {
    mLeftChannelThread.releaseAudioTrack();
    mLeftChannelThread = null;
}
if (null != mRightChannelThread) {
    mRightChannelThread.releaseAudioTrack();
    mRightChannelThread = null;
}

不足

這裏介紹的是在程序中模擬出一個波形滿足正弦波的音頻數據,還有一種方式,可以事先準備好一個這樣的音頻文件,直接播放就可以了。

在程序中模擬音頻數據有一個缺點,就是不能保證兩個線程完完全全的同步,即便是同時開啓兩個線程也有一先一後,在頻率很高的時候,難免會有一點誤差!像下面這樣:

誤差圖

另外,這個波形和硬件有很大關係,越是低配設備,誤差可能會越大,相同的趨勢,但是波動的幅度會比較大(線很粗),可能和設備本身的噪音有關係。

發佈了198 篇原創文章 · 獲贊 281 · 訪問量 87萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章