Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
ShirasawaSama committed Dec 20, 2023
1 parent 584e52e commit 57d4f46
Show file tree
Hide file tree
Showing 18 changed files with 168 additions and 116 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import androidx.compose.ui.input.key.Key
interface Command {
val name: String
val displayName: String
fun execute() {}
val keyBindings: Array<Key>
val icon: ImageVector?
val activeWhen: Array<String>?
fun execute()
}

abstract class AbstractCommand(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ interface BasicEditor {
delete()
}
fun paste() { }
fun duplicate() { }
val hasSelected get() = true
val canPaste get() = true
val canDelete get() = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.*
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.layout.positionInRoot
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.drawText
Expand Down Expand Up @@ -472,7 +472,7 @@ class EnvelopeEditor(

// if (hoveredIndex == -1 && action == EditAction.RESIZE) modifier = modifier.pointerHoverIcon(PointerIconDefaults.VerticalResize)

Canvas(Modifier.fillMaxSize().graphicsLayer { }.onGloballyPositioned { positionInRoot = it.positionInRoot() }.run {
Canvas(Modifier.fillMaxSize().graphicsLayer { }.onPlaced { positionInRoot = it.positionInRoot() }.run {
if (eventHandler == null) this else pointerInput(Unit) {
detectTapGestures(onDoubleTap = {
if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.*
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.layout.positionInRoot
import androidx.compose.ui.unit.*
import androidx.compose.ui.util.fastForEach
Expand Down Expand Up @@ -144,7 +144,7 @@ fun FloatingLayer(
} }
val offset = remember { arrayOf(Offset.Zero) }
val size = remember { arrayOf(Size.Zero) }
Box((if (isCentral) modifier else modifier.onGloballyPositioned {
Box((if (isCentral) modifier else modifier.onPlaced {
offset[0] = it.positionInRoot()
size[0] = it.size.toSize()
}).let { if (enabled) it.pointerHoverIcon(PointerIcon.Hand) else it }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEachReversed
Expand Down Expand Up @@ -58,7 +58,7 @@ private fun SnackbarAnim(snackbar: Snackbar) {
spring(stiffness = Spring.StiffnessMediumLow)
)
AnimatedVisibility(snackbar.isVisible,
Modifier.onGloballyPositioned { if (it.size.height > height[0]) height[0] = it.size.height }
Modifier.onPlaced { if (it.size.height > height[0]) height[0] = it.size.height }
.run { if (height[0] > 0) height(LocalDensity.current.run { (height[0] * anim).toDp() }) else this },
enter = slideInHorizontally { it },
exit = slideOutHorizontally { it }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,34 @@

package com.eimsound.daw.components

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.graphics.*
import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.unit.IntSize
import com.eimsound.audioprocessor.PlayPosition
import com.eimsound.audioprocessor.convertPPQToSeconds
import com.eimsound.dsp.data.AudioThumbnail
import com.eimsound.dsp.data.EnvelopePointList
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlin.math.absoluteValue

private const val STEP_IN_PX = 0.5F
private const val WAVEFORM_DAMPING = 0.93F

private fun DrawScope.drawMinAndMax(
private fun Canvas.drawMinAndMax(
thumbnail: AudioThumbnail, startSeconds: Double, endSeconds: Double,
channelHeight: Float, halfChannelHeight: Float, drawHalfChannelHeight: Float,
color: Color
paint: Paint, width: Float
) {
var min = 0F
var max = 0F
thumbnail.query(size.width.toDouble(), startSeconds, endSeconds, STEP_IN_PX) { x, ch, min0, max0 ->
thumbnail.query(width, startSeconds, endSeconds, STEP_IN_PX) { x, ch, min0, max0 ->
val y = 2 + channelHeight * ch + halfChannelHeight
val curMax = max0.absoluteValue.coerceAtMost(1F) * drawHalfChannelHeight
val curMin = min0.absoluteValue.coerceAtMost(1F) * drawHalfChannelHeight
Expand All @@ -36,35 +38,25 @@ private fun DrawScope.drawMinAndMax(
if (curMax > max) max = curMax
else max *= WAVEFORM_DAMPING
if (min + max < 0.3F) {
drawLine(color, Offset(x, y), Offset(x + STEP_IN_PX, y), STEP_IN_PX)
drawRect(x, y,x + STEP_IN_PX, y, paint)
return@query
}
drawLine(
color,
Offset(x, y - max),
Offset(x, y + min),
0.5F
)
drawRect(x, y - max, x + STEP_IN_PX, y + min, paint)
}
}
private fun DrawScope.drawDefault(
private fun Canvas.drawDefault(
thumbnail: AudioThumbnail, startSeconds: Double, endSeconds: Double,
channelHeight: Float, halfChannelHeight: Float, drawHalfChannelHeight: Float,
color: Color
paint: Paint, width: Float
) {
thumbnail.query(size.width.toDouble(), startSeconds, endSeconds, STEP_IN_PX) { x, ch, min, max ->
thumbnail.query(width, startSeconds, endSeconds, STEP_IN_PX) { x, ch, min, max ->
val v = (if (max.absoluteValue > min.absoluteValue) max else min).coerceIn(-1F, 1F) * drawHalfChannelHeight
val y = 2 + channelHeight * ch + halfChannelHeight
if (v.absoluteValue < 0.3F) {
drawLine(color, Offset(x, y), Offset(x + STEP_IN_PX, y), STEP_IN_PX)
drawRect(x, y, x + STEP_IN_PX, y, paint)
return@query
}
drawLine(
color,
Offset(x, y),
Offset(x, y - v),
STEP_IN_PX
)
drawRect(x, y, x + STEP_IN_PX, y - v, paint)
}
}

Expand All @@ -77,33 +69,50 @@ fun Waveform(
isDrawMinAndMax: Boolean = true,
modifier: Modifier = Modifier
) {
thumbnail.read()
Canvas(modifier.fillMaxSize().graphicsLayer { }) {
val channelHeight = (size.height / thumbnail.channels) - 2
val halfChannelHeight = channelHeight / 2
val drawHalfChannelHeight = halfChannelHeight - 1
if (isDrawMinAndMax) {
drawMinAndMax(
thumbnail, startSeconds, endSeconds, channelHeight, halfChannelHeight,
drawHalfChannelHeight, color
)
} else {
drawDefault(
thumbnail, startSeconds, endSeconds, channelHeight, halfChannelHeight,
drawHalfChannelHeight, color
)
var size: IntSize? by remember { mutableStateOf(null) }
Box(Modifier.fillMaxSize().onPlaced { size = it.size }) {
val image by produceState<ImageBitmap?>(
null, size, thumbnail, thumbnail.read(), startSeconds, endSeconds, isDrawMinAndMax
) {
val curSize = size
if (curSize == null) {
value = null
return@produceState
}
withContext(Dispatchers.Default) {
val bitmap = ImageBitmap(curSize.width, curSize.height)
val paint = Paint()
Canvas(bitmap).apply {
val channelHeight = (curSize.height.toFloat() / thumbnail.channels) - 2
val halfChannelHeight = channelHeight / 2
val drawHalfChannelHeight = halfChannelHeight - 1
if (isDrawMinAndMax) {
drawMinAndMax(
thumbnail, startSeconds, endSeconds, channelHeight, halfChannelHeight,
drawHalfChannelHeight, paint, curSize.width.toFloat()
)
} else {
drawDefault(
thumbnail, startSeconds, endSeconds, channelHeight, halfChannelHeight,
drawHalfChannelHeight, paint, curSize.width.toFloat()
)
}
}
value = bitmap
}
}
image?.let { Image(it, "Waveform", modifier, colorFilter = ColorFilter.tint(color)) }
}
}

private fun DrawScope.drawMinAndMax(
private fun Canvas.drawMinAndMax(
thumbnail: AudioThumbnail, startPPQ: Float, startSeconds: Double,
endSeconds: Double, channelHeight: Float, halfChannelHeight: Float, drawHalfChannelHeight: Float,
stepPPQ: Float, color: Color, volumeEnvelope: EnvelopePointList?
stepPPQ: Float, volumeEnvelope: EnvelopePointList?, paint: Paint, width: Float
) {
var min = 0F
var max = 0F
thumbnail.query(size.width.toDouble(), startSeconds, endSeconds, STEP_IN_PX) { x, ch, min0, max0 ->
thumbnail.query(width, startSeconds, endSeconds, STEP_IN_PX) { x, ch, min0, max0 ->
val y = 2 + channelHeight * ch + halfChannelHeight
val volume = volumeEnvelope?.getValue((startPPQ + x * stepPPQ).toInt(), 1F) ?: 1F
val curMin = (min0.absoluteValue * volume).coerceAtMost(1F) * drawHalfChannelHeight
Expand All @@ -113,37 +122,27 @@ private fun DrawScope.drawMinAndMax(
if (curMax > max) max = curMax
else max *= WAVEFORM_DAMPING
if (min + max < 0.3F) {
drawLine(color, Offset(x, y), Offset(x + STEP_IN_PX, y), STEP_IN_PX)
drawRect(x, y, x + STEP_IN_PX, y, paint)
return@query
}
drawLine(
color,
Offset(x, y - max),
Offset(x, y + min),
0.5F
)
drawRect(x, y - max, x + STEP_IN_PX, y + min, paint)
}
}
private fun DrawScope.drawDefault(
private fun Canvas.drawDefault(
thumbnail: AudioThumbnail, startPPQ: Float, startSeconds: Double,
endSeconds: Double, channelHeight: Float, halfChannelHeight: Float, drawHalfChannelHeight: Float,
stepPPQ: Float, color: Color, volumeEnvelope: EnvelopePointList?
stepPPQ: Float, volumeEnvelope: EnvelopePointList?, paint: Paint, width: Float
) {
thumbnail.query(size.width.toDouble(), startSeconds, endSeconds, STEP_IN_PX) { x, ch, min, max ->
thumbnail.query(width, startSeconds, endSeconds, STEP_IN_PX) { x, ch, min, max ->
val v = ((if (max.absoluteValue > min.absoluteValue) max else min) *
(volumeEnvelope?.getValue((startPPQ + x * stepPPQ).toInt(), 1F) ?: 1F))
.coerceIn(-1F, 1F) * drawHalfChannelHeight
val y = 2 + channelHeight * ch + halfChannelHeight
if (v.absoluteValue < 0.3F) {
drawLine(color, Offset(x, y), Offset(x + STEP_IN_PX, y), STEP_IN_PX)
drawRect(x, y, x + STEP_IN_PX, y, paint)
return@query
}
drawLine(
color,
Offset(x, y),
Offset(x, y - v),
STEP_IN_PX
)
drawRect(x, y, x + STEP_IN_PX, y - v, paint)
}
}

Expand All @@ -156,26 +155,42 @@ fun Waveform(
isDrawMinAndMax: Boolean = true,
modifier: Modifier = Modifier
) {
thumbnail.read()
val factor = (thumbnail.sampleRate / position.sampleRate) * timeScale
val startSeconds = position.convertPPQToSeconds(startPPQ) / factor
val endSeconds = position.convertPPQToSeconds(startPPQ + widthPPQ) / factor
Canvas(modifier.fillMaxSize().graphicsLayer { }) {
val channelHeight = (size.height / thumbnail.channels) - 2
val halfChannelHeight = channelHeight / 2
val drawHalfChannelHeight = halfChannelHeight - 1
val stepPPQ = widthPPQ / size.width
volumeEnvelope?.read()
if (isDrawMinAndMax) {
drawMinAndMax(
thumbnail, startPPQ, startSeconds, endSeconds, channelHeight, halfChannelHeight,
drawHalfChannelHeight, stepPPQ, color, volumeEnvelope
)
} else {
drawDefault(
thumbnail, startPPQ, startSeconds, endSeconds, channelHeight, halfChannelHeight,
drawHalfChannelHeight, stepPPQ, color, volumeEnvelope
)
var size: IntSize? by remember { mutableStateOf(null) }
Box(modifier.fillMaxSize().onPlaced { size = it.size }) {
val factor = (thumbnail.sampleRate / position.sampleRate) * timeScale
val startSeconds = position.convertPPQToSeconds(startPPQ) / factor
val endSeconds = position.convertPPQToSeconds(startPPQ + widthPPQ) / factor
val image by produceState<ImageBitmap?>(
null, size, thumbnail, thumbnail.read(), startSeconds, endSeconds, volumeEnvelope, isDrawMinAndMax
) {
val curSize = size
if (curSize == null) {
value = null
return@produceState
}
withContext(Dispatchers.Default) {
val bitmap = ImageBitmap(curSize.width, curSize.height)
val paint = Paint()
val channelHeight = (curSize.height / thumbnail.channels) - 2F
val halfChannelHeight = channelHeight / 2
val drawHalfChannelHeight = halfChannelHeight - 1
val stepPPQ = widthPPQ / curSize.width
Canvas(bitmap).apply {
if (isDrawMinAndMax) {
drawMinAndMax(
thumbnail, startPPQ, startSeconds, endSeconds, channelHeight, halfChannelHeight,
drawHalfChannelHeight, stepPPQ, volumeEnvelope, paint, curSize.width.toFloat()
)
} else {
drawDefault(
thumbnail, startPPQ, startSeconds, endSeconds, channelHeight, halfChannelHeight,
drawHalfChannelHeight, stepPPQ, volumeEnvelope, paint, curSize.width.toFloat()
)
}
}
value = bitmap
}
}
image?.let { Image(it, "Waveform", Modifier.fillMaxSize(), colorFilter = ColorFilter.tint(color)) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.boundsInRoot
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.layout.positionInRoot
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
Expand Down Expand Up @@ -72,7 +72,7 @@ fun GlobalDraggable(
}
}
val contentColor = LocalContentColor.current
Box(modifier.onGloballyPositioned { currentPos[0] = it.positionInRoot() }.onDrag(onDragStart = {
Box(modifier.onPlaced { currentPos[0] = it.positionInRoot() }.onDrag(onDragStart = {
GlobalScope.launch {
val data = onDragStart() ?: return@launch
isCurrent = true
Expand All @@ -92,7 +92,7 @@ fun GlobalDraggable(
@Composable
fun GlobalDropTarget(onDrop: ((Any, Offset) -> Unit)?, modifier: Modifier = Modifier, content: @Composable (Offset?) -> Unit) {
var currentPos by remember { mutableStateOf(Rect.Zero) }
Box(modifier.onGloballyPositioned { currentPos = it.boundsInRoot() }) {
Box(modifier.onPlaced { currentPos = it.boundsInRoot() }) {
val globalDragAndDrop = LocalGlobalDragAndDrop.current
if (globalDragAndDrop.dataTransfer != null && currentPos.contains(globalDragAndDrop.currentPosition)) {
globalDragAndDrop.dropCallback = onDrop?.let {
Expand Down
Loading

0 comments on commit 57d4f46

Please sign in to comment.