Android MIDI应用发送Bulk Dump消息时出现丢字节或拆分问题求助
Android MIDI Bulk Dump 发送完整性问题解决
问题分析
你遇到的核心问题是Android android.media.midi API发送大尺寸SysEx Bulk Dump时的碎片化/丢失问题,原因主要有三点:
- 连续异步调用
send()导致数据积压,底层USB MIDI缓冲区溢出或数据被错误合并; - 过小的分块(3字节)导致频繁发送请求,超出了USB MIDI接口的处理能力;
- Roland UM-ONE这类USB MIDI设备对数据包大小有MTU限制,非标准分块容易触发传输异常。
解决方案
1. 采用USB MIDI标准分块大小
USB MIDI的标准数据包大小为64字节,按这个尺寸分块发送,能匹配硬件的传输逻辑,减少碎片化:
val inputPort: MidiInputPort val handler = Handler(Looper.getMainLooper()) fun sendBulkDump(data: ByteArray) { var bytesSent = 0 val chunkSize = 64 // 匹配USB MIDI标准MTU fun sendNextChunk() { if (bytesSent >= data.size) return val remaining = data.size - bytesSent val currentChunkSize = min(remaining, chunkSize) val buffer = ByteArray(currentChunkSize) System.arraycopy(data, bytesSent, buffer, 0, currentChunkSize) inputPort.send(buffer, 0, currentChunkSize) bytesSent += currentChunkSize // 延迟确保前一块完成传输(MIDI传输速率31250bps,64字节约需16ms,留冗余) handler.postDelayed({ sendNextChunk() }, 20) } sendNextChunk() }
2. 避免并发MIDI消息发送
确保发送Bulk Dump期间,没有其他MIDI消息(如音符、CC参数)同时发送,否则会抢占传输带宽,导致Bulk Dump数据被截断。
3. 验证硬件与监听工具设置
- 检查Roland UM-ONE的固件是否为最新版本,部分旧固件存在SysEx传输Bug;
- 确认监听工具的接收缓冲区足够大,避免因缓冲区溢出丢失数据;
- 确保手机USB模式设置为MIDI设备,而非文件传输或充电模式。
4. 强制SysEx消息边界校验
虽然你已确认无错误的0xf0/0xf7,但可以在发送前再次验证:
fun validateSysEx(data: ByteArray): Boolean { return data.isNotEmpty() && data[0] == 0xF0.toByte() && data.last() == 0xF7.toByte() }
发送前调用该方法,确保Bulk Dump是合法的SysEx消息。
关键注意事项
- 不要使用
timeStamp参数来控制间隔,该参数用于同步MIDI事件的播放时间,而非传输间隔; - 分块大小不要小于16字节,过小的分块会导致底层USB驱动频繁切换状态,增加传输错误概率;
- 如果问题仍存在,可尝试将分块大小调整为32字节,部分设备对32字节数据包兼容性更好。
内容的提问来源于stack exchange,提问作者subhouse07
相关产品推荐
相关产品推荐

