Remember volume per voices [satb] - for desktop

This commit is contained in:
hasinarak3@gmail.com 2026-02-18 10:44:24 +03:00
parent 84a9626b08
commit e6af7bd39e
4 changed files with 33 additions and 56 deletions

View file

@ -15,7 +15,7 @@ private var androidMediaPlayer: MediaPlayer?= null
actual class FMediaPlayer actual constructor(val filename: String, onFinished: () -> Unit) { actual class FMediaPlayer actual constructor(val filename: String, onFinished: () -> Unit) {
private var mediaPlayer: android.media.MediaPlayer? = android.media.MediaPlayer() private var mediaPlayer: android.media.MediaPlayer? = android.media.MediaPlayer()
private val voiceStates = mutableListOf(true, true, true, true) // private val voiceStates = mutableListOf(true, true, true, true)
private val midiFileName = filename private val midiFileName = filename
// private var currentGlobalVolume: Float = 0.8f // private var currentGlobalVolume: Float = 0.8f
@ -132,11 +132,12 @@ actual fun setVolume(level: Float) {
actual fun getLoopState() = Triple(pointA, pointB, isLoopingAB) actual fun getLoopState() = Triple(pointA, pointB, isLoopingAB)
actual fun toggleVoice(index: Int) { actual fun toggleVoice(index: Int) {
voiceStates[index] = !voiceStates[index] // voiceStates[index] = !voiceStates[index]
println("Toggle voice $index (Limitation: Nécessite SoundFont/Fluidsynth sur Android)") println("Toggle voice $index (Limitation: Nécessite SoundFont/Fluidsynth sur Android)")
} }
actual fun getVoiceStates(): List<Boolean> = voiceStates // actual fun getVoiceStates(): List<Boolean> = voiceStates
actual fun getVoiceVolumes(): List<Float> = MutableList(4) { 127f }
actual fun changeInstru(noInstru: Int) { actual fun changeInstru(noInstru: Int) {
} }

View file

@ -9,7 +9,7 @@ expect class FMediaPlayer(filename: String, onFinished: () -> Unit) {
fun getDuration(): Long fun getDuration(): Long
fun getLoopState(): Triple<Long, Long, Boolean> fun getLoopState(): Triple<Long, Long, Boolean>
fun toggleVoice(index: Int) fun toggleVoice(index: Int)
fun getVoiceStates(): List<Boolean> fun getVoiceVolumes(): List<Float>
fun changeInstru(noInstru: Int) fun changeInstru(noInstru: Int)
fun getCurrentPosition(): Long fun getCurrentPosition(): Long
fun seekTo(position: Long) fun seekTo(position: Long)

View file

@ -64,9 +64,8 @@ fun MidiControlPanel(
} }
} }
val voiceStates = mediaPlayer.getVoiceStates()
val sliderVolumes = remember { val sliderVolumes = remember {
mutableStateListOf(127f, 127f, 127f, 127f) mediaPlayer.getVoiceVolumes().map { mutableStateOf(it) }.toMutableStateList()
} }
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")
@ -201,9 +200,9 @@ fun MidiControlPanel(
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
Slider( Slider(
value = sliderVolumes[i], value = sliderVolumes[i].value,
onValueChange = { newValue -> onValueChange = { newValue ->
sliderVolumes[i] = newValue sliderVolumes[i].value = newValue
mediaPlayer.updateVoiceVolume(i, newValue) mediaPlayer.updateVoiceVolume(i, newValue)
}, },
valueRange = 0f..126f, valueRange = 0f..126f,
@ -234,22 +233,6 @@ fun MidiControlPanel(
) )
} }
} }
/*Row(
modifier = Modifier.padding(vertical = 8.dp),
horizontalArrangement = Arrangement.spacedBy(4.dp)
) {
labels.forEachIndexed { index, label ->
FilterChip(
selected = voiceStates[index],
onClick = { mediaPlayer.toggleVoice(index) },
label = { Text(label) },
colors = FilterChipDefaults.filterChipColors(
selectedContainerColor = MaterialTheme.colorScheme.primaryContainer,
selectedLabelColor = MaterialTheme.colorScheme.primary
)
)
}
}*/
} }
} }
AnimatedVisibility( AnimatedVisibility(

View file

@ -2,13 +2,11 @@ package mg.dot.feufaro.midi
import kotlinx.coroutines.* import kotlinx.coroutines.*
import mg.dot.feufaro.getConfigDirectoryPath import mg.dot.feufaro.getConfigDirectoryPath
import java.io.ByteArrayInputStream
import java.io.File import java.io.File
import java.util.prefs.Preferences import java.util.prefs.Preferences
import javax.sound.midi.MidiSystem import javax.sound.midi.MidiSystem
import javax.sound.midi.Sequencer import javax.sound.midi.Sequencer
import javax.sound.midi.Synthesizer import javax.sound.midi.Synthesizer
import javax.sound.sampled.AudioFormat
import javax.sound.sampled.AudioSystem import javax.sound.sampled.AudioSystem
import javax.sound.sampled.FloatControl import javax.sound.sampled.FloatControl
@ -31,7 +29,6 @@ actual class FMediaPlayer actual constructor(
private var pointB: Long = -1L private var pointB: Long = -1L
private var isLoopingAB: Boolean = false private var isLoopingAB: Boolean = false
private val voiceStates = mutableListOf(true, true, true, true)
private val voiceVolumes = FloatArray(4) { 127f } private val voiceVolumes = FloatArray(4) { 127f }
private var currentGlobalVolume: Float = 0.8f private var currentGlobalVolume: Float = 0.8f
@ -53,7 +50,7 @@ actual class FMediaPlayer actual constructor(
val file = File(filename) val file = File(filename)
if (file.exists()){ if (file.exists()){
sequencer?.sequence = MidiSystem.getSequence(file) sequencer?.sequence = MidiSystem.getSequence(file)
loadVoiceStates() loadVoiceVolumes()
applyVoiceStates() applyVoiceStates()
sequencer?.addMetaEventListener { meta -> sequencer?.addMetaEventListener { meta ->
if(meta.type == 47){ if(meta.type == 47){
@ -103,7 +100,7 @@ actual class FMediaPlayer actual constructor(
synthetizer?.channels?.forEachIndexed { index, channel -> synthetizer?.channels?.forEachIndexed { index, channel ->
if (index < 4) { if (index < 4) {
val vol = if (voiceStates[index]) volumeInt else 0 val vol = if (voiceVolumes[index] != 0f) volumeInt else 0
channel?.controlChange(7, vol) channel?.controlChange(7, vol)
} else { } else {
channel?.controlChange(7, volumeInt) channel?.controlChange(7, volumeInt)
@ -158,13 +155,13 @@ actual class FMediaPlayer actual constructor(
actual fun getLoopState() = Triple(pointA, pointB, isLoopingAB) actual fun getLoopState() = Triple(pointA, pointB, isLoopingAB)
actual fun toggleVoice(index: Int) { actual fun toggleVoice(index: Int) {
voiceStates[index] = !voiceStates[index] saveVoicesVolumes()
saveVoiceStates()
applyVoiceStates() applyVoiceStates()
} }
actual fun updateVoiceVolume(voiceIndex: Int, newVolume: Float) { actual fun updateVoiceVolume(voiceIndex: Int, newVolume: Float) {
if (voiceIndex in 0..3) { if (voiceIndex in 0..3) {
voiceVolumes[voiceIndex] = newVolume voiceVolumes[voiceIndex] = newVolume
saveVoicesVolumes()
applyVoiceStates() applyVoiceStates()
} }
} }
@ -172,28 +169,24 @@ actual class FMediaPlayer actual constructor(
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 volume = voiceVolumes[i].toInt() val targetVolume = voiceVolumes[i].toInt()
val isVoiceActive = voiceStates[i]
val currentVolume = voiceVolumes[i].toInt()
if (volume == 0) { channels[i].controlChange(7, targetVolume)
channels[i].controlChange(123, 0) channels[i].controlChange(11, targetVolume)
voiceStates[i] = false
} else { if (targetVolume == 0) {
channels[i].controlChange(7, currentVolume) channels[i].controlChange(123, 0)
channels[i].controlChange(11, currentVolume) }
voiceStates[i] = true
} }
println("SATB $i Volumes: ${voiceVolumes[i]}")
} }
println("SATB màj: $voiceStates, Volumes: ${voiceVolumes[i]}")
} }
}
} catch (e: Exception) { e.printStackTrace() } } catch (e: Exception) { e.printStackTrace() }
} }
actual fun getVoiceStates(): List<Boolean> = voiceStates actual fun getVoiceVolumes(): List<Float> = voiceVolumes.toList()
actual fun changeInstru(noInstru: Int) { actual fun changeInstru(noInstru: Int) {
val pgm = noInstru val pgm = noInstru
@ -230,19 +223,19 @@ actual class FMediaPlayer actual constructor(
} }
} }
private fun saveVoiceStates() { private fun saveVoicesVolumes() {
val data = voiceStates.joinToString(",") val data = voiceVolumes.joinToString(",")
prefs.put("voice_states", data) prefs.put("voices_volumes", data)
} }
private fun loadVoiceStates() { private fun loadVoiceVolumes() {
val defaultValue = "true,true,true,true" val data = prefs.get("voices_volumes", "127,127,127,127")
val savedData = prefs.get("voice_states", defaultValue) val volumesArray = data.split(",")
val states = savedData.split(",").map { it.toBoolean() } if (volumesArray.size == 4) {
for (i in 0 until 4) { for (i in 0 until 4) {
if (i < states.size) voiceStates[i] = states[i] voiceVolumes[i] = volumesArray[i].toFloatOrNull() ?: 127f
}
} }
} }
} }