implement MidiPlayer for android

This commit is contained in:
hasinarak3@gmail.com 2026-02-06 09:51:33 +03:00
parent 2f0be71dd8
commit d25753aee4

View file

@ -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() {
abJob?.cancel()
abJob = playerScope.launch {
while (isLoopingAB) {
val currentPos = mediaPlayer?.currentPosition?.toLong() ?: 0L
if (currentPos >= pointB) {
mediaPlayer?.seekTo(pointA.toInt())
} }
private fun startABMonitor(){
GlobalScope.launch {
while(isLoopingAB){
// if ((player?.currentPosition ?: 0) >= pointB){
// player?.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
}*/