Compare commits
4 commits
2f0be71dd8
...
7c1f920ae8
| Author | SHA1 | Date | |
|---|---|---|---|
| 7c1f920ae8 | |||
| 01d44d6b42 | |||
| 6dd58b8bb3 | |||
| d25753aee4 |
5 changed files with 215 additions and 110 deletions
|
|
@ -2,8 +2,19 @@ package mg.dot.feufaro
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import org.koin.core.context.GlobalContext
|
import org.koin.core.context.GlobalContext
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
actual fun getConfigDirectoryPath(): String {
|
actual fun getConfigDirectoryPath(): String {
|
||||||
val context = GlobalContext.get().get<Context>()
|
val baseDir = GlobalContext.get().get<Context>().filesDir
|
||||||
return context.filesDir.absolutePath
|
val feufa2Folder = File(baseDir, "Feufaro")
|
||||||
|
|
||||||
|
if (!feufa2Folder.exists()) {
|
||||||
|
val created = feufa2Folder.mkdirs()
|
||||||
|
if (created) {
|
||||||
|
println("CP:15: Dossier créé avec succès : ${feufa2Folder.absolutePath}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val path = feufa2Folder.absolutePath
|
||||||
|
return if (path.endsWith(File.separator)) path else path + File.separator
|
||||||
}
|
}
|
||||||
|
|
@ -1,129 +1,142 @@
|
||||||
package mg.dot.feufaro.midi
|
package mg.dot.feufaro.midi
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
import android.media.MediaPlayer
|
import android.media.MediaPlayer
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
import kotlinx.coroutines.cancel
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileInputStream
|
||||||
|
|
||||||
private var androidMediaPlayer: MediaPlayer?= null
|
private var androidMediaPlayer: MediaPlayer?= null
|
||||||
|
|
||||||
actual class MediaPlayer actual constructor(filename: String, onFinished: () -> Unit) {
|
actual class MediaPlayer actual constructor(filename: String, onFinished: () -> Unit) {
|
||||||
private val player = androidMediaPlayer?.apply {
|
private var mediaPlayer: MediaPlayer? = MediaPlayer()
|
||||||
setDataSource(filename)
|
|
||||||
prepare()
|
|
||||||
setOnCompletionListener {
|
|
||||||
seekTo(0)
|
|
||||||
onFinished()
|
|
||||||
}
|
|
||||||
// val file = File(android.app.Instrumentation().context.filesDir, filename)
|
|
||||||
// if(file.exists()){
|
|
||||||
// androidMediaPlayer?.setDataSource(file.path)
|
|
||||||
// androidMediaPlayer?.prepare()
|
|
||||||
// androidMediaPlayer?.setOnCompletionListener {
|
|
||||||
// onFinished()
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// println("Fichier midi non trouvée")
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
private val voiceStates = mutableListOf(true, true, true, true)
|
private val voiceStates = mutableListOf(true, true, true, true)
|
||||||
private var currentGlobalVolume: Float = 0.8f
|
// private var currentGlobalVolume: Float = 0.8f
|
||||||
|
|
||||||
private var pointA: Long = -1L
|
private var pointA: Long = -1L
|
||||||
private var pointB: Long = -1L
|
private var pointB: Long = -1L
|
||||||
|
|
||||||
|
private val playerScope = CoroutineScope(Dispatchers.Default + SupervisorJob())
|
||||||
|
private var abJob: Job? = null
|
||||||
|
|
||||||
private var isLoopingAB: Boolean = false
|
private var isLoopingAB: Boolean = false
|
||||||
|
|
||||||
|
init {
|
||||||
|
try {
|
||||||
|
val file = File(filename)
|
||||||
|
if (file.exists()) {
|
||||||
|
val fis = FileInputStream(file)
|
||||||
|
mediaPlayer?.setDataSource(fis.fd)
|
||||||
|
mediaPlayer?.prepare()
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
|
||||||
|
val params = mediaPlayer?.playbackParams ?: android.media.PlaybackParams()
|
||||||
|
params.speed = 1.0f
|
||||||
|
mediaPlayer?.playbackParams = params
|
||||||
|
}
|
||||||
|
fis.close()
|
||||||
|
|
||||||
|
mediaPlayer?.setOnCompletionListener {
|
||||||
|
onFinished()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
actual fun play() {
|
actual fun play() {
|
||||||
// player?.start()
|
mediaPlayer?.start()
|
||||||
}
|
}
|
||||||
actual fun pause() {
|
actual fun pause() {
|
||||||
// player?.pause()
|
mediaPlayer?.pause()
|
||||||
}
|
}
|
||||||
actual fun stop() {
|
actual fun stop() {
|
||||||
// player?.stop()
|
mediaPlayer?.stop()
|
||||||
|
mediaPlayer?.prepare()
|
||||||
|
mediaPlayer?.seekTo(0)
|
||||||
|
clearLoop()
|
||||||
}
|
}
|
||||||
|
|
||||||
actual fun getDuration(): Long {
|
actual fun getDuration(): Long {
|
||||||
// player!!.duration.toLong() ?: 0L
|
return mediaPlayer?.duration?.toLong() ?: 0L
|
||||||
return 4.toLong()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
actual fun getCurrentPosition(): Long {
|
actual fun getCurrentPosition(): Long {
|
||||||
// player!!.currentPosition.toLong()
|
return mediaPlayer?.currentPosition?.toLong() ?: 0L
|
||||||
return 4.toLong()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
actual fun seekTo(position: Long) {
|
actual fun seekTo(position: Long) {
|
||||||
// player!!.seekTo(position.toInt())
|
mediaPlayer?.seekTo(position.toInt())
|
||||||
|
}
|
||||||
|
actual fun setVolume(level: Float) {
|
||||||
|
mediaPlayer?.setVolume(level, level)
|
||||||
}
|
}
|
||||||
|
|
||||||
actual fun setVolume(level: Float){
|
actual fun setPointA() {
|
||||||
// currentGlobalVolume =level
|
pointA = mediaPlayer?.currentPosition?.toLong() ?: 0L
|
||||||
// player?.setVolume(level, level)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
actual fun getLoopState() = Triple(pointA, pointB, isLoopingAB)
|
actual fun setPointB() {
|
||||||
|
pointB = mediaPlayer?.currentPosition?.toLong() ?: 0L
|
||||||
actual fun toggleVoice(index: Int): Unit{
|
if (pointB > pointA && pointA != -1L) {
|
||||||
voiceStates[index] = !voiceStates[index]
|
|
||||||
}
|
|
||||||
|
|
||||||
actual fun getVoiceStates(): List<Boolean> = voiceStates
|
|
||||||
|
|
||||||
actual fun changeInstru(noInstru: Int): Unit{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
actual fun setPointA(): Unit{
|
|
||||||
// pointA = getCurrentPosition()
|
|
||||||
}
|
|
||||||
|
|
||||||
actual fun setPointB(): Unit{
|
|
||||||
pointB = getCurrentPosition()
|
|
||||||
if(pointB > pointA) {
|
|
||||||
isLoopingAB = true
|
isLoopingAB = true
|
||||||
startABMonitor()
|
startABMonitor()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actual fun clearLoop(): Unit{
|
actual fun clearLoop() {
|
||||||
isLoopingAB = false
|
isLoopingAB = false
|
||||||
|
pointA = -1L
|
||||||
|
pointB = -1L
|
||||||
|
abJob?.cancel()
|
||||||
}
|
}
|
||||||
private fun startABMonitor(){
|
|
||||||
GlobalScope.launch {
|
private fun startABMonitor() {
|
||||||
while(isLoopingAB){
|
abJob?.cancel()
|
||||||
// if ((player?.currentPosition ?: 0) >= pointB){
|
abJob = playerScope.launch {
|
||||||
// player?.seekTo(pointA?.toInt())
|
while (isLoopingAB) {
|
||||||
// }
|
val currentPos = mediaPlayer?.currentPosition?.toLong() ?: 0L
|
||||||
|
if (currentPos >= pointB) {
|
||||||
|
mediaPlayer?.seekTo(pointA.toInt())
|
||||||
|
}
|
||||||
delay(50)
|
delay(50)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
actual fun setTempo(factor: Float){
|
|
||||||
|
|
||||||
|
actual fun getLoopState() = Triple(pointA, pointB, isLoopingAB)
|
||||||
|
actual fun toggleVoice(index: Int) {
|
||||||
|
voiceStates[index] = !voiceStates[index]
|
||||||
|
println("Toggle voice $index (Limitation: Nécessite SoundFont/Fluidsynth sur Android)")
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun getVoiceStates(): List<Boolean> = voiceStates
|
||||||
|
|
||||||
|
actual fun changeInstru(noInstru: Int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun setTempo(factor: Float) {
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
|
||||||
|
mediaPlayer?.let {
|
||||||
|
val params = it.playbackParams
|
||||||
|
params.speed = factor
|
||||||
|
it.playbackParams = params
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actual fun getCurrentBPM(): Float {
|
actual fun getCurrentBPM(): Float {
|
||||||
return 120f
|
return 120f
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/*
|
|
||||||
actual fun MidiPlayer(filename: String, onFinished: () -> Unit) {
|
|
||||||
StopMidi()
|
|
||||||
val file = File(android.app.Instrumentation().context.filesDir, filename)
|
|
||||||
if(file.exists()){
|
|
||||||
androidMediaPlayer?.setDataSource(file.path)
|
|
||||||
androidMediaPlayer?.prepare()
|
|
||||||
androidMediaPlayer?.setOnCompletionListener {
|
|
||||||
onFinished()
|
|
||||||
}
|
|
||||||
androidMediaPlayer?.start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
actual fun StopMidi() {
|
fun release() {
|
||||||
androidMediaPlayer?.let {
|
mediaPlayer?.release()
|
||||||
if (it.isPlaying) {
|
mediaPlayer = null
|
||||||
it.stop()
|
playerScope.coroutineContext.cancel()
|
||||||
it.release()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
androidMediaPlayer = null
|
}
|
||||||
}*/
|
|
||||||
|
|
@ -34,6 +34,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.geometry.Offset
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.input.pointer.pointerInput
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
|
import androidx.compose.ui.layout.onGloballyPositioned
|
||||||
import androidx.compose.ui.text.font.FontStyle
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.IntOffset
|
import androidx.compose.ui.unit.IntOffset
|
||||||
|
|
@ -64,6 +65,7 @@ object ScreenSolfa : Screen {
|
||||||
val gridTUOData = GridTUOData(measure, tuoList, stanza)
|
val gridTUOData = GridTUOData(measure, tuoList, stanza)
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val scrollState = rememberScrollState()
|
val scrollState = rememberScrollState()
|
||||||
|
var viewportHeight by remember { mutableStateOf(0) }
|
||||||
|
|
||||||
var isScanning by remember { mutableStateOf(false) }
|
var isScanning by remember { mutableStateOf(false) }
|
||||||
var qrCodeResult by remember { mutableStateOf("Aucun code scanné") }
|
var qrCodeResult by remember { mutableStateOf("Aucun code scanné") }
|
||||||
|
|
@ -75,7 +77,8 @@ object ScreenSolfa : Screen {
|
||||||
qrCodeResult = qrCodeResult,
|
qrCodeResult = qrCodeResult,
|
||||||
onScannerButtonClick = {
|
onScannerButtonClick = {
|
||||||
isScanning = true
|
isScanning = true
|
||||||
}
|
},
|
||||||
|
solfaScrollState = scrollState
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
Box(
|
Box(
|
||||||
Modifier.fillMaxSize().padding(paddingValues)
|
Modifier.fillMaxSize().padding(paddingValues)
|
||||||
|
|
@ -91,6 +94,9 @@ object ScreenSolfa : Screen {
|
||||||
showContextualMenu = true
|
showContextualMenu = true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
.onGloballyPositioned { coordinates ->
|
||||||
|
viewportHeight = coordinates.size.height
|
||||||
},
|
},
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
|
|
@ -192,7 +198,7 @@ object ScreenSolfa : Screen {
|
||||||
}
|
}
|
||||||
Row (
|
Row (
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.height(199.dp)
|
.height(75.dp)
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ fun MainScreenWithDrawer(
|
||||||
sharedScreenModel: SharedScreenModel,
|
sharedScreenModel: SharedScreenModel,
|
||||||
qrCodeResult: String,
|
qrCodeResult: String,
|
||||||
onScannerButtonClick: () -> Unit,
|
onScannerButtonClick: () -> Unit,
|
||||||
|
solfaScrollState: ScrollState,
|
||||||
content: @Composable (PaddingValues) -> Unit,
|
content: @Composable (PaddingValues) -> Unit,
|
||||||
) {
|
) {
|
||||||
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
|
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
|
||||||
|
|
@ -79,7 +80,7 @@ val isPos by sharedScreenModel.isPos.collectAsState()
|
||||||
var isDragging = sharedScreenModel.isDragging
|
var isDragging = sharedScreenModel.isDragging
|
||||||
val currentPos by sharedScreenModel.currentPos.collectAsState()
|
val currentPos by sharedScreenModel.currentPos.collectAsState()
|
||||||
val duration by sharedScreenModel.duration.collectAsState()
|
val duration by sharedScreenModel.duration.collectAsState()
|
||||||
val midiFile = "whawyd3.mid"
|
val midiFile = "whawyd3.mid" //What do we gain by all our hard work?
|
||||||
var refreshTrigeer by remember { mutableStateOf(0)}
|
var refreshTrigeer by remember { mutableStateOf(0)}
|
||||||
|
|
||||||
val volumelevel by sharedScreenModel.volumeLevel.collectAsState()
|
val volumelevel by sharedScreenModel.volumeLevel.collectAsState()
|
||||||
|
|
@ -248,6 +249,7 @@ LaunchedEffect(isPlay, isPos) {
|
||||||
currentPos = currentPos,
|
currentPos = currentPos,
|
||||||
volume = volumelevel,
|
volume = volumelevel,
|
||||||
duration = duration,
|
duration = duration,
|
||||||
|
solfaScrollState,
|
||||||
onPlayPauseClick = {
|
onPlayPauseClick = {
|
||||||
sharedScreenModel.togglePlayPause()
|
sharedScreenModel.togglePlayPause()
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
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.tween
|
||||||
|
import androidx.compose.foundation.ScrollState
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
|
|
@ -34,6 +39,7 @@ fun MidiControlPanel(
|
||||||
currentPos: Float,
|
currentPos: Float,
|
||||||
volume: Float,
|
volume: Float,
|
||||||
duration: Float,
|
duration: Float,
|
||||||
|
solfaScrollState: ScrollState,
|
||||||
onPlayPauseClick: () -> Unit,
|
onPlayPauseClick: () -> Unit,
|
||||||
onSeek: (Float) -> Unit,
|
onSeek: (Float) -> Unit,
|
||||||
onVolumeChange: (Float) -> Unit,
|
onVolumeChange: (Float) -> Unit,
|
||||||
|
|
@ -61,6 +67,26 @@ fun MidiControlPanel(
|
||||||
|
|
||||||
var showSATBTools by remember { mutableStateOf(false) }
|
var showSATBTools by remember { mutableStateOf(false) }
|
||||||
var expandedCtl by remember { mutableStateOf(false) }
|
var expandedCtl by remember { mutableStateOf(false) }
|
||||||
|
val platform = getPlatform().name
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
LaunchedEffect(currentPos, duration, solfaScrollState.viewportSize, solfaScrollState.maxValue) {
|
||||||
|
if (duration > 0f && solfaScrollState.maxValue > 0) {
|
||||||
|
val progress = (currentPos / duration).coerceIn(0f, 1f)
|
||||||
|
val viewportHeight = solfaScrollState.viewportSize.toFloat()
|
||||||
|
val totalContentHeight = solfaScrollState.maxValue + viewportHeight
|
||||||
|
|
||||||
|
val targetY = (progress * (totalContentHeight-200)) - (viewportHeight / 2)
|
||||||
|
val finalTarget = targetY.coerceIn(0f, solfaScrollState.maxValue.toFloat())
|
||||||
|
solfaScrollState.animateScrollTo(
|
||||||
|
value = finalTarget.toInt(),
|
||||||
|
animationSpec = tween (
|
||||||
|
durationMillis = 300,
|
||||||
|
easing = LinearEasing
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
LaunchedEffect(tempo) {
|
LaunchedEffect(tempo) {
|
||||||
currentBpm = mediaPlayer.getCurrentBPM()
|
currentBpm = mediaPlayer.getCurrentBPM()
|
||||||
}
|
}
|
||||||
|
|
@ -79,7 +105,7 @@ fun MidiControlPanel(
|
||||||
|
|
||||||
tempo = newFactor
|
tempo = newFactor
|
||||||
mediaPlayer?.setTempo(newFactor)
|
mediaPlayer?.setTempo(newFactor)
|
||||||
println("tempo : $tempo")
|
// println("tempo : $tempo")
|
||||||
}
|
}
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
|
@ -91,8 +117,7 @@ fun MidiControlPanel(
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxWidth(if (getPlatform().name.startsWith("Android")) 0.9f else 0.6f)
|
.fillMaxWidth(if (platform.startsWith("Android")) 1f else 0.6f)
|
||||||
.padding(16.dp)
|
|
||||||
.background(color = Color.Gray.copy(alpha = 0.5f), shape = RoundedCornerShape(size = 5.dp)),
|
.background(color = Color.Gray.copy(alpha = 0.5f), shape = RoundedCornerShape(size = 5.dp)),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
|
|
@ -214,7 +239,7 @@ fun MidiControlPanel(
|
||||||
slideInHorizontally { -it } + fadeIn() togetherWith slideOutHorizontally { it } + fadeOut()
|
slideInHorizontally { -it } + fadeIn() togetherWith slideOutHorizontally { it } + fadeOut()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
modifier = Modifier.padding(horizontal = 4.dp)
|
modifier = Modifier.padding(horizontal = 2.dp)
|
||||||
) { displayedBpm ->
|
) { displayedBpm ->
|
||||||
val isCenter = displayedBpm == currentBpmInt
|
val isCenter = displayedBpm == currentBpmInt
|
||||||
Text(
|
Text(
|
||||||
|
|
@ -225,7 +250,7 @@ fun MidiControlPanel(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clip(CircleShape)
|
.clip(CircleShape)
|
||||||
.clickable(enabled = !isCenter) { updateTempoToBpm(displayedBpm) }
|
.clickable(enabled = !isCenter) { updateTempoToBpm(displayedBpm) }
|
||||||
.padding(horizontal = 4.dp)
|
.padding(horizontal = 2.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -333,7 +358,26 @@ fun MidiControlPanel(
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
|
||||||
Column {
|
if(platform.startsWith("Android")) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.wrapContentWidth(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
IconButton(
|
||||||
|
onClick = onPlayPauseClick,
|
||||||
|
modifier = Modifier.size(48.dp).background(MaterialTheme.colorScheme.primary, CircleShape)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = if (isPause) Icons.Filled.PlayArrow else Icons.Filled.Pause,
|
||||||
|
contentDescription = "Pla",
|
||||||
|
tint = Color.White
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
|
||||||
|
Column {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
isPianoSelected = !isPianoSelected
|
isPianoSelected = !isPianoSelected
|
||||||
|
|
@ -361,29 +405,58 @@ fun MidiControlPanel(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Column {
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
isPianoSelected = !isPianoSelected
|
||||||
|
if (isPianoSelected) {
|
||||||
|
mediaPlayer?.changeInstru(1)
|
||||||
|
} else {
|
||||||
|
mediaPlayer?.changeInstru(20)
|
||||||
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
}
|
||||||
|
) {
|
||||||
Column(
|
if (isPianoSelected) {
|
||||||
modifier = Modifier.wrapContentWidth(),
|
Icon(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
Icons.Default.Piano,
|
||||||
) {
|
contentDescription = "Piano",
|
||||||
IconButton(
|
tint = Color.Black
|
||||||
onClick = onPlayPauseClick,
|
)
|
||||||
modifier = Modifier.size(48.dp).background(MaterialTheme.colorScheme.primary, CircleShape)
|
} else {
|
||||||
) {
|
Icon(
|
||||||
Icon(
|
painter = painterResource(Res.drawable.ic_organ),
|
||||||
imageVector = if (isPause) Icons.Filled.PlayArrow else Icons.Filled.Pause,
|
contentDescription = "Orgue",
|
||||||
contentDescription = "Pla",
|
tint = Color.Black,
|
||||||
tint = Color.White
|
modifier = Modifier.size(25.dp)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.wrapContentWidth(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
IconButton(
|
||||||
|
onClick = onPlayPauseClick,
|
||||||
|
modifier = Modifier.size(48.dp).background(MaterialTheme.colorScheme.primary, CircleShape)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = if (isPause) Icons.Filled.PlayArrow else Icons.Filled.Pause,
|
||||||
|
contentDescription = "Pla",
|
||||||
|
tint = Color.White
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
|
||||||
val platform = getPlatform()
|
if (platform.startsWith("Java")) {
|
||||||
if (platform.name.startsWith("Java")) {
|
|
||||||
ModernVolumeSlider(
|
ModernVolumeSlider(
|
||||||
volume, onVolumeChange = onVolumeChange
|
volume, onVolumeChange = onVolumeChange
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue