Skip to content

Commit 680f005

Browse files
authored
Update bar visualizer design (#17)
Always show bars even with no audio. https://github.com/user-attachments/assets/16578aa3-9e95-4b21-8178-f21cbc594c33
1 parent c81fa02 commit 680f005

File tree

1 file changed

+25
-21
lines changed

1 file changed

+25
-21
lines changed

Sources/LiveKitComponents/UI/Visualizer/Visualizer.swift

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,20 @@ import AVFoundation
1818
import LiveKit
1919
import SwiftUI
2020

21-
class AudioProcessor: ObservableObject, AudioRenderer {
22-
private weak var _track: AudioTrack?
23-
private let isCentered: Bool
21+
public class AudioProcessor: ObservableObject, AudioRenderer {
22+
public let isCentered: Bool
2423
public let smoothingFactor: Float
2524

2625
// Normalized to 0.0-1.0 range.
27-
@Published var bands: [Float]
26+
@Published public var bands: [Float]
2827

2928
private let _processor: AudioVisualizeProcessor
29+
private weak var _track: AudioTrack?
3030

31-
init(track: AudioTrack?,
32-
bandCount: Int,
33-
isCentered: Bool = true,
34-
smoothingFactor: Float = 0.3)
31+
public init(track: AudioTrack?,
32+
bandCount: Int,
33+
isCentered: Bool = true,
34+
smoothingFactor: Float = 0.3)
3535
{
3636
self.isCentered = isCentered
3737
self.smoothingFactor = smoothingFactor
@@ -46,7 +46,7 @@ class AudioProcessor: ObservableObject, AudioRenderer {
4646
_track?.remove(audioRenderer: self)
4747
}
4848

49-
func render(pcmBuffer: AVAudioPCMBuffer) {
49+
public func render(pcmBuffer: AVAudioPCMBuffer) {
5050
let newBands = _processor.process(pcmBuffer: pcmBuffer)
5151
guard var newBands else { return }
5252

@@ -134,50 +134,54 @@ class AudioProcessor: ObservableObject, AudioRenderer {
134134
/// ```
135135
/// BarAudioVisualizer(audioTrack: audioTrack, barColor: .blue, barCount: 10)
136136
/// ```
137-
struct BarAudioVisualizer: View {
137+
public struct BarAudioVisualizer: View {
138138
public let barCount: Int
139139
public let barColor: Color
140140
public let barCornerRadius: CGFloat
141141
public let barSpacingFactor: CGFloat
142+
public let barMinOpacity: Double
142143
public let isCentered: Bool
143144

144145
public let audioTrack: AudioTrack
145146

146147
@StateObject private var audioProcessor: AudioProcessor
147148

148-
init(audioTrack: AudioTrack,
149-
barColor: Color = .white,
150-
barCount: Int = 7,
151-
barCornerRadius: CGFloat = 100,
152-
barSpacingFactor: CGFloat = 0.015,
153-
isCentered: Bool = true)
149+
public init(audioTrack: AudioTrack,
150+
barColor: Color = .white,
151+
barCount: Int = 7,
152+
barCornerRadius: CGFloat = 100,
153+
barSpacingFactor: CGFloat = 0.015,
154+
barMinOpacity: CGFloat = 0.35,
155+
isCentered: Bool = true)
154156
{
155157
self.audioTrack = audioTrack
156158
self.barColor = barColor
157159
self.barCount = barCount
158160
self.barCornerRadius = barCornerRadius
159161
self.barSpacingFactor = barSpacingFactor
162+
self.barMinOpacity = Double(barMinOpacity)
160163
self.isCentered = isCentered
161164

162165
_audioProcessor = StateObject(wrappedValue: AudioProcessor(track: audioTrack,
163166
bandCount: barCount,
164167
isCentered: isCentered))
165168
}
166169

167-
var body: some View {
170+
public var body: some View {
168171
GeometryReader { geometry in
172+
let barMinHeight = (geometry.size.width - geometry.size.width * barSpacingFactor * CGFloat(barCount + 2)) / CGFloat(barCount)
169173
HStack(alignment: .center, spacing: geometry.size.width * barSpacingFactor) {
170174
ForEach(0 ..< audioProcessor.bands.count, id: \.self) { index in
171175
VStack {
172176
Spacer()
173-
RoundedRectangle(cornerRadius: barCornerRadius)
174-
.fill(barColor.opacity(Double(audioProcessor.bands[index])))
175-
.frame(height: CGFloat(audioProcessor.bands[index]) * geometry.size.height)
177+
RoundedRectangle(cornerRadius: barMinHeight)
178+
.fill(barColor.opacity((1.0 - barMinOpacity) * Double(audioProcessor.bands[index]) + barMinOpacity))
179+
.frame(height: (geometry.size.height - barMinHeight) * CGFloat(audioProcessor.bands[index]) + barMinHeight)
176180
Spacer()
177181
}
178182
}
179183
}
184+
.padding(geometry.size.width * barSpacingFactor)
180185
}
181-
.padding()
182186
}
183187
}

0 commit comments

Comments
 (0)