如何用SwiftUI和CoreMIDI获取并解码网络MIDI时间码?
网络MIDI Timecode接收问题及代码示例
我已经在macOS应用中成功获取主机列表,代码实现简单直接。目前希望通过网络获取MIDI Timecode并解码为时钟,解码逻辑已完成,但应用连接会话并获取时钟信息的过程非常困难,网上相关资料极少。
以下是我的代码:
MIDIInputPortCreate(client, "MIDI Timecode Receiver Input Port" as CFString, { packetList, _ in let packets = packetList.pointee let packet = packets.packet let statusByte = packet.data.0 // Check if the MIDI message is a Timecode message if statusByte == 0xF1 { // Extract the timecode values from the MIDI message let frames = Int(packet.data.1 & 0x1F) let seconds = Int(packet.data.2 & 0x3F) let minutes = Int(packet.data.3 & 0x3F) let hours = Int(packet.data.4 & 0x1F) // Update the timecode message with the new timecode values DispatchQueue.main.async { midiTimecode = "\(hours):\(minutes):\(seconds):\(frames)" } } }, nil, &endpoint) let networkSession = MIDINetworkSession.default() networkSession.addConnection(nil, port: outputPort, to: networkSession.sourceEndpoint())
请问是否有人成功实现过该功能,或是知晓如何从会话中提取时间码?
编辑:已找到苹果官方文档,但该文档未涉及输入时间码的处理,文档主题为《将MIDI 2集成到你的应用中》
问题排查与解决方案建议
- 修正网络会话连接逻辑:当前
networkSession.addConnection调用错误地连接到了本地会话的源端点,你需要连接到远程发送MIDI Timecode的设备端点。正确做法是先发现网络上的可用MIDI端点,再筛选目标设备建立连接:// 获取网络上的可用MIDI端点 let availableEndpoints = MIDINetworkSession.default().availableEndpoints // 根据设备名称或属性筛选目标端点(示例:包含Timecode关键词) if let targetEndpoint = availableEndpoints.first(where: { $0.name.contains("Timecode") }) { // 使用输入端口建立连接,而非输出端口 networkSession.addConnection(nil, port: inputPort, to: targetEndpoint) } - 修复输入端口创建参数:
MIDIInputPortCreate的最后一个参数应为MIDIPortRef类型的输入端口引用,而非端点引用。你需要先声明输入端口变量,再传入创建方法:var inputPort: MIDIPortRef = 0 let createResult = MIDIInputPortCreate(client, "MIDI Timecode Receiver Input Port" as CFString, { packetList, _ in // 你的解码逻辑 }, nil, &inputPort) // 校验端口创建是否成功 guard createResult == noErr else { print("MIDI输入端口创建失败,错误码:\(createResult)") return } - 遍历所有MIDI数据包:当前代码仅处理了数据包列表中的第一个包,实际可能存在多个数据包,需遍历处理:
let packetList = packetList.pointee for packetIndex in 0..<packetList.numPackets { let packet = packetList.packet[packetIndex] let statusByte = packet.data.0 if statusByte == 0xF1 { // 提取并处理Timecode数据 let frames = Int(packet.data.1 & 0x1F) let seconds = Int(packet.data.2 & 0x3F) let minutes = Int(packet.data.3 & 0x3F) let hours = Int(packet.data.4 & 0x1F) DispatchQueue.main.async { midiTimecode = "\(hours):\(minutes):\(seconds):\(frames)" } } } - 检查权限与网络配置:确保应用已获取网络权限,设备处于同一局域网,且音频MIDI设置中已启用网络MIDI服务。
内容的提问来源于stack exchange,提问作者Fabian H.
相关产品推荐
相关产品推荐

