-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathViewController.swift
106 lines (87 loc) · 2.95 KB
/
ViewController.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import UIKit
import AVFoundation
class ViewController: UIViewController {
@IBOutlet weak var button: UIButton!
var midiPlayer: AVMIDIPlayer?
let drummer = Drummer()
let soundFont = "1115-Standard Rock Set"
override func viewDidLoad() {
super.viewDidLoad()
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
} catch {
print("Error: could not set audio session")
}
}
@IBAction func playDrums(_ sender: Any) {
if midiPlayer == nil {
button.setTitle("Stop this madness", for: .normal)
hitMeWithYourRhythmStick()
} else {
button.setTitle("Play another one!", for: .normal)
midiPlayer?.stop()
midiPlayer = nil
}
}
func hitMeWithYourRhythmStick() {
let drums = drummer.sample(1000)
if let sequence = createMusicSequence(drums),
let data = dataFromMusicSequence(sequence) {
let midiData = data.takeUnretainedValue() as Data
midiPlayer = createMIDIPlayer(midiData: midiData)
data.release()
midiPlayer?.play(nil)
}
}
func createMusicSequence(_ drums: [(Int, Int)]) -> MusicSequence? {
var musicSequence: MusicSequence?
var status = NewMusicSequence(&musicSequence)
guard status == OSStatus(noErr) else {
print("Error: could not create MusicSequence \(status)")
return nil
}
var track: MusicTrack?
status = MusicSequenceNewTrack(musicSequence!, &track)
guard status == OSStatus(noErr) else {
print("Error: could not create MusicTrack \(status)")
return nil
}
var totalTicks = 0
for (note, ticks) in drums {
var message = MIDINoteMessage(channel: 10, note: UInt8(note),
velocity: 64, releaseVelocity: 0,
duration: 0.5)
totalTicks += ticks
let beat = MusicTimeStamp(totalTicks) / 480
status = MusicTrackNewMIDINoteEvent(track!, beat, &message)
if status != OSStatus(noErr) {
print("Error: could not create MIDINoteEvent \(status)")
}
}
//CAShow(UnsafeMutablePointer<MusicSequence>(musicSequence!))
return musicSequence!
}
func dataFromMusicSequence(_ sequence: MusicSequence) -> Unmanaged<CFData>? {
var data: Unmanaged<CFData>?
let status = MusicSequenceFileCreateData(sequence, .midiType, .eraseFile, 480, &data)
guard status == OSStatus(noErr) else {
print("Error: could not create data from MusicSequence \(status)")
return nil
}
return data
}
func createMIDIPlayer(midiData: Data) -> AVMIDIPlayer? {
guard let url = Bundle.main.url(forResource: soundFont, withExtension: "sf2") else {
print("Error: could not load \(soundFont)")
return nil
}
do {
let midiPlayer = try AVMIDIPlayer(data: midiData, soundBankURL: url)
midiPlayer.prepareToPlay()
return midiPlayer
} catch {
print("Error: could not create AVMIDIPlayer \(error)")
return nil
}
}
}