william-weng/wwspectrumviewui
WWSpectrumViewUI 是一個用 Swift、SwiftUI 與 Accelerate 製作的即時音訊頻譜分析與視覺化套件。它可以從 AVAudioNode 擷取音訊資料,轉成原始頻帶資料,並用可自訂的 SwiftUI 頻譜視圖呈現。
✨ 特色
- 輸出
SpectrumBandRaw原始頻帶資料。 - 提供 SwiftUI 頻譜視覺化元件。
- 多種 bar 樣式:
rounded、sharp、glow、gradient。 - 多種配色方案:
rainbow、fire、ocean、neon、sunset、matrix、custom。 - 可設定
fftSize、barCount、minFrequency、maxFrequency與動畫時間。 - 分離分析層與 UI 層,方便自行客製。
📦 安裝方式
Swift Package Manager
在 Package.swift 中加入:
dependencies: [
.package(url: "https://github.com/William-Weng/WWSpectrumViewUI.git", .upToNextMajor(from: "1.0.0"))
]或者在 Xcode 中選擇 File > Add Package Dependencies...,貼上 GitHub 倉庫網址即可。
🚀 快速開始
1. 建立 ViewModel
let viewModel = WWSpectrumViewUI.ViewModel()2. 安裝 raw tap
spectrumAnalyzer.installRawTap(on: audioNode, sampleRate: sampleRate) { bands in
DispatchQueue.main.async { viewModel.rawBands = bands }
}3. 顯示頻譜視圖
WWSpectrumViewUI(viewModel: viewModel, colorScheme: .rainbow, barStyle: .glow, duration: 0.25).frame(height: 220)💡 使用範例
import AVFAudio
import SwiftUI
import WWNormalizeAudioPlayer
import WWSpectrumViewUI
final class ViewController: UIViewController {
private let audioPlayer = WWNormalizeAudioPlayer()
private let spectrumAnalyzer = WWNormalizeAudioPlayer.SpectrumAnalyzer()
private let viewModel = WWSpectrumViewUI.ViewModel()
private let filenames = ["audio.m4a"]
private var spectrumHostingController: UIHostingController<WWSpectrumViewUI>?
override func viewDidLoad() {
super.viewDidLoad()
setupSpectrumView()
setupAudio()
}
}
extension ViewController {
func setupSpectrumView() {
let spectrumView = WWSpectrumViewUI(viewModel: viewModel, colorScheme: .neon, barStyle: .glow, duration: 0.5)
let hostingController = UIHostingController(rootView: spectrumView)
hostingController.view.backgroundColor = .clear
spectrumHostingController = hostingController
addChild(hostingController)
self.view.addSubview(hostingController.view)
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
hostingController.view.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
hostingController.view.trailingAnchor.constraint(equalTo: self.view.trailingAnchor,),
hostingController.view.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor),
hostingController.view.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor),
])
hostingController.didMove(toParent: self)
}
func setupAudio() {
Task {
do {
try audioPlayer.configure(delegate: self)
let sampleRate = audioPlayer.audioNode.outputFormat(forBus: 0).sampleRate
spectrumAnalyzer.installRawTap(on: audioPlayer.audioNode, sampleRate: sampleRate) { [self] rawBands in
let rawBands = rawBands.map { raw in
WWSpectrumViewUI.BandRaw(index: raw.index, lowerFrequency: raw.lowerFrequency, upperFrequency: raw.upperFrequency, values: raw.values)
}
Task { @MainActor in self.viewModel.rawBands = rawBands }
}
await audioPlayer.play(filenames: filenames, loop: true)
} catch {
print(error)
}
}
}
}
extension ViewController: WWNormalizeAudioPlayer.Delegate {
func audioPlayer(_ player: WWNormalizeAudioPlayer, trackIndex: Int, currentTime: TimeInterval, trackTime: TimeInterval) {}
func audioPlayer(_ player: WWNormalizeAudioPlayer, didFinishTrackIndex trackIndex: Int, callbackType: AVAudioPlayerNodeCompletionCallbackType) {}
func audioPlayer(_ player: WWNormalizeAudioPlayer, error: any Error) {}
}🧩 資料模型
SpectrumBandRaw
SpectrumBandRaw 用來保存每個頻帶的原始 FFT bin 值,適合做進一步分析、自訂轉換或客製視覺化。
struct SpectrumBandRaw {
public let index: Int
public let lowerFrequency: Float
public let upperFrequency: Float
public let values: [Float]
}SpectrumBar
SpectrumBar 用來保存已正規化的振幅,適合拿來畫圖或輸出 JSON。
struct SpectrumBar: Codable {
public let index: Int
public let lowerFrequency: Float
public let upperFrequency: Float
public let amplitude: Float
}⚙️ API 總覽
WWSpectrumViewUI
SwiftUI 視覺化元件,會從 ViewModel 讀取 raw bands,並即時畫出頻譜條。
ColorScheme
內建配色:
rainbowfireoceanneonsunsetmatrixcustom([Color])
BarStyle
內建樣式:
roundedsharpglowgradient
📖 資料流
- 在音訊節點上安裝 tap。
- 取得 raw band 資料。
- 將資料更新到 view model。
- 由
WWSpectrumViewUI繪製即時 bar。
⚠️ 注意事項
viewModel.rawBands請在主執行緒更新。- 頻譜視圖會依照容器大小自動調整。
bandAmplitude(_:)會把 raw band 轉成0...1的顯示振幅。
Package Metadata
Repository: william-weng/wwspectrumviewui
Default branch: main
README: README.md