Технические вопросы и ответы QA1374

Получение имени внешнего MIDI-устройства от Конечной точки MIDI

Q: Как я получаю имя внешнего MIDI-устройства от Конечной точки MIDI?

A: CoreMIDI поддерживает внешние MIDI-устройства с многократными портами, например синтезатор больше чем с одним вводом MIDI. Внешние MIDI-устройства могут иметь многократные конечные точки и объекты. Поэтому вместо того, чтобы запросить просто Объект MIDI для имени устройства, конечные точки MIDI, объекты и внешние устройства должны все быть проверены для получения надлежащего имени устройства.

Начиная с выпуска OS X 10.4, MIDIServices.h включал свойство kMIDIPropertyDisplayName который может использоваться с этой целью. Это свойство обеспечивает рекомендуемое Apple видимое пользователем имя для конечной точки путем объединения устройства и имен конечной точки для Вас. Для объектов кроме конечных точек имя дисплея совпадает с именем.

Перечисление 1  , Получающее конечную точку, выводит на экран имя.

// ____________________________________________________________________________
// Obtain the name of an endpoint without regard for whether it has connections.
// The result should be released by the caller.
static CFStringRef GetEndpointDisplayName(MIDIEndpointRef endpoint)
{
    CFStringRef result = CFSTR(""); // default
 
    MIDIObjectGetStringProperty(endpoint, kMIDIPropertyDisplayName, &result);
 
    return result;
}

Перечисление 2  , Получающее имя конечной точки после соединений.

// Obtain the name of an endpoint, following connections.
// The result should be released by the caller.
static CFStringRef CreateConnectedEndpointName(MIDIEndpointRef endpoint)
{
    CFMutableStringRef result = CFStringCreateMutable(NULL, 0);
    CFStringRef str;
    OSStatus err;
 
    // Does the endpoint have connections?
    CFDataRef connections = NULL;
    int nConnected = 0;
    bool anyStrings = false;
    err = MIDIObjectGetDataProperty(endpoint, kMIDIPropertyConnectionUniqueID, &connections);
    if (connections != NULL) {
        // It has connections, follow them
        // Concatenate the names of all connected devices
        nConnected = CFDataGetLength(connections) / sizeof(MIDIUniqueID);
        if (nConnected) {
            const SInt32 *pid = reinterpret_cast<const SInt32 *>(CFDataGetBytePtr(connections));
            for (int i = 0; i < nConnected; ++i, ++pid) {
               MIDIUniqueID id = EndianS32_BtoN(*pid);
               MIDIObjectRef connObject;
               MIDIObjectType connObjectType;
               err = MIDIObjectFindByUniqueID(id, &connObject, &connObjectType);
               if (err == noErr) {
                if (connObjectType == kMIDIObjectType_ExternalSource  ||
                                                      connObjectType == kMIDIObjectType_ExternalDestination) {
                   // Connected to an external device's endpoint (10.3 and later).
                   str = EndpointName(static_cast<MIDIEndpointRef>(connObject), true);
                } else {
                     // Connected to an external device (10.2) (or something else, catch-all)
                  str = NULL;
                  MIDIObjectGetStringProperty(connObject, kMIDIPropertyName, &str);
                }
                if (str != NULL) {
                    if (anyStrings)
                        CFStringAppend(result, CFSTR(", "));
                    else anyStrings = true;
                    CFStringAppend(result, str);
                    CFRelease(str);
                }
               }
            }
        }
        CFRelease(connections);
    }
 
    if (anyStrings)
        return result;
    else
        CFRelease(result);
 
    // Here, either the endpoint had no connections, or we failed to obtain names for any of them.
    return CreateEndpointName(endpoint, false);
}
 
//////////////////////////////////////
// Obtain the name of an endpoint without regard for whether it has connections.
// The result should be released by the caller.
static CFStringRef CreateEndpointName(MIDIEndpointRef endpoint, bool isExternal)
{
    CFMutableStringRef result = CFStringCreateMutable(NULL, 0);
    CFStringRef str;
 
    // begin with the endpoint's name
    str = NULL;
    MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &str);
    if (str != NULL) {
        CFStringAppend(result, str);
        CFRelease(str);
    }
 
    MIDIEntityRef entity = NULL;
    MIDIEndpointGetEntity(endpoint, &entity);
    if (entity == NULL)
        // probably virtual
        return result;
 
    if (CFStringGetLength(result) == 0) {
        // endpoint name has zero length -- try the entity
        str = NULL;
        MIDIObjectGetStringProperty(entity, kMIDIPropertyName, &str);
        if (str != NULL) {
            CFStringAppend(result, str);
            CFRelease(str);
        }
    }
 
    // now consider the device's name
    MIDIDeviceRef device = NULL;
    MIDIEntityGetDevice(entity, &device);
    if (device == NULL) return result;
 
    str = NULL;
    MIDIObjectGetStringProperty(device, kMIDIPropertyName, &str);
    if (str != NULL) {
        // if an external device has only one entity, throw away
                // the endpoint name and just use the device name
        if (isExternal && MIDIDeviceGetNumberOfEntities(device) < 2) {
            CFRelease(result);
            return str;
        } else {
            // does the entity name already start with the device name?
                        // (some drivers do this though they shouldn't)
            // if so, do not prepend
            if (CFStringCompareWithOptions(str /* device name */,
                                    result /* endpoint name */,
                                         CFRangeMake(0, CFStringGetLength(str)), 0) != kCFCompareEqualTo) {
                // prepend the device name to the entity name
                if (CFStringGetLength(result) > 0)
                    CFStringInsert(result, 0, CFSTR(" "));
                CFStringInsert(result, 0, str);
            }
            CFRelease(str);
        }
    }
 
    return result;
}


История версии документа


ДатаПримечания
24.03.2014

Передовая статья

21.01.2014

Передовая статья

06.08.2013

Передовая статья

01.12.2004

Новый документ, которые получают имена внешних MIDI-устройств от Конечных точек MIDI.