lincollincol / compose-audiowaveform Goto Github PK
View Code? Open in Web Editor NEWAudio waveform library for Jetpack Compose
License: Apache License 2.0
Audio waveform library for Jetpack Compose
License: Apache License 2.0
I get 100 samples from the amplituda call
I can have only 80 max, to fit my width
Chunked doesn't work here because chunked takes an Int so 100 / 80, which is 1.25, will turn out as 1. So I get a 1 to 1 mapping and end up with 100 samples instead of 80.
Hi, thank you for this compose library
I've got an issue when using a colour with an alpha in waveformBrush, the alpha is also carried over to the progressBrush.
A small example to reproduce:
var waveformProgress by remember { mutableStateOf(0F) }
AudioWaveform(
amplitudes = amplitude,
waveformBrush = SolidColor(Color.White.copy(alpha = .5f)),
progressBrush = SolidColor(Color.Red),
amplitudeType = AmplitudeType.Max,
progress = waveformProgress,
onProgressChange = { waveformProgress = it }
)
And here is the actual rendering, the red does not match, it also has the alpha channel
How do i create A basic wave form with a simple list like this?
I see nothing
AudioWaveform(
modifier = Modifier.fillMaxSize(),
amplitudes = listOf(1000,3000,400),
amplitudeType = AmplitudeType.Avg,
progressBrush = animatedGradientBrush,
onProgressChange = { waveformProgress = it }
)
java.lang.NoSuchMethodError: No static method drawRoundRect-ZuiqVtQ$default(Landroidx/compose/ui/graphics/drawscope/DrawScope;Landroidx/compose/ui/graphics/Brush;JJJFLandroidx/compose/ui/graphics/drawscope/DrawStyle;Landroidx/compose/ui/graphics/ColorFilter;IILjava/lang/Object;)V in class Landroidx/compose/ui/graphics/drawscope/DrawScope; or its super classes (declaration of 'androidx.compose.ui.graphics.drawscope.DrawScope' appears in /data/app/~~wme9RWI_TEWRMheotXYODg==/jp.tripmate.slo.dev-dqTZEZknICnb5A4bkff_CQ==/base.apk)
at com.linc.audiowaveform.AudioWaveformKt$AudioWaveform$2.invoke(AudioWaveform.kt:100)
at com.linc.audiowaveform.AudioWaveformKt$AudioWaveform$2.invoke(AudioWaveform.kt:74)
Hi, I'm facing above crash. Is this a bug?
Hi. I want to use Audio Wave.
There is a error like:
Could not resolve all files for configuration ':app:debugRuntimeClasspath'.
Could not find com.github.lincollincol:compose-audiowaveform:v1.1.1.
Searched in the following locations:
- https://dl.google.com/dl/android/maven2/com/github/lincollincol/compose-audiowaveform/v1.1.1/compose-audiowaveform-v1.1.1.pom
- https://repo.maven.apache.org/maven2/com/github/lincollincol/compose-audiowaveform/v1.1.1/compose-audiowaveform-v1.1.1.pom
Required by:
project :app
Run with --info or --debug option to get more log output.
Run with --scan to get full insights.
==============================================================================
BUILD FAILED in 732ms
21 actionable tasks: 8 executed, 13 up-to-date
App crashes when using silent audio source
ex) amplitudes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
java.lang.IllegalStateException: AnimationVector cannot contain a NaN. AnimationVector1D: value = NaN. Animation: TargetBasedAnimation: 1.0 -> NaN,initial velocity: AnimationVector1D: value = 0.0, duration: 500 ms,animationSpec: androidx.compose.animation.core.VectorizedTweenSpec@64fbf4d, playTimeNanos: 0
at androidx.compose.animation.core.TargetBasedAnimation.getValueFromNanos(Animation.kt:242)
at androidx.compose.animation.core.SuspendAnimationKt.animate(SuspendAnimation.kt:233)
at androidx.compose.animation.core.Animatable$runAnimation$2.invokeSuspend(Animatable.kt:305)
at androidx.compose.animation.core.Animatable$runAnimation$2.invoke(Unknown Source:8)
at androidx.compose.animation.core.Animatable$runAnimation$2.invoke(Unknown Source:2)
at androidx.compose.animation.core.MutatorMutex$mutate$2.invokeSuspend(InternalMutatorMutex.kt:119)
at androidx.compose.animation.core.MutatorMutex$mutate$2.invoke(Unknown Source:8)
at androidx.compose.animation.core.MutatorMutex$mutate$2.invoke(Unknown Source:4)
at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:89)
at kotlinx.coroutines.CoroutineScopeKt.coroutineScope(CoroutineScope.kt:264)
at androidx.compose.animation.core.MutatorMutex.mutate(InternalMutatorMutex.kt:112)
at androidx.compose.animation.core.MutatorMutex.mutate$default(InternalMutatorMutex.kt:109)
at androidx.compose.animation.core.Animatable.runAnimation(Animatable.kt:295)
at androidx.compose.animation.core.Animatable.animateTo(Animatable.kt:238)
at androidx.compose.animation.core.Animatable.animateTo$default(Animatable.kt:225)
at androidx.compose.animation.core.AnimateAsStateKt$animateValueAsState$3$1.invokeSuspend(AnimateAsState.kt:428)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at androidx.compose.ui.platform.AndroidUiDispatcher.performTrampolineDispatch(AndroidUiDispatcher.android.kt:81)
at androidx.compose.ui.platform.AndroidUiDispatcher.access$performTrampolineDispatch(AndroidUiDispatcher.android.kt:41)
at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.run(AndroidUiDispatcher.android.kt:57)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7872)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
Hey there, a very weird thing is happening to me. If i run my app it works fine, the moment I generate an APK (debug & prod) the app starts crashing, not sure if there is a version conflict of compose or something
Fatal Exception: java.lang.NoSuchMethodError: No static method drawRoundRect-ZuiqVtQ$default(Landroidx/compose/ui/graphics/drawscope/DrawScope;Landroidx/compose/ui/graphics/Brush;JJJFLandroidx/compose/ui/graphics/drawscope/DrawStyle;Landroidx/compose/ui/graphics/ColorFilter;IILjava/lang/Object;)V in class Landroidx/compose/ui/graphics/drawscope/DrawScope; or its super classes (declaration of 'androidx.compose.ui.graphics.drawscope.DrawScope' appears in /data/app/~~T3hw3VsgkcCWIL9FcsmQJQ==/com.zero.android-64B_I5Q69FNpyFB7i7CAtA==/base.apk)
at com.linc.audiowaveform.AudioWaveformKt$AudioWaveform$2.invoke(AudioWaveform.kt:100)
at com.linc.audiowaveform.AudioWaveformKt$AudioWaveform$2.invoke(AudioWaveform.kt:74)
at androidx.compose.ui.draw.DrawBackgroundModifier.draw(DrawModifier.kt:104)
at androidx.compose.ui.node.BackwardsCompatNode.draw(BackwardsCompatNode.kt:376)
at androidx.compose.ui.node.LayoutNodeDrawScope.draw-x_KDEd0$ui_release(LayoutNodeDrawScope.kt:92)
at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:371)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:360)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.performDraw(LayoutModifierNodeCoordinator.kt:236)
at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:368)
at androidx.compose.ui.node.NodeCoordinator.access$drawContainedDrawModifiers(NodeCoordinator.kt:58)
at androidx.compose.ui.node.NodeCoordinator$invoke$1.invoke(NodeCoordinator.kt:397)
at androidx.compose.ui.node.NodeCoordinator$invoke$1.invoke(NodeCoordinator.kt:396)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2139)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:130)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:126)
at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:341)
at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(:1)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:126)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:120)
at androidx.compose.ui.node.NodeCoordinator.invoke(NodeCoordinator.kt:396)
at androidx.compose.ui.node.NodeCoordinator.invoke(NodeCoordinator.kt:58)
at androidx.compose.ui.platform.RenderNodeApi29.record(RenderNodeApi29.android.kt:180)
at androidx.compose.ui.platform.RenderNodeLayer.updateDisplayList(RenderNodeLayer.android.kt:298)
at androidx.compose.ui.platform.RenderNodeLayer.drawLayer(RenderNodeLayer.android.kt:239)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:355)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.performDraw(LayoutModifierNodeCoordinator.kt:236)
at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:368)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:360)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.performDraw(LayoutModifierNodeCoordinator.kt:236)
at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:368)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:360)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.performDraw(LayoutModifierNodeCoordinator.kt:236)
at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:368)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:360)
at androidx.compose.ui.node.LayoutNode.draw$ui_release(LayoutNode.kt:840)
at androidx.compose.ui.node.InnerNodeCoordinator.performDraw(InnerNodeCoordinator.kt:151)
at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:368)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:360)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.performDraw(LayoutModifierNodeCoordinator.kt:236)
at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:368)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:360)
at androidx.compose.ui.node.LayoutNode.draw$ui_release(LayoutNode.kt:840)
at androidx.compose.ui.node.InnerNodeCoordinator.performDraw(InnerNodeCoordinator.kt:151)
at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:368)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:360)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.performDraw(LayoutModifierNodeCoordinator.kt:236)
at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:368)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:360)
at androidx.compose.ui.node.LayoutNode.draw$ui_release(LayoutNode.kt:840)
at androidx.compose.ui.node.InnerNodeCoordinator.performDraw(InnerNodeCoordinator.kt:151)
at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:368)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:360)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.performDraw(LayoutModifierNodeCoordinator.kt:236)
at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:368)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:360)
at androidx.compose.ui.node.LayoutNode.draw$ui_release(LayoutNode.kt:840)
at androidx.compose.ui.node.InnerNodeCoordinator.performDraw(InnerNodeCoordinator.kt:151)
at androidx.compose.ui.node.LayoutNodeDrawScope.drawContent(LayoutNodeDrawScope.kt:64)
at androidx.compose.foundation.Background.draw(Background.kt:107)
at androidx.compose.ui.node.BackwardsCompatNode.draw(BackwardsCompatNode.kt:376)
at androidx.compose.ui.node.LayoutNodeDrawScope.draw-x_KDEd0$ui_release(LayoutNodeDrawScope.kt:92)
at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:371)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:360)
at androidx.compose.ui.node.LayoutNode.draw$ui_release(LayoutNode.kt:840)
at androidx.compose.ui.node.InnerNodeCoordinator.performDraw(InnerNodeCoordinator.kt:151)
at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:368)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:360)
at androidx.compose.ui.node.LayoutNode.draw$ui_release(LayoutNode.kt:840)
at androidx.compose.ui.node.InnerNodeCoordinator.performDraw(InnerNodeCoordinator.kt:151)
at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:368)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:360)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.performDraw(LayoutModifierNodeCoordinator.kt:236)
at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:368)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:360)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.performDraw(LayoutModifierNodeCoordinator.kt:236)
at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:368)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:360)
at androidx.compose.ui.node.LayoutNode.draw$ui_release(LayoutNode.kt:840)
at androidx.compose.ui.node.InnerNodeCoordinator.performDraw(InnerNodeCoordinator.kt:151)
at androidx.compose.ui.node.LayoutNodeDrawScope.drawContent(LayoutNodeDrawScope.kt:64)
at androidx.compose.material.ripple.AndroidRippleIndicationInstance.drawIndication(Ripple.android.kt:184)
at androidx.compose.foundation.IndicationModifier.draw(Indication.kt:183)
at androidx.compose.ui.node.BackwardsCompatNode.draw(BackwardsCompatNode.kt:376)
at androidx.compose.ui.node.LayoutNodeDrawScope.draw-x_KDEd0$ui_release(LayoutNodeDrawScope.kt:92)
at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:371)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:360)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.performDraw(LayoutModifierNodeCoordinator.kt:236)
at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:368)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:360)
at androidx.compose.ui.node.LayoutNode.draw$ui_release(LayoutNode.kt:840)
at androidx.compose.ui.node.InnerNodeCoordinator.performDraw(InnerNodeCoordinator.kt:151)
at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:368)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:360)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.performDraw(LayoutModifierNodeCoordinator.kt:236)
at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:368)
at androidx.compose.ui.node.NodeCoordinator.access$drawContainedDrawModifiers(NodeCoordinator.kt:58)
at androidx.compose.ui.node.NodeCoordinator$invoke$1.invoke(NodeCoordinator.kt:397)
at androidx.compose.ui.node.NodeCoordinator$invoke$1.invoke(NodeCoordinator.kt:396)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2139)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:130)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:126)
at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:341)
at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(:1)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:126)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:120)
at androidx.compose.ui.node.NodeCoordinator.invoke(NodeCoordinator.kt:396)
at androidx.compose.ui.node.NodeCoordinator.invoke(NodeCoordinator.kt:58)
at androidx.compose.ui.platform.RenderNodeApi29.record(RenderNodeApi29.android.kt:180)
at androidx.compose.ui.platform.RenderNodeLayer.updateDisplayList(RenderNodeLayer.android.kt:298)
at androidx.compose.ui.platform.AndroidComposeView.dispatchDraw(AndroidComposeView.android.kt:1010)
at android.view.View.draw(View.java:22818)
at android.view.View.updateDisplayListIfDirty(View.java:21669)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4588)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4561)
at android.view.View.updateDisplayListIfDirty(View.java:21626)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4588)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4561)
at android.view.View.updateDisplayListIfDirty(View.java:21626)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4588)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4561)
at android.view.View.updateDisplayListIfDirty(View.java:21626)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4588)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4561)
at android.view.View.updateDisplayListIfDirty(View.java:21626)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:534)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:540)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:620)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:4763)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:4467)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3549)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2322)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:9155)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1232)
at android.view.Choreographer.doCallbacks(Choreographer.java:1029)
at android.view.ChoreographerExtImpl.checkScrollOptSceneEnable(ChoreographerExtImpl.java:387)
at android.view.Choreographer.doFrame(Choreographer.java:913)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1217)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:238)
at android.os.Looper.loop(Looper.java:349)
at android.app.ActivityThread.main(ActivityThread.java:8241)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:584)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1034)
Currently, the sample app contains the example which uses the ContentResolver to play the local files.
We need some help to directly play media from the Url. how do we set up the MediaItem to play from the URL? From the Example, we can see it is using MediController to play the local file is there any example where we can play using URL?
As the title suggested whenever I try to customize waveform width with the following line, the waveform take the full width of the screen
AudioWaveform( modifier = modifier.fillMaxWidth(0.75f) )
This is maybe due to behavior of Internally AudioWaveform Composable the Canvas function uses fillMaxWidth()
Any resolution for this?
This could be cool if its implemented or any ideas how this library could be modified to achieve that.
java.lang.NoSuchMethodError: No static method graphicsLayer-Ap8cVGQ$default(Landroidx/compose/ui/Modifier;FFFFFFFFFFJLandroidx/compose/ui/graphics/Shape;ZLandroidx/compose/ui/graphics/RenderEffect;JJIILjava/lang/Object;)Landroidx/compose/ui/Modifier; in class Landroidx/compose/ui/graphics/GraphicsLayerModifierKt; or its super classes (declaration of 'androidx.compose.ui.graphics.GraphicsLayerModifierKt' appears in /data/app/com.pico.learningcanvas-1/base.apk) at com.linc.audiowaveform.AudioWaveformKt.AudioWaveform-x4UjrtE(AudioWaveform.kt:76)
It's the same issue in #9 and I don't know why the issue is closed without providing a solution for it :')
buildscript { ext { compose_version = '1.2.0' } }// Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { id 'com.android.application' version '7.4.1' apply false id 'com.android.library' version '7.4.1' apply false id 'org.jetbrains.kotlin.android' version '1.7.0' apply false }
` plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
android {
namespace 'com.pico.learningcanvas'
compileSdk 33
defaultConfig {
applicationId "com.pico.learningcanvas"
minSdk 23
targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.2.0'
}
packagingOptions {
resources {
excludes += '/META-INF/{AL2.0,LGPL2.1}'
}
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
implementation 'androidx.activity:activity-compose:1.3.1'
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation 'androidx.compose.material3:material3:1.0.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
implementation 'com.github.lincollincol:amplituda:2.2.2'
implementation 'com.github.lincollincol:compose-audiowaveform:1.1.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0'
}
`
`
import android.view.MotionEvent
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.runtime.*
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.*
import androidx.compose.ui.graphics.drawscope.DrawStyle
import androidx.compose.ui.graphics.drawscope.Fill
import androidx.compose.ui.input.pointer.pointerInteropFilter
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.coerceIn
import androidx.compose.ui.unit.dp
import com.linc.audiowaveform.model.AmplitudeType
import com.linc.audiowaveform.model.WaveformAlignment
import kotlin.math.ceil
import kotlin.math.roundToInt
private val MinSpikeWidthDp: Dp = 1.dp
private val MaxSpikeWidthDp: Dp = 24.dp
private val MinSpikePaddingDp: Dp = 0.dp
private val MaxSpikePaddingDp: Dp = 12.dp
private val MinSpikeRadiusDp: Dp = 0.dp
private val MaxSpikeRadiusDp: Dp = 12.dp
private const val MinProgress: Float = 0F
private const val MaxProgress: Float = 1F
private const val MinSpikeHeight: Float = 1F
private const val DefaultGraphicsLayerAlpha: Float = 0.99F
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun AudioWaveform(
modifier: Modifier = Modifier,
style: DrawStyle = Fill,
waveformBrush: Brush = SolidColor(Color.White),
progressBrush: Brush = SolidColor(Color.Blue),
waveformAlignment: WaveformAlignment = WaveformAlignment.Center,
amplitudeType: AmplitudeType = AmplitudeType.Avg,
onProgressChangeFinished: (() -> Unit)? = null,
spikeAnimationSpec: AnimationSpec<Float> = tween(500),
spikeWidth: Dp = 4.dp,
spikeRadius: Dp = 2.dp,
spikePadding: Dp = 1.dp,
progress: Float = 0F,
amplitudes: List<Int>,
onProgressChange: (Float) -> Unit
) {
val _progress = remember(progress) { progress.coerceIn(MinProgress, MaxProgress) }
val _spikeWidth = remember(spikeWidth) { spikeWidth.coerceIn(MinSpikeWidthDp, MaxSpikeWidthDp) }
val _spikePadding = remember(spikePadding) { spikePadding.coerceIn(MinSpikePaddingDp, MaxSpikePaddingDp) }
val _spikeRadius = remember(spikeRadius) { spikeRadius.coerceIn(MinSpikeRadiusDp, MaxSpikeRadiusDp) }
val _spikeTotalWidth = remember(spikeWidth, spikePadding) { _spikeWidth + _spikePadding }
var canvasSize by remember { mutableStateOf(Size(0f, 0f)) }
var spikes by remember { mutableStateOf(0F) }
val spikesAmplitudes = remember(amplitudes, spikes, amplitudeType) {
amplitudes.toDrawableAmplitudes(
amplitudeType = amplitudeType,
spikes = spikes.toInt(),
minHeight = MinSpikeHeight,
maxHeight = canvasSize.height.coerceAtLeast(MinSpikeHeight)
)
}.map { animateFloatAsState(it, spikeAnimationSpec).value }
Canvas(
modifier = Modifier
.fillMaxWidth()
.requiredHeight(48.dp)
.graphicsLayer(alpha = DefaultGraphicsLayerAlpha)
.pointerInteropFilter {
return@pointerInteropFilter when (it.action) {
MotionEvent.ACTION_DOWN,
MotionEvent.ACTION_MOVE -> {
if (it.x in 0F..canvasSize.width) {
onProgressChange(it.x / canvasSize.width)
true
} else false
}
MotionEvent.ACTION_UP -> {
onProgressChangeFinished?.invoke()
true
}
else -> false
}
}
.then(modifier)
) {
canvasSize = size
spikes = size.width / _spikeTotalWidth.toPx()
spikesAmplitudes.forEachIndexed { index, amplitude ->
drawRoundRect(
brush = waveformBrush,
topLeft = Offset(
x = index * _spikeTotalWidth.toPx(),
y = when(waveformAlignment) {
WaveformAlignment.Top -> 0F
WaveformAlignment.Bottom -> size.height - amplitude
WaveformAlignment.Center -> size.height / 2F - amplitude / 2F
}
),
size = Size(
width = _spikeWidth.toPx(),
height = amplitude
),
cornerRadius = CornerRadius(_spikeRadius.toPx(), _spikeRadius.toPx()),
style = style
)
drawRect(
brush = progressBrush,
size = Size(
width = _progress * size.width,
height = size.height
),
blendMode = BlendMode.SrcAtop
)
}
}
}
private fun List<Int>.toDrawableAmplitudes(
amplitudeType: AmplitudeType,
spikes: Int,
minHeight: Float,
maxHeight: Float
): List<Float> {
val amplitudes = map(Int::toFloat)
if(amplitudes.isEmpty() || spikes == 0) {
return List(spikes) { minHeight }
}
val transform = { data: List<Float> ->
when(amplitudeType) {
AmplitudeType.Avg -> data.average()
AmplitudeType.Max -> data.max()
AmplitudeType.Min -> data.min()
}.toFloat().coerceIn(minHeight, maxHeight)
}
return when {
spikes > amplitudes.count() -> amplitudes.fillToSize(spikes, transform)
else -> amplitudes.chunkToSize(spikes, transform)
}.normalize(minHeight, maxHeight)
}
internal fun <T> Iterable<T>.fillToSize(size: Int, transform: (List<T>) -> T): List<T> {
val capacity = ceil(size.safeDiv(count())).roundToInt()
return map { data -> List(capacity) { data } }.flatten().chunkToSize(size, transform)
}
internal fun <T> Iterable<T>.chunkToSize(size: Int, transform: (List<T>) -> T): List<T> {
val chunkSize = count() / size
val remainder = count() % size
val remainderIndex = ceil(count().safeDiv(remainder)).roundToInt()
val chunkIteration = filterIndexed { index, _ ->
remainderIndex == 0 || index % remainderIndex != 0
}.chunked(chunkSize, transform)
return when (size) {
chunkIteration.count() -> chunkIteration
else -> chunkIteration.chunkToSize(size, transform)
}
}
internal fun Iterable<Float>.normalize(min: Float, max: Float): List<Float> {
return map { (max-min) * ((it - min()) / (max() - min())) + min }
}
private fun Int.safeDiv(value: Int): Float {
return if(value == 0) return 0F else this / value.toFloat()
}
`
I really don't know if it's ok to use it like that
Thank you for submitting this wonderful project to JetpackCompose.app. It's now featured on the site and we really appreciate your contribution to the Android community!
How can I use this lib to make a voice visualizer using audio recorder in android?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.