Split voices by sliding volumes per voices SATB, mixer desktop
This commit is contained in:
parent
e02afb3580
commit
86d6de7796
9 changed files with 106 additions and 46 deletions
|
|
@ -150,6 +150,12 @@ actual fun setVolume(level: Float) {
|
|||
return 120f
|
||||
}
|
||||
|
||||
actual fun updateVoiceVolume(voiceIndex: Int, newVolume: Float) {
|
||||
if (voiceIndex in 0..3) {
|
||||
//TODO: implements split voices & change volume per voices
|
||||
}
|
||||
}
|
||||
|
||||
fun release() {
|
||||
mediaPlayer?.release()
|
||||
mediaPlayer = null
|
||||
|
|
|
|||
BIN
composeApp/src/androidMain/res/drawable/mixer_bg.png
Normal file
BIN
composeApp/src/androidMain/res/drawable/mixer_bg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 794 KiB |
BIN
composeApp/src/androidMain/res/drawable/mixer_fader.png
Normal file
BIN
composeApp/src/androidMain/res/drawable/mixer_fader.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
composeApp/src/commonMain/composeResources/drawable/mixer_bg.png
Normal file
BIN
composeApp/src/commonMain/composeResources/drawable/mixer_bg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 794 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
|
|
@ -19,6 +19,7 @@ expect class FMediaPlayer(filename: String, onFinished: () -> Unit) {
|
|||
fun clearLoop()
|
||||
fun setTempo(factor: Float)
|
||||
fun getCurrentBPM(): Float
|
||||
fun updateVoiceVolume(voiceIndex: Int, newVolume: Float)
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1,20 +1,11 @@
|
|||
package mg.dot.feufaro.ui
|
||||
|
||||
import SharedScreenModel
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.ExperimentalSharedTransitionApi
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.scaleIn
|
||||
import androidx.compose.animation.scaleOut
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
|
|
@ -27,20 +18,15 @@ import androidx.compose.ui.draw.alpha
|
|||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.platform.*
|
||||
import kotlinx.coroutines.*
|
||||
import mg.dot.feufaro.data.DrawerItem
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import mg.dot.feufaro.data.getDrawerItems
|
||||
import mg.dot.feufaro.getConfigDirectoryPath
|
||||
import mg.dot.feufaro.getPlatform
|
||||
import mg.dot.feufaro.solfa.Solfa
|
||||
import mg.dot.feufaro.viewmodel.SolfaScreenModel
|
||||
import java.io.File
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
|
|
@ -266,6 +252,9 @@ LaunchedEffect(isPlay, isPos) {
|
|||
sharedScreenModel.setVolume(newVolume)
|
||||
println("Changement volume $newVolume -l $volumelevel")
|
||||
},
|
||||
onVoiceVolumeChange = { index, volume ->
|
||||
player?.updateVoiceVolume(index, volume)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Text("Sélectionner un morceau")
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
package mg.dot.feufaro.ui
|
||||
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.animation.core.AnimationSpec
|
||||
import androidx.compose.animation.core.ExperimentalAnimationSpecApi
|
||||
import androidx.compose.animation.core.LinearEasing
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.ScrollState
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
|
|
@ -20,13 +21,20 @@ import androidx.compose.runtime.*
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.paint
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.graphics.TransformOrigin
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import feufaro.composeapp.generated.resources.Res
|
||||
import feufaro.composeapp.generated.resources.ic_mixer_satb
|
||||
import feufaro.composeapp.generated.resources.ic_organ
|
||||
import feufaro.composeapp.generated.resources.mixer_bg
|
||||
import feufaro.composeapp.generated.resources.mixer_fader
|
||||
import kotlinx.coroutines.delay
|
||||
import mg.dot.feufaro.getPlatform
|
||||
import mg.dot.feufaro.midi.FMediaPlayer
|
||||
|
|
@ -43,6 +51,7 @@ fun MidiControlPanel(
|
|||
onPlayPauseClick: () -> Unit,
|
||||
onSeek: (Float) -> Unit,
|
||||
onVolumeChange: (Float) -> Unit,
|
||||
onVoiceVolumeChange: (voiceIndex: Int, newVolume: Float) -> Unit,
|
||||
mediaPlayer: FMediaPlayer,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
|
|
@ -56,6 +65,9 @@ fun MidiControlPanel(
|
|||
}
|
||||
|
||||
val voiceStates = mediaPlayer.getVoiceStates()
|
||||
val sliderVolumes = remember {
|
||||
mutableStateListOf(127f, 127f, 127f, 127f)
|
||||
}
|
||||
val labels = listOf("S", "A", "T", "B")
|
||||
listOf("Soprano", "Alto", "Ténor", "Basse")
|
||||
|
||||
|
|
@ -168,11 +180,61 @@ fun MidiControlPanel(
|
|||
enter = fadeIn() + scaleIn() + slideInVertically { it / 2 },
|
||||
exit = fadeOut() + scaleOut() + slideOutVertically { it / 2 }
|
||||
) {
|
||||
Row {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Row(
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.height(100.dp)
|
||||
.widthIn(max = 250.dp)
|
||||
.paint(
|
||||
painter = painterResource(Res.drawable.mixer_bg),
|
||||
contentScale = ContentScale.FillBounds
|
||||
)
|
||||
.padding(start = 0.dp, end = 0.dp)
|
||||
,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceEvenly
|
||||
) {
|
||||
for (i in 0 until 4) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.weight(1f),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Slider(
|
||||
value = sliderVolumes[i],
|
||||
onValueChange = { newValue ->
|
||||
sliderVolumes[i] = newValue
|
||||
mediaPlayer.updateVoiceVolume(i, newValue)
|
||||
},
|
||||
valueRange = 0f..126f,
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.graphicsLayer {
|
||||
rotationZ = -90f
|
||||
transformOrigin = TransformOrigin.Center
|
||||
}
|
||||
.fillMaxWidth(),
|
||||
thumb = {
|
||||
Image(
|
||||
painter = painterResource(Res.drawable.mixer_fader),
|
||||
contentDescription = "Fader Thumb",
|
||||
modifier = Modifier
|
||||
.size(width = 20.dp, height = 20.dp)
|
||||
.graphicsLayer {
|
||||
rotationZ = 90f
|
||||
},
|
||||
contentScale = ContentScale.Fit
|
||||
)
|
||||
},
|
||||
colors = SliderDefaults.colors(
|
||||
thumbColor = Color.Transparent,
|
||||
activeTrackColor = Color.Transparent,
|
||||
inactiveTrackColor = Color.Transparent
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
/*Row(
|
||||
modifier = Modifier.padding(vertical = 8.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
|
|
@ -187,8 +249,7 @@ fun MidiControlPanel(
|
|||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
AnimatedVisibility(
|
||||
|
|
|
|||
|
|
@ -1,14 +1,6 @@
|
|||
package mg.dot.feufaro.midi
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import mg.dot.feufaro.FileRepository
|
||||
import kotlinx.coroutines.*
|
||||
import mg.dot.feufaro.getConfigDirectoryPath
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.File
|
||||
|
|
@ -40,7 +32,7 @@ actual class FMediaPlayer actual constructor(
|
|||
private var isLoopingAB: Boolean = false
|
||||
|
||||
private val voiceStates = mutableListOf(true, true, true, true)
|
||||
|
||||
private val voiceVolumes = FloatArray(4) { 127f }
|
||||
private var currentGlobalVolume: Float = 0.8f
|
||||
|
||||
private var currentTempo: Float = 1.0f
|
||||
|
|
@ -170,23 +162,34 @@ actual class FMediaPlayer actual constructor(
|
|||
saveVoiceStates()
|
||||
applyVoiceStates()
|
||||
}
|
||||
actual fun updateVoiceVolume(voiceIndex: Int, newVolume: Float) {
|
||||
if (voiceIndex in 0..3) {
|
||||
voiceVolumes[voiceIndex] = newVolume
|
||||
applyVoiceStates()
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyVoiceStates() {
|
||||
try {
|
||||
synthetizer?.channels?.let { channels ->
|
||||
for (i in 0 until 4) {
|
||||
if (i < channels.size) {
|
||||
val isVoiceActive = voiceStates[i]
|
||||
val volume = if (voiceStates[i]) 127 else 0
|
||||
channels[i].controlChange(7, volume)
|
||||
channels[i].controlChange(11, volume)
|
||||
if(!isVoiceActive) {
|
||||
channels[i].controlChange(123, 0)
|
||||
}
|
||||
for (i in 0 until 4) {
|
||||
if (i < channels.size) {
|
||||
val volume = voiceVolumes[i].toInt()
|
||||
val isVoiceActive = voiceStates[i]
|
||||
val currentVolume = voiceVolumes[i].toInt()
|
||||
|
||||
if (volume == 0) {
|
||||
channels[i].controlChange(123, 0)
|
||||
voiceStates[i] = false
|
||||
} else {
|
||||
channels[i].controlChange(7, currentVolume)
|
||||
channels[i].controlChange(11, currentVolume)
|
||||
voiceStates[i] = true
|
||||
}
|
||||
}
|
||||
println("STAB màj: $voiceStates")
|
||||
println("SATB màj: $voiceStates, Volumes: ${voiceVolumes[i]}")
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) { e.printStackTrace() }
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue