gpt4 book ai didi

swift - 对 CoreMIDI 目的地的混淆

转载 作者:搜寻专家 更新时间:2023-11-01 07:15:44 26 4
gpt4 key购买 nike

给定以下代码,如果我使用 if 分支中的第一个方法来获取 MIDIDestination,代码工作正常,并且 MIDI 数据被发送。如果我使用 else 分支中的第二种方法,则不会发送任何数据。

var client = MIDIClientRef()
var port = MIDIPortRef()
var dest = MIDIEndpointRef()

MIDIClientCreate("jveditor" as CFString, nil, nil, &client)
MIDIOutputPortCreate(client, "output" as CFString, &port)

if false {
dest = MIDIGetDestination(1)
} else {
var device = MIDIGetExternalDevice(0)
var entity = MIDIDeviceGetEntity(device, 0)
dest = MIDIEntityGetDestination(entity, 0)
}

var name: Unmanaged<CFString>?
MIDIObjectGetStringProperty(dest, kMIDIPropertyDisplayName, &name)
print(name?.takeUnretainedValue() as! String)

var gmOn : [UInt8] = [ 0xf0, 0x7e, 0x7f, 0x09, 0x01, 0xf7 ]

var pktlist = MIDIPacketList()
var current = MIDIPacketListInit(&pktlist)
current = MIDIPacketListAdd(&pktlist, MemoryLayout<MIDIPacketList>.stride, current, 0, gmOn.count, &gmOn)

MIDISend(port, dest, &pktlist)

在这两种情况下打印的设备名称都是正确的,并且每次调用的状态都是noErr

我注意到,如果我请求 kMIDIManufacturerName 属性,我会得到不同的结果——特别是使用第一种方法,我从 USB MIDI 接口(interface)得到 Generic MIDI 设备已连接,使用第二种方法,我获得了通过音频 MIDI 设置应用程序配置的 Roland 的值。

我想使用第二种方法的原因是为了过滤掉没有所需制造商名称的设备,但如上所述我无法获得工作输出。

谁能解释这两种方法之间的区别,以及为什么后者不起作用,并最好就我如何解决这个问题提供建议?

最佳答案

听起来您只想找到 MIDI 目标端点以与特定制造商的设备通信。不幸的是,这实际上是不可能的,因为没有用于发现存在哪些 MIDI 设备、它们的属性是什么以及它们如何连接到计算机的协议(protocol)。

(请记住,MIDI 是 1980 年代的原始技术。它甚至不需要双向通信。MIDI 设备有完全有效的 MIDI 设置,您可以向其发送数据,但永远无法从其接收数据,反之亦然。)

计算机知道连接到它的 MIDI 接口(interface)(例如,USB-MIDI 接口(interface))。 CoreMIDI 称这些为“设备”。您可以找出有多少个,每个端口有多少个端口等。但是无法找到有关物理 MIDI 设备(例如连接到它们的键盘和合成器)的任何信息。

“外部设备”是一种绕过发现问题的尝试。当您按下“添加设备”按钮时,它们会出现在音频 MIDI 设置中。就这样!

理想情况下,您的用户会在其设置中为每个物理 MIDI 设备创建一个外部设备,输入每个设备的所有属性,并以完美反射(reflect)其物理 MIDI 电缆的方式设置所有连接。

不幸的是,在现实中:

  • 可能没有任何外部设备。在 Audio MIDI Setup 中创建它们并没有太大好处,而且需要大量无聊的数据输入,因此大多数人不会费心。
  • 如果有外部设备,您就不能相信用户添加的任何信息。例如,制造商可能不正确,或者可能拼写错误。
  • 强制您的用户在使用您的软件之前在音频 MIDI 设置中进行设置是非常不友好的。因此,没有应用程序会这样做......因此没有人在音频 MIDI 设置中进行任何设置。这是先有鸡还是先有蛋的问题。
  • 即使有外部设备,您的用户也可能希望将 MIDI 发送到其他端点(例如其他应用程序创建的虚拟端点),这些端点显然没有连接到外部设备。你应该让他们做他们想做的事。

documentation for MIDIGetDevice()提出了一个很好的建议:

If a client iterates through the devices and entities in the system, it will not ever visit any virtual sources and destinations created by other clients. Also, a device iteration will return devices which are "offline" (were present in the past but are not currently present), while iterations through the system's sources and destinations will not include the endpoints of offline devices.

Thus clients should usually use MIDIGetNumberOfSources, MIDIGetSource, MIDIGetNumberOfDestinations and MIDIGetDestination, rather iterating through devices and entities to locate endpoints.

换句话说:使用 MIDIGetNumberOfDestinationsMIDIGetDestination 获取可能的目的地,然后让您的用户选择其中之一。就这样。

如果您真的想做更多:

  • 给定目标端点,您可以使用 MIDIEndpointGetEntityMIDIEndpointGetDevice 访问 MIDI 接口(interface)。
  • 给定任何 MIDI 对象,您可以找到它与其他对象的联系。使用 MIDIObjectGetDataProperty获取属性值 kMIDIPropertyConnectionUniqueID ,这是连接对象的唯一 ID 的数组。然后使用 MIDIObjectFindByUniqueID到达对象。 outObjectType 会告诉您它是什么类型的对象。

但这很尴尬,您不能保证找到任何有用的信息。

关于swift - 对 CoreMIDI 目的地的混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42301373/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com