Browse Source

修改调音器和节拍器新版

Pq 1 year ago
parent
commit
27e7d821f1
100 changed files with 1497 additions and 585 deletions
  1. 12 0
      BaseLibrary/src/main/res/layout/common_toolbar_layout.xml
  2. 4 5
      metronome/build.gradle
  3. 2 0
      metronome/src/main/AndroidManifest.xml
  4. 131 228
      metronome/src/main/java/com/cooleshow/metronome/MetronomeActivity.java
  5. 255 0
      metronome/src/main/java/com/cooleshow/metronome/Utils/PlayBeanManager.java
  6. 120 0
      metronome/src/main/java/com/cooleshow/metronome/Utils/SoundPoolUtils.java
  7. 4 4
      metronome/src/main/java/com/cooleshow/metronome/adapter/MetronomeAdapter.java
  8. 1 1
      metronome/src/main/java/com/cooleshow/metronome/constants/MetronomeConfig.java
  9. 11 0
      metronome/src/main/java/com/cooleshow/metronome/interfaces/IPlayBeatCallBack.java
  10. 288 152
      metronome/src/main/java/com/cooleshow/metronome/widget/CircularSeekBar.java
  11. 4 2
      metronome/src/main/res/drawable/bg_volume_seekbar.xml
  12. 5 0
      metronome/src/main/res/drawable/shape_009fff_beat_select.xml
  13. 5 0
      metronome/src/main/res/drawable/shape_00acff_27dp.xml
  14. 5 0
      metronome/src/main/res/drawable/shape_ffffff_beat_normal.xml
  15. 131 60
      metronome/src/main/res/layout/activity_metronome_layout.xml
  16. 6 6
      metronome/src/main/res/layout/item_beat_symbol_layout.xml
  17. 1 1
      metronome/src/main/res/layout/pickerview_beat_symbol_layout.xml
  18. BIN
      metronome/src/main/res/mipmap-xhdpi/bg_metronome.png
  19. BIN
      metronome/src/main/res/mipmap-xhdpi/bg_metronome2.png
  20. BIN
      metronome/src/main/res/mipmap-xhdpi/bg_metronome3.png
  21. BIN
      metronome/src/main/res/mipmap-xhdpi/bg_metronome4.png
  22. BIN
      metronome/src/main/res/mipmap-xhdpi/bg_play_beat_big.png
  23. BIN
      metronome/src/main/res/mipmap-xhdpi/icon_beat_value_bg.png
  24. BIN
      metronome/src/main/res/mipmap-xhdpi/icon_beat_volume_seekbar_thump.png
  25. BIN
      metronome/src/main/res/mipmap-xhdpi/icon_metronome_add_bt_bg.png
  26. BIN
      metronome/src/main/res/mipmap-xhdpi/icon_metronome_bt_bg.png
  27. BIN
      metronome/src/main/res/mipmap-xhdpi/icon_pause_beat_bt_tag.png
  28. BIN
      metronome/src/main/res/mipmap-xhdpi/icon_play_beat_arrow_down.png
  29. BIN
      metronome/src/main/res/mipmap-xhdpi/icon_play_beat_bt_tag.png
  30. BIN
      metronome/src/main/res/mipmap-xhdpi/icon_play_beat_title.png
  31. BIN
      metronome/src/main/res/mipmap-xhdpi/icon_progress_bar_thump.png
  32. BIN
      metronome/src/main/res/mipmap-xhdpi/icon_volume_trumpet_add.png
  33. BIN
      metronome/src/main/res/mipmap-xxhdpi/bg_metronome.png
  34. BIN
      metronome/src/main/res/mipmap-xxhdpi/bg_metronome2.png
  35. BIN
      metronome/src/main/res/mipmap-xxhdpi/bg_metronome3.png
  36. BIN
      metronome/src/main/res/mipmap-xxhdpi/bg_metronome4.png
  37. BIN
      metronome/src/main/res/mipmap-xxhdpi/bg_play_beat_big.png
  38. BIN
      metronome/src/main/res/mipmap-xxhdpi/icon_beat_value_bg.png
  39. BIN
      metronome/src/main/res/mipmap-xxhdpi/icon_beat_volume_seekbar_thump.png
  40. BIN
      metronome/src/main/res/mipmap-xxhdpi/icon_metronome_add_bt_bg.png
  41. BIN
      metronome/src/main/res/mipmap-xxhdpi/icon_metronome_bt_bg.png
  42. BIN
      metronome/src/main/res/mipmap-xxhdpi/icon_pause_beat_bt_tag.png
  43. BIN
      metronome/src/main/res/mipmap-xxhdpi/icon_play_beat_arrow_down.png
  44. BIN
      metronome/src/main/res/mipmap-xxhdpi/icon_play_beat_bt_tag.png
  45. BIN
      metronome/src/main/res/mipmap-xxhdpi/icon_play_beat_title.png
  46. BIN
      metronome/src/main/res/mipmap-xxhdpi/icon_progress_bar_thump.png
  47. BIN
      metronome/src/main/res/mipmap-xxhdpi/icon_volume_trumpet_add.png
  48. BIN
      metronome/src/main/res/raw/tick.wav
  49. BIN
      metronome/src/main/res/raw/tock.wav
  50. 7 0
      metronome/src/main/res/values/colors.xml
  51. 4 1
      metronome/src/main/res/values/themes.xml
  52. 5 4
      musictuner/build.gradle
  53. 2 0
      musictuner/src/main/AndroidManifest.xml
  54. 128 17
      musictuner/src/main/java/com/cooleshow/musictuner/MusicTunerActivity.java
  55. 21 6
      musictuner/src/main/java/com/cooleshow/musictuner/constants/MusicTunerConstants.java
  56. 18 13
      musictuner/src/main/java/com/cooleshow/musictuner/utils/VoiceDataUtils.java
  57. 314 84
      musictuner/src/main/java/com/cooleshow/musictuner/widget/DashBoardView.java
  58. 5 0
      musictuner/src/main/java/com/cooleshow/musictuner/widget/MusicTunerSettingDialog.java
  59. 8 1
      musictuner/src/main/java/com/cooleshow/musictuner/widget/MusicTuningForkDialog.java
  60. BIN
      musictuner/src/main/res/drawable-xhdpi/bg_dash_board2.png
  61. BIN
      musictuner/src/main/res/drawable-xhdpi/bg_music_fork.png
  62. BIN
      musictuner/src/main/res/drawable-xhdpi/bg_music_tuner_bottom.png
  63. BIN
      musictuner/src/main/res/drawable-xhdpi/bg_music_tuner_main.png
  64. BIN
      musictuner/src/main/res/drawable-xhdpi/bg_tuner_music.png
  65. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_arrow_top_bottom.png
  66. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_bottom_hole.png
  67. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_metronome_speed_bg.png
  68. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_music_hole.png
  69. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_music_hz_add.png
  70. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_music_hz_reduce.png
  71. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_music_menu_normal.png
  72. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_music_menu_select.png
  73. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_music_tuner_correct_tag.png
  74. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_music_tuner_normal.png
  75. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_music_tuner_select.png
  76. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_music_tuner_setting.png
  77. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_music_tuner_title.png
  78. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_music_tuner_triangle_small.png
  79. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_pause_metronome_bt.png
  80. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_play_beat_speed_tag.png
  81. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_play_metronome_bt.png
  82. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_transposing_tag.png
  83. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_triangle_arrow_blue.png
  84. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_tuning_fork.png
  85. BIN
      musictuner/src/main/res/drawable-xhdpi/icon_tuning_fork_normal.png
  86. BIN
      musictuner/src/main/res/drawable-xhdpi/tm_icon_add_symbol.png
  87. BIN
      musictuner/src/main/res/drawable-xhdpi/tm_icon_reduce_symbol.png
  88. BIN
      musictuner/src/main/res/drawable-xxhdpi/bg_dash_board2.png
  89. BIN
      musictuner/src/main/res/drawable-xxhdpi/bg_music_fork.png
  90. BIN
      musictuner/src/main/res/drawable-xxhdpi/bg_music_tuner_bottom.png
  91. BIN
      musictuner/src/main/res/drawable-xxhdpi/bg_music_tuner_main.png
  92. BIN
      musictuner/src/main/res/drawable-xxhdpi/bg_tuner_music.png
  93. BIN
      musictuner/src/main/res/drawable-xxhdpi/icon_arrow_top_bottom.png
  94. BIN
      musictuner/src/main/res/drawable-xxhdpi/icon_bottom_hole.png
  95. BIN
      musictuner/src/main/res/drawable-xxhdpi/icon_metronome_speed_bg.png
  96. BIN
      musictuner/src/main/res/drawable-xxhdpi/icon_music_hole.png
  97. BIN
      musictuner/src/main/res/drawable-xxhdpi/icon_music_hz_add.png
  98. BIN
      musictuner/src/main/res/drawable-xxhdpi/icon_music_hz_reduce.png
  99. BIN
      musictuner/src/main/res/drawable-xxhdpi/icon_music_menu_normal.png
  100. BIN
      musictuner/src/main/res/drawable-xxhdpi/icon_music_menu_select.png

+ 12 - 0
BaseLibrary/src/main/res/layout/common_toolbar_layout.xml

@@ -36,6 +36,18 @@
         tools:text="我的课程" />
 
     <ImageView
+        android:visibility="gone"
+        android:id="@+id/iv_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerInParent="true"
+        android:layout_gravity="center"
+        android:textColor="@color/white"
+        android:textSize="@dimen/sp_18"
+        android:textStyle="bold"
+        tools:text="我的课程" />
+
+    <ImageView
         android:id="@+id/tv_right"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"

+ 4 - 5
metronome/build.gradle

@@ -39,10 +39,10 @@ android {
             minifyEnabled false
             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
         }
-        preRelease{
-            minifyEnabled false
-            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
-        }
+//        preRelease{
+//            minifyEnabled false
+//            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+//        }
     }
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_1_8
@@ -61,7 +61,6 @@ dependencies {
     testImplementation 'junit:junit:4.13.2'
     androidTestImplementation 'androidx.test.ext:junit:1.1.3'
     implementation project(':BaseLibrary')
-    implementation project(':classRoom')
     //ARouter
     annotationProcessor("com.alibaba:arouter-compiler:$rootProject.ext.android.arouter_api_version")
     implementation 'com.alibaba:arouter-api:1.5.2'

+ 2 - 0
metronome/src/main/AndroidManifest.xml

@@ -5,6 +5,8 @@
     <application>
         <activity
             android:name=".MetronomeActivity"
+            android:configChanges="orientation|screenSize|keyboardHidden|fontScale|smallestScreenSize|screenLayout"
+            android:screenOrientation="portrait"
             android:exported="false"/>
     </application>
 

+ 131 - 228
metronome/src/main/java/com/cooleshow/metronome/MetronomeActivity.java

@@ -8,7 +8,6 @@ import android.media.AudioManager;
 import android.media.SoundPool;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.SystemClock;
 import android.util.Log;
 import android.view.View;
 import android.widget.SeekBar;
@@ -19,13 +18,14 @@ import com.bigkoo.pickerview.builder.OptionsPickerBuilder;
 import com.bigkoo.pickerview.view.OptionsPickerView;
 import com.cooleshow.base.router.RouterPath;
 import com.cooleshow.base.ui.activity.BaseActivity;
-import com.cooleshow.base.utils.LOG;
 import com.cooleshow.base.utils.helper.QMUIStatusBarHelper;
+import com.cooleshow.metronome.Utils.PlayBeanManager;
 import com.cooleshow.metronome.Utils.VolumeManager;
 import com.cooleshow.metronome.adapter.MetronomeAdapter;
 import com.cooleshow.metronome.constants.MetronomeConfig;
 import com.cooleshow.metronome.constants.MetronomeType;
 import com.cooleshow.metronome.databinding.ActivityMetronomeLayoutBinding;
+import com.cooleshow.metronome.interfaces.IPlayBeatCallBack;
 import com.cooleshow.metronome.widget.CircularSeekBar;
 
 import java.util.ArrayList;
@@ -34,44 +34,12 @@ import java.util.List;
 import androidx.recyclerview.widget.LinearLayoutManager;
 
 @Route(path = RouterPath.Other.METRONOME_PAGE)
-public class MetronomeActivity extends BaseActivity<ActivityMetronomeLayoutBinding> implements View.OnClickListener, VolumeManager.VolumeChangeListener {
-    public MetronomeType currentBeatType;
-    public int currentBeatRate = MetronomeConfig.DEFAULT_PLAY_RATE;
-    public float currentNoteRate = MetronomeConfig.DEFAULT_NOTE_RATE;
-    private SoundPool soundPool;
-    private int tickVoiceId;
-    private int tockVoiceId;
+public class MetronomeActivity extends BaseActivity<ActivityMetronomeLayoutBinding> implements View.OnClickListener, VolumeManager.VolumeChangeListener, IPlayBeatCallBack {
     private OptionsPickerView pvOptions;
-    private int playPosition = 0;
-    private boolean isPlaying = false;
-    private Handler mHandler = new Handler();
-    private Runnable mRunnable = new Runnable() {
-        @Override
-        public void run() {
-            long delayMillis = (long) (1 / (currentBeatRate / 60d) * 1000 * currentNoteRate);
-            long next = MetronomeConfig.MIN_COUNT_TIME_SPACE;
-            long l = System.currentTimeMillis();
-            if (totalTime == -1) {
-                handleMusic(delayMillis,l);
-            } else {
-                if (Math.abs(Math.abs(l - totalTime)-delayMillis) < next) {
-                    next =0;
-                }
-                if (Math.abs(l -totalTime) >= delayMillis) {
-                    handleMusic(delayMillis,l);
-                }
-            }
-            mHandler.postDelayed(mRunnable, next);
-        }
-    };
-
-    private long totalTime = -1;
-    private long lastTime = -1;
-
-    private List<MetronomeType> beatSymbolLists;
     private int currentSelectPosition;
     private MetronomeAdapter mMetronomeAdapter;
     private VolumeManager mVolumeManager;
+    private boolean isUpdateMode = false;//如果是更新设置的方式进入此页面,则不需要relase相关组件
 
     public static void start(Context context) {
         Intent intent = new Intent(context, MetronomeActivity.class);
@@ -86,120 +54,37 @@ public class MetronomeActivity extends BaseActivity<ActivityMetronomeLayoutBindi
 
     @Override
     protected void initView() {
-        initMidTitleToolBar(viewBinding.toolbarInclude.toolbar, "节拍器");
+        isUpdateMode = getIntent().getBooleanExtra("isUpdateMode", false);
+        initMidTitleToolBar(viewBinding.toolbarInclude.toolbar, "");
+        viewBinding.toolbarInclude.ivTitle.setVisibility(View.VISIBLE);
+        viewBinding.toolbarInclude.ivTitle.setImageResource(R.mipmap.icon_play_beat_title);
         viewBinding.toolbarInclude.toolbar.setBackgroundColor(Color.TRANSPARENT);
-        updateSpeedText();
-    }
-
-
-    private void updateSpeedText() {
-        viewBinding.tvSpeed.setText(String.valueOf(currentBeatRate));
-    }
-
-    @Override
-    protected ActivityMetronomeLayoutBinding getLayoutView() {
-        return ActivityMetronomeLayoutBinding.inflate(getLayoutInflater());
-    }
-
-    private void handleMusic(long delayMillis,long cTime) {
-        boolean tickOrTock = isTickOrTock();
-        if (lastTime != -1) {
-            long diff = cTime - lastTime;
-            LOG.i("diff:" + diff);
-        }
-        lastTime = cTime;
-        if (tickOrTock) {
-            soundPool.play(tickVoiceId, 1F, 1F, 0, 0, 1F);
-        } else {
-            soundPool.play(tockVoiceId, 1F, 1F, 0, 0, 1F);
-        }
-        if (mMetronomeAdapter != null) {
-            mMetronomeAdapter.notifyData(playPosition);
-            mHandler.postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    //实现闪烁动画效果
-                    mMetronomeAdapter.notifyData(MetronomeAdapter.DEFAULT_SELECT_POSITION);
-                }
-            }, delayMillis / 2);
-        }
-        playPosition++;
-        totalTime = cTime;
-    }
-
-    private void setBeat(MetronomeType metronomeType) {
-        currentBeatType = metronomeType;
-        viewBinding.tvCurrentBeat.setText(metronomeType.getName());
-        playPosition = 0;
-        mMetronomeAdapter.notifyData(MetronomeAdapter.DEFAULT_SELECT_POSITION);
-        mMetronomeAdapter.setCount(getBeatSymbolCount());
-        currentNoteRate = MetronomeType.getNoteSpeedValue(metronomeType);
-        int noteDrawable = MetronomeConfig.getNoteDrawable(metronomeType);
-        viewBinding.ivNote.setImageResource(noteDrawable);
-    }
-
-    private int getBeatSymbolCount() {
-        int value = currentBeatType.getValue();
-        if (value == MetronomeType.METRONOME_12_TYPE.getValue()
-                || value == MetronomeType.METRONOME_14_TYPE.getValue()) {
-            return 1;
-        }
-
-        if (value == MetronomeType.METRONOME_22_TYPE.getValue()
-                || value == MetronomeType.METRONOME_24_TYPE.getValue()) {
-            return 2;
-        }
-
-        if (value == MetronomeType.METRONOME_34_TYPE.getValue()
-                || value == MetronomeType.METRONOME_38_TYPE.getValue()) {
-            return 3;
-        }
-
-        if (value == MetronomeType.METRONOME_44_TYPE.getValue()) {
-            return 4;
-        }
-
-        if (value == MetronomeType.METRONOME_68_TYPE.getValue()) {
-            return 6;
-        }
-
-        if (value == MetronomeType.METRONOME_816_TYPE.getValue()) {
-            return 8;
-        }
-        return 0;
     }
 
     @Override
     protected void initData() {
         super.initData();
+        initListener();
         mMetronomeAdapter = new MetronomeAdapter();
         LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
         viewBinding.recyclerView.setLayoutManager(linearLayoutManager);
         viewBinding.recyclerView.setAdapter(mMetronomeAdapter);
         //set default
-        setBeat(MetronomeType.METRONOME_44_TYPE);
-        initListener();
-        mteronomeSoundPool();
-        beatSymbolLists = new ArrayList<>();
-        beatSymbolLists.add(MetronomeType.METRONOME_12_TYPE);
-        beatSymbolLists.add(MetronomeType.METRONOME_14_TYPE);
-        beatSymbolLists.add(MetronomeType.METRONOME_22_TYPE);
-        beatSymbolLists.add(MetronomeType.METRONOME_24_TYPE);
-        beatSymbolLists.add(MetronomeType.METRONOME_34_TYPE);
-        beatSymbolLists.add(MetronomeType.METRONOME_38_TYPE);
-        beatSymbolLists.add(MetronomeType.METRONOME_44_TYPE);
-        beatSymbolLists.add(MetronomeType.METRONOME_68_TYPE);
-        beatSymbolLists.add(MetronomeType.METRONOME_816_TYPE);
+        PlayBeanManager.getInstance().init(this);
+        PlayBeanManager.getInstance().setCallBackListener(this);
+        loadData();
         mVolumeManager = new VolumeManager(this);
         mVolumeManager.setVolumeChangeListener(this);
         mVolumeManager.registerReceiver();
         int streamVolume = mVolumeManager.getCurrentMusicVolume();
         int maxStreamVolume = mVolumeManager.getMaxMusicVolume();
+        setVolumeText(streamVolume);
         viewBinding.volumeSeekBar.setMax(maxStreamVolume);
         viewBinding.volumeSeekBar.setProgress(streamVolume);
         viewBinding.volumeSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
             @Override
             public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                setVolumeText(progress);
                 mVolumeManager.setCurrentMusicVolume(progress);
             }
 
@@ -215,98 +100,129 @@ public class MetronomeActivity extends BaseActivity<ActivityMetronomeLayoutBindi
         });
     }
 
