Normalization and smooth functions moved to the extension file.

This commit is contained in:
Anton Chekulaev 2020-10-08 17:26:10 +11:00
parent 6df3264692
commit 8cbb34f174
4 changed files with 21 additions and 48 deletions

View File

@ -1,19 +1,3 @@
/*
* Copyright (C) 2015 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thoughtcrime.securesms.loki.utilities.audio; package org.thoughtcrime.securesms.loki.utilities.audio;
import android.media.AudioFormat; import android.media.AudioFormat;

View File

@ -17,13 +17,13 @@ import kotlin.math.sqrt
* If number of samples per channel is less than "maxFrames", * If number of samples per channel is less than "maxFrames",
* the result array will match the source sample size instead. * the result array will match the source sample size instead.
* *
* @return Normalized RMS values float array. * @return RMS values float array where is each value is within [0..1] range.
*/ */
fun DecodedAudio.calculateRms(maxFrames: Int): FloatArray { fun DecodedAudio.calculateRms(maxFrames: Int): FloatArray {
return calculateRms(this.samples, this.numSamples, this.channels, maxFrames) return calculateRms(this.samples, this.numSamples, this.channels, maxFrames)
} }
private fun calculateRms(samples: ShortBuffer, numSamples: Int, channels: Int, maxFrames: Int): FloatArray { fun calculateRms(samples: ShortBuffer, numSamples: Int, channels: Int, maxFrames: Int): FloatArray {
val numFrames: Int val numFrames: Int
val frameStep: Float val frameStep: Float
@ -65,6 +65,7 @@ private fun calculateRms(samples: ShortBuffer, numSamples: Int, channels: Int, m
calculateFrameRms(-1) calculateFrameRms(-1)
normalizeArray(rmsValues) normalizeArray(rmsValues)
// smoothArray(rmsValues, 1.0f)
return rmsValues return rmsValues
} }
@ -72,7 +73,7 @@ private fun calculateRms(samples: ShortBuffer, numSamples: Int, channels: Int, m
/** /**
* Normalizes the array's values to [0..1] range. * Normalizes the array's values to [0..1] range.
*/ */
private fun normalizeArray(values: FloatArray) { fun normalizeArray(values: FloatArray) {
var maxValue = -Float.MAX_VALUE var maxValue = -Float.MAX_VALUE
var minValue = +Float.MAX_VALUE var minValue = +Float.MAX_VALUE
values.forEach { value -> values.forEach { value ->
@ -87,4 +88,17 @@ private fun normalizeArray(values: FloatArray) {
} }
values.indices.forEach { i -> values[i] = (values[i] - minValue) / span } values.indices.forEach { i -> values[i] = (values[i] - minValue) / span }
}
fun smoothArray(values: FloatArray, neighborWeight: Float = 1f): FloatArray {
if (values.size < 3) return values
val result = FloatArray(values.size)
result[0] = values[0]
result[values.size - 1] == values[values.size - 1]
for (i in 1 until values.size - 1) {
result[i] = (values[i] + values[i - 1] * neighborWeight +
values[i + 1] * neighborWeight) / (1f + neighborWeight * 2f)
}
return result
} }

View File

@ -276,7 +276,7 @@ class MessageAudioView: FrameLayout, AudioSlidePlayer.Listener {
// Parse audio and compute RMS values for the WaveformSeekBar in the background. // Parse audio and compute RMS values for the WaveformSeekBar in the background.
asyncCoroutineScope!!.launch { asyncCoroutineScope!!.launch {
val rmsFrames = 32 // The amount of values to be computed to supply for the visualization. val rmsFrames = 32 // The amount of values to be computed for the visualization.
fun extractAttachmentRandomSeed(attachment: Attachment): Int { fun extractAttachmentRandomSeed(attachment: Attachment): Int {
return when { return when {
@ -310,6 +310,8 @@ class MessageAudioView: FrameLayout, AudioSlidePlayer.Listener {
} }
} }
android.util.Log.d(TAG, "RMS: ${rmsValues.joinToString()}")
post { post {
seekBar.sample = rmsValues seekBar.sample = rmsValues

View File

@ -24,32 +24,15 @@ class WaveformSeekBar : View {
context.resources.displayMetrics context.resources.displayMetrics
) )
} }
@JvmStatic
inline fun smooth(values: FloatArray, neighborWeight: Float = 1f): FloatArray {
if (values.size < 3) return values
val result = FloatArray(values.size)
result[0] = values[0]
result[values.size - 1] == values[values.size - 1]
for (i in 1 until values.size - 1) {
result[i] =
(values[i] + values[i - 1] * neighborWeight + values[i + 1] * neighborWeight) / (1f + neighborWeight * 2f)
}
return result
}
} }
var sample: FloatArray = floatArrayOf(0f) var sample: FloatArray = floatArrayOf(0f)
set(value) { set(value) {
if (value.isEmpty()) throw IllegalArgumentException("Sample array cannot be empty") if (value.isEmpty()) throw IllegalArgumentException("Sample array cannot be empty")
// field = smooth(value, 0.25f)
field = value field = value
invalidate() invalidate()
} }
/** Indicates whether the user is currently interacting with the view and performing a seeking gesture. */ /** Indicates whether the user is currently interacting with the view and performing a seeking gesture. */
private var userSeeking = false private var userSeeking = false
private var _progress: Float = 0f private var _progress: Float = 0f
@ -124,11 +107,6 @@ class WaveformSeekBar : View {
private var canvasWidth = 0 private var canvasWidth = 0
private var canvasHeight = 0 private var canvasHeight = 0
private var maxValue =
dp(
context,
2f
)
private var touchDownX = 0f private var touchDownX = 0f
private var scaledTouchSlop = ViewConfiguration.get(context).scaledTouchSlop private var scaledTouchSlop = ViewConfiguration.get(context).scaledTouchSlop
@ -177,7 +155,6 @@ class WaveformSeekBar : View {
val totalWidth = getAvailableWith() val totalWidth = getAvailableWith()
maxValue = sample.max()!!
val step = (totalWidth / (waveGap + waveWidth)) / sample.size val step = (totalWidth / (waveGap + waveWidth)) / sample.size
var lastWaveRight = paddingLeft.toFloat() var lastWaveRight = paddingLeft.toFloat()
@ -185,11 +162,7 @@ class WaveformSeekBar : View {
var i = 0f var i = 0f
while (i < sample.size) { while (i < sample.size) {
var waveHeight = if (maxValue != 0f) { var waveHeight = getAvailableHeight() * sample[i.toInt()]
getAvailableHeight() * (sample[i.toInt()] / maxValue)
} else {
waveMinHeight
}
if (waveHeight < waveMinHeight) { if (waveHeight < waveMinHeight) {
waveHeight = waveMinHeight waveHeight = waveMinHeight