teclado para musical mac configurar conectar macos midi core-foundation coremidi

macos - para - ¿Por qué este simple programa CoreMIDI no produce salida MIDI?



configurar midi mac (3)

Aquí hay una aplicación CoreMIDI OS X extremadamente simple que envía datos MIDI. El problema es que no funciona. Se compila bien, y se ejecuta. No informa de errores, y no se bloquea. La Fuente creada se hace visible en el Monitor MIDI. Sin embargo, no salen datos MIDI .

¿Alguien podría decirme qué estoy haciendo mal aquí?

#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; }


Estás llamando a MIDISourceCreate para crear una fuente MIDI virtual.

Esto significa que su fuente aparecerá en la IU de configuración MIDI de otras aplicaciones, y que esas aplicaciones pueden elegir si escuchar o no su fuente. Su MIDI no se enviará a ningún puerto MIDI físico, a menos que alguna otra aplicación lo canalice allí. También significa que su aplicación no tiene ninguna opción en cuanto a dónde va el MIDI que está enviando. Supongo que eso es lo que quieres.

La documentación para MIDISourceCreate dice:

Después de crear una fuente virtual, use MIDIReceived para transmitir mensajes MIDI desde su fuente virtual a cualquier cliente conectado a la fuente virtual.

Entonces, haz dos cosas:

  • Eliminar el código que crea el puerto de salida. No lo necesitas.
  • cambie MIDISend(outPort, midiOut, pktList) a: MIDIReceived(midiOut, pktlist) .

Eso debería resolver tu problema.

Entonces, ¿para qué sirven los puertos de salida? Si quisiera dirigir sus datos MIDI a un destino específico, tal vez un puerto MIDI físico, NO crearía una fuente MIDI virtual. En lugar:

  1. Llame a MIDIOutputPortCreate() para crear un puerto de salida
  2. Use MIDIGetNumberOfDestinations() y MIDIGetDestination() para obtener la lista de destinos y encontrar el que le interesa.
  3. Para enviar MIDI a un destino, llame a MIDISend(outputPort, destination, packetList) .

Solo estoy dejando esto aquí por mi propia referencia. Es un ejemplo completo basado 100% en el suyo, pero incluye la otra parte (recepción), mi código C incorrecto y las correcciones de la respuesta aceptada (por supuesto).

#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


Un pequeño detalle que otros están omitiendo: el parámetro de time de MIDIPacketListAdd es importante para algunas aplicaciones musicales.

Aquí hay un ejemplo de cómo puedes recuperarlo:

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

Fuente: Documentación Apple

Y luego, aplicado a los otros ejemplos aquí:

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));