Подтвердить что ты не робот

Почему эта простая программа CoreMIDI не выдает MIDI-выход?

Вот очень простое приложение CoreMIDI OS X, которое отправляет MIDI-данные. Проблема в том, что она не работает. Он компилируется отлично и работает. Он не сообщает об ошибках и не падает. Созданный источник становится видимым в MIDI Monitor. Однако не выводится информация MIDI.

Может ли кто-нибудь сообщить мне, что я здесь делаю неправильно?

#include <CoreMIDI/CoreMIDI.h>

int main(int argc, char *args[])
{
    MIDIClientRef   theMidiClient;
    MIDIEndpointRef midiOut;
    MIDIPortRef     outPort;
    char pktBuffer[1024];
    MIDIPacketList* pktList = (MIDIPacketList*) pktBuffer;
    MIDIPacket     *pkt;
    Byte            midiDataToSend[] = {0x91, 0x3c, 0x40};
    int             i;

    MIDIClientCreate(CFSTR("Magical MIDI"), NULL, NULL,
                     &theMidiClient);
    MIDISourceCreate(theMidiClient, CFSTR("Magical MIDI Source"),
                     &midiOut);
    MIDIOutputPortCreate(theMidiClient, CFSTR("Magical MIDI Out Port"),
                         &outPort);

    pkt = MIDIPacketListInit(pktList);
    pkt = MIDIPacketListAdd(pktList, 1024, pkt, 0, 3, midiDataToSend);

    for (i = 0; i < 100; i++) {
        if (pkt == NULL || MIDISend(outPort, midiOut, pktList)) {
            printf("failed to send the midi.\n");
        } else {
            printf("sent!\n");
        }
        sleep(1);
    }

return 0;
}
4b9b3361

Ответ 1

Вы вызываете MIDISourceCreate для создания виртуального MIDI-источника.

Это означает, что ваш источник появится в другом интерфейсе настройки MIDI-приложений, и эти приложения могут выбрать, следует ли слушать ваш источник. Ваш MIDI-интерфейс не будет отправлен на любые физические MIDI-порты, если только какое-то другое приложение не будет направлять его туда. Это также означает, что у вашего приложения нет выбора, куда идет передача MIDI-сообщений. Я предполагаю, что вы хотите.

Документация для MIDISourceCreate говорит:

После создания виртуального источника используйте MIDIReceived для передачи MIDI-сообщений из вашего виртуального источника любым клиентам, подключенным к виртуальному источнику.

Итак, выполните две вещи:

  • Удалите код, создающий выходной порт. Вам это не нужно.
  • измените MIDISend(outPort, midiOut, pktList) на: MIDIReceived(midiOut, pktlist).

Это должно решить вашу проблему.

Итак, для чего нужны выходные порты? Если вы хотите направить свои MIDI-данные на конкретный пункт назначения - возможно, на физический MIDI-порт - вы бы не создали виртуальный MIDI-источник. Вместо этого:

  • Вызов MIDIOutputPortCreate() для создания выходного порта
  • Используйте MIDIGetNumberOfDestinations() и MIDIGetDestination(), чтобы получить список получателей и найти тот, который вас интересует.
  • Чтобы отправить MIDI в один пункт назначения, вызовите MIDISend(outputPort, destination, packetList).

Ответ 2

Я просто оставляю это здесь для своих собственных ссылок. Это полный пример, основанный на 100% на вашем, но включающий в себя другую сторону (получение), мой плохой код C и принятые ответы (конечно).

#import "AppDelegate.h"

@implementation AppDelegate

@synthesize window = _window;

#define NSLogError(c,str) do{if (c) NSLog(@"Error (%@): %u:%@", str, (unsigned int)c,[NSError errorWithDomain:NSMachErrorDomain code:c userInfo:nil]); }while(false)

static void spit(Byte* values, int length, BOOL useHex) {
    NSMutableString *thing = [@"" mutableCopy];
    for (int i=0; i<length; i++) {
        if (useHex)
            [thing appendFormat:@"0x%X ", values[i]];
        else
            [thing appendFormat:@"%d ", values[i]];
    }
    NSLog(@"Length=%d %@", length, thing);
}

- (void) startSending {
    MIDIEndpointRef midiOut;
    char pktBuffer[1024];
    MIDIPacketList* pktList = (MIDIPacketList*) pktBuffer;
    MIDIPacket     *pkt;
    Byte            midiDataToSend[] = {0x91, 0x3c, 0x40};
    int             i;

    MIDISourceCreate(theMidiClient, CFSTR("Magical MIDI Source"),
                     &midiOut);
    pkt = MIDIPacketListInit(pktList);
    pkt = MIDIPacketListAdd(pktList, 1024, pkt, 0, 3, midiDataToSend);

    for (i = 0; i < 100; i++) {
        if (pkt == NULL || MIDIReceived(midiOut, pktList)) {
            printf("failed to send the midi.\n");
        } else {
            printf("sent!\n");
        }
        sleep(1);
    }
}

void ReadProc(const MIDIPacketList *packetList, void *readProcRefCon, void *srcConnRefCon)
{
    const MIDIPacket *packet = &packetList->packet[0];

    for (int i = 0; i < packetList->numPackets; i++)
    {

        NSData *data = [NSData dataWithBytes:packet->data length:packet->length];
        spit((Byte*)data.bytes, data.length, YES);

        packet = MIDIPacketNext(packet);
    }
}

- (void) setupReceiver {
    OSStatus s;
    MIDIEndpointRef virtualInTemp;
    NSString *inName = [NSString stringWithFormat:@"Magical MIDI Destination"];
    s = MIDIDestinationCreate(theMidiClient, (__bridge CFStringRef)inName, ReadProc,  (__bridge void *)self, &virtualInTemp);
    NSLogError(s, @"Create virtual MIDI in");
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    MIDIClientCreate(CFSTR("Magical MIDI"), NULL, NULL,
                     &theMidiClient);
    [self setupReceiver];
    [self startSending];

}

@end

Ответ 3

Небольшая информация, которую другие пропускают: параметр time MIDIPacketListAdd важен для некоторых музыкальных приложений.

Вот пример того, как вы можете его получить:

#import <mach/mach_time.h>
MIDITimeStamp midiTime = mach_absolute_time();

Источник: Документация Apple

И затем применим к другим примерам здесь:

pktBuffer[1024];
MIDIPacketList *pktList = (MIDIPacketList*)pktBuffer;
MIDIPacket *pktPtr = MIDIPacketListInit(pktList);
MIDITimeStamp midiTime = mach_absolute_time();
Byte midiDataToSend[] = {0x91, 0x3c, 0x40};
pktPtr = MIDIPacketListAdd(pktList, sizeof(pktList), pktPtr, midiTime, midiDataToSend, sizeof(midiDataToSend));