我希望在原始语音备忘录应用程序上对记录进行可视化:
我知道我可以获得关卡 - updateMeters - peakPowerForChannel: - averagePowerForChannel:
但是如何绘制图形,我应该自定义吗?我可以使用免费/付费资源吗?
答案 0 :(得分:1)
我遇到了同样的问题。我想创建一个语音备忘录克隆。最近,我找到了一个解决方案,并在媒体上写了一篇有关它的文章。
我从UIView类创建了一个子类,并使用CGRect绘制了条形图。
import UIKit
class AudioVisualizerView: UIView {
// Bar width
var barWidth: CGFloat = 4.0
// Indicate that waveform should draw active/inactive state
var active = false {
didSet {
if self.active {
self.color = UIColor.red.cgColor
}
else {
self.color = UIColor.gray.cgColor
}
}
}
// Color for bars
var color = UIColor.gray.cgColor
// Given waveforms
var waveforms: [Int] = Array(repeating: 0, count: 100)
// MARK: - Init
override init (frame : CGRect) {
super.init(frame : frame)
self.backgroundColor = UIColor.clear
}
required init?(coder decoder: NSCoder) {
super.init(coder: decoder)
self.backgroundColor = UIColor.clear
}
// MARK: - Draw bars
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else {
return
}
context.clear(rect)
context.setFillColor(red: 0, green: 0, blue: 0, alpha: 0)
context.fill(rect)
context.setLineWidth(1)
context.setStrokeColor(self.color)
let w = rect.size.width
let h = rect.size.height
let t = Int(w / self.barWidth)
let s = max(0, self.waveforms.count - t)
let m = h / 2
let r = self.barWidth / 2
let x = m - r
var bar: CGFloat = 0
for i in s ..< self.waveforms.count {
var v = h * CGFloat(self.waveforms[i]) / 50.0
if v > x {
v = x
}
else if v < 3 {
v = 3
}
let oneX = bar * self.barWidth
var oneY: CGFloat = 0
let twoX = oneX + r
var twoY: CGFloat = 0
var twoS: CGFloat = 0
var twoE: CGFloat = 0
var twoC: Bool = false
let threeX = twoX + r
let threeY = m
if i % 2 == 1 {
oneY = m - v
twoY = m - v
twoS = -180.degreesToRadians
twoE = 0.degreesToRadians
twoC = false
}
else {
oneY = m + v
twoY = m + v
twoS = 180.degreesToRadians
twoE = 0.degreesToRadians
twoC = true
}
context.move(to: CGPoint(x: oneX, y: m))
context.addLine(to: CGPoint(x: oneX, y: oneY))
context.addArc(center: CGPoint(x: twoX, y: twoY), radius: r, startAngle: twoS, endAngle: twoE, clockwise: twoC)
context.addLine(to: CGPoint(x: threeX, y: threeY))
context.strokePath()
bar += 1
}
}
}
对于记录功能,我使用installTap实例方法记录,监视和观察节点的输出。
let inputNode = self.audioEngine.inputNode
guard let format = self.format() else {
return
}
inputNode.installTap(onBus: 0, bufferSize: 1024, format: format) { (buffer, time) in
let level: Float = -50
let length: UInt32 = 1024
buffer.frameLength = length
let channels = UnsafeBufferPointer(start: buffer.floatChannelData, count: Int(buffer.format.channelCount))
var value: Float = 0
vDSP_meamgv(channels[0], 1, &value, vDSP_Length(length))
var average: Float = ((value == 0) ? -100 : 20.0 * log10f(value))
if average > 0 {
average = 0
} else if average < -100 {
average = -100
}
let silent = average < level
let ts = NSDate().timeIntervalSince1970
if ts - self.renderTs > 0.1 {
let floats = UnsafeBufferPointer(start: channels[0], count: Int(buffer.frameLength))
let frame = floats.map({ (f) -> Int in
return Int(f * Float(Int16.max))
})
DispatchQueue.main.async {
let seconds = (ts - self.recordingTs)
self.timeLabel.text = seconds.toTimeString
self.renderTs = ts
let len = self.audioView.waveforms.count
for i in 0 ..< len {
let idx = ((frame.count - 1) * i) / len
let f: Float = sqrt(1.5 * abs(Float(frame[idx])) / Float(Int16.max))
self.audioView.waveforms[i] = min(49, Int(f * 50))
}
self.audioView.active = !silent
self.audioView.setNeedsDisplay()
}
}
这是我写的文章,希望您能找到所需的内容: https://medium.com/flawless-app-stories/how-i-created-apples-voice-memos-clone-b6cd6d65f580
该项目在GitHub上也可用: https://github.com/HassanElDesouky/VoiceMemosClone
请注意,我仍然是一个初学者,对不起,我的代码看起来不太干净!