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
|
return 120f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actual fun updateVoiceVolume(voiceIndex: Int, newVolume: Float) {
|
||||||
|
if (voiceIndex in 0..3) {
|
||||||
|
//TODO: implements split voices & change volume per voices
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun release() {
|
fun release() {
|
||||||
mediaPlayer?.release()
|
mediaPlayer?.release()
|
||||||
mediaPlayer = null
|
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 clearLoop()
|
||||||
fun setTempo(factor: Float)
|
fun setTempo(factor: Float)
|
||||||
fun getCurrentBPM(): Float
|
fun getCurrentBPM(): Float
|
||||||
|
fun updateVoiceVolume(voiceIndex: Int, newVolume: Float)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,11 @@
|
||||||
package mg.dot.feufaro.ui
|
package mg.dot.feufaro.ui
|
||||||
|
|
||||||
import SharedScreenModel
|
import SharedScreenModel
|
||||||
import androidx.compose.animation.AnimatedContent
|
import androidx.compose.animation.*
|
||||||
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.foundation.*
|
import androidx.compose.foundation.*
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
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.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.RectangleShape
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.compose.ui.platform.*
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.launch
|
||||||
import mg.dot.feufaro.data.DrawerItem
|
|
||||||
import mg.dot.feufaro.data.getDrawerItems
|
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.solfa.Solfa
|
||||||
import mg.dot.feufaro.viewmodel.SolfaScreenModel
|
import mg.dot.feufaro.viewmodel.SolfaScreenModel
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -266,6 +252,9 @@ LaunchedEffect(isPlay, isPos) {
|
||||||
sharedScreenModel.setVolume(newVolume)
|
sharedScreenModel.setVolume(newVolume)
|
||||||
println("Changement volume $newVolume -l $volumelevel")
|
println("Changement volume $newVolume -l $volumelevel")
|
||||||
},
|
},
|
||||||
|
onVoiceVolumeChange = { index, volume ->
|
||||||
|
player?.updateVoiceVolume(index, volume)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Text("Sélectionner un morceau")
|
Text("Sélectionner un morceau")
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
package mg.dot.feufaro.ui
|
package mg.dot.feufaro.ui
|
||||||
|
|
||||||
import androidx.compose.animation.*
|
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.LinearEasing
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.ScrollState
|
import androidx.compose.foundation.ScrollState
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
|
@ -20,13 +21,20 @@ import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.draw.paint
|
||||||
import androidx.compose.ui.graphics.Color
|
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.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import feufaro.composeapp.generated.resources.Res
|
import feufaro.composeapp.generated.resources.Res
|
||||||
import feufaro.composeapp.generated.resources.ic_mixer_satb
|
import feufaro.composeapp.generated.resources.ic_mixer_satb
|
||||||
import feufaro.composeapp.generated.resources.ic_organ
|
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 kotlinx.coroutines.delay
|
||||||
import mg.dot.feufaro.getPlatform
|
import mg.dot.feufaro.getPlatform
|
||||||
import mg.dot.feufaro.midi.FMediaPlayer
|
import mg.dot.feufaro.midi.FMediaPlayer
|
||||||
|
|
@ -43,6 +51,7 @@ fun MidiControlPanel(
|
||||||
onPlayPauseClick: () -> Unit,
|
onPlayPauseClick: () -> Unit,
|
||||||
onSeek: (Float) -> Unit,
|
onSeek: (Float) -> Unit,
|
||||||
onVolumeChange: (Float) -> Unit,
|
onVolumeChange: (Float) -> Unit,
|
||||||
|
onVoiceVolumeChange: (voiceIndex: Int, newVolume: Float) -> Unit,
|
||||||
mediaPlayer: FMediaPlayer,
|
mediaPlayer: FMediaPlayer,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
|
|
@ -56,6 +65,9 @@ fun MidiControlPanel(
|
||||||
}
|
}
|
||||||
|
|
||||||
val voiceStates = mediaPlayer.getVoiceStates()
|
val voiceStates = mediaPlayer.getVoiceStates()
|
||||||
|
val sliderVolumes = remember {
|
||||||
|
mutableStateListOf(127f, 127f, 127f, 127f)
|
||||||
|
}
|
||||||
val labels = listOf("S", "A", "T", "B")
|
val labels = listOf("S", "A", "T", "B")
|
||||||
listOf("Soprano", "Alto", "Ténor", "Basse")
|
listOf("Soprano", "Alto", "Ténor", "Basse")
|
||||||
|
|
||||||
|
|
@ -168,11 +180,61 @@ fun MidiControlPanel(
|
||||||
enter = fadeIn() + scaleIn() + slideInVertically { it / 2 },
|
enter = fadeIn() + scaleIn() + slideInVertically { it / 2 },
|
||||||
exit = fadeOut() + scaleOut() + slideOutVertically { it / 2 }
|
exit = fadeOut() + scaleOut() + slideOutVertically { it / 2 }
|
||||||
) {
|
) {
|
||||||
Row {
|
Row(
|
||||||
Column(
|
modifier = Modifier
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
.height(100.dp)
|
||||||
) {
|
.widthIn(max = 250.dp)
|
||||||
Row(
|
.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),
|
modifier = Modifier.padding(vertical = 8.dp),
|
||||||
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
||||||
) {
|
) {
|
||||||
|
|
@ -187,8 +249,7 @@ fun MidiControlPanel(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,6 @@
|
||||||
package mg.dot.feufaro.midi
|
package mg.dot.feufaro.midi
|
||||||
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.*
|
||||||
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 mg.dot.feufaro.getConfigDirectoryPath
|
import mg.dot.feufaro.getConfigDirectoryPath
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
@ -40,7 +32,7 @@ actual class FMediaPlayer actual constructor(
|
||||||
private var isLoopingAB: Boolean = false
|
private var isLoopingAB: Boolean = false
|
||||||
|
|
||||||
private val voiceStates = mutableListOf(true, true, true, true)
|
private val voiceStates = mutableListOf(true, true, true, true)
|
||||||
|
private val voiceVolumes = FloatArray(4) { 127f }
|
||||||
private var currentGlobalVolume: Float = 0.8f
|
private var currentGlobalVolume: Float = 0.8f
|
||||||
|
|
||||||
private var currentTempo: Float = 1.0f
|
private var currentTempo: Float = 1.0f
|
||||||
|
|
@ -170,23 +162,34 @@ actual class FMediaPlayer actual constructor(
|
||||||
saveVoiceStates()
|
saveVoiceStates()
|
||||||
applyVoiceStates()
|
applyVoiceStates()
|
||||||
}
|
}
|
||||||
|
actual fun updateVoiceVolume(voiceIndex: Int, newVolume: Float) {
|
||||||
|
if (voiceIndex in 0..3) {
|
||||||
|
voiceVolumes[voiceIndex] = newVolume
|
||||||
|
applyVoiceStates()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun applyVoiceStates() {
|
private fun applyVoiceStates() {
|
||||||
try {
|
try {
|
||||||
synthetizer?.channels?.let { channels ->
|
synthetizer?.channels?.let { channels ->
|
||||||
for (i in 0 until 4) {
|
for (i in 0 until 4) {
|
||||||
if (i < channels.size) {
|
if (i < channels.size) {
|
||||||
val isVoiceActive = voiceStates[i]
|
val volume = voiceVolumes[i].toInt()
|
||||||
val volume = if (voiceStates[i]) 127 else 0
|
val isVoiceActive = voiceStates[i]
|
||||||
channels[i].controlChange(7, volume)
|
val currentVolume = voiceVolumes[i].toInt()
|
||||||
channels[i].controlChange(11, volume)
|
|
||||||
if(!isVoiceActive) {
|
if (volume == 0) {
|
||||||
channels[i].controlChange(123, 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() }
|
} catch (e: Exception) { e.printStackTrace() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue