Skip to content

Commit

Permalink
Issue #2: MIKMIDIMappings can now be loaded from XML on iOS.
Browse files Browse the repository at this point in the history
  • Loading branch information
armadsen committed May 15, 2014
1 parent 6e87e80 commit 22e426f
Show file tree
Hide file tree
Showing 7 changed files with 275 additions and 42 deletions.
19 changes: 16 additions & 3 deletions Source/MIKMIDIMapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@ typedef NS_OPTIONS(NSUInteger, MIKMIDIResponderType){
*/
@interface MIKMIDIMapping : NSObject <NSCopying>

#if !TARGET_OS_IPHONE
/**
* Initializes and returns an MIKMIDIMapping object created from the XML file at url.
*
Expand All @@ -175,6 +174,7 @@ typedef NS_OPTIONS(NSUInteger, MIKMIDIResponderType){
*/
- (instancetype)initWithFileAtURL:(NSURL *)url;

#if !TARGET_OS_IPHONE
/**
* Returns an NSXMLDocument representation of the receiver.
* The XML document returned by this method can be written to disk.
Expand All @@ -186,6 +186,20 @@ typedef NS_OPTIONS(NSUInteger, MIKMIDIResponderType){
* @see -writeToFileAtURL:error:
*/
- (NSXMLDocument *)XMLRepresentation;
#endif

/**
* Returns a data containing an XML string representation of the receiver.
* The XML string data returned by this method can be written to disk.
*
* @note On OS X, this method returns the same string as [[mapping XMLRepresentation] XMLData]. See https://github.com/mixedinkey-opensource/MIKMIDI/issues/2
*
* @return An NSData instance containing an XML string representation of the receiver.
*
* @see -XMLRepresentation
* @see -writeToFileAtURL:error:
*/
- (NSData *)XMLData;

/**
* Writes the receiver as an XML file to the specified URL.
Expand All @@ -198,7 +212,6 @@ typedef NS_OPTIONS(NSUInteger, MIKMIDIResponderType){
* @return YES if writing the mapping to a file succeeded, NO if an error occurred.
*/
- (BOOL)writeToFileAtURL:(NSURL *)fileURL error:(NSError **)error;
#endif

/**
* The mapping items that map controls to responder.
Expand Down Expand Up @@ -400,4 +413,4 @@ typedef NS_OPTIONS(NSUInteger, MIKMIDIResponderType){
*/
- (MIKMIDIResponderType)MIDIResponderTypeForCommandIdentifier:(NSString *)commandID; // Optional. If not implemented, MIKMIDIResponderTypeAll will be assumed.

@end
@end
61 changes: 31 additions & 30 deletions Source/MIKMIDIMapping.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#import "MIKMIDINoteOnCommand.h"
#import "MIKMIDINoteOffCommand.h"
#import "MIKMIDIPrivateUtilities.h"
#import "MIKMIDIUtilities.h"
#import "MIKMIDIMappingXMLParser.h"

#if !__has_feature(objc_arc)
#error MIKMIDIMapping.m must be compiled with ARC. Either turn on ARC for the project or set the -fobjc-arc flag for MIKMIDIMapping.m in the Build Phases for this target
Expand All @@ -36,8 +38,6 @@ @interface MIKMIDIMapping ()

@implementation MIKMIDIMapping

#if !TARGET_OS_IPHONE

- (instancetype)initWithFileAtURL:(NSURL *)url
{
return [self initWithFileAtURL:url error:NULL];
Expand All @@ -46,6 +46,15 @@ - (instancetype)initWithFileAtURL:(NSURL *)url
- (instancetype)initWithFileAtURL:(NSURL *)url error:(NSError **)error;
{
error = error ? error : &(NSError *__autoreleasing){ nil };
#if TARGET_OS_IPHONE
// iOS
NSData *data = [NSData dataWithContentsOfURL:url options:0 error:error];
if (!data) return nil;
MIKMIDIMappingXMLParser *parser = [MIKMIDIMappingXMLParser parserWithXMLData:data];
self = [parser.mappings firstObject];
return self;
#else
// OS X
NSXMLDocument *xmlDocument = [[NSXMLDocument alloc] initWithContentsOfURL:url options:0 error:error];
if (!xmlDocument) {
NSLog(@"Unable to read MIDI map XML file at %@: %@", url, *error);
Expand All @@ -57,8 +66,10 @@ - (instancetype)initWithFileAtURL:(NSURL *)url error:(NSError **)error;
if (![_name length]) _name = [[url lastPathComponent] stringByDeletingPathExtension];
}
return self;
#endif // TARGET_OS_IPHONE
}

#if !TARGET_OS_IPHONE
- (instancetype)initWithXMLDocument:(NSXMLDocument *)xmlDocument
{
self = [self init];
Expand All @@ -70,7 +81,6 @@ - (instancetype)initWithXMLDocument:(NSXMLDocument *)xmlDocument
}
return self;
}

#endif

- (id)init
Expand Down Expand Up @@ -135,20 +145,33 @@ - (NSXMLDocument *)XMLRepresentation;
[result setCharacterEncoding:@"UTF-8"];
return result;
}
#endif

- (NSData *)XMLData;
{
#if !TARGET_OS_IPHONE
return [[self XMLRepresentation] XMLDataWithOptions:NSXMLNodePrettyPrint];
#endif

NSMutableString *result = [NSMutableString string];


return [result dataUsingEncoding:NSUTF8StringEncoding];
}

