綁定帳號登入

Android 台灣中文網

打印 上一主題 下一主題

[原創] 固定頻率聲音輸出

[複製連結] 查看: 29053|回覆: 1|好評: 0
跳轉到指定樓層
樓主
jianrupan | 收聽TA | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
發表於 2020-10-21 17:35

馬上加入Android 台灣中文網,立即免費下載應用遊戲。

您需要 登錄 才可以下載或查看,沒有帳號?註冊

x
驗證程序
sineWave.SetRate(440, 3);                // db 自動轉為負值
sineWave.SetVolume((float)0.5);        // 注意波形變形
sineWave.Start();
sineWave.Play();

// 固定聲音頻率輸出
public class SineWaveGenerator {
    // 採樣頻率
    private int RATE = 44100;

    private final int LEFT = 1;
    private final int RIGHT = 2;
    private final int DOUBLE = 3;
    // 輸出頻率
    private int Hz;
    // 輸出分貝
    private int dB = 0;
    // 輸出音量
    private float volume;

    AudioTrack audioTrack;
    // 輸出聲道
    private int channel;
    // 資料長度
    private int length;
    // 一個正弦波長度
    private int waveLen;
    // 正弦波資料陣列
    private byte[] wave;

    public SineWaveGenerator() {
        wave = new byte[RATE];
    }
       
   // 音量設定
    public void SetVolume(float v) {
        volume = v;
    }

    // 頻率分貝設定
    public void SetRate(int hz, int db) {
        this.Hz = hz;
        this.dB = db;
        updateDB(db);
    }
       
   // 啟動播放
    public void Start() {
        start(DOUBLE);
    }


    // 啟動播放
    // @param channel 左, 右, 立體
    private void start(int channel) {
        Stop();
        if (Hz > 0) {
            waveLen = (RATE/Hz)*2;        // 實測 頻率 為 Hz/2(440Hz=440/2)
            length = waveLen * Hz;
            audioTrack = new AudioTrack(        AudioManager.STREAM_MUSIC,                // streamType
                                                                RATE,                                                // sampleRateInHz
                                                                    AudioFormat.CHANNEL_OUT_STEREO, // channelConfig
                                                                    AudioFormat.ENCODING_PCM_8BIT,        // audioFormat
                                                                    length,                                                        // bufferSizeInBytes
                                                                    AudioTrack.MODE_STREAM                        // mode
                                                                    );
            // 聲道音量
            switch (channel) {
                case LEFT:
                    audioTrack.setStereoVolume(volume, 0f);
                    break;
                case RIGHT:
                    audioTrack.setStereoVolume(0f, volume);
                    break;
                case DOUBLE:
                    audioTrack.setStereoVolume(volume, volume);
                    break;
            }
            // 生成正弦波
            wave = sineWave(waveLen, length);
            if (audioTrack != null) {
                audioTrack.play();
            }
        } else {
            return;
        }

    }

    private boolean isRun = false;
    private boolean isStop = true;

    // 開始播放(寫入數據)
    public void Play() {
        isRun = true;
        isStop = false;
        if (audioTrack != null) {
            new Thread(new Runnable() {
                                @Override
                                public void run() {
                                        while(isRun)
                                                audioTrack.write(wave, 0, length);
                                        isStop = true;
                                }
                        }).start();
        }
    }

    // 停止播放
    public void Stop() {
        isRun = false;
        try {
            int limitCnt = 0;
                while(!isStop)
                {
                        limitCnt++;
                        if(limitCnt > 1000)
                                break;
                    Thread.sleep(1);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        isStop = true;
        if (audioTrack != null) {
            audioTrack.stop();
            audioTrack.release();
            audioTrack = null;
        }
    }

    // 取得播放狀態
    public boolean GetRunStatus() {
                return isRun;
        }       
       
    // 正弦波的高度
    private final int ampMax = 127;        // 8Bit編碼, 振幅最大 127
    private int HEIGHT = ampMax;
    // 2PI
    private final double TWOPI = 2*Math.PI;

    // 生成正弦波
    // @param waveLen 每段正弦波的長度
    // @param length 總長度
    // @return
    private byte[] sineWave(int waveLen, int length) {
        byte[] bWave = new byte[length];
        for(int i=0; i<length; i++)
            bWave = (byte)(HEIGHT*(1-Math.sin(TWOPI*((i%waveLen)*1.00/waveLen))));
        return bWave;
    }

    // 更新聲音的分貝
    // @param dB
    public void updateDB(double dB) {
        // db 自動轉為負值
        if(dB > 0)
                dB = 0-dB;
        // 10 的 **次方
        HEIGHT = (int)(ampMax*Math.pow(10.0, dB/10));
    }
}


「用Android 就來APK.TW」,快來加入粉絲吧!
Android 台灣中文網(APK.TW)
收藏收藏 分享分享 分享專題
用Android 就來Android 台灣中文網(https://apk.tw)
回覆

使用道具 舉報

沙發
johngameboy | 收聽TA | 只看該作者
發表於 2021-8-3 18:08
正弦波資料陣列更新聲音的分貝
用Android 就來Android 台灣中文網(https://apk.tw)
回覆 支持 反對

使用道具 舉報

您需要登錄後才可以回帖 登錄 | 註冊

本版積分規則