krevis / MIDIApps

MIDI apps for Mac OS X: MIDI Monitor and SysEx Librarian.
http://www.snoize.com/
BSD 3-Clause "New" or "Revised" License
713 stars 112 forks source link

SnoizeMIDI: Minimal setup to capture messages #36

Closed masche842 closed 10 years ago

masche842 commented 10 years ago

Hi Kurt,

thanks for the SnoizeMIDI framework! Unfortunately there's not much documentation about its API.

I'm looking for the absolute minimal setup to capture midi messages on all available interfaces. IMHO it should be the code below, but it's not working. takeMIDImessages is never called.

Any help on this is greatly appreciated!

#import <SnoizeMIDI/SnoizeMIDI.h>

@interface MidiController : NSObject <SMMessageDestination>
{
    SMPortInputStream *inputStream;
}

@end

@implementation MidiController

- (id)init;
{
    inputStream = [[SMPortInputStream alloc] init];
    [inputStream setMessageDestination:self];
    [self addEndpointsToInputStream:[SMSourceEndpoint sourceEndpoints]];

    return self;
}

- (void)addEndpointsToInputStream:(NSArray *)endpoints;
{
    unsigned int endpointIndex, endpointCount;

    endpointCount = (unsigned int)[endpoints count];
    for (endpointIndex = 0; endpointIndex < endpointCount; endpointIndex++)
        [inputStream addEndpoint:[endpoints objectAtIndex:endpointIndex]];
}

//
// SMMessageDestination protocol
//

- (void)takeMIDIMessages:(NSArray *)messagesToTake;
{
    NSLog(@"Midi Message received.");
}

@end
krevis commented 10 years ago

That looks reasonable. I see you've found the code in SysEx Librarian (SSEMIDIController) that does the same thing.

masche842 commented 10 years ago

Is this in a Mac app, Mac command-line tool, or iOS app?

A Cocoa Mac app. I used the assistant to scaffold it and just added the MidiController class (printed above).

Did you call [SMClient sharedClient] early in your app? (For instance in your app delegate's -applicationWillFinishLaunching)

No I didn't! Added it to AppDelegate now ... but still no cigar.

If you step through in the debugger, does endpoints contain a few objects, or none?

Yes, it lists all endpoints (the same list that SysexLibrarian has at that point). I tested with a "real" Midi device earlier, now I've tested with the IAC driver and a (second) SysexLibrarian instance. Works with the first Librarian instance but not with my SysexSniffer. Content of the first IAC Endoint:

[1] SMSourceEndpoint *  0x600000267400  0x0000600000267400
- SMEndpoint  SMEndpoint    
-- SMMIDIObject  SMMIDIObject    
--- NSObject  NSObject    
--- objectRef MIDIObjectRef 1409035 1409035
--- uniqueID  MIDIUniqueID  -265309521  -265309521
--- ordinal NSUInteger  0 0
--- flags <anonymous struct>    
---- hasCachedName unsigned int:1  1 1
--- cachedName  __NSCFString *  @"Bus 1"  0x00006080004200a0
-- deviceRef MIDIDeviceRef 0 0
-- endpointFlags <anonymous struct>    
-- cachedManufacturerName  NSString *  nil 0x0000000000000000
-- cachedModelName NSString *  nil 0x0000000000000000

One more thing:

When I pause at the end of MidiController.init, send some Midi and continue, the debugger halts at nonretainedDelegate parser:self didReadMessages:messages with EXC_BAD_ACCESS(code=EXC_I386_GPFLT). Sysex-Librarian does not do that. Maybe I am still missing something?

Thanks for your help!

krevis commented 10 years ago

It sounds like your MidiController is being deallocated before it receives any MIDI events. (To check that, you could override -dealloc and set a breakpoint in the override.)

Is some other object keeping a strong reference to it? The SMPortInputStream won't retain your controller.

If that isn't it, send me your whole Xcdoe project (email krevis@snoize.com) and I can take a look.

masche842 commented 10 years ago

That did the trick! It's my first objective-c app and ARC got me right away...

Thanks for your help!