- (BOOL)writeToFileAtURL:(NSURL *)fileURL error:(NSError **)error;
{
#if !TARGET_OS_IPHONE
error = error ? error : &(NSError *__autoreleasing){ nil };
NSData *mappingXMLData = [[self XMLRepresentation] XMLDataWithOptions:NSXMLNodePrettyPrint];
if (![mappingXMLData writeToURL:fileURL options:NSDataWritingAtomic error:error]) {
if (![[self XMLData] writeToURL:fileURL options:NSDataWritingAtomic error:error]) {
NSLog(@"Error saving MIDI mapping %@ to %@: %@", self.name, fileURL, *error);
return NO;
}
return YES;
#endif
return NO;
}

#endif

- (BOOL)isEqual:(MIKMIDIMapping *)otherMapping
{
if (self == otherMapping) return YES;
Expand Down Expand Up @@ -473,7 +496,7 @@ - (NSUInteger)hash

- (NSString *)description
{
NSMutableString *result = [NSMutableString stringWithFormat:@"%@ %@ %@ CommandID: %@ Channel %li MIDI Command %li Control Number %lu flipped %i", [super description], [self stringForInteractionType:self.interactionType], self.MIDIResponderIdentifier, self.commandIdentifier, (long)self.channel, (long)self.commandType, (unsigned long)self.controlNumber, (int)self.flipped];
NSMutableString *result = [NSMutableString stringWithFormat:@"%@ %@ %@ CommandID: %@ Channel %li MIDI Command %li Control Number %lu flipped %i", [super description], MIKMIDIMappingAttributeStringForInteractionType(self.interactionType), self.MIDIResponderIdentifier, self.commandIdentifier, (long)self.channel, (long)self.commandType, (unsigned long)self.controlNumber, (int)self.flipped];
if ([self.additionalAttributes count]) {
for (NSString *key in self.additionalAttributes) {
NSString *value = self.additionalAttributes[key];
Expand All @@ -487,28 +510,6 @@ - (NSString *)description

#pragma mark - Private

- (NSString *)stringForInteractionType:(MIKMIDIResponderType)type
{
NSDictionary *map = @{@(MIKMIDIResponderTypePressReleaseButton) : @"Key",
@(MIKMIDIResponderTypePressButton) : @"Tap",
@(MIKMIDIResponderTypeAbsoluteSliderOrKnob) : @"KnobSlider",
@(MIKMIDIResponderTypeRelativeKnob) : @"JogWheel",
@(MIKMIDIResponderTypeTurntableKnob) : @"TurnTable",
@(MIKMIDIResponderTypeRelativeAbsoluteKnob) : @"RelativeAbsoluteKnob"};
return [map objectForKey:@(type)];
}

- (MIKMIDIResponderType)interactionTypeForString:(NSString *)string
{
NSDictionary *map = @{@"Key" : @(MIKMIDIResponderTypePressReleaseButton),
@"Tap" : @(MIKMIDIResponderTypePressButton),
@"KnobSlider" : @(MIKMIDIResponderTypeAbsoluteSliderOrKnob),
@"JogWheel" : @(MIKMIDIResponderTypeRelativeKnob),
@"TurnTable" : @(MIKMIDIResponderTypeTurntableKnob),
@"RelativeAbsoluteKnob" : @(MIKMIDIResponderTypeRelativeAbsoluteKnob)};
return [[map objectForKey:string] integerValue];
}

#pragma mark - Properties

@end
8 changes: 1 addition & 7 deletions Source/MIKMIDIMappingManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,6 @@ - (NSURL *)userMappingsFolder
- (void)loadAvailableUserMappings
{
NSMutableSet *mappings = [NSMutableSet set];

#if !TARGET_OS_IPHONE

NSURL *mappingsFolder = [self userMappingsFolder];
NSFileManager *fm = [NSFileManager defaultManager];
Expand All @@ -172,25 +170,21 @@ - (void)loadAvailableUserMappings
} else {
NSLog(@"Unable to get contents of directory at %@: %@", mappingsFolder, error);
}

#endif


self.internalUserMappings = mappings;
}

- (void)loadBundledMappings
{
NSMutableSet *mappings = [NSMutableSet set];

#if !TARGET_OS_IPHONE
NSBundle *bundle = [NSBundle mainBundle];
NSArray *bundledMappingFileURLs = [bundle URLsForResourcesWithExtension:kMIKMIDIMappingFileExtension subdirectory:nil];
for (NSURL *file in bundledMappingFileURLs) {
MIKMIDIMapping *mapping = [[MIKMIDIMapping alloc] initWithFileAtURL:file];
mapping.bundledMapping = YES;
if (mapping) [mappings addObject:mapping];
}
#endif

self.bundledMappings = mappings;
}
Expand Down
24 changes: 24 additions & 0 deletions Source/MIKMIDIMappingXMLParser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// MIKMIDIMappingXMLParser.h
// MIDI Soundboard
//
// Created by Andrew Madsen on 4/15/14.
// Copyright (c) 2014 Mixed In Key. All rights reserved.
//

#import <Foundation/Foundation.h>

@class MIKMIDIMapping;

/**
* A parser for XML MIDI mapping files. Only used on iOS. On OS X, NSXMLDocument is used
* directly instead. Should be considered "private" for use by MIKMIDIMapping.
*/
@interface MIKMIDIMappingXMLParser : NSObject

+ (instancetype)parserWithXMLData:(NSData *)xmlData;
- (instancetype)initWithXMLData:(NSData *)xmlData;

@property (nonatomic, strong, readonly) NSArray *mappings;

@end
Loading

0 comments on commit 22e426f

Please sign in to comment.