@@ -55,6 +55,7 @@ - (id) init {
5555 [[NSNotificationCenter defaultCenter ] removeObserver: as name: NSApplicationWillTerminateNotification object: nil ];
5656
5757 delegates = [[NSMutableArray alloc ] init ];
58+ midiAddressToOSCAddressDict = [[NSMutableDictionary alloc ] init ];
5859 loadedFilePath = nil ;
5960 fileChangeCoalesceTimer = nil ;
6061
@@ -75,6 +76,9 @@ - (id) init {
7576 }
7677 return self;
7778}
79+ - (void ) awakeFromNib {
80+ [self ->midim setDelegate: self ];
81+ }
7882- (void )applicationDidFinishLaunching : (NSNotification *)aNotification {
7983 // check to see if there's a "SampleDocument.json" in ~/Documents/OSCQuery Helper
8084 NSFileManager *fm = [NSFileManager defaultManager ];
@@ -117,6 +121,7 @@ - (void)applicationWillTerminate:(NSNotification *)aNotification {
117121 [as removeDelegate: tmpDelegate forPath: [tmpDelegate address ]];
118122 }
119123 [delegates removeAllObjects ];
124+ [midiAddressToOSCAddressDict removeAllObjects ];
120125}
121126- (BOOL )application : (NSApplication *)sender openFile : (NSString *)filename {
122127 NSLog (@" %s ... %@ " ,__func__,filename);
@@ -324,6 +329,9 @@ - (BOOL) _loadAbletonProject:(NSString *)fullPath {
324329 }
325330 [delegates removeAllObjects ];
326331
332+ // clear out the midi-address-to-osc-address mapping dict
333+ [midiAddressToOSCAddressDict removeAllObjects ];
334+
327335 // clear out the OSC address space
328336 NSArray *baseNodes = [[as nodeContents ] lockCreateArrayCopy ];
329337 for (OSCNode *baseNode in baseNodes) {
@@ -436,6 +444,14 @@ - (BOOL) _loadAbletonProject:(NSString *)fullPath {
436444 }
437445 [newNode addDelegate: tmpDelegate];
438446 [self ->delegates addObject: tmpDelegate];
447+
448+ NSMutableArray *tmpArray = nil ;
449+ tmpArray = [self ->midiAddressToOSCAddressDict objectForKey: [tmpDelegate midiTypeAsString ]];
450+ if (tmpArray == nil ) {
451+ tmpArray = [[NSMutableArray alloc ] init ];
452+ [self ->midiAddressToOSCAddressDict setObject: tmpArray forKey: [tmpDelegate midiTypeAsString ]];
453+ }
454+ [tmpArray addObject: objFullPath];
439455 }
440456
441457 // run through the contents, calling this block recursively on each object
@@ -495,6 +511,9 @@ - (BOOL) _loadJSONFile:(NSString *)fullPath {
495511 }
496512 [delegates removeAllObjects ];
497513
514+ // clear out the midi-address-to-osc-address mapping dict
515+ [midiAddressToOSCAddressDict removeAllObjects ];
516+
498517 // clear out the OSC address space
499518 NSArray *baseNodes = [[as nodeContents ] lockCreateArrayCopy ];
500519 for (OSCNode *baseNode in baseNodes) {
@@ -570,7 +589,7 @@ - (BOOL) _loadJSONFile:(NSString *)fullPath {
570589 [newNode setExtendedType: objExtType];
571590 // if (objAccess != nil && [objAccess isKindOfClass:[NSNumber class]]) {
572591 // [newNode setAccess:[objAccess intValue]]; // don't do this, access is always write-only in this application (we can't read the remote app's OSC address space)
573- [newNode setAccess: 2 ];
592+ [newNode setAccess: 3 ];
574593 // }
575594 if (objRange != nil && [objRange isKindOfClass: [NSArray class ]])
576595 [newNode setRange: objRange];
@@ -601,6 +620,14 @@ - (BOOL) _loadJSONFile:(NSString *)fullPath {
601620 }
602621 [newNode addDelegate: tmpDelegate];
603622 [self ->delegates addObject: tmpDelegate];
623+
624+ NSMutableArray *tmpArray = nil ;
625+ tmpArray = [self ->midiAddressToOSCAddressDict objectForKey: [tmpDelegate midiTypeAsString ]];
626+ if (tmpArray == nil ) {
627+ tmpArray = [[NSMutableArray alloc ] init ];
628+ [self ->midiAddressToOSCAddressDict setObject: tmpArray forKey: [tmpDelegate midiTypeAsString ]];
629+ }
630+ [tmpArray addObject: baseObjPath];
604631 }
605632
606633 // run through the contents, calling this block recursively on each object
@@ -699,6 +726,111 @@ - (void) targetAppHostInfoChangedNotification:(NSNotification *)note {
699726}
700727
701728
729+ #pragma mark -------------------------- VVMIDIDelegate
730+
731+
732+ - (void ) setupChanged {
733+ // NSLog(@"%s",__func__);
734+ }
735+ - (void ) receivedMIDI : (NSArray *)a fromNode : (VVMIDINode *)n {
736+ // if ([a count]==1)
737+ // NSLog(@"%s ... %@, %@",__func__,[a objectAtIndex:0],n);
738+ // else
739+ // NSLog(@"%s ... %@, %@",__func__,a,n);
740+
741+ OSCAddressSpace *as = [OSCAddressSpace mainAddressSpace ];
742+ // run through the midi messages
743+ for (VVMIDIMessage *msg in a) {
744+ // create a midi string that describes the msg- this is the key in 'midiAddressToOSCAddressDict'
745+ NSString *midiMsgKey = [QueryServerNodeDelegate stringForMidiChannel: [msg channel ] type: [msg type ] voice: [msg data1 ]];
746+ // get the array of osc destinations that correspond to this address- run through each osc destination
747+ NSArray *oscDests = [midiAddressToOSCAddressDict objectForKey: midiMsgKey];
748+ // get a normalized double value for the MIDI message, we'll use it later to calculate a non-normalized val
749+ double normMIDIVal = [msg doubleValue ];
750+
751+ // run through every OSC address that this MIDI address is associated with
752+ for (NSString *oscDest in oscDests) {
753+ // get the OSC node for this address
754+ OSCNode *tmpNode = [as findNodeForAddress: oscDest createIfMissing: NO ];
755+ if (tmpNode == nil )
756+ continue ;
757+ // make a new OSC message- this is what we're going to populate, and dispatch to the server
758+ OSCMessage *newMsg = [OSCMessage createWithAddress: oscDest];
759+ NSArray *ranges = [tmpNode range ];
760+ NSDictionary *range = (ranges==nil || [ranges count ]!=1 ) ? nil : [ranges objectAtIndex: 0 ];
761+ double nonNormVal = normMIDIVal;
762+ if (range == nil ) {
763+ nonNormVal = normMIDIVal;
764+ }
765+ else {
766+ NSNumber *tmpMin = [range objectForKey: @" MIN" ];
767+ NSNumber *tmpMax = [range objectForKey: @" MAX" ];
768+ if (tmpMin == nil || tmpMax == nil ) {
769+ nonNormVal = normMIDIVal;
770+ }
771+ else {
772+ double tmpMinVal = [tmpMin doubleValue ];
773+ double tmpMaxVal = [tmpMax doubleValue ];
774+ nonNormVal = (normMIDIVal * (tmpMaxVal-tmpMinVal)) + tmpMinVal;
775+ }
776+ }
777+ NSString *nodeType = [tmpNode typeTagString ];
778+ unichar nodeTypeChar = (nodeType==nil ) ? ' f' : [nodeType characterAtIndex: 0 ];
779+ switch (nodeTypeChar) {
780+ case ' i' :
781+ [newMsg addInt: (int )nonNormVal];
782+ break ;
783+ case ' f' :
784+ [newMsg addFloat: (float )nonNormVal];
785+ break ;
786+ // case 's':
787+ // case 'S':
788+ // break;
789+ case ' d' :
790+ [newMsg addDouble: nonNormVal];
791+ break ;
792+ // case 'c':
793+ // break;
794+ // case 'r':
795+ // break;
796+ case ' T' : // true
797+ [newMsg addValue: [OSCValue createWithBool: YES ]];
798+ break ;
799+ case ' F' : // false
800+ [newMsg addValue: [OSCValue createWithBool: NO ]];
801+ break ;
802+ case ' N' : // nil
803+ [newMsg addValue: [OSCValue createWithNil ]];
804+ break ;
805+ case ' I' : // infinity
806+ [newMsg addValue: [OSCValue createWithInfinity ]];
807+ break ;
808+ case ' h' : // 64 bit int
809+ [newMsg addValue: [OSCValue createWithLongLong: (long long )nonNormVal]];
810+ break ;
811+ case ' [' :
812+ case ' ]' :
813+ break ;
814+ // case 'b': // blob
815+ // break;
816+ // case 't': // time tag
817+ // break;
818+ // case 'm': // midi
819+ // break;
820+ }
821+
822+ // ...at this point i've populated the OSC message- pass it back to the query server so anything listening to it will get it
823+
824+ OSCPacket *newPacket = [OSCPacket createWithContent: newMsg];
825+ [server
826+ sendOSCPacketData: [newPacket payload ]
827+ sized: [newPacket bufferLength ]
828+ toClientsListeningToOSCAddress: oscDest];
829+ }
830+ }
831+ }
832+
833+
702834#pragma mark -------------------------- VVKQueueCenterDelegate
703835
704836
@@ -742,7 +874,6 @@ - (VVOSCQueryReply *) hostInfoQueryFromServer:(VVOSCQueryServer *)s {
742874 // supply an extensions array if there isn't already one
743875 NSDictionary *extDict = @{
744876 kVVOSCQ_OptAttr_Tags : @YES ,
745- // kVVOSCQ_ReqAttr_Type : @YES,
746877 kVVOSCQ_OptAttr_Access : @YES ,
747878 kVVOSCQ_OptAttr_Value : @YES ,
748879 kVVOSCQ_OptAttr_Range : @YES ,
@@ -751,8 +882,8 @@ - (VVOSCQueryReply *) hostInfoQueryFromServer:(VVOSCQueryServer *)s {
751882 kVVOSCQ_OptAttr_Critical : @NO ,
752883 kVVOSCQ_OptAttr_Overloads : @NO ,
753884 kVVOSCQ_OptAttr_HTML : @YES ,
754- kVVOSCQ_WSAttr_Cmd_Listen : @NO ,
755- kVVOSCQ_WSAttr_Cmd_Ignore : @NO ,
885+ kVVOSCQ_WSAttr_Cmd_Listen : @YES ,
886+ kVVOSCQ_WSAttr_Cmd_Ignore : @YES ,
756887 kVVOSCQ_WSAttr_Cmd_PathChanged : @YES ,
757888 kVVOSCQ_WSAttr_Cmd_PathRenamed : @NO ,
758889 kVVOSCQ_WSAttr_Cmd_PathRemoved : @NO ,
@@ -800,7 +931,7 @@ - (void) server:(VVOSCQueryServer *)s receivedOSCPacket:(const void*)packet size
800931- (BOOL ) server : (VVOSCQueryServer *)s wantsToListenTo : (NSString *)address {
801932 // NSLog(@"%s ... %@, %@",__func__,s,address);
802933 // intentionally blank- we can't stream values because we don't have direct access to the remote app's address space (or data model corresponding to an address space)
803- return NO ;
934+ return YES ;
804935}
805936- (void ) server : (VVOSCQueryServer *)s wantsToIgnore : (NSString *)address {
806937 // NSLog(@"%s ... %@, %@",__func__,s,address);
0 commit comments