-    private void play() {
-        mHandler.removeCallbacksAndMessages(null);
-        soundPool.stop(tickVoiceId);
-        soundPool.stop(tockVoiceId);
-        mHandler.post(mRunnable);
-        isPlaying = true;
-        totalTime = -1;
-        lastTime =-1;
-        viewBinding.tvPlay.setText(getString(R.string.pause_play_str));
+    private void setVolumeText(int cProgress) {
+        int maxStreamVolume = mVolumeManager.getMaxMusicVolume();
+        //转成最大值100来显示
+        int value = (int) ((cProgress * 1.0f / maxStreamVolume) * 100);
+        viewBinding.tvVolumeValue.setText(String.valueOf(value));
     }
 
-    private void pausePlay() {
-        mHandler.removeCallbacksAndMessages(null);
-        soundPool.stop(tickVoiceId);
-        soundPool.stop(tockVoiceId);
-        isPlaying = false;
-        viewBinding.tvPlay.setText(getString(R.string.play_str));
+    private void loadData() {
+        if (!isUpdateMode) {
+            setDefault();
+        }
+        setDefaultProgressBySpeed();
+        updateSpeedText();
+        MetronomeType currentBeatType = PlayBeanManager.getInstance().getCurrentBeatType();
+        int beatSymbolCount = PlayBeanManager.getInstance().getBeatSymbolCount();
+        viewBinding.tvCurrentBeat.setText(currentBeatType.getName());
+        mMetronomeAdapter.notifyData(MetronomeAdapter.DEFAULT_SELECT_POSITION);
+        mMetronomeAdapter.setCount(beatSymbolCount);
+        int noteDrawable = MetronomeConfig.getNoteDrawable(currentBeatType);
+        viewBinding.ivNote.setImageResource(noteDrawable);
+
+        boolean playing = PlayBeanManager.getInstance().isPlaying();
+        viewBinding.tvPlay.setText(getString(playing ? R.string.pause_play_str : R.string.play_str));
+        viewBinding.ivPlayStatusTag.setImageResource(playing ? R.mipmap.icon_pause_beat_bt_tag : R.mipmap.icon_play_beat_bt_tag);
     }
 
-    private void mteronomeSoundPool() {
+    private void setDefault() {
+        PlayBeanManager.getInstance().setBeat(MetronomeType.METRONOME_44_TYPE);
+        PlayBeanManager.getInstance().setCurrentBeatRate(MetronomeConfig.DEFAULT_PLAY_RATE);
+    }
 
-        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();
+    private void updateSpeedText() {
+        int currentBeatRate = PlayBeanManager.getInstance().getCurrentBeatRate();
+        viewBinding.tvSpeed.setText(String.valueOf(currentBeatRate));
+    }
 
-        tickVoiceId = soundPool.load(this, com.dayayuemeng.classroom.R.raw.tick, 0);
-        tockVoiceId = soundPool.load(this, com.dayayuemeng.classroom.R.raw.tock, 0);
+    private void setDefaultProgressBySpeed() {
+        int currentBeatRate = PlayBeanManager.getInstance().getCurrentBeatRate();
+        int totalSection = MetronomeConfig.MAX_PLAY_RATE - MetronomeConfig.MIN_PLAY_RATE;
+        int result = currentBeatRate - MetronomeConfig.MIN_PLAY_RATE;
+        float progressPercent = result * 1.0f / totalSection;
+        float progress =(progressPercent * viewBinding.cirSeekbar.getMaxProgress());
+        viewBinding.cirSeekbar.setProgress(progress);
     }
 
+    @Override
+    protected ActivityMetronomeLayoutBinding getLayoutView() {
+        return ActivityMetronomeLayoutBinding.inflate(getLayoutInflater());
+    }
+
+
     private int lastProgress = 0;
 
     private void initListener() {
         viewBinding.ivBeatValue.setOnClickListener(this);
         viewBinding.ivAdd.setOnClickListener(this);
         viewBinding.ivReduce.setOnClickListener(this);
-        viewBinding.tvPlay.setOnClickListener(new View.OnClickListener() {
+        viewBinding.llPlay.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                if (isPlaying) {
-                    pausePlay();
-                } else {
-                    play();
-                }
+                toPlayOrStop();
             }
         });
         viewBinding.cirSeekbar.setSeekBarChangeListener(new CircularSeekBar.OnSeekChangeListener() {
             @Override
-            public void onProgressChange(CircularSeekBar view, int newProgress) {
+            public void onProgressChange(CircularSeekBar view, float newProgress) {
                 Log.i("newProgress", "newProgress:" + newProgress);
                 Log.i("newProgress", "lastProgress:" + lastProgress);
-                int difference = newProgress - lastProgress;
-                if (Math.abs(difference) > 10) {
-                    lastProgress = newProgress;
-                    return;
-                }
-                lastProgress = newProgress;
-                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;
-                }
+//                int difference = newProgress - lastProgress;
+//                if (Math.abs(difference) > 10) {
+//                    lastProgress = newProgress;
+//                    return;
+//                }
+//                lastProgress = newProgress;
+//                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);
+
+                int totalSection = MetronomeConfig.MAX_PLAY_RATE - MetronomeConfig.MIN_PLAY_RATE;
+
+                int maxProgress = viewBinding.cirSeekbar.getMaxProgress();
+                float percent = newProgress / (maxProgress * 1.0f);
+
+                int currentBeatRate = (int) (Math.round(totalSection * percent)) + MetronomeConfig.MIN_PLAY_RATE;
+//                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;
                 }
+                PlayBeanManager.getInstance().setCurrentBeatRate(currentBeatRate);
                 updateSpeedText();
             }
         });
     }
 
+    private void toPlayOrStop() {
+        boolean isPlaying = PlayBeanManager.getInstance().isPlaying();
+        if (isPlaying) {
+            PlayBeanManager.getInstance().pausePlay();
+        } else {
+            PlayBeanManager.getInstance().play();
+        }
+        viewBinding.tvPlay.setText(getString(!isPlaying ? R.string.pause_play_str : R.string.play_str));
+        viewBinding.ivPlayStatusTag.setImageResource(!isPlaying ? R.mipmap.icon_pause_beat_bt_tag : R.mipmap.icon_play_beat_bt_tag);
+    }
+
     public boolean isCanChange(int result) {
+        int currentBeatRate = PlayBeanManager.getInstance().getCurrentBeatRate();
         if (result < 0) {
             return currentBeatRate != MetronomeConfig.MIN_PLAY_RATE;
         } else {
@@ -314,37 +230,15 @@ public class MetronomeActivity extends BaseActivity<ActivityMetronomeLayoutBindi
         }
     }
 
-    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 if (currentBeatType.getValue() == MetronomeType.METRONOME_816_TYPE.getValue() && playPosition % 8 == 0) {
-            return true;
-        } else {
-            return false;
-        }
-    }
 
     private void selectSymbols() {
+        ArrayList<MetronomeType> beatSymbolLists = PlayBeanManager.getInstance().getAllBeatTypeList();
         pvOptions = new OptionsPickerBuilder(this, (options1, options2, options3, v) -> {
             this.currentSelectPosition = options1;
             MetronomeType metronomeType = beatSymbolLists.get(currentSelectPosition);
-            viewBinding.tvCurrentBeat.setText(metronomeType.getName());
-            setBeat(metronomeType);
-            pausePlay();
+            PlayBeanManager.getInstance().pausePlay();
+            PlayBeanManager.getInstance().setBeat(metronomeType);
+            loadData();
         }).setTitleText("拍号").setTitleColor(Color.BLACK).setLayoutRes(R.layout.pickerview_beat_symbol_layout, v -> {
             //自定义布局中的控件初始化及事件处理
             final TextView tvSubmit = (TextView) v.findViewById(com.cooleshow.base.R.id.tv_finish);
@@ -366,19 +260,6 @@ public class MetronomeActivity extends BaseActivity<ActivityMetronomeLayoutBindi
 
 
     @Override
-    public void onDestroy() {
-        super.onDestroy();
-        try {
-            mVolumeManager.unregisterReceiver();
-            soundPool.release();
-            soundPool = null;
-            mHandler.removeCallbacksAndMessages(null);
-        } catch (Exception e) {
-
-        }
-    }
-
-    @Override
     public void onClick(View v) {
         int id = v.getId();
         if (id == R.id.iv_beat_value) {
@@ -388,6 +269,7 @@ public class MetronomeActivity extends BaseActivity<ActivityMetronomeLayoutBindi
 
         if (id == R.id.iv_reduce) {
             //减速
+            int currentBeatRate = PlayBeanManager.getInstance().getCurrentBeatRate();
             if (currentBeatRate != MetronomeConfig.MIN_PLAY_RATE) {
                 updateAnim(-1);
             }
@@ -396,6 +278,7 @@ public class MetronomeActivity extends BaseActivity<ActivityMetronomeLayoutBindi
 
         if (id == R.id.iv_add) {
             //加速
+            int currentBeatRate = PlayBeanManager.getInstance().getCurrentBeatRate();
             if (currentBeatRate != MetronomeConfig.MAX_PLAY_RATE) {
                 updateAnim(1);
             }
@@ -404,14 +287,14 @@ public class MetronomeActivity extends BaseActivity<ActivityMetronomeLayoutBindi
     }
 
     private void updateAnim(int value) {
-        int progress = viewBinding.cirSeekbar.getProgress();
+        float progress = viewBinding.cirSeekbar.getProgress();
         Log.i("qwer", "当前progress:" + progress);
         progress += value;
         if (progress >= MetronomeConfig.MAX_RATE_PROGRESS) {
-            progress = 0;
+            progress = MetronomeConfig.MAX_RATE_PROGRESS;
         }
         if (progress < 0) {
-            progress = MetronomeConfig.MAX_RATE_PROGRESS + value;
+            progress = 0;
         }
         viewBinding.cirSeekbar.setProgress(progress);
     }
@@ -424,4 +307,24 @@ public class MetronomeActivity extends BaseActivity<ActivityMetronomeLayoutBindi
         viewBinding.volumeSeekBar.setProgress(volume);
     }
 
+    @Override
+    public void notifyData(int playPosition) {
+        if (mMetronomeAdapter != null) {
+            mMetronomeAdapter.notifyData(playPosition);
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        try {
+            mVolumeManager.unregisterReceiver();
+            PlayBeanManager.getInstance().resetCallBackListener(this);
+            if (!isUpdateMode) {
+                PlayBeanManager.getInstance().release();
+            }
+        } catch (Exception e) {
+
+        }
+    }
 }

+ 255 - 0
metronome/src/main/java/com/cooleshow/metronome/Utils/PlayBeanManager.java

@@ -0,0 +1,255 @@
+package com.cooleshow.metronome.Utils;
+
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+
+import com.cooleshow.base.utils.LOG;
+import com.cooleshow.metronome.R;
+import com.cooleshow.metronome.adapter.MetronomeAdapter;
+import com.cooleshow.metronome.constants.MetronomeConfig;
+import com.cooleshow.metronome.constants.MetronomeType;
+import com.cooleshow.metronome.interfaces.IPlayBeatCallBack;
+
+import java.util.ArrayList;
+
+/**
+ * Author by pq, Date on 2023/7/13.
+ */
+public class PlayBeanManager {
+    private Handler mHandler = new Handler(Looper.getMainLooper());
+    private int[] musicFileRes = new int[]{R.raw.tick, R.raw.tock};
+    private boolean isInit = false;
+    private boolean isPlaying = false;
+    private ArrayList<MetronomeType> beatSymbolLists;
+
+
+    private int currentBeatRate = MetronomeConfig.DEFAULT_PLAY_RATE;
+    private float currentNoteRate = MetronomeConfig.DEFAULT_NOTE_RATE;
+
+    private MetronomeType currentBeatType;
+    private int playPosition = 0;
+    private IPlayBeatCallBack mCallBack;
+
+    private long totalTime = -1;
+    private long lastTime = -1;
+
+    private Runnable mRunnable = new Runnable() {
+        @Override
+        public void run() {
+            long delayMillis = (long) (1 / (currentBeatRate / 60d) * 1000 * currentNoteRate);
+            long next = MetronomeConfig.MIN_COUNT_TIME_SPACE;
+                long l = System.currentTimeMillis();
+            if (totalTime == -1) {
+                handleMusic(delayMillis,l);
+            } else {
+                if (Math.abs(Math.abs(l - totalTime)-delayMillis)  < next) {
+                    next =0;
+                }
+                if (Math.abs(l -totalTime) >= delayMillis) {
+                    handleMusic(delayMillis,l);
+                }
+            }
+            mHandler.postDelayed(mRunnable, next);
+        }
+    };
+
+    private void handleMusic(long delayMillis,long cTime) {
+        boolean tickOrTock = isTickOrTock();
+        if (lastTime != -1) {
+            long diff = cTime - lastTime;
+            LOG.i("diff:" + diff);
+        }
+        lastTime = cTime;
+        if (tickOrTock) {
+            SoundPoolUtils.getInstance().play(0);
+        } else {
+            SoundPoolUtils.getInstance().play(1);
+        }
+        if (mCallBack != null) {
+            mCallBack.notifyData(playPosition);
+            mHandler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    //实现闪烁动画效果
+                    if (mCallBack != null) {
+                        mCallBack.notifyData(MetronomeAdapter.DEFAULT_SELECT_POSITION);
+                    }
+                }
+            }, delayMillis / 2);
+        }
+        playPosition++;
+        totalTime = cTime;
+    }
+
+
+    private PlayBeanManager() {
+    }
+
+    public static PlayBeanManager getInstance() {
+        return PlayBeanManagerHolder.sManager;
+    }
+
+    public void reset() {
+        playPosition = 0;
+        isPlaying = false;
+        isInit = false;
+    }
+
+    public void release() {
+        if (isPlaying) {
+            pausePlay();
+        }
+        playPosition = 0;
+        SoundPoolUtils.getInstance().release();
+        mHandler.removeCallbacksAndMessages(null);
+        isInit = false;
+    }
+
+    private static final class PlayBeanManagerHolder {
+        private static PlayBeanManager sManager = new PlayBeanManager();
+    }
+
+    public void init(Context context) {
+        if (isInit) {
+            return;
+        }
+        reset();
+        setBeat(MetronomeType.METRONOME_44_TYPE);
+        SoundPoolUtils.getInstance().init(context.getApplicationContext(), musicFileRes);
+        isInit = true;
+    }
+
+    public void setBeat(MetronomeType metronomeType) {
+        currentBeatType = metronomeType;
+        playPosition = 0;
+        currentNoteRate = MetronomeType.getNoteSpeedValue(metronomeType);
+    }
+
+    public int getBeatSymbolCount() {
+        int value = currentBeatType.getValue();
+        if (value == MetronomeType.METRONOME_12_TYPE.getValue()
+                || value == MetronomeType.METRONOME_14_TYPE.getValue()) {
+            return 1;
+        }
+
+        if (value == MetronomeType.METRONOME_22_TYPE.getValue()
+                || value == MetronomeType.METRONOME_24_TYPE.getValue()) {
+            return 2;
+        }
+
+        if (value == MetronomeType.METRONOME_34_TYPE.getValue()
+                || value == MetronomeType.METRONOME_38_TYPE.getValue()) {
+            return 3;
+        }
+
+        if (value == MetronomeType.METRONOME_44_TYPE.getValue()) {
+            return 4;
+        }
+
+        if (value == MetronomeType.METRONOME_68_TYPE.getValue()) {
+            return 6;
+        }
+
+        if (value == MetronomeType.METRONOME_816_TYPE.getValue()) {
+            return 8;
+        }
+        return 0;
+    }
+
+
+    public boolean isPlaying() {
+        return isPlaying;
+    }
+
+    public String getCurrentSpeed() {
+        return String.valueOf(currentBeatRate);
+    }
+
+    public int getCurrentBeatRate() {
+        return currentBeatRate;
+    }
+
+    public void setCurrentBeatRate(int playBeatRate) {
+        currentBeatRate = playBeatRate;
+    }
+
+    public String getCurrentBeanType() {
+        if (currentBeatType == null) {
+            currentBeatType = MetronomeType.METRONOME_44_TYPE;
+        }
+        return currentBeatType.getName();
+    }
+
+    public MetronomeType getCurrentBeatType() {
+        return currentBeatType;
+    }
+
+    public void play() {
+        mHandler.removeCallbacksAndMessages(null);
+        SoundPoolUtils.getInstance().stop();
+        mHandler.post(mRunnable);
+        totalTime = -1;
+        lastTime =-1;
+        isPlaying = true;
+    }
+
+    public void pausePlay() {
+        mHandler.removeCallbacksAndMessages(null);
+        SoundPoolUtils.getInstance().stop();
+        isPlaying = false;
+    }
+
+    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 if (currentBeatType.getValue() == MetronomeType.METRONOME_816_TYPE.getValue() && playPosition % 8 == 0) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+
+    public ArrayList<MetronomeType> getAllBeatTypeList() {
+        if (beatSymbolLists == null) {
+            beatSymbolLists = new ArrayList<>();
+            beatSymbolLists.add(MetronomeType.METRONOME_12_TYPE);
+            beatSymbolLists.add(MetronomeType.METRONOME_14_TYPE);
+            beatSymbolLists.add(MetronomeType.METRONOME_22_TYPE);
+            beatSymbolLists.add(MetronomeType.METRONOME_24_TYPE);
+            beatSymbolLists.add(MetronomeType.METRONOME_34_TYPE);
+            beatSymbolLists.add(MetronomeType.METRONOME_38_TYPE);
+            beatSymbolLists.add(MetronomeType.METRONOME_44_TYPE);
+            beatSymbolLists.add(MetronomeType.METRONOME_68_TYPE);
+            beatSymbolLists.add(MetronomeType.METRONOME_816_TYPE);
+        }
+        return beatSymbolLists;
+    }
+
+
+    public void setCallBackListener(IPlayBeatCallBack callBackListener) {
+        this.mCallBack = callBackListener;
+    }
+
+    public void resetCallBackListener(IPlayBeatCallBack callBackListener){
+        if(this.mCallBack == callBackListener){
+            this.mCallBack =null;
+        }
+    }
+}

+ 120 - 0
metronome/src/main/java/com/cooleshow/metronome/Utils/SoundPoolUtils.java

@@ -0,0 +1,120 @@
+package com.cooleshow.metronome.Utils;
+
+import android.content.Context;
+import android.media.AudioAttributes;
+import android.media.SoundPool;
+
+import com.cooleshow.base.utils.LOG;
+import com.cooleshow.metronome.R;
+
+import java.util.ArrayList;
+
+/**
+ * Author by pq, Date on 2023/7/13.
+ */
+public class SoundPoolUtils implements SoundPool.OnLoadCompleteListener {
+    private static final int DEFAULT_INVALID_ID = -1;
+    private static SoundPoolUtils soundPoolUtil;
+    private SoundPool soundPool;
+    private int mStreamID = DEFAULT_INVALID_ID;
+    private int preparePlaySoundPosition = DEFAULT_INVALID_ID;
+    private int MAX_SIZE = DEFAULT_INVALID_ID;
+
+    private ArrayList<Integer> soundIdList = new ArrayList<>();
+    private boolean isLoadAllCompleted = false;
+
+
+    //单例模式
+    public static SoundPoolUtils getInstance() {
+        if (soundPoolUtil == null) {
+            soundPoolUtil = new SoundPoolUtils();
+        }
+        return soundPoolUtil;
+    }
+
+    private SoundPoolUtils() {
+
+    }
+
+    public void init(Context context, int[] musicRes) {
+        if (musicRes == null || musicRes.length == 0) {
+            return;
+        }
+        MAX_SIZE = musicRes.length;
+        if (soundPool == null) {
+            AudioAttributes audioAttributes = null;
+            audioAttributes = new AudioAttributes.Builder()
+                    .setUsage(AudioAttributes.USAGE_MEDIA)
+                    .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
+                    .build();
+
+            soundPool = new SoundPool.Builder()
+                    .setMaxStreams(2)
+                    .setAudioAttributes(audioAttributes)
+                    .build();
+
+            soundPool.setOnLoadCompleteListener(this);
+        }
+        soundIdList.clear();
+        loadCompletedNum = 0;
+        //加载音频文件
+        for (int i = 0; i < musicRes.length; i++) {
+            int loadId = soundPool.load(context, musicRes[i], 1);
+            soundIdList.add(loadId);
+        }
+    }
+
+    public void stop() {
+        if (soundPool != null) {
+            soundPool.stop(mStreamID);
+            mStreamID = DEFAULT_INVALID_ID;
+        }
+    }
+
+    public void play(int pos) {
+        LOG.i("pos " + pos);
+        //播放音频
+//        if (mStreamID != DEFAULT_INVALID_ID) {
+//            stop();
+//        }
+        if (isLoadAllCompleted) {
+            Integer integer = soundIdList.get(pos);
+            LOG.i("SoundPoolUtils", "pos id" + integer);
+            if (soundPool != null) {
+                mStreamID = soundPool.play(integer, 1, 1, 0, 0, 1);
+            }
+        } else {
+            preparePlaySoundPosition = pos;
+            LOG.i("SoundPoolUtils", "preparePlaySoundPosition:" + preparePlaySoundPosition);
+        }
+    }
+
+    public void release() {
+        if (soundPool != null) {
+            soundIdList.clear();
+            soundPool.autoPause();
+            mStreamID = DEFAULT_INVALID_ID;
+            preparePlaySoundPosition = DEFAULT_INVALID_ID;
+            MAX_SIZE = DEFAULT_INVALID_ID;
+            isLoadAllCompleted = false;
+            loadCompletedNum = 0;
+            soundPool.release();
+            soundPool = null;
+        }
+    }
+
+    int loadCompletedNum = 0;
+
+    @Override
+    public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
+        LOG.i("SoundPoolUtils", "pos onLoadComplete" + sampleId + "--status:" + status + "--loadCompletedNum:" + loadCompletedNum);
+        loadCompletedNum++;
+        if (soundIdList.size() == loadCompletedNum) {
+            isLoadAllCompleted = true;
+            LOG.i("SoundPoolUtils", "all loadComplete");
+            if (preparePlaySoundPosition != DEFAULT_INVALID_ID && preparePlaySoundPosition < soundIdList.size()) {
+                play(preparePlaySoundPosition);
+            }
+        }
+    }
+}

+ 4 - 4
metronome/src/main/java/com/cooleshow/metronome/adapter/MetronomeAdapter.java

@@ -33,11 +33,11 @@ public class MetronomeAdapter extends BaseQuickAdapter<BeatBean, BaseViewHolder>
         view_first.setVisibility(position == 0 ? View.VISIBLE : View.GONE);
         view_other.setVisibility(position == 0 ? View.GONE : View.VISIBLE);
         if (position == selectPosition) {
-            view_first.setBackgroundResource(R.drawable.shape_2dc7aa_beat_select);
-            view_other.setBackgroundResource(R.drawable.shape_2dc7aa_beat_select);
+            view_first.setBackgroundResource(R.drawable.shape_009fff_beat_select);
+            view_other.setBackgroundResource(R.drawable.shape_009fff_beat_select);
         } else {
-            view_first.setBackgroundResource(R.drawable.shape_2dc7aa_beat_normal);
-            view_other.setBackgroundResource(R.drawable.shape_2dc7aa_beat_normal);
+            view_first.setBackgroundResource(R.drawable.shape_ffffff_beat_normal);
+            view_other.setBackgroundResource(R.drawable.shape_ffffff_beat_normal);
         }
     }
 

