如何在Android中播放MIDI文件单个声部的音符?
解决方案:过滤MIDI声部播放
MediaPlayer组件无法直接控制MIDI文件的声部播放,因为它是高层封装的播放组件,不暴露MIDI事件的精细控制接口。要实现仅播放单个声部的需求,需要解析MIDI文件并单独处理目标声部的音符事件,下面是具体的修改方案:
1. 添加MIDI解析依赖
在项目的app/build.gradle中添加第三方MIDI解析库(简化文件解析逻辑):
dependencies { implementation 'com.github.guichaguri:midi-player-android:2.1.0' }
2. 修改Activity播放逻辑
替换原有的MediaPlayer播放逻辑,改为解析MIDI文件并过滤指定声部的音符:
import android.media.AudioManager import android.media.SoundPool import android.os.Bundle import android.widget.Button import androidx.appcompat.app.AppCompatActivity import com.guichaguri.musicplayer.player.MidiPlayer import com.guichaguri.musicplayer.player.PlayerListener import java.io.InputStream class MidiPlayerActivity : AppCompatActivity() { private lateinit var soundPool: SoundPool private var midiPlayer: MidiPlayer? = null // 指定要播放的声部索引(示例为第0个声部,可根据你的MIDI文件调整) private val targetTrackIndex = 0 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_midi_player) soundPool = SoundPool(10, AudioManager.STREAM_MUSIC, 0) val playBtn = findViewById<Button>(R.id.play_btn) val stopBtn = findViewById<Button>(R.id.stop_btn) playBtn.setOnClickListener { playTargetTrackMidi() } stopBtn.setOnClickListener { stopMidiPlayback() } } private fun playTargetTrackMidi() { stopMidiPlayback() // 从assets加载MIDI文件 val inputStream: InputStream = assets.open("your_midi_file.mid") midiPlayer = MidiPlayer(this, soundPool).apply { // 设置仅播放指定声部 setTrackEnabled(targetTrackIndex, true) // 禁用其他所有声部 for (i in 0 until trackCount) { if (i != targetTrackIndex) setTrackEnabled(i, false) } setListener(object : PlayerListener { override fun onPlayingStart() {} override fun onPlayingEnd() { stopMidiPlayback() } override fun onError(message: String?) {} }) load(inputStream) play() } } private fun stopMidiPlayback() { midiPlayer?.stop() midiPlayer?.release() midiPlayer = null } override fun onDestroy() { super.onDestroy() stopMidiPlayback() soundPool.release() } }
3. 保留原有UI布局
你的原布局代码无需修改,只要确保按钮ID与Activity中的引用一致即可。
关键说明
- 声部索引从0开始,你可以根据MIDI文件的实际声部结构调整
targetTrackIndex的值(比如你的示例图中如果第一个声部是索引0,就用0) - 该方案通过
MidiPlayer库解析MIDI文件的各个轨道(声部),然后仅启用目标轨道的播放,其他轨道全部禁用,从而实现只播放单个声部的效果 - 如果你不想用第三方库,也可以自己解析MIDI文件的结构(读取MIDI轨道事件,过滤出目标声部的音符事件,再用SoundPool逐个播放),但第三方库已经封装了复杂的解析和播放逻辑,更高效稳定
内容的提问来源于stack exchange,提问作者macizett
相关产品推荐
相关产品推荐

