From ec4f9ee64129cbc5d5b25aa7f749edf9acd9ae52 Mon Sep 17 00:00:00 2001
From: xufulong <839789740@qq.com>
Date: Tue, 20 Oct 2020 01:08:39 +0800
Subject: [PATCH] Audio effect: equalizer and visualizer
Audio effect: equalizer and visualizer
---
app/build.gradle | 1 +
app/src/main/AndroidManifest.xml | 47 ++--
.../ffmpeg/activity/AudioEffectActivity.kt | 255 ++++++++++++++++++
.../frank/ffmpeg/activity/MainActivity.java | 6 +-
.../frank/ffmpeg/adapter/EqualizerAdapter.kt | 89 ++++++
.../frank/ffmpeg/format/AudioVisualizer.java | 35 +++
.../frank/ffmpeg/listener/OnSeeBarListener.kt | 5 +
.../com/frank/ffmpeg/view/VisualizerView.kt | 168 ++++++++++++
.../main/res/layout/activity_audio_effect.xml | 80 ++++++
app/src/main/res/layout/activity_main.xml | 7 +
app/src/main/res/layout/adapter_equalizer.xml | 18 ++
app/src/main/res/values-en/strings.xml | 6 +
app/src/main/res/values/strings.xml | 6 +
13 files changed, 697 insertions(+), 26 deletions(-)
create mode 100644 app/src/main/java/com/frank/ffmpeg/activity/AudioEffectActivity.kt
create mode 100644 app/src/main/java/com/frank/ffmpeg/adapter/EqualizerAdapter.kt
create mode 100644 app/src/main/java/com/frank/ffmpeg/format/AudioVisualizer.java
create mode 100644 app/src/main/java/com/frank/ffmpeg/listener/OnSeeBarListener.kt
create mode 100644 app/src/main/java/com/frank/ffmpeg/view/VisualizerView.kt
create mode 100644 app/src/main/res/layout/activity_audio_effect.xml
create mode 100644 app/src/main/res/layout/adapter_equalizer.xml
diff --git a/app/build.gradle b/app/build.gradle
index 0ac633a..72e4555 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -56,6 +56,7 @@ dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "androidx.appcompat:appcompat:$rootProject.appcompatVersion"
implementation "androidx.recyclerview:recyclerview:$rootProject.recyclerviewVersion"
+ implementation 'androidx.appcompat:appcompat:1.2.0'
testImplementation 'junit:junit:4.12'
implementation project(':Live')
implementation "androidx.core:core-ktx:$rootProject.core_ktx"
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 90fb5f2..ea88d15 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -8,57 +8,54 @@
-
+
+ android:theme="@style/AppTheme"
+ tools:replace="android:name">
-
+
-
+
+
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
+ android:screenOrientation="landscape" />
+
-
+ android:screenOrientation="portrait" />
-
-
+
+
-
-
diff --git a/app/src/main/java/com/frank/ffmpeg/activity/AudioEffectActivity.kt b/app/src/main/java/com/frank/ffmpeg/activity/AudioEffectActivity.kt
new file mode 100644
index 0000000..7e22894
--- /dev/null
+++ b/app/src/main/java/com/frank/ffmpeg/activity/AudioEffectActivity.kt
@@ -0,0 +1,255 @@
+package com.frank.ffmpeg.activity
+
+import android.Manifest
+import android.media.MediaPlayer
+import android.media.audiofx.*
+import android.os.Build
+import androidx.appcompat.app.AppCompatActivity
+import android.os.Bundle
+import android.os.Environment
+import android.util.Log
+import android.util.Pair
+import android.view.View
+import android.widget.*
+import androidx.annotation.RequiresApi
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.frank.ffmpeg.R
+import com.frank.ffmpeg.adapter.EqualizerAdapter
+import com.frank.ffmpeg.format.AudioVisualizer
+import com.frank.ffmpeg.listener.OnSeeBarListener
+import com.frank.ffmpeg.view.VisualizerView
+import java.io.IOException
+import java.util.ArrayList
+
+/**
+ * Audio effect: equalizer, enhancer, visualizer
+ * Created by frank on 2020/10/20.
+ */
+class AudioEffectActivity : AppCompatActivity(), OnSeeBarListener {
+
+ companion object {
+ private val TAG = AudioEffectActivity::class.java.simpleName
+
+ private val AUDIO_PATH = Environment.getExternalStorageDirectory().path + "/heart.mp3"
+ }
+
+ private var mPlayer: MediaPlayer? = null
+ private var mEqualizer: Equalizer? = null
+ private var mBass: BassBoost? = null
+ private var mPresetReverb: PresetReverb? = null
+ private val reverbValues = ArrayList()
+ private var seekBarList: List? = ArrayList()
+ private var bands: Short = 0
+ private var minEQLevel: Short = 0
+ private var spinnerStyle: Spinner? = null
+ private var spinnerReverb: Spinner? = null
+ private var barBassBoost: SeekBar? = null
+ private var equalizerAdapter: EqualizerAdapter? = null
+ private val enableEqualizer = true
+ private var loudnessEnhancer: LoudnessEnhancer? = null
+ private var barEnhancer: SeekBar? = null
+ private var visualizerView: VisualizerView? = null
+ private var mVisualizer: AudioVisualizer? = null
+
+ private val presetReverb = arrayOf("None", "SmallRoom", "MediumRoom", "LargeRoom",
+ "MediumHall", "LargeHall", "Plate")
+
+ private val permissions = arrayOf(
+ Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ Manifest.permission.RECORD_AUDIO,
+ Manifest.permission.MODIFY_AUDIO_SETTINGS)
+
+ private val onPreparedListener = MediaPlayer.OnPreparedListener {
+ setupEqualizer()
+ setupPresetStyle()
+ setupReverberation()
+ setupBassBoost()
+ setLoudnessEnhancer()
+ setupVisualizer()
+
+ mPlayer!!.start()
+ }
+
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ checkPermission()
+ setContentView(R.layout.activity_audio_effect)
+ initView()
+ initPlayer()
+ }
+
+ private fun initView() {
+ spinnerStyle = findViewById(R.id.spinner_style)
+ spinnerReverb = findViewById(R.id.spinner_reverb)
+ barBassBoost = findViewById(R.id.bar_bassboost)
+ barEnhancer = findViewById(R.id.bar_enhancer)
+ visualizerView = findViewById(R.id.visualizer_view)
+ val equalizerView = findViewById(R.id.equalizer_view)
+ val layoutManager = LinearLayoutManager(this)
+ layoutManager.orientation = RecyclerView.VERTICAL
+ equalizerView.layoutManager = layoutManager
+ equalizerAdapter = EqualizerAdapter(this, this)
+ equalizerView.adapter = equalizerAdapter
+ }
+
+ private fun checkPermission() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ requestPermissions(permissions, 456)
+ }
+ }
+
+ private fun initPlayer() {
+ try {
+ mPlayer = MediaPlayer()
+ mPlayer!!.setDataSource(AUDIO_PATH)
+ mPlayer!!.setOnPreparedListener(onPreparedListener)
+ mPlayer!!.prepareAsync()
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+
+ override fun onProgress(index: Int, progress: Int) {
+ mEqualizer!!.setBandLevel(index.toShort(), (progress + minEQLevel).toShort())
+ }
+
+ private fun setupEqualizer() {
+ val equalizerList = ArrayList>()
+ mEqualizer = Equalizer(0, mPlayer!!.audioSessionId)
+ mEqualizer!!.enabled = enableEqualizer
+ // band level: min and max
+ minEQLevel = mEqualizer!!.bandLevelRange[0]//min level
+ val maxEQLevel = mEqualizer!!.bandLevelRange[1] // max level
+ bands = mEqualizer!!.numberOfBands
+ for (i in 0 until bands) {
+ val centerFreq = (mEqualizer!!.getCenterFreq(i.toShort()) / 1000).toString() + " Hz"
+ val pair = Pair.create(centerFreq, mEqualizer!!.getBandLevel(i.toShort()) - minEQLevel)
+ equalizerList.add(pair)
+ }
+ if (equalizerAdapter != null) {
+ equalizerAdapter!!.setMaxProgress(maxEQLevel - minEQLevel)
+ equalizerAdapter!!.setEqualizerList(equalizerList)
+ }
+ }
+
+ private fun setupPresetStyle() {
+ for (i in 0 until mEqualizer!!.numberOfPresets) {
+ reverbValues.add(mEqualizer!!.getPresetName(i.toShort()))
+ }
+
+ spinnerStyle!!.adapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, reverbValues)
+ spinnerStyle!!.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
+ override fun onItemSelected(arg0: AdapterView<*>, arg1: View, arg2: Int, arg3: Long) {
+ try {
+ mEqualizer!!.usePreset(arg2.toShort())
+ if (equalizerAdapter != null) {
+ seekBarList = equalizerAdapter!!.getSeekBarList()
+ }
+ if (bands > 0 && seekBarList != null && mEqualizer != null) {
+ for (band in 0 until bands) {
+ seekBarList!![band].progress = mEqualizer!!.getBandLevel(band.toShort()) - minEQLevel
+ }
+ }
+
+ } catch (e: Exception) {
+ Log.e(TAG, "preset style error=$e")
+ }
+
+ }
+ override fun onNothingSelected(arg0: AdapterView<*>) {}
+ }
+ }
+
+ private fun setupReverberation() {
+ mPresetReverb = PresetReverb(0, mPlayer!!.audioSessionId)
+ mPresetReverb!!.enabled = enableEqualizer
+ mPlayer!!.attachAuxEffect(mPresetReverb!!.id)
+ //sendLevel:0-1
+ mPlayer!!.setAuxEffectSendLevel(1.0f)
+
+ spinnerReverb!!.adapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, presetReverb)
+ spinnerReverb!!.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
+ override fun onItemSelected(arg0: AdapterView<*>, arg1: View, arg2: Int, arg3: Long) {
+ try {
+ mPresetReverb!!.preset = arg2.toShort()
+ } catch (e: Exception) {
+ Log.e(TAG, "preset reverberation error=$e")
+ }
+ }
+ override fun onNothingSelected(arg0: AdapterView<*>) {}
+ }
+ }
+
+ private fun setupBassBoost() {
+ mBass = BassBoost(0, mPlayer!!.audioSessionId)
+ mBass!!.enabled = enableEqualizer
+ // 0--1000
+ barBassBoost!!.max = 1000
+ barBassBoost!!.progress = 0
+ barBassBoost!!.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
+ override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
+ // set the strength of bass boost
+ mBass!!.setStrength(progress.toShort())
+ }
+
+ override fun onStartTrackingTouch(seekBar: SeekBar) {}
+
+ override fun onStopTrackingTouch(seekBar: SeekBar) {}
+ })
+ }
+
+ @RequiresApi(Build.VERSION_CODES.KITKAT)
+ private fun setLoudnessEnhancer() {
+ loudnessEnhancer = LoudnessEnhancer(mPlayer!!.audioSessionId)
+ loudnessEnhancer!!.enabled = true
+ // Unit: mB
+ loudnessEnhancer!!.setTargetGain(500)
+ barEnhancer!!.max = 1000
+ barEnhancer!!.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
+ override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
+ if (fromUser) {
+ loudnessEnhancer!!.setTargetGain(progress)
+ }
+ }
+
+ override fun onStartTrackingTouch(seekBar: SeekBar?) {
+ }
+
+ override fun onStopTrackingTouch(seekBar: SeekBar?) {
+ }
+ })
+ }
+
+
+ private fun setupVisualizer() {
+ mVisualizer = AudioVisualizer()
+ mVisualizer?.initVisualizer(mPlayer!!.audioSessionId, false, true, object: Visualizer.OnDataCaptureListener{
+ override fun onFftDataCapture(visualizer: Visualizer?, fft: ByteArray?, samplingRate: Int) {
+ if (visualizerView != null && fft != null) {
+ visualizerView!!.post { visualizerView!!.setWaveData(fft) }
+ }
+ }
+
+ override fun onWaveFormDataCapture(visualizer: Visualizer?, waveform: ByteArray?, samplingRate: Int) {
+ }
+ })
+ }
+
+ private fun releaseVisualizer() {
+ mVisualizer?.releaseVisualizer()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+
+ mEqualizer!!.release()
+ mPresetReverb!!.release()
+ mBass!!.release()
+ loudnessEnhancer!!.release()
+ releaseVisualizer()
+ mPlayer!!.release()
+ }
+
+}
diff --git a/app/src/main/java/com/frank/ffmpeg/activity/MainActivity.java b/app/src/main/java/com/frank/ffmpeg/activity/MainActivity.java
index 96a7b60..5727248 100644
--- a/app/src/main/java/com/frank/ffmpeg/activity/MainActivity.java
+++ b/app/src/main/java/com/frank/ffmpeg/activity/MainActivity.java
@@ -30,7 +30,8 @@ public class MainActivity extends BaseActivity {
R.id.btn_live,
R.id.btn_filter,
R.id.btn_preview,
- R.id.btn_probe
+ R.id.btn_probe,
+ R.id.btn_audio_effect
);
}
@@ -65,6 +66,9 @@ public class MainActivity extends BaseActivity {
case R.id.btn_probe://probe media format
intent.setClass(MainActivity.this, ProbeFormatActivity.class);
break;
+ case R.id.btn_audio_effect://audio effect
+ intent.setClass(MainActivity.this, AudioEffectActivity.class);
+ break;
default:
break;
}
diff --git a/app/src/main/java/com/frank/ffmpeg/adapter/EqualizerAdapter.kt b/app/src/main/java/com/frank/ffmpeg/adapter/EqualizerAdapter.kt
new file mode 100644
index 0000000..48ee247
--- /dev/null
+++ b/app/src/main/java/com/frank/ffmpeg/adapter/EqualizerAdapter.kt
@@ -0,0 +1,89 @@
+package com.frank.ffmpeg.adapter
+
+import android.content.Context
+import android.util.Pair
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.SeekBar
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+
+import com.frank.ffmpeg.R
+import com.frank.ffmpeg.listener.OnSeeBarListener
+
+import java.util.ArrayList
+
+/**
+ * @author frank
+ * @date 2020-10-19 0:19
+ * @desc Adapter of equalizer
+ */
+
+class EqualizerAdapter(private val context: Context, private val onSeeBarListener: OnSeeBarListener?) : RecyclerView.Adapter() {
+
+ private var equalizerList: List>? = ArrayList()
+ private val seekBarList = ArrayList()
+ private var maxProgress: Int = 0
+
+ override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): RecyclerView.ViewHolder {
+ return EqualizerHolder(LayoutInflater.from(context).inflate(R.layout.adapter_equalizer, null))
+ }
+
+ override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, i: Int) {
+ val holder = viewHolder as EqualizerHolder
+ if (equalizerList != null) {
+ val centerFreq = equalizerList!![i].first as String
+ holder.txtFrequency.text = centerFreq
+ }
+ seekBarList.add(holder.barEqualizer)
+ holder.barEqualizer.max = maxProgress
+ val currentProgress = equalizerList!![i].second as Int
+ holder.barEqualizer.progress = currentProgress
+
+ holder.barEqualizer.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
+ override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
+ if (fromUser) {
+ onSeeBarListener?.onProgress(i, progress)
+ }
+ }
+
+ override fun onStartTrackingTouch(seekBar: SeekBar) {
+
+ }
+
+ override fun onStopTrackingTouch(seekBar: SeekBar) {
+
+ }
+ })
+ }
+
+ override fun getItemCount(): Int {
+ return if (equalizerList != null) equalizerList!!.size else 0
+ }
+
+ private inner class EqualizerHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView) {
+
+ val txtFrequency: TextView = itemView.findViewById(R.id.txt_frequency)
+ val barEqualizer: SeekBar = itemView.findViewById(R.id.bar_equalizer)
+
+ }
+
+ fun setMaxProgress(maxProgress: Int) {
+ if (maxProgress > 0) {
+ this.maxProgress = maxProgress
+ }
+ }
+
+ fun setEqualizerList(equalizerList: List>?) {
+ if (equalizerList != null) {
+ this.equalizerList = equalizerList
+ notifyDataSetChanged()
+ }
+ }
+
+ fun getSeekBarList(): List {
+ return seekBarList
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/frank/ffmpeg/format/AudioVisualizer.java b/app/src/main/java/com/frank/ffmpeg/format/AudioVisualizer.java
new file mode 100644
index 0000000..7e40bdc
--- /dev/null
+++ b/app/src/main/java/com/frank/ffmpeg/format/AudioVisualizer.java
@@ -0,0 +1,35 @@
+package com.frank.ffmpeg.format;
+
+import android.media.audiofx.Visualizer;
+import android.os.Build;
+
+/**
+ * Visualizer of Audio frequency
+ * Created by frank on 2020/10/20.
+ */
+public class AudioVisualizer {
+
+ private Visualizer visualizer;
+
+ public void initVisualizer(int audioSession, boolean waveform, boolean fft, Visualizer.OnDataCaptureListener dataCaptureListener) {
+ visualizer = new Visualizer(audioSession);
+ int captureSize = Visualizer.getCaptureSizeRange()[1];
+ int captureRate = Visualizer.getMaxCaptureRate() / 2;
+
+ visualizer.setCaptureSize(captureSize);
+ visualizer.setDataCaptureListener(dataCaptureListener, captureRate, waveform, fft);
+ visualizer.setScalingMode(Visualizer.SCALING_MODE_NORMALIZED);
+ visualizer.setEnabled(true);
+ }
+
+ public void releaseVisualizer() {
+ if (visualizer != null) {
+ int captureRate = Visualizer.getMaxCaptureRate() / 2;
+ visualizer.setEnabled(false);
+ visualizer.setDataCaptureListener(null, captureRate, false, false);
+ visualizer.release();
+ visualizer = null;
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/frank/ffmpeg/listener/OnSeeBarListener.kt b/app/src/main/java/com/frank/ffmpeg/listener/OnSeeBarListener.kt
new file mode 100644
index 0000000..73fa736
--- /dev/null
+++ b/app/src/main/java/com/frank/ffmpeg/listener/OnSeeBarListener.kt
@@ -0,0 +1,5 @@
+package com.frank.ffmpeg.listener
+
+interface OnSeeBarListener {
+ fun onProgress(index: Int, progress: Int)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/frank/ffmpeg/view/VisualizerView.kt b/app/src/main/java/com/frank/ffmpeg/view/VisualizerView.kt
new file mode 100644
index 0000000..73f76a0
--- /dev/null
+++ b/app/src/main/java/com/frank/ffmpeg/view/VisualizerView.kt
@@ -0,0 +1,168 @@
+package com.frank.ffmpeg.view
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Path
+import android.graphics.Point
+import android.util.AttributeSet
+import android.view.View
+
+import java.util.ArrayList
+
+/**
+ * the custom view of audio visualizer
+ * Created by frank on 2020/10/19.
+ */
+class VisualizerView : View {
+
+ private var upShowStyle = ShowStyle.STYLE_HOLLOW_LUMP
+
+ private var waveData: ByteArray? = null
+ private var pointList: MutableList? = null
+
+ private var lumpPaint: Paint? = null
+ private var wavePath = Path()
+
+
+ constructor(context: Context) : super(context) {
+ init()
+ }
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
+ init()
+ }
+
+ constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
+ init()
+ }
+
+ private fun init() {
+ lumpPaint = Paint()
+ lumpPaint!!.isAntiAlias = true
+ lumpPaint!!.color = LUMP_COLOR
+
+ lumpPaint!!.strokeWidth = 2f
+ lumpPaint!!.style = Paint.Style.STROKE
+ }
+
+ fun setWaveData(data: ByteArray) {
+ this.waveData = readyData(data)
+ genSamplingPoint(data)
+ invalidate()
+ }
+
+
+ fun setStyle(upShowStyle: ShowStyle) {
+ this.upShowStyle = upShowStyle
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ wavePath.reset()
+
+ for (i in 0 until LUMP_COUNT) {
+ if (waveData == null) {
+ canvas.drawRect(((LUMP_WIDTH + LUMP_SPACE) * i).toFloat(),
+ (LUMP_MAX_HEIGHT - LUMP_MIN_HEIGHT).toFloat(),
+ ((LUMP_WIDTH + LUMP_SPACE) * i + LUMP_WIDTH).toFloat(),
+ LUMP_MAX_HEIGHT.toFloat(),
+ lumpPaint!!)
+ continue
+ }
+
+ when (upShowStyle) {
+ ShowStyle.STYLE_HOLLOW_LUMP -> drawLump(canvas, i, false)
+ ShowStyle.STYLE_WAVE -> drawWave(canvas, i, false)
+ else -> {
+ }
+ }
+ }
+ }
+
+ private fun drawWave(canvas: Canvas, i: Int, reversal: Boolean) {
+ if (pointList == null || pointList!!.size < 2) {
+ return
+ }
+ val ratio = SCALE * if (reversal) -1 else 1
+ if (i < pointList!!.size - 2) {
+ val point = pointList!![i]
+ val nextPoint = pointList!![i + 1]
+ val midX = point.x + nextPoint.x shr 1
+ if (i == 0) {
+ wavePath.moveTo(point.x.toFloat(), LUMP_MAX_HEIGHT - point.y * ratio)
+ }
+ wavePath.cubicTo(midX.toFloat(), LUMP_MAX_HEIGHT - point.y * ratio,
+ midX.toFloat(), LUMP_MAX_HEIGHT - nextPoint.y * ratio,
+ nextPoint.x.toFloat(), LUMP_MAX_HEIGHT - nextPoint.y * ratio)
+
+ canvas.drawPath(wavePath, lumpPaint!!)
+ }
+ }
+
+ private fun drawLump(canvas: Canvas, i: Int, reversal: Boolean) {
+ val minus = if (reversal) -1 else 1
+ val top = LUMP_MAX_HEIGHT - (LUMP_MIN_HEIGHT + waveData!![i] * SCALE) * minus
+
+ canvas.drawRect((LUMP_SIZE * i).toFloat(),
+ top,
+ (LUMP_SIZE * i + LUMP_WIDTH).toFloat(),
+ LUMP_MAX_HEIGHT.toFloat(),
+ lumpPaint!!)
+ }
+
+ /**
+ * generate the waveform of sampling points
+ *
+ * @param data data
+ */
+ private fun genSamplingPoint(data: ByteArray) {
+ if (upShowStyle != ShowStyle.STYLE_WAVE) {
+ return
+ }
+ if (pointList == null) {
+ pointList = ArrayList()
+ } else {
+ pointList!!.clear()
+ }
+ pointList!!.add(Point(0, 0))
+ var i = WAVE_SAMPLING_INTERVAL
+ while (i < LUMP_COUNT) {
+ pointList!!.add(Point(LUMP_SIZE * i, waveData!![i].toInt()))
+ i += WAVE_SAMPLING_INTERVAL
+ }
+ pointList!!.add(Point(LUMP_SIZE * LUMP_COUNT, 0))
+ }
+
+ enum class ShowStyle {
+ STYLE_HOLLOW_LUMP,
+ STYLE_WAVE,
+ STYLE_NOTHING
+ }
+
+ companion object {
+
+ private const val LUMP_COUNT = 128
+ private const val LUMP_WIDTH = 6
+ private const val LUMP_SPACE = 2
+ private const val LUMP_MIN_HEIGHT = LUMP_WIDTH
+ private const val LUMP_MAX_HEIGHT = 200
+ private const val LUMP_SIZE = LUMP_WIDTH + LUMP_SPACE
+ private val LUMP_COLOR = Color.parseColor("#6de6f6")
+
+ private const val WAVE_SAMPLING_INTERVAL = 3
+
+ private const val SCALE = (LUMP_MAX_HEIGHT / LUMP_COUNT).toFloat()
+
+ private fun readyData(fft: ByteArray): ByteArray {
+ val newData = ByteArray(LUMP_COUNT)
+ var abs: Byte
+ for (i in 0 until LUMP_COUNT) {
+ abs = kotlin.math.abs(fft[i].toInt()).toByte()
+ newData[i] = if (abs < 0) 127 else abs
+ }
+ return newData
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_audio_effect.xml b/app/src/main/res/layout/activity_audio_effect.xml
new file mode 100644
index 0000000..9bff88a
--- /dev/null
+++ b/app/src/main/res/layout/activity_audio_effect.xml
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index bf0852d..62d0698 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -76,6 +76,13 @@
android:text="@string/media_probe"
android:layout_marginTop="10dp" />
+
+
diff --git a/app/src/main/res/layout/adapter_equalizer.xml b/app/src/main/res/layout/adapter_equalizer.xml
new file mode 100644
index 0000000..05c478f
--- /dev/null
+++ b/app/src/main/res/layout/adapter_equalizer.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml
index cb7fdab..491783f 100644
--- a/app/src/main/res/values-en/strings.xml
+++ b/app/src/main/res/values-en/strings.xml
@@ -9,6 +9,12 @@
Audio encode
PCM concat
Audio speed
+ Audio effect
+ Audio equalizer:
+ Audio style:
+ Audio reverb:
+ Bass boost:
+ Voice enhancer:
Audio handle
Media handle
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 6d3492a..714ed88 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -9,6 +9,12 @@
音频编码
PCM合并
音频速度
+ 音乐均衡器
+ 均衡器:
+ 风格:
+ 混响:
+ 重低音:
+ 声音增强:
音频处理
音视频处理