├── .gitignore ├── .idea ├── .gitignore ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── gradle.xml ├── misc.xml └── runConfigurations.xml ├── README.md ├── app ├── .gitignore ├── ReadMe.txt ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── free │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── free │ │ │ ├── Activity1.java │ │ │ ├── ChoiceActivity.java │ │ │ ├── Classes │ │ │ ├── ActivityCollector.java │ │ │ ├── BaseActivity.java │ │ │ ├── EachButton.java │ │ │ ├── FFT.java │ │ │ ├── HandleData.java │ │ │ ├── LandEachButton.java │ │ │ ├── MP3ToWav.java │ │ │ ├── MP3ToWav1.java │ │ │ ├── Music.java │ │ │ └── MusicAdapter.java │ │ │ ├── FourGameActivity.java │ │ │ ├── GameActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── Mp3Handle │ │ │ ├── FrameData.java │ │ │ ├── Mp3FileReader.java │ │ │ └── MyMp3FileReader.java │ │ │ ├── MusicActivity.java │ │ │ ├── MusicViewActivity.java │ │ │ ├── OriginChoiceActivity.java │ │ │ ├── ResultActivity.java │ │ │ └── WavHandle │ │ │ └── WaveFileReader.java │ └── res │ │ ├── anim │ │ └── anim.xml │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── _b2.jpg │ │ ├── _note.jpg │ │ ├── _r3.jpg │ │ ├── b1.jpg │ │ ├── b_bottom.jpg │ │ ├── background_auto.xml │ │ ├── ic_launcher_background.xml │ │ ├── r2.jpg │ │ ├── r4.jpg │ │ └── shape.xml │ │ ├── layout-land │ │ └── activity_four_game.xml │ │ ├── layout │ │ ├── activity_1.xml │ │ ├── activity_choice.xml │ │ ├── activity_game.xml │ │ ├── activity_main.xml │ │ ├── activity_music.xml │ │ ├── activity_music_view.xml │ │ ├── activity_origin_choice.xml │ │ ├── activity_result.xml │ │ ├── music_item.xml │ │ ├── toast.xml │ │ └── toast_land.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── 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 │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── example │ └── free │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Free 2 | 一个自动识别音乐节奏点的仿节奏大师音游 3 | 4 | 功能:Free App仿照节奏大师的音游模式,大致实现读取本地音乐,自动识别节奏点并进行游戏的功能。 5 | 6 | 代码注释链接:https://blog.csdn.net/qq_43533416/article/details/105631991 7 | 8 | 备注:此APP为Android开发课程的大作业,背景图片来自网图非原创,未曾商用。 9 | 因为本人不是信号通信专业方向,节奏点的识别不够特别精确,尤其是有压缩的mp3文件,且能执行的音乐文件可能受大小限制,如果以后有机会会进行改良。 10 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/ReadMe.txt: -------------------------------------------------------------------------------- 1 | 功能:Free App仿照节奏大师的音游模式,大致实现读取本地音乐,自动识别节奏点并进行游戏的功能。 2 | 3 | 代码注释链接:https://blog.csdn.net/qq_43533416/article/details/105631991 4 | 5 | 备注:此APP为Android开发课程的大作业,背景图片来自网图非原创,未曾商用。 6 | 因为本人不是信号通信专业方向,节奏点的识别不够特别精确,尤其是有压缩的mp3文件,且能执行的音乐文件可能受大小限制,如果以后有机会会进行改良。 -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 29 5 | buildToolsVersion "29.0.2" 6 | defaultConfig { 7 | applicationId "com.example.free" 8 | minSdkVersion 24 9 | targetSdkVersion 29 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | implementation fileTree(dir: 'libs', include: ['*.jar']) 24 | implementation 'androidx.appcompat:appcompat:1.0.2' 25 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 26 | testImplementation 'junit:junit:4.12' 27 | androidTestImplementation 'androidx.test:runner:1.1.1' 28 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' 29 | 30 | implementation 'com.android.support:recyclerview-v7:29.0.2' 31 | 32 | } 33 | -------------------------------------------------------------------------------- /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/androidTest/java/com/example/free/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.example.free; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | 25 | assertEquals("com.example.free", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 14 | 18 | 19 | 20 | 23 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/free/Activity1.java: -------------------------------------------------------------------------------- 1 | package com.example.free; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.appcompat.app.AppCompatActivity; 5 | import androidx.constraintlayout.widget.ConstraintLayout; 6 | 7 | import android.animation.ObjectAnimator; 8 | import android.app.Activity; 9 | import android.content.Context; 10 | import android.graphics.Color; 11 | import android.os.Bundle; 12 | import android.os.Handler; 13 | import android.os.Message; 14 | import android.util.Log; 15 | import android.util.Property; 16 | import android.view.LayoutInflater; 17 | import android.view.View; 18 | import android.view.animation.AnimationUtils; 19 | import android.widget.Button; 20 | import android.widget.LinearLayout; 21 | import android.widget.TextView; 22 | import android.widget.Toast; 23 | 24 | import org.w3c.dom.Text; 25 | 26 | import java.util.ArrayList; 27 | import java.util.Queue; 28 | 29 | import javax.xml.datatype.Duration; 30 | 31 | public class Activity1 extends AppCompatActivity { 32 | // 33 | // //EachButton eachButton1=null;//每个轨道的按钮list都放在数据域里 34 | // Button button_bottom; 35 | // int height; 36 | // ConstraintLayout constraintLayout; 37 | // static Toast toast; 38 | // 39 | // static ArrayList buttons=new ArrayList(); 40 | // 41 | // @Override 42 | // protected void onCreate(Bundle savedInstanceState) { 43 | // super.onCreate(savedInstanceState); 44 | // setContentView(R.layout.activity_1); 45 | // 46 | // int width=getWindowManager().getDefaultDisplay().getWidth(); 47 | // int height=getWindowManager().getDefaultDisplay().getHeight(); 48 | // Button test1=findViewById(R.id.test_bottom1); 49 | // Button test2=findViewById(R.id.test_bottom2); 50 | // test1.setText(width+""); 51 | // test2.setText(height+""); 52 | // } 53 | // 54 | // constraintLayout=findViewById(R.id.constraintLayout); 55 | // EachButton eachButton1=new EachButton(getApplicationContext(),200,0,200,1300,0,2000); 56 | // eachButton1.setText("here1"); 57 | // 58 | // height=eachButton1.height; 59 | // 60 | // //Toast.makeText(Activity1.this,"button1",Toast.LENGTH_SHORT).show(); 61 | // //linearLayout.addView(eachButton1); 62 | // eachButton1.start(constraintLayout); 63 | // 64 | //// eachButton1.setOnClickListener(new View.OnClickListener() { 65 | //// @Override 66 | //// public void onClick(View v) { 67 | //// Toast.makeText(Activity1.this,eachButton1.getY()+"",Toast.LENGTH_SHORT).show(); 68 | //// } 69 | //// });//button实际的布局位置没变,只是显示变了,点击原位置仍可以有事件响应 70 | // 71 | // EachButton eachButton2=new EachButton(getApplicationContext(),400,0 ,400,1200,500,2000,0); 72 | // eachButton2.setText("here2"); 73 | // //linearLayout.addView(eachButton2); 74 | // eachButton2.start(constraintLayout); 75 | // 76 | // EachButton eachButton3=new EachButton(getApplicationContext(),600,0,600,1200,700,2000); 77 | // eachButton3.setText("here3"); 78 | // //linearLayout.addView(eachButton3); 79 | // eachButton3.start(constraintLayout); 80 | // 81 | // buttons.add(eachButton1); 82 | // buttons.add(eachButton2); 83 | // buttons.add(eachButton3); 84 | // 85 | // Toast.makeText(getApplicationContext(),buttons.size()+"",Toast.LENGTH_SHORT).show(); 86 | // 87 | // toast=new Toast(getApplicationContext()); 88 | // //toast.show(); 89 | // 90 | // 91 | // 92 | // button_bottom=findViewById(R.id.button_bottom); 93 | // button_bottom.setOnClickListener(new View.OnClickListener() { 94 | // @Override 95 | // public void onClick(View v) { 96 | // EachButton button=null; 97 | // try { 98 | // Toast.makeText(Activity1.this,buttons.size()+"",Toast.LENGTH_SHORT).show(); 99 | // if (buttons.size() > 0) 100 | // button = buttons.get(0); 101 | // } 102 | // catch(Exception e){ 103 | // e.printStackTrace(); 104 | // } 105 | // 106 | // //Toast.makeText(Activity1.this,"here click",Toast.LENGTH_SHORT).show(); 107 | // Log.d("testToast","here"); 108 | // Context context=getApplicationContext(); 109 | // View view =LayoutInflater.from(context).inflate(R.layout.toast, null); 110 | // //不然如果后面用setView(findViewById()),AppCompatActivity.findViewById()是无法识别的,会出错 111 | // /*LayoutInflater这个类的作用类似于findViewById()。 112 | // 不同点是LayoutInflater是用来找res/layout/下的xml布局文件,并且实例化; 113 | // 而findViewById()是找xml布局文件下的具体widget控件(如Button、TextView等)。 114 | // */ 115 | // 116 | // toast.cancel();//让上一个取消,不然新的toast放不上去 117 | // 118 | // 119 | // 120 | // 121 | // //float buttonY=getButtonY(); 122 | // //int[] location=new int[2]; 123 | // //eachButton1.getLocationOnScreen(location); 124 | // //eachButton1.getLocationOnScreen(location); 125 | // TextView textView=view.findViewById(R.id.textView); 126 | // 127 | // /* 128 | // ObjectAnimator textAnimator=ObjectAnimator 129 | // .ofFloat(textView,"translationY", textView.getY(), textView.getY()+300) 130 | // .setDuration(1000);*/ 131 | // 132 | // int d=(int)(button_bottom.getY()-button.getY()); 133 | // if((d>-height&&d<-height/2)||(dheight/2)) { 134 | // textView.setText("good"); 135 | // //textView.setTextColor(getResources().getColor(R.color.colorLightGreen)); 136 | // constraintLayout.removeView(button); 137 | // buttons.remove(0); 138 | // button.state=false; 139 | // button.animator.cancel();//这里要取消动画,不然虽然视图里的button消失了,但button对象还在,动画还会继续执行 140 | // //button.viewRemoveButton(constraintLayout); 141 | // 142 | // ObjectAnimator.ofArgb(textView, "textColor", 143 | // Color.parseColor("#ff1B8A22"), 144 | // Color.parseColor("#001B8A22")) 145 | // .setDuration(1000) 146 | // .start(); 147 | // } 148 | // else { 149 | // if(d<=height/2&&d>=-height/2){ 150 | // textView.setText("best"); 151 | // //textView.setTextColor(getResources().getColor(R.color.colorLightBlue)); 152 | // constraintLayout.removeView(button); 153 | // buttons.remove(0); 154 | // button.state=false; 155 | // button.animator.cancel(); 156 | // //button.viewRemoveButton(constraintLayout); 157 | // 158 | // ObjectAnimator.ofArgb(textView, "textColor", 159 | // Color.parseColor("#ff00bfff"), 160 | // Color.parseColor("#0000bfff")) 161 | // .setDuration(1000) 162 | // .start(); 163 | // } 164 | // else{ 165 | // textView.setText(""); 166 | // } 167 | // } 168 | // 169 | // 170 | // //textView.setText(location[1]+" "+eachButton1.getY()+" "+button_bottom.getY());//getTop()得到的是控件距离父级的top的距离 171 | // toast=new Toast(context); 172 | // //LinearLayout toastView=(LinearLayout)toast.getView(); 173 | // toast.setView(view); 174 | // Log.d("testToast","here1"); 175 | // toast.setDuration(Toast.LENGTH_SHORT); 176 | // 177 | // view.animate().translationY(50) 178 | // .setDuration(1000); 179 | // 180 | // 181 | // toast.show(); 182 | // 183 | // } 184 | // }); 185 | // 186 | // /* 187 | // EachButton eachButton4=new EachButton(getApplicationContext(),300,0,300,500,500,3000); 188 | // eachButton3.setText("here3"); 189 | // //linearLayout.addView(eachButton3); 190 | // //eachButton3.start(linearLayout); 191 | // 192 | // new Handler(new Handler.Callback() { 193 | // //不能动态设置开始时间 194 | // @Override 195 | // public boolean handleMessage(@NonNull Message msg) { 196 | // findViewById(R.id.textView).startAnimation(AnimationUtils.loadAnimation(getApplicationContext(),+R.anim.anim)); 197 | // return false; 198 | // } 199 | // }).sendEmptyMessageDelayed(0,2000);*/ 200 | // } 201 | // 202 | //// public float getButtonY(){ 203 | //// return eachButton1.getTranslationY(); 204 | //// } 205 | 206 | } 207 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/free/ChoiceActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.free; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.view.View; 8 | import android.widget.Button; 9 | import android.widget.EditText; 10 | import android.widget.ProgressBar; 11 | import android.widget.Toast; 12 | 13 | import com.example.free.Classes.BaseActivity; 14 | 15 | public class ChoiceActivity extends BaseActivity { 16 | 17 | 18 | String musicPath; 19 | long musicSize; 20 | long musicTime; 21 | 22 | 23 | EditText window; 24 | EditText window_size; 25 | EditText multiplier; 26 | EditText duration; 27 | EditText roads; 28 | @Override 29 | protected void onCreate(Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.activity_choice); 32 | 33 | setTitle("高级设置"); 34 | 35 | Intent intent=getIntent(); 36 | musicPath=intent.getStringExtra("musicPath"); 37 | musicSize=intent.getLongExtra("musicSize",0); 38 | musicTime=intent.getLongExtra("musicTime",0); 39 | 40 | 41 | window=findViewById(R.id.window); 42 | window_size=findViewById(R.id.window_size); 43 | multiplier=findViewById(R.id.multiplier); 44 | duration=findViewById(R.id.duration); 45 | roads=findViewById(R.id.roads); 46 | 47 | Button click=findViewById(R.id.click); 48 | click.setOnClickListener(new View.OnClickListener() { 49 | @Override 50 | public void onClick(View v) { 51 | 52 | // ProgressBar progressBar=findViewById(R.id.progressBar1); 53 | // progressBar.setVisibility(View.VISIBLE); 54 | 55 | int windowInt=1024; 56 | int windowSizeInt=20; 57 | double multiplierDouble=1.5; 58 | int blockDuration=1000; 59 | int roadsCount=2; 60 | 61 | String s1=(window.getText()+"").trim(); 62 | if(!s1.equals("")) 63 | windowInt=Integer.parseInt(s1); 64 | 65 | String s2=(window_size.getText()+"").trim(); 66 | if(!s2.equals("")) 67 | windowSizeInt=Integer.parseInt(s2); 68 | 69 | String s3=(multiplier.getText()+"").trim(); 70 | if(!s3.equals("")) 71 | multiplierDouble=Double.parseDouble(s3); 72 | 73 | String s4=(duration.getText()+"").trim(); 74 | if(!s4.equals("")) 75 | blockDuration=Integer.parseInt(s4); 76 | 77 | String s5=(roads.getText()+"").trim(); 78 | if(!s5.equals("")) 79 | roadsCount=Integer.parseInt(s5); 80 | 81 | Intent intent1; 82 | if(roadsCount==4) 83 | intent1=new Intent(getApplicationContext(),FourGameActivity.class); 84 | else 85 | intent1=new Intent(getApplicationContext(),GameActivity.class); 86 | 87 | intent1.putExtra("className","ChoiceActivity");//getClass().getName()带有根底 88 | // Toast.makeText(getApplicationContext(),getClass().getName(),Toast.LENGTH_SHORT).show(); 89 | intent1.putExtra("window",windowInt); 90 | intent1.putExtra("windowSize",windowSizeInt); 91 | intent1.putExtra("multiplier",multiplierDouble); 92 | intent1.putExtra("duration",blockDuration); 93 | intent1.putExtra("musicPath",musicPath); 94 | intent1.putExtra("musicSize", musicSize); 95 | intent1.putExtra("musicTime",musicTime); 96 | startActivity(intent1); 97 | 98 | 99 | } 100 | }); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/free/Classes/ActivityCollector.java: -------------------------------------------------------------------------------- 1 | package com.example.free.Classes; 2 | 3 | import android.app.Activity; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class ActivityCollector { 9 | public static List activities=new ArrayList<>(); 10 | 11 | public static void addActivity(Activity activity){ 12 | activities.add(activity); 13 | } 14 | public static void removeActivity(Activity activity){ 15 | activities.remove(activity); 16 | } 17 | public static void finishAll(){ 18 | for(Activity activity:activities){ 19 | if(!activity.isFinishing()) 20 | activity.finish(); 21 | } 22 | activities.clear(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/free/Classes/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.free.Classes; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.content.IntentFilter; 7 | import android.os.Bundle; 8 | 9 | import androidx.annotation.Nullable; 10 | import androidx.appcompat.app.AppCompatActivity; 11 | 12 | import com.example.free.MainActivity; 13 | 14 | public class BaseActivity extends AppCompatActivity { 15 | 16 | @Override 17 | protected void onCreate(@Nullable Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | ActivityCollector.addActivity(this); 20 | } 21 | 22 | @Override 23 | protected void onDestroy() { 24 | super.onDestroy(); 25 | ActivityCollector.removeActivity(this); 26 | } 27 | 28 | @Override 29 | protected void onResume() { 30 | super.onResume(); 31 | IntentFilter intentFilter=new IntentFilter(); 32 | intentFilter.addAction("force_offline"); 33 | ForceOffLineReceiver receiver=new ForceOffLineReceiver(); 34 | registerReceiver(receiver,intentFilter); 35 | } 36 | 37 | class ForceOffLineReceiver extends BroadcastReceiver{ 38 | @Override 39 | public void onReceive(Context context, Intent intent) { 40 | ActivityCollector.finishAll();//把所有活动finish后再打开主页面的活动 41 | // Intent intent1=new Intent(context, MainActivity.class); 42 | // context.startActivity(intent1); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/free/Classes/EachButton.java: -------------------------------------------------------------------------------- 1 | package com.example.free.Classes; 2 | 3 | 4 | import android.animation.Animator; 5 | import android.animation.ObjectAnimator; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.graphics.Color; 9 | import android.graphics.Path; 10 | import android.util.Property; 11 | import android.view.LayoutInflater; 12 | import android.view.View; 13 | import android.view.animation.LinearInterpolator; 14 | import android.widget.TextView; 15 | import android.widget.Toast; 16 | 17 | import androidx.appcompat.widget.AppCompatButton; 18 | import androidx.constraintlayout.widget.ConstraintLayout; 19 | 20 | import com.example.free.GameActivity; 21 | import com.example.free.R; 22 | import com.example.free.ResultActivity; 23 | 24 | import java.util.Timer; 25 | import java.util.TimerTask; 26 | 27 | 28 | public class EachButton extends AppCompatButton { 29 | int fromX=0; 30 | int fromY=0; 31 | int toX=0; 32 | int toY=0; 33 | int startTime=0; 34 | int time=0; 35 | 36 | int width=240;//px 37 | int height=120; 38 | // int width=80;//dp 39 | // int height=40;//dp 40 | 41 | // final int endWidth=240;//px 42 | // final int endHeight=120; 43 | 44 | ConstraintLayout mlayout; 45 | Context mcontext; 46 | 47 | public ObjectAnimator animator; 48 | 49 | public boolean state=true;//按钮的状态,是否还存在于视图中 50 | 51 | int path=0;//轨道 52 | 53 | 54 | 55 | 56 | public EachButton(Context context,int _width,int _height,int fx,int fy,int tox,int toy,int st,int t,int p){ 57 | super(context); 58 | 59 | this.fromX=fx; 60 | this.fromY=fy; 61 | this.toX=tox; 62 | this.toY=toy; 63 | this.startTime=st; 64 | this.time=t; 65 | 66 | this.path=p; 67 | 68 | width=_width; 69 | height=_height; 70 | 71 | mcontext=context; 72 | 73 | this.setBackgroundColor(0xaaF8E097); 74 | //this.layout(fx,fy,fx+width,fy+height); 75 | 76 | // this.setVisibility(INVISIBLE); 77 | this.setWidth(width); 78 | this.setHeight(height); 79 | this.layout(1000,0,1000+width,height); 80 | 81 | //this.setWidth(80*441/160); 82 | //this.setHeight(40*441/160);//40dp*441ppi/160 px //setWidth()和后面getX()得到的也都是像素pixels,所以这里也用像素 83 | 84 | 85 | //this.start(); 86 | 87 | 88 | } 89 | 90 | //继承的已有setVisibility(0)方法,getTranslationX(),getX()方法, 91 | 92 | public void start(ConstraintLayout layout){ 93 | // 94 | // TranslateAnimation ta=new TranslateAnimation(fromX,toX,fromY,toY); 95 | // ta.setDuration(time);//动画时长 ms 96 | // ta.setStartOffset(startTime);//延时 97 | // //ta.setFillBefore(false);//动画结束时停在第一帧 98 | // //ta.setFillAfter(false); 99 | // /* final LinearLayout mlayout=layout; 100 | // EachButton eachButton=this;*/ 101 | // //setStateValue(this,layout); 102 | // //this.setVisibility(INVISIBLE); 103 | // LinearInterpolator lin = new LinearInterpolator();//匀速运动 104 | // ta.setInterpolator(lin); 105 | // 106 | // layout=mlayout; 107 | // 108 | // 109 | // //setState(this,ta); 110 | // setStateValue(this); 111 | // layout.addView(this);//把addView放到onAnimationStart里面加载不出来 112 | // 113 | // 114 | // this.startAnimation(ta);//自动启动动画 115 | // //layout.removeView(this); 116 | 117 | //translateAnimation是表面呈现的移动,但布局没变,animator会随着变,方便获得移动中的位置 118 | mlayout=layout; 119 | //layout.addView(this); 120 | //ObjectAnimator.ofFloat(this, "translationY", fromY, toY).setDuration(time).setStartDelay(startTime); 121 | Path path=new Path(); 122 | path.moveTo(fromX,fromY);//开始 123 | path.lineTo(toX,toY);//结束 124 | animator=ObjectAnimator.ofFloat(this, 125 | Property.of(EachButton.class,Float.class,"translationX"), 126 | Property.of(EachButton.class,Float.class,"translationY"), 127 | path); 128 | 129 | animator.setDuration(time); 130 | animator.setStartDelay(startTime); 131 | 132 | //animator.pause(); 133 | 134 | LinearInterpolator lin = new LinearInterpolator();//匀速运动 135 | animator.setInterpolator(lin); 136 | 137 | final EachButton eachButton=this; 138 | animator.addListener(new Animator.AnimatorListener() { 139 | @Override 140 | public void onAnimationStart(Animator animation) { 141 | mlayout.addView(eachButton); 142 | } 143 | 144 | @Override 145 | public void onAnimationEnd(Animator animation) { 146 | mlayout.removeView(eachButton); 147 | 148 | if(eachButton.state) { 149 | View view = LayoutInflater.from(mcontext).inflate(R.layout.toast, null); 150 | TextView textView = view.findViewById(R.id.textView); 151 | textView.setText("miss"); 152 | //textView.setTextColor(Color.parseColor("#909090")); 153 | //textView.setTextColor(getResources().getColor(R.color.colorGray)); 154 | //Toast toast=new Toast(mcontext); 155 | Toast toast = GameActivity.toast;//方便被activity1里面新的点击替代,如果是新的可能替代不了 156 | toast.setView(view); 157 | toast.setDuration(Toast.LENGTH_SHORT); 158 | 159 | /* 160 | ObjectAnimator textAnimator=ObjectAnimator 161 | .ofFloat(textView,"translationY", textView.getY(), textView.getY()+200) 162 | .setDuration(1000);*/ 163 | ObjectAnimator.ofArgb(textView, "textColor", 164 | Color.parseColor("#ff333333"), 165 | Color.parseColor("#00333333")) 166 | .setDuration(1000) 167 | .start(); 168 | toast.show(); 169 | 170 | GameActivity.buttons.get(eachButton.path).remove(0); 171 | GameActivity.missTimes+=1; 172 | 173 | if((GameActivity.buttons.get(0).size()+GameActivity.buttons.get(1).size()==0)&&GameActivity.activityState) { 174 | final Intent iintent = new Intent(mcontext, ResultActivity.class); 175 | iintent.putExtra("wholeScore",GameActivity.wholeScore); 176 | iintent.putExtra("resultScore",GameActivity.resultScore); 177 | iintent.putExtra("bestTimes",GameActivity.bestTimes); 178 | iintent.putExtra("goodTimes",GameActivity.goodTimes); 179 | iintent.putExtra("missTimes",GameActivity.missTimes); 180 | TimerTask task = new TimerTask(){ 181 | public void run(){ 182 | mcontext.startActivity(iintent); 183 | } 184 | }; 185 | Timer timer = new Timer(); 186 | timer.schedule(task, 2000); 187 | 188 | } 189 | 190 | } 191 | 192 | } 193 | 194 | @Override 195 | public void onAnimationCancel(Animator animation) { 196 | 197 | } 198 | 199 | @Override 200 | public void onAnimationRepeat(Animator animation) { 201 | 202 | } 203 | }); 204 | // animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 205 | // @Override 206 | // public void onAnimationUpdate(ValueAnimator animation) { 207 | // eachButton.setWidth(width+(int)animation.getCurrentPlayTime()/time*(endWidth-width)); 208 | // eachButton.setWidth(height+(int)animation.getCurrentPlayTime()/time*(endHeight-height)); 209 | // } 210 | // }); 211 | animator.start(); 212 | /* 213 | layout=mlayout; 214 | layout.addView(this); 215 | final EachButton eachButton=this; 216 | this.animate().translationY(toY) 217 | .setDuration(time).setStartDelay(startTime) 218 | .withEndAction(new Runnable() { 219 | @Override 220 | public void run() { 221 | layout.removeView(eachButton); 222 | } 223 | }); 224 | */ 225 | } 226 | 227 | 228 | 229 | /* 230 | public void viewRemoveButton(ConstraintLayout mlayout){ 231 | mlayout.removeView(this); 232 | } 233 | */ 234 | 235 | /* 236 | public void setState(final EachButton eachButton,TranslateAnimation ta){ 237 | 238 | ta.setAnimationListener(new Animation.AnimationListener() { 239 | 240 | @Override 241 | public void onAnimationStart(Animation animation) { 242 | //layout.addView(eachButton); 243 | Log.d("state","here"); 244 | //eachButton.setVisibility(VISIBLE); 245 | 246 | } 247 | 248 | @Override 249 | public void onAnimationEnd(Animation animation) { 250 | //Log.d("state","there"); 251 | //eachButton.setVisibility(INVISIBLE); 252 | mlayout.removeView(eachButton); 253 | eachButton.state=false; 254 | 255 | View view =LayoutInflater.from(mcontext).inflate(R.layout.toast, null); 256 | TextView textView=view.findViewById(R.id.textView); 257 | textView.setText("miss"); 258 | //textView.setTextColor(Color.parseColor("#909090")); 259 | textView.setTextColor(getResources().getColor(R.color.colorGray)); 260 | Toast toast=new Toast(mcontext); 261 | toast.setView(view); 262 | toast.setDuration(Toast.LENGTH_SHORT); 263 | toast.show(); 264 | 265 | Activity1.buttons.remove(0); 266 | 267 | 268 | } 269 | 270 | @Override 271 | public void onAnimationRepeat(Animation animation) { 272 | 273 | } 274 | }); 275 | 276 | this.addOnLayoutChangeListener(new OnLayoutChangeListener() { 277 | @Override 278 | public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { 279 | Toast.makeText(getContext(),top+"",Toast.LENGTH_SHORT).show(); 280 | } 281 | }); 282 | 283 | 284 | } 285 | */ 286 | 287 | /* 288 | public void setStateValue(final EachButton eachButton){ 289 | 290 | 291 | ValueAnimator valueAnimator= ValueAnimator.ofInt(eachButton.fromY,eachButton.toY); 292 | valueAnimator.setDuration(eachButton.time); 293 | valueAnimator.setStartDelay(eachButton.startTime); 294 | 295 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 296 | @Override 297 | public void onAnimationUpdate(ValueAnimator animation) { 298 | int curValue = (int)animation.getAnimatedValue(); 299 | //layout(left,top,right,bottom) 300 | eachButton.layout(eachButton.fromX,curValue,eachButton.fromX+150,curValue+100); 301 | //if(curValue==1) 302 | //linearLayout.addView(eachButton); 303 | //eachButton.setVisibility(VISIBLE); 304 | if(curValue==eachButton.toY) 305 | //eachButton.setVisibility(INVISIBLE); 306 | mlayout.removeView(eachButton); 307 | } 308 | }); 309 | valueAnimator.start(); 310 | 311 | } 312 | */ 313 | 314 | 315 | 316 | 317 | } 318 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/free/Classes/FFT.java: -------------------------------------------------------------------------------- 1 | package com.example.free.Classes; 2 | 3 | public class FFT { 4 | 5 | int n, m; 6 | 7 | // Lookup tables. Only need to recompute when size of FFT changes. 8 | double[] cos; 9 | double[] sin; 10 | 11 | public FFT(int n) { 12 | this.n = n; 13 | this.m = (int) (Math.log(n) / Math.log(2));//2的几次方 14 | 15 | // Make sure n is a power of 2 16 | if (n != (1 << m)) 17 | throw new RuntimeException("FFT length must be power of 2");//2的幂次方 18 | 19 | // precompute tables 20 | cos = new double[n / 2]; 21 | sin = new double[n / 2]; 22 | 23 | for (int i = 0; i < n / 2; i++) { 24 | cos[i] = Math.cos(-2 * Math.PI * i / n); 25 | sin[i] = Math.sin(-2 * Math.PI * i / n); 26 | } 27 | 28 | } 29 | 30 | 31 | //x是实部,y是虚部 32 | public void fft(double[] x, double[] y) { 33 | int i, j, k, n1, n2, a; 34 | double c, s, t1, t2; 35 | 36 | //n=16; 37 | // Bit-reverse 38 | j = 0; 39 | n2 = n / 2;//8 40 | for (i = 1; i < n - 1; i++) { 41 | n1 = n2;//8 42 | while (j >= n1) { 43 | j = j - n1;//0 4 0 4 0 44 | n1 = n1 / 2;//4 4 4 4 4 45 | } 46 | j = j + n1;//8 4 12 8 4 12 8 4 12 47 | 48 | if (i < j) {// i j,1 8,2 4,3 12, 4 8,5 4,6 12, 7 8,8 4,9 12 ,,10 8,11 4,12 12, 13 8,14 4, 49 | // i j交换,1 8,2 4,3 12, 4 8, ,6 12, 7 8, ,9 12 ,, , , , , , ; 8, 4, 12, 1, 5, 3, 2, 7, 6, 10, 11, 9, 13, 14, 15, 16, 50 | t1 = x[i]; 51 | x[i] = x[j]; 52 | x[j] = t1; 53 | t1 = y[i]; 54 | y[i] = y[j]; 55 | y[j] = t1; 56 | } 57 | } 58 | 59 | // FFT 60 | n1 = 0; 61 | n2 = 1; 62 | //m=4 63 | for (i = 0; i < m; i++) { 64 | n1 = n2;//1 65 | n2 = n2 + n2;//2 66 | a = 0; 67 | 68 | for (j = 0; j < n1; j++) { 69 | c = cos[a]; 70 | s = sin[a]; 71 | a += 1 << (m - i - 1); 72 | 73 | for (k = j; k < n; k = k + n2) { 74 | t1 = c * x[k + n1] - s * y[k + n1]; 75 | t2 = s * x[k + n1] + c * y[k + n1]; 76 | x[k + n1] = x[k] - t1; 77 | y[k + n1] = y[k] - t2; 78 | x[k] = x[k] + t1; 79 | y[k] = y[k] + t2; 80 | } 81 | } 82 | } 83 | } 84 | 85 | //采集的信号虚部为0即可 86 | public static void main(String[] args){ 87 | int N=16; 88 | FFT fft=new FFT(N); 89 | 90 | double[] re=new double[N]; 91 | double[] im=new double[N]; 92 | 93 | // Impulse 94 | re[0] = 1; im[0] = 0; 95 | for(int i=1; i allTime,int sampling,long musicTime,int _window,int window_size,double multiplier){ 23 | 24 | final int window=_window;//样本窗口越大,,可能超过阈值的越多 25 | final int THRESHOLD_WINDOW_SIZE=window_size;//阈值左右各取多少个样本窗口的光谱通量!!!!越慢的歌要的越少,size越大,块数越多 26 | final double MULTIPLIER=multiplier;//阈值的加权值!!!!越慢的歌要的越高(快的歌太高,短时间变得快,块数越少) 27 | // final double lean=0.95; 28 | 29 | 30 | 31 | double[] dataFFT;//频谱 32 | List spectralFlux = new ArrayList<>();//每个样本窗口的光谱通量 33 | List leanRate = new ArrayList<>();//每个样本窗口的光谱通量 34 | 35 | List threshold = new ArrayList<>( );//每个样本窗口的阈值 36 | List leanRateAverage=new ArrayList<>();//附近几个的平均斜率,如果它的斜率大于平均值,则为突然变化值 37 | 38 | 39 | int len = data.length; 40 | 41 | int m=len/window;//样本窗口数 //近似。。待定加一 42 | 43 | dataFFT=new double[len]; 44 | double[] dataFFTVariation=new double[len-m]; 45 | 46 | 47 | FFT fft=new FFT(window);//本地类 48 | 49 | double[] re=new double[window];//实部 50 | double[] im=new double[window];//虚部,为0 51 | 52 | double max=re[0]; 53 | double min=re[0]; 54 | 55 | for(int k=0;k0){ 68 | dataFFTVariation[k*window+i-1-k]=dataFFT[k*window+i]-dataFFT[k*window+i-1]; 69 | double value=dataFFTVariation[k*window+i-1-k]; 70 | flux+=value<0?0:value; 71 | //flux+=value; 72 | } 73 | } 74 | // if(flux>max)max=flux; 75 | // if(flux0.01) 87 | //// allTime.add(i*window/sampling*1000); 88 | // } 89 | // System.out.println(); 90 | 91 | 92 | //阈值 93 | int delete=10; 94 | for(int i=0;i0&&(time-allTime.get(allTime.size()-1))>100)||allTime.size()<1) 112 | allTime.add(time);//不知道为什么只有16的时候效果比较好..平均采样率16000 113 | } 114 | } 115 | for(int i=0;i<5;i++) 116 | allTime.remove(0); 117 | //System.out.println(); 118 | 119 | // for(int i=1;ileanRate.get(i-1)*0.05) 121 | // allTime.add(i*window/sampling*1000); 122 | // } 123 | // 124 | // for(int i=1;iMath.abs(spectralFlux.get(i-1))*0.1) 126 | // allTime.add(i*window/sampling*1000); 127 | // } 128 | //System.out.println("here is allTime length:"+allTime.size()); 129 | 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/free/Classes/LandEachButton.java: -------------------------------------------------------------------------------- 1 | package com.example.free.Classes; 2 | 3 | 4 | import android.animation.Animator; 5 | import android.animation.ObjectAnimator; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.graphics.Color; 9 | import android.graphics.Path; 10 | import android.util.Property; 11 | import android.view.LayoutInflater; 12 | import android.view.View; 13 | import android.view.animation.LinearInterpolator; 14 | import android.widget.TextView; 15 | import android.widget.Toast; 16 | 17 | import androidx.appcompat.widget.AppCompatButton; 18 | import androidx.constraintlayout.widget.ConstraintLayout; 19 | 20 | import com.example.free.FourGameActivity; 21 | import com.example.free.R; 22 | import com.example.free.ResultActivity; 23 | 24 | import java.util.Timer; 25 | import java.util.TimerTask; 26 | 27 | 28 | public class LandEachButton extends AppCompatButton { 29 | int fromX=0; 30 | int fromY=0; 31 | int toX=0; 32 | int toY=0; 33 | int startTime=0; 34 | int time=0; 35 | 36 | int width=240;//px 37 | int height=120; 38 | 39 | // final int endWidth=240;//px 40 | // final int endHeight=120; 41 | 42 | ConstraintLayout mlayout; 43 | Context mcontext; 44 | 45 | public ObjectAnimator animator; 46 | 47 | public boolean state=true;//按钮的状态,是否还存在于视图中 48 | 49 | int path=0;//轨道 50 | 51 | 52 | 53 | 54 | public LandEachButton(Context context,int _width,int _height,int fx,int fy,int tox,int toy,int st,int t,int p){ 55 | super(context); 56 | 57 | this.fromX=fx; 58 | this.fromY=fy; 59 | this.toX=tox; 60 | this.toY=toy; 61 | this.startTime=st; 62 | this.time=t; 63 | 64 | this.path=p; 65 | 66 | width=_width; 67 | height=_height; 68 | 69 | mcontext=context; 70 | 71 | this.setBackgroundColor(0xaaF8E097); 72 | // this.layout(fx,fy,fx+width,fy+height); 73 | this.setWidth(width); 74 | this.setHeight(height); 75 | 76 | //this.setWidth(80*441/160); 77 | //this.setHeight(40*441/160);//40dp*441ppi/160 px //setWidth()和后面getX()得到的也都是像素pixels,所以这里也用像素 78 | 79 | 80 | //this.start(); 81 | 82 | 83 | } 84 | 85 | //继承的已有setVisibility(0)方法,getTranslationX(),getX()方法, 86 | 87 | public void start(ConstraintLayout layout){ 88 | // 89 | // TranslateAnimation ta=new TranslateAnimation(fromX,toX,fromY,toY); 90 | // ta.setDuration(time);//动画时长 ms 91 | // ta.setStartOffset(startTime);//延时 92 | // //ta.setFillBefore(false);//动画结束时停在第一帧 93 | // //ta.setFillAfter(false); 94 | // /* final LinearLayout mlayout=layout; 95 | // EachButton eachButton=this;*/ 96 | // //setStateValue(this,layout); 97 | // //this.setVisibility(INVISIBLE); 98 | // LinearInterpolator lin = new LinearInterpolator();//匀速运动 99 | // ta.setInterpolator(lin); 100 | // 101 | // layout=mlayout; 102 | // 103 | // 104 | // //setState(this,ta); 105 | // setStateValue(this); 106 | // layout.addView(this);//把addView放到onAnimationStart里面加载不出来 107 | // 108 | // 109 | // this.startAnimation(ta);//自动启动动画 110 | // //layout.removeView(this); 111 | 112 | //translateAnimation是表面呈现的移动,但布局没变,animator会随着变,方便获得移动中的位置 113 | mlayout=layout; 114 | //layout.addView(this); 115 | //ObjectAnimator.ofFloat(this, "translationY", fromY, toY).setDuration(time).setStartDelay(startTime); 116 | Path path=new Path(); 117 | path.moveTo(fromX,fromY);//开始 118 | path.lineTo(toX,toY);//结束 119 | animator=ObjectAnimator.ofFloat(this, 120 | Property.of(LandEachButton.class,Float.class,"translationX"), 121 | Property.of(LandEachButton.class,Float.class,"translationY"), 122 | path); 123 | animator.setDuration(time); 124 | animator.setStartDelay(startTime); 125 | 126 | //animator.pause(); 127 | 128 | LinearInterpolator lin = new LinearInterpolator();//匀速运动 129 | animator.setInterpolator(lin); 130 | 131 | final LandEachButton eachButton=this; 132 | animator.addListener(new Animator.AnimatorListener() { 133 | @Override 134 | public void onAnimationStart(Animator animation) { 135 | mlayout.addView(eachButton); 136 | } 137 | 138 | @Override 139 | public void onAnimationEnd(Animator animation) { 140 | mlayout.removeView(eachButton); 141 | 142 | if(eachButton.state) { 143 | View view = LayoutInflater.from(mcontext).inflate(R.layout.toast_land, null); 144 | TextView textView = view.findViewById(R.id.textView); 145 | textView.setText("miss"); 146 | //textView.setTextColor(Color.parseColor("#909090")); 147 | //textView.setTextColor(getResources().getColor(R.color.colorGray)); 148 | //Toast toast=new Toast(mcontext); 149 | Toast toast = FourGameActivity.toast;//方便被activity1里面新的点击替代,如果是新的可能替代不了 150 | toast.setView(view); 151 | toast.setDuration(Toast.LENGTH_SHORT); 152 | 153 | /* 154 | ObjectAnimator textAnimator=ObjectAnimator 155 | .ofFloat(textView,"translationY", textView.getY(), textView.getY()+200) 156 | .setDuration(1000);*/ 157 | ObjectAnimator.ofArgb(textView, "textColor", 158 | Color.parseColor("#ff333333"), 159 | Color.parseColor("#00333333")) 160 | .setDuration(1000) 161 | .start(); 162 | toast.show(); 163 | 164 | FourGameActivity.buttons.get(eachButton.path).remove(0); 165 | FourGameActivity.missTimes+=1; 166 | 167 | if((FourGameActivity.buttons.get(0).size()+FourGameActivity.buttons.get(1).size()+ 168 | FourGameActivity.buttons.get(2).size()+FourGameActivity.buttons.get(3).size()==0)&& 169 | FourGameActivity.activityState){ 170 | final Intent iintent = new Intent(mcontext, ResultActivity.class); 171 | iintent.putExtra("wholeScore",FourGameActivity.wholeScore); 172 | iintent.putExtra("resultScore",FourGameActivity.resultScore); 173 | iintent.putExtra("bestTimes",FourGameActivity.bestTimes); 174 | iintent.putExtra("goodTimes",FourGameActivity.goodTimes); 175 | iintent.putExtra("missTimes",FourGameActivity.missTimes); 176 | TimerTask task = new TimerTask(){ 177 | public void run(){ 178 | mcontext.startActivity(iintent); 179 | } 180 | }; 181 | Timer timer = new Timer(); 182 | timer.schedule(task, 2000); 183 | 184 | } 185 | 186 | } 187 | 188 | } 189 | 190 | @Override 191 | public void onAnimationCancel(Animator animation) { 192 | 193 | } 194 | 195 | @Override 196 | public void onAnimationRepeat(Animator animation) { 197 | 198 | } 199 | }); 200 | // animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 201 | // @Override 202 | // public void onAnimationUpdate(ValueAnimator animation) { 203 | // eachButton.setWidth(width+(int)animation.getCurrentPlayTime()/time*(endWidth-width)); 204 | // eachButton.setWidth(height+(int)animation.getCurrentPlayTime()/time*(endHeight-height)); 205 | // } 206 | // }); 207 | animator.start(); 208 | /* 209 | layout=mlayout; 210 | layout.addView(this); 211 | final EachButton eachButton=this; 212 | this.animate().translationY(toY) 213 | .setDuration(time).setStartDelay(startTime) 214 | .withEndAction(new Runnable() { 215 | @Override 216 | public void run() { 217 | layout.removeView(eachButton); 218 | } 219 | }); 220 | */ 221 | } 222 | 223 | 224 | 225 | /* 226 | public void viewRemoveButton(ConstraintLayout mlayout){ 227 | mlayout.removeView(this); 228 | } 229 | */ 230 | 231 | /* 232 | public void setState(final EachButton eachButton,TranslateAnimation ta){ 233 | 234 | ta.setAnimationListener(new Animation.AnimationListener() { 235 | 236 | @Override 237 | public void onAnimationStart(Animation animation) { 238 | //layout.addView(eachButton); 239 | Log.d("state","here"); 240 | //eachButton.setVisibility(VISIBLE); 241 | 242 | } 243 | 244 | @Override 245 | public void onAnimationEnd(Animation animation) { 246 | //Log.d("state","there"); 247 | //eachButton.setVisibility(INVISIBLE); 248 | mlayout.removeView(eachButton); 249 | eachButton.state=false; 250 | 251 | View view =LayoutInflater.from(mcontext).inflate(R.layout.toast, null); 252 | TextView textView=view.findViewById(R.id.textView); 253 | textView.setText("miss"); 254 | //textView.setTextColor(Color.parseColor("#909090")); 255 | textView.setTextColor(getResources().getColor(R.color.colorGray)); 256 | Toast toast=new Toast(mcontext); 257 | toast.setView(view); 258 | toast.setDuration(Toast.LENGTH_SHORT); 259 | toast.show(); 260 | 261 | Activity1.buttons.remove(0); 262 | 263 | 264 | } 265 | 266 | @Override 267 | public void onAnimationRepeat(Animation animation) { 268 | 269 | } 270 | }); 271 | 272 | this.addOnLayoutChangeListener(new OnLayoutChangeListener() { 273 | @Override 274 | public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { 275 | Toast.makeText(getContext(),top+"",Toast.LENGTH_SHORT).show(); 276 | } 277 | }); 278 | 279 | 280 | } 281 | */ 282 | 283 | /* 284 | public void setStateValue(final EachButton eachButton){ 285 | 286 | 287 | ValueAnimator valueAnimator= ValueAnimator.ofInt(eachButton.fromY,eachButton.toY); 288 | valueAnimator.setDuration(eachButton.time); 289 | valueAnimator.setStartDelay(eachButton.startTime); 290 | 291 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 292 | @Override 293 | public void onAnimationUpdate(ValueAnimator animation) { 294 | int curValue = (int)animation.getAnimatedValue(); 295 | //layout(left,top,right,bottom) 296 | eachButton.layout(eachButton.fromX,curValue,eachButton.fromX+150,curValue+100); 297 | //if(curValue==1) 298 | //linearLayout.addView(eachButton); 299 | //eachButton.setVisibility(VISIBLE); 300 | if(curValue==eachButton.toY) 301 | //eachButton.setVisibility(INVISIBLE); 302 | mlayout.removeView(eachButton); 303 | } 304 | }); 305 | valueAnimator.start(); 306 | 307 | } 308 | */ 309 | 310 | 311 | 312 | 313 | } 314 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/free/Classes/MP3ToWav.java: -------------------------------------------------------------------------------- 1 | //package com.example.free; 2 | // 3 | // 4 | // 5 | //import java.io.File; 6 | //import java.io.IOException; 7 | //import java.net.MalformedURLException; 8 | //import java.net.URL; 9 | // 10 | //import javax.sound.sampled.AudioFileFormat; 11 | //import javax.sound.sampled.AudioFormat; 12 | //import javax.sound.sampled.AudioInputStream; 13 | //import javax.sound.sampled.AudioSystem; 14 | //import javax.sound.sampled.UnsupportedAudioFileException; 15 | // 16 | // 17 | // 18 | ///*import org.json.JSONObject; 19 | // 20 | //import com.baidu.aip.speech.AipSpeech;*/ 21 | // 22 | //public class MP3ToWav { 23 | // 24 | // public static File byteToWav(URL sourceURL, String targetPath) { 25 | // 26 | // File file=new File(targetPath); 27 | // 28 | // try (final AudioInputStream sourceAIS = AudioSystem.getAudioInputStream(sourceURL)) { 29 | // //得到输入流 30 | // 31 | // AudioFormat sourceFormat = sourceAIS.getFormat();//原格式 32 | // 33 | // //需要再从mp3转mp3一次,再从mp3转wav,,直接从mp3转wav报错。。 34 | // // 设置MP3的语音格式,并设置16bit 35 | // AudioFormat mp3tFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, sourceFormat.getSampleRate(), 16, sourceFormat.getChannels(), sourceFormat.getChannels() * 2, sourceFormat.getSampleRate(), false); 36 | // //sourceFormat.getSampleRate()每秒的样本数,16每个样本中的位数(两个字节),sourceFormat.getChannels()声道数,每帧的字节数,每秒的帧数,false是否以 big-endian 字节顺序存储单个样本中的数据 37 | // 38 | // // 设置wav的音频格式 39 | // AudioFormat pcmFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 16000, 16, 1, 2, 16000, false); 40 | // try ( 41 | // // 先通过MP3转一次,使音频流能的格式完整,,mp3格式转mp3格式,得到完整mp3格式的输入流 42 | // final AudioInputStream mp3AIS = AudioSystem.getAudioInputStream(mp3tFormat, sourceAIS); 43 | // 44 | // // 转成需要的流,mp3格式转wav格式,得到输入流 45 | // final AudioInputStream pcmAIS = AudioSystem.getAudioInputStream(pcmFormat, mp3AIS); 46 | // ) { 47 | // // 根据路径生成wav文件,输入流转文件。 48 | // AudioSystem.write(pcmAIS, AudioFileFormat.Type.WAVE, file); 49 | // } 50 | // 51 | // return file; 52 | // } catch (IOException e) { 53 | // //System.out.println("文件转换异常:" + e.getMessage()); 54 | // return null; 55 | // } catch (UnsupportedAudioFileException e) { 56 | // //System.out.println("文件转换异常:" + e.getMessage());//could not get audio input stream from input stream 57 | // 58 | // return null; 59 | // } 60 | // } 61 | // 62 | // 63 | // public static File getWav(String filePath) { 64 | // String fileURL = "file://"+filePath;//url为"file://"开头 65 | // String targetPath = "1.wav"; 66 | // try { 67 | // return byteToWav(new URL(fileURL),targetPath); 68 | // } catch (MalformedURLException e) { 69 | // // TODO Auto-generated catch block 70 | // e.printStackTrace(); 71 | // } 72 | // return null; 73 | // 74 | // } 75 | //} 76 | // 77 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/free/Classes/MP3ToWav1.java: -------------------------------------------------------------------------------- 1 | //package com.example.free; 2 | // 3 | //import android.media.MediaCodec; 4 | //import android.media.MediaExtractor; 5 | //import android.media.MediaFormat; 6 | //import android.text.TextUtils; 7 | // 8 | //import java.io.FileInputStream; 9 | // 10 | //public class MP3ToWav1 { 11 | // 12 | // public static void main(String args[]) { 13 | // String fileURL = "file://G:/app/code/music.mp3";//url为"file://"开头 14 | // String targetPath = "G:/app/code/G.wav"; 15 | // MediaExtractor mediaExtractor = new MediaExtractor(); 16 | // MediaFormat mediaFormat = null; 17 | // MediaCodec mediaCodec = null; 18 | // 19 | // 20 | // } 21 | // 22 | // /** 23 | // * 将音乐文件解码 24 | // * 25 | // * @param musicFileUrl 源文件路径 26 | // * @param decodeFileUrl 解码文件路径 27 | // * @param startMicroseconds 开始时间 微秒 28 | // * @param endMicroseconds 结束时间 微秒 29 | //// * @param decodeOperateInterface 解码过程回调 30 | // */ 31 | // private boolean decodeMusicFile(String musicFileUrl, String decodeFileUrl, 32 | // long startMicroseconds, long endMicroseconds 33 | //// , DecodeOperateInterface decodeOperateInterface 34 | // ) { 35 | // 36 | // //采样率,声道数,时长,音频文件类型 37 | // int sampleRate = 0; 38 | // int channelCount = 0; 39 | // long duration = 0; 40 | // String mime = null; 41 | // 42 | // //MediaExtractor, MediaFormat, MediaCodec 43 | // MediaExtractor mediaExtractor = new MediaExtractor(); 44 | // MediaFormat mediaFormat = null; 45 | // MediaCodec mediaCodec = null; 46 | // 47 | // //给媒体信息提取器设置源音频文件路径 48 | // try { 49 | // mediaExtractor.setDataSource(musicFileUrl); 50 | // }catch (Exception ex){ 51 | // ex.printStackTrace(); 52 | // try { 53 | // mediaExtractor.setDataSource(new FileInputStream(musicFileUrl).getFD()); 54 | // } catch (Exception e) { 55 | // e.printStackTrace(); 56 | //// LogUtil.e("设置解码音频文件路径错误"); 57 | // } 58 | // } 59 | // 60 | // //获取音频格式轨信息 61 | // mediaFormat = mediaExtractor.getTrackFormat(0); 62 | // 63 | // //从音频格式轨信息中读取 采样率,声道数,时长,音频文件类型 64 | // sampleRate = mediaFormat.containsKey(MediaFormat.KEY_SAMPLE_RATE) ? mediaFormat.getInteger( 65 | // MediaFormat.KEY_SAMPLE_RATE) : 44100; 66 | // channelCount = mediaFormat.containsKey(MediaFormat.KEY_CHANNEL_COUNT) ? mediaFormat.getInteger( 67 | // MediaFormat.KEY_CHANNEL_COUNT) : 1; 68 | // duration = mediaFormat.containsKey(MediaFormat.KEY_DURATION) ? mediaFormat.getLong( 69 | // MediaFormat.KEY_DURATION) : 0; 70 | // mime = mediaFormat.containsKey(MediaFormat.KEY_MIME) ? mediaFormat.getString(MediaFormat.KEY_MIME) 71 | // : ""; 72 | // 73 | //// LogUtil.i("歌曲信息Track info: mime:" 74 | //// + mime 75 | //// + " 采样率sampleRate:" 76 | //// + sampleRate 77 | //// + " channels:" 78 | //// + channelCount 79 | //// + " duration:" 80 | //// + duration); 81 | // 82 | // if (TextUtils.isEmpty(mime) || !mime.startsWith("audio/")) { 83 | //// LogUtil.e("解码文件不是音频文件mime:" + mime); 84 | // return false; 85 | // } 86 | // 87 | // if (mime.equals("audio/ffmpeg")) { 88 | // mime = "audio/mpeg"; 89 | // mediaFormat.setString(MediaFormat.KEY_MIME, mime); 90 | // } 91 | // 92 | // if (duration <= 0) { 93 | //// LogUtil.e("音频文件duration为" + duration); 94 | // return false; 95 | // } 96 | // 97 | // //解码的开始时间和结束时间 98 | // startMicroseconds = Math.max(startMicroseconds, 0); 99 | // endMicroseconds = endMicroseconds < 0 ? duration : endMicroseconds; 100 | // endMicroseconds = Math.min(endMicroseconds, duration); 101 | // 102 | // if (startMicroseconds >= endMicroseconds) { 103 | // return false; 104 | // } 105 | // 106 | // //创建一个解码器 107 | // try { 108 | // mediaCodec = MediaCodec.createDecoderByType(mime); 109 | // 110 | // mediaCodec.configure(mediaFormat, null, null, 0); 111 | // } catch (Exception e) { 112 | //// LogUtil.e("解码器configure出错"); 113 | // return false; 114 | // } 115 | // 116 | // //得到输出PCM文件的路径 117 | // decodeFileUrl = decodeFileUrl.substring(0, decodeFileUrl.lastIndexOf(".")); 118 | // String pcmFilePath = decodeFileUrl + ".pcm"; 119 | // 120 | // //后续解码操作 121 | // getDecodeData(mediaExtractor, mediaCodec, pcmFilePath, sampleRate, channelCount, 122 | // startMicroseconds, endMicroseconds, decodeOperateInterface); 123 | // 124 | // return true; 125 | // } 126 | //} 127 | // 128 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/free/Classes/Music.java: -------------------------------------------------------------------------------- 1 | package com.example.free.Classes; 2 | 3 | public class Music { 4 | 5 | private String name=""; 6 | private String path=""; 7 | private long size=0; 8 | private long time=0; 9 | 10 | public Music(String _name,String _path,long _size,long _time){ 11 | name=_name; 12 | path=_path; 13 | size=_size; 14 | time=_time; 15 | } 16 | 17 | public String getName(){ 18 | return name; 19 | } 20 | 21 | public String getPath(){ 22 | return path; 23 | } 24 | public long getSize(){ 25 | return size; 26 | } 27 | public long getTime(){ 28 | return time; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/free/Classes/MusicAdapter.java: -------------------------------------------------------------------------------- 1 | package com.example.free.Classes; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | 10 | import androidx.annotation.NonNull; 11 | import androidx.recyclerview.widget.RecyclerView; 12 | 13 | import com.example.free.ChoiceActivity; 14 | import com.example.free.GameActivity; 15 | import com.example.free.OriginChoiceActivity; 16 | import com.example.free.R; 17 | 18 | import java.util.List; 19 | 20 | 21 | public class MusicAdapter extends RecyclerView.Adapter { 22 | 23 | private List musicList; 24 | 25 | //构造函数别忘了 26 | public MusicAdapter(List _musicList) { 27 | musicList=_musicList; 28 | } 29 | 30 | @NonNull 31 | @Override 32 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 33 | View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.music_item,parent,false); 34 | //得到每一项的样式view,不继承parent 35 | final ViewHolder viewHolder=new ViewHolder(view); 36 | final Context context=parent.getContext(); 37 | view.setOnClickListener(new View.OnClickListener() { 38 | @Override 39 | public void onClick(View v) { 40 | int position=viewHolder.getAdapterPosition(); 41 | Music music=musicList.get(position); 42 | String musicPath=music.getPath(); 43 | long musicSize=music.getSize(); 44 | long musicTime=music.getTime(); 45 | //Intent intent=new Intent(context,MusicActivity.class); 46 | //Intent intent=new Intent(context, ChoiceActivity.class); 47 | Intent intent=new Intent(context, OriginChoiceActivity.class); 48 | intent.putExtra("musicPath",musicPath); 49 | intent.putExtra("musicSize", musicSize); 50 | intent.putExtra("musicTime",musicTime); 51 | context.startActivity(intent); 52 | } 53 | }); 54 | 55 | return viewHolder; 56 | } 57 | 58 | @Override 59 | public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) { 60 | Music music=musicList.get(position); 61 | viewHolder.textView.setText(music.getName()); 62 | } 63 | 64 | @Override 65 | public int getItemCount() { 66 | return musicList.size(); 67 | } 68 | 69 | 70 | class ViewHolder extends RecyclerView.ViewHolder{ 71 | //ViewHolder在adapter新建时储存控件实例/样式,这样在后面就不用一直findViewById查找 72 | 73 | TextView textView; 74 | 75 | ViewHolder(View view){ 76 | super(view); 77 | textView=view.findViewById(R.id.textView); 78 | } 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/free/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.free; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.appcompat.app.AppCompatActivity; 5 | import androidx.core.app.ActivityCompat; 6 | import androidx.core.content.ContextCompat; 7 | 8 | import android.Manifest; 9 | import android.content.Intent; 10 | import android.content.pm.PackageManager; 11 | import android.os.Bundle; 12 | import android.os.Handler; 13 | import android.os.Message; 14 | import android.view.View; 15 | import android.view.animation.AnimationUtils; 16 | import android.view.animation.TranslateAnimation; 17 | import android.widget.Button; 18 | import android.widget.LinearLayout; 19 | import android.widget.Toast; 20 | 21 | import com.example.free.Classes.BaseActivity; 22 | 23 | public class MainActivity extends AppCompatActivity { 24 | 25 | Button location; 26 | 27 | @Override 28 | protected void onCreate(Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_main); 31 | 32 | // Button button=findViewById(R.id.button); 33 | // button.setOnClickListener(new View.OnClickListener() { 34 | // @Override 35 | // public void onClick(View v) { 36 | // //以自身为坐标点 (x轴的起点(与现在位置的差值),结束点,y轴的起点,结束点) 37 | // TranslateAnimation ta=new TranslateAnimation(0,200,0,300); 38 | // ta.setDuration(2000);//时长 ms 39 | // v.startAnimation(ta);//自动启动动画 40 | // } 41 | // }); 42 | 43 | 44 | // Button button_startAnim=findViewById(R.id.button_startAnim); 45 | // button_startAnim.setOnClickListener(new View.OnClickListener() { 46 | // @Override 47 | // public void onClick(View v) { 48 | // v.startAnimation(AnimationUtils.loadAnimation(getApplicationContext(),+R.anim.anim)); 49 | // 50 | // } 51 | // }); 52 | // 53 | // Button remove=findViewById(R.id.remove); 54 | // remove.setOnClickListener(new View.OnClickListener() { 55 | // @Override 56 | // public void onClick(View v) { 57 | // LinearLayout ll=findViewById(R.id.content); 58 | // ll.removeView(findViewById(R.id.textView));//或者是int 即LinearLayout容器里面的第几个(index) 59 | // } 60 | // }); 61 | 62 | // Button button_Activity1=findViewById(R.id.Activity1); 63 | // button_Activity1.setOnClickListener(new View.OnClickListener() { 64 | // @Override 65 | // public void onClick(View v) { 66 | // 67 | // Intent intent=new Intent(MainActivity.this, Activity1.class); 68 | // startActivity(intent); 69 | // } 70 | // }); 71 | 72 | ///* 73 | // Timer timer=new Timer(); 74 | // TextView textView=findViewById(R.id.textView); 75 | // timer.schedule(new Task((View)textView),2000);*/ 76 | // new Handler(new Handler.Callback() { 77 | // @Override 78 | // public boolean handleMessage(@NonNull Message msg) { 79 | // findViewById(R.id.textView).startAnimation(AnimationUtils.loadAnimation(getApplicationContext(),+R.anim.anim)); 80 | // return false; 81 | // } 82 | // }).sendEmptyMessageDelayed(0,2000); 83 | ///* 84 | // new Handler().postDelayed(new Runnable() { 85 | // @Override 86 | // public void run() { 87 | // findViewById(R.id.textView).startAnimation(AnimationUtils.loadAnimation(getApplicationContext(),+R.anim.anim)); 88 | // } 89 | // },2000);*/ 90 | // 91 | // location=findViewById(R.id.location); 92 | // 93 | // location.setOnClickListener(new View.OnClickListener() { 94 | // @Override 95 | // public void onClick(View v) { 96 | // int[] xy=new int[2]; 97 | // location.getLocationOnScreen(xy); 98 | // Toast.makeText(MainActivity.this,xy[1]+"",Toast.LENGTH_SHORT).show(); 99 | // } 100 | // }); 101 | // 102 | Button music=findViewById(R.id.music); 103 | music.setOnClickListener(new View.OnClickListener() { 104 | @Override 105 | public void onClick(View v) { 106 | 107 | if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) 108 | != PackageManager.PERMISSION_GRANTED){ 109 | //申请权限,名字与manifest里面的一致,1为请求码;需要重写onRequestPermissionsResult的得到申请权限的回调函数 110 | ActivityCompat.requestPermissions(MainActivity.this,new String[]{ 111 | Manifest.permission.WRITE_EXTERNAL_STORAGE},1 112 | ); 113 | //这里是需要先把文件读出来,再处理 114 | } 115 | else{ 116 | // Intent intent=new Intent(MainActivity.this,MusicActivity.class); 117 | Intent intent=new Intent(MainActivity.this,MusicViewActivity.class); 118 | startActivity(intent); 119 | } 120 | 121 | } 122 | }); 123 | 124 | Button exit=findViewById(R.id.exit); 125 | exit.setOnClickListener(new View.OnClickListener() { 126 | @Override 127 | public void onClick(View v) { 128 | finish(); 129 | System.exit(0); 130 | } 131 | }); 132 | 133 | // 134 | // Button force=findViewById(R.id.force); 135 | // force.setOnClickListener(new View.OnClickListener() { 136 | // @Override 137 | // public void onClick(View v) { 138 | // Intent intent=new Intent(MainActivity.this,ResultActivity.class); 139 | // startActivity(intent); 140 | // } 141 | // }); 142 | // 143 | // 144 | // 145 | } 146 | 147 | @Override 148 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 149 | //grantResults是用户授权结果,只是接收结果给出反应,不是给出结果的过程 150 | //super.onRequestPermissionsResult(requestCode, permissions, grantResults); 151 | switch(requestCode){ 152 | case 1://请求码,一个活动里可能处理多个权限请求,对应不同的请求码 153 | if(grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION_GRANTED){ 154 | Intent intent=new Intent(MainActivity.this,MusicViewActivity.class); 155 | startActivity(intent); 156 | }else{ 157 | Toast.makeText(this,"you denied the permission",Toast.LENGTH_SHORT).show(); 158 | finish();//拒绝时回到上一页面 159 | } 160 | break; 161 | default: 162 | } 163 | } 164 | 165 | // 166 | // /* 167 | // public void startAnimation(View v){ 168 | // v.startAnimation(AnimationUtils.loadAnimation(getApplicationContext(),+R.anim.anim)); 169 | // }*/ 170 | // 171 | // /* 172 | // class Task extends TimerTask{ 173 | // View v; 174 | // Task(View v){ 175 | // this.v=v; 176 | // } 177 | // @Override 178 | // public void run() { 179 | // v.startAnimation(AnimationUtils.loadAnimation(getApplicationContext(),+R.anim.anim)); 180 | // } 181 | // //Only the original thread that created a view hierarchy can touch its views. 182 | // //只有创建这个view的线程才能操作这个view,普通会认为是将view创建在非UI线程中才会出现这个错误。 183 | // } 184 | //*/ 185 | } 186 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/free/Mp3Handle/FrameData.java: -------------------------------------------------------------------------------- 1 | package com.example.free.Mp3Handle; 2 | 3 | import java.util.Map; 4 | 5 | public class FrameData {//帧信息类 6 | private FrameHead frameHead; 7 | private byte[] bitData; 8 | private int bitSize; 9 | 10 | public FrameData(byte[] head) throws Exception { 11 | this.frameHead = new FrameData.FrameHead(head); 12 | this.bitSize = this.frameHead.getBitDataSize(); 13 | } 14 | 15 | public void setBitData(byte[] data) { 16 | this.bitData = data; 17 | } 18 | 19 | public int getBitSize() { 20 | return this.bitSize; 21 | } 22 | 23 | public int getSampling() { 24 | return this.frameHead.sampling; 25 | } 26 | 27 | class FrameHead { 28 | /* 4字节(32位)数据 */ 29 | /* 30 | * AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM 注意以上格式:将解释按照位操作数据 A 31-21 [11bit] 31 | * Frame sync帧同步 B 20-19 [2 bit] MPEG音频版本 (00 - MPEG Version 2.5) (01 - 32 | * 保留) (10 - MPEG Version 2) (11 - MPEG Version 1) C 18-17 [2 bit] 层描述 33 | * (00 - 保留) (01 - Layer III) (10 - Layer II) (11 - Layer I) D 16 [1 34 | * bit] 保护位 0意味着受CRC保护,帧头后面跟16位的CRC E 15-12 [4 bit] 比特率 F 11-10 [2 bit] 35 | * 采样频率 bits MPEG1 MPEG2 MPEG2.5 00 44100 22050 11025 01 48000 24000 36 | * 12000 10 32000 16000 8000 11 reserv reserv reserv G 9 [1 bit] 37 | * 意味着帧里包含padding位,仅当采样频率为44.1KHz时发生 H 8 [1 bit] 私有未知位 I 7-6 [2 bit] 38 | * 声道模式 (00 - 立体声) (01 - 联合立体声) (11 - 双通道) (11 - 单通道) J 5-4 [2 bit] 扩展模式 39 | * bit 强度立体声 MS立体声 00 关闭 关闭 01 开 关 10 关闭 开 11 开 开 K 3 [1 bit] 版权保护位 L 2 40 | * [1 bit] 是否拷贝 0=副本 1=原来的 M 1-0 [2 bit] 重点位 (00 - 不重视) (01 - 50/15毫秒) 41 | * (10 - 保留) (11 - 国际电报电话咨询委员会J.17) 42 | */ 43 | private String MPEGVersion;// MPEG版本 44 | private boolean protectionBit;// true 代表别保护 帧头后有16bit CRC 45 | private int bitrate;// 比特率 46 | private int sampling;// 采样率 47 | private boolean paddingBit;// 48 | private String channelMode;// 声道模式 49 | private int bitDataSize;// 实际声音数据大小(字节) 50 | 51 | public FrameHead(byte[] head) throws Exception { 52 | // System.out.println(head.toString()); 53 | // for(int i=0;i>>3 63 | this.protectionBit = this.getProtectionBitByBit(head[1]);//CRC校验,第16位,第二个字节byte[1],b&00000001 64 | this.bitrate = this.getBitrateByBit(head[2]);//比特率(码率),第17到20位,第三个字节byte[2],b&11110000>>>4 65 | // int getSampling=this.getSamplingByBit(head[2]); 66 | // if(getSampling>0)this.sampling = getSampling; 67 | // //有的帧采样率无值(-1)(怀疑被压缩)的继承上一个,-1的时候比特率都是96000,不能这样,压缩的,getBit会出错比特率=采样率*12*声道数 68 | this.sampling=this.getSamplingByBit(head[2]);//采样率(码率),第21到22位,第三个字节byte[2],b&00001100>>>2 69 | this.paddingBit = this.getPaddingBitByBit(head[2]);//是否填充空白字,第23位,第三个字节byte[2],b&00000010 70 | this.channelMode = this.getChannelModeByBit(head[3]);//声道模式,第25到26位,第四个字节byte[3],b&11110000>>>4 71 | this.bitDataSize = this.getBitDataSizeByBit(); 72 | 73 | // System.out.println("bitrate:"+bitrate+" sampling:"+sampling+" channelMode:"+channelMode+" bitDataSize:"+bitDataSize); 74 | 75 | } 76 | 77 | public int getBitDataSize() { 78 | return bitDataSize; 79 | } 80 | 81 | public int getBitrate() { 82 | return bitrate; 83 | } 84 | 85 | public String getChannelMode() { 86 | return channelMode; 87 | } 88 | 89 | public String getMPEGVersion() { 90 | return MPEGVersion; 91 | } 92 | 93 | public boolean isPaddingBit() { 94 | return paddingBit; 95 | } 96 | 97 | public boolean isProtectionBit() { 98 | return protectionBit; 99 | } 100 | 101 | public int getSampling() { 102 | return sampling; 103 | } 104 | 105 | // 所有的位操作在private方法进行 106 | private String getMPEGVersionByBit(byte b) {//12到13位,第二个字节byte[1] 107 | b = (byte) ((b & 24) >>> 3);// b&00011000 108 | if (b == 0) 109 | return "MPEG2.5"; 110 | else if (b == 1) 111 | return "保留"; 112 | else if (b == 2) 113 | return "MPEG2"; 114 | else if (b == 3) 115 | return "MPEG1"; 116 | else 117 | return "ERROR"; 118 | } 119 | 120 | private boolean getProtectionBitByBit(byte b) {// 121 | b = (byte) (b & 1);// b&00000001 122 | if (b == 0) 123 | return true; 124 | else 125 | return false; 126 | } 127 | 128 | private int getBitrateByBit(byte b) {//17到20位 129 | /* 130 | * 0000 free free free free free free 0001 32 32 32 32 32 8 (8) 0010 131 | * 64 48 40 64 48 16 (16) 0011 96 56 48 96 56 24 (24) 0100 128 64 56 132 | * 128 64 32 (32) 0101 160 80 64 160 80 64 (40) 0110 192 96 80 192 133 | * 96 80 (48) 0111 224 112 96 224 112 56 (56) 1000 256 128 112 256 134 | * 128 64 (64) 1001 288 160 128 288 160 128 (80) 1010 320 192 160 135 | * 320 192 160 (96) 1011 352 224 192 352 224 112 (112) 1100 384 256 136 | * 224 384 256 128 (128) 1101 416 320 256 416 320 256 (144) 1110 448 137 | * 384 320 448 384 320 (160) 1111 bad bad bad bad bad bad 138 | */ 139 | b = (byte) ((b & 240) >>> 4);// b&11110000 140 | if (b == 0) { 141 | return 0; 142 | } else if (b == 1) 143 | return 8000; 144 | else if (b == 2) 145 | return 16000; 146 | else if (b == 3) 147 | return 24000; 148 | else if (b == 4) 149 | return 32000; 150 | else if (b == 5) 151 | return 40000; 152 | else if (b == 6) 153 | return 48000; 154 | else if (b == 7) 155 | return 56000; 156 | else if (b == 8) 157 | return 64000; 158 | else if (b == 9) 159 | return 80000; 160 | else if (b == 10) 161 | return 96000; 162 | else if (b == 11) 163 | return 112000; 164 | else if (b == 12) 165 | return 128000; 166 | else if (b == 13) 167 | return 144000; 168 | else if (b == 14) 169 | return 160000; 170 | else if (b == 15) 171 | return -1; 172 | else 173 | return -1; 174 | 175 | } 176 | 177 | private int getSamplingByBit(byte b) { 178 | /* 179 | * bits MPEG1 MPEG2 MPEG2.5 00 44100 22050 11025 01 48000 24000 180 | * 12000 10 32000 16000 8000 11 reserv reserv reserv 181 | */ 182 | b = (byte) ((b & 12) >>> 2);// 00001100 183 | if (b == 0) { 184 | if (this.MPEGVersion.equals("MPEG1")) 185 | return 44100; 186 | else if (this.MPEGVersion.equals("MPEG2")) 187 | return 22050; 188 | else if (this.MPEGVersion.equals("MPEG2.5")) 189 | return 11025; 190 | else 191 | return -1; 192 | } else if (b == 1) { 193 | if (this.MPEGVersion.equals("MPEG1")) 194 | return 48000; 195 | else if (this.MPEGVersion.equals("MPEG2")) 196 | return 24000; 197 | else if (this.MPEGVersion.equals("MPEG2.5")) 198 | return 12000; 199 | else 200 | return -1; 201 | } else if (b == 2) { 202 | if (this.MPEGVersion.equals("MPEG1")) 203 | return 32000; 204 | else if (this.MPEGVersion.equals("MPEG2")) 205 | return 16000; 206 | else if (this.MPEGVersion.equals("MPEG2.5")) 207 | return 8000; 208 | else 209 | return -1; 210 | } else 211 | return -1; 212 | } 213 | 214 | private boolean getPaddingBitByBit(byte b) { 215 | b = (byte) ((b & 2) >>> 1);// 00000010 216 | if (b == 1 && this.sampling == 44100) 217 | return true;// ?? 218 | else 219 | return false; 220 | } 221 | 222 | private String getChannelModeByBit(byte b) { 223 | /* (00 - 立体声) (01 - 联合立体声) (11 - 双通道) (11 - 单通道) */ 224 | b = (byte) ((b & 192) >>> 6);// 11000000 225 | if (b == 0) 226 | return "立体声"; 227 | else if (b == 1) 228 | return "联合立体声"; 229 | else if (b == 2) 230 | return "双声道"; 231 | else if (b == 3) 232 | return "单声道"; 233 | else 234 | return "ERROR"; 235 | } 236 | 237 | private int getBitDataSizeByBit() { 238 | // (((MpegVersion == MPEG1 ? 144 : 72) * Bitrate) / SamplingRate) + 239 | // PaddingBit 240 | 241 | /*帧长度是压缩时每一帧的长度, 包括帧头。这里采用LayerIII,,不同layer编码器不一样,表示层 242 | * LayerI空位长4字节,使用公式:帧长度(字节) = (( 每帧采样数/ 8 * 比特率 ) / 采样频率 ) + 填充 * 4 243 | * LayerII和LayerIII使用公式:帧长度(字节)= (( 每帧采样数/ 8 * 比特率 ) / 采样频率 ) + 填充 244 | * 每帧采样数:MPEG1 MPEG2 MPEG2.5 245 | * Layer2 1152 1152 1152 246 | * Layer3 1152 576 576 247 | * 248 | * 第一帧帧头 100 -65 -63 -17 249 | * 二进制源码1100100 11000001 10111111 10010001 250 | * 补码(最高位不变取反加一)1100100 10111111 11000001 11101111 251 | * 第12到13位:版本,其值为11 ->MPEG 1 第14到15位:层,其值为01->Layer 3 252 | * 帧长度(字节)= ( 每帧采样数/ 采样频率 )*比特率 /8 + 填充 253 | * 帧长度*8/采样率 254 | * */ 255 | //System.out.println(this.MPEGVersion); 256 | 257 | //已除以8,单位是字节 258 | 259 | int size =0; 260 | if(bitrate<=0) 261 | if (sampling > 0) 262 | size = (int) ((this.MPEGVersion.equals("MPEG1") ? 144 : 72) * 128000 / this.sampling); 263 | else 264 | size = (int) ((this.MPEGVersion.equals("MPEG1") ? 144 : 72) * 128000 / 44100);//1152/8*采样率/441000 265 | else{ 266 | if (sampling > 0) 267 | size = (int) ((this.MPEGVersion.equals("MPEG1") ? 144 : 72) * this.bitrate / this.sampling); 268 | else 269 | size = (int) ((this.MPEGVersion.equals("MPEG1") ? 144 : 72) * this.bitrate / 44100);//1152/8*采样率/441000 270 | } 271 | if (this.paddingBit)//是否填充空白字 272 | return size + 1; 273 | else 274 | return size; 275 | } 276 | 277 | }// inner Class 278 | 279 | }// outer Class 280 | 281 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/free/Mp3Handle/Mp3FileReader.java: -------------------------------------------------------------------------------- 1 | package com.example.free.Mp3Handle; 2 | 3 | 4 | import java.io.BufferedInputStream; 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.FileNotFoundException; 8 | import java.io.IOException; 9 | import java.util.ArrayList; 10 | import java.util.HashMap; 11 | import java.util.LinkedList; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | import com.example.free.Classes.HandleData; 16 | import com.example.free.Mp3Handle.FrameData; 17 | 18 | //import iface.PrivateInfo; 19 | //import iface.PublicInfo; 20 | 21 | public class Mp3FileReader { 22 | private static Map style = new HashMap(); 23 | 24 | private Mp3FileReader.SongInfo songInfo; 25 | private Mp3FileReader.DataInfo dataInfo; 26 | 27 | private List frameList;//数据内容 28 | byte[] data = null; 29 | // int[][] data1 = null; 30 | int dataLength = 0; 31 | int sampling = 44100; 32 | ArrayList allTime=new ArrayList<>(); 33 | //ArrayList samplings=new ArrayList<>(); 34 | //ArrayList initTimes=new ArrayList<>(); 35 | final int EACHHANDLE=1280;//byte,10240bit 1帧120*2byte,1920bit,十帧一处理 36 | 37 | /** 38 | * 主要分为开头音频信息,标签(标签头 标签内容组),数据(帧头,帧内容组),结尾歌曲信息 39 | **/ 40 | 41 | public Mp3FileReader(String filename) { 42 | 43 | File file = new File(filename); 44 | byte[] bufLast = new byte[128];// 结尾128字节 45 | byte[] bufFront = new byte[10];// 开头10字节 46 | byte[] bufFrame = null;// 中间数据帧 47 | byte[] headLabel = null;// 标签帧(未知长度和帧数) 48 | try { 49 | FileInputStream is = new FileInputStream(file); 50 | BufferedInputStream bis = new BufferedInputStream(is); 51 | try { 52 | System.out.println("here is label head"); 53 | is.read(bufFront, 0, 10); 54 | this.dataInfo = new Mp3FileReader.DataInfo(bufFront);//标签头 版本号 标签大小之类的 55 | 56 | System.out.println("here is label inner"); 57 | headLabel = new byte[this.dataInfo.getSize()]; 58 | is.read(headLabel, 0, headLabel.length);//往下读标签长度的字节,得到标签内容,赋值给headLabel 59 | this.ID3ByHeadList(headLabel);//得到标签信息(标题 作者等)return Map(name,data) 60 | 61 | System.out.println("here is data"); 62 | bufFrame = new byte[(int) (file.length() - 128 - 10 - headLabel.length)];//总长度-结尾128-标签头10-标签,,数据不太符合 63 | is.read(bufFrame, 0, bufFrame.length); 64 | this.analyseFrame(bufFrame);//一帧一帧读,赋值给frameList 65 | 66 | System.out.println("here is last"); 67 | is.skip(file.length() - (128 + 10 + headLabel.length + bufFrame.length));//文本流跳过中间可能冗余的其他信息??? 68 | is.read(bufLast, 0, 128);//获取结尾歌曲信息 69 | this.songInfo = new Mp3FileReader.SongInfo(bufLast); 70 | System.out.println("title:"+songInfo.title+" artist:"+songInfo.artist); 71 | 72 | // int[] dataResult=getData(); 73 | // int n=dataResult.length/EACHHANDLE/8+1; 74 | // for(int i=0;i ID3ByHeadList(byte[] buf) {//得到标签帧内容 标题 作者等 273 | /* 274 | * 标签帧: | 数据名 | 数据长度 | 标记 | [真实数据] | ..... 275 | */ 276 | Map map = new HashMap(); 277 | int pix = 0; 278 | byte[] head;// 4 标识帧,说明其内容 TIT2表示内容为这首歌的标题,TPE1作者 TALB专辑 TRCK因规格是 TYER年代 279 | byte[] size;// 4 帧内容大小(只包含内容的大小) 280 | byte[] flag;// 2 存放标志 (c只读 i压缩 j加密等) 281 | int dataLeng = 0; 282 | byte[] dataBuf;// n 283 | 284 | System.out.println("buf.length:" + buf.length);//230 285 | for (; pix < buf.length; ) {//循环几组 标题组 作者组等 286 | head = new byte[4]; 287 | size = new byte[4]; 288 | flag = new byte[2]; 289 | System.arraycopy(buf, pix, head, 0, 4); 290 | pix = pix + 4; 291 | System.arraycopy(buf, pix, size, 0, 4); 292 | pix = pix + 4; 293 | System.arraycopy(buf, pix, flag, 0, 2); 294 | pix = pix + 2; 295 | dataLeng = getSizeByByte(size); 296 | if (dataLeng <= 0) 297 | return map; 298 | System.out.println(dataLeng); 299 | dataBuf = new byte[dataLeng]; 300 | dataLeng = dataLeng < buf.length - pix ? dataLeng : buf.length - pix; 301 | System.arraycopy(buf, pix, dataBuf, 0, dataLeng); 302 | pix = pix + dataLeng; 303 | map.put(new String(head), new String(dataBuf)); 304 | // System.out.println(new String(head) + " \t| " + new String(dataBuf) + " \t| " + pix); 305 | 306 | } 307 | 308 | return map; 309 | 310 | } 311 | 312 | private void analyseFrame(byte[] frameByte) throws Exception { 313 | data = new byte[frameByte.length]; 314 | int dataIndex = 0; 315 | frameList = new LinkedList(); 316 | int pix = 0; 317 | int size = 0; 318 | byte[] frameHead;// 帧头 (四字节,各位bit包含 同步信息 CRC校验 版权 采样率 声道等信息) 319 | byte[] frameData;// 数据帧 320 | int countLength=0; 321 | int countSampling=0; 322 | int initTime=0; 323 | int initTimeAfter=0; 324 | //initTimes.add(0); 325 | 326 | for (; pix < frameByte.length; ) {//一帧一帧循环 327 | frameHead = new byte[4];//帧头信息,4字节 328 | System.arraycopy(frameByte, pix, frameHead, 0, 4); 329 | pix = pix + 4; 330 | if (pix >= frameByte.length) 331 | break; 332 | //if(pix==4){ 333 | FrameData frame = new FrameData(frameHead);//帧信息类 里面只具体解析了帧头的信息,setBitData(byte[] data)数据是要外部传的 334 | size = frame.getBitSize();//大小 数据长度 335 | 336 | if (pix == 4) this.sampling = frame.getSampling(); 337 | this.dataLength += frame.getBitSize(); 338 | 339 | 340 | countLength+=size; 341 | countSampling+=size*sampling; 342 | initTimeAfter+=(int)(size*8/(sampling/1000.0)); 343 | 344 | if(countLength>= EACHHANDLE){ 345 | byte[] countData=new byte[countLength]; 346 | System.arraycopy(frameByte, pix, countData, 0, countLength); 347 | int[] countDataAfter=changeData(countData); 348 | HandleData.handleData(countDataAfter,allTime,countSampling/countLength,initTime, HandleData.WINDOW_1024,HandleData.WINDOW_SIZE_20,HandleData.MULTIPLIER_3); 349 | countLength=0; 350 | countSampling=0; 351 | initTime=initTimeAfter; 352 | } 353 | 354 | if (size <= 0) 355 | continue; 356 | // if(size<0) break;//是否注释 357 | frameData = new byte[size]; 358 | // System.out.println("SIZE:" + size + " 获取源数组开始位置:" + pix + " 新数组大小:" + frameData.length + " 长度: " 359 | // + frame.getBitSize() + " 总大小:" + frameByte.length);//SIZE:168 获取源数组开始位置:796001 新数组大小:168 长度: 168 总大小:796124 360 | //System.arraycopy(frameByte, pix, frameData, 0, frame.getBitSize()); 361 | size = size < frameByte.length - pix ? size : frameByte.length - pix; 362 | // if(frame.getSampling()<0){ 363 | // for(int f=0;f= frameByte.length) 376 | break; 377 | frame.setBitData(frameData);//给frame对象赋值数据 378 | this.frameList.add(frame); 379 | 380 | System.out.println(); 381 | // if (pix>500) break; 382 | //} 383 | } 384 | System.out.println("frameByteSize:"+frameByte.length+" dataSize:"+data.length); 385 | System.out.println("frameListSize:" + frameList.size()); 386 | } 387 | 388 | public int[] changeData(byte[] mdata){ 389 | int[] dataResult=new int[mdata.length]; 390 | for(int i=0;i getAllTime(){ 396 | return allTime; 397 | } 398 | 399 | public int getSampling(){ 400 | return sampling; 401 | } 402 | 403 | } 404 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/free/Mp3Handle/MyMp3FileReader.java: -------------------------------------------------------------------------------- 1 | package com.example.free.Mp3Handle; 2 | 3 | import java.io.BufferedInputStream; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.IOException; 7 | import java.util.ArrayList; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | public class MyMp3FileReader { 12 | private static Map style = new HashMap(); 13 | 14 | ArrayList labels=new ArrayList<>(); 15 | 16 | String filename; 17 | 18 | private FileInputStream is=null; 19 | private BufferedInputStream bis=null; 20 | 21 | private SongInfo songInfo; 22 | private DataInfo dataInfo; 23 | 24 | private byte[] data; 25 | 26 | public MyMp3FileReader(String _filename){ 27 | 28 | String[] mlabels={"AENC", "APIC", "COMM", "COMR", "ENCR", "EQUA", "ETCO", "GEOB", "GRID", "IPLS", "LINK", "MCDI", "MLLT", "OWNE", "PRIV", "PCNT", "POPM", "POSS", "RBUF", "RVAD", "RVRB", "SYLT", "SYTC", "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDAT", "TDLY", "TENC", "TEXT", "TFLT", "TIME", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED", "TOAL", "TOFN", "TOLY", "TOPE", "TORY", "TOWN", "TPE1", "TPE2", "TPE3", "TPE4", "TPOS", "TPUB", "TRCK", "TRDA", "TRSN", "TRSO", "TSIZ", "TSRC", "TSSE", "TYER", "TXXX", "UFID", "USER", "USLT", "WCOM", "WCOP", "WOAF", "WOAR", "WOAS", "WORS", "WPAY", "WPUB", "WXXX"}; 29 | for(String s:mlabels){ 30 | labels.add(s); 31 | } 32 | 33 | this.filename=_filename; 34 | File file=new File(filename); 35 | try{ 36 | is=new FileInputStream(file); 37 | //bis=new BufferedInputStream(is); 38 | 39 | //dataInfo 40 | byte[] bufFront=new byte[10]; 41 | is.read(bufFront, 0, 10); 42 | this.dataInfo = new DataInfo(bufFront);//标签头 版本号 标签大小之类的 43 | 44 | //headLabel 45 | byte[] headLabel = new byte[this.dataInfo.getSize()]; 46 | is.read(headLabel, 0, headLabel.length);//往下读标签长度的字节,得到标签内容,赋值给headLabel 47 | int headLabelLength=this.ID3ByHeadList(headLabel);//得到标签信息(标题 作者等)return Map(name,data) 48 | 49 | //data 50 | data = new byte[(int) (file.length() - 128 - 10 - headLabelLength)];//总长度-结尾128-标签头10-标签,,数据不太符合 51 | //System.out.println("----------------------data.length:"+data.length+" headLabelLength:"+headLabelLength+" headLabel:"+headLabel.length); 52 | System.arraycopy(headLabel, headLabelLength, data, 0, headLabel.length-headLabelLength); 53 | is.read(data, headLabel.length-headLabelLength, data.length-(headLabel.length-headLabelLength)); 54 | 55 | //songInfo 56 | byte[] bufLast=new byte[128]; 57 | is.read(bufLast, 0, 128);//获取结尾歌曲信息 58 | this.songInfo = new SongInfo(bufLast); 59 | //System.out.println(" ********************** song tag:"+(char)bufLast[0]+(char)bufLast[1]+(char)bufLast[2]); 60 | 61 | 62 | }catch(Exception e){ 63 | e.printStackTrace(); 64 | } 65 | } 66 | 67 | private int ID3ByHeadList(byte[] buf) {//得到标签帧内容 标题 作者等 68 | /*TSSE软硬件编码格式 69 | *APIC图片 70 | *COMM注解评论 comments 71 | *TALB专辑 72 | *TIT2歌名 内容描述 73 | *TPE1作者 74 | *TPE2乐队成员 75 | *0000*/ 76 | 77 | /* 78 | * 标签帧: | 数据名 | 数据长度 | 标记 | [真实数据] | ..... 79 | */ 80 | Map map = new HashMap(); 81 | int length=0; 82 | int pix = 0; 83 | byte[] head;// 4 标识帧,说明其内容 TIT2表示内容为这首歌的标题,TPE1作者 TALB专辑 TRCK因规格是 TYER年代 84 | byte[] size;// 4 帧内容大小(只包含内容的大小) 85 | byte[] flag;// 2 存放标志 (c只读 i压缩 j加密等) 86 | int dataLeng = 0; 87 | byte[] dataBuf;// n 88 | 89 | int dataLengEauals0=0; 90 | 91 | // System.out.println("buf.length:" + buf.length);//230 92 | for (; pix < buf.length; ) {//循环几组 标题组 作者组等 93 | head = new byte[4]; 94 | size = new byte[4]; 95 | flag = new byte[2]; 96 | System.arraycopy(buf, pix, head, 0, 4); 97 | pix = pix + 4; 98 | System.arraycopy(buf, pix, size, 0, 4); 99 | pix = pix + 4; 100 | System.arraycopy(buf, pix, flag, 0, 2); 101 | pix = pix + 2; 102 | 103 | 104 | 105 | //System.out.print("\n 标识帧,说明其内容 TIT2表示内容为这首歌的标题,TPE1作者 TALB专辑 TRCK因规格是 TYER年代:"); 106 | // for(int i=0;i0&&grantResults[0]==PackageManager.PERMISSION_GRANTED){ 89 | initMediaPlayer(); 90 | }else{ 91 | Toast.makeText(this,"you denied the permission",Toast.LENGTH_SHORT).show(); 92 | finish();//拒绝时回到上一页面 93 | } 94 | break; 95 | default: 96 | } 97 | } 98 | 99 | @Override 100 | public void onClick(View v) { 101 | switch(v.getId()){ 102 | 103 | case R.id.musicView: 104 | Intent intent=new Intent(MusicActivity.this,MusicViewActivity.class); 105 | startActivity(intent); 106 | break; 107 | 108 | case R.id.play: 109 | if(!mediaPlayer.isPlaying()) 110 | mediaPlayer.start(); 111 | break; 112 | case R.id.pause: 113 | if(mediaPlayer.isPlaying()) 114 | mediaPlayer.pause(); 115 | break; 116 | case R.id.stop: 117 | if(mediaPlayer.isPlaying()) { 118 | mediaPlayer.reset();//停止播放 119 | initMediaPlayer();//停止之后要再准备一次 //prepare start; pause start; reset prepare start, 120 | } 121 | break; 122 | case R.id.result: 123 | Toast.makeText(getApplicationContext(),"click result activity",Toast.LENGTH_SHORT).show(); 124 | Intent intent1=new Intent(MusicActivity.this,ResultActivity.class); 125 | getApplicationContext().startActivity(intent1); 126 | break; 127 | default: 128 | } 129 | } 130 | 131 | @Override 132 | protected void onDestroy() { 133 | super.onDestroy(); 134 | if(mediaPlayer!=null){ 135 | mediaPlayer.stop();//中间强制退出时,要关掉播放器 136 | mediaPlayer.release();//释放播放器所占资源 137 | 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/free/MusicViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.free; 2 | 3 | import androidx.recyclerview.widget.LinearLayoutManager; 4 | import androidx.recyclerview.widget.RecyclerView; 5 | 6 | import android.database.Cursor; 7 | import android.os.Bundle; 8 | import android.provider.MediaStore; 9 | 10 | import com.example.free.Classes.BaseActivity; 11 | import com.example.free.Classes.Music; 12 | import com.example.free.Classes.MusicAdapter; 13 | 14 | import java.util.ArrayList; 15 | import java.util.Collections; 16 | import java.util.List; 17 | 18 | public class MusicViewActivity extends BaseActivity { 19 | 20 | List musicList=new ArrayList<>(); 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_music_view); 26 | 27 | setTitle("选择歌曲"); 28 | 29 | initMusics(); 30 | 31 | RecyclerView recyclerView=findViewById(R.id.recyclerView); 32 | 33 | LinearLayoutManager layoutManager=new LinearLayoutManager(this);//线性布局管理器,可自行设置布局 34 | layoutManager.setOrientation(LinearLayoutManager.VERTICAL); 35 | recyclerView.setLayoutManager(layoutManager); 36 | 37 | MusicAdapter musicAdapter=new MusicAdapter(musicList); 38 | recyclerView.setAdapter(musicAdapter); 39 | 40 | 41 | 42 | } 43 | public void initMusics() { 44 | // if(ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) 45 | // != PackageManager.PERMISSION_GRANTED){ 46 | // //申请权限,名字与manifest里面的一致,1为请求码;需要重写onRequestPermissionsResult的得到申请权限的回调函数 47 | // ActivityCompat.requestPermissions(this,new String[]{ 48 | // Manifest.permission.WRITE_EXTERNAL_STORAGE},1 49 | // ); 50 | // //这里是需要先把文件读出来,再处理 51 | // } 52 | Cursor cursor = null; 53 | try { 54 | //这里是利用了数据库,不用从sd卡里过滤目录 55 | cursor = getApplicationContext().getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI 56 | , null, null, null, MediaStore.Audio.AudioColumns.IS_MUSIC);//这是查外存的; 57 | 58 | if (cursor != null) { 59 | while (cursor.moveToNext()) { 60 | System.out.println(cursor); 61 | String name=cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME)); 62 | //String MediaStore.Audio.Media.ARTIST;String xx.DATA;Int xx.DURATION;Long xx.SIZE 63 | String path=cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)); 64 | long size=cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE)); 65 | long time=cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION)); 66 | System.out.println("#############################"+name); 67 | System.out.println("#############################"+path); 68 | if(name!=null) 69 | if(name.contains(".wav")||name.contains(".mp3")) 70 | musicList.add(new Music(name,path,size,time)); 71 | // if(name.contains("Lov")||name.contains("克罗")||name.contains("万神纪")) 72 | // System.out.println("name:"+name+" size:"+size+" time:"+time); 73 | } 74 | } 75 | else 76 | System.out.println("********************cursor is null"); 77 | Collections.reverse(musicList); 78 | 79 | } catch (Exception e) { 80 | e.printStackTrace(); 81 | } finally { 82 | if (cursor != null) 83 | cursor.close(); 84 | } 85 | } 86 | 87 | 88 | 89 | /* 90 | public void initMusics(){ 91 | // if(ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) 92 | // != PackageManager.PERMISSION_GRANTED){ 93 | // //申请权限,名字与manifest里面的一致,1为请求码;需要重写onRequestPermissionsResult的得到申请权限的回调函数 94 | // ActivityCompat.requestPermissions(this,new String[]{ 95 | // Manifest.permission.WRITE_EXTERNAL_STORAGE},1 96 | // ); 97 | // //这里是需要先把文件读出来,再处理 98 | // } 99 | //Cursor cursor=null; 100 | try{ 101 | //cursor.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,null,null,null); 102 | //File file = new File(Environment.getExternalStorageDirectory(),"*.mp3"); 103 | 104 | // List mFiles=new ArrayList<>(); 105 | // File root = Environment.getExternalStorageDirectory().getAbsoluteFile(); 106 | // Toast.makeText(getApplicationContext(),root.getAbsolutePath(), Toast.LENGTH_SHORT).show(); 107 | // File files[] = root.listFiles(); 108 | // if (files != null) { 109 | // for (File f : files) { 110 | // if (f.isDirectory()) { 111 | // // getAllFiles(f); 112 | // } else { 113 | // if (f.getAbsolutePath().contains(".wav")) { 114 | // mFiles.add(f); 115 | // }else if (f.getAbsolutePath().contains(".ogg")){ 116 | // mFiles.add(f); 117 | // }else if (f.getAbsolutePath().contains(".mp3")){ 118 | // mFiles.add(f); 119 | // } 120 | // } 121 | // } 122 | // } 123 | List mFiles=getMusicFiles(); 124 | for(int i=0;i getMusicFiles(){ 143 | List mFiles=new ArrayList<>(); 144 | File root=new File("/mnt/sdcard"); 145 | // File root = Environment.getExternalStorageDirectory().getAbsoluteFile(); 146 | // Toast.makeText(getApplicationContext(),root.getAbsolutePath(), Toast.LENGTH_SHORT).show();//"/storage/emulated/0/: 147 | //getChildFiles(mFiles,root); 148 | //return mFiles; 149 | return getChildFiles(mFiles,root); 150 | } 151 | public List getChildFiles(List mFiles,File file){ 152 | File files[] = file.listFiles(); 153 | if (files != null) { 154 | for (File f : files) { 155 | if (f.isDirectory()) { 156 | //if(mFiles.size()<10) 157 | getChildFiles(mFiles,f); 158 | } else { 159 | // if (f.getAbsolutePath().contains(".wav")) { 160 | // mFiles.add(f); 161 | // }else if (f.getAbsolutePath().contains(".ogg")){ 162 | // mFiles.add(f); 163 | // }else 164 | if (f.getAbsolutePath().contains(".mp3")){ 165 | mFiles.add(f); 166 | } 167 | // mFiles.add(new File(mFiles.size()+"")); 168 | } 169 | } 170 | } 171 | Toast.makeText(getApplicationContext(),mFiles.size()+"",Toast.LENGTH_SHORT).show(); 172 | return mFiles; 173 | } 174 | */ 175 | 176 | 177 | } 178 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/free/OriginChoiceActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.free; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.view.View; 8 | import android.widget.Button; 9 | import android.widget.ProgressBar; 10 | import android.widget.RadioButton; 11 | import android.widget.RadioGroup; 12 | import android.widget.Toast; 13 | 14 | import com.example.free.Classes.BaseActivity; 15 | 16 | public class OriginChoiceActivity extends BaseActivity { 17 | 18 | private RadioGroup roadCounts,blockCounts,rateCounts; 19 | // private RadioButton two,four,less,more,slow,middle,fast; 20 | 21 | private int roads=2;//2 4 22 | private int blocks=1;//1 2 23 | private int rates=2;//1 2 3 24 | 25 | String musicPath; 26 | long musicSize; 27 | long musicTime; 28 | 29 | @Override 30 | protected void onCreate(Bundle savedInstanceState) { 31 | super.onCreate(savedInstanceState); 32 | setContentView(R.layout.activity_origin_choice); 33 | 34 | setTitle("选择模式"); 35 | 36 | roadCounts=findViewById(R.id.roadCounts); 37 | blockCounts=findViewById(R.id.blockCounts); 38 | rateCounts=findViewById(R.id.rateCounts); 39 | // two=findViewById(R.id.two); 40 | // four=findViewById(R.id.four); 41 | // less=findViewById(R.id.less); 42 | // more=findViewById(R.id.more); 43 | // slow=findViewById(R.id.slow); 44 | // middle=findViewById(R.id.middle); 45 | // fast=findViewById(R.id.fast); 46 | 47 | Intent intentFrom=getIntent(); 48 | musicPath=intentFrom.getStringExtra("musicPath"); 49 | musicSize=intentFrom.getLongExtra("musicSize",0); 50 | musicTime=intentFrom.getLongExtra("musicTime",musicTime); 51 | 52 | 53 | RadioGroupListener radioGroupListener=new RadioGroupListener(); 54 | roadCounts.setOnCheckedChangeListener(radioGroupListener); 55 | blockCounts.setOnCheckedChangeListener(radioGroupListener); 56 | rateCounts.setOnCheckedChangeListener(radioGroupListener); 57 | 58 | 59 | Button start=findViewById(R.id.start); 60 | start.setOnClickListener(new View.OnClickListener() { 61 | @Override 62 | public void onClick(View v) { 63 | 64 | // ProgressBar progressBar=findViewById(R.id.progressBar); 65 | // progressBar.setVisibility(View.VISIBLE); 66 | 67 | switch(roads){ 68 | case 2:{ 69 | Intent intent=new Intent(getApplicationContext(),GameActivity.class); 70 | intent.putExtra("className","OriginChoiceActivity"); 71 | // Toast.makeText(getApplicationContext(),roads+"",Toast.LENGTH_SHORT).show(); 72 | // System.out.println("******************"+ roads); 73 | intent.putExtra("blocks",blocks); 74 | intent.putExtra("rates",rates); 75 | intent.putExtra("musicPath",musicPath); 76 | intent.putExtra("musicSize", musicSize); 77 | intent.putExtra("musicTime",musicTime); 78 | startActivity(intent); 79 | break; 80 | } 81 | case 4:{ 82 | Intent intent=new Intent(getApplicationContext(),FourGameActivity.class); 83 | intent.putExtra("className","OriginChoiceActivity"); 84 | // Toast.makeText(getApplicationContext(),roads+"",Toast.LENGTH_SHORT).show(); 85 | // System.out.println("******************"+ roads); 86 | intent.putExtra("blocks",blocks); 87 | intent.putExtra("rates",rates); 88 | intent.putExtra("musicPath",musicPath); 89 | intent.putExtra("musicSize", musicSize); 90 | intent.putExtra("musicTime",musicTime); 91 | startActivity(intent); 92 | break; 93 | } 94 | default: 95 | } 96 | 97 | } 98 | }); 99 | 100 | 101 | 102 | 103 | Button advancedChoice=findViewById(R.id.advancedChoice); 104 | advancedChoice.setOnClickListener(new View.OnClickListener() { 105 | @Override 106 | public void onClick(View v) { 107 | Intent intent=new Intent(getApplicationContext(),ChoiceActivity.class); 108 | intent.putExtra("musicPath",musicPath); 109 | intent.putExtra("musicSize", musicSize); 110 | intent.putExtra("musicTime",musicTime); 111 | startActivity(intent); 112 | } 113 | }); 114 | 115 | } 116 | 117 | class RadioGroupListener implements RadioGroup.OnCheckedChangeListener{ 118 | @Override 119 | public void onCheckedChanged(RadioGroup group, int checkedId) { 120 | if(group==roadCounts){ 121 | switch (checkedId){ 122 | case R.id.two: 123 | roads=2;break; 124 | case R.id.four: 125 | roads=4;break; 126 | default: 127 | } 128 | } 129 | else{ 130 | if(group==blockCounts){ 131 | switch (checkedId){ 132 | case R.id.less: 133 | blocks=1;break; 134 | case R.id.more: 135 | blocks=2;break; 136 | default: 137 | } 138 | } 139 | else{//rateCounts 140 | switch (checkedId){ 141 | case R.id.slow: 142 | rates=1;break; 143 | case R.id.middle: 144 | rates=2;break; 145 | case R.id.fast: 146 | rates=3;break; 147 | default: 148 | } 149 | } 150 | } 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/free/ResultActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.free; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.widget.Button; 7 | import android.widget.TextView; 8 | 9 | import com.example.free.Classes.BaseActivity; 10 | 11 | public class ResultActivity extends BaseActivity { 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_result); 17 | 18 | setTitle("得分"); 19 | 20 | // Button forceOffline=findViewById(R.id.forceOffline); 21 | // forceOffline.setOnClickListener(new View.OnClickListener() { 22 | // @Override 23 | // public void onClick(View v) { 24 | // Intent intent=new Intent("force_offline"); 25 | // sendBroadcast(intent); 26 | // 27 | // } 28 | // }); 29 | 30 | Intent intent=getIntent(); 31 | 32 | TextView wholeScore=findViewById(R.id.result_wholeScore); 33 | wholeScore.setText("WholeScore:"+intent.getIntExtra("wholeScore",0)); 34 | TextView score=findViewById(R.id.result_score); 35 | score.setText("Score:"+intent.getIntExtra("resultScore",0)); 36 | TextView bestTimes=findViewById(R.id.result_bestTimes); 37 | bestTimes.setText("Best:"+intent.getIntExtra("bestTimes",0)); 38 | TextView goodTimes=findViewById(R.id.result_goodTimes); 39 | goodTimes.setText("Good:"+intent.getIntExtra("goodTimes",0)); 40 | TextView missTimes=(findViewById(R.id.result_missTimes)); 41 | missTimes.setText("Miss:"+intent.getIntExtra("missTimes",0)); 42 | 43 | 44 | 45 | } 46 | 47 | @Override 48 | protected void onDestroy() { 49 | super.onDestroy(); 50 | Intent intent=new Intent("force_offline"); 51 | sendBroadcast(intent); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/free/WavHandle/WaveFileReader.java: -------------------------------------------------------------------------------- 1 | package com.example.free.WavHandle; 2 | 3 | import java.io.*; 4 | 5 | public class WaveFileReader { 6 | private String filename = null; 7 | private int[][] data = null; 8 | 9 | private int len = 0; 10 | 11 | private String chunkdescriptor = null; 12 | static private int lenchunkdescriptor = 4; 13 | 14 | private long chunksize = 0; 15 | static private int lenchunksize = 4; 16 | 17 | private String waveflag = null; 18 | static private int lenwaveflag = 4; 19 | 20 | 21 | private String fmtubchunk = null; 22 | static private int lenfmtubchunk = 4; 23 | 24 | private long subchunk1size = 0; 25 | static private int lensubchunk1size = 4; 26 | 27 | private int audioformat = 0; 28 | static private int lenaudioformat = 2; 29 | 30 | private int numchannels = 0; 31 | static private int lennumchannels = 2; 32 | 33 | private long samplerate = 0; 34 | static private int lensamplerate = 2; 35 | 36 | private long byterate = 0; 37 | static private int lenbyterate = 4; 38 | 39 | private int blockalign = 0; 40 | static private int lenblockling = 2; 41 | 42 | private int bitspersample = 0; 43 | static private int lenbitspersample = 2; 44 | 45 | private String datasubchunk = null; 46 | static private int lendatasubchunk = 4; 47 | 48 | private long subchunk2size = 0; 49 | static private int lensubchunk2size = 4; 50 | 51 | 52 | private FileInputStream fis = null; 53 | private BufferedInputStream bis = null; 54 | 55 | private boolean issuccess = false; 56 | 57 | public WaveFileReader(String filename) { 58 | 59 | this.initReader(filename); 60 | } 61 | 62 | // 判断是否创建wav读取器成功 63 | public boolean isSuccess() { 64 | return issuccess; 65 | } 66 | 67 | // 获取每个采样的编码长度,8bit或者16bit 68 | public int getBitPerSample(){ 69 | return this.bitspersample; 70 | } 71 | 72 | // 获取采样率 73 | public long getSampleRate(){ 74 | return this.samplerate; 75 | } 76 | 77 | // 获取声道个数,1代表单声道 2代表立体声 78 | public int getNumChannels(){ 79 | return this.numchannels; 80 | } 81 | 82 | // 获取数据长度,也就是一共采样多少个 83 | public int getDataLen(){ 84 | return this.len; 85 | } 86 | 87 | // 获取数据 88 | // 数据是一个二维数组,[n][m]代表第n个声道的第m个采样值 89 | public int[][] getData(){ 90 | return this.data; 91 | } 92 | 93 | private void initReader(String filename){ 94 | this.filename = filename; 95 | 96 | try { 97 | fis = new FileInputStream(this.filename);//读取文件 98 | bis = new BufferedInputStream(fis);//转为二进制流 99 | 100 | //块描述符,前四个字节,判断是不是wave文件,wave数据块chunk由两个子数据块subchunk组成 101 | this.chunkdescriptor = readString(lenchunkdescriptor);//lenchunkdescriptor=4; 102 | //System.out.print(chunkdescriptor+" ");//"RIFF" 103 | if(!chunkdescriptor.endsWith("RIFF")) 104 | throw new IllegalArgumentException("RIFF miss, " + filename + " is not a wave file."); 105 | 106 | //readLong()都是四字节四字节读的,readInt()都是两字节两字节读的,,这与wave文件格式有关 107 | this.chunksize = readLong();//总长度 108 | //System.out.print(chunksize+" ");//8398 109 | this.waveflag = readString(lenwaveflag);//lenwaveflag=4; 110 | //System.out.print(waveflag+" ");//"WAVE" 111 | if(!waveflag.endsWith("WAVE")) 112 | throw new IllegalArgumentException("WAVE miss, " + filename + " is not a wave file."); 113 | 114 | 115 | this.fmtubchunk = readString(lenfmtubchunk); 116 | //System.out.print(fmtubchunk+" ");//"fmt " 117 | if(!fmtubchunk.endsWith("fmt ")) 118 | throw new IllegalArgumentException("fmt miss, " + filename + " is not a wave file."); 119 | 120 | this.subchunk1size = readLong();//第一个子数据块说明数据的结构,子数据块长度为16字节 121 | //System.out.print(subchunk1size+" ");//16 122 | 123 | /**fmt-subchunk*/ 124 | this.audioformat = readInt();//格式种类,值为1时为线性PCM编码 125 | //System.out.print(audioformat+" ");//1 126 | this.numchannels = readInt();//声道数,1为单声道,2为双声道 127 | //System.out.print(numchannels+" ");//1 128 | this.samplerate = readLong();//采样率,一秒钟采样次数 129 | //System.out.print(samplerate+" ");//16000 130 | this.byterate = readLong();//字节率,波形数据传输速率 131 | //System.out.print(byterate+" ");//32000 132 | this.blockalign = readInt();//data数据块长度(声道数*采样精度/8),这里为2,是16位单声道,数据块为 左声道低,左声道高 133 | //System.out.print(blockalign+" ");//2 134 | this.bitspersample = readInt();//采样精度,一次采样的位数,16bits,2bytes,PCM位宽 135 | //System.out.print(bitspersample+" ");//16 136 | 137 | /**data-subchunk*/ 138 | this.datasubchunk = readString(lendatasubchunk); 139 | //System.out.print(datasubchunk+" ");//"data" 140 | if(!datasubchunk.endsWith("data")) 141 | throw new IllegalArgumentException("data miss, " + filename + " is not a wave file."); 142 | this.subchunk2size = readLong(); 143 | //System.out.println(subchunk2size+" ");//8362字节 144 | 145 | this.len = (int)(this.subchunk2size/(this.bitspersample/8)/this.numchannels);//这里去掉了bitspersample,所以在采集的时候要按照8 16选择不同的读取长度。 146 | 147 | this.data = new int[this.numchannels][this.len]; 148 | /*音频数据传输编码格式是 8位双声道时 左声道 右声道 左声道 右声道,16位双声道时 左声道低 左声道高 右声道低 右声道高 (左右声道交叉) 149 | 8位单声道 左声道 左声道 16位单声道 左声道低 左声道高 左声道低 左声道高 */ 150 | 151 | 152 | for(int i=0; i>右移 11>>1=1 215 | * */ 216 | 217 | private long readLong(){ 218 | long res = 0; 219 | try { 220 | long[] l = new long[4]; 221 | for(int i=0; i<4; ++i){ 222 | l[i] = bis.read(); 223 | //System.out.print("'"+l[i]);//206 32 0 0 224 | if(l[i]==-1){ 225 | throw new IOException("no more data!!!"); 226 | } 227 | } 228 | res = l[0] | (l[1]<<8) | (l[2]<<16) | (l[3]<<24);//8398 206+32*2^8 229 | } catch (IOException e) { 230 | e.printStackTrace(); 231 | } 232 | return res; 233 | } 234 | 235 | private byte[] readBytes(int len){ 236 | byte[] buf = new byte[len]; 237 | try { 238 | if(bis.read(buf)!=len) 239 | throw new IOException("no more data!!!"); 240 | } catch (IOException e) { 241 | e.printStackTrace(); 242 | } 243 | return buf; 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /app/src/main/res/anim/anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/_b2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyrh-git/Free/4714064eb2124c02f3523ee6a0122e246b1a6680/app/src/main/res/drawable/_b2.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/_note.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyrh-git/Free/4714064eb2124c02f3523ee6a0122e246b1a6680/app/src/main/res/drawable/_note.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/_r3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyrh-git/Free/4714064eb2124c02f3523ee6a0122e246b1a6680/app/src/main/res/drawable/_r3.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/b1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyrh-git/Free/4714064eb2124c02f3523ee6a0122e246b1a6680/app/src/main/res/drawable/b1.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/b_bottom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyrh-git/Free/4714064eb2124c02f3523ee6a0122e246b1a6680/app/src/main/res/drawable/b_bottom.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_auto.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/r2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyrh-git/Free/4714064eb2124c02f3523ee6a0122e246b1a6680/app/src/main/res/drawable/r2.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/r4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyrh-git/Free/4714064eb2124c02f3523ee6a0122e246b1a6680/app/src/main/res/drawable/r4.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout-land/activity_four_game.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 29 | 30 | 41 | 42 | 43 | 44 | 51 | 52 | 53 | 59 | 68 | 69 | 70 | 76 | 85 | 86 | 92 | 101 | 102 | 108 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 139 | 140 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 24 | 25 | 37 | 38 | 60 | 61 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_choice.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 24 | 33 | 34 | 38 | 47 | 57 | 58 | 59 | 63 | 72 | 82 | 83 | 84 | 88 | 97 | 107 | 108 | 112 | 121 | 131 | 132 | 133 | 138 | 139 | 27 | 28 | 39 | 40 | 41 | 42 | 43 | 50 | 51 | 52 | 58 | 67 | 68 | 69 | 75 | 84 | 85 | 86 | 87 | 88 | 104 | 105 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 76 | 88 | 89 | 90 | 98 | 111 | 112 | 113 | 114 | 115 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_music.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 26 | 33 | 40 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_music_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_origin_choice.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 23 | 24 | 30 | 40 | 41 | 50 | 51 | 52 | 53 | 54 | 58 | 65 | 66 | 72 | 82 | 83 | 92 | 93 | 94 | 95 | 96 | 100 | 107 | 108 | 114 | 123 | 124 | 134 | 135 | 144 | 145 | 146 | 147 | 148 | 153 | 154 | 159 | 168 | 169 | 170 | 175 | 176 | 186 | 187 | 188 | 189 | 190 | 195 | 196 | 197 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_result.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 19 | 20 | 21 | 32 | 33 | 34 | 35 | 40 | 41 | 51 | 52 | 53 | 54 | 63 | 64 | 65 | 66 | 75 | 76 | 77 | 78 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /app/src/main/res/layout/music_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/toast.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/toast_land.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /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/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyrh-git/Free/4714064eb2124c02f3523ee6a0122e246b1a6680/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyrh-git/Free/4714064eb2124c02f3523ee6a0122e246b1a6680/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyrh-git/Free/4714064eb2124c02f3523ee6a0122e246b1a6680/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyrh-git/Free/4714064eb2124c02f3523ee6a0122e246b1a6680/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyrh-git/Free/4714064eb2124c02f3523ee6a0122e246b1a6680/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyrh-git/Free/4714064eb2124c02f3523ee6a0122e246b1a6680/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyrh-git/Free/4714064eb2124c02f3523ee6a0122e246b1a6680/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyrh-git/Free/4714064eb2124c02f3523ee6a0122e246b1a6680/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyrh-git/Free/4714064eb2124c02f3523ee6a0122e246b1a6680/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyrh-git/Free/4714064eb2124c02f3523ee6a0122e246b1a6680/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | #000000 7 | #ffffff 8 | #00bfff 9 | #1B8A22 10 | #333333 11 | #E0A86F 12 | #E6E8FA 13 | #D9D919 14 | #F8E097 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Free 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/com/example/free/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.example.free; 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() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | google() 6 | jcenter() 7 | 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:3.5.0' 11 | 12 | // NOTE: Do not place your application dependencies here; they belong 13 | // in the individual module build.gradle files 14 | } 15 | } 16 | 17 | allprojects { 18 | repositories { 19 | google() 20 | jcenter() 21 | 22 | } 23 | } 24 | 25 | task clean(type: Delete) { 26 | delete rootProject.buildDir 27 | } 28 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | 21 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyrh-git/Free/4714064eb2124c02f3523ee6a0122e246b1a6680/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Nov 22 19:02:56 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /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 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 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 Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | rootProject.name='Free' 3 | --------------------------------------------------------------------------------