2012-05-13 19 views
18

Aquí hay una aplicación CoreMIDI OS X extremadamente simple que envía datos MIDI. El problema es que no funciona. Compila bien y corre. No informa errores y no falla. La fuente creada se vuelve visible en el monitor MIDI. Sin embargo, no se reciben datos MIDI.¿Por qué este simple programa CoreMIDI no produce salida MIDI?

¿Podría alguien 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; 
} 

Respuesta

25

Está llamando al MIDISourceCreate para crear una fuente MIDI virtual.

Esto significa que su fuente aparecerá en la interfaz de usuario de configuración MIDI de otras aplicaciones, y que esas aplicaciones pueden elegir 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 otra opción en cuanto a dónde va el envío MIDI. Supongo que eso es lo que quieres.

The documentation for MIDISourceCreate dice:

Después de crear una fuente virtual, utilice MIDIReceived para transmitir mensajes MIDI desde su fuente virtual a todos los clientes conectados a la fuente virtual.

Por lo tanto, hacer dos cosas:

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

Eso debería resolver su problema.

¿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 su lugar:.

  1. llamada MIDIOutputPortCreate() para hacer un puerto de salida
  2. Uso MIDIGetNumberOfDestinations() y MIDIGetDestination() para obtener la lista de destinos y encontrar el que usted está interesado en
  3. Para enviar MIDI a un destino, llame MIDISend(outputPort, destination, packetList) .
+6

en mil años ¿pensaría usar MIDIReived para enviar MIDI? Gracias por la excelente explicación. – sixohsix

+5

Tiene más sentido si se piensa en una fuente MIDI en el contexto de un controlador de dispositivo MIDI: en ese caso, el controlador recibió algo de MIDI (por cable), y le está diciendo a CoreMIDI al respecto. Las fuentes virtuales MIDI se agregaron más tarde. –

+2

+1 eres un regalo del cielo, Kurt. –

2

Estoy dejando esto aquí para mi propia referencia. Es un ejemplo completo basado 100% en el tuyo, pero incluye el otro lado (recibir), mi código C malo 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 
0

Un pequeño detalle que otros están faltando: el parámetro de timeMIDIPacketListAddes importante para algunas aplicaciones musicales.

Aquí es un ejemplo de cómo se puede recuperar:

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

Fuente: Apple Documentation

Y luego, se aplica 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)); 
Nunca
+0

Es posible que una aplicación realmente conocida, producida por una casa de software alemán muy conocida, se rehúse a dibujar sus datos MIDI-CC entrantes si olvida establecer correctamente el parámetro de tiempo. – gog

Cuestiones relacionadas