├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── styles.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── layout
│ │ │ │ └── activity_main.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── drawable
│ │ │ │ └── ic_launcher_background.xml
│ │ ├── java
│ │ │ └── cn
│ │ │ │ └── okfuture
│ │ │ │ └── soundanalysis
│ │ │ │ ├── domain
│ │ │ │ └── Sound.java
│ │ │ │ ├── utils
│ │ │ │ ├── VoiceUtil.java
│ │ │ │ ├── Complex.java
│ │ │ │ ├── FFT.java
│ │ │ │ └── ColorUtils.java
│ │ │ │ ├── thread
│ │ │ │ └── SoundAnalysisThread.java
│ │ │ │ └── activity
│ │ │ │ └── MainActivity.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── cn
│ │ │ └── okfuture
│ │ │ └── soundanalysis
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── cn
│ │ └── okfuture
│ │ └── soundanalysis
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── README.md
├── .gitignore
├── gradle.properties
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SoundAnalysis
2 | android手机实时获取声音频率和大小
3 |
4 | 可以根据声音的频率变换颜色
5 | 可以根据声音的大小变换透明度
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuanxuandaoren/SoundAnalysis/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuanxuandaoren/SoundAnalysis/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuanxuandaoren/SoundAnalysis/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuanxuandaoren/SoundAnalysis/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuanxuandaoren/SoundAnalysis/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuanxuandaoren/SoundAnalysis/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuanxuandaoren/SoundAnalysis/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuanxuandaoren/SoundAnalysis/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuanxuandaoren/SoundAnalysis/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuanxuandaoren/SoundAnalysis/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SoundAnalysis
3 | 开始
4 | 停止
5 | 声音:%1$f 音量:%2$f
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #fff
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/okfuture/soundanalysis/domain/Sound.java:
--------------------------------------------------------------------------------
1 | package cn.okfuture.soundanalysis.domain;
2 |
3 | /**
4 | * 声音信息
5 | * Created by shine on 18-10-10.
6 | */
7 |
8 | public class Sound {
9 | /**
10 | * 频率
11 | */
12 | public double mFrequency;
13 | /**
14 | * 音量
15 | */
16 | public double mVolume;
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/cn/okfuture/soundanalysis/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package cn.okfuture.soundanalysis;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/cn/okfuture/soundanalysis/utils/VoiceUtil.java:
--------------------------------------------------------------------------------
1 | package cn.okfuture.soundanalysis.utils;
2 |
3 | /**
4 | * 声音计算工具类
5 | * Created by shine on 18-10-15.
6 | */
7 |
8 | public class VoiceUtil {
9 | /**
10 | * 获取声音的分贝
11 | *
12 | * @param bufferRead
13 | * @param lenght
14 | * @return
15 | */
16 | public static double getVolume(byte[] bufferRead, int lenght) {
17 | int volume = 0;
18 |
19 | for (int i = 0; i < bufferRead.length; i++) {
20 | volume += bufferRead[i] * bufferRead[i];
21 | }
22 |
23 | double mean = volume / (float) lenght;
24 | return mean;//10 * Math.log10(mean);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/cn/okfuture/soundanalysis/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package cn.okfuture.soundanalysis;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("cn.okfuture.soundanalysis", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
17 |
18 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 26
5 | defaultConfig {
6 | applicationId "cn.okfuture.soundanalysis"
7 | minSdkVersion 19
8 | targetSdkVersion 26
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | buildToolsVersion '28.0.3'
20 | }
21 |
22 | dependencies {
23 | implementation fileTree(include: ['*.jar'], dir: 'libs')
24 | implementation 'com.android.support:appcompat-v7:26.1.0'
25 | implementation 'com.android.support.constraint:constraint-layout:1.1.3'
26 | testImplementation 'junit:junit:4.12'
27 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
28 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/okfuture/soundanalysis/utils/Complex.java:
--------------------------------------------------------------------------------
1 | package cn.okfuture.soundanalysis.utils;
2 |
3 | /**
4 | * 复数
5 | * Created by shine on 18-10-9.
6 | */
7 |
8 | public class Complex {
9 | /**
10 | * 实部
11 | */
12 | private double real;
13 | /**
14 | * 虚部
15 | */
16 | private double image;
17 |
18 |
19 | public Complex() {
20 | this(0.0, 0.0);
21 | }
22 |
23 |
24 | public Complex(double real, double image) {
25 | this.real = real;
26 | this.image = image;
27 | }
28 |
29 | public double getReal() {
30 | return real;
31 | }
32 |
33 | public double getImage() {
34 | return image;
35 | }
36 |
37 |
38 | @Override
39 | public String toString() {
40 | return "Complex{" +
41 | "real=" + real +
42 | ", image=" + image +
43 | '}';
44 | }
45 |
46 | /**
47 | * 加法
48 | *
49 | * @param other
50 | * @return
51 | */
52 | public Complex plus(Complex other) {
53 | return new Complex(getReal() + other.getReal(), getImage() + other.getImage());
54 | }
55 |
56 | /**
57 | * 乘法
58 | *
59 | * @param other
60 | * @return
61 | */
62 | public Complex multiple(Complex other) {
63 | return new Complex(getReal() * other.getReal() - getImage() * other.getImage(), getReal() * other.getImage() + getImage() * other.getReal());
64 | }
65 |
66 | /**
67 | * 减法
68 | *
69 | * @param other
70 | * @return
71 | */
72 | public Complex minus(Complex other) {
73 |
74 | return new Complex(getReal() - other.getReal(), getImage() - other.getImage());
75 | }
76 |
77 | /**
78 | * 求模值
79 | *
80 | * @return
81 | */
82 | public final double getMod() {
83 | return Math.sqrt(this.getReal() * this.getReal() + this.getImage() * this.getImage());
84 | }
85 |
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/okfuture/soundanalysis/utils/FFT.java:
--------------------------------------------------------------------------------
1 | package cn.okfuture.soundanalysis.utils;
2 |
3 | import android.util.Log;
4 |
5 | /**
6 | * 快速傅里叶变换
7 | * Created by shine on 18-10-9.
8 | */
9 |
10 | public class FFT {
11 |
12 | public Complex[] fft(Complex[] x) {
13 | int n = x.length;
14 |
15 | // 因为exp(-2i*n*PI)=1,n=1时递归原点
16 | if (n == 1) {
17 | return x;
18 | }
19 |
20 | // 如果信号数为奇数,使用dft计算
21 | if (n % 2 != 0) {
22 | return dft(x);
23 | }
24 |
25 | // 提取下标为偶数的原始信号值进行递归fft计算
26 | Complex[] even = new Complex[n / 2];
27 | for (int k = 0; k < n / 2; k++) {
28 | even[k] = x[2 * k];
29 | }
30 | Complex[] evenValue = fft(even);
31 |
32 | // 提取下标为奇数的原始信号值进行fft计算
33 | // 节约内存
34 | Complex[] odd = even;
35 | for (int k = 0; k < n / 2; k++) {
36 | odd[k] = x[2 * k + 1];
37 | }
38 | Complex[] oddValue = fft(odd);
39 |
40 | // 偶数+奇数
41 | Complex[] result = new Complex[n];
42 | for (int k = 0; k < n / 2; k++) {
43 | // 使用欧拉公式e^(-i*2pi*k/N) = cos(-2pi*k/N) + i*sin(-2pi*k/N)
44 | double p = -2 * k * Math.PI / n;
45 | Complex m = new Complex(Math.cos(p), Math.sin(p));
46 | result[k] = evenValue[k].plus(m.multiple(oddValue[k]));
47 | // exp(-2*(k+n/2)*PI/n) 相当于 -exp(-2*k*PI/n),其中exp(-n*PI)=-1(欧拉公式);
48 | result[k + n / 2] = evenValue[k].minus(m.multiple(oddValue[k]));
49 | }
50 | return result;
51 | }
52 |
53 | public Complex[] dft(Complex[] x) {
54 | int n = x.length;
55 |
56 | // 1个信号exp(-2i*n*PI)=1
57 | if (n == 1)
58 | return x;
59 |
60 | Complex[] result = new Complex[n];
61 | for (int i = 0; i < n; i++) {
62 | result[i] = new Complex(0, 0);
63 | for (int k = 0; k < n; k++) {
64 | //使用欧拉公式e^(-i*2pi*k/N) = cos(-2pi*k/N) + i*sin(-2pi*k/N)
65 | double p = -2 * k * Math.PI / n;
66 | Complex m = new Complex(Math.cos(p), Math.sin(p));
67 | result[i].plus(x[k].multiple(m));
68 | }
69 | }
70 | return result;
71 | }
72 |
73 | /**
74 | * 获取最大的频率
75 | *
76 | * @param data
77 | * @param SAMPLE_RATE
78 | * @param FFT_N
79 | * @return
80 | */
81 | public double getFrequency(byte[] data, int SAMPLE_RATE, int FFT_N) {
82 |
83 | if (data.length < FFT_N) {
84 | throw new RuntimeException("Data length lower than " + FFT_N);
85 | }
86 | Complex[] f = new Complex[FFT_N];
87 | for (int i = 0; i < FFT_N; i++) {
88 | f[i] = new Complex(data[i], 0); //实部为正弦波FFT_N点采样,赋值为1
89 | //虚部为0
90 | }
91 | String dataStr = "[";
92 | for (int i = 0; i < f.length; i++) {
93 | dataStr += f[i].getReal() + "-" + f[i].getImage() + ", ";
94 | }
95 | dataStr += "]";
96 |
97 | // Log.i("xiaozhu----------before", "data==" + dataStr + ", SAMPLE_RATE==" + SAMPLE_RATE + ", FFT_N" + FFT_N);
98 |
99 | f = fft(f); //进行快速福利叶变换
100 |
101 | dataStr = "[";
102 | for (int i = 0; i < f.length; i++) {
103 | dataStr += f[i].getReal() + "-" + f[i].getImage() + ", ";
104 | }
105 | dataStr += "]";
106 |
107 | // Log.i("xiaozhu----------afters", "data==" + dataStr + ", SAMPLE_RATE==" + SAMPLE_RATE + ", FFT_N" + FFT_N);
108 |
109 |
110 | // String str = "";
111 | // for(int i = 0;i s[fmax])
126 | fmax = i; //计算最大频率的序号值
127 | }
128 | // Log.i("FFT","max index:"+fmax+" fft:"+f[fmax]+" s:"+s[fmax]);
129 | double fre = fmax * (double) SAMPLE_RATE / FFT_N;
130 | Log.i("FFT", "fre:" + fre);
131 | return fre;
132 | }
133 |
134 | }
135 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/okfuture/soundanalysis/utils/ColorUtils.java:
--------------------------------------------------------------------------------
1 | package cn.okfuture.soundanalysis.utils;
2 |
3 | import android.graphics.Color;
4 | import android.util.Log;
5 |
6 | /**
7 | * 颜色工具类
8 | * Created by shine on 18-10-16.
9 | */
10 |
11 | public class ColorUtils {
12 |
13 | /**
14 | * 赤橙黄绿青蓝紫 七原色
15 | */
16 | public static final int[] COLOR_LIST = {0xff0000, 0xFF7D00, 0xFFFF00, 0x00FF00, 0x00FFFF, 0x0000FF, 0xFF00FF, 0xFF0000};
17 | /**
18 | * 渐变色70种
19 | */
20 | public static final int[] COLOR_LIST_70 = {0xffff0000, 0xffff0c00, 0xffff1900, 0xffff2500, 0xffff3200, 0xffff3e00, 0xffff4b00, 0xffff5700, 0xffff6400, 0xffff7000,
21 | 0xffff7d00, 0xffff8a00, 0xffff9700, 0xffffa400, 0xffffb100, 0xffffbe00, 0xffffcb00, 0xffffd800, 0xffffe500, 0xfffff200,
22 | 0xffffff00, 0xffe5ff00, 0xffccff00, 0xffb2ff00, 0xff99ff00, 0xff7fff00, 0xff66ff00, 0xff4cff00, 0xff33ff00, 0xff19ff00,
23 | 0xff00ff00, 0xff00ff19, 0xff00ff33, 0xff00ff4c, 0xff00ff66, 0xff00ff7f, 0xff00ff99, 0xff00ffb2, 0xff00ffcc, 0xff00ffe5,
24 | 0xff00ffff, 0xff00e5ff, 0xff00ccff, 0xff00b2ff, 0xff0099ff, 0xff007fff, 0xff0066ff, 0xff004cff, 0xff0033ff, 0xff0019ff,
25 | 0xff0000ff, 0xff1900ff, 0xff3300ff, 0xff4c00ff, 0xff6600ff, 0xff7f00ff, 0xff9900ff, 0xffb200ff, 0xffcc00ff, 0xffe500ff,
26 | 0xffff00ff, 0xffff00e5, 0xffff00cc, 0xffff00b2, 0xffff0099, 0xffff007f, 0xffff0066, 0xffff004c, 0xffff0033, 0xffff0019};
27 | /**
28 | * 渐变色140种
29 | */
30 | public static final int[] COLOR_LIST_140 = {0xffff0000, 0xffff0600, 0xffff0c00, 0xffff1200, 0xffff1900, 0xffff1f00, 0xffff2500, 0xffff2b00, 0xffff3200, 0xffff3800, 0xffff3e00, 0xffff4400, 0xffff4b00, 0xffff5100, 0xffff5700, 0xffff5d00, 0xffff6400, 0xffff6a00, 0xffff7000, 0xffff7600,
31 | 0xffff7d00, 0xffff8300, 0xffff8a00, 0xffff9000, 0xffff9700, 0xffff9d00, 0xffffa400, 0xffffaa00, 0xffffb100, 0xffffb700, 0xffffbe00, 0xffffc400, 0xffffcb00, 0xffffd100, 0xffffd800, 0xffffde00, 0xffffe500, 0xffffeb00, 0xfffff200, 0xfffff800,
32 | 0xffffff00, 0xfff2ff00, 0xffe5ff00, 0xffd8ff00, 0xffccff00, 0xffbfff00, 0xffb2ff00, 0xffa5ff00, 0xff99ff00, 0xff8cff00, 0xff7fff00, 0xff72ff00, 0xff66ff00, 0xff59ff00, 0xff4cff00, 0xff3fff00, 0xff33ff00, 0xff26ff00, 0xff19ff00, 0xff0cff00,
33 | 0xff00ff00, 0xff00ff0c, 0xff00ff19, 0xff00ff26, 0xff00ff33, 0xff00ff3f, 0xff00ff4c, 0xff00ff59, 0xff00ff66, 0xff00ff72, 0xff00ff7f, 0xff00ff8c, 0xff00ff99, 0xff00ffa5, 0xff00ffb2, 0xff00ffbf, 0xff00ffcc, 0xff00ffd8, 0xff00ffe5, 0xff00fff2,
34 | 0xff00ffff, 0xff00f2ff, 0xff00e5ff, 0xff00d8ff, 0xff00ccff, 0xff00bfff, 0xff00b2ff, 0xff00a5ff, 0xff0099ff, 0xff008cff, 0xff007fff, 0xff0072ff, 0xff0066ff, 0xff0059ff, 0xff004cff, 0xff003fff, 0xff0033ff, 0xff0026ff, 0xff0019ff, 0xff000cff,
35 | 0xff0000ff, 0xff0c00ff, 0xff1900ff, 0xff2600ff, 0xff3300ff, 0xff3f00ff, 0xff4c00ff, 0xff5900ff, 0xff6600ff, 0xff7200ff, 0xff7f00ff, 0xff8c00ff, 0xff9900ff, 0xffa500ff, 0xffb200ff, 0xffbf00ff, 0xffcc00ff, 0xffd800ff, 0xffe500ff, 0xfff200ff,
36 | 0xffff00ff, 0xffff00f2, 0xffff00e5, 0xffff00d8, 0xffff00cc, 0xffff00bf, 0xffff00b2, 0xffff00a5, 0xffff0099, 0xffff008c, 0xffff007f, 0xffff0072, 0xffff0066, 0xffff0059, 0xffff004c, 0xffff003f, 0xffff0033, 0xffff0026, 0xffff0019, 0xffff000c};
37 |
38 | /**
39 | * 获取渐变过程中特定点的颜色
40 | *
41 | * @param startColor 开始的颜色
42 | * @param endColor 结束的颜色
43 | * @param radio 特定比率
44 | * @return 返回特定点的颜色
45 | */
46 | public static int getColor(int startColor, int endColor, float radio) {
47 | int redStart = Color.red(startColor);
48 | int blueStart = Color.blue(startColor);
49 | int greenStart = Color.green(startColor);
50 | int redEnd = Color.red(endColor);
51 | int blueEnd = Color.blue(endColor);
52 | int greenEnd = Color.green(endColor);
53 |
54 | int red = (int) (redStart + ((redEnd - redStart) * radio));
55 | int greed = (int) (greenStart + ((greenEnd - greenStart) * radio));
56 | int blue = (int) (blueStart + ((blueEnd - blueStart) * radio));
57 | return Color.rgb(red, greed, blue);
58 | }
59 |
60 | /**
61 | * 初始化颜色
62 | */
63 | public static void initColors() {
64 | for (int i = 0; i < COLOR_LIST.length - 1; i++) {
65 | String clolrStr = "[";
66 | for (int j = 0; j < 20; j++) {
67 | clolrStr += Integer.toHexString(getColor(COLOR_LIST[i], COLOR_LIST[i + 1], 0.05f * j)) + ",";
68 | }
69 |
70 | clolrStr += "]";
71 |
72 | Log.i("xiaozhu------------", clolrStr);
73 |
74 | }
75 |
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/okfuture/soundanalysis/thread/SoundAnalysisThread.java:
--------------------------------------------------------------------------------
1 | package cn.okfuture.soundanalysis.thread;
2 |
3 | import android.media.AudioFormat;
4 | import android.media.AudioRecord;
5 | import android.media.MediaRecorder;
6 | import android.os.Handler;
7 | import android.os.Message;
8 | import android.util.Log;
9 |
10 | import cn.okfuture.soundanalysis.activity.MainActivity;
11 | import cn.okfuture.soundanalysis.domain.Sound;
12 | import cn.okfuture.soundanalysis.utils.ColorUtils;
13 | import cn.okfuture.soundanalysis.utils.FFT;
14 | import cn.okfuture.soundanalysis.utils.VoiceUtil;
15 |
16 | /**
17 | * 声音分析工具
18 | * Created by shine on 18-10-10.
19 | */
20 |
21 | public class SoundAnalysisThread extends Thread {
22 | /**
23 | * 线程通讯的handler
24 | */
25 | private Handler handler;
26 | /**
27 | * 傅里叶变化工具类
28 | */
29 | private FFT fft = new FFT();
30 |
31 | /**
32 | * 可能存在的采样频率
33 | */
34 | private static final int[] SAMPLE_RATES_LIST = {11025, 8000, 22050, 44100, 16000};
35 | /**
36 | * 采样频率对应的采样点数
37 | */
38 | private static final int[] SAMPLE_COUNT = {8 * 1024,
39 | 4 * 1024, 16 * 1024, 32 * 1024, 8 * 1024};
40 | /**
41 | * 采样频率
42 | */
43 | private int sampleRate = 44100;
44 | /**
45 | * 采样点数
46 | */
47 | private int sampleCount = 32 * 1024;
48 | /**
49 | * 声音的信息
50 | */
51 | private Sound sound = new Sound();
52 | /**
53 | * 当前的频率
54 | */
55 | private double currentFrequency;
56 | /**
57 | * 当前的声音
58 | */
59 | private double currentVolume;
60 | /**
61 | * 声音采集频率
62 | */
63 | private AudioRecord audioRecord;
64 |
65 | public SoundAnalysisThread(Handler handler) {
66 |
67 | this.handler = handler;
68 | initAudioRecord();
69 | // ColorUtils.initColors();
70 | }
71 |
72 | /**
73 | * 初始化
74 | */
75 | private void initAudioRecord() {
76 | Log.i("xiaozhu----------", "initAudioRecord");
77 | for (int i = 0; i < SAMPLE_RATES_LIST.length; i++) {
78 |
79 | audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATES_LIST[i],
80 | AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, AudioRecord.getMinBufferSize(SAMPLE_RATES_LIST[i],
81 | AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT));
82 |
83 | Log.i("xiaozhu----------", "STATE_INITIALIZED" + audioRecord.getState());
84 | if (audioRecord.getState() == AudioRecord.STATE_INITIALIZED) {
85 | Log.i("xiaozhu----------", "STATE_INITIALIZED");
86 | sampleRate = SAMPLE_RATES_LIST[i];
87 | sampleCount = 1024;//SAMPLE_COUNT[i];
88 | break;
89 | }
90 | }
91 |
92 | }
93 |
94 | @Override
95 | public void run() {
96 | super.run();
97 | Log.i("xiaozhu----------", "run" + sampleCount);
98 | audioRecord.startRecording();
99 | byte[] bufferRead = new byte[sampleCount];
100 | int lenght;
101 |
102 | while ((lenght = audioRecord.read(bufferRead, 0, sampleCount)) > 0) {
103 |
104 | currentFrequency = fft.getFrequency(bufferRead, sampleRate, sampleCount);
105 | currentVolume = VoiceUtil.getVolume(bufferRead, lenght);
106 |
107 |
108 | sound.mFrequency = currentFrequency;
109 | sound.mVolume = currentVolume;
110 | Message message = Message.obtain();
111 | message.obj = sound;
112 | message.what = MainActivity.SOUND_MESSAGE;
113 |
114 | handler.sendMessage(message);
115 |
116 | Log.i("xiaozhu----------", "currentFrequency" + currentFrequency + "---" + currentVolume);
117 | if (currentFrequency > 0) {
118 |
119 |
120 | try {
121 | if (audioRecord.getState() == AudioRecord.STATE_INITIALIZED) {
122 | audioRecord.stop();
123 | }
124 | Thread.sleep(20);
125 | if (audioRecord.getState() == AudioRecord.STATE_INITIALIZED) {
126 | audioRecord.startRecording();
127 | }
128 | } catch (InterruptedException e) {
129 | e.printStackTrace();
130 | }
131 | }
132 | }
133 | }
134 |
135 | /**
136 | * 停止解析
137 | */
138 | public void close() {
139 | if (audioRecord != null && audioRecord.getState() == AudioRecord.STATE_INITIALIZED) {
140 | audioRecord.stop();
141 | audioRecord.release();
142 | }
143 |
144 | }
145 | }
146 |
147 |
148 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/okfuture/soundanalysis/activity/MainActivity.java:
--------------------------------------------------------------------------------
1 | package cn.okfuture.soundanalysis.activity;
2 |
3 | import android.Manifest;
4 | import android.content.pm.PackageManager;
5 | import android.graphics.Color;
6 | import android.os.Bundle;
7 | import android.os.Handler;
8 | import android.os.Message;
9 | import android.support.annotation.NonNull;
10 | import android.support.v4.app.ActivityCompat;
11 | import android.support.v4.content.ContextCompat;
12 | import android.support.v7.app.AppCompatActivity;
13 | import android.view.View;
14 | import android.widget.Button;
15 | import android.widget.LinearLayout;
16 | import android.widget.TextView;
17 |
18 | import cn.okfuture.soundanalysis.R;
19 | import cn.okfuture.soundanalysis.domain.Sound;
20 | import cn.okfuture.soundanalysis.thread.SoundAnalysisThread;
21 | import cn.okfuture.soundanalysis.utils.ColorUtils;
22 |
23 | public class MainActivity extends AppCompatActivity implements View.OnClickListener {
24 | /**
25 | * 声音请求权限信息
26 | */
27 | private static final int PERMISSION_AUDIORECORD = 2;
28 | /**
29 | * 音乐跳变临界点
30 | */
31 | private static final int FREQUENCY_CRITICAL = 500;
32 | /**
33 | * 最大的声音
34 | */
35 | private static final double MAX_SOUND = 3000;
36 |
37 | /**
38 | * 声音信息
39 | */
40 | public static int SOUND_MESSAGE = 1;
41 |
42 | /**
43 | * 采集声音开关
44 | */
45 | private Button btn_start;
46 | /**
47 | * 展示结果
48 | */
49 | private TextView tv_show;
50 | /**
51 | * 声音分析
52 | */
53 | private SoundAnalysisThread soundAnalysisThread;
54 | /**
55 | * 当前的频率
56 | */
57 |
58 | private int currentFrequency;
59 |
60 | /**
61 | * 线程之间通讯
62 | */
63 | private Handler handler = new Handler() {
64 | @Override
65 | public void handleMessage(Message msg) {
66 | super.handleMessage(msg);
67 | switch (msg.what) {
68 | case 1:
69 | Sound sound = (Sound) msg.obj;
70 | updateBackground(sound);
71 | break;
72 | }
73 | }
74 | };
75 | private LinearLayout ll_content;
76 |
77 | /**
78 | * 更新背景
79 | *
80 | * @param sound
81 | */
82 | private void updateBackground(Sound sound) {
83 | int frequency = (int) sound.mFrequency;
84 |
85 | if (frequency <= 0) {
86 | return;
87 | } else if (Math.abs(frequency - currentFrequency) < FREQUENCY_CRITICAL) {
88 | currentFrequency++;
89 | } else {
90 | currentFrequency = frequency;
91 | }
92 |
93 | int alpha = (int) (255 * sound.mVolume / MAX_SOUND);
94 | if (alpha > 255) {
95 | alpha = 255;
96 | }
97 | int color = ColorUtils.COLOR_LIST_140[currentFrequency % 140];
98 | ll_content.setBackgroundColor(Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color)));
99 |
100 | tv_show.setText(String.format(getString(R.string.show_sound), currentFrequency * 1.0f, sound.mVolume));
101 |
102 | }
103 |
104 |
105 | @Override
106 | protected void onCreate(Bundle savedInstanceState) {
107 | super.onCreate(savedInstanceState);
108 | setContentView(R.layout.activity_main);
109 | initView();
110 | }
111 |
112 | private void initView() {
113 | btn_start = (Button) findViewById(R.id.btn_start);
114 | tv_show = (TextView) findViewById(R.id.tv_show);
115 |
116 | btn_start.setOnClickListener(this);
117 | ll_content = (LinearLayout) findViewById(R.id.ll_content);
118 | ll_content.setOnClickListener(this);
119 | }
120 |
121 | @Override
122 | public void onClick(View v) {
123 | switch (v.getId()) {
124 | case R.id.btn_start:
125 | if (btn_start.isSelected()) {
126 | btn_start.setText(R.string.start);
127 | btn_start.setSelected(false);
128 | stopAnalysis();
129 |
130 | } else {
131 | btn_start.setText(R.string.stop);
132 | btn_start.setSelected(true);
133 | //判断是否有权限
134 | if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
135 | //如果应用之前请求过此权限但用户拒绝的请求 ,此方法返回true
136 | if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
137 | //这里可以写个对话框之类的项向用户解释为什么要申请权限,并在对话框的确认键后续再次申请权限
138 | } else {
139 | ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, PERMISSION_AUDIORECORD);
140 | }
141 |
142 | } else {
143 | startAnalysis();
144 | }
145 |
146 | }
147 |
148 | break;
149 | }
150 | }
151 |
152 | @Override
153 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
154 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
155 | if (requestCode == PERMISSION_AUDIORECORD) {
156 | for (int i = 0; i < permissions.length; i++) {
157 | if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
158 | startAnalysis();
159 | }
160 |
161 | }
162 | }
163 | }
164 |
165 | /**
166 | * 开始采集
167 | */
168 | private void startAnalysis() {
169 |
170 | soundAnalysisThread = new SoundAnalysisThread(handler);
171 | soundAnalysisThread.start();
172 | }
173 |
174 | /**
175 | * 停止采集音频
176 | */
177 | private void stopAnalysis() {
178 | if (soundAnalysisThread != null) {
179 | soundAnalysisThread.close();
180 | }
181 |
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------