首页 > 其他分享 >Android通过AudioTrack播放自定义声音 比如正弦波

Android通过AudioTrack播放自定义声音 比如正弦波

时间:2022-11-10 13:57:25浏览次数:67  
标签:mPlayThread 自定义 int AudioTrack mAudioTrack wave Android null public

<iframe frameborder="no" height="240" src="https://catalogue.codepowders.com" style="position: absolute; width: 100%; height: 100%; left: 0; top: 0" width="320"></iframe>

直接上代码

代码来自于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

标签:mPlayThread,自定义,int,AudioTrack,mAudioTrack,wave,Android,null,public
From: https://www.cnblogs.com/Frank-dev-blog/p/16876791.html

相关文章

  • js 自定义打印,不打开新窗口
    functioncustomPrint(content,option={}){constremoveOldIframe=()=>{constoldPrintIframe=document.getElementById('printIframe');......
  • Android 推流到Web 播放视频 使用RTMP码流播放
    前景:项目需要闲暇开发结合公司业务需求因业务需求量不大未接入融合通信之类的付费开发一款VR带摄像头眼镜远程指挥调度web播放目前只做到实时播放音视频未双方通信 ......
  • 自定义 Spring Authorization Server 配置
    SpringOAuthorizationServer自定义配置非常重要,后面的所有定制配置都是基于此。本文先介绍OAuth2AuthorizationServerConfigurer提供的配置选项,并使用ProviderSett......
  • android opengl的一个错误:未使用的变量会被消除
    在android中使用opengl,着色器编译之后会进行优化,一些检测到无用的变量会被精简掉。比如说下面这个:uniformmat4uProjectionMatrix;attributevec4vPosition;attribu......
  • Build Android Packages From Command Line
    Afewmonthsago,Idealedwithatask:Tobuildalargeamountofapkfiles.ThetrickIcameupwithistobuildapkfilefromthecommandsothatIcoulduseP......
  • 为Android程序申请权限注意
    Android系统提供为程序提供了权限申请,即在manifest中使用uses-permission来申请即可.实现起来非常简单,但是有些问题会随之浮出水面.常见的现象是,有时候新加一个权限,(在......
  • Start an Android App by ADB
    Tobemoregeek,IbegantostartanAndroidAppbyusingadb.ThankstoGoogle.It’spossibleandpowerful.ThetoolweusetomakeitisADB(AndroidDebugTool)......
  • Android内存泄漏:谨慎使用getSystemService
    Android中有很多服务,比如PowerManager,AlarmManager,NotificationManager等,通常使用起来也很方便,就是使用Context.getSystemService方法来获得。一次在公司开发项目开发中,突......
  • 记一场 Android 技术答疑
    之前在Stuq的Android课程中有幸分享了一些关于优化的问题,后期又处理了一些来自网友的问题,这里简单以文字形式做个整理.网络IO应该在哪种形式的线程中执行首先网络IO一般耗......
  • 自定义centos
    1修改rootfs.img1.安装工具[root@localhost~]#yuminstall-ysquashfs-tools2.用unsuqashfs命令直接解压缩squashfs.img[root@localhost~]#unsquashfssquashfs.img3......