6

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.

SwiftUI Graph Real Time Updating

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()
        }
}
arata
  • 859
  • 1
  • 8
  • 23

0 Answers0