diff --git a/Examples/ChaosHarmonizer/ChaosHarmonizer/Base.lproj/Main.storyboard b/Examples/ChaosHarmonizer/ChaosHarmonizer/Base.lproj/Main.storyboard index c51a259..a132494 100644 --- a/Examples/ChaosHarmonizer/ChaosHarmonizer/Base.lproj/Main.storyboard +++ b/Examples/ChaosHarmonizer/ChaosHarmonizer/Base.lproj/Main.storyboard @@ -1,7 +1,7 @@ - + - + @@ -148,8 +148,7 @@ - - + @@ -641,16 +640,16 @@ - + - + - + @@ -667,7 +666,7 @@ - + diff --git a/Examples/ChaosHarmonizer/ChaosHarmonizer/ViewController.swift b/Examples/ChaosHarmonizer/ChaosHarmonizer/ViewController.swift index 1dbc85f..13faed8 100644 --- a/Examples/ChaosHarmonizer/ChaosHarmonizer/ViewController.swift +++ b/Examples/ChaosHarmonizer/ChaosHarmonizer/ViewController.swift @@ -5,19 +5,47 @@ import MusicKit class ViewController: NSViewController { + var noteNumberToPitchSet = [UInt : PitchSet]() + override func viewDidLoad() { super.viewDidLoad() + let midi = MIDI(name: "ChaosHarmonizer") midi.noteHandler = { messages in if let first = messages.first { - let possibleChords = ChordQuality.Hexads - let index = arc4random_uniform(UInt32(possibleChords.count)) - let quality = possibleChords[Int(index)] - let intervals = quality.intervals - let indices = MKUtil.semitoneIndices(intervals) - let semitones = indices[indices.count - 1] - let harmonizer = Harmony.transpose(Harmony.create(intervals), semitones: semitones) - midi.send([first, first.transpose(2), first.transpose(3)]) + if first.on { + let possibleChords = [ + ChordQuality.Major, + ChordQuality.Sus2, + ChordQuality.Sus4, + ChordQuality.Minor, + ] + let index = arc4random_uniform(UInt32(possibleChords.count)) + let quality = possibleChords[Int(index)] + let intervals = quality.intervals + let indices = MKUtil.semitoneIndices(intervals) + let transposition = indices[indices.count - 1]*(-2) + let harmonizer = Harmony.transpose(Harmony.create(intervals), semitones: transposition) + let pitch = Pitch(midi: Float(first.noteNumber)) + var pitchSet = harmonizer(pitch) + self.noteNumberToPitchSet[first.noteNumber] = pitchSet + var messages = first.harmonize(harmonizer) + messages.append(first) + midi.send(messages) + } + else { + var offMessages = [MIDINoteMessage]() + if let pitchSet = self.noteNumberToPitchSet[first.noteNumber] { + for pitch in pitchSet { + let message = MIDINoteMessage(on: false, + channel: first.channel, + noteNumber: UInt(pitch.midi), velocity: 0) + offMessages.append(message) + offMessages.append(first) + } + midi.send(offMessages) + } + } } } } diff --git a/MusicKit/MIDI.swift b/MusicKit/MIDI.swift index 8aad17a..a047fea 100644 --- a/MusicKit/MIDI.swift +++ b/MusicKit/MIDI.swift @@ -50,7 +50,7 @@ public class MIDI { /// Note that messages are always sent on `sourceChannel`. /// /// :returns: `true` if the message was successfully sent - public func send(messages: [MIDIMessage]) -> Bool { + public func send(messages: [T]) -> Bool { var success = false var packet = UnsafeMutablePointer.alloc(sizeof(MIDIPacket)) var packetList = UnsafeMutablePointer.alloc(sizeof(MIDIPacketList)) diff --git a/MusicKit/MIDIMessage.swift b/MusicKit/MIDIMessage.swift index 9f12fd3..d8c8f97 100644 --- a/MusicKit/MIDIMessage.swift +++ b/MusicKit/MIDIMessage.swift @@ -36,6 +36,23 @@ public struct MIDINoteMessage : MIDIMessage { public func copyOnChannel(channel: UInt) -> MIDINoteMessage { return MIDINoteMessage(on: on, channel: channel, noteNumber: noteNumber, velocity: velocity) } + + /// The message's pitch + public var pitch : Pitch { + return Pitch(midi: Float(noteNumber)) + } + + /// Applies the given `Harmonizer` to the message. + public func harmonize(harmonizer: Harmonizer) -> [MIDINoteMessage] { + let ps = harmonizer(pitch) + var messages = [MIDINoteMessage]() + // TODO: add a PitchSet -> Array method so this can be mapped + for p in ps { + messages.append(MIDINoteMessage(on: self.on, channel: self.channel, + noteNumber: UInt(p.midi), velocity: self.velocity)) + } + return messages + } } extension MIDINoteMessage : Printable {