+ 1 - 1
metronome/src/main/java/com/cooleshow/metronome/constants/MetronomeConfig.java

@@ -13,7 +13,7 @@ public class MetronomeConfig {
     public static final int MIN_PLAY_RATE = 50;//最小播放速度
     public static final int MAX_PLAY_RATE = 200;//最大播放速度
     public static final int PLAY_RATE_UNIT = 10;//10个进度 +1或者-1速度
-    public static final int MAX_RATE_PROGRESS = 100;//最大进度100
+    public static final int MAX_RATE_PROGRESS = 150;//最大进度100
     public static final int MIN_COUNT_TIME_SPACE = 100;//定时器最小间隔
 
 

+ 11 - 0
metronome/src/main/java/com/cooleshow/metronome/interfaces/IPlayBeatCallBack.java

@@ -0,0 +1,11 @@
+package com.cooleshow.metronome.interfaces;
+
+import com.cooleshow.metronome.constants.MetronomeType;
+
+/**
+ * Author by pq, Date on 2023/7/13.
+ */
+public interface IPlayBeatCallBack {
+    void notifyData(int playPosition);
+
+}

+ 288 - 152
metronome/src/main/java/com/cooleshow/metronome/widget/CircularSeekBar.java

@@ -1,103 +1,159 @@
 package com.cooleshow.metronome.widget;
 
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.LinearGradient;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.Shader;
+import android.graphics.SweepGradient;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 
+import com.cooleshow.base.utils.SizeUtils;
 import com.cooleshow.metronome.R;
 
+import static com.cooleshow.base.utils.ColorUtils.getColor;
+
 
 /**
  * Author by pq, Date on 2022/9/15.
  */
 public class CircularSeekBar extends View {
-
-    /** The context */
-    private Context mContext;
-
-    /** The listener to listen for changes */
+    private static final String TAG = "CircularSeekBar";
+    /**
+     * The listener to listen for changes
+     */
     private OnSeekChangeListener mListener;
 
-    /** The color of the progress ring */
+    /**
+     * The color of the progress ring
+     */
     private Paint circleColor;
 
-    /** the color of the inside circle. Acts as background color */
+    /**
+     * the color of the inside circle. Acts as background color
+     */
     private Paint innerColor;
 
-    /** The progress circle ring background */
+    /**
+     * The progress circle ring background
+     */
     private Paint circleRing;
 
-    /** The markPaint*/
+    /**
+     * The markPaint
+     */
     private Paint markPaint;
 
-    /** The angle of progress */
-    private int angle = 0;
+    /**
+     * The angle of progress
+     */
+    private float angle = 0;
 
-    /** The start angle (12 O'clock */
+    /**
+     * The start angle (12 O'clock
+     */
     private int startAngle = 270;
 
-    /** The width of the progress ring */
+    /**
+     * The width of the progress ring
+     */
     private int barWidth = 5;
 
-    /** The width of the view */
+    /**
+     * The width of the view
+     */
     private int width;
 
-    /** The height of the view */
+    /**
+     * The height of the view
+     */
     private int height;
 
-    /** The maximum progress amount */
+    /**
+     * The maximum progress amount
+     */
     private int maxProgress = 100;
 
-    /** The current progress */
-    private int progress;
+    /**
+     * The current progress
+     */
+    private float progress;
 
-    /** The progress percent */
+    /**
+     * The progress percent
+     */
     private int progressPercent;
 
-    /** The radius of the inner circle */
+    /**
+     * The radius of the inner circle
+     */
     private float innerRadius;
 
-    /** The radius of the outer circle */
+    /**
+     * The radius of the outer circle
+     */
     private float outerRadius;
 
-    /** The circle's center X coordinate */
+    /**
+     * The circle's center X coordinate
+     */
     private float cx;
 
-    /** The circle's center Y coordinate */
+    /**
+     * The circle's center Y coordinate
+     */
     private float cy;
 
-    /** The left bound for the circle RectF */
+    /**
+     * The left bound for the circle RectF
+     */
     private float left;
 
-    /** The right bound for the circle RectF */
+    /**
+     * The right bound for the circle RectF
+     */
     private float right;
 
-    /** The top bound for the circle RectF */
+    /**
+     * The top bound for the circle RectF
+     */
     private float top;
 
-    /** The bottom bound for the circle RectF */
+    /**
+     * The bottom bound for the circle RectF
+     */
     private float bottom;
 
-    /** The X coordinate for the top left corner of the marking drawable */
+    /**
+     * The X coordinate for the top left corner of the marking drawable
+     */
     private float dx;
 
-    /** The Y coordinate for the top left corner of the marking drawable */
+    /**
+     * The Y coordinate for the top left corner of the marking drawable
+     */
     private float dy;
 
-    /** The X coordinate for 12 O'Clock */
+    /**
+     * The X coordinate for 12 O'Clock
+     */
     private float startPointX;
 
-    /** The Y coordinate for 12 O'Clock */
+    /**
+     * The Y coordinate for 12 O'Clock
+     */
     private float startPointY;
 
     /**
@@ -119,13 +175,19 @@ public class CircularSeekBar extends View {
      */
     private float adjustmentFactor = 500;
 
-    /** The progress mark when the view isn't being progress modified */
+    /**
+     * The progress mark when the view isn't being progress modified
+     */
     private Bitmap progressMark;
 
-    /** The progress mark when the view is being progress modified. */
+    /**
+     * The progress mark when the view is being progress modified.
+     */
     private Bitmap progressMarkPressed;
 
-    /** The flag to see if view is pressed */
+    /**
+     * The flag to see if view is pressed
+     */
     private boolean IS_PRESSED = false;
 
     /**
@@ -136,24 +198,30 @@ public class CircularSeekBar extends View {
 
     private boolean SHOW_SEEKBAR = true;
 
-    /** The rectangle containing our circles and arcs. */
+    private float centerRound1RadiusPercent = 0.767f;
+
+    /**
+     * The rectangle containing our circles and arcs.
+     */
     private RectF rect = new RectF();
+    private Paint mCenterRound1Paint;
+    private Paint thumpBarPaint;
 
     {
-        mListener = new OnSeekChangeListener() {
-
-            @Override
-            public void onProgressChange(CircularSeekBar view, int newProgress) {
-                Log.i("pq","newProgress:"+newProgress);
-            }
-        };
+//        mListener = new OnSeekChangeListener() {
+//
+//            @Override
+//            public void onProgressChange(CircularSeekBar view, int newProgress) {
+//                Log.i("pq", "newProgress:" + newProgress);
+//            }
+//        };
 
         circleColor = new Paint();
         innerColor = new Paint();
         circleRing = new Paint();
         markPaint = new Paint();
 
-        circleColor.setColor(Color.TRANSPARENT); // Set default
+        circleColor.setColor(Color.RED); // Set default
         // progress
         // color to holo
         // blue.
@@ -171,61 +239,94 @@ public class CircularSeekBar extends View {
         innerColor.setStrokeWidth(5);
         circleRing.setStrokeWidth(5);
 
+
+        float position[] = {0f, 0.25f, 0.5f, 0.75f, 0.76f, 1.0f};
+        //51DBFF 3FCEFF 28BDFF 16AFFF 009FFF
+        //3FCEFF 28BDFF 16AFFF 009FFF 51DBFF 3FCEFF
+        int[] colors = new int[]{getColor(R.color.color_3fceff),//0f
+                getColor(R.color.color_28bdff),//0.25f
+                getColor(R.color.color_16afff),//0.5f
+                getColor(R.color.color_009fff),//0.75f
+                getColor(R.color.color_51dbff),//0.76f
+                getColor(R.color.color_3fceff)};//1.0f
+        Shader mShader = new SweepGradient(cx, cy, colors, position);
+        circleColor.setShader(mShader);
         circleColor.setStyle(Paint.Style.FILL);
+
+
+        thumpBarPaint = new Paint();
+        thumpBarPaint.setStyle(Paint.Style.FILL);
+        thumpBarPaint.setDither(true);
+        thumpBarPaint.setAntiAlias(true);
+        thumpBarPaint.setStrokeWidth(1);
+
+    }
+
+
+    private void initCenterRound1Paint() {
+        if (mCenterRound1Paint == null) {
+            mCenterRound1Paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+            mCenterRound1Paint.setDither(true);
+            mCenterRound1Paint.setAntiAlias(true);
+            float centerRoundRadius = outerRadius * centerRound1RadiusPercent;
+            Shader mShader = new LinearGradient(cx, cy - centerRoundRadius, cx, cy + centerRoundRadius, Color.WHITE, Color.parseColor("#DCF0FF"), Shader.TileMode.CLAMP);
+            mCenterRound1Paint.setShader(mShader);
+
+            mCenterRound1Paint.setStyle(Paint.Style.FILL);
+            mCenterRound1Paint.setStrokeCap(Paint.Cap.ROUND);
+            mCenterRound1Paint.setStrokeWidth(1);
+            mCenterRound1Paint.setColor(Color.RED);
+        }
+    }
+
+    private int getColor(int colorRes) {
+        return getResources().getColor(colorRes);
     }
 
     /**
      * Instantiates a new circular seek bar.
      *
-     * @param context
-     *            the context
-     * @param attrs
-     *            the attrs
-     * @param defStyle
-     *            the def style
+     * @param context  the context
+     * @param attrs    the attrs
+     * @param defStyle the def style
      */
     public CircularSeekBar(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-        mContext = context;
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircularSeekBar, defStyle, 0);
+        maxProgress = a.getInteger(R.styleable.CircularSeekBar_maxProgress, 100);
+        a.recycle();
         initDrawable();
     }
 
     /**
      * Instantiates a new circular seek bar.
      *
-     * @param context
-     *            the context
-     * @param attrs
-     *            the attrs
+     * @param context the context
+     * @param attrs   the attrs
      */
     public CircularSeekBar(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mContext = context;
-        initDrawable();
+        this(context, attrs, 0);
     }
 
     /**
      * Instantiates a new circular seek bar.
      *
-     * @param context
-     *            the context
+     * @param context the context
      */
     public CircularSeekBar(Context context) {
-        super(context);
-        mContext = context;
-        initDrawable();
+        this(context, null);
     }
 
     /**
      * Inits the drawable.
      */
     public void initDrawable() {
-        progressMark = drawableToBitmap(mContext.getResources().getDrawable(R.drawable.shape_speed_mark));
-        progressMarkPressed = drawableToBitmap(mContext.getResources().getDrawable(R.drawable.shape_speed_mark));
+//        progressMark = drawableToBitmap(mContext.getResources().getDrawable(R.drawable.icon_progress_bar_thump));
+//        progressMarkPressed = drawableToBitmap(mContext.getResources().getDrawable(R.drawable.icon_progress_bar_thump));
 
-//        progressMark = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.shape_speed_mark);
+//        progressMark = BitmapFactory.decodeResource(mContext.getResources(), R.mipmap.icon_progress_bar_thump);
 //        progressMarkPressed = BitmapFactory.decodeResource(mContext.getResources(),
-//                R.drawable.shape_speed_mark);
+//                R.mipmap.icon_progress_bar_thump);
     }
 
     public static Bitmap drawableToBitmap(Drawable drawable) {
@@ -283,6 +384,7 @@ public class CircularSeekBar extends View {
         markPointY = startPointY;// Initial locatino of the marker Y coordinate
 
         rect.set(left, top, right, bottom); // assign size to rect
+        initCenterRound1Paint();
     }
 
     /*
@@ -295,13 +397,29 @@ public class CircularSeekBar extends View {
 
         //可以不绘制
 //        canvas.drawCircle(cx, cy, outerRadius, circleRing);
-//        canvas.drawArc(rect, startAngle, angle, true, circleColor);
+        canvas.drawArc(rect, startAngle, angle, true, circleColor);
 //        canvas.drawCircle(cx, cy, innerRadius, innerColor);
-
-        if(SHOW_SEEKBAR){
-            dx = getXFromAngle();
-            dy = getYFromAngle();
-            drawMarkerAtProgress(canvas);
+        float centerRoundRadius = outerRadius * centerRound1RadiusPercent;
+        canvas.drawCircle(cx, cy, centerRoundRadius, mCenterRound1Paint);
+        if (SHOW_SEEKBAR) {
+            //大圆的最边缘的坐边点
+            dx = getXFromAngle(outerRadius);
+            dy = getYFromAngle(outerRadius);
+
+            //内圆的最边缘的坐边点
+            float innerRoundDx = getXFromAngle(centerRoundRadius);
+            float innerRoundDy = getYFromAngle(centerRoundRadius);
+
+            //拖拽的bar的圆中心点
+            float targetRoundCx = (dx + innerRoundDx) / 2;
+            float targetRoundCy = (dy + innerRoundDy) / 2;
+            float thumpBarRoundRadius = (outerRadius * (1 - centerRound1RadiusPercent)) / 2;
+            thumpBarPaint.setColor(Color.WHITE);
+            canvas.drawCircle(targetRoundCx, targetRoundCy, thumpBarRoundRadius, thumpBarPaint);
+            thumpBarPaint.setColor(getColor(R.color.color_0ba7ff));
+            canvas.drawCircle(targetRoundCx, targetRoundCy, 13, thumpBarPaint);
+
+//            drawMarkerAtProgress(canvas);
         }
         super.onDraw(canvas);
     }
@@ -309,20 +427,19 @@ public class CircularSeekBar extends View {
     /**
      * Draw marker at the current progress point onto the given canvas.
      *
-     * @param canvas
-     *            the canvas
+     * @param canvas the canvas
      */
     public void drawMarkerAtProgress(Canvas canvas) {
         if (IS_PRESSED) {
-            Matrix matrix =new Matrix();
+            Matrix matrix = new Matrix();
             matrix.postRotate(getAngle());
-            matrix.postTranslate(dx,dy);
+            matrix.postTranslate(dx, dy);
 //            canvas.drawBitmap(progressMarkPressed, dx, dy, null);
-            canvas.drawBitmap(progressMarkPressed,matrix,markPaint);
+            canvas.drawBitmap(progressMarkPressed, matrix, markPaint);
         } else {
-            Matrix matrix =new Matrix();
+            Matrix matrix = new Matrix();
             matrix.postRotate(getAngle());
-            matrix.postTranslate(dx,dy);
+            matrix.postTranslate(dx, dy);
 //            canvas.drawBitmap(progressMark, dx, dy, null);
             canvas.drawBitmap(progressMark, matrix, markPaint);
         }
@@ -334,19 +451,12 @@ public class CircularSeekBar extends View {
      *
      * @return the X coordinate
      */
-    public float getXFromAngle() {
-        int size1 = progressMark.getWidth();
-        int size2 = progressMarkPressed.getWidth();
-        int adjust = (size1 > size2) ? size1 : size2;
-        Log.i("pq","markPointX:"+markPointX);
-        Log.i("pq","progressMark width:"+size1);
-        float x = markPointX - (adjust / 2);
-        Log.i("pq","result:"+x);
-        if(angle!=0){
+    public float getXFromAngle(float value) {
+        if (angle != 0) {
             float radian = (float) Math.toRadians(angle);
             Log.i("pq", "radian:" + radian);
-            markPointX = (float) (cx + Math.sin(radian) * outerRadius);
-        }else{
+            markPointX = (float) (cx + Math.sin(radian) * value);
+        } else {
             markPointX = startPointX;
         }
         return markPointX;
@@ -358,20 +468,13 @@ public class CircularSeekBar extends View {
      *
      * @return the Y coordinate
      */
-    public float getYFromAngle() {
-        int size1 = progressMark.getHeight();
-        int size2 = progressMarkPressed.getHeight();
-        int adjust = (size1 > size2) ? size1 : size2;
-        Log.i("pq","markPointY:"+markPointY);
-        Log.i("pq","progressMark height:"+size1);
-        float y = markPointY - (adjust / 2);
-        Log.i("pq","result:"+y);
-        if(angle!=0){
+    public float getYFromAngle(float value) {
+        if (angle != 0) {
             float radian = (float) Math.toRadians(angle);
             Log.i("pq", "radian:" + radian);
-            markPointY = (float) (cy - Math.cos(radian) * outerRadius);
-        }else{
-            markPointY =startPointY;
+            markPointY = (float) (cy - Math.cos(radian) * value);
+        } else {
+            markPointY = cy - value;
         }
         return markPointY;
     }
@@ -381,30 +484,67 @@ public class CircularSeekBar extends View {
      *
      * @return the angle
      */
-    public int getAngle() {
+    public float getAngle() {
         return angle;
     }
 
     /**
      * Set the angle.
      *
-     * @param angle
-     *            the new angle
+     * @param angle the new angle
      */
-    public void setAngle(int angle) {
+    public void setAngle(float angle) {
         this.angle = angle;
-        float donePercent = (((float) this.angle) / 360) * 100;
-        float progress = (donePercent / 100) * getMaxProgress();
+        float donePercent = (((float) this.angle) / 360);
+        float progress = (donePercent) * getMaxProgress();
         setProgressPercent(Math.round(donePercent));
         CALLED_FROM_ANGLE = true;
-        setProgress(Math.round(progress));
+        setProgress(progress);
+    }
+
+    /**
+     * Set the angle.
+     *
+     * @param
+     */
+    public boolean setAngle2(float targetAngle, boolean isLeft) {
+        float donePercent = (((float) targetAngle) / 360);
+        float newProgress = (donePercent) * getMaxProgress();
+        Log.i(TAG, "newProgress:" + newProgress);
+        Log.i(TAG, "progress:" + progress);
+        Log.i(TAG, "isLeft:" + isLeft);
+
+        if ((progress == 0 && isLeft)) {
+            return false;
+        }
+
+        if (newProgress > maxProgress / 2 && Math.abs(newProgress - progress) > maxProgress / 2) {
+            targetAngle = 0.00f * 360;
+            donePercent = (((float) targetAngle) / 360);
+            newProgress = (donePercent) * getMaxProgress();
+        }
+
+        if ((progress == getMaxProgress() && !isLeft)) {
+            return false;
+        }
+
+        if (Math.abs(newProgress - progress) > maxProgress / 2 && newProgress < maxProgress / 2) {
+            targetAngle = 1.0f * 360;
+            donePercent = (((float) targetAngle) / 360);
+            newProgress = (donePercent) * getMaxProgress();
+        }
+
+        this.angle = targetAngle;
+        setProgressPercent((int) Math.floor(donePercent));
+        CALLED_FROM_ANGLE = true;
+        setProgress(newProgress);
+        return true;
     }
 
     /**
      * Sets the seek bar change listener.
      *
-     * @param listener
-     *            the new seek bar change listener
+     * @param listener the new seek bar change listener
      */
     public void setSeekBarChangeListener(OnSeekChangeListener listener) {
         mListener = listener;
@@ -431,8 +571,7 @@ public class CircularSeekBar extends View {
     /**
      * Sets the bar width.
      *
-     * @param barWidth
-     *            the new bar width
+     * @param barWidth the new bar width
      */
     public void setBarWidth(int barWidth) {
         this.barWidth = barWidth;
@@ -454,12 +593,10 @@ public class CircularSeekBar extends View {
         /**
          * On progress change.
          *
-         * @param view
-         *            the view
-         * @param newProgress
-         *            the new progress
+         * @param view        the view
+         * @param newProgress the new progress
          */
-        public void onProgressChange(CircularSeekBar view, int newProgress);
+        public void onProgressChange(CircularSeekBar view, float newProgress);
     }
 
     /**
@@ -474,8 +611,7 @@ public class CircularSeekBar extends View {
     /**
      * Sets the max progress.
      *
-     * @param maxProgress
-     *            the new max progress
+     * @param maxProgress the new max progress
      */
     public void setMaxProgress(int maxProgress) {
         this.maxProgress = maxProgress;
@@ -486,27 +622,26 @@ public class CircularSeekBar extends View {
      *
      * @return the progress
      */
-    public int getProgress() {
+    public float getProgress() {
         return progress;
     }
 
     /**
      * Sets the progress.
      *
-     * @param progress
-     *            the new progress
+     * @param progress the new progress
      */
-    public void setProgress(int progress) {
-        Log.i("qwer","setProgress:"+progress);
+    public void setProgress(float progress) {
+        Log.i("qwer", "setProgress:" + progress);
         if (this.progress != progress) {
             this.progress = progress;
             if (!CALLED_FROM_ANGLE) {
-                int newPercent = (this.progress * 100) / this.maxProgress;
-                int newAngle = (newPercent * 360) / 100 ;
-                Log.i("qwer","set newPercent:"+newPercent);
-                Log.i("qwer","set newAngle:"+newAngle);
+                float newPercent = (this.progress * 1.0f) / this.maxProgress;
+                float newAngle = (newPercent * 360);
+                Log.i("qwer", "set newPercent:" + newPercent);
+                Log.i("qwer", "set newAngle:" + newAngle);
                 this.setAngle(newAngle);
-                this.setProgressPercent(newPercent);
+                this.setProgressPercent((int) newPercent);
                 invalidate();
             }
             mListener.onProgressChange(this, this.getProgress());
@@ -526,8 +661,7 @@ public class CircularSeekBar extends View {
     /**
      * Sets the progress percent.
      *
-     * @param progressPercent
-     *            the new progress percent
+     * @param progressPercent the new progress percent
      */
     public void setProgressPercent(int progressPercent) {
         this.progressPercent = progressPercent;
@@ -536,8 +670,7 @@ public class CircularSeekBar extends View {
     /**
      * Sets the ring background color.
      *
-     * @param color
-     *            the new ring background color
+     * @param color the new ring background color
      */
     public void setRingBackgroundColor(int color) {
         circleRing.setColor(color);
@@ -546,8 +679,7 @@ public class CircularSeekBar extends View {
     /**
      * Sets the back ground color.
      *
-     * @param color
-     *            the new back ground color
+     * @param color the new back ground color
      */
     public void setBackGroundColor(int color) {
         innerColor.setColor(color);
@@ -556,8 +688,7 @@ public class CircularSeekBar extends View {
     /**
      * Sets the progress color.
      *
-     * @param color
-     *            the new progress color
+     * @param color the new progress color
      */
     public void setProgressColor(int color) {
         circleColor.setColor(color);
@@ -568,6 +699,9 @@ public class CircularSeekBar extends View {
      *
      * @see android.view.View#onTouchEvent(android.view.MotionEvent)
      */
+    float lastX;
+    float lastY;
+
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         float x = event.getX();
@@ -575,16 +709,16 @@ public class CircularSeekBar extends View {
         boolean up = false;
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
-//                moved(x, y, up);
+                lastX = x;
+                lastY = y;
                 break;
             case MotionEvent.ACTION_MOVE:
-                if(!up){
+                if (!up) {
                     moved(x, y, up);
                 }
                 break;
             case MotionEvent.ACTION_UP:
                 up = true;
-//                moved(x, y, up);
                 break;
         }
         return true;
@@ -593,12 +727,9 @@ public class CircularSeekBar extends View {
     /**
      * Moved.
      *
-     * @param x
-     *            the x
-     * @param y
-     *            the y
-     * @param up
-     *            the up
+     * @param x  the x
+     * @param y  the y
+     * @param up the up
      */
     private void moved(float x, float y, boolean up) {
         float distance = (float) Math.sqrt(Math.pow((x - cx), 2) + Math.pow((y - cy), 2));
@@ -610,12 +741,18 @@ public class CircularSeekBar extends View {
 
             float degrees = (float) ((float) ((Math.toDegrees(Math.atan2(x - cx, cy - y)) + 360.0)) % 360.0);
             // and to make it count 0-360
+            Log.i(TAG, "degrees:" + degrees);
             if (degrees < 0) {
                 degrees += 2 * Math.PI;
             }
-
-            setAngle(Math.round(degrees));
-            invalidate();
+            Log.i(TAG, "degrees2:" + degrees);
+//            setAngle(degrees);
+            boolean b = setAngle2(degrees, x < lastX);
+            if (b) {
+                lastX = x;
+                lastY = y;
+                invalidate();
+            }
 
         } else {
             IS_PRESSED = false;
@@ -636,8 +773,7 @@ public class CircularSeekBar extends View {
     /**
      * Sets the adjustment factor.
      *
-     * @param adjustmentFactor
-     *            the new adjustment factor
+     * @param adjustmentFactor the new adjustment factor
      */
     public void setAdjustmentFactor(float adjustmentFactor) {
         this.adjustmentFactor = adjustmentFactor;

+ 4 - 2
metronome/src/main/res/drawable/bg_volume_seekbar.xml

@@ -6,7 +6,7 @@
             <!-- 圆角 -->
             <corners android:radius="2dp" />
             <!--            背景色-->
-            <solid android:color="#dfdfdf"/>
+            <solid android:color="#99ffffff"/>
             <size android:height="4dp"/>
         </shape>
     </item>
@@ -16,8 +16,10 @@
             <shape>
                 <!-- 圆角 -->
                 <corners android:radius="2dp" />
+                <gradient android:startColor="#63DAFF"
+                    android:endColor="#1798FF"/>
                 <!--            背景色-->
-                <solid android:color="@color/color_2dc7aa"/>
+<!--                <solid android:color="@color/color_2dc7aa"/>-->
                 <size android:height="4dp"/>
             </shape>
         </clip>

+ 5 - 0
metronome/src/main/res/drawable/shape_009fff_beat_select.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="#009FFF"/>
+</shape>

+ 5 - 0
metronome/src/main/res/drawable/shape_00acff_27dp.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#00ACFF"/>
+    <corners android:radius="27dp"/>
+</shape>

+ 5 - 0
metronome/src/main/res/drawable/shape_ffffff_beat_normal.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="@color/white"/>
+</shape>

+ 131 - 60
metronome/src/main/res/layout/activity_metronome_layout.xml

@@ -4,7 +4,7 @@
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="@drawable/shape_page_main_bg"
+    android:background="@mipmap/bg_play_beat_big"
     tools:context=".MetronomeActivity">
 
     <include
@@ -26,8 +26,8 @@
 
     <ImageView
         android:id="@+id/iv_plate"
-        android:layout_width="300dp"
-        android:layout_height="300dp"
+        android:layout_width="316dp"
+        android:layout_height="316dp"
         android:layout_marginTop="65dp"
         android:src="@mipmap/bg_metronome"
         android:visibility="visible"
@@ -35,15 +35,50 @@
         app:layout_constraintRight_toRightOf="parent"
         app:layout_constraintTop_toBottomOf="@+id/toolbar_include" />
 
+
+    <ImageView
+        android:id="@+id/iv_plate2"
+        android:layout_width="232dp"
+        android:layout_height="232dp"
+        android:src="@mipmap/bg_metronome2"
+        android:visibility="visible"
+        app:layout_constraintBottom_toBottomOf="@+id/iv_plate"
+        app:layout_constraintLeft_toLeftOf="@+id/iv_plate"
+        app:layout_constraintRight_toRightOf="@+id/iv_plate"
+        app:layout_constraintTop_toTopOf="@+id/iv_plate" />
+
     <com.cooleshow.metronome.widget.CircularSeekBar
         android:id="@+id/cir_seekbar"
-        android:layout_width="220dp"
-        android:layout_height="220dp"
+        android:layout_width="232dp"
+        android:layout_height="232dp"
+        app:maxProgress="150"
         app:layout_constraintBottom_toBottomOf="@+id/iv_plate"
         app:layout_constraintLeft_toLeftOf="@+id/iv_plate"
         app:layout_constraintRight_toRightOf="@+id/iv_plate"
         app:layout_constraintTop_toTopOf="@+id/iv_plate" />
 
+
+    <ImageView
+        android:id="@+id/iv_plate3"
+        android:layout_width="178dp"
+        android:layout_height="178dp"
+        android:src="@mipmap/bg_metronome3"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toBottomOf="@+id/iv_plate"
+        app:layout_constraintLeft_toLeftOf="@+id/iv_plate"
+        app:layout_constraintRight_toRightOf="@+id/iv_plate"
+        app:layout_constraintTop_toTopOf="@+id/iv_plate" />
+    
+    <ImageView
+        android:id="@+id/iv_bg_metronome4"
+        app:layout_constraintBottom_toBottomOf="@+id/iv_plate"
+        app:layout_constraintLeft_toLeftOf="@+id/iv_plate"
+        app:layout_constraintRight_toRightOf="@+id/iv_plate"
+        app:layout_constraintTop_toTopOf="@+id/iv_plate"
+        android:src="@mipmap/bg_metronome4"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+    
     <TextView
         android:id="@+id/tv_speed"
         android:layout_width="wrap_content"
@@ -61,6 +96,7 @@
 
 
     <ImageView
+        android:visibility="gone"
         android:id="@+id/iv_note"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
@@ -70,15 +106,15 @@
         app:layout_constraintCircleRadius="55dp" />
 
     <TextView
-
-        android:textColor="@color/color_333333"
-        android:textSize="@dimen/sp_14"
-        app:layout_constraintLeft_toRightOf="@+id/iv_note"
-        app:layout_constraintBottom_toBottomOf="@+id/iv_note"
-        app:layout_constraintTop_toTopOf="@+id/iv_note"
-        android:text="="
+        android:layout_marginBottom="10dp"
+        app:layout_constraintRight_toRightOf="@+id/iv_bg_metronome4"
+        app:layout_constraintLeft_toLeftOf="@+id/iv_bg_metronome4"
+        app:layout_constraintBottom_toTopOf="@+id/iv_bg_metronome4"
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content"/>
+        android:layout_height="wrap_content"
+        android:text="速度"
+        android:textColor="@color/color_333333"
+        android:textSize="@dimen/sp_15" />
 
     <ImageView
         android:id="@+id/iv_reduce"
@@ -91,14 +127,14 @@
         app:layout_constraintRight_toLeftOf="@+id/iv_beat_value"
         app:layout_constraintTop_toBottomOf="@+id/iv_plate" />
 
-    <ImageView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:src="@mipmap/icon_reduce_symbol"
-        app:layout_constraintBottom_toBottomOf="@+id/iv_reduce"
-        app:layout_constraintLeft_toLeftOf="@+id/iv_reduce"
-        app:layout_constraintRight_toRightOf="@+id/iv_reduce"
-        app:layout_constraintTop_toTopOf="@+id/iv_reduce" />
+    <!--    <ImageView-->
+    <!--        android:layout_width="wrap_content"-->
+    <!--        android:layout_height="wrap_content"-->
+    <!--        android:src="@mipmap/icon_reduce_symbol"-->
+    <!--        app:layout_constraintBottom_toBottomOf="@+id/iv_reduce"-->
+    <!--        app:layout_constraintLeft_toLeftOf="@+id/iv_reduce"-->
+    <!--        app:layout_constraintRight_toRightOf="@+id/iv_reduce"-->
+    <!--        app:layout_constraintTop_toTopOf="@+id/iv_reduce" />-->
 
     <ImageView
         android:id="@+id/iv_beat_value"
@@ -113,19 +149,19 @@
         android:id="@+id/iv_add"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:src="@mipmap/icon_metronome_bt_bg"
+        android:src="@mipmap/icon_metronome_add_bt_bg"
         app:layout_constraintLeft_toRightOf="@+id/iv_beat_value"
         app:layout_constraintRight_toRightOf="@+id/iv_plate"
         app:layout_constraintTop_toTopOf="@+id/iv_reduce" />
 
-    <ImageView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:src="@mipmap/icon_add_symbol"
-        app:layout_constraintBottom_toBottomOf="@+id/iv_add"
-        app:layout_constraintLeft_toLeftOf="@+id/iv_add"
-        app:layout_constraintRight_toRightOf="@+id/iv_add"
-        app:layout_constraintTop_toTopOf="@+id/iv_add" />
+    <!--    <ImageView-->
+    <!--        android:layout_width="wrap_content"-->
+    <!--        android:layout_height="wrap_content"-->
+    <!--        android:src="@mipmap/icon_add_symbol"-->
+    <!--        app:layout_constraintBottom_toBottomOf="@+id/iv_add"-->
+    <!--        app:layout_constraintLeft_toLeftOf="@+id/iv_add"-->
+    <!--        app:layout_constraintRight_toRightOf="@+id/iv_add"-->
+    <!--        app:layout_constraintTop_toTopOf="@+id/iv_add" />-->
 
     <TextView
         android:id="@+id/tv_current_beat"
@@ -134,61 +170,96 @@
         android:includeFontPadding="false"
         android:text="6/4"
         android:textColor="@color/color_1a1a1a"
-        android:textSize="@dimen/sp_16"
+        android:textSize="@dimen/sp_19"
+        android:drawablePadding="10dp"
+        android:textStyle="bold"
+        android:drawableRight="@mipmap/icon_play_beat_arrow_down"
         app:layout_constraintBottom_toBottomOf="@+id/iv_beat_value"
         app:layout_constraintLeft_toLeftOf="@+id/iv_beat_value"
         app:layout_constraintRight_toRightOf="@+id/iv_beat_value"
         app:layout_constraintTop_toTopOf="@+id/iv_beat_value"
         tools:text="6/4" />
 
+
     <androidx.appcompat.widget.AppCompatSeekBar
-        android:layout_marginTop="24dp"
         android:id="@+id/volume_seek_bar"
-        android:layout_width="182dp"
+        android:layout_width="210dp"
         android:layout_height="wrap_content"
-        app:layout_constraintRight_toRightOf="parent"
-        app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintTop_toBottomOf="@+id/iv_beat_value"
-        android:thumb="@drawable/shape_volume_seekbar_thumb"
-        android:progressDrawable="@drawable/bg_volume_seekbar"
+        android:layout_marginTop="24dp"
         android:max="100"
-        android:progress="50"
+        android:background="@null"
         android:maxHeight="4dp"
+        android:progress="50"
+        android:progressDrawable="@drawable/bg_volume_seekbar"
         android:splitTrack="false"
-        android:visibility="visible" />
+        android:thumb="@mipmap/icon_beat_volume_seekbar_thump"
+        android:visibility="visible"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/iv_beat_value" />
 
     <ImageView
-        android:layout_marginEnd="8dp"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="2dp"
+        android:src="@mipmap/icon_volume_trumpet_add"
         app:layout_constraintBottom_toBottomOf="@+id/volume_seek_bar"
-        app:layout_constraintTop_toTopOf="@+id/volume_seek_bar"
         app:layout_constraintRight_toLeftOf="@+id/volume_seek_bar"
-        android:src="@mipmap/icon_volume_trumpet_reduce"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"/>
+        app:layout_constraintTop_toTopOf="@+id/volume_seek_bar" />
 
-    <ImageView
-        android:layout_marginStart="8dp"
+    <!--    <ImageView-->
+    <!--        android:layout_marginStart="8dp"-->
+    <!--        app:layout_constraintBottom_toBottomOf="@+id/volume_seek_bar"-->
+    <!--        app:layout_constraintTop_toTopOf="@+id/volume_seek_bar"-->
+    <!--        app:layout_constraintLeft_toRightOf="@+id/volume_seek_bar"-->
+    <!--        android:src="@mipmap/icon_volume_trumpet_add"-->
+    <!--        android:layout_width="wrap_content"-->
+    <!--        android:layout_height="wrap_content"/>-->
+
+    <TextView
+        android:id="@+id/tv_volume_value"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingStart="6dp"
+        android:textColor="@color/color_58a2ec"
+        android:textSize="@dimen/sp_16"
         app:layout_constraintBottom_toBottomOf="@+id/volume_seek_bar"
-        app:layout_constraintTop_toTopOf="@+id/volume_seek_bar"
         app:layout_constraintLeft_toRightOf="@+id/volume_seek_bar"
-        android:src="@mipmap/icon_volume_trumpet_add"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"/>
+        app:layout_constraintTop_toTopOf="@+id/volume_seek_bar"
+        tools:text="40" />
 
-    <TextView
-        android:id="@+id/tv_play"
+
+    <LinearLayout
+        android:id="@+id/ll_play"
         android:layout_width="0dp"
-        android:layout_height="45dp"
+        android:layout_height="54dp"
         android:layout_marginStart="53dp"
         android:layout_marginTop="101dp"
         android:layout_marginEnd="53dp"
-        android:background="@drawable/shape_2dc7aa_24dp"
-        android:elevation="10dp"
+        android:background="@drawable/shape_00acff_27dp"
         android:gravity="center"
-        android:text="播放"
-        android:textColor="@color/white"
-        android:textSize="@dimen/sp_16"
+        android:orientation="horizontal"
         app:layout_constraintLeft_toLeftOf="parent"
         app:layout_constraintRight_toRightOf="parent"
-        app:layout_constraintTop_toBottomOf="@+id/iv_beat_value" />
+        app:layout_constraintTop_toBottomOf="@+id/iv_beat_value">
+
+        <TextView
+            android:id="@+id/tv_play"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:text="播放"
+            android:textColor="@color/white"
+            android:textSize="@dimen/sp_18"
+            android:textStyle="bold" />
+
+        <ImageView
+            android:id="@+id/iv_play_status_tag"
+            android:layout_marginStart="10dp"
+            android:src="@mipmap/icon_play_beat_bt_tag"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+    </LinearLayout>
+
+
 </androidx.constraintlayout.widget.ConstraintLayout>

+ 6 - 6
metronome/src/main/res/layout/item_beat_symbol_layout.xml

@@ -8,16 +8,16 @@
     <View
         android:visibility="gone"
         android:id="@+id/view_first"
-        android:layout_width="21dp"
-        android:layout_height="21dp"
+        android:layout_width="20dp"
+        android:layout_height="20dp"
         android:layout_gravity="center"
-        android:background="@drawable/shape_2dc7aa_beat_normal" />
+        android:background="@drawable/shape_ffffff_beat_normal" />
 
     <View
         android:id="@+id/view_other"
-        android:layout_width="17dp"
-        android:layout_height="17dp"
+        android:layout_width="20dp"
+        android:layout_height="20dp"
         android:layout_gravity="center"
-        android:background="@drawable/shape_2dc7aa_beat_normal"
+        android:background="@drawable/shape_ffffff_beat_normal"
         android:visibility="visible" />
 </FrameLayout>

+ 1 - 1
metronome/src/main/res/layout/pickerview_beat_symbol_layout.xml

@@ -24,7 +24,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_centerInParent="true"
-            android:text=""
+            android:text="调整拍数"
             android:textColor="@color/color_1a1a1a"
             android:textSize="18dp" />
 

BIN
metronome/src/main/res/mipmap-xhdpi/bg_metronome.png


BIN
metronome/src/main/res/mipmap-xhdpi/bg_metronome2.png


BIN
metronome/src/main/res/mipmap-xhdpi/bg_metronome3.png


BIN
metronome/src/main/res/mipmap-xhdpi/bg_metronome4.png


BIN
metronome/src/main/res/mipmap-xhdpi/bg_play_beat_big.png


BIN
metronome/src/main/res/mipmap-xhdpi/icon_beat_value_bg.png


BIN
metronome/src/main/res/mipmap-xhdpi/icon_beat_volume_seekbar_thump.png


BIN
metronome/src/main/res/mipmap-xhdpi/icon_metronome_add_bt_bg.png


BIN
metronome/src/main/res/mipmap-xhdpi/icon_metronome_bt_bg.png


BIN
metronome/src/main/res/mipmap-xhdpi/icon_pause_beat_bt_tag.png


BIN
metronome/src/main/res/mipmap-xhdpi/icon_play_beat_arrow_down.png


BIN
metronome/src/main/res/mipmap-xhdpi/icon_play_beat_bt_tag.png


BIN
metronome/src/main/res/mipmap-xhdpi/icon_play_beat_title.png


BIN
metronome/src/main/res/mipmap-xhdpi/icon_progress_bar_thump.png


BIN
metronome/src/main/res/mipmap-xhdpi/icon_volume_trumpet_add.png


BIN
metronome/src/main/res/mipmap-xxhdpi/bg_metronome.png


BIN
metronome/src/main/res/mipmap-xxhdpi/bg_metronome2.png


BIN
metronome/src/main/res/mipmap-xxhdpi/bg_metronome3.png


BIN
metronome/src/main/res/mipmap-xxhdpi/bg_metronome4.png


BIN
metronome/src/main/res/mipmap-xxhdpi/bg_play_beat_big.png


BIN
metronome/src/main/res/mipmap-xxhdpi/icon_beat_value_bg.png


BIN
metronome/src/main/res/mipmap-xxhdpi/icon_beat_volume_seekbar_thump.png


BIN
metronome/src/main/res/mipmap-xxhdpi/icon_metronome_add_bt_bg.png


BIN
metronome/src/main/res/mipmap-xxhdpi/icon_metronome_bt_bg.png


BIN
metronome/src/main/res/mipmap-xxhdpi/icon_pause_beat_bt_tag.png


BIN
metronome/src/main/res/mipmap-xxhdpi/icon_play_beat_arrow_down.png


BIN
metronome/src/main/res/mipmap-xxhdpi/icon_play_beat_bt_tag.png


BIN
metronome/src/main/res/mipmap-xxhdpi/icon_play_beat_title.png


BIN
metronome/src/main/res/mipmap-xxhdpi/icon_progress_bar_thump.png


BIN
metronome/src/main/res/mipmap-xxhdpi/icon_volume_trumpet_add.png


BIN
metronome/src/main/res/raw/tick.wav


BIN
metronome/src/main/res/raw/tock.wav


+ 7 - 0
metronome/src/main/res/values/colors.xml

@@ -1,3 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
+    <color name="color_58a2ec">#58A2EC</color>
+    <color name="color_3fceff">#3FCEFF</color>
+    <color name="color_28bdff">#28BDFF</color>
+    <color name="color_16afff">#16AFFF</color>
+    <color name="color_009fff">#009FFF</color>
+    <color name="color_0ba7ff">#0ba7ff</color>
+    <color name="color_51dbff">#51DBFF</color>
 </resources>

+ 4 - 1
metronome/src/main/res/values/themes.xml

@@ -1,3 +1,6 @@
 <resources xmlns:tools="http://schemas.android.com/tools">
-
+    <declare-styleable name="CircularSeekBar">
+        <!--seekbar最大值-->
+        <attr name="maxProgress" format="integer"/>
+    </declare-styleable>
 </resources>

+ 5 - 4
musictuner/build.gradle

@@ -34,10 +34,10 @@ android {
             minifyEnabled false
             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
         }
-        preRelease{
-            minifyEnabled false
-            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
-        }
+//        preRelease{
+//            minifyEnabled false
+//            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+//        }
     }
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_1_8
@@ -61,6 +61,7 @@ dependencies {
     implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
     testImplementation 'junit:junit:4.13.2'
     implementation project(':BaseLibrary')
+    implementation project(':metronome')
     androidTestImplementation 'androidx.test.ext:junit:1.1.3'
     androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
     implementation 'com.alibaba:arouter-api:1.5.2'

+ 2 - 0
musictuner/src/main/AndroidManifest.xml

@@ -5,6 +5,8 @@
     <application>
         <activity
             android:name=".MusicTunerActivity"
+            android:configChanges="orientation|screenSize|keyboardHidden|fontScale|smallestScreenSize|screenLayout"
+            android:screenOrientation="portrait"
             android:exported="false">
         </activity>
     </application>

+ 128 - 17
musictuner/src/main/java/com/cooleshow/musictuner/MusicTunerActivity.java

@@ -14,14 +14,22 @@ import android.Manifest;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.graphics.Color;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.widget.TextView;
 
 import com.alibaba.android.arouter.facade.annotation.Route;
+import com.alibaba.android.arouter.launcher.ARouter;
+import com.bigkoo.pickerview.builder.OptionsPickerBuilder;
+import com.bigkoo.pickerview.view.OptionsPickerView;
 import com.cooleshow.base.router.RouterPath;
 import com.cooleshow.base.ui.activity.BaseActivity;
 import com.cooleshow.base.utils.SizeUtils;
+import com.cooleshow.metronome.Utils.PlayBeanManager;
+import com.cooleshow.metronome.constants.MetronomeType;
 import com.cooleshow.musictuner.bean.VoiceToneBean;
 import com.cooleshow.musictuner.constants.MusicTunerConstants;
 import com.cooleshow.musictuner.databinding.ActivityMusicTunerLayoutBinding;
@@ -32,6 +40,8 @@ import com.cooleshow.musictuner.widget.MusicTunerSettingDialog;
 import com.cooleshow.musictuner.widget.MusicTuningForkDialog;
 import com.tbruyelle.rxpermissions3.RxPermissions;
 
+import java.util.ArrayList;
+
 @Route(path = RouterPath.MusicTuner.MUSIC_TUNER_PAGE)
 public class MusicTunerActivity extends BaseActivity<ActivityMusicTunerLayoutBinding> implements View.OnClickListener {
 
@@ -41,6 +51,8 @@ public class MusicTunerActivity extends BaseActivity<ActivityMusicTunerLayoutBin
     private boolean isOnPlayMusicFork = false;//是否正在播放当前音叉音
     private boolean isTransposing = false;
     private String currentTransposingTag = "";
+    private OptionsPickerView pvOptions;
+    private int currentSelectPosition;
 
     public static void start(Context context) {
         Intent intent = new Intent(context, MusicTunerActivity.class);
@@ -54,25 +66,33 @@ public class MusicTunerActivity extends BaseActivity<ActivityMusicTunerLayoutBin
                 .request(Manifest.permission.RECORD_AUDIO)
                 .subscribe(permission -> {
                     if (permission) {
-                        test();
+                        initHelper();
                     }
                 });
     }
 
     @Override
     protected void initView() {
-        initMidTitleToolBar(viewBinding.toolbarInclude.toolbar, "调音器");
+        initMidTitleToolBar(viewBinding.toolbarInclude.toolbar, "");
+        viewBinding.toolbarInclude.toolbar.setBackgroundColor(Color.TRANSPARENT);
+        viewBinding.toolbarInclude.ivTitle.setVisibility(View.VISIBLE);
+        viewBinding.toolbarInclude.ivTitle.setImageResource(R.drawable.icon_music_tuner_title);
+
         viewBinding.ivHzAdd.setOnClickListener(this);
         viewBinding.ivHzReduce.setOnClickListener(this);
         viewBinding.ivLeftBg.setOnClickListener(this);
         viewBinding.ivRightBg.setOnClickListener(this);
+        viewBinding.ivPlayMetronome.setOnClickListener(this);
+        viewBinding.ivMetronomeModeBg.setOnClickListener(this);
+        viewBinding.ivMetronomeSpeedBg.setOnClickListener(this);
         viewBinding.toolbarInclude.tvRightText.setOnClickListener(this);
-        viewBinding.toolbarInclude.tvRightText.setText("设置");
         viewBinding.toolbarInclude.tvRightText.setCompoundDrawablePadding(SizeUtils.dp2px(5));
         viewBinding.toolbarInclude.tvRightText.setVisibility(View.VISIBLE);
         viewBinding.toolbarInclude.tvRightText.setCompoundDrawablesWithIntrinsicBounds(null, null, getResources().getDrawable(R.drawable.icon_music_tuner_setting), null);
         VoiceDataUtils.getInstance().resetHzStandard();
         updateCurrentHzStandardText();
+        Log.i("qwe","MusicTunerActivity onCreate"+this);
+        PlayBeanManager.getInstance().init(this);
     }
 
     @Override
@@ -80,7 +100,26 @@ public class MusicTunerActivity extends BaseActivity<ActivityMusicTunerLayoutBin
         return ActivityMusicTunerLayoutBinding.inflate(getLayoutInflater());
     }
 
-    private void test() {
+    @Override
+    protected void onResume() {
+        super.onResume();
+        updateBeatInfo();
+    }
+
+    private void updateBeatInfo() {
+        String currentSpeed = PlayBeanManager.getInstance().getCurrentSpeed();
+        String currentBeatTypeName = PlayBeanManager.getInstance().getCurrentBeanType();
+        viewBinding.tvPlayBeatSpeed.setText(currentSpeed);
+        viewBinding.tvPlayBeatType.setText(currentBeatTypeName);
+        updatePlayIcon();
+    }
+
+    private void updatePlayIcon() {
+        boolean playing = PlayBeanManager.getInstance().isPlaying();
+        viewBinding.ivPlayMetronome.setImageResource(playing ? R.drawable.icon_pause_metronome_bt : R.drawable.icon_play_metronome_bt);
+    }
+
+    private void initHelper() {
         if (mMusicTunerHelper == null) {
             mMusicTunerHelper = new MusicTunerHelper(new MusicTunerHelper.OnEventListener() {
                 @Override
@@ -122,7 +161,9 @@ public class MusicTunerActivity extends BaseActivity<ActivityMusicTunerLayoutBin
             viewBinding.ivCorrect.setVisibility(isCorrect ? View.VISIBLE : View.GONE);
             viewBinding.progress.setProgress(getDiffProgress((int) differenceValue));
 
+            viewBinding.tvDifference.setTextColor(getResources().getColor(isCorrect ? com.cooleshow.base.R.color.white: com.cooleshow.base.R.color.color_333333));
             viewBinding.tvDifference.setText(differenceValue != -100 ? String.format("%d¢", differenceValue) : "");
+            viewBinding.viewDashBoard.setCorrect(isCorrect);
             viewBinding.viewDashBoard.setProgress((int) differenceValue);
         }
     }
@@ -174,18 +215,6 @@ public class MusicTunerActivity extends BaseActivity<ActivityMusicTunerLayoutBin
     }
 
     @Override
-    protected void onDestroy() {
-        if (viewBinding != null) {
-            viewBinding.viewDashBoard.release();
-        }
-        super.onDestroy();
-        if (mMusicTunerHelper != null) {
-            mMusicTunerHelper.release();
-        }
-        AudioTrackManager.getInstance().stop();
-    }
-
-    @Override
     public void onClick(View v) {
         int id = v.getId();
         if (id == R.id.iv_hz_add) {
@@ -225,6 +254,29 @@ public class MusicTunerActivity extends BaseActivity<ActivityMusicTunerLayoutBin
             }
             return;
         }
+
+        if (id == R.id.iv_play_metronome) {
+            if (PlayBeanManager.getInstance().isPlaying()) {
+                PlayBeanManager.getInstance().pausePlay();
+                viewBinding.ivPlayMetronome.setImageResource(R.drawable.icon_play_metronome_bt);
+            } else {
+                PlayBeanManager.getInstance().play();
+                viewBinding.ivPlayMetronome.setImageResource(R.drawable.icon_pause_metronome_bt);
+            }
+            return;
+        }
+
+        if (id == R.id.iv_metronome_mode_bg) {
+            selectSymbols();
+            return;
+        }
+
+        if (id == R.id.iv_metronome_speed_bg) {
+            ARouter.getInstance().build(RouterPath.Other.METRONOME_PAGE)
+                    .withBoolean("isUpdateMode", true)
+                    .navigation();
+            return;
+        }
     }
 
     private void showTuningForkDialog() {
@@ -233,6 +285,7 @@ public class MusicTunerActivity extends BaseActivity<ActivityMusicTunerLayoutBin
             mTuningForkDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
                 @Override
                 public void onDismiss(DialogInterface dialog) {
+                    switchMusicForkImg(false);
                     if (!isOnPlayMusicFork) {
                         AudioTrackManager.getInstance().stop();
                     }
@@ -241,9 +294,14 @@ public class MusicTunerActivity extends BaseActivity<ActivityMusicTunerLayoutBin
         }
         if (!mTuningForkDialog.isShowing()) {
             mTuningForkDialog.show();
+            switchMusicForkImg(true);
         }
     }
 
+    private void switchMusicForkImg(boolean isSelected) {
+        viewBinding.ivMusicFork.setSelected(isSelected);
+    }
+
     private void playMusicFork() {
         int currentMusicMenu;
         if (mTuningForkDialog != null) {
@@ -265,7 +323,7 @@ public class MusicTunerActivity extends BaseActivity<ActivityMusicTunerLayoutBin
 
     private void updateCurrentHzStandardText() {
         int currentMusicHzStandard = VoiceDataUtils.getInstance().getCurrentMusicHzStandard();
-        viewBinding.ivMusicHzTip.setVisibility(currentMusicHzStandard == VoiceDataUtils.DEFAULT_MUSIC_HZ_STANDARD_440_HZ ? View.GONE : View.VISIBLE);
+        viewBinding.ivMusicHzTip.setVisibility(currentMusicHzStandard == VoiceDataUtils.DEFAULT_MUSIC_HZ_STANDARD_SELECT_HZ ? View.GONE : View.VISIBLE);
         viewBinding.tvMusicHzStandard.setText(getString(R.string.music_hz_str, currentMusicHzStandard));
     }
 
@@ -314,4 +372,57 @@ public class MusicTunerActivity extends BaseActivity<ActivityMusicTunerLayoutBin
             viewBinding.tvResultVoiceTones.setVisibility(View.VISIBLE);
         }
     }
+
+
+    private void selectSymbols() {
+        ArrayList<MetronomeType> allBeatTypeList = PlayBeanManager.getInstance().getAllBeatTypeList();
+        pvOptions = new OptionsPickerBuilder(this, (options1, options2, options3, v) -> {
+            this.currentSelectPosition = options1;
+            MetronomeType metronomeType = allBeatTypeList.get(currentSelectPosition);
+            PlayBeanManager.getInstance().pausePlay();
+            PlayBeanManager.getInstance().setBeat(metronomeType);
+            updateBeatInfo();
+        }).setTitleText("拍号").setTitleColor(Color.BLACK).setLayoutRes(com.cooleshow.metronome.R.layout.pickerview_beat_symbol_layout, v -> {
+            //自定义布局中的控件初始化及事件处理
+            final TextView tvSubmit = (TextView) v.findViewById(com.cooleshow.base.R.id.tv_finish);
+            TextView ivCancel = (TextView) v.findViewById(com.cooleshow.base.R.id.tv_cancel);
+            tvSubmit.setOnClickListener(v12 -> {
+                pvOptions.returnData();
+                pvOptions.dismiss();
+            });
+            ivCancel.setOnClickListener(v1 -> pvOptions.dismiss());
+
+        }).isDialog(false).build();
+        pvOptions.setPicker(allBeatTypeList);
+        if (currentSelectPosition < allBeatTypeList.size()) {
+            pvOptions.setSelectOptions(currentSelectPosition);
+        }
+        pvOptions.show();
+
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        if(isFinishing()){
+            //提前释放相关资源
+            releaseBeatManager();
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        if (viewBinding != null) {
+            viewBinding.viewDashBoard.release();
+        }
+        super.onDestroy();
+        AudioTrackManager.getInstance().stop();
+        if (mMusicTunerHelper != null) {
+            mMusicTunerHelper.release();
+        }
+    }
+
+    private void releaseBeatManager() {
+        PlayBeanManager.getInstance().release();
+    }
 }

+ 21 - 6
musictuner/src/main/java/com/cooleshow/musictuner/constants/MusicTunerConstants.java

@@ -6,18 +6,33 @@ package com.cooleshow.musictuner.constants;
 public class MusicTunerConstants {
     public final static String[] TITLES = new String[]{"没有移调",
             "长笛:C调", "高音萨克斯:降B调", "中音萨克斯:降E调",
-            "单簧管:降B调", "双簧管:C调", "竖笛:C调",
+            "单簧管:降B调", "双簧管:C调",
             "小号:降B调", "长号:C调", "圆号:F调",
-            "大号:降B调", "上低音号:C调", "上低音号:降B调"};
-    public final static int[] TRANSPOSING_VALUES = new int[]{0, 0, -10, -3, -10, 0, -12, -10, 0, -5, -10, 0, -10};
+            "大号:降B调", "上低音号:C调", "上低音号:降B调",
+            "葫芦丝:C调", "葫芦丝:D调", "葫芦丝:降B调", "葫芦丝:F调", "葫芦丝:G调",
+            "排箫:C调", "排箫:D调", "排箫:E调", "排箫:F调", "排箫:G调",
+            "竖笛:C调", "竖笛:中音F调",
+            "口风琴:C调",
+            "陶笛:SC调","陶笛:AC调","陶笛:AG调","陶笛:AF调","陶笛:BC调"};
+    public final static int[] TRANSPOSING_VALUES = new int[]{0, 0, -10, -3, -10, 0, -10, 0, -5, -10, 0, -10,
+            -12, -2, -11, -5, -7,
+            -12, -14, -16, -17, -19,
+            -12, -5,
+             0,
+            -24,-12,-7,-12,0};
     //private let flats = ["C", "D♭","D","E♭","E","F","G♭","G","A♭","A","B♭","B"]
     public final static String[] TRANSPOSING_TITLE_TAG = new String[]{"C",
             "C", "B♭", "E♭",
-            "B♭", "C", "C",
+            "B♭", "C",
             "B♭", "C", "F",
-            "B♭", "C", "B♭"};
+            "B♭", "C", "B♭",
+            "C", "D", "B♭", "F", "G",
+            "C", "D", "E", "F", "G",
+            "C", "F",
+            "C",
+            "C","C","G","F","C"};
 
-    public final static int CORRECT_VALUE_RANGE =10;//音频值差值正确值范围
+    public final static int CORRECT_VALUE_RANGE = 10;//音频值差值正确值范围
 
     public final static int TUNER_POINTER_ANIMATION =220;//调音器指针动画持续时间,建议不要修改了
 }

+ 18 - 13
musictuner/src/main/java/com/cooleshow/musictuner/utils/VoiceDataUtils.java

@@ -26,12 +26,15 @@ public class VoiceDataUtils {
     public ArrayList<VoiceToneBean> voiceToneBeans;
     public static final int MIN_MUSIC_HZ_STANDARD_415_HZ = 415;//最小415Hz
     public static final int MAX_MUSIC_HZ_STANDARD_445_HZ = 445;//最大445Hz
-    public static final int DEFAULT_MUSIC_HZ_STANDARD_440_HZ = 440;//默认440
+    public static final int MUSIC_HZ_STANDARD_440_HZ = 440;//440
+    public static final int MUSIC_HZ_STANDARD_442_HZ = 442;//442
+    public static final int DEFAULT_MUSIC_HZ_STANDARD_SELECT_HZ = MUSIC_HZ_STANDARD_440_HZ;//默认440
     public static final int MAX_MUSIC_POS = 8;//最大C8 D8这种
     public static final int MIN_MUSIC_POS = 0;//最小C0 D0这种
-    public static final int DEFAULT_MUSIC_POS = 5;//默认
-    public static final double DEFAULT_MUSIC_FORK_MUSIC = 523.3;//默认音叉播放的音
-    public int currentMusicHzStandard = DEFAULT_MUSIC_HZ_STANDARD_440_HZ;
+    public static final int DEFAULT_MUSIC_POS = 4;//默认
+    public static final double DEFAULT_MUSIC_FORK_MUSIC = 440.0;//默认音叉播放A4的音
+    public int currentMusicHzStandard = DEFAULT_MUSIC_HZ_STANDARD_SELECT_HZ;
+    public int MUSIC_HZ_STANDARD = MUSIC_HZ_STANDARD_440_HZ;//样本值标准按440算
 
     private VoiceDataUtils() {
     }
@@ -70,7 +73,9 @@ public class VoiceDataUtils {
         if (targetVoiceFrequencyValue == -1) {
             return null;
         }
-        targetVoiceFrequencyValue = countWithMusicHzStandard(targetVoiceFrequencyValue);
+        Log.i("searchTarget","count before:"+targetVoiceFrequencyValue);
+        targetVoiceFrequencyValue = (float) countWithMusicHzStandard2(targetVoiceFrequencyValue);
+        Log.i("searchTarget","count after:"+targetVoiceFrequencyValue);
         if (targetVoiceFrequencyValue >= ALL_VOICE_SAMPLES[ALL_VOICE_SAMPLES.length - 1]) {
             VoiceToneBean voiceToneBean = buildBean(ALL_VOICE_SAMPLES.length - 2, ALL_VOICE_SAMPLES.length - 3, ALL_VOICE_SAMPLES.length - 1);
             voiceToneBean.difference = String.valueOf(targetVoiceFrequencyValue - ALL_VOICE_SAMPLES[ALL_VOICE_SAMPLES.length - 2]);
@@ -138,11 +143,11 @@ public class VoiceDataUtils {
         //如果有移调 赋值移调后的音阶名
         voiceToneBean.transposingName = countName(namePos);
         voiceToneBean.name = countName(pos);
-        voiceToneBean.voiceFrequencyValue = countWithMusicHzStandard2(ALL_VOICE_SAMPLES[pos]);
+        voiceToneBean.voiceFrequencyValue = countWithMusicHzStandard(ALL_VOICE_SAMPLES[pos]);
         voiceToneBean.beforeName = countName(beforeNamePos);
-        voiceToneBean.beforeVoiceFrequencyValue = countWithMusicHzStandard2(ALL_VOICE_SAMPLES[beforePos]);
+        voiceToneBean.beforeVoiceFrequencyValue = countWithMusicHzStandard(ALL_VOICE_SAMPLES[beforePos]);
         voiceToneBean.afterName = countName(nameAfterPos);
-        voiceToneBean.afterVoiceFrequencyValue = countWithMusicHzStandard2(ALL_VOICE_SAMPLES[afterPos]);
+        voiceToneBean.afterVoiceFrequencyValue = countWithMusicHzStandard(ALL_VOICE_SAMPLES[afterPos]);
         Log.i("qaz", "result name:" + voiceToneBean.name +
                 "\nvalue:" + voiceToneBean.voiceFrequencyValue);
         return voiceToneBean;
@@ -205,16 +210,16 @@ public class VoiceDataUtils {
     }
 
     public void resetHzStandard() {
-        currentMusicHzStandard = DEFAULT_MUSIC_HZ_STANDARD_440_HZ;
+        currentMusicHzStandard = DEFAULT_MUSIC_HZ_STANDARD_SELECT_HZ;
     }
 
-    private float countWithMusicHzStandard(float target) {
-        float value = target * DEFAULT_MUSIC_HZ_STANDARD_440_HZ / currentMusicHzStandard;
+    private double countWithMusicHzStandard(double target) {
+        double value = target * currentMusicHzStandard / MUSIC_HZ_STANDARD;
         return value;
     }
 
     private double countWithMusicHzStandard2(double target) {
-        double value = target / DEFAULT_MUSIC_HZ_STANDARD_440_HZ * currentMusicHzStandard;
+        double value = target / currentMusicHzStandard * MUSIC_HZ_STANDARD;
         return value;
     }
 
@@ -237,6 +242,6 @@ public class VoiceDataUtils {
      */
     public double getTargetFromSamples(int posFromVoiceOfTone, int phase) {
         int pos = VOICE_OF_TONE.length * phase + posFromVoiceOfTone;
-        return countWithMusicHzStandard((float) ALL_VOICE_SAMPLES[pos]);
+        return countWithMusicHzStandard(ALL_VOICE_SAMPLES[pos]);
     }
 }

+ 314 - 84
musictuner/src/main/java/com/cooleshow/musictuner/widget/DashBoardView.java

@@ -3,6 +3,8 @@ package com.cooleshow.musictuner.widget;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.LinearGradient;
@@ -15,6 +17,7 @@ import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Shader;
 import android.graphics.SweepGradient;
+import android.graphics.Typeface;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.TypedValue;
@@ -22,6 +25,7 @@ import android.view.View;
 
 import com.cooleshow.base.utils.LOG;
 import com.cooleshow.base.utils.SizeUtils;
+import com.cooleshow.musictuner.R;
 import com.cooleshow.musictuner.constants.MusicTunerConstants;
 
 import androidx.annotation.Nullable;
@@ -30,6 +34,7 @@ import androidx.annotation.Nullable;
  * Author by pq, Date on 2022/9/26.
  */
 public class DashBoardView extends View {
+    private static final String TAG = "DashBoardView";
     private int cx = 0;//圆心点坐标x
     private int cy = 0;//圆心点坐标y
     private int width;
@@ -53,16 +58,31 @@ public class DashBoardView extends View {
     private RectF mGradientLineRectF;
     private Paint mPointerPaint;
     private float pointerHeight = 0;//指针高度
-    private double innerGradientRadiusPercent = 0.75;//渐变线的圆半径比例
+    private double innerGradientRadiusPercent = 0.68;//渐变线的圆半径比例
+    private double innerHighlightRadiusPercent = 0.83;//中心高亮
+    private double scaleRoundPercent = 0.95;//刻度圆环比例
+    private float centerRound1RadiusPercent = 0.49f;//内圆半径比例
+    private float centerRound2RadiusPercent = 0.36f;//最里面内圆半径比例
     private int pointerAngle = 0;
     private float currentProgress = 0;
     private RectF whiteAreaRectF;
     private Paint mWhiteAreaPaint;
     private int whiteAreaStartColor;
     private int whiteAreaEndColor;
+    private RectF mWhiteBoardBgRect;
+    private Paint mBgPaint;
+    private Paint mCenterRound1Paint;
+    private Paint mCenterRound2Paint;
+    private Bitmap triangleBitmap;
+    private Rect triangleRect1;
+    private Rect triangleShowRect;
 
     private ValueAnimator mAnimator;
 
+    private Paint mCorrectPaint;
+
+    private boolean isCorrect = false;
+
     public DashBoardView(Context context) {
         this(context, null);
     }
@@ -77,9 +97,14 @@ public class DashBoardView extends View {
     }
 
     private void init() {
+        triangleBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_music_tuner_triangle_small);
+        int width = triangleBitmap.getWidth();
+        int height = triangleBitmap.getHeight();
+        triangleRect1 = new Rect(0, 0, width, height);
+
 
-        whiteAreaStartColor = Color.parseColor("#006DB7FF");
-        whiteAreaEndColor = Color.parseColor("#606DB7FF");
+        whiteAreaStartColor = Color.parseColor("#8AD0FF");
+        whiteAreaEndColor = Color.parseColor("#006DBCFF");
         mLinePaint = new Paint();
         mLinePaint.setStrokeCap(Paint.Cap.ROUND);
         mLinePaint.setStrokeWidth(SizeUtils.dp2px(1));
@@ -92,20 +117,20 @@ public class DashBoardView extends View {
         mTextValuePaint = new Paint();
         mTextValuePaint.setAntiAlias(true);
         mTextValuePaint.setStrokeCap(Paint.Cap.ROUND);
-        mTextValuePaint.setColor(Color.WHITE);
-        mTextValuePaint.setTextSize(SizeUtils.sp2px(10));
+        mTextValuePaint.setColor(getResources().getColor(com.cooleshow.base.R.color.color_333333));
+        mTextValuePaint.setTextSize(SizeUtils.sp2px(14));
         mTextValuePaint.setTextAlign(Paint.Align.LEFT);
         mTextValuePaint.setStyle(Paint.Style.FILL);
-        mTextValuePaint.setAlpha(160);
+        mTextValuePaint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
 
         mPointerPaint = new Paint();
         mPointerPaint.setAntiAlias(true);
         mPointerPaint.setDither(true);
-        mPointerPaint.setColor(Color.WHITE);
+        mPointerPaint.setStrokeCap(Paint.Cap.ROUND);
+        mPointerPaint.setColor(getContext().getResources().getColor(R.color.color_0082ff));
         mPointerPaint.setStyle(Paint.Style.FILL);
-        mPointerPaint.setStrokeWidth(SizeUtils.dp2px(2));
-
-//        initWhiteAreaPaint();
+        mPointerPaint.setStrokeWidth(SizeUtils.dp2px(3));
+        initCenterRound2Paint();
     }
 
     @Override
@@ -115,12 +140,25 @@ public class DashBoardView extends View {
         height = getHeight();// Get View Height
         width = MeasureSpec.getSize(widthMeasureSpec);
         height = MeasureSpec.getSize(heightMeasureSpec);
-        cx = width / 2;
+        Log.i(TAG, "width2:" + width);
+        Log.i(TAG, "height2:" + height);
+        cx = width / 2;//坐标圆点x坐标
         cy = height - paddingBottom;
+
         mRadius = (int) ((width / 2) * 0.8);
-        pointerHeight = (float) (mRadius * innerGradientRadiusPercent + SizeUtils.dp2px(9));//加上渐变环线笔的宽度的一半
-        initGradientPaint();
-        initWhiteAreaPaint();
+        Log.i(TAG, "mRadius:" + mRadius);
+        //底部多预留30度角度的高度
+        double sin = Math.sin(2 * Math.PI / 360 * 30);
+        paddingBottom = (int) (mRadius * sin);
+        Log.i(TAG, "paddingBottom:" + paddingBottom);
+
+        height = cx + paddingBottom;//View的实际需要高度
+
+        cy = height - paddingBottom;//坐标圆点y坐标
+        setMeasuredDimension(getWidth(), height);
+
+        pointerHeight = (float) (mRadius * innerGradientRadiusPercent + SizeUtils.dp2px(16));//加上渐变环线笔的宽度的一半
+
 
         mGradientLineRectF = new RectF();
         mGradientLineRectF.set(
@@ -130,10 +168,23 @@ public class DashBoardView extends View {
                 (float) (cy + (mRadius * innerGradientRadiusPercent))
         );
         whiteAreaRectF = new RectF();
-        whiteAreaRectF.set((float) (cx - mRadius * innerGradientRadiusPercent),
-                (float) (cy - (mRadius * innerGradientRadiusPercent) + SizeUtils.dp2px(9)),
-                (float) (cx + mRadius * innerGradientRadiusPercent),
-                (float) (cy + (mRadius * innerGradientRadiusPercent) - SizeUtils.dp2px(9)));
+        whiteAreaRectF.set((float) (cx - mRadius * innerHighlightRadiusPercent),
+                (float) (cy - (mRadius * innerHighlightRadiusPercent)),
+                (float) (cx + mRadius * innerHighlightRadiusPercent),
+                (float) (cy + (mRadius * innerHighlightRadiusPercent)));
+
+        mWhiteBoardBgRect = new RectF();
+        double bgRadiusPercent = 1.0;
+        mWhiteBoardBgRect.set((float) (cx - mRadius * bgRadiusPercent),
+                (float) (cy - (mRadius * bgRadiusPercent)),
+                (float) (cx + mRadius * bgRadiusPercent),
+                (float) (cy + (mRadius * bgRadiusPercent)));
+
+
+        initGradientPaint();
+        initWhiteAreaPaint();
+        initBgPaint();
+        initCenterRound1Paint();
     }
 
     private void initGradientPaint() {
@@ -142,9 +193,17 @@ public class DashBoardView extends View {
             mOuterGradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
             //设置圆环渐变色渲染
             mOuterGradientPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
-            float position[] = {0f, 0.25f, 0.5f, 0.875f};
-            int[] colors = new int[]{getResources().getColor(com.cooleshow.base.R.color.color_4effc2), getResources().getColor(com.cooleshow.base.R.color.color_4effc2), getResources().getColor(com.cooleshow.base.R.color.color_ff41d3), getResources().getColor(com.cooleshow.base.R.color.color_4effc2)};
+            float position[] = {0f, 0.25f, 0.5f, 0.75f, 1.0f};
+            int[] colors = new int[]{getColor(R.color.color_abeeff), Color.TRANSPARENT, getColor(R.color.color_50c0ff), getColor(R.color.color_7cd3ff), getColor(R.color.color_abeeff)};
             Shader mShader = new SweepGradient(cx, cy, colors, position);
+
+
+//            float outerGradientRadius = (float) (mRadius * innerHighlightRadiusPercent);
+//            Shader mShader = new LinearGradient(cx, cy-outerGradientRadius, cx, cy+outerGradientRadius, getResources().getColor(com.cooleshow.base.R.color.color_0aa6ff),
+//                    getResources().getColor(com.cooleshow.base.R.color.color_74E4FF), Shader.TileMode.CLAMP);
+            mOuterGradientPaint.setShader(mShader);
+
+
             mOuterGradientPaint.setShader(mShader);
             mOuterGradientPaint.setStrokeCap(Paint.Cap.ROUND);
             mOuterGradientPaint.setStyle(Paint.Style.STROKE);
@@ -153,26 +212,120 @@ public class DashBoardView extends View {
     }
 
     private void initWhiteAreaPaint() {
-        mWhiteAreaPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mWhiteAreaPaint.setDither(true);
-        mWhiteAreaPaint.setAntiAlias(true);
+        if (mWhiteAreaPaint == null) {
+            mWhiteAreaPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+            mWhiteAreaPaint.setDither(true);
+            mWhiteAreaPaint.setAntiAlias(true);
+//        Shader mShader = new LinearGradient(0,0,100,100,Color.parseColor("#6DB7FF"),Color.parseColor("#006DB7FF"), Shader.TileMode.MIRROR);
+//        mWhiteAreaPaint.setColor(Color.parseColor("#256DB7FF"));
+            int r = (int) (mRadius * innerGradientRadiusPercent - SizeUtils.dp2px(9));
+            Shader mShader = new RadialGradient(cx, cy, r, whiteAreaStartColor, whiteAreaEndColor, Shader.TileMode.MIRROR);
+            mWhiteAreaPaint.setShader(mShader);
+            mWhiteAreaPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
+            mWhiteAreaPaint.setStyle(Paint.Style.FILL);
+            mWhiteAreaPaint.setStrokeCap(Paint.Cap.ROUND);
+            mWhiteAreaPaint.setStrokeWidth(1);
+        }
+    }
+
+    private void initBgPaint() {
+        if (mBgPaint == null) {
+            mBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+            mBgPaint.setDither(true);
+            mBgPaint.setAntiAlias(true);
 //        Shader mShader = new LinearGradient(0,0,100,100,Color.parseColor("#6DB7FF"),Color.parseColor("#006DB7FF"), Shader.TileMode.MIRROR);
 //        mWhiteAreaPaint.setColor(Color.parseColor("#256DB7FF"));
-        int r= (int) (mRadius * innerGradientRadiusPercent- SizeUtils.dp2px(9));
-        Shader mShader = new RadialGradient(cx,cy,r,whiteAreaStartColor,whiteAreaEndColor,Shader.TileMode.MIRROR);
-        mWhiteAreaPaint.setShader(mShader);
-        mWhiteAreaPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
-        mWhiteAreaPaint.setStyle(Paint.Style.FILL);
-        mWhiteAreaPaint.setStrokeCap(Paint.Cap.ROUND);
-        mWhiteAreaPaint.setStrokeWidth(1);
+//            int r = (int) (mRadius * innerGradientRadiusPercent - SizeUtils.dp2px(9));
+//        Shader mShader = new RadialGradient(cx, cy, r, whiteAreaStartColor, whiteAreaEndColor, Shader.TileMode.MIRROR);
+//        mBgPaint.setShader(mShader);
+
+            mBgPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
+            float position[] = {0f, 0.075f, 0.25f, 0.425f, 0.5f, 0.525f, 0.75f, 0.975f, 1.0f};
+            int[] colors = new int[]{getResources().getColor(R.color.white_35),
+                    getResources().getColor(com.cooleshow.base.R.color.transparent),
+                    getResources().getColor(com.cooleshow.base.R.color.transparent),
+                    getResources().getColor(com.cooleshow.base.R.color.transparent),
+                    getResources().getColor(R.color.white_35),
+                    getResources().getColor(R.color.white_75),
+                    getResources().getColor(com.cooleshow.base.R.color.white),
+                    getResources().getColor(R.color.white_75),
+                    getResources().getColor(R.color.white_35)};
+            Shader mShader = new SweepGradient(cx, cy, colors, position);
+            mBgPaint.setShader(mShader);
+            mBgPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
+            mBgPaint.setStyle(Paint.Style.FILL);
+            mBgPaint.setStrokeCap(Paint.Cap.ROUND);
+            mBgPaint.setStrokeWidth(1);
+            mBgPaint.setColor(Color.WHITE);
+        }
+    }
+
+    private void initCenterRound1Paint() {
+        if (mCenterRound1Paint == null) {
+            mCenterRound1Paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+            mCenterRound1Paint.setDither(true);
+            mCenterRound1Paint.setAntiAlias(true);
+            float centerRoundRadius = mRadius * centerRound1RadiusPercent;
+            Shader mShader = new LinearGradient(cx, cy - centerRoundRadius, cx, cy + centerRoundRadius, Color.WHITE, Color.parseColor("#D8ECFE"), Shader.TileMode.CLAMP);
+            mCenterRound1Paint.setShader(mShader);
+
+            mCenterRound1Paint.setStyle(Paint.Style.FILL);
+            mCenterRound1Paint.setStrokeCap(Paint.Cap.ROUND);
+            mCenterRound1Paint.setStrokeWidth(1);
+            mCenterRound1Paint.setColor(Color.RED);
+
+            float s = centerRoundRadius - SizeUtils.dp2px(5);
+            int left = cx - triangleBitmap.getWidth() / 2;
+            int top = (int) (cy - s);
+            int right = cx + triangleBitmap.getWidth() / 2;
+            int bottom = top + triangleBitmap.getHeight();
+            triangleShowRect = new Rect(left, top, right, bottom);
+        }
+
+        if (mCorrectPaint == null) {
+            mCorrectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+            float centerRoundRadius = mRadius * 0.36f;
+            int startColor = getColor(R.color.color_90e9ff);
+            int endColor = getColor(R.color.color_11a9ff);
+            Shader shader = new LinearGradient(cx, cy - centerRoundRadius, cx, cy + centerRoundRadius, startColor, endColor, Shader.TileMode.CLAMP);
+            mCorrectPaint.setShader(shader);
+            mCorrectPaint.setDither(true);
+            mCorrectPaint.setAntiAlias(true);
+            mCorrectPaint.setStyle(Paint.Style.FILL);
+            mCorrectPaint.setStrokeCap(Paint.Cap.ROUND);
+            mCorrectPaint.setStrokeWidth(1);
+            mCorrectPaint.setColor(Color.WHITE);
+        }
+    }
+
+    private void initCenterRound2Paint() {
+        if (mCenterRound2Paint == null) {
+            mCenterRound2Paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+            mCenterRound2Paint.setDither(true);
+            mCenterRound2Paint.setAntiAlias(true);
+
+            mCenterRound2Paint.setStyle(Paint.Style.FILL);
+            mCenterRound2Paint.setStrokeCap(Paint.Cap.ROUND);
+            mCenterRound2Paint.setStrokeWidth(1);
+            mCenterRound2Paint.setColor(Color.WHITE);
+        }
+    }
+
+    public void setCorrect(boolean correct) {
+        isCorrect = correct;
     }
 
     @Override
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
 //        canvas.drawLine(cx, cy, cx, 0, mCenterPointPaint);
-        canvas.drawArc(whiteAreaRectF, -108, 36, true, mWhiteAreaPaint);
+//        canvas.drawArc();
+        canvas.drawArc(mWhiteBoardBgRect, -210, 240, true, mBgPaint);
+
+        //渐变色环形条
         canvas.drawArc(mGradientLineRectF, -180, 180, false, mOuterGradientPaint);
+        //指针中心光亮区域
+        canvas.drawArc(whiteAreaRectF, -108, 36, true, mWhiteAreaPaint);
 
         LOG.i("onDraw:" + currentProgress);
         currentProgress += offsetValue;
@@ -183,58 +336,39 @@ public class DashBoardView extends View {
             currentProgress = minMusicHzOffset;
         }
         float[] floats = countPointerPosition(currentProgress);
+        float angle = floats[2];
         canvas.drawLine(cx, cy, floats[0], floats[1], mPointerPaint);
 
+        //中心圆背景1
+        canvas.drawCircle(cx, cy, mRadius * centerRound1RadiusPercent, mCenterRound1Paint);
 
-        //绘制长刻度
-        mLinePaint.setAlpha(255);
-        float x0 = cx;
-        float y0 = height - mRadius;
-        float x1 = cx;
-        float y1 = y0 + longScaleLineHeight;
-        // 逆时针到开始处
-        canvas.save();
-        // 逆时针到开始处
-        canvas.save();
-        canvas.drawLine(x0, y0, x1, y1, mLinePaint);
-        float degree = mSweepAngle / mSection;
-        for (int i = 0; i < mSection / 2; i++) {
-            canvas.rotate(-degree, cx, cy);
-            canvas.drawLine(x0, y0, x1, y1, mLinePaint);
-        }
-        canvas.restore();
-        // 顺时针到结尾处
-        canvas.save();
-        for (int i = 0; i < mSection / 2; i++) {
-            canvas.rotate(degree, cx, cy);
-            canvas.drawLine(x0, y0, x1, y1, mLinePaint);
-        }
-        canvas.restore();
+        //中心圆背景2
+        mCenterRound2Paint.setStyle(Paint.Style.FILL);
+        mCenterRound2Paint.setColor(Color.WHITE);
+        LOG.i("isCorrect:" + isCorrect);
+        canvas.drawCircle(cx, cy, mRadius * centerRound2RadiusPercent, isCorrect ? mCorrectPaint : mCenterRound2Paint);
+        mCenterRound2Paint.setStyle(Paint.Style.STROKE);
+        mCenterRound2Paint.setStrokeWidth(2);
+        mCenterRound2Paint.setColor(getResources().getColor(R.color.color_e8f4ff));
+        canvas.drawCircle(cx, cy, mRadius * 0.36f, mCenterRound2Paint);
 
-        /**
-         * 画短刻度
-         * 同样采用canvas的旋转原理
-         */
-        mLinePaint.setAlpha(90);
 
-        float x2 = cx;
-        float y2 = y0 + shortScaleLineHeight;
-        // 逆时针到开始处
         canvas.save();
-        canvas.drawLine(x0, y0, x2, y2, mLinePaint);
-        degree = mSweepAngle / (mSection * mPortion);
-        for (int i = 0; i < (mSection * mPortion) / 2; i++) {
-            canvas.rotate(-degree, cx, cy);
-            canvas.drawLine(x0, y0, x2, y2, mLinePaint);
-        }
-        canvas.restore();
-        // 顺时针到结尾处
-        canvas.save();
-        for (int i = 0; i < (mSection * mPortion) / 2; i++) {
-            canvas.rotate(degree, cx, cy);
-            canvas.drawLine(x0, y0, x2, y2, mLinePaint);
-        }
+        canvas.rotate(angle, cx, cy);
+        canvas.drawBitmap(triangleBitmap, triangleRect1, triangleShowRect, mPointerPaint);
         canvas.restore();
+//        canvas.save();
+
+
+        float x0 = cx;
+        float y0 = cx - (float) (mRadius * scaleRoundPercent);
+
+        //绘制短刻度
+        drawShortScale(canvas, x0, y0);
+
+        //绘制长刻度
+        drawLongScale(canvas, x0, y0);
+
 
         /**
          * 画长刻度读数
@@ -278,11 +412,83 @@ public class DashBoardView extends View {
         }
     }
 
+    private void drawShortScale(Canvas canvas, float x0, float y0) {
+        //        mLinePaint.setAlpha(90);
+        mLinePaint.setColor(getColor(R.color.color_d6dfe4));
+        float degree = mSweepAngle / (mSection * mPortion);
+
+        float x2 = cx;
+        float y2 = y0 + shortScaleLineHeight;
+        // 逆时针到开始处
+        canvas.save();
+        canvas.drawLine(x0, y0, x2, y2, mLinePaint);
+        for (int i = 0; i < (mSection * mPortion) / 2; i++) {
+            if (i < 10) {
+                mLinePaint.setColor(getColor(R.color.color_198cfe));
+            } else {
+                mLinePaint.setColor(getColor(R.color.color_d6dfe4));
+            }
+            canvas.rotate(-degree, cx, cy);
+            canvas.drawLine(x0, y0, x2, y2, mLinePaint);
+        }
+        canvas.restore();
+        // 顺时针到结尾处
+        canvas.save();
+        for (int i = 0; i < (mSection * mPortion) / 2; i++) {
+            if (i < 10) {
+                mLinePaint.setColor(getColor(R.color.color_198cfe));
+            } else {
+                mLinePaint.setColor(getColor(R.color.color_d6dfe4));
+            }
+            canvas.rotate(degree, cx, cy);
+            canvas.drawLine(x0, y0, x2, y2, mLinePaint);
+        }
+        canvas.restore();
+    }
+
+    private void drawLongScale(Canvas canvas, float x0, float y0) {
+        float degree = mSweepAngle / mSection;
+        float x1 = cx;
+        float y1 = y0 + longScaleLineHeight;
+        mLinePaint.setColor(getColor(R.color.color_198cfe));
+        // 逆时针到开始处
+        canvas.save();
+        canvas.drawLine(x0, y0, x1, y1, mLinePaint);
+        int max = mSection / 2;
+        for (int i = 0; i < max; i++) {
+            if (i == 0) {
+                mLinePaint.setColor(getColor(R.color.color_198cfe));
+            } else {
+                mLinePaint.setColor(getColor(com.cooleshow.base.R.color.color_999999));
+            }
+            canvas.rotate(-degree, cx, cy);
+            canvas.drawLine(x0, y0, x1, y1, mLinePaint);
+        }
+        mLinePaint.setColor(getColor(com.cooleshow.base.R.color.color_999999));
+        canvas.restore();
+        // 顺时针到结尾处
+        canvas.save();
+        for (int i = 0; i < mSection / 2; i++) {
+            if (i == 0) {
+                mLinePaint.setColor(getColor(R.color.color_198cfe));
+            } else {
+                mLinePaint.setColor(getColor(com.cooleshow.base.R.color.color_999999));
+            }
+            canvas.rotate(degree, cx, cy);
+            canvas.drawLine(x0, y0, x1, y1, mLinePaint);
+        }
+        canvas.restore();
+    }
+
+    private int getColor(int colorRes) {
+        return getResources().getColor(colorRes);
+    }
+
     private int maxMusicHzOffset = 50;
     private int minMusicHzOffset = -50;
 
     private float[] countPointerPosition(float diff) {
-        float[] points = new float[2];
+        float[] points = new float[3];
         if (diff > maxMusicHzOffset) {
             diff = maxMusicHzOffset;
         }
@@ -292,25 +498,49 @@ public class DashBoardView extends View {
 
         if (diff > 0) {
             double angle = (diff / maxMusicHzOffset) * mSweepAngle / 2;
-            Log.i("zxc", "angle:" + angle);
+            Log.i("zxc", "angle1:" + angle);
             float radian = (float) Math.toRadians(angle);
             points[0] = (float) (cx + Math.sin(radian) * pointerHeight);
             points[1] = (float) (cy - Math.cos(radian) * pointerHeight);
+            points[2] = (float) angle;
         } else if (diff == 0) {
+            Log.i("zxc", "angle1:" + 0);
             points[0] = cx;
             points[1] = (float) (cy - pointerHeight);
+            points[2] = 0;
         } else {
             double angle = Math.abs((diff / minMusicHzOffset) * mSweepAngle / 2);
-            Log.i("zxc", "angle:" + angle);
+            Log.i("zxc", "angle1:" + angle);
             float radian = (float) Math.toRadians(angle);
             points[0] = (float) (cx - Math.sin(radian) * pointerHeight);
             points[1] = (float) (cy - Math.cos(radian) * pointerHeight);
+            points[2] = (float) -angle;
         }
-        Log.i("zxc", "points[0]:" + points[0]);
-        Log.i("zxc", "points[1]:" + points[1]);
+//        Log.i("zxc", "points[0]:" + points[0]);
+//        Log.i("zxc", "points[1]:" + points[1]);
         return points;
     }
 
+
+    private double getAngle(float diff) {
+        if (diff > maxMusicHzOffset) {
+            diff = maxMusicHzOffset;
+        }
+        if (diff < minMusicHzOffset) {
+            diff = minMusicHzOffset;
+        }
+        double angle = 0;
+        if (diff > 0) {
+            angle = (diff / maxMusicHzOffset) * mSweepAngle / 2;
+        } else if (diff == 0) {
+            angle = 0;
+        } else {
+            angle = Math.abs((diff / minMusicHzOffset) * mSweepAngle / 2);
+        }
+        Log.i("zxc", "angle:" + angle);
+        return angle;
+    }
+
     public void setProgress(int progress) {
         if (progress != -100) {
 //            this.currentProgress = progress;
@@ -321,7 +551,7 @@ public class DashBoardView extends View {
             if (progress <= minMusicHzOffset) {
                 progress = minMusicHzOffset;
             }
-            lastAnimProgress=0;
+            lastAnimProgress = 0f;
             offsetValue = 0;
             currentOffsetValue = 0;
             startAnimation(progress - currentProgress);
@@ -347,8 +577,8 @@ public class DashBoardView extends View {
                     LOG.i("onAnimationUpdate:" + value + "--当前偏移总量:" + currentOffsetValue);
                     float d = currentOffsetValue * value;
                     LOG.i("d:" + d);
-                    offsetValue = (value-lastAnimProgress)*currentOffsetValue;
-                    lastAnimProgress =value;
+                    offsetValue = (value - lastAnimProgress) * currentOffsetValue;
+                    lastAnimProgress = value;
                     LOG.i("offsetValue:" + offsetValue);
                     invalidate();
                 }

+ 5 - 0
musictuner/src/main/java/com/cooleshow/musictuner/widget/MusicTunerSettingDialog.java

@@ -18,6 +18,7 @@ import com.cooleshow.musictuner.utils.VoiceDataUtils;
 
 import java.lang.reflect.Array;
 import java.util.ArrayList;
+import java.util.Locale;
 
 import androidx.annotation.NonNull;
 
@@ -47,6 +48,10 @@ public class MusicTunerSettingDialog extends Dialog implements View.OnClickListe
         findViewById(R.id.view_add_hz).setOnClickListener(this);
         findViewById(R.id.view_reduce_hz).setOnClickListener(this);
         findViewById(R.id.tv_reset).setOnClickListener(this);
+        TextView tv_reset = findViewById(R.id.tv_reset);
+        tv_reset.setText(String.format(Locale.getDefault(),"Reset:%dHz", VoiceDataUtils.DEFAULT_MUSIC_HZ_STANDARD_SELECT_HZ));
+        tv_reset.setOnClickListener(this);
+
         findViewById(R.id.view_transposing_bg).setOnClickListener(this);
         findViewById(R.id.tv_confirm).setOnClickListener(this);
         buildSample();

+ 8 - 1
musictuner/src/main/java/com/cooleshow/musictuner/widget/MusicTuningForkDialog.java

@@ -36,6 +36,7 @@ public class MusicTuningForkDialog extends Dialog implements View.OnClickListene
     private int currentMusicPos = VoiceDataUtils.DEFAULT_MUSIC_POS;
     private TextView mTvHzTip;
     private ImageView mIvHzTip;
+    private int defaultSelectPos = -1;
 
     public MusicTuningForkDialog(@NonNull Context context) {
         super(context, com.cooleshow.base.R.style.DialogStyle);
@@ -54,6 +55,7 @@ public class MusicTuningForkDialog extends Dialog implements View.OnClickListene
         findViewById(R.id.tv_confirm).setOnClickListener(this);
         mTvCurrentMusicPosition = findViewById(R.id.tv_current_music_position);
         mTuningForkAdapter = new MusicTuningForkAdapter();
+        mTuningForkAdapter.setCurrentSelectPos(defaultSelectPos);
         updateText();
         GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), 2);
         gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@@ -81,6 +83,7 @@ public class MusicTuningForkDialog extends Dialog implements View.OnClickListene
 
     private void buildList() {
         mList = new ArrayList<>();
+
         for (int i = 0; i < VoiceDataUtils.VOICE_OF_TONE.length; i++) {
             MusicTuningForkBean musicTuningForkBean = new MusicTuningForkBean();
             String s = VoiceDataUtils.VOICE_OF_TONE[i];
@@ -90,6 +93,10 @@ public class MusicTuningForkDialog extends Dialog implements View.OnClickListene
             } else {
                 musicTuningForkBean.setMatchParent(false);
             }
+
+            if (TextUtils.equals(s, VoiceDataUtils.VOICE_OF_TONE[9])) {
+                defaultSelectPos = i;
+            }
             mList.add(musicTuningForkBean);
         }
     }
@@ -156,7 +163,7 @@ public class MusicTuningForkDialog extends Dialog implements View.OnClickListene
     private void updateCurrentHzStandardText() {
         int currentMusicHzStandard = VoiceDataUtils.getInstance().getCurrentMusicHzStandard();
         if (mTvHzTip != null) {
-            mIvHzTip.setVisibility(currentMusicHzStandard == VoiceDataUtils.DEFAULT_MUSIC_HZ_STANDARD_440_HZ ? View.GONE : View.VISIBLE);
+            mIvHzTip.setVisibility(currentMusicHzStandard == VoiceDataUtils.DEFAULT_MUSIC_HZ_STANDARD_SELECT_HZ ? View.GONE : View.VISIBLE);
             mTvHzTip.setText(getContext().getString(R.string.music_hz_str, currentMusicHzStandard));
         }
     }

BIN
musictuner/src/main/res/drawable-xhdpi/bg_dash_board2.png


BIN
musictuner/src/main/res/drawable-xhdpi/bg_music_fork.png


BIN
musictuner/src/main/res/drawable-xhdpi/bg_music_tuner_bottom.png


BIN
musictuner/src/main/res/drawable-xhdpi/bg_music_tuner_main.png


BIN
musictuner/src/main/res/drawable-xhdpi/bg_tuner_music.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_arrow_top_bottom.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_bottom_hole.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_metronome_speed_bg.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_music_hole.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_music_hz_add.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_music_hz_reduce.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_music_menu_normal.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_music_menu_select.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_music_tuner_correct_tag.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_music_tuner_normal.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_music_tuner_select.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_music_tuner_setting.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_music_tuner_title.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_music_tuner_triangle_small.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_pause_metronome_bt.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_play_beat_speed_tag.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_play_metronome_bt.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_transposing_tag.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_triangle_arrow_blue.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_tuning_fork.png


BIN
musictuner/src/main/res/drawable-xhdpi/icon_tuning_fork_normal.png


BIN
musictuner/src/main/res/drawable-xhdpi/tm_icon_add_symbol.png


BIN
musictuner/src/main/res/drawable-xhdpi/tm_icon_reduce_symbol.png


BIN
musictuner/src/main/res/drawable-xxhdpi/bg_dash_board2.png


BIN
musictuner/src/main/res/drawable-xxhdpi/bg_music_fork.png


BIN
musictuner/src/main/res/drawable-xxhdpi/bg_music_tuner_bottom.png


BIN
musictuner/src/main/res/drawable-xxhdpi/bg_music_tuner_main.png


BIN
musictuner/src/main/res/drawable-xxhdpi/bg_tuner_music.png


BIN
musictuner/src/main/res/drawable-xxhdpi/icon_arrow_top_bottom.png


BIN
musictuner/src/main/res/drawable-xxhdpi/icon_bottom_hole.png


BIN
musictuner/src/main/res/drawable-xxhdpi/icon_metronome_speed_bg.png


BIN
musictuner/src/main/res/drawable-xxhdpi/icon_music_hole.png


BIN
musictuner/src/main/res/drawable-xxhdpi/icon_music_hz_add.png


BIN
musictuner/src/main/res/drawable-xxhdpi/icon_music_hz_reduce.png


BIN
musictuner/src/main/res/drawable-xxhdpi/icon_music_menu_normal.png


BIN
musictuner/src/main/res/drawable-xxhdpi/icon_music_menu_select.png


Some files were not shown because too many files changed in this diff