Skip to content

Commit

Permalink
Add ChordDescriptor.inversion(_:) (#125)
Browse files Browse the repository at this point in the history
  • Loading branch information
jsbean authored Aug 24, 2019
1 parent 9588334 commit 051fbaa
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 2 deletions.
25 changes: 25 additions & 0 deletions Sources/Pitch/Chord/ChordDescriptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,28 @@ public struct ChordDescriptor {

extension ChordDescriptor {

// MARK: - Instance Methods

/// **Example Usage:**
///
/// let major: ChordDescriptor = [.M3, .m3]
/// let firstInversion = major.inversion(1) // => [.m3, .P4]
/// let secondInversion = major.inversion(2) // => [.P4, .M3]
///
/// let majorSeventh: ChordDescriptor = [.M3, .m3, .M3]
/// let thirdInversion = majorSeventh.inversion(3) // => [.m2, .M3, .m3]
///
/// - Returns: A `ChordDescriptor` which is the *nth* inversion of this `ChordDescriptor`.
public func inversion(_ value: Int) -> ChordDescriptor {
precondition(value >= 0 && value <= intervals.count)
if value == 0 { return self }
return ChordDescriptor(
(intervals + [.octave - intervals.sum])
.rotated(by: value)
.dropLast()
)
}

// MARK: - Type Properties

public static let major: ChordDescriptor = [.M3, .m3]
Expand Down Expand Up @@ -140,3 +162,6 @@ extension ChordDescriptor: ExpressibleByArrayLiteral {
self.intervals = intervals
}
}

extension ChordDescriptor: Equatable { }
extension ChordDescriptor: Hashable { }
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ extension CompoundIntervalDescriptor: AdditiveGroup {
public static func - (lhs: CompoundIntervalDescriptor, rhs: CompoundIntervalDescriptor)
-> CompoundIntervalDescriptor {
let semitones = lhs.interval.semitones - rhs.interval.semitones
let steps = lhs.interval.ordinal.steps - rhs.interval.ordinal.steps
let steps = lhs.steps - rhs.steps
let stepsModuloOctave = mod(steps,7)
let octaves = steps / 7
let interval = OrderedIntervalDescriptor(interval: semitones, steps: stepsModuloOctave)
Expand Down Expand Up @@ -329,3 +329,15 @@ extension OrderedIntervalDescriptor {
return ordinal.idealInterval + quality.adjustment
}
}

extension OrderedIntervalDescriptor {
var steps: Int {
return ordinal.steps
}
}

extension CompoundIntervalDescriptor {
var steps: Int {
return interval.steps + octaveDisplacement * 7
}
}
2 changes: 1 addition & 1 deletion Sources/Pitch/IntervalDescriptor/IntervalQuality.swift
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ extension IntervalQuality.Imperfect: CustomStringConvertible {

/// Printable description of IntervalQuality.Imperfect.
public var description: String {
return "P"
return self == .major ? "M" : "m"
}
}

Expand Down
27 changes: 27 additions & 0 deletions Tests/PitchTests/ChordDescriptorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,31 @@ class ChordDescriptorTests: XCTestCase {
let _: ChordDescriptor = [.m3, .m3] // diminished
let _: ChordDescriptor = [.M3, .M3] // augmented
}

func testInversionRootPosition() {
let major = ChordDescriptor([.M3, .m3])
let result = major.inversion(0)
XCTAssertEqual(major, result)
}

func testFirstInversion() {
let major: ChordDescriptor = [.M3, .m3]
let result = major.inversion(1)
let expected: ChordDescriptor = [.m3, .P4]
XCTAssertEqual(result, expected)
}

func testSecondInversion() {
let major: ChordDescriptor = [.M3, .m3]
let result = major.inversion(2)
let expected: ChordDescriptor = [.P4, .M3]
XCTAssertEqual(result, expected)
}

func testThirdInversion() {
let majorSeventh: ChordDescriptor = [.M3, .m3, .M3]
let result = majorSeventh.inversion(3)
let expected: ChordDescriptor = [.m2, .M3, .m3]
XCTAssertEqual(result, expected)
}
}
6 changes: 6 additions & 0 deletions Tests/PitchTests/CompoundIntervalDescriptorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,10 @@ class CompoundIntervalDescriptorTests: XCTestCase {
let expected: CompoundIntervalDescriptor = CompoundIntervalDescriptor(orderedInterval)
XCTAssertEqual(result, expected)
}

func testOctaveSubtractingCompoundInterval() {
let result: CompoundIntervalDescriptor = .octave - (.M3 + .m3)
let expected: CompoundIntervalDescriptor = .P4
XCTAssertEqual(result, expected)
}
}

0 comments on commit 051fbaa

Please sign in to comment.