Android通过AudioTrack播放自定义声音 比如正弦波
直接上代码
代码来自于https://github.com/xiaoniu/PureTone
FMCW这种经常要自定义指定函数的声音,就可以改改函数就可以直接用这里用的是sin
public class SinWave { /** 正弦波的高度 2的8次方减1**/ public static final int HEIGHT = 127; /** 2PI **/ public static final double TWOPI = 2 * 3.1415; /** * 生成正弦波 * * @param wave * @param waveLen * 每段正弦波的长度 * @param length * 总长度 * @return */ public static byte[] sin(byte[] wave, int waveLen, int length) { for (int i = 0; i < length; i++) { wave[i] = (byte) (HEIGHT * (1 - Math.sin(TWOPI * ((i % waveLen) * 1.00 / waveLen)))); } return wave; } }
PlayThread
import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioTrack; public class PlayThread extends Thread { public static final int RATE = 44100; AudioTrack mAudioTrack; public static boolean ISPLAYSOUND; /** * 总长度 **/ int length; /** * 一个正弦波的长度 **/ int waveLen; /** * 频率 **/ int Hz; /** * 正弦波 **/ byte[] wave; /** * 初始化 * @param rate 频率 */ public PlayThread(int rate) { if (rate > 0) { Hz = rate; waveLen = RATE / Hz; length = waveLen * Hz; wave = new byte[RATE]; mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, RATE, AudioFormat.CHANNEL_CONFIGURATION_STEREO, // CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_8BIT, length, AudioTrack.MODE_STREAM); ISPLAYSOUND = true; wave = SinWave.sin(wave, waveLen, length); } else { return; } } @Override public void run() { super.run(); if (null != mAudioTrack) mAudioTrack.play(); //一直播放 while (ISPLAYSOUND) { mAudioTrack.write(wave, 0, length); } } /** * 设置左右声道,左声道时设置右声道音量为0,右声道设置左声道音量为0 * * @param left 左声道 * @param right 右声道 */ public void setChannel(boolean left, boolean right) { if (null != mAudioTrack) { mAudioTrack.setStereoVolume(left ? 1 : 0, right ? 1 : 0); } } //设置音量 public void setVolume(float left, float right) { if (null != mAudioTrack) { mAudioTrack.setStereoVolume(left,right); } } public void stopPlay() { ISPLAYSOUND = false; releaseAudioTrack(); } private void releaseAudioTrack() { if (null != mAudioTrack) { mAudioTrack.stop(); mAudioTrack.release(); mAudioTrack = null; } } }
MainActivity
import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.KeyEvent; import android.view.View; import android.widget.Button; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private PlayThread mPlayThread; Button btnPlay; Button btnLeft; Button btnRight; Button btnStop; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnPlay = (Button) findViewById(R.id.btn_play); btnLeft = (Button) findViewById(R.id.btn_left); btnRight = (Button) findViewById(R.id.btn_right); btnStop = (Button) findViewById(R.id.btn_stop); btnPlay.setOnClickListener(this); btnLeft.setOnClickListener(this); btnRight.setOnClickListener(this); btnStop.setOnClickListener(this); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { this.finish(); if (null != mPlayThread) { mPlayThread.stopPlay(); mPlayThread = null; } } return super.onKeyDown(keyCode, event); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.btn_play: playSound(true, true); break; case R.id.btn_left: playSound(true, false); break; case R.id.btn_right: playSound(false, true); break; case R.id.btn_stop: if (null != mPlayThread) { mPlayThread.stopPlay(); mPlayThread = null; } break; } } private void playSound(boolean left, boolean right) { if (null != mPlayThread) { mPlayThread.stopPlay(); mPlayThread = null; } mPlayThread = new PlayThread(2); mPlayThread.setChannel(left, right); mPlayThread.start(); } }
XML
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <Button android:id="@+id/btn_play" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="双声道播放" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/btn_left" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="左声道播放" /> <Button android:id="@+id/btn_right" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="右声道播放" /> </LinearLayout> <Button android:id="@+id/btn_stop" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="停止播放" /> </LinearLayout>
GitHub地址 下载前给star