【问题标题】:How to create sinwave animation while Recording/Playing audio in Android app ?如何在 Android 应用程序中录制/播放音频时创建正弦波动画?
【发布时间】:2015-10-16 05:08:01
【问题描述】:

在 iOS 应用程序中很容易创建。任何人都告诉我在录制和播放音频的同时创建 Sinwave 动画的简单方法。我尝试了很多方法,但我做不到。是否有任何第三方框架?

谁能帮帮我..

【问题讨论】:

    标签: java android avaudioplayer record sine-wave


    【解决方案1】:

    使用下面的代码来获取类似ios的波形...从录音机中获取幅度并传递给updateAmplitude()函数以获取语音的变化。

    public class WaveFormView extends View {
    
          private static final float defaultFrequency          = 1.5f;
          private static final float defaultAmplitude          = 1.0f;
          private static final float defaultIdleAmplitude      = 0.01f;
          private static final float defaultNumberOfWaves      = 5.0f;
          private static final float defaultPhaseShift         = -0.15f;
          private static final float defaultDensity            = 5.0f;
          private static final float defaultPrimaryLineWidth   = 3.0f;
          private static final float defaultSecondaryLineWidth = 1.0f;
    
          private float phase;
          private float amplitude;
          private float frequency;
          private float idleAmplitude;
          private float numberOfWaves;
          private float phaseShift;
          private float density;
          private float primaryWaveLineWidth;
          private float secondaryWaveLineWidth;
          Paint mPaintColor;
          Rect rect;
          boolean isStraightLine = false;
    
          public WaveFormView(Context context) {
              super(context);
              setUp();
          }
    
          public WaveFormView(Context context, AttributeSet attrs) {
              super(context, attrs);
              setUp();
          }
    
          public WaveFormView(Context context, AttributeSet attrs, int defStyleAttr) {
              super(context, attrs, defStyleAttr);
              setUp();
          }
    
          @TargetApi(Build.VERSION_CODES.LOLLIPOP)
          public WaveFormView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
              super(context, attrs, defStyleAttr, defStyleRes);
              setUp();
          }
    
          private void setUp() {
              this.frequency = defaultFrequency;
    
              this.amplitude = defaultAmplitude;
              this.idleAmplitude = defaultIdleAmplitude;
    
              this.numberOfWaves = defaultNumberOfWaves;
              this.phaseShift = defaultPhaseShift;
              this.density = defaultDensity;
    
              this.primaryWaveLineWidth = defaultPrimaryLineWidth;
              this.secondaryWaveLineWidth = defaultSecondaryLineWidth;
              mPaintColor = new Paint();
              mPaintColor.setColor(Color.WHITE);
          }
    
          public void updateAmplitude(float ampli, boolean isSpeaking) {
              this.amplitude = Math.max(ampli, idleAmplitude);
              isStraightLine = isSpeaking;
          }
    
    
          @Override
          protected void onDraw(Canvas canvas) {
              rect = new Rect(0,0,canvas.getWidth(),canvas.getWidth());
              canvas.drawColor(Color.BLUE);
              /*canvas.drawRect(rect, mPaintColor);*/
              if(isStraightLine) {
                  for (int i = 0; i < numberOfWaves; i++) {
                      mPaintColor.setStrokeWidth(i == 0 ? primaryWaveLineWidth : secondaryWaveLineWidth);
                      float halfHeight = canvas.getHeight() / 2;
                      float width = canvas.getWidth();
                      float mid = canvas.getWidth() / 2;
    
                      float maxAmplitude = halfHeight - 4.0f;
                      float progress = 1.0f - (float) i / this.numberOfWaves;
                      float normedAmplitude = (1.5f * progress - 0.5f) * this.amplitude;
                      Path path = new Path();
    
                      float multiplier = Math.min(1.0f, (progress / 3.0f * 2.0f) + (1.0f / 3.0f));
    
                      for (float x = 0; x < width + density; x += density) {
                          // We use a parable to scale the sinus wave, that has its peak in the middle of the view.
                          float scaling = (float) (-Math.pow(1 / mid * (x - mid), 2) + 1);
    
                          float y = (float) (scaling * maxAmplitude * normedAmplitude * Math.sin(2 * Math.PI * (x / width) * frequency + phase) + halfHeight);
    
                          if (x == 0) {
                              path.moveTo(x, y);
                          } else {
                              path.lineTo(x, y);
                          }
                      }
                      mPaintColor.setStyle(Paint.Style.STROKE);
                      mPaintColor.setAntiAlias(true);
                      canvas.drawPath(path, mPaintColor);
    
                  }
              } else {
                  canvas.drawLine(5,canvas.getHeight()/2,canvas.getWidth(),canvas.getHeight()/2,mPaintColor );
                  canvas.drawLine(0,canvas.getHeight()/2,canvas.getWidth(),canvas.getHeight()/2,mPaintColor);
                  canvas.drawLine(-5, canvas.getHeight() / 2, canvas.getWidth(), canvas.getHeight()/2,mPaintColor );
              }
              this.phase += phaseShift;
              invalidate();
          }
    }
    

    【讨论】:

    • 感谢 Sumathi 的建议。希望对我们有所帮助。
    • 浪花窗外是任何修正这个观点。提前致谢
    • 哇,谢谢文尼拉。棒极了 !为什么这不被接受为答案?如果可以的话,我想再来一次:)
    【解决方案2】:

    基于@Vennila 的回答。

    这是WaveFormView 的 Kotlin 版本。

    class SiriVisualView(context: Context, attrs: AttributeSet) : View(context, attrs) {
    
        private var phase = 0f
        private var amplitude = 1.5f // wave height
        private var frequency = 1.2f // number of waves
        private var idleAmplitude = 0.05f // default height
        private var numberOfWaves = 8.0f // number of wave lines
        private var phaseShift = -0.1f // wave speed
        private var primaryWaveLineWidth = 2.0f // outer line stroke
        private var secondaryWaveLineWidth = 0.5f // inner line stroke
        private var density = 5f
        var mPaintColor: Paint = Paint()
        var isStraightLine = false
    
        fun updateViewColor(@ColorInt color: Int) {
            mPaintColor.color = color
        }
    
        fun updateSpeaking(isSpeaking: Boolean) {
            isStraightLine = isSpeaking
        }
    
        fun updateAmplitude(ampli: Float) {
            amplitude = Math.max(ampli, idleAmplitude)
        }
    
        fun updateSpeed(phase: Float) {
            phaseShift = phase
        }
    
        /** Here you can override default wave values and customize SiriVisualView
    
            updateNumberOfWaves()
            updatePrimaryLineStroke()
                . . .
        */
    
        override fun onDraw(canvas: Canvas) {
            if (isStraightLine) {
                var i = 0
                while (i < numberOfWaves) {
                    mPaintColor.strokeWidth = if (i == 0) primaryWaveLineWidth else secondaryWaveLineWidth
                    val halfHeight = height / 2.toFloat()
                    val width = width.toFloat()
                    val mid = width / 2.toFloat()
                    val maxAmplitude = halfHeight - 4.0f
                    val progress = 1.0f - i.toFloat() / numberOfWaves
                    val normedAmplitude = (1.5f * progress - 0.5f) * amplitude
                    val path = Path()
                    val multiplier = Math.min(1.0f, progress / 3.0f * 2.0f + 1.0f / 3.0f)
                    var x = 0f
                    while (x < width + density) {
                        // We use a parable to scale the sinus wave, that has its peak in the middle of the view.
                        val scaling = (-Math.pow(
                            1 / mid * (x - mid).toDouble(),
                            2.0
                        ) + 1).toFloat()
                        val y = (scaling * maxAmplitude * normedAmplitude * Math.sin(2 * Math.PI * (x / width) * frequency + phase) + halfHeight).toFloat()
                        if (x == 0f) {
                            path.moveTo(x, y)
                        } else {
                            path.lineTo(x, y)
                        }
                        x += density
                    }
                    mPaintColor.style = Paint.Style.STROKE
                    mPaintColor.isAntiAlias = true
                    canvas.drawPath(path, mPaintColor)
                    i++
                }
            } else {
                for(i in 5 downTo -5 step 5) {
                    canvas.drawLine(
                        i.toFloat(),
                        height / 2.toFloat(),
                        width.toFloat(),
                        height / 2.toFloat(),
                        mPaintColor
                    )
                }
            }
            phase += phaseShift
            invalidate()
        }
    }
    

    向您的 XML 文件添加视图

    <linc.com.visualtest.SiriVisualView
        android:id="@+id/siriView"
        android:layout_width="0dp"
        android:layout_height="200dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>
    

    更新和自定义 Activity 或 Fragment 中的视图

    siriView.apply {
            updateSpeaking(true)
            updateViewColor(Color.WHITE)
            updateAmplitude(0.5f)
            updateSpeed(-0.1f)
        }
    

    这里有一些 SiriVisualView 的截图

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-25
      • 1970-01-01
      • 1970-01-01
      • 2011-09-10
      • 2014-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多