You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CoreMIDI蓝牙MIDI多键输入丢音问题(Swift代码排查)

蓝牙MIDI多键输入丢包问题(Mac端)
  • Mac桌面端通过蓝牙连接钢琴时,同时按下3-10个琴键会出现部分音符丢失的情况,iOS端暂未测试该问题是否可复现。
  • 确认问题出在Swift代码中:同一Mac上运行MIDI Monitor可捕获所有音符,但自己基于CoreMIDI实现的代码无法做到;使用USB线缆连接MIDI设备时无此问题。

我的Swift代码

var client = MIDIClientRef()
var inputPort = MIDIPortRef()
MIDIClientCreate("MIDI Input Client" as CFString, nil, nil, &client)

MIDIInputPortCreate(client, "MIDI Input Port" as CFString, { (packetListPointer,_, _) in

    let packets = packetListPointer.pointee
    var packet = packets.packet
    for _ in 0 ..< packets.numPackets {
        let bytes = Mirror(reflecting: packet.data).children.map { $0.value }
//        print("Received MIDI message: \(bytes)")

        // Extract the relevant bytes from the MIDI message
        let statusByte = Int(bytes[0] as! UInt8) // The status byte contains the message type
        let noteByte = Int(bytes[1] as! UInt8)// The note byte contains the MIDI note number

        // Check if the message is a note on or note off message
        let isNoteOn = (statusByte & 0xF0) == 0x90 // The status byte for a note on message starts with 0x90
        let isNoteOff = (statusByte & 0xF0) == 0x80 // The status byte for a note off message starts with 0x80

        if isNoteOn || isNoteOff {
            let noteNumber = Int(noteByte) // Convert the note byte to an integer
            let noteName = NoteName(forNoteNumber: noteNumber)
            let octave = noteNumber / 12 - 1 // Divide the note number by 12 and subtract 1 to get the octave
            let direction = isNoteOn ? "up" : "down" // If it's a note on message, the direction is "up". If it's a note off message, the direction is "down"
            print("Note: \(noteName)\(octave) \(direction)")
        }

        packet = MIDIPacketNext(&packet).pointee
    }
}, nil, &inputPort)

// Set up the MIDI input endpoint and connect it to the input port
let sourceCount = MIDIGetNumberOfSources()
for i in 0..<sourceCount {
    let src = MIDIGetSource(i)
    MIDIPortConnectSource(inputPort, src, nil)
}

func NoteName(forNoteNumber noteNumber: Int) -> String {
    let noteNames = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
    let noteIndex = noteNumber % 12
    return noteNames[noteIndex]
}

我的代码输出

Note: B3 up
Note: A3 up
Note: E3 up
Note: G3 up
Note: F3 up
Note: E4 up
Note: F4 up
Note: D4 up
Note: G3 down
Note: A3 down
Note: F3 down
Note: E3 down
Note: B3 down
Note: D4 down
Note: E4 down
Note: C4 down
Note: G4 down
Note: F4 down

MIDI Monitor输出(完整捕获)

19:58:58.510    From MIDI Piano Bluetooth   Note On 1   B2  45
19:58:58.536    From MIDI Piano Bluetooth   Note On 1   A2  70
19:58:58.536    From MIDI Piano Bluetooth   Note On 1   E2  64
19:58:58.536    From MIDI Piano Bluetooth   Note On 1   G2  70
19:58:58.536    From MIDI Piano Bluetooth   Note On 1   F2  80
19:58:58.536    From MIDI Piano Bluetooth   Note On 1   C3  43 <- 代码未捕获
19:58:58.538    From MIDI Piano Bluetooth   Note On 1   E3  64 
19:58:58.538    From MIDI Piano Bluetooth   Note On 1   F3  45 <- 代码未捕获
19:58:58.538    From MIDI Piano Bluetooth   Note On 1   G3  43
19:58:58.539    From MIDI Piano Bluetooth   Note On 1   D3  47
19:58:58.780    From MIDI Piano Bluetooth   Note Off    1   G2  0
19:58:58.807    From MIDI Piano Bluetooth   Note Off    1   A2  0
19:58:58.807    From MIDI Piano Bluetooth   Note Off    1   F2  0
19:58:58.807    From MIDI Piano Bluetooth   Note Off    1   E2  0
19:58:58.807    From MIDI Piano Bluetooth   Note Off    1   B2  0
19:58:58.808    From MIDI Piano Bluetooth   Note Off    1   D3  0
19:58:58.808    From MIDI Piano Bluetooth   Note Off    1   E3  0
19:58:58.817    From MIDI Piano Bluetooth   Note Off    1   C3  0
19:58:58.817    From MIDI Piano Bluetooth   Note Off    1   G3  0
19:58:58.818    From MIDI Piano Bluetooth   Note Off    1   F3  0

(忽略八度偏移问题)

内容的提问来源于stack exchange,提问作者TSR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 08:22:20