-
-
Notifications
You must be signed in to change notification settings - Fork 113
/
WaveformLiveView.swift
142 lines (115 loc) · 4.28 KB
/
WaveformLiveView.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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#if os(iOS) || swift(>=5.9) && os(visionOS)
import DSWaveformImage
import Foundation
import UIKit
/// Renders a live waveform everytime its `(0...1)`-normalized samples are changed.
public class WaveformLiveView: UIView {
/// Default configuration with damping enabled.
public static let defaultConfiguration = Waveform.Configuration(damping: .init(percentage: 0.125, sides: .both))
/// If set to `true`, a zero line, indicating silence, is being drawn while the received
/// samples are not filling up the entire view's width yet.
public var shouldDrawSilencePadding: Bool = false {
didSet {
sampleLayer.shouldDrawSilencePadding = shouldDrawSilencePadding
}
}
public var configuration: Waveform.Configuration {
didSet {
sampleLayer.configuration = configuration
}
}
/// Returns the currently used samples.
public var samples: [Float] {
sampleLayer.samples
}
private var sampleLayer: WaveformLiveLayer! {
return layer as? WaveformLiveLayer
}
override public class var layerClass: AnyClass {
return WaveformLiveLayer.self
}
public var renderer: WaveformRenderer {
didSet {
sampleLayer.renderer = renderer
}
}
public init(configuration: Waveform.Configuration = defaultConfiguration, renderer: WaveformRenderer = LinearWaveformRenderer()) {
self.configuration = configuration
self.renderer = renderer
super.init(frame: .zero)
self.contentMode = .redraw
defer { // will call didSet to propagate to sampleLayer
self.configuration = configuration
self.renderer = renderer
}
}
public override init(frame: CGRect) {
self.configuration = Self.defaultConfiguration
self.renderer = LinearWaveformRenderer()
super.init(frame: frame)
contentMode = .redraw
defer { // will call didSet to propagate to sampleLayer
self.configuration = Self.defaultConfiguration
self.renderer = LinearWaveformRenderer()
}
}
required init?(coder: NSCoder) {
self.configuration = Self.defaultConfiguration
self.renderer = LinearWaveformRenderer()
super.init(coder: coder)
contentMode = .redraw
defer { // will call didSet to propagate to sampleLayer
self.configuration = Self.defaultConfiguration
self.renderer = LinearWaveformRenderer()
}
}
/// The sample to be added. Re-draws the waveform with the pre-existing samples and the new one.
/// Value must be within `(0...1)` to make sense (0 being loweset and 1 being maximum amplitude).
public func add(sample: Float) {
sampleLayer.add([sample])
}
/// The samples to be added. Re-draws the waveform with the pre-existing samples and the new ones.
/// Values must be within `(0...1)` to make sense (0 being loweset and 1 being maximum amplitude).
public func add(samples: [Float]) {
sampleLayer.add(samples)
}
/// Clears the samples, emptying the waveform view.
public func reset() {
sampleLayer.reset()
}
}
class WaveformLiveLayer: CALayer {
@NSManaged var samples: [Float]
var configuration = WaveformLiveView.defaultConfiguration {
didSet { contentsScale = configuration.scale }
}
var shouldDrawSilencePadding: Bool = false {
didSet {
waveformDrawer.shouldDrawSilencePadding = shouldDrawSilencePadding
setNeedsDisplay()
}
}
var renderer: WaveformRenderer = LinearWaveformRenderer() {
didSet { setNeedsDisplay() }
}
private let waveformDrawer = WaveformImageDrawer()
override class func needsDisplay(forKey key: String) -> Bool {
if key == #keyPath(samples) {
return true
}
return super.needsDisplay(forKey: key)
}
override func draw(in context: CGContext) {
super.draw(in: context)
UIGraphicsPushContext(context)
waveformDrawer.draw(waveform: samples, on: context, with: configuration.with(size: bounds.size), renderer: renderer)
UIGraphicsPopContext()
}
func add(_ newSamples: [Float]) {
samples += newSamples
}
func reset() {
samples = []
}
}
#endif