diff --git a/Documentation/FrameworkOverview.md b/Documentation/FrameworkOverview.md index 8eea030..0d6f3a2 100644 --- a/Documentation/FrameworkOverview.md +++ b/Documentation/FrameworkOverview.md @@ -109,7 +109,7 @@ print(ch) // [A4, C♯5, E5, G♯5] * `Chord.name` can be used to derive a chord name from a pitch set ```swift -let pitchSet : PitchSet = [Chroma.B*0, Chroma.Cs*2, Chroma.F*3, Chroma.G*4] +let pitchSet: PitchSet = [Chroma.B*0, Chroma.Cs*2, Chroma.F*3, Chroma.G*4] print(Chord.name(pitchSet)!) // G7♭5/B let descriptor = Chord.descriptor(pitchSet) print(descriptor!) // root: G, quality: dominant seventh flat five, bass: B diff --git a/MusicKit.xcodeproj/project.pbxproj b/MusicKit.xcodeproj/project.pbxproj index 98fdee5..94fc0b7 100644 --- a/MusicKit.xcodeproj/project.pbxproj +++ b/MusicKit.xcodeproj/project.pbxproj @@ -495,7 +495,8 @@ 96F299191A5663E500D7B006 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0610; + LastSwiftUpdateCheck = 0710; + LastUpgradeCheck = 0700; ORGANIZATIONNAME = benzguo; TargetAttributes = { 9691BB231A57C75500421B56 = { @@ -700,6 +701,7 @@ INFOPLIST_FILE = MusicKitTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "benzguo.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; }; @@ -715,6 +717,7 @@ INFOPLIST_FILE = MusicKitTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "benzguo.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; @@ -737,6 +740,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "benzguo.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = MusicKit; SDKROOT = iphoneos; SKIP_INSTALL = YES; @@ -757,6 +761,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "benzguo.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = MusicKit; SDKROOT = iphoneos; SKIP_INSTALL = YES; @@ -786,6 +791,7 @@ COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -860,6 +866,7 @@ INFOPLIST_FILE = MusicKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "benzguo.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = MusicKit; SKIP_INSTALL = YES; SWIFT_OBJC_BRIDGING_HEADER = ""; @@ -880,6 +887,7 @@ INFOPLIST_FILE = MusicKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "benzguo.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = MusicKit; SKIP_INSTALL = YES; SWIFT_OBJC_BRIDGING_HEADER = ""; @@ -900,6 +908,7 @@ ); INFOPLIST_FILE = MusicKitTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "benzguo.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -914,6 +923,7 @@ ); INFOPLIST_FILE = MusicKitTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "benzguo.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; diff --git a/MusicKit.xcodeproj/xcshareddata/xcschemes/MusicKit_OSX.xcscheme b/MusicKit.xcodeproj/xcshareddata/xcschemes/MusicKit_OSX.xcscheme index f997ca2..6069e9d 100644 --- a/MusicKit.xcodeproj/xcshareddata/xcschemes/MusicKit_OSX.xcscheme +++ b/MusicKit.xcodeproj/xcshareddata/xcschemes/MusicKit_OSX.xcscheme @@ -1,6 +1,6 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -62,15 +62,18 @@ ReferencedContainer = "container:MusicKit.xcodeproj"> + + + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -62,15 +62,18 @@ ReferencedContainer = "container:MusicKit.xcodeproj"> + + Harmonizer { - if indices.count < 2 || contains(indices, 0) { + if indices.count < 2 || indices.contains(0) { return Harmony.IdentityHarmonizer } // sort and convert to zero-indexed indices - let sortedIndices = sorted(indices.map { $0 - 1 }) + let sortedIndices = (indices.map { $0 - 1 }).sort() let maxIndex = Int(sortedIndices.last!) var scalePitches = harmonizer(Chroma.C*0) diff --git a/MusicKit/ChordName.swift b/MusicKit/ChordName.swift index d9992ea..d6398b2 100644 --- a/MusicKit/ChordName.swift +++ b/MusicKit/ChordName.swift @@ -80,14 +80,14 @@ extension Chord { let fullOpt = _descriptor(pitchSet, qualities: fullQs) // unaltered, no-slash, root position -> return if let full = fullOpt { - if contains(fullUnalteredQs, full.quality) && + if fullUnalteredQs.contains(full.quality) && full.bass == full.root { return full } } // try to simplify chord by slashing let noBassOpt = _descriptor(bassRemoved, qualities: slashQs) - var slashNoBassOpt : ChordDescriptor? = nil + var slashNoBassOpt: ChordDescriptor? = nil if let noBass = noBassOpt { slashNoBassOpt = bassChromaOpt.map { ChordDescriptor(root: noBass.root, quality: noBass.quality, bass: $0) diff --git a/MusicKit/ChordQualities.swift b/MusicKit/ChordQualities.swift index 63ffdea..20b9966 100644 --- a/MusicKit/ChordQualities.swift +++ b/MusicKit/ChordQualities.swift @@ -331,7 +331,7 @@ ChordQuality.MajorSeventhFlatNineSharpElevenFlatThirteen, ChordQuality.MinorMajorSeventhFlatNineSharpElevenFlatThirteen, ChordQuality.MinorSeventhFlatNineSharpElevenFlatThirteen, ] -public var name : String { +public var name: String { switch self { case PowerChord: return "PowerChord" case Major: return "Major" diff --git a/MusicKit/ChordQuality.swift b/MusicKit/ChordQuality.swift index b5ddf58..ac1f211 100644 --- a/MusicKit/ChordQuality.swift +++ b/MusicKit/ChordQuality.swift @@ -2,7 +2,7 @@ import Foundation -public enum ChordQuality : String { +public enum ChordQuality: String { //: Dyads case PowerChord = "5" //> Triads @@ -368,8 +368,8 @@ public enum ChordQuality : String { } } -extension ChordQuality : Printable { - public var description : String { +extension ChordQuality: CustomStringConvertible { + public var description: String { return rawValue } } diff --git a/MusicKit/Chroma.swift b/MusicKit/Chroma.swift index 5289cf0..69f469a 100644 --- a/MusicKit/Chroma.swift +++ b/MusicKit/Chroma.swift @@ -5,7 +5,7 @@ import Foundation typealias ChromaNameTuple = (LetterName, Accidental) /// Pitch quality; also known as pitch class. -public enum Chroma : UInt { +public enum Chroma: UInt { /// C case C = 0 /// C Sharp @@ -31,7 +31,7 @@ public enum Chroma : UInt { /// B case B = 11 - var names : [ChromaNameTuple] { + var names: [ChromaNameTuple] { switch self.rawValue { case 0: return [(.C, .Natural), (.B, .Sharp), (.D, .DoubleFlat)] @@ -71,9 +71,9 @@ public enum Chroma : UInt { } // MARK: Printable -extension Chroma : Printable { - public var description : String { - let nameTupleOpt : ChromaNameTuple? = self.names.first +extension Chroma: CustomStringConvertible { + public var description: String { + let nameTupleOpt: ChromaNameTuple? = self.names.first if let (letterName, accidental) = nameTupleOpt { return "\(letterName.description)\(accidental.description(true))" } diff --git a/MusicKit/Harmony.swift b/MusicKit/Harmony.swift index 4dd812b..6273fbc 100644 --- a/MusicKit/Harmony.swift +++ b/MusicKit/Harmony.swift @@ -4,7 +4,7 @@ import Foundation public struct Harmony { /// The identity Harmonizer function - public static let IdentityHarmonizer : Harmonizer = { pitch in + public static let IdentityHarmonizer: Harmonizer = { pitch in return PitchSet(pitches: pitch) } diff --git a/MusicKit/Info.plist b/MusicKit/Info.plist index 3ac1c13..6110912 100644 --- a/MusicKit/Info.plist +++ b/MusicKit/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - benzguo.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/MusicKit/IntervalQuality.swift b/MusicKit/IntervalQuality.swift index ad4ebbc..773a5b6 100644 --- a/MusicKit/IntervalQuality.swift +++ b/MusicKit/IntervalQuality.swift @@ -2,7 +2,7 @@ import Foundation -public enum IntervalQuality : UInt, Printable { +public enum IntervalQuality: UInt, CustomStringConvertible { case Unison = 0 case MinorSecond = 1 case MajorSecond = 2 @@ -28,7 +28,7 @@ public enum IntervalQuality : UInt, Printable { case MinorFourteenth = 22 case MajorFourteenth = 23 - public var description : String { + public var description: String { switch self { case Unison: return "unison" case MinorSecond: return "minor second" @@ -57,7 +57,7 @@ public enum IntervalQuality : UInt, Printable { } } - public var shortName : String { + public var shortName: String { switch self { case Unison: return "P1" case MinorSecond: return "m2" diff --git a/MusicKit/LetterName.swift b/MusicKit/LetterName.swift index 7490790..0add46e 100644 --- a/MusicKit/LetterName.swift +++ b/MusicKit/LetterName.swift @@ -2,7 +2,7 @@ import Foundation -public enum LetterName : UInt, Printable { +public enum LetterName: UInt, CustomStringConvertible { case C = 0 case D = 1 case E = 2 @@ -11,8 +11,8 @@ public enum LetterName : UInt, Printable { case A = 5 case B = 6 - static let names : [String] = ["C", "D", "E", "F", "G", "A", "B"] - public var description : String { + static let names: [String] = ["C", "D", "E", "F", "G", "A", "B"] + public var description: String { return LetterName.names[Int(rawValue)] } } diff --git a/MusicKit/MIDI.swift b/MusicKit/MIDI.swift index a047fea..c89aead 100644 --- a/MusicKit/MIDI.swift +++ b/MusicKit/MIDI.swift @@ -6,32 +6,32 @@ import CoreMIDI public class MIDI { /// Messages sent to the virtual MIDI source will be delivered on this channel. /// Default is 3. - public var sourceChannel : UInt = 3 + public var sourceChannel: UInt = 3 /// Handler for incoming MIDI note on or off messages - public var noteHandler : [MIDINoteMessage] -> Void = { messages in } + public var noteHandler: [MIDINoteMessage] -> Void = { messages in } /// The current pitch set in each input channel public var inputChannelToPitchSet = [UInt: PitchSet]() /// The current pitch set in the source channel - public var sourcePitchSet : PitchSet { + public var sourcePitchSet: PitchSet { return self.inputChannelToPitchSet[sourceChannel] ?? PitchSet() } - var _sources : [MIDIEndpointRef] = [] - var _destinations : [MIDIEndpointRef] = [] + var _sources: [MIDIEndpointRef] = [] + var _destinations: [MIDIEndpointRef] = [] var _name = "MusicKit" /// The virtual source - lazy var _virtualSource : MIDIEndpointRef = { + lazy var _virtualSource: MIDIEndpointRef = { var outSrc = MIDIEndpointRef() let s = MIDISourceCreate(self._client, self._name, &outSrc) return outSrc }() /// The MIDI client - lazy var _client : MIDIClientRef = { + lazy var _client: MIDIClientRef = { var outClient = MIDIClientRef() let s = MIDIClientCreate(self._name, MKMIDIProc.notifyProc(), nil, &outClient) @@ -39,7 +39,7 @@ public class MIDI { }() /// The MIDI input port - lazy var _inputPort : MIDIPortRef = { + lazy var _inputPort: MIDIPortRef = { var outPort = MIDIPortRef() let s = MIDIInputPortCreate(self._client, self._name, MKMIDIProc.readProc(), nil, &outPort) return outPort @@ -53,7 +53,7 @@ public class MIDI { public func send(messages: [T]) -> Bool { var success = false var packet = UnsafeMutablePointer.alloc(sizeof(MIDIPacket)) - var packetList = UnsafeMutablePointer.alloc(sizeof(MIDIPacketList)) + let packetList = UnsafeMutablePointer.alloc(sizeof(MIDIPacketList)) packet = MIDIPacketListInit(packetList) for message in messages { @@ -109,7 +109,7 @@ public class MIDI { let noteOn = UInt(MKMIDIMessage.NoteOn.rawValue) let noteOff = UInt(MKMIDIMessage.NoteOff.rawValue) let noteMessageTypes = [noteOn, noteOff] - if contains(noteMessageTypes, messageType) { + if noteMessageTypes.contains(messageType) { let noteNumber = packet[2] as! UInt let velocity = packet[3] as! UInt let m = MIDINoteMessage(on: messageType == noteOn || velocity == 0, @@ -139,7 +139,7 @@ public class MIDI { var newSources = [MIDIEndpointRef]() for i in 0.. [UInt8] @@ -13,12 +13,12 @@ public protocol MIDIMessage { func copyOnChannel(channel: UInt) -> Self } -public struct MIDINoteMessage : MIDIMessage { +public struct MIDINoteMessage: MIDIMessage { /// Note on: true, Note off: false - public let on : Bool - public let channel : UInt - public let noteNumber : UInt - public let velocity : UInt + public let on: Bool + public let channel: UInt + public let noteNumber: UInt + public let velocity: UInt public init(on: Bool, channel: UInt = 0, noteNumber: UInt, velocity: UInt) { self.on = on @@ -38,7 +38,7 @@ public struct MIDINoteMessage : MIDIMessage { } /// The message's pitch - public var pitch : Pitch { + public var pitch: Pitch { return Pitch(midi: Float(noteNumber)) } @@ -55,14 +55,14 @@ public struct MIDINoteMessage : MIDIMessage { } } -extension MIDINoteMessage : Printable { - public var description : String { +extension MIDINoteMessage: CustomStringConvertible { + public var description: String { let onString = on ? "On" : "Off" return "\(channel): Note \(onString): \(noteNumber) \(velocity)" } } -extension MIDINoteMessage : Transposable { +extension MIDINoteMessage: Transposable { public func transpose(semitones: Float) -> MIDINoteMessage { return MIDINoteMessage(on: self.on, channel: self.channel, diff --git a/MusicKit/MKMIDIProc.h b/MusicKit/MKMIDIProc.h index 6f59ccc..2a2dd1f 100644 --- a/MusicKit/MKMIDIProc.h +++ b/MusicKit/MKMIDIProc.h @@ -38,7 +38,7 @@ typedef NS_ENUM(NSUInteger, MKMIDINotification) { typedef void (^MKMIDIReadCallback)(NSArray *packets); typedef void (^MKMIDINotifyCallback)(MKMIDINotification messageID); -@interface MKMIDIProc : NSObject +@interface MKMIDIProc: NSObject + (void (*)(const MIDIPacketList *pktlist, void *procRef, void *srcRef))readProc; + (void)setReadCallback:(MKMIDIReadCallback)callback; diff --git a/MusicKit/MKMIDIProc.m b/MusicKit/MKMIDIProc.m index 731cf4c..f2d346b 100644 --- a/MusicKit/MKMIDIProc.m +++ b/MusicKit/MKMIDIProc.m @@ -65,7 +65,7 @@ static void notifyProc(const MIDINotification *notification, void *refCon) { if (!_notifyCallback) { return; } - MKMIDINotification messageID = notification->messageID; + MKMIDINotification messageID = (MKMIDINotification)notification->messageID; /// For now, just return the message id. /// TODO: parse the object corresponding to the message id. _notifyCallback(messageID); diff --git a/MusicKit/MKUtil.swift b/MusicKit/MKUtil.swift index 316fc75..1dfde4e 100644 --- a/MusicKit/MKUtil.swift +++ b/MusicKit/MKUtil.swift @@ -8,7 +8,7 @@ public enum MKUtil { let count = semitoneIndices.count let modN = Int(n) % count var semitones = semitoneIndices - for i in 0.. [0, 4, 7] public static func semitoneIndices(intervals: [Float]) -> [Float] { - var indices : [Float] = [0] + var indices: [Float] = [0] for i in 0.. [4, 3] public static func intervals(semitoneIndices: [Float]) -> [Float] { - var intervals : [Float] = [] + var intervals: [Float] = [] for i in 1..(pitches: C,_ pitch: Pitch) -> Int { - if isEmpty(pitches) { + if pitches.isEmpty { return 0 } diff --git a/MusicKit/MusicKit.swift b/MusicKit/MusicKit.swift index b5ec2a7..f07426e 100644 --- a/MusicKit/MusicKit.swift +++ b/MusicKit/MusicKit.swift @@ -4,5 +4,5 @@ import Foundation public struct MusicKit { /// The global value of concert A - public static var concertA : Double = 440.0 + public static var concertA: Double = 440.0 } diff --git a/MusicKit/Pitch.swift b/MusicKit/Pitch.swift index 11621f0..798d6f6 100644 --- a/MusicKit/Pitch.swift +++ b/MusicKit/Pitch.swift @@ -4,7 +4,7 @@ import Foundation /// The auditory attribute of sound according to which sounds can be ordered /// on a scale from low to high (ANSI 1994) -public struct Pitch : Comparable { +public struct Pitch: Comparable { /// midi number to frequency /// TODO: move this to a temperament enum public static func mtof(midi: Float) -> Float { @@ -13,7 +13,7 @@ public struct Pitch : Comparable { return Float(freq) } - public let midi : Float + public let midi: Float /// Creates a `Pitch` with the given MIDI number. /// Note that non-integral MIDI numbers are allowed. @@ -27,41 +27,41 @@ public struct Pitch : Comparable { } /// The frequency of the pitch in Hz - public var frequency : Float { + public var frequency: Float { return Pitch.mtof(self.midi) } /// A `Chroma`, or nil if the pitch doesn't align with the chromas /// in the current tuning system. - public var chroma : Chroma? { + public var chroma: Chroma? { if self.midi - floor(self.midi) == 0 { return Chroma(rawValue: UInt(self.midi)%12) } return nil } - var noteNameTuple : (LetterName, Accidental, Int)? { + var noteNameTuple: (LetterName, Accidental, Int)? { return chroma.flatMap { $0.names.first.map { noteNameWithOctave(octaveNumber, nameTuple: $0) } } } - public var noteName : String? { + public var noteName: String? { return noteNameTuple.map { "\($0.0.description)\($0.1.description(true))\($0.2)" } } /// Unadjusted octave number - var octaveNumber : Int { + var octaveNumber: Int { return Int((self.midi - 12.0)/12.0) } /// Combines an octave number with a chroma name, taking into account /// edge cases for enharmonics like B# func noteNameWithOctave(octave: Int, nameTuple name: ChromaNameTuple) -> (LetterName, Accidental, Int) { - let cFlat : ChromaNameTuple = (.C, .Flat) - let bSharp : ChromaNameTuple = (.B, .Sharp) + let cFlat: ChromaNameTuple = (.C, .Flat) + let bSharp: ChromaNameTuple = (.B, .Sharp) var adjustedOctaveNumber = octave if name == cFlat { adjustedOctaveNumber++ @@ -74,21 +74,21 @@ public struct Pitch : Comparable { } // MARK: Printable -extension Pitch : Printable { - public var description : String { +extension Pitch: CustomStringConvertible { + public var description: String { return (noteName != nil) ? "\(noteName!)" : "\(frequency)Hz" } } // MARK: Hashable -extension Pitch : Hashable { - public var hashValue : Int { +extension Pitch: Hashable { + public var hashValue: Int { return midi.hashValue } } // MARK: Transposable -extension Pitch : Transposable { +extension Pitch: Transposable { public func transpose(semitones: Float) -> Pitch { return Pitch(midi: midi + semitones) } diff --git a/MusicKit/PitchSet.swift b/MusicKit/PitchSet.swift index 7969873..64ba962 100644 --- a/MusicKit/PitchSet.swift +++ b/MusicKit/PitchSet.swift @@ -4,9 +4,9 @@ import Foundation // MARK: == PitchSet == /// A collection of unique `Pitch` instances ordered by frequency. -public struct PitchSet : Equatable { +public struct PitchSet: Equatable { - var contents : [Pitch] = [] + var contents: [Pitch] = [] /// The number of pitches the `PitchSet` contains. public var count: Int { @@ -18,12 +18,12 @@ public struct PitchSet : Equatable { /// Creates a new `PitchSet` with the contents of a given sequence of pitches. public init(_ sequence: S) { - contents = sorted(Array(Set(sequence))) + contents = Array(Set(sequence)).sort() } /// Creates a new `PitchSet` with the given pitches. public init(pitches: Pitch...) { - contents = sorted(Array(Set(pitches))) + contents = Array(Set(pitches)).sort() } /// Returns the index of the given `pitch` @@ -68,7 +68,7 @@ public struct PitchSet : Equatable { /// Inserts the contents of a sequence of pitches into the `PitchSet`. public mutating func insert(pitches: S) { - contents = sorted(Array(Set(contents + pitches))) + contents = Array(Set(contents + pitches)).sort() } /// Removes `pitch` from the `PitchSet` if it exists. @@ -93,22 +93,14 @@ public struct PitchSet : Equatable { } // MARK: Printable -extension PitchSet : Printable { - public var description : String { +extension PitchSet: CustomStringConvertible { + public var description: String { return contents.description } } -// MARK: SequenceType -extension PitchSet : SequenceType { - /// Returns a generator of the elements of the collection. - public func generate() -> GeneratorOf { - return GeneratorOf(contents.generate()) - } -} - // MARK: CollectionType -extension PitchSet : CollectionType { +extension PitchSet: CollectionType { /// The position of the first pitch in the set. (Always zero.) public var startIndex: Int { return 0 @@ -125,26 +117,23 @@ extension PitchSet : CollectionType { public subscript(i: Int) -> Pitch { return contents[i] } -} -// MARK: ArrayLiteralConvertible -extension PitchSet : ArrayLiteralConvertible { - public init(arrayLiteral elements: Pitch...) { - self.contents = sorted(Array(Set(elements))) - } -} - -// MARK: Sliceable -extension PitchSet : Sliceable { /// Access the elements in the given range. public subscript(range: Range) -> PitchSetSlice { return PitchSetSlice(contents[range]) } } +// MARK: ArrayLiteralConvertible +extension PitchSet: ArrayLiteralConvertible { + public init(arrayLiteral elements: Pitch...) { + self.contents = Array(Set(elements)).sort() + } +} + // MARK: Equatable public func ==(lhs: PitchSet, rhs: PitchSet) -> Bool { - if count(lhs) != count(rhs) { + if lhs.count != rhs.count { return false } for (lhs, rhs) in zip(lhs, rhs) { @@ -182,7 +171,7 @@ public func -=(inout lhs: PitchSet, rhs: PitchSet) { // MARK: == PitchSetSlice == /// A slice of a `PitchSet`. -public struct PitchSetSlice : Printable { +public struct PitchSetSlice { private var contents: ArraySlice = [] /// The number of elements the `PitchSetSlice` contains. @@ -195,12 +184,12 @@ public struct PitchSetSlice : Printable { /// Creates a new `PitchSetSlice` with the contents of a given sequence. public init(_ sequence: S) { - contents = ArraySlice(sorted(Array(Set(sequence)))) + contents = ArraySlice(Array(Set(sequence)).sort()) } /// Creates a new `PitchSetSlice` with the given values. public init(values: Pitch...) { - contents = ArraySlice(sorted(Array(Set(values)))) + contents = ArraySlice(Array(Set(values)).sort()) } /// Creates a new `PitchSetSlice` from a sorted slice. @@ -245,7 +234,7 @@ public struct PitchSetSlice : Printable { /// Inserts the contents of a sequence into the `PitchSetSlice`. public mutating func insert(pitches: S) { - contents = ArraySlice(sorted(Array(Set(contents + pitches)))) + contents = ArraySlice(Array(Set(contents + pitches)).sort()) } /// Removes `pitch` from the slice if it exists. @@ -270,22 +259,15 @@ public struct PitchSetSlice : Printable { } // MARK: Printable -extension PitchSetSlice : Printable { +extension PitchSetSlice: CustomStringConvertible { public var description: String { return contents.description } } -// MARK: SequenceType -extension PitchSetSlice : SequenceType { - public func generate() -> GeneratorOf { - return GeneratorOf(contents.generate()) - } -} - // MARK: CollectionType -extension PitchSetSlice : CollectionType { - typealias Index = Int +extension PitchSetSlice: CollectionType { + public typealias Index = Int /// The position of the first pitch in the slice. (Always zero.) public var startIndex: Int { @@ -303,19 +285,16 @@ extension PitchSetSlice : CollectionType { public subscript(i: Int) -> Pitch { return contents[i] } -} - -// MARK: ArrayLiteralConvertible -extension PitchSetSlice : ArrayLiteralConvertible { - public init(arrayLiteral elements: Pitch...) { - self.contents = ArraySlice(sorted(Array(Set(elements)))) - } -} -// MARK: Sliceable -extension PitchSetSlice : Sliceable { /// Access the elements in the given range. public subscript(range: Range) -> PitchSetSlice { return PitchSetSlice(contents[range]) } } + +// MARK: ArrayLiteralConvertible +extension PitchSetSlice: ArrayLiteralConvertible { + public init(arrayLiteral elements: Pitch...) { + self.contents = ArraySlice(Array(Set(elements)).sort()) + } +} diff --git a/MusicKit/PitchSetExtensions.swift b/MusicKit/PitchSetExtensions.swift index f01a0c1..1dbcdc3 100644 --- a/MusicKit/PitchSetExtensions.swift +++ b/MusicKit/PitchSetExtensions.swift @@ -8,14 +8,16 @@ extension PitchSet { public func gamut() -> Set { var set = Set() for pitch in self.contents { - pitch.chroma.map { set.insert($0) } + if let chroma = pitch.chroma { + set.insert(chroma) + } } return set } } // MARK: Transposable -extension PitchSet : Transposable { +extension PitchSet: Transposable { public func transpose(semitones: Float) -> PitchSet { // TODO: use PitchSet.map return PitchSet(contents.map { $0.transpose(semitones) }) @@ -93,7 +95,9 @@ extension PitchSet { } } } - pitchesToRemove.map { self.remove($0) } + for pitch in pitchesToRemove { + self.remove(pitch) + } } /// Collapses the pitch set to within an octave, maintaining the bass. @@ -125,21 +129,6 @@ extension PitchSet { } } -// MARK: Higher-order functions -extension PitchSet { - public func map(transform: Pitch -> T) -> [T] { - return Swift.map(self, transform) - } - - public func reduce(initial: T, combine: (T, Pitch) -> T) -> T { - return Swift.reduce(self, initial, combine) - } - - public func filter(includeElement: Pitch -> Bool) -> PitchSet { - return PitchSet(Swift.filter(self, includeElement)) - } -} - // MARK: PitchSet-Pitch operators public func +(lhs: PitchSet, rhs: Pitch) -> PitchSet { var lhs = lhs diff --git a/MusicKit/ScaleQuality.swift b/MusicKit/ScaleQuality.swift index f53a214..2429674 100644 --- a/MusicKit/ScaleQuality.swift +++ b/MusicKit/ScaleQuality.swift @@ -2,7 +2,7 @@ import Foundation -public enum ScaleQuality : String { +public enum ScaleQuality: String { case Chromatic = "Chromatic" case Wholetone = "Wholetone" case Octatonic1 = "Octatonic mode 1" @@ -15,7 +15,7 @@ public enum ScaleQuality : String { case Minor = "Minor" case Locrian = "Locrian" - public var intervals : [Float] { + public var intervals: [Float] { switch self { case Chromatic: return [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] case Wholetone: return [2, 2, 2, 2, 2, 2] @@ -32,8 +32,8 @@ public enum ScaleQuality : String { } } -extension ScaleQuality : Printable { - public var description : String { +extension ScaleQuality: CustomStringConvertible { + public var description: String { return rawValue } } diff --git a/MusicKitTests/ChordNameBasicTests.swift b/MusicKitTests/ChordNameBasicTests.swift index 27fadfb..404cb80 100644 --- a/MusicKitTests/ChordNameBasicTests.swift +++ b/MusicKitTests/ChordNameBasicTests.swift @@ -2,16 +2,15 @@ import XCTest import MusicKit final class ChordNameBasicTests: XCTestCase { - ///* func testPowerChord() { - var sut : PitchSet = [Chroma.C*0, Chroma.G*0, Chroma.C*2] - var name = Chord.name(sut) - var expected = "C5" + let sut: PitchSet = [Chroma.C*0, Chroma.G*0, Chroma.C*2] + let name = Chord.name(sut) + let expected = "C5" XCTAssert(name == expected, "\(name) != \(expected)") } func testMajorMinor() { - var sut : PitchSet = [Chroma.C*0, Chroma.E*2, Chroma.G*3, Chroma.C*4] + var sut: PitchSet = [Chroma.C*0, Chroma.E*2, Chroma.G*3, Chroma.C*4] var name = Chord.name(sut) var expected = "CM" XCTAssert(name == expected, "\(name) != \(expected)") @@ -28,7 +27,7 @@ final class ChordNameBasicTests: XCTestCase { } func testOtherTriads() { - var sut : PitchSet = [Chroma.C*0, Chroma.E*2, Chroma.Gs*3, Chroma.C*4] + var sut: PitchSet = [Chroma.C*0, Chroma.E*2, Chroma.Gs*3, Chroma.C*4] var name = Chord.name(sut) var expected = "C+" XCTAssert(name == expected, "\(name) != \(expected)") @@ -55,7 +54,7 @@ final class ChordNameBasicTests: XCTestCase { } func testCommonTetrads() { - var sut : PitchSet = [Chroma.C*0, Chroma.E*2, Chroma.G*3, Chroma.As*4, Chroma.G*3] + var sut: PitchSet = [Chroma.C*0, Chroma.E*2, Chroma.G*3, Chroma.As*4, Chroma.G*3] var name = Chord.name(sut) var expected = "C7" XCTAssert(name == expected, "\(name) != \(expected)") @@ -77,7 +76,7 @@ final class ChordNameBasicTests: XCTestCase { } func testOtherTetrads() { - var sut : PitchSet = [Chroma.C*0, Chroma.Ds*2, Chroma.G*3, Chroma.B*4, Chroma.G*3] + var sut: PitchSet = [Chroma.C*0, Chroma.Ds*2, Chroma.G*3, Chroma.B*4, Chroma.G*3] var name = Chord.name(sut) var expected = "CmΔ7" XCTAssert(name == expected, "\(name) != \(expected)") @@ -127,5 +126,4 @@ final class ChordNameBasicTests: XCTestCase { expected = "Gm6" XCTAssert(name == expected, "\(name) != \(expected)") } - //*/ } diff --git a/MusicKitTests/ChordNameExtendedTests.swift b/MusicKitTests/ChordNameExtendedTests.swift index 6224c2f..a31c261 100644 --- a/MusicKitTests/ChordNameExtendedTests.swift +++ b/MusicKitTests/ChordNameExtendedTests.swift @@ -2,9 +2,8 @@ import XCTest import MusicKit final class ChordNameExtendedTests: XCTestCase { - ///* func testSlashTetrads() { - var sut : PitchSet = [Chroma.Cs*0, Chroma.E*2, Chroma.G*3, Chroma.C*4] + var sut: PitchSet = [Chroma.Cs*0, Chroma.E*2, Chroma.G*3, Chroma.C*4] var name = Chord.name(sut) var expected = "CM/C♯" XCTAssert(name == expected, "\(name) != \(expected)") @@ -16,14 +15,14 @@ final class ChordNameExtendedTests: XCTestCase { } func testPentads() { - var sut : PitchSet = [Chroma.As*0, Chroma.Cs*1, Chroma.E*1, Chroma.G*1, Chroma.C*2] - var name = Chord.name(sut) - var expected = "B♭°9" + let sut: PitchSet = [Chroma.As*0, Chroma.Cs*1, Chroma.E*1, Chroma.G*1, Chroma.C*2] + let name = Chord.name(sut) + let expected = "B♭°9" XCTAssert(name == expected, "\(name) != \(expected)") } func testSlashPentads() { - var sut : PitchSet = [Chroma.Cs*0, Chroma.As*1, Chroma.E*2, Chroma.G*3, Chroma.C*4] + var sut: PitchSet = [Chroma.Cs*0, Chroma.As*1, Chroma.E*2, Chroma.G*3, Chroma.C*4] var name = Chord.name(sut) var expected = "C7/C♯" XCTAssert(name == expected, "\(name) != \(expected)") @@ -35,17 +34,16 @@ final class ChordNameExtendedTests: XCTestCase { } func testHexads() { - var sut : PitchSet = [Chroma.C*0, Chroma.E*0, Chroma.Gs*0, Chroma.B*0, Chroma.D*1, Chroma.F*1] - var name = Chord.name(sut) - var expected = "C+Δ11" + let sut: PitchSet = [Chroma.C*0, Chroma.E*0, Chroma.Gs*0, Chroma.B*0, Chroma.D*1, Chroma.F*1] + let name = Chord.name(sut) + let expected = "C+Δ11" XCTAssert(name == expected, "\(name) != \(expected)") } func testHeptads() { - var sut : PitchSet = [Chroma.C*0, Chroma.E*0, Chroma.G*0, Chroma.As*0, Chroma.D*1, Chroma.F*1, Chroma.Gs*1] - var name = Chord.name(sut) - var expected = "C11♭13" + let sut: PitchSet = [Chroma.C*0, Chroma.E*0, Chroma.G*0, Chroma.As*0, Chroma.D*1, Chroma.F*1, Chroma.Gs*1] + let name = Chord.name(sut) + let expected = "C11♭13" XCTAssert(name == expected, "\(name) != \(expected)") } - //*/ } diff --git a/MusicKitTests/ChordQualityTests.swift b/MusicKitTests/ChordQualityTests.swift index 4847b21..f447155 100644 --- a/MusicKitTests/ChordQualityTests.swift +++ b/MusicKitTests/ChordQualityTests.swift @@ -5,7 +5,7 @@ final class ChordQualityTests: XCTestCase { func testUniqueIntervals() { var seen = [String: String]() for quality in ChordQuality.All { - var key = quality.intervals.reduce("", combine: { (s, i) -> String in + let key = quality.intervals.reduce("", combine: { (s, i) -> String in s + "\(i)" }) if let value = seen[key] { diff --git a/MusicKitTests/ChromaTests.swift b/MusicKitTests/ChromaTests.swift index d8cb8ae..ea6d844 100644 --- a/MusicKitTests/ChromaTests.swift +++ b/MusicKitTests/ChromaTests.swift @@ -40,7 +40,7 @@ final class ChromaTests: XCTestCase { } func testDescription() { - var sut = Chroma.C + let sut = Chroma.C let description = sut.description XCTAssertEqual(description, "C") } diff --git a/MusicKitTests/Info.plist b/MusicKitTests/Info.plist index 0875159..ba72822 100644 --- a/MusicKitTests/Info.plist +++ b/MusicKitTests/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - benzguo.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/MusicKitTests/PitchSetTests.swift b/MusicKitTests/PitchSetTests.swift index 5a58af5..ceedf0f 100644 --- a/MusicKitTests/PitchSetTests.swift +++ b/MusicKitTests/PitchSetTests.swift @@ -3,7 +3,7 @@ import MusicKit final class PitchSetTests: XCTestCase { func testInitWithDuplicate() { - var sut : PitchSet = [Chroma.C*2, Chroma.C*2] + var sut: PitchSet = [Chroma.C*2, Chroma.C*2] XCTAssertEqual(sut.count, 1) sut = PitchSet(pitches: Chroma.C*2, Chroma.C*2) XCTAssertEqual(sut.count, 1) @@ -12,7 +12,7 @@ final class PitchSetTests: XCTestCase { } func testInsertDuplicate() { - var sut : PitchSet = [Chroma.C*2] + var sut: PitchSet = [Chroma.C*2] XCTAssertEqual(sut.count, 1) sut.insert(Chroma.C*2) XCTAssertEqual(sut.count, 1) @@ -21,38 +21,38 @@ final class PitchSetTests: XCTestCase { } func testSliceable() { - let sut : PitchSet = [Chroma.C*2, Chroma.C*3, Chroma.C*4] + let sut: PitchSet = [Chroma.C*2, Chroma.C*3, Chroma.C*4] let slice = sut[0...1] XCTAssertEqual(PitchSet(slice), PitchSet([Chroma.C*2, Chroma.C*3])) } func testTransposable() { - var sut : PitchSet = [Chroma.C*2, Chroma.C*3, Chroma.C*4] + var sut: PitchSet = [Chroma.C*2, Chroma.C*3, Chroma.C*4] sut = sut.transpose(2) XCTAssertEqual(sut, [Chroma.D*2, Chroma.D*3, Chroma.D*4]) } func testFilter() { - var sut : PitchSet = [Chroma.C*2, Chroma.C*3, Chroma.C*5] - sut = sut.filter { $0.midi != 72 } + var sut: PitchSet = [Chroma.C*2, Chroma.C*3, Chroma.C*5] + sut = PitchSet(sut.filter { $0.midi != 72 }) XCTAssertEqual(sut, [Chroma.C*2, Chroma.C*3]) } func testMap() { - let sut : PitchSet = [Chroma.C*5, Chroma.Cs*5, Chroma.D*5] + let sut: PitchSet = [Chroma.C*5, Chroma.Cs*5, Chroma.D*5] let result = sut.map { $0.midi } XCTAssertEqual(result, [72, 73, 74]) } func testReduce() { - let sut : PitchSet = [Chroma.C*5, Chroma.Cs*5, Chroma.D*5] + let sut: PitchSet = [Chroma.C*5, Chroma.Cs*5, Chroma.D*5] let result = sut.reduce(0, combine: { (a, r) in a + r.midi }) XCTAssertEqual(result, 219) } func testSemitoneIndices() { - var sut : PitchSet = [Chroma.C*5, Chroma.Cs*5, Chroma.D*5] + var sut: PitchSet = [Chroma.C*5, Chroma.Cs*5, Chroma.D*5] var result = sut.semitoneIndices() XCTAssertEqual(result, [0, 1, 2]) @@ -70,21 +70,21 @@ final class PitchSetTests: XCTestCase { } func testHarmonizer() { - let sut : PitchSet = [Chroma.C*5, Chroma.E*5, Chroma.G*5] + let sut: PitchSet = [Chroma.C*5, Chroma.E*5, Chroma.G*5] let h = sut.harmonizer() let result = h(Chroma.C*5) XCTAssertEqual(result, sut) } func testHarmonicFunction() { - let sut : PitchSet = [Chroma.C*5, Chroma.E*5, Chroma.G*5] + let sut: PitchSet = [Chroma.C*5, Chroma.E*5, Chroma.G*5] let h = sut.harmonicFunction(Scale.Major, 5) let result = h(Chroma.F*4) XCTAssertEqual(result, sut) } func testExtendOctaves() { - var sut : PitchSet = [Chroma.C*5, Chroma.E*5, Chroma.G*5] + var sut: PitchSet = [Chroma.C*5, Chroma.E*5, Chroma.G*5] sut.extendOctaves(0) XCTAssertEqual(sut, [Chroma.C*5, Chroma.E*5, Chroma.G*5]) @@ -97,24 +97,24 @@ final class PitchSetTests: XCTestCase { } func testDedupe() { - var sut : PitchSet = [Chroma.C*5, Chroma.C*6, Chroma.G*6, Chroma.C*7,] + var sut: PitchSet = [Chroma.C*5, Chroma.C*6, Chroma.G*6, Chroma.C*7,] sut.dedupe() XCTAssertEqual(sut, [Chroma.C*5, Chroma.G*6]) } func testCollapse() { - var sut : PitchSet = [Chroma.C*5, Chroma.G*6, Chroma.E*7, Chroma.C*8] + var sut: PitchSet = [Chroma.C*5, Chroma.G*6, Chroma.E*7, Chroma.C*8] sut.collapse() XCTAssertEqual(sut, [Chroma.C*5, Chroma.E*5, Chroma.G*5, Chroma.C*6]) } func testInvert() { - var sut : PitchSet = [Chroma.C*5, Chroma.E*5, Chroma.G*5] - sut.invert(n: 0) + var sut: PitchSet = [Chroma.C*5, Chroma.E*5, Chroma.G*5] + sut.invert(0) XCTAssertEqual(sut, [Chroma.C*5, Chroma.E*5, Chroma.G*5]) sut.invert() XCTAssertEqual(sut, [Chroma.E*5, Chroma.G*5, Chroma.C*6]) - sut.invert(n: 2) + sut.invert(2) XCTAssertEqual(sut, [Chroma.C*6, Chroma.E*6, Chroma.G*6]) } } diff --git a/MusicKitTests/ScaleTests.swift b/MusicKitTests/ScaleTests.swift index 14b3958..2b7cf3b 100644 --- a/MusicKitTests/ScaleTests.swift +++ b/MusicKitTests/ScaleTests.swift @@ -4,7 +4,7 @@ import MusicKit final class ScaleTests: XCTestCase { func testMajor() { let sut = Scale.Major(Chroma.C*5) - let expected : PitchSet = [ + let expected: PitchSet = [ Chroma.C*5, Chroma.D*5, Chroma.E*5, @@ -18,7 +18,7 @@ final class ScaleTests: XCTestCase { func testPhrygian() { let sut = Scale.Phrygian(Chroma.E*5) - let expected : PitchSet = [ + let expected: PitchSet = [ Chroma.E*5, Chroma.F*5, Chroma.G*5, @@ -32,7 +32,7 @@ final class ScaleTests: XCTestCase { func testChromatic() { let sut = Scale.Chromatic(Chroma.C*5) - let chromatic : PitchSet = [Chroma.C*5, Chroma.Cs*5, Chroma.D*5, + let chromatic: PitchSet = [Chroma.C*5, Chroma.Cs*5, Chroma.D*5, Chroma.Ds*5, Chroma.E*5, Chroma.F*5, Chroma.Fs*5, Chroma.G*5, Chroma.Gs*5, Chroma.A*5, Chroma.As*5, Chroma.B*5] XCTAssertEqual(sut, chromatic) diff --git a/Playgrounds/FrameworkOverview.playground/contents.xcplayground b/Playgrounds/FrameworkOverview.playground/contents.xcplayground index 4937636..664a2be 100644 --- a/Playgrounds/FrameworkOverview.playground/contents.xcplayground +++ b/Playgrounds/FrameworkOverview.playground/contents.xcplayground @@ -1,5 +1,5 @@ - + diff --git a/Playgrounds/FrameworkOverview.playground/section-1.swift b/Playgrounds/FrameworkOverview.playground/section-1.swift index acadb3f..0ae88cb 100644 --- a/Playgrounds/FrameworkOverview.playground/section-1.swift +++ b/Playgrounds/FrameworkOverview.playground/section-1.swift @@ -112,7 +112,7 @@ print(ch) // [A4, C♯5, E5, G♯5] ///* `Chord.name` can be used to derive a chord name from a pitch set ///```swift -let pitchSet : PitchSet = [Chroma.B*0, Chroma.Cs*2, Chroma.F*3, Chroma.G*4] +let pitchSet: PitchSet = [Chroma.B*0, Chroma.Cs*2, Chroma.F*3, Chroma.G*4] print(Chord.name(pitchSet)!) // G7♭5/B let descriptor = Chord.descriptor(pitchSet) print(descriptor!) // root: G, quality: dominant seventh flat five, bass: B diff --git a/Playgrounds/FrameworkOverview.playground/timeline.xctimeline b/Playgrounds/FrameworkOverview.playground/timeline.xctimeline index ab86823..d8bc7ad 100644 --- a/Playgrounds/FrameworkOverview.playground/timeline.xctimeline +++ b/Playgrounds/FrameworkOverview.playground/timeline.xctimeline @@ -13,12 +13,12 @@ shouldTrackSuperviewWidth = "NO"> diff --git a/README.md b/README.md index 09976e0..2ceab2e 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ print(V7ofV(C5)) // [D6, F♯6, A6, C7] **Chord recognition** ```swift -let pitchSet : PitchSet = [Chroma.B*0, Chroma.Cs*2, Chroma.F*3, Chroma.G*4] +let pitchSet: PitchSet = [Chroma.B*0, Chroma.Cs*2, Chroma.F*3, Chroma.G*4] print(Chord.name(pitchSet)) // G7♭5/B let descriptor = Chord.descriptor(pitchSet) print(descriptor) // root: G, quality: 7♭5, bass: B