So I have a view and I am computing the amplitude of an audio file and then passing it to a view to graph it and it changes in real-time. The problem is that the graph gets so laggy after few seconds and CPU usage gets maximized and literally everything kind of freezes. Is there any way to render the view using GPU instead of the CPU in SwiftUI macOS?
I am updating the values for amplitudes in a DispatchQueue.main.async
and sending an NSNotification
.
This is the file I am calling when I want to show the graphs
struct TimeDomain: View {
@Binding var manager: AVManager
@State var pub = DSPNotification().publisherPath()
@State var amps = [Double]()
var body: some View {
AmplitudeVisualizer(amplitudes: $amps).frame(height: 300)
.onReceive(pub) { (output) in
self.amps = manager.amplitudes
}
.onAppear {
self.amps = manager.amplitudes
}
.drawingGroup()
}
}
and the file for AmplitudeVisualizer.swift
struct AmplitudeVisualizer: View {
@Binding var amplitudes: [Double]
var body: some View {
HStack(spacing: 0.0){
ForEach(0..<self.amplitudes.count, id: \.self) { number in
VerticalBar(amplitude: self.$amplitudes[number])
}
.drawingGroup()
}
}
}
and VerticalBar.swift
/// Single bar of Amplitude Visualizer
struct VerticalBar: View {
@Binding var amplitude: Double
var body: some View {
GeometryReader
{ geometry in
ZStack(alignment: .bottom){
// Colored rectangle in back of ZStack
Rectangle()
.fill(LinearGradient(gradient: Gradient(colors: [.red, .yellow, .green]), startPoint: .top, endPoint: .center))
// blue/purple bar style - try switching this out with the .fill statement above
//.fill(LinearGradient(gradient: Gradient(colors: [Color.init(red: 0.0, green: 1.0, blue: 1.0), .blue, .purple]), startPoint: .top, endPoint: .bottom))
// Dynamic black mask padded from bottom in relation to the amplitude
Rectangle()
.fill(Color.black)
.mask(Rectangle().padding(.bottom, geometry.size.height * CGFloat(self.amplitude)))
.animation(.easeOut(duration: 0.05))
// White bar with slower animation for floating effect
Rectangle()
.fill(Color.white)
.frame(height: geometry.size.height * 0.005)
.offset(x: 0.0, y: -geometry.size.height * CGFloat(self.amplitude) - geometry.size.height * 0.02)
.animation(.easeOut(duration: 0.6))
}
.padding(geometry.size.width * 0.1)
.border(Color.black, width: geometry.size.width * 0.1)
}.drawingGroup()
}
}