|
@@ -5,12 +5,43 @@ import androidx.viewbinding.ViewBinding;
|
|
|
import android.content.Context;
|
|
|
import android.content.Intent;
|
|
|
import android.graphics.Color;
|
|
|
+import android.media.AudioAttributes;
|
|
|
+import android.media.AudioManager;
|
|
|
+import android.media.SoundPool;
|
|
|
import android.os.Bundle;
|
|
|
+import android.os.Handler;
|
|
|
+import android.util.Log;
|
|
|
+import android.view.View;
|
|
|
|
|
|
import com.cooleshow.base.ui.activity.BaseActivity;
|
|
|
+import com.cooleshow.metronome.constants.MetronomeConfig;
|
|
|
+import com.cooleshow.metronome.constants.MetronomeType;
|
|
|
import com.cooleshow.metronome.databinding.ActivityMetronomeLayoutBinding;
|
|
|
+import com.cooleshow.metronome.widget.CircularSeekBar;
|
|
|
|
|
|
public class MetronomeActivity extends BaseActivity<ActivityMetronomeLayoutBinding> {
|
|
|
+ public MetronomeType currentBeatType;
|
|
|
+ public int currentBeatRate = MetronomeConfig.DEFAULT_PLAY_RATE;
|
|
|
+ private SoundPool soundPool;
|
|
|
+ private int tickVoiceId;
|
|
|
+ private int tockVoiceId;
|
|
|
+
|
|
|
+ public int playPosition = 0;
|
|
|
+ private Handler mHandler = new Handler();
|
|
|
+ private Runnable mRunnable = new Runnable() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ long delayMillis = (long) (1 / (currentBeatRate / 60d) * 1000);
|
|
|
+ boolean tickOrTock = isTickOrTock();
|
|
|
+ if (tickOrTock) {
|
|
|
+ soundPool.play(tickVoiceId, 1F, 1F, 0, 0, 1F);
|
|
|
+ } else {
|
|
|
+ soundPool.play(tockVoiceId, 1F, 1F, 0, 0, 1F);
|
|
|
+ }
|
|
|
+ playPosition++;
|
|
|
+ mHandler.postDelayed(mRunnable, delayMillis);
|
|
|
+ }
|
|
|
+ };
|
|
|
|
|
|
public static void start(Context context) {
|
|
|
Intent intent = new Intent(context, MetronomeActivity.class);
|
|
@@ -25,10 +56,135 @@ public class MetronomeActivity extends BaseActivity<ActivityMetronomeLayoutBindi
|
|
|
@Override
|
|
|
protected void initView() {
|
|
|
viewBinding.toolbarInclude.toolbar.setBackgroundColor(Color.TRANSPARENT);
|
|
|
+ currentBeatType = MetronomeType.METRONOME_44_TYPE;
|
|
|
+ viewBinding.tvCurrentBeat.setText(currentBeatType.getName());
|
|
|
+ viewBinding.tvSpeed.setText(String.valueOf(currentBeatRate));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
protected ActivityMetronomeLayoutBinding getLayoutView() {
|
|
|
return ActivityMetronomeLayoutBinding.inflate(getLayoutInflater());
|
|
|
}
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void initData() {
|
|
|
+ super.initData();
|
|
|
+ initListener();
|
|
|
+ mteronomeSoundPool();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void play() {
|
|
|
+ mHandler.removeCallbacksAndMessages(null);
|
|
|
+ soundPool.stop(tickVoiceId);
|
|
|
+ soundPool.stop(tockVoiceId);
|
|
|
+ mHandler.post(mRunnable);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void mteronomeSoundPool() {
|
|
|
+
|
|
|
+ SoundPool.Builder builder = new SoundPool.Builder();
|
|
|
+ //传入最多播放音频数量,
|
|
|
+ builder.setMaxStreams(2);
|
|
|
+ //AudioAttributes是一个封装音频各种属性的方法
|
|
|
+ AudioAttributes.Builder attrBuilder = new AudioAttributes.Builder();
|
|
|
+ //设置音频流的合适的属性
|
|
|
+ attrBuilder.setLegacyStreamType(AudioManager.STREAM_MUSIC);
|
|
|
+ //加载一个AudioAttributes
|
|
|
+ builder.setAudioAttributes(attrBuilder.build());
|
|
|
+
|
|
|
+ soundPool = builder.build();
|
|
|
+
|
|
|
+ tickVoiceId = soundPool.load(this, com.daya.live_teaching.R.raw.tick, 0);
|
|
|
+ tockVoiceId = soundPool.load(this, com.daya.live_teaching.R.raw.tock, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ private int lastProgress = 0;
|
|
|
+
|
|
|
+ private void initListener() {
|
|
|
+ viewBinding.tvPlay.setOnClickListener(new View.OnClickListener() {
|
|
|
+ @Override
|
|
|
+ public void onClick(View v) {
|
|
|
+ play();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ viewBinding.cirSeekbar.setSeekBarChangeListener(new CircularSeekBar.OnSeekChangeListener() {
|
|
|
+ @Override
|
|
|
+ public void onProgressChange(CircularSeekBar view, int newProgress) {
|
|
|
+ Log.i("newProgress", "newProgress:" + newProgress);
|
|
|
+ Log.i("newProgress", "lastProgress:" + lastProgress);
|
|
|
+ int difference = newProgress - lastProgress;
|
|
|
+ if (Math.abs(difference) > 10) {
|
|
|
+ lastProgress = newProgress;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ int result = difference / MetronomeConfig.PLAY_RATE_UNIT;
|
|
|
+ if (difference < -1) {
|
|
|
+ result = -1;
|
|
|
+ }
|
|
|
+ if (difference > 1) {
|
|
|
+ result = 1;
|
|
|
+ }
|
|
|
+ if (result == 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Log.i("newProgress", "result:" + result);
|
|
|
+ if (isCanChange(result)) {
|
|
|
+ currentBeatRate += result;
|
|
|
+ } else {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (currentBeatRate < MetronomeConfig.MIN_PLAY_RATE) {
|
|
|
+ currentBeatRate = MetronomeConfig.MIN_PLAY_RATE;
|
|
|
+ }
|
|
|
+ if (currentBeatRate > MetronomeConfig.MAX_PLAY_RATE) {
|
|
|
+ currentBeatRate = MetronomeConfig.MAX_PLAY_RATE;
|
|
|
+ }
|
|
|
+ lastProgress = newProgress;
|
|
|
+ viewBinding.tvSpeed.setText(String.valueOf(currentBeatRate));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean isCanChange(int result) {
|
|
|
+ if (result < 0) {
|
|
|
+ return currentBeatRate != MetronomeConfig.MIN_PLAY_RATE;
|
|
|
+ } else {
|
|
|
+ return currentBeatRate != MetronomeConfig.MAX_PLAY_RATE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isTickOrTock() {
|
|
|
+ if (currentBeatType.getValue() == MetronomeType.METRONOME_12_TYPE.getValue() && playPosition % 1 == 0) {
|
|
|
+ return true;
|
|
|
+ } else if (currentBeatType.getValue() == MetronomeType.METRONOME_22_TYPE.getValue() && playPosition % 2 == 0) {
|
|
|
+ return true;
|
|
|
+ } else if (currentBeatType.getValue() == MetronomeType.METRONOME_14_TYPE.getValue() && playPosition % 1 == 0) {
|
|
|
+ return true;
|
|
|
+ } else if (currentBeatType.getValue() == MetronomeType.METRONOME_24_TYPE.getValue() && playPosition % 2 == 0) {
|
|
|
+ return true;
|
|
|
+ } else if (currentBeatType.getValue() == MetronomeType.METRONOME_34_TYPE.getValue() && playPosition % 3 == 0) {
|
|
|
+ return true;
|
|
|
+ } else if (currentBeatType.getValue() == MetronomeType.METRONOME_44_TYPE.getValue() && playPosition % 4 == 0) {
|
|
|
+ return true;
|
|
|
+ } else if (currentBeatType.getValue() == MetronomeType.METRONOME_38_TYPE.getValue() && playPosition % 3 == 0) {
|
|
|
+ return true;
|
|
|
+ } else if (currentBeatType.getValue() == MetronomeType.METRONOME_68_TYPE.getValue() && playPosition % 6 == 0) {
|
|
|
+ return true;
|
|
|
+ } else {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onDestroy() {
|
|
|
+ super.onDestroy();
|
|
|
+ try {
|
|
|
+ soundPool.release();
|
|
|
+ soundPool = null;
|
|
|
+ mHandler.removeCallbacksAndMessages(null);
|
|
|
+ } catch (Exception e) {
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|