Convert mx waveform to floats as early as possible in the chain (#1652)
This way we're sure that internally we always deal with [0;1] float samples. the [0;1024] int range is used only at the rust sdk boundary.
This commit is contained in:
parent
00d24ce4b1
commit
0457e5915c
21 changed files with 88 additions and 93 deletions
|
|
@ -44,7 +44,6 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
|||
import io.element.android.features.messages.impl.voicemessages.timeline.VoiceMessageEvents
|
||||
import io.element.android.features.messages.impl.voicemessages.timeline.VoiceMessageState
|
||||
import io.element.android.features.messages.impl.voicemessages.timeline.VoiceMessageStateProvider
|
||||
import io.element.android.libraries.designsystem.components.media.Waveform
|
||||
import io.element.android.libraries.designsystem.components.media.WaveformPlaybackView
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
|
|
@ -88,7 +87,7 @@ fun TimelineItemVoiceView(
|
|||
WaveformPlaybackView(
|
||||
showCursor = state.button == VoiceMessageState.Button.Pause,
|
||||
playbackProgress = state.progress,
|
||||
waveform = Waveform(data = content.waveform),
|
||||
waveform = content.waveform,
|
||||
modifier = Modifier
|
||||
.height(34.dp)
|
||||
.weight(1f),
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
|||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent
|
||||
import io.element.android.features.messages.impl.timeline.util.FileExtensionExtractor
|
||||
import io.element.android.features.messages.impl.timeline.util.toHtmlDocument
|
||||
import io.element.android.features.messages.impl.voicemessages.fromMSC3246range
|
||||
import io.element.android.libraries.androidutils.filesize.FileSizeFormatter
|
||||
import io.element.android.libraries.core.mimetype.MimeTypes
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||
|
|
@ -117,7 +118,7 @@ class TimelineItemContentMessageFactory @Inject constructor(
|
|||
mediaSource = messageType.source,
|
||||
duration = messageType.info?.duration ?: Duration.ZERO,
|
||||
mimeType = messageType.info?.mimetype ?: MimeTypes.OctetStream,
|
||||
waveform = messageType.details?.waveform?.toImmutableList() ?: persistentListOf(),
|
||||
waveform = messageType.details?.waveform?.fromMSC3246range()?.toImmutableList() ?: persistentListOf(),
|
||||
)
|
||||
else -> TimelineItemAudioContent(
|
||||
body = messageType.body,
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ data class TimelineItemVoiceContent(
|
|||
val duration: Duration,
|
||||
val mediaSource: MediaSource,
|
||||
val mimeType: String,
|
||||
val waveform: ImmutableList<Int>,
|
||||
val waveform: ImmutableList<Float>,
|
||||
) : TimelineItemEventContent {
|
||||
override val type: String = "TimelineItemAudioContent"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,11 +32,11 @@ open class TimelineItemVoiceContentProvider : PreviewParameterProvider<TimelineI
|
|||
),
|
||||
aTimelineItemVoiceContent(
|
||||
durationMs = 10_000,
|
||||
waveform = listOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0),
|
||||
waveform = listOf(0f, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f, 8f, 7f, 6f, 5f, 4f, 3f, 2f, 1f, 0f),
|
||||
),
|
||||
aTimelineItemVoiceContent(
|
||||
durationMs = 1_800_000, // 30 minutes
|
||||
waveform = List(1024) { it },
|
||||
waveform = List(1024) { it / 1024f },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -47,7 +47,7 @@ fun aTimelineItemVoiceContent(
|
|||
durationMs: Long = 61_000,
|
||||
contentUri: String = "mxc://matrix.org/1234567890abcdefg",
|
||||
mimeType: String = MimeTypes.Ogg,
|
||||
waveform: List<Int> = listOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0),
|
||||
waveform: List<Float> = listOf(0f, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f, 8f, 7f, 6f, 5f, 4f, 3f, 2f, 1f, 0f),
|
||||
) = TimelineItemVoiceContent(
|
||||
eventId = eventId?.let { EventId(it) },
|
||||
body = body,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* 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 io.element.android.features.messages.impl.voicemessages
|
||||
|
||||
/**
|
||||
* Resizes the given [0;1024] int list as per unstable MSC3246 spec
|
||||
* to a [0;1] range float list to be used for waveform rendering.
|
||||
*/
|
||||
fun List<Int>.fromMSC3246range(): List<Float> = map { it / 1024f }
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* 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 io.element.android.libraries.designsystem.components.media
|
||||
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
data class Waveform (
|
||||
val data: ImmutableList<Int>
|
||||
) {
|
||||
companion object {
|
||||
private val dataRange = 0..1024
|
||||
}
|
||||
|
||||
fun normalisedData(maxSamplesCount: Int): ImmutableList<Float> {
|
||||
if(maxSamplesCount <= 0) {
|
||||
return persistentListOf()
|
||||
}
|
||||
|
||||
// Filter the data to keep only the expected number of samples
|
||||
val result = if (data.size > maxSamplesCount) {
|
||||
(0..<maxSamplesCount)
|
||||
.map { index ->
|
||||
val targetIndex = (index.toDouble() * (data.count().toDouble() / maxSamplesCount.toDouble())).roundToInt()
|
||||
data[targetIndex]
|
||||
}
|
||||
} else {
|
||||
data
|
||||
}
|
||||
|
||||
// Normalize the sample in the allowed range
|
||||
return result.map { it.toFloat() / dataRange.last.toFloat() }.toPersistentList()
|
||||
}
|
||||
}
|
||||
|
|
@ -46,22 +46,25 @@ import androidx.compose.ui.unit.dp
|
|||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.theme.ElementTheme
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlin.math.max
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
private const val DEFAULT_GRAPHICS_LAYER_ALPHA: Float = 0.99F
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
fun WaveformPlaybackView(
|
||||
playbackProgress: Float,
|
||||
showCursor: Boolean,
|
||||
waveform: Waveform,
|
||||
waveform: ImmutableList<Float>,
|
||||
modifier: Modifier = Modifier,
|
||||
onSeek: (progress: Float) -> Unit = {},
|
||||
brush: Brush = SolidColor(ElementTheme.colors.iconQuaternary),
|
||||
progressBrush: Brush = SolidColor(ElementTheme.colors.iconSecondary),
|
||||
cursorBrush: Brush = SolidColor(ElementTheme.colors.iconAccentTertiary),
|
||||
progressBrush: Brush = SolidColor(ElementTheme.colors.iconSecondary),
|
||||
cursorBrush: Brush = SolidColor(ElementTheme.colors.iconAccentTertiary),
|
||||
lineWidth: Dp = 2.dp,
|
||||
linePadding: Dp = 2.dp,
|
||||
minimumGraphAmplitude: Float = 2F,
|
||||
|
|
@ -145,7 +148,7 @@ fun WaveformPlaybackView(
|
|||
),
|
||||
blendMode = BlendMode.SrcAtop
|
||||
)
|
||||
if(showCursor || seekProgress.value != null) {
|
||||
if (showCursor || seekProgress.value != null) {
|
||||
drawRoundRect(
|
||||
brush = cursorBrush,
|
||||
topLeft = Offset(
|
||||
|
|
@ -166,24 +169,43 @@ fun WaveformPlaybackView(
|
|||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun WaveformPlaybackViewPreview() = ElementPreview {
|
||||
Column{
|
||||
Column {
|
||||
WaveformPlaybackView(
|
||||
modifier = Modifier.height(34.dp),
|
||||
showCursor = false,
|
||||
playbackProgress = 0.5f,
|
||||
waveform = Waveform(persistentListOf()),
|
||||
waveform = persistentListOf(),
|
||||
)
|
||||
WaveformPlaybackView(
|
||||
modifier = Modifier.height(34.dp),
|
||||
showCursor = false,
|
||||
playbackProgress = 0.5f,
|
||||
waveform = Waveform(persistentListOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)),
|
||||
waveform = persistentListOf(0f, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f, 8f, 7f, 6f, 5f, 4f, 3f, 2f, 1f, 0f),
|
||||
)
|
||||
WaveformPlaybackView(
|
||||
modifier = Modifier.height(34.dp),
|
||||
showCursor = true,
|
||||
playbackProgress = 0.5f,
|
||||
waveform = Waveform(List(1024) { it }.toPersistentList()),
|
||||
waveform = List(1024) { it / 1024f }.toPersistentList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun ImmutableList<Float>.normalisedData(maxSamplesCount: Int): ImmutableList<Float> {
|
||||
if (maxSamplesCount <= 0) {
|
||||
return persistentListOf()
|
||||
}
|
||||
|
||||
// Filter the data to keep only the expected number of samples
|
||||
val result = if (this.size > maxSamplesCount) {
|
||||
(0..<maxSamplesCount)
|
||||
.map { index ->
|
||||
val targetIndex = (index.toDouble() * (this.count().toDouble() / maxSamplesCount.toDouble())).roundToInt()
|
||||
this[targetIndex]
|
||||
}
|
||||
} else {
|
||||
this
|
||||
}
|
||||
|
||||
return result.toPersistentList()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:18378d89af53ac54931d3feb3129ff90e0e45c707144322de3d8740fd3ce3645
|
||||
size 6436
|
||||
oid sha256:e9ea30725d03749028f907e341ee09bb98a67cc6bda76757f7b3d266fed3722f
|
||||
size 7177
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d95ae8cc103ad50397c804ba2fe16c3b4fb380456f2b3be6f99ec62877b36758
|
||||
size 6429
|
||||
oid sha256:52ae85fdd9eeb0e3d81336c38147d8251079e2ae61364ca7f7cd573676dc2c57
|
||||
size 7085
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:10058823be0d5f0a23e1712d4523188729dd7579005a48a63e8e553baea105c0
|
||||
size 5936
|
||||
oid sha256:da00e2729bcd8ac55de08a2ff2e101e6746a64a5fdc07c8ddbb8297543dc493f
|
||||
size 6663
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:12eacc1babdc55ec2faed630889157ea0c9e6dca8845ecc93bc72bd645f23a9e
|
||||
size 6481
|
||||
oid sha256:d44ed3c1ff4607171e21c580f337ca0a5664992fb90d2072b511af8e72ac8353
|
||||
size 7070
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2e4ee91fc8599e4c3e1d093587a9688c36df971a94bb832e6662c86572fb08c7
|
||||
size 6436
|
||||
oid sha256:7eb5e7f99047da383a6bc5a45eb76bd902c21fcede196626fc4f6f5507097d51
|
||||
size 7333
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a2649d3974b096f17a6e80d728b08409c0f1b28ed649f33c7798f6223f55ca29
|
||||
size 6343
|
||||
oid sha256:d4a2824fdc49adb0e3fc155e7da319414544a87dc083bdece78e85ba72669d78
|
||||
size 7155
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7841691e0bbcfa0655304ac6a7c0ea24353aae9bfc264dc7978c2a4526781ee3
|
||||
size 6357
|
||||
oid sha256:3817e348ba2775528e3805ad6f5eed044f82b241f73692180c0638c95fb79fa2
|
||||
size 7076
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d1a1ad6a3c02f24a8b811197f6999d93db57d3c1e9b867638c88f4759e9f1b87
|
||||
size 5926
|
||||
oid sha256:fd21f1c5ad2616b698a386d78d5efe0ab40aa1959382ed2a568c10441d093a8f
|
||||
size 6692
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0adbfdd9131913c11d7e4777b4bdfbda84b3a9c6f1784781698d9208023e9c39
|
||||
size 6400
|
||||
oid sha256:07f52161378dfab92ffb76b860680390ccb5dfcc05347c5fd99504c806dd3210
|
||||
size 6930
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:cf18143a576ef0a136ca6e07c51521f5d41b6b5f381d168ff311cdf099752550
|
||||
size 6349
|
||||
oid sha256:4adce5249b20bdc9ed6f4d5f066140e8c9b0f62d04ebf953704a106a6ca2ff53
|
||||
size 7178
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:216e36042ad1ef11331d8610ab32383112bde38e314ae0d8c42d23931c7874a2
|
||||
size 43748
|
||||
oid sha256:5c52825ef36b00ee13496c23db981c226a3f71c0d1755508835b4ab3a140cff6
|
||||
size 46402
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2542c95c067d4d65e76ea606801dc3dbfc196d8128a8547ed3e1bd93b84d4ab9
|
||||
size 42513
|
||||
oid sha256:ceb0cfa1b7ac95de658e339d29b4e18d8e4673d1a269db3d46bc6fd97381e9c2
|
||||
size 45460
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:efc60fcfb39718bfce62f16e82a0c85249b71bf850b2d996bb1234a882261bc9
|
||||
size 10021
|
||||
oid sha256:dbe3214d0b8c497f563957c9df870aa7b6cbf981e174a7f9481cc1555af50533
|
||||
size 10247
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f6f5b1b3ce84e262eec2f5fea04e4d8d15d0ec4dabd589b73b8b0c0b41afb514
|
||||
size 9754
|
||||
oid sha256:876ac7c1ac9f3a188bd4ebcc4faef6fd363e166b1ec3d5a844872f7a0cf676aa
|
||||
size 9969
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue